Autoware.Auto 文档的这一部分提供了为 Autoware.Auto 做出贡献的政策、程序、最佳实践和规则。 您应该从贡献者指南开始。
子页面
您还可以找到下面列出的其他信息性文章。
- 有关如何在考虑安全问题的情况下将算法从 Autoware.AI 和 ROS 1 移植到 Autoware.Auto 和 ROS 2 的指南,请参阅 Apex.AI 的这篇内容丰富的博客文章 。
- 这些文章讨论了如何在开源世界中构建高质量的软件:
指南和最佳实践
贡献工作流程
- 创建一个 定义您的预期贡献的问题
- 通过从下拉列表中选择一个来 使用提供的模板之一 。
- Assignee 在该领域 中选择自己。
- 如果您有权这样做,请分配给适当的里程碑。 如果您没有权限,请 在问题中 提及 维护者 以进行里程碑分配。
- 您选择的问题模板将为问题类型(错误、讨论、功能或改进)分配一个适当的标签。 从可用列表中分配您认为适合问题状态或其他属性的任何其他标签。
- 创建一个分叉
- 有关 fork-and-pull 模型的更多信息,请参阅“ 在 Fork 中开发” 页面。
- 编写代码
- 创建合并请求
- 有关 fork-and-pull 模型的更多信息,请参阅“ 在 Fork 中开发” 页面。
- 完成合并请求
- MR的审核流程如下:
- 提交者添加审阅者并指定自己。
- 审稿人审阅并提交评论。
- 受让人处理审查并进行必要的更改,并通知审查者再看一次。
- 根据需要重复 2 和 3。
- 当 Reviewer 批准后,MR 应该被分配到 @merge-bot 帐户,该帐户将自动 rebase 并合并它。
- 为了将合并请求合并到 Autoware.Auto,它必须满足以下条件:
- 必须解决有关合并请求的所有讨论。
- 合并请求清单的所有项目都被选中。
- 合并请求的 CI 作业必须已成功通过。
- 审核者接受您的合并请求后,将合并请求分配给该 @merge-bot 帐户。
通用代码开发指南
功能代码仅允许使用 C++14 及更低版本。 允许使用 Python 3.7+ 和 Bash 作为工具。 CMake 是首选的构建系统,它应该与 Colcon 集成。 偏差需要得到维护者的批准。
C++14 和 Python 3.7+ 的要求与 ROS Foxy 中的编译器和工具支持一致。 随着新的操作系统或 ROS 环境成为目标,这可能会在未来发生变化; 有关详细信息,请参阅 系统依赖项和目标环境 。
许可和版权
每个文件都应该有一个许可证头; 请参阅 CONTRIBUTING.md中的 许可证 部分 。
构造型
见 构造型 。
提交
开发人员应定期提交并推送到 GitLab,以避免数据丢失。 提交消息应遵循本文所述 的 通用标准。 总之,
- 用命令式写下你的提交信息
- 在强制性的第一行,总结 功能变化是 什么,而不是 为什么 要引入
- (可选)添加更多由空行分隔的详细信息
作为一般建议,在提交消息中添加对问题的引用,以便其他人在未来更容易获得有关提交更改的更多上下文。 如果提交不涉及特定问题,而仅涉及特定包或方面,请添加对它的引用。
参考问题 #716 的示例摘要行:
[#716] 扩展贡献者指南
没有问题的示例摘要行:
[CI] 禁用 foo 和 bar 包中的易碎测试
有通过 git 钩子帮助提交消息的帮助。 导航到 .git/hooks Autoware.Auto 的结帐中,然后:
ln -s ../../.git-hooks/prepare-commit-msg # 前置问题编号
ln -s ../../.git-hooks/commit-msg # 检查提交信息的格式 |
跨平台兼容性
尽可能使用跨平台解决方案进行系统级函数调用。 虽然 C++ 标准库应该用于尽可能多的任务,但某些功能(例如 std::filesystem )在跨平台实现中的 C++14 中不可用。 这通常意味着使用诸如 asio 网络任务和 a std::filesystem shim 文件系统导航之类的库比创建特定于平台的实现更可取。
文档
要检查代码是否正确记录以及所有文档是否正确链接,您可以运行 AutowareAuto/docs/.doxygen/build.py . 生成的文档可以在 AutowareAuto/docs/_build/html/index.html . 有关更多详细信息,请参阅 文档指南 。
格式化
Autoware.Auto 遵循 ROS 对代码样式和格式的建议。 有关更多信息,请参阅 C++ 的 编码风格和语言版本条目或 Python 的编码风格和语言版本条目。 ament 我们尽可能 使用提供的 linter 来执行这些准则。 所有软件包的文件中都应包含以下内容 package.xml :
< test_depend > ament_lint_auto </ test_depend >
< test_depend > ament_lint_common </ test_depend > |
此外,包中应包含以下内容 CMakeLists.txt (通过其他测试扩展):
如果(构建测试)
find_package(需要ament_lint_auto)
ament_lint_auto_find_test_dependencies()
万一() |
在 CI 中,如果合并请求引入格式不正确的代码,则合并请求会失败。 为避免这种情况,请在本地格式化 C++ 代码
ament_uncrustify --reformat file.cpp # 原地更新单个文件
ament_uncrustify --reformat path/to/pkg_foo # 更新包中的所有 C++ 源文件 |
使用上面的 CMake 设置,运行所有 linter 以及 运行测试 部分中描述的包的所有其他测试,或者运行特定的 linter; 例如,
ament_cpplint 路径/到/pkg_foo
CLion 等工具可以解析前一个命令的输出,并提供快速导航到代码中的违规行。
使用 ament_clang_format
ament_uncrustify --reformat 能够在一定程度上格式化代码,但其结果通常不足以通过 ament_cpplint 。 要自动化该过程, ament_clang_format 可以像这样使用:
ament_cpplint 路径/到/pkg_foo |
配置存储在 .clang-format Autoware.Auto 源检出的基本目录中的文本文件中。
ament_clang_format 默认情况下在 ADE 中可用。 在 ADE 之外工作时,安装它,例如
AutowareAuto $ ament_clang_format --config .clang-format --reformat file.cpp |
使用所有这三个工具的方法如下:
- ament_clang_format --config AutowareAuto/.clang-format --reformat file.cpp
- ament_uncrustify --reformat file.cpp
- ament_cpplint file.cpp
- 修复所有报告的错误
- 重复前面的步骤,直到 ament_uncrustify 不再 ament_cpplint 出现错误。
标题的顺序包括
推荐的 #include 指令顺序基于 google styleguide
- 对应的文件:从 bar.cpp 包 foo 中,就是 #include "foo/bar.hpp"
- C系统头文件; 例如 #include <stdint.h>
- C++ 系统头文件; 例如 #include <vector>
- 此包或其他包的标头; 例如 #include "pkg/baz.hpp"
- 消息头; 例如 #include "foo/msg/bar.hpp"
每个组中的标题按字母顺序排序,组由一个空行分隔。
为了使自动分组和排序工作:
- 用于 #include "foo/bar.hpp" 来自相同包和其他包的标头
- 仅用于 C 和 C++ 系统头文件 #include <vector> 的尖括号
- ament_clang_format 像上面解释的那样 调用。
生成的顺序应该满足 ament_cpplint 。
笔记 如果 cpplint 抱怨标题的顺序,请确保分隔符与上述规则匹配。 示例错误: 在 C++ 系统标头之后找到 C 系统标头。
使用 git 预提交
要在每次提交之前自动 lint 代码,请激活 pre-commit hook 。 从存储库基目录,执行:
cd .git/钩子
ln -s ../../.git-hooks/pre-commit |
代码覆盖率
对于 代码覆盖率 ,我们使用流行的 GNU 工具 lcov 来生成有关行覆盖率的统计信息。 对于每个合并请求,我们运行我们的测试套件并报告覆盖行的百分比。 我们的目标是实现 100% 的线路覆盖率,并不断改进我们的测试套件以实现这一数字。 特别是,我们不接受降低覆盖价值的更改。 如果合并请求的行覆盖率低于 master ,我们将要求贡献者添加更多测试。
可在此处 master 获得最新成功 CI 在分支上 运行的覆盖率报告 。
检查 Coverage 以获取详细信息以手动创建该报告或 测试 以获取更多信息。
C++ 资源
ROS 开发指南
一般来说,Autoware.Auto 遵循 ROS 2 开发人员指南 进行贡献,除非另有说明。 下面列出了 ROS 2 开发人员指南中未描述的一些特殊注意事项。
创建新包
可以 在本教程 中找到创建新 ROS 2 包的基本说明。 在 Autoware.Auto 中,可以使用该 autoware_auto_create_pkg 工具自动生成大部分样板代码。
有关使用该工具的更多信息,请参阅 autoware_auto_create_pkg 。
2层发展模式
除了最琐碎的实用程序之外,最好实现一个具有 至少 两层抽象的代码模式,如下所示:
-
一个“核心”纯 C++ 类,它执行所有与 ROS 无关的基本算法和实用功能。
此类可能使用 ROS 实用程序,例如日志记录或消息结构,但必须说明为什么不能通过类的外部接口完成这种使用(例如,封闭节点使用通过类的外部接口获得的信息来填充日志消息) .
-
继承自 rclcpp::Node 或子类的“ROS 节点”或“ROS 组件”类处理所有 ROS 特定的功能。
这个类应该实例化1.中定义的类,并将节点注册为 组件 ,以便可以使用启动文件创建它。
在极少数需要对执行进行细粒度控制的情况下,使用 ROS 执行器 在单独的文件中创建一个主函数,以某种方式(例如通过调用 spin() )控制节点的执行时间的提供。
这种设计模式有助于促进关注点分离和代码重用。 核心和 ROS 节点可以在单独的包中实现; 例如 foo 和 foo_nodes 。 在一些琐碎的情况下,不需要“核心”的简单 ROS 节点是可以接受的,但这些应该是例外,而不是规则。
在 Autoware.Auto 中命名
命名指南 提供了标准、可靠的 命名和命名空间约定,应在所有 Autoware.Auto 包中使用。
关于主题和参数
在大多数情况下,主题应该在代码中接收默认名称,并在需要时重新映射。 将主题名称作为 ROS 参数提供是一种反模式,几乎没有例外。
必需的参数不应具有默认值,但如果未提供值,则在构造过程中会失败。
参数文件语法
为避免需要根据节点的命名空间或节点名称更改参数文件,请使用“双星”语法。 例如:
上面的参数文件可以传递给任何节点,无论命名空间或名称如何,如果声明的参数与文件中的参数匹配,则参数将填充节点的参数。
ROS 组件
从 ROS Dashing 开始,推荐在 ROS 2 中编写节点的方法是使用组件。 有关组件及其使用的更多信息,请参阅 ROS 组合指南 。 要将您的节点实现为组件,它必须符合以下各项( ListenerNode 用作示例):
- 必须继承自 rclcpp::Node 或子类(例如 rclcpp::LifecycleNode )
- 必须使用以下形式的单参数构造函数:
命名空间组合示例
{
类ListenerNode:公共rclcpp::Node {
ListenerNode( const rclcpp::NodeOptions & 选项)
:节点(“监听器”,选项)
{
...
}
}
} // 命名空间组合示例 |
- 必须在单个翻译单元中包含注册宏和标头。 例如, cpp 文件底部的以下内容就足够了:
// 在翻译单元的底部插入,例如 listener_node.cpp
#include <rclcpp_components/register_node_macro.hpp>
// 注册时使用全名
RCLCPP_COMPONENTS_REGISTER_NODE(composition_example::ListenerNode) |
- 必须将组件编译为共享库并将它们注册到您的 CMakeLists.txt 文件中。
- 必须依赖 rclcpp_components 包。
最小的 CMake 示例
以下是使用推荐的 宏、注册单个组件、构建使用该组件的独立节点并将其导出为下游包的依赖项的最小 CMakeLists.txt 文件。 ament_cmake_auto 它可以通过以下方式方便地创建 autoware_auto_create_pkg :
cmake_minimum_required(版本 3.5)
项目(composition_example)
find_package(ament_cmake_auto 需要)
ament_auto_find_build_dependencies()
ament_auto_add_library(listener_node SHARED src/listener_node.cpp)
autoware_set_compile_options(listener_node)
rclcpp_components_register_nodes(listener_node "composition_example::ListenerNode")
ament_auto_add_executable(listener_node_exe src/listener_main.cpp)
autoware_set_compile_options(listener_node_exe)
如果(构建测试)
find_package(需要ament_lint_auto)
ament_lint_auto_find_test_dependencies()
万一()
ament_auto_package() |
编译器设置
C++ 标准在包中设置 autoware_auto_cmake.cmake 并可供包使用,具体取决于 autoware_auto_cmake 包, package.xml 如下所示。 编译器选项和警告标志也是通过调用中 autoware_set_compile_options(${target}) 定义的函数 autoware_auto_cmake.cmake 为每个目标设置的。 它应该应用于每个 C++ 目标,并且通常 Autoware.Auto 代码不应生成警告。
如果警告标志过于严格,例如在包含外部代码时,可以在特殊情况下选择性地停用它们,如下所示:
autoware_set_compile_options(${target})
target_compile_options(${target} PRIVATE -Wno-double-promotion) |
最小 Package.xml 示例
以下是 package.xml 与上述 CMakeLists.txt 示例一起使用的最小文件:
<? xml 版本= "1.0" ?>
<? xml-model href = "http://download.ros.org/schema/package_format3.xsd" schematypens = "http://www.w3.org/2001/XMLSchema" ?>
<封装 格式= "3" >
<名称> composition_example </名称>
<版本>0.0.1</版本>
< description >节点组成示例 < / description >
<维护者 电子邮件= “ my.email@example.com ” > Autoware 基金会</维护者>
<许可证> Apache 许可证2.0</许可证>
< buildtool_depend > ament_cmake_auto </ buildtool_depend >
< buildtool_depend > autoware_auto_cmake </ buildtool_depend >
<依赖> rclcpp </依赖>
<依赖> rclcpp_components </依赖>
< test_depend > ament_lint_auto </ test_depend >
< test_depend > ament_lint_common </ test_depend >
<导出>
< build_type > ament_cmake </ build_type >
</导出>
</包> |
资源
如何在分叉中开发
使用叉拉
Autoware.Auto 遵循 Git 使用的 fork-and-pull 模型。 这意味着开发人员应该创建 Autoware.Auto 存储库的分支,在该分支上的分支中开发,然后从该分支向中央 Autoware.Auto 存储库发出合并请求(GitLab 术语;GitHub 术语中的拉取请求)。
基本流程由以下步骤组成。
- 如果尚不存在,请在 Autoware.Auto 存储库中创建一个问题以跟踪目标和进度。 有关如何创建问题的更多信息, 请参阅 GitLab 文档。
- 创建 Autoware.Auto 存储库的分支。 Autoware.Auto 存储库被称为 相对于您的 fork的 上游存储库。 为此,您需要一个 GitLab 帐户,但一个免费帐户就足够了。 此分叉最初将仅存储在 GitLab 服务器上。
要进行分叉,请单击 Autoware.Auto“项目概览”屏幕右上角的“分叉”按钮。
- 分叉按钮的位置
- 在本地克隆您的 fork 以创建 本地副本 。
您可以通过单击 fork 的“项目概述”屏幕或“Repository - Files”屏幕中的“Clone”按钮来找到克隆 fork 的 URL 。
-
在您的本地副本中,创建一个新分支来完成您的工作。为该分支指定一个描述性名称。 GitLab 使用该模式 [issuenumber]-[issue-name-with-hyphens] 。 例如,如果您正在为问题 #42“计算最终问题的答案”工作,您可以这样命名您的分支:
-
这将创建一个新分支并将您的本地工作副本放入其中。 需要注意的是, 这个新分支仍然只存储在您的计算机上 。 在创建合并请求之前,必须将其推送到 GitLab 服务器上的 fork副本。
- 在新分支的本地副本中完成您的工作。 请务必注意 有关如何编写代码等 的贡献指南。
- 将更改提交 到本地副本中的分支。
- 现在您已经在本地副本中进行了更改,是时候将它们发送到服务器,您可以从中创建合并请求。 从这一点开始,您需要注意运行命令的位置,以确保您不会意外污染您的历史记录。 如果您的历史记录不干净且不是最新的,则您的合并请求将无法合并。
首先将上游存储库位置添加到本地存储库的设置中作为远程存储库。 您只需要第一次执行此操作。
- 现在上游存储库位置已设置,使用上游存储库的主分支使您的分支保持最新。 $ git结账大师 $ git 获取上游 $ git 合并上游/主
最后一个命令更新 master 本地副本的 master 分支以匹配 Autoware.Auto 存储库的分支。 使用该 git merge 命令执行此操作非常重要。 不要使用该 git rebase 命令 来 master 更新本地副本的分支。 这样做的原因是 你永远不应该对公开的提交进行变基 master ,并且分支中的 所有提交本质上都是公开的。
如果上面的最终命令没有顺利执行,那么您的本地 master 分支副本,或者可能是 master 服务器上 fork 中的分支副本,已经被额外的提交污染了。 有关解决方案,请参阅本文档末尾的故障排除部分。
- master 您本地副本中的分支现在与 Autoware.Auto master 存储库中的分支匹配。 为了确保您的分支将干净地应用于 master Autoware.Auto 存储库上的分支,这是发出合并请求的先决条件,您需要将分支中的最新更改 master 带到包含您工作的分支中。 这是使用 git rebase 命令 完成的。 您将根据 master 分支中的最新提交重新调整您的更改。 $ git checkout 42-calculate-the-answer-to-the-ultimate-question $ git rebase master
- 最后,将您的更改推送到 GitLab 服务器上的 fork副本。
如果这是你第一次推送这个分支,你需要告诉 Git 你的 fork 上的分支(不是 Autoware.Auto 存储库)在哪里。
$ git push --set-upstream origin 42-calculate-the-answer-to-the-ultimate-question |
如果你之前推送过这个分支,那么你不需要设置目标分支,但你需要做一个强制推送。
现在,您在 GitLab 服务器上的 fork 中拥有一份分支副本,其中包含您提议的更改。 如果您准备好将此工作合并到 Autoware.Auto 存储库的 master 分支中,您现在必须创建一个合并请求。
-
创建合并请求以将您的更改合并到主分叉中。
当您 git push 第一次执行上述命令时,GitLab 服务器的结果将包含一个 URL,您可以使用该 URL 从您的分支创建合并请求。
直接创建合并请求的 URL
或者,您可以通过 GitLab 网站创建合并请求。 在 Autoware.Auto 项目页面和 fork 页面上,将有一个按钮用于创建合并请求。
创建合并请求的按钮
如果您的合并请求关闭了您在上述第一步中创建的问题,则其描述应包含“关闭 #<issue_number>”字样。 有关更多详细信息,请参阅 Gitlab 文档 。
如果您的合并请求尚未准备好进行审核 :
- 在合并请求标题的开头添加“WIP:”,它将自动标记为“正在进行中”。
- 当您的合并请求可供审核时,删除“WIP:”。 请参阅下一步,了解如何让维护人员知道它已准备就绪。
- WIP 合并请求无法合并。
当您的合并请求可供审核时:
- 将其分配给 维护者 并 添加“review”标签 。
- 如果您无权更改合并请求上的里程碑或标签,或者不确定谁应该审查您的请求,请 在分配的评论中 提及 维护者 。
在审阅过程中,您可能需要根据审阅者的评论进行额外的更改,因此您必须注意您的合并请求并尽快回复评论。 当您推送更改时,合并请求将自动更新,并且持续集成系统也将运行。 如果这检测到任何问题(例如编译或测试失败),您还必须修复这些问题。
当您需要向分支添加其他更改时(例如,在代码审查期间响应评论),您将需要重复上述 git push -f 步骤。 如果自上次推送后有其他合并请求合并到 master 分支中,您还需要重复合并到 master 和变基步骤。 当它需要并且可以由 GitLab 自动完成时,您的合并请求将提供一个“Rebase”按钮。 单击按钮以执行变基并再次启动 CI 作业。 当由于您提议的更改与分支中的源代码之间的冲突而无法自动执行时 master ,您需要在分支中修复这些冲突,然后才能接受合并请求。
处理来自其他合并请求的更改
有时,您在分支中处理某些内容时,您发现需要包含一些尚未合并但在单独的合并请求中可用的工作。 可以在开发时将这项工作临时包含在您自己的分支中,而不会污染最终构成合并请求的更改历史记录。
请注意,这样做会对您自己的合并请求施加以下限制。
- master 在您依赖的其他合并请求首先合并到 Autoware.Auto 存储库 中之前,您的合并请求无法被审核。 您应该 将引起合并请求的问题标记为被其他相关问题阻止 。
- 在发出合并请求之前,您必须变基并确保历史记录干净,仅包含您的更改。 如果您在发出合并请求之前按照此处的说明重新调整您的分支,那么这应该不是问题。
- 要将来自另一个合并请求的更改包含在您自己的分支中,在将它们合并到 master 分支之前,您需要将该分支放入本地副本并将其合并到您的分支中。
- 在您的本地副本中,从上游存储库中获取最新的。
- $ git 获取
- 更改到您的分支并合并来自您希望使用的合并请求的分支的更改。
- $ git checkout 42-calculate-the-answer-to-the-ultimate-question $ git merge upstream/41-calculate-the-ultimate-question
- 当您依赖 的 分支已经合并并且您的分支准备好合并到 master .
何时执行多个合并请求
有时在开发新功能时,您可能会发现需要修复的错误。 在某些情况下,您可能无法继续开发您的功能,直到错误得到修复。
在这种情况下,正确的做法是首先提交错误报告,然后创建包含修复的新合并请求。 但是,该合并请求的来源 不应该 是您的新功能分支。 您应该为错误修复创建一个新的单独分支,并按照标准流程创建合并请求并将错误修复合并到 master Autoware.Auto 存储库上的分支中。
要在新功能 被合并到 之前 master 使用分支中的错误修复,您可以按照上述步骤 处理来自其他合并请求的更改 。
更新master不起作用时该怎么办
如果将分支的本地副本更新 master 到 Autoware.Auto 存储库的副本( git merge upstream/master 命令)的命令运行不顺利,那么您的本地 master 分支副本,或者可能是 master 服务器上 fork 中的分支副本,已经被额外的提交污染。 您可以通过将更改移动到分支来解决这种情况并让您的本地副本与远程副本保持一致。
从 创建一个新分支 master ,然后重置 master 以匹配上游。
$ git checkout -b my-branch-for-some-new-change
$ git结账大师
$ git reset --hard 上游/主
$ git推送-f |
编写文档
一般的
Autoware.Auto 文档是使用该 doxygen 工具基于用 Markdown 编写的文本文件创建的; 有关详细信息,请参阅 doxygen 中的降价。
渲染
通过首先在本地构建来验证文档构建没有错误并按需要显示:
在此命令的长输出结束时,会显示入口点。 在网络浏览器中打开
文档已内置:/home/user/AutowareAuto/docs/_build/html/index.html |
在 CI
作为合并前的最后检查,通过浏览合并请求的构建作业的 文档 阶段的工件来验证 CI 中构建的文档是否正确。 URL 将类似于以下内容,但必须修改构建作业 ID
https://autowarefoundation.gitlab.io/-/autoware.auto/AutowareAuto/-/jobs/BUILD_JOB_ID/artifacts/docs/_build/html/index.html
要使用鼠标选择文档,首先在 GitLab 上打开合并请求的管道,然后选择文档作业:
选择文档构建作业
最后浏览工件并选择合并请求中修改的 html 文件。
浏览文档工件
降价指南
markdown 中的行通常限制为 100 个字符,不切实际的情况除外; 例如
为了简化代码审查,建议每个句子都从新行开始。 除非包含空行,否则这不会中断段落。
代码片段
启动一个受保护的代码块并 cpp, py, bash, xml 在大括号中添加用于语法突出显示的语言(...); 例如,
```{cpp}
主函数()
{
返回0;
}
``` |
图片
插图和屏幕截图非常适合表达观点,并且可以节省大量文字。 将图像放入 docs/images 文件夹并将其称为
@image html 图片/foo.png "图片说明"
这种包含方式可确保 doxygen 在找不到图像时失败。 或者,可以将输出中图像的宽度设置为绝对或相对大小,以防止大图像干扰阅读流程:
@image html 图片/foo.png “图片标题” 宽度=1000px @image html 图片/foo.png “图片标题” 宽度=50%
集成新文档
为新文档添加锚点; 例如
#新文档
在标题之后并使用锚链接到文档的其他部分。 一个最小的例子:
// 分析输入的一致性。
新文档 {#new-document}
==================
@目录
#第一节
# 第二节 |
在另一个 foo.md 文件中,请参阅新文档:
@ref new-document "查看新文档" |
确保文档由适当的人包含, index.md 以便它出现在所需的位置; 例如,
来自外部的链接
链接到 doxygen 输出中某个部分的文档也需要一个锚点,以使该 URL 在文档更新方面保持稳定。 为此,锚点应该有一个对该部分所在的页面唯一的前缀。
推荐的
内部 document.md :
然后网址是 https://autowarefoundation.gitlab.io/autoware.auto/AutowareAuto/document.html#document-foo
灰心
内部 document.md :
那么 URL 可以是例如 https://autowarefoundation.gitlab.io/autoware.auto/AutowareAuto/document.html#autotoc_md21
请注意 autotoc_md21 URL 末尾的 。 Doxygen 增加一个计数器来自动为没有锚的部分创建 URL。 如果该部分 Foo 被移动或在其他地方添加了另一个部分,则 URL 可能会变得无效。
记录一个包
包装应附有以markdown书写的设计文件; 例如在 pkg_foo/design/pkg_foo-design.md . design/ 如果需要, 可以有多个文件。 设计文档的目的是描述组件的预期行为。 作为不熟悉该组件的用户的入口点,它应该在足够的抽象级别上进行解释。
记录源代码
其他人使用的所有 C++ 代码都应该在头文件中声明,并且应该带有 doxygen 注释,包括类、结构、方法、成员等。
使用祈使句来描述每个实体。 用句号结束每个部分 . 。
例如:
// @param input 输入,假设为 `>= 1.2`。
// \throw A `std::invalid_argument` 如果无效。
显式 类Foo(双输入);
// \return `true` 如果输入有效。
布尔有效()常量; |
代码中的注释
在代码不是不言自明的地方添加注释。 添加注释时,请考虑重命名/重组以使代码不言自明。
不要添加此评论,因为它没有提供有用的信息
Autoware.Auto 中的命名准则
概括
为了便于 Autoware.Auto 堆栈中节点的开发和集成,至少需要提供一套基本的 TF 框架、节点、包、主题和命名空间的命名准则。 这允许开发人员对整个堆栈中其他节点中使用的主题和框架做出合理的假设,而无需梳理那些其他节点的代码。 它还帮助 Autoware.Auto 的首次用户根据主题和框架的名称和在命名空间层次结构中的位置来识别它们的内容。
虽然这些指南不可能涵盖所有命名场景,但它们提供了通用建议和一些具体示例。
包名称
REP-144 [1] 为 Autoware 中的包名称和包定义了 ROS 标准。Auto 必须遵守此标准。
此外,最好 _nodes 为包含多个 ROS 节点的包附加后缀。
TF 框架
跨堆栈使用的高级框架在 本地化设计 文档中定义。 在 ROS 中,该 tf 架构支持单个 tf_prefix ,通常用于支持多个机器人在同一 tf 棵树中运行 [2]。 鉴于 Autoware.Auto 堆栈旨在用于具有多个框架的大型复杂移动机器人,它不太可能用于在同一架构内同时运行的多个机器人。 因此,堆栈不需要支持 tf_prefix 约定 [2]。
命名空间
ROS 允许对主题、参数和节点进行命名空间,这提供了以下好处:
- 同一节点类型的多个实例不会导致命名冲突
- 节点发布的主题可以使用节点的命名空间自动命名空间,从而提供有意义且易于查看的连接
- 避免弄乱根命名空间
- 有助于保持关注点分离
当一个节点在命名空间中运行时,该节点发布的所有主题都被赋予相同的命名空间。 Autoware.Auto 堆栈中的所有节点都必须通过避免在全局命名空间中发布主题等做法来支持命名空间,如 REP-135 [4] 中所述。
节点和主题命名空间指南
建议 Autoware.Auto 堆栈中不提供原始传感器数据的节点根据该节点的功能所属的类别进行命名。 根据个人如何看待给定节点的分类,此列表可能会引起争议,但此列表并非详尽无遗,也不是一成不变的。 一般的经验法则是,命名空间类别应该只包含一个节点实例,该实例在该类别中执行主要功能。 一些推荐的命名空间类别是:
- control
- localization
- navigation
- perception
“通用”或“实用程序”节点应落入与使用它们的上下文相关联的名称空间中。 例如,将对象数据从一帧转换到另一帧的节点并不特定于给定的堆栈函数,但 planning 如果它用于规划架构或 perception 用于感知架构,则应放置在其中。
一般来说,主题应该根据产生它们的节点的功能而不是使用它们的节点(或多个节点)来命名。
特例:传感器和传感器驱动器
由于移动机器人上的每个传感器都必须有自己的框架,该框架必须是全局唯一的,因此对 框架和主题/节点命名空间 tf 使用相同的名称是有意义的。 tf 以下建议适用于 tf 框架名称和主题/节点命名空间。
对于存在多个相同类型传感器的所有传感器,推荐的约定是 <sensor_type>_<direction> 。
如果在机器人上仅使用给定传感器类型的单个实例,则 _<direction> 可以省略。 如果单个节点为多个传感器发布数据,则该节点不需要具有命名空间,但传感器框架和主题名称仍应遵循这些准则。
如果单个节点或驱动程序在任何后处理之前为相同类型的多个传感器提供数据,则建议使用复数形式的传感器类型(例如 lidars , radars 等)。
传感器类型前缀
在上述命名约定中, <sensor_type> 表示传感器类型的通用名称。 该通用名称应与制造商和型号无关,并描述传感器的一般“类型”而不是传感器的功能。 一些例子包括:
- lidar (相对于 velodyne or os-1 )
- radar (相对于 delphi or esr )
- camera (相对于 mako or rgb )
GNSS/GPS/GLONASS/伽利略/北斗
由于 GPS、GLONASS、伽利略和北斗是特定类型的全球定位系统,它们仅代表使用单个卫星星座,而 GNSS 是一个超集,可以包含这些 [3] 的任意组合,因此建议 <sensor_type> 使用 gnss .
方向后缀
在上述命名约定中, <direction> 表示以下一个或多个与身体相关的方向,这些方向是在站在机器人后面、面向机器人前方时确定的(ROS RHR 约定中的 X-forward)。 如果使用多个与身体相关的方向,它们应该用下划线分隔。 ROS RHR约定中推荐多个body-relative方向的顺序为X、Y、Z,以免混淆。
传感器节点命名空间/TF 帧示例
- camera_front_left
- gnss
- imu
- lidar_front
- radar_rear_middle
- ultrasonics (如果聚合来自多个传感器的数据)
传感器数据主题名称
对于以表示完整的、未处理的传感器输出的消息类型发布的数据,推荐的格式是 <data_type>_raw .
对于以表示原始传感器数据的消息类型发布但主题包含原始传感器完整输出的子集的数据,建议使用表单 <data_type>_filtered 。 如果给定数据流存在多个过滤阶段,则在之前应用另一个后缀 _filtered 可以帮助区分阶段输出(例如 <data_type>_downsample_filtered )。
对于以消息类型发布的数据,表示原始传感器数据,但主题包含来自多个相同类型传感器的数据,建议使用表单 <data_type>_fused 。
例子
- camera_rear/image_raw
- gnss/nmea_raw
- imu/imu_raw
- lidar_front/points_filtered
- radars/returns_fused
如何处理节点级别的错误
目标
本文介绍了开发人员应如何在 Autoware.Auto 中处理其节点中的错误。
介绍
Autoware.Auto 目前通过 ROS 2 日志机制使用基本的错误报告。
如果您还不熟悉登录 ROS 2 的概念,请参阅 ROS 2 登录页面 以获取一些示例和演示。
日志记录指南
最佳实践
请遵循这些最佳实践,以确保您的日志消息易于理解。
- 在日志消息中放置足够的运行时上下文(包括关键变量的值)以帮助诊断问题( WARN 和更高级别)。
- 在编写 ERROR 或 FATAL 记录消息时,请记住也要以编程方式处理这种情况。 返回一个有意义的值,抛出一个异常并在某处处理它(如果您的组件中允许异常),或者在节点的生命周期中转换到错误状态。 考虑整个系统以及这种情况可能对您的节点产生什么影响,并设计出适应、退出或修复和恢复的最佳方式。
- 登录循环时(意味着高频自旋循环或 ROS 节点的回调),用于 RCLCPP_[SEVERITY]_THROTTLE 控制记录消息的频率(替换 [SEVERITY] 为 DEBUG 等 INFO )。 这在像记录自我位置这样的情况下很有用,而不是以更新的频率,而是以更人性化的方式(例如,仅每秒)。 如果日志是重复的(例如 WARN ,每次传递相同的消息),请使用 RCLCPP_[SEVERITY]_ONCE 宏。
- 使用日志输出进行自动化测试,检查正常和错误执行。 记录您可以检查以确定行为是否符合预期的值(例如节点计算的结果)。
- 在提交合并请求之前,请检查您的新日志消息或更改的日志消息是否遵循指南。 消除开发新功能时使用的不必要的日志消息。
日志严重性级别指南
- FATAL – 当发生需要终止整个应用程序的故障时使用此日志级别。 FATAL 错误应该只发生在非可选组件中,并且要谨慎使用。 示例:关键硬件的驱动程序无法启动或访问设备。 请注意,组件程序员有时很难确定组件故障如何影响整个应用程序 - 可以在审查后更改日志严重性。
- ERROR – 表示组件存在严重问题,要么阻止它完全工作,从而从系统中删除部分功能,要么禁用某些核心功能。 与 不同 FATAL , ERROR 日志不一定表示整个系统异常停机。 示例:无法记录执行器/传感器数据,无法转换传感器的帧之一。
- WARN – 表示不寻常的事情或不会造成重大伤害的问题。 它还可能告知将来可能会出现更大的问题,例如资源即将耗尽。 警告还可以表示异常延迟、质量下降或组件订阅的已发布数据暂时缺失。 警告可能升级为错误,例如,如果延迟变得不可接受。 WARN 不同之处 INFO 在于它应该被调查。 WARN 日志应该涵盖所有此类情况,但在运行良好的应用程序中很少显示。
- INFO – 通知发生了一些值得注意的(和预期的)事件,例如节点转换到不同的状态、组件的成功启动或重要的服务调用。 尝试限制此级别的日志记录数量,并使其简洁并包含有用的信息。
- DEBUG – 用于更详细的信息,有助于调试。 该 DEBUG 级别的日志输出预计会相当全面。 它通过提高程序流的可见性来帮助发现问题。 自动化测试也应涵盖 输出 DEBUG 和日志级别。 级别日志消息可以在循环中使用,尽管开发人员应在每种情况下考虑它是否会提高或降低日志的可读性。 和 日志宏的变体可用于控制音量。 INFO DEBUG _ONCE _THROTTLE
C++ 日志记录宏
替换 [SEVERITY] 为 DEBUG 等 INFO 。
- RCLCCP_[SEVERITY] - 使用格式字符串进行日志记录的默认宏(也接受单个 std::string 参数)。
- RCLCPP_[SEVERITY]_ONCE – 当您只希望日志被调用一次时使用。 随后的调用将被忽略。 当您希望每次传递都会遇到相同的情况时,这对于警告很有用。
- RCLCPP_[SEVERITY]_EXPRESSION – 在满足条件时记录一条消息(方便跳过 if 子句)。 请注意,如果您想要做的不仅仅是登录条件,仍然需要使用显式 if。
- RCLCPP_[SEVERITY]_FUNCTION – 仅在函数返回 false 时记录消息(对“isOk()”类型的函数有用)。
Eloquent 中的新宏
- RCLCPP_[SEVERITY]_STREAM - 用于使用流 (<<) 方式构建日志的默认宏。 这通常比使用格式字符串更方便。 自 Eloquent ( _STREAM_EXPRESSION , _STREAM_ONCE , _STREAM_FUNCTION ) 以来,所有其他宏都有流变体。
- RCLCPP_[SEVERITY]_THROTTLE - 记录消息,但仅按照指示的频率。 当您关心值如何随时间变化但只需要不太频繁的更新时,对于记录高频循环和回调很有用。
日志记录和自动化测试
使用 本文 所述的启动测试来检查节点是否按预期输出日志消息。 您甚至可以从日志中提取值并根据约束检查它们。
FATAL 或日志 的存在 ERROR 应该无法通过正常测试。 与预期不同的日志的 存在 FATAL 或日志应该无法通过错误处理测试。 ERROR 可以在合并请求的代码审查期间确定日志的存在是否 WARN 也应该使测试失败。
IDE 特定配置
任何 IDE 或文本编辑器都可用于开发 Autoware.Auto。 在这里,可以找到一些配置指令。 CLion
在这里,Autoware.Auto在“~/projects/AutowareAuto”路径 中安装 时没有 ADE 。
使 CLion 能够建立索引的关键功能是使用 Compilation Database 。
启动 CLion
您可以使用 CLion 的默认桌面启动器来启动它。 与 ROS1 CLion 配置不同,它不需要从 ROS 来源的终端运行。
构造型
CLion 中的终端可用于构建 Autoware.Auto。
构造部分 有在这里有用的基本信息。
应遵循 编译数据库构建以生成编译数据库。
为了能够使用 CLion 调试代码,应使用 Debug 或 RelWithDebInfo 标志编译代码。 RelWithDebInfo flag 大部分时间都可以使用,没有问题。
colcon build --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1
colcon build --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1 --packages-up-to <package_name>
colcon build --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1 --packages-select <package_name> |
bash 还可以在文件中设置 一些别名 ~/.bash_aliases 以简化构建过程。
别名 colcon_build_reldeb="colcon build --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1"
别名 colcon_build_reldeb_upto="colcon_build_reldeb --packages-up-to "
别名 colcon_build_reldeb_sel="colcon_build_reldeb --packages-select " |
在 CLion 中打开项目
使用上述命令编译 Autoware.Auto 后,即可将其加载到 CLion 中。
导航到 File | Open 主菜单中,然后选择 compile_commands.json (它将位于 AutowareAuto/build/ 文件夹中)文件并单击 Open as Project。
默认情况下,项目根目录设置为包含编译数据库文件的目录,在我们的例子中,就是 AutowareAuto/build/ 文件夹。
更改项目根目录
要更改项目根目录, Tools | Compilation Database | Change Project Root 请从主菜单中选择,然后 AutowareAuto 从那里选择目录。
现在 CLion 的代码洞察、重构、分析和导航完全可用于项目。
为了完成事情,
- 项目窗格 - >右键单击 install 文件夹并选择 Mark Directory as -> Excluded
- 项目窗格 - >右键单击 src 文件夹并选择 Mark Directory as -> Project Sources and Headers
它应该是这样的:
CLion 首次运行
运行和调试节点
ros2 run package_name executable_name <param1> <param2>... 现在可以调试 任何可以运行的东西。
使用命令运行的节点无法使用以下方法进行调试,尽管 将 Clion Attach to a Process ros2 launch 应该相当简单 。
从 ROS2 Foxy 中的感知/过滤器运行“point_cloud_filter_transform_nodes”的示例:**
通常可以使用以下命令运行此节点:
CLion 中有一些 路径变量 可以很容易地缩短某些地方的一些路径。
这里 $ContentRoot$ 将用于指向项目根目录,即 ~/projects/AutowareAuto .
为了 $ContentRoot$ 工作,请确保将 项目根目录更改 为 AutowareAuto 文件夹。
或者:
- 必须选择 Project 窗格中属于该项目的文件。
- 属于该项目的文件必须打开并处于活动状态。
在积极开展项目时,这些条件大多会在不付出额外努力的情况下得到满足。
为了能够使用 CLion 运行和/或调试此文件,请执行以下操作:
- 呼叫运行 | 从菜单编辑配置或单击 Add Configuration... 右上角附近的构建按钮。
- 单击左上角的加号按钮并选择 Custom Build Application
空自定义构建配置
- 在 Before Launch 列表中,按减号按钮 Build 从列表中删除。
自定义构建应用程序
- 点击 Configure Custom Build Targets
- 单击左上角的加号按钮以添加自定义构建目标。
自定义构建目标
其余部分保持原样,因为这是一个虚拟目标。 然后单击确定。
自定义构建目标完成
- 在 Custom Build Application 屏幕中选择 Custom Build Target 您 Target: 已生成的。
- 可执行文件:( /home/mfc/projects/AutowareAuto/install/point_cloud_filter_transform_nodes/lib/point_cloud_filter_transform_nodes/point_cloud_filter_transform_node_exe 此处需要绝对路径)
- 程序参数: --ros-args -r __ns:=/lidar_front --params-file $ContentRoot$/src/perception/filters/point_cloud_filter_transform_nodes/param/vlp16_sim_lexus_filter_transform.param.yaml -r __node:=filter_transform_vlp16_front -r points_in:=/lidar_front/points_xyzi
- (可选)工作目录: $ContentRoot$/install/
- 环境变量:( source /home/mfc/projects/AutowareAuto/install/setup.bash 此处需要绝对路径)
最后它应该是这样的:
运行/调试配置完成
点击 OK 后,现在应该可以点击 Triangle 或 Bug 按钮来运行或调试应用程序了 :)
为其他节点配置
和 可以修改以使其与任何其他节点一起使用 Executable 。 Program Arguments
格式化代码和文档相关设置
代码风格
- 导航到 File | Settings 主菜单中。
- 在“设置”中,导航到 Editor | Code Style 。
- 硬包装:100
- 视觉指南:100
- 启用 ClangFormat:选中
它应该如下所示:
代码风格
- 在“设置”中,导航到 Editor | Code Style | C/C++ 。
- 在右上角点击 Set from...
- 选择谷歌(虽然大多数会被 ClangFormat 覆盖)
- 转到 Code Generation 选项卡
- 在文档评论下
- 添加@brief 标签:选中
- 行注释中的标记前缀:@param
- 块注释中的标记前缀:@param
它应该如下所示:
代码生成
外部工具
为了使以下命令正常工作,应在当前 ROS2 所在的终端中启动 CLion。
- 导航到 File | Settings 主菜单中。
- 在“设置”中,导航到 Tools | External Tools 。
- 按下 + 按钮添加以下工具:
- 当前_cpplint:
- 姓名: ament_cpplint
- 程序: ament_cpplint
- 论据: $FilePath$
- 工作目录: $ProjectFileDir$
当前_cpplint
- ament_uncrustify:
- 姓名: ament_uncrustify
- 程序: ament_uncrustify
- 论据: --reformat $FilePath$
- 工作目录: $ProjectFileDir$
ament_uncrustify
- 当前_flake8:
- 姓名: ament_flake8
- 程序: ament_flake8
- 论据: $FilePath$
- 工作目录: $ProjectFileDir$
当前_flake8
- 按 OK 保存设置并退出 Settings 窗口。
- File | Settings 在主菜单中 重新打开。
- 在“设置”中,导航到 Keymap 。
- 在 External Tools | External Tools 为这些工具分配热键下。
一旦设置好这些,就可以使用这些热键来自动运行这些工具。 Reformat Code 快捷方式也将在代码上应用 设置 .clang-format 。
有关格式化使用说明的详细信息,请参阅 Contributors Guidelines for Formatting
|