本教程介绍了如何创建C++开发语言的pub和sub节点,并演示二者之间通信。至于为什么选择deepin而不是ROS通用的ubuntu,也仅仅是为了支持国产系统。鉴于本人水平有限,如哪位攻城狮网友发现本文存在的问题,烦请留言指正,谢谢!
节点是ROS术语,指连接到ROS网络的可执行程序。本教程我们创建一个Publisher节点,它会持续不断的向外广播消息。切换到beginner_tutorials包
roscd beginner_tutorials
# 创建src目录
mkdir -p src
# 然后在src目录下创建talker.cpp源文件
cd src
touch talker.cpp
之后将下面源码复制到taler.cpp
///ros/ros.h包好了ROS系统中最常见的头文件
#include "ros/ros.h"
/// 包含在std_msgs包里的String.h。这是一个自动从String.msg生成的头文件。具体可查阅msg对应的网站
#include "std_msgs/String.h"
#include
/**
* This tutorial demonstrates simple sending of messages over the ROS system.
*/
int main(int argc, char **argv)
{
/**
* ros::init()需要使用argc,argv两个参数,以便它可以执行命令行提供的ros参数和名称重映射
* 对于编程式重映射,你可以使用不同版本的init(),它可以直接重映射。但对于大多数命令行程序
* 来说传递argc,argv是最简单的方式。第三个参数是节点名称[不能有/]。在使用ros系统任何其他部分之前,必须
* 调用ros::init()其中一个版本
*/
ros::init(argc, argv, "talker");
/**
* NodeHandle是ROS通信中的主要访问点。创建第一个NodeHandle将实际知行节点初始化
* 销毁最后一个NodeHanle时将清除节点正在使用的所有资源
*/
ros::NodeHandle n;
/**
advertise()主要是告知ROS,接下来你要做什么。此处是将在topic:chatter上发布std_msgs/String类型的消息,
master维护了哪些节点在发布什么消息订阅何种消息的注册表,advertise()调用后,master将通知其他订阅此消息的节点。
订阅消息的节点会反过来与发布节点建立点对点通信关系。第二个参数是发布队列的大小,这里设置的是
1000,在这种情况下,如果我们发布的太快,它将在开始丢数据之前缓存1000条消息。
NodeHandle::advertise()返回ros::Publisher对象以方便你后续使用其成员函数publish()发布消息。一旦所有Publisher对象
销毁后,也将自动取消此topic上的消息广播。
**/
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
/// ros::Rate对象用于指定消息发布的频率。下面是要以10Hz的周期发布topic消息
ros::Rate loop_rate(10);
/**
* 统计发送的消息数,用于创建第一无二的消息体.
*/
int count = 0;
/**
* ros::ok()返回false的情况:
* 1.CTRL-C
* 2.被另一同名节点踢出ROS网络
* 3.应用程序其他部分调用了ros::shutdown()
* 4.所有的ros::NodeHandlers都销毁
* 一旦ros::ok()返回失败,所有的ROS调用都将失败。
**/
while (ros::ok())
{
/**
* 使用何时的消息适应类在ROS上广播消息。通常由msg文件产生,这里使用String消息
*/
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
//替换cout/printf等的日志输出函数,可参考rosconsole
ROS_INFO("%s", msg.data.c_str());
/**
* publish()会广播一条消息.参数就是消息对象。
* 此处需要注意publish()中的参数的类型必须与advertise<>() 调用时设置的类型保持一致
*/
chatter_pub.publish(msg);///发布消息
/**
* 这里ros::spinOnce()调用是不必要的。因为我们没有收到任何回调。但是如果你要在这个程序中添加
* 一个subscriber,但是你的程序没有调用ros::spinOnce()那么subscriber所注册的回调函数永远
* 不会被调用。这里添加上只是为了以防万一
**/
ros::spinOnce();
loop_rate.sleep();///ros::Rate对象按照前面的设置进行休眠延时。
++count;
}
return 0;
}
msg
rosconsole
publisher的主要流程:
在src目录创建listener.cpp并复制如下代码
#include "ros/ros.h"
#include "std_msgs/String.h"
/**
* 当subscriber在ROS系统中接收到消息会调用此回调函数.
* 此消息在boost shared_ptr中传递,如果有需要你可以将
* 数据存储起来
*/
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
/**
* 初始化ros,并设置节点名为listener
*/
ros::init(argc, argv, "listener");
/**
* NodeHandle是ROS通信中的主要访问点。创建第一个NodeHandle将实际知行节点初始化
* 销毁最后一个NodeHanle时将清除节点正在使用的所有资源
*/
ros::NodeHandle n;
/**
* 与master通信,告知master此节点订阅chatter的主题消息.当接收到
* chatter主题消息时会自动调用回调函数chatterCallback函数。第二个
* 参数是队列大小,以防止我们不能足够快处理数据。如果队列中有1000条消息后
* 后续消息在之前消息没处理的时候是会丢弃的。
* n.subscribe()函数返回一个ros::Subscriber独享,你可以一致使用此对象,直到
* 你想销毁此订阅对象时,它将自动取消对应主题消息的订阅。对于subscribe()函数其他版本
* 可参考roscpp
*/
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
/**
* 进入loop循环,以尽可能快的速度调用回调函数,不用担心,它不会耗费太多CPU资源。一旦ros::ok()返回false
* ros::spin()也会退出。
*/
ros::spin();
return 0;
}
roscpp
subscriber的主要流程:
在此教程之前您使用catkin_create_pkg,其创建了package.xml和CMakeList.txt.
再经过前面srv,msg教程的修改后CMakeList.txt如下:
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)
## Declare a catkin package
catkin_package()
现在在此CMakeLists.txt的尾部添加如下内容
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)
修改后的CMakeList.txt如下:
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
## Declare ROS messages and services
add_message_files(FILES Num.msg)
add_service_files(FILES AddTwoInts.srv)
## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)
## Declare a catkin package
catkin_package()
## Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
# 必须为可执行程序添加自动生成的依赖
add_dependencies(listener beginner_tutorials_generate_messages_cpp)
这会创建两个可执行文件talker和listener.它们将默认进入您的devel空间的包目录里。默认
位于 devel/lib/<包名>
CMakeLists.txt修改完后可进行构建
# 构建
catkin_make
# 运行
source devel/setup.bash
## 运行方式1
#终端1
rosrun beginner_tutorials talker
# 终端2
rosrun beginner_tutorials listener
## 运行方式2
cd devel/lib/<包名>
# 终端1
./talker
# 终端2
./listener