設定ファイルから見る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
最後に
本当はもっと色々なことを書こうと思っていたのですが、想像以上に長くなりそうだったので別の記事に分けようと思います。 それではまた次の記事で。