功能
只是想给无人机挂载一个外置硬盘,然后录制数据包到这个外置硬盘里面,方便后续模拟和评估啥的;
这个硬盘是开机挂载,但是录完后直接拆下来,所以不能直接把开机挂载写到fstab里面;
重要参考
挂载和录制脚本
在home目录下建一个bin文件夹,然后创建这个录制脚本
mkdir -p bin
cd bin
nano record_to_mount.sh
脚本内容
#!/bin/bash
set -euo pipefail
# 简易录制脚本(中文注释)
# 使用说明:
# - 本脚本为简化版,已将必要配置写死到脚本中(部署前请编辑下面的固定项)。
# - 启动流程:等待 -> 尝试挂载指定设备 -> 若挂载成功,开始 `rosbag record -a` 并按 SIZE_MB 切分文件;若挂载失败则退出不录制。
# - 注意:挂载通常需要 root 权限,建议通过 systemd 或在含有合适权限的环境下运行。
# - 设备支持形式:直接设备路径(/dev/sda1)或 UUID=xxxx 或 LABEL=NAME。
# --- 固定配置(部署前请修改这些值) ---
DEVICE="UUID=ABCD-1234" # 示例:UUID=1234-ABCD 或 /dev/sda1 或 LABEL=MYUSB
MOUNT_POINT="/mnt/record" # 挂载点目录
OUT_SUBDIR="rosbags" # 挂载盘内用于保存 bag 的子目录
SIZE_MB=1024 # 切分大小(MB),默认 1024
WAIT_SECONDS=10 # 启动后等待秒数
BACKGROUND=${BACKGROUND:-1} # 1=后台运行;0=前台运行 (可由环境变量覆盖)
DRY_RUN=${DRY_RUN:-0} # 1=仅打印命令(不执行挂载/录制)
echo "等待 ${WAIT_SECONDS}s,准备挂载..." >&2
sleep "$WAIT_SECONDS"
# Resolve DEVICE to a path mount can use
device_path="$DEVICE"
if [[ "$DEVICE" == UUID=* ]]; then
uuid=${DEVICE#UUID=}
device_path="/dev/disk/by-uuid/$uuid"
elif [[ "$DEVICE" == LABEL=* ]]; then
label=${DEVICE#LABEL=}
device_path="/dev/disk/by-label/$label"
fi
mkdir -p "$MOUNT_POINT"
if command -v mountpoint >/dev/null 2>&1 && mountpoint -q "$MOUNT_POINT"; then
echo "Mount point $MOUNT_POINT already mounted." >&2
else
echo "Attempting mount: $device_path -> $MOUNT_POINT" >&2
if ! mount "$device_path" "$MOUNT_POINT" 2>/dev/null; then
echo "Mount failed: $device_path -> $MOUNT_POINT. Aborting recording." >&2
exit 3
fi
fi
# 载入 ROS 环境(如果存在),放在挂载成功后执行;失败不致命
hostip=`hostname -I | awk -F " " '{print $1}'`
if [[ ! -z $hostip ]]; then
#hostip=192.168.2.20
echo HOST_IP:$hostip
export ROS_IP=$hostip
fi
if [ -f /home/visbot/ros_ws/install/setup.bash ]; then
set +u
source /home/visbot/ros_ws/install/setup.bash || true
set -u
elif [ -f /home/visbot/ros_ws/devel/setup.bash ]; then
set +u
source /home/visbot/ros_ws/devel/setup.bash || true
set -u
fi
OUT_DIR="${MOUNT_POINT%/}/$OUT_SUBDIR"
mkdir -p "$OUT_DIR"
timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
outfile_prefix="$OUT_DIR/${timestamp}_record"
cmd=(rosbag record -a --split --size="$SIZE_MB" -O "$outfile_prefix")
if [ "$DRY_RUN" -eq 1 ]; then
echo "DRY RUN: would mount: $device_path -> $MOUNT_POINT" >&2
echo "DRY RUN: output dir: $OUT_DIR" >&2
echo "DRY RUN: command:" >&2
printf '%q ' "${cmd[@]}"; echo; echo
exit 0
fi
echo "Starting recording to: $outfile_prefix*.bag (split ${SIZE_MB}MB)" >&2
if [ "$BACKGROUND" -eq 1 ]; then
logfile="$OUT_DIR/${timestamp}.log"
nohup "${cmd[@]}" >"$logfile" 2>&1 &
pid=$!
echo "$pid" > "$OUT_DIR/${timestamp}.pid"
echo "Recording started in background (pid: $pid), log: $logfile" >&2
else
exec "${cmd[@]}"
fi
开机自启动脚本
同样在bin下建立record-rostopics.service文件,内容为
# Example systemd unit to start the recorder at boot.
# Edit the Environment lines and ExecStart path as needed before deploying to the UAV.
[Unit]
Description=Record ROS topics to external mount
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# Run as root to allow mounting the device. If you mount in fstab, you can change User.
User=root
# 在同一 shell 中先加载 ROS 环境,再运行脚本,确保 rosbag 能找到消息类型与 Master
Environment=BACKGROUND=0
ExecStart=/bin/bash -lc 'source /home/visbot/ros_ws/install/setup.bash 2>/dev/null || true; source /home/visbot/ros_ws/devel/setup.bash 2>/dev/null || true; exec /bin/bash /home/visbot/bin/record_to_mount.sh'
Restart=on-failure
RestartSec=5
TimeoutStartSec=0
# 发送 SIGINT 以便 rosbag 优雅关闭并 flush 文件
KillSignal=SIGINT
TimeoutStopSec=30
# 停止后尝试同步并卸载(忽略错误),避免拔盘时数据未写入
# ExecStopPost=/bin/sync
# ExecStopPost=/bin/umount -l /mnt/record || true
[Install]
WantedBy=multi-user.target
复制到指定目录
sudo cp ./record-rostopics.service /etc/systemd/system/
尝试重启服务,在命令行分别执行
systemctl daemon-reload
sudo systemctl enable record-rostopics.service
systemctl start record-rostopics.service # 多次重启测试的话用restart
systemctl status record-rostopics.service
最后一个命令打印
record-rostopics.service - Record ROS topics to external mount
Loaded: loaded (/etc/systemd/system/record-rostopics.service; disabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Sat 2021-01-02 12:37:33 CST; 100ms ago
Process: 61380 ExecStart=/home/visbot/bin/record_to_mount.sh (code=exited, status=203/EXEC)
Main PID: 61380 (code=exited, status=203/EXEC)
检查是否成功挂载,敲入df -h,多出了一行
/dev/sda 938G 31G 860G 4% /mnt/record
进入目标目录看是否录制
cd /mnt/record/rosbags
ls
看到类似2021-01-02_16-34-28_record_0.bag.active的文件名就说明成功录制了。