Programar comandos

Importante

Esta documentación describe el uso del legado de la biblioteca de programación basada en comandos. Mientras esta documentación ha sido preservada para ayudar a equipos que aún lo necesiten, los equipos son fuertemente alentados a avanzar a new command-based library.

Los comandos son programados para ejecutarse en base a un número de factores como cadenas, comandos predeterminados cuando ningún otro comando en funcionamiento requiere un subsistema, un comando principal en un grupo termina, un botón se presiona, el inicio del periodo autónomo, etc. A pesar de esto muchos comandos pueden estar funcionando virtualmente al mismo tiempo, solo hay un solo hilo (el hilo principal del robot). Esto es para reducir la complejidad de la sincronización entre hilos. Existen hilos que funcionan en el sistema para sistemas como bucles de PID, comunicaciones, etc, pero ellos son contenidos en si mismos con solo poca interacción requiriendo una sincronización compleja. Esto hace el sistema mucho más robusto y predecible.

Esto es logrado por la clase llamada Scheduler. Tiene un método run() que es llamado periódicamente (típicamente cada 20ms en respuesta a una actualización de la driver station) que intenta hacer un avance en cada comando que se esta ejecutando. Esto es hecho al llamar el método execute() seguido por el método isFinished(). Si isFinished() devuelve un valor verdadero, el comando es marcado para ser removido de ejecutarse en su siguiente paso a través del programa. Entonces, si hay un número de comandos todos programados para ejecutarse al mismo tiempo, entonces cada vez que el método Scheduler.run(), los métodos execute() and isFinished() de cada uno de los comandos activos son llamados. Esto tiene el mismo resultado que usar múltiples hilos.

Estructura de un Programa a Base de Comandos

Full anatomy of the different parts of a command based program.

Esto muestra un típico programa del robot a base de comandos y todo el código necesario para asegurar que los comandos son programados correctamente. El método Scheduler.run provoca el paso a tráves de el programa el cual permitirá a cada comando activo ejecutarse a través de sus métodos execute() e isFinished(). Ignore el método log() en el ejemplo de Java.

Ciclo de Vida de un Comando

Different stages a command goes through.

El trabajo en programas a base de comandos ocurre cuando el método Scheduler.Run (C++) o Scheduler.run (Java) es llamado. Este es llamado típicamente en cada actualización de la driver station lo cual ocurre cada 20 ms o 50 veces por segundo. El pseudocódigo ilustra que sucede en cada vez que se llama al método run.

  1. Los botones y gatillos son sondeados para ver si el comando asociado debería ser programado. Si el gatillo es verdadero, el comando es agregado a una lista de comandos que debería ser programada.

  2. Vea a través de la lista de todos los comandos que están en funcionamiento y llaman a sus métodos execute e isFinished. Los comandos que su método isFinished regrese un valor verdadero son removidos de la lista de comandos en funcionamiento.

  3. Vea a través de los comandos que han sido programados para ejecutarse en los pasos previos. Esos comandos son agregados a la lista de comandos en funcionamiento.

  4. Comandos predeterminados son agregados a cada subsistema que en ese momento no tenga comandos funcionando que requieran ese subsistema.

Optimizar Grupos de Comandos

public class Pickup extends CommandGroup {
    public  Pickup() {
       addSequential(new CloseClaw());
       addParallel(new SetWristSetpoint(-45));
       addSequential(new SetElevatorSetpoint(0.25));
    }
}

Una vez que ya haya estado trabajando con comandos que operen los mecanismos en su robot usted puede combinar esos grupos de comandos para realizar acciones más complejas. Los comandos pueden agregarse a grupos de comandos para ejecutarse secuencialmente o de forma paralela. Comandos secuenciales esperan hasta que terminan (el método isFinished devuelve un valor verdadero) antes de ejecutar el siguiente comando en el grupo. Comandos paralelos empiezan a ejecutarse, luego inmediatamente enlistan al siguiente comando del grupo.

Es importante notar que los comandos son agregados a un grupo en el constructor. Un grupo de comandos es tan simple como una lista de instancias de comandos que se ejecutan cuando se enlistan y cualquier parámetro que pasa a los comandos es evaluado durante el constructor por el grupo.

Imagine que en un diseño de un robot, hay una garra, adjunta una articulación de mano y todo esto adjunto a un elevador. Al recoger algo, la garra necesita cerrarse primero antes que el elevador o articulación de mano pueden moverse a otra dirección que el objeto puede resbalarse del agarre de la garra. En el ejemplo mostrado en la parte superior, el comando ``CloseClaw``será ejecutado primero. Después de que termine (la garra esta cerrada), la muñeca se moverá a su punto fijo y en paralelo, el elevador se moverá. Esto provoca a ambos , el elevador y la muñeca moverse simultáneamente, optimizando el tiempo requerido para completar la tarea.

¿Cuándo se terminan los grupos de comandos?

How commands finish.

Un grupo de comandos termina cuando todos los comandos iniciados en un grupo terminan. Esto es verdadero a pesar de el tipo de comandos que son agregados al grupo. Por ejemplo. si un número de comandos son agregados en paralelo y secuencialmente , el grupo se termina cuando todos los comandos agregados al grupo terminan. Como cada comando es agregado a un grupo de comandos, se pone en una lista. Así como esos comandos hijos terminan, se quitan de la lista. Los grupos de comandos termina cuando la lista de comandos hijos está vacía.

El comando Pickup mostrado en el ejemplo superior, el comando es terminado cuando todos los otros comandos CloseClaw, SetWristSetpoint, y SetElevatorSetpoint terminen . No importa que algunos de los comandos sean secuenciales y algunos paralelos.

Programar un Comando dentro un comando en funcionamiento

Los comandos pueden ser programados al llamar el método ``start()``(Java) o ``Start()``(C++) en una instancia de comandos. Esto puede causar que el comando sea añadido a el conjunto de comandos en funcionamiento en el programa. Esto resulta útil cuando un programa necesita programar un comando u otro condicionalmente. El nuevo comando programado será agregado a una lista de nuevos comandos en este paso a través del método run del programa y en realidad ejecutará la primera vez en el siguiente paso a través del método run. Comandos creados recientemente nunca son ejecutados por el mismo llamado al método run del programa , siempre son enlistados para la siguiente llamada la cual normalmente ocurre 20ms más tarde.

Quitar todos los Comandos del Programa

Scheduler.getInstance().removeAll();

Ocasionalmente es útil asegurarse que no hay comandos en funcionamiento en el programa. Para quitar todos los programas en funcionamiento use el método Scheduler.removeAll() (Java) o Scheduler::RemoveAll() (C++). Esto causara que todos los comandos que estén en funcionamiento tengan sus métodos interrupted() (Java) o Interrupted() (C++) llamados.Los comandos que no han iniciado van a tener el método end() (Java) o End() (C++) llamado.

El método «requires»

How requires works.

Si tiene varios comandos que usan el mismo subsistema, tiene sentido que no se ejecuten al mismo tiempo. Por ejemplo, si hay un subsistema Claw con comandos OpenClaw y CloseClaw, ambos no pueden ejecutarse al mismo tiempo. Cada comando que usa el subsistema Claw declara que 1 llamando al método requires() (Java) o al método Requieres() (C ++). Cuando uno de los comandos se está ejecutando, digamos desde la pulsación de un botón del joystick, e intentas ejecutar otro comando que también requiera el Claw, el segundo se adelanta al primero. Suponga que OpenClaw se estaba ejecutando y presiona el botón para ejecutar el comando CloseClaw. Se interrumpe el comando OpenClaw - 2 se llama al método interrumpido en el siguiente ciclo de ejecución y se programa el comando CloseClaw. Si lo piensa, este es casi siempre el comportamiento deseado. Si presionó un botón para comenzar a abrir la garra y cambia de opinión y desea cerrarla, tiene sentido que se detenga el comando OpenClaw y se inicie CloseClaw.

Un comando puede requerir muchos subsistemas, por ejemplo, una secuencia de autónomo compleja puede usar un número de subsistemas para completar su tarea.

Los grupos de comandos requieren automáticamente a todos los subsistemas para cada comando en el grupo. No hay necesidad para llamar el método requires para un grupo.

¿Cómo son los requerimientos de un grupo evaluados?

Los subsistemas que requiere un grupo de comandos es la unión del conjunto de subsistemas que se requieren para todos los comandos secundarios. Si se agregan 4 comandos a un grupo, entonces el grupo requerirá todos los subsistemas requeridos por cada uno de los 4 comandos del grupo. Por ejemplo, si hay tres comandos programados en un grupo: el primero requiere el subsistema A, el segundo requiere el subsistema B y el tercero requiere los subsistemas C y D. El grupo requerirá los subsistemas A, B, C y D. Si otro comando se inicia, digamos desde un botón de joystick, que requiere A, B, C o D, interrumpirá a todo el grupo, incluidos los comandos paralelos o secuenciales que puedan estar ejecutándose desde ese grupo.