2 ROS2话题通讯基础(2)

news2024/11/20 11:32:37

ROS2话题通讯基础

  • 2.5 自定义话题通讯
    • 2.5.1 自定义话题通讯的一般流程
    • 2.5.2 创建自定义话题消息简单例子
    • 2.5.3 快速创建C/C++和Python自定义话题通讯的Student.msg
  • 2.6 使用C/C++实现自定义话题通讯
    • 2.6.1 创建C/C++自定义话题发布方功能包并编写节点文件
    • 2.6.2 配置C/C++自定义话题发布方功能包
    • 2.6.3 编译并运行C/C++自定义话题发布方功能包
    • 2.6.4 创建C/C++自定义话题订阅方功能包并编辑节点文件
    • 2.6.5 编译并运行C/C++自定义话题订阅节点
  • 2.7 使用Python实现自定义话题通讯
    • 2.7.1 创建Python自定义话题订阅方节点并编写节点内容
    • 2.7.2 配置Python自定义订阅方功能包
    • 2.7.3 编译并运行Python自定义话题发布方
    • 2.7.4 创建Python自定义话题订阅方
    • 2.7.5 编译运行Python发布方节点
  • 2.8 话题通讯小结

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

2.5 自定义话题通讯

参考内容

Creating custom msg and srv files

2.2.4_话题通信_自定义接口消息_接口文件

2.5.1 自定义话题通讯的一般流程

构建自定义话题其实就是利用ament_cmake工具构建出该自定义话题的.c.py文件,编译好的自定义话题,也就可以和std_msgs一样在创建包的时候,手动添加进去,后续即可不用再配置packages.xmlCMakeLists.txt

    1. 创建ROS2功能包,功能包可以只用来作为存放自定义的msg/srv,不需要节点node的功能包,--build-type必须是ament_camke ,因为目前来看,Python的自定义的消息或者服务也需要通过cmake编译出来再调用,功能包必须是下划线的推荐命名方法,而不是大小写的驼峰,否则会报错,如下所示:

在这里插入图片描述

--- stderr: msgDemoError                         
CMake Error at /opt/ros/humble/share/rosidl_adapter/cmake/rosidl_adapt_interfaces.cmake:59 (message):
  execute_process(/usr/bin/python3.10 -m rosidl_adapter --package-name
  msgDemoError --arguments-file
  /mnt/hgfs/VMware/ROS2_DEMO/2_Chapter/code/build/msgDemoError/rosidl_adapter__arguments__msgDemoError.json
  --output-dir
  /mnt/hgfs/VMware/ROS2_DEMO/2_Chapter/code/build/msgDemoError/rosidl_adapter/msgDemoError
  --output-file
  /mnt/hgfs/VMware/ROS2_DEMO/2_Chapter/code/build/msgDemoError/rosidl_adapter/msgDemoError.idls)
  returned error code 1:

  Error processing 'String name' of 'msgDemoError/Student': ''msgDemoError'
  is an invalid package name.  It should have the pattern
  '^(?!.*__)(?!.*_$)[a-z][a-z0-9_]*$''

  Traceback (most recent call last):

    File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
      return _run_code(code, main_globals, None,
    File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
      exec(code, run_globals)
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/__main__.py", line 19, in <module>
      sys.exit(main())
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/main.py", line 53, in main
      abs_idl_file = convert_to_idl(
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/__init__.py", line 19, in convert_to_idl
      return convert_msg_to_idl(
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/msg/__init__.py", line 28, in convert_msg_to_idl
      msg = parse_message_string(package_name, input_file.stem, content)
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/parser.py", line 520, in parse_message_string
      Type(type_string, context_package_name=pkg_name),
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/parser.py", line 277, in __init__
      super(Type, self).__init__(
    File "/opt/ros/humble/local/lib/python3.10/dist-packages/rosidl_adapter/parser.py", line 201, in __init__
      raise InvalidResourceName(

  rosidl_adapter.parser.InvalidResourceName: 'msgDemoError' is an invalid
  package name.  It should have the pattern
  '^(?!.*__)(?!.*_$)[a-z][a-z0-9_]*$'

Call Stack (most recent call first):
  /opt/ros/humble/share/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake:130 (rosidl_adapt_interfaces)
  CMakeLists.txt:16 (rosidl_generate_interfaces)


---
Failed   <<< msgDemoError [1.53s, exited with code 1]
    1. 在ROS2功能包内创建msg文件夹,里面存放自定义的.msg消息文件,并且 .msg文件必须是大写开头的符合类的命名规则
    1. 配置packages.xml文件,都需要配置下面的内容(下面的配置项与.msg文件无关,是默认的固定配置)
<!-- 这一项是针对在msg中可能用到的其他依赖项,例如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. 是针对在msg中可能用到的其他依赖项,例如geomtry_msgs等等,则需要添加
# find_package(geometry_msgs REQUIRED)

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

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

2.5.2 创建自定义话题消息简单例子

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

  2. 在功能包内创建msg文件夹,其中存放Demo.msg文件,文件内容如下:其中还依赖geometry_msgs

geometry_msgs/Point center
float64 radius
  1. 此时的功能包内部的目录结构如下:tree -a
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code/msg_demo$ tree -a
.
├── CMakeLists.txt
├── include
│   └── msg_demo
├── msg
│   └── Demo.msg
├── package.xml
└── src

4 directories, 3 files
  1. 配置packages.xml添加依赖项,特别的是该Demo.msg还需依赖gemotry_msgs:
<?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>

  <!-- 自定义Demo.msg中依赖geometry_msgs所以添加到depend -->
  <depend>geometry_msgs</depend>

  <!-- 构建自定义msg的必须依赖项 -->
  <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文件,添加构建自定义Demo.msg的依赖:
cmake_minimum_required(VERSION 3.8)
project(msg_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. 自定义的Demo.msg依赖geometry_msgs
find_package(geometry_msgs REQUIRED)
# 2. 必须添加的构建自定义包辅助包的位置
find_package(rosidl_default_generators REQUIRED)

# 3. 构建自定义msg
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Demo.msg"                # Demo.msg的位置    
  DEPENDENCIES geometry_msgs    # 创建Demo.msg需要的依赖
)

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 msg_demo

  2. 查看自定义的消息:激活环境:. install/setup.bash ,查看自定义消息ros2 interface show msg_demo/msg/Demo

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ colcon build --packages-select msg_demo
Starting >>> msg_demo
Finished <<< msg_demo [10.4s]                     

Summary: 1 package finished [10.7s]
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ . install/setup.bash 
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 interface show msg_demo/msg/Demo 
geometry_msgs/Point center
        float64 x
        float64 y
        float64 z
float64 radius
  1. 查看instll下面的文件:其中.c的class文件在install/<功能包名>/include/<功能包名>/<功能包名>/msg/**.pyinstall/<功能包名>/local/lib/python3.10/dist-packages/<功能包名>/msg/**

在这里插入图片描述

2.5.3 快速创建C/C++和Python自定义话题通讯的Student.msg

  1. 新建功能包:ros2 pkg create student_msg --build-type ament_cmake

  2. 创建msg文件夹和Student.msg文件,写入如下内容:

string   name
int32    exam
float64  score
  1. 不需要其他依赖项,配置packages.xml添加下面三项即可:
<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_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Student.msg"
)
  1. 快速构建:colcon build --packages-select student_msg:
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ colcon build --packages-select student_msg
Starting >>> student_msg
Finished <<< student_msg [8.93s]                     

Summary: 1 package finished [9.21s]

2.6 使用C/C++实现自定义话题通讯

2.6.1 创建C/C++自定义话题发布方功能包并编写节点文件

  1. 创建ROS2功能包,这里为了省的创建node文件直接指定了cpp_idl_pub,指令如下:ros2 pkg create cpp_idl_pub --build-type ament_cmake --node-name cppIdlPubNode

  2. 配置Vscode:配置Vscode的settings.json

{
    "C_Cpp.default.includePath": [
        "/opt/ros/humble/include/**",
        "./install/student_msg/include/**"
    ],
    "python.analysis.extraPaths": [
        "/opt/ros/humble/local/lib/python3.10/dist-packages/"
    ],
}
  1. 编写自定义节点文件cppIdlPubNode.cpp
#include "rclcpp/rclcpp.hpp"

// 1. 添加自定义消息头文件,如果vscode出现下划线警告,则需要配置settings.json添加include路径
#include "student_msg/msg/student.hpp"

// C++14中的时间库
using namespace std::chrono_literals;

// 2. 引入Student.msg生成的Student类
using student_msg::msg::Student;

class CppIdlMsgPub: public rclcpp::Node
{
  public:
      /* 3. ROS2节点的构造函数,其中包括一个node对象(初始化时候没有给出节点的名称),
      * 和属性exam_(初始化为0,类型为size_t),以及属性socre_(类型为double_t初始值为60.0) */
      CppIdlMsgPub(const char* nodeName):Node(nodeName), exam_(0), score_(60.0)
      {
        // 4. 创建发布者,参数分别为话题名称myStudent,和发布队列的长队为10
        publisher_ = this->create_publisher<Student>("myStudent", 10);
        // 5. 创建定时器,设置发布的频率,并绑定定时执行的事件,这里给到的是CppIdlMsgPub类的函数
        timer_ = this->create_wall_timer(500ms, std::bind(&CppIdlMsgPub::timer_callback, this));
      }

  private:
     // 6. 定义回调函数
    void timer_callback()
    {
      Student stu = Student();
      // 6.1 姓名zhangsan
      stu.name = "zhangsan";
      // 6.2 考试次数递增
      stu.exam = exam_++;
      // 6.3 分数一直递增
      stu.score = score_;
      score_ += 0.1;
      
      RCLCPP_INFO(this->get_logger(), "Student: '%s', exam time: %d, socre is : %f", stu.name.c_str(),stu.exam,stu.score);
      publisher_->publish(stu);

      
    }

    // 5. 计时器、发布者和计数器字段的声明
    rclcpp::TimerBase::SharedPtr timer_;
    rclcpp::Publisher<Student>::SharedPtr publisher_;
    size_t exam_;
    double_t score_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  // 创建节点,给出构造的节点名为CppIdlMsgPubNode
  rclcpp::spin(std::make_shared<CppIdlMsgPub>("CppIdlMsgPubNode"));
  rclcpp::shutdown();
  return 0;
}

2.6.2 配置C/C++自定义话题发布方功能包

  1. 配置packages.xml文件,添加依赖项有rclcpp用于构建节点,和student_msg用于构建Student.msg
<?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_idl_pub</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>

  <!-- 添加依赖项  -->
  <depend>rclcpp</depend>
  <depend>student_msg</depend>

  <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
cmake_minimum_required(VERSION 3.8)
project(cpp_idl_pub)

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)

# 1. 添加依赖项
find_package(rclcpp REQUIRED)
find_package(student_msg REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

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

# 3. 默认已经包括<INSTALL_INTERFACE>的路径也不用更改
target_include_directories(cppIdlPubNode PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)


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

target_compile_features(cppIdlPubNode PUBLIC c_std_99 cxx_std_17)  # Require C99 and C++17

# 5. Install配置,默认ros2 run <包名>的配置
install(TARGETS cppIdlPubNode
  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()

2.6.3 编译并运行C/C++自定义话题发布方功能包

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

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

  3. 运行:ros2 run cpp_idl_pub cppIdlPubNode

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ colcon build --packages-select cpp_idl_pub
Starting >>> cpp_idl_pub
Finished <<< cpp_idl_pub [10.0s]                     

Summary: 1 package finished [10.4s]
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ . install/setup.bash
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 run cpp_idl_pub cppIdlPubNode 
[INFO] [1683041064.126034476] [CppIdlMsgPubNode]: Student: 'zhangsan', exam time: 0, socre is : 60.000000
[INFO] [1683041064.625514370] [CppIdlMsgPubNode]: Student: 'zhangsan', exam time: 1, socre is : 60.100000
[INFO] [1683041065.125571561] [CppIdlMsgPubNode]: Student: 'zhangsan', exam time: 2, socre is : 60.200000
^C[INFO] [1683041082.271152379] [rclcpp]: signal_handler(signum=2)

2.6.4 创建C/C++自定义话题订阅方功能包并编辑节点文件

  1. 创建ROS2功能包,包名为cpp_idl_sub,节点名称为cppIdlSubNode,并直接指定依赖项为rclcppstudent_msg,如下所示:ros2 pkg create cpp_idl_sub --build-type ament_cmake --node-name cppIdlSubNode --dependencies rclcpp student_msg

  2. 编辑节点文件:订阅Student类型的话题,话题名为myStudent:

#include "rclcpp/rclcpp.hpp"

// 1. 添加自定义消息头文件,如果vscode出现下划线警告,则需要配置settings.json添加include路径
#include "student_msg/msg/student.hpp"

// 占位符,结合std::bind函数的绑定使用
using std::placeholders::_1;

// 2. 引入Student.msg生成的Student类
using student_msg::msg::Student;

class CppIdlMsgSub: public rclcpp::Node
{
  public:
      /* 3. ROS2节点的构造函数,其中包括一个node对象(初始化时候没有给出节点的名称),
      * 和属性exam_(初始化为0,类型为size_t),以及属性socre_(类型为double_t初始值为60.0) */
      CppIdlMsgSub(const char* nodeName):Node(nodeName)
      {
      subscription_ = this->create_subscription<Student>(
      "myStudent", 10, std::bind(&CppIdlMsgSub::topic_callback, this, _1));
      }

  private:
    // 4. 定义订阅到消息的回调函数
    void topic_callback(const Student & stu) const
    {
      RCLCPP_INFO(this->get_logger(), "I heard: %s, exam: %d, score: %f", stu.name.c_str(),stu.exam, stu.score);
    }

    // 5. 计时器、发布者和计数器字段的声明
    rclcpp::Subscription<Student>::SharedPtr subscription_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  // 创建节点,给出构造的节点名为CppIdlMsgSubNode
  rclcpp::spin(std::make_shared<CppIdlMsgSub>("CppIdlMsgSubNode"));
  rclcpp::shutdown();
  return 0;
}

2.6.5 编译并运行C/C++自定义话题订阅节点

  1. 由于在创建包时候已经指定了依赖项,可以不用再进行配置packages.xmlCMakeLists.txt文件,直接编译colcon build --packages-select cpp_idl_sub

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

  3. 运行:
    在这里插入图片描述

2.7 使用Python实现自定义话题通讯

2.7.1 创建Python自定义话题订阅方节点并编写节点内容

  1. 创建ROS2 Python发布方功能包,包名为python_idl_pub,节点名为pythonIdlPubNoderos2 pkg create python_idl_pub --build-type ament_python --node-name pythonIdlPubNode

  2. 配置Vscode环境:在settings.json中添加Python的依赖项位置,虽然编译不影响报错,但是vscode的警告看着也不习惯:

在这里插入图片描述

  1. 编写订阅节点:
import rclpy
from rclpy.node import Node

# 1. 导入包,如果vscode下划线警告,则需要配置settings.json
from student_msg.msg import Student


class PythonIdlPub(Node):

    def __init__(self, nodeName):
        # 1. 初始化父类构造函数,其中节点名需要创建时候指定
        super().__init__(nodeName)
        self.exam_ = 0
        self.score_ = 60.0
        # 2. 声明发布者,发布消息类型为Student,话题名为myStudent,队列大小为10
        self.publisher_ = self.create_publisher(Student, 'myStudent', 10)
        # 3. 创建定时器,其中更新频率为0.5秒,并绑定回调函数
        self.timer = self.create_timer(0.5, self.timer_callback)
        
    # 4. 定义回调函数
    def timer_callback(self):
        stu = Student()
        stu.name = "zhangsan"
        stu.exam = self.exam_
        stu.score = self.score_

        self.publisher_.publish(stu)
        self.get_logger().info('Publishing: name: {}, exam:{}, score:{}'.format(stu.name,stu.exam,stu.score))
        self.exam_ += 1
        self.score_ += 0.1


def main(args=None):
    rclpy.init(args=args)
    pythonIdlPubNode = PythonIdlPub("pythonIdlPubNode")
    rclpy.spin(pythonIdlPubNode)
    # 销毁节点
    pythonIdlPubNode.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

2.7.2 配置Python自定义订阅方功能包

  1. 配置packages.xml增加rclpystudent_msg两个依赖项,注意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_idl_pub</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

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

  <!-- 添加依赖项 -->
  <exec_depend>rclpy</exec_depend>
  <exec_depend>student_msg</exec_depend>

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

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

package_name = 'python_idl_pub'

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': [
            'pythonIdlPubNode = python_idl_pub.pythonIdlPubNode:main'
        ],
    },
)

2.7.3 编译并运行Python自定义话题发布方

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

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

  3. 运行节点:ros2 run python_idl_pub pythonIdlPubNode

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 run python_idl_pub pythonIdlPubNode 
[INFO] [1683044269.902750751] [pythonIdlPubNode]: Publishing: name: zhangsan, exam:0, score:60.0
[INFO] [1683044270.393748471] [pythonIdlPubNode]: Publishing: name: zhangsan, exam:1, score:60.1
[INFO] [1683044270.891683074] [pythonIdlPubNode]: Publishing: name: zhangsan, exam:2, score:60.2

2.7.4 创建Python自定义话题订阅方

  1. 创建Python功能包时,包名为python_idl_sub,节点名为pythonIdlSubNode,直接指定依赖项rclpystudent_msgros2 pkg create python_idl_sub --build-type ament_python --node-name pythonIdlSubNode --dependencies rclpy student_msg

  2. 编写节点:

import rclpy
from rclpy.node import Node

# 1. 导入包,如果vscode下划线警告,则需要配置settings.json
from student_msg.msg import Student


class PythonIdlSub(Node):

    def __init__(self, nodeName):
        # 1. 构造函数,初始化node节点
        super().__init__(nodeName)
        # 2. 声明订阅者,订阅话题`myTopicNmae`,并绑定回调函数
        self.subscription = self.create_subscription(Student,'myStudent',self.listener_callback,10)

    # 3. 定义回调函数
    def listener_callback(self, stu:Student):
        self.get_logger().info('I heard: name:{}, exam:{}, score{}'.format(stu.name, stu.exam, stu.score))


def main(args=None):
    rclpy.init(args=args)
    pythonIdlSubNode = PythonIdlSub("pythonIdlSubNode")
    rclpy.spin(pythonIdlSubNode)
    pythonIdlSubNode.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

2.7.5 编译运行Python发布方节点

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

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

  3. 运行所有节点:

在这里插入图片描述

2.8 话题通讯小结

    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找不到或者不是一个,那是需要再进一步的手动配置的

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

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

相关文章

如何选择适合企业的网盘?必须要考虑这几个方面

随着云存储技术的发展&#xff0c;传统的文件存储服务已逐渐不能满足企业日益增长的文件应用、共享和存储需求。越来越多的企业开始将目光转移到企业网盘上。 在选择企业网盘工具时&#xff0c;比较重要的有两个方面&#xff0c;一个是数据的安全性&#xff0c;一个是协同办公。…

Java 将增加虚拟线程,挑战 Go 协程

Java19 正式发布&#xff0c;带来了一个 Java 开发者垂涎已久的新特性 —— 虚拟线程。在 Java 有这个新特性之前&#xff0c;Go 语言的协程风靡已久&#xff0c;在并发编程领域可以说是叱咤风云。随着国内 Go 语言的快速发展与推广&#xff0c;协程好像成为了一个世界上最好语…

K8S二进制单节点 一键部署K8S_V1.21.x

1、安装前注意事项 安装shell脚本在文章最后位置 1、提前配置静态IP 把脚本的IP 192.168.1.31 换成你的IP 2、创建安装包路径 /home/software/shell 所有的tar包 shell脚本 放在这里 3、免密登录配置所有节点 提前下载镜像如下&#xff1a; [rootmaster01 ~]# docker image…

Ubuntu搜狗输入法安装指南

Ubuntu搜狗输入法安装指南 Ubuntu搜狗输入法安装指南搜狗输入法已支持Ubuntu1604、1804、1910、2004、2010Ubuntu20.04及以上安装搜狗输入法步骤 Ubuntu搜狗输入法安装指南 下载地址&#xff1a;https://shurufa.sogou.com/ 计算为amd64的选择x86_64&#xff0c;以下教程来源…

ORBBEC(奥比中光)AstraPro相机在ROS2下的标定与D2C(配准与对齐)

文章目录 1.rgb、depth相机标定矫正1.1.标定rgb相机1.2.标定depth相机1.3.rgb、depth相机一起标定&#xff08;效果重复了&#xff09;1.4.取得标定结果1.4.1.得到的标定结果的意义&#xff1a;1.5.IR、RGB相机分别应用标定结果1.5.1.openCV应用标定结果1.5.2.ros2工程应用标定…

[stable-diffusion-art] 指北-2 如何为sd提出好的prompt

https://stable-diffusion-art.com/how-to-come-up-with-good-prompts-for-ai-image-generation/https://stable-diffusion-art.com/how-to-come-up-with-good-prompts-for-ai-image-generation/1.prompt可以促使模型生成以前不存在的高质量的图片&#xff0c;例如&#xff1a;…

windows如何使用脚本打开多个软件

文章目录 windows如何使用脚本打开多个软件问题缘由省流版本制作脚本步骤新建文本找到文件的安装位置方法一&#xff1a;方法二&#xff1a; 总结 windows如何使用脚本打开多个软件 问题缘由 因为强迫症&#xff0c;不想让软件自启&#xff0c;会导致开机变慢&#xff0c;电脑…

Lecture7 处理多维特征的输入(Multiple Dimension Input)

以实际代码出发&#xff0c;逐行讲解。 完整代码&#xff1a; import numpy as np import torch import matplotlib.pyplot as plt# load data xy np.loadtxt(C:\\Users\\14185\\Desktop\\diabetes.csv, delimiter,, dtypenp.float32) x_data torch.from_numpy(xy[:, :-1])…

226. 翻转二叉树【58】

难度等级&#xff1a;容易 上一篇算法&#xff1a; 543. 二叉树的直径【71】 力扣此题地址&#xff1a; 226. 翻转二叉树 - 力扣&#xff08;Leetcode&#xff09; 1.题目&#xff1a;226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返…

DAY 52 LVS+Keepalived群集

Keepalived工具介绍 普通集群容易出现的问题 企业应用中&#xff0c;单台服务器承担应用存在单点故障的危险。 单点故障一旦发生&#xff0c; 企业服务将发生中断&#xff0c;造成极大的危害。 Keepalived工具 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&…

v2c - 从Verilog 转换到 C语言的工具

文章目录 一、如何安装1.下载二进制文件2.基准测试 二、如何使用v2c的应用描述工具流程使用 v2c 转换器的工作示例 三、注意事项情形一&#xff1a;拼接&#xff1a;{4{x}}情形1-1 y&{x&#xff0c;x&#xff0c;x&#xff0c;x}情形1-2 y&{x&#xff0c;x&#xff0c;…

【C++】string 类的实现

目录 构造函数赋值重载关于浅拷贝 迭代器容量相关reserveresize 修改push_backappendinserterase关于npos 流运算符重载流插入流提取 构造函数 无参数构造和传参构造 通过对参数设置缺省值为空串""同时满足无参构造和传参构造成员 _size 和 _capacity 均是针对有效…

自动驾驶—连续系统LQR最优控制的黎卡提方程推导

1. Why use the Riccati equation? 最优控制算法LQR是Linear Quadratic Regulator的缩写,Q、R就是需要设计的半正定矩阵和正定矩阵。考虑根据实车的情况去标定此参数,从理论和工程层面去理解,如果增大Q、减小R,则此时控制系统响应速度比较快速(比较剧烈),直观反映方向…

5月1日 9H45min|5.2 8H20min+30min|时间轴复盘

8:00 起床 8:00-8:30 洗漱吃饭 8:30-10:40 temporary pools阅读真题精读 (真的很慢了 不知道什么原因 感觉也没有彻底完全弄懂)【2h+10min】 10:40-11:10 午餐+酸奶(423+174KJ) 11:20-12:30 三篇阅读【1h+10min】 13:10-14:50 健身 14:50-15:45诵默写list…

Ae:画笔工具

画笔工具 Brush Tool 快捷键&#xff1a;Ctrl B 画笔工具 Brush Tool仅能工作在图层 Layer面板上。 双击纯色图层、像素图层等可打开图层面板。 在 Ae 中的每次画笔绘制都将新建一条路径&#xff0c;然后通过对路径的描边来显示绘制结果&#xff0c;故又称为“绘画描边”或“…

函数-实现交换两个变量的内容

用函数实现交换两个变量的内容&#xff0c;对于该问题我们该如何实现呢&#xff1f;在这里我就用整型变量来说明。 题目&#xff1a;写一个函数可以交换两个整形变量的内容。 我们先来看看如下代码&#xff1a; #include <stdio.h> void swap(int x, int y) {int tem…

Android进阶之光:Dagger2原理简要分析

Dagger2注入框架原理简要分析 使用Dagger2需要的依赖: implementation com.google.dagger:dagger-android:2.46 implementation com.google.dagger:dagger-android-support:2.46 annotationProcessor com.google.dagger:dagger-android-processor:2.46 annotationProcessor c…

第二十七章 碰撞体Collision(下)

本章节我们继续研究碰撞体&#xff0c;并且探索一下碰撞体与刚体之间的联系。我们回到之前的工程&#xff0c;然后给我们的紫色球体Sphere1也添加一个刚体组件。如下所示 此时&#xff0c;两个球体都具备了碰撞体和刚体组件。接下来&#xff0c;我们Play运行查看效果 我们发现&…

从零开始带你开发橙光游戏AVG框架(仿 葬花 )

来源 从零开始带你开发橙光游戏AVG框架【55课数 收费】 从零开始带你开发橙光游戏AVG框架 unity教程【16课数 免费】 。。。。。。 挺大的&#xff0c;因为很多音频&#xff0c;.git就有 2.6G AVG_20230413_2020.2.23f1c1 介绍 QuickSheet使用 bug 包报错 可能是我换了un…

LeetCode138. 复制带随机指针的链表

138. 复制带随机指针的链表 描述示例解题思路以及代码解法1解法2 描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成…