- 三接口契约:自包含 MJCF / 配置 schema / 报告计算规范 - Python 流水线:urdf_to_mjcf → generate_schema → simulate_report(validate_module 一键编排) - 输入案例 urdf + 生成产物 output(自包含 MJCF/schema/报告/网格副本) - 详细架构说明 docs/architecture.md
7.3 KiB
接口 3 —— 报告计算规范(指标接口)
用途:定义「关节模组仿真报告」里固定要测、要输出的值,以及每个值怎么从 MuJoCo 数据算出来。 前端(WASM)照着这份规范实现报告模块即可,不需要后端再给脚本。
为什么报告逻辑是固定的? 运动关系随上传的构型不同而不同(几级、几个行星轮都不一样),但 「要测什么」是确定的:输入/输出的位置、速度、加速度、力矩,以及由它们导出的功率、效率、减速比、 安全余量。唯一随构型变的是哪个关节是输入、哪个是输出——这由 schema.md 提供。
1. 输入
报告模块需要的输入分三类:
| 输入 | 来源 | 说明 |
|---|---|---|
| 模型 | MJCF(schema.model) |
含网格、质量/惯量、齿轮约束、作动器 |
| 观测配置 | schema | input_joint / output_joint / gear_ratio / limits |
| 场景参数 | schema 的 simulation |
步长、时长、PD 增益、参考轨迹、负载 |
约定记号(下文统一用):
| 记号 | 含义 |
|---|---|
q_in, qd_in, qacc_in |
输入关节位置 / 速度 / 加速度 |
q_out, qd_out, qacc_out |
输出关节位置 / 速度 / 加速度 |
τ_in, τ_out |
输入力矩 / 输出力矩 |
N |
减速比(schema.gear_ratio) |
2. 仿真流程(固定)
加载 MJCF → mj_resetData
for k in 0..(duration/timestep)-1:
t = k · timestep
q_ref = amplitude · sin(2π · frequency · t)
qd_ref = amplitude · 2π·frequency · cos(2π · frequency · t)
τ_in = kp·(q_ref − q_in) + kd·(qd_ref − qd_in) # PD 位置控制
ctrl[input_motor] = τ_in # 输入电机力矩
ctrl[load_motor] = load_torque # 输出端恒值负载
mj_step() # 齿轮约束在步内解算
记录本步数据
齿轮耦合是软约束(
<equality>+solref),mj_step内自动解算;输出力矩τ_out从约束反力读出(见下)。
3. 指标 → 数据源 → 公式(核心表)
MuJoCo 数据源以 d.* 表示 MjData 的字段;input_dof / output_dof 是输入/输出关节
的自由度下标(m.jnt_dofadr[...])。
3.1 运动学(跟踪精度)
| 指标 | 符号 | 数据源(逐时间步) | 单位 |
|---|---|---|---|
| 输入位置 | q_in |
d.qpos[input_dof] |
rad |
| 输入速度 | qd_in |
d.qvel[input_dof] |
rad/s |
| 输入加速度 | qacc_in |
d.qacc[input_dof] |
rad/s² |
| 输出位置 | q_out |
d.qpos[output_dof] |
rad |
| 输出速度 | qd_out |
d.qvel[output_dof] |
rad/s |
| 输出加速度 | qacc_out |
d.qacc[output_dof] |
rad/s² |
汇总(对整段轨迹统计):
| 指标 | 公式 | 说明 |
|---|---|---|
| 输入位置峰值 | `max | q_in |
| 位置跟踪误差 RMS | √ mean((q_in − q_ref)²) |
越小越准 |
| 速度跟踪误差 RMS | √ mean((qd_in − qd_ref)²) |
越小越准 |
| 输出位置峰值 | `max | q_out |
| 传动比实测 | 带截距最小二乘斜率(q_out 对 q_in 拟合,取稳态后半段) |
期望 ≈ 1/N |
不要用逐点
q_out/q_in再取均值:正弦参考下q_in每周期过零,软约束相位滞后会让 过零处比值爆表甚至变号,把均值带偏(实测 0.112368 vs 真实 0.111111)。带截距的 最小二乘斜率对相位滞后和负载静偏置(q_out恒滞后一个常数角)都不敏感,能精确还原1/N。
3.2 动力学(力矩 / 功率)
| 指标 | 符号 | 数据源 / 公式 | 单位 |
|---|---|---|---|
| 输入力矩 | τ_in |
d.actuator_force[input_motor] |
N·m |
| 输出力矩 | τ_out |
d.qfrc_constraint[output_dof] |
N·m |
| 输出功率 | P_out |
τ_out · qd_out |
W |
| 理想输出力矩 | τ_ideal |
N · τ_in |
N·m |
| 力矩损失 | Δτ |
N·τ_in − τ_out |
N·m |
| 效率 | η |
τ_out / (N · τ_in) × 100%(稳态均值) |
% |
稳态均值 = 取时间序列后半段(让瞬态衰减完)的
mean(|·|)。
3.3 安全性(安全余量)
| 指标 | 公式 | 单位 |
|---|---|---|
| 位置余量 | `(‖limit_pos‖ − max | q_in |
| 力矩余量 | `(‖limit_trq‖ − max | τ_in |
| 过载判定 | 力矩余量 < 20% → 警告 | — |
其中 limit_pos = schema.limits.position[1],limit_trq = schema.limits.torque[1]。
3.4 可选:行星轮观测(仅行星构型)
若模组有行星轮(本案例有 3 个),可额外记录某一行星轮的位置/速度 q_p, qd_p(d.qpos[planet_dof])。
这是可选项——报告必填的只有输入/输出端;行星轮数量/命名随构型变,不属于固定指标。
4. 输出格式
4.1 逐时间步数据(CSV)
列名与关节名解耦(用固定的 input_* / output_*,不写死太阳轮/行星架),
前端按 schema.input_joint / schema.output_joint 填充即可:
| 列 | 内容 |
|---|---|
time |
时间 [s] |
input_q, input_qd, input_qacc |
输入位置/速度/加速度(schema.input_joint) |
q_ref, qd_ref |
参考轨迹位置/速度 |
output_q, output_qd, output_qacc |
输出位置/速度/加速度(schema.output_joint) |
planet_q, planet_qd |
(可选)行星轮位置/速度,仅行星构型且有记录时才有 |
tau_in, tau_out, power_out |
输入/输出力矩、输出功率 |
本地
simulate_report.py按固定顺序写出:time, input_q, input_qd, input_qacc, q_ref, qd_ref, output_q, output_qd, output_qacc, [planet_q, planet_qd,] tau_in, tau_out, power_out。
4.2 汇总报告(终端 / JSON)
按第 3 节的三类汇总指标输出:运动学(峰值、跟踪误差、传动比实测)、动力学(力矩、 功率、效率)、安全性(两类余量 + 过载判定)。
报告首行需注明仿真模式(schema.simulation.mode,normal / overload),并显示当前
使用的负载力矩与阻尼。当 mode = overload 时,额外产出一份 过载报告(overload_report.txt):
| 指标 | 公式 | 单位 |
|---|---|---|
| 额定力矩限位 | limit_trq = schema.limits.torque[1] |
N·m |
| 施加负载力矩 | schema.simulation.load_torque |
N·m |
| 输入力矩峰值 | `max | τ_in |
| 力矩余量 | `(limit_trq − max | τ_in |
| 位置跟踪误差 | √ mean((q_in − q_ref)²) |
rad |
| 过载判定 | 余量 ≤ 0 → 已过载;0 < 余量 < 20% → 接近过载;否则未过载 | — |
5. 参考实现
本地参考实现见 ../scripts/simulate_report.py,它就是这份规范的可执行版本。 前端实现时应以本规范为准,脚本只作对照。
两个易错点(实现时务必注意):
- 输出力矩读约束反力,不读作动器力。 齿轮耦合是
<equality>约束,τ_out取d.qfrc_constraint[output_dof];若读load_motor的actuator_force只会得到常数负载。 - 稳态统计取后半段。 参考轨迹从静止起跳会有初始瞬态尖峰,前半段不参与均值/效率计算。