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.
GeofenceScheduler.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
18
19namespace carma_wm_ctrl
20{
21using std::placeholders::_1;
22
23GeofenceScheduler::GeofenceScheduler(std::shared_ptr<TimerFactory> timerFactory)
24 : timerFactory_(timerFactory)
25{
26 // Create repeating loop to clear geofence timers which are no longer needed
28 timerFactory_->buildTimer(nextId(), rclcpp::Duration(1), std::bind(&GeofenceScheduler::clearTimers, this));
29 clock_type_ = timerFactory_->now().get_clock_type();
30}
31
33{
34 return timerFactory_->now();
35}
36
38{
39 next_id_++;
40 return next_id_;
41}
42
44{
45 return clock_type_;
46}
47
49{
50 std::lock_guard<std::mutex> guard(mutex_);
51 auto it = timers_.begin();
52
53 // Erase all expired timers_ using iterators to ensure operation is safe
54 while (it != timers_.end())
55 {
56 // Check if timer is marked for deletion
57 if (it->second.second)
58 {
59 // erase() function returns the iterator of the next
60 // to last deleted element.
61 it = timers_.erase(it);
62 }
63 else
64 {
65 it++;
66 }
67 }
68}
69
70void GeofenceScheduler::addGeofence(std::shared_ptr<Geofence> gf_ptr)
71{
72 std::lock_guard<std::mutex> guard(mutex_);
73
74 RCLCPP_INFO_STREAM(rclcpp::get_logger("carma_wm_ctrl"), "Attempting to add Geofence with Id: " << gf_ptr->id_);
75
76 // Create timer for next start time
77 for (size_t schedule_idx = 0; schedule_idx < gf_ptr->schedules.size(); schedule_idx++)
78 {
79 // resolve clock type
80 auto interval_info = gf_ptr->schedules[schedule_idx].getNextInterval(timerFactory_->now());
81 rclcpp::Time startTime = interval_info.second;
82
83 if (!interval_info.first && startTime == rclcpp::Time(0, 0, clock_type_))
84 {
85 RCLCPP_WARN_STREAM(rclcpp::get_logger("carma_wm_ctrl"),
86 "Failed to add geofence as its schedule did not contain an active or upcoming control period. GF Id: "
87 << gf_ptr->id_);
88 return;
89 }
90 // If this geofence is currently active set the start time to now
91 if (interval_info.first)
92 {
93 startTime = timerFactory_->now();
94 }
95
96 int32_t timer_id = nextId();
97
98 rclcpp::Duration control_duration = rclcpp::Duration(std::max((startTime - timerFactory_->now()).seconds() * 1e9, 0.0)); //guard for negative value
99
100 // Build timer to trigger when this geofence becomes active
101 TimerPtr timer = timerFactory_->buildTimer(
102 timer_id, control_duration,
103 std::bind(&GeofenceScheduler::startGeofenceCallback, this, gf_ptr, schedule_idx, timer_id), true, true);
104
105 timers_[timer_id] = std::make_pair(std::move(timer), false); // Add start timer to map by Id
106 }
107
108}
109
110void GeofenceScheduler::startGeofenceCallback(std::shared_ptr<Geofence> gf_ptr, const unsigned int schedule_id, const int32_t timer_id)
111{
112 std::lock_guard<std::mutex> guard(mutex_);
113 rclcpp::Time endTime = timerFactory_->now() + gf_ptr->schedules[schedule_id].control_span_;
114
115 RCLCPP_INFO_STREAM(rclcpp::get_logger("carma_wm_ctrl"), "Activating Geofence with Id: " << gf_ptr->id_ << ", which will end at:" << endTime.seconds());
116
117 active_callback_(gf_ptr);
118
119 // Build timer to trigger when this geofence becomes inactive
120 int32_t ending_timer_id = nextId();
121
122 rclcpp::Duration control_duration = rclcpp::Duration(std::max((endTime - timerFactory_->now()).seconds() * 1e9, 0.0)); //guard for negative value
123
124 TimerPtr timer = timerFactory_->buildTimer(
125 ending_timer_id, control_duration,
126 std::bind(&GeofenceScheduler::endGeofenceCallback, this, gf_ptr, schedule_id, ending_timer_id), true, true);
127 timers_[ending_timer_id] = std::make_pair(std::move(timer), false); // Add end timer to map by Id
128
129 timers_[timer_id].second = true; // Mark start timer for deletion
130}
131
132void GeofenceScheduler::endGeofenceCallback(std::shared_ptr<Geofence> gf_ptr, const unsigned int schedule_id, const int32_t timer_id)
133{
134 std::lock_guard<std::mutex> guard(mutex_);
135
136 RCLCPP_INFO_STREAM(rclcpp::get_logger("carma_wm_ctrl"), "Deactivating Geofence with Id: " << gf_ptr->id_);
137
138 inactive_callback_(gf_ptr);
139 timers_[timer_id].second = true; // Mark timer for deletion
140
141 // Determine if a new timer is needed for this geofence
142 auto interval_info = gf_ptr->schedules[schedule_id].getNextInterval(timerFactory_->now());
143 rclcpp::Time startTime = interval_info.second;
144
145 // If this geofence should currently be active set the start time to now
146 if (interval_info.first)
147 {
148 startTime = timerFactory_->now();
149 }
150
151 if (!interval_info.first && startTime == rclcpp::Time(0, 0, clock_type_))
152 {
153 // No more active periods for this geofence so return
154 return;
155 }
156
157 // Build timer to trigger when this geofence becomes active
158 int32_t start_timer_id = nextId();
159
160 rclcpp::Duration control_duration = rclcpp::Duration(std::max((startTime - timerFactory_->now()).seconds() * 1e9, 0.0)); //guard for negative value
161
162 TimerPtr timer = timerFactory_->buildTimer(
163 start_timer_id, control_duration,
164 std::bind(&GeofenceScheduler::startGeofenceCallback, this, gf_ptr, schedule_id, start_timer_id), true, true);
165
166 timers_[start_timer_id] = std::make_pair(std::move(timer), false); // Add start timer to map by Id
167}
168
169void GeofenceScheduler::onGeofenceActive(std::function<void(std::shared_ptr<Geofence>)> active_callback)
170{
171 std::lock_guard<std::mutex> guard(mutex_);
172 active_callback_ = active_callback;
173}
174
175void GeofenceScheduler::onGeofenceInactive(std::function<void(std::shared_ptr<Geofence>)> inactive_callback)
176{
177 std::lock_guard<std::mutex> guard(mutex_);
178 inactive_callback_ = inactive_callback;
179}
180} // namespace carma_wm_ctrl
void onGeofenceActive(std::function< void(std::shared_ptr< Geofence >)> active_callback)
Method which allows the user to set a callback which will be triggered when a geofence becomes active...
void endGeofenceCallback(std::shared_ptr< Geofence > gf_ptr, const unsigned int schedule_id, const int32_t timer_id)
The callback which is triggered when a geofence becomes in-active This will call the user set inactiv...
std::unique_ptr< Timer > TimerPtr
rcl_clock_type_t getClockType()
Get the clock type of the clock being created by the timer factory.
GeofenceScheduler(std::shared_ptr< TimerFactory > timerFactory)
Constructor which takes in a TimerFactory. Timers from this factory will be used to generate the trig...
std::function< void(std::shared_ptr< Geofence >)> active_callback_
rclcpp::Time now()
Get current time used by scheduler.
void startGeofenceCallback(std::shared_ptr< Geofence > gf_ptr, const unsigned int schedule_id, const int32_t timer_id)
The callback which is triggered when a geofence becomes active This will call the user set active_cal...
uint32_t nextId()
Generates the next id to be used for a timer.
std::unique_ptr< Timer > deletion_timer_
std::function< void(std::shared_ptr< Geofence >)> inactive_callback_
void addGeofence(std::shared_ptr< Geofence > gf_ptr)
Add a geofence to the scheduler. This will cause it to trigger an event when it becomes active or goe...
void onGeofenceInactive(std::function< void(std::shared_ptr< Geofence >)> inactive_callback)
Method which allows the user to set a callback which will be triggered when a geofence becomes in-act...
std::unordered_map< uint32_t, std::pair< TimerPtr, bool > > timers_
std::shared_ptr< TimerFactory > timerFactory_
void clearTimers()
Clears the expired timers from the memory of this scheduler.