ed
server.cpp
Go to the documentation of this file.
1 #include "ed/server.h"
2 
3 #include "ed/entity.h"
4 #include "ed/error_context.h"
5 #include "ed/measurement.h"
6 #include "ed/plugin.h"
7 #include "ed/plugin_container.h"
8 #include "ed/types.h"
9 #include "ed/world_model.h"
10 
11 // Storing measurements to disk
12 #include "ed/io/filesystem/write.h"
13 
15 
16 #include <tue/config/writer.h>
18 
19 #include <tue/filesystem/path.h>
20 
21 #include <std_msgs/String.h>
22 
23 #include <tf2_ros/buffer.h>
24 #include <tf2_ros/transform_listener.h>
25 
26 namespace ed
27 {
28 
29 // ----------------------------------------------------------------------------------------------------
30 
31 Server::Server() : world_model_(new WorldModel(&property_key_db_))
32 {
33  updater_.setHardwareID("none");
34 
35  tf_buffer_ = ed::make_shared<tf2_ros::Buffer>();
36  tf_buffer_const_ = ed::const_pointer_cast<const tf2_ros::Buffer>(tf_buffer_);
37  tf_listener_ = ed::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
38 }
39 
40 // ----------------------------------------------------------------------------------------------------
41 
43 {
44  ErrorContext errc("Server", "destructor");
45 }
46 
47 // ----------------------------------------------------------------------------------------------------
48 
49 void Server::configure(tue::Configuration& config, bool /*reconfigure*/)
50 {
51  ErrorContext errc("Server", "configure");
52 
53  if (config.readArray("plugins"))
54  {
55  while(config.nextArrayItem())
56  {
57  std::string name;
58  if (!config.value("name", name))
59  return;
60 
61  bool enabled = true;
62  config.value("enabled", enabled, tue::config::OPTIONAL);
63 
64  PluginContainerPtr plugin_container;
65 
67  if (it_plugin == plugin_containers_.end())
68  {
69  // Plugin does not yet exist
70  if (!enabled)
71  {
72  // It is not enabled, so simply skip it
73  continue;
74  }
75 
76  plugin_container = loadPlugin(name, config);
77  if (plugin_container)
78  updater_.add(plugin_container->getLoopUsageStatus());
79  }
80  else
81  {
82  // Plugin already exists
83 
84  plugin_container = it_plugin->second;
85 
86  if (!enabled && plugin_container->isRunning())
87  {
88  plugin_container->requestStop();
89  inactive_plugin_containers_[name] = plugin_container;
91  updater_.removeByName(name);
92  continue;
93  }
94  else
95  {
97  plugin_container->configure(init, true);
98  updater_.add(plugin_container->getLoopUsageStatus());
99  }
100  }
101 
102  if (config.hasError())
103  return;
104 
105  if (enabled && plugin_container && !plugin_container->isRunning())
106  plugin_container->runThreaded();
107 
108  } // end iterate plugins
109 
110  config.endArray();
111  }
112 
113  if (config.value("world_name", world_name_, tue::config::OPTIONAL))
114  initializeWorld();
115 
116  if (config.readArray("world"))
117  {
118  while (config.nextArrayItem())
119  {
122  if (!model_loader_.create(config.data(), "", "", *req, error))
123  {
124  config.addError("Could not instantiate world object: " + error.str());
125  continue;
126  }
127 
128  // Create world model copy (shallow)
129  boost::unique_lock<boost::mutex> ul(mutex_world_);
130  WorldModelPtr new_world_model = ed::make_shared<WorldModel>(*world_model_);
131 
132  new_world_model->update(*req);
133 
134  world_model_ = new_world_model;
135  ul.unlock();
136  }
137  }
138 }
139 
140 // ----------------------------------------------------------------------------------------------------
141 
143 {
144  if (pub_stats_.getTopic().empty())
145  {
146  ros::NodeHandle nh;
147  pub_stats_ = nh.advertise<std_msgs::String>("ed/stats", 10);
148  }
149 }
150 
151 // ----------------------------------------------------------------------------------------------------
152 
153 void Server::reset(bool keep_all_shapes)
154 {
155  ErrorContext errc("Server", "reset");
156 
157  // Create init world request, such that we can check which entities we have to keep in the world model
158  UpdateRequestPtr req_init_world(new UpdateRequest);
160  if (!model_loader_.create("_root", world_name_, *req_init_world, error, true))
161  {
162  ROS_ERROR_STREAM("[ED] Could not initialize world: " << error.str());
163  }
164 
165  // Prepare deletion request
166  UpdateRequestPtr req_delete(new UpdateRequest);
168  for(WorldModel::const_iterator it = wm->begin(); it != wm->end(); ++it)
169  {
170  // Only remove entities that are NOT in the initial world model
171  const ed::EntityConstPtr& e = *it;
172 
173  if (e->id().str().substr(0, 6) == "sergio" || e->id().str().substr(0, 5) == "amigo" || e->id().str().substr(0, 4) == "hero") // TODO: robocup hack
174  continue;
175 
176  if (keep_all_shapes && e->visual())
177  continue;
178 
179  if (req_init_world->updated_entities.find(e->id()) == req_init_world->updated_entities.end())
180  req_delete->removeEntity((*it)->id());
181  }
182 
183  // Create world model copy
184  boost::unique_lock<boost::mutex> ul(mutex_world_);
185  WorldModelPtr new_world_model = ed::make_shared<WorldModel>(*world_model_);
186 
187  // Apply the deletion request
188  new_world_model->update(*req_init_world);
189  new_world_model->update(*req_delete);
190 
191  // Swap to new world model
192  world_model_ = new_world_model;
193  ul.unlock();
194 
195  // Notify plugins
197  {
198  const PluginContainerPtr& c = it->second;
199  c->addDelta(req_init_world);
200  c->addDelta(req_delete);
201  c->setWorld(new_world_model);
202  }
203 }
204 
205 // ----------------------------------------------------------------------------------------------------
206 
208 {
209  ErrorContext errc("Server loadPlugin", plugin_name.c_str());
210 
211  config.setErrorContext("While loading plugin '" + plugin_name + "': ");
212 
213  std::string plugin_type;
214  if (!config.value("type", plugin_type))
215  return nullptr;
216 
217  if (plugin_type.empty())
218  {
219  config.addError("Empty plugin type given.");
220  return nullptr;
221  }
222 
223  // Create a plugin container
224  PluginContainerPtr container = ed::make_shared<PluginContainer>(tf_buffer_const_);
225 
227 
228  // Load the plugin
229  if (!container->loadPlugin(plugin_name, plugin_type, init))
230  return nullptr;
231 
232  // Add the plugin container
233  plugin_containers_[plugin_name] = container;
234 
235  return container;
236 }
237 
238 // ----------------------------------------------------------------------------------------------------
239 
241 {
242  ErrorContext errc("Server", "stepPlugins");
243 
244  WorldModelPtr new_world_model;
245 
246  // collect and apply all update requests
247  std::vector<PluginContainerPtr> plugins_with_requests;
249  {
250  PluginContainerPtr c = it->second;
251 
252  if (c->updateRequest())
253  {
254  if (!new_world_model)
255  {
256  // Create world model copy (shallow)
257  boost::unique_lock<boost::mutex> ul(mutex_world_);
258  new_world_model = ed::make_shared<WorldModel>(*world_model_);
259  }
260 
261  new_world_model->update(*c->updateRequest());
262  plugins_with_requests.push_back(c);
263  }
264  }
265 
266  if (new_world_model)
267  {
268  // Set the new (updated) world
270  {
271  const PluginContainerPtr& c = it->second;
272  c->setWorld(new_world_model);
273  }
274  boost::unique_lock<boost::mutex> ul(mutex_world_);
275  world_model_ = new_world_model;
276  ul.unlock();
277 
278  // Clear the requests of all plugins that had requests (which flags them to continue processing)
279  for(std::vector<PluginContainerPtr>::iterator it = plugins_with_requests.begin(); it != plugins_with_requests.end(); ++it)
280  {
281  PluginContainerPtr c = *it;
282  c->clearUpdateRequest();
283  }
284  }
285 }
286 
287 // ----------------------------------------------------------------------------------------------------
288 
290 {
291  ErrorContext errc("Server", "update");
292 
293  // Create world model copy (shallow)
294  boost::unique_lock<boost::mutex> ul(mutex_world_);
295  WorldModelPtr new_world_model = ed::make_shared<WorldModel>(*world_model_);
296  ul.unlock();
297 
298  // Notify all plugins of the updated world model
300  {
301  PluginContainerPtr c = it->second;
302  c->setWorld(new_world_model);
303  }
304 
305  // Set the new (updated) world
306  ul.lock();
307  world_model_ = new_world_model;
308  ul.unlock();
309 }
310 
311 // ----------------------------------------------------------------------------------------------------
312 
314 {
315  // Create world model copy (shallow)
316  boost::unique_lock<boost::mutex> ul(mutex_world_);
317  WorldModelPtr new_world_model = ed::make_shared<WorldModel>(*world_model_);
318  ul.unlock();
319 
320  // Update the world model
321  new_world_model->update(req);
322 
323  // Notify all plugins of the updated world model
325  {
326  PluginContainerPtr c = it->second;
327  c->setWorld(new_world_model);
328  }
329 
330  // Set the new (updated) world
331  ul.lock();
332  world_model_ = new_world_model;
333 }
334 
335 // ----------------------------------------------------------------------------------------------------
336 
337 void Server::update(const std::string& update_str, std::string& error)
338 {
339  // convert update string to update request
340  tue::Configuration cfg;
341 
342  tue::config::loadFromYAMLString(update_str, cfg);
343 
344  if (cfg.hasError())
345  {
346  error = cfg.error();
347  return;
348  }
349 
350  // - - - - - - - - - Create update request from cfg - - - - - - - - -
351 
352  UpdateRequest req;
353 
354  if (cfg.readArray("entities"))
355  {
356  while(cfg.nextArrayItem())
357  {
358  std::string id;
359  if (!cfg.value("id", id))
360  continue;
361 
362  if (cfg.readGroup("pose"))
363  {
364  geo::Pose3D pose;
365 
366  if (!cfg.value("x", pose.t.x) || !cfg.value("y", pose.t.y) || !cfg.value("z", pose.t.z))
367  continue;
368 
369  double rx = 0, ry = 0, rz = 0;
370  cfg.value("rx", rx, tue::config::OPTIONAL);
371  cfg.value("ry", ry, tue::config::OPTIONAL);
372  cfg.value("rz", rz, tue::config::OPTIONAL);
373 
374  pose.R.setRPY(rx, ry, rz);
375 
376  req.setPose(id, pose);
377 
378  cfg.endGroup();
379  }
380  }
381 
382  cfg.endArray();
383  }
384 
385  // Check for errors
386  if (cfg.hasError())
387  {
388  error = cfg.error();
389  return;
390  }
391 
392  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
393 
394  // Create world model copy (shallow)
395  boost::unique_lock<boost::mutex> ul(mutex_world_);
396  WorldModelPtr new_world_model = ed::make_shared<WorldModel>(*world_model_);
397  ul.unlock();
398 
399  // Update the world model
400  new_world_model->update(req);
401 
402  // Notify all plugins of the updated world model
404  {
405  PluginContainerPtr c = it->second;
406  c->setWorld(new_world_model);
407  }
408 
409  // Set the new (updated) world
410  ul.lock();
411  world_model_ = new_world_model;
412 }
413 
414 // ----------------------------------------------------------------------------------------------------
415 
417 {
420  if (!model_loader_.create("_root", world_name_, *req, error, true))
421  {
422  ROS_ERROR_STREAM("[ED] Could not initialize world: " << error.str());
423  return;
424  }
425 
426  // Create world model copy (shallow)
427  boost::unique_lock<boost::mutex> ul(mutex_world_);
428  WorldModelPtr new_world_model = boost::make_shared<WorldModel>(*world_model_);
429 
430  new_world_model->update(*req);
431 
432  world_model_ = new_world_model;
433 }
434 
435 // ----------------------------------------------------------------------------------------------------
436 
438 {
440  for(WorldModel::const_iterator it = wm->begin(); it != wm->end(); ++it)
441  {
442  const EntityConstPtr& e = *it;
443  MeasurementConstPtr msr = e->lastMeasurement();
444  if (!msr)
445  continue;
446 
447  std::string filename = path + "/" + e->id().str();
448  if (!write(filename, *msr))
449  {
450  std::cout << "Saving measurement failed." << std::endl;
451  }
452  }
453 }
454 
455 // ----------------------------------------------------------------------------------------------------
456 
458 {
459  ErrorContext errc("Server", "publishStatistics");
461 
462  s << "[plugins]" << std::endl;
464  {
465  const PluginContainerPtr& p = it->second;
466 
467  // Calculate CPU usage percentage
468  double cpu_perc = p->getLoopUsageStatus().getTimer().getLoopUsagePercentage() * 100;
469 
470  s << " " << p->name() << ": " << std::fixed << cpu_perc << " % (" << std::defaultfloat << p->loopFrequency() << " hz)" << std::endl;
471  }
472 
473 
474  std_msgs::String msg;
475  msg.data = s.str();
476 
477  pub_stats_.publish(msg);
478  updater_.force_update();
479 }
480 
481 }
ed::WorldModel
Definition: world_model.h:21
ed::UpdateRequest
Definition: update_request.h:24
std::string
ed::Server::stepPlugins
void stepPlugins()
Definition: server.cpp:240
types.h
entity.h
ed::Server::reset
void reset(bool keep_all_shapes=false)
Definition: server.cpp:153
std::vector
std::map::find
T find(T... args)
ed::Server::property_key_db_
PropertyKeyDB property_key_db_
Property Key DB.
Definition: server.h:90
std::stringstream
plugin.h
ed::Server::storeEntityMeasurements
void storeEntityMeasurements(const std::string &path) const
Definition: server.cpp:437
geo::Transform3T
ed::InitData
Definition: init_data.h:12
ed::ErrorContext
Definition: error_context.h:14
ed::EntityConstPtr
shared_ptr< const Entity > EntityConstPtr
Definition: types.h:37
tue::config::loadFromYAMLString
bool loadFromYAMLString(const std::string &string, ReaderWriter &config, const ResolveConfig &resolve_config=ResolveConfig::defaultConfig())
tue::config::ReaderWriter::readArray
bool readArray(const std::string &name, const RequiredOrOptional opt=OPTIONAL)
std::vector::push_back
T push_back(T... args)
std::cout
geo::Vec3T::y
T y
tue::config::ReaderWriter
ed::Server::configure
void configure(tue::Configuration &config, bool reconfigure=false)
Definition: server.cpp:49
ed::models::ModelLoader::create
bool create(const UUID &id, const std::string &type, UpdateRequest &req, std::stringstream &error, const bool allow_sdf=false)
create add entity to update_request with id 'id' of the type 'type'. If allow_sdf is true,...
Definition: model_loader.cpp:285
tue::config::ReaderWriter::data
DataPointer data() const
ed::log::error
std::ostream & error()
Definition: logging.cpp:74
ed::Server::updater_
diagnostic_updater::Updater updater_
Profiling.
Definition: server.h:97
ed::PluginContainerPtr
shared_ptr< PluginContainer > PluginContainerPtr
Definition: types.h:51
ed::Server::~Server
virtual ~Server()
Definition: server.cpp:42
measurement.h
tue::config::ReaderWriter::error
const std::string & error() const
std::string::c_str
T c_str(T... args)
tue::config::ReaderWriter::endGroup
bool endGroup()
ed::Server::tf_buffer_
TFBufferPtr tf_buffer_
Definition: server.h:100
ed::UpdateRequest::setPose
void setPose(const UUID &id, const geo::Pose3D &pose)
Definition: update_request.h:132
ed::Server::world_model_
WorldModelConstPtr world_model_
Definition: server.h:74
ed::write
bool write(const std::string &filename, const Measurement &msr)
Definition: write.cpp:21
ed::Server::loadPlugin
PluginContainerPtr loadPlugin(const std::string &plugin_name, tue::Configuration config)
Definition: server.cpp:207
geo::Transform3T::t
Vec3T< T > t
std::map::erase
T erase(T... args)
ed::WorldModelConstPtr
shared_ptr< const WorldModel > WorldModelConstPtr
Definition: types.h:45
tue::config::OPTIONAL
OPTIONAL
tue::config::ReaderWriter::setErrorContext
void setErrorContext(const std::string &context)
ed::Server::initializeWorld
void initializeWorld()
Definition: server.cpp:416
std::map
yaml.h
ed::Server::world_model
WorldModelConstPtr world_model() const
Definition: server.h:53
ed::WorldModel::EntityIterator
Definition: world_model.h:26
ed::UpdateRequestPtr
shared_ptr< UpdateRequest > UpdateRequestPtr
Definition: types.h:47
ed::Server::update
void update()
Definition: server.cpp:289
ed::Server::plugin_containers_
std::map< std::string, PluginContainerPtr > plugin_containers_
Plugins.
Definition: server.h:93
ed::Server::publishStatistics
void publishStatistics()
Definition: server.cpp:457
ed::MeasurementConstPtr
shared_ptr< const Measurement > MeasurementConstPtr
Definition: types.h:33
tue::config::ReaderWriter::endArray
bool endArray()
ed::WorldModelPtr
shared_ptr< WorldModel > WorldModelPtr
Definition: types.h:43
tue::config::ReaderWriter::addError
void addError(const std::string &msg)
tue::config::ReaderWriter::value
bool value(const std::string &name, T &value, RequiredOrOptional opt=REQUIRED)
path.h
plugin_container.h
ed::Server::model_loader_
models::ModelLoader model_loader_
Model loading.
Definition: server.h:84
std::endl
T endl(T... args)
ed::Server::tf_buffer_const_
TFBufferConstPtr tf_buffer_const_
Definition: server.h:101
ed::Server::world_name_
std::string world_name_
World name.
Definition: server.h:77
std::map::begin
T begin(T... args)
ed::Server::initialize
void initialize()
Definition: server.cpp:142
geo::Transform3T::R
Mat3T< T > R
error_context.h
tue::config::ReaderWriter::readGroup
bool readGroup(const std::string &name, const RequiredOrOptional opt=OPTIONAL)
std::fixed
T fixed(T... args)
geo::Vec3T::z
T z
std::string::empty
T empty(T... args)
ed::Server::pub_stats_
ros::Publisher pub_stats_
Definition: server.h:98
serialization.h
ed
Definition: convex_hull.h:8
std::stringstream::str
T str(T... args)
std::map::end
T end(T... args)
ed::Server::Server
Server()
Definition: server.cpp:31
c
void c()
server.h
ed::Server::tf_listener_
ed::shared_ptr< tf2_ros::TransformListener > tf_listener_
Definition: server.h:102
ed::Server::mutex_world_
boost::mutex mutex_world_
Definition: server.h:72
geo::Mat3T::setRPY
void setRPY(T roll, T pitch, T yaw)
write.h
geo::Vec3T::x
T x
tue::config::ReaderWriter::nextArrayItem
bool nextArrayItem()
ed::Server::inactive_plugin_containers_
std::map< std::string, PluginContainerPtr > inactive_plugin_containers_
Definition: server.h:94
writer.h
config
tue::config::ReaderWriter config
world_model.h
tue::config::ReaderWriter::hasError
bool hasError() const