舵机控制是整个追踪系统的硬件基础。本文对比三种驱动方式,重点讲解pigpio硬件PWM方案——这是树莓派5直驱双轴云台的最佳选择。
三种驱动方式对比
| 方案 | 库/接口 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| A. pigpio硬件PWM | pigpio + hardware_PWM() | 硬件定时器生成,零抖动;CPU占用极低 | 需启动pigpiod守护进程;Pi5仅有GPIO12/13两个硬件PWM通道 | 双轴云台,最适合本项目 |
| B. RPi.GPIO软件PWM | GPIO.PWM() | 无需额外依赖,简单 | 受GIL和系统负载影响,有抖动 | 单舵机调试、非关键应用 |
| C. PCA9685 I2C驱动板 | adafruit_servokit | 16路PWM,硬件生成,解放Pi GPIO | 需额外硬件(约15元) | 多舵机(机械臂、6轴云台) |
pigpio硬件PWM接线
| Pi5 GPIO | 物理引脚 | 接 |
|---|---|---|
| GPIO12 (PWM0) | Pin 32 | Pan舵机信号线(橙/黄) |
| GPIO13 (PWM1) | Pin 33 | Tilt舵机信号线(橙/黄) |
| 5V | Pin 2/4 | 两舵机VCC(建议外部电源) |
| GND | Pin 6/9 | 两舵机GND,与Pi共地 |
安装与启动
sudo apt install pigpio python3-pigpio
sudo pigpiod
# 或限定单核运行,避免核间延迟:
taskset 0x1 sudo pigpiod
PWM参数原理
舵机标准频率50Hz(周期20ms),占空比与角度对应关系(典型SG90/MG90S):
- 2.5% (0.5ms) → 0度
- 7.5% (1.5ms) → 90度(中位)
- 12.5% (2.5ms) → 180度
pigpio的 hardware_PWM(pin, freq, duty) 中 duty 单位是百万分比(0~1000000),7.5%占空比 = 75000。
关键参数范围
AutoTurret项目实测的SG90参数:
| 舵机 | 下限 | 上限 | 备注 |
|---|---|---|---|
| Pan | 35000 (3.5%) | 130000 (13%) | 实测180度范围 |
| Tilt | 45000 (4.5%) | 110000 (11%) | 机械限位约130度 |
完整代码:硬件PWM双轴控制
"""
servo_pigpio.py — 树莓派5 双轴云台硬件PWM控制(推荐方案)
来源:改编自 Cornell ECE5725 AutoTurret 项目
依赖:sudo apt install pigpio python3-pigpio
启动:sudo pigpiod (或 taskset 0x1 sudo pigpiod 减少核间延迟)
接线:
GPIO12 (Pin 32) -> Pan 舵机信号线
GPIO13 (Pin 33) -> Tilt 舵机信号线
外部5V电源 -> 两舵机VCC,GND与Pi5共地
"""
import time
import pigpio
# === 配置 ===
PAN_PIN = 12 # GPIO12 = 硬件PWM0
TILT_PIN = 13 # GPIO13 = 硬件PWM1
FREQ = 50 # 50Hz 标准
# 占空比上下限(百万分比;AutoTurret 实测值,SG90)
PAN_MIN, PAN_MAX = 35000, 130000 # 3.5% ~ 13%
TILT_MIN, TILT_MAX = 45000, 110000 # 4.5% ~ 11%
# 当前位置(全局可读写)
cur_pan = (PAN_MIN + PAN_MAX) // 2
cur_tilt = (TILT_MIN + TILT_MAX) // 2
pi = pigpio.pi()
if not pi.connected:
raise RuntimeError("pigpiod未启动,请先执行 sudo pigpiod")
# 初始居中
pi.hardware_PWM(PAN_PIN, FREQ, cur_pan)
pi.hardware_PWM(TILT_PIN, FREQ, cur_tilt)
def move_pan(direction, strength):
"""direction: -1左, 0停, +1右; strength: 1~5 步进档位"""
global cur_pan
increment = (PAN_MAX - PAN_MIN) / 150.0 # 150档细分
if direction == 0:
pi.hardware_PWM(PAN_PIN, FREQ, 0) # 关PWM防抖动
return
cur_pan += strength * increment * (1 if direction > 0 else -1)
cur_pan = max(PAN_MIN, min(PAN_MAX, cur_pan))
pi.hardware_PWM(PAN_PIN, FREQ, int(cur_pan))
def move_tilt(direction, strength):
"""direction: -1下, 0停, +1上"""
global cur_tilt
increment = (TILT_MAX - TILT_MIN) / 150.0
if direction == 0:
pi.hardware_PWM(TILT_PIN, FREQ, 0)
return
cur_tilt += strength * increment * (1 if direction > 0 else -1)
cur_tilt = max(TILT_MIN, min(TILT_MAX, cur_tilt))
pi.hardware_PWM(TILT_PIN, FREQ, int(cur_tilt))
def set_angle_direct(angle_pan, angle_tilt):
"""直接设角度(0~180度映射到PWM范围)"""
global cur_pan, cur_tilt
pan_duty = int(PAN_MIN + (angle_pan / 180.0) * (PAN_MAX - PAN_MIN))
tilt_duty = int(TILT_MIN + (angle_tilt / 180.0) * (TILT_MAX - TILT_MIN))
cur_pan = pan_duty
cur_tilt = tilt_duty
pi.hardware_PWM(PAN_PIN, FREQ, pan_duty)
pi.hardware_PWM(TILT_PIN, FREQ, tilt_duty)
if __name__ == "__main__":
try:
print("居中3秒...")
time.sleep(3)
# 扫描测试
for ang in range(0, 181, 10):
set_angle_direct(ang, 90)
time.sleep(0.1)
for ang in range(180, -1, -10):
set_angle_direct(ang, 90)
time.sleep(0.1)
set_angle_direct(90, 90) # 复位居中
except KeyboardInterrupt:
pass
finally:
pi.hardware_PWM(PAN_PIN, FREQ, 0)
pi.hardware_PWM(TILT_PIN, FREQ, 0)
pi.stop()
安全注意事项
- 务必外部5V电源驱动舵机:SG90堵转电流可达500mA以上,两个同时转动会让Pi5的5V引脚电压跌落引发重启。
- 共地:外部电源GND必须与Pi5 GND相连,否则PWM信号参考不稳。
- 限位:代码中必须设置安全角度上下限,防止机构卡死或齿轮打坏。
- 断电顺序:先断Pi5电源,再断舵机电源;上电反过来,避免舵机在Pi5未就绪时乱转。
备选方案:PCA9685驱动板
如果Pi5的GPIO12/13硬件PWM通道不够用,或需要驱动更多舵机,PCA9685是最佳备选。它通过I2C接口控制,提供16路硬件PWM,完全不占CPU。安装方式:
sudo raspi-config -> Interface Options -> I2C -> Enable
pip install adafruit-circuitpython-servokit
使用起来非常简单,from adafruit_servokit import ServoKit; kit = ServoKit(channels=16) 即可,然后 kit.servo[0].angle = 90 直接设角度。