GUI Overlay - modulabs/gazebo-tutorial GitHub Wiki
Gazebo GUI ์ค๋ฒ๋ ์ด๋ ๋ ๋๋ง ์๋์ฐ์ ๊ผญ๋๊ธฐ์์๋ ํฌ๋ช ํ 2D ๋ ์ด์ด๋ก ์๊ฐํ ์ ์์ต๋๋ค. QT ์์ ฏ์ ํ๋ฌ๊ทธ์ธ ์ธํฐํ์ด์ค๋ฅผ ํตํด์ด ๋ ์ด์ด์ ์ถ๊ฐ ํ ์ ์์ต๋๋ค. ๋ฉ์ธ Gazebo ๋ฉ๋ด ๋ฐ์์ View-> GUI Overlays๋ฅผ ํด๋ฆญํ์ฌ ๋ชจ๋ GUI ์ค๋ฒ๋ ์ด๋ฅผ ๋ณด์ด๊ฑฐ๋ ๊ฐ์ถ ์ ์์ต๋๋ค. ์ด ์์ต์์์๋ GUI ์ค๋ฒ๋ ์ด ํ๋ฌ๊ทธ์ธ์ ๋ง๋ค๊ณ ์ฌ์ฉํ์ฌ Gazebo์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
GUI ์ค๋ฒ๋ ์ด ๊ธฐ๋ฅ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ๋ ๊ฐ์ง ์๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ฒซ ๋ฒ์งธ ์์ ์์๋ ๊ตฌ๋ฅผ ์์ฑํ๋ ๋ฒํผ์ ๋ง๋ค๊ณ ๋ ๋ฒ์งธ ์์ ์์๋ ํ์ฌ ์๋ฎฌ๋ ์ด์ ์๊ฐ์ ํ์ํฉ๋๋ค. ์ด ๋ ์์ ๋ Gazebo๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๊ณ Gazebo์์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
https://bitbucket.org/osrf/gazebo/src/gazebo9/examples/plugins/gui_overlay_plugin_spawn/ ์์ค์ฝ๋๋ ์ฌ๊ธฐ์ ์ฐพ์ ์ ์์ต๋๋ค.
1.์ต์ Gazebo ๋ฒ์ ์ ์ค์นํ์ญ์์ค.
2.์ค์น ํ์ด์ง์ ์ง์ ์ฌํญ์ ๋ฐ๋ฅด์ญ์์ค.
mkdir ~/gazebo_gui_spawn
cd ~/gazebo_gui_spawn
-
GUI ์ค๋ฒ๋ ์ด ํ๋ฌ๊ทธ์ธ์ ์์ค ์ฝ๋ ๋ค์ด๋ก๋ (OsX์์ wget์ curl -OL๋ก ๋ฐ๊ฟ ์ ์์)
wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/GUIExampleSpawnWidget.hh wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/GUIExampleSpawnWidget.cc wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/CMakeLists.txt
4.ํค๋ ํ์ผ์ ์ดํด๋ณด์ญ์์ค.
gedit GUIExampleSpawnWidget.hh
GUI ์ค๋ฒ๋ ์ด ํ๋ฌ๊ทธ์ธ์ GUIPlugin ํด๋์ค๋ฅผ ์์ ๋ฐ์ Qt์ Q_OBJECT ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค.
class GAZEBO_VISIBLE GUIExampleSpawnWidget : public GUIPlugin
{
Q_OBJECT
๋๋จธ์ง ํ๋ฌ๊ทธ์ธ์๋ ์ฌ์ฉ์์ ํ์์ ๋ง๊ฒ ํ๋ฌ๊ทธ์ธ์ ์์ฑํ๋ ๋ฐ ํ์ํ ์ฝ๋๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค. ์ด ์์์๋ QT ์ฌ๋กฏ์ ์ฌ์ฉํ์ฌ ๋ฒํผ์ ๋๋ฆ
๋๋ค.
/// \brief Callback trigged when the button is pressed.
protected slots: void OnButton()
Gazebo์ ๊ณต์ฅ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ SDF ์คํฐ ๋ฉ์์ง๋ฅผ gzserver๋ก ์ ์กํฉ๋๋ค.:
/// \brief Node used to establish communication with gzserver.
private: transport::NodePtr node;
/// \brief Publisher of factory messages.
private: transport::PublisherPtr factoryPub;
5.์์ค ํ์ผ์ ์ดํด๋ณด์ญ์์ค.
gedit GUIExampleSpawnWidget.cc
์ด ํ์ผ์ ์์ฑ์๋ QT๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒํผ์ ๋ง๋ค๊ณ ์ด๋ฅผ OnButton ์ฝ๋ฐฑ์ ์ฐ๊ฒฐํฉ๋๋ค.:
// 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()));
๊ทธ ์์ฑ์๋ ๋ํ Gazebo์ ์ ์ก ๋ฉ์ปค๋์ฆ์ ์ฐ๊ฒฐํ๊ณ ๊ณต์ฅ ๊ฒ์์๋ฅผ ๋ง๋ญ๋๋ค:
// Create a node for transportation
this->node = transport::NodePtr(new transport::Node());
this->node->Init();
this->factoryPub = this->node->Advertise<msgs::Factory>("~/factory");
OnButton ์ฝ๋ฐฑ์ ์๋ก์ด ๊ตฌํ SDF ๋ฌธ์์ด์ ๋ง๋ญ๋๋ค.:
std::ostringstream newModelStr;
newModelStr << "<sdf version='" << SDF_VERSION << "'>"
<< msgs::ModelToSDF(model)->ToString("")
<< "</sdf>";
๊ทธ๋ฆฌ๊ณ ๊ฐ์ ๋ณด์๊ฒ ๋ฌธ์์ด์ ๋ณด๋
๋๋ค.:
msgs::Factory msg;
msg.set_sdf(newModelStr.str());
this->factoryPub->Publish(msg);
}
6.ํ๋ฌ๊ทธ์ธ ์ปดํ์ผ
cd ~/gazebo_gui_spawn
mkdir build
cd build
cmake ../
make
7.์ด์ ์ฐ๋ฆฌ๋ Gazebo๊ฐ ํ๋ฌ๊ทธ์ธ์ ์ฐพ์ ์ ์๋๋กํด์ผํฉ๋๋ค. ๋น๋ ๋๋ ํ ๋ฆฌ๋ฅผ GAZEBO_PLUGIN_PATH ํ๊ฒฝ ๋ณ์์ ์ถ๊ฐํ์ฌ์ด ์์ ์ ์ํ ํ ์ ์์ต๋๋ค.
cd ~/gazebo_gui_spawn/build
export GAZEBO_PLUGIN_PATH=`pwd`:$GAZEBO_PLUGIN_PATH
์์ ๋ช ๋ น์ ํ์ฌ ์์์๋ง ์๋ํฉ๋๋ค. ์ ํฐ๋ฏธ๋์ ์ด ๋ ํ๋ฌ๊ทธ์ธ์ด ์๋ํ๋์ง ํ์ธํ๋ ค๋ฉด ํ๋ฌ๊ทธ์ธ์ / usr / local / lib์ ๊ฐ์ ์ผ๋ฐ์ ์ธ ๊ฒ์ ๊ฒฝ๋ก ๋ GAZEBO_PLUGIN_PATH ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ง์ ๋ ๊ฒฝ๋ก ์ค ํ๋์ ์ค์นํ์ญ์์ค.
8.๋ํ ์ค๋ฒ๋ ์ด ํ๋ฌ๊ทธ์ธ์๋ก๋ํด์ผํ๋ค๊ณ Gazebo์ ์๋ฆด ํ์๊ฐ ์์ต๋๋ค.
์ด ์์ ์ ์ํํ๋ ๋ฐ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
1.SDF world file : GUI ํ๋ฌ๊ทธ์ธ์ ํฌํจํ๋๋ก world SDF ํ์ผ์ ์์ ํ์ญ์์ค. ์ :
<?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://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_spawn/spawn_widget_example.world
2.GUI INI ํ์ผ : Gazebo๊ฐ ์คํ๋ ๋๋ง๋ค ํ๋ฌ๊ทธ์ธ์ด๋ก๋๋๋๋ก ~ / .gazebo / gui.ini ํ์ผ์ ์์ ํ์ญ์์ค.
gedit ~/.gazebo/gui.ini
Add the following lines:
[overlay_plugins]
filenames=libgui_example_spawn_widget.so
- ์ด์ Gazebo๋ฅผ ์คํํ๋ฉด ๋ ๋๋ง ์๋์ฐ์ ์ผ์ชฝ ์๋จ์ ๋ฒํผ์ด ๋ํ๋ฉ๋๋ค.
GUI ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ฌ์ฉ์ ์ ์ SDF ์๋ ํ์ผ์ ์์ฑ ํ ๊ฒฝ์ฐ :
gazebo spawn_widget_example.world
๋๋ ~ / .gazebo / gui.ini๋ฅผ ์์ ํ ๊ฒฝ์ฐ
gazebo
Click on the button to spawn spheres.
์ด ์์ ์ ์์ค ์ฝ๋๋ ์ฌ๊ธฐ์์ ์ฐพ์ ์ ์์ต๋๋ค.
1.์์ ๋๋ ํ ๋ฆฌ ๋ง๋ค๊ธฐ mkdir ~/gazebo_gui_time cd ~/gazebo_gui_time
2.GUI ์ค๋ฒ๋ ์ด ํ๋ฌ๊ทธ์ธ์ ์์ค ์ฝ๋ ๋ค์ด๋ก๋
wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/GUIExampleTimeWidget.hh
wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/GUIExampleTimeWidget.cc
wget https://bitbucket.org/osrf/gazebo/raw/gazebo9/examples/plugins/gui_overlay_plugin_time/CMakeLists.txt
3.ํค๋ ํ์ผ์ ์ดํด๋ณด์ญ์์ค.
gedit GUIExampleTimeWidget.hh
์ฒซ ๋ฒ์งธ ์์ ์ ๋ง์ฐฌ๊ฐ์ง๋ก์ด ํ๋ฌ๊ทธ์ธ์ GUIPlugin ํด๋์ค์์ ์์ ๋ฐ๊ณ Qt์ Q_OBJECT ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค.
class GAZEBO_VISIBLE GUIExampleTimeWidget : public GUIPlugin
{
Q_OBJECT
ํ์๋ ์๋ฎฌ๋ ์ด์
์๊ฐ์ ์
๋ฐ์ดํธํ๊ธฐ ์ํด SetSimTime ์ ํธ๋ฅผ ์ค๋ ๋ ์์ ๋ฉ์ปค๋์ฆ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
/// \brief A signal used to set the sim time line edit.
/// \param[in] _string String representation of sim time.
signals: void SetSimTime(QString _string);
OnStats ์ฝ๋ฐฑ์ Gazebo์์ ์ ๋ณด๋ฅผ ์์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
/// \brief Callback that received world statistics messages.
/// \param[in] _msg World statistics message that is received.
protected: void OnStats(ConstWorldStatisticsPtr &_msg);
๋ํ Gazebo์ ์ ์ก ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ฌ Gazebo์์ ๋ฉ์์ง๋ฅผ ์์ ํฉ๋๋ค.
/// \brief Node used to establish communication with gzserver.
private: transport::NodePtr node;
/// \brief Subscriber to world statistics messages.
private: transport::SubscriberPtr statsSub;
4.์์ค ํ์ผ์ ์ดํด๋ณด์ญ์์ค.
gedit GUIExampleTimeWidget.cc
์์ฑ์์์ ์๊ฐ์ ํ์ํ๋ QLabel์ ๋ง๋ค๊ณ ์ด๋ฅผ SetSimeTime ์ ํธ์ ์ฐ๊ฒฐํฉ๋๋ค.
// 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);
์์ฑ์๋ Gazebo์ ~ / world_stats ํญ๋ชฉ์๋ ์ฐ๊ฒฐ๋ฉ๋๋ค.
// 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);
๋ฉ์์ง๋ฅผ ๋ฐ์ผ๋ฉด OnStats ํจ์๊ฐ ํธ์ถ๋๊ณ ํ์๋ ์๊ฐ์ด ์
๋ฐ์ดํธ๋ฉ๋๋ค.
void GUIExampleTimeWidget::OnStats(ConstWorldStatisticsPtr &_msg)
{
this->SetSimTime(QString::fromStdString(
this->FormatTime(_msg->sim_time())));
5.์ด์ ํํ ๋ฆฌ์ผ๊ณผ ๊ฐ์ ๋จ๊ณ์ ๋ฐ๋ผ ํ๋ฌ๊ทธ์ธ์ ์ปดํ์ผํ๊ณ Gazebo์ ์ฐพ์์ gui.ini ๋๋ SDF world ํ์ผ์ ํตํด๋ก๋ํ์ญ์์ค.
Tip: ๋ค์๊ณผ ๊ฐ์ด ๋ ํ๋ฌ๊ทธ์ธ์ ๋ชจ๋ gui.ini์ ์ถ๊ฐ ํ ์ ์์ต๋๋ค.
gedit ~/.gazebo/gui.ini
[overlay_plugins] ์น์
์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ์ญ์์ค.
[overlay_plugins]
filenames=libgui_example_spawn_widget.so:libgui_example_time_widget.so
์ด์ ์์ ์ spawn sphere plugin๊ณผ์ด ์์ ์ time plugin์ ๋ชจ๋๋ก๋ํฉ๋๋ค.
6.Gazebo๊ฐ ์คํ๋๋ฉด ์คํฐ ๋ฒํผ ์ค๋ฅธ์ชฝ์ ์ ํ ์คํธ ์์์ ์๋ฎฌ๋ ์ด์ ์๊ฐ์ด ํ์๋ฉ๋๋ค.
gazebo