The Gazebo GUI overlay can be thought of as a transparent 2D layer that sits
on top of the render window. QT widgets can be added to this layer through
a plugin interface. You can show or hide all GUI overlays by clicking on
View->GUI Overlays
on the main Gazebo menu bar. This tutorial describes how to
create and use GUI overlay plugins to create custom interfaces for Gazebo.
Two examples will be used to demonstrate the GUI Overlay functionality. The first example creates a button that spawns a sphere, and the second displays the current simulation time. These two examples show how to send data to Gazebo and receive data from Gazebo.
The source code for this example is found here.
Install the latest Gazebo version: follow the instructions of the install page
Start by creating a working directory
mkdir ~/gazebo_gui_spawn
cd ~/gazebo_gui_spawn
Download the source code for the GUI overlay plugin (On OsX, wget can be replaced with curl -OL)
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/GUIExampleSpawnWidget.hh
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/GUIExampleSpawnWidget.cc
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/CMakeLists.txt
Take a look at the header file.
gedit GUIExampleSpawnWidget.hh
A GUI overlay plugin must inherit from the GUIPlugin class, and use Qt's
Q_OBJECT
macro.class GAZEBO_VISIBLE GUIExampleSpawnWidget : public GUIPlugin { Q_OBJECT
The rest of the plugin may contain any code that is required to make the plugin meet your needs. In this example, we will use a QT slot to receive button presses:
/// \brief Callback trigged when the button is pressed. protected slots: void OnButton()
We will also use Gazebo's factory functionality to send SDF spawn messages to gzserver:
/// \brief Node used to establish communication with gzserver. private: transport::NodePtr node; /// \brief Publisher of factory messages. private: transport::PublisherPtr factoryPub;
Take a look at the source file.
gedit GUIExampleSpawnWidget.cc
The constructor in this file uses QT to create a button and attach it to our
OnButton
callback:// Create a push button, and connect it to the OnButton function QPushButton *button = new QPushButton(tr("Spawn Sphere")); connect(button, SIGNAL(clicked()), this, SLOT(OnButton()));
The constructor also connects to Gazebo's transport mechanism and creates a factory publisher:
// Create a node for transportation this->node = transport::NodePtr(new transport::Node()); this->node->Init(); this->factoryPub = this->node->Advertise<msgs::Factory>("~/factory");
The
OnButton
callback creates a new sphere SDF string:std::ostringstream newModelStr; newModelStr << "<sdf version='" << SDF_VERSION << "'>" << msgs::ModelToSDF(model)->ToString("") << "</sdf>";
and sends the string to Gazebo:
msgs::Factory msg; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); }
Compile the plugin
cd ~/gazebo_gui_spawn
mkdir build
cd build
cmake ../
make
Now we need to make sure Gazebo can find the plugin. You can do this by
appending the build
directory to the GAZEBO_PLUGIN_PATH
environment variable:
cd ~/gazebo_gui_spawn/build
export GAZEBO_PLUGIN_PATH=`pwd`:$GAZEBO_PLUGIN_PATH
Note that the command above works only for the current shell. To make sure
the plugin will work when opening new terminals, install the plugin into a
common search path, such as /usr/local/lib
, or into one of the paths
specified by the GAZEBO_PLUGIN_PATH
library.
We also need to tell Gazebo that it should load the overlay plugin.
There are two methods to accomplish this.
SDF world file: Modify a world SDF file to contain the GUI plugin. For example:
<?xml version="1.0" ?>
<sdf version="1.5">
<world name="default">
<gui>
<plugin name="sample" filename="libgui_example_spawn_widget.so"/>
</gui>
<!-- A global light source -->
<include>
<uri>model://sun</uri>
</include>
<!-- A ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>
</world>
</sdf>
Tip: Download the world file above:
cd ~/gazebo_gui_spawn
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/spawn_widget_example.world
GUI INI file: Modify the ~/.gazebo/gui.ini
file so the plugin is loaded every time Gazebo is run:
gedit ~/.gazebo/gui.ini
Add the following lines:
[overlay_plugins]
filenames=libgui_example_spawn_widget.so
Now when Gazebo is run, a button should appear in the upper left of the render window.
If you created a custom SDF world file with with GUI plugin:
gazebo spawn_widget_example.world
or if you modified ~/.gazebo/gui.ini
gazebo
Click on the button to spawn spheres.
The source code for this example is found here.
Start by creating a working directory
mkdir ~/gazebo_gui_time
cd ~/gazebo_gui_time
Download the source code for the GUI overlay plugin
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/GUIExampleTimeWidget.hh
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/GUIExampleTimeWidget.cc
wget https://github.com/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/CMakeLists.txt
Take a look at the header file.
gedit GUIExampleTimeWidget.hh
Just as in the first example, this plugin inherits from the GUIPlugin class, and use Qt's
Q_OBJECT
macro.class GAZEBO_VISIBLE GUIExampleTimeWidget : public GUIPlugin { Q_OBJECT
We use
SetSimTime
signal as a thread safe mechanism to update the displayed simulation time./// \brief A signal used to set the sim time line edit. /// \param[in] _string String representation of sim time. signals: void SetSimTime(QString _string);
An
OnStats
callback is used to receive information from Gazebo./// \brief Callback that received world statistics messages. /// \param[in] _msg World statistics message that is received. protected: void OnStats(ConstWorldStatisticsPtr &_msg);
We will also use Gazebo's transport mechanism to receive messages from Gazebo.
/// \brief Node used to establish communication with gzserver. private: transport::NodePtr node; /// \brief Subscriber to world statistics messages. private: transport::SubscriberPtr statsSub;
Take a look at the source file.
gedit GUIExampleTimeWidget.cc
In the constructor, we create a QLabel to display the time, and connect it to the
SetSimeTime
signal.// Create a time label QLabel *timeLabel = new QLabel(tr("00:00:00.00")); // Add the label to the frame's layout frameLayout->addWidget(label); frameLayout->addWidget(timeLabel); connect(this, SIGNAL(SetSimTime(QString)), timeLabel, SLOT(setText(QString)), Qt::QueuedConnection);
The constructor also connects to Gazebo's
~/world_stats
topic.// Create a node for transportation this->node = transport::NodePtr(new transport::Node()); this->node->Init("default"); this->statsSub = this->node->Subscribe("~/world_stats", &GUIExampleTimeWidget::OnStats, this);
When a message is received, the
OnStats
function is called and the displayed time is updated.void GUIExampleTimeWidget::OnStats(ConstWorldStatisticsPtr &_msg) { this->SetSimTime(QString::fromStdString( this->FormatTime(_msg->sim_time())));
Follow the same steps as the previous tutorial to compile the plugin,
tell Gazebo where to find it and load it via gui.ini
or an SDF world file.
Tip: You can add both plugins to
gui.ini
as follows:gedit ~/.gazebo/gui.ini
Change the
[overlay_plugins]
section to be:[overlay_plugins] filenames=libgui_example_spawn_widget.so:libgui_example_time_widget.so
This will load both the spawn sphere plugin from the previous example and the time plugin from this example.
When Gazebo is run, a new text box to the right of the spawn button should show the simulation time.
gazebo