Carma-platform v4.10.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>
27#include <geometry_msgs/msg/pose_stamped.hpp>
28#include <geometry_msgs/msg/twist_stamped.hpp>
29#include <autoware_msgs/msg/lamp_cmd.hpp>
30#include <tf2_ros/transform_listener.h>
31#include <tf2_ros/buffer.h>
32#include <tf2/LinearMath/Transform.h>
33#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
36#include <carma_wm/Geometry.hpp>
37#include <string>
38
39// TODO Replace this Macro if possible
46#define GET_MANEUVER_PROPERTY(mvr, property)\
47 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? (mvr).intersection_transit_left_turn_maneuver.property :\
48 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? (mvr).intersection_transit_right_turn_maneuver.property :\
49 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? (mvr).intersection_transit_straight_maneuver.property :\
50 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property :\
51 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property :\
52 ((mvr).type == carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT ? (mvr).stop_and_wait_maneuver.property :\
53 throw new std::invalid_argument("GET_MANEUVER_PROPERTY (property) called on maneuver with invalid type id"))))))))
54
55
56#define SET_MANEUVER_PROPERTY(mvr, property, value)\
57 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? (mvr).intersection_transit_left_turn_maneuver.property = (value) :\
58 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? (mvr).intersection_transit_right_turn_maneuver.property = (value) :\
59 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? (mvr).intersection_transit_straight_maneuver.property = (value) :\
60 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property = (value) :\
61 ((mvr).type == carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT ? (mvr).stop_and_wait_maneuver.property = (value) :\
62 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property = (value) :\
63 throw std::invalid_argument("ADJUST_MANEUVER_PROPERTY (property) called on maneuver with invalid type id " + std::to_string((mvr).type)))))))))
64
65
67{
71 struct Config
72 {
73 // ROS params
74 std::string planning_topic_prefix = "/plugins/";
75 std::string planning_topic_suffix = "/plan_trajectory";
78 double min_crawl_speed = 2.2352; // Min crawl speed in m/s
79 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.
80 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
81 // generation takes longer than this, then planning will immediately end for the current trajectory planning iteration.
82 int max_traj_generation_reattempt = 5; // The maximum number of times plan_delegator attempts to generate a trajectory before giving up
83
84 // Stream operator for this config
85 friend std::ostream &operator<<(std::ostream &output, const Config &c)
86 {
87 output << "PlanDelegator::Config { " << std::endl
88 << "planning_topic_prefix: " << c.planning_topic_prefix << std::endl
89 << "planning_topic_suffix: " << c.planning_topic_suffix << std::endl
90 << "trajectory_planning_rate: " << c.trajectory_planning_rate << std::endl
91 << "max_trajectory_duration: " << c.max_trajectory_duration << std::endl
92 << "min_crawl_speed: " << c.min_crawl_speed << std::endl
93 << "tactical_plugin_service_call_timeout: " << c.tactical_plugin_service_call_timeout << std::endl
94 << "max_traj_generation_reattempt: " << c.max_traj_generation_reattempt << std::endl
95 << "duration_to_signal_before_lane_change: " << c.duration_to_signal_before_lane_change << std::endl
96 << "}" << std::endl;
97 return output;
98 }
99 };
100
105 {
106 double starting_downtrack; // The starting downtrack of the lane change
107 bool is_right_lane_change; // Flag to indicate whether lane change is a right lane change; false if it is a left lane change
108 };
109
110 class PlanDelegator : public carma_ros2_utils::CarmaLifecycleNode
111 {
112 public:
113
114 // constants definition
115 static const constexpr double MILLISECOND_TO_SECOND = 0.001;
116
120 explicit PlanDelegator(const rclcpp::NodeOptions &);
121
125 void maneuverPlanCallback(carma_planning_msgs::msg::ManeuverPlan::UniquePtr plan);
126
130 void guidanceStateCallback(carma_planning_msgs::msg::GuidanceState::UniquePtr plan);
131
137 void poseCallback(geometry_msgs::msg::PoseStamped::UniquePtr pose_msg);
138
144 carma_ros2_utils::ClientPtr<carma_planning_msgs::srv::PlanTrajectory> getPlannerClientByName(const std::string& planner_name);
145
151 bool isManeuverExpired(const carma_planning_msgs::msg::Maneuver& maneuver, rclcpp::Time current_time) const;
152
161 std::shared_ptr<carma_planning_msgs::srv::PlanTrajectory::Request>
163 const carma_planning_msgs::msg::TrajectoryPlan& latest_trajectory_plan,
164 const carma_planning_msgs::msg::ManeuverPlan& locked_maneuver_plan,
165 const uint16_t& current_maneuver_index) const;
166
171
178 void updateManeuverParameters(carma_planning_msgs::msg::Maneuver& maneuver);
179
181 // Overrides
183 carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &);
184 carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &);
185
186 protected:
187 // Node configuration
189
190 // map to store service clients
191 std::unordered_map<std::string, carma_ros2_utils::ClientPtr<carma_planning_msgs::srv::PlanTrajectory>> trajectory_planners_;
192 // local storage of incoming messages
193 carma_planning_msgs::msg::ManeuverPlan latest_maneuver_plan_;
195 geometry_msgs::msg::PoseStamped latest_pose_;
196 geometry_msgs::msg::TwistStamped latest_twist_;
197
198 // wm listener pointer and pointer to the actual wm object
201
202 private:
203 // ROS Publishers
204 std::optional<carma_planning_msgs::msg::TrajectoryPlan> last_successful_traj_;
205 carma_ros2_utils::PubPtr<carma_planning_msgs::msg::TrajectoryPlan> traj_pub_;
206 carma_ros2_utils::PubPtr<carma_planning_msgs::msg::UpcomingLaneChangeStatus> upcoming_lane_change_status_pub_;
207 carma_ros2_utils::PubPtr<autoware_msgs::msg::LampCmd> turn_signal_command_pub_;
208
209 // ROS Subscribers
210 carma_ros2_utils::SubPtr<carma_planning_msgs::msg::ManeuverPlan> plan_sub_;
211 carma_ros2_utils::SubPtr<geometry_msgs::msg::PoseStamped> pose_sub_;
212 carma_ros2_utils::SubPtr<geometry_msgs::msg::TwistStamped> twist_sub_;
213 carma_ros2_utils::SubPtr<carma_planning_msgs::msg::GuidanceState> guidance_state_sub_;
214
215 rclcpp::TimerBase::SharedPtr traj_timer_;
216 // Separate callback group for the timer to avoid blocking other callbacks like pose
217 rclcpp::CallbackGroup::SharedPtr timer_callback_group_;
218
219 bool guidance_engaged = false;
220 int consecutive_traj_gen_failure_num_ = 0; // Number of consecutive trajectory generation failures
221
223
224 // TF listenser
225 std::shared_ptr<tf2_ros::Buffer> tf2_buffer_;
226 std::shared_ptr<tf2_ros::TransformListener> tf2_listener_;
227
228 // 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_
229 boost::optional<LaneChangeInformation> upcoming_lane_change_information_;
230
231 // 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
232 boost::optional<LaneChangeInformation> current_lane_change_information_;
233
234 // The latest UpcomingLaneChangeStatus that was published to upcoming_lane_change_status_pub_.
235 carma_planning_msgs::msg::UpcomingLaneChangeStatus upcoming_lane_change_status_;
236
237 // The latest turn signal command published to turn_signal_command_pub_.
238 autoware_msgs::msg::LampCmd latest_turn_signal_command_;
239
243 void onTrajPlanTick();
244
249 bool isManeuverPlanValid(const carma_planning_msgs::msg::ManeuverPlan& maneuver_plan) const noexcept;
250
255 bool isTrajectoryValid(const carma_planning_msgs::msg::TrajectoryPlan& trajectory_plan) const noexcept;
256
261 bool isTrajectoryLongEnough(const carma_planning_msgs::msg::TrajectoryPlan& plan) const noexcept;
262
267 carma_planning_msgs::msg::TrajectoryPlan planTrajectory();
268
274 LaneChangeInformation getLaneChangeInformation(const carma_planning_msgs::msg::Maneuver& lane_change_maneuver);
275
282 void publishUpcomingLaneChangeStatus(const boost::optional<LaneChangeInformation>& upcoming_lane_change_information);
283
296 void publishTurnSignalCommand(const boost::optional<LaneChangeInformation>& current_lane_change_information, const carma_planning_msgs::msg::UpcomingLaneChangeStatus& upcoming_lane_change_status);
297
298 // Unit Test Accessors
299 FRIEND_TEST(TestPlanDelegator, UnitTestPlanDelegator);
300 FRIEND_TEST(TestPlanDelegator, TestPlanDelegator);
301 FRIEND_TEST(TestPlanDelegator, TestLaneChangeInformation);
302 FRIEND_TEST(TestPlanDelegator, TestUpcomingLaneChangeAndTurnSignals);
303 FRIEND_TEST(TestPlanDelegator, TestUpdateManeuverParameters);
304 };
305}
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 > 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_
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.