¿Cómo adaptar los algoritmos de pathfinding al movimiento restringido?

10

Imagine un movimiento similar al de un automóvil donde las entidades no pueden girar ni un centavo. Digamos, en aras de la discusión, que cuando están a alta velocidad pueden girar 90 grados por segundo. En muchos casos, esto cambiaría la ruta óptima y, por lo tanto, la búsqueda de ruta. Incluso puede hacer que los caminos 'habituales' sean completamente imposibles de recorrer.

¿Hay algún algoritmo de orientación o algoritmo de planificación de movimiento que pueda tener esto en cuenta, o hay formas simples de adaptar los populares?

Weckar E.
fuente
¿La búsqueda de ruta también incluiría los datos de velocidad? como, ir de A a B a X km / h (o mph), ¿o sería una velocidad constante? Además, 90 grados por segundo a velocidades lentas podrían terminar siendo un giro muy cerrado, probablemente incluso físicamente imposible. (a menos que tenga las 4 ruedas girando xD)
Brian H.
@BrianH. Por eso dije 'a toda velocidad'. En circunstancias razonables habría umbrales mínimos y máximos establecidos. Pero lo ideal sería que un algoritmo busque una ruta 'ideal', que puede incluir variaciones de velocidad.
Weckar E.
Me parece una pregunta muy interesante, obtuve un +1 de mí, no puedo esperar para ver algunas respuestas ordenadas :)
Brian H.
Consideraría que esto es una especie de muro invisible. Además, la mayoría de los algoritmos de financiación de rutas tienen un "peso" para cada ruta (por ejemplo, caminar en el agua es más lento que caminar en tierra), por lo que podría agregar peso adicional a la ruta que es más difícil de conseguir. Todo esto se puede conocer solo con la velocidad y dirección del automóvil.
the_lotus

Respuestas:

10

Bienvenido al maravilloso mundo de la planificación del movimiento no holonómico . Recomiendo hacer esto usando un planificador de ruta de rejilla reticular . Otras alternativas incluyen la RRT kinodinámica y la optimización de la trayectoria . Los sistemas no holonómicos incluyen automóviles, botes, monociclos o cualquier cosa en la que el vehículo no pueda viajar en la dirección que desee. La planificación de estos sistemas es mucho más difícil que los sistemas holonómicos y hasta ~ 2000 estuvo al borde de la investigación académica. Hoy en día hay muchos algoritmos para elegir que funcionan decentemente.

ingrese la descripción de la imagen aquí

Así es como funciona.

Estado

La configuración q de su automóvil es en realidad un estado 3D que contiene la posición x, y de su automóvil y su orientación t . Los nodos en su algoritmo A * son en realidad vectores 3D.

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

Comportamiento

¿Y qué hay de los bordes?

Eso es un poco más difícil, porque su automóvil podría elegir una infinidad de formas de girar la rueda. Por lo tanto, podemos hacer que esta accesible a un planificador rejilla reticular mediante la restricción del número de acciones que el coche puede tomar para un conjunto discreto, A . En aras de la simplicidad, supongamos que el automóvil no acelera, sino que puede cambiar su velocidad instantáneamente. En nuestro caso, A puede ser el siguiente:

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

Ahora, podemos crear un conjunto discreto de acciones que el automóvil puede tomar en cualquier momento. Por ejemplo, una derecha dura mientras presiona el gas al máximo durante 0,5 segundos se vería así:

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

Poner el auto en reversa y retroceder se vería así:

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

Y su lista de acciones se vería así:

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

También necesita una forma de definir cómo una acción tomada en un nodo da como resultado un nuevo nodo. Esto se llama la dinámica hacia adelante del sistema.

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

Celdas de rejilla discretas

Ahora, para construir la cuadrícula de celosía, todo lo que tenemos que hacer es dividir los estados del automóvil en celdas de cuadrícula discretas. Esto los convierte en nodos discretos que pueden ser seguidos por A *. Esto es muy importante porque, de lo contrario, A * no tendría forma de saber si dos estados del automóvil son realmente iguales para poder compararlos. Al dividir los valores de las celdas de la cuadrícula entera, esto se vuelve trivial.

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

Ahora, podemos hacer un plan A * donde GridCells son los nodos, las Acciones son los bordes entre los nodos, y el Inicio y el Objetivo se expresan en términos de GridCells. La heurística entre dos GridCells es la distancia en x e y más la distancia angular en theta.

Siguiendo el camino

Ahora que tenemos una ruta en términos de GridCells y Actions entre ellas, podemos escribir un seguidor de ruta para el automóvil. Como las celdas de la cuadrícula son discretas, el automóvil saltaría entre las celdas. Entonces tendremos que suavizar el movimiento del automóvil a lo largo del camino. Si su juego usa un motor de física, esto se puede lograr escribiendo un controlador de dirección que intente mantener el automóvil lo más cerca posible del camino. De lo contrario, puede animar el camino utilizando curvas bezier o simplemente promediando los pocos puntos más cercanos en el camino.

mklingen
fuente
Excelente publicación (¡e incluso corta! Hago algo similar para barcos: resbaladizo :-). Otoh, hay más espacio,
Ventormenta
4

La mayoría de los algoritmos de búsqueda de ruta funcionan en un gráfico arbitrario sin restricción de geometría.

Entonces, lo que debe hacer es agregar orientación del automóvil a cada nodo explorado y restringir qué nodos están realmente conectados.

monstruo de trinquete
fuente
El problema es que el automóvil podría visitar el mismo nodo acercándose desde diferentes direcciones, lo que impone diferentes restricciones a las conexiones que se pueden atravesar desde allí.
Weckar E.
66
@WeckarE. Pero el auto no visita el mismo nodo. Visita 2 nodos que tienen la misma ubicación pero una orientación diferente
Ratchet Freak
3
@WeckarE. Trátelos como dos nodos separados. El gráfico físico y el gráfico lógico no necesitan ser exactamente iguales.
BlueRaja - Danny Pflughoeft
1

Mis pensamientos, no los he probado!

  1. Ejecute A * desde el inicio hasta el destino, devuelva la ruta.
  2. Recorra el camino, cuando detecte un giro, use un algoritmo Bezier (o uno similar) que use la velocidad actual de los buscadores para predecir los nodos que crearán un giro suave. Asegúrese de que intenta volver al nodo de ruta más cercano.
  3. Si se puede hacer el giro, genial, si no, repita con una velocidad más lenta, haciendo un giro más agudo.
  4. Una vez que se crea el camino correcto, regrese a través del camino ajustando la velocidad del buscador antes de que se realice el giro para que disminuya a la velocidad correcta antes de que comience el giro.
  5. Si no se puede hacer el turno, ejecute todo de nuevo. Solo asegúrese de que todos los nodos manejados del turno que no se pueden realizar estén en la lista cerrada, de modo que se ignoren. Y podría comenzar con el punto donde se inicia el giro para poder omitir la parte exitosa de la ruta, sin embargo, en algunos casos esto podría resultar en una ruta menos que óptima.

También debería ser capaz de hacer esto sin tener que completar primero el camino, ergo: manejar giros durante A *, que probablemente estará mucho mejor optimizado, pero también podría resultar problemático y problemático, realmente no lo sabría y desafortunadamente No tengo tiempo para probarlo yo mismo.

Pathfinding

Dennis
fuente
0

Si su agente tiene el control total del automóvil, hágalo al revés. Conecte una línea de principio a fin primero, luego descubra a qué velocidad puede navegar cada turno, similar a la respuesta de Dennis.

Sin embargo, no dibujes curvas de Bezier desde puntos fijos. Para minimizar la pérdida de velocidad, debe mover toda la línea, así que comience insertando nodos adicionales a una distancia más o menos pareja y luego muévase para minimizar la energía o estrategias similares. Para obtener más detalles, debe analizar la generación de líneas AI en juegos de carreras (preferiblemente sim o semi-sim).

Una vez que tenga el sistema de línea AI en ejecución, ejecute su búsqueda A * y para cada ruta avance al menos una esquina hacia adelante, luego calcule la línea AI que le da una estimación de tiempo. Esta sería su función de costo.

BECD9A66
fuente