В этом примере показано, как генерировать достоверность данных синтетических датчиков и алгоритмов отслеживания. Также показано, как обновлять позы актера в моделировании с разомкнутым и замкнутым контуром. Наконец, он показывает, как использовать сценарий вождения для выполнения преобразования координат и включения их в график птичьего глаза.
В этом примере программно создается сценарий управления из командной строки MATLAB ®. Кроме того, сценарии можно создавать в интерактивном режиме с помощью приложения Конструктор сценариев управления. Пример см. в разделах Создание сценария управления в интерактивном режиме и Создание данных синтетических датчиков.
Одной из целей сценария вождения является генерация тестовых примеров «наземной правды» для использования с алгоритмами обнаружения и отслеживания датчиков, используемыми на конкретном транспортном средстве.
Эта основная истина обычно определяется в глобальной системе координат; но, поскольку датчики обычно установлены на движущемся транспортном средстве, эти данные должны быть преобразованы в опорную рамку, которая перемещается вместе с транспортным средством. Сценарий управления обеспечивает автоматическое преобразование, позволяя задавать дороги и траектории объектов в глобальных координатах, а также предоставляет инструменты для преобразования и визуализации этой информации в системе отсчета любого участника сценария.
A drivingScenario состоит из модели дорог и подвижных объектов, называемых актёрами. Актеры можно использовать для моделирования пешеходов, стояночных счетчиков, пожарных гидрантов и других объектов в рамках сценария. Актеры состоят из кубоидов длиной, шириной, высотой и радиолокационным сечением (RCS). Актер позиционируется и ориентируется вокруг одной точки в центре его нижней грани.
Особый вид актера, который движется на колесах, - это транспортное средство, которое расположено и ориентировано на земле прямо под центром задней оси, который является более естественным центром вращения.
Все субъекты (включая транспортные средства) могут быть размещены в любом месте сценария путем указания их соответствующих Position, Roll, Pitch, Yaw, Velocity, и AngularVelocity свойства.
Ниже приведен пример сценария, состоящего из двух транспортных средств, находящихся на расстоянии 10 метров друг от друга и движущихся по направлению к началу координат со скоростью 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]);

После создания всех действующих лиц в сценарии можно проверить информацию о позе всех действующих лиц в координатах сценария путем проверки Position, Roll, Pitch, Yaw, Velocity, и 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]
Мы можем качественно подтвердить относительное размещение транспортного средства, добавив график погони для транспортного средства. По умолчанию на графике погона отображается проективно-перспективный вид с фиксированного расстояния позади транспортного средства.
Здесь мы показываем перспективу, видимую сразу за вторым транспортным средством (красным). Позиции цели, видимые вторым транспортным средством, показывают, что местоположение другого транспортного средства (синим цветом) составляет 6 м вперед и 10 м слева от второго транспортного средства. Мы можем увидеть это качественно в сюжете погони:
chasePlot(v2) set(gcf,'Name','Chase Plot')

Как правило, все графики, связанные со сценарием управления, обновляются в ходе моделирования при вызове advance функция. При обновлении свойства position другого актера вручную можно вызвать updatePlots для немедленного просмотра результатов:
v1.Yaw = 135; updatePlots(scenario);


Сценарий вождения может также использоваться для извлечения границ дорог, определенных в сценарии.
Здесь мы используем простую овальную дорожку, описанную в документе Определение планировок дорог программно, которая занимает площадь примерно 200 метров в длину и 100 метров в ширину и кривые которой имеют угол наклона в девять градусов:
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 функция в сценарии управления. Он возвращает массив ячеек, содержащий границы дороги (показанные на приведенном выше графике сценария как сплошные черные линии).
rb = roadBoundaries(scenario)
rb =
1x2 cell array
{258x3 double} {258x3 double}
В приведенном выше примере имеется две границы дороги (внешняя и внутренняя границы). Вы можете построить их самостоятельно следующим образом:
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}

Можно расположить и построить график для любого конкретного субъекта по предварительно определенной трехмерной траектории.
Ниже приведен пример для двух транспортных средств, которые следуют по гоночному треку со скоростью 30 м/с и 50 м/с соответственно, каждый из которых находится в собственной соответствующей полосе. Сместим машины от центра дороги, установив смещенное положение на половину ширины полосы 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]
Вы можете запустить моделирование, позвонив advance в условном цикле while и команды размещения для проверки или изменения сценария в теле цикла.
Цикл while будет автоматически заканчиваться по завершении траектории для любого транспортного средства или опционально StopTime был достигнут.
scenario.StopTime = 4; while advance(scenario) pause(0.001) end


В качестве удобства, когда траектории всех актеров известны заранее, можно назвать record функция в сценарии возвращает структуру, которая содержит информацию о позе каждого субъекта на каждом шаге времени.
Например, можно проверить информацию о позе каждого актера в течение первых 100 миллисекунд моделирования и проверить пятый зарегистрированный образец:
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)
Дополнительные сведения об определении акторов и дорог см. в разделах Программное создание траекторий акторов и транспортных средств и Программное определение планировок дорог.
Более подробный пример использования графика птичьего глаза с обнаружениями и дорожками см. в разделе Визуализация покрытия датчиков, обнаружений и дорожек.
Примеры использования сценария управления для получения синтетических данных см. в разделах Обнаружение датчиков модели радара, Обнаружение датчиков модели зрения и Слияние датчиков с использованием синтетических данных радара и зрения.
actorPoses | chasePlot | record | road | roadBoundaries | targetPoses | updatePlots | vehicle