Tabla de contenido:
- Paso 1:
- Paso 2: diseño
- Paso 3: CNC
- Paso 4: Electrónica
- Paso 5: Ensamblaje de la electrónica
- Paso 6: ejecución en seco
- Paso 7: epoxi
- Paso 8: Poniéndolo todo junto
- Paso 9: Código
- Paso 10: Visión por computadora - Calibración
- Paso 11: Comentarios de despedida
Video: Reloj LED de madera - Estilo analógico: 11 pasos (con imágenes)
2024 Autor: John Day | [email protected]. Última modificación: 2024-01-30 08:44
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:
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ñé 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
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
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
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
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
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
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
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
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:
Cómo hacer un reloj analógico y un reloj digital con una tira de LED usando Arduino: 3 pasos
Cómo hacer un reloj analógico y un reloj digital con una tira de LED usando Arduino: Hoy haremos un reloj analógico & Reloj digital con Led Strip y módulo MAX7219 Dot con Arduino, corregirá la hora con la zona horaria local. El reloj analógico puede usar una tira de LED más larga, por lo que se puede colgar en la pared para convertirse en una obra de arte
Haga un reloj Nixie con Arduino en una caja de madera MDF: 11 pasos (con imágenes)
Haga un reloj Nixie con Arduino en una caja de madera MDF: En esta instrucción, mostraré cómo hacer un reloj Nixie con Arduino por circuito, que es lo más simple posible. Todos ellos se colocan en caja de madera MDF. Una vez finalizado, el reloj se ve como un producto: atractivo y compacto con firmeza
Reloj de boda de madera con luz LED: 8 pasos (con imágenes)
Reloj de boda de madera con luz LED: comencé este proyecto para hacer un reloj de boda único y único para mi hermana y mi cuñado. Quería hacer algo que pudieran iluminar y mostrar algún aspecto del día de su boda durante mucho tiempo. Pasé por muchos diseños
Reloj LED de madera: 5 pasos (con imágenes)
Reloj LED de madera: el reloj LED de madera parece una aburrida caja de madera con la excepción de que el tiempo brilla en la parte delantera. En lugar de mirar un trozo de plástico gris, tienes una pieza de madera más bonita. Todavía conserva todas sus funciones, incluidas
C51 Reloj Electrónico de 4 Bits - Reloj de Madera: 15 Pasos (con Imágenes)
Reloj electrónico C51 de 4 bits - Reloj de madera: tuve algo de tiempo libre este fin de semana, así que seguí adelante y monté este reloj digital electrónico DIY de 4 bits de AU $ 2.40 que compré en AliExpress hace un tiempo