忙活了一中午,基本上摸清了如何使用colcon等工具编译一个自己的ROS2的项目。本文中,首先介绍了这么几个概念:节点(node)、主题(topic)、服务(services)。然后介绍了如何使用colcon来构建自己的包。本人的使用环境:ubuntu22.04,ROS2 Iron。我会提供源码给大家。本文参考:coze,ros2官网教程
1、激励实例
这一部分,我们提供了两个激励实例,先给大家看一看结果,一方面激发兴趣,另一方面明确这篇文章具体完成了什么任务。具体如何构建将会在后续详细介绍。
1.1 ROS2 初体验——使用绿毛龟(turtlesim)玩一玩
这里开了两个节点,一个是绿毛龟节点,另一一个是控制绿毛龟的节点。开启控制节点之后,键盘上下左右即可控制绿毛龟。这里的节点实际上就是执行特定任务的独立单元,节点之间可以进行通信。目前这个实例就是控制节点捕捉我们的键盘动作,然后将命令传递给绿毛龟节点,即完成控制。
1.2 ROS2 再体验——编译自己的包(talker & listener)
这里构建了两个节点:talker和listener。talker每1s发布一个topic,然后listener监听到topic之后打印下来。这就是经典的ROS2中的Hello word。
2、ROS2中的一些基本概念
-
节点(node):就是一个执行特定任务的独立单元。你可以把它想象成一个程序或一个进程。在一个典型的ROS 2系统中,可能会有多个节点同时运行,每个节点都负责执行一个特定的任务。节点与节点之间可以进行通信。简单来说,节点是ROS 2系统中执行任务和处理数据的基本单位。
-
话题(topic):异步通信方式,发出去就不管了,可以多对多。
-
服务(service):同步通信方式,发出去之后要等待回应,可以一对多。
-
动作(action):是 ROS 2 中的通信类型之一,适用于长时间运行的任务。底层的三个话题和服务组成:一个任务目标(Goal,服务),一个执行结果(Result,服务),周期数据反馈(Feedback,话题)。
3、如何构建自己的包
3.1 玩绿毛龟
ros2 run turtlesim turtlesim_node #运行绿毛龟节点
ros2 run turtlesim turtle_teleop_key #运行控制绿毛龟的节点
3.2 编译自己的包
3.2.1 新建包
ROS2中提供了一个colcon
工具来管理构建。使用ros2 pkg create
命令创建新包。这里的--build-type
需要指定构建的类型:ament_python
、ament_cmake
。--dependencies xxx xxx
表示需要依赖的包。
ros2 pkg create --build-type ament_cmake note_communication --dependencies rclcpp std_msgs
3.2.2 查看新建包的结果
上述创建包之后,生成两个文件CMakeLists.txt
和package.xml
。在ROS2中,package.xml
文件是一个包的清单文件,它包含了关于包的元数据,例如包的名称、版本、作者、许可证信息,以及它与其他ROS软件包的依赖关系等。这个文件是用XML格式编写的,每个包必须有一个这样的文件。它的主要作用是帮助ROS的构建系统理解包的结构和依赖关系,以便正确地构建和链接它们。
3.2.3 编写talker和listener节点代码并且将至添加到CMakeLists.txt中
在src中,添加节点的实现代码(具体代码后续提供)。然后将两个节点添加到CMakeLists.txt中。
add_executable(talker ./src/talker.cpp)
ament_target_dependencies(talker rclcpp std_msgs) #添加节点的依赖
add_executable(listener ./src/listener.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS #添加安装路径
talker
listener
DESTINATION lib/${PROJECT_NAME})
在note_communication
目录执行编译命令:
colcon build
3.2.4 运行节点
source ./install/setup.bash
ros2 run note_communication talker # 跑talker节点
开一个新的终端:
source ./install/setup.bash
ros2 run note_communication listener # 跑listener节点
搞定
4、代码分享
talker.cpp
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
int main(int argc, char const *argv[]){
rclcpp::init(argc, argv);
// 创建名字为talker的节点
auto node = rclcpp::Node::make_shared("talker");
// 在"chatter"这个主题上创建一个发布者,队列大小设为10
auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter", 10);
rclcpp::Rate loop_rate(1); //控制主循环的频率,这里设定为每秒10次
auto msg = std_msgs::msg::String();
int index = 0;
//主循环,只要ROS 2没有被关闭,就一直执行。
while (rclcpp::ok()){
msg.data = "Hello, world. " + std::to_string(index);
RCLCPP_INFO(node->get_logger(), "Publishing: '%s'", msg.data.c_str());
chatter_pub->publish(msg);//发布消息
//循环等待回调函数
rclcpp::spin_some(node);
loop_rate.sleep(); //等待一段时间
++index;
}
rclcpp::shutdown();
return 0;
}
listener.cpp
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
void chatterCallback(const std_msgs::msg::String::SharedPtr msg)
{
RCLCPP_INFO(rclcpp::get_logger("listener"), "I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
// 创建名字为listener的节点
auto node = rclcpp::Node::make_shared("listener");
auto sub = node->create_subscription<std_msgs::msg::String>("chatter", 10, chatterCallback);
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
5、ROS2市场与安装已有包
ros资源网址,看清楚自己的ros2版本,以及是否可以通过apt指令安装。这里以rqt_robot_steering为例。
sudo apt-get install ros-iron-rqt-robot-steering #安装包
ros2 run rqt_robot_steering rqt_robot_steering #启动包
ros2 run turtlesim turtlesim_node #启动绿毛龟节点
然后需要在rqt_robot_steering的最上面节点名称添加加上turtle1/cmd_vel,用来指示我们要控制turtle1。然后设定速度和角速度即可。
6、总结与反思
本人在好几年前接触过ROS1,我记得那时候在执行某个节点时,还需要首先开启一个ros::core节点。本人当时就在想,如果这个core节点挂掉,整个系统就会挂掉。在接触ROS2这两天之后,看来ROS2已经更改了这个特性,每个节点执行都有一定的独立性,类似于去中心化的分布的那个想法。但可以预见的一个疑问是,去中心化意味着整个系统不知道这些节点执行的先后顺序,对于一些注重执行步骤的任务,ROS2中是否存在一些机制能够胜任。
这篇博客,基本上都是标准化的流程,要弄清楚如何创建、编译、执行一个现有的/自己创建的包。其中,还添加了一些ROS2的一些基本概念,topic、service、action等。