Commande prédictive ou par anticipation en WPILib

Note

This article focuses on in-code implementation of feedforward control in WPILib. For a conceptual explanation of the feedforward equations used by WPILib, see Introduction to DC Motor Feedforward

You may have used feedback control (such as PID) for reference tracking (making a system’s output follow a desired reference signal). While this is effective, it’s a reactionary measure; the system won’t start applying control effort until the system is already behind. If we could tell the controller about the desired movement and required input beforehand, the system could react quicker and the feedback controller could do less work. A controller that feeds information forward into the plant like this is called a feedforward controller.

A feedforward controller injects information about the system’s dynamics (like a mathematical model does) or the intended movement. Feedforward handles parts of the control actions we already know must be applied to make a system track a reference, then feedback compensates for what we do not or cannot know about the system’s behavior at runtime.

Les classes FeedForward WPILib

WPILib fournit un certain nombre de classes pour aider les utilisateurs à implémenter une commande feedforward pour leurs mécanismes. À bien des égards, un feedforward précis est plus important que la rétroaction au contrôle efficace d’un mécanisme. Comme la plupart des mécanismes en FRC® obéissent étroitement aux équations bien comprises du système, en commençant par un feedforward précis est à la fois facile et extrêmement bénéfique pour le contrôle précis et robuste du mécanisme

The WPILib feedforward classes closely match the available mechanism characterization tools available in the SysId toolsuite. The system identification toolsuite can be used to quickly and effectively determine the correct gains for each type of feedforward. If you are unable to empirically characterize your mechanism (due to space and/or time constraints), reasonable estimates of kG, kV, and kA can be obtained by fairly simple computation, and are also available from ReCalc. kS is nearly impossible to model, and must be measured empirically.

WPILib fournit actuellement les trois classes suivantes pour le contrôle Feedforward

La classe « SimpleMotorFeedforward »

Note

En C ++, la classe SimpleMotorFeedforward est basée sur le type d’unité utilisé pour les mesures de distance, qui peut être angulaire ou linéaire. Les gains transmis doivent avoir des unités cohérentes avec les unités de distance, sinon une erreur de compilation sera générée. kS doit avoir des unités de volts, kV doit avoir des unités de volts * secondes / distance et kA doit avoir des unités de volts * secondes^2 / distance. Pour plus d’informations sur les unités C ++, voir La librairie d’unités C++.

Note

Les composants Java Feedforward calculent les sorties en unités déterminées par les unités des gains Feedforward fournis par l’utilisateur. Les utilisateurs doivent maintenir la cohérence des unités, car WPILibJ ne dispose pas d’un système d’unités de type sécurisé.

Note

The API documentation for Python feedforward components indicate which unit is being used as wpimath.units.NAME. Users must take care to use correct units, as Python does not have a type-safe unit system.

La classe SimpleMotorFeedforward calcule les valeurs de Feedforward pour les mécanismes qui se composent de moteurs à courant continu à aimant permanent (comme le CIM, Bag, 775…) sans charge externe autre que le frottement et l’inertie, tels que les volants d’inertie et les entraînements de robots.

Pour créer un SimpleMotorFeedforward, il suffit de le construire avec les gains requis:

Note

Le gain kA peut être omis, et s’il l’est, sera par défaut à une valeur de zéro. Pour de nombreux mécanismes, en particulier ceux avec peu d’inertie, ce n’est pas nécessaire.

// Create a new SimpleMotorFeedforward with gains kS, kV, and kA
SimpleMotorFeedforward feedforward = new SimpleMotorFeedforward(kS, kV, kA);
// Create a new SimpleMotorFeedforward with gains kS, kV, and kA
// Distance is measured in meters
frc::SimpleMotorFeedforward<units::meters> feedforward(kS, kV, kA);
from wpimath.controller import SimpleMotorFeedforwardMeters
  # Create a new SimpleMotorFeedforward with gains kS, kV, and kA
# Distance is measured in meters
feedforward = SimpleMotorFeedforwardMeters(kS, kV, kA)

Pour calculer le feedforward, il suffit d’appeler la méthode calculate() avec la vitesse et l’accélération désirées du moteur:

Note

L’argument d’accélération peut être omis de l’appel calculate(), et si c’est le cas, sa valeur par défaut sera zéro. Cela doit être fait chaque fois qu’il n’y a pas de point de consigne d’accélération clairement défini.

// Calculates the feedforward for a velocity of 10 units/second and an acceleration of 20 units/second^2
// Units are determined by the units of the gains passed in at construction.
feedforward.calculate(10, 20);
// Calculates the feedforward for a velocity of 10 meters/second and an acceleration of 20 meters/second^2
// Output is in volts
feedforward.Calculate(10_mps, 20_mps_sq);
# Calculates the feedforward for a velocity of 10 meters/second and an acceleration of 20 meters/second^2
# Output is in volts
feedforward.calculate(10, 20)

La classe ArmFeedforward

Note

En C++, la classe ArmFeedforward suppose que les distances sont angulaires et non linéaires. Les gains transmis doivent avoir des unités cohérentes avec l’unité angulaire, sinon une erreur de compilation sera générée. kS et kG doivent avoir des unités de volts, kV doivent avoir des unités de volts * secondes / radians, et kA doivent avoir des unités de volts * secondes^2 / radians. Pour plus d’informations sur les unités C++, consultez La librairie d’unités C++.

Note

Les composants Java Feedforward calculent les sorties en unités déterminées par les unités des gains Feedforward fournis par l’utilisateur. Les utilisateurs doivent maintenir la cohérence des unités, car WPILibJ ne dispose pas d’un système d’unités de type sécurisé.

Note

The API documentation for Python feedforward components indicate which unit is being used as wpimath.units.NAME. Users must take care to use correct units, as Python does not have a type-safe unit system.

La classe ArmFeedforward calcule les valeurs de Feedforward pour les bras de levier qui sont contrôlés directement par un moteur à courant continu à aimant permanent, avec une charge externe de frottement, d’inertie et de masse du bras. Il s’agit d’un modèle précis qui simule la plupart des bras de levier utilisés en FRC.

Pour créer un ArmFeedforward, il suffit de le construire avec les gains requis:

Note

Le gain kA peut être omis, et s’il l’est, sera par défaut à une valeur de zéro. Pour de nombreux mécanismes, en particulier ceux avec peu d’inertie, ce n’est pas nécessaire.

// Create a new ArmFeedforward with gains kS, kG, kV, and kA
ArmFeedforward feedforward = new ArmFeedforward(kS, kG, kV, kA);
// Create a new ArmFeedforward with gains kS, kG, kV, and kA
frc::ArmFeedforward feedforward(kS, kG, kV, kA);
from wpimath.controller import ArmFeedforward
  # Create a new ArmFeedforward with gains kS, kG, kV, and kA
feedforward = ArmFeedforward(kS, kG, kV, kA)

Pour calculer le Feedforward, il suffit d’appeler la méthode calculate() avec la position, la vitesse et l’accélération souhaitées du bras de levier:

Note

L’argument d’accélération peut être omis de l’appel calculate(), et si c’est le cas, sa valeur par défaut sera zéro. Cela doit être fait chaque fois qu’il n’y a pas de point de consigne d’accélération clairement défini.

// Calculates the feedforward for a position of 1 units, a velocity of 2 units/second, and
// an acceleration of 3 units/second^2
// Units are determined by the units of the gains passed in at construction.
feedforward.calculate(1, 2, 3);
// Calculates the feedforward for a position of 1 radians, a velocity of 2 radians/second, and
// an acceleration of 3 radians/second^2
// Output is in volts
feedforward.Calculate(1_rad, 2_rad_per_s, 3_rad/(1_s * 1_s));
# Calculates the feedforward for a position of 1 radians, a velocity of 2 radians/second, and
# an acceleration of 3 radians/second^2
# Output is in volts
feedforward.calculate(1, 2, 3)

La classe ElevatorFeedforward

Note

In C++, the passed-in gains must have units consistent with the distance units, or a compile-time error will be thrown. kS and kG should have units of volts, kV should have units of volts * seconds / distance, and kA should have units of volts * seconds^2 / distance. For more information on C++ units, see La librairie d’unités C++.

Note

Les composants Java Feedforward calculent les sorties en unités déterminées par les unités des gains Feedforward fournis par l’utilisateur. Les utilisateurs doivent maintenir la cohérence des unités, car WPILibJ ne dispose pas d’un système d’unités de type sécurisé.

Note

The API documentation for Python feedforward components indicate which unit is being used as wpimath.units.NAME. Users must take care to use correct units, as Python does not have a type-safe unit system.

La classe ElevatorFeedforward calcule les feed-back pour un mécanisme de type ascenseur qui se composent de moteurs à courant continu à aimant permanent chargés par le frottement, l’inertie et la masse de charge déplacée par l’ascenseur. Il s’agit d’un modèle précis de la plupart des mécanismes d’ascenseurs en FRC.

Pour créer un ElevatorFeedforward, il suffit de le construire avec les gains requis:

Note

Le gain kA peut être omis, et s’il l’est, sera par défaut à une valeur de zéro. Pour de nombreux mécanismes, en particulier ceux avec peu d’inertie, ce n’est pas nécessaire.

// Create a new ElevatorFeedforward with gains kS, kG, kV, and kA
ElevatorFeedforward feedforward = new ElevatorFeedforward(kS, kG, kV, kA);
// Create a new ElevatorFeedforward with gains kS, kV, and kA
// Distance is measured in meters
frc::ElevatorFeedforward feedforward(kS, kG, kV, kA);
from wpimath.controller import ElevatorFeedforward
  # Create a new ElevatorFeedforward with gains kS, kV, and kA
# Distance is measured in meters
feedforward = ElevatorFeedforward(kS, kG, kV, kA)

Pour calculer le feedforward, il suffit d’appeler la méthode calculate() avec la vitesse et l’accélération désirées du moteur:

Note

L’argument d’accélération peut être omis de l’appel calculate(), et si c’est le cas, sa valeur par défaut sera zéro. Cela doit être fait chaque fois qu’il n’y a pas de point de consigne d’accélération clairement défini.

// Calculates the feedforward for a velocity of 20 units/second
// and an acceleration of 30 units/second^2
// Units are determined by the units of the gains passed in at construction.
feedforward.calculate(20, 30);
// Calculates the feedforward for a velocity of 20 meters/second
// and an acceleration of 30 meters/second^2
// Output is in volts
feedforward.Calculate(20_mps, 30_mps_sq);
# Calculates the feedforward for a velocity of 20 meters/second
# and an acceleration of 30 meters/second^2
# Output is in volts
feedforward.calculate(20, 30)

Utilisation de Feedforward pour contrôler les mécanismes

Note

Since feedforward voltages are physically meaningful, it is best to use the setVoltage() (Java, C++, Python) method when applying them to motors to compensate for « voltage sag » from the battery.

Le contrôle par anticipation (Feedforward) peut être utilisé à lui seul, sans contrôleur de rétroaction. Ceci est connu sous le nom de contrôle « en boucle ouverte », et pour de nombreux mécanismes (en particulier les moteurs qui font avancer le robot) peuvent être parfaitement satisfaisants. Un SimpleMotorFeedforward peut être utilisé pour contrôler un entraînement de robot comme suit:

public void tankDriveWithFeedforward(double leftVelocity, double rightVelocity) {
  leftMotor.setVoltage(feedforward.calculate(leftVelocity));
  rightMotor.setVoltage(feedForward.calculate(rightVelocity));
}
void TankDriveWithFeedforward(units::meters_per_second_t leftVelocity,
                              units::meters_per_second_t rightVelocity) {
  leftMotor.SetVoltage(feedforward.Calculate(leftVelocity));
  rightMotor.SetVoltage(feedforward.Calculate(rightVelocity));
}
def tankDriveWithFeedforward(self, leftVelocity: float, rightVelocity: float):
    self.leftMotor.setVoltage(feedForward.calculate(leftVelocity))
    self.rightMotor.setVoltage(feedForward.calculate(rightVelocity))