Changements apportés lors de la réécriture de 2020

Cet article fournit un résumé des changements à partir de l’infrastructure logicielle orientée commande d’origine à la réécriture de 2020. Ce résumé n’est pas nécessairement complet - pour une documentation rigoureuse, comme toujours, se référer aux documents API (Java, C++).

Emplacement du package

Le nouveau cadre d’application orienté commandes se trouve dans le package wpilibj2 pour Java, et dans l’espace de nommage frc2 pour C++. L’ancien cadre d’application orienté commandes est toujours disponible à l’emplacement d’origine. Le nouveau cadre d’application doit être installé en suivant les instructions: Librairies des commandes WPILib.

Changements architecturaux majeurs

Dans l’ensemble, la structure du cadre d’application orienté commande est restée la même. Il y a toutefois certains changements architecturaux majeurs dont les utilisateurs doivent être conscients :

Commandes et sous-systèmes en tant qu’interfaces

Command (Java, C++) et Subsystem (Java, C++) sont maintenant des interfaces par opposition aux classes abstraites, permettant aux utilisateurs avancés plus de flexibilité potentielle. Les classes de base abstraites CommandBase et SubsystemBase sont toujours fournies pour plus de commodité, mais ne sont pas nécessaires. Pour plus d’informations, voir Commandes et Les sous-systèmes.

Plusieurs classes de groupes de commandes

La classe CommandGroup n’existe plus : elle a été remplacée par un certain nombre de classes ayant chacune un rôle plus précis. Celles-ci peuvent ensuite être combinées en des hiérarchies plus complexes. Pour plus d’informations, consultez Groupes de commandes.

Définitions de commandes en une seule ligne

Auparavant, les utilisateurs devaient écrire une sous-classe de Command dans presque toutes les situations où une commande était nécessaire. Plusieurs des nouvelles classes sont maintenant conçues pour permettre la définition de commandes en une seule ligne (inline), ce qui évite la déclaration d’une sous-classe explicite. Pour plus d’informations, consultez Fonctions pratiques.

Injection des dépendances des commandes

Bien qu’il ne s’agisse pas d’un réel changement au niveau de la programmation de la bibliothèque, le patron recommandé pour utiliser le nouveau cadre d’application orienté commande est l’injection des sous-systèmes dépendants dans les commandes, ce qui ne requiert plus de déclarer les sous-systèmes comme variables globales. Il s’agit d’un patron beaucoup plus clair, maintenable et réutilisable que la déclaration globale des sous-systèmes, ce qui était anciennement recommandé. Pour plus d’informations, consultez Structurer un projet de robot orienté commande.

Propriété des commandes (seulement en C++)

L’ancien cadre d’application orienté commande requérait l’utilisation de pointeurs primitifs (raw pointers) pour toutes les commandes, ce qui entraînait presque inévitablement des fuites de mémoire dans tous les projets C++ qui utilisaient des commandes. De plus, ces pointeurs rendaient également possibles certaines erreurs courantes telles que la double allocation de commandes dans des groupes de commandes.

Le nouveau cadre d’application offre la gestion de la propriété pour toutes les commandes. Les commandes par défaut et les commandes liées à des boutons sont généralement la propriété du CommandScheduler, et les commandes faisant partie d’un groupe de commandes sont la propriété du groupe qui les encapsule. Par conséquent, les utilisateurs ne devraient presque jamais allouer une commande avec new à moins d’avoir une très bonne raison de le faire.

Le transfert de propriété se fait par transfert parfait ou perfect forwarding, ce qui signifie que les rvalues seront déplacées et que les lvalues seront copiées (en anglais :explication des *rvalues* et des *lvalues*).

Changements à la classe Scheduler

  • La classe Scheduler (planificateur) s’appelle désormais CommandScheduler (Java, C++).

  • L’interruptibilité des commandes est maintenant la responsabilité du CommandScheduler, et non des commandes, ce qui peut être spécifié lors de l’appel à la méthode schedule.

  • Les utilisateurs peuvent à présent passer au CommandScheduler des actions qui seront exécutées chaque fois qu’une commande est programmée, interrompue ou complétée normalement. Cela est très utile pour, par exemple, la journalisation d’événements.

Changements à la classe Subsystem

Note

Pour plus d’informations sur les sous-systèmes, consultez Les sous-systèmes.

  • Tel qu’indiqué précédemment, Subsystem est maintenant une interface (Java, C++); l’équivalent le plus proche de l’ancienne classe Subsystem est la nouvelle classe SubsystemBase. De nombreuses surcharges du constructeur liées à l’interface Sendable ont été supprimées afin de réduire l’encombrement. Les utilisateurs peuvent utiliser les mutateurs (setters) directement dans le constructeur de leurs propres sous-systèmes, si nécessaire.

  • La méthode initDefaultCommand a été supprimée; les sous-systèmes n’ont plus besoin de « connaître » leurs commandes par défaut. Celles-ci sont plutôt configurées directement avec le CommandScheduler. La nouvelle méthode setDefaultCommand encapsule simplement l’appel vers le CommandScheduler.

  • Les sous-systèmes n’ont plus besoin de « connaître » les commandes qui les requièrent à tout moment; cela est géré exclusivement par le CommandScheduler. Cependant, une méthode qui encapsule l’appel vers le CommandScheduler est fournie.

Changements à la classe Command

Note

Pour plus d’informations sur les commandes, consultez Commandes.

  • Tel qu’indiqué précédemment, Command est maintenant une interface (Java, C++); l’équivalent le plus proche de l’ancienne Command est la nouvelle classe CommandBase. De nombreuses surcharges du constructeur liées à l’interface Sendable ont été supprimées afin de réduire l’encombrement. Les utilisateurs peuvent utiliser les mutateurs (setters) directement dans le constructeur de leurs propres commandes, si nécessaire.

  • Les commandes ne gèrent plus l’état de leur planification; il s’agit maintenant la responsabilité de la classe CommandScheduler.

  • La méthode interrupted() a été intégrée dans la méthode end(), qui reçoit désormais un paramètre spécifiant si la commande a été interrompue (false si elle s’est terminée normalement).

  • La méthode requires() s’appelle maintenant addRequirement().

  • La méthode void setRunsWhenDisabled(boolean disabled) a été remplacée par la méthode runsWhenDisabled(), qui peut être redéfinie. Les commandes qui doivent s’exécuter lorsque le robot est désactivé (disabled) doivent redéfinir cette méthode afin qu’elle retourne true.

  • La méthode void setInterruptible(boolean interruptible) a été supprimée. L’interruptibilité n’est plus une propriété des commandes : elle peut être définie lorsque la commande est planifiée.

  • Plusieurs méthodes de « décoration » ont été ajoutées afin de faciliter la modification de commandes en une seule ligne (par exemple, en ajoutant un délai de fin).

  • (C++ seulement) Afin de permettre aux décorateurs de travailler avec le modèle de commande approprié, un CRTP est utilisé via la classe CommandHelper. Toute sous-classe de la classe Command définie par l’utilisateur Foo doit étendre CommandHelper<Foo, Base>` ``Base est la classe de base souhaitée.

Changements aux classes PIDSubsystem et PIDCommand

Note

Pour plus d’informations, consultez Contrôle PID via PIDSubsystems et PIDCommands, and Contrôle PID dans WPILib.

  • Suite aux changements apportés à PIDController, ces classes fonctionnent désormais de manière synchrone à partir de la boucle principale du robot (et non dans un processus séparé).

  • Le PIDController est à présent injecté dans le constructeur, ce qui a permis la suppression de plusieurs méthodes faisant le lien avec le contrôleur. Après l’appel du constructeur, celui-ci peut être modifié en utilisant la méthode getController().

  • PIDCommand est destiné en grande partie à une utilisation en inline, comme le montre l’exemple GyroDriveCommands (Java, C++).

  • Si les utilisateurs souhaitent utiliser PIDCommand de façon plus « traditionnelle », la redéfinition des méthodes protégées returnPIDInput() et usePIDOutput(double output) a été remplacée par la modification des attributs protégés m_measurement et m_useOutput. De même, plutôt que d’appeler la méthode setSetpoint(), les utilisateurs peuvent modifier l’attribut protégé m_setpoint.