Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'Arduino'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie

Kategorie

  • Quizy o elektronice
  • Quizy do kursu elektroniki I
  • Quizy do kursu elektroniki II
  • Quizy do kursów Arduino
  • Quizy do kursu STM32L4
  • Quizy do pozostałych kursów

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Imię


Strona

  1. Cześć, niedawno zacząłem budowę łazika z napędem na 6 kół (każde z nich skrętne, stąd 6 serw), całość będzie drukowana w 3D i sterowana przez Arduino Uno. Podczas projektowania obwodu napotkałem problem dotyczący zasilania, poniżej wklejam schemat (bez połączenia przewodów sygnałowych do L298N). Silniki to mocniejsze odpowiedniki tych małych żółtych silników. Producent podaje napięcie 3V-6V (sam myślałem żeby je troszkę zwiększyć, ponieważ w moim układzie będą dość mocno obciążone) a pobór prądu to (przy zatrzymanym wale) do 1,2A. Dlatego wybrałem takie sterowniki. Serwa to Tower Pro MG90S (są to serwa typu micro). A do sterowania całością planuję użyć Arduino Uno. I tu pojawia się problem ponieważ L298N mają spadek napięcia 2V. Więc akumulator/bateria 6V odpada. Myślałem nad tym żeby serwa osobno były zasilane z 4x AA. A silniki z 6x AA. Tylko czy z takich 6 baterii można pobrać max ok. 7A. A z 4 do ok. 5. Do silników można było by użyć też jakiś ogniw, takich jak np. w bateriach do laptopów. Pozostaje jeszcze zasilanie Arduino. Jak wy byście to rozwiązali? Mnie najbardziej przekonują baterie. Z góry dziękuje za pomoc Filip
  2. Cześć, z zawodu jestem alpinistą przemysłowym i pracując na konstrukcji (ścierając kurz ) z racji już średniego wieku stwierdziłem, że będzie mi łatwiej, przyjemniej i ciekawiej jeżeli pomogę sobie jakimś pojazdem zdalnie sterowanym :). W sprawach elektroniki jestem raczej zielony, ale zacząłem i w miarę upływu czasu okazuje się, że można, i jest jakiś mglista szansa, że mi się uda :). Mózgiem operacji jest płytka PWM UNO, pojazd gąsienicowy z 2-ma silnikami 12V(chińskimi-brak jakichkolwiek informacji o prądzie maksymalnym). Sterownik silników to L293d, moduł bluetooth to HC-05. Sterowanie z komórki. Pojazd ma się poruszać po wąskiej konstrukcji ~20cm szerokości, która nachylona jest pod kątem +-45 stopni do poziomu, dlatego używam też magnesu pod spodem oddalonego o jakieś 5 mm od "gruntu". Magnes powoduje, że będę potrzebował sporej mocy, żeby poruszać się łazikiem. I tak rzeczy, o których wiem, że nie są ok to : 1. Sterownik silników powinien być ( w mojej ocenie ) mocniejszy-choć ten się jeszcze nie spalił, ale nie chcę ryzykować i chciałbym kupić inny ( pytanie jaki?) 2. Moduł bluetooth powinien przechodzić przez około 3,5V, u mnie jest 5V, ale nic się nie dzieje. 3. Kod jest bardzo toporny i mi się nie podoba 🙂 ale póki mi działa też się tym nie przejmuję. Nie radzę sobie z : Sytuacją, w której z jakiegoś powodu tracę połączenie z łazikiem, nie chcę żeby stanął i się zrestartował. Chciałbym też zamontować prosty wskaźnik (czerwoną diodę) do sygnalizacji spadku napięcia poniżej pewnego progu (potencjometr dioda i rezystor wystarczą?) Zasilanie- póki co 2 akumulatory połączone szeregowo 7,4V x 2. Na jednym też działa. Chciałbym nie przesadzić, wiem że jest spadek napięcia na sterowniku ale nie wiem do jakiego napięcia mogę dojść (pewnie już przesadziłem :)) Wszelkie informację o kardynalnych i nie tylko, błędach oczywiście mile widziane- pamiętajcie także, że jestem
  3. Cześć, przedstawiam projekt dla fanów drinków dla których zachowanie proporcji jest niezmiernie istotne. Postanowiłem, że robot będzie nalewał trzy różne substancje (jak na domowego barmana w zupełności wystarczy). Wykorzystałem w tym celu pompki membranowe, które są stosunkowo tanie, jednak warto użyć zaworów zwrotnych przy każdym z węży ponieważ "na postoju" nie są szczelne i ciecze powoli kapią z dysz robota. Przy innym projekcie zdarzyło mi się, że pompka była nieszczelna, więc w tym zamontowałem je w miejscu w którym ewentualny wyciek nie narobi szkód. We wcześniejszych konstrukcjach ustawiałem lanie zależne od zadanego czasu, jednak po testach (wspierając się wagą kuchenną) stwierdziłem, że odmierzane wartości nie są powtarzalne. Wtedy postanowiłem dodać wbudowaną wagę. Użyłem belki tensometrycznej do 1kg oraz wzmacniacza HX711. Robot zasilany jest zasilaczem wtykowym 12V a jego serce to Arduino Mega - ze względu na zapotrzebowanie na dużą liczbę wejść/wyjść. Do sterowania pompek użyłem gotowego Shielda - sterownika L293D – może sterować czterema silnikami DC i zajmuje mało miejsca w obudowie, a chciałem żeby konstrukcja była zwarta i jak najmniejsza. Początkowo użyłem wyświetlacza 2x16, jednak wyświetlane dane nie były tak przejrzyste, jakbym tego chciał więc zamontowałem wyświetlacz 4x16. Teraz każdy składnik ma swoją nieskróconą nazwę i ma swoją osobną linijkę. Wartości danych substancji ustawia się przy pomocy trzech potencjometrów. Wyskalowałem wartość każdego od 0 do 150g. W przypadku przekroczenia sumy trzech substancji powyżej 250g, zamontowane diody RGB świecą na czerwono (jest to tylko sygnał ostrzegawczy, nie blokuje nalewania). Diody te również „ubarwiają” proces tworzenia drinka (efekt widoczny na załączonym filmie). Po ustawieniu ulubionych proporcji wciskamy START i nalewanie odbywa się automatycznie, przed nalaniem każdego składnika waga samoczynnie się taruje. Można również korzystać z manualnego nalewania oraz tarowania, gdy stworzony drink nie spełnia wszystkich wymagań. Obudowę wydrukowałem na drukarce 3D. Składa się z wielu elementów, żeby był łatwiejszy dostęp do podzespołów oraz żeby pojedynczy wydruk krócej się drukował. Umieściłem z jednej strony okno rewizyjne żeby móc się w razie potrzeby podłączyć do Arduino. Części których użyłem do budowy robota: Arduino ATmega2560 - 1szt. wyświetlacz LCD 4x20 - Niebieski - ze sterownikiem kompatybilnym z HD44780 - QC2004A konwerter I2C do wyświetlacza LCD HD44780 wzmacniacz do belki tensometrycznej HX711 - 1szt. belka tensometryczna 1kg - 1szt pompa do cieczy 12V 110l/h - 7mm – 3szt moduł sterownika silnika L293 UNO MEGA shield - 1szt moduł diody RGB 5V - 2szt, wtyk DC 2,1/5,5mm z zaciskami skręcanymi – 1szt. gniazdo DC 2,1/5,5 do obudowy plastikowe -1szt. zasilacz wtyczkowy UMEC impulsowy 12V 30W 2,5A - 1szt. przełącznik kołyskowy 15x10mm – 1 szt przewody połączeniowe przycisk podświetlany - 1szt. przycisk okrągły monostabilny chwilowy czerwony - 4szt. potencjometr liniowy 1K – 3szt. .zawór zwrotny - 3szt. wężyk silikonowy 1,5m Oto kod, z którym się najdłużej męczyłem, ale działa 😉 #include <HX711.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <AFMotor.h> #define I2C_ADDR 0x3F #define start 52 #define manpom1 50 #define manpom2 46 #define manpom3 44 #define tara 48 #define redl 24 #define bluel 22 #define greenl 26 #define redr 30 #define bluer 28 #define greenr 32 HX711 waga; LiquidCrystal_I2C lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7); int led = 13; float ciezar; int ml1 = 0; int ml2 = 0; int ml3 = 0; int czasMigania = 250; int predkoscNalewania = 200; char odczyt[8]; AF_DCMotor pompa1 (3); AF_DCMotor pompa2 (2); AF_DCMotor pompa3 (1); void setup() { Serial.begin(9600); pinMode(start, INPUT_PULLUP); pinMode(manpom1, INPUT_PULLUP); pinMode(manpom2, INPUT_PULLUP); pinMode(manpom3, INPUT_PULLUP); pinMode(tara, INPUT_PULLUP); pinMode(redl, OUTPUT); pinMode(bluel, OUTPUT); pinMode(greenl, OUTPUT); pinMode(redr, OUTPUT); pinMode(bluer, OUTPUT); pinMode(greenr, OUTPUT); lcd.begin(20, 4); lcd.setBacklightPin(3, POSITIVE); digitalWrite(led, HIGH); lcd.setBacklight(HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Witaj!"); lcd.setCursor(0, 1); lcd.print("Chlapnij sobie!"); lcd.setCursor(13, 3); lcd.print("Kasztan"); delay(1000); pinMode(led, OUTPUT); waga.begin(A1, A2); waga.set_scale(419341.0 / 200.0); waga.tare(5); pompa1.setSpeed(predkoscNalewania); pompa2.setSpeed(predkoscNalewania); pompa3.setSpeed(predkoscNalewania); } void loop() { pomiar(); ekran(); if ((ml1 + ml2 + ml3) > 250) { czerwona(); delay(500); ciemno (); } else { ciemno(); } if (digitalRead(start) == LOW) { waga.tare(); ekran(); Serial.println("zeruje"); if (ml1 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam promile"); while (ciezar <= ml1) { pomiar(); ekran(); pompa1.run(FORWARD); led1(); } pompa1.run(RELEASE); Serial.println("promile przerwa"); delay(100); if (ml2 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam rozcienczacz"); while (ciezar <= ml2) { pomiar(); ekran(); pompa2.run(FORWARD); led2(); } pompa2.run(RELEASE); Serial.println("rozcienczacz przerwa"); delay(100); if (ml3 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam kwas"); while (ciezar <= ml3) { pomiar(); ekran(); pompa3.run(FORWARD); led3(); } pompa3.run(RELEASE); Serial.println("kwaas przerwa"); delay(100); } } } waga.tare(); pomiar(); kolorowo(); ciemno(); } if (digitalRead(manpom1) == LOW) { pompa1.run(FORWARD); led1(); } else { pompa1.run(RELEASE); } if (digitalRead(manpom2) == LOW) { pompa2.run(FORWARD); led2(); } else { pompa2.run(RELEASE); } if (digitalRead(manpom3) == LOW) { pompa3.run(FORWARD); led3(); } else { pompa3.run(RELEASE); } if (digitalRead(tara) == LOW) { waga.tare(10); } } void pomiar() { ml1 = analogRead(A5); ml1 = map(ml1, 1020, 0, 0, 150); ml2 = analogRead(A4); ml2 = map(ml2, 1020, 0, 0, 150); ml3 = analogRead(A3); ml3 = map(ml3, 1020, 0, 0, 150); ciezar = waga.get_units(); dtostrf(ciezar, 5, 0, odczyt); } void ekran() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("1.Alkohol:"); lcd.print(ml1); lcd.setCursor(0, 1); lcd.print("2.Dodatek:"); lcd.print(ml2); lcd.setCursor(0, 2); lcd.print("3.Kwas:"); lcd.print(ml3); lcd.setCursor(0, 3); lcd.print("Waga:"); lcd.print(odczyt); lcd.print("g"); Serial.println(ml1); Serial.println(ciezar); } void ciemno() { digitalWrite(redl, LOW); digitalWrite(greenl, LOW); digitalWrite(bluel, LOW); digitalWrite(redr, LOW); digitalWrite(greenr, LOW); digitalWrite(bluer, LOW); } void czerwona () { digitalWrite(redl, HIGH); digitalWrite(greenl, LOW); digitalWrite(bluel, LOW); digitalWrite(redr, HIGH); digitalWrite(greenr, LOW); digitalWrite(bluer, LOW); } void zielona () { digitalWrite(redl, LOW); digitalWrite(greenl, HIGH); digitalWrite(bluel, LOW); digitalWrite(redr, LOW); digitalWrite(greenr, HIGH); digitalWrite(bluer, LOW); } void niebieska () { digitalWrite(redl, LOW); digitalWrite(greenl, LOW); digitalWrite(bluel, HIGH); digitalWrite(redr, LOW); digitalWrite(greenr, LOW); digitalWrite(bluer, HIGH); } void kolorowo () { digitalWrite(redl, HIGH); delay(czasMigania); digitalWrite(greenl, HIGH); delay(czasMigania); digitalWrite(bluel, HIGH); delay(czasMigania); digitalWrite(redr, HIGH); delay(czasMigania); digitalWrite(greenr, HIGH); delay(czasMigania); digitalWrite(bluer, HIGH); delay(czasMigania); delay(500); } void led1 () { digitalWrite(redl, HIGH); digitalWrite(greenl, HIGH); digitalWrite(bluel, LOW); digitalWrite(redr, HIGH); digitalWrite(greenr, HIGH); digitalWrite(bluer, LOW); } void led2 () { digitalWrite(redl, LOW); digitalWrite(greenl, HIGH); digitalWrite(bluel, HIGH); digitalWrite(redr, LOW); digitalWrite(greenr, HIGH); digitalWrite(bluer, HIGH); } void led3 () { digitalWrite(redl, HIGH); digitalWrite(greenl, LOW); digitalWrite(bluel, HIGH); digitalWrite(redr, HIGH); digitalWrite(greenr, LOW); digitalWrite(bluer, HIGH); } Link do filmu:
  4. Mam pytanie dotyczące podłączenia wyświetlacza LCD i silnika krokowego. Czy mogę zasilać wyświetlacz LCD z 5v a silnik krokowy z Vin? Czy lepiej podłączyć baterie bezpośrednio do płytki stykowej a wyświetlacz LCD zasilać z portu usb? Nie do końca rozumiem jak działa Vin.
  5. Jakiś czas temu zakupiłem sobie ESP32 CAM, niestety nie umiałem dla niej znaleźć jakiegoś sensownego zastosowania. Przeleżała z pół roku a może i więcej, aż wpadłem na pomysł zrobienia foto-pułapki. I tak oto powstała: Po mojej posiadłości często biegają dzikie zwierzęta takie jak: sarny, bażanty, dziki i zające. Te ostatnie to raczej szkodniki ale lecimy z tematem dalej. Założenia: Zapis zdjęć na karcie SD Wysyłka zdjęć na FTP Wysyłka zdjęć na maila jakiś czujnik temperatury praca możliwie jak najdłużej z jednej baterii wspomaganej panelem PV Po ogarnięciu softu na biurku podłączeniu czujnika PIR wszystko ładnie działało. Za zasilanie odpowiada jedno ogniwo 18650, przetwornica podnosząca napięcie do 5V i mały panel PV 6V 167mA. Jak widać powyżej kamera jest przylepiona klejem dwuskładnikowym, tak by uniknąć uszkodzenia tasiemki. Wszystko zostało umieszczone w obudowie po NanoStation Loco M5. Która została dostosowana do zamontowania panelu PV, czujnika PIR oraz kamery. Poniżej etap pasowania elementów. Został również wydrukowany daszek oraz uchwyty dla szyby która osłania kamerę od deszczu. Obudowa Została dodatkowo pomalowana na czarno - ale chyba będę jej robić jakieś malowanie taktyczne, lub pójdzie w ruch “termoglut” i trzcina żeby się lepiej wtapiała w otoczenie. Pierwsze wyjście w teren i klapa, wszystkie zdjęcia były przejaśnione. Po kilku próbach okazało się że kamera potrzebuje 2s! aby dostosować czas ekspozycji, (lekka tragedia bo przy zajączkach to już go może dawno nie być w kadrze) oczywiście w warsztacie wszystko działało jak należy. Następnym nietrafionym pomysłem okazało się wysyłanie zdjęć na maila, trwa to stosunkowo długo a co za tym idzie zużycie energii jest większe, co doprowadziło do rozładowania baterii po 2 dniach. Konieczne było zrezygnowanie z wysyłki zdjęć na maila. W tej chwili kamera działa bez ładowania już 5 dni. Przykładowe zdjęcia z kamery poniżej: Trapi mnie jeszcze jeden problem mianowicie jeśli na zdjęciu jest więcej szczegółów np: cały kadr trzciny lub trawy, to obraz jest obcinany tak około 100-200px z dołu. Nie jest to chyba problem buforu w ESP bo przy kompresji ustawionej w sofcie na 10 zdjęcia zajmują 384KB jeśli zwiększę kompresje zdjęcia zajmują mniej a obraz i tak jest obcinany. Oprócz zdjęć wyzwalanych czujnikiem ruchu, procesor budzi się co 30 min wykonuje zdjęcie i wysyła je na FTP. To aby mieć pewność że bateria nie uległa rozładowaniu. A i jest jeszcze nieszczęsny czujnik temperatury DS18B20, nie było łatwo go tam upchać bo okazało się że wszystkie piny na płytce są wykorzystywane i jedyny wolny pin który mogę wykorzystać to pin serial RX, co niesie za sobą konieczność wypięcia czujnika w razie chęci przeprogramowania układu. Lista wykorzystanych elementów: ESP32-CAM AI-Thinker Przetwornica step-up 5V wraz z modułem ładowania ogniw 18650 Koszyk na ogniwo 18650 Czujnik PIR Mini panel PV 6V 167mA Antena 2.4 Ghz Podsumowując, działa aczkolwiek widać pewne ograniczenia tego układu chociażby czas jaki kamera potrzebuje na uruchomienie się. Z ciekawostek do ESP32 została podłączona zewnętrzna antena, gdzie przetestowany zasięg to około 200 m :), ale pewnie to też zasługa tego że łącze się do AP który mam wystawiony na dworze. Kodu programu pozwolę sobie w tej chwili nie udostępnić bo mam tam niezły bałagan, a jeszcze staram się uporać z obcinaniem fotek, za jakiś czas na pewno go zamieszczę.
  6. 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>
  7. cześć, potrzebuje pomocy z programem do sterowania rębaka no stress. Większość kodu zrobiłem lecz coś nie działa program i nie mam pomysłu co jest nie tak. program ten ma za zadanie po wykryciu 3000 obrotów RPM włączyć przekaźnik sterowania silnikiem do przodu, lecz gdy obroty spadną do 1000 ma on włączyć na 0,5s przekaźnik silnika do tyłu i go zatrzymać. Po osiągnięciu obrotów 3000 ma on od nowa uruchomić silnik do przodu. pin awaria - wyłącznik bezpieczeństwa(wyłącza oba silniki) zmienna walek - włączanie wyłączanie silnika do przodu prowizorycznie RPM zmieniam wartością zmiennej //#define czujnik 2 // - w projekcie obrotomierz jest jako RPM //#define walek 6 //(OPCJONALNIE) czy jest wlaczony walek #define awaria 5 // wyłącza posów #define cewkaPrzod 3 // przekaznik wlaczajacy posow w przod #define cewkaTyl 4 // przekaznik wlaczajacy posow w tyl int RPM = 3001; int a = 0; bool walek; void setup(){ //pinMode(czujnik, INPUT_PULLUP); //pinMode(walek, INPUT_PULLUP); // wlaczyc jesli jest czujnik wałka pinMode(awaria, INPUT_PULLUP); pinMode(cewkaPrzod, OUTPUT); pinMode(cewkaTyl, OUTPUT); } void loop(){ walek = false; if(walek == true){ digitalWrite(cewkaPrzod, HIGH); } if(walek == false){ digitalWrite(cewkaPrzod, LOW); } walek = false; digitalWrite(cewkaTyl, LOW); //digitalWrite(cewkaPrzod, LOW); while(digitalRead(awaria) == HIGH){ if(a == 0 && RPM < 1000) { walek = false; digitalWrite(cewkaTyl, HIGH); delay(500); digitalWrite(cewkaTyl, LOW); a = a + 1; } if(RPM > 3000){ walek = true; a = 0; } } }
  8. Witam, mam mały problem z programem na arduino z wzmacniaczem. Chciałem zrobić układ wyjściowy 0-10V proporcjonalny do temperatury o zakresie 17 do 22 stopni celsjusza. Napięcie na układzie wyjściowym miało być proporcjonalne do temperatury czyli, temperatura 17 stopni to napięcie na wyjściu 10V i odwrotnie. Problem polega na tym, że po podłączeniu wzmacniacza i dopisaniu dla niego programu wyświetlana na LCD (z konwerterem I2C) temperatura zaczęła wariować. Bez wzmacniacza wszystko było w porządku. przesyłam program oraz na szybko schemat. Z góry dziękuje za pomoc.
  9. Oglądając zestaw arduino uno zastanawia mnie jedna kwestia, dlaczego jest po 5 szt diod koloru czerwonego, żółtego i zielonego a niebieska tylko jedna? Czy chodzi może o koszt i wyprodukowanie niebieskiej diody jest o wiele droższe?
  10. Dzisiaj nieco odpoczynku od elektroniki. Ale oczywiście o ile ta cała kabelkologia jest niezmiernie ważna i ważne jest urządzenie sobie warsztatu - to samo można powiedzieć o "warsztacie programisty", czyli zorganizowaniu tak stanowiska, aby można było skupić się na tym co najważniejsze: tworzeniu kodu. Wrzucam to jako worklog, bo kilka spraw jest jeszcze nie do końca rozwiązanych (m.in. użycie esptool-ftdi, na czym bardzo mi zależy), ale w tej postaci jaka jest program jest absolutnie używalny i spełnia swoją funkcję. Na potrzebę powstania tego programu złożyło się kilka czynników. Przede wszystkim w większości do programowania swoich ESP używam frameworku Arduino, a Arduino IDE z różnych przyczyn uważam za mało używalne. Poza tym także nie przepadam za pisaniem Makefile (chociaż po napisaniu bardzo lubię używać make). Postanowiłem więc zrobić sobie wrapper do arduino-cli. Wrapper działa na Linuksie, ale nie widzę przeszkód w uruchomieniu go na Macu czy nawet na Windows, potrzebne by były jedynie niewielkie zmiany. Przede wszystkim musiałem zrobić to, czego mi a Arduino IDE brakuje - czyli oddzielna konfiguracja dla każdego szkicu. Postanowiłem pójść jeszcze dalej: ponieważ zdarza mi się ten sam program uruchamiać na kilku różnych architekturach, założyłem możliwość istnienia kilku wariantów konfiguracji dla każdego szkicu i zabrałem się do roboty. Ponieważ znałem już strukturę plików boards.txt i platform.txt poszło dość szybko - i w relatywnie krótkim czasie miałem już gotowy konfigurator. Oczywiście zanim cokolwiek się zrobi trzeba dodać nowy wariant. Po wciśnięciu klawisza "Nowa" ukazuje się okno tworzenia wariantu: Jak widać jest to podobne do menu wyboru płytki w Arduino IDE, dochodzi jedynie pole "Nazwa", pozwalające na nadanie wariantowi jakiejś łatwej do zapamiętania nazwy. Po utworzeniu wariantu można zabrać się do konfiguracji. I tu znów wzorowałem się na menu Arduino IDE - wszystkie parametry są widoczne na liście, a aktywacja wiersza (czyli dwuklik albo wciśnięcie Enter) powoduje pojawienie się możliwości wyboru predefiniowanej opcji: Jak widać, na razie różnice w stosunku do IDE są niewielkie, ale następną rzeczą, która w IDE jest dla mnie szalenie niewygodna, jest wybór portu do uploadu. Przede wszystkim - nasze systemy operacyjne przyporządkowują numer portu do urządzenia w sposób raczej losowy. Odłączenie i ponowne podłączenie płytki skutkować może np. zmianą portu z ttyUSB0 ma ttyUSB1, co potrafi trochę krwi napsuć. Dość dawno jednak stworzyłem prosty system detekcji portu, i zastosowanie go tutaj było oczywiste. Po prostu podaję jaki to ma być typ portu (do wyboru ttyS, ttyUSB i ttyACM) i/lub nazwę pod jaką zgłasza się podłączone urządzenie. Program szukając portu przeszukuje tylko te o zadeklarowanym typie, ewentualnie sprawdzając, czy nazwa odczytana z urządzenia zawiera w sobie wyszukany string. W ten sposób np. uploader dostaje informację że ma się połączyć na tym a nie innym porcie. Ten sposób działa u mnie już od ok. dwóch lat i jeszcze mnie nie zawiódł. W programie wprowadziłem jeszcze jedną zmianę: jeśli nazwa rozpoczyna się od VID:PID (np. "2341:0043 Uno R3") będzie wyszukiwane urządzenie odpowiadające odczytanym z USB wartościom VendorID i ProductID. Również nazwa w przypadku urządzeń USB będzie (o ile to mozliwe) pochodzić z oficjalnego wykazu. Następną sprawą jest ustawienie adresu i hasła OTA. O ile w IDE konieczne jest, aby urządzenie było włączone w czasie ustawiania portu, o tyle tu takiej konieczności nie ma: mogę albo skorzystać z listy urządzeń wykrytych przez zeroconf (przy czym mogę sobie zapisać albo nazwę, albo adres IP) albo podać te dane ręcznie (jeśli je znam). Poza tym mój program zapamiętuje hasło, co bywa wygodne (szczególnie w porównaniu do IDE w wersji 2.x). I ostatnia rzecz: użycie zewnętrznego programu do uploadu. Może to być np. program obsługi jakiegoś programatora, albo (jak w moim przypadku, co postaram się pokazać przy najbliższym DIY) skrypt wysyłający skompilowany plik do maszyny, do której podłączona jest płytka. W sumie okno konfiguratora uploadu wygląda tak: Istnieje również możliwość dodania dodatkowych parametrów do kompilacji. Dla architektury AVR można włączyć pełną wersję sprintf (tzn. taką, która pozwala na wypisywanie floatów). Można również dodać dowolną ilość definicji, które w programie będą traktowane jako dodatkowe linie #define. Poziom szczegółowości ostrzeżeń działa nieco inaczej niż w IDE: dla platform, dla których automatycznie dodawane jest -Werror przy wyświetlaniu wszystkich ostrzeżeń parametr ów nie jest dodawany automatycznie, można go dodać zaznaczając odpowiednie pole. W ten sposób można bez zbytniej ekwilibrystyki kompilować programy np. na ESP32 z wyświetlaniem wszystkich ostrzeżeń (w IDE przy takim przełączeniu kompilator odmawia kompilacji bibliotek które generują jakieś ostrzeżenia, choćby nawet nie miały wpływu na ich działanie): I to już cały konfigurator. Teraz wystarczy zapisać całą konfigurację (przycisk "Zapisz" lub "Zapisz i zakończ"). Jako domyślny zostanie wpisany wariant aktualnie wskazany na liście. No, ale konfigurator to nie wszystko - warto by było mieć coś, co z tego konfiguratora korzysta. Postanowiłem stworzyć jedno polecenie, które zależnie od podanych opcji będzie robiło różne czynności. Jako że najważniejszym poleceniem jest "help", tak wygląda wynik jego działania (i kilku następnych): Pisząc program natknąłem się na kilka nieprzyjemnych niespodzianek związanych z arduino-cli. Początkowo najbardziej naturalne wydało mi się umieszczenie katalogów build i cache wewnątrz katalogu szkicu. Stosowałem to już wcześniej używając arduino-builder i make, tak więc wydało mi się to najlepszym i w dodatku sprawdzonym rozwiązaniem. A guzik... arduino-cli bardzo grzecznie kompilował program, ale tylko raz. Ki diabeł? No tak, zajrzenie na githuba do issues wszystko wyjaśniło. Jest to stary, szacowny błąd z długą brodą, polegający na tym, że arduino-cli uważa pliku w katalogu build za pliki żródłowe, i próbuje je jeszcze raz skompilować (co się oczywiście nie udaje). W związku z tym preniosłem owe katalogi do /tmp, jakoś w miarę sensownie je ponazywałem i zadziałało... No prawie, a jak wiadomo - prawie robi wielką różnicę. Otóż plik konfiguracji (w formacie json) zapisywany jest w katalogu szkicu (no bo gdzie miałby być zapisany) z rozszerzeniem .json - a to też zmyliło arduino-cli które koniecznie chciało go skompilować. Zmiana rozszerzenia na .cfg skutecznie oduczyła arduino-cli nadmiernej gorliwości i wszystko ładnie ruszyło... Z jednym wyjątkiem: uploadu przez OTA. Podobno arduinio-cli to potrafi (w końcu jakoś IDE w wersji 2.x daje sobie z tym radę, aczkolwiek nie tak do końca). Postanowiłem więc darować sobie sprawdzanie i upload OTA rozwiązać "ręcznie". Jako że jak dla mnie dotyczy to tylko ESP, zaprzągłęm do pracy parser konfiguracji arduino (który i tak jest częścią programu), i dopisałem kilka linijek. Co prawda w tej postaci upload OTA możliwy jest wyłącznie dla ESP32 i ESP8266, ale po pierwsze nie mam innych mikrokontrolerów dla których mógłbym to wykorzystać, po drugie dopisanie kolejnych architektur to kwestia kliku minut, a po trzecie wszystko można załatwić możliwością uploadu przez zewnętrzne polecenie. Aha, no i najważniejsze: może autorzy arduino-cli jakoś w końcu uporają się z implementacją obsługi OTA 🙂 No cóż - chciałbym powiedzieć że to wszystko, ale już słyszę narzekania: linia poleceń? Ajaj, przecież to takie trudne, lepiej sobie kliknąć w jakieś menu w aplikacji! A da się. Porządne edytory (np. Geany) mają możliwość skonfigurowania zewnętrznych poleceń. Dla przykładu rozwiązanie wyklikane dla plików *.ino wygląda w Geany tak: No i na koniec kwestia instalacji. Najpierw musimy upewnić się, czy mamy potrzebne biblioteki i programy współpracujące:Python, gobject-introspection i gtk3 najprawdopodobniej już mamy; można to łatwo sprawdzić uruchamiając konsolę python3 i wpisując polecenia importu Gtk3: $ python3 Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gi >>> gi.require_version('Gtk', '3.0') >>> from gi.repository import Gtk >>> Jeśli nie było błędu wszystko jest w porządku; w przeciwnym razie należy sprawdzić w dokumentacji swojej dystrybucji. Dodatkowo potrzebny będzie pakiet zeroconf i usb.ids. Jeśli ich nie będzie, pakiet zeroconf można zainstalować z githuba, a plik usb.ids można ściągnąć z internetu i umieścić gdziekolwiek wskazując ścieżkę we właściwym miejscu w pliku arduports.py w linii zawierającej polecenie: f=open('/var/lib/usbutils/usb.ids','rb') No i ostatnie najważniejsze: arduino-cli. Możemy zainstalować z githuba, lub użyć wersji zawartej w Arduino-IDE 2.x. Ważne, aby znalazło się w ścieżce wskazanej przez $PATH! Właściwy program instalujemy oczywiście z poziomu użytkownika, a nie roota! W tym celu musimy znać katalog, w którym możemy umieścić polecenia. Dla Linuksów będą to najprawdopodobniej ~/bin lub ~/.local/bin - można to sprawdzić poleceniem: echo $PATH Załóżmy że jest to katalog ~/bin. Plik pyrduino.tgz umieszczamy tam, gdzie nie powinien się zgubić (np. w katalogu domowym) i wykonujemy kolejno polecenia: tar -xzf pyrduino.tgz cd pyrduino-src chmod 755 ardu.py ln -sf $(pwd)/ardu.py ~/bin/arducfg ln -sf $(pwd)/ardu.py ~/bin/ardu I to wszystko. Możemy teraz wejść do katalogu szkicu i pobawić się poleceniami arducfg i ardu. Na koniec jedna uwaga: o ile polecenie arducfg musi pozostać takie a nie inne (można to zmienić w pliku ardu.py), o tyle zamiast nazwy ardu możemy użyć dowolnej, która nam się podoba. I jeszcze jedno: jak wspominałem na początku, da się to pewnie zainstalować na Macu (z niewielkimi zmianami) i na Windows (z większymi zmianami). Gdyby komuś się to udało - proszę o danie znać w komentarzu; może komuś się przyda! Do ściągnięcia: pyrduino.tgz I tak już całkiem na zakończenie dla miłośników make - krótki przykład: BINARY=$(shell ardu -show | grep -P '^Build\s+=' | tr -d " " | cut -d= -f2) $(BINARY): *.ino ardu PHONY: flash flash: $(BINARY) ardu -V -flash PHONY:ota ota: $(BINARY) ardu -ota PHONY:clean clean: ardu -clean Prawda, że proste?
  11. Witam, W trakcie robienia projektu (pojazd sterowany pilotem przez Bluetooth) napotkałem problem z nowo kupionym Arduino Nano Every (piny lutowałem sam). Chciałem, aby na pinach cyfrowych (podpiętych do przycisków) odczytywane było napięcie (HIGH lub LOW). Arduino z ustawionymi pinami na INPUT odczytuje stan wysoki - zawsze, choć powinien być stan niski. Wszystko działa dobrze po ustawieniu pinów na OUTPUT. Czy tak powinno być? Z tego co wiem to ustawienie na INPUT służy do odczytu, a odczyt z pinu ustawionego na OUTPUT powinien skończyć się błędem. Dla testu napisałem program: const int pinOut = 6; const int pinIn = 7; void setup() { Serial.begin(9600); pinMode(pinOut, OUTPUT); pinMode(pinIn, INPUT); } void loop() { //Odczyt z pinu 6 if(digitalRead(pinOut) == LOW) { Serial.println("Pin 6: LOW"); } //Odczyt z pinu 7 if(digitalRead(pinIn) == LOW) { Serial.println("Pin 7: LOW"); }else { Serial.println("Pin 7: HIGH"); } delay(1000); } Arduino jest podłączone tylko do komputera, żadne piny nie są połączone. A tutaj wynik: Pin 6: LOW Pin 7: HIGH Pin 6: LOW Pin 7: HIGH Pin 6: LOW Pin 7: HIGH Pin 6: LOW Pin 7: HIGH Pin 6: LOW Pin 7: HIGH Pin 6: LOW Pin 7: HIGH Czy to ja się mylę, czy np. płytka jest uszkodzona? Z góry dziękuję za pomoc.
  12. Dzień dobry. Otrzymałam płytkę arduino uno, która wcześniej była programowania za pomocą scratch i prawdopodobnie pythona. Po podłączeniu do komputera płytka komunikuje się z arduino IDE i komputerem (po kliknięciu upload w arduino IDE nie ma komunikatu o błędzie, na płytce mruga dioda). Wgrałam jej przykładowy program "blink" z lekcji nr 1 kursu arduino 1, lecz nie mrugają na niej diody. Po zasygnalizowaniu odebrania danych, nic więcej się nie dzieje. Co należy uczynić, by płytka działała? Pozdrawiam
  13. Witam, mam problem nagłej potrzeby. Prostu układ: esp8266 nodemcu v3 podłączony pod zasilacz impulsowy 12V przekaźnik 8 kanałowy z optoizolacją zasilany na 5V Z Zasilania 12V idzie też prąd na stabilizator 5V - ten zasila tylko i wyłącznie wejście Vcc płytki przekaźnika. problem jest taki, że przekaźnik normalnie działa w przypadku gdy styk IN1 załącze z arduino leonardo. Wszystko jest idealnie z arduino. Natomiast gdy spróbuję to samo zrobić z esp zamiast arduino, to na przekaźniku zapala się tylko LED że 1 styk został załączony, jednak nie słychać nawet charakterystycznego "trzasku" przełączania styku a sam kanał nie działa i nic się nie dzieje oprócz led sygnalizującego załączenie styku. Problem palący czasowo, ktos wie czemu arduino normalnie załącza styk na przekaźniku a esp już nie? I jak to rozwiązać?
  14. Robot który zbudowałem na sobotnie zawody okazało się że w losowych momentach na trasie przestaje jechać. Zatrzymuje się na kilka sekund i czasem rusza znowu a czasem słychać tylko pyknięcie, robot minimalnie drgnie i dalej się zawiesza. Podczas tych zawieszeń diody rx, tx i wbudowana przestają migać, świeci się dioda ON oraz diody sygnalizujące prawidłowy przepływ prądu w 2 miejscach na 2 płytkach. Zwykle pomaga reset ale muszę rozwiązać problem jak najszybciej bo zawody są już w tą sobotę a muszę jeszcze przeprowadzić testy. Więcej o robocie: Typowa konstrukcja z dwoma kołami z tyłu i platformą z 8 czujnikami z przodu Silniki to polulu hp micro z przekładnią file:///C:/Users/Admin/Downloads/Photo-1.jpeg1:10 Zasilane akumulatorem lipo 500mah 11,1V po stabilizatorze na 6V Użyty jest sterownik silników 2-kanałowy sparkfun Algorytm to zwykły PID (po odkryciu problemu zredukowany do samego P i sprawdzony, problem raczej nie leży po stronie programu) Sprawdziłem: po podpięciu przez kabel (bez akumulatora) - działa gdy koła są w powietrzu- działa gdy zablokuję koła- działa gdy zablokuję koła i przyłożę do podłoża czujniki- nie działa PS testy powyżej są dla bardzo niskiej prędkości, około 25% maksymalnej prędkości silników. Po zwiększeniu zadanej prędkości silniki kompletnie odmawiają współpracy.
  15. Witam. mam problem z moją płytką Arduino UNO R3. Gdy staram się wgrać kod do płytki to mi sprawdza kod i pokazuje "Uploadnig...", ale nic się nie dzieje. Cały czas się wgrywa. Płytka była sprawna i dopiero po napisaniu tego kodu i próbie wgrania wystąpił ten problem. Podłączony mam wyświetlacz lcd 2x16 dalmierz ultradźwiękowy i brzęczyk #include <LiquidCrystal.h> LiquidCrystal lcd(2, 3, 4, 5, 6, 7); int CM; int CZAS; // TRIG = 1 // ECHO = 0 void pomiar() { digitalWrite(1, LOW); delayMicroseconds(2); digitalWrite(1, HIGH); delayMicroseconds(10); digitalWrite(1, LOW); digitalWrite(0, HIGH); CZAS = pulseIn(0, HIGH); CM = CZAS / 58; } void alarm() { digitalWrite(8, HIGH); lcd.setCursor(0,2); lcd.print("UWAGA ZA BLISKO"); } void bezpiecznie() { digitalWrite(8, LOW); lcd.setCursor(0,1); lcd.clear(); } void setup() { pinMode(8, OUTPUT); pinMode(1, OUTPUT); pinMode(0, INPUT); lcd.begin(16, 2); lcd.setCursor(0,1); lcd.print("pokaze ci naj-"); lcd.setCursor(0,2); lcd.print("blizsza odleglosc"); delay(3000); lcd.setCursor(0,1); lcd.clear(); lcd.print("od dalmieza"); lcd.setCursor(0,2); lcd.print("ultradzwienkowego"); delay(3000); } void loop() { if(CM <= 4) { pomiar(); lcd.setCursor(0,1); lcd.clear(); lcd.print("Odleglosc: "); lcd.setCursor(12,1); lcd.print(CM); lcd.setCursor(13,1); lcd.print("cm"); alarm(); delay(20); } if(CM > 4) { bezpiecznie(); pomiar(); delay(20); } }
  16. Cześć, pewnego razu na spotkaniu ze znajomymi okazało się, że na hasło „polej” nikt nie zareagował. Wtedy zrodził się pomysł, aby zaradzić takim przykrym sytuacjom w przyszłości postanowiłem stworzyć robota do nalewania alkoholi wysokoprocentowych. Z założenia robot miał nalewać alkohol do każdego kieliszka jaki się postawi oraz miał być zasilany przy pomocy baterii. Pierwsze prototypy zawierały prostą elektronikę opartą na czujnikach i przekaźnikach – jestem laikiem oraz samoukiem w kwestiach elektroniki. Projekty nie spełniały oczekiwań, ponieważ w normalnym użytkowaniu zawodziły. Około rok temu natknąłem się na Arduino i zacząłem pogłębiać swoją wiedzę w tym kierunku. Wydruki 3D wykonałem na swojej drukarce. Robot spełnił założenia. Poprzez zastosowanie czujnika ultradźwiękowego jest w stanie nalać do każdego kieliszka, a potencjometrem można ustawić ilość nalewanej wódki w zakresie około 10 - 50ml. Do zasilania użyłem 8 akumulatorów AA. Wykonałem obudowę z kilku elementów żeby mieć lepszy dostęp do podzespołów. Rynienka na pompce została stworzona po zalaniu układu... z wyciekiem sobie poradziłem ale dla pewności została 😉 Części których użyłem do budowy: Płytka stykowa 170 pól - 1 szt Stabilizator L7805CV 5V 1,5A – 1 szt Ultradźwiękowy czujnik odległości HC-SR04 2-200cm – 1szt Potencjometr liniowy 1K – 1 szt Wtyk DC 2,1/5,5mm z zaciskami skręcanymi – 1 szt Pompa membranowa - silnik R385+ - 12V - 3W - mini pompa wodna – 1szt Moduł sterownika L298N do silników DC – 1 szt Przełącznik kołyskowy 15x10mm – 1 szt Koszyk na baterie 8xAA (R6) – 1 szt Arduino Nano – 1 szt Uniwersalny Proto Shield do Arduino Nano – 1 szt Serwo TowerPro MG-995 – 1szt. Zawór zwrotny – 2szt. Moduł dioda LED RGB 5050 wspólna katoda – 1 szt. Magnesy neodymowe 10x5 – 8 szt Przycisk monostabilny – 1 szt. Rurka sylikonowa – 0,5m Rezystory Przewody połączeniowe Aby "polewacz" był mobilny jego elementy zaprojektowałem tak, aby zmieściły się w drewnianej skrzyni 30x20x15cm.
  17. Witam ostatnio chciałem pobawić się troszkę arduino lecz gdy podłączyłem je do komputera, komputer płytki nie wykrył świeciła się tylko dioda zasilania i migała dioda L . Nie jest to wina kabla, ponieważ pliki z telefonu przez ten kabel przechodzą normalnie. Problem dotyczy płytki arduino Leonardo R3.
  18. W tym projekcie chciałbym opisać krok po kroku proces podłączenia licznika samochodowego od Forda Galaxy do naszego Arduino. Potrzebne elementy: Zasilacz 12V Arduino Przewody męsko-żeńskie Licznik samochodowy Zestaw wskaźników od Forda Galaxy posiada 2 wtyczki - czerwoną oraz czarną. Nas w tym projekcie interesuje tylko czerwona wtyczka gdyż znajdują się w niej piny zasilające oraz dostarczające dane do silników krokowych w liczniku. Najpierw zajmijmy się zasilaniem. Do pinu 3 oraz do pinu 4 na liczniku wpinamy 2 przewody i podłączamy je do minusa na naszym zasilaczu a kolejne 2 przewody wpięte w pin 14 oraz w pin 15 podłączamy do +. Jako zasilacz może nam posłużyć zwykły zasilacz komputerowy kub jakikolwiek o napięciu 12V. Dalej zajmijmy się podłączeniem silniczków od wskazówek. obrotomierz - 10 pin prędkościomierz - 27 pin wskaźnik poziomu paliwa - 21 pin wskaźnik temperatury cieczy - 23 pin (pin 1 jest w lewym dolnym rogu wtyczki) Następnie przewody te wpinamy w wejścia cyfrowe do Arduino. W moim przypadku obrotomierz wpiąłem w wejście oznaczone 2, prędkościomierz w wejście nr 3, wskaźnik poziomu paliwa 4 a temp. cieczy w wejście 5. Jeżeli po podpięciu zasilania licznik zadziała (wskazówki ustawią się w położeniu 0 oraz włączy się podświetlenie) to możemy przejść do konfiguracji. Pobieramy oprogramowanie SimHub i instalujemy je. Po uruchomieniu programu przechodzimy do zakładki Arduino a następnie klikamy na zakładkę "My hardware". Wybieramy "Single Arduino" i klikamy "Open arduino setup tool". Następnie definiujemy w jakie wejścia wpięliśmy nasze wskaźniki. Wybieramy z jakiego arduino korzystamy (w moim przypadku jest to UNO) oraz wybieramy port komunikacyjny. Gdy wszystko mamy już zrobione klikamy Upload to arduino i czekamy aż program zostanie wgrany na Arduino. Jeżeli program wgrał się poprawnie przechodzimy do zakładki "Gauges" i kalibrujemy nasz licznik. Wartości liczbowe są indywidualne dla każdego licznika ale to co musimy ustawić do każdego licznika to MAX Tachometer RPM na 7 (jeżeli zakres na tarczy obrotomierza jest inny to podajemy maksymalną liczbę, jeśli jest to 5 to podajemy 5) oraz tachometer cylinders na 6. Warto zaznaczyć opcję "Always use tachometer full range" jednak jeśli sprawia ona problemy możemy ją wyłączyć. Resztę wartości musimy ustawić tak, żeby wskazówka poprawnie wskazywała położenie min i max. Niestety nie ma uniwersalnych wartości i prędkościomierz u mnie wskazuje poprawnie 240 km/h przy wartości 222 (speedo gauge maximum output) jednak w innym liczniku może być to wartość ciut większa lub mniejsza. Na samym końcu wybieramy grę w którą chcemy zagrać z zakładki "Games". Następnie uruchamiamy naszą grę i cieszymy się rozgrywką z naszym licznikiem. Ktoś mi może powiedzieć "Przecież można napisać kod", zgodzę się z tym tylko ja gram od ETS 2 przez Dirt 4 na Forzie kończąc. O wiele łatwiej jest jednym kliknięciem zmienić grę w simhubie niż pisać osobny kod eksportujący dane z telemetrii do Arduino. Jeżeli ktoś potrzebuje tylko licznika do jednej gry to ma to sens jednak w moim przypadku mija się to z celem. Koszt takiego licznika może zamknąć się w okolicach 50 zł. Możemy wykorzystać klona arduino (klon nano możemy kupić za mniej niż 15zł), a licznik możemy znaleźć na portalach aukcyjnych za ok 20zł. Jest to niedrogi i fajny bajer a na dodatek jest bardzo praktyczny. Poniżej znajdują się zdjęcia i gif pokazujący pracę urządzenia.
  19. Pięć lata temu miałem termometr avt. Zepsuł się po roku więc kupiłem kolejny, kolejny też się zepsuł. Pół roku temu postanowiłem zrobić termometr na arduino. Termometr cały czas udoskonalam. Obecnie posiada cztery czujniki : jeden czujnik DS18B20, Czujnik wilgotności i temperatury DHT11, Dwa czujniki temperatury i wilgotności DHT22. Pozostałe rzeczy, które użyłem to: Wyświetlaczem 4x20 znaków Konwerterem i2C LCD Moduł RTC DS3231 Koszyk na baterie AA do podtrzymania zegara Dwie baterie AA Czujnik ruchu Arduino uno Początkowo nie wiedziałem jak zapisać godzinę i datę w pamięci modułu RTC więc całość posiadało akumulator 12v 7Ah po to by godzina i data była prawdziwa a nie odczytywana z kodu po podaniu zasilania. Nie posiadał w tedy też czujnika ruchu więc posiadał włącznik, którym włączało się podświetlenie LCD. W tym momencie posiadał tylko trzy czujniki temperatury DS18B20 oraz jeden DHT11. Teraz termometr włącza się gdy ktoś przed nim się poruszy, mierzy temperaturę maksymalną i minimalną z każdego z czujników. Oraz posiada zasilacz 12V 1A. Całość umieściłem w obudowie z sklejki 6 mm pomalowanej szarą farbą. Z przodu znajduje się wyświetlacz, czujnik ruchu oraz dioda informująca że termometr oczekuje na ruch wyłącza się jeśli ktoś przednim się poruszy i włączy się wyświetlacz. Po lewej stronie znajduje się czujnik DHT22 mierzący temperaturę w pokoju. Specjalnie oddaliłem go od obudowy, żeby wynik był jak najbardziej prawidłowy. Na arduino wytrawiłem płytkę moją wytrawiarką do PCB (ma się dobrze i ostatnio dorobiłem do niej pompkę powietrza) są do niej podłączone wszystkie rzeczy. Czujniki które są poza pokojem jeden na zewnątrz DS18B20 i DHT11 drugi na dole DHT22 są podłączone przez złącze RJ45 do arduino. Do modułu RTC na miejsce fabrycznej baterii przylutowałem koszyczek na baterie AA ponieważ zegar na fabrycznej baterii wytrzymał 4 miesiące. Temperatury maks. i min. wyświetliłem na osobnym ekranie. Od lewej Strzałki oznaczają temperaturę minimalną i maksymalną oraz jest ona wyświetlana najpierw minimalna potem maksymalna. Galeria pozostałych ekranów: Dziękuję za przeczytaniem oraz liczę na komentarze.
  20. Mam problem z Arduino Uno podłączonym do cnc shield v3 i UGS. Gdy chcę przesunąć serwo w osi Z o 30 °, to ciągle się obraca. Jaka może być przyczyna?
  21. Ten projekt będzie zliczał otwarcie szafki za pomącą kontaktronu i wyświetlał liczbę otworzeń. Do tego projektu potrzebujemy: Wyświetlacz LCD 2×16, Płytkę stykową, Przewody połączeniowe męsko-męskie, Arduino, Kontaktron, Potencjometr 5k, Projekt składamy zgodnie z poniższym schematem: Teraz pora na napisanie kodu. Mój wygląda tak: #include <LiquidCrystal.h> LiquidCrystal lcd(2, 3, 4, 5, 6, 7); int otworzenie = 0; #define kontaktron 8 int otwarcieP/F = 0; //narazie nie uzywana void setup() { digitalWrite(kontaktron, OUTPUT); lcd.begin(16,2); } void loop() { if(digitalRead(kontaktron) == HIGH && otwarcieP/F == 0) { otworzenie = otworzenie + 1; otwarcieP/F = otwarcieP/F + 1; }else if(digitalRead(kontaktron) == LOW && otwarcieP/F == 1) { otwarcieP/F = otwarcieP/F - 1; } lcd.setCursor(0, 0); lcd.print ( otworzenie); lcd.setCursor(0, 1); lcd.print("razy."); delay(1000); } Wgrywamy i potencjometrem regulujemy kontrast. Uwaga: Zamiast przycisku użyłem kontaktronu. Można też tak zrobić gdy się chcę mieć zliczanie otwarcia np. szafki, a nie naciśnięcia przycisku. Autor: Szymon, klasa 3 SP, 2021 ( Utworzenie).
  22. Witam, mój system powstał z praktycznej potrzeby zautomatyzowania systemu podlewania i w celu rozpoczęcia przygody z elektroniką – wyszedłem z założenia, że jak teraz nie zrozumiem, jak działa to wszystko co jest dookoła, to za chwilę będzie to tak złożone, że nie zdążę już tego zrozumieć 🙂 I generalnie myślę, że się udało – zrobiłem dokładnie to, co zamierzałem i w dodatku działa 🙂 OPIS DZIAŁANIA SYSTEMU System w założeniu miał być jak najprostszy (tzn. działać przy jak najmniejszej potrzebie ingerencji człowieka w porównaniu do skomplikowanych systemów programowalnych, które są na rynku). Steruje on trzema liniami rozprowadzonymi w ogrodzie: woda w kranach, zraszacze trawników, linie kroplujące. Sterowanie odbywa się za pomocą elektrozaworów zasilanych z przekaźników (moduł 4 przekaźników). Przekaźnikami steruje Arduino na podstawie: włączenia/wyłączenia przełącznika, upłynięcia maksymalnego czasu określonego dla każdej linii (po upłynięciu tego czasu zawór zostaje zamknięty). System jest zasilany wodą z zestawu hydroforowego (żeby było odpowiednie ciśnienie), który pobiera wodę z ze zbiornika na deszczówkę (ZBIORNIK 1). Ponieważ nie jest on zbyt duży (3 m3) to istniała konieczność dopompowywania wody z drugiego zbiornika na deszczówkę (ten już ma 12 m3). Moje rozwiązanie opiera się na zamontowaniu w zbiorniku 1 dwóch czujników poziomu cieczy i pozwala na automatyczne dopompowywanie wody ze zbiornika 2 do zbiornika 1, gdy w tym poziom spadnie poniżej dolnego czujnika. Pompa, która jest w zbiorniku 2 wyłącza się, gdy poziom w zbiorniku 1 podniesie się powyżej górnego czujnika. REALIZACJA Do sterowania zaworami wykorzystałem Arduino. Początkowo plan był taki, żeby wszystko zrobić bez mikrokontrolera. Jednak Arduino jest mi potrzebne w drugiej wersji urządzenia (już się buduje), o której napisze poniżej. Na czystej elektronice (bez programowania) oparłem moduł sygnalizacji poziomu i uzupełniania wody w zbiorniku. Bazując na dwóch czujnikach poziomu wody mogę określić trzy stany wody w zbiorniku: niski, średni, wysoki. Zależało mi, żeby pompa uzupełniająca wodę zaczynała pompować, gdy woda w zbiorniku osiągnie poziom niski, a kończyła, gdy osiągnie stan wysoki. Poprzez umieszczenie czujników jak najdalej od siebie, uzyskałem samoczynne uzupełnianie zbiornika. Do tego wykorzystałem dwa układy scalone: bramkę OR oraz NAND co pozwoliło zastosować trzy diody oznaczające poziom wody. Logika włączania tych diod jest następująca: Bramkę NAND wykorzystałem dodatkowo jako przerzutnik bistabilny, który pamięta czy pompa jest włączona, czy wyłączona. Oto płytka sporządzona samodzielnie na potrzeby projektu: KONSTRUKCJA Całe urządzenie udało się zamknąć w standardowej obudowie hermetycznej z wyprowadzeniem przewodów do zasilania, podłączenia zaworów, czujników poziomu wody i przewodu sterującego pompą. Do wykonanie „wtyczek” do zaworów wykorzystałem tworzywo, które mięknie w 60 stopniach i w ciepłej wodzie robi się plastyczne – można wszystko ulepić. Chodziło o to, że przy zaworach, jak najbliżej, powinny się znaleźć diody prostownicze i dlatego zrobiłem wtyczki z zatopionymi diodami. Jest to bardzo wygodne przy rozmontowywaniu systemu na zimę. Działanie systemu widać na poniższym filmie (na uchwycie wiszą czujniki poziomu wody). System działał już jeden sezon, także jest sprawdzony. PLANY NA PRZYSZŁOŚĆ Druga wersja urządzenia będzie miała dołączone czujniki deszczu i wilgotności gleby, będą pobierane komunikaty pogodowe z lotniska i będzie sterowanie zaworami przez wifi z telefonu. Chcę także dodać obsługę kalendarza do określenia czasu godziny, gdy system ma się włączać. Długość podlewania będzie sterowana czujnikami wilgotności i deszczu a włączenie podlewania uzależnione od przewidywanej pogody. Myślę, że więcej do systemu podlewania nie jest potrzebne. Musze powiedzieć, że budowa tego urządzenia dała mi wiele satysfakcji, bo nie zajmuję się zawodowo elektroniką ani programowaniem. Chciałbym szczególnie podziękować Trekerowi za kursy, dzięki którym było łatwo zacząć przygodę z elektroniką oraz Markowi za cenne uwagi i przekazaną wiedzę.
  23. Cześć jestem totalnie zielony w tematach arduino lecz chciałbym złożyć sobie button box do gry farming simulator. Narazie nie kupiłem arduino ale zrobiłem mniej więcej schemat i chciałbym sie dopytać czy by on w ogóle działał? Dołączam go w załączniku. Czy jest możliwosc zrobienia przycisku zmiany funkcji że np. 3 przyciski są odczytywane jako a,b,c a po wciśnięciu danego przycisku będą jako d,e,f i po ponownym wciśnięciu znowu jako a,b,c? I ostatnie czy da się jakoś zaoszczędzić jakieś tańsze odpowiedniki arduino warte polecenia do tkaiego projektu? I poprosiłbym o podanie strony z jakimiś przyciskami, przełącznikami itd w nie dużych cenach bo za nic nie mogę znaleźć żadnej. Za pomoc z góry dziękuję jak pisałem jestem totalnie początkujący więc biorę pod uwagę wszystkie rady i fajnie jakby odezwał się ktoś kto miał doświadczenie z button boxami do gier.
  24. Cześć. Postanowiłem zamieścić tu przykład kodu w ramach podzielenia się swoja "twórczością". Jeśli zły dział, proszę przenieść. Post głównie w celach edukacyjnych dla osób, które jeszcze nie miały okazje zrezygnować z miliona zmiennych Pin_1, Pin_2 itd. Dużo przyjemniej i czytelniej jest mieć wszystko skompresowane do obiektów, nawet jeśli to bedzie przerost formy nad treścią. Po prostu sam chciałbym coś takiego przeczytać rok-dwa temu 🙂 Swego czasu, gdy trochę więcej poświęcałem czasu na embedded, natrafiłem na jednym z kursów M. Salamona fajną (według mnie) metodę implementacji obsługi przycisku. Postanowiłem sobie ją trochę przerobić, gdyż oryginał był pisany pod C i używał callbacków, które średnio mi dobrze pasowały, bo za każdym razem napotykałem rozmaite problemy, z którymi średnio sobie umiałem poradzić. Napisałem więc sobie to jako klasę, a kolejno dopisałem drugą klasę, która dziedziczy po niej, a jednocześnie implementuje to co dzieje się po wciśnięciu tego przycisku. Jest to taki chyba najprostszy przykład zastosowania programowania obiektowego dla arduino. Zamieszczam Link do GitHub z plikami .h i .cpp. gdyż wstawienie tu całego kodu byłoby trochę przesadą? Celem w ogóle użycia dziedziczenia było zrobienie swoistej "templatki" dla klasy, która implementuje obsługę przycisku, ale nie definiuje tego co dzieje się po wciśnięciu tego przycisku. Zapewne 80% przycisków w projektach po prostu wystawia jakiś stan na konkretny Pin, więc można było darować sobie to dziedziczenie, no ale.. zrobiłem sobie to głównie pod siebie na przyszłość. W temacie programowania obiektowego jestem początkujący więc wszelakie uwagi od bardziej doświadczonych kolegów mile widziane, bo niestety ale wszystko to moje własne próby sklejenia czegoś z informacji, które zdobyłem. Opisując skromnie co dzieje się w implementacji i jakie są założenia: 1. Brak możliwości stworzenia podstawowej klasy // virtual destructor virtual ~TypeButton() = 0; // virtual methods virtual void ButtonPressed() = 0; virtual void ButtonNotPressed() = 0; Chciałem stworzyć sobie klasę, która będzie miała zaimplementowaną swoista "blokade", żeby nie kusiło stworzenia obiektu, który nie posiada implementacji dla funkcji obsługującej przycisk. W tym celu zmieniłem destruktor na wirtualny i przypisałem mu 0. W ten sposób ustawiłem destruktor czysto wirtualny, czyli taki którego nie można wywołać. Co za tym idzie, nie można również stworzyć obiektu. 2. Funkcje Pressed i NotPressed są wykonywane raz Funkcje wykonywane są raz tylko przy zmianie stanów z Debbounce -> Pressed i z Pressed-> Idle. Zabezpieczało mnie to przed wchodzeniem ciągle, w funkcje, która ustawia stan na wysoki/niski. 3. Działanie głównie opiera się na sprawdzaniu w pętli metody ButtonTask() void TypeButton::ButtonTask() { switch (this->State) { case IDLE: ButtonIdle(); break; case DEBBOUNCE: ButtonDebbounce(); break; case PRESSED: ButtonIsPressed(); break; default: break; } } Metoda za każdym razem sprawdza aktualny stan obiektu, z którego została wywoływana (this->State) i wykonuje funkcje, zależnie od tego w jakim stanie znajduje się aktualnie przycisk. 4. Opierając się na Klasie-rodzic można dorabiać dalej własne implementacje klasy-dziecka, które bedą wykonywać inne zadania. Kwestia inwencji własnej. Ogólnie, jak wspomniałem wcześniej wygląda to jak przerost formy nad treścią, ale obecnie bardzo mi ułatwia pisanie prototypów bo nie musze znowu martwić czy dobrze napisałem kod do przycisku. No i było bardzo fajną lekcją w kontekście robienia klas/metod wirtualnych. Z napotkanych problemów: Mimo, że zaimplementowałem destruktor jako pure virtual to i tak musiałem dodać w pliku .cpp na początku: TypeButton::~TypeButton(){} Bez tego dostawałem ciągłe błedy o tym, że w klasie-dziecko jest nieznany typ destruktora własnie TypeButton::~TypeButton(). Trochę nie mogłem zrozumieć czemu musiałem to zrobić. Wygrzebałem to w jednym z tematów na Stack Overflow i było to tam opisane czymś w rodzaju "Czasem trzeba dodać tego typu deklaracje mimo pure virutal destruktora". Albo ja nie uważałem podczas uczenia się, ale rzadko kiedy widziałem by ktoś miał taki problem. Może ktoś dużo mądrzejszy mi to wytłumaczy? 🙂 To by było na tyle. Wszelakie uwagi mile widziane
  25. Witam. Próbuję rozpocząć swoją przygodę z arduino. Na początek wybrałem płytkę TTGO esp32 z wyświetlaczem. Mam już pewne podstawy jeśli chodzi o samo programowanie w różnych językach ale nigdy nie próbowałem programować urządzeń. Po napisaniu najprostszego programu typu "hello word" albo wybraniu jakiegokolwiek gotowca nie mogę uruchomić go na swojej płytce. Przesyłanie zawsze kończy się komunikatem "hard resetting via RTS pin" i na tym koniec. Resetowanie przyciskiem umieszczanym na płycie nie daje rezultatów. Na YT znalazłem kilka filmów na ten temat. Między innymi ten poniższy, który pokazuje, że nie jest to żaden problem natomiast nic to nie zmienia. Nie uruchamia mi się program. Strasznie sie napaliłem na płytki arduino, widzę wiele zastosowań ale już 3 dzień nie mogę wystartować i powoli opadam z sił a podejrzewam, że to jakiś problem początkującego. Pomożecie?
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.