メインコンテンツ

Unreal Engine シミュレーションを使用した自動バレー パーキングの可視化

この例では、Epic Games® の Unreal Engine® を使用してレンダリングされた 3D シミュレーション環境で車両運動を可視化する方法について説明します。これはSimulink での自動バレー パーキングの例に忠実に従っています。

はじめに

Automated Driving Toolbox™ は Simulink® に Unreal Engine シミュレーション環境を統合します。この環境を使用して、あらかじめ用意されたシーンで車両の運動を可視化できます。この環境では、パス プランニングおよび車両制御アルゴリズムのパフォーマンスを直感的に解析できます。Simulink での自動バレー パーキングの例では、Simulink で自動バレー パーキング システムのためにパス プランニングおよび車両制御アルゴリズムを設計する方法について説明しています。この例では、モデルを拡張して、可視化エンジンを使用してシーン内の車両運動を可視化する方法について説明します。このワークフローの手順は、次のとおりです。

  1. 3D シーンからコストマップを作成する。

  2. シーンからルート計画を作成する。

  3. Simulink で 3D シーンと自車を構成する。

  4. 3D シーンで車両の運動をシミュレーションして可視化する。

この例で開かれたすべてのシステムを最後に閉じることができるように、現在開いているシステムのリストを取得します。

startingOpenSystems = find_system('MatchFilter', @Simulink.match.allVariants);

3D シーンからのコストマップの作成

可視化統合にはあらかじめ用意された多くのシーンが付属しています。各シーンには、シーンの探索に使用できる高解像度のイメージが含まれています。関数 helperShowSceneImage を使用してイメージを表示します。この例では、Large Parking Lotシーンを使用します。

% Load and display the image of the parking lot
sceneName = 'LargeParkingLot';
[sceneImage, sceneRef] = helperGetSceneImage(sceneName);

% Visualize the scene image
figure
helperShowSceneImage(sceneImage, sceneRef)

Figure contains an axes object. The axes object with xlabel X (m), ylabel Y (m) contains an object of type image.

このような高解像度のイメージは、ある程度の解像度まで環境を正確に描いたものです。このイメージを使用して、パス プランニングとナビゲーションのためのvehicleCostmapを作成できます。

まず、イメージからフリー スペースを推定します。フリー スペースとは、車両が駐車中の車、コーン、道路の境界などの他の静的オブジェクトと衝突することなく、またマークが付けられた線を横切ることなく走行できる領域です。この例では、イメージの色に基づいてフリー スペースを推定できます。Image Processing Toolbox から色のしきい値アプリを使用してセグメンテーションを実行し、イメージからバイナリ イメージを生成します。例の最後に次のように補助関数 helperCreateCostmapFromImage を使用してバイナリ イメージを生成することもできます。

sceneImageBinary = helperCreateCostmapFromImage(sceneImage);

あるいは、事前生成されたバイナリ イメージを読み込みます。

sceneImageBinary = imread('sim3d_LargeParkingLotBinary.bmp');

次に、バイナリ イメージからコストマップを作成します。バイナリ イメージを使用して、各セルでコスト値を指定します。

% Get the left-bottom corner location of the map
mapLocation = [sceneRef.XWorldLimits(1), sceneRef.YWorldLimits(1)]; % [meters, meters]

% Compute resolution
mapWidth = sceneRef.XWorldLimits(2)-sceneRef.XWorldLimits(1); % meters
cellSize = mapWidth/size(sceneImageBinary, 2);

% Create the costmap
costmap = vehicleCostmap(im2single(sceneImageBinary), 'CellSize', cellSize, 'MapLocation', mapLocation);

figure
plot(costmap, 'Inflation', 'off');

Figure contains an axes object. The axes object with xlabel X, ylabel Y contains an object of type image.

legend off

3D シーンで使用可能な車両に基づいて、自動的に駐車する車両の寸法を指定する必要もあります。この例では、Hatchbackの寸法を使用しています。これらの寸法は、コストマップと Simulink モデルで一貫している必要があります。

centerToFront = 1.104; % meters
centerToRear  = 1.343; % meters
frontOverhang = 0.828; % meters
rearOverhang  = 0.589; % meters
vehicleWidth  = 1.653; % meters
vehicleHeight = 1.513; % meters
vehicleLength = centerToFront + centerToRear + frontOverhang + rearOverhang;

vehicleDims = vehicleDimensions(vehicleLength, vehicleWidth, vehicleHeight,...
    'FrontOverhang', frontOverhang, 'RearOverhang', rearOverhang);
costmap.CollisionChecker.VehicleDimensions = vehicleDims;

車両を囲む円の数を指定して、インフレーション半径を設定します。

costmap.CollisionChecker.NumCircles = 5;

3D シーンからのルート計画の作成

グローバル ルート計画は、駐車スポットに到達するために移動する車線セグメントのシーケンスとして記述します。Unreal Engine シミュレーションのウェイポイントの選択で説明されているツールを使用して、シーン イメージから中間ゴール位置を対話的に選択することができます。この例では、ルート計画は作成済みで、table に格納されています。シミュレーションを行う前に、モデルのコールバック関数 PreLoadFcn により、ルート計画を読み込みます。

data      = load('routePlanUnreal.mat');
routePlan = data.routePlan %#ok<NOPTS>
routePlan=5×3 table
           StartPose                   EndPose            Attributes
    _______________________    _______________________    __________

     44.5        8      180    -33.5      8.5      180    1×1 struct
    -33.5      8.5      180    -45.2     -0.7      250    1×1 struct
    -45.2     -0.7      250    -33.5    -13.5        0    1×1 struct
    -33.5    -13.5        0    -20.3    -13.5       -7    1×1 struct
    -20.3    -13.5       -7    -13.5     -6.8       90    1×1 struct

% Plot vehicle at the starting pose
startPose = routePlan.StartPose(1,:);
hold on
helperPlotVehicle(startPose, vehicleDims, 'DisplayName', 'Current Pose')
legend

for n = 1 : height(routePlan)
    % Extract the goal waypoint
    vehiclePose = routePlan{n, 'EndPose'};
    
    % Plot the pose
    legendEntry = sprintf('Goal %i', n);
helperPlotVehicle(vehiclePose, vehicleDims, 'DisplayName', legendEntry);
    hold on
end
hold off

Figure contains an axes object. The axes object with xlabel X, ylabel Y contains 43 objects of type image, polygon. These objects represent Current Pose, Goal 1, Goal 2, Goal 3, Goal 4, Goal 5.

3D シーンおよび自車の構成

図を閉じてモデルを開きます。

helperCloseFigures

if ~ispc
    error(['3D Simulation is only supported on Microsoft', char(174), ' Windows', char(174), '.']);
end

modelName = 'APVWith3DSimulation';
open_system(modelName)
snapnow

このモデルは、3D シーンで車両を可視化するための次の 2 つのブロックを追加することで、Simulink での自動バレー パーキングの例で使用されているモデルを拡張したものです。

  • Simulation 3D Scene Configuration:3D シミュレーション環境を実装します。[シーン名] パラメーターは Large parking lot に設定されています。

  • Simulation 3D Vehicle with Ground Following:3D シーンで車両の位置と方向を変更するインターフェイスを提供します。車両の [タイプ] は、costmap の車両の寸法と整合したものになるように、Hatchback に設定されています。このブロックへの入力は、車両の位置 [X, Y] (メートル) および向首角 Yaw (度) です。これらの値は、ワールド座標系のものです。

3 次元シーンでの車両運動の可視化

モデルをシミュレートし、車両がどのように走行して目的の駐車スポットに到達するのかを確認します。

sim(modelName)

Figure Automated Parking Valet contains an axes object. The axes object with title Global costmap, xlabel X, ylabel Y contains 261 objects of type image, line, polygon.

Figure Parking Maneuver contains an axes object. The axes object with title Local costmap, xlabel X, ylabel Y contains 9 objects of type image, line, polygon.

シミュレーションの実行に伴い、Simulink 環境はSimulation 3D Vehicle with Ground Followingブロックを介して 3D 可視化エンジンで車両の位置と方向を更新します。3D 可視化エンジンの新しいウィンドウに自車が示されます。Automated Parking Valet の図で、計画されたパスが青で表示され、車両の実際のパスが赤で表示されます。Parking Maneuver の図は、最終的な駐車の操縦の探索で使用されたローカル コストマップを示しています。

拡張パス プランニング システムの探索

Path Planner ブロックは、最適な RRT* (Rapidly Exploring Random Tree) アルゴリズムを使用して環境マップで実行可能なパスを計画します。プランニング アルゴリズムのパフォーマンスを確保するために、パス プランニング モジュールを変更して次の 2 つの別個のモジュールを組み込みます。

  • Driving Mode:ナビゲーションに駐車場全体のコストマップを使用します。この実装は、Simulink での自動バレー パーキングの例でも使用されています。

  • Parking Mode:最終的な駐車の操縦のためのローカル コストマップを使用します。ローカル コストマップは、正方形のコストマップのサブマップです。このマップのサイズを指定するには、Path Planner ブロック ダイアログ ボックスの [Local costmap size (m)] パラメーターを使用します。コスト マップの寸法が小さいと、最終駐車スポットまでの実行可能なパスの探索における計算負荷が大幅に軽減されます。また、同じプランナー設定で、実行可能なパスが見つかる確率も高くなります。

Path Planner サブシステムを開きます。

open_system([modelName, '/Path Planner'], 'force')

2 つのパス プランナー モジュールがEnabled Subsystem (Simulink)ブロックとして実装されています。イネーブル信号は、Behavior Planner ブロックから送信された入力 Config バスで IsParkingManeuver 信号から送られます。Parking Mode サブシステムが有効になると、車両の現在の位置を中心としてローカル コストマップが作成されます。

モデルと図を閉じます。

endingOpenSystems = find_system('MatchFilter', @Simulink.match.allVariants);
bdclose(setdiff(endingOpenSystems,startingOpenSystems))
helperCloseFigures

まとめ

この例では、3D シミュレーションを既存の Simulink での自動バレー パーキングの例に統合して、3D 駐車場シーンで車両の運動を可視化する方法を示しました。

サポート関数

helperCreateCostmapFromImage

function BW = helperCreateCostmapFromImage(sceneImage) %#ok<DEFNU>
%helperCreateCostmapFromImage Create a costmap from an RGB image.

% Flip the scene image
sceneImage = flipud(sceneImage);

% Call the autogenerated code from the Color Thresholder app
BW = helperCreateMask(sceneImage);

% Smooth the image
BW = im2uint8(medfilt2(BW));

% Resize
BW = imresize(BW, 0.5);

% Compute complement 
BW = imcomplement(BW);
end

helperCreateMask

function [BW,maskedRGBImage] = helperCreateMask(RGB) 
%createMask  Threshold RGB image using auto-generated code from colorThresholder app.
%  [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
%  auto-generated code from the colorThresholder app. The colorspace and
%  range for each channel of the colorspace were set within the app. The
%  segmentation mask is returned in BW, and a composite of the mask and
%  original RGB images is returned in maskedRGBImage.

% Auto-generated by colorThresholder app on 22-Oct-2021
%------------------------------------------------------


% Convert RGB image to chosen color space
I = RGB;

% Define thresholds for channel 1 based on histogram settings
channel1Min = 42.000;
channel1Max = 179.000;

% Define thresholds for channel 2 based on histogram settings
channel2Min = 66.000;
channel2Max = 191.000;

% Define thresholds for channel 3 based on histogram settings
channel3Min = 67.000;
channel3Max = 164.000;

% Create mask based on chosen histogram thresholds
sliderBW = (I(:,:,1) >= channel1Min ) & (I(:,:,1) <= channel1Max) & ...
    (I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
    (I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);
BW = sliderBW;

% Initialize output masked image based on input image.
maskedRGBImage = RGB;

% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;
end

helperCloseFigures

function helperCloseFigures()
%helperCloseFigures Close all the figures except the simulation visualization

% Find all the figure objects
figHandles = findobj('Type', 'figure');

% Close the figures
for i = 1: length(figHandles)
    close(figHandles(i));
end
end

参考

ブロック

関数

アプリ

トピック