ROS2 Humble 学习【openEuler】

ROS2 Humble 学习

  • 1 介绍
    • 1.1 概述
    • 1.2 ROS2 详细介绍
    • 1.3 openEuler 安装 ROS2 Humble
    • 1.4 ROS2 系统架构
  • 2 ROS2 基础
    • 2.1 节点编写、编译、运行【简单示例】
      • 节点编写
      • 节点编译 g++
      • 节点运行
      • 节点编译 make
      • 节点编译 CMakeLists.txt
      • CMake依赖查找流程
      • Python 依赖查找流程
    • 2.2 节点交互、启动、查看【命令】
    • 2.3 ROS2 工作空间、功能包、构建工具 Colcon
      • 工作空间
      • 功能包
        • 功能包获取【安装】
        • 功能包获取【手动编译】
        • 功能包指令 ros2 pkg
      • 构建工具 Colcon 介绍 & 安装
    • 2.4 编写节点
      • 编写节点【RCLCPP】
        • 创建工作空间
        • 创建功能包
        • 创建节点
        • 编写代码
        • 编译运行
        • 测试
      • 编写节点【RCLPY】
        • 创建工作空间
        • 创建功能包
        • 创建节点
        • 编写代码
        • 编译运行
        • 测试
    • 2.5 节点编写、编译、运行【面向对象编程 OOP】
      • C++ 示例
      • Python
    • 2.6 Colcon 介绍
      • colcon
      • catkin_make
      • ament_tools
      • 构建指令
      • 指定构建后安装的目录
      • 合并构建目录
      • 符号链接安装
      • 错误时继续安装
      • CMake参数
      • 控制构建线程
      • 开启构建日志
    • 2.7 ROS2节点发现与多机通信
      • 选择域ID (短版本)
      • 选择域ID (长版本)
    • 2.8 通信--话题与服务
      • TCP/UDP
      • 基于共享内存的进程间通信(IPC)方式
      • ZeroMQ
      • PyZmq
      • 话题
        • 命令
        • 实现 RCLCPP
        • 实现 RCLPY
      • 服务
        • 实现 RCLCPP
        • 实现 RCLPY
    • 2.9 通信--参数
  • 3 机器人学
  • 4 建模仿真
  • 5 Navi2 导航
  • 6 Moveit2 机械臂
  • 参考

1 介绍

1.1 概述

ROS(Robot Operating System,下文简称“ROS”)是一个适用于机器人的开源的元操作系统。它提供了操作系统应有的服务,包括硬件抽象,底层设备控制,常用函数的实现,进程间消息传递,以及包管理。它也提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。

ROS 2 Documentation humble
小鱼–动手学ROS2
机器人操作系统入门讲义
本文在 openEuler 22.03 虚拟机中按照 ROS2 Humble 官方教程、小鱼文章大纲、机器人操作系统入门讲义 进行学习调试记录

1.2 ROS2 详细介绍

ROS2 详细介绍

1.3 openEuler 安装 ROS2 Humble

openEuler 安装 ROS2 Humble

1.4 ROS2 系统架构

在这里插入图片描述

  • 抽象DDS层-RMW(ROS Middleware Interface)
  • RCL(ROS Client Library)ROS客户端库,其实就是ROS的一种API,提供了对ROS话题、服务、参数、Action等接口。
    在这里插入图片描述

2 ROS2 基础

2.1 节点编写、编译、运行【简单示例】

ROS2的C++节点

节点编写

  • 创建文件 ros2_node.cpp
touch ros2_node.cpp
  • 编写代码
#include "rclcpp/rclcpp.hpp"int main(int argc, char **argv)
{// 调用rclcpp的初始化函数rclcpp::init(argc, argv);// 调用rclcpp的循环运行我们创建的first_node节点rclcpp::spin(std::make_shared<rclcpp::Node>("first_node"));return 0;
}

节点编译 g++

  • 编译报错
[euler@Euler node]$ ls
ros2_node.cpp
[euler@Euler node]$ g++ ros2_node.cpp 
ros2_node.cpp:1:10: 致命错误:rclcpp/rclcpp.hpp:没有那个文件或目录1 | #include "rclcpp/rclcpp.hpp"|          ^~~~~~~~~~~~~~~~~~~
编译中断。
[euler@Euler node]$
  • 定位头文件
/opt/ros/humble/include/rclcpp
ls rclcpp/* | grep rclcpp.h
[euler@Euler rclcpp]$ ls rclcpp/* | grep rclcpp.h
rclcpp/rclcpp.hpp
[euler@Euler rclcpp]$
  • g++ 指定相应目录
g++ ros2_node.cpp -I /opt/ros/humble/include/rclcpp/[euler@Euler node]$ g++ ros2_node.cpp -I /opt/ros/humble/include/rclcpp/
In file included from /opt/ros/humble/include/rclcpp/rclcpp/executors/multi_threaded_executor.hpp:25,from /opt/ros/humble/include/rclcpp/rclcpp/executors.hpp:21,from /opt/ros/humble/include/rclcpp/rclcpp/rclcpp.hpp:155,from ros2_node.cpp:1:
/opt/ros/humble/include/rclcpp/rclcpp/executor.hpp:30:10: 致命错误:rcl/guard_condition.h:没有那个文件或目录30 | #include "rcl/guard_condition.h"|          ^~~~~~~~~~~~~~~~~~~~~~~
编译中断。
[euler@Euler node]$
  • g++ 指令多层依赖目录
g++ ros2_node.cpp -lrclcpp -lrcutils -std=c++17 \
-I/opt/ros/humble/include/rclcpp/ \
-I /opt/ros/humble/include/rcl/ \
-I /opt/ros/humble/include/rcutils/ \
-I /opt/ros/humble/include/rmw \
-I /opt/ros/humble/include/rcl_yaml_param_parser/ \
-I /opt/ros/humble/include/rosidl_runtime_c \
-I /opt/ros/humble/include/rosidl_typesupport_interface \
-I /opt/ros/humble/include/rcpputils \
-I /opt/ros/humble/include/builtin_interfaces \
-I /opt/ros/humble/include/rosidl_runtime_cpp \
-I /opt/ros/humble/include/tracetools \
-I /opt/ros/humble/include/rcl_interfaces \
-I /opt/ros/humble/include/libstatistics_collector \
-I /opt/ros/humble/include/statistics_msgs \
-L /opt/ros/humble/lib/ \
-Wl,-rpath,/opt/ros/humble/lib/

-Wl: 这个前缀告诉编译器,接下来的选项是传递给链接器(ld)的。
-rpath: 这个选项指定了运行时库的搜索路径。

节点运行

打开新的终端,使用ros2 node list查看正在运行的节点,是否有first_node。
在这里插入图片描述

source /opt/ros/humble/setup.bash

在这里插入图片描述

节点编译 make

  • 安装 make
  • 编写 Makefile
    新建Makefile
build:g++ ros2_node.cpp -lrclcpp -lrcutils -std=c++17 \-I/opt/ros/humble/include/rclcpp/ \-I /opt/ros/humble/include/rcl/ \-I /opt/ros/humble/include/rcutils/ \-I /opt/ros/humble/include/rmw \-I /opt/ros/humble/include/rcl_yaml_param_parser/ \-I /opt/ros/humble/include/rosidl_runtime_c \-I /opt/ros/humble/include/rosidl_typesupport_interface \-I /opt/ros/humble/include/rcpputils \-I /opt/ros/humble/include/builtin_interfaces \-I /opt/ros/humble/include/rosidl_runtime_cpp \-I /opt/ros/humble/include/tracetools \-I /opt/ros/humble/include/rcl_interfaces \-I /opt/ros/humble/include/libstatistics_collector \-I /opt/ros/humble/include/statistics_msgs \-L /opt/ros/humble/lib/ \-Wl,-rpath,/opt/ros/humble/lib/clean:rm a.out
euler@Euler node]$ ls
Makefile  ros2_node.cpp
[euler@Euler node]$ make build[euler@Euler node]$ ls
a.out  Makefile  ros2_node.cpp
[euler@Euler node]$ make clean
rm a.out
[euler@Euler node]$

节点编译 CMakeLists.txt

使用 make 调用 Makefile,需要自己手写 Makefile,而 cmake 通过调用 CMakeLists.txt 可以直接生成 Makefile。

  • 新建CMakeLists.txt
touch CMakeLists.txt
  • 编写
cmake_minimum_required(VERSION 3.22)project(first_node)#include_directories 添加特定的头文件搜索路径 ,相当于指定g++编译器的-I参数
include_directories(/opt/ros/humble/include/rclcpp/)
include_directories(/opt/ros/humble/include/rcl/)
include_directories(/opt/ros/humble/include/rcutils/)
include_directories(/opt/ros/humble/include/rcl_yaml_param_parser/)
include_directories(/opt/ros/humble/include/rosidl_runtime_c/)
include_directories(/opt/ros/humble/include/rosidl_typesupport_interface/)
include_directories(/opt/ros/humble/include/rcpputils/)
include_directories(/opt/ros/humble/include/builtin_interfaces/)
include_directories(/opt/ros/humble/include/rmw/)
include_directories(/opt/ros/humble/include/rosidl_runtime_cpp/)
include_directories(/opt/ros/humble/include/tracetools/)
include_directories(/opt/ros/humble/include/rcl_interfaces/)
include_directories(/opt/ros/humble/include/libstatistics_collector/)
include_directories(/opt/ros/humble/include/statistics_msgs/)# link_directories - 向工程添加多个特定的库文件搜索路径,相当于指定g++编译器的-L参数
link_directories(/opt/ros/humble/lib/)# add_executable - 生成first_node可执行文件
add_executable(first_node ros2_node.cpp)# target_link_libraries - 为first_node(目标) 添加需要动态链接库,相同于指定g++编译器-l参数
# 下面的语句代替 -lrclcpp -lrcutils
target_link_libraries(first_node rclcpp rcutils)# c++17
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
[euler@Euler node]$ ls
CMakeLists.txt  ros2_node.cpp
[euler@Euler node]$ mkdir build
[euler@Euler node]$ ls
build  CMakeLists.txt  ros2_node.cpp
[euler@Euler node]$ cd build/
[euler@Euler build]$ ls
[euler@Euler build]$ cmake ..
[euler@Euler build]$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile
[euler@Euler build]$ make 
[ 50%] Building CXX object CMakeFiles/first_node.dir/ros2_node.cpp.o
[100%] Linking CXX executable first_node
[100%] Built target first_node
[euler@Euler build]$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  first_node  Makefile
[euler@Euler build]$

CMake依赖查找流程

用cmake虽然成功,但是CMakeLists.txt的内容有些臃肿,需要简化。

  • CMakeLists.txt 优化如下
cmake_minimum_required(VERSION 3.22)
project(first_node)find_package(rclcpp REQUIRED)
add_executable(first_node ros2_node.cpp)
target_link_libraries(first_node rclcpp::rclcpp)
  • 加载 ros 环境
source /opt/ros/humble/setup.bash
  • 生成和编译
mkdir build
cd build
cmake ..
make
[euler@Euler build]$ cmake ..
-- Found rclcpp: 16.0.4 (/opt/ros/humble/share/rclcpp/cmake)
-- Found rosidl_generator_c: 3.1.4 (/opt/ros/humble/share/rosidl_generator_c/cmake)
-- Found rosidl_adapter: 3.1.4 (/opt/ros/humble/share/rosidl_adapter/cmake)
-- Found rosidl_generator_cpp: 3.1.4 (/opt/ros/humble/share/rosidl_generator_cpp/cmake)
-- Using all available rosidl_typesupport_c: rosidl_typesupport_fastrtps_c;rosidl_typesupport_introspection_c
-- Using all available rosidl_typesupport_cpp: rosidl_typesupport_fastrtps_cpp;rosidl_typesupport_introspection_cpp
CMake Warning at /opt/ros/humble/share/libyaml_vendor/cmake/ament_cmake_export_libraries-extras.cmake:116 (message):Package 'libyaml_vendor' exports library 'yaml' which couldn't be found
Call Stack (most recent call first):/opt/ros/humble/share/libyaml_vendor/cmake/libyaml_vendorConfig.cmake:41 (include)/opt/ros/humble/share/rcl_yaml_param_parser/cmake/ament_cmake_export_dependencies-extras.cmake:21 (find_package)/opt/ros/humble/share/rcl_yaml_param_parser/cmake/rcl_yaml_param_parserConfig.cmake:41 (include)/opt/ros/humble/share/rcl/cmake/ament_cmake_export_dependencies-extras.cmake:21 (find_package)/opt/ros/humble/share/rcl/cmake/rclConfig.cmake:41 (include)/opt/ros/humble/share/libstatistics_collector/cmake/ament_cmake_export_dependencies-extras.cmake:21 (find_package)/opt/ros/humble/share/libstatistics_collector/cmake/libstatistics_collectorConfig.cmake:41 (include)/opt/ros/humble/share/rclcpp/cmake/ament_cmake_export_dependencies-extras.cmake:21 (find_package)/opt/ros/humble/share/rclcpp/cmake/rclcppConfig.cmake:41 (include)CMakeLists.txt:4 (find_package)-- Found rmw_implementation_cmake: 6.1.1 (/opt/ros/humble/share/rmw_implementation_cmake/cmake)
-- Found rmw_fastrtps_cpp: 6.2.2 (/opt/ros/humble/share/rmw_fastrtps_cpp/cmake)
-- Using RMW implementation 'rmw_fastrtps_cpp' as default
-- Configuring done
-- Generating done
-- Build files have been written to: /home/euler/worthsen/node/build
[euler@Euler build]$
  • find_package查找路径对应的环境变量如下。
<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH
  • echo $PATH
[euler@Euler build]$ echo $PATH
/opt/ros/humble/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin
[euler@Euler build]$

PATH中的路径如果以bin或sbin结尾,则自动回退到上一级目录,接着检查这些目录下的

<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/          (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/                (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/  (U)

cmake找到这些目录后,会开始依次找Config.cmake或Find.cmake文件。找到后即可执行该文件并生成相关链接信息。

打开 /opt/ros/humble/share/rclcpp/cmake 会发现 rclcppConfig.cmake 就在其中。

Python 依赖查找流程

python 打包和引入依赖,比C++简单很多。

  • 编写 ROS2 的 Python 节点
touch ros2_node.pyvim ros2_node.py 输入如下内容# 导入rclpy库
import rclpy
from rclpy.node import Node
# 调用rclcpp的初始化函数
rclpy.init() 
# 调用rclcpp的循环运行我们创建的second_node节点
rclpy.spin(Node("second_node"))
  • 运行
python3 ros2_node.py
  • 查看
[euler@Euler ~]$ source /opt/ros/humble/setup.bash
[euler@Euler ~]$ ros2 node list
/second_node
[euler@Euler ~]$
  • Python 包查找流程
    Python3 运行 import rclpy 是通过环境变量 PYTHONPATH 查找到的
echo $PYTHONPATH[euler@Euler node]$ echo $PYTHONPATH
/opt/ros/humble/lib/python3.9/site-packages
[euler@Euler node]$ ls -l /opt/ros/humble/lib/python3.9/site-packages | grep rclpy
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_executors
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_executors-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_guard_conditions
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_guard_conditions-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_action_client
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_action_client-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_action_server
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_action_server-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_client
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_client-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_publisher
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_publisher-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_service
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_service-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_minimal_subscriber
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_minimal_subscriber-0.15.1-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 examples_rclpy_pointcloud_publisher
drwxr-xr-x.  2 root root  4096  726 14:27 examples_rclpy_pointcloud_publisher-0.15.1-py3.9.egg-info
drwxr-xr-x.  5 root root  4096  726 14:27 rclpy
drwxr-xr-x.  2 root root  4096  726 14:27 rclpy-3.3.8-py3.9.egg-info
drwxr-xr-x.  3 root root  4096  726 14:27 rclpy_message_converter
drwxr-xr-x.  2 root root  4096  726 14:27 rclpy_message_converter-2.0.1-py3.9.egg-info
drwxr-xr-x.  4 root root  4096  726 14:33 rclpy_message_converter_msgs
drwxr-xr-x.  2 root root  4096  726 14:33 rclpy_message_converter_msgs-2.0.1-py3.9.egg-info
[euler@Euler node]$

2.2 节点交互、启动、查看【命令】

  • ROS2 四种通信方式:
    1)话题-topics
    2)服务-services
    3)动作-Action
    4)参数-parameters

  • 启动节点命令

# 启动 包 中的节点
ros2 run <package_name> <executable_name>eg: ros2 run turtlesim turtlesim_node
  • 查看节点
ros2 node list
  • 查看节点信息
ros2 node info <node_name>
[euler@Euler ~]$ ros2 node info /first_node
/first_nodeSubscribers:/parameter_events: rcl_interfaces/msg/ParameterEventPublishers:/parameter_events: rcl_interfaces/msg/ParameterEvent/rosout: rcl_interfaces/msg/LogService Servers:/first_node/describe_parameters: rcl_interfaces/srv/DescribeParameters/first_node/get_parameter_types: rcl_interfaces/srv/GetParameterTypes/first_node/get_parameters: rcl_interfaces/srv/GetParameters/first_node/list_parameters: rcl_interfaces/srv/ListParameters/first_node/set_parameters: rcl_interfaces/srv/SetParameters/first_node/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomicallyService Clients:Action Servers:Action Clients:
  • 重映射节点名称
ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle
  • 运行节点时设置参数
ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_level:=10

2.3 ROS2 工作空间、功能包、构建工具 Colcon

工作空间

一个工作空间下可以有多个功能包,一个功能包可以有多个节点存在。

eg: 创建 ros2 工作区,其中包含 src 文件夹
mkdir worthsen
cd worthsen
mkdir -p ros2/src

功能包

功能包中存放节点,ROS2 中功能包根据编译方式的不同分为三种类型。
(1)ament_python,适用于python程序
(2)cmake,适用于C++
(3)ament_cmake,适用于C++程序,是cmake的增强版

功能包获取【安装】
sudo yum install ros-<version>-package_name

安装获取会自动放置到系统目录,不用再次手动source。

功能包获取【手动编译】

手动编译之后,需要手动source工作空间的install目录。

功能包指令 ros2 pkg
create       Create a new ROS2 package
executables  Output a list of package specific executables
list         Output a list of available packages
prefix       Output the prefix path of a package
xml          Output the XML of the package manifest or a specific tag
  • 创建功能包
ros2 pkg create <package-name>  --build-type  {cmake,ament_cmake,ament_python}  --dependencies <依赖名字>
  • 列出可执行文件
# 列出所有
ros2 pkg executables# 列出turtlesim功能包的所有可执行文件
ros2 pkg executables turtlesim
  • 列出所有的包
ros2 pkg list
  • 输出某个包所在路径的前缀
ros2 pkg prefix  <package-name>eg: 比如小乌龟
ros2 pkg prefix turtlesim[euler@Euler ~]$ source /opt/ros/humble/setup.bash 
[euler@Euler ~]$ ros2 pkg prefix turtlesim
/opt/ros/humble
[euler@Euler ~]$
  • 列出包的清单描述文件
    每一个功能包都有一个标配的manifest.xml文件,用于记录这个包的名字,构建工具,编译信息,拥有者,干啥用的等信息。
    通过这个信息,就可以自动为该功能包安装依赖,构建时确定编译顺序等
ros2 pkg xml turtlesim[euler@Euler ~]$ ros2 pkg xml turtlesim
<package format="3"><name>turtlesim</name><version>1.4.2</version><description>turtlesim is a tool made for teaching ROS and ROS packages.</description><maintainer email="audrow@openrobotics.org">Audrow Nash</maintainer><maintainer email="michael.jeronimo@openrobotics.org">Michael Jeronimo</maintainer><license>BSD</license><url type="website">http://www.ros.org/wiki/turtlesim</url><url type="bugtracker">https://github.com/ros/ros_tutorials/issues</url><url type="repository">https://github.com/ros/ros_tutorials</url><author email="dthomas@osrfoundation.org">Dirk Thomas</author><author>Josh Faust</author><author email="mabel@openrobotics.org">Mabel Zhang</author><author email="sloretz@openrobotics.org">Shane Loretz</author><build_depend>qt5-qmake</build_depend><build_depend>qtbase5-dev</build_depend><buildtool_depend>ament_cmake</buildtool_depend><buildtool_depend>rosidl_default_generators</buildtool_depend><exec_depend>libqt5-core</exec_depend><exec_depend>libqt5-gui</exec_depend><exec_depend>rosidl_default_runtime</exec_depend><depend>ament_index_cpp</depend><depend>geometry_msgs</depend><depend>rclcpp</depend><depend>rclcpp_action</depend><depend>std_msgs</depend><depend>std_srvs</depend><member_of_group>rosidl_interface_packages</member_of_group><export><build_type>ament_cmake</build_type></export>
</package>
[euler@Euler ~]$

构建工具 Colcon 介绍 & 安装

ROS2 默认是没有安装 colcon 的,colcon 想当于 ros1 中的 catkin 工具。
colcon是一系列python脚本,是对cmake等编译工具的封装。

  • 安装
# Using pip on any platform
# 普通用户权限安装,避障权限问题
pip install -U colcon-common-extensions

openEuler 安装 ROS2 Humble【编译系统】

  • 克隆示例代码
[euler@Euler colcon]$ pwd
/home/euler/worthsen/node/colcon
[euler@Euler colcon]$ git clone https://github.com/ros2/examples src/examples -b humble
[euler@Euler colcon]$ tree -L 4
.
└── src└── examples├── CONTRIBUTING.md├── launch_testing│   └── launch_testing_examples├── LICENSE├── rclcpp│   ├── actions│   ├── composition│   ├── executors│   ├── README.md│   ├── services│   ├── timers│   ├── topics│   └── wait_set├── rclpy│   ├── actions│   ├── executors│   ├── guard_conditions│   ├── pytest.ini│   ├── services│   └── topics└── README.md18 directories, 5 files
[euler@Euler colcon]$
  • 编译
colcon buildeg:
[euler@Euler colcon]$ source /opt/ros/humble/setup.bash 
[euler@Euler colcon]$ colcon build
...
Summary: 22 packages finished [5min 2s]
[euler@Euler colcon]$ tree -L 1
.
├── build
├── install
├── log
└── src4 directories, 0 files
  • 目录
    (1)build 目录存储的是中间文件。对于每个包,将创建一个子文件夹,在其中调用例如CMake
    (2)install 目录是每个软件包将安装到的位置。默认情况下,每个包都将安装到单独的子目录中。
    (3)log 目录包含有关每个colcon调用的各种日志信息。

  • 终端 1 运行订阅者节点

# source 一下资源
source install/setup.bash
# 运行一个订阅节点
ros2 run examples_rclcpp_minimal_subscriber subscriber_member_function
  • 终端 2 运行发布者节点
# source 一下资源
source install/setup.bash
# 运行一个订阅节点
ros2 run examples_rclcpp_minimal_publisher publisher_member_function

在这里插入图片描述

2.4 编写节点

编写节点【RCLCPP】

创建工作空间
[euler@Euler node]$ mkdir -p cpp_ws/src
创建功能包

创建example_cpp功能包,使用ament-cmake作为编译类型,并为其添加rclcpp依赖。

[euler@Euler node]$ cd cpp_ws/src/
[euler@Euler src]$ ros2 pkg create example_cpp --build-type ament_cmake --dependencies rclcpp
[euler@Euler src]$ tree -L 3
.
└── example_cpp├── CMakeLists.txt├── include│   └── example_cpp├── package.xml└── src4 directories, 2 files

(1)pkg create 是创建包的意思
(2)–build-type 用来指定该包的编译类型,一共有三个可选项 ament_python、ament_cmake、cmake
(3)–dependencies 指的是这个功能包的依赖,这里使用 ros2 的 C++ 客户端接口 rclcpp

创建节点

在example_cpp/src下创建一个node_01.cpp文件:

[euler@Euler src]$ tree -L 3
.
└── example_cpp├── CMakeLists.txt├── include│   └── example_cpp├── package.xml└── src└── node_01.cpp4 directories, 3 files
编写代码
  • node_01.cpp 输入代码
#include "rclcpp/rclcpp.hpp"int main(int argc, char **argv)
{/* 初始化rclcpp  */rclcpp::init(argc, argv);/*产生一个node_01的节点*/auto node = std::make_shared<rclcpp::Node>("node_01");// 打印一句自我介绍RCLCPP_INFO(node->get_logger(), "node_01节点已经启动.");/* 运行节点,并检测退出信号 Ctrl+C*/rclcpp::spin(node);/* 停止运行 */rclcpp::shutdown();return 0;
}
  • 修改 CMakeLists.txt
    在CmakeLists.txt最后一行加入下面代码。
# 添加可执行文件
add_executable(node_01 src/node_01.cpp)
# 添加依赖项
ament_target_dependencies(node_01 rclcpp)# 添加安装目标
install(TARGETSnode_01DESTINATION lib/${PROJECT_NAME}
)
编译运行
[euler@Euler cpp_ws]$ ls
src
[euler@Euler cpp_ws]$ colcon build
Starting >>> example_cpp
Finished <<< example_cpp [8.13s]                     Summary: 1 package finished [8.52s]
[euler@Euler cpp_ws]$ tree -L 1
.
├── build
├── install
├── log
└── src4 directories, 0 files
测试
[euler@Euler cpp_ws]$ source install/setup.bash
[euler@Euler cpp_ws]$ ros2 run example_cpp node_01
[INFO] [1722828608.116903186] [node_01]: node_01节点已经启动.

新开窗口查看节点列表:

[euler@Euler ~]$ source /opt/ros/humble/setup.bash 
[euler@Euler ~]$ ros2 node list
/node_01
[euler@Euler ~]$

编写节点【RCLPY】

创建工作空间
[euler@Euler node]$ mkdir -p py_ws/src
创建功能包

创建example_py功能包,使用ament-cmake作为编译类型,并为其添加rclpy依赖。

[euler@Euler node]$ cd cpp_ws/src/
[euler@Euler src]$ ros2 pkg create example_py --build-type ament_python --dependencies rclpy
[euler@Euler src]$ tree -L 3
.
└── example_py├── example_py│   └── __init__.py├── package.xml├── resource│   └── example_py├── setup.cfg├── setup.py└── test├── test_copyright.py├── test_flake8.py└── test_pep257.py4 directories, 8 files

(1)pkg create 是创建包的意思
(2)–build-type 用来指定该包的编译类型,一共有三个可选项 ament_python、ament_cmake、cmake
(3)–dependencies 指的是这个功能包的依赖,这里使用 ros2 的 python 客户端接口 rclpy

创建节点

example_py下创建 node_02.py

[euler@Euler py_ws]$ ls
src
[euler@Euler py_ws]$ touch src/example_py/example_py/node_02.py
编写代码
  • node_02.cpp 输入代码
import rclpy
from rclpy.node import Nodedef main(args=None):"""ros2运行该节点的入口函数编写ROS2节点的一般步骤1. 导入库文件2. 初始化客户端库3. 新建节点对象4. spin循环节点5. 关闭客户端库"""rclpy.init(args=args) # 初始化rclpynode = Node("node_02")  # 新建一个节点node.get_logger().info("大家好,我是node_02.")rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy
  • 修改setup.py
    声明一个ROS2的节点,声明后使用colcon build才能检测到,从而将其添加到install目录下。
    entry_points={'console_scripts': ["node_02 = example_py.node_02:main"],},
)
编译运行
[euler@Euler py_ws]$ ls
src
[euler@Euler py_ws]$ colcon build
Starting >>> example_py
Finished <<< example_py [1.56s]          Summary: 1 package finished [1.92s]
[euler@Euler py_ws]$ tree -L 1
.
├── build
├── install
├── log
└── src4 directories, 0 files
测试
[euler@Euler py_ws]$ source install/setup.bash
[euler@Euler py_ws]$ ros2 run example_py node_02
[INFO] [1722833143.392257307] [node_02]: 大家好,我是node_02.

新开窗口查看节点列表:

[euler@Euler ~]$ source /opt/ros/humble/setup.bash 
[euler@Euler ~]$ ros2 node list
/node_02
[euler@Euler ~]$

2.5 节点编写、编译、运行【面向对象编程 OOP】

面向过程编程思想。缩写:POP
面向对象编程思想。缩写:OOP
函数式思想。缩写:FP

C++ 示例

#include "rclcpp/rclcpp.hpp"/*创建一个类节点,名字叫做Node03,继承自Node.
*/
class Node03 : public rclcpp::Node
{public:// 构造函数,有一个参数为节点名称Node03(std::string name) : Node(name){// 打印一句RCLCPP_INFO(this->get_logger(), "大家好,我是%s.",name.c_str());}private:};int main(int argc, char **argv)
{rclcpp::init(argc, argv);/*产生一个node_03的节点*/auto node = std::make_shared<Node03>("node_03");/* 运行节点,并检测退出信号*/rclcpp::spin(node);rclcpp::shutdown();return 0;
}

Python

#!/usr/bin/env python3
import rclpy
from rclpy.node import Nodeclass Node04(Node):"""创建一个Node04节点,并在初始化时输出一个话"""def __init__(self,name):super().__init__(name)self.get_logger().info("大家好,我是%s!" % name)def main(args=None):rclpy.init(args=args) # 初始化rclpynode = Node04("node_04")  # 新建一个节点rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy

2.6 Colcon 介绍

colcon

colcon是一个命令行工具,用于改进构建,测试和使用多个软件包的工作流程。它自动化了流程,处理了订购并设置了使用软件包的环境。

catkin_make

该工具仅调用 CMake 一次,并使用 CMake 的函数在单个上下文中处理所有包。虽然这是一种有效的方法,因为所有包中的所有目标都可以并行化,但它具有明显的缺点。由于所有函数名称、目标和测试都共享一个命名空间,并且规模更大,这很容易导致冲突。

ament_tools

ament_tools 由用于构建 ROS 2 包的独立 Python 3 包提供。它是为引导ROS 2项目而开发的,因此仅针对Python 3,并且可以在Linux,MacOS和Windows上运行。

构建指令

–packages-select ,仅生成单个包(或选定的包)。
–packages-up-to,构建选定的包,包括其依赖项。
–packages-above,整个工作区,然后对其中一个包进行了更改。此指令将重构此包以及(递归地)依赖于此包的所有包。

指定构建后安装的目录

可以通过 --build-base参数和–install-base,指定构建目录和安装目录。

合并构建目录

–merge-install,使用 作为所有软件包的安装前缀,而不是安装基中的软件包特定子目录。–install-base
如果没有此选项,每个包都将提供自己的环境变量路径,从而导致非常长的环境变量值。
使用此选项时,添加到环境变量的大多数路径将相同,从而导致环境变量值更短。

符号链接安装

启用–symlink-install后将不会把文拷贝到install目录,而是通过创建符号链接的方式。

错误时继续安装

启用–continue-on-error,当发生错误的时候继续进行编译。

CMake参数

–cmake-args,将任意参数传递给CMake。与其他选项匹配的参数必须以空格为前缀。

控制构建线程

  • –executor EXECUTOR,用于处理所有作业的执行程序。默认值是根据所有可用执行程序扩展的优先级选择的。要查看完整列表,请调用 colcon extensions colcon_core.executor --verbose。

    • sequential [colcon-core]
      一次处理一个包。
    • parallel [colcon-parallel-executor]
      处理多个作业平行.
  • –parallel-workers NUMBER

    • 要并行处理的最大作业数。默认值为 os.cpu_count() 给出的逻辑 CPU 内核数。

开启构建日志

使用–log-level可以设置日志级别,比如–log-level info。

2.7 ROS2节点发现与多机通信

在没有 ROSMASTER 的情况下,ROS2 如何实现互相发现。

ROS 2用于通讯的默认中间件是DDS。在DDS中,不同逻辑网络共享物理网络的主要机制称为域(Domain) ID。同一域上的ROS 2节点可以自由地相互发现并发送消息,而不同域上的ROS 2节点则不能。所有ROS 2节点默认使用域ID为0。

选择域ID (短版本)

选择一个介于0和101之间的安全的域ID (包括0和101)。

选择域ID (长版本)

DDS使用域ID计算将用于发现和通讯的UDP端口。在网络中,UDP端口是 无符号16位整型 。因此可以分配的最大端口号是65535。

  • Linux
    默认情况下,linux内核使用端口32768-60999作为临时端口。这意味着域ID 0-101 和 215-232 可以安全使用,而不会与临时端口发生冲突。临时端口范围可在Linux中通过在 /proc/sys/net/ipv4/ip_local_port_range 中设置自定义值进行配置。如果使用自定义临时端口范围,则可能需要相应地调整上述数字。

  • Windows
    默认情况下,Windows上的临时端口范围为49152-65535。这意味着域ID 0-166可以安全使用,不会与临时端口发生冲突。临时的端口范围可通过 使用netsh 在窗口中配置。如果使用自定义临时端口范围,则可能需要相应地调整上述数字。

对于计算机上运行的每个ROS 2进程,将创建一个DDS “participant” 。由于每个DDS参与者占用计算机上的两个端口,因此在一台计算机上运行120个以上的 ROS 2 进程可能会溢出到其他域ID或临时端口。

2.8 通信–话题与服务

TCP/UDP

ping 192.168.0.1# 终端 1: 监听端口
nc -l 1234# 终端 2: 发送数据
echo "Hello, TCP!" | nc 127.0.0.1 1234

基于共享内存的进程间通信(IPC)方式

在Linux命令行中,可以使用ipcs和ipcrm命令来管理共享内存段。

通过ipcs命令查看当前系统中的共享内存段:

ipcs -m

使用ipcrm命令删除不再需要的共享内存段:

ipcrm -m <shmid>

ZeroMQ

FastDDS 官网强调自己比 ZeroMQ 性能要好。
ZeroMQ 非常的轻量,也就是小巧,占用资源少,Zero Message Queue,零消息队列。

PyZmq

https://pyzmq.readthedocs.io/en/latest/

话题

同一个话题,所有的发布者和接收者必须使用相同消息接口。

# 终端 1
[euler@Euler cpp_ws]$ source install/setup.bash
[euler@Euler cpp_ws]$ ros2 run example_cpp node_01# 终端 2
[euler@Euler py_ws]$ source install/setup.bash
[euler@Euler py_ws]$ ros2 run example_py node_02# 终端 3
rqt_graph

openEuler 没有安装 rqt,安装后再补充。

命令
# 返回系统中当前活动的所有主题的列表
ros2 topic list# 增加消息类型
ros2 topic list -t# 打印实时话题内容
ros2 topic echo
eg: ros2 topic echo /chatter# 查看主题信息
ros2 topic info
eg: ros2 topic info  /chatter# 查看消息类型
ros2 interface show
eg: ros2 interface show std_msgs/msg/String# 手动发布命令
ros2 topic pub arg
eg: ros2 topic pub /chatter std_msgs/msg/String 'data: "123"'
实现 RCLCPP
实现 RCLPY

服务

实现 RCLCPP
实现 RCLPY

2.9 通信–参数

3 机器人学

4 建模仿真

5 Navi2 导航

6 Moveit2 机械臂

参考

1、ROS 2 Documentation humble
2、官方–ROS2 Humble 教程
3、官方–ROS2 Humble 控制
4、ROS2
5、ROS2 Humble学习笔记
6、ROS2-humble学习
7、ROS2 学习(一)ROS2 简介与基本使用
8、小鱼–动手学ROS2
9、openEuler22.03SP3中的cmake3.22.0读取openssl版本号为乱码,导致使用cmakecache的其他程序出错
10、官方 colcon – Installation
11、openEuler-22.03-LTS–嵌入式ROS运行时支持
12、生肖Robot–电鼠
13、src-openEuler/ament_cmake
14、ament_cmake_python user documentation
15、ROS2 教程
16、ROS2探索总结-4.ament编译系统
17、机器人操作系统入门讲义
18、Overview and usage of RQt

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode | 441 | 排列硬币 | 二分查找

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天分享的是LeetCode中一道标签为简单的算法题&#xff0c;本质是一道数学题 文章目录 1.题目描述2.题解2.1 公式解法2.2 暴力解法2.3 二分查找 LeetCode链接&#…

【51单片机仿真】基于51单片机设计的钟表定时闹钟系统仿真源码设计文档演示视频——完整资料下载

演示视频 设计内容 &#xff08;1&#xff09;使用 DS1302 结合字符型 LCD12864 显示器设计一个简易的定时闹钟 LCD 时钟。程序执行后 LCD 显示“00&#xff1a;00&#xff1a;00” &#xff08;2&#xff09;K1—设置现在的时间&#xff0c;年闪烁&#xff0c;再按 K1 键月闪…

15.75.【C语言】表达式求值

目录 一.整型提升 1.定义 2. 一.整型提升 1.定义 C语言中整型算术运算总是至少以缺省&#xff08;默认&#xff09;整型类型的精度来进行的。为了获得这个精度&#xff0c;表达式中的字符和短整型操作数在使用之前被转换为普通整型&#xff0c;这种转换称为整型提升 2.整型提…

njs、nginx JavaScript、在nginx上写JavaScript、nginx支持js

njs、nginx JavaScript、在nginx上写JavaScript、nginx支持js 现在是 2024-08-05 &#xff0c;在一个月前&#xff0c;我逛nginx官网&#xff0c;还没有这个模块的介绍。看njs官网&#xff0c;在四年前已经创建这个项目。不知道是不是近期才把这个项目纳入。以前不知道这模块&…

C# 构建观测者模式(或者为订阅者模型)

前言&#xff1a; 观测者模型的基本理念&#xff0c;就是&#xff0c;我有一个公共的事件&#xff0c;定义好他的事件的触发、数据接口。然后&#xff0c;通过增加订阅者&#xff08;实例&#xff09;来订阅这个事件的&#xff0c;或者说观察这个事件。如果事件发生&#xff0…

未授权访问漏洞系列详解⑥!

JBoss未授权访问漏洞 JBoss是一个基于J2EE的开放源代码应用服务器&#xff0c;代码遵循LGPL许可&#xff0c;可以在任何商业应用中免费使用;JBoss也是一个管理EJB的容器和服务器&#xff0c;支持EJB1.1、EJB 2.0和EJB3规范。,默认情况下访问 http://ip:8080/jmx-console 就可以…

【Java数据结构】---初始数据结构

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 前言 从今天开始我们就要学习Java…

Altium designer学习笔记03 -原理图绘制

原理图绘制 1. 原理图页大小设置2.原理图格点的设置3. 原理图模板的应用4. 元件的放置5.元件属性的编辑6.元件的选择、移动、旋转、镜像6.1 元件的选择6.2 元件的移动6.3 元件的旋转6.3 元件的镜像 7.元件的复制/剪切/粘贴8.元件的排列与对齐9.绘制导线的导线属性设置10.放置网…

实时数仓分层架构详解

首先&#xff0c;我们从数据仓库说起。 数据仓库的概念可以追溯到20世纪80年代&#xff0c;当时IBM的研究人员提出了商业数据仓库的概念。数据仓库概念的提出&#xff0c;是为了解决和数据流相关的各种问题&#xff0c;特别是多重数据复制带来的高成本问题。 数据仓库之父Bill …

简单反射型XSS的复现

xss反射型攻击&#xff1a; 1.最简单的漏洞复现&#xff1a; 这里我们有一个最简单的网页&#xff1a;由于地址不存在&#xff0c;所以图片加载不出来。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta…

skynet 连接redis

文章目录 概述main.luaagent.luaredis.lua 小结 概述 之前写过skynet 入门篇&#xff0c;还有skynet实操篇&#xff1b;这2篇&#xff0c;主要写了skynet如何使用&#xff0c;还有些skynet的调用流程之类。 其实&#xff0c;看过skynet的demo之后&#xff0c;发现skynet中没有…

Simulink模型开发中的一些自动化方法

随着Simulink模型的产品化开发进程&#xff0c;许多模型开发人员会关心模型的建模自动化问题。比如如何对模型中的元素进行批量查找和修改&#xff1b;如何构建自己的建模规则对模型进行检查&#xff1b;如何实现测试自动化等。在这些使用场景中我们都需要了解一些Simulink函数…

谈谈冯诺依曼体系

我们都知道冯诺依曼体系这张图最为代表性&#xff0c;而接下来我们就来浅谈一下各部分之间的作用~ 输入设备&#xff1a;键盘&#xff0c;磁盘&#xff0c;网卡&#xff0c;话筒等等 输出设备&#xff1a;磁盘&#xff0c;网卡&#xff0c;声卡&#xff0c;显示屏等等 这些硬件…

1.1、centos stream 9安装Kubernetes v1.30集群 环境说明

最近正在学习kubernetes&#xff0c;买了一套《Kubernetes权威指南 从Docker到Kubernetes实践全接触(第六版)》这本书讲得很好&#xff0c;上下两册&#xff0c;书中k8s的版本是V1.29&#xff0c;目前官网最新版本是v1.30。强烈建议大家买一套看看。 Kubernetes官网地址&#x…

sql注入——二次注入

二次注入 简介工具环境具体实施 简介 二次注入是一种较为隐蔽的 SQL 注入攻击方式。它并非直接在输入时进行攻击&#xff0c;而是先将恶意数据存储到数据库中&#xff0c;这些数据看似正常。随后&#xff0c;应用程序在后续的操作中&#xff0c;再次使用或处理这些之前存储的恶…

消息队列:Kafka吞吐量为什么比RocketMQ大

根据资料显示RocketMQ每秒能处理10W量级数据&#xff0c;而Kafka能处理17W量级数据。 这两者差别主要再使用的零拷贝技术不一样。 再什么情况下零拷贝技术诞生了 为了防止消息队列中的消息因为各种意外情况丢失&#xff0c;要对消息进行持久化处理&#xff0c;将其存储在磁盘…

NLP——文本预处理

本文思维导图 文本预处理及其作用 文本语料在输送给模型前一般需要一系列的预处理工作, 才能符合模型输入的要求, 如: 将文本转化成模型需要的张量, 规范张量的尺寸等, 而且科学的文本预处理环节还将有效指导模型超参数的选择, 提升模型的评估指标. 一、文本处理的基本方法 1…

C++ | Leetcode C++题解之第326题3的幂

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isPowerOfThree(int n) {return n > 0 && 1162261467 % n 0;} };

【TS】declare 全局声明方式

declare关键字 declare是描述TS文件之外信息的一种机制&#xff0c;它的作用是告诉TS某个类型或变量已经存在&#xff0c;我们可以使用它声明全局变量、函数、类、接口、类型别名、类的属性或方法以及后面会介绍的模块与命名空间。 declare关键字用来告诉编译器&#xff0c;某…

工业控制常用的EtherNet/IP、OPC UA协议的标签数据转发到另外的PLC寄存器地址

在工业自动化领域&#xff0c;越来越多的碰到标签方式通讯的设备&#xff0c;常用有CIP(基于EtherNet/IP) 的协议、OPCUA协议等&#xff0c;CIP协议主要是罗克韦尔/AB的PLC、欧姆龙NX/NJ系列的PLC等&#xff0c;OPCUA协议常见于工业机器人、智能焊接设备等。在不具备标签协议接…