Skip to content

Commit 1b8cacf

Browse files
time_until_next_call returns max if timer is canceled. (#910)
* time_until_next_call returns None if timer is canceled. Signed-off-by: Tomoya Fujita <[email protected]> Co-Authored-By: Ivan Santiago Paunovic <[email protected]>
1 parent 12f3698 commit 1b8cacf

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

rclpy/src/rclpy/timer.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,13 @@ void Timer::change_timer_period(int64_t period_nsec)
105105
}
106106
}
107107

108-
int64_t Timer::time_until_next_call()
108+
std::optional<int64_t> Timer::time_until_next_call()
109109
{
110110
int64_t remaining_time;
111111
rcl_ret_t ret = rcl_timer_get_time_until_next_call(rcl_timer_.get(), &remaining_time);
112-
if (ret != RCL_RET_OK) {
112+
if (ret == RCL_RET_TIMER_CANCELED) {
113+
return std::nullopt;
114+
} else if (ret != RCL_RET_OK) {
113115
throw RCLError("failed to get time until next timer call");
114116
}
115117

rclpy/src/rclpy/timer.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define RCLPY__TIMER_HPP_
1717

1818
#include <pybind11/pybind11.h>
19+
#include <pybind11/stl.h>
1920

2021
#include <rcl/timer.h>
2122

@@ -87,9 +88,10 @@ class Timer : public Destroyable, public std::enable_shared_from_this<Timer>
8788
*
8889
* Raises RCLError there is an rcl error
8990
*
90-
* \return the time until next call in nanoseconds
91+
* \return the time until next call in nanoseconds.
92+
* std::nullopt if the timer is canceled.
9193
*/
92-
int64_t time_until_next_call();
94+
std::optional<int64_t> time_until_next_call();
9395

9496
/// Get the time since the timer has been called
9597
/**

rclpy/test/test_timer.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import pytest
2020
import rclpy
21+
from rclpy.constants import S_TO_NS
2122
from rclpy.executors import SingleThreadedExecutor
2223

2324

@@ -49,7 +50,7 @@ def test_zero_callback(period):
4950
executor = SingleThreadedExecutor(context=context)
5051
try:
5152
executor.add_node(node)
52-
# The first spin_once() takes long enough for 1ms timer tests to fail
53+
# The first spin_once() takes long enough for 1ms timer tests to fail
5354
executor.spin_once(timeout_sec=0)
5455

5556
callbacks = []
@@ -78,7 +79,7 @@ def test_number_callbacks(period):
7879
executor = SingleThreadedExecutor(context=context)
7980
try:
8081
executor.add_node(node)
81-
# The first spin_once() takes long enough for 1ms timer tests to fail
82+
# The first spin_once() takes long enough for 1ms timer tests to fail
8283
executor.spin_once(timeout_sec=0)
8384

8485
callbacks = []
@@ -110,7 +111,7 @@ def test_cancel_reset(period):
110111
executor = SingleThreadedExecutor(context=context)
111112
try:
112113
executor.add_node(node)
113-
# The first spin_once() takes long enough for 1ms timer tests to fail
114+
# The first spin_once() takes long enough for 1ms timer tests to fail
114115
executor.spin_once(timeout_sec=0)
115116

116117
callbacks = []
@@ -148,3 +149,34 @@ def test_cancel_reset(period):
148149
node.destroy_node()
149150
finally:
150151
rclpy.shutdown(context=context)
152+
153+
154+
def test_time_until_next_call():
155+
node = None
156+
executor = None
157+
timer = None
158+
context = rclpy.context.Context()
159+
rclpy.init(context=context)
160+
try:
161+
node = rclpy.create_node('test_time_until_next_call', context=context)
162+
executor = SingleThreadedExecutor(context=context)
163+
executor.add_node(node)
164+
executor.spin_once(timeout_sec=0)
165+
timer = node.create_timer(1, lambda: None)
166+
assert not timer.is_canceled()
167+
executor.spin_once(0.1)
168+
assert timer.time_until_next_call() <= (1 * S_TO_NS)
169+
timer.reset()
170+
assert not timer.is_canceled()
171+
assert timer.time_until_next_call() <= (1 * S_TO_NS)
172+
timer.cancel()
173+
assert timer.is_canceled()
174+
assert timer.time_until_next_call() is None
175+
finally:
176+
if timer is not None:
177+
node.destroy_timer(timer)
178+
if executor is not None:
179+
executor.shutdown()
180+
if node is not None:
181+
node.destroy_node()
182+
rclpy.shutdown(context=context)

0 commit comments

Comments
 (0)