Skip to content

Commit a04f825

Browse files
feat(map_based_prediction): prediction with acc constraints (#5960)
* WIP add acc constraints to discard paths Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * Add lat acc constraints to predicted paths Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * Delete debug print Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * delete unused var Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * delete unused var Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * WIP Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * make lat acc calculation with yaw rate Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * eliminate debug prints Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * delete unused variable Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * refactor rename function Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * keep a copy of the straightest path in case all paths are cleared Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * refactor and add constraints check parameter Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * update documentation Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * add braces for readability (style guide) Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> * fix review issues Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> --------- Signed-off-by: Daniel Sanchez <daniel.sanchez@tier4.jp> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
1 parent 2eb8dfb commit a04f825

File tree

4 files changed

+211
-5
lines changed

4 files changed

+211
-5
lines changed

perception/map_based_prediction/README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Lane change logics is illustrated in the figure below.An example of how to tune
6666

6767
### Tuning lane change detection logic
6868

69-
Currently we provide two parameters to tune lane change detection:
69+
Currently we provide three parameters to tune lane change detection:
7070

7171
- `dist_threshold_to_bound_`: maximum distance from lane boundary allowed for lane changing vehicle
7272
- `time_threshold_to_bound_`: maximum time allowed for lane change vehicle to reach the boundary
@@ -124,6 +124,24 @@ See paper [2] for more details.
124124

125125
`lateral_control_time_horizon` parameter supports the tuning of the lateral path shape. This parameter is used to calculate the time to reach the reference path. The smaller the value, the more the path will be generated to reach the reference path quickly. (Mostly the center of the lane.)
126126

127+
#### Pruning predicted paths with lateral acceleration constraint
128+
129+
It is possible to apply a maximum lateral acceleration constraint to generated vehicle paths. This check verifies if it is possible for the vehicle to perform the predicted path without surpassing a lateral acceleration threshold `max_lateral_accel` when taking a curve. If it is not possible, it checks if the vehicle can slow down on time to take the curve with a deceleration of `min_acceleration_before_curve` and comply with the constraint. If that is also not possible, the path is eliminated.
130+
131+
Currently we provide three parameters to tune the lateral acceleration constraint:
132+
133+
- `check_lateral_acceleration_constraints_`: to enable the constraint check.
134+
- `max_lateral_accel_`: max acceptable lateral acceleration for predicted paths (absolute value).
135+
- `min_acceleration_before_curve_`: the minimum acceleration the vehicle would theoretically use to slow down before a curve is taken (must be negative).
136+
137+
You can change these parameters in rosparam in the table below.
138+
139+
| param name | default value |
140+
| ----------------------------------------- | -------------- |
141+
| `check_lateral_acceleration_constraints_` | `false` [bool] |
142+
| `max_lateral_accel` | `2.0` [m/s^2] |
143+
| `min_acceleration_before_curve` | `-2.0` [m/s^2] |
144+
127145
### Path prediction for crosswalk users
128146

129147
This module treats **Pedestrians** and **Bicycles** as objects using the crosswalk, and outputs prediction path based on map and estimated object's velocity, assuming the object has intention to cross the crosswalk, if the objects satisfies at least one of the following conditions:

perception/map_based_prediction/config/map_based_prediction.param.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
sigma_yaw_angle_deg: 5.0 #[angle degree]
1414
object_buffer_time_length: 2.0 #[s]
1515
history_time_length: 1.0 #[s]
16+
check_lateral_acceleration_constraints: false # whether to check if the predicted path complies with lateral acceleration constraints
17+
max_lateral_accel: 2.0 # [m/ss] max acceptable lateral acceleration for predicted vehicle paths
18+
min_acceleration_before_curve: -2.0 # [m/ss] min acceleration a vehicle might take to decelerate before a curve
1619
# parameter for shoulder lane prediction
1720
prediction_time_horizon_rate_for_validate_shoulder_lane_length: 0.8
1821

perception/map_based_prediction/include/map_based_prediction/map_based_prediction_node.hpp

+124-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
#define MAP_BASED_PREDICTION__MAP_BASED_PREDICTION_NODE_HPP_
1717

1818
#include "map_based_prediction/path_generator.hpp"
19+
#include "tf2/LinearMath/Quaternion.h"
20+
#include "tier4_autoware_utils/geometry/geometry.hpp"
21+
#include "tier4_autoware_utils/ros/update_param.hpp"
1922

2023
#include <rclcpp/rclcpp.hpp>
2124
#include <tier4_autoware_utils/ros/transform_listener.hpp>
2225
#include <tier4_autoware_utils/system/stop_watch.hpp>
2326

27+
#include "autoware_auto_planning_msgs/msg/trajectory_point.hpp"
2428
#include <autoware_auto_mapping_msgs/msg/had_map_bin.hpp>
2529
#include <autoware_auto_perception_msgs/msg/predicted_objects.hpp>
2630
#include <autoware_auto_perception_msgs/msg/tracked_objects.hpp>
@@ -34,6 +38,7 @@
3438
#include <lanelet2_routing/Forward.h>
3539
#include <lanelet2_traffic_rules/TrafficRules.h>
3640

41+
#include <algorithm>
3742
#include <deque>
3843
#include <memory>
3944
#include <string>
@@ -99,9 +104,10 @@ using autoware_auto_perception_msgs::msg::PredictedPath;
99104
using autoware_auto_perception_msgs::msg::TrackedObject;
100105
using autoware_auto_perception_msgs::msg::TrackedObjectKinematics;
101106
using autoware_auto_perception_msgs::msg::TrackedObjects;
107+
using autoware_auto_planning_msgs::msg::TrajectoryPoint;
102108
using tier4_autoware_utils::StopWatch;
103109
using tier4_debug_msgs::msg::StringStamped;
104-
110+
using TrajectoryPoints = std::vector<TrajectoryPoint>;
105111
class MapBasedPredictionNode : public rclcpp::Node
106112
{
107113
public:
@@ -123,6 +129,11 @@ class MapBasedPredictionNode : public rclcpp::Node
123129
std::shared_ptr<lanelet::routing::RoutingGraph> routing_graph_ptr_;
124130
std::shared_ptr<lanelet::traffic_rules::TrafficRules> traffic_rules_ptr_;
125131

132+
// parameter update
133+
OnSetParametersCallbackHandle::SharedPtr set_param_res_;
134+
rcl_interfaces::msg::SetParametersResult onParam(
135+
const std::vector<rclcpp::Parameter> & parameters);
136+
126137
// Pose Transform Listener
127138
tier4_autoware_utils::TransformListener transform_listener_{this};
128139

@@ -160,6 +171,10 @@ class MapBasedPredictionNode : public rclcpp::Node
160171
bool consider_only_routable_neighbours_;
161172
double reference_path_resolution_;
162173

174+
bool check_lateral_acceleration_constraints_;
175+
double max_lateral_accel_;
176+
double min_acceleration_before_curve_;
177+
163178
// Stop watch
164179
StopWatch<std::chrono::milliseconds> stop_watch_;
165180

@@ -237,6 +252,114 @@ class MapBasedPredictionNode : public rclcpp::Node
237252
Maneuver predictObjectManeuverByLatDiffDistance(
238253
const TrackedObject & object, const LaneletData & current_lanelet_data,
239254
const double object_detected_time);
255+
256+
// NOTE: This function is copied from the motion_velocity_smoother package.
257+
// TODO(someone): Consolidate functions and move them to a common
258+
inline std::vector<double> calcTrajectoryCurvatureFrom3Points(
259+
const TrajectoryPoints & trajectory, size_t idx_dist)
260+
{
261+
using tier4_autoware_utils::calcCurvature;
262+
using tier4_autoware_utils::getPoint;
263+
264+
if (trajectory.size() < 3) {
265+
const std::vector<double> k_arr(trajectory.size(), 0.0);
266+
return k_arr;
267+
}
268+
269+
// if the idx size is not enough, change the idx_dist
270+
const auto max_idx_dist = static_cast<size_t>(std::floor((trajectory.size() - 1) / 2.0));
271+
idx_dist = std::max(1ul, std::min(idx_dist, max_idx_dist));
272+
273+
if (idx_dist < 1) {
274+
throw std::logic_error("idx_dist less than 1 is not expected");
275+
}
276+
277+
// calculate curvature by circle fitting from three points
278+
std::vector<double> k_arr(trajectory.size(), 0.0);
279+
280+
for (size_t i = 1; i + 1 < trajectory.size(); i++) {
281+
double curvature = 0.0;
282+
const auto p0 = getPoint(trajectory.at(i - std::min(idx_dist, i)));
283+
const auto p1 = getPoint(trajectory.at(i));
284+
const auto p2 = getPoint(trajectory.at(i + std::min(idx_dist, trajectory.size() - 1 - i)));
285+
try {
286+
curvature = calcCurvature(p0, p1, p2);
287+
} catch (std::exception const & e) {
288+
// ...code that handles the error...
289+
RCLCPP_WARN(rclcpp::get_logger("map_based_prediction"), "%s", e.what());
290+
if (i > 1) {
291+
curvature = k_arr.at(i - 1); // previous curvature
292+
} else {
293+
curvature = 0.0;
294+
}
295+
}
296+
k_arr.at(i) = curvature;
297+
}
298+
// copy curvatures for the last and first points;
299+
k_arr.at(0) = k_arr.at(1);
300+
k_arr.back() = k_arr.at((trajectory.size() - 2));
301+
302+
return k_arr;
303+
}
304+
305+
inline TrajectoryPoints toTrajectoryPoints(const PredictedPath & path, const double velocity)
306+
{
307+
TrajectoryPoints out_trajectory;
308+
std::for_each(
309+
path.path.begin(), path.path.end(), [&out_trajectory, velocity](const auto & pose) {
310+
TrajectoryPoint p;
311+
p.pose = pose;
312+
p.longitudinal_velocity_mps = velocity;
313+
out_trajectory.push_back(p);
314+
});
315+
return out_trajectory;
316+
};
317+
318+
inline bool isLateralAccelerationConstraintSatisfied(
319+
const TrajectoryPoints & trajectory [[maybe_unused]], const double delta_time)
320+
{
321+
if (trajectory.size() < 3) return true;
322+
const double max_lateral_accel_abs = std::fabs(max_lateral_accel_);
323+
324+
double arc_length = 0.0;
325+
for (size_t i = 1; i < trajectory.size(); ++i) {
326+
const auto current_pose = trajectory.at(i).pose;
327+
const auto next_pose = trajectory.at(i - 1).pose;
328+
// Compute distance between poses
329+
const double delta_s = std::hypot(
330+
next_pose.position.x - current_pose.position.x,
331+
next_pose.position.y - current_pose.position.y);
332+
arc_length += delta_s;
333+
334+
// Compute change in heading
335+
tf2::Quaternion q_current, q_next;
336+
tf2::convert(current_pose.orientation, q_current);
337+
tf2::convert(next_pose.orientation, q_next);
338+
double delta_theta = q_current.angleShortestPath(q_next);
339+
// Handle wrap-around
340+
if (delta_theta > M_PI) {
341+
delta_theta -= 2.0 * M_PI;
342+
} else if (delta_theta < -M_PI) {
343+
delta_theta += 2.0 * M_PI;
344+
}
345+
346+
const double yaw_rate = std::max(delta_theta / delta_time, 1.0E-5);
347+
348+
const double current_speed = std::abs(trajectory.at(i).longitudinal_velocity_mps);
349+
// Compute lateral acceleration
350+
const double lateral_acceleration = std::abs(current_speed * yaw_rate);
351+
if (lateral_acceleration < max_lateral_accel_abs) continue;
352+
353+
const double v_curvature_max = std::sqrt(max_lateral_accel_abs / yaw_rate);
354+
const double t =
355+
(v_curvature_max - current_speed) / min_acceleration_before_curve_; // acc is negative
356+
const double distance_to_slow_down =
357+
current_speed * t + 0.5 * min_acceleration_before_curve_ * std::pow(t, 2);
358+
359+
if (distance_to_slow_down > arc_length) return false;
360+
}
361+
return true;
362+
};
240363
};
241364
} // namespace map_based_prediction
242365

perception/map_based_prediction/src/map_based_prediction_node.cpp

+65-3
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,12 @@ MapBasedPredictionNode::MapBasedPredictionNode(const rclcpp::NodeOptions & node_
740740
sigma_yaw_angle_deg_ = declare_parameter<double>("sigma_yaw_angle_deg");
741741
object_buffer_time_length_ = declare_parameter<double>("object_buffer_time_length");
742742
history_time_length_ = declare_parameter<double>("history_time_length");
743+
744+
check_lateral_acceleration_constraints_ =
745+
declare_parameter<bool>("check_lateral_acceleration_constraints");
746+
max_lateral_accel_ = declare_parameter<double>("max_lateral_accel");
747+
min_acceleration_before_curve_ = declare_parameter<double>("min_acceleration_before_curve");
748+
743749
{ // lane change detection
744750
lane_change_detection_method_ = declare_parameter<std::string>("lane_change_detection.method");
745751

@@ -789,6 +795,25 @@ MapBasedPredictionNode::MapBasedPredictionNode(const rclcpp::NodeOptions & node_
789795
pub_debug_markers_ =
790796
this->create_publisher<visualization_msgs::msg::MarkerArray>("maneuver", rclcpp::QoS{1});
791797
pub_calculation_time_ = create_publisher<StringStamped>("~/debug/calculation_time", 1);
798+
799+
set_param_res_ = this->add_on_set_parameters_callback(
800+
std::bind(&MapBasedPredictionNode::onParam, this, std::placeholders::_1));
801+
}
802+
803+
rcl_interfaces::msg::SetParametersResult MapBasedPredictionNode::onParam(
804+
const std::vector<rclcpp::Parameter> & parameters)
805+
{
806+
using tier4_autoware_utils::updateParam;
807+
808+
updateParam(parameters, "max_lateral_accel", max_lateral_accel_);
809+
updateParam(parameters, "min_acceleration_before_curve", min_acceleration_before_curve_);
810+
updateParam(
811+
parameters, "check_lateral_acceleration_constraints", check_lateral_acceleration_constraints_);
812+
813+
rcl_interfaces::msg::SetParametersResult result;
814+
result.successful = true;
815+
result.reason = "success";
816+
return result;
792817
}
793818

794819
PredictedObjectKinematics MapBasedPredictionNode::convertToPredictedKinematics(
@@ -972,16 +997,53 @@ void MapBasedPredictionNode::objectsCallback(const TrackedObjects::ConstSharedPt
972997
}
973998
// Generate Predicted Path
974999
std::vector<PredictedPath> predicted_paths;
1000+
double min_avg_curvature = std::numeric_limits<double>::max();
1001+
PredictedPath path_with_smallest_avg_curvature;
1002+
9751003
for (const auto & ref_path : ref_paths) {
9761004
PredictedPath predicted_path = path_generator_->generatePathForOnLaneVehicle(
9771005
yaw_fixed_transformed_object, ref_path.path);
978-
if (predicted_path.path.empty()) {
1006+
if (predicted_path.path.empty()) continue;
1007+
1008+
if (!check_lateral_acceleration_constraints_) {
1009+
predicted_path.confidence = ref_path.probability;
1010+
predicted_paths.push_back(predicted_path);
9791011
continue;
9801012
}
981-
predicted_path.confidence = ref_path.probability;
982-
predicted_paths.push_back(predicted_path);
1013+
1014+
// Check lat. acceleration constraints
1015+
const auto trajectory_with_const_velocity =
1016+
toTrajectoryPoints(predicted_path, abs_obj_speed);
1017+
1018+
if (isLateralAccelerationConstraintSatisfied(
1019+
trajectory_with_const_velocity, prediction_sampling_time_interval_)) {
1020+
predicted_path.confidence = ref_path.probability;
1021+
predicted_paths.push_back(predicted_path);
1022+
continue;
1023+
}
1024+
1025+
// Calculate curvature assuming the trajectory points interval is constant
1026+
// In case all paths are deleted, a copy of the straightest path is kept
1027+
1028+
constexpr double curvature_calculation_distance = 2.0;
1029+
constexpr double points_interval = 1.0;
1030+
const size_t idx_dist = static_cast<size_t>(
1031+
std::max(static_cast<int>((curvature_calculation_distance) / points_interval), 1));
1032+
const auto curvature_v =
1033+
calcTrajectoryCurvatureFrom3Points(trajectory_with_const_velocity, idx_dist);
1034+
if (curvature_v.empty()) {
1035+
continue;
1036+
}
1037+
const auto curvature_avg =
1038+
std::accumulate(curvature_v.begin(), curvature_v.end(), 0.0) / curvature_v.size();
1039+
if (curvature_avg < min_avg_curvature) {
1040+
min_avg_curvature = curvature_avg;
1041+
path_with_smallest_avg_curvature = predicted_path;
1042+
path_with_smallest_avg_curvature.confidence = ref_path.probability;
1043+
}
9831044
}
9841045

1046+
if (predicted_paths.empty()) predicted_paths.push_back(path_with_smallest_avg_curvature);
9851047
// Normalize Path Confidence and output the predicted object
9861048

9871049
float sum_confidence = 0.0;

0 commit comments

Comments
 (0)