本项目在一台 Ubuntu 上接收 Motive 与 Manus 数据,按固定 60 Hz 物理时间轴对齐、录制 HDF5,并提供实时查看和离线回放。Windows 只运行 Motive;不依赖 Ubuntu2 或另一个 NatNet Git 工作区。
现场启动与收数步骤见 启动与收数据操作手册,包含 ROS 2 域配置、三终端启动、保存退出、质量检查和回放。
mocap 唯一操作入口
pyproject.toml 一个 Python 项目,包含 C++ 扩展构建
pixi.toml / pixi.lock Python 3.12 + RoboStack ROS 2 Jazzy + Fast DDS 锁定环境
src/
mocap_runtime/ 命令分派与统一资源路径
acquisition/ 订阅、对齐、录制与采集网页
natnet_ros/ 内置 NatNet → ROS 2 桥与带原许可证的 SDK Python 样例
manus_bridge/ Manus 原始骨架协议与 ROS 2 发布/订阅
mocap_viewer/ 实时动捕查看器
data_viewer/ 离线回放 HTTP 服务
mocap_tools/ 标定、检查、转换与 MANO 工具
mocap_native/ C++ 批量数值内核的 Python 接口
native/ C++ 内核及 Manus 设备采集器源码
tools/ 内部构建和设备进程管理脚本
config/ 采集配置、地标、物体外参和 offset/<用户>.yaml
calibration/manus/ Manus 每用户左右手 .mcal
assets/ 物体网格与 MANO 模型
vendor/manus/ 随项目管理的专有 SDK,动态库使用 Git LFS
build/manus/ 生成的 rawviz.out,不纳入 Git
tests/ 按组件组织的统一测试入口
docs/ 操作、协议与标定说明
licenses/ 内置依赖来源与原许可证
全部活动 Python 包属于同一个发行包。唯一实时传输是 ROS 2 Jazzy 默认 Fast DDS(rmw_fastrtps_cpp);没有 Router、relay、旧传输适配或别名。根目录中保留的旧项目工作树不属于当前运行入口。
Ubuntu 24.04 x86-64 上安装 Pixi、系统 C++17 编译器和 Git LFS;不需要 sudo 安装 ROS,也不要 pip install rclpy。ROS 包由 robostack-jazzy channel 提供,其余包由 conda-forge / 项目依赖提供。pixi.lock 锁定依赖版本;不要把系统 /opt/ros 或其他 Conda 环境叠加到此环境。在项目根目录执行:
pixi install --locked
./mocap --help./mocap 自动进入根 Pixi 环境,激活 ROS_DISTRO=jazzy 和 RMW_IMPLEMENTATION=rmw_fastrtps_cpp。实时传输拒绝其他 ROS 发行版或 RMW。./mocap --help 本身只需要系统 Python,不导入 ROS;离线文件读取/回放不创建 ROS 节点。
所有需要通信的终端使用同一 ROS_DOMAIN_ID(未设置时 0),也可对实时命令指定 --domain-id ID;采集 YAML 使用 ros_domain_id: null 继承环境。域只是发现隔离,不是访问控制、认证或加密。跨机 DDS 需要可达网络、UDP discovery/data 通路及兼容 QoS;详见 网络说明。
安装会编译 C++ 批量四元数插值扩展,需要系统 C++17 编译器(Ubuntu 上的 g++)。原生扩展不可用时直接报错,不悄悄退回另一套计算实现。
Manus SDK 已纳入 vendor/manus/:头文件由 Git 管理,动态库由 Git LFS 管理。
克隆后先安装 Git LFS(Ubuntu 可通过系统包管理器安装 git-lfs),在根目录取回动态库:
git lfs install --local
git lfs pull --include="vendor/manus/lib/libManusSDK_Integrated.so" --exclude=""然后构建:
./mocap build manus生成 build/manus/rawviz.out。采集器通过显式校准目录加载 calibration/manus/,不再要求校准文件与可执行程序相邻。SDK 缺失或动态库仍为 LFS 指针时构建会明确失败。下载源码 ZIP 不保证包含 LFS 实体,建议使用 Git 克隆并执行上述拉取命令。SDK 原权利归属不变,非商业使用不自动授予再分发权。
Windows Motive:Local Interface=169.254.213.247,Unicast,开启 Broadcast Frame Data。本机地址为 169.254.1.1 和 192.168.1.151。详见 网络拓扑。
在三个独立终端运行;每个终端先 export ROS_DOMAIN_ID=0(或同一个选定域)。以下用户名以已有标定的 shd 为例:
./mocap publish mocap
./mocap publish manus --user shd
./mocap record --object hammer --user shd采集网页默认 http://127.0.0.1:8081 。键盘 r 开始、s 保存、d 丢弃、q 退出。退出前先保存;退出会丢弃未保存的当前 take。端口被占用时拒绝启动,不自动结束其他进程。
默认数据根目录:/home/current/Documents/MocapData,按 YYYYMMDD/ 保存。采集配置位于 config/acquisition.yaml,自定义配置用 --config;相邻 offset/<用户>.yaml 的加载规则保留。不会迁移或改写旧数据。
终端只输出操作、启动和错误事件。网页帧率按最近两秒真实接收量连续滑动统计;数字稳定不等于断流。录制/发布仍逐帧处理全部 60 Hz 对齐帧,网页绘制与状态更新使用独立节拍。
./mocap publish mocap --show
./mocap view live
./mocap view recordings
./mocap view recordings --root /path/to/YYYYMMDD
./mocap view manus --user shd
./mocap topics
./mocap subscribe mocap
./mocap subscribe manus
./mocap landmarks
./mocap calibrate wrist left --user shd
./mocap calibrate wrist right --user shd
./mocap calibrate object hammer --gl-mm X Y Z --go-deg P Y R
./mocap track-rigid --help
./mocap calibrate tcp --help
./mocap inspect /path/to/take.h5
./mocap replay --help
./mocap mano-beta --help
./mocap object-offset --help
./mocap check-port 8081实时手套查看与手套发布都占用 dongle,不能同时启动。Python 叶子命令的 --help 由各组件解释;原有数据格式与工具参数保留。专用 HDF5 骨架/MANO 查看器使用 ./mocap view hdf5 --help。
无需启动或安装任何消息路由服务。升级前应由操作者正常停止自己维护的旧传输进程/服务;项目不自动修改系统服务或结束已有采集进程。
pixi run test -q
# 包含真实 DDS 通信测试;173 必须与现场域不同
ROS_DOMAIN_ID=0 MOCAP_TEST_ROS_DOMAIN_ID=173 \
ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST pixi run test -q网络验证必须在与现场不同的域、仅本机 discovery 范围下进行;不要向现场域发布伪造帧。测试覆盖范围与结果以当次执行为准。
- JSON 数据内容、HDF5 datasets、60 Hz 对齐及标定数值保持;新对齐消息/录制元数据用整数
ros_domain_id代替旧传输标识。 - ROS 主题为绝对路径,JSON 放在
std_msgs/msg/String.data;可选 Manus 二进制使用独立/binary后缀主题和std_msgs/msg/UInt8MultiArray,不混用类型。 - 实时流为 RELIABLE / KEEP_LAST(10) / VOLATILE;刚体名字和左右骨架边元数据为 RELIABLE / KEEP_LAST(1) / TRANSIENT_LOCAL,后加入消费者须同样请求 TRANSIENT_LOCAL。
- C++ 只承担批量数值热点;配置、流程、状态机和网页仍由 Python 管理。
- HDF5 格式、消费接口、刚体接口、手腕标定。
- 内置不等于重新授权:NaturalPoint SDK 的原版权和 EULA 保留在源码及
licenses/。公开分发前须确认授权;Manus SDK 和 MANO 资产另受各自许可约束。来源记录见licenses/SOURCE_PROVENANCE.txt。
- 已安装并锁定 Pixi Jazzy 环境,实际 RMW 为
rmw_fastrtps_cpp。 - 启用隔离域 DDS 测试:291 passed;24 条第三方弃用警告来自 MANO/chumpy 的 SciPy 导入及 Lark,未屏蔽。
- 跨进程实测 JSON、二进制字节保真、晚订阅元数据保留、不同 domain 隔离及 ROS graph 消息类型。
- 实时 Viser 浏览器接收隔离合成流,约 59 Hz,显示无解码错误或丢帧。
- 通过真实录制 CLI 开始/保存/退出:隔离合成双手与 hammer 流生成 201 帧、3.33 秒、60 Hz HDF5,严格检查通过;双手、物体及全局有效率均为 100%,录制域属性为 174。
- 22 个叶子命令帮助入口在项目外目录执行成功,6 个 Shell 入口通过语法检查。
- 上述验证未占用 dongle、连接 Motive 或向现场域注入数据;真实设备接入仍需现场验证。
以下仅保留旧版本性能与运行记录,不是当前部署步骤,也不能证明本次 ROS 迁移已通过同样验证。旧环境和 Router 已退出活动架构。
- 合并嵌套 Python 项目、Pixi 环境和独立 NatNet 源码;统一命令、资源路径和测试布局。
- 移除旧 Shell 入口与环境借用;Manus 原生程序及 SDK 分离到
build/与vendor/。 - 保留原运行版本 Viser 1.0.30;此轮不是第三方依赖升级。
- C++ 批量 SLERP、刚体索引与固定拓扑缓存;录制节拍和网页绘制节拍解耦。
本机同一环境对照基准(2026-09-13;不是整机 CPU 占用承诺):
| 场景 | 原实现中位耗时 | v2 中位耗时 | 加速 |
|---|---|---|---|
| 25 节点四元数插值 | 224.295 µs/批 | 1.700 µs/批 | 131.93× |
| 50 节点四元数插值 | 447.996 µs/批 | 2.861 µs/批 | 156.57× |
| 完整对齐帧,含缓存优化 | 833.372 µs/帧 | 357.803 µs/帧 | 2.33× |
2048 行、7 个插值系数、3 种输入布局/类型数值对照的最大绝对误差为 0。 正常及缺失流各 90 帧逐字段对照一致。确定性回归覆盖调度中断后完整保留 60 Hz 样本。
统一测试:294 passed。剩余 22 条弃用警告来自旧 MANO pickle / chumpy 的 SciPy 导入, 没有通过屏蔽警告掩盖这些依赖限制。
实际入口验证在私有 loopback Router 和临时数据目录进行,不向正在运行的 Router 注入数据:网页开始/保存生成 204 帧、3.38 秒、60 Hz 的 HDF5;strict 检查通过, 双手与 hammer 有效率均为 100%;断流后的状态、录制时长、丢弃按钮和显示开关仍响应; KEYPOINTS 与 MANO 离线播放均完成加载并推进时间轴。所有 25 个统一命令/子命令的 帮助入口在项目外目录执行成功。Manus 原生程序完成构建、SDK 动态链接与标定缺失 失败路径验证;未接管现场 dongle 或启动第二个 Motive publisher。