5
5
import types
6
6
import typing
7
7
8
- from typing import Any , Callable
8
+ from typing import Any , Callable , List , Tuple
9
9
10
10
import hal
11
11
import wpilib
12
+ from wpilib import Notifier
12
13
13
14
from ntcore import NetworkTableInstance
14
15
@@ -88,6 +89,11 @@ def __init__(self) -> None:
88
89
self .__lv_update = wpilib .LiveWindow .updateValues
89
90
# self.__sf_update = Shuffleboard.update
90
91
92
+ self ._periodic_callbacks : typing .List [Tuple [Callable [[], None ], float ]] = []
93
+ self ._notifiers : List [Notifier ] = []
94
+
95
+ self .loop_time = self .control_loop_wait_time
96
+
91
97
def _simulationInit (self ) -> None :
92
98
pass
93
99
@@ -99,6 +105,16 @@ def __simulationPeriodic(self) -> None:
99
105
self ._simulationPeriodic ()
100
106
hal .simPeriodicAfter ()
101
107
108
+ def addPeriodic (self , callback : Callable [[], None ], period : float ):
109
+ """
110
+ Add a callback to run at a specific period with a starting time offset.
111
+
112
+ This is scheduled with MagicRobot's loop, so MagicRobot and the callback run synchronously.
113
+ """
114
+
115
+ print (f"Registering periodic: { callback .__name__ } , every { period } s" )
116
+ self ._periodic_callbacks .append ((callback , period ))
117
+
102
118
def robotInit (self ) -> None :
103
119
"""
104
120
.. warning:: Internal API, don't override; use :meth:`createObjects` instead
@@ -558,6 +574,20 @@ def _test(self) -> None:
558
574
wpilib .LiveWindow .setEnabled (False )
559
575
# Shuffleboard.disableActuatorWidgets()
560
576
577
+
578
+ def _stop_notifiers (self ):
579
+ for notifier in self ._notifiers :
580
+ notifier .stop ()
581
+ self ._notifiers .clear ()
582
+
583
+ def _restart_periodics (self ):
584
+ self ._stop_notifiers ()
585
+ for callback , period in self ._periodic_callbacks :
586
+ notifier = Notifier (callback )
587
+ notifier .setName (f"Periodic-{ callback .__name__ } " )
588
+ notifier .startPeriodic (period )
589
+ self ._notifiers .append (notifier )
590
+
561
591
def _on_mode_enable_components (self ) -> None :
562
592
# initialize things
563
593
for _ , component in self ._components :
@@ -567,6 +597,7 @@ def _on_mode_enable_components(self) -> None:
567
597
on_enable ()
568
598
except :
569
599
self .onException (forceReport = True )
600
+ self ._restart_periodics ()
570
601
571
602
def _on_mode_disable_components (self ) -> None :
572
603
# deinitialize things
@@ -577,6 +608,7 @@ def _on_mode_disable_components(self) -> None:
577
608
on_disable ()
578
609
except :
579
610
self .onException (forceReport = True )
611
+ self ._stop_notifiers ()
580
612
581
613
def _create_components (self ) -> None :
582
614
#
@@ -737,6 +769,12 @@ def _do_periodics(self) -> None:
737
769
738
770
for reset_dict , component in self ._reset_components :
739
771
component .__dict__ .update (reset_dict )
772
+
773
+ self .loop_time = max (self .control_loop_wait_time , self .watchdog .getTime ())
774
+
775
+ def get_period (self ) -> float :
776
+ """Get the period of the robot loop in seconds."""
777
+ return self .loop_time
740
778
741
779
def _enabled_periodic (self ) -> None :
742
780
"""Run components and all periodic methods."""
0 commit comments