RC Car with Integrated Robot Arm – Introduction and Setup Guide
Product Overview
This project consists of a 4-wheel RC car integrated with a robot arm system, fully 3D printed. You can remotely control the car's movement and precisely operate the robot arm using potentiometers and a joystick. Communication between the controller and the car is wireless, using NRF24L01 modules and Arduino boards for bidirectional control.
Components Used
Car Side:
1 × Arduino Uno
1 × NRF24L01 PA+LN (100mW) module (E01-ML01DP5)
1 × PCA9685 servo PWM driver board
1 × L298N motor driver
4 × DC motors
4 × MG996R servo motors (for robot arm ts)
1 × SG90 servo motor (for the robot arm gripper)
4 × 18650 Li-ion batteries
1 × 4S battery holder for 18650 cells
Necessary jumper wires and connectors
Controller Side:
1 × Arduino Nano
1 × NRF24L01 PA+LN (100mW) module (E01-ML01DP5)
1 × NRF24 3.3V power regulator
1 × Arduino joystick module
4 × Potentiometers
1 × On/Off button (optional)
Jumper wires
Wiring and Pin Assignments
Car (Arduino Uno) Pin Assignments:
NRF24L01 Module:
CE → Digital Pin 9
CSN → Digital Pin 10
MOSI → Digital Pin 11 (SPI)
MISO → Digital Pin 12 (SPI)
SCK → Digital Pin 13 (SPI)
GND and 3.3V connected properly
PCA9685 Servo Driver (I2C):
SDA → Analog Pin A4
SCL → Analog Pin A5
5V and GND connected
L298N Motor Driver:
IN1 → Digital Pin 2
IN2 → Digital Pin 4
IN3 → Digital Pin 7
IN4 → Digital Pin 8
ENA (PWM for motor 1) → Digital Pin 5
ENB (PWM for motor 2) → Digital Pin 6
Servo Motors on PCA9685 Channels:
Gripper (hand) → Channel 11
Wrist → Channel 12
Elbow → Channel 13
Shoulder → Channel 14
Base → Channel 15
Controller (Arduino Nano) Pin Assignments:
NRF24L01 Module:
CE → Digital Pin 9
CSN → Digital Pin 10
MOSI → Digital Pin 11 (SPI)
MISO → Digital Pin 12 (SPI)
SCK → Digital Pin 13 (SPI)
GND and 3.3V properly connected
Potentiometers:
potBase → Analog Pin A0
potShoulder → Analog Pin A1
potElbow → Analog Pin A2
potWrist → Analog Pin A3
Joystick:
JoyX → Analog Pin A4
JoyY → Analog Pin A5
Joystick Button (SW) → Digital Pin 7 (INPUT_PULLUP)
On/Off Button: Optional, connect according to your setup
Software -
Car (Arduino Uno) Code
This code runs on the car Arduino Uno. It receives data wirelessly from the controller, drives the motors accordingly, and controls the robot arm servos using the PCA9685 driver.
#include
#include
#include
#include
#include
// PCA9685 ayarları
#define MIN_PULSE_WIDTH 650
#define MAX_PULSE_WIDTH 2350
#define FREQUENCY 50
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Servo kanalları
const int hand = 11;
const int wrist = 12;
const int elbow = 13;
const int shoulder = 14;
const int base = 15;
// L298N motor pinleri
#define IN1 2
#define IN2 4
#define IN3 7
#define IN4 8
#define ENA 5 // PWM
#define ENB 6 // PWM
// NRF24L01 bağlantısı
RF24 radio(9, 10); // CE, CSN
const byte adres[6] = "00001";
// Gelen veri yapısı
struct Data {
int potBase;
int potShoulder;
int potElbow;
int potWrist;
bool button;
int joyX;
int joyY;
};
Data veri;
// Joystick nötr konumu için merkez ve tolerans
const int centerX = 501;
const int centerY = 519;
const int tol = 100; // tolerans aralığı
// Hızı azaltma faktörü
const float speedFactor = 0.5;
void setup() {
Serial.begin(9600);
pwm.begin();
pwm.setPWMFreq(FREQUENCY);
// Servo başlangıç pozisyonları
setServoDegree(hand, 90);
setServoDegree(wrist, 90);
setServoDegree(elbow, 90);
setServoDegree(shoulder, 90);
setServoDegree(base, 90);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
radio.begin();
radio.openReadingPipe(0, adres);
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.startListening();
}
void loop() {
if (radio.available()) {
radio.read(&veri, sizeof(veri));
Serial.print("Base: ");
Serial.print(veri.potBase);
Serial.print(" | Shoulder: ");
Serial.print(veri.potShoulder);
Serial.print(" | Elbow: ");
Serial.print(veri.potElbow);
Serial.print(" | Wrist: ");
Serial.print(veri.potWrist);
Serial.print(" | Button: ");
Serial.print(veri.button);
Serial.print(" | joyX: ");
Serial.print(veri.joyX);
Serial.print(" | joyY: ");
Serial.println(veri.joyY);
// Joystick hareketli mi kontrolü
bool joystickActive = (abs(veri.joyX - centerX) > tol || abs(veri.joyY - centerY) > tol);
if (joystickActive) {
// Joystick hareketliyse sadece motor kontrolü yap
controlMotors(veri.joyX, veri.joyY);
} else {
// Joystick nötrse potansiyometreye göre servo kontrolü
setServoDegree(base, map(veri.potBase, 0, 1023, 0, 180));
setServoDegree(shoulder, map(veri.potShoulder, 0, 1023, 0, 180));
setServoDegree(elbow, map(veri.potElbow, 0, 1023, 0, 180));
setServoDegree(wrist, map(veri.potWrist, 0, 1023, 0, 180));
if (veri.button) {
setServoDegree(hand, 180);
} else {
setServoDegree(hand, 90);
}
// Motorları durdur
stopAllMotorsButServos();
}
}
}
void setServoDegree(int channel, int degree) {
degree = constrain(degree, 0, 180);
int pulseLength = map(degree, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
int pwmVal = convertToPWM(pulseLength);
pwm.setPWM(channel, 0, pwmVal);
}
int convertToPWM(int microseconds) {
return (int)((microseconds * 4096L) / (1000000L / FREQUENCY));
}
void controlMotors(int x, int y) {
bool ileri = x < centerX - tol;
bool geri = x > centerX + tol;
bool sag = y < centerY - tol;
bool sol = y > centerY + tol;
int hizX = map(abs(x - centerX), 0, 512, 0, 255);
int hizY = map(abs(y - centerY), 0, 512, 0, 255);
hizX = constrain(hizX, 100, 255);
hizY = constrain(hizY, 100, 255);
hizX = int(hizX * speedFactor);
hizY = int(hizY * speedFactor);
if (ileri && sag) {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
analogWrite(ENA, hizX); analogWrite(ENB, hizY);
Serial.println("İleri Sağ");
} else if (ileri && sol) {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
analogWrite(ENA, hizX); analogWrite(ENB, hizY);
Serial.println("İleri Sol");
} else if (geri && sag) {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
analogWrite(ENA, hizX); analogWrite(ENB, hizY);
Serial.println("Geri Sağ");
} else if (geri && sol) {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
analogWrite(ENA, hizX); analogWrite(ENB, hizY);
Serial.println("Geri Sol");
} else if (ileri) {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
analogWrite(ENA, hizX); analogWrite(ENB, hizX);
Serial.println("İleri");
} else if (geri) {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
analogWrite(ENA, hizX); analogWrite(ENB, hizX);
Serial.println("Geri");
} else if (sag) {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
analogWrite(ENA, hizY); analogWrite(ENB, hizY);
Serial.println("Sağ");
} else if (sol) {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
analogWrite(ENA, hizY); analogWrite(ENB, hizY);
Serial.println("Sol");
} else {
stopAllMotorsButServos();
Serial.println("Dur");
}
}
void stopAllMotorsButServos() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
Controller (Arduino Nano) Code
This code reads potentiometer and joystick values, sends commands wirelessly to the car.
#include
#include
#include
// NRF24L01 ayarları
RF24 radio(9, 10); // CE = D9, CSN = D10
const byte adres[6] = "00001";
// Potansiyometre pinleri
const int potBasePin = A0;
const int potShoulderPin = A1;
const int potElbowPin = A2;
const int potWristPin = A3;
// Joystick pinleri
const int joyXPin = A4;
const int joyYPin = A5;
// Buton pini (joystick SW)
const int buttonPin = 7; // D7 pinine bağlı
// Gönderilen veri yapısı
struct Data {
int potBase;
int potShoulder;
int potElbow;
int potWrist;
bool button;
int joyX;
int joyY;
};
Data veri;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
radio.begin();
radio.openWritingPipe(adres);
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.stopListening();
Serial.println("Kumanda hazır");
}
void loop() {
veri.potBase = analogRead(potBasePin);
veri.potShoulder = analogRead(potShoulderPin);
veri.potElbow = analogRead(potElbowPin);
veri.potWrist = analogRead(potWristPin);
veri.joyX = analogRead(joyXPin);
veri.joyY = analogRead(joyYPin);
veri.button = (digitalRead(buttonPin) == LOW);
bool gonderildi = radio.write(&veri, sizeof(veri));
if (gonderildi) {
Serial.println("Veri gönderildi");
} else {
Serial.println("Gönderme hatası");
}
delay(10);
}
Make sure to install the necessary Arduino libraries:
RF24
Adafruit PWM Servo Driver
nRF24L01
Assembly and Setup Instructions
Hardware Assembly:
Assemble all 3D printed parts and mount the motors, servos, and electronics carefully. Connect wires according to the pin assignments above.
Power Supply:
Connect the 18650 batteries in a 4S configuration to achieve the required voltage. Use proper voltage regulators for the Arduino and NRF24L01 modules.
Code:
the car code to the Arduino Uno first. Then the controller code to the Arduino Nano. Make sure all required libraries are installed in Arduino IDE.
Testing:
Move the joystick and potentiometers on the controller and observe the car motors and robot arm servos respond accordingly.
Press the joystick button to open/close the gripper.
Tips and Precautions
Use a stable 3.3V power source for the NRF24L01 modules to avoid communication issues.
The PCA9685 servo driver requires a 5V power supply but make sure logic levels are compatible.
Double-check all wiring to prevent damage to the Arduino or motor drivers.
Calibrate joystick dead zones carefully for smooth operation.
Monitor battery voltage to prevent over-discharge of Li-ion cells.
Summary:
This project offers an advanced platform combining a 4WD RC car and a controllable robot arm. By leveraging 3D printing, Arduino microcontrollers, and wireless communication, you can build a fully functional mobile robot with real-time remote control.