• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Odczyt DS18B20 i publikacja przez MQTT - zawiesza się po kilku godzinach.
#1
Witam,

Mam problem ze stabilnością działania kodu zawartego w załączniku. Program kompiluje się i działa poprawnie przez 3 - 4 godziny, po tym czasie przestaje publikować wyniki odczytów.

Od strony sprzętowej konfiguracja wygląda tak:

- Arduino Uno R3 lub Mega (bez różnicy, Mega działa nawet trochę krócej)
- Ethernet Shield W5100 (ten ze slotem SD)
- zasilacz 12V 2A
- 4 czujniki DS18B20

Teraz program jest maksymalnie odchudzony. Domyślnie pomiędzy kolejnymi seriami odczytów była przerwa, ale użycie delay(); powodowało zawieszanie się po kilku minutach. Wyrzuciłem również komunikację przez monitor portu szeregowego.

W tym momencie przychodzą mi na myśl trzy rzeczy:

- Fragmentacja pamięci spowodowana zadeklarowaniem buforów jako zmiennych lokalnych. Problem mam taki, że jeżeli zadeklaruję je jako globalne to nie wiem jak je wyczyścić przed kolejnym odtworzeniem pętli. Efekt jest taki, że w pierwszym powtórzeniu wynik jest poprawny (np. { id1 : 20,1 }, a kolejne powtórzenia przepełniają bufor ({ id1 : 20,1 } { id1 : 20,2 } { id1 : 21,3 } i tak aż do przepełnienia.

- Zbyt częste / źle skonstruowane odczyty z czujników.

- Wadliwy Ethernet Shield - ma jakiś problem z inicjalizacją. Po podłączeniu zestawu do zasilania diody na module sieciowym kilkukrotnie zapalają się i gasną. Po czasie 10 - 30 sekund zapalają się na stałe, program działa (wyniki da się odcztać przez Serial.print(); ale komunikacja sieciowa nie działa. Po drugim lub trzecim resecie diody zapalają się natychmiast po zresetowaniu i wtedy komunikacja działa poprawnie aż do zawieszenia.

Jakiś czas temu używałem tego sprzętu do odczytu tych czterech termometrów, ale wyniki raportowałem bezpośrednio do Domoticza przez HTTP GET. Program miał kilometr tekstu, używał bardzo długich stringów, przesyłał mnóstwo danych... i potrafił działać 3 tygodnie bez przerwy. Przejście na MQTT miało zoptymalizować cały proces.

W tym momencie chcę dokupić kolejny Ethernet Shield  żeby wykluczyć ewentualny problem sprzętowy.

Jednocześnie zwracam się z prośbą o przejrzenie kodu pod kątem jakichś ewidentnych błędów.


Załączone pliki
.txt   ds18b20_mqtt.txt (Rozmiar: 1.45 KB / Pobrań: 14)
 
Odpowiedź
#2
Kot wlazł na klawiaturę, zobacz jak będzie działać gdy nie będziesz blokował urządzenia odczytem w kółko temperatur:
Kod:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const byte ONEWIRE_PIN = 7;
const byte NUM_SENSORS = 4;
unsigned long teraz,ostatnio;
byte mac[]    = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 192, 168, 1, 107 };
byte ip[]     = { 192, 168, 1, 200 };



const byte sensorsAddress[NUM_SENSORS][8] = {
  0x28, 0xAF, 0xA8, 0x26, 0x0, 0x0, 0x80, 0x9E,
  0x28, 0x32, 0xAB, 0x26, 0x0, 0x0, 0x80, 0x2B,
  0x28, 0xFF, 0x2E, 0x63, 0xA8, 0x15, 0x1, 0x94,
  0x28, 0xFF, 0xEE, 0x5E, 0xA8, 0x15, 0x4, 0x5C
};


void callback(char* topic, byte* payload, unsigned int length) {
  
}

OneWire oneWire (ONEWIRE_PIN);

DallasTemperature sensors(&oneWire);


EthernetClient ethClient;

PubSubClient client(server, 1883, callback, ethClient);



void setup() {
  

  Ethernet.begin(mac, ip);
sensors.requestTemperatures();
  delay(5000);
sensors.setWaitForConversion(0);
  if (client.connect("arduinoClient")) {
    client.publish("arduino/out", "OK");
  }
  
}


void loop() {
teraz = millis();


  
if((uint32_t) (teraz-ostatnio)>1000)
{
  ostatnio=teraz;
  for (int i = 0; i < NUM_SENSORS; i++)

  {

    char buffer[50] = { 0 };
    char num_buffer[50] = { 0 };
    char payload[50] = { 0 };

    float temperature = sensors.getTempC(sensorsAddress[i]);

    dtostrf(temperature, 5, 2, buffer);
    sprintf(num_buffer, "%d", i);

    strcat(payload, "{ id");
    strcat(payload, num_buffer);
    strcat(payload, " : ");
    strcat(payload, buffer);
    strcat(payload, " }");

    client.publish("arduino/out", payload);

}
sensors.requestTemperatures();
  }

  client.loop();

}
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Dziękuję za poprawkę, kod załadowałem i za jakiś czas powinna być odpowiedź czy pomogło.

Zrobiłem jeszcze jeden test - uruchomiłem raportowanie na monitor portu szeregowego i zostawiłem układ z podłączonym do niego laptopem. Okazało się, że po zaprzestaniu publikacji odczytów przez MQTT nadal pojawiają się one na porcie szeregowym. Płytka działa, program działa, a problem jest z połączeniem sieciowym.

Teraz raczej trudno będzie stwierdzić czy to kwestia wadliwego Shielda czy samego kodu.
 
Odpowiedź
#4
Ja miałem kiedyś podobny problem. Okazało się, ze za dużo stringów pchałem w komunikację.
Pomogło zorganizowanie wszystkich stringów do pamięci programu procka.
Zmniejszenie ilości pchanych stringów wysyłanych bezpośrednio z kodu pomogło.
Stwórz procedurkę i wysyłaj z pamięci procka.

Podobny problem miałem z wysyłaniem danych przez moduł GSM.
Tam również w ten sam sposób sprawa została rozwiązana.

Arduino nie lubi jak wysyła się dużo stringów bezpośrednio z kodu.
Ma to pewnie związek z ilością dostępnej pamięci RAM.
Dlatego tez przerzucam co się da do pamięci programu.

Krótko... TO DZIAŁA!

Pozdr,
Jeżeli pomogłem, to poproszę o punkt reputacji Big Grin
 
Odpowiedź
#5
Będę musiał spróbować, ale na razie jestem jeszcze na etapie dostosowywania gotowych przykładów do swoich potrzeb Shy

W kwestii mojego problemu wynikła ciekawa sprawa. Arduino miałem cały czas podłączone do głównego routera w domu, razem z komputeremi, NASem i Raspebrry Pi. Wczoraj musiałem je przepiąć pod router zapasowy i... od tego czasu działa stabilnie ponad 24 godziny.

Oba routery są sprawne ( z resztą różnych portów na routerze głównym też próbowałem). Układ Arduino -> router 1 -> Rpi sprawiał problemy, a układ Arduino -> router 2 -> router 1 -> Rpi wydaje się działać stabilnie...
 
Odpowiedź
#6
Ja jestem na poziomie wzięcia pały i tłuczenia w obudowę routera jak coś nie działa. Kiedyś tak miałem, że na routerze Linksys (bardzo wtedy drogim, nowość N draft) wszystko chodziło znakomicie, poza VOIP, który rozłączał rozmowy wychodzące po 20s, zawsze tak równiutko. Skype działał OK. Nawet całkowite wyłączenie FIREWALL, żadne przekierowania i tipsy znalezione w necie nie pomagało. Już byłem pewien że NEO blokuje konkurencję. Pomogła wymiana routera na tańszy/inny, ten robił za przedłużenie sieci i WIFI. Z wieszaniem losowym arduino miałem natomiast do czynienia gdy bawiłem się serwerem na ESP8266. Wgrany przykład z wyświetlaniem 1 temperatury w oknie, przez odświeżanie strony co 1s działało OK. Ale zrobienie prostej strony z 4 polami i 4 przyciskami powodowało losowe klęknięcie po paru minutach/godzinach - zapewne wyciek pamięci i przepełnienie stosu. Rozwiązaniem był serwer z WEBSOCKET, każdy klient dostaje stronę raz, a potem uzupełnienie danych osobną funkcją. A w UNO ramu jeszcze mniej, jest taki przykład, można sobie powtykać tu i ówdzie by sprawdzić co jakiś czas, co się dzieje z ramem:
Kod:
size_t freeRam ()
 {
 return RAMEND - size_t (__malloc_heap_start);
 } // end of freeRam

void setup ()
 {
 Serial.begin (115200);
 Serial.println ();

 Serial.print (F("Free memory = "));
 Serial.println (freeRam ());
 }  // end of setup

void loop () { }
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#7
Procek z 2kb ramu i Ethernet to nieporozumienie. Sensownie minimum to 4kb dlatego jeśli już Arduino na AVR to ArduinoMega2560 (8kb ram). Oczywiście rozsądniejszy byłby ARM. Arduino wspiera STM32F1xx i ARMy Microchip (Atmel) SAM.


pS
2kb do zamigania dioda prze Internet wystarczą ale sensownej strony na tym nie da się prosto zrobić.
 
Odpowiedź
#8
Po tygodniu prób mogę ogłosić rozwiązanie problemu Smile

Pomogło przepięcie pod inny router, dla pewności wymieniłem też Ethernet Shield (ten nowy od razu inicjalizuje się poprawnie).

W międzyczasie skończyłem kolejny projekt (przekaźniki sterowane przez MQTT) i w trakcie pisania kodu doszedłem do wniosku, że program z tego wątku działałby poprawnie nawet bez zmian sprzętowych gdyby tylko zawierał funkcję odpowiedzialną za pilnowanie połączenia z serwerem MQTT. W obecnej wersji nawet chwilowa utrata połączenia powodowała, że program przestawał publikować dane.

W wolnej chwili uzupełnię program i wrzucę go na forum, może komuś oszczędzi to podobnych problemów.
 
Odpowiedź
#9
Nie bawię się MQTT, ale myślę, że rozwiązaniem problemu może być reset arduino dla powyższego szkicu (można odpalić watchdog) lub, jeśli korzystasz z biblioteki Nick O'Leary użycie przykładu z mqtt_reconnect_nonblocking. W tym szkicu ustawienie użytkownika jest tylko w setup, jak się potem rozłączy to nic z tym nie robi.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#10
W moim przypadku wystarczyła nawet wersja z przykładu mqtt_basic. Co prawda w przeciwieństwie do mqtt_reconnect_nonblocking blokuje wykonanie pętli loop () do momentu uzyskania połączenia, ale w przypadku gdy Arduino ma tylko publikować wyniki odczytów to ma sens - po co odczytywać skoro i tak nie można opublikować.

Dzięki za pomoc Smile
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości