ros知识点总结—话题

消息查询

rostopic list
/*
/rosout
/rosout_agg
/turtle1/cmd_vel   //速度控制话题
/turtle1/color_sensor //改变背景颜色话题
/turtle1/pose    //姿态位置话题
*/

rostopic info /turtle1/cmd_vel 
/*topic 
Type: geometry_msgs/Twist

Publishers: 
 * /teleop_turtle (http://localhost:34999/)

Subscribers: 
 * /turtlesim (http://localhost:36611/)
*/
//很明显,该话题是键盘控制节点发布,小乌龟去订阅
rostopic info /turtle1/pose 
/*
Type: turtlesim/Pose

Publishers: 
 * /turtlesim (http://localhost:36611/)

Subscribers: None
*/
//该话题由小乌龟节点发布,目前还没有订阅者

话题 发布/订阅 (强烈推荐安装vscode等,会有提示,写代码非常方便)

发布案例

该例发布turtle1/cmd_vel话题,消息类型geometry_msgs::Twist来控制小乌龟的移动,为什么话题名一定要是这样,因为小乌龟本身一直在订阅该话题来实现移动,故我们发布该话题,小乌龟就会自动订阅,实现移动,对后期来说,话题名我们自己定,发布写好后,在写订阅者,只要两者的话题相同即可。但对于特定的,比如小乌龟,turtlebot,无人机等一系列仿真,他们的控制都已经封装好了,我们只需要发布即可,订阅是自动的,这种时候就一定要查询话题,才能动手写,查询就如文章一开始那样,先运行你的功能包,在查阅话题即可。
//前提:启动roscore,和rosrun turtlesim turtlesim_node
cpp代码:


//rostopic list //查找所需话题
//rostopic info turtle1/cmd_vel //查找所需话题的消息类型
//rosmsg info geometry_msgs::Twist //查找具体消息类型格式

 
#include <ros/ros.h>
#include <iostream>
#include <geometry_msgs/Twist.h> //都需要添加消息类型对应的头问件

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

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

	// 创建一个Publisher,发布话题名为/turtle1/cmd_vel,该话题消息类型为geometry_msgs::Twist,队列长度1   ----都是通过前面查询到的;
	ros::Publisher pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1);
	//注意格式即可; <>里是消息类型,advertise的第一个参数是话题名,第二个是队列长度,具体可以看前面对advertise函数介绍

	// 设置循环的频率 
	ros::Rate rate(10); //周期T = 1/10
	
	while (ros::ok())
	{
	    // 初始化geometry_msgs::Twist类型的消息
		geometry_msgs::Twist msg;//rosmsg查询出消息的具体格式
		msg.linear.x = 0.1;
		msg.angular.z = 0.1;

	    // 发布消息
		pub.publish(msg);
		ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]", msg.linear.x, msg.angular.z);
		std::cout<<"v_x: "<<msg.linear.x<< "  w_z: " << msg.angular.z<<endl;//等价上面

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

	return 0;
}

订阅案例

该案例订阅小乌龟的位置信息turtle1/pose,消息类型turtlesim/Pose,情景,在键盘控制下,小乌龟一直移动,则小乌龟的位置消息会一直更新,我们通过订阅该消息,在终端显示,接收到的位置消息
//前提:启动roscore,和rosrun turtlesim turtlesim_node,以及 rosrun turtlesim turtle_teleop_key
cpp代码:


 //rostopic list
 //rostopic info /turtle1/pose
 //rosmsg info turtlesim/Pose 
 
#include <ros/ros.h>
#include <iostream>
#include "turtlesim/Pose.h"
// 消息回调函数
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Turtle pose: x:%0.6f, y:%0.6f", msg->x, msg->y);
    std::cout<<"Turtle pose: x : "<<msg->x<<" ,y : " << msg->y<<std::endl;//上述两条等价,
}

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;
}

在话题发布订阅中使用自定义类型的消息类型

自定义消息

案例:设计一个表示学生的消息类型,包括姓名,年龄,性别,分数。
然后通过一个节点将该消息发布出去,在通过另一个节点订阅显示。

//首先建立消息
//在功能包下创建一个文件夹msg用来放自定义消息
//ros中的自定义消息比较简单,创建一个msg文件,按一定格式编写即可
//在msg文件夹下,创建文件student.msg打开写入
string name
uint8  age
uint8  sex
//其次配置功能包下相关文件
//package.xml
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

//CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
  geometry_msgs//常见类型消息
  roscpp//c++文件格式
  rospy//python文件格式
  std_msgs//一些常用的标准消息
  turtlesim//小乌龟相关消息
  message_generation//自定义msg文件
)//添加依赖
add_message_files(
  FILES
  student.msg//这里是你的msg文件名加后缀
)
generate_messages(
  DEPENDENCIES
  std_msgs
)//因为我们的msg文件里使用到string uint8等类型都是std_msgs里面的,所有需要依赖它来解析我们的msg文件
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES learning_topic
   CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime
#  DEPENDS system_lib
)//添加了message_runtime


//编译运行,就会在工作空间下devel/include/功能包名/找到对应的头文件
//至此我们的消息创建成功。
//编译一下,就会出现对于的头文件,该消息的类型名是: 功能包名:msg文件名

自定义消息发布

发布 cpp代码

 //其实在这里话题名可以自己随便起 ,比如 stu_msg 消息类型自然是我们写的,不过要注意的是,头文件路径只包含到include,故我们包含头文件 #include "learning_topic/student.h" 消息类型learning_topic::student
 
#include <ros/ros.h>
#include <iostream>
#include "learning_topic/student.h"

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "stu_publisher");
    // 创建节点句柄
    ros::NodeHandle n;
    // 创建一个Publisher,发布名为/stu_msg的topic,消息类型为learning_topic::student,队列长度1
    ros::Publisher pub = n.advertise<learning_topic::studnet>("/stu_msg", 1);
    // 循环频率
    ros::Rate rate(1);

    while (ros::ok())
    {
        // 初始化learning_topic::studnet类型的消息
    	learning_topic::studnet msg;
		msg.name = "xiangwang";
		msg.age  = 22;
		msg.sex  = 1;
        // 发布消息
		pub.publish(msg);
       	std::cout<<"name = " << msg.name << std::endl;
        rate.sleep();
    }//按照循环频率发布消息,也可以参考advertise函数讲解,利用可选参数,发布一次也可以。

    return 0;
}//编译完成后,启动roscore,启动该节点,利用rostopic list就可以查看到该话题

`

自定义消息订阅

`

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

// 接收到订阅的消息后,会进入消息回调函数
void stu_back(const learning_topic::student& msg)
{
    // 消息打印
	std::cout<<"name = :" << msg.name << "  , age = :" << msg.age<<std::endl;
}

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

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

    // 创建一个Subscriber,订阅名为/stu_msg的topic,注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe("/stu_msg", 10, stu_back);
    // 循环等待回调函数
    ros::spin();
    return 0;
}

总结

到此为止,话题的发布订阅简单使用就结束了,一般在项目中,通常会出现下列情况:
1:同一个节点需要订阅多个节点;
2:话题发布经常在回调函数中;
3:经常将发布订阅写在类中实现;
针对1:会出现需要话题同步–需要融合多个消息,或者多线程问题—各自订阅不受干扰。—后面在讲消息同步和多线程问题
针对2:一般会在回调函数中对数据进行处理,然后将处理结果或者一种控制信息发布出去,就需要在回调函数中发布消息,后期讲如何处理;
3:大型项目基本都是按类封装,我们可以借鉴这种写法;

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值