ROS学习-创建/测试服务端和客户端

本文详细介绍如何在ROS环境中创建并使用服务通信。通过具体步骤指导读者完成srv文件的创建与配置,以及C++客户端和服务端代码的编写。文章还提供了完整的示例代码,帮助读者理解ROS服务的工作原理。

第一步:
首先要在beginner_tutorials中新建一个srv文件夹。文件夹中新建一个AddTwoInts.srv文件(也可以从rospy_tutorials的srv中复制过来)。该文件内容如下:

int64 a
int64 b
---
int64 sum

加了这个文件之后需对CMakeList.txt修改一下
首先将:

# add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# )

改成:

add_service_files(
  FILES
  AddTwoInts.srv
)

再把:

# generate_messages(
#   DEPENDENCIES
# #  std_msgs  # Or other packages containing msgs
# )

改成:

generate_messages(
  DEPENDENCIES
  std_msgs
)

还有在

find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)

后面加上message_generation
对应的package.xml文件里的依赖项也要把message_generation加上。

<build_depend>message_generation</build_depend>
  <run_depend>message_runtime</run_depend>

第二步:
编写add_two_ints_server和add_two_ints_client两个C++源文件。
add_two_ints_server:

#include"ros/ros.h"
#include"beginner_tutorials/AddTwoInts.h"//编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。
bool add(beginner_tutorials::AddTwoInts::Request &req,beginner_tutorials::AddTwoInts::Response &res)
{
    res.sum=req.a+req.b;
    ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
    ROS_INFO("sending back response: [%ld]", (long int)res.sum);
    return true;
}//int值从request里面获取,而返回数据装入response内,这些数据类型都定义在srv文件内部,函数返回一个boolean值。
int main(int argc, char *argv[])
{
    ros::init(argc, argv, "add_two_ints_server");
    ros::NodeHandle n;
    ros::ServiceServer service=n.advertiseService("add_two_ints",add);//service已经建立起来,并在ROS内发布出来
    ROS_INFO("Ready to add two ints.");
    ros::spin();
    return 0;
}

add_two_ints_client:

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  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;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");//为add_two_ints service创建一个client
  beginner_tutorials::AddTwoInts srv;//实例化一个service类,并给其中的request成员赋值
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  if (client.call(srv))//调用service
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

上述两步完成后,就可以按照之前说的用RoboWare-Studio对其进行编译。
最后就是测试:

$ cd ~/catkin_ws
$ source ./devel/setup.bash
$ rosrun beginner_tutorials add_two_ints_server
$ rosrun beginner_tutorials add_two_ints_client 1 3 
### ROS 客户端服务端实现配置 #### 创建工作空间并初始化包 为了创建一个新的ROS节点来作为客户端或服务器,首先需要设置适当的工作环境。假设已经在`~/ros2_ws/src`目录下操作,则可以按照如下方式创建新的软件包: ```bash cd ~/ros2_ws/src && ros2 pkg create --dependencies rclcpp example_interfaces my_robot_node ``` 这行命令会基于C++创建一个名为`my_robot_node`的新包,并依赖于`rclcpp`库以及标准消息集`example_interfaces`[^5]。 #### 编写服务端代码 对于服务端而言,在`my_robot_node`中添加一个源文件用于处理请求。这里以简单的加法运算为例展示如何编写服务端逻辑: ```cpp // src/add_two_ints_server.cpp #include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" class AddTwoIntsServer : public rclcpp::Node { public: explicit AddTwoIntsServer() : Node("add_two_ints_server") { srv_ = this->create_service<example_interfaces::srv::AddTwoInts>( "/add_two_ints", std::bind(&AddTwoIntsServer::handle_add_two_ints, this, std::placeholders::_1, std::placeholders::_2)); } private: void handle_add_two_ints( 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(this->get_logger(), "%d + %d = %d", request->a, request->b, response->sum); } rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr srv_; }; int main(int argc, char **argv) { rclcpp::init(argc, argv); auto node = std::make_shared<AddTwoIntsServer>(); rclcpp::spin(node); rclcpp::shutdown(); } ``` 此段代码定义了一个能够响应两个整数相加的服务端程序。 #### 编写客户端代码 同样地,在同一项目内增加另一个源文件用来构建客户端部分: ```cpp // src/add_two_ints_client.cpp #include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" using namespace std::chrono_literals; class MinimalClientAsync : public rclcpp::Node { public: using ServiceType = example_interfaces::srv::AddTwoInts; MinimalClientAsync() : Node("minimal_client_async"), cli_(this->create_client<ServiceType>("add_two_ints")) {} bool send_request(int64_t a, int64_t b) { while (!cli_->wait_for_service(1s)) { if (!rclcpp::ok()) { RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting."); return false; } RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..."); } auto request = std::make_shared<ServiceType::Request>(); request->a = a; request->b = b; auto future_result = cli_->async_send_request(request); // Wait until result is ready. if (future_result.wait_for(30s) != std::future_status::ready) { throw std::runtime_error("Failed to call service add_two_ints"); } else { RCLCPP_INFO(get_logger(), "Result of add_two_ints: %" PRId64, future_result.get()->sum); } return true; } private: rclcpp::client<ServiceType>::SharedPtr cli_; }; int main(int argc, char **argv) { rclcpp::init(argc, argv); auto minimal_client = std::make_shared<MinimalClientAsync>(); minimal_client->send_request(1, 7); // Example values rclcpp::shutdown(); } ``` 这段代码实现了向指定服务发送请求的功能,并等待返回的结果。 #### 构建测试 完成上述编码后,通过以下指令编译整个工程: ```bash cd ~/ros2_ws/ colcon build source install/setup.bash ``` 最后启动服务端客户端进行交互验证: ```bash # Terminal 1 - Start Server ros2 run my_robot_node add_two_ints_server # Terminal 2 - Start Client ros2 run my_robot_node add_two_ints_client ``` 以上过程展示了基本的ROS服务端客户端之间的通信机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值