VehicleDifferential.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2023 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/opengl/COpenGLScene.h>
12 #include <mvsim/World.h>
13 
14 #include <rapidxml.hpp>
15 
16 #include "xml_utils.h"
17 
18 using namespace mvsim;
19 using namespace std;
20 
21 // Ctor:
23  World* parent, const std::vector<ConfigPerWheel>& cfgPerWheel)
24  : VehicleBase(parent, cfgPerWheel.size() /*num wheels*/),
25  configPerWheel_(cfgPerWheel)
26 {
27  using namespace mrpt::math;
28 
29  chassis_mass_ = 15.0;
30  chassis_z_min_ = 0.05;
31  chassis_z_max_ = 0.6;
32  chassis_color_ = mrpt::img::TColor(0xff, 0x00, 0x00);
33 
34  // Default shape:
35  chassis_poly_.clear();
36  chassis_poly_.emplace_back(-0.4, -0.5);
37  chassis_poly_.emplace_back(-0.4, 0.5);
38  chassis_poly_.emplace_back(0.4, 0.5);
39  chassis_poly_.emplace_back(0.6, 0.3);
40  chassis_poly_.emplace_back(0.6, -0.3);
41  chassis_poly_.emplace_back(0.4, -0.5);
43 
44  fixture_chassis_ = nullptr;
45  for (auto& fw : fixture_wheels_) fw = nullptr;
46 }
47 
50  const rapidxml::xml_node<char>* xml_node)
51 {
52  const std::map<std::string, std::string> varValues = {{"NAME", name_}};
53 
54  // <chassis ...> </chassis>
55  const rapidxml::xml_node<char>* xml_chassis =
56  xml_node->first_node("chassis");
57  if (xml_chassis)
58  {
59  // Attribs:
60  TParameterDefinitions attribs;
61  attribs["mass"] = TParamEntry("%lf", &this->chassis_mass_);
62  attribs["zmin"] = TParamEntry("%lf", &this->chassis_z_min_);
63  attribs["zmax"] = TParamEntry("%lf", &this->chassis_z_max_);
64  attribs["color"] = TParamEntry("%color", &this->chassis_color_);
65 
67  *xml_chassis, attribs, varValues,
68  "[DynamicsDifferential::dynamics_load_params_from_xml]");
69 
70  // Shape node (optional, fallback to default shape if none found)
71  const rapidxml::xml_node<char>* xml_shape =
72  xml_chassis->first_node("shape");
73  if (xml_shape)
75  *xml_shape, chassis_poly_,
76  "[DynamicsDifferential::dynamics_load_params_from_xml]");
77  }
78 
79  // <l_wheel ...>, <r_wheel ...>
80 
81  // reset default values
82  ASSERT_EQUAL_(getNumWheels(), configPerWheel_.size());
83 
84  // Load common params:
85  for (size_t i = 0; i < getNumWheels(); i++)
86  {
87  const auto& cpw = configPerWheel_.at(i);
88 
89  const rapidxml::xml_node<char>* xml_wheel =
90  xml_node->first_node(cpw.name.c_str());
91  if (xml_wheel)
92  wheels_info_[i].loadFromXML(xml_wheel);
93  else
94  {
95  wheels_info_[i].x = cpw.pos.x;
96  wheels_info_[i].y = cpw.pos.y;
97  }
98  }
99 
100  // Vehicle controller:
101  // -------------------------------------------------
102  {
103  const rapidxml::xml_node<char>* xml_control =
104  xml_node->first_node("controller");
105  if (xml_control)
106  {
107  rapidxml::xml_attribute<char>* control_class =
108  xml_control->first_attribute("class");
109  if (!control_class || !control_class->value())
110  throw runtime_error(
111  "[DynamicsDifferential] Missing 'class' attribute in "
112  "<controller> XML node");
113 
114  const std::string sCtrlClass = std::string(control_class->value());
115  if (sCtrlClass == ControllerRawForces::class_name())
116  controller_ = std::make_shared<ControllerRawForces>(*this);
117  else if (sCtrlClass == ControllerTwistPID::class_name())
118  controller_ = std::make_shared<ControllerTwistPID>(*this);
119  else if (sCtrlClass == ControllerTwistIdeal::class_name())
120  controller_ = std::make_shared<ControllerTwistIdeal>(*this);
121  else
122  THROW_EXCEPTION_FMT(
123  "[DynamicsDifferential] Unknown 'class'='%s' in "
124  "<controller> XML node",
125  sCtrlClass.c_str());
126 
127  controller_->load_config(*xml_control);
128  }
129  }
130 
131  // Default controller:
132  if (!controller_)
133  controller_ = std::make_shared<ControllerRawForces>(*this);
134 }
135 
136 // See docs in base class:
138  const TSimulContext& context)
139 {
140  // Longitudinal forces at each wheel:
141  std::vector<double> otpw;
142  otpw.assign(getNumWheels(), 0.0);
143 
144  if (controller_)
145  {
146  // Invoke controller:
147  TControllerInput ci;
148  ci.context = context;
150  controller_->control_step(ci, co);
151 
152  // Take its output:
153  switch (getNumWheels())
154  {
155  case 2:
156  otpw[WHEEL_L] = co.wheel_torque_l;
157  otpw[WHEEL_R] = co.wheel_torque_r;
158  break;
159  case 3:
160  otpw[WHEEL_L] = co.wheel_torque_l;
161  otpw[WHEEL_R] = co.wheel_torque_r;
162  otpw[WHEEL_CASTER_FRONT] = 0;
163  break;
164  case 4:
165  otpw[WHEEL_LR] = co.wheel_torque_l;
166  otpw[WHEEL_RR] = co.wheel_torque_r;
167  otpw[WHEEL_LF] = co.wheel_torque_l;
168  otpw[WHEEL_RF] = co.wheel_torque_r;
169  break;
170  default:
171  THROW_EXCEPTION("Unexpected number of wheels!");
172  };
173  }
174  return otpw;
175 }
176 
178  const TSimulContext& context)
179 {
180  if (controller_) controller_->on_post_step(context);
181 }
182 
183 // See docs in base class:
185 {
186  mrpt::math::TTwist2D odo_vel;
187  // Equations:
188 
189  // Velocities in local +X at each wheel i={0,1}:
190  // v_i = vx - w_veh * wheel_{i,y} = w_i * R_i
191  // Re-arranging:
192  const double w0 = wheels_info_[WHEEL_L].getW();
193  const double w1 = wheels_info_[WHEEL_R].getW();
194  const double R0 = wheels_info_[WHEEL_L].diameter * 0.5;
195  const double R1 = wheels_info_[WHEEL_R].diameter * 0.5;
196 
197  const double Ay = wheels_info_[WHEEL_L].y - wheels_info_[WHEEL_R].y;
198  ASSERTMSG_(
199  Ay != 0.0,
200  "The two wheels of a differential vehicle cannot be at the same Y "
201  "coordinate!");
202 
203  const double w_veh = (w1 * R1 - w0 * R0) / Ay;
204  const double vx_veh = w0 * R0 + w_veh * wheels_info_[WHEEL_L].y;
205 
206  odo_vel.vx = vx_veh;
207  odo_vel.vy = 0.0;
208  odo_vel.omega = w_veh;
209 
210  return odo_vel;
211 }
This file contains rapidxml parser and DOM implementation.
void updateMaxRadiusFromPoly()
ControllerBase::Ptr controller_
The installed controller.
std::map< std::string, TParamEntry > TParameterDefinitions
virtual void dynamics_load_params_from_xml(const rapidxml::xml_node< char > *xml_node) override
virtual std::vector< double > invoke_motor_controllers(const TSimulContext &context) override
void parse_xmlnode_attribs(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="")
Definition: xml_utils.cpp:184
std::deque< Wheel > wheels_info_
Definition: VehicleBase.h:209
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
virtual void invoke_motor_controllers_post_step(const TSimulContext &context) override
std::string name_
Definition: Simulable.h:120
mrpt::math::TPolygon2D chassis_poly_
Definition: VehicleBase.h:189
b2Fixture * fixture_chassis_
Created at.
Definition: VehicleBase.h:212
Ch * value() const
Definition: rapidxml.hpp:692
mrpt::img::TColor chassis_color_
Definition: VehicleBase.h:197
virtual mrpt::math::TTwist2D getVelocityLocalOdoEstimate() const override
void parse_xmlnode_shape(const rapidxml::xml_node< char > &xml_node, mrpt::math::TPolygon2D &out_poly, const char *functionNameContext="")
Definition: xml_utils.cpp:271
const std::vector< ConfigPerWheel > configPerWheel_
Defined at ctor time:
size_t getNumWheels() const
Definition: VehicleBase.h:80
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
std::vector< b2Fixture * > fixture_wheels_
Definition: VehicleBase.h:216


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:21