亚马逊AWS官方博客
为 AWS RoboMaker 准备 ROS 应用程序和模拟容器
背景
使用 colcon 在容器映像中构建 ROS 应用程序
过去,为了将应用程序带入 RoboMaker 模拟作业,客户需要使用 colcon 来构建他们的 ROS 工作区,然后使用 colcon bundle 来创建包含依赖项的单文件构件。可以在任何地方复制、提取和执行该文件,包括在 AWS RoboMaker 中。但是,colcon bundle 工具专门用于使用 rosdep 或 pip 安装依赖项。因此,在这些软件包管理工具之外安装或配置的任何依赖项都将被忽略。
在下面的演练中,我们将继续使用 colcon 构建 ROS 应用程序工作区,使用 rosdep 安装应用程序依赖项。但是,我们将创建可扩展以支持所需的任何其他软件包和配置的 Docker 映像,而不是生成捆绑包。
有关使用 colcon 构建 ROS 应用程序的更多信息
ROS 开发人员通常从工作区开始,工作区是一个开发人员可以在其中修改、构建和安装 ROS 软件包的文件夹。ROS 软件包中包含库、数据集、配置文件,以及构成有用软件模块的任何其他内容。使用 colcon 时,ROS1 和 ROS2 工作区通常都具有以下结构:
- 源:存储任何 ROS 软件包源代码的目录。这是克隆和存储版本控制系统(即 Git)的代码的地方。
- 构建:暂存要安装的所有已构建文件的目录。
- 安装:存储暂存要安装的已构建工作区的目录。此目录包含一个 setup.sh/setup.bash 文件,该文件用于在应用程序运行之前为其提供源代码。
- 日志:此目录存储所有构建日志,用于对构建过程进行故障排查。
当您首次在工作区中运行 colcon build 时,它将在上述目录结构中创建并填充构建、安装和日志文件夹。在构建过程中,colcon 将在工作区中爬行并查找 ROS 包。ROS 包是通过每个包目录中的清单文件(package.xml)来标识和定义的。如果 ROS 包使用 CMake,colcon 将按照随附的 CMakeLists.txt 中的说明构建和安装应用程序。
ROS 开发人员通常还使用 rosdep,这是一种依赖项管理工具,可在工作区中爬行并安装每个清单(package.xml)文件中定义的依赖项。大多数 ROS 包的构建和安装说明最终是在以下五个步骤的基础上略微有所变化:
- mkdir -p my_workspace/src && cd my_workspace(创建新工作区)
- git clone <path-to-ros-package-src> src/<my-ros-package>(克隆正在开发的 ROS 包)
- rosdep 更新(更新 ROS deps 中的依赖项来源列表)
- rosdep install –from-paths src -i -r -y(爬行 ROS 工作区,并在主机上安装任何必需的依赖项)
- colcon build –install-base <path-to-some-install-directory>(构建并安装 ROS 包)
演练
在这部分中,我们将展示如何将 ROS 应用程序构建并打包到可以在 AWS RoboMaker 中运行的容器映像中,而不是使用捆绑包(tar)文件。在此演练中,您将:
- 克隆 Hello World 示例应用程序。注意:也可以使用您的 ROS 应用程序工作区。
- 使用入口点脚本创建标准 Dockerfile。
- 构建两个 Docker 映像。HelloWorld 示例应用程序、机器人应用程序和模拟应用程序中的每个工作区一个。
- 将 Docker 映像发布到云中的容器注册表 Amazon ECR。
- 在 AWS RoboMaker 中创建引用您的 Docker 映像的模拟应用程序和机器人应用程序。
- 创建一个有权从 Amazon ECR 提取 Docker 映像的 IAM 角色。
- 启动在 AWS RoboMaker 中运行的 Hello World 模拟并与之互动。
先决条件
要运行以下示例,您需要在计算机上安装 Docker、AWS CLI 和 VCS 工具。
- 安装 AWS CLI:https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- 安装 Docker:https://docs.docker.com/get-docker/
- 安装 VCS 导入工具(如果使用):
sudo pip3 install vcstool
您还需要一个具有以下权限的 IAM 用户或角色的 AWS 账户:
- 创建 IAM 角色
- 创建 RoboMaker 资源(模拟作业、机器人应用程序和模拟应用程序)
- 创建并上传 Amazon ECR 存储库
最后,您需要知道自己的账号,并选择要在其中运行模拟的区域。此处列出的以下区域支持 AWS RoboMaker。
在 ROS 工作区中为 AWS RoboMaker 构建 docker 映像
- 克隆 hello World 存储库。
注意:在 AWS 机器人示例应用程序中,代码已经使用 ROS 工作区目录进行了结构化设置。因此,您无需创建工作区和源代码目录。但是,对于大多数开源 ROS 包以及您的代码而言,请先创建工作区目录,然后将源代码克隆到 <workspace>/src 中。git clone https://github.com/aws-robotics/aws-robomaker-sample-application-helloworld.git helloworld && cd helloworld
- 使用 vcs import 将
.rosinstall
中定义的依赖项导入到每个源目录中。vcs import robot_ws < robot_ws/.rosinstall vcs import simulation_ws < simulation_ws/.rosinstall
- 在
helloworld
目录中创建一个名为Dockerfile
的新文件,然后将以下内容复制/粘贴到新文件中:
注意:首先,我们提供了以下可用于 ROS 工作区的示例Dockerfile
。如果您使用自己的 ROS 工作区,可以按照自己的说明修改此文件。在构建 Docker 映像时,需要了解一些有用的术语和技巧。首先,Dockerfile 是用于构建 Docker 映像的指令集。这种方法将多阶段构建和集成缓存与 Docker BuildKit 结合使用。多阶段构建允许工作流采用单独的构建步骤,因此构建依赖项和源代码不会复制到运行时映像中。这减小了 Docker 映像的大小并提高了性能。缓存操作通过存储以前构建的文件可以加快未来的构建速度。要了解有关 Docker BuildKit 的更多信息,请单击此处。通读Dockerfile
中的评论,了解正在构建的内容,并在必要时进行调整。为了便于开发,Dockerfile
基于开源机器人基金会(OSRF)维护的官方 ROS Docker 映像。但是,在生产环境中运行时,您可以选择使用 GitHub 中的 OSRF 源指令集构建 ROS 基础映像,以防止受到上游更改的影响。# ======== ROS/Colcon Dockerfile ======== # 此示例 Dockerfile 将为 AWS RoboMaker 构建 Docker 映像 # 在所有依赖项都由 rosdep 管理的任何 ROS 工作区中。 # # 调整下面的文件以包含 rosdep 之外的其他依赖项/配置。 # ======================================= # ==== 参数 ==== # 重写以下参数以匹配您的应用程序配置。 # =================== # ROS 发行版(例如:melodic、foxy 等) ARG ROS_DISTRO=melodic # 应用程序名称(例如:helloworld) ARG APP_NAME=robomaker_app # 主机上工作区目录的路径(例如:./robot_ws) ARG LOCAL_WS_DIR=workspace # 要创建和使用的用户(默认:robomaker) ARG USERNAME=robomaker # 如果适用,要使用的 gazebo 版本(例如:gazebo-9、gazebo-11) ARG GAZEBO_VERSION=gazebo-9 # 在运行时映像中存储构建的应用程序的位置。 ARG IMAGE_WS_DIR=/home/$USERNAME/workspace # ======= ROS 构建阶段 ======== # ${ROS_DISTRO}-ros-base # -> ros-robomaker-base # -> ros-robomaker-application-base # -> ros-robomaker-build-stage # -> ros-robomaker-app-runtime-image # ================================== # ==== ROS 基本映像 ============ # 如果在生产环境中运行,您可以选择构建 ROS 基础映像 # 来自源指令集,以防止上游更改的影响。 # ARG UBUNTU_DISTRO=focal # FROM public.ecr.aws/lts/ubuntu:${UBUNTU_DISTRO} as ros-base # 可在以下位置找到 OSRF 维护的每个 ROS 版本的说明:https://github.com/osrf/docker_images # ================================== # ==== 使用 AWS RoboMaker 依赖项构建阶段 ==== # 此阶段创建 robomaker 用户,并安装在 RoboMaker 中运行应用程序所需的依赖项。 # ================================== FROM public.ecr.aws/docker/library/ros:${ROS_DISTRO}-ros-base AS ros-robomaker-base ARG USERNAME ARG IMAGE_WS_DIR RUN apt-get clean RUN apt-get update && apt-get install -y \ lsb \ unzip \ wget \ curl \ xterm \ python3-colcon-common-extensions \ devilspie \ xfce4-terminal RUN groupadd $USERNAME && \ useradd -ms /bin/bash -g $USERNAME $USERNAME && \ sh -c 'echo "$USERNAME ALL=(root) NOPASSWD:ALL" >> /etc/sudoers' USER $USERNAME WORKDIR /home/$USERNAME RUN mkdir -p $IMAGE_WS_DIR # ==== ROS 应用程序库 ==== # 这部分为您的 ROS 应用程序安装 exec 依赖项。 # 注意:请确保在 package.xml 文件中正确定义了“exec”和“build”依赖项。 # ======================================== FROM ros-robomaker-base as ros-robomaker-application-base ARG LOCAL_WS_DIR ARG IMAGE_WS_DIR ARG ROS_DISTRO ARG USERNAME WORKDIR $IMAGE_WS_DIR COPY --chown=$USERNAME:$USERNAME $LOCAL_WS_DIR/src $IMAGE_WS_DIR/src RUN sudo apt update && \ rosdep update && \ rosdep fix-permissions # 注意:这将安装所有依赖项。 # 您可以通过只定义 exec 依赖项来进一步优化这一点。 # 然后,在构建映像中安装构建依赖项。 RUN rosdep install --from-paths src --ignore-src -r -y # ==== ROS 工作区构建阶段 ==== # 在此阶段,我们将安装复本源文件,安装构建依赖项并运行构建。 # =================================== FROM ros-robomaker-application-base AS ros-robomaker-build-stage LABEL build_step="${APP_NAME}Workspace_Build" ARG APP_NAME ARG LOCAL_WS_DIR ARG IMAGE_WS_DIR RUN . /opt/ros/$ROS_DISTRO/setup.sh && \ colcon build \ --install-base $IMAGE_WS_DIR/$APP_NAME # ==== ROS 机器人运行时图像 ==== # 在最后阶段,我们会将分阶段安装目录复制到运行时映像中。 # ================================= FROM ros-robomaker-application-base AS ros-robomaker-app-runtime-image ARG APP_NAME ARG USERNAME ARG GAZEBO_VERSION ENV USERNAME=$USERNAME ENV APP_NAME=$APP_NAME ENV GAZEBO_VERSION=$GAZEBO_VERSION RUN rm -rf $IMAGE_WS_DIR/src COPY --from=ros-robomaker-build-stage $IMAGE_WS_DIR/$APP_NAME $IMAGE_WS_DIR/$APP_NAME # 将应用程序源文件添加到入口点。 WORKDIR / COPY entrypoint.sh /entrypoint.sh RUN sudo chmod +x /entrypoint.sh && \ sudo chown -R $USERNAME /entrypoint.sh && \ sudo chown -R $USERNAME $IMAGE_WS_DIR/$APP_NAME ENTRYPOINT ["/entrypoint.sh"]
- 创建一个名为
entrypoint.sh
的新文件。
注意:ENTRYPOINT
文件是一种可执行文件,它将在爬行 docker 容器时运行。我们正在使用入口点追溯 ROS 工作区,因此我们可以轻松地在 AWS RoboMaker 中运行roslaunch
命令。 - 将以下内容复制/粘贴到新文件中
#!/bin/bash set -e source "/home/$USERNAME/workspace/$APP_NAME/setup.bash" if [[ -f "/usr/share/$GAZEBO_VERSION/setup.sh" ]] then source /usr/share/$GAZEBO_VERSION/setup.sh fi printenv exec "${@:1}"
- 现在,运行以下命令来构建机器人应用程序容器映像:
DOCKER_BUILDKIT=1 docker build . \ --build-arg ROS_DISTRO=melodic \ --build-arg LOCAL_WS_DIR=./robot_ws \ --build-arg APP_NAME=helloworld-robot-app \ -t robomaker-helloworld-robot-app
- 然后,要构建模拟应用程序,请运行以下命令:
DOCKER_BUILDKIT=1 docker build . \ --build-arg GAZEBO_VERSION=gazebo-9 \ --build-arg ROS_DISTRO=melodic \ --build-arg LOCAL_WS_DIR=./simulation_ws \ --build-arg APP_NAME=helloworld-sim-app \ -t robomaker-helloworld-sim-app
- 运行命令
docker images
以确认已成功构建 docker 映像。输出应该是:Administrator:~/environment/helloworld (ros1) $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE robomaker-helloworld-sim-app latest 5cb08816b6b3 17 minutes ago 2.8GB robomaker-helloworld-robot-app latest b5f6f755feec 2 hours ago 2.79GB
祝贺您! 您已成功构建 Docker 映像,现在可以在 AWS RoboMaker 中上传和运行这些映像了。
注意:要在您自己的 ROS 应用程序中使用此方法,请运行上述相同流程,并更改构建参数以匹配您的应用程序:
# 使用您自己的 ROS 工作区进行构建的替代/备选方法
DOCKER_BUILDKIT=1 docker build . \
--build-arg GAZEBO_VERSION=<YOUR GAZEBO VERSION> \
--build-arg ROS_DISTRO=<YOUR ROS DISTRO> \
--build-arg LOCAL_WS_DIR=<PATH TO YOUR WORKSPACE> \
--build-arg APP_NAME=<YOUR APPLICATION NAME> \
-t <YOUR APPLICATION TAG NAME>
将 docker 映像发布到 Amazon ECR
AWS RoboMaker 在模拟作业中使用的容器必须存储在 Amazon Elastic Container Registry(ECR)中,这是一个完全托管式容器注册表。按以下步骤上传您的容器映像:
- 设置一些环境变量,这些变量可以在下一组命令中重复使用。 记得将
<您的 AWS 账号>
和<您的 AWS 区域>
替换为您的账号和区域export robotapp=robomaker-helloworld-robot-app export simapp=robomaker-helloworld-sim-app export account=<YOUR AWS ACCOUNT NUMBER> export region=<YOUR AWS REGION> export ecruri=$account.dkr.ecr.$region.amazonaws.com
- 登录 Amazon ECR 并创建两个新存储库。
aws ecr get-login-password --region $region | docker login --username AWS --password-stdin $ecruri aws ecr create-repository --repository-name $robotapp aws ecr create-repository --repository-name $simapp
- 使用 Amazon ECR URI 标记 Docker 映像。
docker tag $robotapp $ecruri/$robotapp:latest docker tag $simapp $ecruri/$simapp:latest
- 将 Docker 映像上传到 Amazon ECR。
docker push $ecruri/$robotapp docker push $ecruri/$simapp
- 运行以下 describe 语句,以确保您的映像已上传到 ECR。
aws ecr list-images --repository-name $simapp aws ecr list-images --repository-name $robotapp
预期输出:
Administrator:~/environment/helloworld (ros1) $ aws ecr list-images --repository-name $simapp { "imageIds": [ { "imageDigest": "sha256:28cad40230402343024kf303f30fk20f2f2fa0a8148", "imageTag": "latest" } ] } Administrator:~/environment/helloworld (ros1) $ aws ecr list-images --repository-name $robotapp { "imageIds": [ { "imageDigest": "sha256:28cad40230402343024kf303f30fk20f2f2fa0a8148", "imageTag": "latest" } ] }
祝贺您! 您现在已将基于 ROS 的机器人和模拟 docker 映像推送到 Amazon ECR。
在 AWS RoboMaker 中使用容器创建和运行机器人应用程序和模拟应用程序
在最后的步骤中,我们将创建一个新的引用 Amazon ECR 中相应 Docker 映像的 AWS RoboMaker 模拟应用程序和机器人应用程序。确保在 shell 会话中仍然设置了上述环境变量。
注意:您也可以按照向导在 AWS 管理控制台中运行以下步骤。这样,将自动为您创建资源,例如下面的 IAM 角色。这篇博客概述了此工作流的类似示例。
-
- 创建机器人应用程序。对于每条命令,保存返回的 ARN,以便在最后一步中使用。
aws robomaker create-robot-application \ --name $robotapp \ --robot-software-suite name=General \ --environment uri=$ecruri/$robotapp:latest
- 创建模拟应用程序。
aws robomaker create-simulation-application \ --name $simapp \ --simulation-software-suite name=SimulationRuntime \ --robot-software-suite name=General \ --environment uri=$ecruri/$simapp:latest
- 创建一个名为
HelloWorldTrustPolicy.json
的新文件,然后将以下 JSON 复制/粘贴到该文件中:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "robomaker.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
- 创建一个名为
HelloWorldPolicy.json
的新文件,然后将以下 IAM 策略 JSON 复制/粘贴到该文件中。 记得将<ACCOUNT_ID>
和<REGION>
替换为您的账号和区域{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": "arn:aws:logs:<REGION>:<ACCOUNT_ID>:log-group:/aws/robomaker/SimulationJobs*" }, { "Effect": "Allow", "Action": [ "ecr:BatchGetImage", "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer" ], "Resource": [ "arn:aws:ecr:<REGION>:<ACCOUNT_ID>:repository/robomaker-helloworld-robot-app", "arn:aws:ecr:<REGION>:<ACCOUNT_ID>:repository/robomaker-helloworld-sim-app" ] }, { "Effect": "Allow", "Action": [ "ecr-public:GetAuthorizationToken", "ecr:GetAuthorizationToken" ], "Resource": "*" } ] }
- 使用上述策略创建一个新的 IAM 角色,并保存输出中的 IAM 角色 ARN 以供下一步使用。
aws iam create-role --role-name RoboMaker-HelloWorld-Role --assume-role-policy-document file://HelloWorldTrustPolicy.json aws iam put-role-policy --role-name RoboMaker-HelloWorld-Role --policy-name RoboMaker-HelloWorld-InlinePolicy --policy-document file://HelloWorldPolicy.json
- 创建一个名为
create_simulation_job.json
的新文件,然后将以下 JSON 复制/粘贴到该文件中。将 <IAM-ROLE-ARN>、<YOUR-ROBOT-APP-ARN> 和 <YOUR-SIM-APP-ARN> 替换为上述命令的输出{ "maxJobDurationInSeconds": 3600, "iamRole": "<IAM-ROLE-ARN>", "robotApplications": [ { "application": "<YOUR-ROBOT-APP-ARN>", "applicationVersion": "$LATEST", "launchConfig": { "environmentVariables": { "ROS_IP": "ROBOMAKER_ROBOT_APP_IP", "ROS_MASTER_URI": "http://ROBOMAKER_ROBOT_APP_IP:11311", "GAZEBO_MASTER_URI": "http://ROBOMAKER_SIM_APP_IP:11345" }, "streamUI": false, "command": [ "roslaunch", "hello_world_robot", "rotate.launch" ] }, "tools": [ { "streamUI": true, "name": "robot-terminal", "command": "/entrypoint.sh && xfce4-terminal", "streamOutputToCloudWatch": true, "exitBehavior": "RESTART" } ] } ], "simulationApplications": [ { "application": "<YOUR-SIM-APP-ARN>", "launchConfig": { "environmentVariables": { "ROS_IP": "ROBOMAKER_SIM_APP_IP", "ROS_MASTER_URI": "http://ROBOMAKER_ROBOT_APP_IP:11311", "GAZEBO_MASTER_URI": "http://ROBOMAKER_SIM_APP_IP:11345", "TURTLEBOT3_MODEL":"waffle_pi" }, "streamUI": true, "command": [ "roslaunch", "hello_world_simulation", "empty_world.launch" ] }, "tools": [ { "streamUI": true, "name": "gzclient", "command": "/entrypoint.sh && gzclient", "streamOutputToCloudWatch": true, "exitBehavior": "RESTART" } ] } ] }
- 运行以下 AWS CLI 命令以开始模拟
aws robomaker create-simulation-job --cli-input-json file://create_simulation_job.json
- 打开 AWS RoboMaker 控制台。在 Simulation run(模拟运行)下,单击 Simulation jobs(模拟作业)。
- 您应该看到正在准备或正在运行模拟作业。单击模拟作业。
- 最后,单击 gzclient 上的 Connect(连接),以查看模拟是否正在运行。
- 单击 Actions(操作),然后在完成后,单击 Cancel(取消)以停止模拟作业。
- 创建机器人应用程序。对于每条命令,保存返回的 ARN,以便在最后一步中使用。
祝贺您! 现在,您可以构建 ROS 应用程序,将这些应用程序打包到 Docker 容器中,然后使用 AWS RoboMaker 运行它们。
清理
完成后,您可以使用以下命令移除您创建的资源:
aws ecr delete-repository --repository-name $ecruri/$simapp
aws ecr delete-repository --repository-name $ecruri/$robotapp
aws robomaker delete-robot-application --application <ROBOT_APPLICATION_ARN>
aws robomaker delete-simulation-application --application <SIMULATION_APPLICATION_ARN>
aws iam delete-role --role-name RoboMaker-HelloWorld-Role
小结
通过本指南,您学习了如何为 AWS RoboMaker 准备 ROS 应用程序 Docker 映像。此方法是使用捆绑包的替代方法,它使开发人员能够自定义其容器的配置,并支持各种不同的构建工具、依赖项管理工具和模拟引擎。
我们选择不使用捆绑包,因为在创建 Docker 映像时,使用 rosdep
的 colcon
构建和安装过程就足够了。但是,colcon bundle 是开源的,如果您决定继续在机器人中使用,则可以使用。在这种情况下,您可以按照上面概述的类似方法为 AWS RoboMaker 创建 Docker 映像。只需移除构建阶段,将捆绑包复制到映像中,然后运行捆绑包使用说明中概述的命令即可。
我们很高兴听到在新的灵活容器支持下,ROS 开发人员现在可以运行所有不同类型的模拟。
祝大家构建顺利!