5. Classes and Objects
Every subsystem in our robot follows this pattern. Learn this lesson well and you can read any file in robot/subsystems/.
Summary
A class is a blueprint. It groups attributes (stored values) and methods (functions). An object is a thing made from the blueprint.
class FakeMotor:
def __init__(self, name): # runs once when you make the object
self.name = name # attribute: stored on the object
self.speed = 0.0
def set(self, speed): # method
self.speed = speed
left = FakeMotor('left intake') # make an object
left.set(0.8) # call a method
print(left.speed) # read an attribute
Rules and tools:
selfmeans: this object. It is the first parameter of every method. You never pass it yourself:left.set(0.8)fills it in automatically.- Every attribute that other code must see starts with
self.. A plain variable inside a method disappears when the method ends. - Objects can hold other objects:
self.left = FakeMotor('left'), thenself.left.set(...). - A subsystem follows one pattern:
__init__makes the hardware, other methods give commands,periodic()runs every frame. - Inheritance: a class can start from another class and add to it.
super().__init__()runs the setup of the parent class first:
class Intake(Subsystem): # Intake is a Subsystem, with more
def __init__(self, robot):
super().__init__()
...
isinstance(x, SomeClass)tests what class an object came from.- Imports bring in classes from other files.
import constgivesconst.LEFT_INTAKE_MOTOR_ID.from wpilib import TimergivesTimerdirectly.
You do not need to know the inside of the libraries. Make objects, set attributes, call methods. Example:
motor = hardware.TalonFX(id), thenmotor.set_control(...). That is all the vendor documentation expects you to do.
In our robot code
robot/subsystems/intake.py:
class Intake(Subsystem):
def __init__(self, robot: "Robot"):
super().__init__()
self.robot = robot
self.left_intake_motor = hardware.TalonFX(const.LEFT_INTAKE_MOTOR_ID, "rio")
self.commanded_intake_speed = 0.0
def set_intake_speed(self, speed):
self.commanded_intake_speed = speed / 100
self.left_intake_motor.set_control(controls.DutyCycleOut(speed / 100))
Try it
Run the code. Then make a second motor, set it to -0.6, and print its name and speed.
The code operates in your browser. The page sends nothing to a server and saves your work on this computer. Press Ctrl+Enter to run it.
Exercises
5.1 Add get() and status()
FakeMotor already stores name and speed, and has set.
PART A: add a method get(self). It returns self.speed.
PART B: add a method status(self). It returns an f-string like 'deploy at -0.35'.
The code operates in your browser. The page sends nothing to a server and saves your work on this computer. Press Ctrl+Enter to run it.
5.2 An intake with two motors
The real intake makes the right motor follow the left one. Here you set both yourself.
PART A: write set_speed(self, speed). It sets both motors to the same speed.
PART B: add a method stop(self). It sets both motors to 0.0.
The code operates in your browser. The page sends nothing to a server and saves your work on this computer. Press Ctrl+Enter to run it.
5.3 Inherit from Subsystem
Hopper inherits from Subsystem, exactly like every file in robot/subsystems/.
PART A: add a method stop(self). It sets self.running = False.
PART B: add a method toggle(self). It switches running: True becomes False, False becomes True.
The code operates in your browser. The page sends nothing to a server and saves your work on this computer. Press Ctrl+Enter to run it.
Next lesson: 6. RobotPy Patterns.