文章目录
- 1、概要
- 2、引言
- 3、服务开始的地方及步骤
- 3.1 创建工作空间
- 3.2 创建功能包
- 3.3 更新package.xml
- 3.4 编写service 节点
- 3.4.1 添加可执行文件
- 3.4.2 添加 install(TARGETS…) 部分
- 3.5 编写client 节点
- 3.5.1 添加可执行文件
- 3.6 编译运行
- 3.7 运行结果
1、概要
目标:使用 C++ 创建和运行service 和 client 节点。
当节点使用服务进行通信时,发送数据请求的节点称为client节点,响应请求的节点称为service节点。请求和响应的结构由 .srv
文件确定。
2、引言
服务是ROS图中节点的另一种通信方式。服务基于呼叫和响应模型,而不是主题的发布者-订阅者模型。虽然主题允许节点订阅数据流并获取持续更新,但服务仅在客户端专门调用它们时提供数据。
这里使用的示例是一个简单的整数加法系统;一个节点请求两个整数的总和,另一个节点响应结果。
3、服务开始的地方及步骤
3.1 创建工作空间
如已经创建了工作空间可以不用创建
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
3.2 创建功能包
- 进入ros2_ws/src的目录下,创建一个新的功能包
cpp_srvcli
ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_srvcli --dependencies rclcpp example_interfaces
- 终端将返回一条消息,验证包cpp_srvcli及其所有必要文件和文件夹的创建。
--dependencies
参数将自动向package.xml
和CMakeLists.txt
添加必要的依赖项行。example_interfaces
是包含构建请求和响应所需的.srv
文件的包:
cpp_srvcli
包的文件结构如下
cpp_srvcli/
├── CMakeLists.txt
├── include
├── LICENSE
├── package.xml
└── src
2 directories, 3 files
- 创建
example_interfaces
功能包
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake exapmle_interfaces
cd exapmle_interfaces
mkdir msg srv
- 在example_interfaces/srv下,新建一个
AddTwoInts.srv
文件
touch AddTwoInts.srv
gedit AddTwoInts.srv
添加以下代码
int64 a
int64 b
---
int64 sum
前两行是请求的参数,短划线下面是响应。
3.3 更新package.xml
由于在包创建过程中使用了 --dependencies
选项,因此无需手动将依赖项添加到package.xml
或CMakeLists.txt
但是,需要确保将描述、维护者电子邮件和名称以及许可证信息添加到package.xml
。
3.4 编写service 节点
cd ~/ros2_ws/src/cpp_srvcli/src
touch add_two_ints_server.cpp
add_two_ints_server.cpp代码
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"#include<memory>//add 函数从请求中添加两个整数,并为响应提供总和,同时使用日志通知控制台其状态。
void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{response->sum = request->a + request->b;RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"Incoming request\na: %ld" "b: %ld",request->a,request->b);RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"sending back response:[%ld]",(long int)response->sum);
}int main(int argc,char* argv[])
{rclcpp::init(argc,argv); //初始化 ROS 2 C++ 客户端库//创建名为 add_two_ints_server 的节点:std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_inits_server");//为该节点创建名为 add_two_ints 的服务,并使用 &add 方法在网络中自动发该服务:rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service = node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints",&add);//准备就绪时打印日志消息:RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"Ready to add two ints.");rclcpp::spin(node); //spin节点,使服务可用。rclcpp::shutdown();return 0;
}
3.4.1 添加可执行文件
add_executable(server src/add_two_ints_server.cpp)
ament_target_dependencies(server rclcpp example_interfaces)
3.4.2 添加 install(TARGETS…) 部分
添加 install(TARGETS…) 部分,以便 ros2 run 可以找到可执行文件:
install(TARGETSserverDESTINATION lib/${PROJECT_NAME})
3.5 编写client 节点
cd ~/ros2_ws/src/cpp_srvcli/src
touch add_two_ints_client.cpp
add_two_ints_client.cpp代码
#include"rclcpp/rclcpp.hpp"
#include"example_interfaces/srv/add_two_ints.hpp"#include<chrono>
#include<cstdlib>
#include<memory>using namespace std::chrono_literals;int main(int argc,char**argv)
{rclcpp::init(argc,argv);if(argc!=3){RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"usage: add_two_ints_client X Y");return 1;}//创建节点,然后为该节点创建客户端:std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_client");rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client = node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");//创建请求,其结构由在 AddTwoInts.srv 文件定义。auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();request->a = atoll(argv[1]);request->b = atoll(argv[2]);while(!client->wait_for_service(1s)){if(!rclcpp::ok()){//如果客户端被取消(例如,通过在终端中输入 Ctrl+C),它将返回一条错误日志消息,指出它已中断。RCLCPP_ERROR(rclcpp::get_logger("rclcpp"),"Interrupted while waiting for the service . exiting.");return 0;}//while 循环为客户端提供 1 秒钟的时间来搜索网络中的服务节点。如果它找不到任何,它将继续等待。RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"service not available,waiting again...");}auto result = client->async_send_request(request);if(rclcpp::spin_until_future_complete(node,result)==rclcpp::FutureReturnCode::SUCCESS){RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"Sum: %ld",result.get()->sum);}else{RCLCPP_ERROR(rclcpp::get_logger("rclcpp"),"Failed to call service add_two_ints");}rclcpp::shutdown();return 0;}
3.5.1 添加可执行文件
add_executable(client src/add_two_ints_client.cpp)
ament_target_dependencies(client rclcpp example_interfaces)install(TARGETSserverclientDESTINATION lib/${PROJECT_NAME})
3.6 编译运行
- 导航回工作区的根目录,ros2_ws,并生成新包:
colcon build --packages-select cpp_srvcli
3.7 运行结果
- 打开一个新终端,导航到ros2_ws,并获取安装文件:
. install/setup.bash
ros2 run cpp_srvcli server
2. 打开另一个终端,再次从内部获取ros2_ws设置文件。启动客户机节点,后跟用空格分隔的任意两个整数:
. install/setup.bash
ros2 run cpp_srvcli client 2 3