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 将更改反向移植到旧版本之前,确保功能或修正已被接受并合并到滚动分支中。

  • 在反向移植到旧版本时,也要考虑反向移植到任何其他 仍支持的版本甚至是非 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 发展或者描述如何使用软件包提供的扩展点。

例如

ROS 软件包的应用程序接口文档

所有已发布的 ROS 软件包的应用程序接口文档都可以在 在这里找到.我们建议使用 index.ros.org 来搜索可用的 ROS 软件包,查找它们的文档。

如果您是 ROS 软件包开发人员,正在寻找软件包文档化指南,请参阅 我们的软件包级文档 "如何 "指南.所有已发布的 ROS 2 软件包的文档都自动托管在 docs.ros.org.

测试

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

单元测试 应始终在正在测试的软件包中,并应使用诸如 模拟 以尝试在构建的场景中测试代码库的狭小部分。单元测试不应引入非测试工具的测试依赖项,如 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 实现。请参见 本页 如何做到这一点。

分支机构

备注

这些只是指导原则。软件包维护者可以根据自己的工作流程选择分支名称。

好的做法是 分行 的分支。这些分支通常以其针对的发行版命名。例如 简陋 专门针对谦卑分布的发展分支。

这些分支也会发布相应的版本。针对特定 ROS 发行版的开发可以在相应的分支上进行。例如针对 狐狸狐狸 分支,以及 狐狸 是由同一树枝制成的。

备注

这就要求软件包维护者在适当的情况下执行反向移植(backports)或前向移植(forwardports),以保持所有分支的功能都是最新的。维护者还必须对仍在发布软件包的所有分支进行一般维护(错误修复等)。

例如,如果某个功能被合并到 Rolling 专属分支(如 滚动主要),并且该功能也适用于 Humble 发行版(不会破坏 API 等),那么将该功能反向移植到 Humble 专属分支是个不错的做法。

如果有新功能或错误修复,维护者可能会发布这些旧版本的版本。

那么 主要 滚动 ?

主要 典型目标 滚动 (因此,下一个未发布的 ROS 发行版),尽管维护者可能会决定从一个 滚动 分支。

拉取请求

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

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

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

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

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

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

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

  • 当您正在处理一项尚未准备好审核或合并的变更时,请使用草案拉取请求。当该变更准备好接受审核时,将拉取请求从草稿状态移出。需要注意的是,如果你希望特定人员对草案拉取请求提供早期反馈,你可以@在拉取请求的描述中或在拉取请求的评论中提及他们。

  • 如果您的拉取请求依赖于其他拉取请求,请通过添加 - 视情况而定 关于 <链接>; 放在拉取请求描述的顶部。这样做有助于审核人员了解拉取请求的上下文。

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

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

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

图书馆版本管理

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

发展进程

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

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

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

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

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

更改 RMW 应用程序接口

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

如果可行(如取决于变更的大小),也应考虑更新非第 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 代码

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

  • 配置配置文件:包含配置文件,如 YAML 参数文件和 RViz 配置文件

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

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

  • 信息:包含所有 ROS 消息定义

  • 服务服务:包含所有 ROS 服务定义

  • 行动:包含所有 ROS 行动定义

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

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

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

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

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

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

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

  • 捐款说明捐款准则

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

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

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

存储库布局

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

上游套餐

Debian 和 Ubuntu 上游软件包

由于 Jochen Sprickerhof 和 Leopold Palomo-Avellaneda 的辛勤努力,部分 ROS 2 软件包现已推出 从主要的 Debian 和 Ubuntu 软件源中获取。 以下是 Jochen 在 ROSCon 2015 上对这一过程的简短概述.原始 ROS 软件包已根据 Debian 指南进行了修改,包括将软件包拆分成多个部分、在某些情况下更改名称、根据 FHS 指南安装到 /usr,以及在共享库上使用 soversions。

此外,还有一些引导依赖项,如命令行工具,如 vcstool胶管 以及一些库,如 osrf-pycommon动情 也在上游打包。

与 OSRF 提供的来自 http://packages.ros.org,上游软件源中的软件包没有附加到特定的 ROS 分布.相反,它们代表了一个时间快照,将在 Debian 不稳定版中定期更新,然后在不同的时间点嵌入到下游的 Debian 和 Ubuntu 发行版中。

不要混流

我们强烈建议不要将来自 Debian/Ubuntu 上游的 ROS 软件包和来自 http://packages.ros.org 在同一个系统上。在某些情况下,这种混合系统可以正常工作,但两套软件包之间可能会产生负面影响。我们正与 Jochen 和朋友们合作,通过文档和软件包冲突规范将问题发生的几率降到最低,但我们预计仍会存在一些风险,包括一些相当微妙的问题。

因此,我们建议您选择安装上游软件包或 http://packages.ros.org但不能同时安装。不仅不能同时安装这两种软件包,而且如果你打算使用上游软件包,你甚至不应该安装 http://packages.ros.org 中的条目(即在 /etc/apt/sources*).同时启用这两个源可能会导致两个源中名称重叠的软件包混用,例如 python3-rospkg.

已知差异

与 packages.ros.org 上的 ROS 软件包相比,上游的 ROS 软件包有一些不同之处值得注意:

  • 这套软件包不完整。

  • 软件包可能有不同的名称和分区。

开发人员工作流程

我们使用以下工具跟踪与即将发布的版本和大型项目相关的未结票据和活动 PR GitHub 项目板.

通常的工作流程是

  • 讨论设计(GitHub 在相应版本库中的票据,并将设计 PR 发至 https://github.com/ros2/design 如果需要)

  • 在分叉分支的功能分支上编写实施方案

  • 编写测试

  • 启用并运行衬垫

  • 使用 胶管 测试科尔康教程)

  • 当所有内容都在本地构建完成且无警告、所有测试都通过后,在功能分支上运行 CI:

    • 转至 ci.ros2.org

    • 登录(右上角)

    • 点击 ci_launcher 工作

    • 单击 "使用参数构建"(左侧栏)

    • 在第一个方框 "CI_BRANCH_TO_TEST "中输入功能分支名称

    • 点击 构建 按钮

    (如果您不是 ROS 2 的提交者,则无法访问 CI 场。在这种情况下,请联系您 PR 的审核人,让他为您运行 CI)

  • 如果您的用例需要运行代码覆盖:

    • 转至 ci.ros2.org

    • 登录(右上角)

    • 点击 ci_linux 覆盖范围 工作

    • 单击 "使用参数构建"(左侧栏)

    • 确保 "CI_BUILD_ARGS "和 "CI_TEST_ARGS "保留默认值

    • 点击 构建 按钮

    • 本文件末尾有说明如何 解读报告结果计算覆盖率

  • 如果构建的 CI 作业没有警告、错误和测试失败,请将作业链接发布到您的 PR 或汇总所有 PR 的高级票据上(请参阅示例 这里)

    • 请注意,这些徽章的标记在 ci_launcher 工作

  • 当 PR 获得批准后:

    • 提交 PR 的人使用 "压扁并合并 "选项合并 PR,以便我们保持历史记录的完整性

      • 如果提交值得分开:将所有挑刺/linters/typo 合并,然后合并剩余的提交集

        • 注意:每个 PR 都应针对特定功能,因此压扁和合并在 99% 的情况下都有意义

  • 合并后删除分支

建筑开发实践

本节介绍了在对 ROS 2 进行大规模架构修改时应采用的理想生命周期。

软件开发生命周期

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

  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 获得批准,软件包维护者就会将更改合并进来。

建设农场简介

建设农场位于 ci.ros2.org.

每天晚上,我们都会运行夜间工作,在不同平台的不同场景中构建和运行所有测试。此外,在合并之前,我们会在这些平台上测试所有拉取请求。

这就是当前的目标平台和架构集,尽管它会随着时间的推移而变化:

  • Ubuntu 24.04 高贵版

    • amd64

    • aarch64

  • Windows 10

    • amd64

建筑工地上有几类工作:

  • 手动任务(由开发人员手动触发):

    • ci_linux:在 Ubuntu 上构建和测试代码

    • ci_linux-aarch64:在 ARM 64 位机器(arch64)上的 Ubuntu 上构建和测试代码

    • ci_linux_coverage:构建 + 测试 + 生成测试覆盖率

    • ci_windows:在 Windows 上构建和测试代码

    • ci_launcher:触发上述所有工作

  • 夜间运行(每晚运行):

    • 调试:使用 CMAKE_BUILD_TYPE=Debug 生成并测试代码

      • nightly_linux_debug

      • nightly_linux-aarch64_debug

      • nightly_win_deb

    • 发布:使用 CMAKE_BUILD_TYPE=Release 构建并测试代码

      • nightly_linux_release

      • nightly_linux-aarch64_release

      • 每晚赢利

    • 重复:构建然后运行每个测试,最多 20 次或直到失败为止(又称 "松散性猎手")。

      • nightly_linux_repeated

      • nightly_linux-aarch64_repeated

      • nightly_win_rep

    • 覆盖范围

      • nightly_linux_coverage:构建 + 测试代码 + 分析 c/c++ 和 python 的覆盖率

        • 结果作为 cobertura 报告导出

  • 打包(每晚运行;结果捆绑到存档中):

    • 包装 Linux

    • 包装窗口

另外两个构建农场通过提供源代码和二进制软件包的构建、持续集成、测试和分析,为 ROS / ROS 2 生态系统提供支持。

有关详细信息、常见问题和故障排除,请参阅 建农场.

关于覆盖运行的说明

ROS 2 软件包的组织方式是,特定软件包的测试代码不仅包含在该软件包中,也可能存在于其他软件包中。换句话说:软件包可以在测试阶段使用属于其他软件包的代码。

为了达到 ROS 2 核心软件包中所有可用代码的覆盖率,建议使用一组固定的建议软件源进行构建。这组资源库在 Jenkins 的覆盖作业默认参数中已定义。

如何从建筑群报告中读取覆盖率

查看特定软件包的覆盖范围报告:

  • ci_linux 覆盖范围 构建完成后,点击 覆盖范围 报告

  • 向下滚动到 覆盖范围 细目 包装

  • 在表格中,查看名为 "姓名 "的第一列

构建库中的覆盖报告包括 ROS 工作区中使用的所有软件包。覆盖率报告包括同一软件包对应的不同路径:

  • 用表格命名条目: src.*.<repository_name>.<package_name>.* 这些与软件包中针对自身源代码的可用单元测试运行相对应

  • 用表格命名条目: build.<repository_name>.<package_name>.* 这些与软件包中针对其在构建或配置时生成的文件的可用单元测试运行相对应

  • 用表格命名条目: install.<package_name>.* 这些对应于来自其他软件包测试运行的系统/集成测试

如何从建筑群报告中计算覆盖率

使用自动脚本获取综合单位覆盖率:

  • 从 ci_linux_coverage Jenkins 构建中复制构建的 URL

  • 下载 get_coverage_ros2_pkg 脚本

  • 执行脚本: ./get_coverage_ros2_pkg.py <jenkins_build_url>; <ros2_package_name>; (阅读说明)

  • 抓取脚本输出中 "合并单元测试 "最后一行的结果

替代方法:从覆盖率报告中获取综合单位覆盖率(需要手动计算):

  • 完成 ci_linux_coverage 的构建后,点击 科贝图拉 覆盖范围 报告

  • 向下滚动到 覆盖范围 细目 包装

  • 在该表的第一列 "名称 "下查找(其中<package_name>是正在测试的软件包):

    • 模式下的所有目录 src.*.<repository_name>.<package_name>.* 抓取 "线条 "栏中的两个绝对值。

    • 模式下的所有目录 build/.<repository_name>.* 抓取 "线条 "栏中的两个绝对值。

  • 根据前面的选择:对于每个单元格,第一个值是已测试行数,第二个值是代码总行数。将所有行汇总,得出测试行总数和被测代码行总数。除以得出覆盖率。

如何使用 lcov 在本地测量覆盖率 (Ubuntu)

要在自己的机器上测量覆盖率,请安装 lcov.

苏都 适切 安装 -y lcov

本节其余部分假定您在 colcon 工作区中工作。在调试中使用覆盖标志进行编译。您可以随意使用 colcon 标志来针对特定软件包进行编译。

胶管 构建 --cmake-args -dcmake_build_type(构建类型=调试 -dcmake_cxx_flags。=";${cmake_cxx_flags} --覆盖范围"; -dcmake_c_flags=";${CMAKE_C_FLAGS} --覆盖范围";

lcov 需要一个初始基线,您可以使用以下命令生成初始基线。根据需要更新输出文件的位置。

lcov --无外部 --捕捉 --初始 --目录 . --输出文件 ~/ros2_base.info

运行与覆盖率测量相关的软件包测试。例如,如果测量 rclcpp 还有 test_rclcpp

胶管 测试 --软件包--选择 rclcpp test_rclcpp

用类似的命令捕捉 lcov 结果,这次去掉了 --初始 旗子

lcov --无外部 --捕捉 --目录 . --输出文件 ~/ros2.info

合并跟踪 .info 文件:

lcov --添加跟踪文件 ~/ros2_base.info --添加跟踪文件 ~/ros2.info --输出文件 ~/ros2_coverage.info

生成 html,方便对覆盖线进行可视化和注释。

mkdir -p 覆盖率 genhtml ~/ros2_coverage.info --输出目录 覆盖率