Robo Race Bot

by sushma_m_09 in Circuits > Arduino

36 Views, 1 Favorites, 0 Comments

Robo Race Bot

WhatsApp Image 2026-03-14 at 8.17.25 PM (1).jpeg
WhatsApp Image 2026-03-14 at 8.17.23 PM (1).jpeg

Robotics competitions like Robo Race challenge students to design and build fast, stable, and efficient racing robots. In this project, I built a Wireless Robo Race Bot using an ESP32 microcontroller, FlySky transmitter and receiver, and Cytron MDD10A motor driver.

This robot is designed to move at high speed while maintaining stability and smooth control on racing tracks with sharp turns, zig-zag paths, and obstacles.

Supplies

Laptop with Arduino IDE.jpg
Wire Cutter.jpg
Soldering Iron.jpg
Screwdriver Set.jpg
motor &wheel.jpg
Wheel Couplers.jpg
Nuts and Bolts.jpg
Motor Mounts.jpg
Acrylic Chassis (Laser Cut).jpg
Connecting Wires.jpg
XT60 Connector.jpg
12V Lithium Battery.jpg
4 × 80mm Wheels.jpg
4 × 1000 RPM Johnson Motors.jpg
FlySky Transmitter & reciver.jpg
Cytron MDD10A Motor Driver - Copy.jpg
Cytron MDD10A Motor Driver.jpg
esp 32.jpg

Electronic Components

  1. ESP32 Dev Kit
  2. Cytron MDD10A Motor Driver
  3. FlySky Transmitter
  4. FlySky Receiver
  5. 4 × 1000 RPM Johnson Motors
  6. 4 × 80mm Wheels
  7. 12V Lithium Battery
  8. Connecting Wires
  9. XT60 Connector

Mechanical Components

  1. Acrylic Chassis (Laser Cut)
  2. Motor Mounts
  3. Nuts and Bolts
  4. Wheel Couplers

Tools Required

  1. Screwdriver Set
  2. Soldering Iron
  3. Wire Cutter
  4. Laptop with Arduino IDE
  5. USB Cable for ESP32

Software Used

  1. Arduino IDE
  2. Onshape (for chassis design)

Chassis Design

Screenshot 2026-03-17 090753.png

First, I designed the robot chassis using Onshape.

The chassis is designed to hold all components properly:

  1. Motors
  2. Battery
  3. ESP32
  4. Motor Driver
  5. FlySky Receiver

I used an acrylic sheet because it is:

  1. Lightweight
  2. Strong
  3. Easy to laser cut

The robot uses a 4-wheel chassis design for better balance and smooth movement.

This design helps the robot stay stable during racing

Assembling Components

ChatGPT Image Mar 16, 2026, 03_37_15 PM (1).png

After making the chassis, I assembled all main components.

Components assembled:

  1. 4 Johnson motors
  2. 4 wheels
  3. Cytron MDD10A motor driver

Assembly process:

  1. Fix all motors to chassis
  2. Attach wheels properly
  3. Mount Cytron motor driver
  4. Place battery section at center

This setup helps the robot move fast and stay balanced.

Soldering ESP32 and Buck Converter

WhatsApp Image 2026-03-14 at 8.17.25 PM (1).jpeg

In this step, I soldered the electronics on PCB.

Components soldered:

  1. ESP32
  2. PCB board
  3. Buck converter

The buck converter is used to reduce voltage and give proper power supply to ESP32.

After soldering:

  1. Check all connections
  2. Make sure no loose wires are present

This makes the circuit clean and stable.

Circuit Connections and Code Upload

ChatGPT Image Mar 16, 2026, 03_37_36 PM (3).png

Now connect all components together.

Connections made:

  1. PCB to Cytron motor driver
  2. Motors to motor driver
  3. ESP32 to motor driver

After connections:

  1. Open Arduino IDE
  2. Select ESP32 board
  3. Upload code

The uploaded code helps:

  1. Control motors
  2. Read FlySky signals
  3. Create WiFi dashboard

After uploading, check if ESP32 powers ON correctly.


Code : Complete Code

#include <WiFi.h>

#include <WebServer.h>

#include <Preferences.h>


// --- PIN DEFINITIONS ---

const int CH1_PIN = 2;

const int CH2_PIN = 4;

const int M1_PWM = 25; const int M1_DIR = 26;

const int M2_PWM = 27; const int M2_DIR = 33;


// PWM Config

const int M1_CH = 0;

const int M2_CH = 1;


// Variables

float speedMultiplier;

bool invertSteering;

bool swapMotors;

long lastPulse1 = 0, lastPulse2 = 0;


WebServer server(80);

Preferences preferences;


void handleRoot() {

if (server.hasArg("speed")) {

speedMultiplier = server.arg("speed").toFloat() / 100.0;

preferences.putFloat("speed", speedMultiplier);

}

if (server.hasArg("invert")) {

invertSteering = (Server.arg("invert") == "true");

preferences.putBool("invert", invertsteering);

}

if (server.hasArg("swap")) {

swapMotors = (server.arg("swap") == "true");

preferences.putBool("swap", swapMotors);

}


String html = "<html><head><meta name='viewport' content='width=device-width, initial-scale=1'>";

html += "<style>body{font-family:'Segoe UI',sans-serif; background:#1a1a1a; color:white; text-align:center; padding:20px;}";

html += ".card{background:#2d2d2d; padding:25px; border-radius:20px; box-shadow:0 10px 20px rgba(0,0,0,0.5); max-width:450px; margin:auto;}";

html += "h1{color:#00d4ff; margin-bottom:10px;} .stat-grid{display:grid; grid-template-columns:1-fr 1fr; gap:10px; margin:20px 0;}";

html += ".stat-box{background:#3d3d3d; padding:15px; border-radius:12px; border:1px solid #444;}";

html += ".slider{width:100%; height:15px; border-radius:10px; background:#444; outline:none; -webkit-appearance:none; margin:20px 0;}";

html += ".slider::-webkit-slider-thumb{-webkit-appearance:none; width:25px; height:25px; background:#00d4ff; border-radius:50%; cursor:pointer;}";

html += ".btn{display:block; width:100%; padding:15px; margin:10px 0; border-radius:10px; border:none; color:white; font-weight:bold; cursor:pointer; text-decoration:none;}";

html += ".blue{background:#007bff;} .grey{background:#555;} .green{background:#28a745;}</style>";

html += "<script>setInterval(function(){location.reload();}, 3000);</script></head><body>"; // Auto-refresh diagnostics

html += "<div class='card'><h1>ROBOT DASHBOARD</h1>";

// Diagnostics Section

html += "<div class='stat-grid'>";

html += "<div class='stat-box'><b>CH1 Pulse</b><br><span style='color:#00d4ff'>" + String(lastPulse1) + "us</span></div>";

html += "<div class='stat-box'><b>CH2 Pulse</b><br><span style='color:#00d4ff'>" + String(lastPulse2) + "us</span></div>";

html += "</div>";


// Speed Control Slider

html += "<h3>Power Limit: " + String(speedMultiplier * 100, 0) + "%</h3>";

html += "<form action='/'> <input name='speed' type='range' min='10' max='100' value='" + String(speedMultiplier * 100) + "' class='slider' onchange='this.form.submit()'>";

html += "<input type='submit' value='SET SPEED' class='btn green'></form>";

// Settings Buttons

html += "<a href='/?invert=" + String(!invertSteering ? "true" : "false") + "' class='btn blue'>STEERING: " + String(invertSteering ? "INVERSED" : "NORMAL") + "</a>";

html += "<a href='/?swap=" + String(!swapMotors ? "true" : "false") + "' class='btn grey'>MAP: " + String(swapMotors ? "SWAPPED" : "STANDARD") + "</a>";

html += "<p style='font-size:12px; color:#888; margin-top:20px;'>Connected to: " + WiFi.softAPIP().toString() + "</p>";

html += "</div></body></html>";

server.send(200, "text/html", html);

}


void setup() {

Serial.begin(115200);

preferences.begin("robot-ui", false);

speedMultiplier = preferences.getFloat("speed", 0.8);

invertSteering = preferences.getBool("invert", false);

swapMotors = preferences.getBool("swap", false);


pinMode(CH1_PIN, INPUT);

pinMode(CH2_PIN, INPUT);

pinMode(M1_DIR, OUTPUT);

pinMode(M2_DIR, OUTPUT);


ledcSetup(M1_CH, 5000, 8);

ledcSetup(M2_CH, 5000, 8);

ledcAttachPin(M1_PWM, M1_CH);

ledcAttachPin(M2_PWM, M2_CH);


WiFi.softAP("ESP32-Commander", "12345678");

Serial.print("Web UI at: "); Serial.println(WiFi.softAPIP());


server.on("/", handleRoot);

server.begin();

}


void loop() {

server.handleClient();


long rawSteer = pulseIn(CH1_PIN, HIGH, 30000);

long rawThrottle = pulseIn(CH2_PIN, HIGH, 30000);

// Store for UI display

if(rawSteer > 0) lastPulse1 = rawSteer;

if(rawThrottle > 0) lastPulse2 = rawThrottle;


if (rawThrottle > 900 && rawSteer > 900) {

int moveVal = map(rawThrottle, 1000, 2000, -255, 255);

int turnVal = map(rawSteer, 1000, 2000, -255, 255);


int leftSpeed, rightSpeed;

if (!invertSteering) {

leftSpeed = moveVal + turnVal;

rightSpeed = moveVal - turnVal;

} else {

leftSpeed = moveVal - turnVal;

rightSpeed = moveVal + turnVal;

}


leftSpeed *= speedMultiplier;

rightSpeed *= speedMultiplier;


if (swapMotors) {

controlMotor(M1_CH, M1_DIR, rightSpeed);

controlMotor(M2_CH, M2_DIR, leftSpeed);

} else {

controlMotor(M1_CH, M1_DIR, leftSpeed);

controlMotor(M2_CH, M2_DIR, rightSpeed);

}

} else {

ledcWrite(M1_CH, 0);

ledcWrite(M2_CH, 0);

}

}


void controlMotor(int channel, int dirPin, int speed) {

speed = constrain(speed, -255, 255);

if (abs(speed) < 20) {

ledcWrite(channel, 0);

} else {

digitalWrite(dirPin, speed > 0 ? HIGH : LOW);

ledcWrite(channel, abs(speed));

}

}

Connect FlySky Receiver and Run the Bot

WhatsApp Image 2026-03-14 at 8.17.21 PM (1).jpeg

Final step is connecting the receiver and battery.

Connections:

  1. FlySky receiver to ESP32
  2. Battery to motor driver

After connecting:

  1. Turn ON battery
  2. Turn ON FlySky transmitter
  3. Check receiver connection
  4. Test movement

Now the robot is ready to:

  1. Move forward
  2. Move backward
  3. Turn left
  4. Turn right

The Robo Race Bot is now ready for competition.