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> 35 using namespace mvsim;
46 static bool done =
false;
88 for (
size_t i = 0; i < nWheels; i++)
wheels_info_.emplace_back(parent);
108 "[VehicleBase::register_vehicle_class] XML node is nullptr");
109 if (0 != strcmp(xml_node->
name(),
"vehicle:class"))
110 throw runtime_error(mrpt::format(
111 "[VehicleBase::register_vehicle_class] XML element is '%s' " 112 "('vehicle:class' expected)",
117 std::stringstream ss;
134 throw runtime_error(
"[VehicleBase::factory] XML node is nullptr");
135 if (0 != strcmp(root->
name(),
"vehicle"))
136 throw runtime_error(mrpt::format(
137 "[VehicleBase::factory] XML root element is '%s' ('vehicle' " 147 std::vector<XML_Doc_Data::Ptr> scopedLifeDocs;
152 if (strcmp(n->name(),
"include") != 0)
continue;
154 auto fileAttrb = n->first_attribute(
"file");
157 "XML tag '<include />' must have a 'file=\"xxx\"' attribute)");
159 const std::string relFile =
mvsim::parse(fileAttrb->value(), {});
162 mrpt::system::LVL_DEBUG,
163 mrpt::format(
"XML parser: including file: '%s'", absFile.c_str()));
165 std::map<std::string, std::string> vars;
166 for (
auto attr = n->first_attribute(); attr;
167 attr = attr->next_attribute())
169 if (strcmp(attr->name(),
"file") == 0)
continue;
170 vars[attr->name()] = attr->value();
175 std::set<std::string> varsRetain = {
176 "NAME" ,
"PARENT_NAME" };
181 scopedLifeDocs.emplace_back(xml);
184 const auto newBasePath =
185 mrpt::system::trim(mrpt::system::extractFileDirectory(absFile));
187 nodes.
add(nRoot->parent());
198 const string sClassName = veh_class->
value();
202 throw runtime_error(mrpt::format(
203 "[VehicleBase::factory] Vehicle class '%s' undefined",
204 sClassName.c_str()));
206 nodes.
add(class_root);
212 const xml_node<>* dyn_node = nodes.
first_node(
"dynamics");
215 "[VehicleBase::factory] Missing XML node <dynamics>");
218 if (!dyn_class || !dyn_class->
value())
220 "[VehicleBase::factory] Missing mandatory attribute 'class' in " 226 throw runtime_error(mrpt::format(
227 "[VehicleBase::factory] Unknown vehicle dynamics class '%s'",
228 dyn_class->
value()));
235 if (attrib_name && attrib_name->
value())
237 veh->name_ = attrib_name->
value();
243 veh->name_ = mrpt::format(
"veh%i", ++cnt);
249 veh->parseSimulable(nodes);
253 veh->parseVisual(nodes);
257 veh->dynamics_load_params_from_xml(dyn_node);
268 const auto& bbVis = veh->collisionShape();
269 if (!bbVis.has_value())
272 "Error: Tag <shape_from_visual/> found but no " 273 "<visual> entry seems to have been found while parsing " 276 const auto& bb = bbVis.value();
277 if (bb.volume() == 0)
280 "Error: Tag <shape_from_visual/> found but bounding box of " 281 "visual object seems incorrect, while parsing <vehicle>");
285 veh->chassis_poly_ = bb.getContour();
286 veh->chassis_z_min_ = bb.zMin();
287 veh->chassis_z_max_ = bb.zMax();
294 veh->chassis_poly_, veh->chassis_z_min_, veh->chassis_z_max_);
296 veh->setCollisionShape(cs);
300 veh->updateMaxRadiusFromPoly();
305 const xml_node<>* log_path_node = nodes.
first_node(
"log_path");
309 veh->log_path_ = log_path_node->value();
322 const auto q = veh->getPose();
323 const auto dq = veh->getTwist();
325 veh->b2dBody_->SetTransform(
b2Vec2(q.x, q.y), q.yaw);
327 veh->b2dBody_->SetLinearVelocity(
b2Vec2(dq.vx, dq.vy));
328 veh->b2dBody_->SetAngularVelocity(dq.omega);
335 const xml_node<>* frict_node = nodes.
first_node(
"friction");
340 std::make_shared<DefaultFriction>(*veh,
nullptr );
345 veh->friction_ = std::shared_ptr<FrictionBase>(
347 ASSERT_(veh->friction_);
353 for (
const auto& xmlNode : nodes)
355 if (!strcmp(xmlNode->name(),
"sensor"))
372 char* input_str =
const_cast<char*
>(xml_text.c_str());
376 xml.
parse<0>(input_str);
381 static_cast<long>(std::count(input_str, e.
where<
char>(),
'\n') + 1);
382 throw std::runtime_error(mrpt::format(
383 "[VehicleBase::factory] XML parse error (Line %u): %s",
384 static_cast<unsigned>(line), e.
what()));
392 for (
auto&
s :
sensors_)
s->simul_pre_timestep(context);
410 ASSERT_EQUAL_(wheelTorque.size(), nW);
414 MRPT_TODO(
"Use chassis cog point");
416 const double weightPerWheel = massPerWheel * gravity;
418 const std::vector<mrpt::math::TVector2D> wheelLocalVels =
421 ASSERT_EQUAL_(wheelLocalVels.size(), nW);
424 std::vector<mrpt::math::TSegment3D> forceVectors, torqueVectors;
426 for (
size_t i = 0; i < nW; i++)
433 fi.
weight = weightPerWheel;
440 const mrpt::math::TPoint2D F_r =
friction_->evaluate_friction(fi);
444 const b2Vec2 wForce = b2dBody_->GetWorldVector(
b2Vec2(F_r.x, F_r.y));
451 b2dBody_->ApplyForce(wForce, wPt,
true );
477 const mrpt::math::TPoint3D pt1(
479 const mrpt::math::TPoint3D pt2 =
480 pt1 + mrpt::math::TPoint3D(wForce.
x, wForce.
y, 0) * forceScale;
482 forceVectors.emplace_back(pt1, pt2);
484 const mrpt::math::TPoint3D pt2_t =
485 pt1 + mrpt::math::TPoint3D(0, 0, wheelTorque[i]) * forceScale;
487 torqueVectors.emplace_back(pt1, pt2_t);
508 for (
auto&
s :
sensors_)
s->simul_post_timestep(context);
513 for (
size_t i = 0; i < nW; i++)
524 const double cur_abs_phi = std::abs(w.
getPhi());
525 if (cur_abs_phi > 1e4)
527 ::fmod(cur_abs_phi, 2 *
M_PI) *
528 (w.
getPhi() < 0.0 ? -1.0 : 1.0));
552 const mrpt::math::TTwist2D& veh_vel_local)
const 559 const double w = veh_vel_local.omega;
562 std::vector<mrpt::math::TVector2D> vels(nW);
564 for (
size_t i = 0; i < nW; i++)
568 vels[i].x = veh_vel_local.vx - w * wheel.
y;
569 vels[i].y = veh_vel_local.vy + w * wheel.
x;
575 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
576 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical)
578 for (
auto&
s :
sensors_)
s->guiUpdate(viz, physical);
582 [[maybe_unused]] mrpt::opengl::COpenGLScene& scene)
609 const float n = pt.norm();
630 std::vector<b2Vec2> pts(nPts);
631 for (
size_t i = 0; i < nPts; i++)
635 chassisPoly.
Set(&pts[0], nPts);
642 fixtureDef.
shape = &chassisPoly;
677 fixtureDef.
shape = &wheelShape;
694 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
695 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical,
703 glChassis_ = mrpt::opengl::CSetOfObjects::Create();
708 for (
size_t i = 0; i < nWs; i++)
710 glWheels_[i] = mrpt::opengl::CSetOfObjects::Create();
718 auto gl_poly = mrpt::opengl::CPolyhedron::CreateCustomPrism(
739 for (
size_t i = 0; i < nWs; i++)
742 glWheels_[i]->setPose(mrpt::math::TPose3D(
752 "Wheel #%zu has linked_yaw_object_name='%s' but parent " 753 "vehicle '%s' does not have any custom visual group " 757 auto p = glLinked->getPose();
759 glLinked->setPose(p);
768 glForces_ = mrpt::opengl::CSetOfLines::Create();
770 glForces_->setColor_u8(0xff, 0xff, 0xff);
809 std::make_shared<CSVLogger>();
826 std::to_string(i + 1) +
".log");
832 std::map<std::string, std::shared_ptr<CSVLogger>>::iterator it;
835 it->second->writeRow();
840 const mrpt::math::TVector2D& force,
const mrpt::math::TPoint2D& applyPoint)
844 applyPoint.x, applyPoint.y));
845 b2dBody_->ApplyForce(
b2Vec2(force.x, force.y), wPt,
true );
852 for (
auto& sensor :
sensors_) sensor->registerOnServer(c);
860 if (glW) glW->setVisibility(visible);
mrpt::opengl::CSetOfObjects::Ptr glChassis_
double force_scale
In meters/Newton.
void internal_internalGuiUpdate_forces(mrpt::opengl::COpenGLScene &scene)
This file contains rapidxml parser and DOM implementation.
float mass
The mass of the shape, usually in kilograms.
void updateMaxRadiusFromPoly()
float density
The density, usually in kg/m^2.
const Wheel & getWheelInfo(const size_t idx) const
virtual const char * what() const
static constexpr char PL_DQ_Y[]
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node)
mrpt::math::TPose3D getPose() const
virtual double getChassisMass() const
std::vector< mrpt::math::TSegment3D > forceSegmentsForRendering_
static constexpr char PL_Q_ROLL[]
virtual void invoke_motor_controllers_post_step([[maybe_unused]] const TSimulContext &context)
mrpt::math::TPose3D getPoseNoLock() const
No thread-safe version. Used internally only.
virtual void simul_post_timestep(const TSimulContext &context) override
std::map< std::string, std::shared_ptr< CSVLogger > > loggers_
double simul_time
Current time in the simulated world.
#define REGISTER_VEHICLE_DYNAMICS(TEXTUAL_NAME, CLASS_NAME)
virtual void initLoggers()
mrpt::math::TTwist2D getTwist() const
const rapidxml::xml_node< Ch > * first_node(const char *name) const
static constexpr char LOGGER_WHEEL[]
static constexpr char WL_VEL_X[]
mrpt::opengl::CSetOfLines::Ptr glForces_
std::unique_ptr< b2World > & getBox2DWorld()
void getAs3DObject(mrpt::opengl::CSetOfObjects &obj)
std::shared_ptr< CSVLogger > getLoggerPtr(std::string logger_name)
static constexpr char PL_Q_X[]
static constexpr char WL_TORQUE[]
mrpt::opengl::CSetOfLines::Ptr glMotorTorques_
b2Vec2 center
The position of the shape's centroid relative to the shape's origin.
std::deque< Wheel > wheels_info_
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
static constexpr char PL_Q_Z[]
static constexpr char PL_Q_PITCH[]
void ComputeMass(b2MassData *massData, float density) const override
double getW() const
Spinning velocity (rad/s) wrt shaft.
void SetAsBox(float hx, float hy)
std::shared_ptr< mrpt::opengl::CSetOfObjects > glCustomVisual_
mrpt::math::TPoint2D chassis_com_
TClassFactory_vehicleDynamics classFactory_vehicleDynamics
static constexpr char PL_Q_YAW[]
void setShapeManual(const mrpt::math::TPolygon2D &contour, const float zMin, const float zMax)
static constexpr char PL_DQ_Z[]
std::vector< mrpt::math::TSegment3D > torqueSegmentsForRendering_
VehicleBase(World *parent, size_t nWheels)
void GetMassData(b2MassData *massData) const
void setPhi(double val)
Orientation (rad) wrt vehicle local frame.
std::shared_ptr< SensorBase > Ptr
std::mutex forceSegmentsForRenderingMtx_
virtual void create_multibody_system(b2World &world)
std::shared_ptr< VehicleBase > Ptr
std::string parse(const std::string &input, const std::map< std::string, std::string > &variableNamesValues={})
void chassisAndWheelsVisible(bool visible)
std::vector< mrpt::opengl::CSetOfObjects::Ptr > glWheels_
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={})
static constexpr char PL_Q_Y[]
static constexpr char WL_FRIC_X[]
static constexpr char PL_DQ_X[]
mrpt::math::TPolygon2D chassis_poly_
b2Fixture * fixture_chassis_
Created at.
static void register_vehicle_class(const rapidxml::xml_node< char > *xml_node)
virtual void registerOnServer(mvsim::Client &c)
void registerOnServer(mvsim::Client &c) override
virtual void simul_post_timestep(const TSimulContext &context)
double getPhi() const
Orientation (rad) wrt vehicle local frame.
virtual void simul_pre_timestep(const TSimulContext &context)
virtual void internalGuiUpdate(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical, bool childrenOnly) override
void Set(const b2Vec2 *points, int32 count)
virtual std::vector< double > invoke_motor_controllers(const TSimulContext &context)=0
virtual void writeLogStrings()
std::string linked_yaw_object_name
mrpt::math::TTwist2D getVelocityLocal() const
TListSensors sensors_
Sensors aboard.
std::string local_to_abs_path(const std::string &in_path) const
Ptr create(const std::string &class_name, ARG1 a1) const
mrpt::img::TColor chassis_color_
static constexpr char WL_VEL_Y[]
#define b2_maxPolygonVertices
static constexpr char LOGGER_POSE[]
static FrictionBase::Ptr factory(VehicleBase &parent, const rapidxml::xml_node< char > *xml_node)
FrictionBasePtr friction_
This file contains rapidxml printer implementation.
void internal_internalGuiUpdate_sensors(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical)
const rapidxml::xml_node< char > * get(const std::string &xml_node_class) const
void add(const std::string &input_xml_node_class)
static constexpr char WL_WEIGHT[]
void register_all_veh_dynamics()
static XmlClassesRegistry veh_classes_registry("vehicle:class")
xml_node< Ch > * next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
std::vector< mrpt::math::TVector2D > getWheelsVelocityLocal(const mrpt::math::TTwist2D &veh_vel_local) const
static SensorBase::Ptr factory(Simulable &parent, const rapidxml::xml_node< char > *xml_node)
static constexpr char WL_FRIC_Y[]
float restitution
The restitution (elasticity) usually in the range [0,1].
This holds the mass data computed for a shape.
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)
size_t getNumWheels() const
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
b2Body * CreateBody(const b2BodyDef *def)
std::vector< b2Fixture * > fixture_wheels_
float friction
The friction coefficient, usually in the range [0,1].
double get_gravity() const
static constexpr char DL_TIMESTAMP[]
virtual void simul_pre_timestep(const TSimulContext &context) override