不知道阅读本篇文章的你有没有被环境配置搞的焦头烂额过?
想要验证一个功能包,但却需要安装各种依赖。装就装吧!但是安装的依赖可能更新本机中的一些配置或软件版本,导致过去可以运行的软件这么折腾一下后就不能再运行了。
这时可能又后悔又懊恼。严重的可能要重新安装电脑系统。
本文描述了一种在Docker环境中开发和调试ROS程序的方法。旨在解决环境配置和软件依赖给我们带来的困扰。
我们使用Docker+Vscode来构建开发环境。下面的操作在Ubuntu 20.04 LTS上验证过。对于其他操作系统,操作步骤应该也是一致的。
安装Docker
按照下面的命令安装Docker。
1 | # step 1: 安装必要的一些系统工具 |
安装Vscode和插件
vscode的安装就不多说了。
需要安装的插件是Remote Containers。可按下图操作。

在插件市场中搜索Remote Containers并安装就可以看到左侧的Docker标志和左下角的图标。
开发环境示例
- 下载开发环境示例
1 | git clone https://github.com/shoufei403/ros2_galactic_ws.git |
- 在本机打开开发环境
1 | cd ros2_galactic_ws |
- 导入工程代码
在文件夹中的demos.repos中维护了需要导入的工程代码。可根据需求自行修改。目前里面是放的自己收集整理的ROS2示例代码。
导入工程代码是通过运行vscode的task来进行的。task的内容维护在.vscode/tasks.json文件中。

按照上图所示,按快捷键Ctrl+Shift+P打开命令面板。选中Run Task将可以看到.vscode/tasks.json文件中维护的各项task。

如上图,选中import from workspace file任务即可导入demos.repos文件中维护的工程代码。如果后面需要更新工程代码则可再次运行import from workspace file任务。
- 在
docker中重新打开环境

第一次打开时会下载docker镜像需要一段时间。后来再打开开发环境就是秒开了。

安装依赖
运行
install dependencies任务可以根据工程代码安装相应的依赖。但有些依赖可能还是要手动安装。如果install dependencies任务运行报错,则可以根据报错信息手动安装依赖。编译工程代码
运行
build任务即可编译。你也可以设置快捷键来对应build任务。
另外,全局搜索时需要注意一下设置。如果files to exclude为空,并且后面的图标按钮被选中,则只会在打开的文件中搜索。

另外,在.gitignore文件中默认是加入了src文件夹的。所以在vscode中的文件浏览器中src目录的文件是灰色显示的。并且vscode中的git工具也会忽略src目录的git信息。

所以平时编辑代码的时候可以注释一下.gitignore文件中的src。然后推这个工作空间的修改时再把.gitignore文件中的src加上。
在Docker中运行GUI应用
devcontainer.json 中的 runArgs 字段中添加 --volume=/tmp/.X11-unix:/tmp/.X11-unix 表示挂载 x11 相关目录到容器中。
containerEnv 字段中添加 “DISPLAY”: “${localEnv:DISPLAY}” 表示设定容器中的 DISPLAY 环境变量与本地 DISPLAY 为一样的值,例如:
1 | { |
在主机电脑的命令行窗口中运行
1 | xhost + |
然后就可以在Docker中运行GUI应用了(如:Rviz2和Gazebo)。
devcontainer.json 解析
详细文档和例子请见 https://aka.ms/vscode-remote/devcontainer.json ,这里我们主要来看一下常用的一些配置信息:
name
当前工作空间名称,会显示在左下角
build
- dockerfile: 用于指定 dockerfile 文件的路径,这里是相对于 devcontainer.json 文件而言
- context:用于指定 docker build 时的上下文路径,这里是相对于 devcontainer.json 文件而言
- args:用于在 docker build 时传递参数
settings
用于设定容器中 settings.json 的默认值,比如这里设定了使用的 shell
1
2
3
4
5
6
7
8"settings": {
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash"
},
},
"terminal.integrated.defaultProfile.linux": "bash"
},extensions
用于指定在容器中安装的插件,比如这里会自动帮我们安装 一系列插件
1
2
3
4
5
6
7
8
9
10
11
12
13"extensions": [
"dotjoshjohnson.xml",
"zachflower.uncrustify",
"ms-azuretools.vscode-docker",
"ms-iot.vscode-ros",
"ms-python.python",
"ms-vscode.cpptools",
"redhat.vscode-yaml",
"smilerobotics.urdf",
"streetsidesoftware.code-spell-checker",
"twxs.cmake",
"yzhang.markdown-all-in-one"
]portsAttributes
用于设定端口属性,比如名称,映射时的行为,也可以用
forwardPorts简单代替postCreateCommand
在容器第一次启动时执行的指令,只会执行这一次
remoteUser
登录到容器的用户名,默认情况下是 root 用户登录,但是有时我们不想这样,可以利用这个指定远程用户名(这个用户必须存在才行)
1
"remoteUser": "ubuntu",
此外,还有一些字段也很有用:
runArgs
docker run 时传递的参数,用于类似设定 –network=host 等操作
1
2
3
4
5
6
7
8"runArgs": [
"--network=host",
"--cap-add=SYS_PTRACE",
"--security-opt=seccomp:unconfined",
"--security-opt=apparmor:unconfined",
"--volume=/tmp/.X11-unix:/tmp/.X11-unix"
// "--gpus" "all", // 取消该注释使用 GPU 功能
],containerEnv / remoteEnv
用于设定容器中的环境变量,比如设定 http_proxy 等环境变量的值
1
"containerEnv": { "DISPLAY": "${localEnv:DISPLAY}" },
参考:
https://www.allisonthackston.com/articles/vscode-docker-ros2.html
觉得有用就点赞吧!
我是首飞,一个帮大家填坑的机器人开发攻城狮。
另外在公众号《首飞》内回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2等机器人行业常用技术资料。
