В этом примере показано, как плавить дорожки от двух транспортных средств для того, чтобы обеспечить более всестороннюю оценку среды, которая видна каждому транспортному средству. Пример демонстрирует использование термофиксатора уровня дорожки и объектного формата данных дорожки. В этом примере вы используете ведущий сценарий и модели от Automated Driving Toolbox™ и отслеживания и отслеживаете модели сплава от Sensor Fusion and Tracking Toolbox™.
Автомобильные приложения безопасности используют сплав данных из различных систем датчика, смонтированных на транспортном средстве. Отдельные транспортные средства плавят обнаружения датчика или при помощи централизованного средства отслеживания или путем проявления более децентрализованного подхода и плавления дорожек, произведенных отдельными датчиками. В дополнение к сплаву данных о внутритранспортном средстве сплав данных из нескольких транспортных средств предоставляет дополнительные преимущества, которые включают лучшее покрытие, ситуативную осведомленность и безопасность. [1] Этот подход сплава датчика межтранспортного средства использует в своих интересах множество датчиков и предоставляет лучше страховую защиту к каждому транспортному средству, потому что это использует данные, обновленные датчиками на других транспортных средствах в области. Правительства и производители транспортного средства долго распознавали потребность поделиться информацией между транспортными средствами для того, чтобы увеличить автомобильную безопасность. Например, Сервис Dedicated Short-Range Communications (DSRC) был установлен, чтобы обеспечить коммуникационное обслуживание для совместного пользования информацией межтранспортного средства. [2]
В то время как сплав датчика через несколько транспортных средств выгоден, большинство транспортных средств требуется, чтобы выполнять определенным требованиям техники безопасности, даже если только внутренние датчики доступны. Поэтому транспортное средство, вероятно, будет оборудовано средством отслеживания и/или термофиксатором дорожки, которые обеспечивают ситуативную осведомленность на одном уровне транспортного средства. В результате предположение, сделанное в этом примере, - то, что транспортные средства совместно используют ситуативную осведомленность путем широковещательной передачи дорожек и выполнения сплава от дорожки к дорожке.
Этот пример демонстрирует преимущество плавления дорожек от двух транспортных средств, чтобы улучшить ситуативную осведомленность и безопасность. Обратите внимание на то, что этот пример не симулирует системы связи. Вместо этого пример принимает, что система связи обеспечивает пропускную способность, требуемую передать дорожки между этими двумя транспортными средствами.
Следующая блок-схема изображает основные функции в этих двух транспортных средствах.
Транспортное средство 1 имеет два датчика, каждое обеспечение обнаружения к локальному средству отслеживания. Средство отслеживания использует обнаружения от локальных датчиков до отслеживаемых объектов и выводит эти локальные дорожки к термофиксатору дорожки транспортного средства. Транспортное средство 2 имеет один датчик, который кормит обнаружениями локальное средство отслеживания на транспортном средстве 2. Локальные дорожки от транспортного средства 2 являются входом к локальному термофиксатору дорожки на транспортном средстве 2.
Термофиксатор дорожки на каждом транспортном средстве плавит локальные дорожки транспортного средства с дорожками, полученными от термофиксатора дорожки другого транспортного средства. После каждого обновления термофиксатор дорожки на каждом транспортном средстве широковещательно передает свои сплавленные дорожки, которые питаются в следующее обновление термофиксатора дорожки на другом транспортном средстве.
В этом примере вы используете trackerJPDA
объект задать каждое средство отслеживания транспортного средства.
% Create trackers for each vehicle v1Tracker = trackerJPDA('TrackerIndex',1, 'DeletionThreshold', [4 4]); % Vehicle 1 tracker v2Tracker = trackerJPDA('TrackerIndex',2, 'DeletionThreshold', [4 4]); % Vehicle 2 tracker posSelector = [1 0 0 0 0 0; 0 0 1 0 0 0];
Обратите внимание на то, что в этой архитектуре, сплавленные дорожки от одного транспортного средства используются, чтобы обновить сплавленные дорожки на другом транспортном средстве. Эти сплавленные дорожки затем широковещательно передаются назад к первому транспортному средству. Избежать распространения слуха, быть осторожным, как дорожки от другого транспортного средства используются, чтобы обновить термофиксатор дорожки.
Рассмотрите следующий пример распространения слуха: на некотором шаге обновления, транспортное средство 1 дорожка объект с помощью его внутренних датчиков. Транспортное средство 1 затем предохранители объектная дорожка и передачи это, чтобы транспортировать 2, который теперь плавит дорожку с ее собственными дорожками и узнает объект. До этой точки это - точно цель сплава от дорожки к дорожке: улучшать ситуативную осведомленность о транспортном средстве 2 с информацией от транспортного средства 1. Поскольку транспортное средство 2 теперь знает об объекте, оно начинает широковещательно передавать дорожку также, возможно, в пользу другого транспортного средства (не показанный в примере).
Однако транспортное средство 1 теперь получает информацию о дорожке от транспортного средства 2 об объекте что только транспортное средство 1 на самом деле дорожки. Так, термофиксатор дорожки на транспортном средстве 1 должен иметь в виду, что дорожки, которые это получает от транспортного средства 2 об этом объекте, на самом деле не содержат новой информации, обновленной независимым источником. Чтобы сделать различие между дорожками, которые содержат новую информацию и дорожки, которые только повторяют информацию, необходимо задать транспортное средство 2 как внешний источник к термофиксатору дорожки на транспортном средстве 1. Точно так же транспортное средство 1 должно быть задано как внешний источник к термофиксатору дорожки на транспортном средстве 2. Кроме того, необходимо задать только дорожки, которые обновляются термофиксатором дорожки на основе информации из внутреннего источника, как самосообщается. Путем выполнения так, термофиксатор дорожки в каждом транспортном средстве может проигнорировать обновления от дорожек, которые возвращаются назад и вперед между термофиксаторами дорожки без любой новой информации в них.
Локальное средство отслеживания каждого транспортного средства отслеживает объекты относительно системы координат транспортного средства, названной системой координат эго. Сплав от дорожки к дорожке сделан в системе координат сценария, которая является системой координат глобального уровня. Помощник egoToScenario
функционируйте преобразовывает дорожки от системы координат эго до системы координат сценария. Точно так же функциональный scenarioToEgo
преобразовывает дорожки от системы координат сценария до любой из систем координат эго. Оба преобразования используют StateParameters
свойство objectTrack
объекты. Обратите внимание на то, что, когда trackFuser
объект вычисляет расстояние центральной дорожки (в системе координат сценария) к локальной дорожке (в любой системе координат), это использует StateParameters
из локальной дорожки, чтобы выполнить координатное преобразование.
Достигнуть вышеупомянутого trackFuser
определения, задайте следующие источники как fuserSourceConfiguration
объект.
% Define sources for each vehicle v1TrackerConfiguration = fuserSourceConfiguration('SourceIndex',1,'IsInternalSource',true, ... % v1Tracker is internal to v1Fuser "CentralToLocalTransformFcn", @scenarioToEgo, 'LocalToCentralTransformFcn', @egoToScenario); % Coordinate transformation v2FuserConfiguration = fuserSourceConfiguration('SourceIndex',4,'IsInternalSource',false); % v2Fuser is external to v2Fuser v1Sources = {v1TrackerConfiguration; v2FuserConfiguration}; v2TrackerConfiguration = fuserSourceConfiguration('SourceIndex',2,'IsInternalSource',true, ... % v2Tracker is internal to v2Fuser "CentralToLocalTransformFcn", @scenarioToEgo, 'LocalToCentralTransformFcn', @egoToScenario); % Coordinate transformation v2FuserConfiguration = fuserSourceConfiguration('SourceIndex',3,'IsInternalSource',false); % v1Fuser is external to v2Fuser v2Sources = {v2TrackerConfiguration; v2FuserConfiguration};
Можно теперь задать каждый термофиксатор дорожки транспортного средства как trackFuser
объект.
stateParams = struct('Frame','Rectangular','Position',[0 0 0],'Velocity',[0 0 0]); v1Fuser = trackFuser('FuserIndex',3,... 'MaxNumSources',2,'SourceConfigurations',v1Sources,... 'StateFusion','Intersection','DeletionThreshold',[3 3],... 'StateParameters',stateParams); v2Fuser = trackFuser('FuserIndex',4,... 'MaxNumSources',2,'SourceConfigurations',v2Sources,'StateFusion',... 'Intersection','DeletionThreshold',[3 3],... 'StateParameters',stateParams); % Initialize the following variables fusedTracks1 = objectTrack.empty(0,1); fusedTracks2 = objectTrack.empty(0,1); wasFuser1Updated = false; wasFuser2Updated = false;
Следующий сценарий показывает два транспортных средства, едущие по улице. Транспортное средство 1 лидирует, оборудованное двумя перспективными датчиками: ближний радар и датчик видения. Транспортное средство 2, ведущие 10 метров позади транспортного средства 1, оборудовано радаром дальним. Правая сторона улицы содержит припаркованные транспортные средства. Пешеход стоит между транспортными средствами. Этот пешеход показывается точкой приблизительно в X = 60 метров.
Из-за короткого расстояния между транспортным средством 2 и транспортным средством 1, большая часть транспортного средства 2 радарных покрытия датчика закрываются транспортным средством 1. В результате большинство дорожек, которые обеспечивает термофиксатор дорожки на транспортном средстве 2, сначала инициализируется широковещательной передачей дорожек от транспортного средства 1.
% Create the drivingScenario object and the two vehicles [scenario, vehicle1, vehicle2] = createDrivingScenario; % Create all the sensors [sensors, numSensors, attachedVehicle] = createSensors(scenario); % Create display [f,plotters] = createT2TDisplay(scenario, sensors, attachedVehicle);
Следующий график преследования замечен с точки зрения второго транспортного средства. Стрелка указывает на положение пешехода, который почти полностью закрывается припаркованными транспортными средствами и первым транспортным средством.
% Define each vehicle as a vehicle, sensors, a tracker, and plotters v1 = struct('Actor', {vehicle1}, 'Sensors', {sensors(attachedVehicle==1)}, 'Tracker', {v1Tracker}, 'DetPlotter', {plotters.veh1DetPlotter}, 'TrkPlotter', {plotters.veh1TrkPlotter}); v2 = struct('Actor', {vehicle2}, 'Sensors', {sensors(attachedVehicle==2)}, 'Tracker', {v2Tracker}, 'DetPlotter', {plotters.veh2DetPlotter}, 'TrkPlotter', {plotters.veh2TrkPlotter});
Следующий код запускает симуляцию.
running = true; % For repeatable results, set the random number seed s = rng; rng(2019) snaptimes = [0.5, 2.6, 4.4, 6.3, inf]; snaps = cell(numel(snaptimes,1)); i = 1; f.Visible = 'on'; while running && ishghandle(f) time = scenario.SimulationTime; % Detect and track at the vehicle level [tracks1,wasTracker1Updated] = detectAndTrack(v1,time,posSelector); [tracks2,wasTracker2Updated] = detectAndTrack(v2,time,posSelector); % Keep the tracks from the previous fuser update oldFusedTracks1 = fusedTracks1; oldFusedTracks2 = fusedTracks2; % Update the fusers if wasTracker1Updated || wasFuser2Updated tracksToFuse1 = [tracks1;oldFusedTracks2]; if isLocked(v1Fuser) || ~isempty(tracksToFuse1) [fusedTracks1,~,~,info1] = v1Fuser(tracksToFuse1,time); wasFuser1Updated = true; pos = getTrackPositions(fusedTracks1,posSelector); plotTrack(plotters.veh1FusePlotter,pos); else wasFuser1Updated = false; fusedTracks1 = objectTrack.empty(0,1); end else wasFuser1Updated = false; fusedTracks1 = objectTrack.empty(0,1); end if wasTracker2Updated || wasFuser1Updated tracksToFuse2 = [tracks2;oldFusedTracks1]; if isLocked(v2Fuser) || ~isempty(tracksToFuse2) [fusedTracks2,~,~,info2] = v2Fuser(tracksToFuse2,time); wasFuser2Updated = true; pos = getTrackPositions(fusedTracks2,posSelector); ids = string([fusedTracks2.TrackID]'); plotTrack(plotters.veh2FusePlotter,pos,ids); else wasFuser2Updated = false; fusedTracks2 = objectTrack.empty(0,1); end else wasFuser2Updated = false; fusedTracks2 = objectTrack.empty(0,1); end % Update the display updateT2TDisplay(plotters, scenario, sensors, attachedVehicle) % Advance the scenario one time step and exit the loop if the scenario is complete running = advance(scenario); % Snap a shot at required times if time >= snaptimes(i) snaps{i} = getframe(f); i = i + 1; end end
Рисунок показывает сцену и отслеживающие результаты в конце сценария.
Когда симуляция начинается, транспортное средство 1 обнаруживает транспортные средства, припаркованные на правой стороне улицы, затем дорожки, сопоставленные с припаркованными транспортными средствами, подтверждены. В это время единственный объект обнаружил и прослеженный транспортным средством, 2 средства отслеживания являются транспортным средством 1 сразу перед ним. Однажды транспортное средство 1 термофиксатор дорожки подтверждает дорожки, это широковещательно передает их и транспортное средство, 2 термофиксатора дорожки плавят их. В результате транспортное средство 2 узнает припаркованные транспортные средства, прежде чем оно сможет обнаружить их самостоятельно.
showsnap(snaps, 1)
В то время как симуляция продолжается, транспортное средство 2 может обнаружить и отследить транспортные средства, припаркованные в стороне также, и плавит их с дорожками, прибывающими из транспортного средства 1. Транспортное средство 2 может обнаружить и отследить пешехода приблизительно 4 секунды в симуляцию и транспортное средство 2 предохранителя дорожка, сопоставленная с пешеходом приблизительно 4,4 секунды в симуляцию (см. снимок состояния 2). Однако это садится в транспортное средство 2 приблизительно за две секунды до того, как это сможет обнаружить и отследить пешехода своими собственными датчиками (см. снимок состояния 3). Эти две секунды могли оказать огромное влияние на безопасность пешехода, если бы тот пешеход начал пересекать улицу.
showsnap(snaps, 2)
showsnap(snaps, 3)
Наконец, отметьте, как, когда транспортные средства передают объекты, и эти объекты выходят из своего поля зрения, сплавленные дорожки, сопоставленные с этими объектами, пропущены обоими средствами отслеживания (см. снимок состояния 4). Отбрасывание дорожек демонстрирует, что сплавленная широковещательная передача дорожек назад и вперед между этими двумя транспортными средствами не используется, чтобы распространить слухи.
showsnap(snaps, 4)
% Restart the driving scenario to return the actors to their initial positions. restart(scenario); % Release all the sensor objects so they can be used again. for sensorIndex = 1:numSensors release(sensors{sensorIndex}); end % Return the random seed to its previous value rng(s)
В этом примере вы видели, как сплав от дорожки к дорожке может улучшить ситуативную осведомленность и увеличить безопасность в автомобильных приложениях. Вы видели, как настроить trackFuser
выполнять сплав от дорожки к дорожке и как задать источники или как внутренние или как внешние при помощи fuserSourceConfiguration
объект. Путем выполнения так, вы избегаете распространения слуха и отслеживаете только сплавленные дорожки, которые, как действительно наблюдает каждое транспортное средство, обеспечены.
[1] Bharanidhar Duraisamy, Тило Шварц и Кристиан Уохлер, "Алгоритмы сплава уровня дорожки для автомобильных приложений безопасности", 2 013 Международных конференций по вопросам Signal Processing, Image Processing & Pattern Recognition, IEEE, 2013.
[2] Федеральная комиссия по связи, "Специализированное Коммуникационное обслуживание Малой дальности", https://www.fcc.gov/wireless/bureau-divisions/mobility-division/dedicated-short-range-communications-dsrc-service.
function [scenario, egoVehicle, secondVehicle] = createDrivingScenario % createDrivingScenario Returns the drivingScenario defined in the Designer % Construct a drivingScenario object. scenario = drivingScenario('SampleTime', 0.05); % Add all road segments roadCenters = [50.8 0.5 0; 253.4 1.5 0]; roadWidth = 12; road(scenario, roadCenters, roadWidth); roadCenters = [100.7 -100.6 0; 100.7 103.7 0]; road(scenario, roadCenters); roadCenters = [201.1 -99.2 0; 199.7 99.5 0]; road(scenario, roadCenters); % Add the ego vehicle egoVehicle = vehicle(scenario, 'ClassID', 1, 'Position', [65.1 -0.9 0]); waypoints = [71 -0.5 0; 148.7 -0.5 0]; speed = 12; trajectory(egoVehicle, waypoints, speed); % Add the second vehicle secondVehicle = vehicle(scenario, 'ClassID', 1, 'Position', [55.1 -0.9 0]); waypoints = [61 -0.5 0; 138.7 -0.5 0]; speed = 12; trajectory(secondVehicle, waypoints, speed); % Add the parked cars vehicle(scenario, 'ClassID', 1, 'Position', [111.0 -3.6 0]); vehicle(scenario, 'ClassID', 1, 'Position', [140.6 -3.6 0]); vehicle(scenario, 'ClassID', 1, 'Position', [182.6 -3.6 0]); vehicle(scenario, 'ClassID', 1, 'Position', [211.3 -4.1 0]); % Add pedestrian actor(scenario, 'ClassID', 4, 'Length', 0.5, 'Width', 0.5, ... 'Height', 1.7, 'Position', [130.3 -2.7 0], 'RCSPattern', [-8 -8;-8 -8]); % Add parked truck vehicle(scenario, 'ClassID', 2, 'Length', 8.2, 'Width', 2.5, ... 'Height', 3.5, 'Position', [117.5 -3.5 0]); end
function [sensors, numSensors, attachedVehicle] = createSensors(scenario) % createSensors Returns all sensor objects to generate detections % Units used in createSensors and createDrivingScenario % Distance/Position - meters % Speed - meters/second % Angles - degrees % RCS Pattern - dBsm % Assign into each sensor the physical and radar profiles for all actors profiles = actorProfiles(scenario); sensors{1} = radarDetectionGenerator('SensorIndex', 1, ... 'SensorLocation', [3.7 0], 'MaxRange', 50, 'FieldOfView', [60 5], ... 'ActorProfiles', profiles, 'HasOcclusion', true, 'HasFalseAlarms', false); sensors{2} = visionDetectionGenerator('SensorIndex', 2, ... 'MaxRange', 100, 'SensorLocation', [1.9 0], 'DetectorOutput', 'Objects only', ... 'ActorProfiles', profiles); sensors{3} = radarDetectionGenerator('SensorIndex', 3, ... 'SensorLocation', [3.7 0], 'MaxRange', 120, 'FieldOfView', [30 5], ... 'ActorProfiles', profiles, 'HasOcclusion', true, 'HasFalseAlarms', false); attachedVehicle = [1;1;2]; numSensors = numel(sensors); end
function trackInEgo = scenarioToEgo(trackInScenario) % Performs coordinate transformation from scenario to ego coordinates % trackInScenario has StateParameters defined to transform it from scenario % coordinates to ego coordinates % We assume a constant velocity model with state [x;vx;y;vy;z;vz] egoPosInScenario = trackInScenario.StateParameters.Position; egoVelInScenario = trackInScenario.StateParameters.Velocity; stateInScenario = trackInScenario.State; stateShift = [egoPosInScenario(1);egoVelInScenario(1);egoPosInScenario(2);egoVelInScenario(2);egoPosInScenario(3);egoVelInScenario(3)]; stateInEgo = stateInScenario - stateShift; trackInEgo = objectTrack('UpdateTime',trackInScenario.UpdateTime,'State',stateInEgo,'StateCovariance',trackInScenario.StateCovariance,'StateParameters',trackInScenario.StateParameters); end
function trackInScenario = egoToScenario(trackInEgo) % Performs coordinate transformation from ego to scenario coordinates % trackInEgo has StateParameters defined to transform it from ego % coordinates to scenario coordinates % We assume a constant velocity model with state [x;vx;y;vy;z;vz] egoPosInScenario = trackInEgo.StateParameters.Position; egoVelInScenario = trackInEgo.StateParameters.Velocity; stateInScenario = trackInEgo.State; stateShift = [egoPosInScenario(1);egoVelInScenario(1);egoPosInScenario(2);egoVelInScenario(2);egoPosInScenario(3);egoVelInScenario(3)]; stateInEgo = stateInScenario + stateShift; trackInScenario = objectTrack('UpdateTime',trackInEgo.UpdateTime,'State',stateInEgo,'StateCovariance',trackInEgo.StateCovariance,'StateParameters',trackInEgo.StateParameters); end
function [tracks,wasTrackerUpdated] = detectAndTrack(agent,time,posSelector) % Create detections from the vehicle poses = targetPoses(agent.Actor); [detections,isValid] = vehicleDetections(agent.Actor.Position,agent.Sensors,poses,time,agent.DetPlotter); % Update tracks for the vehicle if isValid agent.Tracker.StateParameters = struct(... 'Frame','Rectangular', ... 'Position', agent.Actor.Position, ... 'Velocity', agent.Actor.Velocity); tracks = agent.Tracker(detections,time); tracksInScenario = tracks; for i = 1:numel(tracks) tracksInScenario(i) = egoToScenario(tracks(i)); end pos = getTrackPositions(tracksInScenario,posSelector); plotTrack(agent.TrkPlotter,pos) wasTrackerUpdated = true; else tracks = objectTrack.empty(0,1); wasTrackerUpdated = false; end end function [objectDetections,isValid] = vehicleDetections(position, sensors, poses, time, plotter) % Provides the detections for each vehicle. numSensors = numel(sensors); objectDetections = {}; isValidTime = false(1, numSensors); % Generate detections for each sensor for sensorIndex = 1:numSensors sensor = sensors{sensorIndex}; [objectDets, ~, isValidTime(sensorIndex)] = sensor(poses, time); objectDets = cellfun(@(d) setAtt(d), objectDets, 'UniformOutput', false); if isa(sensors{sensorIndex},'radarDetectionGenerator') objectDets = helperClusterDetections(objectDets, 5); end numObjects = numel(objectDets); objectDetections = [objectDetections; objectDets(1:numObjects)]; %#ok<AGROW> end isValid = any(isValidTime); % Plot detections if numel(objectDetections)>0 detPos = cellfun(@(d)d.Measurement(1:2), objectDetections, 'UniformOutput', false); detPos = cell2mat(detPos')' + position(1:2); plotDetection(plotter, detPos); end end function d = setAtt(d) % Set the attributes to be struct d.ObjectAttributes = struct; end function detectionClusters = helperClusterDetections(detections, vehicleSize) % helperClusterDetections Helper to cluster detections in the example N = numel(detections); distances = zeros(N); for i = 1:N for j = i+1:N if detections{i}.SensorIndex == detections{j}.SensorIndex distances(i,j) = norm(detections{i}.Measurement(1:2) - detections{j}.Measurement(1:2)); else distances(i,j) = inf; end end end leftToCheck = 1:N; i = 0; detectionClusters = cell(N,1); while ~isempty(leftToCheck) % Remove the detections that are in the same cluster as the one under % consideration underConsideration = leftToCheck(1); clusterInds = (distances(underConsideration, leftToCheck) < vehicleSize); detInds = leftToCheck(clusterInds); clusterDets = [detections{detInds}]; clusterMeas = [clusterDets.Measurement]; meas = mean(clusterMeas, 2); i = i + 1; detectionClusters{i} = detections{detInds(1)}; detectionClusters{i}.Measurement = meas; leftToCheck(clusterInds) = []; end detectionClusters(i+1:end) = []; % Since the detections are now for clusters, modify the noise to represent % that they are of the whole car for i = 1:numel(detectionClusters) measNoise = eye(6); measNoise(1:2,1:2) = vehicleSize^2 * eye(2); measNoise(4:5,4:5) = eye(2) * vehicleSize^2; detectionClusters{i}.MeasurementNoise = measNoise; end end