Main Content

プログラムでのドライビング シナリオの作成

この例では、合成センサー データおよび追跡アルゴリズム用にグラウンド トゥルースを生成する方法について説明します。また、開ループおよび閉ループのシミュレーションでアクターの姿勢を更新する方法についても説明します。最後に、ドライビング シナリオを使用して座標変換を実行して鳥瞰図プロットに取り込む方法について説明します。

この例では、MATLAB® コマンド ラインからドライビング シナリオをプログラムで作成します。あるいは、Driving Scenario Designerアプリを使用してシナリオを対話的に作成することもできます。例については、Create Driving Scenario Interactively and Generate Synthetic Sensor Dataを参照してください。

はじめに

ドライビング シナリオの目標の 1 つは、特定の車両で使用されるセンサー検出および追跡アルゴリズムで使用する「グラウンド トゥルース」のテスト ケースを生成することです。

このグラウンド トゥルースは通常、グローバル座標系で定義されます。しかし、通常センサーは移動する車両に取り付けられているため、このデータを車両とともに移動する基準座標系に変換する必要があります。ドライビング シナリオによってこの変換が自動的に行われるので、グローバル座標で道路およびオブジェクトの軌跡を指定できます。また、シナリオ内の任意のアクターの基準座標系でこの情報を変換および可視化するツールも用意されています。

姿勢情報をアクターの基準座標系に変換

drivingScenario は、道路およびアクターと呼ばれる移動可能なオブジェクトのモデルで構成されます。アクターを使用して歩行者、パーキング メーター、消火栓などのシナリオ内のオブジェクトをモデル化できます。アクターは、長さ、幅、高さ、およびレーダー反射断面積 (RCS) をもつ直方体で構成されます。アクターは、下面の中心にある単一の点を基準に配置および方向付けされます。

車輪で動く特殊なアクターが車両です。車両は、回転するためのより自然な中心である、後車軸の中心の真下にある地面上を基準に配置および方向付けられます。

すべてのアクター (車両を含む) は、それぞれの PositionRollPitchYawVelocity、および AngularVelocity の各プロパティを指定してシナリオ内の任意の位置に配置できます。

10 メートル離れた 2 台の車両がそれぞれ秒速 3 メートルと 4 メートルで原点に向かって走行するシナリオの例を示します。

scenario = drivingScenario;
v1 = vehicle(scenario,'ClassID',1','Position',[6 0 0],'Velocity',[-3 0 0],'Yaw',180)
v1 = 

  Vehicle with properties:

         FrontOverhang: 0.9000
          RearOverhang: 1
             Wheelbase: 2.8000
             EntryTime: 0
              ExitTime: Inf
               ActorID: 1
               ClassID: 1
                  Name: ""
             PlotColor: [0 0.4470 0.7410]
              Position: [6 0 0]
              Velocity: [-3 0 0]
                   Yaw: 180
                 Pitch: 0
                  Roll: 0
       AngularVelocity: [0 0 0]
                Length: 4.7000
                 Width: 1.8000
                Height: 1.4000
                  Mesh: [1x1 extendedObjectMesh]
            RCSPattern: [2x2 double]
      RCSAzimuthAngles: [-180 180]
    RCSElevationAngles: [-90 90]

v2 = vehicle(scenario,'ClassID',1,'Position',[0 10 0],'Velocity',[0 -4 0],'Yaw',-90)
v2 = 

  Vehicle with properties:

         FrontOverhang: 0.9000
          RearOverhang: 1
             Wheelbase: 2.8000
             EntryTime: 0
              ExitTime: Inf
               ActorID: 2
               ClassID: 1
                  Name: ""
             PlotColor: [0.8500 0.3250 0.0980]
              Position: [0 10 0]
              Velocity: [0 -4 0]
                   Yaw: -90
                 Pitch: 0
                  Roll: 0
       AngularVelocity: [0 0 0]
                Length: 4.7000
                 Width: 1.8000
                Height: 1.4000
                  Mesh: [1x1 extendedObjectMesh]
            RCSPattern: [2x2 double]
      RCSAzimuthAngles: [-180 180]
    RCSElevationAngles: [-90 90]

シナリオを可視化するために、次のように関数 plot を呼び出します。

plot(scenario);
set(gcf,'Name','Scenario Plot')
xlim([-20 20]);
ylim([-20 20]);

シナリオ内のすべてのアクターが作成されたら、各アクターの PositionRollPitchYawVelocity、および AngularVelocity の各プロパティを調べて、シナリオの座標ですべてのアクターの姿勢情報を確認できます。あるいは、シナリオで関数 actorPoses を呼び出して、簡便な構造体ですべてを取得することもできます。

ap = actorPoses(scenario)
ap = 

  2x1 struct array with fields:

    ActorID
    Position
    Velocity
    Roll
    Pitch
    Yaw
    AngularVelocity

独自の基準座標系で特定のアクターから見た他のすべてのオブジェクト (ターゲット) の姿勢情報を取得するには、そのアクター自体で関数 targetPoses を呼び出すことができます。

v2TargetPoses = targetPoses(v2)
v2TargetPoses = 

  struct with fields:

            ActorID: 1
            ClassID: 1
           Position: [10 6.0000 0]
           Velocity: [-4 -3.0000 0]
               Roll: 0
              Pitch: 0
                Yaw: -90.0000
    AngularVelocity: [0 0 0]

車両の追跡プロットを追加することで、相対的な車両の配置を定性的に確認できます。既定では、追跡プロットには、車両より固定距離分後ろから見た射影パースペクティブ ビューが表示されます。

ここでは、2 番目の車両 (赤) のすぐ後ろから見たパースペクティブを表示します。ターゲットの姿勢は、2 番目の車両から見ると、2 番目の車両の 6 メートル前方、10 メートル左方にこのもう 1 台の車両 (青) の位置があることが示されます。これを追跡プロットで次のように定性的に表示できます。

chasePlot(v2)
set(gcf,'Name','Chase Plot')

通常、ドライビング シナリオに関連したプロットはすべて、シミュレーション中に関数 advance を呼び出すと更新されます。別のアクターの位置プロパティを手動で更新した場合、次のように updatePlots を呼び出して結果を即時に表示できます。

v1.Yaw = 135;
updatePlots(scenario);

道路の境界をアクターの基準座標系に変換

ドライビング シナリオを使用して、シナリオで定義されている道路の境界を取得することもできます。

ここでは、Define Road Layouts Programmaticallyで説明されている単純な楕円形のトラックを利用します。このトラックは縦約 200 メートル、横約 100 メートルであり、曲線部分のバンク角は 9 度です。

scenario = drivingScenario;
roadCenters = ...
    [  0  40  49  50 100  50  49 40 -40 -49 -50 -100  -50  -49  -40    0
     -50 -50 -50 -50   0  50  50 50  50  50  50    0  -50  -50  -50  -50
       0   0 .45 .45 .45 .45 .45  0   0 .45 .45  .45  .45  .45    0    0]';
bankAngles = ...
    [  0   0   9   9   9   9   9  0   0   9   9    9    9    9    0    0];

road(scenario, roadCenters, bankAngles, 'lanes', lanespec(2));
plot(scenario);

道路の境界を定義する線を取得するには、ドライビング シナリオで関数 roadBoundaries を使用します。道路の境界 (上のシナリオ プロットでは黒の実線) が格納された cell 配列が返されます。

rb = roadBoundaries(scenario)
rb =

  1x2 cell array

    {258x3 double}    {258x3 double}

上の例では、道路の境界が 2 本あります (外側の境界と内側の境界)。次のようにプロットできます。

figure

outerBoundary = rb{1};
innerBoundary = rb{2};

plot3(innerBoundary(:,1),innerBoundary(:,2),innerBoundary(:,3),'r', ...
      outerBoundary(:,1),outerBoundary(:,2),outerBoundary(:,3),'g')
axis equal

アクターで関数 roadBoundaries を使用して、アクターの座標で道路の境界を取得できます。それを行うには、最初の引数としてシナリオではなくアクターを渡します。

これを確認するために、次のように "自車" を追加してトラック上に配置します。

egoCar = vehicle(scenario,'ClassID',1,'Position',[80 -40 0.45],'Yaw',30);

次に、車両で関数 roadBoundaries を呼び出して前と同じようにプロットします。次のように車両の座標を基準としてレンダリングされます。

figure

rb = roadBoundaries(egoCar)
outerBoundary = rb{1};
innerBoundary = rb{2};

plot3(innerBoundary(:,1),innerBoundary(:,2),innerBoundary(:,3),'r', ...
      outerBoundary(:,1),outerBoundary(:,2),outerBoundary(:,3),'g')
axis equal
rb =

  1x2 cell array

    {258x3 double}    {258x3 double}

アクターの軌跡を指定

事前定義された 3 次元パスに沿って特定のアクターを配置およびプロットできます。

以下に、レーストラックを走行する 2 台の車両の例を示します。それぞれが別個のレーンを 30 m/s と 50 m/s の速度で走行しています。レーン幅 2.7 メートルの半分、トラックのバンク角セクションでは両側に垂直高さの半分のオフセット位置を設定することで、道路の中央から車をオフセットします。

chasePlot(egoCar);
fastCar = vehicle(scenario,'ClassID',1);

d = 2.7/2;
h = .45/2;
roadOffset = [ 0  0  0  0  d  0  0  0  0  0  0 -d  0  0  0  0
              -d -d -d -d  0  d  d  d  d  d  d  0 -d -d -d -d
               0  0  h  h  h  h  h  0  0  h  h  h  h  h  0  0]';

rWayPoints = roadCenters + roadOffset;
lWayPoints = roadCenters - roadOffset;

% loop around the track four times
rWayPoints = [repmat(rWayPoints(1:end-1,:),5,1); rWayPoints(1,:)];
lWayPoints = [repmat(lWayPoints(1:end-1,:),5,1); lWayPoints(1,:)];

smoothTrajectory(egoCar,rWayPoints(:,:), 30);
smoothTrajectory(fastCar,lWayPoints(:,:), 50);

シミュレーションの進行

軌跡を追従するアクターは、ドライビング シナリオで advance を呼び出すことで更新されます。advance が呼び出されると、軌跡を追従している各アクターは前進し、対応するプロットが更新されます。軌跡が定義されているアクターのみが実際に更新されます。これは、シミュレーションの実行中に独自のロジックを用意できるようにするためです。

シナリオの SampleTime プロパティにより、更新間隔を制御します。既定では 10 ミリ秒ですが、次のように任意の間隔を指定できます。

scenario.SampleTime = 0.02
scenario = 

  drivingScenario with properties:

        SampleTime: 0.0200
          StopTime: Inf
    SimulationTime: 0
         IsRunning: 1
            Actors: [1x2 driving.scenario.Vehicle]
          Barriers: [0x0 driving.scenario.Barrier]
       ParkingLots: [0x0 driving.scenario.ParkingLot]

while ループの条件文で advance を呼び出し、ループの本体にシナリオを検査または変更するコマンドを配置することで、シミュレーションを実行できます。

車両の軌跡が終了するか、オプションの StopTime に達すると、while ループは自動的に終了します。

scenario.StopTime = 4;
while advance(scenario)
  pause(0.001)
end

シナリオの記録

すべてのアクターの軌跡が事前にわかっている場合に簡便な方法として、シナリオで関数 record を呼び出して、各タイム ステップにおける各アクターの姿勢情報が格納された構造体を返すことができます。

たとえば、次のように、シミュレーションの最初の 100 ミリ秒間、各アクターの姿勢情報を検査し、5 番目に記録されたサンプルを検査できます。

close all

scenario.StopTime = 0.100;
poseRecord = record(scenario)

r = poseRecord(5)
r.ActorPoses(1)
r.ActorPoses(2)
poseRecord = 

  1x5 struct array with fields:

    SimulationTime
    ActorPoses


r = 

  struct with fields:

    SimulationTime: 0.0800
        ActorPoses: [2x1 struct]


ans = 

  struct with fields:

            ActorID: 1
           Position: [2.4000 -51.3502 0]
           Velocity: [30.0000 -0.0038 0]
               Roll: 0
              Pitch: 0
                Yaw: -0.0073
    AngularVelocity: [0 0 -0.0823]


ans = 

  struct with fields:

            ActorID: 2
           Position: [4.0000 -48.6504 0]
           Velocity: [50.0000 -0.0105 0]
               Roll: 0
              Pitch: 0
                Yaw: -0.0120
    AngularVelocity: [0 0 -0.1235]

鳥瞰図プロットを使用した複数のビューの組み込み

シミュレーションのデバッグ時に、特定のアクターの鳥瞰図プロットに "グラウンド トゥルース" データをレポートする一方で、シナリオによって生成されたプロットを同時に表示する場合があります。これを行うにはまず、次のように座標軸がカスタム配置された図を作成します。

close all;
hFigure = figure;
hFigure.Position(3) = 900;

hPanel1 = uipanel(hFigure,'Units','Normalized','Position',[0 1/4 1/2 3/4],'Title','Scenario Plot');
hPanel2 = uipanel(hFigure,'Units','Normalized','Position',[0 0 1/2 1/4],'Title','Chase Plot');
hPanel3 = uipanel(hFigure,'Units','Normalized','Position',[1/2 0 1/2 1],'Title','Bird''s-Eye Plot');

hAxes1 = axes('Parent',hPanel1);
hAxes2 = axes('Parent',hPanel2);
hAxes3 = axes('Parent',hPanel3);

座標軸の定義が終わったら、プロットを作成する際に次のように Parent プロパティでその座標軸を指定します。

% assign scenario plot to first axes and add indicators for ActorIDs 1 and 2
plot(scenario, 'Parent', hAxes1,'ActorIndicators',[1 2]);

% assign chase plot to second axes
chasePlot(egoCar, 'Parent', hAxes2);

% assign bird's-eye plot to third axes
egoCarBEP = birdsEyePlot('Parent',hAxes3,'XLimits',[-200 200],'YLimits',[-240 240]);
fastTrackPlotter = trackPlotter(egoCarBEP,'MarkerEdgeColor','red','DisplayName','target','VelocityScaling',.5);
egoTrackPlotter = trackPlotter(egoCarBEP,'MarkerEdgeColor','blue','DisplayName','ego','VelocityScaling',.5);
egoLanePlotter = laneBoundaryPlotter(egoCarBEP);
plotTrack(egoTrackPlotter, [0 0]);
egoOutlinePlotter = outlinePlotter(egoCarBEP);

次に、シミュレーションを再開して完了するまで実行します。今度は targetPoses を介してターゲットの車の位置情報を抽出して鳥瞰図プロットに表示します。同様に、自車から直接 roadBoundaries および targetOutlines を呼び出して、道路の境界およびアクターのアウトラインを抽出することもできます。鳥瞰図プロットでは、次のようにこれらの関数の結果を直接表示できます。

restart(scenario)
scenario.StopTime = Inf;

while advance(scenario)
    t = targetPoses(egoCar);
    plotTrack(fastTrackPlotter, t.Position, t.Velocity);
    rbs = roadBoundaries(egoCar);
    plotLaneBoundary(egoLanePlotter, rbs);
    [position, yaw, length, width, originOffset, color] = targetOutlines(egoCar);
    plotOutline(egoOutlinePlotter, position, yaw, length, width, 'OriginOffset', originOffset, 'Color', color);
end

次のステップ

この例では、drivingScenario オブジェクトを使用して合成センサー データおよび追跡アルゴリズムのグラウンド トゥルースを生成して可視化する方法を示しました。対話型環境でこのドライビング シナリオをシミュレート、可視化、または変更するには、次のように drivingScenario オブジェクトをドライビング シナリオ デザイナー アプリにインポートしてください。

drivingScenarioDesigner(scenario)

詳細情報

アクターおよび道路を定義する方法の詳細については、Create Actor and Vehicle Trajectories ProgrammaticallyおよびDefine Road Layouts Programmaticallyを参照してください。

検出および追跡で鳥瞰図プロットを使用する方法の詳細な例については、Visualize Sensor Coverage, Detections, and Tracksを参照してください。

ドライビング シナリオを使用して合成データの生成を支援する例については、Model Radar Sensor DetectionsModel Vision Sensor Detections、およびSensor Fusion Using Synthetic Radar and Vision Dataを参照してください。

参考

アプリ

オブジェクト

関数

関連するトピック