创建自我中心入住地图使用范围的传感器

占位图通过将连续的世界空间映射到离散的数据结构,为机器人应用程序提供了一种简单而健壮的表示环境的方法。个人网格单元可以包含二进制或概率信息,其中0表示空闲空间,1表示占用空间。随着时间的推移,您可以使用传感器测量来构建这些信息,并有效地将它们存储在地图中。这些信息对于更高级的工作流也很有用,比如冲突检测和路径规划。

这个例子显示了如何创建以自我为中心占用图,它可以跟踪机器人的即时环境,并可以在环境中有效移动。轨迹是通过规划环境中的路径生成的,并指示机器人的运动。当机器人移动时,地图会使用来自模拟激光雷达和地面真实地图的传感器信息进行更新。

加载预建的地面实况入住地图

从以前生成的数据文件创建一个非自我中心的地图,这被认为是模拟激光雷达的地面真相。加载地图,属于MapData,其中包含数据字段作为概率矩阵并将其转换为二进制值。

创建一个binaryOccupancyMap与二进制矩阵对象并指定地图的分辨率。

%负载保存的地图信息加载mapData_rayTracingTrajectorybinaryMatrix = mapData.Data> 0.5;世界地图= binaryOccupancyMap(binaryMatrix,mapData.Resolution);

设置地图,相对于世界起源的左下角的位置。

worldMap。LocalOriginInWorld = mapData.GridLocationInWorld;

绘制地面真相。这个例子设置了一个子图,用于并排显示两个地图。

集(GCF,“可见”'上') worldAx = subplot(1,2,1);worldHandle =显示(worldMap,“父”,worldAx);持有所有

创建模拟雷达

创建一个rangeSensor对象,可用于从模拟中收集激光雷达读数。控件上可以修改各种属性rangeSensor以更准确地表示激光雷达的一个特定的模式,或在传感器噪声添加到测试溶液的稳健性。在这个例子中,设置[最小最大]范围和噪声参数。创建对象后,通过提供[X Y的2θ相对世界框架的姿势。例如助手绘制机器人,激光雷达读数超过世界地图。

%创建rangeSensor激光雷达= rangeSensor;lidar.Range = [0 5];lidar.RangeNoise = 0;POS = [0 0 0];在世界地图中显示激光雷达读数[范围,角度] =激光雷达(POS,世界地图);hSensorData = exampleHelperPlotLidar(worldAx,POS,的范围,角度);%的世界地图显示机器人hRobot = exampleHelperPlotRobot(worldAx,POS);

初始化一个自我中心地图

创建occupancyMap对象来表示自我中心地图。通过设置偏移量相对于本地原点的网格原点GridOriginInLocal属性世界极限之间的差值的一半。这班地图,使当地的原产地为中心的范围。

%默认情况下,GridOriginInLocal = [0 0]egoMap = occupancyMap (10 10 worldMap.Resolution);%偏移量GridOriginInLocal使得“本地帧”位于了“地图窗口”的%中心egoMap.GridOriginInLocal =  -  [DIFF(egoMap.XWorldLimits)DIFF(egoMap.YWorldLimits)] / 2;

画出自我中心地图旁边的插曲世界地图。

%更新本地的情节localAx =副区(1,2,2);显示(egoMap,“父”,localAx);持有所有localMapFig =情节(localAx egoMap。LocalOriginInWorld + [0, 1], egoMap。LocalOriginInWorld + [0 0),'R-'“线宽”,3);

规划路径点之间

现在,我们可以用我们的地面实况地图来计划两个自由点之间的路径。创建世界地图的副本,并将它充气基于机器人的大小和所需的间隙。此示例使用一个车状机器人,其具有非完整约束,具有指定的stateSpaceDubins对象。路径规划器利用这个状态空间对机器人的可行状态进行随机采样。最后,创建一个validatorOccupancyMap对象,该对象通过检查相应单元格的占用情况,使用映射验证生成的状态和连接它们的动作。

复制世界地图并使其膨胀。binaryMap = binaryOccupancyMap(世界地图);膨胀(binaryMap,0.1);创建一个状态空间对象。STATESPACE = stateSpaceDubins;%减少转弯半径,以更好地适应地图和障碍物的大小%的密度。stateSpace。MinTurningRadius = 0.5;%创建一个状态验证对象。验证器= validatorOccupancyMap (stateSpace);验证器。地图= binaryMap;验证器。ValidationDistance = 0.1;

使用RRT*规划算法,作为aplannerRRTStar对象并指定状态空间和状态验证器作为输入。指定开始和结束的策划者位置和产生的路径。

使用%以前创建的状态空间和StateValidator对象来创建我们的规划师规划师= plannerRRTStar(状态空间,验证器);计划。MaxConnectionDistance = 2;%设定一个种子为可再现的结果的随机生成的路径。RNG(1,“扭腰”%设置开始和结束点。startPt = [-6 -5 0];goalPt = [8 7 pi/2];计划起点和终点之间的路径。path = plan(planner, startPt, goalPt);插入(路径,大小(path.States 1) * 10);情节(worldAx path.States (: 1), path.States (:, 2),“b -”);

生成轨迹沿路径

规划器生成了一组状态,但要执行轨迹,需要这些状态的时间。本例的目标是使机器人以恒定的线速度沿着路径移动0.5多发性硬化症。要获得时间戳的每个点,计算点之间的距离,累积求和它们,然后由线速度除以此得到一个单调增加的时间戳,tStamps阵列。

得到每个路径点之间的距离pt2ptDist =距离(stateSpace path.States (1: end-1,:), path.States(2:最终,:))
pt2ptDist =139×10.18 0.18 0.18 0.18 0.18 0.18 0.18 0.18 0.18 0.18⋮
linVel = 0.5;% 多发性硬化症tStamps = cumsum (pt2ptDist) / linVel;

产生了最终的模拟轨迹waypointTrajectory,指定路径状态,相应的时间戳,和为10Hz的期望采样率。

TRAJ = waypointTrajectory(path.States,[0; tStamps]'采样率'10);

模拟传感器读数,并建立一个地图

最后,沿轨道移动机器人,同时更新与模拟雷达读数地图。

初始化仿真,重置轨迹,将局部原点设置为轨迹上的第一个xy点,并清除地图。

复位(TRAJ);robotCurrentPose = path.States(1,:);移动(egoMap,robotCurrentPose(1:2));setOccupancy(egoMap,repmat(egoMap.DefaultValue,egoMap.GridSize));

模拟回路的主要操作为:

  • 获取下一姿态从轨迹traj并提取从四元数的z轴方向(THETA)。

  • 移动egoMap到新的[x和y的2θ姿势。

  • 检索来自激光雷达传感器数据。

  • 更新与传感器数据使用本地地图insertRay

  • 刷新可视化。

~结束(traj)%机器人沿轨迹递增[PTS,季铵化合物] =步骤(TRAJ);%从四元数得到取向角rotMatrix = rotmat(季,“点”);orientZ = rotm2eul(rotMatrix);将机器人移动到新的位置robotCurrentPose = [pts(1:2) orientZ(1)];移动(egoMap robotCurrentPose (1:2),“MoveType”'绝对');%来自激光雷达检索传感器信息并将其插入到所述egoMap【范围、角度】=激光雷达(robotCurrentPose, worldMap);insertRay (egoMap robotCurrentPose、范围、角度、lidar.Range (2));更新以egomap为中心的阴谋显示(egoMap,“父”,localAx,“FastUpdate”1);更新方向向量集(localMapFig,“扩展数据”,robotCurrentPose (1) + [0 cos (robotCurrentPose (3))),“YData”,robotCurrentPose(2)+ [0 SIN(robotCurrentPose(3))]);%更新世界剧情例如helperupdaterobotandlidar (hRobot, hSensorData, robotCurrentPose, range, angles);%调用的DrawNow推送更新图drawnowlimitrate结束

注意机器人驱动器通过所述环境,模拟传感器读数,并且因为它去建立一个占用地图。