Skocz do zawartości

TPReal

Użytkownicy
  • Zawartość

    19
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    2

TPReal wygrał w ostatnim dniu 28 października

TPReal ma najbardziej lubianą zawartość!

Reputacja

51 Bardzo dobra

O TPReal

  • Ranga
    2/10

Informacje

  • Płeć
    Mężczyzna
  • Lokalizacja
    Warszawa
  • Języki programowania
    Ruby, Rust
  • Zawód
    Programista

Ostatnio na profilu byli

83 wyświetleń profilu
  1. @spook O kurczę, to faktycznie miałem trochę szczęścia. Testowałem przez HAT i działało, ale na Pi 2, więc bym faktycznie się zdziwił że mi nie działa na Zero. Natomiast jeżeli przyczyną problemów jest podpięcie zasilania 5V, to chyba nie chodzi o wydajność prądową, bo piny 5V są bezpośrednio połączone ze źródłem zasilania Pi, więc można z nich brać duży prąd o ile tylko zasilacz tyle daje (no, 5A bym nie polecał, ale 0.5A spokojnie). Do tego na stronie piszą że moc jest 38mW przy 3.3V..5V, to wychodzi jakieś 12mA. Więc w sumie nie rozumiem na czym polega problem. Przyjemnie wygląda ta twoja rameczka
  2. Jeszcze jeden projekt, na razie to ostatni, bo tym sposobem opisałem już wszystkie moje ukończone projekty a kolejne są dopiero w fazie pomysłów.
  3. Jeszcze jeden mały projekt z diodami RGB. Jest to mała lampka nocna zrobiona dla mojej córki. Sprzęt Lampka posiada pięć diod WS2811, pokrętło z przyciskiem i jeszcze jeden przycisk, wszystko polutowane na płytce uniwersalnej. Procesorem jest Seeeduino Xiao (czyli najtańsze co znalazłem niewymagające budowania programatora i innych takich rzeczy których nie mam ochoty robić), przyklejone do płytki taśmą dwustronną Dorzuciłem też rezystor i kondensator, tak jak sugerowali w opisie diod. Gałka jest zrobiona z sugru. No i obudowa ze sklejki 3mm. Jakbym miał drukarkę 3D to być może obudowę bym wydrukował, ale nie mam, a uważam że efekt nie jest najgorszy. Oprogramowanie Lampka ma kilka trybów pracy: W trybie podstawowym wszystkie diody świecą na ten sam kolor, gałką wybiera się kolor (hue) oraz jasność (naciśnięcie gałki przełącza pomiędzy tymi dwoma parametrami). Jest też trzeci parametr, określający saturation tak z grubsza, żeby go regulować trzeba długo nacisnąć gałkę. Regulacja jasności próbuje na mniej więcej odwzorować postrzeganie jasności przez człowieka, czyli nie jest liniowa od 0 do 255 (w przestrzeni RGB), tylko im niższa, tym wolniej zmienia jasność, a przy bardzo niskich ustawieniach jasność jest ułamkowa, przykładowo jasność 2.4 uzyskuję świecąc dwiema diodami z jasnością 3 i trzema z jasnością 2. Więcej o charakterystyce w sekcji poniżej. Tryb automatycznego przyciemniania - podobny jak poprzedni, ale jasność diod samoistnie maleje, z założenia w takim tempie jak oko dostosowuje się do ciemności. Ten tryb służy do włączenia zaraz po zgaszeniu światła. Tryb tęczy - po diodach przesuwa się cyklicznie "tęcza" hue. W tym trybie można regulować czterema parametrami: jasnością, szybkością przesuwania, saturation oraz rozpiętością. Ten ostatni parametr określa jaką długość łuku hue pokazują diody w każdym momencie. W ustawieniu maksymalnym (zdjęcie powyżej) suma kolorów diod jest zawsze biała, co widać dobrze gdy patrzy się na sufit pokoju - jego kolor się nie zmienia, natomiast przy niskich ustawieniach jest istna dyskoteka, bo wszystkie diody mają w danym momencie podobny kolor, ale zmienny w czasie. Sumowanie RGB (pierwsze zdjęcie poniżej): pierwsza dioda świeci na czerwono, druga na zielono a trzecia na niebiesko, reguluje się niezależnie siłą każdej z nich, a ostatnia świeci sumą tych kolorów. Sygnalizator świetlny, przełącza kolejno światła, samoistnie albo po naciśnięciu przycisku. Wyłączona. Tryby przełącza się przytrzymując dodatkowy guzik i kręcąc gałką. Samo sterowanie diod wygląda (mniej więcej) następująco: WS2812::WS2812(byte pin): pin(pin), portGroup(digitalPinToPort(pin)), pinBitMask(digitalPinToBitMask(pin)){ pinMode(this->pin,OUTPUT); } void WS2812::writeLEDs(const std::vector<RGB>& leds){ noInterrupts(); for(auto led=leds.begin();led!=leds.end();led++) writeLED(*led); interrupts(); } void WS2812::writeLED(const RGB& led){ this->writeByte(led.r); this->writeByte(led.g); this->writeByte(led.b); } void WS2812::writeByte(byte b){ writeBit(b&0x80); writeBit(b&0x40); writeBit(b&0x20); writeBit(b&0x10); writeBit(b&0x08); writeBit(b&0x04); writeBit(b&0x02); writeBit(b&0x01); } void WS2812::writeBit(byte b){ if(b) write1(); else write0(); } void WS2812::write0(){ up(); up(); down(); down(); } void WS2812::write1(){ up(); up(); up(); up(); down(); } void WS2812::up(){ portGroup->OUTSET.reg=pinBitMask; } void WS2812::down(){ portGroup->OUTCLR.reg=pinBitMask; } Uwagi: Muszę używać OUTSET i OUTCLR, bo digitalWrite jest za wolne. Liczba powtórzeń w write0 i write1 została wyznaczona eksperymentalnie, z użyciem oscyloskopu. Mógłbym zamiast powtarzać funkcję dodać tam jakąś dobrze skalibrowaną pustą pętlę wykonującą się n razy, ale tak mi było prościej i jest dostatecznie dobrze. Charakterystyka diod Tak jak wspomniałem, chciałem, żeby regulacja jasności wyglądała na liniową, co jak wiadomo oznacza, że taka nie jest. Robiłem sporo pomiarów jasności diod i długo się grzebałem w excelu, i ustaliłem taką oto funkcję przeliczającą level od 0 do 50 na jasność od 0 do 1 (przeliczaną następnie już liniowo na wartości RGB: float levelToLight(float level){ if(level<=15) return max(78e-5*level,0); if(level<=34) return 22e-4*pow(1.117,level); return min(55e-6*pow(1.221,level)+47e-3,1); } Nie żebym sądził, że się komuś ta funkcja przyda ale w każdym razie działa dość dobrze. Dzięki temu, że do 15 jest liniowa, od RGB(0,0,0) do RGB(3,3,3) ustawia się jasność z dokładnością do 0.2/255, co się w sam raz tłumaczy na wzmacnianie kolejno diod w trybie podstawowym. Powyżej 15 zmiany są coraz szybsze, na przykład przy wartości 16 trzy diody świecą RGB(3,3,3) a dwie RGB(4,4,4), a przy 17 już tylko jedna RGB(3,3,3) a cztery RGB(4,4,4) - oczywiście jeśli aktualnie wybranym kolorem jest biały. Niestety, dla wartości RGB 1 i 2 diody zachowują się ekstremalnie nieliniowo, mianowicie przy wartości 1 świeci tylko składowa G, a R oraz B w ogóle nie świecą, a z kolei przy wartości 2, G chyba świeci tak samo jak przy 1, a R i B robią się dużo jaśniejsze, przy czym R jaśniejsza od B. Na ostatnim zdjęciu widać też, że są różnice pomiędzy samymi diodami, mimo że były kupione razem - druga i czwarta wydają się bardziej czerwone. Wszystkie anomalie występują tylko przy niskich wartościach, przy wysokich świecą równo, albo w każdym razie gołym okiem nie widać między nimi różnicy. Ogólnie w porównaniu z diodami użytymi w tym projekcie, te tutaj dla niskich jasności są po prostu tragiczne - ale na lampkę dla dziecka nadają się w sam raz Ale w niektórych trybach, na przykład tęczy, nie pozwalam na zbytnie obniżenie jasności, bo efekt przestaje dobrze wyglądać.
  4. Specyfikacja e-INK, przynajmniej tych Waveshare, jest, oględnie mówiąc, straszna. Różne ekrany mają różne sekwencje startowe (właściwe kolejności wysyłania komend), przykładowe programy wysyłają komendy w innej kolejności niż opisuje specyfikacja, a wśród nich komendy o kodach, które w ogóle się w specyfikacji nie pojawiają, struktura LUT jest w ogóle nieudokumentowana (patrz mój post wyżej w tym temacie), różne struktury buforów obrazu, kolory faktyczne inne niż w specyfikacji, i sporo innych quirków, na które trafiłem (a nie przejrzałem nawet wszystkich specyfikacji ani przykładowego kodu wszystkich ekranów, tylko kilku). Pisanie uniwersalnego emulatora tych ekranów brzmi mi jak dobre zadanie dla potępionych dusz w piekle Jak chodzi o kod, no cóż, wystarczy mi że w pracy ludzie patrzą na cały kod, który napiszę To, co piszę prywatnie, na razie zostawię dla siebie. Chyba że jesteś zainteresowany jakimś konkretnym kawałkiem logiki czy czymś.
  5. @piotr-jarosz Hej, dzięki! Tak jak napisałem, ja składam obrazek tekstowo w SVG, potem wyciągam piksele przez imagemagick. Zamiast tego można skonwertować ten SVG na PNG i podejrzeć, ja to sobie tak emulowałem. Nie radzę podgladać SVG bezpośrednio bo imagemagick ma trochę biedny ten renderer i można się potem zdziwić że inaczej wychodzi. Co do kodu... chyba nie jestem jeszcze gotowy na to, żeby ktoś go oglądał
  6. Natrafiłem na problem z dodawaniem niektórych zdjęć. Mianowicie chodziło o zdjęcia pobrane z Google Photos, które miały układ pionowy. Wyświetla się wtedy komunikat "Wystąpił błąd podczas przetwarzania przesłanego pliku. -200". W załączniku przesyłam zdjęcie powodujące ten problem. Co ciekawe, po edycji tego zdjęcia w Google Photos, na przykład kadrowaniu (tak że nadal jest pionowe), ale chyba również po na przykład zmianie jasności, i ponownym pobraniu, zdjęcie przechodzi. img_err.zip
  7. @KHX Bo Ruby to jest w ogóle świetny język chociaż jak widać nie równie świetny do wszystkiego. A Rust chyba powoli przestaje być "mniej popularny". Taką mam obserwację: program w Ruście wykonuje się oczywiście dużo szybciej, ale za to kompiluje się masę czasu, i w rezultacie iteracje polegające na małej zmianie w kodzie i uruchomieniu robi się duużo szybciej w Rubym. Potem trochę to poprawiłem bo ogarnąłem cross-kompilację i kompiluję dla Pi Zero na innym urządzeniu, ale nadal iteracje programu w Rubym są znacznie szybsze.
  8. @ewraw Dzięki Ten konkretnie ekran to przestarzały model, już nie sprzedawany, a niestety w każdym modelu mnóstwo rzeczy jest inaczej. Postudiowałem trochę datasheety kilku modeli Waveshare i wyglądają jakby je w dużej mierze robiły zupełnie osobne zespoły. Niektóre mają osobny bufor na obraz czarny a osobny na czerwony, a inne mają jeden bufor, 3 bity na piksel, i w tym każdy kolor ma inny kod, ale żaden z tych bitów nie steruje bezpośrednio czerwonym. Poza tym jest coś co się nazywa LUT, to jest dokładna instrukcja dla ekranu jak ma migać napięciami w ekranie żeby ustawić piksel na określony kolor. Niektóre ekrany mają osobną sekwencję LUT na kolor czarny, biały, szary i czerwony, a inne pamiętają co wyświetlały poprzednio i mają osobną sekwencję LUT na przejście czarny->biały, czarny->szary itd. Niektóre ekrany mają w sterowniku zapisane sekwencje LUT, a innym trzeba po załączeniu je przesłać, wtedy cała sekwencja (kilkadziesiąt bajtów) jest po prostu zapisana w datasheecie i trzeba ją wysłać po SPI. Widziałem że niektórzy też dali radę pohackować trochę, i podmieniali LUT na własny, dzięki czemu ekran smużył, ale na przykład odświeżał się w pół sekundy zamiast 15 sekund. A na koniec warto też pamiętać, że w tych datasheetach jest masa błędów. Przechodząc do rzeczy, w załączniku wrzucam datasheet tego konkretnego ekranu, który miałem, i na stronie 14 jest opisany format bufora. Są trzy bity na piksel i opisane są tam 2 kolory szare i 4 czerwone. To nie jest prawda, nie wiem dlaczego ale trzy z tych czerwonych są identyczne jak szary, czarny i biały, natomiast te dwa szare są identyczne ze sobą. Prawdopodobnie jest tak po prostu dlatego, że wgrany w sterownik LUT dla tych sekwencji tak wygląda, jest na przykład identyczny dla tych dwóch szarych. A jako że nie znalazłem nigdzie pasującego opisu samego formatu LUT, nie umiem tego zmienić, chociaż na pewno się da (bo ten ekran ma w sterowniku zapisany LUT, ale można też wgrać własny). W każdym razie nie korzystałem z żadnej gotowej biblioteki do tego ekranu tylko napisałem swoją na podstawie datasheeta oraz czytania masy różnego kodu, i wtedy szary uzyskuje się dość łatwo. To jest ten szary którym wyświetlam pasy pokazujące gdzie jest noc na wykresie. Ale zrobiłem też sobie inny szary, użyty na przykład do narysowania przeszłej części wykresu, który jest po prostu szachownicą pikseli czarnych i szarych. Repozytorium demo, z którego najbardziej korzystałem, jest tutaj, nie jestem teraz pewien który to był z tych "7in5", ale to da się wywnioskować po rozdzielczości. Jest tam też kod w Pythonie, ale... różni się pewnymi szczegółami. Natomiast ta funkcja EPD_xxx_Display być może akceptuje jakieś odcienie szarości, bo w tym buforze może być więcej niż jeden bit na piksel. Wszystko zależy od ekranu 7.5inch_e-paper-b-Specification.pdf
  9. Zrobiłem ostatnio mały projekt z Raspberry Pi i diodami RGB. Sprzęt Dwa pierścienie po 24 diody (ten i ten) nakleiłem na okrągły kawałek kartonu, na środek dałem pojedynczą diodę (tę) a po przeciwnej stronie przykleiłem Raspberry Pi Zero WH (akurat miałem wersję z wlutowanymi złączami, co w tej sytuacji tylko utrudniało). Znalazłem informację, że piny +5V w Pi są połączone bezpośrednio do zasilania, więc można z nich bezpiecznie ciągnąć duży prąd, więc zasiliłem z nich diody, a jednego pinu użyłem do ich sterowania (diody WS2811 łączy się szeregowo i steruje dowolną ich ilością z pojedynczego pinu protokołem podobnym do 1-wire). Teoretycznie pin sterujący powinien pracować z napięciem 5V, a nie 3.3V, ale w praktyce nie zauważyłem żadnych problemów z tym związanych. Zegar miał z założenia wisieć w sypialni i być użyteczny również do sprawdzania czasu w nocy, więc potrzebowałem elementu światłoczułego żeby dostosowywać jasność diod. I to nie jednobitowego (ciemno/jasno), tylko "analogowego". Akurat nie miałem odpowiedniego modułu, więc użyłem konstrukcji z kondensatorem i rezystorami, jak na schemacie (na zdjęciu fotorezystor jest po lewej stronie, przy kablu). Logika sprawdzania poziomu światła jest następująca: Ustawiam pin na output, stan niski. Zajmuję się innymi rzeczami, na przykład sterowaniem diodami, w tym czasie kondensator się rozładowuje (nie całkiem do zera, bo rezystory działają jako dzielnik napięcia). W chwili t0 ustawiam pin na input (bez pull up/down). W pętli odczytuję jego stan. Najpierw stan jest niski, ale po chwili gdy kondensator się naładuje do około 1.5V na pinie pojawia się stan wysoki, wtedy przerywam pętlę. Sprawdzam ile czasu minęło od t0. Czasy, które otrzymuję, wahają się od około 40μs gdy jest bardzo jasno do nawet ponad 100ms w zupełnej ciemności (nie czekam dłużej niż te 100ms, stwierdzam po prostu, że jest zupełnie ciemno). Nie wątpię, że ten układ mógłby być zrobiony lepiej, bardziej liniowo, z mniejszą liczbą elementów (na przykład pewnie dałoby się wykorzystać rezystory pull up i pull down z Pi), ale ten działa dobrze i skutecznie. Jak mówiłem, wymóg był taki, że ma się to nadawać do ciemnego pokoju, więc w zupełnej ciemności ma świecić bardzo słabo, tak żeby nie razić i nie rozświetlać pokoju. Okazało się, że nawet na minimalnej jasności te diody są znacznie za jasne, więc przykryłem je dwiema warstwami papieru z bloku technicznego i jeszcze kawałkiem materiału, i dopiero wtedy jasność jest mniej więcej taka, jak potrzeba, chociaż szczerze mówiąc rozważam dodanie trzeciej warstwy papieru. Niestety trudno zrobić ładne zdjęcie tych diod, zawsze wyglądają inaczej niż w rzeczywistości, na przykład mają jakby mocniejsze halo naokoło siebie i wydają się prześwietlone. Na zdjęciach jest godzina około 6:26, na tym dziennym akurat sekundnik zasłonił wskazówkę minutową. W trybie nocnym sekundnik jest wyłączony, podobnie jak niebieskie "kreski" naokoło tarczy. A następnie zdarzył się cud, po prostu trudno w to uwierzyć, ale kupowałem coś na allegro i przeglądając inne przedmioty sprzedającego trafiłem na tarczę ze starego zegara w kształcie pierścienia o dokładnie odpowiedniej średnicy wewnętrznej, z dokładnością do jakichś 2mm. Powiem szczerze, teraz bez tej tarczy zegar wygląda mi dość łyso i nieciekawie. Po prostu przeznaczenie Oprogramowanie Program napisany jest w języku Rust. To był mój pierwszy program w tym języku, wybrałem go bo mnie zaciekawił i chciałem się go nauczyć, oraz ponieważ Ruby, w którym robiłem poprzednie projekty na Pi, okazał się trochę za wolny na sterowanie diod RGB - objaśnienie poniżej. (Tak w ogóle - polecam Rusta, bardzo przyjemny, chociaż ma pewien próg wejścia. Utwierdził mnie tym bardziej w moim i tak już silnym postanowieniu nie tykać więcej C++ jeśli tylko nie trzeba.) Do wysterowania diod trzeba nadać na pinie sterującym sekwencję 24 bitów RGB dla każdej diody po kolei, protokołem przypominającym 1-wire. Polega to na tym, że nadanie każdego bitu trwa 1.25μs i polega na ustawieniu pinu w stan wysoki, a następnie w stan niski, przy czym jeśli nadaję bit 0 to stan wysoki ma trwać około 300ns, a jeśli bit 1, to ma trwać około 700ns. Dioda działa tak, że pierwsze 24 bity odczytuje i zapamiętuje dla siebie, a wszystkie dalsze sygnały wysyła do kolejnych diod, więc naprawdę można w ten sposób wysterować dowolnie wiele diod z jednego pinu, tyle że wysłanie pełnego stanu będzie trwało dłużej gdy diod jest więcej. Wreszcie stan niski przez 50μs oznacza, że sekwencja się zakończyła. Szczerze mówiąc jestem pod wielkim wrażeniem prostoty tego protokołu. Tak szybka zmiana stanów pinu mogłaby być trudna nawet w Ruście, ale znalazłem gdzieś w internecie opis innego podejścia, i je zastosowałem. Ustawiam PWM (wbudowany w BCM2835) w tryb serializera, w którym przez pin wysyłane są konkretne podane przeze mnie bity. Ustawiam częstotliwość na trzy razy wyższą, a więc 2.4MHz (=1/1.25μs*3), i żeby wysłać bit 0, wysyłam sekwencję trzech bitów 100, a żeby wysłać bit 1, wysyłam sekwencję 110. Dane do serializera w BCM2835 ładuje się przez FIFO o pojemności chyba 16 słów po 4 bajty, więc najpierw przygotowuję całą sekwencję do wysłania, już przerobioną na ten 1-wire, a potem w pętli czekam aż FIFO jest not full i wpisuję kolejne słowo. I właśnie tego nie dawało się zrobić w Rubym - był za wolny, i pomiędzy nadanymi słowami pojawiały się przerwy, a przerwa 50μs powoduje przerwanie sekwencji. Mógłbym być może pocisnąć tę drogę dalej, nie używać biblioteki, którą miałem, tylko bardziej bezpośredniego dostępu do rejestrów BCM2835, ale zamiast tego uznałem to za pretekst do nauczenia się Rusta, i dobrze wyszło. Sama logika ustalania pozycji wskazówek jest dość prosta. Wskazówki przesuwają się płynnie, to znaczy sekundnik tak jakby pełznie, stopniowo rozświetlając kolejną diodę i wygaszając ostatnią, pozostałe wskazówki, gdy mają się przesunąć, również wykonują stopniową tranzycję Oczywiście zegar nie pokazuje dokładnej minuty, okręgi mają po 24 diody, więc każda pozycja długiej wskazówki odpowiada okresowi 2.5 minut, co zazwyczaj zupełnie wystarcza. Stan diod obliczam i wysyłam w pętli, czekając 50ms pomiędzy powtórzeniami, więc ruch jest płynny. Oczywiście nie wtedy, gdy jest ciemno, i diody świecą z minimalną jasnością - wtedy przejścia siłą rzeczy są skokowe. Ze światłomierzem z telefonu naszkicowałem zależność ilości światła od wartości wpisanej na diodę (nawet w miarę liniowy), potem przyjąłem, że percepcja jasności jest mniej więcej wykładnicza, potem wykonałem jeszcze dużo różnych operacji na wartości odczytanej z tego mojego układu pomiaru światła (bardzo nieliniowego), z pewną ilością magicznych stałych, i o dziwo uzyskałem dość dobry rezultat. Zegar wydaje się zwykle świecić w sam raz tak jak trzeba. Problemy z wywłaszczaniem Od początku miałem następujący problem: co któryś wysłany stan diod wyświetlał się błędnie. Wyglądało to jakby występowały zakłócenia obrazu, jakby na przykład był obrócony w inną stronę, albo kolory były w ogóle nie takie, jak trzeba. Takie zakłócenia pojawiały się nawet kilka razy na minutę, i zaraz następna wysłana klatka je korygowała, ale wyglądało to źle i drażniąco. Z użyciem mojej pokazywaczki Hantek ustaliłem, że taka uszkodzona sekwencja dla diod ma po prostu gdzieś w środku przerwę, trwającą na przykład 120μs. To powoduje, że reszta sekwencji jest traktowana jako nowa sekwencja, więc wyświetla się nie na tych diodach, na których powinna. Po dalszych badaniach doszedłem do wniosku, że czasami nawet w Ruście pętla ładująca dane do FIFO okazuje się za wolna. Pierwsze co zrobiłem, to zmieniłem logikę tej konwersji na 1-wire tak, żeby granica pomiędzy nadawanymi słowami była jednocześnie granicą pomiędzy logicznymi nadawanymi bajtami. Innymi słowy, każdy bajt kodowany jest w postaci 24 bitów złożonych z trójek 100 lub 110, a pozostałe 8 bitów słowa wypełniam zerami (protokół nie ma z tym problemu, pewnie mógłbym też kodować każdy bit na 4 bitach). Dzięki temu jeśli nawet zdarzy się uszkodzona ramka, to uszkodzenie może polegać na tym, że zapalą się inne diody i na inne kolory, ale z tą samą siłą, z którą miały się oryginalnie palić. Dzięki temu uszkodzone ramki są znacznie mniej drażniące. Wcześniej słowo daję, że przynajmniej z 5 razy pomyślałem że coś mi iskrzy, gdy nagle któraś dioda w uszkodzonej ramce zaświeciła bardzo jasno. No ale to nie jest prawdziwe rozwiązanie. Domyśliłem się, że przyczyną problemu są po prostu wywłaszczenia. Raspberry Pi OS nie jest systemem czasu rzeczywistego i nie mam żadnej gwarancji, że mój program będzie miał spokój w czasie wysyłania sekwencji. To, co zastosowałem poza tym, to uruchomienie mojego programu tak: chrt --fifo 99 clock To zmienia jakieś scheduling policy i teoretycznie powinno zapobiegać wywłaszczaniu. O ile widzę w /proc to wywłaszczeń faktycznie jest dużo mniej, ale nie zero, natomiast zegar działa praktycznie dobrze. Uszkodzone ramki zdarzają się bardzo rzadko, myślę że raz na godzinę lub rzadziej. Wolałbym gdyby tak nie było, ale mogę to zaakceptować. Innym możliwym rozwiązaniem byłoby sprawdzanie czy "gap occurred", bo teoretycznie PWM wystawia taką informację, ale w praktyce chyba coś tam nie działa dobrze, bo zwykle ten bit nie jest ustawiony, nawet gdy widzę na oscyloskopie że przecież occurred. Jeszcze inne to przydzielenie dedykowanego rdzenia procesora do tego procesu, tyle że Pi Zero ma tylko jeden rdzeń... Można by też oczywiście dodać mikroprocesor, wysyłać do niego dane po SPI, a on sterowalny diodami, ale tego jakoś nie chciało mi się zrobić. Jeżeli ktoś z czytelników ma jakiś inny pomysł na poprawienie tego, to chętnie posłucham Możliwy dalszy rozwój Zegar mógłby oczywiście wyświetlać jeszcze jakieś inne obracające się tęcze, animacje, buźki i wodotryski. Mam trochę poczucia, że on nie wykorzystuje w pełni potencjału diod RGB. Tylko że póki co nie mam jasnej idei co konkretnie chciałbym tam wyświetlić i kiedy, więc to pozostaje póki co w sferze luźnych planów.
  10. @Gieneq Dzięki. Nie mam pojęcia, ale podejrzewam że trudno będzie znaleźć dokumentację do takiego wymontowanego ekranu niewiadomej marki. Ale pewnie można popróbować.
  11. @KHX To był ten, już niedostępny, ale cena 319zł, i tak jakoś podobnie dałem. Te najmniejsze (z modułem) są poniżej stówy: sklep.
  12. @ethanak Akurat Python jest na mojej liście nie tykać tego nawet kijem (chyba że nie ma innego wyjścia), ale widzę że do Rubiego też ktoś napisał bibliotekę do obliczania zachodów słońca. Akurat najpierw przyszło mi do głowy pobranie tego, bo i tak miałem z innego projektu gotową logikę pobierania danych. I oczywiście przewidziałem że może nie działać sieć, i rozwiązałem ten problem. Wymyślenie rozwiązania pozostawiam jako ćwiczenie dla czytelnika. Jak piszę że od dwóch miesięcy działa, to chyba jednak jest użyteczny, nie? Tyle że pewnego dnia może się okazać że z losowych przyczyn przestanie dociągać, i wtedy trzeba będzie coś przebudować. Ale to nie samolot pasażerski, niczyje życie nie zależy od tego, żeby działało idealnie. No i radzę sobie dobrze bez krańcówki. Jeśli dajmy na to przy rozsuwaniu na końcu zgubi parę kroków, to przy zasuwaniu, gdy zasłona będzie całkiem zasunięta, zgubi tyle samo kroków i się wyrówna. To samo jeśli padnie zasilanie (zresztą aktualną pozycję zrzucam do pliku co dwie sekundy w czasie ruchu, właśnie po to żeby błąd nie był duży nawet w tej sytuacji). Właśnie dzięki temu, że silnik nie ma dużego zapasu momentu, wiem że zgubi kroki, a nie na przykład zerwie listwę z sufitu. To dość wygodne. A jakbym zastosował silnik z przekładnią to być może musiałbym mieć krańcówkę.
  13. Przedstawiam projekt, który ma dla mnie ogromne zastosowanie praktyczne - budzi mnie rano w miarę bezboleśnie, ale dość skutecznie, odsłaniając zasłony w sypialni. Mechanika Zasłony wiszą na standardowej szynie KS biegnącej od ściany do ściany, z zasłoną odsłaniającą się na dwie strony. Pierwszym krokiem projektu było puszczenie wewnątrz szyny sznurka nylonowego w tę i z powrotem, i przywiązanie do niej we właściwych miejscach dwóch żabek/haczyków - skrajnego lewego prawej zasłony, i skrajnego prawego lewej. Oczywiście jeden do sznurka biegnącego w szynie "w tę", a drugi do sznurka biegnącego "z powrotem". Następnie oba końce sznurka przepuściłem przez haczyk i spuściłem po ścianie na dół. Wtedy ciągnięcie jednego końca zasłania, a drugiego odsłania obie zasłony razem. Powiem szczerze, ten etap był najtrudniejszy. Wymagał dużo dokładności żeby zasłony zbiegały się we właściwym miejscu, wiele starań żeby nic się nie plątało i chodziło odpowiednio lekko, a do tego wiele stania na drabinie z rękami do góry. Następnie jako napęd wybrałem silnik krokowy 0.43Nm. Nie mam doświadczenia z projektami z silnikami, i podejrzewam, że to nie był optymalny wybór, i lepszy byłby być może silnik z przekładnią i enkoderem. No cóż użyłem silnika krokowego, i wszystko w miarę działa, ale silnik nie ma zapasu momentu obrotowego. Do wału silnika przymocowana jest rurka aluminiowa, na którą nawija się sznurek. Nie ma naciągu, ale luz jest na tyle mały, a sznurek na tyle śliski, że nic się nie plącze. Silnik jest zamocowany do ściany drewnianą obejmą, którą sobie wyrzeźbiłem. Silnik podłączony jest do sterownika, a komputerem sterującym jest Raspberry Pi Zero, tym razem bez "W" bo to był początek lockdownu i Raspberry Pi Zero W trudno było dostać. Pi ma więc wpiętego na stałe dongla wifi, ale to nie problem bo i tak tego projektu nie przenosi się z miejsca na miejsce, z oczywistych względów. Do Pi podłączony jest również czujnik światła przyklejony do okna i wykierowany na zewnątrz, a także mały panel sterowania z dwoma przyciskami i dwiema diodami. W bardziej ukrytym miejscu jest jeszcze trzeci guzik, używany do czynności serwisowych. Układ nie ma obudowy, ale raczej nie będzie jej miał - nie jest potrzebna bo układ nie jest widoczny z pokoju, zasłania go zasłona, wystaje tylko panel kontrolny. Oprogramowanie Program napisany jest w Rubym. Ruby jest fajny, ale szczerze mówiąc w tym przypadku to mógł nie być najlepszy wybór, a to dlatego, że Ruby jest wolny, a tymczasem potrzebuję generować sygnały STEP do sterownika silnika z częstotliwością około 200Hz. Przy użyciu biblioteki, którą mam, ta wartość jest blisko limitu, gdybym chciał generować 300Hz to musiałbym już zmienić technologię, albo co najmniej bibliotekę. Jednocześnie nie mogłem użyć wbudowanego generatora PWM, bo nawet przy maksymalnym dzielniku byłby za szybki. Musiałbym jeszcze zlutować jakiś dzielnik częstotliwości, a nie miałem na to ochoty. No, ale ostatecznie tak mniej więcej daje radę - jak wiele rzeczy w tym projekcie. Sama logika jest właściwie dość prosta. Uruchamiam dwa wątki, jeden w pętli odczytuje naciśnięte przyciski, zapala diody kiedy trzeba itp, a drugi w niezależnej pętli generuje kroki, chyba że pozycja zasłony jest równa pozycji zadanej. Pozycja zasłony nie jest mierzona, tylko po prostu obliczana na podstawie zliczania kroków. Sterowanie: Przyciski góra i dół odsłaniają i zasłaniają zasłonę ręcznie. W czasie pracy świeci się żółta dioda (a mogłem użyć lampę bramową...). W czasie gdy zasłona pracuje, można ją też zatrzymać przyciskiem. Poza tym zasłona uruchamiana jest automatycznie: Odsłaniana jest o godzinie pobranej z pliku konfiguracyjnego. Można ustawić odsłanianie po kawałku. Moment zasłaniania określany jest następująco: z openweathermap.com pobieram godzinę zachodu słońca, i dwie godziny wcześniej (konfigurowalne) zaczynam monitorować czujnik zmierzchowy. Zasłaniam gdy zrobi się ciemno za oknem, lub najpóźniej pół godziny (konfigurowalne) po zachodzie słońca. Tak, wiem że godzinę zachodu słońca można obliczyć zamiast pobrać, ale jak zobaczyłem ten wzór to stwierdziłem, że pobrać będzie sporo łatwiej. Przy użyciu trzeciego przycisku można też aktywować funkcje dodatkowe: wyłączenie/włączenie automatycznego zasłaniania/odsłaniania, korekty na wypadek gdyby zasłona się zablokowała w czasie ruchu (co się póki co nie zdarza, chyba że ma coś na drodze), i najlepsze: funkcja drzemki. W znaczeniu "drzemki poobiedniej", a nie opóźniania budzenia. Ustawiam drzemkę na wielokrotność 15 minut, zasłony się zasłaniają, a po zadanym czasie się odsłaniają. Proste, a bardzo fajne. Przykładowy plik konfiguracyjny: { "location": {"lat": 0.00, "lon": 0.00}, "openweathermap_api_key": "000000", "close_on_sunset_offset_min": { "min": -120, "max": 30 }, "alarm": { "normal": { "8:30": {"value": 0.5, "dir": 1}, "8:55": 1 }, "holiday": { "9:00": {"value": 0.5, "dir": 1}, "9:30": 1 } } } Filmik Podsumowując, ten projekt doskonale spełnia swoją funkcję, budząc mnie co rano już ponad dwa miesiące, i nie sprawiając problemów. Niemniej jednak jest trochę rzeczy, które zrobiłbym inaczej gdybym musiał to robić drugi raz, tak jak pisałem powyżej. Można by też było dodać na przykład integrację z jakimś systemem inteligentnego domu, ale mi na tym nie zależy, bo takiego systemu nie mam i raczej nie planuję. Jeszcze jedno proste potencjalne usprawnienie - zasilać Pi z tego samego zasilacza, co silnik, a nie z osobnego. Nie wiedziałem jak to prosto zrobić, dlatego jest jak jest.
  14. @ethanak Najpierw myślałem stablicować święta, ale ja po prostu lubię jak rzeczy działają automatycznie I tak już miałem kod do pobierania JSONa (do pogody), calendarific jest darmowe, więc to nie był żaden problem pobierać stamtąd. Poza tym w ten sposób w konfiguracji podaję kraj dla którego chcę święta, i gotowe. Gdybym się kiedyś przeprowadził do innego kraju to wystarczy zmienić w konfiguracji lokalizację do pogody i właśnie kraj do świąt bez zmian w repo. No albo gdyby ktoś gdzieś chciał zbudować sobie taką samą ramkę z mojego kodu... ale to się nie wydarzy, bo kod nawet nie jest obecnie publiczny.
×
×
  • Utwórz nowe...