ROS realizes simple communication programming

Overview

Use intelligent robots to realize simple communication programming——话题、服务、动作。

1. Create a workspace

1. What is a workspace

The workspace (workplace) is a folder for storing project development-related files.

  • src: Code space (source space)
  • build: Build space
  • devel:Development space (development space)
  • install: Install space

2. Create a workspace

The instructions are as follows:

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

Insert picture description here
Compile workspace

cd ..
catkin_make

Insert picture description here
Insert picture description here
Set environment variables

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

Insert picture description here

Insert picture description here
Check environment variables

echo $ROS_PACKAGE_PATH

Insert picture description here

3. Create a feature pack

The instructions are as follows:

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

Insert picture description here
Insert picture description here
Compile function package

cd ~/catkin_ws
catkin_make

Insert picture description here

同一个工作空间下,不允许存在同名功能包;不同空间下,允许存在同名功能包。

4. Coverage of working space

The overlaying mechanism of the ros workspace, that is, the coverage of the workspace;
Insert picture description here

  • The path of the workspace is recorded in the ROS_PACKAGE_PATH environment variable in turn;
  • The newly set path will be automatically placed at the forefront in ROS_PACKAGE_PATH;
  • When running, ROS will first look for the specified function package in the front-end workspace;
  • If it does not exist, other workspaces will be searched backward in sequence.

Two, communication programming-topic

1. Topic programming process

  • Create publisher
  • Create subscriber
  • Add compilation options
  • Run executable program
    Insert picture description here

2. Implementation of the publisher

  • Initialize the ROS node;
  • Register node information with ROS Master, including the name of the published topic and the message type in the topic;
  • Circulate news at a little frequency;

talker.cpp

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

3. The realization of subscribers

  • Initialize the ROS node;
  • Subscribe to the topics needed;
  • Wait for the topic message in a loop, and enter the callback function after receiving the message;
  • Complete the message processing in the callback function;
    listener.cpp
#include"ros/ros.h"
#include"std_msgs/String.h"
//接收到订阅的消息,会进入消息的回调函数
void chatterCallback(const std_mmsgs::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;
}

4. Compile the code

Set the CMakeLists.txt file;
Insert picture description here
Insert picture description here

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

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

Compile

catkin_make

Insert picture description here
Run the executable file

roscore
rosrun learning_communication talker
rosrun learning_communication listener

5. Custom topics

Define msg file

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

Insert picture description here
person.msg

string name
uint8 sex
uint8 age

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

Add function package dependency in package.xml

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

In some ROS versions, exec_depend needs to be modified to run_depend

Add compilation options in CMakeLists.txt
Insert picture description here
Insert picture description here
Insert picture description here
View custom messages

rosmsg show Person

Insert picture description here

Three, communication programming-service

1. Service programming process

  • Create server
  • Create a client
  • Add compilation options
  • Run the executable file

Insert picture description here
Custom server request and response
Define srv file

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

AddTwoInts.srv

int64 a
int64 b
---
int64 sum

Add function package dependency in package.xml

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

In some ROS versions, exec_depend needs to be modified to run_depend

Add compilation options in cmakelist.txt

find_package(...... message_generation)

catkin_package(CATKIN_DEPENDS geometry roscpp rospy std_msgs message_runtime)

add_service_files(FILES AddTwolnts.srv)

Insert picture description here
Insert picture description here
Insert picture description here

2. The realization of the server

  • Initialize the ROS node
  • Create server instance
  • Wait for the service request in a loop and enter the callback function
  • Complete the processing of the service function in the callback function, and feedback the response data
    server.cpp
#include<ros/ros.h>
#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;
}

3. Implementation of the client

  • Initialize the ROS node
  • Create a client instance
  • Publish service request data
  • Waiting for the response result
    client.cpp after server processing
#include<cstdlib>
#include<ros/ros.h>
#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;
}

4. Compile the code

Set up the CMakeLists.txt file

Four, communication programming-action

1. Custom action message

Define action file

mkdir ~/catkin_ws/src/learning_communication/action
sudo nano DoDishes.action

DoDishes.action

#定义目标信息
uint32 dishwasher_id
---
#定义结果信息
uint32 total_dishes_cleaned
---
#定义周期反馈的消息
float32 percent_complete

Add function package dependency in package.xml

<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>

Insert picture description here
Insert picture description here

2. Implement an action server

  • Initialize the ROS node
  • Create an action server instance
  • Start the action server. Wait for action request
  • Complete the processing of the action service function in the callback function, and feedback the progress information
  • The action is complete, send the end message

DoDishes_server.cpp

#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;
// 收到action的goal后调用该回调函数
void execute(const learning_communication::DoDishesGoalConstPtr &goal, Server *as)
{
    
    
	ros::Rate r(1);
	learning_communication::DoDishesFeedback feedback;
	ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);
	// 假设洗盘子的进度,并且按照1Hz的频率发布进度feedback 
	for(int i = 1; i <= 10; i++)
	{
    
    
		feedback.percent_complete = i * 10;
		as->publishFeedback(feedback);
		r.sleep();
	}	
	// 当action完成后,向客户端返回结果
	ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
	as->setSucceeded();
}
int main(int argc, char **argv)
{
    
    
	ros::init(argc, argv, "do_dishes_server");
	ros::NodeHandle hNode;
	// 定义一个服务器
	Server server(hNode, "do_dishes", boost::bind(&execute, _1, &server), false);
	// 服务器开始运行
	server.start();
	ros::spin();
	return 0;
}

3. Implement an action client

  • Initialize the ROS node
  • Create an action client instance
  • Connect action server
  • Send action target
  • Process the callback function
    DoDishes_client.cpp according to different types of server feedback
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;
// 当action完成后会调用该回调函数一次
void doneCallback(const actionlib::SimpleClientGoalState &state
	, const learning_communication::DoDishesResultConstPtr &result)
{
	ROS_INFO("Yay! The dishes are now clean");
	ros::shutdown();
}
// 当action激活后会调用该回调函数一次
void activeCallback()
{
	ROS_INFO("Goal just went active");
}
// 收到feedback后调用该回调函数
void feedbackCallback(const learning_communication::DoDishesFeedbackConstPtr &feedback)
{
	ROS_INFO("percent_complete : %f", feedback->percent_complete);
}
int main(int argc, char **argv)
{
	ros::init(argc, argv, "do_dishes_client");
	// 定义一个客户端
	Client client("do_dishes", true);
	// 等待服务器端
	ROS_INFO("Waiting for action server to start.");
	client.waitForServer();
	ROS_INFO("Action server started, sending goal.");
	// 创建一个 action 的 goal
	learning_communication::DoDishesGoal goal;
	goal.dishwasher_id = 1;
	// 发送action的goal给服务端,并且设置回调函数
	client.sendGoal(goal, &doneCallback, &activeCallback, &feedbackCallback);
	ros::spin();
	return 0;
}

4. Compile the code

Set up the CMakeLists.txt file

Five, summary and reference materials

1. Summary

I have a certain understanding of the basics of ROS-communication programming, and it still feels a bit troublesome to do it, but there are similar tutorial materials on the Internet, and you can do it step by step. Baidu will solve the problem in the middle.

2. Reference materials

ROS operating system study notes under ubuntu16.04 (3 / 2) ROS basics-ROS communication programming .

Guess you like

Origin blog.csdn.net/QWERTYzxw/article/details/114917159