Skip to content

Commit c1b59b5

Browse files
committed
Create ROSClock specialization
1 parent 69a98ca commit c1b59b5

4 files changed

Lines changed: 45 additions & 21 deletions

File tree

rclpy/rclpy/clock.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,36 @@ def __init__(self, *, clock_type=ClockType.SYSTEM_TIME):
4141
def clock_type(self):
4242
return self._clock_type
4343

44+
def __repr__(self):
45+
return 'Clock(clock_type={0})'.format(self.clock_type.name)
46+
47+
def now(self):
48+
from rclpy.time import Time
49+
time_handle = _rclpy.rclpy_clock_get_now(self._clock_handle)
50+
# TODO(dhood): Return a python object from the C extension
51+
return Time(
52+
nanoseconds=_rclpy.rclpy_time_point_get_nanoseconds(time_handle),
53+
clock_type=self.clock_type)
54+
55+
56+
class ROSClock(Clock):
57+
58+
def __init__(self):
59+
super(ROSClock, self).__init__(clock_type=ClockType.ROS_TIME)
60+
4461
@property
4562
def ros_time_is_active(self):
46-
# TODO(dhood): Move to ROS_TIME-specific subclass?
4763
if self.clock_type != ClockType.ROS_TIME:
4864
raise RuntimeError('Only valid for clocks using ROS_TIME')
4965
return _rclpy.rclpy_clock_get_ros_time_override_is_enabled(self._clock_handle)
5066

5167
def _set_ros_time_is_active(self, enabled):
5268
# This is not public because it is only to be called by a TimeSource managing the Clock
53-
# TODO(dhood): Move to ROS_TIME-specific subclass?
5469
if self.clock_type != ClockType.ROS_TIME:
5570
raise RuntimeError('Only valid for clocks using ROS_TIME')
5671
_rclpy.rclpy_clock_set_ros_time_override_is_enabled(self._clock_handle, enabled)
5772

58-
def __repr__(self):
59-
return 'Clock(clock_type={0})'.format(self.clock_type.name)
60-
61-
def now(self):
62-
from rclpy.time import Time
63-
time_handle = _rclpy.rclpy_clock_get_now(self._clock_handle)
64-
# TODO(dhood): Return a python object from the C extension
65-
return Time(
66-
nanoseconds=_rclpy.rclpy_time_point_get_nanoseconds(time_handle),
67-
clock_type=self.clock_type)
68-
6973
def set_ros_time_override(self, time):
70-
# TODO(dhood): Move to ROS_TIME-specific subclass?
7174
from rclpy.time import Time
7275
if self.clock_type != ClockType.ROS_TIME:
7376
raise RuntimeError('Only valid for clocks using ROS_TIME')

rclpy/rclpy/node.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
1616
from rclpy.client import Client
17-
from rclpy.clock import Clock
18-
from rclpy.clock import ClockType
17+
from rclpy.clock import ROSClock
1918
from rclpy.constants import S_TO_NS
2019
from rclpy.exceptions import NotInitializedException
2120
from rclpy.exceptions import NoTypeSupportImportedException
@@ -83,8 +82,9 @@ def __init__(self, node_name, *, cli_args=None, namespace=None, use_global_argum
8382
raise RuntimeError('rclpy_create_node failed for unknown reason')
8483
self._logger = get_logger(_rclpy.rclpy_get_node_logger_name(self.handle))
8584

86-
# Clock that has support for ROS time (uses sim time if parameter has been set on the node)
87-
self._clock = Clock(clock_type=ClockType.ROS_TIME)
85+
# Clock that has support for ROS time.
86+
# TODO(dhood): use sim time if parameter has been set on the node.
87+
self._clock = ROSClock()
8888
self._time_source = TimeSource(node=self)
8989
self._time_source.attach_clock(self._clock)
9090

rclpy/rclpy/time_source.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import builtin_interfaces.msg
1616
from rclpy.clock import Clock
1717
from rclpy.clock import ClockType
18+
from rclpy.clock import ROSClock
1819
from rclpy.time import Time
1920

2021
CLOCK_TOPIC = '/clock'
@@ -76,6 +77,8 @@ def attach_clock(self, clock):
7677
raise TypeError('Clock must be of type rclpy.clock.Clock')
7778
if not clock.clock_type == ClockType.ROS_TIME:
7879
raise ValueError('Only clocks with type ROS_TIME can be attached.')
80+
# "Cast" to ROSClock subclass so ROS time methods can be used.
81+
clock.__class__ = ROSClock
7982
if self._last_time_set is not None:
8083
self._set_clock(self._last_time_set, clock)
8184
clock._set_ros_time_is_active(self.ros_time_is_active)

rclpy/test/test_time_source.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import rclpy
2020
from rclpy.clock import Clock
2121
from rclpy.clock import ClockType
22+
from rclpy.clock import ROSClock
2223
from rclpy.time import Time
2324
from rclpy.time_source import CLOCK_TOPIC
2425
from rclpy.time_source import TimeSource
@@ -46,9 +47,26 @@ def publish_clock_messages(self):
4647
# TODO(dhood): use rate once available
4748
time.sleep(1)
4849

50+
def test_time_source_attach_clock(self):
51+
time_source = TimeSource(node=self.node)
52+
53+
# ROSClock is a specialization of Clock with ROS time methods.
54+
time_source.attach_clock(ROSClock())
55+
56+
# A clock of type ROS_TIME can be attached. It will be converted to a ROSClock for storage.
57+
time_source.attach_clock(Clock(clock_type=ClockType.ROS_TIME))
58+
59+
assert all((isinstance(clock, ROSClock) for clock in time_source._associated_clocks))
60+
61+
with self.assertRaises(ValueError):
62+
time_source.attach_clock(Clock(clock_type=ClockType.SYSTEM_TIME))
63+
64+
with self.assertRaises(ValueError):
65+
time_source.attach_clock(Clock(clock_type=ClockType.STEADY_TIME))
66+
4967
def test_time_source_not_using_sim_time(self):
5068
time_source = TimeSource(node=self.node)
51-
clock = Clock(clock_type=ClockType.ROS_TIME)
69+
clock = ROSClock()
5270
time_source.attach_clock(clock)
5371

5472
# When not using sim time, ROS time should look like system time
@@ -66,15 +84,15 @@ def test_time_source_not_using_sim_time(self):
6684
# Whether or not an attached clock is using ROS time should be determined by the time
6785
# source managing it.
6886
self.assertFalse(time_source.ros_time_is_active)
69-
clock2 = Clock(clock_type=ClockType.ROS_TIME)
87+
clock2 = ROSClock()
7088
clock2._set_ros_time_is_active(True)
7189
time_source.attach_clock(clock2)
7290
self.assertFalse(clock2.ros_time_is_active)
7391
assert time_source._clock_sub is None
7492

7593
def test_time_source_using_sim_time(self):
7694
time_source = TimeSource(node=self.node)
77-
clock = Clock(clock_type=ClockType.ROS_TIME)
95+
clock = ROSClock()
7896
time_source.attach_clock(clock)
7997

8098
# Setting ROS time active on a time source should also cause attached clocks' use of ROS

0 commit comments

Comments
 (0)