做机器人开发这几年,我一直被一个问题反复折磨:好不容易搭好的 ROS 开发环境,经常因为一次系统更新、一个依赖冲突,或者换台机器,就彻底崩掉。重新装一遍又得折腾大半天,尤其是跑仿真、调试驱动、调参数的时候,这种挫败感特别强烈。后来我花了些时间,把 Docker、tmux 和 ROS 这套组合彻底捋顺了,才算是真正解决了这个痛点。这篇内容就是我从零开始搭建这套持久化机器人开发环境的完整记录,会详细拆解为什么是这三样工具、每一步怎么落地、以及我踩过的那些坑。
这套环境适合谁?主要是正在用 ROS 1/ROS 2 做机器人开发的人,不管你是做算法仿真、跑真机,还是开发机械臂控制逻辑,只要你觉得“环境搭建比写代码还累”,那这套方案就很值得参考。它解决的核心问题有三个:环境隔离、会话持久、随时可复现。简单说,就是让你不再被环境折腾,把精力真正花在机器人算法和业务逻辑上。
1. 整体设计拆解:为什么偏偏是这三样工具
很多刚开始接触机器人开发的人会问:ROS 本身不就能管理节点吗?为什么还要叠一个 Docker 和 tmux?其实这三样东西解决的问题完全不同,配合起来才是真正完整的开发体验。
1.1 机器人开发环境最让人头疼的是什么
开发环境这件事,对机器人开发者来说比普通 Web 开发要麻烦得多。ROS 的版本和 Ubuntu 系统版本是强绑定的,比如 ROS 2 Humble 对应 Ubuntu 22.04,ROS 1 Noetic 对应 Ubuntu 20.04,这意味着你没法在一台机器上轻易地同时跑多个 ROS 版本。而机器人项目往往又很复杂,一个完整的系统里通常要装几十个依赖包,每个包的版本稍微有偏差,编译或者运行时就会出现一堆莫名其妙的问题。
我印象最深的一次,是在一个老项目里需要用到特定版本的 OpenCV,结果和系统自带的版本冲突,我为了让整个项目能编译通过,连着折腾了两天,最后还把系统搞崩了,不得不重装。那之后我就下定决心,一定要把环境和代码彻底隔离开。Docker 正好就是干这个的,它能把整个操作系统级别的依赖环境打包成一个镜像,放到哪台机器上都是完全一致的。
除了环境问题,还有一个隐性痛点就是会话断连。机器人开发经常要在一台开发机上长时间跑训练、跑建图算法、跑后台服务,可能一个任务要跑几个小时甚至一晚上。如果直接用普通的 SSH 连接执行命令,网络稍微一抖,进程就断了,前面的工作全部白做。这个问题 tmux 可以完美解决,它能让你的会话在后台保持运行,断开重连之后一切如初。
1.2 Docker 在机器人开发中的核心价值
Docker 在机器人开发里的价值,很多人只看到了“环境隔离”这一层,但实际上它比你想象得更重要。先说隔离,你的 ROS 项目不再依赖宿主机上那套已经装好一大堆乱七八糟包的全局环境,每个项目都有自己独立的文件系统、库依赖、环境变量,互不干扰。
再就是可复现性。你可以在 Dockerfile 里把整个环境的构建过程写清楚,包括基础镜像、ROS 版本、依赖包、编译选项,等需要换机器或者重新部署的时候,一句 docker build 就能把整套环境重建出来。这个过程是确定性的,不会再出现“在我电脑上明明是好的”这种情况。
还有一个很关键的价值是团队协作。以前同事之间传项目,经常要附带一大段环境配置说明,每个人装的依赖还不一样,跑起来效果就千奇百怪。现在直接维护一个基础镜像,大家从同一个镜像启动容器,跑出来的结果就基本一致了,节省了大量的沟通成本。
1.3 tmux 解决的是“会话持久”这个被低估的问题
tmux 是一个终端复用器,它能让你在一个终端窗口里开多个会话,每个会话里可以开多个窗口和窗格,而且这些会话都是后台运行的。最核心的能力是,即使你关掉终端、断开 SSH,会话依然在服务器上继续跑,下次重新连上,执行 tmux attach 就能回到之前的状态。
机器人开发的工作模式特别适合 tmux。举个例子,你要在一个终端里启动机器人底层驱动节点,在另一个终端里启动导航算法,在第三个终端里查看可视化数据。用 tmux 开一个会话,分成三个窗格,一个窗格跑一个模块,鼠标点一下就能切换,特别清晰。更重要的是,如果中途你想要暂时离开,可以直接 detach 会话,让它继续在后台跑,回来看结果就行。
1.4 三者结合起来的工作逻辑
这三样工具结合起来,其实是形成了一条完整的工作流水线。Docker 负责提供稳定的运行环境,你在容器里编译也好、运行仿真也好,都不会污染宿主机;tmux 负责提供持久的工作界面,你启动的那些终端任务不会因为网络或操作失误而中断;ROS 则是整个机器人系统的软件框架,负责把各个模块 —— 驱动、感知、规划、控制 —— 组装成完整的系统。
实际用起来,你会先在宿主机上启动 Docker 容器,然后在容器里面启动一个 tmux 会话,之后所有的日常工作都在这个 tmux 会话里完成。你可以随时离开,随时回来继续,而你做实验的环境始终都在那里等着你。这套组合的体验用一句话概括就是:一切都在掌控之中,不担心丢失,不担心污染,不担心环境变了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建实操:从宿主机到 ROS 容器的完整过程
接下来讲具体的搭建过程。我会以 Ubuntu 22.04 + ROS 2 Humble 为例来演示,这套流程对 Ubuntu 20.04 + ROS 1 Noetic 也同样适用,原理和步骤基本一致。
2.1 宿主机准备:安装 Docker 并配置镜像源
在我们把 Docker 请进机器人开发流程之前,先得把它装好。Ubuntu 系统上安装 Docker 比较简单,官方提供了可以直接用的脚本,也可以手动添加仓库来装。我个人比较推荐手动添加仓库的方式,因为可控性更强,能知道每一步在干什么。
bash复制# 安装必要的依赖包
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
# 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 添加 Docker 软件源
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
装完 Docker 之后一定要把当前用户加入 docker 用户组,不然每次执行 docker 命令都要加 sudo,很麻烦。
bash复制sudo usermod -aG docker $USER
newgrp docker
这里有个实际情况要说明。Docker Hub 在国内访问经常很慢,甚至拉不下来镜像,这时候就需要配置镜像加速器。编辑 /etc/docker/daemon.json 文件,把镜像源地址填进去:
json复制{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.nju.edu.cn"
]
}
修改完重启 Docker 服务生效:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
然后执行 docker info 查看配置是否生效。在 Registry Mirrors 那一栏能看到你填的地址就说明成功了。
提示:镜像加速源并不是绝对可靠的,有些公共源会不定期失效或者限速。如果你发现拉取镜像很慢,可以换个源试试。另外,在企业内网环境,通常会有自建的镜像仓库,直接配置成内网地址会更快更稳。
2.2 ROS 2 Humble 基础镜像与容器创建
Docker 装好之后,接下来的重头戏就是创建 ROS 环境镜像。ROS 官方镜像在 Docker Hub 上有,但是官方镜像比较精简,只包含 ROS 的核心包,很多常用的工具和依赖都没有,比如编译工具 colcon、可视化工具 rviz2、调试工具等,这些都需要自己额外装。
我通常会基于官方镜像写一个 Dockerfile,把常用工具一次性装好,形成一个适合自己开发习惯的“基础开发镜像”。下面是一个让我用得比较顺手的 Dockerfile 示例:
dockerfile复制# 基于 ROS 2 Humble 桌面版镜像
FROM ros:humble-desktop
# 设置环境变量,避免交互式问答
ENV DEBIAN_FRONTEND=noninteractive
# 换软件源(国内开发环境建议使用)
RUN sed -i 's@archive.ubuntu.com@mirrors.aliyun.com@g' /etc/apt/sources.list && \
sed -i 's@security.ubuntu.com@mirrors.aliyun.com@g' /etc/apt/sources.list
# 更新软件源并安装常用的开发工具
RUN apt-get update && apt-get install -y \
git \
vim \
nano \
curl \
wget \
net-tools \
htop \
python3-pip \
python3-colcon-common-extensions \
python3-rosdep \
python3-vcstool \
build-essential \
cmake \
gdb \
tmux \
&& rm -rf /var/lib/apt/lists/*
# 初始化 rosdep
RUN rosdep init || true && \
rosdep update || true
# 设置工作目录
WORKDIR /workspace
# 设置环境变量
RUN echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
Dockerfile 写好后,在同一个目录下执行构建命令:
bash复制docker build -t ros2_humble_dev:latest .
注意这个构建过程会持续一段时间,因为要下载很多依赖包,尤其是当你还额外安装了 gazebo、navigation2 这些大体积库的时候,慢一点是很正常的。构建完成的镜像大小通常在 3GB 以上,所以磁盘空间要提前准备好。
2.3 容器启动的关键参数与数据持久化
环境镜像准备好之后,接下来的核心问题就是:怎么启动这个容器才最合适?我见过很多人直接 docker run -it ros2_humble_dev,跑起来发现各种问题 —— 没有图形界面、不能联网、退出容器代码就丢了。下面这几个参数是我经过反复测试后总结出来的关键配置。
先看完整启动命令:
bash复制docker run -it \
--name ros2_dev \
--hostname ros-dev \
--network host \
--ipc host \
--gpus all \
--device /dev/dri \
-e DISPLAY=$DISPLAY \
-e QT_X11_NO_MITSHM=1 \
-e LIBGL_ALWAYS_INDIRECT=0 \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-v /dev:/dev \
-v ~/workspace:/workspace \
ros2_humble_dev:latest \
/bin/bash
逐项说明一下关键参数:
--network host 指容器直接复用宿主机的网络栈。在机器人开发场景下,经常需要和同一局域网下的硬件设备通信,比如机械臂控制柜、激光雷达、相机,这些设备通常通过 IP 地址和端口访问。默认的 bridge 网络模式会做 NAT 转换,经常导致发现不了设备或者通信超时。用 host 模式能省掉很多网络排查的麻烦。
-v /dev:/dev 是把宿主机的设备文件透传给容器,这样容器里面就能直接访问串口、USB 摄像头等硬件设备。这个对机器人开发至关重要,不然你连激光雷达的数据都读不到。
-v ~/workspace:/workspace 是数据持久化的核心。把宿主机的一个目录挂载到容器的工作目录,这样你在容器里写的代码、保存的文件,其实都存在宿主机上。即使容器被删除,代码也完好无损。
-e DISPLAY=$DISPLAY 和 -v /tmp/.X11-unix:/tmp/.X11-unix:rw 是为了让容器里的 GUI 程序能显示到宿主机屏幕上。比如你要在容器里启动 rviz2 或者 gazebo,就需要这两行配置。
--gpus all 在装有 NVIDIA 显卡的机器上,把 GPU 能力透传给容器。跑一些视觉识别、点云处理或者 ORB-SLAM 之类的算法时,有 GPU 加速会快很多。
注意:--device /dev/dri 是 Intel/AMD 核显设备透传的常用写法,NVIDIA 独显场景下主要用 --gpus all。如果你电脑的显卡比较特殊,可能需要额外调整。
2.4 工作目录与代码管理的持久化策略
说到持久化,这是这套环境最核心的卖点之一。很多新手容易犯一个错误:直接 docker run 之后就在容器里写代码,结果不小心退出容器,代码全丢了。正确的做法是把代码目录挂载出来,让容器只是一个“运行环境”,而不是“存储设备”。
我个人的目录规划是这样的:
bash复制~/workspace/
├── projects/ # 各个 ROS 项目的工作空间
│ ├── robot_nav/ # 导航相关项目
│ ├── robot_arm/ # 机械臂相关项目
│ └── alg_test/ # 算法验证项目
├── data/ # 数据集、bag 包、日志
└── scripts/ # 常用脚本工具
然后把整个 ~/workspace 挂载到容器的 /workspace。这样你在容器里的所有文件、代码、编译产物,其实都保存在宿主机上。哪怕容器删了重建,代码也都还在,重新启动一个容器挂载同一个目录就能接着干活。
还有一个容易被忽略的细节是用户权限。默认情况下,Docker 容器里的用户是 root,这会导致一个问题:你在容器里创建的文件,在宿主机上看到的属主是 root,而你自己的账号可能没有权限去修改它们。这个问题有两种解法,一种是在启动容器时用 -u $(id -u):$(id -g) 指定当前用户,但这种方式在容器里安装软件时会遇到权限问题;另一种是接受 root 身份,遇到宿主机操作文件时临时用 sudo 处理。我个人推荐在容器里开发用 root 身份,日常代码提交都在容器里做,宿主机的操作尽量少,这样最省心。
如果你希望二者兼顾,可以在 Dockerfile 里创建和你宿主机 UID 一样的用户,然后默认用这个用户运行容器。这一步稍微麻烦点,但体验也会更好。
3. tmux 实战:机器人开发中的终端管理方案
环境容器搞定后,接下来就是终端管理层的重头戏。Docker 解决了环境问题,但如果你直接在容器里跑多任务,很快就会遇到一个新的困境——管理混乱。
3.1 tmux 基础操作与思维模型
tmux 的思维模型其实特别好理解,你可以把它想象成在家里客厅装了很多块电视屏幕,各自显示不同的频道,而你自己坐在沙发上遥控切换。tmux 中的每一个“会话”(session)就是一台电视,一个会话里可以有多个“窗口”(window),每个窗口又可以被拆分成多个“窗格”(pane)。
基础命令我都列出来:
bash复制# 新建会话
tmux new -s dev
# 分离会话(进程继续在后台跑)
tmux detach # 或者快捷键 Ctrl+b d
# 查看所有会话
tmux ls
# 重新连接会话
tmux attach -t dev
# 在当前会话中新建窗口
Ctrl+b c
# 切换窗口
Ctrl+b 数字键
# 水平拆分窗格
Ctrl+b "
# 垂直拆分窗格
Ctrl+b %
# 窗格之间切换
Ctrl+b 方向键
使用 tmux 后,你的终端就再也不会因为断网而中断工作流了。我把 tmux 比作“时空穿梭器”,是你的工作现场的保存点——任何时候你离开,回来时都还是原来的样子。
3.2 机器人开发的标准 tmux 工作流模式
在实际的机器人项目中,我们通常需要同时运行多个 ROS 节点,我摸索出一套比较顺手的工作流模式。下面以跑一个 ROS 2 小车导航仿真为例来说明。
启动 Docker 容器后,进入容器,先创建一个名字叫 nav 的会话:
bash复制tmux new -s nav
在这个会话中,先按 Ctrl+b % 垂直拆分成左右两个窗格,再在左侧窗格按 Ctrl+b " 水平拆分成上下两个窗格。总共是三个窗格,可以分别用来运行三个不同的节点进程。
在第一个窗格启动 Gazebo 仿真环境:
bash复制ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
在第二个窗格启动导航算法:
bash复制ros2 launch turtlebot3_navigation2 navigation2.launch.py
在第三个窗格用来执行命令,比如发布目标点:
bash复制ros2 run turtlebot3_teleop teleop_keyboard
如果你中途要离开,直接 Ctrl+b d 分离会话。这个时候三个进程都在继续跑,过了两个小时回来,你会发现仿真还在正常进行,导航结果也都在日志里等着你。这是普通的终端完全做不到的。
3.3 tmux 的持久化与跨机器使用技巧
tmux 还有一个让人惊喜的能力是跨机器恢复。举个例子,你白天在公司开发机上的 tmux 会话里跑着一个长时间的建图任务,回家之后你想继续观察任务状态,只要重新 SSH 连接开发机,然后 tmux attach -t 会话名,就能看到和离开时完全一样的界面。
另外我强烈建议装 tmux-resurrect 和 tmux-continuum 这两个插件。tmux-resurrect 能保存当前的所有窗格布局、执行的命令,重启机器之后一键恢复;tmux-continuum 更进一步,每隔一段时间自动保存状态。装了这两个插件之后,即使开发机意外重启,你也能在几分钟内把之前的工作现场恢复回来。
提示:tmux 的恢复能力有一个前提条件——你运行的程序必须是在 tmux 会话里启动的。如果你在 tmux 外面直接启动了一个进程,然后才打开 tmux,那这个进程仍然不属于任何会话,断连时照样会被杀掉。
4. 完整工作流串联:从一键启动到日常调试
环境搭建到这里,已经有了两个独立的工具块。这一节我会讲清楚怎么把它们串联成真正可用的日常工作流,包括一键启动脚本、代码编译部署循环、以及远程操作技巧。
4.1 一键启动脚本:把复杂的 docker run 封装起来
每次都要手动敲那一长串 docker run 参数实在不现实,所以我把启动过程封装成了一个 shell 脚本,放在 ~/workspace/scripts/ 目录下,供所有项目共用。
bash复制#!/bin/bash
# 文件名: start_ros_dev.sh
WORKSPACE_DIR=~/workspace
CONTAINER_NAME="ros2_dev"
# 如果容器已存在,直接进入
if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then
docker start -ai $CONTAINER_NAME
exit 0
fi
# 否则创建新容器
docker run -it \
--name $CONTAINER_NAME \
--hostname ros-dev \
--network host \
--ipc host \
--gpus all \
--device /dev/dri \
-e DISPLAY=$DISPLAY \
-e QT_X11_NO_MITSHM=1 \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-v $WORKSPACE_DIR:/workspace \
ros2_humble_dev:latest \
/bin/bash
每台机器上第一次使用时运行:
bash复制chmod +x start_ros_dev.sh
./start_ros_dev.sh
之后的每一天,不管你是刚开机、还是容器被某个操作意外关闭,一条命令就能恢复到之前的工作状态。docker start -ai 会启动已经存在的容器并且直接挂载进去,非常高效。这里还有个隐藏收益:因为容器的文件系统是持久化的,你在容器里安装的额外工具、编译的中间产物、rosdep 缓存,下次启动时全部还在,不需要重新装一遍。
4.2 日常开发循环:写代码、编译、运行、调试
环境稳定之后,日常的开发循环就变得特别流畅。拿一个典型场景举例:我需要在已有的导航项目里加一个路径平滑算法。
打开终端,执行 start_ros_dev.sh 进入容器,启动 tmux 会话,进入项目目录:
bash复制tmux new -s nav
cd /workspace/projects/robot_nav
用 vim 或者 VSCode Remote 打开代码,修改完保存后,在 tmux 的一个窗格里执行编译:
bash复制colcon build --symlink-install
编译通过后,source 一下环境:
bash复制source install/setup.bash
然后在另一个窗格运行程序,第三个窗格打开可视化工具查看效果。整个过程都在一个 tmux 会话里完成,窗口切换、日志回看、进程管理都异常顺手。
还有一点,在容器里跑 ROS 2 时,如果遇到 DDS 通讯问题,大多是网络发现机制导致的。使用 --network host 模式后,这个问题基本不会出现,因为容器和宿主机共享网络栈,DDS 的组播发现能正常工作。
4.3 多设备协同:宿主机与容器混合部署
实际项目中还有一个常见场景:宿主机上连着实体机器人或传感器,需要和容器里的 ROS 环境协同工作。比如宿主机上跑着官方的相机驱动 SDK,而你的算法在容器里。
这种场景的推荐做法是在宿主机上做一个轻量的转发节点,把相机数据转成 ROS 话题后发布到网络,容器里的 ROS 节点再订阅这个话题。用 host 网络模式时,这个话题通讯可以走 localhost,延迟几乎可以忽略。
还有一种更简单的方案,是直接在宿主机上同时安装 ROS 客户端,这样宿主机和容器之间可以互相发现对方的话题。但这种方式会引入版本冲突风险,我一般只在临时调试时这么用,平时的主力开发都在容器里完成,宿主机尽量保持干净。
5. 常见问题排查与避坑清单
任何一套方案在实际使用中总会遇到各种问题。下面我把这几年用 Docker + tmux + ROS 踩过的坑、排查过的典型问题整理出来,希望能帮你少走一些弯路。
5.1 Docker 侧问题排查
| 问题 | 可能原因 | 排查思路与解决方案 |
|---|---|---|
| 镜像拉取卡住或超时 | 镜像源不稳定或 Docker Hub 连接超时 | 更换/添加多个 registry-mirrors;重试或使用代理镜像地址;也可以找同事要一份已导入的镜像 tar 包 |
| 容器启动后没有网 | 部分镜像内默认配置问题或 daemon 代理设置互斥 | 优先使用 --network host;检查 /etc/docker/daemon.json 是否有 HTTP_PROXY 干扰;用 docker inspect 查看网络模式 |
| 容器里不能显示 GUI | DISPLAY 未传入,X11 套接字未挂载 | 检查 -e DISPLAY;挂载 /tmp/.X11-unix;宿主机执行 xhost +local: 允许本地容器连接 |
| 容器里打开摄像头黑屏 | 设备权限或驱动库缺失 | 挂载 -v /dev:/dev;容器内安装 v4l-utils;确认宿主机摄像头工作正常 |
| 容器占磁盘空间越来越大 | 镜像、构建缓存、容器数据叠加 | 定期 docker system prune -a 清理;日志写挂载盘;build 时用 --cache-from 复用镜像 |
排查 Docker 问题时有个通用的思路:先把问题最小化。比如 GUI 显示不出,就先运行一个最简单的 xclock 或 xeyes 测试基本 X11 通道通不通,再逐层排查是不是 ROS 程序本身的问题。这个方法能节省大量排障时间。
5.2 tmux 侧常见问题与操作技巧
tmux 本身稳定性不错,但用久了还是有几个典型问题。最常见的场景是:SSH 断开了,重新连接后发现之前的 tmux 会话丢了。排查方法是先 ps aux | grep tmux 看进程是否还在,如果进程还在但 tmux ls 看不到会话,多半是 tmux 服务端口冲突或环境变量异常,可以尝试用 tmux -L 指定不同的 socket 名称。
还有一个老手都踩过但新手不知道的坑:tmux 进入复制模式后,鼠标滚轮会变成"滚动历史记录",不再向上滚动终端输出。初期会觉得很别扭,其实是 tmux 的默认行为。你可以在 ~/.tmux.conf 里配置鼠标模式:
bash复制# 启用鼠标支持,滚轮直接查看历史
set -g mouse on
# 调整前缀键等待时间
set -sg escape-time 20
# 使用 Ctrl+a 作为前缀键,避免和 Ctrl+b 冲突
set -g prefix C-a
配置完成后 Ctrl+b :source-file ~/.tmux.conf 立即生效。个人强烈建议把前缀键改成 Ctrl+a,因为 Ctrl+b 在一些终端工具里绑定了别的功能,用起来很容易冲突。
5.3 综合场景:容器重启后环境不完整怎么办
再一个常见的问题是,容器在运行过程中进入了一个“半坏”状态。比如你在容器里 apt install 到一半网络断了,或者某个进程把 /opt/ros 下的文件弄坏了,容器虽然能启动,但是 ROS 环境明显不正常。这时候与其花时间修,不如彻底重建容器。
好在代码和数据都挂载在宿主机上,重建成本非常低。你只需要把旧容器删除,再用 start_ros_dev.sh 重新跑一遍。因为基础镜像 ros2_humble_dev 还在本地,几秒钟就能进入一个全新的环境。那些在容器里临时安装的工具会丢失,但这些本来就是一次性的,丢失了也不可惜。如果某次你确实需要在容器里装一批较大的依赖,那就把这些安装步骤写进 Dockerfile 里,下次直接构建镜像就有了。
5.4 一定要提前规划好的几个细节
有几个影响长期使用体验的细节,我建议在第一次搭环境时就规划好。
第一,磁盘空间分区。Docker 默认把镜像和容器文件放在 /var/lib/docker,如果你的系统盘比较小,建议把 Docker Root Dir 挪到大分区下。在 /etc/docker/daemon.json 里配置:
json复制{
"data-root": "/data/docker"
}
改完重启 Docker,旧镜像需要重新导入。
第二,日志管理。ROS 节点默认会把日志写到 ~/.ros/log,时间长了会积累很多文件。我的做法是把日志目录重定向到挂载盘:
bash复制export ROS_LOG_DIR=/workspace/data/ros_logs
这样日志、bag、数据文件都在一个地方,方便统一管理和清理。
第三,如果你经常需要给容器加设备、加端口,建议写一个 docker-compose.yml 来管理容器配置。用 compose 的好处是配置可视化、易维护,一个 docker compose up 就能重新创建容器。但对于单容器场景,用一个 shell 脚本反而更简单直接,看个人习惯。
写在最后
这套 Docker + tmux + ROS 的组合,我用了三年多,从 ROS 1 用到 ROS 2,从室内小车用到户外无人车,从单机仿真到多机联调,带给我最大的收益不是“环境干净”这种表面的好处,而是那种“想折腾就折腾、想回退就回退”的底气。我再也不用因为一个环境的调整而畏首畏尾,也不用再担心一觉醒来跑了半天的任务因为会话断开白白丢失。
如果你正被 ROS 环境的各种问题折磨得心烦,我建议你花一个周末的时间把这套环境搭起来。Docker 的隔离、tmux 的持久、加上你的代码管理习惯,一旦这三样真正配合起来,你感受到的不仅仅是效率提升,而是一种完完全全不同的开发节奏。还是那句话——把环境搞定,然后安心写你的算法和代码。
