Skip to content

Kitbot Drivetrain Simulation

It’s common to write code without having immediate access to a physical robot to test changes. Luckily, your computer can also run robot code allowing it to be tested without a robot. While there are some things that can be tested by simulating pure robot code, there are no physical motors to move and respond with new positions. Instead we use simulation classes that use physics to take the desired input voltage to the motors and estimate how the physical mechanism would respond and update our motor controller instances to match. For this stage custom classes have been provided that abstract away much of this logic. You can find these files under the simulation folder if you would like to read the implementation. You can also read the WPILib docs on simulation if you would like to learn more about simulation.

To simulate the drivetrain another class needs to instantiated in Robot.java. Create an instance of the DrivetrainSim class under the DifferentialDrive instance using the left and right Leader motors as inputs. This class will read the voltage commanded to the motors and, using its physics sim, update the motor controllers with new positions. The class will then publish the new drivetrain position and additional motor data so it can be viewed in AdvantageScope.

private DrivetrainSim drivetrainSim = new DrivetrainSim(leftLeader, rightLeader);

Robot code needs to be run in a loop so that it can continually make new commands to motor controllers based on new controller and sensor input. To accomplish this Periodic Methods are provided in the Robot class and OpMode classes. Periodic methods get called every 20ms by default, causing any code placed inside of them to be run 50 times per second. OpModeRobot has additional periodic methods that only run during specific robot states. For example, the teleopPeriodic() function will only be called when teleop mode is selected on the driverstation.

At the moment DrivetrainSim will not actually do anything because it is not being told to update periodically. To fix this, DrivetrainSim’s periodic() function should be called inside of the Robot class’ simulationPeriodic() function.

@Override
public void simulationPeriodic() {
drivetrainSim.periodic();
Note

The simulation class is updated inside of simulationPeriodic() so it only gets updated when the robot code is simulated. This ensures that it doesn’t interfere with the motor controllers when the code is being ran on a real robot.

After adding the simulation code your Robot.java file should now look like this

Solution
/**
* The methods in this class are called automatically as described in the OpModeRobot documentation.
* OpMode classes anywhere in the package (or sub-packages) where this class is located are
* automatically registered to display in the Driver Station. If you change the name of this class
* or the package after creating this project, you must also update the Main.java file in the
* project.
*/
public class Robot extends OpModeRobot {
private final int leftLeaderID = 0;
public TalonFX leftLeader = new TalonFX(leftLeaderID, CANBus.systemcore(0));
private TalonFX leftFollower = new TalonFX(1, CANBus.systemcore(0));
private final int rightLeaderID = 2;
public TalonFX rightLeader = new TalonFX(rightLeaderID, CANBus.systemcore(0));
private TalonFX rightFollower = new TalonFX(3, CANBus.systemcore(0));
public final DifferentialDrive drivetrain =
new DifferentialDrive(leftLeader::setThrottle, rightLeader::setThrottle);
private OnboardIMU imu = new OnboardIMU(MountOrientation.FLAT);
private DrivetrainSim drivetrainSim = new DrivetrainSim(leftLeader, rightLeader);
/**
* This function is run when the robot is first started up and should be used for any
* initialization code.
*/
public Robot() {
var leftConfig = new TalonFXConfiguration();
leftConfig.MotorOutput.withInverted(InvertedValue.Clockwise_Positive);
leftLeader.getConfigurator().apply(leftConfig);
leftFollower.getConfigurator().apply(leftConfig);
leftFollower.setControl(new Follower(leftLeaderID, MotorAlignmentValue.Aligned));
var rightConfig = new TalonFXConfiguration();
rightConfig.MotorOutput.withInverted(InvertedValue.CounterClockwise_Positive);
rightLeader.getConfigurator().apply(rightConfig);
rightFollower.getConfigurator().apply(rightConfig);
rightFollower.setControl(new Follower(rightLeaderID, MotorAlignmentValue.Aligned));
}
@Override
public void simulationPeriodic() {
drivetrainSim.periodic();
intakeLauncherSim.periodic();
feederSim.periodic();
}

When simulating code there are two main windows to control and visualize what the code is doing.

The first important window is the Sim GUI. The Sim GUI is automatically opened when simulating code and acts as both a driverstation and shows information about simulated devices such as position and velocity. More information about the Sim GUI can be found in WPILIb’s documentation.

The other important window is a program called AdvantageScope. AdvantageScope is bundled with WPILib and is used to visualize data sent by the robot. The main tabs used in AdvantageScope are Line Graph, used to graph numeric data such as a motors current position, and 2D Field used to visualize positions on the field. AdvantageScope can also be used to assist in debugging by visualizing logs generated by the robot during a match. More information about using AdvantageScope can be found at their docs.

The first step in simulating code is opening AdvantageScope and loading the layout stored as AdvantageScopeLayout.json in the top level of the robot project.

Next, use the WPILib icon in the upper right corner of VS Code to open the command palette and select WPILib: Simulate Robot Code. This starts the simulation and opens the Sim GUI.

Finally connect AdvantageScope to the simulation and select MyTeleop as the current OpMode. Now when you enable the robot using the Sim GUI the robot should now be able to be controlled using WASD.