Olá Habr!
Nesta publicação, gostaria de falar sobre como eu construí um mapa de cross-country local para o robô. Essa tarefa foi necessária para aumentar as habilidades de programação e dominar sensores e para a subsequente implementação de nossos próprios algoritmos no trabalho de robôs reais em testes robóticos como Robocross e Robofest.
Este artigo é destinado a quem está apenas entrando no mundo da robótica ou tentando descobrir como construir um mapa de cross-country. Tentei expor tudo na linguagem mais simples e compreensível para a maioria das pessoas.
O que é um mapa local de cross-country
Portanto, um
mapa local de cross -
country é o que o robô vê em um determinado momento no tempo.
Esta é a informação que vem dos "olhos" do robô e é posteriormente processada e exibida de uma forma conveniente para nós.
Se o robô ficar parado, seu mapa local sob condições ambientais constantes permanecerá constante.
Se o robô se mover, a cada momento seu ambiente será diferente, respectivamente, o mapa local também mudará.
O mapa local geralmente tem tamanhos constantes. O tamanho é calculado com base no comprimento máximo dos raios emitidos pelo telêmetro. No meu caso, esse comprimento é de 6 metros.
Para simplificar a tarefa, foi decidido tornar o mapa quadrado, e também o localizador de distâncias condicionais estaria exatamente no centro do mapa (este local será o ponto em que x = y = 0). O centro foi escolhido desta maneira porque o telêmetro que eu uso emite raios no avião mais de 180 ° (emite raios a 240 °, mas mais sobre isso depois), ou seja, alguns raios certamente vão por trás do scanner e se você escolher o centro errado, poderá perdê-los. Com uma escolha adequada do centro, todos os raios serão exibidos corretamente. Com base nisso, fiz o tamanho do mapa 2 vezes maior que o comprimento máximo dos raios emitidos.
O tamanho do meu cartão é 12 * 12 metros.

O sensor que eu usei
De fato, para resolver esse tipo de problema, você pode usar qualquer localizador de alcance.
O telêmetro é um dispositivo para determinar a distância a algo (no meu caso, a um obstáculo em potencial).
Na robótica, principalmente 2 tipos de telêmetros são usados: ultrassônico e laser.
Telêmetros ultrassônicos são muito mais baratos, mas os raios ultrassônicos são amplos o suficiente e não são adequados para medições precisas.
Os telêmetros a
laser são mais caros, mas mais precisos, pois seus raios são estreitamente focados.
Para resolver meu problema, usei um scanner a laser Hokuyo URG-04LX-UG01. Este sensor é capaz de emitir raios a 240 ° e fornece informações bastante precisas sobre os obstáculos que impediram os raios. Seu alcance máximo é de 5-6 metros. Vale a pena notar que este telêmetro emite raios apenas no plano 2D. Esse fato obriga a colocar o sensor no robô em um determinado local, geralmente na frente da parte inferior do robô, para obter uma imagem mais precisa. Novamente, você pode usar scanners 3D, que fornecem informações muito mais precisas e completas sobre o ambiente, mas também custam muito mais.
Acredito que esse scanner específico seja perfeito para treinamento na relação qualidade / preço.
Hokuyo URG-04LX-UG01Brevemente sobre o princípio do scanner a laser:O telêmetro emite raios ao longo do avião. Um raio que encontrou um obstáculo em seu caminho é refletido e volta. Pela diferença de fase entre os sinais enviados e recebidos, pode-se avaliar até que ponto o obstáculo está localizado.
Assim, se o feixe emitido não retornar, a 5 - 6 metros ao longo da linha reta de sua emissão não haverá obstáculos ou o feixe não poderá refletir corretamente.
Os seguintes dados podem ser obtidos em um scanner a laser:Para cada raio emitido:
- Distância a um obstáculo
- Ângulo de emissão
* Cada um dos parâmetros é armazenado em uma matriz separada e corresponde aos dados de um dos raios.Sobre a construção do mapa
Para construir o mapa e desenhá-lo, usei as ferramentas ROS (Robot Operating System), a saber: o programa Rviz e o tipo de dados nav_msgs :: OccupancyGrid. Criei um editor do mapa local com o tipo de mensagem nav_msgs :: OccupancyGrid no tópico correspondente local_map. No Rviz, assinando este tópico, recebeu dados sobre o mapa e os exibiu no formato de mapa.
De acordo com esse algoritmo, era necessário configurar programaticamente o processamento de dados de um scanner a laser e registrá-los no formato necessário para a transmissão. No OccupancyGrid, um mapa é armazenado e transmitido em uma matriz unidimensional.
O que está acontecendo aqui?Para aqueles que se deparam com esse tipo de dados ROS pela primeira vez: isso é incomum, pois o mapa é convencionalmente representado como uma matriz bidimensional com um certo número de colunas e linhas.
Então foi comigo. Eu armazeno o mapa com base nos dados do scanner em uma matriz bidimensional e, ao escrever uma mensagem para enviar ao Rviz, converterei a matriz bidimensional na matriz unidimensional necessária para o OccupancyGrid.
De fato, um mapa no OccupancyGrid é armazenado e transmitido apenas em uma matriz unidimensional. Ao descriptografar seus dados, ele se transformará automaticamente em um mapa bidimensional quadrado.
Mas para que isso aconteça corretamente, você precisa escrever esse array unidimensional de uma certa maneira.
A saber: linha por linha do armazenamento bidimensional para escrever em uma linha.
Voila! Este é todo o segredo.
Um apelo a qualquer elemento de uma matriz unidimensional ocorre da seguinte maneira:
mapSize - tamanho do mapa local
j é o número da coluna
i - número da linhaAs células do mapa (novamente de acordo com o tipo de dados do OccupancyGrid) devem ter valores de 0 a 100. Quanto menor o valor, maior a probabilidade de a célula ser passável e vice-versa.
Para simplificar a tarefa, selecionei
três cores primárias para colorir células.- Branco - Área transitável = 0
- Preto - Área intransitável = 100
- Cinza - zona desconhecida = 50
Um ponto importante!Antes da chegada dos dados do scanner, o mapa é completamente desconhecido (valores de todas as células = 50) e todas as vezes após o desenho são atualizados novamente para um estado desconhecido. Isso é feito para que o cartão não sobreponha valores anteriores supérfluos. Afinal, um mapa local reflete o estado do ambiente apenas em um determinado momento no tempo.
Cartão desconhecidoOs raios são construídos usando uma transformação do sistema de coordenadas polares (UCS)
ao sistema de coordenadas cartesianas (DSC).
$$ display $$ \ left \ {\ begin {gather} x = r * cos \\ y = r * sin φ \ end {reunir} \ right. $$ display $$
x, y - novas coordenadas no DSC
r é a distância do obstáculo
φ é o ângulo em que o feixe caiu
r, φ - coordenadas antigas no UCS
Algoritmo de processamento de dados do sensor:
Atravessamos completamente os arranjos das distâncias re ângulos φ dos raios (dados UCS). Para cada item, faça o seguinte:
- Transformamos as coordenadas do UCS em DSC para re finito e φ. Pinte a célula resultante de preto. Isso é um obstáculo.
- Passamos em linha reta do local do scanner para a célula com um obstáculo em uma determinada etapa, no caso mais simples, igual ao tamanho da célula.
- Mais uma vez, convertemos os dados do UCS para o DSC e pintamos a nova célula em branco. Esta é uma área que pode ser percorrida.
O exemplo mais simples de como construir um caminho percorrível até um obstáculoMas e se o feixe emitido não retornar?Se isso acontecesse, poderia significar o seguinte:
- O raio está "perdido", ou seja, não é totalmente refletido ou refletido na outra direção
- Não havia obstáculos no caminho da viga e, por isso, simplesmente não tinha nada para refletir
* Um raio pode "se perder" geralmente porque não foi refletido em um ângulo de 180 ° (ou seja, sob qualquer um que não alcance para trás), pois o obstáculo pode ficar perpendicular ao raio. E como você sabe da física: o ângulo de incidência é igual ao ângulo de reflexão.

Ou porque o obstáculo era muito preto e absorveu a maior parte da energia do feixe e o feixe não tinha energia suficiente para voltar.
Assim, é impossível ter certeza absoluta do que aconteceu se o feixe não retornasse.
O que fazer em tais situações?Fazemos o seguinte:
- Consideramos a distância possível ao obstáculo de um feixe para o scanner (no nosso caso, são 6 metros)
- Consideramos todas as células em linha reta para o obstáculo como semi-passáveis e atribuímos a elas um número intermediário de 25. Essas são células passáveis, mas não temos certeza absoluta delas.
Não perderemos nada se os raios realmente não encontrarem obstáculos, e se algum tipo de obstáculo escapar dos "olhos" do robô, certamente será detectado muito rapidamente.
Resolução do cartão
Finalmente, os retoques finais!
Cada cartão tem permissão. Simplificando, este é o número de células que podem caber em uma célula.
Por exemploSe houver 1 célula em 1 célula (o caso mais simples), a resolução 1.
Se houver 5 células em 1 célula, a resolução será 0,2.
A resolução do meu cartão é 0,04. Ou seja, em cada célula existem 25 células. Assim, meu passo mínimo é de 4 cm e 1 célula é de 1 m.
Célula e diferença de células no meu mapaQual é o resultado?
Um exemplo de construção de um mapa local de cross-country
* Cor amarela indica cores das célulasAcredito que, em geral, o trabalho que fiz foi bem-sucedido, mas entendo que o algoritmo é imperfeito e requer refinamento e refinamento.