ROS topic使用

一、创建ros工作空间ros_ws

$ mkdir -p ~/ros_ws/src
$ cd ~/ros_ws
$ catkin_make  #将ros_ws文件夹初始化为ros的工作空间

此时的工程结构:
install:安装空间,通常与devel合为一个
src:代码空间,存放package源代码
build:编译空间,camke&catkin缓存和中间文件
devel:开发空间,存放生成的目标文件、头文件、动态链接库、静态链接库和可执行文件。

设置环境变量

$ source ~/ros_ws/devel/setup.bash

此方法设置环境变量仅在当前终端有效。

$ gedit ~/.bashrc
source ~/ros_ws/devel/setup.bash
$ source ~/.bashrc  #使配置文件生效

此方法设置环境变量永久有效。

$ echo $ROS_PACKAGE_PATH  #查看ros路径

二、创建功能包

$ cd ~/ros_ws/src
$ catkin_create_pkg topic_demo roscpp rospy std_msgs

其中,topic_demo为功能包名,添加roscpp(ROS提供的c++结构)、rospy(ROS提供的python结构)、std_msgs(ROS定义好的标准数据结构)依赖。

三、rostopic介绍
1、topic是ROS中的异步通信方式,即只发送,不管有没有对象接收,或者只接收,不管是谁发送的。Node之间通过publish-subscribe机制通信。
2、rostopic常用指令:

$ rostopic list	#列出当前所有topic
$ rostopic info/topic_name #显示指定topic属性信息
$ rostopic echo/topic_name	#显示指定topic内容
$ rostopic pub/topic_name	#向指定topic发布内容

四、rostopic代码实现

$ cd topic_demo/src
$ gedit listener.cpp
$ gedit talker.cpp

创建listener.cpp文件

/**
 * 该例程将订阅chatter话题,消息类型String
 */
 
#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节点
  ros::init(argc, argv, "listener");

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

  // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  //订阅第二个名为chatter1的topic,如果实现功能不同,可重写回调函数
  ros::Subscriber sub1 = n.subscribe("chatter1", 1000, chatterCallback);

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

  return 0;
}

创建talker.cpp文件

/**
 * 该例程将发布chatter话题,消息类型String
 */
 
#include 
#include "ros/ros.h"
#include "std_msgs/String.h"

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

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

  int count = 0;
  while (ros::ok())
  {
	// 初始化std_msgs::String类型的消息
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello jingbaixue " << count;
    msg.data = ss.str();

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

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

  return 0;
}

关于ros::spin()和ros::spinOnce():

相同点:都是检测是否有数据进来,如果有数据进来则进行数据处理,因此ros::spinOnce()在publisher程序中没有任何意义。Subscriber中ros::spin()检测到数据进来则进行数据处理,调用chatterCallback()函数。
不同点:ros::spinOnce()只检测一次,如果有数据进来,则进行数据处理;若没有数据进来,则继续执行下一步;ros::spin()会循环检测,如果有数据进来,则进行数据处理,如果没有数据进来,则一直等待检测,所以在subscriber程序中,接收到publisher数据后会一直循环在chatterCallback()函数中,程序执行到ros::spin()会进入无限循环,直到进程结束,所以在ros::spin()语句后任何语句都没有意义,且ros::spin()语句一般不放入while循环中。

Subscriber程序中参数1000的含义:
1000表示队列长度,如果数据发送过快,系统会将来不及处理的数据存入队列中,当队列存满时,自动删除时间戳较早的数据,因此数据发送过快可能会出现丢包、断帧的情况。

CMakeList.txt文件中添加:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
  actionlib_msgs 
  actionlib
)  #指定依赖


add_executable(talker src/talker.cpp) #生成可执行文件
target_link_libraries(talker ${catkin_LIBRARIES})

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})

可执行文件也可由多个cpp文件生成,如:

add_executable(talker src/talker1.cpp talker2.cpp talker3.cpp)

五、topic通信

$ cd ~/ros_ws
$ catkin_make 

生成可执行文件listener和talker保存在“ros_ws/devel/lin/topic_demo/”路径下。
打开一个终端:

$ roscore  #启动ROS

重新打开一个终端

$ rosrun topic_demo listener

再打开一个新的终端

$ rosrun topic_demo talker

ROS topic使用_第1张图片
六、转发topic信息,即订阅一个topic,同时将该topic信息发布出去

#include 
#include "ros/ros.h"
#include "std_msgs/String.h"

class subscribeAndpublish()
{
	public:
		subscribeAndpublish()
		{
			sub=n.subscribe("chatter",1000,&subscribeAndpublish::callback,this);
			senddata_pub=n.advertise<std_msgs::String>("send",1000);
		}
		void callback(const std_msgs::String::ConstPtr& msg)
		{
			std_msgs::String message;
			message.data = msg->data.c_str();
			ROS_INFO("I heard:[%s]", msg->data.c_str());
			senddata_pub.publish(message);
		}
	private:
		ros::NodeHandle n;
		ros::Subscriber sub;
		ros::Publisher senddata_pub;
};

int main(int argc, char** argv)
{
	ros::init(argc, argv, "landt");
	subscribeAndpublish SAPObject;
	ros::spin();
	return 0;
}

你可能感兴趣的:(ROS)