MANUAL 10 · BAM 官方篇 · LEARN NOTES

收进学习手册 · 2026-10-11 · duck.whatled.com

飞特官方 BAM 发布解读:HD-1910 已辨识执行器模型

解读对象:gitee.com/ftservo/ftservo-bam(飞特官方 Gitee 组织,2026-09-23 至 09-30 定稿,Apache-2.0,本地克隆于 ftservo-bam/)
需要的前置:HD-1910 仿真迁移与 PPO 训练教程 §5(执行器模型与 m1–m6 命名)· 称重与标定模板-HD1910 §0.5(参照链命名纪律,工作区文件)

0. 一句话结论

飞特官方把 HD-1910 的全套 BAM 执行器模型(m1–m6,7.4 V) 发布出来了——制造商、
自己的台架、正确的 actuator: "hd1910" 身份、恰好是我们 2S 母线的电压。
它是目前可信度最高的一份 HD-1910 动力学先验,直接插入项目的执行器参照链,
但不改变红线:最终模型仍然是 hd1910_our_measured_m1..m6(实测),官方值是参照不是替身。

1. BAM 是什么(30 秒版)

BAM(Better Actuator Models)出自 Rhoban 团队(ICRA 2025 论文 Extended Friction Models
for the Physics Simulation of Servo Actuators
,Apache-2.0)。MuJoCo/IsaacGym 默认的
Coulomb-Viscous 摩擦模型太简,盖不住 Stribeck 效应、负载相关摩擦和二次速度项;
BAM 用录制的轨迹辨识出一族由简到繁的模型,直接吃进 MuJoCo CPU 和 MuJoCo Warp(GPU)。

模型族编号就是项目里一直在用的 m1–m6(JSON 键即模型项,由简到繁):

模型 摩擦项
m1 基础库仑 + 粘滞 + 指令延迟
m2 m1 + Stribeck(速度项)
m3 m1 + 负载相关摩擦(不分侧)
m4 m3 + Stribeck
m5 负载摩擦分电机侧/外侧,各带 Stribeck
m6 m5 + 二次速度项(最全)

公共电气/机械参数每次都重新辨识:kt(力矩常数)、R(绕组电阻)、armature、q_offset、
command_delay。

2. 官方发布里有什么

ftservo-bam 在 Rhoban 原版基础上新增(主仓 bam/ 是旧版快照,README 尚无 HD-1910):

内容 说明
bam/params/feetech_hd1910_7_4V/ HD-1910 m1–m6 全套已辨识参数(7.4 V 台架)
bam/params/feetech_sts3215_7_4V/ STS3215 m1–m6(7.4 V);另有 waveshare_st3025
bam/feetech/actuator.py HD1910Actuator / STS3215Actuator 控制律:vin=7.4, kp=32, error_gain=0.163, max_pwm=0.97,内部目标平滑(有状态)
bam/feetech/record.py 基于 scservo_sdk 的轨迹采集:位置换算 0 rad=2048、±π=0/4095;Windows 下把定时器精度提到 1ms 再做毫秒级 sleep
bam/dynamixel/measure_delay.py command_delay 的专项测量脚本
bam/mjlab.py + BamActuatorCfg mjlab(MuJoCo Warp GPU)集成:bam_init startup 事件 + 全并行环境向量化的执行器(电压控制律 + DC 电机 + BAM 摩擦预算),兼容 mjlab 1.3
PyPI pip install better-actuator-models[mjlab]

两个与本项目互相印证的细节:官方采集脚本里
ADDR_P_GAIN_MAP = {"sts3215": 21, "hd1910": 50}——HD-1910 的 P 增益在寄存器 50,
与 kissqy 适配驱动(临时 P/D @50)一致;kp=32 与 community-kit 调试器的默认增益一致。

3. 关键对比:官方 m6 vs 陆吾/XGODUCK 参照

项目此前唯一现成的 HD-1910 m6 是 kissqy 携带的陆吾参照
(hd1910_m6.json,与 XGODUCK 1910_m6.json 字节级相同,actuator 字段还错标 sts3215,
只配当数值先验)。两份 m6 的实质差异(官方 7.4 V m6 vs 陆吾 m6):

参数 官方 HD1910(7.4 V) 陆吾/XGODUCK m6 差多少
kt(N·m/A,按库口径) 0.564 0.624 −10%
R(Ω) 2.97 4.91 −40%
command_delay(s) 0.00098 0.0060 6 倍
friction_base 0.0120 0.0158 −24%
load_friction_motor 0.353 0.069 5 倍
load_friction_external 0.043 0.158 −73%
摩擦分侧结构 电机侧主导 外侧主导 几乎对调
actuator 身份 hd1910 sts3215(错标) —
error_gain_ratio 未提供 1.32 陆吾自带拟合质量指标

解读:两份模型不是同一颗舵机的两种拟合,而是两种不同的物理画像——延迟差 6 倍会直接
改变观测-动作对齐,摩擦分侧对调会改变带载下的力矩预算。训练侧此前把陆吾参照当
"第一版仿真基线"(hd1910_kissqy_reference_m6),官方模型出现后,参照链应更新为:

hd1910_our_measured_m1..m6      # 终点:我们自己台架的实测(红线不变)
hd1910_ftservo_official_m6      # 新增:制造商 7.4V 官方辨识 ← 当前最强先验
hd1910_kissqy_reference_m6      # 降级为历史参照(820g 模型配套,身份错标)
xgoduck_1910_reference_m6       # 同上(与 kissqy 那份字节级相同)

三条使用纪律:不混文件(在仿真里与既有配置隔离命名,永不覆盖 our_measured 槽位);
对齐电压口径(官方 7.4 V 恰是 2S 标称,带载 6.6–8.2 V 内插值可接受,但不要拿它外推 8.4 V 满电);
error_gain_ratio 官方没给,评估拟合质量要靠自己回放比对。

4. 怎么用:两条接线(MuJoCo CPU / mjlab GPU)

4.0 先修一个坑(2026-10-11 快照实测)

PyPI 的 better-actuator-models(1.0.2,2026-07-16)不含 HD1910——只有 STS3215。
要用官方 HD1910,必须本地安装 Gitee 克隆;且该快照直接加载会报错:

import sys; sys.path.insert(0, "ftservo-bam")          # 或 pip install -e ftservo-bam
from bam import model as bam_model
# 坑 1:bundled 名是参数目录名,不是 "HD1910"(报错信息会列出可用名)
# 坑 2:注册表键是 "HD1910"(大写),JSON 里 actuator="hd1910"(小写)→ KeyError
bam_model.actuators.setdefault("hd1910", bam_model.actuators["HD1910"])   # 一行别名修复
m = bam_model.load_model(motor_name="feetech_hd1910_7_4V", model="m6")    # OK

加载成功后模型自带官方执行器常量:vin=7.4、kp=32、error_gain=0.163、max_pwm=0.97。
(这个大小写不一致已报给上游并提交了修复 PR:
issue #1 ·
PR #2。合并前用上面的别名绕过,
合并后可删。)
另注意 pyproject 钉死 requires-python = ">=3.12,<3.13"——训练环境要用 Python 3.12。

4.1 环境搭建(本机已验证的配方)

官方 pyproject 钉死 requires-python = ">=3.12,<3.13",用 Python 3.12 建 venv、
从本地克隆 editable 安装(PyPI 1.0.2 没有 HD1910,不要 pip install better-actuator-models):

python3.12 -m venv ~/venvs/bam312
~/venvs/bam312/bin/pip install -e '/Volumes/dev/dev/microduck/ftservo-bam[mujoco]'
# 实测: bam(editable) + mujoco 3.15.0 + numpy + colorama
# 注册表大小写修复见 §4.0(PR #2 合并 pull 后可删)

训练机(Linux/GPU)同理:uv add --editable ../ftservo-bam --extra mjlab,
或把 bam/ 目录放进训练仓的依赖路径。

4.2 MuJoCo CPU(回放验证、单机实验)

用法(docs/usage/mujoco_cpu.rst,线上 https://bam.readthedocs.io ):load_model
得到模型 → MJCF 里执行器必须声明为 motor(BAM 运行时覆写 frictionloss、
damping、armature,XML 里的值被忽略)→ MujocoController(model=…, actuator=[关节名], …)
→ 每步 set_q_target + update() 后 mj_step。电压跌落与 mjlab GPU 路径逐位一致
(同一推导),CPU 回放看到的就是训练时的电池行为。

4.3 mjlab GPU(插进训练任务——本仓落点已找准)

我们自己的训练仓 xgoduck_rl/src/mjlab_microduck/robot/microduck_constants.py
本来就在用 BAM(FrictionDRBamActuatorCfg,摩擦随机化走 BAM 原生 friction_scale),
当前配置是 motor_name="xl330", model="m6", kp_fw=200——XL330 官方参数。
换成官方 HD-1910 就是改这一处:

import bam.model
bam.model.actuators.setdefault("hd1910", bam.model.actuators["HD1910"])   # §4.0 别名

_BAM_ACTUATOR_KWARGS = dict(
    motor_name="feetech_hd1910_7_4V",   # ← 原来是 "xl330"(或用 json_path 指向 m6.json)
    model="m6",
    target_names_expr=(r"^(?!passive_).*",),
    kp_fw=32.0,          # ← 官方 HD1910 执行器常量;200 是 XL330 的,别带过来
    vin_range=(6.5, 8.2),   # 2S 带载区间,保持不变
    vin_drop_gain_range=(0.0, 0.2),
    vin_min=6.0,
    delay_min_lag=3,        # 第一轮 A/B 保持不变——单变量原则,只换执行器模型
    delay_max_lag=6,
)

actuators 与 backlash_actuators(backlash 模型用)共用这套 kwargs,一处改两边生效。
单变量纪律:第一轮 A/B 只换模型与 kp_fw,电压/延迟随机化保持原值,跑完与 XL330 基线
对照 reward、fell_over、air_time(对应 HD1910 仿真迁移教程 §9
的评测方法),再逐项放开。

4.4 验证效果:拿规格书当已知答案(已实测通过)

写了 tools/verify_bam_hd1910.py(工作区文件):用官方解析仿真器
(bam.simulate.Simulator,拟合时用的同一个模型本体)对照《HD-1910-C001 规格书》A/0
@7.4V 档。m6 实测结果(2026-10-12):

验证项 模型预测 规格 (±10%) 判定
空载最高转速 112.2 RPM 113 RPM PASS(偏差 0.7%)
堵转扭矩 13.93 kg·cm 15 kg·cm PASS(−7.1%,负载摩擦吃掉的正是 m6 建模的物理)
保持仿真 0.5×/1.15×τ_stall 推动 / 堵转 推得动/推不动 符合
MuJoCo CPU 管线一致性 112.2 vs 112.2 RPM — 差 0.0%
0.2 rad 阶跃(代表性负载) 超调 10.3%、整定 44 ms 无规格值 模型预测,供训练侧参考
~/venvs/bam312/bin/python tools/verify_bam_hd1910.py            # m6 全套验证
~/venvs/bam312/bin/python tools/verify_bam_hd1910.py --all      # m1–m6 档位对照表

档位对照表(--all 实测)——选档不是玄学:

档位 kt (N·m/V) R (Ω) 空载 RPM 堵转 kg·cm 规格相符
m1 0.582 4.33 108.1 ✓ 9.83 ✗ 转速✓ 扭矩✗
m2 0.581 4.31 107.4 ✓ 9.86 ✗ 转速✓ 扭矩✗
m3 0.571 3.70 115.3 ✓ 11.30 ✗ 转速✓ 扭矩✗
m4 0.619 3.94 104.6 ✓ 11.52 ✗ 转速✓ 扭矩✗
m5 0.559 2.93 112.1 ✓ 13.99 ✓ 全✓
m6 0.564 2.97 112.2 ✓ 13.93 ✓ 全✓

简化档(m1–m4)的 kt/R 拟合取舍牺牲了堵转外推——只有分侧建模的 m5/m6 与规格书全维
相符。训练用 m6(或 m5),CPU 快速实验可以降档但要知道代价。真正的最终校验仍然是
拿我们自己的 PD 阶跃数据回放比对(换舵机重训全流程 §2.3,工作区文件)——官方参数是"已知答案",我们的实测是"卷子"。

4.5 复刻官方辨识(可选,喂 our_measured)

bam/feetech/record.py 是官方的采集脚本(scservo_sdk,毫秒级定时),
bam/dynamixel/measure_delay.py 可借鉴测 command_delay。它与仓库已有的
PD 阶跃采集是同一件事的两种实现:官方脚本换了 SDK,我们的管线换了轨迹设计。跑
our_measured 时把官方 m6 当"已知答案"对照,是免费的校验器。

5. 边界与提醒

6. 文档地图

想深入哪块 去读
官方库全文档 https://bam.readthedocs.io · 本地 ftservo-bam/docs/
m1–m6 模型族与 JSON 参数含义 ftservo-bam/bam/parameter.py · docs/usage/
HD-1910 仿真侧怎么接 HD-1910 仿真迁移与 PPO 训练教程
参照链命名纪律 microduck-replica/docs/称重与标定模板-HD1910.md §0.5–0.6(工作区文件)
台架辨识方法论(解读 55–57、60、203) deep-dive 系列
舵机台架与标定工具 microduck-community-kit 教程

口径提醒:官方发布解决的是"HD-1910 长什么样",解决不了"我们这 15 颗长什么样"——
后者仍然只有台架实测一条路。

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页