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>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
---
|
||||
description: 配置与设备模块的改动规则(site.yaml 分层、devices 布局、权重归位)
|
||||
globs: config/**,devices/**,models/**,src/arm_interfaces/**
|
||||
---
|
||||
|
||||
# 配置与设备改动规则
|
||||
|
||||
权威全文:`docs/FRAMEWORK_RULES.md` 第 1 节(R1.1–R1.5)。
|
||||
|
||||
## 配置分层
|
||||
|
||||
- 优先级固定:**命令行 > `config/site.yaml` > 包内默认值**。
|
||||
- `config/site.yaml` 是站点数据(SN / IP / 序列号 / 锁高 / 权重路径),**不进 git**;
|
||||
改过它之后必须重跑 `python3 scripts/gen_site_example.py`,否则模板漂移
|
||||
(有一条 parity 测试会红)。
|
||||
- **禁止硬编码站点值到代码里**。历史反例:15 处硬编码的 `Rizon4-063989`,
|
||||
换一台臂就会静默连错机器。
|
||||
- 新增 `site.yaml` 键时二选一:**真的接线**,或在启动时**告警**。
|
||||
声明了却没接线、也不告警,是最难查的一类问题(用户改了配置毫无反应)。
|
||||
注意 `wired:` 只是 manifest 里的注释性约定,`arm_interfaces.manifest` 不解析它 ——
|
||||
保障要靠代码里的告警函数(如 `sim_site.unwired_warnings()`),别指望清单。
|
||||
|
||||
## 设备模块布局
|
||||
|
||||
```
|
||||
devices/<kind>/<brand>/
|
||||
├── manifest.yaml # id/label/kind/vendor/version + assets + driver + capabilities + models + config_schema
|
||||
├── driver/ # 与厂商 SDK 对接的实现(可替换)
|
||||
└── models/<型号>/ # 该品牌的型号专属文件
|
||||
```
|
||||
|
||||
- `kind` 用固定那几个(`robots`/`grippers`/`cameras`/`sensors`/`sim`),目录名要与
|
||||
`arm_interfaces.KIND_FOLDERS` 一致。
|
||||
- **换品牌 = 新增目录**,不是改现有目录;上层按 `manifest.yaml` 选型,不认品牌名。
|
||||
- `assets[]` 里标 `required: true` 的物料缺失时,报错信息要给出**格式与命名要求**,
|
||||
不能只说"文件不存在"。
|
||||
|
||||
## 权重
|
||||
|
||||
- 二进制(`.pt/.onnx/.engine`)**不进 git**,`.labels.yaml`(文本标签)**要进**。
|
||||
- 转换链:`models/staging/` → `weights.sh convert` → 自动改名归位 + 固化标签。
|
||||
- 配置里指向不存在的模型(悬空引用)必须修掉:`bash scripts/weights.sh doctor`。
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
description: 本仓库的框架硬规矩(三条元规则 + 改动前检查清单),改任何代码前先读
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 框架硬规矩(权威全文:`docs/FRAMEWORK_RULES.md`,规则编号 R1.1…R8)
|
||||
|
||||
这不是风格建议。违反它们的改动会在真机上以**不报错但结果是错的**方式失败,
|
||||
而防这件事是这个仓库花最多代价在做的事。要绕开某条规则,先改文档并写清理由。
|
||||
|
||||
## 三条元规则
|
||||
|
||||
1. **静默失效是头号敌人。** 任何检查/校验都必须**能真的失败** ——
|
||||
写完先问"我故意弄坏它,这个检查会红吗?"。不会红 = 等于没检查。
|
||||
宁可当场报错,也不要"宽容降级":降级会把"没检查"伪装成"检查通过"。
|
||||
校验代码自己也会静默失效(外部工具会用 `__default__` 这类**假值**填缺失字段)。
|
||||
2. **单一数据源。** 同一事实只写一处,其余派生;能算的不要抄。
|
||||
必须抄的(如仿真侧的像素门槛)要有人守着 —— 脚本交叉核对真机配置,不一致判失败。
|
||||
3. **口径必须显式。** 单位/坐标系/符号/参考基准写下来,换算只做一次、放在适配层。
|
||||
|
||||
## 改动前必答
|
||||
|
||||
- 这个事实仓库里有几处在写?其余的是派生的吗?
|
||||
- 我加的配置键真的接线了吗?没接线会在启动时告警吗?
|
||||
- 涉及的检查有**负向测试**吗(故意弄坏能红)?
|
||||
- 解析外部输出前,我看过它的**真实**输出吗?(文本格式与直觉不一致是常态)
|
||||
- 我改的是上游第三方文件吗?→ 不许直接改,走归一化/适配层。
|
||||
- 文档里的"已就绪 / 未接线"标注与实现还一致吗?不一致立刻改文档(以实现为准)。
|
||||
|
||||
## 严禁
|
||||
|
||||
- 硬编码站点数据(SN / IP / 相机序列号 / 锁高 / 权重路径)—— 一律走 `config/site.yaml`。
|
||||
- 用"有图像 / 有话题 / TF 查得到"作为验收 —— 必须断言物理量。
|
||||
- 把"降级跳过"写成"通过"。
|
||||
- 在中文路径下 `colcon build`。
|
||||
- 提交信息只写"改了什么"而不写"为什么"(中文,附实测验收数据)。
|
||||
|
||||
## 出问题先查症状表
|
||||
|
||||
`docs/FRAMEWORK_RULES.md` 第 8 节按**症状**列出全部历史反例
|
||||
("三维点偏半米"、"深度差 1000 倍"、"夹爪 active 但不动"、"脚本说已停止进程还在"…),
|
||||
先按症状查表,再动手。
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: Gazebo 仿真的改动规则(静默失效高发区:路径/内参/接触力/描述归一化)
|
||||
globs: devices/sim/**,src/arm_sim_gazebo/**
|
||||
---
|
||||
|
||||
# 仿真改动规则
|
||||
|
||||
权威全文:`docs/FRAMEWORK_RULES.md` 第 4 节;平台手册:`devices/sim/gazebo/README.md`。
|
||||
R4.1–R4.10 全部适用,以下是**最容易踩的几条**:
|
||||
|
||||
- **world 里声明任何一个 `<plugin>` 都会挤掉默认系统**(Physics / UserCommands /
|
||||
SceneBroadcaster)。少了 UserCommands,模型根本没进 Gazebo,而 `create` **仍然打印**
|
||||
`OK creation of entity`。要加插件时必须把这几个系统一起显式声明。
|
||||
- **插件/资源搜索路径必须在 `ros2 launch` 之前设好**(conda 激活不会加
|
||||
`$CONDA_PREFIX/lib`)。不要绕过 `scripts/sim_env.sh` 直接 launch。
|
||||
- **不许改上游描述文件**(`flexiv_description` 等):`<mimic>` 会被 `sdformat` 丢弃、
|
||||
零质量 link 会出 NaN 惯性、无质量根 link 会连子树被丢。一律走启动时归一化。
|
||||
- **gz 发的 `camera_info` 是错的**(恒为 60° 视场的默认值),内参必须按
|
||||
`cameras.yaml` 的 `horizontal_fov` 与图幅重算并覆盖。
|
||||
- **深度单位**:gz 是 `32FC1` 米,真机是 `16UC1` 毫米。换算只做一次(适配器)。
|
||||
- **相机 `frame_id` 必须是光学系**;`rpy` 的复合顺序是 `Rz·Ry·Rx`。
|
||||
- **触觉**:轴向映射必须实测(不许从 URDF 推导);接触布尔必须用超时判据
|
||||
(接触消息是事件式的,没有"离开"事件);`force_scale` 决定仿真与真机能否共用阈值。
|
||||
- **验收不用"有图像 / TF 查得到"**:跑 `scripts/check_sim_cameras.py` 与
|
||||
`scripts/check_sim_scene.py`(判据是物理量:反投影命中平面、像素门槛、位姿一致)。
|
||||
- **停仿真用 `scripts/stop_sim_gz.sh`**,不要 `pkill -f`(会先杀掉调用它的 shell)。
|
||||
给栈里加了新进程时,记得加进该脚本的模式表 —— 它末尾会复查残留,漏项会报出来。
|
||||
- **模型约定**:原点在**底面中心**、单位米、目录名 = `<model name>` =
|
||||
`model.config` 的 `<name>` = 推理类别名;碰撞体用简单几何,`visual` 可以加
|
||||
只服务于检测的细节(如工件上的亮环),但 `visual` **名字有意义**,改名字要同步改
|
||||
`sim_scene.features_from_workpiece`。
|
||||
Reference in New Issue
Block a user