仿真感知:真值孔位 + 真值相机 + 补 /home,让流程不改代码就能跑仿真

三块补齐,目标是"同一个流程节点,仿真/真机都不改代码":

1. 真值孔位(truth_holes.py):把 scene.yaml 与模型 SDF 里已知的孔几何
   直接投影到相机像素坐标,替代 HoughCircles。perception.source 选:
     yolo / truth / external —— truth 就走这条路。
   为什么不用 Hough:仿真里孔是"方孔 + 贴片亮环"的近似(SDF 没有布尔运算),
   靠图像门槛去凑 radus 区间很脆;而孔位本来就是场景里已知量,直接投影
   既准又稳,还能当真实检测算法的对照基线。

2. 真值相机(sim_truth_perception.py):同理,直接算物体位姿,供
   visual_servo/filtered_point 用,绕开 ONNX。

3. 补 /home 与 set_named_pose 服务(sim_home_service.py):真机上这两个
   由 Flexiv 驱动提供,仿真里没有 —— 缺了 S01 直接超时。

4. sim_tactile_adapter 容错导入 ros_gz_interfaces:那一路只是"接触点",
   力本身走 geometry_msgs/Wrench。typesupport 加载不了时退化成
   contact 恒 False + centroid 恒 0,三力判据(S07 用的)不受影响 ——
   宁可用退化模式跑,也不要整个适配器起不来。

5. repo_root 解析(已装包要能找回源码仓库根,见 test_repo_root.py 的用例)
   与 use_sim_time 向子 launch 的传递。

另:scripts/gen_sim_handeye.py 把 URDF 真值导出手眼文件(仿真不标定)。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-24 14:43:13 +08:00
parent ddf30e57f8
commit b29339e522
24 changed files with 2232 additions and 74 deletions
+36 -2
View File
@@ -125,8 +125,23 @@ def effective_gates(root: Optional[Path] = None) -> dict:
}
def sim_robot_servo(doc: dict) -> dict:
"""仿真那台臂的 servo 段(顶层 servo 被 robots[] 里 sim 那台覆盖后的结果)。
⚠️ 必须合并,不能只读顶层:顶层那套是**真机**的(台面与基座同高,所以
工作盒 z 是 0.18~0.65),而仿真里机械臂站在地面、台面 0.40 高,一切 Z 都
大 0.412。只读顶层会拿真机的界去核对仿真的悬停高 —— 看起来"过了",
而真正生效的配置可能根本不对(或者反过来,明明配对了却报越界)。
"""
servo = dict(doc.get("servo") or {})
for robot in (doc.get("robot") or {}).get("robots") or []:
if str(robot.get("arm") or "") == "sim" or str(robot.get("sn") or "") == "sim":
servo.update(robot.get("servo") or {})
return servo
def workspace_z_limits(root: Optional[Path] = None):
"""从 site.yaml 读机械臂法兰的工作空间 Z 上下界(用于核对悬停高度)。"""
"""机械臂法兰的工作空间 Z 上下界(按**仿真那台臂**的生效值)。"""
import yaml
base_root = Path(root) if root is not None else REPO_ROOT
@@ -136,7 +151,7 @@ def workspace_z_limits(root: Optional[Path] = None):
if not site.is_file():
return None
doc = yaml.safe_load(site.read_text(encoding="utf-8")) or {}
servo = doc.get("servo") or {}
servo = sim_robot_servo(doc)
try:
return float(servo["workspace_xyz_min"][2]), float(servo["workspace_xyz_max"][2])
except (KeyError, IndexError, TypeError, ValueError):
@@ -217,6 +232,25 @@ def check_hover_height(scene, root) -> list[str]:
)
elif fz < lo:
out.append(f"算出的悬停法兰高度 z≈{fz:.3f}m 低于工作空间下界 {lo}m。")
# 一阶段跟踪高还要再抬 TRACK_CLEARANCE_M(见 pipeline_node 的常量)。
# 单独查这一条的原因:二阶段能过、S04 一跟踪就被"超出工作盒"截断,
# 现象是"跟踪位置总差一截/越跟踪越偏",而配置看着完全合理。
try:
from arm_application.pipeline_node import TRACK_CLEARANCE_M
except Exception: # noqa: BLE001 —— 拿不到常量就不查,不因此拦人
return out
track = fz + float(TRACK_CLEARANCE_M)
if track > hi:
out.append(
f"一阶段跟踪高 = 悬停 {fz:.3f} + {TRACK_CLEARANCE_M:.2f} = {track:.3f}m "
f"**超出工作空间上界 {hi}m**。\n"
f" 二阶段的位姿检查能过、S04 一跟踪却会被「超出工作盒」截断 —— "
f"现象是「越跟踪越偏」,很难往配置上想。\n"
f" 修法(仿真里都自由):把 site.yaml 里仿真那台臂的 "
f"servo.workspace_xyz_max.z 抬到 ≥ {track:.3f},"
f"或调小 scene.yaml 的 camera_to_part_m(法兰随之降低)。"
)
return out