ROS 创建及使用msg和srv(二)

ROS 创建及使用msg和srv(一)介绍了如何创建和编译msg及srv文件,接下来将介绍如何使用。

1. 使用新建的msg

上一章work/src/myros/msg目录下建立了num.msg文件,现在要使用num.msg创建两个节点,在myros/src目录下新建exa1.cpp和exa2.cpp,同时调用num.msg。

1.1 exa1.cpp:

#include "ros/ros.h"
#include "myros/num.h"//包含进之前编写的num.msg 功能包/.msg文件名称
// 由编译系统自动根据我们先前创建的msg文件生成的对应该msg文件的头文件。
#include <sstream>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "exa1_node"); //节点名称
  ros::NodeHandle n;
  ros::Publisher pub = n.advertise<myros::num>("message", 1000);
  ros::Rate loop_rate(10);
  while (ros::ok())
  {
    //使用自定义消息类型int32 A,int32 B,int32 C
    myros::num msg;
    msg.A = 1;
    msg.B = 2;
    msg.C = 3;
    pub.publish(msg);//发布消息
    ros::spinOnce(); 
    loop_rate.sleep(); //休眠时间
  }
  return 0;
}

1.2 exa2.cpp:

#include "ros/ros.h"
#include "myros/num.h" //包含进之前编写的num.msg 功能包/.msg文件名称

void Callback(const myros::num::ConstPtr& msg)//回调函数
{
  //这里使用了自定义消息类型int32 A,int32 B,int32 C
  ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C);
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "exa2_node");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("message", 1000, Callback);
  ros::spin();
  return 0;
}

1.3 编辑CMakeList.txt文件

为了编译节点,在CMakeList.txt文件末尾或文中相对应位置添加:

add_executable(exa1_node src/exa1.cpp)
add_executable(exa2_node src/exa2.cpp)

add_dependencies(exa1_node myros_generate_messages_cpp)
add_dependencies(exa2_node myros_generate_messages_cpp)

target_link_libraries(exa1_node ${catkin_LIBRARIES})
target_link_libraries(exa2_node ${catkin_LIBRARIES})

1.4 运行

在终端:

$ cd work/          //切换到工作空间
$ catkin_make
$ roscore

新建终端:

source devel/setup.bash   
rosrun myros exa1_node   //rosrun 功能包名 节点名

新建终端:

source devel/setup.bash   
rosrun myros exa2_node   //rosrun 功能包名 节点名

2. 使用新建的srv

在开始本节之前,对节点之间的通信方式进行回顾。

节点之间常用两种通信方式:topic(话题)、service(服务)。
“话题”通信:不同的 node 可以向同一个 topic 上发送、接收数据,每个 node 都是相对独立的,只需要负责自己的功能实现以及外部接口,不需要关心其他 node 的行为。这是一种开放式的收、发数据的方式,也是 node 之间通讯的主要形式,有利于构造分布式大系统。
“服务”通信:是一种请求+反馈的通信机制。消息的传输只涉及两个 node:发送请求的一方称为 client,提供服务的一方叫做 server。在通过 service 形式进行通讯时,client 首先向 server 请求服务, 收到消息之后 server 运行事先设置好的服务功能,并返回消息给 client。 service 通讯一般用在事件触发情景中,例如满足某个条件就令 node 开启某项功能,并希望确认功能确实顺利开启。
————————————————
版权声明:本段转自CSDN博主「su扬帆启航」的原创文章
原文链接:https://blog.csdn.net/orange_littlegirl/article/details/96474090

Topic话题 Service服务
节点A——>话题T (节点A发布话题T) 话题T<——节点B (节点B订阅话题T) 节点A——>服务节点S (节点A请求服务S) 服务节点S<——节点A (服务S响应节点A)
异步通信 同步通信
话题内容的数据格式——msg 服务的通信数据格式——srv
用于连续高频的数据发布和接收:雷达测障碍物、里程计等 用于偶尔调用的功能或执行某一项功能:拍照、语言识别等

————————————————
版权声明:本表格为CSDN博主「墨水兰亭」的原创
原文链接:https://blog.csdn.net/moshuilangting/article/details/86484042

之前介绍的都是通过话题进行通信,接下来就是使用新建的srv文件采用服务通信,服务允许发送请求和获得响应。
上一章work/src/myros/srv目录下建立了ber.srv文件,现在用ber.srv创建两个节点(service、client),在myros/src目录下新建exa3.cpp和exa4.cpp,同时调用ber.srv。

2.1 exa3.cpp(service):

#include "ros/ros.h"
#include "myros/ber.h" 
//由编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。

bool add(myros::ber::Request &req,myros::ber::Response &res)
	{
	res.sum = req.A + req.B + req.C;//A、B、C是先前在.srv文件中定义的名称
	ROS_INFO("request: A=%d, B=%d C=%d", (int)req.A, (int)req.B, (int)req.C);
	ROS_INFO("sending back response: [%d]", (int)res.sum);
	return true;
	}
	//服务的处理操作在add()函数中实现(求和),他的输入参数是.srv中的request和response两部分。通常在处理函数中,我们对 Request 部分的数据进行相应的服务操作,然后将结果写入到 Response 中。处理函数返回值是 bool 类型,表示服务是否成功执行。
    // A B C sum 的数据类型(int float 等)要确定好。 
    //相加后,关于request和response的信息被记录下来。最后,service完成计算后返回true值。
int main(int argc, char **argv)
{
	ros::init(argc, argv, "exa3_node");
	ros::NodeHandle n;
    //创建服务并在ROS中发布广播
	ros::ServiceServer service = n.advertiseService("add_3_ints", add);
    //建立完成service,并且发布消息 值得注意的是 add_3_ints 并不是“话题”,因为这个是“服务”
	ROS_INFO("Ready to add 3 ints."); //在命令行窗口输出信息
	ros::spin();
	return 0;
}

2.2 exa4.cpp(client):

#include "ros/ros.h"
#include "myros/ber.h" //包含先前所创建的srv文件
#include <cstdlib>

int main(int argc, char **argv)
{
	ros::init(argc, argv, "exa4_node");
	if (argc != 4)
	  {
      ROS_INFO("usage: add_3_ints_client A B C ");
      return 1;
      }
	ros::NodeHandle n;
	ros::ServiceClient client = n.serviceClient<myros::ber>("add_3_ints");
    //下面创建srv文件的一个实例,并且加入需要发生的数据值 add_3_ints不是“话题”
	myros::ber srv;
	srv.request.A = atoi(argv[1]);
    srv.request.B = atoi(argv[2]);
    srv.request.C = atoi(argv[3]);
    //这里实例化一个由ROS编译系统自动生成的service类,并给其request成员赋值。
    //一个service类包含两个成员request和response。
    //同时也包括两个类定义Request和Response。
	if (client.call(srv))
	  {
      ROS_INFO("Sum: %ld", (long int)srv.response.sum);
 	  }
	else
 	  {
      ROS_ERROR("Failed to call service add_3_ints");
      return 1;
      }
      //这段代码是在调用service。
      //由于service的调用是模态过程(调用的时候占用进程阻止其他代码的执行),一旦调用完成,将返回调用结果。
     //如果service调用成功,call()函数将返回true,srv.response里面的值将是合法的值。
     //如果调用失败,call()函数将返回false,srv.response里面的值将是非法的。
	return 0;
}

2.3 编辑CMakeList.txt文件

为了编译节点,在CMakeList.txt文件末尾或文中相对应位置添加:

add_executable(exa3_node src/exa3.cpp)
add_executable(exa4_node src/exa4.cpp)

add_dependencies(exa3_node myros_generate_messages_cpp)
add_dependencies(exa4_node myros_generate_messages_cpp)

target_link_libraries(exa3_node ${catkin_LIBRARIES})
target_link_libraries(exa4_node ${catkin_LIBRARIES})

2.4 运行

在终端:

$ cd work/          //切换到工作空间
$ catkin_make
$ roscore

新建终端:

source devel/setup.bash   
rosrun myros exa3_node   //rosrun 功能包名 节点名

新建终端:

source devel/setup.bash   
rosrun myros exa4_node 1 2 4   //rosrun 功能包名 节点名

在这里插入图片描述最近发现一片博客写的也蛮好,附上链接供以后查看。
ROS自定义msg类型及使用

原创文章 15 获赞 8 访问量 927

猜你喜欢

转载自blog.csdn.net/weixin_39652282/article/details/103507607
今日推荐