12  Actuator Hands-On Labs

In 60 Seconds

These hands-on labs guide you through building complete actuator control systems, from DC motor speed ramping and servo-based robotic grippers to multi-actuator systems and PID feedback control. Each lab uses ESP32 with Wokwi simulation for safe experimentation before hardware deployment.

Learning Objectives

After completing these labs, you will be able to:

  • Construct complete actuator control systems from scratch using ESP32 and motor drivers
  • Integrate multiple actuator types (DC motors, servos, buzzers, LEDs) in a single project
  • Implement coordinated multi-axis motion control with synchronized timing
  • Validate actuator designs in Wokwi simulations before hardware deployment
  • Diagnose and resolve common actuator wiring, power, and control problems

These labs are like cooking recipes for electronics – they walk you through building real circuits step by step, from connecting wires on a breadboard to writing code that makes motors spin and buzzers beep. You will use a free online simulator called Wokwi, so you can experiment safely without worrying about breaking any physical components.

12.1 Lab 1: DC Motor Control with L298N

Objective: Control a DC motor using the L298N H-bridge driver with smooth acceleration and deceleration.

Materials:

  • ESP32 development board
  • L298N motor driver module
  • 6V DC motor
  • 9V power supply (for motor)
  • Jumper wires

Circuit Diagram:

ESP32          L298N         DC Motor
GPIO26 ------> IN1
GPIO27 ------> IN2
GPIO14 ------> ENA (PWM)
GND ----------> GND --------> Motor GND
               +9V ---------> Motor VCC (from external PSU)
               OUT1 --------> Motor +
               OUT2 --------> Motor -

Code:

#define MOTOR_IN1 26
#define MOTOR_IN2 27
#define MOTOR_EN 14

const int pwmFreq = 5000;
const int pwmChannel = 0;
const int pwmResolution = 8;

void setup() {
  Serial.begin(115200);

  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);

  ledcSetup(pwmChannel, pwmFreq, pwmResolution);
  ledcAttachPin(MOTOR_EN, pwmChannel);

  Serial.println("DC Motor Controller with Ramping");
}

void loop() {
  Serial.println("Accelerating forward...");
  rampSpeed(0, 255, true, 50);
  delay(2000);

  Serial.println("Decelerating to stop...");
  rampSpeed(255, 0, true, 50);
  delay(1000);

  Serial.println("Accelerating backward...");
  rampSpeed(0, 255, false, 50);
  delay(2000);

  Serial.println("Decelerating to stop...");
  rampSpeed(255, 0, false, 50);
  delay(1000);
}

void rampSpeed(int startSpeed, int endSpeed, bool forward, int delayMs) {
  int direction = (endSpeed > startSpeed) ? 1 : -1;

  if (forward) {
    digitalWrite(MOTOR_IN1, HIGH);
    digitalWrite(MOTOR_IN2, LOW);
  } else {
    digitalWrite(MOTOR_IN1, LOW);
    digitalWrite(MOTOR_IN2, HIGH);
  }

  for (int speed = startSpeed;
       direction > 0 ? speed <= endSpeed : speed >= endSpeed;
       speed += direction * 5) {
    ledcWrite(pwmChannel, speed);
    Serial.print("Speed: ");
    Serial.println(speed);
    delay(delayMs);
  }

  ledcWrite(pwmChannel, endSpeed);
}

Expected Learning Outcomes:

  • Explain H-bridge operation for bidirectional motor control
  • Implement PWM speed control with variable duty cycles
  • Design smooth acceleration and deceleration ramp profiles

12.2 Lab 2: Servo-Based Robotic Gripper

Objective: Build a 2-DOF robotic arm with gripper using servo motors and coordinated motion.

Materials:

  • ESP32 development board
  • 3x SG90 or MG90S servo motors
  • 5V 2A power supply
  • Breadboard and jumper wires
Power Supply Warning

Do NOT power multiple servos from the ESP32 5V pin! Use an external 5V 2A power supply. Connect ESP32 GND to power supply GND (common ground).

Circuit Diagram:

ESP32          Servos
GPIO18 ------> Base Servo (Signal)
GPIO19 ------> Arm Servo (Signal)
GPIO21 ------> Gripper Servo (Signal)
GND ----------> All Servo GND
5V ------------> All Servo VCC (from external PSU, NOT ESP32 5V!)

Code:

#include <ESP32Servo.h>

Servo baseServo, armServo, gripperServo;

struct Position { int base, arm, gripper; };

void setup() {
  Serial.begin(115200);
  baseServo.attach(18);
  armServo.attach(19);
  gripperServo.attach(21);
  moveToPosition({90, 90, 90}, 1000);  // Home position
  Serial.println("Commands: h=home, g=grab, r=release, s=sequence");
}

void loop() {
  if (Serial.available()) {
    char cmd = Serial.read();
    switch(cmd) {
      case 'h': moveToPosition({90, 90, 90}, 1500); break;
      case 'g': grabSequence(); break;
      case 'r': releaseSequence(); break;
      case 's': pickAndPlace(); break;
    }
  }
}

// Smooth interpolated motion across all servos
void moveToPosition(Position target, int duration) {
  int curB = baseServo.read(), curA = armServo.read(), curG = gripperServo.read();
  int steps = duration / 20;
  for (int i = 0; i <= steps; i++) {
    float p = (float)i / steps;
    baseServo.write(curB + (target.base - curB) * p);
    armServo.write(curA + (target.arm - curA) * p);
    gripperServo.write(curG + (target.gripper - curG) * p);
    delay(20);
  }
}

void grabSequence() {
  moveToPosition({90, 45, 90}, 1000);  delay(500);  // Lower arm
  moveToPosition({90, 45, 45}, 800);   delay(500);  // Close gripper
  moveToPosition({90, 90, 45}, 1000);               // Lift with object
}

void releaseSequence() {
  moveToPosition({90, 45, 45}, 1000);  delay(500);  // Lower arm
  moveToPosition({90, 45, 90}, 800);   delay(500);  // Open gripper
  moveToPosition({90, 90, 90}, 1000);               // Return home
}

void pickAndPlace() {
  moveToPosition({45, 45, 90}, 1500);  delay(500);  // Move to pick
  moveToPosition({45, 45, 45}, 800);   delay(500);  // Grab
  moveToPosition({135, 45, 45}, 2000); delay(500);  // Move to place
  moveToPosition({135, 45, 90}, 800);  delay(500);  // Release
  moveToPosition({90, 90, 90}, 1500);               // Return home
}


12.3 Lab 3: Multi-Actuator Control System

This lab combines multiple actuator types in a single project.

12.3.1 Wokwi Simulation

12.3.2 About the Components

Component Type Control Method Function
Servo Motor Position PWM (50Hz, 1-2ms pulse) Angle control
DC Motor Speed PWM (5kHz) + Direction Variable speed
RGB LED Visual 3x PWM channels Color mixing
Buzzer Audio Tone frequency Sound alerts

12.3.3 Challenges

Create a traffic light using the RGB LED:

  1. Red for 5 seconds
  2. Yellow for 2 seconds
  3. Green for 5 seconds
  4. Yellow for 2 seconds
  5. Repeat

Add a buzzer beep when changing to green (pedestrian signal).

Use a potentiometer to control:

  • DC motor speed (0-100%)
  • LED brightness (proportional to speed)
  • Buzzer pitch (higher = faster)

Implement a temperature-responsive fan:

  1. Read temperature from sensor (or simulate with potentiometer)
  2. Below 20C: LED blue, motor off
  3. 20-25C: LED green, motor 50%
  4. 25-30C: LED yellow, motor 75%
  5. Above 30C: LED red, motor 100%, alarm buzzer

12.4 Lab 4: Advanced PID Control

This lab implements PID feedback control for precise motor speed regulation.

12.4.1 Learning Objectives

  • Apply PID controller theory to tune proportional, integral, and derivative gains
  • Implement encoder feedback for closed-loop speed control
  • Analyze control loop behavior and diagnose oscillation issues using Serial Monitor

12.4.2 Key Concepts

Proportional Term (P):

Output = Kp x Error

Responds to current error. Higher Kp = faster response but may overshoot.

Integral Term (I):

Output = Ki x Integral(Error)

Eliminates steady-state error. Higher Ki = faster correction but may oscillate.

Derivative Term (D):

Output = Kd x Derivative(Error)

Dampens oscillations. Higher Kd = more stability but sensitive to noise.

12.4.3 Tuning Guide

  1. Start with Kp = 1, Ki = 0, Kd = 0
  2. Increase Kp until system oscillates
  3. Reduce Kp by 50%
  4. Add Ki to eliminate steady-state error
  5. Add Kd if oscillations occur

PID controller proportional term determines how aggressively the system responds to speed error in motor control.

\[ \text{PWM}_{correction} = K_p \times (\text{Target RPM} - \text{Actual RPM}) \]

Worked example: A DC motor targets 300 RPM but encoder measures 250 RPM (50 RPM error). With \(K_p = 0.5\):

\[\text{PWM}_{correction} = 0.5 \times (300 - 250) = 0.5 \times 50 = 25\]

If current PWM is 128 (50% duty), add 25 to reach 153 (60% duty), increasing motor speed. Higher \(K_p\) values respond faster but may overshoot and oscillate — typical starting values are 0.1-1.0 for motor speed control applications.

Interactive Calculator:

12.5 Troubleshooting Guide

Problem Possible Cause Solution
Motor doesn’t spin Wrong wiring Check IN1, IN2, and EN connections
Motor only spins one direction Direction pins swapped Swap IN1 and IN2
Servo jitters Insufficient power Use external 5V supply
Stepper skips steps Acceleration too fast Reduce max speed, increase acceleration time
Driver overheats Current too high Add heatsink, reduce motor current
Random resets Missing flyback diode Add diode across inductive loads

Problem: A 2-DOF robotic arm must move from position A (base=45°, arm=45°) to position B (base=135°, arm=90°) in exactly 2 seconds. Both servos must arrive simultaneously to prevent jerky motion. Calculate the required speeds for each servo.

Given Servo Specifications (SG90):

  • Speed rating: 0.1 seconds / 60 degrees at 5V
  • This means: 60° rotation takes 0.1 seconds
  • Or: 600 degrees per second maximum speed

Step 1: Calculate Angular Distance for Each Servo

Base servo:

  • Start: 45°
  • End: 135°
  • Distance: 135° - 45° = 90° rotation

Arm servo:

  • Start: 45°
  • End: 90°
  • Distance: 90° - 45° = 45° rotation

Step 2: Calculate Required Angular Velocity

Both servos must complete in 2 seconds:

Base servo speed: 90° ÷ 2 seconds = 45°/second

Arm servo speed: 45° ÷ 2 seconds = 22.5°/second

Step 3: Verify Speed is Within Servo Capability

SG90 maximum speed: 600°/second

Both required speeds (45°/s and 22.5°/s) are well below the 600°/s maximum, so this motion is achievable.

Step 4: Implement Synchronized Motion in Code

void moveToPosition(int baseTarget, int armTarget, int durationMs) {
    int baseStart = baseServo.read();
    int armStart = armServo.read();

    int baseDist = baseTarget - baseStart;
    int armDist = armTarget - armStart;

    int steps = durationMs / 20; // 20ms per step (50Hz servo update rate)

    for (int i = 0; i <= steps; i++) {
        float progress = (float)i / (float)steps;

        int basePos = baseStart + (baseDist * progress);
        int armPos = armStart + (armDist * progress);

        baseServo.write(basePos);
        armServo.write(armPos);

        delay(20);
    }
}

Calling the function:

moveToPosition(135, 90, 2000); // Base to 135°, Arm to 90°, in 2000ms

Step 5: Calculate Actual Step Increments

With 2000ms duration and 20ms steps: - Total steps: 2000 ÷ 20 = 100 steps

Base servo:

  • 90° total ÷ 100 steps = 0.9° per step

Arm servo:

  • 45° total ÷ 100 steps = 0.45° per step

Step 6: Verify Servo Can Achieve Step Resolution

SG90 servos typically have: - Control resolution: 1° (can position to nearest degree) - Our increments: 0.9° and 0.45° per step

Since we’re commanding sub-degree increments, the servo’s internal control will round to nearest degree, creating very smooth motion with minimal visible stepping.

Real-World Complications:

Issue 1: Servo Speed Variance

  • Datasheet says 0.1s/60° but real servos vary by ±20%
  • Solution: Measure actual servo speed, adjust timing

Issue 2: Different Servo Models

  • Base servo (metal gear MG996R): 0.17s/60° (slower)
  • Arm servo (SG90): 0.1s/60°
  • They’ll arrive at different times!

Solution for Mixed Servos:

// Calculate minimum time for each servo (distance * seconds_per_degree)
float baseTime = 90.0 * (0.17 / 60.0);  // = 0.255 seconds minimum
float armTime  = 45.0 * (0.10 / 60.0);  // = 0.075 seconds minimum

// Convert to milliseconds and use the longer time as the floor
int minDurationMs = max((int)(baseTime * 1000), (int)(armTime * 1000)); // 255 ms
int duration = max(minDurationMs, 2000); // Use 2000 ms for smooth motion

Key Insight: Coordinated multi-axis motion requires: 1. Calculate each axis’s travel distance 2. Normalize all axes to same total time 3. Break motion into small steps (20ms intervals for servos) 4. Account for different servo speeds if mixing models 5. Use linear interpolation for smooth, synchronized arrival

Extension: Non-Linear Motion (Ease-In/Ease-Out)

For more natural motion, use easing functions:

float easeInOutCubic(float t) {
    return t < 0.5 ? 4 * t * t * t : 1 - pow(-2 * t + 2, 3) / 2;
}

// In loop:
float progress = easeInOutCubic((float)i / (float)steps);

This starts slow, speeds up in middle, slows at end—much more human-like than linear motion.

12.6 Knowledge Check

Key Takeaway

Hands-on labs are essential for understanding actuator behavior that theory alone cannot convey, including power supply limitations, real-world timing constraints, and the importance of smooth acceleration profiles. Always prototype with simulation tools like Wokwi before moving to physical hardware, and remember that proper power supply design is as important as the control code itself.

“Lab day! Lab day!” cheered Lila the LED, blinking excitedly. The Sensor Squad had set up a mini workshop.

“Okay team,” said Max the Microcontroller, “today we’re building a robot arm! Servo Sam, you’re in charge of the joints.”

Servo Sam flexed his gears. “Base rotation – check! Arm lift – check! Gripper – check! I can move to any angle you tell me, Max!”

“But wait,” Bella the Battery said worriedly. “Three servos? That’s a lot of power! Don’t you dare try to power them all through Max – he’ll overheat!”

“Good thinking, Bella!” said Max. “We need a big external power supply for the servos. I just send them tiny signal messages telling them where to go. The heavy lifting power comes from elsewhere.”

Sammy the Sensor watched as the arm picked up a small block. “I can see the arm is at 45 degrees… now closing the gripper… now lifting! It’s working!”

“The secret,” Max explained, “is smooth movements. If I tell all the servos to jump to new positions instantly, the arm jerks around and might knock things over. Instead, I move them gradually – a little bit at a time – like doing a slow-motion dance!”

“Building is the best way to learn!” Lila flashed in agreement.

12.7 See Also

Common Pitfalls

The appropriate transistor, MOSFET, or H-bridge IC depends critically on the actuator’s actual current draw. Without measuring current with a multimeter in series, you might select a driver rated for 500 mA for a motor that draws 800 mA under load, causing driver overheating or failure during the lab. Measure current in your specific circuit before finalizing component selection.

When implementing H-bridge DC motor control, verify direction behavior with low PWM duty cycle (20-30%) before incrementing to full speed. Running a motor at full speed in the wrong direction can mechanically damage the mechanism being driven. Always confirm correct rotation direction at low speed first.

Motor vibration and cable tension cause breadboard connections to loosen during operation, producing intermittent faults difficult to diagnose. Use wire colors consistently (red for power, black for ground, yellow/green for signals), press connectors firmly into breadboard holes, and consider twist-tying cable bundles to reduce mechanical stress on connections.

Starting a motor at 100% PWM immediately causes maximum inrush current, which can trigger power supply protection, cause microcontroller brownout resets, or mechanically stress the driven mechanism. In lab firmware, always ramp PWM duty cycle from 0 to target over 500 ms - 2 seconds to control startup current and reduce mechanical shock.

12.8 What’s Next?

Now that you have completed the hands-on labs, deepen your understanding with the theory chapters or test your knowledge with the assessment.

Chapter Description
DC Motors Theory behind Lab 1: H-bridge operation, PWM speed control, and motor characteristics
Servo Motors Theory behind Lab 2: pulse-width positioning, torque specs, and coordinated motion
PWM Control Duty cycle calculations, frequency selection, and multi-channel PWM on ESP32
Actuator Safety Watchdog timers, current limiting, thermal protection, and flyback diodes
Assessment Test your actuator knowledge with a comprehensive quiz covering all lab topics