CARLA
Loading...
Searching...
No Matches
PIDController.cpp
Go to the documentation of this file.
1// Copyright (c) 2018-2020 CVC.
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7
11#include "carla/geom/Location.h"
13#include "carla/geom/Vector3D.h"
14
15#include <algorithm>
16#include <cmath>
17#include <iostream>
18
19namespace carla {
20namespace agents {
21namespace navigation {
22
23namespace {
24
25constexpr std::size_t kErrorBufferMaxLen = 10;
26
27// Pop oldest entries until the deque is at most max_len long. Mirrors the
28// behaviour of a Python `deque(maxlen=N)`.
29template <typename T>
30void TrimDeque(std::deque<T> &q, std::size_t max_len) {
31 while (q.size() > max_len) {
32 q.pop_front();
33 }
34}
35
36} // namespace
37
38// =========================================================================
39// PIDLongitudinalController
40// =========================================================================
41
44 float K_P, float K_I, float K_D, float dt)
45 : _vehicle(std::move(vehicle)),
46 _k_p(K_P),
47 _k_i(K_I),
48 _k_d(K_D),
49 _dt(dt) {}
50
51float PIDLongitudinalController::RunStep(float target_speed_kmh, bool debug) {
52 const float current_speed_kmh = GetSpeed(_vehicle);
53 if (debug) {
54 std::cout << "Current speed = " << current_speed_kmh << '\n';
55 }
56 return PidControl(target_speed_kmh, current_speed_kmh);
57}
58
60 float target_speed_kmh, float current_speed_kmh) {
61 const float error = target_speed_kmh - current_speed_kmh;
62 _error_buffer.push_back(error);
63 TrimDeque(_error_buffer, kErrorBufferMaxLen);
64
65 float de = 0.0f;
66 float ie = 0.0f;
67 if (_error_buffer.size() >= 2) {
68 de = (_error_buffer.back() - _error_buffer[_error_buffer.size() - 2]) / _dt;
69 float sum = 0.0f;
70 for (float e : _error_buffer) sum += e;
71 ie = sum * _dt;
72 }
73
74 const float u = (_k_p * error) + (_k_d * de) + (_k_i * ie);
75 return std::clamp(u, -1.0f, 1.0f);
76}
77
79 float K_P, float K_I, float K_D, float dt) {
80 _k_p = K_P;
81 _k_i = K_I;
82 _k_d = K_D;
83 _dt = dt;
84}
85
86// =========================================================================
87// PIDLateralController
88// =========================================================================
89
92 float offset,
93 float K_P, float K_I, float K_D, float dt)
94 : _vehicle(std::move(vehicle)),
95 _k_p(K_P),
96 _k_i(K_I),
97 _k_d(K_D),
98 _dt(dt),
99 _offset(offset) {}
100
102 const auto vehicle_transform = _vehicle->GetTransform();
103
104 // Vehicle forward vector projected onto the XY plane.
105 const auto fwd = vehicle_transform.GetForwardVector();
106 const float vx = fwd.x;
107 const float vy = fwd.y;
108
109 // Optionally laterally offset the waypoint along its right vector.
110 geom::Location w_loc;
111 if (_offset != 0.0f) {
112 const auto w_tran = waypoint->GetTransform();
113 const auto r_vec = w_tran.GetRightVector();
114 w_loc = geom::Location(
115 w_tran.location.x + _offset * r_vec.x,
116 w_tran.location.y + _offset * r_vec.y,
117 w_tran.location.z);
118 } else {
119 w_loc = waypoint->GetTransform().location;
120 }
121
122 const float wx = w_loc.x - vehicle_transform.location.x;
123 const float wy = w_loc.y - vehicle_transform.location.y;
124
125 // Python computes `np.linalg.norm(w) * np.linalg.norm(v)`. v_z is 0 by
126 // construction so the 2-D length is enough for both.
127 const float w_len = std::sqrt(wx * wx + wy * wy);
128 const float v_len = std::sqrt(vx * vx + vy * vy);
129 const float wv_linalg = w_len * v_len;
130
131 float dot;
132 if (wv_linalg == 0.0f) {
133 // Matches the Python `_dot = 1` early-out (degenerate inputs).
134 dot = 1.0f;
135 } else {
136 const float cos_theta = std::clamp((wx * vx + wy * vy) / wv_linalg,
137 -1.0f, 1.0f);
138 dot = std::acos(cos_theta);
139 }
140
141 // np.cross(v, w)[2] for 2-D vectors lifted into 3-D is just vx*wy - vy*wx.
142 const float cross_z = vx * wy - vy * wx;
143 if (cross_z < 0.0f) {
144 dot *= -1.0f;
145 }
146
147 _e_buffer.push_back(dot);
148 TrimDeque(_e_buffer, kErrorBufferMaxLen);
149
150 float de = 0.0f;
151 float ie = 0.0f;
152 if (_e_buffer.size() >= 2) {
153 de = (_e_buffer.back() - _e_buffer[_e_buffer.size() - 2]) / _dt;
154 float sum = 0.0f;
155 for (float e : _e_buffer) sum += e;
156 ie = sum * _dt;
157 }
158
159 const float u = (_k_p * dot) + (_k_d * de) + (_k_i * ie);
160 return std::clamp(u, -1.0f, 1.0f);
161}
162
164 _offset = offset;
165}
166
168 float K_P, float K_I, float K_D, float dt) {
169 _k_p = K_P;
170 _k_i = K_I;
171 _k_d = K_D;
172 _dt = dt;
173}
174
175// =========================================================================
176// VehiclePIDController
177// =========================================================================
178
181 const LateralArgs &lateral,
182 const LongitudinalArgs &longitudinal,
183 float offset,
184 float max_throttle,
185 float max_brake,
186 float max_steering)
187 : _vehicle(vehicle),
188 _max_throttle(max_throttle),
189 _max_brake(max_brake),
190 _max_steering(max_steering),
191 _past_steering(vehicle ? vehicle->GetControl().steer : 0.0f),
192 _lon_controller(vehicle, longitudinal.K_P, longitudinal.K_I,
193 longitudinal.K_D, longitudinal.dt),
194 _lat_controller(vehicle, offset, lateral.K_P, lateral.K_I,
195 lateral.K_D, lateral.dt) {}
196
198 float target_speed_kmh,
200 const float acceleration = _lon_controller.RunStep(target_speed_kmh);
201 float current_steering = _lat_controller.RunStep(wp);
202
203 rpc::VehicleControl control;
204 if (acceleration >= 0.0f) {
205 control.throttle = std::min(acceleration, _max_throttle);
206 control.brake = 0.0f;
207 } else {
208 control.throttle = 0.0f;
209 control.brake = std::min(std::abs(acceleration), _max_brake);
210 }
211
212 // Rate-limit steering changes (mirrors controller.py).
213 if (current_steering > _past_steering + 0.1f) {
214 current_steering = _past_steering + 0.1f;
215 } else if (current_steering < _past_steering - 0.1f) {
216 current_steering = _past_steering - 0.1f;
217 }
218
219 float steering;
220 if (current_steering >= 0.0f) {
221 steering = std::min(_max_steering, current_steering);
222 } else {
223 steering = std::max(-_max_steering, current_steering);
224 }
225
226 control.steer = steering;
227 control.hand_brake = false;
228 control.manual_gear_shift = false;
229 _past_steering = steering;
230
231 return control;
232}
233
237
241
244}
245
246} // namespace navigation
247} // namespace agents
248} // namespace carla
void ChangeParameters(float K_P, float K_I, float K_D, float dt)
PIDLateralController(SharedPtr< client::Vehicle > vehicle, float offset=0.0f, float K_P=1.0f, float K_I=0.0f, float K_D=0.0f, float dt=0.03f)
float RunStep(SharedPtr< client::Waypoint > waypoint)
Returns a steering command in the range [-1, 1].
float PidControl(float target_speed_kmh, float current_speed_kmh)
PIDLongitudinalController(SharedPtr< client::Vehicle > vehicle, float K_P=1.0f, float K_I=0.0f, float K_D=0.0f, float dt=0.03f)
void ChangeParameters(float K_P, float K_I, float K_D, float dt)
float RunStep(float target_speed_kmh, bool debug=false)
Returns the throttle/brake command (clamped to [-1, 1]).
VehiclePIDController(SharedPtr< client::Vehicle > vehicle, const LateralArgs &lateral, const LongitudinalArgs &longitudinal, float offset=0.0f, float max_throttle=0.75f, float max_brake=0.30f, float max_steering=0.80f)
void ChangeLongitudinalPID(const LongitudinalArgs &args)
rpc::VehicleControl RunStep(float target_speed_kmh, SharedPtr< client::Waypoint > wp)
Drives towards wp at target_speed_kmh and returns the resulting VehicleControl.
float GetSpeed(SharedPtr< client::Actor > actor)
Compute speed of an actor in km/h.
Definition Misc.cpp:37
This file contains definitions of common data structures used in traffic manager.
std::shared_ptr< T > SharedPtr
Definition Memory.h:15