ROS communication - topic, service and action mode programming

foreword

This blog is mainly to complete the ROS program design of the topic and service mode on Ubuntu, and practice ROS action programming: the client sends a motion coordinate to simulate the process of the robot moving to the target position. Including the code implementation of the server and client, requiring real-time position feedback.

1. Topic programming

1. Create a workspace

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

insert image description here

2. Compile workspace

cd ..
catkin_make

insert image description here
insert image description here

3. Set environment variables

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

4. Check environment variables

echo $ROS_PACKAGE_PATH

insert image description here

5. Create a feature package

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

insert image description here
insert image description here

6. Compile the function package

cd ~/catkin_ws
catkin_make

insert image description here

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

8. Create 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;
}

9. Set CMakeLists.txt

insert image description here

10. Compile

catkin_make

insert image description here
insert image description here

11. Run

roscore
rosrun learning_communication talker
rosrun learning_communication listener

insert image description here

2. Service programming

1. Define the srv file

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

AddTwoInts.srv

int64 a
int64 b
---
int64 sum

2. Add function package dependencies in package.xml

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

3. Add compilation options to CMakeLists.txt

insert image description here

insert image description here
insert image description here
insert image description here

4. Create 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;
}

5. Create client.cpp

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

6. Compile

catkin_make

Build an executable:
insert image description here

7. Run

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

insert image description here

3. Action programming

1. Create a new file turtleMove.cpp

insert image description here

/*
此程序通过通过动作编程实现由 client 发布一个目标位置
然后控制 Turtle 运动到目标位置的过程
*/
#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "comm/turtleMoveAction.h"
#include <turtlesim/Pose.h>
#include <turtlesim/Spawn.h>
#include <geometry_msgs/Twist.h>
typedef actionlib::SimpleActionServer<comm::turtleMoveAction> Server;
struct Myturtle
{
    
    
float x;
float y;
float theta;
}turtle_original_pose,turtle_target_pose;
ros::Publisher turtle_vel;
void posecallback(const turtlesim::PoseConstPtr& msg)
{
    
    
ROS_INFO("turtle1_position:(%f,%f,%f)",msg->x,msg->y,msg->theta);
turtle_original_pose.x=msg->x;
turtle_original_pose.y=msg->y;
turtle_original_pose.theta=msg->theta;
}
// 收到 action 的 goal 后调用该回调函数
void execute(const comm::turtleMoveGoalConstPtr& goal, Server* as)
{
    
    
comm::turtleMoveFeedback feedback;
ROS_INFO("TurtleMove is working.");
turtle_target_pose.x=goal->turtle_target_x;
- 3 -
turtle_target_pose.y=goal->turtle_target_y;
turtle_target_pose.theta=goal->turtle_target_theta;
geometry_msgs::Twist vel_msgs;
float break_flag;
while(1)
{
    
    
ros::Rate r(10);
vel_msgs.angular.z = 4.0 *
(atan2(turtle_target_pose.y-turtle_original_pose.y,
turtle_target_pose.x-turtle_original_pose.x)-turtle_original_pose.theta);
vel_msgs.linear.x = 0.5 *
sqrt(pow(turtle_target_pose.x-turtle_original_pose.x, 2) +
pow(turtle_target_pose.y-turtle_original_pose.y, 2));
break_flag=sqrt(pow(turtle_target_pose.x-turtle_original_pose.x, 2) +
pow(turtle_target_pose.y-turtle_original_pose.y, 2));
turtle_vel.publish(vel_msgs);
feedback.present_turtle_x=turtle_original_pose.x;
feedback.present_turtle_y=turtle_original_pose.y;
feedback.present_turtle_theta=turtle_original_pose.theta;
as->publishFeedback(feedback);
ROS_INFO("break_flag=%f",break_flag);
if(break_flag<0.1) break;
r.sleep();
}
// 当 action 完成后,向客户端返回结果
ROS_INFO("TurtleMove is finished.");
as->setSucceeded();
}
int main(int argc, char** argv)
{
    
    
ros::init(argc, argv, "turtleMove");
ros::NodeHandle n,turtle_node;
ros::Subscriber sub =
turtle_node.subscribe("turtle1/pose",10,&posecallback); //订阅小乌龟的位置
信息
turtle_vel =
turtle_node.advertise<geometry_msgs::Twist>("turtle1/cmd_vel",10);//发布控
制小乌龟运动的速度
// 定义一个服务器
- 4 -
Server server(n, "turtleMove", boost::bind(&execute, _1,
&server), false);
// 服务器开始运行
server.start();
ROS_INFO("server has started.");
ros::spin();
return 0;
}

2. Create a new "publish target location file" turtleMoveClient.cpp

insert image description here

#include <actionlib/client/simple_action_client.h>
#include "comm/turtleMoveAction.h"
#include <turtlesim/Pose.h>
#include <turtlesim/Spawn.h>
#include <geometry_msgs/Twist.h>
typedef actionlib::SimpleActionClient<comm::turtleMoveAction>
Client;
struct Myturtle
{
    
    
float x;
float y;
float theta;
}turtle_present_pose;
// 当 action 完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,
const comm::turtleMoveResultConstPtr& result)
{
    
    
- 5 -
ROS_INFO("Yay! The turtleMove is finished!");
ros::shutdown();
}
// 当 action 激活后会调用该回调函数一次
void activeCb()
{
    
    
ROS_INFO("Goal just went active");
}
// 收到 feedback 后调用该回调函数
void feedbackCb(const comm::turtleMoveFeedbackConstPtr& feedback)
{
    
    
ROS_INFO(" present_pose : %f %f %f",
feedback->present_turtle_x,
feedback->present_turtle_y,feedback->present_turtle_theta);
}
int main(int argc, char** argv)
{
    
    
ros::init(argc, argv, "turtleMoveClient");
// 定义一个客户端
Client client("turtleMove", true);
// 等待服务器端
ROS_INFO("Waiting for action server to start.");
client.waitForServer();
ROS_INFO("Action server started, sending goal.");
// 创建一个 action 的 goal
comm::turtleMoveGoal goal;
goal.turtle_target_x = 1;
goal.turtle_target_y = 1;
goal.turtle_target_theta = 0;
// 发送 action 的 goal 给服务器端,并且设置回调函数
client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);
ros::spin();
return 0;
}

3. Create an action folder in the function package directory

And create the turtleMove.action file under the action folder
insert image description here
and write the code:

# Define the goal
float64 turtle_target_x # Specify Turtle's target position
float64 turtle_target_y
float64 turtle_target_theta
---
# Define the result
float64 turtle_final_x
float64 turtle_final_y
float64 turtle_final_theta
---
# Define a feedback message
- 7 -
float64 present_turtle_x
float64 present_turtle_y
float64 present_turtle_theta

4. Modify the Cmake file

1. Add the following code at the end of the CMakeLists.txt file:

add_executable(turtleMoveClient src/turtleMoveClient.cpp)
target_link_libraries(turtleMoveClient ${
    
    catkin_LIBRARIES})
add_dependencies(turtleMoveClient ${
    
    PROJECT_NAME}_gencpp)
add_executable(turtleMove src/turtleMove.cpp)
target_link_libraries(turtleMove ${
    
    catkin_LIBRARIES})
add_dependencies(turtleMove ${
    
    PROJECT_NAME}_gencpp)

insert image description here
2. Find the find_package function method in the file and modify it as follows:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
  actionlib_msgs
  actionlib
)

insert image description here
3. Continue to find the add_action_files function in the file. By default, it is commented out with #. Here we find it and modify it to the following code:

 add_action_files(
   FILES
   turtleMove.action
 )

insert image description here
4. Continue to find the generate_messages function item in the file, which is also #comment by default. Here, modify it to the following code:

generate_messages(
   DEPENDENCIES
   std_msgs
   actionlib_msgs
 )

insert image description here
5. Find the catkin_package function and modify it to the following code:

#  INCLUDE_DIRS include
#  LIBRARIES comm
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
 CATKIN_DEPENDS roscpp rospy std_msgs
  message_runtime

insert image description here

5. Modify the package.xml file

1. Replace the build_depend column in the file with the following code:

<buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>actionlib</build_depend>
  <build_depend>actionlib_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>

2. Replace the exec_depend column in the file with the following code:

<exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>message_runtime</exec_depend>
  <exec_depend>actionlib</exec_depend>
  <exec_depend>actionlib_msgs</exec_depend> 

insert image description here

6. Run the program

1. Compile

catkin_make

2. Registration procedure

 source ./devel/setup.bash

insert image description here
3. Create a new terminal, the command is terminal 2, start ros
insert image description here
4, create a new terminal, name it terminal 3, run our little turtle, and the little turtle window appears.
insert image description here
5. Create a new terminal, name it terminal 4, run our target location program code:
enter the workspace for program registration:

source ./devel/setup.bash

Run turtleMoveClient.cpp, remember, enter this command, but press Enter if you are not busy

rosrun comm turtleMoveClient

Run turtleMove on terminal 1, remember, enter the following command, and press Enter in no time

rosrun comm turtleMove

6. Press Enter on terminal 1 and press Enter on terminal 4. The final effect is as follows:
insert image description here

Four. Summary

ROS communication programming is a relatively important module, especially action programming allows us to understand the basis of machine learning. The most important thing through this study is to understand the basic steps of ROS communication programming. This blog has more content and longer steps. When I compile, I usually make a compilation error because of a typo of a letter, so I must be careful and meticulous during the programming process. Follow the steps step by step. Enhance understanding.

5. References

ROS basics - topic, service, action programming

Guess you like

Origin blog.csdn.net/asdhnkhn/article/details/129625590