总线舵机 vs 数字舵机,核心结构与信号传输原理深度拆解
1.串口舵机的介绍

舵机是一种位置(角度)伺服执行器,核心功能是根据输入信号精准控制输出轴的旋转角度,广泛应用于机器人关节、航模舵面、智能家居机械臂等场景。从技术迭代来看,舵机经历了 “PWM 模拟舵机 → 数字舵机 → 总线舵机” 的升级路径,每一代都围绕 “控制精度、通信效率、功能扩展性” 进行优化。
无论哪类舵机,核心结构均包含 “信号接收单元、控制单元、驱动单元、执行单元、反馈单元” 五大模块,差异主要体现在 “信号形式” 和 “控制单元的实现方式” :

- 信号接收单元:接收外部控制指令(PWM 或串口信号);
- 控制单元:解析指令,对比当前位置与目标位置的偏差;
- 驱动单元:根据偏差输出电机驱动信号(正转 / 反转 / 停转);
- 执行单元:由直流电机 + 减速齿轮组构成,将电机高速转动转化为输出轴低速大扭矩转动;
- 反馈单元:通过电位器或编码器检测输出轴实际位置,回传给控制单元形成 “闭环控制”。
PWM 模拟舵机是最基础的舵机类型,核心依赖模拟电路实现闭环控制,模拟舵机的控制单元由运算放大器等模拟电路构成,无数字芯片,结构简单:

但是 PWM 模拟舵机也具有控制精度差、响应速度慢、无状态反馈和抗干扰弱的缺点。
PWM 数字舵机是在模拟舵机基础上加入 MCU(微控制单元) ,用 “数字电路” 替代部分模拟电路,解决了模拟舵机的精度、抗干扰与响应问题。

PWM 数字舵机的控制信号仍为 PWM 信号(兼容模拟舵机的控制标准),但内部控制逻辑完全数字化:
- 模拟舵机的 “运算放大器” 被 “MCU + 数字比较器” 替代;
- 电位器的模拟电压信号经 ADC(模数转换器) 转为数字信号,传入 MCU 与目标角度进行精准对比。
但是,PWM 数字舵机仍依赖 PWM 单工通信,无法回传状态数据;同时多舵机控制仍繁琐,同模拟舵机一样,控制一路舵机就需要占用一个 MCU 的 IO 口。而总线舵机的核心突破是用 “总线通信” 替代 PWM 信号,实现 “双向通信 + 总线控制”,彻底重构了舵机的控制逻辑。

主控单元通过指令包的发送和接收获取舵机当前位置和需要抵达的位置。是一种闭环的控制形式。能反馈的参数有电压、电流、温度、扭力、速度、位置,以及舵机的状态是否正常。
常见总线舵机包括以下几种型号:
- RS-485 串口型舵机:基于差分信号传输,抗干扰强、传输距离远,适合工业和科研级机器人。
- TTL 串口型舵机:直接用单片机 UART 控制,布线简单、成本低,常见于教育机器人和开源项目。
- CAN 总线舵机:采用 CAN 总线协议,可靠性高、扩展性强,广泛应用于汽车电子和工业机器人。
总线舵机支持独立地址设置(如通过拨码开关或指令配置 0~255 号地址),多个舵机可共用 1 组串口总线(TX 发送线、RX 接收线、GND 地线):
- 主机发送指令时,帧中包含 “目标舵机地址”;
- 总线上的所有舵机接收指令后,先解析地址 —— 仅与自身地址匹配的舵机执行指令,其他舵机忽略;
- 舵机回传数据时,帧中包含自身地址,主机可识别数据来源。
接下来 我们以幻尔科技 LX-1501 总线舵机为例,讲解如何通过串口自定义协议帧来读写控制串口舵机,幻尔科技 LX-1501 智能总线舵机集成伺服驱动、电机、总线舵机信号于一体,通过半双工 UART 异步串行接口接收指令控制,串口波特率为 115200。用户可依据通信协议发送指令,实现舵机转动、信息读取,还能切换为步进电机模式。该舵机支持多机串联(理论最多串联 253 个),广泛应用于仿生机器人关节等需闭环控制的机器人项目。


LX-1501 的关键参数如下:
- 电源与性能:工作电压额定 7.4V(范围 6 - 8.4V),堵转扭矩 17kg.cm,转动速度 0.16 秒 / 60°(7.4V 下),控制角度范围 0 - 1000(对应实际 0°~240°),精度达 0.3°;
- 功能与保护:支持掉电保存用户设置、角度回读,可反馈温度 / 电压 / 位置等参数,具备堵转保护、过温保护;
- 配置与规格:默认 ID 为 1(可设置 0 - 253),采用金属齿轮,配套 20cm PH2.0-3P 接插件(线长可选),产品尺寸 40×20.0×40.5mm,重量 58g。
使用时需遵循以下要点:
-
电源适配:选择 6 - 8.4V 范围内的稳定电源,超压会烧毁舵机,电压过低则无法正常驱动。
-
ID 设置:出厂默认 ID 为 1,使用前需按需预设;设置 ID 时需单独连接舵机(避免串联时所有舵机被设为同一 ID),设置完成后再串联。
-
机械与散热保护:通电后请勿强行扭动舵臂、舵盘,以免损坏内部结构;持续运行后舵机会发热,需适时冷却,避免过热影响性能和寿命。
-
负载限制:持续转动时,负载应 ≤ 堵转扭矩的 1/3~1/5(堵转扭矩是舵机 “无法旋转时的最大扭矩”,负载过大会增加能耗、降低效能)。
其余详细信息可以在我们提供的资料中获取,这里不做详述。
2.幻尔科技总线舵机通信协议介绍
总线舵机通信协议是驱动与舵机交互的 “语言规范”,所有控制指令(如转动角度、读取温度)和状态反馈都需按协议格式传输。该协议基于半双工 UART 异步通信,支持 253 个舵机串联控制,波特率固定为 115200bps,核心通过 “指令帧打包 - 发送 - 响应帧解析” 实现功能控制。
所有指令和响应均遵循统一帧结构,驱动需按字段顺序处理数据,确保舵机可识别、响应可解析:
| 字段 | 字节数 | 功能说明 | 驱动开发关联要点 |
|---|---|---|---|
| 帧头 | 2 | 指令起始标识,固定为 0x55 0x55 |
解析响应时,需先检测连续两个 0x55,否则丢弃数据(避免误解析干扰信号) |
| ID | 1 | 目标舵机 ID(0~253)或广播 ID(0xFE) | 打包指令时需接收用户传入的 ID;广播 ID 指令无响应(仅读 ID 指令例外) |
| 数据长度 | 1 | 取值 =“指令 + 参数” 总字节数(含自身) | 帧总长度 = 数据长度 + 3,驱动可通过此校验帧完整性(避免断帧导致解析错误) |
| 指令 | 1 | 功能标识(如转动、读温度) | 需定义指令常量映射表(如 SERVO_MOVE_TIME_WRITE = 1),避免硬编码 |
| 参数 | N | 指令补充信息(如角度、时间) | 按指令类型拆分 / 拼接(如 16 位角度拆分为高低 8 位),部分需做有符号 / 无符号转换 |
| 校验和 | 1 | 确保数据传输正确 | 必须实现计算与校验函数,否则指令会被舵机丢弃(计算公式:~(ID+Length+Cmd+参数和) & 0xFF) |
协议按功能分为 “写指令(配置 / 控制)” 和 “读指令(获取状态)”:
- 写指令:后缀
_WRITE,带参数(如设置角度),执行后无响应(驱动发送后无需等待); - 读指令:后缀
_READ,无参数(如读温度),执行后返回响应(驱动需立即接收解析)。
具体指令如下所示:
3.串口控制幻尔科技 LX-1501 总线舵机实验
3.1 SerialServo 串口舵机驱动类代码简介
首先,我们定义了一个 SerialServo 串口舵机驱动类,具有如下方法:
该类封装了舵机控制相关的所有功能,包括生成和发送控制指令、接收舵机反馈、读取舵机状态等。

这里,我们首先将指令及其参数长度或返回数据长度定义为类常量:
# 串口舵机自定义类
class SerialServo:
"""
串口舵机控制类,用于生成和发送控制指令。
该类通过UART串口与舵机进行通信,支持构建控制指令包、计算校验和以及发送指令。
支持可调的波特率和不同舵机的控制。
Attributes:
uart (machine.UART): 用于与舵机通信的UART实例。
Class Variables:
- 指令及其参数长度或返回数据长度的定义。
- 各种舵机控制指令的定义,包括写入命令和读取命令。
- 舵机工作模式的定义。
- LED报警故障类型的定义。
Methods:
calculate_checksum(data: list[int]) -> int:
计算校验和,确保数据的完整性和正确性。
build_packet(servo_id: int, cmd: int, params: list[int]) -> bytearray:
构建舵机指令包。
send_command(servo_id: int, cmd: int, params: list[int] = []) -> None:
发送控制指令到舵机。
receive_command(expected_cmd: int, expected_data_len: int) -> list:
接收并处理舵机返回的指令数据包。
move_servo_immediate(servo_id: int, angle: float, time_ms: int) -> None:
立即控制舵机转动到指定角度。
get_servo_move_immediate(servo_id: int) -> tuple:
获取舵机的预设角度和时间。
move_servo_with_time_delay(servo_id: int, angle: float, time_ms: int) -> None:
控制舵机延迟转动到指定角度。
get_servo_move_with_time_delay(servo_id: int) -> tuple:
获取舵机的预设角度和时间(延迟转动)。
start_servo(servo_id: int) -> None:
启动舵机的转动。
stop_servo(servo_id: int) -> None:
立即停止舵机转动并停在当前角度位置。
set_servo_id(servo_id: int, new_id: int) -> None:
设置舵机的新ID值。
get_servo_id(servo_id: int) -> int:
获取舵机的ID。
set_servo_angle_offset(servo_id: int, angle: float, save_to_memory: bool = False) -> None:
根据角度值调整舵机的偏差。
get_servo_angle_offset(servo_id: int) -> float:
获取舵机的偏差角度。
set_servo_angle_range(servo_id: int, min_angle: float, max_angle: float) -> None:
设置舵机的最小和最大角度限制。
get_servo_angle_range(servo_id: int) -> tuple:
获取舵机的角度限位。
set_servo_vin_range(servo_id: int, min_vin: float, max_vin: float) -> None:
设置舵机的最小和最大输入电压限制。
get_servo_vin_range(servo_id: int) -> tuple:
获取舵机的电压限制值。
set_servo_temp_range(servo_id: int, max_temp: int) -> None:
设置舵机的最高温度限制。
get_servo_temp_range(servo_id: int) -> int:
获取舵机的内部最高温度限制值。
read_servo_temp(servo_id: int) -> int:
获取舵机的实时温度。
read_servo_voltage(servo_id: int) -> float:
获取舵机的实时输入电压。
read_serv:pos_read(servo_id: int) -> float:
获取舵机的实时角度位置。
set_servo_mode_and_speed(servo_id: int, mode: int, speed: int) -> None:
设置舵机的工作模式和电机转速。
get_servo_mode_and_speed(servo_id: int) -> tuple:
获取舵机的工作模式和转动速度。
set_servo_motor_load(servo_id: int, unload: bool) -> None:
设置舵机的电机是否卸载掉电。
get_servo_motor_load_status(servo_id: int) -> bool:
获取舵机电机是否装载或卸载。
set_servo_led(servo_id: int, led_on: bool) -> None:
设置舵机的LED灯的亮灭状态。
get_servo_led(servo_id: int) -> bool:
获取舵机LED的亮灭状态。
set_servo_led_alarm(servo_id: int, alarm_code: int) -> None:
设置舵机LED闪烁报警对应的故障值。
get_servo_led_alarm(servo_id: int) -> int:
获取舵机LED故障报警状态。
=================================================
SerialServo Class:
A class to control the serial servo, used to generate and send control commands.
This class communicates with the servo through UART serial, supporting the construction of control command packets,
checksum calculation, and command sending.
It supports adjustable baud rates and control for various servo models.
Attributes:
uart (machine.UART): UART instance for communication with the servo.
Class Variables:
- Definitions of command lengths or return data lengths.
- Definitions of various servo control commands, including write and read commands.
- Definitions of servo working modes.
- Definitions of LED alarm fault types.
Methods:
calculate_checksum(data: list[int]) -> int:
Calculate checksum to ensure data integrity and correctness.
build_packet(servo_id: int, cmd: int, params: list[int]) -> bytearray:
Construct servo control command packet.
send_command(servo_id: int, cmd: int, params: list[int] = []) -> None:
Send control command to the servo.
receive_command(expected_cmd: int, expected_data_len: int) -> list:
Receive and process the response from the servo.
move_servo_immediate(servo_id: int, angle: float, time_ms: int) -> None:
Control the servo to move immediately to a specified angle.
get_servo_move_immediate(servo_id: int) -> tuple:
Get the servo's preset angle and time for immediate movement.
move_servo_with_time_delay(servo_id: int, angle: float, time_ms: int) -> None:
Control the servo to move to a specified angle with a delay.
get_servo_move_with_time_delay(servo_id: int) -> tuple:
Get the servo's preset angle and time for delayed movement.
start_servo(servo_id: int) -> None:
Start the servo's movement.
stop_servo(servo_id: int) -> None:
Immediately stop the servo and hold at the current position.
set_servo_id(servo_id: int, new_id: int) -> None:
Set a new ID for the servo.
get_servo_id(servo_id: int) -> int:
Get the current ID of the servo.
set_servo_angle_offset(servo_id: int, angle: float, save_to_memory: bool = False) -> None:
Adjust the servo's angle offset based on a specified angle.
get_servo_angle_offset(servo_id: int) -> float:
Get the current angle offset of the servo.
set_servo_angle_range(servo_id: int, min_angle: float, max_angle: float) -> None:
Set the minimum and maximum angle limits for the servo.
get_servo_angle_range(servo_id: int) -> tuple:
Get the current angle limits of the servo.
set_servo_vin_range(servo_id: int, min_vin: float, max_vin: float) -> None:
Set the minimum and maximum input voltage range for the servo.
get_servo_vin_range(servo_id: int) -> tuple:
Get the current input voltage range of the servo.
set_servo_temp_range(servo_id: int, max_temp: int) -> None:
Set the maximum temperature limit for the servo.
get_servo_temp_range(servo_id: int) -> int:
Get the current maximum temperature limit for the servo.
read_servo_temp(servo_id: int) -> int:
Read the current temperature of the servo.
read_servo_voltage(servo_id: int) -> float:
Read the current input voltage of the servo.
read_servo_pos(servo_id: int) -> float:
Read the current angle position of the servo.
set_servo_mode_and_speed(servo_id: int, mode: int, speed: int) -> None:
Set the working mode and motor speed for the servo.
get_servo_mode_and_speed(servo_id: int) -> tuple:
Get the current working mode and motor speed of the servo.
set_servo_motor_load(servo_id: int, unload: bool) -> None:
Set whether the servo motor is loaded or unloaded.
get_servo_motor_load_status(servo_id: int) -> bool:
Get the current load status of the servo motor.
set_servo_led(servo_id: int, led_on: bool) -> None:
Set the LED light status (on/off) of the servo.
get_servo_led(servo_id: int) -> bool:
Get the current LED light status of the servo.
set_servo_led_alarm(servo_id: int, alarm_code: int) -> None:
Set the LED alarm fault code for the servo.
get_servo_led_alarm(servo_id: int) -> int:
Get the current LED alarm fault code of the servo.
"""
# 类变量:指令及其参数长度或返回数据长度
# 写入指令及其对应的参数长度
# 读取指令及其对应的参数长度和返回数据长度
# 舵机立即转动写入命令
SERVO_MOVE_TIME_WRITE = (1, 7)
# 舵机立即转动参数读取命令
SERVO_MOVE_TIME_READ = (2, 3, 7)
# 舵机延迟转动写入命令
SERVO_MOVE_TIME_WAIT_WRITE = (7, 7)
# 舵机延迟转动读取命令
SERVO_MOVE_TIME_WAIT_READ = (8, 3, 7)
# 舵机开启转动指令(配合SERVO_MOVE_TIME_WAIT_WRITE指令使用)
SERVO_MOVE_START = (11, 3)
# 舵机停止转动指令
SERVO_MOVE_STOP = (12, 3)
# 舵机ID写入命令(支持掉电保存)
SERVO_ID_WRITE = (13, 4)
# 舵机ID读取命令
SERVO_ID_READ = (14, 3, 4)
# 舵机偏差调节指令(不支持掉电保存)
SERVO_ANGLE_OFFSET_ADJUST = (17, 4)
# 舵机偏差调节指令(支持掉电保存)
SERVO_ANGLE_OFFSET_WRITE = (18, 3)
# 舵机偏差调节读取指令
SERVO_ANGLE_OFFSET_READ = (19, 3, 4)
# 舵机角度限位写入命令(支持掉电保存)
SERVO_ANGLE_LIMIT_WRITE = (20, 7)
# 舵机角度限位读取命令
SERVO_ANGLE_LIMIT_READ = (21, 3, 7)
# 舵机电压限制写入命令(支持掉电保存)
SERVO_VIN_LIMIT_WRITE = (22, 7)
# 舵机电压限制读取命令
SERVO_VIN_LIMIT_READ = (23, 3, 7)
# 舵机温度限制写入命令(支持掉电保存)
SERVO_TEMP_MAX_LIMIT_WRITE = (24, 4)
# 舵机温度限制读取命令
SERVO_TEMP_MAX_LIMIT_READ = (25, 3, 4)
# 舵机实时温度读取指令
SERVO_TEMP_READ = (26, 3, 4)
# 舵机实时电压读取指令
SERVO_VIN_READ = (27, 3, 5)
# 舵机当前角度读取指令
SERVO_POS_READ = (28, 3, 5)
# 舵机模式切换指令(不支持掉电保存)
SERVO_OR_MOTOR_MODE_WRITE = (29, 7)
# 舵机模式及参数读取指令
SERVO_OR_MOTOR_MODE_READ = (30, 3, 7)
# 舵机上电/掉电控制指令(不支持掉电保存)
SERVO_LOAD_OR_UNLOAD_WRITE = (31, 4)
# 舵机上电/掉电读取指令
SERVO_LOAD_OR_UNLOAD_READ = (32, 3, 4)
# 舵机LED控制指令(支持掉电保存)
SERVO_LED_CTRL_WRITE = (33, 4)
# 舵机LED读取指令
SERVO_LED_CTRL_READ = (34, 3, 4)
# 舵机LED报警闪烁指令
SERVO_LED_ERROR_WRITE = (35, 4)
# 舵机LED报警闪烁值读取指令
SERVO_LED_ERROR_READ = (36, 3, 4)
# 类变量:舵机工作模式
# 0 代表位置控制模式
MODE_POSITION = 0
# 1 代表电机控制模式
MODE_MOTOR = 1
# 类变量:LED报警故障类型
ERROR_NO_ALARM = 0 # 无报警
ERROR_OVER_TEMP = 1 # 过温报警
ERROR_OVER_VOLT = 2 # 过压报警
ERROR_OVER_TEMP_AND_VOLT = 3 # 过温和过压报警
ERROR_STALL = 4 # 堵转报警
ERROR_OVER_TEMP_AND_STALL = 5 # 过温和堵转报警
ERROR_OVER_VOLT_AND_STALL = 6 # 过压和堵转报警
ERROR_ALL = 7 # 过温、过压和堵转报警
# 读取命令集合:根据指令的元组长度来确定哪些是读取命令(命令编号,参数长度,返回数据长度)
READ_COMMANDS = {
2, # SERVO_MOVE_TIME_READ
8, # SERVO_MOVE_TIME_WAIT_READ
14, # SERVO_ID_READ
19, # SERVO_ANGLE_OFFSET_READ
21, # SERVO_ANGLE_LIMIT_READ
23, # SERVO_VIN_LIMIT_READ
25, # SERVO_TEMP_MAX_LIMIT_READ
26, # SERVO_TEMP_READ
27, # SERVO_VIN_READ
28, # SERVO_POS_READ
30, # SERVO_OR_MOTOR_MODE_READ
32, # SERVO_LOAD_OR_UNLOAD_READ
34, # SERVO_LED_CTRL_READ
36 # SERVO_LED_ERROR_READ
}
例如:
SERVO_MOVE_TIME_WRITE和SERVO_MOVE_TIME_READ是与舵机位置控制相关的指令及其参数格式。SERVO_ID_WRITE和SERVO_ID_READ是与舵机 ID 相关的读写指令。
这些常量帮助类在进行通信时,能确保发送正确的指令和正确解析返回的数据。
READ_COMMANDS 集合定义了所有读取命令的编号,这些命令对应舵机的数据读取请求,例如,读取舵机的实时电压、角度、温度等信息。 这个集合便于在 receive_command() 方法中判断接收到的数据是否为期望的读取命令。
在初始化方法中,我们仅需要绑定外部初始化好的 UART 实例即可:
def __init__(self, uart: UART) -> None:
"""
初始化串口舵机控制类。
Args:
uart (UART): 使用的UART实例。
===================================================
Initialize the Serial Servo Control Class.
Args:
uart (UART): The UART instance used for communication with the servo.
"""
self.uart = uart
串口舵机类的核心方法为:
-
构建数据包方法
build_packet:
该方法用于构建舵机控制的指令包,指令包由以下部分组成:
- 帧头:固定为 0x55, 0x55
- 舵机 ID:唯一标识每个舵机
- 数据长度:包括指令和参数
- 指令编号:具体的控制指令
- 参数:控制指令的参数
- 校验和:用于校验数据包的完整性
-
发送指令方法
send_command:该方法构建指令包并通过UART发送给舵机,它调用了build_packet()来构造数据包, 并通过self.uart.write()发送数据:
-
接收指令方法
receive_command :receive_command()方法用于接收来自舵机的反馈数据,此方法的工作过程如下:- 命令验证:确认接收到的是读取命令,而不是其他类型的命令。
- 数据检查:检查数据的帧头是否正确,命令编号是否匹配,数据长度是否符合预期。
- 校验和验证:验证接收到的数据包的校验和是否正确,确保数据未被篡改。
- 数据解析:根据返回的数据长度,解析并返回舵机的状态或数据(例如电压、角度等)。
- 如果数据包无效(如校验和错误、数据长度不符等),该方法将返回空列表。

SerialServo 类的所有上层功能方法(如舵机转动、参数配置、状态读取等)均基于 build_packet(打包)、send_command(发送)、receive_command(接收解析)三个核心通信模块实现。这三个核心方法构成了驱动的 “通信流水线”,上层方法本质是对该流水线的 “业务化封装”—— 将用户输入的 “物理量”(如角度、电压)转换为协议要求的 “原始参数”,再通过核心模块完成与舵机的交互。
根据功能场景,上层方法可分为 “仅发送指令的写操作” 和 “先发送再接收的读写操作”,二者对核心模块的调用逻辑不同:
- 写操作类方法:仅调用
send_command(含build_packet),无需舵机返回数据的操作(如控制转动、设置 ID、启停舵机等),核心是 “将参数打包发送”。 - 读写操作类方法:调用
send_command+receive_command,需获取舵机状态的操作(如读温度、位置、角度偏差等),核心是 “先发读指令,再收响应解析”。
例如 move_servo_immediate 方法,为写操作类方法,代码如下:
def move_servo_immediate(self, servo_id: int, angle: float, time_ms: int) -> None:
"""
立即控制舵机转动到指定角度。
该方法使用 SERVO_MOVE_TIME_WRITE 指令,在给定时间内将舵机转动到指定的角度。
Args:
servo_id (int): 舵机ID,范围0~253。
angle (float): 目标角度(0~240度范围内)。每个单位表示 0.24 度。
time_ms (int): 转动时间(0~30000 毫秒),表示舵机转动到指定角度的时间。
Raises:
ValueError: 如果角度不在 0~240度范围内、舵机ID不在0~253或时间不在范围内,则抛出异常。
===================================================
Immediately control the servo to rotate to the specified angle.
Args:
servo_id (int): Servo ID, range 0~253.
angle (float): Target angle (0~240 degrees). Each unit represents 0.24 degrees.
time_ms (int): Time to rotate (0~30000 milliseconds), indicating the time for the servo to rotate to the specified angle.
Raises:
ValueError: If the angle is not in the range 0~240, the servo ID is not in the range 0~253,
or the time is not in the range, an exception will be raised.
"""
# 判断角度是否在 0~240度范围内
if angle < 0 or angle > 240:
raise ValueError("Angle must be in range 0~240.")
# 判断时间是否在 0~30000 毫秒范围内
if time_ms < 0 or time_ms > 30000:
raise ValueError("Time must be in range 0~30000.")
# 将角度转换为舵机控制指令所需的低八位和高八位
# 转换为整数并限制为低8位
angle_low = int(angle / 0.24) & 0xFF
# 获取高8位
angle_high = (int(angle / 0.24) >> 8) & 0xFF
# 将时间转换为低八位和高八位
# 转换为低8位
time_low = time_ms & 0xFF
# 获取高8位
time_high = (time_ms >> 8) & 0xFF
# 发送 SERVO_MOVE_TIME_WRITE 指令
self.send_command(servo_id, SerialServo.SERVO_MOVE_TIME_WRITE[0], [angle_low, angle_high, time_low, time_high])
它无需舵机返回数据的操作(如控制转动、设置 ID、启停舵机等),核心是 “将参数打包发送”,用户传入舵机 ID、目标角度和转动时间,move_servo_immediate 方法首先进行合法性校验,接着将目标角度和转动时间转换为舵机控制指令所需的低八位和高八位,最后调用 send_command 方法(内部调用 build_packet)进行数据发送。
而对于读写操作类方法而言,其流程为:
- 发送读指令(
send_command) - 延迟等待
- 接收响应(
receive_command) - 解析参数
- 物理量转换
- 返回结果
以 read_servo_position 方法为例,为读写操作类方法,代码如下:
def read_servo_position(self, servo_id: int) -> float:
"""
获取舵机的实时角度位置。
该方法通过舵机ID发送 `SERVO_POS_READ` 指令来读取舵机的当前角度位置。
返回的角度位置值需要根据范围 0~1000 映射到角度 0~240°。
Args:
servo_id (int): 舵机的ID。
Returns:
float: 返回舵机当前的角度位置值,单位为度,范围 0~240°。
如果读取失败,则返回 None。
Raises:
ValueError: 如果角度位置不在 0~240 度范围内,则抛出异常。
=======================================================
Get the real-time position of the servo.
This method sends the `SERVO_POS_READ` command using the servo's ID to read the current angle position of the servo.
The returned position value needs to be mapped from the range 0~1000 to the angle range 0~240°.
Args:
servo_id (int): The servo's ID.
Returns:
float: The current angle position of the servo, in degrees, with a range of 0~240°.
If the read operation fails, it returns None.
Raises:
ValueError: If the position is not within the range of 0~240°, an exception will be raised.
"""
# 发送SERVO_POS_READ命令
self.send_command(servo_id, SerialServo.SERVO_POS_READ[0], [])
# 延迟5ms再接收数据
time.sleep_ms(5)
# 接收并解析返回的数据
params = self.receive_command(SerialServo.SERVO_POS_READ[0], SerialServo.SERVO_POS_READ[2])
# 如果没有接收到数据,则返回None
if len(params) == 0:
return None
# 将角度位置的低高字节合并为一个16位整数
position_value = params[0] + (params[1] << 8)
# 将值转换为 signed short int 型数据(可能为负值)
# 判断是否为负值
if position_value >= 0x8000:
# 如果是负值,进行补码转换
position_value -= 0x10000
# 将位置值转换为角度值,映射到 0~240° 范围
position_angle = (position_value / 1000) * 240
# 判断角度值是否在合理范围内
if not (0 <= position_angle <= 240):
raise ValueError("Position is out of range.")
return position_angle
3.2 实验准备和实验现象
这里,可以在我们的博客中进行查看:

地址为:https://www.cnblogs.com/FreakEmbedded/p/18742422。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)