PC端开发环境搭建
WSL环境搭建
https://www.guyuehome.com/46574
In Windows 11 builds that support wslg:
1. Open up powershell and enter wsl --install
ROS2系统安装
方法一
• 设置编码
Bash $ sudo apt update && sudo apt install locales $ sudo locale-gen en_US en_US.UTF-8 $ sudo update-locale LC_ALL=en_US.UTF-8.UTF-8 $ export.UTF-8 |
• 添加源
Bash $ sudo apt update && sudo apt install curl gnupg lsb-release $ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list /dev/null |
• 如遇报错“Failed to connect to raw.githubusercontent.com”,可参考古月居 - ROS机器人知识分享社区
• 安装ROS2
Bash $ sudo apt update $ sudo apt upgrade $ sudo apt install ros-humble-desktop sudo apt install python3-colcon-common-extensions |
• 设置环境变量
Bash $ source /opt/ros/humble/setup.bash $ echo " source /opt/ros/humble/setup.bash" ~/.bashrc |
方法二
Shell wget http://fishros.com/install -O fishros && . fishros |
基础演示案例
案例一:ROS2安装完毕后,运行其官方例程:小乌龟
Bash ros2 run turtlesim turtlesim_node |
案例二:打印一段文字输出在终端
Bash ros2 pkg create demo_print_py --build-type ament_python --dependencies rclpy --node-name demo_print_py |
Python import rclpy def main(): # 初始化 ROS2 rclpy.init() # 创建节点 node = rclpy.create_node("helloworld_py_node") # 输出文本 node.get_logger().info("hello world!") # 释放资源 rclpy.shutdown() if __name__ == '__main__': main() |
ROS 体系框架
ROS2可以划分为三层:
操作系统层(OSLayer)
ROS虽然称之为机器人操作系统,但实质只是构建机器人应用程序的软件开发工具包, ROS必须依赖于传统意义的操作系统,目前ROS2可以运行在Linux、Windows、Mac或RTOS 上。
中间层(Middleware Layer)
主要由数据分发服务DDS与ROS2封装的关于机器人开发的中间件组成。DDS是一种去中心化的 数据通讯方式,ROS2还引入了服务质量管理 (QualityofService)机制,借助该机制可以保证 在某些较差网络环境下也可以具备良好的通讯效果。ROS2中间件则主要由客户端库、DDS抽象层 与进程内通讯API构成。
应用层(Application Layer)
是指开发者构建的应用程序,在应用程序中是以功能包为核心的,在功能包中可以包含源码、数据 定义、接口等内容。对于一般开发者而言,工作内容主要集中在应用层,开发者一般通过实现具有某一特定功能的功能 包来构建机器人应用程序。对应的我们所介绍的ROS2文件系统主要是指在硬盘上以功能包为核心 的目录与文件的组织形式。
应用层(开发者)视角下文件系统
Bash WorkSpace---自定义的工作空间 |---build:存储中间文件的目录,该目录下会为每一个功能包创建一个单独子目录。 |---install:安装目录,该目录下会为每一个功能包创建一个单独子目录。 |---log:日志目录,用于存储日志文件。 |---src:用于存储功能包源码的目录。 |-- C++功能包 |-- package.xml:包信息,比如:包名、版本、作者、依赖项。 |-- CMakeLists.txt:配置编译规则,比如源文件、依赖项、目标文件 |-- src:C++源文件目录。 |-- include:头文件目录。 |-- msg:消息接口文件目录。 |-- srv:服务接口文件目录。 |-- action:动作接口文件目录。 |-- Python功能包 |-- package.xml:包信息,比如:包名、版本、作者、依赖项。 |-- setup.py:与C++功能包的CMakeLists.txt类似。 |-- setup.cfg:功能包基本配置文件。 |-- resource:资源目录。 |-- test:存储测试相关文件。 |--功能包同名目录:Python源文件目录。 |
另外,无论是Python功能包还是C++功能包,都可以自定义一些配置文件相关的目录。
Bash C++或Python功能包 |-- launch:存储launch文件。 |-- rviz:存储rviz2配置相关文件。 |-- urdf:存储机器人建模文件。 |-- params:存储参数文件。 |-- world:存储仿真环境相关文件。 |-- map:存储导航所需地图文件。 |-- ...... |
源文件说明
https://gitee.com/guyuehome/ros2_21_tutorials
SRC下源代码
C++实例化Node示例如下:
C++ /*** @作者: 古月居(www.guyuehome.com) @说明: ROS2节点示例-发布“Hello World”日志信息, 使用面向对象的实现方式 ***/
#include |
继承方式可以在一个进程内组织多个节点,这对于提高节点间的通信效率是很有帮助的.
配置文件
在ROS2功能包中,经常需要开发者编辑一些配置文件以设置功能包的构建信息,功能包类型不同, 所需修改的配置文件也有所不同。C++功能包的构建信息主要包含在package.xml与 CMakeLists.txt中,Python功能包的构建信息则主要包含在package.xml和setup.py中,接下来 我们就简单了解一下这些配置文件。
package.xml
不管是何种类型的功能包,package.xml的格式都是类似的,在该文件中包含了包名、版本、作者、 依赖项的信息,package.xml可以为colcon构建工具确定功能包的编译顺序。
CMakeLists.txt
C++功能包中需要配置CMakeLists.txt 文件,该文件描述了如何构建C++功能包
Bash cmake_minimum_required(VERSION 3.8) project(demo_print_cpp)
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)
add_executable(demo_print_cpp src/demo_print_cpp.cpp) target_include_directories(demo_print_cpp PUBLIC $ |
setup.py
Python功能包中需要配置setup.py文件
Python from setuptools import find_packages, setup package_name = 'demo_print_py' setup( name=package_name, #包名 version='0.0.0', packages=find_packages(exclude=['test']), data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], zip_safe=True, maintainer='lql', maintainer_email='1245953651@qq.com', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ #映射源文件与可执行文件 'demo_print_py = demo_print_py.demo_print_py:main' ], }, ) |
操作指令
ROS2的文件系统核心是功能包,我们可以通过编译指令colcon和ROS2内置的工具指令ros2来 实现功能包的创建、编译、查找与执行等相关操作。
创建功能包
Bash ros2 pkg create 包名--build-type 构建类型--dependencies 依赖列表--node-name 可执行程序名称 |
编译功能包
Bash colcon build colcon build --packages-select xxx |
执行
核心模块
通信模块
话题(异步通信)
节点A要将获取的图像数据传输给节点B,有了数据,节点B才能做这样可视化的渲染。
此时从节点A到节点B传递图像数据的方式,在ROS中,我们就称之为话题,它作为一个桥梁,实现了节点之间某一个方向上的数据传输。
案例演示一:文字接发
Bash ros2 run learning_topic topic_helloworld_pub |
Bash ros2 run learning_topic topic_helloworld_sub |
案例演示二:自定义msg
Bash ros2 run learning_topic interface_object_sub ros2 run learning_topic interface_object_pub |
服务(同步通信)
假设不需要话题模式般高的频率一直订阅物体的位置,而是更希望在需要这个数据的时候,发一个查询的请求,然后尽快得到此时目标的最新位置;
这样的通信模型和话题单向传输有所不同,变成了发送一个请求,反馈一个应答的形式,好像是你问我答一样,这种通信机制在ROS中成为服务,Service。
案例一:加法求解器
Bash ros2 run learning_service service_adder_server ros2 run learning_service service_adder_client 2 3 |
案例二:自定义srv
...
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME} "srv/GetObjectPosition.srv" )
...
...
... |
动作(自带反馈,同步通信)
举个例子,比如我们想让机器人转个圈,这肯定不是一下就可以完成的,机器人得一点一点旋转,直到360度才能结束,假设机器人并不在我们眼前,发出指令后,我们根本不知道机器人到底有没有开始转圈,转到哪里了?
所以,现在我们需要的是一个反馈,比如每隔1s,告诉我们当前转到多少度了,10度、20度、30度,一段时间之后,到了360度,再发送一个信息,表示动作执行完成。
这样一个需要执行一段时间的行为,使用动作的通信机制就更为合适,就像装了一个进度条,我们可以随时把控进度,如果运动过程当中,我们还可以随时发送一个取消运动的命令。
动作通信适用于长时间运行的任务。就结构而言动作通信由目标、反馈和结果三部分组成;就功能而言动作通信类似 于服务通信,动作客户端可以发送请求到动作服务端,并接收动作服务端响应的最终结果,不过动作通信可以在请求 响应过程中获取连续反馈,并且也可以向动作服务端发送任务取消请求;就底层实现而言动作通信是建立在话题通信 和服务通信之上的,目标发送实现是对服务通信的封装,结果的获取也是对服务通信的封装,而连续反馈则是对话题 通信的封装。
由服务和话题合成
动作的三个通信模块,竟然有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应答,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。
没错,动作是一种应用层的通信机制,其底层就是基于话题和服务来实现的。
案例一:数据反馈
Bash ros2 run learning_action action_move_server ros2 run learning_action action_move_client |
接口定义
例程使用的动作并不是ROS中的标准定义,我们通过MoveCircle.action进行自定义:
learning_interface/action/MoveCircle.action
bool enable 定义动作的目标,表示动作开始的指令
bool finish 定义动作的结果,表示是否成功执行
int32 state 定义动作的反馈,表示当前执行到的位置
包含三个部分:
• 第一块是动作的目标,enable为true时,表示开始运动;
• 第二块是动作的执行结果,finish为true,表示动作执行完成;
• 第三块是动作的周期反馈,表示当前机器人旋转到的角度。
完成定义后,还需要在功能包的CMakeLists.txt中配置编译选项,让编译器在编译过程中,根据接口定义,自动生成不同语言的代码:
Plaintext ... find_package(rosidl_default_generators REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "action/MoveCircle.action" ) ... |
功能包算法
https://gitee.com/guyuehome/originbot_desktop
Bash . /usr/share/gazebo/setup.sh ros2 launch originbot_gazebo originbot_navigation_gazebo.launch.py |
Bash ros2 launch originbot_navigation cartographer_gazebo.launch.py |
分布式开发
ROS2 本身是一个分布式通信框架,可以很方便的实现不同设备之间的通信,ROS2所基于的中间件是DDS,当处 于同一网络中时,通过DDS的域ID机制(ROS_DOMAIN_ID)可以实现分布式通信,大致流程是:在启动节点之前, 猛狮集训营 可以设置域ID的值,不同节点如果域ID相同,那么可以自由发现并通信,反之,如果域ID值不同,则不能实现。 默认情况下,所有节点启动时所使用的域ID为0,换言之,只要保证在同一网络,你不需要做任何配置,不同ROS2 设备上的不同节点即可实现分布式通信。
Bash export ROS_DOMAIN_ID=6 |