arm_dev
|
0fadd26ca2
|
体检判据硬化:sysfs 读取带超时、复位命令不再写成"要密码"
两处都是「体检工具自己失效」——本仓库最贵的那类坑:判据看起来在跑,其实
结论是假的或者干脆没有结论。
scripts/lib/usb_health.py
Hub 在内核里卡死时,读它的 sysfs 属性会**永久阻塞**(实测
/sys/bus/usb/devices/1-3.4/product 读 20 秒不返回)。于是体检脚本自己挂住:
本该报出故障的那一次,恰恰什么都不输出。新增 SysfsReader —— 所有 sysfs 读取
带 1s 超时,卡死的路径只尝试一次并记入 blocked(Python 杀不掉阻塞在系统调用
里的线程,不记就会在 --watch 反复采样时攒出几十个),blocked 映射回父设备
并按 error 报出「给这个 Hub 断电重启 / 改插主板直连」。
scripts/lib/v4l_health.py
· 提示语写「到真终端里带密码跑 orisys-usb-reset」,与实际不符:sudoers 对这个
脚本本来就是 NOPASSWD 白名单(`sudo -n -l` 可见;orisys_tactile.py 的自动
复位用的也是 sudo -n)。现场按这句会以为无人值守时做不了这件事。
改成 `sudo -n /usr/local/bin/orisys-usb-reset <devpath>` 并说明免密来源。
· wedged 的处置写反了:以前是「物理重插;reset 只在没完全卡死时有效」,
而设备还在 sysfs 里正是 unbind/bind 能生效的前提,先说 reset。
· main() 增加可注入的 v4l_root/usb_root,用例不再读真机 sysfs。
测试:test_main_exit_code_is_nonzero_on_error 以前直接读真 sysfs,本机这只
相机没插(unplugged)时会变红 —— 它本该只在 wedged 下断言复位提示。改为注入
临时 sysfs(设备在总线上、无 /dev/video*),用例变成确定性的。
test_usb_health + test_v4l_health 共 28 项通过。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-28 10:42:37 +08:00 |
|
arm_dev
|
98f4277849
|
真机开工体检四件套:USB 链路 / V4L 设备 / RDK 状态 / 手眼几何
这四个都是「现场看着正常、结果不对」的故障源,共同特征是**不报错**,所以要把它们
从流程里拎出来单独判,并且给出可执行的下一步,而不是只报一个失败。
scripts/lib/usb_health.py
RealSense 协商到 480Mbps(USB 2.0)时能出图、不报错,只是帧率掉到 1/2 且
深度不稳定。这里解析 sysfs 拓扑,把「速率对不对」独立于「有没有图」来判,
并在 --watch 下统计掉线/重连次数(线/口/供电 Hub 的问题会表现为反复抖)。
scripts/lib/v4l_health.py
触觉相机有两类完全不同的坏法,处置方式相反,以前都只表现为「没有 /dev/video*」:
· unplugged —— sysfs 里也没有,是没插/线坏
· wedged —— sysfs 里在、/dev/video* 没有,是 USB 端点了卡死(要复位或重插)
2026-09-28 现场左指就是 wedged(1-3.4.1 在 uvcvideo 下,video 节点缺失)。
scripts/lib/rdk_status.py
ros2_control 卡在 wait_for_operational 时,现象是「栈起来了但关节全是 0、
流程一直等」。原因全在 OperationalStatus 上,而它只有 RDK 读得到。
这里把状态翻成人话 + 处置(Auto(Remote) / 松急停 / 清故障)。
判据取自厂商头文件原话:IN_MANUAL_MODE = "need to switch to Auto (Remote) mode"。
scripts/lib/real_geometry_check.py
手眼矩阵与悬停几何。手眼写坏不会报错,只会让位姿整体偏几毫米到几厘米;
判据:R 正交(|RᵀR−I| ≤ 2e-3)、det(R)=+1、平移量级在 10–500mm。
悬停几何直接复用 gauge_fsm.hover_z_guard(流程里唯一判定处,不另写一套);
工件面未标定(site.yaml 写 0.0 = 未知)时**明确报 FAIL 并说明判不了**,
而不是按 0.0 算出一个假的「已修正」结论。
测试:test_usb_health / test_v4l_health / test_real_geometry_check 共 33 例,
全部钉在「判据要能报错」上(故意弄坏的输入必须被抓到)。
顺带 .gitignore 补 log_real/:真机各终端日志是运行产物,与 log_sim/ 对称。
|
2026-09-28 10:17:32 +08:00 |
|
arm_dev
|
c1cd862eea
|
真机落地前的仿真补齐:夹持/腕力/真值位姿,让仿真能验证 S07–S09
这批是 09-24 那轮仿真工作的收尾,一直没提交。内容按目的分四块:
1) 仿真真能「夹住」工件
sim_grasp_lock:给规与夹爪之间加接触锁(默认关,run_gauge_assembly --sim 才开)。
没有它时仿真里规只靠摩擦,S08 棘轮一转就滑出指间,于是把「仿真不真」误读成
「力判据不对」。新增 test_sim_grasp_lock.py。
2) 腕部力传感器进仿真
sim_wrist_ft(+ config/wrist_ft.yaml):S07 的首选判据是腕部 FT 的轴向突变,
而仿真里以前根本没有腕部力,S07 只能退到触觉兜底,两套判据从没在同一场景下比过。
现在两条通道都在,接触判定可对照。
3) 真值位姿可查(不再靠猜)
sim_live_pose / sim_pose_service:把 Gazebo 里刚体的实测位姿发布出来,
stage2 的真值路径按**实测**位姿算孔位,而不是按场景文件里的标称位姿。
顺带把真值孔位的推导(truth_holes)独立出来并补测。
4) 工具几何成为可配置项
config/sim_tool_geometry.yaml + stage2 的 tool_tip_below_flange_m 启动参数:
仿真里规会在指间下滑,工具长每次装夹都不同(实测见过 243/254mm),
悬停高度与 S07 下探预算必须按实测值算,不能再写死。
应用层同时跟进:gauge_fsm / gauge_config 把「悬停时工具尖端入没入工件」的判据
(hover_z_guard)与拖件判定(drag_verdict)收成纯函数并补测;stage3 搜孔、
site 导出、run_gauge_assembly 与若干文档同步。
新增 test_gauge_exit_lift / test_gauge_gripper_client / test_node_handler_collisions。
测试:全仓库 1085 passed。
|
2026-09-28 10:17:06 +08:00 |
|
arm_dev
|
36a59c81bf
|
应用层修复:S00 自检假阴性、S07 触觉假断流、S07 下探静默卡死
三处都是"看着像硬件问题、其实是判据问题"的假警报:
1. S00 自检假阴性(gauge_boot.py)
探测等待时用 time.sleep 不 spin → 订阅回调根本没机会执行,
于是**健康的硬件也会被判"没有数据"**。改成等待期间持续 spin。
2. S07 触觉假断流(stage3_search_node.py)
判据原本是 |fnormal| > 1.0,但力本来就可能是零或很小(真机轻触、
仿真刚接触)→ 明明在发数据却判"触觉断流"。
改成"数据够新(TACTILE_MAX_AGE_S 内)+ connected" —— 判活看的是
**有没有在发**,不是**数值大不大**。
3. S07 下探静默卡死(gauge_fsm.py / gauge_assembly_node.py)
_goto 的到位容差 ≥ 步长时,每一步都被判成"已在容差内",臂一步都不走,
而外层只看到"没进度"→ 死循环到超时,日志里看不出原因。
新增 descend_tol_m / descend_iter_budget / descend_progress:
容差从步长推导(不该手工调大),并显式判"连续 N 步零位移"。
容差 ≥ 步长的反例已进 site 回归测试,防止再犯。
4. site 分段化(export_site_env.py):89/91 两臂的 servo/handeye/点位
各一段,避免"改 91 影响 89"。
另:run_unit_tests.sh 作为统一测试入口(932→933 项),
devices/sim/gazebo/README.md 同步。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 14:43:19 +08:00 |
|
arm_dev
|
aed5d326a0
|
仿真环境串味根治:清残留路径 + 补 conda lib + 修入口脚本 shebang
症状一(最隐蔽):同一 shell 里先 source 过真机环境(scripts/env.sh)再
source 仿真环境,install/ 与 ros_flexiv 的路径不会被 conda deactivate 撤掉,
长在 install_sim/ 前面:
- PYTHONPATH 里真机那份 arm_msgs 压住仿真那份 → 消息类型混用
- LD_LIBRARY_PATH 里没有 $CONDA_PREFIX/lib → sim_tactile_adapter 订阅
ros_gz_interfaces/Contacts 时抛
Type support not from this implementation ...
cannot open shared object file
而库其实就在 conda 里、ldd 全齐。整条触觉链静默死掉(话题不发)。
症状二:setuptools 写 console_scripts 用的是**构建那一刻**的 python。
若在真机环境里跑过 build_sim.sh,install_sim/ 里 7 个入口脚本的 shebang
会指向 ros_flexiv —— 而 ros2 run 是照 shebang 执行的,于是**仿真节点一直
跑在真机 conda 环境里**。两个环境都是 Humble+py3.11,所以"居然能跑",
只有偶发 dlopen / 反序列化怪错。
修法:
- conda_switch.sh 新增 path_drop_patterns:按 glob 从冒号列表里删条目
- sim_env.sh 清掉真机残留 + 末尾补 $CONDA_PREFIX/lib(优先级最低)
- 新增 lib/fix_shebangs.sh,build.sh / build_sim.sh 收尾各扫一遍(幂等)
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 14:42:50 +08:00 |
|
arm_dev
|
6922b18187
|
仿真夹爪适配器:服务接口对齐真机,开口按正运动学换算成真毫米
为什么
------
应用层只认 arm_msgs/srv/GripperExecute(开口毫米),真机与仿真必须同一套接口。
但 GN01 的 URDF 里 <mimic> 是**线性近似**:直接按线性系数下发 finger_width_joint,
"命令开 20 mm"在 Gazebo 里量出来是 21.75 mm —— 抓不住工件,而且看起来像算法问题。
实测(2026-09-24,Gazebo 内量两指尖间距):
线性下发 20 mm → 实际 21.74 mm(偏差 1.74 mm,超 2 mm 抓取容差的前半步)
走 FK 反解 → 实际 20.00 mm(≤0.5 mm)
怎么改
------
- 新增 sim_gripper_kin.py:解析 URDF 正运动学,算出"主关节值 ↔ 真实开口 mm"的
单调曲线,反解用二分。曲线非单调/零行程时**主动报错**,不静默退化成线性。
- sim_gripper.py:开口换算全部走该曲线;容差统一改成毫米。
- sim_gripper_adapter.py:反馈改取**从动关节**(见下);is_gripped 按毫米判定。
- 新增 check_sim_gripper.py:三层验收(服务/开口一致/指尖真实几何行程 + 对称性)。
踩到的坑
--------
- finger_width_joint 挂在无质量的 unused_finger_width_link 上,与手指**没有机械
连接**:命令到 0.100,它的 /joint_states 恒为 1.4e-08,6 个从动关节才准到
0.7854。反馈若取它,/gripper/status 会永远报"开口 0 mm"。
- 残留进程会伪造出"代码写错了"的现场:旧 sim_gripper_adapter 与新实例抢话题,
验收读到"指尖间距 0.03 mm"(真实 127 mm);孤儿 static_transform_publisher
用 latched /tf_static 把旧相机外参按在新仿真上。
→ 新增 scripts/lib/sim_procs.sh;run_sim_gz.sh 用 setsid 独立进程组,
PGID 记进 log_sim/sim.pgid,stop 时整组 kill;启动前预检拒绝带病启动。
- 验收脚本自己也错过两次(把 TF 的米当毫米比 → 127 mm 显示成 0.13 mm;
用会转动指垫的中点漂移判对称 → 必然位移 16 mm)。判据改成"两侧各走多远",
单位只在 _dist_mm 里换算一次。
验证
----
python3 -m pytest src/arm_sim_gazebo/test/ -q → 307 passed
python3 scripts/check_sim_gripper.py → 三层全过
第 2 层:请求/反馈开口最大偏差 < 0.5 mm
第 3 层:期望行程 vs 实际行程、左右行程差,均 < 1.5 mm
bash scripts/stop_sim_gz.sh --list → 整组列出(含 static tf)
文档
----
- 仿真手册:新增 §4.4(开口 mm 怎么换算)、坑 12(宽度关节不动、
反馈必须取从动关节);停止一节改写成进程组语义。
- FRAMEWORK_RULES:新增 R4.11(残留进程会伪造现场)、R4.12(验收判据要挑
与实现无关的物理量);R4.9 表补夹爪;清单补 13/14 两条。
- HANDBOOK:新增 §3.4「在仿真里开合夹爪」,补 §4.4 的两条新教训。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 09:46:09 +08:00 |
|
arm_dev
|
f5ed44a987
|
配置:消灭代码里的硬编码臂 SN,并给"换臂漏改"加一把尺子
## 为什么
"设备 ID 全部可配置"这条要求在代码里只做了一半:site.yaml 能配,
但**代码和静态配置里到处躺着 Rizon4-063989 当兜底**。这类兜底的危害
不是"改起来麻烦",而是它把"配置没生效"伪装成"配置生效了":
* `robot_sn` 默认 `Rizon4-063989` → 换臂后节点去订**上一台臂**的关节话题,
节点起来了、不报错、什么都不动;
* launch 里用 `ee_frame == "Rizon4-063989_flange"` 当"用户没指定"的哨兵 →
换个站点这个判断永远不成立,于是 site.yaml 里的 ee_frame 再也不会被用上,
静态 TF 挂错坐标系、点还照样查得到;
* `if SN == "Rizon4-063989"` 决定要不要拉触觉服务 → 换臂后触觉静默消失。
## 改了什么
1. **删掉所有"兜底成某台臂"的默认值**(15 处脚本 + 6 个 launch + 6 个节点)。
没配就为空 / 直接 `:?` 报错,宁可起不来也不要连错机器:
- `scripts/lib/export_site_env.py`:别名解析改为从 `robots[]` 现算
(`arm_short_id` / `resolve_robot_sn` / `describe_arms`),选不出臂时
抛 `ValueError`;`main()` 捕获后打人话 + 退出码 2(供 shell `eval`);
- 手眼文件/路点/工作目录由当前臂 short id 派生,不再写死 `89_*`;
- `ROBOT_HAS_TACTILE` 改为读 site.yaml 的 `robots[].tactile`;
- `arm_application/site_io.py` 新增 `joint_prefix_default()` /
`base_frame_default()` / `ee_frame_default()`:优先读 `SITE_*`,
退而由 `SITE_ROBOT_SN` 现算,**不写死 SN**;
- `arm.urdf.xacro` 的 `robot_sn` 默认值改成明显的占位符 `UNSET_ARM_SN`
(关节名会带出来,报错信息自解释);
- `ros2_control.launch.py` / `move_group.launch.py` **原先根本不传
robot_sn**,靠 xacro 写死默认值"蒙对"本机,现在都从环境取。
2. **新增 `scripts/check_arm_prefixes.py`**:Flexiv 把 SN 编进关节名,
所以有一批一级配置(SRDF/controllers/joint_names/bringup/servo/...)
必须跟着当前臂走。漏改的症状是"MoveIt 规划成功但机械臂不动",很难查。
这个脚本逐文件逐行列出对不上的地方,并直接给出修法。
`--list` 还会说明 SN 来自 site.yaml 还是被 `ROBOT_SN` 覆盖。
3. **文档**:`FRAMEWORK_RULES.md` 新增 R1.1.1(两类含臂名文件怎么分、
换臂四步)+ 检查清单第 12 条 + 反例 2 条;`HANDBOOK.md` 新增 3.6.1
与症状表 2 行。
4. **顺带修掉的真 bug**(都是这次改动带出来、被 pyflakes + 真跑抓住的):
- `convert_flexiv_traj.py` / `rdk_drag_bridge.py` 用了 `os` 但没 import
→ `--help` 直接 NameError;
- `check_arm_prefixes.py` 第一版正则用 `\b` 收尾,而关节名是
`Rizon4-063989_joint1`(`_` 属于 \w,`\b` 不成立)→ SRDF 里 24 处
硬编码**一处都没报**,还打印 OK。已加负向测试钉住;
- 删掉若干死代码/死 import(`pos_line`/`flat`/`names`、`IfCondition` 等)。
## 验收(都真跑过)
- `python3 -m pyflakes <全部改过的 py>` → 干净
- 逐包 pytest:233 + 69 + 78 + 24 + 236 = **640 passed**
- `env -u ROBOT_SN python3 scripts/check_arm_prefixes.py` → OK(8 文件)
- 换成 SN=Rizon4-777001 的临时 site.yaml → 报出**8 个**文件不一致并给修法(退出码 1)
- 故意不给 SITE_* → 各 launch 的 `robot_sn` / `ee_frame` / `handeye_file`
默认值为 `''`,不再悄悄指向上一台臂
- `ros2 launch ... --show-args` 对 stack/sim/ros2_control/mock_control/
move_group/display/visual_servo **全部通过**
- `convert_flexiv_traj.py --help` 正常;拿 `xunhuan.traj` 真转 5 个路点,
输出 `joint_prefix: "Rizon4-063989_"` 来自 site.yaml
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 09:18:44 +08:00 |
|
arm_dev
|
72353f3773
|
注释与提示信息全面中文化:源码 66 个 .py + 脚本/配置 45 个文件
背景:现场读代码的人只读中文。此前代码里的 docstring 是英文、行内注释是中文,
一半英文一半中文反而更难看懂 —— 新手打开一个 .py 不知道这个模块为什么存在。
范围(本仓库自己的代码,厂商上游不动)
src/arm_application/** 37 个文件:servo_node / perception_node / handeye_* / dh_pgea /
yolo_detector / kalman_filter / goto_ee_plane / dual_gripper …
src/arm_interfaces/** 11 个文件:paths / manifest / loader / config_guard / errors …
src/arm_control/** 5 个文件
src/arm_bringup/** 3 个 launch
scripts/** 6 个 .py + 29 个 .sh(scripts/ 是"唯一操作入口",用户屏幕上
看到的就是这些提示,所以提示信息也一并中文化)
config/ handeye/ devices/ src/arm_*/config/ 17 个 .yaml/.xml/.xacro/.cfg
口径(写进 docs/FRAMEWORK_RULES.md 新增的 R6.5,作为长期约束)
注释、docstring、print/日志/异常里给人看的句子 = 中文;
标识符、API 名、话题名、参数名、字段名、命令名 = 保留英文原文(用 `` `` 包起来);
单位、十六进制、协议报文、CRC 值、命令示例 = 原样保留;
src/flexiv_*/ = 厂商上游代码,不许改也不许翻译(R4.4)。
翻译保原意与原有详细程度:那些"为什么不能用另一种做法""踩过什么坑"的说明
全部完整保留 —— 它们才是这份代码里最贵的部分。
新增 scripts/check_text_only.py:只改文字时的自证工具
人工 review 靠不住(115 个文件、3000 多行 diff)。这个脚本把改动前后的源码解析成
语法树,删掉 docstring、抹平字符串常量、把 f-string 只留"插值了几次 + 插值是什么",
再比对:完全相同 = 改动范围内没有逻辑变化。
留了一个口子:f-string 的插值按内容排序后再比 —— 因为中文语序常常要和英文反着来
(f"on {port} read {idx} failed" → f"在 {port} 上读 {idx} 失败"),只换显示顺序不该判失败;
但多插一个、少插一个、换掉被插入的表达式,立刻会报出来。
本次 66 个 .py 全部通过该闸门。
验收
改动的 66 个 .py:scripts/check_text_only.py 全部通过(零逻辑变化)
45 个非 .py 文件:去注释后与 HEAD 逐字节相同(零配置变化)
docstring 总数:没有一个文件减少(不存在"翻译时顺手删了说明")
单测:arm_application 233 / arm_driver_flexiv 69 / arm_interfaces 46 /
arm_kinematics 24 / arm_sim_gazebo 236 = 608 passed,与改动前一致
全部 .sh:bash -n 通过;并额外实际执行了 --help 验证(见下一个提交:
bash -n 对 CRLF 脚本会漏报,只有真跑才暴露)
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 17:40:55 +08:00 |
|
arm_dev
|
a89250d05d
|
P5c-1:把 Gazebo 仿真环境真正装起来(独立 conda 环境),并固化安装/构建流程
在此之前,仓库里所有 Gazebo 相关的东西都是"声明"而非"事实":
arm.gazebo.xacro 零引用、stack.launch.py 的 isaac 分支只打印日志、
没有 world 文件、devices/sim/gazebo 下的目录全是空占位。
更关键的是:**这台机器上根本没装 Gazebo**,而 ROS 在 conda 里,没有 /opt/ros,
apt 的 ros-humble-gazebo-* 装了也不会被 conda 的 ROS 认到。
环境(与真机环境物理隔离)
- 新建 conda 环境 ros_gz_sim,**不碰能跑真机的 ros_flexiv**。
仿真要往环境里塞 Gazebo 及 protobuf/ignition/渲染一整条链,
和真机环境混装随时可能把它弄坏,代价远大于仿真带来的便利。
- 频道组合照抄 ros_flexiv 的安装记录(robostack-staging + conda-forge),
那是本机已经证明可用的搭配。
两个实测踩到的坑(都写进了脚本注释,避免下次重踩)
1. empy 版本:conda 默认给 empy 4.x,而 Humble 的 rosidl_adapter 用的是 3.x 的
API。症状是构建自定义消息包时报 `_interpreter.shutdown()` 的 AttributeError,
报错点在 rosidl_adapter 内部,完全看不出跟 empy 有关。必须钉 empy=3.3.4。
2. conda 激活是**堆叠**的:同一 shell 里从 ros_gz_sim 切到 ros_flexiv 后,
`which python` 指向 ros_flexiv,但 `python -m pip` 却解析到 ros_gz_sim 的 pip,
导致 colcon --symlink-install 报 "option --editable not recognized"。
这个报错和真实原因毫无关系,极易误判成"环境被搞坏了"。
现在 scripts/lib/conda_switch.sh 会在切换前退到 base,两个 env 脚本共用。
仿真用独立构建产物
- build_sim/ + install_sim/(scripts/build_sim.sh)。工作区只有一份源码,
若仿真也写 install/,就会覆盖真机的构建产物。
- 排除 11 个真机专属包(flexiv_hardware 需要 Flexiv RDK C++ SDK,根本装不上;
另有真机驱动/GPIO/MoveIt 配置/真机 bringup),每个都在脚本里写了理由。
已验证(不是只看退出码)
- Gazebo Fortress 6.16 无头启动正常,物理初始化完成
- /clock 桥接到 ROS 成功收到仿真时间;ros_gz_sim create 成功往世界里建物
- 真机构建 18 包通过、233 项测试通过,build/ install/ 时间戳未变(没被覆盖)
- 仿真侧 7 包构建通过;两环境互切后各自都能正常构建
注:Humble 配的是 Gazebo Fortress(ignition-gazebo6,命令行 `ign gazebo`),
不是现代的 gz-sim —— 后者要 libprotobuf>=6.31,与 RoboStack Humble 钉住的
5.29.3 解不开依赖。Fortress 属于新 Gazebo 家族(非已 EOL 的 Classic),
且是 Humble 的官方配对版本。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 13:52:04 +08:00 |
|
arm_dev
|
2b77ec127d
|
P4:权重/标签模块 —— 旁挂标签文件 + PT→ONNX→TRT 转换工具 + 归档归位
痛点:TensorRT 10.13 的 Python API 没有元数据读写,engine 一转就把类名丢了;
推理侧只能退化成 str(cid)("0"、"1"),界面上看不出是什么类,属于静默失效。
同时旧的 export_yolo_trt.sh 只能手工搬文件、手工改 site.yaml、标签无处安放。
标签子系统(model_labels.py)
- 旁挂标签文件 <模型名>.labels.yaml,放在权重旁边,文本、可手改、进 git
(二进制权重不进 git,标签是配置所以进)
- 读取优先级:旁挂文件 > ONNX 元数据 > 模型元数据 > 占位符 class_N
占位符是故意的:缺标签时要一眼看出来,而不是悄悄退回 cid
- 解析器容忍多种写法:dict / list / 逗号串 / 逐行文本 / Python repr 串
布局与转换(weights_layout.py + weights.py + weights.sh)
- models/<分组>/<模型名>.{pt,onnx,engine} + 同名 .labels.yaml
- convert:PT→ONNX→TensorRT,支持自定义名字、自动归位、固化标签
- staging/:非标准格式先进这里,转换后源文件归档到 staging/done/
- list / labels / doctor / show 四个子命令
- doctor --check-engines 能查出 engine 与 TensorRT 版本不匹配(反序列化返回空)
推理侧接入
- yolo_detector / onnx_workpiece / hole_detect_hough 统一走 read_labels()
- 画框标签不再硬编码 "gongjian",改用实际类名
顺手修掉的真实问题
- setup.py 撞上断掉的符号链接会让整包构建失败,报错还指向 build/ 里的幽灵文件
(源文件被挪走后 build/ 里留下的断链被 os.walk 列出来)。加 _existing() 过滤。
- P3 遗漏:site.yaml / export_site_env.py / run_handeye.sh / handeye_teach.py /
handeye_calibrate.py 里的 handeye 工作目录仍是 /tmp/handeye_calib*,
与已迁到 handeye/ 的其余路径不一致。统一到 handeye/tmp/<臂号>。
- site.yaml 的 hole_weights / hole_detect.weights 原指向不存在的 best.pt,
改为实际存在的 detect_best_1.onnx;active.pt 符号链接已废弃并清理。
- weights.sh labels 原先不接受 "分组/模型名" 写法,而 list 输出正是这个形式,
照着敲会报"找不到模型"。补上,并让报错直接给出可复制的全名。
测试:225 项通过(新增 test_model_labels.py / test_weights_layout.py)。
真实 ONNX→engine 端到端转换已验过。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 12:39:18 +08:00 |
|
arm_dev
|
a3a589b9e3
|
P3a:手眼标定集中到 handeye/,修复三套板尺寸矛盾与从未生效的稳定性参数
新建 handeye/ 专用文件夹(用户要求:专用文件夹 + 使用说明)
- handeye/README.md:从小白视角讲清楚两种模式怎么选、板尺寸怎么量、
完整流程、出问题先看哪里。以前这些知识散在 docs/ 和代码注释里。
- 结构:calibrate.yaml(参数)/ poses/(采点输入)/ results/(结果输出)/ tmp/(临时,不进 git)
- 文件用 git mv 迁移,历史保留
命名约定改为 <臂号>_<模式>.yaml
- 如 89_eye_in_hand.yaml、91_eye_to_hand.yaml
- 臂号 = Flexiv 序列号后两位;模式 = eye_in_hand | eye_to_hand
- 换模式 = 改 site.yaml 里 paths.handeye_file 一行,不动代码
- 迁移只需改 site.yaml(4 个 launch + servo_node 都经 paths 读取,一行没改)
修复:三套互相矛盾的标定板尺寸(真实 bug)
同一个"板子多大"分散在三处,且值各不相同:
handeye_calibrate.py 默认 9x6 / 0.025
handeye/calibrate.yaml 11x16 / 0.011
site.yaml + 结果文件头 8x11 / 0.015 ← 实测的真实板子
谁生效取决于覆盖顺序。症状是"标定流程跑得很顺、不报错,但结果明显不对",
极难排查。已全部统一为 8x11 / 0.015,README 里写明换板必须三处同改。
修复:site.yaml 里五项稳定性配置从未生效
run_handeye.sh 一直在传 settle_qd_max / settle_stable_sec / settle_timeout_sec /
pin_holds / pin_hold_sec,但 handeye_calibrate.py 从未声明这些参数 ——
ROS 2 会静默忽略未声明的覆盖参数,所以"等机械臂停稳再拍照"这件事其实没实现,
实际只有一次固定 settle_sec。现已声明并实现:
- _wait_settled():用关节速度 |qd|_max 判定"真的停了",比固定 sleep 可靠
(负载/姿态不同刹车距离差别很大;等太短会在臂还动时拍照导致角点抖动)
- _pin_hold():静止后再保持几拍,抑制到位后的微小回弹
新增:自动标定进度条
一条可视化进度条([ 4/12] [████░░░░] 33.3%),无人值守的长流程能一眼看出还剩多久。
清理重复文件(内容逐字节比对确认后删除)
- config/handeye_result.yaml 与 _89 逐字节相同 → 删
- config/handeye_poses.yaml 与 _89 逐字节相同 → 删
迁移后 src/arm_application/config/ 下已无 handeye 文件。
测试:224 passed(原 198,新增 26)
新增 src/arm_application/test/test_handeye_lib.py —— 手眼模块此前零测试。
关键用例是合成数据往返:用人为设定的 X_true 反推出每个视图的
(gripper→base, target→cam),再让求解器还原。坐标链方向/求逆/转置
只要有一处写错就必然失败。
- 真值恢复(旋转+平移,atol 1e-6)
- 单独验证平移精确(旋转对而平移错是最易漏的一类 bug)
- 结果必须是 det=+1 的正交阵(排除镜像解)
- 退化输入(全同位姿)不得悄悄给出"看起来能用"的结果
- 稳定性判据:窗口未满不判稳、丢帧后重新计数、抖动超阈不判稳
- 写盘再读回不漂移
|
2026-09-23 11:46:03 +08:00 |
|
arm_dev
|
883ed6b0b9
|
P1:设备契约层收尾 + Flexiv 驱动适配器 + 触觉四路数据打通
新增包
- arm_kinematics:从 arm_application 提取几何雅可比 + DLS 逆解(纯 numpy)。
它被应用层和驱动层共用,留在应用层会让驱动反向依赖应用层。
arm_application/geom_ik.py 改为 re-export shim,现有 import 一行未改。
- arm_driver_flexiv:非夕驱动适配器。只补 manifest 声明而现有节点缺失的接口
(/home /enable /clear_fault /switch_tool /soft_drag /compliant_descent),
已有能力不重复实现。RDK 访问经 rdk_py310 下的长驻桥,本包不 import flexivrdk。
新接口
- arm_msgs/SwitchTool.srv、arm_msgs/CompliantDescent.action
- 合并 capabilities 里语义重复的 set_tool / switch_tool
修复(都是只在真机上暴露、且难以定位的问题)
- rdk_client 会永久挂死:select 的"可读"不等于"有完整一行",readline 遇到
半行 JSON 会一直阻塞等换行符,超时机制完全失效。改用 os.read + 自己做行缓冲。
- CompliantDescent 行程少一步:descended + step > max 在浮点累加下会提前跳出,
永远到不了标称行程。改用整数步数计数。
- CompliantDescentRunner 的 TF frame 退化成 _base_link:没继承节点已解析的 SN。
- resolve_orisys_config 仍指向旧路径;load_orisys_from_site 读的是旧键 config。
触觉四路数据打通
- 深度图 / 力矢量场原先被 tactile_worker 有意丢弃(注释写"图像不过队列"),
从未发布到 ROS。新增 image_utils(数组→Image,编码自动判定)、独立的图像
队列(maxsize=1 满则丢旧)与 /tactile/<side>/{image,vector}。
默认关闭(tactile.image_hz=0),开启也不影响三力的 30fps 时序。
- mock 后端也会发图像,无硬件即可验证整条发布链路。
配置
- site.yaml 新增 tactile.image_hz;移除与 model 重复的旧键 tactile.config
- 型号配置从 src/arm_application/config/orisys/ 迁到
devices/sensors/orisys/models/dd03/(随 SDK 一起放)
测试:198 个(原 139)
- arm_kinematics 24(雅可比/逆解的解析算例与不变量)
- arm_driver_flexiv 69(下压状态机 34 + RDK 协议层 35)
- arm_application 59(图像打包 36 + 矢量场探测 23)
|
2026-09-23 11:17:12 +08:00 |
|
arm_dev
|
6edb8d39ab
|
chore: 框架科学优化前的完整基线
在开始'设备契约层 + 目录重构 + 通止规装配'改造之前,先钉住当前可运行状态,
使后续任何删除/重构都可回退。
本基线包含:
- 现有 ROS 2 工作区全部源码(arm_application / arm_control / arm_bringup 等)
- 官方 flexiv_ros2 栈(含 flexiv_hardware / flexiv_controllers 等符号链接)
- 设备契约层 src/arm_interfaces(新增,46 项单测通过)
- devices/ 设备选型与品牌清单(新增)
- scripts/gen_site_example.py 与由它生成的 config/site.example.yaml
按 .gitignore 排除:build/ / install/ / log/ / config/site.yaml / 模型权重二进制。
|
2026-09-23 10:53:06 +08:00 |
|