Pi视觉追踪(二):舵机控制方案

舵机控制是整个追踪系统的硬件基础。本文对比三种驱动方式,重点讲解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()

安全注意事项

  1. 务必外部5V电源驱动舵机:SG90堵转电流可达500mA以上,两个同时转动会让Pi5的5V引脚电压跌落引发重启。
  2. 共地:外部电源GND必须与Pi5 GND相连,否则PWM信号参考不稳。
  3. 限位:代码中必须设置安全角度上下限,防止机构卡死或齿轮打坏。
  4. 断电顺序:先断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 直接设角度。


已发布

分类

,

来自