Skip to content

MDK: Advanced Features

Introduction

Here you will learn some of the more advanced features of the MDK that will help you in development of your biomimetic project. You can treat page as an updating FAQ, as not every team will need to learn every topic on this page.

Gazebo and ROS bridge

So far, we have covered how to control MiRo in the simulation using the MDK interface. You might also remember from COM1005 and COM2009 how to manipulate other objects via the Gazebo GUI. However, in some scenarios it may be required to control other objects in the environment programmatically, for example in order to implement dynamic objects. In such cases, it is useful to launch Gazebo with a running ROS Bridge. The ROS Bridge in Gazebo is part of the API that lets the user control the simulator directly through ROS topics, as seen on the screenshot below.

Gazebo ROS Bridge

In order to start Gazebo with an exposed ROS bridge use the ./launch_full.sh script inside the ~/mdk/sim

Example: moving the toy ball programmatically

You can see how having access to Gazebo-ROS bridge can be used in practice by running the following code:

roslaunch com3528_examples sim_move_ball.launch

Moving Ball

In this example, a dedicated ROS node, called ball_mover, subscribes to the /set_model_state topic (as seen above) and then changes the pose of the MiRo's toy ball, to make it oscillate in front of MiRo.

The node's source code is located at com3528_examples/scripts/ball_mover.py, if you want to inspect it in more detail.

Roslaunch file structure in MDK

It is useful to have a look at a typical launch file in more detail, as there are some parameters that haven't been covered in COM2009. The following are snippets from sim_move_ball.launch.

  1. Since some of the assets in MDK live in their own dedicated folder, it is necessary to inform ROS where those assets are. One of the easiest ways of doing this is to set up the paths as environment variables inside the launch file:
<!-- Add custom Gazebo paths -->
<env name="GAZEBO_MODEL_PATH"
    value="$(find com3528_examples)/models:$(optenv MIRO_DIR_MDK)/sim/models:$(optenv GAZEBO_MODEL_PATH)" />
<env name="GAZEBO_RESOURCE_PATH"
    value="$(optenv MIRO_DIR_MDK)/sim:$(optenv GAZEBO_RESOURCE_PATH)" />
<env name="GAZEBO_PLUGIN_PATH"
    value="$(optenv MIRO_DIR_MDK)/bin/${MIRO_SYSTEM}:$(optenv GAZEBO_PLUGIN_PATH)" />
  1. In order to tell Gazebo which world to load, a special argument needs to be set that would find the world file by its name in the dedicated worlds folder:
<!-- Specify which .world file to load -->
<arg name="world" default="$(optenv MIRO_DIR_MDK)/sim/worlds/miro.world"/>
  1. The rest should be familiar, but it is important to note that here the Gazebo server and the Gazebo GUI client are loaded separately; such setup provides more flexibility and robustness.

Note

All the Gazebo topics in such setup are prefixed with a namespace that can be set manually.

<!-- Set the name for Gazebo -->
<arg name="gazebo_ns" default="gazebo_server" doc="Gazebo namespace, typically 'gazebo' or 'gazebo_server'" />
<!-- start Gazebo server with exposed ROS interface-->
<node name="$(arg gazebo_ns)"
    pkg="gazebo_ros"
    type="gzserver"
    respawn="false"
    required="true"
    args="--physics ode --verbose $(arg world)"
/>
<!-- Start Gazebo client -->
<node name="gazebo_gui"
    pkg="gazebo_ros"
    type="gzclient"
    respawn="true"
/>

Controlling multiple MiRos in simulation

In some projects you will need to control more than one MiRo in simulation. This section will explain how to do this with the help of roslaunch files and ROS namespaces. The COM3528 examples repo has a template launch file for this purpose, called sim_football.launch. Launching this file will start Gazebo with three MiRos placed on the football pitch, with the MiRos named sequentially as miro01, miro02 and miro03. The relevant snippet from the football_pitch.world is given below```xml

<include>
  <name>miro01</name>
  <uri>model://miro_model</uri>
  <pose>0 0 0 0 0 0</pose>
</include>

<include>
  <name>miro02</name>
  <uri>model://miro_model</uri>
  <pose>-0.5 0.2 0.05 0 0 0.5</pose>
</include>

<include>
  <name>miro03</name>
  <uri>model://miro_model</uri>
  <pose>0.5 0.2 0.05 0 0 -0.5</pose>
</include>

Once the world loads, the kick_blue_ball.py script will launch to control each MiRo independently. This is gonna get messy! 😀

So how is this done? Let's have a look at the relevant part of sim_football.launch:

<!-- MiRo1 behaviour -->
<env name="MIRO_ROBOT_NAME" value="miro01" />
<node ns="miro01" name="kick_blue_ball_01" pkg="com3528_examples" type="kick_blue_ball.py" />

<!-- MiRo2 behaviour -->
<env name="MIRO_ROBOT_NAME" value="miro02" />
<node ns="miro02" name="kick_blue_ball_02" pkg="com3528_examples" type="kick_blue_ball.py" />

<!-- MiRo3 behaviour -->
<env name="MIRO_ROBOT_NAME" value="miro03" />
<node ns="miro03" name="kick_blue_ball_03" pkg="com3528_examples" type="kick_blue_ball.py" />

The key principle here is to temporarily change the value of the MIRO_ROBOT_NAME environment variable using the <env> tag and feed that value to the kick_blue_ball.py node. Recall that we use that robot's name in the script's initialisation

# Individual robot name acts as ROS topic prefix
topic_base_name = "/" + os.getenv("MIRO_ROBOT_NAME")

and thus we can separate the three MiRos into distinct namespaces. Now run rostopic list to check how the topics look like in this case.

Note

All you have to remember in such a setting is to prefix all the topics for your publishers and subscribers with the correct MiRo name.

MiRo Bridge Flags

MiRo bridge allows the user to change certain flags that are linked to the various features on-board MiRo and in the simulator. These includes features such as blinking the LEDs to identify errors in MiRo's control board, disabling the cliff reflex or even translational movement in the MiRo. A list of all the flags can be found in the ~/mdk/share/python/miro2/constants.py. We provided a small utility, located in nodes/publisher_flags.py that can be used to disable the following common flags:

Flag Constant Variable to Disable
Disabling Status LED miro.constants.PLATFORM_D_FLAG_DISABLE_STATUS_LEDS
Disabling Speakers miro.constants.PLATFORM_D_FLAG_DISABLE_SPEAKER
Disabling Wheel Control miro.constants.PLATFORM_D_FLAG_DISABLE_WHEEL_CONTROL
Disabling Opto (Feedback) miro.constants.PLATFORM_D_FLAG_DISABLE_OPTO
Disabling Servo Power miro.constants.PLATFORM_D_FLAG_DISABLE_SERVO_POWER
Disabling I2C Fail Warn miro.constants.PLATFORM_D_FLAG_DISABLE_I2C_FAIL_WARN
Disabling Cliff Reflex miro.constants.PLATFORM_D_FLAG_DISABLE_CLIFF_REFLEX
Disabling Kinematic Idle miro.constants.PLATFORM_D_FLAG_DISABLE_KIN_IDLE
Disabling Translation miro.constants.PLATFORM_D_FLAG_DISABLE_TRANSLATION

=====

This completes the tutorial for the Week 3 lab session.