ROS2 编写一个简单的服务和客户端(​​C ++)

目标:使用C ++创建和运行服务和客户端节点。

1创建一个包

 mkdir dev_ws
 mkdir dev_ws/src
 cd dev_ws/src

创建功能包

cd dev_ws/src
ros2 pkg create --build-type ament_cmake cpp_pubsub
 

2编写服务节点

dev_ws/src/cpp_srv/src目录中,创建一个名为的新文件add_two_ints_server.cpp,并将以下代码粘贴到其中:

// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "tutorial_interfaces/srv/add_three_ints.hpp"     // CHANGE

#include <memory>

void add(const std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Request> request,     // CHANGE
          std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Response>       response)  // CHANGE
{
  response->sum = request->a + request->b + request->c;                                       // CHANGE
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld" " c: %ld",   // CHANGE
                request->a, request->b, request->c);                                          // CHANGE
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
}

int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);

  std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_server");  // CHANGE

  rclcpp::Service<tutorial_interfaces::srv::AddThreeInts>::SharedPtr service =                 // CHANGE
    node->create_service<tutorial_interfaces::srv::AddThreeInts>("add_three_ints",  &add);     // CHANGE

  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add three ints.");      // CHANGE

  rclcpp::spin(node);
  rclcpp::shutdown();
}

3编写客户端节点

// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <functional>
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "tutorial_interfaces/srv/add_three_ints.hpp"        // CHANGE

#include <chrono>
#include <cstdlib>
#include <memory>

using namespace std::chrono_literals;

int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);

  if (argc != 4) { // CHANGE
      RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_three_ints_client X Y Z");      // CHANGE
      return 1;
  }

  std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_client"); // CHANGE
  rclcpp::Client<tutorial_interfaces::srv::AddThreeInts>::SharedPtr client =                        // CHANGE
    node->create_client<tutorial_interfaces::srv::AddThreeInts>("add_three_ints");                  // CHANGE

  auto request = std::make_shared<tutorial_interfaces::srv::AddThreeInts::Request>();               // CHANGE
  request->a = atoll(argv[1]);
  request->b = atoll(argv[2]);
  request->c = atoll(argv[3]);               // CHANGE

  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::executor::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_three_ints");    // CHANGE
  }

  rclcpp::shutdown();
  return 0;
}

4修改cmakelists.txt文件

CMakeLists.txt内容参考如下:

cmake_minimum_required(VERSION 3.5)
project(cpp_srv)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED) 
find_package(rclcpp REQUIRED)
find_package(tutorial_interfaces REQUIRED)                         # CHANGE


add_executable(server src/add_two_ints_server.cpp) 
ament_target_dependencies(server rclcpp tutorial_interfaces)         # CHANGE

add_executable(client src/add_two_ints_client.cpp) 
ament_target_dependencies(client rclcpp tutorial_interfaces)         # CHANGE

install(TARGETS
  server
  client
  DESTINATION lib/${PROJECT_NAME})

  
ament_package()

5修改package.xml文件

package.xml的内容参考如下:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>cpp_srv</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="aid@todo.todo">aid</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>tutorial_interfaces</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

6运行

浏览回到工作区的根目录dev_ws,然后构建新的程序包:

colcon build --packages-select cpp_srvcli

PS:如果缺少以来条件,可以参考上一篇 ROS2 编写一个简单的发布者和订阅者(​​C ++)文章

打开一个新终端,导航到dev_ws,执行操作:

. install/setup.bash
ros2 run cpp_svr  server

打开另一个新终端,导航到dev_ws,执行操作:

. install/setup.bash
ros2 run cpp_svr  client 1 2 3

实际运行效果如下:

ctrl+c退出命令台。

至此完成服务和客户端节点操作。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用ROS实现服务器和客户端通信程序的实验总结: 1. 实验目的 通过本次实验,学生应该掌握ROS的基本概念和使用方法,了解ROS中的节点、话题、服务等概念,能够使用ROS编写简单服务器和客户端通信程序。 2. 实验环境 本实验使用的ROS版本为ROS Kinetic,操作系统为Ubuntu 16.04。 3. 实验步骤 (1)创建ROS工作空间 在终端中执行以下命令: ``` mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace cd .. catkin_make source devel/setup.bash ``` (2)创建ROS包和节点 在终端中执行以下命令: ``` cd ~/catkin_ws/src catkin_create_pkg my_ros_pkg rospy cd my_ros_pkg mkdir scripts cd scripts touch my_ros_node.py chmod +x my_ros_node.py ``` 在my_ros_node.py文件中编写节点代码,代码如下: ``` #!/usr/bin/env python import rospy from std_msgs.msg import String def callback(data): rospy.loginfo("Received message: %s", data.data) def my_ros_node(): rospy.init_node('my_ros_node', anonymous=True) rospy.Subscriber("my_topic", String, callback) rospy.spin() if __name__ == '__main__': try: my_ros_node() except rospy.ROSInterruptException: pass ``` (3)创建ROS服务 在my_ros_pkg包中创建srv文件夹,并在其中创建一个名为MyService.srv的服务文件,文件内容如下: ``` string request --- string response ``` (4)编写服务端代码 在scripts文件夹中编写my_ros_server.py文件,文件内容如下: ``` #!/usr/bin/env python import rospy from my_ros_pkg.srv import MyService def handle_request(req): rospy.loginfo("Received request: %s", req.request) response = "Hello, " + req.request return response def my_ros_server(): rospy.init_node('my_ros_server', anonymous=True) rospy.Service('my_service', MyService, handle_request) rospy.loginfo("Ready to handle requests.") rospy.spin() if __name__ == '__main__': my_ros_server() ``` (5)编写客户端代码 在scripts文件夹中编写my_ros_client.py文件,文件内容如下: ``` #!/usr/bin/env python import rospy from my_ros_pkg.srv import MyService def my_ros_client(): rospy.wait_for_service('my_service') try: my_service = rospy.ServiceProxy('my_service', MyService) request = raw_input("Enter your name: ") response = my_service(request) rospy.loginfo("Received response: %s", response.response) except rospy.ServiceException as e: rospy.logerr("Service call failed: %s", e) if __name__ == '__main__': rospy.init_node('my_ros_client', anonymous=True) my_ros_client() ``` (6)运行程序 在终端中执行以下命令: ``` cd ~/catkin_ws catkin_make source devel/setup.bash roscore ``` 在新的终端中执行以下命令: ``` cd ~/catkin_ws source devel/setup.bash rosrun my_ros_pkg my_ros_node.py ``` 在新的终端中执行以下命令: ``` cd ~/catkin_ws source devel/setup.bash rosrun my_ros_pkg my_ros_server.py ``` 在新的终端中执行以下命令: ``` cd ~/catkin_ws source devel/setup.bash rosrun my_ros_pkg my_ros_client.py ``` 在客户端终端中输入您的名字,服务端会返回“Hello, 您的名字”。 4. 实验心得 本次实验通过使用ROS编写简单服务器和客户端通信程序,让我更深入了解了ROS的基本概念和使用方法,掌握了ROS中的节点、话题、服务等概念,并且学会了如何使用ROS编写服务器和客户端通信程序。同时,在实验过程中,我也学会了如何使用ROS的一些常用命令和工具,如catkin_make、roscd、rosrun等,这些命令和工具对于ROS开发非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值