magicbot module¶
-
class
magicbot.magicrobot.MagicRobot[source]¶ Bases:
wpilib.samplerobot.SampleRobotWarning
This implementation is still being developed, and may be changed during the course of the 2016 season.
Robots that use the MagicBot framework should use this as their base robot class. If you use this as your base, you must implement the following methods:
MagicRobot uses the
AutonomousModeSelectorto allow you to define multiple autonomous modes and to select one of them via the SmartDashboard/SFX.MagicRobot will set the following NetworkTables variables automatically:
/robot/mode: one of ‘disabled’, ‘auto’, ‘teleop’, or ‘test’/robot/is_simulation: True/False/robot/is_ds_attached: True/False
-
consumeExceptions(forceReport=False)[source]¶ This returns a context manager which will consume any uncaught exceptions that might otherwise crash the robot.
Example usage:
def teleopPeriodic(self): with self.consumeExceptions(): if self.joystick.getTrigger(): self.shooter.shoot() with self.consumeExceptions(): if self.joystick.getRawButton(2): self.ball_intake.run() # and so on...
Parameters: forceReport – Always report the exception to the DS. Don’t set this to True See also
onException()for more details
-
control_loop_wait_time= 0.02¶ Amount of time each loop takes (default is 20ms)
-
createObjects()[source]¶ You should override this and initialize all of your wpilib objects here (and not in your components, for example). This serves two purposes:
- It puts all of your motor/sensor initialization in the same place, so that if you need to change a port/pin number it makes it really easy to find it. Additionally, if you want to create a simplified robot program to test a specific thing, it makes it really easy to copy/paste it elsewhere
- It allows you to use the magic injection mechanism to share variables between components
Note
Do not access your magic components in this function, as their instances have not been created yet. Do not create them either.
-
disabledInit()[source]¶ Initialization code for disabled mode may go here.
Users may override this method for initialization code which will be called each time the robot enters disabled mode.
Note
The
on_disablefunctions of all components are called before this function is called.
-
disabledPeriodic()[source]¶ Periodic code for disabled mode should go here.
Users should override this method for code which will be called periodically at a regular rate while the robot is in disabled mode.
This code executes before the
executefunctions of all components are called.
-
error_report_interval= 0.5¶ Error report interval: when an FMS is attached, how often should uncaught exceptions be reported?
-
onException(forceReport=False)[source]¶ This function must only be called when an unexpected exception has occurred that would otherwise crash the robot code. Use this inside your
operatorActions()function.If the FMS is attached (eg, during a real competition match), this function will return without raising an error. However, it will try to report one-off errors to the Driver Station so that it will be recorded in the Driver Station Log Viewer. Repeated errors may not get logged.
Example usage:
def teleopPeriodic(self): try: if self.joystick.getTrigger(): self.shooter.shoot() except: self.onException() try: if self.joystick.getRawButton(2): self.ball_intake.run() except: self.onException() # and so on...
Parameters: forceReport – Always report the exception to the DS. Don’t set this to True
Component¶
-
class
magicbot.magiccomponent.MagicComponent[source]¶ Bases:
objectTo automagically retrieve variables defined in your base robot object, you can add the following:
class MyComponent: # other variables 'imported' automatically from MagicRobot elevator_motor = Talon other_component = MyOtherComponent ... def execute(self): # This will be automatically set to the Talon # instance created in robot.py self.elevator_motor.set(self.value)
What this says is “find the variable in the robot class called ‘elevator_motor’, which is a Talon”. If the name and type match, then the variable will automatically be injected into your component when it is created.
Note
You don’t need to inherit from
MagicComponent, it is only provided for documentation’s sake-
on_enabled()[source]¶ Called when the robot enters autonomous or teleoperated mode. This function should initialize your component to a “safe” state so that unexpected things don’t happen when enabling the robot.
Note
You’ll note that there isn’t a separate initialization function for autonomous and teleoperated modes. This is intentional, as they should be the same.
-
setup()[source]¶ This function is called after
createObjectshas been called in the main robot class, and after all components have been createdThe setup function is optional and components do not have to define one.
setup()functions are called in order of component definition in the main robot class.Note
For technical reasons, variables imported from MagicRobot are not initialized when your component’s constructor is called. However, they will be initialized by the time this function is called.
-
Tunable¶
-
magicbot.magic_tunable.setup_tunables(component, cname, prefix='components')[source]¶ Connects the tunables on an object to NetworkTables.
Parameters: - component – Component object
- cname (str) – Name of component
- prefix (str) – Prefix to use, or no prefix if None
Note
This is not needed in normal use, only useful for testing
-
magicbot.magic_tunable.tunable(default, *, writeDefault=True, subtable=None)[source]¶ This allows you to define simple properties that allow you to easily communicate with other programs via NetworkTables.
The following example will define a NetworkTable variable at
/components/my_component/foo:class MyRobot(magicbot.MagicRobot): my_component = MyComponent ... from magicbot import tunable class MyComponent: # define the tunable property foo = tunable(True) def execute(self): # set the variable self.foo = True # get the variable foo = self.foo
The key of the NetworkTables variable will vary based on what kind of object the decorated method belongs to:
- A component:
/components/COMPONENTNAME/VARNAME - An autonomous mode:
/autonomous/MODENAME/VARNAME - Your main robot class:
/robot/VARNAME
Note
When executing unit tests on objects that create tunables, you will want to use setup_tunables to set the object up. In normal usage, MagicRobot does this for you, so you don’t have to do anything special.
- A component:
State machines¶
-
class
magicbot.state_machine.AutonomousStateMachine[source]¶ Bases:
magicbot.state_machine.StateMachineThis is a specialized version of the StateMachine that is designed to be used as an autonomous mode. There are a few key differences:
- The
engage()function is always called, so the state machine will always run to completion unless done() is called - VERBOSE_LOGGING is set to True, so a log message will be printed out upon each state transition
-
VERBOSE_LOGGING= True¶
- The
-
class
magicbot.state_machine.StateMachine[source]¶ Bases:
objectThis object is designed to be used to easily implement magicbot components that are basically a big state machine.
You use this by defining a class that inherits from
StateMachine. To define each state, you use thetimed_state()decorator on a function. When each state is run, the decorated function will be called. Decorated state functions can receive the following parameters:tm- The number of seconds since autonomous has startedstate_tm- The number of seconds since this state has been active (note: it may not start at zero!)initial_call- Set to True when the state is initially called, False otherwise. If the state is switched to multiple times, this will be set to True at the start of each state.
To be consistent with the magicbot philosophy, in order for the state machine to execute its states you must call the
engage()function upon each execution of the main robot control loop. If you do not call this function, then execution will cease unless the current executing state is marked asmust_finish.When execution ceases, the
done()function will be called unless execution was stopped by calling thedonefunction.As a magicbot component, this contains an
executefunction that will be called on each control loop. All state execution occurs from within that function call. If you call other components from this component, you should ensure that your component occurs before the other components in your Robot class.Here’s a very simple example of how you might implement a shooter automation component that moves a ball into a shooter when the shooter is ready:
class ShooterAutomation: # Some other component shooter = Shooter ball_pusher = BallPusher def fire(self): """This is called from the main loop""" self.engage() @state(first=True) def begin_firing(self): self.shooter.enable() if self.shooter.ready(): self.next_state('firing') @timed_state(duration=1.0, must_finish=True) def firing(self): """This state will continue executing even if engage isn't called""" self.shooter.enable() self.ball_pusher.push() ... class MyRobot(magicbot.MagicRobot): ... def teleopPeriodic(self): if self.joystick.getTrigger(): self.shooter_automation.fire()
This object has a lot of really useful NetworkTables integration as well:
- tunables are created in /components/NAME/state - state durations can be tuned here - The ‘current state’ is output as it happens - Descriptions and names of the states are here (for dashboard use)
Warning
This object is not intended to be threadsafe and should not be accessed from multiple threads
-
VERBOSE_LOGGING= False¶
-
current_state¶ NT variable that indicates which state will be executed next (though, does not guarantee that it will be executed). Will return an empty string if the state machine is not currently engaged.
-
done()[source]¶ Call this function to end execution of the state machine.
Note
If you wish to do something each time execution ceases, override this function (but be sure to call
super().done()!)
-
engage(initial_state=None, force=False)[source]¶ This signals that you want the state machine to execute its states.
Parameters: - initial_state – If specified and execution is not currently occurring, start in this state instead of in the ‘first’ state
- force – If True, will transition even if the state machine is currently active.
-
execute()[source]¶ magicbot component API: This is called on each iteration of the control loop. Most of the time, you will not want to override this function.
-
is_executing¶ Returns: True if the state machine is executing states
-
next_state(name)[source]¶ Call this function to transition to the next state
Parameters: name – Name of the state to transition to Note
This should only be called from one of the state functions
-
next_state_now(name)[source]¶ Call this function to transition to the next state, and call the next state function immediately. Prefer to use
next_state()instead.Parameters: name – Name of the state to transition to Note
This should only be called from one of the state functions
-
magicbot.state_machine.state(f=None, *, first=False, must_finish=False)[source]¶ If this decorator is applied to a function in an object that inherits from
StateMachine, it indicates that the function is a state. The state will continue to be executed until thenext_statefunction is executed.The decorated function can have the following arguments in any order:
tm- The number of seconds since the state machine has startedstate_tm- The number of seconds since this state has been active (note: it may not start at zero!)initial_call- Set to True when the state is initially called, False otherwise. If the state is switched to multiple times, this will be set to True at the start of each state execution.
Parameters: - first (bool) – If True, this state will be ran first
- must_finish (bool) – If True, then this state will continue executing
even if
engage()is not called. However, ifdone()is called, execution will stop regardless of whether this is set.
-
magicbot.state_machine.timed_state(f=None, *, duration=None, next_state=None, first=False, must_finish=False)[source]¶ If this decorator is applied to a function in an object that inherits from
StateMachine, it indicates that the function is a state that will run for a set amount of time unless interruptedThe decorated function can have the following arguments in any order:
tm- The number of seconds since the state machine has startedstate_tm- The number of seconds since this state has been active (note: it may not start at zero!)initial_call- Set to True when the state is initially called, False otherwise. If the state is switched to multiple times, this will be set to True at the start of each state execution.
Parameters: - duration (float) – The length of time to run the state before progressing to the next state
- next_state (str) – The name of the next state. If not specified, then this will be the last state executed if time expires
- first (bool) – If True, this state will be ran first
- must_finish (bool) – If True, then this state will continue executing
even if
engage()is not called. However, ifdone()is called, execution will stop regardless of whether this is set.