3 ROS2服务通讯基础

news2024/11/15 9:01:57

ROS2服务通讯基础

  • 3.1 服务通讯介绍
  • 3.2 ROS2服务通讯的基本流程
    • 3.2.1 创建ROS2服务通讯功能包的基本流程
    • 3.2.2 创建ROS2服务通讯功能包示例
  • 3.3 使用C/C++实现ROS2服务通讯
    • 3.3.1 创建C/C++服务通讯服务端功能包并编写节点文件
    • 3.3.2 配置C/C++服务通讯服务端功能包
    • 3.3.3 编译并运行C/C++服务通讯服务端
    • 3.3.4 创建C/C++服务通讯客户端功能包并编写节点文件
    • 3.3.5 编译并运行C/C++服务通讯客户端节点
  • 3.4 使用Python实现ROS2服务通讯
    • 3.4.1 创建Python服务通讯服务端功能包并编写节点文件
    • 3.4.2 配置Python服务通讯服务端功能包
    • 3.4.3 编译并运行Python服务通讯服务端功能包
    • 3.3.4 创建Python服务通讯客户端功能包并编写节点文件
    • 3.4.5 编译并运行Python服务通讯客户端节点
  • 3.5 服务通讯小结

  • 其他ROS2学习笔记: ROS2学习笔记
  • 代码仓库:Github连接地址
  • 欢迎各位互相学习交流

3.1 服务通讯介绍

参考内容

Understanding services

服务通讯是ROS2的一种基于请求响应式的通讯方式,与之前的话题通讯不同的是服务通讯不是连续的数据流式的通讯,而是需要特定的触发才能收到回复的模式。

服务通讯可以是单个服务端和和单个客户端直接的通讯,一对一的模式

在这里插入图片描述

服务通讯也可以是单个服务端和多个客户端通讯,一对多的模式

在这里插入图片描述

3.2 ROS2服务通讯的基本流程

事实上,服务通讯和自定义的话题通讯的操作过程很类似,即将所需要利用到服务模块利用ament_camke工具编译成.c.py的ROS2功能包,然后新建的功能包依赖这个服务功能包完成通讯。

3.2.1 创建ROS2服务通讯功能包的基本流程

    1. 创建ROS2功能包,功能包可以只用来作为存放自定义的msg/srv/action,不需要节点node的功能包,--build-type必须是ament_camke ,因为目前来看,Python的自定义的消息或者服务也需要通过cmake编译出来再调用,功能包必须是下划线的推荐命名方法,而不是大小写的驼峰,否则会报错,如下所示:
  rosidl_adapter.parser.InvalidResourceName: 'xxxxx' is an invalid
  package name.  It should have the pattern
  '^(?!.*__)(?!.*_$)[a-z][a-z0-9_]*$'
    1. 在ROS2功能包内创建srv文件夹,里面存放自定义的.srv消息文件,并且 .srv文件必须是大写开头的符合类的命名规则
    1. 配置packages.xml文件,都需要配置下面的内容(下面的配置项与.srv文件无关,是默认的固定配置)
<!-- 这一项是针对在srv文件中可能用到的其他依赖项,例如geomtry_msgs等等,如过没有用到就不添加 -->
<depend>其他的depend</depend>

<!-- 下面三项是必须的 -->
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
    1. 配置CMakeLists.txt文件,find_packagerosidl_generate_interfaces
# 0. 是针对在srv文件中可能用到的其他依赖项,例如geomtry_msgs等等,则需要添加
# find_package(geometry_msgs REQUIRED)

# 1. rosidl_default_generators是必须添加的内容
find_package(rosidl_default_generators REQUIRED)

# 2. rosidl_generate_interfaces必须配置,里面添加srv文件位置
rosidl_generate_interfaces(${PROJECT_NAME}
# 2.1 添加自定义的srv位置,例如存放在功能包的srv文件夹下的xxx.srv
  "srv/xxx.srv"
# 2.2 可选,如果xxx.srv依赖了其他的内容,例如依赖了geometry_msgs
  DEPENDENCIES geometry_msgs
)
    1. 编译功能包:colcon build --packages-select <功能包名>
    1. 此时激活install目录下的setup.bash. install/setup.bash,可以通过ros2 interface show <功能包名称>/srv/xxx.srv查看到xxx.srv内容,此时编译好的srv.c文件存放在install/<功能包名>/include下,.py文件则存放在install/<功能包名>/local/

3.2.2 创建ROS2服务通讯功能包示例

  1. 创建自定义消息功能包srv_demo,采用ament_cmake方式:ros2 pkg create srv_demo --build-type ament_cmake

  2. 在功能包内创建srv文件夹,其中存放AddInt.srv文件,需要利用到---符号作为分割,文件在---上面的内容作为请求体的参数,在---下面的内容作为响应体的参数,文件内容如下:

int32 num1
int32 num2
---
int32 sum
  1. 此时的功能包内部的目录结构如下:tree -a
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code/srv_demo$ tree -a
.
├── CMakeLists.txt
├── include
│   └── srv_demo
├── package.xml
├── src
└── srv
    └── AddInt.srv
  1. 配置packages.xml添加依赖项,由于AddInt.srv没有依赖任何的东西因此不需要添加其他的depend:
<?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>msg_demo</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <!-- 构建自定义功能包的的必须依赖项 -->
  <buildtool_depend>rosidl_default_generators</buildtool_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

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

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

  1. 配置CMakeLists.txt文件,添加构建自定义AddInt.srv的依赖:
cmake_minimum_required(VERSION 3.8)
project(srv_demo)

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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

# 1. 构建自定义功能包必须的依赖
find_package(rosidl_default_generators REQUIRED)

# 2. 配置自定义的srv的位置
rosidl_generate_interfaces(${PROJECT_NAME}
  "srv/AddInt.srv"
)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()


  1. 构建功能包:colcon build --packages-select srv_demo

  2. 查看自定义的消息:激活环境:. install/setup.bash ,查看自定义消息ros2 interface show srv_demo/srv/AddInt

pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ colcon build --packages-select srv_demo
Starting >>> srv_demo
Finished <<< srv_demo [12.2s]                     

Summary: 1 package finished [12.5s]
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ . install/setup.bash 
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ ros2 interface show srv_demo/srv/AddInt 
int32 num1
int32 num2
---
int32 sum
  1. 查看instll下面的文件:其中.c的class文件在install/<功能包名>/include/<功能包名>/<功能包名>/msg/**.pyinstall/<功能包名>/local/lib/python3.10/dist-packages/<功能包名>/msg/**,后续Vscode可以通过配置settings.json添加提示

在这里插入图片描述

3.3 使用C/C++实现ROS2服务通讯

这里直接使用3.2.2创建的srv_demo服务功能包进行ROS2 C/C++的服务通讯的实现

参考内容:

Writing a simple service and client (C++)

2.3.3_服务通信_C++实现_01框架搭建

ROS2探索(三)service

3.3.1 创建C/C++服务通讯服务端功能包并编写节点文件

  1. 创建功能包,其中功能包名称为cpp_srv_server,节点名为cppSrvServerNoderos2 pkg create cpp_srv_server --build-type ament_cmake --node-name cppSrvServerNode

  2. 配置Vscode环境,在工作空间创建.vscode文件夹,并加入settings.json文件,添加ROS2include环境和当前工作空间的install文件夹下的srv_demo功能包的include路径:

{
    "C_Cpp.default.includePath": [
        "/opt/ros/humble/include/**",
        "./install/srv_demo/include/**"
    ],
}

在这里插入图片描述

  1. 编写服务端节点文件,主要包括导入包,创建服务节点,实现回调函数:
// 1. 调用自定义的服务文件
// 1.1 rclcpp和srv_demo两个功能包的头文件
// 如果有vscode的下划线提示,说明是settings.json没有配置好
#include "rclcpp/rclcpp.hpp"
#include "srv_demo/srv/add_int.hpp"

// 1.2. 调用功能包下的自定义的服务,其中自定义的服务名已经变成了一个类名
using srv_demo::srv::AddInt;

// std_bind的占位符
using std::placeholders::_1;
using std::placeholders::_2;

// 2.定义节点类;
class CppSrvServer: public rclcpp::Node{
  public:
  // 2.1 构造函数,其中节点名直接赋予cppSrvServerNode
    CppSrvServer():Node("cppSrvServerNode"){
      // 2.2 创建服务端
      server_ = this->create_service<AddInt>("mySrvName",std::bind(&CppSrvServer::addIntFunc, this, _1, _2));
      RCLCPP_INFO(this->get_logger(),"Server is starting ...");
    }
  private:
    
    // 3. 服务端的回调函数实现,其中参数的写法区分主要在于类型,参数数量包括请求体req和响应体rsp
    void addIntFunc(const AddInt::Request::SharedPtr req, const AddInt::Response::SharedPtr rsp)
    {
      rsp->sum = req->num1 + req->num2;
      RCLCPP_INFO(this->get_logger(),"request body :(%d,%d), response is :%d", req->num1, req->num2, rsp->sum);
    }

    // 4 服务的声明
    rclcpp::Service<AddInt>::SharedPtr server_;
};

int main(int argc, char const *argv[])
{
  rclcpp::init(argc,argv);
  auto server_ = std::make_shared<CppSrvServer>();
  rclcpp::spin(server_);
  rclcpp::shutdown();
  return 0;
}

3.3.2 配置C/C++服务通讯服务端功能包

  1. 配置packages.xml文件,添加依赖项有rclcpp用于构建节点,和srv_demo用于构建AddInt
<?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_server</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

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

  <!-- 依赖rclcpp创建节点和自定义的服务功能包 -->
  <depend>rclcpp</depend>
  <depend>srv_demo</depend>

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

  1. 配置CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(cpp_srv_server)

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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

# 1. 列出依赖项的包
find_package(rclcpp REQUIRED)
find_package(srv_demo REQUIRED)

# 2. 默认是已经创建了构建节点的文件配置
add_executable(cppSrvServerNode src/cppSrvServerNode.cpp)

# 3. 默认已经包括<INSTALL_INTERFACE>的路径也不用更改
target_include_directories(cppSrvServerNode PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
target_compile_features(cppSrvServerNode PUBLIC c_std_99 cxx_std_17)  # Require C99 and C++17

# 4. ament工具构建节点的依赖配置
ament_target_dependencies(
  cppSrvServerNode
  rclcpp
  srv_demo
)

# 5. Install配置,默认ros2 run <包名>的配置
install(TARGETS cppSrvServerNode
  DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 6. 生成包的环境
ament_package()

3.3.3 编译并运行C/C++服务通讯服务端

  1. 编译: colcon build --packages-select cpp_srv_server

  2. 激活环境:. install/setup.bash

  3. 运行:ros2 run cpp_srv_server cppSrvServerNode

pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ colcon build --packages-select cpp_srv_server
Starting >>> cpp_srv_server
Finished <<< cpp_srv_server [20.6s]                       
                      
Summary: 1 package finished [21.0s]
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ . install/setup.bash 
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ ros2 run cpp_srv_server cppSrvServerNode 
[INFO] [1683125184.734934447] [cppSrvServerNode]: Server is starting ...
^C[INFO] [1683125186.240946812] [rclcpp]: signal_handler(signum=2)

3.3.4 创建C/C++服务通讯客户端功能包并编写节点文件

  1. 创建功能包,功能包名为cpp_srv_client,节点名称为cppSrvClientNode,依赖rclcppsrv_demoros2 pkg create cpp_srv_client --build-type ament_cmake --node-name cppSrvClientNode --dependencies rclcpp srv_demo

  2. 编写客户端节点,注意在此过程中需要和 服务端的连接进行判断,以及发送的请求是否能够收到返回值的用法的操作

// 1. 调用自定义的服务文件
// 1.1 rclcpp和srv_demo两个功能包的头文件
#include "rclcpp/rclcpp.hpp"
#include "srv_demo/srv/add_int.hpp"

// 1.2. 调用功能包下的自定义的服务,其中自定义的服务名已经变成了一个类名
using srv_demo::srv::AddInt;

// 时间函数用于持续访问服务端
using namespace std::chrono_literals;

// 2.定义节点类;
class CppSrvClient: public rclcpp::Node{
  public:
    CppSrvClient():Node("cppSrvClientNode")
    {
      // 2.1 创建客户端,并绑定服务通讯名称为mySrvName
      client_ = this->create_client<AddInt>("mySrvName");
      RCLCPP_INFO(this->get_logger(),"Client is starting  ...");
    }
    // 2.2 等待与服务的连接
    bool connect_server(){
      while (!client_->wait_for_service(1s))
      {
        if (!rclcpp::ok())
        {
          RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"Interrupted while waiting for the service. Exiting.");
          return false;
        }

        RCLCPP_INFO(this->get_logger(),"service not available, waiting again...");
      }
      return true;
    }
    // 2.3 客户端发送请求;
    rclcpp::Client<srv_demo::srv::AddInt>::FutureAndRequestId send_request(int32_t num1, int32_t num2)
    {
      auto request = std::make_shared<AddInt::Request>();
      request->num1 = num1;
      request->num2 = num2;
      // 2.3.1 发送请求
      auto response = client_->async_send_request(request);
      return response;
    }

  private:
    // 2.4 服务通讯客户端的声明
    rclcpp::Client<AddInt>::SharedPtr client_;
};


int main(int argc, char ** argv)
{
  // 3. 初始化ROS2客户端
  rclcpp::init(argc,argv);

  // 3.1 创建对象指针并调用其功能;
  auto cppSrvClientNode = std::make_shared<CppSrvClient>();
  // 3.2 连接客户端
  bool flag = cppSrvClientNode->connect_server();
  if (!flag)
  {
    RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"Connect failed! ");
    return 0;
  }

  // 3.3 发送请求并等待响应
  auto response = cppSrvClientNode->send_request(100,200);

   // 3.4 节点处理响应
  if (rclcpp::spin_until_future_complete(cppSrvClientNode,response) == rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_INFO(cppSrvClientNode->get_logger(),"The response is :%d!", response.get()->sum);

  } else {
    RCLCPP_INFO(cppSrvClientNode->get_logger(),"Request error");
  }
  rclcpp::shutdown();
  return 0;
}

3.3.5 编译并运行C/C++服务通讯客户端节点

  1. 由于在创建包的过程中已经指明了所有依赖项,不需要进行额外的配置,直接编译运行即可:colcon build --packages-select cpp_srv_client

  2. 激活环境并运行节点

在这里插入图片描述

3.4 使用Python实现ROS2服务通讯

参考内容

Writing a simple service and client (Python)

2.3.4_服务通信_Python实现_01框架搭建

3.4.1 创建Python服务通讯服务端功能包并编写节点文件

  1. 创建功能包,包名为python_srv_server,节点名为pythonSrvServerNoderos2 pkg create python_srv_server --build-type ament_python --node-name pythonSrvServerNode

  2. 配置Vscode,主要添加功能包的提示环境,编辑settings.json

{
    "C_Cpp.default.includePath": [
        "/opt/ros/humble/include/**",
        "./install/srv_demo/include/**"
    ],
    "python.analysis.include": [
        "/opt/ros/humble/local/lib/python3.10/dist-packages/**",
        "./install/srv_demo/local/lib/python3.10/dist-packages/**"
    ]
}

在这里插入图片描述

  1. 编写Python服务端节点文件:
import rclpy
from rclpy.node import Node

# 1. 导入包,其中的类名等于服务文件名称
from srv_demo.srv import AddInt

# 2. 定义服务端节点
class PythonSrvServer(Node):

    def __init__(self):
        super().__init__('pythonSrvServerNode')
        # 2.1 创建服务端
        self.srver_ = self.create_service(AddInt, 'mySrvName', self.addIntFunc)
        self.get_logger().info("Server is starting ...")

    # 2.2 服务端的处理回调函数
    def addIntFunc(self, request:AddInt, response:AddInt):
        response.sum = request.num1 + request.num2
        self.get_logger().info('The request is :{} {},Response is :{}'.format(request.num1, request.num2, response.sum))
        return response


def main():
    rclpy.init()
    pythonSrvServerNode = PythonSrvServer()
    rclpy.spin(pythonSrvServerNode)
    rclpy.shutdown()


if __name__ == '__main__':
    main()

3.4.2 配置Python服务通讯服务端功能包

  1. 配置packages.xml增加rclpysrv_demo两个依赖项,注意Python本身是可执行文件,因此它的为<exec_depend>C/C++<depend>关键字不同:
<?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>python_srv_server</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

  <!-- 添加依赖项的包,注意是exec_depend -->
  <exec_depend>rclpy</exec_depend>
  <exec_depend>srv_demo</exec_depend>

  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

  1. 配置setup.py文件,事实上,我们已经创建包的时候已经指定了节点名,其实应该是不用配置生成节点的main入口的:
from setuptools import setup

package_name = 'python_srv_server'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='pldz',
    maintainer_email='pldz@R7000.com',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    # 配置节点main函数入口
    entry_points={
        'console_scripts': [
            'pythonSrvServerNode = python_srv_server.pythonSrvServerNode:main'
        ],
    },
)

3.4.3 编译并运行Python服务通讯服务端功能包

  1. 编译:colcon build --packages-select python_srv_server

  2. 激活环境:. install/setup.bash

  3. 运行节点:ros2 run python_srv_server pythonSrvServerNode

pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ colcon build --packages-select python_srv_server
Starting >>> python_srv_server
--- stderr: python_srv_server                   
/usr/lib/python3/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
---
Finished <<< python_srv_server [2.18s]

Summary: 1 package finished [2.71s]
  1 package had stderr output: python_srv_server
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ . install/setup.bash 
pldz@pldz-pc:~/share/ROS2_DEMO/3_Chapter/code$ ros2 run python_srv_server pythonSrvServerNode 
[INFO] [1683157866.794236460] [pythonSrvServerNode]: Server is starting ...

3.3.4 创建Python服务通讯客户端功能包并编写节点文件

  1. 创建Python功能包时,包名为python_srv_client,节点名为pythonSrvClientNode,直接指定依赖项rclpysrv_demoros2 pkg create python_srv_client --build-type ament_python --node-name pythonSrvClientNode --dependencies rclpy srv_demo

  2. 编写节点:主要是统一节点的订阅话题,异步接收返回的结果

import sys
import rclpy
from rclpy.node import Node
# 1. 导入包
from srv_demo.srv import AddInt

# 2.定义客户端节点
class pythonSrvClient(Node):

    def __init__(self):
        # 2.1 继承node节点,节点名为pythonSrvClientNode
        super().__init__('pythonSrvClientNode')
        # 2.2 创建客户端
        self.client_ = self.create_client(AddInt, 'mySrvName')
        # 2.3 等待连接
        self.wait_for_connect()


    # 3. 实现等待函数
    def wait_for_connect(self):
        while not self.client_.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('Waiting for connect ...')

    # 4. 实现发送请求函数
    def send_request(self, num1, num2):
        request = AddInt.Request()
        request.num1 = num1
        request.num2 = num2
        self.future = self.client_.call_async(request)


def main():
    rclpy.init()
    # 5.创建客户端节点
    pythonSrvClientNode = pythonSrvClient()
    pythonSrvClientNode.send_request(200,300)

    # 6. 等待响应
    rclpy.spin_until_future_complete(pythonSrvClientNode,pythonSrvClientNode.future)
    try:
        response = pythonSrvClientNode.future.result()
    except Exception as e:
        pythonSrvClientNode.get_logger().info('Request error  {}'.format(e))
    else:
        pythonSrvClientNode.get_logger().info(
            'Response is {}'.format(response.sum))

    rclpy.shutdown()


if __name__ == '__main__':
    main()

3.4.5 编译并运行Python服务通讯客户端节点

  1. 由于指定了依赖项,直接编译即可: colcon build --packages-select python_srv_client

  2. 激活环境: . install/setup.bash

  3. 运行所有节点:

在这里插入图片描述

3.5 服务通讯小结

    1. 创建功能包时,如果能够直接指定节点名和依赖项,可以省去很大部分的配置工作
    1. C/C++手动配置功能包时,packages.xml配置依赖项,CMakeLists.txt配置编译的内容,包括find_packageadd_executabletarget_include_directoriesament_target_dependenciesinstallament_package这六个部分
    1. Python手动配置功能包时,packages.xml配置可执行的依赖项exec_depend而不是depend,并且在setup.py中主要配置节点的main函数入口
    1. 服务通讯的导入本质是创建一个C/C++的功能包,将里面的自定义消息编译成可以使用的.c.py文件,值得注意的是,生成好的中间文件是存放在 工作空间install文件夹下,如果这个这个工作空间的install找不到或者不是一个,那是需要再进一步的手动配置的
    1. 服务通讯的请求响应是这里是异步实现的,即客户端需要等待服务端返回的结果,才能判断是否完成接收

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487888.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

符号三角形-计算机算法设计与分析【1600+字解析 dfs全排列 列举情况】【题意分析】【算法分析】【思路是怎么来的】【过程是什么】

符号三角形 题意分析思路过程分析算法分析 下图是由14个“”和14个“-”组成的符号三角形。2个同号下面都是“”&#xff0c;2个异号下面都是“-”。 在一般情况下&#xff0c;符号三角形的第一行有n个符号。符号三角形问题要求对于给定的n&#xff0c;计算有多少个不同的符号…

JMeter进阶——详解Java请求关于事务的操作 (附源码)

Jmeter事务操作 前面写过一篇文章&#xff0c;介绍Jmeter如何来调用java请求的&#xff0c;可以参考文章 详解JMeter Java请求的设计方法 但这篇文章中有一个问题&#xff0c;在方法public SampleResult runTest(JavaSamplerContext arg0) 中只对一个类的一个api 进行调用&am…

LeetCode 2106. 摘水果

【LetMeFly】2106.摘水果 力扣题目链接&#xff1a;https://leetcode.cn/problems/maximum-fruits-harvested-after-at-most-k-steps/ 在一个无限的 x 坐标轴上&#xff0c;有许多水果分布在其中某些位置。给你一个二维整数数组 fruits &#xff0c;其中 fruits[i] [positio…

Java Test: Specification and Structure Testing(line, branch, path coverage)

这篇文章梳理一下Java软件测试中的Secification test和Structure test。 Specification Test 规范测试&#xff08;specification test&#xff09;&#xff1a;又称黑盒测试&#xff08;black-box testing&#xff09;或需求驱动测试&#xff08;requirements-driven testin…

B树(B-tree、B-树)理论详解

文章目录 基本概念n阶B树的性质&#xff08;n>2&#xff09;B树的搜索B树元素的添加上溢出解决 删除删除叶子节点删除非叶子节点删除——导致下溢出删除——解决下溢出方法一删除——解决下溢出方法二 MongoDB 基本概念 B树是为磁盘或其他直接存取的辅助存储设备而设计的一…

Gitlab on k8s最佳实践

文章目录 gitlab on k8sGitLab部署helm 安装 postgresqlhelm 安装 redis 集群gitlab manifest 部署gitlab如何上传项目&#xff1f;gitlab监控metricsgitlab runner helm 部署helm部署问题k8s中gitlab exector架构图what is Gitlab Runner Helper?gitlab如何连接上k8s&#xf…

【Windows】关闭Windows Update自动更新

目录 一 服务中关闭Win10自动更新及关联服务 二 注册表中关闭Win10自动更新 三 组策略中关闭Win10自动更新 四 计划任务中关闭Win10自动更新 电脑系统盘不够用了&#xff0c;为此准备关闭Windows Update自动更新&#xff0c;以节省空间。为保证关闭之后不死灰复燃&#xff…

Ajax入门

在B/S架构中&#xff0c;浏览器端发送请求的传统方式如下&#xff1a; 1.直接在浏览器地址栏上输入url 2.超链接 3.from表单 4.在JavaScript代码中发送请求 1&#xff09;window.open(url) 2&#xff09;document.location.href url 3&#xff09;window.location.href url ……

优思学院|精益生产在制药行业的应用情况如何?

精益生产作为一项优化生产过程、提高效率的方法论&#xff0c;精益生产在制药行业得到了广泛应用。其核心理念是通过消除浪费&#xff0c;不断改进生产流程&#xff0c;实现资源的最大化利用和生产成本的最小化&#xff0c;从而提高企业的竞争力和市场占有率。 在制药行业&…

Java语言----LinkedList 和 链表的实现

目录 一.链表概念 二.链表的分类 三.无头单向非循环链表的实现 3.1创建简单链表 3.2 链表基本方法实现 3.3四大基本功能 3.3.1.增加元素结点 3.3.2.查找元素结点 3.3.3.删除元素结点 3.3.4.结点信息修改 四.LinkedList是什么&#xff1f; 五.LinkedList使用方法 总结 …

蓝牙耳机哪款性价比高?2023蓝牙耳机性价比排行

随着蓝牙耳机的使用愈发频繁&#xff0c;蓝牙耳机产品也越来越多&#xff0c;蓝牙耳机的功能、价格、外观设计等都不尽相同。接下来&#xff0c;我来给大家推荐几款性价比高的蓝牙耳机&#xff0c;感兴趣的朋友一起来看看吧。 一、南卡小音舱Lite2蓝牙耳机 参考价&#xff1a…

unity,如何让当前物体获取鼠标位置,转向鼠标在屏幕中的位置?

介绍 unity&#xff0c;如何让当前物体获取鼠标位置&#xff0c;转向鼠标在屏幕中的位置&#xff1f; 方法 void Update() {// 获取鼠标在屏幕上的位置Vector3 mousePos Input.mousePosition;// 将鼠标在屏幕上的位置转换为世界空间中的位置Vector3 worldPos Camera.main.S…

C++11多线程join()和detach()的理解

简介 每一个程序至少拥有一个线程&#xff0c;那就是执行main()函数的主线程&#xff0c;而多线程则是出现两个或两个以上的线程并行运行&#xff0c;即主线程和子线程在同一时间段同时运行。而在这个过程中会出现几种情况&#xff1a; 主线程先运行结束子线程先运行结束主子…

NLP实战:基于Pytorch的文本分类入门实战

目录 一、前期准备 1.环境准备 2.加载数据 二、代码实战 1.构建词典 2.生成数据批次和迭代器 3. 定义模型 4. 定义实例 5.定义训练函数与评估函数 6.拆分数据集并运行模型 三、使用测试数据集评估模型 四、总结 这是一个使用PyTorch实现的简单文本分类实战案例。在…

MySQL_1 数据库的基本操作

目录 一、拾枝杂谈 1.cmd验证MySQL服务 : 2.cmd连接MySQL服务 : 3.MySQL服务 : 二、数据库介绍 1.定义 : 2.SQL语句分类 : 三、数据库操作 1.数据库的创建 : 1 基本语法 2 演示 2.数据库的删除 : 1 基本语法 2 演示 3. 数据库的查询 : 1 基本语法 2 演示 4.数据库的…

【youcans 的 OpenCV 学习课】21. Haar 小波变换

专栏地址&#xff1a;『youcans 的图像处理学习课』 文章目录&#xff1a;『youcans 的图像处理学习课 - 总目录』 【youcans 的 OpenCV 学习课】21. Haar 小波变换 1. 小波变换1.1 小波变换基本概念例程 17_1&#xff1a;常用小波族的图像 1.2 连续小波变换1.3 离散小波变换&a…

《通过十几轮数据进行模型训练,实现精确的无创血糖测量的演绎学习》阅读笔记

目录 0 演绎学习 1 论文摘要 2 论文十问 3 论文亮点与不足之处 4 与其他研究的比较 5 实际应用与影响 6 个人思考与启示 参考文献 0 演绎学习 在本文中&#xff0c;DL指的是Deduction Learning&#xff0c;即演绎学习方法。该方法是一种机器学习方法&#xff0c;通过使…

ServerPapers 开源轻量级服务器监控工具

ServerPapers 开源轻量级服务器监控工具 起因 之前用过一些服务器监控工具&#xff0c;但是有些配置复杂不够方便。也有些配置简单&#xff0c;但没有我想要显示的一些信息。所以我就花了三天时间自己写了一个开源的轻量级服务器监控工具。 项目 介绍 ServerPapers是一个基…

聚观早报|苹果版余额宝四天吸金69亿;​微软拟推出私有版ChatGPT

今日要闻&#xff1a;苹果版余额宝四天吸金69亿元&#xff1b;称微软拟推出私有版ChatGPT&#xff1b;特斯拉上调Model 3、Model Y售价&#xff1b;好莱坞编剧将举行15年来首次罢工&#xff1b;字节跳动要在美国卖书了 苹果版余额宝四天吸金69亿元 早些时候&#xff0c;苹果推…

自动驾驶TPM技术杂谈 ———— I-vista验收标准(试验规程)

文章目录 术语介绍试验准备场地要求环境要求精度要求边界车辆&路沿石 试验方法能力试验双边界车辆平行车位白色标线平行车位双边界车辆垂直车位白色标线垂直车位方柱垂直车位双边界车辆斜向车位白色标线斜向车位 新功能评价平行车位远程操控泊入泊出试验垂直车位远程操控泊…