Dépannage
Dépannage des échecs complets
Il y a un certain nombre de choses qui peuvent amener votre robot à complètement avoir le mauvais comportement. La liste de vérification ci-dessous couvre les erreurs les plus courantes.
Mon robot ne bouge pas.
Produisez-vous réellement vos moteurs?
Une
MalformedSplineException
est-elle imprimée sur le poste de conduite? Si oui, passez à la sectionMalformedSplineException
ci-dessous.Votre trajectoire est-elle très courte ou dans les mauvaises unités?
Mon robot pivote pour suivre la trajectoire dans l’autre sens.
Les titres de début et de fin de votre trajectoire sont-ils incorrects?
Le gyroscope de votre robot est-il réinitialisé dans la mauvaise direction?
Vos angles gyroscopiques sont-ils positifs dans le sens horaire? Si oui, vous devez inverser le signe (nouvel angle = 0 - angle gyro).
Mon robot roule en ligne droite même s’il doit tourner.
Votre gyroscope est-il correctement configuré et renvoie-t-il de bonnes données?
Utilisez-vous les bonnes unités de mesure lorsque vous passez votre cap gyroscopique à votre objet odométrique ?
La largeur spécifiée de votre robot (track width) est-elle correcte? Est-ce dans les bonnes unités?
Je reçois un message
MalformedSplineException
sur le poste de pilotage et le robot ne bouge pas.Avez-vous deux points de cheminement très proches l’un de l’autre avec des caps diamétralement opposés?
Avez-vous deux points de cheminement avec les mêmes (ou presque les mêmes) coordonnées?
Mon robot va trop loin.
Vos conversions d’unités d’encodeur sont-elles correctement configurées?
Vos encodeurs sont-ils connectés?
Mon robot fait surtout ce qu’il faut, mais c’est un peu inexact.
Passez à la section suivante.
Dépannage des mauvaises performances
Note
Cette section concerne principalement le dépannage des performances de suivi de trajectoire médiocres, comme une erreur de positionnement de 1 mètre, et non les défaillances catastrophiques comme les erreurs de compilation, les robots se retournant et allant dans la mauvaise direction, ou les erreurs comme MalformedSplineException
s.
Note
Cette section est conçue pour les robots à entraînement différentiel, mais la plupart des idées peuvent être adaptées pour les robots de type Swerve ou Mécanum
Les mauvaises performances de suivi de trajectoire peuvent être difficiles à dépanner. Bien que le générateur de trajectoire et le suiveur soient faciles à utiliser et performants tel quel, il y a des situations où votre robot n’accomplit pas toute sa trajectoire. Le générateur de trajectoire et les suiveurs ont de nombreux ajustements logiciels et mécaniques, il peut donc être difficile de savoir par où commencer, en particulier parce qu’il est difficile de localiser la source des problèmes de trajectoire à partir du comportement général du robot.
Parce qu’il peut être si difficile de localiser la section du générateur de trajectoire et des suiveurs qui est fautive, une approche systématique, étape par étape est recommandée pour les mauvaises performances de suivi générales (comme exemple, le robot a dévié de 20 degrés ou est hors-parcours de quelques pieds). Les étapes ci-dessous sont répertoriées dans l’ordre dans lequel vous devez les effectuer; il est important de suivre cet ordre afin de pouvoir isoler les effets des différentes étapes les unes des autres.
Note
Les exemples ci-dessous mettent des valeurs de diagnostic sur les NetworkTables. La façon la plus simple de représenter graphiquement ces valeurs est d’utiliser les capacités graphiques de Shuffleboard.
Vérifier l’odométrie
Si votre odométrie est mauvaise, votre contrôleur Ramsete peut se comporter de façon erronée, car il modifie les vitesses cibles de votre robot en fonction de l’endroit où votre odométrie pense que le robot se trouve.
Note
Envoi de la pose et de la trajectoire de votre robot à field2d peut aider à vérifier que votre robot se déplace correctement par rapport à sa trajectoire.
Configurez votre code pour enregistrer la position de votre robot après chaque mise à jour de l’odométrie:
NetworkTableEntry m_xEntry = NetworkTableInstance.getDefault().getTable("troubleshooting").getEntry("X");
NetworkTableEntry m_yEntry = NetworkTableInstance.getDefault().getTable("troubleshooting").getEntry("Y");
@Override
public void periodic() {
// Update the odometry in the periodic block
m_odometry.update(Rotation2d.fromDegrees(getHeading()), m_leftEncoder.getDistance(),
m_rightEncoder.getDistance());
var translation = m_odometry.getPoseMeters().getTranslation();
m_xEntry.setNumber(translation.getX());
m_yEntry.setNumber(translation.getY());
}
NetworkTableEntry m_xEntry = nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting")->GetEntry("X");
NetworkTableEntry m_yEntry = nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting")->GetEntry("Y");
void DriveSubsystem::Periodic() {
// Implementation of subsystem periodic method goes here.
m_odometry.Update(frc::Rotation2d(units::degree_t(GetHeading())),
units::meter_t(m_leftEncoder.GetDistance()),
units::meter_t(m_rightEncoder.GetDistance()));
auto translation = m_odometry.GetPose().Translation();
m_xEntry.SetDouble(translation.X().value());
m_yEntry.SetDouble(translation.Y().value());
}
Disposez un ruban à mesurer parallèle à votre robot et poussez votre robot d’environ un mètre le long du ruban à mesurer. Disposez un ruban à mesurer le long de l’axe Y et recommencez, en poussant votre robot d’un mètre le long de l’axe X et d’un mètre le long de l’axe Y en arc de cercle.
Compare X and Y reported by the robot to actual X and Y. If X is off by more than 5 centimeters in the first test then you should check that you measured your wheel diameter correctly, and that your wheels are not worn down. If the second test is off by more than 5 centimeters in either X or Y then your track width (distance from the center of the left wheel to the center of the right wheel) may be incorrect; if you’re sure that you measured the track width correctly with a tape measure then your robot’s wheels may be slipping in a way that is not accounted for by track width, so try increasing the track width number or measuring it programmatically.
Vérifier la fonction Feedforward
Si vos informations sont mauvaises, les contrôleurs P de chaque côté du robot ne suivront pas aussi bien et votre DifferentialDriveVoltageConstraint
ne limitera pas l’accélération de votre robot avec précision. Nous voulons surtout désactiver les contrôleurs P de la roue afin de pouvoir isoler et tester les feedforwards.
Tout d’abord, nous devons désactiver le paramètre P pour neutraliser le PID pour chaque roue. Réglez le gain
P
à 0 pour chaque contrôleur. Dans l’exempleRamseteCommand
, vous définiriezkPDriveVel
à 0:
123 new PIDController(DriveConstants.kPDriveVel, 0, 0),
124 new PIDController(DriveConstants.kPDriveVel, 0, 0),
81 frc::PIDController{DriveConstants::kPDriveVel, 0, 0},
82 frc::PIDController{DriveConstants::kPDriveVel, 0, 0},
Ensuite, nous voulons désactiver le contrôleur Ramsete pour faciliter l’isolement de notre comportement problématique. Pour ce faire, invoquer simplement la méthode
setEnabled(false)
surRamseteController
passé à votreRamseteCommand
:
RamseteController m_disabledRamsete = new RamseteController();
m_disabledRamsete.setEnabled(false);
// Be sure to pass your new disabledRamsete variable
RamseteCommand ramseteCommand = new RamseteCommand(
exampleTrajectory,
m_robotDrive::getPose,
m_disabledRamsete,
...
);
frc::RamseteController m_disabledRamsete;
m_disabledRamsete.SetEnabled(false);
// Be sure to pass your new disabledRamsete variable
frc2::RamseteCommand ramseteCommand(
exampleTrajectory,
[this]() { return m_drive.GetPose(); },
m_disabledRamsete,
...
);
Enfin, nous devons enregistrer la vitesse de roue souhaitée et la vitesse de roue réelle (vous devez mettre les vitesses réelles et souhaitées sur le même graphique si vous utilisez Shuffleboard, ou si votre logiciel graphique a cette capacité):
var table = NetworkTableInstance.getDefault().getTable("troubleshooting");
var leftReference = table.getEntry("left_reference");
var leftMeasurement = table.getEntry("left_measurement");
var rightReference = table.getEntry("right_reference");
var rightMeasurement = table.getEntry("right_measurement");
var leftController = new PIDController(kPDriveVel, 0, 0);
var rightController = new PIDController(kPDriveVel, 0, 0);
RamseteCommand ramseteCommand = new RamseteCommand(
exampleTrajectory,
m_robotDrive::getPose,
disabledRamsete, // Pass in disabledRamsete here
new SimpleMotorFeedforward(ksVolts, kvVoltSecondsPerMeter, kaVoltSecondsSquaredPerMeter),
kDriveKinematics,
m_robotDrive::getWheelSpeeds,
leftController,
rightController,
// RamseteCommand passes volts to the callback
(leftVolts, rightVolts) -> {
m_robotDrive.tankDriveVolts(leftVolts, rightVolts);
leftMeasurement.setNumber(m_robotDrive.getWheelSpeeds().leftMetersPerSecond);
leftReference.setNumber(leftController.getSetpoint());
rightMeasurement.setNumber(m_robotDrive.getWheelSpeeds().rightMetersPerSecond);
rightReference.setNumber(rightController.getSetpoint());
},
m_robotDrive
);
auto table =
nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting");
auto leftRef = table->GetEntry("left_reference");
auto leftMeas = table->GetEntry("left_measurement");
auto rightRef = table->GetEntry("right_reference");
auto rightMeas = table->GetEntry("right_measurement");
frc::PIDController leftController(DriveConstants::kPDriveVel, 0, 0);
frc::PIDController rightController(DriveConstants::kPDriveVel, 0, 0);
frc2::RamseteCommand ramseteCommand(
exampleTrajectory, [this]() { return m_drive.GetPose(); },
frc::RamseteController(AutoConstants::kRamseteB,
AutoConstants::kRamseteZeta),
frc::SimpleMotorFeedforward<units::meters>(
DriveConstants::ks, DriveConstants::kv, DriveConstants::ka),
DriveConstants::kDriveKinematics,
[this] { return m_drive.GetWheelSpeeds(); }, leftController,
rightController,
= <auto left, auto right>__ {
auto leftReference = leftRef;
auto leftMeasurement = leftMeas;
auto rightReference = rightRef;
auto rightMeasurement = rightMeas;
m_drive.TankDriveVolts(left, right);
leftMeasurement.SetDouble(m_drive.GetWheelSpeeds().left.value());
leftReference.SetDouble(leftController.GetSetpoint());
rightMeasurement.SetDouble(m_drive.GetWheelSpeeds().right.value());
rightReference.SetDouble(rightController.GetSetpoint());
},
{&m_drive});
Exécutez le robot sur une variété de trajectoires (courbe et ligne droite) et vérifiez si la vitesse réelle suit la vitesse souhaitée en regardant les graphiques de NetworkTables.
Si les valeurs souhaitées et réelles sont beaucoup différentes, vous devez vérifier si le diamètre de la roue et l”
encoderEPR
que vous avez utilisés pour l’identification du système étaient corrects. Si vous avez vérifié que vos unités et vos conversions sont correctes, vous devriez essayer de requalifier au même étage que celui sur lequel vous testez pour voir si vous pouvez obtenir de meilleures données.
Vérifiez le gain proportionnel P
Si vous avez effectué l’étape précédente et que le problème est réglé, alors le problème initial se situe peut-être dans la boucle de contrôle. Dans cette étape, nous allons vérifier que les paramètres P pour les contrôleurs de roue soient bien réglés. Si vous utilisez Java, nous voulons désactiver Ramsete afin que nous puissions simplement visualiser nos contrôleurs PF par eux-mêmes.
Vous devez réutiliser tout le code de l’étape précédente qui enregistre la vitesse réelle par rapport à la vitesse souhaitée (et le code qui désactive Ramsete, si vous utilisez Java), sauf que le gain P doit être ramené à sa valeur initiale
Exécutez à nouveau le robot sur une variété de trajectoires et vérifiez que vos graphiques réels et souhaités semblent bons
Si les graphiques ne semblent pas bons (c’est-à-dire que la vitesse réelle est très différente de celle souhaitée), vous devriez essayer de régler votre gain P et de réexécuter vos trajectoires de test.
Vérifier les contraintes
Note
Assurez-vous que votre gain P est différent de zéro pour cette étape et que vous avez toujours le code de prises de données ajouté dans les étapes précédentes. Si vous utilisez Java, vous devez supprimer le code pour désactiver Ramsete.
Si votre problème de précision a persisté à travers toutes les étapes précédentes, vous pourriez avoir un problème avec vos contraintes. Vous trouverez ci-dessous une liste des symptômes que les différentes contraintes disponibles présenteront lorsqu’elles sont mal réglées.
Vérifiez une seule contrainte à la fois! Supprimez les autres contraintes, ajustez l’unique contrainte restante et répétez ce processus pour chaque contrainte que vous souhaitez vérifier. La liste de contrôle ci-dessous suppose que vous n’utilisez qu’une seule contrainte à la fois.
DifferentialDriveVoltageConstraint
:Si votre robot accélère très lentement, il est possible que la tension maximale (voltage) pour cette contrainte soit trop faible.
Si votre robot n’atteint pas la fin du chemin, les données d’identification de votre système peuvent être problématiques.
DifferentialDriveKinematicsConstraint
:Si le cap de votre robot est orienté vers la mauvaise direction, il est possible que la vitesse maximale permise du contrôleur soit trop faible ou trop élevée. La seule façon de vérifier cela est d’ajuster la vitesse maximale à une valeur différente et de voir ce qui se passe.
CentripetalAccelerationConstraint
:Si le cap de votre robot pointe vers la mauvaise direction, ce paramètre ci-haut pourrait être le coupable. Si votre robot ne semble pas tourner suffisamment, vous devez augmenter l’accélération centripète maximale, mais s’il semble faire des virages serrés trop rapidement, vous devez diminuer l’accélération centripète maximale.
Vérifier les points de cheminement de la trajectoire
Il est possible que votre trajectoire elle-même ne soit pas très pilotable. Essayez de déplacer certains points de cheminement (et les caps aux points de cheminement, le cas échéant) pour réduire les virages serrés.