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>
32 using namespace mvsim;
43 static bool done =
false;
100 if (!xml_node)
throw runtime_error(
"[VehicleBase::register_vehicle_class] XML node is nullptr");
101 if (0 != strcmp(xml_node->name(),
"vehicle:class"))
102 throw runtime_error(mrpt::format(
103 "[VehicleBase::register_vehicle_class] XML element is '%s' "
104 "('vehicle:class' expected)",
109 const std::set<std::string> varsRetain = {
110 "NAME" ,
"PARENT_NAME" };
125 if (!
root)
throw runtime_error(
"[VehicleBase::factory] XML node is nullptr");
126 if (0 != strcmp(
root->name(),
"vehicle"))
127 throw runtime_error(mrpt::format(
128 "[VehicleBase::factory] XML root element is '%s' ('vehicle' "
138 std::vector<XML_Doc_Data::Ptr> scopedLifeDocs;
141 for (
auto n =
root->first_node(); n; n = n->next_sibling())
143 if (strcmp(n->name(),
"include") != 0)
continue;
145 auto fileAttrb = n->first_attribute(
"file");
146 ASSERTMSG_(fileAttrb,
"XML tag '<include />' must have a 'file=\"xxx\"' attribute)");
148 const std::string relFile =
152 mrpt::system::LVL_DEBUG,
153 mrpt::format(
"XML parser: including file: '%s'", absFile.c_str()));
155 std::map<std::string, std::string> vars;
159 for (
auto attr = n->first_attribute(); attr; attr = attr->next_attribute())
161 if (strcmp(attr->name(),
"file") == 0)
continue;
162 vars[attr->name()] = attr->value();
167 std::set<std::string> varsRetain = {
"NAME" ,
"PARENT_NAME" };
172 scopedLifeDocs.emplace_back(xml);
175 nodes.
add(nRoot->parent());
184 const string sClassName = veh_class->value();
187 throw runtime_error(mrpt::format(
188 "[VehicleBase::factory] Vehicle class '%s' undefined", sClassName.c_str()));
190 nodes.
add(class_root);
196 const xml_node<>* dyn_node = nodes.
first_node(
"dynamics");
197 if (!dyn_node)
throw runtime_error(
"[VehicleBase::factory] Missing XML node <dynamics>");
200 if (!dyn_class || !dyn_class->value())
202 "[VehicleBase::factory] Missing mandatory attribute 'class' in "
207 throw runtime_error(mrpt::format(
208 "[VehicleBase::factory] Unknown vehicle dynamics class '%s'", dyn_class->value()));
215 if (attrib_name && attrib_name->value())
223 veh->name_ = mrpt::format(
"veh%i", ++cnt);
229 veh->parseVisual(nodes);
233 veh->dynamics_load_params_from_xml(dyn_node);
240 const auto& bbVis = veh->collisionShape();
241 if (!bbVis.has_value())
244 "Error: Tag <shape_from_visual/> found but no "
245 "<visual> entry seems to have been found while parsing "
248 const auto& bb = bbVis.value();
249 if (bb.volume() == 0)
252 "Error: Tag <shape_from_visual/> found but bounding box of "
253 "visual object seems incorrect, while parsing <vehicle>");
257 veh->chassis_poly_ = bb.getContour();
258 veh->chassis_z_min_ = bb.zMin();
259 veh->chassis_z_max_ = bb.zMax();
265 cs.
setShapeManual(veh->chassis_poly_, veh->chassis_z_min_, veh->chassis_z_max_);
267 veh->setCollisionShape(cs);
271 veh->updateMaxRadiusFromPoly();
275 veh->parseSimulable(nodes);
280 const xml_node<>* log_path_node = nodes.
first_node(
"log_path");
284 veh->log_path_ = log_path_node->value();
298 const auto dq = veh->getTwist();
300 veh->b2dBody_->SetTransform(
b2Vec2(q.x, q.y), q.yaw);
302 veh->b2dBody_->SetLinearVelocity(
b2Vec2(dq.vx, dq.vy));
303 veh->b2dBody_->SetAngularVelocity(dq.omega);
310 const xml_node<>* frict_node = nodes.
first_node(
"friction");
314 veh->friction_ = std::make_shared<DefaultFriction>(*veh,
nullptr );
320 ASSERT_(veh->friction_);
326 for (
const auto& xmlNode : nodes)
328 if (!strcmp(xmlNode->name(),
"sensor"))
344 char* input_str =
const_cast<char*
>(xml_text.c_str());
348 xml.
parse<0>(input_str);
352 unsigned int line =
static_cast<long>(std::count(input_str, e.
where<
char>(),
'\n') + 1);
353 throw std::runtime_error(mrpt::format(
354 "[VehicleBase::factory] XML parse error (Line %u): %s",
static_cast<unsigned>(line),
363 for (
auto&
s :
sensors_)
s->simul_pre_timestep(context);
380 ASSERT_EQUAL_(wheelTorque.size(), nW);
384 MRPT_TODO(
"Use chassis cog point");
386 const double weightPerWheel = massPerWheel * gravity;
388 const std::vector<mrpt::math::TVector2D> wheelLocalVels =
391 ASSERT_EQUAL_(wheelLocalVels.size(), nW);
394 std::vector<mrpt::math::TSegment3D> forceVectors, torqueVectors;
396 for (
size_t i = 0; i < nW; i++)
403 fi.
weight = weightPerWheel;
409 const mrpt::math::TPoint2D F_r =
friction_->evaluate_friction(fi);
413 const b2Vec2 wForce = b2dBody_->GetWorldVector(
b2Vec2(F_r.x, F_r.y));
420 b2dBody_->ApplyForce(wForce, wPt,
true );
443 const mrpt::math::TPoint3D pt2 =
444 pt1 + mrpt::math::TPoint3D(wForce.
x, wForce.
y, 0) * forceScale;
446 forceVectors.emplace_back(pt1, pt2);
448 const mrpt::math::TPoint3D pt2_t =
449 pt1 + mrpt::math::TPoint3D(0, 0, wheelTorque[i]) * forceScale;
451 torqueVectors.emplace_back(pt1, pt2_t);
472 for (
auto&
s :
sensors_)
s->simul_post_timestep(context);
477 for (
size_t i = 0; i < nW; i++)
483 w.setPhi(w.getPhi() + w.getW() * context.
dt);
488 const double cur_abs_phi = std::abs(w.getPhi());
489 if (cur_abs_phi > 1e4)
490 w.setPhi(::fmod(cur_abs_phi, 2 * M_PI) * (w.getPhi() < 0.0 ? -1.0 : 1.0));
501 logger.updateColumn(
PL_Q_X, q.x);
502 logger.updateColumn(
PL_Q_Y, q.y);
503 logger.updateColumn(
PL_Q_Z, q.z);
504 logger.updateColumn(
PL_Q_YAW, q.yaw);
507 logger.updateColumn(
PL_DQ_X, dq.vx);
508 logger.updateColumn(
PL_DQ_Y, dq.vy);
509 logger.updateColumn(
PL_DQ_Z, dq.omega);
519 const mrpt::math::TTwist2D& veh_vel_local)
const
526 const double w = veh_vel_local.omega;
529 std::vector<mrpt::math::TVector2D> vels(nW);
531 for (
size_t i = 0; i < nW; i++)
535 vels[i].x = veh_vel_local.vx - w * wheel.
y;
536 vels[i].y = veh_vel_local.vy + w * wheel.
x;
542 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
543 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical)
545 for (
auto&
s :
sensors_)
s->guiUpdate(viz, physical);
549 [[maybe_unused]] mrpt::opengl::COpenGLScene& scene)
574 return l && l->isOpen();
584 const float n = pt.norm();
605 std::vector<b2Vec2> pts(nPts);
609 chassisPoly.
Set(&pts[0], nPts);
616 fixtureDef.
shape = &chassisPoly;
651 fixtureDef.
shape = &wheelShape;
667 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
668 const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical,
bool childrenOnly)
684 for (
size_t i = 0; i < nWs; i++)
686 glWheelsViz_[i] = mrpt::opengl::CSetOfObjects::Create();
698 auto gl_poly = mrpt::opengl::CPolyhedron::CreateCustomPrism(
724 for (
size_t i = 0; i < nWs; i++)
728 mrpt::math::TPose3D(w.
x, w.
y, 0.5 * w.
diameter, w.
yaw, w.getPhi(), 0.0));
730 mrpt::math::TPose3D(w.
x, w.
y, 0.5 * w.
diameter, w.
yaw, w.getPhi(), 0.0));
738 "Wheel #%zu has linked_yaw_object_name='%s' but parent "
739 "vehicle '%s' does not have any custom visual group "
743 auto p = glLinked->getPose();
745 glLinked->setPose(p);
754 glForces_ = mrpt::opengl::CSetOfLines::Create();
756 glForces_->setColor_u8(0xff, 0xff, 0xff);
757 glForces_->setPose(
parent()->applyWorldRenderOffset(mrpt::poses::CPose3D::Identity()));
768 parent()->applyWorldRenderOffset(mrpt::poses::CPose3D::Identity()));
795 std::map<std::string, std::shared_ptr<CSVLogger>>::iterator it;
798 it->second->writeRow();
803 const mrpt::math::TVector2D& force,
const mrpt::math::TPoint2D& applyPoint)
807 const b2Vec2 wPt = b2dBody_->GetWorldPoint(
b2Vec2(applyPoint.x, applyPoint.y));
808 b2dBody_->ApplyForce(
b2Vec2(force.x, force.y), wPt,
true );
815 for (
auto& sensor :
sensors_) sensor->registerOnServer(c);
823 if (glW) glW->setVisibility(visible);