Автоматизированный камердинер парковки

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

Обзор

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

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

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

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

  • IMU и энкодеры колеса для точного расчета

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

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

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

Модель среды

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

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

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

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

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

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

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

mapLayers = loadParkingLotMapLayers;
plotMapLayers(mapLayers)

Для простоты, объединение эти три слоя в один costmap.

costmap = combineMapLayers(mapLayers);

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

Объединенный costmap vehicleCostmap объект, который представляет среду транспортного средства как 2D сетку заполнения. Каждая сетка в ячейке имеет значения между 0 и 1, представляя стоимость навигации через ячейку. Препятствия имеют более высокую стоимость, в то время как свободное пространство имеет более низкую цену. Ячейка рассматривается препятствием, если его стоимость выше, чем OccupiedThreshold свойство, и свободный, если его стоимость ниже, чем FreeThreshold свойство.

costmap покрывает целую 75m-by-50m область парковки, разделенную на 0.5m-by-0.5m квадратные ячейки.

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. Для получения дополнительной информации смотрите Системы координат в Automated Driving Toolbox.

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

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

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

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

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

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

  • Нахождение глобального маршрута: модуль маршрутизации вычисляет глобальный маршрут через дорожную сеть, полученную или от сервиса отображения или от инфраструктуры 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.

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

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

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

Создайте 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);

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

refPath.PathSegments
ans = 

  1×6 DubinsPathSegment array with properties:

    StartPose
    GoalPose
    MinTurningRadius
    MotionLengths
    MotionTypes
    Length

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

Получите положения перехода и направления от запланированного пути.

[transitionPoses, directions] = interpolate(refPath);

% Visualize the planned path.
plot(motionPlanner)

В дополнение к запланированному ссылочному пути заметьте красные области на графике. Эти области представляют области costmap, где источник транспортного средства (центр задней оси) не должен пересекаться во избежание удара никаких препятствий. 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')

Проверка столкновения выполняется путем расширения препятствий в costmap радиусом инфляции и проверки ли центр круга, показанного выше лжи на расширенной ячейке сетки. Итоговый маневр парковки требует более точного, менее консервативного проверяющего столкновение механизма. Это обычно решается путем представления формы транспортного средства с помощью (приблизительно 3-5) перекрывающиеся круги вместо одного круга.

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

ccConfig.NumCircles = 4;

figure
plot(ccConfig)
title('New Collision Checker')

Обновите costmap, чтобы использовать это средство проверки столкновения.

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

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

% 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] Buehler, Мартин, Карл Иэгнемма и Сэнджив Сингх. DARPA Городская проблема: Автономные Транспортные средства в Городском движении (1-й редактор). Springer Publishing Company, Incorporated, 2009.

[2] Lepetic, Марко, Грегор Клэнкэр, Игорь Скрянк, Драго Матко, Bostjan Potocnik, "Время Оптимальное Планирование пути, Рассматривая Ускоряющие Пределы". Робототехника и Автономные системы. Объем 45, Выпуски 3-4, 2003, стр 199-210.

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

среда Загрузки loadParkingLotMapLayers сопоставляет слои для парковки

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

struct Графика 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

configurePlanner Конфигурируют планировщика пути с заданными настройками

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

Отображение plotParkingManeuver сгенерированный маневр парковки на costmap.

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

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

Функции

Объекты

Похожие темы