VehicleAckermann_ControllerTwistFrontSteerPID.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 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:
28  dist_fWheels_ = veh_.wheels_info_[WHEEL_FL].y - veh_.wheels_info_[WHEEL_FR].y;
29  r2f_L_ = veh_.wheels_info_[WHEEL_FL].x - veh_.wheels_info_[WHEEL_RL].x;
30  ASSERT_(dist_fWheels_ > 0.0);
31  ASSERT_(r2f_L_ > 0.0);
32 }
33 
34 // See base class docs
37 {
38  // For each wheel:
39  // 1) Compute desired velocity set-point (in m/s)
40  // 2) Run the PI/PID for that wheel independently (in newtons)
41 
42  // 1st: desired steering angle:
43  // --------------------------------
44  if (setpoint_ang_speed == 0)
45  {
46  co.steer_ang = 0.0;
47  }
48  else
49  {
50  const double R = setpoint_lin_speed / setpoint_ang_speed;
51  co.steer_ang = atan(r2f_L_ / R);
52  }
53 
54  // Desired velocities for each wheel
55  // In local vehicle frame:
56  const std::vector<mrpt::math::TVector2D> desired_wheel_vels = veh_.getWheelsVelocityLocal(
57  mrpt::math::TTwist2D(setpoint_lin_speed, 0.0, setpoint_ang_speed));
58 
59  ASSERT_(desired_wheel_vels.size() == 4);
60 
61  // Rotate to obtain the actual desired longitudinal velocity for each wheel:
62  // FL:
63  double vel_fl, vel_fr;
64  double desired_fl_steer_ang, desired_fr_steer_ang;
65  veh_.computeFrontWheelAngles(co.steer_ang, desired_fl_steer_ang, desired_fr_steer_ang);
66  {
67  const mrpt::poses::CPose2D wRotInv(0, 0, -desired_fl_steer_ang);
68  mrpt::math::TPoint2D vel_w;
69  wRotInv.composePoint(desired_wheel_vels[DynamicsAckermann::WHEEL_FL], vel_w);
70  vel_fl = vel_w.x;
71  }
72  {
73  const mrpt::poses::CPose2D wRotInv(0, 0, -desired_fr_steer_ang);
74  mrpt::math::TPoint2D vel_w;
75  wRotInv.composePoint(desired_wheel_vels[DynamicsAckermann::WHEEL_FR], vel_w);
76  vel_fr = vel_w.x;
77  }
78 
79  // Compute each wheel actual velocity (from an "odometry" estimation of
80  // velocity, not ground-truth!):
81  double act_vel_fl, act_vel_fr;
82  {
83  // In local vehicle frame:
84  const std::vector<mrpt::math::TVector2D> odo_wheel_vels =
85  veh_.getWheelsVelocityLocal(veh_.getVelocityLocalOdoEstimate());
86  ASSERT_(odo_wheel_vels.size() == 4);
87 
88  const double actual_fl_steer_ang = veh_.getWheelInfo(DynamicsAckermann::WHEEL_FL).yaw;
89  const double actual_fr_steer_ang = veh_.getWheelInfo(DynamicsAckermann::WHEEL_FR).yaw;
90 
91  {
92  const mrpt::poses::CPose2D wRotInv(0, 0, -actual_fl_steer_ang);
93  mrpt::math::TPoint2D vel_w;
94  wRotInv.composePoint(odo_wheel_vels[DynamicsAckermann::WHEEL_FL], vel_w);
95  act_vel_fl = vel_w.x;
96  }
97  {
98  const mrpt::poses::CPose2D wRotInv(0, 0, -actual_fr_steer_ang);
99  mrpt::math::TPoint2D vel_w;
100  wRotInv.composePoint(odo_wheel_vels[DynamicsAckermann::WHEEL_FR], vel_w);
101  act_vel_fr = vel_w.x;
102  }
103  }
104 
105  // Apply controller:
106  for (int i = 0; i < 2; i++)
107  {
108  PID_[i].KP = KP;
109  PID_[i].KI = KI;
110  PID_[i].KD = KD;
111  PID_[i].max_out = max_torque;
112  }
113 
114  co.rl_torque = .0;
115  co.rr_torque = .0;
116  co.fl_torque = -PID_[0].compute(
117  vel_fl - act_vel_fl,
118  ci.context.dt); // "-" because \tau<0 makes robot moves forwards.
119  co.fr_torque = -PID_[1].compute(vel_fr - act_vel_fr, ci.context.dt);
120 }
121 
123  const rapidxml::xml_node<char>& node)
124 {
125  TParameterDefinitions params;
126  params["KP"] = TParamEntry("%lf", &KP);
127  params["KI"] = TParamEntry("%lf", &KI);
128  params["KD"] = TParamEntry("%lf", &KD);
129  params["max_torque"] = TParamEntry("%lf", &max_torque);
130 
131  // Initial speed.
132  params["V"] = TParamEntry("%lf", &this->setpoint_lin_speed);
133  params["W"] = TParamEntry("%lf_deg", &this->setpoint_ang_speed);
134 
135  parse_xmlnode_children_as_param(node, params);
136 }
137 
139  const TeleopInput& in, TeleopOutput& out)
140 {
142 
143  switch (in.keycode)
144  {
145  case 'W':
146  case 'w':
147  setpoint_lin_speed += 0.1;
148  break;
149 
150  case 'S':
151  case 's':
152  setpoint_lin_speed -= 0.1;
153  break;
154 
155  case 'A':
156  case 'a':
157  setpoint_ang_speed += 1.0 * M_PI / 180.0;
158  break;
159 
160  case 'D':
161  case 'd':
162  setpoint_ang_speed -= 1.0 * M_PI / 180.0;
163  break;
164 
165  case ' ':
166  setpoint_lin_speed = .0;
167  setpoint_ang_speed = .0;
168  break;
169  };
170 
171  out.append_gui_lines += "[Controller=" + std::string(class_name()) + "]";
172 
173  if (in.js && in.js->axes.size() >= 2)
174  {
175  const auto& js = in.js.value();
176  const float js_x = js.axes[0];
177  const float js_y = js.axes[1];
178 
179  setpoint_lin_speed = -js_y * joyMaxLinSpeed;
180  setpoint_ang_speed = -js_x * joyMaxAngSpeed;
181 
182  if (js.buttons.size() >= 7)
183  {
184  if (js.buttons[5]) joyMaxLinSpeed *= 1.01;
185  if (js.buttons[7]) joyMaxLinSpeed /= 1.01;
186 
187  if (js.buttons[4]) joyMaxAngSpeed *= 1.01;
188  if (js.buttons[6]) joyMaxAngSpeed /= 1.01;
189 
190  if (js.buttons[3]) // brake
191  {
192  setpoint_lin_speed = 0;
193  setpoint_ang_speed = 0;
194  }
195  }
196 
197  out.append_gui_lines += mrpt::format(
198  "Teleop joystick:\n"
199  "maxLinSpeed=%.03f m/s\n"
200  "maxAngSpeed=%.03f deg/s\n",
201  joyMaxLinSpeed, mrpt::RAD2DEG(joyMaxAngSpeed));
202  }
203  else
204  {
205  out.append_gui_lines +=
206  "Teleop keys:\n"
207  "w/s=forward/backward.\n"
208  "a/d=left/right.\n"
209  "spacebar=stop.\n";
210  }
211 
212  out.append_gui_lines += mrpt::format(
213  "setpoint: lin=%.03f ang=%.03f deg/s\n", setpoint_lin_speed,
214  180.0 / M_PI * setpoint_ang_speed);
215 }
move-object-example.R
int R
Definition: move-object-example.py:41
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::r2f_L_
double r2f_L_
Definition: VehicleAckermann.h:103
mvsim
Definition: Client.h:21
mvsim::ControllerBaseTempl::teleop_interface
virtual void teleop_interface(const TeleopInput &in, TeleopOutput &out) override
Definition: ControllerBase.h:67
mvsim::TParamEntry
Definition: TParameterDefinitions.h:38
mvsim::parse_xmlnode_children_as_param
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:215
mvsim::ControllerBaseInterface::TeleopOutput::append_gui_lines
std::string append_gui_lines
Definition: ControllerBase.h:35
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::dist_fWheels_
double dist_fWheels_
Definition: VehicleAckermann.h:103
xml_utils.h
mvsim::TSimulContext::dt
double dt
timestep
Definition: basic_types.h:63
mvsim::ControllerBaseTempl
Definition: ControllerBase.h:59
mvsim::DynamicsAckermann::TControllerInput
Definition: VehicleAckermann.h:43
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::control_step
virtual void control_step(const DynamicsAckermann::TControllerInput &ci, DynamicsAckermann::TControllerOutput &co) override
Definition: VehicleAckermann_ControllerTwistFrontSteerPID.cpp:35
mvsim::TParameterDefinitions
std::map< std::string, TParamEntry > TParameterDefinitions
Definition: TParameterDefinitions.h:64
mvsim::ControllerBaseInterface::TeleopOutput
Definition: ControllerBase.h:33
mvsim::DynamicsAckermann::TControllerOutput::fr_torque
double fr_torque
Definition: VehicleAckermann.h:49
mvsim::DynamicsAckermann::TControllerOutput::steer_ang
double steer_ang
Equivalent Ackermann steering angle.
Definition: VehicleAckermann.h:50
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::ControllerTwistFrontSteerPID
ControllerTwistFrontSteerPID(DynamicsAckermann &veh)
Definition: VehicleAckermann_ControllerTwistFrontSteerPID.cpp:17
rapidxml::xml_node< char >
mvsim::DynamicsAckermann::WHEEL_RL
@ WHEEL_RL
Definition: VehicleAckermann.h:29
mvsim::DynamicsAckermann::TControllerInput::context
TSimulContext context
Definition: VehicleAckermann.h:45
mvsim::DynamicsAckermann::WHEEL_FL
@ WHEEL_FL
Definition: VehicleAckermann.h:31
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::load_config
virtual void load_config(const rapidxml::xml_node< char > &node) override
Definition: VehicleAckermann_ControllerTwistFrontSteerPID.cpp:122
std
VehicleAckermann.h
mvsim::DynamicsAckermann::ControllerTwistFrontSteerPID::teleop_interface
virtual void teleop_interface(const TeleopInput &in, TeleopOutput &out) override
Definition: VehicleAckermann_ControllerTwistFrontSteerPID.cpp:138
mvsim::DynamicsAckermann
Definition: VehicleAckermann.h:22
mvsim::ControllerBaseInterface::TeleopInput
Definition: ControllerBase.h:25
mvsim::ControllerBaseTempl::veh_
VEH_DYNAMICS & veh_
Definition: ControllerBase.h:124
mvsim::ControllerBaseInterface::TeleopInput::js
std::optional< TJoyStickEvent > js
Definition: ControllerBase.h:28
mvsim::ControllerBaseInterface::TeleopInput::keycode
int keycode
Definition: ControllerBase.h:27
mvsim::DynamicsAckermann::WHEEL_FR
@ WHEEL_FR
Definition: VehicleAckermann.h:32
mvsim::DynamicsAckermann::TControllerOutput::fl_torque
double fl_torque
Definition: VehicleAckermann.h:49
mvsim::DynamicsAckermann::TControllerOutput
Definition: VehicleAckermann.h:47
mvsim::DynamicsAckermann::TControllerOutput::rr_torque
double rr_torque
Definition: VehicleAckermann.h:49
mvsim::DynamicsAckermann::TControllerOutput::rl_torque
double rl_torque
Definition: VehicleAckermann.h:49


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08