Step 4: Updating Odometry and Visualizing Robot Position

Now that the simulated encoder positions, velocities, and gyro angles are being updated with accurate information periodically, this data can be used to update the pose of the robot in a periodic loop (such as the periodic() method in a Subsystem). In simulation, the periodic loop will use simulated encoder and gyro readings to update odometry whereas on the real robot, the same code will use real readings from physical hardware.

Note

For more information on using odometry, see this document.

Robot Pose Visualization

The robot pose can be visualized on the Simulator GUI (during simulation) or on a dashboard such as Glass (on a real robot) by sending the odometry pose over a Field2d object. A Field2d can be trivially constructed without any constructor arguments:

private Field2d m_field = new Field2d();
#include <frc/smartdashboard/Field2d.h>
...
frc::Field2d m_field;

This Field2d instance must then be sent over NetworkTables. The best place to do this is in the constructor of your subsystem.

public Drivetrain() {
  ...
  SmartDashboard.putData("Field", m_field);
}
#include <frc/smartdashboard/SmartDashboard.h>
Drivetrain() {
  ...
  frc::SmartDashboard::PutData("Field", &m_field);
}

Note

The Field2d instance can also be sent using a lower-level NetworkTables API or using the Shuffleboard API.

Finally, the pose from your odometry must be updated periodically into the Field2d object. Remember that this should be in a general periodic() method i.e. one that runs both during simulation and during real robot operation.

public void periodic() {
  ...
  // This will get the simulated sensor readings that we set
  // in the previous article while in simulation, but will use
  // real values on the robot itself.
  m_odometry.update(m_gyro.getRotation2d(),
                    m_leftEncoder.getDistance(),
                    m_rightEncoder.getDistance());
  m_field.setRobotPose(m_odometry.getPoseMeters());
}
void Periodic() {
  ...
  // This will get the simulated sensor readings that we set
  // in the previous article while in simulation, but will use
  // real values on the robot itself.
  m_odometry.Update(m_gyro.GetRotation2d(),
                    units::meter_t(m_leftEncoder.GetDistance()),
                    units::meter_t(m_rightEncoder.GetDistance()));
  m_field.SetRobotPose(m_odometry.GetPose());
}

Important

It is important that this code is placed in a regular periodic() method – one that is called periodically regardless of mode of operation. If you are using the command-based library, this method already exists. If not, you are responsible for calling this method periodically from the main Robot class.

Note

At this point we have covered all of the code changes required to run your code. You should head to the Simulation User Interface page for more info on how to run the simulation and the Field2d Widget page to add the field that your simulated robot will run on to the GUI.