Этот пример показывает, что наземная сегментация плоскости 3-D данных о лидаре из транспортного средства на NVIDIA® встроила платформы, чтобы найти соседние препятствия. Использование в качестве примера основывает плоскую сегментацию и приложение обнаружения препятствия, чтобы проиллюстрировать:
C++ и генерация кода CUDA® для наземной сегментации плоскости и алгоритма обнаружения препятствия при помощи MATLAB® Coder™ и GPU Coder™.
Проверьте поведение сгенерированного кода на целевой платформе при помощи процессора в цикле (PIL) симуляция.
Сравните эффективности приложения на центральном процессоре (C++) и графический процессор (CUDA).
NVIDIA Джетсон Xavier™ NX Встроенная платформа.
NVIDIA инструментарий CUDA установлен на плате.
Переменные окружения на требуемой плате для компиляторов и библиотек. Для получения дополнительной информации смотрите Необходимые условия Установки и Setup для Советов NVIDIA (Пакет поддержки MATLAB Coder для NVIDIA, Джетсон и NVIDIA УПРАВЛЯЮТ Платформами).
NVIDIA инструментарий CUDA установлен на хосте.
Переменные окружения для компиляторов и библиотек. Для получения информации о поддерживаемых версиях компиляторов и библиотек, смотрите Стороннее Оборудование. Для подготовки переменных окружения смотрите Подготовку Необходимых как условие продуктов.
Пакет поддержки 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) симуляция, чтобы протестировать сгенерированный 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])};
Сгенерируйте Код С++ с объектом 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.
Очистите исполняемый файл 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 с объектом 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.
Отключите установки часов Джетсона, очистите исполняемый файл 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
jetson
(Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA УПРАВЛЯЕТ платформами), | drive
(Пакет поддержки MATLAB Coder для NVIDIA Джетсон и NVIDIA УПРАВЛЯЕТ платформами),