Cześć!
Przyszedł grudzień więc postanowiłem wykonać jakieś ozdoby na choinkę wykorzystując druk 3d, a jak już się bawić to czemu nie zrobić świecącego łańcucha bombek z wyciętym regionalnym wzorem, po ich skończeniu stwierdziłem że gwiazda połączona z łańcuchem to bardzo dobry pomysł.
Zamów płytkę drukowaną na www.pcbway.com
Wykonanie projektu okazało się bardzo czasochłonne stąd artykuł dopiero teraz.
Spis treści:
- Diody Neopixel
- Projekt elektroniki
- Projekt obiektów bryłowych (SolidWorks)
- Montaż łańcucha
- Oprogramowanie
- Podsumowanie
1.Diody Neopixel
Z poprzednich projektów zostało mi kilka diod smd 5050 neopixel (ws2812b), diody posiadają wbudowany sterownik dzięki któremu ograniczamy ilość przewodów do 3: zsilanie, gnd, data. Diody wymagają napięcia 3.5 – 5 [V].
Opis wyprowadzeń:
- VDD – Zasilanie diody
- DOUT – Wyjście sygnału data
- VSS – GND
- DIN – Wejście sygnału data
Cztery wyprowadzenia a mówiłem o trzech przewodach, tak diody połączone są szeregowo wyjście danych z pierwszej należy połączyć z wejściem drugiej diody.
Z rzeczy istotnych zasilanie każdej z diod warto filtrować kondensatorem 100 [nF], a wejście danych pierwszej diody podłączyć przez rezystor 300 – 500 [ohm].
2.Projekt elektroniki
W ramach projektu powstało kilka płytek które kolejno opiszę, a za komunikację odpowiada arduino nano, całość zasilana jest z zasilacza 5v 2A.
Projekt płytek został wykonany w programie Eagle, pierwsza z nich nie będzie zbytnio skomplikowana, by ułatwić przyklejenie płytki do plastiku, i uprościć nieco proces wykonania postanowiłem ograniczyć się do płytek jednostronnych, tak więc pierwsza jest jedynie przejściówką z smd na przewody a ogromne pady pozwalają na przylutowanie kondensatora filtrującego.
Płytki wytrawiam w nadsiarczanie sodu z użyciem domowej roboty wytrawiarki mikroprocesorowej.
Lutując diody starałem się użyć minimalnej ilości ciepła i spoiwa by nie przegrzać wrażliwych układów wewnątrz diody, stąd połączenia nie wyglądają najładniej…
Po przygotowaniu diod do projektu dołączyła jeszcze jedna płytka rozszerzająca arduino o 2 dodatkowe przełączniki podłączone do pinów zapewniających przerwania i diodę led. Rezystor R1 dobieramy w zależności od koloru diody, w moim przypadku czerwona więc jego wartość musi być większa lub równa 190 [OHM], natomiast Kondensatory C1 i C2 pełnią rolę filtru minimalizującego wpływ drgań styków jakie występują przy zmianie stanu przełącznika, ja dobrałem 100 [nF].
Jeśli chodzi o arduino to do pinu 11 przylutowałem rezystor a następnie przewód biegnący do pierwszej diody, do pinów gnd i 5V zasilacz 2A, a oznaczone poniżej piny PCB odpowiadają płytce rozszerzeń wykonanej wcześniej.
3.Projekt obiektów bryłowych (SolidWorks)
Postaram się omówić wszystkie bryły, oraz przedstawić funkcje których nie opisywałem jeszcze w swoich artykułach.
3.1. Korpus obudowy arduino
Na początku obudowa elektroniki sterującej, nie ma tutaj nic skomplikowanego przewidziałem miejsce na poskładany już układ i wystające elementy, myślę że po przeczytaniu moich wcześniejszych poradników każdy poradzi sobie z jej zaprojektowaniem. Poniżej grafiki przedstawiające bryłę.
3.2. Zaślepka obudowy arduino
Do obudowy potrzebna była zaślepka, tutaj warto wspomnieć o przydatnej funkcji: połącz elementy, poniżej przedstawiam samą zaślepkę, a następnie przedstawię działanie funkcji.
3.3. Operacja łączenia brył
Powiedzmy że chcemy zrobić sześcian z zazębiającą się jedną ścianą, najpierw narysujmy korpus
Podetnijmy nasz element w wybrany sposób by zrobić miejsce na zazębienie się ściany
Utwórzmy nową bryłę odpowiadającą interesującej nas ścianie a jej grubość powiększmy o głębokość zazębienia
Korzystając z menu wstaw wybierzmy część, a następnie wskażmy korpus naszego elementu
Upuśćmy korpus w wygodnym dla nas miejscu a następnie korzystając z otwartego już narzędzia lokalizowania części, ustawmy wiązania tak by nowa ściana znalazła się w odpowiednim miejscu, tak by elementy nakładały się na siebie.
Przejdźmy teraz do operacji połącz znajdującej się w menu Wstaw->Operacje.
Typ operacji ustawiamy na Odejmij następnie wskazujemy główny obiekt czyli naszą ścianę oraz obiekt którym będziemy odcinać, za pomocą funkcji pokaż podgląd możemy sprawdzić jaki będzie efekt operacji.
Zatwierdzamy i w zasadzie to wszystko, możemy ewentualnie wyciąć zbędną wewnętrzną powierzchnię by uzyskać sześcian wewnątrz
Poniżej widzimy nasz element w przekroju w tym przykładzie kształt jest na tyle prosty, że ta metoda może wydawać się bez sensu ale dla bardzo skomplikowanych brył często nie ma innego sposobu na bezbłędne odcięcie.
3.4. Bombka choinkowa
Bombka powstaje z dwóch połówek przy czym druga powstała w wyniku wykorzystania operacji połącz elementy. Na początku wykonałem kulę, obciąłem połowę i wyciąłem część przeznaczoną na wzór, następnie utworzyłem skorupę i po przeniesieniu wzoru z pliku png wyciąłem odpowiedni otwór, a poprzez odsunięcie szkicu uzyskałem obrys wzmacniający konstrukcję. Na końcu dodałem miejsce na mocowanie diody led i samej bombki do drzewka gdyby było to konieczne, w kolejnym kroku opiszę jak stworzyć szkic z pliku png.
3.5. Tworzenie szkicu z obrazu png
Można by zastosować dodatek śledzenia, jednakże zapewne nie każdy ma do niego dostęp, więc pokażę wam inną metodę, najpierw musimy przerobić nasz obraz, użyję do tego celu programu gimp.
Po otwarciu naszego obrazu utwórzmy nowy o tych samych wymiarach z podstawowymi parametrami, następnie skopiujmy nasz obraz do nowego na białym tle.
Teraz przejdźmy do progowania obrazu gdyż potrzebujemy wyodrębnić kontury.
Określmy wartość przy której wszystko co nas interesuje zostanie na obrazie.
Następnie wyeksportujmy nasz obraz do pliku png.
W kolejnym kroku nasz obraz png należy przekształcić do pliku dxf używając dowolnego darmowego konwertera, nie chcę promować żadnej strony a jest to operacja na tyle prosta że raczej każdy sobie z tym poradzi. Po pobraniu pliku przechodzimy do solida.
Zakładam że mamy już jakąś bryłę, wskażmy ścianę na której chcemy utworzyć szkic i przejdźmy do menu wstaw->DXF/DWG…
Szybki import pliku, poniżej screeny z mojej konfiguracji.
I efekt jaki uzyskamy będzie odbiegał od oczekiwanego, normalne… teraz należy przeskalować nasz szkic.
Użyjemy operacji Skaluj elementy.
Wskażmy punkt względem którego chcemy skalować, zaznaczmy cały szkic i eksperymentalnie zmieniajmy wartość by wynik był satysfakcjonujący.
Po wszystkim szkicu możemy użyć na przykład do wycięcia.
Zdaję sobie sprawę że nie jest to metoda najprostsza i najlepsza, ale dostęp do niej będzie miał każdy a pozostałe metody są doskonale opisane w różnych źródłach.
3.6. Uchwyt mocujący diodę led i bombkę
Tutaj obyło się już bez niespodzianek, przewidziałem miejsce na przewody kołnierz by uchwyt nie wypadał i ucho do zawieszenie bombki, chociaż raczej wystarczy sam przewód do jej utrzymania.
3.7. Gwiazda
Na pomysł dodania gwiazdy wpadłem po odnalezieniu przypadkowego modelu w internecie, miejscami nie obyło się bez modyfikacji, pliki autora i te moje zmodyfikowane udostępniam a link do projektu to:
https://www.thingiverse.com/thing:661306
4.Montaż łańcucha
Łańcuch składa się z 22 bombek, gwiazdy i elektroniki, elementy plastikowe wykonałem na Drukarce Creality CR-10
- korpusy bombek powstały z białego PLA,
- mocowania biały ABS,
- Obudowa elektroniki czarne PLA,
- Gwiazda transparentny PET-G
Parametry druku różniły się diametralnie w zależności zarówno od materiału jak i kształtu czy też rozmiaru drukowanego elementu, więc pozwolicie że oszczędzę wam szczegółów na ten temat.
Przygotowane wcześniej diody przykleiłem używając kropelki do mocowań.
Następnie poskładałem w całość kolejno bombki łącząc je tak jak to opisałem schematem na samym początku artykułu, do wzmocnienia łączeń posłużyłem się kropelką. Odległość między bombkami na jaką się zdecydowałem to około [40 cm], dało to łańcuch o łącznej długości przekraczającej 9 [m].
Połączenia elektroniki sterującej już opisałem, przedstawiam więc jedynie sposób zabudowania całości, poniżej wklejam zdjęcia z montażu, do wzmocnienia połączeń ponownie posłużyłem się klejem. Czarne PLA nie do końca spełnia moje oczekiwania w przyszłości ten element wydrukuję ponownie.
Jeśli chodzi o gwiazdę to wewnątrz umieściłem 8 diod, wszystko posklejałem by nie rozpadło się jednak na choince i wyprowadziłem przewód z wtyczką pozwalającym na łatwiejsze przechowywanie zestawu.
5.Oprogramowanie
Całość została napisana w Arduino IDE, z wykorzystaniem biblioteki Adafruit_NeoPixel jak również standardowych bibliotek znajdujących się już w IDE. Kod w całości dostępny w paczce zip pod projektem, tutaj wstawię fragmenty gdyż ułatwi to opis całości.
Na początku standardowo dołączamy biblioteki, zdecydowałem się na zastosowanie eepromu do przechowywania ustawień w razie zaniku zasilania, LedDiodePin wskazuje diodę informującą o naciśnięciu przycisku a LedBlinkInterval określa jak długi jest czas świecenia diody. LedStripPin wskazuje na nasz łańcuch diod led. Dalej widzimy zmienne których będę używał do konfiguracji sposobu działania programu, oraz standardową linijkę bibloteki NeoPixel inicjującą łańcuch o długości 30 diod.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <Adafruit_NeoPixel.h> #include <EEPROM.h> #define LedDiodePin 4 #define LedStripPin 11 #define LedBlinkInterval 500 #define ButtonAPin 2 #define ButtonBPin 3 byte Jasnosc = 255; int Opoznienie = 50; //EEPROM - 0; byte WybranyTryb = 3; //EEPROM - 2; byte WybranyKolor = 4; //EEPROM - 4; bool Przerwanie = true; unsigned long Millis = 0; Adafruit_NeoPixel Led = Adafruit_NeoPixel(30, LedStripPin, NEO_GRB + NEO_KHZ800); |
W dalszej części widzimy funkcję uruchamianą przy pojawieniu się zasilania, a w niej na początku sprawdzenie czy w wartościach eeprom jest już coś zapisane jeśli tak to wczytanie tych danych, konfiguracja pinów, ustawienie anteny dla true randoma i dopięcie przerwań do przycisków.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void setup() { if(EEPROM.read(0)!=255) Opoznienie = EEPROM.read(0); if(EEPROM.read(2)!=255) WybranyTryb = EEPROM.read(2); if(EEPROM.read(4)!=255) WybranyKolor = EEPROM.read(4); pinMode(LedDiodePin, OUTPUT); randomSeed(analogRead(0)); Led.begin(); Led.show(); pinMode(ButtonAPin, INPUT_PULLUP); pinMode(ButtonBPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(ButtonAPin), ButtonA, FALLING); attachInterrupt(digitalPinToInterrupt(ButtonBPin), ButtonB, FALLING); } |
Pętla główna programu przenosi nas do wybranej funkcji w zależności od trybu w razie potrzeby dezaktywuje zmienna przerwanie i diodę powiadomień.
1 2 3 4 5 6 7 8 9 10 11 12 |
void loop() { if(WybranyTryb == 1) wolnePrzejscia(); else if (WybranyTryb == 2) tecza(); else if (WybranyTryb == 3) pelnyKolor(); else if (WybranyTryb == 4) losoweKoloryDiod(); else if (WybranyTryb == 5) losoweKoloryPaska(); if((millis()-Millis) >= LedBlinkInterval) { digitalWrite(LedDiodePin, LOW); Przerwanie = false; } } |
Przerwanie od przycisku A aktywuje się przy zboczu opadającym, a pierwszy warunek sprawdza czy dioda już zgasła i wprowadza opóźnienie dzięki któremu zapobiegamy przypadkowym naciśnięciom oraz minimalizujemy wpływ drgań styków. Zadaniem tego przycisku jest zmiana trybu pracy układu, a następnie zapisanie konfiguracji do eepromu.
1 2 3 4 5 6 7 8 9 10 |
void ButtonA() { if(Przerwanie == false) { Przerwanie = true; digitalWrite(LedDiodePin, HIGH); Millis = millis(); WybranyTryb++; if(WybranyTryb >= 6) WybranyTryb = 1; EEPROM.write(2, WybranyTryb); } } |
Przerwanie przycisku B, jeśli tryb pozwala na zmianę koloru to przycisk zmieni kolor w przeciwnym wypadku przycisk odpowiada za zmianę prędkości animacji.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void ButtonB() { if(Przerwanie == false) { Przerwanie = true; digitalWrite(LedDiodePin, HIGH); Millis = millis(); if(WybranyTryb == 3){ WybranyKolor++; if(WybranyKolor >= 8) WybranyKolor = 1; EEPROM.write(4, WybranyKolor); } else{ if(Opoznienie==200)Opoznienie=10; else if(Opoznienie==100)Opoznienie=200; else if(Opoznienie==50)Opoznienie=100; else if(Opoznienie==25)Opoznienie=50; else Opoznienie=25; EEPROM.write(0, Opoznienie); } } } |
Pierwsza z animacji, funkcja ta przewija kolory po całym pasku z określonym opóźnieniem.
1 2 3 4 5 6 7 8 9 10 11 |
void wolnePrzejscia() { colorWipe(Led.Color(Jasnosc, 0, 0), Opoznienie); colorWipe(Led.Color(Jasnosc, Jasnosc, 0), Opoznienie); colorWipe(Led.Color(Jasnosc, Jasnosc, Jasnosc), Opoznienie); colorWipe(Led.Color(0, Jasnosc, 0), Opoznienie); colorWipe(Led.Color(0, Jasnosc, Jasnosc), Opoznienie); colorWipe(Led.Color(Jasnosc, Jasnosc, Jasnosc), Opoznienie); colorWipe(Led.Color(0, 0, Jasnosc), Opoznienie); colorWipe(Led.Color(Jasnosc, 0, Jasnosc), Opoznienie); colorWipe(Led.Color(Jasnosc, Jasnosc, Jasnosc), Opoznienie); } |
Funkcja tęczy jest zaciągnięta z przykładu znajdującego się w bibliotece jej zadaniem jest płynne przejście po kolorach na długości łańcucha.
1 2 3 4 5 6 7 8 9 10 11 |
void tecza() { uint16_t i, j; for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel for(i=0; i< Led.numPixels(); i++) { Led.setPixelColor(i, Wheel(((i * 256 / Led.numPixels()) + j) & 255)); } Led.show(); if(!Przerwanie) delay(Opoznienie); } } |
Funkcja pełnego koloru ustawia cały pasek w określony kolor niezmienny w czasie
1 2 3 4 5 6 7 8 9 10 11 |
void pelnyKolor() { uint32_t c; if (WybranyKolor == 1) c = Led.Color(Jasnosc, 0, 0); else if (WybranyKolor == 2) c = Led.Color(0, Jasnosc, 0); else if (WybranyKolor == 3) c = Led.Color(0, 0, Jasnosc); else if (WybranyKolor == 4) c = Led.Color(Jasnosc, Jasnosc, Jasnosc); else if (WybranyKolor == 5) c = Led.Color(Jasnosc, Jasnosc, 0); else if (WybranyKolor == 6) c = Led.Color(Jasnosc, 0, Jasnosc); else if (WybranyKolor == 7) c = Led.Color(0, Jasnosc, Jasnosc); colorWipe(c, 0); } |
Kolejna funkcja pozwala na w pełni losowe zachowanie się paska, wykorzystuję możliwości true random procesora który traktuje pin analogowy jako antenę do zbierania zakłóceń, a te z natury są losowe. Efektem jest przejście po pasku z losowymi kolorami dla każdej z diod i losowym czasie.
1 2 3 4 5 6 7 8 9 |
void losoweKoloryDiod() { uint32_t c; for(uint16_t i=0; i<Led.numPixels(); i++) { c = Led.Color(random(0, Jasnosc), random(0, Jasnosc), random(0, Jasnosc)); Led.setPixelColor(i, c); Led.show(); if(!Przerwanie) delay(random(Opoznienie/10, Opoznienie*10)); } } |
W tej funkcji działanie różni się jedynie tym iż kolor całego paska ustalany jest po każdym z przejściu na losowy a nie dla każdej z diod jak poprzednio.
1 2 3 4 5 6 7 8 |
void losoweKoloryPaska() { uint32_t c = Led.Color(random(0, Jasnosc), random(0, Jasnosc), random(0, Jasnosc)); for(uint16_t i=0; i<Led.numPixels(); i++) { Led.setPixelColor(i, c); Led.show(); if(!Przerwanie) delay(random(Opoznienie/10, Opoznienie*10)); } } |
Dalej widzimy funkcje wykonawczą i pomocniczą.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void colorWipe(uint32_t c, uint8_t wait) { for(uint16_t i=0; i<Led.numPixels(); i++) { Led.setPixelColor(i, c); Led.show(); if(!Przerwanie) delay(wait); } } uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return Led.Color((255 - WheelPos * 3) * Jasnosc / 255, 0, WheelPos * 3 *Jasnosc / 255); } if(WheelPos < 170) { WheelPos -= 85; return Led.Color(0, WheelPos * 3 *Jasnosc / 255, (255 - WheelPos * 3) * Jasnosc / 255); } WheelPos -= 170; return Led.Color(WheelPos * 3 *Jasnosc / 255, (255 - WheelPos * 3) * Jasnosc / 255, 0); } |
Jak można zauważyć w razie pojawienia się przerwania od dowolnego przycisku, pomijam opóźnienia w kodzie co pozwala na dynamiczne przejścia pomiędzy trybami/kolorami/opóźnieniami, nie trzeba czekać do końca cyklu.
6.Podsumowanie
Projekt zajął mi o wiele więcej czasu niż się spodziewałem ale efekty są zadowalające, układ pobiera maksymalnie 8 [wat] .
Jeśli dobrnęliście do końca tego przydługiego artykułu to dziękuję za uwagę, z radością odpowiem na wszelkie pytania, zachęcam do dzielenia się opiniami i tworzenia własnych dekoracji!
Poniżej wstawiam kilka zdjęć i filmików działającego układu :)
Pozdrawiam i życzę wesołych świąt!
Bez chwili namysłu daję 5 i przerzucam na Główną :D
Dziękuję za uznanie, miałem jeszcze sporo przemyśleń i wskazówek ale nie chciałem zbytnio przedłużać itak długiego już artykułu :)
świetne! :P
gwiazda połączona z łańcuchem to bardzo dobry pomysł
tak stwierdziłem gdy wykonałem już bombki, prądu zasilacza jeszcze sporo zostało a dodatkowo w programie można by napisać dla niej osobne niezależne animacje, kwestia gustu :)
Ładnie. Trzeba pochwalić Twoja pracę. Możesz wrzucić program ale bez wykorzystania pamięci eeprom?
Dzięki, co prawda wystarczy skasować kilka linijek ale program dorzuciłem jako: dodatek_1_program_bez_eeprom.zip
Super! Myślę, że moja choinka z Twoimi lampkami wyglądałaby REWELACYJNIE! :)
Kapitalny projekt, przekonałeś mnie do kupna drukarki 3D. Polecasz drukarkę której używasz? Widziałem ją w Polskim sklepie za 2900zł. Taki prezent na święta może sobie zrobię. A gdzie elektroniczne elementy kupujesz? Projekt w dychę.
W tej cenie spokojnie kupisz oryginalną Prusę i3 MK2s – kawał dobrej drukarki! :)
Ja za swoją dałem około 1500 zł przekonały mnie opinie innych i recenzje, jednak ciężko mi powiedzieć czy nie znajdziesz nic lepszego gdyż w swojej dokonałem już szeregu modyfikacji czym myślę że przebiłem wartość samej drukarki… a jeszcze mam sporo pomysłów, jeśli chodzi o zalety to spory obszar roboczy cicha praca dzięki zastosowaniu rolek, praktycznie poskładana drukarka, zgrabna obudowa, wsparcie w postaci grup użytkowników na portalach społecznościowych, spora ilość dostępnych upgrade-ów :) Co do sklepów z elektroniką to nie chce nic promować , osobiście nie mam jednego źródła sporo rzeczy kupuję w hurtowniach i na aukcjach a pozostałą część ciągnę z zagranicy.
C1, i C2 jakie ma parametry ??
O dzięki że zwróciłeś uwagę, zapomniałem napisać chodzi oczywiście o układ rozszerzający arduino, rezystor dla czerwonej diody powinien miec wartosc większą bądź równą 190 [OHM], natomiast kondensatory pełnią rolę filtru ograniczającego wpływ drgań styków, ja zastosowałem kondensatory 100 [nF], zaraz uzupełnię braki w artykule :)
To sązwykłe elektrolity czy ceramiczne ?
Wszystkie kondensatory jakie stosowałem są ceramiczne, elektrolity nie występują w takich obudowach (0805)
Posiadam tylko elektrolity zwykle. Mogą być ?? jak tak to jakie parametry a jak nie to czy inne ceramiczne moga byc ?
Elektrolitów raczej bym nie stosował tego typu filtracji, pojemności mogą być dowolne o jakiejś niewielkiej wartości rzędu 1-100 [nF], zbyt wielka wartość skróci żywotność styków przycisku, zbyt mała może spowodować kilkukrotne losowe uruchomienie przerwania w momencie naciśnięcia o ile nie zabezpieczysz tego programowo, w moim układzie oprócz filtru to można powiedzieć programowo ograniczam przerwanie zgodnie z wartością zawartą w LedBlinkInterval
To sązwykłe elektrolity czy ceramiczne ?