舵机与总线舵机
概述
舵机(Servo)是集电机、减速器、控制电路和位置传感器于一体的闭环执行器。从最简单的PWM舵机到高性能总线舵机,覆盖了从入门到专业的各种机器人应用。
PWM舵机
工作原理
PWM舵机通过脉冲宽度调制信号控制转角:
- 信号频率:50Hz(周期20ms)
- 脉冲宽度:0.5ms-2.5ms 对应转角范围
- 典型映射:1ms→0°,1.5ms→90°,2ms→180°
1ms 1.5ms 2ms
┌─┐ ┌──┐ ┌───┐
│ │ │ │ │ │
────┘ └───────┘ └───────┘ └────
0° 90° 180°
←──────── 20ms 周期 ──────────→
内部结构
PWM信号 → 控制IC → H桥驱动 → 直流电机 → 减速齿轮组 → 输出轴
↑ ↓
比较/PID ←── 电位器(角度反馈)←─────┘
常见型号
SG90 微型舵机
| 参数 | 值 |
|---|---|
| 扭矩 | 1.8kg·cm (4.8V) |
| 速度 | 0.1s/60° |
| 重量 | 9g |
| 角度范围 | 180° |
| 齿轮 | 塑料 |
| 价格 | ~5元 |
| 适用 | 入门实验、轻载场景 |
MG996R 标准舵机
| 参数 | 值 |
|---|---|
| 扭矩 | 11kg·cm (6V) |
| 速度 | 0.14s/60° |
| 重量 | 55g |
| 角度范围 | 180° |
| 齿轮 | 金属 |
| 价格 | ~20元 |
| 适用 | 机械臂、云台 |
MG90S 微型金属齿轮
| 参数 | 值 |
|---|---|
| 扭矩 | 2.2kg·cm (4.8V) |
| 重量 | 13.4g |
| 齿轮 | 金属 |
| 适用 | 需要耐久的小型场景 |
PWM舵机控制代码
// Arduino PWM舵机控制
#include <Servo.h>
Servo myServo;
void setup() {
myServo.attach(9); // PWM引脚
}
void loop() {
// 方法1:直接设置角度
myServo.write(90); // 转到90°
delay(1000);
// 方法2:设置脉冲宽度(微秒)
myServo.writeMicroseconds(1500); // 中位
delay(1000);
// 平滑运动
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle);
delay(15);
}
}
PWM舵机的局限
- 无反馈:只能发送目标位置,不知道是否到达
- 单线控制:每个舵机占用一个PWM引脚
- 精度有限:电位器反馈精度低
- 无扭矩/速度控制:只能控制位置
- 不可级联:大量舵机需要PCA9685等PWM扩展板
串行总线舵机
总线舵机通过串行通信协议控制,解决了PWM舵机的诸多局限。
核心优势
| 特性 | PWM舵机 | 总线舵机 |
|---|---|---|
| 连接方式 | 每个独占PWM引脚 | 菊花链串联 |
| 反馈 | 无 | 位置+速度+扭矩+温度 |
| 控制模式 | 仅位置 | 位置/速度/扭矩 |
| ID寻址 | 无 | 每个舵机有唯一ID |
| 参数配置 | 无 | 可配置PID、限位、波特率等 |
| 布线 | 复杂(多线) | 简洁(一条总线) |
Waveshare ST3215 / ST3235
幻尔科技(Feetech)STS系列,Waveshare代理销售,性价比高:
| 参数 | ST3215 | ST3235 |
|---|---|---|
| 扭矩 | 15kg·cm | 20kg·cm |
| 速度 | 0.054s/60° | 0.068s/60° |
| 分辨率 | 4096 (0.088°) | 4096 |
| 通信 | 半双工UART (TTL) | 半双工UART |
| 波特率 | 1Mbps (最高) | 1Mbps |
| 反馈 | 位置+速度+负载+温度+电压 | 同左 |
| 控制模式 | 位置/速度/PWM开环 | 同左 |
| 价格 | ~60元 | ~80元 |
菊花链连接
MCU(TX/RX) → 舵机1(ID=1) → 舵机2(ID=2) → 舵机3(ID=3) → ...
│ │ │
GND GND GND
VCC VCC VCC
半双工注意
STS系列使用单线半双工通信,TX和RX共用一根数据线。需要方向控制(三态缓冲器或GPIO控制收发切换)。
控制示例
# Waveshare ST3215 Python控制示例
# 使用 SCServo SDK
from scservo_sdk import *
# 初始化端口
portHandler = PortHandler('/dev/ttyUSB0')
packetHandler = SMS_STS(portHandler)
portHandler.openPort()
portHandler.setBaudRate(1000000) # 1Mbps
SERVO_ID = 1
# 写入目标位置(0-4095对应0-360°)
# 参数: ID, 目标位置, 速度, 加速度
packetHandler.WritePosEx(SERVO_ID, 2048, 1000, 50) # 中位, 速度1000, 加速度50
# 读取当前状态
position = packetHandler.ReadPos(SERVO_ID)
speed = packetHandler.ReadSpeed(SERVO_ID)
load = packetHandler.ReadLoad(SERVO_ID)
temperature = packetHandler.ReadTemperature(SERVO_ID)
print(f"位置: {position}, 速度: {speed}, 负载: {load}, 温度: {temperature}°C")
# 同步写入多个舵机(同时运动)
groupSyncWrite = GroupSyncWrite(portHandler, packetHandler,
SMS_STS_GOAL_POSITION, 4)
groupSyncWrite.addParam(1, [0x00, 0x08, 0xE8, 0x03]) # ID1: pos=2048, speed=1000
groupSyncWrite.addParam(2, [0x00, 0x04, 0xE8, 0x03]) # ID2: pos=1024, speed=1000
groupSyncWrite.txPacket()
Dynamixel 系列
Robotis公司的Dynamixel是最知名的总线舵机品牌,广泛用于科研和竞赛。
常用型号
| 型号 | 扭矩 | 通信 | 分辨率 | 特点 |
|---|---|---|---|---|
| AX-12A | 15.3kg·cm | TTL半双工 | 1024 | 入门经典,已停产 |
| XL330-M288 | 0.43N·m | TTL半双工 | 4096 | 超小型,适合灵巧手 |
| XL430-W250 | 1.4N·m | TTL半双工 | 4096 | 性价比入门 |
| XM430-W350 | 4.1N·m | RS-485 | 4096 | 科研主力 |
| XM540-W270 | 10.6N·m | RS-485 | 4096 | 高扭矩 |
Dynamixel Protocol 2.0
通信协议结构:
[Header] [Reserved] [ID] [Length] [Instruction] [Parameters...] [CRC]
FF FF FD 00 0x01 0x07 0x03 ... CRC
主要指令:
| 指令 | 值 | 功能 |
|---|---|---|
| Ping | 0x01 | 检测舵机是否在线 |
| Read | 0x02 | 读取控制表数据 |
| Write | 0x03 | 写入控制表数据 |
| Sync Read | 0x82 | 同步读取多个舵机 |
| Sync Write | 0x83 | 同步写入多个舵机 |
| Bulk Read | 0x92 | 批量读取(不同地址) |
Dynamixel Python SDK
from dynamixel_sdk import *
ADDR_TORQUE_ENABLE = 64
ADDR_GOAL_POSITION = 116
ADDR_PRESENT_POSITION = 132
BAUDRATE = 57600
PROTOCOL_VERSION = 2.0
portHandler = PortHandler('/dev/ttyUSB0')
packetHandler = PacketHandler(PROTOCOL_VERSION)
portHandler.openPort()
portHandler.setBaudRate(BAUDRATE)
DXL_ID = 1
# 使能扭矩
packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_TORQUE_ENABLE, 1)
# 写入目标位置(0-4095)
packetHandler.write4ByteTxRx(portHandler, DXL_ID, ADDR_GOAL_POSITION, 2048)
# 读取当前位置
position, result, error = packetHandler.read4ByteTxRx(
portHandler, DXL_ID, ADDR_PRESENT_POSITION)
print(f"当前位置: {position}")
# 关闭扭矩
packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_TORQUE_ENABLE, 0)
portHandler.closePort()
RS-485与TTL对比
| 特性 | TTL半双工 | RS-485 |
|---|---|---|
| 电平 | 0/3.3V 或 0/5V | 差分信号 |
| 传输距离 | <1m | <1200m |
| 抗干扰 | 弱 | 强 |
| 节点数 | 较少 | 最多32/256个 |
| 典型应用 | 小型机器人 | 工业/大型机器人 |
详见 串口与I2C_SPI
总线舵机对比总结
| 特性 | Feetech STS | Dynamixel X |
|---|---|---|
| 价格 | 低(60-100元) | 高(300-2000元) |
| 生态 | SDK较简单 | SDK完善、文档丰富 |
| 社区 | 国内为主 | 全球科研社区 |
| 通信协议 | 私有协议 | Protocol 2.0(开放) |
| 软件工具 | FD调试工具 | Dynamixel Wizard 2.0 |
| 适用 | 性价比项目、教育 | 科研、竞赛、商用 |
舵机供电注意事项
供电隔离
- 舵机(尤其多个)应使用独立电源,不要与MCU共用
- 大电流瞬间可能导致MCU复位
- 电源线要足够粗,减少压降
- 总线舵机启动瞬间电流可达额定的3-5倍
典型供电方案
电池/电源 ─┬─→ 降压模块(5V/3.3V) ──→ MCU
│
└─→ 舵机电源(6-12V) ──→ 舵机总线
│
共地 ←─┘
小结
- PWM舵机简单便宜,适合入门和轻载应用
- 总线舵机支持菊花链、状态反馈、多模式控制,适合复杂机器人
- Feetech STS系列性价比高,Dynamixel生态完善
- 大量舵机项目务必注意供电设计
- 选型时需综合考虑扭矩、精度、通信方式和预算