scenario_simulator_v2 C++ API
follow_waypoint_controller.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef TRAFFIC_SIMULATOR__BEHAVIOR__FOLLOW_WAYPOINT_CONTROLLER_HPP_
16 #define TRAFFIC_SIMULATOR__BEHAVIOR__FOLLOW_WAYPOINT_CONTROLLER_HPP_
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <iomanip>
21 #include <iostream>
22 #include <limits>
23 #include <optional>
25 #include <traffic_simulator_msgs/msg/behavior_parameter.hpp>
26 #include <traffic_simulator_msgs/msg/entity_status.hpp>
27 #include <traffic_simulator_msgs/msg/polyline_trajectory.hpp>
28 
29 namespace traffic_simulator
30 {
31 namespace follow_trajectory
32 {
34 {
35  template <typename... Ts>
36  explicit ControllerError(Ts &&... xs)
37  : common::Error(common::concatenate(
38  "An error occurred in the internal controller operation in the FollowTrajectoryAction. ",
39  "Please report the following information to the developer: ",
40  std::forward<decltype(xs)>(xs)...))
41  {
42  }
43 };
44 
46 {
47  double acceleration;
48  double speed;
50  double travel_time;
51 
52  auto moveStraight(const double step_acceleration, const double step_time) -> void
53  {
54  acceleration = step_acceleration;
55  speed += acceleration * step_time;
56  traveled_distance += speed * step_time;
57  travel_time += step_time;
58  }
59 
60  auto isImmobile(const double tolerance) const
61  {
62  return std::abs(speed) < tolerance && std::abs(acceleration) < tolerance;
63  }
64 
65  template <typename StreamType>
66  friend auto operator<<(StreamType & stream, const PredictedState & state) -> StreamType &
67  {
68  stream << std::setprecision(16) << std::fixed;
69  stream << "PredictedState: acceleration: " << state.acceleration << ", speed: " << state.speed
70  << ", distance: " << state.traveled_distance << ", time: " << state.travel_time << ". ";
71  return stream;
72  }
73 };
74 
76 {
77  const double step_time;
78  const bool with_breaking;
79 
80  const double max_speed;
81  const double max_acceleration;
82  const double max_acceleration_rate;
83  const double max_deceleration;
84  const double max_deceleration_rate;
85 
86  const double target_speed;
87 
88  /*
89  Acceptable time step inaccuracy, allowing the time to be rounded up to the
90  full number of steps.
91 
92  There is no technical basis for this value, it was determined based on
93  Dawid Moszynski experiments.
94  */
95  static constexpr double step_time_tolerance = 1e-6;
96 
97  /*
98  Accuracy of the predicted arrival distance at the waypoint with the
99  specified time it is only used to detect in advance that it is most likely
100  impossible to arrive at a sufficient final accuracy.
101 
102  There is no technical basis for this value, it was determined based on
103  Dawid Moszynski experiments.
104  */
105  static constexpr double predicted_distance_tolerance = 1.0;
106 
107  /*
108  Number of considered acceleration candidates. This is a discretization of
109  the current range of [min_acceleration, max_acceleration].
110 
111  There is no technical basis for this value, it was determined based on
112  Dawid Moszynski experiments.
113  */
114  static constexpr std::size_t number_of_acceleration_candidates = 30;
115 
116  /*
117  This is a debugging method, it is not worth giving it much attention.
118  */
119  template <typename StreamType>
120  friend auto operator<<(StreamType & stream, const FollowWaypointController & c) -> StreamType &
121  {
122  stream << std::setprecision(16) << std::fixed;
123  stream << "FollowWaypointController: step_time: " << c.step_time
124  << ", with_breaking: " << c.with_breaking << ", max_speed: " << c.max_speed
125  << ", max_acceleration: " << c.max_acceleration
126  << ", max_deceleration: " << c.max_deceleration
127  << ", max_acceleration_rate: " << c.max_acceleration_rate
128  << ", max_deceleration_rate: " << c.max_deceleration_rate
129  << ", target_speed: " << c.target_speed << ". ";
130  return stream;
131  }
132 
133  /*
134  This provides an analytical method for calculating the acceleration that
135  will allow the best possible accuracy in arriving at the waypoint during
136  the last few frames. It provides the calculation of acceleration for
137  arriving at waypoint without and with braking.
138 
139  The method allows to calculate only the last 3 steps without braking and 4
140  with braking, because analytical calculation of a greater number of steps
141  is difficult - a greater number of steps is processed through the
142  prediction of the controller.
143 
144  Details:
145 
146  - Acceleration at the last step equal to 0.0, therefore in the penultimate
147  step the acceleration is set to 0.0
148 
149  - Only with braking: speed at the last and penultimate step equal to 0.0,
150  therefore when there are 3 steps remain the acceleration is calculated
151  in such a way as to set the speed to 0.0 (a=-v/t)
152 
153  - Only with braking: because the speed is set to 0.0 when there are 3
154  steps remain, in the last 3 steps no distance will be traveled,
155  therefore, when there are 4 steps remain, it is necessary to choose the
156  acceleration in such a way as to travel exactly the remaining distance
157  in this step (s = at^2/2+vt -> a = 2(s-vt)/t^2).
158 
159  - Only without braking: in the penultimate step, the acceleration is set
160  to 0, therefore, when 3 steps remain it is necessary to choose the
161  acceleration in such a way as to ensure that in the penultimate and last
162  step the distance traveled is equal to the remaining distance (s = last
163  + penultimate = (v+at)t + at^2/2+vt -> a = 2/3(s-2vt)/t^2).
164  */
165  auto getAnalyticalAccelerationForLastSteps(
166  const double remaining_time, const double remaining_distance, const double acceleration,
167  const double speed) const -> double;
168 
169  /*
170  This allows the correct counting of the remaining number of steps.
171  Without this, inaccuracy sometimes results in a decrease of more than 1
172  step which can cause major difficulties if we want to arrive at the
173  waypoint at the precise time.
174  */
175  auto roundTimeToFullStepsWithTolerance(
176  const double remaining_time_source, const double time_tolerance) const -> double;
177 
178  /*
179  This allows to calculate how much time (rounded up to whole steps) is
180  needed to reach acceleration equal to zero - which is necessary in case of
181  achieving the maximum speed (to not exceed it) and achieving the speed
182  equal to 0.0 (to not start moving backwards).
183  */
184  auto getTimeRequiredForNonAcceleration(const double acceleration) const -> double;
185 
186  /*
187  This allows the calculation of acceleration limits that meet the
188  constraints. The limits depend on the current acceleration, the current
189  speed and the limits on the change in acceleration (rate).
190  */
191  auto getAccelerationLimits(const double acceleration, const double speed) const
192  -> std::pair<double, double>;
193 
194  auto clampAcceleration(
195  const double candidate_acceleration, const double acceleration, const double speed) const
196  -> double;
197 
198  auto moveStraight(PredictedState & state, const double candidate_acceleration) const -> void;
199 
200  auto getPredictedStopStateWithoutConsideringTime(
201  const double step_acceleration, const double remaining_distance, const double acceleration,
202  const double speed) const -> std::optional<PredictedState>;
203 
204 public:
205  /*
206  Accuracy of the remaining distance to the waypoint at the moment
207  of arrival with a specified time.
208 
209  There is no technical basis for this value, it was determined based on
210  Dawid Moszynski experiments.
211  */
212  static constexpr double remaining_distance_tolerance = 0.1;
213 
214  /*
215  Achieving official epsilon (1e-16) accuracy when using doubles is
216  difficult for this reason the controller uses less accuracy.
217 
218  There is no technical basis for this value, it was determined based on
219  Dawid Moszynski experiments.
220  */
221  static constexpr double local_epsilon = 1e-12;
222 
223  explicit constexpr FollowWaypointController(
224  const traffic_simulator_msgs::msg::BehaviorParameter & behavior_parameter,
225  const double step_time, const bool with_breaking,
226  const std::optional<double> & target_speed = std::nullopt)
227  : step_time{step_time},
228  with_breaking{with_breaking},
229  max_speed{behavior_parameter.dynamic_constraints.max_speed},
230  max_acceleration{behavior_parameter.dynamic_constraints.max_acceleration},
231  max_acceleration_rate{behavior_parameter.dynamic_constraints.max_acceleration_rate},
232  max_deceleration{behavior_parameter.dynamic_constraints.max_deceleration},
233  max_deceleration_rate{behavior_parameter.dynamic_constraints.max_deceleration_rate},
234  target_speed{(target_speed) ? target_speed.value() : max_speed}
235  {
236  }
237 
238  /*
239  This is a debugging method, it is not worth giving it much attention.
240  */
242  const traffic_simulator_msgs::msg::PolylineTrajectory & polyline_trajectory) const
243  -> std::string
244  {
245  if (const auto & vertices = polyline_trajectory.shape.vertices; !vertices.empty()) {
246  std::stringstream waypoint_details;
247  waypoint_details << "Currently followed waypoint: ";
248  if (const auto first_waypoint_with_arrival_time_specified = std::find_if(
249  vertices.begin(), vertices.end(),
250  [](auto && vertex) { return not std::isnan(vertex.time); });
251  first_waypoint_with_arrival_time_specified !=
252  std::end(polyline_trajectory.shape.vertices)) {
253  waypoint_details << "[" << first_waypoint_with_arrival_time_specified->position.position.x
254  << ", " << first_waypoint_with_arrival_time_specified->position.position.y
255  << "] with specified time equal to "
256  << first_waypoint_with_arrival_time_specified->time << "s. ";
257  } else {
258  waypoint_details << "[" << vertices.back().position.position.x << ", "
259  << vertices.back().position.position.y << "] without specified time. ";
260  }
261  return waypoint_details.str();
262  } else {
263  return "No followed waypoint - trajectory is empty.";
264  }
265  }
266 
267  /*
268  This allows to predict the state that will be reached if the current
269  acceleration is changed from acceleration to step_acceleration.
270  */
272  const double step_acceleration, const double remaining_time, const double remaining_distance,
273  const double acceleration, const double speed) const -> std::optional<PredictedState>;
274  /*
275  This allows the best acceleration to be found for the current conditions,
276  without taking into account the arrival time - this is the case when every
277  next point of the trajectory has no specified time.
278  */
279  auto getAcceleration(
280  const double remaining_distance, const double acceleration, const double speed) const -> double;
281 
282  /*
283  This allows the best acceleration to be found for the current conditions,
284  taking into account the arrival time.
285  */
286  auto getAcceleration(
287  const double remaining_time_source, const double remaining_distance, const double acceleration,
288  const double speed) const -> double;
289 
291  const double acceleration, const double speed, const double distance) const -> double
292  {
293  return (!with_breaking || std::abs(speed) < local_epsilon) &&
294  std::abs(acceleration) < local_epsilon && distance < remaining_distance_tolerance;
295  }
296 };
297 } // namespace follow_trajectory
298 } // namespace traffic_simulator
299 
300 #endif // TRAFFIC_SIMULATOR__BEHAVIOR__FOLLOW_WAYPOINT_CONTROLLER_HPP_
Definition: follow_waypoint_controller.hpp:76
auto getAcceleration(const double remaining_distance, const double acceleration, const double speed) const -> double
Definition: follow_waypoint_controller.cpp:296
friend auto operator<<(StreamType &stream, const FollowWaypointController &c) -> StreamType &
Definition: follow_waypoint_controller.hpp:120
constexpr FollowWaypointController(const traffic_simulator_msgs::msg::BehaviorParameter &behavior_parameter, const double step_time, const bool with_breaking, const std::optional< double > &target_speed=std::nullopt)
Definition: follow_waypoint_controller.hpp:223
static constexpr double local_epsilon
Definition: follow_waypoint_controller.hpp:221
static constexpr double remaining_distance_tolerance
Definition: follow_waypoint_controller.hpp:212
auto getPredictedWaypointArrivalState(const double step_acceleration, const double remaining_time, const double remaining_distance, const double acceleration, const double speed) const -> std::optional< PredictedState >
Definition: follow_waypoint_controller.cpp:207
auto getFollowedWaypointDetails(const traffic_simulator_msgs::msg::PolylineTrajectory &polyline_trajectory) const -> std::string
Definition: follow_waypoint_controller.hpp:241
auto areConditionsOfArrivalMet(const double acceleration, const double speed, const double distance) const -> double
Definition: follow_waypoint_controller.hpp:290
auto concatenate
Definition: concatenate.hpp:27
Definition: concatenate.hpp:24
auto distance(const geometry_msgs::Pose &pose1, const geometry_msgs::Pose &pose2)
Definition: detection_sensor.cpp:45
Definition: lanelet_wrapper.hpp:40
Definition: api.hpp:32
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
Definition: exception.hpp:27
Definition: follow_waypoint_controller.hpp:34
ControllerError(Ts &&... xs)
Definition: follow_waypoint_controller.hpp:36
Definition: follow_waypoint_controller.hpp:46
friend auto operator<<(StreamType &stream, const PredictedState &state) -> StreamType &
Definition: follow_waypoint_controller.hpp:66
double traveled_distance
Definition: follow_waypoint_controller.hpp:49
double acceleration
Definition: follow_waypoint_controller.hpp:47
double speed
Definition: follow_waypoint_controller.hpp:48
double travel_time
Definition: follow_waypoint_controller.hpp:50
auto moveStraight(const double step_acceleration, const double step_time) -> void
Definition: follow_waypoint_controller.hpp:52
auto isImmobile(const double tolerance) const
Definition: follow_waypoint_controller.hpp:60