|
19 | 19 | #include <thread> |
20 | 20 |
|
21 | 21 | #include "controller_manager/controller_manager.hpp" |
| 22 | +#include "controller_manager/sleeping_policies.hpp" |
22 | 23 | #include "rclcpp/executors.hpp" |
23 | 24 | #include "realtime_tools/realtime_helpers.hpp" |
24 | 25 |
|
@@ -79,8 +80,20 @@ int main(int argc, char ** argv) |
79 | 80 | cm->get_logger(), "Spawning %s RT thread with scheduler priority: %d", cm->get_name(), |
80 | 81 | thread_priority); |
81 | 82 |
|
| 83 | + const controller_manager::ControlLoopTimingConfig timing_config{ |
| 84 | + .use_sim_time = use_sim_time, |
| 85 | + .manage_overruns = manage_overruns, |
| 86 | + .expect_blocking_read_write = |
| 87 | + cm->get_parameter_or<bool>("hardware_synchronization.expect_blocking_read_write", false), |
| 88 | + .minimum_cycle_time = |
| 89 | + cm->get_parameter_or<double>("hardware_synchronization.minimum_cycle_time", 0.0001), |
| 90 | + }; |
| 91 | + RCLCPP_INFO_EXPRESSION( |
| 92 | + cm->get_logger(), timing_config.expect_blocking_read_write, |
| 93 | + "Synchronizing control loop with hardware."); |
| 94 | + |
82 | 95 | std::thread cm_thread( |
83 | | - [cm, thread_priority, use_sim_time, manage_overruns]() |
| 96 | + [cm, thread_priority, timing_config]() |
84 | 97 | { |
85 | 98 | rclcpp::Parameter cpu_affinity_param; |
86 | 99 | if (cm->get_parameter("cpu_affinity", cpu_affinity_param)) |
@@ -124,63 +137,39 @@ int main(int argc, char ** argv) |
124 | 137 | cm->get_clock()->wait_until_started(); |
125 | 138 | cm->get_clock()->sleep_for(rclcpp::Duration::from_seconds(1.0 / cm->get_update_rate())); |
126 | 139 |
|
127 | | - // for calculating sleep time |
128 | | - auto const period = std::chrono::nanoseconds(1'000'000'000 / cm->get_update_rate()); |
129 | | - |
130 | | - // for calculating the measured period of the loop |
131 | | - rclcpp::Time previous_time = cm->get_trigger_clock()->now(); |
132 | | - std::this_thread::sleep_for(period); |
133 | | - |
134 | | - std::chrono::steady_clock::time_point next_iteration_time{std::chrono::steady_clock::now()}; |
135 | | - |
| 140 | + controller_manager::ControlLoopState state; |
| 141 | + state.period = std::chrono::nanoseconds(1'000'000'000 / cm->get_update_rate()); |
| 142 | + state.previous_time = cm->get_trigger_clock()->now(); |
| 143 | + std::this_thread::sleep_for(state.period); |
| 144 | + state.next_iteration_time = std::chrono::steady_clock::now(); |
136 | 145 | while (rclcpp::ok()) |
137 | 146 | { |
138 | 147 | // calculate measured period |
139 | 148 | auto const current_time = cm->get_trigger_clock()->now(); |
140 | | - auto const measured_period = current_time - previous_time; |
141 | | - previous_time = current_time; |
| 149 | + auto const measured_period = current_time - state.previous_time; |
| 150 | + state.previous_time = current_time; |
142 | 151 |
|
143 | 152 | // execute update loop |
144 | 153 | cm->read(cm->get_trigger_clock()->now(), measured_period); |
145 | 154 | cm->update(cm->get_trigger_clock()->now(), measured_period); |
146 | 155 | cm->write(cm->get_trigger_clock()->now(), measured_period); |
| 156 | + state.cycle_end_time = cm->get_trigger_clock()->now(); |
147 | 157 |
|
148 | 158 | // wait until we hit the end of the period |
149 | | - if (use_sim_time) |
| 159 | + if (timing_config.use_sim_time) |
150 | 160 | { |
151 | | - try |
152 | | - { |
153 | | - cm->get_clock()->sleep_until(current_time + period); |
154 | | - } |
155 | | - catch (const std::runtime_error & e) |
| 161 | + if (!sleep_for_sim_time(cm, state)) |
156 | 162 | { |
157 | | - RCLCPP_ERROR( |
158 | | - cm->get_logger(), |
159 | | - "sleep_until failed with error: %s. Exiting control loop and aborting....", e.what()); |
160 | 163 | break; |
161 | 164 | } |
162 | 165 | } |
| 166 | + else if (timing_config.expect_blocking_read_write) |
| 167 | + { |
| 168 | + sleep_for_blocking_read_write(cm, timing_config, state); |
| 169 | + } |
163 | 170 | else |
164 | 171 | { |
165 | | - next_iteration_time += period; |
166 | | - const auto time_now = std::chrono::steady_clock::now(); |
167 | | - if (manage_overruns && next_iteration_time < time_now) |
168 | | - { |
169 | | - const double time_diff = |
170 | | - static_cast<double>( |
171 | | - std::chrono::duration_cast<std::chrono::nanoseconds>(time_now - next_iteration_time) |
172 | | - .count()) / |
173 | | - 1.e6; |
174 | | - const double cm_period = 1.e3 / static_cast<double>(cm->get_update_rate()); |
175 | | - const int overrun_count = static_cast<int>(std::ceil(time_diff / cm_period)); |
176 | | - RCLCPP_WARN_THROTTLE( |
177 | | - cm->get_logger(), *cm->get_clock(), 1000, |
178 | | - "Overrun detected! The controller manager missed its desired rate of %d Hz. The loop " |
179 | | - "took %f ms (missed cycles : %d).", |
180 | | - cm->get_update_rate(), time_diff + cm_period, overrun_count + 1); |
181 | | - next_iteration_time += (overrun_count * period); |
182 | | - } |
183 | | - std::this_thread::sleep_until(next_iteration_time); |
| 172 | + sleep_for_periodic_cycle(cm, timing_config, state); |
184 | 173 | } |
185 | 174 | } |
186 | 175 | }); |
|
0 commit comments