Skip to content

Commit bfbedd2

Browse files
[RM] Fix skipped cycles by adjusting rw_rate handling (#2091)
1 parent ef2b3fc commit bfbedd2

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

hardware_interface/src/resource_manager.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,7 +1792,11 @@ HardwareReadWriteStatus ResourceManager::read(
17921792
component.get_last_read_time().get_clock_type() != RCL_CLOCK_UNINITIALIZED
17931793
? current_time - component.get_last_read_time()
17941794
: rclcpp::Duration::from_seconds(1.0 / static_cast<double>(read_rate));
1795-
if (actual_period.seconds() * read_rate >= 0.99)
1795+
1796+
const double error_now = std::abs(actual_period.seconds() * read_rate - 1.0);
1797+
const double error_if_skipped = std::abs(
1798+
(actual_period.seconds() + 1.0 / resource_storage_->cm_update_rate_) * read_rate - 1.0);
1799+
if (error_now <= error_if_skipped)
17961800
{
17971801
ret_val = component.read(current_time, actual_period);
17981802
}
@@ -1883,7 +1887,12 @@ HardwareReadWriteStatus ResourceManager::write(
18831887
component.get_last_write_time().get_clock_type() != RCL_CLOCK_UNINITIALIZED
18841888
? current_time - component.get_last_write_time()
18851889
: rclcpp::Duration::from_seconds(1.0 / static_cast<double>(write_rate));
1886-
if (actual_period.seconds() * write_rate >= 0.99)
1890+
1891+
const double error_now = std::abs(actual_period.seconds() * write_rate - 1.0);
1892+
const double error_if_skipped = std::abs(
1893+
(actual_period.seconds() + 1.0 / resource_storage_->cm_update_rate_) * write_rate -
1894+
1.0);
1895+
if (error_now <= error_if_skipped)
18871896
{
18881897
ret_val = component.write(current_time, actual_period);
18891898
}

hardware_interface_testing/test/test_resource_manager.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,60 @@ TEST_F(
19561956
check_read_and_write_cycles(false);
19571957
}
19581958

1959+
TEST_F(
1960+
ResourceManagerTestReadWriteDifferentReadWriteRate,
1961+
test_components_with_different_read_write_freq_not_exact_timing)
1962+
{
1963+
setup_resource_manager_and_do_initial_checks();
1964+
1965+
const auto test_jitter = std::chrono::milliseconds{1};
1966+
1967+
const auto read = [&]()
1968+
{
1969+
const auto [ok, failed_hardware_names] = rm->read(time, duration);
1970+
EXPECT_TRUE(ok);
1971+
EXPECT_TRUE(failed_hardware_names.empty());
1972+
};
1973+
const auto write = [&]()
1974+
{
1975+
const auto [ok, failed_hardware_names] = rm->write(time, duration);
1976+
EXPECT_TRUE(ok);
1977+
EXPECT_TRUE(failed_hardware_names.empty());
1978+
};
1979+
1980+
// t = 1 * duration
1981+
// State interface should not update
1982+
read();
1983+
EXPECT_DOUBLE_EQ(state_itfs[0].get_optional().value(), 0.0);
1984+
EXPECT_TRUE(claimed_itfs[0].set_value(10));
1985+
write();
1986+
node_.get_clock()->sleep_until(time + duration + test_jitter);
1987+
time = node_.get_clock()->now();
1988+
1989+
// t = 2 * duration + test_jitter
1990+
// State interface should update
1991+
read();
1992+
EXPECT_DOUBLE_EQ(state_itfs[0].get_optional().value(), 5.0);
1993+
EXPECT_TRUE(claimed_itfs[0].set_value(20));
1994+
write();
1995+
node_.get_clock()->sleep_until(time + duration - test_jitter);
1996+
time = node_.get_clock()->now();
1997+
1998+
// t = 3 * duration
1999+
// State interface should not update
2000+
read();
2001+
EXPECT_DOUBLE_EQ(state_itfs[0].get_optional().value(), 5.0);
2002+
EXPECT_TRUE(claimed_itfs[0].set_value(30));
2003+
write();
2004+
node_.get_clock()->sleep_until(time + duration - test_jitter);
2005+
time = node_.get_clock()->now();
2006+
2007+
// t = 4 * duration - test_jitter
2008+
// State interface should update
2009+
read();
2010+
EXPECT_DOUBLE_EQ(state_itfs[0].get_optional().value(), 15.0);
2011+
}
2012+
19592013
class ResourceManagerTestAsyncReadWrite : public ResourceManagerTest
19602014
{
19612015
public:

0 commit comments

Comments
 (0)