Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dynamic_obstacle_stop): add option to ignore unavoidable collisions #6594

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions planning/behavior_velocity_dynamic_obstacle_stop_module/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ An object is considered by the module only if it meets all of the following cond
- it is a vehicle (pedestrians are ignored);
- it is moving at a velocity higher than defined by the `minimum_object_velocity` parameter;
- it is not too close to the current position of the ego vehicle;
- it is not unavoidable (only if parameter `ignore_unavoidable_collisions` is set to `true`);
- it is close to the ego path.

An object is considered unavoidable if it is heading towards the ego vehicle such that even if ego stops, a collision would still occur (assuming the object keeps driving in a straight line).

For the last condition,
the object is considered close enough if its lateral distance from the ego path is less than the threshold parameter `minimum_object_distance_from_ego_path` plus half the width of ego and of the object (including the `extra_object_width` parameter).
In addition, the value of the `hysteresis` parameter is added to the minimum distance if a stop point was inserted in the previous iteration.
Expand Down Expand Up @@ -74,12 +77,13 @@ the stop point arc length is calculated to be the arc length of the previously f

### Module Parameters

| Parameter | Type | Description |
| --------------------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| `extra_object_width` | double | [m] extra width around detected objects |
| `minimum_object_velocity` | double | [m/s] objects with a velocity bellow this value are ignored |
| `stop_distance_buffer` | double | [m] extra distance to add between the stop point and the collision point |
| `time_horizon` | double | [s] time horizon used for collision checks |
| `hysteresis` | double | [m] once a collision has been detected, this hysteresis is used on the collision detection |
| `decision_duration_buffer` | double | [s] duration between no collision being detected and the stop decision being cancelled |
| `minimum_object_distance_from_ego_path` | double | [m] minimum distance between the footprints of ego and an object to consider for collision |
| Parameter | Type | Description |
| --------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| `extra_object_width` | double | [m] extra width around detected objects |
| `minimum_object_velocity` | double | [m/s] objects with a velocity bellow this value are ignored |
| `stop_distance_buffer` | double | [m] extra distance to add between the stop point and the collision point |
| `time_horizon` | double | [s] time horizon used for collision checks |
| `hysteresis` | double | [m] once a collision has been detected, this hysteresis is used on the collision detection |
| `decision_duration_buffer` | double | [s] duration between no collision being detected and the stop decision being cancelled |
| `minimum_object_distance_from_ego_path` | double | [m] minimum distance between the footprints of ego and an object to consider for collision |
| `ignore_unavoidable_collisions` | bool | [-] if true, ignore collisions that cannot be avoided by stopping (assuming the obstacle continues going straight) |
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
hysteresis: 1.0 # [m] once a collision has been detected, this hysteresis is used on the collision detection
decision_duration_buffer : 1.0 # [s] duration between no collision being detected and the stop decision being cancelled
minimum_object_distance_from_ego_path: 1.0 # [m] minimum distance between the footprints of ego and an object to consider for collision
ignore_unavoidable_collisions : true # if true, ignore collisions that cannot be avoided by stopping (assuming the obstacle continues going straight)
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
getOrDeclareParameter<double>(node, ns + ".decision_duration_buffer");
pp.minimum_object_distance_from_ego_path =
getOrDeclareParameter<double>(node, ns + ".minimum_object_distance_from_ego_path");
pp.ignore_unavoidable_collisions =
getOrDeclareParameter<bool>(node, ns + ".ignore_unavoidable_collisions");

Check warning on line 43 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/manager.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/manager.cpp#L42-L43

Added lines #L42 - L43 were not covered by tests

const auto vehicle_info = vehicle_info_util::VehicleInfoUtil(node).getVehicleInfo();
pp.ego_lateral_offset =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,37 @@
return obj_arc_length > ego_data.longitudinal_offset_to_first_path_idx +
params.ego_longitudinal_offset + o.shape.dimensions.x / 2.0;
};
for (const auto & object : objects.objects)
const auto is_unavoidable = [&](const auto & o) {

Check warning on line 62 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L62

Added line #L62 was not covered by tests
const auto & o_pose = o.kinematics.initial_pose_with_covariance.pose;
const auto o_yaw = tf2::getYaw(o_pose.orientation);
const auto ego_yaw = tf2::getYaw(ego_data.pose.orientation);
const auto yaw_diff = std::abs(tier4_autoware_utils::normalizeRadian(o_yaw - ego_yaw));
const auto opposite_heading = yaw_diff > M_PI_2 + M_PI_4;
const auto collision_distance_threshold =
params.ego_lateral_offset + o.shape.dimensions.y / 2.0 + params.hysteresis;

Check warning on line 69 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L65-L69

Added lines #L65 - L69 were not covered by tests
// https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_point_and_angle
const auto lat_distance = std::abs(
(o_pose.position.y - ego_data.pose.position.y) * std::cos(o_yaw) -
(o_pose.position.x - ego_data.pose.position.x) * std::sin(o_yaw));
auto has_collision = lat_distance <= collision_distance_threshold;
if (ego_data.earliest_stop_pose) {
const auto collision_at_earliest_stop_pose =
std::abs(
(o_pose.position.y - ego_data.earliest_stop_pose->position.y) * std::cos(o_yaw) -
(o_pose.position.x - ego_data.earliest_stop_pose->position.x) * std::sin(o_yaw)) <=

Check warning on line 79 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L71-L79

Added lines #L71 - L79 were not covered by tests
collision_distance_threshold;
has_collision |= collision_at_earliest_stop_pose;

Check warning on line 81 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L81

Added line #L81 was not covered by tests
}
return opposite_heading && has_collision;
};
for (const auto & object : objects.objects) {
const auto is_not_too_slow = object.kinematics.initial_twist_with_covariance.twist.linear.x >=
params.minimum_object_velocity;

Check warning on line 87 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L83-L87

Added lines #L83 - L87 were not covered by tests
if (
is_vehicle(object) &&
object.kinematics.initial_twist_with_covariance.twist.linear.x >=
params.minimum_object_velocity &&
is_in_range(object) && is_not_too_close(object))
is_vehicle(object) && is_not_too_slow && is_in_range(object) && is_not_too_close(object) &&
(!params.ignore_unavoidable_collisions || !is_unavoidable(object)))

Check warning on line 90 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Complex Conditional

filter_predicted_objects has 1 complex conditionals with 5 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.

Check warning on line 90 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp#L89-L90

Added lines #L89 - L90 were not covered by tests
filtered_objects.push_back(object);
}

Check notice on line 92 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Complex Method

filter_predicted_objects increases in cyclomatic complexity from 11 to 15, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
return filtered_objects;
}
} // namespace behavior_velocity_planner::dynamic_obstacle_stop
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
const rclcpp::Clock::SharedPtr clock)
: SceneModuleInterface(module_id, logger, clock), params_(std::move(planner_param))
{
prev_stop_decision_time_ = rclcpp::Time(int64_t{0}, clock->get_clock_type());
prev_stop_decision_time_ =
clock->now() -
rclcpp::Duration(std::chrono::duration<double>(params_.decision_duration_buffer));

Check warning on line 49 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L48-L49

Added lines #L48 - L49 were not covered by tests
velocity_factor_.init(PlanningBehavior::UNKNOWN);
}

Expand All @@ -65,10 +67,20 @@
motion_utils::findNearestSegmentIndex(ego_data.path.points, ego_data.pose.position);
ego_data.longitudinal_offset_to_first_path_idx = motion_utils::calcLongitudinalOffsetToSegment(
ego_data.path.points, ego_data.first_path_idx, ego_data.pose.position);
const auto min_stop_distance =
motion_utils::calcDecelDistWithJerkAndAccConstraints(
planner_data_->current_velocity->twist.linear.x, 0.0,
planner_data_->current_acceleration->accel.accel.linear.x,
planner_data_->max_stop_acceleration_threshold, -planner_data_->max_stop_jerk_threshold,
planner_data_->max_stop_jerk_threshold)

Check warning on line 75 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L71-L75

Added lines #L71 - L75 were not covered by tests
.value_or(0.0);
ego_data.earliest_stop_pose = motion_utils::calcLongitudinalOffsetPose(

Check warning on line 77 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L77

Added line #L77 was not covered by tests
ego_data.path.points, ego_data.pose.position, min_stop_distance);

make_ego_footprint_rtree(ego_data, params_);
const auto start_time = clock_->now();

Check warning on line 81 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L81

Added line #L81 was not covered by tests
const auto has_decided_to_stop =
(clock_->now() - prev_stop_decision_time_).seconds() < params_.decision_duration_buffer;
(start_time - prev_stop_decision_time_).seconds() < params_.decision_duration_buffer;

Check warning on line 83 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L83

Added line #L83 was not covered by tests
if (!has_decided_to_stop) current_stop_pose_.reset();
double hysteresis = has_decided_to_stop ? params_.hysteresis : 0.0;
const auto dynamic_obstacles =
Expand All @@ -80,13 +92,6 @@
const auto obstacle_forward_footprints =
make_forward_footprints(dynamic_obstacles, params_, hysteresis);
const auto footprints_duration_us = stopwatch.toc("footprints");
const auto min_stop_distance =
motion_utils::calcDecelDistWithJerkAndAccConstraints(
planner_data_->current_velocity->twist.linear.x, 0.0,
planner_data_->current_acceleration->accel.accel.linear.x,
planner_data_->max_stop_acceleration_threshold, -planner_data_->max_stop_jerk_threshold,
planner_data_->max_stop_jerk_threshold)
.value_or(0.0);
stopwatch.tic("collisions");
const auto collision =
find_earliest_collision(ego_data, dynamic_obstacles, obstacle_forward_footprints, debug_data_);
Expand All @@ -101,14 +106,13 @@
? motion_utils::calcLongitudinalOffsetPose(
ego_data.path.points, *collision,
-params_.stop_distance_buffer - params_.ego_longitudinal_offset)
: motion_utils::calcLongitudinalOffsetPose(
ego_data.path.points, ego_data.pose.position, min_stop_distance);
: ego_data.earliest_stop_pose;

Check warning on line 109 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L109

Added line #L109 was not covered by tests
if (stop_pose) {
const auto use_new_stop_pose = !has_decided_to_stop || motion_utils::calcSignedArcLength(
path->points, stop_pose->position,
current_stop_pose_->position) > 0.0;
if (use_new_stop_pose) current_stop_pose_ = *stop_pose;
prev_stop_decision_time_ = clock_->now();
prev_stop_decision_time_ = start_time;

Check warning on line 115 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

DynamicObstacleStopModule::modifyPathVelocity already has high cyclomatic complexity, and now it increases in Lines of Code from 70 to 72. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Check warning on line 115 in planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp

View check run for this annotation

Codecov / codecov/patch

planning/behavior_velocity_dynamic_obstacle_stop_module/src/scene_dynamic_obstacle_stop.cpp#L115

Added line #L115 was not covered by tests
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct PlannerParam
double ego_longitudinal_offset;
double ego_lateral_offset;
double minimum_object_distance_from_ego_path;
bool ignore_unavoidable_collisions;
};

struct EgoData
Expand All @@ -54,6 +55,7 @@ struct EgoData
geometry_msgs::msg::Pose pose;
tier4_autoware_utils::MultiPolygon2d path_footprints;
Rtree rtree;
std::optional<geometry_msgs::msg::Pose> earliest_stop_pose;
};

/// @brief debug data
Expand Down
Loading