Docker镜像进行ROS2开发的实现步骤
ROS2的每个版本都有对应的Ubuntu版本,如果本机的Linux系统和ROS2要求的版本不一致,还得重新安装,但是如果使用Docker镜像,就不用关心本机的Linux版本了。
本文讲述如何使用ROS2的官方镜像来进行开发。本人的本地Linux是WSL2 Debian
一 下载镜像
本文写作时,ROS2处于LTS状态的有三个版本,
- humble:2022-05发布,支持到2027-05
- jazzy:2024-05发布,支持到2029-05
- lyrical:2026-05发布,支持到2031-05
这里以jazzy举例,进入ROS2的docker hub地址https://hub.docker.com/r/osrf/ros/tags,找到jazzy-desktop-full,如下,

然后copy红框中的docker指令,最后进入Linux终端执行这个指令。
下载完毕后通过docker images查看,

二 测试镜像
执行指令
docker run --rm -it --env DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix osrf/ros:jazzy-desktop-full bash
进入容器后,需要执行
source /opt/ros/jazzy/setup.bash
这样才能执行ros2指令。然后运行ROS2自带的小乌龟例子,
ros2 run turtlesim turtlesim_node
然后弹出界面,

此时在宿主机里开启另外一个终端,并使用docker ps来查看容器ID,

然后使用docker指令在当前终端接入这个容器,
docker exec -it 919ff4e779a0 bash
进入后还需再执行source /opt/ros/jazzy/setup.bash,最后执行下面指令开启按键控制节点,
ros2 run turtlesim turtle_teleop_key
开启按键的终端必须保持选中激活,然后按方向键来操作小乌龟移动,

三 使用VSCode基于ROS2容器开发
配置 (由AI生成)
在宿主机里创建一个目录ros2_test,然后里面添加一个docker-compose.yml,内容如下,
services:
ros2_jazzy:
image: osrf/ros:jazzy-desktop-full
stdin_open: true
tty: true
environment:
DISPLAY: ${DISPLAY}
TZ: Asia/Shanghai
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix
# 当前项目目录挂载到容器 /root/ros2_ws
- .:/root/ros2_ws:cached这个配置是把当前工程目录挂载到容器里的/root/ros2_ws/下。
然后创建目录.devcontainer,最后在里面添加devcontainer.json,内容如下,
{
"name": "ROS2 Jazzy Dev",
"dockerComposeFile": "../docker-compose.yml",
"service": "ros2_jazzy",
"workspaceFolder": "/root/ros2_ws",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"ms-python.python",
"twxs.cmake",
"eamodio.gitlens",
"redhat.vscode-yaml",
"Ranch-Hand-Robotics.rde-pack"
]
}
},
"runArgs": ["--cap-add=SYS_PTRACE","--security-opt","seccomp=unconfined"],
"containerEnv": {
"ROS_DOMAIN_ID": "0"
}
}
最后创建src目录,里面的结构如下,

package.xml内容如下,
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" rel="external nofollow" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>cpp_demo</name>
<version>0.0.0</version>
<description>ROS2 C++ simple demo</description>
<maintainer email="user@todo.todo">user</maintainer>
<license>Apache-2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
<buildtool_depend>ament_cmake_auto</buildtool_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
CMakeLists.txt内容如下,
cmake_minimum_required(VERSION 3.8)
project(cpp_demo)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
# ---------------- talker ----------------
add_executable(talker src/talker.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
# ---------------- listener ----------------
add_executable(listener src/listener.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
# 安装可执行文件
install(TARGETS
talker
listener
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
listener.cpp内容如下,
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
class ListenerNode : public rclcpp::Node
{
public:
ListenerNode() : Node("listener")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"/chatter",
10,
std::bind(&ListenerNode::callback, this, std::placeholders::_1)
);
}
private:
void callback(const std_msgs::msg::String::SharedPtr msg) const
{
RCLCPP_INFO(this->get_logger(), "[接收] %s", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ListenerNode>());
rclcpp::shutdown();
return 0;
}
talker.cpp内容如下,
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
#include <chrono>
using namespace std::chrono_literals;
class TalkerNode : public rclcpp::Node
{
public:
TalkerNode() : Node("talker"), count_(0)
{
// 创建发布者,话题名 "/chatter"
publisher_ = this->create_publisher<std_msgs::msg::String>("/chatter", 10);
timer_ = this->create_wall_timer(
500ms,
std::bind(&TalkerNode::timer_callback, this)
);
}
private:
void timer_callback()
{
auto msg = std_msgs::msg::String();
msg.data = "Hello ROS2! count: " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "[发布] %s", msg.data.c_str());
publisher_->publish(msg);
}
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<TalkerNode>());
rclcpp::shutdown();
return 0;
}
进入容器
按Ctrl+Shift+p,弹出命令框,选择Reopen in Container

VSCode会自动根据docker-compose.yml和devcontainer.json来创建容器连接,成功之后可以看下左下角,如下

编译
在VSCode里开启一个终端,然后执行下面指令,
echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc
这样在容器里开启终端就可以自动source,最后执行编译指令
colcon build --symlink-install
显示如下,

编译成功后把这个项目package添加到系统路径里,
source install/setup.bash
此时再开启一个终端,也执行一下上面的source install/setup.bash,这样准备工作就做好了。
测试
现在容器里开启了2个终端,第一个终端执行命令,
ros2 run cpp_demo talker
显示如下,

第二个终端执行命令,
ros2 run cpp_demo listener
显示如下,

验证成功!
四 总结
本文讲述如何使用Docker镜像进行ROS2开发,利用了镜像的方便之处,免除了环境准备的工作,非常方便。更多相关Docker进行ROS2开发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Jenkins+Docker 一键自动化部署 SpringBoot 项目的详细步骤
这篇文章主要介绍了Jenkins+Docker 一键自动化部署SpringBoot 项目,本文章实现最简单全面的Jenkins+docker+springboot 一键自动部署项目,步骤齐全,少走坑路,需要的朋友可以参考下2022-08-08
解决docker容器中出现Access denied for user &apo
这篇文章主要介绍了解决docker容器中出现Access denied for user 'root'@'172.17.0.2'(using password: YES)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-06-06
docker无法删除镜像报Error: No such container的错误问题
docker无法删除镜像的解决方法很简单,只需要简单三步即可完美解决docker删除镜像过程中,一直报Error: No such container的错误问题,感兴趣的朋友跟随小编一起看看吧2023-01-01


最新评论