Changelog 2026 08 - NUSNiuMu/insight-capture-dashboard GitHub Wiki

Changelog 2026-08

新条目加在顶部。每条包含:做了什么、为什么、怎么验证的。


2026-08-28 · 修正录制期丢帧 QC 误报

提交:32e79a8(main)

  • 明确 Dashboard 常驻图像订阅与原生 rosbag2 recorder 是两套独立 DDS reader;前者的 header gap 只作为 Dashboard 调度诊断,不再触发“持续丢帧”语音,也不再把实际完整的 Take 标记为 suspect。
  • 为未来真正来自 recorder 的实时完整性指标保留告警入口,但改为只有缺帧计数持续增长 才满足持续异常;一次历史累计缺口不会在三秒后被误判为持续丢帧。
  • 验证:Take 61–64 的 MCAP 深度检查均通过,三路图像约 30 Hz 且实际缺帧为 0;相关采集、 录制、任务和语音回归测试 96 项通过。Dashboard 在未录制状态下重启后 health 正常、 Preflight 通过,USB 仍使用 /dev/sda1 且无 fallback。

2026-08-27 · UMI Cube Marker 融合 Insight3 全局定位

提交:ea2828d(main)

  • Insight9 彩色相机以 10 Hz 检测两只夹爪 cube:Insight3 A 使用 ID 8–11, Insight3 B 使用 ID 2–5;按 UMI 70 mm cube 和 60 mm marker 的实测面布局联合 求解刚体 PnP,并通过同时间戳的 Insight9 全局 Pose 与 Insight3 VIO 生成 T_map_odom 绝对观测。
  • Cube marker 使用独立的 3/5 帧共识,再与自然地图重定位共同更新 Insight3 的六自由度 误差状态 EKF;小修正平滑吸收,达到 150 mm 或 10 度的已确认修正执行 hard relocalization。Jetson NX 当前 A/B 平移外参分别为 [0,-58,90] mm 与 [0,-53,93] mm,生产 profile 已设置 apply_corrections=true。
  • 支持现场实际发布的 Insight9 CompressedImage,状态消息公开 marker IDs、角点、内点、 重投影误差、观测/更新计数和修正模式;新增只读 rosbag shadow 回放工具,即使生产配置 已启用纠偏也不会修改在线 Pose。
  • 验证:runtime 测试 58 项全部通过,Python 编译、Compose 配置和差异检查通过;Take 54 回放 A/B 分别得到 132/148 个有效 PnP、重投影中位 0.87/0.81 px。B 局部相对误差中位 30.1 mm / 2.59 度;A 为 60.0 mm / 5.31 度且仍存在平面 PnP 错误分支,现场需持续监控 hard_relocalizations,不能把重投影误差当作绝对精度真值。

2026-08-26 · 撤回 RViz 运行时验证改动

提交:a79b30c(main)

  • 按现场决定完整撤回 eb52335 和 7a3e0e4,删除动态调试 topic service、30 Hz Pose 图层及验证频率调整,代码树恢复到 964e068 的状态。
  • mapper/localizer 已在未录制状态下重建并加载回退代码;RViz 验证窗口保持关闭。
  • 验证:回退后的 runtime 测试 51 项全部通过,Python 编译和脚本语法检查通过;ROS graph 中不再存在动态调试 service 或 RViz Path topic,后台建图服务保持在线。

2026-08-25 · 开始校准前检查三台相机实时数据

提交:964e068(main)

  • POST /api/mapping/reset 在真正清空和启动地图前,固定检查 Insight3 A、Insight3 B、 Insight9 三台相机是否都已配置,并且各自有 2 秒内的新鲜图像与原生 vio_100hz 数据; 任一缺失即返回 409,不会触发建图或重定位 reset。
  • 失败响应会逐台指出缺少图像、VIO 或配置,并转换为“右手相机、左手相机、头部相机”的 中文语音提示;离线语音会直接播报该原因,3D 页面也显示同一条错误,不再出现校准一直 没结果但操作员不知道相机掉线的情况。
  • 验证:Mapping route、相机门禁、语音错误透传及相关 runtime 测试共 72 项通过;前端重新 构建成功。Dashboard 热加载后现场三路图像均约 30 FPS,三路 VIO age 均小于 0.01 秒; Playwright 加载 3D 页面返回 HTTP 200、校准按钮存在且控制台无错误。全仓 238 项中 236 项通过,另 2 项为既有前端中文和脚本白名单结构检查问题。

2026-08-24 · Insight9 增加后台双目局部 BA

提交:4c9f645(main)

  • Insight9 关键帧新增保留左右目 2D 观测,通过 SuperPoint 描述子互检和世界坐标 门限建立跨帧重复地标;独立后台线程在有界滑窗内联合优化关键帧 Pose 与统一 3D 地标,降低逐帧三角化和 VIO 误差造成的重复坐标。
  • 固定窗口首帧并保留相邻 Pose 先验;会话 reset、并发回环优化、重投影未改善或 Pose/地标修正超过门限时拒绝结果。求解期间新增的轨迹尾段继承窗口末端刚体修正, 应用后原子重建地图并更新校准关键帧,不阻塞 SuperGlue mapping worker。
  • 默认使用 12 帧窗口,每 10 个关键帧调度,每帧 200 个高置信点、最多 250 个地标和 10 次迭代;状态消息新增 BA 运行次数、拒绝原因、前后 RMSE、耗时和最大修正量。
  • 验证:宿主 runtime 测试 51 项全部通过,全仓 235 项中 233 项通过,另 2 项为既有 前端中文和脚本白名单问题;容器标准 ROS entrypoint 成功导入 mapper,容器内 3 项 合成 BA 测试全部通过。现场服务未重启,未中断当前采集栈。

2026-08-21 · Mapping 核心代码补充中文阅读注释

提交:1930073(main)

  • 为 insight_capture/runtime/mapping/ 全部 20 个 Python 模块补充中文模块说明、 docstring 和关键行内注释,覆盖坐标系约定、线程边界、双目三角化、地标确认、PnP、 多帧共识、VIO 连续性、EKF、位姿图以及 TensorRT/IPC 数据链。
  • 明确区分生产稀疏建图、构建期 ONNX 导出、内部稠密验证和兼容导出代码,重点说明 当前是“位姿图优化 + 地标重融合”而非完整 BA;本次没有修改任何运行逻辑或参数。
  • 验证:Mapping 全目录 compileall 通过;全局定位、VIO 连续性和 Dashboard Mapping 状态桥相关测试共 14 项通过;暂存差异 whitespace 检查通过。

2026-08-21 · Sessions 支持完整任务集管理

提交:0ca7c18(main)

  • Sessions 页面新增任务的新建、编辑、进入/切换和结束操作;Task ID 创建后固定,避免已录 raw bag 与 Take 元数据失去目录归属。录制过程中禁止修改或切换任务。
  • 前端新建或编辑的任务定义持久化到 outputs/results/sessions/<task_id>/task.json,与该任务的 session.json 和 takes/ 放在同一独立目录;内置配置仍作为初始任务,发布镜像升级不会覆盖用户任务。
  • 没有当前任务时,网页和语音录制入口均返回 409,不会产生非任务 bag;直接点击 Recorder 的 Start capture 始终归入当前任务的 <task_id>/ raw 目录。
  • 验证:相关任务、录制、回放与语音测试共 104 项通过;真机 API 实测“结束任务 → 录制被 拒绝 → 重新进入任务”,原 Take 1 保留且下一条仍为 Take 2;Playwright 检查新建/编辑 弹窗和 Recorder 当前任务提示,页面无控制台错误。

2026-08-21 · 任务集持久化与首次回放轨迹修复

提交:ab1a06b(main)

  • 修复 prepared playback 首次点击时,首帧轨迹 snapshot 会被后端激活期间的实时 WebSocket Pose 覆盖、后续 delta 因缺少起始序列而被丢弃的问题;现在先完成后端激活, 再切换播放态并注入首帧 snapshot,准备期间也不再接收实时 Pose 覆盖。
  • 3D 页面删除 OBS mode 和 Set station 控件、OBS 降载分支,以及设置检测位的 HTTP 与 离线语音入口。
  • Task Set 改为稳定的 task_id 目录,不再按日期创建 Session;Sessions 页面可选择并进入 任务集,退出再进入继续原 Take 编号。普通录制写入当前存储根目录的 <task_id>/ 子目录, 断电恢复也保留该归属;升级时只迁移当前 Session 的轻量元数据,raw bag 不移动。
  • 验证:相关 runtime、录制、prepared playback、任务路由和语音测试共 102 项通过;真机 API 已从 20260821-cup_stacking-004 迁移为 cup_stacking,原 Take 1 保留、下一条为 2; 无头首播探针在第一次 Play 后约 0.73 秒得到三路 19/20/19 个轨迹点,页面无 OBS/Set station。

2026-08-21 · 校准录制支持左目回放

提交:3e05a76(main)

  • prepared playback 读取 recording_manifest.json 的 vio_calibration 标记后,固定将 Insight3 A/B 映射到各自 infra1/image_raw 左目画面;右目仍完整保留在原始 MCAP, 但不进入浏览器合成视频。普通录制继续使用原有 rectified stream,不会误切换。
  • 校准回放的 3D 数据同步改用两台 Insight3 各自的原生 vio_100hz,无需依赖校准模式下 本来就不存在的 /insight_global/.../pose。
  • 验证:prepared playback 21 项测试通过;真实 849 MiB 校准包生成 632 帧、21.07 秒、 1280×720 H.264 回放,两路左目各 422 个源帧,两条原生 VIO 轨迹覆盖率均为 100%; /bags 返回 200,视频 Range 请求返回 206,回放状态成功进入 playing 后已正常停止。

2026-08-21 · 修复校准录制时前端被循环重启

提交:b0c7e9c(main)

  • 根因不是网页代码崩溃,而是 run_dashboard.sh 的 DDS 恢复循环仍把 raw-only 下两路 Insight3 校正图 stale 当作断流,每 30 秒向 Dashboard 发送 SIGTERM;脚本只在刚启动时 检查一次录制状态,之后开始的校准录制无法阻止重启。
  • launcher 现在复用原生 vio_100hz 存活字段,把“双 Insight3 校正图 stale、原生 VIO fresh”识别为正常 raw-only 状态;并在每一次重启前重新读取录制状态,任何录制中都退出 恢复循环,不再中断 Dashboard、前端或 recorder。
  • 验证:Docker 事件确认旧退出为外部 SIGTERM/143,不是 watchdog;当前实机 raw-only 判定 launcher_all_cameras_live=true,相关测试 23 项通过。Playwright 实测首页 HTTP 200、完整 渲染且无失败资源。现场校准 bag 已落盘 21.089 秒、17 topic、25,323 条消息、849 MiB。

2026-08-21 · 删除麦克风方向性测试工具

提交:7dd1f12(main)

  • 删除不再使用的 scripts/test_microphone_direction.py,并同步删除只针对该工具的测试, 避免测试收集继续引用不存在的脚本。
  • 验证:语音测试集 63 项全部通过,仓库中无剩余引用。

2026-08-21 · 修复 raw-only 校准录制误报相机断开

提交:f870343(main)

  • 根因是 Insight3 切到只发未校正图像后会主动停止 Dashboard 的校正预览,旧校准前检、 录制中 QC 和 participant watchdog 仍用校正图新鲜度判在线,因而会拒绝录制、误报异常, 甚至在未录制时主动退出 Dashboard。
  • 校准录制现在不再检查校正预览和全局定位;仍严格要求 16 个非 latched topic 有发布者, 并在启动前实际读取四路未校正双目原图。普通录制的三相机、建图和定位门槛保持不变。
  • Dashboard 新增每台相机原生 vio_100hz 轻量存活检查;watchdog 只有在图像、展示 Pose 和原生 VIO 全部停止时才按链路掉线重启。持续诊断日志会把双 Insight3 校正图 stale、 原生 VIO fresh 识别为 insight3_raw_only_detected=true,不再生成掉线误报。
  • 验证:相关测试 92 项通过;真机四路 raw image payload 均在约 1.5–1.8 秒内到达;两路 Insight3 校正预览为空但原生 VIO 约 2–12 ms 新鲜,Dashboard 越过旧 15 秒阈值仍稳定, 新监控快照 active_faults=[]。未启动录制,因此没有产生测试 bag。

2026-08-21 · 新增相机掉线持续监控与自动归因

提交:2e8a7f0(main)

  • 新增 tests/diagnostics/monitor_camera_failures.py,持续把 Dashboard 图像新鲜度、 相机 HTTP/ROS Domain/标称帧率、USB 网卡计数、Dashboard 后端 PID 和内核 USB 事件 写入同一份 JSONL 时间线;异常开始与恢复只记录一次,100 MiB 自动分卷。
  • 相机身份按设备实时返回的 cameraNamespace 动态映射,不把 Insight3 A/B 固定绑定到 某个 IP;相机升级或重连后地址变化只记录迁移事件,多个在线地址声明同一身份才判冲突。
  • 自动区分多路 USB 同时断开、单相机未发现、相机在线但图像/DDS 大包停流、Dashboard 后端退出、ROS Domain 不一致、控制 API 降级、网络错误计数增长和持续低帧率。
  • 验证:相机升级现场实测捕获 USB 断开与重新枚举;Insight3 A 回到 .10.1、Insight3 B 回到 .20.1 后均按实际身份识别。专项及相关 watchdog/system-doctor 测试 33 项通过; 用户级 insight-camera-monitor.service 已运行,日志写入 outputs/camera_diagnostics/。

2026-08-21 · 新增语音 VIO 校准录制模式

提交:5b016f0(main)

  • 新增免唤醒固定命令“录制校准模式”,直接创建独立的 vio_calibration_时间戳 MCAP;仍说“停止录制”结束,并使用专用开始/结束播报。
  • 录制内容固定为 Insight3 A/B 的左右未校正 image_raw、左右 camera_info、IMU、 vio_100hz、vio_image、vio_status 和公共 /tf_static,合计 17 个 topic;明确不含 /insight_global/.../pose,也不占用叠杯子 Task/Take 编号。
  • 该模式用于调试相机原生 VIO,因此前检不要求 Insight9 建图或 Insight3 全局定位;但会 要求全部 16 个连续 topic 有 publisher,并临时订阅四路 raw image 各读取一帧,避免把 “存在空 publisher”误判成可录制。
  • 验证:专项 73 项测试通过,Python 编译与差异检查通过;运行容器注册新 POST 路由, 四路 raw payload 实测均在约 1.6–2.7 秒内到达;Dashboard 和宿主机语音服务已安全重启, USB 音频控制接口正常。未实际启动 rosbag,因此没有产生测试 bag。

2026-08-21 · 回放轨迹随模型推进并平滑模型动画

提交:dce09b5(main)

  • 修复 prepared 回放启动时把整段轨迹作为 snapshot 一次性画完的问题;轨迹现在按媒体 时间对应的源帧序号逐步追加,长轨迹仍保持最多 600 点的既有上限,旧回放缓存无需重建。
  • 模型姿态改为按视频 currentTime 在相邻 30 Hz 位姿之间做位置插值和四元数球面插值, Babylon 场景改由 requestAnimationFrame 驱动,并在回放时以显示刷新节奏更新,消除 30 Hz 离散目标叠加 setTimeout 与浏览器合成不同步造成的顿挫和跳帧感。
  • 验证:前端构建与 JS 语法检查通过;5 个现有回放缓存逐帧走到末尾后,经生产 trace-buffer 重建的轨迹与 manifest 逐点一致;prepared playback 测试 17 项通过, 其余仓库测试 198 项通过。全量测试另有 1 项既有结构白名单失败,并受现场已删除的麦克风 脚本影响无法收集对应测试,均与本次前端改动无关。

2026-08-20 · 一键统一三台相机与程序的 ROS Domain

提交:c14440b(main)

  • 新增 scripts/set_ros_domain_id.py,自动发现三条相机点对点链路,一次设置三台相机、 live config/cameras.json 和 Compose .env 的同一个 ROS Domain;检测到相机数量异常或 正在录制时拒绝修改,部分更新失败会尝试回滚。
  • 开发和客户部署 Compose 的 Dashboard、Insight9 mapper、Insight3 localizer 统一从 ROS_DOMAIN_ID 环境变量读取,不再由 Dashboard 单独硬编码为 20;脚本默认重启相机并 强制重建三个 ROS 服务,使新值立即生效,同时进入客户发布包和升级同步流程。
  • 原因:同一局域网内两台 Dashboard 使用 Domain 20 时出现两套同名建图/定位发布者,导致 校准状态互相覆盖。验证三台真机 dry-run 均从 20 规划到 21 且配置哈希不变;6 项单元测试、 Python/Shell 语法、开发与部署 Compose 在 Domain 21 下展开检查全部通过。

2026-08-20 · 区分 GStreamer 扫描噪声与真实录制盘告警

提交:f157fb6、7ba3381(main)

  • 系统医生不再把本项目未使用的 Jetson GStreamer 显示输出和 CSI Argus 输入插件因 libGLESv2 缺失产生的扫描信息算作高风险错误;WebRTC、NVJPEG 等实际使用插件的加载 失败仍会正常报警,并增加了回归测试。
  • 录制策略继续保持 U 盘优先:/dev/sda1 挂载到 /media/nvidia/INSIGHT_USB/rosbags 时写入 U 盘,U 盘缺失时回退到 NVMe。没有为了清零 报告而把主录制路径固定为 NVMe,也没有屏蔽 storage_fallback 告警。
  • dashboard.preflight 不再和专门的 recording.storage 重复统计同一个 storage_fallback;前检会明确注明已合并,存储章节保留完整证据、影响和修复建议。
  • 验证:完整测试 193 项通过;真机复检故障为 0,GStreamer 日志检查恢复正常。当前机器 未检测到 /dev/sda1,最终只报告 1 个真实的 U 盘缺失警告。

2026-08-20 · 修复相机 USB 重连后的 RPS 自动恢复

提交:0fe8778(main)

  • 根因:开机 oneshot 服务能把三张相机网卡的 rps_cpus 写成 3e,但相机 USB 重连会 重建 cdc_ncm 网卡并恢复为 00。旧 udev 规则匹配 KERNEL=="enx*",而 add 事件开始 时内核名仍是临时的 usbN,所以重连事件没有命中。
  • 处理:规则改为匹配 udev 计算出的 ID_NET_NAME=="enx*",并把这个最终接口名传给 configure_camera_network.sh;新增部署回归测试,防止规则退回到匹配临时内核名。
  • 验证:安装规则后,真实重启 Insight3 B;网卡从 ifindex 32 重建为 36,重建后 rps_cpus=3e,且 insight-camera-network.service 的启动时间未变化,确认恢复来自 udev 而非人工重启服务。三张网卡均为 3e,Insight3 B 图像恢复到 29.98 fps;系统 医生复检 network.rps 正常、故障数为 0,完整测试 191 项通过。

2026-08-20 · 相机未连接优先于校准提示播报

提交:d4450dc(main)

  • 现象:上一条改动把校准失败短路成"目前没有校准,请说开始校准。",但没考虑相机本身 没连接(camera_stale)的情况——这台设备重启后头部相机 insight9_a 一帧图像都没 收到过(fps: 0.0,age_sec: null),语音却只会说"没有校准",操作员会去尝试校准, 但校准本身就需要相机先连上,等于把真正的问题完全盖住了。
  • 处理:PreflightChecker.speech() 里 camera_stale 失败现在优先于校准判断,直接报 出具体哪路相机没连接(用"右手相机/左手相机/头部相机"这种口语化说法,而不是配置里的 英文 dashboard_label),例如"头部相机未连接,请检查相机。";只有相机都在线时才会 继续判断校准状态。
  • 验证:75项既有测试通过;真机验证时头部相机确实处于零采样状态,改动前后 GET /api/preflight 返回的 speech 从"目前没有校准,请说开始校准。"变成"头部相机未连 接,请检查相机。"——顺带暴露了这台设备头部相机当前的真实连接问题,需要单独排查。

2026-08-20 · 简化未校准时的语音/状态播报

提交:00c62bb(main)

  • 现象:语音说"开始录制"或"系统状态",在设备尚未校准时会逐条念出技术细节,例如 "无法开始录制,insight3_a全局定位未就绪;insight3_b全局定位未就绪;insight3_a位姿 数据不新鲜。"——信息准确但太啰嗦,操作员听着费劲。
  • 根因:这句话由 PreflightChecker.speech()(insight_capture/runtime/preflight.py) 统一生成,开始录制、系统状态两个语音命令和只读的 /api/preflight 都共用同一份 文本,之前只是把失败列表前3条拼起来念。
    • 关联但未处理:recording_stopped 播报(insight_capture/voice/replies.py)此前由 并发的另一个改动同步更新为"录制已经结束,请重新校准。",配合本仓库切换到"每次录 制后都要重新校准"的新流程;本次改动与其独立、互不冲突。
  • 处理:失败集合里只要出现 mapping_not_ready 或 localization_not_ready,直接短路 返回"目前没有校准,请说开始校准。",不再列出各相机的技术细节;failures 数组本身 不变,web 端仍能看到完整诊断信息。存储、话题缺失等其它失败类型暂不改动。
  • 验证:tests/runtime/test_capture_runtime.py、tests/voice/、 tests/web/test_settings_routes.py 共75项全部通过;重启 insight-dashboard 容器后 用只读的 GET /api/preflight、GET /api/system/status 在真机(当前确实未校准)上 确认两个接口都返回了简化后的这句话。

2026-08-20 · 新增系统深度诊断与显式修复

提交:02be52e、833b26a、c4db267、47073db、0db8e2a、d69d4c4、df6b928、cc9d2cf、158c1f9、0917983(main)

  • 新增 scripts/system_doctor.py,一次检查 NTP 选中源与偏差、主机资源/温度、录制盘、 相机链路、DDS/UDP 参数、RPS 与短时丢包增量、核心容器、Dashboard Preflight、三路 相机帧率、建图定位、硬件图像管线、近期日志和语音服务。
  • 每个异常输出原始证据、影响和按顺序执行的修复建议;支持人类可读报告、完整 JSON 留档、自动化退出码和可选相机 SSH 时钟偏差验证。相机时钟未验证时明确区分 ROS 消息 新鲜度,避免把传输/处理延迟误报为纯时钟差。
  • 现场入口简化为 ./scripts/system_doctor.sh;无需手写 Python 参数,脚本自动启用完整证据 并保存带时间戳的 /tmp/insight_system_*.json 报告,同时保留可选参数透传。
  • 故障/警告/正常统计结论保留在报告开头,并在全部证据、修复建议、安全提示和 JSON 路径之后再次输出为最后一行,长报告阅读结束后无需回滚查找总结果。
  • 相机时钟最终与 reboot_cameras.sh --sync-phase 采用同一种测量:在三台相机内部执行只读 ntpdate -q,查询各自宿主机链路地址并报告真实 NTP offset;但不执行后续 ntpdate -b、 相机重启或相位调整。曾尝试用 /api/system-time 返回值和 HTTP 请求中点估算 offset,但设备没有保证时间戳的内部取样时机,产生了约 66 ms 的假 偏差;对照既有 NTP 测量后已撤回该算法,不再把 Web 服务响应偏置误报为时钟故障。
  • 为三台相机的 root 账户安装本机专用 Ed25519 公钥,system_doctor.sh 自动使用 ~/.ssh/insight_camera_ed25519,日常巡检不再要求输入相机密码;密码和私钥均未写入仓库。 使用 BatchMode=yes 逐台执行只读 ntpdate -q 验证免密登录,三路均成功;本次未执行校时、 服务重启或相机重启。
  • --repair 扩展为按诊断 finding 分派的综合修复注册表:DDS/RPS 调用 host_setup.sh,宿主机 NTP 重启 chrony,缺失/异常容器与 1970 时间元数据用 Compose 启动或重建,Dashboard、媒体、 建图和语音服务有各自运行态修复,相机时钟/采集相位继续执行校时和 10 秒测量。Shell 入口先 用 sudo -v 取得一次临时主机权限;录制中拒绝全部动作。
  • 自动动作之后重新运行完整诊断并按 postcheck 判定结果;命令成功但检查仍异常时不会宣布修复 成功。磁盘挂载/删数据、配置覆盖、物理链路、资源压力、场景纹理定位和历史日志统一列为人工 项,保留具体证据和建议,不做有歧义的破坏性操作。
  • 真机综合验证中,host_setup.sh 将三张相机网卡的 RPS 全部恢复为 3e 并复检通过;此前的 1970 容器启动元数据也已自动重建为当前时间。相机最终 NTP 最大偏差 0.535 ms,但图像最大 差仍为 16.310 ms,因此相位修复项继续保持故障。最终 JSON 为 /tmp/insight_system_20260820_143218.json;定向测试 17 项、排除用户既有删除项后的完整回归 188 项通过。
  • 中断录制检查改为核对当前配置和实际录制路径下的 _staging 目录;Dashboard API 中启动 时留下的历史 recovery 文本只作证据,目录已删除时不再持续误报。真机删除指定的旧 insight_record_20260713_154448 后复验,该项由警告恢复为正常。
  • 真机只读复验抓到 RPS 自动服务仍指向已删除旧路径(退出 203、三张网卡均为 00)、 录制目录实际落在系统盘而触发 fallback,以及 Insight3 定位/位姿未就绪;同时确认三路 图像约 30 fps、宿主机 NTP/UDP 参数/温度/硬件编码正常。相关 15 项定向测试和排除工作区 既有删除项后的其余 175 项测试全部通过。

2026-08-20 · 精简数采手册并缩短停止播报

提交:22ed787(main)

  • 数采员 PDF 从 8 页压缩为 6 页:合并现场原则与口令、合并单条录制与逐条校准,删除重复说明。
  • 停止录制的最终播报改为“录制已经结束,请重新校准。”,与每条停止后重校准的现场流程一致。
  • 新增停止播报回归断言;语音测试 51 项通过。PDF 确认为 6 页 A4,逐页转图检查无截断。

2026-08-20 · 数采手册改为每条录制后重新校准

提交:614b7f6(main)

  • 按当前现场逻辑移除检测位、设置检测位和逐条“检查相机”流程;现行闭环改为停止录制后 立即说“开始校准”,三台相机重新建图/定位,听到“校准完成”后才开始下一条。
  • 口令速查收敛为现场使用的 8 条固定命令,并同步更新封面流程、开班准备、单条 Take、 异常处置和可打印检查表。
  • 重新生成 8 页 A4 PDF;逐页转图检查无截断,文本抽查确认旧检测位步骤均已移除。

2026-08-20 · 新增数采员语音录制 PDF 手册

提交:f95b21b(main)

  • 新增 8 页 A4《数采员语音录制指导手册》,覆盖 10 条离线固定口令、开班校准、单条 Take 闭环、逐条相机复检、主动告警处置、语音故障排查和可打印班次检查表。
  • 手册面向现场执行,明确“初始化录制中”与“录制已经开始”的边界,以及停止后必须完成 双手归位、头部扫视和“检查相机”PASS 才能进入下一条;动作失败只标记作废,不删除原始 bag。
  • 同时保留可维护的自包含 HTML 印刷源,并从 README 增加 PDF/HTML 入口。
  • 验证:Chromium 生成 PDF 后用 pdfinfo 确认 A4 共 8 页、中文字体嵌入;逐页转图抽查封面、 口令表、流程、异常和勾选页,无内容截断或页码错误;git diff --check 通过。

2026-08-20 · 清理语音回复文案的影子重复定义

提交:9a92c58(main)

  • 根因:insight_capture/voice/service.py 里保留着一份完整的 CANNED_REPLIES、 LOCAL_COMMAND_ALIASES 等旧实现(连同 normalize_transcript、AlsaCapture 等约 300 行函数/类),文件末尾又用 from insight_capture.voice.{audio,commands,replies} import ... 把同名变量重新绑定为拆分模块里的新实现——Python 模块级 import 在加载时 执行,后绑定的必然覆盖前面的,所以这份内联旧代码从未真正生效过,纯粹是误导性的 死代码。
  • 更麻烦的是内容已经分叉:CANNED_REPLIES 里 8 条播报(capture_check_not_ready、 recording_stopped 等)的死代码版本用词是"左右手相机"+"两路全局定位",与 commands.py/preflight.py 当前的双手+头部三相机架构一致,明显是曾经想更新的 文案;但因为被静默覆盖,设备这段时间一直在说 replies.py 里更早、更笼统的旧版本 ("三台相机""检查定位状态")。
  • 处理方式:以死代码里更新的措辞为准合并进 replies.py(唯一生效来源),删除 service.py 里约 330 行被覆盖的旧定义,并把散落的内联播报("没听清。"、 "OpenClaw 暂时不可用。")收成 replies.py 里的具名常量,避免以后再有人对着 service.py 改一句没有任何效果的话。
  • 验证:tests/voice/ + tests/test_deploy_voice.py 63 项在宿主机与 insight-dashboard 容器内均全部通过;import insight_capture.voice.service 后 确认 CANNED_REPLIES/LOCAL_COMMAND_ALIASES 均解析到 replies.py/commands.py 的最新值。

2026-08-19 · 修复 E3 音响热插拔后不恢复

提交:9cc46c0(main)

  • 根因有两层:语音服务为修正 E3 错误 dB 元数据而手工重载的 PulseAudio 模块不会随 USB 拔出自动卸载,插回后 udev 又创建一个 ignore_dB=no 的同卡模块,形成旧 sink 与 .2 新 sink 并存;同时录音进程因拔出重启后会错误回退到 Jetson 板载 APE,插回 E3 也不再换回。
  • 每次状态刷新和实际播放前现在都会按自动发现的 ALSA CARD 合并同卡重复模块,使用最新 模块参数重新加载唯一的 ignore_dB=yes card、刷新 sink 并恢复持久化音量;语音、样例音和 Settings 音量控制都走同一恢复路径。
  • 自动录音/播放启动只接受 USB 声卡;设备缺失时进程明确失败并由 systemd 每 5 秒重试, 不再静默绑定 APE/HDA。USB 插回后下一次重试会重新绑定正确的输入和输出。
  • 真机加载第二个同卡 ignore_dB=no 模块精确复现热插拔后的双 sink,状态刷新后自动合并为 一个 E3 sink,47% 恢复为 PCM 470/999,Dashboard 样例音实播成功;冷启动 PulseAudio 与 语音服务后输入为 plughw:CARD=E3,DEV=0、输出唯一且服务恢复 ready/listening。语音及 Settings 相关测试 61 项全部通过。

2026-08-19 · 修复自动选中 E3 后硬件音量仍为零

提交:c9c56d2(main)

  • 根因:E3 的 0–999 PCM 范围带有错误 dB 元数据,已有 ignore_dB 兼容处理;但语音服务改成 自动发现双工 USB 声卡后,仅在配置了人工 audio_device_hint 时才启用该处理。页面和 paplay 都显示 56% / played: true,硬件寄存器却仍是 0/999,所以物理音响静默。
  • 兼容处理现在可从自动发现的 plughw:CARD=E3,DEV=0 提取声卡 ID,并在服务启动时应用到 实际选中的 PulseAudio card;冷启动后模块为 ignore_dB=yes,56% 线性映射到 PCM 559/999,播放声道恢复为 FL,FR。
  • Settings 样例音代理单独把超时从 2 秒放宽到 15 秒,覆盖语音服务冷启动时首次加载 Piper 模型的耗时;状态和音量接口仍保持 2 秒快速失败。
  • 真机重启 PulseAudio、语音服务和 Dashboard 后立即从 Settings 同一路径播放“宸境科技”, 3.35 秒成功返回且日志记录 played: true;硬件仍为 PCM 559/999。语音 48 项、Settings 路由 4 项测试全部通过。

2026-08-19 · 修复语音播放静默走错 sink(2 字符声卡 ID 匹配不上)

提交:9c9c6a8(main)

  • 根因:discover_pulse_sink() 要求 ALSA 声卡 ID 转成 key 后至少 3 个字符才会去匹配 PulseAudio sink,而当前音响 CF001 E3 的声卡 ID 就是 "E3",只有 2 个字符,永远 过不了这个门槛,函数直接退化成"随便返回系统当前的 default sink"。
  • 恰好这台机器 PulseAudio 的 default sink 变成了主板 onboard 输出 (platform-sound,没接喇叭),导致语音服务一直对着这个哑巴设备放音频: paplay 正常返回、日志记 played: true,但物理上完全没声音——比"报错"更难查。
  • 门槛从 3 降到 2;本地验证 discover_pulse_sink 重新解析回 alsa_output.usb-CF-IC_CF001_E3_2025-1107-1200-00.analog-stereo,直连语音服务和经 Dashboard 代理各触发一次样音播放,用户当场确认从 USB 音响听到了"宸境科技"。

2026-08-19 · 修复 Settings 页样音按钮被浏览器缓存卡死

提交:b3b414f(main)

  • 根因:create_static_cache_middleware(insight_capture/api/middleware.py)对 所有带 ?v= 参数的 /static/ 请求都发 Cache-Control: immutable, max-age=1y, 不管 v 具体是什么值——这个方案要求每次改动共享 JS/CSS 内容时,引用它的页面必须 同步把 ?v= 换成新字符串,否则浏览器会把旧内容缓存整整一年、永不重新请求。
  • 前两条改动(新增播放样音按钮、删掉滑轨说明文字)改了 app.js 和共享 styles.css,但忘记同步给 settings/index.html 里引用它们的 <link>/<script> 换新版本号,导致任何当天已经打开过 Settings 页的浏览器会一直吃旧缓存的 settings.js——那份旧版根本不认识新按钮,所以按钮永远停在 HTML 原始的 disabled 状态:灰色、真点不动,不管后端重建重启多少次都没用。
  • 把 settings 页对 styles.css、settings.js 的引用换成新的 ?v=20260819-voice-sample;用户下次刷新 Settings 页会因为脚本 URL 变了触发一次 真实的网络请求,不需要手动清缓存。已用 curl 确认新 URL 返回最新内容,重新用 headless Playwright 走了一遍按钮点击到真实出声的完整链路。

2026-08-19 · Settings 音量滑轨上方冗余说明文字删除

提交:35777ed(main)

  • 去掉音量滑轨上方(窄屏会换行到上面)的 "Output level" 标签和 "Automatically follows whichever supported USB speaker is currently connected." 说明小字——这段 文字和滑轨本身+右侧百分比读数是重复信息,用户反馈看着冗余。
  • 无障碍标签改为直接放在 <input> 的 aria-label,同时删掉不再使用的 label 相关 CSS 和窄屏专属的 grid 列覆盖规则,让滑轨行铺满卡片宽度。
  • 顺带确认了上一条 "Play sample" 按钮外观:不是灰态 bug,是和 Save/Refresh 等按钮 一致的 quiet-button 二级按钮样式,未被禁用;重建前端后回归测试样音播放仍正常出声。

2026-08-19 · Settings 音量滑块旁新增播放样音按钮

提交:10b228c(main)

  • Settings 页 Speaker volume 滑块旁新增 "Play sample" 按钮,点击播放一句 "宸境科技" TTS 样音,方便凭听感确认当前音量大小,不用特意喊语音指令去触发。
  • 复用语音服务已有的 Piper speak() 播放链路:语音控制服务新增 /v1/audio/sample 路由, Dashboard 通过新增的 /api/settings/voice-sample 代理转发;前端按钮状态跟随音量滑块的 可用性一起启用/禁用。
  • 直接 curl 语音服务和经 Dashboard 代理两条路径都在服务日志里产生了真实的 speech/played: true 记录(确认真的出声);headless Playwright 检查按钮渲染、点击 发起正确请求、播放后按钮恢复可用且无控制台报错。前端已重建。

2026-08-19 · 前端音量滑块自动跟随当前 USB 音响

提交:9d9e3e6(main)

  • Settings 页新增一个 Speaker volume 滑块,通过仅监听宿主机 loopback 的语音控制接口实时 调整音量;百分比持久化到宿主机设置文件,重启服务后继续使用但不绑定具体设备。
  • 播放端在读取或调整音量时重新扫描 ALSA 设备,并按扫描到的稳定 CARD 映射 PulseAudio sink;原音响拔出后自动跟随当前插入的 USB 音响,同型号拔插导致 sink 后缀变化也会刷新, 不写死 A311、E3 或其他产品名,也不要求两台同时连接。
  • lite 真机确认 A311(Yundea A31-1)和 E3(CF001 E3)均可被扫描并映射到各自 sink;当前 A311 经 Dashboard API 实际写入并保持 40%,语音服务恢复 ready/listening。语音 50 项、 Web 16 项、部署 3 项测试通过,前端已重建。

2026-08-19 · 语音服务自动扫描双工 USB 声卡

提交:1548819(main)

  • 移除语音服务对 E3 产品名的默认依赖;启动时分别扫描 ALSA 录音和播放设备,按声卡配对 并优先选择同时支持输入输出的 USB 设备,仍保留环境变量作为可选人工覆盖。
  • PulseAudio 播报优先使用当前有效的默认 sink,失效时回退到扫描到的 USB sink;显式 ALSA 播放也会从自动选中的设备解析 mixer card,不依赖易变化的数字索引。
  • lite 真机安装并重启后自动选中 A311 作为录音和 ALSA 播放设备、Yundea A31-1 作为 PulseAudio sink,服务恢复 ready/listening;语音 43 项、部署 3 项测试通过。

2026-08-19 · 新增麦克风方向性测试脚本

提交:d66c903、1ded60a(main)

  • 新增逐方向麦克风收声测试脚本,以正面为 0 度、顺时针记录角度;每个方向默认录制三次 “安静—固定口令—安静”样本,保存原始 WAV、逐次 CSV 和方向汇总 CSV。
  • 自动计算语音电平、背景噪声、估算信噪比、峰值与削波比例,并累计生成极坐标方向图、 绝对语音电平和信噪比柱状图;重复测试同一角度默认替换旧数据,避免误测污染汇总。
  • 检测到 insight-voice-control.service 正在独占 E3 麦克风时拒绝抢占并提示先暂停服务; 默认结果保存到宿主机用户可写的 runs/microphone-direction/,不受容器创建的 outputs/ 所有权影响。合成波形分析、双方向图表和默认目录回归测试 3 项通过。

2026-08-18 · 叠杯子数据完成穷尽标注、分段与 LeRobot v3 导出

仓库:NUSNiuMu/robot-dataset-annotator

提交:291709e、994406b(main)

做了什么

  • 新增稳定任务 ID cup-stacking、两阶段原子动作 task spec(搭建三杯金字塔、收拢为嵌套杯) 和同步双手位姿候选边界插件;候选算法支持同一源片段中的多个完整 episode,无法可靠判断时 保持 unresolved。
  • 对录制 cup_stacking_take_0008_20260818_175153 的三路必需视角做完整人工审核,确认 8 个 不重叠的完整循环并保存源帧坐标决策;共保留 3076 帧、102.53 秒,其中搭塔 1711 帧、收拢 1365 帧。
  • 新增原子 LeRobotDataset v3.0 导出器:从原始 MCAP 同步左右手红外和头部彩色三路相机, 写入双手 18 维位姿观测、头部 9 维位姿观测、有效性掩码、源帧与原子动作索引,并保留输入 哈希、同步统计、代码版本和动作语义。
  • action 明确定义为下一帧双手 6D 位姿目标,episode 最后一帧保持当前目标;它仍在源追踪 坐标系中,未做机器人重定向且不包含夹爪命令,避免把缺失的控制量伪装成可直接执行动作。
  • 新增 rda export-lerobot、rda validate-lerobot、Python 3.10 固定验证环境和恢复命令; 导出拒绝覆盖已有数据集,只在 LeRobot finalize 成功后原子提升临时目录。

为什么

  • 新采集的叠杯子任务需要复用现有的穷尽审核和批次状态机,同时把任务语义、源格式解析与 LeRobot 写出保持解耦,后续新增操作任务时不应复制整套标注流程。
  • 自动边界只能作为人工审核提示;训练数据必须保留可追溯的源帧范围、动作阶段、同步质量和 明确的数据缺口,尤其不能凭空补造录制中不存在的夹爪或机器人控制指令。

怎么验证的

  • 决策覆盖检查通过:1 个源片段全部审核,8 个 episode 的边界有序、不重叠,并满足每个原子 动作的最短帧数;会话审计最终为 COMPLETE。
  • 导出结果为 8 个 episode、3076 行、三路 H.264 视频;左右手各 3076 帧且无重复,头部流因 原始时序最近邻复用 92 帧,最大同步偏差 29.801 毫秒,低于 30 FPS 的一帧容差。
  • 内部验证检查 row、episode、timestamp、task index、source frame、有效性掩码及 next-frame action 不变量,并逐帧完整解码三路共 9228 个视频帧;全部通过且记录产物 SHA-256。
  • 官方 LeRobot 0.4.4 loader 成功载入 3076 行和 8 个 episode,跨 episode 代表性索引及一个 PyTorch DataLoader batch 通过;本地回归测试 12 项、Skill 校验和 wheel/sdist 文件清单通过, tests/ 未进入 Git 或安装包。

2026-08-18 · 统一 3D 与全站左侧导航顺序

提交:618472c(main)

  • 将 3D 页紧凑导航中的 Recorder 从第三位移到 Optimization 之后,使九个入口与 Sessions、 Rosbags 等普通页面统一为同一顺序;同步重建并提交 web_dashboard/dist/3d.html。
  • 新增结构回归测试,逐页检查所有九个带导航页面;11 项结构测试通过,容器 Chromium 实际 加载 3D 与 Rosbags 页面并截图确认 SE→3D→BG→DS→SC→HP→OP→RC→ST 顺序一致。

2026-08-18 · E3 默认音量调整为 40%

提交:a652ab7(main)

  • E3 线性音量修复保持不变,将语音服务每次启动恢复的 PulseAudio/ALSA 默认值由 50% 调整为 40%,并同步 systemd unit、工程说明、使用文档和环境变量示例。
  • lite 真机立即生效并重启复核:Pulse 为 40%、硬件 PCM 为 400/999,启动日志为 audio_setup.ok=true,服务恢复 ready/listening;语音 41 项、部署 3 项测试通过。

2026-08-18 · 修复 E3 音量滑块断崖

提交:f5ecb26(main)

  • E3 USB 声卡把 0–999 PCM 范围错误上报为 0~+3.90 dB,PulseAudio 因而把 86% 当作 基准点:低于该值时硬件长期停在 0,高于该值才突然提升,表现为几乎无声或突然很响。
  • 语音服务启动时只重载匹配 E3 的 PulseAudio card 并启用 ignore_dB,不影响 Jetson 板载声卡和 HDMI;重载失败会恢复原模块,仍保留共享 Pulse 播放以避免 ALSA 争用。
  • 每次启动把输出恢复到 50%,可通过 LOOPER_PLAYBACK_VOLUME 覆盖;显式 ALSA fallback 同样恢复 PCM 音量。现场服务日志确认 audio_setup.ok=true 并恢复 ready/listening。
  • 20%、50%、80% 滑块分别映射到 PCM 200、500、799;短音频实播成功,语音 41 项、部署 3 项测试以及 Python/Bash 语法检查通过。

2026-08-18 · 放宽左右手相机检测通过阈值

提交:fd03154(main)

  • Insight3 A/B 的 PASS 阈值由 10 毫米、2 度调整为 15 毫米、3 度,以覆盖现场治具回位的 正常波动;静止窗口仍为 6 毫米、1.5 度,RECALIBRATE 阈值仍为 25 毫米、5 度。
  • 同步更新 lite、jetson-nx 设备模板、代码缺省值、当前 lite 运行配置和叠杯子采集 SOP, 防止重启、切换 profile 或缺少显式配置时恢复旧值。
  • 仅重启 Dashboard 主服务,保留 Insight9 地图会话和检测位 Reference;API 确认新阈值已生效, 相机检查专项 15 项和全量 139 项测试通过。

2026-08-18 · 头环闭环检查增加主动等待窗口

提交:77442a0(main)

  • 现场确认 Insight9 闭环算法此前已成功 8 次,最近一次为 155 个描述子匹配、90 个内点、 3.8 毫米和 0.252 度;当前失败画面只有 9 个描述子匹配,低于 20 个门槛,并非 mapper 离线。
  • “检查相机”现在播放对准检测位方向、小范围缓慢扫动的提示,并在后台最多等待 12 秒接收 新闭环;闭环结果有效期由 5 秒改为 30 秒,覆盖扫动、停稳和语音识别耗时。
  • 描述子匹配、PnP、多帧共识和几何误差阈值均未放宽;上一条 PASS 的闭环序号仍不能复用, mapper session 或冻结 Reference 变化仍要求重新校准。
  • lite 真机保留现有地图与 Reference 热加载新配置,API 显示等待 12 秒、有效 30 秒;全量 149 项测试通过,语音服务恢复 ready/listening。

2026-08-18 · 相机检查按设备播报并改善 Piper 断句

提交:5bcccaf(main)

  • “检查相机”未通过时不再只播放统一提示;语音会分别指出右手、左手、头部相机,并根据 结果提示重新归位、扫视已建图工作区或重新校准。通过的相机不重复播报。
  • 修复 Piper 把多个句子音频块无间隔拼接造成的吞句和异常断句:句间新增 220 毫秒静音, 默认语速恢复为自然值,并降低声学和时长随机性;常用固定回复同步拆成短句。
  • lite 真机通过 E3 USB 音响播放多相机失败示例,语音服务重启后恢复 ready/listening; 当前最新检查为左手相机 25.87 毫米需校准、右手相机 21.66 毫米需归位、头部相机通过。
  • 全量 148 项测试通过,覆盖动态相机名称、校准建议、语音命令响应与句间静音帧数。

2026-08-18 · 允许语音录制自动回退到本机存储

提交:39c4ea6、046c987(main)

  • 修复存储层已自动切换到可写 fallback、但 Preflight 又因“必须使用主录制盘”拒绝开始的 配置冲突;三个设备 profile 现在默认允许使用备用存储。
  • fallback 可写且空间充足时报告 storage_fallback warning 并继续录制;目录不可写、空间不足 以及相机、定位、必要 topics 异常仍然阻断。需要强制 U 盘的部署仍可显式启用 preflight.require_primary_storage。
  • 运行中 QC 同样将 fallback 作为不影响数据质量的 warning;它仍保留在 Take 时间线和语音提示 中,但不会单独把 Take 标成 suspect。
  • lite 真机在 U 盘源不匹配时验证 Preflight ok=true,三路相机约 30 FPS、两路定位正常; 通过语音实际使用的 automation 接口成功开始叠杯子第 1 条,写入 rosbags/archives。
  • 全量 144 项测试通过,严格主盘模式、非阻断 warning 与 Take QC 均有回归覆盖。

2026-08-18 · 修复语音“开始校准”HTTP 503

提交:4206220(main)

  • 现场语音准确识别“开始校准”,但 mapper/localizer 是结构迁移前创建的旧容器;普通 docker compose restart 沿用旧启动命令,持续执行已经删除的 scripts/*.py,导致 /api/mapping/reset 返回 503。
  • 重新创建两个容器后,它们已使用当前 insight_capture.runtime.mapping.* 模块入口;校准请求 成功请求 mapper 与 localizer,随后地图恢复到 463 点,两路 Insight3 均重新完成定位。
  • Dashboard 启动脚本现在先执行 docker compose up -d 对齐 Compose 定义,再只重启 Dashboard 载入 bind-mounted 代码;相机 DDS 恢复也不再无谓重启 SuperGlue 和建图服务。
  • 校准服务不可用时新增明确语音原因,不再只播报笼统失败;全量 143 项测试和 Bash 检查通过。

2026-08-18 · 语音播报自动路由到 E3 USB 音响

提交:87c4692(main)

  • 修复语音服务能识别并执行命令、但 PulseAudio 将反馈送往 Jetson 板载默认声卡而听不到的 问题。麦克风此前已正确使用 E3,故日志会误呈现 played=true。
  • 新增 PulseAudio sink 自动发现,按 LOOPER_AUDIO_DEVICE_HINT(默认 E3)选择稳定 USB sink;systemd unit 默认启用自动选择,仍允许通过 LOOPER_PULSE_SINK 显式覆盖。
  • lite 真机已将输入解析为 plughw:CARD=E3,DEV=0,输出解析为 E3 USB Pulse sink;服务为 ready/listening,通过修复路径实播“语音已经恢复”成功。
  • 全量 141 项测试、Python 编译和 Bash 语法检查通过。

2026-08-18 · Task 前端名称统一为英文

提交:1fab892(main)

  • 将叠杯子 Task 拆分为英文界面名称 Cup stacking 和中文语音名称“叠杯子”;Sessions、 Recorder 与元数据面向界面的字段只显示英文,中文固定口令和播报保持不变。
  • Recorder 无活动任务提示改为纯英文;新增结构回归检查,禁止 web_dashboard/src 的 HTML/CSS/JS 及 Task 界面名称再次引入中文字符。
  • 前端重新构建,全量 140 项测试通过;lite 真机重启后 API 返回英文 Task 名,Chromium 验证 Sessions 和 Recorder 页面均只显示英文,录制目录仍为 rosbags/archives。

2026-08-18 · 宿主机语音服务默认安装与旧 unit 自动迁移

提交:c6c9da7(main)

  • 修复语音安装器只在首次部署文档中手动执行、旧 looper-openclaw-voice.service 因而长期运行旧代码的问题。
  • update.sh 现在会从目标 Dashboard 镜像同步最新宿主机语音代码和 unit;离线模型已准备好 时自动安装、启用或升级 insight-voice-control.service,并停止、移除旧 unit,避免两个进程 竞争同一个 ALSA 麦克风。模型未准备好时明确提示并跳过,不阻断 Dashboard 升级。
  • lite 真机已从旧服务迁移,新服务为 enabled、active/running,启动入口为当前仓库的 scripts/run_voice.sh;叠杯子开始、计数查询和任务结束三个固定口令均匹配新动作。
  • Bash 语法、缺模型安全跳过、升级同步/迁移回归检查及全量 139 项测试通过。

2026-08-18 · 叠杯子 Task / Session / Take 与语音计数

提交:a28e567(main)

  • 新增可扩展的 Task 目录,当前默认任务为“叠杯子”;数据按 Task → Session → Take 组织, Session 使用 日期-cup_stacking-序号 命名,Take 与默认 bag 名在批次内递增。
  • 当天 Dashboard 重启会恢复未结束的 Session;重复说“开始任务叠杯子”不会清零。明确说 “结束当前任务”后再次开始才新建批次,录制过程中禁止切换或结束任务。
  • 离线固定口令新增“开始任务叠杯子”“当前任务多少条”“结束当前任务”;状态播报包含 已录制、有效、作废和下一条编号。没有活动任务时,网页和录制接口都会阻止开始录制。
  • Sessions 与 Recorder 页面显示当前 Task、Session、已录条数和下一条编号;前端重新构建, 136 项测试通过。lite 真机接口显示 20260818-cup_stacking-001、已录 0 条、下一条 1, 重复开始返回 changed=false;Chromium 验证 Sessions/Recorder 页面正确显示任务状态。

2026-08-18 · 录制目录与 Rosbag 资料库解耦

提交:bc8b780(main)

  • Recorder 切换目录后只改变新录制的写入目标;新增跨允许存储根目录的 rosbag 索引,使用稳定 bag ID 定位数据,并保留唯一旧 bag 名称的 API 兼容。
  • Bags 页面新增 All directories / Current recording directory 筛选,显示每条 bag 的 所在路径;旧目录和当前目录可同时浏览,删除、回放、评分、Hand pose、优化与数据集导出均按 所选 bag 的真实路径执行。
  • Sessions 的 Take 新增 Open rosbag,依据持久化 bag_path 跳转到 Spatial review 并选中 对应录制,不受后续 Recorder 目录切换影响。
  • 前端重新构建,132 项测试通过;lite 真机保持 rosbags/archives 为当前写入目录时,API 验证 全部目录可见 41 条、当前目录 0 条,Chromium 加载 Bags 页面正确显示筛选和路径且无页面错误。

2026-08-18 · 应用依赖与关闭生命周期收尾

提交:cfdf58f(main)

  • ROS playback topic 映射迁入 runtime/ros/topics.py,runtime 不再反向导入 HTTP API; topic nominal rate 目录迁入共享 quality/,同步消除录制模块对 postprocess 的反向依赖。
  • 新增进程级 insight_capture/composition.py,统一创建 Session/Take、Preflight、Active QC、 playback、scoring、optimization、handpose、gripper 和 dataset export 服务; DashboardContext 改为只保存显式注入的依赖,不再在 Web API 构造阶段启动后台服务。
  • PoseBridgeNode.close() 统一释放 preview、WebRTC 和 hand-overlay 资源;删除已被正式架构文档 吸收的根目录 improve.md。前端 dist 仍按现行后端直出和发布流程保留提交产物。
  • 129 项测试、Ruff、针对性 mypy、Python 编译和 insight_capture_dashboard-2.0.6 wheel 构建通过;lite 真机重启后 health、playback、sessions、voice API 与三路 pose WebSocket 正常, Playwright 加载 /3d 为 HTTP 200 且无控制台错误。

2026-08-18 · Python 应用边界与运行入口收敛

提交:6c0ef5c(main)

  • 新增 pyproject.toml,统一项目 metadata、基础依赖、七个 insight-* console scripts 以及 pytest、Ruff、mypy、pyright 配置;当前仍保留根目录 package 布局, 暂不在同一轮迁移到 src/。
  • 正式实现迁入 core/、api/、services/、perception/ 和 quality/: HTTP route 不再持有 dataset export、trajectory scoring 和 gripper extraction 的 后台任务实现,runtime/media 也不再反向依赖 postprocess.gripper。旧 common/、web/ 和 gripper/station-check import 路径保留为薄兼容 wrapper。
  • runtime/app.py 从 878 行缩为 159 行,只负责参数、配置、node/recorder/API 组装和 关闭生命周期;路径/存储/recorder factory 移入 runtime/bootstrap.py, PoseBridgeNode 移入 runtime/ros/node.py。结构测试会阻止生产代码重新依赖旧边界。
  • Ruff 审计同时发现并修复 Ego LeRobot route 引用未定义 script 的问题,改为稳定的 python -m insight_capture.postprocess.datasets.ego_lerobot.cli 启动,并增加回归测试。
  • 125 项测试、Ruff 全仓检查、210 个 Python 文件字节码编译和 wheel 构建通过。lite 真机 Dashboard 重启后 health、dataset/scoring/handpose 状态接口和 WebSocket 首帧正常; Playwright 首页 HTTP 200、无 page error,三路相机输入仍约 30 FPS。

2026-08-18 · scripts 收敛为七个现场薄入口

提交:9042ddb(main)

  • scripts/ 严格收敛为 run_dashboard.sh、run_voice.sh、select_device.sh、 reboot_cameras.sh、sync_camera_restart.py、check_bag.py 和 export_lerobot.py;发布安装、Kiosk、相机运维、SuperGlue 工程准备和诊断实现分别迁到 deploy/ 与 tools/,未引用的旧 Python facade 和 OpenClaw 专用兼容 unit 删除。
  • Docker 主进程、录后评分、夹爪提取、UMI/LeRobot/Ego LeRobot 以及媒体 worker 统一改为 python -m insight_capture... 模块入口。真机验证时发现并修复了 WebRTC worker 直接执行包内 文件导致导入失败和反复拉起的问题;hand overlay worker 同步使用模块入口。
  • 单元测试增加目录边界保护,防止业务实现重新进入 scripts/。单一 Dashboard Dockerfile、 3D 相机模型、Insight9/Insight3/SuperGlue、WiLoR、语音和 legacy bag 兼容均保留。
  • 110 项测试、Python 编译、Shell、开发/部署 Compose 和镜像重建通过;Playwright 真机加载 /3d 时 Iron Man GLB 成功、控制台无错误,WebRTC 建立 NVENC H.264 管线。viewer 退出后 自动回到 Capture Mode,worker 停止,三路相机仍约 30 FPS 且 fresh。

2026-08-18 · 项目结构收敛到无屏采集产品边界

提交:b5f28ce(main)

  • 将现场运行、语音、媒体、Web、采后处理、公共模型和历史兼容实现迁入 insight_capture/{runtime,voice,media,web,postprocess,common,legacy};scripts/ 只保留运维命令和 兼容薄入口,设备 CLI、Dense Mapping/RViz 与诊断移入 tools/。
  • 前端源码按 sessions/review/datasets/storage/advanced/shared 分区,测试按 runtime/voice/postprocess/web/legacy 分区;设备 profile 的运行配置统一改名为 runtime.json, systemd unit 收敛到 deploy/systemd/。
  • 保留单一 Dashboard Dockerfile、MCAP/回放/LeRobot、Insight9/Insight3/SuperGlue、WiLoR/Ego、 离线语音和可选 OpenClaw;SQLite/composite/UMI Zarr 继续作为 legacy compatibility,真实 3D 相机模型未移除。
  • 108 项测试、全仓 Python 编译、前端构建、Shell 与开发/部署 Compose 校验通过;真机 Dashboard 重启后 API 健康,Playwright /3d 加载 Iron Man GLB 且无控制台错误。viewer 退出后状态回到 Capture Mode,WebRTC worker 停止,三路相机健康订阅仍为 fresh。

2026-08-18 · 恢复 3D 页面相机模型

提交:67f6eee(main)

  • 恢复三套设备 profile 的左右手 vis_assembly.glb 和头部 iron-man_helmet_mk3_optimized.glb 配置,并重新在 pose WebSocket payload 中下发模型路径、 缩放、旋转、偏移和带版本的资源 URL。
  • 只恢复 Spatial review 的模型显示;Capture Mode、按需 WebRTC、Gesture Recording 删除和精简后的 Settings 保持不变。
  • 真机 WebSocket 返回三路模型,三个 GLB 均为 HTTP 200;Playwright 打开 /3d 显示模型已加载且 无页面错误,容器完整 107 项测试通过。

2026-08-18 · 现场采集改为无屏语音优先模式

提交:99ffd14(main)

做了什么

  • 新增 Capture Mode:无 Dashboard viewer 时只保留 MCAP 录制、图像 header audit、2 Hz localization relay、VIO/建图与主动 QC;预览和 WebRTC 按 viewer 需求启动,最后一个 viewer 离开 45 秒后停止媒体 worker。
  • 固定语音命令全部走宿主机 SenseVoice + VAD + Piper 离线链路,覆盖录制、校准、相机检查、 系统状态和“本条作废”;OpenClaw 仅作为非固定自然语言的可选增强。voice systemd service、 安装脚本和 release bundle 已同步,Dashboard 不再挂载 /dev/snd。
  • 录制前增加三相机、定位/建图、录制盘、空间和必要 topic 的 Preflight;增加持久化 Session/Take 元数据和采中持续异常时间线,作废只标记 invalid,不删除原始 MCAP。
  • 删除未引用的 inprocess_bag_writer.py 和 Gesture Recording 后端、设置项及前端入口;SQLite/ composite bag 收敛为 legacy compatibility。Sessions 成为采后首页,Hand pose/COLMAP 分别归入 Advanced/Engineering。

为什么

  • 背包现场主要靠语音操作,不应在无人查看时持续消耗 JPEG 编码、WebRTC 和叠加处理资源; 采集资源应优先服务录制、定位、QC 与离线语音。
  • 开始录制必须在数据流和存储条件满足时才放行,采中异常与人工作废也必须可审计并保留原始数据。

怎么验证的

  • 容器内 106 项单元/异步路由测试通过;Python 120 文件编译、前端重建、JSON、Shell、Compose 和 diff 检查通过。
  • lite 真机三路原始图像约 30 FPS;无 viewer 和仅打开 Sessions 首页时媒体 worker 均不存在, viewer API 会按需拉起 WebRTC,45 秒空闲后自动退出。
  • 当前设备两路 Insight3 尚未全局定位且主录制盘 source 不匹配,Preflight 明确报告定位、pose 和 storage fallback,录制启动返回 422,未创建 Take 或 bag,验证了失败保护。

2026-08-18 · 采集检查统一使用“设置检测位”

提交:6cb7e1f(feat/insight9-episode-drift-check)

做了什么

  • 删除重复的“设置批次基准”语音别名,保留“设置检测位”“记录检测位”“保存检测位”;网页按钮和 状态统一为 Set station / Station reference。
  • 更新宸境播报、使用文档和叠杯 SOP,统一称为“检测位基准”;底层仍保存两台 Insight3 的固定 检测位 Pose,并同时冻结 Insight9 自然特征地图。
  • 修正宸境专项文档遗留的“三台相机固定 Pose”旧说明,明确 Insight9 通过新鲜冻结地图闭环检查。

为什么

  • “设置批次基准”和“设置检测位”调用相同接口且执行相同动作,两套操作名称会让现场人员误以为 需要分别设置。统一保留已经使用的“设置检测位”,降低培训和误操作成本。

怎么验证的

  • 宸境语音桥 30 项、采集检查 13 项、mapping bridge 2 项测试通过;确认“设置检测位”仍能命中, “设置批次基准”不再作为固定口令。
  • 重新构建前端,并用无头 Chromium 加载生成后的 3D 页面,确认 Set station 正常渲染。

2026-08-18 · Recording 页面可选择录包目录

提交:3ea1831(main)

做了什么

  • Recording 页新增 Recording folder → Browse...,可在 Dashboard 已挂载的录制盘和 NVMe fallback 范围内浏览并选择现有目录;当前目录、可进入的子目录和活动保存路径均可见。
  • 后端限制目录浏览边界,隐藏已有 rosbag、_staging 等内部目录;录制或停止排空期间拒绝 切换,确认选择及每次开始录制前都执行写入/fsync 探测。
  • 切换后 Bags、回放、评分、Hand pose、夹爪提取和数据集导出同步使用新根目录;选择保留到 Dashboard 重启,重启后恢复配置的主盘检查和 fallback 规则。

为什么

  • 不同采集批次需要按任务或日期落到不同已挂载目录,过去只能修改环境配置并重启服务。
  • 浏览器原生目录控件不能把客户端绝对路径交给容器内 rosbag writer,因此采用受限的服务端 目录浏览器,同时避免无认证页面枚举设备的其他文件系统。

怎么验证的

  • 容器内完整单元测试 91 项通过;新增覆盖允许范围、已有 bag 过滤、目录切换、消费者通知、 录制中拒绝和 HTTP 路由的 4 项测试。
  • lite 现场重启后目录 API 返回当前 NVMe 路径和可写子目录,访问 /etc 被 HTTP 400 拒绝; 无头 Chromium 实际打开 Recording 页并点击 Browse,弹窗路径、目录和选择按钮正常,无 4xx。

2026-08-17 · 每条采集用冻结自然地图检查头部相机漂移

提交:e11fa0a(feat/insight9-episode-drift-check)

做了什么

  • 检测位基准改为“两台 Insight3 固定检测位 + Insight9 冻结自然特征地图”:设置基准时复制 最多 2 万个已确认三维点及描述子,后续新增关键帧和 Pose Graph 重建不会移动检测基准。
  • 每条 episode 必须获得一条晚于上次 PASS、且年龄不超过 5 秒的 Insight9 闭环;用新 PnP map_to_odom 与现有 VIO 校正之间的创新量判定漂移,头戴相机不再要求回到固定 Pose。
  • mapper session、冻结 reference 或 VIO 时间轴重置会使检测位基准失效;两台 Insight3 继续使用 原机械检测阈值。页面、宸境提示、设备配置和数采 SOP 已同步新流程。

为什么

  • 两台夹爪相机可以可靠归位,但头戴 Insight9 很难机械重复落位;直接比较头部固定 Pose 会把 正常站位变化误判成漂移。
  • 自然场景闭环允许头部位姿自由变化,同时冻结旧地图可避免用本 episode 新增特征自证正确。

怎么验证的

  • 采集门控 13 项、mapping bridge 2 项、路由 3 项、宸境语音桥 30 项测试通过;覆盖头部任意 移动、每条新闭环、结果超时、地图 session 变化和严重校正不能被后续小校正掩盖。
  • 前端重新构建,并以 1600×1000 无头 Chromium 加载 /3d.html,新状态行和操作按钮布局正常。
  • 未把实验 worktree 挂入 live 容器;现场服务保持运行且当前未录制。

2026-08-17 · 声控统一由宸境提供并增加启动延迟观测

提交:3e38f98(main)

做了什么

  • 删除 Dashboard 内旧 Vosk worker、容器模型依赖、设备配置、Settings 开关、Recording 状态标签和对应测试;麦克风只由宿主机宸境服务占用。
  • 语音桥新增 local_command_timing 结构化事件;Dashboard 录制状态新增 start_timings,分别记录存储检查、recorder 拉起、DDS 订阅稳定、resume 和 audit 启用。
  • resume_requested_offset_sec / resume_confirmed_offset_sec 给出 MCAP 真正开始写入的时间 上下界,语音日志同时记录两段缓存播报和本地 HTTP 总耗时。

为什么

  • 两套麦克风 worker 即使旧 worker 默认关闭,仍会增加镜像体积、配置和误开启后争用声卡的 风险;现场已经统一使用 SenseVoice/OpenClaw 宸境链路。
  • “初始化录制中”到“录制已经开始”的等待过去只能看到总时长,无法区分语音、播放器、 Dashboard 和 DDS discovery,难以定位现场波动。

怎么验证的

  • 重建前端与开发镜像,确认新镜像不再包含 Vosk Python 包或中文模型;容器完整测试 87 项 通过,Recording/Settings 两页无头加载正常,旧 voice UI 与 API 字段均已消失。
  • lite 三相机两次真实 MCAP 启动为 3.7210 秒和 8.9435 秒,DDS 稳定分别占 3.2287 秒和 8.4516 秒;较慢样本从识别完成到 resume 确认 10.9702 秒,到最终确认播完 12.4880 秒。两份测量 bag 的三路 image header audit 与内核网络审计均为零丢失,验证后 已删除测试 bag。

2026-08-17 · Insight3 直接匹配 Insight9 校准关键帧

提交:96e9010(main)

做了什么

  • Insight9 mapper 最多以 2 Hz 发布最新左红外校准关键帧,以及该帧双目三角化后的 UV/XYZ 对应;重置地图或 VIO 时间戳回退时显式清空旧关键帧。
  • 两路 Insight3 首次定位优先与校准关键帧做 SuperGlue 直接匹配,再用关联到的三维点 运行 PnP;关键帧未就绪或匹配未通过时仍回退到原有描述子地图。
  • 定位共识由“连续三次成功”改为“最近五次尝试中三个候选一致”,单次模糊或遮挡不再 清空已有确认进度。

为什么

  • 现场三路相机方向接近,但视场和尺度不同;原描述子最近邻能找到 24–41 条对应,PnP 内点通常只有 9–16 条,且一次失败就重置连续确认,导致校准缓慢。
  • 直接 SuperGlue 可以利用整幅图的上下文约束对应关系,并允许在确认地图尚未积累到 80 点前直接使用首个高质量双目关键帧完成初始化。

怎么验证的

  • 新增 5 项测试,覆盖 3/5 滑动共识、窗口淘汰、不一致候选隔离、关键帧像素到三维点 关联和合成 PnP;仓库测试 89 项通过,另 1 项仅因本机缺少既有可选依赖 pyarrow 未运行。
  • ROS 图像与 UV/XYZ PointCloud2 往返无损;真实 TensorRT/ROS 链路中,确认地图为 0 点时 A/B 已分别取得 42/74、32/58 个 PnP 内点并完成初始化。通过网页 New map 再测,两路均 达到 localized=true,服务最终日志无新异常。

2026-08-17 · 固定录制口令即时本地反馈

提交:3809e36、3dad976(main)

做了什么

  • “开始录制”和“停止录制”识别后立即播放预生成的“初始化录制中,请稍等”或“正在结束录制”, 不等待 OpenClaw,也不等待 rosbag 的 DDS 订阅或 writer 排空。
  • Dashboard 真正完成操作后仍播放最终成功提示;失败时播放失败提示,开始录制的最终确认 若无法播出仍执行原有安全回滚。
  • 本地 Dashboard 请求超时从 15 秒延长到 40 秒,覆盖 recorder 最长订阅就绪窗口,避免 后端仍在等待三机时语音桥提前报超时。

为什么

  • 固定短口令本来已经绕过 OpenClaw,但 Dashboard start API 会同步等待三机订阅完成,用户 听到首条反馈前仍可能等待约 10 秒,表现得像经过了模型推理。

怎么验证的

  • 新增开始、停止即时反馈顺序、精确提示文案和无反馈不执行等回归测试;容器完整测试 87 项通过。
  • 重启常驻语音服务后确认四条录制反馈均已预生成并进入本地监听;三机实际 NVMe 录制约 29 秒,三路 878–879 帧、live header 缺帧 0、网络丢包计数 0。

2026-08-17 · 录制盘 I/O 异常自动回退 NVMe

提交:4de6690(main)

做了什么

  • Dashboard 启动时及每次开始录制前,除核对 findmnt 挂载源外,还会在 _staging 创建、写入并 fsync 临时探测文件;挂载不匹配、只读或返回 I/O 错误时自动切到本机 NVMe rosbags/。
  • 首次回退后当前进程固定使用 NVMe,避免 U 盘抖动导致录制目录来回切换;评分、回放、 Hand pose、夹爪提取和 UMI 导出同步更新录制根目录。
  • /api/recording/status 新增 storage.fallback_reason,明确报告回退原因。

为什么

  • U 盘断连后,容器保留的旧 bind mount 仍可能被 findmnt 报告为 /dev/sda1[/rosbags],原逻辑只比较设备名,会把已经对 _staging 返回 EIO 的挂载误判为 健康,导致语音和网页开始录制均返回 HTTP 500。

怎么验证的

  • 使用现场故障挂载验证:内核已中止 /dev/sda1 的 ext4 journal,_staging 返回 Errno 5;重启最终版本后 API 自动显示 using_fallback=true、活动路径 /workspaces/insight_capture/rosbags,并返回完整 EIO 原因。
  • 容器完整单元测试 84 项通过;新增覆盖挂载源仍匹配但目录 EIO、探测文件清理和录制前 动态切换 NVMe 的回归测试。

2026-08-17 · 发布 v2.0.6

Tag:v2.0.6(提交 7d104f2)

发布内容

  • 正式 Dashboard runtime 镜像已按 jetson-nx profile 打包,包含 CycloneDDS 单 MCAP writer、订阅就绪后统一 resume、/tf_static 补发和 cdc_ncm RPS udev 恢复规则。
  • 产出 insight-dashboard-v2.0.6.tar.gz(4.0G)、稳定 SuperGlue 首装依赖 insight-superglue-validation-25.04.tar.gz(716M)及 48K 首装部署包。
  • 生成 SHA256SUMS-v2.0.6.txt;三份 SHA-256 和 gzip 完整性检查全部通过。镜像内部确认 为 aarch64、jetson-nx、已安装 ros-humble-rmw-cyclonedds-cpp,且不含开发用 Playwright 浏览器层。构建后开发机 profile 已恢复为 lite。

2026-08-17 · 录制改为一个标准 MCAP rosbag

提交:6ecba9f、7d104f2(main)

做了什么

  • 全部勾选 topic 改由一个原生 C++ ros2 bag record --storage mcap 进程写入;停止时 排空 cache 并原子发布一个标准 rosbag2 目录,不再生成四个 part,也不需要后台合包。
  • Dashboard 图像 callback 只做独立的 source-header 连续性审计;原生 recorder 启动就绪后 才开启 audit。自动识别 MCAP cache 实际丢弃日志,异常时保留 staging 数据。
  • 中断的单 MCAP staging 支持 reindex/recovery;主机调优新增 udev 规则,在 cdc_ncm USB 网卡重连、RPS 被内核清零后自动恢复 RPS/RFS。
  • recorder 子进程固定使用 CycloneDDS,并以 --start-paused 等待三台相机订阅全部建立后 再统一开始录制;Dashboard 在 resume 后补发缓存的 /tf_static。

为什么

  • Python 单 writer 在 44-topic 负载下实测只能处理约 1,325 message/s,队列会溢出;原生 recorder 短测可保持三路 IMU 约 398–399 Hz,而且直接生成标准 rosbag。
  • 133 秒长测暴露一张相机网卡重连后 rps_cpus=00;恢复三张网卡 RPS 后,FastDDS recorder 仍新增 30,225 次 UdpRcvbufErrors。同样负载切换 CycloneDDS 后网络计数归零, 证明根因是 FastDDS recorder 的 UDP 接收路径,不在 U 盘、MCAP writer 或总带宽。
  • CycloneDDS 会分批发现三台相机 participant,直接开录造成开头 4%–10% 的缺口;先暂停到 订阅就绪再 resume 可消除该启动偏差。paused 期间会消费 latched /tf_static,所以 resume 后只补发一次缓存消息,仍由同一个 writer 写入。

怎么验证的

  • 最终 44-topic 录制直接写 ext4 /dev/sda1,得到一个 9.7 GiB MCAP、258,065 条消息、 130.022 秒;三路 IMU 均为 400.0 Hz,三路主图像约 30 Hz,所有实际连续 topic 深度检查 missing 0,/tf_static 为 1 条。网络的 softnet、netdev、IP 重组、UDP 错误增量全部为 0。
  • 停止时 writer cache 无丢弃,排空 0.805 秒、原子发布 1.147 秒;结果只有一个 MCAP, 不需要合包。手工全选中 7 个 firmware 只 advertise、不发布 payload 的 raw topic 和一个 当前不存在的 depth topic 为 0 条,设备 profile 已排除它们,不属于 recorder 丢帧。
  • 新镜像已重建上线并确认包含 CycloneDDS,U 盘挂载仍为 /dev/sda1[/rosbags] ext4;完整 容器测试 81 项通过,三路相机实时 API 均约 30 fps。

该条取代下方 de824d7 的四-part 方案;旧复合 bag 仍保持读取与恢复兼容。

2026-08-17 · U 盘直录改用 MCAP 复合会话

提交:de824d7(main)

做了什么

  • 三路 Dashboard 主图像分别由进程内 MCAP writer 写入,其余选中 topic 共用一个 MCAP recorder;停止时排空四个 part 并原子发布 manifest,不再复制、合并 SQLite payload。
  • Bags 目录、完整性检查、恢复、普通回放和准备式回放均可直接读取复合会话;writer 异常、 队列丢弃和 recorder 非零退出会阻止发布并保留 staging 数据。
  • Compose 支持把录制根目录直接绑定到 ext4 U 盘。配置的 U 盘未挂载或设备源不匹配时, 自动回退到持久化 NVMe rosbags/,API 返回实际路径和 storage.using_fallback。

为什么

  • 旧 44-topic SQLite 测试中四个 recorder 同时随机写数据库,写回停顿耗尽 rosbag cache, 丢弃 51,205 条;停止后合并另耗时 400.833 秒,无法马上开始下一轮。
  • 同期网卡、softnet、IP 重组和 UDP 接收错误增量均为 0,说明瓶颈在 SQLite recorder 写入路径,不是相机链路或 USB 网络带宽。

怎么验证的

  • ext4 U 盘 44-topic 压测录制 163.41 秒,得到 14,449,452,319 bytes、324,476 条消息; 三路主图像分别 4,899 / 4,899 / 4,902 帧,30 Hz、header 缺帧 0、writer 丢弃 0。
  • 网络审计全部丢包计数为 0;writer 排空 2.422 秒、四 part 原子发布 0.108 秒,随后一段 录制可立即成功启动。完整容器环境 77 项测试通过,最终镜像重建并上线。
  • 实机状态确认 /dev/sda1[/rosbags] 直接写 /mnt/insight-recordings;缺盘模拟自动选择 /workspaces/insight_capture/rosbags,storage.using_fallback=true。

2026-08-14 · 降低 3D 渲染负载并补齐 Insight7 完整性帧率

提交:2f56b58(feat/insight7-triple-camera)

做了什么

  • 正常和回放模式的 3D canvas 改为 80% 线性分辨率渲染,轨迹数据频率、位姿频率和轨迹 点精度保持不变。
  • rosbag 完整性检查将 Insight7 图像及 camera info 识别为 30 Hz 连续流;结果页面明确显示 消息数、实测帧率、额定帧率和丢帧率。
  • 设置页移除 Voice recording 与 Stick-figure mode 两个勾选入口,后端能力保持可用。
  • 通过 SSH 将改动写入 192.168.19.240 的 v2.0.5 镜像覆盖层,并完成 compose 重建验证。 按现场要求删除 v2.0.4 镜像和升级前配置备份。

怎么验证的

  • 合成 301 帧 Insight7 bag 得到实测 30.0 Hz、额定 30.0 Hz、丢帧 0%;目标机直接订阅 Insight7 A/B/C 彩色压缩 topic,三路稳定在约 30.00 Hz。
  • 浏览器断言两个设置入口均不存在、三张相机卡片正常,3D canvas/CSS 宽度比为 0.7993, 页面控制台无错误。
  • 从持久化镜像强制重建全部 compose 服务后,/healthz 正常、建图恢复至 90 个确认点; 目标机可用空间由约 52 GB 增至 61 GB。

2026-08-14 · 发布并部署 v2.0.5 三 Insight7 版本

标签:v2.0.5(ee9306f,feat/insight7-triple-camera)

做了什么

  • 构建 ARM64 客户 release:Dashboard 主镜像、SuperGlue 离线依赖和首次部署包,并生成 SHA256 校验清单。
  • 将 192.168.19.240 从 v2.0.4 升级到 v2.0.5;升级前确认 JetPack 6.1/L4T 36.4.3、 Docker Compose 2.40.3、NVIDIA runtime、磁盘空间和 SuperGlue 镜像均兼容。
  • 目标机原配置仍是 Insight3 A/B + Insight9,不能只加载新镜像;本次同时迁移为 ROS Domain 20 的 Insight7 A/B/C profile 和新版 compose。旧 .env、compose、相机与后处理配置保存在 backups/pre-v2.0.5-20260814/,v2.0.4 镜像继续保留用于回滚。

怎么验证的

  • 目标机 v2.0.5 四个容器全部启动,/healthz 正常;A/B/C 中心彩色流均为 1088×1920、 约 30 FPS,WebRTC 实际处理约 30 FPS。
  • Insight7 C 使用约 70 mm 双目基线建立 133 个确认点;捕获到静止独立观测,重复静止帧 未追加到位姿图。A/B VIO 与全局定位链路在线。
  • /insight_mapping/insight7_c/sparse_map/status 只有一个发布者;3D 页面 HTTP 200,未出现 Station reference required,加载 20260814-trail-recovery 前端资源。
  • 主镜像在本地和目标机的 SHA256 均为 d66b61a7455302e715106c59da163138dcefa348ed3194929f04ae06fe84488f。

2026-08-14 · 按头部相机隔离建图 ROS 接口

提交:ee9306f(feat/insight7-triple-camera)

做了什么

  • mapper 的状态、特征、Pose、调试点云、轨迹和 reset 接口迁移到 /insight_mapping/<head>/sparse_map/,节点名和地图 TF frame 同样包含头部相机名。
  • Dashboard、全局重定位、相机 profile、录制话题目录和 RViz 同步使用新接口;话题发现 只接收本 rig 配置的建图/定位输出,排除 Domain 内其他设备的旧全局话题。
  • localizer reset 改为同一头部相机命名空间,避免“新建地图”请求命中另一台机器的同名服务。

为什么

  • 现场 ROS Domain 20 中存在两个同名 /insight9_sparse_mapper,旧固定状态话题有两个发布端: 本机发布 97 点地图,另一个节点持续发布 waiting_for_inputs / 0,导致网页点数交替归零。
  • 固定特征和 reset 接口也存在同样串台风险,单纯在前端保留上一次点数无法保证定位正确。

怎么验证的

  • 新 Insight7 C 状态和特征话题均只有 1 个发布者,特征话题由唯一 localizer 订阅;两个 reset 服务均位于 /insight_mapping/insight7_c/sparse_map/。
  • 静止头部相机形成 82 个确认点,连续 20 次轮询均保持 82,Insight7 A/B 均完成全局定位。
  • 完整 ROS 环境下 77 项测试通过;录制话题刷新包含新 pose/features/status,旧 /insight9_sparse_map/* 数量为 0。

2026-08-14 · 3D 轨迹自动恢复并保留

提交:e9172d5(feat/insight7-triple-camera)

做了什么

  • 从 3D 页面移除 Station reference required 等检测位状态行及其每秒轮询;检测位设置与 检查接口仍保留给语音调用。
  • 收到轨迹增量但本地缺少完整快照时,前端主动断开并重连取得轨迹基线,不再静默忽略 后续数据。
  • 有效移动门槛从 20 mm 调整为 5 mm;服务端滚动窗口被静止样本填满后,继续保留最近 一段有效轨迹,直到用户清除轨迹或新建地图。

为什么

  • 模型 Pose 使用最新消息即可持续移动,但轨迹依赖完整快照和后续增量;首包缺失时会出现 “模型在移动、轨迹始终为空”的不同步状态。
  • 原 20 mm 门槛会过滤小范围操作,且 300 点窗口进入静止状态后会清掉已绘制轨迹。

怎么验证的

  • 容器完整 ROS 环境下 75 项测试全部通过,前端构建、JavaScript 语法检查和差异检查通过。
  • 浏览器合成轨迹验证:缺快照时拒绝增量并触发恢复,6 mm 移动生成轨迹,随后静止仍保留, 显式清除后归零。
  • 实机 /3d 返回 HTTP 200,无 pageerror/console error,检测位状态行和 /api/capture-check 页面请求均为 0;三路相机在线。

2026-08-14 · 静止头部相机可启动稀疏地图

提交:3ac4091(feat/insight7-triple-camera)

做了什么

  • 将地图观测编号与位姿图关键帧编号分离:地图不足 80 个确认点时,静止相机每 0.4 秒 补充一次独立双目观测,至少三次一致观测才确认地标,最多六次。
  • 静止补帧不向位姿图添加重复节点;回环优化重建地图时,所有保留观测按时间重新应用 位姿图校正。达到 80 点后停止静止推理,避免持续占用 GPU。
  • 3D 页面移除 Check rig 和 Set station 两个按钮,保留只读检测结果;“检查相机”和 “设置检测位”仍通过语音调用原有安全接口。

为什么

  • 旧逻辑只在移动 5 cm 或旋转 3° 后创建新关键帧,而地标要求三个关键帧确认;刚重置后 完全静止的头部相机虽然已有一百多个有效双目三角化点,正式地图仍会一直显示 0。
  • 双目本身已经提供尺度深度,可以使用多帧时域一致性过滤瞬态误匹配,无需用 VIO 抖动 制造位姿图节点。

怎么验证的

  • 静止 Insight7 C 在 1.76 秒时形成首批 57 个确认点,3.01 秒达到 83 点;全过程保持 1 个位姿图关键帧和 5 次地图观测,随后 Insight7 A/B 均完成全局定位。
  • 容器完整 ROS 环境下 75 项测试全部通过,新增同一关键帧不同观测可完成三次确认、 重复观测不重复计数和历史关键帧过滤测试。
  • Playwright 加载 /3d 返回 HTTP 200,两个按钮数量均为 0,页面显示 83 个确认点, 无 pageerror 或 console error。

2026-08-14 · Jetson NX 适配三台 Insight7

提交:1c70a2d(feat/insight7-triple-camera)

做了什么

  • jetson-nx profile 改为 insight7_a 右手、insight7_b 左手、insight7_c 头部, ROS domain 使用 20;建图、双路全局重定位、轨迹、检测位、录制话题和 UMI 导出均改为 按配置角色解析,不再依赖固定的 Insight3/Insight9 名称。
  • 三路网页预览使用中心彩色压缩流;建图、重定位和相机同步使用左右目彩色 NV12 流。 固件沿用 infra1/infra2 topic 名,图像管线按 NV12 完整解码,特征提取只使用亮度平面。
  • 相机同步脚本从 profile 读取三台设备 IP、NTP 地址和测量流;3D 与数据集页面动态显示 当前相机名称和角色。
  • 未复用旧 Insight3 的 TCP 外参;Insight7 A/B 在实物测量完成前保持未标定,避免输出 虚假的 TCP 坐标。

为什么

  • 当前设备实际接入的是三台 Insight7,需要让同一套在线标定、图像和录制链路适配设备 命名空间与角色,同时正确保留左右目“彩色 NV12、legacy infra topic”的真实语义。

怎么验证的

  • 容器完整 ROS 环境下 72 项测试全部通过,Python 编译检查、前端构建和 git diff --check 通过。
  • 实机三路中心彩色画面均约 30 FPS,WebRTC 可用;ROS 实帧确认左目编码为 nv12。
  • Insight7 A/B 的图像、内参、左右/中心外参和 VIO 均就绪;Insight7 C 建图节点使用 约 70 mm 双目基线正常生成特征。现场仍需移动 C 建立足够地图点,再让 A/B 完成定位。

2026-08-14 · 检测位改为逐台全局 Pose 比较

提交:004814d(main)

做了什么

  • “检查相机/开始检测”命中后先播放“开始检测”,确认播放成功后才调用检测接口,完成后 再播报 PASS、重新放置或重新校准。
  • 检测位基准从三组两两相对 Pose 升级为 Insight3 A、Insight3 B、Insight9 三台相机各自的 全局位置和方向;公共平移或旋转不再被相对关系抵消。
  • 两路 Insight3 只要求已在本轮地图中完成全局定位,允许检测时处于 vio_only 连续跟踪, 不再强制检测瞬间必须 map_matched。
  • Insight3 使用严格阈值:PASS 10 mm/2°、重校准 25 mm/5°;Insight9 使用宽阈值: PASS 40 mm/8°、重校准 80 mm/15°,静止窗口也按相机类型分别判定。
  • 基准格式升级到 version 2;旧相对基准不能推导绝对全局 Pose,因此不会静默迁移或覆盖。

为什么

  • 现场检测瞬间要求两路 Insight3 同时重新命中地图过于苛刻;已完成全局定位后,连续 VIO 输出仍是可比较的全局 Pose。
  • Insight3 是操作端,需要更严格地发现位置变化;Insight9 稀疏地图 Pose 波动更大,需要 较宽阈值避免正常波动造成误报。

怎么验证的

  • 容器 ROS 环境下 47 项相关测试全部通过,覆盖共同全局偏移不能被抵消、Insight3/Insight9 分级阈值、vio_only 可检测、未定位拒绝,以及“开始检测”必须先于 API 调用。
  • 实机 API 返回 version 2 两套阈值,旧基准显示不可用;未自动保存或覆盖现场基准。
  • 新“开始检测”缓存通过 PulseAudio 实播成功;宸境为 active/listening。
  • Playwright 打开 3D 页面返回 HTTP 200,检测状态元素正常且无 pageerror/console error; Dashboard、建图、重定位和 SuperGlue 服务均保持运行。

2026-08-14 · 语音录制增加确认反馈安全闭环

提交:3b13628(main)

做了什么

  • 宸境的唤醒提示、固定回复和自然语言回复从直接 aplay 改为 PulseAudio 共享播放, 避免与桌面 speech-dispatcher 争用 E3 USB 声卡。
  • 固定“开始录制”只有在“录制已经开始”完整播放后才确认成功;若播放失败,语音桥会 持续调用只允许停止 looper_record_* 的 automation stop,直到本轮录制停止。
  • OpenClaw 自然语言工具入口在调用前后核对录制状态;本轮新建录制若没有成功播放回复, 使用相同闭环回滚。网页、手势和其他控制器创建的录制不会被误停。
  • 播放失败改为单次交互错误,不能再让常驻语音进程退出;服务就绪日志会记录实际播放 后端和 PulseAudio sink。

为什么

  • 现场“开始录制”已经被识别并执行,但 E3 被 PulseAudio 占用,随后直接 aplay 返回 device busy,导致 systemd 重启语音服务。采集员没有听到确认,录制却继续在后台运行。
  • 录制是有状态且高风险的动作,不能把 API 成功等同于人机交互成功;声音确认失败必须 自动恢复到未录制状态。

怎么验证的

  • 先通过 automation stop 停止现场意外录制;looper_record_20260814_154231 已完成合包, Dashboard 最终为 recording=false、merge_state=done,原始数据未删除。
  • 容器 ROS 环境下 43 项相关测试通过,覆盖固定指令反馈失败回滚、重试直到停止、 OpenClaw 工具路径回滚,以及保护人工录制不被误停。
  • paplay 端到端播放“语音服务已恢复”返回 played=true;服务重启后为 active/listening, ready 日志显示 playback_backend=pulse,且最终再次确认没有录制在运行。

2026-08-14 · 叠杯批量采集增加固定检测位质量门

提交:8b88faf(main)

做了什么

  • 新增三相机固定检测位:稳定采样头部、左手、右手 pose,并比较头↔左手、头↔右手、 左手↔右手三组相对位姿;检测结果分为 PASS、重新放置复检和重新校准。
  • 检测前要求 Insight9 建图在线、两路 Insight3 当前都重新匹配地图、pose 新鲜且静止, 避免用旧 VIO 校正或移动中的相机建立错误结论。
  • 新增 /api/capture-check、/reference、/run,3D 页面提供 Check rig / Set station, 检测结果关联最近一条 bag 并写入 outputs/results/capture_checks/。
  • 宸境新增免唤醒“检查相机/开始检测”和“设置检测位”固定指令;每条录制停止后播报 放回检测位,按检测结果引导下一条、复检或重校准。
  • 新增叠杯批量数据采集 SOP,明确 3-3-3 等任务不可混标、每单元闭环、异常隔离重录、 人员权限、验收条件和语音准备方式。

为什么

  • 批量重复采集中,单路相机漂移可能污染后续所有动作;每个 episode 结束都回到机械固定 检测位,才能把异常范围限制在当前单元并及时阻断后续采集。
  • 使用三组两两相对位姿而非世界系绝对位置,可以检测独立相机漂移,同时避免 Insight9 公共回环校正造成误报。

怎么验证的

  • 容器完整 ROS 环境下 60 项单元测试全部通过,覆盖基准保存、PASS/复检/重校准、疑似相机、 当前 map-matched 门和录制中拒绝检测。
  • 当前 jetson-nx 实机 API 显示三路稳定窗口可用,地图 88 个确认点,两路 Insight3 均为 map_matched;未擅自保存最终治具基准。
  • Playwright 打开 3D 页面返回 HTTP 200,检测按钮和基准按钮可见,无 pageerror 或 console error;前端重新构建且 src/dist 一致。
  • 宸境服务重启后进入 active/listening,新预生成语音已加载;OpenClaw 插件重新解析为 enabled;git diff --check 通过。

2026-08-14 · 固定语音指令改为免唤醒

提交:2b4ecec(main)

做了什么

  • 常驻激活监听同时识别严格整句的录制/校准指令和“宸境”唤醒词。
  • 直接说“开始录制”“结束录制”“开始校准”等固定指令即调用本机 Dashboard 并播放 缓存回复,不需要先说名字。
  • 单独说“宸境”只打开 OpenClaw 模式;听到“我在”后的下一句话强制发送给 OpenClaw, 即使文本恰好是固定指令也不走本地快捷路径。

为什么

  • 确定性控制需要最低延迟和离线可用性,不应增加唤醒与 OpenClaw 往返;自然语言查询 才需要显式唤醒,以保持清晰的权限和交互边界。

怎么验证的

  • 16 项语音桥测试和 4 项 Dashboard 自动化接口测试通过,新增覆盖“直接固定指令旁路 OpenClaw”与“唤醒后的同名固定指令仍强制进入 OpenClaw”。
  • Python 编译与 git diff --check 通过;常驻服务加载新状态机后为 active。
  • 现场音响样音与真人等待窗口未产生 VAD 事件,因此未重复创建录制 bag;此前完整声学 闭环已验证相同固定指令的 ASR 和 Dashboard 执行链路。

2026-08-14 · 完成语音声学闭环与校准完成播报

提交:2b1b20e、eb219c5(main)

做了什么

  • 新增“成静”唤醒别名,对外名称仍为“宸境”;E3 默认播放音量由 40% 调整为 50%。
  • 真人复测中 SenseVoice 还输出“很静”“南静”“沉静”;将这些现场变体加入严格整句 匹配,长句或子串仍不能唤醒。
  • “开始校准”成功 reset 后启动本机后台监控:必须先观察到本轮未完成状态,随后 Insight3 A、B 首次同时 localized=true 时只播放一次预生成的“校准完成”。
  • 所有语音播放共用进程锁,避免唤醒确认、命令回复和异步校准通知争用 E3。
  • 增加默认关闭的 wake candidate 诊断日志,现场闭环调试可显式启用,不在常驻服务中 记录环境谈话。

为什么

  • 单纯把 WAV 直接送入 ASR 不能覆盖音响、房间混响、麦克风和 VAD;必须跑真实 E3 音响到麦克风闭环,才能确认“宸境”和固定命令在现场可用。
  • reset 成功只表示校准开始,不能代表两路 Insight3 已获得全局位姿;完成播报必须使用 首次双路定位成功这一真实条件。

怎么验证的

  • 50% 音量下,E3 音响播放的“成静/宸境”经麦克风被 SenseVoice 识别为“成静”或 “陈静”,均成功触发 wake,并按顺序播放“我在”。
  • 真人近距离复测产生“很静、南静、沉静、嗯这”候选,确认服务和 E3 capture 正常, 并定位到漏配“沉静”而不是进程退出或麦克风静音;修复后服务恢复 active。
  • 完整闭环成功识别并本地执行“开始录制”“结束录制”“开始校准”,未调用 OpenClaw: 创建并停止 looper_record_20260814_143732,mapping reset 后地图点由 290 清为 0, 新会话进入 keyframe 1。
  • 测试 bag 约 1.70 GB;快速完整性检查中除缺少 /insight9_a/camera/vio_image_cov 外其余所列流通过。该缺失属于采集 topic 问题, 与语音启停无关;随后按用户明确指令删除该测试 bag。
  • 15 项语音桥测试、4 项 Dashboard 自动化接口测试、Python 编译、Shell 语法和 git diff --check 通过;服务恢复为 active,缓存“校准完成”WAV 已生成。

2026-08-14 · 固定语音指令改走本地快捷路径

提交:4145288(main)

做了什么

  • “开始/停止录制”和“开始/重新/重置校准”等短指令改为由宸境语音桥直接调用 loopback Dashboard API,不再发送给 OpenClaw。
  • 服务启动时预生成录制成功、校准成功、重复录制和失败等 5 条语音,命中固定指令后 直接播放缓存,不再等待在线推理或临时合成。
  • “开始校准”固定映射到 /api/mapping/reset,清空 Insight9 地图和 Insight3 全局定位状态后开始新一轮在线校准;录制仍只能停止语音自动化创建的 bag。
  • 唤醒同音词优先接受“澄净/澄静”,移除容易误触发普通谈话的“曾经/陈经”。

为什么

  • 录制与校准是确定性设备操作,不需要自然语言推理;本地执行可以缩短响应时间, 也让 OpenClaw 或网络不可用时仍能完成基础控制。
  • “宸境”的目标听感是“澄净”,原先兼容“曾经”会掩盖错误发音并增加误唤醒风险。

怎么验证的

  • 14 项语音桥测试和 4 项 Dashboard 自动化接口测试通过,覆盖精确匹配、礼貌说法、 OpenClaw 旁路、录制 API 和校准 reset API。
  • 服务重启后为 active,/tmp/looper-canned-1000/ 中 5 个有效 WAV 均已生成, 当前录制状态保持 false,未为测试创建 bag。

2026-08-14 · 宸境中文唤醒复用 SenseVoice

提交:a758aa7(main)

做了什么

  • 语音助手对外名称和唤醒词由 Looper 改为“宸境”,内部 looper-* 服务名与录制前缀保留以兼容现有部署和安全边界。
  • 移除英文 Vosk/Zipformer 唤醒依赖;Silero VAD 分段后,常驻的 SenseVoice INT8 中文模型同时负责唤醒词和后续命令转写。
  • 唤醒只接受完整两字短句,并兼容 SenseVoice 对罕见词“宸境”的少量 同音转写;长句中出现“沉浸”或“曾经”不会触发。
  • 兼容 OpenClaw Gateway 新版 result JSON 包装,避免已生成回答却被语音桥 误判为空回复。

为什么

  • GigaSpeech Zipformer 只是英文开放词表 KWS,对现场中文使用者的 Looper 发音检出不稳定;改用中文名称并复用 SenseVoice 可以去掉第二个 识别模型,同时避免中英文发音差异。

怎么验证的

  • 14 项 OpenClaw/语音桥测试、Python 编译、Shell 语法与 git diff --check 通过。
  • 安装脚本重新部署后,systemd 显示“宸境 OpenClaw voice assistant”,日志确认 engine=sensevoice 且 wake_phrases=["宸境"]。
  • USB 音响到麦克风的中文声学回环成功产生 wake,播放“我在”后重新进入 命令监听;语音进程常驻内存由约 605 MB 降至 417 MB。

2026-08-14 · 增加低延迟 Looper 自然语言语音助手

提交:4b4a0ee、4ec8a7a(main)

做了什么

  • 增加宿主机 Looper systemd 用户服务:离线 Vosk 唤醒、Silero VAD 断点、SenseVoice 中文转写和 Piper 播报;USB 声卡启动音量固定恢复到 30%。
  • 交互改为严格单轮两阶段:单独说 Looper 并静音 0.5 秒后播放预生成的“我在”,播完 才打开命令录音;每次只处理一句,回答后重新等待唤醒,避免环境谈话误触发。
  • OpenClaw 改用 gpt-5.6-luna、thinking off、fast mode,并去掉默认 agent 的无关技能; 数采插件拆成只读状态工具和需要单独授权的录制写工具。
  • Piper ONNX 会话在服务启动时加载并借“我在”完成预热,后续回答直接复用,不再为每条 回复重新启动 TTS 进程。

为什么

  • 原流程在 Vosk 半句结果中立即触发,并把唤醒尾音带进命令录音;回答后还会自动监听 8 秒,容易误收周围谈话。gpt-5.6-sol 和冗余技能上下文也不适合短语音问答。

怎么验证的

  • USB 音响到麦克风的声学回环成功检测 Looper,日志确认 pause_sec=0.5、缓存“我在” 播放后才进入 SenseVoice 命令监听;服务重启后左右 PCM 均为 30%。
  • Luna + Fast 短回复总耗时由 23.6 秒降到 17.0 秒,agent 阶段由 12.7 秒降到 6.3 秒; 完整数采状态工具问答约 31.8 秒,较此前约 37 秒缩短。19 项相关测试全部通过。
  • Piper 首次加载加合成耗时 2.014 秒,预热后的完整回答合成只需 0.446 秒。

2026-08-13 · 修复 Insight3 拼接断流和运动误触发

提交:58bde13(main)

做了什么

  • 删除 VIO 重置候选的 4 帧阻塞缓存;每个输入样本现在同步产生一个输出,候选命中时 当帧完成 SE(3) 校正,不再让 3D 模型因 Pose 超时而消失。
  • 自动拼接增加 Insight3 原生 vio_status 门控:仅 TRACKING_STATIC 时允许校正;普通 TRACKING 运动期间只统计候选,不再根据低门限创新修改坐标。
  • vio_continuity 增加设备 tracking 状态、门控结果和输入/输出累计计数,现场可直接 检查 input_samples == output_samples。

为什么

  • 初版仅靠恒速预测的 3 cm / 5° 创新无法区分真实快速运动和坐标重置,实机已将 Insight3 A/B 的正常运动误判 44/9 次,累计产生约 38.6° 和 0.79 m 错误校正; 反复等待确认还使全局 Pose 间歇断流。

怎么验证的

  • 7 个实时合成场景通过,Python 编译和 git diff --check 通过。
  • 重启 localizer 后两路错误累计校正归零;实机状态分别记录 Insight3 A 600/600、Insight3 B 702/702 个输入/输出样本,pending_frames=0,证明实时链路 不再扣留 Pose。

2026-08-13 · 加速录制回放准备

提交:6e4c22e(main)

做了什么

  • 时间轴扫描直接从 SQLite 读取 recorder timestamp,不再载入图像 BLOB;Pose 和编码 阶段也只查询所需 topic,减少 rosbag2 reader 的额外开销。
  • 高分辨率 JPEG 在不低于最终画面所需尺寸时使用解码器原生半尺寸解码;Jetson NVENC 路径直接向 nvvidconv 提交 BGRx,移除 CPU 全帧色彩转换。
  • 回放清单和状态 API 增加扫描、编码、轨迹插值与总耗时;缓存 schema 升至 5,并同步 更新 rosbag 列表的 ready 判定。

为什么

  • 录制结束后虽然会后台生成回放,但未命中缓存时仍需等待完整的图像解码和视频编码; 110 秒实测录制原流程约需 145 秒,主要瓶颈是 JPEG 解码和 CPU 色彩转换。

怎么验证的

  • 相关测试 30 项、Python 编译和 git diff --check 通过;服务重启后实际 API 全流程 生成 3262 帧、1280×720、30 fps H.264 回放,耗时 58.3 秒,较旧流程缩短约 60%。
  • 独立基准为 46.2 秒;新旧完整视频 SSIM 为 0.9967,ffprobe 确认帧数、尺寸、帧率和 时长正确,rosbag 列表将新缓存识别为 ready。

2026-08-13 · 自动拼接 Insight3 VIO 瞬时坐标重置

提交:33c86e0(main)

做了什么

  • 两路 Insight3 在进入全局重定位前分别维护局部 VIO 连续坐标系;恒速预测出现 3 cm / 5° 以上创新时暂存 4 帧,确认新分段稳定后对其应用 SE(3) 刚体校正。
  • 拼接不再要求腕部相机持续看见 Insight9 特征;超过 50 ms 的跟踪空洞不猜测跨段 运动,地图匹配仍单独负责缓慢累计漂移和绝对全局校正。
  • /insight_global/<name>/status 新增 vio_continuity,报告拼接、拒绝候选、空洞、 累计校正和最近一次事件;确认事件同时写入 localizer warning 日志。

为什么

  • Insight3 偶发一次 VIO 坐标系偏移后通常会继续稳定跟踪,但旧的 T_map_odom 会让后面整段左右腕全局位置保持固定误差;腕部视野经常没有 Insight9 地图特征, 不能依赖下一次 PnP 重定位及时恢复。

怎么验证的

  • 7 个合成场景通过:静止跳变、运动中平移和旋转跳变、连续两次重置、真实高速 运动、跟踪空洞、普通时间戳回退及候选确认期间的时间戳回退。
  • Python 编译与 git diff --check 通过;实际重启 insight3-global-localizer 后, Insight3 A/B 两路 ROS 状态均持续发布,vio_continuity 为独立 tracking 状态, 即使当前 localized=false、看不到足够地图特征也正常工作。

2026-08-13 · 加速 rosbag 合包

提交:f906e11(main)

做了什么

  • 正常录制合包改为直接批量复制 SQLite 中的序列化消息,统一重映射 topic ID, 并在插入阶段完成各连续 topic 的启动偏差裁剪,不再逐消息经过 ros2 bag convert。
  • 临时输出完成消息数、topic 时间边界和 SQLite quick_check 后才原子发布;输入布局 不兼容或任何验证失败时自动回退到官方 convert。损坏 staging 的恢复探测继续固定使用 官方 convert,避免绕过 CDR 可读性检查。
  • API 增加 recorder 停止与数据库合并分阶段耗时;Recording 页面在合包期间显示 Finalizing recording 并禁用开始按钮,完成后显示快速路径或 fallback 的实际耗时。
  • 麦克风不可用时 voice worker 重启改为 2、4、8、16、32、60 秒指数退避,稳定运行 30 秒后重置,避免反复加载 Vosk 模型与合包争抢资源。

为什么

  • 原流程需要将 7 个 SQLite 分片通过 rosbag2 逐消息读取并完整重写,1.2–1.9 GB 录制 停止后的收尾实测约 12–28 秒;修改 SQLite storage 参数的 A/B 测试没有收益。

怎么验证的

  • 相关 Python 测试 26 项通过,Python/JavaScript 语法、前端构建和 git diff --check 通过;headless Chromium 打开 Recording 页面无控制台错误。
  • 475 MB 真实 bag 单输入测试:快速路径含裁剪与验证 2.34 秒,官方 convert 加同样裁剪 3.57 秒,快约 35%。拆成四个真实分片后分别为 2.09 秒和 2.79 秒,快约 25%。
  • 两种四分片输出的 18 个 topic、19,936 条消息起止时间与计数一致;逐 topic、timestamp 顺序对全部序列化 payload 计算 SHA-256,哈希完全一致,ros2 bag info 可正常读取。
  • 实机日志确认 voice worker 退避依次达到 2、4、8、16、32、60 秒;所有临时基准输出 验证后已删除。

2026-08-13 · Recording 可选未矫正图像流

提交:4eb1226(main)

做了什么

  • Jetson NX 的 Recording topic 列表不再隐藏相机发布的 7 路未矫正 image_raw 流。
  • 未矫正流仅供手动选择;默认录制仍使用三路 dashboard 主图像流,不增加默认采集负载。

为什么

  • 标定和诊断场景需要按需录制未矫正图像,此前设备 profile 会在 topic catalog 生成前将这些流过滤掉,前端无法选择。

怎么验证的

  • topic catalog 逻辑检查确认 7 路未矫正图像全部可见,且与默认选择集合的交集为 0。
  • 重启 dashboard 后,真实 /api/recording/topics 返回全部 7 路;无头 Chromium 加载 Recording 页面确认 7 个复选框均存在且未勾选。

2026-08-13 · 移除 rosbag 主机同步

提交:c3b383d、e746539(main)

做了什么

  • 删除本地复制和 SSH/rsync 两种 rosbag sync to host 实现,不再在录制合包后自动同步。
  • 清理 RecordingManager 的同步参数、syncing 状态、sync_status API 字段及相关环境变量读取。
  • 从三套设备 profile 和当前 live 配置移除主机同步目标与自动同步开关。

为什么

  • 当前工作流不再需要将录制结果自动复制到主机;保留该功能会延长录制收尾,并产生 不必要的磁盘、CPU 和网络负载。

怎么验证的

  • 相关 Python 测试 22 项通过;修改文件编译、三套 profile 与 live JSON 解析、 git diff --check 均通过。
  • 重启开发容器后,dashboard 正常监听;容器内请求 /api/recording/status 成功, 响应不再包含 sync_status,录制状态为 idle。

2026-08-13 · 修复首次打开 3D 页面无轨迹

提交:3c09808(main)

做了什么

  • 在建立 Pose WebSocket 前启用轨迹处理,保证连接首包的完整轨迹快照被接收。
  • 继续分阶段启动相机、rosbag 列表和 Avatar,不恢复首屏的其他重负载。

为什么

  • 11d8a4f(2026-07-24)为了首屏性能将轨迹延迟 1.2 秒启用,但 WebSocket 首包是唯一无条件完整快照;首包提前到达时会被忽略,后续增量包又缺少本地基线。
  • 该问题一直受页面和网络时序影响,所以之前可能正常,后来才稳定复现。

怎么验证的

  • 实际页面首包收到 Insight3 B 和 Insight9 各 300 个历史点;5 秒后 Babylon 已创建 trail-left_hand 和 trail-head mesh,每条 1800 顶点,页面无 JavaScript 错误。

2026-08-13 · 3D 实时与回放原生分辨率

提交:881f5cd(main)

做了什么

  • 正常 3D 界面的 Babylon hardware scaling 从 1.5 改为 1.0,回放模式从 2.5 改为 1.0,canvas 按 CSS 尺寸一比一渲染,不再放大低分辨率缓冲区。
  • 显式开启 OBS mode 时仍保留 2.0 降分辨率模式,用于录屏或性能紧张场景。

为什么

  • 原正常模式只渲染界面尺寸约 2/3 的宽高,回放模式只渲染约 40%, 再由浏览器拉伸,网格、模型和轨迹都会明显模糊。

怎么验证的

  • 1600×1000 无头 Chromium 实测:正常模式 CSS/渲染像素同为 1166×1000, 回放分区同为 1526×560,页面无 JavaScript 错误。
  • 回放 3D 画布约 85 万像素,低于正常全高模式的 116 万像素,清晰度提升后 不会比正常 3D 视图更重。

2026-08-13 · 回放三路画面横向大屏展示

提交:fcb9d63、bb50ac1(main)

做了什么

  • 准备完成的 rosbag 回放启动后,3D 工作区改为上下分区:3D 场景保留在上方, 三路同步相机画面在下方以三列横向铺开。
  • 回放监看区显示 Playback monitor / Synchronized views;停止回放或返回实时模式时, 自动恢复原有左侧纵向 Camera wall,不影响实时采集布局。
  • 3D 渲染器监听 canvas 实际尺寸变化并重算渲染缓冲区;回放分区后只改变视角范围, 不再将原全高 3D 画面竖向压缩。

为什么

  • 回放与实时监看原先共用 280–360 px 宽的左侧栏,三路回放画面纵向挤在窄栏内, 无法看清操作细节。

怎么验证的

  • 重新构建 web_dashboard/dist,JavaScript 语法检查和 git diff --check 通过。
  • 1600×1000 无头 Chromium 实测:三路面板从左栏约 335×293 切换为横向并排的 493×355,完整占用 1502 px 宽度,页面无 JavaScript 错误。
  • 分区后 canvas CSS 高宽比为 2.725,Babylon 渲染缓冲区为 2.727,仅有像素取整误差; 无头截图确认网格与坐标轴无竖向变形。

2026-08-12 · USB 麦克风离线声控录制

提交:e2de598(main)

做了什么

  • 新增独立 Vosk 中文识别 worker,通过 plughw:YDPI4MIC,0 把四通道 48 kHz USB 麦克风转换为单通道 16 kHz,并只监听“开始录制”“结束录制”“停止录制”。
  • 声控使用服务器默认 topics 创建 voice_record_*,仅允许停止同一控制器创建的 录制,不会误停网页手动录制;保留合包状态和磁盘低于 10%时的自动开始保护。
  • 开发与客户 compose 映射 /dev/snd;镜像固定安装 ARM64 Vosk 0.3.45、ALSA 工具和 校验 SHA-256 的中文小模型。Recording/Settings 页面增加监听状态和即时开关。
  • jetson-nx profile 默认开启,其他 profile 默认关闭;补充使用、部署排障和工程约束。

为什么

  • 采集人员需要在双手忙于操作时无需触碰网页即可开始和结束一段示教录制,同时不能让 常驻音频识别抢占 ROS 图像 callback 或因误识别中断其他来源开始的录制。
  • 设备可能离线运行,因此识别模型随发布镜像交付,音频不上传也不保存。

怎么验证的

  • 实机识别 Yundea IOT YDPI4MIC,确认原生四通道 48 kHz、ALSA 单通道 16 kHz 转换和 容器 /dev/snd 映射;状态 API 为 voice listening,实际 grammar 为模型词表支持的 开始 录制 / 结束 录制 / 停止 录制。
  • ARM64 开发镜像重建成功,Vosk wheel 和中文模型校验通过;完整容器 22 项测试通过。
  • 无头 Chromium 加载 Recording 与 Settings 页面,声控状态和开关正确,两页无控制台错误。

2026-08-12 · 标注测试资产本地化与安装包排除

独立仓库提交:cdf34c4;历史已重写

做了什么

  • tests/ 改为本地忽略目录:测试文件继续保留和执行,但不再由 Git 跟踪或上传 GitHub。
  • 增加 MANIFEST.in 并在 setuptools package discovery 中排除 tests,阻止测试目录和 test_*.py 进入 wheel 或 sdist。
  • 重写独立仓库四个提交的 main 历史,从所有提交移除 tests/,并用旧远端 SHA 保护的 --force-with-lease 更新 GitHub。

为什么

  • 测试代码属于本地开发验证资产,不是该工具的发布内容;只在最新提交删除仍会让 GitHub 历史保留完整测试文件,因此需要同时清理历史和构建清单。

怎么验证的

  • 本地忽略的 7 项测试全部通过;git ls-files tests 和重写后 main 的对象列表均为空。
  • 完整检查生成的 wheel 与 sdist 文件列表,均不包含 tests/ 或 test_*.py。
  • 本地 HEAD 与 origin/main 同为 cdf34c4,受保护的强制推送成功。

2026-08-12 · 标注仓库开发约束与 Dashboard 残留清理

提交:独立仓库 0fb16da;Dashboard fa53956

做了什么

  • 在 robot-dataset-annotator 跟踪内容一致的 AGENTS.md / CLAUDE.md,规定路径确认、 core/tasks/adapters 分层、新任务测试、Skill 校验、文档同步及默认提交推送要求。
  • 从 Dashboard 删除杯子专用 pipeline、升级脚本、测试和专题文档,并移除 Dataset 页与后端 的 cup_grasp 模式;保留通用 LeRobot、UMI、ego-hand 和停顿自动切分能力。
  • 删除已被 process-robot-datasets 取代的旧 process-cup-rosbags Skill。原始 rosbag、 审核证据和已生产数据集继续保留。

为什么

  • 任务语义、自动边界、人工审核和批次恢复已经由独立项目负责;采集产品继续保留重复入口会 形成两套实现和文档,后续修复容易漂移。
  • 开发约束必须随代码仓库迁移并上传,不能只存在某一台机器的本地助手目录。

怎么验证的

  • 独立仓库 7 项测试和 Skill 结构校验通过,AGENTS.md / CLAUDE.md 内容一致,源码和 Skill 未发现设备绝对路径;提交已推送到 main。
  • Dashboard 前端重新构建,JavaScript/Python 语法检查和容器内 20 项测试通过;实际加载 Dataset 页面并完成 rosbag 列表渲染,只显示 bag 与 auto_pause。
  • 全仓扫描不再存在杯子 pipeline、模式、文档或旧审核脚本引用;Dashboard 提交已推送。

2026-08-12 · 多任务数据标注独立仓库与可迁移 Skill

独立仓库:robot-dataset-annotator, 提交 e47686c、0de0732、0fb16da

做了什么

  • 建立独立 robot-dataset-annotator 项目,把决策 schema、分段插件、产物审计、批次恢复和 Insight 低维适配从采集产品职责中分层;纸杯任务成为首个插件,后续任务不再复制流水线。
  • 决策 schema v2 支持一个 source segment 保存多个完整 episode,并在昂贵导出前检查 穷尽覆盖、边界单调、区间不重叠和每个原子动作的最短帧数。
  • 新增标准 process-robot-datasets Skill;执行前必须向用户确认工作区、输入、审核、输出、 task spec 和运行环境,不再内置设备绝对路径。旧杯子 Skill 同步改为显式路径兼容入口。
  • rda resume 根据审计结果渲染 session 中的 argv 命令,默认仅预览;显式 --execute 后才 执行下一步,不通过宿主 shell 拼接用户路径。
  • 汇总 30 包生产数据和瓶颈,明确优先改进交互式审核、自动门召回率、重复编码、验证环境和 磁盘保护。

为什么

  • 标注任务的语义、人工审核和训练格式迭代速度高于采集产品,不应继续与 Dashboard、设备 profile 和 ROS 生命周期耦合。
  • 本轮 2,178 页审核和约 23 GB 中间产物是主要成本;重启后旧 campaign report 还可能停在 PROCESSING,必须改为由文件证据恢复。
  • 自动候选正确率达到 99.8%,但只覆盖 83.1% 的人工有效数据;继续堆固定拒绝阈值会提高 误杀,而不是提高生产效率。

怎么验证的

  • 新项目 core、状态恢复、多 episode schema、插件加载和杯子边界共 6 项测试通过,源码完成 编译检查,Python 包在 Jetson 现有 setuptools 环境中离线构建并安装成功。
  • 通用 Skill 通过官方 skill 结构校验,且扫描确认 Skill 内没有设备/工作区绝对路径。
  • 本轮 30 份真实 review manifest/decisions 全部通过新校验器;新审计器完整发现 30 个输入并 依据实际产物给出阶段,不依赖旧 watcher 状态。

2026-08-12 · 录制后预生成单视频 30 Hz 审阅包

提交:fca1da5(main)

做了什么

  • 每个 rosbag 在自身 review/ 目录保存一个 1280×720、30 Hz 的 H.264 审阅视频和 manifest;三路相机按 recorder timeline 对齐后拼在同一画面,附相机名、时间码和重复帧 标识,3D Pose 仍按同一固定时间轴插值。
  • Jetson 优先使用 nvv4l2h264enc 硬件编码,浏览器只解码一个视频;旧的三路独立视频 变速追赶不再用于新 schema。审阅包用临时目录和可恢复原子替换,失败不损坏 rosbag。
  • 合包完成后自动进入空闲后台队列;开始录制时立即暂停。历史包可在 3D 页点 Prepare all,也可运行 scripts/build_review_bundles.py --all;CLI 无法确认录制状态时 默认拒绝执行。
  • Bags 列表显示 review pending/building/ready/invalid 与 pass/warning;回放页面按浏览器 原生媒体总帧/丢帧计算实际呈现 FPS,避免 Firefox 节流 frame callback 导致约 24 fps 的误报。

为什么

  • 原实现点击 Play 后才扫描和编译三路视频,人工质检必须等待较长编码过程;浏览器同时 解码三路并做独立同步也会争抢 3D 渲染预算,现场难以稳定复核图像和轨迹。
  • 审阅属于录制后的派生工作,应从采集关键路径移开并提前生成;录制期间必须始终优先保证 原始数据完整性。

怎么验证的

  • 15.03 秒三相机实包生成 451 帧、严格 30/1 fps 的 1280×720 视频,三路重复帧均为 0,最大同步偏差 13.85 ms;成品 11.34 MB,旧三视频缓存合计约 25.27 MB。
  • Firefox 原生媒体计数为 451 总帧、1 丢帧,等效约 29.93 fps;文件逐帧时间戳间隔均为 33.333 ms。缓存命中约 0.087 秒,MP4 Range 请求返回 206。
  • 相关 Python 回归测试 14 项通过;前端完成构建和语法检查,3D 页实际列出 106 个包, Prepare all、Play 均可用且控制台无错误。

2026-08-11 · 纸杯 LeRobot 的 OpenPI 分段与夹爪有效性

提交:61e89ff(main)

做了什么

  • 对相邻帧超过 30 mm 的夹爪宽度跳变增加逐侧检测:保留有限原始值,把落点宽度维度的 state/action validity 标为 false;孤立尖峰恢复帧重新有效。
  • 把通常不足 10 帧的 close_grippers 合入搬运动作,标签改为接近、夹持并搬运、释放、 撤离四段;边界自动重分配,保证每段至少 10 帧。
  • 保留官方 LeRobot v3 的 action,同时增加数值一致的 OpenPI 默认字段 actions 及 actions_valid;修正 tasks.parquet 的命名 pandas index,使官方 loader 返回任务字符串。
  • 增加已有纸杯分片的无视频重编码升级命令,并把后续生产导出、质量报告、验证报告和文档 纳入同一规则。

为什么

  • 25 条数据出现 319 个超过 30 mm/frame 的夹爪跳变,不能让异常宽度进入训练损失,但也 不应改写或删除原始有限测量值。
  • OpenPI 以 10 帧为一个推理块;旧数据有 19 个动作段不足 10 帧,最短 1 帧,独立的闭合 标签会在训练取窗时吸收相邻语义。
  • OpenPI 默认动作序列键是 actions,而 LeRobot 官方 loader 仍依赖 action,需要双键 无歧义兼容。

怎么验证的

  • 三份正式分片共 25 条、4011 帧全部升级并完整解码三路视频;100 个动作段最短 10 帧, 不再存在短段。319 个跳变边全部被 validity 覆盖,最终左/右分别标记 99/170 个无效宽度帧。
  • MP4 升级前后 SHA256 一致;腕部仍为 544×640、头部仍为 1088×1920,没有缩放或重编码。
  • 官方 lerobot==0.4.4 的 LeRobotDataset 实际加载 12 条正式分片,跨 episode 取样并以 PyAV 解码三路原图;DataLoader batch size 2 得到 [2,20] 的 state/action/actions, 两套动作字段一致且任务为字符串。
  • 加载 ROS 环境后完整 25 项 pytest 通过;新 25 条审阅归档附独立校验报告和 SHA256。

2026-08-11 · 原分辨率纸杯 LeRobot 生产流水线

提交:011b8c5(main)

做了什么

  • Dataset 页面增加 Production cup grasps · filter, label, verify,固定 LeRobot、双臂 三相机与原始分辨率;前后端同时拒绝该模式下的 224/384 请求。
  • 新增 cup_lerobot_pipeline.py:按停顿切候选段,只保留完整开—闭—开夹爪循环,排除 空闲/人工纸杯复位,并沿用 VIO 位姿连续性门剔除漂移段。
  • 为每条 episode 写入接近、夹持、搬运、释放、撤离五类逐帧 task_index 和 meta/segments.parquet,同时生成质量报告、验证报告和动作代表帧联系表。
  • 每个 rosbag 独立生成 <bag>_cup_lerobot/,累计结果写入 cup_catalog.json,直接显示 当前有效 episode 数及距离 500 条的差额。

为什么

  • 普通停顿切分只能识别夹爪静止,无法排除操作者在夹爪不动时用手复位纸杯,也会保留 没有夹取动作的空闲小节。
  • 正式 500 条训练数据需要保留原始画面,且要有可重复、可审计的漂移剔除、动作标注、 分片验收和进度统计,不能依赖每包一次性的人工脚本。

怎么验证的

  • 容器全量 22 项 pytest 通过;前端重新构建,无头浏览器选择生产模式后确认 LeRobot、 bimanual、original 全部锁定且无控制台错误,API 对 224 请求返回明确拒绝。
  • insight_record_20260811_115900 实际自动生成 4 条、639 帧、31.95 秒原图数据:腕部 544×640、头部 1088×1920、三路 20 Hz,输出约 127 MiB。
  • 三路 H.264 均完整解码 639 帧,所有图像 validity 有效,20 个动作段无空洞/重叠, state/action 无 NaN/Inf;4 个空闲/复位段和 5 个 Insight3 B 位姿不连续段被排除。

2026-08-11 · 回放统一使用 rosbag record timestamp

提交:7765ac3(main)

做了什么

  • 预准备回放扫描图像与 Pose 时统一采用 rosbag record timestamp,并将缓存 schema 升级为 v3,旧缓存会自动重建;原始 header.stamp 不再参与跨相机共同时间段计算。
  • 增加跨时钟域回归测试,覆盖 Insight3 使用 Unix/NTP 时间、Insight9 使用设备启动时间但 record timestamp 对齐的情况。
  • 明确轨迹跳变的离线补救边界:不得直接低通平滑;孤立且前后稳定的刚体重置可切段重锚, 多次米级跳变或单臂全局 Pose 失配需用本地 VIO 和稳健 map-to-VIO 对齐重建,无法验证则重录。

为什么

  • 两个最新 rosbag 的各路数据在 record timeline 上有完整交集,但 Insight3 与 Insight9 的 原始 header 属于不同时间基准。旧逻辑直接比较 header 数值,误报“相机流没有可用共同 回放区间”,导致新包不能回放。

怎么验证的

  • 容器内完整测试 16 项通过,其中新增测试确认不同 header 时钟域不会破坏回放同步。
  • insight_record_20260810_185413 实际生成三路 H.264 30 Hz、各 1403 帧; insight_record_20260810_185527 各 1303 帧。两包均成功进入 playing,三路 Range 请求 返回 206,停止后正常回到 idle。
  • 第二包 Insight3 A 在约 18.2~25.5 秒出现多次跳变,最大约 3.93 米,而 Insight3 B 与 Insight9 无同类跳变;该区间判定为单臂全局位姿污染,不适合插值或平滑。

2026-08-10 · LeRobot 自动识别夹爪与手姿示范

提交:1aa6abc(main)

做了什么

  • Dataset 页面启动 LeRobot 导出时先抽样两路腕部图像,重复检测到 UMI ArUco ID 1/0 双标记则走原有 UMI 夹爪路线;两路均无双标记则走三视角 Ego/WiLoR 手姿路线。
  • 无标记路线自动把整条 rosbag 生成为单 episode、单动作段 spec,使用页面任务文本;保留 三路原图,手姿只从 Insight9 头部 RGB 推理。
  • 页面增加检测阶段、当前路线和每包最终路线显示,并明确单臂/双臂、停顿切分及图像缩放 只影响夹爪路线。

为什么

  • 旧页面的 LeRobot 与 Legacy UMI 选项实际都依赖夹爪标记;已经实现的 Ego 手姿流水线 没有接入网页,操作者必须预先知道录制类型并手工运行命令。

怎么验证的

  • 容器单元测试 5 项通过,前端重新构建并通过 Chromium 无头加载及 rosbag 列表渲染。
  • 最新两包 185413、185527 均在抽样 2~3 帧后判为 umi_gripper;已知纯手部包 20260807_144636 抽样 494 帧无双标记,判为 ego_hand。
  • 两个最新包的夹爪双标记全量检出率分别为 A/B 85.8%/81.3% 和 86.7%/83.4%。转换预检 仍因 Insight3 A 位姿跳变拒绝,未触发正式导出或源包重命名。

2026-08-10 · Insight9 单目 MediaPipe Full 实时手部追踪稳定化

状态:insight9_qr_hand_tracker 工作区实现,尚未合入 insight-capture-dashboard 的 main

做了什么

  • 将实时手部推理默认链路固定为本地 MediaPipe Hand Landmarker Full Task:模型文件 models/hand_landmarker.task 的 SHA256 为 fbc2a30080c3c557093b5ddfc334698132eb341044ccee322ccf8bcf3607cde1,包内为 Full 版 hand_detector.tflite 与 hand_landmarks_detector.tflite;不在线下载权重。
  • 默认使用 CPU/XNNPACK、VIDEO 模式、最多 2 只手,检测/存在/跟踪置信度均为 0.5;输入为 /insight9_a/camera/color/image_rect_raw/compressed 解码后的整幅 RGB,并将 ROS 图像消息 时间戳传给 detect_for_video。MediaPipe 直接处理原始宽高,不再先 letterbox 到 512×512。
  • 默认后端由 TensorRT 改为 MediaPipe,UMI ArUco 检测与米制融合默认关闭;常规流程明确为 “单路 RGB → 手掌检测 → 21 点手部姿态 → 视频时序跟踪”。该实时链路没有使用双目或 WiLoR,world_landmarks 仍是单目网络估计的手部相对三维结构。
  • 固定 Ubuntu x86_64 参考依赖为 Python 3.10.12、MediaPipe 0.10.35、OpenCV 5.0.0.93、 NumPy 2.2.6 和 rosbags 0.11.3;Jetson aarch64 因官方 0.10.35 无对应 wheel,保留加载 同一 Task 权重的兼容依赖清单。README、Docker、Compose、入口脚本和模型校验同步更新。
  • 针对“骨架比视频慢半拍”,在浏览器端加入有界手掌速度前向预测:以推理端到端延迟减去 WebRTC jitter buffer、浏览器解码和传输预算得到补偿时长,每个视频帧重新绘制骨架;预测 时长、速度和最大位移均有限制,原始 MediaPipe 结果及 world_landmarks 不变。可用 ?posePrediction=0 关闭补偿进行对照。
  • WebRTC 接收端请求最小播放缓冲,并上报实际解码 FPS、jitter buffer 和解码处理耗时; 重连前完整释放旧 RTCPeerConnection、媒体 track、统计定时器和回调,只允许一个重连 任务,避免摄像头断流后持续累积浏览器资源。
  • 针对 Firefox 偶发显示“标签页已崩溃 / Restore”,增加独立页面心跳和 kiosk watchdog: 页面每 2 秒报告一次,内容页崩溃但 Firefox 主进程仍存活时,守护程序会结束旧会话并在 约 15 秒内自动重新打开全新页面,不再依赖人工点击 Restore。

为什么

  • 现场原部署虽然已经包含目标 .task 文件,但 Docker/Compose 默认选择 Jetson TensorRT ONNX/FP16 后端,时间戳使用单调时钟,输入还经过 512 方形缩放,并默认运行可选 ArUco 分支,不能严格代表指定的单路 RGB MediaPipe Full 配置。
  • 实测视频解码约 30 fps,而 Full CPU 推理一度只有 9.5~10.6 fps,单帧推理约 89~121 ms,端到端姿态延迟约 109~161 ms,因此骨架天然落后视频约 3~5 帧。 MediaPipe LIVE_STREAM 可以丢弃排队输入,但不能缩短单帧计算时间;当前单槽最新帧策略 已避免旧帧排队,所以增加显示侧有界预测来降低感知延迟。
  • Firefox 日志多次记录子进程被 SIGKILL 和 RemoteTexture ready timeout;检查时 Jetson 7.4 GiB 内存已使用约 5.1 GiB,3.7 GiB Swap 已使用约 2.8 GiB。旧守护程序只能发现 Firefox 主进程退出,无法处理内容页单独崩溃;WebRTC 失败路径也存在过期 peer/定时器 未释放的风险。

怎么验证的

  • 模型 SHA256 校验通过,Task 包确认只包含指定的两个 Full TFLite 模型;MediaPipe adapter 测试验证本地模型、VIDEO、2 手、三个 0.5 阈值、整幅非方形 BGR→RGB、ROS 时间戳透传和按原图宽高还原 21 点坐标。
  • 真实运行基线通过 /api/health 与浏览器 WebRTC stats 采集:输入约 30.3 fps、推理约 9.5 fps、推理 121.5 ms、端到端 161.1 ms;浏览器解码约 30.8 fps,确认延迟主要来自 Full CPU 推理而不是网络 jitter。不同输入分辨率实测只能节省约 10 ms,不足以根治。
  • 新增模型/参数/时间戳、浏览器心跳和 kiosk 自动重启测试;最终完整 35 项 pytest 全部通过, node --check web/app.js、Python compileall、入口 Shell 语法、Compose 配置解析和模型 SHA256SUMS 校验均通过。
  • watchdog 测试模拟 Firefox 主进程仍存活但页面心跳停止,确认会终止旧进程并进入自动重开; WebRTC 清理逻辑同时覆盖旧连接晚到事件,避免误停刚建立的新视频流。

2026-08-10 · MediaPipe、WiLoR、HaMeR 手部姿态双目与 RGB 融合验证

状态:gesture 工作区验证原型,尚未合入 insight-capture-dashboard 的 main

做了什么

  • 确认当前 MediaPipe 使用 Google 官方 Hand Landmarker Full float16 v1 模型包,不是 EgoScale 私有模型或本地训练权重;模型 SHA256 为 fbc2a30080c3c557093b5ddfc334698132eb341044ccee322ccf8bcf3607cde1,内部包含 hand_detector.tflite 和 hand_landmarks_detector.tflite。当前推理环境固定为 Python 3.10.12、MediaPipe 0.10.35、OpenCV 5.0.0、NumPy 2.2.6 和 rosbags 0.11.3。
  • 以 insight_record_20260810_160646 为验证数据,实现 MediaPipe、WiLoR、HaMeR 三套 双目流程:分别对同步的左右红外图像推理,按手别与极线一致性匹配,再使用 bag 内左右 CameraInfo.P 投影矩阵对 21 个关节做三角化;overlay 显示绝对深度、极线误差、重投影 误差和深度有效性。
  • 新增 HaMeR 双目入口和三算法对比合成;双目独立视频统一为 1088×640、511 帧、20 fps, 三栏对比视频为 1920×376、511 帧、20 fps。
  • 增加 RGB+双目融合:以 766 帧/30 fps RGB 为主时间轴,为每帧选择 30 ms 内最近的 20 fps 双目结果;读取 /tf_static 中 insight9_a_camera_left → insight9_a_camera_rgb 外参并取逆,将左红外坐标系的三角化 3D 点变换到 RGB 相机坐标, 再通过 RGB CameraInfo.K 投影、匹配同一只手。
  • 对每只匹配手使用鲁棒 Sim(3) 将 RGB 网络的完整手部姿态先验对齐到双目 3D;根据极线 误差、重投影误差和逐关节残差分配融合权重。可靠双目关节提供绝对位置和尺度,异常或 遮挡关节降低双目权重并由 MediaPipe/WiLoR/HaMeR 姿态先验补齐。JSON 同时保留 stereo_xyz_rgb_m、aligned_network_xyz_rgb_m 和最终唯一结果 fused_xyz_rgb_m。
  • RGB 融合 overlay 最终改为高区分度配色:红色为 RGB 网络原始姿态,黄色为原始双目 投影,蓝色粗线为最终融合姿态;灰色表示当前帧只有 RGB 网络结果、没有可靠双目约束。 三算法 RGB 融合视频均为 1088×1920、766 帧、30 fps,三栏对比为 1920×1128、 766 帧、30 fps。
  • 主要脚本位于 /home/dm/workspace/gesture/scripts/: extract_stereo_mediapipe.py、extract_stereo_wilor.py、 extract_stereo_hamer.py、extract_rgb_stereo_fusion.py 和 compose_stereo_comparison.py。视频与结构化结果分别位于 output/stereo_compare/ 和 output/rgb_stereo_fusion/。

为什么

  • 单目 RGB 网络擅长根据手部结构先验恢复手指姿态和被遮挡关节,但 MediaPipe world_landmarks 是手中心相对坐标,WiLoR/HaMeR 的单目相机平移和尺度也会受数据域、 遮挡及视角影响;单独使用不能稳定提供可信的绝对 3D 位置。
  • 双目几何可以提供相机空间的绝对尺度与深度,但要求左右两侧都检测成功,且独立关节预测 在遮挡、运动和红外画面上可能不一致。将双目作为 metric anchor、RGB 网络作为姿态先验, 可以同时保留绝对位置和遮挡补全能力。
  • RGB 30 fps 与双目 20 fps 并非逐帧同频;直接混用二维坐标会叠加时间差、分辨率和相机 坐标系误差,因此必须先按 header 时间戳关联,再通过实际内外参完成坐标变换和投影。

怎么验证的

  • bag 内包含 766 帧 RGB 和 511 组时间戳完全一致的左右红外图像。外参方向通过真实关键点 反向验证:按 ROS TF 语义取逆后,双目点投影与 RGB MediaPipe 关键点的中位偏差为 13.8 px;若按相反方向使用外参,偏差约 150 px。

  • 双目独立推理结果如下。MediaPipe 红外适配较弱,配对 270/511 帧;WiLoR 与 HaMeR 共用 WiLoR YOLO 手框检测器,均配对 486/511 帧。有效三角化手分别为 406/408、 789/791、789/791;深度中位数分别为 0.494、0.554、0.500 m。

    算法 双目配对帧 配对率 重投影误差中位数
    MediaPipe 270/511 52.8% 0.58 px
    WiLoR 486/511 95.1% 1.05 px
    HaMeR 486/511 95.1% 0.62 px
  • RGB+双目融合全量结果如下。最近双目帧的时间差中位数为 12.69 ms,最大 27.50 ms; 三种算法均低于 30 ms 门限。

    算法 RGB 帧 有双目约束帧 融合手数 投影匹配误差中位数
    MediaPipe 766 399 608 13.81 px
    WiLoR 766 723 1175 14.38 px
    HaMeR 766 725 1177 14.48 px
  • RGB 中手部框对角线中位数约 282~305 px,约 14 px 的跨模态匹配误差相当于手部尺寸的 4.8%~5.2%;94.2%~96.4% 的匹配不超过 40 px。该数值包含 RGB/红外网络差异、最多 27.5 ms 时间差、遮挡预测和标定残差,不能当作纯双目标定误差;双目内部重投影误差仍为 0.58~1.05 px。

  • 三个独立 RGB 融合视频和三栏对比视频均完整写出并逐帧解码,确认 766 帧可播放;JSON 扫描未发现 NaN 或 Infinity。抽查首帧、中段双手帧和末段帧,红色 RGB、黄色双目和 蓝色融合骨架均投影到对应手部,缺少双目配对时正确退化为灰色 RGB 姿态。

2026-08-10 · 支持单路相机回放

提交:573cf0c(main)

做了什么

  • Prepared playback 在生成缓存前按 bag 实际 topic 过滤当前相机与位姿配置;只要至少存在 一路已配置图像即可回放,位姿 topic 可以缺失。
  • Prepared 模式以 manifest 为相机面板真源,只显示实际录制的相机;单路自动填满相机栏, 停止后恢复三路 live 面板。同步清理未录相机的旧 WebRTC、FPS 与 3D pose 状态。
  • 增加单路图像+位姿、纯图像、零匹配和完整三路保序测试。

为什么

  • 旧实现无条件要求当前设备配置中的三路图像和三路位姿全部存在,导致只录一路相机的 bag 在扫描阶段直接报缺失 topic,无法进入编码与回放。

怎么验证的

  • 用仅含 /insight3_a/camera/infra1/image_rect_raw 的真实 bag insight3_a_left_20260803_115721 验证:837 个源帧成功生成单路 H.264 缓存,manifest 为 1 路相机、0 路位姿,输出 1255 帧、544×640、30 Hz;activate/stop 状态正常。
  • 浏览器自动化验证 prepared 时仅显示 insight3_a、状态为 PLAYBACK · 1,停止后恢复 三路 LIVE,无页面异常;既有三路 prepared cache 仍可直接命中。
  • 前端重新构建,JavaScript 语法检查与 13 项单元测试全部通过。

2026-08-10 · 保留 30 Hz 回放功能

提交:b0dbebd(main)

做了什么

  • 撤销 54bc473,继续保留 29de109、b8b23e5、3bc3e31、0439503 提供的播放 平滑、确定性 30 Hz 预准备、编码进度和回放期间 watchdog 处理。
  • 4b0b264 的本地报告、缓存、旧 OTA CLI、死代码和废弃样式清理保持不变。

为什么

  • 经范围确认,这四项属于需要继续保留的回放功能;此前对它们的整体回退不再采用。

怎么验证的

  • 恢复后代码树与 4b0b264 逐文件一致;前端重新构建,JavaScript 语法检查和 9 项单元 测试全部通过。
  • 在无录制任务时重启 insight-dashboard,/healthz 正常;Chromium 无头加载 /3d 成功,页面包含 prepared playback 与编码进度组件。

2026-08-10 · 回退 30 Hz 回放实验(已由 b0dbebd 撤销)

提交:54bc473(main)

做了什么

  • 完整回退 29de109、b8b23e5、3bc3e31、0439503 四个上午提交,恢复到 7aa5b9c 的 Dashboard 回放行为。
  • 删除预准备 H.264 回放、确定性 30 Hz 时间轴、编码进度组件和回放期间 watchdog 特例; 恢复原有 ROS 回放、实时预览、WebSocket 与 3D 渲染路径。
  • 保留 4b0b264 的报告、缓存、旧 OTA CLI、死代码和废弃样式清理结果。

为什么

  • 30 Hz 回放与 FPS 调优没有达到现场稳定性要求,继续保留会增加延迟、画面异常和维护风险; 本次按现场要求回到实验前的已知稳定实现。

怎么验证的

  • 回退后代码树相对 7aa5b9c 只保留 9 个清理文件的差异,四个实验提交没有残留。
  • 重建前端并通过 JavaScript 语法检查;容器内现有 3 项单元测试全部通过。
  • 在无录制任务时重启 insight-dashboard,/healthz 正常;Chromium 无头加载 /3d 与 /recording 均完整生成 DOM,回放编码进度与预准备媒体界面已消失。

2026-08-10 · 清理本地报告与遗留代码

提交:4b0b264(main)

做了什么

  • 删除仓库根目录中未跟踪的报告 PDF、两组报告素材和 dashboard 预览截图,共约 7.7 MiB; .dockerignore 同步加入精确规则,避免同类本地产物进入客户镜像。
  • 删除未被文档、发布包或代码引用的 Looper OTA CLI v1 单体实现(968 行);现行 v2 模块化入口 looper_cli/looper_cli.py 保持不变。
  • 删除未调用的 LeRobot 缓存函数、Optimization 页面局部函数,以及已无 DOM/JS 引用的 旧指标卡、能力列表和 3D 顶栏样式;同步重建前端 dist。
  • 清除源码目录内 Python __pycache__ 和 pytest 缓存;兼容 facade、独立运维 CLI、live 配置、rosbags、runs、outputs 和 release 产物均未删除。

为什么

  • 本地审查产物既污染工作树,又可能随 Docker COPY . 被烘入发布镜像;旧 OTA v1 与现行 v2 重复且不参与发布,继续保留只会增加维护和误用风险。
  • 代码清理以“无入口、无导入、无文档/发布引用”为门槛,避免把动态入口或兼容接口误判为 死代码。

怎么验证的

  • 容器内完整 9 项 unittest 通过;现行 Looper CLI 返回 2.0.0,Compose 配置解析通过。
  • 执行 node web_dashboard/build.js 并检查 JavaScript 语法;Chromium 无头加载 /optimization 与 /3d 均完整生成 DOM,未发现脚本异常。
  • git diff --check、报告/缓存残留扫描通过,Dashboard /healthz 保持正常。

2026-08-10 · 回放期间禁用相机断流看门狗

提交:0439503(main)

做了什么

  • 准备媒体回放激活期间暂停相机无帧/DDS participant 看门狗;停止回放后自动恢复原有断流 检测,录制与正常实时模式的保护逻辑不变。
  • 新增回归测试,保证回放主动暂停实时相机回调时不会被误判为 USB 或 DDS 断流。

为什么

  • 准备媒体回放会有意暂停实时图像回调以保留固定 30 Hz 播放预算,但原看门狗仍检查实时帧 时间戳,导致回放约 15 秒后强制退出 Dashboard 容器;随后 WebRTC worker 和浏览器会话 全部重建,表现为实时画面帧率骤降和卡顿。

怎么验证的

  • 修复前日志稳定复现:Playback mode ON 后约 18.7 秒报告相机超过 15 秒无帧并退出。
  • 修复后激活同一准备缓存并保持约 35 秒,回放状态、容器启动标识和主进程 PID 均保持不变, 日志没有新的看门狗退出。
  • 停止回放后 playback_mode=false,三路实时输入与处理均恢复约 29.9~30.1 Hz;看门狗及 既有回放相关 6 项单元测试通过,无头页面控制台无错误且验证后已关闭。

2026-08-10 · 固定 30 Hz 预准备回放

提交:b8b23e5、3bc3e31(main)

做了什么

  • 点击回放后先扫描 bag,共用一条 30 Hz 时间轴预编码三路 H.264,并预插值整段三路位姿; 所有媒体准备完成后才开始播放,同一 bag 后续直接命中带配置签名的缓存。
  • 以头部视频为主时钟同步三路画面,时钟小偏差用轻微速率修正,避免周期性 seek 造成停顿; 3D 完整轨迹只构建一次,播放期间只更新三个位姿节点。
  • 回放激活后暂停实时 ROS 图像预览、JPEG 和 WebRTC 处理,结束或离开页面后自动恢复;页面 显示固定频率、补帧重复数和最大源时间偏差,便于直接判断数据质量。
  • rosbag 下拉框左侧增加常驻于准备阶段的编码进度组件,明确显示当前编码阶段、百分比和 填充进度;从点击 Play 立即出现,并保持到准备媒体加载完成,失败时自动收起。

为什么

  • ROS 实时重放会同时承担 bag 读取、DDS 发布、图像编码、WebRTC、WebSocket 轨迹和 Babylon 绘制,任何瞬时争用都会直接表现为画面和 3D 卡顿,无法稳定观察 30 Hz 数据质量。
  • 先把随机 I/O、解码和轨迹插值移到准备阶段,可让实际播放只剩浏览器顺序解码和常量级位姿 更新;缺失源帧也会以显式重复帧记录,而不是靠播放时抖动掩盖。

怎么验证的

  • 使用 15.06 秒、557.8 MB 的 insight_record_20260807_142959 完整准备:三路均为 451 帧、 30/1 fps;Insight3 A/B 为 544×640,Insight9 为 408×720。
  • 三路源帧重复数均为 0,最大源时间偏差分别为 3.277、0.037、16.647 ms;HTTP Range 返回 206,缓存再次请求直接进入 ready。
  • Firefox 实际 H.264 回放中 3D 场景达到约 30.04 fps;回放激活后 /api/cameras 三路实时 输入/处理均降为 0,确认后台实时编码不会再抢占播放预算。前端构建、JavaScript/Python 语法检查及新增/既有回放单元测试均通过。
  • 1600×1000 实际页面确认进度组件宽 170 px、位于下拉框左侧且间距 8 px;真实后端编码 状态能更新阶段和百分比,页面控制台无错误。

2026-08-10 · 回放图像与 3D 轨迹流畅度优化

提交:29de109(main)

做了什么

  • Dashboard 回放只发布当前页面实际消费且确实存在于 bag 中的图像、位姿和手部关键点 topic,不再重放未订阅的高频 IMU、VIO 辅助流等消息。
  • 位姿 WebSocket 在首次连接和轨迹 generation 变化时发送完整快照,之后持续发送增量; 取消每 2 秒一次的无条件完整轨迹重传。
  • 新增回放命令单元测试,覆盖 bag topic 过滤、缺失 topic 排除和 remap 参数保留。

为什么

  • 之前回放 19 个 topic、约 1847 条消息/秒,但 3D 页面只消费其中 6~7 个;额外的 rosbag/DDS 负载会与三路 WebRTC 和 Babylon 渲染竞争 CPU。
  • 周期性完整轨迹快照会重复分配、序列化和解析最多 900 个轨迹点,并触发浏览器长帧; WebSocket 本身有序可靠,客户端也会在增量不连续时自动重连获取新快照。

怎么验证的

  • 使用 15.06 秒、557.8 MB 的 insight_record_20260807_142959 在同一 Jetson NX、同一 kiosk 页面做修改前后回放;后端三路输入和处理全程保持约 30 fps。
  • 稳态浏览器呈现由约 12~14 fps 提升到约 18~21 fps;3D 最大帧间隔由 147~190 ms 降到 47~53 ms,单帧工作峰值由 146 ms 降到 12~25 ms。
  • 回放命令确认仅包含 bag 中存在的 6 个展示 topic,回放进程稳态 CPU 由约 23~30% 单核降到约 16~22%;新增单元测试、Python 编译和 diff 检查通过,回放结束后 live 三路恢复约 30 fps,日志无新增异常。

2026-08-07 · Ego 三视角 LeRobot 缓存转换流水线

提交:7aa5b9c(main)

做了什么

  • 新增一条命令完成 rosbag 裁剪、三路 H.264、头部 WiLoR 手姿、相机/pose 对齐、左右手 物理约束、13 段动作标注、LeRobot v3 元数据、质检和 overlay。
  • 三路图像全部交付,但只对头部 RGB 做手姿推理;腕部相机按配置映射为 insight3_b → left、insight3_a → right,且交付外参过滤所有 TCP frame。
  • 增加最终成品缓存和与动作标注解耦的基础视觉/手姿缓存;支持 module:factory 接入其他 手姿模型,后续坐标转换、纠错和写入流程保持不变。

为什么

  • 之前转换依赖多次临时脚本和人工修正,每次重跑都会重复 WiLoR 推理与三路视频编码; 左右手映射、时序误标和动作段也容易在不同版本间漂移。

怎么验证的

  • 当前最终数据审计 PASS:2116 帧、13 段、32 列,三路视频均为 2116 帧/30 fps。
  • 相同规范第二次导出约 1 秒自动命中最终缓存;临时改为一段新标注时约 1.6 秒完成, cache manifest 明确记录 cached_base_reannotation,未运行 WiLoR 或视频编码。
  • 外部模型 factory、动作覆盖和单帧左右手纠错 3 项单元测试通过;命令帮助和 Python 全量编译通过。

2026-08-07 · 移除网页三相机时间复核页

提交:221e9a0(main)

做了什么

  • 从 Rosbags 侧栏、Dashboard 路由和前端构建入口中移除三相机秒表时间同步复核页。
  • 删除该页的 HTML、JavaScript、专属样式及已生成的 dist 文件,旧地址不再能直接访问。
  • 相机校时与相位验收脚本保持不变,时间分析不再作为产品网页功能分发。

为什么

  • 三相机时间分析属于专项验证内容,不应出现在交付网页前端中。

怎么验证的

  • 重新执行 node web_dashboard/build.js,确认构建成功且不再生成复核页文件。
  • 检查源码、后端路由和 dist,确认没有复核页路径、导航文字或专属样式残留。
  • Python 路由模块与相关 JavaScript 语法检查通过;本机 8765 端口未运行服务,未做在线浏览器加载。

2026-08-07 · Insight3 完整性基准对齐 30 Hz 实际帧率

提交:cc99677(main)

做了什么

  • Insight3 图像、CameraInfo 和 vio_image_cov 的 rosbag 完整性基准由 50 Hz 调整为 30 Hz;深度 13 Hz、VIO 约 100 Hz 和 IMU 400 Hz 基准保持不变。
  • 实时录制 header 审计与离线 check_bag.py 继续共用同一套频率定义,避免两处结论不一致。

为什么

  • 近期录制中两台 Insight3 都稳定输出 30 Hz,写入队列、网卡和 UDP 计数均无丢弃;旧的 50 Hz 基准会把每个正常的 33.3 ms 间隔都误判为缺帧,固定报告约 40% 丢失。

怎么验证的

  • 对三类 Insight3 30 Hz topic 及未改动的 VIO/IMU 基准执行断言,全部通过。
  • 使用 85 秒录制 insight_record_20260807_144032 做逐消息精确检查,原先六个约 39.98% 失败项全部变为零缺帧,最终结果为 OK -- all checked topics within 0.5% loss。

2026-08-07 · 三相机重启后自动校时与相位验收

提交:9a31c9f(main)

做了什么

  • 新增 Jetson 侧 sync_camera_restart.py:一次读取 SSH 凭据,并行校准三台相机时钟, 在共同绝对时间重启 S99all_run.service,再直接输出 systemd 触发差、LPWM 配置事件和 三路图像 header timestamp 差。
  • Insight3 A/B 使用红外图像,Insight9 使用中间 30 Hz RGB;录制中默认拒绝执行,密码不 写入仓库或进程参数。
  • reboot_cameras.sh --sync-phase 在三台相机整机恢复后重启 Dashboard DDS participant, 再执行上述软件相位对齐和验收;部署包与可选开机环境配置同步包含该入口。

为什么

  • NTP 只统一系统时钟,三机独立启动的 PWM/传感器仍有相位差;同时发送 reboot 命令也会 受系统调度和不同管线初始化耗时影响,需要在每次重启后用实际图像时间戳验收。
  • Insight9 RGB 当前日志为 lpwm_enable=0,约 33.313 ms 的帧周期也与两台 Insight3 的 33.334 ms 略有差异,统一重启只能校准起始相位,不能替代硬件锁相。

怎么验证的

  • 完整执行三台相机整机重启、Dashboard 恢复、共同绝对时间采集服务重启和实时 ROS 采样; 三台服务和图像流均恢复。
  • 最终 5 秒验收每路收到 150 帧:Insight3 B 相对 A 为约 -6.749 ms,Insight9 RGB 相对 A 为 -9.234~-6.153 ms、相对 B 为 -2.486~+0.593 ms,最大观测差 9.234 ms,10 ms 门限判定 PASS。
  • 同一流程的另一次 10 秒采样出现 15.124 ms 最大差,确认脚本会如实输出 FAIL,软件重启 结果具有非确定性;Python 编译、Shell 语法、只读 SSH/NTP 检查均通过。

2026-08-06 · 120 Hz 屏幕三相机秒表复测

提交:81f855a(main)

做了什么

  • 新录制 stopwatch_120hz_test_20260806_174928,只包含三路图像;复核页切换到该包 各相机前 10 帧,并记录 1 ms 显示精度的秒表读数。
  • Insight9 单帧内可见约四次 120 Hz 刷新形成的滚动快门混合,网页按可见起止值记录, 例如 01:30.405–429,不强行归为单一读数。

为什么

  • 旧手机秒表刷新率不足以区分约 5–23 ms 的相机相位,需要用 120 Hz 显示器缩短单个 显示状态的持续时间,并观察相机的帧内扫描行为。

怎么验证的

  • 包长 23.23 秒,Insight3 A/B 各 697 帧、Insight9 698 帧;写入队列零丢帧,网络审计 无 softnet、UDP 或网卡丢包。Insight3 的 missing 是仍按 50 Hz 标称值检查 30 Hz 数据的误报。
  • Insight3 A/B 前 10 帧读数 10/10 一致,但相机 header 相差约 17.840 ms;Insight9 图像 明确显示滚动快门覆盖多个屏幕刷新状态。
  • 无头 Chromium 确认三路红框原图、秒表裁剪、相对毫秒、滚动范围和 10 组汇总表均正常加载。

2026-08-06 · 秒表复核时间戳改为相对毫秒

提交:65743e3(main)

做了什么

  • 复核页以整包最早图像为 T+0.000 ms,卡片和汇总表不再直接铺开 19 位纳秒时间戳。
  • 三路相机使用不同颜色的时间点;完整原始 header 纳秒值保留在悬停提示中。

为什么

  • 相对毫秒更容易直接比较相机间的固定偏移和逐帧变化,同时避免长整数挤占表格空间。

怎么验证的

  • 无头 Chromium 确认首组显示 Insight9 A T+0.000 ms、Insight3 A T+23.251 ms、 Insight3 B T+38.743 ms,图片、秒表读数及汇总表均正常加载。

2026-08-06 · 三相机秒表时间同步复核页

提交:ce28027(main)

做了什么

  • 新增 /stopwatch-review 页面,按序号并排展示 Insight3 A、Insight3 B 与 Insight9 A 各自前 10 帧的红框原图、秒表裁剪、人工读数、纳秒 header 时间戳和 UTC 时间。
  • 支持第 1–10 帧快速切换、键盘左右键、点击原图放大,以及 10 组读数汇总表。
  • 时间戳按字符串读取后再用 BigInt 计算,避免浏览器对 19 位纳秒整数进行浮点舍入。

为什么

  • 单看文件和 Markdown 表格不便于判断三路画面是否属于同一曝光批次;并排网页可以直接 对照秒表显示内容与相机时间戳,不再仅凭同序号帧推断同步误差。

怎么验证的

  • 页面、manifest 和抽查原图均返回 HTTP 200;无头 Chromium 在 1600×1200 下确认三路 裁剪、红框原图、精确时间戳和汇总表正常加载。
  • 首组页面计算同序号时间戳跨度为 38.743 ms,并正确标出 Insight9 A 最早、Insight3 B 最晚;秒表读数分别为 02:01.68、02:01.71、02:01.68。

2026-08-06 · 数据集默认保留原始分辨率

提交:affefa3(main)

做了什么

  • Dataset 页面默认图像模式由 224×224 下部 ROI 改为 Original resolution;224 和 384 继续作为显式训练副本选项。
  • 正式叠衣服数据集按原始分辨率重新导出并原子替换原 224×224 版本。

为什么

  • 默认归档应保留采集像素,训练侧可按具体模型统一裁剪和缩放,避免设备端提前丢失信息。

怎么验证的

  • 无头 Chromium 加载 Dataset 页面为 HTTP 200,默认值为 original,控制台无错误。
  • insight_record_20260806_143949 重新导出 473 帧;左右腕视频均为 544×640,头部为 1088×1920,全部 H.264/yuv420p、20 FPS、473 帧,数据集约 92 MB。
  • Parquet 逐帧确认 action[t] == state[t+1],末帧 action_valid 全 false。

2026-08-06 · 质量失败 rosbag 改为 fail_ 隔离

提交:72128c0(main)

做了什么

  • 数据质量拒绝不再删除源 rosbag,改为将完整目录重命名为 fail_<原名>;发生重名时 使用 fail_2_<原名> 等递增名称,禁止覆盖既有数据。
  • Dataset 页面过滤 fail_ 包,后端也拒绝直接提交这些包;Bags 页面仍可查看和手工处理。
  • 配置、标定、权限、磁盘或程序错误继续保留原名,不误隔离可恢复数据。

为什么

  • 自动删除不可恢复,现场需要保留失败录制用于排查、重新评估门限或手工修复。

怎么验证的

  • 临时目录回归覆盖完整任务失败、文件内容保留、重名递增、路径越界保护和 fail_ 后端拒绝。
  • Dashboard 重启后导出 API 正常;直接提交 fail_nonexistent 返回 HTTP 400。
  • 无头 Chromium 模拟正常包与 fail_ 包时只显示正常包,页面 HTTP 200 且控制台无错误。

2026-08-06 · 区分连续高速 TCP 运动与定位跳变

提交:d516586(main)

做了什么

  • TCP 平移质量门由“单帧步长超过 5 cm”改为“步长和相对前后局部速度的位移创新量 同时超过 5 cm”。
  • LeRobot 与 UMI 元数据记录 large_step_and_velocity_innovation 判定策略;姿态 45°、 pose 间隔 100 ms 门限不变。

为什么

  • 20 Hz 下约 1 m/s 的连续真实运动每帧会超过 5 cm,旧规则会把完整快速示教误判为 坐标重置;真正的 VIO/重定位跳变则表现为相对前后速度不连续的孤立脉冲。

怎么验证的

  • 合成轨迹覆盖连续 6 cm 步长、40 cm 单帧重置、不等间隔恒速和边界跳变。
  • 最新包 insight_record_20260806_143949 成功导出 1 个 episode、473 帧、23.65 秒; 三路 H.264 视频均为 224×224、20 FPS、473 帧,state/action 全有限,三路图像 473 帧 全部有效。
  • 旧跳变包 insight_record_20260806_142004 仍因 insight3_b 原始与重采样位置跳变被 拒绝,确认安全门没有被直接放宽。

2026-08-06 · 补齐 Insight3 B 米制夹爪标定

提交:0e3183a(main)

做了什么

  • insight3_b 按现场确认复用 insight3_a 的全闭、全开像素距离和 0–0.083 m width_calibration,双臂 LeRobot 导出不再因 B 标定缺失而失败。
  • 数据计划和 Wiki 当前限制同步更新。

为什么

  • 两路夹爪参数一致,但配置中此前只有 A,导致所有双臂包在数据质量检查前被配置门限拒绝。

怎么验证的

  • 加载器确认 A/B 配置完全一致,且两路均同时具备有效像素标定和米制宽度标定。
  • 最新包 insight_record_20260806_143949 的 A/B 双 marker 检出率分别为 87.2% 和 76.0%;正式导出已越过标定检查。
  • 该包仍因 TCP 快速连续运动超过固定 5 cm 位移门限被拒绝:A 的 20 Hz 峰值步长 6.45 cm,B 为 5.60 cm;原始 VIO 连续且录制期间没有 hard relocalization。

2026-08-06 · Insight3 默认屏蔽底部 20% 图像

提交:2048728(main)

做了什么

  • Insight3 全局定位图像的夹爪 mask 默认值由 0 改为 0.2,统一应用于共享后端默认值和 jetson-nx、lite、lite-779 三个设备 profile。
  • Settings 页面同步显示 0.2,并说明设为 0 可关闭 mask。

为什么

  • 默认排除两路 Insight3 图像底部 20% 的夹爪区域,减少随手部运动的近景特征参与全局 重定位匹配。

怎么验证的

  • 前端构建和 Python 语法检查通过;Settings API 返回 0.2。
  • 无头 Chromium 加载 Settings 页面为 HTTP 200,输入框显示 0.2,控制台无错误。

2026-08-06 · 修复 NV12 数据集视频丢失色彩

提交:8d83191(main)

做了什么

  • 保留夹爪检测只读取 NV12 Y 平面的低开销路径;LeRobot 和 Legacy UMI 视频写出改为 完整 NV12 Y/UV → BGR → RGB 解码。
  • LeRobot 元数据新增真实 source_encoding 和 decoded_channels,schema 升至 v3; Legacy UMI schema 升至 v5。
  • 重新生成 105 帧单臂预览数据集,替换此前错误的灰度 MP4。

为什么

  • 数据集导出器误复用了夹爪检测专用解码函数。该函数有意丢弃 UV 色度平面,导致原始 NV12 彩色录制在导出后变成 R == G == B 的伪 RGB。

怎么验证的

  • 原始帧分别通过亮度和完整彩色路径解码为 640×544 与 640×544×3;原始 UV 范围 77–211,确认录制包含真实色度。
  • 真实 bag 重新导出 105 帧 H.264/yuv420p;抽查首/中/末帧,68.1% 像素的 RGB 通道差 大于 2,同时 next-state action、末帧 validity、ROI 和时间戳契约保持通过。

2026-08-06 · LeRobot 绝对 EE 数据契约

提交:fdb0d44(main)

做了什么

  • 单臂 state/action 改为 10D;双臂改为 [左10D, 右10D],每臂均为绝对 xyz + rotation_6d + gripper_width_m。
  • action 保存下一帧绝对目标,末帧复用当前 state 作有限占位且 action_valid 全 false; NaN/Inf 输入统一替换为有限占位并逐维标无效。
  • 视频键改为单臂 right_wrist_0_rgb,双臂 base_0_rgb、left_wrist_0_rgb、 right_wrist_0_rgb;新增统一 state 时间戳、各相机真实时间戳和逐路 validity。
  • 明确 640×544 输入先裁 [0,96,544,544] 再缩放到 224×224;训练 adapter 必须在 normalization 前以当前 T0 为统一参考转换未来 action chunk。

为什么

  • 旧格式固定 20D、按右后左排列且末帧 action 被误标有效,不符合当前单/双臂模型契约。
  • 旧视频键和仅有合成帧时间戳无法表达三路视频的真实采集时刻及同步缺失。

怎么验证的

  • 合成测试覆盖 10D/20D、左右顺序、rot6d、NaN/Inf 占位、末帧 mask、Parquet 字段、 H.264/yuv420p 和 ROI 像素;无头页面加载、动态布局提示、API 与控制台均正常。
  • 实际单臂 rosbag 成功导出 105 帧:state/action 全有限且 next-state 关系成立,视频为 224×224、20 FPS、H.264/yuv420p,ROI、相机 timestamp 和 validity 字段均符合契约。
  • 实际双臂 bag 因现场 insight3_b 缺少有效夹爪标定被安全拒绝,未生成或删除数据。

2026-08-05 · 默认关闭建图调试 Topic

提交:82bb3ef(main)

做了什么

  • mapper 和 global localizer 新增默认关闭的 --publish-debug-topics。
  • 默认不再创建 /insight9_sparse_map/points 和三条历史 Path 的 publisher,也不启动 Path 重建 timer;/insight9_sparse_map/features 继续发布供 global localizer 使用。
  • 实时 Pose、TF、状态、网页轨迹和默认录制链路保持不变。

为什么

  • points 和完整 Path 只服务 RViz/显式诊断,网页 3D 轨迹由三路高频 Pose 在前端累积, 不消费这些调试 topic。
  • 默认关闭可省去稀疏点云序列化和三条完整历史 Path 的周期性构建与 DDS 发布开销。

怎么验证的

  • Python 编译、参数默认值/显式开关断言、Compose 配置和 diff whitespace 检查通过。
  • 实机重建 mapper/localizer 后,日志明确显示调试 topic 关闭;两条 global Path 不再存在, mapper points/path 的 publisher 数均为 0。
  • feature map 保持 1 个 publisher 和 1 个 localizer subscriber;三路 Pose 均保持 1 个 publisher 和 1 个 Dashboard subscriber,TF、/api/mapping 与三路相机预览正常。

2026-08-05 · 建图空转与地图发布 CPU 优化

提交:0134d03(main)

做了什么

  • mapper 在每次输入尝试开始时推进 5 Hz deadline;缺 Pose、静止或没有形成关键帧时, 不再对后续每个双目帧重复等待和变换。
  • status 保持 2 Hz;完整稀疏点云改为地图变化时最高 1 Hz、稳定时每 10 秒保底刷新。
  • mapper 与两路 localizer 的 200 点调试 Path 降至 2 Hz,TF 拆到独立 5 Hz timer, 30 Hz Pose 不变;开发与客户部署 Compose 同步使用新频率。

为什么

  • 原 5 Hz 限频只在成功关键帧后更新时间。缺 Pose 或相机静止时,worker 会退化为逐帧 尝试,并在每帧上最多等待 Pose 30 ms,因此没有实际建图也会持续占用 CPU。
  • mapper 原来每 0.5 秒都把全部地标转成 Python list、重建 PointCloud2 并发布;Path 也为保持 TF 新鲜度而以 5 Hz 重建整段历史,成本会随地图和轨迹增大。

怎么验证的

  • Python 编译、ROS 容器参数加载、Compose 配置、地图点计数晋升检查和 diff whitespace 检查通过;重建 mapper/localizer 后日志无异常,Dashboard 三路 WebRTC 继续工作。
  • 修改前 mapper 在 pose_ready=false 时单次采样为 60.83%;修改后四次 CPU 采样均值 46.99%,期间实际完成了一个 228.1 ms 关键帧,并非通过停建图换取。
  • ROS 实测稳定点云 0.095 Hz(约 10.5 秒间隔)、Path 2.00 Hz;独立 mapper TF 六秒窗口为 4.31 Hz,没有随 Path 一起降到 2 Hz。

2026-08-05 · 全局定位匹配与锁竞争优化

提交:c6d8e05(main)

做了什么

  • Insight3 在特征地图更新时只归一化一次描述子,后续两路定位直接复用不可变缓存; mapper 回环也复用 LandmarkMap 已归一化的描述子。
  • 描述子相似度按 256 个 query 分块,保持原 ratio test、mutual-best、并列值顺序和 PnP 接受规则,不再分配完整 query×map 相似度矩阵。
  • 两路 Insight3 改用各自的状态锁,特征地图使用独立 map lock;TensorRT IPC、匹配和 PnP 继续在锁外执行,避免一台相机阻塞另一台。

为什么

  • 原实现每次定位都重新归一化最多 20k×256 地图描述子,并同时保留完整相似度矩阵; 两路 VIO、图像、地图和定位 worker 还共用一个全局锁。
  • 这些工作不会提高特征或定位精度,却会增加 CPU、峰值内存和跨相机锁竞争。

怎么验证的

  • 随机尺寸、空输入、跨分块并列值和完整 PnP 测试的匹配索引、相似度及定位结果与旧算法 一致;Python 编译、compose 配置和 diff whitespace 检查通过。
  • 1024×20000 相同输入中,完整矩阵核心耗时 821.88 ms,缓存分块实现 724.11 ms; 旧实现每次地图归一化另需中位 13.74 ms,合计约降低 13.3%。
  • 512×10000 校验值完全相同,峰值 RSS 约从 164 MiB 降至 124 MiB。真实 ROS 状态继续 发布,Insight3 B 的匹配计时约 5–8 ms,localizer 近五分钟无新错误。
  • 现场 Insight3 A 上游当时停流,因此最终单路 CPU 采样只用于回归,不作为双路性能 A/B。

2026-08-05 · 前端运行进程 CPU/GPU 复测与二次优化

提交:49e39ef(main)

做了什么

  • 把 mapper 与 localizer 的高频 VIO callback 分成 60 Hz 插值 buffer、30 Hz 滤波/pose 输出和低频 Path 更新;使用稳定时间 deadline,避免 100 Hz 输入混叠成 25 Hz 输出。
  • WebRTC 最高帧率会话复用主进程已完成的限频结果,低帧率会话仍在 worker 独立限流; 三路正常预览保持 25 FPS、原始分辨率和硬件 H.264。
  • localizer 复用不可变特征地图数组引用,避免每次重定位复制最多 20k×256 描述子; 前端轮询只在值变化时写 DOM。
  • Dashboard Compose 启用 init,回收重启后的 kiosk/Firefox 后代进程,避免僵尸进程累积。

为什么

  • mapper/localizer 原先仍对 100 Hz VIO 每条构造矩阵、更新 buffer 与滤波,页面和输出只消费 30 Hz,额外计算没有可见收益。
  • WebRTC 主进程已按最高会话帧率选择帧,worker 对同一批帧再次执行相同 deadline 会重复 丢帧;旧容器 PID 1 为 Python 时也不会主动回收退出的 kiosk 后代。

怎么验证的

  • 15 秒进程采样中 mapper 约从 64.0% 降至 55.5%,localizer 从 44.4% 降至 40.3%;相关进程合计约从 332.0% 降至 323.4%。容器内 zombie 从 24 个降为 0。
  • 三路编码 24.7–24.9 FPS、可见帧率 21.6–23.2 FPS,3D 约 30 FPS;累计新增解码 丢帧和 WebRTC 丢包均为零。ROS pose 为 29.96–30.00 Hz,mapping/API 继续在线。
  • GR3D 长窗口均值约 61%、范围 18–97%,仍由 Firefox/Babylon 与 SuperGlue TensorRT 脉冲共同占用,未通过停服务、降分辨率或降帧率换取数字。
  • 前端构建、Python/JavaScript 编译、compose 配置、限流单测、真实 3D 页面、API、ROS 和进程树检查均通过。

2026-08-05 · Kiosk CPU 与 3D 卡顿治理

提交:13d9d85(main)

做了什么

  • 逐一测量 dashboard、Insight9 mapper、Insight3 localizer、WebRTC worker、Firefox parent/content/RDD/socket、GNOME/Xorg 和 SuperGlue 的 CPU/GPU 占用,并对照上游官方 文档审查可替代方案。
  • WebRTC 按浏览器会话节拍在图像转换和 IPC copy 前丢弃无用预览帧,三路请求 25 FPS; 硬件 H.264 编码、原图尺寸、录制 writer 和原始采集频率保持不变。
  • Insight3 描述子匹配固定 OpenBLAS 单线程;mapper 的 VIO relay 使用独立 ROS callback group 和双线程 executor,避免大点云/描述子发布阻塞姿态。
  • mapper、localizer、dashboard 与 Babylon 显示统一为 30 Hz;3D 改用 wall-clock timer, 每帧插值最新 pose,轨迹 mesh 最多 10 Hz 更新,移除逐视频帧 DOM 更新。
  • 模型、Babylon hardware scaling 和分辨率参数全部保持原值。

为什么

  • mapper 默认单线程 callback group 会被点云序列化连续占住约 355 ms,VIO pose 随后突发 补发;这是模型移动严重停顿的直接原因之一。
  • Firefox 在三路全分辨率视频合成时,即使 Babylon 单帧工作不足 10 ms, requestAnimationFrame 仍会出现 67–119 ms 间隔,不能代表稳定 30 Hz。
  • 原 WebRTC 30 FPS 分支没有真正限流,50 FPS Insight3 帧进入 IPC 和编码;50 Hz pose 又高于页面实际消费频率,产生没有可见收益的 CPU、DDS 和序列化工作。

怎么验证的

  • 30 秒实机采样中,三路累计解码为 24.0–25.1 FPS,新增丢包、解码丢帧均为零; 可见帧率中位数为 21.38、21.49、20.00 FPS。
  • 3D 帧率中位数 30.02–30.04 FPS,区间 29.75–30.38 FPS,最大帧间隔 53 ms; mapper pose 最大停顿由约 355 ms 降到约 69 ms。
  • 整机 CPU busy 从约 85–88% 降到 73.3%;localizer 从 83–102% 降到约 46%, WebRTC worker 从 43–50% 降到约 32%,Firefox RDD 从 45–50% 降到约 31%。
  • GPU 在 12–89% 间随 Babylon/WebRender 与 TensorRT 推理波动;暂停 SuperGlue 的 A/B 测试没有改善 3D 卡顿,因此保留定位功能。前端构建、Python/JavaScript 编译、compose 配置、限流单测、真实 API/WebRTC、日志和 kiosk 截图均通过。

2026-08-05 · 全量手册与 Wiki 专题文档校准

提交:6265ae6 + d875fc3,合并 8d4e83c(main)

做了什么

  • 逐份对照当前 main,更新主仓库 13 份 README/使用/部署/工程/建图/数据集/CLI 手册;补齐八个页面、进程内图像录制、轨迹增量 WebSocket、独立媒体 worker、 Insight9 位姿图、Insight3 2 Hz 重定位中继和 LeRobot v3 标准归档。
  • 重写 Wiki PRD 与本地助手工作须知,同步使用/部署手册;新增 LeRobot/UMI 专题, 更新建图与重定位专题和 Home 导航。
  • 明确旧 AprilTag 在线对齐、MediaPipe hand pose、Qt 双窗口与 A/B 分屏 kiosk 已删除; 给 8 月 4 日双 Firefox 实验条目标注 ff34469 同日完整撤销。
  • 修正 Bags 当前只展示完整性/评分状态、check_bag --fast 的 SQLite 聚合语义、 224×224 默认导出、质量拒绝自动删除边界、CLI 2.0.0 命令/API 和 v2.0.x 发布示例。
  • 对齐同期现场改动:Dashboard WebSocket 和 ROS 全局 Pose 统一为 30 Hz,WebRTC 正常预览请求 25 FPS,并在图像转换/IPC copy 前按会话 deadline 选择帧。

为什么

  • 多轮功能拆分、发布范围变化和功能撤销后,旧手册仍混有单体 app.js、540 px WebRTC、额外图像 rosbag reader、旧发布标签与已撤销 kiosk 等描述,现场操作和 后续开发容易据此走错路径。
  • Wiki 使用/部署镜像页已与仓库源文档漂移,需要重新建立同步基线。

怎么验证的

  • 主仓库与 Wiki 的 Markdown 相对链接均通过检查,代码围栏成对,git diff --check 无空白错误;Wiki 使用/部署页与仓库源仅保留导航链接差异。
  • Looper CLI 文档中的 112 条命令示例全部通过 argparse 解析,--version 返回 2.0.0; 六份 profile JSON 均通过解析。
  • 运行容器内 /healthz、八个页面和 cameras、image capabilities、mapping、recording、 UMI export 等只读 API 均返回 HTTP 200;SuperGlue 服务 health 为 healthy。

2026-08-05 · Insight9 关键帧位姿图与历史地标重融合

提交:4538763(main)

做了什么

  • mapper 保留关键帧 VIO 位姿及其双目局部三维观测,建立相邻 VIO 边和通过三帧 共识的全局回环边;新增 Cauchy 鲁棒核的稀疏 SE(3) 位姿图优化。
  • 回环优化后按新关键帧位姿重放全部保留观测并整体替换特征地图,历史 Path 使用 分段图校正;最新 Pose/TF 继续用 EKF 平滑,避免显示跳变。
  • 图节点限制为 600,描述子以 FP16 保留;小回环按 5 秒限流并由后续关键帧补做, 10 cm / 5° 以上差异立即求解。状态新增图节点、边、pending、代价和重建耗时。

为什么

  • 旧实现只更新统一的 T_map_odom,能修正后续输出,却不会消除已写入历史地图的 局部形变;Insight3 继续用旧地标重定位时会继承这种内部不一致。
  • 位姿图把闭环误差沿关键帧轨迹分配,地标重融合让历史地图与优化轨迹回到同一坐标。

怎么验证的

  • 101 节点 10 cm 漂移回环后末端残差 3.85 mm;61 节点旋转残差 0.001203 rad。
  • 同时加入明显错误回环后,鲁棒求解仍把末端保持在正确位置约 1.9 cm 内;600 节点 求解 1.80 秒、末端残差 3.98 mm。
  • 170×150 个观测的地图重融合 703.1 ms、保留数据 13.43 MB;在线重启后真实双目 首关键帧成功匹配/三角化并发布完整图状态,两项服务无新异常。
  • 本轮是位姿图和地标重融合,不是完整像素级 BA;真实厘米级精度仍需移动相机闭环和 独立控制点测量。

2026-08-04 · 发布镜像体积优化

提交:da77d70(main)

做了什么

  • 构建时把上游 2.56 GB WiLoR FP32 checkpoint 转为推理实际使用的 FP16,并逐张量验证 key、shape、dtype 和 FP16 数值一致后原子替换;原始 FP32 文件不残留在镜像下层。
  • 固定版本的 insight-superglue-validation:25.04 从每次 Dashboard 发布包拆为单独的 首装依赖;update.sh 在新机器上自动从 Dashboard 包旁加载,已有设备升级时直接复用。
  • 部署说明同步区分首次安装的三个压缩文件和日常升级的单个 Dashboard 镜像。

为什么

  • 原发布包 6.08 GB 不只是 WiLoR、PyTorch、CUDA 三项:Docker 显示体积还同时计入未压缩层, 发布 tar 又重复携带约 0.75 GB 的稳定 SuperGlue 镜像。
  • Jetson 推理链路原本就先把 WiLoR 模型转换为 FP16 再加载权重,保存 FP32 checkpoint 只增加镜像、传输和加载开销,不提升实际推理精度。

怎么验证的

  • 完整 runtime Docker 构建通过;481 个浮点张量由 2,564,812,797 字节降至 1,282,425,055 字节,整数和布尔张量保持原类型。
  • 新镜像在一次性 NVIDIA runtime 容器中确认 CUDA 可用,WiLoR 全网络以 FP16 成功初始化, 显存分配约 1.39 GB;Docker 显示体积从 13.7 GB 降至 11.2 GB。
  • 实际流式 gzip:日常升级包为 4,133,821,388 字节,比 v2.0.2 的 6,080,241,349 字节 减少 32.0%;首次安装加 750,702,182 字节 SuperGlue 包后仍减少 19.7%。
  • Shell/Python 语法、Dockerfile build check、diff whitespace 检查均通过。

2026-08-04 · 页面切换延迟优化

提交:99be531(main)

做了什么

  • 页面导航按 hover、键盘焦点或触摸意图预取目标文档,启动稳定后低优先级预热其余小页面; 进入 3D 前额外预取 Babylon 资源。
  • 全站统一样式缓存键,带版本的静态资源使用 immutable 长缓存;3D 页的 Babylon 脚本改为 defer,优化页只在真正打开轨迹结果时按需加载,不再在进入页面时解析 8.6 MB 引擎。
  • 录制 topic 刷新中的 ros2 topic list -t 改在线程执行器运行,避免同步 ROS CLI 阻塞 aiohttp 事件循环和后续页面 HTML 响应。

为什么

  • 录制页启动的 topic 探测会让页面请求等待约 0.5–0.8 秒;优化页又无条件下载和解析完整 Babylon,引起连续切页时明显停顿。
  • 多个页面此前为同一份 CSS 使用不同查询版本,浏览器无法跨页面直接复用缓存。

怎么验证的

  • 新 Chromium profile 中从 Recording 立即切到 Optimization:完整加载从约 1.42 秒降到 0.11 秒,首包等待从 0.81 秒降到 0.02 秒,初次进入优化页不再传输 Babylon。
  • 3D 导航意图预热后,切页传输量从约 9.25 MB 降到 74 KB,完整加载从约 0.99 秒降到 0.64 秒;优化页按需打开已有轨迹结果后 Babylon、结果面板和 canvas 均正常。
  • 前端构建、Python/JavaScript 语法、静态缓存响应头、健康 API 与全部八个页面无头加载通过, 浏览器控制台零错误。

2026-08-04 · Insight3 夹爪 Mask 默认关闭

提交:882fdda(main)

做了什么

  • Settings 页面中的 Insight3 gripper mask 默认值由 0.2 改为 0,即默认不遮挡图像。
  • 后端兜底值和 jetson-nx、lite、lite-779 三个设备 profile 同步改为 0;页面帮助文字 明确 0 表示关闭,仍可手动填写 0.2 等比例。

为什么

  • Mask 应由现场按夹爪遮挡情况显式开启,不应在新设备或缺少配置时默认裁掉底部 20% 特征。

怎么验证的

  • 当前 Settings API 返回 0.0,运行中的 Insight3 localizer 热加载日志确认从 0.2 更新为 0.0。
  • 前端重新构建;headless Chromium 确认输入框显示 0、新缓存版本已加载且控制台零错误。

2026-08-04 · 多 Topic 录制链路与相机 DDS 调优

提交:5ccd75c(main)

做了什么

  • jetson-nx 三台相机统一改为 CycloneDDS;开机恢复脚本会幂等检查并校正设备 DDS, 相机重启后再为三张 USB 网卡恢复 RPS(6 核设备为 3e)。
  • 宿主机持久化 ipfrag_max_dist=4096、DDS socket buffer、分片内存和 RPS/RFS 参数; 每次录制新增网络计数审计与 topic manifest,记录实际内核参数和选择范围。
  • 固件只广告、不发送 payload 的 7 个 raw topic 从 jetson-nx 可录制目录排除,保留对应 有数据的 rectified 流;完整性检查改用源 header 时间戳,并修正 VIO 非均匀节拍误报。
  • 合包与自动 host sync 完成前禁止开始下一段录制,避免大包 rsync 与新采集争用资源。

为什么

  • 录制更多大图 topic 后的掉帧发生在 SSD 写盘之前:FastDDS 约 65 KB UDP 报文在三张 USB 网卡上产生大量 IP 分片与可靠重传,writer queue 和磁盘 iowait 始终为零。
  • 1024 的短测可通过,但 300 秒长测仍有 342 次 IP 重组失败;需要用长测确定最低稳定值。

怎么验证的

  • 4096 下完成 306 秒、44 个实际发布 topic 的实录:三张网卡、softnet、IP reassembly、 UDP 和 writer queue 的丢失计数全部为零;重启 dashboard 后再次短录,落盘审计明确记录 ipfrag_max_dist 从开始到结束均为 4096。
  • 三路主图像持续约 50/50/30 FPS;Insight3 A、Insight9 及全部 IMU/VIO 写入完整。
  • Insight3 B 仍有一次多 topic 同时出现的 40 ms 源节拍缺口,depth 也有固有 120 ms 间隔; 当时网络与 writer 均为零丢失,因此结论是相机发布端未产生样本,而非 recorder 或 SSD 丢帧。独立 depth 订阅与 1024 长测 bag 在相同时间范围内逐帧时间戳完全一致。
  • Shell 语法、Python 编译、JSON、核心 gap/network/catalog 断言、合包/同步启动互斥、 systemd 启用与顺序、三台设备 CycloneDDS 状态均通过验证。

2026-08-04 · 双 Firefox 无缝拼接 A/B 模式(已撤销)

提交:51f93bf(main)

后续状态:该实验在同日由 ff34469 完整撤销。相机墙页面、kiosk 状态 API、双 Firefox supervisor、依赖和开关均已删除;当前产品只使用单 Firefox kiosk。下文保留的是当时的实验记录,不代表现行功能。

做了什么

  • 新增独立的相机墙页面;本机可用两个独立 Firefox profile/进程分别渲染三路视频和 3D, 主窗口仍保留完整导航与其他业务页面。
  • X11 supervisor 自动去除相机窗口边框并固定到原相机栏;切换到 Recording、Rosbags、 Settings 等页面时 unmap 相机窗,返回 3D 自动复位,单路相机放大时覆盖全屏。
  • 两个渲染器通过后端临时状态 API 同步 OBS 性能模式;任一 Firefox 异常退出后独立重启, supervisor 退出时清理 profile、进程和窗口。
  • 双窗口保留为 INSIGHT_KIOSK_SPLIT=1 显式 A/B 开关;普通远程页面和客户本机 kiosk 默认仍使用原单窗口。

为什么

  • 需要验证原来的 17/18/21 presented FPS 是否来自单 Firefox 内部 WebRender 串行调度; 双进程能隔离 content/RDD/WebRender,但仍共享物理 GPU 和 GNOME/X11 桌面合成器。
  • 实机结果没有改善 presented FPS,因此不能把更复杂、当前更慢的双窗口路径默认交付客户; 保留完整实验能力便于后续更换桌面合成器或显示栈后复测。

怎么验证的

  • 2560×1440 设备屏幕确认相机墙与 500 px 3D 占位无标题栏、地址栏或缝隙;验证普通页面 隐藏、返回 3D 复位、相机 2560×1440 fullscreen/退出恢复和 supervisor 停止清理。
  • 实际 Firefox WebRTC 三路流持续上报;相机窗聚焦时 decoded 约 51.2/19.1/29.0 FPS, presented 约 14.1/11.9/14.2 FPS,未优于原单窗口 17/18/21,说明主要限制仍在共享 GPU/桌面合成链路。
  • 默认单窗口回归确认只启动一个 2560×1440 Firefox;前端构建、Python/JavaScript 语法、 API 状态读写、headless 页面加载、生成产物一致性和 staged diff 检查均通过。

2026-08-04 · HiFi-UMI 风格 LeRobot 标准数据集导出

提交:2585d65,合并 10c1f87(main)

做了什么

  • 新增 LeRobot v3 标准导出:逐帧数据写入 Parquet,三路同步图像写入 H.264 MP4,并生成 info.json、统计、任务、模态、episode 索引和设备端 manifest。
  • 状态和动作为 HiFi-UMI 风格的固定 20 维双手布局,每手包含位置、旋转 6D 和夹爪宽度; 单臂缺失侧填零并用 validity mask 排除,动作保存同 episode 的下一帧绝对状态。
  • Domain 20 现场三路相机映射为右腕 right_hand_up、左腕 left_hand_up、头部 head_main,统一按 20 Hz 同步;页面可填写语言任务、选择布局和输出分辨率。
  • LeRobot 成为页面默认标准归档,原 UMI Zarr 仍作为兼容选项保留;π0.5 的相对动作和模型 输入命名放在训练 adapter 转换,不写死在标准数据中。
  • 双臂导出要求两侧 Insight3 都有米制 width_calibration。当前设备的 insight3_b 尚未 完成该标定,因此配置补齐前会保留源 bag 并明确报错,不会伪造夹爪数据。

为什么

  • 标准 LeRobot 目录便于长期归档、交换和复用,HiFi-UMI 的固定双手语义又能为计划采用的 π0.5 保持稳定输入;模型特有的相对坐标处理留在 adapter,可避免污染通用数据集。

怎么验证的

  • 使用真实单臂 rosbag 导出 1 个 episode、105 帧;Parquet 的 20 维状态、下一帧动作、 validity mask 和任务索引均逐项核对。
  • MP4 经 ffprobe 确认为 H.264、224×224、20 Hz、105 帧;官方 LeRobot 0.4.4 LeRobotDataset 成功加载全部 105 帧、任务文本、20 维状态和视频张量。
  • Python 编译、前端构建、staged diff 检查通过;Playwright 验证 LeRobot/UMI 切换、任务 请求、状态展示和页面加载,浏览器控制台零错误。

2026-08-03 · 默认录制原始 VIO 100 Hz 轨迹

提交:fc144be(main)

做了什么

  • 每路启用相机的原始 /camera/vio_100hz 现在都会进入默认录制选择。
  • 配置的 dashboard/global pose 继续同时录制;若 dashboard pose 本身就是 vio_100hz, topic 列表会自动去重。

为什么

  • UMI 单臂导出使用相机原生 VIO 轨迹。Jetson NX 的 dashboard pose 是全局重定位结果, 之前默认录制只选全局 pose,用户漏选原始 VIO 后会导致 UMI 缺少必要 topic。

怎么验证的

  • 合成相机配置验证全局 pose 与原始 VIO 同时出现,并验证原生 VIO profile 不重复。
  • 重启现场服务后,录制 topic API 和 Chromium 页面均确认 Insight3 A、Insight3 B、 Insight9 A 三路 vio_100hz 默认勾选,浏览器控制台零错误。

2026-08-03 · UMI 自动清理数据质量失败的 Rosbag

提交:ddd632d(main)

做了什么

  • UMI 批处理结束后,自动删除因 VIO 连续性、有效帧数、图像解码或夹爪检测问题而无法 生成任何有效 episode 的源 rosbag;至少生成一个有效 episode 的包继续保留。
  • 导出器增加机器可识别的数据质量拒绝标记,配置、相机布局、标定、权限、磁盘和程序 错误保持普通失败并保留源包,避免错误配置造成误删。
  • 页面逐包显示“拒绝包已删除”或“导出失败、源包保留”,清理期间刷新 rosbag 列表,并 在导出配置区明确提示永久删除规则。

为什么

  • 长时间连续采集会产生部分完全不可用的包,人工逐个清理效率低;同时自动删除必须限制 在明确的数据质量拒绝,不能把可通过修正配置恢复的原始数据删除。

怎么验证的

  • 临时构造成功、数据质量失败、系统失败三个 rosbag:成功包保留,质量失败包删除,系统 失败包保留,批处理状态为 partial 且 API 正确返回 source_deleted。
  • 分别验证导出器输出 UMI_REJECTED_BAG 与普通 ERROR 两条路径;Python/JavaScript 语法检查、前端构建通过。
  • 重启服务后 UMI API 为 idle;Chromium 确认永久删除提示和 v5 前端已加载,控制台零错误; 现场新录制的 171504 rosbag 未被处理或删除。

2026-08-03 · UMI 长录制按静止段自动切 Episode

提交:0cf352b(main)

做了什么

  • UMI 页面新增可选的长录制自动切段模式;默认仍保持“一条 rosbag = 一个 episode”。
  • 自动模式在 TCP 平移、旋转和夹爪宽度稳定约 1 秒时切分,实际连续静止检测阈值为 0.8 秒,并容忍最多 0.15 秒的二维码/位姿单帧毛刺。
  • 边界只使用局部速度,不要求返回同一个绝对位置;每段独立写入 demo_start_pose,训练 继续使用 relative pose,隔离前一段累积的缓慢 VIO 漂移。
  • 操作过程中的 VIO 突跳只淘汰受影响小节;若坐标重置发生在静止段内,切点对齐到重置 时刻,使重置前后完整操作都能保留。
  • 功能分支已 rebase 到固定下部 ROI 版本;224/384 裁剪与自动切段可同时使用,schema 升级为 v4。

为什么

  • 连续录制多次来回操作比频繁启停 rosbag 更高效,但训练仍需要每次操作有独立 episode 边界,且不能依赖随时间漂移的 VIO 绝对坐标判断“是否回到原点”。

怎么验证的

  • 合成长序列验证:0.6 秒自然停顿不误切,0.8 秒稳定停顿正确切分;三段绝对起点不同仍 使用各自相对参考。
  • 中段注入 10 cm VIO 跳变时只淘汰中段;跳变位于停顿内时边界对齐跳变帧并保留三段。
  • 真实 160807 rosbag 以 224 模式完整导出 1 episode、102 帧;Zarr 为 [102,224,224,3],固定 ROI 为 (0,96,544,544),schema v4 同时记录裁剪和切段配置。
  • 前端构建与 Chromium 验证通过,请求同时携带 episode_mode=auto_pause 和 image_mode=224,控制台零错误。

2026-08-03 · UMI 方形训练图固定裁剪操作区

提交:3d7747d(main)

做了什么

  • 224×224 和 384×384 训练副本改为先固定裁剪水平居中、底部对齐的最大方形 ROI, 再等比缩放;不再把 portrait 原图直接拉伸成正方形。
  • Zarr 根属性和 manifest 升级为 schema v3,记录每路相机的 camera_crop_boxes_xywh 与 bottom_center_max_square 裁剪策略;页面同步说明固定 ROI 语义。

为什么

  • 操作相关内容集中在 portrait 画面的中央和下部。固定下部 ROI 能保留夹爪、ArUco、 目标物和放置区,同时减少椅背、窗户和人员背景占比,并避免几何形变污染训练数据。

怎么验证的

  • 1088×1920 Insight9 实拍帧固定裁成 (0,832,1088,1088) 后输出 224×224,视觉确认 保留桌面目标区与近身操作区,基本去掉上方背景。
  • 真实 rosbag 成功导出 102 帧,Zarr 数组为 [102,224,224,3],manifest 正确记录 Insight3 ROI (0,96,544,544);Playwright 页面 HTTP 200、加载 12 个 rosbag、零错误。

2026-08-03 · UMI 产物可由主机用户管理

提交:3856617(main)

做了什么

  • 删除旧的 insight_record_20260803_150532_umi 和 single_arm_demo,仅保留 160731、160756、160807 三组新数据。
  • UMI 输出根目录和数据集目录使用可写权限,产物完成后统一校正目录与文件模式;后续 主机用户可直接删除或替换数据,不需要进入容器。

为什么

  • 开发容器以 root 运行,在部分 bind mount 上会被 root-squash 映射为 nobody:nogroup; 原来的目录 755、文件 644 使主机用户 nvidia 无法删除产物。

怎么验证的

  • 将 160807 临时恢复为旧的 755/644 模式后通过 API 重导出,任务返回 done;完成后 目录自动变为 777、Zarr/YAML/manifest 自动变为 666。
  • 现场目录确认只剩指定的三组新数据,Dashboard 相机 API 正常。

2026-08-03 · 修复 UMI 嵌套 Manifest 读取路径

提交:d583a42(main)

做了什么

  • UMI 后台改为从每个 <包名>_umi/ 目录读取同目录 manifest,不再错误读取 outputs/umi_datasets/ 上级目录。

为什么

  • Zarr、YAML 和 manifest 已成功生成时,错误路径仍会让页面把任务标成失败并显示 No such file or directory。

怎么验证的

  • 重启 Dashboard 后通过页面同一 API 重新导出 insight_record_20260803_160807,任务返回 done,正确读取 1 个 episode、102 帧、5.1 秒的 manifest;相机 API 同时保持正常。

2026-08-03 · UMI 固定一包一 Episode 与 8.3 cm 夹爪标定

提交:f4fd361(main)

做了什么

  • insight3_a 夹爪按实测全闭 0 m、全开 0.083 m 写入米制标定端点。
  • 每条 rosbag 固定输出一个 episode,不再因位置、姿态、跟踪空洞或图像同步异常拆分。
  • 质量门发现异常时拒绝整条 rosbag,并报告具体事件计数;不会跨异常插值,也不会生成 部分 episode。

为什么

  • 实际夹爪最大开口为 8.3 cm,需要替代之前仅用于说明格式的 9 cm 示例。
  • 采集约定本身就是“一条 rosbag 对应一次完整示教”,自动切分会改变示教边界语义。

怎么验证的

  • 合成连续流只生成 1 个 40 帧 episode;13.7 cm 位置跳变和 90°姿态重置均整包拒绝, 分别报告 position_jumps=1 和 orientation_jumps=1。
  • 真实 rosbag 输出夹爪宽度 0.060494–0.082990 m;检测到 2 次位置跳变后按预期拒绝整包。
  • Python 编译、前端构建、git diff --check 和 Chromium 页面加载均通过,页面 HTTP 200、 控制台零错误。

2026-08-03 · UMI 米制夹爪与位姿连续性质量门

提交:eda0430(main)

做了什么

  • robot*_gripper_width 改为按多点实测标定输出真实开口宽度,单位为米;缺少 width_calibration 时硬失败,不再把 0–1 归一化 opening 写入可部署数据。
  • 20 Hz 相邻 TCP 位移超过 5 cm、姿态变化超过 45°或 VIO pose 间隔超过 100 ms 时 自动切断 episode;每段只使用自身连续 pose 样本插值,不跨重定位或坐标重置。
  • manifest 和 Zarr 根属性记录米制语义、质量门阈值及每路跳变/跟踪空洞计数;页面和 使用手册同步说明标定格式与质量策略。

为什么

  • 官方 UMI 实机侧把夹爪宽度直接按米下发,归一化值会被误当成约 0.8 m,属于部署硬阻塞。
  • VIO 重定位跳变若混入同一 episode,会让策略学习不连续轨迹;跨跳变插值还会制造不存在 的高速运动样本。

怎么验证的

  • 三点非线性标定合成检查确认中间标定点准确输出米值;真实 rosbag 在未提供米制标定时 明确阻断并提示所缺字段。
  • 合成 13.7 cm 位置跳变和 90°纯姿态重置均切成 16 帧、24 帧两个连续 episode,质量事件 各记录 1 次,段内相邻位置不超过 5 cm。
  • 完成 Python 编译、前端构建、git diff --check 和 Chromium 页面加载验证;页面 HTTP 200,控制台零错误。

2026-08-03 · UMI 产物按 rosbag 独立归档

提交:d7595c8(main)

做了什么

  • 批量选择多个 rosbag 时不再合并成一个数据集;每个包独立导出为 outputs/umi_datasets/<包名>_umi/。
  • 每个目录内放置同名的 Zarr、manifest 和训练 YAML 三个文件,避免不同包的产物 平铺混在一起;旧的两组平铺产物已迁入各自目录。
  • 移除数据集名称输入和浏览器下载入口;页面直接显示设备端保存路径,并逐包报告成功 或失败。单个包失败不会阻止后续包继续处理,失败产生的空目录会自动清理。

为什么

  • UMI 产物需要与原始 rosbag 一一对应,自动命名和独立目录比手工数据集名称更容易追溯, 也避免误以为必须点击下载才会保存。

怎么验证的

  • 真实导出 insight_record_20260803_150532:生成 205 帧、10.25 秒、544×640 的单臂 数据集,Zarr 为 camera0/robot0,训练 action shape 为 [10]。
  • 双选“缺 VIO 的旧包 + 完整新包”得到 partial 状态:旧包单独失败,新包继续成功; API 返回的三条路径均位于同一个 <包名>_umi/ 目录。
  • 前端构建、Python/JavaScript 语法、嵌套路径及空目录清理单元检查、1600×1000 Chromium 页面加载和 git diff --check 均通过;最终服务状态恢复为 idle。

2026-08-03 · 单臂 VIO UMI 导出与 3D 清晰度调整

提交:1aad8cd(main)

做了什么

  • /umi-dataset 新增单臂 Insight3 A、单臂 Insight3 B 和双臂三种采集布局;单臂只 输出 camera0/robot0,训练 YAML 动作维度为 10,双臂格式保持 20 维。
  • 单臂 pose 自动读取所选相机的 /<namespace>/camera/vio_100hz,每个 episode 使用 自身 VIO 坐标系;双臂继续读取左右 /insight_global/.../pose 统一坐标系。
  • manifest 和 Zarr 根属性新增实际 pose topic;3D 默认硬件缩放从 1.8 调到 1.5, 提高模型显示分辨率,采集性能模式仍保持 2.0。

为什么

  • 当前先采单臂 UMI,只有一台 Insight3 时不会产生多相机统一坐标系下的 global pose, 旧导出器却强制要求双手、头部和两路 global pose,无法使用单相机数据。
  • 3D 模型默认渲染分辨率偏低,需要在不改变录制优先策略的前提下适度提高清晰度。

怎么验证的

  • 单元验证确认单臂 A 路由到 /insight3_a/camera/vio_100hz,双臂仍路由到左右 global pose;合成 60 帧单臂流生成的 episode 只有五个 robot0_* 数组。
  • 训练 YAML 验证只有 camera0、robot0 且 action shape 为 [10];现场 API 请求只 检查所选 Insight3,现有图像-only bag 按预期明确报告缺少 vio_100hz。
  • 完成前端构建、Python/JavaScript 语法检查、git diff --check 和 1600×1000 Chromium 页面加载验证;测试结束后 UMI 状态恢复为 idle。

2026-08-03 · UMI 导出支持原始图像分辨率

提交:3d55a75(main)

做了什么

  • /umi-dataset 新增训练图像分辨率选择,默认 Original resolution;保留每路相机 在 rosbag 中各自的原始宽高,不再统一拉伸到 224×224。
  • 原始模式仅转换成 UMI 需要的 RGB 三通道,并用 Zarr zlib 无损压缩;同时保留 224×224、384×384 兼容选项。
  • 训练 YAML 分别写入三路相机真实的 [C,H,W],manifest 与 Zarr 根属性记录各路尺寸; 多个输入 bag 中同一路相机尺寸不一致时拒绝合并。

为什么

  • 训练需要使用采集图像的完整像素信息,避免导出阶段降采样和非等比例拉伸造成细节损失 与几何形变。

怎么验证的

  • 用三路不同尺寸的 30 帧合成 rosbag 完整导出,逐块解压确认 Zarr 数组分别为 (30,240,320,3)、(30,300,400,3)、(30,360,640,3),训练配置分别为 [3,240,320]、[3,300,400]、[3,360,640]。
  • Playwright 以 1600×1000 加载页面,确认默认选择 original、共 3 个分辨率选项且 浏览器控制台零错误;API 对非法分辨率返回 HTTP 400。

2026-08-03 · 独立 UMI Dataset 页面与训练数据导出

提交:353608f(main)

做了什么

  • 将夹爪离线处理从 /bags 移到独立 /umi-dataset 页面,并扩展为完整数据流水线; 可把多条 rosbag 分别作为 episode 合并导出。
  • 按 recorder timeline 将右腕、左腕、头部三路图像、左右全局 pose 和夹爪 opening 对齐到 20 Hz;左右 pose 应用实测 camera-center→TCP 外参。
  • 输出 UMI 官方 ReplayBuffer 结构的 Zarr v2 ZipStore:右手固定为 camera0/robot0、左手为 camera1/robot1、头部为 camera2,包含 data/* 与 meta/episode_ends。
  • 同时输出双臂三相机 shape_meta 训练配置(20 维 action)和质量 manifest;页面可 分别下载 Zarr、YAML 和 JSON。
  • Jetson 端直接写标准 zlib Zarr chunk,不新增 ARM64 zarr/numcodecs 运行依赖; 4090 训练机上的官方 UMI/Zarr 可直接解码。

为什么

  • 现场需要从录制结果直接得到可拷到 4090 训练机的数据集,而不是逐路运行夹爪 JSON extractor 后再手工同步 pose 和图像。

怎么验证的

  • 生成 30 帧合成双臂 rosbag,包含三路图像、左右 PoseStamped 和两组 ID 0/1 marker; 完整导出 1 episode、30 帧 Zarr。
  • 逐块解压确认三路图像均为 (30,224,224,3),episode_ends=[30],首帧右 TCP 为 (0,0.08,0.68),训练 YAML action shape 为 [20]。
  • 现场单路测试 bag 按预期拒绝并列出缺失的左腕、头部图像和左右 pose topic。
  • Playwright 以 1600×1000 加载独立页面,发现 3 条本地 bag、导出按钮和跨页导航, /bags 已无旧 extractor 控件,浏览器控制台零错误。

2026-08-03 · rosbag 页面支持运行离线夹爪提取

提交:ccd97d2、1378519(main)

做了什么

  • 在 /bags 增加 Gripper extraction 面板,可选择 rosbag、相机和可选图像 topic,并可要求相机必须已有开合标定。
  • Dashboard 后台以单任务进程运行现有 gripper_extract.py,页面实时显示已处理帧数 与双二维码命中数;完成后展示检测率、处理速度、标定区间并下载完整 JSON。
  • 接口限制 bag/相机名称和结果路径,拒绝路径穿越;Dashboard 退出时终止仍在运行的 提取进程。
  • 写入 Insight3 A 开合标定:闭合 54.5464 px、张开 247.2844 px。

为什么

  • 让现场人员无需进入容器或手写命令即可从已有录制生成与图像帧对齐的夹爪 opening, 同时保留命令行入口用于批处理。

怎么验证的

  • 从页面对应 API 对 41.8 秒的真实 Insight3 A 左目 bag 完整提取:837/837 帧解码, 双码命中 635 帧(75.87%),耗时 8.39 秒、约 99.8 fps。
  • 结果采用新标定并成功下载 173,528 字节 JSON;非法 .. bag 名返回 HTTP 400。
  • Playwright 在 1600×1000 下加载 /bags,确认结果区与下载链接可见且控制台零错误; 前端构建、Python 编译和 git diff --check 通过。

2026-08-03 · 从 rosbag 离线提取夹爪开合状态

提交:ed6ea24(main)

做了什么

  • 新增 scripts/gripper_extract.py,直接读取 ROS 2 bag 中的 raw/压缩图像,逐帧 检测 UMI 夹爪 ArUco ID 1/0。
  • 输出 JSON 保留 recorder/header 纳秒时间戳、左右 marker 中心、像素距离,以及 基于相机标定的归一化 opening(0=闭合,1=张开)。
  • 自动选择唯一图像 topic 和推断相机,也支持 --topic、--camera、临时 --open-px/--closed-px 覆盖及 --require-calibration 严格模式。
  • 支持 mono8/8UC1、RGB/BGR、RGBA/BGRA、NV12 和 CompressedImage;结果默认 写到 outputs/gripper/<bag>/<camera>.json。

为什么

  • 双臂 UMI 数据需要把左右 TCP pose、夹爪 opening 和三路图像对齐到 20 Hz;先输出 不插值、不保持上一值的逐帧原始检测结果,后续对齐阶段才能明确处理检测缺失,避免 用旧值掩盖空洞。

怎么验证的

  • 对 41.8 秒、837 帧的真实 Insight3 A 左目 bag 完整提取,837 帧全部解码;左码、 右码和双码检测率分别为 95.58%、78.49% 和 75.87%。
  • 双码距离为 53.01–248.28 px,中位数 236.03 px;处理速度约 95.5 fps。
  • 输出 schema、帧数、距离/空值一致性及 header 时间戳单调性检查通过;当前 Insight3 A 未标定时 opening=null,严格模式按预期立即报错,标定覆盖的 0/0.5/1 归一化通过。

2026-08-03 · 定义双臂 UMI TCP 坐标系

提交:a0b3d17、05cb32e,已由 51ab6ba 合入 main

做了什么

  • 固定右手 right_tcp 和左手 left_tcp,原点为两指尖接触面中点。
  • 左右手使用相同的右手坐标系,不做镜像:+X 为画面向右/开合轴, +Y 为画面向下,+Z 为相机指向指尖/接近方向。
  • Jetson NX、Lite 和 Lite 779 的手部相机均在 profile 中通过 tcp_frame_id 显式映射 TCP;手别以 teleop_role 为准。
  • 录入 Jetson NX 左右相同的实测外参:TCP 相对 camera_center 向下 8 cm、向前 18 cm,旋转为 identity。
  • Insight3 global localizer 把 A 到 right_tcp、B 到 left_tcp 的两条变换 聚合成同一条 transient-local 静态 TF 消息;未标定 profile 不发布占位 TF。

为什么

  • 后续需把 TCP pose、夹爪开合和三路图像对齐为 20 Hz 双臂 UMI 数据; 先固定原点、轴向、手别和变换方向,可避免左右镜像或变换取逆。
  • 把相机中心轨迹转成真正的指尖工作中心轨迹,避免夹爪绕 TCP 旋转时 把相机的圆弧位移误当为夹爪平移。
  • 仅 Jetson NX 有本次实测值;其他 profile 不应直接复用 Jetson NX 或 UMI GoPro 的机械参数。

怎么验证的

  • 用仓库 camera_setup.py 实际加载全部 3 个设备 profile。
  • 断言每个 profile 都恰好将 right_hand 映射到 right_tcp、 left_hand 映射到 left_tcp;git diff --check 通过。
  • Python 解析断言和 py_compile 通过;在 ROS 镜像中捕获实际 TransformStamped payload,确认同一消息含左右两条 TF,平移均为 (0, 0.08, 0.18) m,四元数均为 (0, 0, 0, 1)。

2026-08-03 · 3D 页面渲染合成开销优化

提交:75b1b33、9030580、61713f8(main)

做了什么

  • Babylon Engine 关闭 antialias 和 stencil;默认 hardwareScalingLevel 从 1.4 提到 1.8(采集模式仍为 2.0),常量化命名。
  • 相机面板旋转角为 0 时不再设置 --camera-rotation CSS 变量,避免多余的 transform 合成层。
  • 3D 页面下的状态面板、图例、相机浮层去掉 box-shadow/backdrop-filter 毛玻璃效果,改用更不透明的纯色背景。
  • 精简 UMI 双臂叠衣服数采计划文档为 9 行待办清单;删除已过时的 Insight3 全局定位建图验证文档。

为什么

  • 3D 页面渲染合成(尤其 backdrop-filter 模糊)在采集时占用较多 GPU,抗 锯齿、模板缓冲对当前场景视觉收益不大,属于可去掉的合成开销。

怎么验证的

  • node web_dashboard/build.js 重新构建 dist,与手写改动逐文件一致。
  • 真实 kiosk(容器内 Firefox,非 headless)加载 /3d:相机墙三路面板、 HUD 面板(ROSBAG PLAYBACK / GLOBAL SPARSE MAPPING / 图例)、网格场景均 正常渲染,浮层为不透明纯色背景,无与本次改动相关的控制台报错。

2026-08-03 · 设置页可调整 Insight3 夹爪 mask 比例

提交:a29257b(main)

做了什么

  • 设置页新增 Insight3 gripper mask height ratio 数值项,比例直接用小数表示; 0.2 即屏蔽两路 Insight3 图像底部 20%。
  • 设置通过 API 原子写入 config/post_processing.json,三个设备 profile 默认均为 0.2,客户升级时保留现场值。
  • Insight3 global localizer 监测配置文件变化并热更新,无需重启服务;ROS 状态同时 报告当前比例。有效范围为 [0, 1)。

为什么

  • 固定在代码中的 20% 无法适配夹爪安装位置、相机视角和后续硬件调整,需要让现场 操作者直接在网页上微调,同时避免修改 compose 或手工编辑 JSON。

怎么验证的

  • 设置 API 读回默认 0.2;写入 0.21 后运行中的 Insight3 A ROS 状态同步变为 0.21,恢复 0.2 后再次同步;非法值 1 返回 HTTP 400 且不覆盖配置。
  • 配置读写保留其他字段及宿主文件权限/所有者;Python 编译、JavaScript 语法检查和 前端构建通过。
  • 1600×1000 无头 Chromium 实测输入框显示 0.2、保存成功且控制台无错误,页面布局 正常。

2026-08-03 · Insight3 全局重定位屏蔽夹爪静态区域

提交:13fdafc(main)

做了什么

  • Insight3 A/B 的 SuperPoint 查询特征统一过滤图像底部 20%,避免左右夹爪的 静态结构参与全局地图匹配。
  • 新增 --gripper-mask-height-ratio 参数,默认 0.20,设为 0 可关闭。
  • 状态诊断新增原始特征数、过滤特征数和 mask 高度比例。

为什么

  • 两个 Insight3 安装在左右夹爪上,夹爪约占画面底部 20%;这些随相机固定的 特征不属于环境地图,参与 2D-3D 匹配会降低重定位可靠性。

怎么验证的

  • 640×544 的 Insight3 A 实时帧从 y=512 起屏蔽;523 个原始 SuperPoint 特征中 保留 361 个,过滤夹爪区域的 162 个,过滤点 y 坐标范围为 513–631。
  • 边界检查确认 y<512 保留、y≥512 屏蔽;服务重启后日志确认两路底部 20% mask 已启用,图像、内参和外参输入均正常。
⚠️ **GitHub.com Fallback** ⚠️