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

7.7 KiB
Raw Permalink Blame History

接口 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 参考轨迹幅值 默认 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

{
  "$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. 本案例的实例

{
  "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

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 只是「标称参考值」,用于报告的效率/理想力矩计算。