fix: make start_ros_container.sh executable
Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
244
start_ros_container.sh
Normal file → Executable file
244
start_ros_container.sh
Normal file → Executable file
@@ -1,143 +1,139 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# ROS Podman容器启动脚本
|
# ROS Podman 容器启动脚本 — 用于 rosbag 可视化
|
||||||
# 作者自动生成
|
# 用法:
|
||||||
# 功能:启动ROS容器,挂载当前目录,设置环境变量,安装pip3,错误不退出
|
# ./start_ros_container.sh # 启动交互式 shell
|
||||||
|
# ./start_ros_container.sh play <bag_name> # 自动播放 bag + 启动 rviz
|
||||||
|
|
||||||
set +e # 遇到错误时不退出
|
set -euo pipefail
|
||||||
|
|
||||||
# 颜色定义(用于美化输出)
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# 配置参数
|
# ─── 配置 ───────────────────────────────────────────────────────────────────
|
||||||
CONTAINER_IMAGE="69a38b2c0905" # ROS Noetic Desktop Full镜像ID
|
# 使用镜像名而非 ID,更可读;优先用本地 custom 镜像,fallback 到官方
|
||||||
WORKSPACE_DIR="$(pwd)" # 当前工作目录
|
CONTAINER_IMAGE="docker.io/osrf/ros:noetic-desktop-full"
|
||||||
MOUNT_POINT="/mnt" # 容器内挂载点
|
# 如果本地有 custom 镜像,优先用它(可自行修改)
|
||||||
|
if podman image exists localhost/custom-ros-noetic:v1.0 2>/dev/null; then
|
||||||
|
CONTAINER_IMAGE="localhost/custom-ros-noetic:v1.0"
|
||||||
|
fi
|
||||||
|
|
||||||
# ROS环境变量设置
|
WORKSPACE_DIR="$(pwd)"
|
||||||
ROS_ENV_VARS=(
|
MOUNT_POINT="/workspace"
|
||||||
"ROS_DISTRO=noetic"
|
BAG_DIR="$WORKSPACE_DIR/bags"
|
||||||
"ROS_PYTHON_VERSION=3"
|
CONTAINER_NAME="ros_$(date +%s)"
|
||||||
"ROS_VERSION=1"
|
|
||||||
"ROS_ETC_DIR=/opt/ros/noetic/etc/ros"
|
# ─── 前置检查 ───────────────────────────────────────────────────────────────
|
||||||
"ROS_ROOT=/opt/ros/noetic/share/ros"
|
if ! command -v podman &> /dev/null; then
|
||||||
"ROS_PACKAGE_PATH=/opt/ros/noetic/share"
|
echo -e "${RED}错误: 未安装 podman${NC}"; exit 1
|
||||||
"PYTHONIOENCODING=utf-8"
|
fi
|
||||||
"TZ=Asia/Shanghai"
|
|
||||||
|
if ! podman image exists "$CONTAINER_IMAGE"; then
|
||||||
|
echo -e "${YELLOW}正在拉取镜像 $CONTAINER_IMAGE ...${NC}"
|
||||||
|
podman pull "$CONTAINER_IMAGE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── X11 配置 ────────────────────────────────────────────────────────────────
|
||||||
|
# 你的 DISPLAY=localhost:10.0,容器内需要能访问宿主机 X11 socket
|
||||||
|
# 方案: host 网络 + 挂载 X11 socket
|
||||||
|
if [ -z "${DISPLAY:-}" ]; then
|
||||||
|
echo -e "${YELLOW}警告: DISPLAY 未设置,GUI 应用可能无法启动${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 临时允许本地 X11 连接(仅当前用户)
|
||||||
|
xhost +SI:localuser:$USER 2>/dev/null || true
|
||||||
|
|
||||||
|
# ─── 构建 podman 参数 ──────────────────────────────────────────────────────
|
||||||
|
ENV_ARGS=(
|
||||||
|
-e DISPLAY="$DISPLAY"
|
||||||
|
-e QT_X11_NO_MITSHM=1
|
||||||
|
-e ROS_DISTRO=noetic
|
||||||
|
-e ROS_MASTER_URI=http://localhost:11311
|
||||||
|
-e TZ=Asia/Shanghai
|
||||||
)
|
)
|
||||||
|
|
||||||
|
VOLUME_ARGS=(
|
||||||
|
-v "$WORKSPACE_DIR:$MOUNT_POINT:rw"
|
||||||
|
-v "/tmp/.X11-unix:/tmp/.X11-unix:rw"
|
||||||
|
)
|
||||||
|
|
||||||
|
# host 网络模式: 容器直接使用宿主机网络栈,X11 和 ros master 通信都正常
|
||||||
|
NET_ARGS=(--network=host)
|
||||||
|
|
||||||
|
# ─── 打印配置 ────────────────────────────────────────────────────────────────
|
||||||
echo -e "${GREEN}========================================${NC}"
|
echo -e "${GREEN}========================================${NC}"
|
||||||
echo -e "${GREEN}ROS Podman容器启动脚本${NC}"
|
echo -e "${GREEN}ROS Podman 容器 — rosbag 可视化${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e " 镜像: ${CYAN}$CONTAINER_IMAGE${NC}"
|
||||||
|
echo -e " 工作目录: $WORKSPACE_DIR → $MOUNT_POINT"
|
||||||
|
echo -e " DISPLAY: $DISPLAY"
|
||||||
|
echo -e " 网络模式: host"
|
||||||
|
echo -e " Bag 目录: $BAG_DIR"
|
||||||
echo -e "${GREEN}========================================${NC}"
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
|
||||||
# 检查Podman是否安装
|
# ─── 执行 ────────────────────────────────────────────────────────────────────
|
||||||
if ! command -v podman &> /dev/null; then
|
# 根据参数决定模式
|
||||||
echo -e "${RED}错误: Podman未安装,请先安装Podman${NC}"
|
if [ "${1:-}" = "play" ] && [ -n "${2:-}" ]; then
|
||||||
echo -e "${YELLOW}Ubuntu/Debian: sudo apt-get install podman${NC}"
|
BAG_FILE="$BAG_DIR/${2}_davis_with_gt.bag"
|
||||||
echo -e "${YELLOW}CentOS/RHEL: sudo yum install podman${NC}"
|
if [ ! -f "$BAG_FILE" ]; then
|
||||||
exit 1
|
echo -e "${RED}错误: bag 文件不存在: $BAG_FILE${NC}"
|
||||||
fi
|
echo -e "${YELLOW}可用的 bag 文件:${NC}"
|
||||||
|
ls -1 "$BAG_DIR"/*.bag 2>/dev/null | xargs -n1 basename | sed 's/_davis_with_gt.bag//'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# 检查镜像是否存在
|
echo -e "${GREEN}启动 rosbag play + rviz 模式${NC}"
|
||||||
echo -e "${YELLOW}检查容器镜像...${NC}"
|
echo -e " Bag: ${CYAN}$(basename "$BAG_FILE")${NC}"
|
||||||
if ! podman image exists $CONTAINER_IMAGE; then
|
echo -e "${YELLOW}容器启动后会自动播放 bag 并打开 rviz${NC}"
|
||||||
echo -e "${RED}警告: 镜像 $CONTAINER_IMAGE 不存在${NC}"
|
echo -e "${YELLOW}按 Ctrl+C 停止${NC}"
|
||||||
echo -e "${YELLOW}可用的ROS镜像:${NC}"
|
echo -e "${GREEN}========================================${NC}"
|
||||||
podman image list | grep ros
|
|
||||||
echo -e "${YELLOW}继续使用指定镜像,如果启动失败请更换镜像ID${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 构建环境变量参数
|
podman run -it --rm --name "$CONTAINER_NAME" \
|
||||||
ENV_ARGS=""
|
"${VOLUME_ARGS[@]}" \
|
||||||
for env_var in "${ROS_ENV_VARS[@]}"; do
|
"${ENV_ARGS[@]}" \
|
||||||
ENV_ARGS="$ENV_ARGS -e $env_var"
|
"${NET_ARGS[@]}" \
|
||||||
done
|
"$CONTAINER_IMAGE" \
|
||||||
|
/bin/bash -c "
|
||||||
|
set -e
|
||||||
|
source /opt/ros/noetic/setup.bash
|
||||||
|
echo '启动 roscore...'
|
||||||
|
roscore &
|
||||||
|
ROSCORE_PID=\$!
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# 添加额外的环境变量(如果用户需要)
|
echo '播放 bag: ${2}_davis_with_gt.bag'
|
||||||
ENV_ARGS="$ENV_ARGS -e DISPLAY=$DISPLAY" # 支持GUI应用
|
rosbag play --clock \"$MOUNT_POINT/bags/${2}_davis_with_gt.bag\" &
|
||||||
ENV_ARGS="$ENV_ARGS -e QT_X11_NO_MITSHM=1"
|
BAG_PID=\$!
|
||||||
|
sleep 1
|
||||||
|
|
||||||
# X11支持(用于GUI应用)
|
echo '启动 rviz...'
|
||||||
if [ -n "$DISPLAY" ]; then
|
rviz -d \"$MOUNT_POINT/visualize/default.rviz\" 2>/dev/null || rviz
|
||||||
echo -e "${YELLOW}启用X11支持,用于GUI应用...${NC}"
|
|
||||||
xhost +local:root 2>/dev/null
|
|
||||||
ENV_ARGS="$ENV_ARGS --volume /tmp/.X11-unix:/tmp/.X11-unix:rw"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}配置信息:${NC}"
|
# 等待 bag 播放完成
|
||||||
echo -e " 工作目录: $WORKSPACE_DIR"
|
wait \$BAG_PID 2>/dev/null || true
|
||||||
echo -e " 挂载点: $MOUNT_POINT"
|
kill \$ROSCORE_PID 2>/dev/null || true
|
||||||
echo -e " 镜像ID: $CONTAINER_IMAGE"
|
"
|
||||||
echo -e " ROS发行版: noetic"
|
|
||||||
|
|
||||||
echo -e "${YELLOW}正在启动容器...${NC}"
|
|
||||||
|
|
||||||
# 启动容器的命令
|
|
||||||
# 使用bash -c来执行多个命令,确保pip3安装即使失败也不会退出容器
|
|
||||||
PODMAN_CMD="podman run -it \
|
|
||||||
--rm \
|
|
||||||
--name ros_noetic_container_$(date +%s) \
|
|
||||||
-v $WORKSPACE_DIR:$MOUNT_POINT:rw \
|
|
||||||
$ENV_ARGS \
|
|
||||||
$CONTAINER_IMAGE \
|
|
||||||
/bin/bash -c \"\
|
|
||||||
echo '========================================' && \
|
|
||||||
echo 'ROS容器已启动' && \
|
|
||||||
echo '========================================' && \
|
|
||||||
echo '工作目录已挂载到: $MOUNT_POINT' && \
|
|
||||||
echo '当前ROS版本: ' && \
|
|
||||||
echo \\\$ROS_DISTRO && \
|
|
||||||
echo '' && \
|
|
||||||
echo '正在检查并安装pip3...' && \
|
|
||||||
if command -v pip3 &> /dev/null; then \
|
|
||||||
echo 'pip3已安装,版本: ' && \
|
|
||||||
pip3 --version; \
|
|
||||||
else \
|
|
||||||
echo 'pip3未安装,正在安装...' && \
|
|
||||||
apt-get update 2>/dev/null && \
|
|
||||||
apt-get install -y python3-pip 2>/dev/null; \
|
|
||||||
if [ \\\$? -eq 0 ]; then \
|
|
||||||
echo 'pip3安装成功!'; \
|
|
||||||
pip3 --version; \
|
|
||||||
else \
|
|
||||||
echo '警告: pip3安装失败,请手动安装'; \
|
|
||||||
fi; \
|
|
||||||
fi && \
|
|
||||||
echo '' && \
|
|
||||||
echo '========================================' && \
|
|
||||||
echo '环境变量已设置:' && \
|
|
||||||
env | grep ROS_ && \
|
|
||||||
echo '========================================' && \
|
|
||||||
echo '容器已准备就绪,进入交互式shell...' && \
|
|
||||||
echo '提示: 输入exit退出容器' && \
|
|
||||||
echo '========================================' && \
|
|
||||||
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/simple && \
|
|
||||||
source /ros_entrypoint.sh && \
|
|
||||||
cd $MOUNT_POINT && \
|
|
||||||
exec /bin/bash -l\""
|
|
||||||
|
|
||||||
# 执行命令
|
|
||||||
echo -e "${GREEN}执行启动命令...${NC}"
|
|
||||||
# echo -e "${YELLOW}命令详情:${NC}"
|
|
||||||
# echo "$PODMAN_CMD"
|
|
||||||
echo -e "${YELLOW}========================================${NC}"
|
|
||||||
|
|
||||||
# 运行容器
|
|
||||||
eval $PODMAN_CMD
|
|
||||||
|
|
||||||
# 检查退出状态
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}容器已退出(退出码非0)${NC}"
|
|
||||||
else
|
else
|
||||||
echo -e "${GREEN}容器正常退出${NC}"
|
# 交互式 shell 模式
|
||||||
|
echo -e "${GREEN}启动交互式 shell${NC}"
|
||||||
|
echo -e "${YELLOW}提示: 进入后执行以下命令播放 bag${NC}"
|
||||||
|
echo -e " source /opt/ros/noetic/setup.bash"
|
||||||
|
echo -e " roscore &"
|
||||||
|
echo -e " rosbag play --clock $MOUNT_POINT/bags/indoor_forward_3_davis_with_gt.bag"
|
||||||
|
echo -e " rviz"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
|
||||||
|
podman run -it --rm --name "$CONTAINER_NAME" \
|
||||||
|
"${VOLUME_ARGS[@]}" \
|
||||||
|
"${ENV_ARGS[@]}" \
|
||||||
|
"${NET_ARGS[@]}" \
|
||||||
|
"$CONTAINER_IMAGE" \
|
||||||
|
/bin/bash -c "
|
||||||
|
source /opt/ros/noetic/setup.bash
|
||||||
|
cd $MOUNT_POINT
|
||||||
|
exec /bin/bash -l
|
||||||
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 清理X11权限
|
# ─── 清理 ────────────────────────────────────────────────────────────────────
|
||||||
if [ -n "$DISPLAY" ]; then
|
xhost -SI:localuser:$USER 2>/dev/null || true
|
||||||
xhost -local:root 2>/dev/null
|
echo -e "${GREEN}容器已退出${NC}"
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}脚本执行完成${NC}"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user