主要内容

基于履带融合的汽车安全应用

这个例子展示了如何融合两辆车的履带,以提供比每辆车都能看到的更全面的环境估计。该示例演示了跟踪级fuser和对象跟踪数据格式的使用。在本例中,您将使用自动驾驶工具箱™中的驾驶场景和视觉检测生成器,雷达工具箱™中的雷达数据生成器,以及传感器融合和跟踪工具箱™中的跟踪和跟踪融合模型。

动机

汽车安全应用依赖于车载不同传感器系统的数据融合。单个车辆通过使用集中式跟踪器或采用更分散的方法并融合单个传感器产生的轨迹来融合传感器检测。除了车载数据融合外,多辆车的数据融合还提供了额外的好处,包括更好的覆盖范围、态势感知和安全性[1].这种跨车传感器融合方法利用了传感器的多样性,并提供了更好的覆盖每辆车,因为它使用了该地区其他车辆传感器更新的数据。政府和汽车制造商早就认识到,为了提高汽车安全性,需要在车辆之间共享信息。例如,V2X协议和蜂窝通信链路正在开发中。

虽然多辆车之间的传感器融合是有益的,但即使只有内部传感器可用,大多数车辆也必须满足一定的安全要求。因此,车辆很可能配备跟踪器,履带熔断器,或两者兼备。这些跟踪算法在单车层面上提供态势感知。因此,本例中所做的假设是,车辆通过广播履带和执行履带融合来共享态势感知。

这个例子展示了融合两辆车的履带的好处,以增强态势感知和安全性。本例没有模拟通信系统。相反,本例假设通信系统提供了在两个车辆之间传输轨道所需的带宽。

进行航迹架构

下面的方框图描述了这两辆车的主要功能,其中:

  • 车辆1有两个传感器,每个传感器为本地车辆跟踪器提供检测。跟踪器利用来自局部传感器的检测来跟踪目标,并将这些局部轨迹输出到车辆轨迹熔断器。

  • 2号车有一个单独的传感器,这是一个跟踪雷达。跟踪雷达输出轨迹,并作为车辆2的本地跟踪器。来自跟踪雷达的轨迹输入到车辆2上的车辆轨迹熔断器。

  • 每辆车上的履带熔断器将本地车辆的履带与从另一辆车的履带熔断器接收到的履带进行熔断器。每次更新后,每辆车的履带熔断器都会广播其熔断的履带,这些履带将馈送到另一辆车的履带熔断器的下一次更新中。

V2VFusion.png

在本例中,使用atrackerJPDA对象定义车辆1跟踪器。

为车辆1创建跟踪器v1Tracker = trackerJPDA(“TrackerIndex”, 1“DeletionThreshold”, [4 4],“AssignmentThreshold”, [100 inf]);%车辆1跟踪器posSelector = [1 0 0 0 0 0 0;0 0 1 0 0 0];

在这个架构中,一辆车的融合轨道会更新另一辆车的融合轨道。这些融合履带随后被广播回第一辆车。为了避免谣言传播,请小心其他车辆的履带如何更新履带熔断器。

考虑以下谣言传播的例子:在某个更新步骤中,车辆1使用其内部传感器跟踪一个物体。然后,1号车将目标轨迹融合,并将其传输给2号车,2号车现在将轨道与自己的轨道融合,并意识到目标。到目前为止,这正是履带融合的目标:利用履带1的信息增强履带2的态势感知能力。由于车辆2现在知道了这个物体,它也开始广播轨道,可能是为了让另一辆车辆受益(在示例中没有显示)。

然而,车辆1现在从车辆2接收到关于只有车辆1实际跟踪的对象的轨道信息。因此,1号运载器上的轨迹熔合器必须意识到它从2号运载器上获得的这个物体的轨迹实际上不包含任何由独立来源更新的新信息。为了区分包含新信息的轨道和重复信息的轨道,必须将车辆2定义为外部来源1号车的履带熔断器。类似地,车辆1必须被定义为车辆2上的履带熔断器的外部源。此外,您只需要定义由迹线熔断器根据来自内部源的信息更新的迹线为自我报告的.这样一来,每辆车的履带熔断器都会忽略来自履带的更新,这些履带在履带熔断器之间来回反弹,而没有任何新的信息。

每个车辆的本地跟踪器跟踪相对于车辆参考系(称为自我参考系)的对象。轨迹到轨迹的融合是在场景框架中完成的,这是全局级别的框架。助手egoToScenario函数将轨道从自我框架转换为场景框架。类似地,函数scenarioToEgo将轨道从场景框架转换为任何自我框架。两个转换都依赖于StateParameters的属性objectTrack对象。当trackFuser对象计算场景帧中的中心航迹到任何帧中的本地航迹的距离,它使用StateParameters对局部轨道进行坐标变换。

实现前面所描述的trackFuser定义,将以下源定义为fuserSourceConfiguration对象。

为每辆车定义来源v1TrackerConfiguration = fusersourcecconfiguration (“SourceIndex”, 1“IsInternalSource”,真的,...% v1Tracker是v1Fuser内部的“CentralToLocalTransformFcn”@scenarioToEgo,“LocalToCentralTransformFcn”, @egoToScenario);%坐标变换v2FuserConfiguration = fusersourcecconfiguration (“SourceIndex”4“IsInternalSource”、假);% v2Fuser是v2Fuser的外部v1Sources = {v1TrackerConfiguration;v2FuserConfiguration};v2TrackerConfiguration = fusersourcecconfiguration (“SourceIndex”2,“IsInternalSource”,真的,...% v2Tracker是v2Fuser内部的“CentralToLocalTransformFcn”@scenarioToEgo,“LocalToCentralTransformFcn”, @egoToScenario);%坐标变换v1FuserConfiguration = fusersourcecconfiguration (“SourceIndex”3,“IsInternalSource”、假);% v1Fuser是v2Fuser的外部v2Sources = {v2TrackerConfiguration;v1FuserConfiguration};

你现在可以定义每个车辆履带熔断器为trackFuser对象。

stateParams = struct(“帧”“矩形”“位置”,[0 0 0],“速度”,[0 0 0]);v1Fuser = trackFuser(“FuserIndex”3,...“AssignmentThreshold”, [100 inf],...“MaxNumSources”2,“SourceConfigurations”v1Sources,...“StateFusion”“十字路口”“DeletionThreshold”3 [3],...“StateParameters”, stateParams);v2Fuser = trackFuser(“FuserIndex”4...“AssignmentThreshold”, [100 inf],...“MaxNumSources”2,“SourceConfigurations”v2Sources,“StateFusion”...“十字路口”“DeletionThreshold”3 [3],...“StateParameters”, stateParams);初始化以下变量fusedTracks1 = objectTrack.empty(0,1);fusedTracks2 = objectTrack.empty(0,1);wasFuser1Updated = false;wasFuser2Updated = false;

定义场景

下面的场景显示了两辆车在街上行驶。1号车是领头车,配备两个前视传感器:一个近程雷达传感器和一个视觉传感器。2号车在1号车后面10米处行驶,配备了远程雷达。街道的右侧停放着车辆。一名行人站在两辆车之间。这个行人在X = 60米处显示为一个点。

由于车辆2与车辆1之间距离较短,车辆2雷达传感器的大部分覆盖被车辆1遮挡。因此,车辆2上的履带熔断器维护的大多数履带首先由车辆1广播的履带初始化。

创建driingscenario对象和两个车辆[scenario, vehicle1, vehicle2] = createDrivingScenario;创建所有传感器[sensors, numSensors, attachedVehicle] = createSensors(scenario);%创建显示[f, ploters] = createV2VDisplay(场景,传感器,附加车辆);

下面的追逐情节是从第二辆车的角度来看的。箭头表示行人几乎完全被停放的车辆和第一辆车辆挡住的位置。

TrackToTrackChasePlot.png

将每辆车定义为参与者、传感器、跟踪器和绘图仪的组合v1 =结构(“演员”{vehicle1},“传感器”,{传感器(attachedVehicle = = 1)},“追踪”{v1Tracker},“DetPlotter”{plotters.veh1DetPlotter},“TrkPlotter”, {plotters.veh1TrkPlotter});v2 =结构(“演员”{vehicle2},“传感器”,{传感器(attachedVehicle = = 2)},“追踪”{{}},“DetPlotter”{{}},“TrkPlotter”, {plotters.veh2TrkPlotter});2号车上没有探测到或追踪器

运行仿真

下面的代码运行模拟。

Running = true;对于可重复的结果,设置随机数种子S = rng;Rng (2019) snaptimes = [0.5, 2.8, 4.4, 6.3, inf];snap = cell(number (snaptimes,1));I = 1;f.Visible =“上”运行&& ishhandle (f) time = scenario.SimulationTime;在车辆层面进行检测和跟踪。[tracks1,wasTracker1Updated] = detectAndTrack(v1,time,posSelector);[tracks2,wasTracker2Updated] = detectAndTrack(v2,time,posSelector);%保留以前fuser更新的轨道oldFusedTracks1 = fusedTracks1;oldFusedTracks2 = fusedTracks2;更新熔断器如果wasTracker1Updated || wasFuser2Updated tracksToFuse1 = [tracks1;oldFusedTracks2];如果isLocked(v1Fuser) || ~isempty(tracksToFuse1) [fusedTracks1,~,~,info1] = v1Fuser(tracksToFuse1,time);wasFuser1Updated = true;pos = getTrackPositions(fusedTracks1,posSelector);id = string([fusedTracks1.TrackID]');plotTrack (plotters.veh1FusePlotter、pos、ids);其他的wasFuser1Updated = false;fusedTracks1 = objectTrack.empty(0,1);结束其他的wasFuser1Updated = false;fusedTracks1 = objectTrack.empty(0,1);结束如果wasTracker2Updated || wasFuser1Updated tracksToFuse2 = [tracks2;oldFusedTracks1];如果isLocked(v2Fuser) || ~isempty(tracksToFuse2) [fusedTracks2,~,~,info2] = v2Fuser(tracksToFuse2,time);wasFuser2Updated = true;pos = getTrackPositions(fusedTracks2,posSelector);id = string([fusedTracks2.TrackID]');plotTrack (plotters.veh2FusePlotter、pos、ids);其他的wasFuser2Updated = false;fusedTracks2 = objectTrack.empty(0,1);结束其他的wasFuser2Updated = false;fusedTracks2 = objectTrack.empty(0,1);结束更新显示updateV2VDisplay(绘图仪,场景,传感器,附加车辆)将场景向前推进一个时间步,如果场景完成,则退出循环运行=提前(场景);在指定的时间捕获帧的图像如果时间>= snaptimes(i) snaps{i} = takesnap(f);I = I + 1;结束结束

{

图中为场景及场景结束时的跟踪结果。本例的后续部分将分析关键时刻的跟踪结果。

分析模拟开始时的跟踪

当模拟开始时,车辆1检测到停在街道右侧的车辆。然后,车辆1跟踪器确认与停放车辆相关的轨道。此时,车辆2跟踪器检测和跟踪的唯一对象是车辆1,它就在它的前面。一旦车辆1轨道熔断器确认轨道,它将广播它们,车辆2轨道熔断器将它们熔断器。因此,车辆2在自己检测到车辆之前就意识到停在那里的车辆。

showsnap(四合扣,1)

{

分析路边行人的跟踪

随着模拟的继续,车辆2也能够检测和跟踪停靠在一侧的车辆,并将它们与来自车辆1的轨道融合在一起。车辆2能够在模拟中检测到并跟踪行人约4秒,车辆2将与行人相关的轨迹融合到模拟中约4.4秒(见快照2)。然而,车辆2需要大约2秒才能通过自身的传感器检测到并跟踪行人(见快照3)。提前2秒检测到街上的行人可以显著提高安全性。

showsnap(四合扣,2)

{

showsnap(四合扣,3)

{

避免谣言传播

当两辆车相互通信轨道时,存在这样一种风险,即它们将继续通过重复另一辆车所通信的内容来通信关于它们不再检测到的物体的信息。这种情况被称为谣言传播。

当车辆通过这些物体时,这些物体离开了他们的视野,与这些物体相关的融合履带被两个跟踪器丢弃(见快照4)。丢弃履带表明在两辆车辆之间来回广播的融合履带没有被用来传播谣言。

showsnap(断了,4)

{

重新启动驾驶场景,使参与者返回到初始位置。重启(场景);释放所有传感器对象,使它们可以再次使用sensorIndex = 1:numSensors释放(sensors{sensorIndex});结束将随机种子返回到它之前的值rng (s)

总结

在本例中,您看到了履带间融合如何增强态势感知并提高汽车应用中的安全性。你们学过如何建立trackFuser方法来执行航迹到航迹融合,以及如何将源定义为内部或外部fuserSourceConfiguration对象。通过这样做,你可以避免谣言传播,并只保留每辆车真正观察到的融合轨道进行维护。

参考文献

[1] Duraisamy, B., T. Schwarz, C.维勒。汽车安全应用的履带级融合算法在2013年信号处理、图像处理与模式识别国际会议, 179-84, 2013。https://doi.org/10.1109/ICSIPR.2013.6497983

支持功能

createDrivingScenario

中定义的驾驶场景驾驶场景设计应用程序。

函数[scenario, egoVehicle, secondVehicle] = createDrivingScenario构造一个drivingScenario对象scenario = driving (“SampleTime”, 0.1);添加所有路段roadCenters = [50.8 0.5 0;253.4 1.5 0];roadWidth = 12;道路(scenario, roadCenters, roadWidth);roadCenters = [100.7 -100.6 0;100.7 103.7 0];路(场景,roadCenters);roadCenters = [201.1 - 99.20;199.7 99.5 0];路(场景,roadCenters);添加自我载具egoVehicle =车辆(场景,“ClassID”, 1“位置”, [65.1 -0.9 0],“PlotColor”, [0 0.7410 0.4470]);路点= [71 -0.5 0;148.7 -0.5 0];速度= 12;轨迹(egoVehicle,路径点,速度);添加第二个车辆secondVehicle =车辆(场景,“ClassID”, 1“位置”, [55.1 -0.9 0]);路点= [61 -0.5 0;138.7 -0.5 0];速度= 12;轨迹(第二辆车,路点,速度);添加停放的车辆车辆(场景中,“ClassID”, 1“位置”, [111.0 -3.6 0]);车辆(场景中,“ClassID”, 1“位置”, [140.6 -3.6 0]);车辆(场景中,“ClassID”, 1“位置”, [182.6 -3.6 0]);车辆(场景中,“ClassID”, 1“位置”, [211.3 -4.1 0]);%增加行人演员(场景中,“ClassID”4“长度”, 0.5,“宽度”, 0.5,...“高度”, 1.7,“位置”, [130.3 -2.7 0],“RCSPattern”, [-8 -8;-8 -8]);%添加停放的卡车车辆(场景中,“ClassID”2,“长度”, 8.2,“宽度”, 2.5,...“高度”, 3.5,“位置”, [117.5 -3.5 0]);结束

createSensors

创建场景中使用的传感器,并列出它们到车辆的附件。

函数[sensors, numSensors, attachedVehicle] = createSensors(场景)返回所有用于生成检测的传感器对象%在createSensors和createDrivingScenario中使用的单位%距离/位置-米速度-米/秒%角度-角度% RCS模式- dBsm为每个传感器分配所有参与者的物理和雷达配置文件profiles = actorProfiles(场景);1号车雷达报告集群探测传感器{1}= radardatgenerator (“没有扫描”“SensorIndex”, 1“UpdateRate”10...“MountingLocation”, [3.7 0 0.2],“RangeLimits”, [0 50],“FieldOfView”, [60 5],...“RangeResolution”, 2.5,“AzimuthResolution”4...“配置文件”配置文件,“HasOcclusion”,真的,“HasFalseAlarms”假的,...“TargetReportFormat”“集群检测”);2号车雷达报告轨迹传感器{2}= radardatgenerator (“没有扫描”“SensorIndex”2,“UpdateRate”10...“MountingLocation”, [3.7 0 0.2],“RangeLimits”, [0 120],“FieldOfView”, [30 5],...“RangeResolution”, 2.5,“AzimuthResolution”4...“配置文件”配置文件,“HasOcclusion”,真的,“HasFalseAlarms”假的,...“TargetReportFormat”“跟踪”“DeletionThreshold”, [3 3]);%车辆1视觉传感器报告检测到传感器{3}=视觉检测生成器(“SensorIndex”3,...“MaxRange”, 100,“SensorLocation”, [1.9 0],“DetectorOutput”“只将对象”...“ActorProfiles”,概要文件);attachedVehicle = [1;2;1];numSensors =数字(传感器);结束

scenarioToEgo

执行场景坐标到自我坐标的坐标转换。

trackInScenarioStateParameters定义为将其从场景坐标转换为自我坐标。

该状态使用恒速模型[x;vx;y;vy;z;vz]。

函数trackingo = scenarioToEgo(trackInScenario) egposinscenario = trackInScenario. stateparameters . originposition;egoVelInScenario = trackInScenario.StateParameters.OriginVelocity;stateInScenario = trackInScenario.State;stateShift = [egoPosInScenario(1);egoVelInScenario(1);egoPosInScenario(2);egoVelInScenario(2);egoPosInScenario(3);egoVelInScenario(3)];stateingo = stateInScenario - statesshift;trackInEgo = objectTrack(“UpdateTime”, trackInScenario。UpdateTime,“状态”stateInEgo,“StateCovariance”, trackInScenario。StateCovariance,“StateParameters”, trackInScenario.StateParameters);结束

egoToScenario

执行自我坐标到场景坐标的坐标转换。

trackInEgoStateParameters定义为将其从自我坐标转换为场景坐标。

该状态使用恒速模型[x;vx;y;vy;z;vz]。

函数trackInScenario = egoToScenario(trackInEgo) egposinscenario = trackInEgo. stateparameters . originposition;egoVelInScenario = trackegogo . stateparameters . originvelocity;stateInScenario = trackigo . state;stateShift = [egoPosInScenario(1);egoVelInScenario(1);egoPosInScenario(2);egoVelInScenario(2);egoPosInScenario(3);egoVelInScenario(3)];stateingo = stateInScenario + statesshift;trackInScenario = objectTrack(“UpdateTime”, trackInEgo。UpdateTime,“状态”stateInEgo,“StateCovariance”, trackInEgo。StateCovariance,“StateParameters”, trackInEgo.StateParameters);结束

detectAndTrack

此函数用于收集一辆车中传感器的所有检测,并使用它们更新跟踪器。

代理是一个包含参与者信息、传感器、跟踪器和绘图仪的结构,用于绘制检测和车辆轨道。

函数[tracks,wasTrackerUpdated] = detectAndTrack(agent,time,posSelector)从车辆中创建检测pose = targetpose (agent.Actor);[detections,isValid] = vehicleDetections(agent.Actor.Position,agent.Sensors,pose,time,agent.DetPlotter);更新跟踪器以从报告检测的传感器获取跟踪。如果isValid agent.Tracker.StateParameters = struct(...“帧”“矩形”...“OriginPosition”agent.Actor.Position,...“OriginVelocity”, agent.Actor.Velocity);tracks = agent.Tracker(检测,时间);tracksInScenario =轨道;i = 1:numel(tracks) tracksInScenario(i) = egoToScenario(tracks(i));结束pos = getTrackPositions(tracksInScenario,posSelector);plotTrack(agent.TrkPlotter,pos) wasTrackerUpdated = true;其他的轨道= objectTrack.empty(0,1);wasTrackerUpdated = false;结束%从跟踪传感器获得额外的跟踪[sensorTracks,wasSensorTrackerUpdated] = vehicleTracks(agent.Actor,agent.Sensors,pose,time,agent.TrkPlotter);tracks = vertcat(tracks,sensorTracks);wasTrackerUpdated = wasTrackerUpdated || wasSensorTrackerUpdated;结束

vehicleDetections

收集车辆上所有返回检测的传感器的检测结果。

函数[objectDetections,isValid] = vehicleDetections(位置,传感器,姿势,时间,绘图仪)numSensors =数字(传感器);objectDetections = {};isValidTime = false(1, numSensors);为每个传感器生成检测sensorIndex = 1:numSensors sensor = sensors{sensorIndex};如果isa(传感器,“visionDetectionGenerator”) || ~strcmpi(传感器。TargetReportFormat,“跟踪”) [objectDets, ~, sensorConfig] =传感器(姿势,时间);如果islogical(sensorConfig) isValidTime(sensorIndex) = sensorConfig;其他的isValidTime(sensorIndex) = sensorConfig.IsValidTime;结束objectDets = cellfun(@(d) setAtt(d), objectDets,“UniformOutput”、假);numObjects = numel(objectDets);objectDetections = [objectDetections;objectDets (1: numObjects)];% #好< AGROW >结束结束isValid = any(isValidTime);Plot检测百分比如果数值(objectDetections)>0 detPos = cellfun(@(d)d. measurement (1:2), objectDetections,“UniformOutput”、假);detPos = cell2mat(detPos')' +位置(1:2);plotDetection(绘图仪,detPos);结束结束函数d = setAtt(d)将属性设置为结构d.ObjectAttributes = struct;只保留位置测量和移除速度如果d.测量= d.测量(1:3);d.测量噪声= d.测量噪声(1:3,1:3);d.MeasurementParameters{1}。HasVelocity = false;结束结束

vehicleTracks

从报告车辆轨迹的传感器上收集所有的轨迹。

函数[tracks,wasTrackerUpdated] = vehicleTracks(演员,传感器,姿势,时间,绘图仪)从车辆中创建检测numSensors =数字(传感器);tracks = objectTrack.empty;isValidTime = false(1, numSensors);为每个传感器生成检测sensorIndex = 1:numSensors sensor = sensors{sensorIndex};如果isa(传感器,“radarDataGenerator”) && strcmpi(传感器。TargetReportFormat,“跟踪”) [sensorTracks, ~, sensorConfig] =传感器(姿势,时间);如果islogical(sensorConfig) isValidTime(sensorIndex) = sensorConfig;其他的isValidTime(sensorIndex) = sensorConfig.IsValidTime;结束numObjects = numel(sensorTracks);轨道=[轨道;sensorTracks (1: numObjects)];% #好< AGROW >结束结束wasTrackerUpdated = any(isValidTime);如果~ wasTrackerUpdated未安装车辆跟踪传感器返回结束为履带状态参数添加车辆位置和速度i = 1:numel(tracks) tracks(i). stateparameters。OriginPosition = tracks(i). stateparameters。OriginPosition + actor.Position';跟踪.StateParameters(我)。OriginVelocity = tracks(i). stateparameters。OriginVelocity + actor.Velocity';结束%绘图轨迹如果number (tracks)>0 trPos = arrayfun(@(t)t. state ([1,3]), tracks,“UniformOutput”、假);trPos = cell2mat(trPos')' + actor.Position(1:2);plotTrack(绘图仪,trPos);结束结束
Baidu
map