ROS中的Client Library与roscpp talker lisener

文章目录

    • 前言
    • 一、Client Library简介
    • 二、roscpp
    • 三、talker与 lisener

前言

ROS为机器人开发者们提供了不同语言的编程接口,比如C++接口叫做roscpp,Python接口叫做rospy,Java接口叫做rosjava。尽管语言不通,但这些接口都可以用来创建topic、service、param,实现ROS的通信功能。Clinet Lirary有点类似开发中的Helper Class,把一些常用的基本功能做了封装。

一、Client Library简介

目前ROS支持的Clinet Library包括:
ROS中的Client Library与roscpp talker lisener_第1张图片
目前最常用的只有roscpprospy,而其余的语言版本基本都还是测试版。

从开发客户端库的角度看,一个客户端库,至少需要能够包括master注册、名称管理、消息收发等功能。这样才能给开发者提供对ROS通信架构进行配置的方法。
ROS中的Client Library与roscpp talker lisener_第2张图片

二、roscpp

roscpp位于 /opt/ros/kinetic 之下,用C++实现了ROS通信。在ROS中,C++的代码是通过catkin这个编译系统(扩展的CMake)来进行编译构建的。所以简单地理解,你也可以把roscpp就当作为一个C++的库,我们创建一个CMake工程,在其中include了roscpp等ROS的libraries,这样就可以在工程中使用ROS提供的函数了。

通常我们要调用ROS的C++接口,首先就需要#include

roscpp的主要部分包括:

  • ros::init() : 解析传入的ROS参数,创建node第一步需要用到的函数
  • ros::NodeHandle : 和topic、service、param等交互的公共接口
  • ros::master : 包含从master查询信息的函数
  • ros::this_node:包含查询这个进程(node)的函数
  • ros::service:包含查询服务的函数
  • ros::param:包含查询参数服务器的函数,而不需要用到NodeHandle
  • ros::names:包含处理ROS图资源名称的函数

具体可见:http://docs.ros.org/api/roscpp/html/index.html

以上功能可以分为以下几类:

  • Initialization and Shutdown 初始与关闭
  • Topics 话题
  • Services 服务
  • Parameter Server 参数服务器
  • Timers 定时器
  • NodeHandles 节点句柄
  • Callbacks and Spinning 回调和自旋(或者翻译叫轮询?)
  • Logging 日志
  • Names and Node Information 名称管理
  • Time 时钟
  • Exception 异常

三、talker与 lisener

Topic是ROS里一种异步通信的模型,一般是节点间分工明确,有的只负责发送,有的只负责接收处理。对于绝大多数的机器人应用场景,比如传感器数据收发,速度控制指令的收发,Topic模型是最适合的通信方式。为了能都够想明白topic通信的编程思路,我们首先来看 topicLisener 中的代码,这个程序是一个消息收发的例子:自定义一个类型为distance的消息(包括位置x,y和工作状态state信息),一个node以一定频率发布模拟的distance消息,另一个node接收并处理,算出到原点的距离。我们分析一下源码:
1、首先创建diatance 消息
在代码中,我们会用到自定义类型的diatance 消息,因此就需要来自定义diatance 消息,在msg路径下
创建 diatance .msg : 见 topicLisener /msg/diatance .msg

string state #工作状态
float32 x #x坐标
float32 y #y坐标

以上就定义了一个diatance 类型的消息,你可以把它理解成一个C语言中的结构体,类似于

struct diatance 
{
	string state;
	float32 x;
	float32 y;
}

在程序中对一个diatance 消息进行创建修改的方法和对结构体的操作一样。

当创建完了msg文件,记得修改 CMakeLists.txt 和 package.xml ,从而让系统能够编译自定义消息。 在 CMakeLists.txt 中需要改动

find_package(catkin REQUIRED COMPONENTS
	roscpp
	std_msgs
	message_generation # //需要添加的地方
)
add_message_files(FILES diatance.msg)
#//catkin在cmake之上新增的命令,指定从哪个消息文件生成
generate_messages(DEPENDENCIES std_msgs)
#//catkin新增的命令,用于生成消息
#//DEPENDENCIES后面指定生成msg需要依赖其他什么消息,由于gps.msg用到了flaot32这种ROS标准消息,因此需要再把std_msgs作为依赖

add_executable(talker src/talker.cpp) #//生成可执行文件talker
add_dependencies(talker topicLisener_generate_messages_cpp)#//表明在编译talker前,必须先生编译完成自定义消息
#//必须添加add_dependencies,否则找不到自定义的msg产生的头文件
#//表明在编译talker前,必须先生编译完成自定义消息
target_link_libraries(talker ${catkin_LIBRARIES}) #//链接
add_executable(listener src/listener.cpp ) #//声称可执行文件listener
add_dependencies(listener topicLisener_generate_messages_cpp)
target_link_libraries(listener ${catkin_LIBRARIES})#//链接

package.xml 中需要的改动

<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>

当你完成了以上所有工作,就可以回到工作空间,然后编译了。编译完成之后会在 devel 路径下生成 diatance.msg 对应的头文件,头文件按照C++的语法规则定义了topicLisener ::diatance类型的数据。要在代码中使用自定义消息类型,只要 #include 然后声明,按照对结构体操作的方式修改内容即可。

topicLisener::diatancemygpsmsg;
mygpsmsg.x = 1.6;
mygpsmsg.y = 5.5;
mygpsmsg.state = "working";

talker.cpp

//ROS头文件
#include 
//自定义msg产生的头文件
#include 

int main(int argc, char **argv)
{
  //用于解析ROS参数,第三个参数为本节点名
  ros::init(argc, argv, "talker");

  //实例化句柄,初始化node
  ros::NodeHandle nh;

  //自定义distance msg
  topicListener::distance msg;
  msg.x = 1.0;
  msg.y = 1.0;
  msg.state = "working";

  //创建publisher
  ros::Publisher pub = nh.advertise<topicListener::distance>("distance_info", 1);

  //定义发布的频率 
  ros::Rate loop_rate(1.0);
  //循环发布msg
  while (ros::ok())
  {
    //以指数增长,每隔1秒更新一次
    msg.x = 1.03 * msg.x ;
    msg.y = 1.01 * msg.y;
    ROS_INFO("Talker: GPS: x = %f, y = %f ",  msg.x ,msg.y);
    //以1Hz的频率发布msg
    pub.publish(msg);
    //根据前面定义的频率, sleep 1s
    loop_rate.sleep();//根据前面的定义的loop_rate,设置1s的暂停
  }

  return 0;
} 

lisener.cpp

//ROS头文件
#include 
//包含自定义msg产生的头文件
#include 
//ROS标准msg头文件
#include 

void distanceCallback(const topicListener::distance::ConstPtr &msg)
{  
    //计算离原点(0,0)的距离
    std_msgs::Float32 distance;
    distance.data = sqrt(pow(msg->x,2)+pow(msg->y,2));
    //float distance = sqrt(pow(msg->x,2)+pow(msg->y,2));
    ROS_INFO("Listener: Distance to origin = %f, state: %s",distance.data,msg->state.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("distance_info", 1, distanceCallback);
  //ros::spin()用于调用所有可触发的回调函数。将进入循环,不会返回,类似于在循环里反复调用ros::spinOnce()。
  ros::spin(); 
  return 0;
}

执行测试

cd  catkin_ws   //进入工作空间
catkin_make   //编译

roscore  // 新的终端
rosrun topicListener talker  //新终端 执行前source
rosrun topicLIstener lisener  //新终端 执行前source

ROS中的Client Library与roscpp talker lisener_第3张图片

参考:ROS机器人操作系统讲义

你可能感兴趣的:(ROS)