В этом примере показано, как создать автоматизированную систему парковочной камеры. В этом примере рассматриваются инструменты и методы для поддержки планирования траектории, формирования траектории и управления транспортным средством. Хотя в этом примере основное внимание уделяется ориентированному на MATLAB ® рабочему процессу, эти инструменты также доступны в Simulink ®. Версию этого примера Simulink ® см. в разделе Автоматическая парковка в Simulink.
Автоматическая парковка автомобиля, оставленного перед парковкой, является сложной проблемой. Ожидается, что автоматизированные системы транспортного средства возьмут на себя управление и направят транспортное средство в доступное место стоянки. Такая функция использует множество бортовых датчиков. Например:
Фронтальные и боковые камеры для обнаружения разметки полосы движения, дорожных знаков (стоп-знаков, разметки съезда и т.д.), других транспортных средств и пешеходов
Лидарные и ультразвуковые датчики для обнаружения препятствий и расчета точных измерений расстояния
Ультразвуковые датчики для обнаружения препятствий
IMU и кодеры колес для мертвых расплат
Бортовые датчики используются для восприятия окружающей среды вокруг транспортного средства. Воспринимаемая среда включает в себя понимание дорожной разметки для толкования правил дорожного движения и определения зон движения, распознавание препятствий и обнаружение доступных мест стоянки.
Поскольку датчики транспортного средства воспринимают мир, транспортное средство должно планировать путь через окружающую среду к свободному месту парковки и выполнять последовательность управляющих действий, необходимых для его движения. При этом он должен реагировать на динамические изменения в окружающей среде, такие как переход пешеходов через его путь, и корректировать свой план.
В этом примере реализуется подмножество функций, необходимых для реализации такой системы. Основное внимание уделяется планированию возможного пути через среду и выполнению действий, необходимых для прохождения пути. Создание карты и динамическое предотвращение препятствий исключаются из этого примера.
Модель среды представляет карту среды. Для парковочной системы эта карта включает доступные и занятые места стоянки, дорожную разметку и препятствия, такие как пешеходы или другие транспортные средства. Карты занятости являются общим представлением для этой формы модели среды. Такая карта обычно строится с использованием одновременной локализации и отображения (SLAM) путем интегрирования наблюдений с датчиков лидара и камеры. Этот пример концентрируется на более простом сценарии, где карта уже предоставляется, например, системой «транспортное средство-инфраструктура» (V2X) или камерой с видом на все парковочное место. Он использует статическую карту стоянки и предполагает, что самоликвидация транспортного средства точна.
Пример парковки, используемый в этом примере, состоит из трех слоев сетки занятости.
Стационарные препятствия: Этот слой содержит стационарные препятствия, такие как стены, барьеры и границы парковки.
Дорожная разметка: Этот слой содержит информацию о занятости, относящуюся к дорожной разметке, включая дорожную разметку для парковочных мест.
Припаркованные автомобили: Этот слой содержит информацию о том, какие парковочные места уже заняты.
Каждый слой карты содержит различные виды препятствий, которые представляют различные уровни опасности для автомобиля, проезжающего через него. С помощью этой структуры каждый уровень может обрабатываться, обновляться и обслуживаться независимо.
Загрузите и отобразите три слоя карты. В каждом слое темные клетки представляют собой занятые клетки, а светлые - свободные клетки.
mapLayers = loadParkingLotMapLayers; plotMapLayers(mapLayers)

Для простоты объедините три слоя в единую карту затрат.
costmap = combineMapLayers(mapLayers); figure plot(costmap, 'Inflation', 'off') legend off

Объединенное costmap является объект, представляющий окружающую среду транспортного средства в виде 2-D сетки занятости. Каждая сетка в ячейке имеет значения от 0 до 1, представляющие стоимость навигации по ячейке. Препятствия имеют более высокую стоимость, в то время как свободное пространство имеет более низкую стоимость. Ячейка считается препятствием, если ее стоимость выше, чем vehicleCostmapOccupiedThreshold собственность, и бесплатно, если ее стоимость ниже, чем FreeThreshold собственность.
costmap охватывает всю площадь парковки 75 м на 50 м, разделенную на квадратные ячейки 0,5 м на 0,5 м.
costmap.MapExtent % [x, width, y, height] in meters costmap.CellSize % cell size in meters
ans =
0 75 0 50
ans =
0.5000
Создать объект для хранения размеров транспортного средства, который будет парковаться автоматически. Также определите максимальный угол поворота транспортного средства. Это значение определяет пределы радиуса поворота при планировании и управлении движением.vehicleDimensions
vehicleDims = vehicleDimensions;
maxSteeringAngle = 35; % in degrees
Обновить VehicleDimensions свойство средства контроля столкновения costmap с размерами транспортного средства, подлежащего парковке. Эта настройка регулирует степень инфляции на карте вокруг препятствий, чтобы соответствовать размеру припаркованного транспортного средства, гарантируя, что свободные от столкновения пути могут быть найдены через стоянку.
costmap.CollisionChecker.VehicleDimensions = vehicleDims;
Определите начальную позу транспортного средства. Поза получается посредством локализации, которая для простоты оставлена вне этого примера. Поза транспортного средства указана как,
в мировых координатах.
представляет положение центра задней оси транспортного средства в мировой системе координат.
представляет ориентацию транспортного средства относительно мировой оси X. Дополнительные сведения см. в разделе Системы координат в автоматизированной панели инструментов вождения.
currentPose = [4 12 0]; % [x, y, theta]
Планирование включает в себя упорядочение всей релевантной информации по иерархическим уровням. Каждый последующий слой отвечает за более мелкозернистую задачу. Поведенческий слой [1] находится в верхней части этого стека. Он отвечает за активацию и управление различными частями миссии путем предоставления последовательности задач навигации. Поведенческий уровень собирает информацию из всех соответствующих частей системы, включая:
Локализация: Поведенческий уровень проверяет модуль локализации на предмет оценки текущего местоположения транспортного средства.
Модель окружающей среды: Системы слияния восприятия и датчиков сообщают карту окружающей среды вокруг транспортного средства.
Определение парковочного места: поведенческий слой анализирует карту для определения ближайшего доступного парковочного места.
Поиск глобального маршрута: Модуль маршрутизации вычисляет глобальный маршрут через дорожную сеть, полученную либо от картографической службы, либо от V2X инфраструктуры. Разложение глобального маршрута как серии дорожных связей позволяет по-разному планировать траекторию для каждого звена. Например, финальный маневр парковки требует иного профиля скорости, чем приближение к месту стоянки. В более общих условиях это становится решающим для навигации по улицам, которые включают различные ограничения скорости, количество полос движения и дорожные знаки.
Вместо того, чтобы полагаться на автомобильные датчики для построения карты окружающей среды, в этом примере используется карта, которая поступает с интеллектуальной парковки через V2X связь. Для простоты предположим, что карта представляет собой сетку с дорожными связями и местами имеющихся мест стоянки, обеспечиваемыми V2X.
HelperBehavioralPlanner класс имитирует интерфейс уровня поведенческого планирования. HelperBehavioralPlanner создается с использованием карты и глобального плана маршрута. В этом примере используется статический глобальный план маршрутов, сохраненный в таблице MATLAB, но обычно этот план определяется алгоритмом маршрутизации, предоставляемым локальной инфраструктурой парковки или службой отображения. Глобальный план трассы описывается как последовательность сегментов полосы движения, пересекаемых для достижения места парковки.
Загрузите MAT-файл, содержащий план маршрута, который хранится в таблице. Таблица содержит три переменные: StartPose, EndPose, и Attributes. StartPose и EndPose укажите начальную и конечную позы сегмента, выраженные как.
Attributes задает свойства сегмента, такие как ограничение скорости.
data = load('routePlan.mat'); routePlan = data.routePlan %#ok<NOPTS>
routePlan =
4×3 table
StartPose EndPose Attributes
______________ ________________ ____________
4 12 0 56 11 0 [1×1 struct]
56 11 0 70 19 90 [1×1 struct]
70 19 90 70 32 90 [1×1 struct]
70 32 90 53 39 180 [1×1 struct]
Постройте график транспортного средства в текущей позе и вдоль каждой цели в плане маршрута.
% Plot vehicle at current pose hold on helperPlotVehicle(currentPose, vehicleDims, 'DisplayName', 'Current Pose') legend for n = 1 : height(routePlan) % Extract the goal waypoint vehiclePose = routePlan{n, 'EndPose'}; % Plot the pose legendEntry = sprintf('Goal %i', n); helperPlotVehicle(vehiclePose, vehicleDims, 'DisplayName', legendEntry); end hold off

Создайте объект-помощник планировщика поведения. requestManeuver метод запрашивает поток задач навигации у планировщика поведения до тех пор, пока не будет достигнут пункт назначения.
behavioralPlanner = HelperBehavioralPlanner(routePlan, maxSteeringAngle);
Транспортное средство осуществляет навигацию по каждому сегменту пути с помощью следующих шагов:
Планирование движения: Планирование возможного пути через карту среды с использованием оптимального алгоритма быстрого исследования случайного дерева (RRT *) (pathPlannerRRT).
Сглаживание траектории: сглаживание траектории привязки путем подгонки к ней сплайнов с помощью .smoothPathSpline
Создание траектории: преобразование сглаженной траектории в траекторию путем создания профиля скорости с помощью helperGenerateVelocityProfile.
Управление транспортным средством: учитывая сглаженный исходный путь, HelperPathAnalyzer вычисляет исходную позу и скорость на основе текущей позы и скорости транспортного средства. Обеспечиваются эталонными значениями, вычисляет угол поворота для управления курсом транспортного средства. lateralControllerStanleyHelperLongitudinalController вычисляет команды ускорения и замедления для поддержания требуемой скорости транспортного средства.
Проверка цели: Проверьте, достигло ли транспортное средство конечной позы сегмента с помощью helperGoalChecker.
Остальная часть этого примера подробно описывает эти шаги перед их сборкой в полное решение.
При наличии глобального маршрута планирование движения может использоваться для планирования пути через окружающую среду для достижения каждого промежуточного ППМ до тех пор, пока транспортное средство не достигнет конечного пункта назначения. Запланированный путь для каждого канала должен быть выполнимым и свободным от конфликтов. Осуществимый путь - это путь, который может быть реализован транспортным средством с учетом движения и динамических ограничений, наложенных на него. Система парковочной камеры включает в себя низкие скорости и низкие ускорения. Это позволяет безопасно игнорировать динамические ограничения, возникающие в результате инерционных эффектов.
Создать объект для конфигурирования планировщика пути с использованием оптимального подхода быстрого исследования случайного дерева (RRT *). Семейство алгоритмов планирования RRT находит путь путем построения дерева связанных, свободных от столкновения поз транспортного средства. Позы соединяются с помощью рулевого управления Dubins или Reeds-Shepp, гарантируя, что сформированный путь является кинематически осуществимым.pathPlannerRRT
motionPlanner = pathPlannerRRT(costmap, 'MinIterations', 1000, ... 'ConnectionDistance', 10, 'MinTurningRadius', 20);
Планирование пути от текущей позы до первой цели с помощью plan функция. Возвращенный объект, driving.PathrefPath, является возможным и свободным от столкновений опорным путем.
goalPose = routePlan{1, 'EndPose'};
refPath = plan(motionPlanner, currentPose, goalPose);
Ссылочный путь состоит из последовательности сегментов пути. Каждый сегмент пути описывает набор манёвров Дубинса или Ридса-Шеппа, используемых для соединения со следующим сегментом. Проверьте сегменты траектории.
refPath.PathSegments
ans =
1×6 DubinsPathSegment array with properties:
StartPose
GoalPose
MinTurningRadius
MotionLengths
MotionTypes
Length
Опорная траектория содержит переходные позы вдоль траектории, представляющие точки вдоль траектории, соответствующие переходу от одного манёвра к следующему. Они также могут представлять изменения в направлении, например, от движения вперед к движению назад вдоль пути Ридса-Шеппа.
Извлечение позиций и направлений перехода из запланированного пути.
[transitionPoses, directions] = interpolate(refPath);
% Visualize the planned path
plot(motionPlanner)

В дополнение к запланированной опорной траектории обратите внимание на красные области на графике. Эти области представляют собой области карты расходов, где происхождение транспортного средства (центр задней оси) не должно пересекаться во избежание наезда на какие-либо препятствия. находит пути, которые избегают препятствий, проверяя, чтобы сгенерированные позы транспортного средства не лежали на этих участках.pathPlannerRRT
Ссылочный путь, созданный планировщиком пути, состоит из сегментов Dubins или Reeds-Shepp. Кривизна в местах соединения двух таких сегментов не является непрерывной и может привести к резким изменениям угла поворота. Чтобы избежать такого неестественного движения и обеспечить пассажирам комфорт, путь должен быть непрерывно дифференцируемым и, следовательно, гладким [2]. Один из подходов к сглаживанию траектории включает подгонку параметрического кубического сплайна. Сплайновый фитинг позволяет создать гладкую траекторию, которую может выполнить контроллер.
Использовать для размещения параметрического кубического сплайна, который проходит через все точки перехода в траектории привязки. Шлиц приблизительно соответствует начальному и конечному направлениям с начальным и конечным курсовыми углами транспортного средства.smoothPathSpline
% Specify number of poses to return using a separation of approximately 0.1 m approxSeparation = 0.1; % meters numSmoothPoses = round(refPath.Length / approxSeparation); % Return discretized poses along the smooth path [refPoses, directions, cumLengths, curvatures] = smoothPathSpline(transitionPoses, directions, numSmoothPoses); % Plot the smoothed path hold on hSmoothPath = plot(refPoses(:, 1), refPoses(:, 2), 'r', 'LineWidth', 2, ... 'DisplayName', 'Smoothed Path'); hold off

Затем преобразуйте сгенерированную гладкую траекторию в траекторию, которая может быть выполнена с использованием профиля скорости. Вычислите профиль скорости для каждого пути как последовательность из трех фаз: ускорение до заданной максимальной скорости, поддержание максимальной скорости и замедление до конечной скорости. helperGenerateVelocityProfile функция генерирует такой профиль скорости.
Укажите начальную, максимальную и конечную скорости так, чтобы транспортное средство начиналось неподвижно, ускорялось до скорости 5 метров/с и останавливалось.
maxSpeed = 5; % in meters/second startSpeed = 0; % in meters/second endSpeed = 0; % in meters/second
Создание профиля скорости
refVelocities = helperGenerateVelocityProfile(directions, cumLengths, curvatures, startSpeed, endSpeed, maxSpeed);
refVelocities содержит опорные скорости для каждой точки вдоль сглаженной траектории. Постройте график сгенерированного профиля скорости.
plotVelocityProfile(cumLengths, refVelocities, maxSpeed)

Опорные скорости вместе со сглаженной траекторией содержат возможную траекторию, по которой может следовать транспортное средство. Для отслеживания этой траектории используется контроллер обратной связи. Контроллер исправляет ошибки в отслеживании траектории, возникающие из-за проскальзывания шины и других источников шума, таких как неточности в локализации. В частности, контроллер состоит из двух компонентов:
Регулировка угла поворота таким образом, чтобы транспортное средство следовало по исходной траектории.
Продольное управление: При следовании по контрольному пути поддерживайте желаемую скорость, управляя дросселем и тормозом.
Поскольку этот сценарий включает в себя медленные скорости, можно упростить контроллер, чтобы учесть только кинематическую модель. В этом примере боковое управление реализуется посредством функция. Продольное управление осуществляется с помощью вспомогательной системы object™ lateralControllerStanleyHelperLongitudinalController, которая вычисляет команды ускорения и замедления на основе пропорционального интегрального закона.
Контроллер обратной связи требует имитатора, который может выполнять требуемые команды контроллера с использованием подходящей модели транспортного средства. HelperVehicleSimulator класс моделирует такое транспортное средство с использованием следующей кинематической модели велосипеда:




В вышеприведенных уравнениях
представляет положение транспортного средства в мировых координатах.,, 

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



% Close all the figures closeFigures; % Create the vehicle simulator vehicleSim = HelperVehicleSimulator(costmap, vehicleDims); % Set the vehicle pose and velocity vehicleSim.setVehiclePose(currentPose); currentVel = 0; vehicleSim.setVehicleVelocity(currentVel); % Configure the simulator to show the trajectory vehicleSim.showTrajectory(true); % Hide vehicle simulation figure hideFigure(vehicleSim);
Создать HelperPathAnalyzer объект для вычисления опорной позы, опорной скорости и направления движения для контроллера.
pathAnalyzer = HelperPathAnalyzer(refPoses, refVelocities, directions, ... 'Wheelbase', vehicleDims.Wheelbase);
Создать HelperLongitudinalController цель - контроль скорости транспортного средства и определение времени отбора проб.
sampleTime = 0.05;
lonController = HelperLongitudinalController('SampleTime', sampleTime);
Используйте HelperFixedRate обеспечение выполнения контроллера обратной связи с фиксированной скоростью. Используйте управляющую скорость для согласования с продольным контроллером.
controlRate = HelperFixedRate(1/sampleTime); % in Hertz
Пока цель не достигнута, выполните следующие действия:
Вычислите команды управления и ускорения/замедления, необходимые для отслеживания планируемой траектории.
Подача команд управления в тренажер.
Запишите положение и скорость возвращаемого транспортного средства для подачи в контроллер в следующей итерации.
reachGoal = false; while ~reachGoal % Find the reference pose on the path and the corresponding velocity [refPose, refVel, direction] = pathAnalyzer(currentPose, currentVel); % Update driving direction for the simulator updateDrivingDirection(vehicleSim, direction); % Compute steering command steeringAngle = lateralControllerStanley(refPose, currentPose, currentVel, ... 'Direction', direction, 'Wheelbase', vehicleDims.Wheelbase); % Compute acceleration and deceleration commands lonController.Direction = direction; [accelCmd, decelCmd] = lonController(refVel, currentVel); % Simulate the vehicle using the controller outputs drive(vehicleSim, accelCmd, decelCmd, steeringAngle); % Check if the vehicle reaches the goal reachGoal = helperGoalChecker(goalPose, currentPose, currentVel, endSpeed, direction); % Wait for fixed-rate execution waitfor(controlRate); % Get current pose and velocity of the vehicle currentPose = getVehiclePose(vehicleSim); currentVel = getVehicleVelocity(vehicleSim); end % Show vehicle simulation figure showFigure(vehicleSim);

На этом завершается первый этап плана маршрута и демонстрируется каждый шаг процесса. Следующие секции запускают тренажер для всего маршрута, который принимает транспортное средство близко к месту стоянки, и, наконец, выполняет маневр парковки, чтобы поместить транспортное средство в место стоянки.
Теперь объедините все предыдущие шаги в процессе планирования и выполните моделирование для полного плана маршрута. Этот процесс включает включение планировщика поведения.
% Set the vehicle pose back to the initial starting point currentPose = [4 12 0]; % [x, y, theta] vehicleSim.setVehiclePose(currentPose); % Reset velocity currentVel = 0; % meters/second vehicleSim.setVehicleVelocity(currentVel); while ~reachedDestination(behavioralPlanner) % Request next maneuver from behavioral layer [nextGoal, plannerConfig, speedConfig] = requestManeuver(behavioralPlanner, ... currentPose, currentVel); % Configure the motion planner configurePlanner(motionPlanner, plannerConfig); % Plan a reference path using RRT* planner to the next goal pose refPath = plan(motionPlanner, currentPose, nextGoal); % Check if the path is valid. If the planner fails to compute a path, % or the path is not collision-free because of updates to the map, the % system needs to re-plan. This scenario uses a static map, so the path % will always be collision-free. isReplanNeeded = ~checkPathValidity(refPath, costmap); if isReplanNeeded warning('Unable to find a valid path. Attempting to re-plan.') % Request behavioral planner to re-plan replanNeeded(behavioralPlanner); continue; end % Retrieve transition poses and directions from the planned path [transitionPoses, directions] = interpolate(refPath); % Smooth the path numSmoothPoses = round(refPath.Length / approxSeparation); [refPoses, directions, cumLengths, curvatures] = smoothPathSpline(transitionPoses, directions, numSmoothPoses); % Generate a velocity profile refVelocities = helperGenerateVelocityProfile(directions, cumLengths, curvatures, startSpeed, endSpeed, maxSpeed); % Configure path analyzer pathAnalyzer.RefPoses = refPoses; pathAnalyzer.Directions = directions; pathAnalyzer.VelocityProfile = refVelocities; % Reset longitudinal controller reset(lonController); reachGoal = false; % Execute control loop while ~reachGoal % Find the reference pose on the path and the corresponding velocity [refPose, refVel, direction] = pathAnalyzer(currentPose, currentVel); % Update driving direction for the simulator updateDrivingDirection(vehicleSim, direction); % Compute steering command steeringAngle = lateralControllerStanley(refPose, currentPose, currentVel, ... 'Direction', direction, 'Wheelbase', vehicleDims.Wheelbase); % Compute acceleration and deceleration commands lonController.Direction = direction; [accelCmd, decelCmd] = lonController(refVel, currentVel); % Simulate the vehicle using the controller outputs drive(vehicleSim, accelCmd, decelCmd, steeringAngle); % Check if the vehicle reaches the goal reachGoal = helperGoalChecker(nextGoal, currentPose, currentVel, speedConfig.EndSpeed, direction); % Wait for fixed-rate execution waitfor(controlRate); % Get current pose and velocity of the vehicle currentPose = getVehiclePose(vehicleSim); currentVel = getVehicleVelocity(vehicleSim); end end % Show vehicle simulation figure showFigure(vehicleSim);

Теперь, когда транспортное средство находится рядом с местом стоянки, для парковки транспортного средства в месте конечной стоянки используется специализированный парковочный маневр. Этот маневр требует прохождения через узкий коридор, фланкированный краями парковочного места с обоих концов. Такой маневр обычно сопровождается ультразвуковыми датчиками или лазерными сканерами, непрерывно проверяющими наличие препятствий.
% Hide vehicle simulation figure
hideFigure(vehicleSim);
vehicleCostmap использует проверку конфликтов на основе инфляции. Сначала визуально проверьте текущее используемое средство проверки на столкновение.
ccConfig = costmap.CollisionChecker;
figure
plot(ccConfig)
title('Current Collision Checker')

Проверка на столкновение выполняется путем надувания препятствий в карте затрат по радиусу надувания и проверки, лежит ли центр круга, показанного выше, на накачанной ячейке сетки. Окончательный маневр парковки требует более точного, менее консервативного механизма проверки столкновения. Это обычно решается путем представления формы транспортного средства с использованием нескольких (3-5) перекрывающихся окружностей вместо одной окружности.
Используйте большее количество кругов в средстве проверки столкновений и визуально проверьте средство проверки столкновений. Это позволяет планировать через узкие проходы.
ccConfig.NumCircles = 4;
figure
plot(ccConfig)
title('New Collision Checker')

Обновите карту затрат, чтобы использовать эту проверку коллизий.
costmap.CollisionChecker = ccConfig;
Обратите внимание, что радиус инфляции уменьшился, что позволяет планировщику найти беспрепятственный путь к месту парковки.
figure plot(costmap) title('Costmap with updated collision checker') % Set up the pathPlannerRRT to use the updated costmap parkMotionPlanner = pathPlannerRRT(costmap, 'MinIterations', 1000); % Define desired pose for the parking spot, returned by the V2X system parkPose = [36 44 90]; preParkPose = currentPose; % Compute the required parking maneuver refPath = plan(parkMotionPlanner, preParkPose, parkPose); % Plot the resulting parking maneuver figure plotParkingManeuver(costmap, refPath, preParkPose, parkPose)


Как только маневр будет найден, повторите предыдущий процесс, чтобы определить полный план: сгладить траекторию, сформировать профиль скорости и следовать по траектории с помощью контроллера обратной связи.
% Retrieve transition poses and directions from the planned path [transitionPoses, directions] = interpolate(refPath); % Smooth the path numSmoothPoses = round(refPath.Length / approxSeparation); [refPoses, directions, cumLengths, curvatures] = smoothPathSpline(transitionPoses, directions, numSmoothPoses); % Set up the velocity profile generator to stop at the end of the trajectory, % with a speed limit of 5 mph refVelocities = helperGenerateVelocityProfile(directions, cumLengths, curvatures, currentVel, 0, 2.2352); pathAnalyzer.RefPoses = refPoses; pathAnalyzer.Directions = directions; pathAnalyzer.VelocityProfile = refVelocities; % Reset longitudinal controller reset(lonController); reachGoal = false; while ~reachGoal % Find the reference pose on the path and the corresponding velocity [refPose, refVel, direction] = pathAnalyzer(currentPose, currentVel); % Update driving direction for the simulator updateDrivingDirection(vehicleSim, direction); % Compute steering command steeringAngle = lateralControllerStanley(refPose, currentPose, currentVel, ... 'Direction', direction, 'Wheelbase', vehicleDims.Wheelbase); % Compute acceleration and deceleration commands lonController.Direction = direction; [accelCmd, decelCmd] = lonController(refVel, currentVel); % Simulate the vehicle using the controller outputs drive(vehicleSim, accelCmd, decelCmd, steeringAngle); % Check if the vehicle reaches the goal reachGoal = helperGoalChecker(parkPose, currentPose, currentVel, 0, direction); % Wait for fixed-rate execution waitfor(controlRate); % Get current pose and velocity of the vehicle currentPose = getVehiclePose(vehicleSim); currentVel = getVehicleVelocity(vehicleSim); end % Show vehicle simulation figure closeFigures; showFigure(vehicleSim);

Альтернативным способом парковки является возвращение в место стоянки. Когда транспортному средству необходимо выполнить резервное копирование в точку, планировщик движения должен использовать метод соединения Ридса-Шеппа для поиска возможного пути. Соединение Ридс-Шепп допускает обратные движения во время планирования.
% Specify a parking pose corresponding to a back-in parking maneuver parkPose = [49 47.2 -90]; % Change the connection method to allow for reverse motions parkMotionPlanner.ConnectionMethod = 'Reeds-Shepp';

Для поиска возможного пути необходимо скорректировать планировщик движения. Используйте больший радиус поворота и расстояние соединения, чтобы обеспечить плавную обратную связь.
parkMotionPlanner.MinTurningRadius = 10; % meters parkMotionPlanner.ConnectionDistance = 15; % Reset vehicle pose and velocity currentVel = 0; vehicleSim.setVehiclePose(preParkPose); vehicleSim.setVehicleVelocity(currentVel); % Compute the parking maneuver replan = true; while replan refPath = plan(parkMotionPlanner, preParkPose, parkPose); % The path corresponding to the parking maneuver is small and requires % precise maneuvering. Instead of interpolating only at transition poses, % interpolate more finely along the length of the path. numSamples = 10; stepSize = refPath.Length / numSamples; lengths = 0 : stepSize : refPath.Length; [transitionPoses, directions] = interpolate(refPath, lengths); % Replan if the path contains more than one direction switching poses % or if the path is too long replan = sum(abs(diff(directions)))~=2 || refPath.Length > 20; end % Visualize the parking maneuver figure plotParkingManeuver(costmap, refPath, preParkPose, parkPose)


% Smooth the path numSmoothPoses = round(refPath.Length / approxSeparation); [refPoses, directions, cumLengths, curvatures] = smoothPathSpline(transitionPoses, directions, numSmoothPoses, 0.5); % Generate velocity profile refVelocities = helperGenerateVelocityProfile(directions, cumLengths, curvatures, currentVel, 0, 1); pathAnalyzer.RefPoses = refPoses; pathAnalyzer.Directions = directions; pathAnalyzer.VelocityProfile = refVelocities; % Reset longitudinal controller reset(lonController); reachGoal = false; while ~reachGoal % Get current driving direction currentDir = getDrivingDirection(vehicleSim); % Find the reference pose on the path and the corresponding velocity. [refPose, refVel, direction] = pathAnalyzer(currentPose, currentVel); % If the vehicle changes driving direction, reset vehicle velocity in % the simulator and reset longitudinal controller if currentDir ~= direction currentVel = 0; setVehicleVelocity(vehicleSim, currentVel); reset(lonController); end % Update driving direction for the simulator. If the vehicle changes % driving direction, reset and return the current vehicle velocity as zero. currentVel = updateDrivingDirection(vehicleSim, direction, currentDir); % Compute steering command steeringAngle = lateralControllerStanley(refPose, currentPose, currentVel, ... 'Direction', direction, 'Wheelbase', vehicleDims.Wheelbase); % Compute acceleration and deceleration commands lonController.Direction = direction; [accelCmd, decelCmd] = lonController(refVel, currentVel); % Simulate the vehicle using the controller outputs drive(vehicleSim, accelCmd, decelCmd, steeringAngle); % Check if the vehicle reaches the goal reachGoal = helperGoalChecker(parkPose, currentPose, currentVel, 0, direction); % Wait for fixed-rate execution waitfor(controlRate); % Get current pose and velocity of the vehicle currentPose = getVehiclePose(vehicleSim); currentVel = getVehicleVelocity(vehicleSim); end % Take a snapshot for the example closeFigures; snapnow; % Delete the simulator delete(vehicleSim);

В этом примере показано, как:
Планирование возможного пути в полуструктурированной среде, такой как стоянка, с использованием алгоритма планирования пути RRT *.
Сглаживание траектории с помощью сплайнов и формирование профиля скорости вдоль сглаженной траектории.
Управление транспортным средством для следования по контрольному пути с требуемой скоростью.
Реализуйте различные варианты парковки с помощью различных настроек планировщика движения.
[1] Бюлер, Мартин, Карл Иагнемма и Санджив Сингх. Городской вызов DARPA: автономные транспортные средства в городском движении (1-е изд.). Springer Publishing Company, Incorporated, 2009.
[2] Лепетик, Марко, Грегор Кланкар, Игорь Скрян, Драго Матко, Бостьян Поточник, «Планирование оптимального пути времени с учетом пределов ускорения». Робототехника и автономные системы. Том 45, выпуски 3-4, 2003, стр. 199-210.
loadLotMapLayers Загрузка слоев карты среды для парковки
function mapLayers = loadParkingLotMapLayers() %loadParkingLotMapLayers % Load occupancy maps corresponding to 3 layers - obstacles, road % markings, and used spots. mapLayers.StationaryObstacles = imread('stationary.bmp'); mapLayers.RoadMarkings = imread('road_markings.bmp'); mapLayers.ParkedCars = imread('parked_cars.bmp'); end
plotMapLayers Структура печати, содержащая слои карты
function plotMapLayers(mapLayers) %plotMapLayers % Plot the multiple map layers on a figure window. figure cellOfMaps = cellfun(@imcomplement, struct2cell(mapLayers), 'UniformOutput', false); montage( cellOfMaps, 'Size', [1 numel(cellOfMaps)], 'Border', [5 5], 'ThumbnailSize', [300 NaN] ) title('Map Layers - Stationary Obstacles, Road markings, and Parked Cars') end
Объединение combineMapLayers наносит на карту слои в единственный costmap
function costmap = combineMapLayers(mapLayers) %combineMapLayers % Combine map layers struct into a single vehicleCostmap. combinedMap = mapLayers.StationaryObstacles + mapLayers.RoadMarkings + ... mapLayers.ParkedCars; combinedMap = im2single(combinedMap); res = 0.5; % meters costmap = vehicleCostmap(combinedMap, 'CellSize', res); end
configureПланировщик Настройка планировщика путей с заданными параметрами
function configurePlanner(pathPlanner, config) %configurePlanner % Configure the path planner object, pathPlanner, with settings specified % in struct config. fieldNames = fields(config); for n = 1 : numel(fieldNames) if ~strcmpi(fieldNames{n}, 'IsParkManeuver') pathPlanner.(fieldNames{n}) = config.(fieldNames{n}); end end end
plotVelocityProfile Профиль скорости печати
function plotVelocityProfile(cumPathLength, refVelocities, maxSpeed) %plotVelocityProfile % Plot the generated velocity profile % Plot reference velocity along length of the path plot(cumPathLength, refVelocities, 'LineWidth', 2); % Plot a line to display maximum speed hold on line([0;cumPathLength(end)], [maxSpeed;maxSpeed], 'Color', 'r') hold off % Set axes limits buffer = 2; xlim([0 cumPathLength(end)]); ylim([0 maxSpeed + buffer]) % Add labels xlabel('Cumulative Path Length (m)'); ylabel('Velocity (m/s)'); % Add legend and title legend('Velocity Profile', 'Max Speed') title('Generated velocity profile') end
closeFigures
function closeFigures() % Close all the figures except the simulator visualization % Find all the figure objects figHandles = findobj('Type', 'figure'); for i = 1: length(figHandles) if ~strcmp(figHandles(i).Name, 'Automated Valet Parking') close(figHandles(i)); end end end
plotTraManuver Отображение сформированного маневра парковки на карте затрат
function plotParkingManeuver(costmap, refPath, currentPose, parkPose) %plotParkingManeuver % Plot the generated parking maneuver on a costmap. % Plot the costmap, without inflated areas plot(costmap, 'Inflation', 'off') % Plot reference parking maneuver on the costmap hold on plot(refPath, 'DisplayName', 'Parking Maneuver') title('Parking Maneuver') % Zoom into parking maneuver by setting axes limits lo = min([currentPose(1:2); parkPose(1:2)]); hi = max([currentPose(1:2); parkPose(1:2)]); buffer = 6; % meters xlim([lo(1)-buffer hi(1)+buffer]) ylim([lo(2)-buffer hi(2)+buffer]) end