Przeszukaj forum
Pokazywanie wyników dla tagów 'M5Stack'.
Znaleziono 7 wyników
-
M5Stack Gra DIY zielone/czerwone światło inspirowana Squid Game
H1M4W4R1 opublikował temat w Projekty - DIY (mini)
Czasami najciekawsze projekty DIY nie muszą być skomplikowane. Wystarczy kilka gotowych modułów, prosta obudowa z drukarki 3D i krótki program, aby zbudować urządzenie, które od razu zachęca do zabawy. Tym razem przygotujemy prostą zabawkę działającą jak elektroniczna wersja gry „zielone światło, czerwone światło”, znanej między innymi z serialu Squid Game. Rysunek inspirowany serialem Urządzenie losowo przełącza kolor świecenia między zielonym i czerwonym. Gdy świeci się zielone światło, można się poruszać. Gdy zapali się czerwone, czujnik ruchu zaczyna obserwować otoczenie. Wykrycie ruchu powoduje trzykrotne mignięcie diod na żółto, po czym urządzenie wraca do zielonego światła na co najmniej kilka sekund. Artykuł powstał we współpracy z firmą Botland. Co zbudujemy? Projekt składa się z niewielkiego modułu M5Stack Matrix v1.1 z matrycą LED oraz czujnika ruchu (M5Stack Unit PIR lub M5Stack Unit TMOS PIR) umieszczonych w prostej, drukowanej obudowie. Całość zasilana jest przez USB i po uruchomieniu działa w pełni autonomicznie. Nie trzeba podłączać komputera, telefonu ani żadnej aplikacji sterującej. Urządzenie nie posiada wbudowanego akumulatora, więc do działania wymaga podłączenia do zasilacza USB, powerbanku lub portu USB komputera. Takie rozwiązanie upraszcza konstrukcję i eliminuje konieczność ładowania akumulatora. Moduł z matrycą został wybrany jako pokazanie jednej z możliwości, równie dobrze można byłoby użyć modułu z matrycą LCD. Czujniki PIR zostały dobrane do kompletu z modułem, aczkolwiek inne, które posiadają wyjścia kompatybilne z ekosystemem Grove również powinny działać prawidłowo, aczkolwiek nie będą pasowały do obudowy z tego wpisu. Teoretycznie można było użyć np. płytek Xiao, które pozwalają na łatwe dodanie akumulatora, aczkolwiek projekt miał w założeniu być prosty i zachęcać do nauki elektroniki, a lutowanie zwykle odstrasza nowe osoby, stąd wybór padł na ekosystem M5Stack. Zielone światło - można się poruszać Obudowa widoczna na zdjęciach została wydrukowana z filamentu PETG. W tym projekcie obudowa nie jest narażona na duże obciążenia mechaniczne, więc najważniejsze jest poprawne spasowanie elementów i estetyka wydruku. Czujnik PIR można zamocować dwoma śrubami M4 z podkładkami, ale na zdjęciu został on po prostu włożony do obudowy, co wystarczyło, by się solidnie w niej trzymał. Jak działa urządzenie? Zasada działania jest bardzo prosta. Po podłączeniu zasilania program uruchamia się automatycznie i zaczyna losowo przełączać stan urządzenia. W programie zapisane są na sztywno parametry określające, jak długo może trwać zielone i czerwone światło. Dzięki temu urządzenie nie przełącza się zawsze po takim samym czasie, a zabawa jest mniej przewidywalna. Gdy świeci się zielone światło, czujnik ruchu nie powoduje żadnej reakcji. Jest to moment, w którym gracz może się poruszać. Gdy zapali się czerwone światło, urządzenie zaczyna sprawdzać wskazania czujnika PIR. Wykrycie ruchu oznacza przegraną rundę. W takiej sytuacji matryca LED miga trzy razy na żółto, a następnie urządzenie automatycznie przełącza się na zielone światło. Zielone światło świeci wtedy przez minimum 3 sekundy, aby gracz miał chwilę na wznowienie zabawy. Czerwone światło - lepiej unikać ruchu Czujnik PIR i przewód Grove Do wykrywania ruchu używany jest moduł M5Stack Unit PIR albo M5Stack Unit TMOS PIR. Oba moduły można połączyć z M5Stack Matrix v1.1 za pomocą krótkiego przewodu Grove, który znajduje się w pakiecie z modułami. Dzięki temu montaż jest prosty i nie wymaga lutowania. W praktyce najwygodniej jest umieścić czujnik z przodu obudowy, tak aby „patrzył” w stronę gracza. Matryca LED powinna być dobrze widoczna z tej samej strony. Warto zwrócić uwagę, aby obudowa nie zasłaniała pola widzenia czujnika. Stąd też obudowa została stworzona w formie "kamerki internetowej". Montaż w obudowie Obudowa została zaprojektowana tak, aby pomieścić oba moduły. Przewód jest umieszczony pod obudową, gdyż lubię taką estetykę. Model 3D udostępniony jest w formacie STEP (który można go łatwo zmodyfikować w większości programów CAD) oraz formacie STL (do druku 3D). Obudowa widziana od tyłu Najpierw należy wydrukować elementy obudowy. Następnie w obudowie montujemy moduł M5Stack Matrix v1.1 oraz czujnik PIR. Po połączeniu ich przewodem Grove warto sprawdzić, czy przewód nie jest zagięty pod zbyt dużym kątem i czy nie "wyciąga" elementów elektronicznych. Poniżej możesz znaleźć pliki obudowy do samodzielnego wydruku lub modyfikacji. Przed wydrukiem warto sprawdzić orientację elementów, gdyż mogą one nie być optymalnie ustawione. Moje ustawienia wydruku dla drukarki BambuLab X1 Carbon Modele.zip Program urządzenia Program wgrany do urządzenia realizuje kilka prostych zadań: losuje czas trwania zielonego i czerwonego światła, wyświetla odpowiedni kolor na matrycy LED, sprawdza czujnik ruchu tylko podczas czerwonego światła, po wykryciu ruchu miga trzy razy na żółto, po sygnale błędu przełącza urządzenie na zielone światło na minimum 3 sekundy. Wszystkie parametry są zapisane bezpośrednio w kodzie. Dzięki temu projekt jest prosty i nie wymaga dodatkowego panelu konfiguracyjnego. Osoby, które chcą zmienić zachowanie urządzenia, mogą samodzielnie edytować program, na przykład zmieniając minimalny i maksymalny czas świecenia poszczególnych kolorów. Cały projekt mona pobrać tutaj: Program.zip #include <Arduino.h> #include <FastLED.h> #include <M5_STHS34PF80.h> #include <Wire.h> #include <assert.h> /** * @brief Domyślna konfiguracja czasu działania świateł. * * Makra RG_* mogą zostać nadpisane z poziomu platformio.ini przez build_flags, * np. -DRG_GREEN_MIN_MS=3000UL. Pozwala to zmieniać zachowanie programu bez * modyfikowania kodu automatu stanów. */ #ifndef RG_GREEN_MIN_MS #define RG_GREEN_MIN_MS 4000UL #endif #ifndef RG_GREEN_MAX_MS #define RG_GREEN_MAX_MS 9000UL #endif #ifndef RG_RED_MIN_MS #define RG_RED_MIN_MS 4000UL #endif #ifndef RG_RED_MAX_MS #define RG_RED_MAX_MS 9000UL #endif #ifndef RG_TRANSITION_MS #define RG_TRANSITION_MS 500UL #endif #ifndef RG_PENALTY_GREEN_MS #define RG_PENALTY_GREEN_MS 3000UL #endif #ifndef RG_TMOS_MOTION_THRESHOLD #define RG_TMOS_MOTION_THRESHOLD 60 #endif static const uint8_t kLedPin = 27U; static const uint8_t kLedCount = 25U; static const uint8_t kPirSignalPin = 32U; static const uint8_t kGroveSdaPin = 26U; static const uint8_t kGroveSclPin = 32U; /** * @brief Stałe sprzętowe oraz przepisana konfiguracja czasów pracy programu. * * Sekcja zawiera mapowanie pinów ATOM Matrix/Grove, zakresy losowania czasów, * parametry migania ostrzegawczego oraz próg detekcji ruchu dla czujnika TMOS. */ static const uint32_t kGreenMinMs = RG_GREEN_MIN_MS; static const uint32_t kGreenMaxMs = RG_GREEN_MAX_MS; static const uint32_t kRedMinMs = RG_RED_MIN_MS; static const uint32_t kRedMaxMs = RG_RED_MAX_MS; static const uint32_t kTransitionMs = RG_TRANSITION_MS; static const uint32_t kPenaltyGreenMs = RG_PENALTY_GREEN_MS; static const uint32_t kYellowBlinkTotalMs = 2000UL; static const uint8_t kYellowBlinkCount = 3U; static const uint8_t kBrightness = 20U; static const int16_t kTmosMotionThreshold = RG_TMOS_MOTION_THRESHOLD; enum LightState { LIGHT_GREEN, LIGHT_RED, LIGHT_TRANSITION }; /** * @brief Typ aktywnego czujnika ruchu wybrany podczas inicjalizacji. * * Program najpierw sprawdza obecność TMOS na magistrali I2C. Jeśli czujnik * odpowiada i przejdzie inicjalizację, wykorzystywany jest TMOS. W przeciwnym * razie program konfiguruje klasyczny PIR z wyjściem cyfrowym. */ enum MotionSensor { SENSOR_DIGITAL_PIR, SENSOR_TMOS_PIR }; static CRGB g_leds[kLedCount]; static LightState g_state = LIGHT_GREEN; static LightState g_next_state = LIGHT_RED; static MotionSensor g_motion_sensor = SENSOR_DIGITAL_PIR; static uint32_t g_state_started_ms = 0UL; static uint32_t g_state_duration_ms = 0UL; static uint32_t g_after_transition_duration_ms = 0UL; static CRGB g_from_color = CRGB::Black; static CRGB g_to_color = CRGB::Green; static M5_STHS34PF80 g_tmos; static bool g_tmos_ready = false; /** * @brief Losuje czas trwania stanu w podanym zakresie. * * Metoda wykonuje losowanie czasu w milisekundach w celu nadania zmiennej, * nieprzewidywalnej długości fazie zielonej lub czerwonej. * * @param min_ms Minimalny czas trwania stanu w milisekundach. * @param max_ms Maksymalny czas trwania stanu w milisekundach. * @return Wylosowany czas z przedziału domkniętego [min_ms, max_ms]. */ static uint32_t randomDuration(uint32_t min_ms, uint32_t max_ms) { assert(min_ms > 0UL); assert(max_ms >= min_ms); return random(min_ms, max_ms + 1UL); } /** * @brief Interpoluje kolor pomiędzy dwoma wartościami RGB. * * Metoda wykonuje liniowe mieszanie kolorów w celu płynnego przejścia pomiędzy * światłem zielonym i czerwonym w czasie zdefiniowanym przez kTransitionMs. * * @param from_color Kolor początkowy przejścia. * @param to_color Kolor docelowy przejścia. * @param amount Pozycja interpolacji w zakresie 0..255. * @return Kolor pośredni wyliczony przez bibliotekę FastLED. */ static CRGB lerpColor(CRGB from_color, CRGB to_color, uint8_t amount) { assert(kLedCount == 25U); assert(kBrightness <= 100U); return blend(from_color, to_color, amount); } /** * @brief Aktualizuje całą matrycę LED jednym kolorem. * * Metoda ustawia ten sam kolor na wszystkich diodach WS2812 w celu zachowania * jednolitego wyglądu sygnalizacji świetlnej. * * @param color Kolor, który ma zostać wyświetlony na wszystkich diodach. */ static void showAll(CRGB color) { assert(kLedCount > 0U); assert(kLedCount <= 25U); fill_solid(g_leds, kLedCount, color); FastLED.show(); } /** * @brief Ustawia bieżący stan automatu świateł. * * Metoda zapisuje nowy stan, czas jego rozpoczęcia oraz planowany czas trwania * w celu późniejszego sterowania przejściami w funkcji loop(). * * @param state Stan, który ma zostać aktywowany. * @param duration_ms Czas obowiązywania stanu w milisekundach. */ static void setState(LightState state, uint32_t duration_ms) { assert(duration_ms > 0UL); assert(state == LIGHT_GREEN || state == LIGHT_RED || state == LIGHT_TRANSITION); g_state = state; g_state_started_ms = millis(); g_state_duration_ms = duration_ms; } /** * @brief Rozpoczyna płynne przejście do wskazanego światła. * * Metoda zapisuje kolor początkowy, kolor docelowy i czas docelowego stanu * w celu obsłużenia przejścia przez handleTransition(). * * @param target_state Docelowy stan światła po zakończeniu przejścia. * @param target_duration_ms Czas trwania docelowego stanu po przejściu. */ static void startTransition(LightState target_state, uint32_t target_duration_ms) { assert(target_duration_ms > 0UL); assert(target_state == LIGHT_GREEN || target_state == LIGHT_RED); g_from_color = (g_state == LIGHT_GREEN) ? CRGB::Green : CRGB::Red; g_to_color = (target_state == LIGHT_GREEN) ? CRGB::Green : CRGB::Red; g_next_state = target_state; g_after_transition_duration_ms = target_duration_ms; setState(LIGHT_TRANSITION, kTransitionMs); } /** * @brief Uruchamia fazę zielonego światła. * * Metoda losuje czas zielonego światła i wymusza dolny limit czasu w celu * zapewnienia minimum kPenaltyGreenMs po wykryciu ruchu na czerwonym. * * @param min_duration_ms Minimalny dopuszczalny czas zielonego światła. */ static void startGreen(uint32_t min_duration_ms) { const uint32_t random_ms = randomDuration(kGreenMinMs, kGreenMaxMs); assert(min_duration_ms > 0UL); assert(random_ms >= kGreenMinMs); const uint32_t duration_ms = (random_ms < min_duration_ms) ? min_duration_ms : random_ms; startTransition(LIGHT_GREEN, duration_ms); } /** * @brief Uruchamia fazę czerwonego światła. * * Metoda losuje czas czerwonego światła z konfiguracji w celu utrzymania * podstawowego cyklu pracy urządzenia. */ static void startRed(void) { const uint32_t duration_ms = randomDuration(kRedMinMs, kRedMaxMs); assert(duration_ms >= kRedMinMs); assert(duration_ms <= kRedMaxMs); startTransition(LIGHT_RED, duration_ms); } /** * @brief Sprawdza stan klasycznego czujnika PIR. * * Metoda odczytuje cyfrowy pin modułu PIR w celu wykrycia sygnału ruchu * zgłaszanego przez czujnik podłączony do portu Grove. * * @return true, jeśli pin PIR ma stan wysoki; false w przeciwnym razie. */ static bool digitalPirDetected(void) { const int value = digitalRead(kPirSignalPin); assert(value == LOW || value == HIGH); assert(kPirSignalPin < 40U); return value == HIGH; } /** * @brief Sprawdza stan czujnika TMOS STHS34PF80. * * Metoda odczytuje wartość ruchu z czujnika TMOS w celu wykrycia obecności lub * ruchu bez korzystania z cyfrowego wejścia PIR. * * @return true, jeśli TMOS jest gotowy, odczyt się udał i wartość ruchu * przekracza skonfigurowany próg; false w przeciwnym razie. */ static bool tmosPirDetected(void) { int16_t motion = 0; const int32_t result = g_tmos.getMotionValue(&motion); assert(kTmosMotionThreshold > 0); assert(kGroveSdaPin != kGroveSclPin); return g_tmos_ready && result == 0 && motion >= kTmosMotionThreshold; } /** * @brief Wykonuje detekcję ruchu przez aktywny czujnik. * * Metoda wybiera właściwy backend pomiarowy w celu ukrycia różnic pomiędzy * TMOS po I2C oraz klasycznym PIR z wyjściem cyfrowym. * * @return true, jeśli aktywny czujnik zgłasza ruch; false w przeciwnym razie. */ static bool motionDetected(void) { assert(g_motion_sensor == SENSOR_DIGITAL_PIR || g_motion_sensor == SENSOR_TMOS_PIR); assert(kPirSignalPin < 40U); return (g_motion_sensor == SENSOR_TMOS_PIR) ? tmosPirDetected() : digitalPirDetected(); } /** * @brief Sygnalizuje naruszenie czerwonego światła. * * Metoda wykonuje trzy żółte mignięcia w czasie kYellowBlinkTotalMs w celu * pokazania, że ruch został wykryty podczas fazy czerwonej. */ static void blinkPenalty(void) { const uint32_t segment_ms = kYellowBlinkTotalMs / (kYellowBlinkCount * 2UL); assert(segment_ms > 0UL); assert(kYellowBlinkCount == 3U); for (uint8_t index = 0U; index < kYellowBlinkCount; ++index) { showAll(CRGB::Yellow); delay(segment_ms); showAll(CRGB::Black); delay(segment_ms); } } /** * @brief Obsługuje stan płynnego przejścia między kolorami. * * Metoda wylicza postęp przejścia na podstawie czasu od startu stanu w celu * płynnego mieszania koloru początkowego z docelowym. Po zakończeniu przejścia * aktywuje stan zapisany w g_next_state. * * @param elapsed_ms Czas, który upłynął od rozpoczęcia stanu przejściowego. */ static void handleTransition(uint32_t elapsed_ms) { assert(g_state == LIGHT_TRANSITION); assert(kTransitionMs > 0UL); if (elapsed_ms >= kTransitionMs) { setState(g_next_state, g_after_transition_duration_ms); showAll(g_to_color); return; } const uint8_t amount = static_cast<uint8_t>((elapsed_ms * 255UL) / kTransitionMs); showAll(lerpColor(g_from_color, g_to_color, amount)); } /** * @brief Obsługuje fazę zielonego światła. * * Metoda utrzymuje matrycę w kolorze zielonym w celu realizacji bezpiecznej * fazy ruchu. Po upływie zaplanowanego czasu rozpoczyna przejście do czerwieni. * * @param elapsed_ms Czas, który upłynął od rozpoczęcia zielonego światła. */ static void handleGreen(uint32_t elapsed_ms) { assert(g_state == LIGHT_GREEN); assert(g_state_duration_ms > 0UL); showAll(CRGB::Green); if (elapsed_ms >= g_state_duration_ms) { startRed(); } } /** * @brief Obsługuje fazę czerwonego światła. * * Metoda utrzymuje matrycę w kolorze czerwonym i sprawdza czujnik ruchu w celu * wykrycia naruszenia. Wykryty ruch uruchamia sygnał żółty i wymusza powrót do * zielonego na co najmniej kPenaltyGreenMs. * * @param elapsed_ms Czas, który upłynął od rozpoczęcia czerwonego światła. */ static void handleRed(uint32_t elapsed_ms) { assert(g_state == LIGHT_RED); assert(g_state_duration_ms > 0UL); showAll(CRGB::Red); if (motionDetected()) { blinkPenalty(); startGreen(kPenaltyGreenMs); } else if (elapsed_ms >= g_state_duration_ms) { startGreen(kGreenMinMs); } } /** * @brief Sprawdza odpowiedź urządzenia na magistrali I2C. * * Metoda wykonuje krótką transmisję adresową w celu ustalenia, czy na porcie * Grove znajduje się czujnik TMOS o oczekiwanym adresie. * * @param address Siedmiobitowy adres I2C sprawdzanego urządzenia. * @return true, jeśli urządzenie potwierdziło adres; false w przeciwnym razie. */ static bool i2cDeviceExists(uint8_t address) { assert(address > 0U); assert(address < 128U); Wire.beginTransmission(address); return Wire.endTransmission() == 0U; } /** * @brief Inicjalizuje i wybiera aktywny czujnik ruchu. * * Metoda uruchamia magistralę I2C, wykrywa TMOS i próbuje go zainicjalizować * w celu użycia dokładniejszego czujnika, jeśli jest podłączony. Gdy TMOS nie * odpowiada albo inicjalizacja się nie powiedzie, metoda konfiguruje wejście * cyfrowe dla klasycznego PIR. */ static void setupMotionSensor(void) { assert(kGroveSdaPin == 26U); assert(kGroveSclPin == 32U); Wire.begin(kGroveSdaPin, kGroveSclPin); if (i2cDeviceExists(STHS34PF80_I2C_ADDRESS)) { g_tmos_ready = g_tmos.begin(&Wire, STHS34PF80_I2C_ADDRESS, kGroveSdaPin, kGroveSclPin); if (g_tmos_ready) { const int32_t init_result = g_tmos.init(); g_tmos_ready = init_result == 0; } } if (g_tmos_ready) { g_motion_sensor = SENSOR_TMOS_PIR; } else { g_motion_sensor = SENSOR_DIGITAL_PIR; pinMode(kPirSignalPin, INPUT); } } /** * @brief Inicjalizuje urządzenie po starcie mikrokontrolera. * * Metoda przygotowuje port szeregowy, generator losowy, sterownik WS2812, * aktywny czujnik ruchu oraz początkowy stan zielonego światła. */ void setup() { Serial.begin(115200); randomSeed(esp_random()); FastLED.addLeds<WS2812, kLedPin, GRB>(g_leds, kLedCount); FastLED.setBrightness(kBrightness); setupMotionSensor(); setState(LIGHT_GREEN, randomDuration(kGreenMinMs, kGreenMaxMs)); showAll(CRGB::Green); } /** * @brief Wykonuje główną pętlę automatu świateł. * * Metoda oblicza czas trwania aktualnego stanu i deleguje obsługę do funkcji * właściwej dla zielonego, czerwonego albo przejściowego stanu matrycy. */ void loop() { const uint32_t now_ms = millis(); const uint32_t elapsed_ms = now_ms - g_state_started_ms; if (g_state == LIGHT_TRANSITION) { handleTransition(elapsed_ms); } else if (g_state == LIGHT_GREEN) { handleGreen(elapsed_ms); } else { handleRed(elapsed_ms); } delay(20U); } Tworzenia programu nie będę opisywał, gdyż jest on względnie krótki i posiada dokumentację w języku polskim. Jeżeli ktoś będzie miał pytania śmiało służę pomocą. Możliwe rozszerzenia projektu Podstawowa wersja urządzenia działa w pełni lokalnie i nie wymaga żadnej komunikacji z innymi urządzeniami. To wystarcza do prostej zabawy lub demonstracji działania czujnika ruchu. Bardziej zaawansowane osoby mogą rozbudować projekt o serwer WebSocket. W takiej wersji urządzenie mogłoby wysyłać informację o wykryciu ruchu do wskazanego punktu docelowego. Pozwoliłoby to zintegrować zabawkę z interaktywną grą komputerową, aplikacją webową albo innym systemem reagującym na zdarzenia z prawdziwego świata. Można też dodać konfigurację czasów przez Wi-Fi, efekty dźwiękowe, licznik punktów albo tryb wieloosobowy. Warto jednak zacząć od najprostszej wersji, ponieważ już ona dobrze pokazuje, jak połączyć gotowe moduły M5Stack, czujnik ruchu i wydrukowaną obudowę w kompletny projekt DIY. Podsumowanie Ten projekt jest dobrym przykładem niewielkiego urządzenia, które można wykonać bez skomplikowanego montażu elektronicznego. Gotowe moduły M5Stack ograniczają liczbę połączeń do minimum, a drukowana obudowa sprawia, że całość wygląda jak samodzielne urządzenie, a nie tylko testowy układ na biurku. Po podłączeniu zasilania zabawka działa autonomicznie: losowo zmienia światło, wykrywa ruch tylko w odpowiednim momencie i sygnalizuje przegraną rundę żółtym miganiem. To prosty, ale efektowny projekt dla osób, które chcą połączyć elektronikę, programowanie i druk 3D w jednej praktycznej konstrukcji. Post Scriptum Przerobiłem również urządzenie na wersję BLE. Działa poprawnie, ale niestety kod jest nieudokumentowany, więc jest on dedykowany głównie dla osób, które są w stanie go przeczytać i przeanalizować we własnym zakresie. -
M5Stack M5Stack - główne moduły i ich zastosowanie
H1M4W4R1 opublikował temat w Artykuły użytkowników
Wstęp Ten artykuł jest dedykowany dla osób, które nie są zaznajomione z ekosystemem M5Stack i chcą się dowiedzieć nieco więcej o modułach głównych należących do tego ekosystemu. Artykuł powstał we współpracy z firmą Botland. Moduł M5StickC Plus2 Czym jest M5Stack? Ekosystem M5Stack to zestaw modułowych płytek i akcesoriów elektronicznych, które pozwalają bardzo szybko budować urządzenia z mikrokontrolerem. W praktyce jest to coś pomiędzy zestawem edukacyjnym a gotową platformą do prototypowania. Najczęściej bazuje na układzie ESP32, czyli popularnym mikrokontrolerze z WiFi i Bluetooth. Arduino Nesso - moduł typu Stick z wbudowaną komunikacją LoRa (produkowany przez M5Stack dla Arduino) Idea jest prosta. Zamiast budować układ od zera na płytce stykowej, bierzesz gotowy moduł i łączysz go z innymi elementami jak klocki. W samym ekosystemie występują moduły główne oraz unity (jednostki), które dodają nowe funkcje do modułu głównego. Dzięki temu prototypowanie staje się szybkie i przyjemne, a elektronik nie gubi się w gąszczu przewodów. Z tego ekosystemu dość często korzystają również firmy, które tworzą tzw. MVP (minimalny produkt), w celu wykonania testów rynkowych. Serie modułów M5Stack Moduły M5Stack (na moment pisania artykułu) dzielą się na 4 główne serii: M5Stack Atom, M5Stack Core, M5Stack Stamp oraz M5Stack Stick. Każda z nich ma swoje zalety i ograniczenia, a tym samym konkretne zastosowania. Seria Atom jest przystosowana głównie do zastosowań IoT i często przychodzi z wgranym odpowiednim Firmware (np. Atom Echo jest dostarczany z wgranym asystentem głosowym kompatybilnym z HomeAssistant. Są to względnie małe moduły (24x24mm), które pasują idealnie do wszelkich miniaturowych rozwiązań IoT. Na szczególną uwagę zasługują moduły Echo posiadające wbudowany głośnik, a więc będące idealnymi do wielu rozwiązań z powiadomieniami dźwiękowymi. Przykładowe moduły Atom Seria Core to produkt flagowy firmy M5Stack, który służy głównie do projektowania urządzeń. Zazwyczaj są to moduły pełne najróżniejszych peryferiów od akcelerometru przez mikrofon aż po ekran dotykowy. Najczęściej jest wykorzystywana przez osoby, które chcą się nauczyć elektroniki. Moduł CoreS3 SE Seria Stick to kolejny dość interesujący produkt, który charakteryzuje się dość sporą ilością peryferiów, ale za to dużo mniejszym rozmiarem. Są to produkty, które posiadają wbudowany akumulator, a więc sprawdzają się idealnie w rozwiązaniach przenośnych. Przykładowe moduły z serii Stick Seria Stamp jest zaś interesująca dla miłośników pająków. Posiada ona łatwo dostępne pady i minimum peryferiów, a więc pozwala w bardzo prosty sposób protoypować urządzenia na tzw. "pająka". Jest to najlepsza seria dla osób chcących zbudować funkcjonalne urządzenie w produkcji jednostkowej (czyli większości hobbystów DiY). Moduł Stamp ESP32S3 Dostępne sposoby programowania Oprócz tego, że moduły M5Stack są dość praktyczne w obsłudze to jeszcze możemy korzystać z oprogramowania UIFlow2, systemu bloczkowego programowania, który często upraszcza tworzenie projektu. Wprawdzie w dobie AI jest on dość uciążliwy (względem kodu), aczkolwiek jest to dobry sposób, by zachęcić dzieci do nauki elektroniki i programowania. Interfejs M5Stack UIFlow2 Na co zwrócić uwagę podczas doboru modułu? Podczas doboru modułu głównego zwróć przede wszystkim uwagę na: dostępne peryferia - często nieznacznie droższy moduł główny może oszczędzić zakupu np. dodatkowego akcelerometru wbudowany procesor - szczególnie jeżeli chcesz używać USB, gdyż np. Atom Echo USB nie wspiera, a Atom EchoS3R już tak rodzaje wyjść na peryferia - część peryferiów jest łatwiej dostępna w wersji Hat, a część w wersji Unit; są to różne metody podłączeń, które nie są dostępne we wszystkich modułach ilość wyjść na peryferia (lub padów) - o ile można używać ekspanderów, tak znacznie lepiej jeżeli mamy te złącza wyprowadzone bezpośrednio z procesora Przykładowe projekty Jeszcze nie jesteś pewien czy warto korzystać z ekosystemu M5Stack? Obejrzyj kilka przykładowych projektów: Wewnętrzna stacja klimatyczna Podlewaczka roślin w stylu minimalistycznym Zabawy z autoryzacją - RFID vs odcisk palca -
M5Stack Podlewaczka roślin w stylu minimalistycznym
H1M4W4R1 opublikował temat w Projekty - DIY (mini)
W tym artykule, mała dygresja o podlewaniu roślinek. Jako, że kiedyś udało mi się zasuszyć kaktusa oraz to, że dzięki współpracy z Botlandem miałem moduł podlewania roślin to postanowiłem zbudować minimalistyczny moduł do podlewania mojej papryczki habanero (ma działać i nie kłuć w oczy). Moduł podlewania - cover dla ładnego wyglądu na głównej Elektronika i mechanika Wybór padł na wyżej wymieniony moduł podlewania roślin oraz na M5 Atom S3R, który nadaje się idealnie ze względu na wbudowany LCD, dzięki czemu łatwo zauważymy czy moduł jest zasilany oraz jaki jest obecnie status rośliny. Myślałem o dołożeniu akumulatorka, aczkolwiek pobór prądu pompy szybko by go zużywał (albo byłby zbyt duży), więc postanowiłem go pominąć i zasilać urządzenie ze złącza USB-C. Niestety M5 Atom nie posiada otworów montażowych i trzeba było zaprojektować i wdrożyć obudowę, do której zostanie zamocowany, a która te otwory doda (by móc go przykręcić bezpośrednio do modułu podlewającego). Model został zaprojektowan w Fusion360 i był stworzony na podstawie rysunków producenta. Krawędzie zostały zaokrąglone (lub ścięte), by przypadkiem nie rozciąć sobie palca (można się zdziwić jak ostry potrafi być plastik z drukarki 3D). STL.zip Obudowa dla M5 ATOM Oprogramowanie - wstępne przygotowania Na starcie trzeba było wykorzystać M5Burner, by wgrać firmware UIFlow2 na płytkę. Standardowo zapomniałem tego zrobić na początku, więc dla zapominalskich przypominam: bez tego UIFlow nie wgra oprogramowania O wgrywaniu rozpisywałem się już w tym wątku, a nie lubię się powtarzać. Mając LCD stwierdziłem, że dobrym pomysłem będzie wyświetlanie emotek na ekranie. Niestety wszystkie, które znajdowałem w sieci były na płatnych serwisach z plikami graficznymi, a płacić nie zamierzałem. Poszedłem więc do starego zaufanego przyjaciela zwanego ChatGPT i poprosiłem go o wygenerowanie buziek. Rezultat poniżej. Emoji wygenerowane przez ChatGPT Wygląd był w sam raz, a więc teraz wystarczyło to pociąć. W ruch poszła ciężka artyleria: Paint3D (ze względu na bardzo dobre zaznaczanie magiczne) oraz Affinity Designer 2. Obróbka obrazu przy użyciu Paint3D oraz Affinity Designer 2 Obróbka była prosta: zaznaczyć magicznie każdą buźkę z osobna i przerobić ją na osobny element (dzieje się to automatycznie po wykonaniu zaznaczenia magicznego). Potem skopiować element to Affinity Designer 2, którego kanwa jest odrobinę większa niż rozmiar elementu (do sprawdzenia użyłem zwykłego Painta, w którym zmniejszyłem kanwę do minimalnych rozmiarów i wkleiłem obrazek; zwykły Paint zawsze skaluje kanwę do rozmiaru obrazka, a wartość wyświetlana jest na dole). W Affinity Designer 2 wystarczyło ustawić anchor point nad środku obrazka, przenieść go na środek (połowa szerokości i wysokości kanwy) i wyeksportować do PNG/JPG. Dla leniwych gotowiec: Emoji.zip (wersja przezroczysta i z czarnym tłem). Oryginalnie chciałem użyć wersji przezroczystej, ale okazało się, że M5 nie czyści ekranu i pojawiały się paski. Dlatego do emoji zostało dodane czarne tło, które gwarantuje prawidłowe wyświetlanie obrazków. Oprogramowanie - ustawienie UIFlow2 oraz ekran Następnym etapem było przygotowanie oprogramowania w UIFlow2. Do tego celu założyłem nowy projekt na bazie ATOM S3R oraz dodałem moduł Watering Unit z menu po lewej stronie. Wybór modułu Watering Unit w UIFlow2 Kolejnym etapem było dodanie obrazków oraz kanwy obrazu na ekranie. W tym celu z paska po lewej stronie wybrałem "Image" oraz ustawiłem jego rozmiar tak, by pokrywał cały ekran. Obrazki (pliki graficzne) wgrywamy mając zaznaczoną kanwę obrazu i klikając przycisk zaznaczony na czerwono. Wgrany obrazek umieszczony na kanwie Należy też pamiętać, by podczas wgrywania zsynchronizować pliki z modułem, gdyż w innym przypadku program może nie działać poprawnie. Zapytanie o synchronizację plików (naciśnij SYNC, o ile pliki nie są już wgrane) Oprogramowanie - kod programu Kod programu w bloczkach Ostatnim elementem było stworzenie programu. Uprościłem go dzieląc go na dwie funkcje - jedna analizuje dane odczytane z czujnika, a druga zarządza pompą i obrazkiem na wyświetlaczu, ale od początku... Na starcie program inicjuje wszystko co potrzebne - mikrokontroler i moduł Unit. W następnym kroku obracamy ekran o 180 stopni, gdyż w normalnym ułożeniu spód ekranu jest od strony portu USB, a w zaprojektowanej obudowie port jest umieszczony od góry. Po tym inicjowane są dwie zmienne (właściwie to stałe, ale UIFlow ich nie rozróżnia, gdyż używa microPythona), które definiują histerezę pracy systemu. Należy dobrać je eksperymentalnie korzystając z tego, iż pętla programu po odczytaniu danych z czujnika wyświetla je na porcie szeregowym. Gdy czujnik jest suchy (dla pewności można go przetrzeć szmatką) uzyskujemy wartość dla suchego podłoża, a umieszczając czujnik w szklance z wodą otrzymujemy wartość dla 100% wilgotności. Od tych wartości bierzemy poprawkę na niedokładności pomiarowe i wpisujemy wartości do zmiennych. Opór czujnika maleje wraz ze wzrostem wilgotności, gdy pętla dotrze do funkcji analizującej wartość z czujnika weryfikujemy czy czujnik jest suchy (wartość ADC przekracza wartość graniczną dla suchego podłoża). Jeżeli tak to przypisujemy wartość 0 (czujnik suchy) do zmiennej. W innym przypadku porównujemy wartość ADC z wartością dla stanu mokrego. Jeżeli jest większa to zmieniamy wartość na 1 (czujnik mokry), a jak mniejsza to 2 (podłoże nasycone). Warto zauważyć, że wygląda to nielogicznie, ale jest jak najbardziej poprawne (nasycone podłoże ma większą wilgotność, a więc mniejszą wartość ADC niż podłoże mokre). Po zwróceniu wartości przypisujemy ją do zmiennej i uruchamiamy pętlę kontrolującą układ. Jeżeli wartość nie zmieniła się od ostatniego czasu to pomijamy cały kod (w innym przypadku obrazek może migotać lub wyświetlać się w formie skanowania). Gdy wartość uległa zmianie to aktualizujemy ją do nowej wartości i wchodzimy w analizę tej wartości względem stanu, na który się zmieniła. Gdy nowa wartość wynosi 0 (stan suchy) to aktywujemy pompę i wyświetlamy smutną buźkę. Gdy przejdziemy na 1 (stan mokry) to zmieniamy buźkę na uśmiechniętą i dezaktywujemy pompę (można usunąć dla roślin, które lubią bardzo wilgotne podłoże). W przypadku wartości 2 (stan nasycony) wyłączamy pompę i wyświetlamy szeroko uśmiechiętą buźkę. I wracamy do pętli (funkcja się kończy). Rezultat - działający układ podlewania rośliny i moja bardzo niezadowolona papryka, która pije więcej wody niż student kawy; Oryginał był prześwietlony, więc ChatGPT poprawił kolory, co by w oczy nie raziło. Wpis powstał we współpracy ze sklepem Botland, który jest dystrybutorem rozwiązań M5Stack. -
M5Stack Klawiatura USB do wprowadzania daty i godziny
H1M4W4R1 opublikował temat w Projekty - DIY (mini)
Wstęp Jako, że ostatnio dość często rozliczam się korzystając z arkuszy kalkulacyjnych (i to dość dokładnie) postanowiłem spróbować zaprojektować urządzenie, które pozwoli w szybki sposób wpisać datę i godzinę do odpowiednich pól. Wygląd urządzenia Artykuł powstał we współpracy z firmą Botland. Założenia i próba z UIFlow Urządzenie miało być akceptowalnie małe rozmiarowo i działać jako klawiatura USB. W celu minimalizacji czasu montażu postanowiłem użyć systemu M5Stack. Pierwszy wybór padł na Atom Echo oraz moduł przycisku. Rozpocząłem projekt aplikacji w UI Flow 2 i okazało się, że moduł Echo nie wspiera USB Device (nie można go użyć jako klawiatury). Trochę mnie to zdenerwowało, ale od czego jest partner, który dostarczył moduł Echo S3R, który taką funkcję już (teoretycznie) posiada. Program UIFlow2 Teoretycznie, bo gdy skończyłem projekt (i w przysłowiowym międzyczasie wydrukowałem obudowę) wyskoczyła kolejna niespodzianka: UIFlow2 nie wspiera klawiatury dla modułów Echo (mimo, że pojawia się ona na liście bloczków). MicroPython wyrzuca brak modułu USB. Teoretycznie można bawić się w kopilowanie własnego zestawu ustawień, ale to droga dla zapaleńców, a ja wolę prostotę. Padło więc na zmianę środowiska na stare zaufane PlatformIO z frameworkiem Arduino. Wersja, która nareszcie działa Po szybkim kodowaniu z pomocą Google Gemini (Claude akurat miał przerwę w działaniu) stworzyłem w pełni funkcjonalną aplikację. #ifndef CONFIG_H #define CONFIG_H // Ustawienia WiFi #define WIFI_SSID "SSID" #define WIFI_PASSWORD "PASSWD" // Ustawienia NTP #define NTP_SERVER "pool.ntp.org" #define GMT_OFFSET_SEC 0 // Obsolete #define DAYLIGHT_OFFSET_SEC 0 // Obsolete #define TZ_INFO "CET-1CEST,M3.5.0,M10.5.0/3" // Strefa czasowa // Format daty i czasu (zgodny ze strftime) // Użyj tych definicji, aby dostosować wysyłany tekst klawiatury #define DATE_FORMAT "%d/%m/%Y" // DD/MM/YYYY #define TIME_FORMAT "%H:%M" // HH:MM #define FULL_FORMAT "%Y-%m-%d %H:%M:%S" // Opcjonalny alternatywny format // Przypisanie pinów dla zewnętrznego modułu przycisku (Port A) // W Atom Echo S3R Port A: G1 (SDA) oraz G2 (SCL) // Zazwyczaj moduły przycisków od M5 używają żółtego przewodu (G1) #define EXTERNAL_BUTTON_PIN 1 #endif Powyżej plik konfiguracyjny #include <M5Unified.h> #include <WiFi.h> #include "config.h" #include "time.h" #include "USB.h" #include "USBHIDKeyboard.h" USBHIDKeyboard Keyboard; // Stałe czasowe constexpr unsigned long DEBOUNCE_MS = 250; unsigned long lastPressTime = 0; // Funkcja zwracająca sformatowany ciąg czasu String getFormattedTime(const char* format) { tm timeInfo; if (!getLocalTime(&timeInfo)) { return "NTP_ERR"; } char buffer[32]; strftime(buffer, sizeof(buffer), format, &timeInfo); return String(buffer); } void setup() { const auto cfg = M5.config(); M5.begin(cfg); // Połączenie z WiFi WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { // To opóźnienie pozwala poczekać aż ESP znajdzie sieć WiFi (czasem to chwilę zajmuje) delay(500); } // Inicjalizacja NTP configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); setenv("TZ", TZ_INFO, 1); tzset(); // Inicjalizacja pinu zewnętrznego przycisku pinMode(EXTERNAL_BUTTON_PIN, INPUT_PULLUP); // Inicjalizacja klawiatury USB HID USB.begin(); Keyboard.begin(); } void loop() { M5.update(); const unsigned long currentMillis = millis(); // 1. Wbudowany przycisk (Data) // M5.BtnA.wasPressed() obsługuje już wewnętrzne usuwanie drgań styków if (M5.BtnA.wasPressed()) { if (currentMillis - lastPressTime >= DEBOUNCE_MS) { const String dateStr = getFormattedTime(DATE_FORMAT); Keyboard.print(dateStr); lastPressTime = currentMillis; } } // 2. Zewnętrzny moduł przycisku (Czas) static bool lastExtState = HIGH; const bool currentExtState = digitalRead(EXTERNAL_BUTTON_PIN); // Wykrycie zbocza opadającego (stan aktywny niski) if (currentExtState == LOW && lastExtState == HIGH) { if (currentMillis - lastPressTime >= DEBOUNCE_MS) { const String timeStr = getFormattedTime(TIME_FORMAT); Keyboard.print(timeStr); lastPressTime = currentMillis; } } lastExtState = currentExtState; } Oraz sam kod programu, który inicjuje peryferia i WiFi, konfiguruje NTP (serwer do pobierania czasu), a w pętli oczekuje na wciśnięcie przycisku i tworzy "debouncing", który w rzeczywistości pozwala na łatwą reakcję na kliknięcie. Teoretycznie mogłem użyć wbudowanego systemu do obsługi kliknięc, ale zdarzało mu się podwójnie wykryć niektóre kliknięcia. Urządzenie dzięki wbudowanemu głośnikowi można również rozbudować o sygnał dźwiękowy odtwarzany po naciśnięciu dowolnego z przycisków. Dla ułatwienia również konfiguracja PlatformIO: [env:m5stack-atoms3r] platform = [email protected] board = esp32-s3-devkitc-1 framework = arduino board_build.arduino.memory_type = qio_opi build_flags = -DESP32S3 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCORE_DEBUG_LEVEL=5 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 lib_deps = m5stack/M5Unified @ ^0.1.12 Obudowa Obudowa została wykonana w pełni na drukarce 3D. Przyciski zostały rozdzielone na dwie części składane za pomocą imadła / prasy (taka technika pozwala na uniknięcie drukowania podpór). Dodatkowo za pomocą pracy, w odpowiednich wycięciach, są mocowane symbole D oraz H wydrukowane w innym kolorze. Użyty materiał to Fiberlogy Easy PETG (black oraz blue). Wszystkie elementy (włącznie z przewodem USB A do USB-C) zostały zamocowane wewnątrz obudowy. Moduł przycisku został przymocowany śrubami M4x12, a moduł Echo jest dociskany przez spodnią klapkę. Jedyna wada tej konstrukcji to możliwość rozłączenia przewodu USB (krótkotrwała) ze względu na dość słabą jakość gniazd USB-C w modułach Atom. Obudowa została zamknięta klapką mocowaną na 4 śruby M3x12. Pliki 3D - DateTime Keyboard.zip Prawidłowo złożony przycisk Wnętrze obudowy Filmik z działania -
M5Stack Alarm odległościowy - opinia o ekosystemie M5 Stack
H1M4W4R1 opublikował temat w Projekty - DIY (mini)
Wstęp Pozyskałem ostatnio mały zestaw do zapoznania się z ekosystemem M5 Stack (dwa moduły główne i kilka rozszerzeń) - znalazły się w nim między innymi M5Atom Echo oraz Ultrasonic-IO Unit, które wykorzystałem do testowania koncepcji alarmu, który pilnuje odległości mojej głowy od monitora. Wpis powstał we współpracy ze sklepem Botland, który jest dystrybutorem rozwiązań M5Stack. Łączenie modułów M5 Stack to czysta przyjemność Założenia Do celów testowych założyłem koncepcję: alarm działa na zasadzie pikacza w samochodzie, różni się tylko zakresem reakcji i mnożnikiem czasu między piknięciami. W projekcie wykorzystany został moduł główny M5 z wbudowanym głośnikiem oraz moduł czujnika ultradźwiękowego (przewód był w zestawie). Niestety moduły M5 Stack nie zawierają w komplecie przewodu USB-C, więc trzeba się w niego zaopatrzyć samemu. Wgrywanie oprogramowania Autorzy dostarczają oprogramowanie M5Burner, którego używamy do wgrywania wsadów na naszą kostkę. Oryginalnie Echo przychodzi z wgranym ESP32 Home Assistant, ale do naszych potrzeb wykorzystamy UIFlow2. Tutaj napotkałem dwa problemy - pierwszy (trochę wymyślony) to konieczność założenia konta, zalogowania się i przypisania urządzenia do konta... Ale to da się strawić. Drugi to straszny bałagan w liście oprogramowaniem, gdy wyszukamy UIFlow2 nie ma jednej opcji tylko są osobne wpisy dla każdego rodzaju płytki... Strasznie to nieintuicyjne, ale jak ktoś nie jest tak szybki jak ja i wybierze płytkę przed próbą wgrania niewłaściwego oprogramowania (przed tym nie ma żadnego zabezpieczenia) to raczej nie będzie miał problemów Interfejs M5 Burner Samo wgrywanie oprogramowania jest jednak dość proste - wystarczy skonfigurować kilka opcji (w tym WiFi, by móc wgrywać oprogramowanie przez OTA) czy serwery NTP (opcjonalnie) po czym użyć "Burn", przytrzymać przycisk resetu urządzenia aż mignie dioda i wybrać port pod, który podłączone jest urządzenie. Zatwierdzamy, czekamy i gotowe Wgrywanie oprogramowania na M5 Stack UI Flow2 Jak to przystało na bałaganiarzy część płytek jest kompatybilna z UIFlow, a część z UIFlow2... Na szczęście Echo jest kompatybilne z tym drugim, więc nie ma aż tak dużego problemu, aczkolwiek warto mieć to na uwadze podczas zakupów. Sama aplikacja jest przeglądarkowa, co mnie mocno zirytowało... Bo musiałem używać Chrome, gdyż Firefox nie wspiera portów szeregowych (a przynajmniej nie na moich ustawieniach bezpieczeństwa). W sumie miałem go zainstalowanego głównie z tego powodu, że lis z BLE też ma na pieńku. Dlaczego potrzebny był port szeregowy? Głównie do podglądu błędów (UIFlow2 korzysta z MicroPythona) oraz do wgrywania oprogramowania. Niestety nie wiem czy to wina mojego WiFi, które czasem ma problemy z transmisją czy jakiś problem po stronie M5, ale wgrywanie poprzez chmurę (Cloud) nie zawsze się sprawdzało. Na szczęście to alternatywne rozwiązanie istnieje. UIFlow2 jest narzędziem dla osób, które mają na bakier i z elektroniką (bo takie osoby zazwyczaj kupują produkty tytułowej firmy) i z programowaniem - jest to budowanie oprogramowania za pomocą bloczków, a prawie każdy szanujący się programista (w tym ja) woli kod, bo nie dość, że można zrobić to szybciej to jeszcze można go zoptymalizować. Coś czuję, że UIFlow2 w życiu nie da rady "uciągnąć" firmware od mojego programatora pilotów. Programowanie bloczkowe Kilka krótkich przeciągnięć myszką i kliknięć w klawiaturę i program był gotowy. Gotowy program detekcji odległości Nie będę ukrywał, miałem styczność z wieloma rodzajami programowania bloczkowego (czy to node-y czy puzzle), ale aplikacja od M5... działa całkiem dobrze. Jeżeli ktoś nie jest programistą (w sumie nawet jeżeli jest) to rozwiązanie całkiem dobrze sprawdzi się w szybkim testowaniu koncepcji. Sam program był prosty w napisaniu - zainicjować używane podzespoły, odczytać odległość, sprawdzić czy jest w zakresie (moduł Ultrasonic-IO wykrywa odległości od 20 do 4500mm) oraz odtworzyć piknięcie za pomocą wbudowanego głośnika (2kHz przez 50ms), po czym odczekać chwilę w zależności od wykrytej odległości (im bliżej tym krócej czekamy). Liczba 450mm została wybrana "na oko" i działa całkiem dobrze. Teraz chcąc dokończyć projekt wystarczy zaprojektować jakiś system montażu na górze monitora, ale to już temat na jakiś wolny weekend. Podsumowanie W mojej skromnej opinii moduły M5 są bardzo dobre do prototypowania (w szczególności, że można ich też używać w Arduino IDE i PlatformIO i nie trzeba szukać pinoutu, gdyż wszystko jest oznaczone na tyle kostki). Takie moduły (jak producent wspomina) najlepiej sprawdzą się w rękach początkujących, którzy nie chcą mieć problemów z uciążliwymi płytkami stykowymi. Również małe firmy szybciej poskładają produkt z gotowych modułów i zamkną go w obudowie niż będą męczyć się z projektowaniem autorskiej płytki drukowanej, testowaniem i całym arsenałem testów. Przy 5-10 produktach sprzedanych w ciągu miesiąca nie ma sensu się przemęczać. Kończąc ten przydługi wywód - jeżeli chcesz nauczyć się elektroniki lub zbudować MVP produktowe możesz śmiało korzystać z modułów M5 Stack. -
- poniżej interfejs do odczytu parametrów stacji Xiaomi z odczytem wilgotności i temperatury oraz stanu baterii zasilającej. - stacja Xiaomi pracuje na BLE 4.0, z M5Stack Core 0 zapewnia zasięg około 8 - 10 metrów. - w M5Stack wbudowano screen capture oraz shutdown. - aby korzystać z czujników, należy adres MAC jednego z czujników wpisać do linii [516] programu i skompilować cały projekt. - załączono także pliki binarne oraz adres programu do wgrywania do flasha esp32. Xiaomi_M5Stack_core_4.zip
-
- 5
-
-
- Xiaomi
- Screen Capture
-
(i 1 więcej)
Tagi:
-
- za ciepło na budowę skomplikowanych projektów. - Rozbudowa interfejsu OBDII do eNiro MY2020 bazującego na M5Stack-core o możliwość nagrywania ekranu LCD na kartę SD podczas jazdy to w sam raz. - Program Screen-Capture używałem już wcześniej dla zrzutów ekranu w samochodzie Gullietta na tym samym interfejsie BT. - Program autora screen-capture można znależć pod tym linkiem https://github.com/electricidea/M5Stack-Screen-Capture. - interfejs OBDII bazuje na Vgate iCAR Pro BT 4.0. - poniżej kilka zrzutów z uruchomienia na stole.
