VehicleAckermann_ControllerTwistFrontSteerPID.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 
11 
12 #include "xml_utils.h"
13 
14 using namespace mvsim;
15 using namespace std;
16 
18  DynamicsAckermann& veh)
19  : ControllerBase(veh),
20  setpoint_lin_speed(0),
21  setpoint_ang_speed(0),
22  KP(100),
23  KI(0),
24  KD(0),
25  max_torque(100.0)
26 {
27  // Get distance between wheels:
29  veh_.wheels_info_[WHEEL_FL].y - veh_.wheels_info_[WHEEL_FR].y;
30  r2f_L_ = veh_.wheels_info_[WHEEL_FL].x - veh_.wheels_info_[WHEEL_RL].x;
31  ASSERT_(dist_fWheels_ > 0.0);
32  ASSERT_(r2f_L_ > 0.0);
33 }
34 
35 // See base class docs
39 {
40  // For each wheel:
41  // 1) Compute desired velocity set-point (in m/s)
42  // 2) Run the PI/PID for that wheel independently (in newtons)
43 
44  // 1st: desired steering angle:
45  // --------------------------------
46  if (setpoint_ang_speed == 0)
47  {
48  co.steer_ang = 0.0;
49  }
50  else
51  {
52  const double R = setpoint_lin_speed / setpoint_ang_speed;
53  co.steer_ang = atan(r2f_L_ / R);
54  }
55 
56  // Desired velocities for each wheel
57  // In local vehicle frame:
58  const std::vector<mrpt::math::TVector2D> desired_wheel_vels =
59  veh_.getWheelsVelocityLocal(
60  mrpt::math::TTwist2D(setpoint_lin_speed, 0.0, setpoint_ang_speed));
61 
62  ASSERT_(desired_wheel_vels.size() == 4);
63 
64  // Rotate to obtain the actual desired longitudinal velocity for each wheel:
65  // FL:
66  double vel_fl, vel_fr;
67  double desired_fl_steer_ang, desired_fr_steer_ang;
68  veh_.computeFrontWheelAngles(
69  co.steer_ang, desired_fl_steer_ang, desired_fr_steer_ang);
70  {
71  const mrpt::poses::CPose2D wRotInv(0, 0, -desired_fl_steer_ang);
72  mrpt::math::TPoint2D vel_w;
73  wRotInv.composePoint(
74  desired_wheel_vels[DynamicsAckermann::WHEEL_FL], vel_w);
75  vel_fl = vel_w.x;
76  }
77  {
78  const mrpt::poses::CPose2D wRotInv(0, 0, -desired_fr_steer_ang);
79  mrpt::math::TPoint2D vel_w;
80  wRotInv.composePoint(
81  desired_wheel_vels[DynamicsAckermann::WHEEL_FR], vel_w);
82  vel_fr = vel_w.x;
83  }
84 
85  // Compute each wheel actual velocity (from an "odometry" estimation of
86  // velocity, not ground-truth!):
87  double act_vel_fl, act_vel_fr;
88  {
89  // In local vehicle frame:
90  const std::vector<mrpt::math::TVector2D> odo_wheel_vels =
91  veh_.getWheelsVelocityLocal(veh_.getVelocityLocalOdoEstimate());
92  ASSERT_(odo_wheel_vels.size() == 4);
93 
94  const double actual_fl_steer_ang =
95  veh_.getWheelInfo(DynamicsAckermann::WHEEL_FL).yaw;
96  const double actual_fr_steer_ang =
97  veh_.getWheelInfo(DynamicsAckermann::WHEEL_FR).yaw;
98 
99  {
100  const mrpt::poses::CPose2D wRotInv(0, 0, -actual_fl_steer_ang);
101  mrpt::math::TPoint2D vel_w;
102  wRotInv.composePoint(
103  odo_wheel_vels[DynamicsAckermann::WHEEL_FL], vel_w);
104  act_vel_fl = vel_w.x;
105  }
106  {
107  const mrpt::poses::CPose2D wRotInv(0, 0, -actual_fr_steer_ang);
108  mrpt::math::TPoint2D vel_w;
109  wRotInv.composePoint(
110  odo_wheel_vels[DynamicsAckermann::WHEEL_FR], vel_w);
111  act_vel_fr = vel_w.x;
112  }
113  }
114 
115  // Apply controller:
116  for (int i = 0; i < 2; i++)
117  {
118  PID_[i].KP = KP;
119  PID_[i].KI = KI;
120  PID_[i].KD = KD;
121  PID_[i].max_out = max_torque;
122  }
123 
124  co.rl_torque = .0;
125  co.rr_torque = .0;
126  co.fl_torque = -PID_[0].compute(
127  vel_fl - act_vel_fl,
128  ci.context.dt); // "-" because \tau<0 makes robot moves forwards.
129  co.fr_torque = -PID_[1].compute(vel_fr - act_vel_fr, ci.context.dt);
130 }
131 
133  const rapidxml::xml_node<char>& node)
134 {
135  TParameterDefinitions params;
136  params["KP"] = TParamEntry("%lf", &KP);
137  params["KI"] = TParamEntry("%lf", &KI);
138  params["KD"] = TParamEntry("%lf", &KD);
139  params["max_torque"] = TParamEntry("%lf", &max_torque);
140 
141  // Initial speed.
142  params["V"] = TParamEntry("%lf", &this->setpoint_lin_speed);
143  params["W"] = TParamEntry("%lf_deg", &this->setpoint_ang_speed);
144 
145  parse_xmlnode_children_as_param(node, params);
146 }
147 
149  const TeleopInput& in, TeleopOutput& out)
150 {
152 
153  switch (in.keycode)
154  {
155  case 'W':
156  case 'w':
157  setpoint_lin_speed += 0.1;
158  break;
159 
160  case 'S':
161  case 's':
162  setpoint_lin_speed -= 0.1;
163  break;
164 
165  case 'A':
166  case 'a':
167  setpoint_ang_speed += 1.0 * M_PI / 180.0;
168  break;
169 
170  case 'D':
171  case 'd':
172  setpoint_ang_speed -= 1.0 * M_PI / 180.0;
173  break;
174 
175  case ' ':
176  setpoint_lin_speed = .0;
177  setpoint_ang_speed = .0;
178  break;
179  };
180  out.append_gui_lines += "[Controller=" + string(class_name()) +
181  "] Teleop keys: w/s=incr/decr lin speed. "
182  "a/d=left/right steering. spacebar=stop.\n";
183  out.append_gui_lines += mrpt::format(
184  "setpoint: v=%.03f w=%.03f deg/s\n", setpoint_lin_speed,
185  setpoint_ang_speed * 180.0 / M_PI);
186 }
virtual void control_step(const DynamicsAckermann::TControllerInput &ci, DynamicsAckermann::TControllerOutput &co) override
std::map< std::string, TParamEntry > TParameterDefinitions
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="", mrpt::system::COutputLogger *logger=nullptr)
Definition: xml_utils.cpp:224
double max_torque
Maximum abs. value torque (for clamp) [Nm].
double setpoint_ang_speed
desired velocities (m/s) and (rad/s)
#define M_PI
double dt
timestep
Definition: basic_types.h:60
virtual void teleop_interface(const TeleopInput &in, TeleopOutput &out) override
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
virtual void teleop_interface(const TeleopInput &in, TeleopOutput &out) override
virtual void load_config(const rapidxml::xml_node< char > &node) override
double max_out
For clamping (0=no clamp)
double compute(double err, double dt)
double steer_ang
Equivalent Ackermann steering angle.


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