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::from_nanoseconds(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::from_nanoseconds(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"),
116 "Activating Geofence with Id: "
117 << gf_ptr->id_ << ", which will end at:"
118 << std::to_string(endTime.seconds()));
119
120 active_callback_(gf_ptr);
121
122 // Build timer to trigger when this geofence becomes inactive
123 int32_t ending_timer_id = nextId();
124
125 rclcpp::Duration control_duration = rclcpp::Duration::from_nanoseconds(std::max((endTime - timerFactory_->now()).seconds() * 1e9, 0.0)); //guard for negative value
126
127 TimerPtr timer = timerFactory_->buildTimer(
128 ending_timer_id, control_duration,
129 std::bind(&GeofenceScheduler::endGeofenceCallback, this, gf_ptr, schedule_id, ending_timer_id), true, true);
130 timers_[ending_timer_id] = std::make_pair(std::move(timer), false); // Add end timer to map by Id
131
132 timers_[timer_id].second = true; // Mark start timer for deletion
133}
134
135void GeofenceScheduler::endGeofenceCallback(std::shared_ptr<Geofence> gf_ptr, const unsigned int schedule_id, const int32_t timer_id)
136{
137 std::lock_guard<std::mutex> guard(mutex_);
138
139 RCLCPP_INFO_STREAM(rclcpp::get_logger("carma_wm_ctrl"), "Deactivating Geofence with Id: " << gf_ptr->id_);
140
141 inactive_callback_(gf_ptr);
142 timers_[timer_id].second = true; // Mark timer for deletion
143
144 // Determine if a new timer is needed for this geofence
145 auto interval_info = gf_ptr->schedules[schedule_id].getNextInterval(timerFactory_->now());
146 rclcpp::Time startTime = interval_info.second;
147
148 // If this geofence should currently be active set the start time to now
149 if (interval_info.first)
150 {
151 startTime = timerFactory_->now();
152 }
153
154 if (!interval_info.first && startTime == rclcpp::Time(0, 0, clock_type_))
155 {
156 // No more active periods for this geofence so return
157 return;
158 }
159
160 // Build timer to trigger when this geofence becomes active
161 int32_t start_timer_id = nextId();
162
163 rclcpp::Duration control_duration = rclcpp::Duration::from_nanoseconds(std::max((startTime - timerFactory_->now()).seconds() * 1e9, 0.0)); //guard for negative value
164
165 TimerPtr timer = timerFactory_->buildTimer(
166 start_timer_id, control_duration,
167 std::bind(&GeofenceScheduler::startGeofenceCallback, this, gf_ptr, schedule_id, start_timer_id), true, true);
168
169 timers_[start_timer_id] = std::make_pair(std::move(timer), false); // Add start timer to map by Id
170}
171
172void GeofenceScheduler::onGeofenceActive(std::function<void(std::shared_ptr<Geofence>)> active_callback)
173{
174 std::lock_guard<std::mutex> guard(mutex_);
175 active_callback_ = active_callback;
176}
177
178void GeofenceScheduler::onGeofenceInactive(std::function<void(std::shared_ptr<Geofence>)> inactive_callback)
179{
180 std::lock_guard<std::mutex> guard(mutex_);
181 inactive_callback_ = inactive_callback;
182}
183} // 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.
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21