Tabla de contenido:

Reloj LED de madera - Estilo analógico: 11 pasos (con imágenes)
Reloj LED de madera - Estilo analógico: 11 pasos (con imágenes)

Video: Reloj LED de madera - Estilo analógico: 11 pasos (con imágenes)

Video: Reloj LED de madera - Estilo analógico: 11 pasos (con imágenes)
Video: Reloj LED digital de un botón | Configuración de hora y fecha (Cómo Poner) 2024, Noviembre
Anonim
Reloj LED de madera - estilo analógico
Reloj LED de madera - estilo analógico

Es un reloj LED de madera de estilo analógico. No sé por qué no he visto uno de estos antes … aunque los tipos digitales son muy comunes. De todos modos, ¡aquí vamos!

Paso 1:

Imagen
Imagen
Imagen
Imagen

El proyecto del reloj de madera contrachapada comenzó como un simple proyecto inicial para el enrutador CNC. Estaba buscando proyectos simples en línea y encontré esta lámpara (imagen de arriba). También había visto relojes digitales que brillan a través de la chapa de madera (imagen de arriba). Entonces, combinar los dos proyectos fue una idea obvia. Buscando desafiarme a mí mismo, decidí no usar chapa sino solo un trozo de madera para este proyecto.

Paso 2: diseño

Diseño
Diseño
Diseño
Diseño

Diseñé el reloj en Inkscape (imagen de arriba). El diseño es muy simple por elección. Decidí no enrutar los rastros para los cables porque en este punto no estaba seguro de si quería usar un cableado radial o perimetral. (Finalmente decidí ir con cableado perimetral). En cada uno de los pequeños orificios circulares se coloca un neopixel para mostrar el minuto y la hora, con una precisión de cinco minutos. El círculo en el medio se enrutará para acomodar la electrónica.

Paso 3: CNC

CNCing
CNCing
CNCing
CNCing
CNCing
CNCing
CNCing
CNCing

Diseñé las trayectorias de herramientas en MasterCAM y usé un technoRouter para fresar el reloj de madera contrachapada de 3/4 de pulgada. Utilizo una pieza de 15 "x 15" para esto, con un desperdicio mínimo. El truco consiste en enrutar la mayor cantidad de madera posible sin romper la madera. Dejar 0.05 "-0.1" es una buena opción para madera clara. Si no está seguro, es mejor dejar más madera porque siempre puede lijar la otra cara. Terminé quitando demasiada madera de algunas partes, pero afortunadamente los resultados no sufren demasiado por esto.

Nota para usuarios sin acceso a un CNC:

Este proyecto se puede realizar fácilmente con un taladro. Solo necesita establecer el tope en un punto donde deje alrededor de 0.1 de madera restante en la base. Tendrá que ser preciso, pero no demasiado preciso. Después de todo, lo ideal es que nadie vea todos los LED iluminados en al mismo tiempo, para que puedas salirte con la tuya un poco.

Paso 4: Electrónica

Electrónica
Electrónica
Electrónica
Electrónica
Electrónica
Electrónica

La electrónica es bastante simple. Hay 24 neopíxeles, doce para mostrar las horas y doce para mostrar los minutos, con una precisión de cinco minutos. Un Arduino pro mini controla los neopíxeles y obtiene la hora exacta a través de un módulo de reloj en tiempo real (RTC) DS3231. El módulo RTC tiene una celda de botón como respaldo, por lo que no pierde tiempo incluso cuando la energía está apagada.

Material:

Arduino pro mini (o cualquier otro Arduino para el caso)

Placa de conexión DS3231

Neopixels en tableros de ruptura individuales

Paso 5: Ensamblaje de la electrónica

Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica
Ensamblaje de electrónica

Conecté los neopíxeles en una cuerda, usando cables de 2.5 para los primeros doce leds y cable de cuatro pulgadas para los siguientes doce. Podría haber usado longitudes de cable un poco más pequeñas. Después de hacer la cuerda, la probé, asegurándome de que la soldadura Las articulaciones estaban bien, agregué un interruptor momentáneo para encender todos los leds, solo para lucirse.

Paso 6: ejecución en seco

Ejecución en seco
Ejecución en seco
Ejecución en seco
Ejecución en seco
Ejecución en seco
Ejecución en seco
Ejecución en seco
Ejecución en seco

Después de experimentar, poner LED en los agujeros y encenderlos todos, quedé satisfecho con los resultados. Así que lijé un poco la cara frontal y apliqué una capa de PU. Terminé lijando el abrigo más tarde, pero es una buena idea dejarlo puesto si no lo encuentra estéticamente desagradable.

Paso 7: epoxi

Epoxy
Epoxy
Epoxy
Epoxy

Después de algunas pruebas con la posición del LED dentro de los orificios, pensé que la mejor discusión se logra cuando los LED están a aproximadamente 0,2 de distancia del final del orificio. Cuando intente esto usted mismo, el brillo de los LED será muy diferente en cada agujero. No te preocupes por esto; lo arreglaremos en el código. Esto se debe al tipo de broca que utilicé. Si tuviera que hacer esto de nuevo, usaría una broca de punta esférica para los agujeros Pero, en cualquier caso, para conseguir la distancia mezclé un poco de epoxi y puse un poquito en cada agujero.

Paso 8: Poniéndolo todo junto

Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto
Poniendolo todo junto

Los LED se colocarán comenzando desde la posición de la manecilla de las 12 en punto moviéndose en sentido antihorario a través de todas las posiciones de la manecilla de las horas y luego a la manecilla de los minutos, moviéndose nuevamente desde la marca de 60 minutos moviéndose en sentido antihorario. Esto es para que cuando miramos de frente el patrón de LED aparece en sentido horario.

Después de que el epoxi se cure durante una hora, le agregué un poco más de epoxi. Esta vez, coloqué los LED en los orificios, asegurándome de cubrir los cables y soldar las juntas con epoxi. Esto permite una buena difusión de la luz y asegura los cables.

Paso 9: Código

Código
Código

El código está en GitHub, no dude en modificarlo para su uso. Cuando enciende todos los LED al mismo nivel, el brillo de la luz que atraviesa será muy diferente en cada orificio. Esto se debe al diferente grosor de la madera en los agujeros y a la diferencia en el tono de la madera. Como pueden ver, el color de la madera varía bastante en mi pieza. Para remediar esta diferencia de brillo, hice una matriz de niveles de brillo de led. Y disminuyó el brillo de los LED más brillantes. Es un proceso de prueba y error y puede llevar varios minutos, pero los resultados valen la pena.

plywoodClock.ino

// Reloj de madera contrachapada
// Autor: tinkrmind
// Atribución 4.0 Internacional (CC BY 4.0). Eres libre de:
// Compartir: copia y redistribuye el material en cualquier medio o formato.
// Adaptar: remezclar, transformar y construir sobre el material para cualquier propósito, incluso comercialmente.
// ¡Viva!
#incluir
#include "RTClib.h"
RTC_DS3231 rtc;
#include "Adafruit_NeoPixel.h"
#ifdef _AVR_
#incluir
#terminara si
# definePIN6
Tira de Adafruit_NeoPixel = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int hourPixel = 0;
int minutePixel = 0;
unsignedlong lastRtcCheck;
String inputString = ""; // una cadena para contener los datos entrantes
boolean stringComplete = falso; // si la cadena está completa
int nivel [24] = {31, 51, 37, 64, 50, 224, 64, 102, 95, 255, 49, 44, 65, 230, 80, 77, 102, 87, 149, 192, 67, 109, 68, 77};
voidsetup () {
#ifndef ESP8266
mientras (! Serial); // para Leonardo / Micro / Zero
#terminara si
// Esto es para Trinket 5V 16MHz, puede eliminar estas tres líneas si no está usando un Trinket
#si está definido (_AVR_ATtiny85_)
if (F_CPU == 16000000) clock_prescale_set (clock_div_1);
#terminara si
// Fin del código especial de la baratija
Serial.begin (9600);
strip.begin ();
strip.show (); // Inicializar todos los píxeles a 'desactivados'
if (! rtc.begin ()) {
Serial.println ("No se pudo encontrar RTC");
mientras (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)));
if (rtc.lostPower ()) {
Serial.println ("RTC perdió energía, ¡ajustemos la hora!");
// la siguiente línea establece el RTC en la fecha y hora en que se compiló este boceto
rtc.adjust (Fecha y hora (F (_ FECHA_), F (_ HORA_)));
// Esta línea establece el RTC con una fecha y hora explícitas, por ejemplo para establecer
// El 21 de enero de 2014 a las 3 a. M., Llamaría:
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
}
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
// lightUpEven ();
// mientras (1);
lastRtcCheck = 0;
}
voidloop () {
if (millis () - lastRtcCheck> 2000) {
DateTime ahora = rtc.now ();
Serial.print (ahora.hora (), DEC);
Serial.print (':');
Serial.print (ahora.minuto (), DEC);
Serial.print (':');
Serial.print (ahora.segundo (), DEC);
Serial.println ();
tiempo de la funcion();
lastRtcCheck = millis ();
}
if (! digitalRead (2)) {
lightUpEven ();
}
if (stringComplete) {
Serial.println (inputString);
if (inputString [0] == 'l') {
Serial.println ("Nivel");
lightUpEven ();
}
if (inputString [0] == 'c') {
Serial.println ("Mostrando hora");
tiempo de la funcion();
strip.show ();
}
if (inputString [0] == '1') {
Serial.println ("Encendido de todos los LED");
lightUp (tira. Color (255, 255, 255));
strip.show ();
}
if (inputString [0] == '0') {
Serial.println ("Tira de compensación");
claro();
strip.show ();
}
// # 3, 255 establecería el led número 3 en el nivel 255, 255, 255
if (inputString [0] == '#') {
Temp de cadena;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
temp = inputString.substring (inputString.indexOf (',') + 1);
int intensidad = temp.toInt ();
Serial.print ("Configuración");
Serial.print (pixNum);
Serial.print ("a nivel");
Serial.println (intensidad);
strip.setPixelColor (pixNum, strip. Color (intensidad, intensidad, intensidad));
strip.show ();
}
// # 3, 255, 0, 125 colocaría el led número 3 en el nivel 255, 0, 125
if (inputString [0] == '$') {
Temp de cadena;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
int rIntensity = temp.toInt ();
intgIndex = inputString.indexOf (',', rIndex + 1) + 1;
temp = inputString.substring (gIndex);
intgIntensity = temp.toInt ();
int bIndex = inputString.indexOf (',', gIndex + 1) + 1;
temp = inputString.substring (bIndex);
int bIntensity = temp.toInt ();
Serial.print ("Configuración");
Serial.print (pixNum);
Serial.print ("R a");
Serial.print (rIntensity);
Serial.print ("G a");
Serial.print (gIntensity);
Serial.print ("B a");
Serial.println (bIntensity);
strip.setPixelColor (pixNum, strip. Color (rIntensity, gIntensity, bIntensity));
strip.show ();
}
if (inputString [0] == 's') {
Temp de cadena;
int hora, minuto;
temp = inputString.substring (1);
hora = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
minuto = temp.toInt ();
Serial.print ("Mostrando hora:");
Serial.print (hora);
Serial.print (":");
Serial.print (minuto);
showTime (hora, minuto);
retraso (1000);
}
inputString = "";
stringComplete = falso;
}
// retraso (1000);
}
voidserialEvent () {
while (Serial.available ()) {
char inChar = (char) Serial.read ();
inputString + = inChar;
if (inChar == '\ n') {
stringComplete = verdadero;
}
retraso (1);
}
}
voidclear () {
para (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (0, 0, 0));
}
}
voidshowTime () {
DateTime ahora = rtc.now ();
hourPixel = ahora.hora ()% 12;
minutePixel = (ahora.minuto () / 5)% 12 + 12;
claro();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivel [hourPixel], 30 + 30 * nivel [hourPixel], 20 + 20 * nivel [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * nivel [minutoPixel], 30 + 30 * nivel [minutoPixel], 20 + 20 * nivel [minutoPixel]));
strip.setPixelColor (hourPixel, strip. Color (nivel [hourPixel], nivel [hourPixel], nivel [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (nivel [minutePixel], nivel [minutePixel], nivel [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidshowTime (int hora, int minuto) {
hourPixel = hora% 12;
minutePixel = (minuto / 5)% 12 + 12;
claro();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivel [hourPixel], 30 + 30 * nivel [hourPixel], 20 + 20 * nivel [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * nivel [minutoPixel], 30 + 30 * nivel [minutoPixel], 20 + 20 * nivel [minutoPixel]));
strip.setPixelColor (hourPixel, strip. Color (nivel [hourPixel], nivel [hourPixel], nivel [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (nivel [minutePixel], nivel [minutePixel], nivel [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidlightUp (uint32_t color) {
para (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, color);
}
strip.show ();
}
voidlightUpEven () {
para (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (nivel , nivel , nivel ));
}
strip.show ();
}

ver rawplywoodClock.ino alojado con ❤ por GitHub

Paso 10: Visión por computadora - Calibración

Visión por computadora - Calibración
Visión por computadora - Calibración
Visión por computadora - Calibración
Visión por computadora - Calibración

Tomé la decisión consciente de no usar chapa en este proyecto. Si lo hubiera hecho, el grosor de la madera habría sido el mismo frente a todos los LED. Pero, debido a que tengo un grosor de madera diferente frente a cada LED y debido a que el color de la madera también varía mucho, el brillo del LED es diferente para cada LED. Para hacer que todos los LED parezcan tener el mismo brillo, ideé un truco ingenioso.

Escribí un código de procesamiento (en GitHub) que toma una foto del reloj y analiza el brillo de cada LED a su vez. Luego, varía la potencia de cada LED para intentar que todos tengan el mismo brillo que el LED más tenue. Ahora, sé que esto es excesivo, ¡pero el procesamiento de imágenes es muy divertido! Y espero desarrollar el código de calibración como una biblioteca.

Puede ver el brillo del LED antes y después de la calibración en las fotos de arriba.

calibrateDispllay.pde

importprocessing.video. *;
importprocessing.serial. *;
Serial myPort;
Captura de video;
finalint numLed = 24;
int ledNum = 0;
// debe tener estas variables globales para usar PxPGetPixelDark ()
int rDark, gDark, bDark, aDark;
int rLed, gLed, bLed, aLed;
int rOrg, gOrg, bOrg, aOrg;
int rTemp, gTemp, bTemp, aTemp;
PImage ourImage;
int runNumber = 0;
int aceptableError = 3;
int hecho;
int numPixelsInLed;
long ledIntensity;
int ledPower;
targetIntensity largo = 99999999;
voidsetup () {
hecho = newint [numLed];
numPixelsInLed = newint [numLed];
ledIntensity = newlong [numLed];
ledPower = newint [numLed];
para (int i = 0; i <numLed; i ++) {
ledPower = 255;
}
printArray (Serial.list ());
String portName = Serial.list () [31];
myPort = newSerial (este, nombre de puerto, 9600);
tamaño (640, 480);
video = newCapture (esto, ancho, alto);
video.start ();
noStroke ();
liso();
retraso (1000); // Espere a que se abra el puerto serie
}
voiddraw () {
if (video.available ()) {
if (hecho [ledNum] == 0) {
clearDisplay ();
retraso (1000);
video.read ();
imagen (video, 0, 0, ancho, alto); // Dibuja el video de la webcam en la pantalla
saveFrame ("datos / no_leds.jpg");
if (runNumber! = 0) {
if ((ledIntensity [ledNum] - targetIntensity) * 100 / targetIntensity> aceptableError) {
ledPower [ledNum] - = pow (0,75, runNumber) * 100 + 1;
}
if ((targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity> aceptableError) {
ledPower [ledNum] + = pow (0,75, runNumber) * 100 + 1;
}
if (abs (targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity <= aceptableError) {
hecho [ledNum] = 1;
imprimir ("Led");
imprimir (ledNum);
imprimir ("hecho");
}
if (ledPower [ledNum]> 255) {
ledPower [ledNum] = 255;
}
if (ledPower [ledNum] <0) {
ledPower [ledNum] = 0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
retraso (1000);
video.read ();
imagen (video, 0, 0, ancho, alto); // Dibuja el video de la webcam en la pantalla
retraso (10);
while (myPort.available ()> 0) {
int inByte = myPort.read ();
// imprimir (char (inByte));
}
String imageName = "datos /";
imageName + = str (ledNum);
imageName + = "_ led.jpg";
saveFrame (imageName);
String originalImageName = "datos / org";
originalImageName + = str (ledNum);
originalImageName + = ". jpg";
if (runNumber == 0) {
saveFrame (originalImageName);
}
PImage noLedImg = loadImage ("datos / no_leds.jpg");
PImage ledImg = loadImage (nombre de la imagen);
PImage originalImg = loadImage (originalImageName);
noLedImg.loadPixels ();
ledImg.loadPixels ();
originalImg.loadPixels ();
fondo (0);
loadPixels ();
ledIntensity [ledNum] = 0;
numPixelsInLed [ledNum] = 0;
para (int x = 0; x <ancho; x ++) {
para (int y = 0; y <altura; y ++) {
PxPGetPixelDark (x, y, noLedImg.pixels, ancho);
PxPGetPixelLed (x, y, ledImg.pixels, ancho);
PxPGetPixelOrg (x, y, originalImg.pixels, ancho);
if ((rOrg + gOrg / 2 + bOrg / 3) - (rOscuro + gOscuro / 2 + bOscuro / 3)> 75) {
ledIntensity [ledNum] = ledIntensity [ledNum] + (rLed + gLed / 2 + bLed / 3) - (rDark + gDark / 2 + bDark / 3);
rTemp = 255;
gTemp = 255;
bTemp = 255;
numPixelsInLed [ledNum] ++;
} demás {
rTemp = 0;
gTemp = 0;
bTemp = 0;
}
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, píxeles, ancho);
}
}
ledIntensity [ledNum] / = numPixelsInLed [ledNum];
if (targetIntensity> ledIntensity [ledNum] && runNumber == 0) {
targetIntensity = ledIntensity [ledNum];
}
updatePixels ();
}
imprimir (ledNum);
impresión(', ');
imprimir (ledPower [ledNum]);
impresión(', ');
println (ledIntensity [ledNum]);
ledNum ++;
if (ledNum == numLed) {
int donezo = 0;
para (int i = 0; i <numLed; i ++) {
donezo + = hecho ;
}
if (donezo == numLed) {
println ("HECHO");
para (int i = 0; i <numLed; i ++) {
imprimir (i);
imprimir ("\ t");
println (ledPower );
}
print ("int nivel [");
imprimir (ledNum);
imprimir ("] = {");
para (int i = 0; i <numLed-1; i ++) {
imprimir (ledPower );
impresión(', ');
}
print (ledPower [numLed -1]);
println ("};");
lightUpEven ();
while (verdadero);
}
print ("Intensidad objetivo:");
if (runNumber == 0) {
targetIntensity - = 1;
}
println (targetIntensity);
ledNum = 0;
runNumber ++;
}
}
}
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obteniendo los colores como un int de los píxeles
aOrg = (estePixel >> 24) & 0xFF; // necesitamos cambiar y enmascarar para obtener cada componente solo
rOrg = (estePixel >> 16) & 0xFF; // esto es más rápido que llamar a red (), green (), blue ()
gOrg = (estePixel >> 8) & 0xFF;
bOrg = thisPixel & 0xFF;
}
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obteniendo los colores como un int de los píxeles
aDark = (estePixel >> 24) & 0xFF; // necesitamos cambiar y enmascarar para obtener cada componente solo
rDark = (estePixel >> 16) & 0xFF; // esto es más rápido que llamar a red (), green (), blue ()
gDark = (estePixel >> 8) & 0xFF;
bDark = thisPixel & 0xFF;
}
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obteniendo los colores como un int de los píxeles
aLed = (estePixel >> 24) & 0xFF; // necesitamos cambiar y enmascarar para obtener cada componente solo
rLed = (estePixel >> 16) & 0xFF; // esto es más rápido que llamar a red (), green (), blue ()
gLed = (estePixel >> 8) & 0xFF;
bLed = thisPixel & 0xFF;
}
voidPxPSetPixel (intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) {
a = (a << 24);
r = r << 16; // Estamos empaquetando los 4 componentes en un int
g = g << 8; // así que tenemos que trasladarlos a sus lugares
color argb = a | r | g | B; // operación binaria "o" los agrega todos en un int
pixelArray [x + y * pixelsWidth] = argb; // finalmente establecemos el int con te colores en los píxeles
}

ver rawcalibrateDispllay.pde alojado con ❤ por GitHub

Paso 11: Comentarios de despedida

Escollos a evitar:

* Con la madera, obtienes lo que pagas. Por lo tanto, obtenga madera de buena calidad. El contrachapado de abedul es una buena opción; cualquier madera maciza clara también funcionará bien. Bajé la madera y lamenté mi decisión.

* Es mejor perforar menos que más. Un par de agujeros fueron demasiado profundos para mi pieza. Y el epoxi se ve a través de la cara frontal. Es muy notorio una vez que lo notas.

* Utilice una broca de punta esférica en lugar de un extremo recto. No he experimentado con la broca de bola, pero estoy bastante seguro de que los resultados serán mucho mejores.

Estoy coqueteando con la idea de venderlos en Etsy o tindie. Realmente agradecería si pudiera comentar a continuación si cree que tiene sentido:)

Recomendado: