ROS1学习笔记--通信编程

    前面有一个博客笔者概述了关于ROS1的通信机制,现在就来通过几个例子来讲讲具体的通信编程

一、话题编程

 话题编程流程:

  • 创建发布者
  • 创建订阅者
  • 添加编译选项
  • 运行可执行程序

1.创建一个发布者

  • ROS节点初始化
  • 编写相关的节点信息,包括发布的话题名和消息类型
  • 按一定的频率循环发布消息
 
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
  // ROS节点初始化
  ros::init(argc, argv, "talker");
  
  // 创建节点句柄,NodeHandle是与ROS系统通信的主要接入点,执行节点的初始化
  ros::NodeHandle n;
  
  // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  // 设置循环的频率为10hz
  ros::Rate loop_rate(10);

  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();

	// 发布消息
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);

	// 循环等待回调函数
    ros::spinOnce();
	
	// 按照循环频率延时
    loop_rate.sleep();
    ++count;
  }

  return 0;
}

2.实现一个订阅者

  • ROS节点初始化
  • 订阅需要的话题
  • 循环等待话题消息,接收到消息后进入callback函数
  • 在callback函数中完成消息处理
#include "ros/ros.h"
#include "std_msgs/String.h"

//回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
//打印消息
     ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");

  
  ros::NodeHandle n;

  
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

 
  ros::spin();

  return 0;
}

3.编译代码

  • 在cmakelist中添加链接库和依赖

引用参考网站:simple advertiser/pulisher

二、服务编程

1.实现一个服务器

  •     初始化ROS节点
  • 创建一个server
  • 循环等待服务请求,进入回调函数
  • 在回调函数中完成服务功能,并反馈应答数据
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

 //接受srv文件中定义的请求(req输入参数)和响应(res输出参数)类型,
bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)
{
//将输入参数中的请求数据求和,结果放入响应变量
 res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

//创建一个名为add_two_ints的回调函数,注册回调函数add()
  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ROS_INFO("Ready to add two ints.");
//循环等待回调函数
  ros::spin();

  return 0;
}

2.实现一个客户端

  • 初始化ROS节点
  • 创建一个client
  • 发布服务请求数据
  • 等待应答结果
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_client");

//从终端获取两个加数
 if (argc != 3)
  {
    ROS_INFO("usage: add_two_ints_client X Y");
    return 1;
  }

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
//创建一个beginner_tutorials::AddTwoInts的srv文件,这里需要在工作空间beginner_tutorials下创建一个AddTwoInts.srv文件
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  if (client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

3.配置相应cmakelist.tex的执行文件、链接库、依赖

*自定义.srv文件时,要在package.xml和cmakelist.txt文件中添加功能包依赖和编译选项

参考网站:simple server/client

三、动作编程

有时间再添加

action的接口



由上图可知action的接口

  • goal:发布任务目标
  • cancel:请求取消任务
  • status:通知客户端当前的状态
  • feedback:周期反馈任务运行的监控数据
  • result:向客户端发送任务的执行结果,只发布一次
具体可参考: 古月居--action

参考网站:action

官方网站:官方wiki


文章参考了ROS大神古月老师的文章,真的是大神(膜拜膜拜):古月居


猜你喜欢

转载自blog.csdn.net/weixin_40863346/article/details/80481556