3.16. 舵机控制¶
业余(RC)舵机是装在密封外壳内、内置闭环位置控制的小型齿轮电机。外壳内部有一个直流电机、一个减速齿轮箱、一个连接到输出轴的电位器,以及一块小型驱动板,用于将电位器的读数与来自外部的设定值进行比较。驱动板会让电机朝着减小误差的方向转动,并在位置匹配时停止。从摄像头一侧看,这一切都不可见——你只需告诉舵机要去到哪里。
3.16.1. PWM 信号¶
舵机以固定 50 Hz 帧率的 PWM 信号作为其设定值,其中脉冲宽度决定位置:
1.0 ms 的脉冲驱动轴转到其行程的一端。
1.5 ms 的脉冲使轴停在中心位置。
2.0 ms 的脉冲驱动轴转到行程的另一端。
介于两者之间的任何值都映射到一个中间位置。
舵机的 PWM 帧长为 20 ms;脉冲宽度(1.0 -- 2.0 ms)决定位置。¶
与 LED 和电机不同,舵机并不对 PWM 取平均。脉冲宽度本身就是命令:舵机的内部逻辑测量每个脉冲,据此设定目标,并驱动电机直到输出与之匹配。占空比作为一个比例(在整个范围内介于 5 % 和 10 % 之间)只是附带的——真正起作用的是绝对脉冲宽度,这也是软件需要控制的对象。
3.16.2. 接线¶
业余舵机使用三线连接器:
电源(通常为红色):舵机自身的供电,通常为 4.8 V 到 6 V。不要用摄像头的 3.3 V 电平轨为舵机供电——它无法提供堵转电流,且该电平轨会出现欠压。
地(通常为黑色或棕色):舵机电源的回流路径,连接到摄像头的地,使信号也具有共同的参考基准。
信号(通常为白色、黄色或橙色):来自摄像头 GPIO 的 PWM 线。
3.16.3. 代码¶
duty_u16() 也可以用,但它是按周期的比例来设定占空比的——对于一个真正起作用的是绝对脉冲宽度、且周期固定的信号来说,这很不方便。duty_ns() 则直接以纳秒为单位设定脉冲宽度:
from machine import PWM, Pin
servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000) # centre
载波为 50 Hz(20 ms 周期);每个周期的高电平时间正好是 1500 µs。一个小辅助函数让位置到脉冲的映射变得清晰明了:
def set_position(angle):
# angle: 0..180 degrees mapped to 1.0..2.0 ms
pulse_us = 1000 + (angle * 1000) // 180
servo.duty_ns(pulse_us * 1000)
set_position(0) # full one way
set_position(90) # centre
set_position(180) # full the other way
在整个范围内进行一次缓慢扫描:
import time
for angle in range(0, 181, 5):
set_position(angle)
time.sleep_ms(20)
for angle in range(180, -1, -5):
set_position(angle)
time.sleep_ms(20)
1.0 -- 2.0 ms 范围是标准值,但许多舵机为获得完整行程会接受更宽的范围(通常为 500 µs 到 2500 µs)。舵机的数据手册会列出确切的脉冲宽度极限;超出该范围的数值可能会让电机猛撞到其机械限位上。
对于范围非标准的舵机,将这些极限值提取为常量,并将映射参数化:
PULSE_MIN_US = 500 # full one way (from the data sheet)
PULSE_MAX_US = 2500 # full the other way
def set_position(angle):
span_us = PULSE_MAX_US - PULSE_MIN_US
pulse_us = PULSE_MIN_US + (angle * span_us) // 180
servo.duty_ns(pulse_us * 1000)