Elektroda.pl
Elektroda.pl
X
Elektroda.pl
MetalworkMetalwork
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

ESP32 jednoczesne czytanie znaków z dwóch serial portów

14 Wrz 2019 19:22 528 19
  • Poziom 14  
    Witam
    Próbuje wykonać sterowanie dla projektu:
    https://www.elektroda.pl/rtvforum/topic3613898.html
    Ogólnie tak:
    Mam ESP32, które jest jednostka główną
    Jest Arduino mega które przesyła dane co 2ms przez Serial2
    Jest tez Aplikacja na PC, która komunikuje się z ESP32 poprzez Serial
    Problemem jest to, że jak na aplikacji wcisne dany przycisk, to aplikacja po serialu przesyła polecenie do ESP32, ale czasami odczyt nie jest poprawny

    Jak nie korzystałem z Serial2, wszystko było ok. Jak Korzystam z Serial2, to okazuje się, że czasami informacje z aplikacji są ucięte. Myślałem, że jest jakies niezależne kolejkowanie i przetrzymywanie informacji z każdego seriala, a tu sie okazuje, że jak jednocześnie przyjdzie informacja z Serial i Serial1, to ta która nadejdzie pierwsza jest odczytana poprawnie, a ta druga juz nie.
    Jak można rozwiązać ten problem?

    Poniżej przesyłam kod ESP32, jeżeli miałoby to pomóc
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dodano po 4 [minuty]:

    Myślałem o użyciu drugiego procesora, ale to nie działa
  • MetalworkMetalwork
  • Pomocny post
    Poziom 39  
    madiz08 napisał:
    Jest Arduino mega które przesyła dane co 2ms przez Serial2
    Jest tez Aplikacja na PC, która komunikuje się z ESP32 poprzez Serial

    Czy masz konwertery poziomów? Wejścia RX w ESP32 powinny otrzymywać sygnały w logice 3V3. Z opisu projektu to nie wynika.
  • MetalworkMetalwork
  • Poziom 14  

    Na powyższym filmiku widać co sie dzieje jak przesyłam tekst. W poniższym kodzie:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    widać, że to co nadejdzie z aplikacji, ma być do niej odesłane w takiej samej postaci, a niestety tak sie nie dzieje. Może to co wydaje sie dziwne to użycie '@' jako końca wiadomości. okazuje sie, że aplikacja nie wysyla chyba '\r' lub '\n', dlatego jak próbowałem za pomocą któregoś z tych znaków określić koniec linii, to nie odebrałem, żadnego stringa

    Dodano po 3 [minuty]:

    Jak odłączę przewód przesyłający dane z ArduinoMega, to nie ma żadnych problemów, każda wiadomość z aplikacji przychodzi w takiej samej postaci jak została wysłana, ale wówczas nie mam aktualnych pozycji z enkoderów

    Dodano po 3 [minuty]:

    Nie mam konwerterów, zdaję sobie sprawę, że ESP32 ma inne napiecia niż Mega, ale z tym jest ok. ESP32 cały czas pobiera poprawnie dane na RX2 z napieciem 5V i robi to bezproblemowo. Natomiast aplikacja przesyła dane po USB.
  • Pomocny post
    Poziom 39  
    Spróbuj w powyższym przykładzie, zaraz po komendzie Serial.println(dane), wydać komendę Serial.flush();

    Dodano po 47 [sekundy]:

    madiz08 napisał:
    ESP32 cały czas pobiera poprawnie dane na RX2 z napieciem 5V i robi to bezproblemowo.

    Tego akurat nie wiadomo i na pewno nie jest to poprawne.
  • Poziom 14  
    Niestety nic to nie dało, zmieniłem przesył danych z Mega co 10ms. Na poniższym filmiku chciałem pokazać ruszając osiami robota, że pozycje przesyłane są poprawnie, choc może faktycznie nigdy nie wiadomo czy cos nie przyjdzie źle
    Jest lepiej, ale nie ma pewności, że wiadomość z aplikacji nie nadejdzie w tym samym momencie co wiadomość z Megi. Na pewno w poniedziałek zamówi taki konwerter
    https://www.youtube.com/watch?v=4IcpJ1bDmdM&feature=youtu.be
    Nie wiem co jest z tym przesyłem filmów, musiałem wstawić na Youtuba

    Dodano po 1 [godziny] 3 [minuty]:

    A jednak :( , przesył z Mega do ESP32 nie jest idealny. Wpisując w serial monitorze 0.dojazd.200.150.@ wymuszam na osi 0 dojazd do pozycji 200 z prędkością 150. Testowałem raz:
    0.dojazd.200.150.@
    i z powrotem
    0.dojazd.-200.150.@
    czyli w lewo na 200 i w prawo na -200
    Zauważyłem, że co jakiś czas zatrzymuje się przed punktem docelowym, a nie powinien, bo zatrzymania jest dojazd do zadanej pozycji. założyłem pułapkę, zeby w momencie dojazdu wyświetliła się wartość pozycji i mam coś innego niż powinienem, czyli jest źle!
    Mógłbym poprosić o podanie nazwy tych konwerterów? W poniedziałek na pewno coś takiego zamówię. Powodem dodania Megi jako czytnika pozycji enkoderów było to, że ESP32 źle odczytywał impulsy z enkoderów, ale podawane na wejścia miał albo 0V albo 5V. Może gdybym zastosował się do logiki 3,3V odczyty byłyby poprawne. Jutro to sprawdzę. No nic dziękuję za zdiagnozowanie problemu
  • Pomocny post
    Poziom 39  
    madiz08 napisał:
    Mógłbym poprosić o podanie nazwy tych konwerterów?

    Jeżeli w Polsce, to pod nazwą "konwerter stanów logicznych", jeżeli u Chińczyka, to "logic level converter" ;)
    Wygląda to tak, ja na poniższych obrazkach. Ten drugi to "dedykowany" dla RX/TX, ale oba się nadają.

    ESP32 jednoczesne czytanie znaków z dwóch serial portów ESP32 jednoczesne czytanie znaków z dwóch serial portów

    Dodano po 51 [minuty]:

    Jest jeszcze jedna rzecz. W pętli loop() sekwencyjnie odczytujesz najpierw dane przez Serial2 z aplikacji PC, a następnie dane przez Serial z Mega. Jak sam zauważyłeś, może to spowodować gubienie danych z któregokolwiek źródła. Arduino HAL w ESP32 jest oparte na FreeRTOS, więc możesz skorzystać z wielozadaniowości. W najprostszym ujęciu mógłbyś zdefiniować oddzielne zadanie dla czytania danych z Mega o wyższym priorytecie niż pętla loop(), czyli wyższym niż 1.

    Poniżej podaje linki z prostymi przykładami:
    https://techtutorialsx.com/2017/05/06/esp32-arduino-creating-a-task/
    https://github.com/espressif/arduino-esp32/bl...ibraries/ESP32/examples/FreeRTOS/FreeRTOS.ino
  • Poziom 14  
    Bardzo ciekawy temat, próbowałem jeszcze wcześniej w podobny sposób przerzucić odczyt z Mega na Core 0, ale mi się nie udało. Dodałem coś takiego według zaleceń z linku
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Minusem jest to, że w tych taskach trzeba dodać delay(>=1), bo jeżeli to ma być wykonywane nieustannie to musi być w petli fro(), czy tak?
    Dodatkowo, wprowadziłem warunek, że jeżeli odczytana pozycja z megi, odbiega o 10 pozycji od poprzedniego przesyłu, to ten odczyt ma być ignorowany. Jeżeli chodzi o odczyty z megi to jest duża poprawa, ten priorytet ustawiłem na 2.
    Odczyt z aplikacji też jest ważny, zobacz jeśli możesz na poniższy filmik
    https://youtu.be/p85hkcGzs8Q
    Wciskając dany przycisk, przesyłam po prostu informacje po serialu. Jeżeli w tym samym czasie Mega przesyła dane, to dane z aplikacji nie są odebrane w całości
    W czasie 1:20, widac jak wciskam przycisk to aplikacja wysyła 3 linie:
    serialPort1.WriteLine("0.dojazd.200.100.@");
    serialPort1.WriteLine("1.dojazd.200.100.@");
    serialPort1.WriteLine("2.dojazd.-200.90.@");

    Jak widać pierwsza linia kodu nie jest odczytana poprawnie, ponieważ oś[0] się nie ruszyła, dopiero jak ponownie kliknąłem na przycisk to 3 osie znalazły sie w pozycjach 200.
    Jak można by zrobić to w taki sposób aby dane z aplikacji czytane były przez drugi procesor, czyli przez Core0?
  • Poziom 39  
    madiz08 napisał:
    Minusem jest to, że w tych taskach trzeba dodać delay(>=1), bo jeżeli to ma być wykonywane nieustannie to musi być w petli fro(), czy tak?

    Tak, nawet trzeba dodać delay() w celu określenia interwału czasowego zadania, co jaki ma się ono wywoływać. To nie jest minus, w trakcie tego delay() będą mogły się uruchamiać inne zadania, w tym pętla loop(), więc powinno być raczej dłuższe niż 1ms. Tak, jak już napisałem Arduino HAL w ESP32 opiera się na RTOS, więc delay() w danym zadaniu nie wstrzymuje wykonywania się innych zadań FreeRTOS.

    madiz08 napisał:
    Jak można by zrobić to w taki sposób aby dane z aplikacji czytane były przez drugi procesor, czyli przez Core0?

    A jak tworzysz zadanie dla odczytu danych z Mega? Nie zamieściłeś tego fragmentu kodu.

    Dodano po 2 [minuty]:

    madiz08 napisał:
    Odczyt z aplikacji też jest ważny, zobacz jeśli możesz na poniższy filmik

    To zdefiniuj kolejne zadanie dla tego odczytu o priorytecie wyższym niż loop(), ale niższym lub takim samym niż dla zadania odczytu z Mega.
  • Poziom 14  
    Aha, tak to działa! To co zamieściłem, to jest właśnie odczyt z Megi przez serial2. Aplikacja kominikuje się przez USB, czyli musi to być Serial. Zaraz zabieram się dopisanie drugiego watku i dam znać
  • Poziom 39  
    madiz08 napisał:
    To co zamieściłem, to jest właśnie odczyt z Megi przez serial2.

    Tak, zamieściłeś definicję funkcji callback taskOne() dla zadania zadeklarowanego jako? To co masz w setup() ;)
  • Poziom 14  
    Super :) , puściłem robota w pętlę i po ponad 40 płynnych trajektoriach zastopowałem. Dzięki wielkie za pomoc. Na prawdę mocne jest to ESP32
  • Poziom 39  
    madiz08 napisał:
    Jak można by zrobić to w taki sposób aby dane z aplikacji czytane były przez drugi procesor, czyli przez Core0?

    xTaskCreatePinnedToCore()
    https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/freertos.html
  • Pomocny post
    Poziom 19  
    Nie należy łączyć urządzeń 5v i 3.3V - w każdym razie nie bezpośrednio. Wejścia uP są zabezpieczone diodami. Jeśli do układu 3.3V podłączysz sygnał 5V, to oczywiście wymusisz stan wysoki, ale po przekroczeniu 4V popłynie spory prąd przez diodę zabezpieczającą. To, że się coś nie spali wynika tylko z faktu ograniczania prądu przez układ nadawczy (tu Mega). Dlatego jeśli nie chcemy konwerterów, to można:
    - nadawanie z układu 3.3V do 5V - podłączyć bezpośrednio (przeważnie działa, gdyż 3.3 V zostanie rozpoznane już jako stan wysoki). Piszę przeważnie, bo noty katalogowe zwykle wskazują nieco wyższe napięcie dla "1" w układach 5V
    - nadawanie z układu 5V do 3.3V - zastosować dzielnik (to najlepsze rozwiązanie) lub połączyć przez rezystor ok. 2.2k. Użycie rezystora wykorzystuje diodę zabezpieczającą, ale po prostu ogranicza prąd płynący przez nią.
    Myślę, że "najbiedniejsza" wersja (1 rezystor) nie uszczupli budżetu, a na pewno nie zostanie uszkodzony ESP.
  • Poziom 14  
    Ostatnio przystopowałem z tematem, ze względu na uszkodzenie grzałki od drukarki 3D (czekam na nową przesyłke z Chin), ale chciałem sprawdzić grzanie się silników osi 2 przy zwiększonym prądzie na silnikach tej osi.
    https://youtu.be/jlWJpc1fdXc
    Po drugiej godzinie, trzecia oś zaczęła boksować, nie zatrzymała się w punkcie docelowym tylko przejechała go i zatrzymała się na swojej pozycji krańcowej (mechanicznie nie mogła jechać dalej i silniki krokowe zaczęły boksować)
    Zobaczyłem, że przyczyną tego może być kawałek kodu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Odczyt z Megi mam co 5ms, jeżeli kilka razy odczyta źle, czyli odczyt będzie poza zakresem +15 lub -15 pozycji z poprzedniego odczytu to faktycznie silnik przejedzie te 15 pozycji i nawet jak prześle poprawna pozycję to i tak nie zostanie ona nadpisana w esp32.

    Wróciłem do sztywnego przypisywania tego co odczytane
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Zrobiłem tak dla każdej z trzech osi i zaczęły się dziać dziwne rzeczy, jakby robot nie wiedział co ma robić.
    Kod wysyłania danych z Mega wygląda następująco:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    A obecny odbiór w ESP32 realizowany jest przez Core0 i wygląda tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Założyłem pułapkę, że jeżeli nowa pozycja osi bedzie poza zakresem +-15 od poprzedniego odczytu, to żeby wyświetliło mi co ESP32 odebrało od Megi i tu wychodzą problemy:
    Kiedy silniki krokowe nie są załączone i ręcznie poruszam osiami nie ma najmniejszego problemu
    ESP32 jednoczesne czytanie znaków z dwóch serial portów
    Po wywołaniu trajektorii wpisując "jazda.@" robot zaczyna dojeżdżać do swoich pozycji docelowych, jak dojedzie to wysyła "nr_osi.dojechalem". W powyższym zdjęciu dojechałem do punktów docelowych ręcznie przesuwając osie i zero problemu. Następnie załączyłem silniki krokowe i załączyłem trajektorie:
    ESP32 jednoczesne czytanie znaków z dwóch serial portów

    Nie ma znaczenia czy sygnał TX z Megi puszczam przez konwerter stanów logicznych, bezpośrednio lub z rezystorem 2k2. Zawsze pojawia sie podobna liczba błedów, raz troche wiecej, raz troche mniej. No moze odziwo przy użyciu konwertera błednych transmisji jest trochę więcej,
    Już wiadomo, że przyczyną tego są zakłócenia, jeżeli bez krokowców nic złego się nie dzieje.

    ESP32 jednoczesne czytanie znaków z dwóch serial portów
    Tak wyglądają dane na oscyloskopie to z rezystorem 2k2 na linii przesyłowej (który jest obecnie)

    ESP32 jednoczesne czytanie znaków z dwóch serial portów
    a tak po dodaniu kondensatora 47pF linia TX Megi i GND. Po powiększeniu, którego nie mam na zdjęciu jest na prawdę ładny sygnał, ale i tak z Megi przychodzą błędne odczyty.
    ESP32 jednoczesne czytanie znaków z dwóch serial portów
    Czy macie pomysły jak można by jeszcze "podfiltrować" takie połączenia, żeby uniknąć błednego przesyłu danych?
    Jeżeli chodzi o same odczyty pozycji enkoderów przez Megę, to tu na 100% jest dobrze. Jak widać na jednym z powyższych zdjęć.
  • Poziom 39  
    madiz08 napisał:
    A obecny odbiór w ESP32 realizowany jest przez Core0 i wygląda tak:

    Jeżeli wywołujesz to zadanie co 4 ms, a w nim wywołujesz funkcje Serial.print() to tak naprawdę nie wiadomo, co ile czasu to zadanie faktycznie się wywołuje. Wyrzucanie zawartości danych do Serial (port USB) jest nieco czasochłonne.
    Ta sama uwaga dotyczy pętli oczekiwania w tym zadaniu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Nie stosuje się takiej konstrukcji w zadaniach, które mają być cyklicznie wywoływane w krótkich odstępach czasu, bo tak naprawdę nie wiadomo, jaki finalnie będzie miał wartość ten interwał i jak on będzie się zmieniał w kolejnych iteracjach. Takie pętle oczekiwania zatrzymują wykonywanie danego zadania, ale oczywiście nie zatrzymują działania innych zadań FreeRTOS.
    Nie wiem, na ile może mieć to wpływ na problem, który się pojawił, ale algorytm funkcji codeForTask1() to raczej trzeba poprawić.
  • Poziom 14  
    Wydaje mi się, że to na pewno wina samych zakłóceń, ale jak najbardziej zależało by mi na poprawnym pisaniu kodu, tymbardziej, że żaden ze mnie dobry programista. Odnośnie samych zakłóceń, jutro postaram się z pracy załatwić sobie kawałek przewodów ekranowanych i zobaczę czy jest jakakolwiek różnica.
    Odnośnie samego kodu wymiany danych w procesorze 0, czy takie rozwiązanie byłoby lepsze?
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Wgrałem takie coś jeszcze z zabezpieczeniem, że jak 3 razy z rzędu będzie zły odczyt to zatrzymaj robota i to samo po około 35 minutach powtarzania trajektorii robot się zatrzymał. Jak ponownie wywołam wykonywanie trajektorii to robot jedzie z tego miejsca gdzie sie zatrzymał, to idealnie dojechał do pozycji docelowej, stąd moje założenie, że odczyt enkoderów jest w 100% poprawny.

    Dodano po 9 [minuty]:

    Patrząc też na oscyloskop, widzę na nim przesył danych co równe 5ms także wydaje się w porządku.
  • Poziom 39  
    madiz08 napisał:
    Wydaje mi się, że to na pewno wina samych zakłóceń

    Nie ma co ukrywać, że "standardowe" płytki Mega czy ESP32 nie zostały zaprojektowane z myślą o odporności na zakłócenia. Patrząc na obrazek z tego wątku, wydaje mi się, że powinieneś połączyć bezpośrednio oba UART skrętką (może być nieekranowana) i sprawdzić, czy się zmniejszyły zakłócenia.

    madiz08 napisał:
    Odnośnie samego kodu

    Zakomentuj na razie wywołania Serial.print() w funkcji codeForTask1(). Nie będziesz miał podglądu w monitorze portu szeregowego, ale przekonamy się, czy się coś polepszy. Jaką prędkość masz ustawioną w Serial.begin() w kodzie dla ESP32?
  • Poziom 14  
    Dobrze spróbuję dzisiaj po pracy to potestować i dam znać. Jeżeli chodzi o prędkość transmisji to ustawiona jest na 115200.
  • Poziom 39  
    madiz08 napisał:
    Jeżeli chodzi o prędkość transmisji to ustawiona jest na 115200.

    W wypadku ESP32 możesz ustawić Serial.begin(500000). Oczywiście w monitorze portu szeregowego też trzeba zmienić na 500 000.
  • Poziom 14  
    A jednak to były zakłócenia, skrętka bez ekranu nie pomogła. Rozkręciłem z treningowego PLC wtyczkę profibusową. Przewód profibus ma dwa przewody i ekran, który z jednej i drugiej strony podłączyłem do masy i przez 30 minut zero błędnych komunikatów. Od razu widać, że przyspieszenia i hamowania są bardziej płynne. W wolnej chwili potestuję jeszcze jak układ zachowa się przy większych prędkościach transmisji. W sumie ciekawe, bo pamiętam, że jak zmniejszałem prędkość do 9600 (sprawdzając oczywiście na oscyloskopie, czy pomiędzy paczkami danych są wystarczające przerwy) to zakłóceń było znacznie więcej.
    No nic, jeszcze raz dzięki wielkie za pomoc, czekam teraz na nowa grzałkę do drukarki 3D będę próbował pododawać pozostałe osie