Qu’est-ce que la programmation « orientée commande » ?

WPILib supporte une méthodologie de programmation robot appelée programmation « orientée commande. » L’expression « orientée commande » peut faire référence à la fois au paradigme général de programmation et à l’ensemble des fonctionnalités incluses dans WPILib afin de faciliter l’utilisation de ce paradigme.

La programmation « orientée commande  » est un exemple de ce que l’on appelle un patron de conception.. C’est une méthode générale d’organiser le code de son robot qui est bien adaptée à une problématique spécifique. Il ne s’agit pas de la seule façon d’écrire le programme d’un robot, mais c’est une méthode très efficace : un programme « orienté commande » a tendance à être plus clair, extensible et (avec quelques astuces) facile à réutiliser d’année en année.

Le paradigme orienté commande est également un exemple de ce que l’on appelle la programmation déclarative. En programmation déclarative, l’accent est mis sur ce que le programme doit faire, et non sur comment il doit le faire. Ainsi, les bibliothèques orientées commande permettent aux utilisateurs de définir les comportements du robot tout en minimisant la quantité de code à écrire pour gérer la logique d’itération en itération du programme. Par exemple, dans un programme orienté commande, l’utilisateur peut spécifier que « le robot doit effectuer une action lorsqu’un bouton est appuyé » (remarquez l’utilisation d’une expression lambda):

aButton.whenPressed(intake::run);

En revanche, dans un programme impératif classique, l’utilisateur devrait vérifier l’état du bouton à chaque itération, et effectuer l’action appropriée en fonction de l’état du bouton.

if(aButton.get()) {
  if(!pressed) {
    intake.run();
    pressed = true;
  }
} else {
  pressed = false;
}

Sous-systèmes et commandes

image of subsystems and commands

Le patron orienté commande repose sur deux abstractions fondamentales : les commandes et les sous-systèmes.

Les sous-systèmes sont l’unité de base de l’organisation d’un robot dans le paradigme orienté commande. Les sous-systèmes encapsulent les composantes de bas niveau du robot (comme les contrôleurs de moteur, les capteurs et/ou les actionneurs pneumatiques) et définissent les interfaces par lesquelles le reste du programme accèdera à ces composantes. Les sous-systèmes permettent aux utilisateurs de « cacher » au reste du programme la complexité interne de leurs composantes réelles : cela simplifie le reste du code du robot et permet de modifier les détails internes d’un sous-système sans devoir également modifier le reste du programme. Les sous-systèmes implémentent l’interface Subsystem.

Les commandes définissent les actions ou les comportements de haut niveau du robot. Elles utilisent les méthodes déclarées par les sous-systèmes. Une commande est un simple automate qui est soit en cours d’initialisation, en cours d’exécution, en cours de terminaison ou inactif. Les utilisateurs écrivent le code spécifiant quelle action doit être effectuée dans chaque état. Les commandes simples peuvent être combinées en des « groupes de commandes » pour accomplir des tâches plus élaborées. Les commandes, y compris les groupes de commandes, implémentent l’interface Command.

L’exécution des commandes

Note

Pour une explication plus détaillée, consultez Le planificateur de commandes.

Les commandes sont exécutées par le CommandScheduler (Java, C++), une classe singleton qui est au cœur de la librairie orientée commande. Le CommandScheduler est responsable d’interroger périodiquement l’état des boutons dans le but de planifier les nouvelles commandes, vérifier les ressources requises par ces commandes pour éviter les conflits, exécuter les commandes actuellement planifiées et supprimer les commandes dont l’exécution est terminée ou a été interrompue. La méthode run() du planificateur peut être appelée de n’importe quel endroit du code de l’utilisateur ; il est généralement recommandé de l’appeler à partir de la méthode robotPeriodic() de la classe Robot, qui est exécutée à une fréquence par défaut de 50Hz (une fois toutes les 20ms).

Plusieurs commandes peuvent être exécutées simultanément, à condition qu’elles ne nécessitent pas les mêmes ressources. La gestion de ces ressources se fait par sous-système : les commandes peuvent spécifier les sous-systèmes avec lesquels elles interagissent Ainsi, le CommandScheduler n’exécutera jamais en même temps plus d’une commande nécessitant le même sous-système. Cela permet d’éviter, par exemple, que les utilisateurs ne se retrouvent avec deux bouts de code différents essayant de modifier la valeur de sortie du même contrôleur de moteur. Si une nouvelle commande est démarrée et qu’elle a besoin d’un sous-système en cours d’utilisation, le CommandScheduler interrompra la commande en cours d’exécution qui utilise ce sous-système, si cette commande est interruptible. Si elle ne peut pas être interrompue, alors l’autre commande ne sera pas démarrée.

Chaque sous-système peut également être associé à une « commande par défaut » qui est automatiquement démarrée lorsqu’aucune autre commande n’utilise ce sous-système. Cela est utile pour les actions qui s’exécutent continuellement en arrière-plan comme le contrôle de la base pilotable du robot ou le maintien d’un bras articulé à une position fixe.

Lorsqu’une commande est démarrée, sa méthode initialize() est appelée une fois. Ensuite, sa méthode execute() est appelée à chaque fois que la méthode CommandScheduler.getInstance().run() est appelée. Lorsque la commande arrête de s’exécuter, sa méthode end(boolean interrupted) est appelée une fois. Cela se produit lorsque sa méthode isFinished() retourne true ou lorsqu’elle est interrompue (soit par une commande qui requiert un sous-système qu’elle utilise, soit en étant annulée).

Groupes de commandes

Il est souvent souhaitable de concevoir des commandes complexes à partir d’éléments simples. Cela est possible par la composition de commandes en « groupes de commandes ». Un <command-groups> est une commande qui contient plusieurs commandes, qui seront exécutées séquentiellement ou parallèlement. La bibliothèque orientée commande fournit plusieurs types de groupes de commandes à l’usage des équipes et les utilisateurs sont invités à écrire les leurs, s’ils le souhaitent. Comme les groupes de commandes implémentent également l’interface Command, on peut les composer récursivement, c’est-à-dire qu’il est possible d’inclure un groupe de commandes dans d’autres groupes. Il s’agit donc d’un moyen extrêmement puissant de construire des actions complexes avec une bibliothèque relativement simple.

Créer un projet robot

La création d’un projet est détaillée dans Créer le programme du robot. Sélectionnez « Template » puis votre langage de programmation puis « New Command Robot » pour créer un programme de base Command-Based Robot.

Lorsque vous créez un nouveau projet Command Robot, la nouvelle librairie du fournisseur basée sur les commandes est automatiquement importée. Si vous avez importé un projet 2019 ou créé un autre type de projet, l’ancienne librairie de commandes est aussi importée et il est également nécessaire d’importer la nouvelle librairie de fournisseurs basée sur les commandes par Librairies tierces et supprimer l’ancienne librairie de commandes.