Paso 3: Actualización del modelo de transmisión

Ahora que se ha hecho el modelo de transmisión, necesita ser actualizado periódicamente con los últimos comandos de voltaje del motor. Se recomienda hacer este paso en un método separado simulationPeriodic() / SimulationPeriodic() dentro de su subsistema y sólo llamar a este método en la simulación.

Nota

If you are using the command-based framework, every subsystem that extends SubsystemBase has a simulationPeriodic() / SimulationPeriodic() which can be overridden. This method is automatically run only during simulation. If you are not using the command-based library, make sure you call your simulation method inside the overridden simulationPeriodic() / SimulationPeriodic() of the main Robot class. These periodic methods are also automatically called only during simulation.

Hay tres pasos principales para actualizar el modelo:

  1. Establezca el entrada del modelo de transmisión. Estos son los voltajes del motor de los dos lados del tren de transmisión.

  2. Haga avanzar el modelo en el tiempo por el paso de tiempo periódico nominal (generalmente 20 ms). Esto actualiza todos los estados de la transmisión (es decir, pose, posiciones del codificador y velocidades) como si hubieran pasado los 20 ms.

  3. Actualice los sensores simulados con nuevas posiciones, velocidades y ángulos para usar en otros lugares.

private PWMSparkMax m_leftMotor = new PWMSparkMax(0);
private PWMSparkMax m_rightMotor = new PWMSparkMax(1);

public Drivetrain() {
  ...
  m_leftEncoder.setDistancePerPulse(2 * Math.PI * kWheelRadius / kEncoderResolution);
  m_rightEncoder.setDistancePerPulse(2 * Math.PI * kWheelRadius / kEncoderResolution);
}

public void simulationPeriodic() {
  // Set the inputs to the system. Note that we need to convert
  // the [-1, 1] PWM signal to voltage by multiplying it by the
  // robot controller voltage.
  m_driveSim.setInputs(m_leftMotor.get() * RobotController.getInputVoltage(),
                       m_rightMotor.get() * RobotController.getInputVoltage());

  // Advance the model by 20 ms. Note that if you are running this
  // subsystem in a separate thread or have changed the nominal timestep
  // of TimedRobot, this value needs to match it.
  m_driveSim.update(0.02);

  // Update all of our sensors.
  m_leftEncoderSim.setDistance(m_driveSim.getLeftPositionMeters());
  m_leftEncoderSim.setRate(m_driveSim.getLeftVelocityMetersPerSecond());
  m_rightEncoderSim.setDistance(m_driveSim.getRightPositionMeters());
  m_rightEncoderSim.setRate(m_driveSim.getRightVelocityMetersPerSecond());
  m_gyroSim.setAngle(-m_driveSim.getHeading().getDegrees());
}
frc::PWMSparkMax m_leftMotor{0};
frc::PWMSparkMax m_rightMotor{1};

Drivetrain() {
  ...
  m_leftEncoder.SetDistancePerPulse(2 * std::numbers::pi * kWheelRadius / kEncoderResolution);
  m_rightEncoder.SetDistancePerPulse(2 * std::numbers::pi * kWheelRadius / kEncoderResolution);
}

void SimulationPeriodic() {
  // Set the inputs to the system. Note that we need to convert
  // the [-1, 1] PWM signal to voltage by multiplying it by the
  // robot controller voltage.
  m_driveSim.SetInputs(
    m_leftMotor.get() * units::volt_t(frc::RobotController::GetInputVoltage()),
    m_rightMotor.get() * units::volt_t(frc::RobotController::GetInputVoltage()));

  // Advance the model by 20 ms. Note that if you are running this
  // subsystem in a separate thread or have changed the nominal timestep
  // of TimedRobot, this value needs to match it.
  m_driveSim.Update(20_ms);

  // Update all of our sensors.
  m_leftEncoderSim.SetDistance(m_driveSim.GetLeftPosition().value());
  m_leftEncoderSim.SetRate(m_driveSim.GetLeftVelocity().value());
  m_rightEncoderSim.SetDistance(m_driveSim.GetRightPosition().value());
  m_rightEncoderSim.SetRate(m_driveSim.GetRightVelocity().value());
  m_gyroSim.SetAngle(-m_driveSim.GetHeading().Degrees());
}

Importante

Si el lado derecho de su transmisión está invertido, DEBE negar el voltaje correcto en la llamada SetInputs() para asegurarse de que los voltajes positivos corresponden al movimiento hacia adelante.

Importante

Debido a que el modelo del simulador de tren de conducción devuelve las posiciones y las velocidades en metros y m/s respectivamente, éstas deben ser convertidas en ticks de codificación y ticks/s cuando se llama a SetDistance() y SetRate(). Alternativamente, puedes configurar SetDistancePerPulse en los codificadores para que el objeto Encoder se encargue de esto automáticamente - este es el enfoque que se toma en el ejemplo anterior.

Ahora que las posiciones simuladas del codificador, las velocidades y los ángulos del giroscopio se han establecido, puedes llamar a m_leftEncoder.GetDistance(), etc. en tu código de robot como normalmente y se comportará exactamente como lo haría en un robot real. Esto implica realizar cálculos de odometría, ejecutar bucles de retroalimentación PID de velocidad para el seguimiento de la trayectoria, etc.