Posts da série:
8. Nós controlamos a partir do telefone-ROS Control, GPS-node7. Localização do robô: gmapping, AMCL, pontos de referência no mapa da sala6. Odometria com codificadores de roda, mapa da sala, lidar5. Trabalhamos em rviz e gazebo: xacro, novos sensores.4. Crie uma simulação de robô usando os editores rviz e gazebo.3. Acelere, troque a câmera, conserte a marcha2. Software1. FerroContinuação de uma série de artigos sobre a criação de um pequeno robô. Desta vez, vamos nos concentrar na criação de uma cópia do robô na simulação, oferecida pelos ambientes ROS visuais rviz e gazebo (doravante denominados "editores"). O trabalho nos editores será realizado em uma máquina virtual, cuja imagem foi fornecida anteriormente para o download da
imagem . Como estamos falando de simulação, construção de um modelo, o carrinho de robô em si não é necessário.

Postagens anteriores da série:
1.
Parte 32.
Parte 23.
Parte 1Criando arquivos urdf básicos
Em geral, o processo de criação de um robô de maneira simplificada geralmente consiste nos seguintes estágios:
1. Criando um modelo de robô.
2. Testando o modelo em uma simulação.
3. Criando um modelo de robô real.
4. Testando um modelo real.
Ao trabalhar com editores de ROS, que oferecem grandes oportunidades para a construção de modelos e seus testes no mundo virtual, devemos admitir que modelos de robôs reais nem sempre se comportam como seus irmãos incorpóreos. E aqui o tempo para trabalhar com modelos no mundo virtual é adicionado ao tempo necessário para finalizar o modelo real.
Tal presente de tempo, como disse uma pessoa famosa, não pode apenas pagar tudo.
Nesse sentido, em posts anteriores, a sequência da robótica foi interrompida: primeiro, um modelo real do robô foi criado. Agora vamos falar sobre sua virtualização, por assim dizer.
Criar urdf
Para aproveitar totalmente a simulação no Gazebo e testar o robô, você deve primeiro criar um arquivo URDF para o robô.
O arquivo URDF é um tipo de esqueleto no campo da visualização.
Simplificando, um arquivo URDF é um arquivo que descreve um robô.
Como mencionado anteriormente, o trabalho será realizado usando a imagem VMWARE Workstation na qual o ROS (Ubuntu 16.04, ROS-Kinetic) e os editores visuais já estão instalados. Portanto, todas as ações são reproduzíveis neste sistema.
Crie um pacote ROS chamado rosbots_description.
Para fazer isso, você precisa inserir a pasta com catkin_ws / src e executar o comando para criar o pacote no ROS:
roscd; cd ..; cd src; catkin_create_pkg rosbots_description rospy
* Se ao executar o comando roscd; cd ..; cd src; Se você não gosta de catkin_ws, talvez tenha vários ambientes desse tipo. Para ativar o necessário, vá para a pasta catkin_ws e execute o comando: source devel / setup.bash. Para não se perder, se você estiver trabalhando com uma imagem, é possível acessar esta pasta a partir da raiz: cd ~; cd catkin_ws.
Se tudo correu bem, a pasta rosbots_description será criada.
Por que é tão difícil e não mais fácil criar uma pasta no catkin_ws / src manualmente? E que tipo de rosado é esse?
Você pode criar manualmente uma pasta, mas também precisará gravar manualmente mais dois arquivos com os quais o ROS trabalha: CMakeLists.txt e package.xml.
Eles estão presentes na pasta após a criação:

O ROS deles cria por conta própria. Enquanto não vamos nos debruçar sobre o seu conteúdo.
rospy no final do comando significa criar dependências, suportando python.
Seguindo em frente.
Dentro do pacote rosbots_description recém-criado, crie a pasta urdf e nele o arquivo rosbots.xacro.
roscd rosbots_description mkdir urdf; cd urdf; touch rosbots.xacro chmod +x rosbots.xacro
A beleza do sistema ROS é que, em qual pasta do sistema você não estaria localizado, você pode chegar imediatamente ao destino digitando simplesmente seu nome com o comando roscd no início da linha.
Agora coloque o seguinte código no arquivo recém-criado:
rosbots.xacro <?xml version="1.0" encoding="utf-8"?> <robot name="rosbots" xmlns:xacro="http://www.ros.org/wiki/xacro"> <link name="base_footprint"/> <joint name="base_joint" type="fixed"> <origin xyz="0 0 0.05" rpy="0 0 0" /> <parent link="base_footprint"/> <child link="base_link" /> </joint> <link name="base_link"> <visual> <geometry> <mesh filename="package://rosbots_description/meshes/base.dae"/> </geometry> <origin xyz="-0.52 -0.4 0.43" rpy="0 0 0"/> </visual> <collision> <geometry> <mesh filename="package://rosbots_description/meshes/base.dae"/> </geometry> <origin xyz="-0.52 -0.4 0.43" rpy="0 0 0"/> </collision> <inertial> <origin xyz="0.0 0 0."/> <mass value="0.5"/> <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.03" /> </inertial> </link> <joint name="second_level_joint" type="fixed"> <origin xyz="0 0 0.68" rpy="0 0 0" /> <parent link="base_link"/> <child link="base_second_link" /> </joint> <link name="base_second_link"> <visual> <geometry> <mesh filename="package://rosbots_description/meshes/base.dae"/> </geometry> <origin xyz="-0.52 -0.4 0.0" rpy="0 0 0"/> </visual> <collision> <geometry> <mesh filename="package://rosbots_description/meshes/base.dae"/> </geometry> <origin xyz="-0.52 -0.4 0.0" rpy="0 0 0"/> </collision> <!--inertial> <origin xyz="0.01 0 0.7"/> <mass value="1.0"/> <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.03" /> </inertial--> </link> <joint name="mcu_joint" type="fixed"> <origin xyz="0.02 0.12 0.73" rpy="0 0 0" /> <parent link="base_link"/> <child link="mcu_link" /> </joint> <link name="mcu_link"> <visual> <geometry> <mesh filename="package://rosbots_description/meshes/rasp.dae" scale="0.14 0.14 0.14"/> </geometry> <origin xyz="0.9 -1.25 0" rpy="0 0 1.57"/> </visual> <collision> <geometry> <mesh filename="package://rosbots_description/meshes/rasp.dae" scale="0.14 0.14 0.14"/> </geometry> <origin xyz="0.9 -1.25 0" rpy="0 0 1.57"/> </collision> <!-- inertial> <origin xyz="0.01 0 0"/> <mass value="1.0"/> <inertia ixx="0.019995" ixy="0.0" ixz="0.0" iyy="0.019995" iyz="0.0" izz="0.03675" /> </inertial--> </link> <joint name="mcu_joint_1" type="fixed"> <origin xyz="0.02 0.12 0.83" rpy="0 0 0" /> <parent link="base_link"/> <child link="mcu_link_1" /> </joint> <link name="mcu_link_1"> <visual> <geometry> <mesh filename="package://rosbots_description/meshes/rasp.dae" scale="0.14 0.14 0.14"/> </geometry> <origin xyz="0.9 -1.25 0" rpy="0 0 1.57"/> </visual> <collision> <geometry> <mesh filename="package://rosbots_description/meshes/rasp.dae" scale="0.14 0.14 0.14"/> </geometry> <origin xyz="0.9 -1.25 0" rpy="0 0 1.57"/> </collision> <!-- inertial> <origin xyz="0.01 0 0"/> <mass value="1.0"/> <inertia ixx="0.019995" ixy="0.0" ixz="0.0" iyy="0.019995" iyz="0.0" izz="0.03675" /> </inertial--> </link> <joint name="stand_mcu1_joint" type="fixed"> <origin xyz="0.02 0.25 0.78" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_mcu1_link" /> </joint> <link name="stand_mcu1_link"> <visual> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> <joint name="stand_mcu2_joint" type="fixed"> <origin xyz="0.02 -0.1125 0.78" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_mcu2_link" /> </joint> <link name="stand_mcu2_link"> <visual> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> <joint name="stand_mcu3_joint" type="fixed"> <origin xyz="0.25 0.25 0.78" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_mcu3_link" /> </joint> <link name="stand_mcu3_link"> <visual> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> <joint name="stand_mcu4_joint" type="fixed"> <origin xyz="0.25 -0.1125 0.78" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_mcu4_link" /> </joint> <link name="stand_mcu4_link"> <visual> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.1" radius="0.01"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> <joint name="batery_joint" type="fixed"> <origin xyz="1.2 0.2 0.43" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="batery_link" /> </joint> <link name="batery_link"> <visual> <geometry> <mesh filename="package://rosbots_description/meshes/battery.dae" scale="13.0 6.0 6.0"/> </geometry> <origin xyz="0 4.5 0.05" rpy="1.57 0 1.57"/> </visual> <collision> <geometry> <mesh filename="package://rosbots_description/meshes/battery.dae" scale="13.0 6.0 6.0"/> </geometry> <origin xyz="0 4.5 0.05" rpy="1.57 0 1.57"/> </collision> <!-- inertial> <origin xyz="0.01 0 0"/> <mass value="1.0"/> <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.03" /> </inertial--> </link> <joint name="stand_1_joint" type="fixed"> <origin xyz="0.5 0.4125 0.58" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_1_link" /> </joint> <link name="stand_1_link"> <visual> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> <!--inertial> <origin xyz="0.0 0 0"/> <mass value="1.0"/> <inertia ixx="0.019995" ixy="0.0" ixz="0.0" iyy="0.019995" iyz="0.0" izz="0.03675" /> </inertial--> </link> <joint name="stand_2_joint" type="fixed"> <origin xyz="0.5 -0.2625 0.58" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_2_link" /> </joint> <link name="stand_2_link"> <visual> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> <!--inertial> <origin xyz="0.0 0 0"/> <mass value="1.0"/> <inertia ixx="0.019995" ixy="0.0" ixz="0.0" iyy="0.019995" iyz="0.0" izz="0.03675" /> </inertial--> </link> <joint name="wheel_left_joint" type="continuous"> <parent link="base_link"/> <child link="wheel_left_link"/> <origin xyz="0.15 0.4125 0.30" rpy="-1.57 0 0"/> <axis xyz="0 0 1"/> </joint> <link name="wheel_left_link"> <collision> <geometry> <cylinder length="0.20" radius="0.23"/> </geometry> <origin rpy="0.0 0.0 0" xyz="0 0 0.1"/> </collision> <visual name="visual"> <geometry> <!-- cylinder length="0.0206" radius="0.0550"/--> <!--cylinder length="0.20" radius="0.26"/--> <mesh filename="package://rosbots_description/meshes/wheel.dae" scale="8.0 8.0 8.0"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0"/> </visual> <inertial> <mass value="0.4" /> <origin xyz="0 0 0" /> <inertia ixx="0.001" ixy="0.0" ixz="0.0" iyy="0.001" iyz="0.0" izz="0.001" /> </inertial> </link> <joint name="wheel_right_joint" type="continuous"> <parent link="base_link"/> <child link="wheel_right_link"/> <origin xyz="0.15 -0.5625 0.30" rpy="-1.57 0 0"/> <axis xyz="0 0 1"/> </joint> <link name="wheel_right_link"> <collision> <geometry> <cylinder length="0.20" radius="0.23"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.195"/> </collision> <visual name="visual"> <geometry> <!--cylinder length="0.20" radius="0.26"/--> <mesh filename="package://rosbots_description/meshes/wheel.dae" scale="8.0 8.0 8.0"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0"/> </visual> <inertial> <mass value="0.4" /> <origin xyz="0 0.0 0.3" /> <inertia ixx="0.001" ixy="0.0" ixz="0.0" iyy="0.001" iyz="0.0" izz="0.001" /> </inertial> </link> <joint name="caster_back_joint" type="fixed"> <parent link="base_link"/> <child link="caster_back_link"/> <origin xyz="-0.4 0.1 0.26" rpy="0 0 0"/> </joint> <link name="caster_back_link"> <collision> <geometry> <!-- cylinder length="0.05" radius="0.19"/--> <sphere radius="0.19"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0"/> </collision> <visual> <geometry> <!--cylinder length="0.05" radius="0.19"/--> <sphere radius="0.19"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0"/> </visual> <inertial> <mass value="0.1" /> <origin xyz="0 0 0" /> <inertia ixx="0.001023539" ixy="0.0" ixz="0.0" iyy="0.001023539" iyz="0.0" izz="0.001023539" /> </inertial> </link> <joint name="stand_3_joint" type="fixed"> <origin xyz="-0.4 0.4125 0.58" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_3_link" /> </joint> <link name="stand_3_link"> <visual> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> <joint name="stand_4_joint" type="fixed"> <origin xyz="-0.4 -0.2625 0.58" rpy="0 0 1.57" /> <parent link="base_link"/> <child link="stand_4_link" /> </joint> <link name="stand_4_link"> <visual> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </visual> <collision> <geometry> <cylinder length="0.20" radius="0.03"/> </geometry> <origin rpy="0.0 0 0" xyz="0 0 0.0"/> </collision> </link> </robot>
Se o código não aparecer, todos os arquivos poderão ser baixados no final da postagem.
Para o código acima, também precisamos de células (meches), que serão carregadas durante o lançamento do pacote.
Meches pode ser tomado
aquie coloque a pasta meches descompactada em rosbots_description.
Se você olhar o código em detalhes, poderá descobrir que este é um arquivo xml padrão que consiste em blocos:
- visual
- colisão
- inercial
Cada bloco descreve sua parte: visual é a aparência do robô, nada mais, colisão e inercial é a física do robô, como tudo irá interagir com o mundo exterior - colisões, inércia.
juntas - elementos que ajudam a determinar o movimento entre as partes do robô (links). Por exemplo, o movimento da roda (roda) afeta o quadro como um todo (chassi).
origem xyz é a localização inicial do objeto ao longo dos eixos x, y, z.
o link pai e o link filho são os links pai e filho, respectivamente, que crescem a partir do quê.
A presença de tipos também é digna de nota: type = "contínuo", tipo = "fixo". Esta é uma definição do que pode e não pode girar. Então as rodas são contínuas. E, por exemplo, batery_joint é fixo.
A indentação no código é tão profundamente significativa quanto em python, onde você não pode interferir com guias e espaços, não carrega. Mas para o paraíso e a visibilidade de um perfeccionista, é melhor tê-los.
O código acima é essencialmente um modelo de robô.
Trabalhe na rviz
Vamos ver o que aconteceu.
Para fazer isso, crie um arquivo de inicialização que executará o pacote ROS.
Para isso, os chamados arquivos de inicialização são usados no ROS. A essência do arquivo de inicialização é permitir o lançamento de um nó, comando ou vários nós com um comando curto, sem a necessidade de especificar todos os argumentos e outros nele.
Crie uma pasta de inicialização na rosbots_description com o arquivo rviz.launch:
roscd rosbots_description mkdir launch; cd launch; touch rviz.launch
* Este e os tempos subsequentes, não há mais a necessidade de criar um pacote ROS, como foi feito anteriormente. Agora, o próprio sistema "verá" os arquivos dentro do pacote. Portanto, apenas criamos um diretório.
Preencha o arquivo com o conteúdo -
rviz.launch <?xml version="1.0"?> <launch> <param name="robot_description" command="cat '$(find rosbots_description)/urdf/rosbots.xacro'"/> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher"> <param name="use_gui" value="False"/> </node> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher"/> <node name="rviz" pkg="rviz" type="rviz" /> </launch>
Aqui você pode ver que, na inicialização, o sistema procurará uma descrição do modelo em rosbots.xacro.
A seguir, serão lançados 3 nós: joint_state_publisher do pacote joint_state_publisher, robot_state_publisher de robot_state_publisher, rviz de rviz. type é o tipo de nó, geralmente corresponde ao arquivo Python ou C com o mesmo nome, mas é especificado sem uma extensão.
Execute:
No 1º terminal, execute o mestre do ROS:
roscore
No segundo:
roslaunch rosbots_description rviz.launch
* Se ocorreu um erro
O host ROS_MASTER_URI [http: //192.168.1 ....: 11311] não está definido para esta máquina
, verifique o bashrc - no qual o ROS IP está sendo executado:
nano ~/.bashrc
especifique o ip da máquina virtual no próprio arquivo bashrc (por exemplo, este):
export ROS_MASTER_URI=http://192.168.1.114:11311
leia novamente o bashrc:
source ~/.bashrc
ou reinicialize.
**
Se o roslaunch ainda não iniciar, você pode tentar ir para a pasta catkin_ws e executar: source devel / setup.bash
Mergulhando em Rviz
Após a execução do comando, o editor Rviz é iniciado e o shell gráfico é aberto.
A apresentação visual pode variar, mas em geral a visualização será aproximadamente da seguinte maneira:

À esquerda na coluna Monitores, é possível observar as opções de exibição de vários elementos que interagem com os nós ROS, no centro - a imagem do robô à direita - uma coluna com uma visão da câmera do robô. Devo dizer imediatamente que é melhor trabalhar com um mouse de 3 rodas com rviz, pois todos os botões do mouse estão envolvidos aqui. Mantendo a esquerda pressionada, você pode girar o espaço na janela com o robô exibido, mantendo pressionada a direita - aumentar / diminuir o zoom, mantendo as duas teclas - mover o espaço em relação ao robô.
A maior parte do trabalho no editor é realizada nas duas primeiras colunas: Monitores e a representação visual do robô.
Vamos trabalhar com a aparência de um robô
Vamos selecionar "Quadro fixo" - "link base" na linha:

E adicione a descrição do robô aos displays:
Clique em "Adicionar" e selecione "RobotModel" na lista:

"
Agora, na janela de simulação, você pode observar o robô que foi reproduzido a partir do modelo rviz.xacro:

"
Ótimo. Com uma representação visual, tudo está claro. Agora você precisa entender como executar a simulação, porque o rviz é apenas uma
visualização da simulação, mas não a simulação em si.
Ou seja, a física não funciona aqui.
A simulação em si vive em um editor chamado Gazebo.
Gazebo
Para colocar o modelo criado no Gazebo, crie outro arquivo de inicialização - spawn.launch na pasta de inicialização do projeto. Agora temos 2 arquivos de lançamento!
spawn.launch <?xml version="1.0" encoding="UTF-8"?> <launch> <param name="robot_description" command="cat '$(find rosbots_description)/urdf/rosbots.xacro'" /> <arg name="x" default="0"/> <arg name="y" default="0"/> <arg name="z" default="0.5"/> <node name="mybot_spawn" pkg="gazebo_ros" type="spawn_model" output="screen" args="-urdf -param robot_description -model rosbots -x $(arg x) -y $(arg y) -z $(arg z)" /> </launch>
Aqui também lemos o modelo, depois com argumentos passamos sua localização no espaço ao longo dos eixos x, y, z. Em seguida, execute apenas um nó - mybot_spawn no pacote gazebo_ros.
* Não há necessidade de reinstalar os pacotes mencionados acima. Se desejar, você pode olhar para esses pacotes com o mesmo comando: roscd. Por exemplo, roscd gazebo_ros.
Agora pare o Ros-master no terminal 1:
CTRL+C
E execute o editor Gazebo:
roslaunch gazebo_ros empty_world.launch
No terminal 2, execute o arquivo recém-criado:
roslaunch rosbots_description spawn.launch
Agora vemos nosso robô na simulação do editor Gazebo:

* Se você tiver um erro:
Waiting for service /gazebo/spawn_urdf_model
Isso significa que você lançou o modelo sem iniciar o Gazebo, violando a ordem de lançamento.
Vamos para a simulação do gazebo.
Agora adicione o seguinte código ao rosbots.xacro antes da tag de fechamento:
código <gazebo> <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so"> <legacyMode>false</legacyMode> <alwaysOn>true</alwaysOn> <publishWheelTF>true</publishWheelTF> <publishTf>1</publishTf> <publishWheelJointState>true</publishWheelJointState> <updateRate>100.0</updateRate> <leftJoint>wheel_left_joint</leftJoint> <rightJoint>wheel_right_joint</rightJoint> <wheelSeparation>1.1</wheelSeparation> <wheelDiameter>0.52</wheelDiameter> <wheelAcceleration>1.0</wheelAcceleration> <torque>20</torque> <commandTopic>/part2_cmr/cmd_vel</commandTopic> <odometryTopic>odom</odometryTopic> <odometryFrame>odom</odometryFrame> <robotBaseFrame>base_link</robotBaseFrame> </plugin> </gazebo>
O Simulator Gazebo não pode ser fechado durante a edição.
Agora exclua o modelo do editor Gazebo:
rosservice call /gazebo/delete_model "model_name: 'rosbots'"
Ou apenas reinicie o editor.
* O Gazebo é irritadiço em uma máquina virtual; portanto, mesmo depois de fechá-lo, às vezes perdoamos CTRL + C adicionalmente no terminal.
Substitua o modelo no Gazebo após a edição:
roslaunch rosbots_description spawn.launch
Se você agora examinar a lista de tópicos do ROS, poderá ver que, dentre eles, existem
/part2_cmr/cmd_vel

Agora vamos tentar controlar o robô na simulação executando o controle em um terminal separado:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/part2_cmr/cmd_vel
Estando na janela com o controle em execução e pressionando as teclas “i”, “l”, “j”, “k”, “,” na janela do terminal, é possível observar o movimento do robô na simulação do editor Gazebo:

Código -
download .
Para ser continuado.