00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <mvsim/World.h>
00011 #include <mvsim/VehicleBase.h>
00012 #include <mvsim/VehicleDynamics/VehicleAckermann.h>
00013 #include <mvsim/VehicleDynamics/VehicleAckermann_Drivetrain.h>
00014 #include <mvsim/VehicleDynamics/VehicleDifferential.h>
00015 #include <mvsim/FrictionModels/FrictionBase.h>
00016 #include <mvsim/FrictionModels/DefaultFriction.h>
00017
00018 #include "JointXMLnode.h"
00019 #include "XMLClassesRegistry.h"
00020 #include "xml_utils.h"
00021
00022 #include <rapidxml.hpp>
00023 #include <rapidxml_utils.hpp>
00024 #include <rapidxml_print.hpp>
00025 #include <mrpt/utils/utils_defs.h>
00026 #include <mrpt/poses/CPose2D.h>
00027 #include <mrpt/opengl/CPolyhedron.h>
00028
00029 #include <sstream>
00030 #include <map>
00031 #include <string>
00032
00033 using namespace mvsim;
00034 using namespace std;
00035
00036 XmlClassesRegistry veh_classes_registry("vehicle:class");
00037
00038 TClassFactory_vehicleDynamics mvsim::classFactory_vehicleDynamics;
00039
00040
00041
00042 void register_all_veh_dynamics()
00043 {
00044 static bool done = false;
00045 if (done)
00046 return;
00047 else
00048 done = true;
00049
00050 REGISTER_VEHICLE_DYNAMICS("differential", DynamicsDifferential)
00051 REGISTER_VEHICLE_DYNAMICS("ackermann", DynamicsAckermann)
00052 REGISTER_VEHICLE_DYNAMICS(
00053 "ackermann_drivetrain", DynamicsAckermannDrivetrain)
00054 }
00055
00056 constexpr char VehicleBase::DL_TIMESTAMP[];
00057 constexpr char VehicleBase::LOGGER_POSE[];
00058 constexpr char VehicleBase::LOGGER_WHEEL[];
00059
00060 constexpr char VehicleBase::PL_Q_X[];
00061 constexpr char VehicleBase::PL_Q_Y[];
00062 constexpr char VehicleBase::PL_Q_Z[];
00063 constexpr char VehicleBase::PL_Q_YAW[];
00064 constexpr char VehicleBase::PL_Q_PITCH[];
00065 constexpr char VehicleBase::PL_Q_ROLL[];
00066 constexpr char VehicleBase::PL_DQ_X[];
00067 constexpr char VehicleBase::PL_DQ_Y[];
00068 constexpr char VehicleBase::PL_DQ_Z[];
00069
00070 constexpr char VehicleBase::WL_TORQUE[];
00071 constexpr char VehicleBase::WL_WEIGHT[];
00072 constexpr char VehicleBase::WL_VEL_X[];
00073 constexpr char VehicleBase::WL_VEL_Y[];
00074 constexpr char VehicleBase::WL_FRIC_X[];
00075 constexpr char VehicleBase::WL_FRIC_Y[];
00076
00077
00078 VehicleBase::VehicleBase(World* parent, size_t nWheels)
00079 : VisualObject(parent),
00080 m_vehicle_index(0),
00081 m_b2d_vehicle_body(NULL),
00082 m_q(0, 0, 0, 0, 0, 0),
00083 m_dq(0, 0, 0),
00084 m_chassis_mass(15.0),
00085 m_chassis_z_min(0.05),
00086 m_chassis_z_max(0.6),
00087 m_chassis_color(0xff, 0x00, 0x00),
00088 m_chassis_com(.0, .0),
00089 m_wheels_info(nWheels),
00090 m_fixture_wheels(nWheels, NULL)
00091 {
00092 using namespace mrpt::math;
00093
00094 m_chassis_poly.push_back(TPoint2D(-0.4, -0.5));
00095 m_chassis_poly.push_back(TPoint2D(-0.4, 0.5));
00096 m_chassis_poly.push_back(TPoint2D(0.4, 0.5));
00097 m_chassis_poly.push_back(TPoint2D(0.6, 0.3));
00098 m_chassis_poly.push_back(TPoint2D(0.6, -0.3));
00099 m_chassis_poly.push_back(TPoint2D(0.4, -0.5));
00100 updateMaxRadiusFromPoly();
00101 }
00102
00103 void VehicleBase::simul_post_timestep_common(const TSimulContext& context)
00104 {
00105 if (m_b2d_vehicle_body)
00106 {
00107
00108 const b2Vec2& pos = m_b2d_vehicle_body->GetPosition();
00109 const float32 angle = m_b2d_vehicle_body->GetAngle();
00110 m_q.x = pos(0);
00111 m_q.y = pos(1);
00112 m_q.yaw = angle;
00113
00114
00115
00116
00117 const b2Vec2& vel = m_b2d_vehicle_body->GetLinearVelocity();
00118 const float32 w = m_b2d_vehicle_body->GetAngularVelocity();
00119 m_dq.vals[0] = vel(0);
00120 m_dq.vals[1] = vel(1);
00121 m_dq.vals[2] = w;
00122 }
00123 }
00124
00127 void VehicleBase::register_vehicle_class(
00128 const rapidxml::xml_node<char>* xml_node)
00129 {
00130
00131 if (!xml_node)
00132 throw runtime_error(
00133 "[VehicleBase::register_vehicle_class] XML node is NULL");
00134 if (0 != strcmp(xml_node->name(), "vehicle:class"))
00135 throw runtime_error(
00136 mrpt::format(
00137 "[VehicleBase::register_vehicle_class] XML element is '%s' "
00138 "('vehicle:class' expected)",
00139 xml_node->name()));
00140
00141
00142
00143 std::stringstream ss;
00144 ss << *xml_node;
00145
00146 veh_classes_registry.add(ss.str());
00147 }
00148
00151 VehicleBase* VehicleBase::factory(
00152 World* parent, const rapidxml::xml_node<char>* root)
00153 {
00154 register_all_veh_dynamics();
00155
00156 using namespace std;
00157 using namespace rapidxml;
00158
00159 if (!root) throw runtime_error("[VehicleBase::factory] XML node is NULL");
00160 if (0 != strcmp(root->name(), "vehicle"))
00161 throw runtime_error(
00162 mrpt::format(
00163 "[VehicleBase::factory] XML root element is '%s' ('vehicle' "
00164 "expected)",
00165 root->name()));
00166
00167
00168
00169
00170
00171 JointXMLnode<> veh_root_node;
00172 {
00173 veh_root_node.add(
00174 root);
00175
00176 const xml_attribute<>* veh_class = root->first_attribute("class");
00177 if (veh_class)
00178 {
00179 const string sClassName = veh_class->value();
00180 const rapidxml::xml_node<char>* class_root =
00181 veh_classes_registry.get(sClassName);
00182 if (!class_root)
00183 throw runtime_error(
00184 mrpt::format(
00185 "[VehicleBase::factory] Vehicle class '%s' undefined",
00186 sClassName.c_str()));
00187
00188 veh_root_node.add(class_root);
00189
00190 }
00191 }
00192
00193
00194
00195 const xml_node<>* dyn_node = veh_root_node.first_node("dynamics");
00196 if (!dyn_node)
00197 throw runtime_error(
00198 "[VehicleBase::factory] Missing XML node <dynamics>");
00199
00200 const xml_attribute<>* dyn_class = dyn_node->first_attribute("class");
00201 if (!dyn_class || !dyn_class->value())
00202 throw runtime_error(
00203 "[VehicleBase::factory] Missing mandatory attribute 'class' in "
00204 "node <dynamics>");
00205
00206 VehicleBase* veh =
00207 classFactory_vehicleDynamics.create(dyn_class->value(), parent);
00208 if (!veh)
00209 throw runtime_error(
00210 mrpt::format(
00211 "[VehicleBase::factory] Unknown vehicle dynamics class '%s'",
00212 dyn_class->value()));
00213
00214
00215
00216
00217 {
00218 const xml_attribute<>* attrib_name = root->first_attribute("name");
00219 if (attrib_name && attrib_name->value())
00220 {
00221 veh->m_name = attrib_name->value();
00222 }
00223 else
00224 {
00225
00226 static int cnt = 0;
00227 veh->m_name = mrpt::format("veh%i", ++cnt);
00228 }
00229 }
00230
00231
00232 {
00233 const xml_node<>* node = veh_root_node.first_node("init_pose");
00234 if (!node)
00235 throw runtime_error(
00236 "[VehicleBase::factory] Missing XML node <init_pose>");
00237
00238 if (3 != ::sscanf(
00239 node->value(), "%lf %lf %lf", &veh->m_q.x, &veh->m_q.y,
00240 &veh->m_q.yaw))
00241 throw runtime_error(
00242 "[VehicleBase::factory] Error parsing "
00243 "<init_pose>...</init_pose>");
00244 veh->m_q.yaw *= M_PI / 180.0;
00245 }
00246
00247
00248 {
00249 const xml_node<>* node = veh_root_node.first_node("init_vel");
00250 if (node)
00251 {
00252 if (3 != ::sscanf(
00253 node->value(), "%lf %lf %lf", &veh->m_dq.vals[0],
00254 &veh->m_dq.vals[1], &veh->m_dq.vals[2]))
00255 throw runtime_error(
00256 "[VehicleBase::factory] Error parsing "
00257 "<init_vel>...</init_vel>");
00258 veh->m_dq.vals[2] *= M_PI / 180.0;
00259
00260
00261 const mrpt::poses::CPose2D pose(
00262 0, 0, veh->m_q.yaw);
00263 pose.composePoint(
00264 veh->m_dq.vals[0], veh->m_dq.vals[1], veh->m_dq.vals[0],
00265 veh->m_dq.vals[1]);
00266 }
00267 }
00268
00269
00270
00271 veh->dynamics_load_params_from_xml(dyn_node);
00272
00273
00274
00275 {
00276 const xml_node<>* log_path_node = veh_root_node.first_node("log_path");
00277 if (log_path_node)
00278 {
00279
00280 veh->m_log_path = log_path_node->value();
00281 }
00282 }
00283
00284 veh->initLoggers();
00285
00286
00287
00288 b2World* b2world = parent->getBox2DWorld();
00289 veh->create_multibody_system(b2world);
00290
00291 if (veh->m_b2d_vehicle_body)
00292 {
00293
00294 veh->m_b2d_vehicle_body->SetTransform(
00295 b2Vec2(veh->m_q.x, veh->m_q.y), veh->m_q.yaw);
00296
00297 veh->m_b2d_vehicle_body->SetLinearVelocity(
00298 b2Vec2(veh->m_dq.vals[0], veh->m_dq.vals[1]));
00299 veh->m_b2d_vehicle_body->SetAngularVelocity(veh->m_dq.vals[2]);
00300 }
00301
00302
00303
00304
00305 {
00306 const xml_node<>* frict_node = veh_root_node.first_node("friction");
00307 if (!frict_node)
00308 {
00309
00310 veh->m_friction = std::shared_ptr<FrictionBase>(
00311 new DefaultFriction(*veh, NULL ));
00312 }
00313 else
00314 {
00315
00316 veh->m_friction = std::shared_ptr<FrictionBase>(
00317 FrictionBase::factory(*veh, frict_node));
00318 ASSERT_(veh->m_friction)
00319 }
00320 }
00321
00322
00323
00324 for (JointXMLnode<>::iterator it = veh_root_node.begin();
00325 it != veh_root_node.end(); ++it)
00326 {
00327 if (!strcmp(it->name(), "sensor"))
00328 {
00329 SensorBase* se = SensorBase::factory(*veh, *it);
00330 veh->m_sensors.push_back(SensorBase::Ptr(se));
00331 }
00332 }
00333
00334 return veh;
00335 }
00336
00337 VehicleBase* VehicleBase::factory(World* parent, const std::string& xml_text)
00338 {
00339
00340 std::stringstream s;
00341 s.str(xml_text);
00342
00343 char* input_str = const_cast<char*>(xml_text.c_str());
00344 rapidxml::xml_document<> xml;
00345 try
00346 {
00347 xml.parse<0>(input_str);
00348 }
00349 catch (rapidxml::parse_error& e)
00350 {
00351 unsigned int line =
00352 static_cast<long>(std::count(input_str, e.where<char>(), '\n') + 1);
00353 throw std::runtime_error(
00354 mrpt::format(
00355 "[VehicleBase::factory] XML parse error (Line %u): %s",
00356 static_cast<unsigned>(line), e.what()));
00357 }
00358 return VehicleBase::factory(parent, xml.first_node());
00359 }
00360
00361 void VehicleBase::simul_pre_timestep(const TSimulContext& context)
00362 {
00363
00364
00365 for (size_t i = 0; i < m_fixture_wheels.size(); i++)
00366 {
00367 b2PolygonShape* wheelShape =
00368 dynamic_cast<b2PolygonShape*>(m_fixture_wheels[i]->GetShape());
00369 wheelShape->SetAsBox(
00370 m_wheels_info[i].diameter * 0.5, m_wheels_info[i].width * 0.5,
00371 b2Vec2(m_wheels_info[i].x, m_wheels_info[i].y),
00372 m_wheels_info[i].yaw);
00373 }
00374
00375
00376 this->invoke_motor_controllers(context, m_torque_per_wheel);
00377
00378
00379 const size_t nW = getNumWheels();
00380 ASSERT_EQUAL_(m_torque_per_wheel.size(), nW);
00381
00382 const double gravity = getWorldObject()->get_gravity();
00383 const double massPerWheel =
00384 getChassisMass() / nW;
00385 const double weightPerWheel = massPerWheel * gravity;
00386
00387 std::vector<mrpt::math::TPoint2D> wheels_vels;
00388 getWheelsVelocityLocal(wheels_vels, getVelocityLocal());
00389
00390 ASSERT_EQUAL_(wheels_vels.size(), nW);
00391
00392 std::vector<mrpt::math::TSegment3D>
00393 force_vectors;
00394
00395 for (size_t i = 0; i < nW; i++)
00396 {
00397
00398 Wheel& w = getWheelInfo(i);
00399
00400 FrictionBase::TFrictionInput fi(context, w);
00401 fi.motor_torque =
00402 -m_torque_per_wheel[i];
00403 fi.weight = weightPerWheel;
00404 fi.wheel_speed = wheels_vels[i];
00405
00406 m_friction->setLogger(
00407 getLoggerPtr(LOGGER_WHEEL + std::to_string(i + 1)));
00408
00409 mrpt::math::TPoint2D net_force_;
00410 m_friction->evaluate_friction(fi, net_force_);
00411
00412
00413 const b2Vec2 wForce = m_b2d_vehicle_body->GetWorldVector(
00414 b2Vec2(
00415 net_force_.x, net_force_.y));
00416 const b2Vec2 wPt = m_b2d_vehicle_body->GetWorldPoint(
00417 b2Vec2(w.x, w.y));
00418
00419
00420
00421 m_b2d_vehicle_body->ApplyForce(wForce, wPt, true );
00422
00423
00424 {
00425 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00426 DL_TIMESTAMP, context.simul_time);
00427 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00428 WL_TORQUE, fi.motor_torque);
00429 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00430 WL_WEIGHT, fi.weight);
00431 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00432 WL_VEL_X, fi.wheel_speed.x);
00433 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00434 WL_VEL_Y, fi.wheel_speed.y);
00435 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00436 WL_FRIC_X, net_force_.x);
00437 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->updateColumn(
00438 WL_FRIC_Y, net_force_.y);
00439 }
00440
00441
00442 if (m_world->m_gui_options.show_forces)
00443 {
00444 const double forceScale =
00445 m_world->m_gui_options.force_scale;
00446 const mrpt::math::TPoint3D pt1(
00447 wPt.x, wPt.y, m_chassis_z_max * 1.1 + m_q.z);
00448 const mrpt::math::TPoint3D pt2 =
00449 pt1 + mrpt::math::TPoint3D(wForce.x, wForce.y, 0) * forceScale;
00450 force_vectors.push_back(mrpt::math::TSegment3D(pt1, pt2));
00451 }
00452 }
00453
00454
00455 if (m_world->m_gui_options.show_forces)
00456 {
00457 std::lock_guard<std::mutex> csl(m_force_segments_for_rendering_cs);
00458 m_force_segments_for_rendering = force_vectors;
00459 }
00460 }
00461
00464 void VehicleBase::simul_post_timestep(const TSimulContext& context)
00465 {
00466
00467 const size_t nW = getNumWheels();
00468
00469 for (size_t i = 0; i < nW; i++)
00470 {
00471
00472 Wheel& w = getWheelInfo(i);
00473
00474
00475 w.setPhi(w.getPhi() + w.getW() * context.dt);
00476
00477
00478
00479
00480 const double cur_abs_phi = std::abs(w.getPhi());
00481 if (cur_abs_phi > 1e4)
00482 w.setPhi(
00483 ::fmod(cur_abs_phi, 2 * M_PI) *
00484 (w.getPhi() < 0.0 ? -1.0 : 1.0));
00485 }
00486
00487 m_loggers[LOGGER_POSE]->updateColumn(DL_TIMESTAMP, context.simul_time);
00488 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_X, m_q.x);
00489 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_Y, m_q.y);
00490 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_Z, m_q.z);
00491 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_YAW, m_q.yaw);
00492 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_PITCH, m_q.pitch);
00493 m_loggers[LOGGER_POSE]->updateColumn(PL_Q_ROLL, m_q.roll);
00494 m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_X, m_dq.vals[0]);
00495 m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_Y, m_dq.vals[1]);
00496 m_loggers[LOGGER_POSE]->updateColumn(PL_DQ_Z, m_dq.vals[2]);
00497
00498 {
00499 writeLogStrings();
00500 }
00501 }
00502
00504 void VehicleBase::getWheelsVelocityLocal(
00505 std::vector<mrpt::math::TPoint2D>& vels, const vec3& veh_vel_local) const
00506 {
00507
00508
00509
00510
00511
00512 const double w = veh_vel_local.vals[2];
00513
00514 const size_t nW = this->getNumWheels();
00515 vels.resize(nW);
00516 for (size_t i = 0; i < nW; i++)
00517 {
00518 const Wheel& wheel = getWheelInfo(i);
00519
00520 vels[i].x = veh_vel_local.vals[0] - w * wheel.y;
00521 vels[i].y = veh_vel_local.vals[1] + w * wheel.x;
00522 }
00523 }
00524
00526 vec3 VehicleBase::getVelocityLocal() const
00527 {
00528 vec3 local_vel;
00529 local_vel.vals[2] = m_dq.vals[2];
00530
00531 const mrpt::poses::CPose2D p(0, 0, -m_q.yaw);
00532 p.composePoint(
00533 m_dq.vals[0], m_dq.vals[1], local_vel.vals[0], local_vel.vals[1]);
00534 return local_vel;
00535 }
00536
00537 mrpt::poses::CPose2D VehicleBase::getCPose2D() const
00538 {
00539 return mrpt::poses::CPose2D(mrpt::math::TPose2D(m_q));
00540 }
00541
00543 void VehicleBase::gui_update_common(
00544 mrpt::opengl::COpenGLScene& scene, bool defaultVehicleBody)
00545 {
00546
00547
00548 if (defaultVehicleBody)
00549 {
00550 const size_t nWs = this->getNumWheels();
00551 if (!m_gl_chassis)
00552 {
00553 m_gl_chassis =
00554 mrpt::make_aligned_shared<mrpt::opengl::CSetOfObjects>();
00555
00556
00557 m_gl_wheels.resize(nWs);
00558 for (size_t i = 0; i < nWs; i++)
00559 {
00560 m_gl_wheels[i] =
00561 mrpt::make_aligned_shared<mrpt::opengl::CSetOfObjects>();
00562 this->getWheelInfo(i).getAs3DObject(*m_gl_wheels[i]);
00563 m_gl_chassis->insert(m_gl_wheels[i]);
00564 }
00565
00566 mrpt::opengl::CPolyhedron::Ptr gl_poly =
00567 mrpt::opengl::CPolyhedron::CreateCustomPrism(
00568 m_chassis_poly, m_chassis_z_max - m_chassis_z_min);
00569 gl_poly->setLocation(0, 0, m_chassis_z_min);
00570 gl_poly->setColor(mrpt::utils::TColorf(m_chassis_color));
00571 m_gl_chassis->insert(gl_poly);
00572
00573 SCENE_INSERT_Z_ORDER(scene, 1, m_gl_chassis);
00574
00575
00576 m_gl_forces =
00577 mrpt::make_aligned_shared<mrpt::opengl::CSetOfLines>();
00578 m_gl_forces->setLineWidth(3.0);
00579 m_gl_forces->setColor_u8(mrpt::utils::TColor(0xff, 0xff, 0xff));
00580
00581 SCENE_INSERT_Z_ORDER(
00582 scene, 3, m_gl_forces);
00583 }
00584
00585
00586
00587 m_gl_chassis->setPose(m_q);
00588
00589 for (size_t i = 0; i < nWs; i++)
00590 {
00591 const Wheel& w = getWheelInfo(i);
00592 m_gl_wheels[i]->setPose(
00593 mrpt::math::TPose3D(
00594 w.x, w.y, 0.5 * w.diameter, w.yaw, w.getPhi(), 0.0));
00595 }
00596 }
00597
00598
00599 internal_gui_update_sensors(scene);
00600 internal_gui_update_forces(scene);
00601 }
00602
00603 void VehicleBase::internal_gui_update_sensors(mrpt::opengl::COpenGLScene& scene)
00604 {
00605 for (TListSensors::iterator it = m_sensors.begin(); it != m_sensors.end();
00606 ++it)
00607 (*it)->gui_update(scene);
00608 }
00609
00610 void VehicleBase::internal_gui_update_forces(mrpt::opengl::COpenGLScene& scene)
00611 {
00612 if (m_world->m_gui_options.show_forces)
00613 {
00614 std::lock_guard<std::mutex> csl(m_force_segments_for_rendering_cs);
00615 m_gl_forces->clear();
00616 m_gl_forces->appendLines(m_force_segments_for_rendering);
00617 m_gl_forces->setVisibility(true);
00618 }
00619 else
00620 {
00621 m_gl_forces->setVisibility(false);
00622 }
00623 }
00624
00625 void VehicleBase::updateMaxRadiusFromPoly()
00626 {
00627 using namespace mrpt::math;
00628
00629 m_max_radius = 0.001f;
00630 for (TPolygon2D::const_iterator it = m_chassis_poly.begin();
00631 it != m_chassis_poly.end(); ++it)
00632 {
00633 const float n = it->norm();
00634 mrpt::utils::keep_max(m_max_radius, n);
00635 }
00636 }
00637
00639 void VehicleBase::create_multibody_system(b2World* world)
00640 {
00641
00642 b2BodyDef bodyDef;
00643 bodyDef.type = b2_dynamicBody;
00644
00645 m_b2d_vehicle_body = world->CreateBody(&bodyDef);
00646
00647
00648
00649 {
00650
00651 const size_t nPts = m_chassis_poly.size();
00652 ASSERT_(nPts >= 3)
00653 ASSERT_BELOWEQ_(nPts, (size_t)b2_maxPolygonVertices)
00654 std::vector<b2Vec2> pts(nPts);
00655 for (size_t i = 0; i < nPts; i++)
00656 pts[i] = b2Vec2(m_chassis_poly[i].x, m_chassis_poly[i].y);
00657
00658 b2PolygonShape chassisPoly;
00659 chassisPoly.Set(&pts[0], nPts);
00660
00661
00662
00663 b2FixtureDef fixtureDef;
00664 fixtureDef.shape = &chassisPoly;
00665 fixtureDef.restitution = 0.01;
00666
00667
00668 b2MassData mass;
00669 chassisPoly.ComputeMass(
00670 &mass, 1);
00671 fixtureDef.density = m_chassis_mass / mass.mass;
00672
00673
00674 fixtureDef.friction = 0.3f;
00675
00676
00677 m_fixture_chassis = m_b2d_vehicle_body->CreateFixture(&fixtureDef);
00678
00679
00680 b2MassData vehMass;
00681 m_fixture_chassis->GetMassData(&vehMass);
00682 m_chassis_com.x = vehMass.center.x;
00683 m_chassis_com.y = vehMass.center.y;
00684 }
00685
00686
00687
00688 ASSERT_EQUAL_(m_fixture_wheels.size(), m_wheels_info.size())
00689
00690 for (size_t i = 0; i < m_wheels_info.size(); i++)
00691 {
00692 b2PolygonShape wheelShape;
00693 wheelShape.SetAsBox(
00694 m_wheels_info[i].diameter * 0.5, m_wheels_info[i].width * 0.5,
00695 b2Vec2(m_wheels_info[i].x, m_wheels_info[i].y),
00696 m_wheels_info[i].yaw);
00697
00698
00699 b2FixtureDef fixtureDef;
00700 fixtureDef.shape = &wheelShape;
00701 fixtureDef.restitution = 0.05;
00702
00703
00704 b2MassData mass;
00705 wheelShape.ComputeMass(
00706 &mass, 1);
00707 fixtureDef.density = m_wheels_info[i].mass / mass.mass;
00708
00709
00710 fixtureDef.friction = 0.5f;
00711
00712 m_fixture_wheels[i] = m_b2d_vehicle_body->CreateFixture(&fixtureDef);
00713 }
00714 }
00715
00716 void VehicleBase::gui_update(mrpt::opengl::COpenGLScene& scene)
00717 {
00718 this->gui_update_common(scene);
00719 }
00720
00721 void VehicleBase::initLoggers()
00722 {
00723 m_loggers[LOGGER_POSE] = std::make_shared<CSVLogger>();
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 m_loggers[LOGGER_POSE]->setFilepath(
00735 m_log_path + "mvsim_" + m_name + LOGGER_POSE + ".log");
00736
00737 for (size_t i = 0; i < getNumWheels(); i++)
00738 {
00739 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)] =
00740 std::make_shared<CSVLogger>();
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755 m_loggers[LOGGER_WHEEL + std::to_string(i + 1)]->setFilepath(
00756 m_log_path + "mvsim_" + m_name + LOGGER_WHEEL +
00757 std::to_string(i + 1) + ".log");
00758 }
00759 }
00760
00761 void VehicleBase::writeLogStrings()
00762 {
00763 std::map<std::string, std::shared_ptr<CSVLogger>>::iterator it;
00764 for (it = m_loggers.begin(); it != m_loggers.end(); ++it)
00765 {
00766 it->second->writeRow();
00767 }
00768 }
00769
00770 void VehicleBase::apply_force(
00771 double fx, double fy, double local_ptx, double local_pty)
00772 {
00773 ASSERT_(m_b2d_vehicle_body)
00774 const b2Vec2 wPt = m_b2d_vehicle_body->GetWorldPoint(
00775 b2Vec2(local_ptx, local_pty));
00776 m_b2d_vehicle_body->ApplyForce(b2Vec2(fx, fy), wPt, true );
00777 }