仿真感知:真值孔位 + 真值相机 + 补 /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:
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user