Amazon Web Services ブログ
AWS RoboMakerでROSアプリケーションのビルドとバンドルをおこなう
12か月前から、クラウドロボティクスサービスであるAWS RoboMakerの開発を開始しました。 私たちに直面していた最大の疑問の1つは、次のとおりでした。サービス上でROSアプリケーションを簡単に実行できるようにするにはどうすればよいのか。 ロボットアプリケーションは、多数の依存関係を持つさまざまなパッケージが大量に混在しています。 シミュレーションも含まれると、その依存関係のリストがさらに増えます。 多くの検討と研究の結果、私たちはappimage、flatpak、snapcraftに触発され、ローカルのの開発環境でも私たちのサービスでも使える単一のファイルフォーマットを作成しました。 このフォーマットをbundleと呼びます。
パッケージングアーティファクトをどのような設計するかを決定した後、生成を容易にするためのコマンドラインツールを作成したいと思いました。 ツールが既存のROSエコシステム内に収まることが私たちにとって非常に重要でした。 その結果ROSのビルドツールの中で最新かつ最高のものであるcolconの上に構築することにしました。 ColconはROS1とROS2アプリケーションを構築できます。 またそれは非常に拡張性があり、革新的で重要な機能の多くを提供します。
この記事では、既存のROSビルドツールと、なぜcolcon
がROS2のビルドツールとして選ばれたのかを説明しています。 Colconは私たちの代わりに多くの大変な作業を肩代わりすることにより、私たちは特定の機能に集中することができます。 さらに、colcon build
はcatkin_make
とament_make
を利用してビルドしていたパッケージを変更することなく置き換えます。 つまり、colcon
の上にツールを構築することで、AWS RoboMakerユーザーは単一のツールをインストールしてフルワークフローを実行し、AWS RoboMakerで使用するためのbundleを生成できます。
この記事では、AWS RoboMakerで使用するbundleを作成するための通常のワークフローと、頻繁に発生する問題に対するいくつかの解決策について説明します。 2番目のセクションでは、最新バージョンの「bundle」ファイルフォーマットについて詳しく説明し、colcon bundle
を実行してbundleを作成するときに何が起こるかについて概要を説明します。
なぜbundleなのか
ROSシミュレーションワークフローには、ROSおよびその他のアプリケーションのランタイム依存関係がインストールされた環境が必要です。 通常は、さまざまなapt-get install
コマンドを実行することによって実現されます。 このインストールは時間がかかり、さらに公開されているパッケージのアップデートはいつでも発生する可能性があるため、同じインストールを確実に再現することはできません。 私たちのサービスでは、シミュレーションを実行するたびにapt
を使用して新しい環境をインストールすることの信頼性を心配していたので、さまざまなパッケージ形式を調べました。 ROSアプリケーション全体で最も魅力的で信頼性の高い配布形式はDebianパッケージでした。 それはROSのロボットを動かすのに必要な、boostまたは他の外部ライブラリ、そして実際のアプリケーションコードなど、すべてを含むことができます。
ダウンロード、作成、および更新のための最適化を柔軟に追加できるようにするため、既存のフォーマットを使用しないことにしました。 そこで私たちは「bundle」フォーマットと、それをサポートするための対応するツールを作成しました。 最初のバージョンはうまくいきましたが、以下のようないくつかの制限がありました。
- ワークスペースの更新のみでbundleを更新するのは、最初の
colcon bundle
の呼び出しと同じくらいの時間がかかりました。 - 更新されたbundleをロボットにデプロイすることは、ダウンロードとbundleコンテンツの抽出の両方において、期待したほど速くはありませんでした。
これらの制限を軽減または削除するための最適化を含むbundle形式の、バージョン2を発表できることに興奮しています。 フォーマットは現在部分的なダウンロードと部分的な抽出をサポートしています。 これには3つの大きな利点があります。
- 2G / 3Gといった帯域幅に制約のあるリモートデバイスであるロボットのアップデートで、使用される帯域幅を削減することができました
- 必要なものだけを抽出するようになりました。bundleの大部分が変更されていない場合は、ダウンロードまたは展開に無駄なコストを負う必要はありません。 ローエンドのデバイスでは、これにより大幅な時間の節約になります(TurtleBotsでは、デプロイにかかる時間が60分から1分に短縮されました)
- 全体のアーカイブは圧縮されていないので、段階的にbundleすることができます。 これにより、ワークスペースを簡単に更新するための再bundle時間が5分以上から数秒に短縮されます
AWS RoboMakerはこの新しいバージョンをサポートしています。 これらの新しい機能を試してみたい場合は、開発環境でsudo pip3 install -U colcon-bundle
を実行してください。 このブログの後半では、この新しい形式の実装について詳しく説明します。 質問、アイデア、または問題がある場合は、GitHub issueに追加してください。
colconを使ってAWS RoboMaker用のbundleを作成する
ワークスペースをcolconでbundleするには、2つのステップのみです。
- ワークスペースを
colcon build
でビルドする - ワークスペースを
colcon bundle
でbundleを作成する
ビルド
catkin_make
でビルドできるすべてのROSパッケージは、colcon build
でもビルドできます。 何か月もの間ROSパッケージを使って作業してきましたが、colcon build
を使ってパッケージを作成する際に発生する問題はごくわずかでした。 catkin_make
で正常にビルドされるcolcon build
でパッケージをビルドする際に問題が発生した場合はcolcon-ros issuesで報告してください。
注意:catkin_make
からcolcon build
への最も大きな変更は、devel
ディレクトリがなくなったことです。 ワークスペースをローカル環境に追加したい場合は、代わりにsource install/setup.sh
を実行してください。
bundle
ワークスペースをcolcon build
でビルドしたら、build
とinstall
ディレクトリが作成されます。 bundleを開始するには、colcon bundle
を実行してください。 私たちのツールは依存関係を検査し、それら全てをダウンロードし、そしてそれらをビルドされたワークスペースと一緒にまとめてAWS RoboMakerで使用するために圧縮します。 構築されたbundleはbundle/output.tar
にあります。
ビルド時の一般的な問題
ROS1開発のための標準のビルド手順はcatkin_make
を使用します。 colcon
は比較的新しいので、多くのROS1開発者はそれに慣れていないかもしれませんが、catkin
ビルドと完全に互換性があります。 colcon build
で既存のROSパッケージ(以前はcatkin_make
でビルドされていました)をビルドしている間に、いくつかの小さな問題に遭遇しました。
階層ディレクトリ内のCMAKElists.txtファイル
私たちが遭遇した一般的なビルドの問題は、colcon
がワークスペース内のすべてのパッケージを正しく列挙できず、colcon bundle
を実行した際に正しくないディレクトリ構造となり失敗します。 これは、ネストされたディレクトリ構造でCMakeLists.txtが正しくないディレクトリにあることが理由で発生します。 catkin_make
を使用してディレクトリ内にネストされたパッケージを構築するために必要ですが、colcon
で問題を引き起こします。 Colcon
は深い入れ子のフォルダ構造をサポートしているので、パッケージを自動的に見つけます。 以下は、ディレクトリ構造の例です。
src/
├── package_1/
│ ├── package.xml
│ └── CMakeLists.txt (OK)
└── intermediate_directory/
├── package_2
│ ├── package.xml
│ └── CMakeLists.txt (OK)
├── package_3
│ ├── package.xml
│ └── CMakeLists.txt (OK)
└── CMakeLists.txt (REMOVE)
CMAKELists.txt内のインストール情報が不足
私達が遭遇するもう一つの問題はファイルが足りないことです。 catkin_make
を使用するとき、devel
ディレクトリとitssetup.sh
はすべてのローカルパッケージをROSツールの検索パスに追加します。 しかし、Colconの動作は異なります。指定したすべてのターゲットがinstallディレクトリにインストールされます。つまり、CMake
のinstall()
ディレクティブはすべて実行されます。 次のようなエラーが発生した場合
[a_launchfile] is neither a launch file in package [a_package] nor is [a_package] a launch file name
または、
[rosrun] Couldn't find executable named my_node below /opt/ros/kinetic/share/my_package
この場合CMakeLists.txt
にinstall()
の呼び出しを追加すると問題が解決する可能性があります。 これを行う方法の優れた例がROS Wikiにあります。
bundle実行時の問題
AWS RoboMakerでアプリケーションのbundleを処理している間に発生した最も頻繁な問題です。
Cannot Locate rosdep Definition for [Package Name]
利用したいパッケージに正しいROSパッケージ名が使用されているかを確認してください。 パッケージの名前はapt
ではros-kinetic-packagename
ですが、package.xml
ではpackagename
になります。 rosdistro GitHubレポジトリを検索し、利用したいパッケージ名が存在するかを確認してください。 ない場合は、rosdepに依存関係を追加するためのチュートリアルを参考にしてください。
Missing Dependencies
さまざまなオープンソースのROSライブラリをbundleしているときによく遭遇した問題は、依存関係が欠けていたことです。 多くの場合、ビルド環境には別のパッケージのために既に依存関係がインストールされており、すべてが正常にビルドされますが、パッケージがbundleされた後はその依存関係は失われます。依存関係が欠けているときの一般的なエラーメッセージは、Could not load libxzy.so
、No such file or directory some_script.py
、Could not load module 'python_dependency'
。これを解決するには、それを必要とするパッケージのpackage.xml
に依存関係を追加して、bundleを再実行します。
独自のapt
またはpip
リポジトリからアプリケーションで依存関係を使用する場合は、それらのリポジトリをcolcon bundle
に含める必要があります。 これを解決するには、次のことを試してください。
-
colcon bundle
のapt
インストーラの--apt-sources-list
引数でsources.listを上書きすることができます。 ベースOSおよびROSパッケージの解決エラーを避けるために、現在使用しているすべてのソースを含めることをお勧めします。 GitHubのexamplesources.listを調べてください。 -
pip
またはpip3
ソースを上書きするには、--pip-args
または--pip3-args
引数を使用します。 この引数の後の文字列は、pipに直接渡されます。例:--extra-index-url https://my-custom-pip-repo/index
Build と Bundle の完了
これで、AWS RoboMakerでシミュレートするためにアプリケーションを構築してbundleすることができます!パッケージを最新バージョンにアップグレードするには、開発環境で「sudo pip3 install -U colcon-bundle colcon-ros-bundle
」を実行します。 ご質問がある場合や問題が発生した場合は、関連するGitHubリポジトリに投稿してください。お手伝いいたします。 colcon bundle
が実行されたときに実際に何が起きているのかに興味があるなら、読んでください!
Bundle Deep Dive
このセクションでは、bundleフォーマットの内部とcolcon bundle
の実装について技術的に詳しく説明します。 このセクションの終わりには、colcon bundle
が実行されたときに何が起きているのかを理解することができます。 それがいかに簡単であるかを理解した後、あなたが作成したツールをcolcon
のエコシステムにコントリビュートすることを願っています。
Bundle File Format
「bundle」とは、ROSアプリケーション全体を実行するためにAWS RoboMakerによって使用されるパッケージ形式です。それはロボットに必要なものをすべて含んだもの、または対応するシミュレーションアプリケーションを含みます。 ROSは、依存関係の宣言方法と使用する構築ツールを指定する標準のパッケージ形式をすでに定義しています。 colcon
を使用して、このツールは情報を収集し、さまざまなパッケージインストーラ(現在はpipとapt)を起動して依存関係を解決し、それらの依存関係をローカルステージング領域にインストールします。そして、それらをローカルの構築済みワークスペースと一緒にまとめてAWS RoboMakerで使用できるようにbundleします。
そのワークフローが私たちが「bundle」と呼ぶものを生み出します(私たちはそれを退屈な名前にしています – あなたがこのフォーマットの命名のアイデアをお持ちの場合は、私たちのリポジトリで問題を開いてください)。 bundle形式の仕様は、colcon-bundleリポジトリにあります。 ここで概要を説明します。
この図は私達のbundleフォーマットのV2を示しています。 ここで履歴を見ることができます。 「bundle」ファイルは標準のGNU tarフォーマットに従います。 最低3つのコンポーネントがあります。
- バージョンファイルは、後方互換性のない変更を含むbundleバージョンを区別するために使用できます
- メタデータtarballは、少なくともbundle内に含まれるオーバーレイのリストを含み、bundleが関連を持つ可能性のあるその他のメタデータも含みます
- 少なくとも1つのオーバーレイを含みます。 ROSワークスペースはワークスペース オーバーレイの概念をサポートしています。 この概念を採用して、アプリケーション全体に適用しました。 これにより、AWS RoboMakerは、ベースのOSを変更することなく、Linuxオペレーティングシステム上でROSアプリケーションを実行できます
上記のフォーマットの最新バージョンの利点について概説しました。 ここからはV1とV2の間の主な変更点です。
-
最終的なbundleファイルのフォーマットを.tar.gzから .tarに変更しました。
これによりファイル内のランダムアクセスを許可します。 コンテンツの一部をすでに持っている場合は、変更されたコンテンツのみをダウンロードできるので、これは素晴らしいことです。 個々のオーバーレイを圧縮すると、gzip
は複数の小さいファイルほど効率的ではないため、ファイル全体のサイズに影響を与えます。 しかし、これが問題になるとは思いません。なぜならメジャーアップデートのユースケースでは、変更された部分だけをダウンロードできるようになったからです。 -
単一のオーバーレイから任意の数のオーバーレイに変更し、各オーバーレイをgzipします。
これにより、bundle形式の柔軟性が大幅に向上します。 上記のストレートtarへの変更により、各オーバーレイは個別にアクセス可能になりました。 更新ユースケースに合わせて最適化するために、必要なだけオーバーレイを用意する柔軟性があります。 最も詳細なレベルでは、各ライブラリは別々のオーバーレイに存在する可能性があり、1つのライブラリが変更された場合、それがロボットによってダウンロードされる必要がある唯一の変更です(それ以外が最新の場合)。 これにより、リモートデバイスの帯域幅と時間が大幅に節約されます。 -
overlays.jsonをメタデータに追加します。
このファイルには、ワークスペースに適用するオーバーレイの順序付きリスト、およびオーバーレイのバージョン間の比較に使用できるハッシュが含まれています。 このメタデータは、任意の数のオーバーレイを持つことを可能にし、環境が正しい順番で構築されることを保証します。ハッシュで特定のオーバーレイが変更されたことをわかるため、インテリジェントなダウンロードと抽出が可能になります。
全体として、私たちはこれらの改良に非常に満足しています。 もし何かアイデアがありましたら、GitHub issueに登録してください。
colcon bundle の実行フロー
このセクションでは、colcon bundle
を実行したときに実際に何が起きているのかを説明します。 (これは、私たちのツールをcolconの上に構築する素晴らしい経験でした。あなたが特別なビルドツールを作成しようとしているのなら、colconが基本フレームワークとして素晴らしいので、見ることを強くお勧めします。)
colcon
エコシステムは、直接の依存関係と、基本としてのcolcon-coreのみに依存する個々のPythonパッケージで構成されています。 colcon
のほとんどすべての機能は、colcon-coreの基本インフラストラクチャによって定義されたExtensionPointとしてモデル化されています。 colcon
は、モジュール性と疎結合という目的を達成するためのプラグインメカニズムとして、setuptoolsエントリポイントを利用します。
コマンドラインインターフェースを拡張するために、colcon
はVerbExtensionPoints
を介したコマンドの追加をサポートしています。 機能を構築するために、bundle verb(サブコマンド)を作成し、それをsetup.cfg
に登録しました。 この素晴らしいツールに統合されたコマンドを取り入れるためにしなければならなかったのはこれですべてです。 (それ以降の作業はすべて、私たちのドメインに固有のものでした。)ROSワークフローの周りにツールを構築することを検討している場合は、colcon
を使用してください。 十分にお勧めできてませんが、オススメです。
colcon bundle
が呼び出されると、一連のアクションが発生し、その一部はcolconのインフラストラクチャから提供され、また一部は私たちが作成したものです。 ここでそれらの概要を説明しますが、すべてがどのように機能するのかをより深く理解するためにコードにdive deepすることをお勧めします。
- 私たちの
VerbExtensionPoint
であるBundleVerb
が呼び出されます。 登録したすべての引数と他の拡張ポイントからの引数を含むコンテキストが渡されます。 - 次に、
colcon-core
機能の一部を呼び出してワークスペースファイルツリーをクロールし、パッケージを識別します。 次に、これは各パッケージのPackageDescriptor
を作成してbundle
の実行に含めます。 パッケージの識別はPackageIdentificationExtensionPointsを使って行われます。 ROSパッケージを識別するために登録されている拡張子は、colcon-rosで定義されているRosPackageIdentificationです。 ROSパッケージを識別すると、PackageDescriptorのタイプをros.cmake、ros.catkin、またはros.amentに設定します。 - すべてのパッケージが識別されると、
colcon
は特定のパッケージタイプに登録されているPackageAugmentationExtensionPoint
を実行します。 識別とともに、RosPackageIdentification
は、パッケージのpackage.xml
を解析し、パッケージ記述子メタデータにビルド、テスト、および実行時の依存関係を追加する拡張機能も提供します。 - 今度はコードに戻り、各
PackageDescriptor
に添付されている依存関係メタデータを調べて、最後の呼び出し以降に何か変更があったかどうかを判断します。 何も変わっていなければ、それ以上の依存関係分析をスキップして、構築されたワークスペースを既存の依存関係オーバーレイとbundleを続けます。 依存関係が変化したと判断した場合は、引き続き完全な依存関係分析を行います。 - 完全な依存関係の分析中に、各
PackageDescriptor
に対して、対応するbundleタスクを呼び出します。 現在ros.catkin、ros.cmake
、およびpython
パッケージタイプをサポートしています。 このサポートはcolcon-bundle/setup.cfg
およびcolcon-ros-bundle/setup.cfgに登録されています。 対応するbundleタスクを追加することで新しいパッケージタイプをサポートできます。 パッケージタイプごとに、対応するbundleタスクが依存関係を収集してから、依存関係ごとに適切なBundleInstallerExtensionPoint
を呼び出します。 私たちのROSタスクはrosdepを使ってROS依存関係名からそれにマッチするシステムパッケージ名に変換します。 - すべての依存関係がインストーラに登録され、完全推移閉包が決定されると、
libc*
、gazebo*
、およびその他のインフラストラクチャによって提供されるパッケージをインストールしたくないので、システムパッケージリストにブラックリストを適用します。 ブラックリストの動作を上書きしたい場合は、--apt-package-blacklist
引数を使用して独自のブラックリストを指定できます。 - ブラックリストに登録した後、依存関係の登録手順で使用されたすべての登録済み
BundleInstallerExtensionPoint
に対してinstall()
を呼び出します。 インストーラは--bundle-base
(デフォルト:bundle)ディレクトリ内のディレクトリにすべてをインストールします。 ダウンロードとインストールが完了したら、オーバーレイを有効にするsetup.sh
にコピーして、次にtar
とgzip
でフォルダをdependencies.tar.gz
にコピーします。 - 依存関係がアーカイブされたら、最新のビルドされた
install
フォルダをアーカイブします。 オーバーレイを有効にするために、setup.sh
を使用して--install-base
(デフォルト:install)ディレクトリ全体を別のオーバーレイにtarおよびgzip
します。 - 両方のアーカイブが作成されたら、バンドリングプロセス中に生成されたすべてのメタデータを収集し、サイズ、オフセット、およびオーバーレイの順序を記述するメタデータを追加します。 次に、そのメタデータを
tar
してmetadata.tar.gz
に圧縮します。 - 次に、さまざまなアーカイブをまとめて「bundle」を作成し、それを
bundle/output.tar
のディスクに書き込みます。 これで、bundleはAWS RoboMakerのローカルに使用できるようになりました。
bundleを使ってアプリケーションを実行する
bundle形式は、AWS RoboMakerで使用するのと同じようにローカルで使用できます。 これを行うことはあなたのアプリケーション、あるいは単にデバッグツールとして役に立ちます。近々、私達が作成した、サービス内のcolcon bundle
で作成したアーカイブを展開するためのGoLangライブラリを公開します。ここでは、現在どのような手順でcolcon bundle
で作成したアーカイブを展開するかを紹介します
- アーカイブから
version
とmetadata.tar.gz
を抽出します - 使用する互換モードを確認するためにversionを確認します(このステップ以降、bundleはversion 2であると想定します)
-
metadata.tar.gz
からoverlays.json
を抽出します -
overlays.json
を解析して、ディスクに抽出するアーカイブのリストを収集します。overlays.json
には、オーバーレイのsha256
ハッシュが含まれています。 これらのハッシュは、オーバーレイが変更されたため再抽出する必要があるかどうかを判断するために使用されます。 それらはまた、オーバーレイの整合性を検証するためにも使用できます - オーバーレイがディスクに抽出されたら、それらは
overlays.json
にリストされている順序で環境に反映される必要があります。 環境にオーバーレイを追加するには、次のコマンドを実行します。BUNDLE_CURRENT_PREFIX=<path_to overlay_folder> source <path_to_overlay_folder>/setup.sh
ファイルを読み込むときに、そのファイルがどこにあるのかを判断するために、BUNDLE_CURRENT_PREFIX
が必要となります - ROSワークスペースとbundle内の依存関係がローカルにインストールされているかのように、実行環境で実行可能な状態に設定されました
まとめ
私達が作成したフォーマットとツールに満足しており、引き続き改善していくことを楽しみにしております。colcon bundle
の実装は、より多くのパッケージタイプとインストーラに拡張可能です。colcon
上にあなた自身のツールを構築したい場合は、colconのコラボレーションドキュメントをチェックしてください。
原文はこちら
翻訳はSA 市川が担当しました