Inhoudsopgave:

Houten LED-klok - analoge stijl - Ajarnpa
Houten LED-klok - analoge stijl - Ajarnpa

Video: Houten LED-klok - analoge stijl - Ajarnpa

Video: Houten LED-klok - analoge stijl - Ajarnpa
Video: Best Wooden LED Clock With Wireless Charging&Setting Guide 2024, November
Anonim
Houten LED-klok - analoge stijl
Houten LED-klok - analoge stijl

Het is een houten LED-klok in analoge stijl. Ik weet niet waarom ik er nog nooit een heb gezien… hoewel de digitale typen heel gewoon zijn. Hoe dan ook, hier gaan we!

Stap 1:

Afbeelding
Afbeelding
Afbeelding
Afbeelding

Het multiplex klokproject begon als een eenvoudig startproject voor de CNC-router. Ik keek online naar eenvoudige projecten en vond deze lamp (afbeelding hierboven). Ik had ook digitale klokken gezien die door houtfineer schijnen (afbeelding hierboven). Het was dus een voor de hand liggend idee om de twee projecten te combineren. Om mezelf uit te dagen, besloot ik voor dit project geen fineer te gebruiken, maar alleen een stuk hout.

Stap 2: Ontwerp

Ontwerp
Ontwerp
Ontwerp
Ontwerp

Ik ontwierp de klok in Inkscape (afbeelding hierboven). Het ontwerp is naar keuze heel eenvoudig. Ik besloot om geen sporen voor de draden te routeren, omdat ik op dit moment niet zeker wist of ik met radiale of perimeterbedrading wilde gaan. (Ik besloot uiteindelijk om met perimeterbedrading te gaan.) Een neopixel gaat in elk van de kleine ronde gaatjes om de minuten- en uurtijd weer te geven, met een precisie van vijf minuten. De cirkel in het midden wordt naar buiten geleid om plaats te bieden aan de elektronica.

Stap 3: CNCen

CNCen
CNCen
CNCen
CNCen
CNCen
CNCen
CNCen
CNCen

Ik ontwierp de toolpaths op MasterCAM, en gebruikte een technoRouter om de klok uit 3/4 inch multiplex te frezen. Ik gebruik hiervoor een stuk van 15 "x15", met minimale verspilling. De truc is om zoveel mogelijk van het hout weg te werken zonder door het hout te breken. Het laten van 0,05"-0,1" is een goede keuze voor licht hout. Als je het niet zeker weet, kun je er beter meer hout in laten, omdat je de andere kant altijd kunt schuren. Ik heb uiteindelijk iets te veel hout uit sommige delen verwijderd, maar gelukkig hebben de resultaten hier niet al te veel onder te lijden.

Opmerking voor gebruikers zonder toegang tot een CNC:

Dit project kan eenvoudig worden gedaan met een kolomboormachine. Je hoeft alleen maar de stop in te stellen op een punt waar je ongeveer 0,1 hout aan de basis achterlaat. Je moet precies zijn, maar niet te precies. In het ideale geval ziet niemand alle LED's oplichten op tegelijkertijd, dus je kunt wegkomen met een beetje slop.

Stap 4: Elektronica

Elektronica
Elektronica
Elektronica
Elektronica
Elektronica
Elektronica

De elektronica is vrij eenvoudig. Er zijn 24 neopixels, twaalf voor het weergeven van de uren en twaalf voor het weergeven van de minuten, met een precisie van vijf minuten. Een Arduino pro mini bestuurt de neopixels en krijgt nauwkeurige tijd via een DS3231 realtime clock (RTC) -module. De RTC-module heeft een knoopcel als back-up, zodat hij geen tijd verliest, zelfs niet als de stroom is uitgeschakeld.

Materiaal:

Arduino pro mini (of welke andere Arduino dan ook)

DS3231 breakout-bord

Neopixels in afzonderlijke breakout-borden

Stap 5: Elektronica Montage

Elektronica Montage
Elektronica Montage
Elektronica Montage
Elektronica Montage
Elektronica Montage
Elektronica Montage
Elektronica Montage
Elektronica Montage

Ik verbond de neopixels in een string, met 2,5 draden voor de eerste twaalf leds en vier-inch draad voor de volgende twaalf. Ik had iets kleinere draadlengtes kunnen gebruiken. Nadat ik de string had gemaakt, testte ik hem uit en zorgde ervoor dat het soldeer verbindingen waren goed. Ik voegde een tijdelijke schakelaar toe om alle leds in te schakelen, gewoon om te pronken.

Stap 6: Drooglopen

Oefening
Oefening
Oefening
Oefening
Oefening
Oefening
Oefening
Oefening

Na wat geëxperimenteerd te hebben, LED's in de gaten te hebben gestoken en ze allemaal aan te zetten, was ik tevreden met het resultaat. Dus heb ik de voorkant een beetje geschuurd en een PU-laag aangebracht. Uiteindelijk heb ik de vacht er later afgeschuurd, maar het is een goed idee om het aan te laten als je het esthetisch niet onaangenaam vindt.

Stap 7: Epoxy

Epoxy
Epoxy
Epoxy
Epoxy

Na wat testen met de led-positie in de gaten, kwam ik tot de conclusie dat de beste discussie wordt bereikt wanneer de LED's ongeveer 0,2 verwijderd zijn van het einde van het gat. Als je dit zelf probeert, zal de helderheid van de LED's heel anders zijn in elk gat. Maak je hier geen zorgen over; we lossen het in code op. Dit komt door het type boor dat ik heb gebruikt. Als ik dit opnieuw zou doen, zou ik een kogelboor gebruiken voor de gaten Maar in ieder geval om de afstand te krijgen heb ik wat epoxy gemengd en een klein beetje in elk gaatje gedaan.

Stap 8: Alles samenbrengen

Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten
Alles bij elkaar zetten

De LED's worden geplaatst vanaf de 12-uurwijzerpositie tegen de klok in door alle uurwijzerposities en vervolgens naar de minutenwijzer, opnieuw bewegend vanaf de 60-minutenmarkering tegen de klok in. Dit is zo dat wanneer we vanaf de voorkant kijken, het LED-patroon met de klok mee lijkt te gaan.

Nadat de epoxy een uur was uitgehard, heb ik wat meer epoxy aangebracht. Deze keer plaatste ik de LED's in de gaten, waarbij ik ervoor zorgde dat de draden en soldeerverbindingen met de epoxy werden bedekt. Dit zorgt voor een goede lichtverspreiding en borgt de draden.

Stap 9: Coderen

Code
Code

De code staat op GitHub, voel je vrij om deze aan te passen voor jouw gebruik. Wanneer je alle LED's op hetzelfde niveau inschakelt, zal de helderheid van het licht dat er doorheen schijnt in elk gat heel anders zijn. Dit komt door de verschillende diktes van het hout in de gaten en het verschil in de schaduw van het hout. Zoals je kunt zien varieert de houtkleur nogal in mijn stuk. Om dit verschil in helderheid te verhelpen, heb ik een matrix gemaakt van led-helderheidsniveaus. En verminderde de helderheid van de helderdere LED's. Het is een proces van vallen en opstaan en kan enkele minuten duren, maar de resultaten zijn het zeker waard.

multiplexClock.ino

// Multiplex klok
// Auteur: tinkrmind
// Naamsvermelding 4.0 Internationaal (CC BY 4.0). U bent vrij om:
// Delen - kopieer en distribueer het materiaal in elk medium of formaat
// Aanpassen - remix, transformeer en bouw voort op het materiaal voor elk doel, zelfs commercieel.
// Hoera!
#erbij betrekken
#include"RTClib.h"
RTC_DS3231 rtc;
#include"Adafruit_NeoPixel.h"
#ifdef _AVR_
#erbij betrekken
#stop als
#definePIN6
Adafruit_NeoPixel-strip = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int uurPixel = 0;
int minuutPixel = 0;
niet ondertekend lang laatsteRtcCheck;
String inputString = ""; // een string om inkomende gegevens vast te houden
boolean stringComplete = false; // of de string compleet is
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
terwijl (!Serial); // voor Leonardo/Micro/Zero
#stop als
// Dit is voor Trinket 5V 16MHz, u kunt deze drie lijnen verwijderen als u geen Trinket gebruikt
#indien gedefinieerd (_AVR_ATtiny85_)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#stop als
// Einde van speciale code voor trinket
Serieel.begin(9600);
strip.begin();
strip.show(); // Initialiseer alle pixels op 'uit'
if (! rtc.begin()) {
Serial.println ("Kon RTC niet vinden");
terwijl (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust(DateTime(F(_DATE_), F(_TIME_)));
if (rtc.lostPower()) {
Serial.println("RTC heeft geen stroom meer, laten we de tijd instellen!");
// volgende regel stelt de RTC in op de datum en tijd waarop deze schets is gecompileerd
rtc.adjust(DateTime(F(_DATE_), F(_TIME_)));
// Deze regel stelt de RTC in met een expliciete datum en tijd, bijvoorbeeld om in te stellen
// 21 januari 2014 om 3 uur zou je bellen:
// rtc.adjust(DateTime(2017, 11, 06, 2, 49, 0));
}
// rtc.adjust(DateTime(2017, 11, 06, 2, 49, 0));
// lightUpEven();
// terwijl (1);
lastRtcCheck = 0;
}
leegteloop () {
if (millis() - lastRtcCheck >2000) {
DateTime nu = rtc.now();
Serial.print(nu.uur(), DEC);
Serieel.print(':');
Serial.print(nu.minute(), DEC);
Serieel.print(':');
Serial.print(nu.second(), DEC);
Serieel.println();
show Time();
lastRtcCheck = millis();
}
if (!digitalRead(2)) {
lightUpEven();
}
if (stringCompleet) {
Serial.println(inputString);
if (inputString[0] == 'l') {
Serieel.println("Niveau");
lightUpEven();
}
if (inputString[0] == 'c') {
Serial.println ("Toon tijd");
show Time();
strip.show();
}
if (inputString[0] == '1') {
Serial.println ("Alle LED's inschakelen");
lightUp(strip. Color(255, 255, 255));
strip.show();
}
if (inputString[0] == '0') {
Serial.println("Clearing strip");
Doorzichtig();
strip.show();
}
// #3, 255 zou led nummer 3 instellen op niveau 255, 255, 255
if (inputString[0] == '#') {
Stringtemperatuur;
temp = inputString.substring(1);
int pixNum = temp.toInt();
temp = inputString.substring(inputString.indexOf(', ') + 1);
int intensiteit = temp.toInt();
Serial.print("Instelling ");
Serial.print(pixNum);
Serial.print(" naar niveau ");
Serial.println(intensiteit);
strip.setPixelColor(pixNum, strip. Color(intensiteit, intensiteit, intensiteit));
strip.show();
}
// #3, 255, 0, 125 zou led nummer 3 instellen op niveau 255, 0, 125
if (inputString[0] == '$') {
Stringtemperatuur;
temp = inputString.substring(1);
int pixNum = temp.toInt();
int rIndex = inputString.indexOf(', ') + 1;
temp = inputString.substring(rIndex);
int rIntensiteit = 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 bIntensiteit = temp.toInt();
Serial.print("Instelling ");
Serial.print(pixNum);
Serial.print(" R naar ");
Serial.print(rIntensiteit);
Serial.print(" G naar ");
Serial.print(gIntensity);
Serial.print(" B tot ");
Serial.println(bIntensiteit);
strip.setPixelColor(pixNum, strip. Color(rIntensity, gIntensity, bIntensity));
strip.show();
}
if (inputString[0] == 's') {
Stringtemperatuur;
int uur, minuut;
temp = inputString.substring(1);
uur = temp.toInt();
int rIndex = inputString.indexOf(', ') + 1;
temp = inputString.substring(rIndex);
minuut = temp.toInt();
Serial.print("Toon tijd: ");
Seriële.afdruk(uur);
Serial.print(":");
Serieafdruk(minuut);
showTime (uur, minuut);
vertraging (1000);
}
invoerString = "";
stringComplete = onwaar;
}
// vertraging (1000);
}
voidserialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
stringComplete = waar;
}
vertraging(1);
}
}
leegte wissen() {
voor (uint16_t ik = 0; ik <strip.numPixels(); i++) {
strip.setPixelColor(i, strip. Color(0, 0, 0));
}
}
voidshowTime() {
DateTime nu = rtc.now();
hourPixel = nu.uur() % 12;
minutePixel = (now.minute() / 5) % 12 + 12;
Doorzichtig();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * niveau [uurPixel], 30 + 30 * niveau [uurPixel], 20 + 20 * niveau [uurPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * niveau [minutePixel], 30 + 30 * niveau [minutePixel], 20 + 20 * niveau [minutePixel]));
strip.setPixelColor(hourPixel, strip. Color(level[hourPixel], level[hourPixel], level[hourPixel]));
strip.setPixelColor(minutePixel, strip. Color(level[minutePixel], level[minutePixel], level[minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show();
}
voidshowTime(int uur, int minuut) {
uurPixel = uur % 12;
minuutPixel = (minuut / 5) % 12 + 12;
Doorzichtig();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * niveau [uurPixel], 30 + 30 * niveau [uurPixel], 20 + 20 * niveau [uurPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * niveau [minutePixel], 30 + 30 * niveau [minutePixel], 20 + 20 * niveau [minutePixel]));
strip.setPixelColor(hourPixel, strip. Color(level[hourPixel], level[hourPixel], level[hourPixel]));
strip.setPixelColor(minutePixel, strip. Color(level[minutePixel], level[minutePixel], level[minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show();
}
voidlightUp(uint32_t kleur) {
voor (uint16_t ik = 0; ik <strip.numPixels(); i++) {
strip.setPixelColor(i, kleur);
}
strip.show();
}
voidlightUpEven() {
voor (uint16_t ik = 0; ik <strip.numPixels(); i++) {
strip.setPixelColor(i, strip. Color(niveau, niveau, niveau));
}
strip.show();
}

bekijk rawplywoodClock.ino gehost met ❤ door GitHub

Stap 10: Computer Vision - Kalibratie

Computervisie - Kalibratie
Computervisie - Kalibratie
Computervisie - Kalibratie
Computervisie - Kalibratie

Ik heb er bewust voor gekozen om geen fineer te gebruiken in dit project. Als ik dat had gedaan, zou de houtdikte voor alle LED's hetzelfde zijn geweest. Maar omdat ik voor elke LED een andere houtdikte heb en omdat de houtkleur ook erg varieert, is de helderheid van de LED per LED anders. Om ervoor te zorgen dat alle LED's dezelfde helderheid hebben, bedacht ik een handige truc.

Ik heb een verwerkingscode geschreven (op GitHub) die een foto van de klok maakt en om de beurt de helderheid van elke LED analyseert. Het varieert vervolgens het vermogen naar elke LED om te proberen ze allemaal dezelfde helderheid te geven als de zwakste LED. Ik weet dat dit overdreven is, maar beeldverwerking is erg leuk! En ik hoop de kalibratiecode als bibliotheek te ontwikkelen.

U kunt de LED-helderheid voor en na de kalibratie zien op de bovenstaande foto's.

calibrerenDispllay.pde

importprocessing.video.*;
importprocessing.serial.*;
Seriële myPort;
Video opnemen;
finalint numLed =24;
int ledNum =0;
// je moet deze globale variabelen hebben om de PxPGetPixelDark() te gebruiken
int rDonker, gDonker, bDonker, aDonker;
int rLed, gLed, bLed, aLed;
int rOrg, gOrg, bOrg, aOrg;
int rTemp, gTemp, bTemp, aTemp;
PImage onzeImage;
int runNumber =0;
int acceptabelError =3;
int gedaan;
int numPixelsInLed;
lang ledIntensiteit;
int ledPower;
lange doelintensiteit =99999999;
voidsetup() {
gedaan =newint[numLed];
numPixelsInLed =newint[numLed];
ledIntensity =nieuwlang[numLed];
ledPower =newint[numLed];
voor (int i=0; i<numLed; i++) {
ledPower =255;
}
printArray(Serial.list());
String portName =Serial.list()[31];
myPort =newSerial(this, portName, 9600);
grootte (640, 480);
video =newCapture(deze, breedte, hoogte);
video.start();
geen slag();
zacht();
vertraging (1000); // Wacht tot de seriële poort opengaat
}
leegteken() {
if (video.beschikbaar()) {
if (klaar[ledNum] ==0) {
clearDisplay();
vertraging (1000);
video.lezen();
afbeelding (video, 0, 0, breedte, hoogte); // Teken de webcamvideo op het scherm
saveFrame("data/geen_leds.jpg");
if (runNumber !=0) {
if ((ledIntensity[ledNum] - targetIntensity)*100/targetIntensity > acceptabele fout) {
ledPower[ledNum] -=pow(0.75, runNumber)*100+1;
}
if ((targetIntensity - ledIntensity[ledNum])*100/targetIntensity > acceptabele fout) {
ledPower[ledNum] +=pow(0.75, runNumber)*100+1;
}
if (abs(targetIntensity - ledIntensity[ledNum])*100/targetIntensity <= acceptabele fout) {
klaar[ledNum] =1;
print("Led");
print(ledNum);
print("klaar");
}
if (ledPower[ledNum] >255) {
ledPower[ledNum] =255;
}
if (ledPower[ledNum] <0) {
ledPower[ledNum]=0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
vertraging (1000);
video.lezen();
afbeelding (video, 0, 0, breedte, hoogte); // Teken de webcamvideo op het scherm
vertraging(10);
while (myPort.available() >0) {
int inByte = myPort.read();
//print(char(inByte));
}
Tekenreeks afbeeldingsnaam = "data/";
imageName+=str(ledNum);
afbeeldingNaam +="_led.jpg";
saveFrame(afbeeldingNaam);
String originalImageName ="data/org";
originalImageName+=str(ledNum);
originalImageName +=".jpg";
if (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();
achtergrond (0);
loadPixels();
ledIntensity[ledNum] =0;
aantalPixelsInLed[ledNum] =0;
voor (int x =0; x<breedte; x++) {
voor (int y =0; y<hoogte; y++) {
PxPGetPixelDark(x, y, noLedImg.pixels, breedte);
PxPGetPixelLed(x, y, ledImg.pixels, breedte);
PxPGetPixelOrg(x, y, originalImg.pixels, breedte);
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]++;
} anders {
rTemp=0;
gTemp=0;
bTemp=0;
}
PxPSetPixel(x, y, rTemp, gTemp, bTemp, 255, pixels, breedte);
}
}
ledIntensity[ledNum] /= numPixelsInLed[ledNum];
if (targetIntensity > ledIntensity[ledNum] && runNumber ==0) {
targetIntensity = ledIntensity[ledNum];
}
updatePixels();
}
print(ledNum);
afdrukken(', ');
print(ledPower[ledNum]);
afdrukken(', ');
println(ledIntensity[ledNum]);
ledNum++;
if (ledNum == numLed) {
int donezo =0;
voor (int i=0; i<numLed; i++) {
donezo += klaar;
}
if (donezo == numLed) {
println("KLAAR");
voor (int i=0; i<numLed; i++) {
afdrukken (ik);
print("\t");
println(ledPower);
}
print("int niveau[");
print(ledNum);
print("] = {");
voor (int i=0; i<numLed-1; i++) {
print(ledPower);
afdrukken(', ');
}
print(ledPower[numLed -1]);
println("};");
lightUpEven();
terwijl (waar);
}
print("Doelintensiteit: ");
if (runNumber ==0) {
targetIntensity -=1;
}
println(targetIntensity);
ledNum =0;
runNumber++;
}
}
}
voidPxPGetPixelOrg(intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel=pixelArray[x+y*pixelsBreedte]; // de kleuren krijgen als een int van de pixels
aOrg = (dit pixel >>24) &0xFF; // we moeten verschuiven en maskeren om elk onderdeel alleen te krijgen
rOrg = (dit pixel >>16) &0xFF; // dit is sneller dan het aanroepen van red(), green(), blue()
gOrg = (dit pixel >>8) &0xFF;
bOrg = thisPixel &0xFF;
}
voidPxPGetPixelDark(intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel=pixelArray[x+y*pixelsBreedte]; // de kleuren krijgen als een int van de pixels
aDark = (dit pixel >>24) &0xFF; // we moeten verschuiven en maskeren om elk onderdeel alleen te krijgen
rDark = (dit pixel >>16) &0xFF; // dit is sneller dan het aanroepen van red(), green(), blue()
gDark = (dit pixel >>8) &0xFF;
bDonker = ditPixel &0xFF;
}
voidPxPGetPixelLed(intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel=pixelArray[x+y*pixelsBreedte]; // de kleuren krijgen als een int van de pixels
aLed = (dit pixel >>24) &0xFF; // we moeten verschuiven en maskeren om elk onderdeel alleen te krijgen
rLed = (dit pixel >>16) &0xFF; // dit is sneller dan het aanroepen van red(), green(), blue()
gLed = (dit pixel >>8) &0xFF;
bLed = ditPixel &0xFF;
}
voidPxPSetPixel(intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) {
een =(a <<24);
r = r <<16; // We verpakken alle 4 componenten in één int
g = g <<8; // dus we moeten ze naar hun plaats verplaatsen
kleur argb = een | r | g | B; // binaire "of"-bewerking voegt ze allemaal toe aan één int
pixelArray[x+y*pixelsWidth]= argb; // eindelijk zetten we de int met de kleuren in de pixels
}

bekijk rawcalibrateDispllay.pde gehost met ❤ door GitHub

Stap 11: Opmerkingen bij afscheid

Te vermijden valkuilen:

* Met hout krijgt u waar u voor betaalt. Koop dus hout van goede kwaliteit. Berken multiplex is een goede keuze; elk licht massief hout zal het ook goed doen. Ik heb bezuinigd op het hout en heb spijt van mijn beslissing.

* Het is beter om minder te boren dan meer. Een paar van de gaten gingen te diep voor mijn stuk. En de epoxy is zichtbaar aan de voorkant. Het valt erg op als je het eenmaal opmerkt.

* Gebruik een kogelkopboor in plaats van een recht uiteinde. Ik heb niet geëxperimenteerd met het kogeleindstuk, maar ik ben er vrij zeker van dat de resultaten veel beter zullen zijn.

Ik flirt met het idee om deze op Etsy of Tindie te verkopen. Ik zou het erg op prijs stellen als je hieronder een reactie zou plaatsen als je denkt dat het logisch is:)

Aanbevolen: