使用 RoadRunner 高清地图在 RoadRunner 中构建测试赛道 3D 场景
此示例演示如何使用 MATLAB®
函数为测试跑道构建 RoadRunner 场景。您可以使用包含经纬度坐标的 Keyhole 标记语言 (KML) 文件和包含高程的 GeoTIFF 文件构建测试轨道场景。要导入道路数据文件,您必须拥有 Mapping Toolbox™ 许可证。
导入 KML 文件用于测试轨道
在此示例中,您将轨道中心的坐标从 KML 文件(地图数据 © 2022 by Google)导入 MATLAB,然后使用 MATLAB 函数绘制从 KML 文件导入的数据来查看坐标。
通过从 KML 文件读取地理数据来创建地理空间表。
kmlData = readgeotable("TestTrackKMLData.kml");
绘制测试跑道的坐标。
geoplot(kmlData)
geobasemap topographic
导入 GeoTIFF 文件用于测试轨道
本例中使用的样本地形数据是从 EarthExplorer 下载的,它提供了来自美国地质调查局 (USGS) 档案的地球科学数据。您可以通过将 shapefile 上传到 EarthExplorer 来从 USGS 网站下载 TIF 文件,这会将 EarthExplorer 裁剪到测试轨道的区域。
将地理空间表转换为道路中心表,即可获取测试赛道的经纬度坐标。
T = geotable2table(kmlData,["Latitude","Longitude"]); [georefGrid,spatialRef] = readgeoraster("TestTrack.tif",OutputType="double"); [lat1,lon1] = polyjoin(T.Latitude(1),T.Longitude(1)); [lat2,lon2] = polyjoin(T.Latitude(2),T.Longitude(2)); [lat3,lon3] = polyjoin(T.Latitude(3),T.Longitude(3)); [lat4,lon4] = polyjoin(T.Latitude(4),T.Longitude(4)); [lat5,lon5] = polyjoin(T.Latitude(5),T.Longitude(5)); [lat6,lon6] = polyjoin(T.Latitude(6),T.Longitude(6)); [lat7,lon7] = polyjoin(T.Latitude(7),T.Longitude(7));
从地形数据中查询轨迹坐标的高程。
ctrElev1 = geointerp(georefGrid,spatialRef,lat1,lon1); ctrElev2 = geointerp(georefGrid,spatialRef,lat2,lon2); ctrElev3 = geointerp(georefGrid,spatialRef,lat3,lon3); ctrElev4 = geointerp(georefGrid,spatialRef,lat4,lon4); ctrElev5 = geointerp(georefGrid,spatialRef,lat5,lon5); ctrElev6 = geointerp(georefGrid,spatialRef,lat6,lon6); ctrElev7 = geointerp(georefGrid,spatialRef,lat7,lon7);
创建 RoadRunner 高清地图
创建 RoadRunner 高清地图并设置感兴趣区域的地理参考。
创建一个空的 RoadRunner 高清地图作为 roadrunnerHDMap
对象。
rrMap = roadrunnerHDMap;
计算道路网原点的地理坐标作为道路网边界四边形的中心。
[latLim1,lonLim1] = geoquadline(lat1,lon1); latMean1 = mean(latLim1); lonMean1 = mean(lonLim1);
设置感兴趣区域的地理参考。
rrMap.GeoReference = [latMean1 lonMean1];
将经纬度坐标投影至 xy 地图坐标
使用投影坐标参考系统 (CRS) 将导入的纬度和经度坐标转换为 xy 地图坐标。然后,使用 xy 地图坐标作为轨道中心,设置轨道宽度。
从 RoadRunner 高清地图读取横轴墨卡托投影 CRS。
p = readCRS(rrMap);
将纬度和经度坐标投影到 xy 坐标。
[x1,y1] = projfwd(p,lat1,lon1); [x2,y2] = projfwd(p,lat2,lon2); [x3,y3] = projfwd(p,lat3,lon3); [x4,y4] = projfwd(p,lat4,lon4); [x5,y5] = projfwd(p,lat5,lon5); [x6,y6] = projfwd(p,lat6,lon6); [x7,y7] = projfwd(p,lat7,lon7);
定义测试跑道的道路中心和道路宽度。
rdCtrs1 = [x1 y1 ctrElev1]; rdWidth1 = 6.5; rdCtrs2 = [x2 y2 ctrElev2]; rdWidth2 = 10; rdCtrs3 = [x3 y3 ctrElev3]; rdWidth3 = 5; rdCtrs4 = [x4 y4 ctrElev4]; rdWidth4 = 3.5;
上采样道路数据
由于从 KML 文件获取的数据点稀疏,并且测试赛道包含尖锐的曲线,因此必须对数据进行上采样,以避免建模不准确的赛道车道。使用 helperRoadDimensions
辅助函数对数据进行上采样。
[lftBndry1,rgtBndry1,ctrBndry1] = helperRoadDimensions(rdCtrs1,rdWidth1); [lftBndry2,rgtBndry2,ctrBndry2] = helperRoadDimensions(rdCtrs2,rdWidth2); [lftBndry3,rgtBndry3,ctrBndry3] = helperRoadDimensions(rdCtrs3,rdWidth3); [lftBndry4,rgtBndry4,ctrBndry4] = helperRoadDimensions(rdCtrs4,rdWidth4);
指定车道和车道边界
使用插值数据创建 RoadRunner 高清地图,并修改数据以类似于测试跑道。
指定 RoadRunner 高清地图的车道属性。
rrMap.Lanes(4,1) = roadrunner.hdmap.Lane; for i = 1:4 rrMap.Lanes(i).Geometry = eval(strcat("ctrBndry",num2str(i))); rrMap.Lanes(i).TravelDirection = "Bidirectional"; rrMap.Lanes(i).ID = strcat("Lane",num2str(i)); rrMap.Lanes(i).LaneType = "Driving"; end
指定车道边界信息。
rrMap.LaneBoundaries(8,1) = roadrunner.hdmap.LaneBoundary; for i = 1:4 rrMap.LaneBoundaries(i*2-1).ID = strcat("Left",num2str(i)); rrMap.LaneBoundaries(i*2).ID = strcat("Right",num2str(i)); rrMap.LaneBoundaries(i*2-1).Geometry = eval(strcat('lftBndry',num2str(i))); rrMap.LaneBoundaries(i*2).Geometry = eval(strcat('rgtBndry',num2str(i))); end
指定车道和车道边界之间的路线。
leftBoundary(rrMap.Lanes(1),"Left1",Alignment="Forward"); rightBoundary(rrMap.Lanes(1),"Right1",Alignment="Forward"); leftBoundary(rrMap.Lanes(2),"Left2",Alignment="Forward"); rightBoundary(rrMap.Lanes(2),"Right2",Alignment="Forward"); leftBoundary(rrMap.Lanes(3),"Left3",Alignment="Forward"); rightBoundary(rrMap.Lanes(3),"Right3",Alignment="Forward"); leftBoundary(rrMap.Lanes(4),"Left4",Alignment="Forward"); rightBoundary(rrMap.Lanes(4),"Right4",Alignment="Forward");
指定车道标记
使用 roadrunner.hdmap.RelativeAssetPath
对象定义白色实线和白色虚线车道标记素材的文件路径。
wideSolidWhiteAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/Germany/WideSolidSingle.rrlms"); dashedWhiteAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/Germany/DashedSingle12.rrlms");
使用 roadrunner.hdmap.MarkingReference
对象为宽实心白色和虚线白色标记创建参考,以便将标记应用到车道边界。
markingRefSW = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="WideSolidWhite")); markingRefDW = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="DashedWhite"));
使用 roadrunner.hdmap.LaneMarking
对象创建车道标记。
rrMap.LaneMarkings(2,1) = roadrunner.hdmap.LaneMarking; rrMap.LaneMarkings(1).ID = "WideSolidWhite"; rrMap.LaneMarkings(2).ID = "DashedWhite"; rrMap.LaneMarkings(1).AssetPath = wideSolidWhiteAsset; rrMap.LaneMarkings(2).AssetPath = dashedWhiteAsset;
使用标记参考和自定义标记跨度创建参数属性。
prmAttr1Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.007],MarkingReference=markingRefSW); prmAttr1Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.007 0.01],MarkingReference=markingRefDW); prmAttr1Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.01 0.93],MarkingReference=markingRefSW); prmAttr1Span4 = roadrunner.hdmap.ParametricAttribution(Span=[0.93 0.95],MarkingReference=markingRefDW); prmAttr1Span5 = roadrunner.hdmap.ParametricAttribution(Span=[0.95 1],MarkingReference=markingRefSW); prmAttr2Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.575],MarkingReference=markingRefSW); prmAttr2Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.575 0.602],MarkingReference=markingRefDW); prmAttr2Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.602 1],MarkingReference=markingRefSW); prmAttr3Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 1],MarkingReference=markingRefSW); prmAttr4Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.439],MarkingReference=markingRefSW); prmAttr4Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.471 0.655],MarkingReference=markingRefSW); prmAttr4Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.684 1],MarkingReference=markingRefSW); prmAttr5Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.06 0.315],MarkingReference=markingRefSW); prmAttr5Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.73 0.94],MarkingReference=markingRefSW); prmAttr6Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.1 0.85],MarkingReference=markingRefSW); prmAttr7Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 1],MarkingReference=markingRefSW); prmAttr8Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.2 0.959],MarkingReference=markingRefSW);
指定车道边界的参数属性,使其类似于测试跑道。
rrMap.LaneBoundaries(1).ParametricAttributes = [prmAttr1Span1 prmAttr1Span2 prmAttr1Span3 prmAttr1Span4 prmAttr1Span5]; rrMap.LaneBoundaries(2).ParametricAttributes = [prmAttr2Span1 prmAttr2Span2 prmAttr2Span3]; rrMap.LaneBoundaries(3).ParametricAttributes = prmAttr3Span1; rrMap.LaneBoundaries(4).ParametricAttributes = [prmAttr4Span1 prmAttr4Span2 prmAttr4Span3]; rrMap.LaneBoundaries(5).ParametricAttributes = [prmAttr5Span1 prmAttr5Span2]; rrMap.LaneBoundaries(6).ParametricAttributes = prmAttr6Span1; rrMap.LaneBoundaries(7).ParametricAttributes = prmAttr7Span1; rrMap.LaneBoundaries(8).ParametricAttributes = prmAttr8Span1;
指定隔离物
为 BridgeRailing
素材创建参考,用于将隔离物应用到车道边界。
path = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Extrusions/BridgeRailing.rrext"); rrMap.BarrierTypes(1) = roadrunner.hdmap.BarrierType(ID="BridgeRailing",ExtrusionPath=path); guardRailRef = roadrunner.hdmap.Reference(ID="BridgeRailing");
使用 roadrunner.hdmap.Barrier
对象创建隔离物,并指定隔离物及其各自的几何形状。
rrMap.Barriers(5,1) = roadrunner.hdmap.Barrier; for i = 1:5 rrMap.Barriers(i).BarrierTypeReference = guardRailRef; rrMap.Barriers(i).ID = strcat('Barrier',num2str(i)); rrMap.Barriers(i).FlipLaterally = false; end rrMap.Barriers(1).Geometry = lftBndry1(6:428,:); rrMap.Barriers(2).Geometry = [x5 y5 ctrElev5]; rrMap.Barriers(3).Geometry = [x6 y6 ctrElev6]; rrMap.Barriers(4).Geometry = [x7 y7 ctrElev7]; rrMap.Barriers(5).Geometry = lftBndry4;
设置地理边界并将地图数据写入二进制文件
设置 RoadRunner 高清地图的地理边界会将场景集中在导入的道路上,使您能够将道路网络插入到场景中,而无需使用 RoadRunner 中的世界设置工具。
将地图的地理边界设置为左边界的最小和最大坐标值。
minBndry = min(lftBndry1); maxBndry = max(lftBndry1); rrMap.GeographicBoundary = [minBndry; maxBndry];
绘制车道中心和车道边界。
plot(rrMap) title("RoadRunner HD Map of Test Track") xlabel('x (m)') ylabel('y (m)')
使用 write
函数将 RoadRunner 高清地图写入二进制文件,并将该文件复制到项目的素材文件夹中。此代码使用示例 Windows® 项目路径。
fileName1 = "TestTrackMap.rrhd"; write(rrMap,fileName1) copyfile TestTrackMap.rrhd C:\RR\MyProjects\Assets\
将 RoadRunner 高清地图文件导入 RoadRunner
将 RoadRunner 高清地图文件导入 RoadRunner 以构建场景,然后保存场景。
要使用 MATLAB 打开 RoadRunner,请指定项目的路径。此代码显示了 Windows 中的示例项目文件夹。使用项目的指定路径打开 RoadRunner。
rrProjectPath = "C:\RR\MyProjects";
rrApp = roadrunner(rrProjectPath);
将 RoadRunner 高清地图文件导入 RoadRunner 并构建场景。要构建场景,您必须拥有有效的 RoadRunner Scene Builder 许可证。
options = roadrunnerHDMapImportOptions(ImportStep="Load"); importScene(rrApp,fullfile("C:\RR\MyProjects\Assets\","TestTrackMap.rrhd"),"RoadRunner HD Map",options) buildScene(rrApp,"RoadRunner HD Map")
保存构建的场景。
fileName2 = "TestTrackMap.rrscene";
saveScene(rrApp,fileName2)
此图显示了 RoadRunner 中测试赛道场景的 3D 场景。
要可视化地形表面,您可以使用 高程图工具 将 TestTrack.tif
文件导入 RoadRunner。