Comandos en LibreServo (segunda parte)

He dedicado mucho tiempo a la parte de comandos en LibreServo y creo que es una de las partes más importantes del proyecto, es cómo se presenta LibreServo ante el usuario. Ofrece una flexibilidad y posibilidades que yo nunca he visto en ningún fabricante.

La documentación de los comandos la dividiré en dos artículos, este artículo está más centrado en ejemplos y explicación de ejecución y el otro artículo está centrado en la descripción de los comandos de LibreServo.

LibreServo cuenta con un administrador de tareas para la parte del manejo del motor de alta prioridad y otro administrador de tareas independiente de baja prioridad sólo para el envío de datos al usuario (comandos GX). Hay que tenerlo en cuenta ya que el orden y la temporización serán independientes entre los comandos de recibir datos y el resto de comandos.

Todos los comandos empiezan con el carácter 'S' y al menos un número de servomotor y terminan con ';'. Se pueden encadenar comandos con el carácter '|' para que todos los comandos se traten a la vez como un bloque.

Este artículo lo dividiremos en los siguientes temas:


Selección de Servomotores

Todos los comandos empiezan con el carácter 'S' seguido de al menos un ID de servomotor. El ID de un servomotor va de 1 a 255 (por defecto es 1). LibreServo permite enviar un mismo comando a la vez a diferentes servomotores. El carácter '-' indica un rango y el carácter ',' IDs de servomotores independientes. Por ejemplo, el comando S1,3,4,10-20M1000; significa que los servomotores con ID 1, 3, 4 y todos con ID entre 10 y 20 (ambos incluídos) deberán moverse a la posición 1000. Además, el ID 0 está reservado (es de broadcast) y cualquier comando enviado al ID 0 será como enviar el comando a todos los servomotores independientemente de su ID real.


Ejemplo:
S5MW500|S0M12000:1000; Todos los servomotores se moverán a la posición 12000 en 1000 milisegundos, pero el servomotor 5 tras 500ms de espera
S2,5,10-14,6M2000:500; Los servomotores 2, 5, 6, 10, 11, 12, 13 y 14 se moverán a la posición 2000 en 500 milisegundos

Encadenamiento de comandos

Como hemos visto, todos los comandos empiezan con el carácter 'S' y al menos un número de servomotor y terminan con ';'. Se pueden encadenar comandos con el carácter '|' para que todos los comandos se traten a la vez como un bloque. Esto es muy útil por muchos motivos, uno de los principales es que hasta que LibreServo vea el carácter ';' no empieza a ejecutar, con lo que si queremos que diferentes servomotores ejecuten diferentes comandos pero quieres asegurarte que todos empiecen a moverse a la vez, enviar todos los comandos en un mismo comando es la manera de asegurarte de que empiecen a la vez. Además, es útil para mandar los comandos de lectura de variables junto al resto de comandos.


Ejemplo:
S1L255:0:0|S1T1567:300:100|S1T1567:10:0|S1T1567:300:100; Encadena una serie de comandos de Tono y LED, puede ser el inicio de una canción
S2M1000:500|S3M2000:1000|S2M500:500; El servomotor 2 se moverá a 1000 en 500ms y luego a 500 en 500ms a la vez que el servomotor 3 se mueve a 2000 en 1000ms
S2M1000:500|S2Gs13,11:500:1; El servomotor 2 se moverá a 1000 en 500ms y nos reportará cada milisegundo su posición y su consumo de corriente para verlo en el Serial Plotter de Arduino, por ejemplo

Comandos inmediatos [ ! ]

Otra de las características únicas de LibreServo son los comandos inmediatos o prioritarios. Un comando se puede enviar como inmediato con el carácter '!' antes de ';' o '|'. Para que surta efecto, deberá de ser el primer comando para dicho servomotor que se envía, si se envía con más comandos encadenados, el que sea marcado como inmediato. Un comando inmediato provoca que se aborte la ejecución del comando que se estuviera ejecutando y borra el resto de comandos que hubiera en el administrador de tareas. Un comando inmediato del grupo de lectura de variables (GX) no afecta al resto de comandos ya que está en un administrador de tareas independiente, lo mismo que el resto de comandos inmediatos no afecta a los comandos de lectura de variables.


Ejemplo:
S3M2000:200!; El servomotor 3 para el comando que estuviera haciendo y borra todos los comandos de su administrador de tareas, tras ello se mueve a la posición 2000 en 200ms
S2M1000:500|S3M2000:1000!|S2M500:500!|S3M500:1000; El servomotor 2 NO recibirá los comandos como inmediatos porque '!' está en su segundo comando, en cambio, el servomotor 3 sí, ya que es su primer comando en la cadena de comandos
S2M1000:500!|S2Gs13,11:100:5; El servomotor 2 recibirá un comando inmediato, pero no afecta al administrador de tareas del comando Gs, con lo que si ya estuviera ejecutando un comando GX, no va a ejecutar el nuevo comando Gs a la vez que el nuevo comando de movimiento inmediato
S2M1000:500!|S2Gs13,11:100:5!; Esta sería la manera adecuada de asegurarnos que el servomotor deja de hacer lo que estuviera haciendo en ambos administradores de tareas y ejecuta nuestros comandos de manera prioritaria

Comprobación CRC

La comprobación CRC sirve para asegurarnos que el comando recibido por parte de LibreServo es correcto y no hay ningún carácter que haya bailado durante la transmisión Serie (RS485). Por defecto la comprobación CRC está activada en LibreServo pero de manera opcional (uso_crc = 2), esto quiere decir que si mandas un comando con comprobación CRC LibreServo lo va a aceptar (y si la comprobación CRC está mal, no ejecuta el comando), pero si mandas comandos sin comprobación CRC LibreServo también los va a aceptar (si el comando es correcto, claro). Por supuesto, se puede modificar la variable 117 (uso_crc) para que sea obligatorio el uso de CRC o para que no acepte ningún comando con CRC.

Por defecto la comprobación CRC que se hace es la denominada CRC-16/AUG-CCITT. Se recomienda el siguiente calculador de crc online para hacer comprobaciones.

La código CRC se envía al final del comando en formato hexadecimal, justo antes del carácter ';' y después del carácter '!' si lo hubiera. Se precede con el carácter '#' y tiene en cuenta el comando completo hasta justo el carácter anterior a '#'.


Ejemplo:
S1G5#E0CF; El código CRC se envía como hexadecimal. En este caso sería E0CF
S1M1000:1000|S1GW20|S1Gs16,21,9:1100:1|S3MF#DD7B; Por supuesto en comandos encadenados el código CRC funciona de la misma forma y tiene en cuenta el comando completo, incluso aunque partes sean para servomotores diferentes

Administradores de tareas y temporización de comandos

En LibreServo existen dos administadores de tareas. Uno principal para todos los comandos y otro exclusivo sólo para los comandos de lectura de variables. Los comandos de escritura de variables y guardado también van en el administrador de tareas principal.

Ambos administradores de tareas son como colas FIFO, el primer comando que entra es el primero que se ejecuta. El administrador de tareas tan sólo ejecuta un comando detrás de otro esperando a que un comando termine para empezar a ejecutar el siguiente comando. Los dos administradores de tareas se ejecutan a 1KHz, por eso el tiempo mínimo de ejecución de cualquier comando es de 1ms.

Existen dos grandes diferencias entre los administadores de tareas. El principal tiene una capacidad de 100 comandos y se ejecuta con prioridad alta, mientras que el administrador de tareas de lectura de variables tiene una capacidad de 15 comandos y se ejecuta con prioridad baja. La prioridad baja indica que su ejecución no está asegurada que sea exactamente cada milisegundo. Es posible que haya pequeñas variaciones en función de otras interrupciones dentro de LibreServo. Cuando hablamos de pequeñas variaciones, hablamos siempre de variaciones de menos de un milisegundo, con lo que realmente no nos debería de afectar en lo más mínimo.

Teniendo estos conceptos claros, veamos unos ejemplos para ver cual es el orden y temporización de ejecución:


Ejemplo:
S1MT200000:300:2000|S1MT150000:1000|S1GS9:300:1|S3MS80000:200:3000|S1GW1700|S1GS9:150:1;
Linear curve graph
En este ejemplo vemos un comando compuesto por varios subcomandos. Aunque los comandos del servomotor 3 está intercalado, cada servomotor coge sólo sus comandos. Vemos además cómo los comandos de lectura de variables funcionan en otra cola
S1MT200000:300:1500|S1MT100000:300:1500|S1GS9:1500:1|S3M5000:1000;
[ESPERA 0,5 segundo]
S3M0:750|S3M10000:750!|S1M50000:1000!|S1GS9:1000:1;
[ESPERA 0,5 segundo]
S1M600000:1000|S1GS6:1000:1;
Linear curve graph
En este ejemplo vemos el funcionamiento de '!'. Vemos cómo sólo afecta a cada cola específica de cada servomotor. Los comandos con preferencia '!' deben de ser el primer comando para ese servomotor de su cola, como vemos con el servomotor 3, en la segunda tanda de comandos no aplica '!' porque no es el primer comando

Modo recuperación

Hay varios motivos por los que podríamos perder la comunicación con LibreServo. Si desconocemos el ID del servomotor, tan sólo tenemos que mandar un comando al servo de ID 0 (recordar que todos los servomotores responden a dicho ID) y recoger o cambiar el ID del servomotor. Pero, si desconocemos la velocidad del puerto serie, o hemos guardado una velocidad que es mayor de la que podemos utilizar nosotros, por ejemplo, arduino sólo llega a 115200bps pero LibreServo es capaz de comunicarse a 9Mbps, en ese caso existe la posibilidad de forzar a LibreServo a que se reconfigure con la configuración por defecto.

Para lograr que LibreServo entre en modo recuperación, debemos arrancar LibreServo con el pin A del puerto RS485 conectado a tierra y B directamente a VCC. ¡OJO! VCC nunca debe de ser superior a 13V en esta operación ya que el chip RS485 no soporta voltajes superiores en sus pines de entrada. Si al encender LibreServo están los pines A y B como hemos comentado, LibreServo empieza a flashear el led en blanco cada vez más rápido hasta que pasados 6 segundos, si A y B no han cambiado de valor en ningún momento, se reconfigura y guarda la configuración por defecto en flash. Ahora podremos apagar LibreServo o seguir utilizándolo ya que tendrá cargada la configuración por defecto.

Suscripción

Recibe un email por cada nuevo artículo.

Esta pregunta es para comprobar si usted es un visitante humano y prevenir envíos de spam automatizado.

1 + 16 =
Resuelva este simple problema matemático y escriba la solución; por ejemplo: Para 1+3, escriba 4.