Unit 7: Advanced FRC Coding
Simulation is arguably the single most important tool for our team's productivity. It allows us to write, test, and tune our code on a "virtual robot" on our computers, long before the physical robot is built.
The secret to having a competition-ready robot by the end of build season is concurrent engineering. While the fabrication team is machining parts for the arm, the programming team is already writing and testing the code to control that arm. Simulation is the bridge that makes this parallel workflow possible.
How does the code know whether it's running on a real robot or in the simulator? The answer lies in a special method within every subsystem: `simulationPeriodic()`.
Let's look at the structure for an arm with one motor and one encoder. Notice the clean separation between the real and simulated sensor logic.
public class ArmSubsystem extends SubsystemBase {
private final Spark m_motor;
private final Encoder m_encoder;
// Simulation-only objects
private final DCMotorSim m_motorSim;
private final EncoderSim m_encoderSim;
public ArmSubsystem() {
m_motor = new Spark(0);
m_encoder = new Encoder(0, 1);
// Create simulation models based on the physical properties from CAD
m_motorSim = new DCMotorSim(DCMotor.getNEO(1), 100.0, 2.5);
m_encoderSim = new EncoderSim(m_encoder);
}
public void setVoltage(double volts) {
m_motor.setVoltage(volts);
}
public double getAngle() {
// This works on both the real robot and in simulation!
return m_encoder.getDistance();
}
// This method is ONLY called in simulation
@Override
public void simulationPeriodic() {
// 1. Update the physics simulation model
m_motorSim.setInputVoltage(m_motor.getAppliedOutput() * 12.0);
m_motorSim.update(0.02); // Advance simulation by 20ms
// 2. Update the simulated sensor with the model's output
m_encoderSim.setDistance(m_motorSim.getAngularPositionRad());
m_encoderSim.setRate(m_motorSim.getAngularVelocityRadPerSec());
}
// This method is called on the real robot OR in simulation
@Override
public void periodic() {
// Real sensor updates would happen here, but for an encoder,
// the hardware does it automatically. We might log data here.
}
}
Question: In an FRC project, which subsystem method is called repeatedly, but ONLY when the code is running in simulation mode?