0a2a28a355
1) site.yaml 的整数把节点写死(ros_node.TolerantNode)
现场 site.yaml 写 `ae_limit_us: 8000`(YAML 整数),脚本按 `-p ae_limit_us:=8000`
传参,而节点 declare 的是 double —— rclpy 严格比对类型,节点**启动即崩**:
InvalidParameterTypeException: Trying to set parameter 'ae_limit_us'
to '8000' of type 'INTEGER', expecting type 'DOUBLE'
现场看到的只是「顶置 D435 起不来」,报错里一个字都没提 site.yaml,而
`8000` 与 `8000.0` 在运维眼里是同一个数。同一族的雷还有 width 848.0→int、
emitter_enabled 1→bool、带不带引号的序列号。
修法是新增应用层统一基类 TolerantNode:在**声明阶段**把覆盖值的类型按
声明类型收敛(异常就发生在声明阶段,所以 `float(...)` 这种事后 cast 救不了)。
全部应用节点改继承它;补 test_ros_node.py。
2) 权重目录判据(weights_layout)
模型文件「在不在、名字对不对」以前散在几处各判一半,缺文件时的现象是
推理静默退回随机权重。收成 weights_layout.py 一条判据 + scripts/weights.py 调用。
3) 相机日志:USB 降速要说清怎么办
realsense_color_pub 协商到 USB 2.1 / 480Mbps 时只打一行速率,没人知道该做什么;
现在直接给可执行的处置(换线/换口/SuperSpeed 不复用)。realsense_view 同步。
4) stage2_locate:接上 hover_z_guard 与 tool_tip_below_flange_m
悬停高度必须让工具尖端留在工件面上方(09-24 的教训:悬停时尖端已钻进工件
25mm,S05 横向对准把工件拖走 92mm)。step2 侧也按同一判据兜住,且工具长
允许由启动参数覆盖(仿真上料后实测得到)。
5) config/site.example.yaml 与 site.yaml 重新同步
上一批给夹爪加了 auto_init: false,模板没跟着重跑,TestExampleParity 因此失败。
重跑 scripts/gen_site_example.py 同步(模板是生成物,不手改)。
测试:全仓库 1085 passed(此前 1 failed)。
scripts — 唯一操作入口
实现细节在 docs/WORKSPACE.md 和 docs/。
每天: run_real.sh · run_camera_d405.sh · run_visual_servo_rt.sh · go_home.sh
三阶段串联: run_all.sh --arm 89 [--hole k2] [--skip-stage1](run_pipeline.sh 是它的旧名别名)
手眼: run_handeye.sh(teach / merge / calibrate / show)
夹爪: run_gripper.sh --arm 89|91 · run_dual_gripper.sh
入孔: run_hole_detect.sh --arm … [--preview]
触觉: run_tactile.sh [--cli]
通止规装配: run_gauge_assembly.sh --arm 89 [--dry-run] [--holes N] [--backend …]
- 一台状态机走完 S00–S11(自检 → 回 home/预绕 → 粗定位 → 跟踪 → 稳定拍照 → 悬停 → 柔顺接触 → 棘轮拧入 → 拧出 → 换孔 → 复位)。
--dry-run不发任何运动指令,只验编排与自检 —— 改完配置先这么跑。- 前置服务(臂 / 腕部相机 / 夹爪 / 触觉)要自己先起;缺哪项由 S00 自检逐项报出 并停住(不代你启动,也不"带病往下跑")。
- 掉件(E1):流程停在 home 等人,把规塞回爪里后发一次
ros2 topic pub --once /gauge/reload_ok std_msgs/msg/Bool "{data: true}"。 - 判据、调参顺序、还没做的部分:docs/GAUGE_ASSEMBLY.md
权重:
weights.sh(list/labels/convert/doctor/show) - 转换:
weights.sh convert <文件> --name <模型名>—— PT→ONNX→TensorRT,自动改名归位 + 固化标签 - 标签:
weights.sh labels <模型名>看,--set "工件,通止规"改 - 体检:
weights.sh doctor --check-engines(能查出 engine 与 TensorRT 版本不匹配这类静默失效) - 规则写在 models/README.md。
export_yolo_trt.sh现在是它的兼容转发壳。 配置:show_site_config.sh·lib/export_site_env.py
仿真:run_sim_gz.sh(Gazebo 物理仿真,唯一能做接触/力控验证的入口) 停:stop_sim_gz.sh(别敲pkill -f gz—— 会杀掉调用它的 shell,见脚本文件头) - 环境是独立 conda 环境
ros_gz_sim(install_sim_env.sh装、sim_env.sh激活),与真机环境隔离 - 相机验收:
python3 scripts/check_sim_cameras.py—— 别用ros2 topic hz或肉眼看图验收相机, 仿真相机的错误几乎全是静默的(深度单位、frame_id、内参、位姿方向),都能出图却是错的。 这条命令把深度反投影到 world,要求命中已知平面(地面/台面)才算通过。 - 场景验收:
python3 scripts/check_sim_scene.py—— 同样别靠肉眼。它管四件事: 物体的摆放(悬空/穿模/出界/互相嵌入)、场景里的像素门槛与真机生效值是否漂移、 孔检测的成像几何(亮环/孔间距换算成像素后够不够门槛)、以及粗定位用的手外相机 能不能完整看见工件。第二条尤其重要:门槛抄了两份,不一致时仿真会"通过"而真机不认。 - 注意
run_sim.sh不是 Gazebo,它走 mock 驱动(假数据 + RViz),永远不会产生接触力 环境:env.sh·build_all.sh
RDK:test_rdk_python.sh·rdk_switch_tool.sh·rdk_drag_bridge.py
改注释/写文档后自检:python3 scripts/check_text_only.py - 用途:证明这次改动只动了文字(注释、docstring、提示信息),没碰逻辑。
它把改动前后的源码解析成语法树,删掉 docstring、抹平字符串常量后比对;
"翻译 f-string 时漏掉一个
{}插值""顺手改了个变量名"这类问题会被抓出来。 python3 scripts/check_text_only.py查所有改过的.py;也可以直接跟文件名。 基准是git HEAD,所以要在提交之前跑。老手滑手滑的代价比跑一条命令高得多。- 规矩写在 docs/FRAMEWORK_RULES.md 的 R6.5。
一句话:注释/docstring/提示信息用中文;标识符、话题名、字段名保留英文
(但
src/flexiv_*/是厂商上游代码,不许翻译,见 R4.4)。 搁置未用:fetch_isaac_flexiv.sh(拉 Flexiv 的 Isaac Sim / RDK 源码到thirdparty/;Isaac 路线目前搁置,Gazebo 是选定平台)
lib/parse_arm_args.sh 解析 --arm 89|91。
lib/load_site_config.sh 把 config/site.yaml 变成 SITE_*。
排查脚本卡住时的常识
几个脚本开头会等外部条件(控制器 ACTIVE、相机出图、触觉就绪)。正确的判活顺序是
先 ros2 service list / ros2 topic list 看目标在不在,再去 call / echo:
# 对:服务不存在时立刻返回
timeout 3 ros2 service list | grep -q '^/controller_manager/list_controllers$' || exit 1
timeout 3 ros2 service call /controller_manager/list_controllers ...
# 错:服务不存在时每次 call 都要耗满超时才返回,
# 30 次循环 = 白等两三分钟(实测 63s),看起来就像脚本卡死了
for _i in $(seq 1 30); do timeout 5 ros2 service call ... ; done
run_all.sh / run_stage2_locate.sh / run_stage3_search.sh 已按正确顺序改过;
run_handeye.sh 一开始就是对的。