SensorBase.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2023 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include <mrpt/core/format.h>
13 #include <mvsim/Sensors/IMU.h>
15 #include <mvsim/Sensors/Lidar3D.h>
16 #include <mvsim/VehicleBase.h>
17 #include <mvsim/World.h>
18 
19 #include <map>
20 #include <rapidxml.hpp>
21 #include <rapidxml_print.hpp>
22 #include <rapidxml_utils.hpp>
23 #include <sstream> // std::stringstream
24 #include <string>
25 
26 #include "parse_utils.h"
27 #include "xml_utils.h"
28 
29 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
30 #include <mvsim/mvsim-msgs/GenericObservation.pb.h>
31 #include <mvsim/mvsim-msgs/ObservationLidar2D.pb.h>
32 #endif
33 
34 using namespace mvsim;
35 
37 
38 // Explicit registration calls seem to be one (the unique?) way to assure
39 // registration takes place:
41 {
42  static bool done = false;
43  if (done)
44  return;
45  else
46  done = true;
47 
49  REGISTER_SENSOR("rgbd_camera", DepthCameraSensor)
50  REGISTER_SENSOR("camera", CameraSensor)
51  REGISTER_SENSOR("lidar3d", Lidar3D)
52  REGISTER_SENSOR("imu", IMU)
53 }
54 
55 static auto gAllSensorsOriginViz = mrpt::opengl::CSetOfObjects::Create();
56 static auto gAllSensorsFOVViz = mrpt::opengl::CSetOfObjects::Create();
57 static std::mutex gAllSensorVizMtx;
58 
59 mrpt::opengl::CSetOfObjects::Ptr SensorBase::GetAllSensorsOriginViz()
60 {
61  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
62  return gAllSensorsOriginViz;
63 }
64 
65 mrpt::opengl::CSetOfObjects::Ptr SensorBase::GetAllSensorsFOVViz()
66 {
67  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
68  return gAllSensorsFOVViz;
69 }
70 
71 void SensorBase::RegisterSensorFOVViz(const mrpt::opengl::CSetOfObjects::Ptr& o)
72 {
73  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
74  gAllSensorsFOVViz->insert(o);
75 }
77  const mrpt::opengl::CSetOfObjects::Ptr& o)
78 {
79  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
80  gAllSensorsOriginViz->insert(o);
81 }
82 
86  vehicle_(vehicle)
87 {
88 }
89 
90 SensorBase::~SensorBase() = default;
91 
94 {
96 
97  using namespace std;
98  using namespace rapidxml;
99 
100  if (!root) throw runtime_error("[SensorBase::factory] XML node is nullptr");
101  if (0 != strcmp(root->name(), "sensor"))
102  throw runtime_error(mrpt::format(
103  "[SensorBase::factory] XML root element is '%s' ('sensor' "
104  "expected)",
105  root->name()));
106 
107  // Get "class" attrib:
108  const xml_attribute<>* sensor_class = root->first_attribute("class");
109  if (!sensor_class || !sensor_class->value())
110  throw runtime_error(
111  "[VehicleBase::factory] Missing mandatory attribute 'class' in "
112  "node <sensor>");
113 
114  const string sName = string(sensor_class->value());
115 
116  // Class factory:
117  auto we = classFactory_sensors.create(sName, parent, root);
118 
119  if (!we)
120  throw runtime_error(mrpt::format(
121  "[SensorBase::factory] Unknown sensor type '%s'", root->name()));
122 
123  // parse the optional visual model:
124  we->parseVisual(*root);
125 
126  return we;
127 }
128 
130  const rapidxml::xml_node<char>* node,
131  const std::map<std::string, std::string>& varValues)
132 {
133  MRPT_START
134 
135  if (node == nullptr) return false;
136 
137  // Parse XML params:
138  {
139  TParameterDefinitions params;
140  params["publish_topic"] = TParamEntry("%s", &publishTopic_);
141 
142  parse_xmlnode_children_as_param(*node, params, varValues);
143  }
144 
145  // Parse the "enabled" attribute:
146  {
147  bool publishEnabled = true;
148  TParameterDefinitions auxPar;
149  auxPar["enabled"] = TParamEntry("%bool", &publishEnabled);
150  parse_xmlnode_attribs(*node, auxPar, varValues);
151 
152  // Reset publish topic if enabled==false
153  if (!publishEnabled) publishTopic_.clear();
154  }
155 
156  return true;
157  MRPT_END
158 }
159 
161  const std::shared_ptr<mrpt::obs::CObservation>& obs,
162  const TSimulContext& context)
163 {
164  if (!obs) return;
165 
166  // Notify the world:
168 
169  // Publish:
170 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
171  if (!publishTopic_.empty())
172  {
173  mvsim_msgs::GenericObservation msg;
174  msg.set_unixtimestamp(mrpt::Clock::toDouble(obs->timestamp));
175  msg.set_sourceobjectid(vehicle_.getName());
176 
177  std::vector<uint8_t> serializedData;
178  mrpt::serialization::ObjectToOctetVector(obs.get(), serializedData);
179 
180  msg.set_mrptserializedobservation(
181  serializedData.data(), serializedData.size());
182 
183  context.world->commsClient().publishTopic(publishTopic_, msg);
184  }
185 #endif
186 
187  // Save to .rawlog:
188  if (!save_to_rawlog_.empty())
189  {
190  if (!rawlog_io_)
191  {
192  rawlog_io_ = std::make_shared<mrpt::io::CFileGZOutputStream>(
194  }
195 
196  auto arch = mrpt::serialization::archiveFrom(*rawlog_io_);
197  arch << *obs;
198  }
199 }
200 
202  const std::shared_ptr<mrpt::obs::CObservation2DRangeScan>& obs,
203  const TSimulContext& context)
204 {
205  using namespace std::string_literals;
206 
207 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
208  if (publishTopic_.empty()) return;
209 
210  mvsim_msgs::ObservationLidar2D msg;
211  msg.set_unixtimestamp(mrpt::Clock::toDouble(obs->timestamp));
212  msg.set_sourceobjectid(vehicle_.getName());
213 
214  msg.set_aperture(obs->aperture);
215  for (size_t i = 0; i < obs->getScanSize(); i++)
216  {
217  msg.add_scanranges(obs->getScanRange(i));
218  msg.add_validranges(obs->getScanRangeValidity(i));
219  }
220 
221  msg.set_ccw(obs->rightToLeft);
222  msg.set_maxrange(obs->maxRange);
223 
224  const auto& p = obs->sensorPose;
225  auto sp = msg.mutable_sensorpose();
226  sp->set_x(p.x());
227  sp->set_y(p.y());
228  sp->set_z(p.z());
229  sp->set_yaw(p.yaw());
230  sp->set_pitch(p.pitch());
231  sp->set_roll(p.roll());
232 
233  context.world->commsClient().publishTopic(publishTopic_ + "_scan"s, msg);
234 #endif
235 }
236 
238 {
239  // Default base stuff:
241 
242 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
243  // Topic:
244  if (!publishTopic_.empty())
245  c.advertiseTopic<mvsim_msgs::GenericObservation>(publishTopic_);
246 #endif
247 }
248 
250 {
251  // Attribs:
252  TParameterDefinitions attribs;
253  attribs["name"] = TParamEntry("%s", &name_);
254  parse_xmlnode_attribs(*root, attribs, {}, "[SensorBase]");
255 
257  varValues_["NAME"] = name_;
258  varValues_["PARENT_NAME"] = vehicle_.getName();
259 
260  // Parse common sensor XML params:
261  this->parseSensorPublish(root->first_node("publish"), varValues_);
262 
263  TParameterDefinitions params;
264  params["sensor_period"] = TParamEntry("%lf", &sensor_period_);
265  params["save_to_rawlog"] = TParamEntry("%s", &save_to_rawlog_);
266 
267  // Parse XML params:
268  parse_xmlnode_children_as_param(*root, params, varValues_);
269 }
270 
271 void SensorBase::make_sure_we_have_a_name(const std::string& prefix)
272 {
273  if (!name_.empty()) return;
274 
275  size_t nextIdx = 0;
276  if (auto v = dynamic_cast<VehicleBase*>(&vehicle_); v)
277  nextIdx = v->getSensors().size() + 1;
278 
279  name_ = mrpt::format(
280  "%s%u", prefix.c_str(), static_cast<unsigned int>(nextIdx));
281 }
282 
284 {
285  // to fix edge cases with sensor period a multiple of simulation timestep:
286  const double timeEpsilon = 1e-6;
287 
288  if (context.simul_time <
289  sensor_last_timestamp_ + sensor_period_ - timeEpsilon)
290  return false;
291 
292  if ((context.simul_time - sensor_last_timestamp_) >= 2 * sensor_period_)
293  {
294  std::cout
295  << "[mvsim::SensorBase] WARNING: "
296  "At least one sensor sample has been lost due to too coarse "
297  "discrete time steps. sensor_period="
298  << sensor_period_ << " [s], (simul_time - sensor_last_timestamp)="
299  << (context.simul_time - sensor_last_timestamp_) << " [s]."
300  << std::endl;
301  }
302 
304 
305  return true;
306 }
static auto gAllSensorsFOVViz
Definition: SensorBase.cpp:56
This file contains rapidxml parser and DOM implementation.
std::string publishTopic_
Definition: SensorBase.h:89
std::map< std::string, TParamEntry > TParameterDefinitions
void parse_xmlnode_children_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="", mrpt::system::COutputLogger *logger=nullptr)
Definition: xml_utils.cpp:224
A 2D lidar scanner, with FOV up to 360 degrees.
Definition: LaserScanner.h:31
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsFOVViz()
Definition: SensorBase.cpp:65
static void RegisterSensorFOVViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:71
XmlRpcServer s
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsOriginViz()
Definition: SensorBase.cpp:59
double simul_time
Current time in the simulated world.
Definition: basic_types.h:59
void publishTopic(const std::string &topicName, const google::protobuf::Message &msg)
bool should_simulate_sensor(const TSimulContext &context)
Definition: SensorBase.cpp:283
std::map< std::string, std::string > varValues_
Filled in by SensorBase::loadConfigFrom()
Definition: SensorBase.h:92
void parse_xmlnode_attribs(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="")
Definition: xml_utils.cpp:184
bool parseSensorPublish(const rapidxml::xml_node< char > *node, const std::map< std::string, std::string > &varValues)
Definition: SensorBase.cpp:129
Ch * name() const
Definition: rapidxml.hpp:673
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
static void RegisterSensorOriginViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:76
Simulable & vehicle_
The vehicle this sensor is attached to.
Definition: SensorBase.h:74
void registerOnServer(mvsim::Client &c) override
Definition: SensorBase.cpp:237
std::shared_ptr< mrpt::io::CFileGZOutputStream > rawlog_io_
Definition: SensorBase.h:83
void reportNewObservation(const std::shared_ptr< mrpt::obs::CObservation > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:160
std::shared_ptr< SensorBase > Ptr
Definition: SensorBase.h:29
static std::mutex gAllSensorVizMtx
Definition: SensorBase.cpp:57
std::string name_
Definition: Simulable.h:120
void register_all_sensors()
Definition: SensorBase.cpp:40
const std::map< std::string, std::string > & user_defined_variables() const
Definition: World.h:391
virtual void registerOnServer(mvsim::Client &c)
Definition: Simulable.cpp:406
An Inertial Measurement Unit (IMU) sensor.
Definition: IMU.h:25
const std::string & getName() const
Definition: Simulable.h:92
virtual ~SensorBase()
void dispatchOnObservation(const Simulable &veh, const mrpt::obs::CObservation::Ptr &obs)
Definition: World.h:367
double sensor_period_
Definition: SensorBase.h:80
virtual void loadConfigFrom(const rapidxml::xml_node< char > *root)
Definition: SensorBase.cpp:249
double sensor_last_timestamp_
Definition: SensorBase.h:86
Ch * value() const
Definition: rapidxml.hpp:692
A 3D LiDAR sensor, with 360 degrees horizontal fielf-of-view, and a configurable vertical FOV...
Definition: Lidar3D.h:29
TClassFactory_sensors classFactory_sensors
Definition: SensorBase.cpp:36
void advertiseTopic(const std::string &topicName)
Definition: Client.h:187
#define REGISTER_SENSOR(TEXTUAL_NAME, CLASS_NAME)
Definition: SensorBase.h:122
Ptr create(const std::string &class_name, ARG1 a1) const
Definition: ClassFactory.h:40
This file contains rapidxml printer implementation.
void reportNewObservation_lidar_2d(const std::shared_ptr< mrpt::obs::CObservation2DRangeScan > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:201
mvsim::Client & commsClient()
Definition: World.h:379
std::string save_to_rawlog_
Definition: SensorBase.h:82
SensorBase(Simulable &vehicle)
Definition: SensorBase.cpp:83
static SensorBase::Ptr factory(Simulable &parent, const rapidxml::xml_node< char > *xml_node)
Definition: SensorBase.cpp:92
void make_sure_we_have_a_name(const std::string &prefix)
Assign a sensible default name/sensor label if none is provided:
Definition: SensorBase.cpp:271
static auto gAllSensorsOriginViz
Definition: SensorBase.cpp:55
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
World * getSimulableWorldObject()
Definition: Simulable.h:113


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:21