Taula de continguts:

Rellotge LED de fusta: estil analògic: 11 passos (amb imatges)
Rellotge LED de fusta: estil analògic: 11 passos (amb imatges)

Vídeo: Rellotge LED de fusta: estil analògic: 11 passos (amb imatges)

Vídeo: Rellotge LED de fusta: estil analògic: 11 passos (amb imatges)
Vídeo: Штукатурка стен - самое полное видео! Переделка хрущевки от А до Я. #5 2024, Juliol
Anonim
Rellotge LED de fusta: estil analògic
Rellotge LED de fusta: estil analògic

És un rellotge LED de fusta d’estil analògic. No sé per què no n’he vist cap abans, tot i que els tipus digitals són molt habituals. Anyhoo, aquí estem!

Pas 1:

Imatge
Imatge
Imatge
Imatge

El projecte de rellotge contraxapat va començar com un senzill projecte d’arrencada per al router CNC. Vaig mirar projectes senzills en línia i vaig trobar aquest llum (imatge superior). També havia vist rellotges digitals que brillaven a través de xapes de fusta (imatge superior). Per tant, combinar els dos projectes era una idea òbvia. Amb l'objectiu de desafiar-me, vaig decidir no utilitzar xapes, sinó només un tros de fusta per a aquest projecte.

Pas 2: disseny

Disseny
Disseny
Disseny
Disseny

Vaig dissenyar el rellotge a Inkscape (imatge superior). El disseny és molt senzill. Vaig decidir no encaminar les traces dels cables perquè en aquest moment no estava segur de si volia anar amb cablejat radial o perimetral. (Vaig decidir anar amb cablejat perimetral finalment.) Un neopixel entra a cada un dels petits forats circulars per mostrar el temps i les hores, amb una precisió de cinc minuts. El cercle que hi ha al mig s’orientarà per acomodar l’electrònica.

Pas 3: CNC

CNCing
CNCing
CNCing
CNCing
CNCing
CNCing
CNCing
CNCing

Vaig dissenyar les rutes d’eines de MasterCAM i vaig utilitzar un technoRouter per treure el rellotge de fusta contraxapada de 3/4 polzades. Utilitzo una peça de 15 "x15" per a això, amb un malbaratament mínim. El truc és enrutar la major part de la fusta possible sense trencar-la. Deixar 0,05 "-0,1" és una bona opció per a la fusta clara. Si no esteu segur, és millor deixar-hi més fusta, perquè sempre podeu esborrar l’altra cara. Vaig acabar traient una mica massa de fusta d'algunes parts, però, per sort, els resultats no pateixen massa a causa d'això.

Nota per als usuaris sense accés a un CNC:

Aquest projecte es pot fer fàcilment amb una broca. Només heu d’establir l’aturada en un punt en què deixeu uns 0,1 de fusta a la base. Haureu de ser precisos, però no massa precisos. Al cap i a la fi, idealment ningú no veurà que tots els LED s’encenguin a al mateix temps, perquè pugueu sortir amb una mica de pendent.

Pas 4: electrònica

Electrònica
Electrònica
Electrònica
Electrònica
Electrònica
Electrònica

L’electrònica és bastant senzilla. Hi ha 24 neopíxels, dotze per mostrar les hores i dotze per mostrar els minuts, amb una precisió de cinc minuts. Un Arduino pro mini controla els neopíxels i obté temps precís mitjançant un mòdul de rellotge en temps real (RTC) DS3231. El mòdul RTC té una cèl·lula de monedes com a còpia de seguretat, de manera que no perd temps fins i tot quan l’alimentació està apagada.

Material:

Arduino pro mini (o qualsevol altre Arduino per això)

Tauler de sortida DS3231

Neopíxels en taules separades individuals

Pas 5: Muntatge d'electrònica

Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica
Muntatge d'electrònica

Vaig connectar els neopíxels en una cadena, utilitzant cables de 2,5 per als primers dotze leds i fil de quatre polzades per als dotze següents. Podria haver utilitzat longituds de filferro lleugerament menors. Després de fer la corda, la vaig provar, assegurant-me que la soldadura les articulacions eren bones. Vaig afegir un interruptor momentani per encendre tots els leds, només per mostrar-me.

Pas 6: Cursa en sec

Cursa en sec
Cursa en sec
Cursa en sec
Cursa en sec
Cursa en sec
Cursa en sec
Cursa en sec
Cursa en sec

Després d’experimentar, posar LEDs als forats i engegar-los tots, vaig quedar satisfet amb els resultats. Així que vaig lijar una mica la cara frontal i vaig aplicar una capa de PU. Més tard vaig acabar polint l’abric, però és una bona idea deixar-lo encès si no us sembla estèticament desagradable.

Pas 7: Epoxi

Epoxi
Epoxi
Epoxi
Epoxi

Després d'algunes proves amb la posició de led dins dels forats, vaig pensar que la millor discussió s'aconsegueix quan els LED es troben a uns 0,2 del final del forat. Quan ho proveu vosaltres mateixos, la brillantor dels LED serà molt diferent a cada forat. No us preocupeu; solucionarem el codi. Això és degut al tipus de broca que he utilitzat. Si tornés a fer-ho, faria servir una broca de punta de bola per als forats. Però, en qualsevol cas, per aconseguir la distància vaig barrejar una mica d'epoxi i vaig posar una mica a cada forat.

Pas 8: ajuntar-ho tot

Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt
Posant-ho tot junt

Els LED es col·locaran a partir de la posició de l’agulla de les 12 en punt movent-se en sentit antihorari a través de totes les posicions de l’agulla de les hores i després cap a l’agulla dels minuts, passant de nou des de la marca dels 60 minuts que es mouen en sentit antihorari. Això és així quan veiem des de la part frontal el patró de LED apareix en sentit horari.

Després de curar l’epoxi durant una hora, hi vaig posar una mica d’epoxi. Aquesta vegada, he col·locat els LED als forats, assegurant-me de cobrir els cables i les juntes de soldadura amb l’epoxi. Això permet una bona difusió de la llum i assegura els cables.

Pas 9: Codi

Codi
Codi

El codi es troba a GitHub, no dubteu a modificar-lo per al vostre ús. Quan enceneu tots els LEDs al mateix nivell, la brillantor de la llum que brilla serà molt diferent a cada forat. Això es deu al diferent gruix de la fusta als forats i a la diferència de tonalitat de la fusta. Com podeu veure, el color de la fusta varia bastant a la meva peça. Per solucionar aquesta diferència de brillantor, vaig crear una matriu de nivells de brillantor de led. I va disminuir la brillantor dels LED més brillants. És un procés de prova i error i pot trigar uns quants minuts, però els resultats valen la pena.

plywoodClock.ino

// Rellotge contraxapat
// Autor: tinkrmind
// Atribució 4.0 Internacional (CC BY 4.0). Ets lliure de:
// Compartir: copieu i redistribuïu el material en qualsevol mitjà o format
// Adaptar: remesclar, transformar i construir sobre el material per a qualsevol propòsit, fins i tot comercialment.
// Hurra!
#incloure
#include "RTClib.h"
RTC_DS3231 rtc;
#include "Adafruit_NeoPixel.h"
#ifdef _AVR_
#incloure
#endif
# definePIN6
Adafruit_NeoPixel strip = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int hourPixel = 0;
int minutePixel = 0;
unsignedlong lastRtcCheck;
String inputString = ""; // una cadena per contenir les dades entrants
string boolean Complet = fals; // si la cadena està completa
nivell int [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
mentre que (! sèrie); // per a Leonardo / Micro / Zero
#endif
// Això és per a Trinket 5V 16 MHz, podeu eliminar aquestes tres línies si no feu servir un Trinket
#if definit (_AVR_ATtiny85_)
if (F_CPU == 16000000) clock_prescale_set (clock_div_1);
#endif
// Codi especial de fi de bibelot
Serial.begin (9600);
strip.begin ();
strip.show (); // Inicialitza tots els píxels a "off"
if (! rtc.begin ()) {
Serial.println ("No s'ha pogut trobar l'RTC");
mentre que (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_))));
if (rtc.lostPower ()) {
Serial.println ("RTC ha perdut energia, permetem definir l'hora!");
// la línia següent estableix el RTC a la data i hora en què es va compilar aquest esbós
rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_))));
// Aquesta línia estableix el RTC amb una data i hora explícites, per exemple, per definir
// El 21 de gener de 2014 a les 3:00 trucaríeu a:
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
}
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
// lightUpEven ();
// mentre (1);
lastRtcCheck = 0;
}
voidloop () {
if (millis () - lastRtcCheck> 2000) {
Data i hora ara = rtc.now ();
Serial.print (now.hour (), DEC);
Serial.print (':');
Serial.print (now.minute (), DEC);
Serial.print (':');
Serial.print (now.second (), DEC);
Serial.println ();
showTime ();
lastRtcCheck = millis ();
}
if (! digitalRead (2)) {
lightUpEven ();
}
if (stringComplete) {
Serial.println (inputString);
if (inputString [0] == 'l') {
Serial.println ("Nivell");
lightUpEven ();
}
if (inputString [0] == 'c') {
Serial.println ("Temps de visualització");
showTime ();
strip.show ();
}
if (inputString [0] == '1') {
Serial.println ("Encendre tots els LED");
lightUp (strip. Color (255, 255, 255));
strip.show ();
}
if (inputString [0] == '0') {
Serial.println ("Tira de compensació");
clar ();
strip.show ();
}
// # 3, 255 establiria el número 3 del led al nivell 255, 255, 255
if (inputString [0] == '#') {
Temp de la cadena;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
temp = inputString.substring (inputString.indexOf (',') + 1);
int intensitat = temp.toInt ();
Serial.print ("Configuració");
Serial.print (pixNum);
Serial.print ("a nivell");
Serial.println (intensitat);
strip.setPixelColor (pixNum, strip. Color (intensitat, intensitat, intensitat));
strip.show ();
}
// # 3, 255, 0, 125 establiria el número 3 del led al nivell 255, 0, 125
if (inputString [0] == '$') {
Temp de la 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 bIntensitat = temp.toInt ();
Serial.print ("Configuració");
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 la cadena;
int hora, minut;
temp = inputString.substring (1);
hora = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
minut = temp.toInt ();
Serial.print ("Temps de visualització:");
Serial.print (hora);
Serial.print (":");
Serial.print (minut);
showTime (hora, minut);
retard (1000);
}
inputString = "";
stringComplete = false;
}
// demora (1000);
}
voidserialEvent () {
while (Serial.available ()) {
char inChar = (char) Serial.read ();
inputString + = inChar;
if (inChar == '\ n') {
stringComplete = true;
}
retard (1);
}
}
voidclear () {
per a (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (0, 0, 0));
}
}
voidshowTime () {
Data i hora ara = rtc.now ();
hourPixel = now.hour ()% 12;
minutePixel = (now.minute () / 5)% 12 + 12;
clar ();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivell [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel]));
// strip.setPixelColor (minutPíxel, tira. Color (nivell 40 + 40 * [minut Pixel], nivell 30 + 30 * [minut Pixel], nivell 20 + 20 * [minut Pixel]));
strip.setPixelColor (hourPixel, strip. Color (nivell [hourPixel], level [hourPixel], level [hourPixel]));
strip.setPixelColor (minutPíxel, tira. Color (nivell [minutPíxel], nivell [minutPíxel], nivell [minutPíxel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidshowTime (hora int, minut int) {
hourPixel = hora% 12;
minutePixel = (minut / 5)% 12 + 12;
clar ();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivell [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel]));
// strip.setPixelColor (minutPíxel, tira. Color (nivell 40 + 40 * [minut Pixel], nivell 30 + 30 * [minut Pixel], nivell 20 + 20 * [minut Pixel]));
strip.setPixelColor (hourPixel, strip. Color (nivell [hourPixel], level [hourPixel], level [hourPixel]));
strip.setPixelColor (minutPíxel, tira. Color (nivell [minutPíxel], nivell [minutPíxel], nivell [minutPíxel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidlightUp (color uint32_t) {
per a (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, color);
}
strip.show ();
}
voidlightUpEven () {
per a (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (nivell , nivell , nivell ));
}
strip.show ();
}

veure rawplywoodClock.ino allotjat amb ❤ per GitHub

Pas 10: Visió per ordinador: calibració

Visió per ordinador: calibració
Visió per ordinador: calibració
Visió per ordinador: calibració
Visió per ordinador: calibració

Vaig prendre una decisió conscient de no utilitzar xapes en aquest projecte. Si ho hagués tingut, el gruix de la fusta hauria estat el mateix davant de tots els LED. Però, com que tinc un gruix de fusta diferent davant de cada LED i perquè el color de la fusta també varia molt, la brillantor del LED és diferent per a cada LED. Per fer que tots els LED semblessin tenir la mateixa brillantor, vaig idear un enginyós truc.

Vaig escriure algun codi de processament (a GitHub) que pren una foto del rellotge i analitza la brillantor de cada LED al seu torn. A continuació, varia la potència de cada LED per intentar que tots tinguin la mateixa brillantor que el LED més feble. Ara sé que això és excessiu, però el processament d’imatges és molt divertit. I, espero desenvolupar el codi de calibratge com a biblioteca.

Podeu veure la brillantor del LED abans i després del calibratge a les fotos anteriors.

calibrateDispllay.pde

importprocessing.video. *;
importprocessing.serial. *;
MyPort en sèrie;
Captura de vídeo;
finalint numLed = 24;
int ledNum = 0;
// heu de tenir aquestes variables variables globals per utilitzar el 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 acceptableError = 3;
int fet;
int numPixelsInLed;
long ledIntensity;
int ledPower;
objectiu llargIntensitat = 99999999;
voidsetup () {
fet = newint [numLed];
numPixelsInLed = newint [numLed];
ledIntensity = newlong [numLed];
ledPower = newint [numLed];
for (int i = 0; i <numLed; i ++) {
ledPower = 255;
}
printArray (Serial.list ());
String portName = Serial.list () [31];
myPort = newSerial (this, portName, 9600);
mida (640, 480);
video = newCapture (això, amplada, alçada);
video.start ();
noStroke ();
llis();
retard (1000); // Espereu que s’obri el port sèrie
}
voiddraw () {
if (video.available ()) {
if (fet [ledNum] == 0) {
clearDisplay ();
retard (1000);
video.read ();
imatge (vídeo, 0, 0, amplada, alçada); // Dibuixa el vídeo de la càmera web a la pantalla
saveFrame ("dades / no_leds.jpg");
if (runNumber! = 0) {
if ((ledIntensity [ledNum] - targetIntensity) * 100 / targetIntensity> acceptableError) {
ledPower [ledNum] - = pow (0,75, runNumber) * 100 + 1;
}
if ((targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity> acceptableError) {
ledPower [ledNum] + = pow (0,75, runNumber) * 100 + 1;
}
if (abs (targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity <= ErrorError acceptable) {
fet [ledNum] = 1;
imprimir ("Led");
imprimir (ledNum);
imprimir ("fet");
}
if (ledPower [ledNum]> 255) {
ledPower [ledNum] = 255;
}
if (ledPower [ledNum] <0) {
ledPower [ledNum] = 0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
retard (1000);
video.read ();
imatge (vídeo, 0, 0, amplada, alçada); // Dibuixa el vídeo de la càmera web a la pantalla
retard (10);
while (myPort.available ()> 0) {
int inByte = myPort.read ();
// imprimir (char (inByte));
}
String imageName = "dades /";
imageName + = str (ledNum);
imageName + = "_ led.jpg";
saveFrame (imageName);
String originalImageName = "dades / org";
OriginalImageName + = str (ledNum);
originalImageName + = ". jpg";
if (runNumber == 0) {
saveFrame (originalImageName);
}
PImage noLedImg = loadImage ("dades / no_leds.jpg");
PImage ledImg = loadImage (imageName);
PImage originalImg = loadImage (originalImageName);
noLedImg.loadPixels ();
ledImg.loadPixels ();
originalImg.loadPixels ();
fons (0);
loadPixels ();
ledIntensity [ledNum] = 0;
numPixelsInLed [ledNum] = 0;
per a (int x = 0; x <ample; x ++) {
per a (int y = 0; y <altura; y ++) {
PxPGetPixelDark (x, y, noLedImg.pixels, amplada);
PxPGetPixelLed (x, y, ledImg.pixels, amplada);
PxPGetPixelOrg (x, y, OriginalImg.pixels, amplada);
if ((rOrg + gOrg / 2 + bOrg / 3) - (rDark + gDark / 2 + bDark / 3)> 75) {
ledIntensity [ledNum] = ledIntensity [ledNum] + (rLed + gLed / 2 + bLed / 3) - (rDark + gDark / 2 + bDark / 3);
rTemp = 255;
gTemp = 255;
bTemp = 255;
numPixelsInLed [ledNum] ++;
} més {
rTemp = 0;
gTemp = 0;
bTemp = 0;
}
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, píxels, amplada);
}
}
ledIntensity [ledNum] / = numPixelsInLed [ledNum];
if (targetIntensity> ledIntensity [ledNum] && runNumber == 0) {
targetIntensity = ledIntensity [ledNum];
}
updatePixels ();
}
imprimir (ledNum);
imprimir(', ');
print (ledPower [ledNum]);
imprimir(', ');
println (ledIntensity [ledNum]);
ledNum ++;
if (ledNum == numLed) {
int donezo = 0;
for (int i = 0; i <numLed; i ++) {
donezo + = fet ;
}
if (donezo == numLed) {
println ("FET");
for (int i = 0; i <numLed; i ++) {
imprimir (i);
print ("\ t");
println (ledPower );
}
print ("nivell int [");
imprimir (ledNum);
print ("] = {");
for (int i = 0; i <numLed-1; i ++) {
print (ledPower );
imprimir(', ');
}
print (ledPower [numLed -1]);
println ("};");
lightUpEven ();
mentre que (cert);
}
print ("Intensitat objectiu");
if (runNumber == 0) {
targetIntensity - = 1;
}
println (targetIntensity);
ledNum = 0;
runNumber ++;
}
}
}
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels
aOrg = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir cada component sol
rOrg = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau ()
gOrg = (thisPixel >> 8) & 0xFF;
bOrg = thisPixel & 0xFF;
}
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels
aDark = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir que cada component sigui sol
rDark = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau ()
gDark = (thisPixel >> 8) & 0xFF;
bDark = thisPixel & 0xFF;
}
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels
aLed = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir cada component sol
rLed = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau ()
gLed = (thisPixel >> 8) & 0xFF;
bLed = thisPixel & 0xFF;
}
voidPxPSetPixel (intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) {
a = (a << 24);
r = r << 16; // Embalem els 4 components en un int
g = g << 8; // per tant, hem de canviar-los al seu lloc
color argb = a | r | g | b; // operació "o" binària "les afegeix totes en un int
pixelArray [x + y * pixelsWidth] = argb; // finalment establim la int amb els colors en els píxels
}

visualitza rawcalibrateDispllay.pde allotjat amb ❤ per GitHub

Pas 11: Observacions de separació

Trampes a evitar:

* Amb la fusta, obtindreu el que pagueu. Per tant, obtingueu fusta de bona qualitat. La fusta contraxapada de bedoll és una bona opció; qualsevol fusta massissa clara també ho farà molt bé. Vaig abaratir la fusta i em sap greu la meva decisió.

* És millor perforar menys que més. Un parell de forats van quedar massa profunds per a la meva peça. I l’epoxi es mostra a la cara frontal. Es nota molt un cop ho observeu.

* Utilitzeu una broca d'extrem de bola en lloc d'un extrem recte. No he experimentat amb la punta final de la pilota, però estic segur que els resultats seran molt millors.

Estic coquetejant amb la idea de vendre’ls a Etsy o tindie. M'agradaria molt que poguéssiu comentar a continuació si creieu que té sentit:)

Recomanat: