R2D2 Creation with Codey πŸ€– Ep.6

Published: (June 7, 2026 at 10:13 AM EDT)
9 min read
Source: Dev.to

Source: Dev.to

Episode 6: Let the Wookiee Win β€” R2 Moves!

β€œWould Somebody Get This Big Walking Carpet Out of My Way?” 🦾

Han Solo enters the workshop with the energy of someone who has been waiting since Episode 1 for this moment.

HAN: β€œOkay, look. I’ve put up with the blinking LED. The beeps were cute. The screen β€” fine, useful. But I need this droid to actually MOVE. Because right now he’s sitting there like a very opinionated lamp and I am not impressed.”

R2-D2 beeps at high volume and at length.

HAN: β€œYeah yeah, I know, you’re very capable. Prove it. Episode 6. Let’s go.”

Somewhere, a Wookiee roars enthusiastically.

HAN: β€œChewie agrees. Let the droid move.”

πŸ—‚οΈ SIPOC β€” The Motion System

Suppliers Inputs Process Outputs Customers

You (the maker) β€œAdd servo for dome rotation on GPIO14, L298N motor driver for wheels on GPIO pins 25-27” Codey writes ESP32-S3 LEDC servo code + L298N motor control, generates motion.h Dome that sweeps left and right, wheels that drive forward/back/turn R2-D2 β€” who finally lives up to his reputation

ESP32-S3 LEDC PWM 50Hz PWM signal, 3.3V Drives servo signal line (with level shifter) Dome servo at 0Β°, 45Β°, 90Β°, 135Β°, 180Β° SG90 servo β€” which rotates R2’s dome

L298N Motor Driver 5V–12V external power, direction + PWM signals from ESP32-S3 H-bridge controls current direction to each DC motor Forward / backward / left turn / right turn Two DC motors β€” which drive R2’s wheels

Codey Wiring Diagram Full component list including motor power requirements Draws color-coded diagram with separate power rail for motors Two-rail wiring diagram: logic (3.3V) + motor power You β€” who correctly separate the motor power from the logic power

The Components πŸ”§

Yoda examines the motor driver with a long, thoughtful look.

YODA: β€œMoving parts, added today we are. Careful, one must be. Motors, hungry for current they are. Directly from the ESP32-S3, power them you must not β€” destroyed, your microcontroller would be.”

Component Quantity Notes

ESP32-S3 N16R8 1 Our brain from Episode 5

SG90 micro servo 1 For dome rotation β€” 5V, 3-wire

L298N dual H-bridge motor driver 1 Drives two DC motors, needs separate 5V–12V

DC gear motors with wheels 2 3V–6V, ~200mA stall current each

74AHCT125 level shifter 1 Servo signal: 3.3V β†’ 5V

9V battery or 2S LiPo 1 Motor power supply β€” separate from logic

Jumper wires 12 Several gauge sizes

USB cable 1

YODA: β€œTwo power rails, we shall have. Logic power: USB 5V β†’ 3.3V for ESP32-S3. Motor power: separate battery for L298N and motors. Cross them, you must not.”

The ESP32-S3 and Servo Control: LEDC at 50Hz βš™οΈ

C-3PO raises a cautionary finger.

C-3PO: β€œI must explain the servo PWM situation. The Arduino Servo library used the Timer1 hardware. On the ESP32-S3, we use the LEDC peripheral β€” the same one we used for the buzzer tone in Episode 5, but configured at 50Hz for servo control. A standard hobby servo expects a pulse between 0.5ms and 2.5ms at a 50Hz frequency. Codey handles this calculation automatically.”

HAN: β€œThree-PO. The servo. Just the servo.”

C-3PO: β€œYes. Moving on.”

In Agent mode:

We're continuing R2-D2 on ESP32-S3 N16R8.

Add motion systems:

1. SG90 servo for dome rotation:
   - Signal on GPIO14 (through 74AHCT125 level shifter)
   - 5V power from VIN rail
   - Create these movements:
     a. idle_scan: slow sweep 60Β°β†’120Β° and back, 3 second period
     b. alert_snap: snap to face sensor direction
     c. full_sweep: 0Β° to 180Β° and back when "happy"

2. L298N motor driver for two DC wheels:
   - Motor A: IN1=GPIO25, IN2=GPIO26, ENA=GPIO27 (PWM)
   - Motor B: IN3=GPIO32, IN4=GPIO33, ENB=GPIO34 (PWM)
   - Create: forward(), backward(), turnLeft(), turnRight(), stop()
   - Speed: 0-255 mapped to LEDC duty cycle

3. Behavior: when distance = 120) domeSweepDir = -1;
  if (currentDomeAngle = 180) { fullSweepDir = -1; }
  if (fullSweepAngle <= 0)   { fullSweepDone = true; }
  setDomeAngle(fullSweepAngle);
}

// ── L298N MOTOR DRIVER ────────────────────────────────────────────
#define MOTOR_A_IN1  25
#define MOTOR_A_IN2  26
#define MOTOR_A_EN   27   // PWM channel 2

#define MOTOR_B_IN3  32
#define MOTOR_B_IN4  33
#define MOTOR_B_EN   34   // PWM channel 3

#define MOTOR_CHANNEL_A  2
#define MOTOR_CHANNEL_B  3
#define MOTOR_FREQ       5000   // 5kHz PWM for motors
#define MOTOR_RES        8      // 8-bit β†’ 0–255

void initMotors() {
  // Direction pins
  pinMode(MOTOR_A_IN1, OUTPUT);
  pinMode(MOTOR_A_IN2, OUTPUT);
  pinMode(MOTOR_B_IN3, OUTPUT);
  pinMode(MOTOR_B_IN4, OUTPUT);

  // PWM channels for enable pins
  ledcSetup(MOTOR_CHANNEL_A, MOTOR_FREQ, MOTOR_RES);
  ledcSetup(MOTOR_CHANNEL_B, MOTOR_FREQ, MOTOR_RES);
  ledcAttachPin(MOTOR_A_EN, MOTOR_CHANNEL_A);
  ledcAttachPin(MOTOR_B_EN, MOTOR_CHANNEL_B);

  // Start stopped
  ledcWrite(MOTOR_CHANNEL_A, 0);
  ledcWrite(MOTOR_CHANNEL_B, 0);
  Serial.println("Motor driver online.");
}

void motorForward(uint8_t speed = 180) {
  digitalWrite(MOTOR_A_IN1, HIGH); digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN3, HIGH); digitalWrite(MOTOR_B_IN4, LOW);
  ledcWrite(MOTOR_CHANNEL_A, speed);
  ledcWrite(MOTOR_CHANNEL_B, speed);
}

void motorBackward(uint8_t speed = 180) {
  digitalWrite(MOTOR_A_IN1, LOW);  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN3, LOW);  digitalWrite(MOTOR_B_IN4, HIGH);
  ledcWrite(MOTOR_CHANNEL_A, speed);
  ledcWrite(MOTOR_CHANNEL_B, speed);
}

void motorTurnLeft(uint8_t speed = 150) {
  // Left motor backward, right motor forward = left turn
  digitalWrite(MOTOR_A_IN1, LOW);  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN3, HIGH); digitalWrite(MOTOR_B_IN4, LOW);
  ledcWrite(MOTOR_CHANNEL_A, speed);
  ledcWrite(MOTOR_CHANNEL_B, speed);
}

void motorTurnRight(uint8_t speed = 150) {
  // Left motor forward, right motor backward = right turn
  digitalWrite(MOTOR_A_IN1, HIGH); digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN3, LOW);  digitalWrite(MOTOR_B_IN4, HIGH);
  ledcWrite(MOTOR_CHANNEL_A, speed);
  ledcWrite(MOTOR_CHANNEL_B, speed);
}

void motorStop() {
  ledcWrite(MOTOR_CHANNEL_A, 0);
  ledcWrite(MOTOR_CHANNEL_B, 0);
  digitalWrite(MOTOR_A_IN1, LOW); digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN3, LOW); digitalWrite(MOTOR_B_IN4, LOW);
}

void initMotion() {
  initServo();
  initMotors();
}
Enter fullscreen mode


Exit fullscreen mode

Updated r2d2-main.ino loop

// Loop addition β€” reactive motion

void loop() {
  if (!bootDone) { showBootScreen(); return; }

  float dist   = readDistance();
  bool  motion = checkMotion();

  // ── Dome behaviour ─────────────────────────────────────────
  if (dist < 30.0f) {
    domeSnap(90);       // face forward, something is ahead
    motorStop();        // stop wheels β€” obstacle!
  } else if (motion) {
    domeSnap(45);       // snap left β€” motion detected
  } else {
    domeIdleSweep();    // gentle idle scan
  }

  // ── Display ─────────────────────────────────────────────────
  if (dist < 15.0f)    showAlertScreen();
  else if (motion)     showMotionScreen();
  else                 showIdleScreen(dist);

  // ── Dome lights ─────────────────────────────────────────────
  updateAnimationsSensors(dist, motion);
}
Enter fullscreen mode


Exit fullscreen mode

The Wiring Diagram β€” Two Power Rails 🧭

C-3PO studies the diagram, then exhales slowly.

C-3PO: β€œCodey has correctly separated the power rails. The logic rail β€” 3.3V from the ESP32-S3 regulator β€” powers only the microcontroller and the OLED. The motor rail β€” the external 9V battery through the L298N’s onboard 5V regulator β€” powers the motors and the servo. This is exactly correct. Mixing them would cause voltage drops that would reset the ESP32-S3 every time a motor starts.”

R2-D2 Motion System β€” Wiring Diagram (ESP32-S3 N16R8)
════════════════════════════════════════════════════════════════

POWER RAIL 1 β€” LOGIC (USB 5V β†’ ESP32-S3 regulator):
  USB 5V  ──── ESP32-S3 VIN
  ESP32 3V3 ── OLED VCC
  ESP32 GND ── OLED GND, logic GND rail

POWER RAIL 2 β€” MOTOR POWER (9V battery):
  9V Bat (+) ── L298N: VS (motor supply)
  9V Bat (βˆ’) ── L298N: GND (common ground with ESP32 GND)
  L298N: 5V  ── Servo VCC (5V regulated output)
  L298N: 5V  ── 74AHCT125: VCC
  L298N: GND ── Servo GND, 74AHCT125 GND

  ⚠️  IMPORTANT: ESP32 GND and battery GND must be connected together!

SERVO (dome rotation):
  ESP32 GPIO14 ─── 74AHCT125 A1 input (3.3V signal in)
  74AHCT125 Y1 ─── Servo Signal wire (orange/yellow) β€” 5V signal out
  L298N 5V     ─── Servo VCC (red wire)
  L298N GND    ─── Servo GND (brown/black wire)

MOTORS via L298N:
  ESP32 GPIO25 ──── L298N IN1 (Motor A direction)
  ESP32 GPIO26 ──── L298N IN2 (Motor A direction)
  ESP32 GPIO27 ──── L298N ENA (Motor A PWM speed)
  ESP32 GPIO32 ──── L298N IN3 (Motor B direction)
  ESP32 GPIO33 ──── L298N IN4 (Motor B direction)
  ESP32 GPIO34 ──── L298N ENB (Motor B PWM speed)
  L298N OUT1   ──── DC Motor A: terminal 1
  L298N OUT2   ──── DC Motor A: terminal 2
  L298N OUT3   ──── DC Motor B: terminal 1
  L298N OUT4   ──── DC Motor B: terminal 2

NeoPixel (from Episode 5):
  ESP32 GPIO6 ── 74AHCT125 A2 ── NeoPixel DIN

Color code:
  RED    = 5V / VIN power
  ORANGE = 9V battery supply
  BLACK  = GND
  PURPLE = 3.3V logic
  GREEN  = NeoPixel data (level-shifted)
  BLUE   = Servo signal (level-shifted)
  YELLOW = Motor direction signals
  WHITE  = Motor PWM (speed) signals

Connection Table:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ From                 β”‚ To                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 9V Battery (+)       β”‚ L298N: VS                            β”‚
β”‚ 9V Battery (βˆ’)       β”‚ L298N: GND + ESP32 GND (common)      β”‚
β”‚ L298N: 5V out        β”‚ Servo VCC (red), 74AHCT125 VCC       β”‚
β”‚ L298N: GND           β”‚ Servo GND, 74AHCT125 GND             β”‚
β”‚ ESP32 GPIO14         β”‚ 74AHCT125 A1 β†’ servo signal (5V)     β”‚
β”‚ ESP32 GPIO6          β”‚ 74AHCT125 A2 β†’ NeoPixel DIN (5V)     β”‚
β”‚ ESP32 GPIO25         β”‚ L298N IN1                            β”‚
β”‚ ESP32 GPIO26         β”‚ L298N IN2                            β”‚
β”‚ ESP32 GPIO27 (PWM)   β”‚ L298N ENA                            β”‚
β”‚ ESP32 GPIO32         β”‚ L298N IN3                            β”‚
β”‚ ESP32 GPIO33         β”‚ L298N IN4                            β”‚
β”‚ ESP32 GPIO34 (PWM)   β”‚ L298N ENB                            β”‚
β”‚ L298N OUT1,OUT2      β”‚ DC Motor A                           β”‚
β”‚ L298N OUT3,OUT4      β”‚ DC Motor B                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode


Exit fullscreen mode

HAN: β€œTwo power rails. That’s important. I’ve seen people blow a microcontroller trying to power motors directly off the GPIO pins. The L298N’s internal regulator gives you the 5V for the servo and the level shifter. Clean.”

R2-D2 beeps approvingly.

HAN: β€œYeah, even I have to admit that’s well done.”

Compile and Watch the Dome Spin πŸš€

βœ“ Compilation successful
  Board:   ESP32-S3 N16R8
  Sketch:  r2d2-main.ino + 5 headers
  Binary:  498,244 bytes (7.2% of 16MB Flash)
  RAM:     Used 34,128 bytes (10.4% of 327KB)
Enter fullscreen mode


Exit fullscreen mode

The dome servo sweeps slowly between 60Β° and 120Β°. R2-D2 scans the room.

Wave your hand in front of the HC-SR04. The dome snaps to 90Β°. The wheels stop. The OLED shows β€œTOO CLOSE!”

Han Solo watches the dome turn. A long pause.

HAN: ”…Okay. That’s actually pretty good.”

R2-D2 beeps.

HAN: β€œI said it was pretty good. Don’t push it.”

Save Milestone 🚩

Milestone: "R2-D2 Motion Systems β€” Episode 6 Complete"
Enter fullscreen mode


Exit fullscreen mode

Five systems running. Dome rotating. Wheels ready. The droid is almost complete.

What’s Next: R2 Gets His Voice Back πŸ”Š

Obi-Wan speaks with warmth.

OBI-WAN: β€œThe dome spins. The lights glow. The screen projects. The wheels wait. But something is still missing β€” the true voice. Not just beeps from a buzzer, but the full audio character of the galaxy’s most beloved droid. In Episode 7, we add the DFPlayer Mini and a speaker. R2-D2 will play actual audio files. And the Live Serial Monitor will show us exactly what is happening.”

R2-D2 emits a long, heartfelt whistle that says everything.

πŸ”— Resources

ESP32 LEDC (servo): randomnerdtutorials.com/esp32-servo-motor-web-server

L298N motor driver: Search β€œL298N Arduino ESP32 tutorial”

74AHCT125 level shifter: Search β€œ74AHCT125 3.3V 5V logic level converter”

Codey Online: codey.online

πŸ€– R2D2 Creation with Codey β€” building the galaxy’s greatest droid, one episode at a time. May the Force β€” and the cloud compiler β€” be with you.

0 views
Back to Blog

Related posts

Read more Β»

I'm so tired to code. Not even Vibe Coding... D:

!FrancisTRᴅᴇᴠ っ◔◑◔っhttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fupl...