Simulation with WPILibSimulator Lesson

Simulation with WPILibSimulator

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 2910 Advantage: Concurrent Engineering

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 It Works: `simulationPeriodic()`

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()`.

The Separation of Real and Simulated

  • `periodic()`: This method is called every 20ms on the real robot. It's where we get real sensor feedback.
  • `simulationPeriodic()`: This method is called every 20ms only when in simulation mode. It's where we use a physics model to update our simulated sensors.

A Simplified Arm Subsystem Example

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.
    }
}
    

Test Your Knowledge

Question: In an FRC project, which subsystem method is called repeatedly, but ONLY when the code is running in simulation mode?