VehicleBase.cpp
Go to the documentation of this file.
00001 /*+-------------------------------------------------------------------------+
00002   |                       MultiVehicle simulator (libmvsim)                 |
00003   |                                                                         |
00004   | Copyright (C) 2014  Jose Luis Blanco Claraco (University of Almeria)    |
00005   | Copyright (C) 2017  Borys Tymchenko (Odessa Polytechnic University)     |
00006   | Distributed under GNU General Public License version 3                  |
00007   |   See <http://www.gnu.org/licenses/>                                    |
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>  // For use as default model
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>  // mrpt::format()
00026 #include <mrpt/poses/CPose2D.h>
00027 #include <mrpt/opengl/CPolyhedron.h>
00028 
00029 #include <sstream>  // std::stringstream
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 // Explicit registration calls seem to be one (the unique?) way to assure
00041 // registration takes place:
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 // Protected ctor:
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         // Default shape:
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                 // Pos:
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                 // The rest (z,pitch,roll) will be always 0, unless other world-element
00114                 // modifies them! (e.g. elevation map)
00115 
00116                 // Vel:
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         // Sanity checks:
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         // rapidxml doesn't allow making copied of objects.
00142         // So: convert to txt; then re-parse.
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         // "class": When a vehicle has a 'class="XXX"' attribute, look for each
00168         // parameter
00169         //  in the set of "root" + "class_root" XML nodes:
00170         // --------------------------------------------------------------------------------
00171         JointXMLnode<> veh_root_node;
00172         {
00173                 veh_root_node.add(
00174                         root);  // Always search in root. Also in the class root, if any:
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                         // cout << *class_root;
00190                 }
00191         }
00192 
00193         // Class factory according to: <dynamics class="XXX">
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         // Initialize here all common params shared by any polymorphic class:
00215         // -------------------------------------------------
00216         // attrib: name
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                         // Default name:
00226                         static int cnt = 0;
00227                         veh->m_name = mrpt::format("veh%i", ++cnt);
00228                 }
00229         }
00230 
00231         // (Mandatory) initial pose:
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;  // deg->rad
00245         }
00246 
00247         // (Optional) initial vel:
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;  // deg->rad
00259 
00260                         // Convert twist (velocity) from local -> global coords:
00261                         const mrpt::poses::CPose2D pose(
00262                                 0, 0, veh->m_q.yaw);  // Only the rotation
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         // Initialize class-specific params:
00270         // -------------------------------------------------
00271         veh->dynamics_load_params_from_xml(dyn_node);
00272 
00273         // <Optional> Log path. If not specified, app folder will be used
00274         // -----------------------------------------------------------
00275         {
00276                 const xml_node<>* log_path_node = veh_root_node.first_node("log_path");
00277                 if (log_path_node)
00278                 {
00279                         // Parse:
00280                         veh->m_log_path = log_path_node->value();
00281                 }
00282         }
00283 
00284         veh->initLoggers();
00285 
00286         // Register bodies, fixtures, etc. in Box2D simulator:
00287         // ----------------------------------------------------
00288         b2World* b2world = parent->getBox2DWorld();
00289         veh->create_multibody_system(b2world);
00290 
00291         if (veh->m_b2d_vehicle_body)
00292         {
00293                 // Init pos:
00294                 veh->m_b2d_vehicle_body->SetTransform(
00295                         b2Vec2(veh->m_q.x, veh->m_q.y), veh->m_q.yaw);
00296                 // Init vel:
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         // Friction model:
00303         // Parse <friction> node, or assume default linear model:
00304         // -----------------------------------------------------------
00305         {
00306                 const xml_node<>* frict_node = veh_root_node.first_node("friction");
00307                 if (!frict_node)
00308                 {
00309                         // Default:
00310                         veh->m_friction = std::shared_ptr<FrictionBase>(
00311                                 new DefaultFriction(*veh, NULL /*default params*/));
00312                 }
00313                 else
00314                 {
00315                         // Parse:
00316                         veh->m_friction = std::shared_ptr<FrictionBase>(
00317                                 FrictionBase::factory(*veh, frict_node));
00318                         ASSERT_(veh->m_friction)
00319                 }
00320         }
00321 
00322         // Sensors: <sensor class='XXX'> entries
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         // Parse the string as if it was an XML file:
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         // Update wheels position (they may turn, etc. as in an Ackermann
00364         // configuration)
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         // Apply motor forces/torques:
00376         this->invoke_motor_controllers(context, m_torque_per_wheel);
00377 
00378         // Apply friction model at each wheel:
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;  // Part of the vehicle weight on each wheel.
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;  // For visualization only
00394 
00395         for (size_t i = 0; i < nW; i++)
00396         {
00397                 // prepare data:
00398                 Wheel& w = getWheelInfo(i);
00399 
00400                 FrictionBase::TFrictionInput fi(context, w);
00401                 fi.motor_torque =
00402                         -m_torque_per_wheel[i];  // "-" => Forwards is negative
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                 // eval friction:
00409                 mrpt::math::TPoint2D net_force_;
00410                 m_friction->evaluate_friction(fi, net_force_);
00411 
00412                 // Apply force:
00413                 const b2Vec2 wForce = m_b2d_vehicle_body->GetWorldVector(
00414                         b2Vec2(
00415                                 net_force_.x, net_force_.y));  // Force vector -> world coords
00416                 const b2Vec2 wPt = m_b2d_vehicle_body->GetWorldPoint(
00417                         b2Vec2(w.x, w.y));  // Application point -> world coords
00418                 // printf("w%i: Lx=%6.3f Ly=%6.3f  | Gx=%11.9f
00419                 // Gy=%11.9f\n",(int)i,net_force_.x,net_force_.y,wForce.x,wForce.y);
00420 
00421                 m_b2d_vehicle_body->ApplyForce(wForce, wPt, true /*wake up*/);
00422 
00423                 // log
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                 // save it for optional rendering:
00442                 if (m_world->m_gui_options.show_forces)
00443                 {
00444                         const double forceScale =
00445                                 m_world->m_gui_options.force_scale;  // [meters/N]
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         // Save forces for optional rendering:
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         // Integrate wheels' rotation:
00467         const size_t nW = getNumWheels();
00468 
00469         for (size_t i = 0; i < nW; i++)
00470         {
00471                 // prepare data:
00472                 Wheel& w = getWheelInfo(i);
00473 
00474                 // Explicit Euler:
00475                 w.setPhi(w.getPhi() + w.getW() * context.dt);
00476 
00477                 // Wrap wheel spin position (angle), so it doesn't
00478                 // become excessively large (it's actually unbound, but we don't want to
00479                 // lose 'double' accuracy):
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         // Each wheel velocity is:
00508         // v_w = v_veh + \omega \times wheel_pos
00509         // =>
00510         // v_w = v_veh + ( -w*y, w*x )
00511 
00512         const double w = veh_vel_local.vals[2];  // vehicle w
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];  // omega remains the same.
00530 
00531         const mrpt::poses::CPose2D p(0, 0, -m_q.yaw);  // "-" means inverse pose
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         // 1st time call?? -> Create objects
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                         // Wheels shape:
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                         // Robot shape:
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                         // Visualization of forces:
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);  // forces are in global coords
00583                 }
00584 
00585                 // Update them:
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         // Other common stuff:
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         // Define the dynamic body. We set its position and call the body factory.
00642         b2BodyDef bodyDef;
00643         bodyDef.type = b2_dynamicBody;
00644 
00645         m_b2d_vehicle_body = world->CreateBody(&bodyDef);
00646 
00647         // Define shape of chassis:
00648         // ------------------------------
00649         {
00650                 // Convert shape into Box2D format:
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                 // chassisPoly.m_radius = 1e-3;  // The "skin" depth of the body
00661 
00662                 // Define the dynamic body fixture.
00663                 b2FixtureDef fixtureDef;
00664                 fixtureDef.shape = &chassisPoly;
00665                 fixtureDef.restitution = 0.01;
00666 
00667                 // Set the box density to be non-zero, so it will be dynamic.
00668                 b2MassData mass;
00669                 chassisPoly.ComputeMass(
00670                         &mass, 1);  // Mass with density=1 => compute area
00671                 fixtureDef.density = m_chassis_mass / mass.mass;
00672 
00673                 // Override the default friction.
00674                 fixtureDef.friction = 0.3f;
00675 
00676                 // Add the shape to the body.
00677                 m_fixture_chassis = m_b2d_vehicle_body->CreateFixture(&fixtureDef);
00678 
00679                 // Compute center of mass:
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         // Define shape of wheels:
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                 // Define the dynamic body fixture.
00699                 b2FixtureDef fixtureDef;
00700                 fixtureDef.shape = &wheelShape;
00701                 fixtureDef.restitution = 0.05;
00702 
00703                 // Set the box density to be non-zero, so it will be dynamic.
00704                 b2MassData mass;
00705                 wheelShape.ComputeMass(
00706                         &mass, 1);  // Mass with density=1 => compute area
00707                 fixtureDef.density = m_wheels_info[i].mass / mass.mass;
00708 
00709                 // Override the default friction.
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);  // Common part: update sensors, etc.
00719 }
00720 
00721 void VehicleBase::initLoggers()
00722 {
00723         m_loggers[LOGGER_POSE] = std::make_shared<CSVLogger>();
00724         //  m_loggers[LOGGER_POSE]->addColumn(DL_TIMESTAMP);
00725         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_X);
00726         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_Y);
00727         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_Z);
00728         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_YAW);
00729         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_PITCH);
00730         //  m_loggers[LOGGER_POSE]->addColumn(PL_Q_ROLL);
00731         //  m_loggers[LOGGER_POSE]->addColumn(PL_DQ_X);
00732         //  m_loggers[LOGGER_POSE]->addColumn(PL_DQ_Y);
00733         //  m_loggers[LOGGER_POSE]->addColumn(PL_DQ_Z);
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                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00742                 //    1)]->addColumn(DL_TIMESTAMP);
00743                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00744                 //    1)]->addColumn(WL_TORQUE);
00745                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00746                 //    1)]->addColumn(WL_WEIGHT);
00747                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00748                 //    1)]->addColumn(WL_VEL_X);
00749                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00750                 //    1)]->addColumn(WL_VEL_Y);
00751                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00752                 //    1)]->addColumn(WL_FRIC_X);
00753                 //    m_loggers[LOGGER_WHEEL + std::to_string(i +
00754                 //    1)]->addColumn(WL_FRIC_Y);
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));  // Application point -> world coords
00776         m_b2d_vehicle_body->ApplyForce(b2Vec2(fx, fy), wPt, true /*wake up*/);
00777 }


mvsim
Author(s):
autogenerated on Thu Sep 7 2017 09:27:48