ROS话题通信、服务通信编程

ROS话题通信、服务通信编程

  • ros的工作空间
      • 创建工作空间
      • 编译工作空间
      • 环境变量设置
  • 功能包
      • 创建功能包
      • 编译功能包
  • ROS通信编程
    • 1.话题编程
      • 自定义话题消息
    • 2.服务编程

ros的工作空间

主要是一些存放工程开发相关文件的文件夹,其中主要包括src,build,devel,install文件夹。
其中:

src:代码空间(Source Space )
build:编译空间(Build Space)
devel:开发空间(Development Space)
install:安装空间(Install Space)

创建工作空间

创建工作空间是第一步,只有先创建好工作空间,后面的工作才能很好的执行

mkdir -p ~/catkin_ws/src#创建文件夹
cd ~/catkin_ws/src#进入目录
catkin_init_workspace#初始化,使其成为ROS的工作空间

在这里插入图片描述

编译工作空间

cd ..
catkin_make

ROS话题通信、服务通信编程_第1张图片
可以看到,在目录下自动生成了两个文件build、devel
ROS话题通信、服务通信编程_第2张图片

环境变量设置

source /home/shi/catkin_ws/devel/setup.bash#该环境变量设置只对当前终端有效,shi是用户名
#将上面命令放置到~/.bashrc文件中,让其对所有终端都有效
sudo nano ~/.bashrc

在这里插入图片描述
ROS话题通信、服务通信编程_第3张图片
检查环境变量

echo $ROS_PACKAGE_PATH

在这里插入图片描述
到此,工作空间环境就弄好了

功能包

创建功能包

cd ~/catkin_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp

#catkin_create_pkg 功能包名字 依赖
#std_msgs:定义的标准的数据结构
#rospy:提供python编程接口 
#roscpp:提供c++编程接口

在这里插入图片描述

编译功能包

cd ~/catkin_ws
catkin_make

ROS话题通信、服务通信编程_第4张图片
注意,在同一个工作空间,不能有相同名字的包

ROS通信编程

准备工作做完了,开始进入正题

1.话题编程

步骤:

1.创建发布者
1)初始化ROS节点
2)向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
3)按照一定频率循环发布消息
2.创建订阅者
1)初始化ROS节点
2)订阅需要的话题
3)循环等待话题消息,接受到消息后进行回调函数
4)回调函数中完成消息处理
3. 添加编译选项
1)设置需要编译的代码和生成的可执行文件
2)设置链接库
3)设置依赖
4.运行可执行程序

创建cpp文件

gedit talker.cpp
gedit listener.cpp

talker.cpp

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

listener.cpp

#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);
	//循环等待回调函数
	ros::spin();
	return 0;
}

设置CMakeLists.txt文件

加入以下代码

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

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

ROS话题通信、服务通信编程_第5张图片
编译
ROS话题通信、服务通信编程_第6张图片
查看生成的可执行文件
ROS话题通信、服务通信编程_第7张图片
运行

roscore
rosrun learning_communication talker
rosrun learning_communication listener


出现“[rospack]Error:package ‘learning_communication’ not found”错误
解决方法:
sudo gedit ~/.bashrc
在末尾添加source /home/xxx/catkin_ws/devel/setup.bash
这里xxx指的是自己的用户名

自定义话题消息

定义msg文件

mkdir ~/catkin_ws/src/learning_communication/msg
sudo nano Person.msg

Person.msg(注意,该文件的权限如果是只读的话,可能会出错)

string name
uint8 sex
uint8 age

uint8 unknown=0
uint8 male=1
uint8 female=2

在package.xml中添加功能包依赖

message_generation
message_runtime

ROS话题通信、服务通信编程_第8张图片
在这里插入图片描述
ROS话题通信、服务通信编程_第9张图片
ROS话题通信、服务通信编程_第10张图片

编译
ROS话题通信、服务通信编程_第11张图片
查看自定义消息

rosmsg show Person

ROS话题通信、服务通信编程_第12张图片

2.服务编程

定义服务请求与应答的方式

1.定义srv文件

mkdir ~/catkin_ws/src/learning_communication/srv
sudo nano AddTwoInts.srv

AddTwoInts.srv

int64 a
int64 b
---
int64 sum

在这里插入图片描述
2.在package.xml中添加功能包依赖

message_generation
message_runtime

ROS话题通信、服务通信编程_第13张图片
3.在CMakeLists.txt添加编译选项
ROS话题通信、服务通信编程_第14张图片
ROS话题通信、服务通信编程_第15张图片
ROS话题通信、服务通信编程_第16张图片
步骤:

创建服务器

  1. 初始化ROS节点
  2. 创建Serve实例
  3. 循环等待服务请求,进入回调函数
  4. 在回调函数中完成服务功能的处理,并反馈应答数据

创建客户端

  1. 初始化ROS节点
  2. 创建一个Client实例
  3. 发布服务请求数据
  4. 等待Serve处理之后的应答结果

添加编译选项

  1. 设置需要编译的代码和生成的可执行文件
  2. 设置链接库
  3. 设置依赖

运行可执行程序

在src 里创建cpp文件

gedit server.cpp
gedit client.cpp
server.cpp
#include
#include"learning_communication/AddTwoInts.h"
//service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwoInts::Request &req,learning_communication::AddTwoInts::Response &res)
{
     
	//将输入的参数中的请求数据相加,结果放到应答变量中
	res.sum=req.a+req.b;
	ROS_INFO("request: x=%1d,y=%1d",(long int)req.a,(long int)req.b);
	ROS_INFO("sending back response:[%1d]",(long int)res.sum);
	return true;
}
int main(int argc,char **argv)
{
     
	//ROS节点初始化
	ros::init(argc,argv,"add_two_ints_server");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个名为add_two_ints的server,注册回调函数add()
	ros::ServiceServer service=n.advertiseService("add_two_ints",add);
	//循环等待回调函数
	ROS_INFO("Ready to add two ints.");
	ros::spin();
	return 0;
}

client.cpp

#include
#include
#include"learning_communication/AddTwoInts.h"
int main(int argc,char **argv)
{
     
	//ROS节点初始化
	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;
	//创建一个client,请求add_two_ints_service
	//service消息类型是learning_communication::AddTwoInts
	ros::ServiceClient client=n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
	//创建learning_communication::AddTwoInts类型的service消息
	learning_communication::AddTwoInts srv;
	srv.request.a=atoll(argv[1]);
	srv.request.b=atoll(argv[2]);
	//发布service请求,等待加法运算的应答请求
	if(client.call(srv))
	{
     
		ROS_INFO("sum: %1d",(long int)srv.response.sum);
	}
	else
	{
     
		ROS_INFO("Failed to call service add_two_ints");
		return 1;
	}
	return 0;
}

设置CMakeLists.txt文件
ROS话题通信、服务通信编程_第17张图片
查看生成的可执行文件
ROS话题通信、服务通信编程_第18张图片
运行可执行文件
先运行server,再运行client

roscore
rosrun learning_communication server
rosrun learning_communication client 整数1 整数2

ROS话题通信、服务通信编程_第19张图片

你可能感兴趣的:(linux)