ROS计算图结构

ROS节点之间通过收发消息进行通信,消息收发机制分为话题(topic)、服务(service)和动作(action)三种。如上计算图中的节点2与节点3、节点2与节点5采用话题通信,节点2与节点4采用服务通信,节点1与节点2采用动作通信。计算图中的节点、话题、服务、动作都要有唯一名称作为标识。
ROS服务通信方式
服务通信方式是双向同步的,服务客户端向服务提供端发送请求,服务提供端在收到请求后立即进行处理并返回响应信息。服务通信一般用在实时性要求比较高且使用频次低的场景下,比如获取全局静态地图。
编写程序测试服务通信方式
创建一个功能包,在此功能包中设计一些节点来测试服务通信方式。
创建功能包
假设:工作空间为catkin_ws,功能包为pkg_service_example,依赖roscpp和std_msgs功能包。
cd catkin_ws/src/
catkin_create_pkg pkg_service_example roscpp std_msgs
关于创建功能包的更多信息,请参考《创建/删除ROS功能包》

示例:基于服务通信方式,提供和调用一个简易的计算服务
目标
- 服务器节点提供一个简易的计算服务,实现基本的“加减乘除”功能。
- 客户端节点调用服务器节点的计算服务。
程序设计
- nodeServerA.cpp实现名为“NodeServerA”的节点,提供基本的“加减乘除”运算服务"daniel_service_calculation"。
- nodeClientA.cpp实现名为“NodeClientA”的节点,调用“NodeServerA”提供的运算服务"daniel_service_calculation"。
- 自定义服务类型“calculator.srv”。请求成员包含运算元素elementA、运算元素elementB、计算规则algorithm。回复成员包含元素运算结果result。
-
新建服务类型calculator.srv
mkdir -p catkin_ws/src/pkg_service_example/srv touch calculator.srvcalculator.srv
int64 elementA int64 elementB int64 algorithm --- int64 result -
将服务类型calculator.srv添加至编译环境
-
打开pkg_service_example/CMakeLists.txt,添加下面的修改:



-
打开pkg_service_example/package.xml,添加下面的修改:

添加成功后,可以通过rossrv show pkg_service_example/calculator查看calculator服务类型:

-
-
新建源文件 nodeServerA.cpp nodeClientA.cpp
cd catkin_ws/src/pkg_service_example/src/ touch nodeServerA.cpp nodeClientA.cpp
nodeServerA.cpp
#include "ros/ros.h" #include "pkg_service_example/calculator.h" #define NODE_NAME "NodeServerA" #define SERVICE_NAME "daniel_service_calculation" enum Algorithm{ ALG_PLUS = 0, ALG_MINUS = 1, ALG_TIMES = 2, ALG_DIVIDE = 3, }; bool onRecvRequest(pkg_service_example::calculator::Request& request, pkg_service_example::calculator::Response& response) { switch (request.algorithm) { case ALG_PLUS: response.result = request.elementA + request.elementB; break; case ALG_MINUS: response.result = request.elementA - request.elementB; break; case ALG_TIMES: response.result = request.elementA * request.elementB; break; case ALG_DIVIDE: response.result = request.elementA / request.elementB; break; default: return false; } return true; } int main(int argc, char* argv[]) { ros::init(argc, argv, NODE_NAME); ros::NodeHandle nodeHandle; ros::ServiceServer server = nodeHandle.advertiseService(SERVICE_NAME, onRecvRequest); ROS_INFO("%s is ready\n", SERVICE_NAME); ros::spin(); return 0; }nodeClientA.cpp
#include "ros/ros.h" #include "pkg_service_example/calculator.h" #include <iostream> #define NODE_NAME "NodeClientA" #define SERVICE_NAME "daniel_service_calculation" enum Algorithm{ ALG_PLUS = 0, ALG_MINUS = 1, ALG_TIMES = 2, ALG_DIVIDE = 3, }; int main(int argc, char* argv[]) { ros::init(argc, argv, NODE_NAME); ros::NodeHandle nodeHandle; ros::ServiceClient client = nodeHandle.serviceClient<pkg_service_example::calculator>(SERVICE_NAME); while (ros::ok()) { std::cout << "Please input two elements to calculate" << std::endl; long elementA, elementB; std::cin >> elementA >> elementB; std::cout << "Please select calculation algorithm:\n 0:plus\n 1:minus\n 2:times\n 3:divide" << std::endl; long algorithm; std::cin >> algorithm; pkg_service_example::calculator service; service.request.elementA = elementA; service.request.elementB = elementB; service.request.algorithm = algorithm; if (client.call(service)) { switch (algorithm) { case ALG_PLUS: ROS_INFO("%ld plus %ld equals %ld\n", elementA, elementB, (long)service.response.result); break; case ALG_MINUS: ROS_INFO("%ld minus %ld equals %ld\n", elementA, elementB, (long)service.response.result); break; case ALG_TIMES: ROS_INFO("%ld times %ld equals %ld\n", elementA, elementB, (long)service.response.result); break; case ALG_DIVIDE: ROS_INFO("%ld divide %ld equals %ld\n", elementA, elementB, (long)service.response.result); break; } } } return 0; }
编译
-
在pkg_topic_example/CMakeLists.txt的末尾加上下面的内容:
#node serverA add_executable(NodeServerA ./src/nodeServerA.cpp) target_link_libraries(NodeServerA ${catkin_LIBRARIES}) #node clientA add_executable(NodeClientA ./src/nodeClientA.cpp) target_link_libraries(NodeClientA ${catkin_LIBRARIES})
-
编译功能包
在工作空间根目录中使用catkin_make,编译该工作空间中的所有功能包。
如果需要编译指定的某个功能包(譬如:target_pkg),
使用catkin_make -DCATKIN_WHITELIST_PACKAGES=“target_pkg”。cd catkin_ws catkin_make 或者 catkin_make -DCATKIN_WHITELIST_PACKAGES="pkg_service_example"
测试
-
新开终端,运行主节点(如果主节点已运行,则跳过此步骤)
roscore使用
roscore运行主节点。

-
运行服务器节点
执行rosrun pkg_service_example NodeServerA,运行服务器节点NodeServerA。

-
运行客户端节点
执行rosrun pkg_service_example NodeClientA,运行服务器节点NodeClientA。

本文介绍了ROS(RobotOperatingSystem)中计算图结构以及服务通信方式的应用,通过实例展示如何创建和测试基于服务的计算服务,包括设计服务器节点、客户端节点和服务类型定义。
1069

被折叠的 条评论
为什么被折叠?



