Meow API、反馈与多电机 PDO
本页介绍 GUI 使用的 hex-motor 0.3.2 接口和 Meow 对象编码。接线与第一次转动见快速上手,地址及错误码见协议概览。
Rust 接入示例
下面的 Linux / SocketCAN 示例会让节点 0x01 以 0.05 Rev/s 运行约一秒,再发送零速度并失能。运行前按快速上手配置 can0,固定电机、确认运动空间与可用的断电手段。关闭占用此通道的 GUI 和其他主机程序。
Cargo.toml:
[package]
name = "meow-pv-example"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1"
can-transport = { version = "=0.1.4", features = ["socketcan"] }
hex-motor = "=0.3.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
src/main.rs:
use std::{sync::Arc, time::Duration};
use can_transport::{socketcan::SocketCanBus, CanBus};
use hex_motor::{
cia402::PdoProfile,
meow_motor::{
MeowMotorManager, MeowMotorManagerOptions, MeowMotorTarget, MeowProfileLimits,
},
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let bus: Arc<dyn CanBus> = Arc::new(SocketCanBus::open("can0")?);
let manager = MeowMotorManager::new(
bus,
MeowMotorManagerOptions {
heartbeat_node_id: 0x0A,
auto_identify: false,
..Default::default()
},
)?;
let node = 0x01;
let model = manager.identify(node).await?;
println!("{}", model.display_name());
manager
.initialize(node, PdoProfile::from_event_timer_ms(10)?)
.await?;
let motion = async {
manager.set_max_torque(node, 50).await?;
manager
.set_profile_limits(
node,
MeowProfileLimits {
velocity_rev_per_s: 0.2,
acceleration_rev_per_s2: 0.2,
deceleration_rev_per_s2: 0.2,
},
)
.await?;
manager
.set_mode_sdo(
node,
MeowMotorTarget::ProfileVelocity {
velocity_rev_per_s: 0.05,
},
)
.await?;
tokio::time::sleep(Duration::from_secs(1)).await;
let state = manager.status(node)?;
println!("{:?}", state.measurements);
manager
.set_target_sdo(
node,
MeowMotorTarget::ProfileVelocity {
velocity_rev_per_s: 0.0,
},
)
.await?;
tokio::time::sleep(Duration::from_secs(1)).await;
Ok::<(), hex_motor::Error>(())
}
.await;
// Attempt Disable on both success and ordinary error paths.
let disabled = manager.disable(node).await;
motion?;
disabled?;
Ok(())
}
按实际设备修改接口与 Node-ID,然后执行 cargo run。PdoProfile 提供 PDO 周期参数,MeowMotorManager 负责电机控制。示例使用原始力矩上限 50 ‰,不是固定的 N·m 值,也不保证足以带动负载。
初始化与生命周期
推荐顺序为:
identify(nid):重读完整身份,精确匹配 Meow 型号并读取0x2001。initialize(nid, profile):进入 Pre-Operational,清理已有错误并确认失能,配置 TPDO1 / TPDO2 与消费者心跳,读取峰值力矩和 MIT 尺度因子,进入 Operational,等待两路新反馈且模式仍为失能。- 设置力矩和运动轮廓限制,随后发送与模式匹配的目标。
- 结束时显式
disable(nid),并检查结果。
| 生命周期 | 含义与后续动作 |
|---|---|
Unknown |
尚未识别 |
UnsupportedIdentity |
身份不属于支持的 Meow 产品 |
Identified |
身份与通信参数已读取,可初始化 |
Initializing |
初始化事务执行中 |
Initialized |
初始化完成;还应检查 online、NMT 和反馈新鲜度 |
NeedsReinit |
离开 Operational 或反馈过期,恢复后重新初始化 |
NeedsRestart |
通信设置已保存,重新上电后识别 |
默认主机心跳周期为 50 ms、消费者超时为 250 ms。一个总线上应只有一个主机心跳 / 发现 / SDO 管理者;若把 Meow manager 接入已有总线管理器,设置 broadcast_heartbeat = false、auto_identify = false,由现有管理者持续提供心跳、串行协调 SDO 并显式调用识别。不要在没有外部心跳的情况下关闭广播却仍启用消费者超时。
目标与模式切换
| Rust API | 行为 |
|---|---|
set_mode_sdo(nid, target) |
先写全部目标对象,再写 0x4401,等待新 TPDO2 确认模式;可直接在线切换 |
set_target_sdo(nid, target) |
只更新当前模式目标,不写模式命令;目标类型必须匹配当前模式 |
set_max_torque(nid, permille) |
写 0x4572,范围 0–1000 |
set_profile_limits(nid, limits) |
写 0x4581/0x4583/0x4584,值均须为有限正数 |
disable(nid) |
写 0x4401 = 0 并确认失能 |
clear_error(nid) |
清错并确认失能,不恢复此前模式;内部处理重复清错的重触发 |
status(nid) |
读取最新缓存快照,不触发一次 SDO 采样 |
subscribe_status(nid) |
获取 watch 接收器,观察最新状态 |
subscribe_status_stream(nid) |
订阅发布流;消费者应处理溢出 / 丢样通知 |
PP 目标使用 SignedQ8_24::from_revolutions(value)? 构造,不能将 Float32 的位模式写进 0x457A。PV 为 MeowMotorTarget::ProfileVelocity { velocity_rev_per_s };力矩为 Torque { torque_permille }。默认 GUI 的“发送目标值”走 set_mode_sdo,会同时提交所选模式。
MIT 单位与系数
非压缩 MIT 使用 MeowMotorTarget::Mit(MeowMitTarget { ... })。位置和速度为 Rev / Rev/s,torque_nm 为原始命令域的 N·m,kp / kd 为 U16 原始值,kp_kd_limit_permille 为 0–1000。先读取 F = 0x4102:07,确认其为有效正数:
position_rev = position_rad / (2π)
velocity_rev_per_s = velocity_rad_per_s / (2π)
kp_raw = round(kp_Nm_per_rad × 2π / F)
kd_raw = round(kd_Nm_s_per_rad × 2π / F)
Kp / Kd 编码结果须在 0–65535 内。0x4102:06 分别限制 Kp 与 Kd 项运算产生的力矩结果,不限制 Kp / Kd 参数本身。GUI 会执行上述换算;调用 Rust 库时需要自己完成。
出厂力矩系数
read_factory_calibration(nid) 读取 0x4001。驱动只解码,不自动修正命令或反馈;GUI 额外使用其中的力矩系数 k:
raw_torque_command = physical_torque_command × k
physical_torque_feedback = (feedback_permille / 1000 × peak_torque_Nm) / k
力矩目标先按 0x4576 的峰值换算成原始千分比,并检查 ±1000 范围。未出厂标定时 GUI 使用 k = 1;读取失败时拒绝系数未知的目标请求。GUI 仅对力矩目标及 MIT 前馈力矩应用此系数,不改变位置、速度或 Kp / Kd,也不自动应用摩擦补偿。
最大力矩 0x4572 仍是原始峰值的千分比,不自动乘以 k。以有效 k 换算时,该上限对应的物理力矩约为 permille / 1000 × peak / k。不要把 GUI 已修正的输入或显示值重复换算。
TPDO 反馈布局
初始化配置的默认映射如下,均为小端排列。这里的 ID 为默认映射值,PDO COB-ID 本身可以配置。
| PDO | COB-ID | 长度 | 周期 |
|---|---|---|---|
| Device TPDO1 | 0x180 + nid |
8 字节 | 1–100 ms,由 PdoProfile 指定 |
| Device TPDO2 | 0x280 + nid |
7 字节,不补齐到 8 | 固定 20 ms(50 Hz) |
| TPDO1 字节 | 对象 | 类型与含义 |
|---|---|---|
| 0–3 | 0x4564:00 |
I32 Q8.24 位置,Rev |
| 4–5 | 0x4713:00 |
U16 时间戳,µs |
| 6–7 | 0x4577:00 |
I16 力矩,‰ |
| TPDO2 字节 | 对象 | 类型与含义 |
|---|---|---|
| 0 | 0x4402:00 |
U8 模式 / 错误状态 |
| 1–2 | 0x453F:00 |
U16 详细错误码 |
| 3–4 | 0x4104:01 |
I16 驱动温度,0.1 °C |
| 5–6 | 0x4104:02 |
I16 电机温度,0.1 °C |
帧类型按 BRS 规则决定,不由长度单独决定。TPDO1 不含直接速度字段:驱动使用位置与时间戳估计速度;需要独立 SDO 读取时使用 0x456C。
时间戳用 U16 模差处理回绕;位置用 I32 wrapping delta 处理 Q8.24 回绕。仅在采样连续且单次实际位移小于 128 圈时才能据此累计。检查 position_accumulation_valid / position_accumulation_segment,不要跨掉线或采样中断盲目连接轨迹。状态流是软件收到的发布流,不是无丢帧的硬实时采集保证。
多电机共享 PDO 与压缩 MIT
GUI 的普通初始化只配置反馈与 SDO 目标控制,不建立共享压缩 MIT 命令循环。控制器集成可以显式使用:
MeowMotorInitializeOptions::shared_host_pdo = Some(SharedHostPdoConfig { ... }),每帧 1–8 台电机,每台分配一个 slot。compressed_mit_rpdo1_recipe(slot, total, host_nid):电机 RPDO1 订阅主机 TPDO1,每台占 8 字节,映射本机0x4103:02/:03;其他 slot 用0x3000:03填充。mode_rpdo2_recipe(slot, total, host_nid):电机 RPDO2 订阅主机 TPDO2,每台占 1 字节,映射本机0x4401;其余用0x3000:01填充。CompressedMitMapping定义五个物理量的量化范围,CompressedMitTarget/pack_shared_frame完成编码。量化范围必须与电机0x4103配置一致,不能直接发送另一厂商的 MIT 帧。
主机 TPDO1 / TPDO2 ID 为 0x180 + host_nid / 0x280 + host_nid。主机 0x0A 时为 0x18A / 0x28A;4 台电机的共享 MIT 帧为 32 字节,模式帧为 4 字节。以两台电机为例:
Host TPDO1: [ motor 0: 8 bytes ][ motor 1: 8 bytes ]
Motor 0 RPDO1: 0x4103:02 | 0x4103:03 | filler32 | filler32
Motor 1 RPDO1: filler32 | filler32 | 0x4103:02 | 0x4103:03
Host TPDO2: [ motor 0 mode: 1 byte ][ motor 1 mode: 1 byte ]
RPDO 配置本身不会发送主机周期帧。控制程序须先持续发送安全目标 lane,再显式切换到 MIT,并维护心跳和停机逻辑;共享模式帧同样遵循 0x4401 的值变化语义。具体编码与 recipe 以 0.3.2 模块源码为准。
参数持久化
apply_can_settings(nid, settings) 要求身份匹配、节点在线、处于 Pre-Operational / Stopped 且生命周期为 Identified / NeedsReinit。写入及回读成功后使用 0x1010:04 = save 保存,进入 NeedsRestart;重新上电后再识别与初始化。
普通初始化不会保存 PDO 映射;需要在显式配置流程持久化时,驱动提供 pdo_communication_save_write()(0x1010:02 = save)。位置预设使用独立的 0x3001 提交流程,参见上位机零点设置。