美文网首页
ros2 foxy 学写简单的服务

ros2 foxy 学写简单的服务

作者: 寽虎非虫003 | 来源:发表于2021-05-05 23:49 被阅读0次

零、前情提要

前面跟着写了第一个话题订阅的例子,参考用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指依赖于rclcppexample_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文件有点奇妙,而且用法很繁琐

相关文章

网友评论

      本文标题:ros2 foxy 学写简单的服务

      本文链接:https://www.haomeiwen.com/subject/kfwfdltx.html