robonix.robot.agilex.piper_linkerhand_mujoco

robot v0.1.0

AgileX Piper 6-DOF arm + LinkerHand O6 dexterous hand (right), MuJoCo simulation body package for Robonix. The skill drives the sim process via its HTTP API (control/state/sim endpoints).

README robot-agilex-piper_with_linkerhand_mujoco@main

Piper + LinkerHand O6 MuJoCo 仿真本体接入 Robonix

按 Robonix《接入 MuJoCo 仿真本体》指南 将 piper_linker_sim/ (Piper 6 轴臂 + LinkerHand O6 右灵巧手) 接入 Robonix。

场景是一个工作台式抓放单元: 台面上放 3 个任务物体 (红色方块 / 绿色长方体 / 蓝色圆柱) 和 3 处放置区标记 (左/中/右), 两台相机看着工作区。通过 rbnx chat 可以直接问"你有哪些技能"、"桌面上有什么", 并说"抓起红色方块"、"放到右边"。

双层架构(ROS 2 走 Docker Humble,本机是 Ubuntu 24.04):

浏览器 viewer ← MJPEG │ piper_linker_sim (原生, Python 3.13, :8010)
                     │  ├── manipulation.py  逆解 + 抓取/放置状态机
                     │  └── /objects /camera/<n>/frame.jpg /manipulation/*
                     │ WebSocket 客户端 (bridge_client.py, 30Hz state)
                     ▼ ws://127.0.0.1:8775  (8765 被本机其它项目占用)
   robonix_ros_wyh 容器 (ROS 2 Humble, ROS_DOMAIN_ID=23)
   ├── bridge_node.py      sim/bridge_node.py → /joint_states /arm/end_pose /clock
   │                        /arm/joint_command /arm/pos_command /sim/reset
   │                        /sim/task_objects
   └── robot_state_publisher → /tf (urdf/piper_linker_o6_right.urdf 全树)
                     ▲
   rbnx boot: skill piper_linker + primitive piper_linker_arm

用户可调用的能力

说什么 走哪个 capability 类型
你有哪些技能 / 你能做什么 robonix/skill/manipulation/list_skills 同步
桌面上有什么 robonix/skill/manipulation/scene_query 同步
抓起红色方块 robonix/skill/manipulation/pick_object 异步
放到右边 robonix/skill/manipulation/place_object 异步
握拳 / 前伸 / 把 joint2 转到 2 弧度 / 查状态 / 复位 hand_gesture / arm_pose / set_joint / sim_state / sim_reset 同步

pick_object 与 place_object 各自注册 <id>/status 和 <id>/cancel, Executor 据此把它们判定为异步能力: 调用立即返回 run_id, 后台跑完整段运动, 每 2s 轮询 状态直到终态。一次完整"抓起来→放到右边"约 10s 仿真时间。

详细能力说明、抓取实现细节和已知边界见 skills/piper_linker/CAPABILITY.md。

目录结构

<仓库根>/                          # 容器挂载点 /workspace/mujoco
├── robonix_manifest.yaml        # 部署清单 (system + primitive + skill)
├── soma.yaml                    # 本体语义结构 (arm + dexterous_hand + 9 个能力)
├── start.sh / stop.sh / build.sh
├── .env.example                 # VLM 配置模板
├── LICENSE                      # MulanPSL-2.0
├── LICENSES/                    # AgileX MIT / LinkerHand Apache-2.0
├── UPSTREAM.md                  # 上游 commit、许可、本仓库分发了哪些文件
├── sim/
│   └── bridge_node.py           # WebSocket↔ROS 2 bridge (参考包裁剪: 仅臂)
├── ros/
│   └── run_bridge.sh            # 容器内启动 bridge + robot_state_publisher
├── urdf/
│   ├── make_urdf.py             # 合并 URDF 生成脚本 (Piper 去夹爪 + 手挂 link6+17.5mm)
│   └── piper_linker_o6_right.urdf
├── primitives/
│   ├── arm/                     # piper_linker_arm 原语 (ROS topic 能力)
│   └── common/                  # 参考包的通用 provider 模块
├── scripts/                     # primitive 编排 (build/start/stop, docker exec 进容器)
├── tests/                       # 确定性集成场景 (Robonix fake VLM 驱动, 见 tests/README.md)
├── skills/
│   └── piper_linker/            # 仿真本体 skill (MCP ↔ 仿真 HTTP API)
│       ├── capabilities/*.toml  # 14 个 contract 声明
│       ├── capabilities/lib/…   # srv IDL
│       └── piper_linker/main.py
└── piper_linker_sim/            # MuJoCo 仿真本体 (场景 + 机器人模型 + HTTP API)
    ├── scene.xml                # 台面 + 3 个任务物体 + 3 个放置区 + 2 相机
    ├── piper/                   # Piper MJCF + 84 个网格 (AgileX 上游, 未改)
    ├── linkerhand_o6_right/     # O6 右手 MJCF + 12 个网格
    ├── server.py                # HTTP API + bridge 客户端 + 渲染
    ├── manipulation.py          # 抓放状态机 + IK
    ├── tools/                   # 回归/标定工具 (pick_place_matrix 等)
    ├── PROVENANCE.md            # 逐文件溯源与修改清单
    └── README.md

reference/(syswonder 参考包副本)与上游 clone agx_arm_sim/、linkerhand-urdf/ 仅保留在本地工作目录,已由 .gitignore 排除,见 UPSTREAM.md。

使用

cd <本仓库根目录>
cp .env.example .env && vim .env      # 填 VLM_API_KEY
bash build.sh                          # rbnx build (codegen, 生成 MCP 类型)
bash start.sh                          # 容器 bridge → 仿真 → rbnx boot
# 另开终端
rbnx chat

rbnx chat 示例指令:

  • "你有哪些技能"
  • "桌面上有什么" / "桌子上有几个东西"
  • "把红色方块抓起来" / "抓起蓝色圆柱"
  • "放到右边" / "放到左边" / "放到中间"
  • "张开手掌" / "握拳" / "比个 OK" / "点赞"
  • "机械臂前伸" / "回到初始姿态" / "把 joint2 转到 2 弧度"
  • "查询仿真状态" / "复位仿真"

仿真画面: 浏览器打开 http://<本机IP>:8010 (MJPEG viewer)。

场景与相机

台面正好在 z=0, 与机械臂底座同一平面(臂坐在台面上,不是站在地上); 范围 x∈[-0.12,0.78] y∈[-0.36,0.36]。台面上分两排:

  • 3 个任务物体在 x=0.555 一排:y=-0.255 / -0.075 / +0.105,间距 18cm; 尺寸 5×5×9cm(蓝色圆柱 Ø5×9cm),质量 0.05~0.06kg;
  • 3 个放置区在 x=0.40 一排:y=+0.20 / 0.00 / -0.20,间距 20cm; 标记是 6×6cm 的纯视觉几何 (contype=0),不参与物理。

尺寸、间距、位置都是照着这只手定的(平抓姿态下张开的拇指会向掌侧扫出约 12cm, 排得太密会把旁边的物体扫倒),推导过程见 piper_linker_sim/README.md。

相机 位置 用途
table_cam 台面左前上方, 注视台面中心 工作区俯视, 桌面物体一览
front_cam 台面正前方 正面视角
curl -o /tmp/table.jpg http://127.0.0.1:8010/camera/table_cam/frame.jpg
curl http://127.0.0.1:8010/camera/table_cam/info   # 内参 K + 外参

真机上这两个相机对应 robonix/primitive/camera/{rgb,snapshot,intrinsics,extrinsics}; 本部署暂未接 ROS 相机 primitive (见"已知边界")。

ROS 2 链路验证 (已通过)

# 容器内查看话题
docker exec robonix_ros_wyh bash -c 'source /opt/ros/humble/setup.bash && \
  export ROS_DOMAIN_ID=23 && ros2 topic list'
# 下发关节命令 (12 驱动关节按名映射, 联动关节自动跟随)
docker exec robonix_ros_wyh bash -c 'source /opt/ros/humble/setup.bash && \
  export ROS_DOMAIN_ID=23 && ros2 topic pub --rate 20 /arm/joint_command \
  sensor_msgs/msg/JointState "{name: [joint2, rh_index_mcp_pitch], position: [2.4, 1.2]}"'
  • /joint_states: 17 关节 (6 臂 + 11 手) @30Hz, sim 时间戳
  • /arm/joint_command → 仿真执行器 (验证: joint2→2.4, 食指→1.2, DIP=0.89×MCP 联动)
  • /tf: base_link→…→rh_hand_base_link→手指 全树

关节映射 (ctrl 数组, 12 通道)

下标 通道 限位 (rad)
0-5 joint1..joint6 (臂) 见 MJCF piper.xml
6 rh_thumb_cmc_yaw (拇指旋转) 0 – 1.36
7 rh_thumb_cmc_pitch (拇指弯曲) 0 – 0.58
8-11 rh_{index,middle,ring,pinky}_mcp_pitch 0 – 1.6

手部 0=张开, 上限=最大弯曲; DIP/IP 联动由仿真内 equality 约束实现 (拇指 1.86×, 四指 0.89×)。 qpos 顺序(38): joint1-6, 手 11 关节, 之后是 3 个任务物体的 freejoint (7 维/个)。

URDF mesh 包位置

URDF 使用 package:// 引用网格 (robot_state_publisher 只需运动学, 不加载网格):

  • package://piper_description/ → piper_linker_sim/piper/
  • package://linkerhand_o6_right/ → linkerhand-urdf/O6/right/(该 clone 未随仓库分发,见 UPSTREAM.md)

重新生成 URDF: python3 urdf/make_urdf.py (默认右手; 加 --side left 可生成左手合并 URDF)

端到端验证

两条路都跑通了:

真实 VLM(rbnx ask,与 rbnx chat 同一条 gRPC 链路):

用户说法 结果
你有哪些技能 ✅ 自己去读了 CAPABILITY.md,返回 8 项技能
桌面上有什么 ✅ 3 个物体的名称/形状/尺寸/坐标
把红色方块放到右边 ✅ pick → place → 又用 scene_query 复核落点,报"已完成"

真值坐标以当前场景为准:上面这次记录产生于早期布局,坐标已失效。 可复现的核对方式是跑 tools/pick_place_matrix.py,它直接比对落点与放置区中心的 水平误差(最近一次实跑见下)。

确定性 fake VLM:tests/ 下的三个场景(跑法见 tests/README.md),用于把 VLM 这一层排除掉、只验证 skill → 仿真链路。另有 3 物体 × 3 放置区的全遍历:tools/pick_place_matrix.py。最近一次实跑(当前布局):9/9 成功, 落点误差 1.1~2.1cm,单次任务 26.7~36.1s 仿真时间。

已知边界 (下一步)

  • VLM 要选对(.env 里的 VLM_*)。踩过的三个坑,按报错对号入座:
  • couldn't produce a valid robot plan after retrying once + 模型回复"我是 Kiro…" → 网关把请求转到了带自带人设的后端(本机 api.ikuncode.cc 的 claude-opus-* 就是这套),系统提示被顶掉。换网关或换模型。
  • VLM stream error: open VLM chat stream → 传输层失败,不是协议问题。 先 curl 一下 ${VLM_BASE_URL}/chat/completions 看端点通不通。
  • 推理模型别设 max_tokens:deepseek-flash 是推理模型,token 预算会先被 reasoning 吃光,content 返回空字符串,Pilot 拿到空回复。Robonix 不传 max_tokens,所以直接用它没问题;自己写探针时容易踩。
  • 本机验证通过的配置:VLM_BASE_URL=https://api.deepseek.com/v1 + VLM_MODEL=deepseek-flash(或 deepseek-chat)。 备选:CC Switch 代理 http://10.29.0.196:15721/v1 + gpt-6-astra (该代理只声明这一个模型,实测也能出合规 RTDL)。
  • 一个 provider 只能有一个异步能力: Executor 靠 <contract_id>/status + /cancel 判定异步,而 MCP 工具名取 contract_id 的最后一段,所以同一个 skill 里两个异步能力的 status 工具同名。这里 pick/place 各注册一份、实现共用 (任务号在仿真侧全局),行为一致;要接第三个异步能力就得拆成独立 provider。
  • build 需要 grpcio-tools: rbnx codegen 生成 Python proto 桩代码时要求 PATH 里的 python3 能 import grpc_tools。build.sh 会自动在 仓库根 .venv/bin/python3(其次 $HOME/miniconda3/bin/python3)等位置找一个装了的; 若都没有会跳过桩代码生成。
  • 相机只到 HTTP, 未接 ROS 相机 primitive: 仿真侧有内参/外参/JPEG 快照, 但没有发布 sensor_msgs/Image。要接 Robonix 的 system/scene 语义地图服务, 需要在 bridge 里加一路图像发布 + 起 scene 容器 (重, 需 GPU + YOLO/MobileSAM)。 当前"桌面上有什么"由 skill 直接返回仿真真值, 比视觉更准, 但不走 scene 服务。
  • 抓持是真实的手指摩擦夹持,没有吸附或约束兜底: 指关节位置伺服合拢时被物体挡住、 停在半路压出法向力,靠摩擦把物体提起来;物理解算与碰撞检测全程开启,抓不住就是真失败。 判定阈值(接触点数、法向力、抬起跟随)见 CAPABILITY.md 的"抓取是怎么实现的"。
  • 容器重建流程: 镜像 robonix-ros:humble-wyh 已含全部依赖 (commit 持久化), docker run -d --name robonix_ros_wyh --net host \ -v "$PWD:/workspace/mujoco" -v <robonix 源码路径>/pylib:/robonix/pylib:ro \ robonix-ros:humble-wyh sleep infinity
  • 完整参考包克隆 (GitHub 网络) 失败过一次, 关键文件已存于本地 reference/(该目录 未随仓库分发,见 UPSTREAM.md)

许可与来源

  • 本项目自身代码:MulanPSL-2.0,见 LICENSE。
  • 随仓库分发的第三方模型数据(AgileX Piper 的网格与 MJCF、LinkerHand O6 的网格): 许可文本在 LICENSES/;上游 commit、逐文件字节级校验结果、以及本仓库 实际分发了哪些文件,见 UPSTREAM.md;逐文件修改清单见 piper_linker_sim/PROVENANCE.md。
  • Robonix catalog 身份:robonix.robot.agilex.piper_linkerhand_mujoco (声明在 robonix_manifest.yaml 的 catalog: 块)。

⚠️ 上游 agx_arm_sim 只在 README 里写了 "MIT License" 而没有 LICENSE 文件; LICENSES/AgileX-MIT.txt 的版权行取自 AgileX 同厂商仓库 piper_sdk。如需权威 署名请向 AgileX 确认,详见 UPSTREAM.md。