Spisu treści:

Zegar na mapie metra w Londynie: 9 kroków (ze zdjęciami)
Zegar na mapie metra w Londynie: 9 kroków (ze zdjęciami)

Wideo: Zegar na mapie metra w Londynie: 9 kroków (ze zdjęciami)

Wideo: Zegar na mapie metra w Londynie: 9 kroków (ze zdjęciami)
Wideo: Doda i jej miny podczas przemówienia Górniak (oryg. cezarywisniewski_) 2024, Listopad
Anonim
Zegar na mapie metra w Londynie
Zegar na mapie metra w Londynie
Zegar na mapie metra w Londynie
Zegar na mapie metra w Londynie

W 2014 roku, po stażu w firmie doradczej zajmującej się drukowaniem 3D w Londynie i eksperymencie z kolorowymi litofanami przy użyciu ich maszyny Stratasys, zaprojektowałem własny prezent wyjazdowy, kolorowy wydruk 3D linii rur w ich biurach. Byłem zdeterminowany, żeby coś z tego zrobić. Niedługo 2 lata później, w 2016 roku, miałem własną drukarkę 3D i zabrałem się do robienia z niej zegara.

Jako dziecko myślałem, że cyfrowe zegarki Tokyo Flash były najwspanialszymi rzeczami w historii i odmrożone, które byłyby punktem inspiracji dla projektu.

A teraz to była tylko niewielka 4-letnia przerwa, zanim zabrałem się do pisania!

Chociaż dokładne instrukcje będą trudne do odtworzenia, a obniżenie kosztów produkcji PCB przez hobbystów w ciągu ostatnich kilku lat może sprawić, że moja dokładna metoda rozmieszczenia diod LED stanie się przestarzała. Mam nadzieję, że wspólne pomysły mogą sprawić, że inni zrobią dziwne zegary z cienkich przedmiotów!

Krok 1: Przednia warstwa

Przednia warstwa
Przednia warstwa
Przednia warstwa
Przednia warstwa
Przednia warstwa
Przednia warstwa

Jak wspomniano we wstępie, był to kolorowy druk 3D, wydaje mi się, że maszyna Stratasys używała łoża proszkowego i zmodyfikowanego wkładu atramentowego do spoiwa i pigmentu.

Plik ginie w historii, ale ta warstwa może być cokolwiek, zdjęcie lub jednokolorowa litofan zdziałałyby cuda.

Ta część została wykonana w 3DS max w 2014 roku, ale dziś istnieją narzędzia online do przekształcania obrazu w SLT w oparciu o jasność

Krok 2: Projektowanie warstwy pomocniczej

Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika
Projektowanie warstwy przewodnika

To tutaj decydujemy o złożoności projektu i sposobie odczytywania czasu. Obrazy pokazują 2 pomysły, z którymi się bawiłem.

Zostały one wykonane przez skanowanie projektu i rysowanie linii w inkscape.

Nie jest to zbyt czytelny zegar, ale wolałem pomysł wypełniania linii przez cały dzień, więc stało się to celem projektu.

Liczenie binarne jest realną metodą zmniejszenia liczby diod LED i poprawiłoby czytelność, jeśli binarny jest twoim zacięciem, ale to podważyło mój pomysł na „linie wypełniające”, więc nie było opcji dla tego projektu

W zegarkach Tokyo Flash zwykle minimalizuje się liczbę diod LED, ale mając jedną sekcję liczącą się w 3 lub 5, a następnie kolejne wypełnienie za każdym razem, gdy ta sekcja zostanie wypełniona, użyłem tej techniki przez minuty, aby zmniejszyć je z 60 do 20 plus 2. przez kilka sekund nie martwił się tak bardzo o precyzję.

Krok 3: Budowanie warstwy przewodnika

Budowanie warstwy przewodnika
Budowanie warstwy przewodnika
Budowanie warstwy przewodnika
Budowanie warstwy przewodnika
Budowanie warstwy przewodnika
Budowanie warstwy przewodnika

Ta warstwa prowadząca dla diod LED ma 2 cele, utrzymuje diody LED na miejscu i zapobiega rozlewaniu się między nimi

Został narysowany jako warstwa w Inkscape bezpośrednio nad skanem, którego używałem do projektowania układu. Przed wysłaniem do mojej drukarki w blenderze dodano 1 mm grubości.

To był jeden z najtrudniejszych wydruków, jakie muszę wykonać na moim skromnym Makibox A6, część została wydrukowana w abs, więc użyto tony zawiesiny acetonu, aby utrzymać ją przyłączoną do platformy roboczej z minimalnym wypaczeniem. Na szczęście ta część nie jest widoczna na produkcie końcowym

Ostateczny obraz pokazuje, że trzymany jest przy lampie, aby sprawdzić odstępy.

Z perspektywy czasu rozlanie między światłami wzdłuż linii może być w rzeczywistości lepsze dla efektów wizualnych, nie jest trudniejsze do odczytania, można to osiągnąć poprzez dodanie fazki do prowadnicy na krótszych bokach każdego światła

Krok 4: Okablowanie diod LED

Okablowanie diod LED
Okablowanie diod LED
Okablowanie diod LED
Okablowanie diod LED
Okablowanie diod LED
Okablowanie diod LED

Pierwszy obraz przedstawia wydruk testowy, który wykonałem w celu sprawdzenia rozmiaru otworu. Chciałem, aby dioda LED ściśle przylegała do koronki z niewielką siłą, a następnie podczas układania warstwy prowadzącej ręcznie ułożono prawidłowy kształt.

Ze względu na niską tolerancję mojej drukarki 3D, niektóre były luźne i wymagały odrobiny superkleju, aby pozostać na miejscu, podczas gdy inne były zbyt ciasne, ale zachęcano ich do umieszczenia na miejscu poprzez naciśnięcie diody LED podczas lutowania, było to właściwie lepsze dopasowanie niż otwór o odpowiedniej wielkości, który miał dzierżawę do wyciągnięcia po podłączeniu.

Aby zmniejszyć ilość drutów diody LED zostały wlutowane w matrycę 7 na 8, co oznacza, że wszystkie 55 diod LED można było sterować tylko 13 pinami, miałem ręcznie narysowaną mapę każdego z tych połączeń, która niestety została utracona.

Użyto drutu emaliowanego, aby sekcje można było odsłonić na miejscu przez podgrzanie sekcji żelazkiem i cynowanie przed wykonaniem połączenia.

Ten proces był bardzo czasochłonny, gorąco polecam zaprojektowanie płytki drukowanej

Krok 5: Projektowanie elektroniki

Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki
Projektowanie elektroniki

Moim początkowym planem było użycie mikrokontrolera Arduino z zegarem czasu rzeczywistego, ale zdecydowałem się na ESP8266 na płycie Node MCU D1, ponieważ pozwalało to na automatyczne oszczędzanie światła dziennego i możliwość kontroli nad WIFI.

Aby jeszcze bardziej zredukować liczbę pinów, miałem idealną liczbę diod LED, aby móc użyć MAX7219 (który może obsłużyć do 64 diod LED).

Ten układ scalony jest powszechnie używany do sterowania 7-segmentowymi wyświetlaczami LED, ale miał bardzo podobny przypadek użycia do mojego, oświetlając dowolną liczbę diod LED z minimalnym migotaniem, a nawet ma regulowaną jasność.

Zdecydowałem się użyć płyty prototypowej do okablowania, ale eagle był pomocny w umieszczeniu części i zrozumieniu okablowania

Załączyłem pliki planszy, ale to był mój pierwszy raz, kiedy używałem eagle (i nieaktualna wersja do tej pory), więc są tylko w celach informacyjnych

Krok 6: Okablowanie elektroniki

Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki
Okablowanie elektroniki

Był to powtarzalny, prosty krok, zgodnie ze schematem Eagle, użycie nagłówków dla ESP i matrycy LED ogromnie pomogło w montażu.

Pin 1 na głowicach LED Anode i Cathode został oznaczony srebrnym sharpie, można je rozróżnić, tak jak na 7 pozostałych 8.

Krok 7: Programowanie

Programowanie
Programowanie

Ponieważ nasz wyświetlacz nie jest tradycyjną matrycą, musiałem znaleźć sposób na wizualizację, które bity włączyć, które wysłał do MAX IC w HEX. Na szczęście znam wystarczająco dużo excela, aby wpaść w kłopoty i stworzyłem „czarodzieja szesnastków”, który poprowadził mnie przez wzór, który chciałem wyświetlić, ręcznie umieszczane pola wyboru i wszystko.

Przyszło to wraz z przewartościowaniem, że hex dla mojej godziny, minuty i sekund można połączyć za pomocą bitowego OR, aby utworzyć ostateczne polecenie hex do wysłania do max7219, w tym małą animację, którą dodałem do sekund, abym mógł upewnić się, że tablica nie zamarzł.

A więc prawie na końcu. i czas na kolejną decyzję, która nie postarzała się zbyt dobrze.

Kod dla ESP jest w LUA. Dzisiaj polecam używanie arduino IDE ze względu na lepszą dokumentację i solidną bibliotekę pakietów, w tym czasie społeczność ESP wciąż dojrzewała i wybrałem LUA jako język dla tego projektu.

Podjąłem wątpliwą decyzję, aby regularnie pingować serwery Google, aby odczytać godzinę. To ominęło potrzebę RTC, aby zminimalizować dryf, to działa, ale lepiej byłoby użyć API czasu rzeczywistego.

halfSec = 0godzina=0 minuta=0 sekunda=0

niska intensywność = 0

wysoka intensywność = 9

lokalny identyfikator SSID ="Wi-Fi"

lokalne SSID_PASSWORD ="Hasło"

funkcja time() -- połącz się z internetem, aby uzyskać aktualną godzinę i datę

jeśli wifi.sta.getip() to local conn=net.createConnection(net. TCP, 0) conn:connect(80, "google.com")

conn:on("połączenie", function(conn, payload) conn:send("HEAD / HTTP/1.1\r\n".. "Host: time.is\r\n".. "Accept: */*\r\n".. " User-Agent: Mozilla/4.0 (kompatybilny; esp8266 Lua;)".. Koniec "\r\n\r\n"))

conn:on("odbierz", function(conn, payload) --print(payload) conn:close() local p=string.find(payload, "GMT") -- znajdź ciąg czasu i daty w ładunku z Internetu, zmień na strefę czasową, jeśli p~ =nil then -- wyodrębnij liczby odpowiadające godzinie, minucie, sekundzie, dniu, miesiącowi hour=tonumber(string.sub(payload, p-9, p-8)) minute=tonumber(string.sub(payload, p- 6, p-5)) sekunda=tonumber(string.sub(payload, p-3, p-2)) addHour() --kodowany na stałe BST (czas letni brytyjski) oszczędzanie światła dziennego print(godzina, minuta, sekunda) halfSec = (second%6)*2 --print(halfSec) else print("aktualizacja sieciowa nie powiodła się!") end end --function) --end of on obsługi zdarzenia "odbierz"

conn:on("rozłączenie", function(conn, payload) conn=nil payload=nil end) end print("jeszcze nie ma wifi") end

function borTable(a, b, …) --bitowe OR tabele razem

if arg[1] then b = borTable(b, unpack(arg)) end local z = {} for i, v in ipairs(a) do table.insert(z, bit.bor(v, b)) koniec powrót z koniec

function bxorTable(a, b, …) --bitowe OR tabele razem

if arg[1] then b = bxorTable(b, unpack(arg)) end local z = {} for i, v in ipairs(a) do table.insert(z, bit.bxor(v, b)) koniec powrót z koniec

funkcja addSecond()

sekunda=sekunda+1 jeśli sekunda>=60 to sekunda=0 minuta=minuta+1 jeśli minuta>=60 to minuta=0 addHour() end end end

funkcja dodajGodzinę()

hour=hour+1 if hour>=24 then hour=0 end if hour == 2 or hour == 16 then max7219.setIntensity(lowIntensity) end if hour == 8 or hour == 18 then max7219.setIntensity(highIntensity) end end funkcja update() lokalna secGap = 6 lokalna minGap = 3 lokalna horGap = 1 lokalna sec={ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x03}, { 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x03}, {0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x01, 0x03}, { 0x00, 0x00, 0x01, 0x01, 0x01, 0x03, 0x01, 0x03}, { 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x03 }, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x03} }; lokalne min={ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00}, { 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00}, { 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00}, { 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00}, { 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00}, { 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x10}, { 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x12, 0x10}, { 0x02, 0x02, 0x02, 0x02, 0x02, 0x10, 0x12, 0x10}, { 0x02, 0x02, 0x02, 0x02, 0x12, 0x10, 0x12, 0x10 }, { 0x02, 0x02, 0x02, 0x12, 0x12, 0x10, 0x12, 0x10}, { 0x02, 0x02, 0x12, 0x12, 0x12, 0x10, 0x12, 0x10}, { 0x02, 0x12, 0x12, 0x12, 0x12, 0x10, 0x12, 0x10}, {0x12, 0x12, 0x12, 0x12, 0x12, 0x10, 0x12, 0x10}, {0x12, 0x12, 0x12, 0x12, 0x12, 0x30, 0x12, 0x10}, {0x12, 0x12, 0x12, 0x12, 0x32, 0x30, 0x12, 0x10}, {0x12, 0x12, 0x12, 0x32, 0x32, 0x30, 0x12, 0x10}, {0x12, 0x12, 0x32, 0x32, 0x32, 0x30, 0x12, 0x10}, { 0x12, 0x32, 0x32, 0x32, 0x32, 0x30, 0x12, 0x10}, { 0x32, 0x32, 0x32, 0x32, 0x32, 0x30, 0x12, 0x10} }; lokalny poziom = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00}, { 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00}, { 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08}, { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0C, 0x08}, { 0x04, 0x04, 0x04, 0x04, 0x04, 0x0C, 0x08x0C }, { 0x04, 0x04, 0x04, 0x04, 0x0C, 0x0C, 0x0C, 0x08}, { 0x04, 0x04, 0x04, 0x0C, 0x0C, 0x0C, 0x0C, 0x08}, { 0x04, 0x04, 0x0C, 0x0C, 0C, 0x0C, 0x08}, { 0x04, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08}, { 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08}, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x48}, { 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x4C, 0x48}, { 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x4, 0x0x4}, 0x0C, 0x0C, 0x4C, 0x4C, 0x4C, 0x48}, { 0x0C, 0x0C, 0x0C, 0x4C, 0x4C, 0x4C, 0x4C, 0x48}, { 0x0C, 0x0C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x48}, { 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x48} }; --print(godzina, minuta, sekunda)

--tabela zaczyna się od 0, więc od 1, ponieważ obecnie sec[0] = zero)

max7219.write({animate(borTable(s[1+(sekunda/sek.przerwy)], min[1+(minuta/min.przerwy)], hor[1+(godzina/horGap)]))})

koniec --funkcja

wifi.setmode(wifi. STACJA)

wifi.sta.config(SSID, SSID_PASSWORD) wifi.sta.autoconnect(1)

--skonfiguruj max7219

max7219 = require("max7219") max7219.setup({numberOfModules = 1, slaveSelectPin = 8, intensywność = highIntensity })

--Główny program

checkOnline = tmr.create()

alarm.tmr(0, 180000, 1, czas)

tmr.alarm(1, 1000, 1, dod.druga)

tmr.alarm(2, 500, 1, aktualizacja)

animacja funkcji (wciąż)

ramki lokalne = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; halfSec=halfSec+1 jeśli halfSec >=12 to halfSec = 0 end --print(halfSec) return bxorTable(frames[halfSec+1], still) end

Krok 8: Obudowa

Obudowa
Obudowa
Obudowa
Obudowa
Obudowa
Obudowa

Teraz nadszedł czas, aby pochwalić się niesamowitym kunsztem i umieścić projekt.

Albo weź paczkę Amazon z recyklingu i zbuduj tymczasową obudowę, która nadal jest w użyciu.

Zaletą takiego podejścia było to, że każda warstwa projektu prawie idealnie pasowała do grubości tektury, dzięki czemu kanapkę można było ułożyć w stos i skleić razem. Podobna wersja premium może używać akrylu

Krok 9: Uwagi końcowe

Dziękuję za przeczytanie. Jak wielu z was wie, dokumentowanie projektu może być równie trudne, jak jego wykonanie. są skrawki wideo, na których rozmawiam, które mogą w końcu ujrzeć światło dzienne.

W latach między stworzeniem tego projektu a jego napisaniem spodziewałem się zobaczyć więcej przykładów dowolnych wyświetlaczy LED wykorzystujących druk 3D, ale redukcja pasków RGB w większości wyeliminowała potrzebę alternatywy.

Mam nadzieję, że było to pouczające i proszę zadawać pytania, ponieważ postaram się podać więcej szczegółów w sekcjach, które nie są w pełni satysfakcjonujące.

Pozdrawiam

Zalecana: