1.写一个publisher节点
“节点”是连接到ROS网络的可执行文件的ROS术语。在这里,我们将创建一个发布者(“ talker”)节点,该节点将不断广播消息。
1.1 将目录更改为在catkin工作区以前的教程中创建的beginner_tutorials包:
roscd beginner_tutorials
1.2 在beginner_tutorials包目录中创建一个src目录:
mkdir -p src
该目录将包含我们beginner_tutorials包的所有源文件。
1.3 在beginner_tutorials包中创建src / talker.cpp文件,并将以下内容粘贴到其中:
// ros/ros.h是一个方便的工具,其中包括使用ROS系统最常见的公共部分所需的所有标头。
#include "ros/ros.h"
// 这包括std_msgs / String消息,该消息驻留在std_msgs包中。
// 这是从该程序包中的String.msg文件自动生成的标头。有关消息定义的更多信息,请参见msg页面。
#include "std_msgs/String.h"
#include
/**
* 本教程演示了如何通过ROS系统简单地发送消息。
*/
// 这是下面事情的精简版:
// 初始化ROS系统
// 宣传我们将在chatter主题上向主服务器发布std_msgs / String消息
// 在将消息发布到聊天时每秒循环10次
int main(int argc, char** argv)
{
// 初始化ROS。这使ROS可以通过命令行进行名称重映射-目前尚不重要。
// 这也是我们指定节点名称的地方。节点名称在运行的系统中必须唯一。
ros::init(argc, argv, "talker");
// 创建此进程的节点的句柄。创建的第一个NodeHandle实际上将对节点进行初始化,
// 而最后一个被破坏的节点将清理该节点正在使用的所有资源。
ros::NodeHandle node_handle;
// 告诉管理员,我们将在主题讨论中发布std_msgs / String类型的消息。
// 这样,主服务器就可以告诉所有正在聊天的节点,我们将发布有关该主题的数据。
// 第二个参数是发布队列的大小。在这种情况下,如果我们发布得太快,
// 它将最多缓冲1000条消息,然后再开始丢弃旧消息。
// NodeHandle :: advertise()返回一个ros :: Publisher对象,
// 该对象有两个作用:
// 1)它包含一个publish()方法,可用于将消息发布到其创建的主题上;
// 2)当它超出范围时,它将自动取消广告。
ros::Publisher chatter_pub = node_handle.advertise("chatter", 100);
// ros :: Rate对象允许您指定要循环播放的频率。
// 它将跟踪自上次调用Rate::sleep()以来已等待了多长时间,并睡眠了正确的时间。
// 在这种情况下,我们告诉我们要以10Hz运行。
ros::Rate loop_rate(10);
int count = 0;
// 默认情况下,roscpp将安装SIGINT处理程序,
// 该处理程序提供Ctrl-C处理,如果发生这种情况,
// 将导致ros :: ok()返回false。
// ros :: ok()将在以下情况下返回false:
// 收到SIGINT(Ctrl-C)
// 我们已经被另一个同名节点踢出网络
// ros :: shutdown()已由应用程序的另一部分调用。
// 所有ros :: NodeHandles已被销毁
// 一旦ros :: ok()返回false,所有ROS调用都会失败。
while (ros::ok())
{
// 我们使用消息自适应类在ROS上广播消息,该类通常是从msg文件生成的。
// 可能有更复杂的数据类型,但是现在我们将使用标准的String消息,
// 该消息具有一个成员:“ data”。
std_msgs::String msg;
std::stringstream ss;
ss << "hello world" << count;
msg.data = ss.str();
// ROS_INFO可以代替printf / cout。有关更多信息,请参见rosconsole文档。
ROS_INFO("%s", msg.data.c_str());
// 现在,我们实际上将消息广播给了已连接的任何人。
chatter_pub.publish(msg);
// 对于这个简单的程序,不需要在此处调用ros :: spinOnce(),
// 因为我们没有收到任何回调。但是,如果您要向此应用程序添加订阅,
// 并且在此处没有ros :: spinOnce(),则将永远不会调用您的回调。
// 因此,请将其添加为良好的度量。
ros::spinOnce();
// 现在,我们使用ros :: Rate对象休眠剩余时间,使我们达到10Hz的发布速率。
loop_rate.sleep();
++count;
}
return 0;
}
2.写一个subscriber节点
- 在beginner_tutorials包中创建src / listener.cpp文件,并将以下内容粘贴到其中:
// ros/ros.h是一个方便的工具,其中包括使用ROS系统最常见的公共部分所需的所有标头。
#include "ros/ros.h"
// 这包括std_msgs / String消息,该消息驻留在std_msgs包中。
// 这是从该程序包中的String.msg文件自动生成的标头。有关消息定义的更多信息,请参见msg页面。
#include "std_msgs/String.h"
/**
本教程演示了通过ROS系统简单接收消息的过程。
*/
//当在chatter主题上收到新消息时,将调用此回调函数。
// 该消息在boost shared_ptr中传递,
// 这意味着您可以根据需要将其存储起来,
// 而不必担心它下面的内容被删除,也无需复制基础数据。
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
// 同样,这是正在发生的事情的精简版:
// 初始化ROS系统
// 订阅聊天主题
// 旋转,等待消息到达
// 消息到达时,将调用chatterCallback()函数
int main(int argc, char** argv)
{
// 初始化ROS。这使ROS可以通过命令行进行名称重映射-目前尚不重要。
// 这也是我们指定节点名称的地方。节点名称在运行的系统中必须唯一。
ros::init(argc, argv, "listener");
// 创建此进程的节点的句柄。创建的第一个NodeHandle实际上将对节点进行初始化,
// 而最后一个被破坏的节点将清理该节点正在使用的所有资源。
ros::NodeHandle node_handle;
// 订阅与主机的聊天主题。每当有新消息到达时,ROS就会调用chatterCallback()函数。
// 第二个参数是队列大小,以防万一我们不能足够快地处理消息。
// 在这种情况下,如果队列达到1000条消息,我们将在新消息到达时开始丢弃旧消息。
// NodeHandle :: subscribe()返回ros :: Subscriber对象,
// 您必须保留该对象直到要取消订阅为止。破坏Subscriber对象后,
// 它将自动取消订阅chatter主题。
// NodeHandle :: subscribe()函数有多种版本,
// 可让您指定类成员函数,甚至可以指定Boost.Function对象可以调用的任何函数。
ros::Subscriber sub = node_handle.subscribe("chatter", 100, chatterCallback);
// ros :: spin()进入循环,并尽可能快地调用消息回调。
// 不过,请不要担心,如果没有什么可做的,则不会占用太多CPU。
// 一旦ros :: ok()返回false,ros :: spin()将退出,
// 这意味着ros :: shutdown()已被默认Ctrl-C处理程序,
// 主程序告诉我们关闭或被调用了手动。
ros::spin();
return 0;
}
3.编译节点
您在上一教程中使用过catkin_create_pkg,该教程为您创建了package.xml和CMakeLists.txt文件。 生成的CMakeLists.txt应该如下所示(对“创建Msgs和Srvs”教程进行了修改,并删除了未使用的注释和示例):
1 cmake_minimum_required(VERSION 2.8.3)
2 project(beginner_tutorials)
3
4 ## Find catkin and any catkin packages
5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
6
7 ## Declare ROS messages and services
8 add_message_files(DIRECTORY msg FILES Num.msg)
9 add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
10
11 ## Generate added messages and services
12 generate_messages(DEPENDENCIES std_msgs)
13
14 ## Declare a catkin package
15 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)
- 生成的CMakeLists.txt文件应如下所示:
1 cmake_minimum_required(VERSION 2.8.3)
2 project(beginner_tutorials)
3
4 ## Find catkin and any catkin packages
5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
6
7 ## Declare ROS messages and services
8 add_message_files(FILES Num.msg)
9 add_service_files(FILES AddTwoInts.srv)
10
11 ## Generate added messages and services
12 generate_messages(DEPENDENCIES std_msgs)
13
14 ## Declare a catkin package
15 catkin_package()
16
17 ## Build talker and listener
18 include_directories(include ${catkin_INCLUDE_DIRS})
19
20 add_executable(talker src/talker.cpp)
21 target_link_libraries(talker ${catkin_LIBRARIES})
22 add_dependencies(talker beginner_tutorials_generate_messages_cpp)
23
24 add_executable(listener src/listener.cpp)
25 target_link_libraries(listener ${catkin_LIBRARIES})
26 add_dependencies(listener beginner_tutorials_generate_messages_cpp)
这将创建两个可执行文件,talker和listener,默认情况下它们将进入开发空间的package目录,默认情况下位于〜/ catkin_ws / devel / lib /
。
- 请注意,您必须将可执行目标的依赖项添加到消息生成目标:
target_link_libraries(talker ${catkin_LIBRARIES})
您可以直接调用可执行文件,也可以使用rosrun调用它们。它们没有放在'
- 现在运行catkin_make编译:
# In your catkin workspace
cd ~/catkin_ws
catkin_make
4.测试你的节点(两种方式)
- 打开三个终端分别运行:
roscore
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials talker
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials listener
- 打开三个终端分别运行:
roscore
~/catkin_ws/devel/lib/beginer_tutorials/talker
~/catkin_ws/devel/lib/beginer_tutorials/listener
最后结果: