本例演示了如何使用三维特征实现用于空中测绘的同步定位和测绘(SLAM)算法。本例的目标是估计机器人的轨迹并创建其环境的点云地图。
本例中的SLAM算法通过查找下采样接受扫描之间的粗对齐来估计轨迹,使用在每个点提取的快速点特征直方图(FPFH)描述符,然后应用迭代最近点(ICP)算法来微调对齐。3-D姿态图优化,来自导航工具箱™,减少了估计轨迹中的漂移。
从OpenTopography网站下载的航空数据块创建合成激光雷达扫描[1].加载一个mat文件,其中包含一系列航路点,这些航路点定义了机器人的轨迹。计算激光雷达扫描从数据在每个航路点使用helperCreateDataset
功能。该功能将在每个航路点计算的激光雷达扫描输出为pointCloud
物体、机器人覆盖的原始地图和地面真实航路点。
外部=“aerialMap.tar.gz”;航路点文件=“gTruthWayPoints.mat”;%使用辅助功能在每个航路点生成激光雷达扫描[pClouds,orgMap,gTruthWayPts]=helperCreateDataset(数据文件,航路点文件);
在机器人覆盖的原始地图上可视化地面真实路径点。
%创建一个图形窗口来可视化地面真实地图和路径点hFigGT =图;axGT =轴(“父”hFigGT,“颜色”,“黑”);可视化地面真实路径点pcshow (gTruthWayPts“红色”,“MarkerSize”, 150,“父”axGT)举行在可视化被机器人覆盖的原始地图pcshow (orgMap“MarkerSize”10“父”axGT)举行从%自定义轴标签包含(axGT“X (m)”) ylabel (axGT“Y (m)”) zlabel (axGT“Z (m)”)标题(axGT,“地面真实地图和机器人轨迹”)
可视化提取的激光雷达扫描,使用pcplayer
对象。
%为玩家指定限制xlimits=[-9090];ylimits=[-9090];zlimits=[-625-587];%创建一个pcplayer对象来可视化激光雷达扫描lidarPlayer = pcplayer (xlimits ylimits zlimits);%自定义pcplayer轴标签xlabel(lidarPlayer.Axes,“X (m)”) ylabel (lidarPlayer。轴,“Y (m)”)zlabel(lidarPlayer.Axes,“Z (m)”)标题(lidarPlayer。轴,激光雷达扫描的)%循环并可视化数据对于l = 1:长度(pClouds)提取激光雷达扫描ptCloud = pClouds (l);%更新激光雷达显示视图(lidarPlayer ptCloud)暂停(0.05)终止
指定轨迹和闭环估计的参数。针对特定的机器人和环境调整这些参数。
指定在接受注册的每次扫描之间跳过的激光雷达扫描的数量。由于连续扫描有很高的重叠,跳过一些帧可以在不影响精度的情况下提高算法的速度。
skipFrames = 3;
下采样激光雷达扫描可以提高算法速度。长方体栅格过滤器通过将每个单元内的所有点平均为单个点来对点云进行下采样。指定长方体栅格过滤器各个单元的大小,单位为米。
gridStep=1.5;%在米
为下采样点云中的每个有效点提取FPFH描述符。指定用于计算描述符的k最近邻(KNN)搜索方法的邻域大小。
邻居= 60;
设置匹配FPFH描述符的阈值和比率,用于识别点对应。
匹配阈值=0.1;匹配比率=0.97;
设置连续扫描之间的相对姿态估计的最大距离和路径数。
maxDistance=1;maxNumTrails=3000;
指定微调相对姿态所需考虑的内偏百分比。
inlierRatio = 0.1;
指定方框网格过滤器的每个单元格的大小,用于通过对准激光雷达扫描来创建地图。
alignGridStep=1.2;
指定围绕当前机器人位置的半径,以搜索循环结束候选。
loopClosureSearchRadius=7.9;
闭环算法基于三维子地图创建和匹配。子映射由指定数量的接受扫描组成nScansPerSubmap
。循环闭合算法也会忽略指定数量的最近扫描subMapThresh
,同时搜索循环候选项。指定均方根误差(RMSE)阈值循环关闭阈值,
接受子映射作为匹配。较低的分数可能表明较好的匹配,但分数会根据传感器数据和预处理的不同而变化。
nScansPerSubmap = 3;subMapThresh = 15;loopClosureThreshold = 0.6;
指定最大可接受的均方根误差(RMSE)的估计相对姿态之间的循环候选人rmseThreshold
.选择较低的值可以得到更精确的闭环边,这对位姿图优化有很大的影响,但评分会根据传感器数据和预处理的不同而有所不同。
rmseThreshold=0.6;
创建一个姿势图,使用poseGraph3D
(导航工具箱)对象,存储在接受的激光雷达扫描之间的估计相对姿态。
pGraph = poseGraph3D;%6乘6信息矩阵的默认序列化右上三角形infoMat = [1 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1];
预分配和初始化计算所需的变量。
%分配内存来存储子映射子映射=单元(地板(长度(pClouds)/(skipFrames*nScansPerSubmap)),1;%分配内存以存储每个子贴图姿势subMapPoses = 0(圆(长度(pClouds) / (skipFrames * nScansPerSubmap)), 3);初始化变量以存储接受的扫描及其转换submap创建百分比pcAccepted=pointCloud.empty(0);tformAccepted=rigid3d.empty(0);%初始化变量来存储基于特征的方法的相对姿态%无姿势图形优化fpfhTform=rigid3d.empty(0);用于跟踪添加的扫描次数的计数器数= 1;
创建变量以可视化处理的激光雷达扫描和估计轨迹。
%设置为1可在构建过程中可视化已处理的激光雷达扫描viewPC=0;%创建pcplayer对象以查看激光雷达扫描,同时%顺序处理它们,如果viewPC是启用的如果viewPC==1 pplayer=pcplayer(xlimits、ylimits、zlimits);%自定义播放器轴标签包含(pplayer。轴,“X (m)”) ylabel (pplayer。轴,“Y (m)”) zlabel (pplayer。轴,“Z (m)”)标题(pplayer。轴,“处理扫描”)终止%创建一个图形窗口来可视化估计的轨迹hFigTrajUpdate =图;axTrajUpdate =轴(“父”hFigTrajUpdate,“颜色”,“黑”);标题(axTrajUpdate,“传感器姿态轨迹”)
机器人的轨迹是机器人在三维空间中的位置和姿态的集合。利用三维激光雷达SLAM算法从三维激光雷达扫描实例估计机器人的姿态。使用这些过程进行三维SLAM估计:
点云将采样
点云注册
Submap创建
循环闭包查询
构成图优化
迭代处理激光雷达扫描来估计机器人的轨迹。
rng (“默认”)%在pcmatchfeature中设置随机种子以保证一致的结果对于FrameIdx = 1: skipFrames:长度(pClouds)
点云下采样可以提高点云配准算法的速度。降采样应该根据您的具体需要进行调整。
%向下采样当前扫描curScan = pcdownsample (pClouds (FrameIdx),“gridAverage”, gridStep);如果viewPC = = 1%可视化向下采样点云视图(pplayer curScan)终止
点云配准估计当前扫描和前一次扫描之间的相对位姿。该示例使用以下步骤进行注册:
提取FPFH描述符从每次扫描使用extractFPFHFeatures
函数
通过使用pcmatchfeatures
函数
微调相对姿势使用pcregistericp
函数
%提取FPFH特征curFeature=extractFPFHFeatures(curScan,“NumNeighbors”、邻居);如果FrameIdx = = 1%更新验收扫描及其形式pcAccepted(计数,1)= curScan;tformAccepted(计数,1)= rigid3d;%更新初始姿态到地面真相的第一个路径点%比较fpfhTform(计数,1)= rigid3d(眼(3),gTruthWayPts (1:));其他的%通过匹配当前扫描和前一次扫描来识别对应关系indexPairs=pcmatchfeatures(curFeature、prevFeature、curScan、prevScan、,…“MatchThreshold”matchThreshold,“RejectRatio”, matchRatio);matchedPrevPts =选择(prevScan indexPairs (:, 2));matchedCurPts =选择(curScan indexPairs (: 1));%估计当前扫描和上一次扫描之间的相对姿势%使用通讯tform1 = estimateGeometricTransform3D (matchedCurPts。的位置,…matchedPrevPts。的位置,“刚性”,“最大距离”maxDistance,…“MaxNumTrials”, maxNumTrails);执行ICP注册以微调相对姿态tform = pcregistericp (curScan prevScan,“InitialTransform”tform1,…“InlierRatio”,内插率);
将刚性变换转换为xyz -位置和四元数方向,将其添加到姿态图中。
relPose = [tform2trvec(tform.T') tform2quat(tform.T')];在姿势图中添加相对姿势addRelativePose (pGraph relPose);
存储用于创建子映射的接受扫描及其姿态。
%更新计数器和存储接受扫描和他们的姿势计数=计数+1;pcAccepted(count,1)=curScan;accumPose=pGraph.nodes(高度(pGraph.nodes));tformAccepted(count,1)=rigid3d((trvec2tform)(累加(1:3))*…quat2tform (accumPose (4))));更新估计姿态fpfhTform(数)= rigid3d (tform。T * fpfhTform(把1).T);终止
通过将连续的、可接受的扫描对齐到指定大小的组中来创建子映射nScansPerSubmap
,使用pcalign
函数。使用子映射可以导致更快的循环闭包查询。
currSubMapId =地板(数/ nScansPerSubmap);如果快速眼动(计数,nScansPerSubmap) = = 0%对齐激光雷达扫描数组以创建子映射submap {currSubMapId} = pcalign (…pcAccepted((count - nScansPerSubmap + 1):count,1),…tformAccepted((count - nScansPerSubmap + 1):count,1),…校准步骤);%指定中心扫描姿态为子映射的姿态submappose (currSubMapId,:) = tformAccepted(count -…地板(nScansPerSubmap / 2), 1) .Translation;终止
使用一个循环闭包查询标识以前访问过的位置。循环结束查询包括查找当前扫描和以前子映射之间的相似性。如果找到相似的扫描,则当前扫描是循环结束候选。循环结束候选估计包括以下步骤:
方法估计以前的子映射和当前扫描之间的匹配帮助评估候选人
如果当前扫描和submap之间的RMSE小于指定的循环关闭阈值。
前面由所有匹配的子映射表示的扫描是循环闭包候选。
使用ICP配准算法计算当前扫描和闭环候选之间的相对位姿。RMSE最低的闭环候选是当前扫描的最佳可能匹配。
只有当RMSE低于指定的阈值时,循环闭包候选者才被接受为有效的循环闭包。
如果currSubMapId > subMapThresh mostRecentScanCenter = pGraph.nodes(height(pGraph.nodes));通过匹配电流估计可能的环路闭合候选%扫描与子映射[loopSubmapIds, ~] = helperEstimateLoopCandidates (curScan submap,…次级对手,最新世纪扫描中心,currSubMapId,subMapThresh,…loopClosureSearchRadius loopClosureThreshold);如果~isempty(loopSubmapIds) rmseMin = inf;%从匹配的子映射id估计当前扫描的最佳匹配对于k = 1:长度(loopSubmapIds)%检查submap中的每个扫描对于kf = 1:nScansPerSubmap probableLoopCandidate =…loopSubmapIds(k)*nScansPerSubmap - kf + 1;[pose_Tform ~, rmse] = pcregistericp (curScan,…PCA已接受(可能是候选);%更新最佳循环闭包候选如果rmse < rmseMinmatchingNode = probableLoopCandidate;构成= [tform2trvec pose_Tform.T”)…tform2quat(pose_Tform.T');终止终止终止%检查循环闭包候选项是否有效如果rmseMin将候选环的相对位姿添加到位姿图addRelativePose (pGraph姿势,infoMat matchingNode,…珠心);终止终止终止%更新以前的点云和功能prevScan=curScan;prevFeature=curFeature;%可视化从接受的扫描估计的轨迹。显示(pGraph“id”,“关闭”,“父”, axTrajUpdate);drawnow终止
利用该方法减小估计轨迹中的漂移优化组合图
(导航工具箱)函数。通常,姿态图中第一个节点的姿态表示原点。为了将估计的轨迹与地面真路径点进行比较,指定第一个地面真路径点作为第一个节点的位姿。
pGraph = optimizePoseGraph (pGraph,“FirstNodePose”,[gTruthWayPts(1,:) 1 0 0 0]);
利用未经过位姿图优化的特征、经过位姿图优化的特征和地面真实数据可视化估计轨迹。
从姿态图中得到估计的轨迹pGraphTraj = pGraph.nodes;从特征配准中得到估计的轨迹,而不需要姿态%图优化fpfhEstimatedTraj = 0(统计,3);对于i = 1:count fpfhEstimatedTraj(i,:) = fpfhTform(i).Translation;终止%创建一个图形窗口来可视化地面真相和估计%的轨迹hFigTraj=图形;axTraj=轴(“父”hFigTraj,“颜色”,“黑”);plot3 (fpfhEstimatedTraj (: 1) fpfhEstimatedTraj (:, 2), fpfhEstimatedTraj (:, 3),…的r *,“父”,axTraj)保持在图3(pGraphTraj(:,1),pGraphTraj(:,2),pGraphTraj(:,3),“b.”,“父”axTraj) plot3 (gTruthWayPts (: 1), gTruthWayPts (:, 2), gTruthWayPts (:, 3),“去”,“父”,axTraj)保持从轴平等的视图(axTraj 2)包含(axTraj“X (m)”) ylabel (axTraj“Y (m)”) zlabel (axTraj“Z (m)”)标题(axTraj“轨迹比较”)传说(axTraj“无姿势图优化的估计轨迹”,…“姿态图优化的估计轨迹”,…“地面实况轨迹”,“位置”,“最佳户外”)
使用估计的姿势变换和合并激光雷达扫描,以创建累积点云地图。
从姿态得到估计的轨迹estimatedTraj = pGraphTraj (:, 1:3);将相对姿态转换为刚性转换estimatedTforms = rigid3d.empty (0);对于idx = 1: pGraph。NumNodes pose = pGraph.nodes(idx);rigidPose = rigid3d((trvec2tform(pose(1:3)) * quat2tform(pose(4:7)))');estimatedTforms (idx, 1) = rigidPose;终止%从处理过的点云和它们的相对姿态创建全局地图globalMap = pcalign (pcAccepted estimatedTforms alignGridStep);%创建一个图形窗口来可视化估计的地图和轨迹hFigTrajMap =图;axTrajMap =轴(“父”,hFigTrajMap,“颜色”,“黑”); pcshow(估计数),“红色”,“MarkerSize”, 150,“父”axTrajMap)举行在pcshow (globalMap“MarkerSize”10“父”axTrajMap)举行从%自定义轴标签包含(axTrajMap“X (m)”) ylabel (axTrajMap“Y (m)”) zlabel (axTrajMap“Z (m)”)标题(axTrajMap'估计的机器人轨迹和生成的地图')
可视化地面真实地图和估计地图。
%创建一个数字窗口来显示地面真实地图和估计地图hFigMap =图(“位置”,[0 0 700 400]);axMap1 =次要情节(1、2、1,“颜色”,“黑”,“父”, hFigMap);axMap1。Position = [0.08 0.2 0.4 0.55];pcshow (orgMap“父”axMap1)包含(axMap1“X (m)”) ylabel (axMap1“Y (m)”)zlabel(axMap1,“Z (m)”)标题(axMap1“地面实况图”) axMap2 = subplot(1,2,2,“颜色”,“黑”,“父”, hFigMap);axMap2。Position = [0.56 0.2 0.4 0.55];pcshow (globalMap“父”axMap2)包含(axMap2“X (m)”) ylabel (axMap2“Y (m)”) zlabel (axMap2“Z (m)”)标题(axMap2,“估计地图”)
readPointCloud
|插入点云
(导航工具箱)|rayIntersection
(导航工具箱)|addRelativePose
(导航工具箱)|优化组合图
(导航工具箱)|显示
(导航工具箱)|extractFPFHFeatures
|pcmatchfeatures
|estimateGeometricTransform3D
|下采样
|pctransform
|pcregistericp
|pcalign
|tform2trvec
(导航工具箱)|tform2quat
(导航工具箱)
lasFileReader
|pointCloud
|pcplayer
|occupancyMap3D
(导航工具箱)|poseGraph3D
(导航工具箱)|rigid3d
[1]斯塔尔,斯科特。图斯卡卢萨:季节性洪水动态和无脊椎动物群落。国家机载激光测绘中心,2011年12月1日。OpenTopography (https://doi.org/10.5069/G9SF2T3K).