Files
ros_contorl/scripts/fetch_flexiv.sh
T
arm_dev f5ed44a987 配置:消灭代码里的硬编码臂 SN,并给"换臂漏改"加一把尺子
## 为什么

"设备 ID 全部可配置"这条要求在代码里只做了一半:site.yaml 能配,
但**代码和静态配置里到处躺着 Rizon4-063989 当兜底**。这类兜底的危害
不是"改起来麻烦",而是它把"配置没生效"伪装成"配置生效了":

  * `robot_sn` 默认 `Rizon4-063989` → 换臂后节点去订**上一台臂**的关节话题,
    节点起来了、不报错、什么都不动;
  * launch 里用 `ee_frame == "Rizon4-063989_flange"` 当"用户没指定"的哨兵 →
    换个站点这个判断永远不成立,于是 site.yaml 里的 ee_frame 再也不会被用上,
    静态 TF 挂错坐标系、点还照样查得到;
  * `if SN == "Rizon4-063989"` 决定要不要拉触觉服务 → 换臂后触觉静默消失。

## 改了什么

1. **删掉所有"兜底成某台臂"的默认值**(15 处脚本 + 6 个 launch + 6 个节点)。
   没配就为空 / 直接 `:?` 报错,宁可起不来也不要连错机器:
   - `scripts/lib/export_site_env.py`:别名解析改为从 `robots[]` 现算
     (`arm_short_id` / `resolve_robot_sn` / `describe_arms`),选不出臂时
     抛 `ValueError`;`main()` 捕获后打人话 + 退出码 2(供 shell `eval`);
   - 手眼文件/路点/工作目录由当前臂 short id 派生,不再写死 `89_*`;
   - `ROBOT_HAS_TACTILE` 改为读 site.yaml 的 `robots[].tactile`;
   - `arm_application/site_io.py` 新增 `joint_prefix_default()` /
     `base_frame_default()` / `ee_frame_default()`:优先读 `SITE_*`,
     退而由 `SITE_ROBOT_SN` 现算,**不写死 SN**;
   - `arm.urdf.xacro` 的 `robot_sn` 默认值改成明显的占位符 `UNSET_ARM_SN`
     (关节名会带出来,报错信息自解释);
   - `ros2_control.launch.py` / `move_group.launch.py` **原先根本不传
     robot_sn**,靠 xacro 写死默认值"蒙对"本机,现在都从环境取。

2. **新增 `scripts/check_arm_prefixes.py`**:Flexiv 把 SN 编进关节名,
   所以有一批一级配置(SRDF/controllers/joint_names/bringup/servo/...)
   必须跟着当前臂走。漏改的症状是"MoveIt 规划成功但机械臂不动",很难查。
   这个脚本逐文件逐行列出对不上的地方,并直接给出修法。
   `--list` 还会说明 SN 来自 site.yaml 还是被 `ROBOT_SN` 覆盖。

3. **文档**:`FRAMEWORK_RULES.md` 新增 R1.1.1(两类含臂名文件怎么分、
   换臂四步)+ 检查清单第 12 条 + 反例 2 条;`HANDBOOK.md` 新增 3.6.1
   与症状表 2 行。

4. **顺带修掉的真 bug**(都是这次改动带出来、被 pyflakes + 真跑抓住的):
   - `convert_flexiv_traj.py` / `rdk_drag_bridge.py` 用了 `os` 但没 import
     → `--help` 直接 NameError;
   - `check_arm_prefixes.py` 第一版正则用 `\b` 收尾,而关节名是
     `Rizon4-063989_joint1`(`_` 属于 \w,`\b` 不成立)→ SRDF 里 24 处
     硬编码**一处都没报**,还打印 OK。已加负向测试钉住;
   - 删掉若干死代码/死 import(`pos_line`/`flat`/`names`、`IfCondition` 等)。

## 验收(都真跑过)

- `python3 -m pyflakes <全部改过的 py>` → 干净
- 逐包 pytest:233 + 69 + 78 + 24 + 236 = **640 passed**
- `env -u ROBOT_SN python3 scripts/check_arm_prefixes.py` → OK(8 文件)
- 换成 SN=Rizon4-777001 的临时 site.yaml → 报出**8 个**文件不一致并给修法(退出码 1)
- 故意不给 SITE_* → 各 launch 的 `robot_sn` / `ee_frame` / `handeye_file`
  默认值为 `''`,不再悄悄指向上一台臂
- `ros2 launch ... --show-args` 对 stack/sim/ros2_control/mock_control/
  move_group/display/visual_servo **全部通过**
- `convert_flexiv_traj.py --help` 正常;拿 `xunhuan.traj` 真转 5 个路点,
  输出 `joint_prefix: "Rizon4-063989_"` 来自 site.yaml

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 09:18:44 +08:00

117 lines
4.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 克隆 Flexiv 官方 ROS 2 栈(Rizon 用,RDK v1.x → humble-v1 分支)。
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SRC="${ROOT}/src"
BRANCH="${FLEXIV_ROS2_BRANCH:-humble-v1}"
mkdir -p "${SRC}"
cd "${SRC}"
# 无论如何都要保证官方 URDF 包存在(mesh + xacro)
if [[ ! -d flexiv_description ]]; then
echo "Fetching flexiv_description (${BRANCH})..."
if ! git clone --depth 1 -b "${BRANCH}" https://github.com/flexivrobotics/flexiv_description.git; then
echo "git clone slow/failed — downloading zip..."
python3 - <<PY
import urllib.request, socket, zipfile, io, shutil, os
url = "https://codeload.github.com/flexivrobotics/flexiv_description/zip/refs/heads/${BRANCH}"
old = socket.getaddrinfo
socket.getaddrinfo = lambda h, p, f=0, t=0, pr=0, fl=0: [ai for ai in old(h, p, socket.AF_INET, t, pr, fl)]
data = urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}), timeout=300).read()
dest = "${SRC}/flexiv_description"
with zipfile.ZipFile(io.BytesIO(data)) as z:
z.extractall("/tmp")
shutil.rmtree(dest, ignore_errors=True)
shutil.move("/tmp/flexiv_description-${BRANCH}", dest)
print("flexiv_description ready at", dest)
PY
fi
else
echo "flexiv_description already present"
fi
if [[ ! -d flexiv_ros2 ]]; then
echo "Cloning flexiv_ros2 (${BRANCH})..."
git clone https://github.com/flexivrobotics/flexiv_ros2.git -b "${BRANCH}"
else
echo "flexiv_ros2 already present — pull if needed: git -C flexiv_ros2 pull"
fi
REPOS_FILE=""
for candidate in flexiv_ros2/flexiv.humble.repos flexiv_ros2/flexiv.repos; do
if [[ -f "${candidate}" ]]; then
REPOS_FILE="${candidate}"
break
fi
done
if [[ -z "${REPOS_FILE}" ]]; then
echo "ERROR: no .repos file found under flexiv_ros2"
exit 1
fi
echo "Importing dependencies from ${REPOS_FILE}..."
if ! command -v vcs >/dev/null 2>&1; then
echo "Please install: sudo apt install python3-vcstool"
exit 1
fi
# 优先用本地 Flexiv_Rizon4 里的 RDK(有本地副本时就不去 GitHub 克隆)
LOCAL_FLEXIV="${LOCAL_FLEXIV:-$HOME/文档/Flexiv_Rizon4}"
if [[ -d "${LOCAL_FLEXIV}/flexiv_rdk" ]]; then
echo "Using local RDK: ${LOCAL_FLEXIV}/flexiv_rdk"
bash "${ROOT}/scripts/use_local_flexiv.sh"
elif [[ -d flexiv_rdk ]]; then
touch flexiv_rdk/COLCON_IGNORE
else
echo "Importing flexiv_rdk from ${REPOS_FILE}..."
vcs import "${SRC}" < "${REPOS_FILE}" --recursive --skip-existing
if [[ -d flexiv_rdk ]]; then
touch flexiv_rdk/COLCON_IGNORE
fi
fi
# 其余依赖一律从 .repos 导入(description 已单独处理;skip-existing 跳过已有)
vcs import "${SRC}" < "${REPOS_FILE}" --recursive --skip-existing || true
cat <<EOF
Done. Next steps (Ubuntu 22.04 / Humble + Rizon):
Local RDK wired via: scripts/use_local_flexiv.sh
src/flexiv_rdk -> ${LOCAL_FLEXIV}/flexiv_rdk (your copy, often RDK 2.x)
src/flexiv_rdk_v1 -> RDK 1.9.1 for flexiv_ros2 humble-v1 (if present)
1) Install ROS deps:
sudo apt install -y python3-colcon-common-extensions python3-vcstool \\
ros-humble-ros2-control ros-humble-ros2-controllers \\
ros-humble-moveit ros-humble-xacro ros-humble-joint-state-publisher-gui
2) Build & install RDK **v1.9.1** into ~/flexiv_install (for flexiv_hardware):
RDK_SRC=${SRC}/flexiv_rdk_v1
# fallback if only one tree: RDK_SRC=${SRC}/flexiv_rdk
cd \${RDK_SRC}/thirdparty
source /opt/ros/humble/setup.bash # or: conda activate ros_flexiv
bash build_and_install_dependencies_not_in_ros2.sh ~/flexiv_install
cd \${RDK_SRC} && rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=~/flexiv_install -DCMAKE_PREFIX_PATH=~/flexiv_install
cmake --build . --target install --config Release
3) Build this workspace:
cd ${ROOT}
source /opt/ros/humble/setup.bash
colcon build --symlink-install --cmake-args -DCMAKE_PREFIX_PATH=~/flexiv_install
source install/setup.bash
4) Real robot (site SN, no gripper yet):
ros2 launch arm_bringup real.launch.py
# or explicitly:
ros2 launch arm_bringup real.launch.py robot_sn:=<site.yaml 里该臂的 robot.sn> load_gripper:=false
Official fake hardware:
ros2 launch flexiv_bringup rizon.launch.py robot_sn:=<site.yaml 里该臂的 robot.sn> use_fake_hardware:=true load_gripper:=false
EOF