0 引言
本文旨在学习ROS基础包的从零开始创建,包括如何创建一个发布消息节点,一个接收消息节点,还有如何使用roslaunch同时启动多个节点,如何编译ROS工程包等操作。
默认已在Ubuntu系统中安装ROS机器人系统,比如Ubuntu18.04-melodic
工程目录tree
# catkin_ws/src 目录下
.
├── CMakeLists.txt -> /opt/ros/melodic/share/catkin/cmake/toplevel.cmake
└── hello_world
├── CMakeLists.txt
├── include
│ └── hello_world
├── launch
│ └── talker_listener.launch
├── package.xml
└── src
├── listener.cpp
└── talker.cpp
1 工作空间创建并初始化
# 新开一个终端
# 创建一个名为catkin_ws工作空间,及src子目录
mkdir -p ~/catkin_ws/src
# 进入到src文件夹
cd ~/catkin_ws/src
# 初始化工作空间
catkin_init_workspace
# 回到工作空间根目录
cd ..
# 编译工作空间
catkin_make
2 创建ROS程序包
# 切换到src文件夹
cd ~/catkin_ws/src
# 创建名为hello_world的ROS程序包,以后创建其他的包也是此方法,只需修改包的名称即可
catkin_create_pkg hello_world roscpp rospy std_msgs
执行后,src目录下新建了一个 hello_world文件夹及子目录和子文件
.
├── CMakeLists.txt -> /opt/ros/melodic/share/catkin/cmake/toplevel.cmake
└── hello_world
├── CMakeLists.txt
├── include
│ └── hello_world
├── package.xml
└── src
3 创建消息节点
3.1 发布消息节点
在 hello_world/src 代码资源文件夹下新建发布消息节点的talker.cpp文件,详细代码如下:
#include "ros/ros.h" //创建ROS节点必须包含的头文件,固定格式
#include "std_msgs/String.h" //节点中使用某种特定的消息类型
#include <sstream> // c++中用来处理面向流的输入和输出的标准库
int main(int argc,char **argv)
{
ros::init(argc,argv,"talker"); // 初始化一个名为talker的节点,以后写其他的节点只要修改talker就行
ros::NodeHandle n; // 创建名为n的节点句柄,自己写程序只要改n这个地方就行
// ROS节点中发布话题的方式,chatter_pub是发布者实例,发布消息的类型是std_msgs/String的话题,
// topic话题名称为chatter,队列大小为1000,n为访问实例,要修改的话就改提到的这几个地方
ros::Publisher chatter_pub=n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10); // 制定循环的频率,此处为10HZ,固定格式
int count=0; // 进入节点的主循环,在节点未发生异常的情况下将一直在循环,固定格式
while(ros::ok()) // 当Ctrl+c按下时,ros::ok()将会返回false,固定格式
{
// 初始化std_msgs::String类型的消息
std_msgs::String msg;
std::stringstream ss;
ss<<"hello world"<<count;
msg.data=ss.str(); // 用data来存储字符串
// 发布消息
ROS_INFO("%s",msg.data.c_str()); //ROS_INFO类似于cout和printf
chatter_pub.publish(msg); // 发布封装完毕的消息msg
// 循环等待回调函数
ros::spinOnce(); // 用来处理节点订阅话题的所有回调函数
// 按照循环频率延时,固定格式
loop_rate.sleep();
++count;
}
return 0;
}
3.2 接收消息节点
在 hello_world/src 代码资源文件夹下新建接收消息节点的listener.cpp文件,详细代码如下:
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc,char **argv)
{
ros::init(argc,argv,"listener"); // 初始化一个名为listener的节点
ros::NodeHandle n; // 创建名为n的节点句柄
// 创建一个Subscriber的话题,注册回调函数chatterCallback
ros::Subscriber sub=n.subscribe("chatter", 1000, chatterCallback);
// 循环等待回调函数
ros::spin();
return 0;
}
// 接收到订阅的消息,进入回调函数
void chatterCallback(const std_msgs::String::ConstPtr & msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str()); // 将接收的消息打印出来
}
4 编辑CMakeLists.txt
执行第2步后,hello_world文件夹下生成了CMakeLists.txt,打开编辑:
# 第一行修改cmake最小版本为 2.8.3
cmake_minimum_required(VERSION 2.8.3)
# 最后添加以下几行
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker hello_world)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener hello_world)
5 编译程序包
# 回到catkin_ws工作空间
cd ~/catkin_ws/src
# 执行catkin_make编译
catkin_make
6 运行消息节点
# 新开终端
roscore
# 新开终端,运行talker节点
source ~/catkin_ws/devel/setup.bash
rosrun hello_world talker
运行后,可以看到已成功创建发布消息的节点,并持续发布消息:
[ INFO] [1688019211.336438520]: hello world0
[ INFO] [1688019211.436538723]: hello world1
[ INFO] [1688019211.536531392]: hello world2
[ INFO] [1688019211.636536978]: hello world3
[ INFO] [1688019211.736561791]: hello world4
[ INFO] [1688019211.836520559]: hello world5
[ INFO] [1688019211.936556623]: hello world6
[ INFO] [1688019212.036533914]: hello world7
[ INFO] [1688019212.136574843]: hello world8
[ INFO] [1688019212.236534653]: hello world9
[ INFO] [1688019212.336576466]: hello world10
[ INFO] [1688019212.436533892]: hello world11
[ INFO] [1688019212.536543132]: hello world12
...
# 新开终端,运行listener节点
source ~/catkin_ws/devel/setup.bash
rosrun hello_world listener
运行后,可以看到打印已订阅talker发出的消息:
[ INFO] [1688019425.918466687]: I heard: [hello world4]
[ INFO] [1688019426.018305977]: I heard: [hello world5]
[ INFO] [1688019426.117968093]: I heard: [hello world6]
[ INFO] [1688019426.218154007]: I heard: [hello world7]
[ INFO] [1688019426.318345417]: I heard: [hello world8]
[ INFO] [1688019426.418056486]: I heard: [hello world9]
[ INFO] [1688019426.517999187]: I heard: [hello world10]
[ INFO] [1688019426.618130109]: I heard: [hello world11]
[ INFO] [1688019426.718321709]: I heard: [hello world12]
[ INFO] [1688019426.818094286]: I heard: [hello world13]
[ INFO] [1688019426.917948960]: I heard: [hello world14]
[ INFO] [1688019427.017976226]: I heard: [hello world15]
[ INFO] [1688019427.118302080]: I heard: [hello world16]
7 添加launch启动文件
rosrun只能启动一个消息节点,可以用ROS中launch文件启动多个节点,在hello_world文件夹中新建launch文件夹,并在launch文件夹中新建talker_listener.launch,打开talker_listener.launch,添加如下xml格式的代码:
<launch>
<node name="listener_node" pkg="hello_world" type="listener" output="screen"/>
<node name="talker_node" pkg="hello_world" type="talker" output="screen"/>
</launch>
- node name: 该节点的名字,相当于代码中 ros::init() 中设置的信息,有了它代码中的名称会被覆盖;
- pkg: 表示该节点的package,相当于 rosrun 命令后面的第一个参数;
- type: 可执行文件的名字,rosrun 命令的第二个参数;是否可以理解为要执行的节点;
- output=“screen”: 将标准输出显示在屏幕上而不是记录在日志中
8 重新编译
# 新开终端
# 重新编译前,先给talker_listener.launch可执行权限
sudo chmod +x ~/catkin_ws/src/hello_world/launch/talker_listener.launch
# 回到catkin_ws工作空间
cd ~/catkin_ws
# 重新编译
catkin_make
9 运行launch文件
# 编译后,重新source
source ~/catkin_ws/devel/setup.bash
# 运行talker_listener.launch
roslaunch hello_world talker_listener.launch
运行后,自动启动了roscore, 也启动了talker和listener两个消息节点:
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://px:35833/
SUMMARY
========
PARAMETERS
* /rosdistro: melodic
* /rosversion: 1.14.11
NODES
/
listener_node (hello_world/listener)
talker_node (hello_world/talker)
ROS_MASTER_URI=http://localhost:11311
process[listener_node-1]: started with pid [30875]
process[talker_node-2]: started with pid [30877]
[ INFO] [1688020081.054048128]: hello world0
[ INFO] [1688020081.154174941]: hello world1
[ INFO] [1688020081.254183692]: hello world2
[ INFO] [1688020081.354176431]: hello world3
[ INFO] [1688020081.354852999]: I heard: [hello world3]
[ INFO] [1688020081.454181460]: hello world4
[ INFO] [1688020081.454357334]: I heard: [hello world4]
[ INFO] [1688020081.554196089]: hello world5
[ INFO] [1688020081.554813633]: I heard: [hello world5]
[ INFO] [1688020081.654196695]: hello world6
[ INFO] [1688020081.654732170]: I heard: [hello world6]
...
10 查看节点和topic
查看消息node
rosnode list
输出:
/listener_node
/rosout
/talker_node
查看话题topic
rostopic list
输出:
/chatter
/rosout
/rosout_agg
用rqt_graph查看消息节点node和话题topic的关系
至此,成功创建一个ROS基础包,并包含一个发布节点,一个接收节点,一个话题用来传递消息,也学习了基础的ROS包编译等操作。