2
2
import inspect
3
3
import logging
4
4
5
+ import hal
5
6
import wpilib
6
7
7
8
from networktables import NetworkTables
8
9
from wpilib .shuffleboard import Shuffleboard
9
10
10
- from robotpy_ext .misc import NotifierDelay
11
11
from robotpy_ext .autonomous import AutonomousModeSelector
12
-
12
+ from robotpy_ext . misc import NotifierDelay
13
13
from robotpy_ext .misc .orderedclass import OrderedClass
14
14
from robotpy_ext .misc .annotations import get_class_annotations
15
15
@@ -34,8 +34,8 @@ class MagicRobot(wpilib.SampleRobot, metaclass=OrderedClass):
34
34
35
35
MagicRobot uses the :class:`.AutonomousModeSelector` to allow you
36
36
to define multiple autonomous modes and to select one of them via
37
- the SmartDashboard/SFX .
38
-
37
+ the SmartDashboard/Shuffleboard .
38
+
39
39
MagicRobot will set the following NetworkTables variables
40
40
automatically:
41
41
@@ -78,6 +78,8 @@ def robotInit(self):
78
78
self .__nt .putBoolean ("is_simulation" , self .isSimulation ())
79
79
self .__nt .putBoolean ("is_ds_attached" , self .ds .isDSAttached ())
80
80
81
+ self .watchdog = wpilib .Watchdog (self .control_loop_wait_time , self ._loop_overrun )
82
+
81
83
def createObjects (self ):
82
84
"""
83
85
You should override this and initialize all of your wpilib
@@ -183,9 +185,13 @@ def robotPeriodic(self):
183
185
The default implementation will update
184
186
SmartDashboard, LiveWindow and Shuffleboard.
185
187
"""
188
+ watchdog = self .watchdog
186
189
wpilib .SmartDashboard .updateValues ()
190
+ watchdog .addEpoch ("SmartDashboard" )
187
191
wpilib .LiveWindow .updateValues ()
192
+ watchdog .addEpoch ("LiveWindow" )
188
193
Shuffleboard .update ()
194
+ watchdog .addEpoch ("Shuffleboard" )
189
195
190
196
def onException (self , forceReport = False ):
191
197
"""
@@ -289,6 +295,7 @@ def autonomous(self):
289
295
self .control_loop_wait_time ,
290
296
(self ._execute_components , self ._update_feedback , self .robotPeriodic ),
291
297
self .onException ,
298
+ watchdog = self .watchdog ,
292
299
)
293
300
294
301
self ._on_mode_disable_components ()
@@ -301,6 +308,8 @@ def disabled(self):
301
308
302
309
.. warning:: Internal API, don't override
303
310
"""
311
+ watchdog = self .watchdog
312
+ watchdog .reset ()
304
313
305
314
self .__nt .putString ("mode" , "disabled" )
306
315
ds_attached = None
@@ -311,21 +320,31 @@ def disabled(self):
311
320
self .disabledInit ()
312
321
except :
313
322
self .onException (forceReport = True )
323
+ watchdog .addEpoch ("disabledInit()" )
314
324
315
325
with NotifierDelay (self .control_loop_wait_time ) as delay :
316
326
while self .isDisabled ():
317
327
if ds_attached != self .ds .isDSAttached ():
318
328
ds_attached = not ds_attached
319
329
self .__nt .putBoolean ("is_ds_attached" , ds_attached )
320
330
331
+ hal .observeUserProgramDisabled ()
321
332
try :
322
333
self .disabledPeriodic ()
323
334
except :
324
335
self .onException ()
336
+ watchdog .addEpoch ("disabledPeriodic()" )
325
337
326
338
self ._update_feedback ()
327
339
self .robotPeriodic ()
340
+ watchdog .addEpoch ("robotPeriodic()" )
341
+ watchdog .disable ()
342
+
343
+ if watchdog .isExpired ():
344
+ watchdog .printEpochs ()
345
+
328
346
delay .wait ()
347
+ watchdog .reset ()
329
348
330
349
def operatorControl (self ):
331
350
"""
@@ -335,6 +354,8 @@ def operatorControl(self):
335
354
336
355
.. warning:: Internal API, don't override
337
356
"""
357
+ watchdog = self .watchdog
358
+ watchdog .reset ()
338
359
339
360
self .__nt .putString ("mode" , "teleop" )
340
361
# don't need to update this during teleop -- presumably will switch
@@ -349,24 +370,36 @@ def operatorControl(self):
349
370
self .teleopInit ()
350
371
except :
351
372
self .onException (forceReport = True )
373
+ watchdog .addEpoch ("teleopInit()" )
352
374
353
375
with NotifierDelay (self .control_loop_wait_time ) as delay :
354
376
while self .isOperatorControl () and self .isEnabled ():
377
+ hal .observeUserProgramTeleop ()
355
378
try :
356
379
self .teleopPeriodic ()
357
380
except :
358
381
self .onException ()
382
+ watchdog .addEpoch ("teleopPeriodic()" )
359
383
360
384
self ._execute_components ()
385
+
361
386
self ._update_feedback ()
362
387
self .robotPeriodic ()
388
+ watchdog .addEpoch ("robotPeriodic()" )
389
+ watchdog .disable ()
390
+
391
+ if watchdog .isExpired ():
392
+ watchdog .printEpochs ()
363
393
364
394
delay .wait ()
395
+ watchdog .reset ()
365
396
366
397
self ._on_mode_disable_components ()
367
398
368
399
def test (self ):
369
400
"""Called when the robot is in test mode"""
401
+ watchdog = self .watchdog
402
+ watchdog .reset ()
370
403
371
404
self .__nt .putString ("mode" , "test" )
372
405
self .__nt .putBoolean ("is_ds_attached" , self .ds .isDSAttached ())
@@ -376,33 +409,45 @@ def test(self):
376
409
self .testInit ()
377
410
except :
378
411
self .onException (forceReport = True )
412
+ watchdog .addEpoch ("testInit()" )
379
413
380
414
with NotifierDelay (self .control_loop_wait_time ) as delay :
381
415
while self .isTest () and self .isEnabled ():
416
+ hal .observeUserProgramTest ()
382
417
try :
383
418
self .testPeriodic ()
384
419
except :
385
420
self .onException ()
421
+ watchdog .addEpoch ("testPeriodic()" )
386
422
387
423
self ._update_feedback ()
388
424
self .robotPeriodic ()
425
+ watchdog .addEpoch ("robotPeriodic()" )
426
+ watchdog .disable ()
427
+
428
+ if watchdog .isExpired ():
429
+ watchdog .printEpochs ()
430
+
389
431
delay .wait ()
432
+ watchdog .reset ()
390
433
391
434
def _on_mode_enable_components (self ):
392
435
# initialize things
393
- for component in self ._components :
394
- if hasattr (component , "on_enable" ):
436
+ for _ , component in self ._components :
437
+ on_enable = getattr (component , "on_enable" , None )
438
+ if on_enable is not None :
395
439
try :
396
- component . on_enable ()
440
+ on_enable ()
397
441
except :
398
442
self .onException (forceReport = True )
399
443
400
444
def _on_mode_disable_components (self ):
401
445
# deinitialize things
402
- for component in self ._components :
403
- if hasattr (component , "on_disable" ):
446
+ for _ , component in self ._components :
447
+ on_disable = getattr (component , "on_disable" , None )
448
+ if on_disable is not None :
404
449
try :
405
- component . on_disable ()
450
+ on_disable ()
406
451
except :
407
452
self .onException (forceReport = True )
408
453
@@ -492,7 +537,6 @@ def _create_components(self):
492
537
493
538
# For each new component, perform magic injection
494
539
for cname , component in components :
495
- self ._components .append (component )
496
540
setup_tunables (component , cname , "components" )
497
541
self ._feedbacks += collect_feedbacks (component , cname , "components" )
498
542
self ._setup_vars (cname , component )
@@ -518,6 +562,8 @@ def _create_components(self):
518
562
if hasattr (mode , "setup" ):
519
563
mode .setup ()
520
564
565
+ self ._components = components
566
+
521
567
def _create_component (self , name , ctyp ):
522
568
# Create instance, set it on self
523
569
component = ctyp ()
@@ -638,13 +684,19 @@ def _update_feedback(self):
638
684
self .onException ()
639
685
continue
640
686
entry .setValue (value )
687
+ self .watchdog .addEpoch ("@magicbot.feedback" )
641
688
642
689
def _execute_components (self ):
643
- for component in self ._components :
690
+ for name , component in self ._components :
644
691
try :
645
692
component .execute ()
646
693
except :
647
694
self .onException ()
695
+ self .watchdog .addEpoch (name )
648
696
649
697
for reset_dict , component in self ._reset_components :
650
698
component .__dict__ .update (reset_dict )
699
+
700
+ def _loop_overrun (self ):
701
+ # TODO: print something here without making it extremely annoying
702
+ pass
0 commit comments