云犀Python SDK
Gloria-M-SDK 是 Gloria-M 系列机械夹爪的 Python 开发包,通过串口转 CAN 适配器与电机通信,封装了 MIT/PV 控制、参数读写和状态解析等接口。
本文档基于 Synria-Robotics/Gloria-M-SDK main 版本。
1. 介绍
1.1 核心能力
- 通过串口转 CAN 适配器控制 Gloria-M 夹爪电机
- 提供
GloriaGripper门面类作为推荐入口,封装 MotorAPI / MotionAPI / ParamAPI - 支持 MIT 模式和 PV 模式两种常用控制方式
- 支持使能、失能、设零点、模式切换等基础控制命令
- 支持读取位置、速度、力矩等反馈状态
- 支持参数读写和保存,例如
PMAX、VMAX、TMAX、CTRL_MODE - 支持连杆夹爪力控示例,并可结合空载力矩基线做补偿
- 提供完整异常体系(
GloriaSdkError及子类)
1.2 SDK 目录结构
官方仓库 main 的核心结构如下:
Gloria-M-SDK/
├── src/gloria_m_sdk/
│ ├── __init__.py # 包入口,导出公开 API
│ ├── client.py # GloriaGripper 门面层(推荐入口)
│ ├── exceptions.py # 异常体系(GloriaSdkError 及子类)
│ ├── api/ # API 层:按领域拆分的子 API
│ │ ├── __init__.py
│ │ ├── base.py # BaseAPI(共享控制器访问)
│ │ ├── motor_api.py # MotorAPI:使能/失能/模式/归零/读取
│ │ ├── motion_api.py # MotionAPI:send_mit / send_pos_vel
│ │ └── param_api.py # ParamAPI:读写寄存器、保存、应用限制
│ ├── actuator.py
│ ├── controller.py
│ ├── protocol_mit.py
│ ├── serial_can_adapter.py
│ ├── param_config.py
│ ├── registers.py
│ ├── types.py
│ ├── constants.py
│ └── gripper_baseline.py
├── demos/
│ ├── 01_gripper_quicktest.py # PV 模式往复运动测试
│ ├── 02_pv_control.py # PV 模式柔顺闭合
│ ├── 03_mit_linkage_force_control.py # MIT 连杆夹爪力控
│ ├── mit_close_baseline.py # MIT 空载闭合基线采集
│ └── baseline/ # 基线数据 CSV 输出目录
├── requirements.txt
└── pyproject.toml
2. 安装与准备
2.1 环境要求
- Python 3.11 及以上版本
- 串口转 CAN 适配器
- 已上电的 Gloria-M 夹爪或对应电机
2.2 安装步骤
克隆指定版本源码:
git clone https://github.com/Synria-Robotics/Gloria-M-SDK.git -b main
cd Gloria-M-SDK
安装依赖:
pip install -r requirements.txt
pip install -e .
2.3 串口连接检查
- Windows:在设备管理器中确认串口号,例如
COM5 - Linux:常见端口为
/dev/ttyUSB0或/dev/ttyACM0 - 默认波特率为
921600
Linux 如遇权限问题,可执行:
sudo usermod -a -G dialout $USER
重新登录后再访问串口。
3. 公共 API 概览
gloria_m_sdk 在包入口导出了以下常用对象:
3.1 推荐入口(门面层)
| 名称 | 说明 |
|---|---|
GloriaGripper | 门面类,封装了 MotorAPI / MotionAPI / ParamAPI,推荐作为首选入口 |
3.2 底层对象(低层访问)
| 名称 | 说明 |
|---|---|
Actuator | 执行器配置对象,包含命令 ID、反馈 ID、限幅和安全位置范围 |
ActuatorState | 保存当前位置、速度、力矩和最近更新时间 |
SerialCanAdapter | 串口转 CAN 通信适配器 |
CanController | 底层控制器,负责命令发送、回包解析和参数读写 |
Variable | 电机参数寄存器枚举,例如 CTRL_MODE、PMAX、VMAX |
TorqueBaseline | 空载力矩基线读取与插值对象,用于连杆夹爪力控 |
3.3 公共类型
| 名称 | 说明 |
|---|---|
ControlMode | 控制模式枚举,包含 MIT、POS_VEL 等 |
Limits | MIT 模式打包/解包的缩放范围,常见值为 pmax=3.14、vmax=10.0、tmax=12.0 |
PositionRange | 安全位置范围,超出后会被自动夹紧 |
MIT_SAFE_Q_MIN / MIT_SAFE_Q_MAX | 包内提供的默认安全范围常量 |
apply_limits_and_save | 将限幅参数写入电机并保存(旧接口,建议改用 gripper.params.apply_limits()) |
3.4 异常体系
| 名称 | 说明 |
|---|---|
GloriaSdkError | 基类,可一网打尽所有 SDK 异常 |
GloriaConnectionError | 串口打不开 |
GloriaCommunicationError | 超时或帧格式错误 |
GloriaConfigError | 参数越界或配置无效 |
GloriaModeError | 模式切换未被电机确认 |
4. GloriaGripper 门面 API
GloriaGripper 是门面类,封装了底层五层架构,推荐所有新代码使用此入口。
4.1 构造参数
GloriaGripper(
port, # "COM5" 或 "/dev/ttyUSB0"
*,
baudrate=921_600,
command_id=0x01, # 电机命令 CAN ID
feedback_id=0x101, # 电机反馈 CAN ID
limits=None, # Limits(pmax, vmax, tmax),默认 (3.14, 10, 12)
safe_position=None, # PositionRange(min, max) — 位置限幅
baseline_csv=None, # 空载扭矩基线 CSV 路径
timeout=0.5, # 串口读超时 [s]
)
4.2 属性
| 属性 | 类型 | 说明 |
|---|---|---|
state | ActuatorState | 最新反馈快照(位置、速度、扭矩) |
current_mode | ControlMode | None | 电机最后确认的控制模式;set_mode() 前为 None |
is_connected | bool | True 表示串口已打开 |
4.3 .motor — MotorAPI
| 方法 | 说明 |
|---|---|
enable() | 发送使能命令 |
disable() | 发送失能命令 |
set_zero() | 将当前位置设为零点 |
set_mode(mode) | 切换控制模式;失败则抛出 GloriaModeError |
refresh() | 广播请求状态并更新 gripper.state |
poll() | 解析待处理 RX 包,更新执行器状态 |
4.4 .motion — MotionAPI
| 方法 | 说明 |
|---|---|
send_mit(*, kp, kd, q, dq, tau) | 发送 MIT 扭矩控制帧 |
send_pos_vel(*, position, velocity) | 发送 PV 位置+速度帧 |
4.5 .params — ParamAPI
| 方法 | 说明 |
|---|---|
read(rid, *, timeout_s) | 读取寄存器;超时返回 None |
write_f32(rid, value) | 写入 float32 寄存器 |
write_u32(rid, value) | 写入 uint32 寄存器 |
save() | 将参数持久化到 Flash |
apply_limits(limits) | 写入 PMAX/VMAX/TMAX 并保存 |
4.6 快速开始示例
from gloria_m_sdk import GloriaGripper, ControlMode
with GloriaGripper("COM5") as g:
g.motor.set_mode(ControlMode.POS_VEL)
g.motor.enable()
g.motor.refresh()
print(f"位置 = {g.state.position:.3f} rad")
# 移动到开仓位置
g.motion.send_pos_vel(position=2.5, velocity=1.0)
5. 示例脚本(Demos)
5.1 01_gripper_quicktest.py
PV 模式往返快测。夹爪在 open_q 与 close_q 之间持续往返,反馈位置稳定后自动切换方向,用于验证串口通信、CAN ID 和开合方向是否正确。
运行示例:
python demos/01_gripper_quicktest.py --port COM5 --id 0x01 --close-q 0.0 --open-q 2.5 --vel 1.0
核心逻辑:
from gloria_m_sdk import (
Actuator,
CanController,
ControlMode,
Limits,
PositionRange,
SerialCanAdapter,
apply_limits_and_save,
)
safe_q = PositionRange(min=min(args.open_q, args.close_q), max=max(args.open_q, args.close_q))
limits = Limits(pmax=3.14, vmax=10.0, tmax=12.0)
act = Actuator(
name="gripper_cycle",
command_id=args.id,
feedback_id=args.fb_id,
limits=limits,
safe_position=safe_q,
)
with SerialCanAdapter(args.port, baudrate=args.baud, timeout=0.5) as adapter:
apply_limits_and_save(adapter, motor_id=args.id, limits=limits)
ctrl = CanController(adapter)
ctrl.register(act)
ok = ctrl.set_control_mode(act, ControlMode.POS_VEL)
print(f"[mode] set PV: {ok}")
ctrl.enable(act)
ctrl.refresh_state(act)
while True:
target = float(args.close_q) if cycle % 2 == 0 else float(args.open_q)
ctrl.send_pos_vel(act, position=target, velocity=args.velocity, poll=True)
5.2 02_pv_control.py
PV 模式柔顺闭合。先以较高速度张开到 open_q,再以低速缓慢闭合到 close_q 并保持,适合柔顺夹取场景。
运行示例:
python demos/02_pv_control.py --port COM5 --open-q 2.5 --close-q 0.0 --close-vel 0.3
执行阶段:张开 → 缓慢闭合 → 保持。关键代码:
with SerialCanAdapter(args.port, baudrate=args.baud, timeout=0.5) as adapter:
apply_limits_and_save(adapter, motor_id=args.id, limits=limits)
ctrl = CanController(adapter)
ctrl.register(act)
ok = ctrl.set_control_mode(act, ControlMode.POS_VEL)
print(f"[mode] set PV: {ok}")
ctrl.enable(act)
ctrl.refresh_state(act)
open_q = act.clamp_position(args.open_q)
_move_to(ctrl, act, target=open_q, velocity=args.open_vel,
loop_sleep=args.loop_sleep, print_hz=args.print_hz,
settle_threshold=args.settle_threshold, settle_time=args.settle_time,
timeout=args.timeout)
close_q = act.clamp_position(args.close_q)
_move_to(ctrl, act, target=close_q, velocity=args.close_vel,
loop_sleep=args.loop_sleep, print_hz=args.print_hz,
settle_threshold=args.settle_threshold, settle_time=args.settle_time,
timeout=args.timeout)
hold_end = time.perf_counter() + args.hold_time
while time.perf_counter() < hold_end:
ctrl.send_pos_vel(act, position=close_q, velocity=0.0, poll=True)
5.3 03_mit_linkage_force_control.py
MIT 模式连杆夹爪力控。结合力臂曲线和反馈力矩做接触判定,实现"张开 → 接近 → 接触 → 保持 → 释放"闭环控制。
运行示例:
python demos/03_mit_linkage_force_control.py --port COM5 --id 0x01 --fb-id 0x101 --open-q 2.77 --close-q 0.003 --target-force 15
如果是 4340 强力版本夹爪,需指定对应基线文件并调整力阈值:
python demos/03_mit_linkage_force_control.py --port COM5 --baseline-csv ".\demos\baseline\close_baseline_4340.csv" --target-force 30 --contact-force 60
如未指定 --baseline-csv,脚本默认使用 .\demos\baseline\close_baseline_4310.csv。
夹持力近似关系:
其中 为当前位置的等效力臂。关键初始化:
from gloria_m_sdk import (
Actuator,
CanController,
ControlMode,
Limits,
PositionRange,
SerialCanAdapter,
TorqueBaseline,
Variable,
apply_limits_and_save,
)
safe_q = PositionRange(min=min(raw_open_q, raw_close_q), max=max(raw_open_q, raw_close_q))
limits = Limits(pmax=3.14, vmax=10.0, tmax=12.0)
baseline = TorqueBaseline.from_csv(args.baseline_csv) if args.baseline_csv else None
act = Actuator(
name="linkage_gripper",
command_id=args.id,
feedback_id=args.fb_id,
limits=limits,
safe_position=safe_q,
)
with SerialCanAdapter(args.port, baudrate=args.baud, timeout=0.5) as adapter:
apply_limits_and_save(adapter, motor_id=args.id, limits=limits)
ctrl = CanController(adapter)
ctrl.register(act)
ok = ctrl.set_control_mode(act, ControlMode.MIT)
print(f"[mode] set MIT: {ok}")
ctrl.enable(act)
ctrl.refresh_state(act)
控制循环根据阶段动态调整参数,通过 send_mit() 发送:
ctrl.send_mit(
act,
kp=float(kp),
kd=float(kd),
q=float(q_target),
dq=0.0,
tau=float(tau_cmd),
poll=True,
)
注意事项:
close_q <= open_q方向约定必须成立open_tau为正,close_tau为负radius-profile为占位值,需替换为实际标定数据- 建议加载空载基线
baseline-csv以提升夹持力精度
5.4 mit_close_baseline.py
MIT 空载闭合基线采集。在 MIT 模式下以固定负扭矩让夹爪空载闭合,记录闭合过程中的位置、速度、反馈扭矩和估算夹持力,输出基线 CSV 文件供 03_mit_linkage_force_control.py 使用,用于扣除自身摩擦和机构阻力。
建议在没有夹持物的情况下运行:
python demos/mit_close_baseline.py --port COM5 --close-tau -1.25
常用参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
--port | COM12 | 串口号 |
--baud | 921600 | 串口波特率 |
--id | 0x01 | 电机命令 CAN ID |
--fb-id | 0x201 | 电机反馈 CAN ID |
--open-q | 2.77 | 夹爪最大张开位置 [rad] |
--close-q | 0.003 | 夹爪闭合位置 [rad] |
--close-tau | -1.25 | 闭合方向扭矩 [N·m],必须为负值 |
--kd | 0.8 | MIT 扭矩控制阻尼项 |
--stop-force | 0.0 | 估算夹持力达到该阈值后停止,0 表示禁用 [N] |
--radius-mm | 12.0 | 用于估算夹持力的等效力臂 [mm] |
--timeout | 5.0 | 最长采集时间 [s] |
--position-epsilon | 0.02 | 判定到达闭合位置的容差 [rad] |
--bin-width | 0.05 | 按位置生成基线曲线时的分桶宽度 [rad] |
--save-dir | demos/baseline | CSV 输出目录 |
--save-prefix | close_baseline | CSV 文件名前缀 |
--no-save | false | 只运行测试,不保存 CSV |
运行完成后默认生成两个 CSV 文件:
demos/baseline/{save_prefix}_{timestamp}_raw.csv
demos/baseline/{save_prefix}_{timestamp}_binned.csv
原始采样 CSV 每一行对应控制循环中的一次采样:
| 字段 | 说明 |
|---|---|
elapsed_s | 从本次测试开始到当前采样点的时间 [s] |
position_rad | 当前电机位置反馈 [rad] |
velocity_rad_s | 当前电机速度反馈 [rad/s] |
tau_cmd_nm | 当前发送的 MIT 扭矩命令 [N·m] |
tau_fb_nm | 电机反馈扭矩 [N·m] |
force_est_n | 根据反馈扭矩估算的夹持力 [N],计算方式为 max(0, -tau_fb_nm) / (radius_mm / 1000) |
分桶基线 CSV 会把位置相近的原始采样点归为一组,并对每组求平均,适合后续作为基线曲线使用:
| 字段 | 说明 |
|---|---|
position_mean_rad | 当前位置分桶内的平均位置 [rad] |
velocity_mean_rad_s | 当前位置分桶内的平均速度 [rad/s] |
tau_fb_mean_nm | 当前位置分桶内的平均反馈扭矩 [N·m] |
force_est_mean_n | 当前位置分桶内的平均估算夹持力 [N] |
sample_count | 当前位置分桶内包含的原始采样点数量 |
5.5 获取夹爪运行参数
5.5.1 实时状态
位置、速度、力矩在每次控制回包后自动写入 act.state:
ctrl.refresh_state(act)
print(f"position = {act.state.position:+.3f} rad")
print(f"velocity = {act.state.velocity:+.3f} rad/s")
print(f"torque = {act.state.torque:+.3f} Nm")
print(f"updated = {act.state.updated_at:.3f}")
发送命令时带 poll=True 即可自动更新,也可手动调用 ctrl.refresh_state(act)。
使用 GloriaGripper 时,通过 gripper.state 访问:
gripper.motor.refresh()
print(f"position = {gripper.state.position:+.3f} rad")
5.5.2 读取寄存器参数
使用 GloriaGripper 时,可通过 gripper.params.read() 高层接口读取任意寄存器:
from gloria_m_sdk import GloriaGripper, Variable
with GloriaGripper("COM5") as g:
mode = g.params.read(Variable.CTRL_MODE)
pmax = g.params.read(Variable.PMAX)
vmax = g.params.read(Variable.VMAX)
tmax = g.params.read(Variable.TMAX)
print(f"CTRL_MODE = {mode}")
print(f"PMAX = {pmax}")
print(f"VMAX = {vmax}")
print(f"TMAX = {tmax}")
使用低层 CanController 时,需要直接向 0x7FF 发送读参帧:
import struct
import time
from gloria_m_sdk import Variable
def read_param_once(adapter, *, target_id: int, rid: int, timeout_s: float = 0.03):
can_id_l = int(target_id) & 0xFF
can_id_h = (int(target_id) >> 8) & 0xFF
# 0x33 表示读参数
adapter.send(0x7FF, bytes([can_id_l, can_id_h, 0x33, int(rid) & 0xFF, 0, 0, 0, 0]))
deadline = time.time() + float(timeout_s)
expect_ids = {int(target_id), int(0x100 + int(target_id)), 0x00}
is_u32 = (7 <= int(rid) <= 10) or (13 <= int(rid) <= 16) or (35 <= int(rid) <= 36)
while time.time() < deadline:
for pkt in adapter.read_packets():
if len(pkt.data) != 8:
continue
if int(pkt.can_id) not in expect_ids and not (
pkt.data[0] == can_id_l and pkt.data[1] == can_id_h
):
continue
if pkt.data[2] not in (0x33, 0x55):
continue
if int(pkt.data[3]) != (int(rid) & 0xFF):
continue
if is_u32:
return struct.unpack("<I", pkt.data[4:8])[0]
return struct.unpack("<f", pkt.data[4:8])[0]
time.sleep(0.002)
return None
使用示例:
mode = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.CTRL_MODE))
pmax = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.PMAX))
vmax = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.VMAX))
tmax = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.TMAX))
pm = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.p_m))
xout = read_param_once(adapter, target_id=act.command_id, rid=int(Variable.xout))
print(f"CTRL_MODE = {mode}")
print(f"PMAX = {pmax}")
print(f"VMAX = {vmax}")
print(f"TMAX = {tmax}")
print(f"p_m = {pm}")
print(f"xout = {xout}")
应用层控制优先使用 act.state(position / velocity / torque);仅在排查模式切换或限幅配置时再读寄存器,避免高频循环中引入过多读参请求。
6. 底层 CanController 方法速查
CanController 属于低层接口,供需要精细控制的高级用户使用。普通用户推荐使用 GloriaGripper 门面(见第 4 节)。
| 方法 | 作用 |
|---|---|
register(act) | 注册执行器 |
enable(act) | 使能电机 |
disable(act) | 失能电机 |
set_zero(act) | 设当前位置为零点 |
set_control_mode(act, mode) | 切换控制模式(MIT / POS_VEL) |
refresh_state(act) | 广播请求状态回包 |
send_mit(act, *, kp, kd, q, dq, tau) | 发送 MIT 命令 |
send_pos_vel(act, *, position, velocity) | 发送 PV 命令 |
7. 参数约定与注意事项
7.1 默认参数
| 参数 | 默认值 |
|---|---|
| 波特率 | 921600 |
| 命令 CAN ID | 0x01 |
| 反馈 CAN ID | 0x101 |
| MIT 缩放 | pmax=3.14、vmax=10.0、tmax=12.0 |
7.2 位置和方向约定
MIT_SAFE_Q_MIN=0.0、MIT_SAFE_Q_MAX=2.7为通用安全范围- demos 默认
open_q > close_q(如open_q=2.5、close_q=0.0) - 正力矩 = 张开,负力矩 = 闭合
实际使用中 PositionRange、open_q / close_q、力矩符号三者需与机构方向一致,否则会出现方向反转或限位抖动。
7.3 安全建议
- 首次调试用低速、小力矩
- 先单次开合验证,再进循环或力控
- 退出前始终调用
disable() - 力控先验证空载基线和力臂曲线
8. 故障排查
| 现象 / 异常 | 排查方向 |
|---|---|
GloriaConnectionError / 串口打不开 | 检查串口号、设备管理器中是否出现 CAN 适配器;Linux 下检查 dialout 组权限 |
GloriaCommunicationError / 超时或帧错误 | 检查波特率(默认 921600)、CAN 线缆是否接好;确认 feedback_id 与电机实际反馈 ID 匹配 |
GloriaModeError / 模式切换失败 | 检查 command_id / feedback_id;低层 set_control_mode() 返回 False 同理 |
GloriaConfigError / 参数越界 | 检查 Limits、PositionRange 取值是否合法 |
| 无状态反馈 | 确认 poll=True 或手动调用 gripper.motor.poll() / ctrl.poll();检查反馈 ID |
| 开合方向相反 | 检查 open_q / close_q 定义、力矩符号、PositionRange 区间 |