Skocz do zawartości

Tablica liderów


Popularna zawartość

Pokazuje zawartość z najwyższą reputacją od 15.02.2017 we wszystkich miejscach

  1. 13 punktów
    Większość osób myśląc o cyfrowej telekomunikacji, myśli o współczesne mikroelektronice: smartfonach, komputerach i Internecie. Nie każdy zdaje sobie sprawę z tego, że idea przesylania informacji zakodowanej w ciągach zer i jedynek jest dużo, dużo starsza. Pierwszym urządzeniem tego rodzaju był telegraf skonstruowany przez Emille'a Baudot w latach siedemdziesiątych XIX wieku. Urządzenie po stronie nadajnika posiadało klawiaturę złożoną z pięciu przycisków, które operator musiał wciskać w różnych kombinacjach. Urządzenie wysyłało na linię ciąg impulsów, odpowiadających wciśniętej kombinacji. Odbiornik interpretował ten sygnał drukując na papierowej taśmie odpowiednią literę lub cyfrę, w jej naturalnej formie. Na początku XX wieku idea to została udoskonalona. Nadajnik został wyposażony w klawiaturę podobną do tych stosowanych w maszynach do pisania. Tak narodził się dalekopis. Transmisja danych pomiędzy tymi urządzeniami przypominała standardowy interfejs szeregowy. Z tą różnicą, że z przeciwieństwie do TTL UART-a czy RS323 poszczególne stany logiczne nie były kodowane przez wartości napięć, ale przez fakt przepływu (bądź nie) prądu w obwodzie. Normalnie przez linię płynął prąd o ustalonej wartości (zazwyczaj 60, 40 lub 20 mA). To był stan domyślny. Rozpoczęcie nadawania kolejnego znaku wymagało nadania bitu startu, czyli chwilowego przerwania obwodu. Potem nadajnik oczekiwał na pięć bitów z kodem znaku w alfabecie Baudot (zwanym także międzynarodowym alfabetem telegraficznym). Na końcu pojawiały się bity stopu w trakcie których odebrany znak był drukowany na papierze. Ktoś zapewne zauważył już, że używając pięciu bitów można było zakodować maksymalnie 32 znaki - zdecydowanie za mało, aby pomieścić wszystkie litery alfabetu, cyfry i znaki interpunkcyjne. To prawda. Stosowano pewną sztuczkę - dwie kombinacje bitów były zarezerwowane do przełączania pomiędzy dwoma rejestrami zawierającymi litery oraz cyfry i inne znaki. Ne stosowano także rozróżnienia na male i duże litery. Dalekopis chociaż w pełni cyfrowy, był urządzeniem elektromechanicznym, radzącym sobie bez pojedynczego tranzystora (chociaż oczywiście w latach osiemdziesiątych i dziewięćdziesiątych produkowano nowoczesne, elektroniczne wersje). Dalekopisy były powszechnie używane do przesyłania wiadomości przez wojsko i państwowe służby. Poczta wykorzystywała je do transmisji telegramów. Stosowano je także w roli terminali komputerowych, przed pojawieniem się monitorów CRT. Ślad tej zaszłości historycznej zachował się w nomenklaturze stosowanej w systemach uniksowych, gdzie terminal jest oznaczany skrótem TTY - od angielskiego słowa "teletype", czyli właśnie dalekopis. Przepraszam za ten przydługi wstęp, nie byłem jednak pewien, czy wszyscy będą jeszcze kojarzyć o jakie urządzenie chodzi... Przechodząc do sedna sprawy. Na co dzień pracuję w krakowskim Muzeum Inżynierii Miejskiej. Jakiś czas temu został nam przekazany dalekopis T100, wyprodukowany w latach siedemdziesiątych w Czechoslowacji, na licencji Siemensa. Ponieważ posiadaliśmy już taki eksponat, zostałem poproszony o sprawdzenie możliwości uruchomienia go i wykorzystywania w roli interaktywnej instalacji, zamiast "martwego" eksponatu ukrytego w muzealnej gablocie. Tak rozpoczęły się moje eksperymenty. Najpierw skonstruowałem prosty interfejs USB, oparty na starym mikrokontrolerze AT89C2051 i układzie FTDI. Do generowania pętli prądowej 40 mA używałem zestawu kilku baterii 9V oraz rezystorów o dużej mocy. Komunikacja z dalekopisem ruszyła bez problemu - pojawiła się jednak inna trudność. Okazało się, że uszkodzony jest moduł wzywaka - urządzenia odpowiedzialnego m.in. za zdalne włączanie silnika dalekopisu przy połączeniu przychodzącym, sygnalizowanym odwróceniem kierunku przepływu prądu w linii. Naprawa tego modułu okazała się bardziej skomplikowana niż początkowo sądziłem, ostatecznie postanowiłem więc wymontować wadliwą część i sterować silnikiem za pomocą przekaźnika, zamontowanego w moim interfejsie. Finalna wersja interfejsu zawiera mikrokontroler PIC32MX270F256B oraz moduł GSM SIM800L. Wykorzystałem także 2MB pamięć SPI flash, do wykonywania elektronicznej kopii przychodzących wiadomości. W osobnej obudowie znajduje się generator pętli prądowej, złożony z zasilacza transformatorowego oraz zestawu kondensatorów. Całość można obecnie oglądać na wystawie "Uwaga! Nieprzyjaciel podsłuchuje." w Muzeum Inżynierii Miejskiej w Krakowie. Po wysłaniu SMS-a na podany numer można oglądać dalekopis podczas pracy.
  2. 12 punktów
    Ten artykuł jest tłumaczeniem (za zgodą autora) na język polski artykułu napisanego przez Paula Stoffregena, dostępnego pod adresem: https://www.pjrc.com/how-to-get-tech-help-from-strangers-on-the-internet/. Internetowe fora techniczne mogą być bardzo onieśmielające. Trzy proste zasady mogą znacznie ułatwić ci życie i zwiększyć szansę na uzyskanie pomocy, niezależnie od poziomu twoich umiejętności. Dobre Pierwsze Wrażenie — aby ludzie chcieli ci pomóc, Wyjaśnij Kontekst — aby ludzie zrozumieli czego potrzebujesz, Podaj Szczegóły — aby ludzie mogli ci pomóc, Poziom 1: Aby dostrzegli twój problem, Poziom 2: Aby mogli go powtórzyć. Dobre Pierwsze Wrażenie "Nie ma drugiej szansy na zrobienie pierwszego wrażenia" to ponadczasowe powiedzenie. Obcy ludzie błyskawicznie wyrabiają sobie o tobie opinię zaledwie na podstawie słów, obrazów lub nagrania w twoim komunikacie. Niech te słowa zadziałają! Największy wpływ na ludzką chęć do pomocy ma pokazanie, że sam włożyłeś wysiłek w rozwiązanie problemu. Ale jaki to może być wysiłek jeśli dopiero zaczynasz? Łatwo jest skorzystać z wyszukiwarki internetowej używając słów ze swojego pytania. Wielu ekspertów nie zdaje sobie jednak sprawy jak trudno jest znaleźć zrozumiałą i istotną informację gdy nie zna się właściwej terminologii, lub gdy te same słowa używane są także w niezwiązanych z twoim problemem dziedzinach. Zatem napisanie czego próbowałeś szukać i jakie wyniki są dla ciebie niezrozumiałe lub nie na temat może pomóc doświadczonym ekspertom w zrozumieniu twojej sytuacji. To nie wyniki są tutaj istotne, ale twój osobisty wysiłek. Szczera chęć nauki także zazwyczaj sprawia dobre wrażenie. Nawet parę słów pokaże twoje podejście. Bycie zniecierpliwionym, ale zdecydowanym na naukę na błędach robi dobre wrażenie. Inteligentni ludzie, którzy mogą pomóc, często doceniają szczere i uczciwe postawienie sprawy. Oczywiście jeśli już rozpocząłeś swój projekt i pracujesz nad nim, wspomnij o tym. Albo nawet lepiej, pokaż czego już próbowałeś. Zrzuty ekranu, zdjęcia, a nawet krótkie nagranie mogą doskonale zaprezentować co już zrobiłeś i upiec dwie pieczenie na jednym ogniu, jednocześnie komunikując i robiąc dobre wrażenie. Nawet kilka prostych słów dodanych do pytania, pokazujących że szczerze się starasz i chcesz się uczyć będzie mieć duży wpływ na odpowiedź, jaką otrzymasz. Kontekst Umożliwia Zrozumienie Istoty ludzkie mają niesamowitą umiejętność dogłębnego zrozumienia. Eksperci mogą zastosować swoją ogromną wiedzę do wypracowania twórczych pomysłów rozwiązujących twój problem... pod warunkiem, że będą wiedzieć czego tak naprawdę potrzebujesz. Kluczowe jest wyjaśnienie kontekstu pytania. Co chcesz osiągnąć? Jak twoje pytanie jest z tym związane? Jakie rozwiązanie byłoby dla ciebie idealne? Dlaczego? Kiedy zajmujemy się techniczną stroną zagadnienia, łatwo jest skupić się tylko na bezpośrednim problemie. Pamiętaj, że przyjaźni ludzie o ogromnej wiedzy i doświadczeniu regularnie czytają fora tylko dlatego, że lubią pomagać. Kiedy piszesz swoje pytanie, nie zapomnij opisać kontekstu. To może zmienić odpowiedź z technicznie poprawnej ale całkowicie bezużytecznej informacji, na rzeczywiście przydatną radę. Diabeł Tkwi w Szczegółach Współczesne zagadnienia techniczne często zawierają oszałamiającą ilość szczegółów. Ile informacji powinno zwierać twoje pytanie? Zanim je wyślesz, zastanów się nad tymi dwoma kwestiami: Czy czytelnik będzie mógł zrozumieć istotę twojego problemu? Czy będzie mógł go odtworzyć? Łatwo jest sobie zakpić "był jakiś błąd, ale zamknąłem go bez czytania", ale bądźmy poważni, minimalny poziom detali pozwoli czytelnikom zrozumieć problem. Zrzut ekranu lub dokładna kopia tekstu błędu, plus dokładna informacja o użytym oprogramowaniu, wersjach, sprzęcie oraz przedsięwziętych kroków to absolutna podstawa umożliwiająca czytelnikowi w ogóle dostrzec problem tak, jak ty go widzisz. W idealnej sytuacji ludzie czytający twoje pytanie powinni móc powtórzyć twój problem. Taki poziom szczegółowości nie zawsze jest praktyczny, ale jeśli dostarczysz wystarczająco dużo informacji, to szanse na rozwiązanie problemu znacznie się zwiększają. Pytania na temat programowania powinny zawsze zawierać cały kod źródłowy, a nie tylko wycięte fragmenty. Często problem ukrywa się w subtelnych szczegółach w definicjach zmiennych daleko od właściwego kodu. Doświadczeni programiści wiedzą czego szukać i potrafią dostrzec takie błędy natychmiast, jeśli tylko pokażesz cały swój kod. Nie zapomnij także poinformować jakich dokładnie bibliotek używasz. Zagadnienia dotyczące sprzętu elektronicznego często nie obejdą się bez zdjęć albo szczegółowych schematów połączeń, oraz linków do użytych części, lub ich symboli katalogowych. Nieśmiałość i niechęć do opisywania szczegółów swojego projektu na forum są powszechne. Nie wstydź się! Eksperci czytający forum naprawdę chcą pomóc. Pokaż dość szczegółów, wyjaśnij kontekst i pokaż, że się starasz, a oni z pewnością pomogą. Częste Błędy Fora nie zawsze działają idealnie. Powyższe trzy kroki najczęściej zadziałają, ale należy też pamiętać o kilku powtarzających się błędach: Zbyt Wiele Zgadywania Rozwiązywanie technicznych problemów polega na obserwacji i dedukowaniu przyczyn. Całkowicie normalne jest, że kiedy jesteśmy na tym skupieniu, to piszemy w zasadzie tylko na podejrzewanych przez nas przyczynach, a zapominamy opisać zaobserwowane efekty. Krótka przerwa przed napisaniem pytania często tutaj pomaga. Kiedy piszesz, staraj się myśleć z punktu widzenia czytelnika. Czy na pewno prosisz o pomoc w problemie, czy tylko chcesz, aby potwierdzili to co sam już odgadłeś? Z drugiej strony, opisanie jak doszedłeś do swoich wniosków może pomóc uniknąć niepotrzebnego powtarzania tego samego toku rozumowania. Nie ma idealnej metody. Po prostu pamiętaj, że zbytnie skupianie się na wnioskach może powstrzymać ludzi od pomocy. Dawanie Upustu Frustracji Szczerze mówiąc niektóre problemy są bardzo trudne i niesłychanie irytujące. Kiedy jesteś zły, dawanie upustu emocjom jest całkowicie naturalne. Zanim wyślesz wiadomość na forum, robiąc tak istotne pierwsze wrażenie, przeczytaj ją przynajmniej raz. Pewien poziom emocji jest normalny i może nawet pomocny. Pokazuje, że naprawdę się starasz. Ale strzeż się częstego błędu, gdy twoja wiadomość jest odbierana jako narzekanie a nie prośba o pomoc. Brak Odpowiedzi Nawet w idealnej sytuacji czasem nie dostaniesz odpowiedzi. To może rozczarować i przygnębić. Postaraj nie dać się ponieść tym emocjom i nie domagać się odpowiedzi. Jest lepszy sposób. Wysiłek jest istotny. Jeśli minęły całe dnie lub tygodnie od wysłania pierwszej wiadomości, to zapewne w tym czasie włożyłeś w swój projekt trochę więcej pracy? Nawet jeśli bezowocny, ten wysiłek jest czymś, czym warto się podzielić, aby przyciągnąć ludzi. Zdjęcia lub kod, albo inne efekty twojej pracy mogą bardzo pomóc. Czasem bardzo trudne i szczegółowe pytania pozostają bez odpowiedzi, bo po prostu nikt jej nie zna. Albo nikt nie jest pewien. W tej sytuacji dobrze jest zapytać o opinie albo sugestie w którym kierunku szukać odpowiedzi, aby usprawnić rozmowę. Ponownie, pokazanie wysiłku jest kluczowym czynnikiem zachęcającym ludzi do pomocy. Większość forów zniechęca lub nawet zabrania wysyłania wielokrotnie tej samej wiadomości czy "krospostowania". To prawie nigdy nie działa. Eksperci, którzy regularnie czytają fora — ludzie najbardziej skłonni do pomocy — na pewno to zauważą. Masz tylko jedną szansę na zrobienie dobrego wrażenia. Natomiast po dłuższym czasie bez odpowiedzi, ponowienie pytania, najlepiej z linkiem do poprzedniej wiadomości i dodatkowym wyjaśnieniem, nie musi być źle odebrane. Nierzetelni Uczniowie Na każdym forum zdarzają się leniwi uczniowie domagający się odrobienie za nich pracy domowej. Eksperci czytający fora regularnie są zalewani takimi marnymi pytaniami. Nie chcesz, aby twoje pytanie zostało potraktowane jak spam i zignorowane. Jeśli twój projekt jest robiony w ramach zajęć, to najlepiej jest szczerze się do tego przyznać (oraz do terminów) i upewnić się, że widać jednak twój własny wkład. Rzetelny wysiłek i szczera chęć nauki wyróżniają dobrych uczniów. Zastrzeżone Projekty Kiedy nie możesz podzielić się kodem źródłowym albo innymi szczegółami technicznymi, pomoc na forum rzadko będzie dobra. Zazwyczaj musisz poświęcić dodatkową pracę aby wydzielić problematyczny fragment z reszty projektu, aby móc go opublikować. Jeśli tego nie zrobisz i po prosty spytasz "czy ktoś spotkał się kiedyś z takim problemem", to traktujesz ludzi jak wyszukiwarkę internetową. Czasem może się udać, ale naprawdę trudno jest zgadywać na ślepo rozwiązania trudnych technicznych problemów. Jeśli twój pracodawca lub organizacja kategorycznie nie zgadza się na publikowanie kodu lub szczegółów, niezależnie jak drobnych, być może zamiast szukać darmowej pomocy na forum powinieneś użyć komercyjnych produktów, które zapewniają kontraktowo wsparcie, albo zatrudnić eksperta z firmy konsultingowej. Kiedy Otrzymasz Odpowiedź Najlepszym sposobem na wyrażenie wdzięczności jest wskazanie osoby, która udzieliła poprawnej odpowiedzi. Wielu ekspertów poświęca niezliczone darmowe godziny swojego czasu pomagając obcym na forach tylko dlatego, że lubią pomagać. Bycie docenionym jest miłą nagrodą. Kiedy twój problem jest rozwiązany, pamiętaj, że wielu innych ludzi trafi do tego wątku szukając rozwiązania podobnego problemu jeszcze wiele lat później. Najlepiej więc jest napisać na koniec krótką wiadomość podsumowującą poprawne rozwiązanie. Jeśli pytałeś w wielu miejscach, to wypada teraz odwiedzić każde z nich i podlinkować do wiadomości z odpowiedzią. O Tym Artykule (i Autorze) Przez ostatnie 6 lat odpowiedziałem 18620 razy na forum PJRC i nawet więcej na innych forach. Udało nam się w tym czasie stworzyć całkiem dobrą społeczność i pomóc w projektach wielu tysiącom ludzi. Obserwowałem i próbowałem się nauczyć co działa i jak możemy dokonać ulepszeń. Oczywiste stało się, że wielu ludzi potrzebuje nieco wsparcia w zadawaniu dobrych pytań. Najbardziej liczą się tu nie technikalia, ale subtelne czynniki ludzkie. Mam nadzieję, że wszystkie fora techniczne się poprawią. Proszę podzielcie się tym artykułem. — Paul Stoffregen
  3. 10 punktów
    Już słyszę głosy: O, staremu ethanakowi coś się chyba pokręciło... Post jest o jakimś Kedrigernie w dziale DIY - a na zdjęciu mamy coś przypominającego robota z dumnym napisem "Ciapek"... Spieszę z wyjaśnieniami. To nie pomyłka. Post jest na temat serwera mowy Kedrigern, a Ciapek to żaden robot. Po prostu dość trudno zrobić zdjęcie programu, poza tym wypadałoby raczej pokazać ów program w działaniu - a ten wymaga jednak czegoś co będzie gadać (czyli jakiejś bardziej fikuśnej obudowy na głośnik). A ponieważ ostatnio zapatrzyłem się w rysunki Daniela Mroza... cóż, Ciapek z ludzkimi dłońmi, stopami i uszkami wyszedł tak jak wyszedł Zacznę możę od opisu elektroniki (jako że jest to najprostsze, a użytkownik może sobie ją skomponować z zupełnie innych elementów). Sercem całego układu jest Raspberry Pi. Można zastosować dowolny model (chociaż ze starymi, krótkimi GPIO mogą być lekkie problemy), ja użyłem w swoim egzemplarzu Raspberry Pi Zero W. Oprócz tego potzebny jest jakikolwiek układ odtwarzania dźwięku. "Duże" (pełnpowymiarowe) malinki jak popularny 3B+ mają już wyprowadzone wyjście audio, potrzebny jest tylko jakiś niewielki wzmacniacz. Dla wersji Zero potrzebny jest jednak układ zewnętrzny. Prawdopodobnie doskonale spisałby się opisywany ostatnio moduł z wyjściem audio do Raspberry Pi Zero, ja zastosowałem jednak moduł i2s. Jest on dość wygodny w użyciu jako że zawiera w sobie wzmacniacz mono o całkiem sporej (do 3 W) mocy, poza tym początkujący elektronicy nie muszą się martwić o jakieś dziwne masy audio, filtrowane zasilania i tym podobne dziwactwa interesujące tylko "analogowców" - moduł podłącza się pięcioma przewodami do malinki, z drugiej strony dwoma do głośnika i już gra Ponieważ nasz "robocik" musi potrafić poruszać ustami, zastosowałem najprostsze (i najprawdopodobniej najtańsze) rozwiązanie - czyli matrycę LED 8x8 ze sterownikiem, na której rysowane będą kształty ust. Od razu uprzedzę pytanie: owszem, próbowałem zrobić bardziej skomplikowany mechanizm używający serw. Niestety - oprócz trudności mechanicznych (te są do przezwyciężenia) natrafiłem na rzecz, której nie da się przeskoczyć: prędkość serwa. Typowe serwo potrzebuje 0.1 sekundy na przekręcenie orczyka o 60° - a nawet zakładając, że owe 60° wystarczy (w co osobiście wątpię), jest to co najmniej dwa razy za wolno (przy czym owe "dwa" mogłoby się w rzeczywistych układach rozrosnąć do trzech czy czterech). Będę jeszcze próbować rozwiązania z solenoidami - jeśli mi się uda to opublikuję wyniki. Ale może w międzyczasie ktoś inny napisze moduł "solenoid"? Zresztą - chciałem, aby każdy mógł sobie w domu wypróbować Kedrigerna ponosząc jak najmniejsze koszty, a opisywany układ można (mając RPi z wyjściem audio) zmontować kosztem klikunastu złotych (matryca) bez żadnych płytek - po prostu łącząc matrycę przewodami z GPIO malinki. Jako głośnika użyłem leżącego gdzieś w szufladzie zakurzonego głośniczka od starego telefonu z sekretarką, pasować jednak będzie dowolny pod warunkiem dopasowania mocy głośnika do posiadanego wzmacniacza. I to cała wielce skomplikowana elektronika. Jak widać na zdjęciu - nie ma tam nic skomplikowanego. Przejdę więc do opisu programu. Kilka lat temu udało mi się zmusić Mbrolę do w miarę prawidłowego gadania po polsku (do tego stopnia, że można ją było wykorzystać np. do tworzenia audiobooków). System TTS Milena (tak się nazywa ten "zmuszacz" do Mbroli - czyli bardziej fachowo NLP) bardzo dobrze sprawdził się na pecetowym Linuksie, wersja na Windows była raczej ciekawostką ale również działała - postanowiłem więc przystosować ją do malinki. Po przezwyciężeniu pewnych trudności z kompilacją (np. "char" dla architerktury Intel to w GCC domyślnie signed, w ARM z jakichś przyczyn unsigned) okazało się, że co prawda Milena działa, ale "rozruch" ma straszliwie powolny. Nic dziwnego - pliki tekstowe słowników wymowy i translacji fonetycznej muszą być kompilowane przy załadowaniu programu, a malinka ze swoją wolniutką kartą pamięci i nieszczególnie silnym procesorkiem potrzebuje zbyt dużo czasu, zanim wydobędzie z siebie jakieś zdanie. Postanowiłem więc zrobić inaczej: serwer wczytuje wszystkie pliki raz przy starcie systemu, a prosty program klienta przekazuje mu tylko treść komunikatów. Takie rozwiązanie ma również inne zalety: uruchomiony na sockecie TCP serwer może być na zupełnie innej fizycznej maszynie niż klient. I w ten sposób powstał program Kedrigern (nazwany na cześć pewnego czarodzieja, który postanowił odczarować księżniczkę z zaklęcia odbierającego głos). Jak mi to wyszło - oceńcie sami. Oto filmik ukazujący Kedrigerna w działaniu: Nie będę tu rozpisywał się o wszystkich zasadach działania i możliwościach Kedrigerna i Mileny (to w końcu ma byc post na forum a nie książka z dokumentacją), zacznę więc od instalacji Kedrigerna na malince. Wszystkie konieczne komponenty (z wyjątkiem głosu pl1) są w załączonym pliku tgz. Rozpakujmy go w dowolnym katalogu (np. w głównym katalogu użytkownika malinki) i instalujemy mbrolę wraz z polskim głosem: sudo dpkg -i mbrola3.0.1h_armhf.deb sudo apt install mbrola-pl1 Teraz możemy zainstalować Milenę. I tu uwaga: jeśli ktoś miał starszą wersję Mileny niż 0.2.92 musi ją przeinstalować na tę właśnie wersję - inaczej nie będzie działać moduł ruchu ust Kedrigerna! sudo dpkg -i milena*.deb Po zainstalowaniu wszystkiego powinno działać już polecenie milena_say, czyli musimy wypróbować: milena_say dzień dobry kolego I znów uwaga: jeśli wyjściem audio jest HDMI, polecenie może nie działać prawidłowo! Należy spróbować dodać parametr -d opóżniający generację mowy do czasu "załapania" HDMI, czyli najprościej: milena_say -d 2000 dzień dobry kolego Niestety, przy użyciu wyjścia HDMI mogą pojawić się problemy z późniejszym działaniem Kedrigerna, ale po pierwsze nie jest to miejsce na omawianie problemów z audio, po drugie wcale nie czuję się mistrzem w tym zakresie i prawdopodobnie ktoś tu wie lepiej ode mnie jak tym problemom zaradzić. W każdym razie mając uruchomiona Milenę i Mbrolę możemy przystąpić do instalacji Kedrigerna. Zaczynamy od instalacji serwera, czyli sudo dpkg -i kedrigern_0.2.0-1_armhf.deb Jeśli mamy podłąćzoną matrycę LED (8x8, MAX7219) możemy użyć jej jako wyświetlacz ust: sudo dpkg -i kedrigern-matrix_0.2.0-1_armhf.deb No i oczywiście coś co pozwoli nam korzystać z serwera, czyli: sudo dpkg -i libkedrigern_0.1.2-1_armhf.deb Teraz możemy sprawdzić, co potrafi nasz serwer: kedrigern -h lub (jeśli mamy zainstalowany moduł matrix) kedrigern -M matrix -h W odpowiedzi dostaniemy wykaz opcji, z którymi możemy uruchomić serwer. Aby je przetestować, należy otworzyć drugi terminal; w pierwszym uruchamiamy serwer poleceniem "kedrigern" z różnymi opcjami, w drugim testujemy poleceniem kdr-say. Po ustaleniu opcji należy zedytować plik /etc/default/kedrigern i w nim ustawić domyślne parametry. Po przetestowaniu poleceniem kedrigern -C /etc/default/kedrigern możemy już uruchomić nasz serwer w tle: sudo systemctl start kedrigern Jeśli chcemy, aby serwer startował od razu przy starcie systemu, należy wydać polecenie: sudo systemctl enable kedrigern Do komunikacji z serwerem służą polecenia kdr-say, kdr-stop i kdr-speaking. Moduł matrix pozwala na wyświetlanie ust zsynchronizowane z głosem syntezatora. Oto przykładowe obrazy ust dla różnych fonemów: Fonem A Fonem I Fonem O Fonem U Fonemy M, P i B Wybrałem do pokazania kilka najbardziej charakterystycznych kształtów. Jeśli komuś nie odpowiadają stworzone przeze mnie kształty może w prosty sposób dorobić własne lub poprawić moje na bazie pliku /usr/share/kedrigern/demo.shape i podłączyć go do Kedrigerna, np. za pomocą opcji "-m matrix:shape" lub wprowadzając odpowiednie zmiany w pliku konfiguracyjnym. Protokół komunikacyjny jest bardzo prosty. Nie wnikając w szczegóły - załączony moduł w Pythonie (działa w wersji 2 i 3 Pythona) pozwala na sterowanie serwerem, a jednocześnie stanowi przykład sposobu komunikacji. I to wszystko... A nie, nie wszystko. Bo zaraz ktoś powie że to tylko zabawka, że komu potrzebne gadające roboty... Przede wszystkim: Kedrigern może generować komunikaty diagnostyczne w czasie testowania/programowania robota. Jakie to ma znacze nie nie muszę chyba mówić nikomu, kto choć raz ustawiał np. regulatory silników czy zakres ruchu serw w warunkach polowych. Poza robotyką może być bardzo dobrym rozwiązaniem do urządzeń typu headless - ja np. stosuję podobne (poprzednika Kedrigerna) rozwiązanie do obsługi sterownika pieca CO (podanie np. godzin nieobecności w mieszkaniu) czy jako wygodnego interfejsu do wpisywania wyników pomiaru ciśnienia krwi i poziomu cukru z małej przenośnej klawiaturki. A to już nie są zabawki A w ogóle przypominam, że Roomba też gada (tyle że Ciapek ładniej) Zdaję sobie sprawę z tego, że opis jest bardzo pobieżny. Z chęcią odpowiem na wszystkie pytania - o ile kogoś to będzie interesować... W każdym razie wypróbowanie Kedrigerna nawet bez modułu ust posiadacza RPi z wyjściem audio nic nie kosztuje, a może się przyda? Kody źródłowe Mileny i Kedrigerna są dostępne na stronie http://milena.polip.com A, i ostatnie wyjaśnienie: Ciapek to mały troll, wychowanek czarodzieja Kedrigerna w książce Johna Morressy'ego "Głos dla księżniczki". Nawet trochę podobny Przy okazji: @Treker, czemu pliki zip są cacy a tgz są be? kedrigern.zip pykedrigern.zip
  4. 9 punktów
    Witam wszystkich, od mojego ostatniego postu tutaj minęło sporo czasu ale wcale nie porzuciłem robotyki. Jak wszyscy wiemy życie po studiach zaczyna zjadać coraz więcej czasu. Prawie 4 lata temu wrzuciłem tutaj post z moją konstrukcją robota typu delta (Delta Robot). Mam wrażenie, że bardzo fajnie się przyjął i tamta konstrukcja (jak wspominałem 4 lata temu) była prototypem, na którym zaczynałem się uczyć. Cztery lata rozwoju nie tylko mnie ale też dostępnej technologii jak np. druk 3D i mocniejsze mikrokontrolery niż poczciwa Atmega pozwoliły mi rozwinąć skrzydła. Ale przechodząc do meritum, przedstawiam moją następną wersję robota typu delta: Robot składa się w tym momencie z: ramienia, taśmociągu, systemu wizyjnego. systemu generującego podciśnienie 1.Mechanika Do zrobienia tego robota wykorzystałem tyle części z poprzedniej konstrukcji ile się dało. Ale ze względu na postęp techniki i moje większe możliwości finansowe większość przeprojektowałem w SolidWorksie i wydrukowałem na własnej drukarce 3D. Ramiona zamontowane są na podwójnie łożyskowanym wale, który napędzany jest poprzez pasek zębaty, a ten z kolei przez silnik krokowy z zamontowanym 12bitowym enkoderem. Taśmociąg także sam zrobiłem z profilu aluminiowego z Allegro oraz silnika DC z przekładnią. Pas kupiłem z profesjonalnej firmy na zamówienie. Może to brzmi groźnie i drogo ale tak nie jest. Pas kosztował 110 zł brutto. robot posiada 4 osie, dokładnie tak jak poprzednia konstrukcja. 2. Elektronika Najważniejszym układem scalonym jest mikrokontroler TEENSY 3.6 (link) zajmuje się: sterowaniem silnikami krokowymi, obsługą enkoderów silników jak i taśmociągu, komunikacją z komputerem, zapisem programów, punktów oraz wszelkich ustawień na karcie SD Jest to kontroler kompatybilny z bibliotekami Arduino i szczerze dla całego projektu zbawienne było to, że miałem gotowe biblioteki dla wielu rzeczy i nie musiałem się uczyć tego procka wraz z wszystkimi rejestrami, algorytmami zapisu na kartę SD, protokołu SPI oraz obsługi wielu peryferii jak sterowniki silników krokowych (o tym za chwilę) oraz np. ekranu LCD. Mogłem się skupić na moim celu czyli aplikacji, która ma spełniać moje założenia. Dodatkowo w kontrolerze, a także w ramieniu znajdują się: Teensy 3.2 - obsługa ESTOP, IO (wejść/wyjść), obsługa LCD oraz pomost w komunikacji pomiędzy głównym prockiem, a Arduino w ramieniu, Arduino Nano - obsługa PID taśmociągu, sterowanie serwochwytakiem ( kontroler Pololu Maestro), sterowanie pompą podciśnienia oraz elektrozaworem, Arduino Nano - komunikacja z komputerem poprzez zTCP/IP Silniki wyposażone są w enkodery absolutne AMS AS5045, które dostałem za darmo. Robot wyposażony jest w 4 wejścia oraz 4 wyjścia 24V (standard przemysłowy). W celu testowania czy wszystko dobrze działa zrobiłem dodatkowo prosty panel z 4 diodami oraz 4 przyciskami do testowania czy wszystko dobrze działa. Silniki sterowane są poprzez sterownik silników krokowych AMIS-30543 (link), który pozwala na konfiguracje poprzez magistralę SPI, a także na sterowanie z mikrokrokiem x32, które to sterowanie tutaj wykorzystuję. Dodatkowo jak widać na zdjęciach zaprojektowałem oraz zmontowałem (po dostaniu od Satlandu) płytki, które pozwoliły wszystko spiąć ze sobą. Nie będę wrzucał schematu PCB, bo nie jest to nic interesującego. 3. System wizyjny Robot skalibrowany został z systemem wizyjnym OpenMV (link). Kamera została zaprogramowa w języku Python i jej zadaniem jest w zadanym czasie (komunikat wysłany po uart) zrobić zdjecie i zliczyć bloby o odpowiedniej wielkości. Kamera wurzyca po porcie uart dane do mikrokontrolera głównego w postaci NUMER/X/Y/KĄT/ już we współrzędnych robota. Po dostaniu danych do tablicy punktu dodawana jest aktualna pozycja taśmociągu. Dzięki temu robot jest w stanie trafić w detal podczas ruchu taśmy. 4. System sterowania Całość oparta jest na matematyce, mikrokontroler oblicza zadanie proste oraz odwrotne kinematyki (dla pozycji oraz prędkości). W przeciwieństwie do starej konstrukcji układ sterowania naprawdę bierze pod uwagę pozycję oraz prędkość, dzięki temu robot porusza się bardzo płynnie oraz może zachować określoną prędkość liniową punktu TCP (Tool Central Point). Algorytmy pozwalając na poruszanie się w trybach: JOINT - ruch obliczany jest tak, aby każda oś zakończyła pracę w tym samym czasie, LINEAR - ruch lionowy punktu TCP z określoną prędkością liniową, TOOL - ruch liniowy ale zgodny z układem współrzędnych narzędzia CONV - tryb ruchu liniowego z załączonym śledzeniem taśmy, Cały program posiada w tym momencie jakieś 6 tys linijek kodu i pozwala na pracę w trybie automatycznym jak i ręcznym robota. Całość jest napisana w języku C/C++. 5.Program na PC Program napisany w C# w środowisku VisualStudio. Pozwala na: załączenie silników (przekaźnik odcinający na linii 24V), Zwolnienie napędów (enable na sterowniku krokowców) ułatwia ręczne uczenie punktów, Resetowanie błędów, Sterowanie robotem w trybie ręcznym, Uczenie punktów, Edycję ręczną zapisanym punktów na robocie, ustawienie układu TOOL oraz pozycji domowej robota, pisanie prostych programów w skryptowym języku podobnym do BASICA (jestem w trakcie prac) uruchamianie programów w trybie automatycznym, deklarowanie konkretnych działań pod wejścia oraz wyjścia np. cykl start na wejściu 1 podgląd pozycji robota, podgląd IO robota, sterowanie taśmociągiem, zapisywanie oraz sczytywanie ustawień robota oraz punktów z/do pliku na PC po połączeniu z robotem automatyczne sczytanie ustawień oraz punktów z karty SD w kontrolerze. 6.Filmiki Wiem, że to tylko krótki post na temat tego robota i w temacie dla zainteresowanych jest znacznie więcej do opowiedzenia dlatego jak ktoś ma jakieś pytania to zapraszam do komentarzy oraz wiadomości
  5. 9 punktów
    Od momentu poznania ESP8266 bardzo spodobał mi się ten układ. Gdy skończyłem robić pierwszy projekt oparty na tym układzie od razu zacząłem wymyślać kolejny. Dzisiaj chciałbym Wam przedstawić sterownik oświetlenia. Współpracuje on ze zwykłym włącznikiem świecznikowym i mieści się w puszce fi60, dzięki czemu (nad każdym włącznikiem światła mam puszkę fi70) w puszcze fi70 zostaje jeszcze sporo miejsca na kable. Po zaprojektowaniu płytki w programie Eagle zleciłem wyprodukowanie jej firmie jlcpcb. Wszystko trwało tydzień (zamawiałem również inne płytki dlatego tyle to trwało ). Płytki wysłali w piątek po południu czasu lokalnego a w poniedziałek płaciłem już vat u kuriera z DHL . Płytki wyglądają bardzo dobrze (sami możecie ocenić jakość produktu ) Po odebraniu płytek zacząłem wszystko składać w całość. ESP8266 12F zostało wykorzystane jako "mózg" płytki. Jako zasilacz służy Hi-Link HLK-PM01 230V na 5V. Za załączenie napięcia odpowiedzialne są dwa przekaźniki z cewką na 5V. Dodatkowo do każdego przekaźnika dołożyłem diodę prostowniczą. ESP jest zasilane napięciem 3.3v przez co musiałem zastosować LDO. Dodatkowo na wejściu fazy do układu zamontowałem bezpiecznik firmy bel fuse. Żeby esp mogło załączać przekaźnik musiałem wykorzystać tranzystor bc817 w wersji smd. Do tego potrzebowałem jedno złącze ark raster 5mm podwójne, oraz dwa złącza ark raster 5mm potrójne. Całość po zlutowaniu i umieszczeniu w puszcze fi60 wygląda następująco: Teraz przyszła kolej na oprogramowanie. Zdecydowałem się zrobić prostą stronę konfiguracyjną na której możemy: zmienić hasło do urządzenia zmienić dane serwera mqtt (sterowanie z każdego miejsca na świecie ) zmienić przyłączenie do sieci wi-fi zobaczyć jak długo pracuje nasz układ wybrać ilość podpiętych włączników (jedno albo dwa) Całość jest również sterowana z telefonu z systemem android. Teraz przymierzam się do zrobienia wersji v2 tego sterownika, chcę by był oparty na triakach i optotriakach (z tego co wyliczyłem to żarówka led o mocy 15W pobiera tylko 60mA a świeci jak zwykła żarówka 120W) oraz będzie posiadała wsparcie dla dotykowych podświetlanych włączników (moduły httm oraz panele marki weilak, wszystko mam tylko projekt został ) Jestem bardzo ciekaw Waszych opinii, dajcie znać w komentarzach co myślicie mo jej konstrukcji
  6. 9 punktów
    Już na samym początku prosiłem o to, aby darować sobie zgryźliwości. Jeszcze raz ponawiam moją prośbę i obiecuję od teraz usuwać wszelkie posty, które będą miały nawet jedno złośliwe zdanie. Niezależnie od tego czy autorem będzie nowa osoba, czy użytkownik, który ma na koncie 100 tysięcy postów - każdego obowiązują takie same zasady. To, że opisywany projekt jest częściowo reklamą tego projektu jest chyba oczywiste - wystarczy poświęcić kilka sekund i obejrzeć filmy, które są w pierwszym poście. Nie przypominam sobie, aby gdzieś był zakaz publikacji tego typu opisów. Nie jest to produkcja masowa, nie widzę więc powodu, aby od razu "rzucać" się na autora i krytykować za wszystko co możliwe. Czym taki projekt różni się od innych DIY, w których autorzy nie podają dokładnej instrukcji budowy i nie dzielą się projektami? Moim zdaniem niczym. Ten projekt wypada nawet lepiej, bo jak ktoś będzie bardzo chciał to sobie chociaż może kupić takie urządzenie. Prawie nikt nie zadał konkretnych pytań technicznych, pojawiały się tylko różne uwagi "byle udowodnić, że projekt jest zły". Autor próbował Wam wszystko wyjaśnić, wstawiał zdjęcia i filmy, a dla Was nadal jest źle. Rozumiem, że komuś projekt może się nie podobać, wystarczy raz wyrazić swoje zdanie lub zignorować temat. Jak widać po głosach czytelników, raportach oraz otrzymanych przeze mnie wiadomościach jest sporo osób, którym ten projekt się zwyczajnie podoba. Proszę więc wszystkich krytyków, aby wzięli pod uwagę, że nie każdy musi się z Wami zgadzać, niektórym taki projekt się podoba i tyle. Nie musicie na siłę wszystkich przekonywać, że jest źle i atakować ciągle autora. Projekt ten zaakceptowałem świadomie i widziałem, że jest to częściowo reklama. Uznałem jednak, że projekt jest ciekawy, nie było u nas opisu takiej maszynki. Liczyłem więc, że takie DIY może być dla wielu osób ciekawą inspiracją. Autor nie jest pierwszą osobą na świecie, która zrobiła takie urządzenie. W Internecie jest sporo maszynek do ręcznej produkcji filamentu. Jak ktoś będzie chciał to wykona urządzenie samodzielnie. To czy jest sens sprzedawać taka maszynkę to już zweryfikuje rynek - jak będą klienci to będzie sens, a jak nie będzie zainteresowanych to trudno, przynajmniej ktoś próbował. Dziwie się osobom, które poświęcają tyle czasu na pisanie krytyki i szukanie zaczepek. Ciężko mi uwierzyć, że liczą one na merytoryczną dyskusje. Nie macie ciekawszych zajęć od krytykowania projektów? Jeśli macie gorszy dzień lub nadmiar energii to proponuje skupić się na chwaleniu DIY, które według Was są ciekawe. Sprawdźcie listę opisanych projektów, znajdźcie coś ciekawego i napiszcie autorowi, że robi dobrą robotę. Nie widzę wielu postów, które chwaliłyby ciekawe DIY - tak ciężko napisać komuś dobre słowo? Jeszcze raz apeluję o ograniczenia zgryźliwość, a wszystkim będzie przyjemniej czytać posty i więcej osób będzie chętnie brało udział w dyskusjach. Zachęcam również osoby, które nie zgadzają się z takimi złośliwościami, aby wyrażały to jakoś publicznie (np. przez posty lub reakcje). Oczywiście doceniam raporty i PW kierowane do mnie, ale może jednak byłoby dobrze, aby autorzy takich wiadomości widzieli, że to "nie są tylko moje wymysły", a jest wiele osób, którym taki ton dyskusji zwyczajnie nie odpowiada.
  7. 9 punktów
    Cześć! Powoli zauważam, że roboty tego typu zaczynają wymierać i odchodząc na lf-ową "emeryturkę" chciałbym zostawić jakiś ślad po swoim projekcie. Choć na zawodach nigdy nie szczędzę informacji na temat swojego robota i chętnie dzielę się wiedzą oraz doświadczeniem w temacie, to mam wrażenie, że ilość lepszych robotów w konkurencji nie zwiększa się, a nawet spada. Na zawodach starzy bywalce ścigają się między sobą, a młodzi pewnie zniechęcają się do konkurencji, ze względu na wysoki próg wejścia do walki o nagrody. Cukiereczek - LineFollower bez turbiny (Nazwa nawiązuje do mojej poprzedniej konstrukcji - Candy). Jest to robot, którego zbudowałem w ramach pracy przejściowej magisterskiej między styczniem a marcem 2018r. Debiutował na zawodach Robomaticon 2018 w Warszawie, gdzie zajął 3 miejsce, zaraz za Candy (zabrakło czasu na napisanie sensownego programu). Później rozwijane było oprogramowanie, które zostało tematem pracy dyplomowej. Wydaje mi się, że jest to obecnie najszybszy robot w swojej kategorii w Polsce, aczkolwiek scena LF od 2018r. mocno się uszczupliła - być może o potencjalnie szybszą konstrukcję. Główne cechy: 12 czujników linii Mikrokontroler STM32 F7 IMU: żyroskop + akcelerometr RGB Lidar ToF USB karta µSD Bluetooth 4.2 Własny mostek H Enkodery magnetyczne 1. Konstrukcja mechaniczna Wydaje mi się, że kształtem przypomina robota Fuzzy, którym swego czasu mocno się inspirowałem przy robocie Candy. Mam nadzieję, że nikt tutaj nie uzna robota za bezpośrednią kopię - kształt jest zdecydowanie inny, podyktowany konkretnymi założeniami i doświadczeniami z poprzednich konstrukcji. Podwozie stanowią 2 moduły PCB: płytki głównej oraz płytki z czujnikami linii, połączone ze sobą taśmą FFC i usztywnione węglową listewką modelarską. Ślizg przedniej listewki zapewniają 2 ścięte łby nylonowych śrubek, z doklejoną podkładką teflonową. Z tyłu robota doklejony jest wheelie bar, w postaci kawałka listewki węglowej ze śrubką oraz teflonem. Wielokrotnie przerobiony temat - gdyby nie podpórka, robot wywracałby się do góry dołem oraz podskakiwał na każdym zakręcie. Napęd: 2 silniki szczotkowe Pololu HPCB 10:1 z obustronnym wałem, na który nałożono magnes 6x2.5 do enkodera magnetycznego. Koła to felgi wydrukowane na drukarce 3D z oponami Mini- Z. Nie dają takiej przyczepności jak poliuretan, ale nie udało mi się dobrać lepszych kół przy samodzielnym odlewaniu. Silniki zostały odrobinę podniesione podkładkami z PCB o grubości 1mm oraz kauczukiem tłumiącym wibracje. Do ich montażu wykorzystałem standardowe, plastikowe mocowania Pololu. Waga konstrukcji to 55.5g (66g z akumulatorem). Nie była priorytetem. 2. Elektronika Wszystkie płytki PCB zostały wykonane w firmie Techno Service z Gdańska. Płytka główna oraz płytka z czujnikami to płytki 4-warstwowe, pozostałe: płytki enkoderów oraz płytka IMU, 2-warstwowe. Schemat oraz layout stworzyłem w programie Altium Designer. Robot może być zasilany z akumulatora li-po 2-4S (6-17V) lub bezpośrednio z USB (bez możliwości uruchomienia silników). Oprócz pomiaru napięcia wejściowego, dodatkowo wstawiono układ pomiaru prądu pobieranego przez robota. Robot startuje obecnie z akumulatorami 2S, 180mAh, 50C. Sekcję zasilania (oprócz sekcji silnikowej) stanowi przetwornica 5V 1A, oraz układy LDO na napięcie 3.3V (osobne dla MCU, sekcji analogowej oraz czujnika IMU). Na płytce czujników znalazło się 12 transoptorów KTIR0711S. Są gęsto ułożone w jednakowych odstępach tworząc delikatny łuk. Zdecydowano się na proste rozwiązanie hardware'owe, dające równomierne odczyty z trasy. Przekombinowany układ czujników mógłby powodować dodatkowe komplikacje (różne odczyty na odsuniętych czujnikach, wpływ nierówności trasy - odległości sensorów od podłoża), więc wszelkie wykrywania dziwnych elementów na trasie realizowane są software'owo. Moduł IMU został zamocowany na padzie kauczukowym tłumiącym wibracje. Użyto sensora Invensense ICM-20602. Jak widać na zdj. poniżej, bardzo poważnie potraktowałem kwestię wibracji, które mają spory wpływ na odczyty. Wykorzystany czujnik posiada wysoką czułość i jest wrażliwy na wibracje i naprężenia. Sensor posiada dedykowaną linię zasilania z oddzielnego LDO o wysokim PSRR. Mostki H zbudowano na układach przekształtnikowych TI DRV8703 oraz tranzystorach N-FET: Toshiba TPWR8503NL. Taki układ mimo, że skonstruowany mocno na wyrost, pozwala na dowolne wysterowanie silnika, w tym zmianę kierunku obrotu bez żadnych dodatkowych opóźnień. Poprzednio stosowane mostki, popularne TB6612 wymagały łączenia kanałów i stosowania opóźnień. Wydajność takiego mostka szacuję na ok. 10A ciągłego prądu (z prądem chwilowym sięgającym +100A), sensownie byłoby lepiej dopasować mostek do wykorzystanych silników, jednak ze względu brak czasu na testowanie i chęć zamknięcia projektu w jednej rewizji PCB, postawiłem na "zero kompromisów". Dodatkowym założeniem była chęć ewentualnej zmiany silników na mocniejsze. Enkodery to AS5047P zamontowane na pionowych płytkach PCB. Podłączone zostały magistralą SPI. Dokonują pomiaru kąta absolutnego, z rozdzielczością 14 bitów. Uwzględniając przekładnię mechaniczną, można uzyskać ponad 160 tysięcy jednostek na obrót koła. Mikrokontroler zastosowany w projekcie to STM32F722 w LQFP64. MCU taktowany jest z częstotliwością 216MHz. Wszystkie piny procesora zostały wykorzystane. Posiada bardzo duży zasób obliczeniowy, znacznie większy od F1, dzięki czemu algorytmy sterujące mogą być skomplikowane i nie trzeba rezygnować z obliczeń na floatach. Karta µSD podłączona została pod SDMMC, na 4-bitowej szynie SDIO. Czujnik odległości to ST VL53L1X, laserowy czujnik Time of Flight, podłączony pod magistralę I2C. Został umieszczony na mocowaniu silnika, w celu uniknięcia dodatkowej bezwładności na listewce robota. Posiada spory zasięg, więc utrata długości z listewki nie jest problemem. Niestety czujnik domyślnie posiada spory field of view, który można odrobinę zmniejszyć tracąc również na zasięgu. Mam z tym czujnikiem sporo problemów. Na zawodach w Rzeszowie wyłapywał patyczki znaków drogowych postawionych przy trasie (inni zawodnicy nie mieli z nimi problemu) oraz bardzo często zdarza mi się, że silnik potrafi zawiesić czujnik podczas przejazdu. Rozwiązania w tej formie nie polecam. 3. Oprogramowanie Przy prowadzeniu projektu wspomagałem się programem CubeMX, a kod pisany był w środowisku Atollic TrueStudio. Poza bibliotekami CubeHAL, z których korzystam, całość własnego kodu została napisana w języku C++. Kod został podzielony na klasy, często wykorzystując przy tym mechanizm dziedziczenia. Użycie C++ pozwoliło wygodnie operować kodem, którego fragmenty wykorzystuję również w innych swoich projektach. Zrezygnowano z wykorzystania RTOSa (FreeRTOS w tym przypadku), ze względu na spory koszt samego OS przy pętlach rzędu 10kHz. STM serii F7 posiada wystarczająco dużo timerów, aby poszczególne zadania podzielić w niezależne pętle z własnym priorytetem. Do obsługi czujników linii, wykorzystano "tylko" 1 przetwornik ADC. Łączenie kilku przetworników w celu uzyskania szybszych pomiarów uznałem za bezcelowe, gdyż prawdopodobnie i tak musiałbym wyzwalać pomiary timerem, aby nadążyć z przetwarzaniem pomiarów. Obecnie pomiary wykonują się z częstotliwością ok. 56kHz i każda próbka brana jest pod uwagę podczas przejazdu. Pozycja linii wyznaczana jest w prosty sposób, przy pomocy średniej z wag przypisanych do każdego czujnika. Wagi czujników są u mnie odrobinę nieliniowe. Osobno rozpatrywane są "przypadki specjalne", gdy pod czujnikami brakuje linii itp. Osobny przetwornik wykorzystano do pomiaru napięcia i prądu. Liczona jest także zużyta pojemność baterii. Pętla sterowania silnikami z regulatorami PID wykonuje się z częstotliwością 8kHz. Nastawy zostały dobrane po części w Matlabie, później dostrojone empirycznie. Pętla żyroskopu również wykonuje się z częstotliwością 8kHz, taktowana jest przerwaniem dataready czujnika. Żyroskop wykorzystuję obecnie do omijania przeszkód oraz w odometrii. Główna pętla - podążania za linią wykonuje się z częstotliwością 400Hz. Sterowanie odbywa się poprzez typowy regulator PD, którego nastawy dobrane zostały metodą prób i błędów, bazując również na poprzedniej konstrukcji - przyspieszony proces. 4. Dodatki Sygnalizacja RGB - Zamiast niezależnych diod LED, wykorzystałem 4 diody WS2812B, które mogłem podłączyć do 1 pinu mikrokontrolera (a zużyłem wszystkie). Na diodach sygnalizowany są stany poszczególnych elementów robota, np. kalibracji żyroskopu, stanu baterii, stanu załączenia silników czy błędu regulatora linii. Interfejs USB - Jedyne złącze użytkowe w robocie. Jako, że interfejs SWD programowania wyprowadziłem w postaci padów do lutowania, "codzienne" programowanie robota odbywało się przez interfejs USB w trybie DFU. Napisany został kod umożliwiający przejście mikrokontrolera do wewnętrznego bootloadera, a następnie wgranie nowego programu. USB służył także do debugowania poprzez port COM. Karta µSD do logowania danych podczas przejazdu. Logowanie odbywa się w tle, w czasie wolnym procesora. Dane zbieram z częstotliwością ~1kHz i zapisuję binarnie w pliku (system FAT32). Logi dostarczyły mi sporo informacji "ukrytych" w robocie i przydały się w pracy magisterskiej. Poniżej przykładowe wykresy dla poboru energii, sterowania, czy utworzonej mapy trasy z uwzględnieniem omijania przeszkody. Aplikacja na smartfon pod moduł BT 4.2. Stosując moduł inny niż HC-05, zmuszony byłem stworzyć własną aplikację smartfonową do zmiany nastaw robota oraz zdalnego startu. 5. Osiągnięcia: 1 miejsce, LineFollower bez turbiny, Robomaticon 2019 w Warszawie , 9 marca 2019 1 miejsce, LineFollower Standard, XI Robotic Arena – Wrocław, 12 stycznia 2019 1 miejsce, LineFollower Enhanc3D, XI Robotic Arena – Wrocław, 12 stycznia 2019 1 miejsce, LineFollower Standard, Bałtyckie Bitwy Robotów w Gdańsku, 26-27 maja 2018 3 miejsce, LineFollower 3D, Bałtyckie Bitwy Robotów w Gdańsku, 26-27 maja 2018 1 miejsce, LineFollower Standard, Zawody ROBO~motion w Rzeszowie, 19 maja 2018 3 miejsce, LineFollower bez turbiny, Robomaticon 2018 w Warszawie, 3 marca 2018 Poniżej kilka filmów:
  8. 9 punktów
    1) Prolog Cześć, dzisiaj opiszę wam mój projekt inżynierski w którym budowałem model autonomicznego pojazdu. W ramach pracy dyplomowej zaprojektowałem uproszczony model autonomicznego pojazdu. Model przystosowany jest do poruszania się w prostym środowisku testowym, symulującym prawdziwe otoczenie. Mój model wyposażony jest w kamerę, pozwalającą na pozyskiwanie informacji o otoczeniu. Obraz z kamery jest źródłem danych dla zaimplementowanej sieci neuronowej, która odpowiada za podejmowanie decyzji o kierunku przemieszczania się pojazdu. Całość pracy zawiera opis poszczególnych etapów tworzenia modelu, projektowanie architektury, implementacje oraz uczenie jednokierunkowych sieci neuronowych do prawidłowego działania. W projekcie użyłem Raspberry Pi, w którym została zaimplementowana sieć neuronowa stworzona w języku Python oraz Arduino odpowiedzialne za sterowanie podzespołami. Rozwiązanie zaproponowane w pracy opiera się szeregu transformacji obrazu za pomocą biblioteki OpenCV w celu ekstrakcji cech tak, aby sieć neuronowa otrzymywała tylko najistotniejsze informacje na podstawie których podejmie decyzje. 2) Wykorzystane elementy: Raspberry Pi B+ (chociaż lepsza była by Raspberry Pi 3b+) Raspberry Pi Cam 8Mpx Lego 42037 Lego Motor M Serwomechanizm SG90 (wymagało modyfikacji) Arduino UNO Rev3 Konwerter poziomów logicznych 2x18650 z rozbiórki laptopów + koszyk L298N - dwukanałowy sterownik silników - moduł 12V/2A 3) Przebieg Prac Praca nie determinowała typu modelu jaki zostanie opisany w pracy a jej głównym celem miało być czy implementacja w prosty sposób funkcji takich jak jazda na wprost, po łuku, skręt czy poruszanie się po okręgu jest możliwa do implementacji wykorzystując sieci neuronowe i wiedzę wyniesioną z toku studiów. W Pierwszej kolejności zrobiłem małe rozeznanie co do możliwości jakie mogłem wybrać i z grubsza można było je podzielić na 2 rodzaje: a) fizyczne - do których zaliczamy np przerobienie realnie istniejącego samochodu osobowego lub modelu pojazdu zdalnie sterowanego RC lub inne tego typu konstrukcje: b) software-owe - w skład których wchodzą takie propozycje jak: dedykowane symulatory, gry komputerowe (symulujemy wtedy klawisze które normalnie naciska gracz) lub własnoręcznie napisane programy do tego celu, np napisane w matlabie lub specjalna "gra" wykorzystana w tym celu. W moim przypadku realizowałem to w pojedynkę i ograniczały mnie dwa aspekty takie jak czas wykonania, koszt który musiał bym ponieść, oraz zasób wiedzy jaki trzeba było by do tego użyć dlatego musiałem znaleźć swojego rodzaju złoty środek którym był fizyczny model (bardziej namacalny) w pomniejszeniu czyli Model RC, ale ze nie posiadam żadnego modelu RC to wykorzystałem zestaw Lego 40237. 4) Hardware Podstawą pojazdu jest już wcześniej wspomniany zestaw Lego 42037 który posiada pewne braki i w tym rozdziale należało zabawkę z lego dostosować do potrzeb projektu. Głównym problemem był brak napędu oraz zdalnego sterowania, o ile z napędem na tylną oś poradziłem sobie bardzo szybko (były już w modelu półosie, dyferencjał i wał) i wystarczyło wstawić w odpowiednie miejsce kilka klocków i silnik Lego M to z układem kierowniczym trzeba było więcej się nagimnastykować. Aby przenie koła wprawić "w ruch" trzeba było znaleźć miejsce na serwomechanizm + zintegrować go z istniejącym układem kierowniczym, dodatkowym problemem był fakt że standardowe serwo ma "wyjście" na orczyk/ wieloklin) al układ kierowniczy lego był zakończony Axlem. Nie chciałem też ingerować i niszczyć klocków dlatego wykonałem nieinwazyjny adapter i skleiłem klejem na gorąco odpowiednio docięty orczyk z klockami które miały otwór na axle. W ten oto sposób nasza podstawa ma wyprowadzone 2 zestawy przewodów - jeden do Silnika napędowego a drugi do serwomechanizmu połączonego z układem napędowym. 5) Elektronika Teraz czas na elektronikę... która jest bardzo prosta bo w zasadzie sygnały sterujące musimy przesłać do 2 komponentów - silnika oraz serwa. W pierwotnym zamyśle było podłączenie bezpośrednio Raspberry Pi do tych 2 komponentów ale wiedziałem że "nie będzie czasu" na generowanie PWM softwareowo dla serwa + dla silnika napędowego dlatego zostało dołożone Arduino które potrafi to robić sprzętowo i odciąży Raspbery Pi od tego zadania. Zyskałem na tym niewielki wzrost skomplikowania elektroniki i oszczędziłem moc obliczeniową w Raspberry Pi. Z kolei silnik napędowy wymagał zastosowania "jakiegoś" mostka H aby nie upalić Raspberry bo wbrew pozorom Silnki z lego potrafią pobierać znaczącą ilość prądu ( więcej info można znaleźć tutaj ) dlatego wybór padł na wcześniej wymieniony gotowy moduł dwukanałowego (zostały zmostkowane oba kanały) mostka H - wystarczy teraz podać tylko odpowiedni sygnał PWM do mostka H i już mamy możliwość płynnej kontroli nad prędkością modelu. Ostatnim etapem było zestawienie komunikacji po porcie szeregowym Arduino z Raspberry Pi za pomocą portu szeregowego i w tym wypadku. Takie połączenie wymaga zastosowania konwertera poziomów logicznych gdyż Raspberry Pi toleruje tylko 3V3 volta a arduino daje 5V - gdyby tego nie było mogło by dojść do uszkodzenia Rarspberry Pi 6) Software I teraz to co tygryski lubią najbardziej - programowanie i tutaj jest podział na 2 części (ale nie mogę wrzucić tutaj kodów źródłowych) a) Arduino Dla Arduino został napisane proste API (ASCII) sterowane przez raspberry - oferowało zestaw prostych funkcji takich jak: - Ustaw silnik na x PWM (zakres 0-255) - Ustaw serwo na x PWM ( 0 - prawo, 90 - prosto, 180 - lewo) - START - Po tej komendzie można było uruchomić pojazd - STOP - powodowała zatrzymanie silnika i ustawienie serwa na 90 stopni (przygotowanie do jazdy na wprost) b) Raspberry Pi Zasada działania tego modelu wykorzystywała sieci neuronowe i nauczanie pod nadzorem nauczyciela ( w skrócie mamy 2 rodzaje uczenia sieci neuronowych - z wykorzystaniem nauczyciela czyli dajemy jakieś dane uczące, potem sprawdzamy na części danych kontrolnych i korygujemy tak długo aż osiągniemy dobre rezultaty i na koniec testujemy na nigdy nie używanych danych, same dane dzielimy w stosunku 4-1-1. Druga opcja to bez nauczyciela i sieć musi nauczyć się sama i jest to o wiele bardziej skomplikowane). Uproszczony schemat działania programu: Aby to działało musimy zaprojektować sieć ( u mnie rozważyłem kilka przypadków) i jest to zależne od ilości wejść i tego co chcemy uzyskać na wyjściu czyli sygnał sterujący w najprostszej wersji może to wykorzystywać kilka neuronów a najbardziej skomplikowane mogą ich mieć dziesiątki tysięcy ( w różnych warstwach) jednak korzystając z Raspbery Pi mamy ograniczą moc obliczeniową i musiałem ułatwić analizę i pracę sieci. Dlatego dokonałem ekstrakcji danych z obrazu i wstępnego przetworzenia w OpenCV gdzie pozyskuje informacje o położeniu linii drogi którą ma podążać: Idąc od lewej - obraz widziany przez kamerę, dalej sektory które obserwujemy aby dokonać analiz "ucieczki linii", trzeci obrazek to binaryzacja i wykrycie gdzie aktualnie znajduje się linia i jak "ucieka" aby można było określić w którą stronę należy skręcić aby jechać prosto. Dzięki temu na wejściu sieci neuronowej podajemy jedynie 2 parametry (położenie lewej i położenie prawej linii) co znacząco ułatwia obliczenia i projekt sieci. Mając te informacje zbieramy dane z przejazdów i zachowania linii podczas konkretnych manewrów np jazda na wprost, po łuku itp. I zapisujemy do pliku - co ważne w tym momencie sterujemy robotem ręcznie i od naszej precyzji sterowania zależeć będa w dużej mierze efekty jakie uzyskamy. Po zebraniu danych możemy przejść dalej. Uczenie sieci: Realizowałem w matlabie i toolboxie z sieciami neuronowymi i tam testowałem jak wyglądają efekty uczenia a następnie eksprtowałem sieć (sieć to tak naprawdę liczby które decydują o "wadze" neuronu poszczególnego) do własnej implementacji w pythonie i testowałem w realu co było pracochłonne. I tak aż do skutku i poprawiałem błędy aż do uzyskania efektu zadowalającego . Na koniec zostały przeprowadzone eksperymenty jak sieć radzi sobie z poszczególnymi testami. 7) Co bym zrobił inaczej W wersji 2.0 lub po prostu gdybym zaczął robić projekt od nowa zmienił bym niestety dosyć dużo widząc jakie braki / niepotrzebne problemy napotkałem na drodze: Rozwiązanie z modelem było dobre - jednak lepiej było do tego celu wykorzystać nie lego a model RC z uwagi na łatwiejszą integrację i o wiele mniejsze luzy w układzie np kierowniczym co generowało duże odchyłki a także dużo większą sztywność konstrukcji i spasowanie. Zastosowanie wydajniejszego SBC np nVidia Jetson lub nawet przenieść to na jakiś iCore desktopowy co zapewni wielokrotnie większą moc obliczeniową Zastosowanie kilku kamer najlepiej czarno białych + doświetlanie IR co pozwoliło by na działanie np o zmroku Wykorzystanie np biblioteki TensorFlow a nie własnej implementacji SN ( skrócenie czasu pisania i eliminiacja ewentualnych błędów z implementacją sieci) Ps. Ciężko opisać wszystkie zagadnienia związane z budową tego modelu w 1-2 kartkach A4 i tak aby nie zanudzić kogoś szczegółami - mam nadzieje że opis nie jest zbyt lakoniczny ale też nie przesadziłem z dokładnością. Może kiedyś powstanie wersja poprawiona to udostępniona szerszy i dokładniejszy opis.
  9. 9 punktów
    Jakiś czas temu w moje ręce trafił dość specyficzny zabytek techniki - układ MCY7880, będący jedynym mikroprocesorem produkowanym seryjnie w Polsce. Element ten był klonem intelowskiego procesora 8080, wytwarzanym przez nieistniejące już przedsiębiorstwo CEMI. Początkowo potraktowałem go jako kolejną elektroniczną ciekawostkę do kolekcji, po jakimś czasie zacząłem się jednak zastanawiać, czy nie będę w stanie wykorzystać go w bardziej konstruktywny sposób. Zacząłem więc gromadzić pozostałe elementy potrzebne do zbudowania prostego systemu mikroprocesorowego, jednocześnie wczytując się w dokumentację i literaturę komputerową z epoki. Właściwa konstrukcja zaczęła powstawać niewiele później. Z uwagi na mocno eksperymentalny charakter przedsięwzięcia zdecydowałem się pominąć etap projektowania PCB i od razu przystąpić do montażu komputera na płytce prototypowej. Najpierw wlutowane zostały podstawki pod układy scalone, potem grubszą srebrzanką poprowadziłem masę i linie zasilające. Należy tutaj nadmienić, że MCY7880 jest dość kłopotliwym procesorem, jeśli chodzi o zasilanie. Nie tylko pobór prądu jest duży jak na obecne standardy, ale także konieczne jest dotarczenie trzech różnych napięć: +12, +5 oraz -5V. Dodatkowo muszą być one podane w odpowiedniej kolejności, niedopełnienie tego obowiązku grozi uszkodzeniem procesora. Oryginalnie systemy mikroprocesorowe na MCY7880 były zasilane z dużych zasilaczy transformatorowych. Była to pierwsza z kilku kwestii, co do których zdecydowałem się na drobny kompromis i zastosowałem nieco uwspółcześnione podejście. I tak napięcie 12V jest generowane przez przetwornicę boost na MC34063A, a -5V jest pobierane z pompy ICL7660. Głowna linia zasilająca o napięciu 5V jest zasilana bezpośrednio ze współczesnego, stabilizowanego zasilacza impulsowego. Po poprowadzeniu masy i zasilania, a także wlutowaniu wszystkich elementów pasywnych, przyszedł czas na najbardziej mozolny etap projektu. Łączenie linii sygnałowych przy pomocy kynaru. Bardzo dużej ilości kynaru. Zajęło mi to kilka wieczorów. O dziwo pomyliłem się tylko raz, zapominając o podciągnięciu jednego z wyprowadzeń EPROM-u do 5V. Po przebadaniu magistrali oscyloskopem i analizatorem stanów logicznych stwierdziłem, że procesor zachowuje się prawidłowo pracując "na luzie" (szyna danych pociągnięta w sposób wymuszający ciągłe wykonywanie instrukcji NOP i zwiększanie licznika instrukcji). Przyszedł więc czas na zaprogramowanie pamięci EPROM. Na potrzeby tego projektu zaopatrzyłem się w chiński programator oraz urządzenie do kasowania tych zabytkowych pamięci. Zapoznałem się także z podstawami asemblera 8080. Pierwszy napisany program służył rzecz jasna do migania diodą podłączoną do znajdującego się na płytce układu 8255. Potem zabrałem się za portowanie TinyBASIC-a, który po jakimś czasie udało mi się odpalić na tym komputerze. Obecnie POLON 7880 może komunikować się ze światem jedynie przez port szeregowy RS232, zrealizowany za pomocą układu 8251 oraz konwertera MAX232. W planach na bliżej nieokreśloną przyszłość jest budowa dodatkowej płytki z interfejsem monitora CRT i klawiatury, a być może także i sterownikiem stacji dyskietek. Pozwoliłoby mi to na uruchomienie systemu operacyjnego CP/M - organizacja pamięci komputera jest do tego przystosowana. Oczywiście najprostszym rozwiązaniem byłoby symulowanie układów I/O za pomocą jakiegoś współczesnego mikrokontrolera, wolałbym jednak wykorzystać w tym celu oryginalne układy scalone z epoki.
  10. 8 punktów
    Posiadając dwa futrzaki pojawiła się potrzeba zapewnienia im odpowiedniej ilości jedzenia, szczególnie podczas weekendowych wyjazdów. Przeglądając gotowe rozwiązania stwierdziłem, że najlepiej zbudować samemu mając przy tym sporo frajdy i satysfakcji. Urządzenie zostało zbudowane w oparciu o: Raspberry Pi Zero W Kamera do Raspberry Pi Serwo L360 Uchwyt na kamerę Czujnik odległości Główne cechy urządzenia Zdalna możliwość karmienia z dowolnego miejsca na świecie podgląd z ruchomej kamery ultradźwiękowy czujnik wykrywający kota oświetlenie IR pozwalające na podgląd w nocy możliwość wgrywania i odtwarzania dowolnych plików audio opcja "Text To Speach" duży 10 litrowy zbiornik na karę detekcja pustego zbiornika harmonogram automatycznego podawania karmy Pierwszym etapem i najtrudniejszym było wykonanie niezawodnego mechanizmu podającego karmę. Przetestowałem kilka rozwiązań: podajnik ślimakowy mechanizm koszykowy zasuwa podajnik tłokowy - to rozwiązanie sprawdziło się świetnie Układ podający powstał z ogólnodostępnych elementów PCV Niżej widok od tyłu pokazujący montaż tłoka Na filmie pokazana jest idea pracy mechanizmu, były to pierwsze próby ze słabszym serwomechanizmem. Ostatecznie został wymieniony na L360, a ruch obrotowy samego serwa zastąpiony ruchem "po łuku - przód, tył" co pozwoliło zapobiec ewentualnemu zakleszczeniu się karmy. Mechanizm - film Kolejnym etapem było wykonanie dodatkowej elektroniki obsługującej: 2 serwa do kamery 1 serwo podające karmę wzmacniacz audio czujnik odbiciowy IR czujnik zbliżeniowy Dodatkową wyzwaniem było przerobienie zwykłej kamery na kamerę NoIR, w tym celu zdemontowałem układ optyczny i delikatnie usunąłem filtr podczerwony. Poniżej wygląd matrycy po zdemontowaniu tych elementów. Po ponownym zamontowaniu soczewki, kamera działała już prawidłowo przy oświetleniu podczerwonym. Poniżej widok od spodu: Główne oprogramowanie sterujące sprzętem zostało napisane w pythonie, a interfejs użytkownika w PHP, na raspberry pi jest postawiony serwer www razem z mysql, tak więc jest to mały potworek do karmienia kotów. Sterowanie odbywa się przez stronę www, co wyeliminowało pisanie dedykowanej aplikacji na każdy z systemów osobno. Na koniec kilka dodatkowych zdjęć
  11. 8 punktów
    Pojawiło się zapotrzebowanie na zegar cyfrowy, który będzie miał duże cyfry, przynajmniej 8-10cm wysokości. Dodatkowym wymaganiem było to, że cyfry nie mogą być czerwone. Wykluczyło to praktycznie wszystkie wyświetlacze 7-segmentowe. Dodatkowo cena wyświetlaczy tej wielkości jest już znaczna, koszt 4 sztuk to wydatek mniej więcej 200zł. Z tego powodu powstał pomysł realizacji takiego zegara na diodach WS2812. Po wykonaniu wstępnych projektów, zegar miał mieć cyfry wysokości ok 14cm, po dwie diody na segment, a obudowa miała zostać wykonana na drukarce 3D. Cały układ sterujący miał się znaleźć pomiędzy cyframi godzin i minut, co znacznie ograniczyło miejsce na podzespoły. Na początku układ miał bazować na Atmedze 8, jednak po dłuższych poszukiwaniach zdecydowałem się na Attiny814. W sieci nie ma zbyt wielu materiałów na temat tego procesora, jednak jego dokumentacja jest chyba jedną z najlepszych, z jakich miałem okazję do tej pory korzystać. Ponieważ nie jestem fanem ustawiania godziny poprzez przyciski, to zegar miał mieć możliwość zdalnego sterowania. Ostatecznie wybór padł na moduł Bluetooth HM-10. Do odmierzania czasu użyty został zegar DS1307 wraz z baterią CR2032. Dodatkową funkcjonalnością jest pomiar temperatury poprzez ADC i czujnik LM35. Konieczny był także pomiar jasności otoczenia, aby umożliwić automatyczne dostosowywanie się jasności diod. Wykorzystany został do tego zwykły fotorezystor. Jak się okazało, kompilowanie programów na Attiny81x przez gcc i Makefile nie jest proste i oczywiste. Przede wszystkim konieczne jest wykorzystanie gcc w wersji 8.x, oraz trzeba pobrać odpowiednie pliki nagłówkowe ze strony atmela, ponieważ avr-libc ich (jeszcze) nie dostarcza. Kolejnym wyzwaniem był programator, ponieważ Attiny814 korzysta z interfejsu UPDI, nie da się go zaprogramować poprzez USBasp. Programatory UPDI są kilkadziesiąt razy droższe od Attiny814, dlatego mocno wskazane było znalezienie jakiejś alternatywy. Okazało się nią jtag2updi, pozwalające na programowanie poprzez konwerter USB-UART oraz dowolny procesor, przy czym autor dostarcza gotowe wsady do atmegi328p (arduino). Sporą wadą takiego rozwiązania jest brak możliwości korzystania z debuggera, ale z odrobiną cierpliwości i oscyloskopem dało radę i bez niego. Diody led połączone są w dwa łańcuchy, było to konieczne ze względu na budowę zegara, a także pozwoliło zoptymalizować czas pełnego odświeżenia wyświetlacza. Ważne było, aby przeładowywać wszystkie diody w czasie mniejszym niż czas trwania jednego bajtu wysyłanego poprzez UART z prędkością 9600 baud. Wynikało to z faktu, że diody mają bardzo niewielki czas trwania jednego bitu, wynoszący ok 1.25us, przez co konieczne było wyłączenie przerwań na czas przeładowywania diod. Diody WS2812 działają na tej zasadzie, że pierwsza dioda w łańcuchu odbiera 3 bajty (24 bity) danych, a każde kolejne ignoruje i przesyła dalej. W przypadku przerwy w transmisji dłuższej niż 50us stan transmisji jest resetowany i pierwsza dioda zaczyna ponownie odbierać 3 bajty dla siebie. Aby zapewnić czasy możliwie najbardziej zbliżone do tych w dokumentacji, funkcja odświeżająca diody została napisana w assemblerze. Ponieważ nie posiadam drukarki, która umiałaby drukować dwoma kolorami jednocześnie, to cyfry składają się z czarnego szkieletu oraz białych wkładek, wydrukowanych oddzielnie. Efekt jest całkiem dobry. Aby jeszcze nieco poprawić równomierność świecenia segmentów cyfry zostały od środka pomalowane farbą akrylową na biało. Z racji tego że każdy segment składa się z dwóch diód, to możliwe jest wyświetlanie dwukolorowe, dające całkiem ciekawy efekt, jednak z braku czasu na razie zegar jest w stanie świecić tylko na jeden wybrany kolor. Na zdjęciu powyżej niektóre segmenty są pomalowane farbą od środka, stąd te ciemniejsze ramki, ostatecznie wszystkie wkładki zostały wymienione na takie bez farby. Do sterowania zegarem napisana została aplikacja w React Native, pozwalająca na ustawianie czasu, koloru oraz dodatkowych efektów. Komunikacja odbywa się poprzez wspomniany wyżej Bluetooth. Wskaźniki jasności były przydatne głównie w fazie rozwoju zegara, między innymi do testowania korekcji gamma. W aktualnej wersji zegar nie wysyła już pomiarów, ale w razie czego możliwe jest ich przywrócenie. Ostatecznie pomiar temperatury okazał się dość nieskuteczny, ponieważ termometr jest w środku obudowy, to pokazuje temperaturę wyższą niż jest w rzeczywistości. Wynika to między innymi z faktu, że podzespoły w środku nie są idealne i wydzielają trochę ciepła, na tyle dużo że temperatura zawyżona jest o 2-3°.
  12. 7 punktów
    Artykuł przeznaczony do wszystkich zapaleńców druku 3D. Można nie kupować dość drogi filament do swojej drukarki 3D, a produkować w domu własny filament z zużytych butelek PET od napojów. Przy tym nieważne, jeżeli butelka jest pognieciona, ona również się nadaje do domowej produkcji filamentu. Filament z butelek ma sporo zalet w porównaniu z firmowym filamentem kupowanym – ABS albo PLA. Przede wszystkim, że produkowany filament nic nie kosztuje, jest po prostu darmowy Produkowany pręt filamentu Jest bardzo sztywny i absolutnie nie łamliwy, wytrzymuje sporo ostrych przegięć. Filament własnej produkcji jest sporo mocniejszy i twardszy, jak na rozciąganie tak i o wiele bardziej odporny na uderzenie. Absolutnie nie pochłania wody, czyli nie trzeba go ani suszyć, ani chronić w zamkniętym zabezpieczonym od nawilżania się opakowaniu. Praktycznie nie skurcze się przy ochłodzeniu w trakcie druku. Nie wymaga chłodzenia drukowanej warstwy. Nie wymaga stołu podgrzewanego. Dla przyczepności wystarczy miejsce na stole posmarować cienką warstwą kleju w sztyfcie na przykład typu „Glue Stick” Wydrukowane detal można obklejać od razu po skończeniu wydruku. Taki filament jest bardzo odporny na działanie rozpuszczalników i środków chemicznych. Jak widać filament produkcji własnej ma sporo zalet w porównaniu z filamentami kupowanymi, a najważniejsze – że jest darmowy. Niżej przedstawiono zdjęcia maszynki do produkcji filamentu: Do domowej produkcji filamentu wykorzystywane zużyte butelki od napojów. Ale butelki muszą być czyste, resztki kleju do nalepki powinni być usuwane. Technologia produkcji jest bardzo prosta i składa się z trzech następujących operacji: Poprawa zgniecionych butelek i butelek z ryflowaną powierzchnią tak, żeby ścianka boczna butelki była gładka. Nacinanie butelek na paski o określonej szerokości, od 5mm do 12mm w zależności od grubości ścianki butelki. Produkcja pręta filamentu z nacinanych pasków na specjalnej maszynce z nawijaniem na bębenek odbiorczy. Na tych wideo można obejrzeć prace maszynki i przyrządu do nacinania pasków z butelek: Zębatka drukowanie:
  13. 7 punktów
    Skoro forum powoli zmienia profil i przestajemy się skupiać na robotach, to postanowiłem, że zrobię sobie tutaj trochę bezczelnej reklamy i napiszę o projekcie, nad którym pracowałem od jakiegoś roku, który choć związany z mikrokontrolerami i programowaniem, robotem stanowczo nie jest. Zaczęło się mniej więcej rok temu, kiedy wpadłem na pomysł jak można sprawić, żeby nauka języka Python była znacznie łatwiejsza, mniej problematyczna oraz przede wszystkim fascynująca. Micro:bit i Raspberry Pi pokazały, że programowanie dedykowanego urządzenia daje bardzo dużo radości oraz poczucie kontroli nad techniką — moim zdaniem bardzo ważne rzeczy przy uczeniu jakichkolwiek technicznych tematów. Niestety, moje doświadczenia z przeróżnych szkoleń i warsztatów pokazały także achillesową piętę takiego podejścia: zawsze coś nie działa. Ludzie przychodzą z własnymi laptopami, niektórzy mają na nich poinstalowane jakieś Windowsy czy inne Makoesiksy, połowa z nich nie potrafi zainstalować sterownika, druga połowa akurat miała system update i sterownik im przestał chodzić, trzecia połowa dopiero ściąga prze konferencyjne WiFi środowisko uruchomieniowe i kompilator, a czwartej połowie nie chcą zainstalować się biblioteki. W efekcie ponad połowa czasu zawsze jest tracona na ustawianie wszystkiego. Do tego kiedy już uczniowie napiszą te swoje gry i będą chcieć się nimi pochwalić, to nie będą mogli — bo działają tylko na ich komputerze gdzie jest wszystko zainstalowane, a uruchomienie na komputerze kolegi wymaga przechodzenia całego procesu ponownie. Koszmar. Zatem postanowiłem zrobić urządzenie dedykowane do pisania gier, usuwając przy tym z drogi jak najwięcej przeszkód tak, aby można się było skoncentrować na celu — czyli samym programowaniu — bez wszystkich dodatkowych problemów. Początkowo stworzyłem shield dla płytek sprzedawanych przez Adafruit, zawierający przyciski i prosty kolorowy wyświetlacz LED 8x8, aby dało się pisać gry w rodzaju snake-a czy tetris-a. Jednak nie było to jeszcze rozwiązanie idealne, choć pozwoliło mi zbadać co działa, a co nie, oraz doszlifować moje umiejętności. Dzisiaj udostępniam szerszej publiczności moje najnowsze dzieło, czyli "prawdziwą" przenośną konsolę do gier. Zawiera ona kolorowy ekran 128x128, głośniczek, 6 przycisków i mikrokontroler programowany w CircuitPythonie. Urządzenie po podłączeniu do komputera widoczne jest jako dysk USB, nie wymagając przy tym żadnych sterowników (chyba, że ktoś ma Windows 7, wtedy niestety konieczne jest zainstalowanie sterownika aby mieć dostęp do konsoli na porcie szeregowym), a programujemy je po prostu edytując widoczne na nim pliki (lub kopiując je z komputera, oczywiście). Wbudowana w firmware prosta biblioteka do obsługi duszków i kafelków ułatwia zadanie. Grafika jest trzymana w plikach BMP, dźwięki w plikach WAV, kod w plikach tekstowych — zatem można użyć dowolnego programu jaki akurat się ma dostępny i jaki umie się już obsługiwać. Więcej informacji o projekcie, wraz z logami z jego konstruowania można znaleźć na https://hackaday.io/project/27629 Tylko, że co daje taki projekt zrobiony dla siebie do szuflady? Oczywiście wszystko jest opisane i opublikowane na otwartych licencjach, ale szanse na to, że ktoś inny zbuduje takie urządzenie są w zasadzie znikome. Aby było ono rzeczywiście przydatne, ludzie muszą go używać, a zatem musi być ono dostępne w sprzedaży. Dlatego kolejnym moim krokiem było zlecenie wyprodukowanie małej serii tych urządzeń. Dzisiaj właśnie przyszła paczka z fabryki i rozpoczynam ich sprzedaż na Tindie. Jest ich tylko 50, nie liczę na zbicie na tym kokosów, ale być może uda się zbudować społeczność zainteresowaną programowaniem tych urządzeń. Oczywiście jak na polskie warunki cena jest wysoka — niestety tak to jest z produkowaniem małych serii niestandardowych urządzeń. Ale być może kogoś jednak to zainteresuje: https://www.tindie.com/products/deshipu/game-10-game-console-kit/ Wreszcie, żeby nie było, że to tylko taka reklama i komercja, bardzo chętnie pomogę ludziom chcącym zbudować swoją własną wersję tej konsoli. Nie trzeba do tego wytrawiać płytek i lutować elementów montowanych powierzchniowo — wystarczy dowolna płytka rozwojowa z mikrokontrolerem SAMD21, moduł wyświetlacza, kilka przycisków, trochę kabelków, kostka pamięci flash i opcjonalnie głośniczek lub słuchawki.
  14. 7 punktów
    Cześć. Chciałbym przedstawić wam mój projekt robota samobalansującego. Jest to mój najbardziej zaawansowany jak dotąd projekt, który pochłonął najwięcej pracy. Pomysł na zbudowanie takiego robota zrodził się w mojej głowie w wakacje po obejrzeniu filmiku przedstawiającego podobną konstrukcję. Pracę nad nim rozpocząłem jeszcze w wakacje, a z przerwami zakończyłem w lutym. Działanie robota jest podobne do dostępnych na rynku Hoverboardów, czyli robot ma za zadanie poruszać się w taki sposób, aby utrzymać się w pionie, oczywiście bez podpierania. Konstrukcję robota zaprojektowałem sam i wykonałem z pręta gwintowanego i plexi. Uznałem że taka konstrukcja zapewni robotowi wymaganą sztywność i niską masę, jednocześnie nie rujnując budżetu. Najpierw wykonałem jej model w Fusion 360, a później przystąpiłem do pracy. Roboty z tym trochę było, bo obróbka plexi do łatwych nie należy. Sporo czasu zajęło przycięcie prostokątów, a jeszcze więcej wywiercenie otworów, które musiały być idealnie rozmieszczone, aby później dało się przełożyć przez nie pręt gwintowany. Po zbudowaniu ramy przyszła pora na elektronikę. Ponieważ robot nie zapewnia dużo miejsca, a jednocześnie środek ciężkości powinien być możliwie wysoko, dla ułatwienia balansu, musiałem się postarać ścisnąć wszystko jak to tylko możliwe. Baterię zasilającą robota (ogniwe Li-Po odzyskane z powerbanka o pojemności 3000 mAh) umieściłem na najwyższej półce. Tam również trafiła przetwornica step-up podnosząca napięcie do 7,4 V. Wiem że lepiej byłoby dać dwie baterie połączone szeregowo, ale w momencie budowania budżet na to nie pozwolił. Szybko okazało się że jedna przetwornica to za mało - Arduino restartowało się przy każdym uruchomieniu silnika, nawet jeśli do układu przyłączyłem bardzo duży kondensator. Dodałem więc drugą - teraz silniki były zasilanie niezależnie od elektroniki sterującej. Pozwoliło to stanąć robotowi po raz pierwszy, jednak wciąż jedna przetwornica zasilająca silniki ograniczała ich moc. Dodałem drugą, co nieco poprawiło sytuację, jednak wciąż nieco ogranicza silniki. Póki co szukam lepszego rozwiązania. Schodząc na niższą półkę. Tam trafiła płytka ze sterownikiem i druga z mostkiem H. Pierwszą płytkę lutowałem sam na płytce uniwersalnej - zajęło to kilka godzin i mnóstwo cyny, ale satysfakcja była nie do opisania, zwłaszcza że wszystkie połączenia wykonałem cyną. Po spędzeniu kolejnej godziny na pozbywaniu się zwarć układ był gotowy do testów Robot aby ustalić swoją pozycję korzysta z modułu żyroskopu i akcelerometru MPU6050 oraz wbudowanych w silniki enkoderów. Dane z tych czujników trafiają do Arduino Nano które poprzez układ L298N steruje dwoma silnikami. Dzięki akcelerometrowi i żyroskopowi robot zna swój kąt przechylenia. W pierwszych wersjach kodu szybko okazało się, że to nie wystarczająco, ponieważ o ile robot stał, to cały czas przesuwał się w jedną stronę. Wynika to z tego że konstrukcja nie jest idealnie wyważona, a robot nie zna swojej pozycji, jedynie kąt nachylenia, więc jeżeli ustawiony na sztywno kąt odbiegał od kąta balansu, robot "dryfował". Aby temu zapobiec dodałem drugie sprzężenie zwrotne, tym razem oparte o enkodery przy silnikach. Enkodery zliczają ilość impulsów które silniki wykonały w każdą ze stron, a oprogramowanie dąży, aby ich różnica była równa 0. Pierwsze próby nie były zbyt udane. Kiedy doprowadziłem kod do stanu w którym robot chociaż próbował się utrzymać, udawało mu się to przez maksymalnie kilkanaście sekund. Jednak wraz z poprawianiem kodu robot stał dłużej i dłużej. Obecnie już się nie wywala, jednak mostek H po dłuższym staniu się przegrzewa, więc czas pracy ograniczony jest do kilku minut. Mimo to robot robi duże wrażenie, chociaż z pewnością nie jest idealny. Zastosowałem tanie chińskie silniki, i jak się okazało, jeden obraca się szybciej niż drugi, więc robot obraca się w jedną stronę. Do tego jak wspomniałem przegrzewa się, a silnikom brakuje momentu, więc robot się trzęsie zamiast stać idealnie prosto. Są to jednak problemy które mam w planach poprawić. Planuję dodać również możliwość sterowania po BT (już nawet na płytce jest miejsce na moduł HC-06), ale na razie nie miałem czasu. Oto filmik prezentujący działanie robota:
  15. 7 punktów
    Witajcie. Chciałbym Wam przedstawić prosty sposób wykorzystania modułu ESP-32, który użyłem do stworzenia urządzenia, za pomocą którego możecie śledzić poziom zainteresowania wybranym repozytorium GitHub. Dzięki wbudowanym dwóm wyświetlaczom, będziecie na bieżąco informowani o: aktualnej liczbie gwiazdek dziennej liczbie gwiazdek aktualnej liczbie obserwujących aktualnej liczbie forków Początkowo chciałem skorzystać ze starszego modułu ESP8266 12-F, jednak napotkałem problem który objawiał się przy wykonywaniu requesta do api GitHub. Podczas oczekiwania na odpowiedź z serwera, na wyświetlaczach zanikały wszystkie cyfry i wyglądało to jakby coś było nie tak z urządzeniem. Z pomocą przyszedł układ ESP-32, który oparty jest na dwóch rdzeniach. Była to świetna okazja aby zapoznać się z tym modułem, ponieważ wcześniejsze projekty wykonywałem na ESP8266. Użycie nowszej odsłony ESP, pozwoliło mi wysyłać requesty asynchronicznie. Do działania ramki wymagane jest połączenie z siecią poprzez WiFi. Tutaj świetnie sprawdziła się biblioteka "WiFi Manager", która umożliwiła mi szybkie podłączenie ramki do dowolnej sieci. Jeżeli chodzi o zasilanie to jest to napięcie 5V, które podaje poprzez wtyki USB. W obudowie ramki znajdują się trzy przyciski. Pierwszy służy jako włącznik. Pozostałe dwa to włączniki chwilowe. Po wciśnięciu pierwszego na wyświetlaczu prezentowany jest adres IP, który wykorzystujemy przy konfiguracji. Natomiast drugi przycisk resetuje liczbę gwiazdek z dnia. Do układu podłączona jest 3 kolorowa dioda LED, która informuje nas o stanie połączenia: CZERWONY – brak sieci, błąd podczas pobierania danych ZIELONY – połączenie sieciowe ustanowione, dane pobrane poprawnie NIEBIESKI – tryb access pointu ( zanik sieci ) Domyślnie odświeżanie danych odbywa się co 90 sekund. Oczywiście interwał można zmienić. Ale należy uważać, aby nie wykonywać do api GitHub więcej niż 60 requestów na godzinę, ponieważ serwer ma ustawiony RateLimit. Po przekroczeniu ilości zapytań zostaniemy zablokowani na godzinę. Jak już wspomniałem wyżej, pod adresem IP jaki przydzielony został do urządzenia działa prosty web server, który serwuje nam stronę z konfiguracją, gdzie musimy wprowadzić nazwę użytkownika repozytorium oraz nazwę repozytorium które chcemy obserwować. Po zapisaniu konfiguracji w pamięci EEPROM urządzenie jest restartowane i gotowe do użycia. Dodatkowym atutem urządzenia jest automatyczna aktualizacja oprogramowania poprzez HTTPS OTA. Sprawdzanie wersji następuje podczas uruchomienia oraz po północy. Urządzenie jest w pełni bezobsługowe. Gdy wystąpi zanik sieci, ESP cały czas będzie próbowało nawiązać połączenie za pośrednictwem zapamiętanych poświadczeń. Jeśli sieć nie będzie dostępna, przełączy się w tryb access pointu ( ssid: "GITHUB-FRAME"). Jeśli nie zostanie wybrana nowa sieć w menadżerze sieci, to po czasie 3 minut, nastąpi restart i proces się powtórzy. Tak pokrótce, wygląda zasada działania całego układu. Poniżej przedstawię Wam główne etapy budowy całej ramki. A więc zaczynamy. LISTA ELEMENTÓW: ESP-32 WROOM DevKit 1.0 – 1 szt. Wyświetlacz LED 4-Cyfrowy TM1637 – 0.56" – 1 szt. Wyświetlacz LED 4-Cyfrowy TM1637 - 0.36" – 1 szt. 4-pinowy przewód, żeński – żeński – raster 2.54 – 4 szt. Gniazdo + wtyk, JST – JST – 2 szt. Gniazdo + wtyk, mikro JST – mikro JST – 2 szt. Płytka uniwersalna PCB 50x70mm PI-01 – 1 szt. Rezystor węglowy – 220 ohm – 5 szt. Rezystor węglowy – 2,2k ohm – 3 szt. Zworki do płytek stykowych - 1 zestaw Wtyk goldpin kątowy 4 pinowy, raster 2,54mm – 4 szt. Dioda LED 5mm RGB wsp. Anoda – 1 szt. Dioda LED 3mm biała – 3 szt. Przełącznik chwilowy okrągły – 10mm – 2 szt. Przełącznik kołyskowy ON-OFF – 1 szt. Kabel USB A – USB micro – 1 szt. Zasilacz 5V z gniazdem USB A – 1 szt. Rurki termokurczliwe - 1 szt. Ramka IKEA RIBBA – 21x30cm ( ważne żeby była dość głęboka, aby zmieścić elektronkę ) – 1 szt. Papier samoprzylepny do drukarki – 1 szt. Rura elektroinstalacyjna RLM 16 – 1 szt. NARZĘDZIA: Lutownica Cyna Obcążki Wiertarka lub wkrętarka Wiertła: 7, 10, 13 Pistolet do kleju na gorąco Nóż Drukarka ZAŁOŻENIA: Stabilność działania Intuicyjna obsługa Szybka adaptacja w miejscu instalacji Estetyka Plan Początkowo ramka miała powstać pod konkretnie wybrane repozytorium i wyświetlać tylko liczbę gwiazdek. Ale stwierdziłem, że i tak pobieram inne dane z endpointa api to czemu miałbym ich nie wyświetlić. Postanowiłem, że dodam dwa nowe klucze: "forks" oraz "watchers" i wyświetlać je kolejno w 5 sekundowym odstępie czasowym. Jeżeli chodzi o repozytorium, to dając możliwość wprowadzenia własnych ustawień url-a, zwiększyłem tym samym skalowalność przedsięwzięcia. Do tego doszły automatycznie aktualizacje software-u. Więc taką ramkę może stworzyć każda osoba, która chociaż trochę ma pojęcie o informatyce i niekoniecznie zna się na programowaniu. BUDOWA Prace nad ramką rozpocząłem od budowy prototypu metodą na "pająka". W tym celu skorzystałem z płytki prototypowej, przycisków typu "tact switch", paru zworek oraz kilkunastu przewodów do połączenia wszystkiego w całość. Całe oprogramowanie zostało napisane za pośrednictwem Arduino IDE czyli w języku C. Gdy miałem już działający prototyp, rozpocząłem prace nad przeniesieniem całości na uniwersalną płytkę PCB. Zadanie wydawałoby się proste ale wymagało procesu planowania. W tym celu wykorzystałem oprogramowanie Fritzing. Oprogramowanie to umożliwia stworzenie całej dokumentacji projektu. Na tę chwilę wykorzystałem tylko narzędzie do stworzenia szkicu płytki prototypowej. Mając gotowy już projekt z rozlokowaniem wszystkich elementów i połączeń. Mogłem przystąpić do lutowania. Jak widać na zdjęciach, podczas montażu elementów używałem uchwytu, który stabilnie trzyma płytkę w miejscu. Bardzo ułatwił mi pracę. Po przylutowaniu wszystkich elementów elektronicznych, wlutowałem przewody z gniazdami, dzięki którym będę mógł odłączyć układ od samej konstrukcji ramki Teraz przyszedł czas na najtrudniejszy etap jakim było dostosowanie drewnianej ramki do potrzeb projektu. W programie Photoshop stworzyłem szablon do wiercenia i wycinania potrzebnych otworów. Szablony te znajdziecie również w repozytorium projektu. Po wydrukowaniu szablonu przykleiłem kartkę do “pleców ramki” i wyciąłem wszystkie otwory. Trochę trzeba się do tego przyłożyć i mieć sporo cierpliwości. Cięcie, pasowanie, cięcie, pasowanie aż do skutku. Ufff. W końcu mogłem przystąpić do zamontowania wyświetlaczy oraz diod LED. Z pomocą przyszedł mi klej na gorąco. Trzyma mocno i pewnie, wystarczająco do tego typu prac. Trzy diody LED umieściłem w przyciętych krążkach z białej rury pcv ( tych do prowadzenia przewodów po ścianach ) a górę zaślepiłem kawałkiem plastiku w którym zamocowałem diody. A tak całość prezentuje się od frontu Za pomocą 4 żyłowych przewodów zakończonych wtykami żeńskimi, połączyłem wszystkie elementy z główną płytką. W celu szybszej identyfikacji przewodów, oznaczyłem każde połączenie za pomocą lakierów do paznokci ( pozdrawiam swoją żonę Magdalenę ). Główny układ przykleiłem do pleców ramki również za pomocą kleju na gorąco. Na koniec pomalowałem cały front na biało farbą emulsyjną, ponieważ papier który używa się w drukarkach ma małą gramaturę co sprawia, że jest półprzezroczysty. Dzięki podbiciu koloru tła biel będzie intensywniejsza. W ostatecznej wersji grafikę wydrukowałem na papierze fotograficznym, który jest na tyle gruby, że malowanie okazało się być zbędne. SOFTWARE Cały program opiera się na dwóch pętlach. Pierwsza pętla Task1, sprawdza czy użytkownik wprowadził url repozytorium z którego mają zostać pobrane dane. Jeżeli konfiguracja została wprowadzona, program wywołuje funkcję getData(), która odpowiedzialna jest za pobranie danych z API. Interwał tej pętli definiuje zmienna requestInterval, która domyślnie posiada wartość 90 ( czyli 90 sekund). Druga pętla Task2, służy do wyświetlania odpowiednich danych na wyświetlaczach oraz podświetlania ikon. Tutaj również sprawdzany jest stan na pinach 27 i 15 ( przyciski BUTTON_IP oraz BUTTON_RESET_TODAY). Interwał tej pętli to około 15 sekund. Po północy następuje sprawdzenie dostępności nowszej wersji oprogramowania oraz resetowany jest licznik gwiazdek otrzymanych w ciągu całego dnia. Poniżej znajdziecie link do repozytorium z projektem: OPROGRAMOWANIE + SZABLONY DO DRUKU PODSUMOWANIE Przyznam się szczerze, że prototyp urządzenia miałem już gotowy rok temu. Ale ze względu na gruntowny remont mieszkania musiałem odsunąć hobby na dalszy plan. Rozciągnięcie projektu w czasie sprawiło, że przy każdym powrocie zawsze coś zmieniałem, rozbudowywałem. Wszystko wtedy można przemyśleć kilka razy i na spokojnie zastanowić się nad rozwiązaniem jakiegoś problemu. Na co dzień zajmuję się programowaniem front-endu, ale dzięki takim projektom mogę połączyć moje główne zainteresowania: majsterkowanie, elektronikę, grafikę i jak już wcześniej wspomniałem, programowanie i stworzyć coś namacalnego i cieszącego oko. Zachęcam wszystkich do twórczego działania i poszerzania swojej wiedzy. Tego typu projekty dadzą Wam satysfakcję, świetną zabawę oraz sporo nauczą. Także klawiatury, lutownice, piły, śrubokręty, wiertarki w dłoń i do działania! Instrukcję już macie Do następnego projektu! Pozdrawiam.
  16. 7 punktów
    Jakiś czas temu na forum pojawiło się kilka wpisów krytykujących Raspberry Pi jako platformę sprzętową. Nie próbuję nawet wmawiać, że malinka jest idealna - jednak niektóre problemy można rozwiązać bardzo (albo chociaż dość) łatwo. Problemy o których piszę to np. zużywanie kart SD, długi czas uruchamiania płytki, problemy z systemem plików jeśli nagle odłączymy zasilanie, długi czas kompilacji programów, czy brak możliwości uruchomienia systemu z pamięci USB. Wiele z opisanych niedogodności wynika ze sposobu używania malinki. Większość osób stara się zrobić z niej mały komputer PC - i nie ma w tym nic złego, w końcu na Forbocie właśnie tak opisywaliśmy kurs Raspberry Pi. Jednak malinka nie we wszystkim może zastąpić komputer stacjonarny i czasem nieco inne podejście może dawać nieco lepsze rezultaty. Komputer stacjonarny, a komputer wbudowany Pierwsza istotna sprawa to rozróżnienie między rozwiązaniami wbudowanymi (embedded), a komputerem stacjonarnym (desktop/laptop). Urządzenia wbudowane są konstruowane do spełniania jednej, z góry określonej funkcji - przykłady to procesor w ekspresie do kawy, bankomacie, czy samochodzie. Oprogramowanie można aktualizować, nawet zmieniać na własne (tym zajmują się hackerzy), ale nadal program ma ściśle określone zadanie do wykonania. System ogólnego przeznaczenia, to nasze komputery stacjonarne lub przenośne - czyli zupełne przeciwieństwo wbudowanych. Można na nich grać w pasjansa, Wiedźmina, a nawet inne gry, przeglądać internet, pisać programy i robić miliony innych rzeczy. Instalacja nowych programów jest łatwa, niekiedy nawet udaje się je odinstalować. Arduino jest kolejnym przykładem platformy wbudowanej. Program kompilujemy na PC, wgrywamy na płytkę i ma on wykonywać to co sobie zaplanowaliśmy - migać diodą, sterować robotem, itd. Ale już nowych progamów nie dodamy, nie będziemy na Arduino kompilować kodu, ani grać w pasjansa (chyba że to jest główna funkcja naszego układu). Raspberry Pi natomiast jest najczęściej używane jako mały komputer PC. Instalujemy na karcie SD Raspbiana (lub inną dystrybucję) i dalej używamy tak samo jak komputer stacjonarny. Może gier jest mniej, ale minecraft działa całkiem fajnie, RetroPie pozwala na emulację starych komputerów i konsol, a użwanie kompilatora (np. gcc) nikogo nie dziwi. Raspberry Pi całkiem dobrze sobie z takimi zadaniami radzi, ale to wbrew pozorom nadal głównie komputer wbudowany. W niniejszym artykule chciałbym chociaż wprowadzić w nową opcję, czyli użycie malinki jako komputera wbudowanego - mającego jedno zadanie, które dobrze wykonuje. System operacyjny Wszyscy wiemy jak działa Raspberry Pi - na karcie SD mamy ulubioną dystrybucję, kartę umieszczamy w czytniku, podłączanie zasilanie, czekamy, chwilę jeszcze czekamy, a może jeszcze jedną chwilę... i mamy pulpit z ikonkami albo chociaż konsolę do wydawania poleceń. Programy pobieramy z sieci (repozytorium), apt jest prosty i sympatyczny w użyciu. A gdybyśmy tak spróbowali przygotować własną, mniejszą ale dopasowaną do naszych potrzeb wersję systemu? Okazuje się że nie jest to aż tak trudne (chociaż proste też nie jest), w nagrodę będziemy za to mogli pozbyć się problemów o których wspominałem na początku artykułu. Yocto Własną dystrybucję Linux-a można przygotować zupełnie od podstaw - zaczynając od kompilacji kompilatora. Jest to jednak dość złożony proces, świetny do nauki, ale niekoniecznie wygodny. Na szczęście znajdziemy gotowe projekty przygotowujące naszą dystrybucję linuksa od podstaw. Buildroot (https://buildroot.org/) jest jednym z takich projektów - pozwala on na łatwe wybranie potrzebnych nam programów oraz ich skompilowanie ze źródeł. Ostatnio coraz większą popularność zyskuje jednak inny projekt - Yocto (https://www.yoctoproject.org/). Działa o wiele wolniej niż buildroot (jak to z narzędziamy opartymi o Pythona bywa), ale lepiej sprawdza się w dużych projektach. W następnym wpisie postaram się opisać jak można użyć Yocto to przygotowania własnej wersji systemu dla malinki. Jeszcze dwa słowa odnośnie buildroot-a. Dawno, dawno temu opisywałem jak użyć go podczas instalowania linuksa na netbook-u domyślnie pracującym z Androidem: https://forbot.pl/blog/sprawdz-jak-tanio-zbudowac-robota-z-systemem-linux-id7751 To co chcę teraz opisać to bardzo podobne rozwiązanie, ale zamiast netbook-a jest Raspberry Pi, a rolę Androida zajmuje Raspbian. No i po tych kilku latach yocto uzyskało pewną przewagę na buildrootem, więc też będzie użyte. Szybki start Żeby nie zanudzić najpierw szybki i dość ogólny opis. Celem będzie utworzenie podstawowego obrazu systemu, z którego wystartuje malinka. Najpierw należy przygotować odpowiedni komputer PC oraz system operacyjny. System to oczywiście Linux - wspierane są dystrybucje Debian, Ubuntu, Fedora, OpenSUSE oraz CentOS. Prawdopodobnie użycie innej dystrybucji jest też możliwe, może jednak wymagać dodatkowych kroków. W zależności od posiadanej wersji musimy zainstalować odpowiednie pakiety oprogramowania, wszystko znajdziemy opisane tutaj: https://www.yoctoproject.org/docs/2.5/ref-manual/ref-manual.html#required-packages-for-the-host-development-system Yocto można używać w systemie Windows lub MacOS wykorzystując maszynę wirtualną. Jednak takie rozwiązanie ma znaczącą wadę - bardzo spowalnia i tak czasochłonną kompilację obrazu systemu. Nie polecam takiego rozwiązania, lepiej używać natywnego linux-a i poszukać możliwie mocnego komputera - 4 rdzenie to raczej minimum, ale yocto potrafi nawet 44 wykorzystać (tyle testowałem), więc im silniejszy komputer tym lepiej i szybciej - a maszyny wirtualne pod względem wydajności niestety nie oszałamiają. Oprócz szybkiego procesora o możliwie wielu rdzeniach, będziemy potrzebowali również sporo miejsca na dysku. Minimum to ok. 30 GB, ale nieco bardziej rozbudowana konfiguracja może potrzebować i 100GB. Oczywiście szybki dysk ma swoje zalety, więc jeśli mamy miejsce na dysku SSD, warto go użyć. Ja wykorzystuję dysk SSD podłączany przez USB. To całkiem wydajne rozwiązanie, a możliwość odłączenia dysku od stacji roboczej i podłączenia do laptopa bardzo się przydaje. Dlatego u mnie ścieżka do projektu jest nieco długa: /mnt/usbssd/raspberry/yocto W tym katalogu należy pobrać sam projekt yocto, czyli wykonać: git clone -b sumo git://git.yoctoproject.org/poky.git Potrzebne będą jeszcze dwie tzw. warstwy, czyli powiedzmy biblioteki: meta-openembedded oraz meta-raspberrypi. Pobiera się je poleceniami: git clone -b sumo git://git.yoctoproject.org/meta-raspberrypi git clone -b sumo git://git.openembedded.org/meta-openembedded Teraz w katalogu /mnt/usbssd/raspberry/yocto znajdziemy trzy podkatalogi: poky, meta-raspberrypi, meta-openembedded. Pierwszy z nich jest dla nas najważniejszy więc wchodzimy do niego, a następnie wczytujemy zmienne ze skryptu oe-init-build-env: cd poky source oe-init-build-env Na ekranie widzimy podpowiedź co zrobić dalej, jednak zanim do tego przejdziemy musimy poprawić domyślną konfigurację yocto. Plik conf/bblayers.conf zawiera listę wybranych wartstw (bibliotek). Musimy dopisać używane przez nas, dopisujemy więc: BBLAYERS ?= " \ /mnt/usbssd/raspberry/yocto/poky/meta \ /mnt/usbssd/raspberry/yocto/poky/meta-poky \ /mnt/usbssd/raspberry/yocto/poky/meta-yocto-bsp \ /mnt/usbssd/raspberry/yocto/meta-raspberrypi \ /mnt/usbssd/raspberry/yocto/meta-openembedded/meta-oe \ /mnt/usbssd/raspberry/yocto/meta-openembedded/meta-multimedia \ /mnt/usbssd/raspberry/yocto/meta-openembedded/meta-networking \ /mnt/usbssd/raspberry/yocto/meta-openembedded/meta-python \ " Kolejny krok to edycja głównego pliku konfiguracyjnego o nazwie conf/local.conf. Domyślnie zawiera on dużo komentarzy, uproszczona wersja wygląda następująco: MACHINE = "raspberrypi3-64" DL_DIR = "${TOPDIR}/downloads" DISTRO ?= "poky" PACKAGE_CLASSES ?= "package_ipk" EXTRA_IMAGE_FEATURES ?= "debug-tweaks" USER_CLASSES ?= "buildstats image-mklibs image-prelink" CONF_VERSION = "1" RPI_USE_U_BOOT = "1" ENABLE_UART = "1" Pierwsza linia ustala typ naszej "maszyny", czyli Raspberry Pi 3 w wersji 64-bitowej. Jeśli używamy innej wersji, musimy odpowiednio zmodyfikować ten wpis. Co ciekawe cała dystrybucja będzie wykorzystywała ustawienia zoptymalizowane dla naszgo procesora - domyślnie Raspbian jest kompilowany tak, aby programy działały na najmniejszym wspólnym mianowniku, czyli starym Raspberry 1 - używając yocto nie tylko jądro, ale i cały system zostanie skompilowany pod nasze potrzeby. Nie zadziała na starszych płytkach, ale na naszej wykorzysta jej potencjał. Kolejny ważny parametr to ustawienie RPI_USE_U_BOOT. Dzięki niemu zostanie użyty bootloader u-boot, co pozwoli na załadowanie systemu przez sieć (TFTP), podłączenie dysku sieciowego (NFS), albo nawet użycie pamięci USB. Jest to pierwszy etap pozwalający na pozbycie się usterek na które wiele osób narzeka. W tym pliku można również wymusić użycie systemu "tylko do odczytu". Jedna dodatkowa linijka i karta SD będzie działać prawie w nieskończoność - do tego wrócimy później. Na razie czas zacząć kompilację i zrobić sobie (długą) przerwę. Wydajemy polecenie: bitbake core-image-minimal Yocto pobierze z sieci źródła wszystkich programów a następnie je skompiluje. Taki proces wymaga szybkiego łącza i trwa... od 20min do 4h. Na szczęście później jest już szybciej, ale za pierwszym razem można sobie zrobić przerwę na lunch. Po zjedzeniu lunchu, albo chociaż przerwie mamy gotowy obraz naszego systemu. Wynikowe pliki znajdziemy w katalogu tmp/deploy/images/raspberrypi3-64: Tym co na początek nas zainteresuje to plik z gotowym obrazem całej karty SD, czyli core-image-minimal-raspberrypi3-64.rpi-sdimg. Warto zwrócić uwagę na wielkość obrazu - u mnie wyszło 56 MB. To nadal bardzo dużo, ale domyślny Raspbian wymaga kilku GB. Kartę SD przygotujemy poleceniem dd, u mnie urządzenie /dev/sdh odpowiada karcie, więc polecenie: sudo dd if=tmp/deploy/images/raspberrypi3-64/core-image-minimal-raspberrypi3-64.rpi-sdimg of=/dev/sdh bs=4M Pozwala na nagranie obrazu na nośnik. Teraz można umieścić kartę w czytniku Raspberry Pi i wystartować system: Uruchomienie sytemu zajmuje znacznie mniej czasu niż w przypadku domyślnego systemu. To nadal bardzo daleka od optymalnej konfiguracja, ale i tak linux jest gotowy do pracy w kilka sekund. To co otrzymaliśmy to pierwsza, minimalna wersja systemu - mała ale zoptymalizowana dla naszego sprzętu. Nie znajdziemy na niej minecrafta, ani nawet interfejsu graficznego, ale to co wybraliśmy działa szybko i wydajnie. Mając taki system jako punkt wyjścia możemy przygotować bardziej rozbudowaną wersję, wyposażoną w potrzebne nam programy i biblioteki. Warto natomiast zwrócić uwagę na nieco inny sposób pracy z systemem. Całą kompilację wykonujemy na komputerze stacjonarnym, malinka tylko wykonuje przygotowane programy. Działa więc tak jak Arduino, a nie typowy Raspbian.
  17. 7 punktów
    Zdecydowałem się przestawić swój kolejny projekt utrzymany w klimatach retro. Wszystko zaczęło się jakiś rok temu, gdy przypadkowo odkryłem, że sprzedawcy na popularnych chińskim serwisie aukcyjnym posiadają podejrzanie duże ilości podejrzanie tanich układów MOS6502. Wydało mi się to zbyt piękne, aby było prawdziwe. Z ciekawości zamówiłem kilka sztuk, płacąc za nie kilka dolarów i zapomniałem o całej sprawie, licząc na to, że pewnie otrzymam podróbki z wygrawerowanymi laserowo oznaczeniami. Jak bardzo się myliłem! Po uruchomieniu na płytce prototypowej okazały się być prawdziwymi układami MOS6502, wykonanymi w technice NMOS. Zabrałem się więc za projektowanie właściwej płytki, myśląc o stworzeniu swojego własnego komputera pracującego pod kontrolą języka BASIC. Ten projekt ciągle jest w realizacji, ale nie o nim chcę tutaj napisać. W międzyczasie bowiem w mojej głowie pojawił się jeszcze jeden pomysł. Chciałem sprawdzić jak ta rodzina procesorów sprawdza się w roli mikrokontrolera. Albo innymi słowy - byłem ciekaw co by było, gdyby Arduino powstało trzydzieści lat temu. Tym razem od brytyjskiego sprzedawcy na eBay-u zamówiłem kilka sztuk nowszych procesorów WDC65C02, wykonanych w technologii CMOS. Zastosowanie tej wersji układów nie tylko zmniejszało znacznie pobór prądu, ale także upraszczało układ, niwelując konieczność stosowania bufora szyny adresowej. Za punkt wyjścia do tego projektu posłużyła płyta procesorowa mojego ciągle powstającego komputera na MOS6502, która została poddana pewnym modyfikacjom. Przede wszystkim zmieniła się organizacja pamięci - zwiększyłem ilość EPROM-u kosztem RAM-u, dodana została także pamięć EEPROM. Organizacja pamięci wygląda następująco, zaczynając od 0x000: 8 kB pamięci RAM 8 kB przestrzeni adresowej I/O 8 kB pamięci EEPROM 8 kB układ EPROM (dodatkowa pamięć, obecnie niewykorzystywana) 32 kB EPROM (główna pamięć, przechowująca program, dane i adresy wektorów) Urządzenie pracuje z prędkością 4 MHz. Sygnał taktowania pochodzi z jednoukładowego generatora kwarcowego. Układ DS1232 odpowiada za obsługę wejścia RST (likwidacja drgań styków i obsługa power-on reset). Urządzenie posiada także port wyjściowy na 74HCT373 - można za jego pomocą migać dwiema diodami, pozostałe linie są wyprowadzone na złącze IDC-40. Dekoder adresów jest zrealizowany na układach 74HCT138 i 74HCT139. Dodatkowo kilka bramek układu 74HCT00 posłużyło do generowania sygnałów !RD i !WR, wykorzystywanych w układach kompatybilnych z magistralą intela (a więc także zastosowanych pamięciach). Wszystkie sygnały szyny danych, adresowej, te związane z obsługą przerwań oraz wyjścia dekodera adresów są wyprowadzone na złącze IDC-40. Moim zamiarem było stworzenie płytki, która nie tylko będzie mogła służyć do eksperymentów z historyczną rodziną procesorów, ale także będzie mogła posłużyć jako podstawa do budowy jakiegoś użytecznego projektu, poprzez dodanie odpowiednich modułów, na wzór shieldów Arduino - z tą różnicą, że podpinanych bezpośrednio do magistrali procesora za pomocą taśmy IDC-40. Na pierwszy ogień poszła płytka zawierająca wyświetlacz HD44780 (4x20) oraz kilka przycisków tact switch. Wyświetlacz pracuje bezpośrednio na magistrali procesora - do tego w końcu został zaprojektowany. Konieczne było tylko dodanie prostej logiki, generującej sygnały sterujące. Od strony programowej obsługa wyświetlacza w takich systemach jest nawet prostsza niż obecnie - wystarczy jedynie wpisywać odpowiednie wartości pod odpowiednie adresy w przestrzeni adresowej procesora. Przyciski posiadają własny port wejściowy, zrealizowany na 74HCT245. Praca nad tym projektem była dla mnie także okazją do zapoznania się z asemblerem 6502, chociaż prawdę mówiąc większość kodu napisałem w C posługując się kompilatorem cc65, uzupełniając go o asemblerowe wstawki. Co prawda jest to dość prosty kompilator i być może nie nadaje się do pisania gier pod Commodore C64, ale w w tego typu zastosowaniach sprawdza się całkiem nieźle.
  18. 7 punktów
    Witam, Chciałbym przedstawić zbudowany ostatnio pojazd inspekcyjny. Założenia były następujące: dobra mobilność w nierównym terenie, sterowanie za pomocą aplikacji na Android'a oraz podgląd z wbudowanej kamery w czasie rzeczywistym. Mechanika W pojeździe zastosowano uproszczoną, 4-kołową wersję zawieszenia rocker-bogie stosowaną m.in. w łazikach marsjańskich. Główną zaletą tego rozwiązania jest niemal równomierny nacisk wszystkich kół na podłoże oraz możliwość uniesienia koła na przeszkodzie. Zastosowane koła pochodzą od "jakiejś" zabawki (znalezione na strychu ) i są zamocowane adapterem hex 12 mm (z małymi przeróbkami, aby schować przekładnię wewnątrz koła). Każde koło posiada własny silnik DC z przekładnią - prędkość wyjściowa: ok. 120 obr/min przy zasilaniu 12V. Silniki zostały zamocowane do aluminiowego profilu kwadratowego 10 mm za pomocą opasek zaciskowych. Profil ten stanowi część wahacza przymocowanego do osi kadłuba przez łożyska z wiertarek (średnica wewnętrzna 6 mm). Z tyłu pojazdu widoczna jest belka różnicowa łącząca wahacze po obu stronach. Dzięki niej kadłub utrzymywany jest w swojej pozycji a wychylenie jednego wahacza powoduje odchylenie drugiego o taki sam kąt przeciwnie skierowany. Jako kadłub wykorzystano obudowę z ABS. Do jej wieczka przymocowano również maszt z kamerą sterowany w dwóch osiach. Elektronika Komputerem sterującym w pojeździe jest Raspberry Pi Zero W z systemem Raspbian w wersji Jessie. Zastosowano ten model z powodu małych rozmiarów, stosunkowo niskiej ceny i małego poboru mocy. Z racji braku przetwornika ADC, zastosowano również arduino w wersji Pro Mini o napięciu 3.3V (aby było zgodne ze standardem w Raspberry). Są również 2 sterowniki silników na bazie modułu L298N (Sterownik ten ma dwa kanały i można było zastosować tylko jeden sterownik, jednak z powodu niewystarczającej wydajności prądowej zastosowano dwa), 2 przetwornice step-down 5V (osobno dla logiki, i osobno dla serwomechanizmów), dwa serwomechanizmy TowerPro SG90, kamera, oraz pakiet 3S ogniw li-ion w rozmiarze 18650. Z racji tego, że kamera jest podłączana przez taśmę FFC, zastosowano również przejściówki z FFC na goldpin, aby nie uszkodzić taśmy podczas obracania kamerą. Oprogramowanie Arduino w tym pojeździe odpowiedzialne jest za odczyt aktualnego napięcia zasilania oraz generowanie sygnałów PWM dla prędkości silników oraz serwomechanizmów pozycjonowania kamery. To jaki sygnał ma być generowany, jest wiadome dzięki połączeniu z Raspberry poprzez UART. Dodatkową funkcją Arduino jest wyłączenie PWM dla silników w przypadku braku komunikacji z Raspberry co zapobiega niekontrolowanej jeździe pojazdu w przypadku np. zerwania zasięgu. Raspberry komunikuje się z użytkownikiem poprzez sieć WiFi (Malinka działa w trybie hot-spot'u). Program działający na Raspberry został napisany w Python'ie i wykorzystuje również biblioteki Flask, w celu utworzenia serwera. Odpowiednie fragmenty kodu są wykonywane po wywołaniu przypisanego do niego adresu. Do transmisji wideo wykorzystano platformę Gstreamer, która pozwala na strumieniowanie w formacie H.264. Dzięki temu udało się uzyskać płynny obraz przy 30 FPS i rozdzielczości 800x600 cechujący się niewielkim opóźnieniem (ok. 300 ms). Powstała również dedykowana aplikacja na system Android, gdzie widoczny jest podgląd z kamery oraz sterowanie pojazdem. Podsumowanie Powstały pojazd zgodnie z założeniami dobrze radzi sobie w terenie, jednak pozostawia również spore możliwości rozbudowy. Można np. dodać zewnętrzną antenę WiFi aby poprawić zasięg (obecnie jest to ok 50m na otwartej przestrzeni), diodę doświetlającą, czy też różne czujniki. Najprawdopodobniej następnym krokiem będzie dodanie przetwarzania obrazów, aby pojazd był w stanie podążać za danym obiektem i być może omijać przeszkody. Na koniec krótka prezentacja działania:
  19. 6 punktów
    Jakiś czas temu na portalu z ogłoszeniami natknąłem się na ofertę sprzedaży zabytkowego układu scalonego AY-3-8500. Jest to dość specyficzny element, wykorzystywany na przełomie lat siedemdziesiątych i osiemdziesiątych do budowy konsol do gier pierwszej generacji. Układ scalony zawiera w swojej strukturze kompletną logikę, niezbędną do generowania kilku prostych gier, m.in. kultowego "Ponga". Wykorzystywany był m.in. w kultowym ELWRO/Ameprod TVG-10 - jedynej polskiej konsoli do gier, jaka trafiła do masowej sprzedaży. Oczywiście nie byłbym sobą, gdybym go wtedy nie kupił i nie spróbował odpalić. Zacząłem więc szukać w Sieci informacji na temat tego układu. Efekty tych poszukiwań przeszły moje oczekiwania - natknąłem się na stronę, której autor zajął się podobnym projektem. Była tam cała niezbędna dokumentacja, karty katalogowe, a także projekt płytki drukowanej konsoli wykorzystującej posiadany przeze mnie układ scalony. No cóż... Postanowiłem nie wyważać otwartych drzwi i wykorzystałem ten wzór, prowadzając jednakże pewne modyfikacje w swojej implementacji tego projektu. Największa z nich dotyczyła kontrolerów , które zbudowałem w oparciu o niewielkie, plastikowe obudowy. Musze przyznać, że tworzą one całkiem poręczne "pady". Każdy z kontrolerów jest wyposażony w potencjometr służący do kontrolowania położenia paletki oraz przycisk do serwowania. Sama konsola została umieszczona w typowej plastikowej skrzynce. Na przednim panelu znajdują się przełączniki dźwigniowe dwu i trzypozycyjne służące do konfiguracji trybu rozgrywki, a także przełącznik obrotowy, do wyboru właściwej gry. Układ AY-3-8500 pozwala na korzystanie z pistoletu świetlnego. Dwie z generowanych przez niego gier wymagają posiadania takiego sterownika. Zdecydowałem się jednak zrezygnować z jego budowy. Na płytce są wyprowadzone odpowiednie piny, więc w przyszłości będzie możliwa taka rozbudowa. Niestety strona na której znalazłem oryginalny projekt niedługo później przestała działać, jednak wciąż można się do niej dostać przez Wayback Machine. Konsola przez jakiś czas była dostępna na wystawie "Game start/game over" w krakowskim Muzeum Inżynierii Miejskiej. Przetrwała - grupy gimnazjalistów nie były w stanie jej zniszczyć. W ramach ciekawostki mogę dodać, że mojemu sześcioletniemu siostrzeńcowi spodobała się ta gra sprzed kilku dekad.
  20. 6 punktów
    Witam chciałem wam przedstawić wykonaną przeze mnie kierownicę do komputera PC. Kierownica nie jest jeszcze do końca wykonana tak jak bym chciał , ale jest skończona działa można ją będzie jeszcze rozbudować Budowa od strony elektronicznej: Do budowy kierownicy użyłem jako podstawę Arduino Leonardo. Opierałem się o podobny projekt który znalazłem na yt . Lecz ja zrobiłem to trochę ładniej niż tamten chociaż nie ma rewelacji mogło być lepiej , ale w przyszłości myślę zrobić jeszcze jedną lepszą Oprócz Arduino Leonardo , zamiast jakiś potencjometrów i kombinowania z przekładniami użyłem enkoder z drukarki Canon IP2700. Ogólnie to oprócz enkodera to jeszcze parę przycisków potencjometry do pedałów i jakieś diody na podświetlenie. Poniżej schemat jak to podłączone. Oprogramowanie gotowe znalazłem pod tym filmem z którego się wzorowałem, wystarczyło wgrać XLoaderem i to wszystko podłączyć jak na schemacie. Od strony mechanicznej wygląda to tak: Odbijanie i blokada zostały zrobione na sprężynie niestety nie mam zdjęć . Dodam link do filmu na którym jest pokazane jak to działa. Ręczny przerobiony ze starej kierownicy . Elementy skrzyni biegów wydrukował mi kolega w 3D. i wygląda to tak: Pedały ze starej kierownicy , dorobiony jeden sprzęgłowy z innej kierownicy: Ostatecznie wygląda to tak: Link do filmu jak to działa i jak zrobione niektóre rzeczy: To by było na tyle w planach zrobienie Force Feed Back , na silniku DC 12v i przekładniach Pozdrawiam Krzysiek
  21. 6 punktów
    Od dawna interesowały mnie pomiary warunków meteorologicznych w mojej miejscowości, pierwsza stacja meteorologiczna, którą zbudowałem około roku 2010, wykonana była na mikrokontrolerze Atmega32. Do komunikacji z światem wykorzystywała moduł LAN Wiznet 7010a. Stacja ta była oprogramowana w języku BASCOM. Projekt który chcę zaprezentować dzisiaj działa już od roku 2018 i został oprogramowany w środowisku Arduino. Stacja została podzielona na 2 moduły, pierwszy pomiarowy oparty jest na klonie Arduino Nano oraz drugi odbiorczy którego sercem jest ESP8266 NodeMCU v3, służy on również do wyświetlania aktualnych pomiarów na wyświetlaczu LED dot matrix o wymiarach 8x56 punktów. Na pracach stolarskich się nie będziemy skupiać napiszę tylko że klatka meteorologiczna została wykonana z drewna sosnowego i umieszczona na wysokości 2 m. Moduł Pomiarowy Czujniki jakie zastosowałem to dwie sztuki DS18B20 pierwszy zajmuje się pomiarem temperatury przy gruncie na wysokości 5cm, drugi pełni rolę zapasowego czujnika temperatury na wypadek uszkodzenia się głównego czujnika BME280. Do pomiaru prędkości wiatru wykorzystuję wiatromierz firmy Maplin na jeden obrót wiatromierza przypadają 2 impulsy z kontaktronu który jest w nim zamontowany, producent dostarcza również odpowiedni wzór według którego można obliczyć rpm oraz prędkość wiatru w km/h. Dane mierzone przez wiatromierz możemy podzielić na dwie wartości, pierwsza to chwilowa prędkość, druga prędkość w porywach, aby uśrednić wartości mierzone program zlicza impulsy z 5s a następnie dokonuje odpowiednich obliczeń. Zebrane dane przesyłane są do drugiego urządzenia poprzez moduły radiowe które działają na częstotliwości 433,92 MHz. W tym celu zastosowana została biblioteka RCSwitch. Każda mierzona wartość jest wysyłana jako osobna transmisja. aby rozróżnić pomiary z konkretnych czujników mierzona wartość mnożona jest przez 100 a następnie dodawana jest liczba 100 000 dla pierwszego czujnika, 200 000 dla drugiego itd. Przykład kodu który realizuje tę funkcję poniżej: // temperatura sensor BME codetosend = temp * 100 + (1 * 100000); mySwitch.send(codetosend, 24); // wilgotnosc sensor BME codetosend = hum * 100 + (2 * 100000); mySwitch.send(codetosend, 24); Moduł Wewnętrzny Obudowa, która idealnie nadawała się do implementacji wewnętrznego modułu pochodzi z tunera IPTV Motorola VIP1910-9. Przedni panel został wykonany z ciemnego półprzepuszczalnego plastiku który idealnie nadaje się do umieszczenia w nim wyświetlacza. Sercem urządzenia jest układ ESP8266. "Moduł wewnętrzny" został również wyposażony w czujnik temperatury oraz wilgotności DHT22, dodatkowo w celu prezentacji zmierzonych wartości dołączone zostało 7 szt. modułów wyświetlacza LED dot matrix z układem MAX7219. Do obsługi tej matrycy zastosowałem bibliotekę Max72xxPanel.h która współpracuje z biblioteką Adafruit_GFX.h w ten sposób nie byłem zmuszony implementować do rozwiązania własnych czcionek. Matryca ta oprócz modułowej konstrukcji umożliwia również sterowaniem jasnością podświetlania, w tym celu aby uprzyjemnić użytkowanie w porach nocnych odbiornik został wyposażony w fotorezystor dzięki któremu potrafi określić natężenie oświetlenia otoczenia i odpowiednie ustawienie podświetlenia. Na wyświetlaczu w pierwszej kolejności wyświetlam aktualną godzinę oraz temperaturę wewnątrz pomieszczenia oraz wilgotność, po około jednej minucie wyświetlane są informacje odczytane z stacji meteo czyli temperatura wilgotność i ciśnienie, postanowiłem nie wyświetlać tutaj informacji dotyczących prędkości wiatru oraz temperatury przy gruncie. Decyzję tą podjąłem na podstawie użytkowania innego podobnego rozwiązania, akurat jak chcemy odczytać godzinę to wyświetlane są inne informacje. Dodatkowo w godzinach nocnych, które zostały ustawione w sztywnych ramach czasowych między 21:00 a 7:00 informacje odczytane z stacji meteo zostały okrojone tylko do temperatury. W projekcie zostały zastosowane 2 rodzaje animacji pierwsza z nich, przesuwa tekst z prawej strony wyświetlacza na lewą, z możliwością zatrzymania w interesujących momentach. Drugi rodzaj to pionowa animacja. Mikrokontroler również poprzez protokół NTP i bibliotekę time.h pobiera aktualną godzinę i datę. Za odbiór danych z pierwszego układu odpowiedzialny jest moduł radiowy którego obsługą tak jak w poprzednim module zajmuje się biblioteka RCswitch. Poniżej fragment programu który demonstruje w jaki sposób odbierane i dekodowane są dane: rc = mySwitch.getReceivedValue(); // czujnik temperatury powietrza BME280 if (abs(rc)>=50000&& abs(rc)<150000) { rc=(rc-100000)/100; if (rc > -50 and rc < 60) { temp1 = rc; Serial.print("Czujnik BME280 - temperatura: \t"); Serial.println(rc); matrix.drawPixel(55,0,1); matrix.write(); } } // czujnik wilgotności BME280 if (abs(rc)>=150000 && abs(rc)<250000) { rc=(rc-200000)/100; if (rc > 5 and rc <= 100) { hum = rc; Serial.print("Czujnik BME280 - wilgotnowsc: \t"); Serial.println(rc); matrix.drawPixel(55,1,1); matrix.write(); } } Dzięki zastosowaniu zewnętrznej anteny oraz odbiornika opartego na superheterodynie, zasięg w otwartym terenie to około 250 m. Po odebraniu danych z pierwszego układu poprzez moduł radiowy następuje przekazanie ich do serwera z systemem Domoticz. Domoticz to bardzo lekki system automatyki domowej, który pozwala monitorować i konfigurować różne urządzenia, przełączniki, czujniki takie jak temperatura, opady deszczu, wiatr, promieniowanie ultrafioletowe (UV), zużycie energii elektrycznej, zużycie gazu, zużycie wody i wiele więcej. Wykresy dostępne są również na stronie www http://meteo.palowice.net Poniżej film z działania odbiornika, smużenie animacji które występuje na filmiku ludzie oko nie rejestruje. Gdyby kogoś interesował kod to również zamieszczam: meteo.zip
  22. 6 punktów
    Swoją przygodę z elektroniką zacząłem kilka lat temu z celem zbudowania czworonożnego chodzącego robota. Nie bardzo sobie zdawałem wówczas sprawę ze stopnia skomplikowania tego zadania i śmieszy mnie dziś moja ówczesna naiwność, ale od tego czasu minęło parę lat i wiele się nauczyłem. W międzyczasie stworzyłem projekt taniego i łatwego w montażu robota, który opublikowałem pod adresem http://tote.rtfd.io, żeby nieco ułatwić zadanie innym. Naiwnie myślałem, że skoro dałem ludziom prosty punkt startowy, to teraz będą na jego bazie budować bardziej rozbudowane roboty i eksperymentować z platformą. Oczywiście myliłem się straszliwie, choć wiem o kilku konstrukcjach zainspirowanych moją. Dziś sam jestem dziadkiem^W^Wwiedząc więcej o tym jak to działa, postanowiłem zaprojektować zestaw do samodzielnego montażu oparty na podobnych pomysłach, ale bardziej mający formę gotowca. Zamiast optymalizować cenę postanowiłem tym razem zoptymalizować wygodę. Docelowo zamierzam zestaw sprzedawać częściowo zmontowany na Tindie. Dużo szczegółów konstrukcji pozostało z Tote. Nadal używam tanich serw SG90, które nadal zasilam bezpośrednio z baterii LiPo, kompensując za niskie napięcie większą częstotliwością sygnału sterującego. Nadal wykorzystuję fakt, że robot jest taki lekki, żeby przemycić nie do końca koszerne rozwiązania, jak wykorzystanie serw jako stawów nóg, bez dodatkowego podparcia, albo sklejanie ze sobą dwóch serw za pomocą hot glue. Ale tym razem nie używam taniego Arduino Pro Mini i C++, tylko mikrokontroler Atmel SAMD21 i CircuitPython. Nie ma już brzęczyka piezo na nóżce GPIO, tylko głośniczek podłączony do DAC. Do tego dodany jest akcelerometr dla prostego reagowania na ruszanie robotem i to tyle. Na górze jest header z nieużywanymi pinami do wpinania ewentualnych rozszerzeń — czujników lub dodatkowych serw czy światełek. Największą innowacją jest zrezygnowanie z użycia plastikowych orczyków od serw jako elementów konstrukcyjnych nóg, a zamiast tego płytka PCB zawiera, poza układem sterującym robota także wszystkie elementy mechaniczne. Sprawia to też, że łatwo możemy wymienić fragmenty nóg na inne, zawierające czujniki lub inne elementy elektroniczne. Programowanie, jak to w CircuitPythonie, odbywa się poprzez wgranie plików z kodem w Pythonie do robota, który po podłączeniu przez USB pojawia się w komputerze jako dysk. Możliwe też jest eksperymentowanie na żywo za pomocą konsoli pythonowej dostępnej po serialu. Robot jest pod względem mechanicznym w zasadzie ukończony, jak zwykle pozostaje jego zaprogramowanie, które pomimo wykorzystania języka wysokiego poziomu zajmuje mi sporo czasu — muszę się przyznać, że to nie ze względu na trudność problemu, ale na zmęczenie dzienną pracą i ciągłe odkładanie tego na później.
  23. 6 punktów
    Cześć! Skończyłem budowę mojego pierwszego robota. Jest to też mój pierwszy większy projekt, więc proszę o wyrozumiałość, komentarze, porady mile widziane. Z racji tego, że posiadam jeszcze dwa komplety lego, postanowiłem je wykorzystać do budowy pojazdu. Początkowo miały być silniki lego, ale stwierdziłem, że lepiej będzie zrobić to na zwykłych, uniwersalnych częściach. Konstrukcja miała być mała, zwinna, sterowana przez WIFI. Przednia oś, jak widać, sterowana za pomocą micro serwa. Nie było większych oporów, serwo bez problemów sobie radziło ze sterowaniem. Zacząłem szukać jakiegoś ciekawego i małego silnika DC. Postanowiłem wybrać silnik z podwójnym wałem. Kolejnym zadaniem było przebudowanie konstrukcji tak, żeby silnik się zmieścił i nie wadził w poruszaniu się robota. Z racji tego, że wolałem zaoszczędzić kilkanaście złotych na przejściówkę lego-wał, rozwierciłem otwory w częściach które miałem. Zacząłem myśleć jak wyglądałoby połączenie iPhone - ESP, ale w międzyczasie na uczelni dziekan zapowiedział nam dodatkowy projekt na zajęciach z mikrokontrolerów ( pierwsze takie zajęcia na drugim roku studiów ) - dowolny robot na platformie Arduino lub STM. Chłopaki na Facebookowej grupie Arduino uświadomili mi, że nie ma sensu robić projektu na ESP, bo musiałbym się łączyć tylko przez sieć i lepszym wyborem byłby bluetooth. Tak też się stało, zakupiłem moduł HM-10, który współpracuje z używanym przeze mnie iOS. Do tego całość przeniosłem na klona płytki Arduino. Jako aplikacji sterującej użyłem ArduinoBlue, wraz z biblioteką. Inne aplikacje nie chciały działać. W dodatku albo na iOS nie ma żadnych popularnych aplikacji do sterowania przez BLE albo nie udało mi się znaleźć. Możecie polecić ciekawe aplikacje na iOS, na pewno sprawdzę! Można zauważyć, że na breadbordzie zainstalowałem jakąś płytkę. Jest to sterownik silników DC, polecany, łatwy w użyciu. Dobra, silnik jest, działa, serwo jest, łączność przez BLE również. Wypadało by odpiąć wszystko od zasilania z gniazdka i zastosować akumulatory, baterie. Z początku była to dla mnie czarna magia, większe napięcie, jakieś ampery, przetwornice. Czytałem różne artykuły, oglądałem poradniki, pytałem na Facebookowej grupie. Ostatecznie, zgodnie z zasadami: Arduino + sekcja logiczna zasilana z powerbanka + wyprowadzenie zasilania bezpośrednio do serwa, silnik DC zasilany przez dwa ogniwa litowo-jonowe połączone szeregowo z BMS, napięcie zmniejszane przez przetwornicę Żeby szybko podpinać ogniwa do robota albo ładować, przylutowałem wtyki/gniazda DC 5.5mm. BTW. Bardzo długo męczyłem się z lutowaniem ogniw na 30-watowej lutownicy kolbowej. Metodą prób i błędów wszystko się złączyło. Przed podłączeniem każdego elementu lutowanego, sprawdzałem miernikiem czy nie ma zwarcia! Dodatkowo pokusiłem się o popularny czujnik odległości oraz mała prowizorka - dwie diody z opornikami schowane w obudowie po serwie (spaliło się), informujące o przeszkodzie w danej odległości. Wersja finalna, kilkukrotnie większa i cięższa niż pierwotna wersja. Wzmocniony układ kierowniczy. Jeździ, skręca, hamuje, cofa. Trzymany pod kocem Wszelkie komentarze mile widziane! A tutaj krótki filmik (musiałem zdemontować czujnik odległości, ponieważ powodował zakłócenia całego układu: Tak wygląda sterowanie za pomocą joysticka:
  24. 6 punktów
    Cześć W ramach organizowanej akcji postanowiłem opisać projekt, który wykonałem już jakiś czas temu. WPROWADZENIE Projekt to stacja meteorologiczna montowana na wyrzutni rakiet zaprojektowana i wykonana przeze mnie w ramach rekrutacji do Sekcji Rakietowej Studenckiego Koła Astronautycznego (działającego na Politechnice Warszawskiej). Wymagania wobec stacji: pomiar prędkości i kierunku wiatru, pomiar temperatury i ciśnienia, pomiar położenia oraz orientacji wyrzutni i kąta nachylenia ramienia, komunikacja bezprzewodowa z bazą, zasięg 500-700m, aplikacja na PC wyświetlająca i rejestrująca odbierane dane. ELEKTRONIKA Ogólny diagram sprzętowy wygląda następująco: Do realizacji 'mózgu' stacji wykorzystałem Arduino Pro Mini (zarówno w nadajniku, jak i odbiorniku). Komunikacja bezprzewodowa zrealizowana jest poprzez moduły NRF24L01+ ze wzmacniaczem mocy (w przeprowadzonych na poligonie testach bez problemu uzyskiwały zasięg 700m). Do pomiaru ciśnienia i temperatury zastosowałem moduł z układem BMP180. Pomiar prędkości i kierunku wiatru jest wykonywany przez zestaw stacji pogodowej. Do pomiaru kąta nachylenia wyrzutni zastosowałem moduł z układem MPU-6050. Położenie wyrzutni jest mierzone poprzez standardowy moduł GPS (NEO-7M-C firmy Waveshare). Urządzenie montowane na wyrzutni zasilane jest dwoma ogniwami litowo-jonowymi, a odbiornik jest zasilany przez komputer za pośrednictwem USB. Do generacji napięcia 5V w nadajniku wykorzystałem moduł przetwornicy D24V6F5 z Pololu. Z przeprowadzonych pomiarów wynika, że jedno ładowanie baterii pozwala działać stacji przez około 30 godzin. Schemat jednostki głównej: Ciekawą sprawą jest pomiar prędkości wiatru. Anemometr raz na obrót zwiera styk, a prędkość obrotowa jest proporcjonalna do prędkości wiatru (1Hz przekłada się na 2.4km/h). Mierząc więc okres pomiędzy kolejnymi krawędziami, można określić prędkość wiatru. Aby pomiar był możliwie dokładny, wykorzystałem przerwania. Jednak jak to z mechanicznymi stykami bywa, pojawiały się drgania styków: Aby zniwelować ten efekt zastosowałem dwie bramki NOT z przerzutnikami Schmitta i filtrem RC (o stałej czasowej około 1ms). Układ sprawia, że na pinie mikrokontrolera pojawiają się ładne, pojedyncze zbocza (czerwony to wyjście anemometru, a niebieski przebieg to sygnał podłączony do pinu mikrokontrolera): Na pokładzie zamontowany jest również magnetometr (znajdujący się poza główną obudową, w oddzielnej obudowie), który miał służyć do pomiaru azymutu wyrzutni (przy startach rakiet bardzo istotne są dwa kąty: azymut oraz nachylenie ramienia wyrzutni). Ostatecznie jednak nie został wykorzystany ze względu na problemy z kalibracją (magnetometr musiałby być za każdym razem montowany dokładnie tak samo na wyrzutni, co nie jest wykonalne). Odbiornik jest stosunkowo prostym urządzeniem: Zawiera tylko mikrokontroler (na module Arduino Pro Mini) oraz moduł radiowy. Komunikacja z PC wykonywana jest przez konwerter USB-UART. Odbiornik wyposażony jest też w diodę, która jest zapalana na chwilę w momencie odebrania pakietu. Bardzo to pomaga przy rozstawianiu stacji. Oba układy zmontowałem na płytkach prototypowych. OPROGRAMOWANIE Oprogramowanie projektu jest dość rozbudowane, gdyż składa się z dwóch projektów na systemy wbudowane (nadajnik i odbiornik) oraz oprogramowania na PC. Oprogramowanie nadajnika Kod napisany oczywiście z wykorzystaniem środowiska i bibliotek Arduino dla przyspieszenia developmentu Wykorzystałem dodatkowe biblioteki: MPU6050 (konfiguracja i odczytywanie danych z akcelerometru) HMC5883L (konfiguracja i odczytywanie danych z magnetometru) I2Cdev (wykorzystywane przez bibliotekę MPU6050) TinyGPS (parsowanie danych z GPS) RF24 (komunikacja z modułem radiowym) Adafruit_BMP085 (konfiguracja i odczytywanie danych z barometru) Oprogramowanie odbiornika Zadaniem programu uruchomionego na odbiorniku jest odczytanie danych z modułu radiowego i przerzucenie ich od razu na port szeregowy. Nic skomplikowanego. Kod na systemy wbudowane jest w repozytorium: https://github.com/Lukaszm94/rocketLauncherDAQ_embedded Oprogramowanie na PC Program do uruchamiany na PC służy do odbierania danych z odbiornika, wyświetlania ich i zapisywania do pliku CSV. Do zrealizowania powyższych zadań wykorzystałem język C++, framework Qt i bibliotekę Qwt. Kod znajduje się w repozytorium: https://github.com/Lukaszm94/RocketLauncherDataAcquisitionApp Na temat samej implementacji nie będę się rozpisywał. Kilka ciekawszych funkcji programu to wyznaczanie wartości średniej prędkości wiatru (z możliwością ustalenia z jakiego okresu ma być wyliczana średnia) oraz podmuchu (chwilowa maksymalna prędkość wiatru). Dodatkowo, jeżeli któryś sensor działa niepoprawnie (np. akcelerometr jest niepodłączony albo GPS nie ma fixa), to wartość z tego sensora jest wyświetlana w kolorze czerwonym. Widok okna programu: MECHANIKA Wszystkie obudowy i elementy mocujące zaprojektowałem w Autodesk Inventor i wykonałem z wykorzystaniem drukarki 3D. Na wyrzutni montowane są trzy urządzenia: jednostka główna, moduł kompasu i moduł akcelerometru. W czasie projektowania kierowałem się łatwością montażu w warunkach polowych (stąd np. zastosowanie nakrętek motylkowych do mocowania obejm) oraz zapewnienie możliwie wysokiej odporności na wodę. Render głównej obudowy: Render odbiornika: Nadajnik: Wnętrze nadajnika: Wnętrze odbiornika: Ciekawy patent, jaki mogę pokazać, to wykonanie złącz do świata zewnętrznego. Wykorzystałem złącza męskie KK254, które przylutowane są do odpowiednio wyciętej płytki prototypowej. W płytce są dwa otwory pod śruby M3, analogiczne otwory są w obudowie. Płytka jest mocowana od wewnątrz do ścianki urządzenia z wykorzystaniem dwóch śrub. Całość od zewnątrz wygląda elegancko i jest wytrzymała. Cała jednostka główna zmontowana: WNIOSKI I PODSUMOWANIE Projekt spełnia większość założeń i uważam, że został zrealizowany z sukcesem. Wykorzystany został już wielokrotnie na poligonie i w zasadzie za każdym razem system działał poprawnie. Jeśli chodzi o wady, to główny problem jaki zaobserwowałem, to uszkadzanie się modułów radiowych (konkretniej to wzmacniaczy mocy) w momencie włączenia urządzenia bez podłączonej anteny - co niestety zdarzyło się kilkukrotnie (przypadkowe włączenie). Drugi problem to brak pomiaru orientacji wyrzutni, związany z opisaną wcześniej kłopotliwą kalibracją. Przykładowy wykres uzyskany z wykorzystaniem stacji (na zawodach CanSatów w 2016 jeśli dobrze pamiętam): Krótki opis projektu jest też na mojej stronie internetowej: http://lukemeyer.me/rldaq.php Na koniec mogę pokazać ładne zdjęcie ze startu rakiety TuCAN (jak się dokładnie przyjrzycie, to widać stację zamontowaną na wyrzutni ). W projekcie TuCAN również brałem udział, zajmowałem się całością systemów elektronicznych w rakiecie. Jakby ktoś był zainteresowany, to mam mały opis na mojej stronie: http://lukemeyer.me/tucan.php
  25. 6 punktów
    Co może zrobić uczeń podstawówki, kiedy nie można w szkole używać telefonów? Specjalny kalkulator! Tak, wiem że urządzenie jest trochę przekombinowane - za pare zł mam nowy kalkulator z kiosku, ale to nie jest zwykły kalkulator.Ten kalkulator, albowiem, robiłem ja Budowa Urządzenie posiada wyświetlacz TFT 1.8" ze slotem na kartę pamięci, z której możemy odtwarzać zdjęcia. Do wprowadzania informacji posłużyła mi klawiatura 4x4 w formie naklejki. Całość napędza Arduino Pro Mini, które przeprogramowałem na korzystanie z wewnętrznego kwarcu 8Mhz i wyłączenie BOD. Energię dostarcza akumulator Lipo wyjęty z tableta, ładowany przez dolutowanie się do akusa. Napięcie obniża stabilizator AMS1117 na 3,3v, co rozwiązało kwestię napięcia logiki (TFT ma 3.3v, arduino normalnie 5v) oraz zużycia energii. Wyświetlacz, do programowania, można zdejmować. Po prawej stronie dostrzegamy przełącznik włączający urządzenie, zaś pod TFT znajduje się przycisk funkcyjny. Obudowy nie chciałem robić, gdyż chciałem wzbudzić zainteresowanie wśród kolegów Funkcje Kalkulator ma funkcję liczenia. Wow. Potrafi dzielić, mnożyć, dodawać i odejmować liczby dziesiętne, dodatnie i ujemne - ale nie umie wykonywać kolejności działań (dlatego według kalkulatora 2+2x2=8). ALE. Oprócz kalkulatora, utworzyłem aplikację paint - służy do malowania piksel po pikselu. Dobre na nudne lekcje polskiego. Po włączeniu urządzenia, wyświetla nam się lista dostępnych aplikacji. Oprócz niedokończonego snejka, jest jeszcze "czwarta aplikacja" - ściąga Wyświetla ona wzory z fizyki, chemii i matematyki oraz prawa dynamiki Newtona. Kalkulator może również w progmemie przechować jedno kolorowe zdjęcie, i wyświetlić je po 8x naciśnięciu przycisku Równa się. Taki kalkulator to fajna rzecz, z racji tego że można go używać w szkole bez ograniczeń i da się na nim pobawić. W ostateczności przeglądać memy, po włożeniu karty SD. Pozdrawiam, Leoneq :3
  26. 6 punktów
    Jak zbudować robota kroczącego? Na czym właściwie polega chodzenie? Jakie czujniki są do tego potrzebne? Na te pytania postaram się tutaj odpowiedzieć. Kroczenie a pełzanie Na początek zastanówmy się co tak naprawdę chcemy uzyskać. Aby zbudować urządzenie przemieszczające się bez kół nie potrzeba wiele — ot, dowolny mechaniczny aktuator wykonujący cykliczne ruchy może, na odpowiednim podłożu i przy odrobinie szczęścia, poruszać się jakimś mniej lub bardziej przewidywalnym kierunku. Istnieje nawet całkiem sporo publikacji naukowych o "robotach uczących się chodzić", w których te periodyczne ruchy są sterowane przez sieć neuronową lub inny ewoluujący element tak, aby zoptymalizować prędkość przemieszczania się. Ale ja osobiście nie nazwałbym tego chodzeniem, a już na pewno nie kroczeniem. Czego zatem wymagamy? Według mnie podstawowym i minimalnym wymaganiem jest to, aby żadna część robota nie była wleczona podczas przemieszczania się — aby tylko stopy dotykały podłogi i aby nie poruszały się względem tej podłogi przez cały czas gdy jej dotykają. Raz postawiona stopa musi pozostać w jednym miejscu aż nie zostanie ponownie podniesiona. W ten sposób gwarantujemy sobie dużą niezależność od rodzaju podłoża i minimalizujemy niszczenie jego oraz elementów go dotykających. Oczywiście w praktyce zawsze będą występować drobne ruchy: szpiczasta noga pająko-podobngo robota może, pozostając w miejscu, obracać się, a nawet stopa humanoida będzie się w momencie odbijania od ziemi lekko przesuwać. Ale wiemy już przynajmniej w którym kierunku chcemy... kroczyć. Kroczysz czy się toczysz? Drugim pytaniem, jakie musimy sobie zadać, jest jak dużo kontroli powinniśmy mieć nad ruchami nóg? Czy jeżeli z drewnianego koła od wozu drabiniastego zdejmę felgę i na odsłonięte tak drewniane szprychy pozakładam stare buty, to uzyskam urządzenie kroczące? Nasz pierwszy warunek jest w zasadzie spełniony — but raz postawiony na ziemi nie przesuwa się aż się od niej nie oderwie — jednak uzyskany sposób lokomocji niewiele różni się od zwykłego transportu kołowego, w szczególności dzieląc z nim problemy z radzeniem sobie z nierównym podłożem czy przeszkodami. To samo rozumowanie dotyczyć będzie wszelkiego rodzaju napędzanych jednym silnikiem mechanizmów takich jak Strandbeest czy Hexbugs. Jasne, wyglądają jakby miały nogi i chodziły, ale tak naprawdę są to tylko bardziej skomplikowane koła. W naszych robotach kroczących chcielibyśmy mieć kontrolę nad miejscem postawienia każdej nogi. Stopnie swobody Skoro jeden silnik to za mało, to w takim razie ile stopni swobody musi posiadać nasz robot żeby kroczyć? Powyższy warunek kontroli miejsca postawienia nogi daje nam minimalną granicę dwóch stopni swobody: poruszanie nogą i jej opuszczanie i podnoszenie. I rzeczywiście, można sobie wyobrazić robota składającego się z dwóch trójnogów przemieszczających się względem siebie w przód i w tył oraz w górę i w dół. W praktyce jednak najczęściej stosujemy konfiguracje wzorowane na zwierzętach, z osobnymi nogami o dwóch, trzech albo i więcej stopniach swobody. Niezależnie od konfiguracji, aby poruszać się w linii prostej nasz robot musi umieć podnieść i opuścić każdą z nóg, oraz przesunąć stojącą na ziemi nogę do tyłu wzdłuż linii prostej. Wymaga to dwóch stopni swobody, jeśli noga porusza się równolegle do ciała (jak u kota czy człowieka), lub trzech, jeśli noga porusza się po łuku (jak u pająka lub jaszczurki). Dodatkowo, niezbędne mogą być dodatkowe stopnie swobody jeśli noga posiada stopę, a także jeśli robot ma być w stanie wykonywać zakręty czy nawet obroty w miejscu. Należy się zatem przygotować na konieczność sterowania dużą liczbą aktuatorów (a także ich pozyskania i zasilania), co niestety często jest największą barierą przy budowanie takiego robota. Siła i masa Drugim, poza liczbą aktuatorów, wyzwaniem dla konstruktora robotów kroczących jest masa. Podobnie jak pojazdy latające, a w odróżnieniu od pojazdów kołowych i gąsienicowych, pojazd kroczący niesie własne ciało (plus ewentualny ładunek) siłą swoich silników. Istnieją co prawda bardzo wydajne chody pozwalające na odzyskiwanie i ponowne użycie znacznej porcji energii (ludzie właśnie taki chód stosują), ale są one na tyle zaawansowane, że nie mamy praktycznych systemów je wykorzystujących. Dla amatora-hobbysty pozostaje opcja niesienia całego robota energią baterii. Chcemy zatem, aby nasz robot był jak najlżejszy. Warto przy tym pamiętać o tak zwanym prawie sześcianów: przy zachowaniu wszystkiego innego, masa robota rośnie do sześcianu jego wielkości. Zatem jeśli robot wielkości 1m waży 10kg, to taki sam robot (tylko przeskalowany) o wielkości 2m ważyć będzie 80kg (możemy sobie wyobrazić 8 mniejszych robotów ustawionych w kostkę wewnątrz większego). Stwarza to wiele problemów, oczywiście, bo konstrukcja większego robota, przy użyciu tych samych materiałów, będzie tylko 4 razy mocniejsza, a silniki tylko dwa razy silniejsze. Na szczęście pojemność baterii także wzrośnie proporcjonalnie do sześcianu wielkości. Dlatego zdecydowanie łatwiej jest budować roboty o mniejszych wymiarach. Możemy sobie wówczas pozwolić na użycie tańszych i łatwiejszych w obróbce materiałów i słabszych silników. Oczywiście ograniczy to nam także wielkość i masę jednostki sterującej, ale przy postępującej miniaturyzacji jest to najmniej bolesne ograniczenie. Bardziej bolesne jest ograniczenie masy ładunku, którym nasz robot będzie w stanie manipulować — nie pojeździmy sobie na pająku. Jednak szczególnie dla początkujących zbudowanie małego robota będzie i łatwiejsze i bardziej praktyczne — łatwiej z nim eksperymentować i więcej się można nauczyć. Stabilność statyczna Dla uproszczenia zaczniemy od modelu, w którym nasz robot jest na tyle lekki i porusza się na tyle wolno, że siły bezwładności są pomijalnie małe i możemy je zignorować. W ten sposób z naszych obliczeń eliminujemy zmienną czasu i znacznie je upraszczamy. Dodatkowym ułatwieniem przy takim podejściu jest fakt, że nasz robot może się wtedy poruszać dowolnie wolno, a nawet w dowolnym momencie zatrzymać się bez przewracania. Oczywiście ogranicza to nas wtedy do statycznie stabilnych chodów, no ale od czegoś w końcu trzeba zacząć. W modelu bez inercji warunek stabilności robota jest bardzo prosty: obrysowujemy znajdujące się na ziemi stopy robota wypukłą obwiednią (czyli tak, jakbyśmy zrobili wokół nich pętlę ze sznurka i ją zacisnęli). Kształt, który uzyskamy nazywamy wielokątem podparcia. Jeśli stopy są szpiczaste, jak u insektów, to będą w narożnikach tego wielokąta. Jeśli mają inny kształt, to stanie się on częścią obrysu. Na przykład przy czworonożnym pająkopodobnym robocie i przy wszystkich nogach na ziemi, będziemy mieć czworokąt: A kiedy podniesiemy jedną nogę, uzyskamy trójkąt: Kiedy już mamy nasz wielokąt podparcia, to pozostaje nam znaleźć środek ciężkości naszego robota (uwaga — może się on zmieniać na skutek poruszania nóg czy innych elementów), poprowadzić z niego pionową kreskę aż do ziemi (zgodną z kierunkiem działania grawitacji) i sprawdzić, czy znajduje się ona wewnątrz naszego wielokąta. Jeśli tak, robot będzie stał. Jeśli nie, to znaczy że już się przewraca. Przy okazji, odległość tego punktu od najbliższego brzegu wielokąta podparcia jest dobrym wyznacznikiem stabilności robota — jego odporności na zewnętrzne siły. W przykładzie powyżej pionowy rzut środka ciężkości wypada dokładnie na brzegu trójkąta — zatem robot przewróci się od najdrobniejszego dotknięcia czy wibracji. Aby tego uniknąć, można przesunąć trzy nogi robota w kierunku tej, która ma zostać podniesiona zanim zaczniemy ją podnosić: To właśnie dlatego kroczące roboty często kiwają się na boki — przesuwają swój środek ciężkości, aby zawsze mieścił się w wielokącie podparcia. Stabilność dynamiczna Gdy chcemy, aby nasz robot poruszał się szybciej, a także potrafił chodzić z mniej niż trzema nogami na ziemi i bez rakiet śnieżnych, to musimy uwzględnić w naszych obliczeniach bezwładność. Jest wiele sposobów na zrobienie tego, ale niestety większość oznacza numeryczne rozwiązywanie skomplikowanych równań różniczkowych, co wymaga sporej mocy obliczeniowej. Istnieje jednak jedna dość prosta metoda nie wymagająca złożonych obliczeń, nazwana ZMP (zero-movement point). Czym jest ZMP? Pamiętacie ten punkt na ziemi bezpośrednio pod środkiem ciężkości robota? To właśnie jest ZMP w przypadku, kiedy inercja jest zerowa. W przypadku, gdy nie jest ona zerowa, punkt ten przesuwa się zgodnie z kierunkiem i siłą jej działania. Jest to po prostu punkt, w którym musielibyśmy się podeprzeć, żeby w danym momencie się nie przewrócić. Zatem wystarczy, że tak będziemy planować nasze ruchy, żeby ZMP nigdy nie znajdował się poza wielokątem podparcia na tyle długo, żeby robot się zdążył przewrócić, a wszystko będzie działać. No dobra, ale jak możemy wyznaczyć ZMP? Okazuje się, że jest na to kilka bardzo prostych sposobów. Jeśli mamy w stopach robota czujniki nacisku, to mierząc i uśredniając działające na nie siły jesteśmy w stanie wyznaczyć ZMP. Możemy też ZMP wyznaczyć przy pomocy akcelerometru, jeśli znamy środek ciężkość — wystarczy poprowadzić linię w kierunku wskazywanym przez niego, a tam gdzie przetnie podłogę będzie ZMP. Kinematyka odwrotna Aby mieć dobrą kontrolę nad tym co nasz robot robi i gdzie dokładnie stawia stopy, musimy opanować geometrię jego nóg i potrafić wyliczyć jak te nogi przesunąć żeby ustawiły się w danej pozycji. Takie obliczenia nazywane są kinematyką odwrotną i w przypadku nóg o dwóch lub trzech ortogonalnych stopniach swobody są relatywnie proste — wystarczy nam znajomość trygonometrii ze szkoły podstawowej. Cała sztuka sprowadza się do tego, aby współrzędne stopy móc przeliczyć na kąty w poszczególnych stawach nogi. Oczywiście dla każdej konfiguracji obliczenia będą inne, zatem nie będę się w nie tutaj bardzo zagłębiał. Oczywiście da się poradzić sobie z tym problemem bez obliczeń, po prostu zaszywając w programie poszczególne pozy naszego robota i przejścia między nimi. Niestety takie podejście nie pozwala nam modyfikować chodu w odpowiedzi na nierówny teren, dodatkowe siły, skręcanie czy zmianę pozycji ciała względem trasy — zatem daje naszemu robotowi niewiele przewagi nad zwykłym robotem na kołach. Układy współrzędnych Układ współrzędnych, w którym określana jest pozycja stopy względem ciała robota (a w zasadzie względem punktu przyczepienia nogi do tego ciała), to tylko początek. Oczywiście każda noga będzie miała swój. Ale jeśli chcemy naszego robota kontrolować jako całość (na przykład żeby przesuwać jego ciało celem odpowiedniego ustawiania środka ciężkości), to będziemy chcieli mieć drugi układ współrzędnych, wspólny dla wszystkich nóg — układ współrzędnych ciała. Następnie przydałoby się znać pozycję niejako środka robota, ignorującą przesunięcia ciała wynikające z balansowania i ruszania nogami — to, czym sterowalibyśmy przy pomocy zdalnego sterowania, na przykład. To układ współrzędnych wirtualnego pojazdu. No i wreszcie, jeśli nasz robot zapamiętuje mapę otoczenia, to wypadałoby mieć układ współrzędnych świata, w którym ten wirtualny pojazd się przesuwa. Przejścia pomiędzy tymi układami współrzędnych najłatwiej zrealizować poprzez mnożenie współrzędnych przez macierze przejścia pomiędzy bazami. W ten sposób trywialnie zaimplementujemy translację i rotację ciała robota. Chód Sam chód to prosta sprawa, choć oczywiście istnieje wiele wariacji na jego temat. Generalnie idea jest taka, że wszystkie nogi znajdujące się na ziemi przesuwają się do tyłu (najlepiej jednostajnie, choć można to też robić skokowo), a te najdalej wysunięte do tyłu są podnoszone i przestawiane do przodu kiedy tylko jest do tego okazja (na tyle szybko, żeby się nie skończył ich zakres ruchu do tyłu). W przypadku czworonogów istnieje optymalna kolejność takiego przestawiania (prawa-przednia, lewa-tylna, lewa-przednia, prawa-tylna) zapewniająca najlepszą stabilność, w przypadku dwunogów nie ma za bardzo wyboru, a sześcio-i-więcej-nogi mogą sobie pozwolić na dużo fantazji w tym zakresie. Statycznie stabilny chód u czworonogów jest jeden i nazywa się "creep" (skradanie się?) — polega na przestawianiu jednej nogi na raz. Gdy mamy stabilność dynamiczną, to możemy przejść do kłusu ("trot"), w którym przestawiamy dwie nogi na raz — po przekątnej, a nawet do galopu, w którym momentami tylko jedna noga dotyka ziemi (istnieją 4 wariacje tego chodu, w zależności od kolejności nóg). Jeśli mamy naprawdę szybki komputer i dobre czujniki (i silne aktuatory), to możemy nawet skakać... To tyle Tyle potrafię na ten temat napisać bez wchodzenia w szczegóły dotyczące konkretnych konfiguracji (humanoid, czworonóg, sześcionóg, etc.). Mam nadzieję, że jest to przynajmniej jakiś punkt startowy dla hobbystów projektujących swojego pierwszego robota kroczącego.
  27. 6 punktów
    Budżet każdego cubesata zawierającego podobne komponenty jest podobny. Ceny podzespołów dla nas i w innych krajach są podobne, koszty rakiety również. Nie mam dokładnie takich informacji, ale np. w Stanach buduje się cubesaty na każdym uniwersytecie więc być może nie jest to takie wielkie wydarzenie jak u nas. Są normy np. europejskie ECSS, które są nieaplikowalne do cubesatów i innych satelitów (komercyjnych) z tzw. "new space". Nieaplikowalne ze względu na wymiary, budżet i szereg innych powodów. Warto jednak przeczytać i wybrać z tych standardów rzeczy aplikowalne. Cały satelita powstał z elementów tzw. COTS, czyli tego co można kupić w sklepie. Jednak nie były to przypadkowe elementy: co tylko było dostępne było wybierane w wersjach hi-rel (np. kondensatory, które mają określony failure rate), komponenty z serii z rozszerzonym zakresem temperaturowym. Nie były używane obudowy typu BGA czy DFN, szczególnie w "busie" satelity (czyli kluczowych elementach jak układ zasilania, komputer pokładowy itd.). Część kluczowych komponentów ma redundancję. Jak najbardziej. Może przy tak krótkiej misji nie ma dużej obawy o TID, ale single eventy i spowodowane nimi latch-upy mogą się zdarzyć. Po pierwsze staraliśmy się wybierać elementy które już leciały i się spisały (tzw. flight heritage), po drugie elementy COTS często bywają testowane ze względu na odporność na promieniowanie (CERN robi dużo takich testów i publikuje te dane, ale nie tylko oni). Mikrokontroler w komputerze pokładowym (OBC) ma zewnętrzne pamięci SRAM a ich zawartość przechodzi przez FPGA który robi korekcję błędów "w locie" tak, aby właśnie bity zmienione przez promieniowanie nie zakłóciły pracy. To samo z kodem programu - przechowywany jest w 6. kopiach a bootloader robi głosowanie na 3. slotach i dopiero wtedy ładuje poprawny obraz (potrafi go też naprawiać i sklejać). Samo oprogramowanie OBC w trakcie robi tzw. scrubbing na pamięciach. Z układu zasilania: wszystkie linie zasilania mają zabezpieczenia nadprądowe tzw. latch-up current limitter (LCL) - jeśli któryś podsystem dostanie latchu-upa od promieniowania to zostanie zresetowany. Tam gdzie to potrzebne i osiągalne. Redundancja szczególnie potrzebna jest w systemie zasilania (np. są dwa mikrokontrolery), system rozkładający anteny (mikrokontroler + rezystory przepalający linkę "trzymającą" anteny w pozycji złożonej) też są zdublowane. Sam żagiel ma dwa rezystory oddzielnie sterowane dla redundancji. Dochodzi też redundancja na poziomie systemu - nawet jeśli OBC przestanie działać - automatycznie otwarcia żagla dokona układ OBC (który ma dwa mikrokontrolery, a każdy z nich steruje oddzielnym rezystorem zwalniającym żagiel). Są ścianki z aluminium + zasobnik na żagiel i akumulatory to całkiem dobry shielding. Dobre pytanie - staraliśmy się wzorować na innych (na ich sprawdzonych rozwiązaniach), ale jest to dosyć ciężkie. Mało konstrukcji, nawet studenckich jest udostępnionych. Będziemy chcieli ze swojego projektu udostępnić jak najwięcej, w jak najlepszej formie. Przynajmniej ze strony elektroniki i software. Dużo wiedzy wynieśliśmy z Centrum Badań Kosmicznych, przeglądy projektu robiła ESA. Jeśli chodzi o materiały to są wspomniane ECSS i pewnie dziesiątki innych publikacji/materiałów z których korzystaliśmy a teraz "na szybko" ich tytułów nie wyczaruję. Wrócę na pewno do tego tematu za jakiś czas (pewnie po misji).
  28. 6 punktów
    Nie samą maliną człowiek żyje Już na samym początku wspominałem o tym, że Raspberry Pi nie jest wcale ani jedyną, najlepszą, ani najtańszą platformą sprzętową dla wbudowanego Linux-a. Jej ogromnym plusem jest bardzo dobre wsparcie, ale nic nie stoi na przeszkodzie w używaniu innych płytek. I tutaj ważna uwaga - w bardzo podobny sposób możemy łatwo przygotować obraz systemu również dla innych platform. Yocto wykorzystuje tzw. warstwy - są to zestawy gotowych skryptów, jak dla mnie to takie moduły, czy biblioteki, ale ktoś wymyślił określenie warstwa więc będę się tego trzymać. W internecie znajdziemy całkiem sporo gotowych warstw, wiele osób przygotowuje własne - my też możemy, chociaż to chyba trochę bardziej zaawansowany temat. Co ważne warstwy pozwalają na oddzielenie części sprzętowej (BSP - Board Support Package) od reszty systemu. Więc zmieniając warstwę meta-raspberrypi na inną dostaniemy taki sam system (tzn. z takimi samymi pakietami), ale działający na innej platformie. Jakie platformy są wspierane? W sumie to prawie wszystkie - najlepiej do znajdowania warstw użyć wyszukiwarki: http://layers.openembedded.org/layerindex/branch/sumo/layers/ Wspomnę o kilku platformach, które moim zdaniem są warte uwagi: BeagleBone - jest domyślnie wspierana przez Yocto i włączona do dystrybucji Odroid (http://layers.openembedded.org/layerindex/branch/sumo/layer/meta-odroid/) - często wymieniane jako konkurencja malinki, na ogół wydajniejsze niż oryginał Xilinx (http://layers.openembedded.org/layerindex/branch/sumo/layer/meta-xilinx/) - tutaj znajdziemy wsparcie dla układów Zynq, czyli FPGA z Cortex-A9 Freescale (http://layers.openembedded.org/layerindex/branch/sumo/layer/meta-freescale/) - bardzo fajne procesory i płytki, trochę droższe ale z lepszą dokumentacją Intel (http://layers.openembedded.org/layerindex/branch/sumo/layer/meta-intel/) - yocto może też przygotować dystrybucję dla x86. Stary komputer może odzyskać drugą młodość jeśli potraktujemy go jako urządzenie wbudowane. Poza tym są wszystkie LattePanda i podobne (był też Edison, ale to już historia) Tegra (http://layers.openembedded.org/layerindex/branch/sumo/layer/meta-tegra/) - coś dla miłośników szybkich maszyn oraz GPU (albo hackerów Nintendo Switch) W nieco starszej wersji yocto mamy jeszcze większy wybór: Altera (http://layers.openembedded.org/layerindex/branch/rocko/layer/meta-altera/) - układy z FPGA oraz Cortex-A9, odpowiednik Zynq od Xilinx-a. Właśnie tej warstwy używałem przygotowując oprogramowanie dla mojego wyświetlacza paneli LED (https://forbot.pl/forum/topic/12015-wyswietlacz-z-paneli-led/) AllWinner (http://layers.openembedded.org/layerindex/branch/rocko/layer/meta-sunxi/) - to coś dla miłośników tańszych układów, znajdziemy je na wszelkiej maści OrangePi, BananaPi, NanoPi oraz Olinuxino Jeśli będzie zainteresowanie tematem Yocto, postaram się opisać nieco dokładniej możliwości jego wykorzystania z Raspberry Pi - ale większość omawianych możliwości można wykorzystać na innych platformach.
  29. 6 punktów
    Pojawiają się tutaj co jakiś czas dyskusje o kosztach naszego hobby i o porównywaniu cen w różnych sytuacjach. Sam ostatnio zacząłem sprzedawać swoje projekty na Tindie, więc postanowiłem napisać artykuł wyjaśniający dlaczego rzeczy nowe, niszowe i robione przez hobbystów są takie drogie, podczas gdy takie Raspberry Pi Zero można kupić za 50zł (i dwa razy tyle kosztu wysyłki). Przy okazji być może wyjaśni to też dlaczego tak wiele kickstarterów się nie udaje. Różnica pomiędzy projektem a produktem Większość z nas ma już jakieś tam doświadczenie w realizowaniu projektów elektronicznych. Wymyśliliśmy (lub skopiowaliśmy z noty katalogowej) schemat, zaprojektowaliśmy płytkę, wytrawiliśmy ją, zamówiliśmy próbki części, zlutowaliśmy wszystko, zaprogramowaliśmy, zdebugowaliśmy, pięknie nam działa, koniec. Czas otwierać szampana i zakładać stronę na kickstarterze, już wkrótce wszyscy hobbyści będą mogli korzystać z naszego wspaniałego nowego produktu, który kosztował nas dużo mniej niż podobne produkty dostępne w sklepach, a przecież wyprodukowaliśmy tylko jedną sztukę -- w masowej produkcji powinno być jeszcze tańsze, prawda? Tak właśnie miałem z moim shieldem. Udało mi się gdzieś kupić okazyjnie matryce ledowe, które wielkością pasują idealnie do D1 Mini i aż się proszą o shielda. Napisałem też ostatnio bilbiotekę do obsługi HT16K33, który bardzo łatwo taką macierzą steruje. Tylko dodać dwa oporniki do I2C i gotowe. Będę to sprzedawał za dolara od sztuki. Kilka miesięcy i 5 prototypów później już nie byłem taki pewien. Oczywiście, błędy, które popełniałem były głupie i wynikały z roztargnienia i zbyt dużej pewności siebie. W końcu to taki prosty projekt. Mimo to czas mija, części na kolejne prototypy kosztują. Kilka razy projekt porzuciłem, ale jakoś zawsze jednak do niego wracałem. W końcu na początku roku uzyskałem coś, z czego byłem w miarę zadowolony. (Muszę tu przyznać, że projekt rzeczywiście był wyjątkowo pechowy, no ale nie kontrolujemy tego i nigdy nie możemy zakładać, że wszystko się uda.) No dobra, to teraz czas rozpocząć produkcję "masową". Powiedzmy 40 sztuk -- powinno się sprzedać błyskawicznie, jak tylko ludzie to zobaczą, to na pewno się rzucą i wtedy będę mógł zrobić kolejną partię, 400 albo i 4000 sztuk. No dobra, to gdzie najlepiej zrobić 40 płytek? Zdecydowałem się na DirtyPCB z ich ofertą 10 (+/-1) płytek o wymiarach 5x5cm -- bo udało mi się wcisnąć w tym obszarze cztery swoje płytki, a pozwalają na panelizację. Poprawiłem kilka detali, wcisnąłem po 4 płytki w jeden gerber, zamówiłem. Miesiąc później nadal czekam na płytki -- piszę do nich o co chodzi, zawsze płytki w 2 tygodnie były -- a oni mi odpisują, że mają dużą kolejkę po chińskim nowym roku, do tego musieli zmienić wykonawcę, etc. Acha, jako bonus, zmienili ostatnio wygląd strony i od tego czasu nie pokazuje się obrys płytki na podglądzie. Niby drobiazg, ale będzie to istotne później. W międzyczasie zamówiłem macierze i czipy. Płytki są małe, więc użyłem w nich najmniejszej wersji HT16K33, z minimalną liczbą nóżek. Okazuje się, że trudno znaleźć je w większych ilościach i są droższe. No trudno, kilka centów na czipie mnie nie zbawi, a płytki już zamówiłem. No to teraz macierze. Okazuje się, że są dwa rodzaje -- ze wspólna anodą i ze wspólną katodą. Oczywiście w przypadku macierzy 8x8 nie ma tu absolutnie żadnej różnicy, bo obie wersje mają po prostu LED-y podłączone do kolumn i wierszy, ale różnią się one wyprowadzeniami. Zatem należy uważać co się zamawia -- oczywiście najtańsze oferty nie mają w opisie informacji o tym jakie mają wyprowadzania albo jakiego są typu -- nie będę ryzykować kupowania 40 macierzy, które się potem okażą złe. Zatem trzeba wziąć te droższe. Zazwyczaj są w paczkach po 10 sztuk, więc sobie wymyśliłem, że zamówię różne kolory i ludzie będą sobie mogli wybrać. Doskonale, ale wszystko, co nie jest czerwone, jest dwa razy droższe. No trudno. To pewnie w ramach promowania komunizmu. Wysyłka na szczęście darmowa, zamówione. Mniej więcej dwa tygodnie po tych zamówieniach, pracując nad innymi projektami zorientowałem się, że co prawda mam zapas oporników, ale nie aż tyle, żeby zmontować te wszystkie macierze. No to jeszcze zamówiłem oporniki, 500 sztuk na zapas. Przyszły macierze. Zamawiając nie zauważyłem, że wszystkie są od tego samego sprzedawcy, więc przyszły w jednej paczce, która przez to przekroczyła próg cła i dopłaciłem drugie tyle za cło (tu gdzie mieszkam płaci się cło i "opłatę manipulacyjną" za to, że sprawdzili co to jest i oclili, która wynosi często więcej niż samo cło). Kolejna kosztowna pomyłka. W tym momencie już wiedziałem, że za dolara ich sprzedawać nie będę. Przyszły w końcu płytki. Okazało się, że zrobiłem błąd w projekcie i otwór na środku płytki, który powinien rozdzielać panele, nie jest wycięty. Oczywiście zemścił się brak podglądu, ale ostatecznie to moja wina. Dwa dni zajęło mi powycinanie 40 płytek dremelem. To teraz składanie. Najpierw polutowałem do wszystkich płytek oporniki i czipy. Oczywiście przez nieuwagę na dwóch płytkach czipy przylutowałem odwrotnie. Pojawiły się pierwsze zamówienia. Polutowałem do końca zamówione egzemplarze, przetestowałem czy działają i... jak ja mam to wysłać? Potrzebuję kopert bąbelkowych. W domu znalazłem dwie, na razie wystarczy, ale trzeba kupić więcej. Poszedłem na pocztę, popatrzyłem na ceny kopert i stwierdziłem, że zamówię je z Chin. No ale trzeba najpierw wysłać zamówienia. Ustalając ceny sprawdziłem koszty wysyłki na stronie poczty, więc teraz całkiem pewnie podaje pani w okienku koperty i mówię, że chcę to wysłać. Pani mierzy grubość i mówi, że musi wysłać jako paczkę, cztery razy drożej. No trudno, płacę i wracam do domu. Zamówiłem koperty (oczywiście dziesięć razy taniej niż na poczcie) i dodałem do strony produktu informację o tym, że wysyłam z nieprzylutowanymi nóżkami, bo inaczej się nie mieści do koperty. Biorę się za lutowanie pozostałych macierzy. Polutowałem wszystkie kolory i zabieram się za sprawdzanie -- zrobiłem sobie testing rig, tak że dość prosto mogę podłączyć i odpalić prosty program zapalający wszystkie piksele. Wszystkie niebieskie sprawne. Wszystkie czerwone sprawne, tylko w jednym miejscu mostek z cyny do usunięcia. Sprawdzam białe -- sprawna co druga. Hmm. Patrzę na kilka macierzy, które mi zostało -- oczywiście oznaczenia góra/dół mają całkowicie losowo -- a to według nich je lutowałem. Odlutować tego teraz już nie ma jak, połowa do wyrzucenia. Przyszły koperty, pojawiło się więcej zamówień. Skończyły mi się piny -- używałem tych, które miałem w zapasie -- trzeba zamówić. Kończy mi się rolka cyny, grot lutownicy zaczyna wykazywać oznaki zużycia. Moja lutownica jest markowa i droga i takież są też do niej groty. Wysyłam to, co mam zrobione aż się nie skończą -- średnio 1-2 zamówienia tygodniowo. Więcej nie będę raczej tego robić. Wszystkie projekty udostępniłem na otwartej licencji -- może jakiś Chinczyk to weźmie i zacznie produkować taniej i z darmową wysyłką. Koniec końców, wyszło około $5 za sztukę, z około $2 za wysyłkę do tego. Czyli siedem razy więcej, niż szacowałem. Oczywiście nie wliczyłem w cenę własnej robocizny -- ani godzin spędzonych na projektowaniu i testowaniu, ani na składaniu tego, ani na bieganiu na pocztę i wysyłaniu. Siedzę i czekam aż płytki dotrą do klientów -- i boję się, że coś będzie nie tak i trzeba będzie oddawać im kasę albo wysyłać nowe. Duży może więcej No dobra, to jakim cudem możemy kupować te płytki za $2 z darmową wysyłką? Dlaczego chińscy producenci nie mają takich problemów? Powodów jest kilka: Po pierwsze, mają subsydiowaną przez rząd darmową wysyłkę i wszystkie części dostępne na miejscu bez cła. Mogą kupować te najtańsze części bez dokumentacji, bo po prostu sobie sprawdzą czy wyprowadzenia są dobre. Po drugie, produkują w naprawdę gigantycznych ilościach i mają hurtowe ceny. Dodatkowo potrafią wynegocjować sobie naprawdę dobre warunki. Po trzecie, nie robią w zasadzie żadnej kontroli jakości. To jest krok, który u mnie okazał się najbardziej kosztowny -- nie dlatego, że był czasochłonny, choć był, ale dlatego, że wadliwych produktów nie sprzedam -- a Chińczyk by sprzedał. Po czwarte, mają naprawdę dobrze ogarnięty cały proces, wszystko przygotowane z góry, robili to już wiele razy, więc wiedzą czego się spodziewać. U mnie wiele kosztów wynikało z tego, że coś przegapiłem albo zapomniałem -- tam, nawet jeśli coś takiego się na początku zdarzy, to te koszty znikną przy takiej skali. Po piąte, nie mają kosztów projektowania, bo to są w większości otwarte projekty, które ktoś już im zaprojektował. Nawet jeśli musi na to spojrzeć specjalista, to znowu koszt jego pensji znika przy tej skali. Czyli kupować tylko od Chińczyka? Z ekonomicznego punktu widzenia, wydaje się to logiczną decyzją -- w końcu pieniądze nie rosną na drzewach. Najlepiej więc projektować wszystko tak, żeby używało tanich chińskich modułów? Taka taktyka działa dobrze na krótką metę. Jednak jest jeden podstawowy problem -- oni rzadko projektują coś nowego, nawet kiedy to robią, to nie jest to zbyt długo wspierane. W tym samym czasie technika galopuje do przodu i pojawiają się nowe rozwiązania. Potrzebujemy nowych projektów i potrzebujemy społeczności wokół nich, które będą je wspierać. Zatem być może jednak warto kupić czasem taki "przedrożony" nowy produkt -- w ramach inwestycji na przyszłość.
  30. 5 punktów
    Nixie - lampy od których nie można oderwać wzroku. Kiedyś podstawowy element do prezentowania danych, dzisiaj poszukiwany rarytas przez pasjonatów. Chciałem zaprezentować kilka zegarów jakie wykonałem swego czasu. Opiszę jeden konkretny, a na końcu pokażę kilka innych konstrukcji, które maja podobną elektronikę. Podstawowe funkcje Lampy LC-531 firmy DOLAM Format wyświetlania czasu HH:MM:SS Wyświetlanie daty Dwa niezależne czujniki temperatury DS18B20 Podtrzymanie bateryjne pracy układu zegara Prosta obsługa za pomocą pilota Programowany alarm z różnymi trybami powtórzeń Kilka melodyjek do wyboru jako dźwięk budzika Możliwość wł/wył zera z przodu Programowana częstotliwość „przewijania” lamp, w celu uniknięcia zatrucia katod Elektronika Zegar został oparty o mikrokontroler Atmega8 i zegar RTC PCF8563 . W urządzeniu można wyszczególnić kilka funkcjonalnych bloków: Zegar RTC przetwornica czujniki temperatury odbiornik IR multipleksowanie lamp Przetwornica oparta jest o poczciwego NE555, a jasność lamp reguluje się potencjometrem. Do zegara można podłączyć dwa czujniki temperatury, a odczytana z nich wartość będzie wyświetlana co kilkadziesiąt sekund. Do sterowania wykorzystany jest malutki pilot na podczerwień. Zegar posiada zaprogramowanych kilka melodyjek monofonicznych, które można ustawić jako dźwięk budzika. Użyłem do tego celu buzzer bez wbudowanego generatora. Fajną opcją jest tzw. “slot machine”, czyli krótkie przewijanie wszystkich cyfr, głównym celem tego zabiegu jest ochrona lamp przed zatruciem katod, zwłaszcza pierwszych lamp, gdzie cyfra nie zmienia się przez wiele godzin, szczególnie w zegarach gdzie wyświetlana jest tylko godzina. Efekt przewijania cyfr jest włączany co pięć minut i trwa 10 sekund. Jest to efekt naprawdę miły dla oka. Lampy są aktywowane za pomocą wysokonapięciowych tranzystorów z serii MMBT, a poszczególne cyfry z wykorzystaniem modułu 74141. Układ 74141 jest dekoderem kodu BCD na kod dziesiętny, który zaprojektowano specjalnie do sterowania lampami z zimną katodą. Obudowa W tym konkretnym egzemplarzu wykonana została z poczciwej zabejcowanej sosny. Całość została zamknięta pod pleksą, która była wygięta na ciepło zwykła opalarką. Płytka z elektroniką jest wyeksponowana, widać wszystkie elementy, a PCB jest zabezpieczone prostą soldermaską wykonaną z farby termoutwardzalnej. Schemat Niżej zamieszczam zdjęcia kilku innych zegarów jakie wykonałem, schemat elektroniczny jest w nich podobny.
  31. 5 punktów
    Na wstępie zaznaczam: ani kody nie są mistrzostwem świata, ani ta cała elektronika nie jest najwyższego lotu. Dla mnie ważne było przedstawienie działającego i przydatnego urządzenia, jeśli ktoś będzie chciał zrobić lepiej - przynajmniej będzie miał jakąś podstawę. Również estetyka może być dla kogoś wątpliwa - ale pamiętajmy o jednym: o gustach się nie dyskutuje. Nie zwracajcie uwagi na stan stolarki - mieszkanie jest do remontu. Dlatego też wszystkie elementy dekoracyjne przyklejone są po prostu taśmą - i tak trzeba będzie to rozebrać a po remoncie złożyć z powrotem. A więc... Zaczęło się od narzekań mojej pięknej pani, że odkurzacz się psuje a w ogóle to takie odkurzanie to straszna robota i ona ma dość. Ponieważ jestem bardzo podobnego zdania (jeśli chodzi o straszną robotę) staliśmy się właścicielami urządzenia o nazwie Roomba 805. Odkurzaczyk okazał się bardzo fajny. Bez zbędnych bajerów (nie potrzebujemy sterowania jakąś wymyślną aplikacją z komórki ani pilota żeby go włączyć jak się stoi metr od niego), jeździ, odkurza, karmi się sam i tyle. Niestety, z uwagi na układ mieszkania dwie wirtualne ściany dołączone w komplecie do odkurzacza to dla nas trochę za mało, trzy to minimum a najlepiej cztery. I co się okazało... cena takiego czegoś to 1/4 ceny odkurzacza! Akurat parę dni wcześniej na Forum byłą dyskusja o miganiu ledami. Jako że zadanie wirtualnej ściany sprowadza się praktycznie do migania - stwierdziłem że dwie i pół stówy na takie migadło to nieco za dużo. Zacząłem szukać jakichś gotowców - oczywiście najpierw znalazłem coś na Arduino, potem całą resztę na PIC-ach. Ponieważ moim zdaniem zastosowanie Arduino (nawet Pro Mini) do migania ledą to przerost formy nad treścią, a na PIC-ach to ja się ostatnio znałem w zeszłym tysiącleciu, postanowiłem zrobić coś od zera. W szufladzie leżały sobie dwie sztuki ATtiny13 (nadmiar ze starszego projektu) - więc postanowiłem je wykorzystać. Na początku jednak trzeba było określić, jak ta nieszczęsna dioda IR ma migać. W tym celu zacząłem czytać, czytać, czytać... i okazało się, że co autor to inne zdanie, co komentarz to "mi nie działa". W jednym przynajmniej wszyscy byli zgodni: dioda pracuje na 38 kHz. I tyle. No cóż... właściwie mogłem zacząć od czego innego. Znalazłem w rupieciach TSOP31236, co prawda jest on na 36 a nie na 38 kHz ale szybkie zerknięcie do datasheeta upewniło mnie, że powinien jako-tako działać (przynajmniej z bliska) na 38. Podłączyłem go do analizatora stanów, włączyłem oryginalną ścianę... no i okazało się, że to całe "miganie" sprowadza się do trzech impulsów po 0.5 msec co 8 msec, a potem przerwy gdzieś w okolicach 130 msec (przerwy były różne, od 100 do 150 msec, czyli najprawdopodobniej niekrytyczne). No cóż, teraz wypadałoby sprawdzić efekty moich ciężkich poszukiwań. Nabazgrany na kolanie kod skompilowałem w Arduino IDE, leda IR podłączona przez opornik 100Ω do PB0, czerwona przez 2kΩ do PB1, przytwierdzone gumką do koszyka na baterie... #ifndef F_CPU #define F_CPU 9600000UL #endif #include <avr/io.h> #include <util/delay.h> #define pon do { \ TCCR0A |= (1<<WGM01) | (1<<COM0A0);\ TCCR0B |= (1<<CS00); \ } while(0) #define poff do { \ TCCR0A &= ~((1<<WGM01) | (1<<COM0A0)); \ TCCR0B &= ~(1<<CS00); \ PORTB &= ~(1 << PB0);\ } while (0) int main(void) { char i,n; DDRB |= (1 << PB0) | (1 << PB1); PORTB |= (1 << PB1); OCR0A = 125; for (n=0;; n = (n+1) & 31) { if (!n) PORTB |= (1 << PB1); for (i=0; i<3; i++) { pon; _delay_us(500); poff; _delay_us(7500); } if (!n) PORTB &= ~(1 << PB1); PORTB &= ~(1 << PB0); _delay_ms(132); } } Odkurzacz bardzo grzecznie zareagował, wycofał się z terenu pilnowanego przez moje migadło i ruszył w swoją stronę. W tym momencie już byłem pewny, że urządzenie będzie działać i mogę się bawić w wersję finalną. Przede wszystkim pomyślałem, że warto trochę pooszczędzać baterie. Poczytałem sobie nieco o usypianiu i oszczędnościach, wyszło mi coś takiego, że ATtiny działa przez ok. 17 milisekund a następnie idzie sobie spać. Całkiem nieźle, ale brakowało mi jednej rzeczy, której nie ma w oryginalnej ścianie: wskaźnika poziomu baterii. Niestety - ATtiny13 nie potrafi zmierzyć napięcia zasilania. Wypróbowałem kilka różnych sposobów (w tym jeden, który nawet nieźle działał - potencjometr podłączony do jednego z wyjść ATtiny i porównanie przez komparator z wewnętrznym napięciem wzorcowym), tyle że w pewnym momencie uświadomiłem sobie, że "ściana" będzie na stałe zamocowana w krytycznych miejscach i zasilanie mogę wziąć skądś obok - na pewno nie z baterii (urządzenie ma być stuprocentowo bezobsługowe). Tak więc wszystkie pomiary zostawiłem sobie na przyszłość (jeśli będę robił wersję na baterie) i wziąłem się do roboty. Najważniejsze było niewpuszczenie odkurzacza do kuchni (możliwa mokra podłoga i pałętanie się pod nogami człowiekowi co może nieść coś gorącego) oraz zakaz wstępu za szafkę z telewizorem (trochę kabli tam niestety leży, podłączone jest w sumie siedem urządzeń z których trzy wiszą na ścianie). Ponieważ szafka stoi zaraz obok wejścia do kuchni, postanowiłem zrobić tylko jedno urządzenie, do którego podłączę dwie ledy IR, a zasilanie 5V wezmę po prostu z USB telewizora, dodając dodatkowo akumulatorek na wypadek, gdyby elektrowni akurat odbiło wyłączyć mi prąd kiedy odkurzacz sprząta. Ponieważ musiałem zasilić dwie diody IR (a myślałem jeszcze o trzeciej, chociaż zostawiłem to sobie na później), diody nie są podłączone bezpośrednio do wyjścia ATtiny, ale przez tranzystor (użyłem tu 2N2222 tylko dlatego, że jako pierwszy wpadł mi do ręki). Urządzenie wyszło całkiem zgrabnie: Schemat połączeń: Trzypinowe łącza zastosowałem dlatego, aby nie trzeba było zastanawiać się którą stroną włożyć wtyczkę. Jednocześnie nawet w przypadku pomylenia wtyczki od diody kontrolnej z IR od razu widać, że kontrolka świeci nie tak jak powinna. Kod się niewiele bardziej skomplikował: #ifndef F_CPU #define F_CPU 9600000UL #endif #include <avr/sleep.h> #include <avr/wdt.h> #include <avr/io.h> #include <util/delay.h> ISR(WDT_vect) {} #define pon do { \ TCCR0A |= (1<<WGM01) | (1<<COM0A0);\ TCCR0B |= (1<<CS00); \ } while(0) #define poff do { \ TCCR0A &= ~((1<<WGM01) | (1<<COM0A0)); \ TCCR0B &= ~(1<<CS00); \ PORTB &= ~(1 << PB0);\ } while (0) int main(void) { char i, n; DDRB |= (1 << PB0) | (1 << PB1); PORTB |= (1 << PB1); OCR0A = 125; // watchdog MCUSR &= ~(1<<WDRF); WDTCR |= (1 << WDCE) | (1 << WDE); WDTCR = 1 | (1 << WDCE); WDTCR |= (1 << WDTIE); sei(); for (n=0;; n= (n + 1) & 7) { if (!n) PORTB |= (1 << PB1); for (i=0; i<3; i++) { pon; _delay_us(500); poff; if (i<2) _delay_us(7500); } if (!n) PORTB &= ~(1 << PB1); for (i=0; i<5; i++) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); } } } Pozostało mi tylko umieszczenie diod. O ile przy szafce byłoby to proste (w sumie tę diodę nie bardzo widać czyli można by zrobić dowolne, najprostsze mocowanie), o tyle przy framudze nie chciałem, aby wystawała tam jakaś elektronika. Poradziłem sobie w prosty sposób: ponieważ zawsze mi się podobały różne bajki o krasnoludkach, Pożyczalskich i innych stworach zamieszkujących dom - dioda IR została ukryta w drzwiach do domku Zgredka, dioda kontrolna to alarm przy drzwiach, a wjazdu za szafkę pilnuje Nessie Urządzenie się sprawdza, prąd pobiera jakiś znikomy (zdechły prawie całkowicie akumulatorek wydłubany ze starego laptopa, naładowany na tyle żeby sprawdzić że działa, wytrzymał prawie miesiąc - dopiero potem podłączyłem ładowarkę do USB), alarm przy drzwiach Zgredka wesoło sobie mruga, więc teraz przyszła pora na urządzenie numer dwa. Tu niestety miałem większy problem. Z uwagi na dość dziwaczny układ mieszkania (troje drzwi w wąskim korytarzyku) jak bym nie umieścił diody broniącej drzwi do łazienki, zawsze coś się odbijało od białej stolarki (framugi, trzecie drzwi) i odkurzacz bał się wjechać przez właściwe drzwi. Wymyśliłem sobie, że zrobię jakąś barierę foto która będzie włączać diodę IR tylko wtedy, kiedy robot spróbuje wjechać do łazienki (tam mu nie wolno), ale wychodziło mi to jakieś straszliwie skomplikowane. I tu znowu czytanie Forum mi pomogło - ktoś w pewnym wątku zaproponował diodę laserową. Postanowiłem spróbować - akurat i tak coś w Botlandzie kupowałem, tak że diodę wziąłem przy okazji z myślą, że jeśli to mi nie wyjdzie, wykorzystam do jakiegoś inngo projektu. Okazało się to strzałem w dziesiątkę. Co prawda zaprojektowanie mocowania diody (z koniecznością regulacji, bo kąty w 80-letniej stolarce są proste tylko z nazwy) przysporzyło mi nieco roboty i nie wyszło dokładnie jak chciałem, ale spełnia swoje zadanie. Tu już program się skomplikował. Założenia były następujące: Jeśli fototranzystor jest zwarty (na czas regulacji), dioda laserowa świeci cały czas aby umożliwić wycelowanie promienia; Jeśli drzwi do łazienki są zamknięte (kontaktron), nie ma potrzeby uruchamiania led; nic nie świeci, nic nie miga, ATtiny sprawdza sobie tylko raz na jakiś czas czy otworzyłem drzwi; Jeśli drzwi są otwarte, dioda laserowa włącza się na co chwilę i sprawdzane jest, czy robot nie próbuje wleźć tam gdzie nie trzeba. Dioda kontrola błyska sobie co kilka sekund; Jeśli wykryta zostaje obecność robota, włącza się dioda IR, i wyłącza się dopiero chwilę po odjeździe robota. Dioda kontrolna błyska szybciej. Tutaj też zastosowałem dwie diody IR (po obu stronach framugi), ale tym razem połączyłem je po prostu szeregowo. Tak więc kod znów nieco urósł: #ifndef F_CPU #define F_CPU 9600000UL #endif #include <avr/sleep.h> #include <avr/wdt.h> #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define PIN_IRED PB0 #define PIN_CONTROL PB1 #define PIN_PHOTO PB2 #define PIN_LASER PB4 #define PIN_DOOR PB3 #define setPin(a) do {PORTB |= (1 << (a));} while(0) #define unsetPin(a) do {PORTB &= ~(1 << (a));} while(0) ISR(WDT_vect) {} #define pon do { \ TCCR0A |= (1<<WGM01) | (1<<COM0A0);\ TCCR0B |= (1<<CS00); \ } while(0) #define poff do { \ TCCR0A &= ~((1<<WGM01) | (1<<COM0A0)); \ TCCR0B &= ~(1<<CS00); \ unsetPin(PIN_IRED);\ } while (0) int adc_read (void) { ADMUX = (1 << MUX0) | (1 << ADLAR); ADCSRA |= (1 << ADSC) ; while (ADCSRA & (1 << ADSC)); return ADCH; } #define LASER_DELAY 500 #define MIN_PHOTO 20 #define CALIBRATE 2 #define SHADE 1 #define DECAY 3 uint8_t readPhoto(void) { int8_t i, pom;uint8_t na, nb; ADCSRA |= ( 1<<ADEN); for (i=pom=0;i<3;i++) { if (i) _delay_us(LASER_DELAY); na = adc_read(); if (!i && na < 5) { ADCSRA &= ~( 1<<ADEN); return CALIBRATE; } setPin(PIN_LASER); _delay_us(LASER_DELAY); nb=adc_read(); unsetPin(PIN_LASER); if (na > MIN_PHOTO && na - MIN_PHOTO > nb) pom++; } ADCSRA &= ~( 1<<ADEN); return (pom > 1) ? 0 : SHADE; } int main(void) { int8_t ndark, res, i; uint8_t ledctl; DDRB |= (1 << PIN_IRED) | (1 << PIN_LASER) | (1 << PIN_CONTROL); PORTB |= (1 << PIN_CONTROL) | (1 << PIN_DOOR); OCR0A = 125; // watchdog MCUSR &= ~(1<<WDRF); WDTCR |= (1 << WDCE) | (1 << WDE); WDTCR = 1 | (1 << WDCE); WDTCR |= (1 << WDTIE); // ADC ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); sei(); for (ndark = ledctl = 0;;) { if (ndark > 0) { ndark --; res = DECAY; } else { if (!(PINB & (1 << PIN_DOOR))) { for (i = 10; i >= 0; i--) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); } ledctl = 0; continue; } res = readPhoto(); if (res == CALIBRATE) { ndark = 0; setPin(PIN_LASER); for (;;) { _delay_ms(100); res = readPhoto(); if (res != CALIBRATE) break; } unsetPin(PIN_LASER); _delay_ms(100); continue; } } if (res) { if (res != DECAY) ndark = 20; if (!ledctl) setPin(PIN_CONTROL); ledctl = (ledctl + 1) & 3; for (i=0; i<3; i++) { pon; _delay_us(500); poff; if (i<2) _delay_us(7500); } unsetPin(PIN_CONTROL); for (i=0; i<5; i++) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); } } else { if (!ledctl) { setPin(PIN_CONTROL); _delay_ms(10); unsetPin(PIN_CONTROL); } for (i=0; i<3; i++) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); } ledctl = (ledctl + 1) & 31; } } } Schemat połączeń wygląda mniej więcej tak (odtwarzam z pamięci): Kilka uwag: Użyłem gotowego modułu z diodą laserową, który ma już potrzebny rezystor (stąd brak na schemacie). Fototranzystor TEPT 4400 został użyty przede wszystkim dlatego, że go miałem. Prawdopodobnie nadałby się dowolny reagujący na kolor światła diody. Mój błąd - rezystor R3 podłączony jest cały czas do VCC zamiast np. być zasilany razem z diodą laserową (oszczędność energii). Jak już wspomniałem - urządzenie jest zasilane z sieci, czyli nie jest to krytyczne, ale w razie gdyby komuś chciało się coś takiego zrobić można pomyśleć o podłączeniu tego rezystora razem z diodą i odpowiednim przerobieniu funkcji readPhoto(). Na początku bałem się jednak, że nie będę mógł odróżnić zwarcia fototranzystora od jego oświetlenia - dlatego tak już zostało. I znowu kwestia umieszczenia tego wszystkiego na framudze drzwi w ten sposób, aby nic (ani szalejący odkurzacz, ani jakieś przypadkowe potrącenie) nie ruszyło diody. Ponieważ miałem już domek Zgredka - dorobiłem mu saunę i wygódkę. Przy okazji wyskoczył bardzo ciekawy efekt uboczny - światło diody laserowej prześwieca przez pomarańczowy "murek" sauny i tworzy wrażenie płonącego w saunie pieca Urządzenie numer dwa zasilane jest oddzielnie ze zwykłej starej ładowarki od e-papierosa. Planuję wspólne zasilanie obu urządzeń - ale aby podciągnąć tam kabel muszę wbić się po drodze pod dwa progi (i tak do wymiany) - czyli czekam na remont...
  32. 5 punktów
    Miniaturowy Tetris z pięcioma przyciskami, głośniczkiem Piezo i ekranem Oled 128×64. To wszystko przy zaledwie sześciu dostępnych GPIO jednodolarowego Digisparka/ATtiny85. Moja wersja kodu dodaje kilka ulepszeń, które znacząco zmieniają odbiór całej gry (opisane niżej), a koszt budowy całego zestawu wynosi około 15 zł. ATtiny Tetris Gold Multi Button obsługuje narastający poziom trudności (przyspieszanie opadania wraz z usuwaniem kolejnych linii), informację o klocku pojawiającym się w kolejnej turze, podpowiedź o pozycji klocka w dolnej partii planszy, pełną pseudo-losowość doboru klocków, dźwięki i temat muzyczny z oryginalnej gry. Poniżej mój filmik prezentujący ten układ w działaniu: W filmie można zobaczyć krótkie urywki z rozgrywki, proces instalacji szkicu w urządzeniu oraz pełny, pięciominutowy gameplay. Sprzęt Jakiś czas temu zainteresowały mnie klasyczne gry retro dla ATtiny85, ale w repo Attiny-Arduino-Games wszystkie były zaledwie dwu-przyciskowe. Tetris wymagał nieco więcej logiki, ale i tak obsługiwało się go przez naciskanie lub przytrzymywanie jednego z tylko dwóch przycisków, co generowało błędy i nie było zbyt wygodne. Z czasem jednak pojawiła się w repo wersja Tetris Multi Button, w której rozwiązano ten problem wykorzystując odpowiednią kombinację rezystorów i przycisków, dzięki czemu podłączono trzy przyciski pod jeden pin mikrokontrolera. Nie posiadam czystego ATtiny85, ale miałem na stanie Digisparka z tym chipem i postanowiłem złożyć to urządzenie. To chyba pierwsze nagranie wideo takiego zestawu - w sieci brak w sieci brak filmów i opisów wykonania pełnej, pięcio-przyciskowej wersji. Żeby się nie pogubić podczas montażu , korzystając z rozpiski pinów Digisparka i ATtiny85 przeniosłem dostarczony ze sketchem poniższy schemat: na lekko chaotyczną wersję graficzną dla stykowej płytki prototypowej i Digisparka zasilanego baterią 9V: a przy okazji też dla czystego ATtiny85 zasilanego baterią 3V: Poszczególne przyciski odpowiadają za: start nowej gry lub restart aktualnie rozgrywanej, włączenie/wyłączenie układu, obrót, przyspieszenie opadania, przesunięcie w lewo, przesunięcie w prawo. Przytrzymanie przycisku opadania i włączenie restartu gry aktywuje tryb ducha, a przytrzymanie przycisku opadania razem z przyciskiem obrotu podczas restartu ustawia trudny poziom gry, wypełniając dodatkowo błędnie klockami część planszy. Po aktywacji tych opcji grę należy uruchomić przyciskiem przyspieszonego opadania. Wersja na czystym ATtiny85 potrzebuje tylko 3V, bo sketch jest pisany dla obniżonego do 8MHz taktowania zegara. Wersję dla Digisparka zasilam poprzez pin VIN 9V baterią i przy takim poborze wystarczy jej na baaardzo długo. Wymagane do działania 5V przenoszę dodatkowym, pustym goldpinem na lewą stronę płytki prototypowej za pomocą dziesięciocentymetrowego przewodu połączeniowego żeńsko-męskiego. Po zlutowaniu powyższego układu w połączeniu z gołym ATtiny85 i po ubraniu go w miniaturowy brelok do kluczy, koszt (bez baterii) zamknąłby się poniżej 15 złotych. Na Aliexpress ATtiny85 kosztuje 0,80$, ekran Oled 128×64 1.80$, mały piezo buzzer 0,17$, a reszta części to już koszty groszowe. Tym sposobem otrzymujemy pełną grę sterowaną w identyczny sposób, jak w wielkich automatach Arcade lata temu, a do tego zasilaną malutką baterią 3V. Do zestawu zamiast białego ekranu można wybrać ekran niebieski lub żółto-niebieski, ale ponieważ ten ostatni jest dzielony na dwie różne części z odstępem, to nie prezentuje się zbyt atrakcyjnie (co widać na powyższym filmie) i polecam jednokolorowy odpowiednik. Potencjalny brelok mógłby wyglądać tak, jak na obrazku poniżej: Kod Zmiany w kodzie, których dokonałem, nie są duże, ale znaczące w odbiorze gry. Poniżej różnice między moją wersją, dostępną na GitHubie, a oryginałem gry dla ATtiny85: Dodałem losowość doboru klocków – domyślnie ATtiny Tetris generuje tę samą sekwencję klocków w każdej nowej grze, bo użyta funkcja random korzysta w kółko z tej samej tablicy liczb losowych. Programiści nie aktywowali randomSeed, ponieważ wszystkie piny w układzie są już podłączone. Moja wersja przesuwa tablicę liczb pseudo-losowych po każdym rozpoczęciu gry inkrementując seed do EEPROMu i aktywując w ten sposób pełną pseudolosowość doboru klocków (powtarzają się tylko pierwsze dwa). Grając w oryginalną wersję, do piątej linii miałem już ustalony optymalny schemat położenia klocków, przez co gra stawała się nudna. Teraz jest już poprawnie i mam świadomość, że wykorzystanie EEPROMu w randomSeedowaniu ograniczy liczbę rozgrywek do zaledwie 99000 (podana liczba uwzględnia już obecny w kodzie zapis najlepszych wyników również do EEPROMu). Na starcie gry dodałem fragment tematu muzycznego z oryginalnej gry Tetris z 1986 roku – domyślnie brak jakiejkolwiek muzyki w grze. Po wybraniu trybu ducha temat muzyczny jest nieco dłuższy. Dodałem dźwięk opadającego klocka (tylko podczas swobodnego spadania) oraz inny dźwięk dla klocka, który kończy opadanie. Domyślnie dźwięki w tej grze pojawiają się sporadycznie – tylko podczas usunięcia pełnej linii klocków oraz na zakończenie gry. Naprawiłem część błędnie wyświetlanych fontów na ekranie startowym Domyślnie wyłączyłem tryb ducha, który wyświetla podpowiedź o docelowej pozycji klocka. Tryb ducha można aktywować sposobem opisanym powyżej pod konfiguracją przycisków. Ze swoimi zmianami musiałem się zmieścić w sześciu procentach wolnej pamięci. Obecnie pozostaje już tylko 1% wolnego Projekcik jest dość interesujący i co najważniejsze, w pełni użyteczny, więc możliwe, że znajdą się osoby chcące zbudować taki układzik. Jako dodatek zamieszczam więc proces instalacji. Instalacja Kod zabiera blisko 100% pamięci ATtiny85, więc na Digisparku nie mieści się bootloader i nie można uploadować sketcha poprzez USB – należy więc skompilować hexa i wgrać go za pomocą programatora ISP. Jako programatora użyłem Arduino wg poniższego schematu: Na Arduino trzeba wgrać dostępny w przykładach Arduino IDE sketch ArduinoISP. Aby poprawnie skompilować tę wersję dla Digisparka należy w Arduino IDE zastąpić dodatkowy adres URL dla menadżera płytek od Digistump JSONem dla czystego ATtiny85, a następnie wybrać płytkę ATtiny25/45/85, procesor ATtiny85, zegar Internal 8MHz. Następnie z menu szkic eksportować skompilowany program, który zostanie wtedy umieszczony w katalogu źródła sketcha. Na koniec zostaje już tylko wgranie hexa na Digisparka poprzez Arduino programem avrdude. Poniżej przykładowe polecenie kopiujące (z fusami) wykonane na macOS, ale w innych systemach wygląda podobnie: /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/avrdude -C/Applications/Arduino.app/Contents/Java/hardware/tools/avr/etc/avrdude.conf -v -pattiny85 -cstk500v1 -P/dev/cu.usbmodem14101 -b19200 -Uflash:w:/Users/username/Documents/ATtiny-Tetris-Gold/ATtiny-Tetris-Gold.ino.tiny8.hex -U lfuse:w:0xF1:m -U hfuse:w:0xD5:m -U efuse:w:0xFE:m Jak przebiega taki proces można obejrzeć na końcu powyższego filmiku. Poniżej też zdjęcie "programatora" i układu obok siebie. W filmie i na zdjęciach do włączania układu korzystam z przełącznika suwakowego SS22T25, ale lepiej sprawdził się przełącznik prosty ESP1010. Napięcia na przyciskach są istotne i podczas gry trzeba uważać aby nie dotykać rezystorów Ten problem wyeliminuje się po zlutowaniu układu. Najlepszy wynik gry jest również zapisywany w EEPROMie. Ponieważ głośniczek jest podłączony do pierwszego pinu Digisparka, to dodatkowo otrzymujemy LEDowe sygnały świetlne w momencie odtwarzania dźwięków. Po zakończeniu gry Tetris natychmiast przechodzi w tryb uśpienia z minimalnym poborem prądu, jednak do Digisparka dodałem przełącznik włączający/wyłączający zasilanie dla układu – wersja opierająca się wyłącznie na ATtiny85 nie wymaga wykonania tego kroku. Gra chodzi bardzo płynnie, co widać na powyższym filmie, gdy przytrzymuję przycisk przyspieszonego opadania dla kilku klocków pod rząd. Miniaturowy ATtiny Tetris Gold jest bardzo regrywalny (nie nudzi się) i to niesamowite, że udało się go upchnąć na tanim ATtiny85 przy zachowaniu tak dużej funkcjonalności. Serdecznie polecam montaż tego prostego układu. Powiększenia układów i trochę więcej informacji można znaleźć na moim blogu: http://jm.iq.pl/tetris
  33. 5 punktów
    Cyfrowa stacja lutownicza Jest to mój 2 prolekt po 12 letniej przerwie z elektroniką. Była to okazja do poznania Eagle oraz podstaw programowania mikroprocesorów. Obecnie wiele rzeczy bym poprawił i docelowo tak się chyba stanie. Działanie stacji oceniam bardzo pozytywnie. Obecnie mam 3 stacje lutownicze, więc już mogę coś na ten temat napisać ale to już dłuższy temat. Projekt polecam wszystkim, którzy mają niewykorzystane trafo 2x12V 60VA (minimum) oraz LCD1602 i procesor Atmega8. Są to chyba 3 najdroższe elementy (pomijając kolbę 907A, którą przez internet można kupić poniżej 30zł z kosztami wysyłki). Docelowo schemat podzieliłem na 2 zasadnicze części: 1. Płytka zasilająca 2.Płytka sterowania Wzory płytek w Eagle standardowo dostępne są w załączniku. A tutaj jeszcze foto gotowych płytek: Aby ułatwić możliwość wymiany procesora i wzmacniacza operacyjnego, zostały one umieszczone w podstawkach. Płytka sterująca oraz płytka zasilająca zostały połączone za pomocą złącza goldpin. Obudowa została wykonana z płyt meblowych oklejonych fornirem dębowym. Dodatkowo składałem dla znajomego CNC z chin i w ramach testów wykonałem panel przedni oraz tylni na tym CNC (materiał to 1,5mm blacha aluminiowa). Efekty pracy widać na poniższych zdjęciach: Zasilanie 230V trafia na gniazdo komputerowe oraz włącznik (pozyskane z zasilacza ATX). Następnie mamy bezpiecznik szklany i transformator toroidalny 50VA 2x12V. Transformator miał wymienione uzwojenia wtórne. Miałem transformator z tylko jednym uzwojeniem o napięciu 10,5V, więc od nowa zostały nawinięte uzwojenia 2x12V. Takie napięcia są wprowadzone zgodnie z zamieszczonym schematem na płytkę zasilającą. Zastosowałem najprostszą kolbę 907A z termoparą. Wykorzystałem dostępne w sieci oprogramowanie stacji lutowniczej RL-1 zawierające algorytm PID do sterowania grzałką. Konstrukcja nie jest pozbawiona wad: Obudowa nie jest dokładnie spasowana z panelami czołowym i tylnym (miała być tymczasowa, a wyszło jak zwykle). Słaby obieg powietrza w obudowie (pomimo tego faktu nic się nie przegrzewa przy długiej pracy. Oto film prezentujący rozgrzewanie grota od temperatury 38 stopni do 320 stopni: Już w 22 sekundzie grzałka osiąga temperaturę zadaną. Od 35 sekundy przykładam do grota cynę o grubości 0,7mm. Cyna zaczyna się topić ok. 50 sekundy. Temperatura grota została zestrojona ze wskazaniem stacji za pomocą termopary i procedury opisanej w dokumentacji stacji RL-1 (w załączniku AVT987). A to obecnie przeze mnie posiadane stacje lutownicze: Jak już wcześniej wspomniałem, wykonałbym kilka zmian. Najważniejsza to zmniejszenie wymiarów stacji. Trafo zajmuje 1/3-1/4 obudowy. Obecnie całość znalazłaby się na jednym PCB, wszystkie elementy SMD, cała stacja zmieściłaby się za LCD. Do tego trafo i wymiar całości zmniejszony minimum o połowę. Poza tym, prócz najdłuższego rozgrzewania i braku mocy przy lutowaniu dużych pól masy stacja działa nad wyraz dobrze. EAGLE_Moja stacja lutownicza.zip AVT987.pdf Cyfrowa_Stacja_Lutownicza_RL1 - do wgrania.zip Cyfrowa_Stacja_Lutownicza_RL1 - edytowalne oprogramowanie.zip Cyfrowa stacja lutownicza RL1.zip
  34. 5 punktów
    Dla mnie to logiczne że ta maszynka nie jest wydrukowana z filamentu PET. Przecież pierw autor musiał zbudować tą maszynkę aby mieć ten filament Nie wiem jak sie ma PET do ABS czy PLA pod względem wytrzymałości. Nawet jeśli wyraźnie gorszy, to przecież nie zawsze jest wymagana super wytrzymałość. No i często drukuje się z jakimś tam wypełnieniem.
  35. 5 punktów
    O mnie Witam, Jestem Maciej - pracuje jako software architect (nie mam wykształcenia elektronicznego dlatego proszę o wyrozumiałość jeżeli chodzi o połączenia i rozwiązania - z tego też powodu w projekcie nie daje gotowego przepisu na zasilanie ) i żeby do końca nie zgnuśnieć po godzinach tworzę platformę RemoteMe. W platformie chodzi głównie o ułatwienie sterowaniem urządzeniami IoT poprzez internet - bez konieczności posiadania VPNa, publicznego IP. Po stronie RemoteMe tworzycie strony internetowe ( RemoteMe posiada hosting na Wasze pliki ) + zestaw bilbiotek (Javascript, RasbeprryPi (python), Arduino ESP ) które w łatwy sposób pozwolą na komunikowanie się z Waszymi urządzeniami. Co do protokołu to opracowałem własny (bardziej jest to konwencja przesyłu paczek niż protokół jako taki ) (działa przez sockety, websockety, wywoływania RESTowe) - umożliwia on przesył wiadomości do określonego urządzenia, i coś w rodzaju topic- subscribera ( u mnie się to nazwa"variables" zmienne ) Wasze urządzenia rejestrują się w RemoteMe po zarejestrowaniu, możecie do nich wysyłać komendy przez stronę internetową albo z innych urządzeń. Jednym z ostatnich featerów są "Out of the box projects" - polega to na tym, że jednym kliknięciem importujecie projekt na Wasze konto - oczywiście możecie potem wszytko zmieniać wedle własnych pomysłów - właśnie ostatnim takim projektem jest Samochód RaspberryPi z kamerką o którym w tym kursie. Projekt jest częściowo openSourcowy - bilbioteki Javascript, Python, api Restowe są openSource - sam kod serwera i program na RasbeprryPi jest zamknięty. Platformę tworzę sam - po godzinach i udostępniam za darmo O kursie Ten kurs – przedstawia budowę samochodu sterowanego przez przeglądarkę z wyświetlaniem obrazu z kamerki. Jest to dość specyficzny kurs (jak pisałem wyżej ) – całość oprogramowanie jest już zrobiona, a dodanie plików do własnego konta w RemoteMe sprowadza się do paru kliknięć. Po tak dodanym projekcie można własnoręcznie i dowolnie edytować wszystkie pliki źródłowe (strona WWW skrypt pythonowy) – zwłaszcza, że same pliki projektu nie są skomplikowane, a kod jest dość czytelny i samo opisujący się (mam przynajmniej taką nadzieję ) Na dole kursu opisana jest bardziej szczegółowo zasada działania samochodu. Jeżeli nie jesteście zainteresowani samą platformą RemoteMe to i tak myślę, że w kursie znajdziecie garść pomysłów na podobny projekt Kurs właściwy Na filmie działanie + krok po kroku wszystko z tego kursu. W poprzednim kursie pokazałem jak sterować pozycją kamerki i przechwytywać obraz na przeglądarkę tutaj i sterowanie kamerką tutaj . Teraz rozbudujemy ten projekt i zbudujemy samochód z napędem na 4 koła ( sterowany podobnie jak czołg – żeby skręcić prawa para kół musi się kręcić z inną prędkością niż lewa). Taki efekt otrzymamy na wideo też całość kursu – można zaglądnąć, gdy gdzieś utkniecie Części RaspberryPi z wifi ( np zeroW) link Podwozie z silnikami link Sterownik serwomechanizmów na I2C link Kamera do Rpi + taśma jeżeli potrzebna link Dwa SerwoMechanizmy kompatybilne z uchwytem kamerki kamery link Uchwyt na kamerkę z serwami link Mostek H TB6612FNG link Zasialnie – np akumlatory podłączone do przetwornicy – żeby uzyskać odpowiednie napięcie link Połączenia RaspberryPI steruje serwami poprzez moduł PWM i napędem przez ustawianie stanu pinów na mostku oraz dostarczając sygnału PWM poprzez ten sam moduł, który wysyła sygnał do serwomechanizmów. (Dzięki modułowi do generowanie sygnału PWM nie musimy tych sygnałów generować przez samo RaspberryPi – co jest dość problematyczne, poprostu przez I2C przesyłamy odpowiednie instrukcje do sterownika serw (poprzez bibliotekę pythonową dostarczoną przez adafruit), a ten generuje odpowiedni sygnał PWM dla serwo mechanizmów i do mostka H) Schemat połączeń: Poprzez magistrale I2C RPi steruje kontrolerem serwo mechanizmów, dwa ostanie wyprowadzenia kontrolera są podłączone do mostka H, gdzie wykorzystując sygnał PWM ustawiamy prędkość silników. Do mostka H są również podłączone piny RPi które stanami wysokim i niskim będą określać kierunek obrotu silników napędowych – po szczegóły odsyłam do dokumentacji układu TB6612FNG, równie dobrze można użyć mostka L298N lub podobnego. Zaprojektowałem płytkę PCB, którą możecie użyć pliki eagle,gerber itd tutaj plik pcb.zip Schemat płytki pokrywa się ze schematem powyżej. Wyprowadzenia płytki: Wejście sygnału PWM z kanałów 15 i 14 modułu PWM Wejście zasilania silników do poruszania się Zasilanie układów (PWM, RPi) koniecznie dokładne +5V Wyjście silników napędu, pierwsze dwa wyjścia do jednej pary silników kolejne dwa do drugiej Zasilanie serw i w tym przypadku silników napędu w moim przypadku ~6V (należy sprawdzić w specyfikacji serw i silników, jakie maksymalne napięcie można podłączyć) ZWORKA gdy zepniemy dwa piny napięcie z 5 będzie podawane też do zasilania silników napędu ZWORKA gdy jest podłączona zasilane jest RaspberryPI z połączenia 3 przed podłączeniem zworki należy dokładnie sprawdzić napięcia, żeby nie uszkodzić Najdroższego komponentu czyli właśnie malinki Wlutowujemy kabelki, bo nie będziemy korzystali z konwertera stanów Wlutowujemy kabelki, bo nie będziemy korzystali z konwertera stanów Oczywiście jest jeszcze potrzebne odpowiednie zasilanie, w moim przypadku 6v jako napięcie silników napędu i serw, oraz 5v dla RasbeprryPi i kontrolerów. Poniżej kilka zdjęć poglądowych całości samochodu: Programowanie Przed utworzeniem projektu skonfigurujcie kamerkę i komunikacje I2C używając raspi-config opisane tutaj. Ten projekt jest jednym z gotowych projektów, które możecie prosto zaimplementować kilkoma kliknięciami: KLIK - po zalogowaniu otworzy się projekt. Przejdźcie do zakładki “Build It” i podążajcie krokami, na końcu klik w “Build Project” i otrzymacie: Po kliknięciu “Get QR” pokaże się kod QR, który możecie zeskanować smartfonem, lub po prostu otworzyć stronę przyciskiem “Open” w przeglądarce na komputerze. Narazie nie radzę zmieniać pozycji kamery dopóki nie ustawimy pozycji serw – w niektórych przypadkach możecie uszkodzić swoje serwomechanizmy. Samochód powinien jeździć jak na filmie – może się zdarzyć, że skręca w złą stronę albo serwa są źle skalibrowane, poniżej w omawianiu kodu napisałem jak to naprawić. Omówienie tego, co się stało Jak zauważyliście, tworzenie projektu było mocno zautomatyzowane. Dlatego omówię teraz, co się dokładnie wydarzyło i jak modyfikować Wasz projekt. Przede wszystkim utworzyły się dwie zmienne (zakładka variables): Zmienna cameraPos przesyła pozycje kamery, drive pozycje joysticka. Obie są typem “Small int x2” oznacza to, że wartoscią zmiennej są dwie liczby integer. Strona internetowa zmienia nasze zmienne, a skrypt pythonowy te zmiany rejestruje i odpowiednio reaguje (jak rozwiniemy zmienne zobaczymy, że urządzeniem nasłuchującym na zmiany jest właśnie skrypt pythonowy). Zobaczmy jak wygląda kod Pythonowy (więcej o zmiennych tutaj) Python Skrypt pythonowy został automatycznie wgrany. Oczywiście możemy go podejrzeć i modyfikować ( żeby stworzyć nowy skrypt pythonowy np dla innych projektów zobacz tutaj) . Z informacji jakie teraz są Ci potrzebne to skrypt pythonowy to kolejne urządzenie w remoteMe jest zarządzalne przez skrypt (uruchomiony przez ./runme.sh) , do tego urządzenia możemy wysłać wiadomości, urządzenie reaguje też na zmiany zmiennych, które obserwuje i może te zmienne zmieniać. Żeby otworzyć skrypt pythonowy kliknij python.py i wybierz Edit : Wygląda on następująco. Poniżej omówię ciekawsze fragmenty import logging import socket import math import struct import sys import os os.chdir(sys.argv[1]) sys.path.append('../base') import remoteme import Adafruit_PCA9685 import time import RPi.GPIO as GPIO motorAIn1 = 25 # GPIO25 motorAIn2 = 8 # GPIO8 motorBIn1 = 24 # 24 motorBIn2 = 23 # 23 motors = [[motorAIn1, motorAIn2], [motorBIn1, motorBIn2]] motorsPWM = [14, 15] pwm = None; def motorForward(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.HIGH) def motorBackward(motorId): GPIO.output(motors[motorId][0], GPIO.HIGH) GPIO.output(motors[motorId][1], GPIO.LOW) def motorSoftStop(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.LOW) def setMotor(motorId, speed): if speed == 0: motorSoftStop(motorId) elif speed > 0: motorForward(motorId) elif speed < 0: motorBackward(motorId) speed=-speed logger.info("set speed {} for motor {} ".format(speed,motorId)) pwm.set_pwm(motorsPWM[motorId], 0, int(speed)) def onCameraPosChange(i1, i2): global pwm logger.info("on camera change {} , {}".format(i1, i2)) pwm.set_pwm(1, 0, i1) pwm.set_pwm(0, 0, i2) pass def onDriveChange(x, y): logger.info("on drive change x {} , y {}".format(x, y)) global pwm left=y right=y left+=x right-=x delta=(left+right)/2 left+=delta right+=delta # when your car doesnt drive as suppose try to swich right and left variable below # or remove add minuses next to 2 # another way is to switch cables conencted to motors setMotor(0, 2*left) setMotor(1, 2*right) pass def setupPWM(): global pwm pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(80) def setupPins(): global GPIO GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme for motor in motors: for pinId in motor: GPIO.setup(pinId, GPIO.OUT) try: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%d.%m %H:%M', filename="logs.log") logger = logging.getLogger('application') setupPWM() setupPins() remoteMe = remoteme.RemoteMe() remoteMe.startRemoteMe(sys.argv) remoteMe.getVariables().observeSmallInteger2("cameraPos" ,onCameraPosChange); remoteMe.getVariables().observeSmallInteger2("drive" ,onDriveChange); remoteMe.wait() finally: pass Sterowanie silnikami: def motorForward(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.HIGH) def motorBackward(motorId): GPIO.output(motors[motorId][0], GPIO.HIGH) GPIO.output(motors[motorId][1], GPIO.LOW) def motorSoftStop(motorId): GPIO.output(motors[motorId][0], GPIO.LOW) GPIO.output(motors[motorId][1], GPIO.LOW) def setMotor(motorId, speed): if speed == 0: motorSoftStop(motorId) elif speed > 0: motorForward(motorId) elif speed < 0: motorBackward(motorId) speed=-speed logger.info("set speed {} for motor {} ".format(speed,motorId)) pwm.set_pwm(motorsPWM[motorId], 0, int(speed)) Funkcja setMotor dla motorId 1 lub 2 ustawia prędkość speed (może być ujemna). poprostu najperw na odpowiednich pinach ustawiamy odpowiednio stany (ruch do przodu do tyłu, hamowanie), a następnie w zależności od prędkości ustawiamy odpowiednio wypełnienie PWM korzystając ze sterownika serw. def onCameraPosChange(x, y): global pwm logger.info("on camera change {} , {}".format(x, y)) pwm.set_pwm(1, 0, x) pwm.set_pwm(0, 0, y) pass Funkcja setMotor dla motorId 1 lub 2 ustawia prędkość speed (może być ujemna). poprostu najperw na odpowiednich pinach ustawiamy odpowiednio stany (ruch do przodu do tyłu, hamowanie), a następnie w zależności od prędkości ustawiamy odpowiednio wypełnienie PWM korzystając ze sterownika serw. def onDriveChange(x, y): logger.info("on drive change x {} , y {}".format(x, y)) global pwm left=y right=y left+=x right-=x delta=(left+right)/2 left+=delta right+=delta # when your car doesnt drive as suppose try to swich right and left variable below # or remove add minuses next to 2 # another way is to switch cables conencted to motors setMotor(0, 2*left) setMotor(1, 2*right) pass Powyższa funkcja zostanie wywołana jak zmieni się zmienna drive – np po zmianie joysticka na stronie. x,y to po prostu współrzędne wychylenia joysticka (1024,1024) oznacza wychylenie maksymalnie do góry i w prawo. Na podstawie tych zmiennych wyliczamy prędkość lewej i prawej strony samochodu. Jeżeli samochód skręca, zamiast jechać do przodu, jedzie do tyłu zamiast do przodu: setMotor(0, Y2*left) setMotor(1, X2*right) Dajcie minusy w różnych kombinacjach (w miejsca X i Y) do czasu, aż samochód jedzie do przodu – gdy joystick jest wychylony do góry. (będzie to odpowiadać zamianą miejscami przewodów lewej strony dla miejsca Y i prawej strony dla miejsca X). Następnie, jeżeli prawa i lewa strony są zamienione (samochód skręca w złą stronę ), w funkcji powyżej zamieńcie left i right miejscami. def setupPWM(): global pwm pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(80) def setupPins(): global GPIO GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme for motor in motors: for pinId in motor: GPIO.setup(pinId, GPIO.OUT) Po prostu ustawiamy odpowiednie piny (te do sterowania mostkiem H) na wyjścia. I tworzymy obiekt do kontrolowania sterowania serw. (Uwaga żeby sterownik serw działał prawidłowo musimy włączyć komunikacje I2C używając raspi-config więcej tutaj ) remoteMe.startRemoteMe(sys.argv) remoteMe.getVariables().observeSmallInteger2("cameraPos" ,onCameraPosChange); remoteMe.getVariables().observeSmallInteger2("drive" ,onDriveChange); remoteMe.wait() Ustawienie RemoteMe i ustawienie jakie funkcję mają zostać wywołane, gdy zmienne do sterowania kamery i napędu zostaną zmienione. To tyle w samym skrypcie pythonowym, jak widzicie, nie jest on zbyt skomplikowany, po więcej informacji zapraszam tutaj Strona WWW Tak naprawdę zostały stworzone dwie strony WWW — jedna do kalibracji druga — strona do sterowania samochodem i wyświetlania obrazu z kamerki. Otwórzmy stronę do kalibracji: Otworzy się strona internetowa z dwoma suwakami. Ustawmy górny i dolny na środkową pozycję – kamera się poruszy- górny suwak powinien poruszać kamerę w osi x, dolny y. Jeżeli się tak nie dzieje – zamieńcie miejscami przewody serwomechanizmu. Następnie za pomocą suwaków ustalcie maksymalne wychylenie osi x i osi y dla mnie jest to: x : 298 – 830 i centralna pozycja. Ważne, żeby centralna pozycja byłą dokładnie pomiędzy przedziałem u mnie ((298+830) /2 = 564) y: 223 – 723 i podobnie centralna pozycja kamery w osi y powinna być w środku przedziału Zapiszmy liczby gdzieś w notatniku i otwórzmy do edycji stronę do sterowania samochodem: <camera autoConnect="true" showInfo="true" class="cameraView"></camera> <connectionstatus webSocket="true" directConnection="false" camera="true"></connectionstatus> <variable component="cameraMouseTrack" type="SMALL_INTEGER_2" style="display:block" name="cameraPos" xMin="298" xMax="830" invertX="true" yMin="223" yMax="723" invertY="true" requiredMouseDown="true" reset="true" onlyDirect="true"></variable> <div class="joystickButtons"> <div class="buttons"> <variable class="gyroscope" component="gyroscope" type="SMALL_INTEGER_2" name="cameraPos" label="Gyroscope Camera" orientationSupport="true" xMin="298" xMax="830" xRange="19" invertX="true" yMin="223" yMax="723" yRange="20" invertY="false" onlyDirect="true"></variable> <variable class="gyroscope" component="gyroscope" type="SMALL_INTEGER_2" name="drive" label="Gyroscope Drive" xMin="-512" xMax="512" xRange="19" invertX="false" yMin="-512" yMax="512" yRange="20" invertY="false" onlyDirect="true"></variable> <button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect gyroscope" onClick="toggleFullScreen()">fullscreen </button> </div> <div class="joystickParent"> <variable class="joystick" component="joystick_simple" type="SMALL_INTEGER_2" name="drive" xRange="1024" yRange="1024" onlyDirect="true"></variable> </div> <div style="clear: both;"/> </div> Są to automatyczne komponenty do sterowania samochodem i wyświetlaniem obrazu wideo. Strona, którą otworzyliście zawiera już wszystkie komponenty potrzebne do sterowania waszym samochodem. Jedyne co trzeba zrobić to zmienić zakres ruchów serwo mechanizmów. xMin,xMax,yMin,yMax, zamieńcie na wartości jakie otrzymaliście na poprzedniej stronie z suwakami. Jeżeli chcecie stworzyć własną stronę ze swoimi komponentami najlepiej utworzyć ją od początku pokazane tutaj – pozwoli Wam to dodawać komponenty w przy pomocy kreatora, gdzie ustalicie potrzebne parametry, albo po prostu edytować źródła tej już utworzonej strony – wcześniej warto utworzyć kopię, gdyby coś poszło nie tak (albo skasować pliki i utworzyć projekt jeszcze raz – wtedy nie zapomnijcie wcześniej wykasować też zmienne) Po zmianie wartości x/y/Min/Max możemy otworzyć naszą stronę np w smartfonie, klikamy na index.html, ale tym razem wybieramy opcje get anymous link Następnie, klikamy ikonkę kodu QR, a kod, który się pojawi skanujemy smarfonem. Oczywiście sterowanie działa również poprzez internet – nie tylko w sieci lokalnej, jednak w niektórych przypadkach jest potrzebna dodatkowa konfiguracja więcej o niej tutaj Trochę szczegółów technicznych ( nie obowiązkowe ) RemoteMe serwuję stronę WWW do sterowania Waszym samochodem ( a dodatkowo Was loguje na Wasze konto – stąd token w linku otwieranym przez smartfon ) i uczestniczy w negocjowaniu tworzenia połączenia WebRTC. Połączenie webRTC jest to połączenie bezpośrednie (RaspberryPi – przeglądarka ( w niektórych przypadkach np za NATem jest potrzebny dodatkowo stun sewer)). Po stworzeniu połączenia webRTC stan zmiennych nie jest w ogóle wysyłany do remoteMe (bo pole “onlyDirect” w komponentach jest ustawione na true). Protokołem webRTC przesyłany jest też obraz, a że webRTC tworzy połaczenie point to point opóźnienie jest znikome. Program na RaspberryPi który odpalacie poleceniem ./runme.sh tworzy połączenie websocketowe z platformą RemoteMe oraz zarządza skryptem pythonowym (wysyła do niego wiadomości, przesyła wiadomości ze skryptu dalej do platformy etc ). Działanie skryptu pythonowego jest możliwe dzięki dodatkowym bilbiotekom RemoteMe (znajdują sie w folderze leafDevices/base/ ). Sama strona internetowa po websocketach łączy się do platformy RemoteMe (pozwalają na to skrypty javascriptowe zaimportowane w headerze pliku index.html ze ścieżek /libs/). Ułatwiają i ustanawiają komunikacje z platformą RemoteMe. Same komponenty wstawione w index.html typu : <variable component="**" W funkcjach pliku remoteMeComponents.js są zastępowane na “standardowe” i “bootstrapowe” komponenty htmlowe, dodatkowo do komponentów przypinane są eventy reagujące na akcje użytkownika i wysyłające odpowiednie komunikaty do skryptu pythonowego. Można podejrzeć jak remoteMeComponents.js zamienia i tworzy nowe komponenty – może to być interesujące gdy macie potrzebę stworzenia własnych komponentów, które RemoteMe nie pozwala dodać z kreatora. W większości przypadków akcje Waszych komponentów będą wykonywać zapis zmiennych w postaci RemoteMe.getInstance().getVariables() .setSmallInteger2("cameraPos",123,456,true); która wyśle do skryptu pythonowego informacje o zmianie zmiennej, podobnie sterujemy silnikami ustawiając odpowiednią zmienną. Podsumowanie Tworząc tej projekt chciałem pokazać Wam jak w łatwy sposób sterować Waszym samochodem z widokiem FPV. Projekt można rozbudowywać, lub zmieniać np, gdy korzystanie z innego mostka H niż ja. Zachęcam zatem do eksperymentowania ze źródłami projektu . Gdy jest to Wasz pierwszy projekt, zachęcam do zrobienia na początek projektu z mrugającą diodą i poczytanie dokumentacji na www.remoteme.org Pozdrawiam, Maciej
  36. 5 punktów
    Właśnie zaakceptowałem Twój opis, możesz go teraz zgłosić do akcji rabatowej umieszczając link w temacie zbiorczym. Dziękuję za przedstawienie ciekawego projektu, zachęcam do prezentowania kolejnych DIY oraz aktywności na naszym forum Świetny projekt, bardzo lubię takie klimaty! Tutaj dla porównania moje "analogowe" statystyki Forbota (liczba osób online + odsłony z całego dnia):
  37. 5 punktów
    Witam, od kiedy kupiłem swoje arduino (było to ze trzy lata temu) to chciałem zbudować frezerkę do płytek pcb. Obejrzałem w Internecie wiele projektów i w końcu postanowiłem zbudować swoją własną frezarkę :). Pochłonęła ona dużo pieniędzy i jeszcze więcej czasu. Swoje prace zacząłem od kupienia profili 25mmx 1.5mm x 2000mm (dwie sztuki) i kilkanaście kątowników. Wymierzyłem całą konstrukcję i zacząłem składać stelarz stołu a następnie go pomalowałem podkładem i czarną farbą matową. Gdy farba schła zamówiłem wsporniki wałków, wałki fi 12, łożyska oraz kupiłem skleję 10mm na stół. następnym krokiem było położenie blachy na stół żeby nie zniszczyć sklejki potem zacząłem składać oś Z z wałków fi 8 Kilkanaście dni później kontrukcja wyglądała następująco została postawiona brama, została ona wzmocniona zastrzałami z tyły oraz lewa i prawa strona bramy została połączona płaskownikiem stalowym 4mm x 20mm. Cała konstrukcja była bardzo solidna. Pozostało pomalowanie bramy na kolor czarny mat ale to dopiero w wakacje jak zrobi się ciepło Dzisiaj odbyły się pierwsze testy bezpieczeństwo przede wszystkim Całość wymaga oczywiście kalibracji oraz muszę kupić nakrętki bezluzowe na śruby trapezowe. Całość jest sterowana a pomocą GCode. Obszar roboczy to 40cm x 40cm. Elementy potrzebne do budowy to: 4 wałki fi12 (dwa na oś X i dwa na oś Y) 2 wałki fi8 8 wsporników wałków fi 12 4 wsporniki wałków fi 8 profile na stelarz blacha aluminiowa na oś Z trzy zestawy składające się z śruby trapezowej wraz z nakrętką, uchwytem nakrętki, łożyskami samonastawnymi, sprzęgła elastycznego (po komplecie na każdą oś) 3 silniki krokowe 3 mocowania silników arduino 3 sterowniki silnków krokowych CNC shield zasilacz 12V 4A frezy V 20 stopni komplet wierteł od 0.6mm do 1.5mm Potrzebujemy jeszcze silnik do wrzeciona, ja użyłem "pisaka" i dremela. Kosztów nie liczę gdyż nie chcę się załamać ale frajda z budowy była ogromna. Płytki pcb projektuje w Eaglu następnie tworzę gerbery które ląduję do programu flatcam. W tym programie ustawiam wymiary frezu, wierteł i generuje gcode który przesyłam do Arduino za pomocą programu source rabbit gcode sender. Ważna rzecz, przed zaladaowanie pliku drill do flatcamu musimy się upewnić ze każda współrzędna składa się z takiej samej ilości znaków jeśli nie to musimy dopisać odpowiednią ilość zer na początku (tzn po X lub Y ) następnie gdy załamujemy plik drill do flatcamu musimy zmniejszyć skalę tego pliku. Wchodzimy właściwości> scale i ustawiamy na 0.1
  38. 5 punktów
    Witam, jest to mój pierwszy projekt, na którym uczyłem się nieco programowania ... a że w piwnicy leżał mi popsuty odkurzacz to postanowiłem go ożywić po swojemu. Odkurzacz który notabene dostałem jako gratis działał dosłownie 10 minut po czym nie dawał oznak życia. 1.Podwozie jest wykorzystane w 100% z oryginału, nie zmieniałem nic oprócz zrobienia miejsca na elektronikę. 2. Z oryginału wykorzystałem również zasilanie (czyli ogniwa Li-lon) wraz z ładowarką. Zasilanie było oryginalne 7.2 V 3. Elektronika - wykorzystałem Arduino UNO wraz z shield sterownika L293D do 4x silników DC lub 2x krokowych w sumie wykorzystałem taki bo taki miałem, trochę nad wyrost bo zostają nie wykorzystane (a może jeszcze nie wykorzystane) dwa wejścia pod silniki DC. Jako że zaczynałem od podstaw programowanie, przysporzyło mi to trochę problemów. Ale od czego jest forum Na początku udało mi się zrobić aby pojazd sam się poruszał i odbijając od przeszkód (za pomocą dwóch umieszczonych wyłączników krańcowych umieszczonych z przodu odkurzacza) zmieniał kierunek jazdy, nie działało to w 100% tak jak sobie to na początku założyłem, ze względu na ogromny brak wiedzy w programowaniu, ale jednak pierwsze efekty pracy zainspirowały mnie do dalszej pracy nad robotem. #include <AFMotor.h> AF_DCMotor motorP(1); // silnik prawy AF_DCMotor motorL(2); // silnik lewy #define zdL 9 #define zdP 10 void setup() { motorP.setSpeed(255); motorL.setSpeed(255); pinMode(zdP, INPUT_PULLUP); pinMode(zdL, INPUT_PULLUP); } void loop() { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; // jazda do tyłu if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); } // // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(FORWARD); } // skręt w lewo else if (zderzakP == LOW) { // delay(200); motorP.run(FORWARD); motorL.run(BACKWARD); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } Z shelda wykorzystałem piny 9 oraz 10 do serwa jako sterowanie do krańcówek. Kolejną rzecz jaką chciałem zrobić i pobawić się było stworzenie możliwości sterowania odkurzaczem za pomocą bluetooth oraz telefonu z androidem. A więc jak tylko paczuszka ze sklepu pojawiła się w moim domu wraz z modułem bluetooth (2.1 XM-15B 3,3V/5V) postanowiłem działać dalej. Pierwszy problem to połączenie modułu bluetooth z płytką, musiałem dolutować w odpowiednie miejsca przewody aby móc komunikować się z arduino (Rx, Tx) jak również doprowadzenie zasilania. Jednak nie stanowiło to większego wyzwania, udało się za pierwszym razem. Następnie przyszedł czas na połączenie bluetooth z telefonem. Udało mi się to zrealizować również w dość szybkim czasie (wcześniej oczywiście przeglądałem różnego rodzaju poradniki, czy posty kolegów z forum). Przyszedł czas na aplikację do telefonu, jako że gotowe rozwiązania nie podobały się (a może bardziej ambicja wzięła górę) postanowiłem stworzyć coś własnego. Z pomocą przyszła stronka http://ai2.appinventor.mit.edu. Gdzie w sposób prawie że obrazkowy udało mi się zrobił własny interfejs z własna logiką. Przyszedł czas na oprogramowanie w Arduino wszystkich funkcji które chciałem uzyskać tj: możliwość ręcznego sterowania przełączania na tryb automatyczny sterowania prędkością silniczków Udało mi się to za pomocą kodu: #include <AFMotor.h> AF_DCMotor motorP(1); // silnik prawy AF_DCMotor motorL(2); // silnik lewy #define zdL 9 #define zdP 10 String data; void setup() { Serial.begin(9600); Serial.println("Test portu"); pinMode(zdP, INPUT_PULLUP); pinMode(zdL, INPUT_PULLUP); bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; } uint8_t oP = 255; uint8_t oL = 255; int pierwszyStart = 1; void loop() { if (Serial.available() > 0) { delay(1); char znak = Serial.read(); data += znak; pierwszyStart = 2; ///////////// Prędkość silników ///////////// if (data == "X") { oP = oP + 1; } if (data == "x") { oP = oP - 1; } if (data == "Y") { oL = oL + 1; } if (data == "y") { oL = oL - 1; } ///////////// Prędkość silników ///////////// Serial.print("Prędkość silnika prawego: "); Serial.println(oL); Serial.print("Prędkość silnika lewego: "); Serial.println(oP); if (data == "G") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(FORWARD); motorL.run(FORWARD); } if (data == "B") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(BACKWARD); motorL.run(BACKWARD); } if (data == "L") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(BACKWARD); motorL.run(FORWARD); } if (data == "R") { motorP.setSpeed(oP); motorL.setSpeed(oL); motorP.run(FORWARD); motorL.run(BACKWARD); } if (data == "S") { motorP.setSpeed(0); motorL.setSpeed(0); } if (data == "A") { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; motorP.setSpeed(oP); motorL.setSpeed(oL); // jeżeli oba zderzaki if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(250); motorP.run(FORWARD); motorL.run(BACKWARD); delay(1150); } // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(FORWARD); motorL.run(BACKWARD); delay(100); } // skręt w lewo else if (zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(BACKWARD); motorL.run(FORWARD); delay(100); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } data = ""; } else { if (pierwszyStart == 1) { bool zderzakL = digitalRead(zdL) == HIGH; bool zderzakP = digitalRead(zdP) == HIGH; motorP.setSpeed(oP); motorL.setSpeed(oL); // jeżeli oba zderzaki if (zderzakL == LOW && zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(250); motorP.run(FORWARD); motorL.run(BACKWARD); delay(1150); } // skręt w prawo else if (zderzakL == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(FORWARD); motorL.run(BACKWARD); delay(100); } // skręt w lewo else if (zderzakP == LOW) { motorP.run(BACKWARD); motorL.run(BACKWARD); delay(100); motorP.run(BACKWARD); motorL.run(FORWARD); delay(100); } // jazda do przodu else { motorP.run(FORWARD); motorL.run(FORWARD); } } } delay(50); } Na pewno nie jest on w 100% zgodny ze sztuką, ale nic dziwnego bo programowania się nie uczyłem. Jest to zlepek funkcji odnalezionych w internecie i przystosowanych do moich potrzeb. Szczerze chciałbym zobaczyć prawidłowy wygląd kodu Na tym chyba zakończę podsumowując że obiekt spełnił moje oczekiwania, a to jest chyba najważniejsze: mogę sterować robotem/odkurzaczem z telefonu przy włączeniu uruchamia się tryb automatyczny bez potrzeby uruchamiania aplikacji w telefonie możliwość włączania/wyłączania na tryb automatyczny z telefonu sterowanie robotem w trybie automatycznym (w przypadku chęci korekty kierunku jazdy) i poza nim odbijanie od przedmiotów Filmik prezentujący funkcjonalność automatycznej jazdy.
  39. 5 punktów
    O czymś podobnym myślałem praktycznie od chwili kupna drukarki. I pewnie dalej bym myślał, gdyby nie projekt na Majsterkowie, opisujący podobną (prostszą) konstrukcję. A i tak przymierzałem się do tego jak pies do jeża, zawsze cos mi przeszkadzało (a to nie potrafiłem rozwiązać problemu zasilania, a to miałem coś pilniejszego do roboty, a to nie miałem jakiegoś tam elementu...). Ale po zrobieniu mojej przystawki do OctoPrinta i (całkiem udanych) próbach druku w wielu kolorach - a co się z tym wiąże koniecznością ręcznej zmiany filamentu w odpowiednim momencie - potrzeba stała się raczej pilna. Zacząłem więc od sprecyzowania założeń. Monitorek miał przede wszystkim wyświetlać aktualne dane na temat wydruku (temperatury, stan drukarki, postęp). Jako że główną jego funkcją miało być zwrócenie uwagi na coś ważnego (np. konieczność zmiany filamentu czy wychłodzenie stołu wystarczające do zdjęcia wydruku) w czasie, kiedy byłem zajęty innymi Wielce Ważnymi Rzeczami (np. oglądaniem najnowszego odcinka przygód bohaterskiego Hannibala Smitha czy innego McGyvera) sygnalizacja powinna być głosowa. Jednocześnie najważniejsze parametry (temperatura i postęp) powinny być wyświetlane w czytelny sposób nawet dla krótkowidza bez okularów - czyli żadne nawet największe cyferki, jakiś pasek postępu w kontrastowych kolorach albo jakiś inny czytelny glif. Zasilanie akumulatorowe (na stoliku przy telewizorze nie mam jak podłączyć zasilacza), z możliwością podłączenia ładowarki. Nadałem więc urządzeniu roboczą nazwę OctoMon, wymęczyłem na forum że ktoś mi wreszcie wyoślił temat ładowarki (dzięki @marek1707!) i zabrałem się do konkretnego projektowania. Miałem już wyświetlacz, moduł ESP8266E i parę innych potrzebnych drobiazgów. Początkowo chciałem ESP umieścić na płytce podłączanej bezpośrednio do pinów wyświetlacza - niestety, jakbym ścieżek nie prowadził i tak jednostronna płytka wychodziła mi za duża. Postanowiłem więc dać sobie spokój, zastosować adapter i użyć po prostu płytki uniwersalnej. Ponieważ tego modelu wyświetlacza już uzywałem, eksperymenty z dźwiękiem też się powiodły (przynajmniej w zakresie wystarczającym do uruchomienia gadacza) - mogłem mieć pewność, że od strony programu nie będę już miał żadnych niespodzianek. Postanowiłem więc zaprojektować całą (niezbyt skomplikowaną zresztą) elektronikę. Jako że akurat w Botlandzie pojawił się moduł MAX9837A postanowiłem go wykorzystać jako DAC i wzmacniacz dźwięku. Niestety nie zdał egzaminu... ale o tym później. Zasilanie rozwiązałem w najprostszy chyba z możliwych sposób. Akumulator połączony z ładowarką, do tego przetwornica MT3608 ustawiona na 5V. Wyświetlacz i DAC zasilane bezpośrednio z 5V, ESP przez stabilizator LM1117, połączony z resztą świata jak na schemacie poniżej. Teoretycznie powinno to działać... ...No i już na wstępie pojawił się problem. Podłączony bezpośrednio (znaczy się kabelkami) do ESP i zasilany z USB moduł dźwiękowy pokazał co potrafi - czyli jak mi zepsuć dobry humor. Z powodów niewiadomych raz działał raz nie... a do tego owo niedziałanie powodowane było chyba fanaberiami motylków w Brazylii albo aktualna pogodą na Marsie. Doszedłem do wniosku, że USB to niespecjalnie dobry sposób zasilania, po prowizorycznym podłączeniu jakichś uczciwych 5V wydawało mi się, że działa. Postanowiłem więc sprawdzić wszystko później już na gotowym układzie. Może się to komuś wydać dziwaczne i ryzykowne... ale miałem w odwodzie sprawdzone rozwiązanie które co prawda dawało niższą jakość dźwięku, ale za to nie okazywało żadnych fanaberii Reszta elektroniki to praktycznie tylko połączenie tego wszystkiego do kupy - mogłem się więc zabrać za projekt obudowy. Nie chciałem się bawić w wymyślanie jakichś skomplikowanych kształtów, a więc obudowa została wydrukowana w kilku częściach i skręcona śrubkami M2. Początkowo urządzenie miało mieć jeden klawisz, ale okazało się, że mam wolne dwa piny GPIO, mogłem więc połączyć dwa. Płytę czołową postanowiłem umieścić pod kątem ze względu na wyświetlacz (który nie lubi jak patrzy się na niego lekko z boku, masz się gapić prosto i już!). Oprócz wyświetlacza miały tam się znaleźć głośnik i klawisze. W sumie więc górna część obudowy wygląda na projekcie tak: Otwory obok głośnika są przelotowe - od zewnątrz jest do nich przykręcona kratka mocująca i osłaniająca głośnik. Mocowanie klawiszy jest dopasowane do ratra płytki uniwersalnej (podobnie zresztą, jak mocowania płytki pod ESP8266). Cała reszta elektroniki oprócz DAC-a została umieszczona w dolnej części obudowy: Oprócz koszyka na akumulator są tam mocowania dla ładowarki, przetwornicy i małej płytki pod ESP. Po złożeniu cały układ wygląda tak: Niestety - po złożeniu wszystkiego w całość okazało się, że DAC nie bardzo chce ze mną współpracować. Co prawda wyczyniał swoje hece to dużo rzadziej, ale jednak. Postanowiłem więc wypróbować inny układ: wzmacniacz (wykorzystana połowa układu) oraz prosty filtr: Okazało się, że działa to całkiem znośnie - prawdopodobnie potrzebna by była jeszcze dodatkowa filtracja na zasilaniu (w głośniku słychać czasem ciche trzaski) ale bez tego już mogłem się obejść. Po złożeniu całość wygląda tak: I tu uwaga: ponieważ wątpię, aby ktoś kto chciałby zrobić to urządzonko miał dokładnie takie same elementy jak ja i identycznie spaczone poczucie estetyki - nie zamieszczam STL-i tylko plik dla OpenSCAD-a. Są w nim zawarte wymiary poszczególnych elementów i może być przydatny. No i kilka słów o programie. Program łączy się z serwerem OctoPrint i okresowo odpytuje o stan drukarki i (w przypadku gdy jest to drukowanie) o postęp. Oprócz podstawowych stanów sygnalizowanych przez serwer odróżniane są: Offline - drukarka jest wyłączona lub serwer nie odpowiada Rozgrzewanie stołu Rozgrzewanie dyszy Studzenie stołu - gdy po zakończeniu drukowania temperatura jest nie niższa niż 30°. Wciśnięcie pierwszego klawisza w trybie pauzy powoduje, że monitorek przestanie się odzywać. Bez tego co chwila będzie krzyczał że masz zmienić filament. W trybie studzenia powoduje przejście w tryb bezczynności. Wciśnięcie drugiego klawisza spowoduje podanie głosowo godziny. Dłuższe wciśnięcie pozwala na zmianę gadatliwości programu. Serwer WWW pozwala na zmianę wszystkich ważnych parametrów w dowolnej chwili. W trybie "drukowanie" wyświetlane są informacje o temperaturze dyszy i stołu, postępie w procentach oraz czasu dotychczasowanego i prognozowanego. Dodatkowo wyświetlane są: Adres IP monitora Bieżąca godzina Stan naładowania akumulatora Poziom gadatliwości (tylko wydarzenia/postęp/postęp i pozostały czas) Włączenie OTA Siła sygnału WiFi W trybie Offline monitor zachowuje się jak zegarek - wyświetla bieżące godzinę i datę Jeśli w czasie resetu urządzenia przytrzymamy pierwszy klawisz, startuje ono w trybie AccessPoint. Pod podanym adresem zgłasza się serwer WWW, gdzie można zapisać wszystkie potrzebne parametry. Jeśli w czasie resetu urządzenia przytrzymany drugi klawisz, startuje ono w trybie awaryjnym. W tym trybie nie będzie działać nic oprócz OTA. Przydatne, jeśli coś tak naknocimy w programie że nie będziemy mieli dostępu do OTA w normalnym trybie. Program został napisany z pomocą Arduino IDE. Biblioteka syntezy mowy jest na githubie. Pozostałe biblioteki instalowane były "po bożemu" poprzez managera bibliotek. Syntezator mowy to zwykły syntezator formantowy (użyłem w większości oryginalnego kodu D. Klatta z początku lat 80-tych), dostosowany kiedyś przeze mnie do języka polskiego. Dostosowanie nie jest może najlepsze - ale i syntezator Klatta nie jest mistrzem dykcji Kalibrację miernika poziomu akululatora należy przeprowadzić włączając opcję DEBUG w Octomon.h i podając w pliku wifi.cpp adres i port , na którym będziemy odbierać komunikaty UDP. Należy do wejścia przetwornicy podłączyć woltomierz, odczytać komunikat "Volts=..." i w pliku "display.cpp" w funkcji displayBattery() w linijce: ivolt = ivolt * 413 / 753; podstawić właściwe wartości (czyli napięcie akumulatora w setnych wolta oraz wartość odczytaną a przetwornika A/C). W moim przypadku jak widać woltomierz podał 4.13V a przetwornik zinterpretował to jako wartość 753 Aby program działał, należy w Arduino IDE ustawić zegar 160 MHz, tryb pamięci QIO oraz częstotliwość Flash 80 MHz. Dołączony programik bmconvert.py pozwala na zapisanie jako tablicę w C obrazka PNG. Obrazek powinien być zapisany w trybie indeksowanej palety kolorów bez przezroczystości, będzie przetworzony na skompresowaną w RLE tablicę, a do jego wyświetlenia należy użyć funkcji drawBitMap() z pliku display.cpp (lub analogicznej). Sprawdzony na Linuksie, ale powinien działać na wszystkim gdzie się da zainstalować Pythona 2.7 i PIL. Urządzenia używam od jakichś dwóch tygodni, na razie jest bardzo przydatne. octomon.zip
  40. 5 punktów
    Dzień dobry Nie będę zupełnie oryginalny i zrobiłem dwie stacje meteo. Chciałem poduczyć się trochę arduino i szukałem pomysłu na projekt przeglądając Botland znalazłem czujniki pyłu PM 2,5 i PM 10. Przez to, że temat smogu jest na czasie uznałem to za dobry pomysł by zweryfikować czy miejscowość w której mieszkam (wieś) jest od niego wolna. Zacząłem od kursów na Forbocie (vel wyświetlacz lcd) by załapać podstawy arduino i elektroniki. Były bardzo pomocne. Następnie chciałem przetestować niektóre czujniki i tak sprawdziłem Temperatura DS18B20 MCP9808 SHT 15 SHT 31 Wilgotność DHT 11 DHT 22 SHT 15 SHT 31 Przy wyborze też między innymi kierowałem się dokładnością pomiaru najlepiej ok 5% oraz możliwością pracy przy ujemnych temperaturach im mniej tym lepiej gdyż mrozy tu mogą sięgać -20C. Przy testowaniu tylko miałem problem z DHT11 i DHT22 - mianowicie nie podawał mi poprawnych danych (miałem obok kupny wilgotnościomierz i dane zupełnie nie pasowały do siebie ale opisałem to w innym poście na forum). Wybrałem MCP9808 gdyż uznałem, na czujnik temperatury gdyż wg moich obserwacji najlepiej się sprawdzał w różnych warunkach i wahaniach temperatury. Osobno tak samo wybrałem czujniki wilgotności tylko do tego celu tj. SHT31. Barometr widziałem, że polecany jest BMP180 więc na nim zostałem. Z programowaniem nie było problemu ze względu na biblioteki. Czujniki pyłu były małym wyzwaniem. Brak bibliotek. I śmigają na UART Trzeba operować na przykładowych kodach i rozumieć jak lecą bity. Ponadto trzeb zwracać uwagę na to że różne modele mogą mieć różny formę ramki danych przesyłanych. Przetestowałem 3 czujniki pyłu PMS5003 PMS5003 z detekcją formaldehydu Gravity Każdy z nich miał inaczej ramkę ukształtowaną. Ponadto czujniki zasilane są napięciem 5V a linia danych 3,3V Do tego należy dokupić konwerter poziomów logicznych by zadziałało to sprawnie. Do tego zestawu dokupiłem stacje meteo z wiatromierzem. Następnie chciałem aby stacja mogła być na zewnątrz i komunikować się z odbiornikiem w środku przez nRF24L01+. Warto brać moduł z zewnętrzną anteną oraz adapterem poprawia działanie modułu. Mając już na płytce w miarę temat ogarnięty chciałem najpierw testowo zrobić mobilny czujnik pyłu aby zrobić pierwsze przymiarki do lutowania i montażu. Lutowałem na płytkach prototypowych z cienkimi kablami. Nie był to dobry pomysł ale na daną chwilę dało się. Zamiast przylutowywać moduły na stałe lutowałem sloty do nich. Wolałem trochę poświęcić jakość wykonania na rzecz sytuacji w której mógłbym się pomylić. Nie mam rozlutotwnicy a standardowa lutownica i odsysacz słabo mi się sprawdzały. Specyfikacja mobilnego czujnika pyłu (główne moduły) Arduino Pro Mini 328 - 5V/16MHz SHT 15 (wilgotność i temperatura) PMS5003 (czujnik pyłu) Konwerter USB-UART FTDI FT232RL - gniazdo miniUSB (programator ew zasilanie poza bateryjne) Wyświetlacz LCD 4x20 znaków zielony Efekt był zadowalający wiec uznałem, że warto będzie spróbować wysyłać dane na stronę www. Do tego zadania zaprzęgłem malinkę z modułem nRF24L01+. Idea była taka aby: ->pomiar stacji ->wysłanie danych drogą radiową ->odebranie przez Ras Pi ->wysłanie danych na zewnętrzny bazę danych MySQL ->pobranie danych z bazy i wyświetlenie jej na stronie bazującej na wordpresie Główny problem był z liczbami zmiennoprzecinkowymi. Gdyż malinka odbiera surowe bity i nie chce ich prze konwertować na liczbę zmiennoprzecinkową. W każdym bądź razie wszelkie próby konwersji i operacji na bitach skończyły się komunikatem ze Python nie obsługuje przesunięć bitowych dla liczb zmiennoprzecinkowych. Do zastosowań domowych wystarczy mi pomiar do drugiego miejsca po przecinku (temperatura) więc po prostu każdą zmienna która miała część ułamkową mnożę na Arduino razy 100 i jak odbiorę na malince dzielę przez 100. O ile odbiór między arduino to linijka kodu to tu przy odbiorze suchej transmisji (już przy użyciu biblioteki ...... ) trzeba było bity ręcznie składać bo Arduino wysyła jedną zmienną w dwóch bajtach trzeba było używać operatorów bitowych by te bajty złączyć w jeden. Przed montażem należało wyznaczyć miejsce dla stacji. Z tego względu do stacji mobilnej dorzuciłem adapter NRF na który mogłem po prostu zamiennie testować wersje z zewnętrzną i wewnętrzną anteną. Syngał nadawał do malinki kolejne cyfry a obok miałem telefon z teamviwerem na którym patrzałem się co na konsoli wyświetliło. Jeśli był cykl 1 2 3 .... 11 12, tzn., że w miejscu w którym stałem jak nadawano cyfry 4 5 6 7 8 9 10 sygnał nie doszedł i nie należało go brać pod uwagę do montażu docelowej stacji meteo. Wiatromierz montowałem na chwycie antenowym. Średnica rur od stacji była mniejsza więc wkładając ją uzupełniłem całość pianką montażową by nie latało. Rezultat był taki, że moduł z wbudowaną anteną za oknem 3m tracił zasięg drugi miał sygnał spokojnie do ok 10m (nawet przez ściany). Po teście wysłania danych i odebrania jednej danej na wordpresie przytępiono do montażu stacji. Jej finalna konfiguracja to Arduino Pro Mini 328 - 5V/16MHz Konwerter USB-UART FTDI FT232RL - gniazdo miniUSB (programator i zasilanie) nRF24L01+ Stacja meteo dfrobot PMS5003 (czujnik pyłu) Gravity (czujnik pyłu) MCP9808 (temperatura) SHT 31 (wigotność) BMP180 (ciśnienie) Dorzuciłem dwa czujniki pyły by porównać ich działanie. Jako końcowy element została mi kwestia wyświetlenia danych na stronie www. Dzięki wtyczce do pisania skryptów php w wordpresie udało napisać moduł pobierania danych z bazy i jego wyświetlania. Wykresy były większym problemem. Darmowe wtyczki do wordpressa nie chcą pobierać danych z sql i są ciężko edytowalne preferują prace na .csv i najlepiej jakby je ręcznie przeładowywać. Finalnie użyłem do tego celu Google Charts (nota bene na których wiele darmowych wtyczek do wordpresa bazuje). Z racji, że nie jestem web-developerem było to moje pierwsze spotkanie z php oraz javascriptem na którym Google Charsty operują. Zmuszenie tego pracy odbyło się metodą prób i błędów ale efekt jest zadowalający. Mam wykresy z 24h, tygodnia i miesiąca. Problemy Kodowanie int w arduino i malince Ze względu za na sposób kodowania liczny int w pythonie ujemne wartości temperatury np -5C na arduino pokazywały na malince wartość 65531 C. Trzeba było dopisać fragment który usuwał ten błąd. Komunikacja L01+ Moduły te są bardzo wrażliwe na zmiany napięcia. Można do nich dokupić adapter do wpięcia który głównie ma stabilizator napięcia. Nawet nie zawsze on pomaga jeśli do niego pójdzie nie wystarczające napięcie. Widać to np. jak się rusza kable to migocze LED lub jest "ciut" jaśniejszy. Wtedy anteny nie mogą się dogadać. Potrafi się zdarzyć takie kuriozum, że w takiej sytuacji antena straci własny adres. Jeśli anteny nie są w stanie się dogadać należy bezwzględnie sprawdzić pewność zasilania. Błąd wysłania danych SQL Czasami kod w malince się zawiesi w oczekiwaniu na wysłanie danych do serwera SQL. Trudno mi powiedzieć jak dobrze temu zaradzić. Występuję to przy dłuższej pracy (tydzień, miesiąc) aczkolwiek jedyne co mi przychodzi do głowy to ustawić na Raspianie auto-restart systemu co 24h. Wycinanie dziur w plastikowej obudowie Próbowałem wycinać szlifierką modelarską ale zawsze plastik się topił. Po szperaniu w necie rozwiązaniem są albo nożyki do plastiku albo wycinarka włosowa do plastiku ale nie udało mi się tego przetestować. Niestety wycięcia wyglądają mało estetycznie ale trudno. Google Charts Przesyłanie danych z PHP do JavaScript tak aby Google bylo problemem. Wykresy nie łykną dowolnego formatu danych i nie wyświetlą błędy jeśli uznają, że format im nie pasuje. Co mógłbym zrobić inaczej? Gdybym miał robić update to zamiast komunikacji radiowej do malinki wydaje mi się bardziej rozsądne pójście w wyposażenie arduino w WIFI i wysyłanie bezpośrednio na serwer. Nie uczyniłem tak ze względu na to pisanie kodu komunikacji Arduino WIFI nie jest to pare linijek. Plus też kod do wysyłania do SQL który znalazłem też pewnie by zawierał trochę kodu. Więcej dłubania ale efekt powinien być bardziej zadowalający. Plany na przyszłość Jedyne co chce na dniach zrobić to poduczyć się Eagla i przenieść całość na płytkę drukowaną i zamówić ją np. JLCPCB. Wtedy wypnę moduły z tamtych płytek i przypnę je do zamówionej. Reasumując Stacja działa już ok 6 miesięcy. Bez problemowo. Jak widać na wykresie z ostatniego miesiąca (tj. 26.12.2018 - 25.12.2019), że normy dla smogu w mojej wsi były w paru dniach przekroczone (a mieszkam w centrum pomorskiego bez kopalni, ciężkiego przemysłu wokół). Gdyby dobrze opisać każdy etap pracy można by z tego zrobić osobny kurs Poniżej kody źródłowe Arduino Ras PI Wordpress pobieranie suchych danych Wordpress pobieranie danych i osadzenie ich na Google Charts //Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Proszę tylko podać autora kodu #include <math.h> #include <Wire.h> #include <Arduino.h> #include <Adafruit_BMP085.h> #include <SoftwareSerial.h> #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include "Adafruit_SHT31.h" #include "Adafruit_MCP9808.h"7 #define dataSize 16 #define PMS5003BufferSize 40 #define dustGravityBufferSize 32 Adafruit_BMP085 bmp; Adafruit_MCP9808 tempsensor = Adafruit_MCP9808(); Adafruit_SHT31 sht31 = Adafruit_SHT31(); // software serial #2: RX = digital pin 8, TX = digital pin 9 SoftwareSerial Serial1(4, 5); SoftwareSerial Serial3(8, 9); SoftwareSerial Serial2(3, 2); RF24 radio(10, 14); // CE, CSN const byte address[6] = "00001"; char col; unsigned int dustSensor25 = 0,dustSensor10 = 0; unsigned int PMS = 0,PM10 = 0, formalin = 0,CR1 = 0,CR2 = 0; float PMSTemp = 0, PMSHigro = 0; bool readErr = false, readErr25 = false; int dustSensorReadError = 0; unsigned int higherBit = 0, LowerBit = 0; unsigned char buffer_RTT[40]={}; //Serial buffer; Received Data char meteoDatabuffer[35]; int measurments [dataSize]; void readPMS(); void readPM25(); void readDustSensorUARTData(SoftwareSerial S, unsigned char *bufferData, int bufferSize); unsigned int mergeBitsToInt(unsigned char *bufferData, int startBit, int stopBit); void clearBuffer(unsigned char *bufferData); void calculateControlSum(unsigned int &CR1Var, unsigned int &CR2Var, unsigned char *bufferData, int bufferSize); void encageDustSensorReadError(); void printUARTRecievedData(); void readMeteoStation(); int transCharToInt(char *_buffer,int _start,int _stop); //char to int) void sendData(); void printSendedData(); void printDataBySensor(); void setup() { Serial.begin(115000); Serial.println("start"); Serial1.begin(9600); Serial1.setTimeout(1500); delay(2000); Serial2.begin(9600); Serial2.setTimeout(1500); delay(1000); Serial3.begin(9600); Serial3.setTimeout(1500); radio.begin(); radio.setPALevel(RF24_PA_MAX); radio.setDataRate(RF24_1MBPS); radio.setChannel(0x76); radio.openWritingPipe(0xF0F0F0F0E1LL); radio.enableDynamicPayloads(); radio.stopListening(); if (!bmp.begin()) { while (1) {} } if (!tempsensor.begin()) { while (1); } if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr while (1) delay(1); } Serial.println("Zakończony Init"); delay(2000); } void loop() { readPMS(); readPM25(); readMeteoStation(); printDataBySensor(); if(readErr == false && readErr25 == false) { //Serial.println("Wysyłam dane"); sendData(); //Serial.print("Wysłano dane: "); } delay(1000); } void readPMS() { Serial.println("Czujnik pm5003"); readDustSensorUARTData(Serial1, buffer_RTT, PMS5003BufferSize); calculateControlSum(CR1, CR2, buffer_RTT, PMS5003BufferSize); if(CR1 == CR2 && CR1 != 0) //Check { PMS = mergeBitsToInt(buffer_RTT, 12, 13); PM10 = mergeBitsToInt(buffer_RTT, 14, 15); formalin = mergeBitsToInt(buffer_RTT, 28, 29); PMSTemp = mergeBitsToInt(buffer_RTT, 30, 31) / 10; PMSHigro = mergeBitsToInt(buffer_RTT, 32, 33) / 10; readErr = false; } else { PMS = 4321; PM10 = 4321; formalin = 4321; encageDustSensorReadError(); } clearBuffer(buffer_RTT); } void readPM25() { Serial.println("Czujnik p, 25"); readDustSensorUARTData(Serial3, buffer_RTT, dustGravityBufferSize); calculateControlSum(CR1, CR2, buffer_RTT, dustGravityBufferSize); if(CR1 == CR2 && CR1 != 0) //Check { dustSensor25 = mergeBitsToInt(buffer_RTT, 6, 7); dustSensor10 = mergeBitsToInt(buffer_RTT, 8, 9); readErr25 = false; } else { dustSensor25 = 4321; dustSensor10 = 4321; encageDustSensorReadError(); } clearBuffer(buffer_RTT); } void readDustSensorUARTData(SoftwareSerial S, unsigned char *bufferData, int bufferSize) { S.listen(); while(!S.available()); while(S.available()>0) //Data check: weather there is any Data in Serial1 { col =S.read(); delay(2); if (col == 0x42) { bufferData[0]=(char)col; col =S.read(); delay(2); if (col == 0x4d) { bufferData[1]=(char)col; for(int i = 2; i < bufferSize; i++) { col =S.read(); bufferData[i]=(char)col; delay(2); } break; } } S.flush(); } } unsigned int mergeBitsToInt(unsigned char *bufferData, int startBit, int stopBit) { higherBit = buffer_RTT[startBit]; //Read PM2.5 High 8-bit LowerBit = buffer_RTT[stopBit]; //Read PM2.5 Low 8-bit return (higherBit << 8) + LowerBit; } void clearBuffer(unsigned char *bufferData) { for(int i = 0; i < 40; i++) { bufferData[i] = 0; } delay(100); } void calculateControlSum(unsigned int &CR1Var, unsigned int &CR2Var, unsigned char *bufferData, int bufferSize) { CR1Var = 0; CR2Var = 0; CR1Var =(buffer_RTT[bufferSize - 2]<<8) + buffer_RTT[bufferSize - 1]; for(int i = 0; i < bufferSize - 2; i++) { CR2Var += bufferData[i]; } } void encageDustSensorReadError() { dustSensorReadError = dustSensorReadError + 1; readErr = true; readErr25 = true; Serial.print("Błąd odczytu: "); Serial.println(dustSensorReadError); //printUARTRecievedData(); } void readMeteoStation() { Serial.println("Stacja meteo nasłuchuje"); Serial2.listen(); while(!Serial2.available()); while(Serial2.available()>0) //Data check: weather there is any Data in Serial1 { Serial.println("Start meteo"); for (int index = 0;index < 35;index ++) { if(Serial2.available()) { meteoDatabuffer[index] = Serial2.read(); if (meteoDatabuffer[0] != 'c') { //Serial.println("Transmisja w toku meteo"); index = -1; } } else { index --; } } } Serial.println("Koniec"); } int transCharToInt(char *_buffer,int _start,int _stop) { //char to int) int result = 0; int num = _stop - _start + 1; int tempArr[num]; for (int indx = _start; indx <= _stop; indx++) { tempArr[indx - _start] = _buffer[indx] - '0'; result = 10 * result + tempArr[indx - _start]; } return result; } void sendData(){ for(int z = 0; z < dataSize; z++) { measurments[z] = -1000; } //Meteo station measurments[0] = (int)(transCharToInt(meteoDatabuffer,1,3)); //wind directoin measurments[1] = (int)(transCharToInt(meteoDatabuffer,28,32) / 10.00); //pressure //measurments[2] = (int)(((transCharToInt(meteoDatabuffer,13,15) - 32.00) * 5.00 / 9.00) * 100); //temp *C //measurments[3] = (int)((transCharToInt(meteoDatabuffer,25,26)) * 100); //higro %RH measurments[2] = (int)((transCharToInt(meteoDatabuffer,5,7) / 0.44704) * 100); //avg wind speed 1 min (m/s) measurments[3] = (int)((transCharToInt(meteoDatabuffer,9,11) / 0.44704) * 100); //max wind speed 5min (m/s) measurments[4] = (int)((transCharToInt(meteoDatabuffer, 17, 19) * 25.40 * 0.01) * 100); // rain 1 hour (mm) measurments[5] = (int)((transCharToInt(meteoDatabuffer, 21, 23) * 25.40 * 0.01) * 100); // rain 24 hour (mm) //MCP9008 measurments[6] = (int)(tempsensor.readTempC() * 100); //SHT31 measurments[7] = (int)(sht31.readHumidity() * 100); measurments[8] = (int) (sht31.readTemperature()* 100); //PMS5003 //measurments[11] = PMSTemp * 100; //measurments[12] = PMSHigro * 100; measurments[9] = PMS; measurments[10] = PM10; measurments[11] = formalin; //PM2,5 Gravity measurments[12] = dustSensor25; measurments[13] = dustSensor10; //BMP180 measurments[14] = bmp.readPressure() / 100; //measurments[19] = (int) (bmp.readTemperature() * 100); measurments[15] = 666; int testMe = 0; for(int k = 0; k < 15; k++) { testMe += measurments[k]; } Serial.print("PRZYKLADOWA CHECK SUMA: "); Serial.println(testMe); radio.write(&measurments, sizeof(measurments)); printSendedData(); } void printSendedData() { Serial.println("Wysłano następujące dane:"); for (int i = 0; i < dataSize; i++) { Serial.print(measurments[i]); Serial.print(" "); } Serial.println(); } void printUARTRecievedData() { byte b; for(int i=0;i<32;i++) { b = (byte)buffer_RTT[i]; //buffer_RTT[i] = 0; Serial.print(b, HEX); Serial.print(" "); } Serial.print("CR1: "); Serial.print(CR1); Serial.print(" = "); Serial.println(CR2); } void printDataBySensor() { Serial.println(); Serial.println("MCP9808: "); Serial.print("Temperatura: "); float c = tempsensor.readTempC(); Serial.print(c); Serial.println("*C"); Serial.println(); Serial.println("SHT31: "); Serial.print("Wilgotność: "); Serial.print(sht31.readHumidity()); Serial.println("%RH"); Serial.print("Temperatura: "); Serial.print(sht31.readTemperature()); Serial.println("*C"); Serial.println(); Serial.println("BMP180: "); Serial.print("Temperatura: "); float bmpTemp = bmp.readTemperature(); Serial.print(bmpTemp); Serial.println("*C"); Serial.print("Ciśnienie: "); Serial.print(bmp.readPressure() / 100); Serial.println("hPa"); Serial.print("Teoretyczna wysokość: "); Serial.print(bmp.readAltitude(101100)); Serial.println("m.n.p.m"); Serial.println(); Serial.println("PMS5003:"); Serial.print("PM 2,5: "); Serial.print(PMS); Serial.println(" /25 ug/m3 "); Serial.print("PM 10 : "); Serial.print(PM10); Serial.println(" /50 ug/m3 "); Serial.print("Formaldehyd : "); Serial.print(formalin); Serial.println(" ug/m3 "); Serial.print("Temperatura: "); Serial.print(PMSTemp); Serial.println("*C"); Serial.print("Wilgotność: "); Serial.print(PMSHigro); Serial.println("%RH"); Serial.println(); Serial.println("PM 2,5 GRAVITY:"); Serial.print("PM 2,5: "); Serial.print(dustSensor25); Serial.println(" /25 ug/m3 "); Serial.print("PM 10 : "); Serial.print(dustSensor10); Serial.println(" /50 ug/m3 "); Serial.println(); Serial.println("STACJA METEO: "); Serial.print("Temperatura: "); c = (transCharToInt(meteoDatabuffer,13,15) - 32.00) * 5.00 / 9.00; Serial.print(c); Serial.println("*C"); Serial.print("Wilgotnosc: "); float metHigro = transCharToInt(meteoDatabuffer,25,26); Serial.print(metHigro); Serial.println("%RH"); Serial.print("Cisnienie: "); float pp = transCharToInt(meteoDatabuffer,28,32) / 10.00; Serial.print(pp); Serial.println("hPa"); Serial.print("Predkośc wiatru: "); float w = transCharToInt(meteoDatabuffer,5,7) / 0.44704; Serial.print(w); Serial.println("m/s"); Serial.print(" "); w = w * 3.6; Serial.print(w); Serial.println("km/h"); Serial.print("Max Predkośc wiatru: "); float m = transCharToInt(meteoDatabuffer,9,11) / 0.44704; Serial.print(m); Serial.println("m/s (ostatnie 5 minut)"); Serial.print(" "); m = m * 3.6; Serial.print(m); Serial.println("km/h (ostatnie 5 minut)"); Serial.print("Kierunek wiatru: "); Serial.print(transCharToInt(meteoDatabuffer,1,3)); Serial.println("C"); Serial.print("Opad (1h): "); float rain1 = transCharToInt(meteoDatabuffer, 17, 19) * 25.40 * 0.01; Serial.print(rain1); Serial.println("mm"); Serial.print("Opad (24h): "); float rain24 = transCharToInt(meteoDatabuffer, 21, 23) * 25.40 * 0.01; Serial.print(rain24); Serial.println("mm"); Serial.println(); } #Autor Bartosz Jakusz. Można replikować nawet w celach komercyjnych. Tylko umieścić autora kodu. import RPi.GPIO as GPIO from lib_nrf24 import NRF24 import time import spidev import struct import os import mysql.connector from mysql.connector import errorcode from datetime import date, datetime, timedelta GPIO.setmode(GPIO.BCM) pipes = [[0xE8, 0xE8, 0xF0, 0xF0, 0xE1], [0xF0, 0xF0, 0xF0, 0xF0, 0xE1]] radio = NRF24(GPIO, spidev.SpiDev()) radio.begin(0, 17) radio.setPayloadSize(32) radio.setChannel(0x76) radio.setDataRate(NRF24.BR_1MBPS) radio.setPALevel(NRF24.PA_MAX) radio.setAutoAck(True) radio.enableDynamicPayloads() radio.enableAckPayload() i = 0 j = 0 sucRate = 0 errRate = 0 totalRec = 0 try: while True: radio.openReadingPipe(1, pipes[1]) #radio.printDetails() radio.startListening() print(" ") print(datetime.now()) radio.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) radio.print_address_register("TX_ADDR", NRF24.TX_ADDR) j = 0 while not radio.available(0): j = j + 1 receivedMessage = [] radio.read(receivedMessage, radio.getDynamicPayloadSize()) radio.stopListening() print("Received: {}".format(receivedMessage)) string = "" floatBytes = [] indx = 0 while indx < 4: floatBytes.append(0) indx = indx + 1 measurments = [] indx = 0 mIndx = 0 tmpStr= "" tmpIndx = 0 crc = 0 if not receivedMessage: print("pusto wywalam sie") else: for n in receivedMessage: #print(tmpIndx) tmpIndx = tmpIndx + 1 floatBytes.insert(indx, n) if(indx >= 1): b1 = floatBytes[0] b2 = floatBytes[1] host = 0 host = b2 host = host << 8 host = host | b1 if(mIndx == 6): print("trt {}".format(host)) if(host > 65536 / 2): host = (65536 - host) * (-1) print("trti {}".format(host)) tmpVar = host / 100 print("trtf {}".format(tmpVar)) elif(mIndx >= 2 and mIndx < 5 or mIndx >= 7 and mIndx <= 8): tmpVar = host / 100 else: tmpVar = host indx = 0 measurments.append(tmpVar) mIndx = mIndx + 1 else: indx = indx + 1 totalRec = totalRec + 1 print(" ") if(host == 666): sucRate = sucRate + 1 print("Odebrano z sukcesem {}/{} transmisji".format(sucRate, totalRec)) try: print("Zaczynamy łacznie z baza") cnx = mysql.connector.connect(host='00.00.00.00',database='db') cursor = cnx.cursor() print("Połączono z baza") #zapytania SQL add_probeTime = ("INSERT INTO MeasrumentDateTime" "(time, date)" "VALUES (%s, %s)") add_MCP8006 = ("INSERT INTO MCP8006 " "(temperature, MeasrumentDateTime_ID) " "VALUES (%(temperature)s, %(timeID)s)") add_SHT31 = ("INSERT INTO SHT31 " "(humidity, temperature, MeasrumentDateTime_ID) " "VALUES (%(humidity)s ,%(temperature)s, %(timeID)s)") add_BMP180 = ("INSERT INTO BMP180" "(pressure, MeasrumentDateTime_ID) " "VALUES (%(pressure)s, %(timeID)s)") add_PMS5003 = ("INSERT INTO PMS5003" "(pm25, pm10, formaldehyd, MeasrumentDateTime_ID) " "VALUES (%(pm25)s, %(pm10)s, %(formaldehyd)s,%(timeID)s)") add_PMGravity = ("INSERT INTO PM25" "(PM25, PM10, MeasrumentDateTime_ID) " "VALUES (%(pm25)s, %(pm10)s, %(timeID)s)") add_meteoSation = ("INSERT INTO MeteoStation" "(windDirection, avgWindSpeedPerMinute, avgWindSpeedPerFiveMinutes, rainfallOneHour, rainfal24Hours, pressure, MeasrumentDateTime_ID) " "VALUES (%(windDir)s, %(avgWind)s, %(maxWind)s, %(rain1h)s, %(rain24h)s, %(pressure)s, %(timeID)s)") #Dodaj obecna godzine currentTimeAndDate = datetime.now() formatted_time = currentTimeAndDate.strftime('%H:%M:%S') currentDate = datetime.now().date() toSendSampleDate = (formatted_time, currentDate) cursor.execute(add_probeTime, toSendSampleDate) sampleTimeID = cursor.lastrowid #Wyslij do bazy MySql dane czujnik temp MCP8006Data = { 'timeID' : sampleTimeID, 'temperature' : measurments[6], } cursor.execute(add_MCP8006, MCP8006Data) #Wyslij do bazy MySql dane higrometr SHT 31 SHT31Data = { 'timeID' : sampleTimeID, 'humidity' : measurments[7], 'temperature' : measurments[8], } cursor.execute(add_SHT31, SHT31Data) #Wyslij do bazy MySql dane barometr BMP180 BMP180Data = { 'timeID' : sampleTimeID, 'pressure' : measurments[14], } cursor.execute(add_BMP180, BMP180Data) #Wyslij do bazy MySql dane czujnik pylu PMS5003 PMS5003Data = { 'timeID' : sampleTimeID, 'pm25' : measurments[9], 'pm10' : measurments[10], 'formaldehyd' : measurments[11], } cursor.execute(add_PMS5003, PMS5003Data) #Wyslij do bazy MySql dane czujnik pylu PM 2,5 Gravity PMGravityData = { 'timeID' : sampleTimeID, 'pm25' : measurments[12], 'pm10' : measurments[13], } cursor.execute(add_PMGravity, PMGravityData) #Wyslij do bazy MySql dane stacja meteo metStationData = { 'timeID' : sampleTimeID, 'windDir' : measurments[0], 'avgWind' : measurments[2], 'maxWind' : measurments[3], 'rain1h' : measurments[4], 'rain24h' : measurments[5], 'pressure' : measurments[1], } cursor.execute(add_meteoSation, metStationData) print("Wysylanie danych na serwer") cnx.commit() cursor.close() print("Wyslano do bazy pomyslnie dane") except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: print("Something is wrong with your user name or password") elif err.errno == errorcode.ER_BAD_DB_ERROR: print("Database does not exist") else: print(err) else: cnx.close() time.sleep(14) else: print("BLAD TRANSMISJI: nie zgadza sie suma kontrolna") #errRate = errRate + 1 #print("Żle odebrano {}/{} transmisji".format(errRate, totalRec)) print(" ") print("------------------------------------------") #radio.closeReadingPipe(pipes[1]) #radio.stopListening() time.sleep(1) except KeyboardInterrupt: print(i) except: # this catches ALL other exceptions including errors. # You won't get any error messages for debugging # so only use it once your code is working print ("Other error or exception occurred!") finally: GPIO.cleanup() # this ensures a clean exit echo"Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Wsakazać tylko autora kodu. "; $mydb = new wpdb('usr_db','db','localhost'); $currentTime = $mydb->get_results("SELECT time, date FROM MeasrumentDateTime ORDER BY ID DESC LIMIT 1"); $tempData = $mydb->get_results("SELECT temperature FROM MCP8006, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $higroData = $mydb->get_results("SELECT humidity FROM SHT31, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $pressureData = $mydb->get_results("SELECT pressure FROM BMP180, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $pms5003Data = $mydb->get_results("SELECT pm25, pm10, formaldehyd FROM PMS5003, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $gravityData = $mydb->get_results("SELECT PM25, PM10 FROM PM25, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $metStationData = $mydb->get_results("SELECT windDirection, avgWindSpeedPerMinute, avgWindSpeedPerFiveMinutes, rainfallOneHour, rainfal24Hours FROM MeteoStation, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $avgkmPerHour = $metStationData[0]->avgWindSpeedPerMinute * 3.6; $maxkmPerHour = $metStationData[0]->avgWindSpeedPerFiveMinutes * 3.6; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Ostatni pomiar z: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>".$currentTime[0]->time." </th>"; echo"<th>".$currentTime[0]->date." </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; $dir = $metStationData[0]->windDirection; $dirName = ""; if ($dir < 45) { $dirName = "Północny"; } elseif ($dir >= 45 or $dir < 90 ) { $dirName = "Północno-Wschodni"; } elseif ($dir >= 90 or $dir < 135 ) { $dirName = "Wschodni"; } elseif ($dir >= 135 or $dir < 180 ) { $dirName = "Południowo-Wschodni"; } elseif ($dir >= 180 or $dir < 225 ) { $dirName = "Południowy"; } elseif ($dir >= 225 or $dir < 270 ) { $dirName = "Południowo-Zachodni"; } elseif ($dir >= 270 or $dir < 315 ) { $dirName = "Zachodni"; } else { $dirName = "Północno-Zachodni"; } echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Temperatura: </th>"; echo"<th>".$tempData[0]->temperature."*C </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Wilgotność: </th>"; echo"<th>".$higroData[0]->humidity."%RH </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ciśnienie: </th>"; echo"<th>".$pressureData[0]->pressure."hPa </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Czystość powietrza: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PM 2,5 - norma 25ug/m3: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->pm25."ug/m3</th>"; echo"</tr>"; echo"<tr>"; echo"<th>Gravity: </th>"; echo"<th>".$gravityData[0]->PM25."ug/m3</th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>PM 10 - norma 50ug/m3</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->pm10."ug/m3 </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Gravity: </th>"; echo"<th>".$gravityData[0]->PM10."ug/m3 </th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Formaldehyd</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->formaldehyd."ug/m3 </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Stacja Meteo: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Kierunek Wiatru: </th>"; echo"<th>".$dirName."</th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Średnia prędkość wiatru (ostatnia minuta): </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$metStationData[0]->avgWindSpeedPerMinute."m/s</th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$avgkmPerHour."km/h</th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Max prędkość wiatru (ostatnie 5 min)</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$metStationData[0]->avgWindSpeedPerFiveMinutes."m/s</th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$maxkmPerHour."km/h</th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Opad atmosferyczny</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ostatnia godzina: </th>"; echo"<th>".$metStationData[0]->rainfallOneHour."mm</th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ostatnia doba: </th>"; echo"<th>".$metStationData[0]->rainfal24Hours."mm </th>"; echo"</tr>"; echo"</table>"; echo"Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Wsakazać tylko autora kodu. "; $mydb = new wpdb('usr_db','db','localhost'); $pm25DataPMS5003 = $mydb->get_results("SELECT time, date, round(avg(pm25), 0) as pm25PMSMonth FROM PMS5003, MeasrumentDateTime WHERE TIMESTAMP(date, time) > NOW() - INTERVAL 1 MONTH and MeasrumentDateTime_ID = MeasrumentDateTime.ID group by DAY(TIMESTAMP(date, time)) ORDER BY MeasrumentDateTime.ID"); $pm25DataGravity = $mydb->get_results("SELECT time, date, round(avg(PM25.PM25),0) as pm25GravMonth FROM PM25, MeasrumentDateTime WHERE TIMESTAMP(date, time) > NOW() - INTERVAL 1 MONTH and MeasrumentDateTime_ID = MeasrumentDateTime.ID group by DAY(TIMESTAMP(date, time)) ORDER BY MeasrumentDateTime.ID"); $tmpPM25 = []; $i = 0; $someRandData = 25; foreach ($pm25DataGravity as $obj) : array_push($tmpPM25, array(substr((string)$obj->date,5)." ".substr((string)$obj->time,0,-9), (float)$obj->pm25GravMonth, (float)$pm25DataPMS5003[$i]->pm25PMSMonth, (float)$someRandData )); $i++; endforeach; echo"<div id='pm25ChartMonth'></div>"; ?> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> var pm25 = <?php echo json_encode($tmpPM25); ?>; google.charts.load('current', {packages: ['corechart', 'line']}); google.charts.setOnLoadCallback(drawBasic); function drawBasic() { var data = new google.visualization.DataTable(); data.addColumn('string', 'Last Hour'); data.addColumn('number', 'Gravity'); data.addColumn('number', 'PMS5003'); data.addColumn('number', 'Norma'); data.addRows(pm25); var options = { 'title':'Zaniczyszczenie PM 2,5 ostatni miesiąc', 'curveType': 'function', hAxis: { title: 'Godzina' }, vAxis: { title: 'um/m3' }, height: 500 }; var chart = new google.visualization.LineChart(document.getElementById('pm25ChartMonth')); chart.draw(data, options); } </script>
  41. 5 punktów
    Metod samodzielnego wykonywania płytek pcb jest wiele. Termotransfer - potrzebna dobra drukarka laserowa, fototransfer - też dobra drukarka, płytki światłoczułe lub własnoręczne pokrywanie takim lakierem, suszenie, naświetlanie itp. Testowałem naświetlanie i albo prześwietliło albo odwrotnie. Można frezować. Ale można też rysować. Oczywiście nie ręcznie, jak to dawniej bywało. Jako, że z cnc i budową urządzeń mam trochę do czynienia, postanowiłem zbudować sobie taką małą maszynkę. Większość materiałów miałem - aluminiowe płytki, kątowniki, silniki krokowe i szlifowane prowadnice ze starych drukarek, a także dostęp do własnej małej tokarko - frezarki cnc. Całość miała być "po taniości" i maksymalne wykorzystanie "przydasiów" . Początkowo użyłem kilku gotowych podzespołów, jak stolik krzyżowy (proxxon) i mechanizm napędu ze starego CD/DVD jako oś Z. Użyte silniczki mają 24 kroki/obrót, zasilane z 12 V. Ich sterowniki to DRV8825 . Koła zębate pod paski też wyrób własny - frezowanie ( aluminium i poliamid ), paski trzeba było nabyć. Całością steruje Arduino Uno i GRLB1.1. Problem pojawił się w momencie zainstalowania krańcówek. Jedna oś działała, reszta martwa. CNC Shield był projektowany pod GRLB-8, a nowsze wersje tego oprogramowania mają pozmieniane niektóre wyprowadzenia. Ale jest to opisane na stronie GRLB. Nic nie pomagało - wgrywanie softu, czyszczenie procka i jego EEPROM'u. Oczywiście kontrola przewodów i samych krańcówek. Do "przyzwoitego" połączenia przewodów z układem sterującym przydają się złącza BLS. Dopiero nowa Atmega328 - i teraz wszystko gra. Nie spodziewałem się wadliwego układu. W ferworze walki o działające krańcówki została wykonana optoizolacja na układzie LTV847 . Płytkę do tego wyrysowała maszyna już sama dla siebie. Ponieważ wszystko działało, można by tak zostawić. Jednak pole robocze było małe - 45 x 120 mm. Trochę pracy trzeba było włożyć - cięcie, frezowanie i toczenie elementów. Ale warto było, bo powstałą dość solidna konstrukcja - już tak przyszłościowo.Dorobienie śruby i nakrętki (żeliwo) z kasowaniem luzu, mocowania silnika i łożyskowania śruby dopełnia reszty. Oczywiście dokładne ustawienie na czujnik zegarowy i dokładnym kątomierzem równoległości oraz kątów. W efekcie obszar roboczy zwiększył się do 180 x 120 mm. Większych płytek chyba robić nie będę. Mocowanie pisaka umożliwia ruch góra/dół - taki luz bezpieczeństwa - z uwagi na czasem spotykane niezbyt "płaskie" laminaty, natomiast luz poprzeczny jest minimalny i wg. pomiarów nie przekracza 0,03mm. Można więc mówić o precyzji . Oczywiście kusi przeróbka. W pierwszym rzędzie zmiana silników na taki krokowiec. Obecnie używane mają cienką oś - 2 mm, która wygina się od naciągniętych pasków. Ich łożyska cierne też się od tego mocno wyrabiają jednostronnie. Drugi powód - mocniejszy silnik umożliwi większą szybkość pracy. Obecnie to 300 mm/min. Nowa oś Z ( mocniejsza ) i zwiększenie jej zakresu pracy oraz obniżenie stołu roboczego. Zamiast obecnego mazaka - bo tylko tyle ten mały silniczek dźwignie - można by założyć jakiś moduł lasera albo i głowicę drukującą ( 3D ). Albo i mały silnik jako wiertarkę. W chwili obecnej pisak daje ścieżkę szerokości 0,4 mm lub wielokrotność. Próby z cieńszą ścieżką nie wypadły na razie pomyślnie - za słabe krycie i potrafią zostać przetrawione - używam chlorku żelaza.
  42. 5 punktów
    Tym razem będzie nietechnicznie — to co tu opisuję, to wyłącznie moja własna prywatna opinia. Jeśli ktoś się nie zgadza, to zapraszam do dyskusji, jednak rezerwuję sobie prawo pozostania przy swoich wnioskach. Będzie o androidach, ale nie systemie operacyjnym dla telefonów, tylko o człekokształtnych robotach. Otóż uważam, że pomimo ich częstego pojawiania się w wiadomościach i na pierwszych stronach gazet, roboty tego typu są generalnie bezużyteczne poza bardzo wąską dziedziną zastosowań, jaką jest przemysł rozrywkowy. Jest tak z bardzo prostego powodu: humanoidalny kształt człowieka nie ma, z technicznego punktu widzenia, żadnych zalet, natomiast niesie ze sobą wiele nietrywialnych wyzwań. Zatem jeśli główną rolą naszego robota jest wyglądanie jak człowiek — po to, żeby stać na wystawie sklepowej i prezentować ubrania, iść w pochodzie, występować na scenie lub w filmie, bawić dzieci jako zabawka, czy zapewniać firmie dobrą prasę — to jak najbardziej ma sens nadanie mu właśnie takiego kształtu. W innych przypadkach nie ma to najmniejszego sensu, bo okazuje się, że wszelkie zalety takiego rozwiązania są tylko pozorne: 1. Zastępowanie ludzi w środowisku przystosowanym dla ludzi: używanie ludzkich maszyn i narzędzi, poruszanie się w mieszkaniach i biurach. Wydaje się, że to niezła racjonalizacja — jeśli dany robot ma zastąpić człowieka, to musi mieć możliwość sięgnięcia do wszystkich rzeczy, do których człowiek by sięgnął, wejścia w miejsce, w które człowiek może wejść i ogólnie robienia tego, co człowiek mógłby zrobić. Ale okazuje się, że można to osiągnąć bez kopiowania ludzkiego ciała. Co więcej, taki nie-człekokształtny robot będzie miał znaczącą przewagę, bo będzie mieć większą zwinność, lepszy zasięg, większą siłę i szybkość, nie mówiąc już o łatwiejszym sterowaniu. Roboty w rodzaju Robosimiania z łatwością mieszczą się wszędzie tam, gdzie człowiek, a są znacznie bardziej uniwersalne. 2. Interakcja z ludźmi. Wydawałoby się, że lepiej się będziemy czuć współpracując z czymś, co wygląda i zachowuje się tak jak my sami. Okazuje się, że wręcz przeciwnie. Im bardziej robot przypomina człowieka, tym bardziej obrzydliwy, wstrętny i straszny będzie się wydawał i tym gorzej przebiegać będzie interakcja. Zjawisko nosi nazwę "uncanny valley" i jest dość dobrze zbadane przez psychologów. Rozwiązaniem jest nadanie abstrakcyjnych lub komiksowych kształtów robotom, ale jeszcze łatwiej po prostu zaprojektować je tak, żeby ich kształt odpowiadał ich funkcji. 3. Wydajność energetyczna. Homo sapiens jest chyba najwydajniejszym biegaczem długodystansowym wśród zwierząt — potrafimy zagonić na śmierć konia. Nasz chód jest bardzo wydajny energetycznie — wybicie się z kostki pozwala na odzyskanie sporej części energii, która w innym przypadku zmarnowana by była na uderzeniu nogi w ziemię. Od dłuższego czasu próbujemy zbudować urządzenia, które by naśladowały ten chód. No ale przy całej tej wydajności tak naprawdę nic nie umywa się do transportu kołowego, który ma tą zaletę, że nie zużywa energii na ciągłą walkę z grawitacją. To między innymi dlatego wszystkie łaziki marsjańskie są na kołach, nawet jeśli mają pokonywać dość nierówny teren. Nawet jeśli kiedyś uda nam się zbudować dwunożne podwozie wzorowane na ludzkim chodzie, to przecież nie ma żadnego powodu dla którego jego górna część miałaby wyglądać jak człowiek. 4. Teleoperacja — w literaturze science fiction oraz filmach, szczególnie japońskich, często pojawia się pomysł robota sterowanego bezpośrednio ruchami człowieka. Pilot takiego robota, siedzący w jego wnętrzu lub w osobnym urządzeniu, jest zwieszony w specjalnej uprzęży (lub pływa w pojemniku ze specjalnym płynem) z sensorami, które każdy jego ruch przekładają na ruch robota. Robot jest przy tym często wielokrotnie większy i silniejszy od człowieka. Wydaje się oczywistym, że w takiej sytuacji najlepiej sprawdzać się będzie kształt kopiujący ludzkie ciało. W praktyce okazuje się jednak, że pomysł taki jest na dzień dzisiejszy praktycznie niemożliwy do zrealizowania w takiej postaci: utrzymywanie równowagi wymaga informacji zwrotnej, której nie mamy jak takiemu pilotowi przekazać. Być może kiedyś będziemy potrafili wpiąć się bezpośrednio w układ nerwowy pilota i w ten sposób sterować robotem, ale wówczas właściwie nie ma powodu, żeby nadal był on człekokształtny, a nie, na przykład, w kształcie goryla czy gibbona — przecież mamy nawet nerwy i odruchy potrzebne do sterowania ogonem! Na dzień dzisiejszy teleoperacja zazwyczaj ogranicza się do samych manipulatorów, czasem zamontowanych na ruchomej platformie — i to w zupełności wystarcza. Nawet nie mają na końcach ludzkich dłoni, tylko od razu narzędzia. 5. Seksboty. Bez komentarza — chyba tylko naprawdę zdesperowany nastolatek mógłby wpaść na taki pomysł. Podsumowując, w zasadzie nie ma żadnego powodu, aby budować praktyczne człekokształtne roboty. Jeśli ich wygląd nie jest celem samym w sobie, to warto zastanowić się nad projektem najlepiej przystosowanym do ich zadań, zamiast niepotrzebnie komplikować sobie życie próbując naśladować naturę.
  43. 5 punktów
    Cześć, Myślę że każdy kojarzy monitory, które mają wbudowane oświetlenie z tyłu. Zawsze uważałem to za fajny dodatek, jednak producenci często słono sobie za takie monitory liczą. Dlatego postanowiłem, że stworzę własną wersję w oparciu o Arduino i taśmę LED RGB i chciałbym się z Wami podzielić efektami mojej pracy. Zacznę od spisu niezbędnych materiałów: Arduino Nano (ja użyłem klona) Taśma LED RGB 12V Zasilacz 12V, minimum 1A 3 tranzystory MOSFET IRL540N 3 tact switche Przełącznik bistabilny suwakowy 3 rezystory 10k Listwa goldpin żeńska Płytka prototypowa Przewody Niezbędna będzie też lutownica (i oczywiście cyna), przydatny jest także pistolet z klejem na ciepło oraz płytka stykowa i pojedyncza dioda RGB ze wspólną anodą (i 3 rezystory 330R) w celu sprawdzenia czy układ działa poprawnie zanim zaczniemy lutować. Jak już mamy skompletowany cały zestaw możemy zabierać się do pracy. Na początek schemat układu: Całość ma działać w taki sposób, że po naciśnięciu przycisku jasność danego koloru wzrasta, a jeżeli przestawimy pozycję przełącznika to tym samym przyciskiem będziemy przyciemniać wybrany kolor. Natężenie światła będzie regulowane przez sygnał PWM na portach Arduino, które będą podłączone do bramek tranzystorów unipolarnych. Warto zacząć od złożenia całości na płytce stykowej w celu skontrolowania czy układ działa poprawnie. U mnie wygląda to tak: Oczywiście żeby dioda zaświeciła potrzebny jest program dla Arduino: #define oswietlenieG 10 //PWM do bramki tranzystorów sterujących oświetleniem (przez R 10k) #define oswietlenieR 11 // -//- #define oswietlenieB 9 // -//- #define przyciskG 3 //przycisk zmieniajacy natezenie B #define przyciskB 4 //przycisk zmieniajacy natezenie G #define przyciskR 5 //przycisk zmieniajacy natezenie R #define przycisk 2 //przelacznik do zmiany znaku "zmiany" int R=0; //jasność koloru czerwonego int G=0; //jasność koloru zielonego int B=0; //jasność koloru niebieskiego int zmiana=5; //wartość o jaką zmieni się natężenie przy pojedynczym kliknięciu void setup() { pinMode(przycisk,INPUT_PULLUP); //definiowanie pinów pinMode(przyciskR,INPUT_PULLUP); pinMode(przyciskG,INPUT_PULLUP); pinMode(przyciskB,INPUT_PULLUP); pinMode(oswietlenieR,OUTPUT); pinMode(oswietlenieG,OUTPUT); pinMode(oswietlenieB,OUTPUT); } void loop() { if(digitalRead(przycisk)==LOW) //sprawdzenie czy przełącznik jest w pozycji "on" { if(digitalRead(przyciskR)==LOW) //sprawdzenie czy przycisk do zmiany koloru czerwonego jest wciśnięty { R=R-zmiana; //zmniejszenie wypełnienia if(R<=0) R=0; delay(20); //niwelacja drgań styków } if(digitalRead(przyciskG)==LOW) { G=G-zmiana; if(G<=0) G=0; delay(20); } if(digitalRead(przyciskB)==LOW) { B=B-zmiana; if(B<=0) B=0; delay(20); } } else { if(digitalRead(przyciskR)==LOW) { R=R+zmiana; if(R>=255) R=255; delay(20); } if(digitalRead(przyciskG)==LOW) { G=G+zmiana; if(G>=255) G=255; delay(20); } if(digitalRead(przyciskB)==LOW) { B=B+zmiana; if(B>=255) B=255; delay(20); } } analogWrite(oswietlenieR,R); //ustawienie zadanego wypełnienia na pinie R analogWrite(oswietlenieG,G); // -//- G analogWrite(oswietlenieB,B); // -//- B } Jeżeli wszystko jest połączone poprawnie dioda powinna zmieniać kolor gdy naciskamy przyciski. Jak już wiemy, że nasz układ działa, możemy przejść do lutowania go na płytce prototypowej. Zacząłem od przylutowania listwy goldpin do której będziemy wpinać nasze Arduino. Co prawda powinno się zaczynać od małych elementów, jednak w ten sposób łatwiej jest określić gdzie mają się znajdować tranzystory. Kolejno na płytce pojawiły się rezystory oraz mosfety. Na koniec przylutowałem wyprowadzenia zasilacza, przewody które będą biegły do modułu z przyciskami i piny z taśmy LED. Trzeba pamiętać o podłączeniu zasilania do wejścia taśmy. Do tworzenia połączeń bardzo dobrze się nadają odcięte końcówki wyprowadzeń rezystorów. Gotowa płytka wygląda u mnie tak: (tył jest lekko ubrudzony, bo pokryłem całość klejem na ciepło i nie udało mi się usunąć całego do zdjęcia) Następnie stworzyłem moduł sterowania. Połączyłem każdy przycisk, oraz wyprowadzenie przełącznika do wspólnej masy a do poszczególnych przycisków dolutowałem przewody z płytki. Całość zamknąłem w tekturowym opakowaniu, które zalałem klejem na ciepło: Co prawda nie wygląda to zbyt ładnie, jednak przykleiłem to na bocznej ściance głośnika, więc nie jest to widoczne. Teraz jest dobry moment żeby przeprowadzić test całości, jeszcze zanim pokryjemy całość klejem na ciepło (ja popełniłem ten błąd że nie zrobiłem testu i miałem przez to dodatkową robotę z usuwaniem kleju jak okazało się że jeden z tranzystorów nie działa). Jeżeli wszystko jest tak jak powinno możemy przejść do przycinania taśmy na właściwą długość a następnie polutowania odpowiednich wyprowadzeń (ponownie przydatne są ucięte "nóżki" od rezystorów) tak żeby stworzyć prostokąt który będzie pasował do naszego monitora. Gdy taśma jest już gotowa warto ponownie zrobić test i jeżeli wszystko działa poprawnie "zaizolować" łączenia za pomocą kleju na ciepło a następnie przykleić taśmę do monitora. Ja moją dodatkowo dokleiłem za pomocą taśmy izolacyjnej, żeby się lepiej trzymała: Teraz wystarczy podłączyć taśmę do naszej płytki, wpiąć Arduino i całość powinna nam pięknie świecić: Mam nadzieję, że mój projekt się Wam spodoba i sami spróbujecie stworzyć takie oświetlenie, bo efekt jest naprawdę warty poświęcenia czasu. PS. Zamiast przycisków można by użyć np. modułu bluetooth albo odbiornika podczerwieni i dowolnego pilota od telewizora, ale ze względu na to, że sterowanie w moim przypadku znajduje się w łatwo dostępnym miejscu uznałem że byłaby to niepotrzebna komplikacja. Pozdrawiam ~Usohaki
  44. 5 punktów
    Wstęp O projekcie myślałem od czerwca poprzedniego roku, to jest 2018. Postępy prac opisywałem tu - cel projektu stanowiła budowa robota klasy SCARA - dwuosiowego ramienia robotycznego manipulującego efektorem w płaszczyźnie XY, z funkcją grawerowania laserowego oraz mini- wrzecionem modelarskim, rysowania mazakiem i pick&place realizowanym techniką próżniową. SCARA to akronim słów Selective Compliance Articulated Robot Arm, co oznacza, że robot w osiach X i Y porusza się obrotowo względem siebie i liniowo w osi Z. Dzięki temu, SCARA jest szybsza (w porównaniu do maszyny pracującej w układzie kartezjańskim), pozwala na osiągnięcie zadanego w obszarze roboczym punktu dwoma trajektoriami, a także umożliwia łatwy montaż połączony z niewielkimi rozmiarami w porównaniu do pola roboczego, który oferuje (klasyczna konfiguracja XYZ cechuje się faktem, że pole robocze musi być mniejsze od rozmiarów samej konstrukcji). Nie może natomiast przenosić dużych sił, a samo sterowanie wymaga zastosowania równań trygonometrycznych oraz interpolowania w momencie, kiedy końcówka ma wykonać ruch po linii prostej. Ponadto, roboty tej klasy cechują się mniejszą sztywnością. Całość sprawia, że ramiona robotyczne tego typu są idealne dla lekkich aplikacji, gdzie często wymagana jest szybkość, higieniczność (małe natężenie hałasu) oraz łatwość instalacji połączona z niewielką ilością miejsca, czyli w zastosowaniach "podnieś i przenieś" lub operacjach montażowych, chociaż z powodzeniem może posiadać koncówkę roboczą typową dla tradycyjnych maszyn CNC. Mechanika i elektronika Prostokątna podstawa robota o wymiarach 320x240mm została numerycznie wyfrezowana, z plexi o grubości 16mm. Otwory, służące zamocowaniu silnika oraz dysku łożyskującego I stopień swobody zostały nagwintowane gwintem M5. Wszystkie elementy 2D, które osobiście frezowałem, projektowałem w Solid Edge 2019. Najwięcej problemów miałem z przekładniami (zwiększenie momentów obrotowych silników oraz rozdzielczości (stosunek ilość kroków/obrót) oraz konieczność przenoszenia dużych sił, zgodnie z równaniem dźwigni jednostronnej) - właściwe ramię jest przymocowane do koła zębatego, które łożyskowane jest przez dysk z poliamidu (przeniesienie sił osiowych) oraz wciskane łożyska 6008RS (przeniesienie sił promieniowych). Oś koła stanowi imbusowa śruba M10, przykręcona nakrętką samohamowną z podkładką. W obydwóch stopniach swobody, przekładnie pasowe działają w oparciu o zamknięte paski zębate o module HTD 3mm, które pochodzą ze znanych robotów kuchennych "KASIA". Koła zębate, podobnie jak inne wydruki 3D, wykonano przy pomocy drukarki Zortrax M200. Wykorzystałem bardzo dobry filament ABS firmy Spectrum. Drugi stopień swobody działa i założyskowany jest identycznie z tą różnicą, iż wykorzystano jedno łożysko kulkowe, a dysk wykonano z ABS-u. Warto zaznaczyć, że każdy z uchwytów silników krokowych posiada podłużne otwory, tak zwane "fasolki", które pozwalają na regulację naprężenia paska. Średnice osi silników krokowych to odpowiednio 6,35mm oraz 5mm, niezawodne połączenie małych zębatek z gładkim wałem uzyskano poprzez wcisk na gorąco oraz ścisk dwoma śrubkami imbusowymi M3. Drugie z ramion można łatwo zmienić, w zależności od tego, jaką funkcję ma pełnić robot (na zdjęciu koncówka z modułem lasera IR 500mW). Każde z ramion ma długość 200mm, zatem maksymalny obszar roboczy konstrukcji (bez uwzględnienia faktu ograniczenia go przez wieże silników i podstawę) to koło o średnicy 800mm. Wymiana ramienia (a co za tym idzie - funkcji) jest łatwa i przyjemna, zajmuje mniej niż 5 minut. W robocie nie zastosowano czujników krańcowych, pozycję zerową ustawiam ręcznie w linii prostej. W precyzyjnym ustawieniu pozycji zerowej pomocne są specjalne znaczniki (zdjęcie poniżej), zakładane tylko na czas zerowania. Drugie zdjęcie przedstawia budowę, a trzecie - mosiężne emblematy, jakimi ozdobiłem podstawę Wykorzystałem silniki krokowe, NEMA23 i NEMA17 Osobny blok funkcjonalny robota stanowi sterownik, którego zdjęcie przedstawiono poniżej - połączenia z urządzeniami zewnętrznymi (silniki krokowe oraz efektor) zrealizowane zostały złączami JST-BEC (bądź 3-pinowym złączem 0,1" jeżeli efektorem jest serwomechanizm modelarski). Do zasilacza sterownika (1) podłączany jest przewód zasilający sieciowy. Napięcie wyjściowe wynosi 12V DC, a wydajność prądowa zasilacza to 5A. Celem sterowania robotem (kiedy nie jest wgrana zaprogramowana sekwencja ruchów) należy podłączyć przewodem USB typu B do komputera PC płytkę Arduino UNO (6), która stanowi "mózg" sterownika - podaje ona sygnały sterujące pracą silników krokowych (HY-DIV268N oraz TB6560 - odpowiednio 2 i 3), serwomechanizmu i/lub przekaźnika (7), który może załączać palnik laserowy lub elektrozawór. Płytka (5) posiada bezpiecznik, diodę - wskaźnik napięcia (na płycie znajduje się również woltomierz (9)), kondensatory chroniące przed chwilowym spadkiem napięcia zasilania oraz umożliwia podłączenie każdego modułu odpowiednio pod linię 12V DC lub 5V DC (dla logiki), za którą odpowiedzialny jest moduł stabilizatora szeregowego (8) - LM7805. Zadaniem wentylatora (4) jest chłodzenie sterowników silników krokowych. Sterownik przeszedł drobny lifting i obecnie wygląda tak, jak na II zdjęciu Software Dla funkcji rysowania, palenia laserem oraz grawerowania wykorzystano udostępniane na zasadach open-source oprogramowanie firmy Makeblock - mDraw, rozszerzony o funkcję sterowania przekaźnikiem. Natomiast dla aplikacja pick&place napisałem własny program, z funkcją odwrotnego liczenia kinematyki, oraz zamykania/otwierania elektrozaworu, co pozwala na zaprogramowanie pełnego cyklu "podnieś i przenieś". Składa się on z prostych procedur, typu PrzejdzDoPunktu(x,y), Chwyc(), Pusc(), SilownikZ(pozycja) i tak dalej. Trzecią oś swobody stanowi bowiem dla rysowania i grawerowania niewielka prowadnica podnoszona za pomocą linki przez serwo, natomiast przy chwytaniu podciśnieniowym wspomogłem się https://www.thingiverse.com/thing:3170748 Tak wygląda moduł generujący podciśnienie, wykorzystałem pompę próżniową Film - podsumowanie zawierające ujęcia z budowy oraz działania konstrukcji Robot otrzymał wyróżnienie na tegorocznych zawodach Robotic Arena oraz został zgłoszony do konkursu "Elektronika, by żyło się łatwiej". Przy okazji, pragnę podziękować mojemu sponsorowi - firmie MONDI Polska, która umożliwiła realizację całości projektu. Pozdrawiam, Wiktor Nowacki wn2001 (dla ścisłości - spostrzegawczy z pewnością zauważą rozbieżności w detalach pomiędzy różnymi zdjęciami oraz ujęciami z filmu - wykonałem je po prostu w różnym czasie, kiedy udoskonalałem jeszcze i poprawiałem konstrukcję )
  45. 5 punktów
    Powoli zbliżam się do listy moich ukończonych projektów, które nadają się do publikacji na forum. Ten będzie jednym z ostatnich, jeśli nie ostatnim. Oczywiście na jakiś czas, a nie zupełnie. Prawdę mówiąc początkowo miałem wątpliwości, czy w ogóle nadaje się on do publikacji. Po pierwsze nie jest to zupełnie autorskie opracowanie, po drugie nie jestem pewien, czy można nazwać go dostatecznie ambitnym. Co do pierwszej kwestii, to po przejrzeniu poprzednich wpisów doszedłem do wniosku, że większość amatorskich projektów nie jest zupełnie oryginalna - każdy szuka gdzieś inspiracji, wykorzystuje gotowe biblioteki, odtwarza na swój sposób cudze projekty. W końcu zegarów nixie i zegarów binarnych także powstało całe mnóstwo przed moim... A co do drugiej kwestii to cóż... Pozostawiam to ocenie czytelników. Źródłem inspiracji tego projektu był artykuł znaleziony w serwisie Evil Mad Scientist. Jego autorzy postanowili odtworzyć Tennis for two, czyli tytuł uważany za pierwszą grę elektroniczną w historii. Oryginalna wersja z 1958 roku pracowała na analogowym komputerze lampowym, wykorzystując oscyloskop w roli wyświetlacza. Prezentowano ją gościom amerykańskiego Broohaven National Laboratory, odwiedzającym tę placówkę badawczą w ramach dni otwartych. Rozgrywka przypomina trochę późniejszego "Ponga", z tą różnicą, że tutaj obserwujemy kort tenisowy w rzucie z boku. Każdy z dwóch graczy otrzymuje kontroler wyposażony w przycisk i potencjometr. Przycisk służy do serwowania i odbijania piłeczki, pokrętło regulują kąt odbicia. Pośrodku ekranu znajduje się również siatka. Wersja ze strony EMS była typowym "weekendowym" projektem, przygotowanym za pomocą zestawu uruchomieniowego i płytki uniwersalnej. Ja postanowiłem zbudować bardziej "finalną" wersję. Płytkę zaprojektowałem od podstaw, stosując inny mikrokontroler (Atmega32), co wymagało niewielkich zmian w kodzie. Przy okazji poprawiłem kilka bugów znalezionych w oryginalnej wersji (brakowało m.in. jednej instrukcji warunkowej, co w pewnych warunkach pozwalało na oszukiwanie przez wpływanie na zachowanie piłeczki, gdy ta znajdowała się po stronie przeciwnika). Urządzenie zostało zabudowane w kompaktowej, plastikowej obudowie. Dwie mniejsze obudowy okazały się być świetnym materiałem na kontrolery. Sygnał sterujący oscyloskopem (ustawionym w tryb XY) jest generowany przez dwa przetworniki R2R, których sygnały są wyprowadzone na dwa złącza RCA. Do podłączenia oscyloskopu potrzebna jest jeszcze przejściówka na BNC. W ramach ciekawostki mogę dodać, że gra przez kilka miesięcy była prezentowana na wystawie w krakowskim Muzeum Inżynierii Miejskiej. Wytrzymała intensywne użytkowanie przez szkolna młodzież. Obecnie można w nią zagrać odwiedzając krakowski Hackerspace.
  46. 5 punktów
    Niewątpliwie procesory, bądź mikroprocesory stanowią ogromną część elektroniki użytkowej. Prawie w każdym urządzeniu, poczynając od najprostszych, a kończąc na najbardziej zaawansowanych komputerach, najważniejsza jest jednostka centralna. Czasy największej świetności ośmiobitowe procesory mają już za sobą, ale nadal stanowią ważną część elektroniki. Wiele urządzeń nadal z nich korzysta. Moją przygodę z elektroniką cyfrową rozpocząłem od programowania mikroprocesorów firmy Atmel były to dokładniej procesory Atmega8 oraz Atmega328. Mimo wielkich możliwości jakie dają mikrokontrolery bardziej interesowała mnie strona hardware’owa tych układów. Na ich podstawie oraz procesorów takich jak Intel 4004, 8080 stopniowo poznawałem budowę oraz działanie mikroprocesorów. W pewnym momencie stwierdziłem że nie jest to takie trudne i sam zbuduję własny procesor. Był to DCE 4 (D-digital, C-computer, E-electronic, 4 ponieważ była to jednostka czterobitowa). Następnie rozpocząłem prace nad ośmiobitowym procesorem DCE 84. Jednak i on z upływem czasu wydał mi się bardzo prosty. Prezentowany mikroprocesor DCE 812 zaprojektowałem korzystając z rozwiązań zastosowanych w DCE 84 bazując na pełnej architekturze harwardzkiej (gdzie pamięć dla programu i danych jest fizycznie rozdzielona). Schemat blokowy układu można znaleźć poniżej. Do budowy zostały użyte podstawowe układy logiczne wykonane w technologii CMOS (przykładowo bramki AND) oraz gotowe układy pamięci RAM (UL6516 2k x 8bit) oraz ROM(dwa układy 28c64 8k x 8bit) , ponieważ budowa własnych pamięci nie była możliwa z powodu braku czasu i środków. Elementy takie jak ALU, układ sterowania, zegar, oraz obsługa pamięci i poszczególnych rejestrów roboczych została zaprojektowana przeze mnie od podstaw. Fizycznie układ powstał stosunkowo niedawno i nie obyło się bez komplikacji. Zmiana układu obsługującego pamięć RAM sprawiła, że układ działa zgodnie z założeniami. Pozwala on na wykonywanie podstawowych działań matematycznych oraz prostych programów stworzonych w języku C++ i przekonwertowanych na polecenia dla tego procesora. Najbardziej zaawansowanym programem, który udało mi się uruchomić było generowanie kolejnych liczb z ciągu Fibonacciego. Praca mikroprocesora zostaje rozpoczęta od wciśnięcia fizycznego przycisku RESET, który ustawia stan "0" na wyjściach wszystkich wewnętrznych rejestrów. Uzyskujemy poprzez to adres zero na wyjściu licznika rozkazów co powoduje rozpoczęcie pracy od pierwszego wprowadzonego rozkazu (lista rozkazów widoczna na zdjęciu poniżej). Następnie układ zaczyna liczyć od 0 do 15 wewnątrz układu sterowania do każdej z tych mikrooperacji przypisane jest odpowiednie działanie zgodne z rozkazem wprowadzonym do pamięci ROM może to być np. zapis do rejestru B, reset licznika rozkazów. Po wykonaniu wszystkich mikrooperacji licznik rozkazów zwiększa swoją wartość o jeden co skutkuje przejściem do kolejnego rozkazu i cały cykl wykonywany jest ponownie. Programowanie procesora realizowane jest poprzez odpowiednie przełączniki które umożliwiają przełączanie układu między stanem pracy a programowaniem. Wprowadzanie danych oraz wybieranie adresów również realizowane jest w ten sposób. Odpowiednie przełączniki służą również do sterowania zegarem procesora. Generowanie impulsów może odbywać się automatycznie z częstotliwością ok. 10Hz lub manualnie poprzez wciśnięcie przycisku. Obecnie projektuje kolejną wersje własnego procesora tym razem staram się wszystko umieścić w jednym układzie FPGA (Korzystam z tej płytki). Postępy w pracach można obserwować na moim blogu https://rafal-bartoszak.blogspot.com/ Dodatkowo wstawiam też link do filmu gdzie można zobaczyć działanie układu.
  47. 5 punktów
    Witam! Chciałbym przedstawić wam moją konstrukcję, która stała się przedmiotem mojej pracy inżynierskiej. Mechanika: Konstrukcja mechaniczna w zasadzie oparta jest na 2 płytkach PCB. Do płytki głównej zamontowane są dwie kulki podporowe, a także silniki pololu o przekładni 1:10 co stanowi napęd robota. Z przodu zamontowana jest płytka z podstawą zawierająca uchwyty do czujników ultradźwiękowych. Taki sam uchwyt pod czujnik znajduje się również na 'ogonie' robota - jest on nie używany i został zamontowany eksperymentalnie. Na przedłużonej osi silników zostały zamontowane magnesy enkoderów magnetycznych co ilustruje poniższa fotografia. Elektronika: Sercem robota jest mikrokontroler AVR ATmega162, którego zadaniem jest sterowanie robotem w tym: obsługa enkoderów, sterowanie silnikami, odbiór informacji z mikrokontrolera slave nt. odległości mierzonych przez czujniki, realizację algorytmów sterowania, realizacja połączenia bluetooth, obsługa wyświetlacza LCD hd44780. Drugi mikrokontroler również AVR, ATmega328 realizuje tylko i wyłącznie obsługę czujników odległości HC-SR04. Pomiary normalizuje i wysyła interfejsem SPI do jednostki głównej ATmega162. Na pokładzie robota znajdują się również dwa enkodery magnetyczne AS5040 pracujące w pętli sterowania regulatora PI silników. Enkodery te pracują w trybie defaultowym czyli wyjście kwadraturowe, rozdzielczość 2x256. Silniki sterowane są poprzez mostek H L293. Komunikacją z robotem zajmuje się moduł bluetooth bt222 - czyli komunikacja jest przez UART mikrokontrolera. Główny mikrokontroler jest taktowany zewnętrznym kwarcem 16Mhz co przy takiej ilości obsługiwanych urządzeń i wykorzystywanych interfejsów było po prostu konieczne, z kolei mikrokontroler atmega328 jest taktowany zewnętrznym kwarcem jednak z powodu lepszej podstawy czasowej, która jest konieczna do dokładnych odczytów z czujników odległości. Na wyświetlaczu LCD są wyświetlane aktualnie mierzone wartości odległości czujników. Automatyka: Zostało wspomniane, że silnikami steruje algorytm regulatora PI. Aby obliczyć jego nastawy została przeprowadzona identyfikacja transmitancji. W tym celu wykorzystałem UART do przesyłania aktualnej prędkości silników oraz środowisko Matlab do wizualizacji danych na wykresie. Z wyliczeń wyszło, że silniki z zastosowanymi kołami mają transmitancję: G(s)=107/(0.19s+1) Po obliczeniu nastaw regulatora i zastosowaniu w praktyce okazało się, że można jeszcze troszkę dopieścić nastawy i ostatecznie wykresy odpowiedzi skokowej bez i z regulatorem wyglądają następująco: Software: Napisane w C w środowisku Eclipse. Umożliwia robotowi 3 tryby. Tryb avoid. W trybie tym robot ma za zadanie omijać przeszkody wykorzystując regulator rozmyty Takagi-Sugeno. Wykorzystuje w tym celu odczyty z czujników odległości. Tryb goal seeking. Robot podąża do celu czyli do odebranych przez bluetooth współrzędnych kartezjańskich podanych w [mm], zakładając, że miejsce od którego zaczyna lub dostał nowy zestaw współrzędnych, ma współrzędne 0,0. W trybie tym regulator Takagi-Sugeno ma za zadanie na podstawie zaimplementowanej odometrii oraz współrzędnych końcowych sterować robotem w celu osiągnięcia zadanego położenia. Problem algorytmu przedstawia ilustracja: Tryb avoid + goal seeking. Jest to połączenie dwóch wcześniej opisanych trybów. W trybie tym działają równocześnie obydwa wcześniej opisane algorytmy, jednak na wejście regulatorów PI sterujących silnikami jest podawany zbalansowany sygnał z obu algorytmów. Tzn w zależności od najmniejszej odległości od przeszkody mierzonej przez któryś z czujników jest obliczany procentowy udział wartości sterowania od dwóch algorytmów. Brzmi skomplikowanie ale takie nie jest. Najlepiej zobrazuje to wzór: V=K*Vg+(1-K)*Va gdzie V jest prędkością zadaną na regulator PI silnika, Vg jest prędkością wynikającą z algorytmu goal seeking, Va jest prędkością wynikającą z algorytmu avoid, K jest parametrem, który przyjmuje wartość z przedziału 0-1 w zależności od mierzonej minimalnej odległości do przeszkody. Robota wprowadza się w odpowiedni tryb za pomocą dwóch przycisków lub poprzez interfejs bluetooth. Odpowiednie tryby sygnalizują diody LED. W celu przesłania komendy zawierającej współrzędne celu najpierw należy wprowadzić robota w odpowiedni tryb, a następnie wysłać do niego wg stworzonego prze zemnie protokołu dane. Protokół wysyłania danych jest następujący: X±⌴⌴⌴Y±⌴⌴⌴& gdzie +- – znak współrzędnej, _ – wartość współrzędnej. Testy. Konstrukcja została przetestowana pod względem dokładności odometrii. Robot podczas licznych testów na bieżąco wysyłał swoje współrzędne, które w dalszej kolejności były obrabiane w środowisku Octave do przyjemnych w analizie wykresów. Przykładowy wykres drogi, którą pokonał robot na 'placu manewrowym' w trybie avoid: ... oraz rzut z góry na 'plac manewrowy': U góry pozycja początkowa, na dole końcowa robota. Cały ten obszar był dookoła ogrodzony ścianką. Słowa samokrytyki Co bym zmienił ? Czujniki. Ze względu na problematyczność wykrywania małych przeszkód lub gdy płaszczyzna przedmiotu uniemożliwia odbicie się fali ultradźwiękowej w stronę odbiornika. Zdarza się, że z powodu gubienia przeszkód robot po prostu w nie wpada. Najciekawsze fragmenty programu: Regulatory PI: //######################################## REGULATOR PRĘDKOŚCI ############################################ erra = vl-Va;//liczenie błedu prędkości errb = vp-Vb; if(ua<1023&&ua>-1023)Ca = Ca+(erra*dt);//całka błędu ua = kp*(erra + Ca/Ti);//regulator PI //P I if(ub<1023&&ub>-1023)Cb = Cb+(errb*dt);//całka błędu ub = kp*(errb + Cb/Ti);//regulator PI //P I if((ua<10)&&(ua>-10))ua=0; if((ub<10)&&(ub>-10))ub=0; motor_set(ua,ub);//ustawia sterowanie silników Regulator rozmyty Takagi-Sugeno trybu goal seeking: inline void PsiZ2Vlr(float *Psi, float *z, int16_t *vl,int16_t *vp) { float PSI[3]; float XL[6],XR[6]; float NR,FR,L,S,P,VL=0,VP=0,m=0; uint8_t i,k; ///////////////////////////////LICZENIE PRZYNALEŻNOŚCI////////////////////////////////// if(*z<=100)NR=-0.01*(*z)+1;else NR=0;//jak bardzo blisko jest cel if(*z<=100)FR=0.01*(*z);else FR=1;//jak bardzo daleko jest cel if(*Psi<=0)L=-0.3183*(*Psi);else if(*Psi<-M_PI)L=1;else L=0; if(*Psi<=0)S=0.3183*(*Psi)+1;else if(*Psi<-M_PI)S=0; else if(*Psi>M_PI)S=0;else S=-0.3183*(*Psi)+1; if(*Psi>=0)P=0.3183*(*Psi);else if(*Psi>M_PI)P=1;else P=0; /////////////////////////////////////TABLICA REGUŁ////////////////////////////////////// PSI[0]=L; PSI[1]=S; PSI[2]=P; //NR; XL[0]=-4000;XR[0]=4000; XL[1]=0;XR[1]=0; XL[2]=4000;XR[2]=-4000; //FR; XL[3]=-4000;XR[3]=4000; XL[4]=4000;XR[4]=4000; XL[5]=4000;XR[5]=-4000; /////////////////////////////obliczanie prędkości silników////////////////////////////// for(k=0,i=0;k<3;k++,i++)//pierwszy wiersz tabeli { VL+=NR*PSI[k]*XL[i]; VP+=NR*PSI[k]*XR[i]; m+=NR*PSI[k]; } for(k=0;i<6;k++,i++)//drugi wiersz tabeli { VL+=FR*PSI[k]*XL[i]; VP+=FR*PSI[k]*XR[i]; m+=FR*PSI[k]; } *vl=(int16_t)VL/m; *vp=(int16_t)VP/m; } Obsługa czujników odległości: //PRZERWANIE OD CAPTURE PIN ISR(TIMER1_CAPT_vect) { if( (TCCR1B & (1<<ICES1)) ) { LastCapture = ICR1;//jesli zbocze narastajace, zlap ICR1 } else { PulseWidth = ICR1 - LastCapture;//Jeśli zbocze opadajace oblicz PW pomiar=0;//wyzeruj flagę pomiaru } TCCR1B ^= (1<<ICES1);//Zmiana zbocza wyw. przerwanie } Mam nadzieję że robocik się podoba. W razie pytań proszę śmiało. Całości kodu nie udostępniam ze względu na prawa autorskie niektórych funkcji bibliotecznych. Co mogłem udostępniłem. Pozdrawiam was wszystkich !
  48. 5 punktów
    Czytam te wpisy kolegi @xirtt i coraz bardziej się zastanawiam, czy to jeszcze forum o robotyce, elektronice, czy już portal randkowy. Ciągle tylko o miłości i miłości... A biorąc pod uwagę, że na portalu prawie sami faceci, to nawet wolę nie zgadywać w którą stronę ten portal zmierza.
  49. 5 punktów
    @Treker a może to właśnie jest pomysł na "kolejny krok" portalu? Nie ograniczać się do samych kursów, ale przeprowadzać egazminy, czy testy i wydawać "certyfikaty"? Pewnie zabrzmi to bez sensu, ale może to pewien biznes-plan i kiedyś pracodawcy będą doceniali w CV ukończenie szkolenia Forbot-a? Co więcej odpowiednie egzaminy mogłyby ustalać rangę użytkownika na forum - co czasem oszczędzałoby pewnie wielu pytań.
  50. 5 punktów
    Myślę, że nie warto spierać się o takie głupoty - jako inny przykład definicji dystrybucji linuxa polecam wiki: https://pl.wikipedia.org/wiki/Dystrybucja_Linuksa Tutaj mamy nieco lepiej zdefiniowane kryteria, bo pisanie o paru ludziach to chyba kiepski pomysł - w każdej nietrywialnej firmie znajdziemy paru ludzi, niektórzy nawet pracują. Pobieranie i używanie też nie nadaje się zbytnio - jako ciekawostkę podam, że yocto ma manager pakietów, do wyboru .deb, .rpm, .ipk oraz .tar - nie opisuję tego, ale pakiety są automatycznie tworzone i wystarczy je umieścić na serwerze. A co do jednego użytkownika to faktycznie na RPi moja dystrybucja ma jednego użytkownika - natomiast systemy nad którymi pracuję zawodowo mają znacznie więcej użytkowników. Wszyscy pobierają pakiety i z nich korzystają np. oglądając telewizję, chociaż wcale nie widzą że na pokładzie dekodera działa linux... Więc zostawmy może te spory językowe w spokoju - yocto to w rzeczywistości zestaw skryptów, coś jak make. Pozwala na skompilowanie relatywnie dużego systemu, a czy nazwiemy go dystrybucją, firmware-m, czy androidem to zostawmy lingwistom. A jak już się czepiamy słówek - formalnie Linux to samo jądro... Cała reszta to właśnie dystrybucja, czyli zestaw oprogramowania bazujący na GNU. Dlatego niektórzy puryści nazywają takie cudo GNU/Linux, natomiast to co mamy w telefonach Android/Linux. Zawartość karty SD Wracając do głównego wątku, czyli możliwości pracy z linuksem nieco inaczej niż przez instalację Raspbiana. Ostatnio wygenerowałem obraz systemu poleceniem bitbake core-image-minimal. Jak łatwo się domyślić jest to minimalny działający obraz, możemy go uruchomić ale praca na nim nie będzie pasjonująca. Jednak zanim przejdziemy dalej chciałbym zatrzymać się przez chwilę nad tym co taki minimalny obraz zawiera - skoro jest mały to łatwiej zrozumieć jak to działa. Tutaj pierwsza uwaga - wbrew pozorom działa już całkiem sporo rzeczy. Zawdzięczamy to jądru systemu - mamy minimalny zestaw oprogramowania, ale jądro oraz większość sterowników jest już na miejscu. Jeśli podłączymy np. wyświetlacz zobaczymy że działa - nawet bez x serwera. Wspominam o tym żeby zwrócić uwagę na pewną nadmiarowość pełnych dystrybucji. Okazuje się że system wbudowany może używać znacznie mniej pamięci i innych zasobów niż pełna wersja "desktopowa". Na karcie SD znajdziemy podobnie jak w przypadku Raspbiana dwie partycje: Pierwsza ma rozmiar "aż" 40MB i typ FAT32. Druga to główny system plików, który zajmuje raptem 12MB. Na pierwszej partycji znajdziemy firmware dla GPU Malinki (za chwilę do tego wrócę), bootloadery oraz obraz jądra linuksa. Druga partycja to raczej minimalistyczny system plików - znajdziemy na nim (dość sporą) bibliotekę języka C oraz BusyBox, czyli program udostępniający podstawowe polecenia powłoki (https://busybox.net/about.html). Warto zwrócić uwagę na znaczny rozmiar katalogu lib - to właśnie domyślna biblioteka C tyle zajmuje. W urządzeniach wbudowanych są popularne jej zamienniki, jak chociażby uclibc (https://www.uclibc.org/) - nie tylko są mniejsze, ale często szybciej działają. W każdym razie taka optymalizacja pojednczych MB to temat na osobny wątek. Jak startuje system Celem moich być może zbyt długich wpisów jest pokazanie jak korzystać z u-boot-a, jednak niejako przy okazji chciałbym wyjaśnić miejsce bootloadera w procesie uruchamiania komputera. Zacznijmy od czegoś prostego co wszyscy znają, czyli mikrokontrolera. Powiedzmy ATmega328 - po włączeniu zasilania następuje reset procesora oraz wykonywany jest program z pamięci Flash. Adres gdzie zaczyna się program jest znany (nie jestem pewien jaki, ale to chyba mało istotne). Nowy mikrokontroler ma pustą pamięć Flash, więc przed pierwszym zaprogramowaniem procesor wykonuje tylko instrukcje NOP (https://www.microchip.com/webdoc/avrassembler/avrassembler.wb_NOP.html). Aby wgrać program konieczny jest sprzętowy programator - po zaprogramowaniu, program z pamięci Flash będzie wykonywany zaraz po załączeniu zasilania lub resecie procesora. Wszystko jest proste, ale wymaga dwóch istotnych elementów: pamieci flash oraz programatora. Konieczność posiadania programatora została elegancko rozwiązana w przypadku Arduino. Nowe mikrokontrolery są programowane za pomocą sprzętowego programatora i wgrywany jest do nich krótki program - nazywany właśnie bootloader-em. Przy kolejnych uruchomieniach procesora najpierw będzie zawsze działać bootloader. Wykona on sprawdzenie stanów odpowiednich pinów lub poczeka na dane przesyłane przez UART i jeśli wykryje odpowiednie sekwencje umożliwi programowanie pozostałej części pamięci flash. Natomiast podczas normalnej pracy urządzenia po prostu przekaże sterowanie do programu użytkownika. W pamięci flash przechowywane są więc dwa programy: bootloader oraz kod użytkownika. Jednak nie działają one równocześnie - bootloader rozpoczyna pracę, a następnie przekazuje sterowanie do głównego programu. Podobny schemat wykorzystywany jest w przypadku mikroprocesorów, chociaż jest nieco bardziej skomplikowany. Raspberry Pi jest pod tym względem nieco nietypowe - BCM2837 zawiera aż dwa procesory. Głównym wcale nie jest znany nam ARM, ale procesor graficzny, czyli VideoCore IV (https://en.wikipedia.org/wiki/VideoCore). Wiele osób takie rozwiązanie krytykuje, ale wcale nie jest ono aż tak nietypowe - spotkamy je również w świecie mikrokontrolerów, przykładowo przetworniki ADC mogą mieć wbudowany procesor (http://www.analog.com/en/products/aduc814.html), moduły radiowe często mogą wykonywać programy (http://www.ti.com/lit/ug/swru319c/swru319c.pdf), nawet popularny ESP8266 jest właściwie modułem radiowym który przypadkiem ma również procesor. Po załączeniu zasilania pierwszy startuje procesor graficzny, czyli VideoCore. Początkowy program jest zapisany w jego pamięci ROM - tutaj pojawia się pierwsza różnica między światem mikorkontrolerów i mikroprocesorów - ROM zamiast flash, to wbrew pozorom istotna zmiana. Jednak zasada jest identyczna - w ROM mamy bootloader, który wczytuje program. Różnica to liczba etapów. Na Arduino bootloader wczytywał od razu program główny, natomiast w przypadku mikroprocesorów najczęściej jest uruchamianych kilka bootloaderów, a dopiero na końcu właściwy program. Więc jako pierwszy uruchmia się bootloader zapisany w pamięci ROM - niewiele o nim wiadomo, większość producentów traktuje taki kod jako bardzo tajny. Ten bootloader potrafi obsługiwać karty SD oraz system Fat32. Stara się wczytać i uruchomić plik o nazwie bootcode.bin. Jak łatwo się domyślić, yocto pobrało odpowiedni plik z sieci i umieściło w obrazie, który nagraliśmy na karcie. Kolejny etap to wczytanie pliku start.elf. Nie jestem na 100% pewien, ale to chyba główny program dla VideoCore. Na naszej karcie znajdziemy jeszcze wersję start_x.elf z obsługą kamery RaspiCam oraz start_db.elf w wersji do debugowania (ale kodu i tak nie dostaniemy). Jest jeszcze plik start_cd.elf - nie wiem po co, może ktoś na forum wie do czego ta wersja służy? Pliki start.elf mają odpowiadajace im pliki z danymi, czyli fixup.dat, fixup_x.dat, fixup_db.dat oraz fixup_cd.dat. Wszystkie znajdziemy na naszej karcie SD - chociaż niepotrzebne możemy usunąć. Jeszcze dwa pliki są istotne dla uruchamiania malinki - config.txt oraz cmdline.txt. Oba są w formacie tekstowym, więc można użyć dowolnego edytora do ich zmiany. Pełnią funkcję ustawień, coś jak BIOS w stacjonarnym komputerze. Pierwszy jest bardzo rozbudowany, więcej o nim przeczytamy na stronie raspberrypi: https://www.raspberrypi.org/documentation/configuration/config-txt/README.md. Drugi zawiera parametry dla jądra systemu - używając u-boota nie będziemy musieli z niego korzystać. Teraz ostatnia i najważniejsza część - VideoCore ładuje z karty plik o nazwie kernel8.img do pamięci RAM oraz uruchamia rdzeń ARM tak aby wykonywał wczytany kod. Pewnie większość osób odgadnie, że kernel8.img to jądro systemu Linux - tak jest domyślnie, ale to wcale nie jest wymagane. Możemy napisać własny program, nazwać go kernel8.img i zostanie on uruchomiony bez Linux-a, czyli tak jak na Arduino. Jeśli lubimy takie ekstremalne rozrywki, polecam kurs programowania Raspberry Pi bez systemu operacyjnego: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/, jest nawet wersja dla języka C zmiast asemblera (ale to takie niesportowe : http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/. W naszym przypadku kernel8.img to wcale nie jądro linuksa - jądro znajdziemy w pliku Image. Natomiast kernel8.img to u-boot, czyli kolejny bootloader: https://www.denx.de/wiki/U-Boot Konfiguracja przygotowana przez yocto startuje więc u-boota, który dopiero uruchamia właściwego Linux-a. W kolejnych wpisach pokażę do czego się to może przydać - wspomnę tylko że możliwości są spore, a przede wszystkim możliwe jest pobieranie obrazu przez sieć. Więc karta SD może być używana jedynie na początku uruchamiania systemu, podczas gdy wszystkie pliki przechowamy bezpiecznie na serwerze lub stacji roboczej.
Tablica liderów jest ustawiona na Warszawa/GMT+02:00
×
×
  • Utwórz nowe...