CustomSensorPreloader.cpp
Go to the documentation of this file.
2 
4 #include <gazebo/sensors/Sensor.hh>
5 
6 #include <boost/filesystem.hpp>
7 
8 #include <gazebo/physics/PhysicsFactory.hh>
9 #include <gazebo/sensors/SensorManager.hh>
10 
11 // ignition-common is find_packaged by gazebo
12 #include <ignition/common/StringUtils.hh>
13 
14 namespace fs = boost::filesystem;
15 
16 namespace gazebo
17 {
18 
21 {
22  if (this->deferredLoadThread)
23  {
24  this->deferredLoadThread->join();
25  }
26 };
27 
29 {
31  "gazebo_custom_sensor_preloader", "gazebo::sensors::Sensor");
32 
33  const auto names = loader.getDeclaredClasses();
34  for (const auto& name : names)
35  {
36  std::string type;
37  if (ignition::common::StartsWith(name, "sensors/"))
38  {
39  const auto parts = ignition::common::Split(name, '/');
40  if (parts.size() != 2 || parts[1].empty())
41  {
42  gzerr << "CustomSensorPreloader: Wrong 'name' attribute of custom "
43  << "sensor. It should have the form 'sensors/sensor_type', got "
44  << name << std::endl;
45  continue;
46  }
47  type = parts[1];
48  }
49  else
50  {
51  if (name.find('/') != std::string::npos)
52  {
53  gzerr << "CustomSensorPreloader: Wrong 'name' attribute of custom "
54  << "sensor. It should have the form 'sensors/sensor_type', got "
55  << name << std::endl;
56  continue;
57  }
58  else
59  {
60  gzwarn << "CustomSensorPreloader: Attribute 'name' of custom sensor '"
61  << name << "' is missing the 'sensors/' prefix. This may lead "
62  << "to name collisions. Consider adding the prefix."
63  << std::endl;
64  type = name;
65  }
66  }
67 
68  const auto classType = loader.getClassType(name);
69  const auto classParts = ignition::common::Split(classType, ':');
70 
71  if (classParts.size() != 5)
72  {
73  gzerr << "CustomSensorPreloader: Attribute 'type' of custom sensor "
74  << name << " should have the form 'gazebo::sensors::ClassName', "
75  << "got '" << classType << "' instead." << std::endl;
76  continue;
77  }
78 
79  const auto classname = classParts.back();
80  const auto fullname = loader.getClassLibraryPath(name);
81 
82  if (fullname.empty())
83  {
84  gzerr << "CustomSensorPreloader: Could not find path to the library of "
85  << "custom sensor '" << name << "'." << std::endl;
86  continue;
87  }
88  else if (!fs::exists(fullname))
89  {
90  gzerr << "CustomSensorPreloader: Library '" << fullname << "' of custom "
91  << "sensor '" << name << "' does not exists." << std::endl;
92  continue;
93  }
94 
95  this->ProcessCustomSensor(type, classname, fullname);
96  }
97 
98  // We want to run after SensorFactory::RegisterAll() to be sure the factory
99  // is fully initialized. Therefore, we need to defer the preloading a bit
100  // until it finishes. Unfortunately, there's no nice callback that would get
101  // called when sensors are loaded but before world loading. So we piggyback
102  // on PhysicsFactory, which is known to create the physics engines between
103  // sensors::load() and sensors::init() calls (in gazebo.cc).
104  this->deferredLoadThread.reset(new std::thread(
106 }
107 
109 {
110  // as stated above, wait for physics engine initialization
111  // but if it should take too long, give up the wait - it's very probable that
112  // nothing bad will happen
113  const size_t max_iterations = 2000000;
114  size_t it = 0;
115  while (!gazebo::physics::PhysicsFactory::IsRegistered("ode") && it < max_iterations)
116  {
117  usleep(1);
118  ++it;
119  }
120 
121  // call all the saved registration functions
122  for (const auto& tuple : this->sensorsToRegister)
123  {
124  const auto registerFunc = std::get<0>(*tuple);
125  const auto type = std::get<1>(*tuple);
126  const auto classname = std::get<2>(*tuple);
127  const auto fullname = std::get<3>(*tuple);
128 
129  // Call the registration function
130  (*registerFunc)();
131 
132  std::vector<std::string> types;
133  sensors::SensorManager::Instance()->GetSensorTypes(types);
134 
135  if (std::find(types.begin(), types.end(), type) == types.end())
136  {
137  gzwarn << "CustomSensorPreloader: Custom sensor " << classname
138  << " from library " << fullname
139  << " was preloaded, but it did not register a sensor of type "
140  << type << std::endl;
141  }
142  else
143  {
144  gzmsg << "CustomSensorPreloader: Preloaded custom sensor " << classname
145  << " from library " << fullname << std::endl;
146  }
147  }
148 
149  this->sensorsToRegister.clear();
150 }
151 
152 void CustomSensorPreloader::ProcessCustomSensor(const std::string& _type,
153  const std::string& _classname, const std::string& _fullname)
154 {
155 
156  const auto path = fs::path(_fullname);
157  auto filename = path.filename().string();
158  const auto libraryDir = path.parent_path();
159 
160  // this implementation is inspired by gazebo::common::Plugin<T>::Create()
161 
162 #ifdef __APPLE__
163  {
164  // replace .so with .dylib
165  size_t soSuffix = filename.rfind(".so");
166  if (soSuffix != std::string::npos)
167  {
168  const std::string macSuffix(".dylib");
169  filename.replace(soSuffix, macSuffix.length(), macSuffix);
170  }
171  }
172 #elif _WIN32
173  {
174  // replace .so with .dll
175  size_t soSuffix = filename.rfind(".so");
176  if (soSuffix != std::string::npos)
177  {
178  const std::string winSuffix(".dll");
179  filename.replace(soSuffix, winSuffix.length(), winSuffix);
180  }
181  size_t libPrefix = filename.find("lib");
182  if (libPrefix == 0)
183  {
184  // remove the lib prefix
185  filename.erase(0, 3);
186  }
187  }
188 #endif // ifdef __APPLE__
189 
190  const auto fullname = (libraryDir / fs::path(filename)).string();
191 
192  void *dlHandle = dlopen(fullname.c_str(), RTLD_LAZY|RTLD_GLOBAL);
193  if (!dlHandle)
194  {
195  gzerr << "CustomSensorPreloader: Failed to load custom sensor library "
196  << fullname << ": " << dlerror() << std::endl;
197  return;
198  }
199 
200  // The GZ_REGISTER_STATIC_SENSOR macro generates function RegisterClassName()
201  const auto registerFuncName = "Register" + _classname;
202  const auto registerFunc = (registerFuncType) dlsym(dlHandle, registerFuncName.c_str());
203 
204  if (!registerFunc)
205  {
206  gzerr << "CustomSensorPreloader: Failed to resolve registration function "
207  << registerFuncName << ": " << dlerror() << std::endl
208  << "Did you call GZ_REGISTER_STATIC_SENSOR(\"" << _type << "\", "
209  << _classname << ") inside your sensor source file?" << std::endl;
210  return;
211  }
212 
213  // The actual registerFunc call has to be done in the deferred loading thread.
214  this->sensorsToRegister.insert(std::make_shared<registerTuple>(
215  std::make_tuple(registerFunc, _type, _classname, fullname)));
216 }
217 
218 void CustomSensorPreloader::Load(int _argc, char **_argv)
219 {
220  // Nothing to do here, everything happens in Init()
221 }
222 
223 
225 {
226  // nothing to do here, everything happens in Init()
227 }
228 
229 }
230 
231 GZ_REGISTER_SYSTEM_PLUGIN(gazebo::CustomSensorPreloader)
gazebo::CustomSensorPreloader::Load
void Load(int _argc, char **_argv) override
Definition: CustomSensorPreloader.cpp:218
CustomSensorPreloader.h
class_loader.h
gazebo
pluginlib::ClassLoader::getClassType
virtual std::string getClassType(const std::string &lookup_name)
gazebo::CustomSensorPreloader::Init
void Init() override
Definition: CustomSensorPreloader.cpp:28
gazebo::CustomSensorPreloader::DeferredPreloadSensors
virtual void DeferredPreloadSensors()
We need to register the sensors a little bit later, so we defer the calls to a separate thread.
Definition: CustomSensorPreloader.cpp:108
gazebo::CustomSensorPreloader::Reset
void Reset() override
Definition: CustomSensorPreloader.cpp:224
gazebo::CustomSensorPreloader::~CustomSensorPreloader
~CustomSensorPreloader() override
Definition: CustomSensorPreloader.cpp:20
pluginlib::ClassLoader::getClassLibraryPath
virtual std::string getClassLibraryPath(const std::string &lookup_name)
gazebo::CustomSensorPreloader::deferredLoadThread
std::unique_ptr< std::thread > deferredLoadThread
This thread performs the deferred preloading.
Definition: CustomSensorPreloader.h:46
gazebo::CustomSensorPreloader::CustomSensorPreloader
CustomSensorPreloader()
pluginlib::ClassLoader
gazebo::CustomSensorPreloader
Gazebo system plugin which allows using custom sensors.
Definition: CustomSensorPreloader.h:17
gazebo::CustomSensorPreloader::registerFuncType
void(* registerFuncType)()
Type of the RegisterCustomSensor function generated by GZ_REGISTER_STATIC_SENSOR.
Definition: CustomSensorPreloader.h:32
gazebo::CustomSensorPreloader::ProcessCustomSensor
virtual void ProcessCustomSensor(const std::string &_type, const std::string &_classname, const std::string &_fullname)
Store one custom sensor registration function for deferred loading.
Definition: CustomSensorPreloader.cpp:152
gazebo::CustomSensorPreloader::sensorsToRegister
std::unordered_set< std::shared_ptr< registerTuple > > sensorsToRegister
A set of sensors waiting for deferred registration.
Definition: CustomSensorPreloader.h:51
pluginlib::ClassLoader::getDeclaredClasses
std::vector< std::string > getDeclaredClasses()


gazebo_custom_sensor_preloader
Author(s): Martin Pecka
autogenerated on Sun Sep 3 2023 02:35:25