lunes, 4 de febrero de 2013

Robot evita obstáculos con Arduino [Parte 4]: Programación del robot

Programación del robot

Para que sea todo más fácil de entender, sobretodo para quien no haya programado nunca nada, explicaré como programar todo por separado, con sus respectivos códigos.

Luego abordaré la programación del robot y subiré el código con un enlace externo para que lo podáis descargarlo y modificarlo a vuestro gusto. ¡Empezamos! 



Antes de nada, para poder programar Arduino necesitarás descargarte su entorno de programación totalmente gratuito que puedes encontrar en http://arduino.cc/en/Main/Software

LO BÁSICO
Entorno de programación Arduino. Compilador. Estructura de un programa. Declaración de variables. 

A continuación, la teoria:


Mediante la programación puedes hacer escritura digital, escritura analógica digital, lectura tanto analógica como digital, comunicación serial Arduino-PC y viceversa, y realización de pulsos por modulación a través de los pin PWM. 
En la práctica se puede traducir a encender y apagar un led, variar la intensidad de éste, crear botones con estado, realizar operaciones aritméticas obtener valores de los sensores, comunicarse con Arduino a través de un puerto serie,  mover los motores en ambos sentidos, etc.

Antes de explicar algunas de las prácticas, es importante conocer el entorno de programación de Arduino, que consigue hacer fácil la escritura del código y además es el encargado de cargar el programa a la placa mediante la conexión USB.

Como se puede observar , consta de una serie de botones, que uno tiene que conocer, y un cuerpo central vacío donde se escribirá el código que se enviará a la placa. Ejemplos son los botones que se muestran a continuación.


El código que se escribirá en el compilador es un lenguaje y como todo lenguaje tiene su vocabulario, sintaxis, normas y una estructura que hay que respetar. Podeís encontrar más sobre la sintaxis en: http://arduino.cc/en/Reference/HomePage 

Para la programación se utiliza el lenguaje Wiring. El  lenguaje Wiring, es muy parecido a C, ya que es un subconjunto de éste. Tiene unas peculiaridades destacables, se dice que son Case Sensitive, es decir sensible a las mayúsculas. No es lo mismo escribir “analogWrite” que “analogwrite”. Otra peculiaridad es que cada vez que se acaba una instrucción se ha de separar por “;” (punto y coma).

La estructura principal está dividida en dos apartados:

La función setup(), establece cuando se inicia un programa. Se utiliza para iniciar variables, establecer estados de los pins,  o establecer cualquier configuración inicial. Esta función se ejecuta una única vez después de conectar la alimentación a Arduino o cuando se pulsa el botón reset.

La función loop() que se escribe justo debajo debajo del setup(). Inicializa y hace justo lo que su propio nombre sugiere, se ejecuta consecutivamente, permitiendo al programa variar y responder, es decir actúa como un bucle. Una vez llamadas las funciones, el código que se escriba debe ir entre llaves “{}”.

Por encima del setup(), se declararán las variables globales, que en programación son estructuras de datos, como su nombre indica, pueden cambiar de contenido a lo largo de la ejecución de un programa. Dependiendo del tipo de dato que se tenga que almacenar en la variable lo indicaremos con una palabra u otra.

 ¿Cómo se declara una variable? Al principio escribiremos el tipo de dato, dejaremos un espacio en blanco, escribiremos el nombre que le queramos asignar a la variable y finalizaremos con un punto y coma. En el caso que la variable se refiera a un pin determinado de arduino, después de asignar un nombre a la variable, escribiremos un igual, el número de pin y cerraremos con el punto y coma. 
Ejemplo:
         int /*tipo de dato entero*/ led /*nombre de la variable*/ =13 /*asignación del pin nº 13*/;

Muchas veces se crean pequeños programas dentro del programa que se está creando para hacer más sencilla la escritura del código. Éstos se crearan justo debajo del loop().

De la misma forma que las variables, para crear un programa al principio debemos indicar el tipo de dato, un espacio en blanco, el nombre del programa y lo finalizaremos con dos paréntesis uno abierto y otro cerrado “()”, los paréntesis indican que se trata de una función, y luego entre llaves escribiremos el programa. Después para llamarla en el loop() solo escribiremos su nombre entre paréntesis y finalizado con punto y coma. 

Resumen estructura de programación en el entorno de programación arduino usando el lenguaje Wiring:




En la segunda entrada del foro podréis encontrar un archivo en formato .zip con los códigos de todos los ejercicios y la programación del robot. También lo podréis encontrar en este enlace externo y al final de cada apartado.
Recordad que para abrir estos archivos necesitareis el entorno de programación Arduino que podéis encontrar en http://arduino.cc/en/Main/Software  y cualquier duda que tengáis sobre el proyecto, ya sea programación o no, lo podéis hacer aquí en el foro. 

Ejercicios de programación básica:

A continuación explicaré tres ejercicios el primero de escritura, el segundo de lectura y el tercero de modulación por ancho de pulsos.

-Ejercicio 1

Objetivos: encender y apagar un led, variar la intensidad del led.

Conectaremos un led en el pin numero 11 de la siguiente manera , lo he conectado en un pin PWM para después explicar cómo variar la intensidad del led utilizando el mismo pin.

 Encender y apagar un led: para hacer más comoda la escritura del código declararemos una variable  de nombre “led” que asignaremos al pin donde lo hayamos conectado en este caso el número 11.
En la configuración incial hemos de declarar el estado del pin que puede ser de entrada (INPUT) o salida (OUTPUT). En este caso es de salida. 
En el loop() escribiremos la función digitalWrite, que espera recibir dos datos, el numero de pin(escribiremos “led”), y el valor de éste puede recibir dos valores que son de carácter  constantes, HIGH o LOW. 
Escribir un HIGH significa que arduino recibirá un 1, y lo traducirá enviando 5V al pin numero 11 y nosotros lo interpretaremos como un ON (Encendido). 
Dejaremos un espacio de tiempo de un segundo escribiendo delayed(1000) (1000milisegundos=1segundo), y repetiremos la escritura digital pero escribiendo esta vez un LOW.
Cuando se ejecute el loop() encenderá y apagará el led cada segundo.
Para entender mejor el encendido y apagado podemos fijarnos a continuación en la tabla dónde se muestra la representación lógica del voltaje.


- Variar la intensidad del LED

Para conseguir variar la intensidad del led mediante la programación hemos de conseguir que la diferencia de potencial que se le suministre al LED sea por debajo de 5V y superior a 0V.
Esto se consigue mediante la escritura analógica, llamando a la función analogWrite(), solo funciona en los pin PWM, de la misma forma que la escritura digital nos pide el numero del pin y un valor. 
Esta vez el valor será un número comprendido entre el 0 y el 255 que como expresa la tabla que hay a continuación, cuando enviamos 255, se traducirá a 5V y cuando el valor analógico sea 0 el voltaje será 0. De esta forma el led emitirá distintas intensidades.


- Ejercicio 2

Objetivo: obtener lecturas de un sensor infrarrojo, a través del serial monitor.

Realizaremos las conexiones como aparecen en la imagen. El sensor lo colocamos en un pin analógico.
Para conseguir una lectura analógica, primero hemos de leer y luego imprimirlo en la pantalla.

Empezaremos configurando el setup(), indicando que el sensor es un elemento de entrada (INPUT) y la velocidad de comunicación con el serial monitor, escribiendo: Serial.begin(115200) (115200 baudios). 
La lectura del sensor la haremos llamando a la función analogRead(),  entre paréntesis escribiremos la variable a leer por ejemplo: analogRead(sensor).
Ahora crearemos otra variable dónde será almacenado el valor que leerá el sensor y asignaremos a la nueva variable la lectura del sensor y la imprimiremos en el monitor serial, llamando a la funcion Serial.print(), indicando entre paréntesis la variable que tiene que imprimir. Serial.print(dato). 

Al abrir el serial monitor recibiremos datos comprendidos entre el 0 y el 1023. El dato recibido por el sensor habrá que interpretarlo en voltios, de la misma forma que en el proceso de escritura analógica, 1023 equivaldrá a 5V y 0 a 0V.
Una vez descifrado el voltaje nos queda interpretar la gráfica del sensor que estemos utilizando. Este caso es un sensor de distancia IR Sharp GP2D12 y su gráfica es la siguiente:

Ejercicio 3

Objetivo: mover los servomotores en ambos sentidos.

Conectaremos los motores en pins PWM para la realización de este ejercicio.

El servomotor de rotación continua se controla a través de la modulación por  ancho de pulso donde la velocidad y el sentido de rotación están determinados por la duración del pulso. Para que la rotación sea uniforme, el servomotor necesita una pausa de 20 milisegundos entre cada pulso.
Cuando se realiza un pulso inferior a los 1500 microsegundos, el servo motor girará en la direccion de las agujas del reloj


Y viceversa, cuando el pulso sea superior a los 1500 microsegundos, el servo motor girara en el sentido contrario a las agujas del reloj.

Los valores del espaciado de tiempo para realizar el pulso variaran según el modelo y el fabricante del servomotor, los valores utilizados son del servomotor parallax de rotación continua.

¿Como intercalar dos pulsos para mover dos motores a la vez?

El objetivo es conseguir es realizar 2 pulsos (uno en cada motor) cada 20 ms (como indica el periodo).
Para ello, vamos a contar el tiempo en que los motores estan a 0 (20 ms) en vez de parar durante 20 ms, como haciamos en el ejemplo anterior con el delay

if (instanteTiempoActual > ultimoInstanteTiempo + 20)
 {/*Explicación: han pasado 20 ms desde la última vez que realice un pulso en este motor. Puedo hacer un nuevo pulso porque ha pasado tanto tiempo como indica el periodo*/ultimoInstanteTiempo=instanteTiempoActual;}
DESCARGAR CÓDIGO EJERCICIO SERVOMOTORES

- PROGRAMACIÓN DEL ROBOT

He creado un diagrama de flujo para tener una guía a la hora de programar. Así que vamos a ello.

Lo que haré será explicar como se ha programado y os dejaré el código para descargar en el foro y también podéis preguntar cualquier duda.





Siguiendo las instrucciones del diagrama el loop() solo cumplirá dos funciones detectar() y adelante().

La función detectar() realizara la acción de hacer 5 lecturas de cada sensor, eliminar la lectura más alta y más baja, por si se trataran de subidas, bajadas de tension o algún error del sensor, y despúes realizará la media aritmetica de éstas y cada sensor en una variable distinta, guardará en dicha variable si existe o no existe obstaculo.
La función adelante(), comprobará las variables para averiguar si hay obstáculo. En caso de existir obstáculo, girará en dirección contraria al obstaculo y en el caso de que ninguna variable comunique obstáculo seguira hacia adelante.
Existen más funciones para que esta programación que he explicado funcione correctamente, como la realización de los pulsos, que he situado fuera del loop() al igual que muchas otras funciones.

El setup() lo he configurado, para que una vez cargado todos los datos se encienda el led durante dos segundos. ¿Por qué? Es una manera muy sencilla de comprobar que el setup() se ha cargado de forma correctamente, puede parecer una tonteria pero si no se encendiera el led, sabria que si ocurre algun problema, el error probablemente procederá del setup().
Una vez que se apague el led, el loop() se iniciará y tan solo se volverá a iluminar el led cuando el sensor detecte algún obstáculo.

DESCARGAR CÓDIGO ROBOT EVITA-OBSTACULOS 


No olvidéis comentar lo que queráis y si tenéis dudas, no dudes en dejar algún comentario en el foro y si habéis realizado el proyecto subir una foto o un vídeo.

Arduindroid.



3 comentarios:

  1. GRACIASSSSSSS. Si lo llego a hacer cosa que queda muy poco tiempo para hacerlo como proyecto final de curso os lo enseño. SALu2

    ResponderEliminar
  2. Muy buenas, excelente tutorial, estamos en clases desarrollando el proyecto y está casi todo listo, tenemos que terminar la alimentación y sobre todo el código fuente, ya que hemos optado por utilizar los servos más sencillos de 60º, que tenían que trucarse, tenemos también el texto del fuente para controlar el motor trucado, pero no me termina de ejecutar, también comentar que estamos haciendo un cambio en el tema de los sensores, estamos utilizando unos pulsadores, ya veré la forma de haceros llegar fotos, cambiamos también el chasis, es en base a un case de disco duro.

    Muchas gracias por el aporte, espero me pudierais aconsejar con respecto a los 2 temas, tanto de los servos trucados como de los sensores (que parámetros debería cambiar, creo será necesario simplemente utilizar pines digitales ya que cuando se tope contra algo es cuando activará el giro.

    ResponderEliminar
  3. Hola, muchas gracias por visitar nuestro blog.

    Referente a tus dudas:
    Si no he entendido mal los servos trucados no se te mueven al subir el código a la placa, eso puede ser porque los anchos de pulso que mandas a los servos no sean los adecuados, ya que yo utilizaba los propios que recomendaba el fabricante para ese modelo concreto de servos, ese puede ser un caso, o el otro que no lo hayas conectado a pines PWM.

    Y respecto a los sensores que pretendes utilizar si son tipo "switch" son fáciles de programar.

    Tienes que guardar en una variable le lectura del sensor p.ej

    lectura=digitalRead(numero pin);

    if lectura==true
    {
    aqui programas lo que quieras que haga el robot al toparse contra el obstaculo

    }

    Si no te referias a este tipo de sensor, deja un comentario con un link y veremos que podemos hacer por ayudarte.

    Espero que te haya servido de ayuda.

    Un saludo

    ResponderEliminar