Planejamento de Tragetória » Histórico » Versão 1
Danielly Satyro, 29/05/2025 12:28 h
| 1 | 1 | Danielly Satyro | # Planejamento de Trajetória |
|---|---|---|---|
| 2 | |||
| 3 | Nos utilizamos do algoritmo RRT (Rapidly-Exploring Random Tree) para calcular nossa trajetória. Ele busca uma trajetória a partir de um estado inicial até o objetivo expandindo uma árvore de busca. |
||
| 4 | Para isso necessitamos de 3 funções básicas: |
||
| 5 | |||
| 6 | * Extend(env:enviroment,current:state,target:state,Step:real):state |
||
| 7 | |||
| 8 | Essa função dado um estado atual extende dando um passo em direção ao objetivo, ou em uma direção aleatória. Caso uma colisão ocorra ela retorna um estado vazio (EmptyState). |
||
| 9 | Pseudo código: |
||
| 10 | |||
| 11 | ```c |
||
| 12 | r = (Target - Current)/||Targe-Current|| ; //vetor unitário na direção do target |
||
| 13 | NewState = r*Step + Current ; |
||
| 14 | if (Colision(NewState)) NewState = EmptyState; //confere se o novo estado vai colidir com algum obstáculo. |
||
| 15 | return NewState; |
||
| 16 | ``` |
||
| 17 | |||
| 18 | * Distance(current:state,target:state):real |
||
| 19 | |||
| 20 | Calcula a distância do estado atual ao objetivo, utilizamos a euclidiana nessa implementação. |
||
| 21 | |||
| 22 | * RandomState():state |
||
| 23 | |||
| 24 | Retorna um novo estado uniformemente distribuído no ambiente. |
||
| 25 | |||
| 26 | ```c |
||
| 27 | float random_x; |
||
| 28 | float random_y; |
||
| 29 | random_x = fiel_length*(rand()-0.5); //Random gera um número aleatório uniformemente aleatório distribuído entre 0 e 1 |
||
| 30 | random_y = fiel_length*(rand()-0.5); |
||
| 31 | ``` |
||
| 32 | |||
| 33 | Basicamente a função estender pode utilizar como target o objetivo ou um ponto aleátório, o que garante que o algoritmo pode encontrar um caminho sem colidir com nenhum obstáculo. Como na figura abaixo: |
||
| 34 | |||
| 35 |  |
||
| 36 | |||
| 37 | A implementação seguiu o pseudo código abaixo: |
||
| 38 | |||
| 39 |  |
||
| 40 | |||
| 41 | ***A função Nearest garante que sempre extendemos a árvore do nó mais próximo do objetivo, porém ela também demanda muito processamento, já que tem q varrer a árvore toda a cada iteração. Vamos estudar um jeito para resolver isso.*** |
||
| 42 | Definimos uma árvore de pontos como uma matriz de 4 colunas, onde a primeira é o id do ponto, a segunda a coordenada x, a terceira a coordenada y e a quarta o id do pai. Dessa forma os nós são adicionados com o id sendo incrementado de 1 a cada nó. O id do pai é o id do nó da onde aquale novo ramo foi gerado. Assim quando encontramos um solução podemos fazer o backtracking nessa árvore para reconstruir a trajetória. |
||
| 43 | |||
| 44 | O próximo passo foi implentar a extenção do RRT (ERRT), com memória da última trajetória. Assim na hora de escolhermos um target podemos ir em direção ao objetivo, em uma direção aleatória ou em direção a algum ponto da última trajetória, como na imagem e código abaixo. |
||
| 45 | |||
| 46 |  |
||
| 47 |  |
||
| 48 | |||
| 49 | Por último implementamos a suavização da trajetória que segue o algoritmo abaixo descrito. Ela auxilia muito na rapidez com que o robô será capaz de seguir a trajetóra. |
||
| 50 | |||
| 51 |  |
||
| 52 | |||
| 53 | ## Raio dos Obstáculos |
||
| 54 | |||
| 55 | ### Robôs Inimigos |
||
| 56 | |||
| 57 | Para os robôs inimigos agora é considerada a influência da velocidade relativa. Assim o raio do obstáculo é dado por: |
||
| 58 | |||
| 59 | ```c |
||
| 60 | radius_enemy + radius_our + bound(0, |speed_enemy-speed_our|*100, 100) |
||
| 61 | ``` |
||
| 62 | E caso o goal esteja dentro de um obstáculo esse raio é reduzido o suficiente para que um trajetória válida possa ser gerada. O mesmo acontece quando o ponto inicial da trajetória está dentro de um obstáculo, o raio é reduzido afim de ser possível a geração da trajetória. |
||
| 63 | |||
| 64 | ## Implementações futuras e problemas atuais |
||
| 65 | |||
| 66 | * Tornar os nossos robôs obstáculos, porém com um raio menor. |
||
| 67 | * Tornar as áreas dos goleiros e a parte de trás do gol em obstáculos |
||
| 68 | * Colocar a bola como obstáculo na situação de stop |
||
| 69 | * Tornar o RRT otimizado para diferentes personalidades |
||
| 70 | |||
| 71 | # Otimização feita (RRT apenas nos obstáculos) |
||
| 72 | |||
| 73 | Conversando com outras equipes na RoboCup 2018, nos deram uma dica de como poderíamos otimizar nosso planejamento de trajetória. A ideia consiste em traçar uma linha reta entre o ponto atual e o final (objetivo) do robô, identificar possíveis obstáculos que cruzam essa reta e aplicar o RRT apenas na região em que ocorrem esses conflitos, mantendo a linha reta onde não houver problema. Isso é essencial para diminuir o custo de processamento e reduzir os cálculos para gerar nosso path, já que o algoritmo é aplicado numa região muito menor. |
||
| 74 | |||
| 75 | Pesquisamos o TDP de outras equipes para procurar alguma referência dessa implementação, mas não foi encontrada essa ideia de fazer o RRT apenas nos obstáculos escrita em nenhum deles. Todos os TDPs se baseavam naquele mesmo artigo (autores James Bruce e Manuela Veloso) por onde estudamos o RRT, e não foi encontrado nada diferente daquilo. |
||
| 76 | |||
| 77 | A respeito da implementação: |
||
| 78 | |||
| 79 | * Criei a VI FindColisionPoints, para encontrar a posição dos obstáculos que cruzam a trajetória reta mais simples entre os pontos inicial e final (Simple Path). Ela retorna um vetor com todas as posições de obstáculos nesse caminho. |
||
| 80 | |||
| 81 | * Criei a VI FindStartEndPointsRRT, que serve para encontrar a posição do obstáculo mais distante e do mais próximo do ponto inicial, dentre os que estao no vetor dos pontos de colisão. Em seguida aplica-se um range (por enquanto escolhi o tamanho 200mm pra cada lado) em volta dessas duas extremidades de obstaculos. Essa área interna ao range aplicado é a que será percorrida usando o RRT, e as de fora por uma linha reta. Verifica-se após aplicar o range se o novo ponto cai fora do simple path, o que significa que está muito perto do ponto inicial (ou final) da trajetória, e nesse caso trocamos o ponto gerado que deu problema pelo ponto inicial ou final correspondente. Ou seja, se os pontos encontrados para iniciar ou acabar o RRT forem muito próximos da extremidade (usei um valor de comparação <200mm por enquanto), ou se caírem fora daquele segmento, entao ignora-se a linha reta nesse pequeno caminho e aplica-se o RRT diretamente desde o ponto inicial ou até o ponto destino diretamente. |
||
| 82 | |||
| 83 | * Adaptei a VI RRTPlan para essas modificações. Primeiro, modularizei um grande pedaço onde se fazia o algoritmo do RRT de fato, criando uma subVI chamada RRTAlgorithm, para facilitar a visualização da escolha dos pontos inicial e final de onde aplicaríamos o RRT. Em seguida usei as duas VIs anteriores para gerar os pontos de obstáculos e encontrar os pontos iniciais e finais convenientes no algoritmo, gerando o novo path. |
||
| 84 | |||
| 85 | Durante a implementação, foi perguntado como ficaria o algoritmo quando existem vários obstáculos em sequência ou um outro obstáculo no end point. |
||
| 86 | |||
| 87 | Resposta: primeiramente eu fiz da forma mais simples, fazendo o RRT em toda a extensão dos obstáculos, desde o primeiro (mais próximo do ponto inicial) até o último (mais perto do ponto final). Optei por essa implementação mais simples a princípio pra verificar se daria certo e observar a trajetória gerada. Depois de debugar e testar dessa maneira, finalmente consegui obter a trajetória desejada pensada dessa forma, e agora posso partir pra implementação mais otimizada ainda: de fazer o rrt em cada obstáculo separadamente (basta fazer um loop no vetor dos obstáculos que eu gerei e tratar os casos de os obstáculos estarem muito próximos e serem aglutinados em apenas 1). |
||
| 88 | |||
| 89 | Seguem agora imagens de como ficou a trajetória gerada nessa implementação mais simples. Vejam que com dois ou mais robôs a trajetória ainda não é a ótima, pois ele calcula o rrt em todo o espaço entre os obstáculos também, e isso é ruim no caso deles estarem muito longes um do outro. |
||
| 90 | |||
| 91 |  |
||
| 92 | |||
| 93 |  |
||
| 94 | |||
| 95 | Em seguida, foi finalizada a implementação mais otimizada, com o RRT aplicado apenas nos obstáculos e em cada um por vez. Obtive as seguintes trajetórias: |
||
| 96 | |||
| 97 |  |
||
| 98 | |||
| 99 |  |
||
| 100 | |||
| 101 | Veja que, quando dois obstáculos estão muito próximos um do outro, de forma que não é possível executar a trajetória reta entre eles, estes são algutinados em 1 só, e é aplicado o RRT sobre aquela extensão: |
||
| 102 | |||
| 103 |  |
||
| 104 | |||
| 105 | Iniciou-se a partir daí os testes para medir o tempo que demora para a execução de todo o cálculo e comparar com a implementação anterior para saber se está mais rápido ou não. Foi decidido como seriam os testes: a ideia é que faremos diversos zig zags com um robô e vou medir o tempo máximo de execução da VI RRTPlan pra cada teste desse. Em seguida vou replicar os mesmos zig zags para a outra implementação do RRT e vamos comparar os tempos. As variações entre os zig zags vão ser apenas nas posições e no número dos obstáculos que vão atrapalhar o robô nessa tarefa. Vou deixar cada zig zag rodando por um tempo determinado (Ex: 1 min) e anotar o tempo máximo de execução obtido nesse período. |
||
| 106 | |||
| 107 | Fiz os testes do RRT novo e antigo, para comparar os tempos de execução da VI RRT Plan, que contém todo o cálculo da trajetória e também a parte de suavização. Fiz os testes nas mesmas condições (apenas um robô ligado e posicionamento preciso no grsim com o set position), e obtive os seguintes resultados de tempo e fps durante o tempo de observação (1 min para cada zig zag feito): |
||
| 108 | |||
| 109 | 1º) Zig Zag entre os pontos (0,2000) e (0,-2000) SEM obstáculos. |
||
| 110 | |||
| 111 | | RRT antigo | RRT novo | |
||
| 112 | |--- | --- | |
||
| 113 | |t=0,0225756s|t=0,000511674s| |
||
| 114 | |fps=45 |fps=57 | |
||
| 115 | |||
| 116 | 2º) Zig Zag entre os pontos (-4000,0) e (4000,0) SEM obstáculos. |
||
| 117 | |||
| 118 | | RRT antigo | RRT novo | |
||
| 119 | |--- | --- | |
||
| 120 | |t=0,0558839s|t=0,000469714s| |
||
| 121 | |fps=43 |fps=57 | |
||
| 122 | |||
| 123 | 3º) Zig Zag entre os pontos (0,2000) e (0,-2000) |
||
| 124 | Obstáculo (robô) no ponto (0,0) |
||
| 125 | |||
| 126 | | RRT antigo | RRT novo | |
||
| 127 | |--- | --- | |
||
| 128 | |t=0,070037s |t=0,0809514s | |
||
| 129 | |fps=50 |fps=57 | |
||
| 130 | |||
| 131 | |||
| 132 | 4º) Zig Zag entre os pontos (-3000,0) e (3000,-0) |
||
| 133 | Obstáculos (robôs) nos pontos (-1000,0) e (1000,0) |
||
| 134 | |||
| 135 | | RRT antigo | RRT novo | |
||
| 136 | |--- | --- | |
||
| 137 | |t=0,0533753s|t=0,0781024s | |
||
| 138 | |fps=50 |fps=57 | |
||
| 139 | |||
| 140 | |||
| 141 | 5º) Zig Zag entre os pontos (-3000,0) e (3000,-0) |
||
| 142 | Obstáculos (robôs) nos pontos (-2000,0) e (2000,0) |
||
| 143 | |||
| 144 | | RRT antigo | RRT novo | |
||
| 145 | |--- | --- | |
||
| 146 | |t=0,0809107s|t=0,0846672s | |
||
| 147 | |fps=50 |fps=57 | |
||
| 148 | |||
| 149 | |||
| 150 | Conclusões dos testes: |
||
| 151 | |||
| 152 | * Quando não há obstáculos, o RRT novo é na ordem de 100 vezes mais rápido. |
||
| 153 | * Quando há obstáculos, os dois tempos são de mesma ordem de grandeza, sendo que o RRT antigo é ligeiramente mais rápido: no teste de maior diferença (teste 4), a diferença de tempos foi de 0,0247271s. |
||
| 154 | * Em todos os testes, o código se manteve com fps mais alto no RRT novo. Nos testes em que não havia obstáculos e a trajetória simples podia ser usada, o fps do RRT antigo se mostrou ainda mais baixo que nos outros casos. |