Skip to content

Commit 56fc052

Browse files
authored
Fix the skipped cycles of controllers running at different rate (#2557)
1 parent d77582e commit 56fc052

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

controller_manager/src/controller_manager.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,16 +2964,16 @@ controller_interface::return_type ControllerManager::update(
29642964
const auto controller_actual_period =
29652965
(current_time - *loaded_controller.last_update_cycle_time);
29662966

2967-
/// @note The factor 0.99 is used to avoid the controllers skipping update cycles due to the
2968-
/// jitter in the system sleep cycles.
2969-
// For instance, A controller running at 50 Hz and the CM running at 100Hz, then when we have
2970-
// an update cycle at 0.019s (ideally, the controller should only trigger >= 0.02s), if we
2971-
// wait for next cycle, then trigger will happen at ~0.029 sec and this is creating an issue
2972-
// to keep up with the controller update rate (see issue #1769).
2967+
const double error_now =
2968+
std::abs((controller_actual_period.seconds() * controller_update_rate) - 1.0);
2969+
const double error_if_skipped = std::abs(
2970+
((controller_actual_period.seconds() + (1.0 / static_cast<double>(update_rate_))) *
2971+
controller_update_rate) -
2972+
1.0);
29732973
const bool controller_go =
29742974
run_controller_at_cm_rate ||
29752975
(time == rclcpp::Time(0, 0, this->get_trigger_clock()->get_clock_type())) ||
2976-
(controller_actual_period.seconds() * controller_update_rate >= 0.99) || first_update_cycle;
2976+
(error_now <= error_if_skipped) || first_update_cycle;
29772977

29782978
RCLCPP_DEBUG(
29792979
get_logger(), "update_loop_counter: '%d ' controller_go: '%s ' controller_name: '%s '",

controller_manager/test/test_controller_manager.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -920,11 +920,11 @@ TEST_P(TestControllerManagerWithUpdateRates, per_controller_equal_and_higher_upd
920920
EXPECT_THAT(
921921
cm_->get_loaded_controllers()[0].periodicity_statistics->get_average(),
922922
testing::AllOf(
923-
testing::Ge(0.90 * cm_->get_update_rate()), testing::Lt((1.05 * cm_->get_update_rate()))));
923+
testing::Ge(0.9 * cm_->get_update_rate()), testing::Lt((1.05 * cm_->get_update_rate()))));
924924
EXPECT_THAT(
925925
cm_->get_loaded_controllers()[0].periodicity_statistics->get_min(),
926926
testing::AllOf(
927-
testing::Ge(0.70 * cm_->get_update_rate()), testing::Lt((1.2 * cm_->get_update_rate()))));
927+
testing::Ge(0.5 * cm_->get_update_rate()), testing::Lt((1.2 * cm_->get_update_rate()))));
928928
EXPECT_THAT(
929929
cm_->get_loaded_controllers()[0].periodicity_statistics->get_max(),
930930
testing::AllOf(
@@ -1031,12 +1031,14 @@ TEST_P(TestControllerUpdateRates, check_the_controller_update_rate)
10311031
const auto cm_update_rate = cm_->get_update_rate();
10321032
const auto controller_update_rate = test_controller->get_update_rate();
10331033
const double controller_period = 1.0 / controller_update_rate;
1034+
const double exp_controller_period =
1035+
std::round((static_cast<double>(cm_update_rate) / controller_update_rate) - 0.01) /
1036+
cm_update_rate;
10341037

10351038
const auto initial_counter = test_controller->internal_counter;
10361039
// don't start with zero to check if the period is correct if controller is activated anytime
10371040
rclcpp::Time time = time_;
1038-
const auto exp_periodicity =
1039-
cm_update_rate / std::ceil(static_cast<double>(cm_update_rate) / controller_update_rate);
1041+
const auto exp_periodicity = 1.0 / exp_controller_period;
10401042
for (size_t update_counter = 0; update_counter <= 10 * cm_update_rate; ++update_counter)
10411043
{
10421044
rclcpp::Time old_time = time;
@@ -1053,10 +1055,11 @@ TEST_P(TestControllerUpdateRates, check_the_controller_update_rate)
10531055
EXPECT_THAT(
10541056
test_controller->update_period_.seconds(),
10551057
testing::AllOf(
1056-
testing::Gt(0.99 * controller_period),
1057-
testing::Lt((1.2 * controller_period) + PERIOD.seconds())))
1058+
testing::Gt(0.99 * exp_controller_period),
1059+
testing::Lt((1.2 * exp_controller_period) + PERIOD.seconds())))
10581060
<< "update_counter: " << update_counter
10591061
<< " desired controller period: " << controller_period
1062+
<< " expected controller period: " << exp_controller_period
10601063
<< " actual controller period: " << test_controller->update_period_.seconds();
10611064
}
10621065
else
@@ -1092,10 +1095,10 @@ TEST_P(TestControllerUpdateRates, check_the_controller_update_rate)
10921095
<< "The first update is not counted in periodicity statistics";
10931096
EXPECT_THAT(
10941097
cm_->get_loaded_controllers()[0].periodicity_statistics->get_average(),
1095-
testing::AllOf(testing::Ge(0.92 * exp_periodicity), testing::Lt((1.05 * exp_periodicity))));
1098+
testing::AllOf(testing::Ge(0.9 * exp_periodicity), testing::Lt((1.05 * exp_periodicity))));
10961099
EXPECT_THAT(
10971100
cm_->get_loaded_controllers()[0].periodicity_statistics->get_min(),
1098-
testing::AllOf(testing::Ge(0.75 * exp_periodicity), testing::Lt((1.2 * exp_periodicity))));
1101+
testing::AllOf(testing::Ge(0.5 * exp_periodicity), testing::Lt((1.2 * exp_periodicity))));
10991102
EXPECT_THAT(
11001103
cm_->get_loaded_controllers()[0].periodicity_statistics->get_max(),
11011104
testing::AllOf(testing::Ge(0.75 * exp_periodicity), testing::Lt((2.0 * exp_periodicity))));
@@ -1178,12 +1181,14 @@ TEST_F(TestAsyncControllerUpdateRates, check_the_async_controller_update_rate_an
11781181
const auto cm_update_rate = cm_->get_update_rate();
11791182
const auto controller_update_rate = test_controller->get_update_rate();
11801183
const double controller_period = 1.0 / controller_update_rate;
1184+
const double exp_controller_period =
1185+
std::round((static_cast<double>(cm_update_rate) / controller_update_rate) - 0.01) /
1186+
cm_update_rate;
11811187

11821188
const auto initial_counter = test_controller->internal_counter;
11831189
// don't start with zero to check if the period is correct if controller is activated anytime
11841190
rclcpp::Time time = time_;
1185-
const auto exp_periodicity =
1186-
cm_update_rate / std::ceil(static_cast<double>(cm_update_rate) / controller_update_rate);
1191+
const auto exp_periodicity = 1.0 / exp_controller_period;
11871192
for (size_t update_counter = 0; update_counter <= 10 * cm_update_rate; ++update_counter)
11881193
{
11891194
rclcpp::Time old_time = time;
@@ -1200,10 +1205,11 @@ TEST_F(TestAsyncControllerUpdateRates, check_the_async_controller_update_rate_an
12001205
EXPECT_THAT(
12011206
test_controller->update_period_.seconds(),
12021207
testing::AllOf(
1203-
testing::Gt(0.99 * controller_period),
1204-
testing::Lt((1.05 * controller_period) + PERIOD.seconds())))
1208+
testing::Gt(0.99 * exp_controller_period),
1209+
testing::Lt((1.05 * exp_controller_period) + PERIOD.seconds())))
12051210
<< "update_counter: " << update_counter
12061211
<< " desired controller period: " << controller_period
1212+
<< " expected controller period: " << exp_controller_period
12071213
<< " actual controller period: " << test_controller->update_period_.seconds();
12081214
}
12091215
// else

0 commit comments

Comments
 (0)