Obsah:

Dřevěné LED hodiny - analogový styl: 11 kroků (s obrázky)
Dřevěné LED hodiny - analogový styl: 11 kroků (s obrázky)

Video: Dřevěné LED hodiny - analogový styl: 11 kroků (s obrázky)

Video: Dřevěné LED hodiny - analogový styl: 11 kroků (s obrázky)
Video: IoT Arduino analógové vstupy a displeje 2024, Červenec
Anonim
Dřevěné LED hodiny - analogový styl
Dřevěné LED hodiny - analogový styl

Jedná se o analogové dřevěné LED hodiny. Nevím, proč jsem žádný takový neviděl … i když jsou digitální typy velmi běžné. Anyhoo, jdeme na to!

Krok 1:

obraz
obraz
obraz
obraz

Projekt překližkových hodin začal jako jednoduchý startovací projekt pro CNC router. Díval jsem se na jednoduché projekty online a našel jsem tuto lampu (obrázek výše). Také jsem viděl digitální hodiny, které prosvítají dřevěnou dýhou (obrázek výše). Spojení těchto dvou projektů bylo tedy zřejmým nápadem. Když jsem se chtěl vyzvat, rozhodl jsem se pro tento projekt nepoužívat dýhu, ale pouze kus dřeva.

Krok 2: Design

Design
Design
Design
Design

Hodiny jsem navrhl v Inkscape (obrázek výše). Design je podle výběru velmi jednoduchý. Rozhodl jsem se nepoužít trasování vodičů, protože v tomto bodě jsem si nebyl jistý, jestli chci jít s radiálním nebo obvodovým vedením. (Rozhodl jsem se konečně použít obvodové vedení.) Do každého z malých kruhových otvorů jde jeden neopixel, který ukazuje minutový a hodinový čas s pětiminutovou přesností. Kruh uprostřed bude vyveden ven, aby pojal elektroniku.

Krok 3: CNC

CNC
CNC
CNC
CNC
CNC
CNC
CNC
CNC

Navrhl jsem dráhy nástrojů na MasterCAM a pomocí technoRouteru vyfrézoval hodiny z 3/4 palcové překližky. K tomu používám kus 15 "x15" s minimálním plýtváním. Jde o to, vytěsnit co nejvíce dřeva, aniž byste prorazili dřevo. Ponechání 0,05 "-0,1" je dobrou volbou pro lehké dřevo. Pokud si nejste jisti, je lepší nechat v sobě více dřeva, protože druhou tvář můžete vždy obrousit. Nakonec jsem z některých částí odstranil příliš mnoho dřeva, ale naštěstí kvůli tomu výsledky příliš neutrpěly.

Poznámka pro uživatele bez přístupu k CNC:

Tento projekt lze snadno provést pomocí vrtačky. Stačí nastavit zarážku v místě, kde na základně zůstane asi 0,1 dřeva. Budete muset být přesní, ale ne příliš přesní. Koneckonců v ideálním případě nikdo neuvidí, že se všechny LED diody rozsvítily ve stejnou dobu, takže se můžete dostat pryč s malým nedbalostí.

Krok 4: Elektronika

Elektronika
Elektronika
Elektronika
Elektronika
Elektronika
Elektronika

Elektronika je poměrně jednoduchá. Existuje 24 neopixelů, dvanáct pro zobrazení hodin a dvanáct pro zobrazení minut s pětiminutovou přesností. Arduino pro mini ovládá neopixely a získává přesný čas pomocí modulu hodin reálného času (RTC) DS3231. Modul RTC má jako záložní knoflíkový článek, takže neztrácí čas ani při vypnutém napájení.

Materiál:

Arduino pro mini (nebo jiné Arduino)

Odlomená deska DS3231

Neopixely v jednotlivých breakout deskách

Krok 5: Sestavení elektroniky

Sestava elektroniky
Sestava elektroniky
Sestava elektroniky
Sestava elektroniky
Sestava elektroniky
Sestava elektroniky
Sestava elektroniky
Sestava elektroniky

Neopixely jsem připojil do řetězce pomocí prvních 2,5 vodičů pro prvních dvanáct LED a čtyřpalcových vodičů pro dalších dvanáct. Mohl jsem použít o něco menší délky vodičů. Po vytvoření řetězce jsem to vyzkoušel a ujistil se, že pájka klouby byly dobré. Přidal jsem chvilkový spínač, abych rozsvítil všechny LED diody, jen abych se předvedl.

Krok 6: běh na sucho

Suchý běh
Suchý běh
Suchý běh
Suchý běh
Suchý běh
Suchý běh
Suchý běh
Suchý běh

Po experimentování, vložení LED diod do otvorů a jejich rozsvícení jsem byl s výsledky spokojen. Přední čelo jsem tedy trochu obrousil a nanesl PU lak. Nakonec jsem kabát vybrousil později, ale je dobré to nechat, pokud vám to esteticky nevyhovuje.

Krok 7: Epoxid

Epoxid
Epoxid
Epoxid
Epoxid

Po několika testech s pozicí LED v otvorech jsem zjistil, že nejlepší diskuse je dosaženo, když jsou diody LED vzdáleny přibližně 0,2 od konce díry. Když to vyzkoušíte sami, jas LED bude velmi odlišný v každou díru. Nebojte se toho; opravíme to v kódu. Je to kvůli typu vrtáku, který jsem použil. Pokud bych to udělal znovu, použil bych pro otvory vrták s kuličkovým koncem Ale v každém případě, abych získal vzdálenost, namíchal jsem trochu epoxidu a do každé díry vložil trochu.

Krok 8: Dát to všechno dohromady

Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady
Dát to všechno dohromady

LED diody budou umístěny od polohy 12 hodinové ručičky pohybující se proti směru hodinových ručiček přes všechny pozice hodinové ručičky a poté do minutové ručičky, opět pohybující se od 60minutové značky pohybující se proti směru hodinových ručiček. Je tomu tak proto, že když se díváme zepředu, LED vzor vypadá ve směru hodinových ručiček.

Poté, co se epoxid hodinu vytvrdil, vložil jsem další epoxid. Tentokrát jsem umístil LED diody do otvorů a ujistil jsem se, že pokryjeme dráty a pájené spoje epoxidem. To zajišťuje dobrou difuzi světla a zajišťuje dráty.

Krok 9: Kód

Kód
Kód

Kód je na GitHubu, můžete jej upravit pro své použití. Když zapnete všechny LED diody na stejnou úroveň, jas světla, které prosvítá, bude v každém otvoru velmi odlišný. Je to kvůli různé tloušťce dřeva v otvorech a rozdílu ve stínu dřeva. Jak vidíte, barva dřeva se v mém kuse dost liší. Aby se tento rozdíl v jasu napravil, vytvořil jsem matici úrovní jasu LED. A snížil jas jasnějších LED diod. Je to proces pokusu a omylu a může trvat několik minut, ale výsledky stojí za to.

překližkaClock.ino

// Překližkové hodiny
// Autor: tinkrmind
// Attribution 4.0 International (CC BY 4.0). Můžete svobodně:
// Sdílet - zkopírujte a znovu distribuujte materiál v jakémkoli médiu nebo formátu
// Přizpůsobit - remixovat, transformovat a stavět na materiálu za jakýmkoli účelem, dokonce i komerčně.
// Hurá!
#zahrnout
#include "RTClib.h"
RTC_DS3231 rtc;
#include "Adafruit_NeoPixel.h"
#ifdef _AVR_
#zahrnout
#endif
#definePIN6
Proužek Adafruit_NeoPixel = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800);
int hodinaPixel = 0;
int minutePixel = 0;
unsignedlong lastRtcCheck;
Řetězec inputString = ""; // řetězec pro uložení příchozích dat
boolean stringComplete = false; // zda je řetězec úplný
int úroveň [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 (! Serial); // pro Leonardo/Micro/Zero
#endif
// Toto je pro Trinket 5V 16MHz, tyto tři řádky můžete odstranit, pokud nepoužíváte Trinket
#je -li definováno (_AVR_ATtiny85_)
if (F_CPU == 16000000) clock_prescale_set (clock_div_1);
#endif
// Speciální kód konce cetky
Serial.begin (9600);
strip.begin ();
strip.show (); // Inicializace všech pixelů na 'vypnuto'
if (! rtc.begin ()) {
Serial.println ("Nelze najít RTC");
zatímco (1);
}
pinMode (2, INPUT_PULLUP);
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_))));
if (rtc.lostPower ()) {
Serial.println („RTC ztratil výkon, nastavíme čas!“);
// následující řádek nastaví RTC na datum a čas, kdy byla tato skica sestavena
rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_))));
// Tento řádek nastaví RTC s explicitním datem a časem, například pro nastavení
// 21. ledna 2014 ve 3 hodiny ráno byste volali:
// 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 (':');
Serial.print (now.second (), DEC);
Serial.println ();
Zobrazit čas();
lastRtcCheck = milis ();
}
if (! digitalRead (2)) {
lightUpEven ();
}
if (stringComplete) {
Serial.println (inputString);
if (inputString [0] == 'l') {
Serial.println ("Úroveň");
lightUpEven ();
}
if (inputString [0] == 'c') {
Serial.println ("Zobrazování času");
Zobrazit čas();
strip.show ();
}
if (inputString [0] == '1') {
Serial.println („Zapnutí všech LED“);
lightUp (strip. Color (255, 255, 255));
strip.show ();
}
if (inputString [0] == '0') {
Serial.println ("Vymazávací proužek");
Průhledná();
strip.show ();
}
// #3, 255 by nastavilo číslo LED 3 na úroveň 255, 255, 255
if (inputString [0] == '#') {
Teplota řetězce;
temp = inputString.substring (1);
int pixNum = temp.toInt ();
temp = inputString.substring (inputString.indexOf (',') + 1);
int intenzita = temp.toInt ();
Serial.print ("Nastavení");
Serial.print (pixNum);
Serial.print ("na úroveň");
Serial.println (intenzita);
strip.setPixelColor (pixNum, strip. Color (intenzita, intenzita, intenzita));
strip.show ();
}
// #3, 255, 0, 125 by nastavilo LED číslo 3 na úroveň 255, 0, 125
if (inputString [0] == '$') {
Teplota řetězce;
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 ("Nastavení");
Serial.print (pixNum);
Serial.print („R to“);
Serial.print (rIntensity);
Serial.print („G to“);
Serial.print (gIntensity);
Serial.print („B to“);
Serial.println (hustota);
strip.setPixelColor (pixNum, strip. Color (rIntensity, gIntensity, bIntensity));
strip.show ();
}
if (inputString [0] == 's') {
Teplota řetězce;
int hodina, minuta;
temp = inputString.substring (1);
hodina = temp.toInt ();
int rIndex = inputString.indexOf (',') + 1;
temp = inputString.substring (rIndex);
minuta = temp.toInt ();
Serial.print ("Zobrazovaný čas:");
Serial.print (hodina);
Serial.print (":");
Serial.print (minuta);
showTime (hodina, minuta);
zpoždění (1000);
}
inputString = "";
stringComplete = false;
}
// zpoždění (1000);
}
voidserialEvent () {
while (Serial.available ()) {
char inChar = (char) Serial.read ();
inputString += inChar;
if (inChar == '\ n') {
stringComplete = true;
}
zpoždění (1);
}
}
voidclear () {
pro (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 = (now.minute () / 5) % 12 + 12;
Průhledná();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * úroveň [hourPixel], 30 + 30 * úroveň [hourPixel], 20 + 20 * úroveň [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * úroveň [minutePixel], 30 + 30 * úroveň [minutePixel], 20 + 20 * úroveň [minutePixel]));
strip.setPixelColor (hourPixel, strip. Color (úroveň [hourPixel], úroveň [hourPixel], úroveň [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (úroveň [minutePixel], úroveň [minutePixel], úroveň [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidshowTime (int hodina, int minuta) {
hourPixel = hodina % 12;
minutePixel = (minuta / 5) % 12 + 12;
Průhledná();
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * úroveň [hourPixel], 30 + 30 * úroveň [hourPixel], 20 + 20 * úroveň [hourPixel]));
// strip.setPixelColor (minutePixel, strip. Color (40 + 40 * úroveň [minutePixel], 30 + 30 * úroveň [minutePixel], 20 + 20 * úroveň [minutePixel]));
strip.setPixelColor (hourPixel, strip. Color (úroveň [hourPixel], úroveň [hourPixel], úroveň [hourPixel]));
strip.setPixelColor (minutePixel, strip. Color (úroveň [minutePixel], úroveň [minutePixel], úroveň [minutePixel]));
// lightUp (strip. Color (255, 255, 255));
strip.show ();
}
voidlightUp (barva uint32_t) {
pro (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, barva);
}
strip.show ();
}
voidlightUpEven () {
pro (uint16_t i = 0; i <strip.numPixels (); i ++) {
strip.setPixelColor (i, strip. Color (úroveň , úroveň , úroveň ));
}
strip.show ();
}

zobrazit rawplywoodClock.ino hostované s ❤ od GitHub

Krok 10: Počítačové vidění - kalibrace

Počítačové vidění - kalibrace
Počítačové vidění - kalibrace
Počítačové vidění - kalibrace
Počítačové vidění - kalibrace

Vědomě jsem se rozhodl v tomto projektu dýhu nepoužívat. Kdybych měl, tloušťka dřeva by byla před všemi LED diodami stejná. Ale protože mám před každou LED jinou tloušťku dřeva a protože se barva dřeva také hodně liší, jas LED je pro každou LED jiný. Aby se zdálo, že všechny LED diody mají stejný jas, vymyslel jsem šikovný trik.

Napsal jsem nějaký kód pro zpracování (na GitHub), který vyfotí hodiny a postupně analyzuje jas každé LED. Potom mění výkon každé LED, aby se pokusil, aby všechny měly stejný jas jako nejtmavší LED. Teď vím, že je to přehnané, ale zpracování obrazu je velká zábava! A doufám, že vyvinuli kalibrační kód jako knihovnu.

Jas LED před a po kalibraci můžete vidět na fotografiích výše.

calibrateDispllay.pde

importprocessing.video.*;
importprocessing.serial.*;
Sériový myPort;
Natočit video;
finalint numLed = 24;
int ledNum = 0;
// k použití PxPGetPixelDark () musíte mít tyto globální proměnné
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 přijatelná chyba = 3;
int hotovo;
int numPixelsInLed;
long ledIntensity;
int ledPower;
long 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 ());
Řetězec portName = Serial.list () [31];
myPort = newSerial (this, portName, 9600);
velikost (640, 480);
video = newCapture (toto, šířka, výška);
video.start ();
noStroke ();
hladký();
zpoždění (1000); // Počkejte, až se otevře sériový port
}
voiddraw () {
if (video.available ()) {
if (done [ledNum] == 0) {
clearDisplay ();
zpoždění (1000);
video.read ();
obrázek (video, 0, 0, šířka, výška); // Nakreslete video z webové kamery na obrazovku
saveFrame ("data/no_leds.jpg");
if (runNumber! = 0) {
if ((ledIntensity [ledNum] - targetIntensity)*100/targetIntensity> akceptovatelná chyba) {
ledPower [ledNum] -= pow (0,75, runNumber)*100+1;
}
if ((targetIntensity - ledIntensity [ledNum])*100/targetIntensity> přijatelná chyba) {
ledPower [ledNum] += pow (0,75, runNumber)*100 +1;
}
if (abs (targetIntensity - ledIntensity [ledNum])*100/targetIntensity <= přijatelná chyba) {
provedeno [ledNum] = 1;
tisk ("Led");
tisk (ledNum);
tisk („hotovo“);
}
if (ledPower [ledNum]> 255) {
ledPower [ledNum] = 255;
}
if (ledPower [ledNum] <0) {
ledPower [ledNum] = 0;
}
}
setLedPower (ledNum, ledPower [ledNum]);
zpoždění (1000);
video.read ();
obrázek (video, 0, 0, šířka, výška); // Nakreslete video z webové kamery na obrazovku
zpoždění (10);
while (myPort.available ()> 0) {
int inByte = myPort.read ();
// print (char (inByte));
}
Řetězec imageName = "data/";
imageName+= str (ledNum);
imageName += "_ led.jpg";
saveFrame (imageName);
Řetězec 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 ();
pozadí (0);
loadPixels ();
ledIntensity [ledNum] = 0;
numPixelsInLed [ledNum] = 0;
pro (int x = 0; x <šířka; x ++) {
pro (int y = 0; y <výška; y ++) {
PxPGetPixelDark (x, y, noLedImg.pixels, šířka);
PxPGetPixelLed (x, y, ledImg.pixels, šířka);
PxPGetPixelOrg (x, y, originalImg.pixels, šířka);
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] ++;
} else {
rTemp = 0;
gTemp = 0;
bTemp = 0;
}
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, pixelů, šířka);
}
}
ledIntensity [ledNum] /= numPixelsInLed [ledNum];
if (targetIntensity> ledIntensity [ledNum] && runNumber == 0) {
targetIntensity = ledIntensity [ledNum];
}
updatePixels ();
}
tisk (ledNum);
tisk(', ');
tisk (ledPower [ledNum]);
tisk(', ');
println (ledIntensity [ledNum]);
ledNum ++;
if (ledNum == numLed) {
int donezo = 0;
for (int i = 0; i <numLed; i ++) {
donezo += hotovo ;
}
if (donezo == numLed) {
println („HOTOVO“);
for (int i = 0; i <numLed; i ++) {
tisk (i);
tisk ("\ t");
println (ledPower );
}
print ("int level [");
tisk (ledNum);
tisk ("] = {");
pro (int i = 0; i <numLed-1; i ++) {
tisk (ledPower );
tisk(', ');
}
print (ledPower [numLed -1]);
println ("};");
lightUpEven ();
while (true);
}
tisk ("Cílová intenzita:");
if (runNumber == 0) {
targetIntensity -= 1;
}
println (targetIntensity);
ledNum = 0;
runNumber ++;
}
}
}
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelWidth]; // získání barev jako int z pixelů
aOrg = (thisPixel >> 24) & 0xFF; // musíme posunout a maskovat, abychom dostali každou komponentu samostatně
rOrg = (thisPixel >> 16) & 0xFF; // to je rychlejší než volání red (), green (), blue ()
gOrg = (thisPixel >> 8) & 0xFF;
bOrg = thisPixel & 0xFF;
}
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelWidth]; // získání barev jako int z pixelů
aDark = (thisPixel >> 24) & 0xFF; // musíme posunout a maskovat, abychom dostali každou komponentu samostatně
rDark = (thisPixel >> 16) & 0xFF; // to je rychlejší než volání red (), green (), blue ()
gDark = (thisPixel >> 8) & 0xFF;
bDark = thisPixel & 0xFF;
}
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) {
int thisPixel = pixelArray [x+y*pixelWidth]; // získání barev jako int z pixelů
aLed = (thisPixel >> 24) & 0xFF; // musíme posunout a maskovat, abychom dostali každou komponentu samostatně
rLed = (thisPixel >> 16) & 0xFF; // to je rychlejší než volání 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; // Balíme všechny 4 skladatele do jednoho int
g = g << 8; // tak je musíme přesunout na svá místa
barva argb = a | r | g | b; // binární operace "nebo" je všechny přidá do jednoho int
pixelArray [x+y*pixelWidth] = argb; // nakonec nastavíme int s te barvami do pixelů
}

zobrazit rawcalibrateDispllay.pde hostovaný s ❤ od GitHub

Krok 11: Poznámky k rozchodu

Úskalím, kterým je třeba se vyvarovat:

* Se dřevem získáte to, za co zaplatíte. Pořiďte si tedy kvalitní dřevo. Březová překližka je dobrá volba; každé lehké masivní dřevo bude také dobře fungovat. Vylezl jsem na dřevo a lituji svého rozhodnutí.

* Je lepší vrtat méně než více. Několik děr bylo pro můj kousek příliš hluboké. A epoxid se prosvítá na přední straně. Je to velmi nápadné, jakmile si toho všimnete.

* Místo přímého konce použijte vrták s kuličkovým koncem. Neexperimentoval jsem s koncovkou bitu, ale jsem si docela jistý, že výsledky budou mnohem lepší.

Koketuji s myšlenkou prodat je na Etsy nebo Tindie. Opravdu bych ocenil, kdybyste se mohli vyjádřit níže, pokud si myslíte, že to dává smysl:)

Doporučuje: