警告
您正在阅读的 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 版本的解决方案都是非理想的:
修改 X-turtle 的次要版本:不理想,因为它违反了 SemVer 的原则,即破坏性修改必须修改主要版本。
将 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 发展
或者描述如何使用软件包提供的扩展点。
例如
能力: https://docs.ros.org/hydro/api/capabilities/html/
本例给出了描述公共应用程序接口的文档示例
catkin_tools: https://catkin-tools.readthedocs.org/en/latest/development/extending_the_catkin_command.html
这是一个描述软件包扩展点的示例
(应用程序接口文档尚未自动生成)
测试
所有软件包都应进行一定程度的系统、集成和/或单元测试。
单元测试 应始终在正在测试的软件包中,并应使用诸如 模拟
以尝试在构建的场景中测试代码库的狭小部分。单元测试不应引入非测试工具的测试依赖项,如 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 客户端库。 推理:这有助于我们缩小问题可能出现在堆栈中哪一层的范围。
包括重现问题的步骤列表。
如果出现错误,请考虑提供 简短、自含、正确(可编译)、示例.如果其他人可以很容易地复制这些问题,那么这些问题就更有可能得到解决。
提及已经尝试过的故障排除步骤,包括
拉取请求
一个拉取请求应只关注一项变更。不同的变更应分别提交不同的拉取请求。参见 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 符合要求的更新日志
存储库布局
每个软件包都应放在与软件包同名的子文件夹中。如果一个软件源只包含一个软件包,可以选择将其放在软件源的根目录中。
有抱负的做法
目前,我们并没有采用本节中的做法,但我们相信这些做法对开发过程是有益的,并希望将来能正式采用。
软件开发生命周期
本节将逐步介绍如何规划、设计和实施新功能:
创建任务
创建设计文件
设计审查
实施情况
代码审查
创建任务
需要更改 ROS 2 关键部分的任务应在发布周期的早期阶段进行设计审查。如果设计审查是在后期进行的,那么这些更改将成为未来版本的一部分。
编写设计文件
设计文件绝不能包含机密信息。变更是否需要设计文件取决于任务的大小。
您正在做一个小改动或修复一个错误:
不需要设计文档,但应在适当的资源库中打开一个问题,以跟踪工作并避免重复工作。
您正在实施一项新功能,或希望为 OSRF 拥有的基础设施(如 Jenkins CI)做出贡献:
设计文件是必需的,应提交给 ros2/design 在 https://design.ros2.org/.
您应该 fork 该版本库,并提交一份拉取请求,详细说明设计。
提及相关的 ros2 问题(例如:
设计 文件 对于 工作 ros2/ros2#<issue id>;
) 在拉取请求或提交信息中。详细说明请参见 ROS 2 贡献 页。设计意见将直接在拉取请求中提出。
如果任务计划与特定版本的 ROS 一起发布,则应在拉取请求中包含此信息。
设计文件审查
一旦设计准备就绪,就应开启拉取请求并指定适当的审核人员。建议包括项目所有者--所有受影响软件包的维护者(由以下定义 package.xml
维护者字段,请参见 REP-140) - 作为审查员。
如果设计文件比较复杂,或者评审人员的时间安排有冲突,可以选择召开设计评审会议。在这种情况下
会前
至少提前一周发出会议邀请
建议会议时间为一小时
会议邀请函应列出审查期间要做出的所有决定(需要软件包维护者批准的决定)
- 会议所需与会者:设计拉动请求审查员
会议可选与会者:所有 OSRF 工程师(如适用
会议期间
任务负责人推动会议,提出自己的想法并管理讨论,确保按时达成一致意见
会后
任务负责人应将会议记录反馈给所有与会者
如果对设计提出了一些小问题:
任务负责人应根据反馈意见更新设计文档拉取请求
无需额外审查
如果对设计提出了重大问题:
删除未达成明确一致意见的部分是可以接受的
设计中值得商榷的部分可在今后作为一项单独任务重新提交
如果无法移除有争议的部分,则直接与包件所有者合作达成协议
一旦达成共识:
确保 ros2/design 已合并拉取请求(如适用
更新并关闭与此设计任务相关的 GitHub 问题
实施情况
在开始之前,请阅读 拉取请求 部分了解最佳做法。
代码审查
一旦变更准备就绪,即可进行代码审查: