ROS学习笔记7:话题发布与订阅(实践作业)

前言:

        在笔记3中,我们提到ROS的核心是分布式通信机制,基本通信方式分为话题通信机制(异步通信机制)、服务通信机制(同步通信机制)参数管理机制三大类,本节介绍话题通信机制。

ROS学习笔记7:话题发布与订阅(实践作业)_第1张图片

一、发布者Publisher的编程实现:

1.实现目标:通过编程发布速度指令,使小海龟运动。

2.创建功能包:

ROS学习笔记7:话题发布与订阅(实践作业)_第2张图片

ROS学习笔记7:话题发布与订阅(实践作业)_第3张图片

3.编写publisher(C++实现):

        如何编写Publisher:

(1)初始化ROS节点,创建名为“Velocity_publisher”的节点;

(2)向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;

(3)创建消息数据;

(4)循环发布数据。

        代码如下:

/**
 * 该例程将发布turtle1/cmd_vel话题,消息类型geometry_msgs::Twist
 */
 
#include 
#include 

int main(int argc, char **argv)
{
	// ROS节点初始化
	ros::init(argc, argv, "velocity_publisher");//节点名(不允许重复)

	// 创建节点句柄,管理ROS的相关资源
	ros::NodeHandle n;

	// 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
	ros::Publisher turtle_vel_pub = n.advertise("/turtle1/cmd_vel", 10);

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

	int count = 0;
	while (ros::ok())
	{
	    // 初始化geometry_msgs::Twist类型的消息
		geometry_msgs::Twist vel_msg;
		vel_msg.linear.x = 0.5;
		vel_msg.angular.z = 0.2;

	    // 发布消息
		turtle_vel_pub.publish(vel_msg);
		ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]", 
				vel_msg.linear.x, vel_msg.angular.z);

	    // 按照循环频率延时
	    loop_rate.sleep();
	}

	return 0;
}

4.将上述代码粘贴到功能包"learning_topic"的src目录下:

ROS学习笔记7:话题发布与订阅(实践作业)_第4张图片

5.配置CMakeLists.txt中的编译规则:

(1)打开功能包目录下的CMakeLists.txt文件:

ROS学习笔记7:话题发布与订阅(实践作业)_第5张图片

(2)加入以下两行代码:

1)add_executable:设置需要编译的代码和生成的可执行文件。第一个参数为期望生成的可执行文件名称,第二个参数为参与编译的源码文件。

2)target_link_libraries:设置链接库。很多功能需要使用系统或第三方的库函数,通过该选项可以配置执行文件链接的库文件。
 

6.编译并运行Publisher:

(1)编译工作空间:

ROS学习笔记7:话题发布与订阅(实践作业)_第6张图片

 (2)设置环境变量(相当于刷新一下工作空间):

(3)编译后的可执行文件位于home/catkin_ws/devel/lib/pkgconfig目录下:

编译前的文件夹:

ROS学习笔记7:话题发布与订阅(实践作业)_第7张图片

编译后的文件夹:

ROS学习笔记7:话题发布与订阅(实践作业)_第8张图片

ROS学习笔记7:话题发布与订阅(实践作业)_第9张图片

 ROS学习笔记7:话题发布与订阅(实践作业)_第10张图片

         velocity_publisher即为编译后的可执行文件。

(4)启动节点管理器:

ROS学习笔记7:话题发布与订阅(实践作业)_第11张图片

(5)设置环境变量,打开小乌龟仿真窗口:

ROS学习笔记7:话题发布与订阅(实践作业)_第12张图片

(6)设置环境变量,执行程序:

ROS学习笔记7:话题发布与订阅(实践作业)_第13张图片

        注意事项:每打开一个节点都需要重新设置工作空间的环境变量,否则会出现找不到工作空间的错误。

二、订阅者Subscriber的编程实现:

1.实现目标:

        订阅者订阅小海龟的pose信息。

2.编写Subscriber(C++实现):

(1)初始化ROS节点,创建名为“pose_subscriber”的节点;

(2)订阅需要的话题;

(3)循环等待话题消息,接收到消息后进入回调函数;

(4)在回调函数中完成消息处理。

/**
 * 该例程将订阅/turtle1/pose话题,消息类型turtlesim::Pose
 */
 
#include 
#include "turtlesim/Pose.h"

// 接收到订阅的消息后,会进入消息回调函数
// msg是一个常指针,指向turtlesim::Pose的所用内容
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Turtle pose: x:%0.6f, y:%0.6f", msg->x, msg->y);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "pose_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
    ros::Subscriber pose_sub = n.subscribe("/turtle1/pose", 10, poseCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}

3.将上述代码粘贴到功能包"learning_topic"的src目录下:

4.配置CMakeLists.txt中的编译规则:

5.编译并运行Subscriber:

(这里不再赘述详细过程,直接给出运行结果)

三、话题消息的自定义与使用:

1.实现目标:

        自定义消息类型文件,Publisher发布该消息,Subscriber接收。

2.定义msg文件:

ROS学习笔记7:话题发布与订阅(实践作业)_第14张图片

ROS学习笔记7:话题发布与订阅(实践作业)_第15张图片

3.为了使用这个自定义的消息类型,需要编译msg文件:

(1)在package.xml中添加功能包依赖:

ROS学习笔记7:话题发布与订阅(实践作业)_第16张图片

  

(2)在CMakeLists中添加编译选项:

ROS学习笔记7:话题发布与订阅(实践作业)_第17张图片

ROS学习笔记7:话题发布与订阅(实践作业)_第18张图片

4. 编写person_publisher和person_subscriber:

(1)person_publisher:

/**
 * 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include 
#include "learning_topic/Person.h"

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "person_publisher");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    ros::Publisher person_info_pub = n.advertise("/person_info", 10);

    // 设置循环的频率
    ros::Rate loop_rate(1);

    int count = 0;
    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
    	learning_topic::Person person_msg;
		person_msg.name = "Tom";
		person_msg.age  = 18;
		person_msg.sex  = learning_topic::Person::male;

        // 发布消息
		person_info_pub.publish(person_msg);

       	ROS_INFO("Publish Person Info: name:%s  age:%d  sex:%d", 
				  person_msg.name.c_str(), person_msg.age, person_msg.sex);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}

(2)person_subscriber:

/**
 * 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include 
#include "learning_topic/Person.h"

// 接收到订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s  age:%d  sex:%d", 
			 msg->name.c_str(), msg->age, msg->sex);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "person_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}

4.将上述代码粘贴到功能包"learning_topic"的src目录下:

5.配置CMakeLists.txt中的编译规则:

ROS学习笔记7:话题发布与订阅(实践作业)_第19张图片

6.编译并运行:

ROS学习笔记7:话题发布与订阅(实践作业)_第20张图片

你可能感兴趣的:(ROS编程技术,学习)