diff --git a/handeye/README.md b/handeye/README.md index 2788062..14791e5 100644 --- a/handeye/README.md +++ b/handeye/README.md @@ -160,6 +160,27 @@ bash ~/ros2/scripts/run_handeye.sh show --arm 89 两者共用同一份 `poses/*.yaml`,顺序是 `teach`(采)→ `merge`(存)→ `calibrate`(算)。 +### 一条命令跑完(手动模式 + 自动求解) + +```bash +# 需要先在另一个终端跑 run_real.sh +bash ~/ros2/scripts/run_handeye.sh teach --ros --auto-solve --arm 89 +``` + +采完点按 `q` 之后,脚本会自动 `merge`、重启相机、接着 `calibrate`, +不用再敲第二条命令。 + +> ⚠️ **`--auto-solve` 只在 `--ros`(示教器)模式能全程跑通。** +> +> 原因是一个硬件约束:标定必须通过 `run_real.sh` 的控制器驱动机械臂走点位, +> 而 `--rdk` 软拖拽要求 **RDK 独占**,两者无法同时存在。 +> 所以 `--rdk --auto-solve` 会照常自动 merge,然后明确告诉你剩下那两条命令 —— +> **这是物理限制,不是脚本能绕过的**。 +> +> 想要真正一条命令,就用示教器 Free Drive:先在示教器上打开 Free Drive, +> 再用 `--ros --auto-solve`。 + + ### 切换 eye-in-hand / eye-to-hand ```bash diff --git a/scripts/run_handeye.sh b/scripts/run_handeye.sh index cb08546..b7ebe7d 100755 --- a/scripts/run_handeye.sh +++ b/scripts/run_handeye.sh @@ -12,12 +12,19 @@ # bash ~/ros2/scripts/run_handeye.sh calibrate # bash ~/ros2/scripts/run_handeye.sh waypoints # bash ~/ros2/scripts/run_handeye.sh teach # RDK 软拖拽(推荐) +# bash ~/ros2/scripts/run_handeye.sh teach --ros --auto-solve +# # 示教器模式 + 采完自动 merge 并直接标定(一条命令跑完) # bash ~/ros2/scripts/run_handeye.sh teach --points 12 # 目标采 12 个点 # bash ~/ros2/scripts/run_handeye.sh teach --append # 接着上次点位继续采 # bash ~/ros2/scripts/run_handeye.sh teach --ros # 示教器 Free Drive # bash ~/ros2/scripts/run_handeye.sh merge [taught.txt] # bash ~/ros2/scripts/run_handeye.sh show # 看当前配置与点数 # +# 关于 --auto-solve(采完自动标定)的重要限制: +# 只有 --ros(示教器)模式能真正一条命令跑完。因为标定必须在 run_real.sh 的 +# 控制器上走点位,而 --rdk 软拖拽要 RDK 独占,两者互斥 —— 这是硬件约束。 +# --rdk --auto-solve 会照常自动 merge,然后明确告诉你接下来那两条命令。 +# # 全局选项(放在子命令前或后都可以): # --arm 89|91|left|right 选臂(默认 89) # --mode eye_in_hand|eye_to_hand @@ -46,7 +53,7 @@ CMD="${1:-}" shift || true usage() { - sed -n '2,36p' "$0" + sed -n '2,40p' "$0" } # shellcheck disable=SC1091 @@ -237,12 +244,14 @@ cmd_teach() { local backend="rdk" local append=false local points=0 + local auto_solve=false while [[ $# -gt 0 ]]; do case "$1" in --rdk) backend="rdk"; shift ;; --ros|--pendant) backend="ros"; shift ;; --append|--keep) append=true; shift ;; --points) points="${2:?--points 需要一个数字}"; shift 2 ;; + --auto-solve) auto_solve=true; shift ;; *) echo "Unknown teach arg: $1" >&2; exit 1 ;; esac done @@ -280,6 +289,9 @@ cmd_teach() { fi echo " 结束后: bash ~/ros2/scripts/run_handeye.sh merge" echo " bash ~/ros2/scripts/run_handeye.sh calibrate" + if [[ "${auto_solve}" == true ]]; then + echo " --auto-solve: 采完会自动 merge,并视后端决定是否直接标定" + fi TEACH_ARGS=( -p backend:="${backend}" -p robot_sn:="${SITE_ROBOT_SN:-Rizon4-063989}" @@ -301,7 +313,60 @@ cmd_teach() { -p exposure_us:="${SITE_CAM_EXPOSURE_US:-0}" -p gain:="${SITE_CAM_GAIN:-0}" ) - exec ros2 run arm_application handeye_teach --ros-args "${TEACH_ARGS[@]}" + ros2 run arm_application handeye_teach --ros-args "${TEACH_ARGS[@]}" || true + + # ---- 采点结束 ---- + if [[ "${auto_solve}" != true ]]; then + echo + echo "采点结束。接着跑(或下次加 --auto-solve 让它自动接):" + echo " bash ~/ros2/scripts/run_handeye.sh merge --arm ${SITE_ROBOT_ARM:-89}" + echo " bash ~/ros2/scripts/run_handeye.sh calibrate --arm ${SITE_ROBOT_ARM:-89}" + return 0 + fi + + echo + echo "=== --auto-solve: 自动 merge ===" + if [[ ! -s "${TAUGHT}" ]]; then + echo "ERROR: 没采到任何点(${TAUGHT} 为空),中止。" >&2 + return 1 + fi + if ! python3 "${ROOT}/scripts/merge_handeye_poses.py" "${TAUGHT}" "${WP}"; then + echo "ERROR: merge 失败,点还在 ${TAUGHT},可手动重跑 merge。" >&2 + return 1 + fi + echo " 已写入 ${WP}" + + # RDK 软拖拽与控制器互斥:软拖拽要 RDK 独占,标定必须在 run_real.sh 的 + # 控制器上走点位,两者无法同时存在。这是硬件约束,脚本绕不过去, + # 所以这里如实停下并给出下一步,而不是硬跑一个必然失败的 calibrate。 + if [[ "${backend}" == "rdk" ]]; then + echo + echo "⚠️ 当前是 RDK 拖拽模式(--rdk),无法自动接着求解。" + echo " 原因:软拖拽需要 RDK 独占,而标定需要通过 run_real.sh 的控制器走点位," + echo " 两者不能同时存在。" + echo + echo " 继续两步即可:" + echo " 1) 另开终端: bash ~/ros2/scripts/run_real.sh --arm ${SITE_ROBOT_ARM:-89}" + echo " 2) 回到这里: bash ~/ros2/scripts/run_handeye.sh calibrate --arm ${SITE_ROBOT_ARM:-89}" + echo + echo " 想真正一条命令跑完,请改用示教器 Free Drive 模式:" + echo " bash ~/ros2/scripts/run_handeye.sh teach --ros --auto-solve" + return 0 + fi + + # --ros(示教器)后端:控制器本来就在跑,可以无缝接上标定。 + # 但 teach 阶段把相机杀掉了(USB 独占),标定拍照要用,得先拉回来。 + echo + echo "=== 重启相机(teach 阶段杀掉了它,标定拍照需要)===" + nohup bash "${ROOT}/scripts/run_camera_d405.sh" --arm "${SITE_ROBOT_ARM:-89}" \ + --no-preview > /tmp/run_handeye_camera.log 2>&1 & + echo " pid=$! log=/tmp/run_handeye_camera.log" + # _need_camera 内部失败时会自己打印原因并 exit,不需要在这里再判一次。 + _need_camera + + echo + echo "=== --auto-solve: 自动 calibrate ===" + cmd_calibrate } case "${CMD}" in