ROS2学习(十五).ROS概念 - 交叉编译

19 篇文章 10 订阅

概述

Open Robotics为多个平台提供了预构建的ROS 2包,但许多开发人员仍需要依赖交叉编译1,原因如下:

  • 开发机与目标系统不一致。
  • 为特定的核心架构调优构建(例如,在为Raspberry Pi3构建时设置-mcpu=cortex-a53 -mfpu=neon-fp-armv8)。
  • 希望运行于不同于Open Robotics发布的预构建镜像所支持的文件系统上的应用。

它是如何工作的?

交叉编译简单软件(例如,不依赖外部库的软件),只需要使用交叉编译器工具链替代本地工具链即可。

交叉编译的复杂性往往由以下因素带来:

  • 构建的软件系统是基于目标架构的。在构建过程中,必须根据目标体系结构正确地隔离和启用依赖特定体系结构的代码。 典型的例子是汇编代码。
  • 所有依赖项(通常是各种库)必须存在,通常以以下两种方式予以支持:
    • 作为预构建包
    • 使依赖项的库在目标软件之前被交叉编译
  • 当使用构建工具(如colcon)构建software stacks(相对于独立软件的概念)时,构建工具应该提供一种机制,以保证开发者在stacks中的每个软件构建时使用的相同的底层构建系统进行交叉编译。

交叉编译ROS 2

ROS 2交叉编译工具由Open Robotics和ROS Tooling Working Group所共有。
它是一个Python脚本,使用docker容器中的模拟器为受支持的目标架构编译ROS 2源文件。
该工具的详细设计可在ROS 2 design2中找到。 使用该工具的说明在cross_compile包中。

如果您使用的是旧版本,请遵循交叉编译指南

ROS 2包的交叉编译工具设计

接下来我们看一下设置和管理用于交叉编译的sysroot环境的ROS 2工具的方案。
本方案的目标是简单和可扩展。
我们可以使用colcon mixins扩展支持新的交叉编译配置。

背景

ROS的交叉编译指南esteve/ros2_raspbian_tools库中说明了如何使用CMake和Docker镜像的工具链将ROS 2交叉编译未受官方支持的架构,如ARM64和ARM-HF。
esteve/ros2_objcesteve/ros2_java也提供对Android和iOS等其他平台的支持。
理想情况下,我们应该能够通过单个命令来交叉编译用于ROS 2的ROS包。该命令还应该具备良好的可扩展性以便于支持新平台。该设计方案是对ARM-HF和ARM64架构的一级支持的推动。

设计思路

我们将继续使用交叉编译教程的一般方法。这涉及到为目标平台构建一个sysroot,使用QEMU和Docker,然后在colcon mixins中使用C和C++交叉编译器进行编译。

我们将在交叉编译教程中添加一组命令来进行二次封装。这些命令将为目标平台使用一个新的workspace目录,并基于以下关键字确定:

  • 目标平台
  • 操作系统
  • RMW实现
  • ROS发行版

我们称此工作区目录称为cc-root。平台意味着体系结构,但是像generic_armhf这样的通用平台也属于此语境范畴。平台标识符的例子如:generic_armhf-ubuntu_bionic-fastrtps-crystalturtlebot_armhf-ubuntu_bionic-fastrtps-dashing。我们将添加以下命令:

  • 一个新的create-cc-sysroot命令,将使用Docker为目标平台生成sysroot,并将其存储在cc-root的sysroot子目录中。这个命令将接受参数来指定目标平台,例如:
create-cc-sysroot --arch generic_armhf --os ubuntu_bionic \
                  --rmw fastrtps --rosdistro crystal
  • 每个已知平台的一个新的colcon mixin,它向colcon构建任务中添加了使用由create-cc-sysroot生成的sysroot的选项,使用相同的路径约定。
    例如,在开发者工作站上的ROS 2覆盖workspace中执行以下命令,可以将交叉编译工作区中的包编译至performance_test包。这将在cc-root generic_armhf-ubuntu_bionic-fastrtps-crystalbuildinstalllog子目录下交叉编译生成相应的二进制文件。
colcon build --mixin cc-generic_armhf-ubuntu_bionic-fastrtps-crystal \
  --packages-up-to performance_test # any other other `colcon build` arguments
  • 此外:
    • 维护一个用于交叉编译的docker镜像,它同时安装了交叉编译工具链和前面提到的colcon mixins。
    • 实现一个新的cc-build命令,确保使用create-cc-sysroot创建了sysroot,然后在Docker容器中启动交叉编译相应的Docker镜像。

create-cc-sysroot命令将暗自执行以下操作:

  1. 下载目标平台的基本ROS 2 Docker镜像。
  2. 通过使用一个从基础镜像开始的Dockerfile来构建一个依赖于工作区的sysroot镜像,并且:
    1. 运行COPY以将工作区的内容获取到容器中。
    2. 使用rosdep确保workspace的系统依赖项没有丢失。注意,由于使用了QEMU,我们可以在Docker中为ARM-HF架构运行rosdep
  3. 启动该镜像的容器,并将其文件系统导出到cc-root的sysroot子目录中。
  4. 在构建过程中,colcon mixin使用CMAKE_TOOLCHAIN_FILE参数指向工具链文件(例如generic_linux.cmake),从而为交叉编译设置适当的CMake参数。

ROS 2基本镜像是使用Docker官方镜像的ros2/cross_compile中的sysroot/Dockerfile_ubuntu_arm的变体。
OSRF将发布带有预构建ROS 2的基本ROS 2镜像,这用于交叉编译用户包。
OSRF还将发布其他基本ROS 2镜像,并预装用于构建ROS 2的系统设置和基本工具,这些工具应该用于从源构建ROS 2。

create-cc-sysroot命令也支持以下可选参数:

  • --sysroot-base-image:指定一个Docker镜像作为依赖于工作空间的sysroot镜像的基础镜像。所指定的参数可作为docker image pull的有效参数,并在FROM Dockerfile 语句中使用。如果没有指定,该命令将从目标平台推断--sysroot-base-image的值,并从Docker的官方ROS镜像arm64v8 Dockerhub repoarm32v7 Dockerhub repo上发布的镜像中进行拉取。
  • --sysroot-image:指定工作空间的sysroot的Docker镜像。构建将从该镜像中导出sysroot,而不是从工作区创建sysroot镜像。开发者需自行保证workspace的包所需的所有依赖项都被包含在镜像中。
  • --use-base-image-sysroot: Boolean标志,当为true时,将使用base ROS 2 Docker镜像构建sysroot,此时工作区包中声明的依赖项将被忽略。在没有额外依赖的情况下,该选项可以加速包的构建。

通过创建相应的ROS 2 Docker镜像以及工具链文件的变体,我们可以添加对其他平台的支持。我们在Ubuntu Bionic的ROS 2 crystal和fastrtps版本上,首次添加了对ARM-HF和ARM64的通用版本的支持。

常见问题

  • 我们如何运行生成的二进制文件?

打包生成的二进制文件不在本文档的描述范围内。
满足以下条件后,交叉编译的二进制文件将在cc-root的工作区中可用(如generic_armhf-ubuntu_bionic-fastrtps-crystal):

  • 将包含src在内的整个工作区复制到远程设备
  • 在目标平台上运行rosdep以在运行二进制文件前安装ROS相关依赖项。

维护和测试

为了支持新平台的交叉编译,我们需要:

  • 为新平台准备并发布一个基本的ROS 2 Docker镜像,使用rosdep install获取ROS 2源代码所需的依赖项。如果该平台存在预构建的二进制文件,我们也可以从二进制文件中获取依赖项。
  • 为新平台调整工具链文件。ruslo/polly库中提供了大量的交叉编译可用的CMake工具链文件和脚本。
  • cross-compile库添加新平台的colcon mixin,并根据工具链文件进行相应的修改。

我们可以通过如下方法测试新平台的交叉编译支持情况:

  1. 构建基本ROS 2 Docker镜像。
  2. 使用create-cc-sysroot为一些参考包(例如ApexAI/performance_test)构建一个自定义的sysroot映像,并将其文件系统导出至sysroot中。
  3. 使用该sysroot交叉编译该包。
  4. 为sysroot镜像启动一个Docker容器,并使用交叉编译的二进制文件运行colcon test。该容器将与工作区的bind mount一起启动,这样它们就可以访问已编译的二进制文件。

为了简化针对新架构-操作系统组合的基础ROS 2 Docker镜像的开发,在未来的迭代中,我们可能会添加一个新的命令build-sysroot-base-image,功能如下:

  1. 将所需的QEMU文件和ROS 2源文件复制到临时位置。
  2. 从指定的Dockerfile构建一个Docker镜像,并访问上述资源。
  3. 【可选】将镜像发布到Docker注册表中,并命名为与平台标识符相匹配的名称。

与该命令兼容的Dockerfiles将保留在ros2/cross_compile中。如果需要,我们可以在CI/CD管道中使用它们。

该方案的优点

本方案带来了简便的开发体验,其中:

  • 交叉编译由两个简单命令触发
  • 在二次迭代编译中,仅需由一个cc-build命令触发
    此外,本方案具有可扩展性,可以轻松支持新的平台。
    对于带有附加依赖项的简单包,开发者仅需使用现成的基础Docker镜像,而无需使用Docker在本地构建sysroot。对于具有自定义依赖项的包,可以在通过binfmt_misc方式使用QEMU的Docker映像上执行rosdep install的方式来扩展基本的sysroot应用。

局限性和开放性问题

这个方案主要解决的是基于Linux平台的交叉编译。由于我们无法使用Apt安装Visual Studio编译器,因此我们也无法在Windows上进行交叉编译。
所以,在Windows或Mac开发环境上,我们只能通过在容器的方式运行本工具。当然,受限于虚拟化层,性能多少会有所下降。

我们应该为每个平台确定一个构建和发布基本ROS 2 Docker映像的过程。 理想情况下,为master发布从源代码构建的镜像应该是无感的,但根据可用资源的不同,这可能很难实现的。

其他方法

可以使用colcon bundle插件将ROS工作区及其所有依赖打包成一个tarball。通过启动目标平台的Docker容器,构建并打包工作空间,并导出bundle,可以将其部署到目标硬件,从而交叉编译ROS 2的工作空间。 这种方法的主要缺点是在Docker映像中使用默认的ARM编译器会显著降低编译速度,这可能会给日常开发带来负担。通过安装qemu-user-static,我们安装了QEMU二进制文件来模拟ARM32/64处理器,而且还在本地机器中注册了binfmt_misc的钩子。这意味着每次程序启动时,如果是它希望运行在QEMU支持的平台上,则二进制文件将自动通过QEMU运行。实际上,它允许您在X86实例上直接运行ARM二进制文件,这个工作是在构建基本镜像时通过Docker隐式完成的。由于QEMU模拟器比正常的执行慢10倍以上,通过此方案我们将QEMU的使用限制在构建基本镜像阶段,在其余时间在本机上使用用于目标平台的交叉编译器。
colcon bundle方法需要在colcon bundle中添加对ROS 2的支持,而后者目前不支持Ament。 这将提供一种分发交叉编译的系统依赖项的方法,由于rosdep install 在资源受限的硬件上会花费很多时间,并且需要Internet连接,因此本方法提供了极大的便利性。 目前的方案和colcon bundle是互补方案,若colcon bundle最终支持ROS 2,我们就可以使用cc-build轻松地完成交叉编译,最小化Docker的使用,然后使用colcon bundle来生成可部署的工件。

对于依赖于工作空间的sysroot映像,我们可以通过不构建工作空间的sysroot映像来避免该工作空间的Docker COPY,我们只需为基础ROS 2镜像启动一个容器,并bind mount该工作空间。 容器的入口点将在挂载工作空间的目录上启动rosdep,然后我们就可以通过docker container export导出容器的文件系统。这避免了COPY,但缺点是我们的工作空间就不会有sysroot映像,而且每次启动容器时都必须在该镜像的入口点上运行rosdep。该镜像对于运行测试非常有用,而最终的cc-test命令可以进一步简化使用该镜像的操作。

最后,与交叉编译教程中的原始方案相比,本方案基本上在cross_compile/entry_point.sh中对上述教程所使用的命令进行了重新组织,这样就可以用简单的一行命令对工作区进行交叉编译工作区。 因此,本方案是上述教程的演进。

参考3


  1. 交叉编译 ↩︎

  2. Cross-compiling ROS 2 packages ↩︎

  3. ROS 2交叉编译 ↩︎

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值