arm_dev
|
7d22f777c8
|
把当前控制栈收成一份可克隆的源码:腕部看不见时用顶视一次定到基座,二阶段对孔和手外标定跟着进同一份树。
现场 site.yaml、权重和编译产物仍不入库;模板只留占位符。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-10-09 14:51:03 +08:00 |
|
arm_dev
|
bda2fa7129
|
通止规装配:配置段进 site.yaml + 中文手册 + 成败判定「不看 $?」
配置(site.yaml → gauge_assembly:,38 键全部带中文注释)
------------------------------------------------------
- 键名/单位/类型/交叉矛盾由 gauge_config.py 校验:拼错键名报错并给最相近的候选,
单位后缀(_deg/_mm/_m/_s/_pct/_delta)逐条对表,`contact_safe_delta ≤
contact_tangential_delta` 这类矛盾启动就拦(R1.2:没接线的键不许静默存在)。
- 借机清掉 4 个**没接线**的键(require_preview / track_*_s / hover_m:前两个是
stage1 那层的、后两个是 servo 那层的,放在这里等于第二份真相),
并把 contact_speed_m_s / coarse_timeout_s / 夹爪力速 真的接上。
- site.example.yaml 由 site.yaml 生成(gen_site_example.py --check 通过)。
成败判定:`ros2 launch` 的退出码**恒为 0**
------------------------------------------
实测(Humble):子进程 exit 3,`ros2 launch` 仍返回 0。用 `$?` 判成败的脚本会把
"装配失败"记成"成功"——没人会去查一个说成功的脚本。改成:
- 节点把结论**落盘**(--result-file,默认 /tmp/gauge_assembly_result.json,原子写、
先落盘再发话题),任何"没跑到收尾"的退出也会补一份 ok=false;
- 脚本读结论文件判成败:0=成功、1=失败、**文件不存在也算失败**并说清;
- 新增 test_gauge_result_gate.py:把脚本里那段判成败的 Python 抽出来,
对成功/失败/干跑/缺文件/坏 JSON 五种输入断言退出码 —— 判据本身也有测试。
顺带修掉两个"看着像玄学"的现象
------------------------------
- **流程打完了终端不回提示符**:launch 里的静态 TF 发布者是常驻的,主节点退出
带不走它 —— 挂 OnProcessExit → Shutdown。
- **"已装 1/2 孔"**:结果里 hole_index 是 0 基当前孔号,不是"装完几个",
新增 holes_done 给人和脚本看。
文档(全部中文,含"怎么调参/还没做")
------------------------------------
- 新增 docs/GAUGE_ASSEMBLY.md:状态机全图、每步判据表、E1 掉件处理(**按实现**:
掉件后该孔作废、换下一个孔;最后一个孔掉件则序号被夹住=重试本孔)、
话题契约、调参顺序、验收命令、踩过的坑。
- FRAMEWORK_RULES 新增 R5.8(同一份数学只许一份 + 守卫测试)、R5.9(自检的
期望类型与调用处同源)、R5.10(缺依赖 skip,别留常年红)、R6.9(硬退出前打
traceback)、R6.10(ros2 launch 退出码恒 0)+ R5.7 补真机/仿真"生效方式不同"
(真机软链即改即生效,仿真拷贝必须重编)+ 5 条症状反例、.cursor/rules 同步。
- WORKSPACE / INTERFACES / SITE_CONFIG / HANDBOOK / 两份 README 索引与决策表补齐。
验证(本机真跑)
----------------
pytest(仿真环境) 436 passed, 14 skipped(缺 onnx 跳过)
干跑 --sim --dry-run → 脚本退出码 0,结论 ok=true 已装 2/2 孔
不干跑 --sim → 脚本退出码 1,S00 拦住,未发任何运动指令
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 10:30:11 +08:00 |
|
arm_dev
|
fac2d5384d
|
P5b 新手手册:这台机器在干什么 / 改哪里 / 怎么验 / 出问题查哪
此前仓库有规则文档(FRAMEWORK_RULES)、有目录表(WORKSPACE)、有各模块说明,
但**缺一份"从零进来的人读什么"**:业务目标没有一处讲清("通止规装配"散落在
7 个文件里各提一句),测试怎么跑在 docs/ 里一次都没写过,改一个东西该动哪个文件
要靠翻源码猜。
docs/HANDBOOK.md(416 行,新增)
1. 这台机器在干什么 —— 通止规是检验螺纹的量具(通端应旋到底、止端应旋不进);
为什么值得自动化(留下可追溯的力曲线);三段主线的数据流;日志三行判进度。
★ 1.4 节是**承诺书**:逐项标 ✅/⚠️/❌,并给出"哪条命令能证明它已就绪"。
如实写明还没做的四项:自动拉起全部服务、夹爪持规自检、D435 手眼标定、
装配合格判定。指不出验证命令的,就老实标 ❌(R6.1)。
2. 系统长什么样 —— 三层各有硬边界;两块**独占资源**(RDK、D405 USB)
以及各自的冲突表现;从像素到关节的全链路加上"每步的口径写错会怎么表现"。
3. 我要改东西,改哪里 —— 决策表(改 X → 动 Y → 用 Z 验),覆盖换臂/悬高/夹爪/
入孔/触觉/相机/仿真场景/权重/新品牌设备/命名位姿。每行都外链权威文档,
不复制内容(M2)。
4. 怎么验 —— 三层验收(不报错不算验收 / 物理量命中真值 / 任务成功)+ 命令清单 +
**单元测试怎么跑**(此前 docs/ 里没有任何一处写过)。含 608 项分包清单。
4.4 节专讲"验收工具自己也会失效",把 M1/R5.3/R6.6 串成一条线。
5. 出问题按现象查 —— 三处权威文档的分工表 + 15 行"现象 → 先怀疑什么",
覆盖 8 条仿真坑与全部触觉坑(坑 1/2/5/6/7/9/10)。
6. 术语表 + 未做的事(按优先级)+ 往下读的路线。
顺带写进规则的(docs/FRAMEWORK_RULES.md)
R6.7 验收命令必须真跑过 —— 本仓库已经因此踩过两次(CRLF 死脚本被五处文档推荐)
R6.8 install/ 构建产物会互相污染 —— 见下面这个发现
第 7 节清单加两条(第 10 条真跑过命令、第 11 条构建环境对不对)
第 8 节反例表加三行症状
★ 顺带发现一个哑弹(R6.8,**已记录未修**)
colcon build 会把当时激活的那个 python 的绝对路径写进每个入口脚本的 shebang。
实测:install/ 里 31/59 条指向仿真环境 ros_gz_sim,install_sim/ 里 31/55 条
(后者是对的)—— 说明真机 install/ 是在仿真 conda 环境里构建出来的,违反 R5.7。
$ head -1 install/arm_interfaces/lib/arm_interfaces/device_check
#!/home/cc/anaconda3/envs/ros_gz_sim/bin/python3.11
为什么现在没炸:两个 conda 环境的 Python 依赖当前完全相同(pyrealsense2 / serial /
cv2 / numpy / torch / ultralytics / tensorrt 都在),指错了也照样 import 成功。
这是一颗哑弹 —— 哪天某个环境多装或少装一个包,真机栈就会以"模块找不到"的形式炸,
而人是不会想到去查 shebang 的。
修法(写进 R6.8,待执行):在真机 conda 环境里重建 install/,再
`grep -l ros_gz_sim install/*/lib/*/* | wc -l` 应当变成 0。
预防:构建脚本开头应断言当前 conda 环境与目标一致(待补)。
验收
- 文档内所有相对链接与反引号路径引用均存在(脚本检查,0 坏链)
- 文档里给的每条命令都实际执行过:
ros2 run arm_interfaces device_check 通过
device_check --list-brands 列出 5 类设备
scripts/show_site_config.sh 存在
check_sim_cameras.py / check_sim_scene.py / check_text_only.py 存在
for d in src/*/test ... pytest 循环 608 passed
- 单测 608 passed,与改动前一致(本次只改文档)
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-24 09:05:09 +08:00 |
|
arm_dev
|
d78e66ce98
|
P5a 框架规则文档:M1-M3 元规则 + R1-R6 分领域规矩 + 反例清单
背景:这个框架踩过的坑几乎都是同一类——"没报错但结果是错的"。
之前这些教训只存在于聊天记录和零散注释里,改一次代码就要重踩一遍。
现在收敛成一份可引用的文档,并压缩成 .cursor/rules/ 常驻规则。
docs/FRAMEWORK_RULES.md(414 行)
第 0 节 三条元规则:M1 静默失效是头号敌人 / M2 单一数据源 / M3 口径必须显式
第 1 节 配置与数据 R1.1-R1.5(分层优先级、site.yaml 新键必须接线或告警、设备走 devices/、权重走 models/)
第 2 节 几何/单位/坐标系 R2.1-R2.7(米与弧度、frame_id 必须是光学系、深度 mm↔m、
rpy=Rz·Ry·Rx、Gazebo camera_info 不可信、像素门槛绑图幅、位姿容差要写理由)
第 3 节 触觉与力 R3.1-R3.6(力是相对基线的增量、fnormal 压为正、轴向映射必须实测、
接触布尔要用超时、force_scale 口径、仿真图像只能占位)
第 4 节 仿真 R4.1-R4.10(唯一 site.yaml、world 里写 plugin 会挤掉默认系统、搜索路径要在
launch 前设好、上游 description 不许改、场景走 scene.yaml、校验要逐碰撞体、
不用"有话题就算通"验收、停仿真用 stop_sim_gz.sh)
第 5 节 代码与测试 R5.1-R5.7(纯逻辑抽纯函数、校验要有测试证明有效、不许把降级写成通过、
解析外部输出先确认真实格式、删除前扫全仓库引用、别在中文路径 colcon build、真机仿真产物隔离)
第 6 节 文档与提交 R6.1-R6.4(文档与实现不一致立刻修文档、每份文档说明记录什么事实、
结论数字要可复现、提交信息讲为什么并附实测数据)
第 7 节 改动前检查清单
第 8 节 历史反例清单——按"你看到的症状"查表,不是按道理排序
第 9 节 给 AI 的具体指令
.cursor/rules/*.mdc 三份压缩版(常驻)
framework-core.mdc alwaysApply,元规则 + 检查清单 + 禁止项
sim-gazebo.mdc globs=devices/sim/**,src/arm_sim_gazebo/**
config-and-devices.mdc globs=config/**,devices/**,models/**,src/arm_interfaces/**
顺手修掉文档与实现不一致(R6.1)
docs/WORKSPACE.md 此前【完全没有 devices/ 这一层】——通用化落点却没进目录总表。
补 devices/ 一节(kind/brand 目录约定、registry.yaml 与 manifest.yaml 分工、
assets[].required 缺失会报错),补 build_sim/install_sim/log_sim 与 .cursor/rules/,
并把 FRAMEWORK_RULES.md 标为 docs/ 首行
README.md 文档表首行加 FRAMEWORK_RULES.md
顺手删死代码(R5.5:先扫引用)
src/arm_interfaces/arm_interfaces/paths.py 删 assets_root()
它返回 ros2_root()/"assets",而仓库里从来没有 assets/ 这个目录——实际权重树是 models/,
且 models/ 的定位已由 arm_application.weights_layout.default_weights_root() 负责
(带 SITE_WEIGHTS_ROOT 覆盖,且能从 install/ 反查仓库根)。
两个实现并存违反 M2,且这个还指向不存在的路径,属于"照着名字用就踩空"。
src/arm_interfaces/test/test_real_devices.py 从清环境变量列表里去掉 SITE_ASSETS_ROOT
验收
src/arm_application 233 passed / arm_driver_flexiv 69 / arm_interfaces 46 /
arm_kinematics 24 / arm_sim_gazebo 236 = 608 passed
(flexiv_rdk 的 test 需装厂商 flexivrdk 包,仿真环境无此依赖,与本改动无关)
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 17:16:47 +08:00 |
|
arm_dev
|
d32e6ae53f
|
P5c-6 场景物料落地 + Gazebo 中文手册:工件/通止规模型、场景校验、两处静默失效修复
一、场景物料(新增)
devices/sim/gazebo/models/workpiece/ 带三个孔的铝板。碰撞体是"带方孔的平板",
视觉额外加两个 φ14/φ7 亮环 —— 因为真机的 HoughCircles 就是靠这两个亮环找孔,
只按碰撞体建视觉会让"孔检测"在仿真里永远失败,而那看起来像算法问题。
devices/sim/gazebo/models/gauge/ 通止规:通端/套环/握柄/止端四段,各段异色
便于肉眼判断方向。接触刚度刻意比台面软 —— 位置控制器会"刚性压进去",
用默认刚度会被弹飞(注释里写了原因,不是随手抄的参数)。
devices/sim/gazebo/models/gauge_stand/ 规座(static)。规直接站在台面上会立刻倒,
加个方孔底座把它立住。
三个模型都是 model.sdf + model.config,原点在**底面中心**,单位米。
二、场景配置与校验(新增)
config/scene.yaml 物体不再写死在 world 里,改为 scene.yaml + 启动时动态 spawn。
理由:world 是"环境"(地面/台面/相机/系统插件),场景是"这一批活做什么"。
动 world 的风险面太大 —— 它只要丢一个系统声明,所有模型都 spawn 不进去(见旧坑 2)。
含 operating(相机到工件的距离等作业条件)与 gates_px(像素门槛)。
sim_scene.py 摆放校验:从 SDF **逐碰撞体**解析 AABB(不抄尺寸,避免漂移),
检查原点在底面 / 不穿台面 / 不出界 / 物体之间不嵌入。
重叠判定必须逐碰撞体三维判,不能拿总包围盒相交 ——
正常装配里本来就有嵌套(规立在规座方孔里),粗判会误报,
而误报的后果是人把检查整个关掉,之后真重叠也抓不到。
另有成像几何:把亮环/孔间距按相机距离换算成像素,与门槛比对。
scripts/check_sim_scene.py 验收工具(退出码可用):摆放 + 门槛漂移 + 成像几何 +
悬停高度 vs 工作空间 + 手外相机是否**完整**看得见工件 + Gazebo 实际位姿。
三、修掉两处静默失效(都是"看起来一切正常")
1) parse_spawned_poses 一直是**死代码**:它按 "x: N / y: N / z: N" 解析,
而 Fortress 实际输出是方括号两行(XYZ / RPY)。对不上 → 永远返回空 →
调用方按设计"降级成跳过位姿核对" → 位姿检查**从来没跑过**,
而日志只说"跳过",看起来像正常降级。
现在两种格式都支持,并用真实抓下来的输出样本做回归测试。
教训:宽容降级会把"没检查"伪装成"检查通过"。
2) stop_sim_gz.sh 的模式表里漏了 robot_state_publisher(而注释里写着它有覆盖):
脚本报"已停止",它却还在发上一份 /robot_description 与 TF,
下一次启动就会"改了描述却不生效"。
顺带修掉同源的两个问题:awk 用 -v 传模式导致它匹配到自己、每次复查都多报
一个空命令行的幽灵 PID;以及"杀的时候"和"复查的时候"两份扫描实现会各自漂移。
现在共用同一个 scan_pids(),模式改用环境变量传递,并在杀完之后**再扫一遍**:
有残留就报出来并非零退出 —— 下次再有漏项,不再静默。
实测:--list 列出全套 9 个进程;停止后 rc=0 且 pgrep 干净。
四、相机:D405 分辨率对齐真机
仿真的 D405 此前渲染 640x480,而真机跑 848x480(fx 337 而非 447)。后果是
58mm 的两孔间距成像只剩 85px,低于 hole_distance_min=90 ——
孔检测在仿真里根本不可能通过,而现象看起来像"算法不行"。
已把 xacro 与 cameras.yaml 一起改成 848x480,并把启动时的比对从"只比视场"
扩成"视场 + 图幅"(sim_cameras.check_camera_consistency),
不一致时说明它对像素门槛的影响。
五、文档
devices/sim/gazebo/README.md 重写为中文手册:使用方法 / 建模要求 / 导入格式 /
配置方式(含"改哪里才真的生效"的接线表)/ 11 条实测坑(每条都有"怎么发现")。
manifest.yaml 的进度、assets、description、坑清单与本轮状态对齐。
scripts/README.md 补两个验收工具与停止脚本;根 README 补仿真入口与手册链接。
cameras.yaml 里一处过期的函数名(check_fov_consistency)修正。
六、测试
新增 test_sim_scene.py(79 条,此前 sim_scene.py 完全没有单测 —— 这正是
位姿解析死掉却无人发现的原因)与 test_check_sim_scene.py(21 条),
含三条回归:world_boxes 的偏移碰撞体不能被对称化放大(假重叠)、
center_bore 不能被 _bore 后缀吃掉、Fortress 位姿输出格式。
全量:src/arm_sim_gazebo + arm_interfaces + arm_application 共 515 通过。
同时附上 config/site.example.yaml 的重新生成(此前 site.yaml 的注释改动没同步,
它的 parity 测试是红的)。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 17:13:00 +08:00 |
|
arm_dev
|
e9da641160
|
README 与 handeye:把"什么该入库"的规则和仓库实际状态对齐
子代理同步文档时发现 README 的"要提交/不要提交"清单漏了 handeye/,顺着一查发现
规则写的是"不要提交含序列号的文件、克隆后必须重新标定",但仓库里
handeye/poses/ 与 handeye/results/ 一直是**被跟踪**的,而且
results/89_eye_in_hand.yaml 的文件头就写着 Rizon4-063989 —— 正是那个让
config/site.yaml 被排除的序列号,从另一个门漏了出来。规则与实际不符。
澄清后的规则(已写进 README):按"配置 vs 资产"区分,而不是按"是否含序列号"
配置属于站点 → 不入库(config/site.yaml、handeye/tmp/)
标定成果属于资产 → 入库(handeye/poses/、handeye/results/)
理由是手眼标定要上真机示教十几分钟,是费真机时间换来的;入库才有一份可回滚的
备份。若按"含序列号就排除"一刀切,代价是误删后必须重新上真机采点。
同时把结果文件头里的完整序列号去掉(只留臂号 89/91)—— 臂号本来就唯一标识了
是哪台机器,完整 SN 是多余的暴露面。
另:handeye/README.md 补充"tmp 是按臂号分目录"的后果说明,并点出直接启节点
(绕过 run_handeye.sh)会退回共用的 handeye/tmp —— 那种情况下两条臂的采点会
互相覆盖,而症状表现为"标定结果突然变差",很难联想到目录冲突。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 14:27:43 +08:00 |
|
arm_dev
|
d93dab31c9
|
P4d:文档同步 —— 修掉 P3 手眼路径迁移后遗留的过期引用,并指向新的 weights 工具
P3 把 handeye 相关文件从 src/arm_application/config/ 迁到了仓库根的 handeye/,
但文档还写着老路径。这类"代码改了、文档没跟"的偏差最麻烦:新人照着文档敲
命令会直接报文件不存在,然后开始怀疑人生。
同步内容
- docs/HANDEYE.md / WORKSPACE.md / SITE_CONFIG.md / ARCHITECTURE.md:
手眼结果与示教点位改指 handeye/results|poses/<臂号>_<模式>.yaml,
临时目录改指 handeye/tmp/<臂号>/,并补上 --mode / --points / --auto-solve。
- docs/INTERFACES.md / TRACKING.md / docs/HOLE_DETECT.md / README.md:
权重那一行从 export_yolo_trt.sh 改为 weights.sh,并注明前者已是兼容转发壳。
- docs/HOLE_DETECT.md:hole_weights / workpiece_weights 的实际取值改为
models/hole_insert/detect_best_1.onnx(原文档写的是不存在的 best.pt)。
- scripts/merge_handeye_poses.py:只更新文件头注释里的示例路径。
多处改为指向 models/README.md 与 handeye/README.md,避免同一套规则在
七八个文件里各写一遍、然后各自漂移。
验证:rg 扫 docs/ README.md,已无 handeye_poses_/handeye_result_/
/tmp/handeye 之类过期路径残留。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-09-23 13:52:28 +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 |
|