exponenta event banner

Автоматическая парковочная камера

В этом примере показано, как создать автоматизированную систему парковочной камеры. В этом примере рассматриваются инструменты и методы для поддержки планирования траектории, формирования траектории и управления транспортным средством. Хотя в этом примере основное внимание уделяется ориентированному на MATLAB ® рабочему процессу, эти инструменты также доступны в Simulink ®. Версию этого примера Simulink ® см. в разделе Автоматическая парковка в Simulink.

Обзор

Автоматическая парковка автомобиля, оставленного перед парковкой, является сложной проблемой. Ожидается, что автоматизированные системы транспортного средства возьмут на себя управление и направят транспортное средство в доступное место стоянки. Такая функция использует множество бортовых датчиков. Например:

  • Фронтальные и боковые камеры для обнаружения разметки полосы движения, дорожных знаков (стоп-знаков, разметки съезда и т.д.), других транспортных средств и пешеходов

  • Лидарные и ультразвуковые датчики для обнаружения препятствий и расчета точных измерений расстояния

  • Ультразвуковые датчики для обнаружения препятствий

  • IMU и кодеры колес для мертвых расплат

Бортовые датчики используются для восприятия окружающей среды вокруг транспортного средства. Воспринимаемая среда включает в себя понимание дорожной разметки для толкования правил дорожного движения и определения зон движения, распознавание препятствий и обнаружение доступных мест стоянки.

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

В этом примере реализуется подмножество функций, необходимых для реализации такой системы. Основное внимание уделяется планированию возможного пути через среду и выполнению действий, необходимых для прохождения пути. Создание карты и динамическое предотвращение препятствий исключаются из этого примера.

Модель среды

Модель среды представляет карту среды. Для парковочной системы эта карта включает доступные и занятые места стоянки, дорожную разметку и препятствия, такие как пешеходы или другие транспортные средства. Карты занятости являются общим представлением для этой формы модели среды. Такая карта обычно строится с использованием одновременной локализации и отображения (SLAM) путем интегрирования наблюдений с датчиков лидара и камеры. Этот пример концентрируется на более простом сценарии, где карта уже предоставляется, например, системой «транспортное средство-инфраструктура» (V2X) или камерой с видом на все парковочное место. Он использует статическую карту стоянки и предполагает, что самоликвидация транспортного средства точна.

Пример парковки, используемый в этом примере, состоит из трех слоев сетки занятости.

  • Стационарные препятствия: Этот слой содержит стационарные препятствия, такие как стены, барьеры и границы парковки.

  • Дорожная разметка: Этот слой содержит информацию о занятости, относящуюся к дорожной разметке, включая дорожную разметку для парковочных мест.

  • Припаркованные автомобили: Этот слой содержит информацию о том, какие парковочные места уже заняты.

Каждый слой карты содержит различные виды препятствий, которые представляют различные уровни опасности для автомобиля, проезжающего через него. С помощью этой структуры каждый уровень может обрабатываться, обновляться и обслуживаться независимо.

Загрузите и отобразите три слоя карты. В каждом слое темные клетки представляют собой занятые клетки, а светлые - свободные клетки.

mapLayers = loadParkingLotMapLayers;
plotMapLayers(mapLayers)

Для простоты объедините три слоя в единую карту затрат.

costmap = combineMapLayers(mapLayers);

figure
plot(costmap, 'Inflation', 'off')
legend off

Объединенное costmap является vehicleCostmap объект, представляющий окружающую среду транспортного средства в виде 2-D сетки занятости. Каждая сетка в ячейке имеет значения от 0 до 1, представляющие стоимость навигации по ячейке. Препятствия имеют более высокую стоимость, в то время как свободное пространство имеет более низкую стоимость. Ячейка считается препятствием, если ее стоимость выше, чем OccupiedThreshold собственность, и бесплатно, если ее стоимость ниже, чем 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,y,\theta]$в мировых координатах.$(x,y)$ представляет положение центра задней оси транспортного средства в мировой системе координат.$\theta$ представляет ориентацию транспортного средства относительно мировой оси X. Дополнительные сведения см. в разделе Системы координат в автоматизированной панели инструментов вождения.

currentPose = [4 12 0]; % [x, y, theta]

Поведенческий слой

Планирование включает в себя упорядочение всей релевантной информации по иерархическим уровням. Каждый последующий слой отвечает за более мелкозернистую задачу. Поведенческий слой [1] находится в верхней части этого стека. Он отвечает за активацию и управление различными частями миссии путем предоставления последовательности задач навигации. Поведенческий уровень собирает информацию из всех соответствующих частей системы, включая:

  • Локализация: Поведенческий уровень проверяет модуль локализации на предмет оценки текущего местоположения транспортного средства.

  • Модель окружающей среды: Системы слияния восприятия и датчиков сообщают карту окружающей среды вокруг транспортного средства.

  • Определение парковочного места: поведенческий слой анализирует карту для определения ближайшего доступного парковочного места.

  • Поиск глобального маршрута: Модуль маршрутизации вычисляет глобальный маршрут через дорожную сеть, полученную либо от картографической службы, либо от V2X инфраструктуры. Разложение глобального маршрута как серии дорожных связей позволяет по-разному планировать траекторию для каждого звена. Например, финальный маневр парковки требует иного профиля скорости, чем приближение к месту стоянки. В более общих условиях это становится решающим для навигации по улицам, которые включают различные ограничения скорости, количество полос движения и дорожные знаки.

Вместо того, чтобы полагаться на автомобильные датчики для построения карты окружающей среды, в этом примере используется карта, которая поступает с интеллектуальной парковки через V2X связь. Для простоты предположим, что карта представляет собой сетку с дорожными связями и местами имеющихся мест стоянки, обеспечиваемыми V2X.

HelperBehavioralPlanner класс имитирует интерфейс уровня поведенческого планирования. HelperBehavioralPlanner создается с использованием карты и глобального плана маршрута. В этом примере используется статический глобальный план маршрутов, сохраненный в таблице MATLAB, но обычно этот план определяется алгоритмом маршрутизации, предоставляемым локальной инфраструктурой парковки или службой отображения. Глобальный план трассы описывается как последовательность сегментов полосы движения, пересекаемых для достижения места парковки.

Загрузите MAT-файл, содержащий план маршрута, который хранится в таблице. Таблица содержит три переменные: StartPose, EndPose, и Attributes. StartPose и EndPose укажите начальную и конечную позы сегмента, выраженные как.$[x,y,\theta]$ 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);

Транспортное средство осуществляет навигацию по каждому сегменту пути с помощью следующих шагов:

  1. Планирование движения: Планирование возможного пути через карту среды с использованием оптимального алгоритма быстрого исследования случайного дерева (RRT *) (pathPlannerRRT).

  2. Сглаживание траектории: сглаживание траектории привязки путем подгонки к ней сплайнов с помощью smoothPathSpline.

  3. Создание траектории: преобразование сглаженной траектории в траекторию путем создания профиля скорости с помощью helperGenerateVelocityProfile.

  4. Управление транспортным средством: учитывая сглаженный исходный путь, HelperPathAnalyzer вычисляет исходную позу и скорость на основе текущей позы и скорости транспортного средства. Обеспечиваются эталонными значениями, lateralControllerStanley вычисляет угол поворота для управления курсом транспортного средства. HelperLongitudinalController вычисляет команды ускорения и замедления для поддержания требуемой скорости транспортного средства.

  5. Проверка цели: Проверьте, достигло ли транспортное средство конечной позы сегмента с помощью helperGoalChecker.

Остальная часть этого примера подробно описывает эти шаги перед их сборкой в полное решение.

Планирование движения

При наличии глобального маршрута планирование движения может использоваться для планирования пути через окружающую среду для достижения каждого промежуточного ППМ до тех пор, пока транспортное средство не достигнет конечного пункта назначения. Запланированный путь для каждого канала должен быть выполнимым и свободным от конфликтов. Осуществимый путь - это путь, который может быть реализован транспортным средством с учетом движения и динамических ограничений, наложенных на него. Система парковочной камеры включает в себя низкие скорости и низкие ускорения. Это позволяет безопасно игнорировать динамические ограничения, возникающие в результате инерционных эффектов.

Создать pathPlannerRRT объект для конфигурирования планировщика пути с использованием оптимального подхода быстрого исследования случайного дерева (RRT *). Семейство алгоритмов планирования RRT находит путь путем построения дерева связанных, свободных от столкновения поз транспортного средства. Позы соединяются с помощью рулевого управления Dubins или Reeds-Shepp, гарантируя, что сформированный путь является кинематически осуществимым.

motionPlanner = pathPlannerRRT(costmap, 'MinIterations', 1000, ...
    'ConnectionDistance', 10, 'MinTurningRadius', 20);

Планирование пути от текущей позы до первой цели с помощью plan функция. Возвращенный driving.Path объект, refPath, является возможным и свободным от столкновений опорным путем.

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)

Управление транспортными средствами и их моделирование

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

  • Регулировка угла поворота таким образом, чтобы транспортное средство следовало по исходной траектории.

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

Поскольку этот сценарий включает в себя медленные скорости, можно упростить контроллер, чтобы учесть только кинематическую модель. В этом примере боковое управление реализуется посредством lateralControllerStanley функция. Продольное управление осуществляется с помощью вспомогательной системы object™ HelperLongitudinalController, которая вычисляет команды ускорения и замедления на основе пропорционального интегрального закона.

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

$$\dot x_r = v_r*\cos(\theta) $$

$$\dot y_r = v_r*\sin(\theta) $$

$$\dot \theta = \frac{v_r}{l}*\tan(\delta) $$

$$\dot v_r = a_r $$

В вышеприведенных уравнениях$(x_r,y_r,\theta)$ представляет положение транспортного средства в мировых координатах.,, $v_r$$a_r$$l$и $\delta$представляет скорость заднего колеса, ускорение заднего колеса, колесную базу и угол поворота рулевого управления соответственно. Положение и скорость переднего колеса могут быть получены посредством:

$$ x_f = x_r + l cos(\theta)$$

$$ y_f = y_r + l sin(\theta)$$

$$ v_f = \frac{v_r} {cos(\delta)}$$

% 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);

Заключение

В этом примере показано, как:

  1. Планирование возможного пути в полуструктурированной среде, такой как стоянка, с использованием алгоритма планирования пути RRT *.

  2. Сглаживание траектории с помощью сплайнов и формирование профиля скорости вдоль сглаженной траектории.

  3. Управление транспортным средством для следования по контрольному пути с требуемой скоростью.

  4. Реализуйте различные варианты парковки с помощью различных настроек планировщика движения.

Ссылки

[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

См. также

Функции

Объекты

Связанные темы