Étape 3: Mise à jour du modèle de transmission
Maintenant que le modèle de transmission a été créé, il doit être mis à jour périodiquement avec les dernières commandes de tension du moteur. Il est recommandé de faire cette étape dans une méthode séparée simulationPeriodic()
/ SimulationPeriodic()
dans votre sous-système et d’appeler cette méthode uniquement en simulation.
Note
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.
La mise à jour du modèle comporte trois étapes principales:
Définissez l’ entrée du modèle de transmission. Ce sont les tensions du moteur des deux côtés de la transmission.
Avancez le modèle dans le temps du pas de temps périodique nominal (généralement 20 ms). Cela met à jour tous les états de la transmission (c’est-à-dire la pose, les positions de l’encodeur et les vitesses) comme si 20 ms s’étaient écoulés.
Mettez à jour les capteurs simulés avec de nouvelles positions, vitesses et angles.
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());
}
Important
Si le côté droit de votre transmission est inversé, vous DEVEZ inverser le signe de la tension dans l’appel SetInputs()
pour vous assurer que les tensions positives correspondent au mouvement vers l’avant.
Important
Étant donné que le modèle de simulateur de transmission renvoie respectivement les positions et les vitesses en mètres et en m/s, celles-ci doivent être converties en ticks d’encodeur lors de l’appel de SetDistance()
et SetRate()
. Alternativement, vous pouvez configurer SetDistancePerPulse
sur les encodeurs pour que l’objet Encoder
s’en charge automatiquement - c’est l’approche qui est adoptée dans l’exemple ci-dessus.
Maintenant que les positions, les vitesses et les angles du gyroscope simulés ont été définis, vous pouvez appeler m_leftEncoder.GetDistance()
, etc. dans le code de votre robot comme d’habitude et il se comportera exactement comme il le ferait sur un vrai robot. Cela implique d’effectuer des calculs d’odométrie, des boucles de rétroaction PID de vitesse pour le suivi de trajectoire, etc.