6baf989595
实测(2026-09-28)在仿真里上料失败,一路查到 IK / TF / 时钟上,全是被冤枉的。 根因是两个真机侧一直缺的东西: 1) **真机侧没有停止脚本**。仿真侧早有 stop_sim_gz.sh(R4.10/R4.11:残留会伪造出 "代码写错了"的现场),真机侧只有 run_real.sh 里两行 pkill。而真机栈里有一族 **独立于 ros2_control_node 存活**的进程 —— 上一轮栈的主体早没了,只剩 real_trajectory_adapter / named_pose_server / arm_status_node / joint_state_publisher 四条,两条 pkill 一条都匹配不到。 危害不是占资源而是**冒名顶替**:残留的 adapter 照样订阅 /trajectory、 残留的 joint_state_publisher 照样发 /joint_states(mock 的静态关节角)。 现象极具误导性:控制器 feedback 与 reference 完全一致(控制器没坏), TF 却显示末端一动不动。 新增 stop_real.sh + lib/real_procs.sh:扫描 = 点名表 + `install/` 前缀兜底, 按 ROS_DOMAIN_ID 判别真机/仿真(两边有同名的 robot_state_publisher, 否则停真机会把正在跑的仿真杀一半),杀完复查残留并非零退出。 run_real.sh 启动前的清理改用它,不再各写一份会漂移的模式表。 真机侧**有意不**用仿真的"进程组"法:真机栈是前台交互跑的,没有独立进程组, 它的 PGID 就是调用它的 shell —— 记下来再 kill 会杀掉自己的终端。 2) **真机侧不强制 ROS_DOMAIN_ID**。sim_env.sh 早就强制 77 并写明"隔离不能靠 『环境里恰好没设』",真机侧没有对应保护:先 source 过 sim_env.sh 的 shell 里 再起真机栈,真机栈就落到**仿真的域**上,节点名撞车、/joint_states 与 /tf 各有两个来源互相盖。补 lib/ros_domain.sh(真机 0 / 覆盖用 REAL_ROS_DOMAIN_ID), env.sh、run_real.sh、run_sim.sh 三处共用一份实现 —— 成对强制,否则一侧的 强制只是把运气挪到了另一侧。 run_sim.sh 特别容易漏:它名为 sim,用的却是**真机的 install/**、节点名与真机 完全一样,而且当时不管域;这次也钉到真机域 0。run_sim_gz.sh 文件头那句 "两者互不影响"是错的,一并改掉。 验证:stop_real.sh --list 在有仿真在跑时为空(REAL_PROC_INCLUDE_SIM=1 能看到 并按"域 77"标出);伪装一个 install/arm_control/lib/arm_control/arm_status_node 的孤儿进程能被点名。新增 6 项单测钉住域的四种输入 + 一个不许误报。 Co-authored-by: Cursor <cursoragent@cursor.com>
119 lines
5.1 KiB
Bash
Executable File
119 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 真机 Rizon4 启动入口 —— 设置 RDK 运行时库,然后以 backend:=real 启动整栈
|
||
# 注意:这里不加 `set -u` —— conda/RoboStack 的钩子会引用未绑定的变量(CONDA_BUILD、COLCON_TRACE)
|
||
#
|
||
# bash ~/ros2/scripts/run_real.sh
|
||
# bash ~/ros2/scripts/run_real.sh --arm 91
|
||
# bash ~/ros2/scripts/run_real.sh --sn Rizon4-063991 # 本次启动换臂(不改 yaml)
|
||
set -eo pipefail
|
||
|
||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
FLEXIV_PREFIX="${HOME}/flexiv_install"
|
||
LIST_ONLY=false
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--sn|--arm) export ROBOT_SN="${2:?}"; export ROBOT_ARM="${2}"; shift 2 ;;
|
||
--list|-l) LIST_ONLY=true; shift ;;
|
||
-h|--help)
|
||
sed -n '2,8p' "$0"
|
||
echo " Extra args are passed to ros2 launch (e.g. use_rviz:=false)."
|
||
exit 0
|
||
;;
|
||
*) break ;;
|
||
esac
|
||
done
|
||
|
||
source /home/cc/anaconda3/etc/profile.d/conda.sh
|
||
conda activate ros_flexiv
|
||
# shellcheck disable=SC1091
|
||
source "${ROOT}/install/setup.bash"
|
||
# shellcheck disable=SC1091
|
||
source "${ROOT}/scripts/lib/load_site_config.sh"
|
||
# 真机与仿真的 DDS 域隔离:这个入口**不经过** env.sh,所以这里也得纠正一次。
|
||
# shellcheck source=lib/ros_domain.sh
|
||
source "${ROOT}/scripts/lib/ros_domain.sh"
|
||
ros_domain_force_real
|
||
|
||
# `flexiv_hardware` 必须从 flexiv_install 加载 spdlog/RBDyn(不能用 conda 的 fmt v11)
|
||
export LD_LIBRARY_PATH="${FLEXIV_PREFIX}/lib:${LD_LIBRARY_PATH:-}"
|
||
|
||
# `SITE_ROBOT_SN` 是解析后的 Flexiv 序列号(89/91 别名已经映射好了)。
|
||
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}}"
|
||
NET_IFACE="${SITE_NET_IFACE:-}"
|
||
RDK_PYTHON="${RDK_PYTHON:-/home/cc/rdk_py310/bin/python}"
|
||
|
||
if [[ "${LIST_ONLY}" == true ]]; then
|
||
python3 "${ROOT}/scripts/lib/export_site_env.py" --print
|
||
exit 0
|
||
fi
|
||
|
||
echo "=== site: ${SITE_CONFIG:-n/a} SN=${ROBOT_SN} ${SITE_ROBOT_LABEL:-} arm=${SITE_ROBOT_ARM:-} ==="
|
||
echo "=== catalog: ${SITE_ROBOT_CATALOG:-} ==="
|
||
echo "=== handeye: ${SITE_HANDEYE_FILE:-} ==="
|
||
echo "=== camera serial: ${SITE_CAM_SERIAL:-} gripper: ${SITE_GRIP_MODEL:-} ${SITE_GRIP_PORT:-} ==="
|
||
echo "=== network iface=${NET_IFACE:-auto} robot=${ROBOT_IP} pc=${SITE_PC_IP:-} ==="
|
||
echo "=== stop leftover real stack (RDK exclusive) ==="
|
||
# 以前这里是两行 pkill(ros2_control_node + stack.launch),漏掉了
|
||
# arm_control 那一族**独立存活**的孤儿(adapter / named_pose_server /
|
||
# arm_status_node / joint_state_publisher)—— 它们会冒名顶替新一轮的栈,
|
||
# 见 lib/real_procs.sh 的文件头。扫描规则与 stop_real.sh 共用一份。
|
||
# shellcheck source=lib/real_procs.sh
|
||
source "${ROOT}/scripts/lib/real_procs.sh"
|
||
mapfile -t _stale < <(real_proc_targets)
|
||
if [ "${#_stale[@]}" != "0" ]; then
|
||
echo "清掉上一轮残留(${#_stale[@]} 个):"
|
||
for _pid in "${_stale[@]}"; do
|
||
printf ' %-7s %s\n' "$_pid" "$(ps -o args= -p "$_pid" 2>/dev/null | cut -c1-120)"
|
||
kill -TERM "$_pid" 2>/dev/null || true
|
||
done
|
||
sleep 1
|
||
for _pid in "${_stale[@]}"; do
|
||
kill -0 "$_pid" 2>/dev/null && kill -KILL "$_pid" 2>/dev/null || true
|
||
done
|
||
unset _pid
|
||
fi
|
||
unset _stale
|
||
sleep 1
|
||
# 清掉把 91 的 .100 误绑到 89 MAC 上的陈旧 ARP
|
||
if [[ -n "${NET_IFACE}" ]]; then
|
||
ip neigh del "${ROBOT_IP}" dev "${NET_IFACE}" 2>/dev/null || true
|
||
fi
|
||
if ping -c 2 -W 1 "${ROBOT_IP}" >/dev/null 2>&1; then
|
||
echo "robot ${ROBOT_IP} ping OK"
|
||
else
|
||
echo "WARN: cannot ping ${ROBOT_IP} — 这一台不在网里,RDK 大概率会失败。"
|
||
echo " 本机: $(ip -4 -o addr show dev "${NET_IFACE:-enp4s0}" 2>/dev/null | awk '{print $4}' | tr '\n' ' ')"
|
||
echo " ARP ${ROBOT_IP}: $(ip neigh show "${ROBOT_IP}" 2>/dev/null | head -1 || echo none)"
|
||
MAC91="$(ip neigh show "${ROBOT_IP}" 2>/dev/null | awk '{print $5}' | head -1)"
|
||
MAC89="$(ip neigh show 192.168.2.101 2>/dev/null | awk '{print $5}' | head -1)"
|
||
if [[ -n "${MAC91}" && -n "${MAC89}" && "${MAC91}" == "${MAC89}" ]]; then
|
||
echo " ARP MAC 与 89(192.168.2.101) 相同 → .100 是误绑,91 并没有回包。"
|
||
fi
|
||
echo " 91 请接控制柜 User Port 1(出厂静态 192.168.2.100)到同一交换机,示教器 AUTO+Remote Ethernet。"
|
||
echo " 89=192.168.2.101 91=192.168.2.100"
|
||
fi
|
||
|
||
echo "=== RDK preflight + tool (${ROBOT_SN}) ==="
|
||
TOOL_NAME="${SITE_ROBOT_TOOL_NAME:-}"
|
||
RDK_TOOL_ARGS=(--sn "${ROBOT_SN}")
|
||
if [[ -n "${NET_IFACE}" ]]; then
|
||
RDK_TOOL_ARGS+=(--iface "${NET_IFACE}")
|
||
fi
|
||
if [[ -n "${TOOL_NAME}" ]]; then
|
||
RDK_TOOL_ARGS+=(--name "${TOOL_NAME}")
|
||
echo "=== Studio tool → ${TOOL_NAME} ==="
|
||
fi
|
||
if ! "${RDK_PYTHON}" "${ROOT}/scripts/rdk_switch_tool.py" "${RDK_TOOL_ARGS[@]}"; then
|
||
echo ""
|
||
echo "ERROR: RDK cannot connect / switch tool on ${ROBOT_SN}."
|
||
echo " 先确认 ping ${ROBOT_IP} 通(91=控制柜 User Port 1 → 192.168.2.100)。"
|
||
echo " Stop any other RDK client (this run_real.sh is exclusive)."
|
||
echo " On teach pendant: Settings → Remote → enable Ethernet/RDK remote mode."
|
||
echo " Test: bash ${ROOT}/scripts/test_rdk_python.sh ${ROBOT_SN}"
|
||
exit 1
|
||
fi
|
||
|
||
exec ros2 launch arm_bringup stack.launch.py backend:=real robot_sn:="${ROBOT_SN}" "$@"
|