Sadržaj:

Drveni LED sat - analogni stil: 11 koraka (sa slikama)
Drveni LED sat - analogni stil: 11 koraka (sa slikama)

Video: Drveni LED sat - analogni stil: 11 koraka (sa slikama)

Video: Drveni LED sat - analogni stil: 11 koraka (sa slikama)
Video: Моя работа наблюдать за лесом и здесь происходит что-то странное 2024, Srpanj
Anonim
Drveni LED sat - analogni stil
Drveni LED sat - analogni stil

To je drveni LED sat u analognom stilu. Ne znam zašto prije nisam vidio jedno od ovih … iako su digitalni tipovi vrlo česti. U svakom slučaju, evo nas!

Korak 1:

Slika
Slika
Slika
Slika

Projekt sata od šperploče započeo je kao jednostavan početni projekt za CNC usmjerivač. Gledao sam jednostavne projekte na internetu i pronašao ovu lampu (slika gore). Također sam vidio digitalne satove koji sjaje kroz drveni furnir (slika gore). Dakle, kombiniranje dva projekta bila je očita ideja. U želji da se izazovem, odlučio sam ne koristiti furnir već samo komad drveta za ovaj projekt.

Korak 2: Dizajn

Oblikovati
Oblikovati
Oblikovati
Oblikovati

Dizajnirao sam sat u Inkscape -u (slika gore). Dizajn je vrlo jednostavan po izboru. Odlučio sam se protiv usmjeravanja tragova za žice jer u ovom trenutku nisam bio siguran želim li ići s radijalnim ili obodnim ožičenjem. (Odlučio sam konačno krenuti s ožičenjem po obodu.) Po jedan neopiksel ulazi u svaku od malih kružnih rupa za pokazivanje minuta i sati, s petominutnom preciznošću. Krug u sredini bit će usmjeren prema elektronici.

Korak 3: CNC

CNC
CNC
CNC
CNC
CNC
CNC
CNC
CNC

Dizajnirao sam staze alata na MasterCAM -u, a pomoću technoRoutera izradio sam sat od šperploče od 3/4 inča. Za to koristim komad 15 "x15", s minimalnim rasipanjem. Trik je u tome da izvučete što je moguće više drva bez probijanja kroz drvo. Ostavljanje 0,05 "-0,1" dobar je izbor za svijetlo drvo. Ako niste sigurni, bolje je ostaviti više drva jer drugu stranu uvijek možete brusiti. Na kraju sam uklonio malo previše drva s nekih dijelova, ali na sreću rezultati zbog toga ne trpe previše.

Napomena za korisnike bez pristupa CNC -u:

Ovaj se projekt lako može izvesti bušilicom. Samo trebate postaviti zaustavljanje na mjestu gdje ostavljate oko 0,1 drva preostalog u podnožju. Morat ćete biti precizni, ali ne previše precizni. Uostalom, idealno je da nitko neće vidjeti da sve LED diode svijetle na u isto vrijeme, tako da se možete malo izvući.

Korak 4: Elektronika

Elektronika
Elektronika
Elektronika
Elektronika
Elektronika
Elektronika

Elektronika je prilično jednostavna. Postoji 24 neopiksela, dvanaest za prikazivanje sati i dvanaest za prikazivanje minuta, s petominutnom preciznošću. Arduino pro mini kontrolira neopiksele i dobiva točno vrijeme putem DS3231 modula sata u stvarnom vremenu (RTC). RTC modul ima rezervnu ćeliju u obliku novčića, tako da ne gubi vrijeme čak ni kad je napajanje isključeno.

Materijal:

Arduino pro mini (ili bilo koji drugi Arduino po tom pitanju)

DS3231 ploča za razbijanje

Neopikseli u pojedinačnim pločama za razbijanje

Korak 5: Montaža elektronike

Sklop elektronike
Sklop elektronike
Sklop elektronike
Sklop elektronike
Sklop elektronike
Sklop elektronike
Sklop elektronike
Sklop elektronike

Spojio sam neopiksele u niz, koristeći žice od 2,5 za prvih dvanaest LED dioda i žicu od 4 inča za sljedećih dvanaest. Mogao sam upotrijebiti nešto manje duljine žica. Nakon što sam napravio niz, testirao sam ga, pazeći da lemljenje spojevi su bili dobri. Dodao sam trenutni prekidač za uključivanje svih LED dioda, samo da se pokažem.

Korak 6: Suho trčanje

Testno pokretanje
Testno pokretanje
Testno pokretanje
Testno pokretanje
Testno pokretanje
Testno pokretanje
Testno pokretanje
Testno pokretanje

Nakon eksperimentiranja, stavljanja LED dioda u rupe i uključivanja svih njih, bio sam zadovoljan rezultatima. Pa sam malo brusila prednju stranu i nanijela PU premaz. Kasnije sam ošišao kaput, ali bilo bi dobro ostaviti ga ako vam se ne čini estetski neugodnim.

Korak 7: epoksid

Epoksid
Epoksid
Epoksid
Epoksid

Nakon nekog testiranja sa LED pozicijom unutar rupa, zaključio sam da se najbolja rasprava postiže kada su LED diode udaljene oko 0,2 od kraja rupe. Kad to sami pokušate, svjetlina LED dioda bit će vrlo različita u svaka rupa. Ne brinite se oko ovoga; popravit ćemo to u kodu. To je zbog vrste svrdla koje sam upotrijebio. Ako bih ovo ponovio, upotrijebio bih svrdlo s kuglastom rupom. Ali, u svakom slučaju, kako bih dobio udaljenost, pomiješao sam malo epoksida i stavio malo u svaku rupu.

Korak 8: Sve spojite

Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno
Spajajući sve zajedno

LED diode će biti postavljene počevši od položaja kazaljke na satu u 12 sati koja se pomiče u smjeru suprotnom od kazaljke na satu kroz sve položaje kazaljki na satu, a zatim do minute, opet se pomičući od oznake od 60 minuta koja se pomiče u smjeru suprotnom od kazaljke na satu. To je tako da kada gledamo sprijeda LED uzorak se pojavljuje u smjeru kazaljke na satu.

Nakon što se epoksid očvrsnuo sat vremena, stavio sam još malo epoksida. Ovaj put sam LED diode stavio u rupe pazeći da žice i lemne spojeve prekrijemo epoksidom. To omogućuje dobru difuziju svjetlosti i učvršćuje žice.

Korak 9: Kodirajte

Kodirati
Kodirati

Kôd je na GitHubu, slobodno ga izmijenite za svoju upotrebu. Kad uključite sve LED diode na istu razinu, jačina svjetla koja svijetli bit će vrlo različita u svakoj rupi. To je zbog različite debljine drva u rupama i razlike u sjeni drveta. Kao što vidite, boja drva prilično se razlikuje u mom komadu. Kako bih ispravio ovu razliku u svjetlini, napravio sam matricu razina svjetline LED -a. I smanjila svjetlinu svjetlijih LED dioda. To je proces pokušaja i pogrešaka i može potrajati nekoliko minuta, ali rezultati su vrijedni toga.

šperpločaSat.ino

// Sat od šperploče
// Autor: tinkrmind
// Atribucija 4.0 International (CC BY 4.0). Slobodni ste:
// Dijeljenje - kopiranje i ponovna distribucija materijala u bilo kojem mediju ili formatu
// Adapt - remiks, transformacija i nadogradnja materijala u bilo koju svrhu, čak i komercijalnu.
// Ura!
#uključi
#include "RTClib.h"
RTC_DS3231 rtc;
#include "Adafruit_NeoPixel.h"
#ifdef _AVR_
#uključi
#završi ako
#definePIN6
Adafruit_NeoPixel traka = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int hourPixel = 0;
int minutePixel = 0;
unsignedlong lastRtcCheck;
Niz inputString = ""; // niz za držanje dolaznih podataka
boolean stringComplete = false; // je li niz potpun
int razina [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
while (! Serijski); // za Leonarda/Micro/Zero
#završi ako
// Ovo je za Trinket 5V 16MHz, možete ukloniti ove tri linije ako ne koristite Trinket
#ako je definirano (_AVR_ATtiny85_)
if (F_CPU == 16000000) clock_prescale_set (clock_div_1);
#završi ako
// Poseban kod kraja sitnica
Serial.begin (9600);
strip.begin ();
strip.show (); // Pokretanje svih piksela na "isključeno"
if (! rtc.begin ()) {{100} {101}
Serial.println ("Nije moguće pronaći RTC");
while (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)));
if (rtc.lostPower ()) {
Serial.println ("RTC je izgubio napajanje, dopustite da postavite vrijeme!");
// sljedeći redak postavlja RTC na datum i vrijeme sastavljanja ove skice
rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)));
// Ovaj redak postavlja RTC s eksplicitnim datumom i vremenom, na primjer za postavljanje
// 21. siječnja 2014. u 3 ujutro nazvali biste:
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
}
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0));
// lightUpEven ();
// while (1);
lastRtcCheck = 0;
}
voidloop () {
if (millis () - lastRtcCheck> 2000) {
DateTime now = rtc.now ();
Serial.print (now.hour (), DEC);
Serial.print (':');
Serial.print (now.minute (), DEC);
Serial.print (':');
Serijski.ispis (sada.sekunda (), DEC);
Serial.println ();
showTime ();
lastRtcCheck = millis ();
}
if (! digitalRead (2)) {
lightUpEven ();
}
if (stringComplete) {
Serial.println (inputString);
if (inputString [0] == 'l') {
Serial.println ("Razina");
lightUpEven ();
}
if (inputString [0] == 'c') {
Serial.println ("Prikazivanje vremena");
showTime ();
strip.show ();
}
if (inputString [0] == '1') {
Serial.println ("Uključivanje svih LED -a");
lightUp (strip. Boja (255, 255, 255));
strip.show ();
}
if (inputString [0] == '0') {
Serial.println ("Čišćenje trake");
čisto();
strip.show ();
}
// #3, 255 postavilo bi vodeći broj 3 na razinu 255, 255, 255
if (inputString [0] == '#') {
Niska temp;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
temp = inputString.substring (inputString.indexOf (',') + 1);
int intenzitet = temp.toInt ();
Serial.print ("Postavka");
Serijski.ispis (pixNum);
Serial.print ("na razinu");
Serial.println (intenzitet);
strip.setPixelColor (pixNum, strip. Color (intenzitet, intenzitet, intenzitet));
strip.show ();
}
// #3, 255, 0, 125 postavilo bi vodeći broj 3 na razinu 255, 0, 125
if (inputString [0] == '$') {
Niska 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 ("Postavka");
Serijski.ispis (pixNum);
Serial.print ("R do");
Serial.print (rIntensity);
Serial.print ("G do");
Serial.print (gIntensity);
Serial.print ("B do");
Serial.println (bIntensity);
strip.setPixelColor (pixNum, strip. Color (rIntensity, gIntensity, bIntensity));
strip.show ();
}
if (inputString [0] == 's') {
Niska temp;
int sat, minuta;
temp = inputString.substring (1);
sat = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
minuta = temp.toInt ();
Serial.print ("Prikazuje se vrijeme:");
Serijski.tisak (sat);
Serial.print (":");
Serijski.tisak (minuta);
showTime (sat, minuta);
kašnjenje (1000);
}
inputString = "";
stringComplete = false;
}
// kašnjenje (1000);
}
voidserialEvent () {
while (Serial.available ()) {
char inChar = (char) Serial.read ();
inputString += inChar;
if (inChar == '\ n') {
stringComplete = true;
}
odgoda (1);
}
}
voidclear () {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (0, 0, 0));
}
}
voidshowTime () {
DateTime now = rtc.now ();
hourPixel = now.hour () % 12;
minutePixel = (sada.minuta () / 5) % 12 + 12;
čisto();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * razina [hourPixel], 30 + 30 * razina [hourPixel], 20 + 20 * razina [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * razina [minutePixel], 30 + 30 * razina [minutePixel], 20 + 20 * razina [minutePixel]));
strip.setPixelColor (hourPixel, strip. Color (razina [hourPixel], razina [hourPixel], razina [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (razina [minutePixel], razina [minutePixel], razina [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidshowTime (int sat, int minuta) {
hourPixel = sat % 12;
minutePixel = (minuta / 5) % 12 + 12;
čisto();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * razina [hourPixel], 30 + 30 * razina [hourPixel], 20 + 20 * razina [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * razina [minutePixel], 30 + 30 * razina [minutePixel], 20 + 20 * razina [minutePixel]));
strip.setPixelColor (hourPixel, strip. Color (razina [hourPixel], razina [hourPixel], razina [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (razina [minutePixel], razina [minutePixel], razina [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidlightUp (boja uint32_t) {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, boja);
}
strip.show ();
}
voidlightUpEven () {
for (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (razina , razina , razina ));
}
strip.show ();
}

pogledajte rawplywoodClock.ino hosted with ❤ by GitHub

Korak 10: Računalni vid - kalibracija

Računalni vid - kalibracija
Računalni vid - kalibracija
Računalni vid - kalibracija
Računalni vid - kalibracija

Svjesno sam odlučio da ne koristim furnir u ovom projektu. Da jesam, debljina drva bila bi ista ispred svih LED dioda. No, budući da ispred svake LED diode imam različitu debljinu drva i zato što se boja drveta također jako razlikuje, svjetlina LED svjetla je različita za svaku LED. Kako bi sve LED diode izgledale iste svjetline, smislio sam sjajan trik.

Napisao sam neki procesni kod (na GitHub -u) koji fotografira sat i analizira svjetlinu svake LED -a redom. Zatim mijenja snagu svake LED diode kako bi pokušao postići da svi imaju istu svjetlinu kao i prigušena LED. Znam da je ovo pretjerano, ali obrada slika je jako zabavna! Nadam se da ću kalibracijski kôd razviti kao biblioteku.

Svjetlinu LED diode prije i poslije kalibracije možete vidjeti na gornjim fotografijama.

calibrateDispllay.pde

uvozprocesiranje.video.*;
importprocessing.serial.*;
Serijski myPort;
Snimanje videozapisa;
finalint numLed = 24;
int ledNum = 0;
// morate koristiti ove globalne varijable da biste koristili PxPGetPixelDark ()
int rDark, gDark, bDark, aDark;
int rLed, gLed, bLed, aLed;
int rOrg, gOrg, bOrg, aOrg;
int rTemp, gTemp, bTemp, aTemp;
PImage našu sliku;
int runNumber = 0;
int prihvatljivaError = 3;
int učinjeno;
int numPixelsInLed;
long ledIntensity;
int ledPower;
long targetIntensity = 99999999;
voidsetup () {
učinjeno = newint [numLed];
numPixelsInLed = newint [numLed];
ledIntensity = newlong [numLed];
ledPower = newint [numLed];
za (int i = 0; i <numLed; i ++) {
ledPower = 255;
}
printArray (Serial.list ());
Niz portName = Serial.list () [31];
myPort = newSerial (this, portName, 9600);
veličina (640, 480);
video = newCapture (ovo, širina, visina);
video.start ();
noStroke ();
glatko, nesmetano();
kašnjenje (1000); // Pričekajte da se serijski port otvori
}
voiddraw () {
if (video.available ()) {
if (učinjeno [ledNum] == 0) {
clearDisplay ();
kašnjenje (1000);
video.read ();
slika (video, 0, 0, širina, visina); // Nacrtajte video zapis web kamere na zaslon
saveFrame ("data/no_leds.jpg");
if (broj izvođenja! = 0) {
if ((ledIntensity [ledNum] - targetIntensity)*100/targetIntensity> prihvatljiva greška) {
ledPower [ledNum] -= pow (0.75, runNumber)*100+1;
}
if ((targetIntensity - ledIntensity [ledNum])*100/targetIntensity> prihvatljiva greška) {
ledPower [ledNum] += pow (0.75, runNumber)*100 +1;
}
if (abs (targetIntensity - ledIntensity [ledNum])*100/targetIntensity <= prihvatljiva greška) {
učinjeno [ledNum] = 1;
print ("Led");
ispis (ledNum);
print ("gotovo");
}
if (ledPower [ledNum]> 255) {
ledPower [ledNum] = 255;
}
if (ledPower [ledNum] <0) {
ledPower [ledNum] = 0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
kašnjenje (1000);
video.read ();
slika (video, 0, 0, širina, visina); // Nacrtajte video zapis web kamere na zaslon
kašnjenje (10);
while (myPort.available ()> 0) {
int inByte = myPort.read ();
// ispis (char (inByte));
}
Niz imageName = "podaci/";
imageName+= str (ledNum);
imageName += "_ led.jpg";
saveFrame (imageName);
String originalImageName = "podaci/organizacija";
originalImageName+= str (ledNum);
originalImageName += ". jpg";
if (broj izvođenja == 0) {
saveFrame (originalImageName);
}
PImage noLedImg = loadImage ("podaci/no_leds.jpg");
PImage ledImg = loadImage (imageName);
PImage originalImg = loadImage (originalImageName);
noLedImg.loadPixels ();
ledImg.loadPixels ();
originalImg.loadPixels ();
pozadina (0);
loadPixels ();
ledIntensity [ledNum] = 0;
numPixelsInLed [ledNum] = 0;
for (int x = 0; x <širina; x ++) {
for (int y = 0; y <visina; y ++) {
PxPGetPixelDark (x, y, noLedImg.piksela, širina);
PxPGetPixelLed (x, y, ledImg.pikseli, širina);
PxPGetPixelOrg (x, y, originalImg.piksela, širina);
ako ((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] ++;
} else {
rTemp = 0;
gTemp = 0;
bTemp = 0;
}
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, pikseli, širina);
}
}
ledIntensity [ledNum] /= numPixelsInLed [ledNum];
if (targetIntensity> ledIntensity [ledNum] && runNumber == 0) {
targetIntensity = ledIntensity [ledNum];
}
updatePixels ();
}
ispis (ledNum);
print (',');
ispis (ledPower [ledbroj]);
print (',');
println (ledIntensity [ledNum]);
ledNum ++;
if (ledNum == numLed) {
int donezo = 0;
za (int i = 0; i <numLed; i ++) {
donezo += učinjeno ;
}
if (donezo == numLed) {{100} {101}
println ("GOTOVO");
za (int i = 0; i <numLed; i ++) {
ispis (i);
print ("\ t");
println (ledPower );
}
print ("int level [");
ispis (ledNum);
print ("] = {");
za (int i = 0; i <numLed-1; i ++) {
ispis (ledPower );
print (',');
}
ispis (ledPower [broj -1]);
println ("};");
lightUpEven ();
while (istina);
}
print ("Intenzitet cilja:");
if (broj izvođenja == 0) {
targetIntensity -= 1;
}
println (targetIntensity);
ledNum = 0;
runNumber ++;
}
}
}
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // dobivanje boja kao int iz piksela
aOrg = (thisPixel >> 24) & 0xFF; // moramo se pomaknuti i maskirati da bismo dobili svaku komponentu zasebno
rOrg = (thisPixel >> 16) & 0xFF; // ovo je brže od pozivanja red (), green (), blue ()
gOrg = (thisPixel >> 8) & 0xFF;
bOrg = ovaj piksel & 0xFF;
}
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // dobivanje boja kao int iz piksela
aDark = (thisPixel >> 24) & 0xFF; // moramo se pomaknuti i maskirati da bismo dobili svaku komponentu zasebno
rDark = (thisPixel >> 16) & 0xFF; // ovo je brže od pozivanja red (), green (), blue ()
gDark = (thisPixel >> 8) & 0xFF;
bDark = thisPixel & 0xFF;
}
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelsWidth]; // dobivanje boja kao int iz piksela
aLed = (thisPixel >> 24) & 0xFF; // moramo se pomaknuti i maskirati da bismo dobili svaku komponentu zasebno
rLed = (thisPixel >> 16) & 0xFF; // ovo je brže od pozivanja red (), green (), blue ()
gLed = (thisPixel >> 8) & 0xFF;
bLed = thisPixel & 0xFF;
}
voidPxPSetPixel (intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) {
a = (a << 24);
r = r << 16; // Pakiramo sve 4 komponente u jedan int
g = g << 8; // pa ih moramo pomaknuti na njihova mjesta
boja argb = a | r | g | b; // binarna operacija "ili" dodaje ih sve u jedan int
pixelArray [x+y*pixelsWidth] = argb; // konačno postavljamo int sa te bojama u piksele
}

pogledajte rawcalibrateDispllay.pde hostirano sa ❤ od GitHub -a

11. korak: Napomene o rastanku

Zamke koje treba izbjegavati:

* Drvom dobivate ono što plaćate. Zato nabavite kvalitetno drvo. Šperploča od breze dobar je izbor; lijepo će poslužiti i svako svijetlo masivno drvo. Jeftinio sam na drvu i požalio sam zbog svoje odluke.

* Bolje je bušiti manje nego više. Nekoliko rupa otišlo je preduboko za moj komad. I epoksid se vidi kroz prednju stranu. Vrlo je uočljivo kad to primijetite.

* Koristite bušilicu s kugličnim vrhom umjesto ravnog kraja. Nisam eksperimentirao s završetkom loptice, ali prilično sam siguran da će rezultati biti puno bolji.

Koketiram s idejom da ih prodam na Etsyju ili tindieju. Bio bih vam zahvalan ako biste mogli komentirati ispod ako mislite da ima smisla:)

Preporučeni: