ROS通信编程入门

目录

一、工作空间的创建

二、创建功能包

三、话题编程

自定义话题编程

四、服务编程

五、动作编程


 

 


 

 


 

 

一、工作空间的创建

首先创建一个工作空间

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

然后进行工作空间的编译

cd ~/catkin_ws
catkin_make

设置环境变量

source devel/setup.bash

进行环境变量的检查

echo $ROS_PACKAGE_PATH

若打印的路径中包括当前工作空间的路径,则说明环境变量设置成功

如果想要设置的环境变量对所有的终端都生效

sudo gedit ~/.bashrc
//在文件末尾添加
source /home/用户名/catkin_ws/devel/setup.bash
//使配置好的环境变量对所有终端都生效
source ~/.bashrc

再次使用echo命令进行环境变量的检查即可

二、创建功能包

命令格式:catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
同一个工作空间下,不允许存在同名功能包
不同工作空间下,允许存在同名功能包

在catkin_ws/src路径下创建功能包,并设置依赖包

cd ~/catkin_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp

编译工作空间

cd ~/catkin_ws
catkin_make

三、话题编程

ros的通信机制是分布式通信机制

话题编程的流程:

——创建发布者

——创建订阅者

——添加编译选项

——运行可执行程序

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NzajkyNTMxOQ==,size_16,color_FFFFFF,t_70

 创建发布者

发布者的实现流程:

——初始化ros节点

——向ros master注册节点信息,包括发布的话题名与话题的消息类型

——按照一定的频率循环发布消息

1、在 ~/catkin_ws/src/learning_communicaiton/src下创建talker.cpp文件

cd ~/catkin_ws/src/learning_communication/src
gedit talker

在文件中写入以下代码

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

创建订阅者

订阅者的实现流程

——初始化ros节点

——订阅所需要的话题

——循环等待话题消息。接受后进入回调函数

——在回调函数中完成消息处理

在 ~/catkin_ws/src/learning_communicaiton/src下创建listener.cpp文件

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

进行代码的编译

1.编译配置文件CMakeLists.txt

cd ~/catkinx_ws/src/learning_communicaiton
ls -a
//此时会看到显示出来的CMakeLists.txt文件
gedit 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})

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NzajkyNTMxOQ==,size_16,color_FFFFFF,t_70

 然后进行工作空间的编译

cd ~/catkin_ws
catkin_make

编译完成并且正确会看到以下提示信息

337fc370a3264aa08e65adddd643c38a.png

 

运行可执行文件

roscore

80f3b952a5e64b149c70bd52a96203c5.png

 然后分别新建两个终端,依次输入

rosrun learning_communication talker
rosrun learning_communication listener

运行话题发布者端口

203c98061aec4f709c4cf917829aeafe.png

运行话题订阅者端口

 c6759ed832174e8db80ead82f011312b.png

 此时说明操作成功,已经成功实现了话题编程

自定义话题编程

1、创建一个msg文件夹

mkdir ~/catkin_ws/src/learning_communication/msg
cd ~/catkin_ws/src/learning_communication/msg
sudo vi Person.msg

在其中写入以下代码

string name
uint8 sex
uint8 age

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

然后返回到learning_communication目录下,进行package.xml文件的编辑

在其中添加以下功能包依赖

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

注意:部分ros版本中exec_depend需要修改为run_depend

gedit CMakeLists.txt

在CMakeListis.txt文件中添加

find_package(catkin REQUIRED COMPONENTS
  std_msgs
  roscpp
  message_generation
)
 
catkin_package(
  CATKIN_DEPENDS std_msgs roscpp message_runtime
)
 
## Generate messages in the 'msg' folder
 add_message_files(
   FILES
   my_Mecanum_speed.msg
 )
 
## Generate added messages and services with any dependencies listed here
 generate_messages(
   DEPENDENCIES
   std_msgs
 )

然后编译即可

cd ~/catkin_ws
catkin_make

然后在现有终端直接输入命令查看自定义消息即可

rosmsg show Person

四、服务编程

服务编程的流程:

——创建服务器server

——创建客户端client

——添加编译选项

——运行可执行程序

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NzajkyNTMxOQ==,size_16,color_FFFFFF,t_70

 1、创建srv文件

mkdir ~/catkin_ws/src/learning_communication/srv
cd ~/catkin_ws/src/learning_communication/srv
sudo vi AddTwoInts.srv

写入以下代码

int64 a
int64 b
---
int64 sum

2、添加功能包依赖

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

3、编辑CMakeLists.txt文件

添加以下代码即可(已经实现了前两步并且添加过功能包依赖的话只需要再添加以下一节语句)

add_service_files(FILES AddTwoInts.srv)

4、创建服务器与客户端

在~catkin_ws/src/learning_communication/src路径下创建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;
}

同样路径下创建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;
}

设置配置文件

在CMakelist.txt文件中添加以下依赖

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

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

然后进行编译

cd ~/catkin_ws
catkin_make

看到以下信息提示即为编译成功

967c68fa1af7479dafa6012df3150b55.png

 然后跟话题编程执行过程相同

roscore
rosrun learning_communication server
rosrun learning_communication client 15 26

直接执行即可。

五、动作编程

9fbf52246aec4440aad76054622702b4.png

 

创建一个action文件

mkdir ~/catkin_ws/src/learning_communication/action
cd ~/catkin_ws/src/learning_communication/action
gedit DoDishes.action

然后在其中写入以下内容

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

返回learning_communication 路径下进行package.xml文件的配置

添加以下依赖

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

然后配置CMakeLists.txt文件

添加以下内容

find_package(catkin REQUIRED actionlib_msgs actionlib)

add_action_files(DIRECTORY action FILES DoDishes.action)

generate_messages(DEPENDENCIES actionlib_msgs)

5766d6e5c14f4ca6b4c43d33a1310aee.png

 然后创建服务器和客户端

cd src

进入src路径下创建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;
}

DoDishes_client.cpp

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

然后再编辑CMakeLists.txt文件添加编译所需依赖

add_executable(DoDishes_server src/DoDishes_server.cpp)
target_link_libraries(DoDishes_server ${catkin_LIBRARIES})
add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

add_executable(DoDishes_client src/DoDishes_client.cpp)
target_link_libraries(DoDishes_client ${catkin_LIBRARIES})
add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})

然后进行工作空间的编译

cd ~/catkin_ws
catkin_make

 然后进行正常执行即可

roscore
rosrun learning_communication DoDishes_client
rosrun learning_communication DoDishes_server

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Ubuntu 18.04上进行ROS通信编程,需要先安装ROS Melodic版本。安装完成后,可以使用ROS提供的通信机制,如话题(Topic)和服务(Service)等。 话题是一种发布/订阅(Publish/Subscribe)模式的通信机制,可以实现多个节点之间的异步通信。在ROS中,话题的数据类型是消息(Message),可以自定义消息类型。节点可以发布消息到话题,也可以订阅话题接收消息。 服务是一种请求/响应(Request/Response)模式的通信机制,可以实现节点之间的同步通信。在ROS中,服务的数据类型也是消息,但是服务消息包含请求消息和响应消息两部分。节点可以提供服务,也可以请求服务。 下面是一个简单的ROS话题通信示例: 1. 创建一个ROS工作空间 ``` mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_make ``` 2. 创建一个ROS包 ``` cd ~/catkin_ws/src catkin_create_pkg my_package rospy ``` 3. 在my_package中创建一个发布者节点 ``` cd ~/catkin_ws/src/my_package mkdir scripts cd scripts touch talker.py chmod +x talker.py ``` 将以下代码复制到talker.py文件中: ```python #!/usr/bin/env python import rospy from std_msgs.msg import String def talker(): pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(10) # 10hz while not rospy.is_shutdown(): hello_str = "hello world %s" % rospy.get_time() rospy.loginfo(hello_str) pub.publish(hello_str) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass ``` 4. 在my_package中创建一个订阅者节点 ``` cd ~/catkin_ws/src/my_package/scripts touch listener.py chmod +x listener.py ``` 将以下代码复制到listener.py文件中: ```python #!/usr/bin/env python import rospy from std_msgs.msg import String def callback(data): rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) def listener(): rospy.init_node('listener', anonymous=True) rospy.Subscriber('chatter', String, callback) rospy.spin() if __name__ == '__main__': listener() ``` 5. 编译ROS包 ``` cd ~/catkin_ws/ catkin_make ``` 6. 运行ROS节点 在一个终端中运行发布者节点: ``` source ~/catkin_ws/devel/setup.bash rosrun my_package talker.py ``` 在另一个终端中运行订阅者节点: ``` source ~/catkin_ws/devel/setup.bash rosrun my_package listener.py ``` 你可以看到,发布者节点会不断地发布消息到话题“chatter”中,而订阅者节点会接收到这些消息并打印出来。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值