P5c-1:把 Gazebo 仿真环境真正装起来(独立 conda 环境),并固化安装/构建流程
在此之前,仓库里所有 Gazebo 相关的东西都是"声明"而非"事实": arm.gazebo.xacro 零引用、stack.launch.py 的 isaac 分支只打印日志、 没有 world 文件、devices/sim/gazebo 下的目录全是空占位。 更关键的是:**这台机器上根本没装 Gazebo**,而 ROS 在 conda 里,没有 /opt/ros, apt 的 ros-humble-gazebo-* 装了也不会被 conda 的 ROS 认到。 环境(与真机环境物理隔离) - 新建 conda 环境 ros_gz_sim,**不碰能跑真机的 ros_flexiv**。 仿真要往环境里塞 Gazebo 及 protobuf/ignition/渲染一整条链, 和真机环境混装随时可能把它弄坏,代价远大于仿真带来的便利。 - 频道组合照抄 ros_flexiv 的安装记录(robostack-staging + conda-forge), 那是本机已经证明可用的搭配。 两个实测踩到的坑(都写进了脚本注释,避免下次重踩) 1. empy 版本:conda 默认给 empy 4.x,而 Humble 的 rosidl_adapter 用的是 3.x 的 API。症状是构建自定义消息包时报 `_interpreter.shutdown()` 的 AttributeError, 报错点在 rosidl_adapter 内部,完全看不出跟 empy 有关。必须钉 empy=3.3.4。 2. conda 激活是**堆叠**的:同一 shell 里从 ros_gz_sim 切到 ros_flexiv 后, `which python` 指向 ros_flexiv,但 `python -m pip` 却解析到 ros_gz_sim 的 pip, 导致 colcon --symlink-install 报 "option --editable not recognized"。 这个报错和真实原因毫无关系,极易误判成"环境被搞坏了"。 现在 scripts/lib/conda_switch.sh 会在切换前退到 base,两个 env 脚本共用。 仿真用独立构建产物 - build_sim/ + install_sim/(scripts/build_sim.sh)。工作区只有一份源码, 若仿真也写 install/,就会覆盖真机的构建产物。 - 排除 11 个真机专属包(flexiv_hardware 需要 Flexiv RDK C++ SDK,根本装不上; 另有真机驱动/GPIO/MoveIt 配置/真机 bringup),每个都在脚本里写了理由。 已验证(不是只看退出码) - Gazebo Fortress 6.16 无头启动正常,物理初始化完成 - /clock 桥接到 ROS 成功收到仿真时间;ros_gz_sim create 成功往世界里建物 - 真机构建 18 包通过、233 项测试通过,build/ install/ 时间戳未变(没被覆盖) - 仿真侧 7 包构建通过;两环境互切后各自都能正常构建 注:Humble 配的是 Gazebo Fortress(ignition-gazebo6,命令行 `ign gazebo`), 不是现代的 gz-sim —— 后者要 libprotobuf>=6.31,与 RoboStack Humble 钉住的 5.29.3 解不开依赖。Fortress 属于新 Gazebo 家族(非已 EOL 的 Classic), 且是 Humble 的官方配对版本。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,6 +22,12 @@ models/staging/**
|
||||
build/
|
||||
install/
|
||||
log/
|
||||
# 仿真的构建产物 —— 与真机的 build/ install/ 隔离(见 scripts/build_sim.sh)
|
||||
# 两套产物目录并存是刻意的:工作区只有一份源码,两个环境的依赖路径不同,
|
||||
# 共用 install/ 会互相覆盖。
|
||||
build_sim/
|
||||
install_sim/
|
||||
log_sim/
|
||||
.colcon/
|
||||
|
||||
# Python
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# 在仿真环境里构建本工作区。
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/build_sim.sh # 增量构建
|
||||
# bash scripts/build_sim.sh --clean # 先删掉 build_sim/ install_sim/
|
||||
# bash scripts/build_sim.sh --all # 不做任何排除(用于排查)
|
||||
#
|
||||
# 关键:构建产物写进 build_sim/ install_sim/,**绝不碰真机环境的 build/ install/**。
|
||||
# 工作区只有一份源码,两个环境各用一套产物目录,互不覆盖。
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${ROOT}"
|
||||
|
||||
CLEAN=0
|
||||
NO_SKIP=0
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
--clean) CLEAN=1 ;;
|
||||
--all) NO_SKIP=1 ;;
|
||||
-h|--help) sed -n '2,15p' "$0"; exit 0 ;;
|
||||
*) echo "未知参数: $a" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- 排除清单 ---------------------------------------------------------------
|
||||
# 这些包在仿真里用不上,而且不少根本**装不上**(依赖真机 SDK),不排除就整个构建失败。
|
||||
# 每一项都写清理由,避免以后有人不明就里地删掉或加回来。
|
||||
SKIP=(
|
||||
# 需要 Flexiv RDK C++ SDK(flexiv_rdk),仿真里硬件层由 gz_ros2_control 提供
|
||||
flexiv_hardware
|
||||
# 真机 RDK 桥接驱动(起子进程连真机),仿真里无真机可连
|
||||
arm_driver_flexiv
|
||||
# Flexiv 官方真机栈
|
||||
flexiv_msgs
|
||||
flexiv_bringup
|
||||
flexiv_gripper
|
||||
flexiv_robot_states_broadcaster
|
||||
# 真机硬件测试节点
|
||||
flexiv_test_nodes
|
||||
# 真机 GPIO(气爪/电磁阀),仿真里没有对应的物理器件
|
||||
gpio_controller
|
||||
# MoveIt 配置:体量大,且仿真运动不走 MoveIt 规划
|
||||
arm_moveit_config
|
||||
flexiv_moveit_config
|
||||
# 真机 bringup。它 CMake 硬依赖 arm_moveit_config,而仿真启动器是
|
||||
# arm_sim_gazebo(见 devices/sim/gazebo/manifest.yaml 的声明),
|
||||
# 不需要它。真机路径完全不受影响。
|
||||
arm_bringup
|
||||
)
|
||||
|
||||
echo "=== 构建仿真工作区 ==="
|
||||
echo " 产物目录: build_sim/ install_sim/"
|
||||
if [[ "${NO_SKIP}" -eq 1 ]]; then
|
||||
echo " 排除: 无(--all)"
|
||||
else
|
||||
echo " 排除: ${#SKIP[@]} 个真机专属包"
|
||||
fi
|
||||
|
||||
if [[ "${CLEAN}" -eq 1 ]]; then
|
||||
echo " 清理: 删除 build_sim/ install_sim/ log_sim/"
|
||||
rm -rf build_sim install_sim log_sim
|
||||
fi
|
||||
|
||||
# --- 激活仿真环境 -----------------------------------------------------------
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/scripts/sim_env.sh"
|
||||
|
||||
ARGS=(build --build-base build_sim --install-base install_sim)
|
||||
# 注意:这里**不能**加 --symlink-install。仿真环境的 setuptools 较旧,
|
||||
# 不认 --editable,会报 "error: option --editable not recognized"。
|
||||
# 代价只是安装产物是拷贝而非软链,功能不受影响。
|
||||
if [[ "${NO_SKIP}" -eq 0 ]]; then
|
||||
ARGS+=(--packages-skip "${SKIP[@]}")
|
||||
fi
|
||||
|
||||
colcon --log-base log_sim "${ARGS[@]}" 2>&1 \
|
||||
| grep -vE 'anaconda-auth|conda-content-trust|Unknown distribution option|warnings\.warn'
|
||||
|
||||
echo
|
||||
echo "构建完成。启动仿真: bash scripts/run_sim_gz.sh"
|
||||
@@ -14,7 +14,20 @@ fi
|
||||
if [[ -f "${HOME}/anaconda3/etc/profile.d/conda.sh" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "${HOME}/anaconda3/etc/profile.d/conda.sh"
|
||||
# 干净切换:先把堆叠的激活退到 base,再激活真机环境。
|
||||
# 同一 shell 里从仿真环境(ros_gz_sim)切过来时,不清干净会残留 PATH/PYTHONPATH,
|
||||
# 导致 python/pip 解析到另一个环境的包,构建报 "--editable not recognized"
|
||||
# 之类与真实原因无关的错。详见 scripts/lib/conda_switch.sh。
|
||||
_env_helper="${ROOT}/scripts/lib/conda_switch.sh"
|
||||
if [[ -f "${_env_helper}" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${_env_helper}"
|
||||
conda_switch_clean "ros_flexiv" "${SIM_ENV_NAME:-ros_gz_sim}" || \
|
||||
conda activate ros_flexiv 2>/dev/null || true
|
||||
else
|
||||
conda activate ros_flexiv 2>/dev/null || true
|
||||
fi
|
||||
unset _env_helper
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# 创建 / 修复 Gazebo 仿真用的独立 conda 环境。
|
||||
#
|
||||
# 为什么单独一个环境,而不是往 ros_flexiv 里装:
|
||||
# ros_flexiv 是**能跑真机**的那一套。仿真需要往环境里加 Gazebo 及其一大堆
|
||||
# 依赖(protobuf / ignition / 渲染栈),和真机环境混装随时可能把它弄坏。
|
||||
# 真机环境坏了,代价远大于仿真带来的便利。所以两者物理隔离。
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/install_sim_env.sh # 创建或补齐(幂等,可重复跑)
|
||||
# bash scripts/install_sim_env.sh --verify # 只验证现有环境,不安装
|
||||
#
|
||||
# 装完用 scripts/sim_env.sh 激活,用 scripts/run_sim_gz.sh 启动。
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_NAME="${SIM_ENV_NAME:-ros_gz_sim}"
|
||||
CONDA_SH="${HOME}/anaconda3/etc/profile.d/conda.sh"
|
||||
|
||||
# 频道组合照抄现有 ros_flexiv 环境的安装记录,那是已经证明可用的搭配。
|
||||
CHANNELS=(-c robostack-staging -c conda-forge)
|
||||
|
||||
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
|
||||
info() { printf ' \033[36m·\033[0m %s\n' "$1"; }
|
||||
die() { printf ' \033[31m✗ %s\033[0m\n' "$1" >&2; exit 1; }
|
||||
|
||||
if [[ ! -f "${CONDA_SH}" ]]; then
|
||||
die "找不到 conda: ${CONDA_SH}(本脚本假定 anaconda 装在 ~/anaconda3)"
|
||||
fi
|
||||
# shellcheck disable=SC1090
|
||||
source "${CONDA_SH}"
|
||||
|
||||
# --- 验证 -------------------------------------------------------------------
|
||||
verify() {
|
||||
info "激活 ${ENV_NAME} 并自检…"
|
||||
conda activate "${ENV_NAME}" 2>/dev/null || die "激活失败,环境可能没建好"
|
||||
|
||||
echo
|
||||
echo "1) 仿真器本体"
|
||||
# 注意:Humble 配的是 Gazebo Fortress,命令行是 `ign gazebo`,不是 `gz sim`。
|
||||
# 现代包名 gz-sim 在 conda-forge 上要 libprotobuf>=6.31,而 RoboStack 的
|
||||
# Humble 把 protobuf 钉在 5.29.3,混装会解不开依赖。Fortress 是官方配对版本。
|
||||
ign gazebo --version 2>&1 | head -1 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "2) ROS 侧桥接与力控"
|
||||
local missing=0 p
|
||||
for p in ros_gz_sim ros_gz_bridge gz_ros2_control controller_manager ros2_control xacro; do
|
||||
if ros2 pkg prefix "$p" >/dev/null 2>&1; then
|
||||
ok "$p"
|
||||
else
|
||||
printf ' \033[31m✗ %s 缺失\033[0m\n' "$p"; missing=1
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "3) 构建工具链(Humble 的 rosidl 需要 empy 3.x)"
|
||||
local empy_ver
|
||||
empy_ver="$(python -c 'import em; print(em.__version__)' 2>/dev/null || echo '?')"
|
||||
if [[ "${empy_ver}" == 3.* ]]; then
|
||||
ok "empy ${empy_ver}"
|
||||
else
|
||||
printf ' \033[31m✗ empy %s —— 必须是 3.x,否则 rosidl 生成接口时会报\n' "${empy_ver}"
|
||||
printf ' "AttributeError: NoneType object has no attribute shutdown"\033[0m\n'
|
||||
missing=1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "4) 仿真能真跑起来吗(无头空跑 30 步)"
|
||||
local world
|
||||
world="$(find "${CONDA_PREFIX}/share" -name empty.sdf -path '*gazebo*' 2>/dev/null | head -1)"
|
||||
if [[ -n "${world}" ]] && timeout 60 ign gazebo -s -r --iterations 30 "${world}" >/dev/null 2>&1; then
|
||||
ok "仿真引擎正常启动"
|
||||
else
|
||||
printf ' \033[31m✗ 仿真引擎启动失败\033[0m\n'; missing=1
|
||||
fi
|
||||
|
||||
echo
|
||||
if [[ "${missing}" -eq 0 ]]; then
|
||||
echo "环境就绪。下一步:"
|
||||
echo " source scripts/sim_env.sh"
|
||||
echo " bash scripts/build_sim.sh"
|
||||
echo " bash scripts/run_sim_gz.sh"
|
||||
else
|
||||
echo "环境不完整,重跑 bash scripts/install_sim_env.sh 补齐。"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--verify" ]]; then
|
||||
verify
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# --- 安装 -------------------------------------------------------------------
|
||||
echo "=== 1/4 创建环境 ${ENV_NAME} ==="
|
||||
if conda env list | awk '{print $1}' | grep -qx "${ENV_NAME}"; then
|
||||
ok "已存在,跳过创建"
|
||||
else
|
||||
conda create -y -n "${ENV_NAME}" python=3.11 pip || die "创建环境失败"
|
||||
ok "已创建"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== 2/4 安装 ROS 2 Humble 仿真栈 ==="
|
||||
info "ros-humble-ros-gz 会一并带入 Gazebo Fortress(ignition-gazebo6)"
|
||||
conda install -y -n "${ENV_NAME}" "${CHANNELS[@]}" \
|
||||
ros-humble-ros-base \
|
||||
ros-humble-ros-gz \
|
||||
ros-humble-gz-ros2-control \
|
||||
ros-humble-ros2-control \
|
||||
ros-humble-ros2-controllers \
|
||||
ros-humble-controller-manager \
|
||||
ros-humble-robot-state-publisher \
|
||||
ros-humble-joint-state-publisher \
|
||||
ros-humble-joint-state-publisher-gui \
|
||||
ros-humble-xacro \
|
||||
ros-humble-tf2-ros \
|
||||
ros-humble-camera-info-manager \
|
||||
ros-humble-image-transport-plugins \
|
||||
compilers cmake make pkg-config catkin_pkg lark-parser numpy \
|
||||
colcon-common-extensions || die "ROS 仿真栈安装失败"
|
||||
|
||||
echo
|
||||
echo "=== 3/4 钉住 empy 3.x(Humble 的硬性要求)==="
|
||||
# 坑:conda 默认会给 empy 4.x,而 Humble 的 rosidl_adapter 用 empy 3.x 的 API。
|
||||
# 症状是构建自定义消息包时报 '_interpreter.shutdown()' 的 AttributeError,
|
||||
# 报错点在 rosidl_adapter 内部,看起来完全不像 empy 的问题。
|
||||
conda install -y -n "${ENV_NAME}" "${CHANNELS[@]}" "empy=3.3.4" || die "empy 降级失败"
|
||||
ok "empy 3.3.4"
|
||||
|
||||
echo
|
||||
echo "=== 4/4 自检 ==="
|
||||
verify
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# conda 环境切换的公共逻辑。被 scripts/env.sh 与 scripts/sim_env.sh 共用。
|
||||
#
|
||||
# 为什么需要这个:conda 的 activate 是**堆叠**的。在同一个 shell 里反复
|
||||
# activate / 切换不同环境,会不断往 PATH、PYTHONPATH 里追加条目,而不会
|
||||
# 清掉前一个环境留下的。实测的后果非常隐蔽:
|
||||
#
|
||||
# 在同一个 shell 里先 activate ros_gz_sim 再切 ros_flexiv 之后,
|
||||
# `which python` 指向 ros_flexiv/bin/python,
|
||||
# 但 `python -m pip` 却解析到 ros_gz_sim 的 pip!
|
||||
# 于是 colcon --symlink-install 报:
|
||||
# error: option --editable not recognized
|
||||
# 这个报错和真实原因(shell 脏了)毫无关系,极易被误判成
|
||||
# "环境被搞坏了 / setuptools 版本不对",进而去做一堆无用的修复。
|
||||
#
|
||||
# 对策:切换前先把堆叠的激活全部退掉(退到 base),再激活目标环境。
|
||||
# =============================================================================
|
||||
|
||||
# conda_deactivate_all: 退到 base(CONDA_SHLVL=1)。任何环境下调用都安全。
|
||||
conda_deactivate_all() {
|
||||
local guard=0
|
||||
# CONDA_SHLVL 是 conda 自己维护的激活层数;base 为 1。
|
||||
# 加 guard 是为了防止某些畸形状态下无限循环。
|
||||
while [[ "${CONDA_SHLVL:-1}" -gt 1 && "${guard}" -lt 20 ]]; do
|
||||
conda deactivate 2>/dev/null || break
|
||||
guard=$((guard + 1))
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# conda_switch_clean <env_name> [<other_env_name>]
|
||||
# 干净地激活 <env_name>;若当前已在 <other_env_name> 里,先退到 base 再切,
|
||||
# 并提示用户最好开新 shell。
|
||||
# 返回 0 = 成功;非 0 = 目标环境不存在。
|
||||
conda_switch_clean() {
|
||||
local target="$1"
|
||||
local other="${2:-}"
|
||||
|
||||
if [[ -n "${other}" && "${CONDA_DEFAULT_ENV:-}" == "${other}" ]]; then
|
||||
echo "提示: 当前 shell 激活的是 ${other},即将切到 ${target}。" >&2
|
||||
echo " conda 的激活是堆叠的,同一 shell 里来回切会残留 PATH/PYTHONPATH," >&2
|
||||
echo " 典型症状是构建报 \"--editable not recognized\" 这类与真实原因无关的错。" >&2
|
||||
echo " 这里会先退到 base 再切以规避;但最稳妥仍是开一个新 shell。" >&2
|
||||
fi
|
||||
|
||||
conda_deactivate_all
|
||||
|
||||
if ! conda activate "${target}" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# 供调用方按需取消设置,避免污染使用者的变量空间。
|
||||
# (bash 没有"私有函数"概念,命名上统一加 conda_ 前缀降低撞名概率。)
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# 激活**仿真**环境(Gazebo Fortress + 本工作区的仿真构建产物)。
|
||||
#
|
||||
# 用法: source scripts/sim_env.sh
|
||||
#
|
||||
# 与 scripts/env.sh(真机环境)的关系:
|
||||
# 两者互斥,各自用一套 conda 环境 + 一套构建产物。
|
||||
# 真机: ros_flexiv → build/ install/
|
||||
# 仿真: ros_gz_sim → build_sim/ install_sim/
|
||||
# 切换时**最好开新的 shell**。同一 shell 里来回切会残留 PATH/PYTHONPATH,
|
||||
# 症状详见 scripts/lib/conda_switch.sh 顶部的说明(实测踩过)。
|
||||
# 这里会先退到 base 再切以尽量规避,但开新 shell 才是稳妥做法。
|
||||
#
|
||||
# 为什么仿真用独立的 build/install 目录:
|
||||
# 工作区只有一份源码。如果仿真也往 install/ 里写,就会把真机环境的构建
|
||||
# 产物覆盖掉(两边的依赖路径不同)。分目录后互不干扰。
|
||||
# =============================================================================
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
SIM_ENV_NAME="${SIM_ENV_NAME:-ros_gz_sim}"
|
||||
REAL_ENV_NAME="${REAL_ENV_NAME:-ros_flexiv}"
|
||||
CONDA_SH="${HOME}/anaconda3/etc/profile.d/conda.sh"
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/scripts/lib/conda_switch.sh"
|
||||
|
||||
if [[ ! -f "${CONDA_SH}" ]]; then
|
||||
echo "找不到 conda: ${CONDA_SH}" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${CONDA_SH}"
|
||||
|
||||
# 关掉 `set -u`:ROS 的 activate.d 脚本会引用未绑定的 CONDA_BUILD,
|
||||
# 调用方常带 set -u,那样会直接把 source 打断,表现为"脚本毫无输出就退出"。
|
||||
_sim_had_u=0
|
||||
case "$-" in *u*) _sim_had_u=1; set +u ;; esac
|
||||
|
||||
if ! conda_switch_clean "${SIM_ENV_NAME}" "${REAL_ENV_NAME}"; then
|
||||
[[ "${_sim_had_u}" -eq 1 ]] && set -u
|
||||
unset _sim_had_u
|
||||
echo "无法激活 conda 环境 ${SIM_ENV_NAME}。" >&2
|
||||
echo "先创建: bash ${ROOT}/scripts/install_sim_env.sh" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
# 仿真构建产物(由 scripts/build_sim.sh 用 --install-base 生成,与真机隔离)
|
||||
if [[ -f "${ROOT}/install_sim/setup.bash" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/install_sim/setup.bash"
|
||||
else
|
||||
echo "提示: install_sim/ 还不存在,先跑 bash scripts/build_sim.sh" >&2
|
||||
fi
|
||||
|
||||
[[ "${_sim_had_u}" -eq 1 ]] && set -u
|
||||
unset _sim_had_u
|
||||
|
||||
export YOLO_AUTOINSTALL=false
|
||||
export ROS2_WS="${ROOT}"
|
||||
# 仿真单独一个 DDS domain:避免与正在跑的真机节点互相抢话题/污染 TF。
|
||||
# 真机用的是默认 domain,两者天然隔离。
|
||||
export ROS_DOMAIN_ID="${ROS_DOMAIN_ID:-77}"
|
||||
|
||||
# 仿真与真机共用同一份 site.yaml —— 这样"仿真里调好的参数搬到真机也生效"。
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT}/scripts/lib/load_site_config.sh" 2>/dev/null || true
|
||||
|
||||
echo "[sim_env] CONDA=${CONDA_DEFAULT_ENV} ROS_DISTRO=${ROS_DISTRO} ROS_DOMAIN_ID=${ROS_DOMAIN_ID}"
|
||||
Reference in New Issue
Block a user