Files
chenshijue 4240bb889a 初始提交:关节模组仿真平台
- 三接口契约:自包含 MJCF / 配置 schema / 报告计算规范
- Python 流水线:urdf_to_mjcf → generate_schema → simulate_report(validate_module 一键编排)
- 输入案例 urdf + 生成产物 output(自包含 MJCF/schema/报告/网格副本)
- 详细架构说明 docs/architecture.md
2026-08-28 11:37:47 +08:00

160 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 接口 2 —— 关节模组配置 Schema
> 用途:给「浏览器端 WASM 仿真」一个**统一观测接口**。无论用户上传的是什么构型的关节模组
> (一级/多级、三个/四个行星轮、太阳轮+行星架、谐波、摆线…),后端把它归一化成这份 JSON,
> 前端只读这份 JSON 就能:找到输入端/输出端、知道减速比、拿到限位、按默认参数跑仿真。
---
## 1. Schema 是什么 / 不是什么
| | 说明 |
|---|---|
| ✅ 是什么 | 关节模组的**对外观测契约**:输入关节、输出关节、减速比、限位、默认仿真参数 |
| ❌ 不是什么 | **不描述内部构型**(几级传动、几个行星轮、齿数、几何)。这些全部已经编码在 MJCF 里,前端不需要知道 |
| ❌ 不是用户上传的 | 这份 JSON 是**后端从 URDF 生成**的,不是用户填写的。用户上传的始终是「URDF + mesh」的 zip |
**为什么必须要有 schema**
1. 报告里要测的输入/输出力矩,是「哪个关节」取决于构型。schema 告诉前端哪两个关节是输入/输出端。
2. 减速比的标称值(`gear_ratio`)可能来自 URDF 的 `<mimic>`,也可能是标定/手动填的,需要显式声明来源。
3. 前端要做统一的限位检查、统一的安全余量,就需要统一格式的限位。
> 一句话:**MJCF 管「怎么动」,schema 管「观测什么」,报告规范管「算出什么」。**
---
## 2. 字段定义(格式契约,定义一次)
| 字段 | 类型 | 单位 | 必填 | 含义 | 取值来源 |
|---|---|---|---|---|---|
| `module_id` | string | — | ✅ | 模组唯一标识 | 后端生成(如模型名) |
| `name` | string | — | | 显示名 | 后端生成 |
| `model` | string | — | ✅ | 要加载的 MJCF 文件名(自包含,网格与它同目录) | 转换工具输出 |
| `input_joint` | string | — | ✅ | **输入关节名**(电机端) | URDF 里唯一没有 `<mimic>` 的关节 |
| `output_joint` | string | — | ✅ | **输出关节名**(模组输出端) | URDF 里以正 multiplier 跟随输入的关节 |
| `gear_ratio` | number | — | ✅ | 标称减速比 = 输入 / 输出 = `1/multiplier` | 默认取 `<mimic multiplier>` 倒数;可标定覆盖 |
| `gear_ratio_source` | enum | — | ✅ | `mimic` / `calibrated` / `manual` | 减速比来源 |
| `limits.position` | [number, number] | rad | ✅ | 输入关节位置限位 `[lower, upper]` | URDF `<limit lower/upper>` |
| `limits.torque` | [number, number] | N·m | ✅ | 输入力矩限位 `[-T, +T]` | MJCF `<actuator ctrlrange>`(占位,待填真实值) |
| `limits.velocity` | [number, number] | rad/s | | 速度限位 | URDF `<limit velocity>`(若有) |
| `simulation.timestep` | number | s | ✅ | 仿真步长 | 默认 `0.001` |
| `simulation.duration` | number | s | ✅ | 仿真时长 | 默认 `4.0` |
| `simulation.kp` / `kd` | number | — | ✅ | 输入 PD 位置控制增益 | 默认 `20.0` / `0.3` |
| `simulation.amplitude` | number | rad | ✅ | 参考轨迹幅值 | 默认 `2π`1 圈) |
| `simulation.frequency` | number | Hz | ✅ | 参考轨迹频率 | 默认 `0.25` |
| `simulation.load_torque` | number | N·m | ✅ | 输出端恒值负载(负 = 阻力) | 默认 `-3.0` |
| `simulation.damping` | number | N·m·s/rad | ✅ | 关节粘性阻尼 | 默认 `0.01` |
| `simulation.mode` | enum | — | ✅ | 仿真模式:`normal` / `overload` | 默认 `normal` |
> 所有带默认值的字段,前端都可以覆盖(用户调参)。`input_joint` / `output_joint` /
> `limits` / `gear_ratio` 是后端算好的「事实」,前端只读。
---
## 3. 形式化 JSON Schema(供前端校验用,draft 2020-12
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "joint-module.schema.json",
"title": "关节模组配置",
"type": "object",
"required": ["module_id", "model", "input_joint", "output_joint",
"gear_ratio", "gear_ratio_source", "limits", "simulation"],
"additionalProperties": false,
"properties": {
"module_id": { "type": "string" },
"name": { "type": "string" },
"model": { "type": "string" },
"input_joint": { "type": "string" },
"output_joint": { "type": "string" },
"gear_ratio": { "type": "number", "exclusiveMinimum": 0 },
"gear_ratio_source": { "type": "string", "enum": ["mimic", "calibrated", "manual"] },
"limits": {
"type": "object",
"required": ["position", "torque"],
"properties": {
"position": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 },
"torque": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 },
"velocity": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 }
}
},
"simulation": {
"type": "object",
"properties": {
"timestep": { "type": "number", "default": 0.001 },
"duration": { "type": "number", "default": 4.0 },
"kp": { "type": "number", "default": 20.0 },
"kd": { "type": "number", "default": 0.3 },
"amplitude": { "type": "number", "default": 6.283185307179586 },
"frequency": { "type": "number", "default": 0.25 },
"load_torque": { "type": "number", "default": -3.0 },
"damping": { "type": "number", "default": 0.01 },
"mode": { "type": "string", "enum": ["normal", "overload"], "default": "normal" }
}
}
}
}
```
---
## 4. 本案例的实例
```json
{
"module_id": "planetary_joint_split_motor_demo",
"name": "行星轮系分体电机关节模组",
"model": "planetary_joint_split_motor_demo.xml",
"input_joint": "sun_input_joint",
"output_joint": "carrier_output_joint",
"gear_ratio": 6.0,
"gear_ratio_source": "mimic",
"limits": {
"position": [-37.6991118431, 37.6991118431],
"torque": [-10.0, 10.0],
"velocity": [-6.28318530718, 6.28318530718]
},
"simulation": {
"timestep": 0.001,
"duration": 4.0,
"kp": 20.0,
"kd": 0.3,
"amplitude": 6.283185307179586,
"frequency": 0.25,
"load_torque": -3.0,
"damping": 0.01,
"mode": "normal"
}
}
```
对照说明:
| 实例值 | 怎么来的 |
|---|---|
| `input_joint = sun_input_joint` | URDF 里 5 个关节中,唯一没有 `<mimic>` 的是 `sun_input_joint`(独立驱动源) |
| `output_joint = carrier_output_joint` | `<mimic joint="sun_input_joint" multiplier="0.16667">`,正 multiplier → 减速输出端 |
| `gear_ratio = 6.0` | `1 / 0.166666666666667 = 6`(1 级行星轮系,齿圈固定,太阳轮:行星架 = 6:1) |
| `limits.position = ±37.6991` | URDF `<limit lower="-37.6991118431" upper="37.6991118431">`(±6 圈 = ±12π) |
| `limits.torque = ±10` | MJCF `<actuator ctrlrange="-10 10">`(**占位**,待填真实电机额定值) |
| `limits.velocity = ±6.2832` | URDF `<limit velocity="6.28318530718">`1 圈/秒) |
| `simulation.*` | 报告规范的默认场景参数,见 [report_spec.md](report_spec.md) |
---
## 5. 减速比来源的优先级(多来源怎么取)
后端生成 schema 时,`gear_ratio` 按下面顺序确定,并在 `gear_ratio_source` 里记录用的是哪个:
1. **`mimic`** —— URDF `<mimic multiplier>` 的倒数(最优先,本案例)。
2. **`calibrated`** —— 跑一次仿真,`mean(q_out / q_in)` 标定得到(无 `<mimic>` 或传动力不可靠时)。
3. **`manual`** —— 前端手动填(都没有时兜底)。
> 减速比只进 schema 与报告,**不进 MJCF**——MJCF 里的传动关系由 `<equality>` 精确表达,
> schema 里的 `gear_ratio` 只是「标称参考值」,用于报告的效率/理想力矩计算。