Як адаптувати алгоритми накладання маршрутів до обмеженого руху?


10

Уявіть, як автомобільний рух, коли суб'єкти не можуть ввімкнути ні копійки. Скажіть заради обговорення, що при швидкості вони можуть повертатися на 90 градусів за секунду. Це в багатьох випадках змінило б оптимальну трасу, а отже, і орієнтування. Це навіть може зробити «звичайні» шляхи абсолютно неможливими для проходження.

Чи є якісь алгоритми наведення маршрутів або алгоритми планування руху, які можуть пам’ятати про це, чи є прості способи адаптації популярних?


Чи буде також включення даних про швидкість включати дані про швидкість? наприклад, їхати від А до В зі швидкістю X км / год (або миль / год), чи це була б постійна швидкість? Крім того, 90 градусів за секунду при повільній швидкості може закінчитися дуже закритим поворотом, можливо, навіть фізично неможливим. (якщо у вас немає всіх 4 коліс, що обертаються xD)
Брайан Х.

@BrianH. Тому я сказав «на швидкість». За розумних обставин існували б мінімальні та максимальні пороги. Але в ідеалі я б алгоритм шукав "ідеальний" шлях, який може включати зміни швидкості.
Weckar E.

Я вважаю це дуже цікавим питанням, отримав +1 від мене, не можу чекати, щоб побачити кілька акуратних відповідей :)
Брайан Х.


Я вважав би це якоюсь невидимою стіною. Крім того, більшість алгоритмів фінансування шляхів мають "вагу" для кожного шляху (наприклад, ходьба у воді відбувається повільніше, ніж ходіння по суші), щоб ви могли додати додаткову вагу до важче пройти шлях. Це все можна знати лише за швидкістю та напрямком автомобіля.
the_lotus

Відповіді:


10

Ласкаво просимо у чудовий світ нехолономічного планування руху. Я рекомендую зробити це за допомогою гратичного планувальника сітки . Інші альтернативи включають кінодинамічну RRT та оптимізацію траєкторії . Неголономічні системи включають автомобілі, човни, одноколісні велосипеди, і справді будь-що там, де транспортний засіб не може подорожувати в будь-якому напрямку, якого він хоче. Планування цих систем набагато складніше, ніж голономічні системи і до ~ 2000 року опинилося на межі академічних досліджень. Сьогодні існує маса алгоритмів, з яких можна вибрати пристойно.

введіть тут опис зображення

Ось як це працює.

Держава

Конфігурація вашого автомобіля q - це фактично тривимірний стан, що містить положення x, y автомобіля та його орієнтацію t . Вузли в алгоритмі A * - це фактично 3D-вектори.

class Node
{
    // The position and orientation of the car.
    float x, y, theta;
}

Дії

Отже, що з ребрами?

Це трохи складніше, адже ваш автомобіль насправді міг вибрати нескінченну кількість способів повернути колесо. Таким чином, ми можемо зробити це доступне для решітки сітки планувальника, обмежуючи кількість дій , автомобіль може прийняти для дискретного безлічі, A . Для простоти припустимо, що автомобіль не розганяється, а може змінити швидкість миттєво. У нашому випадку A може бути таким:

class Action
{
    // The direction of the steering wheel.
    float wheelDirection;

    // The speed to go at in m/s.
    float speed;

    // The time that it takes to complete an action in seconds.
    float dt;
}

Тепер ми можемо створити дискретний набір дій, які може здійснити автомобіль у будь-який час. Наприклад, жорсткий правий при натисканні на газ протягом 0,5 секунд виглядатиме так:

Action turnRight;
turnRight.speed = 1;
turnRight.wheelDirection = 1;
turnRight.dt = 0.5;

Повернення автомобіля в зворотний бік і резервне копіювання виглядатиме так:

Action reverse;
reverse.speed = -1;
reverse.wheelDirection = 0;
reverse.dt = 0.5;

І ваш список дій буде виглядати приблизно так:

List<Action> actions = { turnRight, turnLeft, goStraight, reverse ...}

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

// These forward dynamics are for a dubin's car that can change its
// course instantaneously.
Node forwardIntegrate(Node start, Action action) 
{
    // the speed of the car in theta, x and y.
    float thetaDot = action.wheelDirection * TURNING_RADIUS;

    // the discrete timestep in seconds that we integrate at.
    float timestep = 0.001;

    float x = start.x;
    float y = start.y;
    float theta = start.theta;

    // Discrete Euler integration over the length of the action.
    for (float t = 0; t < action.dt; t += timestep)
    {
       theta += timestep * thetaDot;
       float xDot = action.speed * cos(theta);
       float yDot = action.speed * sin(theta);
       x += timestep * xDot;
       y += timestep * yDot;
    }

    return Node(x, y, theta);
}

Дискретні клітинки сітки

Тепер, щоб побудувати решітчасту сітку, все, що нам потрібно зробити, - це перекосити стани автомобіля в дискретні осередки сітки. Це перетворює їх у дискретні вузли, за якими може слідувати A *. Це надзвичайно важливо, оскільки в іншому випадку A * не зможе знати, чи справді два автомобілі стають однаковими для того, щоб порівняти їх. Перемішуючи цілі значення значень комірок сітки, це стає тривіальним.

GridCell hashNode(Node node)
{
    GridCell cell;
    cell.x = round(node.x / X_RESOLUTION);
    cell.y = round(node.y / Y_RESOLUTION);
    cell.theta = round(node.theta / THETA_RESOLUTION);
    return cell; 
}

Тепер ми можемо скласти план A *, де GridCells - це вузли, Дії - це краї між вузлами, а Пуск і Мета виражаються в термінах GridCells. Евристичний між двома GridCells - це відстань у x та y плюс кутове відстань у теті.

Слідом за Шляхом

Тепер, коли у нас є шлях з точки зору GridCells та дій між ними, ми можемо написати послідовник шляху для автомобіля. Оскільки осередки сітки дискретні, автомобіль стрибне між клітинами. Тож нам доведеться згладити рух машини по стежці. Якщо у вашій грі використовується фізичний двигун, це можна досягти, написавши рульовий контролер, який намагається тримати машину якомога ближче до шляху. В іншому випадку ви можете анімувати шлях за допомогою кривих Безьє або просто шляхом усереднення кількох найближчих точок шляху.


Відмінний пост (і навіть короткий! Я роблю щось подібне для човнів - слизьке :-). Ото, місця більше,
Stormwind

4

Більшість алгоритмів пошуку шляху працюють на довільному графіку без обмеження геометрії.

Тож, що вам потрібно зробити, це додати орієнтацію автомобіля на кожен досліджений вузол та обмежити, які вузли насправді підключені.


Проблема полягає в тому, що автомобіль міг відвідувати той самий вузол, що наближався з різних напрямків, що ставить різні обмеження на з'єднання, які можна проїхати звідти.
Векар Е.

6
@WeckarE. Але машина не відвідує той самий вузол. Він відвідує 2 вузли, які, мабуть, мають одне і те ж місце розташування, але різної орієнтації
щурячий вирод

3
@WeckarE. Трактуйте їх як два окремих вузли. Фізичний та логічний графік не повинні бути абсолютно однаковими.
BlueRaja - Danny Pflughoeft

1

Мої думки, не перевіряв їх!

  1. Виконати A * від початку до пункту призначення, повернути шлях.
  2. Проведіть цикл через шлях, коли ви виявите поворот, використовуйте алгоритм Безьє (або будь-який подібний), який використовує поточну швидкість шукачів для прогнозування вузлів, які створять плавний поворот. Переконайтеся, що він намагається повернутися до найближчого вузла шляху.
  3. Якщо поворот можна зробити, чудово, якщо ні, повторіть з меншою швидкістю, роблячи більш різкий поворот.
  4. Після того, як буде створено правильний шлях, поверніться по шляху, регулюючи швидкість шукача, перш ніж здійсниться поворот, щоб він сповільнився до потрібної швидкості, перш ніж ініціювати поворот.
  5. Якщо поворот взагалі неможливо зробити, запустіть всю справу ще раз. Просто переконайтеся, що всі оброблені вузли повороту, які неможливо зробити, є у закритому списку, щоб вони ігнорувалися. І ви можете почати з точки, коли починається поворот, щоб ви могли пропустити успішну частину шляху, однак, у деяких випадках це може призвести до менш оптимального шляху.

Ви також повинні бути в змозі зробити це, не спершу завершуючи шлях, ерго: обробка поворотів під час A *, що, ймовірно, буде набагато краще оптимізовано, але це також може виявитись проблематичним і глюкітним, я дійсно не знаю і, на жаль, я у вас немає часу, щоб перевірити це сам.

Шлях


0

Якщо ваш агент повністю контролює машину, зробіть це навпаки. Спочатку з'єднайте лінію від початку до кінця, а потім визначте, з якою швидкістю ви можете орієнтуватися на кожному повороті, подібно до відповіді Денніса.

Не малюйте кривих Безьє з фіксованих точок. Щоб мінімізувати втрати швидкості, вам потрібно перемістити всю лінію навколо, тому почніть, вставляючи зайві вузли на більш-менш рівномірній відстані, а потім перемістіться до мінімізації енергії або подібних стратегій. Для детальної інформації вам потрібно вивчити покоління AI в гоночних іграх (бажано сім або напівсим).

Після запуску системи ліній AI запустіть пошук A * і для кожного шляху пройдіть хоча б один кут вперед, а потім обчисліть рядок AI, який дає оцінку часу. Це було б вашою функцією витрат.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.