Community project

App-Controlled Wall-E Robot

Arduino
Photo of App-Controlled Wall-E Robot

Erik Alvarez

Published October 22, 2026

Build a Wall-E inspired robot that responds to commands from a smartphone via Bluetooth. This tracked robot features articulated hands and head controlled by servo motors, blue LED eyes, and sound playback capabilities, all powered by a rechargeable lithium battery pack and coordinated by an Arduino Uno microcontroller.

This guide provides a complete parts list, wiring diagram showing connections between the motor driver, servo controller, Bluetooth module, and audio playback circuit, step-by-step assembly instructions, and Arduino firmware with Bluetooth command handling. Builders will learn how to integrate multiple motor types, manage power distribution from a 24V buck converter, and create interactive robot behaviors through serial communication.

Wiring diagram

Wiring diagram for App-Controlled Wall-E Robot

Gather all the parts

QtyComponent
1

24v Buck Converter

Ajustado a 5.0 V para Arduino, PCA9685 y audio

LM2596-based adjustable step-down buck converter module. Commonly used to regulate a higher battery rail, such as a 2S 18650 pack, down to 5V for Arduino logic. It is a regulator, not a charger or battery protection board.

1

Módulo controlador doble de motores L298N

La placa que cambia el sentido y la velocidad de los dos motores de las orugas.

1

Motorreductor tipo D de 12 V (oruga izquierda)

Motor con caja reductora que mueve la oruga izquierda del robot.

1

Motorreductor tipo D de 12 V (oruga derecha)

Motor con caja reductora que mueve la oruga derecha del robot.

1

Controlador de servos PCA9685 de 16 canales

Placa que genera las señales precisas para mover los servos de las manos y la cabeza con una alimentación separada de 5 V.

1

MG996R Servo Motor

Servo de mano izquierda, giro limitado a ±45°

High-torque digital metal gear RC servo motor by TowerPro. Operating voltage 4.8V-7.2V (nominal 5V-6V external supply). Standard RC servo control: 50 Hz signal with roughly 500-2500 us pulse width for 0-180 degree rotation. Three-wire interface: Brown = GND, Red = VCC, Orange = signal. Stall current can reach about 2.5A at 6V, so use a dedicated external servo supply and common ground with the controller. Add bulk capacitance across the servo rail when driving one or more servos. Torque: 9.4 kg.cm (4.8V) / 11 kg.cm (6V).

1

MG996R Servo Motor

Servo de mano derecha, giro limitado a ±45°

High-torque digital metal gear RC servo motor by TowerPro. Operating voltage 4.8V-7.2V (nominal 5V-6V external supply). Standard RC servo control: 50 Hz signal with roughly 500-2500 us pulse width for 0-180 degree rotation. Three-wire interface: Brown = GND, Red = VCC, Orange = signal. Stall current can reach about 2.5A at 6V, so use a dedicated external servo supply and common ground with the controller. Add bulk capacitance across the servo rail when driving one or more servos. Torque: 9.4 kg.cm (4.8V) / 11 kg.cm (6V).

1

MG996R Servo Motor

Servo de cabeza, giro limitado a ±45°

High-torque digital metal gear RC servo motor by TowerPro. Operating voltage 4.8V-7.2V (nominal 5V-6V external supply). Standard RC servo control: 50 Hz signal with roughly 500-2500 us pulse width for 0-180 degree rotation. Three-wire interface: Brown = GND, Red = VCC, Orange = signal. Stall current can reach about 2.5A at 6V, so use a dedicated external servo supply and common ground with the controller. Add bulk capacitance across the servo rail when driving one or more servos. Torque: 9.4 kg.cm (4.8V) / 11 kg.cm (6V).

1

Hc 05 Bluetooth Module

Serial Bluetooth module for wireless communication using UART interface. Operates at 9600 baud (Data Mode) or 38400 baud (AT Command Mode). Supports two-way full-duplex wireless functionality with range up to 100m.

1

Resistor

1 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

2 kΩ

Through-hole resistor (current-limiting in series with an LED)

1

Módulo grabador/reproductor ISD1820-S16

Módulo que graba una frase mediante su micrófono y la reproduce por una bocina al recibir una orden.

1

8Ω Speaker

8 Ω, 0.5–3 W

Generic small 8Ω 0.5-3W loudspeaker (~28mm typical). Pair with an I2S amp (MAX98357A) or class-D amp (TPA3116D2) for usable volume; do not drive directly from a GPIO pin. Audio output for music/voice playback.

1

BMS 3S 40 A para baterías de litio

Placa de protección que evita sobrecarga, descarga excesiva y cortocircuitos en el paquete de tres pilas.

1

Paquete 3S de tres pilas 18650 de 1800 mAh

11.1 V nominal, 12.6 V cargado, 1800 mAh

Tres pilas recargables de litio conectadas en serie para producir 11.1 V nominales y alimentar el robot.

1

Cargador CC/CV 12.6 V 2 A para batería 3S

Eliminador cargador que recarga el paquete de tres pilas de litio mediante el BMS.

1

Convertidor reductor de 5 V y mínimo 5 A

5 V, ≥5 A

Módulo regulador que baja la batería a 5 V estables para los tres servos.

1

Regleta de distribución protegida de 12 V

Regleta o bloque de terminales que reparte la salida protegida de la batería hacia motores, reguladores y cargador.

1

LED

Azul, 5 mm

Standard 3mm/5mm through-hole LED. A current-limiting series resistor is added automatically.

1

LED

Azul, 5 mm

Standard 3mm/5mm through-hole LED. A current-limiting series resistor is added automatically.

1

Resistor

220 Ω

Through-hole resistor (current-limiting in series with an LED)

1

Resistor

220 Ω

Through-hole resistor (current-limiting in series with an LED)

Assemble it in 7 steps

1. Prepara el paquete de batería protegido

Monta las tres pilas 18650 idénticas en serie dentro de un portapilas o paquete con aislamiento. Conecta PACK− a B−, la primera unión de pilas a B1, la segunda unión a B2 y PACK+ a B+ del BMS. Desde este momento, usa solamente P+ y P− del BMS como salida del paquete.

  • Comprueba con un multímetro que el paquete mide aproximadamente 9 a 12.6 V entre P+ y P− antes de conectar otros módulos.
  • No inviertas B−, B1, B2 y B+: una conexión equivocada en el BMS puede dañar las pilas o la placa.
  • No unas pilas con distinta carga, marca o estado; una pila dañada o caliente debe retirarse.

2. Conecta carga y los reguladores

Conecta el positivo del cargador de 12.6 V a P+ del BMS y su negativo a P−. Lleva también P+ y P− a la entrada del LM2596 y a la entrada del regulador de 5 V de al menos 5 A. Antes de enchufar el Arduino, ajusta el LM2596 con multímetro a 9.0 V y conecta su salida positiva a VIN del Uno y su salida negativa a GND. Ajusta el segundo regulador a 5.0 V.

  • Ajusta cada regulador sin cargas conectadas y vuelve a medir su salida.
  • La salida de 5 V alimenta los servos, el PCA9685, el HC-05, el ISD1820 y el pin 5V del L298N.
  • Nunca conectes 9 V o el paquete de batería directamente al pin 5V: puede quemar los módulos.
  • No conectes la salida de 5 V de un regulador a la salida de 5 V del otro regulador; comparten solo GND.

3. Cablea las orugas y el controlador de motores

Conecta P+ del BMS a VS del L298N (potencia de motores) y P− a GND (tierra). Conecta el regulador de 5 V al pin 5V del L298N (alimentación de control). Conecta OUT1 y OUT2 al motor izquierdo, y OUT3 y OUT4 al motor derecho. Lleva ENA a D3 (velocidad), IN1 a D4, IN2 a D5, IN3 a D6, IN4 a D7 y ENB a D11 (velocidad) del Arduino.

  • Si una oruga gira al revés, intercambia solamente sus dos cables en OUT1/OUT2 o OUT3/OUT4.
  • Retira los pequeños puentes ENA y ENB del L298N para que D3 y D11 puedan controlar la velocidad.
  • El L298N puede calentarse al mover el robot; detén el robot si no puedes tocar el disipador durante más de un instante.
  • Mantén los cables de motor gruesos y lejos de los cables de señal para reducir reinicios.

4. Conecta los servos de manos y cabeza

Conecta el PCA9685 al Arduino: VCC a 5 V (alimentación), GND a GND (tierra), SDA a A4 (datos) y SCL a A5 (reloj). Conecta V+ del PCA9685 al regulador de 5 V y su GND al mismo GND. Enchufa señal, rojo y marrón/negro del servo de mano izquierda en canal 0; mano derecha en canal 1; cabeza en canal 2. Los cables rojos van al lado V+ y los oscuros al lado GND.

  • Monta primero los brazos y la cabeza centrados mecánicamente antes de atornillar los brazos del servo.
  • El programa inicia los tres servos en el centro y limita su recorrido entre 45° y 135°.
  • No alimentes estos servos desde el pin 5V del Arduino; se reiniciaría o se podría dañar.
  • Asegúrate de que V+ y GND no estén intercambiados — alimentar un servo al revés puede dañarlo.

5. Conecta Bluetooth y el sonido

Conecta VCC del HC-05 a 5 V y GND a GND. Conecta TX del HC-05 a D8 (datos que llegan al Arduino). Para proteger RX del HC-05, conecta D9 a una resistencia de 1 kΩ; une su otro extremo con una resistencia de 2 kΩ y con RX del HC-05; conecta el extremo libre de la resistencia de 2 kΩ a GND. Conecta VCC y GND del ISD1820 a 5 V y GND, PLAYE a D10, y SP+ y SP− a los dos terminales de la bocina de 8 Ω.

  • Para grabar, mantén pulsado REC del propio ISD1820 mientras hablas cerca de su micrófono; suelta REC al terminar.
  • Empareja el teléfono con el HC-05 y configura tu app para enviar caracteres por Bluetooth a 9600 baudios.
  • No uses la bocina de 4 Ω con el ISD1820; una bocina de 8 Ω evita sobrecargar su salida.
  • El divisor de resistencias es importante: evita que los 5 V de D9 lleguen directamente al pin RX del HC-05.

6. Monta los dos ojos azules

Para el ojo izquierdo, conecta la pata larga del LED a una resistencia de 220 Ω y el otro extremo de esa resistencia a D12 (luz). Conecta la pata corta del LED a GND (tierra). Para el ojo derecho, conecta su pata larga a otra resistencia de 220 Ω y el otro extremo a D13 (luz); conecta su pata corta a GND (tierra). Al encender el robot, los dos ojos quedan iluminados.

  • En un LED normal, la pata larga es el positivo; la pata corta y el lado plano son el negativo.
  • Puedes fijar los LED detrás de los huecos de los ojos con una gota de silicona caliente, sin cubrir sus patas ni dejar que se toquen.
  • Cada LED necesita su propia resistencia de 220 Ω; conectarlo directo al Arduino puede quemar el LED o dañar el pin.
  • Desconecta la batería antes de conectar los ojos y evita que las patas desnudas se toquen.

7. Prueba y controla el robot

Con el robot levantado para que las orugas no toquen la mesa, enciende la batería y verifica que no haya cables calientes. Los ojos azules deben iluminarse. Después de cargar el programa, usa tu app Bluetooth para enviar F adelante, B atrás, L izquierda, R derecha y S parar. Usa A/Z para mano izquierda, D/C para mano derecha, H/N para cabeza y P para iniciar el audio manualmente.

  • El programa inicia y repite automáticamente el audio aproximadamente cada 11 segundos; ajusta ese tiempo luego si tu grabación dura más.
  • Cada orden de mano o cabeza cambia 5° y nunca permite superar 45° desde el centro.
  • Prueba sin personas, mascotas ni objetos cerca de las orugas: el robot puede arrancar al recibir una orden Bluetooth.
  • Desconecta la batería antes de mover cables o cambiar conexiones.

Review all connections

1. Connections between "battery_3s" and "Arduino"

Functionbattery_3sArduino
powerPACK+ → BMS 3S 40 A para baterías de litio B+EXT
groundPACK- → BMS 3S 40 A para baterías de litio B-EXT
powerCELL1+ → BMS 3S 40 A para baterías de litio B1EXT
powerCELL2+ → BMS 3S 40 A para baterías de litio B2EXT

2. Connections between "bms_3s_40a" and "Arduino"

Functionbms_3s_40aArduino
powerP+ → Regleta de distribución protegida de 12 V BMS_INEXT
groundP-GND

3. Connections between "charger_12v6" and "Arduino"

Functioncharger_12v6Arduino
powerOUT+ → Regleta de distribución protegida de 12 V CHARGER_INEXT
groundOUT-GND

4. Connections between "power_distribution_12v" and "Arduino"

Functionpower_distribution_12vArduino
powerTO_LM2596 → 24v Buck Converter VIN+EXT
powerTO_L298N → Módulo controlador doble de motores L298N VSEXT
powerTO_SERVO_BUCK → Convertidor reductor de 5 V y mínimo 5 A VIN+EXT

5. Connections between "lm2596_5v" and "Arduino"

Functionlm2596_5vArduino
groundVIN-GND
powerVOUT+VIN
groundVOUT-GND

6. Connections between "servo_buck_5v5a" and "Arduino"

Functionservo_buck_5v5aArduino
groundVIN-GND
powerVOUT+5V
groundVOUT-GND

7. Connections between "l298n_1" and "Arduino"

Functionl298n_1Arduino
groundGNDGND
power5V5V
digitalIN1GPIO 4
digitalIN2GPIO 5
digitalIN3GPIO 6
digitalIN4GPIO 7
pwmENAGPIO 3
pwmENBGPIO 11
digitalOUT1 → Motorreductor tipo D de 12 V (oruga izquierda) M+EXT
digitalOUT2 → Motorreductor tipo D de 12 V (oruga izquierda) M-EXT
digitalOUT3 → Motorreductor tipo D de 12 V (oruga derecha) M+EXT
digitalOUT4 → Motorreductor tipo D de 12 V (oruga derecha) M-EXT

8. Connections between "pca9685_1" and "Arduino"

Functionpca9685_1Arduino
powerVCC5V
groundGNDGND
i2cSDAGPIO 18
i2cSCLGPIO 19
powerV+5V
pwmPWM0 → MG996R Servo Motor SIGEXT
pwmPWM1 → MG996R Servo Motor SIGEXT
pwmPWM2 → MG996R Servo Motor SIGEXT

9. Connections between "servo_hand_left" and "Arduino"

Functionservo_hand_leftArduino
powerVCC5V
groundGNDGND

10. Connections between "servo_hand_right" and "Arduino"

Functionservo_hand_rightArduino
powerVCC5V
groundGNDGND

11. Connections between "servo_head" and "Arduino"

Functionservo_headArduino
powerVCC5V
groundGNDGND

12. Connections between "hc05_1" and "Arduino"

Functionhc05_1Arduino
powerVcc5V
groundGNDGND
dataTXGPIO 8

13. Connections between "hc05_rx_resistor_top" and "Arduino"

Functionhc05_rx_resistor_topArduino
digitalP1GPIO 9
digitalP2 → Resistor P1EXT

14. Connections between "hc05_rx_resistor_bottom" and "Arduino"

Functionhc05_rx_resistor_bottomArduino
digitalP2 → Hc 05 Bluetooth Module RXEXT
groundP1GND

15. Connections between "isd1820_1" and "Arduino"

Functionisd1820_1Arduino
powerVCC5V
groundGNDGND
digitalPLAYEGPIO 10
analogSP+ → 8Ω Speaker POSEXT
analogSP- → 8Ω Speaker NEGEXT

16. Connections between "eye_led_left" and "Arduino"

Functioneye_led_leftArduino
digitalANODE → Resistor P1EXT
groundGNDGND

17. Connections between "eye_led_left_resistor" and "Arduino"

Functioneye_led_left_resistorArduino
digitalP2GPIO 12

18. Connections between "eye_led_right" and "Arduino"

Functioneye_led_rightArduino
digitalANODE → Resistor P1EXT
groundGNDGND

19. Connections between "eye_led_right_resistor" and "Arduino"

Functioneye_led_right_resistorArduino
digitalP2GPIO 13

Deploy the firmware

#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_PWMServoDriver.h>

const uint8_t MOTOR_ENA_PIN = 3;
const uint8_t MOTOR_IN1_PIN = 4;
const uint8_t MOTOR_IN2_PIN = 5;
const uint8_t MOTOR_IN3_PIN = 6;
const uint8_t MOTOR_IN4_PIN = 7;
const uint8_t BT_RX_PIN = 8;
const uint8_t BT_TX_PIN = 9;
const uint8_t ISD_PLAYE_PIN = 10;
const uint8_t MOTOR_ENB_PIN = 11;
const uint8_t PCA9685_SDA_PIN = A4;
const uint8_t PCA9685_SCL_PIN = A5;
const uint8_t LEFT_EYE_LED_PIN = 12;
const uint8_t RIGHT_EYE_LED_PIN = 13;

const uint8_t LEFT_HAND_CHANNEL = 0;
const uint8_t RIGHT_HAND_CHANNEL = 1;
const uint8_t HEAD_CHANNEL = 2;
const int CENTER_ANGLE = 90;
const int MIN_ANGLE = 45;
const int MAX_ANGLE = 135;
const int SERVO_STEP = 5;
const uint8_t MOTOR_SPEED = 210;
const unsigned long SERVO_ANIMATION_MS = 40UL;
const unsigned long AUDIO_REPEAT_MS = 11000UL;
const unsigned long PLAY_PULSE_MS = 80UL;

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
SoftwareSerial bluetooth(BT_RX_PIN, BT_TX_PIN);

int leftHandAngle = CENTER_ANGLE;
int rightHandAngle = CENTER_ANGLE;
int headAngle = CENTER_ANGLE;
unsigned long lastAudioStart = 0;
unsigned long playPulseStart = 0;
bool playPulseActive = false;
bool automaticServoMotion = true;
unsigned long lastServoAnimation = 0;
int handMotionDirection = 1;
int headMotionDirection = 1;

uint16_t angleToPulse(int angle) {
  return map(angle, 0, 180, 150, 600);
}

void setServoAngle(uint8_t channel, int angle) {
  angle = constrain(angle, MIN_ANGLE, MAX_ANGLE);
  pwm.setPWM(channel, 0, angleToPulse(angle));
}

void updateAutomaticServos() {
  unsigned long now = millis();
  if (!automaticServoMotion || now - lastServoAnimation < SERVO_ANIMATION_MS) {
    return;
  }
  lastServoAnimation = now;

  leftHandAngle += handMotionDirection;
  rightHandAngle -= handMotionDirection;
  if (leftHandAngle >= MAX_ANGLE || leftHandAngle <= MIN_ANGLE) {
    leftHandAngle = constrain(leftHandAngle, MIN_ANGLE, MAX_ANGLE);
    rightHandAngle = constrain(rightHandAngle, MIN_ANGLE, MAX_ANGLE);
    handMotionDirection = -handMotionDirection;
  }

  headAngle += headMotionDirection;
  if (headAngle >= 120 || headAngle <= 60) {
    headAngle = constrain(headAngle, 60, 120);
    headMotionDirection = -headMotionDirection;
  }

  setServoAngle(LEFT_HAND_CHANNEL, leftHandAngle);
  setServoAngle(RIGHT_HAND_CHANNEL, rightHandAngle);
  setServoAngle(HEAD_CHANNEL, headAngle);
}

void stopTracks() {
  analogWrite(MOTOR_ENA_PIN, 0);
  analogWrite(MOTOR_ENB_PIN, 0);
  digitalWrite(MOTOR_IN1_PIN, LOW);
  digitalWrite(MOTOR_IN2_PIN, LOW);
  digitalWrite(MOTOR_IN3_PIN, LOW);
  digitalWrite(MOTOR_IN4_PIN, LOW);
}

void driveTracks(bool leftForward, bool rightForward) {
  // El motor izquierdo está montado con el giro eléctrico invertido.
  digitalWrite(MOTOR_IN1_PIN, leftForward ? LOW : HIGH);
  digitalWrite(MOTOR_IN2_PIN, leftForward ? HIGH : LOW);
  digitalWrite(MOTOR_IN3_PIN, rightForward ? HIGH : LOW);
  digitalWrite(MOTOR_IN4_PIN, rightForward ? LOW : HIGH);
  analogWrite(MOTOR_ENA_PIN, MOTOR_SPEED);
  analogWrite(MOTOR_ENB_PIN, MOTOR_SPEED);
}

void startAudioPlayback() {
  digitalWrite(ISD_PLAYE_PIN, HIGH);
  playPulseStart = millis();
  playPulseActive = true;
  lastAudioStart = playPulseStart;
}

void updateAudioLoop() {
  unsigned long now = millis();
  if (playPulseActive && now - playPulseStart >= PLAY_PULSE_MS) {
    digitalWrite(ISD_PLAYE_PIN, LOW);
    playPulseActive = false;
  }
  if (!playPulseActive && now - lastAudioStart >= AUDIO_REPEAT_MS) {
    startAudioPlayback();
  }
}

void handleCommand(char command) {
  switch (command) {
    case 'F': case 'f': driveTracks(true, true); break;
    case 'B': case 'b': driveTracks(false, false); break;
    case 'L': case 'l': driveTracks(false, true); break;
    case 'R': case 'r': driveTracks(true, false); break;
    case 'S': case 's': stopTracks(); break;
    case 'A': automaticServoMotion = false; leftHandAngle = constrain(leftHandAngle + SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(LEFT_HAND_CHANNEL, leftHandAngle); break;
    case 'Z': automaticServoMotion = false; leftHandAngle = constrain(leftHandAngle - SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(LEFT_HAND_CHANNEL, leftHandAngle); break;
    case 'D': automaticServoMotion = false; rightHandAngle = constrain(rightHandAngle + SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(RIGHT_HAND_CHANNEL, rightHandAngle); break;
    case 'C': automaticServoMotion = false; rightHandAngle = constrain(rightHandAngle - SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(RIGHT_HAND_CHANNEL, rightHandAngle); break;
    case 'H': automaticServoMotion = false; headAngle = constrain(headAngle + SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(HEAD_CHANNEL, headAngle); break;
    case 'N': automaticServoMotion = false; headAngle = constrain(headAngle - SERVO_STEP, MIN_ANGLE, MAX_ANGLE); setServoAngle(HEAD_CHANNEL, headAngle); break;
    case 'M': case 'm': automaticServoMotion = !automaticServoMotion; break;
    case 'P': case 'p': startAudioPlayback(); break;
    default: break;
  }
}

void setup() {
  pinMode(MOTOR_ENA_PIN, OUTPUT);
  pinMode(MOTOR_ENB_PIN, OUTPUT);
  pinMode(MOTOR_IN1_PIN, OUTPUT);
  pinMode(MOTOR_IN2_PIN, OUTPUT);
  pinMode(MOTOR_IN3_PIN, OUTPUT);
  pinMode(MOTOR_IN4_PIN, OUTPUT);
  pinMode(ISD_PLAYE_PIN, OUTPUT);
  pinMode(LEFT_EYE_LED_PIN, OUTPUT);
  pinMode(RIGHT_EYE_LED_PIN, OUTPUT);
  digitalWrite(ISD_PLAYE_PIN, LOW);
  digitalWrite(LEFT_EYE_LED_PIN, HIGH);
  digitalWrite(RIGHT_EYE_LED_PIN, HIGH);
  stopTracks();
  Wire.begin();
  pwm.begin();
  pwm.setPWMFreq(50);
  setServoAngle(LEFT_HAND_CHANNEL, leftHandAngle);
  setServoAngle(RIGHT_HAND_CHANNEL, rightHandAngle);
  setServoAngle(HEAD_CHANNEL, headAngle);
  bluetooth.begin(9600);
  startAudioPlayback();
}

void loop() {
  while (bluetooth.available() > 0) {
    handleCommand((char)bluetooth.read());
  }
  updateAudioLoop();
  updateAutomaticServos();
  delay(1);
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik