Carma-platform v4.2.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.
platoon_strategic_ihp::PlatoonStrategicIHPPlugin Class Reference

Class containing the logic for Strategic IHP Plugin. This class is responsible for all the negotiations as well as generating a maneuver msg. More...

#include <platoon_strategic_ihp.h>

Collaboration diagram for platoon_strategic_ihp::PlatoonStrategicIHPPlugin:
Collaboration graph

Public Member Functions

 PlatoonStrategicIHPPlugin (carma_wm::WorldModelConstPtr wm, PlatoonPluginConfig config, MobilityResponseCB mobility_response_publisher, MobilityRequestCB mobility_request_publisher, MobilityOperationCB mobility_operation_publisher, PlatooningInfoCB platooning_info_publisher, std::shared_ptr< carma_ros2_utils::timers::TimerFactory > timer_factory)
 Constructor. More...
 
void mob_op_cb (const carma_v2x_msgs::msg::MobilityOperation::UniquePtr msg)
 Callback function for Mobility Operation Message. More...
 
void mob_req_cb (const carma_v2x_msgs::msg::MobilityRequest::UniquePtr msg)
 Callback function for Mobility Request Message. More...
 
void mob_resp_cb (const carma_v2x_msgs::msg::MobilityResponse::UniquePtr msg)
 Callback function for Mobility Response Message. More...
 
MobilityRequestResponse handle_mob_req (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to the process and respond to the mobility request. More...
 
bool plan_maneuver_cb (carma_planning_msgs::srv::PlanManeuvers::Request &req, carma_planning_msgs::srv::PlanManeuvers::Response &resp)
 Callback function to the maneuver request. More...
 
int findLaneletIndexFromPath (int target_id, lanelet::routing::LaneletPath &path)
 Find lanelet index from path. More...
 
double findLaneWidth ()
 Find lanelet width from local position. More...
 
carma_planning_msgs::msg::Maneuver composeManeuverMessage (double current_dist, double end_dist, double current_speed, double target_speed, int lane_id, rclcpp::Time &current_time)
 Find lanelet index from path. More...
 
carma_planning_msgs::msg::Maneuver composeLaneChangeManeuverMessage (double current_dist, double end_dist, double current_speed, double target_speed, int starting_lane_id, int ending_lane_id, rclcpp::Time &current_time)
 Find start(current) and target(end) lanelet index from path to generate lane change maneuver message. More...
 
void updateCurrentStatus (carma_planning_msgs::msg::Maneuver maneuver, double &speed, double &current_progress, int &lane_id)
 Update maneuver status based on prior plan. More...
 
void pose_cb (const geometry_msgs::msg::PoseStamped::UniquePtr msg)
 Callback function for current pose. More...
 
carma_planning_msgs::msg::PlatooningInfo composePlatoonInfoMsg ()
 Compose Platoon information message. More...
 
void twist_cb (const geometry_msgs::msg::TwistStamped::UniquePtr msg)
 Callback for the twist subscriber, which will store latest twist locally. More...
 
void cmd_cb (const geometry_msgs::msg::TwistStamped::UniquePtr msg)
 Callback for the control command. More...
 
void georeference_cb (const std_msgs::msg::String::UniquePtr msg)
 Callback for the georeference. More...
 
bool onSpin ()
 Spin callback function. More...
 
void run_leader ()
 Run Leader State. More...
 
void run_leader_waiting ()
 Run Leader Waiting State. More...
 
void run_candidate_follower ()
 Run Candidate Follower State. More...
 
void run_follower ()
 Run Follower State. More...
 
void run_leader_aborting ()
 Run Leader Aborting State. More...
 
void run_candidate_leader ()
 Run Candidate Leader State. More...
 
void run_lead_with_operation ()
 UCLA Run lead with operation State. More...
 
void run_prepare_to_join ()
 UCLA Run prepare to join State. More...
 
void setHostECEF (carma_v2x_msgs::msg::LocationECEF pose_ecef_point)
 UCLA Update the private variable pose_ecef_point_. More...
 
PlatoonManager getHostPM ()
 UCLA Getter: for PlatoonManager class. More...
 
void setPMState (PlatoonState desiredState)
 UCLA Setter: function to set pm_.platoon_state. More...
 
void updatePlatoonList (std::vector< PlatoonMember > platoon_list)
 UCLA Setter: Update platoon list (Unit Test). More...
 
void setConfig (const PlatoonPluginConfig &config)
 Set the current config. More...
 

Public Attributes

carma_v2x_msgs::msg::LocationECEF pose_ecef_point_
 

Private Member Functions

bool isVehicleRightInFront (double downtrack, double crosstrack)
 Function to determine if a target vehicle is in the front of host vehicle note: This is only applicable for same lane application, so it will check cross track distance. More...
 
double findSpeedLimit (const lanelet::ConstLanelet &llt)
 Function to find speed limit of a lanelet. More...
 
MobilityRequestResponse mob_req_cb_leader (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in leader state. More...
 
MobilityRequestResponse mob_req_cb_leaderwaiting (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in leader waiting state. More...
 
MobilityRequestResponse mob_req_cb_follower (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in follower state. More...
 
MobilityRequestResponse mob_req_cb_candidatefollower (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in candidate follower state. More...
 
MobilityRequestResponse mob_req_cb_standby (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in standby state. More...
 
void mob_resp_cb_leader (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in leader state. More...
 
void mob_resp_cb_leaderwaiting (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in leader waiting state. More...
 
void mob_resp_cb_follower (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in follower state. More...
 
void mob_resp_cb_candidatefollower (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in candidate follower state. More...
 
void mob_resp_cb_standby (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in standby state. More...
 
void mob_op_cb_leader (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in leader state. More...
 
void mob_op_cb_leaderwaiting (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in leader waiting state. More...
 
void mob_op_cb_follower (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in follower state. More...
 
void mob_op_cb_candidatefollower (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in candidate follower state. More...
 
void mob_op_cb_standby (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in standby state. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeader (const std::string &type)
 Function to compose mobility operation in leader state. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationFollower ()
 Function to compose mobility operation in follower state. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeaderWaiting ()
 Function to compose mobility operation in leader waiting state. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationCandidateFollower ()
 Function to compose mobility operation in candidate follower state. More...
 
carma_v2x_msgs::msg::LocationECEF pose_to_ecef (geometry_msgs::msg::PoseStamped pose_msg)
 Function to convert pose from map frame to ecef location. More...
 
lanelet::BasicPoint2d ecef_to_map_point (carma_v2x_msgs::msg::LocationECEF ecef_point)
 Function to convert ecef location to a 2d point in map frame. More...
 
bool isVehicleRightBehind (double downtrack, double crosstrack)
 Function to determine if the given downtrack distance (m) is behind the host vehicle. More...
 
bool isJoiningVehicleNearPlatoon (double joining_downtrack, double joining_crosstrack)
 The method for platoon leader to determine if the joining vehicle is closeby. (Note: Used when host vehicle is the platoon leader) More...
 
bool isVehicleNearTargetPlatoon (double rearVehicleDtd, double frontVehicleDtd, double frontVehicleCtd)
 Function to determine if the host vehicle is close to the target platoon (used for cut-in join scenarios). More...
 
int find_target_lanelet_id (double start_downtrack, double end_downtrack)
 Function to find the starting and ending lanelet ID for lane change in a two-lane scenario (used for cut-in join scenarios). More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationSTATUS ()
 Function to compose mobility operation message with STATUS params. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationINFO ()
 Function to compose mobility operation message with INFO params. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeaderAborting ()
 Function to compose mobility operation in LeaderAborting state. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationCandidateLeader ()
 Function to compose mobility operation in CandidateLeader. More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeadWithOperation (const std::string &type)
 Function to compose mobility operation in LeadWithOperation (cut-in join) More...
 
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationPrepareToJoin ()
 Function to compose mobility operation in PrepareToJoin (cut-in join) More...
 
void mob_op_cb_STATUS (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation message with STATUS params, read ecef location and update platoon member info. More...
 
double mob_op_find_platoon_length_from_INFO_params (std::string strategyParams)
 Function to process mobility operation INFO params to find platoon length in m. More...
 
carma_v2x_msgs::msg::LocationECEF mob_op_find_ecef_from_INFO_params (std::string strategyParams)
 Function to process mobility operation INFO params to find platoon leader's ecef location. More...
 
carma_v2x_msgs::msg::LocationECEF mob_op_find_ecef_from_STATUS_params (std::string strategyParams)
 Function to process mobility operation for STATUS params. More...
 
void mob_op_cb_leaderaborting (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in leaderaborting state. More...
 
void mob_op_cb_candidateleader (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in candidateleader state. More...
 
void mob_op_cb_leadwithoperation (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in LeadWithOperation state (cut-in join) More...
 
void mob_op_cb_preparetojoin (const carma_v2x_msgs::msg::MobilityOperation &msg)
 Function to process mobility operation in PrepareToJoin state (cut-in join) More...
 
MobilityRequestResponse mob_req_cb_leaderaborting (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in leaderaborting state. More...
 
MobilityRequestResponse mob_req_cb_candidateleader (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in candidateleader state. More...
 
MobilityRequestResponse mob_req_cb_leadwithoperation (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in leadwithoperation state (cut-in join) More...
 
MobilityRequestResponse mob_req_cb_preparetojoin (const carma_v2x_msgs::msg::MobilityRequest &msg)
 Function to process mobility request in preparetojoin state (cut-in join) More...
 
void mob_resp_cb_leaderaborting (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in leaderaborting state. More...
 
void mob_resp_cb_candidateleader (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in candidateleader state. More...
 
void mob_resp_cb_leadwithoperation (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in leadwithoperation state (cut-in join) More...
 
void mob_resp_cb_preparetojoin (const carma_v2x_msgs::msg::MobilityResponse &msg)
 Function to process mobility response in preparetojoin state. More...
 
bool is_lanechange_possible (lanelet::Id start_lanelet_id, lanelet::Id target_lanelet_id)
 Function to check if lanechange is possible. More...
 
 FRIEND_TEST (PlatoonStrategicIHPPlugin, platoon_info_pub_front)
 
 FRIEND_TEST (PlatoonStrategicIHPPlugin, is_lanechange_possible)
 

Private Attributes

MobilityRequestCB mobility_request_publisher_
 
MobilityResponseCB mobility_response_publisher_
 
MobilityOperationCB mobility_operation_publisher_
 
PlatooningInfoCB platooning_info_publisher_
 
carma_wm::WorldModelConstPtr wm_
 
PlatoonPluginConfig config_
 
geometry_msgs::msg::PoseStamped pose_msg_
 
double cmd_speed_ = 0
 
double current_speed_ = 0
 
double current_downtrack_ = 0
 
double current_crosstrack_ = 0
 
long waitingStartTime = 0
 
long candidatestateStartTime = 0
 
std::string HostMobilityId = "hostid"
 
std::string georeference_ {""}
 
std::shared_ptr< lanelet::projection::LocalFrameProjector > map_projector_
 
bool map_loaded_ = false
 
carma_planning_msgs::msg::Plugin plugin_discovery_msg_
 
int numLeaderAbortingCalls_ = 0
 
int candidate_follower_delay_count_ = 0
 
double maxAllowedJoinTimeGap_ = 15.0
 
double maxAllowedJoinGap_ = 90
 
int maxPlatoonSize_ = 10
 
double vehicleLength_ = 5.0
 
unsigned long infoMessageInterval_ = 200
 
unsigned long prevHeartBeatTime_ = 0.0
 
int statusMessageInterval_ = 100
 
unsigned long NEGOTIATION_TIMEOUT = 15000
 
unsigned long LANE_CHANGE_TIMEOUT = 300000
 
int noLeaderUpdatesCounter = 0
 
int LEADER_TIMEOUT_COUNTER_LIMIT = 5
 
double waitingStateTimeout = 25.0
 
double desiredJoinGap = 30.0
 
double desiredJoinTimeGap = 4.0
 
lanelet::BasicPoint2d target_cutin_pose_
 
const double STOPPED_SPEED = 0.5
 
int target_join_index_ = -2
 
bool safeToLaneChange_ = false
 
std::shared_ptr< carma_ros2_utils::timers::TimerFactory > timer_factory_
 
PlatoonManager pm_
 
const std::string PLATOONING_STRATEGY = "Carma/Platooning"
 
const std::string OPERATION_INFO_TYPE = "INFO"
 
const std::string OPERATION_STATUS_TYPE = "STATUS"
 
const std::string OPERATION_INFO_PARAMS = "INFO|LENGTH:%.2f,SPEED:%.2f,SIZE:%d,ECEFX:%.2f,ECEFY:%.2f,ECEFZ:%.2f"
 
const std::string OPERATION_STATUS_PARAMS = "STATUS|CMDSPEED:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%"
 
const std::string JOIN_PARAMS = "SIZE:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%,JOINIDX:%6%"
 

Detailed Description

Class containing the logic for Strategic IHP Plugin. This class is responsible for all the negotiations as well as generating a maneuver msg.

Definition at line 69 of file platoon_strategic_ihp.h.

Constructor & Destructor Documentation

◆ PlatoonStrategicIHPPlugin()

platoon_strategic_ihp::PlatoonStrategicIHPPlugin::PlatoonStrategicIHPPlugin ( carma_wm::WorldModelConstPtr  wm,
PlatoonPluginConfig  config,
MobilityResponseCB  mobility_response_publisher,
MobilityRequestCB  mobility_request_publisher,
MobilityOperationCB  mobility_operation_publisher,
PlatooningInfoCB  platooning_info_publisher,
std::shared_ptr< carma_ros2_utils::timers::TimerFactory >  timer_factory 
)

Constructor.

Parameters
wmPointer to initalized instance of the carma world model for accessing semantic map data
configThe configuration to be used for this object

Definition at line 36 of file platoon_strategic_ihp.cpp.

40 : mobility_request_publisher_(mobility_request_publisher),
41 mobility_response_publisher_(mobility_response_publisher), mobility_operation_publisher_(mobility_operation_publisher),
42 platooning_info_publisher_(platooning_info_publisher), wm_(wm), config_(config), timer_factory_(timer_factory), pm_(timer_factory_)
43 {
44 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Top of PlatoonStrategicIHP ctor.");
45 std::string hostStaticId = config_.vehicleID; //static ID for this vehicle
46 pm_.HostMobilityId = hostStaticId;
47 // construct platoon member for host vehicle as the first element in the vector, since it starts life as a solo vehicle
48 long cur_t = timer_factory_->now().nanoseconds()/1000000; // time in millisecond
49 PlatoonMember hostVehicleMember = PlatoonMember(hostStaticId, 0.0, 0.0, 0.0, 0.0, cur_t);
50 pm_.host_platoon_.push_back(hostVehicleMember);
51 plugin_discovery_msg_.name = "platoon_strategic_ihp";
52 plugin_discovery_msg_.version_id = "v1.0";
53 plugin_discovery_msg_.available = true;
54 plugin_discovery_msg_.activated = true;
55 plugin_discovery_msg_.type = carma_planning_msgs::msg::Plugin::STRATEGIC;
56 plugin_discovery_msg_.capability = "strategic_plan/plan_maneuvers";
57 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "ctor complete. hostStaticId = " << hostStaticId);
58 }
std::vector< PlatoonMember > host_platoon_
std::shared_ptr< carma_ros2_utils::timers::TimerFactory > timer_factory_
carma_planning_msgs::msg::Plugin plugin_discovery_msg_

References config_, platoon_strategic_ihp::PlatoonManager::host_platoon_, platoon_strategic_ihp::PlatoonManager::HostMobilityId, plugin_discovery_msg_, pm_, timer_factory_, and platoon_strategic_ihp::PlatoonPluginConfig::vehicleID.

Member Function Documentation

◆ cmd_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::cmd_cb ( const geometry_msgs::msg::TwistStamped::UniquePtr  msg)

Callback for the control command.

Parameters
msgLatest twist cmd message

Definition at line 137 of file platoon_strategic_ihp.cpp.

138 {
139 cmd_speed_ = msg->twist.linear.x;
140 }

References cmd_speed_.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the caller graph for this function:

◆ composeLaneChangeManeuverMessage()

carma_planning_msgs::msg::Maneuver platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeLaneChangeManeuverMessage ( double  current_dist,
double  end_dist,
double  current_speed,
double  target_speed,
int  starting_lane_id,
int  ending_lane_id,
rclcpp::Time &  current_time 
)

Find start(current) and target(end) lanelet index from path to generate lane change maneuver message.

Parameters
current_distcurrent downtrack distance
end_distending downtrack distance
current_speedcurrent speed
target_speedtarget speed
starting_lane_idcurrent lanelet id which serves as the starting lanlet id
ending_lane_idtarget lanelet id which is also the ending lanelet id that is in another lane
current_timecurrent time in seconds
Returns
Maneuver message

Definition at line 3165 of file platoon_strategic_ihp.cpp.

3166 {
3167 carma_planning_msgs::msg::Maneuver maneuver_msg;
3168 // UCLA: change to lane change maneuvers
3169 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_CHANGE;
3170 maneuver_msg.lane_change_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::PLATOONING;
3171 maneuver_msg.lane_change_maneuver.parameters.presence_vector = carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
3172 maneuver_msg.lane_change_maneuver.parameters.planning_tactical_plugin = "cooperative_lanechange";
3173 maneuver_msg.lane_change_maneuver.parameters.planning_strategic_plugin = "platoon_strategic_ihp";
3174 maneuver_msg.lane_change_maneuver.start_dist = current_dist;
3175 maneuver_msg.lane_change_maneuver.start_speed = current_speed;
3176 maneuver_msg.lane_change_maneuver.start_time = current_time;
3177 maneuver_msg.lane_change_maneuver.end_dist = end_dist;
3178 maneuver_msg.lane_change_maneuver.end_speed = target_speed;
3179 // Generate a new maneuver ID for the lane change maneuver (not needed for lane following maneuver).
3180 maneuver_msg.lane_following_maneuver.parameters.maneuver_id = boost::uuids::to_string(boost::uuids::random_generator()());
3181
3182 // because it is a rough plan, assume vehicle can always reach to the target speed in a lanelet
3183 double cur_plus_target = current_speed + target_speed;
3184 if (cur_plus_target < 0.00001)
3185 {
3186 maneuver_msg.lane_change_maneuver.end_time = current_time + rclcpp::Duration(config_.time_step*1e9);
3187 }
3188 else
3189 {
3190 // maneuver_msg.lane_change_maneuver.end_time = current_time + rclcpp::Duration((end_dist - current_dist) / (0.5 * cur_plus_target));
3191 maneuver_msg.lane_change_maneuver.end_time = current_time + rclcpp::Duration(20.0*1e9);
3192
3193 }
3194
3195 // UCLA: need both start laneID and end laneID for lane change
3196 maneuver_msg.lane_change_maneuver.starting_lane_id = { std::to_string(starting_lane_id) };
3197 maneuver_msg.lane_change_maneuver.ending_lane_id = { std::to_string(ending_lane_id) };
3198
3199 current_time = maneuver_msg.lane_change_maneuver.end_time;
3200 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Creating lane change start dist:"<<current_dist<<" end dist:"<<end_dist);
3201 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Duration:"<< rclcpp::Time(maneuver_msg.lane_change_maneuver.end_time).seconds() - rclcpp::Time(maneuver_msg.lane_change_maneuver.start_time).seconds());
3202 return maneuver_msg;
3203 }
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21

References config_, platoon_strategic_ihp::PlatoonPluginConfig::time_step, and carma_cooperative_perception::to_string().

Referenced by plan_maneuver_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeManeuverMessage()

carma_planning_msgs::msg::Maneuver platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeManeuverMessage ( double  current_dist,
double  end_dist,
double  current_speed,
double  target_speed,
int  lane_id,
rclcpp::Time &  current_time 
)

Find lanelet index from path.

Parameters
current_distcurrent downtrack distance (m)
end_distending downtrack distance (m)
current_speedcurrent speed (m/s)
target_speedtarget speed (m/s)
lane_idlanelet id
current_timecurrent time (s)
Returns
Maneuver message

Definition at line 3125 of file platoon_strategic_ihp.cpp.

3126 {
3127 carma_planning_msgs::msg::Maneuver maneuver_msg;
3128 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING;
3129 maneuver_msg.lane_following_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::PLATOONING;
3130 maneuver_msg.lane_following_maneuver.parameters.presence_vector = carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
3131 maneuver_msg.lane_following_maneuver.parameters.planning_tactical_plugin = "platooning_tactical_plugin";
3132 maneuver_msg.lane_following_maneuver.parameters.planning_strategic_plugin = "platoon_strategic_ihp";
3133 maneuver_msg.lane_following_maneuver.start_dist = current_dist;
3134 maneuver_msg.lane_following_maneuver.start_speed = current_speed;
3135 maneuver_msg.lane_following_maneuver.start_time = current_time;
3136 maneuver_msg.lane_following_maneuver.end_dist = end_dist;
3137 maneuver_msg.lane_following_maneuver.end_speed = target_speed;
3138
3139 // because it is a rough plan, assume vehicle can always reach to the target speed in a lanelet
3140 maneuver_msg.lane_following_maneuver.end_time = current_time + rclcpp::Duration(config_.time_step*1e9);
3141 maneuver_msg.lane_following_maneuver.lane_ids = { std::to_string(lane_id) };
3142
3143 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "in compose maneuver lane id:"<< lane_id);
3144
3145 lanelet::ConstLanelet current_lanelet = wm_->getMap()->laneletLayer.get(lane_id);
3146 if(!wm_->getMapRoutingGraph()->following(current_lanelet, false).empty())
3147 {
3148
3149 auto next_lanelet_id = wm_->getMapRoutingGraph()->following(current_lanelet, false).front().id();
3150 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "next_lanelet_id:"<< next_lanelet_id);
3151 maneuver_msg.lane_following_maneuver.lane_ids.push_back(std::to_string(next_lanelet_id));
3152 }
3153 else
3154 {
3155 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "No following lanelets");
3156 }
3157
3158 current_time = maneuver_msg.lane_following_maneuver.end_time;
3159 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Creating lane follow start dist:"<<current_dist<<" end dist:"<<end_dist);
3160 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Duration:"<< rclcpp::Time(maneuver_msg.lane_following_maneuver.end_time).seconds() - rclcpp::Time(maneuver_msg.lane_following_maneuver.start_time).seconds());
3161 return maneuver_msg;
3162 }

References config_, platoon_strategic_ihp::PlatoonPluginConfig::time_step, carma_cooperative_perception::to_string(), and wm_.

Referenced by plan_maneuver_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationCandidateFollower()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationCandidateFollower ( )
private

Function to compose mobility operation in candidate follower state.

Returns
mobility operation msg

Definition at line 604 of file platoon_strategic_ihp.cpp.

605 {
606 carma_v2x_msgs::msg::MobilityOperation msg;
608 return msg;
609 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationSTATUS()
Function to compose mobility operation message with STATUS params.

References composeMobilityOperationSTATUS().

Referenced by run_candidate_follower().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationCandidateLeader()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationCandidateLeader ( )
private

Function to compose mobility operation in CandidateLeader.

Returns
mobility operation msg.

Definition at line 624 of file platoon_strategic_ihp.cpp.

625 {
626 /*
627 UCLA Implementation note:
628 This is the joiner which will later become the new leader,
629 host vehicle publish status msgs and waiting to lead the rear platoon
630 */
631 carma_v2x_msgs::msg::MobilityOperation msg;
633 return msg;
634 }

References composeMobilityOperationSTATUS().

Referenced by run_candidate_leader().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationFollower()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationFollower ( )
private

Function to compose mobility operation in follower state.

Returns
mobility operation msg

Definition at line 586 of file platoon_strategic_ihp.cpp.

587 {
588 carma_v2x_msgs::msg::MobilityOperation msg;
590 return msg;
591 }

References composeMobilityOperationSTATUS().

Referenced by run_follower().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationINFO()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationINFO ( )
private

Function to compose mobility operation message with INFO params.

Returns
mobility operation msg.

Note: INFO param format: "INFO| --> LENGTH:%.2f,SPEED:%.2f,SIZE:%d,ECEFX:%.2f,ECEFY:%.2f,ECEFZ:%.2f" |----—0--------—1------—2-----—3-------—4-------—5----—|

Definition at line 317 of file platoon_strategic_ihp.cpp.

318 {
324 carma_v2x_msgs::msg::MobilityOperation msg;
325 msg.m_header.plan_id = pm_.currentPlatoonID; // msg.m_header.plan_id is the platoon ID of the request sender (rear join and frontal join).
326 msg.m_header.recipient_id = "";
327 std::string hostStaticId = config_.vehicleID;
328 msg.m_header.sender_id = hostStaticId;
329 msg.m_header.timestamp = timer_factory_->now().nanoseconds() / 1000000;;
330 msg.strategy = PLATOONING_STRATEGY;
331
332 double CurrentPlatoonLength = pm_.getCurrentPlatoonLength();
333 int PlatoonSize = pm_.getHostPlatoonSize();
334
335 boost::format fmter(OPERATION_INFO_PARAMS);
336 // Note: need to update "OPERATION_INFO_PARAMS" in m_header file --> strategic_platoon_ihp.h
337 fmter% CurrentPlatoonLength; // index = 0, physical length of the platoon, in m.
338 fmter% current_speed_; // index = 1, in m/s.
339 fmter% PlatoonSize; // index = 2, number of members
340 fmter% pose_ecef_point_.ecef_x; // index = 3, in cm.
341 fmter% pose_ecef_point_.ecef_y; // index = 4, in cm.
342 fmter% pose_ecef_point_.ecef_z; // index = 5, in cm.
343
344 std::string infoParams = fmter.str();
345 msg.strategy_params = infoParams;
346 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Composed a mobility operation message with params " << msg.strategy_params);
347 return msg;
348 }
int getHostPlatoonSize()
Returns total size of the platoon , in number of vehicles.
double getCurrentPlatoonLength()
Returns overall length of the platoon. in m.
carma_v2x_msgs::msg::LocationECEF pose_ecef_point_

References config_, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::getCurrentPlatoonLength(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), OPERATION_INFO_PARAMS, PLATOONING_STRATEGY, pm_, pose_ecef_point_, timer_factory_, and platoon_strategic_ihp::PlatoonPluginConfig::vehicleID.

Referenced by composeMobilityOperationLeader(), and composeMobilityOperationLeadWithOperation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationLeader()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationLeader ( const std::string &  type)
private

Function to compose mobility operation in leader state.

Parameters
typetype of mobility operation (info or status)
Returns
mobility operation msg

Definition at line 561 of file platoon_strategic_ihp.cpp.

562 {
563 carma_v2x_msgs::msg::MobilityOperation msg;
564
565 // info params
566 if (type == OPERATION_INFO_TYPE)
567 {
569 }
570
571 // status params
572 else if (type == OPERATION_STATUS_TYPE)
573 {
575 }
576 // Unknown strategy param.
577 else
578 {
579 RCLCPP_ERROR(rclcpp::get_logger("platoon_strategic_ihp"),"UNKNOWN strategy param string!!!");
580 msg.strategy_params = "";
581 }
582 return msg;
583 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationINFO()
Function to compose mobility operation message with INFO params.

References composeMobilityOperationINFO(), composeMobilityOperationSTATUS(), OPERATION_INFO_TYPE, and OPERATION_STATUS_TYPE.

Referenced by run_leader().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationLeaderAborting()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationLeaderAborting ( )
private

Function to compose mobility operation in LeaderAborting state.

Returns
mobility operation msg.

Definition at line 612 of file platoon_strategic_ihp.cpp.

613 {
614 /*
615 UCLA Implementation note:
616 Sending STATUS info for member updates and platoon trajectory regulation.
617 */
618 carma_v2x_msgs::msg::MobilityOperation msg;
620 return msg;
621 }

References composeMobilityOperationSTATUS().

Referenced by run_leader_aborting().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationLeaderWaiting()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationLeaderWaiting ( )
private

Function to compose mobility operation in leader waiting state.

Returns
mobility operation msg

Definition at line 594 of file platoon_strategic_ihp.cpp.

595 {
596 //TODO: shouldn't a leaderwaiting also be sending INFO messages since it is still leading?
597
598 carma_v2x_msgs::msg::MobilityOperation msg;
600 return msg;
601 }

References composeMobilityOperationSTATUS().

Referenced by run_leader_waiting().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationLeadWithOperation()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationLeadWithOperation ( const std::string &  type)
private

Function to compose mobility operation in LeadWithOperation (cut-in join)

Parameters
typetype of mobility operation (info or status)
Returns
msg: mobility operation msg Return null ("") if the incoming message is trashed/unrecognized.

Definition at line 649 of file platoon_strategic_ihp.cpp.

650 {
651 carma_v2x_msgs::msg::MobilityOperation msg;
652
653 // info params
654 if (type == OPERATION_INFO_TYPE)
655 {
657 }
658
659 // status params
660 else if (type == OPERATION_STATUS_TYPE)
661 {
663 }
664 // Unknown strategy param.
665 else
666 {
667 RCLCPP_ERROR(rclcpp::get_logger("platoon_strategic_ihp"),"UNKNOWN strategy param string!!!");
668 msg.strategy_params = "";
669 }
670 return msg;
671 }

References composeMobilityOperationINFO(), composeMobilityOperationSTATUS(), OPERATION_INFO_TYPE, and OPERATION_STATUS_TYPE.

Referenced by run_lead_with_operation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationPrepareToJoin()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationPrepareToJoin ( )
private

Function to compose mobility operation in PrepareToJoin (cut-in join)

Parameters
typetype of mobility operation (info or status)
Returns
msg: mobility operation msg Return null ("") if the incoming message is trashed/unrecognized.

Definition at line 637 of file platoon_strategic_ihp.cpp.

638 {
639 /*
640 UCLA Implementation note:
641 This is the joiner that is preapring for cut-in join.
642 host vehicle publish status msgs and waiting to lead the rear platoon.
643 */
644 carma_v2x_msgs::msg::MobilityOperation msg;
646 return msg;
647 }

References composeMobilityOperationSTATUS().

Referenced by run_prepare_to_join().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeMobilityOperationSTATUS()

carma_v2x_msgs::msg::MobilityOperation platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composeMobilityOperationSTATUS ( )
private

Function to compose mobility operation message with STATUS params.

Returns
mobility operation msg.

Note: STATUS params format: STATUS | --> "CMDSPEED:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%" |-------—0-------—1------—2------—3------—4---—|

Definition at line 280 of file platoon_strategic_ihp.cpp.

281 {
288 //TODO future: consider setting recipient_id to the platoon ID to make it obvious that anyone in that group is intended reader.
289 // This requires an architectural agreement on use of group messaging protocol.
290
291 // Extract data
292 carma_v2x_msgs::msg::MobilityOperation msg;
293 msg.m_header.plan_id = pm_.currentPlatoonID;
294 msg.m_header.recipient_id = "";
295 std::string hostStaticId = config_.vehicleID;
296 msg.m_header.sender_id = hostStaticId;
297 msg.m_header.timestamp = timer_factory_->now().nanoseconds() / 1000000;
298 msg.strategy = PLATOONING_STRATEGY;
299
300 // form message
301 double cmdSpeed = cmd_speed_;
302 boost::format fmter(OPERATION_STATUS_PARAMS);
303 fmter% cmdSpeed; // index = 0, in m/s.
304 fmter% current_speed_; // index = 1, in m/s.
305 fmter% pose_ecef_point_.ecef_x; // index = 2, in cm.
306 fmter% pose_ecef_point_.ecef_y; // index = 3, in cm.
307 fmter% pose_ecef_point_.ecef_z; // index = 4, in cm.
308
309 // compose message
310 std::string statusParams = fmter.str();
311 msg.strategy_params = statusParams;
312 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Composed a mobility operation message with params " << msg.strategy_params);
313 return msg;
314 }

References cmd_speed_, config_, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, OPERATION_STATUS_PARAMS, PLATOONING_STRATEGY, pm_, pose_ecef_point_, timer_factory_, and platoon_strategic_ihp::PlatoonPluginConfig::vehicleID.

Referenced by composeMobilityOperationCandidateFollower(), composeMobilityOperationCandidateLeader(), composeMobilityOperationFollower(), composeMobilityOperationLeader(), composeMobilityOperationLeaderAborting(), composeMobilityOperationLeaderWaiting(), composeMobilityOperationLeadWithOperation(), and composeMobilityOperationPrepareToJoin().

Here is the caller graph for this function:

◆ composePlatoonInfoMsg()

carma_planning_msgs::msg::PlatooningInfo platoon_strategic_ihp::PlatoonStrategicIHPPlugin::composePlatoonInfoMsg ( )

Compose Platoon information message.

Returns
PlatooningInfo msg

Note: There is a difference between the "platoon info status" versus the the "platoon strategic plugin states".

  [platooning info status]
  The "platooning info status" reflect the overall operating status. The status can
  include vehicles in different "platoon strategic plugin states" as long as the current state is relavent
  to the genral status.

  [platoon strategic plugin states]
  The "platoon strategic plugin states" manage the negotiation strategies and
  vehicle communication in a more refined manner that can achieve the "platooning info status'" objective. Hence,
  vehicles in different states will behave differently based on the corresponding roles and predefined rules.
  However, they can belong to the same "platooning info statu" for the same operation purpose.

  [Example]
  Multiple strategic states, such as "leader aborting" and "candidate follower", can both be mapped to
  "connecting to new leader" platooning info status, as both states are serving the same purpose of connecting
  to the leader.

Note: There is a difference between the "platoon info status" versus the the "platoon strategic plugin states". The "platooning info status" reflect the overall operating status. The "platoon strategic plugin states" manage the negotiation strategies and vehicle communication in a more refined manner. A more detailed note can be found in the corresponding function declaration in "platoon_strategic_ihp.h" file.

Definition at line 422 of file platoon_strategic_ihp.cpp.

423 {
431 carma_planning_msgs::msg::PlatooningInfo status_msg;
432
434 {
435 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::DISABLED;
436 }
438 {
439 status_msg.state = pm_.getHostPlatoonSize() == 1 ? carma_planning_msgs::msg::PlatooningInfo::SEARCHING : carma_planning_msgs::msg::PlatooningInfo::LEADING;
440 }
442 {
443 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_FOLLOWER;
444 }
446 {
447 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_LEADER;
448 }
450 {
451 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::FOLLOWING;
452 }
453 // UCLA: add leader aborting for frontal join (inherited from candidate follower).
455 {
456 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_LEADER;
457 }
458 // UCLA: add candidate leader for frontal join (inherited from leader waiting).
460 {
461 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_FOLLOWER;
462 }
463 // UCLA: add "lead with operation" for frontal join (inherited from leader waiting).
465 {
466 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_FOLLOWER;
467 }
468 // UCLA: add "prepare to join" for frontal join (inherited from leader waiting).
470 {
471 status_msg.state = carma_planning_msgs::msg::PlatooningInfo::CONNECTING_TO_NEW_LEADER;
472 }
473 //TODO: Place holder for departure (PREPARE TO DEPART)
474
475 // compose msgs for anything other than standby
477 {
478 status_msg.platoon_id = pm_.currentPlatoonID;
479 status_msg.size = pm_.getHostPlatoonSize();
480 status_msg.size_limit = config_.maxPlatoonSize;
481
483 {
484 PlatoonMember platoon_leader = pm_.getDynamicLeader();
485 status_msg.leader_id = platoon_leader.staticId;
486 status_msg.leader_downtrack_distance = platoon_leader.vehiclePosition;
487 status_msg.leader_cmd_speed = platoon_leader.commandSpeed;
488 status_msg.host_platoon_position = pm_.getNumberOfVehicleInFront();
489 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm platoonsize: " << pm_.getHostPlatoonSize() << ", platoon_leader " << platoon_leader.staticId);
490
491 int numOfVehiclesGaps = pm_.getNumberOfVehicleInFront() - pm_.dynamic_leader_index_;
492 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The host vehicle have " << numOfVehiclesGaps << " vehicles between itself and its leader (includes the leader)");
493
494 // use current position to find lanelet ID
495 lanelet::BasicPoint2d current_loc(pose_msg_.pose.position.x, pose_msg_.pose.position.y);
496
497 auto llts = wm_->getLaneletsFromPoint(current_loc, 1);
498
499 double lanelet_digitalgap = config_.standStillHeadway;
500
501 if (!llts.empty())
502 {
503 auto geofence_gaps = llts[0].regulatoryElementsAs<lanelet::DigitalMinimumGap>();
504
505 if (!geofence_gaps.empty())
506 {
507 lanelet_digitalgap = geofence_gaps[0]->getMinimumGap();
508 }
509 }
510
511 else
512 {
513 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "No lanelets in this location!!!: ");
514 }
515
516 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "lanelet_digitalgap: " << lanelet_digitalgap);
517 double desired_headway = std::max(current_speed_ * config_.timeHeadway, lanelet_digitalgap);
518 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "speed based gap: " << current_speed_ * config_.timeHeadway);
519 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "max desired_headway " << desired_headway);
520 // TODO: currently the average length of the vehicle is obtained from a config parameter. In future, plugin needs to be updated to receive each vehicle's actual length through status or BSM messages for more accuracy.
521 status_msg.desired_gap = std::max(config_.standStillHeadway * numOfVehiclesGaps, desired_headway * numOfVehiclesGaps) + (numOfVehiclesGaps - 1) * 5.0;//config_.averageVehicleLength;
522 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The desired gap with the leader is " << status_msg.desired_gap);
523
524
525 // TODO: To uncomment the following lines, platooninfo msg must be updated
526 // UCLA: Add the value of the summation of "veh_len/veh_speed" for all predecessors
527 status_msg.current_predecessor_time_headway_sum = pm_.getPredecessorTimeHeadwaySum();
528 // UCLA: preceding vehicle info
529 status_msg.predecessor_speed = pm_.getPredecessorSpeed();
530 status_msg.predecessor_position = pm_.getPredecessorPosition();
531
532 // Note: use isCreateGap to adjust the desired gap send to control plugin
533 double regular_gap = status_msg.desired_gap;
534 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "regular_gap: " << regular_gap);
535 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_speed_: " << current_speed_);
536 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "speed based gap: " << desired_headway);
537 if (pm_.isCreateGap){
538 // enlarged desired gap for gap creation
539 status_msg.desired_gap = regular_gap*(1 + config_.createGapAdjuster);
540 }
541 status_msg.actual_gap = platoon_leader.vehiclePosition - current_downtrack_;
542 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "status_msg.actual_gap: " << status_msg.actual_gap);
543 }
544 else
545 {
546 status_msg.leader_id = config_.vehicleID;
547 status_msg.leader_downtrack_distance = current_downtrack_;
548 status_msg.leader_cmd_speed = cmd_speed_;
549 status_msg.host_platoon_position = 0;
550
551 }
552
553 // This info is updated at platoon control plugin
554 status_msg.host_cmd_speed = cmd_speed_;
555
556 }
557 return status_msg;
558 }
int getNumberOfVehicleInFront()
Get number of vehicles in front of host vehicle inside platoon.
PlatoonMember getDynamicLeader()
Returns dynamic leader of the host vehicle.
double getPredecessorPosition()
UCLA: Return the position of the preceding vehicle, in m.
double getPredecessorSpeed()
UCLA: Return the speed of the preceding vehicle, in m/s.
double getPredecessorTimeHeadwaySum()
UCLA: Return the time headway summation of all predecessors, in s.

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, cmd_speed_, platoon_strategic_ihp::PlatoonMember::commandSpeed, config_, platoon_strategic_ihp::PlatoonPluginConfig::createGapAdjuster, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dynamic_leader_index_, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::PlatoonManager::getDynamicLeader(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::getNumberOfVehicleInFront(), platoon_strategic_ihp::PlatoonManager::getPredecessorPosition(), platoon_strategic_ihp::PlatoonManager::getPredecessorSpeed(), platoon_strategic_ihp::PlatoonManager::getPredecessorTimeHeadwaySum(), platoon_strategic_ihp::PlatoonManager::isCreateGap, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, platoon_strategic_ihp::PlatoonPluginConfig::maxPlatoonSize, pm_, pose_msg_, platoon_strategic_ihp::PREPARETOJOIN, platoon_strategic_ihp::STANDBY, platoon_strategic_ihp::PlatoonPluginConfig::standStillHeadway, platoon_strategic_ihp::PlatoonMember::staticId, platoon_strategic_ihp::PlatoonPluginConfig::timeHeadway, platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, platoon_strategic_ihp::PlatoonMember::vehiclePosition, and wm_.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ecef_to_map_point()

lanelet::BasicPoint2d platoon_strategic_ihp::PlatoonStrategicIHPPlugin::ecef_to_map_point ( carma_v2x_msgs::msg::LocationECEF  ecef_point)
private

Function to convert ecef location to a 2d point in map frame.

Parameters
ecef_pointecef location point
Returns
2d point in map frame

Definition at line 252 of file platoon_strategic_ihp.cpp.

253 {
254 if (!map_projector_)
255 {
256 throw std::invalid_argument("No map projector available for ecef conversion");
257 }
258
259 lanelet::BasicPoint3d map_point = map_projector_->projectECEF( { (double)ecef_point.ecef_x/100.0, (double)ecef_point.ecef_y/100.0, (double)ecef_point.ecef_z/100.0 } , -1);
260
261 lanelet::BasicPoint2d output {map_point.x(), map_point.y()};
262 return output;
263 }
std::shared_ptr< lanelet::projection::LocalFrameProjector > map_projector_

References map_projector_.

Referenced by mob_op_cb_leader(), mob_op_cb_preparetojoin(), mob_op_cb_STATUS(), mob_req_cb_candidateleader(), mob_req_cb_leader(), mob_req_cb_leaderwaiting(), and mob_req_cb_leadwithoperation().

Here is the caller graph for this function:

◆ find_target_lanelet_id()

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::find_target_lanelet_id ( double  start_downtrack,
double  end_downtrack 
)
private

Function to find the starting and ending lanelet ID for lane change in a two-lane scenario (used for cut-in join scenarios).

Note: This is a temporary function for internal test only. The scenario is not generalized. Can only find adjacent lanletID based on predefined direction (left, right).

\TODO: This function should be replaced by the complete arbitrary lane change module.

Parameters
start_downtrackThe downtrack distance (m) of the starting point. end_downtrack: The downtrack distance (m) of the target (end) point.
Returns
(int): The adjacent laneletID based on the provided downtrack distance range.

◆ findLaneletIndexFromPath()

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::findLaneletIndexFromPath ( int  target_id,
lanelet::routing::LaneletPath &  path 
)

Find lanelet index from path.

Parameters
pathpath
target_idtarget lanelet id
Returns
lanelet index

Definition at line 153 of file platoon_strategic_ihp.cpp.

154 {
155 for(size_t i = 0; i < path.size(); ++i)
156 {
157 if(path[i].id() == target_id)
158 {
159 return i;
160 }
161 }
162 return -1;
163 }

References process_bag::i.

◆ findLaneWidth()

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::findLaneWidth ( )

Find lanelet width from local position.

Returns
lanelet index

Definition at line 186 of file platoon_strategic_ihp.cpp.

187 {
188 lanelet::BasicPoint2d current_loc(pose_msg_.pose.position.x, pose_msg_.pose.position.y);
189
190 auto current_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, current_loc, 10);
191 lanelet::ConstLanelet current_lanelet = current_lanelets[0].second;
192
193 // find left and right bound
194 lanelet::ConstLineString3d left_bound = current_lanelet.leftBound();
195 lanelet::ConstLineString3d right_bound = current_lanelet.leftBound();
196
197 // find lane width
198 double dx = abs (left_bound[0].x() - right_bound[0].x());
199 double dy = abs (left_bound[0].y() - right_bound[0].y());
200 double laneWidth = sqrt(dx*dx + dy*dy);
201 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "calculated lane width: " << laneWidth);
202
203 // TODO temporary disable this function and return constant value
204 laneWidth = 3.5;
205
206
207 return laneWidth;
208 }

References pose_msg_, wm_, process_traj_logs::x, and process_traj_logs::y.

Referenced by isJoiningVehicleNearPlatoon(), and isVehicleNearTargetPlatoon().

Here is the caller graph for this function:

◆ findSpeedLimit()

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::findSpeedLimit ( const lanelet::ConstLanelet &  llt)
private

Function to find speed limit of a lanelet.

Parameters
lltinout lanelet
Returns
speed limit value (m/s)

Definition at line 166 of file platoon_strategic_ihp.cpp.

167 {
168 double target_speed = 0.0;
169
170 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm_->getTrafficRules();
171 if (traffic_rules)
172 {
173 target_speed =(*traffic_rules)->speedLimit(llt).speedLimit.value();
174 }
175 else
176 {
177 throw std::invalid_argument("Valid traffic rules object could not be built");
178 }
179
180 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target speed (limit) " << target_speed);
181
182 return target_speed;
183 }

References wm_.

Referenced by plan_maneuver_cb().

Here is the caller graph for this function:

◆ FRIEND_TEST() [1/2]

platoon_strategic_ihp::PlatoonStrategicIHPPlugin::FRIEND_TEST ( PlatoonStrategicIHPPlugin  ,
is_lanechange_possible   
)
private

◆ FRIEND_TEST() [2/2]

platoon_strategic_ihp::PlatoonStrategicIHPPlugin::FRIEND_TEST ( PlatoonStrategicIHPPlugin  ,
platoon_info_pub_front   
)
private

◆ georeference_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::georeference_cb ( const std_msgs::msg::String::UniquePtr  msg)

Callback for the georeference.

Parameters
msgLatest georeference

Definition at line 266 of file platoon_strategic_ihp.cpp.

267 {
268 if (georeference_ != msg->data)
269 {
270 georeference_ = msg->data;
271 map_projector_ = std::make_shared<lanelet::projection::LocalFrameProjector>(msg->data.c_str());
272 }
273 }

References georeference_, and map_projector_.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the caller graph for this function:

◆ getHostPM()

PlatoonManager platoon_strategic_ihp::PlatoonStrategicIHPPlugin::getHostPM ( )

UCLA Getter: for PlatoonManager class.

Definition at line 97 of file platoon_strategic_ihp.cpp.

98 {
99 return pm_;
100 }

References pm_.

◆ handle_mob_req()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::handle_mob_req ( const carma_v2x_msgs::msg::MobilityRequest &  msg)

Function to the process and respond to the mobility request.

Parameters
msgMobility Request Message
Returns
Mobility response message

Definition at line 1357 of file platoon_strategic_ihp.cpp.

1358 {
1360
1361 // Check that this is a message about platooning (could be from some other Carma activity nearby)
1362 std::string strategy = msg.strategy;
1363 if (strategy.rfind(PLATOONING_STRATEGY, 0) != 0)
1364 {
1365 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring mobility operation message for " << strategy << " strategy.");
1367 }
1368
1369 // Handle the message based on host's current state
1371 {
1372 mobility_response = mob_req_cb_leader(msg);
1373 }
1375 {
1376 mobility_response = mob_req_cb_follower(msg);
1377 }
1379 {
1380 mobility_response = mob_req_cb_candidatefollower(msg);
1381 }
1383 {
1384 mobility_response = mob_req_cb_leaderwaiting(msg);
1385 }
1387 {
1388 mobility_response = mob_req_cb_standby(msg);
1389 }
1390 // UCLA: leader aborting
1392 {
1393 mobility_response = mob_req_cb_leaderaborting(msg);
1394 }
1395 // UCLA: candidate leader
1397 {
1398 mobility_response = mob_req_cb_candidateleader(msg);
1399 }
1400
1401 // UCLA: lead with operation (for cut-in join)
1403 {
1404 mobility_response = mob_req_cb_leadwithoperation(msg);
1405 }
1406 // UCLA: prepare to join (for cut-in join)
1408 {
1409 mobility_response = mob_req_cb_preparetojoin(msg);
1410 }
1411 // TODO: Place holder for prepare to depart
1412
1413 return mobility_response;
1414 }
MobilityRequestResponse mob_req_cb_preparetojoin(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in preparetojoin state (cut-in join)
MobilityRequestResponse mob_req_cb_leadwithoperation(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in leadwithoperation state (cut-in join)
MobilityRequestResponse mob_req_cb_follower(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in follower state.
MobilityRequestResponse mob_req_cb_leader(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in leader state.
MobilityRequestResponse mob_req_cb_candidatefollower(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in candidate follower state.
MobilityRequestResponse mob_req_cb_leaderwaiting(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in leader waiting state.
MobilityRequestResponse mob_req_cb_standby(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in standby state.
MobilityRequestResponse mob_req_cb_candidateleader(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in candidateleader state.
MobilityRequestResponse mob_req_cb_leaderaborting(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to process mobility request in leaderaborting state.
MobilityRequestResponse
A response to an MobilityRequest message. ACK - indicates that the plugin accepts the MobilityRequest...

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, mob_req_cb_candidatefollower(), mob_req_cb_candidateleader(), mob_req_cb_follower(), mob_req_cb_leader(), mob_req_cb_leaderaborting(), mob_req_cb_leaderwaiting(), mob_req_cb_leadwithoperation(), mob_req_cb_preparetojoin(), mob_req_cb_standby(), platoon_strategic_ihp::NO_RESPONSE, PLATOONING_STRATEGY, pm_, platoon_strategic_ihp::PREPARETOJOIN, and platoon_strategic_ihp::STANDBY.

Referenced by mob_req_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_lanechange_possible()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::is_lanechange_possible ( lanelet::Id  start_lanelet_id,
lanelet::Id  target_lanelet_id 
)
private

Function to check if lanechange is possible.

Parameters
start_lanelet_idstart lanelet id
target_lanelet_idstart lanelet id
Returns
true or false

Definition at line 3475 of file platoon_strategic_ihp.cpp.

3476 {
3477 lanelet::ConstLanelet starting_lanelet = wm_->getMap()->laneletLayer.get(start_lanelet_id);
3478 lanelet::ConstLanelet ending_lanelet = wm_->getMap()->laneletLayer.get(target_lanelet_id);
3479 lanelet::ConstLanelet current_lanelet = starting_lanelet;
3480 bool shared_boundary_found = false;
3481
3482 while(!shared_boundary_found)
3483 {
3484 //Assumption- Adjacent lanelets share lane boundary
3485 if(current_lanelet.leftBound() == ending_lanelet.rightBound())
3486 {
3487 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lanelet " << std::to_string(current_lanelet.id()) << " shares left boundary with " << std::to_string(ending_lanelet.id()));
3488 shared_boundary_found = true;
3489 }
3490 else if(current_lanelet.rightBound() == ending_lanelet.leftBound())
3491 {
3492 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lanelet " << std::to_string(current_lanelet.id()) << " shares right boundary with " << std::to_string(ending_lanelet.id()));
3493 shared_boundary_found = true;
3494 }
3495
3496 else
3497 {
3498 //If there are no following lanelets on route, lanechange should be completing before reaching it
3499 if(wm_->getMapRoutingGraph()->following(current_lanelet, false).empty())
3500 {
3501 //In this case we have reached a lanelet which does not have a routable lanelet ahead + isn't adjacent to the lanelet where lane change ends
3502 return false;
3503 }
3504
3505 current_lanelet = wm_->getMapRoutingGraph()->following(current_lanelet, false).front();
3506 if(current_lanelet.id() == starting_lanelet.id())
3507 {
3508 //Looped back to starting lanelet
3509 return false;
3510 }
3511 }
3512 }
3513
3514
3515 return true;
3516 }

References carma_cooperative_perception::to_string(), and wm_.

Referenced by plan_maneuver_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isJoiningVehicleNearPlatoon()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::isJoiningVehicleNearPlatoon ( double  joining_downtrack,
double  joining_crosstrack 
)
private

The method for platoon leader to determine if the joining vehicle is closeby. (Note: Used when host vehicle is the platoon leader)

Parameters
joining_downtrackThe downtrack distance of the joining vehicle. joining_crosstrack: The crosstrack distance of the joining vehicle.
Returns
(boolean): if the host vehicle is close to the target platoon.

Definition at line 356 of file platoon_strategic_ihp.cpp.

357 {
358 // Position info of the host vehicle
359 double frontVehicleDtd = current_downtrack_;
360 double frontVehicleCtd = current_crosstrack_;
361 // platoon rear positions
362 int lastVehicleIndex = pm_.host_platoon_.size()-1;
363 double rearVehicleDtd = pm_.host_platoon_[lastVehicleIndex].vehiclePosition;
364
365 // lateral error for two lanes (lane width was calculated based on current lanelet)
366 double two_lane_cross_error = 2*config_.maxCrosstrackError + findLaneWidth();
367 // add longitudinal check threshold in config file
368 bool longitudinalCheck = joining_downtrack >= rearVehicleDtd - config_.longitudinalCheckThresold ||
369 joining_downtrack <= frontVehicleDtd + config_.maxCutinGap;
370 bool lateralCheck = joining_crosstrack >= frontVehicleCtd - two_lane_cross_error ||
371 joining_crosstrack <= frontVehicleCtd + two_lane_cross_error;
372 // logs for longitudinal and lateral check
373 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The longitudinalCheck result is: " << longitudinalCheck );
374 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The lateralCheck result is: " << lateralCheck );
375
376 if (longitudinalCheck && lateralCheck)
377 {
378 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Joining vehicle is nearby. It is able to join.");
379 return true;
380 }
381 else
382 {
383 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle is not close by, the join request will not be approved.");
384 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle downtrack is " << joining_downtrack << " and the host (platoon leader) downtrack is " << frontVehicleDtd);
385 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle crosstrack is " << joining_crosstrack << " and the host (platoon leader) crosstrack is " << frontVehicleCtd);
386 return false;
387 }
388 }
double findLaneWidth()
Find lanelet width from local position.

References config_, current_crosstrack_, current_downtrack_, findLaneWidth(), platoon_strategic_ihp::PlatoonManager::host_platoon_, platoon_strategic_ihp::PlatoonPluginConfig::longitudinalCheckThresold, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, platoon_strategic_ihp::PlatoonPluginConfig::maxCutinGap, and pm_.

Referenced by mob_req_cb_leader().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isVehicleNearTargetPlatoon()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::isVehicleNearTargetPlatoon ( double  rearVehicleDtd,
double  frontVehicleDtd,
double  frontVehicleCtd 
)
private

Function to determine if the host vehicle is close to the target platoon (used for cut-in join scenarios).

Parameters
rearVehicleDtdThe downtrack of the neighbor platoon rear vehicle.
frontVehicleDtdThe downtrack of the neighbor platoon leader.
frontVehicleCtdThe crosstrack of the neighbor platoon leader.
Returns
(boolean): if the host vehicle is close to the target platoon.

Definition at line 391 of file platoon_strategic_ihp.cpp.

392 {
393
394 // lateral error for two lanes (lane width was calculated based on current lanelet)
395 double two_lane_cross_error = 2*config_.maxCrosstrackError + findLaneWidth();
396 // add longitudinal check threshold in config file
397 bool longitudinalCheck = current_downtrack_ >= rearVehicleDtd - config_.longitudinalCheckThresold ||
399 bool lateralCheck = abs(current_crosstrack_ - frontVehicleCtd) <= two_lane_cross_error;
400 // current_crosstrack_ >= frontVehicleCtd - two_lane_cross_error ||
401 // current_crosstrack_ <= frontVehicleCtd + two_lane_cross_error;
402 // logs for longitudinal and lateral check
403 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The longitudinalCheck result is: " << longitudinalCheck );
404 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The lateralCheck result is: " << lateralCheck );
405
406 if (longitudinalCheck && lateralCheck)
407 {
408 // host vehicle is close to target platoon longitudinally (within 10m) and laterally (within 5m)
409 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Found a platoon nearby. We are able to join.");
410 return true;
411 }
412 else
413 {
414 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring platoon.");
415 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The platoon leader dtd is " << frontVehicleDtd << " and we are current at " << current_downtrack_);
416 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The platoon leader ctd is " << frontVehicleCtd << " and we are current at " << current_crosstrack_);
417 return false;
418 }
419 }

References config_, current_crosstrack_, current_downtrack_, findLaneWidth(), platoon_strategic_ihp::PlatoonPluginConfig::longitudinalCheckThresold, and platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError.

Referenced by mob_op_cb_leader().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isVehicleRightBehind()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::isVehicleRightBehind ( double  downtrack,
double  crosstrack 
)
private

Function to determine if the given downtrack distance (m) is behind the host vehicle.

note: This is only applicable for same lane application, so it will check cross track distance.

Parameters
downtrackThe downtrack distance (m) of the target vehicle to compare with the host. crosstrack: The crosstrack distance (m) of the target vehicle to compart with the host.
Returns
(boolean): if target vehicle is behind the host vehicle.

Definition at line 232 of file platoon_strategic_ihp.cpp.

233 {
234 double currentDtd = current_downtrack_;
235 double currentCtd = current_crosstrack_;
236 bool samelane = abs(currentCtd-crosstrack) <= config_.maxCrosstrackError;
237
238 if (downtrack < currentDtd && samelane)
239 {
240 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Found a platoon at behind. We are able to join");
241 return true;
242 }
243 else
244 {
245 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring platoon that is either ahead of us or in another lane.");
246 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The front platoon dtd is " << downtrack << " and we are current at " << currentDtd);
247 return false;
248 }
249 }

References config_, current_crosstrack_, current_downtrack_, and platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError.

Referenced by mob_op_cb_leader().

Here is the caller graph for this function:

◆ isVehicleRightInFront()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::isVehicleRightInFront ( double  downtrack,
double  crosstrack 
)
private

Function to determine if a target vehicle is in the front of host vehicle note: This is only applicable for same lane application, so it will check cross track distance.

Parameters
downtracktarget vehicle downtrack distance relative to host's route (m) crosstrack: target vehicle crosstrack (m)
Returns
true or false

Definition at line 211 of file platoon_strategic_ihp.cpp.

212 {
213 // Position info of the host vehcile
214 double currentDtd = current_downtrack_;
215 double currentCtd = current_crosstrack_;
216 bool samelane = abs(currentCtd-crosstrack) <= config_.maxCrosstrackError;
217
218 if (downtrack > currentDtd && samelane)
219 {
220 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Found a platoon in front. We are able to join");
221 return true;
222 }
223 else
224 {
225 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring platoon that is either behind host or in another lane.");
226 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The front platoon dtd is " << downtrack << " and we are current at " << currentDtd);
227 return false;
228 }
229 }

References config_, current_crosstrack_, current_downtrack_, and platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError.

Referenced by mob_op_cb_leader().

Here is the caller graph for this function:

◆ mob_op_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb ( const carma_v2x_msgs::msg::MobilityOperation::UniquePtr  msg)

Callback function for Mobility Operation Message.

Parameters
msgMobility Operation Message

Definition at line 812 of file platoon_strategic_ihp.cpp.

813 {
815 {
816 return;
817 }
818
819 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "mob_op_cb received msg with sender ID " << msg->m_header.sender_id
820 << ", plan ID " << msg->m_header.plan_id);
821 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "...strategy " << msg->strategy << ", strategy params " << msg->strategy_params);
822
823 // Check that this is a message about platooning (could be from some other Carma activity nearby)
824 std::string strategy = msg->strategy;
825 if (strategy.rfind(PLATOONING_STRATEGY, 0) != 0)
826 {
827 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring mobility operation message for " << strategy << " strategy.");
828 return;
829 }
830
831 // Ignore messages as long as host vehicle is stopped
833 {
834 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring message since host is stopped.");
835 return;
836 }
837
838 // Perform common operations that apply to all states
839 std::string strategyParams = msg->strategy_params;
840 bool isPlatoonStatusMsg = strategyParams.rfind(OPERATION_STATUS_TYPE, 0) == 0;
841 bool isPlatoonInfoMsg = strategyParams.rfind(OPERATION_INFO_TYPE, 0) == 0;
842 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "strategyParams: " << strategyParams << "isPlatoonStatusMsg: " << isPlatoonStatusMsg << "isPlatoonInfoMsg: " << isPlatoonInfoMsg);
843 if (isPlatoonStatusMsg)
844 {
845 mob_op_cb_STATUS(*msg);
846 }
847 else if (isPlatoonInfoMsg)
848 {
849 // Note: this is where confusion will reign if multiple neighbor platoons are discovered; need more sophisticated
850 // logic to handle that situation
851
852 // If it is a legitimate platoon (2 or more members) other than our own then
853 std::vector<std::string> inputsParams;
854 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
855 std::vector<std::string> p_size;
856 boost::algorithm::split(p_size, inputsParams[2], boost::is_any_of(":"));
857 int platoon_size = std::stoi(p_size[1]);
858 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "neighbor platoon_size from INFO: " << platoon_size);
859 if (platoon_size > 1 && msg->m_header.plan_id.compare(pm_.currentPlatoonID) != 0)
860 {
861 // If platoon ID doesn't match our known target platoon then clear any old neighbor platoon info and record
862 // the platoon ID and the sender as the leader (only leaders send INFO)
863 if (msg->m_header.plan_id.compare(pm_.neighborPlatoonID) != 0)
864 {
866 pm_.neighborPlatoonID = msg->m_header.plan_id;
867 }
868 pm_.neighbor_platoon_leader_id_ = msg->m_header.sender_id;
869 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.neighbor_platoon_leader_id_: " << pm_.neighbor_platoon_leader_id_);
870 pm_.neighbor_platoon_info_size_ = platoon_size;
871 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.neighbor_platoon_info_size_: " << pm_.neighbor_platoon_info_size_);
872 }
873 }
874
875 else
876 {
877 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Invalid Mob Op received");
878 }
879
880 // Perform state-specific additional actions
882 {
883 mob_op_cb_leader(*msg);
884 }
886 {
887 mob_op_cb_follower(*msg);
888 }
890 {
892 }
894 {
896 }
898 {
899 mob_op_cb_standby(*msg);
900 }
901 // UCLA: add leader aborting
903 {
905 }
906 // UCLA: add candidate leader
908 {
910 }
911 // UCLA: add lead with operation for cut-in join
913 {
915 }
916 // UCLA: add prepare to join for cut-in join
918 {
920 }
921 // TODO: Place holder for prepare to depart
922
923 // TODO: If needed (with large size platoons), add a queue for status messages
924 // INFO messages always processed, STATUS messages if saved in que
925 }
void resetNeighborPlatoon()
Resets all variables that describe a neighbor platoon, so that no neighbor is known.
void mob_op_cb_leaderaborting(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in leaderaborting state.
void mob_op_cb_candidateleader(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in candidateleader state.
void mob_op_cb_leaderwaiting(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in leader waiting state.
void mob_op_cb_leadwithoperation(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in LeadWithOperation state (cut-in join)
void mob_op_cb_candidatefollower(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in candidate follower state.
void mob_op_cb_standby(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in standby state.
void mob_op_cb_follower(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in follower state.
void mob_op_cb_STATUS(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation message with STATUS params, read ecef location and update plat...
void mob_op_cb_leader(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in leader state.
void mob_op_cb_preparetojoin(const carma_v2x_msgs::msg::MobilityOperation &msg)
Function to process mobility operation in PrepareToJoin state (cut-in join)

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, mob_op_cb_candidatefollower(), mob_op_cb_candidateleader(), mob_op_cb_follower(), mob_op_cb_leader(), mob_op_cb_leaderaborting(), mob_op_cb_leaderwaiting(), mob_op_cb_leadwithoperation(), mob_op_cb_preparetojoin(), mob_op_cb_standby(), mob_op_cb_STATUS(), platoon_strategic_ihp::PlatoonManager::neighbor_platoon_info_size_, platoon_strategic_ihp::PlatoonManager::neighbor_platoon_leader_id_, platoon_strategic_ihp::PlatoonManager::neighborPlatoonID, OPERATION_INFO_TYPE, OPERATION_STATUS_TYPE, PLATOONING_STRATEGY, pm_, platoon_strategic_ihp::PREPARETOJOIN, platoon_strategic_ihp::PlatoonManager::resetNeighborPlatoon(), process_traj_logs::split, platoon_strategic_ihp::STANDBY, and STOPPED_SPEED.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_op_cb_candidatefollower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_candidatefollower ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in candidate follower state.

Parameters
msgincoming mobility operation

Definition at line 934 of file platoon_strategic_ihp.cpp.

935 {
936 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CANDIDATEFOLLOWER state no further action on message from " << msg.m_header.sender_id);
937 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_candidateleader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_candidateleader ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in candidateleader state.

Parameters
msgincoming mobility operation message.

Definition at line 1235 of file platoon_strategic_ihp.cpp.

1236 {
1237 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CANDIDATELEADER state no further action on message from " << msg.m_header.sender_id);
1238 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_follower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_follower ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in follower state.

Parameters
msgincoming mobility operation

Definition at line 940 of file platoon_strategic_ihp.cpp.

941 {
942 //std::string strategyParams = msg.strategy_params;
943 //bool isPlatoonStatusMsg = (strategyParams.rfind(OPERATION_STATUS_TYPE, 0) == 0);
944
945 // TODO: Place holder for prepare to depart
946
947 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "FOLLOWER state no further action on message from " << msg.m_header.sender_id);
948 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_leader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_leader ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in leader state.

Parameters
msgincoming mobility operation

Note: This is the function to handle the mobility operation message. Vehicle in leader state is either a single ADS vehicle or a platoon leader.

Single ADS will send out INFO messages. Platoon leaders will send out both INFO and STATUS messages.

If the host is single vehicle, it should have "isPlatoonInfoMsg = true" and "isInNegotiation = false". In such condition, single leader will start joining and send request to the platoon leader. mob_op_cb_leader(

If the host vehicle is platoon leader, then it should have "isPlatoonInfoMsg = true" and "isInNegotiation = true". But existing platoon leader do not need to send out joining request.

Both the platoon leader and single vehicle need to subscribe to the STATUS message to populate the platoon manager with existing platoon members, so the PM can calculate dtd and ctd corresponds to host vehicle's origin position, hence to be used for later calculation.

note: [veh3*] -------— [veh2] --------------— [veh1] -------— [*veh0] |<---------------— front-rear DTD difference -----------------—>| |<--------------------------— platoon length -------------------------—>|

front-rear DTD difference = platoon_length + one_vehicle_length Vehicle length is already accounted for in the message's LENGTH value

Note: "isVehicleRightInFront" tests for same lane

Note: "isVehicleRightBehind" tests for same lane

JOIN_PARAMS format: JOIN_PARAMS| --> "SIZE:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%,JOINIDX:%6%" |----—0---— –1------—2------—3------—4-------—5----—|

UCLA Implementation note:

  1. isVehicleNearTargetPlatoon --> determine if the platoon is next to host vehicle
  2. sender_id == requesting veh ID --> joiner ID

Definition at line 957 of file platoon_strategic_ihp.cpp.

958 {
974 // Read incoming message info
975 std::string strategyParams = msg.strategy_params;
976 std::string senderId = msg.m_header.sender_id;
977 std::string platoonId = msg.m_header.plan_id;
978
979 // In the current state, host vehicle care about the INFO heart-beat operation message if we are not currently in
980 // a negotiation, and host also need to care about operation from members in our current platoon.
981 bool isPlatoonInfoMsg = strategyParams.rfind(OPERATION_INFO_TYPE, 0) == 0; // INFO message only broadcast by leader and single CAV.
982 bool isInNegotiation = pm_.current_plan.valid || pm_.currentPlatoonID.compare(pm_.dummyID) != 0; // In negotiation indicates host is not available to become a joiner
983 // (i.e., not currently in a platoon or trying to join a platoon).
984 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Top of mob_op_cb_leader, isInNegotiation = " << isInNegotiation);
985
986 // Condition 1. Host vehicle is the single CAV joining the platoon.
987 if (isPlatoonInfoMsg && !isInNegotiation)
988 {
989 //TODO future enhancement: add logic here for if/how to join two existing platoons
990 // (e.g. the shorter platoon should join the longer one, or rear joins front if same length)
991
992 // step 1. read INFO message from the target platoon leader
993
994 // read ecef location from strategy params.
995 carma_v2x_msgs::msg::LocationECEF ecef_loc;
996 ecef_loc = mob_op_find_ecef_from_INFO_params(strategyParams);
997
998 // use ecef_loc to calculate front Dtd in m.
999 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(ecef_loc);
1000 double frontVehicleDtd = wm_->routeTrackPos(incoming_pose).downtrack;
1001
1002 // use ecef_loc to calculate front Ctd in m.
1003 double frontVehicleCtd = wm_->routeTrackPos(incoming_pose).crosstrack;
1004 // downtrack and crosstrack of the platoon leader --> used for frontal join
1005 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Neighbor platoon frontVehicleDtd from ecef: " << frontVehicleDtd << ", frontVehicleCtd from ecef: " << frontVehicleCtd);
1006
1007 // use INFO param to find platoon rear vehicle DTD and CTD.
1008 double platoon_length = mob_op_find_platoon_length_from_INFO_params(strategyParams); // length of the entire platoon in meters.
1019 double rearVehicleDtd = frontVehicleDtd - platoon_length;
1020 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "rear veh dtd from platoon length: " << rearVehicleDtd);
1021 if (!pm_.neighbor_platoon_.empty())
1022 {
1023 rearVehicleDtd = pm_.neighbor_platoon_.back().vehiclePosition;
1024 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "rear veh dtd from neighbor platoon: " << rearVehicleDtd);
1025 }
1026
1027 // Note: For one platoon, we assume all members are in the same lane.
1028 double rearVehicleCtd = frontVehicleCtd;
1029 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Neighbor platoon rearVehicleDtd: " << rearVehicleDtd << ", rearVehicleCtd: " << rearVehicleCtd);
1030
1031 // Parse the strategy params
1032 std::vector<std::string> inputsParams;
1033 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
1034
1035 // Get the target platoon's size (number of members) from strategy params
1036 std::vector<std::string> targetPlatoonSize_parsed;
1037 boost::algorithm::split(targetPlatoonSize_parsed, inputsParams[2], boost::is_any_of(":"));
1038 int targetPlatoonSize = std::stoi(targetPlatoonSize_parsed[1]);
1039 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target Platoon Size: " << targetPlatoonSize);
1040 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Found a vehicle/platoon with id = " << platoonId << " within range.");
1041
1042 //TODO future: add logic here to assess closeness of the neighbor platoon, as well as its speed, destination
1043 // & other attributes to decide if we want to join before assembling a join request
1044
1045 // step 2. Generate default info for join request
1046 carma_v2x_msgs::msg::MobilityRequest request;
1047 request.m_header.plan_id = boost::uuids::to_string(boost::uuids::random_generator()());
1048 request.m_header.recipient_id = senderId;
1049 request.m_header.sender_id = config_.vehicleID;
1050 request.m_header.timestamp = timer_factory_->now().nanoseconds()/1000000;
1051 request.location = pose_to_ecef(pose_msg_);
1052 request.strategy = PLATOONING_STRATEGY;
1053 request.urgency = 50;
1054
1055 int platoon_size = pm_.getHostPlatoonSize();
1056
1057 // step 3. Request Rear Join
1058 if(isVehicleRightInFront(rearVehicleDtd, rearVehicleCtd) && !config_.test_front_join)
1059 {
1063 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Neighbor platoon is right in front of us");
1064
1065 request.plan_type.type = carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_AT_REAR;
1066
1067 /*
1068 * JOIN_PARAMS format:
1069 * JOIN_PARAMS| --> "SIZE:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%,JOINIDX:%6%"
1070 * |-------0------ --1---------2---------3---------4----------5-------|
1071 */
1072
1073 boost::format fmter(JOIN_PARAMS);
1074 int dummy_join_index = -2; //not used for this message, but message spec requires it
1075 fmter %platoon_size; // index = 0
1076 fmter %current_speed_; // index = 1, in m/s
1077 fmter %pose_ecef_point_.ecef_x; // index = 2, in cm.
1078 fmter %pose_ecef_point_.ecef_y; // index = 3, in cm.
1079 fmter %pose_ecef_point_.ecef_z; // index = 4, in cm.
1080 fmter %dummy_join_index; // index = 5
1081 request.strategy_params = fmter.str();
1083 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Publishing request to leader " << senderId << " with params " << request.strategy_params << " and plan id = " << request.m_header.plan_id);
1084
1085 // Create a new join plan
1086 pm_.current_plan = ActionPlan(true, request.m_header.timestamp, request.m_header.plan_id, senderId);
1087
1088 // If we are asking to join an actual platoon (not a solo vehicle), then save its ID for later use
1089 if (platoonId.compare(pm_.dummyID) != 0)
1090 {
1091 pm_.targetPlatoonID = platoonId;
1092 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Detected neighbor as a real platoon & storing its ID: " << platoonId);
1093 }
1094 }
1095
1096 // step 4. Request frontal join, if the neighbor is a real platoon
1097 else if ((targetPlatoonSize > 1 || config_.test_front_join) && isVehicleRightBehind(frontVehicleDtd, frontVehicleCtd))
1098 {
1102 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Neighbor platoon leader is right behind us");
1103
1104 // UCLA: assign a new plan type
1105 request.plan_type.type = carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_FROM_FRONT;
1106
1112 boost::format fmter(JOIN_PARAMS); // Note: Front and rear join uses same params, hence merge to one param for both condition.
1113 int dummy_join_index = -2; //not used for this message, but message spec requires it
1114 fmter %platoon_size; // index = 0
1115 fmter %current_speed_; // index = 1, in m/s
1116 fmter %pose_ecef_point_.ecef_x; // index = 2, in cm.
1117 fmter %pose_ecef_point_.ecef_y; // index = 3, in cm.
1118 fmter %pose_ecef_point_.ecef_z; // index = 4, in cm.
1119 fmter %dummy_join_index; // index = 5
1120 request.strategy_params = fmter.str();
1122 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Publishing front join request to the leader " << senderId << " with params " << request.strategy_params << " and plan id = " << request.m_header.plan_id);
1123
1124 // Create a new join plan
1125 pm_.current_plan = ActionPlan(true, request.m_header.timestamp, request.m_header.plan_id, senderId);
1126
1127 // If testing with a solo vehicle to represent the target platoon, then use the current join plan ID for that platoon;
1128 // otherwise, it will already have and ID so store it for future use
1130 {
1131 pm_.targetPlatoonID = request.m_header.plan_id;
1132 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Since neighbor is a fake platoon, storing " << pm_.targetPlatoonID << " as its platoon ID");
1133 }
1134 else
1135 {
1136 pm_.targetPlatoonID = platoonId;
1137 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Storing real neighbor platoon's ID as target: " << pm_.targetPlatoonID);
1138 }
1139 }
1140
1141 // step 5. Request cut-in join (front, middle or rear, from adjacent lane)
1142 else if ((targetPlatoonSize > 1 || config_.test_cutin_join) && !config_.test_front_join
1143 && isVehicleNearTargetPlatoon(rearVehicleDtd, frontVehicleDtd, frontVehicleCtd))
1144 {
1145
1146 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "starting cut-in join process");
1147 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "rearVehicleDtd " << rearVehicleDtd);
1148 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "rearVehicleCtd " << rearVehicleCtd);
1149
1150 // If we are asking to join an actual platoon (not a solo vehicle), then save its ID for later use
1151 if (platoonId.compare(pm_.dummyID) != 0)
1152 {
1153 pm_.targetPlatoonID = platoonId;
1154 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Detected neighbor as a real platoon & storing its ID: " << platoonId);
1155 }
1156
1157
1158 carma_wm::TrackPos target_trackpose(rearVehicleDtd, rearVehicleCtd);
1159 auto target_rear_pose = wm_->pointFromRouteTrackPos(target_trackpose);
1160 if (target_rear_pose)
1161 {
1162 target_cutin_pose_ = incoming_pose;
1163
1164 auto target_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, target_rear_pose.get(), 1);
1165 if (!target_lanelets.empty())
1166 {
1167 long target_rear_pose_lanelet_id = target_lanelets[0].second.id();
1168 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_rear_pose_lanelet_id: " << target_rear_pose_lanelet_id);
1169 }
1170 else
1171 {
1172 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_rear_pose_lanelet not found!!");
1173 }
1174 }
1175
1176 else
1177 {
1178 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "No target pose is found, so we cannot prodeed with a cutin join request.");
1179 return;
1180 }
1181
1188 //TODO: verify purpose of this logic then its correctness accordingly:
1189 // -is step 5 (this block) really for all 3 types of joining?
1190 // -ensure join_index gets an appropriate value for the type of join
1191 // -ensure plan type corresponds to join_index
1192
1193 // complete the request
1194 // UCLA: this is a newly added plan type
1195 // Note: Request conposed outside of if conditions
1196 // UCLA: Desired joining index for cut-in join, indicate the index of gap-leading vehicle. -1 indicate cut-in from front.
1197 // Note: remove join_index to info param.
1198 request.plan_type.type = carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
1199
1200 // At this step all cut-in types start with this request, so the join_index at this point is set to default, -2.
1201 int join_index = -2;
1202 boost::format fmter(JOIN_PARAMS); // Note: Front and rear join uses same params, hence merge to one param for both condition.
1203 fmter %platoon_size; // index = 0
1204 fmter %current_speed_; // index = 1, in m/s
1205 fmter %pose_ecef_point_.ecef_x; // index = 2
1206 fmter %pose_ecef_point_.ecef_y; // index = 3
1207 fmter %pose_ecef_point_.ecef_z; // index = 4
1208 fmter %join_index; // index = 5
1209 request.strategy_params = fmter.str();
1211 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Publishing request to the leader " << senderId << " with params " << request.strategy_params << " and plan id = " << request.m_header.plan_id);
1212
1213 // Create a new join plan
1214 pm_.current_plan = ActionPlan(true, request.m_header.timestamp, request.m_header.plan_id, senderId);
1215 }
1216
1217 // step 6. Return none if no platoon nearby
1218 else
1219 {
1220 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore platoon with platoon id: " << platoonId << " because it is too far away to join.");
1221 }
1222 }
1223
1224 // TODO: Place holder for prepare to depart (else if isdepart)
1225
1226 }
Position in a track based coordinate system where the axis are downtrack and crosstrack....
Definition: TrackPos.hpp:35
std::vector< PlatoonMember > neighbor_platoon_
carma_v2x_msgs::msg::LocationECEF pose_to_ecef(geometry_msgs::msg::PoseStamped pose_msg)
Function to convert pose from map frame to ecef location.
bool isVehicleRightInFront(double downtrack, double crosstrack)
Function to determine if a target vehicle is in the front of host vehicle note: This is only applicab...
double mob_op_find_platoon_length_from_INFO_params(std::string strategyParams)
Function to process mobility operation INFO params to find platoon length in m.
lanelet::BasicPoint2d ecef_to_map_point(carma_v2x_msgs::msg::LocationECEF ecef_point)
Function to convert ecef location to a 2d point in map frame.
bool isVehicleNearTargetPlatoon(double rearVehicleDtd, double frontVehicleDtd, double frontVehicleCtd)
Function to determine if the host vehicle is close to the target platoon (used for cut-in join scenar...
carma_v2x_msgs::msg::LocationECEF mob_op_find_ecef_from_INFO_params(std::string strategyParams)
Function to process mobility operation INFO params to find platoon leader's ecef location.
bool isVehicleRightBehind(double downtrack, double crosstrack)
Function to determine if the given downtrack distance (m) is behind the host vehicle.

References config_, platoon_strategic_ihp::PlatoonManager::current_plan, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), isVehicleNearTargetPlatoon(), isVehicleRightBehind(), isVehicleRightInFront(), JOIN_PARAMS, mob_op_find_ecef_from_INFO_params(), mob_op_find_platoon_length_from_INFO_params(), mobility_request_publisher_, platoon_strategic_ihp::PlatoonManager::neighbor_platoon_, OPERATION_INFO_TYPE, PLATOONING_STRATEGY, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), process_traj_logs::split, target_cutin_pose_, platoon_strategic_ihp::PlatoonManager::targetPlatoonID, platoon_strategic_ihp::PlatoonPluginConfig::test_cutin_join, platoon_strategic_ihp::PlatoonPluginConfig::test_front_join, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::ActionPlan::valid, platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and wm_.

Referenced by mob_op_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_op_cb_leaderaborting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_leaderaborting ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in leaderaborting state.

Parameters
msgincoming mobility operation message.

Definition at line 1229 of file platoon_strategic_ihp.cpp.

1230 {
1231 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LEADERABORTING state no further action on message from " << msg.m_header.sender_id);
1232 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_leaderwaiting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_leaderwaiting ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in leader waiting state.

Parameters
msgincoming mobility operation

Definition at line 951 of file platoon_strategic_ihp.cpp.

952 {
953 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LEADERWAITING state no further action on message from " << msg.m_header.sender_id);
954 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_leadwithoperation()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_leadwithoperation ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in LeadWithOperation state (cut-in join)

Parameters
msgincoming mobility operation

Definition at line 1241 of file platoon_strategic_ihp.cpp.

1242 {
1243 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LEADWITHOPERATION state no further action on message from " << msg.m_header.sender_id);
1244 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_preparetojoin()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_preparetojoin ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in PrepareToJoin state (cut-in join)

Parameters
msgincoming mobility operation

Definition at line 1247 of file platoon_strategic_ihp.cpp.

1248 {
1249 /*
1250 * If same lane with leader, then send request to do same lane join.
1251 * Otherwise, just send status params.
1252 * Note: leader in state 'leading with operation' also send out INFO msg
1253 */
1254
1255 // read parameters
1256 std::string strategyParams = msg.strategy_params;
1257 std::string senderId = msg.m_header.sender_id;
1258
1259 // locate INFO type
1260 bool isPlatoonInfoMsg = strategyParams.rfind(OPERATION_INFO_TYPE, 0) == 0;
1261
1262 // If this is an INFO message and our record of the neighbor platoon is complete then
1263 // pm_.is_neighbor_record_complete_ = true; //TODO temporary
1264 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.is_neighbor_record_complete_" << pm_.is_neighbor_record_complete_);
1265
1266 if (isPlatoonInfoMsg && pm_.is_neighbor_record_complete_)
1267 {
1268
1269 //TODO: would be good to have a timeout here; if a neighbor platoon has been identified, and no INFO messages
1270 // from it are received in a while, then its record should be erased, and any in-work joining should be
1271 // aborted.
1272
1273 // read ecef location from strategy params.
1274 carma_v2x_msgs::msg::LocationECEF ecef_loc;
1275 ecef_loc = mob_op_find_ecef_from_INFO_params(strategyParams);
1276 // use ecef_loc to calculate front Dtd in m.
1277 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(ecef_loc);
1278
1279 double frontVehicleDtd = wm_->routeTrackPos(incoming_pose).downtrack;
1280
1281 // use ecef_loc to calculate front Ctd in m.
1282 double frontVehicleCtd = wm_->routeTrackPos(incoming_pose).crosstrack;
1283
1284 // // Find neighbor platoon end vehicle and its downtrack in m
1285 int rearVehicleIndex = pm_.neighbor_platoon_.size() - 1;
1286 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "rearVehicleIndex: " << rearVehicleIndex);
1287 double rearVehicleDtd = pm_.neighbor_platoon_[rearVehicleIndex].vehiclePosition;
1288 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Neighbor rearVehicleDtd from ecef: " << rearVehicleDtd);
1289
1290 // If lane change has not yet been authorized, stop here (this method will be running before the negotiations
1291 // with the platoon leader are complete)
1292 if (!safeToLaneChange_)
1293 {
1294 return;
1295 }
1296
1297 // determine if the lane change is finished
1298 bool isSameLaneWithPlatoon = abs(frontVehicleCtd - current_crosstrack_) <= config_.maxCrosstrackError;
1299 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane change has been authorized. isSameLaneWithPlatoon = " << isSameLaneWithPlatoon);
1300 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "crosstrack diff" << abs(frontVehicleCtd - current_crosstrack_));
1301 if (isSameLaneWithPlatoon)
1302 {
1303 // request 1. reset the safeToChangLane indicators if lane change is finished
1304 safeToLaneChange_ = false;
1305
1306 // request 2. change to same lane operation states (determine based on DTD differences)
1307 carma_v2x_msgs::msg::MobilityRequest request;
1308 request.m_header.plan_id = boost::uuids::to_string(boost::uuids::random_generator()());
1309 request.m_header.recipient_id = senderId;
1310 request.m_header.sender_id = config_.vehicleID;
1311 request.m_header.timestamp = timer_factory_->now().nanoseconds()/1000000;
1312 request.location = pose_to_ecef(pose_msg_);
1313
1314 // UCLA: send request based on cut-in type
1315 if (frontVehicleDtd < current_downtrack_)
1316 {
1317 request.plan_type.type = carma_v2x_msgs::msg::PlanType::CUT_IN_FRONT_DONE;
1318 }
1319 else
1320 {
1321 request.plan_type.type = carma_v2x_msgs::msg::PlanType::CUT_IN_MID_OR_REAR_DONE;
1322 }
1323 request.strategy = PLATOONING_STRATEGY;
1324 double host_platoon_size = pm_.getHostPlatoonSize();
1325
1326 boost::format fmter(JOIN_PARAMS);
1327 fmter %host_platoon_size; // index = 0
1328 fmter %current_speed_; // index = 1, in m/s
1329 fmter %pose_ecef_point_.ecef_x; // index = 2
1330 fmter %pose_ecef_point_.ecef_y; // index = 3
1331 fmter %pose_ecef_point_.ecef_z; // index = 4
1332 fmter %target_join_index_; // index = 5
1333 request.strategy_params = fmter.str();
1334 request.urgency = 50;
1335
1337 if (pm_.currentPlatoonID.compare(pm_.dummyID) == 0)
1338 {
1339 pm_.currentPlatoonID = request.m_header.plan_id;
1340 }
1341
1342 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "new platoon id: " << pm_.currentPlatoonID);
1343 pm_.current_plan = ActionPlan(true, request.m_header.timestamp, request.m_header.plan_id, senderId);
1344
1345 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility request to revert to same-lane operation");
1346 }
1347 else
1348 {
1349 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane Change not completed");
1350 }
1351 }
1352 }

References config_, current_crosstrack_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_plan, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::is_neighbor_record_complete_, JOIN_PARAMS, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, mob_op_find_ecef_from_INFO_params(), mobility_request_publisher_, platoon_strategic_ihp::PlatoonManager::neighbor_platoon_, OPERATION_INFO_TYPE, PLATOONING_STRATEGY, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), safeToLaneChange_, target_join_index_, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and wm_.

Referenced by mob_op_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_op_cb_standby()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_standby ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation in standby state.

Parameters
msgincoming mobility operation

Definition at line 927 of file platoon_strategic_ihp.cpp.

928 {
929 // In standby state, it will ignore operation message since it is not actively operating
930 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "STANDBY state no further action on message from " << msg.m_header.sender_id);
931 }

Referenced by mob_op_cb().

Here is the caller graph for this function:

◆ mob_op_cb_STATUS()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_cb_STATUS ( const carma_v2x_msgs::msg::MobilityOperation &  msg)
private

Function to process mobility operation message with STATUS params, read ecef location and update platoon member info.

Parameters
msgincoming mobility operation message.

Note: STATUS params format: STATUS | --> "CMDSPEED:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%" |-------—0-------—1------—2------—3------—4---—|

Definition at line 711 of file platoon_strategic_ihp.cpp.

712 {
719 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Entered mob_op_cb_STATUS");
720 std::string strategyParams = msg.strategy_params;
721 std::string vehicleID = msg.m_header.sender_id;
722 std::string platoonId = msg.m_header.plan_id;
723 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "strategyParams = " << strategyParams);
724 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "platoonId = " << platoonId << ", sender ID = " << vehicleID);
725 std::string statusParams = strategyParams.substr(OPERATION_STATUS_TYPE.size() + 1);
726 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.currentPlatoonID = " << pm_.currentPlatoonID << ", targetPlatoonID = " << pm_.targetPlatoonID);
727
728 // read Downtrack
729 carma_v2x_msgs::msg::LocationECEF ecef_loc = mob_op_find_ecef_from_STATUS_params(strategyParams);
730 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(ecef_loc);
731 double dtd = wm_->routeTrackPos(incoming_pose).downtrack;
732 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "DTD calculated from ecef is: " << dtd);
733 // read Crosstrack
734 double ctd = wm_->routeTrackPos(incoming_pose).crosstrack;
735 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CTD calculated from ecef is: " << ctd);
736
737 // If it comes from a member of an identified neighbor platoon, then
738 if (platoonId.compare(pm_.neighborPlatoonID) == 0 && platoonId.compare(pm_.dummyID) != 0)
739 {
740 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Incoming platoonID matches target platoon id");
741 // // Update this member's status (or add if it's unknown to us)
742 pm_.neighborMemberUpdates(vehicleID, platoonId, statusParams, dtd, ctd);
743 }
744
745 // else if this message is for our platoon then store its info
746 else if (platoonId.compare(pm_.currentPlatoonID) == 0 && platoonId.compare(pm_.dummyID) != 0)
747 {
748 pm_.hostMemberUpdates(vehicleID, platoonId, statusParams, dtd, ctd);
749 }
750
751 // else it represents an uninteresting platoon
752 else
753 {
754 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mob op for platoon " << platoonId << " that doesn't match our platoon: " << pm_.currentPlatoonID
755 << " or known neighbor platoon: " << pm_.targetPlatoonID);
756 }
757 }
void hostMemberUpdates(const std::string &senderId, const std::string &platoonId, const std::string &params, const double &DtD, const double &CtD)
Update information for members of the host's platoon based on a mobility operation STATUS message.
void neighborMemberUpdates(const std::string &senderId, const std::string &platoonId, const std::string &params, const double &DtD, const double &CtD)
Update information for members of a neighboring platoon based on a mobility operation STATUS message.
carma_v2x_msgs::msg::LocationECEF mob_op_find_ecef_from_STATUS_params(std::string strategyParams)
Function to process mobility operation for STATUS params.

References platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::hostMemberUpdates(), mob_op_find_ecef_from_STATUS_params(), platoon_strategic_ihp::PlatoonManager::neighborMemberUpdates(), platoon_strategic_ihp::PlatoonManager::neighborPlatoonID, OPERATION_STATUS_TYPE, pm_, platoon_strategic_ihp::PlatoonManager::targetPlatoonID, and wm_.

Referenced by mob_op_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_op_find_ecef_from_INFO_params()

carma_v2x_msgs::msg::LocationECEF platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_find_ecef_from_INFO_params ( std::string  strategyParams)
private

Function to process mobility operation INFO params to find platoon leader's ecef location.

Parameters
strategyParamsThe parsed strategy params, used to find ecef locaton.
Returns
ecef location of the sender.

Note: INFO param format: "INFO| --> LENGTH:%.2f,SPEED:%.2f,SIZE:%d,ECEFX:%.2f,ECEFY:%.2f,ECEFZ:%.2f" |----—0--------—1------—2-----—3-------—4-------—5----—|

Definition at line 780 of file platoon_strategic_ihp.cpp.

781 {
787 // For INFO params, the string format is INFO|REAR:%s,LENGTH:%.2f,SPEED:%.2f,SIZE:%d,DTD:%.2f
788 std::vector<std::string> inputsParams;
789 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
790
791 std::vector<std::string> ecef_x_parsed;
792 boost::algorithm::split(ecef_x_parsed, inputsParams[3], boost::is_any_of(":"));
793 double ecef_x = std::stod(ecef_x_parsed[1]);
794
795 std::vector<std::string> ecef_y_parsed;
796 boost::algorithm::split(ecef_y_parsed, inputsParams[4], boost::is_any_of(":"));
797 double ecef_y = std::stod(ecef_y_parsed[1]);
798
799 std::vector<std::string> ecef_z_parsed;
800 boost::algorithm::split(ecef_z_parsed, inputsParams[5], boost::is_any_of(":"));
801 double ecef_z = std::stod(ecef_z_parsed[1]);
802
803 carma_v2x_msgs::msg::LocationECEF ecef_loc;
804 ecef_loc.ecef_x = ecef_x;
805 ecef_loc.ecef_y = ecef_y;
806 ecef_loc.ecef_z = ecef_z;
807
808 return ecef_loc;
809 }

References process_traj_logs::split.

Referenced by mob_op_cb_leader(), and mob_op_cb_preparetojoin().

Here is the caller graph for this function:

◆ mob_op_find_ecef_from_STATUS_params()

carma_v2x_msgs::msg::LocationECEF platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_find_ecef_from_STATUS_params ( std::string  strategyParams)
private

Function to process mobility operation for STATUS params.

Parameters
strategyParamsThe parsed strategy params, used to find ecef locaton.
Returns
ecef location of the sender.

Definition at line 678 of file platoon_strategic_ihp.cpp.

679 {
680 /*
681 * Helper function that extract ecef location from STATUS msg.
682 * Note: STATUS params format:
683 * STATUS | --> "CMDSPEED:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%"
684 * |----------0----------1---------2---------3---------4------|
685 */
686
687 std::vector<std::string> inputsParams;
688 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
689
690 std::vector<std::string> ecef_x_parsed;
691 boost::algorithm::split(ecef_x_parsed, inputsParams[2], boost::is_any_of(":"));
692 double ecef_x = std::stod(ecef_x_parsed[1]);
693
694 std::vector<std::string> ecef_y_parsed;
695 boost::algorithm::split(ecef_y_parsed, inputsParams[3], boost::is_any_of(":"));
696 double ecef_y = std::stod(ecef_y_parsed[1]);
697
698 std::vector<std::string> ecef_z_parsed;
699 boost::algorithm::split(ecef_z_parsed, inputsParams[4], boost::is_any_of(":"));
700 double ecef_z = std::stod(ecef_z_parsed[1]);
701
702 carma_v2x_msgs::msg::LocationECEF ecef_loc;
703 ecef_loc.ecef_x = ecef_x;
704 ecef_loc.ecef_y = ecef_y;
705 ecef_loc.ecef_z = ecef_z;
706
707 return ecef_loc;
708 }

References process_traj_logs::split.

Referenced by mob_op_cb_STATUS().

Here is the caller graph for this function:

◆ mob_op_find_platoon_length_from_INFO_params()

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_op_find_platoon_length_from_INFO_params ( std::string  strategyParams)
private

Function to process mobility operation INFO params to find platoon length in m.

Parameters
strategyParamsThe parsed strategy params, used to find ecef locaton.
Returns
The length of the platoon in m.

Note: INFO param format: "INFO| --> LENGTH:%.2f,SPEED:%.2f,SIZE:%d,ECEFX:%.2f,ECEFY:%.2f,ECEFZ:%.2f" |----—0--------—1------—2-----—3-------—4-------—5----—|

Definition at line 760 of file platoon_strategic_ihp.cpp.

761 {
767 // For INFO params, the string format is INFO|REAR:%s,LENGTH:%.2f,SPEED:%.2f,SIZE:%d,DTD:%.2f
768 std::vector<std::string> inputsParams;
769 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
770
771 // Use the strategy params' length value and leader location to determine DTD of its rear
772 std::vector<std::string> target_platoon_length;
773 boost::algorithm::split(target_platoon_length, inputsParams[0], boost::is_any_of(":"));
774 double platoon_length = std::stod(target_platoon_length[1]);
775
776 return platoon_length;
777 }

References process_traj_logs::split.

Referenced by mob_op_cb_leader().

Here is the caller graph for this function:

◆ mob_req_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb ( const carma_v2x_msgs::msg::MobilityRequest::UniquePtr  msg)

Callback function for Mobility Request Message.

Parameters
msgMobility Request Message

Definition at line 2554 of file platoon_strategic_ihp.cpp.

2555 {
2556 // Ignore messages as long as host vehicle is stopped
2558 {
2559 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring message since host speed is below platooning speed.");
2560 return;
2561 }
2562
2563 // Check that this is a message about platooning (could be from some other Carma activity nearby)
2564 std::string strategy = msg->strategy;
2565 if (strategy.rfind(PLATOONING_STRATEGY, 0) != 0)
2566 {
2567 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring mobility operation message for " << strategy << " strategy.");
2568 return;
2569 }
2570
2571 carma_v2x_msgs::msg::MobilityResponse response;
2572 response.m_header.sender_id = config_.vehicleID;
2573 response.m_header.recipient_id = msg->m_header.sender_id;
2574 response.m_header.plan_id = msg->m_header.plan_id;
2575 response.m_header.timestamp = timer_factory_->now().nanoseconds() / 1000000;
2576
2577 // UCLA: add plantype in response
2578 response.plan_type.type = msg->plan_type.type;
2579
2580 MobilityRequestResponse req_response = handle_mob_req(*msg);
2581 if (req_response == MobilityRequestResponse::ACK)
2582 {
2583 response.is_accepted = true;
2585 }
2586 else if (req_response == MobilityRequestResponse::NACK)
2587 {
2588 response.is_accepted = false;
2590 }
2591 else
2592 {
2593 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), " NO response to mobility request. ");
2594 }
2595 }
MobilityRequestResponse handle_mob_req(const carma_v2x_msgs::msg::MobilityRequest &msg)
Function to the process and respond to the mobility request.

References platoon_strategic_ihp::ACK, config_, current_speed_, handle_mob_req(), platoon_strategic_ihp::PlatoonPluginConfig::minPlatooningSpeed, mobility_response_publisher_, platoon_strategic_ihp::NACK, PLATOONING_STRATEGY, timer_factory_, and platoon_strategic_ihp::PlatoonPluginConfig::vehicleID.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_candidatefollower()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_candidatefollower ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in candidate follower state.

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

Definition at line 1423 of file platoon_strategic_ihp.cpp.

1424 {
1425 // This state does not handle any mobility request for now
1426 // TODO Maybe it should handle some ABORT request from a waiting leader
1427 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mobility request with type " << msg.plan_type.type << " but ignored.");
1429 }

References platoon_strategic_ihp::NO_RESPONSE.

Referenced by handle_mob_req().

Here is the caller graph for this function:

◆ mob_req_cb_candidateleader()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_candidateleader ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in candidateleader state.

Parameters
msgincoming mobility request.
Returns
ACK, NACK, or No response.

Definition at line 1830 of file platoon_strategic_ihp.cpp.

1831 {
1832 bool isTargetVehicle = msg.m_header.sender_id == pm_.current_plan.peerId; // need to check: senderID (old leader)
1833 bool isCandidateJoin = msg.plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_FRONT_JOIN;
1834
1835 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(msg.location);
1836 double obj_cross_track = wm_->routeTrackPos(incoming_pose).crosstrack;
1837 bool inTheSameLane = abs(obj_cross_track - current_crosstrack_) < config_.maxCrosstrackError;
1838 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_cross_track error = " << abs(obj_cross_track - current_crosstrack_));
1839 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "obj_cross_track = " << obj_cross_track);
1840 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_crosstrack_ = " << current_crosstrack_);
1841 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "inTheSameLane = " << inTheSameLane);
1842 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isTargetVehicle = " << isTargetVehicle);
1843 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isCandidateJoin = " << isCandidateJoin);
1844 if (isCandidateJoin && inTheSameLane && isTargetVehicle)
1845 {
1846 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Old platoon leader " << pm_.current_plan.peerId << " has agreed to joining.");
1847 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Changing to PlatoonLeaderState and send ACK to the previous leader vehicle");
1849
1850 // Clean up planning info
1853
1854 // Clean up neighbor platoon info since we just joined it
1856
1858 }
1859 else
1860 {
1861 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received platoon request with vehicle id = " << msg.m_header.sender_id);
1862 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The request type is " << msg.plan_type.type << " and we choose to ignore");
1864 pm_.resetHostPlatoon(); //ASSUMES host is a solo joiner
1865
1866 // return to leader state as a solo vehicle
1869 }
1870 }
void resetHostPlatoon()
Resets all variables that might indicate other members of the host's platoon; sets the host back to s...
void clearActionPlan()
Resets necessary variables to indicate that the current ActionPlan is dead.

References platoon_strategic_ihp::ACK, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), config_, current_crosstrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, ecef_to_map_point(), platoon_strategic_ihp::LEADER, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, platoon_strategic_ihp::NACK, platoon_strategic_ihp::ActionPlan::peerId, platoon_strategic_ihp::PlatoonManager::platoonLeaderID, pm_, platoon_strategic_ihp::PlatoonManager::resetHostPlatoon(), platoon_strategic_ihp::PlatoonManager::resetNeighborPlatoon(), platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and wm_.

Referenced by handle_mob_req().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_follower()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_follower ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in follower state.

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

For cut-in join, the gap rear vehicle need to slow down once they received the request from platoon leader. Note:1. (cut-in) When joiner is in position, the leader will send the request to relevent platoon member. So no need to check for "in-position" one more time.

  1. (cut-in) If a new member is added in middle, "mob_op_cb_STATUS" will update and resort all vehicle information. So the ordering of the platoon can be updated.
  2. (depart) If the current leader is departing, the closest follower (i.e., 2nd in platoon) will become the new leader, and switch to candidate follower state. While the previous leader depart and operating in single leader state.

Definition at line 1431 of file platoon_strategic_ihp.cpp.

1432 {
1443 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
1444 std::string reccipientID = msg.m_header.recipient_id;
1445 std::string reqSenderID = msg.m_header.sender_id;
1446
1447 // Check joining plan type.
1448 bool isCutInJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
1449 bool isGapCreated = plan_type.type == carma_v2x_msgs::msg::PlanType::STOP_CREATE_GAP;
1450 // TODO: Place holder for departure
1451
1452 // Check if host is intended recipient
1453 bool isHostRecipent = pm_.getHostStaticID() == reccipientID;
1454
1455 if (isCutInJoin && isHostRecipent)
1456 {
1457 // Read requesting vehicle's joining index
1458 std::string strategyParams = msg.strategy_params;
1459 std::vector<std::string> inputsParams;
1460 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
1461 std::vector<std::string> join_index_parsed;
1462 boost::algorithm::split(join_index_parsed, inputsParams[5], boost::is_any_of(":"));
1463 int req_sender_join_index = std::stoi(join_index_parsed[1]);
1464 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Requesting join_index parsed: " << req_sender_join_index);
1465
1466 // Control vehicle speed based on cut-in type
1467 // 1. cut-in from rear
1468 if (static_cast<size_t>(req_sender_join_index) == pm_.host_platoon_.size()-1)
1469 {
1470 // Accept plan and idle (becasue rear join, gap leading vehicle do not need to slow down).
1471 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"Requested cut-in from rear, start approve cut-in and wait for lane change.");
1472 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"Due to the rear join nature, there is no need to slow down or create gap.");
1474
1475 }
1476 // 2. cut-in from middle
1477 else if (req_sender_join_index >= 0 && static_cast<size_t>(req_sender_join_index) < pm_.host_platoon_.size()-1)
1478 {
1479 // Accept plan and slow down to create gap.
1480 pm_.isCreateGap = true;
1481 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Requested cut-in index is: " << req_sender_join_index << ", approve cut-in and start create gap.");
1483 }
1484 // 3. Abnormal join index
1485 else
1486 {
1487 // Note: Leader will abort plan if reponse is not ACK for plantype "PLATOON_CUT_IN_JOIN".
1488 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Abnormal cut-in index, abort operation.");
1490 }
1491 }
1492
1493
1494 // 4. Reset to normal speed once the gap is created.
1495 else if (isGapCreated)
1496 {
1497 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Gap is created, revert to normal operating speed.");
1498 // Only reset create gap indicator, no need to send response.
1499 pm_.isCreateGap = false;
1501 }
1502
1503 // 5. Place holder for departure (host is follower)
1504
1505 // 6. Same-lane join, no need to respond.
1506 else
1507 {
1509 }
1510 }
std::string getHostStaticID() const
Returns current host static ID as a string.

References platoon_strategic_ihp::ACK, platoon_strategic_ihp::PlatoonManager::getHostStaticID(), platoon_strategic_ihp::PlatoonManager::host_platoon_, platoon_strategic_ihp::PlatoonManager::isCreateGap, platoon_strategic_ihp::NACK, platoon_strategic_ihp::NO_RESPONSE, pm_, and process_traj_logs::split.

Referenced by handle_mob_req().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_leader()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_leader ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in leader state.

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

UCLA implementation note:

  1. Here the mobility requests of joining platoon (front and rear) get processed and responded.
    1. The host is the leader of the existing platoon or single vehicle in default leader state.
    2. Request sender is the joiner.
    3. when two single vehicle meet, only allow backjoin.

Note: For front and rear jon, the JOIN_PARAMS format: JOIN_PARAMS| --> "SIZE:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%,JOINIDX:%6%" |----—0---— –1------—2------—3------—4-------—5----—|

Note: JOIN_FROM_FRONT indicate a same-lane front join. JOIN_PLATOON_AT_REAR indicate a same-lane rear join. PLATOON_CUT_IN_JOIN indicate a cut-in join, which include three cut-in methods: cut-in front, cut-in middle, and cut-in rear.

Definition at line 1574 of file platoon_strategic_ihp.cpp.

1575 {
1588 // Check joining plan type.
1589 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
1596 bool isFrontJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_FROM_FRONT;
1597 bool isRearJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_AT_REAR;
1598 bool isCutInJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
1599 bool isDepart = (plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_DEPARTURE);
1600
1601 // Ignore the request if we are already working with a join/departure process or if no join type was requested (prevents multiple applicants)
1602 if (isFrontJoin || isRearJoin || isCutInJoin || isDepart)
1603 {
1604 if (pm_.current_plan.valid){
1605 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignoring incoming request since we are already negotiating a join.");
1606 return MobilityRequestResponse::NO_RESPONSE; //TODO: replace with NACK that indicates to ask me later
1607 }
1608 }
1609 else
1610 {
1611 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received request with bogus message type " << plan_type.type << "; ignoring");
1613 }
1614
1615 // TODO: Generalize - We currently ignore the lane information for now and assume the applicant is in the same lane with us.
1616 // Determine intra-platoon conditions
1617 // We are currently checking two basic JOIN conditions:
1618 // 1. The size limitation on current platoon based on the plugin's parameters.
1619 // 2. Calculate how long that vehicle can be in a reasonable distance to actually join us.
1620 carma_v2x_msgs::msg::MobilityHeader msgHeader = msg.m_header;
1621 std::string params = msg.strategy_params;
1622 std::string applicantId = msgHeader.sender_id;
1623 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mobility JOIN request from " << applicantId << " and PlanId = " << msgHeader.plan_id);
1624 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The strategy parameters are " << params);
1625 if (params.length() == 0)
1626 {
1627 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The strategy parameters are empty, return no response");
1629 }
1630
1631 // The incoming message is "mobility Request", which has a location category.
1632 std::vector<std::string> inputsParams;
1633 boost::algorithm::split(inputsParams, params, boost::is_any_of(","));
1634
1635 // Parse applicantSize
1636 std::vector<std::string> applicantSize_parsed;
1637 boost::algorithm::split(applicantSize_parsed, inputsParams[0], boost::is_any_of(":"));
1638 int applicantSize = std::stoi(applicantSize_parsed[1]);
1639 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "applicantSize: " << applicantSize);
1640
1641 // Parse applicant Current Speed in m/s
1642 std::vector<std::string> applicantCurrentSpeed_parsed;
1643 boost::algorithm::split(applicantCurrentSpeed_parsed, inputsParams[1], boost::is_any_of(":"));
1644 double applicantCurrentSpeed = std::stod(applicantCurrentSpeed_parsed[1]);
1645 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "applicantCurrentSpeed: " << applicantCurrentSpeed);
1646
1647 // Calculate downtrack (m) based on incoming pose.
1648 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(msg.location);
1649 double applicantCurrentDtd = wm_->routeTrackPos(incoming_pose).downtrack;
1650 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "applicantCurrentmemberUpdates from ecef pose: " << applicantCurrentDtd);
1651
1652 // Calculate crosstrack (m) based on incoming pose.
1653 double applicantCurrentCtd = wm_->routeTrackPos(incoming_pose).crosstrack;
1654 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "applicantCurrentCtd from ecef pose: " << applicantCurrentCtd);
1655 bool isInLane = abs(applicantCurrentCtd - current_crosstrack_) < config_.maxCrosstrackError;
1656 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isInLane = " << isInLane);
1657
1658 // Check if we have enough room for that applicant
1659 int currentPlatoonSize = pm_.getHostPlatoonSize();
1660 bool hasEnoughRoomInPlatoon = applicantSize + currentPlatoonSize <= config_.maxPlatoonSize;
1661
1662 // rear join; platoon leader --> leader waiting
1663 if (isRearJoin)
1664 {
1665 // Log the request type
1666 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The received mobility JOIN request from " << applicantId << " and PlanId = " << msgHeader.plan_id << " is a same-lane REAR-JOIN request !");
1667
1668 // -- core condition to decided accept joiner or not
1669 if (hasEnoughRoomInPlatoon && isInLane)
1670 {
1671 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon has enough room for the applicant with size " << applicantSize);
1672 double currentRearDtd = pm_.getPlatoonRearDowntrackDistance();
1673 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon rear dtd is " << currentRearDtd);
1674 double currentGap = currentRearDtd - applicantCurrentDtd - config_.vehicleLength;
1675 double currentTimeGap = currentGap / applicantCurrentSpeed;
1676 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The gap between current platoon rear and applicant is " << currentGap << "m or " << currentTimeGap << "s");
1677 if (currentGap < config_.minAllowedJoinGap)
1678 {
1679 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"We should not receive any request from the vehicle in front of us. NACK it.");
1681 }
1682
1683 // Check if the applicant can join based on max timeGap/gap
1684 bool isDistanceCloseEnough = currentGap <= config_.maxAllowedJoinGap || currentTimeGap <= config_.maxAllowedJoinTimeGap;
1685 if (isDistanceCloseEnough)
1686 {
1687 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant is close enough and we will allow it to try to join");
1688 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to LeaderWaitingState and waiting for " << msg.m_header.sender_id << " to join");
1689
1690 // change state to leaderwaiting !
1692 waitingStartTime = timer_factory_->now().nanoseconds() / 1000000;
1693 pm_.current_plan = ActionPlan(true, waitingStartTime, msgHeader.plan_id, applicantId);
1696 }
1697 else
1698 {
1699 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant is too far away from us. NACK.");
1700 return MobilityRequestResponse::NACK; //TODO: add reason & request to try again
1701 }
1702 }
1703 else
1704 {
1705 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon does not have enough room for applicant of size " << applicantSize << ". NACK");
1707 }
1708 }
1709
1710 // front join; platoon leader --> leader aborting
1711 else if (isFrontJoin)
1712 {
1713 // Log the request type
1714 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The received mobility JOIN request from " << applicantId << " and PlanId = " << msgHeader.plan_id << " is a same-lane FRONT-JOIN request !");
1715
1716 // -- core condition to decided accept joiner or not
1717 if (hasEnoughRoomInPlatoon && isInLane)
1718 {
1719 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon has enough room for the applicant with size " << applicantSize);
1720
1721 // UCLA: change to read platoon front info
1722 double currentFrontDtd = pm_.getPlatoonFrontDowntrackDistance();
1723 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon front dtd is " << currentFrontDtd);
1724 // UCLA: adjust for calculating gap between new leader and old leader
1725 double currentGap = applicantCurrentDtd - currentFrontDtd - config_.vehicleLength;
1726 double currentTimeGap = currentGap / applicantCurrentSpeed;
1727 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The gap between current platoon front and applicant is " << currentGap << "m or " << currentTimeGap << "s");
1728
1729 if (currentGap < config_.minAllowedJoinGap)
1730 {
1731 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"The current time gap is not suitable for frontal join. NACK it.");
1733 }
1734
1735 // Check if the applicant can join based on max timeGap/gap
1736 bool isDistanceCloseEnough = currentGap <= config_.maxAllowedJoinGap || currentTimeGap <= config_.maxAllowedJoinTimeGap;
1737
1738 // UCLA: add condition: only allow front join when host platoon size >= 2 (make sure when two single vehicle join, only use back join)
1739 bool isPlatoonNotSingle = pm_.getHostPlatoonSize() >= 2 || config_.test_front_join;
1740
1741 if (isDistanceCloseEnough && isPlatoonNotSingle)
1742 {
1743 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant is close enough for frontal join, send acceptance response");
1744 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to LeaderAborting state and waiting for " << msg.m_header.sender_id << " to join as the new platoon leader");
1745
1746 // ----------------- give up leader position and look for new leader --------------------------
1747
1748 // adjust for frontal join. Platoon info is related to the platoon at back of the candidate leader vehicle.
1749 // Don't want an action plan here
1751 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
1752
1753 // If we are testing with a single vehicle representing this platoon, then we don't yet have a platoon ID,
1754 // so use the ID for the proposed joining action plan
1756 {
1757 pm_.currentPlatoonID = msgHeader.plan_id;
1758 }
1759
1760 // Store the leader ID as that of the joiner to allow run_leader_aborting to work correctly
1761 pm_.platoonLeaderID = applicantId;
1762
1763 waitingStartTime = timer_factory_->now().nanoseconds() / 1000000;
1764 pm_.current_plan.valid = false;
1766 }
1767 else
1768 {
1769 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining gap (" << currentGap << " m) is too far away from us or the target platoon size (" << pm_.getHostPlatoonSize() << ") is one. NACK.");
1770 return MobilityRequestResponse::NACK; //TODO: add reason & request to try again
1771 }
1772 }
1773 else
1774 {
1775 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon does not have enough room for applicant of size " << applicantSize << ". NACK");
1777 }
1778 }
1779
1780 // UCLA: conditions for cut-in join; platoon leader --> leading with operation
1781 else if (isCutInJoin)
1782 {
1783 // Log the request type
1784 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The received mobility JOIN request from " << applicantId << " and PlanId = " << msgHeader.plan_id << " is a CUT-IN-JOIN request !");
1785
1786 // -- core condition to decided accept joiner or not. It is necessary leader only process the first cut-in joining request.
1787 // Note: The host is the platoon leader, need to use a different method to determine if joining vehicle is nearby.
1788 if (hasEnoughRoomInPlatoon && isJoiningVehicleNearPlatoon(applicantCurrentDtd, applicantCurrentCtd))
1789 {
1790 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon has enough room for the applicant with size " << applicantSize);
1791 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant is close enough for cut-in join, send acceptance response");
1792 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to Leading with operation state and waiting for " << msg.m_header.sender_id << " to change lane");
1793 // change state to lead with operation
1795 waitingStartTime = timer_factory_->now().nanoseconds() / 1000000;
1796 pm_.current_plan = ActionPlan(true, waitingStartTime, msgHeader.plan_id, applicantId);
1799 }
1800 else
1801 {
1802 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current platoon does not have enough room or the applicant is too far away from us. NACK the request.");
1803 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current applicant size: " << applicantSize << ".");
1804 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant downtrack is: " << current_downtrack_ << ".");
1805 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The applicant crosstrack is: " << current_crosstrack_ << ".");
1807 }
1808 }
1809
1810 // TODO: Place holder for deaprture.
1811
1812 // no response
1813 else
1814 {
1815 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mobility request with type " << msg.plan_type.type << " and ignored.");
1817 }
1818 }
double getPlatoonRearDowntrackDistance()
Returns downtrack distance of the rear vehicle in platoon, in m.
double getPlatoonFrontDowntrackDistance()
UCLA: Return the platoon leader downtrack distance, in m.
bool isJoiningVehicleNearPlatoon(double joining_downtrack, double joining_crosstrack)
The method for platoon leader to determine if the joining vehicle is closeby. (Note: Used when host v...

References platoon_strategic_ihp::ACK, candidatestateStartTime, config_, current_crosstrack_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::getPlatoonFrontDowntrackDistance(), platoon_strategic_ihp::PlatoonManager::getPlatoonRearDowntrackDistance(), platoon_strategic_ihp::PlatoonManager::HostMobilityId, isJoiningVehicleNearPlatoon(), platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, platoon_strategic_ihp::PlatoonPluginConfig::maxAllowedJoinGap, platoon_strategic_ihp::PlatoonPluginConfig::maxAllowedJoinTimeGap, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, platoon_strategic_ihp::PlatoonPluginConfig::maxPlatoonSize, platoon_strategic_ihp::PlatoonPluginConfig::minAllowedJoinGap, platoon_strategic_ihp::NACK, platoon_strategic_ihp::NO_RESPONSE, platoon_strategic_ihp::PlatoonManager::platoonLeaderID, pm_, process_traj_logs::split, platoon_strategic_ihp::PlatoonPluginConfig::test_front_join, timer_factory_, platoon_strategic_ihp::ActionPlan::valid, platoon_strategic_ihp::PlatoonPluginConfig::vehicleLength, waitingStartTime, and wm_.

Referenced by handle_mob_req().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_leaderaborting()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_leaderaborting ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in leaderaborting state.

Parameters
msgincoming mobility request.
Returns
ACK, NACK, or No response.

Definition at line 1821 of file platoon_strategic_ihp.cpp.

1822 {
1823 // This state does not handle any mobility request for now
1824 // TODO Maybe it should handle some ABORT request from a candidate leader
1825 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mobility request with type " << msg.plan_type.type << " but ignored.");
1827 }

References platoon_strategic_ihp::NO_RESPONSE.

Referenced by handle_mob_req().

Here is the caller graph for this function:

◆ mob_req_cb_leaderwaiting()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_leaderwaiting ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in leader waiting state.

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

Definition at line 1513 of file platoon_strategic_ihp.cpp.

1514 {
1515 bool isTargetVehicle = msg.m_header.sender_id == pm_.current_plan.peerId;
1516 bool isCandidateJoin = msg.plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_FOLLOWER_JOIN;
1517
1518 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(msg.location);
1519 double obj_cross_track = wm_->routeTrackPos(incoming_pose).crosstrack;
1520 bool inTheSameLane = abs(obj_cross_track - current_crosstrack_) < config_.maxCrosstrackError;
1521 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_cross_track error = " << abs(obj_cross_track - current_crosstrack_));
1522 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "inTheSameLane = " << inTheSameLane);
1523
1524 // If everything is agreeable then approve the request; if it is from an unexpected vehicle or
1525 // is not a candidate join request, then we can just ignore it with no action
1527 if (isTargetVehicle && isCandidateJoin)
1528 {
1529 if (inTheSameLane)
1530 {
1531 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Target vehicle " << pm_.current_plan.peerId << " is actually joining.");
1532 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Changing to PlatoonLeaderState and send ACK to target vehicle");
1533
1534 // Change state to LEADER
1536
1537 // If we are not already in a platoon, then use this activity plan ID for the newly formed platoon
1538 if (pm_.currentPlatoonID.compare(pm_.dummyID) == 0)
1539 {
1540 pm_.currentPlatoonID = msg.m_header.plan_id;
1541 }
1542
1543 // Add the joiner to our platoon record (ASSUMES that we have not yet received a mob_op STATUS msg from joiner!)
1544 PlatoonMember newMember = PlatoonMember();
1545 newMember.staticId = msg.m_header.sender_id;
1546 newMember.vehiclePosition = wm_->routeTrackPos(incoming_pose).downtrack;
1547 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "New member being added to platoon vector whose size is currently " << pm_.host_platoon_.size());
1548 pm_.host_platoon_.push_back(newMember);
1549 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_ now thinks platoon size is " << pm_.getHostPlatoonSize());
1550
1551 // Send approval of the request
1553 // Indicate the current join activity is complete
1555 }
1556 else //correct vehicle and intent, but it's in the wrong lane
1557 {
1558 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received platoon request with vehicle id = " << msg.m_header.sender_id << " but in wrong lane. NACK");
1560
1561 // // Remove the candidate joiner from the platoon structure
1562 // if (!pm_.removeMemberById(msg.m_header.sender_id))
1563 // {
1564 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Failed to remove candidate joiner from platoon record: " << msg.m_header.sender_id);
1565 // }
1566 }
1567 }
1568
1569
1570 return response;
1571 }

References platoon_strategic_ihp::ACK, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), config_, current_crosstrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::host_platoon_, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, platoon_strategic_ihp::NACK, platoon_strategic_ihp::NO_RESPONSE, platoon_strategic_ihp::ActionPlan::peerId, pm_, platoon_strategic_ihp::PlatoonMember::staticId, platoon_strategic_ihp::PlatoonMember::vehiclePosition, and wm_.

Referenced by handle_mob_req().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_leadwithoperation()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_leadwithoperation ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in leadwithoperation state (cut-in join)

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

Definition at line 1873 of file platoon_strategic_ihp.cpp.

1874 {
1875 /*
1876 * Current leader change state to lead with opertaion once the cut-in join request is accepeted.
1877 For cut-in front, the leading vehicle will open gap for the joining vehicle.
1878 For cut-in middle, the leading vechile will request gap following vehcile to create gap.
1879 The host leading vheicle will also send lane cut-in approval response to the joining vehicle.
1880 The host leading vehicle will change to same-lane state once the lanechange completion plan was recieved.
1881
1882 */
1883
1884 // Check request plan type
1885 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
1886 std::string strategyParams = msg.strategy_params;
1887 std::string reqSenderID = msg.m_header.sender_id;
1888
1889 // Calculate downtrack (m) based on ecef.
1890 lanelet::BasicPoint2d incoming_pose = ecef_to_map_point(msg.location);
1891 // read downtrack
1892 double applicantCurrentDtd = wm_->routeTrackPos(incoming_pose).downtrack;
1893 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Applicant downtrack from ecef pose: " << applicantCurrentDtd);
1894
1895 // Read requesting join index
1896 std::vector<std::string> inputsParams;
1897 boost::algorithm::split(inputsParams, strategyParams, boost::is_any_of(","));
1898
1899 std::vector<std::string> join_index_parsed;
1900 boost::algorithm::split(join_index_parsed, inputsParams[5], boost::is_any_of(":"));
1901 int req_sender_join_index = std::stoi(join_index_parsed[1]);
1902 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Requesting join_index parsed: " << req_sender_join_index);
1903
1904 if (plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN)
1905 {
1906 // Send response
1907 // ----- CUT-IN front -----
1908 if (req_sender_join_index == -1)
1909 {
1910 // determine if joining vehicle in position for cut-in front - this value must be > 0
1911 double cutinDtdDifference = applicantCurrentDtd - current_downtrack_ - config_.vehicleLength;
1912 // check dtd between current leader (host) and joining vehicle is far enough away to avoid a collision
1913 bool isFrontJoinerInPosition = cutinDtdDifference >= 1.5*config_.vehicleLength;
1914
1915 if (isFrontJoinerInPosition)
1916 {
1917 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle is cutting in from front. Gap is already sufficient.");
1919 }
1920 else if (cutinDtdDifference > 0.0 && cutinDtdDifference < 1.5*config_.vehicleLength)
1921 {
1922 // slow down leader to allow joiner cut-in
1923 pm_.isCreateGap = true;
1924 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle is cutting in from front.");
1925 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Host (leader) slow down notified, joining vehicle can prepare to join");
1927 }
1928
1929 else
1930 {
1931 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Front join geometry violation. NACK. cutinDtdDifference = " << cutinDtdDifference);
1934 }
1935 }
1936
1937 // ----- CUT-IN rear -----
1938 else if (static_cast<size_t>(req_sender_join_index) == pm_.host_platoon_.size()-1)
1939 {
1940 // determine if joining vehicle in position for cut-in rear
1941 // To pass, the joining vehicle need to be behind the last member, within three vehicle length.
1942 //TODO: should it also test CTE to ensure vehicle is in same lane?
1943 double platoonEndVehicleDtd = pm_.host_platoon_[pm_.host_platoon_.size()-1].vehiclePosition - config_.vehicleLength;
1944 double rearGap = platoonEndVehicleDtd - applicantCurrentDtd;
1945 bool isRearJoinerInPosition = rearGap >= 0 && rearGap <= config_.maxCutinGap;//3*config_.vehicleLength; TODO: temporary increase
1946
1947 if (isRearJoinerInPosition)
1948 {
1949 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility cut-in-rear-Join request to relavent platoon member, host is leader.");
1950 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"Published Mobility cut-in-rear-Join request to relavent platoon members to signal gap creation.");
1951 pm_.isCreateGap = true;
1953 }
1954 else
1955 {
1956 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Rear join geometry violation. NACK. rearGap = " << rearGap);
1959 }
1960 }
1961 // ----- CUT-IN middle -----
1962 else //any other join_index value
1963 {
1964 // determine if joining vehicle in position for cut-in mid
1965 // To pass, the joining vehicle should be in front of the gap following vehicle, within three vehicle length.
1966 double gapFollowingVehicleDtd = pm_.host_platoon_[req_sender_join_index].vehiclePosition;
1967 double gapFollowerDiff = applicantCurrentDtd - gapFollowingVehicleDtd;
1968 bool isMidJoinerInPosition = gapFollowerDiff >=0 && gapFollowerDiff <= 3*config_.vehicleLength;
1969
1970 // Task 4: send request to index member to slow down (i.e., set isCreateGap to true)
1971 // Note: Request recieving vehicle set pm_.isCreateGap
1972 if (isMidJoinerInPosition)
1973 {
1974 // compose request (Note: The recipient should be the gap following vehicle.)
1975 carma_v2x_msgs::msg::MobilityRequest request;
1976 request.m_header.plan_id = boost::uuids::to_string(boost::uuids::random_generator()());
1977 // Note: For cut-in mid, notify gap rear member to create/increase gap.
1978 std::string recipient_ID = pm_.host_platoon_[req_sender_join_index+1].staticId;
1979 request.m_header.sender_id = config_.vehicleID;
1980 request.m_header.timestamp = timer_factory_->now().nanoseconds() / 1000000;;
1981 // UCLA: add plan type, add this in cav_mwgs/plan_type
1982 request.plan_type.type = carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
1983 request.strategy = PLATOONING_STRATEGY;
1984
1985 double platoon_size = pm_.getHostPlatoonSize();
1986
1987 boost::format fmter(JOIN_PARAMS); // Note: Front and rear join uses same params, hence merge to one param for both condition.
1988 fmter %platoon_size; // index = 0
1989 fmter %current_speed_; // index = 1, in m/s
1990 fmter %pose_ecef_point_.ecef_x; // index = 2
1991 fmter %pose_ecef_point_.ecef_y; // index = 3
1992 fmter %pose_ecef_point_.ecef_z; // index = 4
1993 fmter %req_sender_join_index; // index = 5
1994
1995 request.strategy_params = fmter.str();
1996 request.urgency = 50;
1997 request.location = pose_to_ecef(pose_msg_);
1998 // note: for rear join, cut-in index == host_platoon_.size()-1; for join from front, index == -1
1999 // for cut-in in middle, index indicate the gap leading vehicle's index
2001 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility cut-in-mid-Join request to relavent platoon members to signal gap creation, host is leader.");
2002 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"Published Mobility cut-in-mid-Join request to relavent platoon members to signal gap creation.");
2003 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The joining vehicle is cutting in at index: "<< req_sender_join_index <<". Notify gap rear vehicle with ID: " << recipient_ID << " to slow down");
2005 }
2006 else
2007 {
2008 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Mid join geometry violation. NACK. gapFollwerDiff = " << gapFollowerDiff);
2011 }
2012 }
2013 }
2014
2015 // task 2: For cut-in from front, the leader need to stop creating gap
2016 else if (plan_type.type == carma_v2x_msgs::msg::PlanType::STOP_CREATE_GAP)
2017 {
2018 // reset create gap indicator
2019 pm_.isCreateGap = false;
2020 // no need to response, simple reset the indicator
2022 }
2023
2024 // task 3 cut-in front: After creating gap, revert back to same-lane operation
2025 else if (plan_type.type == carma_v2x_msgs::msg::PlanType::CUT_IN_FRONT_DONE)
2026 {
2027 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cut-in from front lane change finished, leader revert to same-lane maneuver.");
2029 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2030 // if testing with two vehicles, use plan id as platoon id
2031 if (pm_.currentPlatoonID.compare(pm_.dummyID) == 0)
2032 // if (config_.allowCutinJoin)
2033 {
2034 pm_.currentPlatoonID = msg.m_header.plan_id;
2035 }
2036 // Store the leader ID as that of the joiner to allow run_leader_aborting to work correctly
2037 pm_.platoonLeaderID = msg.m_header.sender_id;
2038 pm_.current_plan.valid = false;
2040 }
2041
2042 // task 4 cut-in from middle/rear
2043 else if (plan_type.type == carma_v2x_msgs::msg::PlanType::CUT_IN_MID_OR_REAR_DONE)
2044 {
2045 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cut-in from mid/rear lane change finished, leader revert to same-lane maneuver.");
2047 waitingStartTime = timer_factory_->now().nanoseconds() / 1000000;
2049 }
2050
2051
2052 // task 5: if other joining vehicle send joning request, NACK it since there is already a cut-in join going on.
2053 else
2054 {
2055 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CUT-IN join maneuver is already in operation, NACK incoming join requests from other candidates.");
2056 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Plan Type: " << plan_type.type );
2058 }
2059
2060 // this statement should never be reached, but will ensure reasonable behavior in case of coding error above
2061 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "End of method reached! Apparent logic fault above.");
2062 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "End of method reached! Apparent logic fault above."); //since WARN doesn't always print
2064 }

References platoon_strategic_ihp::ACK, candidatestateStartTime, config_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, ecef_to_map_point(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::host_platoon_, platoon_strategic_ihp::PlatoonManager::isCreateGap, JOIN_PARAMS, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::PlatoonPluginConfig::maxCutinGap, mobility_request_publisher_, platoon_strategic_ihp::NACK, platoon_strategic_ihp::NO_RESPONSE, PLATOONING_STRATEGY, platoon_strategic_ihp::PlatoonManager::platoonLeaderID, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), process_traj_logs::split, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::ActionPlan::valid, platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, platoon_strategic_ihp::PlatoonPluginConfig::vehicleLength, waitingStartTime, and wm_.

Referenced by handle_mob_req().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_req_cb_preparetojoin()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_preparetojoin ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in preparetojoin state (cut-in join)

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

Definition at line 2067 of file platoon_strategic_ihp.cpp.

2068 {
2069 // This state does not handle any mobility request for now
2070 // TODO: if joining vehicle need to adjust speed, the leader should request it and the request should be handled here.
2071 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received mobility request with type " << msg.plan_type.type << " but ignored.");
2073 }

References platoon_strategic_ihp::NO_RESPONSE.

Referenced by handle_mob_req().

Here is the caller graph for this function:

◆ mob_req_cb_standby()

MobilityRequestResponse platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_req_cb_standby ( const carma_v2x_msgs::msg::MobilityRequest &  msg)
private

Function to process mobility request in standby state.

Parameters
msgincoming mobility request
Returns
ACK, NACK, or No response

Definition at line 1416 of file platoon_strategic_ihp.cpp.

1417 {
1418 // In standby state, the plugin is not responsible for replying to any request messages
1419 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "STANDBY state does nothing with msg from " << msg.m_header.sender_id);
1421 }

References platoon_strategic_ihp::NO_RESPONSE.

Referenced by handle_mob_req().

Here is the caller graph for this function:

◆ mob_resp_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb ( const carma_v2x_msgs::msg::MobilityResponse::UniquePtr  msg)

Callback function for Mobility Response Message.

Parameters
msgMobility Response Message

If any of the three condition (i.e., isCurrPlanValid, isForCurrentPlan and isFromTargetVehicle) was not satisfied, return ignore as this message was not intended for the host.

Definition at line 2080 of file platoon_strategic_ihp.cpp.

2081 {
2082 // Firstly, check eligibility of the received message.
2083 bool isCurrPlanValid = pm_.current_plan.valid; // Check if current plan is still valid (i.e., not timed out).
2084 bool isForCurrentPlan = msg->m_header.plan_id == pm_.current_plan.planId; // Check if plan Id matches.
2085 bool isFromTargetVehicle = msg->m_header.sender_id == pm_.current_plan.peerId; // Check if expected peer ID and sender ID matches.
2086 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "mob_resp_cb: isCurrPlanValid = " << isCurrPlanValid << ", isForCurrentPlan = " <<
2087 isForCurrentPlan << ", isFromTargetVehicle = " << isFromTargetVehicle);
2088 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "sender ID = " << msg->m_header.sender_id << ", current peer ID = " << pm_.current_plan.peerId);
2089 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "incoming plan ID = " << msg->m_header.plan_id << "current plan ID = " << pm_.current_plan.planId);
2090
2091 if (!(isCurrPlanValid && isForCurrentPlan && isFromTargetVehicle))
2092 {
2097 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), " Ignore the received response message as it was not intended for the host vehicle.");
2098 return;
2099 }
2101 {
2102 mob_resp_cb_leader(*msg);
2103 }
2105 {
2107 }
2109 {
2111 }
2113 {
2115 }
2117 {
2118 mob_resp_cb_standby(*msg);
2119 }
2120 // UCLA: add leader aboorting
2122 {
2124 }
2125 //UCLA: add candidate leader
2127 {
2129 }
2130 // UCLA: add lead with operation for cut-in join
2132 {
2134 }
2135 // UCLA: add prepare to join for cut-in join
2137 {
2139 }
2140 // TODO: Place holder for departure.
2141 }
void mob_resp_cb_leadwithoperation(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in leadwithoperation state (cut-in join)
void mob_resp_cb_candidateleader(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in candidateleader state.
void mob_resp_cb_leader(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in leader state.
void mob_resp_cb_follower(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in follower state.
void mob_resp_cb_preparetojoin(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in preparetojoin state.
void mob_resp_cb_standby(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in standby state.
void mob_resp_cb_candidatefollower(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in candidate follower state.
void mob_resp_cb_leaderwaiting(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in leader waiting state.
void mob_resp_cb_leaderaborting(const carma_v2x_msgs::msg::MobilityResponse &msg)
Function to process mobility response in leaderaborting state.

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, mob_resp_cb_candidatefollower(), mob_resp_cb_candidateleader(), mob_resp_cb_follower(), mob_resp_cb_leader(), mob_resp_cb_leaderaborting(), mob_resp_cb_leaderwaiting(), mob_resp_cb_leadwithoperation(), mob_resp_cb_preparetojoin(), mob_resp_cb_standby(), platoon_strategic_ihp::ActionPlan::peerId, platoon_strategic_ihp::ActionPlan::planId, pm_, platoon_strategic_ihp::PREPARETOJOIN, platoon_strategic_ihp::STANDBY, and platoon_strategic_ihp::ActionPlan::valid.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_resp_cb_candidatefollower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_candidatefollower ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in candidate follower state.

Parameters
msgincoming mobility response

Definition at line 2149 of file platoon_strategic_ihp.cpp.

2150 {
2151 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Callback for candidate follower ");
2152
2153 // Check if current plan is still valid (i.e., not timed out)
2155 {
2156 bool isForCurrentPlan = msg.m_header.plan_id == pm_.current_plan.planId;
2157 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isForCurrentPlan " << isForCurrentPlan);
2158
2159 // Check the response is received correctly (i.e., host vehicle is the desired receiver).
2160 if (isForCurrentPlan)
2161 {
2162 if (msg.is_accepted)
2163 {
2164 // We change to follower state and start to actually follow that leader
2165 // The platoon manager also need to change the platoon Id to the one that the target leader is using
2167 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.currentPlatoonID: " << pm_.currentPlatoonID);
2168 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.targetPlatoonID: " << pm_.currentPlatoonID);
2169
2170 if (pm_.targetPlatoonID.compare(pm_.dummyID) != 0)
2171 {
2173 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.currentPlatoonID now: " << pm_.currentPlatoonID);
2175 }
2176 else
2177 {
2178 pm_.currentPlatoonID = msg.m_header.plan_id;
2179 }
2180
2181 pm_.changeFromLeaderToFollower(pm_.currentPlatoonID, msg.m_header.sender_id);
2182 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The leader " << msg.m_header.sender_id << " agreed on our join. Change to follower state.");
2183 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"changed to follower");
2185 }
2186 else
2187 {
2188 // We change back to normal leader state and try to join other platoons
2189 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The leader " << msg.m_header.sender_id << " does not agree on our join. Change back to leader state.");
2190 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Trying again..");
2191 // join plan failed, but we still need the peerid
2192 pm_.current_plan.valid = false;
2193
2194 // Clear out any platooning plan we don't need
2195 if (pm_.getHostPlatoonSize() == 1)
2196 {
2198 }
2199 }
2200
2201 }
2202 else
2203 {
2204 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore received response message because it is not for the current plan.");
2205 }
2206 }
2207 else
2208 {
2209 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore received response message because we are not in any negotiation process.");
2210 }
2211 }
void changeFromLeaderToFollower(std::string newPlatoonId, std::string newLeaderId)
Update status when state change from Leader to Follower.

References platoon_strategic_ihp::PlatoonManager::changeFromLeaderToFollower(), platoon_strategic_ihp::PlatoonManager::clearActionPlan(), platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::ActionPlan::planId, pm_, platoon_strategic_ihp::PlatoonManager::resetHostPlatoon(), platoon_strategic_ihp::PlatoonManager::resetNeighborPlatoon(), platoon_strategic_ihp::PlatoonManager::targetPlatoonID, and platoon_strategic_ihp::ActionPlan::valid.

Referenced by mob_resp_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_resp_cb_candidateleader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_candidateleader ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in candidateleader state.

Parameters
msgincoming mobility response.

Definition at line 2446 of file platoon_strategic_ihp.cpp.

2447 {
2448 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CANDIDATELEADER state does nothing with msg from " << msg.m_header.sender_id);
2449 }

Referenced by mob_resp_cb().

Here is the caller graph for this function:

◆ mob_resp_cb_follower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_follower ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in follower state.

Parameters
msgincoming mobility response

UCLA Note:

This method was implemented with the purpose of updating the platoon related references (i.e., platoon leader, platoon Id) to the new leader that joined from front. Changing the existing follower to candidate follower state will initiate a member update and therefore point all refernce to the new leader.

For rear join, since the existing follower already following the platoon leader. There is no need to establish communication hence no response will be handled for rear-join.

Definition at line 2223 of file platoon_strategic_ihp.cpp.

2224 {
2237 // UCLA: read plan type
2238 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
2239
2240 // UCLA: determine joining type
2241 bool isFrontJoin = (plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_FROM_FRONT);
2242
2243 //TODO: when would this code block ever be used? A normal follower would have to talk to a front joiner.
2244 // UCLA: add response so follower can change to candidate follower, then change leader
2245 if (isFrontJoin && msg.is_accepted)
2246 {
2247 // if frontal join is accepted, change followers to candidate follower to update leader
2248 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received positive response for front-join plan id = " << pm_.current_plan.planId);
2249 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to CandidateFollower state and prepare to update platoon information");
2250 // Change to candidate follower state and request a new plan to catch up with the front platoon
2252 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2253 }
2254
2255 // TODO: Place holder for follower departure.
2256 }

References platoon_strategic_ihp::CANDIDATEFOLLOWER, candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::ActionPlan::planId, pm_, and timer_factory_.

Referenced by mob_resp_cb().

Here is the caller graph for this function:

◆ mob_resp_cb_leader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_leader ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in leader state.

Parameters
msgincoming mobility response

UCLA implementation note: This is where the Mobility response gets processed for leader state.

If the host is a single vehicle in the leader state, then the host vehicle is the joiner vehicle (frontal join: candidate leader; back join: candidate follower), and the response sender is the existing platoon leader (front join: aborting leader, back join: waiting leader).

If the host is the current platoon leader, all three case will be false and no further action is needed.

Disclaimer: Currently, if the host vehicle is platoon leader, there is no further action needed when receiving the mobility response. However, future development may add functions in this mehtod.

Definition at line 2259 of file platoon_strategic_ihp.cpp.

2260 {
2275 // UCLA: read plan type
2276 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
2277 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "plan_type.type = " << plan_type.type);
2278
2279 // UCLA: determine joining type
2280 bool isCutInJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN && !config_.test_front_join;
2281 bool isRearJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_AT_REAR && !config_.test_front_join;
2282 bool isFrontJoin = plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_FROM_FRONT || config_.test_front_join;
2283 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Joining type: isRearJoin = " << isRearJoin);
2284 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Joining type: isFrontJoin = " << isFrontJoin);
2285 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Joining type: isCutInJoin = " << isCutInJoin);
2286
2287 // Check if current plan is still valid (i.e., not timed out).
2289 {
2290 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "My plan id = " << pm_.current_plan.planId << " and response plan Id = " << msg.m_header.plan_id);
2291 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Expected peer id = " << pm_.current_plan.peerId << " and response sender Id = " << msg.m_header.sender_id);
2292
2293 // Check the response is received correctly (i.e., host vehicle is the desired receiver).
2294 if (pm_.current_plan.planId == msg.m_header.plan_id && pm_.current_plan.peerId == msg.m_header.sender_id)
2295 {
2296 // rear join
2297 if (isRearJoin && msg.is_accepted)
2298 {
2299 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received positive response for plan id = " << pm_.current_plan.planId);
2300 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to CandidateFollower state and notify trajectory failure in order to replan");
2301
2302 // Change to candidate follower state and wait to catch up with the front platoon
2304 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2305 pm_.current_plan.valid = false; //but leave peerId intact for use in second request
2306 }
2307
2308 // UCLA: frontal join (candidate leader, inherited from leaderwaiting)
2309 else if (isFrontJoin && msg.is_accepted)
2310 {
2311 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received positive response for plan id = " << pm_.current_plan.planId);
2312 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to CandidateLeader state and prepare to become new leader. ");
2313
2314 // Change to candidate leader and idle
2316 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2317 pm_.current_plan.valid = false; //but leave peerId intact for use in second request
2318
2319 // Set the platoon ID to that of the target platoon even though we haven't yet joined;
2320 // for front join this is necessary for the aborting leader to recognize us as an incoming
2321 // member (via our published op STATUS messages)
2323 }
2324
2325 // UCLA: CutIn join
2326 else if (isCutInJoin && msg.is_accepted)
2327 {
2328 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received positive response for plan id = " << pm_.current_plan.planId);
2329 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Change to Prepare to join state and prepare to change lane. ");
2330
2331 // Change to candidate leader and idle
2333 pm_.neighbor_platoon_leader_id_ = msg.m_header.sender_id;
2334 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2335 pm_.current_plan.valid = false; //but leave peerId intact for use in second request
2336 }
2337
2338 // Current leader of an actual platoon (to be in this method host is in leader state)
2339 else if(pm_.getHostPlatoonSize() >= 2)
2340 {
2341 //TODO future: add logic here to allow two platoons to join together
2342
2343 // Keep the leader idling, since this must be a bogus response
2344 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Host received response for joining vehicles, remain idling as the host is a current platoon leader.");
2345 }
2346 else
2347 {
2348 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Received negative response for plan id = " << pm_.current_plan.planId << ". Resetting plan & platoon info.");
2349 // Forget about the previous plan totally
2352 }
2353 }
2354 else
2355 {
2356 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore the response message because planID match: " << (pm_.current_plan.planId == msg.m_header.plan_id));
2357 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "My plan id = " << pm_.current_plan.planId << " and response plan Id = " << msg.m_header.plan_id);
2358 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "And peer id match " << (pm_.current_plan.peerId == msg.m_header.sender_id));
2359 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Expected peer id = " << pm_.current_plan.peerId << " and response sender Id = " << msg.m_header.sender_id);
2360 }
2361 }
2362 }

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), config_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::neighbor_platoon_leader_id_, platoon_strategic_ihp::ActionPlan::peerId, platoon_strategic_ihp::ActionPlan::planId, pm_, platoon_strategic_ihp::PREPARETOJOIN, platoon_strategic_ihp::PlatoonManager::resetHostPlatoon(), platoon_strategic_ihp::PlatoonManager::targetPlatoonID, platoon_strategic_ihp::PlatoonPluginConfig::test_front_join, timer_factory_, and platoon_strategic_ihp::ActionPlan::valid.

Referenced by mob_resp_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_resp_cb_leaderaborting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_leaderaborting ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in leaderaborting state.

Parameters
msgincoming mobility response.

UCLA implementation note: This state is the middle state to handle the leader aborting process of the previous platoon leader in a front join scenario. Within this state, the previous leader will check for front joining vehicle's position and will not handle any further mobility requests.

Note: As the previous leader will join the new leader (joined from front), the corresponding join request will be send out by the previos leader.

Definition at line 2365 of file platoon_strategic_ihp.cpp.

2366 {
2378 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Callback for leader aborting !");
2379
2380 // Check if current plan is still valid (i.e., not timed out).
2382 {
2383 bool isForCurrentPlan = msg.m_header.plan_id == pm_.current_plan.planId;
2384 bool isForFrontJoin = msg.plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_FRONT_JOIN;
2385
2386 if (msg.plan_type.type == carma_v2x_msgs::msg::PlanType::UNKNOWN){
2387 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "*** plan type UNKNOWN");
2388 }else if (msg.plan_type.type == carma_v2x_msgs::msg::PlanType::JOIN_PLATOON_FROM_FRONT){
2389 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "*** plan type JOIN_PLATOON_FROM_FRONT");
2390 }else if (msg.plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN){
2391 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "*** plan type PLATOON_CUT_IN_JOIN");
2392 }else {
2393 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "*** plan type not captured.");
2394 }
2395
2396 bool isFromTargetVehicle = msg.m_header.sender_id == pm_.current_plan.peerId;
2397 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "msg.m_header.sender_id " << msg.m_header.sender_id);
2398 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Plan Type " << msg.plan_type.type);
2399 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isForFrontJoin " << isForFrontJoin);
2400 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isForCurrentPlan " << isForCurrentPlan);
2401 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isFromTargetVehicle " << isFromTargetVehicle);
2402
2403 // Check the response is received correctly (i.e., host vehicle is the desired receiver).
2404 if (isForCurrentPlan && isFromTargetVehicle && isForFrontJoin)
2405 {
2406 if (msg.is_accepted)
2407 {
2408 // We change to follower state and start to actually follow the new leader
2409 // The platoon manager also need to change the platoon Id to the one that the target leader is using
2411 pm_.changeFromLeaderToFollower(pm_.currentPlatoonID, msg.m_header.sender_id);
2412 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The new leader " << msg.m_header.sender_id << " agreed on the frontal join. Change to follower state.");
2413 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"changed to follower");
2414
2415 // reset leader aborting request marker
2417 }
2418 else
2419 {
2420 // We change back to normal leader state
2421 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The new leader " << msg.m_header.sender_id << " does not agree on the frontal join. Change back to leader state.");
2423 // We were already leading a platoon, so don't erase any of that info. But we need to remove the erstwhile candidate
2424 // leader from our platoon roster; we know it is in position 0, so just remove that element
2425 if (!pm_.removeMember(0))
2426 {
2427 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Failed to remove candidate leader from the platoon!");
2428 }
2429 }
2430
2431 // Clean up the joining plan
2433 }
2434 else
2435 {
2436 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore received response message because it is not for the current plan.");
2437 }
2438 }
2439 else
2440 {
2441 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Ignore received response message because we are not in any negotiation process.");
2442 }
2443 }
bool removeMember(const size_t mem)
Removes a single member from the internal record of platoon members.

References platoon_strategic_ihp::PlatoonManager::changeFromLeaderToFollower(), platoon_strategic_ihp::PlatoonManager::clearActionPlan(), platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::LEADER, numLeaderAbortingCalls_, platoon_strategic_ihp::ActionPlan::peerId, platoon_strategic_ihp::ActionPlan::planId, pm_, platoon_strategic_ihp::PlatoonManager::removeMember(), and platoon_strategic_ihp::ActionPlan::valid.

Referenced by mob_resp_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_resp_cb_leaderwaiting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_leaderwaiting ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in leader waiting state.

Parameters
msgincoming mobility response

Leader waiting is the state to check joining vehicle is in proper position and to prevent platoon leader from receiving messages from other CAVs in leader state. There was no response involved in this state, hence no action needed in this section.

Definition at line 2213 of file platoon_strategic_ihp.cpp.

2214 {
2220 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LEADERWAITING state does nothing with msg from " << msg.m_header.sender_id);
2221 }

Referenced by mob_resp_cb().

Here is the caller graph for this function:

◆ mob_resp_cb_leadwithoperation()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_leadwithoperation ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in leadwithoperation state (cut-in join)

Parameters
msgincoming mobility response

Definition at line 2452 of file platoon_strategic_ihp.cpp.

2453 {
2454 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LEADWITHOPERATION state does nothing with msg from " << msg.m_header.sender_id);
2455 }

Referenced by mob_resp_cb().

Here is the caller graph for this function:

◆ mob_resp_cb_preparetojoin()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_preparetojoin ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in preparetojoin state.

Parameters
msgincoming mobility response

Definition at line 2458 of file platoon_strategic_ihp.cpp.

2459 {
2460 /*
2461 If leader notify the member to slow down and ACK the request,
2462 start to check the gap and change lane when gap is large enough
2463 */
2464
2465 carma_v2x_msgs::msg::PlanType plan_type = msg.plan_type;
2466 bool isCreatingGap = plan_type.type == carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
2467 bool isFinishLaneChangeFront = plan_type.type == carma_v2x_msgs::msg::PlanType::CUT_IN_FRONT_DONE;
2468 bool isFinishLaneChangeMidorRear = plan_type.type == carma_v2x_msgs::msg::PlanType::CUT_IN_MID_OR_REAR_DONE;
2469 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isCreatingGap = " << isCreatingGap << ", is_neighbor_record_complete = " << pm_.is_neighbor_record_complete_);
2470
2471 if (!msg.is_accepted)
2472 {
2473 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Request " << msg.m_header.plan_id << " was rejected by leader.");
2474 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Action Plan reset.");
2475 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Trying again....");
2476 pm_.current_plan.valid = false;
2478 return;
2479 }
2480 // UCLA: Create Gap or perform a rear join (no gap creation necessary)
2481 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.is_neighbor_record_complete_ " << pm_.is_neighbor_record_complete_);
2482 if (isCreatingGap && pm_.is_neighbor_record_complete_)
2483 {
2484
2485 // task 2: set indicator if gap is safe
2486 safeToLaneChange_ = true;
2487 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Gap is now sufficiently large.");
2488 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "in mob_resp_cb safeToLaneChange_: " << safeToLaneChange_);
2489
2490 // task 3: notify gap-rear vehicle to stop slowing down
2491 carma_v2x_msgs::msg::MobilityRequest request;
2492 request.m_header.plan_id = boost::uuids::to_string(boost::uuids::random_generator()());
2493 request.m_header.recipient_id = pm_.current_plan.peerId;
2494 request.m_header.sender_id = config_.vehicleID;
2495 request.m_header.timestamp = timer_factory_->now().nanoseconds() / 1000000;;
2496 // UCLA: A new plan type to stop creat gap.
2497 request.plan_type.type = carma_v2x_msgs::msg::PlanType::STOP_CREATE_GAP;
2498 request.strategy = PLATOONING_STRATEGY;
2499 request.urgency = 50;
2500 request.location = pose_to_ecef(pose_msg_);
2501 double platoon_size = pm_.getHostPlatoonSize();
2502
2503 boost::format fmter(JOIN_PARAMS);
2504 fmter %platoon_size; // index = 0
2505 fmter %current_speed_; // index = 1, in m/s
2506 fmter %pose_ecef_point_.ecef_x; // index = 2
2507 fmter %pose_ecef_point_.ecef_y; // index = 3
2508 fmter %pose_ecef_point_.ecef_z; // index = 4
2509 fmter %target_join_index_; // index = 5
2510
2511 request.strategy_params = fmter.str();
2513 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility Candidate-Join request to the leader to stop creating gap");
2514 }
2515
2516 // UCLA: Revert to same-lane for cut-in front
2517 else if (isFinishLaneChangeFront)
2518 {
2519 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cut-in from front lane change finished, the joining vehicle revert to same-lane maneuver.");
2521 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2522 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.currentPlatoonID: " << pm_.currentPlatoonID);
2523 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.targetPlatoonID: " << pm_.targetPlatoonID);
2524 if (pm_.targetPlatoonID.compare(pm_.dummyID) != 0)
2525 {
2527 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.currentPlatoonID now: " << pm_.currentPlatoonID);
2528 }
2529
2530 pm_.current_plan.valid = false; //but leave peerId intact for use in second request
2531 }
2532
2533 // UCLA: Revert to same-lane operation for cut-in from middle/rear
2534 else if (isFinishLaneChangeMidorRear)
2535 {
2536 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cut-in from mid or rear, the lane change finished, the joining vehicle revert to same-lane maneuver.");
2538 candidatestateStartTime = timer_factory_->now().nanoseconds() / 1000000;
2539 pm_.current_plan.valid = false; //but leave peerId intact for use in second request
2540
2541 }
2542
2543 else
2544 {
2545 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "End of mob_resp_cb_preparetojoin");
2546 }
2547 }

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, candidatestateStartTime, config_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonManager::currentPlatoonID, platoon_strategic_ihp::PlatoonManager::dummyID, platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::is_neighbor_record_complete_, JOIN_PARAMS, platoon_strategic_ihp::LEADER, mobility_request_publisher_, platoon_strategic_ihp::ActionPlan::peerId, PLATOONING_STRATEGY, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), safeToLaneChange_, target_join_index_, platoon_strategic_ihp::PlatoonManager::targetPlatoonID, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::ActionPlan::valid, and platoon_strategic_ihp::PlatoonPluginConfig::vehicleID.

Referenced by mob_resp_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mob_resp_cb_standby()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mob_resp_cb_standby ( const carma_v2x_msgs::msg::MobilityResponse &  msg)
private

Function to process mobility response in standby state.

Parameters
msgincoming mobility response

Definition at line 2143 of file platoon_strategic_ihp.cpp.

2144 {
2145 // In standby state, it will not send out any requests so it will also ignore all responses
2146 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "STANDBY state does nothing with msg from " << msg.m_header.sender_id);
2147 }

Referenced by mob_resp_cb().

Here is the caller graph for this function:

◆ onSpin()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::onSpin ( )

Spin callback function.

Definition at line 3063 of file platoon_strategic_ihp.cpp.

3064 {
3065 // Update the platoon manager for host's current location & speeds
3068
3070 {
3071 run_leader();
3072 }
3074 {
3075 run_follower();
3076 }
3078 {
3080 }
3082 {
3084 }
3085 // UCLA: added for frontal join
3087 {
3089 }
3090 // UCLA: added for frontal join
3092 {
3094 }
3095 // UCLA: added lead with operationfor CUT-IN join
3097 {
3099 }
3100 // UCLA: added prepare to join for CUT-IN join
3102 {
3104 }
3106 {
3107 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "standby state, nothing to do");
3108 }
3109 // coding oversight
3110 else
3111 {
3112 RCLCPP_ERROR_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "///// unhandled state " << pm_.current_platoon_state);
3113 }
3114 // TODO: Place holder for departure
3115
3116 carma_planning_msgs::msg::PlatooningInfo platoon_status = composePlatoonInfoMsg();
3117 platooning_info_publisher_(platoon_status);
3118
3119 return true;
3120 }
void updateHostSpeeds(const double cmdSpeed, const double actualSpeed)
Stores the latest info on host vehicle's command & actual speeds.
void updateHostPose(const double downtrack, const double crosstrack)
Stores the latest info on location of the host vehicle.
void run_candidate_follower()
Run Candidate Follower State.
void run_prepare_to_join()
UCLA Run prepare to join State.
void run_lead_with_operation()
UCLA Run lead with operation State.
carma_planning_msgs::msg::PlatooningInfo composePlatoonInfoMsg()
Compose Platoon information message.

References platoon_strategic_ihp::CANDIDATEFOLLOWER, platoon_strategic_ihp::CANDIDATELEADER, cmd_speed_, composePlatoonInfoMsg(), current_crosstrack_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::FOLLOWER, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::LEADERABORTING, platoon_strategic_ihp::LEADERWAITING, platoon_strategic_ihp::LEADWITHOPERATION, platooning_info_publisher_, pm_, platoon_strategic_ihp::PREPARETOJOIN, run_candidate_follower(), run_candidate_leader(), run_follower(), run_lead_with_operation(), run_leader(), run_leader_aborting(), run_leader_waiting(), run_prepare_to_join(), platoon_strategic_ihp::STANDBY, platoon_strategic_ihp::PlatoonManager::updateHostPose(), and platoon_strategic_ihp::PlatoonManager::updateHostSpeeds().

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ plan_maneuver_cb()

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::plan_maneuver_cb ( carma_planning_msgs::srv::PlanManeuvers::Request &  req,
carma_planning_msgs::srv::PlanManeuvers::Response &  resp 
)

Callback function to the maneuver request.

Parameters
reqManeuver service request
respManeuver service response
Returns
Mobility response message

Definition at line 3224 of file platoon_strategic_ihp.cpp.

3225 {
3226 // use current position to find lanelet ID
3227 lanelet::BasicPoint2d current_loc(pose_msg_.pose.position.x, pose_msg_.pose.position.y);
3228
3229 // *** get the actually closest lanelets that relate to current location (n=10) ***//
3230 auto current_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, current_loc, 10);
3231
3232 lanelet::ConstLanelet current_lanelet;
3233
3234 // To avoid overlapping lanelets, compare the nearest lanelets with the route
3235 for (auto llt: current_lanelets)
3236 {
3237 if (wm_->getRoute()->contains(llt.second))
3238 {
3239 current_lanelet = llt.second;
3240 break;
3241 }
3242 }
3243
3244 // raise warn if no path was found
3245 if(current_lanelets.size() == 0)
3246 {
3247 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cannot find any lanelet in map!");
3248 return true;
3249 }
3250
3251 // locate lanelet on shortest path
3252 auto shortest_path = wm_->getRoute()->shortestPath(); // find path amoung route
3253
3254 // read status data
3255 double current_progress = wm_->routeTrackPos(current_loc).downtrack;
3256 double speed_progress = current_speed_;
3257 rclcpp::Time time_progress = timer_factory_->now();
3258
3259 // ---------------- use IHP platoon trajectory regulation here --------------------
3260 // Note: The desired gap will be adjusted and send to control plugin (via platoon_info_msg) where gap creation will be handled.
3261 double target_speed;
3262
3263 // Note: gap regulation has moved to control plug-in, no need to adjust speed here.
3264 target_speed = findSpeedLimit(current_lanelet); //get Speed Limit
3265 double total_maneuver_length = current_progress + config_.time_step * target_speed;
3266 // ----------------------------------------------------------------
3267
3268 // pick smaller length, accomendate when host is close to the route end
3269 double route_length = wm_->getRouteEndTrackPos().downtrack;
3270 total_maneuver_length = std::min(total_maneuver_length, route_length);
3271
3272 // Update current status based on prior plan
3273 if(req.prior_plan.maneuvers.size()!= 0)
3274 {
3275 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Provided with initial plan...");
3276 time_progress = req.prior_plan.planning_completion_time;
3277 int end_lanelet = 0;
3278 updateCurrentStatus(req.prior_plan.maneuvers.back(), speed_progress, current_progress, end_lanelet);
3279 }
3280
3281 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Starting Loop");
3282 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "total_maneuver_length: " << total_maneuver_length << " route_length: " << route_length);
3283
3284
3285 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "in mvr callback safeToLaneChange: " << safeToLaneChange_);
3286
3287 // Note: Use current_lanlet list (which was determined based on vehicle pose) to find current lanelet ID.
3288 lanelet::Id current_lanelet_id = current_lanelet.id();
3289
3290
3291
3292 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_lanelet_id: " << current_lanelet_id);
3293 // lane change maneuver
3295 {
3296 // for testing purpose only, check lane change status
3297 double target_crosstrack = wm_->routeTrackPos(target_cutin_pose_).crosstrack;
3298 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_crosstrack: " << target_crosstrack);
3299 double crosstrackDiff = current_crosstrack_ - target_crosstrack;
3300 bool isLaneChangeFinished = abs(crosstrackDiff) <= config_.maxCrosstrackError;
3301 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "crosstrackDiff: " << crosstrackDiff);
3302 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "isLaneChangeFinished: " << isLaneChangeFinished);
3303
3304 // lane change not finished, use lane change plan
3305 if(!isLaneChangeFinished)
3306 {
3307 // send out lane change plan
3308 while (current_progress < total_maneuver_length)
3309 {
3310 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane Change Maneuver for Cut-in join ! ");
3311 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_progress: "<< current_progress);
3312 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "speed_progress: " << speed_progress);
3313 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_speed: " << target_speed);
3314 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "time_progress: " << rclcpp::Time(time_progress).seconds());
3315
3316 // set to next lane destination, consider sending ecef instead of dtd
3317 double end_dist = total_maneuver_length;
3318 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "end_dist: " << end_dist);
3319 // consider calculate dtd_diff and ctd_diff
3320 double dist_diff = end_dist - current_progress;
3321 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "dist_diff: " << dist_diff);
3322
3323
3324 //TODO: target_cutin_pose_ represents the platoon leader. It seems this may be the wrong answer for mid- or rear-cutins?
3325 //SAINA: currently, the functions do not provide the correct point of rear vehicle of the platoon
3326 double lc_end_dist = wm_->routeTrackPos(target_cutin_pose_).downtrack;
3327 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "lc_end_dist before buffer: " << lc_end_dist);
3328 lc_end_dist = std::max(lc_end_dist, current_progress + config_.maxCutinGap);
3329 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "lc_end_dist after buffer: " << lc_end_dist);
3330
3331 //TODO: target_cutin_pose_ represents the platoon leader. Is this the best pose to use here?
3332 // get the actually closest lanelets,
3333 auto target_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, target_cutin_pose_, 1);
3334 if (target_lanelets.empty())
3335 {
3336 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The target cutin pose is not on a valid lanelet. So no lane change!");
3337 break;
3338 }
3339 lanelet::Id target_lanelet_id = target_lanelets[0].second.id();
3340 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_lanelet_id: " << target_lanelet_id);
3341
3342 lanelet::ConstLanelet starting_lanelet = wm_->getMap()->laneletLayer.get(current_lanelet_id);
3343 lanelet::ConstLanelet ending_lanelet = wm_->getMap()->laneletLayer.get(target_lanelet_id);
3344
3345 bool lanechangePossible = is_lanechange_possible(current_lanelet_id, target_lanelet_id);
3346 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "lanechangePossible: " << lanechangePossible);
3347
3348 if (lanechangePossible)
3349 {
3350 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane change possible, planning it.. " );
3351 resp.new_plan.maneuvers.push_back(composeLaneChangeManeuverMessage(current_downtrack_, lc_end_dist,
3352 speed_progress, target_speed, current_lanelet_id, target_lanelet_id , time_progress));
3353
3354 }
3355 else
3356 {
3357 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane change impossible, planning lanefollow instead ... " );
3358 resp.new_plan.maneuvers.push_back(composeManeuverMessage(current_downtrack_, end_dist,
3359 speed_progress, target_speed, current_lanelet_id, time_progress));
3360 }
3361
3362
3363
3364 current_progress += dist_diff;
3365 // read lane change maneuver end time as time progress
3366 time_progress = resp.new_plan.maneuvers.back().lane_change_maneuver.end_time;
3367 speed_progress = target_speed;
3368 if(current_progress >= total_maneuver_length)
3369 {
3370 break;
3371 }
3372
3373 }
3374 }
3375
3376 // lane change finished, use lane following plan
3377 else
3378 {
3379 // send out lane following plan
3380 while (current_progress < total_maneuver_length)
3381 {
3382 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Same Lane Maneuver for platoon join ! ");
3383 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_progress: "<< current_progress);
3384 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "speed_progress: " << speed_progress);
3385 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_speed: " << target_speed);
3386 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "time_progress: " << rclcpp::Time(time_progress).seconds());
3387 double end_dist = total_maneuver_length;
3388 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "end_dist: " << end_dist);
3389 double dist_diff = end_dist - current_progress;
3390 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "dist_diff: " << dist_diff);
3391 if(end_dist < current_progress)
3392 {
3393 break;
3394 }
3395 // Note: The previous plan was generated at the beginning of the trip. It is necessary to update
3396 // it as the lane ID and lanelet Index are different.
3397 resp.new_plan.maneuvers.push_back(composeManeuverMessage(current_downtrack_, end_dist,
3398 speed_progress, target_speed, current_lanelet_id, time_progress));
3399
3400 current_progress += dist_diff;
3401 time_progress = resp.new_plan.maneuvers.back().lane_following_maneuver.end_time;
3402 speed_progress = target_speed;
3403 if(current_progress >= total_maneuver_length)
3404 {
3405 break;
3406 }
3407 }
3408 }
3409 }
3410
3411 // same-lane maneuver
3412 else
3413 {
3414 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Planning Same Lane Maneuver! ");
3415 while (current_progress < total_maneuver_length)
3416 {
3417 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Same Lane Maneuver for platoon join ! ");
3418 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_progress: "<< current_progress);
3419 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "speed_progress: " << speed_progress);
3420 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "target_speed: " << target_speed);
3421 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "time_progress: " << rclcpp::Time(time_progress).seconds());
3422 double end_dist = total_maneuver_length;
3423 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "end_dist: " << end_dist);
3424 double dist_diff = end_dist - current_progress;
3425 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "dist_diff: " << dist_diff);
3426 if (end_dist < current_progress)
3427 {
3428 break;
3429 }
3430
3431 resp.new_plan.maneuvers.push_back(composeManeuverMessage(current_progress, end_dist,
3432 speed_progress, target_speed,current_lanelet_id, time_progress));
3433
3434
3435 current_progress += dist_diff;
3436 time_progress = resp.new_plan.maneuvers.back().lane_following_maneuver.end_time;
3437 speed_progress = target_speed;
3438 if(current_progress >= total_maneuver_length)
3439 {
3440 break;
3441 }
3442 }
3443 }
3444
3445
3446 if(resp.new_plan.maneuvers.size() == 0)
3447 {
3448 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Cannot plan maneuver because no route is found");
3449 }
3450
3451
3453 {
3454 resp.new_plan.maneuvers = {};
3455 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Platoon size 1 so Empty maneuver sent");
3456 }
3457 else
3458 {
3459 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Planning maneuvers: ");
3460 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "safeToLaneChange_: " << safeToLaneChange_);
3461 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.getHostPlatoonSize(): " << pm_.getHostPlatoonSize());
3462 }
3463
3465 {
3467 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "change the state from standby to leader at start-up");
3468 }
3469
3470 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_downtrack: " << current_downtrack_);
3471
3472 return true;
3473 }
void updateCurrentStatus(carma_planning_msgs::msg::Maneuver maneuver, double &speed, double &current_progress, int &lane_id)
Update maneuver status based on prior plan.
carma_planning_msgs::msg::Maneuver composeManeuverMessage(double current_dist, double end_dist, double current_speed, double target_speed, int lane_id, rclcpp::Time &current_time)
Find lanelet index from path.
double findSpeedLimit(const lanelet::ConstLanelet &llt)
Function to find speed limit of a lanelet.
carma_planning_msgs::msg::Maneuver composeLaneChangeManeuverMessage(double current_dist, double end_dist, double current_speed, double target_speed, int starting_lane_id, int ending_lane_id, rclcpp::Time &current_time)
Find start(current) and target(end) lanelet index from path to generate lane change maneuver message.
bool is_lanechange_possible(lanelet::Id start_lanelet_id, lanelet::Id target_lanelet_id)
Function to check if lanechange is possible.

References composeLaneChangeManeuverMessage(), composeManeuverMessage(), config_, current_crosstrack_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, findSpeedLimit(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), is_lanechange_possible(), platoon_strategic_ihp::LEADER, platoon_strategic_ihp::PlatoonPluginConfig::maxCrosstrackError, platoon_strategic_ihp::PlatoonPluginConfig::maxCutinGap, pm_, pose_msg_, safeToLaneChange_, platoon_strategic_ihp::STANDBY, target_cutin_pose_, platoon_strategic_ihp::PlatoonPluginConfig::time_step, timer_factory_, updateCurrentStatus(), and wm_.

Here is the call graph for this function:

◆ pose_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::pose_cb ( const geometry_msgs::msg::PoseStamped::UniquePtr  msg)

Callback function for current pose.

Parameters
msgPoseStamped msg

Definition at line 115 of file platoon_strategic_ihp.cpp.

116 {
117 pose_msg_ = geometry_msgs::msg::PoseStamped(*msg);
118
120 {
121 lanelet::BasicPoint2d current_loc(pose_msg_.pose.position.x, pose_msg_.pose.position.y);
122 carma_wm::TrackPos tc = wm_->routeTrackPos(current_loc);
123
124 // update host's DtD and CtD
127 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_downtrack_ = " << current_downtrack_ << ", current_crosstrack_ = " << current_crosstrack_);
129
130 // note: the ecef read from "pose_ecef_point" is in cm.
131 carma_v2x_msgs::msg::LocationECEF pose_ecef_point = pose_to_ecef(pose_msg_);
132 setHostECEF(pose_ecef_point);
133 }
134 }
void setHostECEF(carma_v2x_msgs::msg::LocationECEF pose_ecef_point)
UCLA Update the private variable pose_ecef_point_.

References carma_wm::TrackPos::crosstrack, current_crosstrack_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_platoon_state, carma_wm::TrackPos::downtrack, pm_, pose_msg_, pose_to_ecef(), setHostECEF(), platoon_strategic_ihp::STANDBY, platoon_strategic_ihp::PlatoonManager::updateHostPose(), and wm_.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pose_to_ecef()

carma_v2x_msgs::msg::LocationECEF platoon_strategic_ihp::PlatoonStrategicIHPPlugin::pose_to_ecef ( geometry_msgs::msg::PoseStamped  pose_msg)
private

Function to convert pose from map frame to ecef location.

Parameters
pose_msgpose message
Returns
mobility operation msg

Definition at line 64 of file platoon_strategic_ihp.cpp.

65 {
66
67 if (!map_projector_)
68 {
69 throw std::invalid_argument("No map projector available for ecef conversion");
70 }
71
72 carma_v2x_msgs::msg::LocationECEF location;
73
74 // note: ecef point read from map projector is in m.
75 lanelet::BasicPoint3d ecef_point = map_projector_->projectECEF({pose_msg.pose.position.x, pose_msg.pose.position.y, 0.0}, 1);
76 location.ecef_x = ecef_point.x() * 100.0;
77 location.ecef_y = ecef_point.y() * 100.0;
78 location.ecef_z = ecef_point.z() * 100.0;
79
80
81 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "location.ecef_x: " << location.ecef_x);
82 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "location.ecef_y: " << location.ecef_y);
83 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "location.ecef_z: " << location.ecef_z);
84
85 // note: the returned ecef is in cm.
86 return location;
87 }

References map_projector_.

Referenced by mob_op_cb_leader(), mob_op_cb_preparetojoin(), mob_req_cb_leadwithoperation(), mob_resp_cb_preparetojoin(), pose_cb(), run_candidate_follower(), run_leader_aborting(), and run_prepare_to_join().

Here is the caller graph for this function:

◆ run_candidate_follower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_candidate_follower ( )

Run Candidate Follower State.

Definition at line 2725 of file platoon_strategic_ihp.cpp.

2726 {
2727 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2728
2729 // Task 1: state timeout
2730 bool isCurrentStateTimeout = (tsStart - candidatestateStartTime) > waitingStateTimeout * 1000;
2731 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "timeout1: " << tsStart - candidatestateStartTime);
2732 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "waitingStateTimeout: " << waitingStateTimeout * 1000);
2733 if (isCurrentStateTimeout)
2734 {
2735 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current candidate follower state is timeout. Change back to leader state.");
2738 }
2739
2740 // Task 2: plan timeout, check if current plan is still valid (i.e., not timed out).
2742 {
2743 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.current_plan.planStartTime: " << pm_.current_plan.planStartTime);
2744 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "timeout2: " << tsStart - pm_.current_plan.planStartTime);
2745 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "NEGOTIATION_TIMEOUT: " << NEGOTIATION_TIMEOUT);
2746 bool isPlanTimeout = tsStart - pm_.current_plan.planStartTime > NEGOTIATION_TIMEOUT;
2747 if (isPlanTimeout)
2748 {
2751 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current plan did not receive any response. Abort and change to leader state.");
2752 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Changed the state back to Leader");
2753 }
2754 }
2755
2756 // Task 3: update plan calculate gap, update plan: send PLATOON_FOLLOWER_JOIN request with new gap
2757 double desiredJoinGap2 = config_.desiredJoinTimeGap * current_speed_;
2758 double maxJoinGap = std::max(config_.desiredJoinGap, desiredJoinGap2);
2759 double currentGap = 0.0;
2760 if (!pm_.neighbor_platoon_.empty())
2761 {
2762 currentGap = pm_.neighbor_platoon_.back().vehiclePosition - current_downtrack_;
2763 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "curent gap calculated from back of neighbor platoon: " << currentGap);
2764 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "pm_.neighbor_platoon_.back().vehiclePosition " << pm_.neighbor_platoon_.back().vehiclePosition);
2765
2766 }
2767 else
2768 {
2769 currentGap = pm_.getDistanceToPredVehicle();
2770 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "curent gap when there is no neighbor platoon: " << currentGap);
2771 }
2772
2773 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Based on desired join time gap, the desired join distance gap is " << desiredJoinGap2 << " ms");
2774 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Since we have max allowed gap as " << config_.desiredJoinGap << " m then max join gap became " << maxJoinGap << " m");
2775 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current gap from radar is " << currentGap << " m");
2776 if (currentGap <= maxJoinGap && !pm_.current_plan.valid)
2777 {
2778 carma_v2x_msgs::msg::MobilityRequest request;
2779 std::string planId = boost::uuids::to_string(boost::uuids::random_generator()());
2780 long currentTime = timer_factory_->now().nanoseconds() / 1000000;
2781 request.m_header.plan_id = planId;
2782 request.m_header.recipient_id = pm_.current_plan.peerId;
2783 request.m_header.sender_id = config_.vehicleID;
2784 request.m_header.timestamp = currentTime;
2785
2786 request.plan_type.type = carma_v2x_msgs::msg::PlanType::PLATOON_FOLLOWER_JOIN;
2787 request.strategy = PLATOONING_STRATEGY;
2788 request.strategy_params = ""; //params will not be read by receiver since this is 2nd msg in sequence
2789 request.urgency = 50;
2790 request.location = pose_to_ecef(pose_msg_);
2792 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility Candidate-Join request to the leader");
2793 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current plan peer id: " << pm_.current_plan.peerId);
2794
2795 // Update the local record of the new activity plan and now establish that we have a platoon plan as well,
2796 // which allows us to start sending necessary op STATUS messages
2797 pm_.current_plan = ActionPlan(true, currentTime, planId, pm_.current_plan.peerId);
2799
2800 // Initialize counter to delay transmission of first operation STATUS message
2802 }
2803
2804 //Task 4: publish platoon status message (as single joiner)
2806 {
2807 // Don't want to do this until after the above MobReq message is delivered, otherwise recipient will double-count us in their platoon
2809 {
2810 carma_v2x_msgs::msg::MobilityOperation status;
2813 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published platoon STATUS operation message as Candidate Follower");
2814 }
2815 }
2816
2817 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2818 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2819 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2820 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2821 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2822 }
double getDistanceToPredVehicle()
Returns distance to the predessecor vehicle, in m.
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationCandidateFollower()
Function to compose mobility operation in candidate follower state.

References candidate_follower_delay_count_, candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationCandidateFollower(), config_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonPluginConfig::desiredJoinGap, platoon_strategic_ihp::PlatoonPluginConfig::desiredJoinTimeGap, platoon_strategic_ihp::PlatoonManager::getDistanceToPredVehicle(), platoon_strategic_ihp::LEADER, mobility_operation_publisher_, mobility_request_publisher_, NEGOTIATION_TIMEOUT, platoon_strategic_ihp::PlatoonManager::neighbor_platoon_, platoon_strategic_ihp::ActionPlan::peerId, platoon_strategic_ihp::ActionPlan::planStartTime, PLATOONING_STRATEGY, platoon_strategic_ihp::PlatoonManager::platoonLeaderID, pm_, pose_msg_, pose_to_ecef(), statusMessageInterval_, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::ActionPlan::valid, platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and waitingStateTimeout.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_candidate_leader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_candidate_leader ( )

Run Candidate Leader State.

Definition at line 2921 of file platoon_strategic_ihp.cpp.

2922 {
2923 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Run Candidate Leader State ");
2924 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2925 // Task 1: State time out
2926 if (tsStart - candidatestateStartTime > waitingStateTimeout * 1000)
2927 {
2928 //TODO if the current state timeouts, we need to have a kind of ABORT message to inform the applicant
2929 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "CandidateLeader state is timeout, changing back to PlatoonLeaderState.");
2933 }
2934
2935 // Task 2: publish status message
2936 carma_v2x_msgs::msg::MobilityOperation status;
2939 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "publish status message");
2940 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2941 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2942 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2943 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2944 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2945 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationCandidateLeader()
Function to compose mobility operation in CandidateLeader.

References candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationCandidateLeader(), platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::LEADER, mobility_operation_publisher_, pm_, platoon_strategic_ihp::PlatoonManager::resetHostPlatoon(), statusMessageInterval_, timer_factory_, and waitingStateTimeout.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_follower()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_follower ( )

Run Follower State.

Definition at line 2682 of file platoon_strategic_ihp.cpp.

2683 {
2684 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "run follower");
2685 // This is a interrupted-safe loop.
2686 // This loop has four tasks:
2687 // 1. Check the state start time, if it exceeds a limit it will give up current plan and change back to leader state
2688 // 2. Abort current request if we wait for long enough time for response from leader and change back to leader state
2689
2690 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2691 // Job 1
2692 carma_v2x_msgs::msg::MobilityOperation status;
2695 // Job 2
2696 // Get the number of vehicles in this platoon who is in front of us
2697 int vehicleInFront = pm_.getNumberOfVehicleInFront();
2698 if (vehicleInFront == 0)
2699 {
2702 {
2703 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "noLeaderUpdatesCounter = " << noLeaderUpdatesCounter << " and change to leader state");
2707 }
2708 }
2709 else
2710 {
2711 // reset counter to zero when we get updates again
2713 }
2714 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2715 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2716 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2717 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2718 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2719
2720 // Job 3: Dissoleve request.
2721 //TODO: set departure indicator
2722
2723 }
void changeFromFollowerToLeader()
Update status when state change from Follower to Leader.
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationFollower()
Function to compose mobility operation in follower state.

References platoon_strategic_ihp::PlatoonManager::changeFromFollowerToLeader(), composeMobilityOperationFollower(), platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::PlatoonManager::getNumberOfVehicleInFront(), platoon_strategic_ihp::LEADER, LEADER_TIMEOUT_COUNTER_LIMIT, mobility_operation_publisher_, noLeaderUpdatesCounter, pm_, statusMessageInterval_, and timer_factory_.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_lead_with_operation()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_lead_with_operation ( )

UCLA Run lead with operation State.

Definition at line 2948 of file platoon_strategic_ihp.cpp.

2949 {
2950 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2951 // Task 1: heart beat timeout: constantly send INFO mob_op
2952 bool isTimeForHeartBeat = tsStart - prevHeartBeatTime_ >= infoMessageInterval_;
2953 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "time since last heart beat: " << tsStart - prevHeartBeatTime_);
2954 if (isTimeForHeartBeat)
2955 {
2956 carma_v2x_msgs::msg::MobilityOperation infoOperation;
2958 mobility_operation_publisher_(infoOperation);
2959 prevHeartBeatTime_ = timer_factory_->now().nanoseconds() / 1000000;
2960 }
2961
2962
2963 // Task 4: STATUS msgs
2964 bool hasFollower = pm_.getHostPlatoonSize() > 1 || config_.test_cutin_join;
2965 // if has follower, publish platoon message as STATUS mob_op
2966 if (hasFollower)
2967 {
2968 carma_v2x_msgs::msg::MobilityOperation statusOperation;
2970 mobility_operation_publisher_(statusOperation);
2971 }
2972 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2973 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2974 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2975 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2976 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2977 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeadWithOperation(const std::string &type)
Function to compose mobility operation in LeadWithOperation (cut-in join)

References composeMobilityOperationLeadWithOperation(), config_, platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), infoMessageInterval_, mobility_operation_publisher_, OPERATION_INFO_TYPE, OPERATION_STATUS_TYPE, pm_, prevHeartBeatTime_, statusMessageInterval_, platoon_strategic_ihp::PlatoonPluginConfig::test_cutin_join, and timer_factory_.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_leader()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_leader ( )

Run Leader State.

Definition at line 2625 of file platoon_strategic_ihp.cpp.

2626 {
2627 unsigned long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2628
2629 // If vehicle is not rolling then return
2631 {
2632 return;
2633 }
2634
2635 // Task 1: heart beat timeout: send INFO mob_op
2636 bool isTimeForHeartBeat = tsStart - prevHeartBeatTime_ >= infoMessageInterval_;
2637 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "time since last heart beat: " << tsStart - prevHeartBeatTime_);
2638 if (isTimeForHeartBeat)
2639 {
2640 carma_v2x_msgs::msg::MobilityOperation infoOperation;
2642 mobility_operation_publisher_(infoOperation);
2643 prevHeartBeatTime_ = timer_factory_->now().nanoseconds() / 1000000;
2644 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published heart beat platoon INFO mobility operation message");
2645 }
2646
2647 // Task 3: plan time out, check if any current join plan is still valid (i.e., not timed out).
2649 {
2650 bool isCurrentPlanTimeout = tsStart - pm_.current_plan.planStartTime > NEGOTIATION_TIMEOUT;
2651 if (isCurrentPlanTimeout)
2652 {
2653 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Give up current on waiting plan with planId: " << pm_.current_plan.planId);
2655 }
2656 }
2657
2658 // Task 4: STATUS msgs
2659 bool hasFollower = pm_.getHostPlatoonSize() > 1 || config_.test_cutin_join;
2660 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "hasFollower" << hasFollower);
2661 // if has follower, publish platoon message as STATUS mob_op
2662 if (hasFollower)
2663 {
2664 carma_v2x_msgs::msg::MobilityOperation statusOperation;
2666 // mob_op_pub_.publish(statusOperation);
2667 mobility_operation_publisher_(statusOperation);
2668 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published platoon STATUS operation message as a Leader with Follower");
2669 }
2670
2671 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2672 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2673 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2674 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2675 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2676
2677 // Job 5: Dissoleve request.
2678 // TODO: Place holder for departure. Need to change to departing state and tracking departng ID.
2679
2680 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeader(const std::string &type)
Function to compose mobility operation in leader state.

References platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationLeader(), config_, platoon_strategic_ihp::PlatoonManager::current_plan, current_speed_, platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), infoMessageInterval_, mobility_operation_publisher_, NEGOTIATION_TIMEOUT, OPERATION_INFO_TYPE, OPERATION_STATUS_TYPE, platoon_strategic_ihp::ActionPlan::planId, platoon_strategic_ihp::ActionPlan::planStartTime, pm_, prevHeartBeatTime_, statusMessageInterval_, STOPPED_SPEED, platoon_strategic_ihp::PlatoonPluginConfig::test_cutin_join, timer_factory_, and platoon_strategic_ihp::ActionPlan::valid.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_leader_aborting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_leader_aborting ( )

Run Leader Aborting State.

Definition at line 2825 of file platoon_strategic_ihp.cpp.

2826 {
2827 /*
2828 UCLA implementation note:
2829 1. this function send step plan type: "PLATOON_FRONT_JOIN"
2830 2. the sender of the plan (host vehicle) is the previous leader, it wil prepare to follow front joiner (new leader)
2831 */
2832 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2833 // Task 1: state timeout
2834 bool isCurrentStateTimeout = (tsStart - candidatestateStartTime) > waitingStateTimeout * 1000;
2835 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "timeout1: " << tsStart - candidatestateStartTime);
2836 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "waitingStateTimeout: " << waitingStateTimeout * 1000);
2837 if (isCurrentStateTimeout)
2838 {
2839 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current leader aborting state is timeout. Change back to leader state.");
2841
2842 //clear plan validity & end; leave platoon info alone, as we may still be leading a valid platoon
2844 return;
2845 }
2846
2847 // Task 3: update plan: PLATOON_FRONT_JOIN with new gap
2848 double desiredJoinGap2 = config_.desiredJoinTimeGap * current_speed_;
2849 double maxJoinGap = std::max(config_.desiredJoinGap, desiredJoinGap2);
2850
2851 // check if compatible for front join --> return front gap, no veh type check, is compatible
2852 // Note that pm_ only represents host's platoon members. As the aborting leader, the only vehicle
2853 // preceding host is the candidate joiner. For this code to work, it depends on the candidate to publish
2854 // mobility operation STATUS messages so that host can include it in the pm_ platoon membership.
2855 double currentGap = pm_.getDistanceToPredVehicle(); //returns 0 if we haven't received op STATUS from joiner yet
2856 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Based on desired join time gap, the desired join distance gap is " << desiredJoinGap2 << " m");
2857 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Since we have max allowed gap as " << config_.desiredJoinGap << " m then max join gap became " << maxJoinGap << " m");
2858 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current gap to joiner is " << currentGap << " m");
2859
2860 // NOTE: The front join depends upon the joiner to publish op STATUS messages with this platoon's ID, then host receives at least one
2861 // and thereby adds the joiner to the platoon record. This process requires host's mob_req_cb_leader() to ACK the join request, then
2862 // the remote vehicle to handle that ACK and broadcast its first op STATUS, then host to receive and process it. All that has to happen
2863 // before the below code block runs, even though this method starts to spin immediately after we send out the mentioned ACK. To avoid
2864 // a race condition, we must wait a few cycles to ensure the 2-way messaging has completed. The race is that above calculation for
2865 // current gap will be returned as 0 until we have received said STATUS message from the joiner, which would prematurely trigger the
2866 // process to move forward.
2867
2868 // Check if gap is big enough and if there is no currently active plan and this method has been called several times
2869 // Add a condition to prevent sending repeated requests (Note: This is a same-lane maneuver, so no need to consider lower bound of joining gap.)
2871 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "numLeaderAbortingCalls = " << numLeaderAbortingCalls_ << ", max = " << config_.maxLeaderAbortingCalls);
2872 if (currentGap <= maxJoinGap && !pm_.current_plan.valid && numLeaderAbortingCalls_ > config_.maxLeaderAbortingCalls)
2873 {
2874 // compose frontal joining plan, senderID is the old leader
2875 carma_v2x_msgs::msg::MobilityRequest request;
2876 std::string planId = boost::uuids::to_string(boost::uuids::random_generator()());
2877 long currentTime = timer_factory_->now().nanoseconds() / 1000000;
2878 request.m_header.plan_id = planId;
2879 request.m_header.recipient_id = pm_.platoonLeaderID; //the new joiner
2880 request.m_header.sender_id = config_.vehicleID;
2881 request.m_header.timestamp = currentTime;
2882
2883 int platoon_size = pm_.getHostPlatoonSize(); //depends on joiner to send op STATUS messages while joining
2884
2885 boost::format fmter(JOIN_PARAMS); // Note: Front and rear join uses same params, hence merge to one param for both condition.
2886 int dummy_join_index = -2; //leader aborting doesn't need join_index so use default value
2887 fmter %platoon_size; // index = 0
2888 fmter %current_speed_; // index = 1, in m/s
2889 fmter %pose_ecef_point_.ecef_x; // index = 2
2890 fmter %pose_ecef_point_.ecef_y; // index = 3
2891 fmter %pose_ecef_point_.ecef_z; // index = 4
2892 fmter %dummy_join_index; // index = 5
2893 request.strategy_params = fmter.str();
2894
2895 // assign a new plan type
2896 request.plan_type.type = carma_v2x_msgs::msg::PlanType::PLATOON_FRONT_JOIN;
2897 request.strategy = PLATOONING_STRATEGY;
2898 request.urgency = 50;
2899 request.location = pose_to_ecef(pose_msg_);
2901 RCLCPP_WARN(rclcpp::get_logger("platoon_strategic_ihp"),"Published Mobility Candidate-Join request to the new leader");
2902
2903 // Create a new join action plan
2904 pm_.current_plan = ActionPlan(true, currentTime, planId, pm_.platoonLeaderID);
2905 }
2906
2907 //Task 4: publish platoon status message
2908 carma_v2x_msgs::msg::MobilityOperation status;
2911 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published platoon STATUS operation message");
2912
2913 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2914 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2915 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2916 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2917 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2918 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeaderAborting()
Function to compose mobility operation in LeaderAborting state.

References candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationLeaderAborting(), config_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonPluginConfig::desiredJoinGap, platoon_strategic_ihp::PlatoonPluginConfig::desiredJoinTimeGap, platoon_strategic_ihp::PlatoonManager::getDistanceToPredVehicle(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), JOIN_PARAMS, platoon_strategic_ihp::LEADER, platoon_strategic_ihp::PlatoonPluginConfig::maxLeaderAbortingCalls, mobility_operation_publisher_, mobility_request_publisher_, numLeaderAbortingCalls_, PLATOONING_STRATEGY, platoon_strategic_ihp::PlatoonManager::platoonLeaderID, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), statusMessageInterval_, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and waitingStateTimeout.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_leader_waiting()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_leader_waiting ( )

Run Leader Waiting State.

Definition at line 2600 of file platoon_strategic_ihp.cpp.

2601 {
2602 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Run LeaderWaiting State ");
2603 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2604 // Task 1
2605 if (tsStart - waitingStartTime > waitingStateTimeout * 1000)
2606 {
2607 //TODO if the current state timeouts, we need to have a kind of ABORT message to inform the applicant
2608 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "LeaderWaitingState is timeout, changing back to PlatoonLeaderState.");
2611 }
2612 // Task 2
2613 carma_v2x_msgs::msg::MobilityOperation status;
2616 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "publish status message");
2617 long tsEnd = timer_factory_->now().nanoseconds() / 1000000;
2618 long sleepDuration = std::max((int32_t)(statusMessageInterval_ - (tsEnd - tsStart)), 0);
2619
2620 // TODO this solution is not sim-time complient and should be replaced with one which is when possible
2621 // https://github.com/usdot-fhwa-stol/carma-platform/issues/1888
2622 std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
2623 }
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationLeaderWaiting()
Function to compose mobility operation in leader waiting state.

References platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationLeaderWaiting(), platoon_strategic_ihp::PlatoonManager::current_platoon_state, platoon_strategic_ihp::LEADER, mobility_operation_publisher_, pm_, statusMessageInterval_, timer_factory_, waitingStartTime, and waitingStateTimeout.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_prepare_to_join()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::run_prepare_to_join ( )

UCLA Run prepare to join State.

Definition at line 2980 of file platoon_strategic_ihp.cpp.

2981 {
2982 /*
2983 * The prepare join state should have the following tasks:
2984 * 1. Compose mobility operation param: status.
2985 * 2. Time out check.
2986 * 3. Calculate proper cut_in index
2987 * 4. Send out lane change intend to leader.
2988 * Note: 1. safeToLaneChange_ monitors the gap condition.
2989 * 2. Once it is safe to lane change, the updated plan will send-out in "plan_maneuver_cb"
2990 */
2991
2992 // Task 2.1: state timeout
2993 long tsStart = timer_factory_->now().nanoseconds() / 1000000;
2994 bool isCurrentStateTimeout = (tsStart - candidatestateStartTime) > waitingStateTimeout * 1000;
2995 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "timeout1: " << tsStart - candidatestateStartTime);
2996 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "waitingStateTimeout: " << waitingStateTimeout * 1000);
2997 if (isCurrentStateTimeout)
2998 {
2999 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "The current prepare to join state is timeout. Change back to leader state and abort lane change.");
3001 safeToLaneChange_ = false;
3004 // Leave neighbor platoon info in place, as we may retry the join later
3005 }
3006
3007 // TODO: Plan timeout is not needed for this state
3008
3009 // If we aren't already waiting on a response to one of these plans, create one once neighbor info is available
3010 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "current_plan.valid = " << pm_.current_plan.valid << ", is_neighbor_record_complete = " << pm_.is_neighbor_record_complete_);
3011
3013 {
3014 // Task 1: compose mobility operation (status)
3015 carma_v2x_msgs::msg::MobilityOperation status;
3016 status = composeMobilityOperationPrepareToJoin(); //TODO: I bet we could consolidate a lot of these compose methods
3018 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published platoon STATUS operation message");
3019
3020 // Task 3: Calculate proper cut_in index
3021 // Note: The cut-in index is zero-based and points to the gap-leading vehicle's index. For cut-in from front, the join index = -1.
3022 double joinerDtD = current_downtrack_;
3024 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "calculated join index: " << target_join_index_);
3025
3026 // Task 4: Send out request to leader about cut-in position
3027 carma_v2x_msgs::msg::MobilityRequest request;
3028 std::string planId = boost::uuids::to_string(boost::uuids::random_generator()());
3029 long currentTime = timer_factory_->now().nanoseconds() / 1000000;
3030 request.m_header.plan_id = planId;
3031 request.m_header.recipient_id = pm_.neighbor_platoon_leader_id_;
3032 request.m_header.sender_id = config_.vehicleID;
3033 request.m_header.timestamp = currentTime;
3034 request.plan_type.type = carma_v2x_msgs::msg::PlanType::PLATOON_CUT_IN_JOIN;
3035 request.strategy = PLATOONING_STRATEGY;
3036 request.urgency = 50;
3037 request.location = pose_to_ecef(pose_msg_);
3038 double platoon_size = pm_.getHostPlatoonSize();
3039
3040 boost::format fmter(JOIN_PARAMS);
3041 fmter %platoon_size; // index = 0
3042 fmter %current_speed_; // index = 1, in m/s
3043 fmter %pose_ecef_point_.ecef_x; // index = 2
3044 fmter %pose_ecef_point_.ecef_y; // index = 3
3045 fmter %pose_ecef_point_.ecef_z; // index = 4
3046 fmter %target_join_index_; // index = 5
3047 request.strategy_params = fmter.str();
3049 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Published Mobility cut-in join request to leader " << request.m_header.recipient_id << " with planId = " << planId);
3050
3051 // Create a new join action plan
3052 pm_.current_plan = ActionPlan(true, currentTime, planId, pm_.neighbor_platoon_leader_id_);
3053 }
3054 }
int getClosestIndex(double joinerDtD)
UCLA: Return joiner's desired position in terms of target platoon index to cut into the platoon....
carma_v2x_msgs::msg::MobilityOperation composeMobilityOperationPrepareToJoin()
Function to compose mobility operation in PrepareToJoin (cut-in join)

References candidatestateStartTime, platoon_strategic_ihp::PlatoonManager::clearActionPlan(), composeMobilityOperationPrepareToJoin(), config_, current_downtrack_, platoon_strategic_ihp::PlatoonManager::current_plan, platoon_strategic_ihp::PlatoonManager::current_platoon_state, current_speed_, platoon_strategic_ihp::PlatoonManager::getClosestIndex(), platoon_strategic_ihp::PlatoonManager::getHostPlatoonSize(), platoon_strategic_ihp::PlatoonManager::is_neighbor_record_complete_, JOIN_PARAMS, platoon_strategic_ihp::LEADER, mobility_operation_publisher_, mobility_request_publisher_, platoon_strategic_ihp::PlatoonManager::neighbor_platoon_leader_id_, PLATOONING_STRATEGY, pm_, pose_ecef_point_, pose_msg_, pose_to_ecef(), platoon_strategic_ihp::PlatoonManager::resetHostPlatoon(), safeToLaneChange_, target_join_index_, timer_factory_, carma_cooperative_perception::to_string(), platoon_strategic_ihp::ActionPlan::valid, platoon_strategic_ihp::PlatoonPluginConfig::vehicleID, and waitingStateTimeout.

Referenced by onSpin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setConfig()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::setConfig ( const PlatoonPluginConfig config)

Set the current config.

Definition at line 3520 of file platoon_strategic_ihp.cpp.

3521 {
3522 config_ = config;
3523 }

References config_.

◆ setHostECEF()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::setHostECEF ( carma_v2x_msgs::msg::LocationECEF  pose_ecef_point)

UCLA Update the private variable pose_ecef_point_.

Definition at line 90 of file platoon_strategic_ihp.cpp.

91 {
92 // Note, the ecef here is in cm.
93 pose_ecef_point_ = pose_ecef_point;
94 }

References pose_ecef_point_.

Referenced by pose_cb().

Here is the caller graph for this function:

◆ setPMState()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::setPMState ( PlatoonState  desiredState)

UCLA Setter: function to set pm_.platoon_state.

Definition at line 103 of file platoon_strategic_ihp.cpp.

104 {
105 pm_.current_platoon_state = desiredState;
106 }

References platoon_strategic_ihp::PlatoonManager::current_platoon_state, and pm_.

◆ twist_cb()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::twist_cb ( const geometry_msgs::msg::TwistStamped::UniquePtr  msg)

Callback for the twist subscriber, which will store latest twist locally.

Parameters
msgLatest twist message

Definition at line 143 of file platoon_strategic_ihp.cpp.

144 {
145 current_speed_ = msg->twist.linear.x;
147 {
148 current_speed_ = 0.0;
149 }
150 }

References current_speed_, and STOPPED_SPEED.

Referenced by platoon_strategic_ihp::Node::on_configure_plugin().

Here is the caller graph for this function:

◆ updateCurrentStatus()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::updateCurrentStatus ( carma_planning_msgs::msg::Maneuver  maneuver,
double &  speed,
double &  current_progress,
int &  lane_id 
)

Update maneuver status based on prior plan.

Parameters
maneuvermaneuver
speedspeed
current_progresscurrent progress
lane_idlanelet ud

Definition at line 3206 of file platoon_strategic_ihp.cpp.

3207 {
3208 if(maneuver.type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
3209 speed = maneuver.lane_following_maneuver.end_speed;
3210 current_progress = maneuver.lane_following_maneuver.end_dist;
3211 if (maneuver.lane_following_maneuver.lane_ids.empty())
3212 {
3213 RCLCPP_WARN_STREAM(rclcpp::get_logger("platoon_strategic_ihp"), "Lane id of lane following maneuver not set. Using 0");
3214 lane_id = 0;
3215 }
3216 else
3217 {
3218 lane_id = stoi(maneuver.lane_following_maneuver.lane_ids[0]);
3219 }
3220 }
3221 }

Referenced by plan_maneuver_cb().

Here is the caller graph for this function:

◆ updatePlatoonList()

void platoon_strategic_ihp::PlatoonStrategicIHPPlugin::updatePlatoonList ( std::vector< PlatoonMember platoon_list)

UCLA Setter: Update platoon list (Unit Test).

Definition at line 109 of file platoon_strategic_ihp.cpp.

110 {
111 pm_.host_platoon_ = platoon_list;
112 }

References platoon_strategic_ihp::PlatoonManager::host_platoon_, and pm_.

Member Data Documentation

◆ candidate_follower_delay_count_

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::candidate_follower_delay_count_ = 0
private

Definition at line 786 of file platoon_strategic_ihp.h.

Referenced by run_candidate_follower().

◆ candidatestateStartTime

long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::candidatestateStartTime = 0
private

◆ cmd_speed_

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::cmd_speed_ = 0
private

◆ config_

◆ current_crosstrack_

◆ current_downtrack_

◆ current_speed_

◆ desiredJoinGap

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::desiredJoinGap = 30.0
private

Definition at line 800 of file platoon_strategic_ihp.h.

◆ desiredJoinTimeGap

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::desiredJoinTimeGap = 4.0
private

Definition at line 801 of file platoon_strategic_ihp.h.

◆ georeference_

std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::georeference_ {""}
private

Definition at line 773 of file platoon_strategic_ihp.h.

Referenced by georeference_cb().

◆ HostMobilityId

std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::HostMobilityId = "hostid"
private

Definition at line 339 of file platoon_strategic_ihp.h.

◆ infoMessageInterval_

unsigned long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::infoMessageInterval_ = 200
private

Definition at line 792 of file platoon_strategic_ihp.h.

Referenced by run_lead_with_operation(), and run_leader().

◆ JOIN_PARAMS

const std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::JOIN_PARAMS = "SIZE:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%,JOINIDX:%6%"
private

index = 0, SIZE, number of members. index = 1, SPEED, in m/s. index = 2, ECEFX, in cm. index = 3, ECEFY, in cm. index = 4, ECEFZ, in cm. index = 5, JOINIDX, index of the position in platoon the incoming vehicle tries to join note: The cut-in index is zero-based and points to the gap-leading vehicle's index. eg: for rear join, cut-in index == platoon.size()-1; for join from front, index == -1; for cut-in in middle, index indicate the gap leading vehicle's index.

Definition at line 859 of file platoon_strategic_ihp.h.

Referenced by mob_op_cb_leader(), mob_op_cb_preparetojoin(), mob_req_cb_leadwithoperation(), mob_resp_cb_preparetojoin(), run_leader_aborting(), and run_prepare_to_join().

◆ LANE_CHANGE_TIMEOUT

unsigned long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::LANE_CHANGE_TIMEOUT = 300000
private

Definition at line 796 of file platoon_strategic_ihp.h.

◆ LEADER_TIMEOUT_COUNTER_LIMIT

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::LEADER_TIMEOUT_COUNTER_LIMIT = 5
private

Definition at line 798 of file platoon_strategic_ihp.h.

Referenced by run_follower().

◆ map_loaded_

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::map_loaded_ = false
private

Definition at line 777 of file platoon_strategic_ihp.h.

◆ map_projector_

std::shared_ptr<lanelet::projection::LocalFrameProjector> platoon_strategic_ihp::PlatoonStrategicIHPPlugin::map_projector_
private

Definition at line 774 of file platoon_strategic_ihp.h.

Referenced by ecef_to_map_point(), georeference_cb(), and pose_to_ecef().

◆ maxAllowedJoinGap_

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::maxAllowedJoinGap_ = 90
private

Definition at line 789 of file platoon_strategic_ihp.h.

◆ maxAllowedJoinTimeGap_

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::maxAllowedJoinTimeGap_ = 15.0
private

Definition at line 788 of file platoon_strategic_ihp.h.

◆ maxPlatoonSize_

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::maxPlatoonSize_ = 10
private

Definition at line 790 of file platoon_strategic_ihp.h.

◆ mobility_operation_publisher_

MobilityOperationCB platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mobility_operation_publisher_
private

◆ mobility_request_publisher_

MobilityRequestCB platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mobility_request_publisher_
private

◆ mobility_response_publisher_

MobilityResponseCB platoon_strategic_ihp::PlatoonStrategicIHPPlugin::mobility_response_publisher_
private

Definition at line 309 of file platoon_strategic_ihp.h.

Referenced by mob_req_cb().

◆ NEGOTIATION_TIMEOUT

unsigned long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::NEGOTIATION_TIMEOUT = 15000
private

Definition at line 795 of file platoon_strategic_ihp.h.

Referenced by run_candidate_follower(), and run_leader().

◆ noLeaderUpdatesCounter

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::noLeaderUpdatesCounter = 0
private

Definition at line 797 of file platoon_strategic_ihp.h.

Referenced by run_follower().

◆ numLeaderAbortingCalls_

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::numLeaderAbortingCalls_ = 0
private

Definition at line 783 of file platoon_strategic_ihp.h.

Referenced by mob_resp_cb_leaderaborting(), and run_leader_aborting().

◆ OPERATION_INFO_PARAMS

const std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::OPERATION_INFO_PARAMS = "INFO|LENGTH:%.2f,SPEED:%.2f,SIZE:%d,ECEFX:%.2f,ECEFY:%.2f,ECEFZ:%.2f"
private

index = 0, LENGTH, physical length of the platoon, in m. index = 1, SPEED, in m/s. index = 2, SIZE, number of members. index = 3, ECEFX, in cm. index = 4, ECEFY, in cm. index = 5, ECEFZ, in cm.

Definition at line 834 of file platoon_strategic_ihp.h.

Referenced by composeMobilityOperationINFO().

◆ OPERATION_INFO_TYPE

const std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::OPERATION_INFO_TYPE = "INFO"
private

◆ OPERATION_STATUS_PARAMS

const std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::OPERATION_STATUS_PARAMS = "STATUS|CMDSPEED:%1%,SPEED:%2%,ECEFX:%3%,ECEFY:%4%,ECEFZ:%5%"
private

index = 0, CMDSPEED, in m/s. index = 1, SPEED, in m/s. index = 2, ECEFX, in cm. index = 3, ECEFY, in cm. index = 4, ECEFZ, in cm.

Definition at line 843 of file platoon_strategic_ihp.h.

Referenced by composeMobilityOperationSTATUS().

◆ OPERATION_STATUS_TYPE

const std::string platoon_strategic_ihp::PlatoonStrategicIHPPlugin::OPERATION_STATUS_TYPE = "STATUS"
private

◆ platooning_info_publisher_

PlatooningInfoCB platoon_strategic_ihp::PlatoonStrategicIHPPlugin::platooning_info_publisher_
private

Definition at line 311 of file platoon_strategic_ihp.h.

Referenced by onSpin().

◆ PLATOONING_STRATEGY

◆ plugin_discovery_msg_

carma_planning_msgs::msg::Plugin platoon_strategic_ihp::PlatoonStrategicIHPPlugin::plugin_discovery_msg_
private

Definition at line 780 of file platoon_strategic_ihp.h.

Referenced by PlatoonStrategicIHPPlugin().

◆ pm_

◆ pose_ecef_point_

carma_v2x_msgs::msg::LocationECEF platoon_strategic_ihp::PlatoonStrategicIHPPlugin::pose_ecef_point_

◆ pose_msg_

◆ prevHeartBeatTime_

unsigned long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::prevHeartBeatTime_ = 0.0
private

Definition at line 793 of file platoon_strategic_ihp.h.

Referenced by run_lead_with_operation(), and run_leader().

◆ safeToLaneChange_

bool platoon_strategic_ihp::PlatoonStrategicIHPPlugin::safeToLaneChange_ = false
private

◆ statusMessageInterval_

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::statusMessageInterval_ = 100
private

◆ STOPPED_SPEED

const double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::STOPPED_SPEED = 0.5
private

Definition at line 806 of file platoon_strategic_ihp.h.

Referenced by mob_op_cb(), run_leader(), and twist_cb().

◆ target_cutin_pose_

lanelet::BasicPoint2d platoon_strategic_ihp::PlatoonStrategicIHPPlugin::target_cutin_pose_
private

Definition at line 803 of file platoon_strategic_ihp.h.

Referenced by mob_op_cb_leader(), and plan_maneuver_cb().

◆ target_join_index_

int platoon_strategic_ihp::PlatoonStrategicIHPPlugin::target_join_index_ = -2
private

◆ timer_factory_

◆ vehicleLength_

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::vehicleLength_ = 5.0
private

Definition at line 791 of file platoon_strategic_ihp.h.

◆ waitingStartTime

long platoon_strategic_ihp::PlatoonStrategicIHPPlugin::waitingStartTime = 0
private

◆ waitingStateTimeout

double platoon_strategic_ihp::PlatoonStrategicIHPPlugin::waitingStateTimeout = 25.0
private

◆ wm_


The documentation for this class was generated from the following files: