Skip to main content

Servo Control with gpiod

A comprehensive Python implementation for controlling servo motors using the gpiod library on Raspberry Pi and other Linux systems with GPIO support.

Features

  • Full PWM Control: Software-generated PWM signals using gpiod
  • Flexible Configuration: Customizable frequency, pulse width ranges, and angle limits
  • Multiple Control Methods: Angle-based, pulse width direct, and percentage-based control
  • Thread-Safe: Concurrent access protection with threading locks
  • Sweep Functions: Smooth servo movement between positions
  • Calibration Support: Custom pulse width calibration for different servo types
  • Context Manager: Automatic cleanup with with statement
  • Comprehensive Testing: Full test suite with mock hardware support
  • Error Handling: Custom exceptions and robust error management

Servo Control with gpiod

A comprehensive Python implementation for controlling servo motors using the gpiod library on Raspberry Pi and other Linux systems with GPIO support.


Requirements

PyPI Version PyPI Status Python Version PyPI Downloads License GitHub Stars GitHub Issues GitHub Forks Build and Test Publish to PyPI Code Size

Servo Class

Constructor

Servo(pin, chip="gpiochip4", frequency=50, min_pulse_width=1.0, max_pulse_width=2.0, min_angle=0, max_angle=90)
Parameter Type Default Description
pin int required GPIO pin number for servo signal
chip str "gpiochip4" GPIO chip name
frequency int 50 PWM frequency in Hz
min_pulse_width float 1.0 Minimum pulse width in ms
max_pulse_width float 2.0 Maximum pulse width in ms
min_angle int 0 Minimum servo angle in degrees
max_angle int 90 Maximum servo angle in degrees

Methods

Method Description
set_angle(angle) Set specific angle (degrees)
set_angle_rad(angle) Set specific angle (radians)
center() Move to center position
move_to_min() Move to minimum angle
move_to_max() Move to maximum angle
set_pulse_width(width_ms) Set pulse width directly (ms)
set_position_percent(percent) Set position as percentage (0-100%)
sweep(start, end, duration, steps=50) Smooth sweep between angles over duration
get_current_angle() Returns current angle
get_current_pulse_width() Returns current pulse width (ms)
get_current_position_percent() Returns current position (%)
is_running() Returns True if PWM is active
start() Start PWM signal generation
stop() Stop PWM signal generation
cleanup() Release GPIO resources
calibrate(min_pulse, max_pulse) Calibrate pulse width range
  • Python 3.12.3+
  • gpiod library (version 2.0+)
  • Linux system with GPIO support (Raspberry Pi, etc.)

Installation

pip install python-servo-gpiod

From Source

git clone https://github.com/Svndsn/python-servo.git
cd python-servo
pip install -e .

Quick Start

from python_servo_gpiod import Servo

# Create and use servo with context manager (recommended)
with Servo(pin=18) as servo:
    servo.set_angle(90)    # Move to 90 degrees
    servo.center()         # Move to center position
    servo.sweep(0, 90, 3) # Sweep from 0 to 90 degrees over 3 seconds

# Manual control
servo = Servo(pin=18)
servo.start()              # Start PWM
servo.set_angle(45)        # Set angle
servo.stop()               # Stop PWM
servo.cleanup()            # Clean up resources

API Reference

Servo Class

Constructor

Servo(pin, chip="gpiochip4", frequency=50, 
      min_pulse_width=1.0, max_pulse_width=2.0, 
      min_angle=0, max_angle=90)

Parameters:

  • pin: GPIO pin number for servo signal
  • chip: GPIO chip (default: "gpiochip4")
  • frequency: PWM frequency in Hz (default: 50Hz)
  • min_pulse_width: Minimum pulse width in ms (default: 1.0ms)
  • max_pulse_width: Maximum pulse width in ms (default: 2.0ms)
  • min_angle: Minimum servo angle in degrees (default: 0°)
  • max_angle: Maximum servo angle in degrees (default: 90°)

Control Methods

Angle Control:

servo.set_angle(angle)              # Set specific angle
servo.center()                      # Move to center position
servo.move_to_min()                 # Move to minimum angle
servo.move_to_max()                 # Move to maximum angle

Pulse Width Control:

servo.set_pulse_width(width_ms)     # Set pulse width directly (ms)

Percentage Control:

servo.set_position_percent(percent) # Set position as percentage (0-100%)

Movement Functions:

servo.sweep(start_angle, end_angle, duration, steps=50)
# Smooth sweep between angles over specified duration

Status Methods

servo.get_current_angle()           # Returns current angle
servo.get_current_pulse_width()     # Returns current pulse width (ms)
servo.get_current_position_percent() # Returns current position (%)
servo.is_running()                  # Returns True if PWM is active

PWM Control

servo.start()                       # Start PWM signal generation
servo.stop()                        # Stop PWM signal generation
servo.cleanup()                     # Release GPIO resources

Calibration

servo.calibrate(min_pulse, max_pulse) # Calibrate pulse width range

Examples

Basic Usage

from python_servo_gpiod import Servo
import time

# Initialize servo on GPIO pin 18
servo = Servo(pin=18)
servo.start()

# Test different positions
servo.set_angle(0)      # 0 degrees
time.sleep(1)
servo.set_angle(45)     # 45 degrees  
time.sleep(1)
servo.set_angle(90)    # 90 degrees
time.sleep(1)

servo.cleanup()

Custom Servo Configuration

# Configure for a servo with different specifications
servo = Servo(
    pin=20,
    frequency=60,           # 60Hz instead of 50Hz
    min_pulse_width=0.5,    # 0.5ms minimum pulse
    max_pulse_width=2.5,    # 2.5ms maximum pulse
    min_angle=-90,          # -90 to +90 degree range
    max_angle=90
)

Percentage Control

with Servo(pin=18) as servo:
    servo.set_position_percent(0)    # Minimum position
    time.sleep(1)
    servo.set_position_percent(50)   # Center position
    time.sleep(1)
    servo.set_position_percent(100)  # Maximum position

Smooth Sweeping

with Servo(pin=18) as servo:
    # Sweep from 0 to 90 degrees over 5 seconds
    servo.sweep(0, 90, duration=5.0, steps=100)
    
    # Sweep back with fewer steps (less smooth)
    servo.sweep(90, 0, duration=3.0, steps=30)

Calibration for Custom Servos

servo = Servo(pin=18)
# Calibrate for a servo that needs 0.8ms to 2.2ms pulse widths
servo.calibrate(0.8, 2.2)
servo.start()

# Now angle control uses the calibrated pulse widths
servo.set_angle(90)  # Uses 1.5ms pulse width

Testing

Run Unit Tests

python test_servo.py --verbose

Hardware Testing

# WARNING: Only run with real servo connected!
python test_servo.py --hardware

Demo Scripts

# Simple demonstration
python demo.py simple

# Interactive control
python demo.py interactive

# Performance benchmark
python demo.py benchmark

PWM Signal Details

The servo generates PWM signals with the following characteristics:

  • Default Frequency: 50Hz (20ms period)
  • Pulse Width Range: 1.0ms to 2.0ms
  • Resolution: Limited by Python's time.sleep() precision
  • Duty Cycle: 5% (1ms) to 10% (2ms) at 50Hz

Timing Calculations

  • 0° position: 1.0ms pulse width (5% duty cycle)
  • 45° position: 1.5ms pulse width (7.5% duty cycle)
  • 90° position: 2.0ms pulse width (10% duty cycle)

Thread Safety

The Servo class is thread-safe for concurrent access:

  • Multiple threads can safely call angle/position setting methods
  • PWM generation runs in a separate daemon thread
  • Thread locks protect shared state variables

Error Handling

The implementation includes comprehensive error handling:

try:
    servo = Servo(pin=18)
    servo.start()
    servo.set_angle(270)  # Invalid angle
except ServoError as e:
    print(f"Servo error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
finally:
    servo.cleanup()

Common error conditions:

  • GPIO initialization failures
  • Invalid angle ranges
  • Invalid pulse width values
  • PWM already running when starting
  • Hardware access permissions

Hardware Connections

Standard Servo Connection

Servo Wire Colors:
- Red:  +5V power supply
- Brown/Black: Ground (GND)
- Orange: Signal (connect to GPIO pin)

Limitations

  1. Software PWM: Uses software timing, less precise than hardware PWM
  2. CPU Usage: PWM generation consumes CPU cycles
  3. Timing Jitter: Python's threading may introduce small timing variations
  4. Single Servo: Each instance controls one servo (multiple instances needed for multiple servos)

Performance

Typical performance characteristics:

  • Command Response: < 1ms for angle/position changes
  • PWM Frequency: Stable 50Hz ±1Hz
  • Pulse Width Accuracy: ±50μs (depending on system load)
  • CPU Usage: ~1-2% per active servo on Raspberry Pi 5

License

This project is licensed under the MIT License.

See LICENSE.md for full license details.

Contributing

Feel free to submit issues, improvements, or extensions to this servo control implementation.

Release files for python-servo-gpiod 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-servo-gpiod 1.1.1
File Size Uploaded
python_servo_gpiod-1.1.1.tar.gz 17.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-servo-gpiod 1.1.1
File Interpreter ABI Platform
python_servo_gpiod-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 31.8 kB

Release files / python_servo_gpiod-1.1.1.tar.gz

Download URL python_servo_gpiod-1.1.1.tar.gz
Size 17.2 kB
Tags Source
SHA-256 checksum
How to use checksums
3b86221d1c7229d31f19fad1448a475054426179f6e70700ae4acc960ec4ba51
BLAKE2b-256 checksum
How to use checksums
8cb80366b87c0cf72a199db7a7b6e52ded0a45a31d35b30ee52558c5f8bf77dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2025.

Transparency log

Release files / python_servo_gpiod-1.1.1-py3-none-any.whl

Download URL python_servo_gpiod-1.1.1-py3-none-any.whl
Size 14.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
05bb78841a170acd514a6f72988ebfae3b7485d980f8acb575ce7b9bb266fa69
BLAKE2b-256 checksum
How to use checksums
3b6d59bba53a6af79b14affa1fcf496cade05c173c78f21102bea192b6e8853c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page