零、前情提要
前面跟着写了第一个话题订阅的例子,参考用colcon和c++写自己的第一个ROS2包,这次跟着教程写服务--客户端的例子。
这次依旧是跟着官方的示例走的。 Writing a simple service and client (C++)。
但是有些步骤可能就没有上一篇那么详细了。
一、创建文件夹和包
#dev_ws可以自己命名,但最好保留`_ws`的缩写标志。
mkdir -p dev_ws/src
#进入源目录
cd dev_ws/src
#创建包
ros2 pkg create --build-type ament_cmake cpp_srvcli --dependencies rclcpp example_interfaces
上面
--build-type ament_cmake
就不必说了,ros2
写c++的声明构建方式,cpp_srvcli
是包名,--dependencies rclcpp example_interfaces
指依赖于rclcpp
和example_interfaces
,主要是这个example_interfaces
,暂时我还没有看太懂这儿。按愿意是提供了一个类似以下的.srv
文件,叫做AddTwoInts.srv,
接下来还有一个相关的头文件我也不甚了解,先在这里表示疑问。前两行是请求的参数,破折号下面是响应。
int64 a
int64 b
---
int64 sum
接下来是照常更新
package.xml
,怎么打开我就不再说了,基本上文本编辑器都行。修改或添加如下的行:
<description>C++ client server tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
二、写服务端代码
在
dev_ws/src/cpp_srvcli/src
文件下下创建add_two_ints_server.cpp
文件,填入以下代码:
//ros2相关的头文件
#include "rclcpp/rclcpp.hpp"
//相关的文件夹下面好像并没有找到这个hpp,只有对应的.srv
#include "example_interfaces/srv/add_two_ints.hpp"
//内存相关
#include <memory>
//从.srv文件搁置中按要求获得request,和response,并打印到命令行
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);
}
/******************************************************************************
* @brief 主函数
* @param argc My Param doc
* @param argv My Param doc
* @return int
******************************************************************************/
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);//!初始化
//创建node并命名
std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_server");
//创建服务,这个也和依赖相关性太大了,这个反正也太麻烦了
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);
rclcpp::shutdown();
}
三、写客户端代码
在
dev_ws/src/cpp_srvcli/src
目录下创建add_two_ints_client.cpp
文件
//ros2相关
#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");
//获得结构体信息和数据
auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
request->a = atoll(argv[1]);
request->b = atoll(argv[2]);
//一分钟内搜寻服务端,如果没有找到,继续找,中间可以用Ctrl+C中断,并打印错误信息
while (!client->wait_for_service(1s)) {
if (!rclcpp::ok()) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");
return 0;
}
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");
}
//发送数据,并设置返回的格式
auto result = client->async_send_request(request);
// Wait for the result.
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;
}
修改
CMakeLists.txt
,最后简化后可能就只有这么点
cmake_minimum_required(VERSION 3.5)
project(cpp_srvcli)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)
add_executable(server src/add_two_ints_server.cpp)
ament_target_dependencies(server
rclcpp example_interfaces)
add_executable(client src/add_two_ints_client.cpp)
ament_target_dependencies(client
rclcpp example_interfaces)
install(TARGETS
server
client
DESTINATION lib/${PROJECT_NAME})
ament_package()
四、生成和运行
我是在
vs code
里面添加了colcon tasks
工具,Ctrl+shift+P
选择构建工具为colcon
以后,直接Ctrl+shift+B
进行构建了,然后就可以到裕兴一步了,也可以按照官方的的方式进行构建
官方构建,首先,回到dev_ws
文件夹目录下,检查依赖并构建
rosdep install -i --from-path src --rosdistro foxy -y #检查依赖
colcon build --packages-select cpp_srvcli #构建
运行,打开两个
terminal
,两个都输入如下source
. install/setup.bash
在其中一个里面运行服务端
ros2 run cpp_srvcli server
会得到如下输出
[INFO] [rclcpp]: Ready to add two ints.
在另一个里面会运行客户端,其中2,3是创给服务端让服务端进行计算的数。
ros2 run cpp_srvcli client 2 3
如果你输入的是2和3,则客户端得到的返回应该是这样的
[INFO] [rclcpp]: Sum: 5
而服务端打印的信息应该是这样的
[INFO] [rclcpp]: Incoming request
a: 2 b: 3
[INFO] [rclcpp]: sending back response: [5]
运行效果总体上是这样
总结
那个.srv文件有点奇妙,而且用法很繁琐
网友评论