Aplicaciones con Arduino.
PROLOGO.
Arduino es una plataforma de código abierto, basada en una sencilla placa con entradas y salidas analógicas y digitales, posee además de una memoria No-volátil cuya capacidad depende de la versión de microcontrolador utilizado, los primeros disponían de 8Mbytes, sin embargo se puede intercambiar por otros de gama mayor 16Mbytes o más. El entorno de desarrollo está basado en el lenguaje Processing/Wiring.
Mediante los pines de entrada/salida, puede recibir señales de gran variedad de sensores, de modo que puede interactuar en su entorno, controlando luces, motores o actuadores, trabajando de manera autónoma o a través de un programa corriendo en un computador (por ejemplo, Macromedia Flash, Processing, etc.). Está compuesto por un micro controlador Atmel AVR que viene pre-programado con una secuencia de arranque (Boot Loader), con el que se puede actuar sobre el contenido de la memoria, por lo que no necesita un programador externo.
El protocolo de comunicación que utiliza Arduino es el RS232 serie. Los protocolos de comunicación, se han desarrollado para que las máquinas pueden enviar y recibir datos a/de otras máquinas. Cada protocolo se compone de un conjunto de normas que definen cómo se representan los datos. El protocolo RS232 serie, es un viejo protocolo bien establecido en la década de 1960. Que ha sido ampliamente reemplazado por protocolos más rápidos y más avanzado como el USB.
Sin embargo, sigue siendo ampliamente utilizado a través de emulación de software – en gran parte debido a su fácil aplicación. Configurar una conexión en serie, consiste en especificar un puerto (COM en Windos, / dev / Linux, OS X) y una velocidad de comunicación para cada dispositivo o máquina. Arduino, también dispone y utiliza el protocolo vía USB para comunicarse, con un computador externo.
La presentación, es un tema que ya está muy desarrollado por los propios creadores y una larga lista de entusiastas que venimos utilizando esta plataforma, por dicho motivo no me extenderé más.
APLICACIONES.
Entre las aplicaciones, debido a las posibilidades que presentan sus entradas, nos permite utilizar una gran variedad de sensores, como se ha dicho. Para no repetirme con proyectos de los primeros pasos en esta plataforma, aquí daremos un pequeño salto y voy a describir cómo controlar un relé, luego veremos como podemos leer la posición de un potenciómetro (más corto pot), más tarde, veremos como controlar el giro de un servomotor. Esto es sólo el arranque de una aventura con la compañía de nuestro Arduino.
1 2 3 4 5 6 7 |
<a href="#Control_de_un_relé.">Control de un relé.</a> <a href="#Un_pulsador.">Un conmutador.</a> <a href="#Leer_la_posición_de_un_potenciómetro.">Leer la posición de un potenciómetro.</a> <a href="#Control_de_un_servo.">Control de un servo.</a> <a href="#Ejemplo_1.">Ejemplo 1.</a> <a href="#Ejemplo_2.">Ejemplo 2.</a> <a href="#Motor_DC.">Motor DC. </a> |
MATERIALES NECESARIOS.
Es conveniente disponer de un mínimo de componentes para llevar a cabo las presentes prácticas, a continuación, sigue una lista de los componentes más relevantes:
CONTROL DE UN RELÉ.
Para empezar, una aplicación sencilla, ésta consiste en activar un relé mediante un sensor. El sensor puede ser cualquiera que se adapte a las necesidades del proyecto. En ente caso, vamos a utilizar un simple mini pulsador de los que podemos encontrar en el comercio o si lo preferimos en multitud de equipos que ya no nos sirven y de los cuales podemos recuperar dichos pulsadores entre otros componentes. Un relé cuya tensión de trabajo puede ser de 12V, un diodo de protección que puede ser un 1N4148 o en su defecto un 1N4001.
Este es el circuito que necesitaría para activar un relé de 12V controlado por una salida digital del Arduino, en él se puede ver los componentes que se utilizan habitualmente, el diodo D1, evita la destrucción del transistor por la contra corriente producida por la inducción del relé. Se ha utilizado un relé de dos circuitos, para producir el efecto memoria, es decir, cuando se ceba el relé, el contacto secundario, al cual se ha intercalado el pulsador ‘reset’, el circuito de activación permanece activo hasta que se pulsa éste pulsador que corta el circuito de retención o memoria.
EL ESQUEMA.
El esquema es muy simple, se puede apreciar en la imagen de abajo, generada con la ayuda del programa gratuito fritzing.
Ahora, lo primero que hemos de hacer es abrir el editor de texto habitual (o Notepad), vamos a escribir nuestro programa para que al presionar el pulsador el relé se active. Si lo desea, puede copiar y pegar el contenido del archivo del programa que encontrará aquí, guárdelo con el nombre «pulsador.pde», cárguelo en el IDE de Arduino y verifique su sintaxis y lo puede cargar en su Arduino.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* * Pulsador.pde * * Autor: V. García * Cambia estado de un relé, conectado al pin digital 13, con un transistor * si es necesario, cuando presionas un pulsador conectado al pin 7. * Se desconecta al liberar el pulsador. */ int switchPin = 2; // elige el pin 2 de entrada (para un botón) int relePin = 8; // elige el pin 13 para el relé int val = 0; // variable para leer el estado de pin2 void setup () { pinMode (relePin, OUTPUT); // declara relePin como salida digitalWrite(switchPin, HIGH); // activa la rpa al pin 2 pinMode (switchPin, INPUT); // declara el botón como entrada } void loop () { val = digitalRead (switchPin); // lee valor de la entrada if (val == HIGH) { // comprueba si la entrada es ALTA (botón libre) digitalWrite (relePin, LOW); // si, cambia y desactiva el relé. } else { digitalWrite (relePin, HIGH); // no, cambia y activa el relé. } } |
¿QUÉ HEMOS HECHO?
El primer apartado corresponde al nombre del archivo, la descripción, fecha y autor; todo esto se pone entre líneas comentadas, es decir, cada línea está precedida por dos barras «// comentario» o en su caso «/* comentarios */». Esta sería una sección que serviría:
1 2 3 4 5 6 7 8 |
/* * Pulsador * * Autor: V. Garcia * Cambia estado de un relé, conectado al pin digital 13, con un transistor * si es necesrario, cuando presionas un pulsador conectado al pin 7. * Se desconecta al liberar el pulsador. */ |
El principiante, debe utilizar una cabecera similar para sus proyectos. A continuación, se deben declarar los archivos a incluir así como, las variables que se utilizaran en el programa.
Es bastante normal el uso de librerías que incorpora la plataforma Arduino, como: servos.h, timer.h, rtc.h u otras, dependiendo de las necesidades del programa. En esta actividad, no se utilizan librerías extras, debido a lo sencillo del proyecto. La forma de utilizar las librerías es como se ve en el siguiente ejemplo:
1 |
#include <<span style="color: #339999;">Servo</span>.h> <span style="color: #009900;"> // esto indica que utiliza la librería servo.h</span> |
En la siguientes líneas se declaran las distintas variables. Vemos que se declara como entero (int) el valor del pin digital 2, donde se leerá el estado del pulsador. También se declara, como entero (int) el pin digital 11, donde aplicaremos el relé o mejor dicho, el transistor que manejará el relé. Utilizaremos el transistor por dos razones, por si la corriente que necesita el relé es mayor que la que proporciona la salida del Arduino y por que nos sirve de separador de las corrientes inducidas, por la bibina del relé.
1 2 |
<span style="color: #3366ff;">int</span> switchPin = 2; <span style="color: #009900;">// pin digital de entrada para switch</span> <span style="color: #3366ff;">int</span> relePin = 8; <span style="color: #009900;">// pin digital de salida para relé</span> |
La siguiente sección, se encarga de configurar los pines involucrados en el proyecto e inicia el puerto serie, si intervienen las comunicaciones serie.
1 2 3 4 5 6 |
void setup() { <span style="color: #009900;"> // esta sección, sólo se lee una vez, cuando empieza el programa.</span> pinMode(switchPin, INPUT); <span style="color: #009900;">// declara el botón como entrada </span> digitalWrite(switchPin, HIGH); <span style="color: #009900;">// activa la rpa al pin 2 </span> pinMode(relePin, OUTPUT); <span style="color: #009900;">// declara relePin como salida</span> <span style="color: #009900;"> // Serial.begin(9600); // inicia la comunicación Serial. Si fuera necesario.</span> } |
Configurar, con el pinMode(switchPin, INPUT);, le indicamos al programa que el pin digital 2 estará en modo entrada. Con digitalWrite(switchPin, HIGH); se activa la RPA (resistencia polarización interna a alto), esto fuerza al pin2 a ver un H, si no es presionado el pulsador. Con pinMode(relePin, OUTPUT); se declara el pin digital 8 como salida. Y si interviene la comunicación, con Serial.begin(9600); le indicamos que, inicie la comunicación con la consola a 9600 baudios/s, en este caso. Léase la guía de Arduino, para más detalle. Esta rutina del seup(), se lee una sola vez, al iniciar el programa o después de un rest.
Ahora, se añadirían las distintas rutinas que intervinieran en el proyecto, no es el caso en este proyecto. Las rutinas, si las hay, se leen una vez, al iniciar el programa o después de un rest y posteriormente cuantas veces sea necesario, al ser llamadas por el flujo del programa.
Por último, se abre el bucle o loop() (lazo) en donde se repetirá indefinidamente el flujo del programa, hasta que lo abortemos con un reset o corte de tensión.
1 2 3 4 5 6 7 8 9 |
void loop() { val = digitalRead (switchPin); <span style="color: #009900;">// lee valor de la entrada </span> if (val == HIGH) { <span style="color: #009900;">// comprueba si la entrada es ALTA (botón liberado)</span> digitalWrite (relePin, LOW); <span style="color: #009900;">// si, cambia y desactiva el relé. </span> } else { digitalWrite (relePin, HIGH); <span style="color: #009900;">// no, cambia y activa el relé.</span> } } |
Se observa que el relé se activa mientras está presionado el pulsador y se desactiva al ser liberado éste. Esto confirma que el programa hace lo que preveíamos, sin embargo, ahora, vemos que, esto realmente no es lo que queríamos (el programa no adivina lo que queremos), lo que nos iría mejor es que se activara el relé con una pulsación y con una segunda pulsación se desactivara.
Por lo tanto, tenemos que modificar en parte el programa ya que este, realmente responde a la acción del pulsador mientras este es presionado y lo que queremos es un conmutador.
UN CONMUTADOR.
Como todos sabemos, un conmutador tiene dos estados estables, los cuales se cambian con una acción mecánica externa. Esto mismo lo llevaremos a nuestro entorno Arduino. Las primeras líneas como siempre, describen lo que hace el programa, en segundo lugar, están las variables, usaremos nombres intuitivos, fáciles de comprender como switchPin para el pulsador, outPin para la salida y otros que se comentan en el propio programa. Haremos uso de una función de tiempo como esmillis(), para controlar el siempre presente problema de los rebotes lo que se conoce en inglés como bouncing.
En la configuración (setup), aprovecharemos las posibilidades que nos presentan los pines digitales, esto no sólo lo haremos para evitarnos una resistencia, como son las RPA (resistencias de polarización a alto), si no, para verificar la importancia que tiene este detalle, pero eso lo veremos más tarde.
RECOMENDACIONES.
Es importante recordar las recomendaciones al respecto de los pines configurados como salida (OUTPUT) con pinMode() se dice que están, en estado de baja impedancia. Esto significa que puede proporcionar una cantidad sustancial de corriente a otros circuitos. Los pines del Atmega pueden proporcionar corriente positiva o proporcionar corriente negativa de hasta 40 mA (miliamperios) a otros dispositivos o circuitos. Esta es suficiente corriente para la brillante luz de un LED (no se olvide de la resistencia en serie) o para utilizar muchos sensores por ejemplo; sin embargo, no es conveniente utilizar las salidas directamente en los dispositivos con inductancias, como relés, solenoides o motores.
Los cortocircuitos en los pines de Arduino o intentos de extraer mucha corriente de ellos, pueden dañar o destruir los transistores de salida en el pin, pudiendo dañar completamente el chip Atmega. A menudo, esto se traducirá en un pin del microcontrolador «muerto», pero el resto del chip seguirá funcionando adecuadamente. Por esta razón es buena idea conectar los pines de salida a otros dispositivos con resistencias de 470Ω o 1k, limitando la corriente máxima que desde los pines es requerida para una aplicación particular. Veamos el código.
Conmutador.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* conmutador.pde * * Cada vez el pin de entrada va de BAJO a ALTO (p.ej. debido a apretar un botón), * el pin de salida basculará de BAJO a ALTO o de ALTO a BAJO. Hay un retraso * mínimo entre basculados, para evitar los rebotes del circuito. * (así no haremos caso del ruido). * * Modificado por V. García 30062009 23:10H * * Funciona correctamente, emplea 2.514 bytes. * */ // variables. int switchPin = 2; // input pin2 (switch o pulsador) int outPin = 8; // pin8 output del pin2 int estado = 0; // estado actual del pin de salida int previo = 0; // lectura anterior del pinX de entrada int reading; // lectura actual del pin de entrada // las siguientes variables son para el tiempo, medido en miliseconds. long time = 0; // la ultima vez que el pin de salida fue basculado long debounce = 500; // el tiempo de rebote, aumenta si la salida parpadea void setup() // Configuramos los pines { pinMode(switchPin, INPUT); // pone como entrada el pin2 digitalWrite(switchPin, HIGH); // activa la rpa del pin 2 pinMode(outPin, OUTPUT); // pone el pin 8 como salida Serial.begin(9600); // activa comunicaciones serie } void loop() { reading = digitalRead(inPin); // solo si la entrada va de BAJO a ALTO y hemos esperado tiempo suficiente // para que ningún rrebote afecte al circuito, el pin de salida basculará y // recordará desde cuando. if (reading == HIGH && previo == LOW && millis()+100 - time > debounce) { if (estado == HIGH) { estado = LOW; time = millis(); } else { estado = HIGH; time = millis(); } } digitalWrite(outPin, estado); previo = reading; } |
Por seguridad ponga una resistencia limitadora de 270Ω y un LED conectados entre el pin digital 8 y masa. Se puede apreciar que, cuando presiona el pulsador se enciende el LED y si vuelve a pulsar, se apaga el LED, ahora permanece en cada estado hasta que se produce una nueva pulsación, justo lo que queríamos. De nuevo, si lo desea, puede copiar y pegar el contenido del archivo de este programa que encontrará aquí, guárdelo con el nombre «conmutador.pde» para poder recordarlo con facilidad.
Ahora, como ya comenté antes, vamos a ver la importancia de las RPA’s. Para lo cual, haremos un pequeño cambio en el programa, se trata de comentar las dos línea que siguen:
1 2 |
digitalWrite(inPin, HIGH); <span style="color: #009900;">// activa la rpa del pin 2</span> pinMode(outPin, OUTPUT); <span style="color: #009900;">// pone el pin 8 como salida</span> |
debe quedar así:
1 2 |
<span style="color: #009900;">// digitalWrite(inPin, HIGH); // activa la rpa del pin 2 // pinMode(outPin, OUTPUT); // pone el pin 8 como salida </span> |
Lo debe compilar de nuevo y ejecutarlo. ¿Qué ha notado? Cuando acerca la mano al pulsador, se cambia el estado del LED y además el LED no se enciende con la misma potencia.
En primer lugar, es tan sensible que, influye la capacidad de la mano con el conductor del pin 2 al pulsador, esto hace que haya una incertidumbre de estabilidad, parece descontrolado. Sin duda, la RPA tiene su importancia.
En cuanto a la indefinición del estado de salida del pin digital 8, hace que la tensión de salida sea inferior a la de alimentación y éste es el efecto que produce, parece de poca importancia, pero no debe descuidar este detalle, puede llevarle a innecesarios quebraderos de cabeza.
Ya puede sustituir el diodo LED, por un transistor BC549 o similar y conecte el relé en el colector, como muestra el circuito de arriba. Los negativos de las tensiones utilizadas, siempre deben unirse. Con esto, terminamos la presente práctica, como siempre, si desea alguna aclaración, puede hacerme llegar su consulta.
EL POTENCIÓMETRO.
Como ya dije al principio, este es el momento de leer la posición de un pot. Seguramente esta pensando, para que sirve leer la posición de un pot. Para que mediante un programa (soft), lograr mover el eje de un motor, una cantidad de grados, es una respuesta posible o igualmente controlar la velocidad del motor. ¿Cómo? ¡Ya tiene más respuestas, como estos ejemplos!. Eso esta bien. Aclarado esto, podemos seguir. Observe la figura que sigue. Que le sugiere.
Hay infinidad de programas en la red que, muestran como hacer esto, por lo tanto, no hay necesidad de «inventar» nada nuevo. Ya que no voy a mejorar nada, con permiso del autor (no consultado), voy a exponer uno de esos ejemplos, para que sirva a mi propósito que es avanzar en este documento. Sin más preámbulos:
Los extremos del potenciómetro se conectan al +5V y a masa 0V. El punto central, se conecta a una entrada analógica pin2 (pin0 – pin3), con la ayuda de un voltímetro se puede leer la tensión de salida, los valores así obtenidos, los procesaremos y esperemos a ver los resultados obtenidos. Realmente, hemos hecho un divisor de tensión, el programa leerá los valores de tensión de la entrada por el pin analógico 2 conectado al terminal central del pot. El valor leído así, varía de 0 a 5.000mV y es proporcional a la posición de mando del potenciómetro, por ese motivo debe utilizarse un pot lineal. El valor obtenido se puede analizar a través de la conexión serie que se controlará visualmente mediante la pantalla del monitor.
Aclaremos esto de los pines analógicos, estas entradas analógicas en Arduino son manejadas por un convertidor analógico/digital de 10 bits, por lo que entregan a su salida, valores entre 0 y 1023 (2^10 – 1=1023). Así que, la tensión que entrega el pot a la entrada analógica, en la función analogRead, variará entre 0 (cuando esté a 0V) y 1023 (cuando esté a 5V).
Veamos un código que nos sirva de partida para nuestro propósito.
EL CÓDIGO.
El programa se basa en un simple código, con el cual, una entrada analógica recibe las variaciones de niveles de tensión que posteriormente convierte a números que podemos interpretar. Este ejemplo, muestra cómo se desvanece un LED conectado al pin 9, no olvide utilizar la función analogWrite(). Este código que sigue, es de dominio público.
Dimer 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Enciende un LED con PWM según pos. potenciómetro int potPin = 2; // seleccionar el pin de entrada analógico 2 para el pot int ledPin = 9; // seleccionar el pin de salida digital 9 para el LED (PWM) int val = 0; // variable para almacenar el valor capturado desde el sensor void setup() { Serial.begin(9600); // sets the serial port to 9600 pinMode(ledPin, OUTPUT); // declara el ledPin en modo salida } void loop() { val = analogRead(potPin); // lee el valor del sensor analogWrite(ledPin, val); // enciende LED Serial.print(val); Serial.println(" "); delay(20); // detiene el programa por un tiempo determinado. } |
Copie, pegue y guarde este código con el nombre leepot.pde. Ahora, compile, cargue el programa al Arduino y compruebe el resultado. Cuando mueve el eje del pot el brillo del LED varía, sin embargo no parece estar dentro de lo esperado, debería ir más fino, no le parece.
Porque ocurre que, cuando debería estar el LED apagado del todo, está parpadeando. Esto se debe a que el valor que se lee del pot. se convierte en fracciones de 0-1023, esto entra en conflicto, puesto que el valor máximo de un byte es 255. Este es el motivo por el que, encontramos como cuatro puntos de apagado o encendido al girar de un extremo a otro el eje del pot. Esto lo podemos comprobar simplemente realizando la prueba que sigue:
1 |
analogWrite(ledPin, val/4); // enciende LED. Dividimos 1024 por 4, para obtener de 0 a 255. |
Y volvemos a compilar, cargar y por fin comprobamos que ahora sí, obtenemos el resultado que esperábamos. Hay un detalle que no debe pasar desapercibido, me refiero al función utilizada analogWrite() por la anterior digitalWrite(), esto es así, para que podamos aprovechar la Modulación por Ancho de Pulso PWM (en inglés Pulse Width Modulation) que llevan algunos de los pines de salida del Arduino. Para obtener más información, consulte la página de la biblioteca Arduino.
Dimer 2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* * PotDimer * --------- * * Uso de un potenciometro para adjustar el brillo del LED PWM's * * Como el máximo valor de salida del convertidor es 255, el * valor leido del pot, tenemos que vividirlo por 4 * de esta forma podremos mostrar sus valores. * */ int potPin = 2; // selec. el pin entrada del potenciómetro int ledPin = 9; // selec el pin para el LED int val = 0; // variable para guardar el valor leído por el sensor void setup() { pinMode(ledPin, OUTPUT); // declara el ledPin como OUTPUT Serial.begin(9600); } void loop() { val = analogRead(potPin); // lee el valor del sensor analogWrite(ledPin, val/4); // pone el ledPin encendido Serial.print(val); // imprime valor del pot y vuelve al panel de depuración Serial.println(" "); delay(20); // espera 20 seg } |
Así que, el código final es el siguiente:
Ahora sí, copie, pegue y guarde o descargue el código de aquí, dele el nombre por ejemplo potdimer.pde, compile, cargue y compruebe que, ahora sí, obtenemos el resultado que esperábamos. El LED realmente se desvanece (fading), en la medida que variamos el eje del pot. o al contrario, se enciende. ¿Esto, nos servirá en el caso de los servos?.
SERVOMOTOR.
Una simple descripción de un servomotor puede ser esta: es un pequeño motor eléctrico que, puede ser controlado para que gire a una posición angular específica y mantenerse estable en dicha posición. Algo más concreto, el servo, consta de un motor de corriente continua, con una caja reductora y un circuito de control, para su posicionamiento. Los servomotores tienen tres hilos: alimentación, tierra o masa, y señal de control. El cable de alimentación suele ser rojo y debe ser conectado al pin de 5V, el cable negro se conecta a masa (0V) y el cable de control puede ser de color amarillo, naranja o blanco, por el que se aplican los pulsos para su control.
Existen un gran número de aplicaciones que vienen utilizando este tipo de servomotores, por ejemplo controles de juguetes, máquinas herramienta, robots, etc. entre otras. Actualmente, con la proliferación de los micro controladores como Arduino o PIC entre otros, se viene desarrollando una gran cantidad de aplicaciones, cuyo límite es la imaginación.
Fig. 5 Vista de la caja reductora y engranajes
Cuando haya que utilizar un servomotor, se deben tener en cuenta, un mínimo de factores básicos a considerar como:
- Recorrido de giro o sea, intervalo angular, 0 – 180 grados o 360 grados (giro completo).
- Velocidad de giro.
- Par (torque o fuerza) que el servo puede generar.
- Tamaño, peso, coste, etc.
Como hemos visto, los servo-motores tienen engranajes reductores integrados y un eje que se puede controlar con precisión. Los servos estándar, permiten que el eje se controle con precisión en ángulos de pocos grados, por lo general entre 0 y 180 grados. Los servos de rotación continua permiten la rotación del eje a distintas velocidades. El control de parada, se puede realizar de forma automatizada (soft) o mediante la acción de un pot que permite modificar el ángulo de giro con cierta precisión. Para una descripción más detallada debe visitar este sitio. También puede visitar el artículo sobre, cómo trucar un servo conservando la electrónica, en trucar_servo_futaba_s3003.pdf, aquí
Nota: En todos los ejemplos que se presentan en este artículo, recomiendo utilizar la librería #include <Servo.h> de la versión 0018 o posterior. No se presenta el enlace en este sitio, para no inducir a error.
De esta forma ya tendremos acceso a una serie de comandos del servo como: myservo, myservo.attach(#); myservo.write(pos); etc. Veamos un par de ejemplos que ilustren estos comandos entre otros, donde pos es un valor entre 0 y 180º aproximadamente.
Como se aprecia en la imagen anterior, para las próximas prácticas y puesto que la placa Arduino puede manejar directamente hasta seis servos, necesitamos estos componentes; un Arduino, un potenciómetro y un servo-motor estándar (he utilizado el S3000 de Futaba, por tener algunos en el cajón), con un margen de giro de 0-180º. Esto bastará, espero, para comprender cómo controlar un servo.
Porque me he decidido por el control del servomotor antes que del motor DC, es una cuestión de practica, ya que Arduino tiene capacidad para manejar un servo (realmente hasta seis) en cada una de las salidas dotadas de PWM, lo cual permite la conexión directa del servo al pin elegido, no es por otra cuestión. Dicho esto, voy a seguir con lo propuesto.
En el IDE de Arduino disponemos de la librería Servo.h, resultará hasta cierto punto sencillo el control de un servo como vamos a comprobar. Empezaremos por algo sencillo, en el propio IDE Arduino viene un ejemplo que vamos a utilizar.
EJEMPLO 1.
Ejercicio-1. Veamos un ejemplo de control de un servo, código que, he tomado de la web de Barragan, he reducido un poco el código, para mi propósito. En este código, se aplica la señal PWM que dirigimos al pin digital 9. Como se puede comprobar no tenemos ningún modo de influir externamente en lo que hace el programa. En él, el servo, gira en un sentido y al llegar al final predeterminado (180º), inicia un retroceso hasta volver al punto predeterminado (0º), así de simple, no hay más. El que sigue es el código.
Sweep (Barrido)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Sweep (Barrido) // ejemplo 1 // by BARRAGAN #include Servo myservo; // create servo object to control a servo // a maximum of eight servo objects can be created int pos = 0; // variable to store the servo position void setup() { myservo.attach(9); // attaches the servo on pin 9 to the servo object } void loop() { for(pos = 0; pos < 75; pos += 1) // goes from 0 degrees to 180 degrees { // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(15); // waits 15ms for the servo to reach the position } for(pos = 75; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees { myservo.write(pos); // tell servo to go to position in variable 'pos' delay(15); // waits 15ms for the servo to reach the position } } |
En el código de barrido, porque se trata de un barrido, como el limpia parabrisas de un coche. Un recorrido en un sentido y acto seguido cambia el sentido y hace otro barrido o recorrido. Con la señal PWM se controla el punto de ajuste de posición, no la velocidad.
En el código, el punto de ajuste de posición (pos) cambia en un grado cada 15 milisegundos. No tiene mucho sentido un cambio mayor de 15 milisegundos, porque el período PWM, base de los servos es de unos 20 milisegundos.
Para controlar la velocidad del barrido, se necesita controlar la rapidez con que cambia el punto de ajuste. Por ejemplo un incremento de 3 grados (pos += 3), hará un barrido tres veces más rápido (naturalmente, sujeto a la velocidad máxima del servo en uso).
Por lo tanto, este ejemplo tiene una aplicación muy concreta y para mi propósito no es exactamente lo que esperaba. Voy a realizar algunos cambios a continuación.
Ejercicio-2. Pretendo aplicar al servo, una salida de Modulación de Ancho de Pulso y mediante la variación de una señal analógica (potenciómetro), modificar el ancho del pulso, con lo cual variará el ángulo de giro del servo motor.
Código.
Vamos a controlar el giro de un servomotor conectado a un pin analógico. Mediante la señal analógica del potenciómetro, leída por el pin analógico 2 (analogPin), regularemos el ángulo de giro del servo según el giro del eje del potenciómetro. En este ejemplo, para reducir el código, se utiliza la librería Servo.h.
Servo con pot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* * potservo.pde * * by V. Garcia * Controlar un servo con Arduino, se utiliza un pot en el pin analogico 2 * el servo se conecta al pin 9 (PWM). * Utilizando Arduino v0018, funciona bien. Si utiliza la ver. 0013, debe * cambiar la librería Servo en Harware/libreries/Servo, para que funcione. */ #include //include the servo libary Servo myservo; // crea el objeto servo para control del servo // a maximum of eight servo objects can be created int analogPin = 2; int = 2; // Valor devuelto por el sensor analogico (pot.) int pos = 0; // variable para guardar posición del servo void setup() { myservo.attach(9); // attaches the servo on pin 9 to the servo object } void loop() { analogValue = analogRead(analogPin); myservo.write(analogValue*8/50); // dice al servo la position en variable "analogValue" delay(15); // espera 15ms a que servo reaccione a la posición } |
El código anterior es sencillo (si utiliza una versión del IDE Arduino, anterior a la ver. 0018, debe cambiar la librería Servo.h ubicada en las librerías, para que funcione), el valor leído, entrada del pin 2 (procede del potenciómetro), será convertido en un byte para indicar la posición del servo. El pin de salida (PWM) es el pin 9, al mover el eje del pot, el servo reaccionará desplazándose en proporción al total del giro permitido.
Si dispone de un servo de giro continuo, haga la prueba, con este código de ejemplo. Observe que, con el eje del pot girado a un extremo, el servo gira en una dirección y cuando pone el eje del pot en el otro extremo, el servo cambia también de dirección, girando de forma continua en ambos casos.
Trate de girar el pot lentamente; encontrará un punto en el que el servo se detiene. Reajuste el punto de giro del servo ajustando el potenciómetro interno del servo (ver imagen anterior), para hacer coincidir el centro del recorrido del servo e igualar ambos lados de giro. ¡Uf!, espero se me entienda.
EJEMPLO 2.
En los dos códigos que hemos descrito en el ejemplo anterior, se ha utilizado la librería Servo.h mediante la cual se tiene acceso a los comandos que (aunque, nos es transparente) reducen nuestro código. En este ejemplo, voy a presentar un código que permita el mismo resultado, obtenido en el ejemplo anterior, sin dicha librería.
El Código.
Hay diferentes opciones para cubrir este tema, algunas versiones utilizan el map(), otras en cambio, utilizan otros medios, el caso es, respetar los parámetros de frecuencia con un período de 20ms y la modulación por ancho de pulso, PWM entre 0’5 y 2’4 ms.
Utilizando el código de más arriba y modificando unos detalles, podemos conseguir mover el eje de un sencillo servo, desde un extremo al otro de su habitual recorrido. El siguiente es el código:
Servo poteniómetro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* * Pot_Servo.pde * --------- * * Uso de un potenciometro para mover el servo por PWM * * Como el máximo valor de salida del convertidor es 255, el * valor leido del potenciómetro, tenmos que vividirlo por 4 * de esta forma podremos mostrar sus valores. * */ int potPin = 2; // selecciona el pin input para el potenciometro int ledPin = 9; // selecciona el pin para el servo int val = 0; // variable para guardar el value del sensor void setup() { pinMode(ledPin, OUTPUT); // declare the ledPin as an OUTPUT Serial.begin(9600); } void loop() { val = analogRead(potPin); // lee el valor desde el sensor val = val/4; // convierte desde 0-1023 en 0-255 analogWrite(ledPin, val); // devuelve el ledPin on Serial.print(val); // imprime el valor devuelto pot por el panel debugger Serial.println(" "); } |
Como se puede comprobar, este código es bastante endeble para su uso habitual, necesitamos un código más robusto, con el cual podamos asegurar el emplazamiento del eje motor del servo en una posición más ajustada al eje del potenciómetro. Este código que se muestra a continuación puede servir.
Servo control.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/* Servo control, con una entrada analógica. by Tom Igoe additions by Carlyn Maw & Rob Faludi Created 28 Jan. 2006 Updated 10 Jun. 2008 http://itp.nyu.edu/physcomp/Labs/Servo Funciona bien, necesita 2114 bytes */ int servoPin = 2; // pin para control servo motor int minPulse = 500; // posicion Minima servo int maxPulse = 2500; // posicion Maxima servo int pulse = 0; // cantidad de pulsos del servo long lastPulse = 0; // el tiempo en milliseconds del ultimo pulso int refreshTime = 20; // tiempo necesario entre pulsos int analogValue = 0; // valor devuelto por el sensor int analogPin = 2; // pin analogico para el sensor void setup() { pinMode(servoPin, OUTPUT); // Set servo pin como un pin de salida pulse = minPulse; // Set del valor posicion motor para el minimo Serial.begin(9600); } void loop() { analogValue = analogRead(analogPin); // read the analog input pulse = map(analogValue,0,1023,minPulse,maxPulse); // convert the analog value // para un rango entre minPulse y maxPulse. // el nuevo pulso al servo, si el tiempo de actualización (20 ms) han pasado: if (millis() - lastPulse >= refreshTime) { digitalWrite(servoPin, HIGH); // Enciende el motor delayMicroseconds(pulse); // La longitud del pulso establece la posición del motor digitalWrite(servoPin, LOW); // Apaga el motor lastPulse = millis(); // guarda el tiempo del último impulso } } |
Los valores mínimo (minPulse) y maximo (maxPulse), serán diferentes dependiendo de su servo motor específico. Teóricamente, deberían estar entre 1 y 2 milisegundos, pero en la práctica 0,5 a 2,5 milisegundos suele funcionar bien. Pruebe diferentes valores para ver qué números son los mejores para usted.
Este programa, como bien advierte T. Igoe, utiliza la función millis() para no perder de vista cuando fue impulsado el servo por última vez. Así pues, la función millis() con el tiempo, produce un error de desbordamiento (es decir, genera un número que es demasiado grande para caber en una variable long) después de 5 días. Si usted está haciendo un programa que tiene que correr por más de 5 días, puede ser necesario tomar en cuenta de este dato.
MOTOR DC.
No entrare a describir que es un motor de corriente continua ya que, este es un conocimiento preliminar que, se supone debe tener el lector, para poder comprender lo que se describe en esta práctica. El motor, girará en el momento que se aplique una tensión de rango adecuado en sus bornes o terminales. Normalmente, los motores tienen una referencia en su cuerpo que nos indica sus características.
QUÉ PODEMOS HACER.
Con la capacidad de Arduino, vemos que se pueden controlar dispositivos de bajo consumo, como los LEDs, servos, etc. sin embargo, cuando tratamos de mayores consumos, sobre todo, con cargas con inducciones, como un motor de corriente continua, relés, etc., por precaución, se necesita utilizar al menos, un transistor externo.
Un transistor externo, es increíblemente útil, con él, se controla una mayor cantidad de corriente con la pequeña aportación de la señal procedente de Arduino. Cuando a un transistor NPN, se le conecta la carga al colector y el emisor a tierra, de modo que aplicamos a la base, la salida de Arduino del pin elegido, podemos mover el motor que girará en proporción a la señal que le entrega el pin.
CONTROLANDO LA VELOCIDAD.
Anteriormente, en un ejemplo, jugamos con el control de brillo de un LED mediante la modulación por ancho de pulso (PWM), ahora, vamos a utilizar la misma característica, para controlar la velocidad de giro de un pequeño motor de juguete. En el mundo real, vemos girar un motor de parado a máxima velocidad, variando la tensión que aplicamos. En el mundo de la electrónica ocurre lo mismo, se pasa de 0 a 5 voltios y con la informática se hace, mediante un byte de 0 a 255.
Con Arduino, se puede utilizar algo llamado, modulación por ancho de pulso (PWM), esto se consigue, mediante un A/D de 10bits, se basa en la capacidad de Arduino para operar muy, muy rápido. En lugar de controlar directamente la tensión procedente del pin, Arduino cambiará el pin de encendido a apagado muy rápidamente. Por ejemplo, si ponemos el PWM de Arduino al 50%, vemos una luz tenue, debido a la persistencia de nuestros ojos que, no reaccionan tan rápido como para ver que parpadea, la mitad del ciclo está apagada y la otra mitad del ciclo está encendida.
El mismo principio, servirá a nuestro propósito que, aplicando un transistor, dotará de una mayor capacidad de carga, al pin de salida que hayamos elegido, para manejar un motor, como podemos comprobar con el ejemplo que muestro a continuación.
Control Motor CC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// // Funccion: CC_motor_control_pot // // Utilizar un potenciometro para controlar un motor CC int ledPin = 9; // LED connected to digital pin 9 int analogPin = 2; // potentiometer connected to analog pin 3 int val = 0; // variable to store the read value void setup() { pinMode(ledPin, OUTPUT); // sets the pin as output } void loop() { val = analogRead(analogPin); // read the input pin analogWrite(ledPin, val / 4); // analogRead values go from 0 to 1023 // analogWrite values from 0 to 255 } |
Como puede verse el código utilizado es muy simple, lo que no deja de tener calidad. El valor que entrega el potenciómetro es dividido por 4, tratando de establecer una relación entre los valores leídos y los valores de un byte, de un modo muy simple.
Ahora presento un código algo más elaborado, con el que se obtiene un resultado algo más preciso:
Motor CC pot
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// // Función: motor_cc_control_pot // // Uso de un potenciómetro para controlar un motor CC int sensor_pin = 2; int motor_pin = 9; // un pin digital PWM output void setup() { Serial.begin(9600); pinMode(motor_pin, OUTPUT); } void loop() { long pot_val, motor_speed; pot_val = analogRead( sensor_pin ); motor_speed = pot_val*255.0/1024.0; // Incluir decimales /* Sutil: No utilice valores enteros cono 255 y 1024 aquí. Compiladores parcos pre-calculan la division entera del 255/1024 como cero. */ analogWrite( motor_pin, motor_speed); } |
Este es un ejemplo, nos permite el control del motor con muy pocos cambios, hay que resaltar la conversión de los valores leídos del potenciómetro, en esta ocasión se establecen dos parámetros que incluye punto decimal, esto se sugiere porque algunos compiladores, suelen entregar cero, al calcular una división como 255/1024, por no admitir decimales no declarados. Una vez más puede copiar y pegar en su editor preferido este código y comprobar su efectividad.
Nota. No debemos olvidar que debido a la poca intensidad de las salidas del Arduino, es necesario utilizar un transistor que nos permitirá una mayor corriente de salida, siempre que apliquemos una alimentación externa para completar la puesta en marcha.
En este tutorial, se ha tratado de dar una visión cuantitativa más que cualitativa, de las posibilidades que ofrece este sistema, en otros se estudiarán temas más específicos, donde se puede tratar en profundidad cada caso.
Esto es todo, por este simple tutorial.
los ficheros dowload.txt son siempre los mismos concretamente el ejemplo del pulsador.
¿teneis los enlaces mal?
Gracias
Hola Willy,
Gracias por tu inestimable información. Ya están corregidos los enlaces, y sí, son los archivos que puedes descargar los correspondientes a los listados, salvo los pdf y foros.
Gracias por colaborar Willy.