Оснуйте Плоское Обнаружение Сегментации и Препятствия на NVIDIA Джетсон Xavier™ NX Встроенная платформа

Этот пример показывает, что наземная сегментация плоскости 3-D данных о лидаре из транспортного средства на NVIDIA® встроила платформы, чтобы найти соседние препятствия. Использование в качестве примера основывает плоскую сегментацию и приложение обнаружения препятствия, чтобы проиллюстрировать:

  • C++ и генерация кода CUDA® для наземной сегментации плоскости и алгоритма обнаружения препятствия при помощи MATLAB® Coder™ и GPU Coder™.

  • Проверьте поведение сгенерированного кода на целевой платформе при помощи процессора в цикле (PIL) симуляция.

  • Сравните эффективности приложения на центральном процессоре (C++) и графический процессор (CUDA).

Сторонние необходимые условия

Требования требуемой платы

  • NVIDIA Джетсон Xavier™ NX Встроенная платформа.

  • NVIDIA инструментарий CUDA установлен на плате.

  • Переменные окружения на требуемой плате для компиляторов и библиотек. Для получения дополнительной информации смотрите Необходимые условия Установки и Setup для Советов NVIDIA (Пакет поддержки MATLAB Coder для NVIDIA, Джетсон и NVIDIA УПРАВЛЯЮТ Платформами).

Требования узла разработки

Сконфигурируйте и проверьте целевую платформу NVIDIA

Свяжите с оборудованием NVIDIA

Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA Платформы Drive™ использует связь SSH по TCP/IP, чтобы выполнить команды при создании и выполнении сгенерированного кода на платформах Джетсона. Соедините целевую платформу с той же сетью как хост - компьютер.

Чтобы связаться с оборудованием NVIDIA, создайте живой аппаратный объект связи при помощи jetson (Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA УПРАВЛЯЕТ Платформами), функция. Этот пример использует адрес устройства, имя пользователя и установки пароля с новой успешной связи на оборудование Джетсона.

hwobj = jetson;
Checking for CUDA availability on the Target...
Checking for 'nvcc' in the target system path...
Checking for cuDNN library availability on the Target...
Checking for TensorRT library availability on the Target...
Checking for prerequisite libraries is complete.
Gathering hardware details...
Checking for third-party library availability on the Target...
Gathering hardware details is complete.
 Board name         : NVIDIA Jetson AGX Xavier
 CUDA Version       : 10.2
 cuDNN Version      : 8.0
 TensorRT Version   : 7.1
 GStreamer Version  : 1.14.5
 V4L2 Version       : 1.14.2-1
 SDL Version        : 1.2
 OpenCV Version     : 4.1.1
 Available Webcams  : HP Webcam HD 4310
 Available GPUs     : Xavier

Сконфигурируйте PIL симуляцию

Этот пример использует процессор в цикле (PIL) симуляция, чтобы протестировать сгенерированный C++ и код CUDA по плате Джетсона. Поскольку передача входных данных и расчеты алгоритма используют время, измените значение по умолчанию выше значение тайм-аута PIL, чтобы предотвратить ошибки из-за тайм-аута.

setPILTimeout(hwobj,100);

Проверьте среду графического процессора

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

envCfg = coder.gpuEnvConfig('jetson');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
envCfg.HardwareObject = hwobj;
coder.checkGpuInstall(envCfg);

Сконфигурируйте параметры генерации кода

Чтобы сгенерировать исполняемый файл PIL, который работает на центральном процессоре ARM® платы Джетсона, создайте coder.EmbeddedCodeConfig объект для статической библиотеки.

cfgCpu = coder.config('lib');

Установите выходной язык для сгенерированного кода на C++ и включите выполнение PIL в объекте настройки кода. Затем включите время выполнения, профилируя во время выполнения PIL. Время выполнения профилируя генерирует метрики для задач и функций в сгенерированном коде. Для получения дополнительной информации смотрите, что Выполнение кода Профилирует с SIL и PIL (Embedded Coder). Наконец, создайте coder.hardware объект для платформы Джетсона и присвоения это к Hardware свойство объекта настройки кода.

cfgCpu.TargetLang = 'C++';
cfgCpu.VerificationMode = 'PIL';
cfgCpu.CodeExecutionProfiling = true;
cfgCpu.Hardware = coder.hardware('NVIDIA Jetson');

Точно так же создайте параметры конфигурации для графического процессора CUDA на плате Джетсона при помощи coder.gpuConfig.

cfgGpu = coder.gpuConfig('lib');
cfgGpu.VerificationMode = 'PIL';
cfgGpu.CodeExecutionProfiling = true;
cfgGpu.Hardware = coder.hardware('NVIDIA Jetson');

segmentGroundAndObstacles Функция точки входа

segmentGroundAndObstacles точки сегментов функции точки входа, принадлежащие наземной плоскости, автомобилю, оборудованному датчиком и соседним препятствиям от местоположений облака точки ввода. Следующая схема иллюстрирует алгоритм, реализованный в функции точки входа. Для получения дополнительной информации смотрите Наземное Обнаружение Плоскости и Препятствия Используя Лидар (Automated Driving Toolbox).

type segmentGroundAndObstacles
function [egoPoints, groundPoints, obstaclePoints] = ...
    segmentGroundAndObstacles(ptCloudLocation)
%segmentGroundAndObstacles segments ground and nearby obstacle points from 
%the pointcloud.
%   egoPoints = segmentGroundAndObstacles(ptCloudLocation) segments the 
%   ground points and nearby obstacle points from the input argument 
%   ptCloudLocation. egoPoints are the vehicle points segmented with the 
%   help of helper function helperSegmentEgoFromLidarData. 
%   segmentGroundFromLidarData is used to segment the ground points, 
%   groundPoints. findNeighborsInRadius is used to segment the nearby 
%   obstacles, obstaclePoints.
%
%   [..., groundPoints, obstaclePoints] = segmentGroundAndObstacles(...)
%   additionally returns segmented groundPoints and obstaclePoints.

%   Copyright 2021 The MathWorks, Inc.

%#codegen

% GPU Coder pragma
coder.gpu.kernelfun;

% Create a pointCloud object for point cloud locations
ptCloud = pointCloud(ptCloudLocation);

%% Segment the Ego Vehicle
% The lidar is mounted on top of the vehicle, and the point cloud may 
% contain points belonging to the vehicle itself, such as on the roof or 
% hood. Knowing the dimensions of the vehicle, we can segment out points 
% that are closest to the vehicle.

% Create a vehicleDimensions object for storing dimensions of the vehicle.
% Typical vehicle 4.7m by 1.8m by 1.4m

vehicleDims.Length = 4.7;
vehicleDims.Width = 1.8;
vehicleDims.Height = 1.4;
vehicleDims.RearOverhang = 1.0;

% Specify the mounting location of the lidar in the vehicle coordinate 
% system. The vehicle coordinate system is centered at the center of the 
% rear-axle, on the ground, with positive X direction pointing forward, 
% positive Y towards the left, and positive Z upwards. In this example, 
% the lidar is mounted on the top center of the vehicle, parallel to the 
% ground.

mountLocation = [...
    vehicleDims.Length/2 - vehicleDims.RearOverhang, ... % x
    0, ...                                               % y
    vehicleDims.Height];                                 % z

% Segment the ego vehicle using the helper function 
% |helperSegmentEgoFromLidarData|. This function segments all points within
% the cuboid defined by the ego vehicle. 

egoPoints = helperSegmentEgoFromLidarData(ptCloudLocation, vehicleDims, mountLocation);

%% Segment Ground Plane and Nearby Obstacles
% In order to identify obstacles from the lidar data, first segment the 
% ground plane using the segmentGroundFromLidarData function to accomplish 
% this. This function segments points belonging to the ground from organized 
% lidar data.

elevationDelta = 10;
groundPoints = segmentGroundFromLidarData(ptCloud, 'ElevationAngleDelta', elevationDelta);

% Remove points belonging to the ego vehicle and the ground plane by using 
% the select function on the point cloud. Specify the 'OutputSize' as 
% 'full' to retain the organized nature of the point cloud. For CUDA code 
% generation, an optimized approach for removing the points is considered.

nonEgoGroundPoints = coder.nullcopy(egoPoints);
coder.gpu.kernel;
for iter = 1:numel(egoPoints)
    nonEgoGroundPoints(iter) = ~egoPoints(iter) & ~groundPoints(iter);
end

ptCloudSegmented = select(ptCloud, nonEgoGroundPoints, 'OutputSize', 'full');

% Next, segment nearby obstacles by looking for all points that are not 
% part of the ground or ego vehicle within some radius from the ego
% vehicle. This radius can be determined based on the range of the lidar 
% and area of interest for further processing.

sensorLocation  = [0, 0, 0]; % Sensor is at the center of the coordinate system
radius          = 40; % meters

obstaclePoints = findNeighborsInRadius(ptCloudSegmented, sensorLocation, radius);

end


function egoPoints = helperSegmentEgoFromLidarData(ptCloudLocation, vehicleDims, mountLocation)
%#codegen
%helperSegmentEgoFromLidarData segment ego vehicle points from lidar data
%   egoPoints = helperSegmentEgoFromLidarData(ptCloudLocation,vehicleDims,mountLocation)
%   segments points belonging to the ego vehicle of dimensions vehicleDims
%   from the lidar scan ptCloud. The lidar is mounted at location specified
%   by mountLocation in the vehicle coordinate system. ptCloud is a
%   pointCloud object. vehicleDimensions is a vehicleDimensions object.
%   mountLocation is a 3-element vector specifying XYZ location of the
%   lidar in the vehicle coordinate system.
%
%   This function assumes that the lidar is mounted parallel to the ground
%   plane, with positive X direction pointing ahead of the vehicle,
%   positive Y direction pointing to the left of the vehicle in a
%   right-handed system.

% GPU Coder pragma
coder.gpu.kernelfun;

% Buffer around ego vehicle 
bufferZone = [0.1, 0.1, 0.1]; % in meters

% Define ego vehicle limits in vehicle coordinates
egoXMin = -vehicleDims.RearOverhang - bufferZone(1);
egoXMax = egoXMin + vehicleDims.Length + bufferZone(1);
egoYMin = -vehicleDims.Width/2 - bufferZone(2);
egoYMax = egoYMin + vehicleDims.Width + bufferZone(2);
egoZMin = 0 - bufferZone(3);
egoZMax = egoZMin + vehicleDims.Height + bufferZone(3);

egoXLimits = [egoXMin, egoXMax];
egoYLimits = [egoYMin, egoYMax];
egoZLimits = [egoZMin, egoZMax];

% Transform to lidar coordinates
egoXLimits = egoXLimits - mountLocation(1);
egoYLimits = egoYLimits - mountLocation(2);
egoZLimits = egoZLimits - mountLocation(3);

% Use logical indexing to select points inside ego vehicle cube
egoPoints = ptCloudLocation(:,:,1) > egoXLimits(1) ...
    & ptCloudLocation(:,:,1) < egoXLimits(2) ...
    & ptCloudLocation(:,:,2) > egoYLimits(1) ...
    & ptCloudLocation(:,:,2) < egoYLimits(2) ...
    & ptCloudLocation(:,:,3) > egoZLimits(1) ...
    & ptCloudLocation(:,:,3) < egoZLimits(2);
end

Сгенерируйте и запущенные исполняемые файлы на цели

Данные об облаке точек из датчика лидара имеют размер 32 1 100 3. Должный сигнализировать промахам и шуму, на несколько пунктов можно упасть из этих данных об облаке точек. Так, второе измерение может меняться в зависимости от верхней границы 1 100. Создайте входной тип для функции точки входа segmentGroundAndObstacles с различными размерностями для второго аргумента с помощью coder.typeof функция.

codegenArgs = {coder.typeof(single(0),[32,1100,3],[0,1,0])};

Сгенерируйте и запущенный исполняемый файл C++

Сгенерируйте Код С++ с объектом cfgCpu настройки центрального процессора кода.

codegen -config cfgCpu -args codegenArgs segmentGroundAndObstacles -report
### Connectivity configuration for function 'segmentGroundAndObstacles': 'NVIDIA Jetson'
PIL execution is using Port 17725.
PIL execution is using 100 Sec(s) for receive time-out.
Code generation successful: View report

obstacleDetectionWrapper функция обертки выполнения, которая обрабатывает покадровые входные данные лидара потоковой передачи, вызывает исполняемый файл PIL и отображает 3-D облако точек с сегментацией точек, принадлежащих наземной плоскости, автомобилю, оборудованному датчиком и соседним препятствиям. Данные о лидаре, используемые в этом примере, были зарегистрированы с помощью датчика Velodyne HDL32E, смонтированного на транспортном средстве. Для объяснения обработки, выполняемой obstacleDetectionWrapper функционируйте, смотрите Наземное Обнаружение Плоскости и Препятствия Используя Лидар (Automated Driving Toolbox).

obstacleDetectionWrapper();
### Starting application: 'codegen/lib/segmentGroundAndObstacles/pil/segmentGroundAndObstacles.elf'
    To terminate execution: clear segmentGroundAndObstacles_pil
### Launching application segmentGroundAndObstacles.elf...
    Execution profiling data is available for viewing. Open Simulation Data Inspector.
    Execution profiling report available after termination.

Профиль выполнения исполняемого файла C++

Очистите исполняемый файл PIL и соберите профиль времени выполнения при помощи getCoderExecutionProfile функция.

clear segmentGroundAndObstacles_pil;
PIL execution terminated on target.
### Connectivity configuration for function 'segmentGroundAndObstacles': 'NVIDIA Jetson'
PIL execution is using Port 17725.
PIL execution is using 100 Sec(s) for receive time-out.
    Execution profiling report: report(getCoderExecutionProfile('segmentGroundAndObstacles'))
cpuExecutionProfile = getCoderExecutionProfile('segmentGroundAndObstacles');

Сгенерируйте и запущенный исполняемый файл CUDA

Сгенерируйте код CUDA с объектом cfgGpu настройки графического процессора кода.

codegen -config cfgGpu -args codegenArgs segmentGroundAndObstacles -report
### Connectivity configuration for function 'segmentGroundAndObstacles': 'NVIDIA Jetson'
PIL execution is using Port 17725.
PIL execution is using 100 Sec(s) for receive time-out.
Code generation successful: View report

Чтобы максимизировать эффективность графического процессора, используйте jetson_clocks.sh скрипт на плате. Для получения дополнительной информации смотрите NVIDIA Ксавьер - Максимизация Эффективности (RidgeRun wiki).

system(hwobj,'echo "ubuntu" | sudo -S jetson_clocks');

Используйте obstacleDetectionWrapper чтобы обработать входные данные лидара потоковой передачи, вызывает исполняемый файл PIL, и отобразите 3-D облако точек с сегментацией точек, принадлежащих наземной плоскости, автомобилю, оборудованному датчиком и соседним препятствиям.

obstacleDetectionWrapper();
### Starting application: 'codegen/lib/segmentGroundAndObstacles/pil/segmentGroundAndObstacles.elf'
    To terminate execution: clear segmentGroundAndObstacles_pil
### Launching application segmentGroundAndObstacles.elf...
    Execution profiling data is available for viewing. Open Simulation Data Inspector.
    Execution profiling report available after termination.

Профиль выполнения исполняемого файла CUDA

Отключите установки часов Джетсона, очистите исполняемый файл PIL и соберите профиль времени выполнения при помощи getCoderExecutionProfile функция.

system(hwobj,'echo "ubuntu" | sudo -S jetson_clocks --restore');
clear segmentGroundAndObstacles_pil;
PIL execution terminated on target.
### Connectivity configuration for function 'segmentGroundAndObstacles': 'NVIDIA Jetson'
PIL execution is using Port 17725.
PIL execution is using 100 Sec(s) for receive time-out.
    Execution profiling report: report(getCoderExecutionProfile('segmentGroundAndObstacles'))
gpuExecutionProfile = getCoderExecutionProfile('segmentGroundAndObstacles');

Анализ профилей выполнения центрального процессора и графического процессора

Доберитесь во времена выполнения системы координат центрального процессора и графического процессора от их профилей выполнения при помощи ExecutionTimeInSeconds свойство.

[~,cpuExecTimePerFrame,~] = cpuExecutionProfile.Sections.ExecutionTimeInSeconds;
[~,gpuExecTimePerFrame,~] = gpuExecutionProfile.Sections.ExecutionTimeInSeconds;

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

figure;
% Plot CPU execution times.
plot(cpuExecTimePerFrame(2:end)*1000,'r');
hold on;
% Plot GPU execution times.
plot(gpuExecTimePerFrame(2:end)*1000,'b');
grid on;
% Set the title, legend and labels.
title('CPU vs GPU Per-frame Execution times (in ms)');
legend('GPU Timings', 'CPU Timings');
axis([0,1240,0,40]);
xlabel('Frame Number');
ylabel('Execution Time (in ms)');

Вспомогательные Функции

obstacleDetectionWrapper обрабатывает данные о лидаре, вызывает исполняемый файл PIL, и визуализируйте результаты. Для объяснения обработки, выполняемой obstacleDetectionWrapper функционируйте, смотрите Наземное Обнаружение Плоскости и Препятствия Используя Лидар (Automated Driving Toolbox).

function obstacleDetectionWrapper()
%OBSTACLEDETECTIONWRAPPER process lidar data and visualize results
%   The OBSTACLEDETECTIONWRAPPER is an execution wrapper function that
%   processess the streaming lidar input data frame-by-frame, calls the PIL
%   executable, and displays the 3-D point cloud with segmenting points
%   belonging to the ground plane, the ego vehicle, and nearby obstacles.

fileName    = 'lidarData_ConstructionRoad.pcap';
deviceModel = 'HDL32E';
veloReader = velodyneFileReader(fileName, deviceModel);

% Setup Streaming Point Cloud Display
xlimits = [-25 45];   % Limits of point cloud display, meters
ylimits = [-25 45];
zlimits = [-20 20];

% Create a pcplayer
lidarViewer = pcplayer(xlimits, ylimits, zlimits);
xlabel(lidarViewer.Axes, 'X (m)')
ylabel(lidarViewer.Axes, 'Y (m)')
zlabel(lidarViewer.Axes, 'Z (m)')

% Set the colormap for labeling the ground plane, ego vehicle, and nearby
% obstacles.
colorLabels = [...
    0      0.4470 0.7410; ... % Unlabeled points, specified as [R,G,B]
    0.4660 0.6740 0.1880; ... % Ground points
    0.9290 0.6940 0.1250; ... % Ego points
    0.6350 0.0780 0.1840];    % Obstacle points

% Define indices for each label
colors.Unlabeled = 1;
colors.Ground    = 2;
colors.Ego       = 3;
colors.Obstacle  = 4;

% Set the colormap
colormap(lidarViewer.Axes, colorLabels)

% Stop processing the frame after specified time.
stopTime = veloReader.EndTime;

i = 1;
isPlayerOpen = true;
while hasFrame(veloReader) && veloReader.CurrentTime < stopTime && isPlayerOpen

    % Grab the next lidar scan
    ptCloud = readFrame(veloReader);

    % Segment points belonging to the ego vehicle
    [egoPoints,groundPoints,obstaclePoints] = segmentGroundAndObstacles_pil(ptCloud.Location);

    i = i+1;
    closePlayer = ~hasFrame(veloReader);

    % Update lidar display
    points = struct('EgoPoints',egoPoints, 'GroundPoints',groundPoints, ...
        'ObstaclePoints',obstaclePoints);
    isPlayerOpen = helperUpdateView(lidarViewer, ptCloud, points, colors, closePlayer);
end
snapnow
end

helperUpdateView обновляет отображение облака точек потоковой передачи с последним облаком точек и сопоставленными цветными метками.

function isPlayerOpen = helperUpdateView(lidarViewer,ptCloud,points,colors,closePlayer)
%HELPERUPDATEVIEW update streaming point cloud display
%   isPlayerOpen =
%   HELPERUPDATEVIEW(lidarViewer,ptCloud,points,colors,closePlayers)
%   updates the pcplayer object specified in lidarViewer with a new point
%   cloud ptCloud. Points specified in the struct points are colored
%   according to the colormap of lidarViewer using the labels specified by
%   the struct colors. closePlayer is a flag indicating whether to close
%   the lidarViewer.

if closePlayer
    hide(lidarViewer);
    isPlayerOpen = false;
    return;
end

scanSize = size(ptCloud.Location);
scanSize = scanSize(1:2);

% Initialize colormap
colormapValues = ones(scanSize, 'like', ptCloud.Location) * colors.Unlabeled;

if isfield(points, 'GroundPoints')
    colormapValues(points.GroundPoints) = colors.Ground;
end

if isfield(points, 'EgoPoints')
    colormapValues(points.EgoPoints) = colors.Ego;
end

if isfield(points, 'ObstaclePoints')
    colormapValues(points.ObstaclePoints) = colors.Obstacle;
end

% Update view
view(lidarViewer, ptCloud.Location, colormapValues)

% Check if player is open
isPlayerOpen = isOpen(lidarViewer);

end

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

Объекты

  • (Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA УПРАВЛЯЕТ платформами), | (Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA УПРАВЛЯЕТ платформами),

Похожие темы