Skip to content

Commit c495292

Browse files
nkoenigazeey
andauthored
Parallel asset download (#2992)
This will download simulation assets in background threads by default. You can force simulation to wait for assets using the --wait-for-assets CLI option. I'm defaulting to async download because: It's a better user experience to have some instant GUI feedback. If you're using only the simulation server (no GUI), then you're in the experienced user category and can choose whether to wait for assets or not. --------- Signed-off-by: Nate Koenig <natekoenig@gmail.com> Signed-off-by: Addisu Z. Taddese <addisu@openrobotics.org> Co-authored-by: Addisu Z. Taddese <addisu@openrobotics.org>
1 parent b692ae2 commit c495292

File tree

14 files changed

+442
-83
lines changed

14 files changed

+442
-83
lines changed

examples/worlds/tunnel.sdf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
<include>
214214
<pose>9.23 2.18 0 0 0 -1.226</pose>
215215
<uri>
216-
https://fuel.gazebosim.org/1.0/chapulina/models/Extinguisher PBR
216+
https://fuel.gazebosim.org/1.0/OpenRobotics/models/Fire Extinguisher
217217
</uri>
218218
</include>
219219

include/gz/sim/ServerConfig.hh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,20 @@ namespace gz
447447
public: const std::chrono::time_point<std::chrono::system_clock> &
448448
Timestamp() const;
449449

450+
/// \brief Set whether simulation should wait for assets to
451+
/// download before starting.
452+
/// The default value is true.
453+
/// \param[in] _set True to wait while assets download. False will
454+
/// download assets in a background thread.
455+
public: void SetWaitForAssets(bool _set);
456+
457+
/// \brief Get whether simulation should wait for assets to
458+
/// download before starting.
459+
/// The default value is true.
460+
/// \return True if simulation should wait while assets download. False
461+
/// indicates assets should be downloaded in a separate thread.
462+
public: bool WaitForAssets() const;
463+
450464
/// \brief Get the type of source
451465
/// \return The source type.
452466
public: SourceType Source() const;

src/Server.cc

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ Server::Server(const ServerConfig &_config)
6969
config.SetCacheLocation(_config.ResourceCache());
7070
this->dataPtr->fuelClient = std::make_unique<fuel_tools::FuelClient>(config);
7171

72+
// Turn off downloads so that we can do an initial parsing of the SDF
73+
// file. This will let us get the world names, and queue the simulation asset
74+
// URIs for download.
75+
this->dataPtr->enableDownload = false;
76+
7277
// Configure SDF to fetch assets from Gazebo Fuel.
7378
sdf::setFindCallback(std::bind(&ServerPrivate::FetchResource,
7479
this->dataPtr.get(), std::placeholders::_1));
@@ -77,42 +82,62 @@ Server::Server(const ServerConfig &_config)
7782

7883
addResourcePaths();
7984

85+
sdf::Root sdfRoot;
86+
8087
// Loads the SDF root object based on values in a ServerConfig object.
81-
sdf::Errors errors = this->dataPtr->LoadSdfRootHelper(_config);
88+
// Ignore the sdf::Errors returned by this function. The errors will be
89+
// displayed later in the downloadThread.
90+
ServerConfig cfg = _config;
91+
cfg.SetBehaviorOnSdfErrors(
92+
ServerConfig::SdfErrorBehavior::CONTINUE_LOADING);
93+
sdf::Errors errors = this->dataPtr->LoadSdfRootHelper(
94+
cfg, sdfRoot);
8295

83-
if (!errors.empty())
96+
// Add record plugin
97+
if (_config.UseLogRecord())
8498
{
85-
for (auto &err : errors)
86-
gzerr << err << "\n";
87-
if (_config.BehaviorOnSdfErrors() ==
88-
ServerConfig::SdfErrorBehavior::EXIT_IMMEDIATELY)
89-
{
90-
return;
91-
}
99+
this->dataPtr->AddRecordPlugin(_config, sdfRoot);
92100
}
93101

94-
// Add record plugin
95-
if (_config.UseLogRecord())
102+
// Remove all the models, lights, and actors from the primary sdfRoot object
103+
// so that they can be downloaded and added to simulation in the background.
104+
for (uint64_t i = 0; i < sdfRoot.WorldCount(); ++i)
96105
{
97-
this->dataPtr->AddRecordPlugin(_config);
106+
sdfRoot.WorldByIndex(i)->ClearModels();
107+
sdfRoot.WorldByIndex(i)->ClearActors();
108+
sdfRoot.WorldByIndex(i)->ClearLights();
98109
}
99110

111+
// This will create the simulation runners, but not entities.
112+
this->dataPtr->CreateSimulationRunners(sdfRoot);
113+
114+
// Storing the sdf root. The ServerPrivate.hh header file mentions
115+
// that other classes may keep pointers to child nodes of the root,
116+
// so we need to keep this object around.
117+
// However, everything seems to work fine without storing this.
118+
// \todo(nkoenig): Look into removing the sdfRoot member variable.
119+
this->dataPtr->sdfRoot = sdfRoot;
120+
121+
// Establish publishers and subscribers. Setup transport before
122+
// downloading simulation assets so that the GUI is not blocked during
123+
// download.
124+
this->dataPtr->SetupTransport();
125+
100126
// If we've received a signal before we create entities, the Stop event
101127
// won't be propagated to them. Instead, we just quit early here.
102128
if (this->dataPtr->signalReceived)
103129
return;
104130

105-
this->dataPtr->CreateEntities();
131+
// Download the simulation assets. This function will block if
132+
// _config.WaitForAssets() is true;
133+
this->dataPtr->DownloadAssets(_config);
106134

107135
// Set the desired update period, this will override the desired RTF given in
108-
// the world file which was parsed by CreateEntities.
136+
// the world file which was parsed by LoadSdfRootHelper.
109137
if (_config.UpdatePeriod())
110138
{
111139
this->SetUpdatePeriod(_config.UpdatePeriod().value());
112140
}
113-
114-
// Establish publishers and subscribers.
115-
this->dataPtr->SetupTransport();
116141
}
117142

118143
/////////////////////////////////////////////////

src/ServerConfig.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,10 @@ class gz::sim::ServerConfigPrivate
212212
seed(_cfg->seed),
213213
logRecordTopics(_cfg->logRecordTopics),
214214
isHeadlessRendering(_cfg->isHeadlessRendering),
215+
sdfRoot(_cfg->sdfRoot),
215216
source(_cfg->source),
216-
behaviorOnSdfErrors(_cfg->behaviorOnSdfErrors){ }
217+
behaviorOnSdfErrors(_cfg->behaviorOnSdfErrors),
218+
waitForAssets(_cfg->waitForAssets) { }
217219

218220
// \brief The SDF file that the server should load
219221
public: std::string sdfFile = "";
@@ -293,14 +295,17 @@ class gz::sim::ServerConfigPrivate
293295
public: bool isHeadlessRendering{false};
294296

295297
/// \brief Optional SDF root object.
296-
public: std::optional<sdf::Root> sdfRoot;
298+
public: std::optional<sdf::Root> sdfRoot{std::nullopt};
297299

298300
/// \brief Type of source used.
299301
public: ServerConfig::SourceType source{ServerConfig::SourceType::kNone};
300302

301303
/// \brief Server loading behavior in presence of SDF errors.
302304
public: ServerConfig::SdfErrorBehavior behaviorOnSdfErrors{
303305
ServerConfig::SdfErrorBehavior::EXIT_IMMEDIATELY};
306+
307+
/// \brief True to block while simulation assets download.
308+
public: bool waitForAssets{true};
304309
};
305310

306311
//////////////////////////////////////////////////
@@ -741,6 +746,18 @@ ServerConfig::Timestamp() const
741746
return this->dataPtr->timestamp;
742747
}
743748

749+
/////////////////////////////////////////////////
750+
void ServerConfig::SetWaitForAssets(bool _set)
751+
{
752+
this->dataPtr->waitForAssets = _set;
753+
}
754+
755+
/////////////////////////////////////////////////
756+
bool ServerConfig::WaitForAssets() const
757+
{
758+
return this->dataPtr->waitForAssets;
759+
}
760+
744761
/////////////////////////////////////////////////
745762
void ServerConfig::AddLogRecordTopic(const std::string &_topic)
746763
{

0 commit comments

Comments
 (0)