Projeto

Geral

Perfil

Ações

Atividade #609

Fechada

Implementação de KD-Tree para otimização do RRT

Adicionado por Luciano Barreira mais de 7 anos atrás. Atualizado quase 7 anos atrás.

Situação:
Fechada
Prioridade:
Normal
Atribuído para:
Início:
01/03/2018
Data prevista:

Descrição

As equipes que usam RRT como algoritmo de planejamento de trajetória otimizam a checagem de vizinho mais próximo da árvore ( que originalmente é feita com uma varredura completa da árvore, cuja complexidade computacional é ´O(n)´ , sendo ´n´ a quantidade de nós da árvore ) utilizando um método de clusterização da árvore chamado KD-Tree (árvore K dimensional). Segundo [este](http://www4.cs.umanitoba.ca/~jacky/Robotics/Papers/Bruce-RealTimeRandomizedPathPlanning.pdf) paper da CMDragons, a otimização permite que o algoritmo seja utilizado para pelo menos 5 robôs com folga de recursos computacionais para os algoritmos de IA.


Arquivos

CG_RangeKDtrees.pdf (394 KB) CG_RangeKDtrees.pdf Nicolas Oliveira, 05/03/2018 19:09 h
nearest_search.pdf (868 KB) nearest_search.pdf Nicolas Oliveira, 05/03/2018 19:09 h
CreateKD-Tree.PNG (49,8 KB) CreateKD-Tree.PNG Nicolas Oliveira, 05/03/2018 20:01 h
KD-Tree.PNG (41,5 KB) KD-Tree.PNG Nicolas Oliveira, 05/03/2018 20:01 h
buildkdtreeCode.PNG (103 KB) buildkdtreeCode.PNG Nicolas Oliveira, 05/03/2018 20:01 h
buildkdtree.PNG (62,3 KB) buildkdtree.PNG Nicolas Oliveira, 05/03/2018 21:03 h
KD-TreeLabView.PNG (12,5 KB) KD-TreeLabView.PNG Nicolas Oliveira, 08/03/2018 00:03 h
ex.PNG (7,86 KB) ex.PNG Nicolas Oliveira, 08/03/2018 00:03 h
NN.PNG (77,6 KB) NN.PNG Nicolas Oliveira, 15/03/2018 01:07 h
BB.PNG (30,2 KB) BB.PNG Nicolas Oliveira, 15/03/2018 01:18 h
Write Line to File.jpg (19,5 KB) Write Line to File.jpg Lucas Germano, 16/03/2018 11:32 h
WriteLine to File.vi (13,6 KB) WriteLine to File.vi Lucas Germano, 16/03/2018 11:33 h
tree.PNG (26,3 KB) tree.PNG Nicolas Oliveira, 18/03/2018 03:56 h
tree1.PNG (32,4 KB) tree1.PNG Nicolas Oliveira, 18/03/2018 03:56 h
code.PNG (33,2 KB) code.PNG Nicolas Oliveira, 18/03/2018 03:57 h

Atualizado por Nicolas Oliveiramais de 7 anos

Para estudo foi utilizado o seguinte [link](https://salzis.wordpress.com/2014/06/28/kd-tree-and-nearest-neighbor-nn-search-2d-case/) e os documentos anexos.

Entendi como a kd-tree funciona e tenho uma ideia para sua implementação. Vou gerar uma wiki no redmine sobre isso.

Ações #2

Atualizado por Luiz Renault Leite Rodriguesmais de 7 anos

Colocar resumo na tarefa sobre o funcionamento.

Atualizado por Nicolas Oliveiramais de 7 anos

O primeiro passo foi entender como uma KD-Tree é criada. A ideia principal é fazer uma busca binária só que em 2D. Pra isso vamos dividindo o ambiente em dois por X e por Y alternadamente. Os pontos restandes de cada lado dessas regiões são ordenados com relação ao eixo em que serão divididos.
De acordo com as imagens abaixo:
![](CreateKD-Tree.PNG)

![](buildkdtree.PNG)

Podemos gerar esta árvore utilizando a implementação do pseudo código abaixo:

![](buildkdtreeCode.PNG)

Ações #4

Atualizado por Luciano Barreiramais de 7 anos

Encontrei [esta](https://www.geeksforgeeks.org/k-dimensional-tree/) referência muito boa do GeeksForGeeks.

A ideia é utilizar a subrotina de inserção da árvore, pois se construíssemos a KD-Tree (nesse caso, 2D-Tree) toda vez que formos buscar pelo nearest, teríamos uma complexidade maior até que a atual, o que não é interessante já que queremos otimizar o processo. Dado que sabemos montar, inserir e buscar na KD-Tree (depois discutimos como implementar as subrotinas no LabView), minha sugestão de algoritmo, em alto nível, é:

- inicializa a 2D-Tree ``2Dtree``
- insere ``starting_point``

No loop de expansão do ``RRT``, para cada nó aleatório ``random_node``, fazemos:

- busca pelo vizinho ``neighbour`` mais próximo de ``random_node`` na ``2DTree``, utilizando rotina de busca
- gera nó auxiliar ``candidate`` na direção de ``neighbour`` a um passo ``r`` (expansão do ``RRT``). Note que estamos usando r como passo espacial, uma sugestão futura é utilizar um passo de tempo pela lógica do perfil bang-bang.

- checa se ``candidate`` está dentro de algum obstáculo
- se não
- expande ``RRT`` colocando ``candidate`` no RRT como filho de ``neighbour``
- expande ``2DTree`` inserindo ``candidate`` a partir de ``neighbour`` (não é necessário inserir a partir da raíz da ``2DTree``, uma vez que esta insersão resultaria em inserir a partir do ``neighbour``), consoante lógica de inserção da kd-tree
- se sim, continua
- checa se ``candidate`` está a uma distância ``d`` do ``goal_point`` (isso também pode ser levemente otimizado comparando as somas dos quadrados das diferenças das coordenadas, em vez de as raízes quadradas disto, mas isso é superotimizar).
- se sim
- insere ``goal_point`` no RRT como filho de ``candidate`` e termina o processo

Atualizado por Nicolas Oliveiramais de 7 anos

Criada a VI para inserir pontos na KD-tree, ou construí-la do zero.
O fato de eu não saber como utilizar, ou se posso utilizar, ponteiros no labview dificultou bastante, já que todas as implementações se utilizavam disso.

Então criei uma estrutura de kD-tree com 3 dimensões (x,y,F), rebeca vai utilizar terceira dimenção, custo, no A*, mais o indice de seu filho a esquerda e a direita nessa ordem.
A arvore começa vazia e toda alguém é inserido e reservado espaço para seus filhos nos índices size e size+1 da árvore, colocando valor de infinito.

Ex: (3, 6), (17, 15), (13, 15), (6, 12), (9, 1), (2, 7), (10, 19) essa sequência gera:

Essa ávore
![](ex.PNG)

Fica assim
![Fica assim](KD-TreeLabView.PNG)

Sou capaz de dizer também em que nó quero começar a inserção. Isso será usado para que possa começar a inserção pelo neirest.

Ações #6

Atualizado por Nicolas Oliveiramais de 7 anos

  • Título alterado de Estudar implementações de KD-Tree para otimização do RRT para Implementação de KD-Tree para otimização do RRT
Ações #7

Atualizado por Nicolas Oliveiramais de 7 anos

A ideia de utilizar os indices sempre como 2k e 2k+1, comum na construção de árvores binárias, foi abandonada pois necessitáriamos alocar muita memória desnecessária. Dessa maneira implementada n corremos risco nenhum de estouro de memória.

Ações #8

Atualizado por Luciano Barreiramais de 7 anos

[este](https://forums.ni.com/t5/Example-Program-Drafts/Advanced-Data-Structures-in-LabVIEW/ta-p/3519662) link, tirado do submundo dos fóruns da NI, pode ajudar. Tem várias implementações abstraídas de árvore, fila, lista encadeada e grafos.

Ações #9

Atualizado por Nicolas Oliveiramais de 7 anos

Dei uma olhada nas VIs que vem junto com essas implementações. Mas elas são bem complexas, porque mexem com o labview de uma forma que não estamos acostumados. Existe até um de shortest path, mas o tempo de execução me pareceu bem longo.
Talvez o ideal seja continuar usando nossos algoritmos já implementados porém mudar as estruturas para as dessa "biblioteca".

Ações #10

Atualizado por Luciano Barreiramais de 7 anos

Nicolas Oliveira escreveu:

Dei uma olhada nas VIs que vem junto com essas implementações. Mas elas são bem complexas, porque mexem com o labview de uma forma que não estamos acostumados. Existe até um de shortest path, mas o tempo de execução me pareceu bem longo.
Talvez o ideal seja continuar usando nossos algoritmos já implementados porém mudar as estruturas para as dessa "biblioteca".

A ideia não é necessariamente usar essas VIs, mas usar as soluções de implementações delas em nossas soluções. São bibliotecas de desenvolvedores da NI, pelo que eu entendi.

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

A implementação do Nearest Neighbor está sendo feita utilizando este [link](https://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/kdtrees.pdf) como referência. Pseudo código do NN:

![](NN.PNG)

Onde uma da principais vantagens é o cálculo da BoundingBox (BB), de acordo com o desenho abaixo. Isso garante que sub-árvores irrelevantes não sejam visitadas.

![](BB.PNG)

Para o cálculo da BB foram implementadas as VIs de findMin e findMax, para achar os nós com as menores ou maiores coordenadas, respectivamente, tanto em x ou em y. Assim temos as fronteiras da BB. Caso a distância do Target a BB seja maior do que a Best_dist não existirá nenhum ponto promissor nessa BB. O que preciso ajeitar é como calcular a distância um ponto a um retângulo.

Caso eu esteja em uma sub-árvore promissora eu visitarei o melhor lado primeiro, o que também dá mais velocidade ao algoritmo.

Ações #12

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

Estou tendo problemas também para atualizar as variáveis globais.

Ações #13

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

Implementei as VIs para cálculo da distância a BoundingBox e para decidir através desse resultado se é essa subTree é promissora ou não.

A VI do nearest está pronta, porém estou tendo problemas nas variáveis globais do código. A VI é recursiva, porém elas só estão sendo atualizadas na primeira iteração. E estou com muita dificuldade em debbugar isso. Resolvendo isso, tecnicamente, a busca do nearest point pela KD-tree vai estar pronta.

Ações #14

Atualizado por Luciano Barreiraaproximadamente 7 anos

Nicolas Oliveira escreveu:

A implementação do Nearest Neighbor está sendo feita utilizando este [link](https://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/kdtrees.pdf) como referência. Pseudo código do NN:

![](NN.PNG)

Onde uma da principais vantagens é o cálculo da BoundingBox (BB), de acordo com o desenho abaixo. Isso garante que sub-árvores irrelevantes não sejam visitadas.

![](BB.PNG)

Para o cálculo da BB foram implementadas as VIs de findMin e findMax, para achar os nós com as menores ou maiores coordenadas, respectivamente, tanto em x ou em y. Assim temos as fronteiras da BB. Caso a distância do Target a BB seja maior do que a Best_dist não existirá nenhum ponto promissor nessa BB. O que preciso ajeitar é como calcular a distância um ponto a um retângulo.

Caso eu esteja em uma sub-árvore promissora eu visitarei o melhor lado primeiro, o que também dá mais velocidade ao algoritmo.

Massa. Diferente de outras árvores, não basta pesquisar pelo elemento na KD-Tree e inserir onde ele "estaria". Mesmo assim, como explica no link, o caso médio fica O(altura da árvore).

Próximos passos:

- revisão da implementação, testes com o debugger visual. Testar com várias configurações diferentes, observando a trajetória no debugger visual. Testar uma unidade dessas é meio complicado, não consegui pensar numa forma melhor.
- benchmarking da VI. Podemos medir o quão melhorou. Dado um frame de jogo, qual o tempo de execução da VI, tanto usando o performance tools (tempo de execução de um frame) do LabView quando usando um FPS counter que nos retorne a frequência obtida, rodando apenas a VI do cálculo da trajetória em loop com um frame dummy. Imagino que o FPS counter seja uma medida mais confiável pois há o bias do waypoint cache no cálculo do RRT, que estaria vazio em uma única execução.
- teste em jogo simulado (mesmo sem navegação ainda, dá pra visualizar a trajetória e medir se a performance está pesando em um jogo dinâmico)

E após a implementação da navegação:
- teste com 1 robô real
- teste com vários robôs reais

Atualizado por Lucas Germanoaproximadamente 7 anos

Ontem eu e o Nicolas conseguimos debugar a KD-tree imprimindo vários valores num arquivo .txt. O debug de uma VI recursiva estava sendo muito difícil só pelos probes, principalmente se analisarmos a NearestNeighbor.vi, que é um VI que utiliza uma recursão para outras duas funções, daí utilizamos a seguinte ideia para imprimir linhas de debug no arquivo (não é uma coisa tão trivial quanto outras linguagens de programação):
![](Write Line to File.jpg)

A vi também está disponível em anexo.

Vimos que estava passando um valor NaN, devido a um parâmetro que estava faltando. Quando corrigimos, a KD-tree funcionou!!!

Ações #16

Atualizado por Luciano Barreiraaproximadamente 7 anos

Lucas Germano escreveu:

Ontem eu e o Nicolas conseguimos debugar a KD-tree imprimindo vários valores num arquivo .txt...

Parabéns. Mas o que seriam esses "vários valores" ?? Qual era o problema ?

Ações #17

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

Valores impressos no .txt (usar como referência o pseudo código na tarefa):

  • ditancia(Q,BB)
  • best_dist
  • NóAtual
  • ditancia(Q,NóAtual)>best_dist
  • best
  • Q
  • deepth

Percebemos que distancia de Q ao nóAtual era sempre um NaN e os problemas nos outros valores eram devidos a isso. O erro era q o Q (chamado de target na VI) não era uma variável global nem uma entrada, então n estava sendo passado seu valor certo para as chamadas recursivas.

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

A primeira implementação da KD tree segui o pseudo-código da imagem abaixo a partir de uma árvore do tipo abaixo também. Porém ao utilizá-lo no RRT o desempenho do nosso software caiu muito, levando até 1s para q uma trajetória simples fosse calculada.

![](NN.PNG)
![](tree1.PNG)

Sendo assim, estudando um pouco, vi que há outra maneira de se escrever a KD-tree, descrita abaixo. Mas ela normalmente não é usada quando desejamos inserir nós, mas sim montar toda árvore de uma vez. Porém como não achei qualquer restrição para isso a implementei.

![](code.PNG)
![](tree.PNG)

Dessa vez de uma forma bem mais organizada inclusive com o código todo comentado e utilizando um cluster para designar um nó. Porém o desempenho foi muito parecido. Para um trajetória que é calculada em 5ms pelo RRT normal, demora cerca de 0.5s utilizando-se a kdtree.

Fazendo algumas pesquisas sobre como aumentar a performance do labview vi que ele n lida bem com recursão e além disso ficou claro que ainda não sabemos bem como utilizar as ferramentas que o labview disponibiliza para isso.
Mas não sei se o labview pode chegar perto do desempenho de um biblioteca otimizada por exemplo.

Ações #19

Atualizado por Luiz Renault Leite Rodriguesaproximadamente 7 anos

O desempenho pode chegar muito perto.

De que tipo de recursão está falando.

Hoje não temos nenhuma preocupação de desempenho. Por exemplo, a depuração está habilitada em todas as VIs.
VIs críticas podem ser implementadas como Inline, evitando chamadas desnecessárias e troca de contexto.

Ações #20

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

Recursão normal, como a do código acima. Não conheço outros tipos rs. Já que li aqui que não podemos transformar VIs recursivas em inline ou subrotina. Acho q seria bom desligar o debug nessas VIs também para aumentar o desempenho.

O que ficou estranho pra mim foi que o desempenho caiu MUITO para algo que deveria melhorar.

Acho que começarmos a nos preocupar com o desempenho e fazer um levantamento das VIs críticas. Talvez diminuindo o consumo delas consigamos utilizar o RRT sem kD-tree por enquanto.

Ações #21

Atualizado por Nicolas Oliveiraaproximadamente 7 anos

Eu escondi os controls para não mostrar no painel frontal e tentar melhorar o desempenho. Mas segundo esse [link](http://zone.ni.com/reference/en-XX/help/371361H-01/lvconcepts/vi_execution_speed/) mesmo escondidos os controls ainda vão sendo atualizados. Vou pesquisar mais formas de melhorar a performance de VIs recursivas.

Ações #22

Atualizado por Gabriel Borges da Conceiçãoquase 7 anos

  • Situação alterado de Em andamento para Resolvida
Ações #23

Atualizado por Gabriel Borges da Conceiçãoquase 7 anos

  • Situação alterado de Resolvida para Fechada
Ações

Exportar para Atom PDF