Intermediate Level • Lesson 7

⚙️ Controlling Motors

⏱️ 50 minutes 📚 Intermediate 🎯 Motor Control
⚙️

Controlling Motors

Learn how to control motors with your Raspberry Pi - this lets you build moving projects like fans, robots, and more!

Types of Motors

There are different types of motors you can control. Here are the most common ones:

🔄

Servo Motor

Moves to specific angles (0-180 degrees)

Perfect for pan/tilt, robot arms

DC Motor

Spins continuously at variable speed

Perfect for fans, wheels, propellers

🎯

Stepper Motor

Moves in precise steps

Perfect for 3D printers, precise positioning

What is PWM?

PWM stands for Pulse Width Modulation. It's a way to control motors by rapidly turning power on and off. By changing how long the power is on vs off, you can control speed or position!

💡 Think of it like: If you flick a light switch on and off very fast, the light appears dimmer. PWM works the same way - rapid on/off pulses control motor speed or servo position.

Controlling Servo Motors

Servo motors can move to specific angles (usually 0-180 degrees). They're perfect for pan/tilt cameras, robot arms, and steering mechanisms.

Materials Needed:

  • Raspberry Pi
  • Servo motor (SG90 is common and affordable)
  • Jumper wires
  • External power supply (recommended for larger servos)

Wiring Instructions:

  1. Red wire (VCC): Connect to 5V (or external 5V power supply)
  2. Black/Brown wire (GND): Connect to GND
  3. Orange/Yellow wire (Signal): Connect to GPIO 18 (PWM pin)

Note: Small servos can run from Raspberry Pi power, but larger ones need external power supply!

Servo Control Code:

import RPi.GPIO as GPIO import time # Set up GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.OUT) # Create PWM object (50 Hz is standard for servos) pwm = GPIO.PWM(18, 50) # Pin 18, 50 Hz frequency pwm.start(0) # Start with 0% duty cycle def set_angle(angle): # Convert angle (0-180) to duty cycle (2-12%) # 0 degrees = 2% duty cycle # 90 degrees = 7% duty cycle # 180 degrees = 12% duty cycle duty = 2 + (angle / 180) * 10 pwm.ChangeDutyCycle(duty) try: # Move servo to different positions print("Moving to 0 degrees...") set_angle(0) time.sleep(1) print("Moving to 90 degrees...") set_angle(90) time.sleep(1) print("Moving to 180 degrees...") set_angle(180) time.sleep(1) print("Moving back to 0 degrees...") set_angle(0) time.sleep(1) except KeyboardInterrupt: pwm.stop() GPIO.cleanup() print("Servo stopped!")

Understanding the Code:

  • GPIO.PWM(pin, frequency): Creates a PWM object - 50 Hz is standard for servos
  • pwm.start(0): Starts PWM with 0% duty cycle
  • set_angle(angle): Function that converts angle to duty cycle
  • Duty cycle formula: 2% = 0°, 7% = 90°, 12% = 180°
  • pwm.ChangeDutyCycle(): Changes the position of the servo

Controlling DC Motors

DC motors spin continuously. You can control their speed using PWM, and direction using an H-bridge motor driver.

DC Motor with L298N Driver:

import RPi.GPIO as GPIO import time # Motor control pins ENA = 18 # Enable pin (PWM for speed) IN1 = 23 # Direction control IN2 = 24 # Direction control GPIO.setmode(GPIO.BCM) GPIO.setup(ENA, GPIO.OUT) GPIO.setup(IN1, GPIO.OUT) GPIO.setup(IN2, GPIO.OUT) # Create PWM for speed control pwm = GPIO.PWM(ENA, 100) # 100 Hz frequency pwm.start(0) # Start at 0% speed def motor_forward(speed): GPIO.output(IN1, GPIO.HIGH) GPIO.output(IN2, GPIO.LOW) pwm.ChangeDutyCycle(speed) # Speed 0-100% def motor_backward(speed): GPIO.output(IN1, GPIO.LOW) GPIO.output(IN2, GPIO.HIGH) pwm.ChangeDutyCycle(speed) def motor_stop(): GPIO.output(IN1, GPIO.LOW) GPIO.output(IN2, GPIO.LOW) pwm.ChangeDutyCycle(0) try: print("Motor forward at 50% speed...") motor_forward(50) time.sleep(3) print("Motor backward at 30% speed...") motor_backward(30) time.sleep(3) motor_stop() print("Motor stopped!") except KeyboardInterrupt: motor_stop() pwm.stop() GPIO.cleanup()

Project: Servo Motor Position Controller

Let's create a system that moves a servo motor to different positions!

Materials Needed:

  • Raspberry Pi
  • Servo motor (SG90 recommended)
  • Jumper wires
  • Optional: External 5V power supply

Complete Servo Control Code:

import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.OUT) pwm = GPIO.PWM(18, 50) pwm.start(0) def set_servo_angle(angle): """Move servo to a specific angle (0-180 degrees)""" duty = 2 + (angle / 180) * 10 pwm.ChangeDutyCycle(duty) time.sleep(0.3) # Give servo time to move pwm.ChangeDutyCycle(0) # Stop sending signal (prevents jitter) try: # Sweep from 0 to 180 degrees print("Sweeping servo from 0 to 180 degrees...") for angle in range(0, 181, 10): # Step by 10 degrees set_servo_angle(angle) print("Angle:", angle) time.sleep(0.5) # Sweep back print("Sweeping back to 0 degrees...") for angle in range(180, -1, -10): # Step down by 10 degrees set_servo_angle(angle) print("Angle:", angle) time.sleep(0.5) except KeyboardInterrupt: pwm.stop() GPIO.cleanup() print("Servo control stopped!")

Understanding the Code:

  • The servo sweeps smoothly from 0° to 180° in 10° steps
  • Then sweeps back from 180° to 0°
  • pwm.ChangeDutyCycle(0) after movement prevents servo jitter
  • This creates a smooth back-and-forth motion

Common Mistakes to Avoid

⚠️ Watch Out For:

  • Wrong Frequency: Servos need 50 Hz, DC motors can use 100-1000 Hz
  • Not Stopping PWM: Always call pwm.stop() before cleanup
  • Insufficient Power: Large motors need external power supply
  • Wrong Duty Cycle: Servos need 2-12% duty cycle for 0-180°
  • Forgetting Cleanup: Always call GPIO.cleanup() when done

Summary

You've learned:

  • ✅ Motors let you create moving projects
  • ✅ Servo motors move to specific angles (0-180 degrees)
  • ✅ DC motors spin continuously at variable speeds
  • ✅ PWM (Pulse Width Modulation) controls motor speed and position
  • ✅ Servos use 50 Hz PWM with 2-12% duty cycle for 0-180°
  • ✅ Always stop PWM and cleanup GPIO when done
  • ✅ Large motors may need external power supply
🎉 Great Work! You can now control motors! In the next lesson, you'll learn about using cameras for vision.

🎮 Try It: Practice with Motors!

Practice writing code to control motors. Try these challenges:

📝 Challenge 1: Servo to Center

Write code that moves a servo to 90 degrees (center position):

📝 Challenge 2: Servo Sweep

Write code that makes a servo sweep from 0 to 180 degrees and back:

💡 Tip: Remember that servos use 50 Hz frequency and duty cycle of 2-12% for 0-180 degrees. Always stop PWM and cleanup when done!

🎯 Activity: Servo Motor Position Controller

What You'll Build:

Create a system that controls a servo motor to move to different positions!

Step-by-Step Instructions:

  1. Wire Servo: Connect signal wire to GPIO 18, power to 5V, ground to GND
  2. Write Code: Use the servo control code from the Learn tab
  3. Test Basic Movement: Try moving to 0°, 90°, and 180°
  4. Create Sweep: Make servo sweep smoothly from 0 to 180 and back
  5. Experiment: Try different speeds and step sizes

Testing Checklist:

  • ✅ Servo moves to 0 degrees
  • ✅ Servo moves to 90 degrees (center)
  • ✅ Servo moves to 180 degrees
  • ✅ Servo sweeps smoothly without jitter
🏆 Bonus Challenge: Can you create a servo that moves to positions based on button presses? (Button 1 = 0°, Button 2 = 90°, Button 3 = 180°)

💪 Practice Challenges

Challenge 1: Servo Sequence

Create a sequence where servo moves: 0° → 45° → 90° → 135° → 180° → 0°

Challenge 2: Slow Sweep

Make the servo sweep very slowly (hint: use smaller steps and longer delays):

# Sweep from 0 to 180 in 1-degree steps # with 0.2 second delay between each step

Challenge 3: Button-Controlled Servo

Use a button to control servo position:

  • Press button once: Move to 0°
  • Press again: Move to 90°
  • Press again: Move to 180°
  • Press again: Back to 0° (cycle repeats)

Challenge 4: Code Detective

What's wrong with this servo code? Find and fix the mistakes!

import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.OUT) pwm = GPIO.PWM(18, 100) # Wrong frequency? pwm.start(50) # Wrong starting value? pwm.ChangeDutyCycle(90) # Wrong value? time.sleep(1)
Click to see the answer
import RPi.GPIO as GPIO import time # Added: missing import GPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.OUT) pwm = GPIO.PWM(18, 50) # Fixed: servos need 50 Hz, not 100 pwm.start(0) # Fixed: start at 0, not 50 # To move to 90 degrees: duty = 2 + (90 / 180) * 10 # Fixed: calculate duty cycle pwm.ChangeDutyCycle(duty) # Fixed: use calculated duty, not angle time.sleep(1) pwm.stop() # Added: stop PWM GPIO.cleanup() # Added: cleanup