Como adaptar os algoritmos de busca de caminhos ao movimento restrito?

10

Imagine um movimento parecido com um carro, onde as entidades não podem se interessar. Diga, por uma questão de discussão, que quando estiverem na velocidade certa, eles podem girar 90 graus por segundo. Em muitos casos, isso mudaria o caminho ideal e, portanto, a busca de caminhos. Pode até tornar caminhos 'habituais' inteiramente impossíveis de percorrer.

Existem algoritmos de busca de caminhos ou de planejamento de movimento que podem manter isso em mente, ou existem maneiras simples de adaptar os populares?

Weckar E.
fonte
o pathfinding também incluiria os dados de velocidade? como, ir de A a B a X km / h (ou mph), ou seria uma velocidade constante? Além disso, 90 graus por segundo em velocidades lentas podem acabar sendo uma curva muito fechada, provavelmente até fisicamente impossível. (a menos que você tem todas as 4 rodas girando xD)
Brian H.
@BrianH. Por isso eu disse 'em alta velocidade'. Em circunstâncias razoáveis, haveria limites mínimos e máximos em vigor. Mas, idealmente, eu teria que um algoritmo procurar um caminho 'ideal', que pode incluir variações de velocidade.
Weckar E. 9/11
Acho isso uma pergunta muito interessante, tem um +1 de mim, não posso esperar para ver algumas respostas puro :)
Brian H.
Eu consideraria isso algum tipo de parede invisível. Além disso, a maioria dos algoritmos de financiamento de caminhos possui um "peso" para cada caminho (por exemplo, caminhar na água é mais lento que caminhar na terra), portanto, você pode adicionar um peso adicional ao caminho mais difícil de conseguir. Tudo isso pode ser conhecido apenas com a velocidade e a direção do carro.
the_lotus

Respostas:

10

Bem-vindo ao maravilhoso mundo do planejamento de movimento não-holonômico . Eu recomendo fazer isso usando um planejador de caminho de grade de malha . Outras alternativas incluem o TRS cinodinâmico e a otimização de trajetória . Os sistemas não-holonômicos incluem carros, barcos, monociclos ou realmente qualquer coisa em que o veículo não possa viajar na direção que desejar. O planejamento desses sistemas é muito mais difícil do que os sistemas holonômicos e até 2000 estava à beira da pesquisa acadêmica. Atualmente, existem muitos algoritmos para escolher quais funcionam decentemente.

insira a descrição da imagem aqui

Aqui está como isso funciona.

Estado

A configuração do seu carro q é realmente um estado 3D contendo a posição x, y do carro e sua orientação t . Os nós no seu algoritmo A * são na verdade vetores 3D.

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

Ações

E as arestas?

Isso é um pouco mais difícil, porque seu carro pode realmente escolher um número infinito de maneiras de girar o volante. Então, nós podemos fazer isso acessível a um planejador grade rede, restringindo o número de acções do carro pode tomar para um conjunto discreto, A . Por uma questão de simplicidade, vamos assumir que o carro não acelera, mas pode mudar sua velocidade instantaneamente. No nosso caso, A pode ser o seguinte:

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

Agora, podemos criar um conjunto discreto de ações que o carro pode executar a qualquer momento. Por exemplo, um disco rígido enquanto pressionava o gás por 0,5 segundos ficaria assim:

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

Colocar o carro em marcha à ré e fazer o backup seria assim:

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

E sua lista de ações seria assim:

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

Você também precisa definir como uma ação executada em um nó resulta em um novo nó. Isso é chamado de dinâmica direta do 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);
}

Células de Grade Discreta

Agora, para construir a grade de treliça, tudo o que precisamos fazer é misturar os estados do carro em células de grade discretas. Isso os transforma em nós discretos que podem ser seguidos por A *. Isso é super importante porque, caso contrário, A * não teria como saber se dois estados de carros são realmente os mesmos para compará-los. Ao fazer hash nos valores das células da grade inteira, isso se torna 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; 
}

Agora, podemos fazer um plano A * em que GridCells são os nós, Actions são as arestas entre os nós e Start e Goal são expressos em termos de GridCells. A Heurística entre duas GridCells é a distância em xey mais a distância angular em theta.

Seguindo o caminho

Agora que temos um caminho em termos de GridCells e Actions entre eles, podemos escrever um seguidor de caminho para o carro. Como as células da grade são discretas, o carro pula entre as células. Então teremos que suavizar o movimento do carro ao longo do caminho. Se o seu jogo estiver usando um mecanismo de física, isso pode ser conseguido escrevendo um controlador de direção que tenta manter o carro o mais próximo possível do caminho. Caso contrário, você pode animar o caminho usando curvas de bezier ou simplesmente calculando a média dos poucos pontos mais próximos no caminho.

mklingen
fonte
Excelente post (e até curto! Faço algo parecido com barcos - escorregadio :-). Otoh, há mais espaço, #
Stormwind
4

A maioria dos algoritmos de localização de caminho funciona em um gráfico arbitrário sem restrição de geometria.

Portanto, o que você precisa fazer é adicionar a orientação do carro a cada nó explorado e restringir quais nós estão realmente conectados.

catraca arrepiante
fonte
O problema é que o carro pode visitar o mesmo nó se aproximando de direções diferentes, o que impõe restrições diferentes nas conexões que podem ser percorridas a partir daí.
Weckar E. 9/11
6
@WeckarE. Mas o carro não visita o mesmo nó. Visita 2 nós que acontecem ter a mesma localização, mas diferente orientação
aberração catraca
3
@WeckarE. Trate esses como dois nós separados. O gráfico físico e o gráfico lógico não precisam ser exatamente iguais.
precisa saber é o seguinte
1

Meus pensamentos, não os testaram!

  1. Execute A * do início ao destino, retorne o caminho.
  2. Faça um loop pelo caminho, quando detectar uma curva, use um algoritmo de bezier (ou qualquer outro semelhante) que usa a velocidade atual dos buscadores para prever os nós que criarão uma curva suave. Verifique se ele tenta voltar ao nó do caminho mais próximo.
  3. Se for possível fazer a curva, ótimo, se não, repita com velocidade mais lenta, fazendo uma curva mais acentuada.
  4. Depois que o caminho correto for criado, volte pelo caminho ajustando a velocidade do buscador antes que a curva seja feita, para que ela diminua para a velocidade correta antes de iniciar a curva.
  5. Se não for possível fazer o turno, execute a coisa toda novamente. Apenas garanta que todos os nós manipulados da curva que não podem ser feitos estejam na lista fechada, para que sejam ignorados. E você pode começar com o ponto em que a curva é iniciada para que você possa pular a parte bem-sucedida do caminho, no entanto, em alguns casos, isso pode resultar em um caminho abaixo do ideal.

Você também deve ser capaz de fazer isso sem ter que concluir o caminho primeiro, portanto: manipular curvas durante A *, que provavelmente será muito melhor otimizado, mas também pode ser problemático e com falhas, eu realmente não saberia e infelizmente eu não tenho tempo para testá-lo eu mesmo.

Encontrando o caminho

Dennis
fonte
0

Se o seu agente tiver controle total do carro, faça o contrário. Conecte uma linha do início ao fim primeiro e, em seguida, descubra em que velocidade você pode navegar a cada turno, semelhante à resposta de Dennis.

Não desenhe curvas de Bezier a partir de pontos fixos. Para minimizar a perda de velocidade, você precisa mover toda a linha, comece inserindo nós extras a uma distância mais ou menos uniforme e depois mova-se para minimizar a energia ou estratégias semelhantes. Para detalhes, você precisa analisar a geração de linha de IA em (de preferência sim ou semi-sim) jogos de corrida.

Depois de ter o sistema de linha de IA em execução, execute sua pesquisa A * e, para cada caminho, vá pelo menos um canto à frente, e calcule a linha de AI que fornece uma estimativa de tempo. Essa seria sua função de custo.

BECD9A66
fonte