一键式自动化清除ROS2节点脚本[原创]

温清在此 队员 2026-01-14 16:06:39
加精

问题:调试建图参数等场景等需要彻底清除当前运行的ros2节点,配好参数重新启动ros2节点,但是ros节点启动数比较多,且清除ros2节点进程号后还存留ros2节点无法彻底清除。

解决方法:核心原理是清理共享内存 (SHM)。ROS 2 的默认中间件(如 FastDDS, CycloneDDS)为了实现高性能,使用了 共享内存(Shared Memory) 进行进程间通信(IPC)。如果 ROS 2 进程异常崩溃(Crash),它在 /dev/shm 目录下创建的段文件(Segment Files)不会被自动回收。下次启动时,新进程会尝试申请同名的内存段,从而触发 Failed to create segment 或内存溢出错误。以下的脚本通过“进程终止”与“资源释放”两手抓,解决由于程序异常崩溃导致的共享内存(Shared Memory)残留和节点僵死问题。


#!/usr/bin/env bash
set -euo pipefail

# ==========================================
# 参数配置
# ==========================================
DRY_RUN=0
FORCE=0
SIGNAL="INT"  # ROS2 推荐使用 SIGINT
TIMEOUT_SEC=5

usage() {
    echo "用法: $0 [选项]"
    echo "选项:"
    echo "  --dry-run   仅显示将要执行的操作(不杀进程,不删文件)"
    echo "  --force     超时后强制发送 SIGKILL"
    echo "  --signal S  指定信号 (默认: INT, 可选 TERM/KILL)"
    echo "  --timeout N 等待秒数 (默认: 5)"
    exit 0
}

# 解析参数
while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run) DRY_RUN=1; shift ;;
        --force) FORCE=1; shift ;;
        --signal) SIGNAL="${2:-}"; shift 2 ;;
        --timeout) TIMEOUT_SEC="${2:-}"; shift 2 ;;
        -h|--help) usage ;;
        *) echo "未知参数: $1"; usage ;;
    esac
done

echo "=== 开始执行 ROS 2 环境清理 ==="

# 1. 尝试停止 ROS 2 Daemon
if command -v ros2 >/dev/null 2>&1; then
    if [[ "$DRY_RUN" -eq 1 ]]; then
        echo "[Dry-run] 将停止 ROS 2 Daemon"
    else
        echo "停止 ROS 2 Daemon..."
        ros2 daemon stop >/dev/null 2>&1 || true
    fi
fi

# 2. 收集需要杀死的 PIDs
DECLARE_PIDS=()

# A. 从日志获取 PID
LATEST_LOG=$(ls -td /tmp/ros2_nav_* 2>/dev/null | head -1 || true)
if [[ -n "$LATEST_LOG" && -f "$LATEST_LOG/pids.txt" ]]; then
    echo "发现日志 PID 文件: $LATEST_LOG/pids.txt"
    mapfile -t FILE_PIDS < "$LATEST_LOG/pids.txt"
    DECLARE_PIDS+=("${FILE_PIDS[@]}")
fi

# B. 基于正则匹配所有 ROS 2 相关进程
ROS2_REGEX='ros2|/opt/ros/|rviz2|nav2_|slam_toolbox|chassis_controller|lazer_node|pose_node|explore|controller_node|cyclonedds|fastrtps|fastdds|iceoryx'

MAPFILE_PIDS=($(ps -eo pid=,args= | awk -v re="$ROS2_REGEX" -v self="$$" '$0 ~ re { if ($1 != self) print $1 }'))
DECLARE_PIDS+=("${MAPFILE_PIDS[@]}")

# 去重并验证 PID 是否存在
FINAL_PIDS=($(echo "${DECLARE_PIDS[@]}" | tr ' ' '\n' | sort -u | xargs -I{} sh -c "kill -0 {} 2>/dev/null && echo {}" || true))

if [[ ${#FINAL_PIDS[@]} -eq 0 ]]; then
    echo "未发现运行中的相关进程。"
else
    echo "待处理进程数: ${#FINAL_PIDS[@]}"
    if [[ "$DRY_RUN" -eq 1 ]]; then
        ps -o pid=,args= -p "${FINAL_PIDS[@]}"
        echo "[Dry-run] 进程清理跳过"
    else
        # 3. 发送信号
        echo "发送 SIG${SIGNAL} 信号..."
        kill -s "$SIGNAL" "${FINAL_PIDS[@]}" 2>/dev/null || true

        # 4. 等待退出
        echo "等待进程退出 (超时: ${TIMEOUT_SEC}s)..."
        end=$((SECONDS + TIMEOUT_SEC))
        while (( SECONDS < end )); do
            still_running=0
            for pid in "${FINAL_PIDS[@]}"; do
                if kill -0 "$pid" 2>/dev/null; then ((still_running++)); fi
            done
            if [[ $still_running -eq 0 ]]; then break; fi
            sleep 0.5
        done

        # 5. 强制杀掉残留
        if [[ "$FORCE" -eq 1 ]]; then
            for pid in "${FINAL_PIDS[@]}"; do
                if kill -0 "$pid" 2>/dev/null; then
                    echo "强制杀掉残留进程: $pid"
                    kill -9 "$pid" 2>/dev/null || true
                fi
            done
        fi
    fi
fi

# 6. 核心优化:清理共享内存段与 IPC 残留
# 这是解决 "Failed to create segment / No such file or directory" 的关键
echo "清理共享内存与 IPC 残留..."

# 定义需要清理的文件模式
# fastrtps: FastDDS 默认前缀
# iceoryx: 高级共享内存管理前缀
# rtps: 通用实时传输协议残留
SHM_PATTERNS=("fastrtps_*" "iceoryx_*" "rtps_*")

if [[ "$DRY_RUN" -eq 1 ]]; then
    for pattern in "${SHM_PATTERNS[@]}"; do
        found=$(find /dev/shm -name "$pattern" 2>/dev/null)
        if [[ -n "$found" ]]; then
            echo "[Dry-run] 将删除共享内存文件: $found"
        fi
    done
else
    for pattern in "${SHM_PATTERNS[@]}"; do
        # 使用 -user 过滤避免权限警告,使用 sudo 确保彻底清理(可选)
        find /dev/shm -name "$pattern" -user "$(whoami)" -delete 2>/dev/null || true
    done
    echo "共享内存清理完成。"
fi

# 7. 附加操作:清理 ROS 2 锁文件与本地日志缓存 (可选)
if [[ "$DRY_RUN" -eq 0 ]]; then
    echo "清理本地节点锁文件..."
    rm -rf ~/.ros/log/* 2>/dev/null || true
fi

echo "=== 环境清理完成 ==="

第一遍运行该脚本后可能会报共享内存错误,再次直接运行该脚本,正常情况下会返回"=== 环境清理完成 ==="。

可以通过ros2 node list查看当前的ros2节点运行情况,正常情况下本机的ros2 node list应该返回空。

...全文
74 4 打赏 收藏 转发到动态 举报
写回复
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
江淼98 01-15 23:14
  • 打赏
  • 举报
回复
感谢分享
fanna123123 队员 01-14 21:48
  • 打赏
  • 举报
回复
🤩
Adnachiel03 队员 01-14 21:47
  • 打赏
  • 举报
回复

感谢分享

2301_80744354 助教 01-14 16:44
  • 打赏
  • 举报
回复

感谢分享!!👍

91

社区成员

发帖
与我相关
我的任务
社区描述
「智能机器人开发者大赛」官方平台,致力于为开发者和参赛选手提供赛事技术指导、行业标准解读及团队实战案例解析;聚焦智能机器人开发全栈技术闭环,助力开发者攻克技术瓶颈,促进软硬件集成、场景应用及商业化落地
机器人人工智能 高校
社区管理员
  • CSDN产品汪
  • Zachary_86
  • NO.2社区助手
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

「智能机器人开发者大赛」官方平台,致力于为开发者和参赛选手提供赛事技术指导、行业标准解读及团队实战案例解析;聚焦智能机器人开发全栈技术闭环,助力开发者攻克技术瓶颈,促进软硬件集成、场景应用及商业化落地