Carma-platform v4.11.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
plan_delegator.hpp
Go to the documentation of this file.
1#pragma once
2/*
3 * Copyright (C) 2022-2023 LEIDOS.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy of
7 * the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17
18#include <unordered_map>
19#include <math.h>
20#include <rclcpp/rclcpp.hpp>
21#include <gtest/gtest_prod.h>
22#include <carma_planning_msgs/msg/maneuver_plan.hpp>
23#include <carma_planning_msgs/msg/guidance_state.hpp>
24#include <carma_planning_msgs/msg/upcoming_lane_change_status.hpp>
25#include <carma_planning_msgs/srv/plan_trajectory.hpp>
26#include <carma_ros2_utils/carma_lifecycle_node.hpp>
28#include <geometry_msgs/msg/pose_stamped.hpp>
29#include <geometry_msgs/msg/twist_stamped.hpp>
30#include <autoware_msgs/msg/lamp_cmd.hpp>
31#include <tf2_ros/transform_listener.h>
32#include <tf2_ros/buffer.h>
33#include <tf2/LinearMath/Transform.h>
34#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
37#include <carma_wm/Geometry.hpp>
38#include <string>
39
40// TODO Replace this Macro if possible
47#define GET_MANEUVER_PROPERTY(mvr, property)\
48 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? (mvr).intersection_transit_left_turn_maneuver.property :\
49 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? (mvr).intersection_transit_right_turn_maneuver.property :\
50 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? (mvr).intersection_transit_straight_maneuver.property :\
51 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property :\
52 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property :\
53 ((mvr).type == carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT ? (mvr).stop_and_wait_maneuver.property :\
54 throw new std::invalid_argument("GET_MANEUVER_PROPERTY (property) called on maneuver with invalid type id"))))))))
55
56
57#define SET_MANEUVER_PROPERTY(mvr, property, value)\
58 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? (mvr).intersection_transit_left_turn_maneuver.property = (value) :\
59 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? (mvr).intersection_transit_right_turn_maneuver.property = (value) :\
60 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? (mvr).intersection_transit_straight_maneuver.property = (value) :\
61 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property = (value) :\
62 ((mvr).type == carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT ? (mvr).stop_and_wait_maneuver.property = (value) :\
63 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property = (value) :\
64 throw std::invalid_argument("ADJUST_MANEUVER_PROPERTY (property) called on maneuver with invalid type id " + std::to_string((mvr).type)))))))))
65
66
68{
72 struct Config
73 {
74 // ROS params
75 std::string planning_topic_prefix = "/plugins/";
76 std::string planning_topic_suffix = "/plan_trajectory";
79 double min_crawl_speed = 2.2352; // Min crawl speed in m/s
80 double duration_to_signal_before_lane_change = 2.5; // (Seconds) If an upcoming lane change will begin in under this time threshold, a turn signal activation command will be published.
81 int tactical_plugin_service_call_timeout = 100; // (Milliseconds) The maximum duration that Plan Delegator will wait after calling a tactical plugin's trajectory planning service; if trajectory
82 // generation takes longer than this, then planning will immediately end for the current trajectory planning iteration.
83 int max_traj_generation_reattempt = 5; // The maximum number of times plan_delegator attempts to generate a trajectory before giving up
84 bool enable_object_avoidance = true; // Activate object avoidance logic by calling yield_plugin on the final trajectory before publishing
85
86 // Stream operator for this config
87 friend std::ostream &operator<<(std::ostream &output, const Config &c)
88 {
89 output << "PlanDelegator::Config { " << std::endl
90 << "planning_topic_prefix: " << c.planning_topic_prefix << std::endl
91 << "planning_topic_suffix: " << c.planning_topic_suffix << std::endl
92 << "trajectory_planning_rate: " << c.trajectory_planning_rate << std::endl
93 << "max_trajectory_duration: " << c.max_trajectory_duration << std::endl
94 << "min_crawl_speed: " << c.min_crawl_speed << std::endl
95 << "tactical_plugin_service_call_timeout: " << c.tactical_plugin_service_call_timeout << std::endl
96 << "max_traj_generation_reattempt: " << c.max_traj_generation_reattempt << std::endl
97 << "duration_to_signal_before_lane_change: " << c.duration_to_signal_before_lane_change << std::endl
98 << "enable_object_avoidance: " << c.enable_object_avoidance << std::endl
99 << "}" << std::endl;
100 return output;
101 }
102 };
103
108 {
109 double starting_downtrack; // The starting downtrack of the lane change
110 bool is_right_lane_change; // Flag to indicate whether lane change is a right lane change; false if it is a left lane change
111 };
112
113 class PlanDelegator : public carma_ros2_utils::CarmaLifecycleNode
114 {
115 public:
116
117 // constants definition
118 static const constexpr double MILLISECOND_TO_SECOND = 0.001;
119
123 explicit PlanDelegator(const rclcpp::NodeOptions &);
124
128 void maneuverPlanCallback(carma_planning_msgs::msg::ManeuverPlan::UniquePtr plan);
129
133 void guidanceStateCallback(carma_planning_msgs::msg::GuidanceState::UniquePtr plan);
134
140 void poseCallback(geometry_msgs::msg::PoseStamped::UniquePtr pose_msg);
141
147 carma_ros2_utils::ClientPtr<carma_planning_msgs::srv::PlanTrajectory> getPlannerClientByName(const std::string& planner_name);
148
154 bool isManeuverExpired(const carma_planning_msgs::msg::Maneuver& maneuver, rclcpp::Time current_time) const;
155
164 std::shared_ptr<carma_planning_msgs::srv::PlanTrajectory::Request>
166 const carma_planning_msgs::msg::TrajectoryPlan& latest_trajectory_plan,
167 const carma_planning_msgs::msg::ManeuverPlan& locked_maneuver_plan,
168 const uint16_t& current_maneuver_index) const;
169
174
181 void updateManeuverParameters(carma_planning_msgs::msg::Maneuver& maneuver);
182
184 // Overrides
186 carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &);
187 carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &);
188
189 protected:
190 // Node configuration
192
193 // map to store service clients
194 std::unordered_map<std::string, carma_ros2_utils::ClientPtr<carma_planning_msgs::srv::PlanTrajectory>> trajectory_planners_;
195 // service client for yield_plugin, used to adjust the final trajectory before publishing to avoid obstacles
196 carma_ros2_utils::ClientPtr<carma_planning_msgs::srv::PlanTrajectory> yield_client_;
197 // local storage of incoming messages
198 carma_planning_msgs::msg::ManeuverPlan latest_maneuver_plan_;
200 geometry_msgs::msg::PoseStamped latest_pose_;
201 geometry_msgs::msg::TwistStamped latest_twist_;
202
203 // wm listener pointer and pointer to the actual wm object
206
207 private:
208 // ROS Publishers
209 std::optional<carma_planning_msgs::msg::TrajectoryPlan> last_successful_traj_;
210 carma_ros2_utils::PubPtr<carma_planning_msgs::msg::TrajectoryPlan> traj_pub_;
211 carma_ros2_utils::PubPtr<carma_planning_msgs::msg::UpcomingLaneChangeStatus> upcoming_lane_change_status_pub_;
212 carma_ros2_utils::PubPtr<autoware_msgs::msg::LampCmd> turn_signal_command_pub_;
213
214 // ROS Subscribers
215 carma_ros2_utils::SubPtr<carma_planning_msgs::msg::ManeuverPlan> plan_sub_;
216 carma_ros2_utils::SubPtr<geometry_msgs::msg::PoseStamped> pose_sub_;
217 carma_ros2_utils::SubPtr<geometry_msgs::msg::TwistStamped> twist_sub_;
218 carma_ros2_utils::SubPtr<carma_planning_msgs::msg::GuidanceState> guidance_state_sub_;
219
220 rclcpp::TimerBase::SharedPtr traj_timer_;
221 // Separate callback group for the timer to avoid blocking other callbacks like pose
222 rclcpp::CallbackGroup::SharedPtr timer_callback_group_;
223
224 bool guidance_engaged = false;
225 int consecutive_traj_gen_failure_num_ = 0; // Number of consecutive trajectory generation failures
226
228
229 // TF listenser
230 std::shared_ptr<tf2_ros::Buffer> tf2_buffer_;
231 std::shared_ptr<tf2_ros::TransformListener> tf2_listener_;
232
233 // Object to store information regarding the next upcoming lane change in latest_maneuver_plan_; empty if no upcoming lane change exists in latest_maneuver_plan_
234 boost::optional<LaneChangeInformation> upcoming_lane_change_information_;
235
236 // Object to store information regarding the current active lane change in latest_maneuver_plan_; empty if first maneuver in latest_maneuver_plan_ is not a lane change
237 boost::optional<LaneChangeInformation> current_lane_change_information_;
238
239 // The latest UpcomingLaneChangeStatus that was published to upcoming_lane_change_status_pub_.
240 carma_planning_msgs::msg::UpcomingLaneChangeStatus upcoming_lane_change_status_;
241
242 // The latest turn signal command published to turn_signal_command_pub_.
243 autoware_msgs::msg::LampCmd latest_turn_signal_command_;
244
248 void onTrajPlanTick();
249
254 bool isManeuverPlanValid(const carma_planning_msgs::msg::ManeuverPlan& maneuver_plan) const noexcept;
255
260 bool isTrajectoryValid(const carma_planning_msgs::msg::TrajectoryPlan& trajectory_plan) const noexcept;
261
266 bool isTrajectoryLongEnough(const carma_planning_msgs::msg::TrajectoryPlan& plan) const noexcept;
267
272 carma_planning_msgs::msg::TrajectoryPlan planTrajectory();
273
279 LaneChangeInformation getLaneChangeInformation(const carma_planning_msgs::msg::Maneuver& lane_change_maneuver);
280
287 void publishUpcomingLaneChangeStatus(const boost::optional<LaneChangeInformation>& upcoming_lane_change_information);
288
301 void publishTurnSignalCommand(const boost::optional<LaneChangeInformation>& current_lane_change_information, const carma_planning_msgs::msg::UpcomingLaneChangeStatus& upcoming_lane_change_status);
302
303 // Unit Test Accessors
304 FRIEND_TEST(TestPlanDelegator, UnitTestPlanDelegator);
305 FRIEND_TEST(TestPlanDelegator, TestPlanDelegator);
306 FRIEND_TEST(TestPlanDelegator, TestLaneChangeInformation);
307 FRIEND_TEST(TestPlanDelegator, TestUpcomingLaneChangeAndTurnSignals);
308 FRIEND_TEST(TestPlanDelegator, TestUpdateManeuverParameters);
309 FRIEND_TEST(TestPlanDelegator, TestGetLaneChangeInformation);
310 };
311}
Class which provies automated subscription and threading support for the world model.
Definition: WMListener.hpp:49
void onTrajPlanTick()
Callback function for triggering trajectory planning.
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::GuidanceState > guidance_state_sub_
carma_planning_msgs::msg::TrajectoryPlan planTrajectory()
Plan trajectory based on latest maneuver plan via ROS service call to plugins.
LaneChangeInformation getLaneChangeInformation(const carma_planning_msgs::msg::Maneuver &lane_change_maneuver)
Function for generating a LaneChangeInformation object from a provided lane change maneuver.
carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > yield_client_
carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > getPlannerClientByName(const std::string &planner_name)
Get PlanTrajectory service client by plugin name and create new PlanTrajectory service client if spec...
void poseCallback(geometry_msgs::msg::PoseStamped::UniquePtr pose_msg)
Callback function for vehicle pose subscriber. Updates latest_pose_ and makes calls to publishUpcomin...
carma_wm::WorldModelConstPtr wm_
carma_ros2_utils::SubPtr< geometry_msgs::msg::TwistStamped > twist_sub_
std::shared_ptr< carma_planning_msgs::srv::PlanTrajectory::Request > composePlanTrajectoryRequest(const carma_planning_msgs::msg::TrajectoryPlan &latest_trajectory_plan, const carma_planning_msgs::msg::ManeuverPlan &locked_maneuver_plan, const uint16_t &current_maneuver_index) const
Generate new PlanTrajecory service request based on current planning progress.
carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &)
boost::optional< LaneChangeInformation > upcoming_lane_change_information_
carma_ros2_utils::PubPtr< carma_planning_msgs::msg::UpcomingLaneChangeStatus > upcoming_lane_change_status_pub_
carma_planning_msgs::msg::UpcomingLaneChangeStatus upcoming_lane_change_status_
bool isTrajectoryValid(const carma_planning_msgs::msg::TrajectoryPlan &trajectory_plan) const noexcept
Example if a trajectory plan contains at least two trajectory points.
carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &)
bool isManeuverExpired(const carma_planning_msgs::msg::Maneuver &maneuver, rclcpp::Time current_time) const
Example if a maneuver end time has passed current system time.
void guidanceStateCallback(carma_planning_msgs::msg::GuidanceState::UniquePtr plan)
Callback function of guidance state subscriber.
void updateManeuverParameters(carma_planning_msgs::msg::Maneuver &maneuver)
Update the starting downtrack, ending downtrack, and maneuver-specific Lanelet ID parameters associat...
rclcpp::TimerBase::SharedPtr traj_timer_
std::shared_ptr< tf2_ros::TransformListener > tf2_listener_
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::ManeuverPlan > plan_sub_
bool isTrajectoryLongEnough(const carma_planning_msgs::msg::TrajectoryPlan &plan) const noexcept
Example if a trajectory plan is longer than configured time thresheld.
carma_planning_msgs::msg::ManeuverPlan latest_maneuver_plan_
carma_ros2_utils::PubPtr< carma_planning_msgs::msg::TrajectoryPlan > traj_pub_
carma_ros2_utils::PubPtr< autoware_msgs::msg::LampCmd > turn_signal_command_pub_
FRIEND_TEST(TestPlanDelegator, TestUpdateManeuverParameters)
boost::optional< LaneChangeInformation > current_lane_change_information_
std::unordered_map< std::string, carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > > trajectory_planners_
bool isManeuverPlanValid(const carma_planning_msgs::msg::ManeuverPlan &maneuver_plan) const noexcept
Example if a maneuver plan contains at least one maneuver.
carma_ros2_utils::SubPtr< geometry_msgs::msg::PoseStamped > pose_sub_
static const constexpr double MILLISECOND_TO_SECOND
FRIEND_TEST(TestPlanDelegator, TestLaneChangeInformation)
geometry_msgs::msg::TwistStamped latest_twist_
FRIEND_TEST(TestPlanDelegator, UnitTestPlanDelegator)
std::optional< carma_planning_msgs::msg::TrajectoryPlan > last_successful_traj_
FRIEND_TEST(TestPlanDelegator, TestPlanDelegator)
rclcpp::CallbackGroup::SharedPtr timer_callback_group_
void lookupFrontBumperTransform()
Lookup transfrom from front bumper to base link.
geometry_msgs::msg::PoseStamped latest_pose_
PlanDelegator(const rclcpp::NodeOptions &)
PlanDelegator constructor.
void maneuverPlanCallback(carma_planning_msgs::msg::ManeuverPlan::UniquePtr plan)
Callback function of maneuver plan subscriber.
std::shared_ptr< tf2_ros::Buffer > tf2_buffer_
FRIEND_TEST(TestPlanDelegator, TestGetLaneChangeInformation)
autoware_msgs::msg::LampCmd latest_turn_signal_command_
void publishTurnSignalCommand(const boost::optional< LaneChangeInformation > &current_lane_change_information, const carma_planning_msgs::msg::UpcomingLaneChangeStatus &upcoming_lane_change_status)
Function for processing an optional LaneChangeInformation object pertaining to the currently-occurrin...
void publishUpcomingLaneChangeStatus(const boost::optional< LaneChangeInformation > &upcoming_lane_change_information)
Function for processing an optional LaneChangeInformation object pertaining to an upcoming lane chang...
FRIEND_TEST(TestPlanDelegator, TestUpcomingLaneChangeAndTurnSignals)
std::shared_ptr< const WorldModel > WorldModelConstPtr
Definition: WorldModel.hpp:454
friend std::ostream & operator<<(std::ostream &output, const Config &c)
std::string planning_topic_suffix
std::string planning_topic_prefix
double duration_to_signal_before_lane_change
Convenience struct for storing information regarding a lane change maneuver.