Robótica Móvil: Control de motores de paso con Java SE Embedded en la plataforma Raspberry Pi

Por Ivan Jose Areinamo Martinez
Publicado en Marzo 2016

Resumen

Desarrollar un robot móvil es una tarea sencilla si se cuentan con los componentes y herramientas de software adecuadas. En este articulo se explicará paso a paso cómo construir un robot móvil con ruedas que hace uso de código Java® SE Embedded para controlar los motores de paso que están conectados a las ruedas del robot. De esta manera el usuario puede programar rutas y el comportamiento del robot ante diversas situaciones. Adicionalmente, se explica cómo compilar de manera remota mediante enlace SSH.

Los motores de paso permiten controlar con precisión el ángulo de giro del eje del motor, los que los hace útiles para tareas de precisión por lo tanto, es importante conocer su funcionamiento para controlarlos adecuadamente. Los encontramos en muchos dispositivos comunes como impresoras, plotters, máquinas de escribir, entre otros.

Los motores de paso que se van a controlar en este artículo son de tipo bipolar y es necesario utilizar un controlador para motores de paso como el chip Allegro A4988 (muy popular en impresoras 3D y maquinas CNC). La mayoría de los controladores funcionan de manera similar por lo que el lector será capaz de extrapolar el conocimiento adquirido a otros modelos de controladores (EasyDriver, Texas Instruments DRV8825, entre otros).

Este articulo cuenta con un ejemplo desarrollado en Java® SE Embedded que hace uso de los puertos GPIO del Raspberry Pi. Se escribe directamente el estado de los puertos sin utilizar librerías como Pi4J. El programa en el Raspberry Pi emite señales desde los puertos GPIO que luego son recibidas por el controlador y el chip convierte las señales recibidas en movimiento.

El artículo está dirigido a usuarios novatos en el lenguaje Java y permite al lector familiarizarse con las herramientas de compilación, el procedimiento para desarrollar una aplicación y la configuración de los puertos GPIO del Raspberry Pi 2 Modelo B.

Componentes y equipos utilizados:

  1. Raspberry Pi 2 Model B
  2. Tarjeta MicroSD de 8 GB
  3. Tarjeta USB de Red inalámbrica
  4. Teclado y mouse USB
  5. Cable HDMI
  6. Dos controladores A4988
  7. Dos motores de paso de tipo bipolar Nema 17 con sus respectivos cables. Nema 17 y 200 pasos por vuelta (1 paso = 1.8 grados)
  8. Cables con conectores Hembra-Hembra
  9. Fuente de poder para alimentar al Raspberry Pi, que cuente con puerto MicroUSB, que proporcione 5 voltios y 1 ampere o más. Puede ser utilizada una batería portátil.
  10. Fuente de poder de 12 Voltios y 3 Amperes o más
  11. Base de plástico o madera liviana para montaje de componentes

Versiones del software utilizado:

Raspbian Jessie Version: November 2015 Release date: 2015-11-21 Kernel version: 4.1
Compilador Java version 1.8.0 / Java(TM) SE Runtime Environment (build 1.8.0-b132) / Java HotSpot(TM) Client VM (build 25.0-b70, mixed mode)

La mayoria de nosotros estamos familiarizados con el concepto de robots. Los hemos visto en películas de ciencia ficción, historietas y en nuestra vida diaria. Sin embargo, antes de empezar a construir nuestro robot móvil con ruedas, que es el objetivo de éste artículo, lo mejor que podemos hacer será repasar una serie de conceptos básicos acerca de robótica móvil.

En primer lugar, debemos conocer el concepto de robot. Un robot es una máquina que ha sido diseñada por el ser humano que puede interactuar con su entorno. Cuenta con un computador a bordo que actúa como cerebro y le permite ejecutar una serie de instrucciones, las cuales de manera autónoma (tomando sus propias decisiones) o siguiendo órdenes definidas por un usuario. Dichas instrucciones le permiten al robot controlar sus movimientos y todos aquellos instrumentos a bordo con el objetivo de interactuar con el ambiente que le rodea.

Según la literatura, existen varios tipos de robots. Algunos autores los clasifican como: manipuladores, industriales, humanoides, insectos, móviles, entre otros. Todos presentan algunas de las siguientes cualidades:

  1. Obtienen información de su entorno mediante sensores
  2. Pueden realizar tareas físicas como moverse o manipular objetos
  3. Son reprogramables lo que permite diversos usos para la misma máquina.
  4. Pueden interactuar con el ser humano a través de sensores o comunicación digital.

Nosotros nos vamos a enfocar en los robots móviles con ruedas debido a que son fáciles de construir y sus usos son infinitos. Son utilizados en fábricas y almacenes para movilizar objetos y herramientas e incluso los robots que utiliza la NASA en el planeta Marte son robots móviles con ruedas, como el Curiosity.

Para nuestro modelo de robot móvil con ruedas vamos a necesitar una plataforma o base para colocar los componentes, al menos dos Motores de paso de tipo bipolar con sus respectivas ruedas, dos controladores A4988 y un Computador a bordo (en nuestro caso será un Raspberry Pi 2 Modelo B y lo programaremos con Java SE).

Sin perder más tiempo en explicaciones, a continuación vamos a realizar uno a uno los siguientes pasos:

  1. Instalar el sistema operativo Raspbian y realizar la configuración bàsica
  2. Utilizar putty en windows o terminal de Linux para conectarse por ssh desde otro equipo.
  3. Compilar un ejemplo de código con Java SE Embedded (Ejemplo clásico “Hello World”)
  4. Entender el funcionamiento del controlador A4988 y de los motores de paso
  5. Conectar todos los componentes al Raspberry Pi 2 Modelo B
  6. Definir el comportamiento de nuestro robot móvil (trayectoria)
  7. Ejecutar el código java con la trayectoria predefinida

En resumen el usuario (después de instalar el sistema operativo y configurarlo) escribirá el código con la conducta de robot. Dicho programa será escrito utilizando un editor de texto y será compilado en Java SE Embedded mediante conexión remota via ssh (utilizando conexión wifi). El robot ejecutará el programa y éste se traducirá en movimiento de las ruedas de una manera predefinida. Así el robot se moverá siguiendo el trayecto establecido.

El programa lo que hace es transmitir pulsos al controlador A4988 y cada pulso recibido se traduce en giro angular del motor; como la rueda está conectada al eje, los pulsos se traducen en rotación de la rueda en n cantidad de grados. Los pulsos son enviados utilizando los puertos GPIO del Raspberry Pi 2 modelo B a los puertos Step y Dir del A4988.

Instalación del sistema operativo Raspbian y configuración:

Lo primero que debes hacer es conectar a los puertos USB del Raspberry Pi 2 Modelo B, un teclado, un ratón y una tarjeta wifi. Previamente debes conocer la configuración de tu router wifi para poder ver la lista de direcciones IP asignadas, las cuales serán útiles en un futuro.
Seguiré exactamente las instrucciones de la página oficial de Raspberry para instalar el sistema operativo:

  1. Primero descargas la imagen del Raspbian Jessie Full desktop (es un sistema operativo basado en Debian)
  2. Insertas la tarjeta de memoria MicroSD en tu computador principal (donde descargaste la imagen de Raspbian Jessie) y sigues los pasos para escribir la imagen en la tarjeta MicroSD de acuerdo al sistema operativo utilizado. Instrucciones para usuarios de Linux: https://www.raspberrypi.org/documentation/installation/installing-images/linux.md
  3. Insertas la tarjeta de memoria en el Raspberry Pi y conectas la fuente de alimentación al puerto microUSB y esperas que inicie el sistema.
  4. Si te pide usuario y contraseña, escribes como usuario pi y la contraseña es raspberry.
  5. Finalmente en el Shell de Linux, puedes escribir el comando sudo raspi-config. En las opciones avanzadas debes habilitar el acceso al Raspberry Pi mediante enlace SSH. Despues de hacer eso puedes salir del rasp-config
  6. Luego en el Shell de Linux (la línea de comandos) escribe startx. Puedes familizarte con el sistema y en la esquina derecha puedes seleccionar tu red wifi. Es importante que configures la conexión a tu red y hacer que el Raspberry se conecte automáticamente ya que en un futuro deseamos trabajar sin monitor ni periféricos conectados a éste.

Por fortuna viene preinstalada en el Raspbian Jessie la versión 1.8.0 del Java SE Embedded por lo que no necesitamos realizar ningún paso adicional para instalarlo (puedes escribir el comando java -version para obtener la versión instalada)

Iniciar el enlace SSH:

Este paso te permite utilizar la línea de comandos del Raspberry de manera remota utilizando otro equipo. Esto nos va a permitir trabajar de manera cómoda.

Si utilizas Windows debes instalar PuTTY http://www.chiark.greenend.org.uk/~sgtatham/putty/ el cual es un programa que permite la conexión remota. Debes conocer la dirección IP asignada a tu Raspberry Pi y colocas el puerto 22 antes de abrir la conexión. Luego te pedirá escribir el usuario y contraseña (usuario pi y la contraseña es raspberry)

Si utilizas Linux solo debes abrir una terminal y escribir ssh usuario@host  (por ejemplo, si el Raspberry Pi está conectado por wifi al router puedes revisar la dirección IP asignada en la lista de clientes del router, en mi caso es 192.168.1.100, por lo tanto para conectarme escribo ssh pi@192.168.1.100)

Compilar un ejemplo clásico: “Hello World”

Para crear un programa en Java lo primero que debemos hacer es escribir el código en un editor de texto. Como estamos utilizando la terminal del Raspberry Pi utilizaremos el programa nano para crear nuestros códigos.

Escribe en la terminal el siguiente comando para crear el documento HelloWorld.java el cual es un programa sencillo que escribe un mensaje de saludo:

nano HelloWorld.java

ahora debes escribir el siguiente código:

public class  HelloWorld { 
   public static void  main(String[] args) { 
   System.out.println("Hola, Mundo");
}
}

Guarda el documento y sal del editor nano,

Para compilar el código anterior debes escribir en la terminal javac HelloWorld.java

Para ejecutar el programa ya compilado escribe

java HelloWorld
y verás el resultado en la pantalla.

 

Los motores de paso y el controlador Allegro A4988

Aunque el funcionamiento interno de los motores de paso no es objetivo de este artículo, debemos conocer un poco acerca de este tipo de motores electricos.

También conocidos como motores stepper, son un tipo especial de dispositivo que convierte una señal eléctrica en movimiento angular preciso. Mientras que un motor convencional gira libremente al aplicarle una tensión, el motor paso a paso gira un determinado ángulo de forma incremental (transforma impulsos eléctricos en movimientos de giro controlados), lo que le permite realizar desplazamientos angulares fijos muy precisos

De acuerdo a sus especificaciones, vienen en distintos voltajes y pasos. Utilizaremos en nuestro robot motores de paso del tipo utilizado en las impresoras 3D, generalmente se consiguen en formato Nema 17, funcionan a 12 Voltios y cuentan con 200 pasos por vuelta. Esto significa que un motor de paso de este tipo requiere 200 señales para dar un giro completo de 360 grados.

Debes tener en cuenta que no podemos conectar directamente los motores de este tipo al Raspberry Pi ya que funcionan a distinto voltaje y necesitamos un dispositivo intermedio que permita convertir las señales enviadas por el Raspberry Pi en movimiento del motor. Este dispositivo es el Allegro A4988.

Por cada motor conectamos un Allegro A4988 y cada uno de ellos recibe dos señales: Step y Dir.

En Step le indicamos el paso. Mientras más pasos por segundo enviemos al A4988, el motor girará más rápido (existe un límite en la velocidad pero depende de cada motor y hallamos ese límite mediante ensayo y error)

Dir establece la dirección de giro como Horaria o Antihoraria

Si tenemos un motor de 1.8º y necesitamos que el motor gire 3000 pasos entonces enviamos 3000 pulsos de voltaje al puerto Step del motor (esto equivale en escribir en los puertos GPIO señales Low y High, 3000 veces). Si conocemos el radio de la rueda y el angulo de cada paso podemos calcular la distancia recorrida. La formula es sencilla:

Distancia_recorrida = (Pasos * Grados)(2 * 3.14159 * Radio) / 360º

En nuestro caso particular si tenemos los siguientes datos: radio de rueda de 0.025 metros, un motor de 1.8º por paso, 3000 pasos; la distancia recorrida será de 2.35 metros. Es decir el motor 15 vueltas completas (3000/200=15)

Esta información es útil ya que nuestro robot contará con dos motores. Si los hacemos girar al mismo tiempo en la misma dirección y velocidad, entonces el robot recorrerá esa distancia de manera lineal. Si los hacemos girar en direcciones contrarias a la misma velocidad, entonces el robot va a girar manteniendo la misma posición.

El controlador A4988 tiene puertos adicionales los cuales los podemos observar en el siguiente gráfico:

Los puertos STEP y DIR los vamos a conectar directamente a los puertos GPIO del RPi 2 para que ejecuten la función anteriormente mencionada. Los puertos MS1, MS2 y MS3 se utilizan para cambiar la resolución de los pasos.

El A4988 tiene la habilidad de dividir los pasos originales de un motor en micropasos lo que nos permite multiplicar la precisión. Para ello, debemos añadir una señal High o Low a los puertos MS1, MS2 y MS3 como lo indica la siguiente tabla:

MS1     MS2     MS3      Resolucion de paso
Low      Low      Low      1 paso (Full step)
High     Low      Low      1/2 paso (Half step)
Low      High     Low      1/4 paso (Quarter step)
High     High     Low      1/8 paso (Eighth step)
High     High     High     1/16 paso (Sixteenth step)

Si nuestro motor es de 200 pasos o 1.8º por pasos, podemos obtener 1600 micropasos si configuramos el A4988 con una resolución de 1/8 (Eight step).

VDD lo conectamos a un puerto de 3.3v del Raspberry y el que está debajo, GND, a un puerto GND del Raspberry Pi 2.

2B, 2A, 1A, 1B conectamos el motor de paso bipolar

En la parte superior derecha tenemos VMOT y GND donde conectamos la fuente de poder del motor (utilizaré 12V)

Para finalizar, unimos RESET con SLEEP para habilitar el funcionamiento del motor.

El siguiente paso es conectar todos los componentes al Raspberry Pi 2 Modelo B e instalarlos en la plataforma o base

A continuación puedes observar la descripción de los pines del Raspberry Pi 2 Modelo B:

Description: C:\N_2016\_ _\rpi\GPIO_Pi2.png Para nuestro robot vamos a utilizar dos motores, dos A4988. Conectaremos el controlador A4988 del primer motor a los puertos GPIO26 (STEP) y GPIO19 (DIR) y el otro controlador A4988 a los pines GPIO20 (STEP) y GPIO21 (DIR)

No olvides conectar la fuente de poder microUSB de 5 voltios para alimentar el Raspberry Pi

Definir el comportamiento de nuestro robot (trayectoria)

Vamos a definir una trayectoria sencilla de 4 etapas:

  1. Desplazamiento de 3000 pasos
  2. Giro de 2000 pasos
  3. Desplazamiento de 1500 pasos
  4. Giro en dirección contraria de 1200 pasos

Analisis del código: El código completo lo puedes descargar en este enlace

En linux, todos los dispositivos son considerados archivos del sistema. En consecuencia, cada puerto GPIO del Raspberry Pi, está relacionado a un archivo. El código funciona escribiendo el estado que deseamos en el puertos GPIO como una escritura de archivo. Si queremos asignar un estado High o Low a un puerto, escribimos 1 o 0 respectivamente en el archivo de sistema correspondiente.

En las primeras líneas del creamos una función de escritura de archivo, llamada EscribirGPIO, la cual utilizaremos innumerables veces. Recibe como datos de entrada una cadena A que es el valor que queremos escribir y una cadena B que es la dirección en el sistema del archivo al que vamos a escribir

public static  void EscribirGPIO(String A, String B) {

FileWriter  fichero = null; 
   PrintWriter pw = null; 
try 
{           
   fichero = new FileWriter(B);           
   pw = new PrintWriter(fichero); 
   pw.println(A); 
} catch (Exception e) { 
   e.printStackTrace(); 
} finally {
try {
   // Nuevamente aprovechamos el finally para 
   // asegurarnos que se cierra el fichero.
   
if (null != fichero) 
   fichero.close(); 
} catch (Exception e2) {
   e2.printStackTrace();
}
}  
}
 

Luego en la función principal (Main) el primer paso es configurar uno a uno los puertos GPIO que queremos utilizar:

//Controlador  de Motor 1
//configurar  puerto step 20 como puerto de salida
EscribirGPIO("20", "/sys/class/gpio/export");
EscribirGPIO("out", "/sys/class/gpio/gpio20/direction"); 

//configurar puerto dir 21 como puerto de salida
EscribirGPIO("21", "/sys/class/gpio/export");
EscribirGPIO("out", "/sys/class/gpio/gpio21/direction");

//Controlador  de Motor 2
//configurar puerto step 26 como puerto de salida
EscribirGPIO("26", "/sys/class/gpio/export");
EscribirGPIO("out", "/sys/class/gpio/gpio26/direction");

//configurar puerto dir 19 como puerto de salida
EscribirGPIO("19", "/sys/class/gpio/export");
EscribirGPIO("out", "/sys/class/gpio/gpio19/direction"); 


A continuación ejecutaremos las etapas indicadas:

Etapa 1: 3000 pasos

//Escribir 3000 pasos

//Indicamos la dirección de los motores
EscribirGPIO("1", "/sys/class/gpio/gpio19/value");
EscribirGPIO("0", "/sys/class/gpio/gpio21/value");

A los puertos DIR les asignamos un valor inicial correspondiente a la dirección de Giro. Deben iniciar en direcciones opuestas ya que así están dispuestos sus ejes en la plataforma (los ejes están dispuestos a 180º con respecto al otro)

Luego ejecutamos los pasos utilizando un ciclo for

for(int i=0; i<3000; i++) 
{ 
   System.out.println("step  " + i);   
   
EscribirGPIO("1", "/sys/class/gpio/gpio26/value"); 
//Escribir High en el puerto GPIO26, equivale a asignar un  1 al archivo de sistema

EscribirGPIO("1", "/sys/class/gpio/gpio20/value"); 
//Escribir High en el puerto GPIO20, equivale a asignar un  1 al archivo de sistema
               
try { Thread.sleep(1); //esperamos un  milisegundo
               } catch(InterruptedException ex) { 
   Thread.currentThread().interrupt(); 
}

EscribirGPIO("0", "/sys/class/gpio/gpio26/value");   
//Escribir Low en el puerto GPIO26, equivale a asignar un 0 al archivo de sistema EscribirGPIO("0", "/sys/class/gpio/gpio20/value"); //Escribir Low en el puerto GPIO26, equivale a asignar un 0 al archivo de sistema
 
   try { Thread.sleep(1); 
   } catch(InterruptedException  ex) { 
   Thread.currentThread().interrupt();
}
 }

Funciona escribiendo pulsos de un milisegundo que son recibidos por el A4988 y se convierten en pasos en los motores.

En la siguiente etapa debemos hacer un giro, uno de los motores debe girar en dirección contraria, por lo tanto antes de ejecutar un ciclo de 2000 pasos debemos asignar la dirección correcta.

//Indicamos la dirección de los motores
EscribirGPIO("0", "/sys/class/gpio/gpio19/value");
EscribirGPIO("0", "/sys/class/gpio/gpio21/value");
 

Luego ejecutamos el ciclo de 2000 pasos

for(int i=0; i<2000; i++) 
{ 
   System.out.println("step  " + i);   
   
EscribirGPIO("1", "/sys/class/gpio/gpio26/value"); 
//Escribir High en el puerto GPIO26, equivale a asignar un  1 al archivo de sistema

EscribirGPIO("1", "/sys/class/gpio/gpio20/value"); 
//Escribir High en el puerto GPIO20, equivale a asignar un  1 al archivo de sistema
               try { Thread.sleep(1); //esperamos un  milisegundo
               } catch(InterruptedException ex) { 
   Thread.currentThread().interrupt(); 
}

EscribirGPIO("0", "/sys/class/gpio/gpio26/value");    
//Escribir Low en el puerto GPIO26, equivale a asignar un 0 al archivo de sistema EscribirGPIO("0", "/sys/class/gpio/gpio20/value"); //Escribir Low en el puerto GPIO26, equivale a asignar un 0 al archivo de sistema
 
   try { Thread.sleep(1); 
   } catch(InterruptedException  ex) { 
   Thread.currentThread().interrupt();
}
}

Las etapas 3 y 4 funcionan de la misma manera.

El ultimo paso consiste en ejecutar el código y observar el resultado

Para compilar el código debes escribir en la terminal javac robot.java

Luego para ejecutar el programa ya compilado escribe sudo java robot y verás el resultado.

Observaciones:

  1. Puedes utilizar el IDE oficial de Oracle, Netbeans IDE 8 (https://netbeans.org/ para crear tu código y obtener los beneficios de utilizar un IDE. Luego el archivo de código fuente lo puedes enviar via SSH al Raspberry Pi (Si utilizas Windows puedes instalar Cyberduck https://cyberduck.io/ )
  2. Si deseas cambiar la velocidad de giro de los motores solo debes cambiar el valor en milisegundos dentro de la función Thread.sleep (milisegundos). Puedes utilizar decimales.

 

 


Ivan Jose Areinamo Martinez es experto en Arduino y Raspberry Pi, desarrollo de prototipos de Robótica y Domótica, Instrumentación (control de temperatura y sensores) e Ingeniería Mecánica. También desarrollo de aplicaciones en Visual C#, Python y Java.

Este artículo ha sido revisado por el equipo de productos Oracle y se encuentra en cumplimiento de las normas y prácticas para el uso de los productos Oracle.