diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5cb8c09aa7..7db5e42012 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -28,12 +28,12 @@ jobs:
# Pull docker image from docker hub
# XTERM used for better catkin_make output
docker:
- - image: usdotfhwastol/autoware.ai:carma-system-3.10.0
+ - image: usdotfhwastol/autoware.ai:carma-system-3.11.0
user: carma
environment:
TERM: xterm
INIT_ENV: /home/carma/.base-image/init-env.sh
- resource_class: large
+ resource_class: large
# Set working directory
working_directory: "/opt/carma/"
# Pull code and execute tests
diff --git a/.sonarqube/sonar-scanner.properties b/.sonarqube/sonar-scanner.properties
index f7c394d50d..f34f83d8ba 100644
--- a/.sonarqube/sonar-scanner.properties
+++ b/.sonarqube/sonar-scanner.properties
@@ -66,7 +66,8 @@ sonar.modules= bsm_generator, \
mobilitypath_visualizer, \
wz_strategic_plugin, \
sci_strategic_plugin, \
- stop_controlled_intersection_tactical_plugin
+ stop_controlled_intersection_tactical_plugin, \
+ light_controlled_intersection_tactical_plugin
guidance.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/guidance
bsm_generator.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/bsm_generator
@@ -106,6 +107,7 @@ mobilitypath_visualizer.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/mobi
wz_strategic_plugin.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/wz_strategic_plugin
sci_strategic_plugin.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/sci_strategic_plugin
stop_controlled_intersection_tactical_plugin.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/stop_controlled_intersection_tactical_plugin
+light_controlled_intersection_tactical_plugin.sonar.projectBaseDir = /opt/carma/src/CARMAPlatform/light_controlled_intersection_tactical_plugin
# C++ Package differences
# Sources
@@ -147,6 +149,7 @@ mobilitypath_visualizer.sonar.sources = src
wz_strategic_plugin.sonar.sources = src
sci_strategic_plugin.sonar.sources = src
stop_controlled_intersection_tactical_plugin.sonar.sources = src
+light_controlled_intersection_tactical_plugin.sonar.sources = src
# Tests
# Note: For C++ setting this field does not cause test analysis to occur. It only allows the test source code to be evaluated.
@@ -184,3 +187,4 @@ mobilitypath_visualizer.sonar.tests = test
wz_strategic_plugin.sonar.tests = test
sci_strategic_plugin.sonar.tests = test
stop_controlled_intersection_tactical_plugin.sonar.tests = test
+light_controlled_intersection_tactical_plugin.sonar.tests = test
diff --git a/Dockerfile b/Dockerfile
index 9a3c97f2ad..8c26ba8204 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -33,7 +33,7 @@
# Stage 1 - Acquire the CARMA source as well as any extra packages
# /////////////////////////////////////////////////////////////////////////////
-FROM usdotfhwastol/autoware.ai:carma-system-3.10.0 AS base-image
+FROM usdotfhwastol/autoware.ai:carma-system-3.11.0 AS base-image
FROM base-image AS source-code
diff --git a/README.md b/README.md
index 20aea2bdae..09300707cb 100644
--- a/README.md
+++ b/README.md
@@ -71,10 +71,12 @@ For administrative information on CARMA2, including vehicle and developer PC con
## Other CARMA Packages
CARMA PlatformSM is a downloadable, open source software (OSS) platform architected to be extensible and reusable for a wide variety of research purposes to advance innovation for cooperative driving automation. It enables communication between vehicles, road users such as pedestrians, bicyclists, and scooters, and infrastructure devices capable of communication. It promotes collaboration between a community of engineers and researchers to accelerate the development, testing, and evaluation of cooperative driving automation while advancing the safety, security, data, and use of artificial intelligence in automated driving technology.
-The CARMA Platform is distributed as a set of multiple independent packages hosted in separate Github repositories. These packages facilitate operation of the CARMA Platform with different hardware configurations or allow it to support different modes of operation. To include one of these packages in your build of the CARMA Platform system please clone the Github repository into the same Catkin workspace `src/` folder as this repository. The Catkin build system will verify that dependencies are resolved appropriately and build the newly included package when you next run `catkin_make`. An incomplete listing of available packages for CARMA2 includes:
+The CARMA Platform is distributed as a set of multiple independent packages hosted in separate Github repositories. These packages facilitate operation of the CARMA Platform with different hardware configurations or allow it to support different modes of operation. To include one of these packages in your build of the CARMA Platform system please clone the Github repository into the same Catkin workspace `src/` folder as this repository. The Catkin build system will verify that dependencies are resolved appropriately and build the newly included package when you next run `catkin_make`. An incomplete listing of available packages for CARMA3 includes:
### Vehicle Controller Interface Drivers
* [carma-ssc-interface-wrapper](https://github.com/usdot-fhwa-stol/carma-ssc-interface-wrapper)
+* [dataspeed_controller_driver](https://github.com/VT-ASIM-LAB/dataspeed_controller_driver) (Externally managed)
+* [dataspeed_can_driver](https://github.com/VT-ASIM-LAB/dataspeed_can_driver) (Externally managed)
### Sensor Drivers
* [carma-cohda-dsrc-driver](https://github.com/usdot-fhwa-stol/carma-cohda-dsrc-driver)
@@ -82,6 +84,9 @@ The CARMA Platform is distributed as a set of multiple independent packages host
* [avt_vimba_camera](https://github.com/usdot-fhwa-stol/avt_vimba_camera)
* [carma-delphi-srr2-driver](https://github.com/usdot-fhwa-stol/carma-delphi-srr2-driver)
* [novatel_gps_driver](https://github.com/usdot-fhwa-stol/novatel_gps_driver)
+* [gstreamer_camera_driver](https://github.com/VT-ASIM-LAB/gstreamer_camera_driver) (Externally managed)
+* [ouster_lidar_driver](https://github.com/VT-ASIM-LAB/ouster_lidar_driver) (Externally managed)
+* [inertiallabs_gnss_driver](https://github.com/VT-ASIM-LAB/inertiallabs_gnss_driver) (Externally managed)
### General System Utilites
* [carma-web-ui](https://github.com/usdot-fhwa-stol/carma-web-ui)
diff --git a/arbitrator/config/arbitrator_params.yaml b/arbitrator/config/arbitrator_params.yaml
index 03b7b5ba8c..fe2910e791 100644
--- a/arbitrator/config/arbitrator_params.yaml
+++ b/arbitrator/config/arbitrator_params.yaml
@@ -26,4 +26,4 @@ use_fixed_costs: true
# Map: The priorities associated with each plugin during the planning
# process, values will be normalized at runtime and inverted into costs
# Unit: N/a
-plugin_priorities: {RouteFollowingPlugin: 4.0, WorkZonePlugin: 8.0, PlatooningStrategicPlugin: 1.0}
+plugin_priorities: {SCIStrategicPlugin: 4.0, RouteFollowingPlugin: 2.0, WorkZonePlugin: 4.0, PlatooningStrategicPlugin: 1.0}
diff --git a/arbitrator/include/capabilities_interface.tpp b/arbitrator/include/capabilities_interface.tpp
index 3f8424931b..7046e24ae0 100644
--- a/arbitrator/include/capabilities_interface.tpp
+++ b/arbitrator/include/capabilities_interface.tpp
@@ -33,6 +33,7 @@ namespace arbitrator
for (auto i = topics.begin(); i != topics.end(); i++)
{
ros::ServiceClient sc = nh_->serviceClient(*i);
+ ROS_DEBUG_STREAM("found client: " << *i);
if (sc.call(msg)) {
responses.emplace(*i, msg);
}
diff --git a/arbitrator/src/capabilities_interface.cpp b/arbitrator/src/capabilities_interface.cpp
index 0128451c62..70d0bedb61 100644
--- a/arbitrator/src/capabilities_interface.cpp
+++ b/arbitrator/src/capabilities_interface.cpp
@@ -43,6 +43,11 @@ namespace arbitrator
stream << std::endl;
ROS_INFO(stream.str().c_str());
}
+ else
+ {
+ ROS_DEBUG_STREAM("servicd call failed...");
+ ROS_DEBUG_STREAM("client: " << sc_s);
+ }
return topics;
diff --git a/basic_autonomy/include/basic_autonomy/basic_autonomy.h b/basic_autonomy/include/basic_autonomy/basic_autonomy.h
index 423e786f71..3c9e668408 100644
--- a/basic_autonomy/include/basic_autonomy/basic_autonomy.h
+++ b/basic_autonomy/include/basic_autonomy/basic_autonomy.h
@@ -244,8 +244,8 @@ namespace basic_autonomy
const cav_msgs::VehicleState &ending_state_before_buffer, carma_debug_msgs::TrajectoryCurvatureSpeeds debug_msg,
const DetailedTrajConfig &detailed_config);
- //Functions specific to lane change
- /**
+ //Functions specific to lane change
+ /**
* \brief Converts a set of requested LANE_CHANGE maneuvers to point speed limit pairs.
*
* \param maneuvers The list of maneuvers to convert
@@ -260,9 +260,36 @@ namespace basic_autonomy
*
* \return A vector of point speed pair struct which contains geometry points as basicpoint::lanelet2d and speed as a double for the maneuver
*/
- std::vector create_lanechange_geometry(const cav_msgs::Maneuver &maneuver, double max_starting_downtrack,
+ std::vector get_lanechange_points_from_maneuver(const cav_msgs::Maneuver &maneuver, double max_starting_downtrack,
const carma_wm::WorldModelConstPtr &wm, cav_msgs::VehicleState &ending_state_before_buffer,
- const cav_msgs::VehicleState &state, const DetailedTrajConfig &detailed_config);
+ const cav_msgs::VehicleState &state, const GeneralTrajConfig &general_config,const DetailedTrajConfig &detailed_config);
+
+ /**
+ * \brief Creates a vector of lane change points using parameters defined.
+ *
+ * \param starting_lane_id lanelet id for where lane change plan should start
+ * \param ending_lane_id lanelet id for where lane change plan should end
+ * \param starting_downtrack The downtrack distance from which the lane change maneuver starts
+ * \param ending_downtrack The downtrack distance at which the lane change maneuver end
+ * \param wm Pointer to intialized world model for semantic map access
+ * \param state The vehicle state at the time the function is called
+ *
+ * \return A vector of geometry points as lanelet::basicpoint2d
+ */
+ std::vector create_lanechange_geometry(lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double starting_downtrack, double ending_downtrack,
+ const carma_wm::WorldModelConstPtr &wm,const cav_msgs::VehicleState &state, int downsample_ratio);
+
+
+ /**
+ * \brief Resamples a pair of basicpoint2d lines to get lines of same number of points.
+ *
+ * \param line_1 a vector of points to be resampled
+ * \param line_2 a vector of points to be resampled
+ *
+ * \return A 2d vector with input lines resampled at same rate. The first iteration is the resampled line_1 and the resampled line_2 is the second iteration
+ * Assumption here is for lane change to happen between two adjacent lanelets, they must share a lane boundary (linestring)
+ */
+ std::vector> resample_linestring_pair_to_same_size(std::vector& line_1, std::vector& line_2);
/**
* \brief Method converts a list of lanelet centerline points and current vehicle state into a usable list of trajectory points for trajectory planning for a Lane following maneuver.
diff --git a/basic_autonomy/include/basic_autonomy/helper_functions.h b/basic_autonomy/include/basic_autonomy/helper_functions.h
index d6678eca39..9dc38f5eaf 100644
--- a/basic_autonomy/include/basic_autonomy/helper_functions.h
+++ b/basic_autonomy/include/basic_autonomy/helper_functions.h
@@ -95,8 +95,7 @@ namespace waypoint_generation
* \return index of nearest point in points
*/
int get_nearest_index_by_downtrack(const std::vector& points, const carma_wm::WorldModelConstPtr& wm,
- const cav_msgs::VehicleState& state);
-
+ const cav_msgs::VehicleState& state);
}
}
\ No newline at end of file
diff --git a/basic_autonomy/src/basic_autonomy.cpp b/basic_autonomy/src/basic_autonomy.cpp
index 3373ebf87f..2fdde54d29 100644
--- a/basic_autonomy/src/basic_autonomy.cpp
+++ b/basic_autonomy/src/basic_autonomy.cpp
@@ -47,7 +47,7 @@ namespace basic_autonomy
}
else if(maneuver.type == cav_msgs::Maneuver::LANE_CHANGE){
ROS_DEBUG_STREAM("Creating Lane Change Geometry");
- std::vector lane_change_points = create_lanechange_geometry(maneuver, starting_downtrack, wm, ending_state_before_buffer, state, detailed_config);
+ std::vector lane_change_points = get_lanechange_points_from_maneuver(maneuver, starting_downtrack, wm, ending_state_before_buffer, state, general_config, detailed_config);
points_and_target_speeds.insert(points_and_target_speeds.end(), lane_change_points.begin(), lane_change_points.end());
}
else{
@@ -257,9 +257,220 @@ namespace basic_autonomy
return constrained_points;
}
- std::vector create_lanechange_geometry(const cav_msgs::Maneuver &maneuver, double starting_downtrack,
+ std::vector create_lanechange_geometry(lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double starting_downtrack, double ending_downtrack,
+ const carma_wm::WorldModelConstPtr &wm,const cav_msgs::VehicleState &state, int downsample_ratio)
+ {
+ std::vector centerline_points;
+
+ //Get starting lanelet and ending lanelets
+ lanelet::ConstLanelet starting_lanelet = wm->getMap()->laneletLayer.get(starting_lane_id);
+ lanelet::ConstLanelet ending_lanelet = wm->getMap()->laneletLayer.get(ending_lane_id);
+
+ lanelet::ConstLanelets starting_lane;
+ starting_lane.push_back(starting_lanelet);
+
+ std::vector reference_centerline;
+ // 400 value here is an arbitrary attempt at improving performance by reducing copy operations.
+ // Value picked based on annecdotal evidence from STOL system testing
+ reference_centerline.reserve(400);
+ bool shared_boundary_found = false;
+ bool is_lanechange_left = false;
+
+ lanelet::BasicLineString2d current_lanelet_centerline = starting_lanelet.centerline2d().basicLineString();
+ lanelet::ConstLanelet current_lanelet = starting_lanelet;
+ reference_centerline.insert(reference_centerline.end(), current_lanelet_centerline.begin(), current_lanelet_centerline.end());
+
+ while(!shared_boundary_found){
+ //Assumption- Adjacent lanelets share lane boundary
+ if(current_lanelet.leftBound() == ending_lanelet.rightBound()){
+ is_lanechange_left = true;
+ shared_boundary_found = true;
+ }
+
+ else if(current_lanelet.rightBound() == ending_lanelet.leftBound()){
+ shared_boundary_found = true;
+ }
+
+ else{
+ //If there are no following lanelets on route, lanechange should be completing before reaching it
+ if(wm->getMapRoutingGraph()->following(current_lanelet, false).empty())
+ {
+ // Maneuver requires we travel further before completing lane change, but no routable lanelet directly ahead
+ //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
+ //A lane change should have already happened at this point
+ throw(std::invalid_argument("No following lanelets from current lanelet reachable without a lane change, incorrectly chosen end lanelet"));
+ }
+
+ current_lanelet = wm->getMapRoutingGraph()->following(current_lanelet, false).front();
+ if(current_lanelet.id() == starting_lanelet.id()){
+ //Looped back to starting lanelet
+ throw(std::invalid_argument("No lane change in path"));
+ }
+ auto current_lanelet_linestring = current_lanelet.centerline2d().basicLineString();
+ //Concatenate linestring starting from + 1 to avoid overlap
+ reference_centerline.insert(reference_centerline.end(), current_lanelet_linestring.begin() + 1, current_lanelet_linestring.end());
+ starting_lane.push_back(current_lanelet);
+ }
+ }
+
+ //Find crosstrack distance between starting lane and ending lane
+ std::vector target_lane_centerline;
+ for(size_t i = 0;igetMapRoutingGraph()->left(starting_lane[0])){
+ curr_end_lanelet = wm->getMapRoutingGraph()->left(starting_lane[0]).get();
+ }
+ else{
+ curr_end_lanelet = wm->getMapRoutingGraph()->adjacentLeft(starting_lane[0]).get();
+ }
+ }
+ else{
+
+ //get right lanelet
+ if(wm->getMapRoutingGraph()->right(starting_lane[0])){
+ curr_end_lanelet = wm->getMapRoutingGraph()->right(starting_lane[0]).get();
+ }
+ else{
+ curr_end_lanelet = wm->getMapRoutingGraph()->adjacentRight(starting_lane[0]).get();
+ }
+ }
+
+ auto target_lane_linestring = curr_end_lanelet.centerline2d().basicLineString();
+ //Concatenate linestring starting from + 1 to avoid overlap
+ target_lane_centerline.insert(target_lane_centerline.end(), target_lane_linestring.begin() + 1, target_lane_linestring.end());
+
+ }
+
+ //Downsample centerlines
+ // 400 value here is an arbitrary attempt at improving performance by reducing copy operations.
+ // Value picked based on annecdotal evidence from STOL system testing
+
+ std::vector downsampled_starting_centerline;
+ downsampled_starting_centerline.reserve(400);
+ downsampled_starting_centerline = carma_utils::containers::downsample_vector(reference_centerline, downsample_ratio);
+
+ std::vector downsampled_target_centerline;
+ downsampled_target_centerline.reserve(400);
+ downsampled_target_centerline = carma_utils::containers::downsample_vector(target_lane_centerline, downsample_ratio);
+
+ //If points are not the same size - resample to ensure same size along both centerlines
+ if(downsampled_starting_centerline.size() != downsampled_target_centerline.size())
+ {
+ auto centerlines = resample_linestring_pair_to_same_size(downsampled_starting_centerline, downsampled_target_centerline);
+ downsampled_starting_centerline = centerlines.front();
+ downsampled_target_centerline = centerlines.back();
+
+ }
+
+ //Constrain to starting and ending downtrack
+ int start_index_starting_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_starting_centerline, wm, starting_downtrack);
+ cav_msgs::VehicleState start_state;
+ start_state.X_pos_global = downsampled_starting_centerline[start_index_starting_centerline].x();
+ start_state.Y_pos_global = downsampled_starting_centerline[start_index_starting_centerline].y();
+ int start_index_target_centerline = waypoint_generation::get_nearest_point_index(downsampled_target_centerline, start_state);
+
+ int end_index_target_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_target_centerline, wm, ending_downtrack);
+ cav_msgs::VehicleState end_state;
+ end_state.X_pos_global = downsampled_target_centerline[end_index_target_centerline].x();
+ end_state.Y_pos_global = downsampled_target_centerline[end_index_target_centerline].y();
+ int end_index_starting_centerline = waypoint_generation::get_nearest_point_index(downsampled_starting_centerline, end_state);
+
+ std::vector constrained_start_centerline(downsampled_starting_centerline.begin() + start_index_starting_centerline, downsampled_starting_centerline.begin() + end_index_starting_centerline);
+ std::vector constrained_target_centerline(downsampled_target_centerline.begin() + start_index_target_centerline, downsampled_target_centerline.begin() + end_index_target_centerline);
+
+ //Create Trajectory geometry
+ double delta_step = 1.0 / constrained_start_centerline.size();
+
+ for (size_t i = 0; i < constrained_start_centerline.size(); ++i)
+ {
+ lanelet::BasicPoint2d current_position;
+ lanelet::BasicPoint2d start_lane_pt = constrained_start_centerline[i];
+ lanelet::BasicPoint2d target_lane_pt = constrained_target_centerline[i];
+ double delta = delta_step * i;
+ current_position.x() = target_lane_pt.x() * delta + (1 - delta) * start_lane_pt.x();
+ current_position.y() = target_lane_pt.y() * delta + (1 - delta) * start_lane_pt.y();
+
+ centerline_points.push_back(current_position);
+ }
+
+ //Add points from following lanelet to provide sufficient distance for adding buffer
+ auto following_lanelets = wm->getMapRoutingGraph()->following(ending_lanelet, false);
+ if(!following_lanelets.empty()){
+ //Arbitrarily choosing first following lanelet for buffer since points are only being used to fit spline
+ auto following_lanelet_centerline = following_lanelets.front().centerline2d().basicLineString();
+ centerline_points.insert(centerline_points.end(), following_lanelet_centerline.begin(),
+ following_lanelet_centerline.end());
+ }
+
+ return centerline_points;
+ }
+
+ std::vector> resample_linestring_pair_to_same_size(std::vector& line_1, std::vector& line_2){
+
+ std::vector> output;
+ ros::WallTime start_time = ros::WallTime::now(); // Start timing the execution time for planning so it can be logged
+
+ //Fit centerlines to a spline
+ std::unique_ptr fit_curve_1 = compute_fit(line_1); // Compute splines based on curve points
+ if (!fit_curve_1)
+ {
+ throw std::invalid_argument("Could not fit a spline curve along the starting_lane centerline points!");
+ }
+
+ std::unique_ptr fit_curve_2 = compute_fit(line_2); // Compute splines based on curve points
+ if (!fit_curve_2)
+ {
+ throw std::invalid_argument("Could not fit a spline curve along the ending_lane centerline points!");
+ }
+
+ //Sample spline to get centerlines of equal size
+ std::vector all_sampling_points_line1;
+ std::vector all_sampling_points_line2;
+
+ size_t total_point_size = std::min(line_1.size(), line_2.size());
+
+ all_sampling_points_line1.reserve(1 + total_point_size * 2);
+ std::vector downtracks_raw_line1 = carma_wm::geometry::compute_arc_lengths(line_1);
+ int total_step_along_curve1 = static_cast(downtracks_raw_line1.back() / 2.0);
+ double step_threshold_line1 = (double)total_step_along_curve1 / (double)total_point_size;
+
+ all_sampling_points_line2.reserve(1 + total_point_size * 2);
+ std::vector downtracks_raw_line2 = carma_wm::geometry::compute_arc_lengths(line_2);
+ int total_step_along_curve2 = static_cast(downtracks_raw_line2.back() / 2.0);
+ double step_threshold_line2 = (double)total_step_along_curve2 / (double)total_point_size;
+
+ double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
+
+
+ all_sampling_points_line2.reserve(1 + total_point_size * 2);
+
+ for(size_t i = 0;i get_lanechange_points_from_maneuver(const cav_msgs::Maneuver &maneuver, double starting_downtrack,
const carma_wm::WorldModelConstPtr &wm, cav_msgs::VehicleState &ending_state_before_buffer,
- const cav_msgs::VehicleState &state, const DetailedTrajConfig &detailed_config)
+ const cav_msgs::VehicleState &state, const GeneralTrajConfig &general_config,const DetailedTrajConfig &detailed_config)
{
if(maneuver.type != cav_msgs::Maneuver::LANE_CHANGE){
throw std::invalid_argument("Create_lanechange called on a maneuver type which is not LANE_CHANGE");
@@ -275,8 +486,10 @@ namespace basic_autonomy
throw(std::invalid_argument("Start distance is greater than or equal to ending distance"));
}
- //get route between starting and ending downtracks
- std::vector route_geometry = create_route_geom(starting_downtrack, stoi(lane_change_maneuver.starting_lane_id), ending_downtrack + detailed_config.buffer_ending_downtrack, wm);
+ //get route between starting and ending downtracks - downtracks should be constant for complete length of maneuver
+ double lanechange_starting_downtrack;
+ std::vector route_geometry = create_lanechange_geometry(std::stoi(lane_change_maneuver.starting_lane_id),std::stoi(lane_change_maneuver.ending_lane_id),
+ starting_downtrack, ending_downtrack, wm, state, general_config.default_downsample_ratio);
ROS_DEBUG_STREAM("Route geometry size:"< future_geom_points;
std::vector final_actual_speeds;
split_point_speed_pairs(future_points, &future_geom_points, &final_actual_speeds);
- std::vector final_yaw_values = carma_wm::geometry::compute_tangent_orientations(future_geom_points);
+ std::unique_ptr fit_curve = compute_fit(future_geom_points);
+ if(!fit_curve){
+ throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
+ }
+ ROS_DEBUG("Got fit");
+ std::vector all_sampling_points;
+ all_sampling_points.reserve(1 + future_geom_points.size() * 2);
+
+
//Compute points to local downtracks
std::vector downtracks = carma_wm::geometry::compute_arc_lengths(future_geom_points);
+
+ auto total_step_along_curve = static_cast(downtracks.back() /detailed_config.curve_resample_step_size);
+ size_t total_point_size = future_geom_points.size();
+
+ double scaled_steps_along_curve = 0.0; //from 0 (start) to 1 (end) for the whole trajectory
+
+ for(size_t steps_along_curve = 0; steps_along_curve < total_step_along_curve; steps_along_curve++){
+ lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
+
+ all_sampling_points.push_back(p);
+
+ scaled_steps_along_curve += 1.0 / total_step_along_curve;
+ }
+ ROS_DEBUG_STREAM("Got sampled points with size:" << all_sampling_points.size());
+
+ std::vector final_yaw_values = carma_wm::geometry::compute_tangent_orientations(future_geom_points);
final_actual_speeds = smoothing::moving_average_filter(final_actual_speeds, detailed_config.speed_moving_average_window_size);
//Convert speeds to time
@@ -821,94 +1058,6 @@ namespace basic_autonomy
return traj_points;
}
- lanelet::BasicLineString2d create_lanechange_path(const lanelet::ConstLanelet &start_lanelet, const lanelet::ConstLanelet &end_lanelet)
- {
- std::vector centerline_points = {};
- lanelet::BasicLineString2d centerline_start_lane = start_lanelet.centerline2d().basicLineString();
- lanelet::BasicLineString2d centerline_end_lane = end_lanelet.centerline2d().basicLineString();
-
- auto total_points = std::min(centerline_start_lane.size(), centerline_end_lane.size());
- double delta_step = 1.0 / total_points;
-
- for (int i = 0; i < total_points; i++)
- {
- lanelet::BasicPoint2d current_position;
- lanelet::BasicPoint2d start_lane_pt = centerline_start_lane[i];
- lanelet::BasicPoint2d end_lane_pt = centerline_end_lane[i];
- double delta = delta_step * i;
- current_position.x() = end_lane_pt.x() * delta + (1 - delta) * start_lane_pt.x();
- current_position.y() = end_lane_pt.y() * delta + (1 - delta) * start_lane_pt.y();
-
- centerline_points.push_back(current_position);
- }
-
- std::unique_ptr fit_curve = compute_fit(centerline_points);
- if (!fit_curve)
- {
- throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
- }
-
- lanelet::BasicLineString2d lc_route;
-
- double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
- for (int i = 0; i < centerline_points.size(); i++)
- {
- lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
- lc_route.push_back(p);
- scaled_steps_along_curve += 1.0 / total_points;
- }
- lc_route.push_back(centerline_end_lane.back()); // at 1.0 scaled steps
-
- return lc_route;
- }
-
- std::vector create_route_geom(double starting_downtrack, int starting_lane_id, double ending_downtrack, const carma_wm::WorldModelConstPtr &wm)
- {
- //Create route geometry for lane change maneuver
- //Starting downtrack maybe in the previous lanelet, if it is, have a lane follow till new lanelet starts
- std::vector lanelets_in_path = wm->getLaneletsBetween(starting_downtrack, ending_downtrack, true);
- lanelet::BasicLineString2d centerline_points = {};
- int lane_change_iteration = 0;
- if (lanelets_in_path[0].id() != starting_lane_id)
- {
- bool lane_change_req = false;
- //Check if future lanelet is lane change lanelet
- for (int i = 0; i < lanelets_in_path.size(); i++)
- {
- if (lanelets_in_path[i].id() == starting_lane_id)
- {
- lane_change_req = true;
- lane_change_iteration = i;
- break;
- }
- }
- if (!lane_change_req)
- {
- throw std::invalid_argument("Current path does not require a lane change. Request Incorrectly sent to Cooperative lane change plugin");
- }
- //lane_follow till lane_change req
- lanelet::BasicLineString2d new_points = lanelets_in_path[lane_change_iteration - 1].centerline2d().basicLineString();
- lanelet::BasicLineString2d new_points_spliced(new_points.begin(), new_points.end() - 1);
- centerline_points.insert(centerline_points.end(), new_points_spliced.begin(), new_points_spliced.end());
- }
-
- lanelet::BasicLineString2d new_points = create_lanechange_path(lanelets_in_path[lane_change_iteration],lanelets_in_path[lane_change_iteration + 1]);
- centerline_points.insert(centerline_points.end(), new_points.begin(), new_points.end());
-
- //Add points from following lanelet to provide sufficient distance for adding buffer
- auto following_lanelets = wm->getMapRoutingGraph()->following(lanelets_in_path[lane_change_iteration + 1], false);
-
- if(!following_lanelets.empty()){
- //Arbitrarily choosing first following lanelet for buffer since points are only being used to fit spline
- auto following_lanelet_centerline = following_lanelets.front().centerline2d().basicLineString();
- centerline_points.insert(centerline_points.end(), following_lanelet_centerline.begin() + 1,
- following_lanelet_centerline.end());
- }
-
- std::vector centerline_as_vector(centerline_points.begin(), centerline_points.end());
-
- return centerline_as_vector;
- }
}
}
\ No newline at end of file
diff --git a/basic_autonomy/src/helper_functions.cpp b/basic_autonomy/src/helper_functions.cpp
index a256d37800..3a6de36b31 100644
--- a/basic_autonomy/src/helper_functions.cpp
+++ b/basic_autonomy/src/helper_functions.cpp
@@ -112,5 +112,6 @@ namespace waypoint_generation
double ending_downtrack = wm->routeTrackPos(state_pos).downtrack;
return get_nearest_index_by_downtrack(points, wm, ending_downtrack);
}
+
}
}
\ No newline at end of file
diff --git a/basic_autonomy/test/test_waypoint_generation.cpp b/basic_autonomy/test/test_waypoint_generation.cpp
index f93123ac2a..6188d8a44a 100644
--- a/basic_autonomy/test/test_waypoint_generation.cpp
+++ b/basic_autonomy/test/test_waypoint_generation.cpp
@@ -590,6 +590,96 @@ namespace basic_autonomy
ASSERT_NEAR(6.0, result[4].point.y(), 0.0000001);
}
+ TEST(BasicAutonomyTest, test_lanechange_trajectory)
+ {
+ //Case 1: Lane change from start to end of adjacent lanelets
+ std::string path = ros::package::getPath("basic_autonomy");
+ std::string file = "/resource/map/town01_vector_map_lane_change.osm";
+ file = path.append(file);
+ int projector_type = 0;
+ std::string target_frame;
+ lanelet::ErrorMessages load_errors;
+ lanelet::io_handlers::AutowareOsmParser::parseMapParams(file, &projector_type, &target_frame);
+ lanelet::projection::LocalFrameProjector local_projector(target_frame.c_str());
+ lanelet::LaneletMapPtr map = lanelet::load(file, local_projector, &load_errors);
+ if (map->laneletLayer.size() == 0)
+ {
+ FAIL() << "Input map does not contain any lanelets";
+ }
+ std::shared_ptr cwm = std::make_shared();
+ cwm->carma_wm::CARMAWorldModel::setMap(map);
+
+ //Set Route
+ lanelet::Id start_id = 106;
+ lanelet::Id end_id = 111;
+
+ carma_wm::test::setRouteByIds({start_id,end_id},cwm);
+ //get starting position
+ auto shortest_path = cwm->getRoute()->shortestPath();
+ lanelet::BasicPoint2d veh_pos = shortest_path[0].centerline2d().front();
+ double starting_downtrack =cwm->routeTrackPos(veh_pos).downtrack;
+ double ending_downtrack = cwm->routeTrackPos(shortest_path.back().centerline2d().back()).downtrack;
+
+ //Arguments for create geometry profile function-
+ cav_msgs::Maneuver maneuver;
+ maneuver.type = cav_msgs::Maneuver::LANE_CHANGE;
+ maneuver.lane_change_maneuver.start_dist = starting_downtrack;
+ maneuver.lane_change_maneuver.end_dist = ending_downtrack;
+ maneuver.lane_change_maneuver.start_speed = 5.0;
+ maneuver.lane_change_maneuver.start_time = ros::Time::now();
+ //calculate end_time assuming constant acceleration
+ double acc = pow(maneuver.lane_change_maneuver.start_speed, 2) / (2 * (ending_downtrack - starting_downtrack));
+ double end_time = maneuver.lane_change_maneuver.start_speed / acc;
+ maneuver.lane_change_maneuver.end_speed = 25.0;
+ maneuver.lane_change_maneuver.end_time = ros::Time(end_time + 10.0);
+ maneuver.lane_change_maneuver.starting_lane_id = std::to_string(start_id);
+ maneuver.lane_change_maneuver.ending_lane_id = std::to_string(end_id);
+
+ std::vector maneuvers;
+ maneuvers.push_back(maneuver);
+ cav_msgs::VehicleState state;
+ state.X_pos_global = veh_pos.x();
+ state.Y_pos_global = veh_pos.y();
+ state.longitudinal_vel = 8.0;
+
+ std::string trajectory_type = "cooperative_lanechange";
+ waypoint_generation::GeneralTrajConfig general_config = waypoint_generation::compose_general_trajectory_config(trajectory_type, 1, 1);
+ const waypoint_generation::DetailedTrajConfig config = waypoint_generation::compose_detailed_trajectory_config(0, 0, 0, 0, 0, 5, 0, 0, 20);
+ double maneuver_fraction_completed;
+ cav_msgs::VehicleState ending_state;
+
+ std::vector points = basic_autonomy::waypoint_generation::create_geometry_profile(maneuvers,
+ starting_downtrack, cwm, ending_state, state, general_config, config);
+ ros::Time state_time = ros::Time::now();
+ double target_speed = 11.176;
+
+ EXPECT_EQ(points.back().speed, state.longitudinal_vel);
+
+
+ //Case 2: Complete lane change before end of lanelet
+ int centerline_size = shortest_path.back().centerline2d().size();
+ maneuver.lane_change_maneuver.end_dist = cwm->routeTrackPos(shortest_path.back().centerline2d()[centerline_size/2]).downtrack;
+ maneuvers[0] = maneuver;
+ points = basic_autonomy::waypoint_generation::create_geometry_profile(maneuvers,
+ starting_downtrack, cwm, ending_state, state, general_config, config);
+
+ EXPECT_TRUE(points.size() > 4);
+
+ //Test resample linestring
+ lanelet::BasicLineString2d line_one = shortest_path.front().centerline2d().basicLineString();
+ std::vector line_1;
+ for(int i = 0;i line_2;
+ for(int i = 0;i> linestrings = basic_autonomy::waypoint_generation::resample_linestring_pair_to_same_size(line_1, line_2);
+
+ }
+
TEST(BasicAutonomyTest, maneuvers_to_lanechange_points)
{
@@ -643,8 +733,8 @@ namespace basic_autonomy
state.longitudinal_vel = 8.0;
std::string trajectory_type = "cooperative_lanechange";
- waypoint_generation::GeneralTrajConfig general_config = waypoint_generation::compose_general_trajectory_config(trajectory_type, 0, 0);
- const waypoint_generation::DetailedTrajConfig config = waypoint_generation::compose_detailed_trajectory_config(0, 0, 0, 0, 0, 5, 0, 0, 20);
+ waypoint_generation::GeneralTrajConfig general_config = waypoint_generation::compose_general_trajectory_config(trajectory_type, 1, 1);
+ const waypoint_generation::DetailedTrajConfig config = waypoint_generation::compose_detailed_trajectory_config(0, 1, 0, 0, 0, 5, 0, 0, 20);
double maneuver_fraction_completed;
cav_msgs::VehicleState ending_state;
@@ -656,19 +746,7 @@ namespace basic_autonomy
std::vector trajectory_points = basic_autonomy::waypoint_generation::compose_lanechange_trajectory_from_path(points,
state, state_time, cmw, ending_state, config);
EXPECT_TRUE(trajectory_points.size() > 2);
-
- basic_autonomy::waypoint_generation::create_route_geom(starting_downtrack, int(start_id), ending_downtrack, cmw);
-
- lanelet::ConstLanelet start_lanelet = shortest_path.front();
- lanelet::BasicPoint2d lc_start_point = start_lanelet.centerline2d().front();
- lanelet::ConstLanelet end_lanelet = shortest_path.back();
- lanelet::BasicPoint2d lc_end_point = end_lanelet.centerline2d().back();
- //create lanechange path creates the actual lanechange path. From starting of first lanelet's centerline, to the end of the adjacent
- //lanelet's centerline
- lanelet::BasicLineString2d lc_geom = basic_autonomy::waypoint_generation::create_lanechange_path(start_lanelet, end_lanelet);
-
- ASSERT_NEAR(lc_start_point.y(), lc_geom.front().y(), 0.000001);
- ASSERT_NEAR(lc_start_point.x(), lc_geom.front().x(), 0.000001);
+ basic_autonomy::waypoint_generation::create_lanechange_geometry(start_id, end_id,starting_downtrack, ending_downtrack, cmw, state, 1);
}
TEST(BasicAutonomyTest, lanefollow_geometry_visited_lanelets)
diff --git a/bsm_generator/CMakeLists.txt b/bsm_generator/CMakeLists.txt
index 4b80563cd9..21f06e3898 100644
--- a/bsm_generator/CMakeLists.txt
+++ b/bsm_generator/CMakeLists.txt
@@ -32,7 +32,6 @@ find_package(catkin REQUIRED COMPONENTS
geometry_msgs
pacmod_msgs
j2735_msgs
- novatel_gps_msgs
wgs84_utils
lanelet2_extension
)
@@ -46,7 +45,7 @@ find_package(Boost REQUIRED COMPONENTS system)
catkin_package(
CATKIN_DEPENDS roscpp std_msgs cav_msgs carma_utils automotive_platform_msgs
- geometry_msgs pacmod_msgs j2735_msgs novatel_gps_msgs wgs84_utils lanelet2_extension
+ geometry_msgs pacmod_msgs j2735_msgs wgs84_utils lanelet2_extension
)
###########
diff --git a/bsm_generator/config/parameters.yaml b/bsm_generator/config/parameters.yaml
index 8cd7fb06c6..4713ce5727 100644
--- a/bsm_generator/config/parameters.yaml
+++ b/bsm_generator/config/parameters.yaml
@@ -1,2 +1,3 @@
# The desired frequency for BSM generation
bsm_generation_frequency: 10.0
+
diff --git a/bsm_generator/include/bsm_generator.h b/bsm_generator/include/bsm_generator.h
index 3631c3f804..5c5d4d7553 100644
--- a/bsm_generator/include/bsm_generator.h
+++ b/bsm_generator/include/bsm_generator.h
@@ -22,12 +22,20 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
-#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include "bsm_generator_worker.h"
namespace bsm_generator
@@ -70,6 +78,12 @@ namespace bsm_generator
// frequency for bsm generation
double bsm_generation_frequency_;
+ //Enable/disable rotation of BSM ID during vehicle operations
+ bool bsm_id_rotation_enabled_;
+
+ std::vector bsm_message_id_;
+
+
// size of the vehicle
double vehicle_length_, vehicle_width_;
@@ -88,12 +102,12 @@ namespace bsm_generator
// callbacks for the subscribers
void poseCallback(const geometry_msgs::PoseStampedConstPtr& msg);
void accelCallback(const automotive_platform_msgs::VelocityAccelCovConstPtr& msg);
- void yawCallback(const pacmod_msgs::YawRateRptConstPtr& msg);
+ void yawCallback(const sensor_msgs::ImuConstPtr& msg);
void gearCallback(const j2735_msgs::TransmissionStateConstPtr& msg);
- void speedCallback(const std_msgs::Float64ConstPtr& msg);
+ void speedCallback(const geometry_msgs::TwistStampedPtr& msg);
void steerWheelAngleCallback(const std_msgs::Float64ConstPtr& msg);
void brakeCallback(const std_msgs::Float64ConstPtr& msg);
- void headingCallback(const novatel_gps_msgs::NovatelDualAntennaHeadingConstPtr& msg);
+ void headingCallback(const gps_common::GPSFixConstPtr& msg);
/**
* \brief Callback for map projection string to define lat/lon -> map conversion
diff --git a/bsm_generator/launch/bsm_generator.launch b/bsm_generator/launch/bsm_generator.launch
index b662105305..ccf3dd0109 100644
--- a/bsm_generator/launch/bsm_generator.launch
+++ b/bsm_generator/launch/bsm_generator.launch
@@ -15,5 +15,10 @@
-->
-
+
+
+
+
+
+
diff --git a/bsm_generator/package.xml b/bsm_generator/package.xml
index d92e4c4fc8..e9f05551a5 100644
--- a/bsm_generator/package.xml
+++ b/bsm_generator/package.xml
@@ -32,7 +32,6 @@
geometry_msgs
pacmod_msgs
j2735_msgs
- novatel_gps_msgs
wgs84_utils
lanelet2_extension
diff --git a/bsm_generator/src/bsm_generator.cpp b/bsm_generator/src/bsm_generator.cpp
index 5ac627f2cc..3ddb2d020a 100644
--- a/bsm_generator/src/bsm_generator.cpp
+++ b/bsm_generator/src/bsm_generator.cpp
@@ -23,21 +23,29 @@ namespace bsm_generator
void BSMGenerator::initialize()
{
+ int bsmid;
nh_.reset(new ros::CARMANodeHandle());
pnh_.reset(new ros::CARMANodeHandle("~"));
pnh_->param("bsm_generation_frequency", bsm_generation_frequency_, 10.0);
+ pnh_->param("/bsm_id_rotation_enabled", bsm_id_rotation_enabled_, true);
+ pnh_->param("/bsm_message_id", bsmid, 0);
+ for(size_t i = 0; i < 4; ++i ) //As the BSM Messsage ID is a four-element vector, the loop should iterate four times.
+ {
+ bsm_message_id_.emplace_back( bsmid >> (8 * i) );
+ }
+
nh_->param("vehicle_length", vehicle_length_, 5.0);
nh_->param("vehicle_width", vehicle_width_, 2.0);
bsm_pub_ = nh_->advertise("bsm_outbound", 5);
timer_ = nh_->createTimer(ros::Duration(1.0 / bsm_generation_frequency_), &BSMGenerator::generateBSM, this);
gear_sub_ = nh_->subscribe("transmission_state", 1, &BSMGenerator::gearCallback, this);
- speed_sub_ = nh_->subscribe("vehicle_speed_cov", 1, &BSMGenerator::speedCallback, this);
+ speed_sub_ = nh_->subscribe("ekf_twist", 1, &BSMGenerator::speedCallback, this);
steer_wheel_angle_sub_ = nh_->subscribe("steering_wheel_angle", 1, &BSMGenerator::steerWheelAngleCallback, this);
accel_sub_ = nh_->subscribe("velocity_accel_cov", 1, &BSMGenerator::accelCallback, this);
- yaw_sub_ = nh_->subscribe("yaw_rate_rpt", 1, &BSMGenerator::yawCallback, this);
+ yaw_sub_ = nh_->subscribe("imu_raw", 1, &BSMGenerator::yawCallback, this);
brake_sub_ = nh_->subscribe("brake_position", 1, &BSMGenerator::brakeCallback, this);
pose_sub_ = nh_->subscribe("pose", 1, &BSMGenerator::poseCallback, this);
- heading_sub_ = nh_->subscribe("dual_antenna_heading", 1, &BSMGenerator::headingCallback, this);
+ heading_sub_ = nh_->subscribe("gnss_fix_fused", 1, &BSMGenerator::headingCallback, this);
georeference_sub_ = nh_->subscribe("georeference", 1, &BSMGenerator::georeferenceCallback, this);
}
@@ -62,9 +70,9 @@ namespace bsm_generator
map_projector_ = std::make_shared(msg->data.c_str()); // Build projector from proj string
}
- void BSMGenerator::speedCallback(const std_msgs::Float64ConstPtr& msg)
+ void BSMGenerator::speedCallback(const geometry_msgs::TwistStampedPtr& msg)
{
- bsm_.core_data.speed = worker.getSpeedInRange(msg->data);
+ bsm_.core_data.speed = worker.getSpeedInRange(msg->twist.linear.x);
bsm_.core_data.presence_vector = bsm_.core_data.presence_vector | bsm_.core_data.SPEED_AVAILABLE;
}
@@ -85,9 +93,9 @@ namespace bsm_generator
bsm_.core_data.accelSet.presence_vector = bsm_.core_data.accelSet.presence_vector | bsm_.core_data.accelSet.ACCELERATION_AVAILABLE;
}
- void BSMGenerator::yawCallback(const pacmod_msgs::YawRateRptConstPtr& msg)
+ void BSMGenerator::yawCallback(const sensor_msgs::ImuConstPtr& msg)
{
- bsm_.core_data.accelSet.yaw_rate = worker.getYawRateInRange(msg->yaw_rate);
+ bsm_.core_data.accelSet.yaw_rate = worker.getYawRateInRange(static_cast(msg->angular_velocity.z));
bsm_.core_data.accelSet.presence_vector = bsm_.core_data.accelSet.presence_vector | bsm_.core_data.accelSet.YAWRATE_AVAILABLE;
}
@@ -115,16 +123,25 @@ namespace bsm_generator
}
- void BSMGenerator::headingCallback(const novatel_gps_msgs::NovatelDualAntennaHeadingConstPtr& msg)
+ void BSMGenerator::headingCallback(const gps_common::GPSFixConstPtr& msg)
{
- bsm_.core_data.heading = worker.getHeadingInRange(msg->heading);
+ bsm_.core_data.heading = worker.getHeadingInRange(static_cast(msg->track));
+ bsm_.core_data.presence_vector = bsm_.core_data.presence_vector | bsm_.core_data.HEADING_AVAILABLE;
}
void BSMGenerator::generateBSM(const ros::TimerEvent& event)
{
bsm_.header.stamp = ros::Time::now();
bsm_.core_data.msg_count = worker.getNextMsgCount();
- bsm_.core_data.id = worker.getMsgId(ros::Time::now());
+
+ if(bsm_id_rotation_enabled_)
+ {
+ bsm_.core_data.id = worker.getMsgId(ros::Time::now());
+ }
+ else
+ {
+ bsm_.core_data.id = bsm_message_id_;
+ }
bsm_.core_data.sec_mark = worker.getSecMark(ros::Time::now());
bsm_.core_data.presence_vector = bsm_.core_data.presence_vector | bsm_.core_data.SEC_MARK_AVAILABLE;
// currently the accuracy is not available because ndt_matching does not provide accuracy measurement
diff --git a/carma-platform.repos b/carma-platform.repos
index 4eb43efcad..f09ef0f9a3 100644
--- a/carma-platform.repos
+++ b/carma-platform.repos
@@ -6,7 +6,7 @@ repositories:
src/autoware.ai:
type: git
url: git@github.com:usdot-fhwa-stol/autoware.ai.git
- version: develop
+ version: carma-develop
src/avt_vimba_camera:
type: git
url: git@github.com:usdot-fhwa-stol/avt_vimba_camera.git
diff --git a/carma/launch/guidance.launch b/carma/launch/guidance.launch
index 88adfdd77e..4cb51db0c2 100644
--- a/carma/launch/guidance.launch
+++ b/carma/launch/guidance.launch
@@ -231,6 +231,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/carma_wm/CMakeLists.txt b/carma_wm/CMakeLists.txt
index 1acc5ed778..25c45365fe 100644
--- a/carma_wm/CMakeLists.txt
+++ b/carma_wm/CMakeLists.txt
@@ -79,6 +79,7 @@ add_library(
src/TrafficControl.cpp
src/IndexedDistanceMap.cpp
src/collision_detection.cpp
+ src/SignalizedIntersectionManager.cpp
)
## Add cmake target dependencies of the library
@@ -136,6 +137,7 @@ install(DIRECTORY include/${PROJECT_NAME}/
catkin_add_gmock(${PROJECT_NAME}-test
test/TestMain.cpp
test/CARMAWorldModelTest.cpp
+ test/SignalizedIntersectionManagerTest.cpp
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test # Add test directory as working directory for unit tests
)
diff --git a/carma_wm/include/carma_wm/CARMAWorldModel.h b/carma_wm/include/carma_wm/CARMAWorldModel.h
index fd62742ad2..9d813bddce 100644
--- a/carma_wm/include/carma_wm/CARMAWorldModel.h
+++ b/carma_wm/include/carma_wm/CARMAWorldModel.h
@@ -30,7 +30,7 @@
#include "TrackPos.h"
#include
#include "boost/date_time/posix_time/posix_time.hpp"
-
+#include
namespace carma_wm
{
@@ -216,12 +216,14 @@ class CARMAWorldModel : public WorldModel
std::vector nonConnectedAdjacentLeft(const lanelet::BasicPoint2d& input_point, const unsigned int n = 10) const override;
- std::vector getLightsAlongRoute(const lanelet::BasicPoint2d& loc) const override;
+ std::vector getSignalsAlongRoute(const lanelet::BasicPoint2d& loc) const override;
std::vector> getIntersectionsAlongRoute(const lanelet::BasicPoint2d& loc) const override;
std::unordered_map traffic_light_ids_;
+ carma_wm::SignalizedIntersectionManager sim_; // records SPAT/MAP lane ids to lanelet ids
+
private:
double config_speed_limit_;
@@ -250,7 +252,7 @@ class CARMAWorldModel : public WorldModel
LaneletRoutePtr route_;
LaneletRoutingGraphPtr map_routing_graph_;
double route_length_ = 0;
- std::unordered_map>>> traffic_light_states_; //[intersection_id][signal_group_id]
+ std::unordered_map>>> traffic_light_states_; //[intersection_id][signal_group_id]
lanelet::LaneletSubmapConstUPtr shortest_path_view_; // Map containing only lanelets along the shortest path of the
// route
std::vector shortest_path_centerlines_; // List of disjoint centerlines seperated by lane
diff --git a/carma_wm/include/carma_wm/SignalizedIntersectionManager.h b/carma_wm/include/carma_wm/SignalizedIntersectionManager.h
new file mode 100644
index 0000000000..df60a290ef
--- /dev/null
+++ b/carma_wm/include/carma_wm/SignalizedIntersectionManager.h
@@ -0,0 +1,143 @@
+#pragma once
+
+/*
+ * Copyright (C) 2021 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+namespace carma_wm
+{
+
+struct LANE_DIRECTION
+{
+ static const uint8_t INGRESS = 1;
+ static const uint8_t EGRESS = 2;
+};
+
+using namespace lanelet::units::literals;
+
+/*! \brief This class manages and keeps track of all signalized intersections in the map.
+ All of the SPAT and MAP standard's lane ids to lanelet id mapping is recorded here.
+ NOTE: This class functions do not update the map given.
+ */
+class SignalizedIntersectionManager
+{
+public:
+ SignalizedIntersectionManager(){}
+
+ /*!
+ * \brief Create relevant signalized intersection and carma traffic signals based on the MAP.msg and the lanelet_map
+ NOTE: The function does not update the map with new elements
+ * \param[out] intersections to return
+ * \param[out] traffic_signals to return
+ * \param map_msg MAP.msg that consists all static data portion of the intersection
+ * \param map lanelet_map to check
+ * \param routing_graph of the lanelet map to accurately detect lanes
+ */
+ void createIntersectionFromMapMsg(std::vector& intersections, std::vector& traffic_signals, const cav_msgs::MapData& map_msg,
+ const std::shared_ptr& map, std::shared_ptr routing_graph);
+
+ /*!
+ * \brief Returns mapping of MAP lane id to lanelet id for the given map and intersection.msg in the MAP.msg.
+ This function also records signal_group_id_to its own lanelet id, and also signal group to entry and exit lanelets id mappings
+ * \param[out] entry lane id to lanelet id mappings to return
+ * \param[out] exit lane id to lanelet id mappings to return
+ * \param intersection MAP.msg that consists all static data portion of the intersection
+ * \param map lanelet_map to check
+ * \param routing_graph of the lanelet map to accurately detect lanes
+ * \throw invalid_argument if given coordinates in the msg doesn't exist in the map
+ * TODO: Need to think about error buffer in the future. Map msgs are made from google maps or open streets maps normally so this function might run into some errors from that.
+ */
+ void convertLaneToLaneletId(std::unordered_map& entry, std::unordered_map& exit, const cav_msgs::IntersectionGeometry& intersection,
+ const std::shared_ptr& map, std::shared_ptr current_routing_graph);
+
+ /*!
+ * \brief Sets the max lane width in meters. Map msg points are associated to a lanelet if they are
+ * within this distance to a lanelet as map msg points are guaranteed to apply to a single lane
+ */
+ void setMaxLaneWidth(double max_lane_width);
+
+ /*!
+ * \brief Returns existing signalized intersection with same entry and exit llts if exists.
+ * \param entry_llts of the intersection
+ * \param exit_llts of the intersection
+ * \param map lanelet_map to check
+ * \return id of the matching intersection in the map, or lanelet::InvalId if none exists
+ */
+ lanelet::Id matchSignalizedIntersection(const lanelet::Lanelets& entry_llts, const lanelet::Lanelets& exit_llts, const std::shared_ptr& map);
+
+ /*!
+ * \brief Saves the georeference string to be used for converting MAP.msg coordinates
+ * \param target_frame PROJ string of the map
+ */
+ void setTargetFrame(const std::string& target_frame);
+
+ /*!
+ * \brief Returns carma traffic signal and saves all id relevant id mappings (signal group to lanelet id) internally
+ * \param signal_group_id of the traffic signal
+ * \param exit_llts of the signal_group
+ * \param entry_llts of the signal_group
+ * \return traffic signal corresponding to the signal group
+ */
+ std::shared_ptr createTrafficSignalUsingSGID(uint8_t signal_group_id, const lanelet::Lanelets& entry_lanelets, const lanelet::Lanelets& exit_lanelets);
+
+ /*!
+ * \brief Returns carma traffic signal and saves all id relevant id mappings (signal group to lanelet id) internally
+ * \param signal_group_id of the traffic signal
+ * \param exit_llts of the signal_group
+ * \param entry_llts of the signal_group
+ * \return traffic signal corresponding to the signal group
+ */
+ lanelet::Lanelets identifyInteriorLanelets(const lanelet::Lanelets& entry_llts, const std::shared_ptr& map);
+
+ // SignalizedIntersection quick id lookup
+ std::unordered_map intersection_id_to_regem_id_;
+
+ // CarmaTrafficSignal quick id lookup
+ std::unordered_map signal_group_to_traffic_light_id_;
+
+ // CarmaTrafficSignal exit lanelets ids quick lookup
+ std::unordered_map> signal_group_to_exit_lanelet_ids_;
+
+ // CarmaTrafficSignal entry lanelets ids quick lookup
+ std::unordered_map> signal_group_to_entry_lanelet_ids_;
+
+ // Traffic signal states and their end_time mappings.
+ std::unordered_map>>> traffic_signal_states_; //[intersection_id][signal_group_id]
+
+private:
+
+ // PROJ string of current map
+ std::string target_frame_ = "";
+
+ // Max width of lane in meters
+ double max_lane_width_ = 4;
+};
+
+} // namespace carma_wm
\ No newline at end of file
diff --git a/carma_wm/include/carma_wm/TrafficControl.h b/carma_wm/include/carma_wm/TrafficControl.h
index 996c7ae59c..5783b73d7e 100644
--- a/carma_wm/include/carma_wm/TrafficControl.h
+++ b/carma_wm/include/carma_wm/TrafficControl.h
@@ -26,9 +26,10 @@
#include
#include
#include
-#include
+#include
#include
#include
+#include
#include
@@ -59,6 +60,9 @@ class TrafficControl
// traffic light id lookup
std::vector> traffic_light_id_lookup_;
+
+ // signalized intersection manager
+ carma_wm::SignalizedIntersectionManager sim_;
};
/**
@@ -115,6 +119,9 @@ inline void save(Archive& ar, const carma_wm::TrafficControl& gf, unsigned int /
size_t traffic_light_id_lookup_size = gf.traffic_light_id_lookup_.size();
ar << traffic_light_id_lookup_size;
for (auto pair : gf.traffic_light_id_lookup_) ar << pair;
+
+ // convert signalized intersection manager
+ ar << gf.sim_;
}
template
@@ -165,6 +172,115 @@ inline void load(Archive& ar, carma_wm::TrafficControl& gf, unsigned int /*versi
ar >> traffic_light_id_pair;
gf.traffic_light_id_lookup_.push_back(traffic_light_id_pair);
}
+
+ // save signalized intersection manager
+ ar >> gf.sim_;
+}
+
+
+template
+// NOLINTNEXTLINE
+inline void save(Archive& ar, const carma_wm::SignalizedIntersectionManager& sim, unsigned int /*version*/)
+{
+ // convert traffic light id lookup
+ size_t intersection_id_to_regem_id_size = sim.intersection_id_to_regem_id_.size();
+ ar << intersection_id_to_regem_id_size;
+ for (auto pair : sim.intersection_id_to_regem_id_)
+ {
+ ar << pair;
+ }
+
+ // convert traffic light id lookup
+ size_t signal_group_to_traffic_light_id_size = sim.signal_group_to_traffic_light_id_.size();
+ ar << signal_group_to_traffic_light_id_size;
+ for (auto pair : sim.signal_group_to_traffic_light_id_)
+ {
+ ar << pair;
+ }
+
+ size_t signal_group_to_exit_lanelet_ids_size = sim.signal_group_to_exit_lanelet_ids_.size();
+ ar << signal_group_to_exit_lanelet_ids_size;
+ for (auto pair : sim.signal_group_to_exit_lanelet_ids_)
+ {
+ size_t set_size = pair.second.size();
+ ar << set_size;
+ ar << pair.first;
+ for (auto iter = pair.second.begin(); iter != pair.second.end(); iter++)
+ {
+ ar << *iter;
+ }
+ }
+
+ size_t signal_group_to_entry_lanelet_ids_size = sim.signal_group_to_entry_lanelet_ids_.size();
+ ar << signal_group_to_entry_lanelet_ids_size;
+ for (auto pair : sim.signal_group_to_entry_lanelet_ids_)
+ {
+ size_t set_size = pair.second.size();
+ ar << set_size;
+ ar << pair.first;
+ for (auto iter = pair.second.begin(); iter != pair.second.end(); iter++)
+ {
+ ar << *iter;
+ }
+ }
+}
+
+template
+// NOLINTNEXTLINE
+inline void load(Archive& ar, carma_wm::SignalizedIntersectionManager& sim, unsigned int /*version*/)
+{
+ // save traffic light id lookup
+ size_t intersection_id_to_regem_id_size;
+ ar >> intersection_id_to_regem_id_size;
+ for (size_t i = 0; i < intersection_id_to_regem_id_size; i ++)
+ {
+ std::pair pair;
+ ar >> pair;
+ sim.intersection_id_to_regem_id_.emplace(pair);
+ }
+
+ // save traffic light id lookup
+ size_t signal_group_to_traffic_light_id_size;
+ ar >> signal_group_to_traffic_light_id_size;
+ for (size_t i = 0; i < signal_group_to_traffic_light_id_size; i ++)
+ {
+ std::pair pair;
+ ar >> pair;
+ sim.signal_group_to_traffic_light_id_.emplace(pair);
+ }
+
+ size_t signal_group_to_exit_lanelet_ids_size;
+ ar >> signal_group_to_exit_lanelet_ids_size;
+ for (size_t i = 0; i < signal_group_to_exit_lanelet_ids_size; i ++)
+ {
+ size_t set_size;
+ ar >> set_size;
+ uint8_t signal_grp;
+ ar >> signal_grp;
+ for (size_t j = 0; j >id;
+ sim.signal_group_to_exit_lanelet_ids_[signal_grp].insert(id);
+ }
+ }
+
+ size_t signal_group_to_entry_lanelet_ids_size;
+ ar >> signal_group_to_entry_lanelet_ids_size;
+ for (size_t i = 0; i < signal_group_to_entry_lanelet_ids_size; i ++)
+ {
+ size_t set_size;
+ ar >> set_size;
+ uint8_t signal_grp;
+ ar >> signal_grp;
+ for (size_t j = 0; j >id;
+ sim.signal_group_to_entry_lanelet_ids_[signal_grp].insert(id);
+ }
+ }
+
}
template
@@ -174,6 +290,20 @@ void serialize(Archive& ar, std::pair
+void serialize(Archive& ar, std::pair& p, unsigned int /*version*/)
+{
+ ar& p.first;
+ ar& p.second;
+}
+
+template
+void serialize(Archive& ar, std::pair& p, unsigned int /*version*/)
+{
+ ar& p.first;
+ ar& p.second;
+}
+
template
void serialize(Archive& ar, std::pair& p, unsigned int /*version*/)
{
@@ -184,4 +314,5 @@ void serialize(Archive& ar, std::pair& p, unsigned int /*
} // namespace serialization
} // namespace boost
-BOOST_SERIALIZATION_SPLIT_FREE(carma_wm::TrafficControl);
\ No newline at end of file
+BOOST_SERIALIZATION_SPLIT_FREE(carma_wm::TrafficControl);
+BOOST_SERIALIZATION_SPLIT_FREE(carma_wm::SignalizedIntersectionManager);
diff --git a/carma_wm/include/carma_wm/WMTestLibForGuidance.h b/carma_wm/include/carma_wm/WMTestLibForGuidance.h
index 81a6bbc412..02c6cc4cd4 100644
--- a/carma_wm/include/carma_wm/WMTestLibForGuidance.h
+++ b/carma_wm/include/carma_wm/WMTestLibForGuidance.h
@@ -30,7 +30,7 @@
#include
#include
#include
-#include
+#include
/**
* This is a test library made for guidance unit tests. In general, it includes the following :
* - Helper functions to create the world from scratch or extend the world in getGuidanceTestMap()
@@ -488,16 +488,16 @@ inline void setRouteByIds (std::vector lanelet_ids, std::shared_ptr
* \param light_id The lanelet id to use for the generated traffic light regulatory element. This id should NOT be present in the map prior to this method call
* \param owning_lanelet_id The id of the lanelet which will own thr traffic light element. This id MUST be present in the map prior to this method being called
* \param controlled_lanelet_ids A list of lanelet ids which the traffic light will control access to. The ids MUST be present in the map. Additionally, they should be listed in order along the direction of travel.
- * \param timeing_plan Optional parameter that is the timing plan to use for the light. The specifications match those of CarmaTrafficLightState.setStates()
+ * \param timeing_plan Optional parameter that is the timing plan to use for the light. The specifications match those of CarmaTrafficSignalState.setStates()
* The default timing plan is 4sec yewllow, 20sec red, 20sec green
*/
inline void addTrafficLight(std::shared_ptr cmw, lanelet::Id light_id, lanelet::Id owning_lanelet_id, std::vector controlled_lanelet_ids,
-std::vector> timing_plan =
+std::vector> timing_plan =
{
- std::make_pair(lanelet::time::timeFromSec(0), lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED), // Just ended green
- std::make_pair(lanelet::time::timeFromSec(4.0), lanelet::CarmaTrafficLightState::PROTECTED_CLEARANCE), // 4 sec yellow
- std::make_pair(lanelet::time::timeFromSec(24.0), lanelet::CarmaTrafficLightState::STOP_AND_REMAIN), // 20 sec red
- std::make_pair(lanelet::time::timeFromSec(44.0), lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED) // 20 sec green
+ std::make_pair(lanelet::time::timeFromSec(0), lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED), // Just ended green
+ std::make_pair(lanelet::time::timeFromSec(4.0), lanelet::CarmaTrafficSignalState::PROTECTED_CLEARANCE), // 4 sec yellow
+ std::make_pair(lanelet::time::timeFromSec(24.0), lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN), // 20 sec red
+ std::make_pair(lanelet::time::timeFromSec(44.0), lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED) // 20 sec green
}) {
std::vector controlled_lanelets;
@@ -524,7 +524,7 @@ std::vector
lanelet::LineString3d virtual_stop_line(lanelet::utils::getId(), { owning_lanelet.leftBound().back(), owning_lanelet.rightBound().back() });
// Build traffic light
- std::shared_ptr traffic_light(new lanelet::CarmaTrafficLight(lanelet::CarmaTrafficLight::buildData(light_id, { virtual_stop_line }, controlled_lanelets )));
+ std::shared_ptr traffic_light(new lanelet::CarmaTrafficSignal(lanelet::CarmaTrafficSignal::buildData(light_id, { virtual_stop_line }, {controlled_lanelets.front()}, {controlled_lanelets.back()} )));
// Set the timing plan
traffic_light->setStates(timing_plan,0);
diff --git a/carma_wm/include/carma_wm/WorldModel.h b/carma_wm/include/carma_wm/WorldModel.h
index 591f43cae0..0c8f089bca 100644
--- a/carma_wm/include/carma_wm/WorldModel.h
+++ b/carma_wm/include/carma_wm/WorldModel.h
@@ -31,7 +31,7 @@
#include
#include
#include
-#include
+#include
#include
#include "TrackPos.h"
@@ -366,7 +366,7 @@ class WorldModel
*
* \return list of traffic lights along the current route
*/
- virtual std::vector getLightsAlongRoute(const lanelet::BasicPoint2d& loc) const = 0;
+ virtual std::vector getSignalsAlongRoute(const lanelet::BasicPoint2d& loc) const = 0;
/**
* \brief Return a list of all way stop intersections along the current route.
diff --git a/carma_wm/include/carma_wm/WorldModelUtils.h b/carma_wm/include/carma_wm/WorldModelUtils.h
index 0b61a802ce..2a757e8c49 100644
--- a/carma_wm/include/carma_wm/WorldModelUtils.h
+++ b/carma_wm/include/carma_wm/WorldModelUtils.h
@@ -30,6 +30,10 @@
#include
#include
#include
+#include
+#include
+#include
+
namespace carma_wm
{
@@ -103,6 +107,30 @@ std::vector nonConnectedAdjacentLeft(const lanelet::Lanel
std::vector nonConnectedAdjacentLeft(const lanelet::LaneletMapPtr& semantic_map, const lanelet::BasicPoint2d& input_point,
const unsigned int n = 10);
+
+/*!
+ * \brief Gets the affected lanelet or areas based on the points in the given map's frame
+ * \param geofence_msg lanelet::Points3d in local frame
+ * \param lanelet_map Lanelet Map Ptr
+ * \param routing_graph Routing graph of the lanelet map
+ * \param max_lane_width max lane width of the lanes in the map
+ *
+ * NOTE:Currently this function only checks lanelets and will be expanded to areas in the future.
+ */
+lanelet::ConstLaneletOrAreas getAffectedLaneletOrAreas(const lanelet::Points3d& gf_pts, const lanelet::LaneletMapPtr& lanelet_map, std::shared_ptr routing_graph, double max_lane_width);
+
+/*!
+ * \brief A function that filters successor lanelets of root_lanelets from possible_lanelets
+ * \param possible_lanelets all possible lanelets to check
+ * \param root_lanelets lanelets to filter from
+ * \param lanelet_map Lanelet Map Ptr
+ * \param routing_graph Routing graph of the lanelet map
+ *
+ * NOTE:Mainly used as a helper function for getAffectedLaneletOrAreas
+ */
+std::unordered_set filterSuccessorLanelets(const std::unordered_set& possible_lanelets, const std::unordered_set& root_lanelets,
+ const lanelet::LaneletMapPtr& lanelet_map, std::shared_ptr routing_graph);
+
} // namespace query
namespace utils
diff --git a/carma_wm/src/CARMAWorldModel.cpp b/carma_wm/src/CARMAWorldModel.cpp
index 37fb3f80e9..255d6c7b3c 100755
--- a/carma_wm/src/CARMAWorldModel.cpp
+++ b/carma_wm/src/CARMAWorldModel.cpp
@@ -1136,7 +1136,7 @@ std::vector CARMAWorldModel::nonConnectedAdjacentLeft(con
return carma_wm::query::getLaneletsFromPoint(getMap(), input_point, n);
}
-std::vector CARMAWorldModel::getLightsAlongRoute(const lanelet::BasicPoint2d& loc) const
+std::vector CARMAWorldModel::getSignalsAlongRoute(const lanelet::BasicPoint2d& loc) const
{
// Check if the map is loaded yet
if (!semantic_map_ || semantic_map_->laneletLayer.empty())
@@ -1150,12 +1150,12 @@ std::vector CARMAWorldModel::getLightsAlongRoute(
ROS_ERROR_STREAM("Route has not yet been loaded");
return {};
}
- std::vector light_list;
+ std::vector light_list;
auto curr_downtrack = routeTrackPos(loc).downtrack;
// shortpath is already sorted by distance
for(const auto& ll : route_->shortestPath())
{
- auto lights = semantic_map_->laneletLayer.get(ll.id()).regulatoryElementsAs();
+ auto lights = semantic_map_->laneletLayer.get(ll.id()).regulatoryElementsAs();
if (lights.empty())
{
continue;
@@ -1244,7 +1244,7 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
", and signal_group_id: " << (int)current_movement_state.signal_group);
continue;
}
- auto curr_light_list = lanelets_general[0].regulatoryElementsAs();
+ auto curr_light_list = lanelets_general[0].regulatoryElementsAs();
if (curr_light_list.empty())
{
@@ -1252,7 +1252,7 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
", and signal_group_id: " << (int)current_movement_state.signal_group);
continue;
}
- lanelet::CarmaTrafficLightPtr curr_light = curr_light_list[0];
+ lanelet::CarmaTrafficSignalPtr curr_light = curr_light_list[0];
// reset states if the intersection's geometry changed
if (curr_light->revision_ != curr_intersection.revision)
@@ -1307,7 +1307,7 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
//if same data as last time:
//where state is same and timestamp is equal or less, skip
if (traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].size() > 0 && traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().second ==
- static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) &&
+ static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) &&
traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().first >= min_end_time)
{
continue;
@@ -1316,17 +1316,17 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
// if received same state as last time, but with updated time, just update the time of last state
// skip setting state until received a new state that is different from last recorded one
if (traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].size() > 0 && traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().second ==
- static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) &&
+ static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) &&
traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().first < min_end_time)
{
- ROS_DEBUG_STREAM("Updated time for state: " << static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) << ", with time: "
+ ROS_DEBUG_STREAM("Updated time for state: " << static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) << ", with time: "
<< std::to_string(lanelet::time::toSec(min_end_time)));
traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().first = min_end_time;
continue;
}
// detected that new state received; therefore, set the last recorded state (not new one received)
- ROS_DEBUG_STREAM("Received new state for light: " << curr_light_id << ", with state: " << static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) <<
+ ROS_DEBUG_STREAM("Received new state for light: " << curr_light_id << ", with state: " << static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state) <<
", time: " << ros::Time::fromBoost(min_end_time));
@@ -1341,12 +1341,12 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
}
else if (curr_light->recorded_time_stamps.empty()) // if it was never initialized, do its best to plan with the current state until the future state is also received.
{
- std::vector> default_state;
+ std::vector> default_state;
// green 20sec, yellow 3sec, red 20sec, back to green 20sec etc...
- default_state.push_back(std::make_pair(boost::posix_time::from_time_t(0), lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED));
- default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(YELLOW_LIGHT_DURATION), lanelet::CarmaTrafficLightState::PROTECTED_CLEARANCE));
- default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(RED_LIGHT_DURATION), lanelet::CarmaTrafficLightState::STOP_AND_REMAIN));
- default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(GREEN_LIGHT_DURATION), lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED));
+ default_state.push_back(std::make_pair(boost::posix_time::from_time_t(0), lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED));
+ default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(YELLOW_LIGHT_DURATION), lanelet::CarmaTrafficSignalState::PROTECTED_CLEARANCE));
+ default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(RED_LIGHT_DURATION), lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN));
+ default_state.push_back(std::make_pair(default_state.back().first + lanelet::time::durationFromSec(GREEN_LIGHT_DURATION), lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED));
curr_light->setStates(default_state, curr_intersection.revision);
ROS_DEBUG_STREAM("Set default cycle of total seconds: " << lanelet::time::toSec(curr_light->fixed_cycle_duration));
@@ -1357,7 +1357,7 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
auto yellow_light_duration = lanelet::time::durationFromSec(YELLOW_LIGHT_DURATION);
auto red_light_duration = lanelet::time::durationFromSec(RED_LIGHT_DURATION);
- std::vector> partial_states;
+ std::vector> partial_states;
// set the partial cycle.
ROS_DEBUG_STREAM("Setting last recorded state for light: " << curr_light_id << ", with state: " << traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().second <<
", time: " << traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].back().first);
@@ -1365,20 +1365,20 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
{
auto light_state = traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i + 1].second;
- if (light_state == lanelet::CarmaTrafficLightState::STOP_AND_REMAIN || light_state == lanelet::CarmaTrafficLightState::STOP_THEN_PROCEED)
+ if (light_state == lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN || light_state == lanelet::CarmaTrafficSignalState::STOP_THEN_PROCEED)
red_light_duration = traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i + 1].first - traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i].first;
- else if (light_state == lanelet::CarmaTrafficLightState::PERMISSIVE_MOVEMENT_ALLOWED || light_state == lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED)
+ else if (light_state == lanelet::CarmaTrafficSignalState::PERMISSIVE_MOVEMENT_ALLOWED || light_state == lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED)
green_light_duration = traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i + 1].first - traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i].first;
- else if (light_state == lanelet::CarmaTrafficLightState::PERMISSIVE_CLEARANCE || light_state == lanelet::CarmaTrafficLightState::PROTECTED_CLEARANCE)
+ else if (light_state == lanelet::CarmaTrafficSignalState::PERMISSIVE_CLEARANCE || light_state == lanelet::CarmaTrafficSignalState::PROTECTED_CLEARANCE)
yellow_light_duration = traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i + 1].first - traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group][i].first;
}
- partial_states.push_back(std::make_pair(boost::posix_time::from_time_t(0), lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED));
- partial_states.push_back(std::make_pair(partial_states.back().first + yellow_light_duration, lanelet::CarmaTrafficLightState::PROTECTED_CLEARANCE));
- partial_states.push_back(std::make_pair(partial_states.back().first + red_light_duration, lanelet::CarmaTrafficLightState::STOP_AND_REMAIN));
- partial_states.push_back(std::make_pair(partial_states.back().first + green_light_duration, lanelet::CarmaTrafficLightState::PROTECTED_MOVEMENT_ALLOWED));
+ partial_states.push_back(std::make_pair(boost::posix_time::from_time_t(0), lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED));
+ partial_states.push_back(std::make_pair(partial_states.back().first + yellow_light_duration, lanelet::CarmaTrafficSignalState::PROTECTED_CLEARANCE));
+ partial_states.push_back(std::make_pair(partial_states.back().first + red_light_duration, lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN));
+ partial_states.push_back(std::make_pair(partial_states.back().first + green_light_duration, lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED));
curr_light->setStates(partial_states, curr_intersection.revision);
ROS_DEBUG_STREAM("Set new partial cycle of total seconds: " << lanelet::time::toSec(curr_light->fixed_cycle_duration));
@@ -1387,7 +1387,7 @@ void CARMAWorldModel::processSpatFromMsg(const cav_msgs::SPAT& spat_msg)
// record the new state received
traffic_light_states_[curr_intersection.id.id][current_movement_state.signal_group].push_back(std::make_pair(min_end_time,
- static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state)));
+ static_cast(current_movement_state.movement_event_list[0].event_state.movement_phase_state)));
}
}
}
diff --git a/carma_wm/src/SignalizedIntersectionManager.cpp b/carma_wm/src/SignalizedIntersectionManager.cpp
new file mode 100644
index 0000000000..f9a68d9540
--- /dev/null
+++ b/carma_wm/src/SignalizedIntersectionManager.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2021 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include
+#include
+#include
+
+namespace carma_wm
+{
+ void SignalizedIntersectionManager::setTargetFrame(const std::string& target_frame)
+ {
+ target_frame_ = target_frame;
+ }
+
+ void SignalizedIntersectionManager::setMaxLaneWidth(double max_lane_width)
+ {
+ max_lane_width_ = max_lane_width;
+ }
+
+ void SignalizedIntersectionManager::convertLaneToLaneletId(std::unordered_map& entry, std::unordered_map& exit, const cav_msgs::IntersectionGeometry& intersection,
+ const std::shared_ptr& map, std::shared_ptr current_routing_graph)
+ {
+ std::unordered_map> signal_group_to_exit_lanes;
+ std::unordered_map> signal_group_to_entry_lanes;
+
+ if (target_frame_ == "")
+ {
+ throw std::invalid_argument("Map is not initialized yet as the georeference was not found...");
+ }
+
+ lanelet::projection::LocalFrameProjector local_projector(target_frame_.c_str());
+
+ lanelet::GPSPoint gps_point;
+ gps_point.lat = intersection.ref_point.latitude;
+ gps_point.lon = intersection.ref_point.longitude;
+ gps_point.ele = intersection.ref_point.elevation;
+
+ auto ref_node = local_projector.forward(gps_point);
+
+ ROS_DEBUG_STREAM("Reference node in map frame x: " << ref_node.x() << ", y: " << ref_node.y());
+
+ std::vector node_list;
+
+ for (auto lane : intersection.lane_list)
+ {
+ double curr_x = ref_node.x();
+ double curr_y = ref_node.y();
+
+ ROS_DEBUG_STREAM("Processing Lane id: " << (int)lane.lane_id);
+
+ size_t min_number_of_points = 2; // only two points are sufficient to get corresponding lanelets
+
+ if (lane.node_list.nodes.node_set_xy.size() < min_number_of_points)
+ {
+ ROS_WARN_STREAM("Not enough points are provided to match a lane. Skipping... ");
+ continue;
+ }
+
+ for (size_t i = 0; i < min_number_of_points; i ++ )
+ {
+ curr_x = lane.node_list.nodes.node_set_xy[i].delta.x + curr_x;
+ curr_y = lane.node_list.nodes.node_set_xy[i].delta.y + curr_y;
+ lanelet::Point3d curr_node{map->pointLayer.uniqueId(), curr_x, curr_y, 0};
+
+ ROS_DEBUG_STREAM("Current node x: " << curr_x << ", y: " << curr_y);
+
+ node_list.push_back(curr_node);
+ }
+
+ for (auto node : node_list)
+ {
+ ROS_ERROR_STREAM("x: " << node.x() << ", y: " << node.y());
+ }
+
+ // save which signal group connect to which exit lanes
+ for (auto connection : lane.connect_to_list)
+ {
+ signal_group_to_exit_lanes[connection.signal_group].emplace(connection.connecting_lane.lane);
+
+ if (lane.lane_attributes.directional_use.lane_direction == LANE_DIRECTION::INGRESS)
+ signal_group_to_entry_lanes[connection.signal_group].emplace(lane.lane_id);
+ }
+
+ // query corresponding lanelet lane from local map
+ auto affected_llts = carma_wm::query::getAffectedLaneletOrAreas(node_list, map, current_routing_graph, max_lane_width_);
+
+ if (affected_llts.empty())
+ {
+ throw std::invalid_argument("Given offset points are not inside the map...");
+ }
+
+ lanelet::Id corresponding_lanelet_id = affected_llts.front().id();
+
+ ROS_DEBUG_STREAM("Found existing lanelet id: " << corresponding_lanelet_id);
+
+ if (lane.lane_attributes.directional_use.lane_direction == LANE_DIRECTION::INGRESS)
+ {
+ ROS_DEBUG_STREAM("Detected INGRESS, " << (int)lane.lane_id);
+ entry[lane.lane_id] = corresponding_lanelet_id;
+ }
+ else if (lane.lane_attributes.directional_use.lane_direction == LANE_DIRECTION::EGRESS)
+ {
+ ROS_DEBUG_STREAM("Detected EGRESS, " << (int)lane.lane_id);
+ exit[lane.lane_id] = corresponding_lanelet_id;
+ }
+ // ignoring types that are neither ingress nor egress
+
+ node_list = {};
+ }
+
+ // convert and save exit lane ids into lanelet ids with their corresponding signal group ids
+ for (auto iter = signal_group_to_exit_lanes.begin(); iter != signal_group_to_exit_lanes.end(); iter++)
+ {
+ for (auto exit_lane : iter->second)
+ {
+ if (exit.find(exit_lane) != exit.end())
+ {
+ ROS_DEBUG_STREAM("Adding exit_lane id: " << exit_lane);
+ signal_group_to_exit_lanelet_ids_[iter->first].insert(exit[exit_lane]);
+ }
+ else
+ {
+ throw std::invalid_argument(std::string("Unable to convert exit lane Id: " + std::to_string((int)exit_lane) + ", to lanelet id using the given MAP.msg!").c_str());
+ }
+ }
+ }
+
+ // convert and save entry lane ids into lanelet ids with their corresponding signal group ids
+ for (auto iter = signal_group_to_entry_lanes.begin(); iter != signal_group_to_entry_lanes.end(); iter++)
+ {
+ for (auto entry_lane : iter->second)
+ {
+ ROS_DEBUG_STREAM("Adding entry_lane id: " << entry_lane);
+ if (entry.find(entry_lane) != entry.end())
+ {
+ signal_group_to_entry_lanelet_ids_[iter->first].insert(entry[entry_lane]);
+ }
+ else
+ {
+ throw std::invalid_argument(std::string("Unable to convert entry lane Id: " + std::to_string((int)entry_lane) + ", to lanelet id using the given MAP.msg!").c_str());
+ }
+ }
+ }
+ }
+
+ lanelet::Id SignalizedIntersectionManager::matchSignalizedIntersection(const lanelet::Lanelets& entry_llts, const lanelet::Lanelets& exit_llts, const std::shared_ptr& map)
+ {
+ lanelet::Id matching_id = lanelet::InvalId;
+
+ std::vector existing_si;
+
+ for (auto llt : entry_llts)
+ {
+ auto intersections = llt.regulatoryElementsAs();
+
+ if (intersections.empty())
+ {
+ // no match if any of the entry lanelet is not part of any intersection.
+ break;
+ }
+ existing_si.insert(existing_si.end(), intersections.begin(),intersections.end());
+ }
+
+ for (auto intersection : existing_si)
+ {
+ auto existing_entry_llts = intersection->getEntryLanelets();
+ auto existing_exit_llts = intersection->getExitLanelets();
+
+ if (existing_exit_llts.size() != exit_llts.size() || existing_entry_llts.size() != entry_llts.size())
+ continue;
+
+ bool is_different = false;
+
+ for (auto llt: existing_entry_llts)
+ {
+ if (std::find(entry_llts.begin(), entry_llts.end(), llt) == entry_llts.end())
+ {
+ is_different = true;
+
+ break;
+ }
+ }
+
+ for (auto llt: existing_exit_llts)
+ {
+ if (std::find(exit_llts.begin(), exit_llts.end(), llt) == exit_llts.end())
+ {
+ is_different = true;
+
+ break;
+ }
+ }
+
+ if (!is_different)
+ {
+ // found a match
+ matching_id = intersection->id();
+
+ break;
+ }
+
+ }
+
+ return matching_id;
+ }
+
+ std::shared_ptr SignalizedIntersectionManager::createTrafficSignalUsingSGID(uint8_t signal_group_id, const lanelet::Lanelets& entry_lanelets, const lanelet::Lanelets& exit_lanelets)
+ {
+ std::vector stop_lines;
+ for (auto llt : entry_lanelets)
+ {
+ std::vector points;
+ points.push_back(lanelet::Point3d(lanelet::utils::getId(), llt.leftBound2d().back().x(), llt.leftBound2d().back().y(), 0));
+ points.push_back(lanelet::Point3d(lanelet::utils::getId(), llt.rightBound().back().x(), llt.rightBound().back().y(), 0));
+ lanelet::LineString3d stop_line(lanelet::utils::getId(), points);
+ stop_lines.push_back(stop_line);
+ }
+
+ lanelet::Id traffic_light_id = lanelet::utils::getId();
+ std::shared_ptr traffic_light(new lanelet::CarmaTrafficSignal(lanelet::CarmaTrafficSignal::buildData(traffic_light_id, stop_lines, entry_lanelets, exit_lanelets)));
+ signal_group_to_traffic_light_id_[signal_group_id] = traffic_light_id;
+
+ for (auto llt : exit_lanelets)
+ {
+ signal_group_to_exit_lanelet_ids_[signal_group_id].insert(llt.id());
+ }
+ for (auto llt : entry_lanelets)
+ {
+ signal_group_to_entry_lanelet_ids_[signal_group_id].insert(llt.id());
+ }
+ return traffic_light;
+ }
+
+ void SignalizedIntersectionManager::createIntersectionFromMapMsg(std::vector& sig_intersections, std::vector& traffic_signals, const cav_msgs::MapData& map_msg,
+ const std::shared_ptr& map, std::shared_ptr