VehicleBase.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2020 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>
13 #include <mrpt/poses/CPose2D.h>
14 #include <mvsim/FrictionModels/DefaultFriction.h> // For use as default model
16 #include <mvsim/VehicleBase.h>
20 #include <mvsim/World.h>
21 
22 #include <map>
23 #include <rapidxml.hpp>
24 #include <rapidxml_print.hpp>
25 #include <rapidxml_utils.hpp>
26 #include <sstream> // std::stringstream
27 #include <string>
28 
29 #include "JointXMLnode.h"
30 #include "XMLClassesRegistry.h"
31 #include "xml_utils.h"
32 
33 using namespace mvsim;
34 using namespace std;
35 
36 static XmlClassesRegistry veh_classes_registry("vehicle:class");
37 
39 
40 // Explicit registration calls seem to be one (the unique?) way to assure
41 // registration takes place:
43 {
44  static bool done = false;
45  if (done)
46  return;
47  else
48  done = true;
49 
53  "ackermann_drivetrain", DynamicsAckermannDrivetrain)
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),
80  m_vehicle_index(0),
81  m_chassis_mass(15.0),
82  m_chassis_z_min(0.05),
83  m_chassis_z_max(0.6),
84  m_chassis_color(0xff, 0x00, 0x00),
85  m_chassis_com(.0, .0),
86  m_wheels_info(nWheels),
87  m_fixture_wheels(nWheels, nullptr)
88 {
89  // Default shape:
90  m_chassis_poly.emplace_back(-0.4, -0.5);
91  m_chassis_poly.emplace_back(-0.4, 0.5);
92  m_chassis_poly.emplace_back(0.4, 0.5);
93  m_chassis_poly.emplace_back(0.6, 0.3);
94  m_chassis_poly.emplace_back(0.6, -0.3);
95  m_chassis_poly.emplace_back(0.4, -0.5);
97 }
98 
102  const rapidxml::xml_node<char>* xml_node)
103 {
104  // Sanity checks:
105  if (!xml_node)
106  throw runtime_error(
107  "[VehicleBase::register_vehicle_class] XML node is nullptr");
108  if (0 != strcmp(xml_node->name(), "vehicle:class"))
109  throw runtime_error(mrpt::format(
110  "[VehicleBase::register_vehicle_class] XML element is '%s' "
111  "('vehicle:class' expected)",
112  xml_node->name()));
113 
114  // rapidxml doesn't allow making copied of objects.
115  // So: convert to txt; then re-parse.
116  std::stringstream ss;
117  ss << *xml_node;
118 
119  veh_classes_registry.add(ss.str());
120 }
121 
125  World* parent, const rapidxml::xml_node<char>* root)
126 {
128 
129  using namespace std;
130  using namespace rapidxml;
131 
132  if (!root)
133  throw runtime_error("[VehicleBase::factory] XML node is nullptr");
134  if (0 != strcmp(root->name(), "vehicle"))
135  throw runtime_error(mrpt::format(
136  "[VehicleBase::factory] XML root element is '%s' ('vehicle' "
137  "expected)",
138  root->name()));
139 
140  // "class": When a vehicle has a 'class="XXX"' attribute, look for each
141  // parameter
142  // in the set of "root" + "class_root" XML nodes:
143  // --------------------------------------------------------------------------------
144  JointXMLnode<> veh_root_node;
145  {
146  veh_root_node.add(
147  root); // Always search in root. Also in the class root, if any:
148 
149  const xml_attribute<>* veh_class = root->first_attribute("class");
150  if (veh_class)
151  {
152  const string sClassName = veh_class->value();
153  const rapidxml::xml_node<char>* class_root =
154  veh_classes_registry.get(sClassName);
155  if (!class_root)
156  throw runtime_error(mrpt::format(
157  "[VehicleBase::factory] Vehicle class '%s' undefined",
158  sClassName.c_str()));
159 
160  veh_root_node.add(class_root);
161  // cout << *class_root;
162  }
163  }
164 
165  // Class factory according to: <dynamics class="XXX">
166  // -------------------------------------------------
167  const xml_node<>* dyn_node = veh_root_node.first_node("dynamics");
168  if (!dyn_node)
169  throw runtime_error(
170  "[VehicleBase::factory] Missing XML node <dynamics>");
171 
172  const xml_attribute<>* dyn_class = dyn_node->first_attribute("class");
173  if (!dyn_class || !dyn_class->value())
174  throw runtime_error(
175  "[VehicleBase::factory] Missing mandatory attribute 'class' in "
176  "node <dynamics>");
177 
178  VehicleBase::Ptr veh =
179  classFactory_vehicleDynamics.create(dyn_class->value(), parent);
180  if (!veh)
181  throw runtime_error(mrpt::format(
182  "[VehicleBase::factory] Unknown vehicle dynamics class '%s'",
183  dyn_class->value()));
184 
185  // Initialize here all common params shared by any polymorphic class:
186  // -------------------------------------------------
187  // attrib: name
188  {
189  const xml_attribute<>* attrib_name = root->first_attribute("name");
190  if (attrib_name && attrib_name->value())
191  {
192  veh->m_name = attrib_name->value();
193  }
194  else
195  {
196  // Default name:
197  static int cnt = 0;
198  veh->m_name = mrpt::format("veh%i", ++cnt);
199  }
200  }
201 
202  // (Mandatory) initial pose:
203  {
204  const xml_node<>* node = veh_root_node.first_node("init_pose");
205  if (!node)
206  throw runtime_error(
207  "[VehicleBase::factory] Missing XML node <init_pose>");
208 
210  if (3 != ::sscanf(node->value(), "%lf %lf %lf", &p.x, &p.y, &p.yaw))
211  throw runtime_error(
212  "[VehicleBase::factory] Error parsing "
213  "<init_pose>...</init_pose>");
214  p.yaw *= M_PI / 180.0; // deg->rad
215 
216  veh->setPose(p);
217  }
218 
219  // (Optional) initial vel:
220  {
221  const xml_node<>* node = veh_root_node.first_node("init_vel");
222  if (node)
223  {
225  if (3 !=
226  ::sscanf(
227  node->value(), "%lf %lf %lf", &dq.vx, &dq.vy, &dq.omega))
228  throw runtime_error(
229  "[VehicleBase::factory] Error parsing "
230  "<init_vel>...</init_vel>");
231  dq.omega *= M_PI / 180.0; // deg->rad
232 
233  // Convert twist (velocity) from local -> global coords:
234  dq.rotate(veh->getPose().yaw);
235  veh->setTwist(dq);
236  }
237  }
238 
239  // Custom visualization 3D model:
240  // -----------------------------------------------------------
241  veh->parseVisual(veh_root_node.first_node("visual"));
242  veh->parseSimulable(veh_root_node.first_node("publish"));
243 
244  // Initialize class-specific params (mass, chassis shape, etc.)
245  // ---------------------------------------------------------------
246  veh->dynamics_load_params_from_xml(dyn_node);
247 
248  // Auto shape node from visual?
249  if (const rapidxml::xml_node<char>* xml_chassis =
250  dyn_node->first_node("chassis");
251  xml_chassis)
252  {
253  if (const rapidxml::xml_node<char>* sfv =
254  xml_chassis->first_node("shape_from_visual");
255  sfv)
256  {
257  mrpt::math::TPoint3D bbmin, bbmax;
258  veh->getVisualModelBoundingBox(bbmin, bbmax);
259  if (bbmin == bbmax)
260  {
262  "Error: Tag <shape_from_visual/> found but bounding box of "
263  "visual object seems incorrect.");
264  }
265 
266  auto& poly = veh->m_chassis_poly;
267  poly.clear();
268  poly.emplace_back(bbmin.x, bbmin.y);
269  poly.emplace_back(bbmin.x, bbmax.y);
270  poly.emplace_back(bbmax.x, bbmax.y);
271  poly.emplace_back(bbmax.x, bbmin.y);
272  }
273  }
274  veh->updateMaxRadiusFromPoly();
275 
276  // <Optional> Log path. If not specified, app folder will be used
277  // -----------------------------------------------------------
278  {
279  const xml_node<>* log_path_node = veh_root_node.first_node("log_path");
280  if (log_path_node)
281  {
282  // Parse:
283  veh->m_log_path = log_path_node->value();
284  }
285  }
286 
287  veh->initLoggers();
288 
289  // Register bodies, fixtures, etc. in Box2D simulator:
290  // ----------------------------------------------------
291  veh->create_multibody_system(*parent->getBox2DWorld());
292 
293  if (veh->m_b2d_body)
294  {
295  // Init pos:
296  const auto q = veh->getPose();
297  const auto dq = veh->getTwist();
298 
299  veh->m_b2d_body->SetTransform(b2Vec2(q.x, q.y), q.yaw);
300  // Init vel:
301  veh->m_b2d_body->SetLinearVelocity(b2Vec2(dq.vx, dq.vy));
302  veh->m_b2d_body->SetAngularVelocity(dq.omega);
303  }
304 
305  // Friction model:
306  // Parse <friction> node, or assume default linear model:
307  // -----------------------------------------------------------
308  {
309  const xml_node<>* frict_node = veh_root_node.first_node("friction");
310  if (!frict_node)
311  {
312  // Default:
313  veh->m_friction = std::shared_ptr<FrictionBase>(
314  new DefaultFriction(*veh, nullptr /*default params*/));
315  }
316  else
317  {
318  // Parse:
319  veh->m_friction = std::shared_ptr<FrictionBase>(
320  FrictionBase::factory(*veh, frict_node));
321  ASSERT_(veh->m_friction);
322  }
323  }
324 
325  // Sensors: <sensor class='XXX'> entries
326  // -------------------------------------------------
327  for (const auto& xmlNode : veh_root_node)
328  {
329  if (!strcmp(xmlNode->name(), "sensor"))
330  {
331  SensorBase::Ptr se = SensorBase::factory(*veh, xmlNode);
332  veh->m_sensors.push_back(SensorBase::Ptr(se));
333  }
334  }
335 
336  return veh;
337 }
338 
340  World* parent, const std::string& xml_text)
341 {
342  // Parse the string as if it was an XML file:
343  std::stringstream s;
344  s.str(xml_text);
345 
346  char* input_str = const_cast<char*>(xml_text.c_str());
348  try
349  {
350  xml.parse<0>(input_str);
351  }
352  catch (rapidxml::parse_error& e)
353  {
354  unsigned int line =
355  static_cast<long>(std::count(input_str, e.where<char>(), '\n') + 1);
356  throw std::runtime_error(mrpt::format(
357  "[VehicleBase::factory] XML parse error (Line %u): %s",
358  static_cast<unsigned>(line), e.what()));
359  }
360  return VehicleBase::factory(parent, xml.first_node());
361 }
362 
364 {
366  for (auto& s : m_sensors) s->simul_pre_timestep(context);
367 
368  // Update wheels position (they may turn, etc. as in an Ackermann
369  // configuration)
370  for (size_t i = 0; i < m_fixture_wheels.size(); i++)
371  {
372  b2PolygonShape* wheelShape =
373  dynamic_cast<b2PolygonShape*>(m_fixture_wheels[i]->GetShape());
374  wheelShape->SetAsBox(
375  m_wheels_info[i].diameter * 0.5, m_wheels_info[i].width * 0.5,
377  m_wheels_info[i].yaw);
378  }
379 
380  // Apply motor forces/torques:
382 
383  // Apply friction model at each wheel:
384  const size_t nW = getNumWheels();
385  ASSERT_EQUAL_(m_torque_per_wheel.size(), nW);
386 
387  const double gravity = getWorldObject()->get_gravity();
388  const double massPerWheel =
389  getChassisMass() / nW; // Part of the vehicle weight on each wheel.
390  const double weightPerWheel = massPerWheel * gravity;
391 
392  std::vector<mrpt::math::TPoint2D> wheels_vels;
394 
395  ASSERT_EQUAL_(wheels_vels.size(), nW);
396 
397  std::vector<mrpt::math::TSegment3D>
398  force_vectors; // For visualization only
399 
400  for (size_t i = 0; i < nW; i++)
401  {
402  // prepare data:
403  Wheel& w = getWheelInfo(i);
404 
405  FrictionBase::TFrictionInput fi(context, w);
406  fi.motor_torque =
407  -m_torque_per_wheel[i]; // "-" => Forwards is negative
408  fi.weight = weightPerWheel;
409  fi.wheel_speed = wheels_vels[i];
410 
411  m_friction->setLogger(
412  getLoggerPtr(LOGGER_WHEEL + std::to_string(i + 1)));
413  // eval friction:
414  mrpt::math::TPoint2D net_force_;
415  m_friction->evaluate_friction(fi, net_force_);
416 
417  // Apply force:
418  const b2Vec2 wForce = m_b2d_body->GetWorldVector(b2Vec2(
419  net_force_.x, net_force_.y)); // Force vector -> world coords
420  const b2Vec2 wPt = m_b2d_body->GetWorldPoint(
421  b2Vec2(w.x, w.y)); // Application point -> world coords
422  // printf("w%i: Lx=%6.3f Ly=%6.3f | Gx=%11.9f
423  // Gy=%11.9f\n",(int)i,net_force_.x,net_force_.y,wForce.x,wForce.y);
424 
425  m_b2d_body->ApplyForce(wForce, wPt, true /*wake up*/);
426 
427  // log
428  {
429  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
430  DL_TIMESTAMP, context.simul_time);
431  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
432  WL_TORQUE, fi.motor_torque);
433  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
434  WL_WEIGHT, fi.weight);
435  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
436  WL_VEL_X, fi.wheel_speed.x);
437  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
438  WL_VEL_Y, fi.wheel_speed.y);
439  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
440  WL_FRIC_X, net_force_.x);
441  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
442  WL_FRIC_Y, net_force_.y);
443  }
444 
445  // save it for optional rendering:
447  {
448  const double forceScale =
449  m_world->m_gui_options.force_scale; // [meters/N]
450  const mrpt::math::TPoint3D pt1(
451  wPt.x, wPt.y, m_chassis_z_max * 1.1 + getPose().z);
452  const mrpt::math::TPoint3D pt2 =
453  pt1 + mrpt::math::TPoint3D(wForce.x, wForce.y, 0) * forceScale;
454  force_vectors.push_back(mrpt::math::TSegment3D(pt1, pt2));
455  }
456  }
457 
458  // Save forces for optional rendering:
460  {
461  std::lock_guard<std::mutex> csl(m_force_segments_for_rendering_cs);
462  m_force_segments_for_rendering = force_vectors;
463  }
464 }
465 
469 {
470  // Common part (update m_q, m_dq)
472  for (auto& s : m_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(
491  ::fmod(cur_abs_phi, 2 * M_PI) *
492  (w.getPhi() < 0.0 ? -1.0 : 1.0));
493  }
494 
495  const auto q = getPose();
496  const auto dq = getTwist();
497 
498  m_loggers[LOGGER_POSE]->updateColumn(DL_TIMESTAMP, context.simul_time);
499  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_X, q.x);
500  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_Y, q.y);
501  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_Z, q.z);
502  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_YAW, q.yaw);
503  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_PITCH, q.pitch);
504  m_loggers[LOGGER_POSE]->updateColumn(PL_Q_ROLL, q.roll);
505  m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_X, dq.vx);
506  m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_Y, dq.vy);
507  m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_Z, dq.omega);
508 
509  {
510  writeLogStrings();
511  }
512 }
513 
516  std::vector<mrpt::math::TPoint2D>& vels,
517  const mrpt::math::TTwist2D& veh_vel_local) const
518 {
519  // Each wheel velocity is:
520  // v_w = v_veh + \omega \times wheel_pos
521  // =>
522  // v_w = v_veh + ( -w*y, w*x )
523 
524  const double w = veh_vel_local.omega; // vehicle w
525 
526  const size_t nW = this->getNumWheels();
527  vels.resize(nW);
528  for (size_t i = 0; i < nW; i++)
529  {
530  const Wheel& wheel = getWheelInfo(i);
531 
532  vels[i].x = veh_vel_local.vx - w * wheel.y;
533  vels[i].y = veh_vel_local.vy + w * wheel.x;
534  }
535 }
536 
538 {
539  return mrpt::poses::CPose3D(getPose());
540 }
541 
544 {
545  for (auto& s : m_sensors) s->guiUpdate(scene);
546 }
547 
550 {
552  {
553  std::lock_guard<std::mutex> csl(m_force_segments_for_rendering_cs);
554  m_gl_forces->clear();
556  m_gl_forces->setVisibility(true);
557  }
558  else
559  {
560  m_gl_forces->setVisibility(false);
561  }
562 }
563 
565 {
566  using namespace mrpt::math;
567 
568  m_max_radius = 0.001f;
569  for (const auto& pt : m_chassis_poly)
570  {
571  const float n = pt.norm();
572  mrpt::keep_max(m_max_radius, n);
573  }
574 }
575 
578 {
579  // Define the dynamic body. We set its position and call the body factory.
580  b2BodyDef bodyDef;
581  bodyDef.type = b2_dynamicBody;
582 
583  m_b2d_body = world.CreateBody(&bodyDef);
584 
585  // Define shape of chassis:
586  // ------------------------------
587  {
588  // Convert shape into Box2D format:
589  const size_t nPts = m_chassis_poly.size();
590  ASSERT_(nPts >= 3);
591  ASSERT_LE_(nPts, (size_t)b2_maxPolygonVertices);
592  std::vector<b2Vec2> pts(nPts);
593  for (size_t i = 0; i < nPts; i++)
594  pts[i] = b2Vec2(m_chassis_poly[i].x, m_chassis_poly[i].y);
595 
596  b2PolygonShape chassisPoly;
597  chassisPoly.Set(&pts[0], nPts);
598  // chassisPoly.m_radius = 1e-3; // The "skin" depth of the body
599 
600  // Define the dynamic body fixture.
601  b2FixtureDef fixtureDef;
602  fixtureDef.shape = &chassisPoly;
603  fixtureDef.restitution = 0.01;
604 
605  // Set the box density to be non-zero, so it will be dynamic.
606  b2MassData mass;
607  chassisPoly.ComputeMass(
608  &mass, 1); // Mass with density=1 => compute area
609  fixtureDef.density = m_chassis_mass / mass.mass;
610 
611  // Override the default friction.
612  fixtureDef.friction = 0.3f;
613 
614  // Add the shape to the body.
615  m_fixture_chassis = m_b2d_body->CreateFixture(&fixtureDef);
616 
617  // Compute center of mass:
618  b2MassData vehMass;
619  m_fixture_chassis->GetMassData(&vehMass);
620  m_chassis_com.x = vehMass.center.x;
621  m_chassis_com.y = vehMass.center.y;
622  }
623 
624  // Define shape of wheels:
625  // ------------------------------
627 
628  for (size_t i = 0; i < m_wheels_info.size(); i++)
629  {
630  b2PolygonShape wheelShape;
631  wheelShape.SetAsBox(
632  m_wheels_info[i].diameter * 0.5, m_wheels_info[i].width * 0.5,
634  m_wheels_info[i].yaw);
635 
636  // Define the dynamic body fixture.
637  b2FixtureDef fixtureDef;
638  fixtureDef.shape = &wheelShape;
639  fixtureDef.restitution = 0.05;
640 
641  // Set the box density to be non-zero, so it will be dynamic.
642  b2MassData mass;
643  wheelShape.ComputeMass(
644  &mass, 1); // Mass with density=1 => compute area
645  fixtureDef.density = m_wheels_info[i].mass / mass.mass;
646 
647  // Override the default friction.
648  fixtureDef.friction = 0.5f;
649 
650  m_fixture_wheels[i] = m_b2d_body->CreateFixture(&fixtureDef);
651  }
652 }
653 
655  mrpt::opengl::COpenGLScene& scene, bool childrenOnly)
656 {
657  auto lck = mrpt::lockHelper(m_gui_mtx);
658 
659  // 1st time call?? -> Create objects
660  // ----------------------------------
661  if (!childrenOnly)
662  {
663  const size_t nWs = this->getNumWheels();
664  if (!m_gl_chassis)
665  {
666  m_gl_chassis = mrpt::opengl::CSetOfObjects::Create();
667 
668  // Wheels shape:
669  m_gl_wheels.resize(nWs);
670  for (size_t i = 0; i < nWs; i++)
671  {
672  m_gl_wheels[i] = mrpt::opengl::CSetOfObjects::Create();
673  this->getWheelInfo(i).getAs3DObject(*m_gl_wheels[i]);
674  m_gl_chassis->insert(m_gl_wheels[i]);
675  }
676  // Robot shape:
677  mrpt::opengl::CPolyhedron::Ptr gl_poly =
680  gl_poly->setLocation(0, 0, m_chassis_z_min);
681  gl_poly->setColor_u8(m_chassis_color);
682  m_gl_chassis->insert(gl_poly);
683 
684  scene.insert(m_gl_chassis);
685  }
686 
687  // Update them:
688  // ----------------------------------
689  m_gl_chassis->setPose(getPose());
690 
691  for (size_t i = 0; i < nWs; i++)
692  {
693  const Wheel& w = getWheelInfo(i);
694  m_gl_wheels[i]->setPose(mrpt::math::TPose3D(
695  w.x, w.y, 0.5 * w.diameter, w.yaw, w.getPhi(), 0.0));
696  }
697  }
698 
699  // Init on first use:
700  if (!m_gl_forces)
701  {
702  // Visualization of forces:
704  m_gl_forces->setLineWidth(3.0);
705  m_gl_forces->setColor_u8(0xff, 0xff, 0xff);
706  scene.insert(m_gl_forces); // forces are in global coords
707  }
708 
709  // Other common stuff:
712 }
713 
715 {
716  m_loggers[LOGGER_POSE] = std::make_shared<CSVLogger>();
717  // m_loggers[LOGGER_POSE]->addColumn(DL_TIMESTAMP);
718  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_X);
719  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_Y);
720  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_Z);
721  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_YAW);
722  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_PITCH);
723  // m_loggers[LOGGER_POSE]->addColumn(PL_Q_ROLL);
724  // m_loggers[LOGGER_POSE]->addColumn(PL_DQ_X);
725  // m_loggers[LOGGER_POSE]->addColumn(PL_DQ_Y);
726  // m_loggers[LOGGER_POSE]->addColumn(PL_DQ_Z);
727  m_loggers[LOGGER_POSE]->setFilepath(
728  m_log_path + "mvsim_" + m_name + LOGGER_POSE + ".log");
729 
730  for (size_t i = 0; i < getNumWheels(); i++)
731  {
732  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)] =
733  std::make_shared<CSVLogger>();
734  // m_loggers[LOGGER_WHEEL + std::to_string(i +
735  // 1)]->addColumn(DL_TIMESTAMP);
736  // m_loggers[LOGGER_WHEEL + std::to_string(i +
737  // 1)]->addColumn(WL_TORQUE);
738  // m_loggers[LOGGER_WHEEL + std::to_string(i +
739  // 1)]->addColumn(WL_WEIGHT);
740  // m_loggers[LOGGER_WHEEL + std::to_string(i +
741  // 1)]->addColumn(WL_VEL_X);
742  // m_loggers[LOGGER_WHEEL + std::to_string(i +
743  // 1)]->addColumn(WL_VEL_Y);
744  // m_loggers[LOGGER_WHEEL + std::to_string(i +
745  // 1)]->addColumn(WL_FRIC_X);
746  // m_loggers[LOGGER_WHEEL + std::to_string(i +
747  // 1)]->addColumn(WL_FRIC_Y);
748  m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->setFilepath(
749  m_log_path + "mvsim_" + m_name + LOGGER_WHEEL +
750  std::to_string(i + 1) + ".log");
751  }
752 }
753 
755 {
756  std::map<std::string, std::shared_ptr<CSVLogger>>::iterator it;
757  for (it = m_loggers.begin(); it != m_loggers.end(); ++it)
758  {
759  it->second->writeRow();
760  }
761 }
762 
764  const mrpt::math::TVector2D& force, const mrpt::math::TPoint2D& applyPoint)
765 {
766  ASSERT_(m_b2d_body);
767  const b2Vec2 wPt = m_b2d_body->GetWorldPoint(b2Vec2(
768  applyPoint.x, applyPoint.y)); // Application point -> world coords
769  m_b2d_body->ApplyForce(b2Vec2(force.x, force.y), wPt, true /*wake up*/);
770 }
771 
773 {
774  // register myself, and my children objects:
776  for (auto& sensor : m_sensors) sensor->registerOnServer(c);
777 }
const b2Shape * shape
Definition: b2Fixture.h:71
#define ASSERT_EQUAL_(__A, __B)
void getWheelsVelocityLocal(std::vector< mrpt::math::TPoint2D > &vels, const mrpt::math::TTwist2D &veh_vel_local) const
mrpt::img::TColor m_chassis_color
Definition: VehicleBase.h:189
double force_scale
In meters/Newton.
Definition: World.h:289
void internal_internalGuiUpdate_forces(mrpt::opengl::COpenGLScene &scene)
This file contains rapidxml parser and DOM implementation.
GLint GLint GLint GLint GLint GLint y
mrpt::opengl::CSetOfObjects::Ptr m_gl_chassis
Definition: VehicleBase.h:214
Ch * where() const
Definition: rapidxml.hpp:94
void updateMaxRadiusFromPoly()
excludes the mass of wheels)
static SensorBase::Ptr factory(VehicleBase &parent, const rapidxml::xml_node< char > *xml_node)
Definition: SensorBase.cpp:54
Ch * value() const
Definition: rapidxml.hpp:692
static constexpr char PL_DQ_Y[]
Definition: VehicleBase.h:234
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node)
const GLfloat * c
static constexpr char PL_Q_ROLL[]
Definition: VehicleBase.h:232
#define THROW_EXCEPTION(msg)
Scalar * iterator
GLubyte GLubyte GLubyte GLubyte w
virtual void simul_post_timestep(const TSimulContext &context) override
double simul_time
Current time in the simulated world.
Definition: basic_types.h:60
#define REGISTER_VEHICLE_DYNAMICS(TEXTUAL_NAME, CLASS_NAME)
Definition: VehicleBase.h:252
virtual void initLoggers()
static constexpr char LOGGER_WHEEL[]
Definition: VehicleBase.h:225
#define M_PI
std::vector< double > m_torque_per_wheel
Definition: VehicleBase.h:181
static constexpr char WL_VEL_X[]
Definition: VehicleBase.h:239
mrpt::math::TPose3D getPose() const
Definition: Simulable.h:55
static CSetOfLinesPtr Create(const std::vector< mrpt::math::TSegment3D > &sgms, const bool antiAliasing=true)
void parse(Ch *text)
Definition: rapidxml.hpp:1381
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:189
void getAs3DObject(mrpt::opengl::CSetOfObjects &obj)
Definition: Wheel.cpp:25
std::shared_ptr< CSVLogger > getLoggerPtr(std::string logger_name)
Definition: VehicleBase.h:106
static constexpr char PL_Q_X[]
Definition: VehicleBase.h:227
static constexpr char WL_TORQUE[]
Definition: VehicleBase.h:237
b2Vec2 center
The position of the shape&#39;s centroid relative to the shape&#39;s origin.
Definition: b2Shape.h:33
virtual void internalGuiUpdate(mrpt::opengl::COpenGLScene &scene, bool childrenOnly) override
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
std::string m_log_path
Definition: VehicleBase.h:149
A 2D column vector.
Definition: b2Math.h:52
void insert(const CRenderizablePtr &newObject, const std::string &viewportName=std::string("main"))
static constexpr char PL_Q_Z[]
Definition: VehicleBase.h:229
static constexpr char PL_Q_PITCH[]
Definition: VehicleBase.h:231
std::vector< mrpt::math::TSegment3D > m_force_segments_for_rendering
Definition: VehicleBase.h:218
GLdouble s
double get_gravity() const
Definition: World.h:82
double x
Definition: Wheel.h:36
TClassFactory_vehicleDynamics classFactory_vehicleDynamics
Definition: VehicleBase.cpp:38
static constexpr char PL_Q_YAW[]
Definition: VehicleBase.h:230
GLsizei n
static constexpr char PL_DQ_Z[]
Definition: VehicleBase.h:235
size_t getNumWheels() const
Definition: VehicleBase.h:83
b2BodyType type
Definition: b2Body.h:74
double dt
timestep
Definition: basic_types.h:61
void ComputeMass(b2MassData *massData, float32 density) const
float32 mass
The mass of the shape, usually in kilograms.
Definition: b2Shape.h:30
VehicleBase(World *parent, size_t nWheels)
Definition: VehicleBase.cpp:78
static CPolyhedronPtr CreateCustomPrism(const std::vector< mrpt::math::TPoint2D > &baseVertices, double height)
mrpt::math::TTwist2D getVelocityLocal() const
Definition: Simulable.cpp:84
World * getWorldObject()
Definition: VisualObject.h:34
void setPhi(double val)
Orientation (rad) wrt vehicle local frame.
Definition: Wheel.h:65
double getW() const
Spinning velocity (rad/s) wrt shaft.
Definition: Wheel.h:69
GLint GLint GLint GLint GLint x
Ch * name() const
Definition: rapidxml.hpp:673
double y
Definition: Wheel.h:36
std::shared_ptr< SensorBase > Ptr
Definition: SensorBase.h:24
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
void internal_internalGuiUpdate_sensors(mrpt::opengl::COpenGLScene &scene)
virtual void create_multibody_system(b2World &world)
std::shared_ptr< VehicleBase > Ptr
Definition: VehicleBase.h:44
mrpt::opengl::CSetOfLines::Ptr m_gl_forces
Definition: VehicleBase.h:216
std::mutex m_force_segments_for_rendering_cs
Definition: VehicleBase.h:217
GLfloat GLfloat p
TGUI_Options m_gui_options
Definition: World.h:311
double diameter
Definition: Wheel.h:39
virtual const char * what() const
Definition: rapidxml.hpp:85
static constexpr char PL_Q_Y[]
Definition: VehicleBase.h:228
static constexpr char WL_FRIC_X[]
Definition: VehicleBase.h:241
static constexpr char PL_DQ_X[]
Definition: VehicleBase.h:233
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
#define b2_maxPolygonVertices
Definition: b2Settings.h:54
Ptr create(const std::string &class_name, ARG1 a1) const
Definition: ClassFactory.h:39
static void register_vehicle_class(const rapidxml::xml_node< char > *xml_node)
std::map< std::string, std::shared_ptr< CSVLogger > > m_loggers
Definition: VehicleBase.h:148
void GetMassData(b2MassData *massData) const
Definition: b2Fixture.h:334
void rotate(const double ang)
virtual void registerOnServer(mvsim::Client &c)
Definition: Simulable.cpp:150
void registerOnServer(mvsim::Client &c) override
TListSensors m_sensors
Sensors aboard.
Definition: VehicleBase.h:178
float32 density
The density, usually in kg/m^2.
Definition: b2Fixture.h:83
const Wheel & getWheelInfo(const size_t idx) const
Definition: VehicleBase.h:84
double yaw
Definition: Wheel.h:36
virtual void invoke_motor_controllers(const TSimulContext &context, std::vector< double > &out_force_per_wheel)=0
void SetAsBox(float32 hx, float32 hy)
virtual void simul_post_timestep(const TSimulContext &context)
Definition: Simulable.cpp:38
double getPhi() const
Orientation (rad) wrt vehicle local frame.
Definition: Wheel.h:61
const rapidxml::xml_node< Ch > * first_node(const char *name)
Definition: JointXMLnode.h:28
GLdouble GLdouble z
float32 y
Definition: b2Math.h:139
std::vector< Wheel > m_wheels_info
Definition: VehicleBase.h:197
virtual void simul_pre_timestep(const TSimulContext &context)
Definition: Simulable.cpp:25
std::vector< mrpt::opengl::CSetOfObjects::Ptr > m_gl_wheels
Definition: VehicleBase.h:215
void Set(const b2Vec2 *points, int32 count)
virtual void writeLogStrings()
mrpt::math::TPoint2D wheel_speed
Definition: FrictionBase.h:42
double motor_torque
(Newtons), excluding the weight of the wheel itself.
Definition: FrictionBase.h:39
#define ASSERT_(f)
virtual mrpt::poses::CPose3D internalGuiGetVisualPose() override
float32 restitution
The restitution (elasticity) usually in the range [0,1].
Definition: b2Fixture.h:80
std::mutex m_gui_mtx
Definition: VehicleBase.h:220
const rapidxml::xml_node< char > * get(const std::string &xml_node_class) const
static constexpr char WL_VEL_Y[]
Definition: VehicleBase.h:240
std::vector< b2Fixture * > m_fixture_wheels
Definition: VehicleBase.h:204
static constexpr char LOGGER_POSE[]
Definition: VehicleBase.h:224
double m_chassis_z_min
each change via updateMaxRadiusFromPoly()
Definition: VehicleBase.h:188
static FrictionBase::Ptr factory(VehicleBase &parent, const rapidxml::xml_node< char > *xml_node)
string ss
This file contains rapidxml printer implementation.
void add(const std::string &input_xml_node_class)
static constexpr char WL_WEIGHT[]
Definition: VehicleBase.h:238
GLdouble GLdouble GLdouble GLdouble q
float32 x
Definition: b2Math.h:139
void register_all_veh_dynamics()
Definition: VehicleBase.cpp:42
static XmlClassesRegistry veh_classes_registry("vehicle:class")
std::string m_name
Definition: Simulable.h:118
mrpt::math::TPoint2D m_chassis_com
Definition: VehicleBase.h:191
GLint GLint GLint GLint GLint GLint GLsizei width
mrpt::math::TPolygon2D m_chassis_poly
Definition: VehicleBase.h:185
static constexpr char WL_FRIC_Y[]
Definition: VehicleBase.h:242
b2Fixture * m_fixture_chassis
Created at.
Definition: VehicleBase.h:203
This holds the mass data computed for a shape.
Definition: b2Shape.h:27
virtual void apply_force(const mrpt::math::TVector2D &force, const mrpt::math::TPoint2D &applyPoint=mrpt::math::TPoint2D(0, 0)) override
void add(const rapidxml::xml_node< Ch > *node)
Definition: JointXMLnode.h:27
float32 friction
The friction coefficient, usually in the range [0,1].
Definition: b2Fixture.h:77
virtual double getChassisMass() const
Definition: VehicleBase.h:76
b2Body * CreateBody(const b2BodyDef *def)
Definition: b2World.cpp:107
FrictionBasePtr m_friction
Definition: VehicleBase.h:176
mrpt::math::TTwist2D getTwist() const
Definition: Simulable.h:63
static constexpr char DL_TIMESTAMP[]
Definition: VehicleBase.h:223
virtual void simul_pre_timestep(const TSimulContext &context) override


mvsim
Author(s):
autogenerated on Fri May 7 2021 03:05:51