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>
21 #include <iomanip>
22 #include <iostream>
23 #include <limits>
24 #include <optional>
26 #include <traffic_simulator_msgs/msg/behavior_parameter.hpp>
27 #include <traffic_simulator_msgs/msg/entity_status.hpp>
28 #include <traffic_simulator_msgs/msg/polyline_trajectory.hpp>
29 
30 namespace traffic_simulator
31 {
32 namespace follow_trajectory
33 {
35 {
36  template <typename... Ts>
37  explicit ControllerError(Ts &&... xs)
38  : common::Error(common::concatenate(
39  "An error occurred in the internal controller operation in the FollowTrajectoryAction. ",
40  "Please report the following information to the developer: ",
41  std::forward<decltype(xs)>(xs)...))
42  {
43  }
44 };
45 
47 {
50  static constexpr bool use_distance_along_lanelet = false;
51 
53  double travel_time;
54 
56  : traveled_distance(0.0), travel_time(0.0), entity_status_(status)
57  {
58  }
59 
62  const double travel_time)
63  : traveled_distance(traveled_distance), travel_time(travel_time), entity_status_(status)
64  {
65  }
66 
81  template <typename UpdateEntityStatusFunc, typename DistanceAlongLaneletFunc>
82  auto step(
83  const double step_acceleration, const double step_time,
84  const UpdateEntityStatusFunc & update_entity_status,
85  const DistanceAlongLaneletFunc & distance_along_lanelet) -> void
86  {
87  const auto current_speed = entity_status_.action_status.twist.linear.x;
88  const auto desired_speed = current_speed + step_acceleration * step_time;
89 
90  if constexpr (use_distance_along_lanelet) {
91  const auto desired_velocity = [&]() {
92  const auto euler =
93  math::geometry::convertQuaternionToEulerAngle(entity_status_.pose.orientation);
95  return geometry_msgs::build<geometry_msgs::msg::Vector3>()
96  .x(std::cos(-euler.y) * std::cos(euler.z) * desired_speed)
97  .y(std::cos(-euler.y) * std::sin(euler.z) * desired_speed)
98  .z(std::sin(-euler.y) * desired_speed);
99  }();
100  const auto position_before_update = entity_status_.pose.position;
101  entity_status_ = update_entity_status(entity_status_, desired_velocity);
103  distance_along_lanelet(position_before_update, entity_status_.pose.position);
104  } else {
105  entity_status_.action_status.twist.linear.x = desired_speed;
106  entity_status_.action_status.accel.linear.x = (desired_speed - current_speed) / step_time;
107  traveled_distance += (current_speed + desired_speed) * 0.5 * step_time;
108  }
109  travel_time += step_time;
110  }
111 
113  {
114  return entity_status_;
115  }
116  auto getSpeed() const -> double { return entity_status_.action_status.twist.linear.x; }
117  auto getAcceleration() const -> double { return entity_status_.action_status.accel.linear.x; }
118 
119  auto isImmobile(const double tolerance) const -> bool
120  {
121  return std::abs(entity_status_.action_status.twist.linear.x) < tolerance &&
122  std::abs(entity_status_.action_status.accel.linear.x) < tolerance;
123  }
124 
125 private:
127 };
128 
130 {
131  const double step_time;
132  const bool with_braking;
133 
134  const double max_speed;
135  const double max_acceleration;
136  const double max_acceleration_rate;
137  const double max_deceleration;
138  const double max_deceleration_rate;
139 
140  const double target_speed;
141 
142  /*
143  Acceptable time step inaccuracy, allowing the time to be rounded up to the
144  full number of steps.
145 
146  There is no technical basis for this value, it was determined based on
147  Dawid Moszynski experiments.
148  */
149  static constexpr double step_time_tolerance = 1e-6;
150 
151  /*
152  Accuracy of the predicted arrival distance at the waypoint with the
153  specified time it is only used to detect in advance that it is most likely
154  impossible to arrive at a sufficient final accuracy.
155 
156  There is no technical basis for this value, it was determined based on
157  Dawid Moszynski experiments.
158  */
159  static constexpr double predicted_distance_tolerance = 1.0;
160 
161  /*
162  Number of considered acceleration candidates. This is a discretization of
163  the current range of [min_acceleration, max_acceleration].
164 
165  There is no technical basis for this value, it was determined based on
166  Dawid Moszynski experiments.
167  */
168  static constexpr std::size_t number_of_acceleration_candidates = 30;
169 
170  /*
171  This is a debugging method, it is not worth giving it much attention.
172  */
173  template <typename StreamType>
174  friend auto operator<<(StreamType & stream, const FollowWaypointController & c) -> StreamType &
175  {
176  stream << std::setprecision(16) << std::fixed;
177  stream << "FollowWaypointController: step_time: " << c.step_time
178  << ", with_braking: " << c.with_braking << ", max_speed: " << c.max_speed
179  << ", max_acceleration: " << c.max_acceleration
180  << ", max_deceleration: " << c.max_deceleration
181  << ", max_acceleration_rate: " << c.max_acceleration_rate
182  << ", max_deceleration_rate: " << c.max_deceleration_rate
183  << ", target_speed: " << c.target_speed << ". ";
184  return stream;
185  }
186 
187  /*
188  This provides an analytical method for calculating the acceleration that
189  will allow the best possible accuracy in arriving at the waypoint during
190  the last few frames. It provides the calculation of acceleration for
191  arriving at waypoint without and with braking.
192 
193  The method allows to calculate only the last 3 steps without braking and 4
194  with braking, because analytical calculation of a greater number of steps
195  is difficult - a greater number of steps is processed through the
196  prediction of the controller.
197 
198  Details:
199 
200  - Acceleration at the last step equal to 0.0, therefore in the penultimate
201  step the acceleration is set to 0.0
202 
203  - Only with braking: speed at the last and penultimate step equal to 0.0,
204  therefore when there are 3 steps remain the acceleration is calculated
205  in such a way as to set the speed to 0.0 (a=-v/t)
206 
207  - Only with braking: because the speed is set to 0.0 when there are 3
208  steps remain, in the last 3 steps no distance will be traveled,
209  therefore, when there are 4 steps remain, it is necessary to choose the
210  acceleration in such a way as to travel exactly the remaining distance
211  in this step (s = at^2/2+vt -> a = 2(s-vt)/t^2).
212 
213  - Only without braking: in the penultimate step, the acceleration is set
214  to 0, therefore, when 3 steps remain it is necessary to choose the
215  acceleration in such a way as to ensure that in the penultimate and last
216  step the distance traveled is equal to the remaining distance (s = last
217  + penultimate = (v+at)t + at^2/2+vt -> a = 2/3(s-2vt)/t^2).
218  */
219  auto getAnalyticalAccelerationForLastSteps(
220  const double remaining_time, const double remaining_distance, const double acceleration,
221  const double speed) const -> double;
222 
223  /*
224  This allows the correct counting of the remaining number of steps.
225  Without this, inaccuracy sometimes results in a decrease of more than 1
226  step which can cause major difficulties if we want to arrive at the
227  waypoint at the precise time.
228  */
229  auto roundTimeToFullStepsWithTolerance(
230  const double remaining_time_source, const double time_tolerance) const -> double;
231 
232  /*
233  This allows to calculate how much time (rounded up to whole steps) is
234  needed to reach acceleration equal to zero - which is necessary in case of
235  achieving the maximum speed (to not exceed it) and achieving the speed
236  equal to 0.0 (to not start moving backwards).
237  */
238  auto getTimeRequiredForNonAcceleration(const double acceleration) const -> double;
239 
264  auto getAccelerationLimits(const double acceleration, const double speed) const
265  -> std::pair<double, double>;
266 
267  auto clampAcceleration(
268  const double candidate_acceleration, const double acceleration, const double speed) const
269  -> double;
270 
271  auto getPredictedStopEntityStatusWithoutConsideringTime(
272  const double step_acceleration, const double remaining_distance,
273  const traffic_simulator_msgs::msg::EntityStatus & entity_status,
274  const std::function<traffic_simulator_msgs::msg::EntityStatus(
276  update_entity_status,
277  const std::function<
278  double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &
279  distance_along_lanelet) const -> std::optional<PredictedEntityStatus>;
280 
281 public:
282  /*
283  Accuracy of the remaining distance to the waypoint at the moment
284  of arrival with a specified time.
285 
286  There is no technical basis for this value, it was determined based on
287  Dawid Moszynski experiments.
288  */
289  static constexpr double remaining_distance_tolerance = 0.1;
290 
291  /*
292  Achieving official epsilon (1e-16) accuracy when using doubles is
293  difficult for this reason the controller uses less accuracy.
294 
295  There is no technical basis for this value, it was determined based on
296  Dawid Moszynski experiments.
297  */
298  static constexpr double local_epsilon = 1e-12;
299 
300  explicit constexpr FollowWaypointController(
301  const traffic_simulator_msgs::msg::BehaviorParameter & behavior_parameter,
302  const double step_time, const bool with_braking,
303  const std::optional<double> & target_speed = std::nullopt)
304  : step_time{step_time},
305  with_braking{with_braking},
306  max_speed{behavior_parameter.dynamic_constraints.max_speed},
307  max_acceleration{behavior_parameter.dynamic_constraints.max_acceleration},
308  max_acceleration_rate{behavior_parameter.dynamic_constraints.max_acceleration_rate},
309  max_deceleration{behavior_parameter.dynamic_constraints.max_deceleration},
310  max_deceleration_rate{behavior_parameter.dynamic_constraints.max_deceleration_rate},
311  target_speed{(target_speed) ? target_speed.value() : max_speed}
312  {
313  }
314 
409  const double current_speed, const double target_speed, const double acceleration_rate) const
410  -> double;
411 
412  /*
413  This is a debugging method, it is not worth giving it much attention.
414  */
416  const traffic_simulator_msgs::msg::PolylineTrajectory & polyline_trajectory) const
417  -> std::string
418  {
419  if (const auto & vertices = polyline_trajectory.shape.vertices; !vertices.empty()) {
420  std::stringstream waypoint_details;
421  waypoint_details << "Currently followed waypoint: ";
422  if (const auto first_waypoint_with_arrival_time_specified = std::find_if(
423  vertices.begin(), vertices.end(),
424  [](const auto & vertex) { return std::isfinite(vertex.time); });
425  first_waypoint_with_arrival_time_specified !=
426  std::end(polyline_trajectory.shape.vertices)) {
427  waypoint_details << "[" << first_waypoint_with_arrival_time_specified->position.position.x
428  << ", " << first_waypoint_with_arrival_time_specified->position.position.y
429  << "] with specified time equal to "
430  << first_waypoint_with_arrival_time_specified->time << "s. ";
431  } else {
432  waypoint_details << "[" << vertices.back().position.position.x << ", "
433  << vertices.back().position.position.y << "] without specified time. ";
434  }
435  return waypoint_details.str();
436  } else {
437  return "No followed waypoint - trajectory is empty.";
438  }
439  }
440 
441  /*
442  This allows to predict the state that will be reached if the current
443  acceleration is changed from acceleration to step_acceleration.
444  */
446  const double step_acceleration, const double remaining_time, const double remaining_distance,
447  const traffic_simulator_msgs::msg::EntityStatus & entity_status,
448  const std::function<traffic_simulator_msgs::msg::EntityStatus(
450  update_entity_status,
451  const std::function<
452  double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &
453  distance_along_lanelet) const -> std::optional<PredictedEntityStatus>;
454  /*
455  This allows the best acceleration to be found for the current conditions,
456  without taking into account the arrival time - this is the case when every
457  next point of the trajectory has no specified time.
458  */
459  auto getAcceleration(
460  const double remaining_distance,
461  const traffic_simulator_msgs::msg::EntityStatus & entity_status,
462  const std::function<traffic_simulator_msgs::msg::EntityStatus(
464  update_entity_status,
465  const std::function<
466  double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &
467  distance_along_lanelet) const -> double;
468 
469  /*
470  This allows the best acceleration to be found for the current conditions,
471  taking into account the arrival time.
472  */
473  auto getAcceleration(
474  const double remaining_time_source, const double remaining_distance,
475  const traffic_simulator_msgs::msg::EntityStatus & entity_status,
476  const std::function<traffic_simulator_msgs::msg::EntityStatus(
478  update_entity_status,
479  const std::function<
480  double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &
481  distance_along_lanelet) const -> double;
482 
484  const double acceleration, const double speed, const double distance) const -> double
485  {
486  return (!with_braking || std::abs(speed) < local_epsilon) &&
487  std::abs(acceleration) < local_epsilon && distance < remaining_distance_tolerance;
488  }
489 };
490 } // namespace follow_trajectory
491 } // namespace traffic_simulator
492 
493 #endif // TRAFFIC_SIMULATOR__BEHAVIOR__FOLLOW_WAYPOINT_CONTROLLER_HPP_
Definition: follow_waypoint_controller.hpp:130
auto accelerationWithJerkConstraint(const double current_speed, const double target_speed, const double acceleration_rate) const -> double
Calculate the optimal acceleration for a single discrete step to reach a desired target speed while r...
Definition: follow_waypoint_controller.cpp:129
friend auto operator<<(StreamType &stream, const FollowWaypointController &c) -> StreamType &
Definition: follow_waypoint_controller.hpp:174
auto getAcceleration(const double remaining_distance, const traffic_simulator_msgs::msg::EntityStatus &entity_status, const std::function< traffic_simulator_msgs::msg::EntityStatus(const traffic_simulator_msgs::msg::EntityStatus &, const geometry_msgs::msg::Vector3 &)> &update_entity_status, const std::function< double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &distance_along_lanelet) const -> double
Definition: follow_waypoint_controller.cpp:350
static constexpr double local_epsilon
Definition: follow_waypoint_controller.hpp:298
static constexpr double remaining_distance_tolerance
Definition: follow_waypoint_controller.hpp:289
auto getFollowedWaypointDetails(const traffic_simulator_msgs::msg::PolylineTrajectory &polyline_trajectory) const -> std::string
Definition: follow_waypoint_controller.hpp:415
auto areConditionsOfArrivalMet(const double acceleration, const double speed, const double distance) const -> double
Definition: follow_waypoint_controller.hpp:483
constexpr FollowWaypointController(const traffic_simulator_msgs::msg::BehaviorParameter &behavior_parameter, const double step_time, const bool with_braking, const std::optional< double > &target_speed=std::nullopt)
Definition: follow_waypoint_controller.hpp:300
auto getPredictedWaypointArrivalState(const double step_acceleration, const double remaining_time, const double remaining_distance, const traffic_simulator_msgs::msg::EntityStatus &entity_status, const std::function< traffic_simulator_msgs::msg::EntityStatus(const traffic_simulator_msgs::msg::EntityStatus &, const geometry_msgs::msg::Vector3 &)> &update_entity_status, const std::function< double(const geometry_msgs::msg::Point &, const geometry_msgs::msg::Point &)> &distance_along_lanelet) const -> std::optional< PredictedEntityStatus >
Definition: follow_waypoint_controller.cpp:238
auto concatenate
Definition: concatenate.hpp:27
Definition: concatenate.hpp:24
auto convertQuaternionToEulerAngle(const T &q)
Definition: quaternion_to_euler.hpp:30
auto distance(const geometry_msgs::Pose &pose1, const geometry_msgs::Pose &pose2)
Definition: detection_sensor.cpp:45
Definition: lanelet_wrapper.hpp:40
geometry_msgs::msg::Point Point
Definition: lanelet_wrapper.hpp:65
geometry_msgs::msg::Vector3 Vector3
Definition: lanelet_wrapper.hpp:70
Definition: operators.hpp:25
Definition: api.hpp:32
traffic_simulator_msgs::msg::EntityStatus EntityStatus
Definition: entity_status.hpp:25
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
traffic_simulator_msgs::EntityStatus EntityStatus
Definition: helper_functions.hpp:32
Definition: exception.hpp:27
Definition: follow_waypoint_controller.hpp:35
ControllerError(Ts &&... xs)
Definition: follow_waypoint_controller.hpp:37
Definition: follow_waypoint_controller.hpp:47
auto getSpeed() const -> double
Definition: follow_waypoint_controller.hpp:116
double travel_time
Definition: follow_waypoint_controller.hpp:53
auto getAcceleration() const -> double
Definition: follow_waypoint_controller.hpp:117
double traveled_distance
Definition: follow_waypoint_controller.hpp:52
PredictedEntityStatus(const traffic_simulator_msgs::msg::EntityStatus &status, const double traveled_distance, const double travel_time)
Definition: follow_waypoint_controller.hpp:60
auto step(const double step_acceleration, const double step_time, const UpdateEntityStatusFunc &update_entity_status, const DistanceAlongLaneletFunc &distance_along_lanelet) -> void
Advance simulation by one time step with given acceleration.
Definition: follow_waypoint_controller.hpp:82
auto isImmobile(const double tolerance) const -> bool
Definition: follow_waypoint_controller.hpp:119
static constexpr bool use_distance_along_lanelet
Definition: follow_waypoint_controller.hpp:50
auto getEntityStatus() const -> const traffic_simulator_msgs::msg::EntityStatus &
Definition: follow_waypoint_controller.hpp:112
PredictedEntityStatus(const traffic_simulator_msgs::msg::EntityStatus &status)
Definition: follow_waypoint_controller.hpp:55