Plataforma de pessoas para robôs em ROS

O artigo foi escrito apenas para aqueles que fazem parte do próprio ROS e que precisam construir um robô real para treinar ou realizar tarefas reais.







Quando você começa a aprender ROS, geralmente deseja trabalhar com plataformas físicas, e não com modelos em um simulador. Na verdade, o Gazebo é suficiente para estudar apenas algoritmos de movimento ou apenas ensinar o próprio ROS, mas trabalhar com uma plataforma real imediatamente permite entender na prática todos os problemas com o movimento das rodas. Bem, e muitas vezes a plataforma é necessária simplesmente como um pré-requisito para o projeto.



Para o futuro, é melhor começar com uma rodada, porque por razões óbvias, tal configuração pode girar em torno do eixo sem levar em consideração o tamanho da parte saliente. O retângulo de retorno é muito menos conveniente, por exemplo, em corredores estreitos - às vezes torna-se necessário desdobrar 3 ou mais manobras, acho que os motoristas vão entender.



Compra de plataformas prontas



Não existem muitas plataformas prontas no mercado, uma lista delas é fornecida no site da ROS .



Ao mesmo tempo, seu custo na Rússia é alto o suficiente para começar a funcionar; a opção mais barata é o Turtlebot Burger 3 - $ 549. Encontramos revendedores diretamente na Rússia por cerca de 90.000 rublos.







Na China, você pode comprar por 45-50 tr ... Em qualquer caso, serão plataformas de pequeno tamanho e capacidade de carga, incapazes de realizar tarefas reais.



Você mesmo pode construir a plataforma, há muitos guias e configurações diferentes. Mas, em média, acontece algo como:



  • Slamtech A1-A2 classe lidar
  • Rodas baratas baseadas em motores coletores com caixas de câmbio
  • , PWM , UART + rosserial.
  • Single Board Computer — Raspberry, Jetson Nano
  • 2
  • gmapping + amcl/rosbot_ekf + move_base






Não gostamos dos motores coletores porque são barulhentos, têm alto consumo e é necessária uma caixa de câmbio. Aqui, devo dizer que as plataformas são consideradas bastante pesadas - ou seja, caixas de engrenagens + motores intertravados, algo como o motor da foto, não funcionarão.



Consequentemente, os motores de roda BLDC foram escolhidos como motores. A opção mais acessível no momento são as rodas de prancha 6.5. Resta apenas gerenciá-los a partir de ROS.



Mas então surgiu um problema: mesmo quando se trabalhava com robôs de golfe , um problema significativo foi percebido com a rotação de tal plataforma em baixa velocidade - o robô girou bastante irregular.



As razões para este comportamento são simples: as forças de fricção deslizante desempenham um papel significativo na resistência ao movimento na curva. E eles têm uma peculiaridade - a resistência depende da massa e da natureza das próprias superfícies - é por isso que um pequeno parafuso segura grandes estruturas com as primeiras 2-3 voltas.



Portanto, tornar as rodas estreitas no centro para que vire torna-se bastante inútil - a resistência mudará muito pouco. A roda de borracha esfrega contra a grama e o solo, que não são uniformes e a força pode mudar drasticamente, por isso foi feito algo como uma caixa de câmbio - na velocidade baixa controlamos o momento na roda, e com movimento direto - a própria velocidade.





Ao dirigir em parquet ou linóleo, a situação deveria parecer melhor, mas, infelizmente, o coeficiente de atrito é quase o mesmo (lembre-se que os calçados antiderrapantes também são feitos de borracha).







E como resultado, um robô pesando 10-15 kg já está começando a se desdobrar com solavancos tangíveis.



A segunda parte do problema é adicionada pelo pacote ROS diff_drive em combinação com placas SBC bastante fracas.



Aqui está uma lista do que eu consegui entender



O gerenciamento é realizado em tempo real, mas não leva em consideração que outros pacotes devem esperar essa abordagem ao trabalhar com o gerenciamento.



Aqui, devemos lembrar que o tempo real não é uma reação instantânea a um evento, mas uma garantia de que o evento será processado em intervalos garantidos de tempo físico. Essa. hidrelétrica condicional, regulada a cada minuto (necessariamente a cada) também é um sistema em tempo real.

Há uma chance de que as mensagens obstruam os tópicos do planejador de rotas e, para posicionamento e subsistemas de planejamento de rotas, esse comportamento geralmente leva à interrupção e reinicialização do fluxo ou à tentativa de ajustar o processo em tempo real.







Como resultado, em SBCs fracos , surge uma situação com recálculo contínuo do caminho, ou a busca por localização consome um tempo de processador bastante grande - e quanto mais tentativas são feitas para acompanhar o componente RT, mais tempo de execução se acumula. Em sua forma pura, feedback positivo, que neste caso não é necessário.



Além disso, o gmapping não começa a funcionar muito rapidamente com mudanças abruptas na posição da plataforma e um lidar fraco - houve pausas de até meio segundo, o que também confunde muito o planejador de rotas.



Os motores são controlados separadamente, portanto, ao usar SBC e uma implementação ingênua de drivers, as rodas serão controladas com algum atraso.



Aqui, o problema é ainda mais simples - precisamos controlar 2-4 rodas através do canal de comunicação, que. Conseqüentemente, os sinais de controle se alinham e começam a ser transmitidos um após o outro - roda esquerda, roda direita, roda esquerda, roda direita.



Com isso, as próprias rodas e, pior ainda, as posições das rodas dos codificadores passam a contribuir para a formação do PIC entre o planejamento do trajeto e o controle dos motores.



A odometria embutida é muito simplista.



Como não estávamos procurando uma maneira simples de sincronizar o comando e o retorno da odometria - não consegui encontrar. A sincronização está sempre associada à espera de alguns comandos na entrada, mas eles não são regulares no tempo e, como resultado, a odometria começa a demorar na saída. Talvez os leitores sugiram uma maneira fácil - aqui não nos consideramos um guru em ROS.



Não conseguimos garantir que tal assembleia se comportasse bem. Mais precisamente, foi possível subestimar a aceleração de deslocamento para 0,05-0,1 m / s ^ 2 e a velocidade angular para 0,03 rad / s.



Achei que seria bom ter:



  • Plataforma barata
  • Direção de roda sincronizada
  • Cálculo de odometria baseado no comportamento e manuseio da roda
  • Modos de movimento giratório com controles diferentes
  • Restrições diferentes em modos diferentes


O que aconteceu no final



O controlador foi retirado das placas da giro-scooter e o controle da roda foi escrito de forma que o controle de torque é usado ao iniciar o movimento e virar. E se o carrinho está indo em linha reta e acelerado até uma determinada velocidade, o modo de controle de velocidade é ativado. Em ambos os modos, os dados dos codificadores são processados ​​dentro do controlador, levando em consideração a velocidade e o modo, e os dados são enviados com alguma previsão antes de 10-15 ms.



Os codificadores são sempre lidos no controlador, se acumulam em um buffer de 2 a 3 elementos e são transmitidos com atraso. O resultado final é que, quando o controle é recebido, a resposta só vai depois que o comando é executado - ou seja, o buffer é bloqueado até que os valores alterados do codificador sejam recebidos. Mas a odometria está sendo emitida, apenas usa o último valor já transmitido.



Porque Todos os problemas acima resumem-se ao fato de que é necessário em qualquer caso sincronizar o controle na recepção e transmissão síncronas da porta UART, então consideramos não razoável introduzir um sincronizador forçado no pacote diff_drive, então escrevemos nosso próprio pacote de controle.



Ele está localizado aqui github.com/Shadowru/hoverboard_driver e está sendo finalizado ativamente:



O pacote está incluído no arquivo de inicialização como:



<node name="hoverboard_driver" pkg="hoverboard_driver" type="node" output="screen">
        <param name="uart" value="{ }"/>
        <param name="baudrate" value="115200"/>
        <param name="wheel_radius" value="0.116"/>
        <param name="base_width”  value="0.43"/>
        <param name="odom_frame”  value="odom"/>
        <param name="base_frame”  value="base_link"/>
    </node>
      
      





A própria porta uart deve ter os direitos de acesso apropriados; em algumas plataformas, nem sempre tem acesso para o usuário. Por exemplo - para o Jetson Nano no diretório hoverboard_driver / scripts / jetson_nano_serial.sh, é anexado um script que define os direitos quando o sistema operacional é iniciado.



O próprio pacote contém a leitura do fluxo de dados do controlador e a emissão das informações relevantes para os tópicos:



hoverboard_driver / hoverboard_msg com um pacote como hoverboard_msg



A estrutura da mensagem é a seguinte:



int16 estado1 - informações internas na roda 1

int16 estado2 - informações internas na roda 2

int16 velocidade1 - velocidade instantânea da roda 1

int16 speed2 - velocidade instantânea da roda 2

int16 batVoltage - tensão da bateria

int16 boardTemp - temperatura do controlador

int16 error1 - wheel 1 error

int16 error2 - wheel 2 error

int32 pulseCount1 - wheel 1 encoder counter

int32 pulseCount2 - wheel 2 encoder counter



Além disso, o tópico hoverboard_driver / odometry recebe uma mensagem típica nav_msgs :: Odometry A



posição é calculada da seguinte maneira:



Com base nos parâmetros wheel_radius - radius rodas em metros, base_width - a distância entre os centros das rodas, calculamos quanto cada roda se moveu durante o tempo entre a posição anterior e a lida.



double curr_wheel_L_ang_pos = getAngularPos((double) feedback.pulseCount1);
double curr_wheel_R_ang_pos = getAngularPos((double) feedback.pulseCount2);

double dtime = (current_time - last_time).toSec();

double delta_L_ang_pos = curr_wheel_L_ang_pos - raw_wheel_L_ang_pos;
double delta_R_ang_pos = -1.0 * (curr_wheel_R_ang_pos - raw_wheel_R_ang_pos);
      
      





Em seguida, calculamos a aceleração de cada uma das rodas



wheel_L_ang_vel = delta_L_ang_pos / (dtime);
wheel_R_ang_vel = delta_R_ang_pos / (dtime);
      
      





Em seguida, calculamos a aceleração linear do robô ao longo de cada um dos eixos



robot_angular_vel = (((wheel_R_ang_pos - wheel_L_ang_pos) * wheel_radius / base_width) - robot_angular_pos) / dtime;
robot_angular_pos = (wheel_R_ang_pos - wheel_L_ang_pos) * wheel_radius / base_width;

robot_x_vel = ((wheel_L_ang_vel * wheel_radius + robot_angular_vel * (base_width / 2.0)) * cos(robot_angular_pos));
robot_y_vel = ((wheel_L_ang_vel * wheel_radius + robot_angular_vel * (base_width / 2.0)) * sin(robot_angular_pos));
      
      





Como resultado, obtém-se um conjunto completo - aceleração linear, aceleração angular e multiplicando-as pelo tempo - o deslocamento da posição do robô.



robot_x_pos = robot_x_pos + robot_x_vel * dtime;
robot_y_pos = robot_y_pos + robot_y_vel * dtime;
      
      





Em seguida, é enviada a mensagem da odometria, mais uma tradução tf entre o quadro da odometria e a base.



O controlador de entrada é controlado por um pacote com 2 parâmetros - velocidade e giro, o pacote é traduzido do giro quase nativamente - a velocidade é dividida pela circunferência e giros são obtidos.



double v = vel.linear.x;
double rps = v / rpm_per_meter;
double rpm = rps * 60;
int16_t speed = static_cast(rpm);

      
      





e a aceleração angular é convertida na diferença nas velocidades das rodas na forma de multiplicação por um coeficiente, novo cálculo será adicionado levando em consideração a distância entre eixos, mas na prática isso só é necessário para robôs suficientemente grandes e pesados.



double w = vel.angular.z;
int16_t steer = static_cast<int>(-1 * w * 30);

      
      





Como resultado, foi possível obter um controle muito estável do carrinho com componentes baratos.







Criamos robôs, como a grande maioria de vocês. Temos nosso principal produto, que estamos desenvolvendo ativamente. Piloto testado e pronto para produção. Este é um robô para coletar bolas de golfe.



Desenvolvemos robôs personalizados e soluções derivadas. Às vezes, é um trabalho desde a especificação técnica e esboço até o produto acabado, às vezes faz parte do trabalho.







Na maioria dos casos, o robô precisa de rodas para interagir com o mundo exterior. Na maioria das vezes, são motores sem escova, devido à capacidade de controlar com precisão a velocidade e a posição.



Para pequenos robôs, as rodas de um giroscópio são frequentemente utilizadas, isso se justifica devido à produção em massa e ao preço desta solução. Qualquer pessoa que tenha visto a lista de preços dos motores russos entende a importância da produção em massa.







Quanto ao controlador, na maioria das vezes são os modelos esc, vesc, odrive, BLD-300B ou soluções próprias.



Para facilitar a criação de robôs reais e quebrar a maldição Gazebo, a maioria dos desenvolvedores precisa de uma baleia para uma entrada fácil. Muito no mundo real é diferente do ideal.



Às vezes acontecem coisas imprevisíveis, os sensores são barulhentos, em tempo real, estouros de buffer. Neste vídeo, o dispositivo que testamos anteriormente com um contator e um kilswitch remoto.





Oferecemos algo que nos ajudaria a poupar nervos em devido tempo, trata-se de um kit de montagem de maleta (paralelepípedo e cilindro), duas rodas motrizes, uma bateria, um carregador e um controlador de flash que dá odometria e funciona com nosso pacote ROS pronto para 19.000 fricção. É mais barato do que o corte por fresamento, o custo de material composto, fixadores e uma roda giratória almofadada.







Ligue para nós ou inscreva-se para uma plataforma de ROS online . Vamos fazer robôs juntos. Falaremos



mais sobre a plataforma no encontro do Robot Operating System em 5 de dezembro. As inscrições para participantes já estão abertas.



→ Registro para visualizadores



All Articles