DEEP 87 · 第九辑 · 电压专项 · LEARN NOTES

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

解读 87 · 代码里的电压:vin_range 与 BAM

解读对象:microduck-replica/upstream/microduck_rl/src/mjlab_microduck/robot/microduck_constants.py(_BAM_ACTUATOR_KWARGS)+ bam/bam/model.py、bam/bam/actuator.py(电压进力矩的路径)
需要的前置:解读 54(为什么给执行器建数学模型)· 解读 57(参数写回仿真的路径)

电压在代码里出现两次:训练侧,它是一组随机化参数;部署侧,它是一对常量。两处必须讲同一个故事,策略才能"训练时见过的电 = 上机时真实的电"。

1. 训练侧:电压是三个随机化参数

microduck_constants.py 的 _BAM_ACTUATOR_KWARGS 里,电压相关共三项:

旁边还有 kp_fw=200.0(固件位置环刚度,注释对照:microban 用 125)和 delay_min/max_lag=3/6(指令延迟)。换舵机时全流程 §3 专门提醒:"vin_range 按新舵机额定改(官方是 6.5–8.2 超压特例,勿照抄)"。

2. 模型侧:电压怎么变成力矩

BAM 把"固件 PD → PWM → 电压 → 电流 → 力矩"整条链搬进仿真。bam/bam/actuator.py 的 VoltageControlledActuator.compute_control:duty_cycle = clip(位置误差 × kp × error_gain, ±max_pwm),输出电压 = vin × duty_cycle;compute_torque 用直流电机方程 τ = kt·V/R − kt²·q̇/R。所以 vin 线性缩放可用电压:电池掉 1V,同样误差下满占空比能给出的电压就少 1V,力矩跟着缩水——这正是电压必须随机化的原因:策略在千万步里见过各种电压,才不会"满电生龙活虎、半电萎靡不振"。被注释掉的 max_current=1.75 若启用,会把固件限流建模成对占空比的约束窗口(注释明说:firmware can only bound the duty cycle)。

bam/bam/model.py 管的是另一条正交的轴:摩擦预算。m1–m6 六档从纯库仑(M1)一路加到"库仑 + Stribeck + 负载相关 + 方向性 + 二次项"(M6),friction_base/load_friction_*/friction_viscous 这些参数描述"转起来多费劲",与 vin 描述"力气多大"互不覆盖——合起来才是完整的执行器。

3. 部署侧:一对实测常量

duck-control/src/model.rs:BATTERY_FULL_V = 8.2(注释:"Off a full charge, under load. NP-F550, 2S Li-ion")、BATTERY_EMPTY_V = 6.6("The sag floor"),battery_percent() 在两者间线性映射并钳位。注意口径:8.2 是带载满电,不是充电器上的 8.4V——注释明说这是 usable-under-load,不是电芯化学范围。换 HL-2915 时(教程 §6.1)这里改 9–14V,用 62 号遥测(0.1V 分辨率)直接除以 10。model.rs 头注释还立了纪律:这些数来自 microduck_runtime 对实机的测量,"从规格书重新推导,恰恰是那种看起来对、走起来错的改动"。

你带走的收获

延伸

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