Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

[Gazebo 11] Allow gazebo to download models from Fuel in the sdf files #2822

Merged
merged 20 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions gazebo/Server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
#include <sdf/sdf.hh>

#include <ignition/math/Rand.hh>
#include "ignition/common/Profiler.hh"
#include <ignition/common/Profiler.hh>
#include <ignition/common/Filesystem.hh>
#include <ignition/common/URI.hh>
#include <ignition/fuel_tools/Interface.hh>

#include "gazebo/gazebo.hh"
#include "gazebo/transport/transport.hh"
Expand Down Expand Up @@ -402,9 +405,36 @@ bool Server::LoadFile(const std::string &_filename,
return false;
}

if (!sdf::readFile(common::find_file(_filename), sdf))
std::string filename = _filename;
auto filenameUri = ignition::common::URI(filename);

if (filenameUri.Scheme() == "http" || filenameUri.Scheme() == "https")
{
gzerr << "Unable to read sdf file[" << _filename << "]\n";
std::string downloadedDir = ignition::fuel_tools::fetchResource(filename);
// Find the first sdf file in the world path for now, the later intention is
// to load an optional world config file first and if that does not exist,
// continue to load the first sdf file found as done below
for (ignition::common::DirIter file(downloadedDir);
file != ignition::common::DirIter(); ++file)
{
std::string current(*file);
if (ignition::common::isFile(current))
{
std::string fileName = ignition::common::basename(current);
std::string::size_type fileExtensionIndex = fileName.rfind(".");
std::string fileExtension = fileName.substr(fileExtensionIndex + 1);

if (fileExtension == "sdf" || fileExtension == "world")
{
filename = current.c_str();
}
}
}
}

if (!sdf::readFile(common::find_file(filename), sdf))
{
gzerr << "Unable to read sdf file[" << filename << "]\n";
return false;
}

Expand Down
10 changes: 9 additions & 1 deletion gazebo/common/CommonIface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@
#include "gazebo/common/Console.hh"
#include "gazebo/common/CommonIface.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/common/FuelModelDatabase.hh"
#include "gazebo/common/SystemPaths.hh"

#include "ignition/fuel_tools/Interface.hh"

using namespace gazebo;

#ifdef _WIN32
Expand Down Expand Up @@ -159,7 +162,12 @@ void common::add_search_path_suffix(const std::string &_suffix)
/////////////////////////////////////////////////
std::string common::find_file(const std::string &_file)
{
return common::SystemPaths::Instance()->FindFile(_file, true);
std::string path = common::FuelModelDatabase::Instance()->ModelPath(_file);
if (path.empty())
{
path = common::SystemPaths::Instance()->FindFile(_file, true);
}
return path;
}

/////////////////////////////////////////////////
Expand Down
58 changes: 43 additions & 15 deletions gazebo/common/FuelModelDatabase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,26 +213,54 @@ std::string FuelModelDatabase::ModelPath(const std::string &_uri,
}

std::string path;
std::string fileUrl;
ignition::fuel_tools::ModelIdentifier model;
using namespace ignition::fuel_tools;

if (!_forceDownload)
if ((this->dataPtr->fuelClient->ParseModelUrl(fuelUri, model) &&
!this->dataPtr->fuelClient->CachedModel(fuelUri, path))
|| _forceDownload)
{
if (this->dataPtr->fuelClient->CachedModel(fuelUri, path))
Result result_download =
this->dataPtr->fuelClient->DownloadModel(fuelUri, path);
if (result_download != Result(ResultType::FETCH) ||
result_download != Result(ResultType::FETCH_ALREADY_EXISTS))
{
return path;
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else
{
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
}
}

if (!this->dataPtr->fuelClient->DownloadModel(fuelUri, path))
{
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else
{
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
if (path.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (path.empty()) {
if (path.empty())
{

if ((this->dataPtr->fuelClient->ParseModelFileUrl(fuelUri, model, fileUrl) &&
!this->dataPtr->fuelClient->CachedModelFile(fuelUri, path))
|| _forceDownload)
{
auto modelUri = _uri.substr(0,
_uri.find("files", model.UniqueName().size())-1);
Result result_download =
this->dataPtr->fuelClient->DownloadModel(ignition::common::URI(modelUri), path);
if (result_download != Result(ResultType::FETCH) ||
result_download != Result(ResultType::FETCH_ALREADY_EXISTS))
{
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else
{
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
path += "/" + fileUrl;
}
}
}

return path;
Expand Down
21 changes: 0 additions & 21 deletions gazebo/gui/InsertModelWidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,6 @@ using namespace gui;

static bool gInsertModelWidgetDeleted = false;

/////////////////////////////////////////////////
// TODO: Remove this once Fuel support is fully functional
bool usingFuel()
{
auto useFuel = std::getenv("USE_IGNITION_FUEL");
if (!useFuel || *useFuel == '\0')
return false;

std::string useFuelStr(useFuel);
std::transform(useFuelStr.begin(), useFuelStr.end(),
useFuelStr.begin(), ::tolower);

return useFuelStr != "false" && useFuelStr != "0";
}

/////////////////////////////////////////////////
InsertModelWidget::InsertModelWidget(QWidget *_parent)
: QWidget(_parent), dataPtr(new InsertModelWidgetPrivate)
Expand Down Expand Up @@ -523,9 +508,6 @@ bool InsertModelWidget::IsPathAccessible(const boost::filesystem::path &_path)
/////////////////////////////////////////////////
void InsertModelWidget::InitializeFuelServers()
{
if (!usingFuel())
return;

// Get the list of Ignition Fuel servers.
auto servers = common::FuelModelDatabase::Instance()->Servers();

Expand All @@ -550,9 +532,6 @@ void InsertModelWidget::InitializeFuelServers()
/////////////////////////////////////////////////
void InsertModelWidget::PopulateFuelServers()
{
if (!usingFuel())
return;

// Get the list of Ignition Fuel servers.
auto servers = common::FuelModelDatabase::Instance()->Servers();

Expand Down
62 changes: 62 additions & 0 deletions test/integration/factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,68 @@ TEST_F(FactoryTest, FilenameFuelURL)
// Check model was spawned
ASSERT_NE(nullptr, world->ModelByName("test_box"));
}

TEST_F(FactoryTest, worldWithFuelModels)
{
this->Load("worlds/fuel_models.world", true);

// World
auto world = physics::get_world("default");
ASSERT_NE(nullptr, world);

// Wait for it to be spawned
int sleep = 0;
int maxSleep = 50;
while (!world->ModelByName("Radio") && sleep++ < maxSleep)
{
common::Time::MSleep(100);
}

// Check model was spawned
ASSERT_NE(nullptr, world->ModelByName("Radio"));
}

TEST_F(FactoryTest, FuelURIAsWorldArgument)
{
this->Load(
"https://staging-fuel.ignitionrobotics.org/1.0/chapulina/worlds/Shapes",
true);

// World
auto world = physics::get_world("default");
ASSERT_NE(nullptr, world);

// Wait for it to be spawned
int sleep = 0;
int maxSleep = 50;
while (!world->ModelByName("box") && sleep++ < maxSleep)
{
common::Time::MSleep(100);
}

// Check model was spawned
ASSERT_NE(nullptr, world->ModelByName("box"));

sleep = 0;
maxSleep = 50;
while (!world->ModelByName("cylinder") && sleep++ < maxSleep)
{
common::Time::MSleep(100);
}

// Check model was spawned
ASSERT_NE(nullptr, world->ModelByName("cylinder"));

sleep = 0;
maxSleep = 50;
while (!world->ModelByName("sphere") && sleep++ < maxSleep)
{
common::Time::MSleep(100);
}

// Check model was spawned
ASSERT_NE(nullptr, world->ModelByName("sphere"));
}
#endif

//////////////////////////////////////////////////
Expand Down
39 changes: 39 additions & 0 deletions worlds/fuel_models.world
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" ?>
<sdf version="1.5">
<world name="default">
<!-- A global light source -->
<include>
<uri>model://sun</uri>
</include>
<!-- A ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>

<include>
<pose>0 1 3 0.0 0.0 1.57</pose>
<uri>https://fuel.ignitionrobotics.org/1.0/openrobotics/models/Construction Cone</uri>
</include>

<model name="Radio">
<pose>3 -1.5 0 0 0 0</pose>
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<mesh>
<uri>https://fuel.ignitionrobotics.org/1.0/openrobotics/models/Radio/4/files/meshes/Radio.dae</uri>
</mesh>
</geometry>
</collision>
<visual name="visual">
<geometry>
<mesh>
<uri>https://fuel.ignitionrobotics.org/1.0/openrobotics/models/Radio/4/files/meshes/Radio.dae</uri>
</mesh>
</geometry>
</visual>
</link>
</model>
</world>
</sdf>