VehicleAckermann.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2020 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 
12 #include <mvsim/World.h>
13 
14 #include <cmath>
15 #include <rapidxml.hpp>
16 
17 #include "xml_utils.h"
18 
19 using namespace mvsim;
20 using namespace std;
21 
22 // Ctor:
24  : VehicleBase(parent, 4 /*num wheels*/)
25 {
26  m_chassis_mass = 500.0;
27  m_chassis_z_min = 0.20;
28  m_chassis_z_max = 1.40;
29  m_chassis_color = mrpt::img::TColor(0xe8, 0x30, 0x00);
30 
31  // Default shape:
32  m_chassis_poly.clear();
33  m_chassis_poly.emplace_back(-0.8, -1.0);
34  m_chassis_poly.emplace_back(-0.8, 1.0);
35  m_chassis_poly.emplace_back(1.5, 0.9);
36  m_chassis_poly.emplace_back(1.8, 0.8);
37  m_chassis_poly.emplace_back(1.8, -0.8);
38  m_chassis_poly.emplace_back(1.5, -0.9);
40 
41  m_fixture_chassis = nullptr;
42  for (int i = 0; i < 4; i++) m_fixture_wheels[i] = nullptr;
43 
44  // Default values:
45  // rear-left:
46  m_wheels_info[WHEEL_RL].x = 0;
47  m_wheels_info[WHEEL_RL].y = 0.9;
48  // rear-right:
49  m_wheels_info[WHEEL_RR].x = 0;
50  m_wheels_info[WHEEL_RR].y = -0.9;
51  // Front-left:
52  m_wheels_info[WHEEL_FL].x = 1.3;
53  m_wheels_info[WHEEL_FL].y = 0.9;
54  // Front-right:
55  m_wheels_info[WHEEL_FR].x = 1.3;
56  m_wheels_info[WHEEL_FR].y = -0.9;
57 }
58 
61  const rapidxml::xml_node<char>* xml_node)
62 {
63  const std::map<std::string, std::string> varValues = {{"NAME", m_name}};
64 
65  // <chassis ...> </chassis>
66  if (const rapidxml::xml_node<char>* xml_chassis =
67  xml_node->first_node("chassis");
68  xml_chassis)
69  {
70  // Attribs:
72  attribs["mass"] = TParamEntry("%lf", &this->m_chassis_mass);
73  attribs["zmin"] = TParamEntry("%lf", &this->m_chassis_z_min);
74  attribs["zmax"] = TParamEntry("%lf", &this->m_chassis_z_max);
75  attribs["color"] = TParamEntry("%color", &this->m_chassis_color);
76 
78  *xml_chassis, attribs, {},
79  "[DynamicsAckermann::dynamics_load_params_from_xml]");
80 
81  // Shape node (optional, fallback to default shape if none found)
82  if (const rapidxml::xml_node<char>* xml_shape =
83  xml_chassis->first_node("shape");
84  xml_shape)
86  *xml_shape, m_chassis_poly,
87  "[DynamicsAckermann::dynamics_load_params_from_xml]");
88  }
89 
90  //<rl_wheel pos="0 1" mass="6.0" width="0.30" diameter="0.62" />
91  //<rr_wheel pos="0 -1" mass="6.0" width="0.30" diameter="0.62" />
92  //<fl_wheel mass="6.0" width="0.30" diameter="0.62" />
93  //<fr_wheel mass="6.0" width="0.30" diameter="0.62" />
94  const char* w_names[4] = {
95  "rl_wheel", // 0
96  "rr_wheel", // 1
97  "fl_wheel", // 2
98  "fr_wheel" // 3
99  };
100  // Load common params:
101  for (size_t i = 0; i < 4; i++)
102  {
103  const rapidxml::xml_node<char>* xml_wheel =
104  xml_node->first_node(w_names[i]);
105  if (xml_wheel) m_wheels_info[i].loadFromXML(xml_wheel);
106  }
107 
108  //<f_wheels_x>1.3</f_wheels_x>
109  //<f_wheels_d>2.0</f_wheels_d>
110  // Load front ackermann wheels and other params:
111  {
112  double front_x = 1.3;
113  double front_d = 2.0;
114  TParameterDefinitions ack_ps;
115  // Front wheels:
116  ack_ps["f_wheels_x"] = TParamEntry("%lf", &front_x);
117  ack_ps["f_wheels_d"] = TParamEntry("%lf", &front_d);
118  // other params:
119  ack_ps["max_steer_ang_deg"] = TParamEntry("%lf_deg", &m_max_steer_ang);
120 
122  *xml_node, ack_ps, varValues,
123  "[DynamicsAckermann::dynamics_load_params_from_xml]");
124 
125  // Front-left:
126  m_wheels_info[WHEEL_FL].x = front_x;
127  m_wheels_info[WHEEL_FL].y = 0.5 * front_d;
128  // Front-right:
129  m_wheels_info[WHEEL_FR].x = front_x;
130  m_wheels_info[WHEEL_FR].y = -0.5 * front_d;
131  }
132 
133  // Vehicle controller:
134  // -------------------------------------------------
135  {
136  const rapidxml::xml_node<char>* xml_control =
137  xml_node->first_node("controller");
138  if (xml_control)
139  {
140  rapidxml::xml_attribute<char>* control_class =
141  xml_control->first_attribute("class");
142  if (!control_class || !control_class->value())
143  throw runtime_error(
144  "[DynamicsAckermann] Missing 'class' attribute in "
145  "<controller> XML node");
146 
147  const std::string sCtrlClass = std::string(control_class->value());
148  if (sCtrlClass == ControllerRawForces::class_name())
149  m_controller =
151  else if (sCtrlClass == ControllerTwistFrontSteerPID::class_name())
152  m_controller =
154  else if (sCtrlClass == ControllerFrontSteerPID::class_name())
155  m_controller =
157  else
158  throw runtime_error(mrpt::format(
159  "[DynamicsAckermann] Unknown 'class'='%s' in "
160  "<controller> XML node",
161  sCtrlClass.c_str()));
162 
163  m_controller->load_config(*xml_control);
164  }
165  }
166  // Default controller:
167  if (!m_controller)
169 }
170 
171 // See docs in base class:
173  const TSimulContext& context, std::vector<double>& out_torque_per_wheel)
174 {
175  // Longitudinal forces at each wheel:
176  out_torque_per_wheel.assign(4, 0.0);
177 
178  if (m_controller)
179  {
180  // Invoke controller:
181  TControllerInput ci;
182  ci.context = context;
184  m_controller->control_step(ci, co);
185  // Take its output:
186  out_torque_per_wheel[WHEEL_RL] = co.rl_torque;
187  out_torque_per_wheel[WHEEL_RR] = co.rr_torque;
188  out_torque_per_wheel[WHEEL_FL] = co.fl_torque;
189  out_torque_per_wheel[WHEEL_FR] = co.fr_torque;
190 
191  // Kinematically-driven steering wheels:
192  // Ackermann formulas for inner&outer weels turning angles wrt the
193  // equivalent (central) one:
196  m_wheels_info[WHEEL_FR].yaw);
197  }
198 }
199 
201  const double desired_equiv_steer_ang, double& out_fl_ang,
202  double& out_fr_ang) const
203 {
204  // EQ1: cot(d)+0.5*w/l = cot(do)
205  // EQ2: cot(di)=cot(do)-w/l
206  const double w = m_wheels_info[WHEEL_FL].y - m_wheels_info[WHEEL_FR].y;
207  const double l = m_wheels_info[WHEEL_FL].x - m_wheels_info[WHEEL_RL].x;
208  ASSERT_(l > 0);
209  const double w_l = w / l;
210  const double delta =
211  b2Clamp(std::abs(desired_equiv_steer_ang), 0.0, m_max_steer_ang);
212 
213  const bool delta_neg = (desired_equiv_steer_ang < 0);
214  ASSERT_LT_(delta, 0.5 * M_PI - 0.01);
215  const double cot_do = 1.0 / tan(delta) + 0.5 * w_l;
216  const double cot_di = cot_do - w_l;
217  // delta>0: do->right, di->left wheel
218  // delta<0: do->left , di->right wheel
219  (delta_neg ? out_fr_ang : out_fl_ang) =
220  atan(1.0 / cot_di) * (delta_neg ? -1.0 : 1.0);
221  (delta_neg ? out_fl_ang : out_fr_ang) =
222  atan(1.0 / cot_do) * (delta_neg ? -1.0 : 1.0);
223 }
224 
225 // See docs in base class:
227 {
228  mrpt::math::TTwist2D odo_vel;
229  // Equations:
230 
231  // Velocities in local +X at each wheel i={0,1}:
232  // v_i = vx - w_veh * wheel_{i,y} = w_i * R_i
233  // Re-arranging:
234  const double w0 = m_wheels_info[WHEEL_RL].getW();
235  const double w1 = m_wheels_info[WHEEL_RR].getW();
236  const double R0 = m_wheels_info[WHEEL_RL].diameter * 0.5;
237  const double R1 = m_wheels_info[WHEEL_RR].diameter * 0.5;
238 
239  const double Ay = m_wheels_info[WHEEL_RL].y - m_wheels_info[WHEEL_RR].y;
240  ASSERTMSG_(
241  Ay != 0.0,
242  "The two wheels of a differential vehicle CAN'T by at the same Y "
243  "coordinate!");
244 
245  const double w_veh = (w1 * R1 - w0 * R0) / Ay;
246  const double vx_veh = w0 * R0 + w_veh * m_wheels_info[WHEEL_RL].y;
247 
248  odo_vel.vx = vx_veh;
249  odo_vel.vy = 0.0;
250  odo_vel.omega = w_veh;
251 
252 #if 0 // Debug
253  {
254  mrpt::math::TTwist2D gt_vel = this->getVelocityLocal();
255  printf("\n gt: vx=%7.03f, vy=%7.03f, w= %7.03fdeg\n", gt_vel.vx, gt_vel.vy, mrpt::RAD2DEG(gt_vel.omega));
256  printf("odo: vx=%7.03f, vy=%7.03f, w= %7.03fdeg\n", odo_vel.vx, odo_vel.vy, mrpt::RAD2DEG(odo_vel.omega));
257  }
258 #endif
259  return odo_vel;
260 }
#define printf
mrpt::img::TColor m_chassis_color
Definition: VehicleBase.h:189
This file contains rapidxml parser and DOM implementation.
void updateMaxRadiusFromPoly()
excludes the mass of wheels)
virtual void invoke_motor_controllers(const TSimulContext &context, std::vector< double > &out_force_per_wheel) override
std::map< std::string, TParamEntry > TParameterDefinitions
Ch * value() const
Definition: rapidxml.hpp:692
void parse_xmlnode_children_as_param(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:179
DynamicsAckermann(World *parent)
ControllerBasePtr m_controller
The installed controller.
GLubyte GLubyte GLubyte GLubyte w
virtual mrpt::math::TTwist2D getVelocityLocalOdoEstimate() const override
#define M_PI
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:140
virtual void dynamics_load_params_from_xml(const rapidxml::xml_node< char > *xml_node) override
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
GLdouble l
const GLint * attribs
mrpt::math::TTwist2D getVelocityLocal() const
Definition: Simulable.cpp:84
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
void computeFrontWheelAngles(const double desired_equiv_steer_ang, double &out_fl_ang, double &out_fr_ang) const
std::vector< Wheel > m_wheels_info
Definition: VehicleBase.h:197
std::shared_ptr< ControllerBase > ControllerBasePtr
T b2Clamp(T a, T low, T high)
Definition: b2Math.h:653
#define ASSERT_(f)
double steer_ang
Equivalent ackerman steering angle.
std::vector< b2Fixture * > m_fixture_wheels
Definition: VehicleBase.h:204
double m_chassis_z_min
each change via updateMaxRadiusFromPoly()
Definition: VehicleBase.h:188
void parse_xmlnode_shape(const rapidxml::xml_node< char > &xml_node, mrpt::math::TPolygon2D &out_poly, const char *functionNameContext="")
Definition: xml_utils.cpp:222
std::string m_name
Definition: Simulable.h:118
mrpt::math::TPolygon2D m_chassis_poly
Definition: VehicleBase.h:185
#define ASSERTMSG_(f, __ERROR_MSG)
b2Fixture * m_fixture_chassis
Created at.
Definition: VehicleBase.h:203
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1


mvsim
Author(s):
autogenerated on Fri May 7 2021 03:05:51