ROS2教程 - 3 HelloWorld

更好的阅读体验:https://www.foooor.com

3 HelloWorld

下面从 HelloWorld 开始,讲解 ROS2 的开发。

ROS 开发主要使用 C++ 或 Python 实现,如果要实现的功能,对性能有要求,可以使用 C++ 实现,如果对性能没有特别高的要求,可以使用 Python 实现,Python 的开发效率要高一些。

ROS1核心是C++03,而ROS2广泛使用C++11;ROS1 的Python使用Python2,ROS2 使用的Python版本至少是3.5及以上。


在开始之前,先介绍几个概念:工作空间功能包节点

  • 功能包

功能包类似于模块或子项目,它们可以被独立开发和复用,每个功能包通常有一个明确的功能目标,比如实现某种算法、驱动硬件等。

我们在开发机器人的时候,机器人的摄像头、雷达等硬件,厂家会提供 ROS 开发的功能包,我们只需要在我们的项目中集成厂家提供的 ROS 功能包,就能获取到硬件传感器的数据。同样,在开发机器人 SLAM 建图导航功能的时候,可以将建图封装在一个功能包中,导航封装在一个功能包中,这样也便于管理、复用和维护。

  • 节点

节点是 ROS 中的执行单元,是一个正在运行的 ROS 程序。每个节点都独立运行,可以与其他节点通过 ROS 通信机制进行数据交换。

节点的职责是完成特定的功能,比如控制机器人、处理传感器数据、发布指令等,节点是在功能包中的,一个功能包中可以存在多个节点。

  • 工作空间

工作空间是 ROS 项目开发的顶层目录,可以理解为一个项目,用来存放和管理多个功能包。它包含了所有与项目相关的代码、配置和依赖项。

三者关系:

  • 工作空间是一个容器,它包含多个功能包
  • 功能包是功能代码的逻辑单元,里面可能包含多个节点
  • 节点是实际执行功能的程序,通过 ROS 的通信机制与其他节点协作完成系统功能。

所以在 ROS 中实现功能是通过节点来实现的,节点是在功能包中,一个功能包可以提供多个功能,功能包是在工作空间中进行管理的。

类似于 项目 -> 子模块 -> 功能 ,所以在 ROS 中实现功能,从0开始创建,需要 创建工作空间 -> 创建功能包 -> 创建节点

3.1 创建工作空间

ROS2 中,工作空间的目录结构:

ros2_ws/          # 工作空间根目录,自定义名称
├── src/          # 源代码目录,存放所有的功能包
├── build/        # 编译目录,存放构建文件(colcon build 时生成)
├── install/      # 安装目录,存放可执行文件和已编译的依赖项(colcon build 时生成)
└── log/          # 日志文件目录,存放构建和运行时的日志信息

在进行 ROS 开发,首先需要创建工作空间,然后在工作空间的 src/ 目录下创建功能包。开发完成通过 colcon build 命令将功能包编译到 install/ 目录中,然后运行。


下面来创建工作空间。

可以使用界面,在你放置的位置创建工作空间的文件夹,或者使用终端命令来创建也是可以的,工作空间的名称是自定义的。

例如我在主目录(~表示主目录)创建一个 ros2_ws 的工作空间:

mkdir ~/ros2_ws    # 创建文件夹
cd ros2_ws    # 进入到 ros2_ws 目录中
mkdir src    # 在 ros2_ws 目录下创建 src 目录

这样工作空间就创建好了,其实就是创建了两个目录。

创建完成,可以进入到工作空间下进行构建:

cd mkdir ~/ros2_ws
colcon build

构建完成,工作空间下就会存在 src、install、build、log 四个目录了。

3.2 创建功能包

功能包是在工作空间的 src 目录下创建的。ROS2 中功能包需要指定使用的语言,创建功能包使用如下命令:

# 首先进入到工作空间的 src 目录下
cd ~/dev_ws/src# 创建C++功能包
ros2 pkg create --build-type ament_cmake hello_pkg_cpp# 或者,创建Python功能包
ros2 pkg create --build-type ament_python hello_pkg_python
  • ros2 pkg create :ROS2 中创建功能包的命令
  • --build-type :表示新创建的功能包是C++还是Python的,如果使用C++或者C,参数值为ament_cmake,如果使用Python,值为ament_python;
  • 命令后面的 hello_pkg_cpphello_pkg_python 表示的是功能包的名称。
  • 功能包的名字不要包含 -,可以使用 _

这样就会在工作空间下的 src 目录下创建功能包,每个功能包下都会有一个 package.xml 文件,里面有功能包的描述和功能包的依赖信息等。

3.3 Python实现节点

下面就来实现一个简单的节点,功能很简单,就是循环打印 Hello World! ,主要是看如何实现一个节点。

在上面已经创建了两个功能包,hello_pkg_cpphello_pkg_python

下面在 hello_pkg_python 功能包下,使用 Python 实现一个节点。

1 创建节点文件

hello_pkg_python/hello_pkg_python 目录下创建 python 文件,名称自定义。

例如我这里叫 hello_world.py ,内容如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-import rclpy        # 导入 rclpy 库,这是 ROS2 的 Python 接口
from rclpy.node import Node     # 导入 Node 类,这是 ROS2 的节点类
import time     # 导入 time 模块,用于实现线程的休眠def main(args=None):        # main 函数是 ROS2 节点的入口函数,参数 args 通常保留为 None,表示不需要额外的启动参数# 1.创建节点rclpy.init(args=args)       # 初始化 ROS2 Python 客户端库,必须在创建节点之前调用node = Node("hello_node")     # 创建一个名为 "hello_node" 的节点# 2.实现功能while rclpy.ok():		# 当 ROS2 系统处于正常运行状态时,循环会持续执行node.get_logger().info("Hello World!")  # ROS2中打印日志time.sleep(1)  # 线程休眠 1 秒,防止打印过于频繁# 3.销毁节点node.destroy_node()     # 销毁节点,释放资源rclpy.shutdown()        # 关闭 ROS2 客户端库

实现节点主要分为三个步骤:

  1. 创建节点
  2. 实现功能,循环打印 Hello World!
  3. 销毁节点

2 配置文件可执行权限

需要授权 python 文件可执行权限:

# 进入到python文件目录
cd src/hello_pkg_python/hello_pkg_python
chmod +x hello_world.py

3 配置节点

在功能包下的 setup.py 中配置节点,在 entry_points 中配置:

entry_points={'console_scripts': ['hello_node = hello_pkg_python.hello_world:main',],
},

上面就是配置节点运行的是哪个 Python 文件的哪个方法。前面的 hello_node 是自定义的,建议和 Node("hello_node") 对应。

一个功能包下是可以创建多个节点的,创建多个 Python 文件即可,进行同样的配置。

4 构建项目

现在代码已经编写完成了,需要构建项目。

在工作空间下执行如下命令:

colcon build

构建完成,会在 install 目录下生成文件。

也可以使用如下命令,单独编译一个功能包:

colcon build --packages-select hello_pkg_python

5 运行节点

首先执行 source 命令,在工作空间下执行:

source install/local_setup.sh

执行的作用主要是为了让 ros2 命令可以找到我们的功能包。

每次都执行上面的命令有些麻烦,我们可以将命令添加到环境变量中,这样每次打开终端就能 source 一下,就不用每次都运行 source 了。

source /opt/ros/humble/setup.bash    # 安装ros2的时候已经添加了,指定ROS2的路径
source ~/ros2_ws/install/local_setup.sh    # 指定工作空间的路径,让ROS可以找到我们的功能包

然后使用如下命令启动节点:

ros2 run hello_pkg_python hello_node
  • ros2 run :这个是 ros2 中运行节点的命令;
  • hello_pkg_python :是功能包的名字;
  • hello_node :是节点的名称。

执行效果如下,每秒打印 Hello World!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


在 ROS 1 中,roscore是一个非常关键的组件。它主要用于提供名称服务(ROS Master)、参数服务器等功能。节点在启动时需要向roscore中的 ROS Master 进行注册,以便让其他节点能够发现它。所以在 ROS1 中启动节点前,需要先运行 roscore

但是ROS2 采用了一种分布式的发现机制,不再依赖于像roscore这样的中央节点管理器。它使用了 DDS(Data - Distribution Service)中间件。DDS 是一种以数据为中心的发布 - 订阅通信标准,能够自动发现网络中的节点和话题。所以在 ROS2 中启动节点不需要roscore

3.4 C++实现节点

使用 C++ 实现节点也是类似的。

1 创建节点文件

hello_pkg_cpp/src 目录下创建 C++ 文件,名称自定义。

例如我这里叫 hello_world.cpp ,内容如下:

#include <rclcpp/rclcpp.hpp>  // 导入 ROS2 C++ 客户端库
#include <chrono>             // 导入时间处理库
#include <thread>             // 导入线程库int main(int argc, char **argv) {// 1.创建和初始化操作rclcpp::init(argc, argv);  // 初始化 ROS2 客户端库auto node = rclcpp::Node::make_shared("hello_node");  // 创建一个名为 "hello_node" 的节点// 2.实现功能while (rclcpp::ok()) {  // 当 ROS2 系统正常运行时RCLCPP_INFO(node->get_logger(), "Hello World!");  // 打印日志信息 "Hello World!"std::this_thread::sleep_for(std::chrono::seconds(1));  // 线程休眠 1 秒,防止打印过于频繁}// 3.关闭节点rclcpp::shutdown();  // 关闭 ROS2 客户端库return 0;  // 返回 0,表示程序正常结束
}

2 配置CMakeLists.txt

在功能包下的 CMakeLists.txt 中,添加 C++ 编译配置,可以添加在 find_package(ament_cmake REQUIRED) 下面:

# 找到此包需要的其他包
find_package(rclcpp REQUIRED)# 添加可执行文件
add_executable(hello_node src/hello_world.cpp)# 目标链接库
ament_target_dependencies(hello_node rclcpp)# 安装可执行文件
install(TARGETShello_nodeDESTINATION lib/${PROJECT_NAME}
)

节点的名称是 hello_node ,和 C++ 代码中对应。

一个功能包下是可以创建多个节点的,创建多个 C++ 文件即可,如果创建多个节点,那么在 CMakeLists.txt 中配置如下:

# 找到此包需要的其他包
find_package(rclcpp REQUIRED)# 添加可执行文件,指向 hello_world.cpp
add_executable(hello_node src/hello_world.cpp)
ament_target_dependencies(hello_node rclcpp)# 添加可执行文件,指向 print_word.cpp
add_executable(print_node src/print_word.cpp)
ament_target_dependencies(print_node rclcpp)# 安装可执行文件
install(TARGETShello_nodeprint_nodeDESTINATION lib/${PROJECT_NAME}
)

上面配置了 hello_nodeprint_node 两个节点。

3 构建项目

现在代码已经编写完成了,需要构建项目。

在工作空间下执行如下命令:

colcon build

构建完成,会在 install 目录下生成文件。

也可以使用如下命令,单独编译一个功能包:

colcon build --packages-select hello_pkg_cpp

4 运行节点

首先执行 source 命令,在工作空间下执行:

source install/local_setup.sh

如果 ROS 还找不到你的功能包和节点,你就 source 一下,如果找得到就不用了。

然后使用如下命令启动节点:

ros2 run hello_pkg_cpp hello_node
  • ros2 run :这个是 ros2 中运行节点的命令;
  • hello_pkg_cpp :是功能包的名字;
  • hello_node :是节点的名称。

执行效果也是每秒打印 Hello World!

3.5 节点代码优化

上面在使用 Python 实现节点的时候,使用的是面向过程的编码方式,在实际的开发中,现在更推荐使用面向对象的编码方式。

1 优化Python代码

我们可以创建一个类继承 Node 类,然后类中实现我们的功能。

修改上面的 Python 代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-import rclpy        # ROS2 Python接口库
from rclpy.node import Node     # ROS2节点类
import time     # 线程用来休眠# 创建节点类,实现节点,具体的功能在类中实现
class HelloWorldNode(Node):def __init__(self):super().__init__('hello_node')def print_hello_world(self):while rclpy.ok():self.get_logger().info("Hello World!")  # ROS2打印日志time.sleep(1)  # 休眠1秒def main(args=None):# 初始化和创建节点rclpy.init(args=args)node = HelloWorldNode()# 调用打印node.print_hello_world()# 销毁node.destroy_node()rclpy.shutdown()

上面的代码使用面向对象的方式,将节点实现的具体功能放到类中。

2 优化C++代码

同样,也是用面向对象的编码方式优化 C++ 代码:

#include <rclcpp/rclcpp.hpp>      // 引入 ROS2 C++ 接口库
#include <chrono>                 // 引入 chrono 库,用于时间处理
#include <thread>                 // 引入 thread 库,用于休眠线程// 定义一个 HelloWorldNode 类,继承自 rclcpp::Node 类
class HelloWorldNode : public rclcpp::Node
{
public:// 构造函数,初始化节点名称为 "hello_node"HelloWorldNode() : Node("hello_node") {}// 定义一个函数,用于每秒打印一次 "Hello World!"void print_hello_world(){// 使用 while 循环,检查节点是否正常运行while (rclcpp::ok()) {// 打印 "Hello World!" 消息到终端,带有日志信息RCLCPP_INFO(this->get_logger(), "Hello World!");// 休眠 1 秒钟,类似于 Python 的 time.sleep(1)std::this_thread::sleep_for(std::chrono::seconds(1));}}
};// main 函数是程序的入口点
int main(int argc, char * argv[])
{// 初始化 ROS2,必须在创建节点之前调用rclcpp::init(argc, argv);// 创建一个共享指针,指向 HelloWorldNode 节点对象auto node = std::make_shared<HelloWorldNode>();// 调用节点的 print_hello_world 函数,开始打印 "Hello World!"node->print_hello_world(); // 当循环结束时,关闭 ROS2 系统,释放资源rclcpp::shutdown(); // 返回 0,表示程序成功退出return 0;
}

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

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

相关文章

洛谷 B3626 跳跃机器人 C语言 记忆化搜索

题目&#xff1a; https://www.luogu.com.cn/problem/B3626 题目描述 地上有一排格子&#xff0c;共 n 个位置。机器猫站在第一个格子上&#xff0c;需要取第 n 个格子里的东西。 机器猫当然不愿意自己跑过去&#xff0c;所以机器猫从口袋里掏出了一个机器人&#xff01;这…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…

⭐️ GitHub Star 数量前十的工作流项目

文章开始前&#xff0c;我们先做个小调查&#xff1a;在日常工作中&#xff0c;你会使用自动化工作流工具吗&#xff1f;&#x1f64b; 事实上&#xff0c;工作流工具已经变成了提升效率的关键。其实在此之前我们已经写过一篇博客&#xff0c;跟大家分享五个好用的工作流工具。…

Tree搜索二叉树、map和set_数据结构

数据结构专栏 如烟花般绚烂却又稍纵即逝的个人主页 本章讲述数据结构中搜索二叉树与HashMap的学习&#xff0c;感谢大家的支持&#xff01;欢迎大家踊跃评论&#xff0c;感谢大佬们的支持! 目录 搜索二叉树的概念二叉树搜索模拟实现搜索二叉树查找搜索二叉树插入搜索二叉树删除…

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

【开篇】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

qt QAnimationDriver详解

1、概述 QAnimationDriver是Qt框架中提供的一个类&#xff0c;它主要用于自定义动画帧的时间控制和更新。通过继承和实现QAnimationDriver&#xff0c;开发者可以精确控制动画的时间步长和更新逻辑&#xff0c;从而实现丰富和灵活的动画效果。QAnimationDriver与QAbstractAnim…

何时在 SQL 中使用 CHAR、VARCHAR 和 VARCHAR(MAX)

在管理数据库表时&#xff0c;考虑 CHAR、VARCHAR 和 VARCHAR(MAX) 是必不可少的。此外&#xff0c;使用正确的工具&#xff08;例如dbForge Studio for SQL Server&#xff09; &#xff0c;与数据库相关的任务都会变得更加容易。它是针对 SQL Server 专业人员的强大的一体化解…

20241127 给typecho文章编辑附件 添加视频 图片预览

Typecho在写文章时&#xff0c;如果一次性上传太多张图片可能分不清哪张&#xff0c;因为附件没有略缩图&#xff0c;无法实时阅览图片&#xff0c;给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…

Linux命令系列-常见查看系统资源命令

Linux命令系列-常见查看命令 进程管理内存管理磁盘空间管理网络管理主机系统 摘要&#xff1a;本文将对linux系统上常见的查看系统各种资源的命令进行介绍&#xff0c;包括du&#xff0c;df&#xff0c;netstat等命令。所有这些命令都有相关实验截图&#xff0c;实验平台为ubun…

【Python网络爬虫笔记】6- 网络爬虫中的Requests库

一、概述 Requests 是一个用 Python 语言编写的、简洁且功能强大的 HTTP 库。它允许开发者方便地发送各种 HTTP 请求&#xff0c;如 GET、POST、PUT、DELETE 等&#xff0c;并且可以轻松地处理请求的响应。这个库在 Python 生态系统中被广泛使用&#xff0c;无论是简单的网页数…

SolarCube: 高分辨率太阳辐照预测基准数据集

太阳能作为清洁能源在减缓气候变化中的作用日益凸显&#xff0c;其稳定的供应对电网管理至关重要。然而&#xff0c;太阳辐照受云层和天气变化的影响波动较大&#xff0c;给光伏电力的管理带来挑战&#xff0c;尤其是在调度、储能和备用系统管理方面。因此&#xff0c;精确的太…

对拍详细使用方法

对拍的作用 对于我们在学校OJ&#xff0c;cf&#xff0c;牛客…各种只提供少量测试数据的题目&#xff0c;常常交上代码常常超时&#xff0c;能写出正确的暴力代码而题目要求的时间复杂度更低。然而这时你写出了能通过样例且时间复杂度更低的代码&#xff0c;但交上去就是错误…

玄机应急:Apache日志分析Mysql应急Redis应急

目录 第二章&#xff1a;Linux的Apache日志分析 1、提交当天访问次数最多的IP&#xff0c;即黑客IP 2、黑客使用的浏览器指纹是什么&#xff0c;提交指纹的md5 3、查看index.php页面被访问的次数&#xff0c;提交次数&#xff1a; 4、查看黑客IP访问了多少次&#xff0c;提…

使用easyexcel导出复杂模板,同时使用bean,map,list填充

背景 在使用easyexcel导出时&#xff0c;如果遇到一个模板中同时存在 一部分是实体类中的字段&#xff0c;另外部分是列表的字段&#xff0c;需要特殊处理一下&#xff0c;比如下面的模板&#xff1a; 这里面 user&#xff0c; addr 是实体类&#xff08;或者map&#xff09…

otter 扩展

参见otter官方的说明&#xff1a;数据处理自定义&#xff0c;比如Extract , Transform的数据处理. 目前Select/Load不支持数据自定义处理。 Extract模块&#xff1a; 1.EventProcessor : 自定义数据处理&#xff0c;可以改变一条变更数据的任意内容。 2.FileResolver : 解决数…

STM32的CAN波特率计算

公式&#xff1a; CAN波特率 APB总线频率 / &#xff08;BRP分频器 1&#xff09;/ (SWJ BS1 BS2) SWJ一般为1。 例如STM32F407的&#xff0c;CAN1和CAN2都在在APB1下&#xff0c;频率是42000000 如果想配置成1M波特率&#xff0c;则计算公式为&#xff1a;

Z2400039基于Java-+ SpringBoot + vue 企业信息管理系统的设计与实现(源码 配置 PPT 文档 分享)

企业信息管理系统 1.项目描述2.项目结构后端&#xff08;Spring Boot&#xff09;前端&#xff08;Vue.js Element UI&#xff09; 2. 功能实现登录页首页系统管理岗位管理部门管理 3. 部署和运行注意事项 4.界面展示5.源码获取 1.项目描述 基于你的描述&#xff0c;这个项目…

hhdb数据库介绍(10-20)

监控 监控面板 监控面板为用户提供计算节点、服务器相关的监控功能&#xff0c;包含&#xff1a;计算节点服务状态、计算节点流量、计算节点服务器资源、其他服务器资源。 数据采集说明&#xff1a; 监控面板显示24小时内采集的数据&#xff08;需要放大显示&#xff0c;正…

医学机器学习:数据预处理、超参数调优与模型比较的实用分析

摘要 本文介绍了医学中的机器学习&#xff0c;重点阐述了数据预处理、超参数调优和模型比较的技术。在数据预处理方面&#xff0c;包括数据收集与整理、处理缺失值、特征工程等内容&#xff0c;以确保数据质量和可用性。超参数调优对模型性能至关重要&#xff0c;介绍了多种调…