En una entrada de hace un par de semanas describía cómo construir un «botón sin contacto», por medio de una célula fotoeléctrica, en previsión que este tipo de interruptores van a utilizarse mucho más a partir de ahora, en este nuevo mundo durante y tras COVID-19…
Cuento ahora otro botón «sin contacto» también muy sencillo, empleando el sensor ultrasónico HC-SR04.
El concepto detrás de este sensor es muy sencillo: se emite un pulso de alta frecuencia que tras rebotar en un objeto es captado de vuelta por un micrófono. Midiendo el tiempo entre la señal emitida y la recepción de su rebote se puede calcular la distancia a la que se encuentra el objeto en cuestión.
Según la hoja de especificaciones, se alimenta de 5V y su rango de medida está entre 2 cm y 400 cm, con un ángulo de 15º. Es un sensor muy típico y barato (menos de 2€).
Instalo la librería NewPing desde el IDE de Arduino, y conecto de la siguiente forma:
Puede conectarse «Trig» y «Echo» a pines diferentes, pero con la librería «NewPing», que se puede instalar directamente desde el IDE de Arduino, se puede emplear un mismo pin, en mi caso el 5. A fin de cuentas, cuando se está emitiendo la señal no se está esperando la respuesta, por lo que se puede emplear el mismo pin para los dos propósitos.
Conecto también un led (con su resistencia correspondiente), de forma que me queda conectado así:
Y cargo el siguiente código:
<code>#include <NewPing.h>
// HC-SR04 -> Arduino Pro Micro (Leonardo):
// Vcc -> VCC
// Trig -> 5
// Echo -> 5
// Gnd -> GND
const int UltrasonicPin = 5; // Pin al que se envía y recibe la señal del HC-SR04
const int MaxDistance = 200;
const int ledPin = 9; // Pin al que está conectado el LED
const int distSens = 11; // Distancia por debajo de la cual se enciende el led
int dist;
NewPing sonar(UltrasonicPin, UltrasonicPin, MaxDistance);
void setup() {
Serial.begin(9600);
}
void loop() {
delay(50); // esperar 50ms entre pings (29 ms como mínimo)
dist=sonar.ping_cm();
Serial.print(dist);
Serial.println("cm");
if (dist < distSens)
{
Serial.println("Enciendo");
digitalWrite(ledPin, HIGH);
delay(50);
Serial.println("Apago");
digitalWrite(ledPin, LOW);
}
}</code>
En el vídeo del principio puede verse en funcionamiento.
En los tiempos que nos ha tocado vivir con la crisis del COVID-19 previsiblemente vamos a tener que habituarnos a un nuevo escenario vital, en el que deberemos cambiar ciertos hábitos y formas de relacionarnos entre las personas y de interactuar con los objetos, al menos por un tiempo.
Entre otras cosas, es de esperar que cada vez más se evite en la medida de lo posible tocar cosas que tocan otras muchas personas, como interruptores, por lo que seguramente se tenderá a interruptores sin contacto.
Describo aquí uno de esos tipos de botones, que pretendo emplear en un próximo proyecto (un termómetro infrarrojo sin contacto, para que por ejemplo las personas de una oficina puedan tomarse la temperatura de forma inmediata y sin contacto, estando colocado el aparatito en una zona común, como puede ser el baño…)
La verdad es que es uno de los proyectos más simples que puede haber: tomar lecturas de una célula fotoeléctrica y si se cumple cierto criterio (que baja la intensidad en un breve tiempo para luego recuperarse, que es lo que ocurre al pasar la mano por delante «a lo Jedi») enciende un LED.
En el fondo, es el mismo tipo de interruptor de los grifos automáticos:
Lo he hecho con un Arduino Micro (Leonardo), conectando los componentes según el siguiente diagrama:
El código que he creado es el siguiente:
<code>const int ledPin = 9;
const int fotoresistPin = 0;
const int sensibilidad = 5;
const int tiempoSens1 =200;
const int tiempoSens2 =50;
int valor;
int valorAnt;
int valorPrev;
void setup() {
Serial.begin(9600);
}
void loop() {
valor = analogRead(fotoresistPin);
Serial.print("Valor :");
Serial.println(valor);
valorPrev = valor;
if (valor < valorAnt - sensibilidad)
{
delay(tiempoSens1);
valor = analogRead(fotoresistPin);
if (valor >= valorPrev)
{
Serial.println("Enciendo");
digitalWrite(ledPin, HIGH);
delay(50);
Serial.println("Apago");
digitalWrite(ledPin, LOW);
}
}
valorAnt = valor;
delay(tiempoSens2);
}</code>
Y en el siguiente vídeo se puede ver en funcionamiento:
Quiero monitorizar la evolución en el tiempo de la temperatura de una masa de hormigón armado de gran espesor en tres puntos de su volumen durante su fraguado. Para ello, voy a disponer 4 sondas DS18B20 en el interior de la masa (en el centro, y cerca de las caras), y un sensor DHT22 en el exterior para controlar la temperatura y humedad ambientes, conectados todos a una Raspberry Pi que irá registrando los valores cada minuto, archivándolos en un pincho USB, y enviándolos por correo electrónico cada hora.
Materiales
Raspberry Pi. Vale cualquier modelo. Yo he empleado una Raspberry Pi B+ v1.2 que tenía disponible. Aprox 20€.
Tarjeta SD 16 GB. Valdría con una de 8 GB, lo suficiente para una instalación de Raspbian.
Memoria USB. Cualquier pincho USB que tengamos.
4x DS18B20 sumergibles. Comprados aquí por 2.59€ la unidad. Total: 7.77€
Sensor DHT22 de temperatura y humedad, para monitorizar la temperatura y humedad ambientes
5m cable CAT5
Modem 3G USB
Caja Estanca IP55, o un tupper.
Batería
Preparo los sensores
Los DS18b20 vienen con 1 m de cable. Como necesito algo más de longitud, empalmo un par de metros más por cada sensor y luego los junto todos a un cable de 5m. El tipo de cable que empleo es RJ45.
Hasta los 10m de longitud aproximadamente me basta con soldar entre dos de los cables una resistencia de 4.7kohm. Para longitudes mayores, en esta página hablan de la resistencia pull-up a disponer en función de la longitud del cable.
Tras soldar todos los cables, los protejo con cola térmica, y luego con cinta aislante.
Código para registrar las temperaturas
En esta entrada ya hablé de cómo usar un sensor DS18B20 con una Raspberry Pi, y esta otra, del sensor DHT22. Antes de la conexión definitiva hago pruebas con cada uno de los sensores por separado para ver que está todo en orden.
Básicamente, sigo los pasos que indiqué en la entrada en la que hablé del DS18B20 para probar que funcionan cada uno de los sensores. Una vez que averiguo el identificador de cada uno de los sensores, preparo este pequeño script en Python que registra la temperatura de los sensores en un fichero:
# -*- coding: utf-8 -*-
import os #Para poder pasar comandos al sistema (sudo modprobe...)
import time #Para poder sacar la hora del sistema
import logging #Para loguear los eventos
import Adafruit_DHT #Para poder usar el DHT
termo1 = "28-0417838399ff"
termo2 = "28-041783898fff"
termo3 = "28-04178386dbff"
termo4 = "28-04178389e9ff"
sensor = Adafruit_DHT.DHT22
pin = 24 #Pin donde está conectado el DHT22
#Cargo los módulos para el termómetro:
os.system("sudo modprobe wire")
os.system("sudo modprobe w1-gpio")
os.system("sudo modprobe w1-therm")
#Inicializo el log:
logging.basicConfig(filename='/media/pincho/temps.log',level=logging.INFO,format='%(asctime)s %(message)s')
#Función para obtener la hora del sistema:
def get_date_time():
return time.strftime("%d/%m/%Y,%H:%M:%S")
#Función para obtener la temperatura de un termómetro:
def get_temp_sens(term):
try:
ruta = "/sys/bus/w1/devices/" + term + "/w1_slave"
tfile = open(ruta)
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
temperature = round (temperature,1)
except:
temperature = 0
return float(temperature)
#Función para obtener la temperatura y humedad del DHT22:
def get_tempYhum():
try:
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
temperature = round (temperature,1)
humidity = round (humidity,1)
except:
humidity = 0
temperature = 0
return float(temperature), float(humidity)
hora = get_date_time()
temp0,humedad = get_tempYhum()
temp0 = str(temp0)
humedad = str(humedad)
tempsens1= str(get_temp_sens(termo1))
tempsens2= str(get_temp_sens(termo2))
tempsens3= str(get_temp_sens(termo3))
tempsens4= str(get_temp_sens(termo4))
linealog = hora + \
"," + temp0 + \
"," + humedad + \
"," + tempsens1 + \
"," + tempsens2 + \
"," + tempsens3 + \
"," + tempsens4
print(linealog)
logging.info(linealog)
Conexión de los sensores
Para conectar los DS18B20, decido emplear un conector RJ45 (para facilitar la conexión en obra) que saco de una tarjeta de red vieja que tenía por ahí (ni siquiera la desueldo, directamente la corto con una sierra:
Y le sueldo la resistencia y los cables que conectaré a la Raspberry Pi:
Configuro la Raspberry Pi
Descargo la última versión de Raspbian (Raspbian Stretch, 2018-03-13) y la instalo en una tarjeta SD con Etcher
Configuro Raspbian para poder acceder desde SSH, configuro los locales y teclado, etc. La nombro RaspiHormiMon
Creo un túnel reverso SSH, siguiendo las instrucciones que preparé en esta entrada.
Conecto el pincho USB
Además de enviar los datos por internet, voy a archivar los registros en un pincho USB. Para ello tengo que instalarlo y garantizar que se cargue siempre en el arranque, modificando /etc/fstab. Sigo los pasos que ya conté en esta entrada.
Conexión a internet
Pensaba que tendría que seguir los pasos de esta entrada que escribí hace un par de años, pero compruebo que al conectar el Huawei E303 con una tarjeta SIM con el pin deshabilitado, la Raspberry Pi la reconoce perfectamente (en las últimas versiones de Raspbian viene por defecto usbmodeswitch) sin necesidad de hacer nada y se conecta automáticamente a internet como si fuese una conexión alámbrica, eth1.
Que envíe el log por email
Configuro la Raspberry Pi para que pueda enviar ficheros por correo, siguiendo los pasos que cuento en esta entrada.
Crontab
Ahora añado las siguientes líneas al crontab para que se ejecuten las tareas descritas anteriormente:
Registro de temperaturas cada minuto
Envío por correo electrónico del fichero de registros cada hora
Como pretendo dejar el invento en una obra, que estará alimentado a saber de qué forma (un grupo electrógeno seguramente), le pongo una batería, que permita seguir funcionando si se va un rato la luz, y también que proteja de las subidas de tensión.
La alimentación se hará por medio de un cargador convencional micro-usb de 5V (los de los móviles).
Carcasa
Con todo ya listo, lo meto dentro de una caja IP55, que es relativamente estanca, y de dimensiones perfectas para encajar todo sin estar muy apretado.
Montaje en obra
Tengo que decir que yo no pude colocar los sensores en obra y los colocó mi compañero y amigo Jorge. Como no podía ser de otra forma, estuvo lloviendo mientras lo colocaba, por lo que ¡se empapó enterito!
Aquí van una serie de fotos de la colocación de los sensores en obra:
Resultados
La Raspberry Pi tomaba medidas cada minuto, y enviaba un correo electrónico con todo el registro cada hora.
Versión 2
Código revisado, que incorpora los leds de aviso de si hay un error cada minuto, para poder comprobar en obra una vez instalado que está todo en orden, sin tener que esperar a recibir el mensaje cada hora. En caso de haber algún problema, y tras descartar error en conexiones, podría ajustarse la resistencia variable (potenciómetro).
También instalé 5 conectores RJ-45, para poder conectar directamente varios cables y no tener que hacer laboriosos empalmes como tuve que hacer en la ocasión anterior…
He terminado un megáfono para regalarle a mi sobrino de tres años y que se dedique a gritar todo lo que quiera por él.
La idea es tener un juguete al que habla o grita por un lado y se amplifica por el otro (un megáfono). También le añado un conector de audio por si se quiere poner unos auriculares, y un potenciómetro para regular el volumen. Empleará unas baterías de ión litio recuperadas de la batería de un portátil, y se podrá recargar con un conector micro USB.
Lista de la compra:
Tubo de PVC diámetro 40 mm, con embellecedor (acoplamiento a pared para sifones). Comprado aquí por 3.50 €, aunque hubiera valido cualquier tubo, vaso de plástico, etc.
Amplificador audio LM386. Comprado aquí por 6 € (porque tenía prisa), pero si se quiere esperar unas semanas, puede venir de China por 1.19 €.
Potenciómetro con embellecedor (lo tenía por ahí). Realmente no es necesario, valdría el del kit LM386.
Altavoz 8 ohm reciclado de algún juguete (no recuerdo)
2 pilas 18650 extraídas de la batería de un portátil
BMS para 2 pilas 18650 en serie, comprado aquí por 2.25 €.
Módulo cargador de pilas de litio TP4056, comprado aquí (5 unidades por 1.99€; 0.40€ la unidad)
Convertidor DC-DC (Step-up) comprado aquí por 2.29 €.
Cables diversos, pegamento, etc…
Herramientas:
Soldador
Dremel (yo he usado uno que me fabriqué hace tiempo; ver esta entrada)
Algunas de las piezas antes de ponerme a montarlo todo:
El esquema de montaje es el siguiente:
Todo montado, a falta del convertidor de voltaje, que aún no me había llegado:
Hago la tapa a partir de un plástico cualquiera (de una tapa de un lector de DVD portátil que tenía por ahí), que corto del mismo diámetro que el embudo, y le hago unos agujeros para el altavoz, por medio de una plantilla:
Para trabajar con todo tipo de «inventos» es muy útil tener una fuente de alimentación. Las fuentes de ordenador de sobremesa se pueden adaptar de forma muy fácil para esto, y suministran (sin necesidad de hacer nada) diferentes voltajes:
+3.3 V
+5 V
+12 V
-12 V
(Combinando los anteriores podemos obtener otros voltajes, naturalmente).
Hay inifinidad de tutoriales por internet en el que explican cómo hacer esto, aunque relamente no hace falta un tutorial porque es cortar cables y listo.
Como puntos a destacar, para que arranque la fuente es necesario puentear el cable verde a cualquier cable tierra (negro). Y en función de lo antigua que sea la fuente será necesario añadir una resistencia o no; en mi caso no fue necesario.
Para hacer los agujeros en la cargasa recomiendo empezar con pequeños taladros y luego hacerlos más grandes.
Compré unos conectores como estos y estos los que realmente compré ya no los veo, pero hay miles)
Y para la próxima que me haga, las conexiones las voy a hacer con estas horquillas, que facilitará mucho la vida.
No hice muchas fotos durante el montaje, pero es que es muy básico todo…
Voy a contar cómo manejar un motor paso a paso (stepper) con Arduino a través de un driver A4988. En esta otra entrada ya expliqué cómo hacerlo con un controlador DRV8825, que es una versión mejorada del A4988 (el DRV8825 admite microstepping has 1/32, frente al 1/16 del A4988, 45V frente a 35V, y 2.5A frente a 2A).
Pololu driver A4988
Características principales del driver A4988:
Para motores bipolares
Permite microstepping de hasta 1/16
2A
Interfaz casi idéntica al DRV8825
35 V máximo
Control de corriente máxima con un potenciómetro
Nota importantísima: los datos anteriores, en especial el del límite de 2A es para los A4988 en los módulos Pololu (algo más caros). Hay una variante muy común que son los StepStick (más baratos, y seguramente es este el que tienes si lo has comprado de China). y la principal diferencia es que su límite es de 1A. Así que mucho ojito.
Stepstick driver A4988
El motor que voy a usar es un motor NEMA 17 GZGW09, comprado aquí por 13.50 €, pero valdría cualquier motor bipolar de 4 cables.
Driven X-axis and Y-axis movement, sprinkler wire wheel to scroll
Great for DIY project
Dimensions: 5.8 cm x 4.2 cm x 4.2 cm
Weight: 220 g
Para alimentar el motor empleo una fuente de alimentación de un ordenador (ver esta entrada).
Siguiendo las instrucciones de Pololu, voy a emplear el siguiente esquema de conexión, con paso completo (sin microstepping):
Empleo un Arduino Nano, pero valdría cualquier otro. Uso el pin 8 para la dirección y el 9 para el step. El esquema Fritzing sería así:
La conexión de los cables del motor al StepStick A4988 la hago así:
1A: rojo (morado)
1B: gris (gris)
2A: amarillo (blanco)
2B: verde (negro)
Para no dañar el motor tenemos que regular inicialmente el potenciómetro a la mínima potencia, girando el potenciómetro en sentido antihorario hasta el final, y más adelante ajustarlo hasta la capacidad del motor. En este vídeo se explica cómo regular adecuadamente la intensidad.
Lo primero es determinar el chip que realmente tenemos, pues cambia mucho si es un Pololu o un StepStick.
En la hoja de especificaciones se dice:
El Pololu tiene un valor de para la resistencia de censado SMD de 0.05 Ω (si se fabricó a partir de enero de 2017, entonces 0.068 Ω), mientras que en el StepStick es de 0.2 Ω. Lo mejor es mirarlo en la propia placa.
Así pues, en mi caso, tengo un StepStick (Rs= 0.2 Ω), y la intensidad máxima para mi motor de 0.84 A.
Pero ojo, el valor de la intensidad que hemos empleado antes es la máxima. En función de qué configuración de microstepping vayamos a usar, se podrá emplear otro valor.
Así, si empleamos pasos completos sin micro pasos, vemos que la tensión va variando en cada micropaso (también se puede consultar una tabla en las especificaciones):
Si emplease pasos completos y no micro pasos, entonces la tensión máxima que se entrega al motor es de un 70.71%.
Y entonces, si voy a emplear pasos completos tendré que ajustar el voltaje a:
Para medir este voltaje, lo hacemos con el multímetro sobre el potenciómetro y sobre tierra, y ajustamos el potenciómetro hasta la VREF calculada antes (0.95 V).
Ya tengo el driver ajustado a mi motor para pasos completos, así que ya puedo conectarlo y empezar a utilizarlo.
Cargando el siguiente código a Arduino, el motor da una vuelta completa en una dirección, y luego cambia de dirección y da otra vuelta:
const int dirPin = 8;
const int stepPin = 9;
const int steps = 200;
int microPausa = 1000;
void setup() {
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
}
void loop() {
digitalWrite(dirPin, HIGH); // Establezco una dirección
for (int x = 0; x < steps ; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(microPausa);
digitalWrite(stepPin, LOW);
delayMicroseconds(microPausa);
}
delay(1000);
digitalWrite(dirPin, LOW); // Cambio la dirección
for (int x = 0; x < steps ; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(microPausa);
digitalWrite(stepPin, LOW);
delayMicroseconds(microPausa);
}
delay(1000);
}
Y un vídeo mostrando el motor en movimiento con el código anterior:
Voy a contar cómo manejar un motor paso a paso (stepper) con Arduino a través de un controlador DRV8825. En esta otra entrada explico cómo hacerlo con una Raspberry Pi, de forma muy similar, y en esta hablo de varios motores y drivers.
Características principales del driver DRV8825:
Para motores bipolares
Permite microstepping de hasta 1/32
1.5 por fase o 2.2A si se dispone de ventilación forzada de aire o disipadores
Interfaz casi idéntica al A4988
45 V máximo
Control de corriente máxima con un potenciómetro
El motor que voy a usar es un motor NEMA 17 JK42HS40-1704 13A, comprado aquí por 12.50 €, pero valdría cualquier motor bipolar de 4 cables.
Características del motor:
Número de parte: JK42HS40-1704 13A
Tamaño de marco: NEMA17
Ángulo del paso: 1,8 grados
Voltaje: 3.4V
Corriente: 1,7 A/fase
Resistencia: 2,0 ohmios/fase
Inductancia: 3,0 mH/phase
Llevar a cabo el esfuerzo de torsión: 4000g-cm 58.30 OZ-IN
Inercia del rotor: 54 g-cm2
Esfuerzo de torsión de la muesca: 0,22 kilogramo-cm
Número de ventajas de alambre: 4
Peso: 0,24 kilogramos
Longitud: 40m m
Eje del motor: 5mm
Longitud del árbol delantero: 20 mm
Certificación: CE, ROHS, ISO9001
Para alimentar el motor empleo una fuente de alimentación de un ordenador (ver esta entrada).
Siguiendo las instrucciones de la página de Pololu, voy a emplear el siguiente modo de conexión, con paso completo (sin microstepping):
Empleo un Arduino Nano, pero valdría cualquier otro. Uso el pin 8 para la dirección y el 9 para el step. El esquema Fritzing de mi montaje es así:
Manejar un motor paso a paso con DRV8825 y Arduino
La conexión de los cables del motor al DRV8825 la hago así:
B2: azul
B1: rojo
A1: negro
A2: verde
Para no dañar el motor tenemos que regular inicialmente el potenciómetro a la mínima potencia, girando el potenciómetro en sentido antihorario hasta el final, y más adelante ajustarlo hasta la capacidad del motor. En este vídeo se explica cómo regular adecuadamente la intensidad, que cuento a continuación.
Empiezo con el motor desconectado. Lo primero, calculo el voltaje por cada fase. Para eso me fijo en las características de mi motor. Ahí me dicen que el motor es de 1.7 A / fase. Tendré que limitar el DRV8825 a este valor. Por encima de 1.5 A (y hasta 2.2A) el controlador DRV8825 debe tener ventilación forzada de aire o un disipador, así que le pego un disipador (me venía al comprarlo con el DRV8825), pues pretendo fijarlo en la capacidad máxima del motor.
Ahora tengo que ajustar la corriente del DRV8825 con el potenciómetro. Primero tengo que averiguar a cuánto he de limitar esa corriente. Para ello empleo la fórmula que viene en la hoja de especificaciones del driver:
Current Limit = VREF × 2
(Ojo, que por muchas páginas se ven otras fórmulas; hay que emplear la fórmula específica de nuestro driver).
Entonces:
1.7 = VREF x 2
VREF = 0.85 V
Pero ojo, este voltaje va asociado a la corriente máxima que recibirá el motor, y depende de la configuración de micropasos. Hay que consultar en la Tabla 2 de la hoja de especificaciones del DRV8825. En mi caso, con paso completo (full step), la corriente es un 71%, así que deberé multiplicar por este factor el resultado anterior:
VREF = 0.71 · 0.85 = 0.60 V
Así que el voltaje límite que debo ajustar es 0.60 V por fase.
Ahora tengo que ver dónde medir con el multímetro en el DRV8825:
Aunque es más fácil medir directamente desde el potenciómetro:
Desconecto el motor, pero alimento con 12V el DRV8825 y alimento también el Arduino a través del puerto USB. Con todo así, mido el voltaje y ajusto el potenciómetro hasta alcanzar mis VREF calculado antes (0.60 V).
Ya tengo el driver ajustado a mi motor, así que ya puedo conectarlo y empezar a utilizarlo.
Cargando el siguiente código a Arduino, el motor da una vuelta completa en una dirección, y luego cambia de dirección y da otra vuelta:
const int dirPin = 8;
const int stepPin = 9;
const int steps = 200;
int microPausa = 1000;
void setup() {
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
}
void loop() {
digitalWrite(dirPin, HIGH); // Establezco una dirección
for (int x = 0; x < steps ; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(microPausa);
digitalWrite(stepPin, LOW);
delayMicroseconds(microPausa);
}
delay(1000);
digitalWrite(dirPin, LOW); // Cambio la dirección
for (int x = 0; x < steps ; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(microPausa);
digitalWrite(stepPin, LOW);
delayMicroseconds(microPausa);
}
delay(1000);
}
Y un vídeo mostrando el motor en movimiento con el código anterior:
Hace tiempo me encontré por internet una página en la que se explicaba cómo construirse un arpa láser casera. La idea es sencilla: se tiene un láser que encendemos y apagamos a muy alta velocidad contra un espejo montado sobre un motor a pasos que va cambiando de posición de forma sincronizada con el láser, de tal manera que por persistencia de la visión da lugar a una serie de haces de luz muy espectaculares, si el láser tiene la potencia adecuada y/o la luz ambiente es apropiada. Si disponemos una célula fotoeléctrica que detecte cuándo uno de los haces de láser ha sido interrumpido y vemos en qué posición está el láser en ese momento, podemos asociar a cada posición del láser una nota musical, que se envía por MIDI a un teclado o al ordenador, o podemos también hacer sonar con un pequeño altavoz.
Arpa láser en su configuración final
Como además estaba preparando un concierto para unos meses más tarde en el que podría quedar muy bien hacer una parte con el arpa láser, decidí construirme una.
En esta página describo todo el proceso de montaje de un arpa láser plenamente funcional, tratando de explicar las pruebas que hice y todos los pasos que seguí, así como las referencias que consulté siempre que he podido. Ojo, que muchas de las páginas de internet sobre arpas láser no son del todo funcionales, o se quedan a la mitad y no lo llevan hasta el final, o directamente cuentan cosas que no son del todo creíbles.
Para llegar al arpa que empleé en el concierto, construí varios prototipos parciales y uno completo antes del arpa definitiva. Las fotos que pongo en la página pueden corresponder a alguno de los prototipos o a la definitiva en proceso de montaje.
Aviso al navegante: si tienes intención de hacer algo parecido a las arpas láser de Jean Michel Jarre ya puedes ir preparándote para un gran desembolso económico y para dedicarle mucho tiempo…
Y el aviso más importante, y no es broma: trabajar con láseres, especialmente de alta potencia como el que empleo en este arpa, supone un riesgo muy alto y existe la posibilidad de quedarse ciego si se mira accidentalmente al láser (o un reflejo de éste en alguna superficie reflectante) ya que puedes quemarte la retina en un tiempo menor del tiempo de reacción de cerrar el ojo o apartar la mirada. Así que hay que emplear en todo momento gafas protectoras, adecuadas al láser que empleemos, evitar que haya más gente donde estemos trabajando y ser muy cuidadoso…
Material y lista de la compra
Arduino Nano: 2.59 €. También valdría un Arduino UNO, pero es más grande y algo más caro: 5.99 € (pirata).
Motor paso a pasop (stepper) He probado muchos motores con diferentes resultados. Si se tiene suerte, puede valer uno de una impresora vieja. El que empleé finalmente fue este (19.69 €)
Altavoz piezoeléctrico: de cualquier juguete o altavoz malo
Transistor NPN 2N222 (10 unidades por 1.62 €: 0.16 €) Solo necesario si el láser no viene con su propio driver.
1 LED
Módulo lector de tarjeta SD (1.99 €) y una tarjeta SD. Solo necesario si queremos que al arrancar el arpa láser se reproduzca un archovo wav con el sonido de un sable láser encendiéndose.
TOTAL: Configuración mínima: unos 150€, que podría llegar a ser unos 80 € si usamos un láser malucho (no se verían los haces salvo en una habitación con humo). También depende de los elementos que ya tengamos reciclados de otros inventos.
El láser
Probé con varios láseres, desde los baratos tipo puntero hasta uno «bueno» de 300 mW. Ojo con estos láseres que generalmente vienen de China. Venden diferentes modelos de diferentes potencias, pero luego descubres que te llega exactamente el mismo y que lo único es juegas con el potenciómetro. Así que en caso de utilizar estos láseres, es mejor comprar el de menor potencia y luego ajustar el potenciómetro. Yo alguna vez he jugado con este de 50 mW (11€), y este de 5 mW (5€), y me llegaron exactamente iguales.
El que finalmente utilicé fue este de 300 mW, por unos 80 €. Un láser bueno «de discoteca» puede costar varios cientos de euros o incluso miles. Lo importante es que sea TTL y que tenga cuanta más potencia os podáis permitir, pues entonces podrá verse el haz de láser mejor, o con mayor luz ambiente. Los más típicos (y baratos) son los láseres verdes de 532 nm de longitud de onda.
No penséis en ningún momento que puede verse el haz del láser a plena luz del día o, o en una sala muy iluminada. Es necesario que esté en un entorno oscuro, y lo ideal es emplear humo para que se vea mejor…
Advertencia. Jugar con láseres es muy peligroso, y no es una advertencia banal. En menos tiempo de lo que el ojo puede reaccionar un láser dirigido al ojo, o reflejado en una superficie brillante puede dañar permanentemente tu visión. Para toda la vida. Por ello, es necesario llevar siempre unas gafas protectoras adecuadas al láser específico que estemos manejando. En mi caso empleo láseres de 532 nm, pero ojo, algunos láseres chinos de mala calidad emiten a la vez a 1064 nm, por lo que opté por protegerme para ambas frecuencias y compré estas gafas por unos 35 €.
Estas son las características que da el fabricante del láser:
Output Wavelength:532nm
Output Power:300mW with 5%
operating Voltage:DC12V
Lifepan:>5000 hours
Laser Shape: DOT
Focusable:Yes (By Tool)
Working Temperature:+10dgC-+40dgC
Working Temperature:+10dgC-+50dgC
Focus lens:Glass
Cooling mode:Heatsink and Fan
TTL signal:0~30K
El motor
Aquí está el quid de la cuestión. El láser es importante, sí, pero sólo depende de cuánto me quiera gastar en comprar un láser de mayor potencia, así que hay pocas incógnitas. En cambio con el motor es bastante más delicado. Debe ser muy rápido, y además permitir un control preciso del ángulo de giro para que se dé el efecto de persistencia de la visión y que al reflejar el láser de forma sincronizada con los giros sobre un espejo en el eje del motor dé la sensación de tener varios haces de luz.
Hice muchísimas pruebas con diversos motores y drivers (ver esta entrada). Lo primero, que se pregunta mucho en otras páginas, es dejar claro que el típico stepper de todos los kits de iniciación a la electrónica, el 28BYJ-48 no vale para un arpa láser, es muy lento. Hablo sobre este motor aquí.
En varias páginas se dice que con un motor sacado de una vieja impresora funciona. Yo probé con un MITSUMI M35SP-9, sacado de una vieja impresora Deskjet HP. Puede valer, aunque obtuve mejores resultados con otros motores.
Lo ideal sería emplear un galvanómetro (lo que se emplea en láseres de discoteca) que son capaces de girar a más de 20.000 revoluciones por minuto, pero son extremadamente caros, así que lo descarté desde el principio.
El motor que finalmente empleé fue este de Adafruit, aunque estuve a punto de utilizar uno que rescaté de una vieja impresora.
También es muy importante qué driver (controlador) del motor empleamos. En mi caso empleé el A3967 EasyDriver. Aquí se explica de forma muy sencilla su manejo.
En esta entrada explico cómo hacer funcionar el motor con este driver.
MIDI
El protocolo MIDI es bastante sencillo. En esencia, Arduino no genera música, sino que envía comandos por este protocolo para que otra máquina genere la música con el instrumento que queramos. En mi caso, como ya tenía un teclado MIDI (Casio CT-655), solo he tenido que comprar el enchufe MIDI y un cable. También se puede hacer sin un teclado/sintetizador, conectando el cable MIDI al ordenador por un adaptador USB, y configurar el ordenador para que se encargue de generar el sonido que queramos (ver más abajo).
Lo primero es hacer una pequeña prueba para ver que hemos conectado bien todo y que nuestro teclado/sintetizador/ordenador es generar de interpretar lo que Arduino le manda por MIDI y produce sonidos. Podemos seguir el tutorial sencillo que viene en el SDK y la página web de Arduino.
En la siguiente página se explica en profundidad el protocolo MIDI y la estructura de comandos. Voy a conectar el arpa láser a un teclado CASIO CT-655, y me interesa, además de las notas en concreto, poder decirle al teclado que cambie a un instrumento determinado.
Por cierto, cada vez que actualicemos el código de Arduino y lo subamos a la placa, debemos desconectar el cable MIDI, pues si no el teclado puede recibir instrucciones erróneas y el resultado que obtendremos sonará muy raro…
Audio
Como es un poco trabajoso tener que conectar el arpa láser a un teclado MIDI o a un ordenador para producir algún sonido, he probado a que además de enviar el sonido por MIDI produzca sonido digital directamente, a través de un pequeño altavoz piezo, y un jack de 2.5mm al que se puede conectar unos auriculares.
[Explicar más]
Secuencia de audio al inicio
Se me ocurrió que podía añadir un sonido de encendido de espada láser de Star Wars, así que le añadí un módulo lector de tarjeta SD, busqué por internet y descargué un audio con el sonido de espada láser, lo convertí a wav con el Audacity y pasándolo a mono, 16.000 Hz, 32 bits y grabado como «Unsigned 8-bit PCM». Aquí está el audio final:
Diagrama fritzing
Código
El código de Arduino empleado en este proyecto es el siguiente:
#include // Cargo la librería de motores a pasos
#include // Cargo la librería SD, para reproducir audio al comienzo por altavoz
#define SDPin 10 // Conecto el CS al pin 10, para reproducir audio al comienzo por altavoz
#include // Cargo la librería TMRpcm, para reproducir audio al comienzo por altavoz
#include // Cargo la librería SPI, para reproducir audio al comienzo por altavoz
TMRpcm audio; // Creo el objeto audio
int pinStep = 7; // Pin de Step del EasyDriver
int pinDirec = 8; // Pin de Direction del EasyDriver
int micropausa = 600; // microsegundos de pausa entre (micro)paso y (micro)paso (velocidad del motor)
int micropausaInicio = 15000; //microsegundos de pausa entre (micro)paso y (micro)paso en la secuencia de inicio
int posVert = 465; // Número de (micro)pasos que deja el espejo para que el láser esté en su sitio al comienzo
int sensor = 155; // Umbral de sensibilidad del fotorresitor. Cuanto más bajo, más sensible a la luz. En cuarto oscuro funciona bien con 160
int micropausaLaser = 2000; // Tiempo que se queda encendido el láser (microsengudos). En mi caso, va bien con 2000
int micropausaSensor = 2000; // Pausa tras apagar láser y antes de girar, para dar tiempo al sensor a reaccionar (microsengudos). En mi caso, va bien con 2000
int haces = 6; // Número de notas / haces de láser
int pasosHaces = 12; // Número de (micro)pasos entre haz y haz
int pinLaser = 4; // Pin donde tengo conectado el láser
int pinLed = 6; // Pin donde tengo conectado el LED de estado
int pinAudio = 9; // Pin donde está conectado el altavoz piezo. Debe ser el Pin 9 en Arduino Uno y Nano, y 11 en el Mega
int pinBoton = 3; // Pin donde está conectado el interruptor de fin de carrera del motor
int valBot = 0; //Estado del botón del motor
int noteStatus[] = {0,0,0,0,0,0}; // Inicializo el estado de las notas (sonando/no sonando). Debe haber el mismo número que número de haces
int notasMIDI[] = {58,62,65,70,72,74}; // Nota asignada a cada haz. Debe haber el mismo número que número de haces
void setup() {
pinMode(pinLaser, OUTPUT); // Declaro el pin del laser
digitalWrite(pinLaser, LOW); // Apago el laser
pinMode(pinLed, OUTPUT); // Declaro el pin del Led de status
digitalWrite(pinLed, LOW); // Dejo el Led de estatus apagado
// Para que suene el sable láser al arrancar
audio.speakerPin = pinAudio; // Debe ser el Pin 9 en Arduino Uno y Nano, y 11 en el Mega
Serial.begin(9600); // Para reproducir el audio al comienzo
pinMode(SDPin, OUTPUT);
ajusteMotor(); // Llamo a la función ajusteMotor() para colocar el espejo en su sitio y arrancar la secuencia de incio
//Arranco MIDI:
Serial.begin(31250); // Especifico el canal de comunicación para MIDI
Serial.write(192); // Byte para cambiar de instrumento en canal 0
Serial.write(15); // Número de instrumento
delay(100);
}
// Pongo el motor/espejo en su sitio al comienzo y secuencia de inicio:
void ajusteMotor()
{
int numpasosini; //número de pasos en la secuencia de inicio (se calcula automáticamente)
int contini=0; // contador secuencia de inicio (se calcula automáticamente)
pinMode(pinBoton, INPUT); // Declaro el pin del boton como input
pinMode(pinDirec, OUTPUT);
pinMode(pinStep, OUTPUT);
digitalWrite(pinDirec, LOW);
digitalWrite(pinStep, LOW);
for (int pos = 0; pos < 4000; pos++)
{
valBot = digitalRead(pinBoton);
if (valBot == LOW)
{ // si el botón está pulsado:
//digitalWrite(pinLed, HIGH); // Enciendo el led
digitalWrite(pinDirec, HIGH); // Cambio la dirección
for (int pos2 = 0; pos2<posVert; pos2++) { digitalWrite(pinStep, LOW); digitalWrite(pinStep, HIGH); delayMicroseconds(micropausa); } digitalWrite(pinLaser, HIGH); // Enciendo el laser // Reproduzco el sonido de sable láser: if (SD.begin(SDPin)) { // Solo ejecuto si la tarjeta está accesible audio.volume(6); // Fijo el volumen (min=0, max=7) audio.play("laser.wav"); } // Secuencia abanico desplegado totalmente, acelerando linealmente: numpasosini=(haces-1)*pasosHaces*17/2; // Calculo el número de pasos en la secuencia de inicio // Compruebo la célcula fotoeléctrica, y mando arrancar la secuencia de inicio cuando se active: while(true) { if ( (analogRead(0) > sensor*2 ) ) // Si el sensor recibe señal
{
digitalWrite(pinLed, HIGH); // Enciendo el led
digitalWrite(pinDirec, LOW); // Cambio la dirección
for (int pos2 = 0; pos2<((haces-1)*pasosHaces/2); pos2++)
{
digitalWrite(pinStep, LOW);
digitalWrite(pinStep, HIGH);
digitalWrite(pinLaser, HIGH); // Enciendo el laser
delayMicroseconds(micropausaInicio-(micropausaInicio-micropausa)/numpasosini*contini++);
digitalWrite(pinLaser, LOW); // Apago el laser
}
for (int pos3 = 0; pos3<4; pos3++)
{
digitalWrite(pinDirec, HIGH); // Cambio la dirección
for (int pos2 = 0; pos2<((haces-1)*pasosHaces); pos2++)
{
digitalWrite(pinStep, LOW);
digitalWrite(pinStep, HIGH);
digitalWrite(pinLaser, HIGH); // Enciendo el laser
delayMicroseconds(micropausaInicio-(micropausaInicio-micropausa)/numpasosini*contini++);
digitalWrite(pinLaser, LOW); // Apago el laser
}
digitalWrite(pinDirec, LOW); // Cambio la dirección
for (int pos2 = 0; pos2<((haces-1)*pasosHaces); pos2++)
{
digitalWrite(pinStep, LOW);
digitalWrite(pinStep, HIGH);
digitalWrite(pinLaser, HIGH); // Enciendo el laser
delayMicroseconds(micropausaInicio-(micropausaInicio-micropausa)/numpasosini*contini++);
digitalWrite(pinLaser, LOW); // Apago el laser
}
}
break;
}
}
// // Si quiero ahorrarme la secuencia de inicio, habría que comentar la sección anterior.
// // Dejo el espejo en la posición del primer haz:
// digitalWrite(pinDirec, LOW); // Cambio la dirección
// for (int pos2 = 0; pos2<((haces-1)*pasosHaces/2); pos2++)
// {
// digitalWrite(pinStep, LOW);
// digitalWrite(pinStep, HIGH);
// delayMicroseconds(micropausa);
// }
break;
}
else
{ // el botón no está pulsado:
digitalWrite(pinLed, LOW); // Mantengo el led apagado
digitalWrite(pinStep, LOW);
digitalWrite(pinStep, HIGH);
delayMicroseconds(micropausa);
}
}
}
void loop()
{
for (int pos = 1; pos < haces; pos++) { // En una dirección digitalWrite(pinDirec, HIGH); // Establezco la dirección del motor digitalWrite(pinLaser, HIGH); // Enciendo el láser delayMicroseconds(micropausaLaser); // Dejo el láser encendido el tiempo micropausaLaser // Compruebo la célcula fotoeléctrica, y mando tocar/parar de tocar la nota correspondiente: if ( (analogRead(0) > sensor ) && ( noteStatus[pos] == 0 )) // Si el sensor recibe señal, y la nota no está sonando
{
noteMIDI(0x90, notasMIDI[pos-1], 0x45); // Que se toque la nota por MIDI
//tone(pinAudio,notas[pos-1]); // Que se toque la nota por el piezo/auriculares
digitalWrite(pinLed, HIGH); // Enciendo el Led de estado
noteStatus[pos]++; // Cambio el estado de esa nota a "sonando"
}
else if (analogRead(0) < sensor ) // Si el sensor no recibe señal { if (noteStatus[pos] >= 1) // Si hay una nota tocando (porque aún no la he apagado, aunque no haya señal)
{
//if (noteStatus[pos]++ == 2) //Solo para de sonar si ya han pasado tres ciclos sin recibir señal...
//{
noteMIDI(0x90, notasMIDI[pos-1], 0x00); // Parar de tocar la nota por MIDI
//noTone(pinAudio); // Parar de tocar la nota por el piezo/auriculares
digitalWrite(pinLed, LOW); // Apago el led de estado
noteStatus[pos]=0; // Cambio el estado de esa nota a "apagada"
//}
}
}
digitalWrite(pinLaser, LOW); // Apago el láser
delayMicroseconds(micropausaSensor); // Antes de pasar al siguiente haz, pequeña pausa para reacción del sensor fotoeléctrico
//Muevo el motor al siguiente haz:
for (int pos2 = 0; pos2<pasosHaces; pos2++) // Avanzo un haz (el número de (micro)pasos definidos en la variable pasosHaces { digitalWrite(pinStep, LOW); digitalWrite(pinStep, HIGH); delayMicroseconds(micropausa); } } for (int pos = haces; pos > 1; pos--)
{ // En la otra dirección
digitalWrite(pinDirec, LOW); // Pongo el motor en el sentido contrario
digitalWrite(pinLaser, HIGH); // Enciendo el láser
delayMicroseconds(micropausaLaser); // Dejo el láser encendido el tiempo micropausaLaser
// Compruebo la célcula fotoeléctrica, y mando tocar/parar de tocar la nota correspondiente:
if ( (analogRead(0) > sensor ) && ( noteStatus[pos] == 0 )) // Si el sensor recibe señal, y la nota no está sonando
{
noteMIDI(0x90, notasMIDI[pos-1], 0x45); // Que se toque la nota
//tone(pinAudio,notas[pos-1]); // Que se toque la nota por el piezo/auriculares
digitalWrite(pinLed, HIGH); // Enciendo el Led de estado
noteStatus[pos]++; // Cambio el estado de esa nota a "sonando"
}
else if (analogRead(0) < sensor ) // Si el sensor no recibe señal { if (noteStatus[pos] >= 1) // Si hay una nota tocando (porque aún no la he apagado, aunque no haya señal)
{
//if (noteStatus[pos]++ == 2) //Solo para de sonar si ya han pasado dos ciclos sin recibir señal...
//{
noteMIDI(0x90, notasMIDI[pos-1], 0x00); // Parar de tocar la nota por MIDI
//noTone(pinAudio); // Parar de tocar la nota por el piezo/auriculares
digitalWrite(pinLed, LOW); // Apago el led de estado
noteStatus[pos]=0; // Cambio el estado de esa nota a "apagada"
//}
}
}
digitalWrite(pinLaser, LOW); // Apago el láser
delayMicroseconds(micropausaSensor); // Antes de pasar al siguiente haz, pequeña pausa para reacción del sensor fotoeléctrico
//Muevo el motor al siguiente haz:
for (int pos2 = 0; pos2<pasosHaces; pos2++) // Avanzo un haz (el número de (micro)pasos definidos en la variable pasosHaces
{
digitalWrite(pinStep, LOW);
digitalWrite(pinStep, HIGH);
delayMicroseconds(micropausa);
}
}
}
void noteMIDI(int cmd, int pitch, int velocity) {
Serial.write(cmd);
Serial.write(pitch);
Serial.write(velocity);
}
Para un proyecto que tengo entre manos, construir un arpa láser, quiero explorar el funcionamiento de los motores paso a paso (steppers) con Arduino. Tengo varios motores y también varios controladores, por lo que haré diversas pruebas con todos ellos.
Esta entrada es más bien una recopilación de datos, enlaces y apuntes míos, pocas explicaciones por el momento, me temo.
Busco conseguir la máxima velocidad del motor, sin requerir un gran par, simplemente para mover un espejo que está pegado a su eje y que he de poder girar a diversas posiciones muy rápido. Al apuntar un láser al espejo, y encenderlo y apagarlo de forma sincronizada con los cambios de posición del motor, quiero conseguir la ilusión de tener varios haces de laser, por persistencia de la visión.
Para hacer funcionar un stepper no basta con enchufarles una corriente continua y listo. Constan de una serie de bobinas que hay que ir accionando consecutivamente para conseguir el movimiento del motor, paso a paso. Además, accionando a la vez varias de las bobinas en secuencias determinadas podemos conseguir micropasos. Para realizar esto empleamos controladores (drivers) que se encargan de todo el proceso.
Motores
Tengo los siguientes motores:
28BYJ-48
Ya he escrito sobre el uso de este motorcito en esta entrada. Es el motor que viene en todos los kits de Arduino. Se suele controlar con el ULN2003. Compré uno junto con su controlador aquí, por poco más de 2€.
Llevar a cabo el esfuerzo de torsión: 4000g-cm 58.30 OZ-IN
Inercia del rotor: 54 g-cm2
Esfuerzo de torsión de la muesca: 0,22 kilogramo-cm
Número de ventajas de alambre: 4
Peso: 0,24 kilogramos
Longitud: 40m m
Eje del motor: 5mm
Longitud del árbol delantero: 20 mm
Certificación: CE, ROHS, ISO9001
MITSUMI M35SP-9
Lo saqué de una vieja impresora. Venía con etiqueta, así que puede investigar el modelo y características, ahorrándome mucho trabajo. Es un MITSUMI M35SP-9, y por lo visto es (era) muy típico en impresoras, escáneres, faxes, etc. Es un motor paso a paso (stepper) unipolar.
La ficha puede consultarse aquí, de donde he sacado las siguientes tablas y figuras:
Y aquí hay un vídeo italiano empleando el motor con Arduino UNO y un controlador ULN2003A:
Uno de los motores que voy a emplear con este driver tiene una corriente de 1.7 A por fase, por lo que le colocaré un disipador al driver.
Ajustar la corriente:
A3967 Easydriver
El que yo compré es la versión v4.4 (aunque hay una versión más reciente, la 4.5). Sirve para controlar motores bipolares, y permite micropasos hasta 1/16.
Se puede consultar las especificaciones técnicas del chip A3967 aquí, y del propio modulo EasyDriver aquí.
The EasyDriver is a simple to use stepper motor driver,
compatible with anything that can output a digital 0 to 5V pulse (or 0 to 3.3V pulse if you solder SJ2 closed on the EasyDriver)
EasyDriver requires a 7V to 30V supply to power the motor and can power any voltage of stepper motor.
The EasyDriver has an on board voltage regulator for the digital interface that can be set to 5V or 3.3V.
Connect a 4-wire stepper motor and a micro controller and got precision motor control!
EasyDriver drives bi-polar motors, and motors wired as bi-polar. I.e. 4,6, or 8 wire stepper motors.
MS1 and MS2 pins broken out to change micro stepping resolution to full, half, quarter and eighth steps (defaults to eighth)
Compatible with 4, 6, and 8 wire stepper motors of any voltage
Adjustable current control from 150mA/phase to 750mA/phase
Power supply range from 7V to 30V. The higher the voltage, the higher the torque at high speeds
Voy a utilizar un motor Adafruit de 200 pasos, 12V y 35mA por fase con un controlador EasyDriver y Arduino.
El motor lo compré aquí, por unos 20€. Sus especificaciones pueden consultarse aquí, y sus características principales son:
200 pasos por vuelta, 1.8º
Bobina nº 1: cables rojo y amarillo. Bobina nº 2: cables verde y gris.
Bipolar de 4 cables
Dimensión NEMA17 (42mm
42mm/1.65″ square body
12V
350mA máx
28 oz*in, 20 N*cm, 2 Kg*cm holding torque per phase
35 ohms per winding
El controlador EasyDriver lo compré aquí por menos de 5€. Sus características son:
Para ajustar la corriente del Pololu, podemos hacerlo a ojo, aumentando con un destornillador poco a poco, o mejor, midiendo la corriente y ajustándolo a las especificaciones del motor. El siguiente vídeo explica cómo hacerlo midiendo la corrieng:
Con este pequeño código en el Arduino, me funciona perfectamente: