diff --git a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.xml b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.xml
index 2d5177d4252d8..4e39c8e43d4ab 100644
--- a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.xml
+++ b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.xml
@@ -2,6 +2,9 @@
+
+
+
@@ -9,6 +12,21 @@
+
+
+
+
+
@@ -141,6 +161,9 @@
+
+
+
diff --git a/planning/.pages b/planning/.pages
index 7444815cdd28a..735e2b2c907c0 100644
--- a/planning/.pages
+++ b/planning/.pages
@@ -63,6 +63,9 @@ nav:
- 'Motion Velocity Planner':
- 'About Motion Velocity Planner': planning/motion_velocity_planner/autoware_motion_velocity_planner_node_universe/
- 'Available Modules':
+ - 'Obstacle Stop': planning/motion_velocity_planner/autoware_motion_velocity_obstacle_stop_module/
+ - 'Obstacle Slow Down': planning/motion_velocity_planner/autoware_motion_velocity_obstacle_slow_down_module/
+ - 'Obstacle Cruise': planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/
- 'Dynamic Obstacle Stop': planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/
- 'Out of Lane': planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/
- 'Obstacle Velocity Limiter': planning/motion_velocity_planner/autoware_motion_velocity_obstacle_velocity_limiter_module/
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp
index c7a103e0269ca..15fcc52f0fd24 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp
@@ -97,19 +97,21 @@ void DynamicObstacleStopModule::update_parameters(const std::vector & ego_trajectory_points,
+ [[maybe_unused]] const std::vector &
+ raw_trajectory_points,
+ const std::vector & smoothed_trajectory_points,
const std::shared_ptr planner_data)
{
VelocityPlanningResult result;
debug_data_.reset_data();
- if (ego_trajectory_points.size() < 2) return result;
+ if (smoothed_trajectory_points.size() < 2) return result;
autoware::universe_utils::StopWatch stopwatch;
stopwatch.tic();
stopwatch.tic("preprocessing");
dynamic_obstacle_stop::EgoData ego_data;
ego_data.pose = planner_data->current_odometry.pose.pose;
- ego_data.trajectory = ego_trajectory_points;
+ ego_data.trajectory = smoothed_trajectory_points;
autoware::motion_utils::removeOverlapPoints(ego_data.trajectory);
ego_data.first_trajectory_idx =
autoware::motion_utils::findNearestSegmentIndex(ego_data.trajectory, ego_data.pose.position);
@@ -164,7 +166,7 @@ VelocityPlanningResult DynamicObstacleStopModule::plan(
if (stop_pose) {
result.stop_points.push_back(stop_pose->position);
planning_factor_interface_->add(
- ego_trajectory_points, ego_data.pose, *stop_pose, PlanningFactor::STOP,
+ smoothed_trajectory_points, ego_data.pose, *stop_pose, PlanningFactor::STOP,
SafetyFactorArray{});
create_virtual_walls();
}
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp
index a678e7657a6c3..aca86a82798ab 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp
@@ -36,7 +36,8 @@ class DynamicObstacleStopModule : public PluginModuleInterface
void publish_planning_factor() override { planning_factor_interface_->publish(); };
void update_parameters(const std::vector & parameters) override;
VelocityPlanningResult plan(
- const std::vector & ego_trajectory_points,
+ const std::vector & raw_trajectory_points,
+ const std::vector & smoothed_trajectory_points,
const std::shared_ptr planner_data) override;
std::string get_module_name() const override { return module_name_; }
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp
index 0726fdba02de0..850255e0c5093 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.cpp
@@ -96,12 +96,12 @@ bool is_unavoidable(
};
std::vector filter_predicted_objects(
- const std::vector & objects, const EgoData & ego_data,
+ const std::vector> & objects, const EgoData & ego_data,
const PlannerParam & params, const double hysteresis)
{
std::vector filtered_objects;
for (const auto & object : objects) {
- const auto & predicted_object = object.predicted_object;
+ const auto & predicted_object = object->predicted_object;
const auto is_not_too_slow =
predicted_object.kinematics.initial_twist_with_covariance.twist.linear.x >=
params.minimum_object_velocity;
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.hpp
index 33abb19074099..77b3d2b1ead45 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.hpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/object_filtering.hpp
@@ -76,7 +76,7 @@ bool is_unavoidable(
/// @param hysteresis [m] extra distance threshold used for filtering
/// @return filtered predicted objects
std::vector filter_predicted_objects(
- const std::vector & objects, const EgoData & ego_data,
+ const std::vector> & objects, const EgoData & ego_data,
const PlannerParam & params, const double hysteresis);
} // namespace autoware::motion_velocity_planner::dynamic_obstacle_stop
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/types.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/types.hpp
index 8cf83f63f4d01..2e3af577a83f4 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/types.hpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/types.hpp
@@ -53,23 +53,23 @@ struct PlannerParam
struct EgoData
{
- TrajectoryPoints trajectory;
+ TrajectoryPoints trajectory{};
size_t first_trajectory_idx{};
- double longitudinal_offset_to_first_trajectory_idx; // [m]
- geometry_msgs::msg::Pose pose;
- autoware::universe_utils::MultiPolygon2d trajectory_footprints;
- Rtree rtree;
- std::optional earliest_stop_pose;
+ double longitudinal_offset_to_first_trajectory_idx{}; // [m]
+ geometry_msgs::msg::Pose pose{};
+ autoware::universe_utils::MultiPolygon2d trajectory_footprints{};
+ Rtree rtree{};
+ std::optional earliest_stop_pose{};
};
/// @brief debug data
struct DebugData
{
- autoware::universe_utils::MultiPolygon2d obstacle_footprints;
+ autoware::universe_utils::MultiPolygon2d obstacle_footprints{};
size_t prev_dynamic_obstacles_nb{};
- autoware::universe_utils::MultiPolygon2d ego_footprints;
+ autoware::universe_utils::MultiPolygon2d ego_footprints{};
size_t prev_ego_footprints_nb{};
- std::optional stop_pose;
+ std::optional stop_pose{};
size_t prev_collisions_nb{};
double z{};
void reset_data()
@@ -82,8 +82,8 @@ struct DebugData
struct Collision
{
- geometry_msgs::msg::Point point;
- std::string object_uuid;
+ geometry_msgs::msg::Point point{};
+ std::string object_uuid{};
};
} // namespace autoware::motion_velocity_planner::dynamic_obstacle_stop
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/test/test_object_filtering.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/test/test_object_filtering.cpp
index 419b5d9e46bd1..3ff4cf0c9972f 100644
--- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/test/test_object_filtering.cpp
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/test/test_object_filtering.cpp
@@ -205,7 +205,7 @@ TEST(TestObjectFiltering, isUnavoidable)
TEST(TestObjectFiltering, filterPredictedObjects)
{
using autoware::motion_velocity_planner::dynamic_obstacle_stop::filter_predicted_objects;
- std::vector objects;
+ std::vector> objects;
autoware::motion_velocity_planner::dynamic_obstacle_stop::EgoData ego_data;
autoware::motion_velocity_planner::dynamic_obstacle_stop::PlannerParam params;
double hysteresis{};
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/CMakeLists.txt b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/CMakeLists.txt
new file mode 100644
index 0000000000000..f51e026428aec
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.14)
+project(autoware_motion_velocity_obstacle_cruise_module)
+
+find_package(autoware_cmake REQUIRED)
+autoware_package()
+pluginlib_export_plugin_description_file(autoware_motion_velocity_planner_node_universe plugins.xml)
+
+ament_auto_add_library(${PROJECT_NAME} SHARED
+ DIRECTORY src
+)
+
+ament_auto_package(INSTALL_TO_SHARE config)
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/README.md b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/README.md
new file mode 100644
index 0000000000000..296bb6290e398
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/README.md
@@ -0,0 +1,118 @@
+# Obstacle Cruise
+
+## Role
+
+The `obstacle_cruise` module does the cruise planning against a dynamic obstacle in front of the ego.
+
+## Activation
+
+This module is activated if the launch parameter `launch_obstacle_cruise_module` is set to true.
+
+## Inner-workings / Algorithms
+
+### Obstacle Filtering
+
+The obstacles meeting the following condition are determined as obstacles for cruising.
+
+- The lateral distance from the object to the ego's trajectory is smaller than `obstacle_filtering.max_lat_margin`.
+
+- The object type is for cruising according to `obstacle_filtering.object_type.*`.
+- The object is not crossing the ego's trajectory (\*1).
+- If the object is inside the trajectory.
+ - The object type is for inside cruising according to `obstacle_filtering.object_type.inside.*`.
+ - The object velocity is larger than `obstacle_filtering.obstacle_velocity_threshold_from_cruise`.
+- If the object is outside the trajectory.
+ - The object type is for outside cruising according to `obstacle_filtering.object_type.outside.*`.
+ - The object velocity is larger than `obstacle_filtering.outside_obstacle.obstacle_velocity_threshold`.
+ - The highest confident predicted path collides with the ego's trajectory.
+ - Its collision's period is larger than `obstacle_filtering.outside_obstacle.ego_obstacle_overlap_time_threshold`.
+
+#### NOTE
+
+##### \*1: Crossing obstacles
+
+Crossing obstacle is the object whose orientation's yaw angle against the ego's trajectory is smaller than `obstacle_filtering.crossing_obstacle.obstacle_traj_angle_threshold`.
+
+##### Yield for vehicles that might cut in into the ego's lane
+
+It is also possible to yield (cruise) behind vehicles in neighbor lanes if said vehicles might cut in the ego vehicle's current lane.
+
+The obstacles meeting the following condition are determined as obstacles for yielding (cruising).
+
+- The object type is for cruising according to `obstacle_filtering.object_type.*` and it is moving with a speed greater than `obstacle_filtering.yield.stopped_obstacle_velocity_threshold`.
+- The object is not crossing the ego's trajectory (\*1).
+- There is another object of type `obstacle_filtering.object_type.*` stopped in front of the moving obstacle.
+- The lateral distance (using the ego's trajectory as reference) between both obstacles is less than `obstacle_filtering.yield.max_lat_dist_between_obstacles`
+- Both obstacles, moving and stopped, are within `obstacle_filtering.yield.lat_distance_threshold` and `obstacle_filtering.yield.lat_distance_threshold` + `obstacle_filtering.yield.max_lat_dist_between_obstacles` lateral distance from the ego's trajectory respectively.
+
+If the above conditions are met, the ego vehicle will cruise behind the moving obstacle, yielding to it so it can cut in into the ego's lane to avoid the stopped obstacle.
+
+### Cruise Planning
+
+The role of the cruise planning is keeping a safe distance with dynamic vehicle objects with smoothed velocity transition.
+This includes not only cruising a front vehicle, but also reacting a cut-in and cut-out vehicle.
+
+The safe distance is calculated dynamically based on the Responsibility-Sensitive Safety (RSS) by the following equation.
+
+$$
+d_{rss} = v_{ego} t_{idling} + \frac{1}{2} a_{ego} t_{idling}^2 + \frac{v_{ego}^2}{2 a_{ego}} - \frac{v_{obstacle}^2}{2 a_{obstacle}},
+$$
+
+assuming that $d_{rss}$ is the calculated safe distance, $t_{idling}$ is the idling time for the ego to detect the front vehicle's deceleration, $v_{ego}$ is the ego's current velocity, $v_{obstacle}$ is the front obstacle's current velocity, $a_{ego}$ is the ego's acceleration, and $a_{obstacle}$ is the obstacle's acceleration.
+These values are parameterized as follows. Other common values such as ego's minimum acceleration is defined in `common.param.yaml`.
+
+| Parameter | Type | Description |
+| ------------------------------------------ | ------ | ----------------------------------------------------------------------------- |
+| `cruise_planning.idling_time` | double | idling time for the ego to detect the front vehicle starting deceleration [s] |
+| `cruise_planning.min_ego_accel_for_rss` | double | ego's acceleration for RSS [m/ss] |
+| `cruise_planning.min_object_accel_for_rss` | double | front obstacle's acceleration for RSS [m/ss] |
+
+The detailed formulation is as follows.
+
+$$
+\begin{align}
+d_{error} & = d - d_{rss} \\
+d_{normalized} & = lpf(d_{error} / d_{obstacle}) \\
+d_{quad, normalized} & = sign(d_{normalized}) *d_{normalized}*d_{normalized} \\
+v_{pid} & = pid(d_{quad, normalized}) \\
+v_{add} & = v_{pid} > 0 ? v_{pid}* w_{acc} : v_{pid} \\
+v_{target} & = max(v_{ego} + v_{add}, v_{min, cruise})
+\end{align}
+$$
+
+| Variable | Description |
+| ----------------- | --------------------------------------- |
+| `d` | actual distance to obstacle |
+| `d_{rss}` | ideal distance to obstacle based on RSS |
+| `v_{min, cruise}` | `min_cruise_target_vel` |
+| `w_{acc}` | `output_ratio_during_accel` |
+| `lpf(val)` | apply low-pass filter to `val` |
+| `pid(val)` | apply pid to `val` |
+
+#### Algorithm selection for cruise planner
+
+Currently, only a PID-based planner is supported.
+Each planner will be explained in the following.
+
+| Parameter | Type | Description |
+| --------------------------- | ------ | ------------------------------------------------------------ |
+| `option.planning_algorithm` | string | cruise and stop planning algorithm, selected from "pid_base" |
+
+#### PID-based planner
+
+In order to keep the safe distance, the target velocity and acceleration is calculated and sent as an external velocity limit to the velocity smoothing package (`velocity_smoother` by default).
+The target velocity and acceleration is respectively calculated with the PID controller according to the error between the reference safe distance and the actual distance.
+
+#### Optimization-based planner
+
+under construction
+
+## Debugging
+
+### Obstacle for cruise
+
+Orange sphere which is an obstacle for cruise is visualized by `obstacles_to_cruise` in the `~/debug/marker` topic.
+
+Orange wall which means a safe distance to cruise if the ego's front meets the wall is visualized in the `~/debug/cruise/virtual_wall` topic.
+
+
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/config/obstacle_cruise.param.yaml b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/config/obstacle_cruise.param.yaml
new file mode 100644
index 0000000000000..214f7bb35a155
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/config/obstacle_cruise.param.yaml
@@ -0,0 +1,120 @@
+/**:
+ ros__parameters:
+ obstacle_cruise:
+ option:
+ planning_algorithm: "pid_base" # currently supported algorithm is "pid_base"
+
+ cruise_planning:
+ idling_time: 2.0 # idling time to detect front vehicle starting deceleration [s]
+ min_ego_accel_for_rss: -1.0 # ego's acceleration to calculate RSS distance [m/ss]
+ min_object_accel_for_rss: -1.0 # front obstacle's acceleration to calculate RSS distance [m/ss]
+ safe_distance_margin : 5.0 # This is also used as a stop margin [m]
+
+ pid_based_planner:
+ use_velocity_limit_based_planner: true
+ error_function_type: quadratic # choose from linear, quadratic
+
+ velocity_limit_based_planner:
+ # PID gains to keep safe distance with the front vehicle
+ kp: 10.0
+ ki: 0.0
+ kd: 2.0
+
+ output_ratio_during_accel: 0.6 # target acceleration is multiplied with this value while ego accelerates to catch up the front vehicle [-]
+ vel_to_acc_weight: 12.0 # target acceleration is calculated by (target_velocity - current_velocity) * vel_to_acc_weight [-]
+
+ enable_jerk_limit_to_output_acc: false
+
+ disable_target_acceleration: true
+
+ velocity_insertion_based_planner:
+ kp_acc: 6.0
+ ki_acc: 0.0
+ kd_acc: 2.0
+
+ kp_jerk: 20.0
+ ki_jerk: 0.0
+ kd_jerk: 0.0
+
+ output_acc_ratio_during_accel: 0.6 # target acceleration is multiplied with this value while ego accelerates to catch up the front vehicle [-]
+ output_jerk_ratio_during_accel: 1.0 # target acceleration is multiplied with this value while ego accelerates to catch up the front vehicle [-]
+
+ enable_jerk_limit_to_output_acc: true
+
+ min_accel_during_cruise: -2.0 # minimum acceleration during cruise to slow down [m/ss]
+ min_cruise_target_vel: 0.0 # minimum target velocity during slow down [m/s]
+ time_to_evaluate_rss: 0.0
+
+ lpf_normalized_error_cruise_dist_gain: 0.2
+
+ optimization_based_planner:
+ dense_resampling_time_interval: 0.2
+ sparse_resampling_time_interval: 2.0
+ dense_time_horizon: 5.0
+ max_time_horizon: 25.0
+ velocity_margin: 0.2 #[m/s]
+
+ # Parameters for safe distance
+ t_dangerous: 0.5
+
+ # For initial Motion
+ replan_vel_deviation: 5.0 # velocity deviation to replan initial velocity [m/s]
+ engage_velocity: 0.25 # engage velocity threshold [m/s] (if the trajectory velocity is higher than this value, use this velocity for engage vehicle speed)
+ engage_acceleration: 0.1 # engage acceleration [m/ss] (use this acceleration when engagement)
+ engage_exit_ratio: 0.5 # exit engage sequence to normal velocity planning when the velocity exceeds engage_exit_ratio x engage_velocity.
+ stop_dist_to_prohibit_engage: 0.5 # if the stop point is in this distance, the speed is set to 0 not to move the vehicle [m]
+
+ # Weights for optimization
+ max_s_weight: 100.0
+ max_v_weight: 1.0
+ over_s_safety_weight: 1000000.0
+ over_s_ideal_weight: 50.0
+ over_v_weight: 500000.0
+ over_a_weight: 5000.0
+ over_j_weight: 10000.0
+
+ obstacle_filtering:
+ object_type:
+ inside:
+ unknown: true
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: true
+ pedestrian: false
+
+ outside:
+ unknown: false
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: false
+ pedestrian: false
+
+ max_lat_margin: 1.0 # lateral margin between obstacle and trajectory band with ego's width
+
+ # if crossing vehicle is determined as target obstacles or not
+ crossing_obstacle:
+ obstacle_velocity_threshold : 1.0 # velocity threshold for crossing obstacle for cruise or stop [m/s]
+ obstacle_traj_angle_threshold : 0.523599 # [rad] = 70 [deg], yaw threshold of crossing obstacle against the nearest trajectory point for cruise or stop
+
+ outside_obstacle:
+ obstacle_velocity_threshold : 1.5 # minimum velocity threshold of obstacles outside the trajectory to cruise or stop [m/s]
+ ego_obstacle_overlap_time_threshold : 0.2 # time threshold to decide cut-in obstacle for cruise or stop [s]
+ max_prediction_time_for_collision_check : 10.0 # prediction time to check collision between obstacle and ego
+ max_lateral_time_margin: 5.0 # time threshold of lateral margin between obstacle and trajectory band with ego's width [s]
+ num_of_predicted_paths: 1 # number of the highest confidence predicted path to check collision between obstacle and ego
+ yield:
+ enable_yield: true
+ lat_distance_threshold: 5.0 # lateral margin between obstacle in neighbor lanes and trajectory band with ego's width for yielding
+ max_lat_dist_between_obstacles: 2.5 # lateral margin between moving obstacle in neighbor lanes and stopped obstacle in front of it
+ max_obstacles_collision_time: 10.0 # how far the blocking obstacle
+ stopped_obstacle_velocity_threshold: 0.5
+
+ # hysteresis for cruise and stop
+ obstacle_velocity_threshold_from_cruise : 3.0 # stop planning is executed to the obstacle whose velocity is less than this value [m/s]
+ obstacle_velocity_threshold_to_cruise : 3.5 # stop planning is executed to the obstacle whose velocity is less than this value [m/s]
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/docs/cruise_visualization.png b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/docs/cruise_visualization.png
new file mode 100644
index 0000000000000..acb094135e884
Binary files /dev/null and b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/docs/cruise_visualization.png differ
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/package.xml b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/package.xml
new file mode 100644
index 0000000000000..e0cbf2c193b7a
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/package.xml
@@ -0,0 +1,41 @@
+
+
+
+ autoware_motion_velocity_obstacle_cruise_module
+ 0.40.0
+ obstacle cruise feature in motion_velocity_planner
+
+ Takayuki Murooka
+ Yuki Takagi
+ Maxime Clement
+
+ Apache License 2.0
+
+ ament_cmake_auto
+ autoware_cmake
+ autoware_motion_utils
+ autoware_motion_velocity_planner_common_universe
+ autoware_osqp_interface
+ autoware_perception_msgs
+ autoware_planning_msgs
+ autoware_route_handler
+ autoware_signal_processing
+ autoware_universe_utils
+ autoware_vehicle_info_utils
+ geometry_msgs
+ libboost-dev
+ pluginlib
+ rclcpp
+ tf2
+ tier4_metric_msgs
+ tier4_planning_msgs
+ visualization_msgs
+
+ ament_cmake_ros
+ ament_lint_auto
+ autoware_lint_common
+
+
+ ament_cmake
+
+
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/plugins.xml b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/plugins.xml
new file mode 100644
index 0000000000000..d841b9beba5c9
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/plugins.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/cruise_planner_interface.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/cruise_planner_interface.hpp
new file mode 100644
index 0000000000000..63f979813e78f
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/cruise_planner_interface.hpp
@@ -0,0 +1,104 @@
+// Copyright 2025 TIER IV, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRUISE_PLANNER_INTERFACE_HPP_
+#define CRUISE_PLANNER_INTERFACE_HPP_
+
+#include "autoware/motion_velocity_planner_common_universe/planner_data.hpp"
+#include "parameters.hpp"
+#include "type_alias.hpp"
+#include "types.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace autoware::motion_velocity_planner
+{
+class CruisePlannerInterface
+{
+public:
+ CruisePlannerInterface(
+ rclcpp::Node & node, const CommonParam & common_param,
+ const CruisePlanningParam & cruise_planning_param)
+ {
+ clock_ = node.get_clock();
+ logger_ = node.get_logger();
+ common_param_ = common_param;
+ cruise_planning_param_ = cruise_planning_param;
+ }
+
+ virtual ~CruisePlannerInterface() = default;
+
+ virtual std::vector plan_cruise(
+ const std::shared_ptr planner_data,
+ const std::vector & stop_traj_points,
+ const std::vector & obstacles, std::shared_ptr debug_data_ptr,
+ std::unique_ptr &
+ planning_factor_interface,
+ std::optional & velocity_limit) = 0;
+
+ virtual void update_parameters(const std::vector & parameters) = 0;
+
+ virtual Float32MultiArrayStamped get_cruise_planning_debug_message(
+ [[maybe_unused]] const rclcpp::Time & current_time) const
+ {
+ return Float32MultiArrayStamped{};
+ }
+
+protected:
+ rclcpp::Clock::SharedPtr clock_{};
+ rclcpp::Logger logger_{rclcpp::get_logger("")};
+ CommonParam common_param_;
+ CruisePlanningParam cruise_planning_param_;
+
+ static double calc_distance_to_collisionPoint(
+ const std::vector & traj_points,
+ const std::shared_ptr planner_data,
+ const geometry_msgs::msg::Point & collision_point)
+ {
+ const double offset = planner_data->is_driving_forward
+ ? std::abs(planner_data->vehicle_info_.max_longitudinal_offset_m)
+ : std::abs(planner_data->vehicle_info_.min_longitudinal_offset_m);
+
+ const size_t ego_segment_idx =
+ planner_data->find_segment_index(traj_points, planner_data->current_odometry.pose.pose);
+
+ const size_t collision_segment_idx =
+ autoware::motion_utils::findNearestSegmentIndex(traj_points, collision_point);
+
+ const auto dist_to_collision_point = autoware::motion_utils::calcSignedArcLength(
+ traj_points, planner_data->current_odometry.pose.pose.position, ego_segment_idx,
+ collision_point, collision_segment_idx);
+
+ return dist_to_collision_point - offset;
+ }
+
+ double calc_rss_distance(
+ const double ego_vel, const double obstacle_vel, const double margin = 0.0) const
+ {
+ const double rss_dist_with_margin =
+ ego_vel * cruise_planning_param_.idling_time +
+ std::pow(ego_vel, 2) * 0.5 / std::abs(cruise_planning_param_.min_ego_accel_for_rss) -
+ std::pow(obstacle_vel, 2) * 0.5 / std::abs(cruise_planning_param_.min_object_accel_for_rss) +
+ margin;
+ return rss_dist_with_margin;
+ }
+};
+} // namespace autoware::motion_velocity_planner
+
+#endif // CRUISE_PLANNER_INTERFACE_HPP_
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/metrics_manager.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/metrics_manager.hpp
new file mode 100644
index 0000000000000..11554121a0882
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/metrics_manager.hpp
@@ -0,0 +1,60 @@
+// Copyright 2025 TIER IV, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef METRICS_MANAGER_HPP_
+#define METRICS_MANAGER_HPP_
+
+#include "type_alias.hpp"
+#include "types.hpp"
+
+#include
+#include
+#include
+
+namespace autoware::motion_velocity_planner
+{
+class MetricsManager
+{
+public:
+ void init() { metrics_.clear(); }
+
+ void calculate_metrics(const std::string & module_name, const std::string & reason)
+ {
+ // Create status
+ {
+ // Decision
+ Metric decision_metric;
+ decision_metric.name = module_name + "/decision";
+ decision_metric.unit = "string";
+ decision_metric.value = reason;
+ metrics_.push_back(decision_metric);
+ }
+ }
+
+ MetricArray create_metric_array(const rclcpp::Time & current_time)
+ {
+ MetricArray metrics_msg;
+ metrics_msg.stamp = current_time;
+ metrics_msg.metric_array.insert(
+ metrics_msg.metric_array.end(), metrics_.begin(), metrics_.end());
+ return metrics_msg;
+ }
+
+private:
+ std::vector metrics_;
+};
+
+} // namespace autoware::motion_velocity_planner
+
+#endif // METRICS_MANAGER_HPP_
diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/obstacle_cruise_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/obstacle_cruise_module.cpp
new file mode 100644
index 0000000000000..c1d02842de1bb
--- /dev/null
+++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_cruise_module/src/obstacle_cruise_module.cpp
@@ -0,0 +1,826 @@
+// Copyright 2025 TIER IV, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "obstacle_cruise_module.hpp"
+
+#include "autoware/universe_utils/ros/uuid_helper.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include