[robotpy][examples] Split examples and snippets (#8944)

This also updates the bazel scripts to behave more like the C++ and Java
examples, and updates the copybara scripts to be able to sync up
`mostrobotpy`
This commit is contained in:
PJ Reiniger
2026-06-03 22:43:16 -04:00
committed by GitHub
parent a734275cc5
commit dca59147e1
134 changed files with 111 additions and 80 deletions

View File

@@ -0,0 +1,134 @@
#
# Copyright (c) FIRST and other WPILib contributors.
# Open Source Software; you can modify and/or share it under the terms of
# the WPILib BSD license file in the root directory of this project.
#
import wpilib
import wpilib.simulation
import wpimath
import wpimath.units
import constants
class Elevator:
def __init__(self) -> None:
# This gearbox represents a gearbox containing 4 Vex 775pro motors.
self.elevatorGearbox = wpimath.DCMotor.NEO(2)
self.profile = wpimath.ExponentialProfileMeterVolts(
wpimath.ExponentialProfileMeterVolts.Constraints.fromCharacteristics(
constants.kElevatorMaxV,
constants.kElevatorkV,
constants.kElevatorkA,
)
)
self.setpoint = wpimath.ExponentialProfileMeterVolts.State(0, 0)
# Standard classes for controlling our elevator
self.pidController = wpimath.PIDController(
constants.kElevatorKp, constants.kElevatorKi, constants.kElevatorKd
)
self.feedforward = wpimath.ElevatorFeedforward(
constants.kElevatorkS,
constants.kElevatorkG,
constants.kElevatorkV,
constants.kElevatorkA,
)
self.encoder = wpilib.Encoder(
constants.kEncoderAChannel, constants.kEncoderBChannel
)
self.motor = wpilib.PWMSparkMax(constants.kMotorPort)
# Simulation classes help us simulate what's going on, including gravity.
self.elevatorSim = wpilib.simulation.ElevatorSim(
self.elevatorGearbox,
constants.kElevatorGearing,
constants.kCarriageMass,
constants.kElevatorDrumRadius,
constants.kMinElevatorHeight,
constants.kMaxElevatorHeight,
True,
0,
[0.005, 0.0],
)
self.encoderSim = wpilib.simulation.EncoderSim(self.encoder)
self.motorSim = wpilib.simulation.PWMMotorControllerSim(self.motor)
# Create a Mechanism2d visualization of the elevator
self.mech2d = wpilib.Mechanism2d(
wpimath.units.inchesToMeters(10),
wpimath.units.inchesToMeters(51),
)
self.mech2dRoot = self.mech2d.getRoot(
"Elevator Root",
wpimath.units.inchesToMeters(5),
wpimath.units.inchesToMeters(0.5),
)
self.elevatorMech2d = self.mech2dRoot.appendLigament(
"Elevator", self.elevatorSim.getPosition(), 90
)
# Subsystem constructor.
self.encoder.setDistancePerPulse(constants.kElevatorEncoderDistPerPulse)
# Publish Mechanism2d to SmartDashboard
# To view the Elevator visualization, select Network Tables -> SmartDashboard -> Elevator Sim
wpilib.SmartDashboard.putData("Elevator Sim", self.mech2d)
def simulationPeriodic(self) -> None:
"""Advance the simulation."""
# In this method, we update our simulation of what our elevator is doing
# First, we set our "inputs" (voltages)
self.elevatorSim.setInputVoltage(
self.motorSim.getThrottle() * wpilib.RobotController.getBatteryVoltage()
)
# Next, we update it. The standard loop time is 20ms.
self.elevatorSim.update(0.020)
# Finally, we set our simulated encoder's readings and simulated battery voltage
self.encoderSim.setDistance(self.elevatorSim.getPosition())
# SimBattery estimates loaded battery voltages
wpilib.simulation.RoboRioSim.setVInVoltage(
wpilib.simulation.BatterySim.calculate([self.elevatorSim.getCurrentDraw()])
)
def reachGoal(self, goal: float) -> None:
"""Run control loop to reach and maintain goal.
:param goal: the position to maintain
"""
goalState = wpimath.ExponentialProfileMeterVolts.State(goal, 0)
next_state = self.profile.calculate(0.020, self.setpoint, goalState)
# With the setpoint value we run PID control like normal
pidOutput = self.pidController.calculate(
self.encoder.getDistance(), self.setpoint.position
)
feedforwardOutput = self.feedforward.calculate(
self.setpoint.velocity, next_state.velocity
)
self.motor.setVoltage(pidOutput + feedforwardOutput)
self.setpoint = next_state
def stop(self) -> None:
"""Stop the control loop and motor output."""
self.motor.setThrottle(0.0)
def reset(self) -> None:
"""Reset Exponential profile to begin from current position on enable."""
self.setpoint = wpimath.ExponentialProfileMeterVolts.State(
self.encoder.getDistance(), 0
)
def updateTelemetry(self) -> None:
"""Update telemetry, including the mechanism visualization."""
# Update elevator visualization with position
self.elevatorMech2d.setLength(self.encoder.getDistance())