Microduck 项目解读

项目是一个小型双足机器人 Microduck,分为两个主要部分:

  1. microduck/ - 在 Raspberry Pi Zero 2 W 上运行的部署代码
  2. mjlab_microduck/ - 基于 MuJoCo/MjLab 的强化学习训练环境

下面是对 Microduck 项目的完整解读。


Microduck 项目解读

一、项目概览

Microduck 是一个小型双足机器人项目,核心思路是:在仿真中用强化学习训练行走策略 → 导出为 ONNX 模型 → 部署到真实硬件(树莓派 + Dynamixel 舵机)上运行

项目分为两大相对独立的子工程:

子工程 作用 运行平台
microduck/ 部署运行时:读 IMU、读手柄/键盘、驱动舵机、加载 ONNX 策略 Raspberry Pi Zero 2 W
mjlab_microduck/ 强化学习训练环境:训练并导出 walk.onnx 开发机(GPU)

两者通过 walk.onnx 模型文件衔接。


二、整体目录结构

复制代码
Microduck/
├── README.md                    # 中英文双语装机/运行文档
├── bno08x_calibrate_ui.py       # BNO08x IMU 校准工具
├── scripts/
│   └── imu_mujoco_orientation_viewer.py  # IMU 方向可视化调试
│
├── microduck/                   # ===== 部署代码(运行在 Pi 上)=====
│   ├── Makefile                 # rsync 同步 + SSH 运行/调试
│   ├── pyproject.toml           # 依赖:numpy, onnxruntime, placo, rustypot, imu库
│   ├── systemd/
│   │   ├── microduck-gamepad.service       # 无头手柄开机服务
│   │   └── install-gamepad-daemon.sh
│   └── src/
│       ├── main.py              # 入口:开扭矩→回中位→启动调度器
│       ├── scheduler.py         # 50Hz 控制主循环(核心)
│       ├── controller.py        # ControllerProtocol 接口定义
│       ├── robot_controller.py  # 真实硬件:Xl330PyController + IMU 封装
│       ├── observer.py          # 每 tick 读取电机/IMU 状态 → RobotState
│       ├── imu_reader.py        # BNO08x I2C 线程读取 + 四元数坐标变换
│       ├── constants.py         # 舵机ID映射、中位、KP、过流保护参数
│       ├── scheduler.py
│       ├── observer.py
│       ├── voltage.py / imu.py / stop.py   # 调试小工具
│       ├── agents/
│       │   └── walk.onnx        # 训练好的行走策略(ONNX)
│       ├── moves/               # 动作策略(状态机:INACTIVE→STARTING→ACTIVE→STOPPING)
│       │   ├── move.py          # Move 抽象基类 + MotorCommand
│       │   ├── walk.py          # 行走:ONNX 推理 + 启动平滑过渡 + 摔倒检测
│       │   ├── squat.py         # 下蹲
│       │   └── rotate_head.py   # 转头
│       ├── input/               # 输入源抽象
│       │   ├── input_source.py  # UserInput 数据结构 + 速度限幅
│       │   ├── keyboard_input.py
│       │   └── gamepad_input.py
│       ├── sim/                 # 本地 MuJoCo 仿真(不部署)
│       │   ├── sim_main.py      # 仿真入口,可注入延迟/CoM偏移
│       │   ├── mujoco_controller.py   # 实现 ControllerProtocol 的仿真控制器
│       │   └── placo_controller.py
│       ├── debug/               # 绘图/方向校验脚本
│       └── model/
│           ├── mjcf/robot.xml   # MuJoCo 机器人模型(含 STL 资产)
│           └── urdf/robot.urdf
│
└── mjlab_microduck/             # ===== 强化学习训练环境 =====
    ├── pyproject.toml           # 依赖:mjlab, warp-lang, placo
    └── src/mjlab_microduck/
        ├── agents/velocity.pt   # 训练好的 PyTorch 策略权重
        ├── scripts/export_onnx.py  # 导出 ONNX
        └── tasks/
            ├── __init__.py
            ├── mdp.py           # 自定义奖励/观测/课程函数
            └── microduck_velocity_env_cfg.py  # 完整训练配置(PPO)

三、部署端核心架构(microduck/src

1. 控制主循环:Scheduler(50Hz)

scheduler.py 是整个系统的心脏,每个 tick(20ms)做:

  1. 读状态Observer.read_state() → 电机位置/速度/电流 + IMU(加速度/角速度/四元数)
  2. 读输入 :键盘或手柄 → UserInput(激活哪些动作 + 速度指令)
  3. 动作状态机 :遍历已注册的 Move(walk/squat/head),按 INACTIVE → STARTING → ACTIVE → STOPPING 状态调用,每个 Move 向同一个 MotorCommand.target_angles 字典写入目标角
  4. 过流保护:用 BAM 电机模型估算总电流,超过阈值(15A)连续 2 tick 就断扭矩
  5. 下发指令sync_write_goal_position 批量写入目标位置
  6. 频率保持:sleep 补足剩余时间

2. 控制器抽象:ControllerProtocol

controller.py 定义了一个 Protocol 接口,真实硬件RobotController)和仿真器MuJoCoController)都实现同一套接口,所以 scheduler.pymoves/* 的代码在真机和仿真中完全复用。

RobotController 内部:

  • rustypot.Xl330PyController 通过 OpenRB-150 与 14 个 XL330 舵机通信
  • 自动查找 /dev/serial/by-id/usb-ROBOTIS_OpenRB-150_*
  • MOTOR_SIGN / MOTOR_OFFSET 做模型坐标→硬件坐标转换(膝盖有 ±45° offset)
  • 启动 ThreadedIMUReader 后台线程以 50Hz 读 BNO08x I2C

3. 行走策略:WalkMove

moves/walk.py 的核心逻辑:

  • 加载onnxruntime 加载 walk.onnx,从模型 metadata 读取 joint_namesdefault_joint_pos(参考中位)
  • 启动过渡on_start 用 smoothstep 把关节从当前位置平滑插值到策略默认位姿(1.5s),同时把 KP 从 400 降到 125(更柔顺)
  • 每步推理 :构造观测向量 → ONNX 推理 → 输出动作 = default_pose + action * scale
    • 观测 = gyro(3) + projected_gravity(3) + 关节位置偏差(N) + 关节速度(N) + 上一步动作(N) + 速度指令(3) [+ 参考相位(2)]
  • 摔倒检测:body 系下 projected_gravity 的 z 分量 > -0.5 时跳过推理(机器人已倒地)
  • 停止:恢复 KP 到 400,回到 INACTIVE

4. 输入系统

input_source.py 抽象出 InputSource 接口,键盘和手柄各自实现。速度统一在 scale_velocity() 中限幅(前进 0.7 m/s、后退 0.5、侧移 0.3、原地转向 3 rad/s、行进转向 1.5 rad/s)。

5. 安全机制

  • PID 文件锁/tmp/microduck_scheduler.pid 防止两个控制进程抢占总线
  • 过流保护:BAM 模型估算 + 实测 current 双路,断扭矩
  • 摔倒检测:IMU 重力投影判断
  • 停止标志/tmp/microduck_scheduler.stop 可由 stop.py 远程触发

四、训练端(mjlab_microduck

基于 MjLab (MuJoCo 强化学习框架),用 PPO 训练速度跟踪行走策略:

  • 场景 :平地,timestep=0.005snum_envs=1
  • 观测:关节位置/速度、IMU 安装帧下的 projected_gravity 和角速度(带噪声和 0~1 步延迟,模拟真实 BNO080)
  • 动作:关节位置指令(scale=1.0)
  • 奖励:线/角速度跟踪、姿态 upright、空气时间(迈步)、脚滑惩罚、自碰撞惩罚、双脚距离惩罚、动作平滑
  • 课程学习:3000 步后解除"禁止迈步"惩罚并扩大速度范围
  • 网络 :Actor/Critic 均为 (512, 256, 128),ELU 激活,obs 归一化
  • 导出scripts/export_onnx.pyvelocity.pt 转成 walk.onnx,并把 joint_namesdefault_joint_pos 写入模型 metadata

训练时的 IMU 安装四元数 BNO080_MOUNT_QUAT = (0.7071, 0, 0.7071, 0) 与部署端 constants.pyIMU_MOUNT_QUAT 完全一致,保证 sim-to-real 对齐。


五、关键设计亮点

  1. ControllerProtocol 解耦 :真机/仿真共用调度器和动作代码,sim_main.py 只换 controller 和 input source
  2. ONNX metadata 传递参考位姿:训练时的默认关节角直接编码进模型,部署端无需硬编码
  3. 延迟建模 :训练中对 IMU/关节观测加延迟,仿真中也可注入 --delay-* 参数,提高 sim-to-real 鲁棒性
  4. BAM 电机模型过流保护:在不增加总线读取的情况下,用位置误差+速度反推电流,提前于 BMS 跳闸切断
  5. 无头手柄服务:systemd 服务让机器人开机后可直接用手柄启动,手柄连接时自动关 Wi-Fi 提升 2.4GHz 蓝牙稳定性

六、数据流总结

复制代码
IMU(BNO08x) ──I2C──► ThreadedIMUReader ─┐
                                         ├─► Observer.read_state() ─► RobotState
舵机(XL330) ──OpenRB-150──► RobotController ─┘                        │
                                                                       ▼
键盘/手柄 ──► InputSource.read() ─► UserInput ──────► Observation
                                                                       │
                                                                       ▼
                                          Move.step() ─► ONNX(walk.onnx) ─► action
                                                                       │
                                                                       ▼
                                          MotorCommand.target_angles ─► sync_write_goal_position ─► 舵机
相关推荐
czhc11400756631 小时前
有没有「反馈」?—— 伺服加减速 · AI Agent · 五个语法坑
人工智能
合米AI SOP系统1 小时前
3C 电子|手机模组装配工位,合米科技AI SOP 视觉防错破解错漏困局。
人工智能·科技
三小河1 小时前
AI 对话 "打字机" 是怎么实现的?从 SSE 流式、Markdown 组件到 Nginx 防粘连
前端·人工智能·面试
海浪仙人掌1 小时前
速动比率怎么分析?速动比率分析有哪些注意事项?
大数据·数据库·人工智能
武子康1 小时前
SGLang 一加并发就出问题,先查显存还是队列
人工智能·llm·agent
Jared_devin1 小时前
单头、多头 Self-Attention可视化
人工智能·pytorch·深度学习·算法·机器学习·pycharm
七爷数码AI1 小时前
通知播报与作业配音:4款文字转语音工具怎么选?
人工智能·语音识别
天国梦1 小时前
同步课本单词APP怎么选?实测3款才知道真实差距
人工智能·机器学习
昇腾CANN1 小时前
9月14日直播丨人芯对话:昇腾950算力落地算子的编程范式探索
人工智能·昇腾·cann·cann开源