数据可视化与回放(Playback)¶
读取 ubt_sim/dataset/{walker_s2,tienkung_pro,walker_c1,tienkung_dex}/<时间戳>/trajectory.hdf5,支持两种模式:
| 模式 | 作用 | 依赖 |
|---|---|---|
预览(--mode preview) |
Rerun 查看采集的相机画面 + 关节/手/夹爪曲线,时间轴 scrub/逐帧步进/循环为内置功能 | rerun-sdk(控制 Python) |
控制(--mode control) |
把录制动作按原始频率直发到仿真或真机执行 | ROS2(rclpy + 机器人消息包) |
入口脚本位于 ubt_sim/teleoperation/tools/:
playback_walker_s2.py- Walker S2 EDU 探索者(17 身体关节 + 7+7 V4 手 + 2 夹爪 + 4 相机)playback_tienkung_pro.py- 天工行者(7+7 臂 + 6+6 手 + 1 相机含深度)playback_walker_c1.py- Walker C1 EDU 共创者(31 身体关节 + 6+6 手 + 1 相机)playback_tienkung_dex.py- 天工行者 Dex(右臂 7 + 右手 6/13 + 1 相机含深度)
架构:共用核心 playback/common.py(HDF5 加载、节奏、CLI、Rerun 预览)+ 机器人适配层 playback/robots/(schema + ROS2 发布器 + 首帧对齐),各机型薄入口脚本在 tools/ 层。
环境准备(容器内)¶
# rerun-sdk 已加入 Dockerfile 控制环境;旧容器免重建安装:
# (锁 0.23.0:0.24+ 要求 numpy>=2,与本容器 numpy<2 约束冲突)
docker exec -it ubt-sim /usr/bin/python3 -m pip install "numpy<2" "rerun-sdk==0.23.0" -i https://pypi.tuna.tsinghua.edu.cn/simple
# 控制模式额外需要(walker 需要 SDK 消息包,天工仅需 ROS2):
source /opt/ros/humble/setup.bash
source /opt/ubt_sim/walker_sdk_ros2_msgs/install/setup.bash # 仅 walker
# 统一用系统 Python:
/usr/bin/python3
预览模式¶
⚠️ 容器内请用 web viewer(浏览器):Rerun 原生 viewer 是 wgpu/egui 应用,容器里只有 NVIDIA vendor GL(无 Mesa、无 vulkan surface),wgpu 拿不到 adapter 会静默启动失败。本地弹窗模式仅在有正常 GL/Vulkan 窗口环境的主机上可用。
cd /ubt_sim
# ① 浏览器预览(推荐,容器内可用)
python3 teleoperation/tools/playback_walker_s2.py \
--episode dataset/walker_s2/1786681892 --mode preview --web-port 9090
# ② 保存 .rrd(无 viewer),拷贝到宿主机后用 rerun viewer 打开
python3 teleoperation/tools/playback_walker_s2.py \
--episode dataset/walker_s2/1786681892 --mode preview --save-rrd /tmp/walker_ep.rrd
# ③ 本地弹窗(仅 GPU 窗口环境可用:工作站/宿主机直接跑时)
python3 teleoperation/tools/playback_walker_s2.py \
--episode dataset/walker_s2/1786681892 --mode preview
- 其它机型同理,脚本换成
playback_tienkung_pro.py/playback_walker_c1.py/playback_tienkung_dex.py。 - 启动 web viewer 后脚本会打印完整 URL(形如
http://localhost:9090/?url=rerun%2Bhttp%3A%2F%2F127.0.0.1%3A9876%2Fproxy),照它打开即可。⚠️ 末尾?url=参数是数据源地址,不能省。远程浏览器需同时转发 9090 与 9876 两个端口(ssh -L 9090:localhost:9090 -L 9876:localhost:9876)。 --episode缺省 =dataset/<robot>/下最新(时间戳目录名最大)episode;--max-frames N只记录前 N 帧。- Rerun 面板:
cameras/color/<相机名>(图像)、cameras/depth/...(天工深度)、action/<组>/<通道名>(指令曲线)、observation|puppet/...(观测曲线),均随frame_index/timestamp两条时间轴同步。

控制模式¶
回放直发录制帧原始值(最忠实)。发布的 ROS2 话题:
- Walker S2 EDU 探索者:17 关节
RobotCommand(MODE_POSITION)@/mc/sdk/robot_command+ 双手JointCommand(mode=5)+ 双夹爪GripCmd - 天工行者:
CmdSetMotorPosition(14 电机)@/arm/cmd_pos+ 双手JointState - Walker C1 EDU 共创者:
RobotCommand(MODE_POSITION)@/mc/sdk/robot_command+ 双手JointCommand(mode=5) - 天工行者 Dex:
ArmCtrl@/arm/cmd(+/head/cmd、/waist/cmd)+ 右手angle_set/set_motor_multi(按手型)
仿真(bridge 转发)与真机话题完全一致,同一脚本通吃,仅 ROS_DOMAIN_ID 不同。
# 第一步永远先 dry-run(不初始化 ROS2、不发布,只打印每帧摘要)
python3 teleoperation/tools/playback_walker_s2.py \
--episode dataset/walker_s2/1786681892 --mode control --dry-run --end 3
# 回放(仿真与真机同命令,靠 ROS_DOMAIN_ID 区分:真机 0 / 仿真 146,以实际为准)
# 仿真:先 start_sim.sh 起仿真+桥接,确认 echo $ROS_DOMAIN_ID 与桥接一致
python3 teleoperation/tools/playback_walker_s2.py \
--episode dataset/walker_s2/1786681892 --mode control --align-first --end 200
# 真机:ROS_DOMAIN_ID=0 后直接同一条命令
ROS_DOMAIN_ID=0 python3 teleoperation/tools/playback_tienkung_pro.py \
--episode dataset/tienkung_pro/1786638182 --mode control --align-first
常用参数(--help 查看全部):
| 参数 | 默认 | 说明 |
|---|---|---|
--start/--end |
0/末帧 |
帧索引或 "5s"(第 5 秒);--end 不含末帧 |
--rate |
数据集 fps | 发布频率(walker 仿真桥接身体限 100Hz,>100 会被静默限速) |
--loop |
关 | 循环播放直到 Ctrl-C |
--align-first |
关 | 播放前平滑移动到首帧位姿(walker: quintic 插值 3s;天工: 关节空间 ramp ~2s) |
--dry-run |
关 | 只打印不发布 |
--interp |
关 | 【walker】记录帧间线性插值到 --rate(更平滑,偏离原始记录) |
--spd/--cur |
0.2/5.0 |
【天工】电机默认速度/电流 |
--arm-clamp-lo/hi |
±2.5 |
【天工】臂限位(teleoperation 侧无臂限位常量,保守假设) |
安全须知¶
- 限位裁剪默认开启(walker 用硬件限位表,天工手 [0,1]/臂保守限位);数据含 NaN/inf 直接拒绝。
--align-first在回放前先对齐首帧位姿,避免从任意当前位姿直接跳变。- Ctrl-C 停止后机器人保持最后指令(仿真侧 HoldTargetManager 保持;真机需自行复位)。
- 回放前务必先
--dry-run,并确认ROS_DOMAIN_ID与目标一致、机器人处于安全位置。