Продолжение цикла статей о создании небольшого робота. В этот раз речь пойдет о создании копии робота в симуляции, которую предлагают визуальные ROS-среды rviz и gazebo (далее «редакторы»). Работа в редакторах будет вестись на виртуальной машине, образ которой был ранее предоставлен для скачивания (образ). Так как речь идет о симуляции, построении модели, сам робот-тележка не понадобится.



Предыдущие посты серии:

1. Часть 3
2. Часть 2
3. Часть 1

Создание базовых urdf-файлов

Вообще, процесс создания робота упрощенно состоит как правило из следующих стадий:

1. Создание модели робота.
2. Тестирование модели в симуляции.
3. Создание реальной модели робота.
4. Тестирование реальной модели.

Работая с редакторами ROS, которые предоставляют шикарные возможности как по построению моделей и их тестам в виртуальном мире, надо признать, что реальные модели роботов ведут себя не всегда аналогично своим бестелесным братьям. И здесь время на работу с моделями в виртуальном мире складывается со временем, необходимым на доработку реальной модели.
Такое дарение времени, как говорил один известный человек, могут себе позволить не только лишь все.

В связи с этим, в предыдущих постах была нарушена последовательность роботостроения: сначала была создана реальная модель робота. Теперь же речь пойдет о ее виртуализации, так сказать.

Создаем urdf


Для того, чтобы в полной мере насладиться симуляцией в Gazebo и протестировать робота, сперва необходимо создать URDF файл для робота.

URDF файл является своеобразным каркасом-скелетом в области визуализации.
Проще говоря, URDF файл — это файл, описывающий робота.

Как ранее было заявлено, работа будет вестись с использованием образа VMWARE Workstation, на котором уже установлена ROS(Ubuntu 16.04, ROS-Kinetic) и визуальные редакторы. Поэтому все действия воспроизводимы в данной системе.

Создадим пакет ROS с названием rosbots_description.

Для того, чтобы это сделать надо войти в папку с catkin_ws/src и выполнить команду создания пакета в ROS:

roscd; cd ..; cd src;
catkin_create_pkg rosbots_description rospy

*Если при выполнении команды roscd; cd ..; cd src; вы не попали в catkin_ws, то возможно у вас несколько сред подобного типа. Для того, чтобы активировать нужную, необходимо зайти в папку catkin_ws и выполнить команду: source devel/setup.bash. Чтобы не заблудиться, если вы работаете с образом, в эту папку можно попасть из корня: cd ~; cd catkin_ws.

Если все прошло успешно, то создастся папка rosbots_description.

Почему так сложно и не проще ли просто создать папку в catkin_ws/src вручную? И что там за rospy?

Вручную создать папку можно, но придется также вручную писать еще два файла, с которыми работает ROS: CMakeLists.txt и package.xml.

Именно они присутствуют в папке после создания:



Их ROS создает самостоятельно. Пока на их содержимом останавливаться не будем.
rospy в конце команды означает создание зависимости, поддержку python.

Движемся дальше.

Внутри вновь созданного пакета rosbots_description создадим папку urdf, а в ней — файл rosbots.xacro.

roscd rosbots_description

mkdir urdf; cd urdf;

touch rosbots.xacro

chmod +x rosbots.xacro

Прелесть системы ROS в том, что в какой папке системы вы бы не находились, можно сразу попасть в целевую, просто набрав ее название с командой roscd в начале строки.

Теперь поместим во вновь созданный файл следующий код:

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>


Если код не отображается, то все файлы можно скачать в конце поста.

Для кода выше нам также понадобятся ячейки (meches), которые будут подгружаться в процессе запуска пакета.

Meches можно взять здесь
и положить распакованную папку meches в rosbots_description.

Если посмотреть код детально, то можно выяснить, что это стандартный файл xml, состоящий из блоков:
— visual
— collision
— inertial

Каждый блок описывает свою часть: visual — это внешность робота, не более, collision и inertial — это физика робота, как все будет взаимодействовать с внешним миром — столкновения, инерция.
joints — элементы, которые помогают определить движение между частями робота (links). Так например, движение колеса (wheel) влияет на раму в целом (chasis).

origin xyz — это первоначальное расположение объекта по осям x,y,z.

parent link и child link это соответственно родительская и дочерняя связи, что из чего растет.
Также примечательно наличие типов: type=«continuous», type=«fixed». Это определение того, что может вращаться, а что нет. Так колеса имеют тип continuous. А, например, batery_joint — fixed.
Отступы в коде такого же глубоко смысла как в python, где нельзя мешать табы и пробелы, не несут. Но для рая перфекциониста и наглядности лучше их иметь.

Код приведенный выше является по сути моделью робота.

Работа в rviz


Посмотрим что вышло.

Для этого надо создать файл запуска, который будет запускать пакет ROS.

Для этого в ROS служат так называемые launch файлы. Суть launch файла — позволить запустить ноду, команду или несколько нод одной короткой командой без необходимости указывать в ней все аргументы и прочая.

Создадим в rosbots_description папку launch с файлом rviz.launch:

roscd rosbots_description
mkdir launch; cd launch;
touch rviz.launch

*В этот и последующие разы уже нет необходимости создавать ROS-пакет как это делалось ранее. Теперь система сама будет «видеть» файлы внутри пакета. Поэтому мы просто создаем директорию.

Наполним файл содержимым —
rviz.launch
 <?xml version="1.0"?>
<launch>
   <param name="robot_description" command="cat '$(find rosbots_description)/urdf/rosbots.xacro'"/>
   <!-- send fake joint values -->
  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
    <param name="use_gui" value="False"/>
  </node>
   <!-- Combine joint values -->
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher"/>
   <!-- Show in Rviz   -->
  <node name="rviz" pkg="rviz" type="rviz" /> 
</launch>


Здесь видно, что при запуске система будет искать описание модели в rosbots.xacro.

Далее запустит 3-и ноды: joint_state_publisher из пакета joint_state_publisher, robot_state_publisher из robot_state_publisher, rviz из rviz. type -это тип ноды, как правило соответствует одноименному Python или С файлу, но указывается без расширения.

Запустим:

В 1-м терминале запустим ROS-мастер:

roscore

Во 2-м:

roslaunch rosbots_description rviz.launch

*Если выдало ошибку
ROS_MASTER_URI [http://192.168.1....:11311] host is not set to this machine
, то надо проверить bashrc — на каком ip запускается ROS:

nano ~/.bashrc

в самом файле bashrc указать ip виртуальной машины (например, такой):

export ROS_MASTER_URI=http://192.168.1.114:11311

далее перечитать bashrc:

source ~/.bashrc или перезагрузиться.
**
Если roslaunch все равно не запускается, то можно попробовать зайти в папку catkin_ws и выполнить: source devel/setup.bash

Погружаемся в Rviz


После выполнения команды, запустится Rviz-редактор и откроется графическая оболочка.
Визуальное представление может отличаться, но в целом вид будет примерно следующим:



Слева в колонке Displays можно наблюдать опции отображения тех или иных элементов, взаимодействующих с нодами ROS, по центру — изображение робота, справа — колонка с камерой вида робота. Сразу надо сказать, что с rviz лучше работать с 3-х колесной мышью, так как все кнопки мыши здесь задействованы. Зажав левую можно повращать пространство в окне с отображением робота, зажав правую — приблизить/отдалить, зажав обе клавиши — перемещать пространство относительно робота.

В основном работа в редакторе ведется в первых двух колонках: Displays и Визуальном представлении робота.

Поработаем с видом робота


Выберем в строке «Fixed Frame» — «base link»:



И добавим Robot Description в Displays:

Нажмем «Add» и в списке выберем «RobotModel»:

"

Теперь в окне симуляции можно наблюдать робота, который был воспроизведен из модели rviz.xacro:

"

Отлично. С визуальным представлением все ясно. Теперь необходимо понять как запустить симуляцию, потому как rviz лишь визуализация симуляции, но не сама симуляция.
То есть физика здесь не работает.

Сама симуляция живет в редакторе под названием Gazebo.

Gazebo


Чтобы поместить созданную модель в Gazebo, создадим еще один launch файл — spawn.launch в папке launch проекта. Теперь у нас 2 launch файла!

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>


Здесь мы также считываем модель, затем аргументами передаем ее расположение в пространстве по осям x,y,z. Далее запускаем всего лишь одну ноду — mybot_spawn из пакета gazebo_ros.
*Доустанавливать пакеты, упомянутые выше нет необходимости. При желании можно посмотреть на эти пакеты все той же командой: roscd. Например roscd gazebo_ros.

Теперь остановим Ros-мастер в 1-м терминале:

CTRL+C

И запустим редактор Gazebo:

roslaunch gazebo_ros empty_world.launch

Во 2-м терминале запустим вновь созданный файл:

roslaunch rosbots_description spawn.launch

Теперь мы видим нашего робота в симуляции редактора Gazebo:



*Если у вас ошибка: Waiting for service /gazebo/spawn_urdf_model
Это значит, что вы запустили модель без предварительного запуска Gazebo, нарушив очередность запуска.

Поездим в симуляции gazebo.


Теперь добавим в rosbots.xacro следующий код до закрывающего тега :

код
<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>


Симулятор Gazebo можно не закрывать при правках.

Теперь удалим модель из редактора Gazebo:

rosservice call /gazebo/delete_model "model_name: 'rosbots'"

либо просто перезагрузим редактор.

*Gazebo капризный на виртуальной машине, поэтому даже после закрытия иногда простит CTRL+C дополнительно в терминале.

Заново разместим модель в Gazebo после правок:

roslaunch rosbots_description spawn.launch

Если теперь посмотреть список топиков ROS, то можно увидеть, что среди них есть и

/part2_cmr/cmd_vel



Теперь попробуем поуправлять роботом в симуляции, запустив управление в отдельном терминале:

rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/part2_cmr/cmd_vel

Находясь в окне с запущенным управлением и нажимая в окне терминала клавиши «i»,«l»,«j»,«k»,"," можно наблюдать движение робота в симуляции редактора Gazebo:



Код — скачать.

Продолжение следует.

Комментарии (0)