Module 10: Motors & Movement

Level: 🟡 Intermediate
Board: Arduino Uno
Prerequisites: Modules 5, 7
Estimated time: 70–90 minutes
Goal: Control different types of motors safely and understand their electrical demands.


What You'll Learn

Motors turn electrical energy into physical movement. They're also the most electrically demanding components you'll work with: they draw high current, generate noise, and produce voltage spikes that can reset or damage your Arduino. In this module, you'll learn to control three types of motors (servo, DC, stepper), understand why each needs careful power management, and build a precision turntable.


10.1 Servo Motors: Precise Position Control

What Is a Servo?

A servo motor moves to a specific angle and holds it. Inside the housing: a DC motor, a gear train (for torque), and a feedback potentiometer (so the servo knows its current angle). You tell it "go to 90°" and it goes there and stays.

How Servo Control Works

Servos are controlled by a specific kind of PWM signal, but it's not the same as analogWrite() PWM.

Parameter Servo PWM analogWrite PWM
Frequency 50 Hz (20 ms period) ~490 Hz or ~980 Hz
Pulse width range 1 ms–2 ms 0 ms–2 ms (at ~490 Hz)
What it controls Angular position (0°–180°) Average voltage (0–5V)

The servo reads the pulse width:

This happens 50 times per second. The Arduino Servo library handles all the timing.

Never use analogWrite() for servos. The wrong frequency and pulse range will cause erratic behavior or damage.

Using the Servo Library

/*
 * Module 10: Basic Servo Control
 *
 * Circuit:
 * - Servo signal (orange/white) → pin 6
 * - Servo VCC (red) → EXTERNAL 5V supply
 * - Servo GND (brown/black) → GND (shared with Arduino)
 *
 * Board: Arduino Uno
 */

#include <Servo.h>

const int SERVO_PIN = 6;
Servo myServo;

void setup() {
  myServo.attach(SERVO_PIN);
  myServo.write(90);  // Start at center
  delay(500);
}

void loop() {
  // Sweep from 0° to 180°
  for (int angle = 0; angle <= 180; angle++) {
    myServo.write(angle);
    delay(15);  // Give the servo time to reach the position
  }

  // Sweep back
  for (int angle = 180; angle >= 0; angle--) {
    myServo.write(angle);
    delay(15);
  }
}

Servo Power: Revisiting Module 5

From Module 5: servos need external power. The SG90 micro servo draws 100–250 mA when moving, with peaks up to 500 mA under load. That exceeds the Arduino's USB supply headroom.

Always:

Potentiometer-Controlled Servo

const int POT_PIN = A0;
const int SERVO_PIN = 6;
Servo myServo;

void setup() {
  myServo.attach(SERVO_PIN);
}

void loop() {
  int potValue = analogRead(POT_PIN);
  int angle = map(potValue, 0, 1023, 0, 180);
  myServo.write(angle);
  delay(15);
}

Servo Types

Type Rotation Use Case
Standard servo 0°–180° Robotic arms, pan/tilt, gates
Continuous rotation servo Full 360° Wheels, winches (speed control, not position)
High-torque servo 0°–180° Heavy loads, larger mechanisms

For continuous rotation servos, write(90) = stop, write(0) = full speed one direction, write(180) = full speed other direction.


10.2 DC Motors: Speed and Direction

The Simplest Motor

A DC motor spins when you apply voltage. Reverse the voltage, it spins the other way. Change the voltage, it changes speed. Simple concept, but driving one from an Arduino requires extra hardware.

Why You Can't Just Connect a DC Motor to a Pin

  1. Current: Even small DC motors draw 200–500 mA. Arduino pins max out at 40 mA.
  2. Back-EMF: When a motor stops, its inertia generates a reverse voltage spike that can damage electronics.
  3. Direction: Reversing a motor requires swapping the polarity of the power connections, and a single pin can't do that.

The H-Bridge: Motor Driver

An H-bridge is a circuit with four switches arranged in an "H" pattern. By closing different pairs of switches, current flows through the motor in either direction.

You don't build H-bridges from scratch; you use driver ICs or modules.

L298N Motor Driver Module

The L298N is the most common motor driver for Arduino projects. It can drive two DC motors independently.

L298N Specs:

L298N Pin Connections

L298N Pin Connection Function
VCC (12V) External motor power supply Motor voltage (5V–35V)
GND Arduino GND + power supply GND Shared ground
5V Can supply 5V to Arduino (or leave NC if using USB) Onboard regulator output
IN1 Arduino digital pin Motor A direction control
IN2 Arduino digital pin Motor A direction control
ENA Arduino PWM pin Motor A speed (PWM)
IN3 Arduino digital pin Motor B direction control
IN4 Arduino digital pin Motor B direction control
ENB Arduino PWM pin Motor B speed (PWM)
OUT1, OUT2 Motor A terminals Motor A power
OUT3, OUT4 Motor B terminals Motor B power

Direction and Speed Control Logic

IN1 IN2 Motor A
HIGH LOW Forward
LOW HIGH Reverse
LOW LOW Stop (coast)
HIGH HIGH Stop (brake)

Speed is controlled by the PWM signal on ENA: analogWrite(ENA, 0–255).

Code: DC Motor Control

/*
 * Module 10: DC Motor with L298N
 *
 * Circuit:
 * - L298N IN1 → pin 7, IN2 → pin 8, ENA → pin 9 (PWM)
 * - L298N VCC → external motor power supply (e.g., 9V)
 * - L298N GND → Arduino GND + power supply GND
 * - Motor connected to OUT1, OUT2
 * - Potentiometer on A0 for speed control
 *
 * Board: Arduino Uno
 */

const int IN1 = 7;
const int IN2 = 8;
const int ENA = 9;  // Must be PWM pin
const int POT_PIN = A0;

void setup() {
  Serial.begin(9600);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(ENA, OUTPUT);
}

void motorForward(int speed) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, speed);
}

void motorReverse(int speed) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, speed);
}

void motorStop() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, 0);
}

void motorBrake() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, 255);
}

void loop() {
  int potValue = analogRead(POT_PIN);

  // Center position (around 512) = stop
  // Below center = reverse, above center = forward
  if (potValue > 562) {
    int speed = map(potValue, 562, 1023, 0, 255);
    motorForward(speed);
    Serial.print("Forward: ");
    Serial.println(speed);
  } else if (potValue < 462) {
    int speed = map(potValue, 462, 0, 0, 255);
    motorReverse(speed);
    Serial.print("Reverse: ");
    Serial.println(speed);
  } else {
    motorStop();
    Serial.println("Stopped");
  }

  delay(50);
}

Flyback Diodes: Protecting Your Electronics

When a motor is suddenly disconnected (or when switching direction), the collapsing magnetic field in the motor coils generates a voltage spike (back-EMF). This spike can be 50–100V and will damage your driver IC and Arduino.

Flyback diodes (also called freewheeling diodes) provide a safe path for this current. The L298N module has built-in flyback diodes for its output. If you're building your own H-bridge with discrete transistors, you must add them yourself (1N4007 across each motor terminal, cathode toward the positive supply).


10.3 Stepper Motors: Precision Rotation

What Makes Steppers Different

A stepper motor moves in discrete steps, typically 1.8° per step (200 steps per revolution). You control exactly how many steps it takes, giving precise position control without a feedback sensor.

Types of Stepper Motors

Type Wires Common Models
Bipolar 4 NEMA 17
Unipolar 5 or 6 28BYJ-48

The 28BYJ-48 with its ULN2003 driver board is the most common beginner stepper. It's cheap, comes with a driver, and is perfect for learning. It's also slow and weak; for real projects, you'll want a NEMA 17 with an A4988 or DRV8825 driver.

28BYJ-48 + ULN2003 Driver

Specs:

Wiring:

ULN2003 Pin Arduino Pin
IN1 D8
IN2 D9
IN3 D10
IN4 D11
VCC External 5V (NOT Arduino 5V; too much current)
GND Arduino GND + external supply GND

Step Modes

Full step (4 steps per cycle): Strongest torque, coarser positioning.

Step IN1 IN2 IN3 IN4
1 HIGH LOW LOW LOW
2 LOW HIGH LOW LOW
3 LOW LOW HIGH LOW
4 LOW LOW LOW HIGH

Half step (8 steps per cycle): Smoother movement, double the resolution.

The half-step sequence interleaves single-coil and dual-coil energizations, giving 8 positions per cycle instead of 4.

Code: Stepper with AccelStepper Library

The built-in Stepper library works but lacks acceleration control. The AccelStepper library is much better for smooth motion.

Install AccelStepper from the Library Manager.

/*
 * Module 10: Stepper Motor with AccelStepper
 *
 * Circuit:
 * - ULN2003: IN1→D8, IN2→D10, IN3→D9, IN4→D11
 *   (Note: pin order for AccelStepper is IN1, IN3, IN2, IN4)
 * - ULN2003 VCC → External 5V supply
 * - ULN2003 GND → Arduino GND + external GND
 *
 * Library: AccelStepper
 * Board: Arduino Uno
 */

#include <AccelStepper.h>

// For 28BYJ-48 with ULN2003, use HALF4WIRE mode
// Pin order: IN1, IN3, IN2, IN4 (not sequential!)
AccelStepper stepper(AccelStepper::HALF4WIRE, 8, 10, 9, 11);

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

  stepper.setMaxSpeed(1000);       // Steps per second
  stepper.setAcceleration(500);    // Steps per second²

  Serial.println("Stepper ready");
}

void loop() {
  // Rotate one full revolution (2048 half-steps for 28BYJ-48)
  stepper.moveTo(2048);

  // Run until target reached
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }

  delay(500);

  // Return to start
  stepper.moveTo(0);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }

  delay(500);
}

Pin order warning: The AccelStepper library expects pins in the order IN1, IN3, IN2, IN4 for the 28BYJ-48. This is not a typo; it matches the coil activation sequence. If your motor vibrates but doesn't turn, the pin order is wrong.

Holding Torque and Power

When a stepper holds position, it continuously draws current through its coils to maintain torque. This means:

// Release all coils — motor can spin freely, draws no current
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);

10.4 Why Motors Need Separate Power

This topic was introduced in Module 5, but it's so critical for motor projects that we reinforce it here.

The Three Motor Power Problems

1. Current spikes: Motors draw much more current when starting or reversing than when running at steady speed. A motor rated for 300 mA might spike to 1A for a fraction of a second. If powered from the Arduino's 5V rail, this drops the voltage and resets the board.

2. Electrical noise: Motor brushes (in DC motors) create electromagnetic interference that appears as voltage spikes on the power line. These can corrupt sensor readings, cause I2C communication failures, and trigger false interrupts.

3. Back-EMF: When a motor is disconnected or suddenly stops, the collapsing magnetic field generates a reverse voltage that can damage driver ICs and the Arduino.

Protection Strategy

For every motor project, follow this checklist:

Motor Shields vs. Discrete Drivers

Approach Pros Cons
Motor shield (e.g., Adafruit Motor Shield) Clean stacking, integrated design, library support Expensive ($15–25), fixed pin usage
Discrete driver module (L298N, A4988) Cheap ($2–5), flexible pin choice More wiring, needs external power setup
Discrete transistors / MOSFETs Cheapest, fully custom Most complex, must add own protection

For learning, discrete driver modules are the best balance of cost and simplicity. For polished projects, shields are cleaner.


Module Project: Motorized Turntable

Objective

Build a stepper-motor-driven turntable that rotates an object at a speed controlled by a potentiometer. An OLED display shows the current angle and speed. Pressing a button resets the position to 0°.

Components Needed

Component Quantity Notes
Arduino Uno 1
USB-B cable 1
Breadboard 1
28BYJ-48 stepper motor + ULN2003 driver 1 set
SSD1306 OLED (128×64, I2C) 1
Potentiometer (10kΩ) 1 Speed control
Pushbutton 1 Position reset
External 5V/2A power supply 1 For stepper motor
470µF electrolytic capacitor 1 Motor power smoothing
Jumper wires 10+

The Code

/*
 * Module 10 Project: Motorized Turntable
 *
 * Stepper motor turntable with:
 * - Potentiometer speed control (center = stop, left = CCW, right = CW)
 * - OLED showing angle and speed
 * - Button to reset position to 0°
 *
 * Circuit:
 * - Stepper: ULN2003 IN1→D8, IN3→D10, IN2→D9, IN4→D11
 * - ULN2003 power: EXTERNAL 5V (not Arduino!)
 * - OLED: SDA→A4, SCL→A5 (I2C)
 * - Potentiometer: wiper→A0, ends→5V/GND
 * - Button: pin 7 (INPUT_PULLUP)
 * - 470µF cap across external 5V supply
 * - All GNDs connected together
 *
 * Libraries: AccelStepper, Adafruit SSD1306
 * Board: Arduino Uno
 */

#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>

// --- Pins ---
const int POT_PIN = A0;
const int BUTTON_PIN = 7;

// --- Stepper (28BYJ-48 with ULN2003) ---
AccelStepper stepper(AccelStepper::HALF4WIRE, 8, 10, 9, 11);
const int STEPS_PER_REV = 2048;  // Half-step mode

// --- OLED ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// --- State ---
long currentSteps = 0;
float currentAngle = 0;
float currentSpeedRPM = 0;
bool isRunning = false;

// --- Debounce ---
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;

// --- Display timing ---
unsigned long lastDisplayUpdate = 0;
const unsigned long DISPLAY_INTERVAL = 200;

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

  // Stepper setup
  stepper.setMaxSpeed(800);
  stepper.setAcceleration(400);

  // Button
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  // OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED not found");
    while (1);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);

  // Splash screen
  display.setTextSize(2);
  display.setCursor(10, 10);
  display.println("Turntable");
  display.setTextSize(1);
  display.setCursor(10, 40);
  display.println("Module 10 Project");
  display.display();
  delay(2000);

  Serial.println("Turntable ready");
}

void updateDisplay() {
  display.clearDisplay();

  // Title
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("TURNTABLE");

  // Running indicator
  display.setCursor(80, 0);
  display.print(isRunning ? "[RUN]" : "[STOP]");

  display.drawLine(0, 10, 127, 10, SSD1306_WHITE);

  // Angle (large)
  display.setTextSize(2);
  display.setCursor(0, 14);
  char angleStr[10];
  dtostrf(currentAngle, 6, 1, angleStr);
  display.print(angleStr);
  display.setTextSize(1);
  display.setCursor(80, 14);
  display.print("deg");

  // Visual angle indicator (circle with line)
  int centerX = 106;
  int centerY = 22;
  int radius = 10;
  display.drawCircle(centerX, centerY, radius, SSD1306_WHITE);
  float rad = currentAngle * PI / 180.0;
  int lineX = centerX + radius * sin(rad);
  int lineY = centerY - radius * cos(rad);
  display.drawLine(centerX, centerY, lineX, lineY, SSD1306_WHITE);

  // Speed
  display.setTextSize(1);
  display.setCursor(0, 36);
  display.print("Speed: ");
  display.print(currentSpeedRPM, 1);
  display.print(" RPM");

  // Direction
  display.setCursor(0, 48);
  if (currentSpeedRPM > 0.1) {
    display.print("Direction: CW");
  } else if (currentSpeedRPM < -0.1) {
    display.print("Direction: CCW");
  } else {
    display.print("Direction: ---");
  }

  // Steps counter
  display.setCursor(0, 57);
  display.print("Steps: ");
  display.print(stepper.currentPosition());

  display.display();
}

void handleButton() {
  unsigned long now = millis();
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState) {
    lastDebounceTime = now;
  }

  if ((now - lastDebounceTime) > 50) {
    static int buttonState = HIGH;
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        // Reset position
        stepper.setCurrentPosition(0);
        currentAngle = 0;
        Serial.println("Position reset to 0°");
      }
    }
  }
  lastButtonState = reading;
}

void loop() {
  unsigned long now = millis();

  // --- Read potentiometer ---
  int potValue = analogRead(POT_PIN);

  // Dead zone in the center (stop zone)
  if (potValue > 480 && potValue < 544) {
    // Stop
    stepper.setSpeed(0);
    isRunning = false;
    currentSpeedRPM = 0;
  } else {
    // Map pot to speed: left half = negative (CCW), right half = positive (CW)
    float speed;
    if (potValue >= 544) {
      speed = map(potValue, 544, 1023, 0, 700);
    } else {
      speed = map(potValue, 480, 0, 0, -700);
    }
    stepper.setSpeed(speed);
    isRunning = true;

    // Convert steps/sec to RPM
    currentSpeedRPM = (speed / STEPS_PER_REV) * 60.0;
  }

  // --- Run stepper ---
  if (isRunning) {
    stepper.runSpeed();
  }

  // --- Calculate angle ---
  long pos = stepper.currentPosition();
  currentAngle = fmod((pos * 360.0 / STEPS_PER_REV), 360.0);
  if (currentAngle < 0) currentAngle += 360.0;

  // --- Handle button ---
  handleButton();

  // --- Update display ---
  if (now - lastDisplayUpdate >= DISPLAY_INTERVAL) {
    lastDisplayUpdate = now;
    updateDisplay();
  }
}

Circuit Diagram (SVG)

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 500" font-family="monospace" font-size="11">
  <!-- Arduino -->
  <rect x="30" y="100" width="140" height="310" fill="#1a7a8a" stroke="#333" stroke-width="2" rx="8"/>
  <text x="100" y="128" text-anchor="middle" fill="white" font-size="14" font-weight="bold">Arduino Uno</text>

  <!-- Pins -->
  <rect x="170" y="150" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="160" text-anchor="middle" fill="white" font-size="8">5V</text>
  <rect x="170" y="170" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="180" text-anchor="middle" fill="white" font-size="8">GND</text>
  <rect x="170" y="210" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="220" text-anchor="middle" fill="white" font-size="8">A0</text>
  <rect x="170" y="240" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="250" text-anchor="middle" fill="white" font-size="8">A4</text>
  <rect x="170" y="260" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="270" text-anchor="middle" fill="white" font-size="8">A5</text>
  <rect x="170" y="300" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="310" text-anchor="middle" fill="white" font-size="8">D7</text>
  <rect x="170" y="330" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="340" text-anchor="middle" fill="white" font-size="8">D8</text>
  <rect x="170" y="350" width="22" height="14" fill="#2a8a9a" stroke="white" stroke-width="1" rx="2"/>
  <text x="181" y="360" text-anchor="middle" fill="white" font-size="8">D9-11</text>

  <!-- External Power -->
  <rect x="620" y="100" width="120" height="55" fill="#cc4444" stroke="#333" stroke-width="2" rx="6"/>
  <text x="680" y="122" text-anchor="middle" fill="white" font-size="11" font-weight="bold">External</text>
  <text x="680" y="140" text-anchor="middle" fill="white" font-size="10">5V / 2A</text>

  <rect x="755" y="115" width="35" height="18" fill="none" stroke="#333" stroke-width="1.5" rx="3"/>
  <text x="773" y="128" text-anchor="middle" font-size="7">470µF</text>

  <!-- Shared GND -->
  <line x1="192" y1="177" x2="750" y2="177" stroke="blue" stroke-width="2" stroke-dasharray="6,3"/>
  <text x="460" y="172" text-anchor="middle" font-size="9" fill="blue" font-weight="bold">SHARED GND</text>

  <!-- ULN2003 + Stepper -->
  <rect x="500" y="230" width="120" height="80" fill="#ff9933" stroke="#333" stroke-width="2" rx="6"/>
  <text x="560" y="255" text-anchor="middle" font-size="11" font-weight="bold" fill="white">ULN2003</text>
  <text x="560" y="275" text-anchor="middle" font-size="9" fill="white">+ 28BYJ-48</text>
  <text x="560" y="295" text-anchor="middle" font-size="8" fill="#ffddaa">Stepper Motor</text>

  <!-- Stepper control wires -->
  <line x1="192" y1="337" x2="500" y2="250" stroke="orange" stroke-width="1.5"/>
  <text x="340" y="280" font-size="8" fill="orange">IN1-IN4 (D8-D11)</text>

  <!-- Stepper power from external -->
  <line x1="680" y1="155" x2="680" y2="240" stroke="red" stroke-width="2"/>
  <line x1="680" y1="240" x2="620" y2="240" stroke="red" stroke-width="2"/>
  <text x="655" y="230" font-size="8" fill="red">EXT 5V</text>

  <!-- OLED Display -->
  <rect x="350" y="360" width="130" height="70" fill="#222" stroke="#333" stroke-width="2" rx="6"/>
  <rect x="363" y="370" width="104" height="42" fill="#000" stroke="#555" stroke-width="1" rx="3"/>
  <text x="415" y="390" text-anchor="middle" fill="#00ccff" font-size="10">123.5° CW</text>
  <text x="415" y="404" text-anchor="middle" fill="#00ccff" font-size="8">5.2 RPM</text>
  <text x="415" y="425" text-anchor="middle" fill="white" font-size="9">SSD1306 OLED</text>

  <line x1="192" y1="247" x2="350" y2="385" stroke="#cc8800" stroke-width="1.5"/>
  <text x="260" y="320" font-size="8" fill="#cc8800">SDA (A4)</text>
  <line x1="192" y1="267" x2="350" y2="400" stroke="#008800" stroke-width="1.5"/>
  <text x="260" y="340" font-size="8" fill="#008800">SCL (A5)</text>

  <!-- Potentiometer -->
  <rect x="350" y="100" width="80" height="40" fill="#ddd" stroke="#333" stroke-width="1.5" rx="4"/>
  <text x="390" y="122" text-anchor="middle" font-size="9">10kΩ POT</text>
  <line x1="192" y1="217" x2="350" y2="120" stroke="green" stroke-width="1.5"/>
  <text x="265" y="165" font-size="8" fill="green">Wiper (A0)</text>

  <!-- Button -->
  <rect x="350" y="160" width="70" height="30" fill="none" stroke="#333" stroke-width="1.5" rx="4"/>
  <text x="385" y="179" text-anchor="middle" font-size="9">Reset BTN</text>
  <line x1="192" y1="307" x2="350" y2="175" stroke="purple" stroke-width="1.5"/>
  <text x="265" y="238" font-size="8" fill="purple">D7</text>
</svg>

Circuit Schema (JSON)

{
  "module": 10,
  "project": "Motorized Turntable",
  "board": "Arduino Uno",
  "schematic": {
    "components": [
      {
        "id": "U1", "type": "arduino_uno",
        "pins_used": {
          "5V": "net_arduino_vcc", "GND": "net_gnd",
          "A0": "net_pot_wiper", "A4": "net_sda", "A5": "net_scl",
          "D7": "net_button", "D8": "net_in1", "D9": "net_in2", "D10": "net_in3", "D11": "net_in4"
        }
      },
      { "id": "PS1", "type": "power_supply", "value": "5V", "max_current": "2A",
        "pins": { "positive": "net_ext_vcc", "negative": "net_gnd" } },
      { "id": "C1", "type": "capacitor_electrolytic", "value": "470", "unit": "uF",
        "pins": { "positive": "net_ext_vcc", "negative": "net_gnd" } },
      { "id": "DRV1", "type": "uln2003_driver",
        "pins": { "in1": "net_in1", "in2": "net_in2", "in3": "net_in3", "in4": "net_in4",
                  "vcc": "net_ext_vcc", "gnd": "net_gnd" } },
      { "id": "MOT1", "type": "stepper_motor", "model": "28BYJ-48",
        "steps_per_rev": 2048, "current_draw": "240mA",
        "connection": "Connected to ULN2003 output via ribbon cable" },
      { "id": "OLED1", "type": "ssd1306", "protocol": "I2C", "address": "0x3C",
        "pins": { "vcc": "net_arduino_vcc", "gnd": "net_gnd", "sda": "net_sda", "scl": "net_scl" } },
      { "id": "POT1", "type": "potentiometer", "value": "10000", "unit": "ohm",
        "pins": { "pin1": "net_arduino_vcc", "wiper": "net_pot_wiper", "pin3": "net_gnd" } },
      { "id": "SW1", "type": "pushbutton",
        "pins": { "pinA": "net_button", "pinB": "net_gnd" } }
    ],
    "nets": [
      { "name": "net_gnd", "description": "Shared ground", "nodes": ["U1.GND", "PS1.negative", "C1.negative", "DRV1.gnd", "OLED1.gnd", "POT1.pin3", "SW1.pinB"] },
      { "name": "net_arduino_vcc", "nodes": ["U1.5V", "OLED1.vcc", "POT1.pin1"] },
      { "name": "net_ext_vcc", "description": "External 5V for motor", "nodes": ["PS1.positive", "C1.positive", "DRV1.vcc"] },
      { "name": "net_sda", "nodes": ["U1.A4", "OLED1.sda"] },
      { "name": "net_scl", "nodes": ["U1.A5", "OLED1.scl"] },
      { "name": "net_pot_wiper", "nodes": ["U1.A0", "POT1.wiper"] },
      { "name": "net_button", "nodes": ["U1.D7", "SW1.pinA"] },
      { "name": "net_in1", "nodes": ["U1.D8", "DRV1.in1"] },
      { "name": "net_in2", "nodes": ["U1.D9", "DRV1.in2"] },
      { "name": "net_in3", "nodes": ["U1.D10", "DRV1.in3"] },
      { "name": "net_in4", "nodes": ["U1.D11", "DRV1.in4"] }
    ],
    "power": {
      "usb": { "voltage": 5.0, "used_ma": 90, "note": "Arduino + OLED + pot" },
      "external": { "voltage": 5.0, "used_ma": 240, "note": "Stepper motor" }
    }
  },
  "code": { "filename": "module10_turntable.ino", "language": "cpp" },
  "validation": {
    "expected_behavior": "Pot controls speed and direction. OLED shows angle, RPM, direction. Button resets to 0°. Motor powered externally — no Arduino resets.",
    "common_mistakes": [
      "Motor vibrates but doesn't turn: AccelStepper pin order wrong — use IN1, IN3, IN2, IN4",
      "Arduino resets when motor moves: motor drawing from Arduino 5V — use external supply",
      "Motor runs in wrong direction: swap any two adjacent input pins",
      "OLED flickers when motor runs: add 0.1µF cap near OLED, keep motor wires away from I2C lines",
      "Speed unresponsive: pot center dead zone too wide or too narrow — adjust 480/544 values"
    ]
  }
}

Self-Check: Module 10

Before moving to Module 11, make sure you can:


Key Terms Glossary

Term Definition
Servo motor Motor with built-in feedback for precise angle control (0°–180°)
DC motor Continuous rotation motor. Speed depends on voltage, direction on polarity
Stepper motor Motor that moves in discrete steps for precise position control
H-bridge Circuit that allows reversing motor polarity for bidirectional control
L298N Common dual H-bridge motor driver module
Back-EMF Voltage spike generated by a motor's collapsing magnetic field
Flyback diode Diode that safely absorbs back-EMF energy
ULN2003 Darlington transistor array commonly used to drive stepper motors
AccelStepper Library for smooth stepper control with acceleration/deceleration
Holding torque Force a stepper applies while stationary to hold position
NEMA 17 Standard bipolar stepper motor size used in 3D printers and CNC
Half-step Stepper mode that doubles resolution by interleaving coil activations
Continuous rotation servo Modified servo that rotates 360°. Speed control, not position

Previous: ← Module 9: Sound & Audio Next: Module 11: Arduino Nano & Compact Builds →