5. Controlling a Positional Servo Motor with PWM (Basic)¶
This guide explains how to control a servo motor using Pulse Width Modulation (PWM) on the Raspberry Pi. We'll use a C++ program that interfaces with the Linux PWM subsystem to precisely position a servo motor.
Required Hardware¶
- Raspberry Pi (any model with hardware PWM support)
- Standard servo motor (Here, we use FS90 from FEETECH)
- Jumper wires
- Breadboard (optional, but recommended)
Hardware Setup¶
This guide uses GPIO 12 (PWM Channel 0) for the servo connection. Connect the components as follows:
- Connect the signal wire (orange for FS90) to GPIO 12
- Connect the ground wire (brown for FS90) to GND
- Connect the power wire (red for FS90) to 5V
graph LR
subgraph RPi["Raspberry Pi"]
GPIO12["GPIO 12 (PWM)"]
V5["5V"]
GND["GND"]
end
subgraph Servo["Servo Motor"]
Signal["Signal (Orange)"]
Power["Power (Red)"]
Ground["Ground (Brown)"]
end
GPIO12 --- Signal
V5 --- Power
GND --- Ground
style Servo fill:#50c878
Note: For larger servos or when controlling multiple servos, use an external 5V power supply to prevent overloading the Raspberry Pi's power regulator.
Servo Motor Basics¶
Servo motors are controlled by sending PWM (Pulse Width Modulation) signals:
- Pulse width determines position for FS90:
- 0.5ms pulse (~500μs): 0 degrees
- 1.5ms pulse (~1500μs): 90 degrees
- 2.5ms pulse (~2500μs): 180 degrees
PWM Setup Configuration¶
Before writing any code, you need to activate the PWM functionality on your Raspberry Pi. By default, the PWM channels are not activated on the GPIO pins.
Enabling PWM on GPIO Pins¶
The Raspberry Pi has two PWM channels (PWM0 and PWM1) that can be mapped to specific GPIO pins. You'll need to activate the appropriate channel for servo control.
Available PWM Channel Options¶
You have four possible configurations:
| PWM Channel | GPIO Pin | Function | Alt Mode | dtoverlay Configuration |
|---|---|---|---|---|
| PWM0 | 12 | 4 | Alt0 | dtoverlay=pwm,pin=12,func=4 |
| PWM0 | 18 | 2 | Alt5 | dtoverlay=pwm,pin=18,func=2 |
| PWM1 | 13 | 4 | Alt0 | dtoverlay=pwm,pin=13,func=4 |
| PWM1 | 19 | 2 | Alt5 | dtoverlay=pwm,pin=19,func=2 |
For this tutorial, we'll use GPIO 12 mapped to PWM0.
Configuration Steps¶
-
Edit the configuration file:
-
Add the following line at the end of the file:
- Reboot your Raspberry Pi:
After rebooting, your Raspberry Pi will have PWM0 activated on GPIO 12, ready for connecting a servo motor.
Code Explanation¶
This program uses the Linux sysfs interface to control hardware PWM on the Raspberry Pi to position a servo motor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
Key Program Elements¶
-
Signal Handling:
- The program sets up a signal handler to catch Ctrl+C (SIGINT)
- This allows for clean shutdown when the user terminates the program
-
PWM Configuration:
- The program uses GPIO 12, which is connected to hardware PWM channel 0
- PWM is accessed through the Linux sysfs interface at
/sys/class/pwm/pwmchip0 - Period is set to 20,000,000 nanoseconds (20ms or 50Hz)
-
Servo Position Control:
- 0 degrees: 500,000 nanoseconds (0.5ms) pulse width
- 90 degrees: 1,500,000 nanoseconds (1.5ms) pulse width
- 180 degrees: 2,500,000 nanoseconds (2.5ms) pulse width
-
Cleanup Process:
- Returns servo to 0 degrees position before exit
- Disables PWM output
- Unexports the PWM channel
-
Helper Functions:
write_sysfs: Utility function to write values to sysfs filessignal_handler: Handles SIGINT to enable clean program termination
Compiling and Running¶
-
Save the code to a file, e.g.,
servo_control.cpp -
Compile the program:
-
Run the program with root privileges (needed for PWM access):
-
The program will cycle the servo through 0°, 90°, 180°, and back to 90° positions. Press Ctrl+C to exit the program.
How It Works in Detail¶
-
PWM Export: The program exports PWM channel 0 to make it available for use.
-
Setting Period: The period is set to 20ms (20,000,000 nanoseconds), which is the standard for most servo motors.
-
Setting Duty Cycle: The duty cycle is what controls the servo position:
- 0° position: 2.5% duty cycle (0.5ms pulse in a 20ms period)
- 90° position: 7.5% duty cycle (1.5ms pulse in a 20ms period)
- 180° position: 12.5% duty cycle (2.5ms pulse in a 20ms period)
-
Enable PWM: Writing "1" to the enable file starts the PWM output.
-
Position Loop: The program cycles through different positions, waiting 2 seconds at each position.
-
Graceful Shutdown: When Ctrl+C is pressed, the program:
- Returns the servo to the 0° position
- Disables the PWM output
- Unexports the PWM channel
Troubleshooting¶
-
Servo Not Moving:
- Check connections, especially the signal wire to GPIO 12
- Ensure your servo is receiving adequate power
- Some servos may need slightly different pulse widths for the same angles
-
Permission Issues:
- The "Failed to open" error usually means the program needs administrator privileges
- In that case, run with
sudo
-
Jittery Movement:
- This could indicate insufficient power
- Use an external 5V power supply for the servo
-
PWM Already in Use:
- If another process is using the PWM channel, you might get errors
- The program handles this gracefully and continues execution
Taking It Further¶
You can expand this program to:
- Create a servo controller that accepts angle input from the user
- Implement smooth transitions between positions
- Control multiple servos for more complex motion
- Build a web interface to control servo positions remotely
- Use the servo for robotics projects like robotic arms or pan-tilt mechanisms
Safety Considerations¶
-
Power Requirements: Servos can draw substantial current. For larger servos or multiple servos, use an external power supply.
-
Mechanical Limits: Respect the mechanical limits of your servo. Some servos have physical stops and forcing them beyond these limits can damage gears.
-
Initial Position: It's good practice to set a known initial position (as this program does) to prevent unexpected movement.