PTENES
MODULE 1.5 · PRACTICE

⚙️ Motors and power

So far, the robot senses and thinks. Now it acts: you choose the right motor, connect a modern H-bridge, control speed and direction with PWM, point a servo, and, above all, build a safe, clean power supply, where most first robots run into trouble.

6
Topics
Beginner
Level
Practice
Type
Motor + driver
Hardware required
0%
0 of 0 topics read · Section 1 of 6

Detailed content

1

🔄 DC, servo, or stepper motor: which one to use

Almost every movement in a benchtop robot comes from one of three motor types. A DC motor spins continuously while it receives power: it’s the rover’s wheel. A servo goes to an angle and stays there: it’s the “neck” that turns the sensor. The stepper motor moves in small, precise steps: it’s the axis of a 3D printer. The right question isn’t “which is better?” but “what movement does the task require?”

🌱 New here?

Torque is rotational force: how hard the motor can push the robot uphill. RPM is speed, in revolutions per minute. The gearbox (the yellow gears in the TT motor) trades speed for torque: the shaft turns more slowly, but with more force. Without gearing, a small DC motor spins fast and can’t even move its own weight.

DC MOTOR spins continuouslyyou controlspeed and direction SERVO 0°180°moves to an angle and holds thereSTEPPER moves in stepsknows how many it took,without an extra sensor

How to read this map: the DC motor’s solid arrow indicates free rotation; the servo’s dashed arc shows that it only moves within a range (0° to 180°); the stepper motor’s little marks are the fixed positions where it stops. The two green cards spin without limit; the cyan one works by position.

MotorUse it forRequires
Geared DC (TT, N20)rover wheels, tracks, fanH-bridge (driver) and PWM; encoder if you want to measure rotation (Track 2)
Servo (SG90, MG90S)turning a sensor, gripper, rudder, small armone signal pin and 5 V with enough current available
Stepper (28BYJ-48, NEMA 17)precise positioning: plotter, printer, turntablededicated driver (ULN2003, A4988, TMC2209) and more power while stationary

💡 Continuous rotation servo

There are “360°” servos that spin continuously: the angle setting becomes speed (90 = stopped, 0 and 180 = maximum speed in each direction). It doesn’t need an H-bridge and works well for a very simple rover. The trade-off is less force and less precise speed control than a TT motor with a driver.

Why learn this

The wrong motor leaves the robot weak, slow, or imprecise, and no code can fix that. Choosing based on the type of movement also determines the rest: which driver to buy, how much current the battery needs to deliver, and how many ESP32 pins you’ll use.

Key concepts

Torque
rotational force
Rotation
speed in RPM
Position
servos and steppers know where they are
Gearing
trades speed for force
2

🔀 H-bridge: TB6612FNG and DRV8833

An ESP32 pin supplies only a few milliamps at 3.3 V; a TT motor draws hundreds of milliamps and over 1 A at startup. Connecting the motor directly to the pin will burn it out. Between them, you need a motor driver: the ESP32 sends only the signal, and the driver opens the path for current from the battery.

🌱 New here?

A H-bridge is a set of four electronic switches around the motor, arranged like the letter H. Closing two diagonal switches sends current through the motor in one direction; closing the other two sends it in the opposite direction. That’s how the same motor moves forward and backward. The TB6612FNG and DRV8833 are chips with two H-bridges each: one chip controls both wheels.

S1 S2 S3 S4 MVM (battery +) GND (battery −) S1 + S4 closed: current →, motor turns forwardS2 + S3 closed: current ←, motor turns backward

How to read this map: follow the green arrow: it enters through S1, passes through the motor from left to right, and exits through S4. The dashed cyan arrow follows the mirrored path (S2, motor in the opposite direction, S3). Closing S1 and S3 together would connect the battery directly to GND, causing a short circuit; the driver chip is there specifically to ensure the IN1/IN2 pins never allow that.

Driver pinTB6612FNGDRV8833
Motor powerVM (from battery)VM / VCC on the module (from battery)
LogicVCC = ESP32 3V3not needed: reads 3.3 V directly
DirectionAIN1, AIN2 (digital)AIN1, AIN2 (both accept PWM)
SpeedPWMA (dedicated pin)PWM on AIN1 or AIN2 itself
Enable the chipSTBY set highnSLEEP (or EEP) set high; many modules come enabled
Motor outputAO1/AO2 and BO1/BO2AOUT1/AOUT2 and BOUT1/BOUT2

✓ Do

  • ✓Use a TB6612FNG or DRV8833: MOSFET transistors, low power loss, and compatible with 3.3 V logic.
  • ✓Check your module’s continuous and peak current ratings in the datasheet and compare them with the motor.
  • ✓Connect the driver, battery, and ESP32 GND pins to the same point.

✗ Avoid

  • ✗L298N: still sold, but inefficient; it loses about 2 V as heat, leaving the motor weak.
  • ✗Connecting a motor directly to an ESP32 pin, even “just to test.”
  • ✗Changing the driver wires while the battery is connected.

Why learn this

The driver is the bridge between the code and the power. Understanding its pins (power, logic, direction, speed, on/off) means the rover wiring in 1.6 is no longer a memorized recipe: you know why each wire is there and can switch drivers with confidence.

Key concepts

H-bridge
4 switches, 2 directions
VM and VCC
power separate from logic
STBY
high = driver enabled
Peak current
the startup surge
3

🎚️ Speed and direction with PWM

Direction comes from the IN1/IN2 pins. Speed comes from PWM, which you already used in module 1.3 to control the LED brightness: the driver switches battery power to the motor on and off thousands of times per second, and the motor responds to the average. The greater the fraction of each cycle that’s “on,” the duty cycle, the faster it spins.

25%50%90% dead zone(buzzes)half poweralmost all the way same voltage; only the on-time in each cycle changes

How to read this map: all three waves have the same height (the battery voltage) and the same rhythm; only the width of the high section changes. At 25%, the TT motor usually just buzzes: the average force isn’t enough to overcome the gearbox friction. This useless range is the dead zone, and the code below skips over it.

🌱 New here?

A ramp gradually increases the speed instead of jumping from 0 to 100%: the robot moves smoothly and the battery avoids a sudden voltage drop. The frequency of the PWM is the number of cycles per second; we use 20 kHz (20 thousand), above the range of human hearing, so the motor doesn’t “whistle.” In API 3.x, ledcAttach(pino, 20000, 8) sets up the pin, and ledcWrite(pino, 0..255) sets the speed.

Goal: create the rover’s “verbs” (forward, reverse, turn, stop, and ramp) with a TB6612FNG and see each one in the Serial Monitor. The pins are the same as in project 1.6: left motor on PWMA 25, AIN1 26, AIN2 27; right motor on PWMB 33, BIN1 32, BIN2 4; STBY on 13.

motores-teste.ino
// Motor test with TB6612FNG (ESP32, esp32 core 3.x)
// Forward, reverse, turn, and stop, with acceleration ramp.
// The first time, keep the robot SUSPENDED (wheels off the ground).

const int PINO_PWMA = 25, PINO_AIN1 = 26, PINO_AIN2 = 27;  // left motor
const int PINO_PWMB = 33, PINO_BIN1 = 32, PINO_BIN2 = 4;   // right motor
const int PINO_STBY = 13;
const int PWM_FREQ = 20000;  // 20 kHz: outside the range of human hearing
const int PWM_BITS = 8;      // speed from 0 to 255
const int VEL_MIN  = 90;     // below this, the TT motor hums but doesn't turn
// speed from -255 (reverse) to 255 (forward); 0 = stopped
void motor(int in1, int in2, int pinoPwm, int vel) {
  vel = constrain(vel, -255, 255);
  int forca = abs(vel);
  if (forca > 0 && forca < VEL_MIN) forca = VEL_MIN;  // skips the dead zone
  digitalWrite(in1, vel > 0 ? HIGH : LOW);
  digitalWrite(in2, vel < 0 ? HIGH : LOW);
  ledcWrite(pinoPwm, forca);                  // API 3.x: receives the PIN
}
void andar(int esq, int dir) {
  motor(PINO_AIN1, PINO_AIN2, PINO_PWMA, esq);
  motor(PINO_BIN1, PINO_BIN2, PINO_PWMB, dir);
}
void frente(int v)       { andar(v, v); }
void re(int v)           { andar(-v, -v); }
void girarDireita(int v) { andar(v, -v); }  // wheels in opposite directions
void parar()            { andar(0, 0); }
// increases (or decreases) speed in steps of 5: no sudden jolts
void rampa(int de, int ate, int passoMs) {
  int passo = (ate > de) ? 5 : -5;
  for (int v = de; (passo > 0) ? (v < ate) : (v > ate); v += passo) { frente(v); delay(passoMs); }
  frente(ate);
}
void setup() {
  Serial.begin(115200);
  pinMode(PINO_AIN1, OUTPUT); pinMode(PINO_AIN2, OUTPUT);
  pinMode(PINO_BIN1, OUTPUT); pinMode(PINO_BIN2, OUTPUT);
  pinMode(PINO_STBY, OUTPUT);
  ledcAttach(PINO_PWMA, PWM_FREQ, PWM_BITS);   // channel selected automatically
  ledcAttach(PINO_PWMB, PWM_FREQ, PWM_BITS);
  digitalWrite(PINO_STBY, HIGH);               // takes the driver out of standby
  parar();
  Serial.println("Motor test: forward, reverse, turn, stop");
  delay(2000);
}
void loop() {
  Serial.println("ramp to forward 200"); rampa(0, 200, 20); delay(1000);
  Serial.println("parar");                parar();           delay(800);
  Serial.println("re 160");               re(160);           delay(1000);
  Serial.println("parar");                parar();           delay(800);
  Serial.println("turn right"); girarDireita(160); delay(700);
  Serial.println("parar");                parar();           delay(2000);
}

How to check

  • ✓With the robot suspended, both wheels accelerate forward together, stop, reverse, and then turn in opposite directions.
  • ✓The Serial Monitor (115200) shows each step as it happens.
  • ✗Does one wheel turn the wrong way when moving “forward”? Swap the two wires for that motor on AO1/AO2 (or BO1/BO2), not the code.
  • ✗Nothing turns and nothing gets hot? Check that STBY is at 3.3 V, VM is connected to the battery, and GND is shared.

💡 Using the DRV8833

The DRV8833 has no separate speed pin: both input pins for each motor receive PWM. To move forward, apply PWM to AIN1 and 0 to AIN2; for reverse, do the opposite; setting both to 0 lets the motor coast. The rover sketch in module 1.6 includes both versions, selected by a line at the top of the code.

Why learn this

Forward, reverse, turn, and stop are the verbs the rover’s state machine will use. Writing them once as small functions keeps the project code short and readable: “if the wall is close, parar(), then re()".

Key concepts

Duty cycle
portion of the cycle that is on
Ramp
accelerates smoothly
Brake vs. coast
stops firmly or rolls
Dead zone
low PWM won't move it
4

📐 Servo on the ESP32 with ESP32Servo

The servo has three wires: brown (GND), red (5 V), and orange (signal). It doesn’t read the duty cycle like a DC motor; it reads the pulse width. A pulse arrives every 20 ms (50 times per second), and its duration determines the angle. The ESP32Servo library calculates these pulses for you. The Servo.h from Arduino Uno doesn’t work on the ESP32.

0.5 ms1.5 ms2.4 msone pulse every 20 ms (50 Hz) 0°90°180°

How to read this map: each pulse color on the left corresponds to the arm of the same color on the right. A short pulse (green) moves the arm to one end, a medium pulse (cyan) to the center, and a long pulse (amber) to the other end. The space after the pulse completes the 20 ms. Your servo may use a slightly different range; the values 500 and 2400 in the code adjust it.

Step by step

1

Install the library

In Arduino IDE 2.x, open the Library Manager, search for “ESP32Servo” (author Kevin Harrington), and install the latest version, which is compatible with the esp32 core 3.x.

2

Connect the three wires

Orange to GPIO 23, brown to shared GND, red to the regulator’s 5 V (topic 6). For a quick test without a load, you can use the 5V pin on the board while it’s connected to USB.

3

Try it in Wokwi first, if you like

Wokwi has a servo and the ESP32Servo library: build the same circuit, paste in the code, and watch the virtual arm move.

Goal: make the servo “look” forward, to the right, forward again, and to the left, as the rover’s neck will do in 1.6.

servo-olhar.ino
// SG90 servo on the ESP32 with the ESP32Servo library (esp32 core 3.x)
#include <ESP32Servo.h>

const int PINO_SERVO = 23;  // orange wire (signal)
Servo cabeca;   // the servo that turns the rover's sensor

void setup() {
  Serial.begin(115200);
  cabeca.setPeriodHertz(50);             // one pulse every 20 ms
  cabeca.attach(PINO_SERVO, 500, 2400);  // 0.5 ms = 0 degrees ... 2.4 ms = 180 degrees
  cabeca.write(90);                      // starts facing forward
  Serial.println("Servo ready on GPIO 23");
  delay(1000);
}

void loop() {
  int angulos[] = {90, 20, 90, 160};    // forward, right, forward, left
  for (int i = 0; i < 4; i++) {
    cabeca.write(angulos[i]);
    Serial.printf("angle: %d\n", angulos[i]);
    delay(800);                          // time for the servo to reach its position
  }
}

How to check

  • ✓The arm moves to the center, to one side, back to the center, and then to the other side, holding firmly at each position.
  • ✓The Serial Monitor repeats “angle: 90”, “angle: 20”, “angle: 90”, “angle: 160”.
  • ✗Compilation error mentioning PWM functions? Update ESP32Servo; older versions were for API 2.x.
  • ✗Servo shaking or ESP32 restarting? The 5 V supply can’t provide enough current; use the regulator from topic 6.

Why learn this

With the distance sensor mounted on the servo, the rover looks to both sides before deciding which way to turn, instead of always turning the same way. It’s the same “pointing” technique you’ll use with the gripper, the camera that follows an object, and the arm in Track 5.

Key concepts

50 Hz
one pulse every 20 ms
Pulse width
sets the angle
ESP32Servo
the ESP32 library
separate 5 V supply
never from the 3V3 pin
5

🔋 Batteries: NiMH, 18650, LiPo, and BMS

A robot battery needs two things: the voltage right one for the motors and current enough for startup. This is where the square 9 V battery fails: the voltage looks good, but it delivers too little current, drops on the first acceleration, and the ESP32 restarts. For Track 1, the safe choice is 4 rechargeable AA batteries (NiMH) or 2 18650 cells with a protection board.

🌱 New here?

mAh (milliamp-hours) is the capacity: a 2000 mAh battery theoretically powers a 500 mA load for about 240 minutes. 2S means two lithium cells in series: 2 × 3,7 V = 7,4 V nominal, 8,4 V when charged. The BMS (battery management system) is the small board that cuts power if the cell discharges too much, overcharges, or short-circuits.

current delivered (comparison, not to scale) → square 9 Vnot suitable for motors 4× AA NiMH4,8 V · safe starting point 2× 18650 + BMS7,4 V · rover LiPo 2Scaution more current = more power, and more energy in a short circuit

How to read this map: The longer the bar, the more current the battery delivers without the voltage plummeting. The tiny red bar explains why the 9 V battery makes the robot restart. The LiPo has the longest bar, which is exactly why it is the most dangerous: in a short circuit, it turns all that current into heat.

✓ Lithium safety

  • ✓Use 18650 cells only in a holder with a BMS, from a well-known brand; use matching cells with the same charge level.
  • ✓Charge LiPo batteries with a balance charger, inside a fire-resistant bag, on a nonflammable surface.
  • ✓Put an on/off switch on the positive wire, close to the battery.
  • ✓Store at a medium charge level, away from sunlight and loose metal objects.

✗ Never

  • ✗Leave a lithium battery charging unattended.
  • ✗Use a swollen, dented, or punctured LiPo battery: take it to a collection point for disposal.
  • ✗Touch the two terminals together with a tool or bare wire.
  • ✗Use a square 9 V battery for a motor or servo.

⚠️ Voltage too high for the TT motor

TT motors are designed for about 3 to 6 V. Two fully charged 18650 cells provide 8,4 V: the motor runs, but it gets hot and wears out. The rover code has a speed limit (about 70% PWM) to keep the average voltage close to 6 V. With 4 NiMH batteries, the limit can be raised to 100%.

Why learn this

The wrong power supply is the number one cause of a robot that “restarts by itself,” and lithium batteries are the biggest real hazard on the workbench. Knowing how to read voltage, capacity, and protection helps your rover run longer and keeps the classroom (and your home) safer.

Key concepts

mAh
how long it lasts
Discharge current
how much it can deliver
BMS
cuts power before it becomes dangerous
Fire-resistant bag
where the LiPo charges
6

⚡ Voltage regulator, common GND, and motor noise

The battery provides 7,4 V; the ESP32, sensor, and servo need 5 V. The conversion is done by a buck regulator, a small board that lowers the voltage while wasting little energy as heat. The wiring has two branches: the battery connects directly to VM on the driver (motor power) and, through the buck, to the electronics' 5 V supply. All the negative terminals meet at a single point: the Common GND.

battery7,4 V switch driver VM motors+ 100 nF each 5 V buck ESP32 (5V/VIN)HC-SR04 · servo 3V3 → driver VCCdriver logic common GND (one point)

How to read this map: The amber path is the battery voltage, which only goes to the driver and the buck. Green is the clean 5 V supply for the electronics. The dashed cyan line is the 3,3 V that the ESP32 sends to the driver's logic. The dotted gray lines are the GND connections: they all end at the same circle. If one is missing, the signals lose their reference and the robot behaves unpredictably.

🌱 New here?

Brownout is a rapid drop in voltage: the motor starts, draws a current spike, the voltage drops for a few milliseconds, and the ESP32 restarts to protect itself. A decoupling capacitor is a small charge reservoir placed near the component drawing power: a 100 nF ceramic capacitor soldered across each motor's terminals absorbs electrical sparks from the brushes, and a 470 µF to 1000 µF electrolytic capacitor on the driver's VM line helps handle current spikes.

Goal: find out why the ESP32 restarted. Run the sketch by itself to see the “normal” reason. Then copy the function reason() and the lines from setup() to the start of the motor test in topic 3: each time the board restarts, the first line in the Serial Monitor tells you why.

reset-reason.ino
// Why did the ESP32 restart? (esp32 3.x package)
#include "esp_system.h"

const char* motivo(esp_reset_reason_t r) {
  switch (r) {
    case ESP_RST_POWERON:  return "power was turned on or EN was pressed (normal)";
    case ESP_RST_SW:       return "reset requested by the program";
    case ESP_RST_PANIC:    return "program error (panic)";
    case ESP_RST_BROWNOUT: return "BROWNOUT: voltage dropped (motor, weak battery, wire)";
    default:               return "other reason";
  }
}
void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.print("Last restart: ");
  Serial.println(motivo(esp_reset_reason()));
}

void loop() {}

How to check

  • ✓When it starts normally, it displays "power was turned on or EN was pressed (normal)".
  • ✗Does it display "BROWNOUT" (or the message "Brownout detector was triggered" beforehand)? The power supply is weak: check the buck, capacitors, battery, and common GND.

✓ Clean power

  • ✓Set the buck to 5,0 V with a multimeter before connecting any board to it.
  • ✓Connect the buck's 5 V output to the ESP32's 5V/VIN pin; the board's regulator provides 3,3 V.
  • ✓Keep motor wires short and twisted together in pairs; route them away from the sensor wires.

✗ Guaranteed noise

  • ✗Powering a servo or motor from the ESP32's 3V3 pin.
  • ✗Connecting the battery directly (7,4 V) to the 3V3 pin or a GPIO: this burns out the board.
  • ✗Using a separate GND for the driver without connecting it to the ESP32's GND.

Why learn this

Without a regulator, capacitors, and common GND, motor noise restarts the ESP32 exactly when it most needs to work: while braking and turning in front of the wall. This fault looks like a “code bug” and makes many people give up; now you know to check the power supply first.

Key concepts

Buck
lowers the voltage without heating up
Decoupling
capacitor near the load
Brownout
voltage drop that causes a reset
Common GND
one reference for everything

✅ Module summary

✓
Motors in motion: DC motors spin, servos point, and stepper motors position precisely.
✓
Modern H-bridge: TB6612FNG or DRV8833 between the ESP32 and the motor; never connect a motor to a pin.
✓
PWM in API 3.x: ledcAttach + ledcWrite(pin, value), with a ramp and a dead-zone jump.
✓
Servo with ESP32Servo: 50 Hz, pulse width, 5 V from the regulator.
✓
Safe, clean power: NiMH or 18650 with BMS, 5 V buck converter, capacitors, and common GND; no 9 V batteries.

To go further

Next module

1.6 · Project: obstacle-avoiding rover. Everything from the track comes together: plan, build, test in stages, and program the state machine.