Коррекция локализации Используя данные о дорожном знаке отсюда карты HD

В этом примере показано, как использовать данные о дорожном знаке из HD HERE Живая Карта (HERE HDLM) сервис откорректировать измерения GPS, собранные автономным транспортным средством.

Обзор

Данные HERE HDLM содержат очень подробную информацию и достоверную информацию о среде транспортного средства, такой как дорога и топология маршрута, и подходят для разработки автоматизированных ведущих приложений. Для обзора данных, которые доступны отсюда слои HDLM, смотрите, что HD HERE Живет Слои Карты. Этот пример фокусируется на слое HD Localization Model, который содержит точную и плотную информацию о дорожных знаках. Можно улучшить точность локализации путем объединения этой информации с живыми обнаружениями дорожных знаков от встроенных датчиков. Этот пример демонстрирует упрощенное решение, в котором вы получаете данные о местоположении дорожного знака и затем используете их, чтобы откорректировать показания GPS. Больше полного решения использует такие данные в качестве ориентиров в основанном на ориентире конвейере одновременной локализации и картографии (SLAM).

В этом примере вы учитесь как:

  1. Читайте и информация о дорожном знаке процесса отсюда данные HDLM с помощью последовательности GPS.

  2. Совпадайте с дорожными знаками, обнаруженными встроенными датчиками лидара и камеры со знаками, сохраненными в данных HERE HDLM.

  3. Вычислите ошибку положения путем сравнения известных местоположений знака в HERE HDLM к возвращенным из GPS местоположениям и откорректируйте результаты локализации.

Загрузите данные о датчике

Данные о датчике транспортного средства, используемые в этом примере, были зарегистрированы к rosbag использование ROS. Пример включает только отрывок rosbag, чтобы показать, как извлечь, синхронизировать, и постобработать данные. Чтобы оптимизировать коррекцию локализации, остальная часть примера использует постобработанные данные, хранимые в файлах MAT.

% Download sensor data
baseDownloadURL = 'https://ssd.mathworks.com/supportfiles/vision/data/localizationAutonomousCarDataset.zip'; 
dataFolder = fullfile(tempdir,'localizationAutonomousCarDataset',filesep); 
options = weboptions('Timeout',Inf);
zipFileName = [dataFolder,'localizationAutonomousCarDataset.zip'];
folderExists = exist(dataFolder,'dir');

% Create a folder in a temporary directory to save the downloaded file
if ~folderExists  
    mkdir(dataFolder)
    disp('Downloading localizationAutonomousCarDataset.zip (1.01 GB). This download can take a few minutes.') 
    websave(zipFileName, baseDownloadURL, options); 
    
    % Extract contents of the downloaded file
    disp('Extracting localizationAutonomousCarDataset.zip (1.01 GB) ...') 
    unzip(zipFileName, dataFolder)
end

% Extract data from a rosbag (requires ROS Toolbox)
readRosbagData = false;
hasROSToolbox = license('test','ros_toolbox');
if readRosbagData && hasROSToolbox   
    filepath = [dataFolder,'\rosbag\demoRosbag.bag'];
    % helperReadRosbag uses a small rosbag sample to show how a larger 
    % rosbag can be processed.  An entire data set is loaded below from MAT files.
    [ptCloudsRosbag, imgsRosbag, gpsRosbag] = helperReadRosbag(filepath);
end

% Load synchronized sensor data directly from MAT files. This data was 
% extracted from a much larger rosbag collected using an autonomous car.
imgs = load([dataFolder,'\sensor\images.mat']).imgs;    % Images
ptClouds = load([dataFolder,'\sensor\ptClouds.mat']).pcds;  % Point clouds
gps = load([dataFolder,'\sensor\gps.mat']).gps;        % GPS signals

В полном конвейере вы сначала обнаруживаете дорожные знаки в системах координат камеры, и затем проектируете их на облака точек лидара с помощью результата калибровки фотоаппарата лидара. Эта проекция дает вам 3-D местоположения дорожных знаков, которые могут использоваться, чтобы вычислить ошибочную метрику на основе дорожных знаков, обнаруженных в данных о карте HD HERE. Чтобы упростить обработку в целях рисунка, данные о дорожном знаке в этом примере были аннотированы рукой с помощью приложения Ground Truth Labeler. Загрузите ограничительные рамки дорожных знаков и для изображений и для облаков точек.

imgBBoxes = load([dataFolder,'\utility\imgBBoxes.mat']).imgBBoxes;
pcBBoxes = load([dataFolder,'\utility\pcBBoxes.mat']).pcBBoxes;

Не исказите изображения при помощи калибровки фотоаппарата. Калибровочные данные были получены с помощью приложения Camera Calibrator.

camCalib = load([dataFolder,'\utility\calibration.mat']).calib;
intrinsics = camCalib.intrinsics;

Отобразите одну из систем координат, чтобы смотреть данные о датчике.

% Pick a frame
frameIndex = 110; 

% Display the camera image and 2-D bounding box of the traffic sign 
helperDisplayCameraFrame(imgs,imgBBoxes,frameIndex,intrinsics);

% Display the point cloud and 3-D bounding box of the traffic sign 
helperDisplayPointCloud(ptClouds, pcBBoxes, frameIndex);

Данные HERE HDLM содержат ссылки в мозаиках карты. Загрузите координаты GPS полного маршрута. Этот маршрут покрывает ссылку, которая расширяет более чем три мозаики HDLM.

gpsRoute = load([dataFolder,'\utility\gpsRoute.mat']).gps_route;

Считайте данные о карте

Чтобы считать данные из мозаик карты, что маршрут GPS включен, используйте hereHDLMReader объект. Использование HD HERE Живой Картографический сервис требует допустимых учетных данных HERE HDLM. Необходимо заключить отдельное соглашение с HERE для того, чтобы получить доступ к сервисам HDLM и получить необходимые учетные данные (access_key_id и access_key_secret) для использования Сервиса HERE.

% Create and configure the reader
config = hereHDLMConfiguration('hrn:here:data::olp-here-had:here-hdlm-protobuf-na-2',2291);
reader = hereHDLMReader(gpsRoute(:,1),gpsRoute(:,2),'Configuration',config);

% Read data
topologyLayer = read(reader,'TopologyGeometry');
signLayer= read(reader,'LocalizationSign');

Предварительно обработайте данные, чтобы улучшить время поиска при запросе необходимых данных. Функция помощника helperProcessHDLMData, заданный в конце примера, следует маршрутом GPS и возвращает следующие данные:

  • linkData — Содержит все ссылки, существующие в мозаиках, охватывающих маршрут GPS. Ссылки сегментируются на пары [lat, lon] координаты.

  • signData — Содержит информацию о знаках, доступных в мозаиках, охватывающих маршрут GPS.

[linkData,signData] = helperProcessHDLMData(config,topologyLayer,signLayer);

Локализация, соответствие дорожного знака и исправление ошибок

Чтобы локализовать автономное транспортное средство, используйте измерения GPS и ссылки, формирующие каждую дорогу в TopologyGeometry слой:

  1. Для каждого местоположения GPS найдите самую близкую ссылку в мозаике с помощью helperFindClosestLink функция.

  2. Найдите самый близкий дорожный знак к положению транспортного средства на основе LocalizationSign данные о слое. Затем соответствие, которые подают знак тому из дорожных знаков, обнаруженных лидаром и камерой.

  3. Если дорожный знак больше не обнаруживается, вычислите разность в положении между дорожными знаками, обнаруженными лидаром и камерой и дорожными знаками, выбранными из данных HERE HDLM.

  4. Примените коррекции к предыдущим измерениям GPS.

% Initialize variables
hdlmDetectedSigns = zeros(0,2);
lidarDetectedSigns = zeros(0,2);
relevantGPS = zeros(0,2); 
finalGPS = zeros(0,4);
finalSigns = zeros(0,4);
numDetections = 0;

for i = 1:numel(gps)
    
    gpsMeasurement = gps{i};
    pcBBox = pcBBoxes{i};
    
    % Find the closest link
    closestLinkID = helperFindClosestLink(linkData, gpsMeasurement);
    
    isSignDetected = ~isempty(pcBBox);
    if isSignDetected
        % If a traffic sign is detected by lidar and camera, find the ID of
        % the traffic sign that is closest to the current GPS position.
        distToSigns = helperDistance(gpsMeasurement(1),gpsMeasurement(2), ...
            signData(:,2),signData(:,3));
        [~,minIndex] = min(distToSigns);
        closestSignID = signData(minIndex,1);
        
        % Make sure that the closest traffic sign is on the closest link
        for m = 1:size(signLayer,1)
            roadToSignsRefs = signLayer(m,1).RoadToSignsReferences;
            
            if ismember(closestLinkID,[roadToSignsRefs.LinkRef])
                signRefs = vertcat(roadToSignsRefs.SignRefs);
                if ismember(closestSignID,[signRefs.SignId])
                    % Transform the coordinates from the lidar frame to the GPS frame
                    [lat,lon] = helperLidar2latlon(pcBBox,gps,i);
                    
                    % Store relevant results
                    hdlmDetectedSigns = [hdlmDetectedSigns; signData(minIndex,2:3)]; %#ok<*AGROW>
                    lidarDetectedSigns = [lidarDetectedSigns; lat, lon];
                    relevantGPS = [relevantGPS; gpsMeasurement(1:2)];
                    numDetections = numDetections+1;
                    break
                end
            end
        end
        
    elseif numDetections > 1
        % Once a traffic sign is not detected anymore, calculate the error between 
        % the traffic signs detected by the lidar and camera and the traffic signs 
        % selected from the HDLM data.
        error = hdlmDetectedSigns(end,1:2) - mean(lidarDetectedSigns(:,1:2));
        
        % Apply the correction to the GPS coordinates reported by the GPS sensor
        correctedGPS = relevantGPS + error;
        
        % Store results
        finalGPS = [finalGPS; relevantGPS, correctedGPS];
        finalSigns = [finalSigns; mean(lidarDetectedSigns), hdlmDetectedSigns(end,:)];
        
        % Re-initialize storage variables
        numDetections = 0;
        relevantGPS = zeros(0,2);
        hdlmDetectedSigns = zeros(0,2);
        lidarDetectedSigns = zeros(0,2);
    end
end

Отобразите результаты на карте

Отобразите результаты конвейера локализации на карте с помощью расчетных измерений широты и долготы.

helperDisplayResults(finalSigns,finalGPS,topologyLayer);

Откорректированная трассировка локализации совпадает с локализацией уровня маршрута более точно по сравнению с фактическим диском.

Функции помощника

helperReadRosbag считывает данные о датчике из rosbag, и выходные параметры синхронизировали облака точек, изображения и данные о GPS. Это предназначается, чтобы проиллюстрировать обработку rosbag. В этом примере это обрабатывает только отрывок данных, которые хранятся в постобработанных файлах MAT. Эта функция требует ROS Toolbox™.

function [ptClouds, images, gps] = helperReadRosbag(filepath)

bag = rosbag(filepath);

% Names of ROS topics
lidarTopic = '/os1_cloud_node/points';
imageTopic = '/camera/image_color';
gpsTopic = '/raw_fix';

bagLidar = select(bag,'Topic',lidarTopic);
bagImage = select(bag,'Topic',imageTopic);
bagGPS = select(bag,'Topic',gpsTopic);

% Read the messages
msgStructsImage = readMessages(bagImage);
msgStructsPC = readMessages(bagLidar);
msgStructsGPS = readMessages(bagGPS);

numLidarFrames = size(bagLidar.MessageList,1);

ptClouds = cell(numLidarFrames, 1);
images = cell(numLidarFrames, 1);
gps = cell(numLidarFrames, 1);

% Since each sensor runs at a different frequency, use the
% lidar's acquisition rate as the basis for synchronizing lidar, 
% video and GPS data. Collect frames from other sensors by
% selecting the closest ones according to their time stamps.
for i = 1:numLidarFrames
    timeStamp = bagLidar.MessageList.Time(i);
    
    % Lidar point cloud
    msgPC = msgStructsPC{i};
    ptClouds{i} = pointCloud(readXYZ(msgPC));
    
    % Camera data
    [~, minIdx] = min(abs(bagImage.MessageList.Time-timeStamp));
    images{i} = readImage(msgStructsImage{minIdx});
    
    % GPS data
    [~, minIdx] = min(abs(bagGPS.MessageList.Time-timeStamp));
    gps{i} = [msgStructsGPS{minIdx}.Latitude, ...
        msgStructsGPS{minIdx}.Longitude, ...
        msgStructsGPS{minIdx}.Altitude];
end
end

helperProcessHDLMData обрабатывает доступные данные в TopologyGeometry и LocalizationSign слои используются для локализации.

function [linkData,signData] = helperProcessHDLMData(config,topologyLayer,signLayer)

% Collect all the links in the tiles from the TopologyGeometry layer
[linkIDs,linkGeometries] = helperCollectLinksData(config,topologyLayer);

% Divide the links into segments of two points. This gives more accurate 
% results when finding the closest link for a given GPS position
linkData = helperSegmentLinks(linkIDs,linkGeometries);

% Collect all the signs in the tiles from the LocalizationSign layer
signData = helperCollectSignData(signLayer);
end

helperCollectLinksData собирает релевантную информацию относительно всех ссылок, которые появляются в мозаиках.

function [linkIDs, linkGeometries] = helperCollectLinksData(config,topologyLayer)

linkIDs=[];
linkGeometries=[];

intersectLinkRefs = vertcat(topologyLayer.IntersectingLinkRefs);
tileIDs = unique(vertcat(intersectLinkRefs.LinkHereTileId));
reader = hereHDLMReader(tileIDs,'Configuration',config);
topologies = read(reader,'TopologyGeometry'); 

for j = 1:size(topologyLayer,1)
    % Intersecting links
    currIntersectLinkRefs = topologyLayer(j, 1).IntersectingLinkRefs;
    for i = 1:size(currIntersectLinkRefs,1)
        tileID = currIntersectLinkRefs(i).LinkHereTileId;
        linkID = currIntersectLinkRefs(i).LinkId;
        topology = topologies(tileIDs==tileID);
        
        linksStartingInTile = topology.LinksStartingInTile;
        linksTileID = vertcat(linksStartingInTile.LinkId);
        linkGeometry = linksStartingInTile(linksTileID==linkID).Geometry.Here2dCoordinateDiffs;
        linkIDs = [linkIDs; linkID];
        linkGeometries = [linkGeometries; {linkGeometry}];
    end
    
    % Links starting in tile
    linksStartingInTile = topologyLayer(j,1).LinksStartingInTile;
    for i = 1:size(linksStartingInTile,1)
        linkIDs = [linkIDs; linksStartingInTile(i).LinkId];
        linkGeometry = linksStartingInTile(i).Geometry.Here2dCoordinateDiffs;
        linkGeometries = [linkGeometries; {linkGeometry}];
    end
end
end

helperCollectSignData собирает идентификаторы и положения дорожных знаков.

function signData = helperCollectSignData(signLayer)

signData = [];
for i = 1:size(signLayer,1)
    signData = [signData; double(vertcat(signLayer(i).Signs.SignId)), ...
        vertcat(signLayer(i).Signs.Here2dCoordinate)];
end
end

helperSegmentLinks разбивает длинные ссылки в более короткие сегменты.

function linkData = helperSegmentLinks(linkIDs,linkGeometries)

linkData = zeros(0,5); % [LinkID, start_lat, start_lon, end_lat, end_lon]
for i = 1:numel(linkIDs)
    points = linkGeometries{i};
    numSegments = size(points, 1) - 1;
    linkData = [linkData; [repmat(double(linkIDs(i)),numSegments,1), ...
        points(1:numSegments, 1:2), points(2:numSegments+1, 1:2)]];
end
end

helperFindClosestLink находит самую близкую ссылку на местоположение GPS.

function closestLinkID = helperFindClosestLink(linkData,gps)

% Compute distance to link
distToLinkStart = helperDistance(gps(1),gps(2),linkData(:, 2),linkData(:, 3));
distToLinkEnd = helperDistance(gps(1),gps(2),linkData(:, 4),linkData(:, 5));
distToLinks = min(distToLinkStart,distToLinkEnd);

% Find closest link
[~,index] = min(distToLinks);
closestLinkID = linkData(index, 1);
end

helperLidar2latlon преобразует координаты от системы координат лидара до системы координат GPS.

function [lat,lon] = helperLidar2latlon(bbox, gps, i)
% Converts the lidar coordinates of the detected traffic sign to latitude and 
% longitude measurements. This is done by first converting the lidar coordinates 
% to the vehicle frame, then the East, North, Up (ENU) frame, and finally the GPS frame.

% Center of the bounding box in the lidar frame.
center = bbox(1:3);

% Calculate the bearing angle.
lon1 = gps{1,i-4}(1);
lon2 = gps{1,i}(1);
lat1 = gps{1,i-4}(2);
lat2 = gps{1,i}(2);

dLon = lon2 - lon1;
y = sin(dLon) * cos(lat2);
x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
theta = atan2(y, x);

initialBearing = mod(theta + 2*pi, 2*pi);
finalBearing   = mod(initialBearing + pi/2, 2*pi);

% Transform from the lidar frame to the vehicle frame.
x = -center(1);
y = -center(2);

% Transform from the vehicle frame to the ENU frame.
e = sin(finalBearing)*x - cos(finalBearing)*y;
n = cos(finalBearing)*x + sin(finalBearing)*y;

% Transform from the ENU frame to the GPS frame.
% The origin of the ENU local frame is set to the current GPS location.
origin     = [gps{1,i}(1) gps{1,i}(2) gps{1,i}(3)];
[lat,lon] = local2latlon(e,n,0,origin);
end

helperDistance вычисляет расстояние между двумя группами точек GPS.

function d = helperDistance(lat1,lon1,lat2,lon2)
numSignals = numel(lat2);
[x,y] = latlon2local(lat2,lon2,zeros(numSignals,1),[lat1 lon1 0]); % Assuming zero altitude
d = sqrt(x.^2 + y.^2);
end

helperDisplayResults отображает результаты GPS конвейера на карте. Эта основная карта является отсюда Технологиями и требует допустимой лицензии, отдельной от вашей лицензии HERE HDLM. Чтобы использовать эту карту, необходимо ввести идентификатор Приложения и Код Приложения, соответствующий лицензии HERE.

function helperDisplayResults(finalSigns,finalGPS,topologyLayer)

% Create dialog box for entering the App ID and App Code of your HERE license.
url = ['https://2.base.maps.cit.api.here.com/maptile/2.1/maptile/', ...
    'newest/normal.day/${z}/${x}/${y}/256/png?app_id=%s&app_code=%s'];

prompt = {'HERE App ID:','HERE App Code:'};
title = 'HERE Tokens';

dims = [1 40]; % Text edit field height and width
hereTokens = inputdlg(prompt,title,dims);

if ~isempty(hereTokens)
    
    % Add HERE basemap with custom attribution.
    url = sprintf(url,hereTokens{1},hereTokens{2});
    copyrightSymbol = char(169); 
    attribution = [copyrightSymbol,' ',datestr(now,'yyyy'),' HERE'];
    addCustomBasemap('herestreets',url,'Attribution',attribution);
    
    f = figure('Name','Corrected GPS measurements');
    gx = geoaxes("Parent",f);
    plot(topologyLayer,'Axes',gx);
    hold(gx,'on');
    legend(gx,'Boundaries','Nodes','Links','Location','northwest');
    
    nlat = [finalSigns(1,1) finalSigns(end,1)];
    nlon = [finalSigns(1,2) finalSigns(end,2)];
    nzoom = 16;
    
    geolimits(gx,nlat,nlon);
    gx.ZoomLevel = nzoom;
    
    geobasemap(gx,'herestreets');
    geoplot(gx,finalSigns(:,1),finalSigns(:,2),'o','DisplayName','Lidar traffic signs');
    geoplot(gx,finalSigns(:,3),finalSigns(:,4),'*','DisplayName','HDLM traffic signs');
    geoplot(gx,finalGPS(:,1),finalGPS(:,2),'r-+','DisplayName','GPS before correction');
    geoplot(gx,finalGPS(:,3),finalGPS(:,4),'g-+','DisplayName','GPS after correction');
else
    error('You must enter valid credentials to access maps from HERE Technologies');
end
end

helperDisplayCameraFrame отображения одно изображение камеры с 2D ограничительными рамками дорожного знака.

function helperDisplayCameraFrame(imgs,imgBBoxes,frameIndex,intrinsics)

img = undistortImage(imgs{frameIndex},intrinsics);

f  = figure('Name','Camera frame');
ax = gca(f);

% Display camera frame
imshow(img,'Parent',ax);
hold(ax,'on')

showShape('rectangle',imgBBoxes{frameIndex},'Color','blue','LineWidth',2,'Parent',ax);
end

helperDisplayPointCloud отображения одно облако точек лидара с 3-D ограничительными рамками дорожного знака.

function helperDisplayPointCloud(ptClouds,pcBBoxes,frameIndex)

f = figure('Name','Point cloud');
ax = gca(f);

pcshow(ptClouds{frameIndex},'Parent',ax);
hold(ax,'on')
xlabel(ax,'X')
ylabel(ax,'Y')
zlabel(ax,'Z')

xlim([-40 40])
ylim([-20 40])
zlim([-5 10])
view([90 45])

showShape('cuboid', pcBBoxes{frameIndex},'Color','red','LineWidth',2,'Parent',ax);
end

Смотрите также

Похожие темы