SensorBase.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 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/GNSS.h>
14 #include <mvsim/Sensors/IMU.h>
16 #include <mvsim/Sensors/Lidar3D.h>
17 #include <mvsim/VehicleBase.h>
18 #include <mvsim/World.h>
19 
20 #include <map>
21 #include <rapidxml.hpp>
22 #include <rapidxml_print.hpp>
23 #include <rapidxml_utils.hpp>
24 #include <sstream> // std::stringstream
25 #include <string>
26 
27 #include "parse_utils.h"
28 #include "xml_utils.h"
29 
30 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
31 #include <mvsim/mvsim-msgs/GenericObservation.pb.h>
32 #include <mvsim/mvsim-msgs/ObservationLidar2D.pb.h>
33 #endif
34 
35 using namespace mvsim;
36 
38 
39 // Explicit registration calls seem to be one (the unique?) way to assure
40 // registration takes place:
42 {
43  static bool done = false;
44  if (done)
45  return;
46  else
47  done = true;
48 
50  REGISTER_SENSOR("rgbd_camera", DepthCameraSensor)
51  REGISTER_SENSOR("camera", CameraSensor)
52  REGISTER_SENSOR("lidar3d", Lidar3D)
53  REGISTER_SENSOR("imu", IMU)
54  REGISTER_SENSOR("gnss", GNSS)
55 }
56 
57 static auto gAllSensorsOriginViz = mrpt::opengl::CSetOfObjects::Create();
58 static auto gAllSensorsFOVViz = mrpt::opengl::CSetOfObjects::Create();
59 static std::mutex gAllSensorVizMtx;
60 
61 mrpt::opengl::CSetOfObjects::Ptr SensorBase::GetAllSensorsOriginViz()
62 {
63  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
64  return gAllSensorsOriginViz;
65 }
66 
67 mrpt::opengl::CSetOfObjects::Ptr SensorBase::GetAllSensorsFOVViz()
68 {
69  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
70  return gAllSensorsFOVViz;
71 }
72 
73 void SensorBase::RegisterSensorFOVViz(const mrpt::opengl::CSetOfObjects::Ptr& o)
74 {
75  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
76  gAllSensorsFOVViz->insert(o);
77 }
78 void SensorBase::RegisterSensorOriginViz(const mrpt::opengl::CSetOfObjects::Ptr& o)
79 {
80  auto lck = mrpt::lockHelper(gAllSensorVizMtx);
81  gAllSensorsOriginViz->insert(o);
82 }
83 
85  : VisualObject(vehicle.getSimulableWorldObject()),
86  Simulable(vehicle.getSimulableWorldObject()),
87  vehicle_(vehicle)
88 {
89 }
90 
91 SensorBase::~SensorBase() = default;
92 
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(
121  mrpt::format("[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, const std::map<std::string, std::string>& varValues)
131 {
132  MRPT_START
133 
134  if (node == nullptr) return false;
135 
136  // Parse XML params:
137  {
138  TParameterDefinitions params;
139  params["publish_topic"] = TParamEntry("%s", &publishTopic_);
140 
141  parse_xmlnode_children_as_param(*node, params, varValues);
142  }
143 
144  // Parse the "enabled" attribute:
145  {
146  bool publishEnabled = true;
147  TParameterDefinitions auxPar;
148  auxPar["enabled"] = TParamEntry("%bool", &publishEnabled);
149  parse_xmlnode_attribs(*node, auxPar, varValues);
150 
151  // Reset publish topic if enabled==false
152  if (!publishEnabled) publishTopic_.clear();
153  }
154 
155  return true;
156  MRPT_END
157 }
158 
160  const std::shared_ptr<mrpt::obs::CObservation>& obs, const TSimulContext& context)
161 {
162  if (!obs) return;
163 
164  // Notify the world:
166 
167  // Publish:
168 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
169  if (!publishTopic_.empty())
170  {
171  mvsim_msgs::GenericObservation msg;
172  msg.set_unixtimestamp(mrpt::Clock::toDouble(obs->timestamp));
173  msg.set_sourceobjectid(vehicle_.getName());
174 
175  std::vector<uint8_t> serializedData;
176  mrpt::serialization::ObjectToOctetVector(obs.get(), serializedData);
177 
178  msg.set_mrptserializedobservation(serializedData.data(), serializedData.size());
179 
180  context.world->commsClient().publishTopic(publishTopic_, msg);
181  }
182 #endif
183 }
184 
186  const std::shared_ptr<mrpt::obs::CObservation2DRangeScan>& obs, const TSimulContext& context)
187 {
188  using namespace std::string_literals;
189 
190 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
191  if (publishTopic_.empty()) return;
192 
193  mvsim_msgs::ObservationLidar2D msg;
194  msg.set_unixtimestamp(mrpt::Clock::toDouble(obs->timestamp));
195  msg.set_sourceobjectid(vehicle_.getName());
196 
197  msg.set_aperture(obs->aperture);
198  for (size_t i = 0; i < obs->getScanSize(); i++)
199  {
200  msg.add_scanranges(obs->getScanRange(i));
201  msg.add_validranges(obs->getScanRangeValidity(i));
202  }
203 
204  msg.set_ccw(obs->rightToLeft);
205  msg.set_maxrange(obs->maxRange);
206 
207  const auto& p = obs->sensorPose;
208  auto sp = msg.mutable_sensorpose();
209  sp->set_x(p.x());
210  sp->set_y(p.y());
211  sp->set_z(p.z());
212  sp->set_yaw(p.yaw());
213  sp->set_pitch(p.pitch());
214  sp->set_roll(p.roll());
215 
216  context.world->commsClient().publishTopic(publishTopic_ + "_scan"s, msg);
217 #endif
218 }
219 
221 {
222  // Default base stuff:
224 
225 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
226  // Topic:
227  if (!publishTopic_.empty()) c.advertiseTopic<mvsim_msgs::GenericObservation>(publishTopic_);
228 #endif
229 }
230 
232 {
233  // Attribs:
234  TParameterDefinitions attribs;
235  attribs["name"] = TParamEntry("%s", &name_);
236  parse_xmlnode_attribs(*root, attribs, {}, "[SensorBase]");
237 
239  varValues_["NAME"] = name_;
240  varValues_["PARENT_NAME"] = vehicle_.getName();
241 
242  // Parse common sensor XML params:
243  this->parseSensorPublish(root->first_node("publish"), varValues_);
244 
245  TParameterDefinitions params;
246  params["sensor_period"] = TParamEntry("%lf", &sensor_period_);
247 
248  // Parse XML params:
250 }
251 
252 void SensorBase::make_sure_we_have_a_name(const std::string& prefix)
253 {
254  if (!name_.empty()) return;
255 
256  size_t nextIdx = 0;
257  if (auto v = dynamic_cast<VehicleBase*>(&vehicle_); v) nextIdx = v->getSensors().size() + 1;
258 
259  name_ = mrpt::format("%s%u", prefix.c_str(), static_cast<unsigned int>(nextIdx));
260 }
261 
263 {
264  // to fix edge cases with sensor period a multiple of simulation timestep:
265  const double timeEpsilon = 1e-6;
266 
267  if (context.simul_time < sensor_last_timestamp_ + sensor_period_ - timeEpsilon) return false;
268 
269  if ((context.simul_time - sensor_last_timestamp_) >= 2 * sensor_period_)
270  {
271  std::cout << "[mvsim::SensorBase] WARNING: "
272  "At least one sensor sample has been lost due to too coarse "
273  "discrete time steps. sensor_period="
274  << sensor_period_ << " [s], (simul_time - sensor_last_timestamp)="
275  << (context.simul_time - sensor_last_timestamp_) << " [s]." << std::endl;
276  }
277 
279 
280  return true;
281 }
mvsim::VisualObject::parent
World * parent()
Definition: VisualObject.h:51
mvsim
Definition: Client.h:21
mvsim::SensorBase::reportNewObservation_lidar_2d
void reportNewObservation_lidar_2d(const std::shared_ptr< mrpt::obs::CObservation2DRangeScan > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:185
mvsim::Simulable::getName
const std::string & getName() const
Definition: Simulable.h:107
mvsim::GNSS
Definition: GNSS.h:25
mvsim::VisualObject::world_
World * world_
Definition: VisualObject.h:73
mvsim::SensorBase::make_sure_we_have_a_name
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:252
mvsim::SensorBase::varValues_
std::map< std::string, std::string > varValues_
Filled in by SensorBase::loadConfigFrom()
Definition: SensorBase.h:97
mvsim::SensorBase::reportNewObservation
void reportNewObservation(const std::shared_ptr< mrpt::obs::CObservation > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:159
parse_utils.h
mvsim::LaserScanner
Definition: LaserScanner.h:31
mvsim::World::dispatchOnObservation
void dispatchOnObservation(const Simulable &veh, const mrpt::obs::CObservation::Ptr &obs)
Definition: World.cpp:243
Lidar3D.h
mvsim::TParamEntry
Definition: TParameterDefinitions.h:38
s
XmlRpcServer s
mvsim::parse_xmlnode_children_as_param
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:215
gAllSensorsOriginViz
static auto gAllSensorsOriginViz
Definition: SensorBase.cpp:57
World.h
mvsim::Client
Definition: Client.h:48
mvsim::SensorBase::vehicle_
Simulable & vehicle_
The vehicle this sensor is attached to.
Definition: SensorBase.h:82
mvsim::ClassFactory::create
Ptr create(const std::string &class_name, ARG1 a1) const
Definition: ClassFactory.h:42
mvsim::TSimulContext::simul_time
double simul_time
Current time in the simulated world.
Definition: basic_types.h:62
mvsim::SensorBase::registerOnServer
void registerOnServer(mvsim::Client &c) override
Definition: SensorBase.cpp:220
mvsim::IMU
Definition: IMU.h:24
mvsim::SensorBase::GetAllSensorsOriginViz
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsOriginViz()
Definition: SensorBase.cpp:61
REGISTER_SENSOR
#define REGISTER_SENSOR(TEXTUAL_NAME, CLASS_NAME)
Definition: SensorBase.h:123
xml_utils.h
mvsim::SensorBase::should_simulate_sensor
bool should_simulate_sensor(const TSimulContext &context)
Definition: SensorBase.cpp:262
rapidxml::xml_attribute
Definition: rapidxml.hpp:138
VehicleBase.h
mvsim::SensorBase::parseSensorPublish
bool parseSensorPublish(const rapidxml::xml_node< char > *node, const std::map< std::string, std::string > &varValues)
Definition: SensorBase.cpp:129
rapidxml
Definition: rapidxml.hpp:57
mvsim::TSimulContext
Definition: basic_types.h:58
mvsim::SensorBase::~SensorBase
virtual ~SensorBase()
rapidxml::xml_node::first_node
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
mvsim::Lidar3D
Definition: Lidar3D.h:30
mvsim::TParameterDefinitions
std::map< std::string, TParamEntry > TParameterDefinitions
Definition: TParameterDefinitions.h:64
mvsim::SensorBase::factory
static SensorBase::Ptr factory(Simulable &parent, const rapidxml::xml_node< char > *xml_node)
Definition: SensorBase.cpp:93
gAllSensorVizMtx
static std::mutex gAllSensorVizMtx
Definition: SensorBase.cpp:59
rapidxml_utils.hpp
mvsim::Simulable::name_
std::string name_
Definition: Simulable.h:145
mvsim::SensorBase::sensor_period_
double sensor_period_
Definition: SensorBase.h:88
mvsim::SensorBase::Ptr
std::shared_ptr< SensorBase > Ptr
Definition: SensorBase.h:37
mvsim::TSimulContext::world
World * world
Definition: basic_types.h:61
mvsim::Simulable::registerOnServer
virtual void registerOnServer(mvsim::Client &c)
Definition: Simulable.cpp:458
DepthCameraSensor.h
mvsim::SensorBase::publishTopic_
std::string publishTopic_
Definition: SensorBase.h:94
mvsim::SensorBase::SensorBase
SensorBase(Simulable &vehicle)
Definition: SensorBase.cpp:84
mvsim::SensorBase::GetAllSensorsFOVViz
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsFOVViz()
Definition: SensorBase.cpp:67
mvsim::VehicleBase
Definition: VehicleBase.h:44
rapidxml::xml_node< char >
mvsim::World::user_defined_variables
const std::map< std::string, std::string > & user_defined_variables() const
Definition: World.h:390
mvsim::SensorBase::sensor_last_timestamp_
double sensor_last_timestamp_
Definition: SensorBase.h:91
mvsim::Simulable
Definition: Simulable.h:39
std
mvsim::CameraSensor
Definition: CameraSensor.h:23
mvsim::Client::advertiseTopic
void advertiseTopic(const std::string &topicName)
Definition: Client.h:177
CameraSensor.h
mvsim::SensorBase::loadConfigFrom
virtual void loadConfigFrom(const rapidxml::xml_node< char > *root)
Definition: SensorBase.cpp:231
IMU.h
mvsim::ClassFactory
Definition: ClassFactory.h:25
mvsim::classFactory_sensors
TClassFactory_sensors classFactory_sensors
Definition: SensorBase.cpp:37
root
root
GNSS.h
mvsim::DepthCameraSensor
Definition: DepthCameraSensor.h:34
LaserScanner.h
rapidxml.hpp
mvsim::parse_xmlnode_attribs
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:182
register_all_sensors
void register_all_sensors()
Definition: SensorBase.cpp:41
mvsim::VisualObject
Definition: VisualObject.h:35
mvsim::SensorBase::RegisterSensorFOVViz
static void RegisterSensorFOVViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:73
mvsim::SensorBase::RegisterSensorOriginViz
static void RegisterSensorOriginViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:78
rapidxml_print.hpp
gAllSensorsFOVViz
static auto gAllSensorsFOVViz
Definition: SensorBase.cpp:58


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08