VehicleBase.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/lock_helper.h>
11 #include <mrpt/math/TPose2D.h>
12 #include <mrpt/opengl/CPolyhedron.h>
13 #include <mrpt/poses/CPose2D.h>
14 #include <mrpt/system/filesystem.h>
15 #include <mvsim/FrictionModels/DefaultFriction.h> // For use as default model
17 #include <mvsim/VehicleBase.h>
21 #include <mvsim/World.h>
22 
23 #include <map>
24 #include <rapidxml.hpp>
25 #include <string>
26 
27 #include "JointXMLnode.h"
28 #include "XMLClassesRegistry.h"
29 #include "parse_utils.h"
30 #include "xml_utils.h"
31 
32 using namespace mvsim;
33 using namespace std;
34 
35 static XmlClassesRegistry veh_classes_registry("vehicle:class");
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 
54 }
55 
56 constexpr char VehicleBase::DL_TIMESTAMP[];
57 constexpr char VehicleBase::LOGGER_POSE[];
58 constexpr char VehicleBase::LOGGER_WHEEL[];
59 
60 constexpr char VehicleBase::PL_Q_X[];
61 constexpr char VehicleBase::PL_Q_Y[];
62 constexpr char VehicleBase::PL_Q_Z[];
63 constexpr char VehicleBase::PL_Q_YAW[];
64 constexpr char VehicleBase::PL_Q_PITCH[];
65 constexpr char VehicleBase::PL_Q_ROLL[];
66 constexpr char VehicleBase::PL_DQ_X[];
67 constexpr char VehicleBase::PL_DQ_Y[];
68 constexpr char VehicleBase::PL_DQ_Z[];
69 
70 constexpr char VehicleBase::WL_TORQUE[];
71 constexpr char VehicleBase::WL_WEIGHT[];
72 constexpr char VehicleBase::WL_VEL_X[];
73 constexpr char VehicleBase::WL_VEL_Y[];
74 constexpr char VehicleBase::WL_FRIC_X[];
75 constexpr char VehicleBase::WL_FRIC_Y[];
76 
77 // Protected ctor:
78 VehicleBase::VehicleBase(World* parent, size_t nWheels)
79  : VisualObject(parent), Simulable(parent), fixture_wheels_(nWheels, nullptr)
80 {
81  // Create wheels:
82  for (size_t i = 0; i < nWheels; i++) wheels_info_.emplace_back(parent);
83 
84  // Default shape:
85  chassis_poly_.emplace_back(-0.4, -0.5);
86  chassis_poly_.emplace_back(-0.4, 0.5);
87  chassis_poly_.emplace_back(0.4, 0.5);
88  chassis_poly_.emplace_back(0.6, 0.3);
89  chassis_poly_.emplace_back(0.6, -0.3);
90  chassis_poly_.emplace_back(0.4, -0.5);
92 }
93 
97  const World& parent, const rapidxml::xml_node<char>* xml_node)
98 {
99  // Sanity checks:
100  if (!xml_node) throw runtime_error("[VehicleBase::register_vehicle_class] XML node is nullptr");
101  if (0 != strcmp(xml_node->name(), "vehicle:class"))
102  throw runtime_error(mrpt::format(
103  "[VehicleBase::register_vehicle_class] XML element is '%s' "
104  "('vehicle:class' expected)",
105  xml_node->name()));
106 
107  // Delay the replacement of this variable (used in Sensors) until
108  // "veh" is constructed and we actually have a name:
109  const std::set<std::string> varsRetain = {
110  "NAME" /*sensor name*/, "PARENT_NAME" /*vehicle name*/};
111 
112  // Parse XML to solve for includes:
114 }
115 
119 {
121 
122  using namespace std;
123  using namespace rapidxml;
124 
125  if (!root) throw runtime_error("[VehicleBase::factory] XML node is nullptr");
126  if (0 != strcmp(root->name(), "vehicle"))
127  throw runtime_error(mrpt::format(
128  "[VehicleBase::factory] XML root element is '%s' ('vehicle' "
129  "expected)",
130  root->name()));
131 
132  // "class": When a vehicle has a 'class="XXX"' attribute, look for each
133  // parameter
134  // in the set of "root" + "class_root" XML nodes:
135  // --------------------------------------------------------------------------------
136  JointXMLnode<> nodes;
137 
138  std::vector<XML_Doc_Data::Ptr> scopedLifeDocs;
139 
140  // Solve includes:
141  for (auto n = root->first_node(); n; n = n->next_sibling())
142  {
143  if (strcmp(n->name(), "include") != 0) continue;
144 
145  auto fileAttrb = n->first_attribute("file");
146  ASSERTMSG_(fileAttrb, "XML tag '<include />' must have a 'file=\"xxx\"' attribute)");
147 
148  const std::string relFile =
149  mvsim::parse(fileAttrb->value(), parent->user_defined_variables());
150  const auto absFile = parent->local_to_abs_path(relFile);
151  parent->logStr(
152  mrpt::system::LVL_DEBUG,
153  mrpt::format("XML parser: including file: '%s'", absFile.c_str()));
154 
155  std::map<std::string, std::string> vars;
156  // Inherit the user-defined variables from parent scope
157  vars = parent->user_defined_variables();
158  // Plus new ones:
159  for (auto attr = n->first_attribute(); attr; attr = attr->next_attribute())
160  {
161  if (strcmp(attr->name(), "file") == 0) continue;
162  vars[attr->name()] = attr->value();
163  }
164 
165  // Delay the replacement of this variable (used in Sensors) until "veh"
166  // is constructed and we actually have a name:
167  std::set<std::string> varsRetain = {"NAME" /*sensor name*/, "PARENT_NAME" /*vehicle name*/};
168 
169  const auto [xml, nRoot] = readXmlAndGetRoot(absFile, vars, varsRetain);
170 
171  // the XML document object must exist during this whole function scope
172  scopedLifeDocs.emplace_back(xml);
173 
174  // recursive parse:
175  nodes.add(nRoot->parent());
176  }
177 
178  // ---
179  // Always search in root. Also in the class root, if any:
180  nodes.add(root);
181 
182  if (const xml_attribute<>* veh_class = root->first_attribute("class"); veh_class)
183  {
184  const string sClassName = veh_class->value();
185  const rapidxml::xml_node<char>* class_root = veh_classes_registry.get(sClassName);
186  if (!class_root)
187  throw runtime_error(mrpt::format(
188  "[VehicleBase::factory] Vehicle class '%s' undefined", sClassName.c_str()));
189 
190  nodes.add(class_root);
191  }
192 
193  // Class factory according to: <dynamics class="XXX">
194  // -------------------------------------------------
195 
196  const xml_node<>* dyn_node = nodes.first_node("dynamics");
197  if (!dyn_node) throw runtime_error("[VehicleBase::factory] Missing XML node <dynamics>");
198 
199  const xml_attribute<>* dyn_class = dyn_node->first_attribute("class");
200  if (!dyn_class || !dyn_class->value())
201  throw runtime_error(
202  "[VehicleBase::factory] Missing mandatory attribute 'class' in "
203  "node <dynamics>");
204 
205  VehicleBase::Ptr veh = classFactory_vehicleDynamics.create(dyn_class->value(), parent);
206  if (!veh)
207  throw runtime_error(mrpt::format(
208  "[VehicleBase::factory] Unknown vehicle dynamics class '%s'", dyn_class->value()));
209 
210  // Initialize here all common params shared by any polymorphic class:
211  // -------------------------------------------------
212  // attrib: name
213  {
214  const xml_attribute<>* attrib_name = root->first_attribute("name");
215  if (attrib_name && attrib_name->value())
216  {
217  veh->name_ = mvsim::parse_variables(attrib_name->value(), {}, {});
218  }
219  else
220  {
221  // Default name:
222  static int cnt = 0;
223  veh->name_ = mrpt::format("veh%i", ++cnt);
224  }
225  }
226 
227  // Custom visualization 3D model:
228  // -----------------------------------------------------------
229  veh->parseVisual(nodes);
230 
231  // Initialize class-specific params (mass, chassis shape, etc.)
232  // ---------------------------------------------------------------
233  veh->dynamics_load_params_from_xml(dyn_node);
234 
235  // Auto shape node from visual?
236  if (const rapidxml::xml_node<char>* xml_chassis = dyn_node->first_node("chassis"); xml_chassis)
237  {
238  if (const rapidxml::xml_node<char>* sfv = xml_chassis->first_node("shape_from_visual"); sfv)
239  {
240  const auto& bbVis = veh->collisionShape();
241  if (!bbVis.has_value())
242  {
243  THROW_EXCEPTION(
244  "Error: Tag <shape_from_visual/> found but no "
245  "<visual> entry seems to have been found while parsing "
246  "<vehicle>");
247  }
248  const auto& bb = bbVis.value();
249  if (bb.volume() == 0)
250  {
251  THROW_EXCEPTION(
252  "Error: Tag <shape_from_visual/> found but bounding box of "
253  "visual object seems incorrect, while parsing <vehicle>");
254  }
255 
256  // Set contour polygon:
257  veh->chassis_poly_ = bb.getContour();
258  veh->chassis_z_min_ = bb.zMin();
259  veh->chassis_z_max_ = bb.zMax();
260  }
261  else
262  {
263  // Update collision shape from shape loaded from XML:
264  Shape2p5 cs;
265  cs.setShapeManual(veh->chassis_poly_, veh->chassis_z_min_, veh->chassis_z_max_);
266 
267  veh->setCollisionShape(cs);
268  }
269  }
270 
271  veh->updateMaxRadiusFromPoly();
272 
273  // Common setup for simulable objects:
274  // -----------------------------------------------------------
275  veh->parseSimulable(nodes);
276 
277  // <Optional> Log path. If not specified, app folder will be used
278  // -----------------------------------------------------------
279  {
280  const xml_node<>* log_path_node = nodes.first_node("log_path");
281  if (log_path_node)
282  {
283  // Parse:
284  veh->log_path_ = log_path_node->value();
285  }
286  }
287 
288  veh->initLoggers();
289 
290  // Register bodies, fixtures, etc. in Box2D simulator:
291  // ----------------------------------------------------
292  veh->create_multibody_system(*parent->getBox2DWorld());
293 
294  if (veh->b2dBody_)
295  {
296  // Init pos:
297  const auto q = parent->applyWorldRenderOffset(veh->getPose());
298  const auto dq = veh->getTwist();
299 
300  veh->b2dBody_->SetTransform(b2Vec2(q.x, q.y), q.yaw);
301  // Init vel:
302  veh->b2dBody_->SetLinearVelocity(b2Vec2(dq.vx, dq.vy));
303  veh->b2dBody_->SetAngularVelocity(dq.omega);
304  }
305 
306  // Friction model:
307  // Parse <friction> node, or assume default linear model:
308  // -----------------------------------------------------------
309  {
310  const xml_node<>* frict_node = nodes.first_node("friction");
311  if (!frict_node)
312  {
313  // Default:
314  veh->friction_ = std::make_shared<DefaultFriction>(*veh, nullptr /*default */);
315  }
316  else
317  {
318  // Parse:
319  veh->friction_ = std::shared_ptr<FrictionBase>(FrictionBase::factory(*veh, frict_node));
320  ASSERT_(veh->friction_);
321  }
322  }
323 
324  // Sensors: <sensor class='XXX'> entries
325  // -------------------------------------------------
326  for (const auto& xmlNode : nodes)
327  {
328  if (!strcmp(xmlNode->name(), "sensor"))
329  {
330  SensorBase::Ptr se = SensorBase::factory(*veh, xmlNode);
331  veh->sensors_.push_back(SensorBase::Ptr(se));
332  }
333  }
334 
335  return veh;
336 }
337 
338 VehicleBase::Ptr VehicleBase::factory(World* parent, const std::string& xml_text)
339 {
340  // Parse the string as if it was an XML file:
341  std::stringstream s;
342  s.str(xml_text);
343 
344  char* input_str = const_cast<char*>(xml_text.c_str());
346  try
347  {
348  xml.parse<0>(input_str);
349  }
350  catch (rapidxml::parse_error& e)
351  {
352  unsigned int line = static_cast<long>(std::count(input_str, e.where<char>(), '\n') + 1);
353  throw std::runtime_error(mrpt::format(
354  "[VehicleBase::factory] XML parse error (Line %u): %s", static_cast<unsigned>(line),
355  e.what()));
356  }
357  return VehicleBase::factory(parent, xml.first_node());
358 }
359 
361 {
363  for (auto& s : sensors_) s->simul_pre_timestep(context);
364 
365  // Update wheels position (they may turn, etc. as in an Ackermann
366  // configuration)
367  for (size_t i = 0; i < fixture_wheels_.size(); i++)
368  {
369  b2PolygonShape* wheelShape = dynamic_cast<b2PolygonShape*>(fixture_wheels_[i]->GetShape());
370  wheelShape->SetAsBox(
371  wheels_info_[i].diameter * 0.5, wheels_info_[i].width * 0.5,
372  b2Vec2(wheels_info_[i].x, wheels_info_[i].y), wheels_info_[i].yaw);
373  }
374 
375  // Apply motor forces/torques:
376  const std::vector<double> wheelTorque = invoke_motor_controllers(context);
377 
378  // Apply friction model at each wheel:
379  const size_t nW = getNumWheels();
380  ASSERT_EQUAL_(wheelTorque.size(), nW);
381 
382  // Part of the vehicle weight on each wheel:
383  const double gravity = parent()->get_gravity();
384  MRPT_TODO("Use chassis cog point");
385  const double massPerWheel = getChassisMass() / nW;
386  const double weightPerWheel = massPerWheel * gravity;
387 
388  const std::vector<mrpt::math::TVector2D> wheelLocalVels =
390 
391  ASSERT_EQUAL_(wheelLocalVels.size(), nW);
392 
393  // For visualization only
394  std::vector<mrpt::math::TSegment3D> forceVectors, torqueVectors;
395 
396  for (size_t i = 0; i < nW; i++)
397  {
398  // prepare data:
399  Wheel& w = getWheelInfo(i);
400 
401  FrictionBase::TFrictionInput fi(context, w);
402  fi.motorTorque = -wheelTorque[i]; // "-" => Forwards is negative
403  fi.weight = weightPerWheel;
404  fi.wheelCogLocalVel = wheelLocalVels[i];
405 
406  friction_->setLogger(getLoggerPtr(LOGGER_WHEEL + std::to_string(i + 1)));
407 
408  // eval friction (in the frame of the vehicle):
409  const mrpt::math::TPoint2D F_r = friction_->evaluate_friction(fi);
410 
411  // Apply force:
412  // Force vector -> world coords
413  const b2Vec2 wForce = b2dBody_->GetWorldVector(b2Vec2(F_r.x, F_r.y));
414  // Application point -> world coords
415  const b2Vec2 wPt = b2dBody_->GetWorldPoint(b2Vec2(w.x, w.y));
416 
417  // printf("w%i: Lx=%6.3f Ly=%6.3f | Gx=%11.9f
418  // Gy=%11.9f\n",(int)i,net_force_.x,net_force_.y,wForce.x,wForce.y);
419 
420  b2dBody_->ApplyForce(wForce, wPt, true /*wake up*/);
421 
422  // log
423  {
424  auto& l = loggers_[LOGGER_WHEEL + std::to_string(i + 1)];
425  ASSERT_(l);
426  auto& logger = *l;
427  logger.updateColumn(DL_TIMESTAMP, context.simul_time);
428  logger.updateColumn(WL_TORQUE, fi.motorTorque);
429  logger.updateColumn(WL_WEIGHT, fi.weight);
430  logger.updateColumn(WL_VEL_X, fi.wheelCogLocalVel.x);
431  logger.updateColumn(WL_VEL_Y, fi.wheelCogLocalVel.y);
432  logger.updateColumn(WL_FRIC_X, F_r.x);
433  logger.updateColumn(WL_FRIC_Y, F_r.y);
434  }
435 
436  // save it for optional rendering:
438  {
439  // [meters/N]
440  const double forceScale = world_->guiOptions_.force_scale;
441 
442  const mrpt::math::TPoint3D pt1(wPt.x, wPt.y, chassis_z_max_ * 1.1 + getPose().z);
443  const mrpt::math::TPoint3D pt2 =
444  pt1 + mrpt::math::TPoint3D(wForce.x, wForce.y, 0) * forceScale;
445 
446  forceVectors.emplace_back(pt1, pt2);
447 
448  const mrpt::math::TPoint3D pt2_t =
449  pt1 + mrpt::math::TPoint3D(0, 0, wheelTorque[i]) * forceScale;
450 
451  torqueVectors.emplace_back(pt1, pt2_t);
452  }
453  }
454 
455  // Save forces for optional rendering:
457  {
458  std::lock_guard<std::mutex> csl(forceSegmentsForRenderingMtx_);
459  forceSegmentsForRendering_ = forceVectors;
460  torqueSegmentsForRendering_ = torqueVectors;
461  }
462 }
463 
467 {
469 
470  // Common part (update q_, dq_)
472  for (auto& s : sensors_) s->simul_post_timestep(context);
473 
474  // Integrate wheels' rotation:
475  const size_t nW = getNumWheels();
476 
477  for (size_t i = 0; i < nW; i++)
478  {
479  // prepare data:
480  Wheel& w = getWheelInfo(i);
481 
482  // Explicit Euler:
483  w.setPhi(w.getPhi() + w.getW() * context.dt);
484 
485  // Wrap wheel spin position (angle), so it doesn't
486  // become excessively large (it's actually unbound, but we don't want to
487  // lose 'double' accuracy):
488  const double cur_abs_phi = std::abs(w.getPhi());
489  if (cur_abs_phi > 1e4)
490  w.setPhi(::fmod(cur_abs_phi, 2 * M_PI) * (w.getPhi() < 0.0 ? -1.0 : 1.0));
491  }
492 
493  const auto q = getPose();
494  const auto dq = getTwist();
495 
496  {
497  auto& l = loggers_[LOGGER_POSE];
498  ASSERT_(l);
499  auto& logger = *l;
500  logger.updateColumn(DL_TIMESTAMP, context.simul_time);
501  logger.updateColumn(PL_Q_X, q.x);
502  logger.updateColumn(PL_Q_Y, q.y);
503  logger.updateColumn(PL_Q_Z, q.z);
504  logger.updateColumn(PL_Q_YAW, q.yaw);
505  logger.updateColumn(PL_Q_PITCH, q.pitch);
506  logger.updateColumn(PL_Q_ROLL, q.roll);
507  logger.updateColumn(PL_DQ_X, dq.vx);
508  logger.updateColumn(PL_DQ_Y, dq.vy);
509  logger.updateColumn(PL_DQ_Z, dq.omega);
510  }
511 
512  {
513  writeLogStrings();
514  }
515 }
516 
518 std::vector<mrpt::math::TVector2D> VehicleBase::getWheelsVelocityLocal(
519  const mrpt::math::TTwist2D& veh_vel_local) const
520 {
521  // Each wheel velocity is:
522  // v_w = v_veh + \omega \times wheel_pos
523  // =>
524  // v_w = v_veh + ( -w*y, w*x )
525 
526  const double w = veh_vel_local.omega; // vehicle w
527 
528  const size_t nW = this->getNumWheels();
529  std::vector<mrpt::math::TVector2D> vels(nW);
530 
531  for (size_t i = 0; i < nW; i++)
532  {
533  const Wheel& wheel = getWheelInfo(i);
534 
535  vels[i].x = veh_vel_local.vx - w * wheel.y;
536  vels[i].y = veh_vel_local.vy + w * wheel.x;
537  }
538  return vels;
539 }
540 
542  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
543  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical)
544 {
545  for (auto& s : sensors_) s->guiUpdate(viz, physical);
546 }
547 
549  [[maybe_unused]] mrpt::opengl::COpenGLScene& scene)
550 {
552  {
553  std::lock_guard<std::mutex> csl(forceSegmentsForRenderingMtx_);
554  glForces_->clear();
556  glForces_->setVisibility(true);
557 
558  glMotorTorques_->clear();
560  glMotorTorques_->setVisibility(true);
561  }
562  else
563  {
564  glForces_->setVisibility(false);
565  glMotorTorques_->setVisibility(false);
566  }
567 }
568 
570 {
571  if (loggers_.empty()) return false;
572  auto& l = loggers_.begin()->second;
573 
574  return l && l->isOpen();
575 }
576 
578 {
579  using namespace mrpt::math;
580 
581  maxRadius_ = 0.001f;
582  for (const auto& pt : chassis_poly_)
583  {
584  const float n = pt.norm();
585  mrpt::keep_max(maxRadius_, n);
586  }
587 }
588 
591 {
592  // Define the dynamic body. We set its position and call the body factory.
593  b2BodyDef bodyDef;
594  bodyDef.type = b2_dynamicBody;
595 
596  b2dBody_ = world.CreateBody(&bodyDef);
597 
598  // Define shape of chassis:
599  // ------------------------------
600  {
601  // Convert shape into Box2D format:
602  const size_t nPts = chassis_poly_.size();
603  ASSERT_(nPts >= 3);
604  ASSERT_LE_(nPts, (size_t)b2_maxPolygonVertices);
605  std::vector<b2Vec2> pts(nPts);
606  for (size_t i = 0; i < nPts; i++) pts[i] = b2Vec2(chassis_poly_[i].x, chassis_poly_[i].y);
607 
608  b2PolygonShape chassisPoly;
609  chassisPoly.Set(&pts[0], nPts);
610 
611  // FIXED value by design in b2Box: The "skin" depth of the body
612  chassisPoly.m_radius = 2.5e-3; // b2_polygonRadius;
613 
614  // Define the dynamic body fixture.
615  b2FixtureDef fixtureDef;
616  fixtureDef.shape = &chassisPoly;
617  fixtureDef.restitution = 0.01;
618 
619  // Set the box density to be non-zero, so it will be dynamic.
620  b2MassData mass;
621  // Mass with density=1 => compute area
622  chassisPoly.ComputeMass(&mass, 1);
623  fixtureDef.density = chassis_mass_ / mass.mass;
624 
625  // Override the default friction.
626  fixtureDef.friction = 0;
627 
628  // Add the shape to the body.
629  fixture_chassis_ = b2dBody_->CreateFixture(&fixtureDef);
630 
631  // Compute center of mass:
632  b2MassData vehMass;
633  fixture_chassis_->GetMassData(&vehMass);
634  chassis_com_.x = vehMass.center.x;
635  chassis_com_.y = vehMass.center.y;
636  }
637 
638  // Define shape of wheels:
639  // ------------------------------
640  ASSERT_EQUAL_(fixture_wheels_.size(), wheels_info_.size());
641 
642  for (size_t i = 0; i < wheels_info_.size(); i++)
643  {
644  b2PolygonShape wheelShape;
645  wheelShape.SetAsBox(
646  wheels_info_[i].diameter * 0.5, wheels_info_[i].width * 0.5,
647  b2Vec2(wheels_info_[i].x, wheels_info_[i].y), wheels_info_[i].yaw);
648 
649  // Define the dynamic body fixture.
650  b2FixtureDef fixtureDef;
651  fixtureDef.shape = &wheelShape;
652  fixtureDef.restitution = 0.05;
653 
654  // Set the box density to be non-zero, so it will be dynamic.
655  b2MassData mass;
656  wheelShape.ComputeMass(&mass, 1); // Mass with density=1 => compute area
657  fixtureDef.density = wheels_info_[i].mass / mass.mass;
658 
659  // Override the default friction.
660  fixtureDef.friction = 0.5f;
661 
662  fixture_wheels_[i] = b2dBody_->CreateFixture(&fixtureDef);
663  }
664 }
665 
667  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
668  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical, bool childrenOnly)
669 {
670  // 1st time call?? -> Create objects
671  // ----------------------------------
672  const size_t nWs = this->getNumWheels();
673  if (!glChassisViz_ && viz && physical)
674  {
675  glChassisViz_ = mrpt::opengl::CSetOfObjects::Create();
676  glChassisViz_->setName("vehicle_chassis_"s + name_);
677 
678  glChassisPhysical_ = mrpt::opengl::CSetOfObjects::Create();
679  glChassisPhysical_->setName("vehicle_chassis_"s + name_);
680 
681  // Wheels shape:
682  glWheelsViz_.resize(nWs);
683  glWheelsPhysical_.resize(nWs);
684  for (size_t i = 0; i < nWs; i++)
685  {
686  glWheelsViz_[i] = mrpt::opengl::CSetOfObjects::Create();
687  this->getWheelInfo(i).getAs3DObject(*glWheelsViz_[i], false);
688  glChassisViz_->insert(glWheelsViz_[i]);
689 
690  glWheelsPhysical_[i] = mrpt::opengl::CSetOfObjects::Create();
691  this->getWheelInfo(i).getAs3DObject(*glWheelsPhysical_[i], true);
693  }
694 
695  if (!childrenOnly)
696  {
697  // Robot shape:
698  auto gl_poly = mrpt::opengl::CPolyhedron::CreateCustomPrism(
700  gl_poly->setLocation(0, 0, chassis_z_min_);
701  gl_poly->setColor_u8(chassis_color_);
702  glChassisViz_->insert(gl_poly);
703  glChassisPhysical_->insert(gl_poly);
704  }
705 
706  viz->get().insert(glChassisViz_);
707  physical->get().insert(glChassisPhysical_);
708 
709  glInit_ = true;
710  }
711 
712  // Update them:
713  // ----------------------------------
714  // If "viz" does not have a value, it's because we are already inside a
715  // setPose() change event, so my caller already holds the mutex and we don't
716  // need/can't acquire it again:
717  const auto objectPose = viz.has_value() ? getPose() : getPoseNoLock();
718  const auto pp = parent()->applyWorldRenderOffset(objectPose);
719 
720  if (glInit_)
721  {
722  glChassisViz_->setPose(pp);
723  glChassisPhysical_->setPose(pp);
724  for (size_t i = 0; i < nWs; i++)
725  {
726  const Wheel& w = getWheelInfo(i);
727  glWheelsPhysical_[i]->setPose(
728  mrpt::math::TPose3D(w.x, w.y, 0.5 * w.diameter, w.yaw, w.getPhi(), 0.0));
729  glWheelsViz_[i]->setPose(
730  mrpt::math::TPose3D(w.x, w.y, 0.5 * w.diameter, w.yaw, w.getPhi(), 0.0));
731 
732  if (!w.linked_yaw_object_name.empty())
733  {
734  auto glLinked = VisualObject::glCustomVisual_->getByName(w.linked_yaw_object_name);
735  if (!glLinked)
736  {
737  THROW_EXCEPTION_FMT(
738  "Wheel #%zu has linked_yaw_object_name='%s' but parent "
739  "vehicle '%s' does not have any custom visual group "
740  "with that name.",
741  i, w.linked_yaw_object_name.c_str(), name_.c_str());
742  }
743  auto p = glLinked->getPose();
744  p.yaw = w.yaw + w.linked_yaw_offset;
745  glLinked->setPose(p);
746  }
747  }
748  }
749 
750  // Init on first use:
751  if (!glForces_ && viz)
752  {
753  // Visualization of forces:
754  glForces_ = mrpt::opengl::CSetOfLines::Create();
755  glForces_->setLineWidth(3.0);
756  glForces_->setColor_u8(0xff, 0xff, 0xff);
757  glForces_->setPose(parent()->applyWorldRenderOffset(mrpt::poses::CPose3D::Identity()));
758 
759  viz->get().insert(glForces_); // forces are in global coords
760  }
761  if (!glMotorTorques_ && viz)
762  {
763  // Visualization of forces:
764  glMotorTorques_ = mrpt::opengl::CSetOfLines::Create();
765  glMotorTorques_->setLineWidth(3.0);
766  glMotorTorques_->setColor_u8(0xff, 0x00, 0x00);
767  glMotorTorques_->setPose(
768  parent()->applyWorldRenderOffset(mrpt::poses::CPose3D::Identity()));
769  viz->get().insert(glMotorTorques_); // torques are in global coords
770  }
771 
772  // Other common stuff:
773  if (viz && physical)
774  {
775  internal_internalGuiUpdate_sensors(viz->get(), physical->get());
777  }
778 }
779 
781 {
782  loggers_[LOGGER_POSE] = std::make_shared<CSVLogger>();
783  loggers_[LOGGER_POSE]->setFilepath(log_path_ + "mvsim_" + name_ + "_" + LOGGER_POSE + ".log");
784 
785  for (size_t i = 0; i < getNumWheels(); i++)
786  {
787  loggers_[LOGGER_WHEEL + std::to_string(i + 1)] = std::make_shared<CSVLogger>();
788  loggers_[LOGGER_WHEEL + std::to_string(i + 1)]->setFilepath(
789  log_path_ + "mvsim_" + name_ + "_" + LOGGER_WHEEL + std::to_string(i + 1) + ".log");
790  }
791 }
792 
794 {
795  std::map<std::string, std::shared_ptr<CSVLogger>>::iterator it;
796  for (it = loggers_.begin(); it != loggers_.end(); ++it)
797  {
798  it->second->writeRow();
799  }
800 }
801 
803  const mrpt::math::TVector2D& force, const mrpt::math::TPoint2D& applyPoint)
804 {
805  ASSERT_(b2dBody_);
806  // Application point -> world coords
807  const b2Vec2 wPt = b2dBody_->GetWorldPoint(b2Vec2(applyPoint.x, applyPoint.y));
808  b2dBody_->ApplyForce(b2Vec2(force.x, force.y), wPt, true /*wake up*/);
809 }
810 
812 {
813  // register myself, and my children objects:
815  for (auto& sensor : sensors_) sensor->registerOnServer(c);
816 }
817 
819 {
820  if (glChassisViz_) glChassisViz_->setVisibility(visible);
821  for (auto& glW : glWheelsViz_)
822  {
823  if (glW) glW->setVisibility(visible);
824  }
825 }
mvsim::World::TGUI_Options::show_forces
bool show_forces
Definition: World.h:505
mvsim::VisualObject::parent
World * parent()
Definition: VisualObject.h:51
mvsim::VehicleBase::getLoggerPtr
std::shared_ptr< CSVLogger > getLoggerPtr(std::string logger_name)
Definition: VehicleBase.h:99
XMLClassesRegistry.h
mvsim
Definition: Client.h:21
mvsim::VehicleBase::glWheelsViz_
std::vector< mrpt::opengl::CSetOfObjects::Ptr > glWheelsViz_
Definition: VehicleBase.h:219
b2Vec2::y
float y
Definition: b2_math.h:128
register_all_veh_dynamics
void register_all_veh_dynamics()
Definition: VehicleBase.cpp:41
mvsim::VehicleBase::PL_Q_X
static constexpr char PL_Q_X[]
Definition: VehicleBase.h:233
mvsim::VehicleBase::PL_DQ_X
static constexpr char PL_DQ_X[]
Definition: VehicleBase.h:239
mvsim::VisualObject::world_
World * world_
Definition: VisualObject.h:73
b2MassData::mass
float mass
The mass of the shape, usually in kilograms.
Definition: b2_shape.h:36
parse_utils.h
mvsim::VehicleBase::internal_internalGuiUpdate_sensors
void internal_internalGuiUpdate_sensors(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical)
Definition: VehicleBase.cpp:541
mvsim::JointXMLnode
Definition: basic_types.h:53
mvsim::Wheel::yaw
double yaw
Definition: Wheel.h:40
mvsim::FrictionBase::factory
static FrictionBase::Ptr factory(VehicleBase &parent, const rapidxml::xml_node< char > *xml_node)
Definition: FrictionBase.cpp:43
mvsim::VehicleBase::sensors_
TListSensors sensors_
Sensors aboard.
Definition: VehicleBase.h:177
mvsim::Shape2p5::setShapeManual
void setShapeManual(const mrpt::math::TPolygon2D &contour, const float zMin, const float zMax)
Definition: Shape2p5.cpp:217
mvsim::VehicleBase::chassis_z_max_
double chassis_z_max_
Definition: VehicleBase.h:187
mvsim::VehicleBase::maxRadius_
double maxRadius_
Definition: VehicleBase.h:185
mvsim::VehicleBase::fixture_wheels_
std::vector< b2Fixture * > fixture_wheels_
Definition: VehicleBase.h:208
JointXMLnode.h
s
XmlRpcServer s
mvsim::Wheel::linked_yaw_object_name
std::string linked_yaw_object_name
Definition: Wheel.h:60
mvsim::VehicleBase::chassis_mass_
double chassis_mass_
Definition: VehicleBase.h:180
mvsim::VehicleBase::glChassisPhysical_
mrpt::opengl::CSetOfObjects::Ptr glChassisPhysical_
Definition: VehicleBase.h:218
mvsim::VehicleBase::forceSegmentsForRendering_
std::vector< mrpt::math::TSegment3D > forceSegmentsForRendering_
Definition: VehicleBase.h:224
mvsim::World::guiOptions_
TGUI_Options guiOptions_
Definition: World.h:544
mvsim::xml_to_str_solving_includes
std::string xml_to_str_solving_includes(const World &parent, const rapidxml::xml_node< char > *xml_node, const std::set< std::string > &varsRetain={})
Definition: xml_utils.cpp:498
mvsim::VehicleBase::chassis_color_
mrpt::img::TColor chassis_color_
Definition: VehicleBase.h:189
mvsim::VehicleBase::create_multibody_system
virtual void create_multibody_system(b2World &world)
Definition: VehicleBase.cpp:590
mvsim::VehicleBase::PL_Q_Y
static constexpr char PL_Q_Y[]
Definition: VehicleBase.h:234
mvsim::World::applyWorldRenderOffset
mrpt::math::TPose3D applyWorldRenderOffset(mrpt::math::TPose3D p) const
Definition: World.h:631
World.h
mvsim::Client
Definition: Client.h:48
mvsim::VehicleBase::friction_
FrictionBasePtr friction_
Definition: VehicleBase.h:175
mvsim::VehicleBase::WL_FRIC_Y
static constexpr char WL_FRIC_Y[]
Definition: VehicleBase.h:248
mvsim::VehicleBase::PL_Q_PITCH
static constexpr char PL_Q_PITCH[]
Definition: VehicleBase.h:237
b2PolygonShape::ComputeMass
void ComputeMass(b2MassData *massData, float density) const override
Definition: b2_polygon_shape.cpp:357
mvsim::VehicleBase::internal_internalGuiUpdate_forces
void internal_internalGuiUpdate_forces(mrpt::opengl::COpenGLScene &scene)
Definition: VehicleBase.cpp:548
mvsim::VehicleBase::getWheelsVelocityLocal
std::vector< mrpt::math::TVector2D > getWheelsVelocityLocal(const mrpt::math::TTwist2D &veh_vel_local) const
Definition: VehicleBase.cpp:518
mvsim::World::get_gravity
double get_gravity() const
Definition: World.h:154
mvsim::ClassFactory::create
Ptr create(const std::string &class_name, ARG1 a1) const
Definition: ClassFactory.h:42
mvsim::FrictionBase::TFrictionInput
Definition: FrictionBase.h:38
b2FixtureDef
Definition: b2_fixture.h:61
mvsim::TSimulContext::simul_time
double simul_time
Current time in the simulated world.
Definition: basic_types.h:62
mvsim::Simulable::getVelocityLocal
mrpt::math::TTwist2D getVelocityLocal() const
Definition: Simulable.cpp:141
mvsim::DynamicsAckermannDrivetrain
Definition: VehicleAckermann_Drivetrain.h:28
mvsim::VehicleBase::wheels_info_
std::deque< Wheel > wheels_info_
Definition: VehicleBase.h:201
mvsim::Wheel::x
double x
Definition: Wheel.h:40
b2Vec2
A 2D column vector.
Definition: b2_math.h:41
mvsim::VehicleBase::initLoggers
virtual void initLoggers()
Definition: VehicleBase.cpp:780
xml_utils.h
b2PolygonShape::Set
void Set(const b2Vec2 *points, int32 count)
Definition: b2_polygon_shape.cpp:118
VehicleDifferential.h
REGISTER_VEHICLE_DYNAMICS
#define REGISTER_VEHICLE_DYNAMICS(TEXTUAL_NAME, CLASS_NAME)
Definition: VehicleBase.h:260
mvsim::VehicleBase::PL_Q_Z
static constexpr char PL_Q_Z[]
Definition: VehicleBase.h:235
mvsim::World::TGUI_Options::force_scale
double force_scale
In meters/Newton.
Definition: World.h:507
mvsim::VehicleBase::forceSegmentsForRenderingMtx_
std::mutex forceSegmentsForRenderingMtx_
Definition: VehicleBase.h:226
mvsim::classFactory_vehicleDynamics
TClassFactory_vehicleDynamics classFactory_vehicleDynamics
Definition: VehicleBase.cpp:37
mvsim::VehicleBase::WL_FRIC_X
static constexpr char WL_FRIC_X[]
Definition: VehicleBase.h:247
rapidxml::xml_attribute
Definition: rapidxml.hpp:138
mvsim::VehicleBase::DL_TIMESTAMP
static constexpr char DL_TIMESTAMP[]
Definition: VehicleBase.h:229
VehicleAckermann_Drivetrain.h
mvsim::TSimulContext::dt
double dt
timestep
Definition: basic_types.h:63
b2BodyDef::type
b2BodyType type
Definition: b2_body.h:74
mvsim::VehicleBase::glWheelsPhysical_
std::vector< mrpt::opengl::CSetOfObjects::Ptr > glWheelsPhysical_
Definition: VehicleBase.h:219
mvsim::VehicleBase::LOGGER_WHEEL
static constexpr char LOGGER_WHEEL[]
Definition: VehicleBase.h:231
mvsim::parse_variables
std::string parse_variables(const std::string &in, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain)
Definition: xml_utils.cpp:428
b2Fixture::GetMassData
void GetMassData(b2MassData *massData) const
Definition: b2_fixture.h:354
mvsim::VehicleBase::apply_force
virtual void apply_force(const mrpt::math::TVector2D &force, const mrpt::math::TPoint2D &applyPoint=mrpt::math::TPoint2D(0, 0)) override
Definition: VehicleBase.cpp:802
VehicleBase.h
mvsim::VehicleBase::registerOnServer
void registerOnServer(mvsim::Client &c) override
Definition: VehicleBase.cpp:811
mvsim::Wheel::diameter
double diameter
Definition: Wheel.h:46
mvsim::VehicleBase::glForces_
mrpt::opengl::CSetOfLines::Ptr glForces_
Definition: VehicleBase.h:220
mvsim::XmlClassesRegistry::get
const rapidxml::xml_node< char > * get(const std::string &xml_node_class) const
Definition: XMLClassesRegistry.cpp:20
b2FixtureDef::restitution
float restitution
The restitution (elasticity) usually in the range [0,1].
Definition: b2_fixture.h:85
mvsim::VehicleBase::internalGuiUpdate
virtual void internalGuiUpdate(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical, bool childrenOnly) override
Definition: VehicleBase.cpp:666
b2FixtureDef::friction
float friction
The friction coefficient, usually in the range [0,1].
Definition: b2_fixture.h:82
mvsim::Shape2p5
Definition: Shape2p5.h:31
b2MassData::center
b2Vec2 center
The position of the shape's centroid relative to the shape's origin.
Definition: b2_shape.h:39
mvsim::Wheel::getAs3DObject
void getAs3DObject(mrpt::opengl::CSetOfObjects &obj, bool isPhysicalScene)
Definition: Wheel.cpp:27
mvsim::World::local_to_abs_path
std::string local_to_abs_path(const std::string &in_path) const
Definition: World.cpp:106
b2_dynamicBody
@ b2_dynamicBody
Definition: b2_body.h:47
mvsim::Wheel
Definition: Wheel.h:33
rapidxml
Definition: rapidxml.hpp:57
mvsim::TSimulContext
Definition: basic_types.h:58
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::VehicleBase::writeLogStrings
virtual void writeLogStrings()
Definition: VehicleBase.cpp:793
mvsim::JointXMLnode::first_node
const rapidxml::xml_node< Ch > * first_node(const char *name) const
Definition: JointXMLnode.h:30
b2Shape::m_radius
float m_radius
Definition: b2_shape.h:102
mvsim::VehicleBase::invoke_motor_controllers_post_step
virtual void invoke_motor_controllers_post_step([[maybe_unused]] const TSimulContext &context)
Definition: VehicleBase.h:164
mvsim::VehicleBase::torqueSegmentsForRendering_
std::vector< mrpt::math::TSegment3D > torqueSegmentsForRendering_
Definition: VehicleBase.h:225
mvsim::VehicleBase::LOGGER_POSE
static constexpr char LOGGER_POSE[]
Definition: VehicleBase.h:230
mvsim::VehicleBase::WL_VEL_X
static constexpr char WL_VEL_X[]
Definition: VehicleBase.h:245
mvsim::VehicleBase::invoke_motor_controllers
virtual std::vector< double > invoke_motor_controllers(const TSimulContext &context)=0
mvsim::SensorBase::factory
static SensorBase::Ptr factory(Simulable &parent, const rapidxml::xml_node< char > *xml_node)
Definition: SensorBase.cpp:93
mvsim::Simulable::simul_post_timestep
virtual void simul_post_timestep(const TSimulContext &context)
Definition: Simulable.cpp:64
mvsim::World::getBox2DWorld
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:307
mvsim::VehicleBase::log_path_
std::string log_path_
Definition: VehicleBase.h:145
mvsim::parse
std::string parse(const std::string &input, const std::map< std::string, std::string > &variableNamesValues={})
Definition: parse_utils.cpp:217
b2PolygonShape::SetAsBox
void SetAsBox(float hx, float hy)
Definition: b2_polygon_shape.cpp:36
b2FixtureDef::density
float density
The density, usually in kg/m^2.
Definition: b2_fixture.h:92
mvsim::VehicleBase::glInit_
std::atomic_bool glInit_
Definition: VehicleBase.h:222
mvsim::Simulable::name_
std::string name_
Definition: Simulable.h:145
mvsim::XmlClassesRegistry
Definition: XMLClassesRegistry.h:19
mvsim::readXmlAndGetRoot
std::tuple< XML_Doc_Data::Ptr, rapidxml::xml_node<> * > readXmlAndGetRoot(const std::string &pathToFile, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain={})
Definition: xml_utils.cpp:315
b2Vec2::x
float x
Definition: b2_math.h:128
mvsim::VehicleBase::PL_Q_YAW
static constexpr char PL_Q_YAW[]
Definition: VehicleBase.h:236
mvsim::SensorBase::Ptr
std::shared_ptr< SensorBase > Ptr
Definition: SensorBase.h:37
mvsim::VehicleBase::PL_DQ_Y
static constexpr char PL_DQ_Y[]
Definition: VehicleBase.h:240
mvsim::Wheel::linked_yaw_offset
double linked_yaw_offset
Definition: Wheel.h:61
mvsim::VehicleBase::simul_pre_timestep
virtual void simul_pre_timestep(const TSimulContext &context) override
Definition: VehicleBase.cpp:360
b2BodyDef
Definition: b2_body.h:52
mvsim::Simulable::registerOnServer
virtual void registerOnServer(mvsim::Client &c)
Definition: Simulable.cpp:458
rapidxml::parse_error::where
Ch * where() const
Definition: rapidxml.hpp:94
b2FixtureDef::shape
const b2Shape * shape
Definition: b2_fixture.h:76
rapidxml::xml_document
Definition: rapidxml.hpp:139
mvsim::World
Definition: World.h:82
DefaultFriction.h
mvsim::VehicleBase::getChassisMass
virtual double getChassisMass() const
Definition: VehicleBase.h:75
mvsim::VehicleBase::getWheelInfo
const Wheel & getWheelInfo(const size_t idx) const
Definition: VehicleBase.h:83
mvsim::VehicleBase::getNumWheels
size_t getNumWheels() const
Definition: VehicleBase.h:82
rapidxml::xml_node< char >
b2World::CreateBody
b2Body * CreateBody(const b2BodyDef *def)
Definition: b2_world.cpp:115
mvsim::VehicleBase::register_vehicle_class
static void register_vehicle_class(const World &parent, const rapidxml::xml_node< char > *xml_node)
Definition: VehicleBase.cpp:96
mvsim::World::user_defined_variables
const std::map< std::string, std::string > & user_defined_variables() const
Definition: World.h:390
b2PolygonShape
Definition: b2_polygon_shape.h:32
mvsim::VehicleBase::loggers_
std::map< std::string, std::shared_ptr< CSVLogger > > loggers_
Definition: VehicleBase.h:144
mvsim::Simulable
Definition: Simulable.h:39
std
mvsim::FrictionBase::TFrictionInput::weight
double weight
Definition: FrictionBase.h:46
mvsim::FrictionBase::TFrictionInput::wheelCogLocalVel
mrpt::math::TVector2D wheelCogLocalVel
Definition: FrictionBase.h:54
VehicleAckermann.h
mvsim::VehicleBase::VehicleBase
VehicleBase(World *parent, size_t nWheels)
Definition: VehicleBase.cpp:78
mvsim::VehicleBase::chassis_poly_
mrpt::math::TPolygon2D chassis_poly_
Definition: VehicleBase.h:181
mvsim::VehicleBase::glChassisViz_
mrpt::opengl::CSetOfObjects::Ptr glChassisViz_
Definition: VehicleBase.h:218
mvsim::VehicleBase::PL_Q_ROLL
static constexpr char PL_Q_ROLL[]
Definition: VehicleBase.h:238
mvsim::Simulable::simul_pre_timestep
virtual void simul_pre_timestep(const TSimulContext &context)
Definition: Simulable.cpp:35
mvsim::DynamicsAckermann
Definition: VehicleAckermann.h:22
mvsim::Wheel::y
double y
Definition: Wheel.h:40
mvsim::VehicleBase::WL_TORQUE
static constexpr char WL_TORQUE[]
Definition: VehicleBase.h:243
mrpt::math
Definition: xml_utils.h:22
mvsim::VehicleBase::simul_post_timestep
virtual void simul_post_timestep(const TSimulContext &context) override
Definition: VehicleBase.cpp:466
mvsim::VehicleBase::fixture_chassis_
b2Fixture * fixture_chassis_
Created at.
Definition: VehicleBase.h:204
mvsim::VehicleBase::isLogging
bool isLogging() const
Definition: VehicleBase.cpp:569
b2World
Definition: b2_world.h:46
mvsim::Simulable::getPose
mrpt::math::TPose3D getPose() const
Definition: Simulable.cpp:490
mvsim::Simulable::getTwist
mrpt::math::TTwist2D getTwist() const
Definition: Simulable.cpp:498
mvsim::VehicleBase::Ptr
std::shared_ptr< VehicleBase > Ptr
Definition: VehicleBase.h:47
b2MassData
This holds the mass data computed for a shape.
Definition: b2_shape.h:33
mvsim::ClassFactory
Definition: ClassFactory.h:25
mvsim::XmlClassesRegistry::add
void add(const std::string &input_xml_node_class)
Definition: XMLClassesRegistry.cpp:29
root
root
rapidxml::parse_error::what
virtual const char * what() const
Definition: rapidxml.hpp:85
mvsim::VehicleBase::PL_DQ_Z
static constexpr char PL_DQ_Z[]
Definition: VehicleBase.h:241
mvsim::VisualObject::glCustomVisual_
std::shared_ptr< mrpt::opengl::CSetOfObjects > glCustomVisual_
Definition: VisualObject.h:77
mvsim::VehicleBase::chassisAndWheelsVisible
void chassisAndWheelsVisible(bool visible)
Definition: VehicleBase.cpp:818
rapidxml.hpp
mvsim::FrictionBase::TFrictionInput::motorTorque
double motorTorque
Definition: FrictionBase.h:50
mvsim::VehicleBase::chassis_com_
mrpt::math::TPoint2D chassis_com_
Definition: VehicleBase.h:193
mvsim::VehicleBase::WL_VEL_Y
static constexpr char WL_VEL_Y[]
Definition: VehicleBase.h:246
mvsim::VehicleBase::chassis_z_min_
double chassis_z_min_
Definition: VehicleBase.h:187
rapidxml::parse_error
Definition: rapidxml.hpp:71
mvsim::VehicleBase::glMotorTorques_
mrpt::opengl::CSetOfLines::Ptr glMotorTorques_
Definition: VehicleBase.h:221
veh_classes_registry
static XmlClassesRegistry veh_classes_registry("vehicle:class")
mvsim::VehicleBase::factory
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node)
Definition: VehicleBase.cpp:118
mvsim::DynamicsDifferential_3_wheels
Definition: VehicleDifferential.h:226
mvsim::DynamicsDifferential_4_wheels
Definition: VehicleDifferential.h:245
mvsim::VisualObject
Definition: VisualObject.h:35
mvsim::VehicleBase::updateMaxRadiusFromPoly
void updateMaxRadiusFromPoly()
Definition: VehicleBase.cpp:577
mvsim::Simulable::getPoseNoLock
mrpt::math::TPose3D getPoseNoLock() const
No thread-safe version. Used internally only.
Definition: Simulable.cpp:496
b2_maxPolygonVertices
#define b2_maxPolygonVertices
Definition: b2_settings.h:53
rapidxml::xml_document::parse
void parse(Ch *text)
Definition: rapidxml.hpp:1381
mvsim::DynamicsDifferential
Definition: VehicleDifferential.h:30
mvsim::VehicleBase::WL_WEIGHT
static constexpr char WL_WEIGHT[]
Definition: VehicleBase.h:244
mvsim::JointXMLnode::add
void add(const rapidxml::xml_node< Ch > *node)
Definition: JointXMLnode.h:28
FrictionBase.h


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