Rastreamento de alvo: quando acelerar e desacelerar uma torre rotativa?

24

Digamos que eu tenha uma circular móvel targetdefinida como:

Vector2 position;
Vector2 velocity;
float radius;

E uma rotação turret(montada em algum veículo em movimento) 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

(Ou algo nesse sentido. Observe que a posição e a velocidade de ambos são controladas em outros lugares - suponha que a velocidade seja constante e a posição mude com base na velocidade.)

Estou tentando escrever duas funções relacionadas à AI para determinar, em um determinado quadro:

  • Qual aceleração angular (e em qual direção) aplicar ao ângulo da torre para manter a torre apontando para o alvo?

  • Se o alvo estiver à vista no momento, ele (qualquer parte dentro do raio) pode ser mantido à vista por xsegundos, onde xfica uma fração de segundo? (Como alternativa: existe outra estratégia para garantir que o alvo esteja realmente "travado" e não simplesmente voando pelos locais?)

E eu poderia usar alguma ajuda ...

Andrew Russell
fonte
11
Você pode ter valores diferentes para aceleração e desaceleração rotacional - no mundo real, um provavelmente é um motor e o outro um freio.
e100

Respostas:

19

Primeiro, você precisa determinar a diferença de ângulo entre a direção da torre e a direção do alvo.

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;

Depois de ter essas quantidades, você pode configurar uma expressão de segundo grau para o ângulo da torre. Você precisa calcular isso em cada atualização para garantir sempre o uso dos dados mais recentes de posições e velocidades.

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

Aqui, o primeiro termo (grau zero) na expressão de aceleração fará com que a torre comece a girar em direção ao alvo. No entanto, ele não para no tempo, mas oscila de um lado para o outro. Para fazê-lo parar, precisamos do amortecimento do segundo termo (primeiro grau), que faz com que uma alta velocidade de rotação seja oposta a uma alta aceleração.

Agora, as constantes positivas (não necessariamente constantes do programa) precisam ser determinadas e equilibradas para que o sistema se comporte bem. C0é o principal controle da velocidade do sistema. Um valor alto para C0dará uma velocidade de rotação rápida e um valor baixo dará uma velocidade de rotação baixa. O valor real depende de muitos fatores; portanto, você deve usar tentativa e erro aqui. C1controla a magnitude do amortecimento. O discriminante da equação quadrática nos diz que se C1*C1 - 4*C0 >= 0temos um sistema não-oscilante.

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

Você provavelmente deve escolher C1um pouco maior que isso por razões numéricas, mas não muito grande, pois pode ficar muito úmido e lento para responder. Novamente, você precisa ajustar.

Também é importante observar que esse código calcula apenas a aceleração angular. O ângulo e a velocidade angular precisam ser atualizados a partir disso em outro lugar, usando algum tipo de integrador. Da pergunta, presumo que isso tenha sido coberto.

Finalmente, há algo a dizer sobre o atraso, porque a torre provavelmente sempre estará para trás ao rastrear um alvo rápido. Uma maneira simples de resolver isso é adicionar uma previsão linear à posição do alvo, ou seja, sempre apontar um pouco à frente na direção para frente do alvo.

// 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;
/// ...

Quanto a manter a torre apontada dentro do raio do alvo por algum tempo, pode ser um requisito difícil de impor diretamente a esse tipo de sistema. Você pode ter certeza de que este controlador se esforçará para manter a torre apontada para o alvo (ou melhor, para a posição prevista) o tempo todo. Se o resultado acaba por não ser satisfatório você tem que modificar os parâmetros predictionTime, C0e C1(dentro de limites estáveis).

Staffan E
fonte
Não estou qualificado para dizer se isso está certo ou não, mas parece algo inteligente! Eu resolvi esses tipos de problemas no passado, prevendo antecipadamente o efeito da aceleração para descobrir quando acelerar e quando "aplicar as quebras". Isso significa que eu tenho feito errado?
Iain
O atan2 dificulta a adaptação desse método a um sistema preditivo, uma vez que os parâmetros xey para atan2 se tornam dependentes de t.
Skizz
Esta é exatamente a solução que eu estava sugerindo na minha resposta abaixo. Excelentes detalhes e apresentação!
Drxzcl 30/07/10
@ Iain: Não, não há certo e errado aqui. Embora eu ache que seu método tenha dois estados distintos: acelerar / desacelerar, esse método é inspirado por um regulador da teoria de controle, escalando a aceleração para obter uma resposta rápida e reduzindo o overshoot e as oscilações.
precisa
11
Como nos outros comentários, isso funcionará para um alvo fixo, mas provavelmente será inaceitável para qualquer alvo em movimento. Os termos C0 e C1 são material tradicional de mola amortecida, onde C0 representa a força da mola (geralmente chamada k) e C1 é o fator de amortecimento (geralmente chamado de 'B' ou 'c'). Portanto, sim, você pode minimizar a oscilação acionando o amortecimento, mas o problema é que isso não tenta antecipar onde o alvo estará , portanto está fadado a atrasar o objetivo desejado.
traço-tom-bang
3

O que você tem aqui é um problema de controle básico . A torre é o sistema, a aceleração é o controle e o sensor mede a posição / velocidade. Existem muitas maneiras de resolver esses problemas, pois é um problema muito bem estudado em engenharia.

A chave está finalizando com um sistema estável, ou seja, um sistema que não gera oscilações. Isso geralmente é feito adicionando amortecimento. A página da Wikipedia deve começar.

drxzcl
fonte
2

Primeiro, calcule o vetor da torre para o alvo. Em seguida, compare isso com o vetor atual da torre. Em seguida, use a diferença entre os dois para calcular a aceleração angular e a velocidade angular necessárias para fazer com que a torre gire para apontar na direção certa dentro de um determinado período de tempo.

OK, isso parecia simples. No entanto, você deve realmente tentar antecipar a posição do alvo, já que o alvo se moverá quando você girar a torre. Para fazer isso:-

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

onde P é a posição e V é a velocidade e o índice é d para o destino (alvo) es para a fonte (torre), que fornece um vetor de direção: -

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

onde D é um vetor de direção e Dsd 'é a direção necessária no tempo t. Agora, calcule a direção da torre com base na posição atual e velocidade e aceleração máximas por um determinado tempo t: -

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

Ds e Ds 'são as direções da fonte e Rs é a velocidade de rotação. Com tudo isso, você deseja encontrar t para quando Dsd '== Ds' e, portanto, Rs, a velocidade de rotação necessária. Não esqueça que todos os P's, D's e V's possuem componentes x e y.

Não levei em consideração a aceleração aqui - isso adiciona muito mais à complexidade. Depois de obter Rs e t, você provavelmente poderá aproximar um Rs parabólico (ou seja, acelerar e desacelerar) para obter o mesmo resultado.

Skizz
fonte
Parece uma boa resposta para o cálculo de interceptação, mas infelizmente existe uma grande lacuna entre as pessoas que podem ler esse tipo de notação matemática e transformá-lo em código de programa, e a maioria das pessoas que cria jogos que ainda não sabem a resposta para a questão. Em outras palavras, acho que os desenvolvedores de jogos que podem ler essa notação matemática provavelmente já podem descobrir como programar a solução de disparo. Isso me ajudaria a entender suas fórmulas se você explicasse o que seus termos significavam.
Dronz 20/03
2

O que você provavelmente está procurando aqui é um controlador PID , semelhante à resposta aceita nesta pergunta do SO

Inicialmente, eu respondi a essa pergunta "fazendo o meu próprio", mas essa resposta é significativamente mais completa e elegante.

nicolaskruchten
fonte
0

A primeira coisa a fazer é calcular o ângulo entre o turrent e o objeto rastreado.
O próximo passo é verificar se, usando a velocidade atual do torrent e aplicando a aceleração máxima para trás (interrompendo o torrent), o torrent será interrompido antes ou depois do objeto rastreado.
Se a resposta for que o torrent irá parar antes do objeto rastreado, aplique a aceleração máxima para frente (velocidade crescente).
Se a resposta for que o torrent irá parar após o objeto rastreado, aplique a aceleração máxima para trás (interrompendo o torrent).
Dessa forma, o torrent sempre chegará mais rápido e parará no ponto certo (ou uma fração depois).

Dani
fonte