Hello, everyone, I hope you may help me in my robot car project of a security robot car with aligned SDGs. Its function is to detect and roam around surroundings, acting similar to a police car. Basically its specific components are: ultrasonic sensor, servo motor, buzzer, DC motors, lcd module, rgb led, thermistor (heat detection), photoresistor (light detection), level shifter, and ps4 controller. It's main components are: Arduino UNO, Adafruit Motorshield v1, and ESP32 w/ CAM module. To add, there's no cam in the esp32 since the robot's too complex as it is.
I just need help because the problem is the robot is not moving, especially the fact that there is serious trouble in connecting the esp32 with the arduino UNO. Even if I finally managed to connect them both with a long serious effort, the problem persists with the robot not fulfilling its commands as the Arduino's serial monitor does not act; this goes back with the original problem of the connection between arduino and esp32.
Also, I've managed to at least connect successfully the ps4 controller and the esp32, and I have already planned several command buttons for the robot function.
Please help me fix this code. I'm already quite dying before being able to manage fixing this robot.
![]()
Arduino UNO code
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <AFMotor.h>
#include <SoftwareSerial.h>
// RX = 8, TX = 9
SoftwareSerial EspSerial(8, 9); // RX, TX
// Pin Definitions
const int BUZZER_PIN = 7;
const int LED_R_PIN = 3;
const int LED_G_PIN = 5;
const int LED_B_PIN = 6;
const int SERVO_PIN = 10;
// Sensor Pins
const int PHOTORESISTOR_PIN = 2;
const int THERMISTOR_PIN = 4;
const int ULTRASONIC_TRIGGER_PIN = A2;
const int ULTRASONIC_ECHO_PIN = A3;
Servo ultrasonicServo;
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool sdgModeActive = false;
bool intruderModeActive = false;
bool obstacleDetected = false; // for off when robot is on
unsigned long lastMoveTime = 0;
int roamingState = 0;
// Motor Speed
int motorSpeed = 128;
bool ramModeActive = false;
// Thresholds
const int HIGH_TEMP_THRESHOLD = 40; // Temperature threshold in Celsius
const int dangerDistance = 15; // Distance in cm, adjust as needed
const int lightThreshold = 200; // Adjust based on your sensor range
long duration;
int distance;
// Define motors
AF_DCMotor motor1(1);
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);
void setup() {
Serial.begin(19200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_R_PIN, OUTPUT);
pinMode(LED_G_PIN, OUTPUT);
pinMode(LED_B_PIN, OUTPUT);
pinMode(PHOTORESISTOR_PIN, INPUT);
pinMode(THERMISTOR_PIN, INPUT);
ultrasonicServo.attach(SERVO_PIN);
ultrasonicServo.write(90);
Wire.begin(); // Uses A4 (SDA) and A5 (SCL)
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Waiting...");
pinMode(ULTRASONIC_TRIGGER_PIN, OUTPUT);
pinMode(ULTRASONIC_ECHO_PIN, INPUT);
}
void loop() {
if (EspSerial.available()) {
String command = EspSerial.readStringUntil('\n');
command.trim();
handleCommand(command);
}
if (sdgModeActive) {
roamAutomatically();
}
if (intruderModeActive) {
monitorIntruder();
}
checkSensors();
}
// --- Handle incoming ESP32 commands ---
void handleCommand(String cmd) {
if (cmd.startsWith("SERVO:")) {
int angle = cmd.substring(6).toInt();
ultrasonicServo.write(angle);
}
else if (cmd == "COMMAND: SDG_MODE_ON") {
sdgModeActive = true;
intruderModeActive = false;
lcd.clear();
lcd.print("SDG Mode ON");
beep();
setLEDColor(0, 255, 0);
}
else if (cmd == "COMMAND: SDG_MODE_OFF") {
sdgModeActive = false;
lcd.clear();
lcd.print("Manual Mode");
beep();
setLEDColor(255, 255, 255);
}
else if (cmd == "COMMAND: INTRUDER_MODE_ON") {
intruderModeActive = true;
sdgModeActive = false;
lcd.clear();
lcd.print("Guard Mode");
beep();
setLEDColor(255, 0, 0);
}
else if (cmd == "COMMAND: INTRUDER_MODE_OFF") {
intruderModeActive = false;
lcd.clear();
lcd.print("Manual Mode");
beep();
setLEDColor(255, 255, 255);
}
else if (cmd == "COMMAND: MANUAL_MODE") {
sdgModeActive = false;
intruderModeActive = false;
lcd.clear();
lcd.print("Manual Mode");
beep();
setLEDColor(255, 255, 255);
}
else if (cmd == "COMMAND: BUZZER_BEEP") {
beep();
}
else if (cmd == "COMMAND: LED_BLINK") {
blinkLED();
}
else {
if (!sdgModeActive && !intruderModeActive) {
handleManualDrive(cmd);
}
}
}
// --- Simulated roaming movement ---
void roamAutomatically() {
unsigned long now = millis();
if (now - lastMoveTime > 2000) {
lastMoveTime = now;
roamingState = (roamingState + 1) % 4;
switch (roamingState) {
case 0:
moveForward();
break;
case 1:
rotateLeft();
break;
case 2:
moveForward();
break;
case 3:
rotateRight();
break;
}
}
}
// --- Intruder Monitoring ---
void monitorIntruder() {
distance = readUltrasonic();
if (distance < 20) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Intruder Detected!");
beep();
setLEDColor(255, 0, 0);
moveBackward();
delay(1000);
rotateLeft();
delay(1000);
stopMoving();
} else {
// No intruder and no other warnings – turn off LCD display
lcd.clear();
}
}
float getTemperature(int analogValue) {
float voltage = analogValue * 5.0 / 1023.0;
float resistance = (5.0 - voltage) * 10000.0 / voltage;
float tempK = 1.0 / (log(resistance / 10000.0) / 3950.0 + (1.0 / 298.15));
return tempK - 273.15;
}
int getDistance() {
digitalWrite(ULTRASONIC_TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(ULTRASONIC_TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(ULTRASONIC_TRIGGER_PIN, LOW);
long duration = pulseIn(ULTRASONIC_ECHO_PIN, HIGH);
return duration * 0.034 / 2;
}
void setColor(int r, int g, int b) {
analogWrite(LED_R_PIN, r);
analogWrite(LED_G_PIN, g);
analogWrite(LED_B_PIN, b);
}
// --- Sensor Checks ---
void checkSensors() {
// Example for a multi-sensor system (temperature + light + distance)
// --- Temperature Monitoring ---
int digitalTemp = digitalRead(4); // Assume A0 for thermistor
float temperature = getTemperature(digitalTemp);
if (temperature >= HIGH_TEMP_THRESHOLD) {
lcd.setCursor(0, 0);
lcd.print("TEMP ALERT: ");
lcd.print(temperature);
lcd.print("C ");
lcd.setCursor(0, 1);
lcd.print("High Heat Level");
// High temp: rapid purple flashing + buzzer
tone(BUZZER_PIN, 1000);
digitalWrite(LED_R_PIN, HIGH);
digitalWrite(LED_B_PIN, HIGH);
digitalWrite(LED_G_PIN, LOW);
delay(100);
noTone(BUZZER_PIN);
digitalWrite(LED_R_PIN, LOW);
digitalWrite(LED_B_PIN, LOW);
delay(100);
}
// --- Light Intrusion Detection ---
int lightValue = digitalRead(2);
if (lightValue > lightThreshold) {
lcd.setCursor(0, 0);
lcd.print("INTRUDER ALERT ");
lcd.setCursor(0, 1);
lcd.print("Bright Light ");
for (int i = 0; i < 5; i++) {
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_R_PIN, HIGH);
digitalWrite(LED_G_PIN, LOW);
digitalWrite(LED_B_PIN, LOW);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_R_PIN, LOW);
delay(100);
}
}
// --- Ultrasonic Distance Alert ---
int distance = getDistance();
if (distance > 0 && distance <= dangerDistance) {
lcd.setCursor(0, 0);
lcd.print("MOTION DETECTED ");
lcd.setCursor(0, 1);
lcd.print("Dist: ");
lcd.print(distance);
lcd.print(" cm ");
for (int i = 0; i < 3; i++) {
digitalWrite(BUZZER_PIN, HIGH);
setColor(255, 0, 0); // Red
delay(150);
digitalWrite(BUZZER_PIN, LOW);
setColor(0, 0, 0); // Off
delay(150);
}
}
// --- Normal State ---
if (temperature < HIGH_TEMP_THRESHOLD && lightValue <= lightThreshold && (distance > dangerDistance || distance <= 0)) {
lcd.setCursor(0, 0);
lcd.print("Monitoring... ");
lcd.setCursor(0, 1);
lcd.print("All Normal ");
noTone(BUZZER_PIN);
setColor(0, 255, 0); // Green
delay(500);
}
}
// --- Helper Functions ---
void beep() {
digitalWrite(BUZZER_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
}
void setLEDColor(int r, int g, int b) {
analogWrite(LED_R_PIN, r);
analogWrite(LED_G_PIN, g);
analogWrite(LED_B_PIN, b);
}
void blinkLED() {
setLEDColor(255, 255, 0);
delay(100);
setLEDColor(0, 0, 0);
delay(100);
setLEDColor(255, 255, 0);
delay(100);
setLEDColor(0, 0, 0);
}
long readUltrasonic() {
digitalWrite(ULTRASONIC_TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(ULTRASONIC_TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(ULTRASONIC_TRIGGER_PIN, LOW);
long duration = pulseIn(ULTRASONIC_ECHO_PIN, HIGH, 20000);
return duration * 0.034 / 2;
}
void moveForward() {
if (obstacleDetected && !ramModeActive) {
stopMoving();
return;
}
setAllMotors(FORWARD);
Serial.println("MOVING: FORWARD");
}
void moveBackward() {
setAllMotors(BACKWARD);
Serial.println("MOVING: BACKWARD");
}
void rotateLeft() {
motor1.setSpeed(motorSpeed);
motor2.setSpeed(motorSpeed);
motor3.setSpeed(motorSpeed);
motor4.setSpeed(motorSpeed);
motor1.run(BACKWARD);
motor2.run(FORWARD);
motor3.run(BACKWARD);
motor4.run(FORWARD);
Serial.println("MOVING: ROTATE LEFT");
}
void rotateRight() {
motor1.setSpeed(motorSpeed);
motor2.setSpeed(motorSpeed);
motor3.setSpeed(motorSpeed);
motor4.setSpeed(motorSpeed);
motor1.run(FORWARD);
motor2.run(BACKWARD);
motor3.run(FORWARD);
motor4.run(BACKWARD);
Serial.println("MOVING: ROTATE RIGHT");
}
void stopMoving() {
motor1.setSpeed(0);
motor2.setSpeed(0);
motor3.setSpeed(0);
motor4.setSpeed(0);
motor1.run(RELEASE);
motor2.run(RELEASE);
motor3.run(RELEASE);
motor4.run(RELEASE);
Serial.println("MOVING: STOPPED");
}
void setAllMotors(uint8_t dir) {
motor1.setSpeed(motorSpeed);
motor2.setSpeed(motorSpeed);
motor3.setSpeed(motorSpeed);
motor4.setSpeed(motorSpeed);
motor1.run(dir);
motor2.run(dir);
motor3.run(dir);
motor4.run(dir);
}
void handleManualDrive(String cmd) {
if (cmd == "COMMAND: FORWARD") moveForward();
else if (cmd == "COMMAND: BACKWARD") moveBackward();
else if (cmd == "COMMAND: LEFT") rotateLeft();
else if (cmd == "COMMAND: RIGHT") rotateRight();
else if (cmd == "COMMAND: FORWARD_SMOOTH") moveForward();
else if (cmd == "COMMAND: BACKWARD_SMOOTH") moveBackward();
else if (cmd == "COMMAND: LEFT_SMOOTH") rotateLeft();
else if (cmd == "COMMAND: RIGHT_SMOOTH") rotateRight();
else if (cmd == "COMMAND: ROTATE_LEFT_SERVO") {
ultrasonicServo.write(45); // Rotate servo to the left
Serial.println("Ultrasonic Sensor Rotated Left.");
}
else if (cmd == "COMMAND: ROTATE_RIGHT_SERVO") {
ultrasonicServo.write(135); // Rotate servo to the right
Serial.println("Ultrasonic Sensor Rotated Right.");
}
else if (cmd == "COMMAND: ROTATE_180_SERVO") {
ultrasonicServo.write(180); // Rotate servo to 180 degrees
Serial.println("Ultrasonic Sensor Rotated to 180 degrees.");
}
else if (cmd == "COMMAND: KICK_LEFT") rotateLeft();
else if (cmd == "COMMAND: KICK_RIGHT") rotateRight();
else if (cmd == "COMMAND: STOP") stopMoving();
else if (cmd == "COMMAND: RAM") { // Cross button pressed
ramModeActive = true;
motorSpeed = 255;
moveForward();
delay(1000);
motorSpeed = 128;
ramModeActive = false;
stopMoving();
}
else if (cmd == "COMMAND: AUTO_RAM") { // Triangle button pressed
ramModeActive = true;
motorSpeed = 255;
moveForward();
}
else if (cmd == "COMMAND: MAX_SPEED") motorSpeed = 255;
else if (cmd == "COMMAND: MIN_SPEED") motorSpeed = 128;
else if (cmd == "COMMAND: STOP_RAM") {
ramModeActive = false;
stopMoving();
}
else if (cmd == "COMMAND: NORMAL_SPEED") {
motorSpeed = 128;
}
}
ESP32 Code (AI Thinker ESP32 board)
#include <Bluepad32.h>
ControllerPtr myController;
// Servo Rotation control flag
int servoAngle = 90; // Default servo angle
// Mode activation flags
bool sdgModeActive = false;
bool intruderModeActive = false;
// Function to process PS4 controller inputs
void processGamepad(ControllerPtr ctl) {
if (!ctl) return;
int axisRX = ctl->axisRX(); // Right joystick X-axis
int axisRY = ctl->axisRY(); // Right joystick Y-axis
// Map the R-joystick X-axis to a servo angle between 0 and 180
servoAngle = map(axisRX, -512, 512, 0, 180);
// --- L-stick for smooth movement ---
int axisLX = ctl->axisX(); // Left joystick X-axis (left-right)
int axisLY = ctl->axisY(); // Left joystick Y-axis (up-down)
// If the left analog stick is pushed up (forward), move forward
if (axisLY < -200) { // Threshold for moving forward
Serial.println("L-Stick Up: Move Forward Smoothly");
Serial.println("COMMAND: FORWARD_SMOOTH");
Serial1.println("L-Stick Up: Move Forward Smoothly");
Serial1.println("COMMAND: FORWARD_SMOOTH");
}
// If the left analog stick is pushed down (backward), move backward
else if (axisLY > 200) { // Threshold for moving backward
Serial.println("L-Stick Down: Move Backward Smoothly");
Serial.println("COMMAND: BACKWARD_SMOOTH");
Serial1.println("L-Stick Down: Move Backward Smoothly");
Serial1.println("COMMAND: BACKWARD_SMOOTH");
}
// If the left analog stick is pushed left (left), move left
if (axisLX < -200) { // Threshold for moving left
Serial.println("L-Stick Left: Move Left Smoothly");
Serial.println("COMMAND: LEFT_SMOOTH");
Serial1.println("L-Stick Left: Move Left Smoothly");
Serial1.println("COMMAND: LEFT_SMOOTH");
}
// If the left analog stick is pushed right (right), move right
else if (axisLX > 200) { // Threshold for moving right
Serial.println("L-Stick Right: Move Right Smoothly");
Serial.println("COMMAND: RIGHT_SMOOTH");
Serial1.println("L-Stick Right: Move Right Smoothly");
Serial1.println("COMMAND: RIGHT_SMOOTH");
}
// Send the servo angle to Arduino
Serial1.print("SERVO: ");
Serial1.println(servoAngle);
Serial.print("SERVO: ");
Serial.println(servoAngle);
uint16_t buttons = ctl->buttons();
// --- D-Pad for movement ---
if (ctl->dpad() == DPAD_UP) {
Serial.println("D-Pad Up: Move Forward");
Serial.println("COMMAND: FORWARD");
Serial1.println("D-Pad Up: Move Forward");
Serial1.println("COMMAND: FORWARD");
}
else if (ctl->dpad() == DPAD_DOWN) {
Serial.println("D-Pad Down: Move Backward");
Serial.println("COMMAND: BACKWARD");
Serial1.println("D-Pad Down: Move Backward");
Serial1.println("COMMAND: BACKWARD");
}
else if (ctl->dpad() == DPAD_LEFT) {
Serial.println("D-Pad Left: Move Left");
Serial.println("COMMAND: LEFT");
Serial1.println("D-Pad Left: Move Left");
Serial1.println("COMMAND: LEFT");
}
else if (ctl->dpad() == DPAD_RIGHT) {
Serial.println("D-Pad Right: Move Right");
Serial.println("COMMAND: RIGHT");
Serial1.println("D-Pad Right: Move Right");
Serial1.println("COMMAND: RIGHT");
}
// --- SDG Mode Toggle (L3 + R3) ---
if (buttons == (0x0100 | 0x0200)) { // L3 + R3 pressed
delay(200); // Small delay for stable button reading
if (!sdgModeActive) {
Serial.println("L3 + R3: Activate SDG Mode");
Serial.println("COMMAND: SDG_MODE");
Serial1.println("L3 + R3: Activate SDG Mode");
Serial1.println("COMMAND: SDG_MODE");
sdgModeActive = true;
intruderModeActive = false; // Ensure intruder mode is off
} else {
Serial.println("L3 + R3: Deactivate SDG Mode (Return to Manual)");
Serial.println("COMMAND: SDG_MODE_OFF");
Serial1.println("L3 + R3: Deactivate SDG Mode (Return to Manual)");
Serial1.println("COMMAND: SDG_MODE_OFF");
sdgModeActive = false;
}
}
// --- Intruder Alert Mode Toggle (R3 only) ---
else if (buttons == 0x0200) { // R3 pressed
delay(200); // Small delay for stable button reading
if (!intruderModeActive) {
Serial.println("R3: Activate Intruder Alert Mode");
Serial.println("COMMAND: INTRUDER_ALERT_MODE");
Serial1.println("R3: Activate Intruder Alert Mode");
Serial1.println("COMMAND: INTRUDER_ALERT_MODE");
intruderModeActive = true;
sdgModeActive = false; // Ensure SDG mode is off
} else {
Serial.println("R3: Deactivate Intruder Mode (Return to Manual)");
Serial.println("COMMAND: INTRUDER_ALERT_MODE_OFF");
Serial1.println("R3: Deactivate Intruder Mode (Return to Manual)");
Serial1.println("COMMAND: INTRUDER_ALERT_MODE_OFF");
intruderModeActive = false;
}
}
// --- L3 Only ---
else if (buttons == 0x0100) { // L3 pressed alone
delay(200);
Serial.println("L3: Manual Mode Activated (Forced)");
Serial.println("COMMAND: MANUAL_MODE");
Serial1.println("L3: Manual Mode Activated (Forced)");
Serial1.println("COMMAND: MANUAL_MODE");
// Reset modes
sdgModeActive = false;
intruderModeActive = false;
// Feedback: Buzzer beep and LED blink command
Serial.println("COMMAND: BUZZER_BEEP");
Serial.println("COMMAND: LED_BLINK");
Serial1.println("COMMAND: BUZZER_BEEP");
Serial1.println("COMMAND: LED_BLINK");
}
// --- Normal manual controls ---
else if (!sdgModeActive && !intruderModeActive) {
// Handle button commands ONLY if no mode is active
if (buttons == 0x0001) { // Cross button
Serial.println("CROSS: RAM FORWARD");
Serial.println("COMMAND: FORWARD");
Serial1.println("CROSS: RAM FORWARD");
Serial1.println("COMMAND: FORWARD");
}
if (buttons == 0x0002) { // Circle button
Serial.println("CIRCLE: Kick Left");
Serial.println("COMMAND: KICK_LEFT");
Serial1.println("CIRCLE: Kick Left");
Serial1.println("COMMAND: KICK_LEFT");
}
if (buttons == 0x0004) { // Square button
Serial.println("SQUARE: Rotate Left");
Serial.println("COMMAND: ROTATE_LEFT");
Serial1.println("SQUARE: Rotate Left");
Serial1.println("COMMAND: ROTATE_LEFT");
}
if (buttons == 0x0008) { // Triangle button
Serial.println("TRIANGLE: Rotate Right");
Serial.println("COMMAND: ROTATE_RIGHT");
Serial1.println("TRIANGLE: Rotate Right");
Serial1.println("COMMAND: ROTATE_RIGHT");
}
if (buttons == 0x0040) { // L2 button
Serial.println("L2: Decelerate and Stop");
Serial.println("COMMAND: STOP");
Serial1.println("L2: Decelerate and Stop");
Serial1.println("COMMAND: STOP");
}
if (buttons == 0x0080) { // R2 button
Serial.println("R2: Accelerate at Max Speed");
Serial.println("COMMAND: MAX_SPEED");
Serial1.println("R2: Accelerate at Max Speed");
Serial1.println("COMMAND: MAX_SPEED");
}
// Handle L1 and R1 (Servo Rotation)
if (buttons == 0x0010) { // L1
Serial.println("L1: Rotate Servo Left");
Serial.println("COMMAND: ROTATE_LEFT_SERVO");
Serial1.println("L1: Rotate Servo Left");
Serial1.println("COMMAND: ROTATE_LEFT_SERVO");
}
if (buttons == 0x0020) { // R1
Serial.println("R1: Rotate Servo Right");
Serial.println("COMMAND: ROTATE_RIGHT_SERVO");
Serial1.println("R1: Rotate Servo Right");
Serial1.println("COMMAND: ROTATE_RIGHT_SERVO");
}
if (buttons == (0x0010 | 0x0020)) { // L1 + R1
Serial.println("L1 + R1: Rotate Servo to 180 degrees");
Serial.println("COMMAND: ROTATE_180_SERVO");
Serial1.println("L1 + R1: Rotate Servo to 180 degrees");
Serial1.println("COMMAND: ROTATE_180_SERVO");
}
}
}
void onConnect(ControllerPtr ctl) {
Serial1.println("Controller Connected");
myController = ctl;
}
void onDisconnect(ControllerPtr ctl) {
Serial1.println("Controller Disconnected");
myController = nullptr;
}
void setup() {
Serial.begin(19200);
// Use GPIO2 as RX and GPIO4 as TX for Serial1
Serial1.begin(19200, SERIAL_8N1, 2, 4);
BP32.setup(&onConnect, &onDisconnect);
BP32.forgetBluetoothKeys();
}
void loop() {
bool dataUpdated = BP32.update();
if (dataUpdated) {
processGamepad(myController);
}
delay(10); // Small delay for smoother operation
}