仿真环境串味根治:清残留路径 + 补 conda lib + 修入口脚本 shebang

症状一(最隐蔽):同一 shell 里先 source 过真机环境(scripts/env.sh)再
source 仿真环境,install/ 与 ros_flexiv 的路径不会被 conda deactivate 撤掉,
长在 install_sim/ 前面:
  - PYTHONPATH 里真机那份 arm_msgs 压住仿真那份 → 消息类型混用
  - LD_LIBRARY_PATH 里没有 $CONDA_PREFIX/lib → sim_tactile_adapter 订阅
    ros_gz_interfaces/Contacts 时抛
      Type support not from this implementation ...
      cannot open shared object file
    而库其实就在 conda 里、ldd 全齐。整条触觉链静默死掉(话题不发)。

症状二:setuptools 写 console_scripts 用的是**构建那一刻**的 python。
若在真机环境里跑过 build_sim.sh,install_sim/ 里 7 个入口脚本的 shebang
会指向 ros_flexiv —— 而 ros2 run 是照 shebang 执行的,于是**仿真节点一直
跑在真机 conda 环境里**。两个环境都是 Humble+py3.11,所以"居然能跑",
只有偶发 dlopen / 反序列化怪错。

修法:
  - conda_switch.sh 新增 path_drop_patterns:按 glob 从冒号列表里删条目
  - sim_env.sh 清掉真机残留 + 末尾补 $CONDA_PREFIX/lib(优先级最低)
  - 新增 lib/fix_shebangs.sh,build.sh / build_sim.sh 收尾各扫一遍(幂等)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-24 14:42:50 +08:00
parent bda2fa7129
commit aed5d326a0
5 changed files with 171 additions and 0 deletions
+47
View File
@@ -52,5 +52,52 @@ conda_switch_clean() {
return 0
}
# path_drop_patterns <VAR> <glob>...
# 从环境变量 <VAR> 的冒号分隔列表里删掉所有匹配任一 glob 的条目(保持剩余顺序)。
# 用于清理"同一个 shell 里先 source 过另一套环境"留下的路径残留。
#
# 为什么必须清:真机环境(scripts/env.sh)与仿真环境(scripts/sim_env.sh)
# 共用同一个工作区,各自的 setup.bash 都会往 PATH / PYTHONPATH /
# LD_LIBRARY_PATH / AMENT_PREFIX_PATH 里追加自己的产物目录。conda 的
# deactivate 只会撤掉 conda 自己那部分,**不会**撤掉 setup.bash 追加的条目。
# 于是"先真机后仿真"的 shell 里会长成这样:
# PYTHONPATH = .../install/arm_msgs/... : .../install_sim/arm_msgs/...
# 此时 `import arm_msgs` 会拿到**真机那份**,与 install_sim 下的运行库混用,
# 症状是消息反序列化莫名失败、字段对不上、dlopen 找不到 typesupport ——
# 报错信息完全不提"环境脏了"这个真实原因。
#
# 实测踩过:sim_tactile_adapter 订阅 ros_gz_interfaces/msg/Contacts 时崩在
# rcutils_set_error_state: Type support not from this implementation ...
# Could not load library libros_gz_interfaces__rosidl_typesupport_fastrtps_c.so
# 库其实就在 $CONDA_PREFIX/lib 下(ldd 全齐),根因是 LD_LIBRARY_PATH 里
# 既残留着 ros_flexiv 的 lib、又**没有** $CONDA_PREFIX/lib。
path_drop_patterns() {
local _var="$1"
shift
local -a _pats=("$@")
local _cur="${!_var:-}"
[[ -z "${_cur}" ]] && return 0
local _out="" _entry _pat _hit
local IFS=':'
for _entry in ${_cur}; do
_hit=0
for _pat in "${_pats[@]}"; do
# 故意不加引号:让右侧当 glob 用(这里就是要通配匹配)
# shellcheck disable=SC2053
if [[ "${_entry}" == ${_pat} ]]; then
_hit=1
break
fi
done
[[ "${_hit}" -eq 1 ]] && continue
_out="${_out:+${_out}:}${_entry}"
done
printf -v "${_var}" '%s' "${_out}"
export "${_var?}"
return 0
}
# 供调用方按需取消设置,避免污染使用者的变量空间。
# (bash 没有"私有函数"概念,命名上统一加 conda_ 前缀降低撞名概率。)