Brazo por RS232

He recibido mails pidiendo que los datos de todo el brazo (los ángulos y la distancia de las pinzas) puedan salir a través de un puerto serie. No tengo en cuenta lo que hay detrás del puerto, eso quiere decir que tu electrónica (PIC, Arduino, PLC, controladora de servos, etc.) se supone que entiende lo que recibe.

El código (en FreeBasic) es largo porque contiene la parte de OpenGL (es el mismo programa "BrazoSimple.bas"con varias líneas de código más), es mejor que te bajes el código fuente, ejecutable y todo lo necesario haciendo clic aquí.

(Si usas antivirus Avast has de añadir una exclusión para poder ejecutar el .exe que contiene. Para analizar este o cualquier otro archivo puedes hacer clic aquí)

Se trata de abrir el puerto de comunicaciones (puerto serie) y enviar los datos de todos los ángulos cada vez que movemos el brazo robot, y cerrar el puerto de comunicaciones antes de salir del programa.

Verás justo donde comienza el programa principal está "abrir el puerto":

Open Com "COM1:9600, N, 8, 1, CD0, CS0, DS0, RS" For Binary As #1

y luego, al final del procedimiento "Inversek", el envío de datos al puerto COM:

If Flag = 1 Then
   Print #1, CInt(AngGiro+180);   CInt(AngBrazo+90);   CInt(AngAntBr+180);_
             CInt(AngMunecA+180); CInt(AngMunecB+180); CInt(DistDedos*1000)
EndIf

O bien, lo podemos hacer de esta otra forma, es lo mismo:

If Flag = 1 Then
   Print #1, CInt(AngGiro+180);
   Print #1, CInt(AngBrazo+90);
   Print #1, CInt(AngAntBr+180);
   Print #1, CInt(AngMunecA+180);
   Print #1, CInt(AngMunecB+180);
   Print #1, CInt(DistDedos*1000)
EndIf

La suma de 180 ó 90 grados a cada variable convierte los ángulos en reales y además evita números negativos. Esto se debe a que las variables tienen un rango de -180 a 179 grados. Si le sumas 180 a las variables (a excepción de "AngBrazo" donde le sumamos 90 grados) , obtenemos una salida de rango 0 a 359 grados (360 en total).

La función "CInt" (redondeo al alza) deja el número entero sin decimales. Puedes cambiarlo por la función "Int" o "Fix" de entero si quieres. Si usas servos no vas a necesitar precisión porque los servos tipo Futaba RC u otros del estilo carece de precisión (unas 100 posiciones aprox. para 180 grados y de aquella manera...) Por eso es mejor eliminar los decimales, lo cual hace que el envío de datos sea un poco más rápido. Si necesitas los decimales has de eliminar las funciones CInt.

He puesto como velocidad de transmisión de los datos a 9600 baudios porque es estándar. A esta velocidad de envío el brazo se mueve muy lentamente (para aburrirse). Pero puedes cambiar este detalle a la máxima velocidad que soporte tu invento. Al triple de esta velocidad (38400) el brazo se mueve con total normalidad.

La variable "Flag" tiene como función detectar que quieres mover el brazo. Esto significa que sólo cuando mueves el brazo envía los datos al puerto COM (COM1 en nuestro ejemplo) evitando la saturación del puerto.

Para saber qué es exactamente lo que sale por el puerto:

Puedes hacer una cosa, y es que en vez de sacar los datos por el puerto COM, lo escriba en un fichero de texto. De esta manera verás qué tipo de dato sale y la forma. Podrás comprobar que el formato de salida es ASCII.

Le pones una comilla ' (equivale al REM del Basic) para deshabilitar temporalmente el puerto de comunicaciones y así hacer esta prueba y debajo configuras para abrir un fichero normal. Tal como sigue:

'Open Com "COM1:9600, N, 8, 1, CD0, CS0, DS0, RS" For Binary As #1
Kill "Pruebas.txt  '  Elimina el fichero "Pruebas.txt" si hubiese uno anterior.
Open "Pruebas.txt" For Binary As #1 '  Crea el fichero "Pruebas.txt"

Ejecutas el programa, mueves el brazo un poco y sales del programa. Se habrá creado el fichero "Pruebas.txt". Lo abres y verás un buen montón de números en columnas de seis separados por un espacio. Esto se debe a que hemos separado cada variable por un punto y coma ;

Cambiar el formato de salida:

En el procedimiento "InverseK", cambias la parte de enviar los datos por esta otra:

If Flag = 1 Then
   Print #1, CInt(AngGiro+180)
   Print #1, CInt(AngBrazo+90)
   Print #1, CInt(AngAntBr+180)
   Print #1, CInt(AngMunecA+180)
   Print #1, CInt(AngMunecB+180)
   Print #1, CInt(DistDedos*1000)
EndIf 

En este caso, sale el ángulo con un "retorno de carro" y "nueva línea", lo que equivale en Basic a los caracteres no imprimibles chr(13)+chr(10).

Hay otra forma de hacerlo y sale todo junto con un espacio entre cada dato pero sin los retorno de carro que es poniendo un punto y coma ; al final de cada comando Print:

If Flag = 1 Then
   Print #1, CInt(AngGiro+180);
   Print #1, CInt(AngBrazo+90);
   Print #1, CInt(AngAntBr+180);
   Print #1, CInt(AngMunecA+180);
   Print #1, CInt(AngMunecB+180);
   Print #1, CInt(DistDedos*1000);
EndIf 

El comando "Print", tanto en ficheros como en caracteres imprimibles, tiene como particularidad que si pones un punto y coma ; al final del comando, no envía retorno de carro y nueva línea [ es decir, los famosos caracteres no imprimibles Chr( 13, 10 ) en este orden ]. Por el contrario, si no le pones punto y coma al final, sí envía un retorno de carro y nueva línea [ Chr( 13, 10 ) ]. Juego con este detalle en el programa de descarga (primer ejemplo de Prints, arriba); observa que todos llevan punto y coma ; a excepción del último Print para que éste último haga el retorno de carro y nueva línea. Si en vez de poner un punto y coma ; pones una coma , deja un espacio de 9 espacios entre variable y variable (no recomendado para nuestro caso).

Y por último, una forma donde no es en formato ASCII, sino tal como es en la memoria del ordenador, sale según su tipo. Por "tipo" me refiero a que el formato es diferente si es "Integer", "Single" o "Double". Las variables de los ángulos en el programa de ejemplo "BrazoSimple.bas" tiene el formato "Double". La salida es totalmente binaria, no de unos y ceros, sino en un formato ilegible a la vista.

If Flag = 1 Then
   Put #1,, CInt(AngGiro+180)
   Put #1,, CInt(AngBrazo+90)
   Put #1,, CInt(AngAntBr+180)
   Put #1,, CInt(AngMunecA+180)
   Put #1,, CInt(AngMunecB+180)
   Put #1,, CInt(DistDedos*1000)
EndIf 

A la hora de compilar según la versión del compilador de Freebasic en las funciones "MultiKey()" puede dar problemas. Si te da fallo en esa función tendrías que cambiar todos los "FB.SC_" por "SC_", o al revés (según el caso), y asunto resuelto.

Ejemplo:

If MultiKey(FB.SC_A) Then Xreal=Xreal-1

por

If MultiKey(SC_A) Then Xreal=Xreal-1

Así con todas las funciones "MultiKey()".