Seguimiento de objetivos: ¿cuándo acelerar y desacelerar una torreta giratoria?

24

Digamos que tengo una circular móvil targetdefinida como:

Vector2 position;
Vector2 velocity;
float radius;

Y una rotación turret(montada en un vehículo en movimiento de algún tipo) definida como:

Vector2 position;
Vector2 velocity;
float angle; // radians
float angularVelocity; // radians per second
const float maxAngularVelocity; // radians per second
const float maxAngularAcceleration; // radians per second per second

(O algo por el estilo. Tenga en cuenta que la posición y la velocidad de ambas están controladas en otra parte: suponga que la velocidad es constante y que la posición cambia según la velocidad).

Estoy tratando de escribir dos funciones de IA relacionadas para determinar, en un marco dado:

  • ¿Qué aceleración angular (y en qué dirección) aplicar al ángulo de la torreta para mantener la torre apuntando al objetivo?

  • Si el objetivo está actualmente a la vista, ¿se puede mantener a la vista (cualquier parte dentro de su radio) durante xsegundos, ¿dónde xestá una fracción de segundo? (Alternativamente: ¿existe otra estrategia para garantizar que el objetivo esté realmente "bloqueado" y no simplemente volando a través de las vistas?)

Y podría usar algo de ayuda ...

Andrew Russell
fuente
1
Es posible que tenga valores diferentes para la aceleración y desaceleración rotacional: en el mundo real, uno es probablemente un motor y el otro un freno.
e100

Respuestas:

19

Primero debe determinar la diferencia de ángulo entre la dirección de la torreta y la dirección del objetivo.

Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;

// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;

Una vez que tenga estas cantidades, puede configurar una expresión de segundo grado para el ángulo de la torreta. Debe calcular esto en cada actualización para asegurarse de utilizar siempre los últimos datos de posiciones y velocidades.

// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;

Aquí, el primer término (grado cero) en la expresión de aceleración hará que la torreta comience a girar hacia el objetivo. Sin embargo, no se detendrá a tiempo sino que oscilará de un lado a otro. Para detenerlo, necesitamos el segundo término de amortiguación (primer grado) que hace que una alta velocidad de giro se oponga por una alta aceleración.

Ahora las constantes positivas (no necesariamente las constantes del programa) deben determinarse y equilibrarse para que el sistema se comporte bien. C0es el mayor control para la velocidad del sistema. Un valor alto para C0dará una velocidad de giro rápida y un valor bajo dará una velocidad de giro baja. El valor real depende de muchos factores, por lo que debe usar prueba y error aquí. C1controla la magnitud de la amortiguación. El discriminante de la ecuación cuadrática nos dice que si C1*C1 - 4*C0 >= 0tenemos un sistema no oscilante.

// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.

Probablemente debería elegir C1un poco más grande que esto por razones numéricas, pero no demasiado grande, ya que en su lugar se puede amortiguar demasiado y responder lentamente. Nuevamente, necesitas modificar.

También es importante tener en cuenta que este código solo calcula la aceleración angular. El ángulo y la velocidad angular deben actualizarse a partir de esto en otro lugar, utilizando un integrador de algún tipo. De la pregunta asumo que esto ha sido cubierto.

Finalmente, hay algo que decir sobre el retraso, porque la torreta probablemente siempre estará detrás cuando se rastrea un objetivo rápido. Una manera simple de abordar esto es agregar una predicción lineal a la posición del objetivo, es decir, siempre apunte un poco hacia adelante en la dirección hacia adelante del objetivo.

// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...

En cuanto a mantener la torreta apuntada dentro del radio del objetivo durante algún tiempo, este puede ser un requisito difícil de imponer directamente en este tipo de sistema. Puede estar seguro de que este controlador se esforzará por mantener la torreta apuntada al objetivo (o más bien la posición predicha) en todo momento. Si el resultado resulta no ser satisfactoria tiene que modificar los parámetros predictionTime, C0y C1(dentro de ciertos límites estables).

Staffan E
fuente
No estoy calificado para decir si esto es correcto o no, ¡pero parece algo inteligente! He resuelto este tipo de problemas en el pasado al predecir el efecto de la aceleración para determinar cuándo acelerar y cuándo "aplicar los descansos". ¿Eso significa que lo he estado haciendo mal?
Iain
El atan2 hace que este método sea difícil de adaptar a un sistema predictivo ya que los parámetros x e y de atan2 se vuelven dependientes de t.
Skizz
Esta es exactamente la solución que estaba insinuando en mi respuesta a continuación. Excelente detalle y presentación!
drxzcl
@Iain: No, no hay bien ni mal aquí. Si bien supongo que su método tendría dos estados discretos: acelerar / desacelerar, este método está inspirado en un regulador de la teoría de control, que escala la aceleración para dar una respuesta rápida mientras reduce el sobreimpulso y las oscilaciones.
Staffan E
1
Al igual que con los otros comentarios, esto funcionará para un objetivo estacionario, pero probablemente sea inaceptable para cualquier objetivo en movimiento. Los términos C0 y C1 son elementos tradicionales de resorte amortiguado, donde C0 representa la resistencia del resorte (generalmente llamado k) y C1 es el factor de amortiguamiento (generalmente llamado 'B' o 'c'). Entonces, sí, puede minimizar la oscilación aumentando la amortiguación, pero el problema es que esto no intenta anticipar dónde estará el objetivo , por lo que está condenado a retrasar el objetivo deseado.
dash-tom-bang
3

Lo que tienes aquí es un problema de control básico . La torreta es el sistema, la aceleración es el control y el sensor mide la posición / velocidad. Hay muchas formas de abordar estos problemas, ya que es un problema muy bien estudiado en ingeniería.

La clave está terminando con un sistema estable, es decir, un sistema que no genera oscilaciones. Esto generalmente se hace agregando amortiguación. La página de wikipedia debería ayudarlo a comenzar.

drxzcl
fuente
2

En primer lugar, calcule el vector desde la torreta hasta el objetivo. Luego compare esto con el vector actual de la torreta. Luego use la diferencia entre los dos para calcular la aceleración angular y la velocidad angular requeridas para hacer que la torreta gire para apuntar en la dirección correcta dentro de un tiempo determinado.

OK, eso parecía simple. Sin embargo, realmente deberías tratar de anticipar la posición del objetivo ya que el objetivo se moverá para cuando hayas girado la torreta. Para hacer esto:-

Pd' = Pd + t.Vd
Ps' = Ps + t.Vs

donde P es la posición y V es la velocidad y el subíndice es d para el destino (objetivo) ys para la fuente (torreta), lo que da un vector de dirección: -

Dsd' = Pd' - Ps' = Pd + t.Vd - (Ps + t.Vs) = Pd - Ps + (Vd - Vs).t

donde D es un vector de dirección y Dsd 'es la dirección requerida en el tiempo t. Ahora, calcule la dirección de la torreta basándose en la posición actual y la velocidad y aceleración máximas para un tiempo dado t: -

Ds' = t.Ds.Rs -> this is a vector rotation

Ds y Ds 'son las direcciones de origen y Rs es la velocidad de rotación. Con todo eso, desea encontrar t para cuando Dsd '== Ds' y, por lo tanto, Rs, la velocidad de rotación requerida. No olvide que todas las P, D y V tienen componentes x e y.

No he tenido en cuenta la aceleración aquí, eso agrega mucho más a la complejidad. Una vez que tenga Rs y t, probablemente podría aproximarse a un Rs parabólico (es decir, acelerar y desacelerar) para obtener el mismo resultado.

Skizz
fuente
Esto parece una buena respuesta para el cálculo de la intercepción, pero desafortunadamente hay una gran brecha entre las personas que pueden leer ese tipo de notación matemática y convertirlo en código de programa, y ​​la mayoría de las personas que hacen juegos que aún no saben la respuesta. la pregunta. En otras palabras, creo que los desarrolladores de juegos que pueden leer esa notación matemática, probablemente ya puedan descubrir cómo programar la solución de disparo. Me ayudaría a entender sus fórmulas si explicara lo que significan sus términos.
Dronz
2

Lo que probablemente esté buscando aquí es un controlador PID , similar a la respuesta aceptada en esta pregunta SO

Inicialmente había respondido esa pregunta "rodando la mía" pero esta respuesta es significativamente más completa y elegante.

nicolaskruchten
fuente
0

Lo primero que debe hacer es calcular el ángulo entre la torre y el objeto rastreado.
Lo siguiente es verificar si al usar la velocidad actual del torrente y aplicar la aceleración máxima hacia atrás (detener el torrent), el torrent se detendrá antes o después del objeto rastreado.
Si la respuesta es que el torrente se detendrá antes que el objeto rastreado, aplique la aceleración máxima hacia adelante (aumentando la velocidad).
Si la respuesta es que el torrente se detendrá después del objeto rastreado, aplique la aceleración máxima hacia atrás (deteniendo el torrente).
De esta manera, el torrent siempre llegará más rápido y se detendrá en el punto correcto (o una fracción después).

Dani
fuente