Repository navigation
Add AlignedTimer and AlignedWallTimer for start-time and phase-aligned timers - #3270
thomasmoore16 wants to merge 5 commits into
Conversation
|
This breaks the Events and EventsCBG executor for sure. |
|
Hm, this will actually work, as I use rcl_timer_get_next_call_time in the timer_manager.... |
|
@jmachowinski - the essence of this PR is very simple. The actual meat of the change is the modification of the following line in - atomic_init(&impl.next_call_time, now + period);
+ atomic_init(&impl.next_call_time, initial_call_time);The rest of the change to |
|
Pushed a follow-up commit (5a1e0e4) adding clock-type validation for the new |
|
I have multiple points were I think the design needs some rework. The Interface : Reset uses internally now and moves the timer call point around. For the rcl change, would it not be easier to extend the reset API instead of a new init version ? Calling the existing init wit start false, and afterwards reset with the parameters would also do the trick. The autostart parameter does not make any sense with the current init interface. |
|
The goal is to be able to create a set of timers across a set of ROS2 nodes which fire relative to each other in a deterministic manner. With the current use of The concept of an interval and offset is precisely how we're determining the start time to use for the timer. However, I wanted the interface to be more generic in order to allow for other use cases. We can certainly add both interfaces. I hadn't considered the |
|
After thinking about this some more, I've decided to add a |
|
I am not too sure about the API. What do you think about adding dedicated new Timer classes and change how reset works on them. This would have the advantage that the API is consistent between timers, and it is more in line with how other timers are modeled in rclcpp. E.g. WallTimer vs GenericTimer |
|
We discussed this feature in the client library working group, and the general consensus was that we are all in favor of it. |
Signed-off-by: Thomas Moore <thomas.moore@torc.ai>
Signed-off-by: Thomas Moore <thomas.moore@torc.ai>
WallTimer (and create_wall_timer) always construct their underlying Clock as RCL_STEADY_TIME, but the new initial_call_time overloads accepted a Time of any clock type without checking it. Passing e.g. a ROS-time Time into create_wall_timer silently produced a garbage next_call_time, since rcl treats the value as a bare nanosecond count with no cross-clock conversion. TimerBase's initial_call_time constructor now throws std::runtime_error if initial_call_time's clock type doesn't match the timer's clock, consistent with the existing clock-type-mismatch checks in Time::operator- and Clock::sleep_until. The check is skipped when the clock itself is uninitialized, leaving that case to the existing rcl-level validation. Signed-off-by: Thomas Moore <thomas.moore@torc.ai> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds rclcpp::TimerBase::resume(), a thin wrapper over the new rcl_timer_resume() (see the companion rcl change): unlike reset(), it preserves the timer's existing schedule phase, only catching up if it is overdue rather than unconditionally recomputing from now(). This is what makes autostart=false combined with an explicit initial_call_time actually useful: a timer can be created paused with a specific phase-anchored schedule and later resumed without losing it, which reset() cannot do. Also fixes a gap found while writing this: Node::create_timer( initial_call_time, ...) had no way to pass autostart at all, unlike its create_wall_timer sibling overload, even though the underlying free function already supported it. Adds rclcpp::compute_phase_aligned_time(clock, interval, phase): a small utility to compute the smallest instant >= now() of the form k * interval + phase. This lets independent nodes/processes sharing a synchronized clock agree on the same aligned timer start instants without exchanging an explicit time out-of-band. Renamed the internal call from rcl_timer_init3 to rcl_timer_init_with_start_time to match the companion rcl rename. Signed-off-by: Thomas Moore <thomas.moore@torc.ai> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8e7fa08 to
29589a7
Compare
|
@jmachowinski - I have made the requested changes as well as eliminated the Note that I am no longer with my previous company, so I'm shifting over to using my personal account to wrap up these PRs. Feel free to re-assign the PR to this account. |
Signed-off-by: Thomas Moore <tcm0116@gmail.com>
29589a7 to
182b9a3
Compare
rclcpp: Add AlignedTimer and AlignedWallTimer for start-time and phase-aligned timers
Branch:
timer-initial-call-time(this repo:ros2/rclcpp)Depends on: ros2/rcl#1335 — "Allow specifying an initial timer trigger time" (adds
rcl_timer_init_with_start_timeand preserves phase alignment inrcl_timer_reset). This PR requires that change to be available and should land after it (note: the single-repoRpr__rclcppbuildfarm job will fail until ros2/rcl#1335 is merged and synced into Rolling).Summary
Building on
rcl_timer_init_with_start_timein ros2/rcl#1335 and incorporating feedback from the Client Library Working Group, this adds dedicatedAlignedTimerandAlignedWallTimerclasses (along withcreate_aligned_timer/create_aligned_wall_timerhelpers) that let callers either specify an explicit initial trigger time or align periodic timers to(period, phase)boundaries instead of always starting atnow() + period.Unlike
GenericTimerandWallTimer(whosereset()re-anchors the schedule tonow() + period),AlignedTimerandAlignedWallTimerpreserve their schedule phase acrosscancel()/reset()cycles.Changes
rclcpp::AlignedTimer/rclcpp::AlignedWallTimer: Dedicated timer subclasses initialized viarcl_timer_init_with_start_time, supporting both:(clock, initial_call_time, period, callback, context, autostart)(and the wall-clock equivalent withoutclock), validating thatinitial_call_time's clock type matches the timer's clock, and(clock, period, phase, callback, context, autostart)(and the wall-clock equivalent), computing the initial phase-aligned trigger time automatically.rclcpp::compute_phase_aligned_time(clock, interval, phase): Computes the smallest time>= clock.now()of the formk * interval + phase, allowing independent nodes/processes sharing a synchronized clock to align periodic timers without exchanging a start timestamp out-of-band.rclcpp::create_aligned_timer(...)/rclcpp::create_aligned_wall_timer(...)free functions increate_timer.hppand matchingrclcpp::Node::create_aligned_timer(...)/rclcpp::Node::create_aligned_wall_timer(...)member functions.test_timer.cppandtest_create_timer.cppcoveringAlignedTimer,AlignedWallTimer,create_aligned_timer,create_aligned_wall_timer,compute_phase_aligned_time, clock-type validation,autostart=false, and phase preservation acrossreset()(both when not yet due and when catching up from overdue).Compatibility
Purely additive. Existing
TimerBase/GenericTimer/WallTimer/create_timer/create_wall_timerpublic signatures and behavior are unchanged.Testing
Built and tested against
rollingin aros:rolling-ros-basecontainer alongside ros2/rcl#1335 (colcon build+colcon testacrossrclandrclcpptimer suites and allament_lint_autolinters:uncrustify,cpplint,cppcheck,copyright,lint_cmake,xmllint).Landing order
Depends on ros2/rcl#1335 (
rcl_timer_init_with_start_time). Please test together viaci.ros2.organd land ros2/rcl#1335 first.