前言
- 上一期我们提到使用Systemd去处理wifi断连的自动重连服务
- 本期我们继续来谈一谈有关Systemd的另一个妙用:开机自启与看门狗日志服务
1 开机自启与自动重启
1-1 创建启动脚本
- 创建一个用于启动 ROS2 节点的 shell 脚本,用来统一配置环境并运行
ros2 run命令。
bash
nano /home/yourname/ros2_talker.sh
- 在
shell脚本中设置一些运行必须的环境变量- 注意这里使用
exec直接替换shell进程运行ROS2节点,避免额外子进程导致信号不一致问题。
- 注意这里使用
bash
#!/bin/bash
# ROS2 环境
source /opt/ros/humble/setup.bash
# 如果你有工作空间(没有可以删掉这一行)
# source /home/yourname/ros2_ws/install/setup.bash
# 防止乱码 / 日志更稳定
export ROS_DOMAIN_ID=0
export RCUTILS_COLORIZED_OUTPUT=0
# 启动 demo talker
exec ros2 run demo_nodes_cpp talker
- 给脚本添加可执行权限,使 systemd 或手动调用时可以直接运行。
bash
chmod +x /home/yourname/ros2_talker.sh
1-2 创建 systemd 服务
- 创建 systemd 服务文件,用于定义 ROS2 节点的启动方式与生命周期管理。
bash
sudo nano /etc/systemd/system/ros2-talker.service
- 内容如下:
INI
[Unit]
Description=ROS2 Talker Demo
After=network.target
[Service]
Type=simple
User=yourname
WorkingDirectory=/home/yourname
ExecStart=/home/yourname/ros2_talker.sh
# 自动重启
Restart=always
RestartSec=2
# 日志统一进入 systemd journal
StandardOutput=journal
StandardError=journal
# ROS2 常用环境变量
Environment=ROS_DOMAIN_ID=0
Environment=RCUTILS_LOGGING_USE_STDOUT=1
[Install]
WantedBy=multi-user.target
[Unit]:定义服务基本信息,用于描述服务名称、启动依赖关系等基础元数据- `Description:服务的描述信息,用于在 systemctl status 中显示该服务的用途说明
After=network.target:指定该服务在网络服务启动完成之后再启动,确保ROS2运行时网络环境已就绪
[Service]:定义服务的核心运行参数,包括启动方式、执行用户、进程管理与重启策略Type=simple:表示服务为简单类型,ExecStart启动的进程即为主进程,不创建子守护进程User:指定服务以XXX用户身份运行WorkingDirectory:设置服务运行时的工作目录
ExecStart=:指定服务启动时执行的脚本路径Restart=always:设置服务无论正常退出还是异常崩溃都会自动重启RestartSec=2:设置重启前等待 2 秒
StandardOutput=journal:将标准输出重定向到 systemd journal 日志系统统一管理StandardError=journal:将标准错误输出同样写入 journal,便于统一日志查看与调试Environment=ROS_DOMAIN_ID=0:设置 ROS2 通信域 ID,确保节点在同一 DDS 网络中通信Environment=RCUTILS_LOGGING_USE_STDOUT=1:强制 ROS2 日志输出到标准输出,避免日志分散或写入文件[Install]:定义服务的安装与启动目标,用于 systemctl enable 时的挂载关系WantedBy=multi-user.target:表示该服务会在系统进入多用户运行级别后自动启动(开机自启)
1-3 启动 + 设置开机自启
bash
sudo systemctl daemon-reload
sudo systemctl enable ros2-talker.service
sudo systemctl start ros2-talker.service

1-4 查看运行状态
- 查看服务当前运行状态,包括 PID、启动时间和日志摘要。
bash
systemctl status ros2-talker.service

1-5 查看日志
- 实时看日志
bash
journalctl -u ros2-talker.service -f

- 查看历史日志
bash
journalctl -u ros2-talker.service
1-6 自重启测试
- 我们先通过状态尝试获取本服务的
pid
bash
systemctl status ros2-talker

- 然后我们手动尝试杀死这个进程,并观察这个进程是否会自己复活:
bash
kill -9 9449

1-7 关闭服务
bash
sudo systemctl stop ros2-talker.service
1-8 删除服务
bash
sudo systemctl stop ros2-talker.service
sudo systemctl disable ros2-talker.service
sudo rm /etc/systemd/system/ros2-talker.service
2 看门狗
2-1 介绍
看门狗(Watchdog)是一种用于监控系统或程序运行状态的机制,当检测到异常、卡死或特定条件触发时,会自动执行恢复操作(如重启服务)- 一般分为几种:通常分为
硬件看门狗(芯片级自动复位系统)系统看门狗(systemd等守护机制)应用看门狗(程序内部心跳检测)日志看门狗(通过日志内容判断异常)
- 如果像这样无法修改程序源码的,可以做
日志看门狗补全:
当无法在程序内部加入 heartbeat 或监控逻辑时,可以通过监听
systemd journal或日志文件,基于关键字匹配的方式实现外部异常检测与自动重启机制
- 值得说的是
Restart=always/Restart=on-failure本质是 systemd 自带的进程级看门狗(Process Watchdog),但它只覆盖"进程层面",不等于完整看门狗体系。
2-2 看门狗脚本
- 创建看门狗脚本文件,用于监听 ROS2 服务日志并在触发条件时执行自动重启逻辑。
bash
nano /home/yourname/ros2_grep_watchdog.sh
- 核心内容就是
实时监听 systemd 服务日志,并逐行读取输出内容,判断当前日志是否包含触发关键字,不匹配则跳过处理。
bash
#!/bin/bash
SERVICE="ros2-talker.service"
PATTERN='Hello World: 50'
LAST_LINE=""
COOLDOWN=5
LAST_RESTART_TIME=0
journalctl -u "$SERVICE" -f --no-tail | while read -r line
do
echo "$line"
# 只匹配关键字
if [[ "$line" != *"$PATTERN"* ]]; then
continue
fi
# 去重:完全相同日志不重复触发
if [[ "$line" == "$LAST_LINE" ]]; then
continue
fi
LAST_LINE="$line"
NOW=$(date +%s)
# 冷却时间防抖
if (( NOW - LAST_RESTART_TIME < COOLDOWN )); then
echo "[WATCHDOG] cooldown active, skip restart"
continue
fi
LAST_RESTART_TIME=$NOW
echo "[WATCHDOG] trigger restart → $SERVICE"
sudo systemctl restart "$SERVICE"
done
2-3 看门狗服务
- 创建 systemd 服务文件,用于将 watchdog 脚本注册为系统守护进程。
bash
sudo nano /etc/systemd/system/ros2-log-watchdog.service
- 和上面一样,这里就不解释了
bash
[Unit]
Description=ROS2 Log Watchdog
After=network.target
[Service]
ExecStart=/home/yourname/ros2_grep_watchdog.sh
Restart=always
RestartSec=1
User=yourname
[Install]
WantedBy=multi-user.target
2-4 权限添加
- 由于看门狗服务在检测到特定关键词后重启服务时需要
sudo权限,为了避免该服务在后台运行时候没法请求用户手动输入密码,我们需要配置免密权限来防止该服务执行失败。 - 打开 sudoers 的独立配置文件,用于给特定用户添加受控的免密权限,避免直接修改
/etc/sudoers导致系统风险。
bash
sudo vim /etc/sudoers.d/ros2-watchdog
- 允许用户
lzh在不输入密码的情况下执行指定的systemctl restart ros2-talker.service命令,因为看门狗脚本是在 systemd 后台运行的,没有 TTY 交互能力,无法手动输入密码,如果不配置免密权限就会导致 watchdog 在触发重启时卡死或失败。
bash
lzh ALL=(ALL) NOPASSWD: /bin/systemctl restart ros2-talker.service
2-5 启用服务
bash
sudo systemctl daemon-reload
sudo systemctl enable ros2-log-watchdog
sudo systemctl start ros2-log-watchdog

2-6 观察日志
- 通过观察日志我们可以看到,当检测到
'Hello World: 50'时,看门狗服务会自动重启服务
bash
journalctl -u ros2-log-watchdog.service -f

2-7 关闭服务
bash
sudo systemctl stop ros2-log-watchdog.service
总结
- 本文通过 systemd 实现 ROS2 节点的开机自启与自动重启,并结合日志监听脚本构建外部看门狗机制,在无法修改源码的情况下实现基础级运行监控与故障恢复。
- 如有错误,欢迎指出!
- 感谢支持!
