Allow specifying an initial timer trigger time in create_timer/create_wall_timer - #3270
thomasmoore-torc wants to merge 4 commits into
Conversation
Signed-off-by: Thomas Moore <thomas.moore@torc.ai>
Signed-off-by: Thomas Moore <thomas.moore@torc.ai>
|
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 |
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>
|
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 |
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>
|
After thinking about this some more, I've decided to add a |
rclcpp: Allow specifying an initial timer trigger time in create_timer/create_wall_timer
Branch:
timer-initial-call-time(this repo:ros2/rclcpp)Depends on: ros2/rcl#1335 — "Allow specifying an initial timer trigger time" (adds
rcl_timer_init3). This PR requires that change to be available and should land after it.Summary
Building on the new
rcl_timer_init3(see the companionrclPR), this addsrclcpp-level overloads that let callers specify an explicit initial trigger time for a timer instead of always waiting one fullperiodbefore the first callback.Typical motivating cases: firing a timer immediately then repeating every
period, staggering multiple timers' first calls to avoid a thundering herd, or aligning a timer's first call to a specific point in time (e.g. synchronizing with an external schedule).Changes
rclcpp::TimerBase/rclcpp::GenericTimergain constructors taking an explicitrclcpp::Time initial_call_timein addition toperiod, callingrcl_timer_init3under the hood.rclcpp::create_timer(...)/rclcpp::create_wall_timer(...)(free functions increate_timer.hpp) gain overloads takinginitial_call_timebeforeperiod.rclcpp::Node::create_timer(...)/rclcpp::Node::create_wall_timer(...)gain matching overloads.test_timer.cppandtest_create_timer.cppcovering: invalid-argument handling for the new overloads, that a futureinitial_call_timeis honored (next trigger reflects it, notnow + period), and a fix-regression test (call_timer_forwards_autostart_regardless_of_initial_call_time_overload) confirmingautostartis respected consistently across both the old and new overloads.Compatibility
Purely additive. Existing
create_timer/create_wall_timer/TimerBase/GenericTimer/WallTimercall sites are unaffected.Testing
Built and tested against
rollingin aros:rolling-ros-basecontainer viacolcon build/colcon test(3091 tests, 0 failures acrossrclcpp,rclcpp_action,rclcpp_lifecycle,rclcpp_components, built together with the companionrclbranch), plusuncrustify/cpplintlint targets.Landing order
Depends on ros2/rcl#1335 (
rcl_timer_init3). Please land that one first, or merge together.🤖 Generated with Claude Code