設定ファイルから見るLiDARシミュレータの世界

この記事はLiDAR Advent Calendar 2023の12/06分の記事です。

いろんなシミュレータのLiDARに関する設定ファイルの読書感想文です。

3D LiDARの簡単な分類

シミュレータの話に入る前に、一度シミュレーション対象であるLiDARをみておきましょう。 ここでは細かな動作原理の違いを考えずに出力される点群の特徴をざっくりと捉えていきます。

回転式LiDAR

昔からよくあり、現在でも主流のLiDARの種類です。 レーザーと受光センサのユニットを水平に回転させるため、水平360°にセンシングできることが特徴です。 1ユニットでは縦方向に視野を広げることができないため、ピッチ角を変化させた複数ユニットを用いることが多いです。 垂直方向の点群密度を増やすにはユニットを増やす必要があるため、水平方向の点群密度に対して縦方向の点群密度は粗くなりがちです。

SolidState式LiDAR

回転式(機械式)と対比されることが多いSolidState式は機械的な可動部が存在しない(または小さい*1)LiDARの種類です。

回転式とは違って光源を動かさずに光を曲げたり加工したりして走査する必要があるため、回転式に比べて水平視野はどうしても狭くなります。 一方で構造次第で垂直方向にも自由度を持てるので、垂直方向の点群密度を容易に上げることが可能です。 カメラの画像のような縦横比がほぼ同じ解像度をもつLiDARが多いですが、独自のスキャンパターンを持つLiDARも少なくありません。

シミュレータ選手紹介

今回見ていくシミュレータの選手紹介です。 オープンソースで提供されているもののみを対象としています。 3D LiDARは自動運転で使われることが多い関係上、自動運転向けシミュレータが多くなりました。

シミュレータ 概要
Gazebo ROS向けデフォルトのシミュレータ
Choreonoid 産総研発の国産シミュレータ
UnitySensors Unityでセンサをシミュレーションするためのシミュレータ、というよりはライブラリ?
CARLA 自動運転業界でデファクトスタンダードになっているシミュレータ
LGSVL 旧Autoware向け標準シミュレータ
AWSIM 現Autoware向け標準シミュレータ

各シミュレータの設定ファイル

一番最初に触れたように3D LiDARはそれぞれ独自の構成を持っています。 LiDARシミュレータで多くの種類のLiDARに対応するために、構造の違いをパラメータの違いで表現できるように一般化して実装されます。 この構造の一般化方式が色濃く出るのがLiDARセンサのために設定ファイルです。
さぁ、設定ファイルからLiDARシミュレータの世界に飛び込んでみましょう。

※一部ソースコードも含みますが、一般化できていれば設定ファイルとして扱います。

Gazebo(Classic)

垂直・水平方向に過不足なく表現力を持ったフォーマットです。 LiDAR以外にも深度カメラでも使えるように配慮されたフォーマットのように思えます。

<ray>
  <scan>
    <horizontal>
      <samples>32</samples>
      <resolution>1</resolution>
      <min_angle>-3.14156</min_angle>
      <max_angle>3.14156</max_angle>
    </horizontal>
    <vertical>
      <samples>3</samples>
      <resolution>1</resolution>
      <min_angle>-0.02</min_angle>
      <max_angle>0.02</max_angle>
    </vertical>
  </scan>
  <range>
    <min>0.05</min>
    <max>70</max>
    <resolution>0.02</resolution>
  </range>
</ray>

Choreonoid

最低限のシンプルなパラメータで構造を表現しています。 視野角を下限上限の2パラメータではなく角度の1パラメータで表現しているため、 上方向などある方向に偏った視野をもつ3D LiDARを表現できないことに注意です。

yawRange: 180
yawStep:  0.4
pitchRange: 30.0
pitchStep: 2.0
scanRate:  20
maxDistance: 100.0

参考:URL

UnitySensors

このシミュレータは設定ファイルを持たず、それぞれのセンサーに専用実装を持っています。 しかし、以下のように実質設定ファイルとなっている箇所もあります。

[SerializeField]
private RotatingLiDARScanPattern _scanPattern;
[SerializeField]
private float _minDistance = 0.0f;
[SerializeField]
private float _maxDistance = 100.0f;
[SerializeField]
private float _maxIntensity = 255.0f;
[SerializeField]
private float _gaussianNoiseSigma = 0.0f;

参考:URL

スキャンパターンは現状以下のようなものがサポートされているようです

名前 特徴
RotatingLiDARScanPattern 回転式LiDAR用の実装。垂直方向の角度は細かく設定できるようになっているのが特徴
CSVLiDARScanPattern CSVファイルからスキャンパターンを読み込む。Livoxのような複雑なパターンも再現可

CARLA

回転式LiDARに特化した設定ファイルとなっています。 回転式以外の表現は難しいですが、流石自動運転向けと言ったところで大気減衰率やドロップオフ(点群の消失)に関するパラメータが充実しており、 天候によるLiDARセンシングの変化もシミュレーションできるようになっているようです。

Blueprint attribute Type Default
channels int 32
range float 10.0
points_per_second int 56000
rotation_frequency float 10.0
upper_fov float 10.0
lower_fov float -30.0
horizontal_fov float 360.0
atmosphere_attenuation_rate float 0.004
dropoff_general_rate float 0.45
dropoff_intensity_limit float 0.8
dropoff_zero_intensity float 0.4
sensor_tick float 0.0
noise_stddev float 0.0

参考:URL

LGSVL

こちらも回転式LiDARに特化した設定ファイルになっています。 カスタムLiDARでは一様にならないことも多い各センサーの垂直方向の角度は細かく設定できるようになっているのが特徴で、 形状の表現力としてはCARLAよりも上になります。

Name = "Lidar32-NonUniform",
LaserCount = 32,
MinDistance = 0.5f,
MaxDistance = 100.0f,
RotationFrequency = 10, // 5 .. 20
MeasurementsPerRotation = 1500, // 900 .. 3600
FieldOfView = 41.33f,
VerticalRayAngles = new List<float>
{
  -25.0f, -1.0f, -1.667f, -15.639f,
  -11.31f, 0.0f, -0.667f, -8.843f,
  -7.254f, 0.333f, -0.333f, -6.148f,
  -5.333f, 1.333f, 0.667f, -4.0f,
  -4.667f, 1.667f, 1.0f, -3.667f,
  -3.333f, 3.333f, 2.333f, -2.667f,
  -3.0f, 7.0f, 4.667f, -2.333f,
  -2.0f, 15.0f, 10.333f, -1.333f
},
CenterAngle = 10.0f,

参考:URL

AWSIM

UnitySensorsのCSVLiDARScanPatternに似てレーザー一本一本を設定することができます。 注目すべきはtimeOffsetでタイミングのズレを設定できるところです。 UnitySensorsも同じく任意形状のスキャンパターンを設定できますが、時刻の設定ができないためLivoxのようなレーザーが一本しかないLiDARしか表現できません。 一方で、AWSIMは複数本のレーザーを持つLiDARはもちろんの事、フラッシュ式のようなタイミングが特殊なLiDARに対する表現力を持っています。 また、この設定項目があるということは、スキャン中にセンサーが移動することによる点群の歪み*2もシミュレーションできるのかもしれません。

public static LaserArray VelodyneVLP16 => new LaserArray
{
    centerOfMeasurementLinearOffsetMm = new Vector3(0.0f, 37.7f, 0.0f),
    focalDistanceMm = 0.0f,
    lasers = new[]
    {
        new Laser {verticalAngularOffsetDeg = +15.0f, verticalLinearOffsetMm = +11.2f, ringId = 0, timeOffset = 0.0f },
        new Laser {verticalAngularOffsetDeg = -1.0f, verticalLinearOffsetMm = -0.7f, ringId = 8, timeOffset = 0.002304f },
        new Laser {verticalAngularOffsetDeg = +13.0f, verticalLinearOffsetMm = +9.7f, ringId = 1, timeOffset = 0.004608f },
        new Laser {verticalAngularOffsetDeg = -3.0f, verticalLinearOffsetMm = -2.2f, ringId = 9, timeOffset = 0.006912f },
        new Laser {verticalAngularOffsetDeg = +11.0f, verticalLinearOffsetMm = +8.1f, ringId = 2, timeOffset = 0.009216f },
        new Laser {verticalAngularOffsetDeg = -5.0f, verticalLinearOffsetMm = -3.7f, ringId = 10, timeOffset = 0.011520f },
        new Laser {verticalAngularOffsetDeg = +9.0f, verticalLinearOffsetMm = +6.6f, ringId = 3, timeOffset = 0.013824f },
        new Laser {verticalAngularOffsetDeg = -7.0f, verticalLinearOffsetMm = -5.1f, ringId = 11, timeOffset = 0.016128f },
        new Laser {verticalAngularOffsetDeg = +7.0f, verticalLinearOffsetMm = +5.1f, ringId = 4, timeOffset = 0.018432f },
        new Laser {verticalAngularOffsetDeg = -9.0f, verticalLinearOffsetMm = -6.6f, ringId = 12, timeOffset = 0.020736f },
        new Laser {verticalAngularOffsetDeg = +5.0f, verticalLinearOffsetMm = +3.7f, ringId = 5, timeOffset = 0.023040f },
        new Laser {verticalAngularOffsetDeg = -11.0f, verticalLinearOffsetMm = -8.1f, ringId = 13, timeOffset = 0.025344f },
        new Laser {verticalAngularOffsetDeg = +3.0f, verticalLinearOffsetMm = +2.2f, ringId = 6, timeOffset = 0.027648f },
        new Laser {verticalAngularOffsetDeg = -13.0f, verticalLinearOffsetMm = -9.7f, ringId = 14, timeOffset = 0.029952f },
        new Laser {verticalAngularOffsetDeg = +1.0f, verticalLinearOffsetMm = +0.7f, ringId = 7, timeOffset = 0.032256f },
        new Laser {verticalAngularOffsetDeg = -15.0f, verticalLinearOffsetMm = -11.2f, ringId = 15, timeOffset = 0.034560f },
    }
};

参考:URL

最後に

本当はもっと色々なことを書こうと思っていたのですが、想像以上に長くなりそうだったので別の記事に分けようと思います。 それではまた次の記事で。

*1:これをSolidStateに含めるかは会社や文献によりまちまちです。 小さい可動部が存在する広義のSolidStateLiDARと差別化するため、True-Solid-Stateを名乗るLiDARもあります

*2:イメージし辛い方はカメラで発生するローリングシャッター現象のLiDAR版、と言えば分かるでしょうか?いや、もっと分かりにくいか...

ディープラーニングとやらの力をお借りして喋らせるやつの力をお借りして喋るROS2パッケージをババーっと作った

この記事はROS2アドベントカレンダー2022,12/14(つまり昨日)の記事です.

ROS2のカレンダー | Advent Calendar 2022 - Qiita

遅れてすみません.

はじめに

ロボコンに出ました.ロボットを喋らせました.

これはこれでロボットらしくて良かったです.

でも大会終わって思ったんですよ,もうちょっと流暢に喋らせたいなって.

で,作りました.

ディープラーニングとやらの力をお借りして喋らせるやつの力をお借りしてしゃべるROS2パッケージを!

github.com

今回はこれを作った話について書こうと思います.

下調べ

まず,今どんな喋るROSパッケージがあるのか調べてみました.
ロボコンで使ったのはこれです.お世話になりました.

github.com

知り合いが作ってるパッケージも見つけました.

github.com

よく見たらこちらの方が少し世に出たのが早いんですね.
きっと作者の方は思ったのでしょう,「なければ作れば良いのでは」と

他にも色々見てみましたが,バックエンドがespeak系だったり最近のイケてそうな声が出せそうなROS(2)パッケージはありませんでした.

なければ作れば良いのでは

という訳で僕も作り始めました.

バックエンドはVOICEVOXを使うことにしました.
VOICEROIDやVOICEPEAKも見ていたんですが,せっかく作るからには色々な人に使ってもらえるようにしたかったので有料の壁はやっぱり高かったです.(ごめんなさい)

その点,VOICEVOXは無料しかも商用利用可でここまで高品質な話し声を出せるのは素直にすごいと思いました.(ちゃんとマネタイズできてるのか気になってくる社会人1年生であった)

voicevox.hiroshiba.jp

探していると,なんとDockerコンテナも提供されていてなんとまぁ使いやすいことでしょう!

https://hub.docker.com/r/voicevox/voicevox_engine

通化

早くパッケージを作りたい気持ちを抑えて,ふと思いました

GitHub - ActiveIntelligentSystemsLab/japanese_tts_ros: 日本語テキストを音声として出力するROS node
GitHub - hakuturu583/openjtalk_ros: ros bridge for openjtalk

はじめに出てきたこの2つのパッケージ,めちゃめちゃ似ているんですよね.

よく考えたらそれもそう,音声合成で喋らせるROSパッケージって

  1. 合成音声エンジンに音声合成をさせる
  2. 出てきた音声ファイルを再生する

をやっているだけなんですよね.

このまま,僕が上の2つのパッケージを参考にしてまた似たようなパッケージを作ってもいいかもしれません.

でも基本のところが同じなら1つのパッケージで色々な合成エンジンを切り替えられると楽しいんじゃないかと思ったわけです.

プラグイン化計画

さて,色々なエンジンを切り替えるとなると,まずは各エンジンに対して音声合成させる部分をプラグインに切り出す.

そして,共通処理を扱う母艦プログラムを作れば,あとは母艦プログラムに好きなプラグインを差し込めばいけそうな気がしてきました.

イメージはこんな感じ

という訳でできたのがこちら!

github.com

設計は甘いとは思いますが,なにせ基本の音声合成の手順が単純なのでこれでも色々な音声合成エンジンに対して簡単にプラグインを実装できるようになったのではないかと思います.

OpenJTalkプラグイン

母艦プログラムができてもプラグイン実装がないとこのプログラムは喋りません.

まずは試しにOpenJTalkのプラグインを作ってみました.

github.com

自分が作ったプログラムを通して聞く音声はなんだか少し温かみがある気がしました(寝ろ

VOICEVOXプラグイン

さて,待ちに待ったVOICEVOXプラグイン
遠回りが過ぎましたが準備はバッチリであとはこれを実装するのみです!

VOICEVOXはどうやらDockerコンテナを立ち上げると,HTTPのAPIサーバーが立ち上がってそれを叩けば音声合成ができるようです.

今回はC++でプログラムを作るのでMicrosoftC++ REST SDKというライブラリを使ってAPIを叩くことにしました.

github.com

このライブラリのクセがなかなか強くて途中ちょっと苦労もしましたが, 無事出来上がったのがこちらです!

github.com

おお,喋る!!
実装終わったのは昨日(12/14)の夜,それも仕事のミーティングが長引いて疲れ果てていましたが,流石にちょっと感動しました.
(その後,頭の死んでいた僕はTwitterのTLに流れて来るツイートを読ませてひとしきり遊びました.)

このリポジトリのREADMEだけはしっかりと書いたので是非みなさんも試してみてください!

あ,ROS2 Humbleでしか動作確認していないので気をつけてくださいね.

動かなかったりしたらIssue・プルリク待ってます.

最後に

ふとした思いつきをババーっとプログラム書いて,ババーっとこうして記事に書きましたがやっててとても楽しかったです.
こんな雑な記事を書くのもはじめてでしたが,こういうスピード感ある記事執筆もアドカレ感が出ていいなと思いました.

プログラムは色々雑ですが,それでも基礎部分は割といい感じに設計したつもりです. これからも雑な部分は少しづつ直していこうと思いますので,使ってみたり,別のプラグイン作ったよ〜って人は是非教えてほしいです.泣いて喜びます.

ROS2でヘッダファイルのインストール先が変わったらしい

※この記事はCalendar for ROS2 | Advent Calendar 2022 - Qiita,2日目の記事である
※である調で書いてしまったので文章が多少高圧的に感じられるかもしれないがご容赦願いたい

ROS2 Humbleを早々と試している人々の中には既に気付いている方もいらっしゃるかもしれない.
そう,ヘッダファイルのインストール先が変わっているのである!!

嘘だと思うなら下の画像を見て欲しい.

GalacticとHumbleでフォルダ構成が違うことが分かっていただけると思う. Galacticではstd_msgsフォルダの直下にmsgフォルダがあるのだが,Humbleではさらにもう一つstd_msgsフォルダを挟んでいる.

この記事では,この変更がどうして行われたかを解説していく.

読み進める人への注意 : この記事は要求される事前知識が多い割に読んで得られる知見は少ない.ROSの勉強にはなると思うが...

事前知識

記事を読み進める前に頭に入れておきたい事前知識たち. 単語を見て理解できるなら飛ばしてもらって構わない.

マージインストール

詳細

コマンド

colcon build --merge-install

起こること

パッケージのインストール先が変わる 例えば,ヘッダファイルのインストール先は以下のようになる

インストールの種類 ヘッダファイルのインストール先
通常 colcon_ws/install/<package_name>/include
マージインストール colcon_ws/install/include/<package_name>

得られる効果

環境変数の汚染がマシになる*1

全パッケージのlibフォルダを環境変数に入れようとすると,通常インストールの場合では 各パッケージにそれぞれに対して colcon_ws/install/<package_name>/libを追加する必要がある. しかし,マージインストールしているとcolcon_ws/install/libを追加するだけで事足りる.

因みに自分が確認した限りでは通常インストールで膨れ上がる環境変数は以下の通り

  • AMENT_PREFIX_PATH
  • CMAKE_PREFIX_PATH
  • PYTHONPATH
  • LD_LIBRARY_PATH

ワークスペースのオーバーレイ / アンダーレイ

詳細

Creating a workspace — ROS 2 Documentation: Galactic documentation

簡単に言うと,ROSのワークスペースが複数あって,両方で source path/to/setup.bash をした時,先にsourceしたワークスペースのことを「アンダーレイ」,後にsourceしたワークスペースのことを「オーバーレイ」と呼ぶ.

aptでインストールしたROSパッケージのバージョンが気に入らない時,手元のワークスペースソースコードをcloneしてビルドすると思いますが, このような状況ではこの仕様がうまく働く.

もし,オーバーレイのパッケージが優先されない場合,オーバーレイである手元のワークスペースソースコードからビルドしたにもかかわらず, アンダーレイにあるaptでインストールしたバージョンの使用を強制されるかもしれない.

何が問題だったのか?

ヘッダファイルのインストール先が変わる原因となる現象は下のIssueで報告されている. github.com

一言で言うと,「特定の状況でをファイルの参照先がおかしくなる」 のである.

特定の状況とは以下のようなものだ

  • システム以外にアンダーレイ / オーバーレイのワークスペースがある
  • アンダーレイ / オーバーレイのワークスペースに同じ名前のパッケージがある
  • アンダーレイでマージインストールを利用している

このような状況は特におかしなものではない.

特に,aptでインストールされる/opt/ros/humble以下のワークスペースはマージインストールと同じ状態になっており,aptでインストールしたパッケージをオーバーレイにクローンする

そして,ros2コマンドでアンダーレイ / オーバーレイ両方のワークスペースに存在するパッケージを呼び出しても,オーバーレイのパッケージが優先されることで解決されるはずである.

しかし,今回のIssueではマージインストールを併用した場合,オーバーレイが優先されなくなってしまうという報告がなされているのである.

詳しく

今回のバグを再現するために作られたリポジトリを簡素化して説明する

GitHub - jacobperron/overlay_bug_reproduction: Reproducing a dependency bug involving an overlay workspace

以下のような構成のワークスペースとパッケージを考える

それぞれのパッケージの情報として,パッケージの名前,パッケージのインクルードパス(パス),他のパッケージへの依存を書いている.

ここで,理想的な依存関係は当然こうなる

理想のの依存関係

しかし,実際は以下のようになってしまうというのが今回の問題である.

実際の依存関係

では,どうしてそんなことが起こっているのか,更に細かく見ていく.
Dパッケージを中心に書くとこうなる

では,次にそれぞれがヘッダファイルを持っていると考えてコンパイラの気持ちになってみる.

d.hppは以下の手順でプリプロセスでインクルードが展開されていく

インクルードの展開の過程

ここで,③のA/a.hppの展開を更に詳しく見てみる

まず,A/a.hppを展開するにはファイルがどこにあるか探すわけだが,コンパイラは依存パスを順番に精査していく. 本来なら,オーバーレイのAパッケージがある~/ros2_ws/install/A/includeA/a.hppが見つかって欲しい. しかし,依存パスの順番的に,はじめにアンダーレイの /opt/ros/humble/includeを探索するのだが, この配下にはA/a.hppが存在するため,間違ったファイルがヒットして展開なされてしまうというわけだ.

それぞれの依存パスの状態
もちろん,ここでアンダーレイでマージインストールなされていなければ,Bのパスを通じて間違ったAのパスにつながることもないので問題は発生しない.

どう対策したのか?

対策の検討

問題に対して,OpenRoboticsのShaneLoretzs氏によって4つの対策案が挙げられています.

それぞれ簡単に紹介すると

  • ①CMake でインクルード ディレクトリを並べ替える
  • ②ヘッダファイルを1階層深い場所にインストールする
  • ③colconでパッケージの重複を検知してどうにかする
  • ④colconでパッケージの重複を検知して知らせる(そして解決はユーザーに任せる)

といった感じになる. 詳しくは原文を参照して欲しいが, ①③はかなり無理がある解決策で④は解決そのものを諦めている.

という事で,選ばれた②について説明していく. ちなみに,④も②の予防策として採用されることになっている.

選ばれた解決策

「ヘッダファイルを1階層深い場所にインストールする」とはどういうことかと言うと, CMakeLists.txt

install(DIRECTORY include/ DESTINATION include)

と書いてヘッダファイルをインストールしていたところを,

install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME})

と書いて更に1階層深い場所にインストールする,ということである.

そう,これこそがタイトルにもある「ROS2でヘッダファイルのインストール先が変わったらしい」と言うことである!!!!

では気になるのは,なぜこれが問題の解決策になるのか?ということであろう.

インストール先が変えることによる効果

まず,対策前後のアンダーレイにおけるマージインストールの結果を見ていこう

マージインストールの結果

対策の前後がそれぞれ記事の冒頭に示した比較画像のgalactic/humbleのようになっていることがわかるだろう.

また,install文が変わったことによって,インストール先だけではなく,依存パスも変化する. Dパッケージの場合は次のように変化する.

依存パスの変化

赤太字で示した場所が変化点である.

この変更によって,問題の原因であった「Bのパスを通じて間違ったAのパスにつながる」ことがなくなったことにお気づきだろうか?

インストールする階層を1つ深くするだけでマージインストール時にもユニークなパスになるようにできるとはよく考えたものである.

解決策の実装

さて,この解決策というのは,アンダーレイのワークスペースに格納される可能性のあるパッケージに実装されなければならない. とりわけ,aptでインストールされて/opt/ros/humble以下にマージインストールされるros/rosdistroに掲載されたリポジトリ群は絶対にアンダーレイになってしまうわけで早急な実装が求められる.

かくして,ROSコミュニティの面々はひたすら解決策の実装に明け暮れるのであった...

ひたすら解決策の実装に明け暮れる様子

ちょうど一年前の話である.

当時rollingだったそれらの解決策がマージされたパッケージたちは,humbleのパッケージとして世に放たれた.
マージから1年後,humbleでヘッダファイルのインストール先が変化したことに気付いた筆者はこうしてこの記事を書くことになったわけである.

*1:envコマンドで確認推奨

*2:これはオーバーレイされる順番にインクルード・ディレクトリをCMake上でソートすることによって実現されている,はず

ROS2パッケージをリリースしよう!準備編

ROSのbloomを使ったパッケージリリースについてはネットに素晴らしい有用な記事があるのですが, GitHubの仕様変更やROS2の公式リリースリポジトリ置き場など, 新しい部分については日本語情報が少ないので情報を残しておきます.

準備するもの

パッケージをリリースするには以下のものが必要です.

必要なもの 備考
GitHubアカウント 当然必要
GitHubアクセストーク リリース用ツールに権限を与えるのに使います
リリースしたいROS2リポジトリ これがないと始まらない
リリース用リポジトリ 作り方は2通り

GitHubアカウント,リリースしたいROS2リポジトリは当然あるものとして,残りの2つについて解説します.

GitHubアクセストーク

本来なら,パッケージのリリースではたくさんのGitHub上での操作を人間が手動で行う必要があります.
bloomはそんな大変な作業を人間に変わって自動でやってくれるツールです.
しかし,GitHub上での操作には認証が求められるため,ツールにアクセス権限を付与する必要があります.

また,近年GitHubではパスワードによる認証が禁止されたため,パスワードを求められた際にはアクセストークンを入力する必要があります.

詳しい作成方法はこちらです.

アクセストークン作成ページ : https://github.com/settings/tokens

アクセストークンには「repo」と「workflow」の権限を設定してください.

アクセストークンの設定

リリース用リポジトリ

パッケージをリリースするためにはソースコードが入ったリポジトリとは別に,<パッケージの名前>-release という名前のリリース用のリポジトリが必要です.
リリース用リポジトリの中身はパッケージの内容を基にbloomが勝手に管理するので開発者はリポジトリを作るだけでOKです.

リポジトリの作成場所ですが,自分の場所に作る方法・公式の場所に作る方法の2通りあるのでそれぞれについて説明します.

公式の場所に作る方法

公式のリリースリポジトリの置き場所がこちらです.

github.com

ここにリリースリポジトリを作る手順は以下のとおりです.

  1. issueを立ててリポジトリの追加をお願いする
  2. リポジトリが追加される

手順自体は簡単ですが,メンテナの方の対応を待たなければいけませんので,時間がかかることは理解しておいてください.
急ぎの場合は「自分の場所に作る方法」を検討するのも手です.

issueを立ててリポジトリの追加をお願いする

こちらのリポジトリにIssueを立てて,リポジトリ追加のお願いをしていきます.

github.com

Issueを追加しようとすると,3つのIssueテンプレートが現れるので,「New release team」を選択して次に進みます.

Issueテンプレート

  • チーム名(英小文字とアンダーバーのみ)
  • リリースしたいリポジトリ
  • メンテナの情報

の3つの情報を埋めてIssueを立てられたらメンテナの人がリポジトリを作ってくれるのを待ちます.
Issueをどう書けばいいかわからない場合は過去のIssueを参考にしてみましょう.
例えば,自分が立てたIssueがこれです↓

github.com

大抵,1週間以内にメンテナ欄に追加したユーザーはOrganizationに追加され,チームの追加,空のリリースリポジトリの作成までをros2-gbpのメンテナの方がやってくださいます.

ここまで来たらようやく,リリースリポジトリの準備が終わりです.
最後に作業をやって頂いたメンテナの方への感謝を忘れずに!

OSSでは何事にも感謝!

自分の場所に作る方法

これはROS1のリリース用リポジトリと同じです. 自分で好きなOrganizationなり自分のユーザーディレクトリなりに<パッケージの名前>-releaseという名前の空リポジトリを作るだけです. 気軽にリリースしたい場合や,急ぎのリリースの場合はこちらの方が良いかもしれません.

作成したリリースリポジトリmasterブランチを作る

最近,GitHubではリポジトリを新規作成した時のデフォルトブランチは masterからmainに変わりました. しかし,bloomは古いツールなので,masterをデフォルトブランチとして扱うため,masterブランチの作成が必須です.

準備完了

これでリリースに必要なものは揃いました!
ということで,準備編はここまでです.

あとのリリースの手順は,GitHubのパスワードを求められた時にアクセストークンを入力するところ以外はネットにある日本語情報を参考にすると良いでしょう.
この記事は特に分かりやすくて良いですね!

qiita.com

気が向けば,リリース編も書こうと思いますが,期待しないでください.

参考

アクセストークン周りに関して

wiki.ros.org

公式の場所へのリリースリポジトリ作成に関して

docs.ros.org

ROS2のCMakeを簡単に!~ament_cmake_auto~

この記事はROS/ROS2アドベントカレンダー2020の18日目の記事です

こんな経験はありませんか?

ROS2のCMakeLists.txtを書いていてこんな経験はありませんか?

  • package.xmlで依存関係を変えたらCMakeも書き換えないといけない...
  • ROS2のコンポーネント指向,便利だけどCMake書くのが面倒...
  • 毎回同じような内容を書く割には抜け漏れが起こりやすい...

その悩み,”ament_cmake_auto”が解決します!

ament_cmake_autoを使うとROS2のCMakeを簡潔に書くことが出来るようになります*1

では,実際にどれくらい簡潔に書けるのかを見ていきます.

ament_cmake_autoを使ったCMakeLists.txt

最小限のサンプルがこちらになります.

cmake_minimum_required(VERSION 3.5)
project(example)

find_package(ament_cmake_auto REQUIRED)
ament_auto_find_build_dependencies()

ament_auto_add_library(${PROJECT_NAME} SHARED
 src/example.cpp include/example.hpp)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  ament_lint_auto_find_test_dependencies()
endif()

ament_auto_package()

あれ?依存関係は??
exportしなくていいの???
installは????

まともにROS2のCMakeを書いたことがある人なら頭の中がはてなマークでいっぱいになると思います.
でも大丈夫,"ament_cmake_auto"がぜ〜んぶやってくれます.

関数群

具体的にどのようなことをやってくれているのかを関数ごとに見ていきます.
詳しくは実装*2をご覧ください.

ament_auto_add_executable

実行ファイル生成に関して

  • add_executable
  • target_include_directories
  • target_link_libraries
  • ament_target_dependencies

をまとめてやってくれます

ament_auto_add_library

ライブラリ生成に関して

  • add_library
  • target_include_directories
  • target_link_libraries
  • ament_target_dependencies

をまとめてやってくれます

ament_auto_find_build_dependencies

package.xmlから依存を読み取ってfind_packageしてくれます.

ament_auto_generate_code

メッセージのファイルを探してヘッダーなどを自動生成してくれるようですが,未実装のようです.
今後に期待

ament_auto_package

  • ament_export_include_directories
  • ament_export_libraries
  • install

export,install関係を全部やってくれます

最後に

ros2に標準でついてくるament_cmake_autoですが, 非常に便利なのに使っている人も文献も少ないように思えた*3ので今回記事にしてみました.

*1:ROS1でもcatkin_simpleというCMakeを簡単に書くためのパッケージがあります

*2:https://github.com/ament/ament_cmake/tree/master/ament_cmake_auto/cmake

*3:使われているのをAutowareのROS2バージョンであるAutoware.Auto以外に見たことがない...

colconで補完を出す

colcon buildするときとかにcolconと打ってからTABキーで補完をだそうとしてうまくいかない経験はありませんか?

colconで補完が出ない!

colconと打ってからTABキーを押すと以下のようにディレクトリが表示されます.
今欲しい補完はそれじゃない...

$ colcon <TAB>
build/   install/ log/     src/     

colcon bくらいまで打って補完を出すとcolcon build/になってしまい,エラーを吐かれます.

colcon build/
usage: colcon [-h] [--log-base LOG_BASE] [--log-level LOG_LEVEL]
              {build,extension-points,extensions,graph,info,list,metadata,test,test-result,version-check}
              ...
colcon: error: argument verb_name: invalid choice: 'build/' (choose from 'build', 'extension-points', 'extensions', 'graph', 'info', 'list', 'metadata', 'test', 'test-result', 'version-check')

catkinならちゃんと補完出てたのに!!

補完を出す

colconの補完はpython3-colcon-argcompleteというパッケージで提供されています. ROS2のインストール時に一緒に入ってくるはずなので追加でインストールする必要はありません.
ただ,補完を有効にするためにスクリプトを読み込む必要があります.

スクリプト/usr/share/colcon_argcomplete/hook/というディレクトリにあり,colcon-argcomplete.bashを読み込めばOKです.*1

$ colcon <TAB>
build             extension-points  extensions        graph             info              list              --log-base        --log-level       metadata          test              test-result       version-check  

しっかり出ましたね.
よく使う人は.bashrc

source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash

と書いておくと良いでしょう

参考

Installation — colcon documentation

*1:zshの人はcolcon-argcomplete.zshを読み込んでください

ROS2でコードチェック!

TL;DR

## コードチェック!
colcon test
## エラー内容を確認!
colcon test-result --verbose    

コーディング規約

ROS2にはコーディング規約*1があります.*2 ROS2のプログラムを書いている読者の皆さんなら当然規約に則っているとは思いますが,細かいところまできっちり守るのは中々難しいものです.

というわけでROS2のコードチェックを自動化する方法を紹介したいと思います.

確認

ここで述べるものがなければコードチェックがうまく動きませんので動かない場合は確認してみてください.

CMakeLists.txt

よほど変な方法でパッケージを作っていない限り,CMakeLists.txtの最後の方に以下の記述があると思います.

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

もしない場合はCMakeLists.txtの最後にあるament_package()の記述の直前に追加しておきましょう.

package.xml

こちらも通常,はじめから追加されているはずですが念の為.

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

記述が無ければ追加しておきましょう.

チェックの実行

colcon buildした後に以下を実行しましょう.

colcon test

コードチェックはたったこれだけで実行できます. 簡単ですね.

エラーの確認

チェックを実行したら何かしらエラーが出ます.

 Starting >>> crane_bt_executor
 --- stderr: crane_bt_executor
 Errors while running CTest
 ---
 Finished <<< crane_bt_executor [4.00s]    [ with test failures ]

しかし,colcon testだけではこのようにエラーの有無しか分かりません. エラーを修正するためには「どこで」「どのような」エラーが出ているかという情報が必要です. そこで次のコマンドを実行します.

colcon test-result --verbose

以下のような文字列が大量*3に吐き出されて面食らうかも知れませんが何ということはありません.

- crane_bt_executor.cpplint build/include_what_you_use [4] (/root/ros2_ws/src/crane/crane_bt_executor/include/crane_bt_executor/behavior_tree/multi_robot_sequence.hpp:54)
   <<< failure message
     Add #include <memory> for shared_ptr<>
   >>>

しっかり読めば解決策も書いてありますので一つ一つ丁寧に直していきましょう.

ament_lint_autoの気持ちになるですよー

正直,このコードチェックはかなり厳しいです.
はじめのうちは大量のエラーを出して修正に時間がかかりますが慣れると素早くできるようになります. また,そもそもの話としてエラーが少ないプログラムを書けるようになるので心配する必要はありません.
特にチェックが1発で通った*4ときは中々の快感です.

CI

どうせならチェックの実行自体も自動化してしまいましょう.
Gitlab CI/CDやGithub Actionsを使えば簡単にできます.
https://github.com/SSL-Roots/consai2r2/actions/runs/8872558/workflow

CIの設定など細かいことは省きますが結局の所,colcon testを実行しておけばOKです.

次回予告

今回はコードチェックの仕方やエラーの確認方法について書きました.
次回以降は具体的なエラーの内容や運用する上でのtipsなど書いていこうと思います.  

 

 

*1:https://index.ros.org/doc/ros2/Contributing/Code-Style-Language-Versions/

*2:無印ROSにもコーディング規約はありますが無印ROSを使っていた頃の私は恥ずかしながらあまりコーディング規約を守っていませんでした...

*3:適当に書いたプログラムだと500件を超えることも珍しくない

*4:※少々修行が必要です