警告

您正在阅读的 ROS 2 文档版本已达到 EOL(生命周期结束),不再受官方支持。如果您想了解最新信息,请访问 Jazzy.

ROS 2 开发人员指南

本页定义了我们在开发 ROS 2 时所采用的实践和政策。

一般原则

所有 ROS 2 的开发都遵循一些共同原则:

  • 共有产权:每个从事 ROS 2 研究的人都应该对系统的所有部分拥有所有权。某段代码的原作者没有任何特殊权限或义务来控制或维护该段代码。每个人都可以自由地在任何地方提出修改建议、处理任何类型的票据以及审核任何拉取请求。

  • 愿意从事任何工作:作为共享所有权的必然结果,每个人都应愿意承担任何可用的任务,并为系统的任何方面做出贡献。

  • 寻求帮助:如果您在某件事情上遇到困难,请酌情通过票据、评论或电子邮件向其他开发人员寻求帮助。

质量实践

软件包可根据其所遵循的开发实践,按照《软件包质量指南》中的指导原则划分为不同的质量等级。 REP 2004:包装质量类别.这些类别根据版本、测试、文档等方面的政策进行区分。

以下部分是我们为确保核心软件包达到最高质量("1 级")而遵循的具体开发规则。我们建议所有 ROS 开发人员努力遵守以下政策,以确保整个 ROS 生态系统的质量。

版本控制

我们将使用 语义版本管理准则 (半导体) 进行版本控制。

我们还将遵守一些 ROS 特有的规则,这些规则建立在 晾衣架 完整含义:

  • 不应在已发布的 ROS 发行版中进行重大版本升级(即破坏性更改)。

    • 补丁(界面保留)和次要(非破坏性)版本增量不会破坏兼容性,因此这类更改 允许在释放范围内使用。

    • ROS 重大版本是发布破坏性改动的最佳时机。如果一个核心软件包需要多处破坏性修改,则应将其合并到集成分支(如主分支)中,以便在 CI 中快速发现问题,但同时发布,以减少 ROS 用户的主要发布次数。

    • 虽然重大增量需要新的发行版,但新的发行版并不一定需要重大增量(如果开发和发布能在不破坏应用程序接口的情况下进行)。

  • 对于已编译的代码,ABI 被视为公共接口的一部分。任何需要重新编译依赖代码的变更都被视为重大变更(破坏性变更)。

    • ABI 破坏性更改 在小版本更新时 之前 发布版本(添加到滚动发布版本中)。

  • 我们为 Dashing 和 Eloquent 中的核心软件包执行 API 稳定性,即使它们的主要版本组件是 0尽管 SemVer 的规格 关于初期发展。

    • 随后,软件包应努力达到成熟状态,并增加到以下版本 1.0.0 以配合 晾衣架 规格。

注意事项

这些规则是 尽力.在不太可能的极端情况下,可能有必要在主要版本/发行版内中断 API。计划外中断是否会增加主要版本或次要版本,将根据具体情况进行评估。

例如,考虑一种情况,涉及已发布的 X-乌龟,对应的主要版本是 1.0.0并发布了 Y-turtle,对应的主要版本为 2.0.0.

如果在 X-turtle 中发现绝对有必要进行 API 破坏性修复,则将其提升至 2.0.0 显然是不可能的,因为 2.0.0 已经存在。

在这种情况下,处理 X-turtle 版本的解决方案都是非理想的:

  1. 修改 X-turtle 的次要版本:不理想,因为它违反了 SemVer 的原则,即破坏性修改必须修改主要版本。

  2. 将 X-乌龟的主要版本提升到 Y-乌龟(至 3.0.0):并不理想,因为旧发行版的版本会高于新发行版的可用版本,这将导致特定版本的条件代码失效/破解。

开发人员必须决定使用哪种解决方案,或者更重要的是,他们愿意打破哪条原则。我们无法建议二者取一,但无论哪种情况,我们都要求采取明确的措施,以人工方式向用户传达中断及其解释(而不仅仅是版本增量)。

如果没有 Y-乌龟,即使技术上的修复只是一个补丁,X-乌龟也必须跳转到 2.0.0.这种情况遵守了 SemVer 的规定,但打破了我们自己的规则,即不应该在已发布的发行版中引入重大增量。

这就是我们考虑版本规则的原因 尽力.尽管上述例子不太可能发生,但准确定义我们的版本系统还是很重要的。

公共应用程序接口声明

根据 半导体因此,每个软件包都必须明确声明公共 API。我们将使用软件包质量声明中的 "公共 API 声明 "部分来声明哪些符号是公共 API 的一部分。

对于大多数 C 和 C++ 软件包来说,声明就是它安装的任何头文件。不过,定义一组被视为私有的符号也是可以接受的。避免在头文件中使用私有符号有助于提高 ABI 的稳定性,但并非必须。

对于其他语言(如 Python),必须明确定义公共 API,以便明确哪些符号可依赖于版本控制准则。公共 API 还可以扩展到构建工件,如配置变量、CMake 配置文件等,以及可执行文件、命令行选项和输出。公共 API 的任何元素都应在软件包的文档中明确说明。如果在软件包的文档中没有将您正在使用的内容明确列为公共 API 的一部分,那么您就不能指望它不会在次版本或补丁版本之间发生变化。

折旧战略

在可能的情况下,我们还将在主要版本增量中使用 "滴答-滴答 "弃用和迁移策略。新的弃用功能将在新的发布版本中出现,并伴有编译器警告,说明该功能已被弃用。在下一个版本中,该功能将被完全删除(无警告)。

功能示例 动物 已废止,由函数 酒吧:

版本

应用程序接口

X-turtle

void foo();

乌龟

[[deprecated("use bar()")]] void foo(); <br> void bar();

乌龟

void bar();

我们不能在发行版发布后添加弃用内容。不过,弃用并不一定需要大版本升级。如果小版本升级发生在发行版发布之前,则可以在小版本升级中引入弃用(类似于 ABI 破坏性修改)。

例如,如果 X-turtle 以 2.0.0可以在 2.1.0 在 X-turtle 被释放之前。

我们将尽可能保持各发行版之间的兼容性。不过,就像与 SemVer 相关的注意事项一样,在某些情况下,tick-tock 甚至是一般的弃用(deprecation)可能无法完全遵守。

变更控制流程

  • 所有更改都必须通过拉取请求进行。

  • 我们将执行 开发商原产地证书(DCO) ROSCore 资源库中的拉取请求。

    • 它要求所有提交信息都包含 签署 行,并输入与提交作者匹配的电子邮件地址。

    • 您可以通过 -s / --签名笨蛋 承诺 或手动编写预期信息(例如 签署: 您的 名称 开发人员 <your.name@example.com>;).

    • 会计处是 对于只涉及空白删除、错字更正和其他问题的拉动请求,需要 琐屑.

  • 始终为所有 一级平台 并在拉取请求中包含作业链接。(如果您无法访问 Jenkins 作业,会有人为您触发作业)。

  • 拉取请求至少需要获得一名非作者的开发人员的批准,才能视为已获批准。合并前必须获得批准。

    • 套餐可选择增加这一数字。

  • 在合并相关变更之前,必须对文档(应用程序接口文档、功能文档、发布说明等)提出任何必要的变更。

反向移植 PR 的指导原则

更换旧版本的 ROS 时:

  • 确保功能或修正已被主分支接受并合并,然后再开启 PR,将更改回传至旧版本。

  • 反向移植到旧版本时,也要反向移植到任何 [更新的、仍受支持的版本](https://index.ros.org/doc/ros2/Releases/),甚至是非 LTS 版本。

  • 如果您要全部反向移植一个 PR,请将反向移植 PR 的标题定为"[Distro] <原始 PR 的名称>"。如果要反向移植一个或多个 PR 中的修改子集,标题应为"[Distro] <description of changes>"。

  • 在您的反向移植 PR 的描述中,链接到您要反向移植的所有 PR。在 Foxy 变更的 Dashing backport 中,您不需要链接到同一变更的 Eloquent backport。

文件

所有软件包都应在其 README 中包含这些文档元素,或从其 README 中链接到这些文档元素:

  • 说明和目的

  • 公共应用程序接口的定义和说明

  • 实例

  • 如何构建和安装(应参考外部工具/工作流程)

  • 如何构建和运行测试

  • 如何建立文档

  • 如何开发(用于描述以下内容 蟒蛇 setup.py 发展)

  • 许可证和版权声明

每个源文件都必须有许可证和版权声明,并通过自动检查程序进行检查。

每个软件包都必须有一个 LICENSE 文件,通常是 Apache 2.0 许可证,除非该软件包有现有的许可许可证(例如 rviz 使用三条款 BSD)。

每个软件包都应尽可能假设读者是在不了解 ROS 或其他相关项目的情况下偶然发现它的,并对其本身及其目的进行描述。

每个软件包都应定义和描述其公共应用程序接口(Public API),以便用户对语义版本化策略所涵盖的内容有一个合理的预期。即使在 C 和 C++ 中,公共 API 可以通过 API 和 ABI 检查来执行,但这也是描述代码布局和代码各部分功能的好机会。

任何软件包都可以很容易地从该软件包的文档中了解如何构建、运行、构建和运行测试以及构建文档。显然,我们应该避免重复常见的工作流程,比如在工作区中构建软件包,但基本的工作流程应该得到描述或引用。

最后,它还应包括任何供开发人员使用的文档。这可能包括使用以下工具测试代码的工作流程 蟒蛇 setup.py 发展或者描述如何使用软件包提供的扩展点。

例如

(应用程序接口文档尚未自动生成)

测试

所有软件包都应进行一定程度的系统、集成和/或单元测试。

单元测试 应始终在正在测试的软件包中,并应使用诸如 模拟 以尝试在构建的场景中测试代码库的狭小部分。单元测试不应引入非测试工具的测试依赖项,如 gtest、nosetest、pytest、mock 等。

集成测试 可以测试代码各部分之间或代码各部分与系统之间的交互。它们通常以我们期望用户使用的方式来测试软件接口。与单元测试一样,集成测试也应在被测试的软件包中进行,除非绝对必要,否则不应引入非工具测试依赖项,也就是说,只有在极端严格的审查下才允许所有非工具依赖项,因此应尽可能避免。

系统测试 旨在测试软件包之间的端到端情况,应放在自己的软件包中,以避免软件包臃肿或耦合,并避免循环依赖。

一般来说,应尽量避免外部或跨包测试依赖,以防止出现循环依赖和紧耦合测试包。

所有软件包都应该有一些单元测试,也可能有集成测试,但其程度取决于软件包的质量类别。以下小节适用于 "1 级 "软件包:

代码覆盖率

我们将提供线路覆盖率,并使线路覆盖率达到 95% 以上。如果有理由降低目标百分比,则必须在显著位置予以说明。我们可以提供分支覆盖率,或将代码排除在覆盖范围之外(测试代码、调试代码等)。我们要求在合并变更之前,覆盖率必须提高或保持不变,但在有适当理由的情况下,也可以接受降低代码覆盖率的变更(例如,删除以前覆盖的代码可能会导致覆盖率下降)。

性能

我们强烈建议进行性能测试,但也认识到性能测试对某些软件包没有意义。如果有性能测试,我们会选择在每次变更或每次发布前进行检查,或两者兼而有之。我们还将要求在合并变更或发布版本时说明降低性能的理由。

林特和静态分析

我们将使用 ROS 代码风格 并用 ament_lint_common.所有衬垫/静态分析均属于 ament_lint_common 必须使用

"(《世界人权宣言》) 自动 文档提供了运行 ament_lint_common.

一般做法

有些做法在所有 ROS 2 开发中都是通用的。

这些做法不会影响包件质量水平,如 REP 2004但仍强烈建议在开发过程中使用。

问题

在提交问题时,请确保:

  • 包含足够的信息,以便他人了解问题。在 ROS 2 中,需要以下几点来缩小问题原因的范围。在可行的情况下,尽可能多地测试每个类别中的替代方案会特别有帮助。

    • 操作系统和版本。 理由ROS 2 支持多种平台,有些错误是特定操作系统/编译器版本特有的。

    • 安装方法。 理由是什么?有些问题只有在从 "胖压缩包 "或 Debians 安装 ROS 2 时才会出现。这可以帮助我们确定问题是否出在打包过程中。

    • 特定版本的 ROS 2. 理由某些错误可能存在于特定的 ROS 2 版本中,但后来被修复了。了解您的安装是否包含这些修复很重要。

    • 使用的 DDS/RMW 实现 (见 本页 如何确定哪一个)。推理:通信问题可能与所使用的底层 ROS 中间件有关。

    • 正在使用的 ROS 2 客户端库。 推理:这有助于我们缩小问题可能出现在堆栈中哪一层的范围。

  • 包括重现问题的步骤列表。

  • 如果出现错误,请考虑提供 简短、自含、正确(可编译)、示例.如果其他人可以很容易地复制这些问题,那么这些问题就更有可能得到解决。

  • 提及已经尝试过的故障排除步骤,包括

    • 升级到最新版本的代码,其中可能包括尚未发布的错误修复。参见 本节 并按照说明获取 "主 "分支。

    • 尝试使用不同的 RMW 实现。请参见 本页 如何做到这一点。

拉取请求

  • 一个拉取请求应只关注一项变更。不同的变更应分别提交不同的拉取请求。参见 GitHub 完美拉取请求撰写指南.

  • 补丁的大小应该最小,避免任何不必要的改动。

  • 拉取请求必须包含最少数量的有意义提交。

    • 您可以在拉取请求审核期间创建新提交。

  • 在合并拉取请求之前,应将所有更改压缩成少量语义提交,以保持历史清晰。

    • 但要避免在拉取请求正在审核时压制提交。审阅者可能不会注意到你做了改动,从而可能造成混乱。另外,无论如何,您都会在合并前压制提交;提前压制提交没有任何好处。

  • 欢迎任何开发人员审查和批准拉取请求(请参阅 一般原则).

  • 当您开始审核拉取请求时,请在拉取请求上发表评论,以便其他开发人员知道您正在审核该请求。

  • 拉动式请求审稿不是只读,审稿人可以提出意见,然后等待作者处理。作为审阅者,可以随时就地进行小的改进(错别字、风格问题等)。作为拉取请求的开启者,如果您在一个分叉中工作,请勾选 允许上游贡献者进行编辑 将协助完成上述工作。作为审阅者,您也可以随意做出更多实质性的改进,但请考虑将其放在一个单独的分支中(在评论中提及新分支,或从新分支向原分支提交另一个拉取请求)。

  • 任何开发者(作者、审核者或其他人)都可以合并任何已批准的拉取请求。

图书馆版本管理

我们会将软件包中的所有库一起进行版本控制。这意味着库将从软件包中继承其版本。这样可以避免库和软件包的版本出现分歧,同时也符合将共享源的软件包一起发布的政策。如果需要不同版本的库,可以考虑将它们拆分成不同的软件包。

发展进程

  • 默认分支(大多数情况下是主分支)必须始终进行编译、通过所有测试并在编译时不出现警告。如果在任何时候出现回归,首要任务是至少恢复之前的状态。

  • 始终启用测试进行构建。

  • 在更改后和在拉取请求中提出之前,始终在本地运行测试。除了使用自动测试外,也要手动运行修改后的代码路径,以确保补丁能按预期运行。

  • 始终为每个拉取请求运行所有平台的 CI 作业,并在拉取请求中包含作业链接。

有关推荐软件开发工作流程的更多详情,请参阅 软件开发生命周期 节。

更改 RMW 应用程序接口

更新时 RMW API因此,需要同时更新第 1 层中间件库的 RMW 实现。例如,一个新函数 rmw_foo() 引入 RMW 应用程序接口必须在以下软件包中实现(截至 ROS Foxy):

如果可行(如取决于变更的大小),也应考虑更新非第 1 层中间件库。参见 REP-2000 中间件库及其层级的列表。

跟踪任务

为了帮助组织 ROS 2 的工作,ROS 2 核心开发团队使用了看板式的 GitHub 项目板.

不过,并非所有问题和拉取请求都会在项目板上进行跟踪。板块通常代表即将发布的版本或特定项目。可以通过浏览项目板的 ROS 2 资源库 单期页面。

ROS 2 项目板中各栏的名称和用途各不相同,但一般都遵循相同的总体结构:

  • 要做:与项目相关的问题,可随时分配

  • 进行中:当前工作正在进行中的活动拉取请求

  • 回顾:工作已完成并准备接受审核的拉取请求,以及目前正在接受审核的拉取请求

  • 已完成:拉取请求和相关问题已合并/关闭(仅供参考)

要申请更改权限,只需在您感兴趣的票单上发表评论即可。根据问题的复杂程度,描述您计划如何解决可能会有所帮助。我们将更新状态(如果您没有权限),然后您就可以开始拉取请求。如果您经常做出贡献,我们可能会授予您权限,让您自己管理标签等。

编程惯例

  • 防御性编程:确保尽可能早地保留假设。例如,检查每一个返回代码,确保至少抛出一个异常,直到该情况得到更优雅的处理。

  • 所有错误信息必须发送到 stderr.

  • 在尽可能小的范围内声明变量。

  • 保存按字母顺序排列的项目组(依赖项、导入项、包含项等)。

C++ 专用

  • 避免使用直接流 (<<;)到 数据输出 / stderr 以防止在多个线程之间交错运行。

  • 避免将参考文献用于 std::shared_ptr 因为这会颠覆引用计数。如果原始实例退出作用域,而引用正在被使用,它就会访问已释放的内存。

文件系统布局

软件包和软件源的文件系统布局应遵循相同的约定,以便为浏览源代码的用户提供一致的体验。

包装布局

  • 来源:包含所有 C 和 C++ 代码

    • 还包含未安装的 C/C++ 头文件

  • 包括:包含所有已安装的 C 和 C++ 头文件

    • <package name>;注意:对于所有已安装的 C 和 C++ 头文件,应使用软件包名称命名文件夹

  • <package_name>;:包含所有 Python 代码

  • 测试:包含所有自动测试和测试数据

  • 文件文件:包含所有文件

  • package.xml:根据以下定义 REP-0140 (可为原型设计进行更新)

  • CMakeLists.txt:仅使用 CMake 的 ROS 软件包

  • setup.py:仅使用 Python 代码的 ROS 软件包

  • 阅读说明:可在 GitHub 上显示为项目的登陆页面

    • 简短或详细均可,但至少应链接到项目文件

    • 考虑在此 README 中加入 CI 或代码覆盖率标签

    • 也可以 .rst 或其他任何 GitHub 支持的功能

  • 捐款说明捐款准则

    • 这可能包括许可证含义,例如在使用 Apache 2 许可证时。

  • 许可证:该软件包的许可证副本

  • CHANGELOG.rst: REP-0132 符合要求的更新日志

存储库布局

每个软件包都应放在与软件包同名的子文件夹中。如果一个软件源只包含一个软件包,可以选择将其放在软件源的根目录中。

有抱负的做法

目前,我们并没有采用本节中的做法,但我们相信这些做法对开发过程是有益的,并希望将来能正式采用。

软件开发生命周期

本节将逐步介绍如何规划、设计和实施新功能:

  1. 创建任务

  2. 创建设计文件

  3. 设计审查

  4. 实施情况

  5. 代码审查

创建任务

需要更改 ROS 2 关键部分的任务应在发布周期的早期阶段进行设计审查。如果设计审查是在后期进行的,那么这些更改将成为未来版本的一部分。

  • 应在适当的 ros2 存储库清楚地描述正在进行的工作。

    • 它应该有明确的成功标准,并强调预期的具体改进。

    • 如果功能的目标是发布 ROS 版本,请确保在 ROS 发布票据 (范例).

编写设计文件

设计文件绝不能包含机密信息。变更是否需要设计文件取决于任务的大小。

  1. 您正在做一个小改动或修复一个错误:

  • 不需要设计文档,但应在适当的资源库中打开一个问题,以跟踪工作并避免重复工作。

  1. 您正在实施一项新功能,或希望为 OSRF 拥有的基础设施(如 Jenkins CI)做出贡献:

提及相关的 ros2 问题(例如: 设计 文件 对于 工作 ros2/ros2#<issue id>;) 在拉取请求或提交信息中。详细说明请参见 ROS 2 贡献 页。设计意见将直接在拉取请求中提出。

如果任务计划与特定版本的 ROS 一起发布,则应在拉取请求中包含此信息。

设计文件审查

一旦设计准备就绪,就应开启拉取请求并指定适当的审核人员。建议包括项目所有者--所有受影响软件包的维护者(由以下定义 package.xml 维护者字段,请参见 REP-140) - 作为审查员。

  • 如果设计文件比较复杂,或者评审人员的时间安排有冲突,可以选择召开设计评审会议。在这种情况下

    会前

    • 至少提前一周发出会议邀请

    • 建议会议时间为一小时

    • 会议邀请函应列出审查期间要做出的所有决定(需要软件包维护者批准的决定)

    • 会议所需与会者:设计拉动请求审查员

      会议可选与会者:所有 OSRF 工程师(如适用

    会议期间

    • 任务负责人推动会议,提出自己的想法并管理讨论,确保按时达成一致意见

    会后

    • 任务负责人应将会议记录反馈给所有与会者

    • 如果对设计提出了一些小问题:

      • 任务负责人应根据反馈意见更新设计文档拉取请求

      • 无需额外审查

    • 如果对设计提出了重大问题:

      • 删除未达成明确一致意见的部分是可以接受的

      • 设计中值得商榷的部分可在今后作为一项单独任务重新提交

      • 如果无法移除有争议的部分,则直接与包件所有者合作达成协议

  • 一旦达成共识:

    • 确保 ros2/design 已合并拉取请求(如适用

    • 更新并关闭与此设计任务相关的 GitHub 问题

实施情况

在开始之前,请阅读 拉取请求 部分了解最佳做法。

  • 对于每个要修改的版本库:

    • 修改代码,完成后进入下一步,或定期备份工作。

    • 自我审查 使用 笨蛋 增加 -i.

    • 使用 笨蛋 承诺 -s.

      • 拉取请求应包含语义意义最小的提交(例如,不接受大量单行提交)。在迭代反馈的同时创建新的修复提交,或使用 笨蛋 承诺 --修改 如果您不想每次都创建新的提交,请使用

      • 每个提交都必须有正确书写的、有意义的提交信息。更多说明 这里.

      • 移动文件必须在单独的提交中完成,否则 git 可能无法准确跟踪文件历史。

      • 无论是拉取请求描述还是提交信息,都必须包含对相关 ros2 问题的引用,以便在合并拉取请求时自动关闭该问题。参见 文件 了解更多详情。

      • 推送新提交

代码审查

一旦变更准备就绪,即可进行代码审查:

  • 为每个修改过的版本库打开一个拉取请求。

    • 请记住 拉取请求 最佳实践。

    • GitHub 可用于从命令行创建拉取请求。

    • 如果任务计划与特定版本的 ROS 一起发布,则应在每个拉取请求中包含此信息。

  • 拉取请求中应提及审核设计文档的软件包所有者。

  • 代码审查 SLO:尽管审查拉取请求是尽力而为的,但让审查员在一周内对拉取请求发表评论,让代码作者在一周内回复评论,这样就不会丢失上下文,这很有帮助。

  • 像往常一样迭代反馈,根据需要修改和更新开发分支。

  • 一旦 PR 获得批准,软件包维护者就会将更改合并进来。