diff --git a/launch/tier4_planning_launch/config/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/obstacle_cruise_planner.param.yaml b/launch/tier4_planning_launch/config/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/obstacle_cruise_planner.param.yaml
new file mode 100644
index 0000000000000..32af994e49938
--- /dev/null
+++ b/launch/tier4_planning_launch/config/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/obstacle_cruise_planner.param.yaml
@@ -0,0 +1,123 @@
+/**:
+ ros__parameters:
+ common:
+ planning_algorithm: "pid_base" # currently supported algorithm is "pid_base"
+
+ is_showing_debug_info: true
+
+ # longitudinal info
+ idling_time: 4.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 : 6.0 # This is also used as a stop margin [m]
+ min_strong_accel: -3.0 # obstacle stop requiring deceleration less than this value will be ignored [m/ss]
+
+ lpf_gain_for_accel: 0.2 # gain of low pass filter for ego acceleration [-]
+
+ nearest_dist_deviation_threshold: 3.0 # [m] for finding nearest index
+ nearest_yaw_deviation_threshold: 1.57 # [rad] for finding nearest index
+ min_behavior_stop_margin: 3.0 # [m]
+
+ cruise_obstacle_type:
+ unknown: true
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: false
+ pedestrian: false
+
+ stop_obstacle_type:
+ unknown: true
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: true
+ pedestrian: true
+
+ obstacle_filtering:
+ rough_detection_area_expand_width : 5.0 # rough lateral margin for rough detection area expansion [m]
+ detection_area_expand_width : 0.0 # lateral margin for precise detection area expansion
+ decimate_trajectory_step_length : 2.0 # longitudinal step length to calculate trajectory polygon for collision checking
+
+ # if crossing vehicle is decided as target obstacles or not
+ crossing_obstacle_velocity_threshold : 3.0 # velocity threshold for crossing obstacle for cruise or stop [m/s]
+ crossing_obstacle_traj_angle_threshold : 1.22 # [rad] = 70 [deg], yaw threshold of crossing obstacle against the nearest trajectory point for cruise or stop
+ collision_time_margin : 8.0 # time threshold of collision between obstacle adn ego for cruise or stop [s]
+
+ ego_obstacle_overlap_time_threshold : 1.0 # time threshold to decide cut-in obstacle for cruise or stop [s]
+ max_prediction_time_for_collision_check : 20.0 # prediction time to check collision between obstacle and ego
+
+ ignored_outside_obstacle_type:
+ unknown: false
+ car: false
+ truck: false
+ bus: false
+ trailer: false
+ motorcycle: false
+ bicycle: true
+ pedestrian: true
+
+ pid_based_planner:
+ # use_predicted_obstacle_pose: false
+
+ # PID gains to keep safe distance with the front vehicle
+ kp: 0.6
+ ki: 0.0
+ kd: 0.5
+
+ min_accel_during_cruise: -2.0 # minimum acceleration during cruise to slow down [m/ss]
+
+ output_ratio_during_accel: 2.5 # target acceleration is multiplied with this value while ego accelerates to catch up the front vehicle [-]
+ vel_to_acc_weight: 8.0 # target acceleration is calculated by (target_velocity - current_velocity) * vel_to_acc_weight [-]
+
+ min_cruise_target_vel: 0.0 # minimum target velocity during slow down [m/s]
+
+ obstacle_velocity_threshold_from_cruise_to_stop : 3.0 # stop planning is executed to the obstacle whose velocity is less than this value [m/s]
+
+ optimization_based_planner:
+ limit_min_accel: -3.0
+ resampling_s_interval: 2.0
+ dense_resampling_time_interval: 0.1
+ sparse_resampling_time_interval: 1.0
+ dense_time_horizon: 5.0
+ max_time_horizon: 25.0
+ max_trajectory_length: 200.0
+ velocity_margin: 0.1 #[m/s]
+
+ # Parameters for safe distance
+ safe_distance_margin: 5.0
+ t_dangerous: 0.5
+
+ # Parameters for collision detection
+ collision_time_threshold: 10.0
+ object_zero_velocity_threshold: 3.0 #[m/s]
+ object_low_velocity_threshold: 3.0 #[m/s]
+ external_velocity_limit: 20.0 #[m/s]
+ delta_yaw_threshold_of_object_and_ego: 90.0 # [deg]
+ delta_yaw_threshold_of_nearest_index: 60.0 # [deg]
+ collision_duration_threshold_of_object_and_ego: 1.0 # [s]
+
+ # Switch for each functions
+ enable_adaptive_cruise: true
+ use_object_acceleration: false
+ use_hd_map: true
+
+ # 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
diff --git a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
index 89d04bc5b3a00..0aad10cb6812c 100644
--- a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
+++ b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
@@ -21,6 +21,7 @@
from launch.actions import OpaqueFunction
from launch.actions import SetLaunchConfiguration
from launch.conditions import IfCondition
+from launch.conditions import LaunchConfigurationEquals
from launch.conditions import UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import ComposableNodeContainer
@@ -172,6 +173,52 @@ def launch_setup(context, *args, **kwargs):
extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
)
+ # obstacle cruise planner
+ obstacle_cruise_planner_param_path = os.path.join(
+ get_package_share_directory("tier4_planning_launch"),
+ "config",
+ "scenario_planning",
+ "lane_driving",
+ "motion_planning",
+ "obstacle_cruise_planner",
+ "obstacle_cruise_planner.param.yaml",
+ )
+ with open(obstacle_cruise_planner_param_path, "r") as f:
+ obstacle_cruise_planner_param = yaml.safe_load(f)["/**"]["ros__parameters"]
+ obstacle_cruise_planner_component = ComposableNode(
+ package="obstacle_cruise_planner",
+ plugin="motion_planning::ObstacleCruisePlannerNode",
+ name="obstacle_cruise_planner",
+ namespace="",
+ remappings=[
+ ("~/input/trajectory", "obstacle_avoidance_planner/trajectory"),
+ ("~/input/odometry", "/localization/kinematic_state"),
+ ("~/input/objects", "/perception/object_recognition/objects"),
+ ("~/output/trajectory", "/planning/scenario_planning/lane_driving/trajectory"),
+ ("~/output/velocity_limit", "/planning/scenario_planning/max_velocity_candidates"),
+ ("~/output/clear_velocity_limit", "/planning/scenario_planning/clear_velocity_limit"),
+ ("~/output/stop_reasons", "/planning/scenario_planning/status/stop_reasons"),
+ ],
+ parameters=[
+ common_param,
+ obstacle_cruise_planner_param,
+ ],
+ extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
+ )
+
+ obstacle_cruise_planner_relay_component = ComposableNode(
+ package="topic_tools",
+ plugin="topic_tools::RelayNode",
+ name="obstacle_cruise_planner_relay",
+ namespace="",
+ parameters=[
+ {"input_topic": "obstacle_avoidance_planner/trajectory"},
+ {"output_topic": "/planning/scenario_planning/lane_driving/trajectory"},
+ {"type": "autoware_auto_planning_msgs/msg/Trajectory"},
+ ],
+ extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
+ )
+
container = ComposableNodeContainer(
name="motion_planning_container",
namespace="",
@@ -179,18 +226,42 @@ def launch_setup(context, *args, **kwargs):
executable=LaunchConfiguration("container_executable"),
composable_node_descriptions=[
obstacle_avoidance_planner_component,
- obstacle_stop_planner_component,
],
)
+ obstacle_stop_planner_loader = LoadComposableNodes(
+ composable_node_descriptions=[obstacle_stop_planner_component],
+ target_container=container,
+ condition=LaunchConfigurationEquals("cruise_planner", "obstacle_stop_planner"),
+ )
+
+ obstacle_cruise_planner_loader = LoadComposableNodes(
+ composable_node_descriptions=[obstacle_cruise_planner_component],
+ target_container=container,
+ condition=LaunchConfigurationEquals("cruise_planner", "obstacle_cruise_planner"),
+ )
+
+ obstacle_cruise_planner_relay_loader = LoadComposableNodes(
+ composable_node_descriptions=[obstacle_cruise_planner_relay_component],
+ target_container=container,
+ condition=LaunchConfigurationEquals("cruise_planner", "none"),
+ )
+
surround_obstacle_checker_loader = LoadComposableNodes(
composable_node_descriptions=[surround_obstacle_checker_component],
target_container=container,
condition=IfCondition(LaunchConfiguration("use_surround_obstacle_check")),
)
- group = GroupAction([container, surround_obstacle_checker_loader])
-
+ group = GroupAction(
+ [
+ container,
+ obstacle_stop_planner_loader,
+ obstacle_cruise_planner_loader,
+ obstacle_cruise_planner_relay_loader,
+ surround_obstacle_checker_loader,
+ ]
+ )
return [group]
@@ -221,6 +292,9 @@ def add_launch_arg(name: str, default_value=None, description=None):
# surround obstacle checker
add_launch_arg("use_surround_obstacle_check", "true", "launch surround_obstacle_checker or not")
+ add_launch_arg(
+ "cruise_planner", "obstacle_stop_planner", "cruise planner type"
+ ) # select from "obstacle_stop_planner", "obstacle_cruise_planner", "none"
add_launch_arg("use_intra_process", "false", "use ROS2 component container communication")
add_launch_arg("use_multithread", "false", "use multithread")
diff --git a/planning/obstacle_cruise_planner/CMakeLists.txt b/planning/obstacle_cruise_planner/CMakeLists.txt
new file mode 100644
index 0000000000000..7ba8bd9c000ed
--- /dev/null
+++ b/planning/obstacle_cruise_planner/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.14)
+project(obstacle_cruise_planner)
+
+find_package(autoware_cmake REQUIRED)
+autoware_package()
+
+find_package(Eigen3 REQUIRED)
+
+ament_auto_add_library(obstacle_cruise_planner_core SHARED
+ src/node.cpp
+ src/utils.cpp
+ src/polygon_utils.cpp
+ src/optimization_based_planner/resample.cpp
+ src/optimization_based_planner/box2d.cpp
+ src/optimization_based_planner/velocity_optimizer.cpp
+ src/optimization_based_planner/optimization_based_planner.cpp
+ src/pid_based_planner/pid_based_planner.cpp
+)
+
+rclcpp_components_register_node(obstacle_cruise_planner_core
+ PLUGIN "motion_planning::ObstacleCruisePlannerNode"
+ EXECUTABLE obstacle_cruise_planner
+)
+
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ ament_lint_auto_find_test_dependencies()
+endif()
+
+ament_auto_package(
+ INSTALL_TO_SHARE
+ launch
+ config
+)
+
+install(PROGRAMS
+ scripts/trajectory_visualizer.py
+ DESTINATION lib/${PROJECT_NAME}
+)
diff --git a/planning/obstacle_cruise_planner/config/obstacle_cruise_planner.param.yaml b/planning/obstacle_cruise_planner/config/obstacle_cruise_planner.param.yaml
new file mode 100644
index 0000000000000..32af994e49938
--- /dev/null
+++ b/planning/obstacle_cruise_planner/config/obstacle_cruise_planner.param.yaml
@@ -0,0 +1,123 @@
+/**:
+ ros__parameters:
+ common:
+ planning_algorithm: "pid_base" # currently supported algorithm is "pid_base"
+
+ is_showing_debug_info: true
+
+ # longitudinal info
+ idling_time: 4.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 : 6.0 # This is also used as a stop margin [m]
+ min_strong_accel: -3.0 # obstacle stop requiring deceleration less than this value will be ignored [m/ss]
+
+ lpf_gain_for_accel: 0.2 # gain of low pass filter for ego acceleration [-]
+
+ nearest_dist_deviation_threshold: 3.0 # [m] for finding nearest index
+ nearest_yaw_deviation_threshold: 1.57 # [rad] for finding nearest index
+ min_behavior_stop_margin: 3.0 # [m]
+
+ cruise_obstacle_type:
+ unknown: true
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: false
+ pedestrian: false
+
+ stop_obstacle_type:
+ unknown: true
+ car: true
+ truck: true
+ bus: true
+ trailer: true
+ motorcycle: true
+ bicycle: true
+ pedestrian: true
+
+ obstacle_filtering:
+ rough_detection_area_expand_width : 5.0 # rough lateral margin for rough detection area expansion [m]
+ detection_area_expand_width : 0.0 # lateral margin for precise detection area expansion
+ decimate_trajectory_step_length : 2.0 # longitudinal step length to calculate trajectory polygon for collision checking
+
+ # if crossing vehicle is decided as target obstacles or not
+ crossing_obstacle_velocity_threshold : 3.0 # velocity threshold for crossing obstacle for cruise or stop [m/s]
+ crossing_obstacle_traj_angle_threshold : 1.22 # [rad] = 70 [deg], yaw threshold of crossing obstacle against the nearest trajectory point for cruise or stop
+ collision_time_margin : 8.0 # time threshold of collision between obstacle adn ego for cruise or stop [s]
+
+ ego_obstacle_overlap_time_threshold : 1.0 # time threshold to decide cut-in obstacle for cruise or stop [s]
+ max_prediction_time_for_collision_check : 20.0 # prediction time to check collision between obstacle and ego
+
+ ignored_outside_obstacle_type:
+ unknown: false
+ car: false
+ truck: false
+ bus: false
+ trailer: false
+ motorcycle: false
+ bicycle: true
+ pedestrian: true
+
+ pid_based_planner:
+ # use_predicted_obstacle_pose: false
+
+ # PID gains to keep safe distance with the front vehicle
+ kp: 0.6
+ ki: 0.0
+ kd: 0.5
+
+ min_accel_during_cruise: -2.0 # minimum acceleration during cruise to slow down [m/ss]
+
+ output_ratio_during_accel: 2.5 # target acceleration is multiplied with this value while ego accelerates to catch up the front vehicle [-]
+ vel_to_acc_weight: 8.0 # target acceleration is calculated by (target_velocity - current_velocity) * vel_to_acc_weight [-]
+
+ min_cruise_target_vel: 0.0 # minimum target velocity during slow down [m/s]
+
+ obstacle_velocity_threshold_from_cruise_to_stop : 3.0 # stop planning is executed to the obstacle whose velocity is less than this value [m/s]
+
+ optimization_based_planner:
+ limit_min_accel: -3.0
+ resampling_s_interval: 2.0
+ dense_resampling_time_interval: 0.1
+ sparse_resampling_time_interval: 1.0
+ dense_time_horizon: 5.0
+ max_time_horizon: 25.0
+ max_trajectory_length: 200.0
+ velocity_margin: 0.1 #[m/s]
+
+ # Parameters for safe distance
+ safe_distance_margin: 5.0
+ t_dangerous: 0.5
+
+ # Parameters for collision detection
+ collision_time_threshold: 10.0
+ object_zero_velocity_threshold: 3.0 #[m/s]
+ object_low_velocity_threshold: 3.0 #[m/s]
+ external_velocity_limit: 20.0 #[m/s]
+ delta_yaw_threshold_of_object_and_ego: 90.0 # [deg]
+ delta_yaw_threshold_of_nearest_index: 60.0 # [deg]
+ collision_duration_threshold_of_object_and_ego: 1.0 # [s]
+
+ # Switch for each functions
+ enable_adaptive_cruise: true
+ use_object_acceleration: false
+ use_hd_map: true
+
+ # 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
diff --git a/planning/obstacle_cruise_planner/config/plot_juggler_obstacle_velocity_planner.xml b/planning/obstacle_cruise_planner/config/plot_juggler_obstacle_velocity_planner.xml
new file mode 100644
index 0000000000000..634268b93f2de
--- /dev/null
+++ b/planning/obstacle_cruise_planner/config/plot_juggler_obstacle_velocity_planner.xml
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/planning/obstacle_cruise_planner/image/collision_point.png b/planning/obstacle_cruise_planner/image/collision_point.png
new file mode 100644
index 0000000000000..29a4f913891b3
Binary files /dev/null and b/planning/obstacle_cruise_planner/image/collision_point.png differ
diff --git a/planning/obstacle_cruise_planner/image/detection_area.png b/planning/obstacle_cruise_planner/image/detection_area.png
new file mode 100644
index 0000000000000..6e1a831979fc0
Binary files /dev/null and b/planning/obstacle_cruise_planner/image/detection_area.png differ
diff --git a/planning/obstacle_cruise_planner/image/obstacle_to_cruise.png b/planning/obstacle_cruise_planner/image/obstacle_to_cruise.png
new file mode 100644
index 0000000000000..c5f56f59a6d7b
Binary files /dev/null and b/planning/obstacle_cruise_planner/image/obstacle_to_cruise.png differ
diff --git a/planning/obstacle_cruise_planner/image/obstacle_to_stop.png b/planning/obstacle_cruise_planner/image/obstacle_to_stop.png
new file mode 100644
index 0000000000000..aee61797a6d6c
Binary files /dev/null and b/planning/obstacle_cruise_planner/image/obstacle_to_stop.png differ
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/common_structs.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/common_structs.hpp
new file mode 100644
index 0000000000000..675b708b3914b
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/common_structs.hpp
@@ -0,0 +1,120 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__COMMON_STRUCTS_HPP_
+#define OBSTACLE_CRUISE_PLANNER__COMMON_STRUCTS_HPP_
+
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+
+#include
+
+#include "autoware_auto_perception_msgs/msg/predicted_objects.hpp"
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+#include "visualization_msgs/msg/marker_array.hpp"
+
+#include
+
+#include
+
+using autoware_auto_perception_msgs::msg::ObjectClassification;
+using autoware_auto_perception_msgs::msg::PredictedObject;
+using autoware_auto_perception_msgs::msg::PredictedPath;
+using autoware_auto_perception_msgs::msg::Shape;
+
+struct TargetObstacle
+{
+ TargetObstacle(
+ const rclcpp::Time & arg_time_stamp, const PredictedObject & object,
+ const double aligned_velocity, const geometry_msgs::msg::Point & arg_collision_point)
+ {
+ time_stamp = arg_time_stamp;
+ orientation_reliable = true;
+ pose = object.kinematics.initial_pose_with_covariance.pose;
+ velocity_reliable = true;
+ velocity = aligned_velocity;
+ is_classified = true;
+ classification = object.classification.at(0);
+ shape = object.shape;
+
+ predicted_paths.clear();
+ for (const auto & path : object.kinematics.predicted_paths) {
+ predicted_paths.push_back(path);
+ }
+
+ collision_point = arg_collision_point;
+ }
+
+ rclcpp::Time time_stamp;
+ bool orientation_reliable;
+ geometry_msgs::msg::Pose pose;
+ bool velocity_reliable;
+ float velocity;
+ bool is_classified;
+ ObjectClassification classification;
+ Shape shape;
+ std::vector predicted_paths;
+ geometry_msgs::msg::Point collision_point;
+};
+
+struct ObstacleCruisePlannerData
+{
+ rclcpp::Time current_time;
+ autoware_auto_planning_msgs::msg::Trajectory traj;
+ geometry_msgs::msg::Pose current_pose;
+ double current_vel;
+ double current_acc;
+ std::vector target_obstacles;
+};
+
+struct LongitudinalInfo
+{
+ LongitudinalInfo(
+ const double arg_max_accel, const double arg_min_accel, const double arg_max_jerk,
+ const double arg_min_jerk, const double arg_min_strong_accel, const double arg_idling_time,
+ const double arg_min_ego_accel_for_rss, const double arg_min_object_accel_for_rss,
+ const double arg_safe_distance_margin)
+ : max_accel(arg_max_accel),
+ min_accel(arg_min_accel),
+ max_jerk(arg_max_jerk),
+ min_jerk(arg_min_jerk),
+ min_strong_accel(arg_min_strong_accel),
+ idling_time(arg_idling_time),
+ min_ego_accel_for_rss(arg_min_ego_accel_for_rss),
+ min_object_accel_for_rss(arg_min_object_accel_for_rss),
+ safe_distance_margin(arg_safe_distance_margin)
+ {
+ }
+ double max_accel;
+ double min_accel;
+ double max_jerk;
+ double min_jerk;
+ double min_strong_accel;
+ double idling_time;
+ double min_ego_accel_for_rss;
+ double min_object_accel_for_rss;
+ double safe_distance_margin;
+};
+
+struct DebugData
+{
+ std::vector intentionally_ignored_obstacles;
+ std::vector obstacles_to_stop;
+ std::vector obstacles_to_cruise;
+ visualization_msgs::msg::MarkerArray stop_wall_marker;
+ visualization_msgs::msg::MarkerArray cruise_wall_marker;
+ std::vector detection_polygons;
+ std::vector collision_points;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__COMMON_STRUCTS_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/node.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/node.hpp
new file mode 100644
index 0000000000000..3b9db69162d21
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/node.hpp
@@ -0,0 +1,165 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__NODE_HPP_
+#define OBSTACLE_CRUISE_PLANNER__NODE_HPP_
+
+#include "obstacle_cruise_planner/common_structs.hpp"
+#include "obstacle_cruise_planner/optimization_based_planner/optimization_based_planner.hpp"
+#include "obstacle_cruise_planner/pid_based_planner/pid_based_planner.hpp"
+#include "signal_processing/lowpass_filter_1d.hpp"
+#include "tier4_autoware_utils/system/stop_watch.hpp"
+
+#include
+
+#include "autoware_auto_perception_msgs/msg/predicted_object.hpp"
+#include "autoware_auto_perception_msgs/msg/predicted_objects.hpp"
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+#include "geometry_msgs/msg/transform_stamped.hpp"
+#include "geometry_msgs/msg/twist_stamped.hpp"
+#include "nav_msgs/msg/odometry.hpp"
+#include "tier4_debug_msgs/msg/float32_stamped.hpp"
+#include "tier4_planning_msgs/msg/velocity_limit.hpp"
+#include "tier4_planning_msgs/msg/velocity_limit_clear_command.hpp"
+#include "visualization_msgs/msg/marker_array.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+
+using autoware_auto_perception_msgs::msg::ObjectClassification;
+using autoware_auto_perception_msgs::msg::PredictedObject;
+using autoware_auto_perception_msgs::msg::PredictedObjects;
+using autoware_auto_perception_msgs::msg::PredictedPath;
+using autoware_auto_planning_msgs::msg::Trajectory;
+using autoware_auto_planning_msgs::msg::TrajectoryPoint;
+using nav_msgs::msg::Odometry;
+using tier4_debug_msgs::msg::Float32Stamped;
+using tier4_planning_msgs::msg::StopReasonArray;
+using tier4_planning_msgs::msg::VelocityLimit;
+using tier4_planning_msgs::msg::VelocityLimitClearCommand;
+using vehicle_info_util::VehicleInfo;
+
+namespace motion_planning
+{
+class ObstacleCruisePlannerNode : public rclcpp::Node
+{
+public:
+ explicit ObstacleCruisePlannerNode(const rclcpp::NodeOptions & node_options);
+
+private:
+ // callback functions
+ rcl_interfaces::msg::SetParametersResult onParam(
+ const std::vector & parameters);
+ void onObjects(const PredictedObjects::ConstSharedPtr msg);
+ void onOdometry(const Odometry::ConstSharedPtr);
+ void onTrajectory(const Trajectory::ConstSharedPtr msg);
+ void onSmoothedTrajectory(const Trajectory::ConstSharedPtr msg);
+
+ // member Functions
+ ObstacleCruisePlannerData createPlannerData(
+ const Trajectory & trajectory, const geometry_msgs::msg::Pose & current_pose,
+ DebugData & debug_data);
+ double calcCurrentAccel() const;
+ std::vector filterObstacles(
+ const PredictedObjects & predicted_objects, const Trajectory & traj,
+ const geometry_msgs::msg::Pose & current_pose, const double current_vel,
+ DebugData & debug_data);
+ geometry_msgs::msg::Point calcNearestCollisionPoint(
+ const size_t & first_within_idx,
+ const std::vector & collision_points,
+ const Trajectory & decimated_traj);
+ double calcCollisionTimeMargin(
+ const geometry_msgs::msg::Pose & current_pose, const double current_vel,
+ const geometry_msgs::msg::Point & nearest_collision_point,
+ const PredictedObject & predicted_object, const size_t first_within_idx,
+ const Trajectory & decimated_traj,
+ const std::vector & decimated_traj_polygons);
+ void publishVelocityLimit(const boost::optional & vel_limit);
+ void publishDebugData(const DebugData & debug_data) const;
+ void publishCalculationTime(const double calculation_time) const;
+
+ bool is_showing_debug_info_;
+ double min_behavior_stop_margin_;
+ double nearest_dist_deviation_threshold_;
+ double nearest_yaw_deviation_threshold_;
+
+ // parameter callback result
+ OnSetParametersCallbackHandle::SharedPtr set_param_res_;
+
+ // publisher
+ rclcpp::Publisher::SharedPtr trajectory_pub_;
+ rclcpp::Publisher::SharedPtr vel_limit_pub_;
+ rclcpp::Publisher::SharedPtr clear_vel_limit_pub_;
+ rclcpp::Publisher::SharedPtr debug_marker_pub_;
+ rclcpp::Publisher::SharedPtr debug_cruise_wall_marker_pub_;
+ rclcpp::Publisher::SharedPtr debug_stop_wall_marker_pub_;
+ rclcpp::Publisher::SharedPtr debug_calculation_time_pub_;
+
+ // subscriber
+ rclcpp::Subscription::SharedPtr trajectory_sub_;
+ rclcpp::Subscription::SharedPtr smoothed_trajectory_sub_;
+ rclcpp::Subscription::SharedPtr objects_sub_;
+ rclcpp::Subscription::SharedPtr odom_sub_;
+
+ // self pose listener
+ tier4_autoware_utils::SelfPoseListener self_pose_listener_;
+
+ // data for callback functions
+ PredictedObjects::ConstSharedPtr in_objects_ptr_;
+ geometry_msgs::msg::TwistStamped::SharedPtr current_twist_ptr_;
+ geometry_msgs::msg::TwistStamped::SharedPtr prev_twist_ptr_;
+
+ // low pass filter of acceleration
+ std::shared_ptr lpf_acc_ptr_;
+
+ // Vehicle Parameters
+ VehicleInfo vehicle_info_;
+
+ // planning algorithm
+ enum class PlanningAlgorithm { OPTIMIZATION_BASE, PID_BASE, INVALID };
+ PlanningAlgorithm getPlanningAlgorithmType(const std::string & param) const;
+ PlanningAlgorithm planning_algorithm_;
+
+ // stop watch
+ mutable tier4_autoware_utils::StopWatch<
+ std::chrono::milliseconds, std::chrono::microseconds, std::chrono::steady_clock>
+ stop_watch_;
+
+ // planner
+ std::unique_ptr planner_ptr_;
+
+ // obstacle filtering parameter
+ struct ObstacleFilteringParam
+ {
+ double rough_detection_area_expand_width;
+ double detection_area_expand_width;
+ double decimate_trajectory_step_length;
+ double crossing_obstacle_velocity_threshold;
+ double collision_time_margin;
+ double ego_obstacle_overlap_time_threshold;
+ double max_prediction_time_for_collision_check;
+ double crossing_obstacle_traj_angle_threshold;
+ std::vector ignored_outside_obstacle_types;
+ };
+ ObstacleFilteringParam obstacle_filtering_param_;
+
+ bool need_to_clear_vel_limit_{false};
+};
+} // namespace motion_planning
+
+#endif // OBSTACLE_CRUISE_PLANNER__NODE_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/box2d.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/box2d.hpp
new file mode 100644
index 0000000000000..84349eca57dec
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/box2d.hpp
@@ -0,0 +1,135 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__BOX2D_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__BOX2D_HPP_
+
+#include
+#include
+
+#include
+#include
+#include
+
+class Box2d
+{
+public:
+ Box2d(const geometry_msgs::msg::Pose & center_pose, const double length, const double width);
+
+ bool hasOverlap(const Box2d & box) const;
+
+ void initCorners();
+
+ /**
+ * @brief Getter of the center of the box
+ * @return The center of the box
+ */
+ const geometry_msgs::msg::Point & center() const { return center_; }
+
+ /**
+ * @brief Getter of the x-coordinate of the center of the box
+ * @return The x-coordinate of the center of the box
+ */
+ double getCenterX() const { return center_.x; }
+
+ /**
+ * @brief Getter of the y-coordinate of the center of the box
+ * @return The y-coordinate of the center of the box
+ */
+ double getCenterY() const { return center_.y; }
+
+ /**
+ * @brief Getter of the length
+ * @return The length of the heading-axis
+ */
+ double length() const { return length_; }
+
+ /**
+ * @brief Getter of the width
+ * @return The width of the box taken perpendicularly to the heading
+ */
+ double width() const { return width_; }
+
+ /**
+ * @brief Getter of half the length
+ * @return Half the length of the heading-axis
+ */
+ double getHalfLength() const { return half_length_; }
+
+ /**
+ * @brief Getter of half the width
+ * @return Half the width of the box taken perpendicularly to the heading
+ */
+ double getHalfWidth() const { return half_width_; }
+
+ /**
+ * @brief Getter of the heading
+ * @return The counter-clockwise angle between the x-axis and the heading-axis
+ */
+ double heading() const { return heading_; }
+
+ /**
+ * @brief Getter of the cosine of the heading
+ * @return The cosine of the heading
+ */
+ double getCosHeading() const { return cos_heading_; }
+
+ /**
+ * @brief Getter of the sine of the heading
+ * @return The sine of the heading
+ */
+ double getSinHeading() const { return sin_heading_; }
+
+ /**
+ * @brief Getter of the area of the box
+ * @return The product of its length and width
+ */
+ double area() const { return length_ * width_; }
+
+ /**
+ * @brief Getter of the size of the diagonal of the box
+ * @return The diagonal size of the box
+ */
+ double diagonal() const { return std::hypot(length_, width_); }
+
+ /**
+ * @brief Getter of the corners of the box
+ * @param corners The vector where the corners are listed
+ */
+ std::vector getAllCorners() const { return corners_; }
+
+ double getMaxX() const { return max_x_; }
+ double getMinX() const { return min_x_; }
+ double getMaxY() const { return max_y_; }
+ double getMinY() const { return min_y_; }
+
+private:
+ geometry_msgs::msg::Point center_;
+ double length_ = 0.0;
+ double width_ = 0.0;
+ double half_length_ = 0.0;
+ double half_width_ = 0.0;
+ double heading_ = 0.0;
+ double cos_heading_ = 1.0;
+ double sin_heading_ = 0.0;
+
+ std::vector corners_;
+
+ double max_x_ = std::numeric_limits::lowest();
+ double min_x_ = std::numeric_limits::max();
+ double max_y_ = std::numeric_limits::lowest();
+ double min_y_ = std::numeric_limits::max();
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__BOX2D_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/optimization_based_planner.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/optimization_based_planner.hpp
new file mode 100644
index 0000000000000..c8d6b294afd59
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/optimization_based_planner.hpp
@@ -0,0 +1,189 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__OPTIMIZATION_BASED_PLANNER_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__OPTIMIZATION_BASED_PLANNER_HPP_
+
+#include "obstacle_cruise_planner/optimization_based_planner/box2d.hpp"
+#include "obstacle_cruise_planner/optimization_based_planner/s_boundary.hpp"
+#include "obstacle_cruise_planner/optimization_based_planner/st_point.hpp"
+#include "obstacle_cruise_planner/optimization_based_planner/velocity_optimizer.hpp"
+#include "obstacle_cruise_planner/planner_interface.hpp"
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+#include "vehicle_info_util/vehicle_info_util.hpp"
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+using autoware_auto_perception_msgs::msg::ObjectClassification;
+using autoware_auto_perception_msgs::msg::PredictedPath;
+using autoware_auto_planning_msgs::msg::TrajectoryPoint;
+using tier4_debug_msgs::msg::Float32Stamped;
+
+class OptimizationBasedPlanner : public PlannerInterface
+{
+public:
+ OptimizationBasedPlanner(
+ rclcpp::Node & node, const LongitudinalInfo & longitudinal_info,
+ const vehicle_info_util::VehicleInfo & vehicle_info);
+
+ Trajectory generateTrajectory(
+ const ObstacleCruisePlannerData & planner_data, boost::optional & vel_limit,
+ DebugData & debug_data) override;
+
+private:
+ struct TrajectoryData
+ {
+ TrajectoryData() {}
+
+ Trajectory traj;
+ std::vector s;
+ };
+
+ struct ObjectData
+ {
+ geometry_msgs::msg::Pose pose;
+ double length;
+ double width;
+ double time;
+ };
+
+ // Member Functions
+ std::vector createTimeVector();
+
+ double getClosestStopDistance(
+ const ObstacleCruisePlannerData & planner_data, const TrajectoryData & ego_traj_data,
+ const std::vector & resolutions);
+
+ std::tuple calcInitialMotion(
+ const double current_vel, const Trajectory & input_traj, const size_t input_closest,
+ const Trajectory & prev_traj, const double closest_stop_dist);
+
+ TrajectoryPoint calcInterpolatedTrajectoryPoint(
+ const Trajectory & trajectory, const geometry_msgs::msg::Pose & target_pose);
+
+ bool checkHasReachedGoal(const Trajectory & traj, const size_t closest_idx, const double v0);
+
+ TrajectoryData getTrajectoryData(
+ const Trajectory & traj, const geometry_msgs::msg::Pose & current_pose);
+
+ TrajectoryData resampleTrajectoryData(
+ const TrajectoryData & base_traj_data, const double resampling_s_interval,
+ const double max_traj_length, const double stop_dist);
+
+ Trajectory resampleTrajectory(
+ const std::vector & base_index, const Trajectory & base_trajectory,
+ const std::vector & query_index, const bool use_spline_for_pose = false);
+
+ boost::optional getSBoundaries(
+ const ObstacleCruisePlannerData & planner_data, const TrajectoryData & ego_traj_data,
+ const std::vector & time_vec);
+
+ boost::optional getSBoundaries(
+ const rclcpp::Time & current_time, const TrajectoryData & ego_traj_data,
+ const TargetObstacle & object, const rclcpp::Time & obj_base_time,
+ const std::vector & time_vec);
+
+ boost::optional getSBoundaries(
+ const TrajectoryData & ego_traj_data, const std::vector & time_vec,
+ const double safety_distance, const TargetObstacle & object,
+ const double dist_to_collision_point);
+
+ boost::optional getSBoundaries(
+ const rclcpp::Time & current_time, const TrajectoryData & ego_traj_data,
+ const std::vector & time_vec, const double safety_distance,
+ const TargetObstacle & object, const rclcpp::Time & obj_base_time,
+ const PredictedPath & predicted_path);
+
+ bool checkIsFrontObject(const TargetObstacle & object, const Trajectory & traj);
+
+ boost::optional resampledPredictedPath(
+ const TargetObstacle & object, const rclcpp::Time & obj_base_time,
+ const rclcpp::Time & current_time, const std::vector & resolutions,
+ const double horizon);
+
+ boost::optional getDistanceToCollisionPoint(
+ const TrajectoryData & ego_traj_data, const ObjectData & obj_data,
+ const double delta_yaw_threshold);
+
+ boost::optional getCollisionIdx(
+ const TrajectoryData & ego_traj, const Box2d & obj_box, const size_t start_idx,
+ const size_t end_idx);
+
+ geometry_msgs::msg::Pose transformBaseLink2Center(
+ const geometry_msgs::msg::Pose & pose_base_link);
+
+ boost::optional processOptimizedResult(
+ const double v0, const VelocityOptimizer::OptimizationResult & opt_result);
+
+ void publishDebugTrajectory(
+ const rclcpp::Time & current_time, const Trajectory & traj, const size_t closest_idx,
+ const std::vector & time_vec, const SBoundaries & s_boundaries,
+ const VelocityOptimizer::OptimizationResult & opt_result);
+
+ // Calculation time watcher
+ tier4_autoware_utils::StopWatch stop_watch_;
+
+ Trajectory prev_output_;
+
+ // Velocity Optimizer
+ std::shared_ptr velocity_optimizer_ptr_;
+
+ // Publisher
+ rclcpp::Publisher::SharedPtr boundary_pub_;
+ rclcpp::Publisher::SharedPtr optimized_sv_pub_;
+ rclcpp::Publisher::SharedPtr optimized_st_graph_pub_;
+ rclcpp::Publisher::SharedPtr distance_to_closest_obj_pub_;
+ rclcpp::Publisher::SharedPtr debug_calculation_time_;
+ rclcpp::Publisher::SharedPtr debug_wall_marker_pub_;
+
+ // Resampling Parameter
+ double resampling_s_interval_;
+ double max_trajectory_length_;
+ double dense_resampling_time_interval_;
+ double sparse_resampling_time_interval_;
+ double dense_time_horizon_;
+ double max_time_horizon_;
+ double limit_min_accel_;
+
+ double delta_yaw_threshold_of_nearest_index_;
+ double delta_yaw_threshold_of_object_and_ego_;
+ double object_zero_velocity_threshold_;
+ double object_low_velocity_threshold_;
+ double external_velocity_limit_;
+ double collision_time_threshold_;
+ double safe_distance_margin_;
+ double t_dangerous_;
+ double velocity_margin_;
+ bool enable_adaptive_cruise_;
+ bool use_object_acceleration_;
+
+ double replan_vel_deviation_;
+ double engage_velocity_;
+ double engage_acceleration_;
+ double engage_exit_ratio_;
+ double stop_dist_to_prohibit_engage_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__OPTIMIZATION_BASED_PLANNER_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/resample.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/resample.hpp
new file mode 100644
index 0000000000000..dffe7f181fec5
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/resample.hpp
@@ -0,0 +1,50 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__RESAMPLE_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__RESAMPLE_HPP_
+
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+
+#include "autoware_auto_perception_msgs/msg/predicted_path.hpp"
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+
+#include "boost/optional.hpp"
+
+#include
+
+namespace resampling
+{
+std::vector resampledValidRelativeTimeVector(
+ const rclcpp::Time & start_time, const rclcpp::Time & obj_base_time,
+ const std::vector & rel_time_vec, const double duration);
+
+autoware_auto_perception_msgs::msg::PredictedPath resamplePredictedPath(
+ const autoware_auto_perception_msgs::msg::PredictedPath & input_path,
+ const std::vector & rel_time_vec);
+
+geometry_msgs::msg::Pose lerpByPose(
+ const geometry_msgs::msg::Pose & p1, const geometry_msgs::msg::Pose & p2, const double t);
+
+boost::optional lerpByTimeStamp(
+ const autoware_auto_perception_msgs::msg::PredictedPath & path,
+ const rclcpp::Duration & rel_time);
+
+autoware_auto_planning_msgs::msg::Trajectory applyLinearInterpolation(
+ const std::vector & base_index,
+ const autoware_auto_planning_msgs::msg::Trajectory & base_trajectory,
+ const std::vector & out_index, const bool use_spline_for_pose = false);
+} // namespace resampling
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__RESAMPLE_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/s_boundary.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/s_boundary.hpp
new file mode 100644
index 0000000000000..1665434ad5969
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/s_boundary.hpp
@@ -0,0 +1,33 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__S_BOUNDARY_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__S_BOUNDARY_HPP_
+
+#include
+#include
+
+class SBoundary
+{
+public:
+ SBoundary(const double _max_s, const double _min_s) : max_s(_max_s), min_s(_min_s) {}
+ SBoundary() : max_s(std::numeric_limits::max()), min_s(0.0) {}
+
+ double max_s = std::numeric_limits::max();
+ double min_s = 0.0;
+ bool is_object = false;
+};
+
+using SBoundaries = std::vector;
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__S_BOUNDARY_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/st_point.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/st_point.hpp
new file mode 100644
index 0000000000000..8ef958c741414
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/st_point.hpp
@@ -0,0 +1,31 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__ST_POINT_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__ST_POINT_HPP_
+
+#include
+
+class STPoint
+{
+public:
+ STPoint(const double _s, const double _t) : s(_s), t(_t) {}
+ STPoint() : s(0.0), t(0.0) {}
+
+ double s;
+ double t;
+};
+
+using STPoints = std::vector;
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__ST_POINT_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/velocity_optimizer.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/velocity_optimizer.hpp
new file mode 100644
index 0000000000000..cb7d1baab79b8
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/optimization_based_planner/velocity_optimizer.hpp
@@ -0,0 +1,73 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__VELOCITY_OPTIMIZER_HPP_
+#define OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__VELOCITY_OPTIMIZER_HPP_
+
+#include "obstacle_cruise_planner/optimization_based_planner/s_boundary.hpp"
+#include "osqp_interface/osqp_interface.hpp"
+
+#include
+
+class VelocityOptimizer
+{
+public:
+ struct OptimizationData
+ {
+ std::vector time_vec;
+ double s0;
+ double v0;
+ double a0;
+ double v_max;
+ double a_max;
+ double a_min;
+ double limit_a_min;
+ double j_max;
+ double j_min;
+ double t_dangerous;
+ double idling_time;
+ double v_margin;
+ SBoundaries s_boundary;
+ };
+
+ struct OptimizationResult
+ {
+ std::vector t;
+ std::vector s;
+ std::vector v;
+ std::vector a;
+ std::vector j;
+ };
+
+ VelocityOptimizer(
+ const double max_s_weight, const double max_v_weight, const double over_s_safety_weight,
+ const double over_s_ideal_weight, const double over_v_weight, const double over_a_weight,
+ const double over_j_weight);
+
+ OptimizationResult optimize(const OptimizationData & data);
+
+private:
+ // Parameter
+ double max_s_weight_;
+ double max_v_weight_;
+ double over_s_safety_weight_;
+ double over_s_ideal_weight_;
+ double over_v_weight_;
+ double over_a_weight_;
+ double over_j_weight_;
+
+ // QPSolver
+ autoware::common::osqp::OSQPInterface qp_solver_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__OPTIMIZATION_BASED_PLANNER__VELOCITY_OPTIMIZER_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/debug_values.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/debug_values.hpp
new file mode 100644
index 0000000000000..ae8a909d3bb51
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/debug_values.hpp
@@ -0,0 +1,79 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__DEBUG_VALUES_HPP_
+#define OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__DEBUG_VALUES_HPP_
+
+#include
+
+class DebugValues
+{
+public:
+ enum class TYPE {
+ // current
+ CURRENT_VELOCITY = 0,
+ CURRENT_ACCELERATION,
+ CURRENT_JERK, // ignored
+ // stop
+ STOP_CURRENT_OBJECT_DISTANCE = 3,
+ STOP_CURRENT_OBJECT_VELOCITY,
+ STOP_TARGET_OBJECT_DISTANCE,
+ STOP_TARGET_VELOCITY, // ignored
+ STOP_TARGET_ACCELERATION,
+ STOP_TARGET_JERK, // ignored
+ STOP_ERROR_OBJECT_DISTANCE,
+ // cruise
+ CRUISE_CURRENT_OBJECT_DISTANCE = 10,
+ CRUISE_CURRENT_OBJECT_VELOCITY,
+ CRUISE_TARGET_OBJECT_DISTANCE,
+ CRUISE_TARGET_VELOCITY,
+ CRUISE_TARGET_ACCELERATION,
+ CRUISE_TARGET_JERK,
+ CRUISE_ERROR_OBJECT_DISTANCE,
+
+ SIZE
+ };
+
+ /**
+ * @brief get the index corresponding to the given value TYPE
+ * @param [in] type the TYPE enum for which to get the index
+ * @return index of the type
+ */
+ int getValuesIdx(const TYPE type) const { return static_cast(type); }
+ /**
+ * @brief get all the debug values as an std::array
+ * @return array of all debug values
+ */
+ std::array(TYPE::SIZE)> getValues() const { return values_; }
+ /**
+ * @brief set the given type to the given value
+ * @param [in] type TYPE of the value
+ * @param [in] value value to set
+ */
+ void setValues(const TYPE type, const double val) { values_.at(static_cast(type)) = val; }
+ /**
+ * @brief set the given type to the given value
+ * @param [in] type index of the type
+ * @param [in] value value to set
+ */
+ void setValues(const int type, const double val) { values_.at(type) = val; }
+
+ void resetValues() { values_.fill(0.0); }
+
+private:
+ static constexpr int num_debug_values_ = static_cast(TYPE::SIZE);
+ std::array(TYPE::SIZE)> values_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__DEBUG_VALUES_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_based_planner.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_based_planner.hpp
new file mode 100644
index 0000000000000..7697fd54b1d1a
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_based_planner.hpp
@@ -0,0 +1,138 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_BASED_PLANNER_HPP_
+#define OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_BASED_PLANNER_HPP_
+
+#include "obstacle_cruise_planner/pid_based_planner/debug_values.hpp"
+#include "obstacle_cruise_planner/pid_based_planner/pid_controller.hpp"
+#include "obstacle_cruise_planner/planner_interface.hpp"
+#include "tier4_autoware_utils/system/stop_watch.hpp"
+
+#include "tier4_debug_msgs/msg/float32_multi_array_stamped.hpp"
+#include "tier4_planning_msgs/msg/stop_reason_array.hpp"
+#include "tier4_planning_msgs/msg/stop_speed_exceeded.hpp"
+#include "visualization_msgs/msg/marker_array.hpp"
+
+#include
+
+#include
+#include
+
+using tier4_debug_msgs::msg::Float32MultiArrayStamped;
+using tier4_planning_msgs::msg::StopSpeedExceeded;
+
+class PIDBasedPlanner : public PlannerInterface
+{
+public:
+ struct CruiseObstacleInfo
+ {
+ CruiseObstacleInfo(
+ const TargetObstacle & obstacle_arg, const double dist_to_cruise_arg,
+ const double normalized_dist_to_cruise_arg)
+ : obstacle(obstacle_arg),
+ dist_to_cruise(dist_to_cruise_arg),
+ normalized_dist_to_cruise(normalized_dist_to_cruise_arg)
+ {
+ }
+ TargetObstacle obstacle;
+ double dist_to_cruise;
+ double normalized_dist_to_cruise;
+ };
+
+ struct StopObstacleInfo
+ {
+ StopObstacleInfo(const TargetObstacle & obstacle_arg, const double dist_to_stop_arg)
+ : obstacle(obstacle_arg), dist_to_stop(dist_to_stop_arg)
+ {
+ }
+ TargetObstacle obstacle;
+ double dist_to_stop;
+ };
+
+ PIDBasedPlanner(
+ rclcpp::Node & node, const LongitudinalInfo & longitudinal_info,
+ const vehicle_info_util::VehicleInfo & vehicle_info);
+
+ Trajectory generateTrajectory(
+ const ObstacleCruisePlannerData & planner_data, boost::optional & vel_limit,
+ DebugData & debug_data) override;
+
+ void updateParam(const std::vector & parameters) override;
+
+private:
+ void calcObstaclesToCruiseAndStop(
+ const ObstacleCruisePlannerData & planner_data,
+ boost::optional & stop_obstacle_info,
+ boost::optional & cruise_obstacle_info);
+ double calcDistanceToObstacle(
+ const ObstacleCruisePlannerData & planner_data, const TargetObstacle & obstacle);
+ bool isStopRequired(const TargetObstacle & obstacle);
+
+ void planCruise(
+ const ObstacleCruisePlannerData & planner_data, boost::optional & vel_limit,
+ const boost::optional & cruise_obstacle_info, DebugData & debug_data);
+ VelocityLimit doCruise(
+ const ObstacleCruisePlannerData & planner_data, const CruiseObstacleInfo & cruise_obstacle_info,
+ std::vector & debug_obstacles_to_cruise,
+ visualization_msgs::msg::MarkerArray & debug_walls_marker);
+
+ Trajectory planStop(
+ const ObstacleCruisePlannerData & planner_data,
+ const boost::optional & stop_obstacle_info, DebugData & debug_data);
+ boost::optional doStop(
+ const ObstacleCruisePlannerData & planner_data, const StopObstacleInfo & stop_obstacle_info,
+ std::vector & debug_obstacles_to_stop,
+ visualization_msgs::msg::MarkerArray & debug_walls_marker) const;
+
+ void publishDebugValues(const ObstacleCruisePlannerData & planner_data) const;
+
+ size_t findExtendedNearestIndex(
+ const Trajectory traj, const geometry_msgs::msg::Pose & pose) const
+ {
+ const auto nearest_idx = tier4_autoware_utils::findNearestIndex(
+ traj.points, pose, nearest_dist_deviation_threshold_, nearest_yaw_deviation_threshold_);
+ if (nearest_idx) {
+ return nearest_idx.get();
+ }
+ return tier4_autoware_utils::findNearestIndex(traj.points, pose.position);
+ }
+
+ // ROS parameters
+ double min_accel_during_cruise_;
+ double vel_to_acc_weight_;
+ double min_cruise_target_vel_;
+ double obstacle_velocity_threshold_from_cruise_to_stop_;
+ // bool use_predicted_obstacle_pose_;
+
+ // pid controller
+ std::unique_ptr pid_controller_;
+ double output_ratio_during_accel_;
+
+ // stop watch
+ tier4_autoware_utils::StopWatch<
+ std::chrono::milliseconds, std::chrono::microseconds, std::chrono::steady_clock>
+ stop_watch_;
+
+ // publisher
+ rclcpp::Publisher::SharedPtr stop_reasons_pub_;
+ rclcpp::Publisher::SharedPtr stop_speed_exceeded_pub_;
+ rclcpp::Publisher::SharedPtr debug_values_pub_;
+
+ boost::optional prev_target_vel_;
+
+ DebugValues debug_values_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_BASED_PLANNER_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_controller.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_controller.hpp
new file mode 100644
index 0000000000000..593fd1f4336d6
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/pid_based_planner/pid_controller.hpp
@@ -0,0 +1,62 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_CONTROLLER_HPP_
+#define OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_CONTROLLER_HPP_
+
+#include
+
+class PIDController
+{
+public:
+ PIDController(const double kp, const double ki, const double kd)
+ : kp_(kp), ki_(ki), kd_(kd), error_sum_(0.0)
+ {
+ }
+
+ double calc(const double error)
+ {
+ error_sum_ += error;
+
+ // TODO(murooka) use time for d gain calculation
+ const double output =
+ kp_ * error + ki_ * error_sum_ + (prev_error_ ? kd_ * (error - prev_error_.get()) : 0.0);
+ prev_error_ = error;
+ return output;
+ }
+
+ double getKp() const { return kp_; }
+ double getKi() const { return ki_; }
+ double getKd() const { return kd_; }
+
+ void updateParam(const double kp, const double ki, const double kd)
+ {
+ kp_ = kp;
+ ki_ = ki;
+ kd_ = kd;
+
+ error_sum_ = 0.0;
+ prev_error_ = {};
+ }
+
+private:
+ double kp_;
+ double ki_;
+ double kd_;
+
+ double error_sum_;
+ boost::optional prev_error_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__PID_BASED_PLANNER__PID_CONTROLLER_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/planner_interface.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/planner_interface.hpp
new file mode 100644
index 0000000000000..af31e1d979e4b
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/planner_interface.hpp
@@ -0,0 +1,192 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_
+#define OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_
+
+#include "obstacle_cruise_planner/common_structs.hpp"
+#include "obstacle_cruise_planner/utils.hpp"
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+#include "vehicle_info_util/vehicle_info_util.hpp"
+
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+#include "tier4_planning_msgs/msg/velocity_limit.hpp"
+
+#include
+
+#include
+#include
+
+using autoware_auto_perception_msgs::msg::ObjectClassification;
+using autoware_auto_planning_msgs::msg::Trajectory;
+using tier4_planning_msgs::msg::VelocityLimit;
+
+class PlannerInterface
+{
+public:
+ PlannerInterface(
+ rclcpp::Node & node, const LongitudinalInfo & longitudinal_info,
+ const vehicle_info_util::VehicleInfo & vehicle_info)
+ : longitudinal_info_(longitudinal_info), vehicle_info_(vehicle_info)
+ {
+ { // cruise obstacle type
+ if (node.declare_parameter("common.cruise_obstacle_type.unknown")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::UNKNOWN);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.car")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::CAR);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.truck")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::TRUCK);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.bus")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::BUS);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.trailer")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::TRAILER);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.motorcycle")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::MOTORCYCLE);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.bicycle")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::BICYCLE);
+ }
+ if (node.declare_parameter("common.cruise_obstacle_type.pedestrian")) {
+ cruise_obstacle_types_.push_back(ObjectClassification::PEDESTRIAN);
+ }
+ }
+
+ { // stop obstacle type
+ if (node.declare_parameter("common.stop_obstacle_type.unknown")) {
+ stop_obstacle_types_.push_back(ObjectClassification::UNKNOWN);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.car")) {
+ stop_obstacle_types_.push_back(ObjectClassification::CAR);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.truck")) {
+ stop_obstacle_types_.push_back(ObjectClassification::TRUCK);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.bus")) {
+ stop_obstacle_types_.push_back(ObjectClassification::BUS);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.trailer")) {
+ stop_obstacle_types_.push_back(ObjectClassification::TRAILER);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.motorcycle")) {
+ stop_obstacle_types_.push_back(ObjectClassification::MOTORCYCLE);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.bicycle")) {
+ stop_obstacle_types_.push_back(ObjectClassification::BICYCLE);
+ }
+ if (node.declare_parameter("common.stop_obstacle_type.pedestrian")) {
+ stop_obstacle_types_.push_back(ObjectClassification::PEDESTRIAN);
+ }
+ }
+ }
+
+ PlannerInterface() = default;
+
+ void setParams(
+ const bool is_showing_debug_info, const double min_behavior_stop_margin,
+ const double nearest_dist_deviation_threshold, const double nearest_yaw_deviation_threshold)
+ {
+ is_showing_debug_info_ = is_showing_debug_info;
+ min_behavior_stop_margin_ = min_behavior_stop_margin;
+ nearest_dist_deviation_threshold_ = nearest_dist_deviation_threshold;
+ nearest_yaw_deviation_threshold_ = nearest_yaw_deviation_threshold;
+ }
+
+ /*
+ // two kinds of velocity planning is supported.
+ // 1. getZeroVelocityIndexWithVelocityLimit
+ // returns zero velocity index and velocity limit
+ // 2. generateTrajectory
+ // returns trajectory with planned velocity
+ virtual boost::optional getZeroVelocityIndexWithVelocityLimit(
+ [[maybe_unused]] const ObstacleCruisePlannerData & planner_data,
+ [[maybe_unused]] boost::optional & vel_limit)
+ {
+ return {};
+ };
+ */
+
+ virtual Trajectory generateTrajectory(
+ const ObstacleCruisePlannerData & planner_data, boost::optional & vel_limit,
+ DebugData & debug_data) = 0;
+
+ void updateCommonParam(const std::vector & parameters)
+ {
+ auto & i = longitudinal_info_;
+
+ tier4_autoware_utils::updateParam(parameters, "common.max_accel", i.max_accel);
+ tier4_autoware_utils::updateParam(parameters, "common.min_accel", i.min_accel);
+ tier4_autoware_utils::updateParam(parameters, "common.max_jerk", i.max_jerk);
+ tier4_autoware_utils::updateParam(parameters, "common.min_jerk", i.min_jerk);
+ tier4_autoware_utils::updateParam(
+ parameters, "common.min_ego_accel_for_rss", i.min_ego_accel_for_rss);
+ tier4_autoware_utils::updateParam(
+ parameters, "common.min_object_accel_for_rss", i.min_object_accel_for_rss);
+ tier4_autoware_utils::updateParam(parameters, "common.idling_time", i.idling_time);
+ }
+
+ virtual void updateParam([[maybe_unused]] const std::vector & parameters) {}
+
+ // TODO(shimizu) remove this function
+ void setSmoothedTrajectory(const Trajectory::ConstSharedPtr traj)
+ {
+ smoothed_trajectory_ptr_ = traj;
+ }
+
+ bool isCruiseObstacle(const uint8_t label)
+ {
+ const auto & types = cruise_obstacle_types_;
+ return std::find(types.begin(), types.end(), label) != types.end();
+ }
+
+ bool isStopObstacle(const uint8_t label)
+ {
+ const auto & types = stop_obstacle_types_;
+ return std::find(types.begin(), types.end(), label) != types.end();
+ }
+
+protected:
+ // Parameters
+ bool is_showing_debug_info_{false};
+ LongitudinalInfo longitudinal_info_;
+ double min_behavior_stop_margin_;
+ double nearest_dist_deviation_threshold_;
+ double nearest_yaw_deviation_threshold_;
+
+ // Vehicle Parameters
+ vehicle_info_util::VehicleInfo vehicle_info_;
+
+ // TODO(shimizu) remove these parameters
+ Trajectory::ConstSharedPtr smoothed_trajectory_ptr_;
+
+ double calcRSSDistance(
+ const double ego_vel, const double obj_vel, const double margin = 0.0) const
+ {
+ const auto & i = longitudinal_info_;
+ const double rss_dist_with_margin =
+ ego_vel * i.idling_time + std::pow(ego_vel, 2) * 0.5 / std::abs(i.min_accel) -
+ std::pow(obj_vel, 2) * 0.5 / std::abs(i.min_object_accel_for_rss) + margin;
+ return rss_dist_with_margin;
+ }
+
+private:
+ std::vector cruise_obstacle_types_;
+ std::vector stop_obstacle_types_;
+};
+
+#endif // OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/polygon_utils.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/polygon_utils.hpp
new file mode 100644
index 0000000000000..8a34f49172cd2
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/polygon_utils.hpp
@@ -0,0 +1,62 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__POLYGON_UTILS_HPP_
+#define OBSTACLE_CRUISE_PLANNER__POLYGON_UTILS_HPP_
+
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+#include "vehicle_info_util/vehicle_info_util.hpp"
+
+#include "autoware_auto_perception_msgs/msg/predicted_object.hpp"
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+#include "geometry_msgs/msg/point32.hpp"
+#include "geometry_msgs/msg/pose.hpp"
+
+#include
+#include
+
+#include
+
+namespace polygon_utils
+{
+namespace bg = boost::geometry;
+using tier4_autoware_utils::Point2d;
+using tier4_autoware_utils::Polygon2d;
+
+Polygon2d convertObstacleToPolygon(
+ const geometry_msgs::msg::Pose & pose, const autoware_auto_perception_msgs::msg::Shape & shape);
+
+boost::optional getFirstCollisionIndex(
+ const std::vector & traj_polygons, const Polygon2d & obj_polygon,
+ std::vector & collision_points);
+
+boost::optional getFirstNonCollisionIndex(
+ const std::vector & base_polygons,
+ const autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
+ const autoware_auto_perception_msgs::msg::Shape & shape, const size_t start_idx);
+
+bool willCollideWithSurroundObstacle(
+ const autoware_auto_planning_msgs::msg::Trajectory & traj,
+ const std::vector & traj_polygons,
+ const autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
+ const autoware_auto_perception_msgs::msg::Shape & shape, const double max_dist,
+ const double ego_obstacle_overlap_time_threshold,
+ const double max_prediction_time_for_collision_check);
+
+std::vector createOneStepPolygons(
+ const autoware_auto_planning_msgs::msg::Trajectory & traj,
+ const vehicle_info_util::VehicleInfo & vehicle_info, const double expand_width);
+} // namespace polygon_utils
+
+#endif // OBSTACLE_CRUISE_PLANNER__POLYGON_UTILS_HPP_
diff --git a/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/utils.hpp b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/utils.hpp
new file mode 100644
index 0000000000000..d1e6a0b86e715
--- /dev/null
+++ b/planning/obstacle_cruise_planner/include/obstacle_cruise_planner/utils.hpp
@@ -0,0 +1,49 @@
+// Copyright 2022 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 OBSTACLE_CRUISE_PLANNER__UTILS_HPP_
+#define OBSTACLE_CRUISE_PLANNER__UTILS_HPP_
+
+#include
+
+#include "autoware_auto_perception_msgs/msg/object_classification.hpp"
+#include "autoware_auto_perception_msgs/msg/predicted_path.hpp"
+#include "autoware_auto_planning_msgs/msg/trajectory.hpp"
+#include "geometry_msgs/msg/pose.hpp"
+#include "visualization_msgs/msg/marker_array.hpp"
+
+#include
+
+#include
+
+namespace obstacle_cruise_utils
+{
+using autoware_auto_perception_msgs::msg::ObjectClassification;
+
+bool isVehicle(const uint8_t label);
+
+visualization_msgs::msg::Marker getObjectMarker(
+ const geometry_msgs::msg::Pose & obstacle_pose, size_t idx, const std::string & ns,
+ const double r, const double g, const double b);
+
+boost::optional calcForwardPose(
+ const autoware_auto_planning_msgs::msg::Trajectory & traj, const size_t nearest_idx,
+ const double target_length);
+
+boost::optional getCurrentObjectPoseFromPredictedPath(
+ const autoware_auto_perception_msgs::msg::PredictedPath & predicted_path,
+ const rclcpp::Time & obj_base_time, const rclcpp::Time & current_time);
+} // namespace obstacle_cruise_utils
+
+#endif // OBSTACLE_CRUISE_PLANNER__UTILS_HPP_
diff --git a/planning/obstacle_cruise_planner/launch/obstacle_cruise_planner.launch.xml b/planning/obstacle_cruise_planner/launch/obstacle_cruise_planner.launch.xml
new file mode 100644
index 0000000000000..a6c95d65acc6a
--- /dev/null
+++ b/planning/obstacle_cruise_planner/launch/obstacle_cruise_planner.launch.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/planning/obstacle_cruise_planner/obstacle_cruise_planner-design.md b/planning/obstacle_cruise_planner/obstacle_cruise_planner-design.md
new file mode 100644
index 0000000000000..3a78af3827b2e
--- /dev/null
+++ b/planning/obstacle_cruise_planner/obstacle_cruise_planner-design.md
@@ -0,0 +1,326 @@
+# Obstacle Velocity Planner
+
+## Overview
+
+The `obstacle_cruise_planner` package has following modules.
+
+- obstacle stop planning
+ - inserting a stop point in the trajectory when there is a static obstacle on the trajectory.
+- adaptive cruise planning
+ - sending an external velocity limit to `motion_velocity_smoother` when there is a dynamic obstacle to cruise on the trajectory
+
+## Interfaces
+
+### Input topics
+
+| Name | Type | Description |
+| ----------------------------- | ----------------------------------------------- | --------------------------------- |
+| `~/input/trajectory` | autoware_auto_planning_msgs::Trajectory | input trajectory |
+| `~/input/smoothed_trajectory` | autoware_auto_planning_msgs::Trajectory | trajectory with smoothed velocity |
+| `~/input/objects` | autoware_auto_perception_msgs::PredictedObjects | dynamic objects |
+| `~/input/odometry` | nav_msgs::msg::Odometry | ego odometry |
+
+### Output topics
+
+| Name | Type | Description |
+| ------------------------------ | ---------------------------------------------- | ------------------------------------- |
+| `~output/trajectory` | autoware_auto_planning_msgs::Trajectory | output trajectory |
+| `~output/velocity_limit` | tier4_planning_msgs::VelocityLimit | velocity limit for cruising |
+| `~output/clear_velocity_limit` | tier4_planning_msgs::VelocityLimitClearCommand | clear command for velocity limit |
+| `~output/stop_reasons` | tier4_planning_msgs::StopReasonArray | reasons that make the vehicle to stop |
+
+## Design
+
+Design for the following functions is defined here.
+
+- Obstacle candidates selection
+- Obstacle stop planning
+- Adaptive cruise planning
+
+A data structure for cruise and stop planning is as follows.
+This planner data is created first, and then sent to the planning algorithm.
+
+```cpp
+struct ObstacleCruisePlannerData
+{
+ rclcpp::Time current_time;
+ autoware_auto_planning_msgs::msg::Trajectory traj;
+ geometry_msgs::msg::Pose current_pose;
+ double current_vel;
+ double current_acc;
+ std::vector target_obstacles;
+};
+```
+
+```cpp
+struct TargetObstacle
+{
+ rclcpp::Time time_stamp;
+ bool orientation_reliable;
+ geometry_msgs::msg::Pose pose;
+ bool velocity_reliable;
+ float velocity;
+ bool is_classified;
+ ObjectClassification classification;
+ Shape shape;
+ std::vector predicted_paths;
+ geometry_msgs::msg::Point collision_point;
+};
+```
+
+### Obstacle candidates selection
+
+In this function, target obstacles for stopping or cruising are selected based on their pose and velocity.
+
+By default, objects that realize one of the following conditions are considered to be the target obstacle candidates.
+Some terms will be defined in the following subsections.
+
+- Vehicle objects "inside the detection area" other than "far crossing vehicles".
+- non vehicle objects "inside the detection area"
+- "Near cut-in vehicles" outside the detection area
+
+Note that currently the obstacle candidates selection algorithm is for autonomous driving.
+However, we have following parameters as well for stop and cruise respectively so that we can extend the obstacles candidates selection algorithm for non vehicle robots.
+By default, unknown and vehicles are obstacles to cruise and stop, and non vehicles are obstacles just to stop.
+
+| Parameter | Type | Description |
+| ------------------------------ | ---- | ------------------------------------------------- |
+| `cruise_obstacle_type.unknown` | bool | flag to consider unknown objects as being cruised |
+| `cruise_obstacle_type.car` | bool | flag to consider unknown objects as being cruised |
+| `cruise_obstacle_type.truck` | bool | flag to consider unknown objects as being cruised |
+| ... | bool | ... |
+| `stop_obstacle_type.unknown` | bool | flag to consider unknown objects as being stopped |
+| ... | bool | ... |
+
+#### Inside the detection area
+
+To calculate obstacles inside the detection area, firstly, obstacles whose distance to the trajectory is less than `rough_detection_area_expand_width` are selected.
+Then, the detection area, which is a trajectory with some lateral margin, is calculated as shown in the figure.
+The detection area width is a vehicle's width + `detection_area_expand_width`, and it is represented as a polygon resampled with `decimate_trajectory_step_length` longitudinally.
+The roughly selected obstacles inside the detection area are considered as inside the detection area.
+
+![detection_area](./image/detection_area.png)
+
+This two-step detection is used for calculation efficiency since collision checking of polygons is heavy.
+Boost.Geometry is used as a library to check collision among polygons.
+
+In the `obstacle_filtering` namespace,
+
+| Parameter | Type | Description |
+| ----------------------------------- | ------ | ----------------------------------------------------------------------------------- |
+| `rough_detection_area_expand_width` | double | rough lateral margin for rough detection area expansion [m] |
+| `detection_area_expand_width` | double | lateral margin for precise detection area expansion [m] |
+| `decimate_trajectory_step_length` | double | longitudinal step length to calculate trajectory polygon for collision checking [m] |
+
+#### Far crossing vehicles
+
+Near crossing vehicles (= not far crossing vehicles) are defined as vehicle objects realizing either of following conditions.
+
+- whose yaw angle against the nearest trajectory point is greater than `crossing_obstacle_traj_angle_threshold`
+- whose velocity is less than `crossing_obstacle_velocity_threshold`.
+
+Assuming `t_1` to be the time for the ego to reach the current crossing obstacle position with the constant velocity motion, and `t_2` to be the time for the crossing obstacle to go outside the detection area, if the following condition is realized, the crossing vehicle will be ignored.
+
+$$
+t_1 - t_2 > \mathrm{margin\_for\_collision\_time}
+$$
+
+In the `obstacle_filtering` namespace,
+
+| Parameter | Type | Description |
+| ---------------------------------------- | ------ | ----------------------------------------------------------------------------- |
+| `crossing_obstacle_velocity_threshold` | double | velocity threshold to decide crossing obstacle [m/s] |
+| `crossing_obstacle_traj_angle_threshold` | double | yaw threshold of crossing obstacle against the nearest trajectory point [rad] |
+| `collision_time_margin` | double | time threshold of collision between obstacle and ego [s] |
+
+#### Near Cut-in vehicles
+
+Near Cut-in vehicles are defined as vehicle objects
+
+- whose predicted path's footprints from the current time to `max_prediction_time_for_collision_check` overlap with the detection area longer than `ego_obstacle_overlap_time_threshold`.
+
+In the `obstacle_filtering` namespace,
+
+| Parameter | Type | Description |
+| ----------------------------------------- | ------ | --------------------------------------------------------------- |
+| `ego_obstacle_overlap_time_threshold` | double | time threshold to decide cut-in obstacle for cruise or stop [s] |
+| `max_prediction_time_for_collision_check` | double | prediction time to check collision between obstacle and ego [s] |
+
+### Stop planning
+
+| Parameter | Type | Description |
+| ----------------------------- | ------ | ----------------------------------------- |
+| `common.min_strong_accel` | double | ego's minimum acceleration to stop [m/ss] |
+| `common.safe_distance_margin` | double | distance with obstacles for stop [m] |
+
+The role of the stop planning is keeping a safe distance with static vehicle objects or dynamic/static non vehicle objects.
+
+The stop planning just inserts the stop point in the trajectory to keep a distance with obstacles inside the detection area.
+The safe distance is parameterized as `common.safe_distance_margin`.
+
+When inserting the stop point, the required acceleration for the ego to stop in front of the stop point is calculated.
+If the acceleration is less than `common.min_strong_accel`, the stop planning will be cancelled since this package does not assume a strong sudden brake for emergency.
+
+### Adaptive cruise planning
+
+| Parameter | Type | Description |
+| ----------------------------- | ------ | ---------------------------------------------- |
+| `common.safe_distance_margin` | double | minimum distance with obstacles for cruise [m] |
+
+The role of the adaptive 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 = 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$ 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 |
+| --------------------------------- | ------ | ----------------------------------------------------------------------------- |
+| `common.idling_time` | double | idling time for the ego to detect the front vehicle starting deceleration [s] |
+| `common.min_object_accel_for_rss` | double | front obstacle's acceleration [m/ss] |
+
+## Implementation
+
+### Flowchart
+
+Successive functions consist of `obstacle_cruise_planner` as follows.
+
+Various algorithms for stop and cruise planning will be implemented, and one of them is designated depending on the use cases.
+The core algorithm implementation `generateTrajectory` depends on the designated algorithm.
+
+```plantuml
+@startuml
+title trajectoryCallback
+start
+
+group createPlannerData
+ :filterObstacles;
+end group
+
+:generateTrajectory;
+
+:publishVelocityLimit;
+
+:publish trajectory;
+
+:publishDebugData;
+
+:publish and print calculation time;
+
+stop
+@enduml
+```
+
+### Algorithm selection
+
+Currently, only a PID-based planner is supported.
+Each planner will be explained in the following.
+
+| Parameter | Type | Description |
+| ------------------------ | ------ | ------------------------------------------------------------ |
+| `common.planning_method` | string | cruise and stop planning algorithm, selected from "pid_base" |
+
+### PID-based planner
+
+#### Stop planning
+
+In the `pid_based_planner` namespace,
+
+| Parameter | Type | Description |
+| ------------------------------------------------- | ------ | ------------------------------------------------------------ |
+| `obstacle_velocity_threshold_from_cruise_to_stop` | double | obstacle velocity threshold to be stopped from cruised [m/s] |
+
+Only one obstacle is targeted for the stop planning.
+It is the obstacle among obstacle candidates whose velocity is less than `obstacle_velocity_threshold_from_cruise_to_stop`, and which is the nearest to the ego along the trajectory. A stop point is inserted keeping`common.safe_distance_margin` distance between the ego and obstacle.
+
+Note that, as explained in the stop planning design, a stop planning which requires a strong acceleration (less than `common.min_strong_accel`) will be canceled.
+
+#### Adaptive cruise planning
+
+In the `pid_based_planner` namespace,
+
+| Parameter | Type | Description |
+| --------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
+| `kp` | double | p gain for pid control [-] |
+| `ki` | double | i gain for pid control [-] |
+| `kd` | double | d gain for pid control [-] |
+| `output_ratio_during_accel` | double | The output velocity will be multiplied by the ratio during acceleration to follow the front vehicle. [-] |
+| `vel_to_acc_weight` | double | target acceleration is target velocity \* `vel_to_acc_weight` [-] |
+| `min_cruise_target_vel` | double | minimum target velocity during cruise [m/s] |
+
+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 (`motion_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
+
+## Minor functions
+
+### Prioritization of behavior module's stop point
+
+When stopping for a pedestrian walking on the crosswalk, the behavior module inserts the zero velocity in the trajectory in front of the crosswalk.
+Also `obstacle_cruise_planner`'s stop planning also works, and the ego may not reach the behavior module's stop point since the safe distance defined in `obstacle_cruise_planner` may be longer than the behavior module's safe distance.
+To resolve this non-alignment of the stop point between the behavior module and `obstacle_cruise_planner`, `common.min_behavior_stop_margin` is defined.
+In the case of the crosswalk described above, `obstacle_cruise_planner` inserts the stop point with a distance `common.min_behavior_stop_margin` at minimum between the ego and obstacle.
+
+| Parameter | Type | Description |
+| --------------------------------- | ------ | ---------------------------------------------------------------------- |
+| `common.min_behavior_stop_margin` | double | minimum stop margin when stopping with the behavior module enabled [m] |
+
+## Visualization for debugging
+
+### Detection area
+
+Green polygons which is a detection area is visualized by `detection_polygons` in the `~/debug/marker` topic.
+
+![detection_area](./image/detection_area.png)
+
+### Collision point
+
+Red point which is a collision point with obstacle is visualized by `collision_points` in the `~/debug/marker` topic.
+
+![collision_point](./image/collision_point.png)
+
+### Obstacle for cruise
+
+Yellow sphere which is a obstacle for cruise is visualized by `obstacles_to_cruise` in the `~/debug/marker` topic.
+
+![obstacle_to_cruise](./image/obstacle_to_cruise.png)
+
+### Obstacle for stop
+
+Red sphere which is a obstacle for stop is visualized by `obstacles_to_stop` in the `~/debug/marker` topic.
+
+![obstacle_to_stop](./image/obstacle_to_stop.png)
+
+
+
+
+
+
+
+### Obstacle cruise wall
+
+Yellow wall which means a safe distance to cruise if the ego's front meets the wall is visualized in the `~/debug/cruise_wall_marker` topic.
+
+![obstacle_to_cruise](./image/obstacle_to_cruise.png)
+
+### Obstacle stop wall
+
+Red wall which means a safe distance to stop if the ego's front meets the wall is visualized in the `~/debug/stop_wall_marker` topic.
+
+![obstacle_to_stop](./image/obstacle_to_stop.png)
+
+## Known Limits
+
+- Common
+ - When the obstacle pose or velocity estimation has a delay, the ego sometimes will go close to the front vehicle keeping deceleration.
+ - Current implementation only uses predicted objects message for static/dynamic obstacles and does not use pointcloud. Therefore, if object recognition is lost, the ego cannot deal with the lost obstacle.
+- PID-based planner
+ - The algorithm strongly depends on the velocity smoothing package (`motion_velocity_smoother` by default) whether or not the ego realizes the designated target speed. If the velocity smoothing package is updated, please take care of the vehicle's behavior as much as possible.
diff --git a/planning/obstacle_cruise_planner/package.xml b/planning/obstacle_cruise_planner/package.xml
new file mode 100644
index 0000000000000..ec261d99a229f
--- /dev/null
+++ b/planning/obstacle_cruise_planner/package.xml
@@ -0,0 +1,40 @@
+
+
+ obstacle_cruise_planner
+ 0.1.0
+ The Stop/Slow down planner for dynamic obstacles
+
+ Takayuki Murooka
+
+ Apache License 2.0
+
+ ament_cmake_auto
+
+ autoware_cmake
+
+ autoware_auto_perception_msgs
+ autoware_auto_planning_msgs
+ geometry_msgs
+ interpolation
+ lanelet2_extension
+ nav_msgs
+ osqp_interface
+ rclcpp
+ rclcpp_components
+ signal_processing
+ std_msgs
+ tf2
+ tf2_ros
+ tier4_autoware_utils
+ tier4_debug_msgs
+ tier4_planning_msgs
+ vehicle_info_util
+ visualization_msgs
+
+ ament_lint_auto
+ autoware_lint_common
+
+
+ ament_cmake
+
+
diff --git a/planning/obstacle_cruise_planner/scripts/trajectory_visualizer.py b/planning/obstacle_cruise_planner/scripts/trajectory_visualizer.py
new file mode 100755
index 0000000000000..00833d4e84e83
--- /dev/null
+++ b/planning/obstacle_cruise_planner/scripts/trajectory_visualizer.py
@@ -0,0 +1,384 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright 2022 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.
+
+from autoware_auto_planning_msgs.msg import Trajectory
+from geometry_msgs.msg import Pose
+from geometry_msgs.msg import Twist
+from geometry_msgs.msg import TwistStamped
+from matplotlib import animation
+import matplotlib.pyplot as plt
+import message_filters
+from nav_msgs.msg import Odometry
+import numpy as np
+import rclpy
+from rclpy.node import Node
+from tf2_ros.buffer import Buffer
+from tf2_ros.transform_listener import TransformListener
+
+PLOT_MAX_ARCLENGTH = 200
+PATH_ORIGIN_FRAME = "map"
+SELF_POSE_FRAME = "base_link"
+
+
+class TrajectoryVisualizer(Node):
+ def __init__(self):
+
+ super().__init__("trajectory_visualizer")
+
+ self.fig = plt.figure()
+
+ self.max_vel = 0.0
+ self.min_vel = 0.0
+
+ # update flag
+ self.update_sv_traj = False
+ self.update_traj = False
+ self.update_max_traj = False
+ self.update_boundary = False
+ self.update_optimized_st_graph = False
+
+ self.tf_buffer = Buffer(node=self)
+ self.tf_listener = TransformListener(
+ self.tf_buffer, self, spin_thread=True
+ ) # For get self-position
+ self.self_pose = Pose()
+ self.self_pose_received = False
+ self.localization_twist = Twist()
+ self.vehicle_twist = Twist()
+
+ self.sv_trajectory = Trajectory()
+ self.trajectory = Trajectory()
+ self.max_trajectory = Trajectory()
+ self.boundary = Trajectory()
+ self.optimized_st_graph = Trajectory()
+
+ self.sub_localization_twist = self.create_subscription(
+ Odometry, "/localization/kinematic_state", self.CallbackLocalizationOdom, 1
+ )
+ self.sub_vehicle_twist = self.create_subscription(
+ TwistStamped, "/vehicle/status/twist", self.CallbackVehicleTwist, 1
+ )
+
+ topic_header = "/planning/scenario_planning/lane_driving/motion_planning/"
+ traj0 = "obstacle_cruise_planner/optimized_sv_trajectory"
+ self.sub_status0 = message_filters.Subscriber(self, Trajectory, topic_header + traj0)
+ traj1 = "/planning/scenario_planning/lane_driving/trajectory"
+ self.sub_status1 = message_filters.Subscriber(self, Trajectory, traj1)
+ traj2 = "surround_obstacle_checker/trajectory"
+ self.sub_status2 = message_filters.Subscriber(self, Trajectory, topic_header + traj2)
+ traj3 = "obstacle_cruise_planner/boundary"
+ self.sub_status3 = message_filters.Subscriber(self, Trajectory, topic_header + traj3)
+ traj4 = "obstacle_cruise_planner/optimized_st_graph"
+ self.sub_status4 = message_filters.Subscriber(self, Trajectory, topic_header + traj4)
+
+ self.ts1 = message_filters.ApproximateTimeSynchronizer(
+ [self.sub_status0, self.sub_status1, self.sub_status2], 30, 0.5
+ )
+ self.ts1.registerCallback(self.CallbackMotionVelOptTraj)
+ self.ts2 = message_filters.ApproximateTimeSynchronizer(
+ [self.sub_status3, self.sub_status4], 30, 0.5
+ )
+ self.ts2.registerCallback(self.CallbackMotionVelObsTraj)
+
+ # Main Process
+ self.ani = animation.FuncAnimation(
+ self.fig, self.plotTrajectoryVelocity, interval=100, blit=True
+ )
+ self.setPlotTrajectoryVelocity()
+
+ plt.show()
+ return
+
+ def CallbackLocalizationOdom(self, cmd):
+ self.localization_twist = cmd.twist.twist
+
+ def CallbackVehicleTwist(self, cmd):
+ self.vehicle_twist = cmd.twist
+
+ def CallbackMotionVelOptTraj(self, cmd0, cmd1, cmd2):
+ self.CallbackSVTraj(cmd0)
+ self.CallbackTraj(cmd1)
+ self.CallbackMaxTraj(cmd2)
+
+ def CallbackMotionVelObsTraj(self, cmd1, cmd2):
+ self.CallbackBoundary(cmd1)
+ self.CallbackOptimizedSTGraph(cmd2)
+
+ def CallbackSVTraj(self, cmd):
+ self.sv_trajectory = cmd
+ self.update_sv_traj = True
+
+ def CallbackTraj(self, cmd):
+ self.trajectory = cmd
+ self.update_traj = True
+
+ def CallbackMaxTraj(self, cmd):
+ self.max_trajectory = cmd
+ self.update_max_traj = True
+
+ def CallbackBoundary(self, cmd):
+ self.boundary = cmd
+ self.update_boundary = True
+
+ def CallbackOptimizedSTGraph(self, cmd):
+ self.optimized_st_graph = cmd
+ self.update_optimized_st_graph = True
+
+ def setPlotTrajectoryVelocity(self):
+ self.ax1 = plt.subplot(2, 1, 1) # row, col, index(= 0:
+ x_closest = x[opt_closest]
+ self.im3.set_data(x_closest, self.localization_twist.linear.x)
+ self.im4.set_data(x_closest, self.vehicle_twist.linear.x)
+
+ opt_zero_vel_id = -1
+ for i in range(opt_closest, len(trajectory.points)):
+ if trajectory.points[i].longitudinal_velocity_mps < 1e-3:
+ opt_zero_vel_id = i
+ break
+ else:
+ opt_zero_vel_id = len(trajectory.points) - 1
+
+ opt_pos = self.CalcPartArcLength(trajectory, opt_closest, opt_zero_vel_id + 1)
+ opt_time = self.CalcTime(trajectory, opt_closest, opt_zero_vel_id + 1)
+ self.im6.set_data(opt_time, opt_pos)
+
+ if self.update_max_traj:
+ x = self.CalcArcLength(max_trajectory)
+ y = self.ToVelList(max_trajectory)
+ self.im1.set_data(x, y)
+ self.update_max_traj = False
+
+ max_closest = self.calcClosestTrajectory(max_trajectory)
+ if max_closest >= 0:
+ max_zero_vel_id = -1
+ for i in range(max_closest, len(max_trajectory.points)):
+ if max_trajectory.points[i].longitudinal_velocity_mps < 1e-3:
+ max_zero_vel_id = i
+ break
+ else:
+ max_zero_vel_id = len(max_trajectory.points) - 1
+
+ max_pos = self.CalcPartArcLength(max_trajectory, max_closest, max_zero_vel_id + 1)
+ max_time = self.CalcTime(max_trajectory, max_closest, max_zero_vel_id + 1)
+ self.im5.set_data(max_time, max_pos)
+
+ if self.update_boundary:
+ self.update_boundary = False
+ s_list = []
+ t_list = []
+ for p in self.boundary.points:
+ s_list.append(p.pose.position.x)
+ t_list.append(p.pose.position.y)
+ self.im7.set_data(t_list, s_list)
+
+ if self.update_optimized_st_graph:
+ self.update_optimized_st_graph = False
+ s_list = []
+ t_list = []
+ for p in self.optimized_st_graph.points:
+ s_list.append(p.pose.position.x)
+ t_list.append(p.pose.position.y)
+ self.im8.set_data(t_list, s_list)
+
+ # change y-range
+ self.ax1.set_ylim([-1.0, 50.0])
+
+ return (
+ self.im0,
+ self.im1,
+ self.im2,
+ self.im3,
+ self.im4,
+ self.im5,
+ self.im6,
+ self.im7,
+ self.im8,
+ )
+
+ def CalcArcLength(self, traj):
+ return self.CalcPartArcLength(traj, 0, len(traj.points))
+
+ def CalcPartArcLength(self, traj, start, end):
+ assert start <= end
+ s_arr = []
+ ds = 0.0
+ s_sum = 0.0
+
+ if len(traj.points) > 0:
+ s_arr.append(s_sum)
+
+ for i in range(start + 1, end):
+ p0 = traj.points[i - 1]
+ p1 = traj.points[i]
+ dx = p1.pose.position.x - p0.pose.position.x
+ dy = p1.pose.position.y - p0.pose.position.y
+ ds = np.sqrt(dx**2 + dy**2)
+ s_sum += ds
+ s_arr.append(s_sum)
+ return s_arr
+
+ def CalcTrajectoryInterval(self, traj, start, end):
+ ds_arr = []
+
+ for i in range(start + 1, end):
+ p0 = traj.points[i - 1]
+ p1 = traj.points[i]
+ dx = p1.pose.position.x - p0.pose.position.x
+ dy = p1.pose.position.y - p0.pose.position.y
+ ds = np.sqrt(dx**2 + dy**2)
+ ds_arr.append(ds)
+ return ds_arr
+
+ def CalcTime(self, traj, start, end):
+ t_arr = []
+ t_sum = 0.0
+ ds_arr = self.CalcTrajectoryInterval(traj, start, end)
+
+ if len(traj.points) > 0:
+ t_arr.append(t_sum)
+
+ for i in range(start, end - 1):
+ v = traj.points[i].longitudinal_velocity_mps
+ ds = ds_arr[i - start]
+ dt = ds / max(v, 0.1)
+ t_sum += dt
+ t_arr.append(t_sum)
+ return t_arr
+
+ def ToVelList(self, traj):
+ v_list = []
+ for p in traj.points:
+ v_list.append(p.longitudinal_velocity_mps)
+ return v_list
+
+ def updatePose(self, from_link, to_link):
+ try:
+ tf = self.tf_buffer.lookup_transform(from_link, to_link, rclpy.time.Time())
+ self.self_pose.position.x = tf.transform.translation.x
+ self.self_pose.position.y = tf.transform.translation.y
+ self.self_pose.position.z = tf.transform.translation.z
+ self.self_pose.orientation.x = tf.transform.rotation.x
+ self.self_pose.orientation.y = tf.transform.rotation.y
+ self.self_pose.orientation.z = tf.transform.rotation.z
+ self.self_pose.orientation.w = tf.transform.rotation.w
+ self.self_pose_received = True
+ return
+ except BaseException:
+ self.get_logger().warn(
+ "lookup transform failed: from {} to {}".format(from_link, to_link)
+ )
+ return
+
+ def calcClosestTrajectory(self, path):
+ closest = -1
+ min_dist_squared = 1.0e10
+ for i in range(0, len(path.points)):
+ dist_sq = self.calcSquaredDist2d(self.self_pose, path.points[i].pose)
+ if dist_sq < min_dist_squared:
+ min_dist_squared = dist_sq
+ closest = i
+ return closest
+
+ def calcSquaredDist2d(self, p1, p2):
+ dx = p1.position.x - p2.position.x
+ dy = p1.position.y - p2.position.y
+ return dx * dx + dy * dy
+
+
+def main(args=None):
+ try:
+ rclpy.init(args=args)
+ node = TrajectoryVisualizer()
+ rclpy.spin(node)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ node.destroy_node()
+ rclpy.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/planning/obstacle_cruise_planner/src/node.cpp b/planning/obstacle_cruise_planner/src/node.cpp
new file mode 100644
index 0000000000000..45bab678c98b7
--- /dev/null
+++ b/planning/obstacle_cruise_planner/src/node.cpp
@@ -0,0 +1,780 @@
+// Copyright 2022 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.
+
+#include "obstacle_cruise_planner/node.hpp"
+
+#include "obstacle_cruise_planner/polygon_utils.hpp"
+#include "obstacle_cruise_planner/utils.hpp"
+#include "tier4_autoware_utils/ros/update_param.hpp"
+#include "tier4_autoware_utils/trajectory/tmp_conversion.hpp"
+
+#include
+
+#include
+#include
+
+namespace
+{
+VelocityLimitClearCommand createVelocityLimitClearCommandMsg(const rclcpp::Time & current_time)
+{
+ VelocityLimitClearCommand msg;
+ msg.stamp = current_time;
+ msg.sender = "obstacle_cruise_planner";
+ msg.command = true;
+ return msg;
+}
+
+// TODO(murooka) make this function common
+size_t findExtendedNearestIndex(
+ const Trajectory traj, const geometry_msgs::msg::Pose & pose, const double max_dist,
+ const double max_yaw)
+{
+ const auto nearest_idx =
+ tier4_autoware_utils::findNearestIndex(traj.points, pose, max_dist, max_yaw);
+ if (nearest_idx) {
+ return nearest_idx.get();
+ }
+ return tier4_autoware_utils::findNearestIndex(traj.points, pose.position);
+}
+
+Trajectory trimTrajectoryFrom(const Trajectory & input, const double nearest_idx)
+{
+ Trajectory output{};
+
+ for (size_t i = nearest_idx; i < input.points.size(); ++i) {
+ output.points.push_back(input.points.at(i));
+ }
+
+ return output;
+}
+
+bool isFrontObstacle(
+ const Trajectory & traj, const size_t ego_idx, const geometry_msgs::msg::Point & obj_pos)
+{
+ size_t obj_idx = tier4_autoware_utils::findNearestSegmentIndex(traj.points, obj_pos);
+
+ const double ego_to_obj_distance =
+ tier4_autoware_utils::calcSignedArcLength(traj.points, ego_idx, obj_idx);
+
+ if (obj_idx == 0 && ego_to_obj_distance < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+TrajectoryPoint calcLinearPoint(
+ const TrajectoryPoint & p_from, const TrajectoryPoint & p_to, const double length)
+{
+ TrajectoryPoint output;
+ const double dx = p_to.pose.position.x - p_from.pose.position.x;
+ const double dy = p_to.pose.position.y - p_from.pose.position.y;
+ const double norm = std::hypot(dx, dy);
+
+ output = p_to;
+ output.pose.position.x += length * dx / norm;
+ output.pose.position.y += length * dy / norm;
+
+ return output;
+}
+
+// TODO(murooka) replace with spline interpolation
+Trajectory decimateTrajectory(const Trajectory & input, const double step_length)
+{
+ Trajectory output{};
+
+ if (input.points.empty()) {
+ return output;
+ }
+
+ double trajectory_length_sum = 0.0;
+ double next_length = 0.0;
+
+ for (int i = 0; i < static_cast(input.points.size()) - 1; ++i) {
+ const auto & p_front = input.points.at(i);
+ const auto & p_back = input.points.at(i + 1);
+ constexpr double epsilon = 1e-3;
+
+ if (next_length <= trajectory_length_sum + epsilon) {
+ const auto p_interpolate =
+ calcLinearPoint(p_front, p_back, next_length - trajectory_length_sum);
+ output.points.push_back(p_interpolate);
+ next_length += step_length;
+ continue;
+ }
+
+ trajectory_length_sum += tier4_autoware_utils::calcDistance2d(p_front, p_back);
+ }
+
+ output.points.push_back(input.points.back());
+
+ return output;
+}
+
+PredictedPath getHighestConfidencePredictedPath(const PredictedObject & predicted_object)
+{
+ const auto reliable_path = std::max_element(
+ predicted_object.kinematics.predicted_paths.begin(),
+ predicted_object.kinematics.predicted_paths.end(),
+ [](const PredictedPath & a, const PredictedPath & b) { return a.confidence < b.confidence; });
+ return *reliable_path;
+}
+
+bool isAngleAlignedWithTrajectory(
+ const Trajectory & traj, const geometry_msgs::msg::Pose & pose, const double threshold_angle)
+{
+ if (traj.points.empty()) {
+ return false;
+ }
+
+ const double obj_yaw = tf2::getYaw(pose.orientation);
+
+ const size_t nearest_idx = tier4_autoware_utils::findNearestIndex(traj.points, pose.position);
+ const double traj_yaw = tf2::getYaw(traj.points.at(nearest_idx).pose.orientation);
+
+ const double diff_yaw = tier4_autoware_utils::normalizeRadian(obj_yaw - traj_yaw);
+
+ const bool is_aligned = std::abs(diff_yaw) <= threshold_angle;
+ return is_aligned;
+}
+
+double calcAlignedAdaptiveCruise(
+ const PredictedObject & predicted_object, const Trajectory & trajectory)
+{
+ const auto & object_pos = predicted_object.kinematics.initial_pose_with_covariance.pose.position;
+ const auto & object_vel =
+ predicted_object.kinematics.initial_twist_with_covariance.twist.linear.x;
+
+ const size_t object_idx = tier4_autoware_utils::findNearestIndex(trajectory.points, object_pos);
+
+ const double object_yaw =
+ tf2::getYaw(predicted_object.kinematics.initial_pose_with_covariance.pose.orientation);
+ const double traj_yaw = tf2::getYaw(trajectory.points.at(object_idx).pose.orientation);
+
+ return object_vel * std::cos(object_yaw - traj_yaw);
+}
+} // namespace
+
+namespace motion_planning
+{
+ObstacleCruisePlannerNode::ObstacleCruisePlannerNode(const rclcpp::NodeOptions & node_options)
+: Node("obstacle_cruise_planner", node_options),
+ self_pose_listener_(this),
+ in_objects_ptr_(nullptr),
+ lpf_acc_ptr_(nullptr),
+ vehicle_info_(vehicle_info_util::VehicleInfoUtil(*this).getVehicleInfo())
+{
+ using std::placeholders::_1;
+
+ // subscriber
+ trajectory_sub_ = create_subscription(
+ "~/input/trajectory", rclcpp::QoS{1},
+ std::bind(&ObstacleCruisePlannerNode::onTrajectory, this, _1));
+ smoothed_trajectory_sub_ = create_subscription(
+ "/planning/scenario_planning/trajectory", rclcpp::QoS{1},
+ std::bind(&ObstacleCruisePlannerNode::onSmoothedTrajectory, this, _1));
+ objects_sub_ = create_subscription(
+ "~/input/objects", rclcpp::QoS{1}, std::bind(&ObstacleCruisePlannerNode::onObjects, this, _1));
+ odom_sub_ = create_subscription(
+ "~/input/odometry", rclcpp::QoS{1},
+ std::bind(&ObstacleCruisePlannerNode::onOdometry, this, std::placeholders::_1));
+
+ // publisher
+ trajectory_pub_ = create_publisher("~/output/trajectory", 1);
+ vel_limit_pub_ =
+ create_publisher("~/output/velocity_limit", rclcpp::QoS{1}.transient_local());
+ clear_vel_limit_pub_ = create_publisher(
+ "~/output/clear_velocity_limit", rclcpp::QoS{1}.transient_local());
+ debug_calculation_time_pub_ = create_publisher("~/debug/calculation_time", 1);
+ debug_cruise_wall_marker_pub_ =
+ create_publisher("~/debug/cruise_wall_marker", 1);
+ debug_stop_wall_marker_pub_ =
+ create_publisher("~/virtual_wall", 1);
+ debug_marker_pub_ = create_publisher("~/debug/marker", 1);
+
+ // longitudinal_info
+ const auto longitudinal_info = [&]() {
+ const double max_accel = declare_parameter("normal.max_acc");
+ const double min_accel = declare_parameter("normal.min_acc");
+ const double max_jerk = declare_parameter("normal.max_jerk");
+ const double min_jerk = declare_parameter("normal.min_jerk");
+
+ const double min_strong_accel = declare_parameter("common.min_strong_accel");
+ const double min_ego_accel_for_rss = declare_parameter("common.min_ego_accel_for_rss");
+ const double min_object_accel_for_rss =
+ declare_parameter("common.min_object_accel_for_rss");
+ const double idling_time = declare_parameter("common.idling_time");
+ const double safe_distance_margin = declare_parameter("common.safe_distance_margin");
+
+ return LongitudinalInfo(
+ max_accel, min_accel, max_jerk, min_jerk, min_strong_accel, idling_time,
+ min_ego_accel_for_rss, min_object_accel_for_rss, safe_distance_margin);
+ }();
+
+ const bool is_showing_debug_info_ = declare_parameter("common.is_showing_debug_info");
+
+ // low pass filter for ego acceleration
+ const double lpf_gain_for_accel = declare_parameter("common.lpf_gain_for_accel");
+ lpf_acc_ptr_ = std::make_shared(0.0, lpf_gain_for_accel);
+
+ { // Obstacle filtering parameters
+ obstacle_filtering_param_.rough_detection_area_expand_width =
+ declare_parameter("obstacle_filtering.rough_detection_area_expand_width");
+ obstacle_filtering_param_.detection_area_expand_width =
+ declare_parameter("obstacle_filtering.detection_area_expand_width");
+ obstacle_filtering_param_.decimate_trajectory_step_length =
+ declare_parameter("obstacle_filtering.decimate_trajectory_step_length");
+ obstacle_filtering_param_.crossing_obstacle_velocity_threshold =
+ declare_parameter("obstacle_filtering.crossing_obstacle_velocity_threshold");
+ obstacle_filtering_param_.collision_time_margin =
+ declare_parameter("obstacle_filtering.collision_time_margin");
+ obstacle_filtering_param_.ego_obstacle_overlap_time_threshold =
+ declare_parameter("obstacle_filtering.ego_obstacle_overlap_time_threshold");
+ obstacle_filtering_param_.max_prediction_time_for_collision_check =
+ declare_parameter("obstacle_filtering.max_prediction_time_for_collision_check");
+ obstacle_filtering_param_.crossing_obstacle_traj_angle_threshold =
+ declare_parameter("obstacle_filtering.crossing_obstacle_traj_angle_threshold");
+
+ {
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.unknown")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::UNKNOWN);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.car")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::CAR);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.truck")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::TRUCK);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.bus")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::BUS);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.trailer")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::TRAILER);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.motorcycle")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::MOTORCYCLE);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.bicycle")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::BICYCLE);
+ }
+ if (declare_parameter("obstacle_filtering.ignored_outside_obstacle_type.pedestrian")) {
+ obstacle_filtering_param_.ignored_outside_obstacle_types.push_back(
+ ObjectClassification::PEDESTRIAN);
+ }
+ }
+ }
+
+ { // planning algorithm
+ const std::string planning_algorithm_param =
+ declare_parameter("common.planning_algorithm");
+ planning_algorithm_ = getPlanningAlgorithmType(planning_algorithm_param);
+
+ if (planning_algorithm_ == PlanningAlgorithm::OPTIMIZATION_BASE) {
+ planner_ptr_ =
+ std::make_unique(*this, longitudinal_info, vehicle_info_);
+ } else if (planning_algorithm_ == PlanningAlgorithm::PID_BASE) {
+ planner_ptr_ = std::make_unique(*this, longitudinal_info, vehicle_info_);
+ } else {
+ std::logic_error("Designated algorithm is not supported.");
+ }
+
+ min_behavior_stop_margin_ = declare_parameter("common.min_behavior_stop_margin");
+ nearest_dist_deviation_threshold_ =
+ declare_parameter("common.nearest_dist_deviation_threshold");
+ nearest_yaw_deviation_threshold_ =
+ declare_parameter("common.nearest_yaw_deviation_threshold");
+ planner_ptr_->setParams(
+ is_showing_debug_info_, min_behavior_stop_margin_, nearest_dist_deviation_threshold_,
+ nearest_yaw_deviation_threshold_);
+ }
+
+ // wait for first self pose
+ self_pose_listener_.waitForFirstPose();
+
+ // set parameter callback
+ set_param_res_ = this->add_on_set_parameters_callback(
+ std::bind(&ObstacleCruisePlannerNode::onParam, this, std::placeholders::_1));
+}
+
+ObstacleCruisePlannerNode::PlanningAlgorithm ObstacleCruisePlannerNode::getPlanningAlgorithmType(
+ const std::string & param) const
+{
+ if (param == "pid_base") {
+ return PlanningAlgorithm::PID_BASE;
+ } else if (param == "optimization_base") {
+ return PlanningAlgorithm::OPTIMIZATION_BASE;
+ }
+ return PlanningAlgorithm::INVALID;
+}
+
+rcl_interfaces::msg::SetParametersResult ObstacleCruisePlannerNode::onParam(
+ const std::vector & parameters)
+{
+ planner_ptr_->updateCommonParam(parameters);
+ planner_ptr_->updateParam(parameters);
+
+ tier4_autoware_utils::updateParam(
+ parameters, "common.is_showing_debug_info", is_showing_debug_info_);
+ planner_ptr_->setParams(
+ is_showing_debug_info_, min_behavior_stop_margin_, nearest_dist_deviation_threshold_,
+ nearest_yaw_deviation_threshold_);
+
+ // obstacle_filtering
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.rough_detection_area_expand_width",
+ obstacle_filtering_param_.rough_detection_area_expand_width);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.detection_area_expand_width",
+ obstacle_filtering_param_.detection_area_expand_width);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.decimate_trajectory_step_length",
+ obstacle_filtering_param_.decimate_trajectory_step_length);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.crossing_obstacle_velocity_threshold",
+ obstacle_filtering_param_.crossing_obstacle_velocity_threshold);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.collision_time_margin",
+ obstacle_filtering_param_.collision_time_margin);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.ego_obstacle_overlap_time_threshold",
+ obstacle_filtering_param_.ego_obstacle_overlap_time_threshold);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.max_prediction_time_for_collision_check",
+ obstacle_filtering_param_.max_prediction_time_for_collision_check);
+ tier4_autoware_utils::updateParam(
+ parameters, "obstacle_filtering.crossing_obstacle_traj_angle_threshold",
+ obstacle_filtering_param_.crossing_obstacle_traj_angle_threshold);
+
+ rcl_interfaces::msg::SetParametersResult result;
+ result.successful = true;
+ result.reason = "success";
+ return result;
+}
+
+void ObstacleCruisePlannerNode::onObjects(const PredictedObjects::ConstSharedPtr msg)
+{
+ in_objects_ptr_ = msg;
+}
+
+void ObstacleCruisePlannerNode::onOdometry(const Odometry::ConstSharedPtr msg)
+{
+ if (current_twist_ptr_) {
+ prev_twist_ptr_ = current_twist_ptr_;
+ }
+
+ current_twist_ptr_ = std::make_unique();
+ current_twist_ptr_->header = msg->header;
+ current_twist_ptr_->twist = msg->twist.twist;
+}
+
+void ObstacleCruisePlannerNode::onSmoothedTrajectory(const Trajectory::ConstSharedPtr msg)
+{
+ planner_ptr_->setSmoothedTrajectory(msg);
+}
+
+void ObstacleCruisePlannerNode::onTrajectory(const Trajectory::ConstSharedPtr msg)
+{
+ const auto current_pose_ptr = self_pose_listener_.getCurrentPose();
+
+ // check if subscribed variables are ready
+ if (
+ msg->points.empty() || !current_twist_ptr_ || !prev_twist_ptr_ || !in_objects_ptr_ ||
+ !current_pose_ptr) {
+ return;
+ }
+
+ stop_watch_.tic(__func__);
+
+ // create algorithmic data
+ DebugData debug_data;
+ const auto planner_data = createPlannerData(*msg, current_pose_ptr->pose, debug_data);
+
+ // generate Trajectory
+ boost::optional vel_limit;
+ const auto output_traj = planner_ptr_->generateTrajectory(planner_data, vel_limit, debug_data);
+
+ // publisher external velocity limit if required
+ publishVelocityLimit(vel_limit);
+
+ // Publish trajectory
+ trajectory_pub_->publish(output_traj);
+
+ // publish debug data
+ publishDebugData(debug_data);
+
+ // publish and print calculation time
+ const double calculation_time = stop_watch_.toc(__func__);
+ publishCalculationTime(calculation_time);
+ RCLCPP_INFO_EXPRESSION(
+ rclcpp::get_logger("ObstacleCruisePlanner"), is_showing_debug_info_, "%s := %f [ms]", __func__,
+ calculation_time);
+}
+
+ObstacleCruisePlannerData ObstacleCruisePlannerNode::createPlannerData(
+ const Trajectory & trajectory, const geometry_msgs::msg::Pose & current_pose,
+ DebugData & debug_data)
+{
+ stop_watch_.tic(__func__);
+
+ const double current_vel = current_twist_ptr_->twist.linear.x;
+ const double current_accel = calcCurrentAccel();
+
+ // create planner_data
+ ObstacleCruisePlannerData planner_data;
+ planner_data.current_time = now();
+ planner_data.traj = trajectory;
+ planner_data.current_pose = current_pose;
+ planner_data.current_vel = current_vel;
+ planner_data.current_acc = current_accel;
+ planner_data.target_obstacles =
+ filterObstacles(*in_objects_ptr_, trajectory, current_pose, current_vel, debug_data);
+
+ // print calculation time
+ const double calculation_time = stop_watch_.toc(__func__);
+ RCLCPP_INFO_EXPRESSION(
+ rclcpp::get_logger("ObstacleCruisePlanner"), is_showing_debug_info_, " %s := %f [ms]",
+ __func__, calculation_time);
+
+ return planner_data;
+}
+
+double ObstacleCruisePlannerNode::calcCurrentAccel() const
+{
+ const double diff_vel = current_twist_ptr_->twist.linear.x - prev_twist_ptr_->twist.linear.x;
+ const double diff_time = std::max(
+ (rclcpp::Time(current_twist_ptr_->header.stamp) - rclcpp::Time(prev_twist_ptr_->header.stamp))
+ .seconds(),
+ 1e-03);
+
+ const double accel = diff_vel / diff_time;
+
+ return lpf_acc_ptr_->filter(accel);
+}
+
+std::vector ObstacleCruisePlannerNode::filterObstacles(
+ const PredictedObjects & predicted_objects, const Trajectory & traj,
+ const geometry_msgs::msg::Pose & current_pose, const double current_vel, DebugData & debug_data)
+{
+ const auto time_stamp = rclcpp::Time(predicted_objects.header.stamp);
+
+ const size_t ego_idx = findExtendedNearestIndex(
+ traj, current_pose, nearest_dist_deviation_threshold_, nearest_yaw_deviation_threshold_);
+
+ // calculate decimated trajectory
+ const auto trimmed_traj = trimTrajectoryFrom(traj, ego_idx);
+ const auto decimated_traj =
+ decimateTrajectory(trimmed_traj, obstacle_filtering_param_.decimate_trajectory_step_length);
+ if (decimated_traj.points.size() < 2) {
+ return {};
+ }
+
+ // calculate decimated trajectory polygons
+ const auto decimated_traj_polygons = polygon_utils::createOneStepPolygons(
+ decimated_traj, vehicle_info_, obstacle_filtering_param_.detection_area_expand_width);
+ debug_data.detection_polygons = decimated_traj_polygons;
+
+ std::vector target_obstacles;
+ for (const auto & predicted_object : predicted_objects.objects) {
+ // filter object whose label is not cruised or stopped
+ const bool is_target_obstacle =
+ planner_ptr_->isStopObstacle(predicted_object.classification.front().label) ||
+ planner_ptr_->isCruiseObstacle(predicted_object.classification.front().label);
+ if (!is_target_obstacle) {
+ RCLCPP_INFO_EXPRESSION(
+ get_logger(), is_showing_debug_info_, "Ignore obstacles since its label is not target.");
+ continue;
+ }
+
+ const auto & object_pose = predicted_object.kinematics.initial_pose_with_covariance.pose;
+ const auto & object_velocity =
+ predicted_object.kinematics.initial_twist_with_covariance.twist.linear.x;
+
+ const bool is_front_obstacle = isFrontObstacle(traj, ego_idx, object_pose.position);
+ if (!is_front_obstacle) {
+ RCLCPP_INFO_EXPRESSION(
+ get_logger(), is_showing_debug_info_, "Ignore obstacles since its not front obstacle.");
+ continue;
+ }
+
+ // rough detection area filtering without polygons
+ const double dist_from_obstacle_to_traj = [&]() {
+ return tier4_autoware_utils::calcLateralOffset(decimated_traj.points, object_pose.position);
+ }();
+ if (dist_from_obstacle_to_traj > obstacle_filtering_param_.rough_detection_area_expand_width) {
+ RCLCPP_INFO_EXPRESSION(
+ get_logger(), is_showing_debug_info_,
+ "Ignore obstacles since it is far from the trajectory.");
+ continue;
+ }
+
+ // calculate collision points
+ const auto obstacle_polygon =
+ polygon_utils::convertObstacleToPolygon(object_pose, predicted_object.shape);
+ std::vector collision_points;
+ const auto first_within_idx = polygon_utils::getFirstCollisionIndex(
+ decimated_traj_polygons, obstacle_polygon, collision_points);
+
+ // precise detection area filtering with polygons
+ geometry_msgs::msg::Point nearest_collision_point;
+ if (first_within_idx) { // obstacles inside the trajectory
+ // calculate nearest collision point
+ nearest_collision_point =
+ calcNearestCollisionPoint(first_within_idx.get(), collision_points, decimated_traj);
+ debug_data.collision_points.push_back(nearest_collision_point);
+
+ const bool is_angle_aligned = isAngleAlignedWithTrajectory(
+ decimated_traj, object_pose,
+ obstacle_filtering_param_.crossing_obstacle_traj_angle_threshold);
+ const double has_high_speed =
+ std::abs(object_velocity) > obstacle_filtering_param_.crossing_obstacle_velocity_threshold;
+
+ // ignore running vehicle crossing the ego trajectory with high speed with some condition
+ if (!is_angle_aligned && has_high_speed) {
+ const double collision_time_margin = calcCollisionTimeMargin(
+ current_pose, current_vel, nearest_collision_point, predicted_object,
+ first_within_idx.get(), decimated_traj, decimated_traj_polygons);
+ if (collision_time_margin > obstacle_filtering_param_.collision_time_margin) {
+ // Ignore condition 1
+ // Ignore vehicle obstacles inside the trajectory, which is crossing the trajectory with
+ // high speed and does not collide with ego in a certain time.
+ RCLCPP_INFO_EXPRESSION(
+ get_logger(), is_showing_debug_info_,
+ "Ignore inside obstacles since it will not collide with the ego.");
+
+ debug_data.intentionally_ignored_obstacles.push_back(predicted_object);
+ continue;
+ }
+ }
+ } else { // obstacles outside the trajectory
+ const auto & types = obstacle_filtering_param_.ignored_outside_obstacle_types;
+ if (
+ std::find(types.begin(), types.end(), predicted_object.classification.front().label) !=
+ types.end()) {
+ continue;
+ }
+
+ const auto predicted_path_with_highest_confidence =
+ getHighestConfidencePredictedPath(predicted_object);
+
+ const bool will_collide = polygon_utils::willCollideWithSurroundObstacle(
+ decimated_traj, decimated_traj_polygons, predicted_path_with_highest_confidence,
+ predicted_object.shape, obstacle_filtering_param_.rough_detection_area_expand_width,
+ obstacle_filtering_param_.ego_obstacle_overlap_time_threshold,
+ obstacle_filtering_param_.max_prediction_time_for_collision_check);
+
+ // TODO(murooka) think later
+ nearest_collision_point = object_pose.position;
+
+ if (!will_collide) {
+ // Ignore condition 2
+ // Ignore vehicle obstacles outside the trajectory, whose predicted path
+ // overlaps the ego trajectory in a certain time.
+ RCLCPP_INFO_EXPRESSION(
+ get_logger(), is_showing_debug_info_,
+ "Ignore outside obstacles since it will not collide with the ego.");
+
+ debug_data.intentionally_ignored_obstacles.push_back(predicted_object);
+ continue;
+ }
+ }
+
+ // convert to obstacle type
+ const double trajectory_aligned_adaptive_cruise =
+ calcAlignedAdaptiveCruise(predicted_object, traj);
+ const auto target_obstacle = TargetObstacle(
+ time_stamp, predicted_object, trajectory_aligned_adaptive_cruise, nearest_collision_point);
+ target_obstacles.push_back(target_obstacle);
+ }
+
+ return target_obstacles;
+}
+
+geometry_msgs::msg::Point ObstacleCruisePlannerNode::calcNearestCollisionPoint(
+ const size_t & first_within_idx, const std::vector & collision_points,
+ const Trajectory & decimated_traj)
+{
+ std::array segment_points;
+ if (first_within_idx == 0) {
+ const auto & traj_front_pose = decimated_traj.points.at(0).pose;
+ segment_points.at(0) = traj_front_pose.position;
+
+ const auto front_pos = tier4_autoware_utils::calcOffsetPose(
+ traj_front_pose, vehicle_info_.max_longitudinal_offset_m, 0.0, 0.0)
+ .position;
+ segment_points.at(1) = front_pos;
+ } else {
+ const size_t seg_idx = first_within_idx - 1;
+ segment_points.at(0) = decimated_traj.points.at(seg_idx).pose.position;
+ segment_points.at(1) = decimated_traj.points.at(seg_idx + 1).pose.position;
+ }
+
+ size_t min_idx = 0;
+ double min_dist = std::numeric_limits::max();
+ for (size_t cp_idx = 0; cp_idx < collision_points.size(); ++cp_idx) {
+ const auto & collision_point = collision_points.at(cp_idx);
+ const double dist =
+ tier4_autoware_utils::calcLongitudinalOffsetToSegment(segment_points, 0, collision_point);
+ if (dist < min_dist) {
+ min_dist = dist;
+ min_idx = cp_idx;
+ }
+ }
+
+ return collision_points.at(min_idx);
+}
+
+double ObstacleCruisePlannerNode::calcCollisionTimeMargin(
+ const geometry_msgs::msg::Pose & current_pose, const double current_vel,
+ const geometry_msgs::msg::Point & nearest_collision_point,
+ const PredictedObject & predicted_object, const size_t first_within_idx,
+ const Trajectory & decimated_traj,
+ const std::vector & decimated_traj_polygons)
+{
+ const auto & object_pose = predicted_object.kinematics.initial_pose_with_covariance.pose;
+ const auto & object_velocity =
+ predicted_object.kinematics.initial_twist_with_covariance.twist.linear.x;
+ const auto predicted_path_with_highest_confidence =
+ getHighestConfidencePredictedPath(predicted_object);
+
+ const double time_to_collision = [&]() {
+ const double dist_from_ego_to_obstacle =
+ tier4_autoware_utils::calcSignedArcLength(
+ decimated_traj.points, current_pose.position, nearest_collision_point) -
+ vehicle_info_.max_longitudinal_offset_m;
+ return dist_from_ego_to_obstacle / std::max(1e-6, current_vel);
+ }();
+
+ const double time_to_obstacle_getting_out = [&]() {
+ const auto obstacle_getting_out_idx = polygon_utils::getFirstNonCollisionIndex(
+ decimated_traj_polygons, predicted_path_with_highest_confidence, predicted_object.shape,
+ first_within_idx);
+ if (!obstacle_getting_out_idx) {
+ return std::numeric_limits::max();
+ }
+
+ const double dist_to_obstacle_getting_out = tier4_autoware_utils::calcSignedArcLength(
+ decimated_traj.points, object_pose.position, obstacle_getting_out_idx.get());
+
+ return dist_to_obstacle_getting_out / object_velocity;
+ }();
+
+ return time_to_collision - time_to_obstacle_getting_out;
+}
+
+void ObstacleCruisePlannerNode::publishVelocityLimit(
+ const boost::optional & vel_limit)
+{
+ if (vel_limit) {
+ vel_limit_pub_->publish(vel_limit.get());
+ need_to_clear_vel_limit_ = true;
+ } else {
+ if (need_to_clear_vel_limit_) {
+ const auto clear_vel_limit_msg = createVelocityLimitClearCommandMsg(now());
+ clear_vel_limit_pub_->publish(clear_vel_limit_msg);
+ need_to_clear_vel_limit_ = false;
+ }
+ }
+}
+
+void ObstacleCruisePlannerNode::publishDebugData(const DebugData & debug_data) const
+{
+ stop_watch_.tic(__func__);
+
+ visualization_msgs::msg::MarkerArray debug_marker;
+ const auto current_time = now();
+
+ // obstacles to cruise
+ for (size_t i = 0; i < debug_data.obstacles_to_cruise.size(); ++i) {
+ const auto marker = obstacle_cruise_utils::getObjectMarker(
+ debug_data.obstacles_to_cruise.at(i).pose, i, "obstacles_to_cruise", 0.7, 0.7, 0.0);
+ debug_marker.markers.push_back(marker);
+ }
+
+ // obstacles to stop
+ for (size_t i = 0; i < debug_data.obstacles_to_stop.size(); ++i) {
+ const auto marker = obstacle_cruise_utils::getObjectMarker(
+ debug_data.obstacles_to_stop.at(i).pose, i, "obstacles_to_stop", 1.0, 0.0, 0.0);
+ debug_marker.markers.push_back(marker);
+ }
+
+ // intentionally ignored obstacles to cruise or stop
+ for (size_t i = 0; i < debug_data.intentionally_ignored_obstacles.size(); ++i) {
+ const auto marker = obstacle_cruise_utils::getObjectMarker(
+ debug_data.intentionally_ignored_obstacles.at(i).kinematics.initial_pose_with_covariance.pose,
+ i, "intentionally_ignored_obstacles", 0.0, 1.0, 0.0);
+ debug_marker.markers.push_back(marker);
+ }
+
+ { // footprint polygons
+ auto marker = tier4_autoware_utils::createDefaultMarker(
+ "map", current_time, "detection_polygons", 0, visualization_msgs::msg::Marker::LINE_LIST,
+ tier4_autoware_utils::createMarkerScale(0.01, 0.0, 0.0),
+ tier4_autoware_utils::createMarkerColor(0.0, 1.0, 0.0, 0.999));
+
+ for (const auto & detection_polygon : debug_data.detection_polygons) {
+ for (size_t dp_idx = 0; dp_idx < detection_polygon.outer().size(); ++dp_idx) {
+ const auto & current_point = detection_polygon.outer().at(dp_idx);
+ const auto & next_point =
+ detection_polygon.outer().at((dp_idx + 1) % detection_polygon.outer().size());
+
+ marker.points.push_back(
+ tier4_autoware_utils::createPoint(current_point.x(), current_point.y(), 0.0));
+ marker.points.push_back(
+ tier4_autoware_utils::createPoint(next_point.x(), next_point.y(), 0.0));
+ }
+ }
+ debug_marker.markers.push_back(marker);
+ }
+
+ { // collision points
+ for (size_t i = 0; i < debug_data.collision_points.size(); ++i) {
+ auto marker = tier4_autoware_utils::createDefaultMarker(
+ "map", current_time, "collision_points", i, visualization_msgs::msg::Marker::SPHERE,
+ tier4_autoware_utils::createMarkerScale(0.25, 0.25, 0.25),
+ tier4_autoware_utils::createMarkerColor(1.0, 0.0, 0.0, 0.999));
+ marker.pose.position = debug_data.collision_points.at(i);
+ debug_marker.markers.push_back(marker);
+ }
+ }
+
+ debug_marker_pub_->publish(debug_marker);
+
+ // wall for cruise and stop
+ debug_cruise_wall_marker_pub_->publish(debug_data.cruise_wall_marker);
+ debug_stop_wall_marker_pub_->publish(debug_data.stop_wall_marker);
+
+ // print calculation time
+ const double calculation_time = stop_watch_.toc(__func__);
+ RCLCPP_INFO_EXPRESSION(
+ rclcpp::get_logger("ObstacleCruisePlanner"), is_showing_debug_info_, " %s := %f [ms]",
+ __func__, calculation_time);
+}
+
+void ObstacleCruisePlannerNode::publishCalculationTime(const double calculation_time) const
+{
+ Float32Stamped calculation_time_msg;
+ calculation_time_msg.stamp = now();
+ calculation_time_msg.data = calculation_time;
+ debug_calculation_time_pub_->publish(calculation_time_msg);
+}
+} // namespace motion_planning
+#include
+RCLCPP_COMPONENTS_REGISTER_NODE(motion_planning::ObstacleCruisePlannerNode)
diff --git a/planning/obstacle_cruise_planner/src/optimization_based_planner/box2d.cpp b/planning/obstacle_cruise_planner/src/optimization_based_planner/box2d.cpp
new file mode 100644
index 0000000000000..6fc5900e7ccab
--- /dev/null
+++ b/planning/obstacle_cruise_planner/src/optimization_based_planner/box2d.cpp
@@ -0,0 +1,101 @@
+// Copyright 2022 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.
+
+#include "obstacle_cruise_planner/optimization_based_planner/box2d.hpp"
+
+#include "tier4_autoware_utils/tier4_autoware_utils.hpp"
+
+#include
+
+Box2d::Box2d(const geometry_msgs::msg::Pose & center_pose, const double length, const double width)
+: center_(center_pose.position),
+ length_(length),
+ width_(width),
+ half_length_(length / 2.0),
+ half_width_(width / 2.0)
+{
+ max_x_ = std::numeric_limits