Indholdsfortegnelse:

LED -ur i træ - Analog stil: 11 trin (med billeder)
LED -ur i træ - Analog stil: 11 trin (med billeder)

Video: LED -ur i træ - Analog stil: 11 trin (med billeder)

Video: LED -ur i træ - Analog stil: 11 trin (med billeder)
Video: Den nye pige - En film om mobning 2024, Juli
Anonim
LED -ur i træ - Analog stil
LED -ur i træ - Analog stil

Det er en analog LED -ur i træ. Jeg ved ikke, hvorfor jeg ikke har set en af disse før..selvom de digitale typer er meget almindelige. Anyhoo, her går vi!

Trin 1:

Billede
Billede
Billede
Billede

Krydsfinerursprojektet startede som et simpelt startprojekt for CNC -routeren. Jeg kiggede på enkle projekter online og fandt denne lampe (billedet ovenfor). Jeg havde også set digitale ure, der skinner gennem træfiner (billede ovenfor). Så at kombinere de to projekter var en oplagt idé. For at udfordre mig selv besluttede jeg mig for ikke at bruge finer, men kun et stykke træ til dette projekt.

Trin 2: Design

Design
Design
Design
Design

Jeg designet uret i Inkscape (billede ovenfor). Designet er meget enkelt efter eget valg. Jeg besluttede mig for at føre spor efter ledningerne, fordi jeg på dette tidspunkt var usikker på, om jeg ville gå med radial eller perimeter ledninger. (Jeg besluttede mig for endelig at gå med perimeterledninger.) En neopixel går i hvert enkelt af de små cirkulære huller for at vise minut- og timetiden med fem minutters præcision. Cirklen i midten dirigeres ud for at rumme elektronikken.

Trin 3: CNC -bearbejdning

CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning
CNC -bearbejdning

Jeg designede værktøjsstierne på MasterCAM og brugte en technoRouter til at fræse uret fra 3/4 tommer krydsfiner. Jeg bruger et 15 "x15" stykke til dette, med minimalt spild. Tricket er at føre så meget ud af træet som muligt uden at bryde igennem træet. At forlade 0,05 "-0,1" er et godt valg til lyst træ. Hvis du er usikker, er det bedre at efterlade mere træ, for du kan altid slibe det andet ansigt. Jeg endte med at fjerne lidt for meget træ fra nogle dele, men heldigvis lider resultaterne ikke for meget på grund af dette.

Bemærk til brugere uden adgang til en CNC:

Dette projekt kan let udføres med en boremaskine. Du skal bare indstille stoppet på et punkt, hvor du efterlader omkring 0,1 træ tilbage på basen. Du skal være præcis, men ikke for præcis. Når alt kommer til alt, er det ideelt set, at ingen vil se alle lysdioderne lyse kl. på samme tid, så du kan slippe af sted med en lille slop.

Trin 4: Elektronik

Elektronik
Elektronik
Elektronik
Elektronik
Elektronik
Elektronik

Elektronikken er ret simpel. Der er 24 neopixel, tolv til visning af timer og tolv til visning af minutter, med fem minutters præcision. En Arduino pro mini styrer neopixelerne, og den får præcis tid gennem et DS3231 -realtidsur (RTC) -modul. RTC -modulet har en møntcelle som backup, så det taber ikke tid, selv når strømmen er slukket.

Materiale:

Arduino pro mini (eller enhver anden Arduino for den sags skyld)

DS3231 breakout board

Neopixels i individuelle breakout boards

Trin 5: Elektronikmontering

Elektronikmontering
Elektronikmontering
Elektronikmontering
Elektronikmontering
Elektronikmontering
Elektronikmontering
Elektronikmontering
Elektronikmontering

Jeg tilsluttede neopixel i en snor ved hjælp af 2,5 ledninger til de første tolv lysdioder og fire tommer ledning til de næste tolv. Jeg kunne have brugt lidt mindre ledningslængder. Efter at have lavet snoren, testede jeg den og sørgede for lodning leddene var gode. Jeg tilføjede en kortvarig kontakt for at tænde alle lysdioderne, bare for at vise mig.

Trin 6: Tørløb

Tørt løb
Tørt løb
Tørt løb
Tørt løb
Tørt løb
Tørt løb
Tørt løb
Tørt løb

Efter at have eksperimenteret, sat lysdioder i hullerne og tændt dem alle, var jeg tilfreds med resultaterne. Så jeg slibede forsiden lidt og påførte en PU -frakke. Jeg endte med at slibe pelsen senere, men det er en god idé at lade den være på, hvis du ikke synes den er æstetisk utilfredsstillende.

Trin 7: Epoxy

Epoxy
Epoxy
Epoxy
Epoxy

Efter nogle test med led -positionen inden i hullerne, regnede jeg med, at den bedste diskussion opnås, når lysdioderne er omkring 0,2 væk fra hullets ende. Når du selv prøver dette, vil lysdiodernes lysstyrke være meget anderledes i hvert hul. Du skal ikke bekymre dig om dette; vi retter det i kode. Dette er på grund af den type bor, jeg brugte. Hvis jeg skulle gøre dette igen, ville jeg bruge en kuglebor til hullerne. Men under alle omstændigheder for at få afstanden blandede jeg lidt epoxy og lagde en lille smule i hvert hul.

Trin 8: Sæt det hele sammen

Samler det hele
Samler det hele
Samler det hele
Samler det hele
Samler det hele
Samler det hele
Samler det hele
Samler det hele

Lysdioderne vil blive placeret fra klokken 12-timers position, der bevæger sig mod uret gennem alle timers positioner og derefter til minutviseren, igen ved at bevæge sig fra 60-minutters-mærket, der bevæger sig mod uret. Dette er sådan, at når vi ser forfra, vises LED -mønsteret med uret.

Efter at epoxyen var hærdet i en time, kom jeg lidt mere epoxy i. Denne gang placerede jeg lysdioderne i hullerne, og sørgede for at dække ledningerne og loddeledene med epoxy. Dette giver god lysspredning og sikrer ledningerne.

Trin 9: Kode

Kode
Kode

Koden er på GitHub, du er velkommen til at ændre den til din brug. Når du tænder alle lysdioderne på samme niveau, vil lysstyrken, der skinner igennem, være meget forskellig i hvert hul. Dette er på grund af den forskellige tykkelse af træ i hullerne og forskellen i træets skygge, Som du kan se, varierer træfarven en del i mit stykke. For at afhjælpe denne forskel i lysstyrke lavede jeg en matrix af LED -lysstyrkeniveauer. Og reducerede lysstyrken på de lysere lysdioder. Det er en prøve- og fejlproces og kan tage flere minutter, men resultaterne er det hele værd.

krydsfinerClock.ino

// Krydsfinerur
// Forfatter: tinkrmind
// Attribution 4.0 International (CC BY 4.0). Du er fri til at:
// Del - kopier og omfordel materialet i ethvert medie eller format
// Tilpas - remix, transformer og bygger på materialet til ethvert formål, også kommercielt.
// Hurra!
#omfatte
#include "RTClib.h"
RTC_DS3231 rtc;
#include "Adafruit_NeoPixel.h"
#ifdef _AVR_
#omfatte
#Afslut Hvis
#definerePIN6
Adafruit_NeoPixel strip = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int timePixel = 0;
int minutPixel = 0;
unsignedlong sidsteRtcCheck;
String inputString = ""; // en streng til at gemme indgående data
boolsk stringComplete = false; // om strengen er komplet
int niveau [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
mens (! Seriel); // til Leonardo/Micro/Zero
#Afslut Hvis
// Dette er til Trinket 5V 16MHz, du kan fjerne disse tre linjer, hvis du ikke bruger en Trinket
#if defineret (_AVR_ATtiny85_)
hvis (F_CPU == 16000000) clock_prescale_set (clock_div_1);
#Afslut Hvis
// Slut på specialpinkode
Serial.begin (9600);
strip.begin ();
strip.show (); // Initialiser alle pixels til 'off'
hvis (! rtc.begin ()) {
Serial.println ("RTC kunne ikke findes");
mens (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)));
hvis (rtc.lostPower ()) {
Serial.println ("RTC mistede strøm, lad os indstille tiden!");
// følgende linje indstiller RTC til dato og klokkeslæt, hvor denne skitse blev udarbejdet
rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)));
// Denne linje indstiller RTC med en eksplicit dato og tid, f.eks
// 21. januar 2014 kl. 03.00 vil du ringe til:
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
}
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
// lightUpEven ();
// mens (1);
lastRtcCheck = 0;
}
voidloop () {
if (millis () - lastRtcCheck> 2000) {
DateTime nu = rtc.now ();
Serial.print (nu. Time (), DEC);
Serial.print (':');
Serial.print (nu. Minut (), DEC);
Serial.print (':');
Serial.print (nu. Sekund (), DEC);
Serial.println ();
showTime ();
lastRtcCheck = millis ();
}
hvis (! digitalRead (2)) {
lightUpEven ();
}
hvis (stringComplete) {
Serial.println (inputString);
hvis (inputString [0] == 'l') {
Serial.println ("niveau");
lightUpEven ();
}
hvis (inputString [0] == 'c') {
Serial.println ("Viser tid");
showTime ();
strip.show ();
}
hvis (inputString [0] == '1') {
Serial.println ("Tænd for alle lysdioder");
lightUp (strip. Color (255, 255, 255));
strip.show ();
}
hvis (inputString [0] == '0') {
Serial.println ("Clearing strip");
klar();
strip.show ();
}
// #3, 255 ville sætte led nummer 3 til niveau 255, 255, 255
hvis (inputString [0] == '#') {
Streng temp;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
temp = inputString.substring (inputString.indexOf (',') + 1);
int intensitet = temp.toInt ();
Serial.print ("Indstilling");
Serial.print (pixNum);
Serial.print ("til niveau");
Serial.println (intensitet);
strip.setPixelColor (pixNum, strip. Color (intensitet, intensitet, intensitet));
strip.show ();
}
// #3, 255, 0, 125 ville sætte led nummer 3 til niveau 255, 0, 125
hvis (inputString [0] == '$') {
Streng temp;
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 ("Indstilling");
Serial.print (pixNum);
Serial.print ("R til");
Serial.print (rIntensity);
Serial.print ("G til");
Serial.print (gIntensity);
Serial.print ("B til");
Serial.println (bIntensity);
strip.setPixelColor (pixNum, strip. Color (rIntensity, gIntensity, bIntensity));
strip.show ();
}
hvis (inputString [0] == 's') {
Streng temp;
int time, minut;
temp = inputString.substring (1);
time = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
minut = temp.toInt ();
Serial.print ("Viser tid:");
Seriel.print (time);
Serial.print (":");
Serial.print (minut);
showTime (time, minut);
forsinkelse (1000);
}
inputString = "";
stringComplete = false;
}
// forsinkelse (1000);
}
voidserialEvent () {
mens (Serial.available ()) {
char inChar = (char) Serial.read ();
inputString += inChar;
hvis (inChar == '\ n') {
stringComplete = true;
}
forsinkelse (1);
}
}
voidclear () {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (0, 0, 0));
}
}
voidshowTime () {
DateTime nu = rtc.now ();
timePixel = nu. time () % 12;
minutPixel = (nu. minut () / 5) % 12 + 12;
klar();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * level [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * niveau [minutPixel], 30 + 30 * niveau [minutPixel], 20 + 20 * niveau [minutPixel]));
strip.setPixelColor (hourPixel, strip. Color (niveau [timePixel], niveau [hourPixel], niveau [hourPixel]));
strip.setPixelColor (minutPixel, strip. Color (niveau [minutPixel], niveau [minutPixel], niveau [minutPixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidshowTime (int time, int minut) {
timePixel = time % 12;
minutPixel = (minut / 5) % 12 + 12;
klar();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * level [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * niveau [minutPixel], 30 + 30 * niveau [minutPixel], 20 + 20 * niveau [minutPixel]));
strip.setPixelColor (hourPixel, strip. Color (niveau [timePixel], niveau [hourPixel], niveau [hourPixel]));
strip.setPixelColor (minutPixel, strip. Color (niveau [minutPixel], niveau [minutPixel], niveau [minutPixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidlightUp (uint32_t farve) {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, farve);
}
strip.show ();
}
voidlightUpEven () {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (niveau , niveau , niveau ));
}
strip.show ();
}

se rawplywoodClock.ino hostet af ❤ af GitHub

Trin 10: Computersyn - Kalibrering

Computersyn - Kalibrering
Computersyn - Kalibrering
Computersyn - Kalibrering
Computersyn - Kalibrering

Jeg tog et bevidst valg om ikke at bruge finer i dette projekt. Hvis jeg havde, ville trætykkelsen have været den samme foran alle lysdioder. Men fordi jeg har en anden tykkelse af træ foran hver LED, og fordi træfarven også varierer meget, er LED -lysstyrken forskellig for hver LED. For at få alle lysdioderne til at synes at have samme lysstyrke, udtænkte jeg et smart trick.

Jeg skrev en behandlingskode (på GitHub), der tager et foto af uret og analyserer lysstyrken på hver LED efter tur. Det varierer derefter strømmen til hver LED for at forsøge at få dem alle til at have samme lysstyrke som den lyseste LED. Nu ved jeg, at dette er overkill, men billedbehandling er meget sjovt! Og jeg håber at udvikle kalibreringskoden som et bibliotek.

Du kan se LED -lysstyrken før og efter kalibrering på billederne ovenfor.

kalibrerDispllay.pde

importprocessing.video.*;
importprocessing.serial.*;
Seriel myPort;
Optag video;
finalint numLed = 24;
int ledNum = 0;
// du skal have disse globale variabler for at bruge 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 udført;
int numPixelsInLed;
lang ledIntensitet;
int ledPower;
lang targetIntensity = 99999999;
voidsetup () {
done = 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 (dette, portnavn, 9600);
størrelse (640, 480);
video = newCapture (dette, bredde, højde);
video.start ();
noStroke ();
glat();
forsinkelse (1000); // Vent på, at den serielle port åbnes
}
voiddraw () {
hvis (video.available ()) {
hvis (udført [ledNum] == 0) {
clearDisplay ();
forsinkelse (1000);
video.read ();
billede (video, 0, 0, bredde, højde); // Tegn webcam -videoen på skærmen
saveFrame ("data/no_leds.jpg");
hvis (runNumber! = 0) {
hvis ((ledIntensity [ledNum] - targetIntensity)*100/targetIntensity> acceptError) {
ledPower [ledNum] -= pow (0,75, runNumber)*100+1;
}
if ((targetIntensity - ledIntensity [ledNum])*100/targetIntensity> acceptError) {
ledPower [ledNum] += pow (0,75, runNumber)*100 +1;
}
if (abs (targetIntensity - ledIntensity [ledNum])*100/targetIntensity <= acceptableError) {
udført [ledNum] = 1;
print ("Led");
print (ledNum);
print ("færdig");
}
hvis (ledPower [ledNum]> 255) {
ledPower [ledNum] = 255;
}
hvis (ledPower [ledNum] <0) {
ledPower [ledNum] = 0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
forsinkelse (1000);
video.read ();
billede (video, 0, 0, bredde, højde); // Tegn webcam -videoen på skærmen
forsinkelse (10);
mens (myPort.available ()> 0) {
int inByte = myPort.read ();
// print (char (inByte));
}
String imageName = "data/";
imageName+= str (ledNum);
imageName += "_ led.jpg";
saveFrame (imageName);
String originalImageName = "data/org";
originalImageName+= str (ledNum);
originalImageName += ". jpg";
hvis (runNumber == 0) {
saveFrame (originalImageName);
}
PImage noLedImg = loadImage ("data/no_leds.jpg");
PImage ledImg = loadImage (imageName);
PImage originalImg = loadImage (originalImageName);
noLedImg.loadPixels ();
ledImg.loadPixels ();
originalImg.loadPixels ();
baggrund (0);
loadPixels ();
ledIntensity [ledNum] = 0;
numPixelsInLed [ledNum] = 0;
for (int x = 0; x <bredde; x ++) {
for (int y = 0; y <højde; y ++) {
PxPGetPixelDark (x, y, noLedImg.pixels, bredde);
PxPGetPixelLed (x, y, ledImg.pixels, bredde);
PxPGetPixelOrg (x, y, originalImg.pixels, bredde);
hvis ((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] ++;
} andet {
rTemp = 0;
gTemp = 0;
bTemp = 0;
}
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, pixels, bredde);
}
}
ledIntensity [ledNum] /= numPixelsInLed [ledNum];
hvis (targetIntensity> ledIntensity [ledNum] && runNumber == 0) {
targetIntensity = ledIntensity [ledNum];
}
updatePixels ();
}
print (ledNum);
Print(', ');
print (ledPower [ledNum]);
Print(', ');
println (ledIntensity [ledNum]);
ledNum ++;
hvis (ledNum == numLed) {
int donezo = 0;
for (int i = 0; i <numLed; i ++) {
donezo += udført ;
}
hvis (donezo == numLed) {
println ("DONE");
for (int i = 0; i <numLed; i ++) {
print (i);
print ("\ t");
println (ledPower );
}
print ("int niveau [");
print (ledNum);
print ("] = {");
for (int i = 0; i <numLed-1; i ++) {
print (ledPower );
Print(', ');
}
print (ledPower [numLed -1]);
println ("};");
lightUpEven ();
mens (sandt);
}
print ("Målintensitet:");
hvis (runNumber == 0) {
targetIntensity -= 1;
}
println (targetIntensity);
ledNum = 0;
runNumber ++;
}
}
}
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // at få farverne som en int fra pixels
aOrg = (thisPixel >> 24) & 0xFF; // vi skal skifte og maskere for at få hver komponent alene
rOrg = (thisPixel >> 16) & 0xFF; // dette er hurtigere end at kalde rød (), grøn (), blå ()
gOrg = (thisPixel >> 8) & 0xFF;
bOrg = thisPixel & 0xFF;
}
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // at få farverne som en int fra pixels
aDark = (thisPixel >> 24) & 0xFF; // vi skal skifte og maskere for at få hver komponent alene
rDark = (thisPixel >> 16) & 0xFF; // dette er hurtigere end at kalde rød (), grøn (), blå ()
gDark = (thisPixel >> 8) & 0xFF;
bDark = thisPixel & 0xFF;
}
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // at få farverne som en int fra pixels
aLed = (thisPixel >> 24) & 0xFF; // vi skal skifte og maskere for at få hver komponent alene
rLed = (thisPixel >> 16) & 0xFF; // dette er hurtigere end at kalde rød (), grøn (), blå ()
gLed = (thisPixel >> 8) & 0xFF;
bLed = thisPixel & 0xFF;
}
voidPxPSetPixel (intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) {
a = (a << 24);
r = r << 16; // Vi pakker alle 4 komponenter i ét int
g = g << 8; // så vi skal flytte dem til deres steder
farve argb = a | r | g | b; // binær "eller" operation tilføjer dem alle til ét int
pixelArray [x+y*pixelsWidth] = argb; // endelig satte vi int med te farver ind i pixels
}

se rawcalibrateDispllay.pde hostet af ❤ af GitHub

Trin 11: Afmærkninger

Faldgruber at undgå:

* Med træ får du, hvad du betaler for. Så få træ af god kvalitet. Birkekrydsfiner er et godt valg; ethvert let massivt træ vil også gøre det pænt. Jeg billede ud på skoven og fortryder min beslutning.

* Det er bedre at bore mindre end mere. Et par af hullerne gik for dybt til mit stykke. Og epoxyen viser sig på forsiden. Det er meget mærkbart, når du opdager det.

* Brug en kuglebor i stedet for en lige ende. Jeg har ikke eksperimenteret med kugleenden, men jeg er temmelig sikker på, at resultaterne bliver meget bedre.

Jeg flirter med tanken om at sælge disse på Etsy eller tindie. Jeg ville virkelig sætte pris på det, hvis du kunne kommentere herunder, hvis du synes, det giver mening:)

Anbefalede: