@@ -29,12 +29,14 @@ use async_std::future::timeout;
2929use rosidl_runtime_rs:: Message ;
3030
3131use crate :: {
32- rcl_bindings:: * , Client , ClientOptions , ClientState , Clock , ContextHandle , ExecutorCommands ,
33- IntoAsyncServiceCallback , IntoAsyncSubscriptionCallback , IntoNodeServiceCallback ,
34- IntoNodeSubscriptionCallback , LogParams , Logger , ParameterBuilder , ParameterInterface ,
35- ParameterVariant , Parameters , Promise , Publisher , PublisherOptions , PublisherState , RclrsError ,
36- Service , ServiceOptions , ServiceState , Subscription , SubscriptionOptions , SubscriptionState ,
37- TimeSource , ToLogParams , Worker , WorkerOptions , WorkerState , ENTITY_LIFECYCLE_MUTEX ,
32+ rcl_bindings:: * , AnyTimerCallback , Client , ClientOptions , ClientState , Clock , ContextHandle ,
33+ ExecutorCommands , IntoAsyncServiceCallback , IntoAsyncSubscriptionCallback ,
34+ IntoNodeServiceCallback , IntoNodeSubscriptionCallback , IntoNodeTimerOneshotCallback ,
35+ IntoNodeTimerRepeatingCallback , IntoTimerOptions , LogParams , Logger , ParameterBuilder ,
36+ ParameterInterface , ParameterVariant , Parameters , Promise , Publisher , PublisherOptions ,
37+ PublisherState , RclrsError , Service , ServiceOptions , ServiceState , Subscription ,
38+ SubscriptionOptions , SubscriptionState , TimeSource , Timer , TimerState , ToLogParams , Worker ,
39+ WorkerOptions , WorkerState , ENTITY_LIFECYCLE_MUTEX ,
3840} ;
3941
4042/// A processing unit that can communicate with other nodes. See the API of
@@ -908,6 +910,229 @@ impl NodeState {
908910 )
909911 }
910912
913+ /// Create a [`Timer`] with a repeating callback.
914+ ///
915+ /// This has similar behavior to `rclcpp::Node::create_timer` by periodically
916+ /// triggering the callback of the timer. For a one-shot timer alternative,
917+ /// see [`NodeState::create_timer_oneshot`].
918+ ///
919+ /// See also:
920+ /// * [`Self::create_timer_oneshot`]
921+ /// * [`Self::create_timer_inert`]
922+ ///
923+ /// # Behavior
924+ ///
925+ /// While the callback of this timer is running, no other callbacks associated
926+ /// with this node will be able to run. This is in contrast to callbacks given
927+ /// to [`Self::create_subscription`] which can run multiple times in parallel.
928+ ///
929+ /// Since the callback of this timer may block other callbacks from being able
930+ /// to run, it is strongly recommended to ensure that the callback returns
931+ /// quickly. If the callback needs to trigger long-running behavior then you
932+ /// can consider using [`std::thread::spawn`], or for async behaviors you can
933+ /// capture an [`ExecutorCommands`] in your callback and use [`ExecutorCommands::run`]
934+ /// to issue a task for the executor to run in its async task pool.
935+ ///
936+ /// Since these callbacks are blocking, you may use [`FnMut`] here instead of
937+ /// being limited to [`Fn`].
938+ ///
939+ /// # Timer Options
940+ ///
941+ /// You can choose both
942+ /// 1. a timer period (duration) which determines how often the callback is triggered
943+ /// 2. a clock to measure the passage of time
944+ ///
945+ /// Both of these choices are expressed by [`TimerOptions`][1].
946+ ///
947+ /// By default the steady clock time will be used, but you could choose
948+ /// node time instead if you want the timer to automatically use simulated
949+ /// time when running as part of a simulation:
950+ /// ```
951+ /// # use rclrs::*;
952+ /// # let executor = Context::default().create_basic_executor();
953+ /// # let node = executor.create_node("my_node").unwrap();
954+ /// use std::time::Duration;
955+ ///
956+ /// let timer = node.create_timer_repeating(
957+ /// TimerOptions::new(Duration::from_secs(1))
958+ /// .node_time(),
959+ /// || {
960+ /// println!("Triggering once each simulated second");
961+ /// },
962+ /// )?;
963+ /// # Ok::<(), RclrsError>(())
964+ /// ```
965+ ///
966+ /// If there is a specific manually-driven clock you want to use, you can
967+ /// also select that:
968+ /// ```
969+ /// # use rclrs::*;
970+ /// # let executor = Context::default().create_basic_executor();
971+ /// # let node = executor.create_node("my_node").unwrap();
972+ /// use std::time::Duration;
973+ ///
974+ /// let (my_clock, my_source) = Clock::with_source();
975+ ///
976+ /// let timer = node.create_timer_repeating(
977+ /// TimerOptions::new(Duration::from_secs(1))
978+ /// .clock(&my_clock),
979+ /// || {
980+ /// println!("Triggering once each simulated second");
981+ /// },
982+ /// )?;
983+ ///
984+ /// my_source.set_ros_time_override(1_500_000_000);
985+ /// # Ok::<(), RclrsError>(())
986+ /// ```
987+ ///
988+ /// If you are okay with the default choice of clock (steady clock) then you
989+ /// can choose to simply pass a duration in as the options:
990+ /// ```
991+ /// # use rclrs::*;
992+ /// # let executor = Context::default().create_basic_executor();
993+ /// # let node = executor.create_node("my_node").unwrap();
994+ /// use std::time::Duration;
995+ ///
996+ /// let timer = node.create_timer_repeating(
997+ /// Duration::from_secs(1),
998+ /// || {
999+ /// println!("Triggering per steady clock second");
1000+ /// },
1001+ /// )?;
1002+ /// # Ok::<(), RclrsError>(())
1003+ /// ```
1004+ ///
1005+ /// # Node Timer Repeating Callbacks
1006+ ///
1007+ /// Node Timer repeating callbacks support three signatures:
1008+ /// - <code>[FnMut] ()</code>
1009+ /// - <code>[FnMut] ([Time][2])</code>
1010+ /// - <code>[FnMut] (&[Timer])</code>
1011+ ///
1012+ /// You can choose to receive the current time when the callback is being
1013+ /// triggered.
1014+ ///
1015+ /// Or instead of the current time, you can get a borrow of the [`Timer`]
1016+ /// itself, that way if you need to access it from inside the callback, you
1017+ /// do not need to worry about capturing a [`Weak`][3] and then locking it.
1018+ /// This is useful if you need to change the callback of the timer from inside
1019+ /// the callback of the timer.
1020+ ///
1021+ /// For an [`FnOnce`] instead of [`FnMut`], use [`Self::create_timer_oneshot`].
1022+ ///
1023+ /// [1]: crate::TimerOptions
1024+ /// [2]: crate::Time
1025+ /// [3]: std::sync::Weak
1026+ pub fn create_timer_repeating < ' a , Args > (
1027+ self : & Arc < Self > ,
1028+ options : impl IntoTimerOptions < ' a > ,
1029+ callback : impl IntoNodeTimerRepeatingCallback < Args > ,
1030+ ) -> Result < Timer , RclrsError > {
1031+ self . create_timer_internal ( options, callback. into_node_timer_repeating_callback ( ) )
1032+ }
1033+
1034+ /// Create a [`Timer`] whose callback will be triggered once after the period
1035+ /// of the timer has elapsed. After that you will need to use
1036+ /// [`TimerState::set_repeating`] or [`TimerState::set_oneshot`] or else
1037+ /// nothing will happen the following times that the `Timer` elapses.
1038+ ///
1039+ /// This does not have an equivalent in `rclcpp`.
1040+ ///
1041+ /// See also:
1042+ /// * [`Self::create_timer_repeating`]
1043+ /// * [`Self::create_timer_inert`]
1044+ ///
1045+ /// # Behavior
1046+ ///
1047+ /// While the callback of this timer is running, no other callbacks associated
1048+ /// with this node will be able to run. This is in contrast to callbacks given
1049+ /// to [`Self::create_subscription`] which can run multiple times in parallel.
1050+ ///
1051+ /// Since the callback of this timer may block other callbacks from being able
1052+ /// to run, it is strongly recommended to ensure that the callback returns
1053+ /// quickly. If the callback needs to trigger long-running behavior then you
1054+ /// can consider using [`std::thread::spawn`], or for async behaviors you can
1055+ /// capture an [`ExecutorCommands`] in your callback and use [`ExecutorCommands::run`]
1056+ /// to issue a task for the executor to run in its async task pool.
1057+ ///
1058+ /// Since these callbacks will only be triggered once, you may use [`FnOnce`] here.
1059+ ///
1060+ /// # Timer Options
1061+ ///
1062+ /// See [`NodeSate::create_timer_repeating`][3] for examples of setting the
1063+ /// timer options.
1064+ ///
1065+ /// # Node Timer Oneshot Callbacks
1066+ ///
1067+ /// Node Timer OneShot callbacks support three signatures:
1068+ /// - <code>[FnOnce] ()</code>
1069+ /// - <code>[FnOnce] ([Time][2])</code>
1070+ /// - <code>[FnOnce] (&[Timer])</code>
1071+ ///
1072+ /// You can choose to receive the current time when the callback is being
1073+ /// triggered.
1074+ ///
1075+ /// Or instead of the current time, you can get a borrow of the [`Timer`]
1076+ /// itself, that way if you need to access it from inside the callback, you
1077+ /// do not need to worry about capturing a [`Weak`][3] and then locking it.
1078+ /// This is useful if you need to change the callback of the timer from inside
1079+ /// the callback of the timer.
1080+ ///
1081+ /// [2]: crate::Time
1082+ /// [3]: std::sync::Weak
1083+ pub fn create_timer_oneshot < ' a , Args > (
1084+ self : & Arc < Self > ,
1085+ options : impl IntoTimerOptions < ' a > ,
1086+ callback : impl IntoNodeTimerOneshotCallback < Args > ,
1087+ ) -> Result < Timer , RclrsError > {
1088+ self . create_timer_internal ( options, callback. into_node_timer_oneshot_callback ( ) )
1089+ }
1090+
1091+ /// Create a [`Timer`] without a callback. Nothing will happen when this
1092+ /// `Timer` elapses until you use [`TimerState::set_repeating`] or
1093+ /// [`TimerState::set_oneshot`].
1094+ ///
1095+ /// This function is not usually what you want. An inert timer is usually
1096+ /// just a follow-up state to a oneshot timer which is waiting to be given
1097+ /// a new callback to run. However, you could use this method to declare a
1098+ /// timer whose callbacks you will start to feed in at a later.
1099+ ///
1100+ /// There is no equivalent to this function in `rclcpp`.
1101+ ///
1102+ /// See also:
1103+ /// * [`Self::create_timer_repeating`]
1104+ /// * [`Self::create_timer_oneshot`]
1105+ pub fn create_timer_inert < ' a > (
1106+ self : & Arc < Self > ,
1107+ options : impl IntoTimerOptions < ' a > ,
1108+ ) -> Result < Timer , RclrsError > {
1109+ self . create_timer_internal ( options, AnyTimerCallback :: Inert )
1110+ }
1111+
1112+ /// Used internally to create any kind of [`Timer`].
1113+ ///
1114+ /// Downstream users should instead use:
1115+ /// * [`Self::create_timer_repeating`]
1116+ /// * [`Self::create_timer_oneshot`]
1117+ /// * [`Self::create_timer_inert`]
1118+ fn create_timer_internal < ' a > (
1119+ self : & Arc < Self > ,
1120+ options : impl IntoTimerOptions < ' a > ,
1121+ callback : AnyTimerCallback < Node > ,
1122+ ) -> Result < Timer , RclrsError > {
1123+ let options = options. into_timer_options ( ) ;
1124+ let clock = options. clock . as_clock ( self ) ;
1125+ let node = options. clock . is_node_time ( ) . then ( || Arc :: clone ( self ) ) ;
1126+ TimerState :: create (
1127+ options. period ,
1128+ clock,
1129+ callback,
1130+ self . commands . async_worker_commands ( ) ,
1131+ & self . handle . context_handle ,
1132+ node,
1133+ )
1134+ }
1135+
9111136 /// Returns the ROS domain ID that the node is using.
9121137 ///
9131138 /// The domain ID controls which nodes can send messages to each other, see the [ROS 2 concept article][1].
0 commit comments