换台电脑克隆后启动失败,是因为 site 和启动脚本写死了 /home/cc/ros2。仓库内路径改成相对仓库根,加载时再展开;缺 install 时先说明要编译,而不是 source 一个不存在的文件。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+37
-29
@@ -10,8 +10,8 @@
|
|||||||
# 用法:复制本文件为 config/site.yaml,然后把所有 <占位符> 换成现场实际值。
|
# 用法:复制本文件为 config/site.yaml,然后把所有 <占位符> 换成现场实际值。
|
||||||
# 现场值包括:机械臂 SN / IP、相机序列号、夹爪串口、传感器 USB 路径。
|
# 现场值包括:机械臂 SN / IP、相机序列号、夹爪串口、传感器 USB 路径。
|
||||||
#
|
#
|
||||||
# 说明:site.yaml 里的路径出现 /home/USER 是因为生成时匿名化了用户名;
|
# 说明:仓库里的文件用相对仓库根的路径(例如 models/yolo/...)。
|
||||||
# 部署时请改成实际用户的 home 目录。
|
# 不要改回某个用户的绝对家目录,换台电脑就会找不到文件。
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -61,13 +61,15 @@ robot:
|
|||||||
# (status 里的 init=need_init 只说明"绝对位置标定没做",不影响夹持)
|
# (status 里的 init=need_init 只说明"绝对位置标定没做",不影响夹持)
|
||||||
# 想让开机必初始化(无人值守的上电流程)就显式改 true,并确认爪里是空的。
|
# 想让开机必初始化(无人值守的上电流程)就显式改 true,并确认爪里是空的。
|
||||||
auto_init: false
|
auto_init: false
|
||||||
named_poses_file: "/home/USER/ros2/src/arm_control/config/named_poses_89.yaml"
|
named_poses_file: "src/arm_control/config/named_poses_89.yaml"
|
||||||
paths:
|
paths:
|
||||||
handeye_file: "/home/USER/ros2/handeye/results/89_eye_in_hand.yaml"
|
handeye_file: "handeye/results/89_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/USER/ros2/handeye/poses/89_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/89_eye_in_hand.yaml"
|
||||||
handeye_workdir: "/home/USER/ros2/handeye/tmp/89"
|
handeye_workdir: "handeye/tmp/89"
|
||||||
handeye:
|
handeye:
|
||||||
# Studio tcp_location(法兰系,米 + qwxyz)。与 rdk Tool.params 必须一致。
|
# Studio tcp_location(法兰系,米 + qwxyz)。与 rdk Tool.params 必须一致。
|
||||||
|
# 眼在手上:AX=XB 的手是这份 TCP,再折成 cam→法兰写 T_4x4。
|
||||||
|
# 眼在手外:AX=XB 的手同样是这份 TCP(板夹在工具上);T_4x4 仍是 cam→基座,不折。
|
||||||
gripper_tool: "tool10120938"
|
gripper_tool: "tool10120938"
|
||||||
gripper_tcp_xyz: [-0.0005, 0.0067, 0.2245]
|
gripper_tcp_xyz: [-0.0005, 0.0067, 0.2245]
|
||||||
gripper_tcp_qwxyz: [1.0, 0.0, 0.0, 0.0]
|
gripper_tcp_qwxyz: [1.0, 0.0, 0.0, 0.0]
|
||||||
@@ -177,7 +179,8 @@ robot:
|
|||||||
# 落在本文件下方注释记录的合理区间 0.204~0.233 内。
|
# 落在本文件下方注释记录的合理区间 0.204~0.233 内。
|
||||||
# 复核:python3 scripts/sense_tool_length.py --sn Rizon4-XXXXXX
|
# 复核:python3 scripts/sense_tool_length.py --sn Rizon4-XXXXXX
|
||||||
# python3 scripts/lib/real_geometry_check.py --sn Rizon4-XXXXXX
|
# python3 scripts/lib/real_geometry_check.py --sn Rizon4-XXXXXX
|
||||||
# 下臂安全距离按 tool10120938 的 TCP +Z,不再用旧 tool1 的 0.223。
|
# 2026-10-12:下臂安全距离改按 Studio 工具 tool10120938 的 TCP +Z。
|
||||||
|
# 上面 0.223 是旧 tool1(夹爪 TCP 0.147 + 规露出 0.076),这把工具不再用。
|
||||||
tool_tip_below_flange_m: 0.2245
|
tool_tip_below_flange_m: 0.2245
|
||||||
# >>> 仿真那台臂(Gazebo)也登记成 robots[] 里的一台 <<<
|
# >>> 仿真那台臂(Gazebo)也登记成 robots[] 里的一台 <<<
|
||||||
# 为什么必须登记:应用是按"当前臂"的名字去查 frame / joint / 相机话题的
|
# 为什么必须登记:应用是按"当前臂"的名字去查 frame / joint / 相机话题的
|
||||||
@@ -208,7 +211,7 @@ robot:
|
|||||||
# 为什么必须给文件而不能留空:visual_servo 的 servo_node 需要
|
# 为什么必须给文件而不能留空:visual_servo 的 servo_node 需要
|
||||||
# T_flange_cam 矩阵做像素→笛卡尔换算;留空它就直接拒绝启动
|
# T_flange_cam 矩阵做像素→笛卡尔换算;留空它就直接拒绝启动
|
||||||
#("手眼标定结果缺失"),S04 跟踪起不来。
|
#("手眼标定结果缺失"),S04 跟踪起不来。
|
||||||
handeye_file: "/home/USER/ros2/handeye/results/sim_eye_in_hand.yaml"
|
handeye_file: "handeye/results/sim_eye_in_hand.yaml"
|
||||||
# 运动参数:**大部分**与 89 共用(锚点),但**高度类**必须按仿真台的几何改写。
|
# 运动参数:**大部分**与 89 共用(锚点),但**高度类**必须按仿真台的几何改写。
|
||||||
#
|
#
|
||||||
# 为什么不能直接共用:真机是"机械臂装在台面同一高度",所以"法兰相对基座"
|
# 为什么不能直接共用:真机是"机械臂装在台面同一高度",所以"法兰相对基座"
|
||||||
@@ -302,11 +305,11 @@ robot:
|
|||||||
port: "/dev/ttyUSB1"
|
port: "/dev/ttyUSB1"
|
||||||
stroke_mm: 30.0
|
stroke_mm: 30.0
|
||||||
auto_init: false
|
auto_init: false
|
||||||
named_poses_file: "/home/USER/ros2/src/arm_control/config/named_poses_91.yaml"
|
named_poses_file: "src/arm_control/config/named_poses_91.yaml"
|
||||||
paths:
|
paths:
|
||||||
handeye_file: "/home/USER/ros2/handeye/results/91_eye_in_hand.yaml"
|
handeye_file: "handeye/results/91_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/USER/ros2/handeye/poses/91_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/91_eye_in_hand.yaml"
|
||||||
handeye_workdir: "/home/USER/ros2/handeye/tmp/91"
|
handeye_workdir: "handeye/tmp/91"
|
||||||
# >>> 右臂跟踪高度:只改这里,89 仍用上面那段 <<<
|
# >>> 右臂跟踪高度:只改这里,89 仍用上面那段 <<<
|
||||||
# 法兰 Z;RGI 比平行爪高,通常要比 89 略抬一点。改完重启:
|
# 法兰 Z;RGI 比平行爪高,通常要比 89 略抬一点。改完重启:
|
||||||
# bash ~/ros2/scripts/run_visual_servo_rt.sh --arm 91 --control
|
# bash ~/ros2/scripts/run_visual_servo_rt.sh --arm 91 --control
|
||||||
@@ -327,7 +330,7 @@ robot:
|
|||||||
|
|
||||||
paths:
|
paths:
|
||||||
# >>> YOLO 权重(标准放法,不必改代码)<<<
|
# >>> YOLO 权重(标准放法,不必改代码)<<<
|
||||||
# 1) 把 .onnx / .pt 放到 /home/USER/ros2/models/yolo/
|
# 1) 把 .onnx / .pt 放到 models/yolo/
|
||||||
# 2) 这一行改成那个绝对路径(写 .onnx 即可;TensorRT 会找同名 .engine)
|
# 2) 这一行改成那个绝对路径(写 .onnx 即可;TensorRT 会找同名 .engine)
|
||||||
# 3) backend=tensorrt 时必须先导出引擎(只需做一次):
|
# 3) backend=tensorrt 时必须先导出引擎(只需做一次):
|
||||||
# bash ~/ros2/scripts/weights.sh convert <源文件> --name <名字> --group yolo
|
# bash ~/ros2/scripts/weights.sh convert <源文件> --name <名字> --group yolo
|
||||||
@@ -341,18 +344,18 @@ paths:
|
|||||||
# ultralytics 解不了 pose 的 TensorRT engine,运行时走
|
# ultralytics 解不了 pose 的 TensorRT engine,运行时走
|
||||||
# arm_application/pose_detector.py 的自解码(见该模块头)。
|
# arm_application/pose_detector.py 的自解码(见该模块头)。
|
||||||
# 仍然用 .engine(实测 ~2.6 ms/帧;onnx 只有 CPU provider,约 27 ms)。
|
# 仍然用 .engine(实测 ~2.6 ms/帧;onnx 只有 CPU provider,约 27 ms)。
|
||||||
yolo_weights: "/home/USER/ros2/models/yolo/gongjian0929.onnx"
|
yolo_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 换模型:把 models/yolo/ 下别的 .onnx / .pt 绝对路径填进来即可。
|
# 换模型:把 models/yolo/ 下别的 .onnx / .pt 绝对路径填进来即可。
|
||||||
# 未在用的模型已移出仓库(体积大且干扰 `weights.sh list`),要恢复见 models/README.md。
|
# 未在用的模型已移出仓库(体积大且干扰 `weights.sh list`),要恢复见 models/README.md。
|
||||||
# 入孔模型(backend=yolo 时把孔当框)。two_stage 用下面的工件权重。
|
# 入孔模型(backend=yolo 时把孔当框)。two_stage 用下面的工件权重。
|
||||||
# pose 模型两处共用同一份 —— 它既能框工件,又直接给 k1/k2 关键点。
|
# pose 模型两处共用同一份 —— 它既能框工件,又直接给 k1/k2 关键点。
|
||||||
# 查悬空引用:bash ~/ros2/scripts/weights.sh doctor
|
# 查悬空引用:bash ~/ros2/scripts/weights.sh doctor
|
||||||
hole_weights: "/home/USER/ros2/models/yolo/gongjian0929.onnx"
|
hole_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 下面是缺省(未匹配到 robots[] 时)。真机以 robots[].paths 为准:89 / 91 各一份。
|
# 下面是缺省(未匹配到 robots[] 时)。真机以 robots[].paths 为准:89 / 91 各一份。
|
||||||
handeye_file: "/home/USER/ros2/handeye/results/89_eye_in_hand.yaml"
|
handeye_file: "handeye/results/89_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/USER/ros2/handeye/poses/89_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/89_eye_in_hand.yaml"
|
||||||
handeye_calibrate: "/home/USER/ros2/handeye/calibrate.yaml"
|
handeye_calibrate: "handeye/calibrate.yaml"
|
||||||
handeye_workdir: "/home/USER/ros2/handeye/tmp/89"
|
handeye_workdir: "handeye/tmp/89"
|
||||||
# 空=默认 DDS(SHM);勿强制 UDP-only,否则相机预览收不到 /workpiece/detection
|
# 空=默认 DDS(SHM);勿强制 UDP-only,否则相机预览收不到 /workpiece/detection
|
||||||
fastdds_profile: ""
|
fastdds_profile: ""
|
||||||
|
|
||||||
@@ -593,6 +596,7 @@ servo:
|
|||||||
# 混合模式必填。交回 D405 的等待不再用它,见 d435_handback_sec。
|
# 混合模式必填。交回 D405 的等待不再用它,见 d435_handback_sec。
|
||||||
lock_still_sec: 3.0
|
lock_still_sec: 3.0
|
||||||
# 进程内 MoveL 到位后,法兰 XY 连续停稳这么久才交回 D405。
|
# 进程内 MoveL 到位后,法兰 XY 连续停稳这么久才交回 D405。
|
||||||
|
# 旧 3s 是杀栈冷启动的垫时间;不杀栈后只留机械停稳。晃了把数加大,不许再杀栈。
|
||||||
d435_handback_sec: 0.5
|
d435_handback_sec: 0.5
|
||||||
# 框心对准并且法兰停稳这么久,才精拍一次小孔关键点、进对孔。实时点到此为止。
|
# 框心对准并且法兰停稳这么久,才精拍一次小孔关键点、进对孔。实时点到此为止。
|
||||||
wrist_align_sec: 0.5
|
wrist_align_sec: 0.5
|
||||||
@@ -675,10 +679,10 @@ gripper:
|
|||||||
hole_detect:
|
hole_detect:
|
||||||
backend: "two_stage" # two_stage | yolo | hough
|
backend: "two_stage" # two_stage | yolo | hough
|
||||||
# backend=yolo 时用。
|
# backend=yolo 时用。
|
||||||
weights: "/home/USER/ros2/models/yolo/gongjian0929.onnx"
|
weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 二阶段工件检测权重。pose 模型既框工件、又直接给 k1/k2 关键点,
|
# 二阶段工件检测权重。pose 模型既框工件、又直接给 k1/k2 关键点,
|
||||||
# 所以和上面的跟踪权重是同一份。
|
# 所以和上面的跟踪权重是同一份。
|
||||||
workpiece_weights: "/home/USER/ros2/models/yolo/gongjian0929.onnx"
|
workpiece_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# pose 关键点优先:检测器给了 k1/k2 就直接用,不用再找圆。
|
# pose 关键点优先:检测器给了 k1/k2 就直接用,不用再找圆。
|
||||||
# 关键点不可信(低于 keypoint_min_conf / 两点几乎重合)时自动回落到
|
# 关键点不可信(低于 keypoint_min_conf / 两点几乎重合)时自动回落到
|
||||||
# 亮环 + Hough 那套老路径。
|
# 亮环 + Hough 那套老路径。
|
||||||
@@ -686,7 +690,7 @@ hole_detect:
|
|||||||
keypoint_min_conf: 0.30
|
keypoint_min_conf: 0.30
|
||||||
keypoint_min_dist_px: 15.0
|
keypoint_min_dist_px: 15.0
|
||||||
keypoint_hole_radius_px: 12.0 # 关键点没有半径;反投影时按这个半径取孔周深度环
|
keypoint_hole_radius_px: 12.0 # 关键点没有半径;反投影时按这个半径取孔周深度环
|
||||||
config: "/home/USER/ros2/src/arm_application/config/hole_detect.yaml"
|
config: "src/arm_application/config/hole_detect.yaml"
|
||||||
conf: 0.25
|
conf: 0.25
|
||||||
iou: 0.7
|
iou: 0.7
|
||||||
imgsz: 640
|
imgsz: 640
|
||||||
@@ -769,17 +773,21 @@ hole_detect:
|
|||||||
# —— 柔顺运动(夹爪持规,防急加速/急停/过冲把规震脱):速度放慢 + 平滑刹车 ——
|
# —— 柔顺运动(夹爪持规,防急加速/急停/过冲把规震脱):速度放慢 + 平滑刹车 ——
|
||||||
align_speed: 0.014 # 对准段笛卡尔速度 [m/s](原0.03,放缓防冲)
|
align_speed: 0.014 # 对准段笛卡尔速度 [m/s](原0.03,放缓防冲)
|
||||||
move_speed: 0.022 # 升降/粗居中段速度 [m/s](原0.05,放缓防震规)
|
move_speed: 0.022 # 升降/粗居中段速度 [m/s](原0.05,放缓防震规)
|
||||||
|
# 对小孔关键点:只用像素射线交到 workpiece_surface_z_m,不读深度图。
|
||||||
hole_visual_only: true
|
hole_visual_only: true
|
||||||
# 本分支实验:true=悬停拍一次并走完到孔;main 保存点应保持 false。
|
# 本分支实验(exp/hole-keypoint-once):true=悬停拍一次,框心→k1 一次走完
|
||||||
|
# (40mm 上限)。main 保存点是 false(多走多拍)。
|
||||||
hole_keypoint_once: true
|
hole_keypoint_once: true
|
||||||
# true=悬停走完后一条厂家 MoveL 贴面。对照观察高补交时改 false。
|
# true=悬停走完后一条厂家 MoveL 贴面(不补拍)。对照 37b85aa 改回 false。
|
||||||
hole_once_lock_xy_descend: true
|
hole_once_lock_xy_descend: true
|
||||||
# 0=笛卡尔锁 XY 只降 Z。k>0 才沿 -look 加前馈。
|
# 贴面相对悬停:沿 -look 走 k×剩余下降 [m/m]。0=笛卡尔锁 XY 只降 Z。
|
||||||
|
# 0.018 在框心改平面交点后两条链路都 +1.3mm X 过补,插不进。
|
||||||
once_ff_look_per_m: 0.0
|
once_ff_look_per_m: 0.0
|
||||||
final_gap_mm: 2.0 # 对准后贴面目标:规尖离面 [mm]。CLI --final-gap 覆盖。
|
final_gap_mm: 2.0 # 对准后贴面目标:规尖离面 [mm](不接触)。笛卡尔锁 XY
|
||||||
|
# 时法兰 Z = 工具长 + 工件面 + 本值。CLI --final-gap 覆盖。
|
||||||
observe_gap_mm: 15.0 # --no-descent 时的观测下降:只降到离面这么高 [mm],
|
observe_gap_mm: 15.0 # --no-descent 时的观测下降:只降到离面这么高 [mm],
|
||||||
# 方便看规尖偏没偏。必须 ≥ final_gap_mm。
|
# 方便看规尖偏没偏。必须 ≥ final_gap_mm。
|
||||||
# 左臂89:悬停间隙约 75mm(0.320−0.223−0.022)⇒ 大约下降 60mm。
|
# 左臂89:悬停间隙约 73.5mm(0.320−0.2245−0.022)⇒ 观测下降约 58mm。
|
||||||
final_descent_speed: 0.005 # 最后轻降速度 [m/s](很慢,柔顺)
|
final_descent_speed: 0.005 # 最后轻降速度 [m/s](很慢,柔顺)
|
||||||
# ✅ 2026-10-08 定稿:下降量**只由几何决定**(法兰 FK − 工具长 − 工件面 − final_gap),
|
# ✅ 2026-10-08 定稿:下降量**只由几何决定**(法兰 FK − 工具长 − 工件面 − final_gap),
|
||||||
# 深度读数只做交叉核对、不再参与任何决策。两段真机事故方向相反、都指向这条:
|
# 深度读数只做交叉核对、不再参与任何决策。两段真机事故方向相反、都指向这条:
|
||||||
@@ -792,7 +800,7 @@ hole_detect:
|
|||||||
# ⇒ 读数往**小**错一次就永远到不了目标。
|
# ⇒ 读数往**小**错一次就永远到不了目标。
|
||||||
# 同一套读数两个方向各错一次、幅度 150mm 量级、随位姿乱跳 —— 它对"能降多少"
|
# 同一套读数两个方向各错一次、幅度 150mm 量级、随位姿乱跳 —— 它对"能降多少"
|
||||||
# 和"该不该停"都没有发言权。现在它只在偏差 >10mm 时喊一句"深度测距与几何不符"。
|
# 和"该不该停"都没有发言权。现在它只在偏差 >10mm 时喊一句"深度测距与几何不符"。
|
||||||
# 现行几何:悬停 0.320 − 工具长 0.223 − 工件面 0.022 = 75mm 间隙 ⇒ 降 73mm 到 2mm。
|
# 现行几何:悬停 0.320 − 工具长 0.2245 − 工件面 0.022 = 73.5mm 间隙 ⇒ 降 71.5mm 到 2mm。
|
||||||
# 三道**物理/几何**保险:descent_budget_m(配置上限)+ 腕部 FT 接触检测(停+退 1mm)
|
# 三道**物理/几何**保险:descent_budget_m(配置上限)+ 腕部 FT 接触检测(停+退 1mm)
|
||||||
# + 任一步 _goto 走不到位就停。
|
# + 任一步 _goto 走不到位就停。
|
||||||
# 缺几何(工具长/工件面没配)时**拒绝下降**并报错(保持悬停),绝不拿测距去赌。
|
# 缺几何(工具长/工件面没配)时**拒绝下降**并报错(保持悬停),绝不拿测距去赌。
|
||||||
@@ -1093,7 +1101,7 @@ tactile:
|
|||||||
# 传感器型号。必须与 devices/sensors/orisys/models/ 下的子目录名一致。
|
# 传感器型号。必须与 devices/sensors/orisys/models/ 下的子目录名一致。
|
||||||
model: "dd03"
|
model: "dd03"
|
||||||
# 型号配置随 SDK 一起放:devices/sensors/orisys/models/<型号>/config.json
|
# 型号配置随 SDK 一起放:devices/sensors/orisys/models/<型号>/config.json
|
||||||
config_file: "/home/USER/ros2/devices/sensors/orisys/models/dd03/config.json"
|
config_file: "devices/sensors/orisys/models/dd03/config.json"
|
||||||
# 用 by-path 稳定路径(插哪个 USB 口就认哪个口,不受 video 编号漂移影响)。
|
# 用 by-path 稳定路径(插哪个 USB 口就认哪个口,不受 video 编号漂移影响)。
|
||||||
# 当前:3.4.1=左指 3.4.2=右指;若左右反了,互换两行即可。
|
# 当前:3.4.1=左指 3.4.2=右指;若左右反了,互换两行即可。
|
||||||
left_video: "/dev/v4l/by-path/pci-0000:00:14.0-usb-0:X.Y.Z:1.0-video-index0"
|
left_video: "/dev/v4l/by-path/pci-0000:00:14.0-usb-0:X.Y.Z:1.0-video-index0"
|
||||||
|
|||||||
+20
-20
@@ -45,11 +45,11 @@ robot:
|
|||||||
# (status 里的 init=need_init 只说明"绝对位置标定没做",不影响夹持)
|
# (status 里的 init=need_init 只说明"绝对位置标定没做",不影响夹持)
|
||||||
# 想让开机必初始化(无人值守的上电流程)就显式改 true,并确认爪里是空的。
|
# 想让开机必初始化(无人值守的上电流程)就显式改 true,并确认爪里是空的。
|
||||||
auto_init: false
|
auto_init: false
|
||||||
named_poses_file: "/home/cc/ros2/src/arm_control/config/named_poses_89.yaml"
|
named_poses_file: "src/arm_control/config/named_poses_89.yaml"
|
||||||
paths:
|
paths:
|
||||||
handeye_file: "/home/cc/ros2/handeye/results/89_eye_in_hand.yaml"
|
handeye_file: "handeye/results/89_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/cc/ros2/handeye/poses/89_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/89_eye_in_hand.yaml"
|
||||||
handeye_workdir: "/home/cc/ros2/handeye/tmp/89"
|
handeye_workdir: "handeye/tmp/89"
|
||||||
handeye:
|
handeye:
|
||||||
# Studio tcp_location(法兰系,米 + qwxyz)。与 rdk Tool.params 必须一致。
|
# Studio tcp_location(法兰系,米 + qwxyz)。与 rdk Tool.params 必须一致。
|
||||||
# 眼在手上:AX=XB 的手是这份 TCP,再折成 cam→法兰写 T_4x4。
|
# 眼在手上:AX=XB 的手是这份 TCP,再折成 cam→法兰写 T_4x4。
|
||||||
@@ -195,7 +195,7 @@ robot:
|
|||||||
# 为什么必须给文件而不能留空:visual_servo 的 servo_node 需要
|
# 为什么必须给文件而不能留空:visual_servo 的 servo_node 需要
|
||||||
# T_flange_cam 矩阵做像素→笛卡尔换算;留空它就直接拒绝启动
|
# T_flange_cam 矩阵做像素→笛卡尔换算;留空它就直接拒绝启动
|
||||||
#("手眼标定结果缺失"),S04 跟踪起不来。
|
#("手眼标定结果缺失"),S04 跟踪起不来。
|
||||||
handeye_file: "/home/cc/ros2/handeye/results/sim_eye_in_hand.yaml"
|
handeye_file: "handeye/results/sim_eye_in_hand.yaml"
|
||||||
# 运动参数:**大部分**与 89 共用(锚点),但**高度类**必须按仿真台的几何改写。
|
# 运动参数:**大部分**与 89 共用(锚点),但**高度类**必须按仿真台的几何改写。
|
||||||
#
|
#
|
||||||
# 为什么不能直接共用:真机是"机械臂装在台面同一高度",所以"法兰相对基座"
|
# 为什么不能直接共用:真机是"机械臂装在台面同一高度",所以"法兰相对基座"
|
||||||
@@ -289,11 +289,11 @@ robot:
|
|||||||
port: "/dev/ttyUSB1"
|
port: "/dev/ttyUSB1"
|
||||||
stroke_mm: 30.0
|
stroke_mm: 30.0
|
||||||
auto_init: false
|
auto_init: false
|
||||||
named_poses_file: "/home/cc/ros2/src/arm_control/config/named_poses_91.yaml"
|
named_poses_file: "src/arm_control/config/named_poses_91.yaml"
|
||||||
paths:
|
paths:
|
||||||
handeye_file: "/home/cc/ros2/handeye/results/91_eye_in_hand.yaml"
|
handeye_file: "handeye/results/91_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/cc/ros2/handeye/poses/91_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/91_eye_in_hand.yaml"
|
||||||
handeye_workdir: "/home/cc/ros2/handeye/tmp/91"
|
handeye_workdir: "handeye/tmp/91"
|
||||||
# >>> 右臂跟踪高度:只改这里,89 仍用上面那段 <<<
|
# >>> 右臂跟踪高度:只改这里,89 仍用上面那段 <<<
|
||||||
# 法兰 Z;RGI 比平行爪高,通常要比 89 略抬一点。改完重启:
|
# 法兰 Z;RGI 比平行爪高,通常要比 89 略抬一点。改完重启:
|
||||||
# bash ~/ros2/scripts/run_visual_servo_rt.sh --arm 91 --control
|
# bash ~/ros2/scripts/run_visual_servo_rt.sh --arm 91 --control
|
||||||
@@ -314,7 +314,7 @@ robot:
|
|||||||
|
|
||||||
paths:
|
paths:
|
||||||
# >>> YOLO 权重(标准放法,不必改代码)<<<
|
# >>> YOLO 权重(标准放法,不必改代码)<<<
|
||||||
# 1) 把 .onnx / .pt 放到 /home/cc/ros2/models/yolo/
|
# 1) 把 .onnx / .pt 放到 models/yolo/
|
||||||
# 2) 这一行改成那个绝对路径(写 .onnx 即可;TensorRT 会找同名 .engine)
|
# 2) 这一行改成那个绝对路径(写 .onnx 即可;TensorRT 会找同名 .engine)
|
||||||
# 3) backend=tensorrt 时必须先导出引擎(只需做一次):
|
# 3) backend=tensorrt 时必须先导出引擎(只需做一次):
|
||||||
# bash ~/ros2/scripts/weights.sh convert <源文件> --name <名字> --group yolo
|
# bash ~/ros2/scripts/weights.sh convert <源文件> --name <名字> --group yolo
|
||||||
@@ -328,18 +328,18 @@ paths:
|
|||||||
# ultralytics 解不了 pose 的 TensorRT engine,运行时走
|
# ultralytics 解不了 pose 的 TensorRT engine,运行时走
|
||||||
# arm_application/pose_detector.py 的自解码(见该模块头)。
|
# arm_application/pose_detector.py 的自解码(见该模块头)。
|
||||||
# 仍然用 .engine(实测 ~2.6 ms/帧;onnx 只有 CPU provider,约 27 ms)。
|
# 仍然用 .engine(实测 ~2.6 ms/帧;onnx 只有 CPU provider,约 27 ms)。
|
||||||
yolo_weights: "/home/cc/ros2/models/yolo/gongjian0929.onnx"
|
yolo_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 换模型:把 models/yolo/ 下别的 .onnx / .pt 绝对路径填进来即可。
|
# 换模型:把 models/yolo/ 下别的 .onnx / .pt 绝对路径填进来即可。
|
||||||
# 未在用的模型已移出仓库(体积大且干扰 `weights.sh list`),要恢复见 models/README.md。
|
# 未在用的模型已移出仓库(体积大且干扰 `weights.sh list`),要恢复见 models/README.md。
|
||||||
# 入孔模型(backend=yolo 时把孔当框)。two_stage 用下面的工件权重。
|
# 入孔模型(backend=yolo 时把孔当框)。two_stage 用下面的工件权重。
|
||||||
# pose 模型两处共用同一份 —— 它既能框工件,又直接给 k1/k2 关键点。
|
# pose 模型两处共用同一份 —— 它既能框工件,又直接给 k1/k2 关键点。
|
||||||
# 查悬空引用:bash ~/ros2/scripts/weights.sh doctor
|
# 查悬空引用:bash ~/ros2/scripts/weights.sh doctor
|
||||||
hole_weights: "/home/cc/ros2/models/yolo/gongjian0929.onnx"
|
hole_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 下面是缺省(未匹配到 robots[] 时)。真机以 robots[].paths 为准:89 / 91 各一份。
|
# 下面是缺省(未匹配到 robots[] 时)。真机以 robots[].paths 为准:89 / 91 各一份。
|
||||||
handeye_file: "/home/cc/ros2/handeye/results/89_eye_in_hand.yaml"
|
handeye_file: "handeye/results/89_eye_in_hand.yaml"
|
||||||
handeye_waypoints: "/home/cc/ros2/handeye/poses/89_eye_in_hand.yaml"
|
handeye_waypoints: "handeye/poses/89_eye_in_hand.yaml"
|
||||||
handeye_calibrate: "/home/cc/ros2/handeye/calibrate.yaml"
|
handeye_calibrate: "handeye/calibrate.yaml"
|
||||||
handeye_workdir: "/home/cc/ros2/handeye/tmp/89"
|
handeye_workdir: "handeye/tmp/89"
|
||||||
# 空=默认 DDS(SHM);勿强制 UDP-only,否则相机预览收不到 /workpiece/detection
|
# 空=默认 DDS(SHM);勿强制 UDP-only,否则相机预览收不到 /workpiece/detection
|
||||||
fastdds_profile: ""
|
fastdds_profile: ""
|
||||||
|
|
||||||
@@ -663,10 +663,10 @@ gripper:
|
|||||||
hole_detect:
|
hole_detect:
|
||||||
backend: "two_stage" # two_stage | yolo | hough
|
backend: "two_stage" # two_stage | yolo | hough
|
||||||
# backend=yolo 时用。
|
# backend=yolo 时用。
|
||||||
weights: "/home/cc/ros2/models/yolo/gongjian0929.onnx"
|
weights: "models/yolo/gongjian0929.onnx"
|
||||||
# 二阶段工件检测权重。pose 模型既框工件、又直接给 k1/k2 关键点,
|
# 二阶段工件检测权重。pose 模型既框工件、又直接给 k1/k2 关键点,
|
||||||
# 所以和上面的跟踪权重是同一份。
|
# 所以和上面的跟踪权重是同一份。
|
||||||
workpiece_weights: "/home/cc/ros2/models/yolo/gongjian0929.onnx"
|
workpiece_weights: "models/yolo/gongjian0929.onnx"
|
||||||
# pose 关键点优先:检测器给了 k1/k2 就直接用,不用再找圆。
|
# pose 关键点优先:检测器给了 k1/k2 就直接用,不用再找圆。
|
||||||
# 关键点不可信(低于 keypoint_min_conf / 两点几乎重合)时自动回落到
|
# 关键点不可信(低于 keypoint_min_conf / 两点几乎重合)时自动回落到
|
||||||
# 亮环 + Hough 那套老路径。
|
# 亮环 + Hough 那套老路径。
|
||||||
@@ -674,7 +674,7 @@ hole_detect:
|
|||||||
keypoint_min_conf: 0.30
|
keypoint_min_conf: 0.30
|
||||||
keypoint_min_dist_px: 15.0
|
keypoint_min_dist_px: 15.0
|
||||||
keypoint_hole_radius_px: 12.0 # 关键点没有半径;反投影时按这个半径取孔周深度环
|
keypoint_hole_radius_px: 12.0 # 关键点没有半径;反投影时按这个半径取孔周深度环
|
||||||
config: "/home/cc/ros2/src/arm_application/config/hole_detect.yaml"
|
config: "src/arm_application/config/hole_detect.yaml"
|
||||||
conf: 0.25
|
conf: 0.25
|
||||||
iou: 0.7
|
iou: 0.7
|
||||||
imgsz: 640
|
imgsz: 640
|
||||||
@@ -1085,7 +1085,7 @@ tactile:
|
|||||||
# 传感器型号。必须与 devices/sensors/orisys/models/ 下的子目录名一致。
|
# 传感器型号。必须与 devices/sensors/orisys/models/ 下的子目录名一致。
|
||||||
model: "dd03"
|
model: "dd03"
|
||||||
# 型号配置随 SDK 一起放:devices/sensors/orisys/models/<型号>/config.json
|
# 型号配置随 SDK 一起放:devices/sensors/orisys/models/<型号>/config.json
|
||||||
config_file: "/home/cc/ros2/devices/sensors/orisys/models/dd03/config.json"
|
config_file: "devices/sensors/orisys/models/dd03/config.json"
|
||||||
# 用 by-path 稳定路径(插哪个 USB 口就认哪个口,不受 video 编号漂移影响)。
|
# 用 by-path 稳定路径(插哪个 USB 口就认哪个口,不受 video 编号漂移影响)。
|
||||||
# 当前:3.4.1=左指 3.4.2=右指;若左右反了,互换两行即可。
|
# 当前:3.4.1=左指 3.4.2=右指;若左右反了,互换两行即可。
|
||||||
left_video: "/dev/v4l/by-path/pci-0000:00:14.0-usb-0:3.4.1:1.0-video-index0"
|
left_video: "/dev/v4l/by-path/pci-0000:00:14.0-usb-0:3.4.1:1.0-video-index0"
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ handeye_waypoints:
|
|||||||
camera_namespace: ""
|
camera_namespace: ""
|
||||||
image_topic: ""
|
image_topic: ""
|
||||||
preview_window: true
|
preview_window: true
|
||||||
append_poses_file: "/home/cc/ros2/handeye/tmp/taught_poses.txt"
|
append_poses_file: "handeye/tmp/taught_poses.txt"
|
||||||
|
|
||||||
waypoint_times: [4.0, 4.0, 4.0, 4.0, 4.0, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.0, 4.0]
|
waypoint_times: [4.0, 4.0, 4.0, 4.0, 4.0, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.0, 4.0]
|
||||||
|
|||||||
@@ -30,8 +30,12 @@ if [[ -f "${HOME}/anaconda3/etc/profile.d/conda.sh" ]]; then
|
|||||||
unset _env_helper
|
unset _env_helper
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -f "${ROOT}/install/setup.bash" ]]; then
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "${ROOT}/install/setup.bash"
|
source "${ROOT}/install/setup.bash"
|
||||||
|
else
|
||||||
|
echo "警告:${ROOT}/install 还没编译。工位窗口可以先开;真机栈要先在仓库根目录 colcon build(不要在中文路径下编)。" >&2
|
||||||
|
fi
|
||||||
export LD_LIBRARY_PATH="${HOME}/flexiv_install/lib:${LD_LIBRARY_PATH:-}"
|
export LD_LIBRARY_PATH="${HOME}/flexiv_install/lib:${LD_LIBRARY_PATH:-}"
|
||||||
# pip 版 TensorRT(tensorrt-cu12)—— 加载 YOLO `.engine` 需要它
|
# pip 版 TensorRT(tensorrt-cu12)—— 加载 YOLO `.engine` 需要它
|
||||||
_TRT_SITE="${CONDA_PREFIX:-${HOME}/anaconda3/envs/ros_flexiv}/lib/python3.11/site-packages"
|
_TRT_SITE="${CONDA_PREFIX:-${HOME}/anaconda3/envs/ros_flexiv}/lib/python3.11/site-packages"
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ HEADER = """\
|
|||||||
# 用法:复制本文件为 config/site.yaml,然后把所有 <占位符> 换成现场实际值。
|
# 用法:复制本文件为 config/site.yaml,然后把所有 <占位符> 换成现场实际值。
|
||||||
# 现场值包括:机械臂 SN / IP、相机序列号、夹爪串口、传感器 USB 路径。
|
# 现场值包括:机械臂 SN / IP、相机序列号、夹爪串口、传感器 USB 路径。
|
||||||
#
|
#
|
||||||
# 说明:site.yaml 里的路径出现 /home/USER 是因为生成时匿名化了用户名;
|
# 说明:仓库里的文件用相对仓库根的路径(例如 models/yolo/...)。
|
||||||
# 部署时请改成实际用户的 home 目录。
|
# 不要改回某个用户的绝对家目录,换台电脑就会找不到文件。
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -99,6 +99,6 @@ Next:
|
|||||||
--packages-up-to flexiv_bringup flexiv_hardware arm_bringup
|
--packages-up-to flexiv_bringup flexiv_hardware arm_bringup
|
||||||
|
|
||||||
Python (already ready, no GitHub):
|
Python (already ready, no GitHub):
|
||||||
/home/cc/rdk_py310/bin/python
|
\${HOME}/rdk_py310/bin/python
|
||||||
bash ${ROOT}/scripts/test_rdk_python.sh
|
bash ${ROOT}/scripts/test_rdk_python.sh
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# 本机工具链。仓库位置用调用方已经算好的 ROOT,不写死某个用户的家目录。
|
||||||
|
# 用法:source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
|
||||||
|
dev_source_conda() {
|
||||||
|
local cand
|
||||||
|
for cand in \
|
||||||
|
"${HOME}/anaconda3/etc/profile.d/conda.sh" \
|
||||||
|
"${HOME}/miniconda3/etc/profile.d/conda.sh"
|
||||||
|
do
|
||||||
|
if [[ -f "${cand}" ]]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "${cand}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "ERROR: 找不到 conda.sh。试过 \$HOME/anaconda3 和 \$HOME/miniconda3。" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_rdk_python() {
|
||||||
|
if [[ -n "${RDK_PYTHON:-}" && -x "${RDK_PYTHON}" ]]; then
|
||||||
|
printf '%s\n' "${RDK_PYTHON}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ -x "${HOME}/rdk_py310/bin/python" ]]; then
|
||||||
|
printf '%s\n' "${HOME}/rdk_py310/bin/python"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "ERROR: 找不到 RDK 的 Python。设置 RDK_PYTHON,或装到 \$HOME/rdk_py310。" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
@@ -42,7 +42,13 @@ def load_site(path: Path | None = None) -> dict:
|
|||||||
data = yaml.safe_load(text) or {}
|
data = yaml.safe_load(text) or {}
|
||||||
if not isinstance(data, dict):
|
if not isinstance(data, dict):
|
||||||
raise ValueError(f"无效的 site.yaml: {path}")
|
raise ValueError(f"无效的 site.yaml: {path}")
|
||||||
return data
|
# 相对路径按仓库根展开。site.yaml 里不再写 /home/某用户/ros2。
|
||||||
|
src = str(_root() / "src" / "arm_application")
|
||||||
|
if src not in sys.path:
|
||||||
|
sys.path.insert(0, src)
|
||||||
|
from arm_application.site_io import absolutize_site_paths
|
||||||
|
|
||||||
|
return absolutize_site_paths(data, _root())
|
||||||
|
|
||||||
|
|
||||||
def list_robots(data: dict) -> list[dict]:
|
def list_robots(data: dict) -> list[dict]:
|
||||||
|
|||||||
@@ -55,7 +55,15 @@ LEVEL_FAIL = "fail"
|
|||||||
#: 级别排序:fail 最先报
|
#: 级别排序:fail 最先报
|
||||||
_LEVEL_RANK = {LEVEL_FAIL: 0, LEVEL_WARN: 1, LEVEL_OK: 2}
|
_LEVEL_RANK = {LEVEL_FAIL: 0, LEVEL_WARN: 1, LEVEL_OK: 2}
|
||||||
|
|
||||||
DEFAULT_RDK_PYTHON = os.environ.get("RDK_PYTHON") or "/home/cc/rdk_py310/bin/python"
|
def default_rdk_python() -> str:
|
||||||
|
"""RDK 解释器。环境变量优先,否则用当前用户家目录下的 rdk_py310。"""
|
||||||
|
env = os.environ.get("RDK_PYTHON", "").strip()
|
||||||
|
if env:
|
||||||
|
return env
|
||||||
|
return str(Path.home() / "rdk_py310" / "bin" / "python")
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_RDK_PYTHON = default_rdk_python()
|
||||||
|
|
||||||
#: 上一轮没退干净的进程特征。留着它们会让这一轮的错误指向别处:
|
#: 上一轮没退干净的进程特征。留着它们会让这一轮的错误指向别处:
|
||||||
#: · ros2_control_node 占着 RDK(同一个 SN 是独占访问)
|
#: · ros2_control_node 占着 RDK(同一个 SN 是独占访问)
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ sys.path.insert(0, str(ROOT / "scripts" / "lib"))
|
|||||||
|
|
||||||
from rdk_release import is_control_stack_cmd # noqa: E402
|
from rdk_release import is_control_stack_cmd # noqa: E402
|
||||||
|
|
||||||
RDK_PYTHON = os.environ.get("RDK_PYTHON", "/home/cc/rdk_py310/bin/python")
|
RDK_PYTHON = os.environ.get("RDK_PYTHON", "").strip() or str(
|
||||||
|
Path.home() / "rdk_py310" / "bin" / "python"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _procs() -> list[tuple[int, str]]:
|
def _procs() -> list[tuple[int, str]]:
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "${ROOT}/scripts/lib/load_site_config.sh"
|
source "${ROOT}/scripts/lib/load_site_config.sh"
|
||||||
|
|
||||||
RDK_PYTHON="${RDK_PYTHON:-/home/cc/rdk_py310/bin/python}"
|
# shellcheck disable=SC1091
|
||||||
|
source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
RDK_PYTHON="$(dev_rdk_python)"
|
||||||
SN="${ROBOT_SN:-${SITE_ROBOT_SN:-}}"
|
SN="${ROBOT_SN:-${SITE_ROBOT_SN:-}}"
|
||||||
NAME="${SITE_ROBOT_TOOL_NAME:-}"
|
NAME="${SITE_ROBOT_TOOL_NAME:-}"
|
||||||
IFACE="${SITE_NET_IFACE:-}"
|
IFACE="${SITE_NET_IFACE:-}"
|
||||||
|
|||||||
+3
-1
@@ -139,7 +139,9 @@ if [[ "${D435_ONLY}" == true ]]; then
|
|||||||
fi
|
fi
|
||||||
echo "=== MoveL:XY 对准 K0,工具尖高度保持当前(K0 的 z 是工件表面)==="
|
echo "=== MoveL:XY 对准 K0,工具尖高度保持当前(K0 的 z 是工件表面)==="
|
||||||
# --go:不按直线距离拦截。800 mm 是脚本自己的保护,不是机械臂限位。
|
# --go:不按直线距离拦截。800 mm 是脚本自己的保护,不是机械臂限位。
|
||||||
exec /home/cc/rdk_py310/bin/python "${ROOT}/scripts/rdk_goto_xyz.py" \
|
# shellcheck disable=SC1091
|
||||||
|
source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
exec "$(dev_rdk_python)" "${ROOT}/scripts/rdk_goto_xyz.py" \
|
||||||
--xyz "${kx}" "${ky}" "${kz}" --keep-z --go --vel 0.05
|
--xyz "${kx}" "${ky}" "${kz}" --keep-z --go --vel 0.05
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
source /home/cc/anaconda3/etc/profile.d/conda.sh
|
# shellcheck disable=SC1091
|
||||||
|
source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
dev_source_conda
|
||||||
conda activate ros_flexiv
|
conda activate ros_flexiv
|
||||||
|
if [[ ! -f "${ROOT}/install/setup.bash" ]]; then
|
||||||
|
echo "ERROR: ${ROOT}/install/setup.bash 不存在。先在仓库根目录 colcon build。" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1091
|
||||||
source "${ROOT}/install/setup.bash"
|
source "${ROOT}/install/setup.bash"
|
||||||
ros2 run arm_application demo_named_poses --ros-args \
|
ros2 run arm_application demo_named_poses --ros-args \
|
||||||
-p "poses:=['home','ready','inspect','pos_left','home']" \
|
-p "poses:=['home','ready','inspect','pos_left','home']" \
|
||||||
|
|||||||
+8
-2
@@ -26,8 +26,14 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
source /home/cc/anaconda3/etc/profile.d/conda.sh
|
# shellcheck disable=SC1091
|
||||||
|
source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
dev_source_conda
|
||||||
conda activate ros_flexiv
|
conda activate ros_flexiv
|
||||||
|
if [[ ! -f "${ROOT}/install/setup.bash" ]]; then
|
||||||
|
echo "ERROR: ${ROOT}/install/setup.bash 不存在。先在仓库根目录 colcon build,不要在中文路径下编。" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "${ROOT}/install/setup.bash"
|
source "${ROOT}/install/setup.bash"
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
@@ -44,7 +50,7 @@ export LD_LIBRARY_PATH="${FLEXIV_PREFIX}/lib:${LD_LIBRARY_PATH:-}"
|
|||||||
ROBOT_SN="${SITE_ROBOT_SN:?run_real.sh 需要已配置的机械臂 SN —— 见 scripts/lib/load_site_config.sh 的报错}"
|
ROBOT_SN="${SITE_ROBOT_SN:?run_real.sh 需要已配置的机械臂 SN —— 见 scripts/lib/load_site_config.sh 的报错}"
|
||||||
ROBOT_IP="${ROBOT_IP:-${SITE_ROBOT_IP:-192.168.100.1}}"
|
ROBOT_IP="${ROBOT_IP:-${SITE_ROBOT_IP:-192.168.100.1}}"
|
||||||
NET_IFACE="${SITE_NET_IFACE:-}"
|
NET_IFACE="${SITE_NET_IFACE:-}"
|
||||||
RDK_PYTHON="${RDK_PYTHON:-/home/cc/rdk_py310/bin/python}"
|
RDK_PYTHON="$(dev_rdk_python)"
|
||||||
|
|
||||||
if [[ "${LIST_ONLY}" == true ]]; then
|
if [[ "${LIST_ONLY}" == true ]]; then
|
||||||
python3 "${ROOT}/scripts/lib/export_site_env.py" --print
|
python3 "${ROOT}/scripts/lib/export_site_env.py" --print
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ python3 "${ROOT}/scripts/lib/export_site_env.py" --print ${ROBOT_SN:+--sn "$ROBO
|
|||||||
echo
|
echo
|
||||||
echo "Edit: ${SITE_CONFIG:-$ROOT/config/site.yaml}"
|
echo "Edit: ${SITE_CONFIG:-$ROOT/config/site.yaml}"
|
||||||
echo "Switch weights:"
|
echo "Switch weights:"
|
||||||
echo " paths.yolo_weights: \"/home/cc/ros2/models/yolo/detect_best_0.onnx\" # 写 onnx 或 pt 均可"
|
echo " paths.yolo_weights: \"models/yolo/detect_best_0.onnx\" # 相对仓库根,写 onnx 或 pt 均可"
|
||||||
echo " 改完确认标签和 engine 都对:"
|
echo " 改完确认标签和 engine 都对:"
|
||||||
echo " bash ~/ros2/scripts/weights.sh list"
|
echo " bash ~/ros2/scripts/weights.sh list"
|
||||||
echo " bash ~/ros2/scripts/weights.sh doctor --check-engines"
|
echo " bash ~/ros2/scripts/weights.sh doctor --check-engines"
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ source "${ROOT}/scripts/lib/load_site_config.sh" 2>/dev/null || true
|
|||||||
SN="${1:-${ROBOT_SN:-${SITE_ROBOT_SN:-}}}"
|
SN="${1:-${ROBOT_SN:-${SITE_ROBOT_SN:-}}}"
|
||||||
ROBOT_IP="${ROBOT_IP:-${SITE_ROBOT_IP:-192.168.100.1}}"
|
ROBOT_IP="${ROBOT_IP:-${SITE_ROBOT_IP:-192.168.100.1}}"
|
||||||
IFACE="${SITE_NET_IFACE:-}"
|
IFACE="${SITE_NET_IFACE:-}"
|
||||||
PY="${RDK_PYTHON:-/home/cc/rdk_py310/bin/python}"
|
# shellcheck disable=SC1091
|
||||||
|
source "${ROOT}/scripts/lib/dev_tools.sh"
|
||||||
|
PY="$(dev_rdk_python)"
|
||||||
|
|
||||||
echo "Using: ${PY}"
|
echo "Using: ${PY}"
|
||||||
echo "Robot SN: ${SN} IP: ${ROBOT_IP} iface: ${IFACE:-auto}"
|
echo "Robot SN: ${SN} IP: ${ROBOT_IP} iface: ${IFACE:-auto}"
|
||||||
|
|||||||
@@ -137,7 +137,9 @@ class HandeyeCalibrate(TolerantNode):
|
|||||||
self.declare_parameter('pin_hold_sec', 0.45) # 每拍多长
|
self.declare_parameter('pin_hold_sec', 0.45) # 每拍多长
|
||||||
self.declare_parameter('skip_unstable_poses', True)
|
self.declare_parameter('skip_unstable_poses', True)
|
||||||
|
|
||||||
self.declare_parameter('output_dir', '/home/cc/ros2/handeye/tmp')
|
from arm_application.site_io import ros2_root
|
||||||
|
|
||||||
|
self.declare_parameter('output_dir', str(ros2_root() / 'handeye' / 'tmp'))
|
||||||
self.declare_parameter('result_file', '')
|
self.declare_parameter('result_file', '')
|
||||||
self.declare_parameter('cleanup_images', True)
|
self.declare_parameter('cleanup_images', True)
|
||||||
# 眼在手上:AX=XB 的 gripper 用 Studio 工具 TCP,再折成 cam→法兰写 T_4x4。
|
# 眼在手上:AX=XB 的 gripper 用 Studio 工具 TCP,再折成 cam→法兰写 T_4x4。
|
||||||
|
|||||||
@@ -108,10 +108,12 @@ class RdkBridge:
|
|||||||
self.robot_sn = robot_sn
|
self.robot_sn = robot_sn
|
||||||
self._last_q: Optional[List[float]] = None
|
self._last_q: Optional[List[float]] = None
|
||||||
self._io = threading.Lock()
|
self._io = threading.Lock()
|
||||||
py = os.environ.get('RDK_PYTHON', '/home/cc/rdk_py310/bin/python')
|
from arm_application.site_io import ros2_root
|
||||||
bridge = Path.home() / 'ros2' / 'scripts' / 'rdk_drag_bridge.py'
|
|
||||||
if not bridge.is_file():
|
py = os.environ.get('RDK_PYTHON', '').strip() or str(
|
||||||
bridge = Path('/home/cc/ros2/scripts/rdk_drag_bridge.py')
|
Path.home() / 'rdk_py310' / 'bin' / 'python'
|
||||||
|
)
|
||||||
|
bridge = ros2_root() / 'scripts' / 'rdk_drag_bridge.py'
|
||||||
if not bridge.is_file():
|
if not bridge.is_file():
|
||||||
raise FileNotFoundError(f'找不到 rdk_drag_bridge.py:{bridge}')
|
raise FileNotFoundError(f'找不到 rdk_drag_bridge.py:{bridge}')
|
||||||
|
|
||||||
@@ -246,7 +248,9 @@ class RdkBridge:
|
|||||||
class HandeyeTeach(TolerantNode):
|
class HandeyeTeach(TolerantNode):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__('handeye_teach')
|
super().__init__('handeye_teach')
|
||||||
self.declare_parameter('output_dir', '/home/cc/ros2/handeye/tmp')
|
from arm_application.site_io import ros2_root
|
||||||
|
|
||||||
|
self.declare_parameter('output_dir', str(ros2_root() / 'handeye' / 'tmp'))
|
||||||
self.declare_parameter('width', 1280)
|
self.declare_parameter('width', 1280)
|
||||||
self.declare_parameter('height', 720)
|
self.declare_parameter('height', 720)
|
||||||
self.declare_parameter('fps', 15)
|
self.declare_parameter('fps', 15)
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class PerceptionNode(TolerantNode):
|
|||||||
self.declare_parameter("image_topic", "")
|
self.declare_parameter("image_topic", "")
|
||||||
self.declare_parameter("camera_info_topic", "")
|
self.declare_parameter("camera_info_topic", "")
|
||||||
self.declare_parameter("depth_topic", "/d405/aligned_depth_to_color/image_raw")
|
self.declare_parameter("depth_topic", "/d405/aligned_depth_to_color/image_raw")
|
||||||
self.declare_parameter("weights", "/home/cc/ros2/models/yolo/gongjian0929.onnx")
|
self.declare_parameter("weights", "models/yolo/gongjian0929.onnx")
|
||||||
self.declare_parameter("conf", 0.10)
|
self.declare_parameter("conf", 0.10)
|
||||||
self.declare_parameter("iou", 0.45)
|
self.declare_parameter("iou", 0.45)
|
||||||
self.declare_parameter("imgsz", 640)
|
self.declare_parameter("imgsz", 640)
|
||||||
@@ -336,7 +336,9 @@ class PerceptionNode(TolerantNode):
|
|||||||
r_pos=float(self.get_parameter("kf_r_pos").value),
|
r_pos=float(self.get_parameter("kf_r_pos").value),
|
||||||
)
|
)
|
||||||
|
|
||||||
weights_raw = str(self.get_parameter("weights").value)
|
from arm_application.site_io import resolve_repo_path
|
||||||
|
|
||||||
|
weights_raw = resolve_repo_path(str(self.get_parameter("weights").value))
|
||||||
weights = str(resolve_weights(weights_raw, self.backend_name))
|
weights = str(resolve_weights(weights_raw, self.backend_name))
|
||||||
yolo_cfg = {
|
yolo_cfg = {
|
||||||
"weights": weights,
|
"weights": weights,
|
||||||
|
|||||||
@@ -73,15 +73,9 @@ def _fill_camera_info(
|
|||||||
|
|
||||||
|
|
||||||
def _site_yaml_path() -> Path:
|
def _site_yaml_path() -> Path:
|
||||||
env = str(os.environ.get("SITE_CONFIG") or "").strip()
|
from arm_application.site_io import site_path
|
||||||
if env:
|
|
||||||
p = Path(env).expanduser()
|
return site_path()
|
||||||
if p.is_file():
|
|
||||||
return p
|
|
||||||
home = Path.home() / "ros2" / "config" / "site.yaml"
|
|
||||||
if home.is_file():
|
|
||||||
return home
|
|
||||||
return Path("/home/cc/ros2/config/site.yaml")
|
|
||||||
|
|
||||||
|
|
||||||
class RealsenseColorPub(TolerantNode):
|
class RealsenseColorPub(TolerantNode):
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class ServoNode(TolerantNode):
|
|||||||
self.declare_parameter("point_topic", "visual_servo/filtered_point")
|
self.declare_parameter("point_topic", "visual_servo/filtered_point")
|
||||||
# 默认值只作兜底:真机运行一定由 launch 传入 site.yaml 的 paths.handeye_file。
|
# 默认值只作兜底:真机运行一定由 launch 传入 site.yaml 的 paths.handeye_file。
|
||||||
# 指向 /tmp 是历史遗留(标定临时产物),会让人误以为"标定结果在那里"。
|
# 指向 /tmp 是历史遗留(标定临时产物),会让人误以为"标定结果在那里"。
|
||||||
self.declare_parameter("handeye_file", "/home/cc/ros2/handeye/results/89_eye_in_hand.yaml")
|
self.declare_parameter("handeye_file", "handeye/results/89_eye_in_hand.yaml")
|
||||||
# eye_in_hand = cam→法兰;eye_to_hand = cam→基座。写错会把固定相机当腕部用。
|
# eye_in_hand = cam→法兰;eye_to_hand = cam→基座。写错会把固定相机当腕部用。
|
||||||
self.declare_parameter("handeye_mode", "eye_in_hand")
|
self.declare_parameter("handeye_mode", "eye_in_hand")
|
||||||
self.declare_parameter("use_static_handeye_tf", False)
|
self.declare_parameter("use_static_handeye_tf", False)
|
||||||
@@ -374,9 +374,10 @@ class ServoNode(TolerantNode):
|
|||||||
self.ws_min = np.array([float(v) for v in ws_min[:3]], dtype=float)
|
self.ws_min = np.array([float(v) for v in ws_min[:3]], dtype=float)
|
||||||
self.ws_max = np.array([float(v) for v in ws_max[:3]], dtype=float)
|
self.ws_max = np.array([float(v) for v in ws_max[:3]], dtype=float)
|
||||||
|
|
||||||
self.T_cam_to_gripper = load_handeye_T(
|
from arm_application.site_io import resolve_repo_path
|
||||||
str(self.get_parameter("handeye_file").value)
|
|
||||||
)
|
handeye_path = resolve_repo_path(str(self.get_parameter("handeye_file").value))
|
||||||
|
self.T_cam_to_gripper = load_handeye_T(handeye_path)
|
||||||
self.handeye_mode = str(
|
self.handeye_mode = str(
|
||||||
self.get_parameter("handeye_mode").value or "eye_in_hand"
|
self.get_parameter("handeye_mode").value or "eye_in_hand"
|
||||||
).strip().lower()
|
).strip().lower()
|
||||||
@@ -399,7 +400,7 @@ class ServoNode(TolerantNode):
|
|||||||
t_he = np.asarray(self.T_cam_to_gripper[:3, 3], dtype=float)
|
t_he = np.asarray(self.T_cam_to_gripper[:3, 3], dtype=float)
|
||||||
axis_z = float(np.clip(R_he[2, 2], -1.0, 1.0))
|
axis_z = float(np.clip(R_he[2, 2], -1.0, 1.0))
|
||||||
self._cam_tilt_deg = float(np.degrees(np.arccos(axis_z)))
|
self._cam_tilt_deg = float(np.degrees(np.arccos(axis_z)))
|
||||||
he_path = str(self.get_parameter("handeye_file").value)
|
he_path = handeye_path
|
||||||
if self.handeye_mode == "eye_to_hand":
|
if self.handeye_mode == "eye_to_hand":
|
||||||
self.get_logger().warn(
|
self.get_logger().warn(
|
||||||
f"HANDEYE yaml={he_path} mode=eye_to_hand "
|
f"HANDEYE yaml={he_path} mode=eye_to_hand "
|
||||||
|
|||||||
@@ -10,13 +10,83 @@ import yaml
|
|||||||
|
|
||||||
|
|
||||||
def ros2_root() -> Path:
|
def ros2_root() -> Path:
|
||||||
|
"""仓库根目录。先看环境变量,再从本文件向上找 ``config/site.yaml``。
|
||||||
|
|
||||||
|
不能默认 ``~/ros2``:别人把仓库克隆到别的目录时,写死的家目录路径是空的,
|
||||||
|
启动会报文件不存在。
|
||||||
|
"""
|
||||||
for key in ("SITE_ROS2_ROOT", "ROS2_WS"):
|
for key in ("SITE_ROS2_ROOT", "ROS2_WS"):
|
||||||
v = os.environ.get(key, "").strip()
|
v = os.environ.get(key, "").strip()
|
||||||
if v:
|
if v:
|
||||||
return Path(v).expanduser()
|
return Path(v).expanduser()
|
||||||
|
here = Path(__file__).resolve()
|
||||||
|
for parent in here.parents:
|
||||||
|
if (parent / "config" / "site.yaml").is_file() and (parent / "scripts" / "env.sh").is_file():
|
||||||
|
return parent
|
||||||
return Path.home() / "ros2"
|
return Path.home() / "ros2"
|
||||||
|
|
||||||
|
|
||||||
|
_PATH_KEYS = frozenset({
|
||||||
|
"named_poses_file",
|
||||||
|
"handeye_file",
|
||||||
|
"handeye_waypoints",
|
||||||
|
"handeye_workdir",
|
||||||
|
"handeye_calibrate",
|
||||||
|
"yolo_weights",
|
||||||
|
"hole_weights",
|
||||||
|
"weights",
|
||||||
|
"workpiece_weights",
|
||||||
|
"config_file",
|
||||||
|
"append_poses_file",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_repo_path(value: str, root: Path | None = None) -> str:
|
||||||
|
"""仓库内的相对路径展开成绝对路径。已经是绝对路径的原样保留。"""
|
||||||
|
text = str(value or "").strip()
|
||||||
|
if not text:
|
||||||
|
return ""
|
||||||
|
path = Path(text).expanduser()
|
||||||
|
if path.is_absolute():
|
||||||
|
return str(path)
|
||||||
|
base = root or ros2_root()
|
||||||
|
return str((base / path).resolve())
|
||||||
|
|
||||||
|
|
||||||
|
def _is_path_key(key: str) -> bool:
|
||||||
|
return (
|
||||||
|
key in _PATH_KEYS
|
||||||
|
or key.startswith("handeye_file")
|
||||||
|
or key.startswith("handeye_waypoints")
|
||||||
|
or key.endswith("_weights")
|
||||||
|
or key.endswith("_file")
|
||||||
|
or key.endswith("_workdir")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def absolutize_site_paths(data: Any, root: Path | None = None) -> Any:
|
||||||
|
"""把 site 里的仓库相对路径展开。只动路径字段,不动别的字符串。"""
|
||||||
|
base = root or ros2_root()
|
||||||
|
if isinstance(data, dict):
|
||||||
|
out: dict[Any, Any] = {}
|
||||||
|
for key, val in data.items():
|
||||||
|
name = str(key)
|
||||||
|
if isinstance(val, str) and _is_path_key(name):
|
||||||
|
out[key] = resolve_repo_path(val, base)
|
||||||
|
elif (
|
||||||
|
name == "config"
|
||||||
|
and isinstance(val, str)
|
||||||
|
and (val.endswith((".yaml", ".yml", ".json")) or "/" in val)
|
||||||
|
):
|
||||||
|
out[key] = resolve_repo_path(val, base)
|
||||||
|
else:
|
||||||
|
out[key] = absolutize_site_paths(val, base)
|
||||||
|
return out
|
||||||
|
if isinstance(data, list):
|
||||||
|
return [absolutize_site_paths(item, base) for item in data]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def site_path() -> Path:
|
def site_path() -> Path:
|
||||||
env = os.environ.get("SITE_CONFIG", "").strip()
|
env = os.environ.get("SITE_CONFIG", "").strip()
|
||||||
if env:
|
if env:
|
||||||
@@ -29,7 +99,11 @@ def load_site_dict(path: str | Path | None = None) -> dict[str, Any]:
|
|||||||
if not p.is_file():
|
if not p.is_file():
|
||||||
return {}
|
return {}
|
||||||
data = yaml.safe_load(p.read_text(encoding="utf-8")) or {}
|
data = yaml.safe_load(p.read_text(encoding="utf-8")) or {}
|
||||||
return data if isinstance(data, dict) else {}
|
if not isinstance(data, dict):
|
||||||
|
return {}
|
||||||
|
resolved = p.resolve()
|
||||||
|
root = resolved.parent.parent if resolved.parent.name == "config" else ros2_root()
|
||||||
|
return absolutize_site_paths(data, root)
|
||||||
|
|
||||||
|
|
||||||
def deep_merge(base: dict[str, Any], overlay: dict[str, Any]) -> dict[str, Any]:
|
def deep_merge(base: dict[str, Any], overlay: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ perception_node:
|
|||||||
image_topic: ""
|
image_topic: ""
|
||||||
camera_info_topic: ""
|
camera_info_topic: ""
|
||||||
depth_topic: "/d405/aligned_depth_to_color/image_raw"
|
depth_topic: "/d405/aligned_depth_to_color/image_raw"
|
||||||
weights: "/home/cc/ros2/models/yolo/gongjian0929.onnx"
|
weights: "models/yolo/gongjian0929.onnx"
|
||||||
conf: 0.10
|
conf: 0.10
|
||||||
iou: 0.45
|
iou: 0.45
|
||||||
imgsz: 640
|
imgsz: 640
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ servo_node:
|
|||||||
camera_frame: "d405_color_optical_frame"
|
camera_frame: "d405_color_optical_frame"
|
||||||
traj_topic: "rizon_arm_controller/joint_trajectory"
|
traj_topic: "rizon_arm_controller/joint_trajectory"
|
||||||
point_topic: "visual_servo/filtered_point"
|
point_topic: "visual_servo/filtered_point"
|
||||||
handeye_file: "/home/cc/ros2/src/arm_application/config/handeye_result.yaml"
|
handeye_file: "src/arm_application/config/handeye_result.yaml"
|
||||||
use_static_handeye_tf: false
|
use_static_handeye_tf: false
|
||||||
handeye_child_frame: "d405_color_optical_frame"
|
handeye_child_frame: "d405_color_optical_frame"
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,16 @@ import time
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
def default_rdk_python() -> str:
|
||||||
|
"""RDK 解释器在当前用户家目录,不写死某一台机器的用户名。"""
|
||||||
|
env = os.environ.get("RDK_PYTHON", "").strip()
|
||||||
|
if env:
|
||||||
|
return env
|
||||||
|
return str(Path.home() / "rdk_py310" / "bin" / "python")
|
||||||
|
|
||||||
|
|
||||||
#: 桥进程必须用这个解释器 —— RDK 绑定只在这里有。
|
#: 桥进程必须用这个解释器 —— RDK 绑定只在这里有。
|
||||||
DEFAULT_RDK_PYTHON = "/home/cc/rdk_py310/bin/python"
|
DEFAULT_RDK_PYTHON = default_rdk_python()
|
||||||
|
|
||||||
#: 桥脚本位置(相对工作区根)。
|
#: 桥脚本位置(相对工作区根)。
|
||||||
BRIDGE_SCRIPT_REL = "scripts/rdk_drag_bridge.py"
|
BRIDGE_SCRIPT_REL = "scripts/rdk_drag_bridge.py"
|
||||||
|
|||||||
Reference in New Issue
Block a user