Mon Sketch Arduino s'arrête après 2 ou 3 minutes de bon fonctionnement

Bonjour à tous,

Je me trouve dans une situation que je ne m'explique pas. Je vous présente mon projet et ensuite mon problème.

Projet : grâce à un ensemble de boutons (6) et à une carte Arduino Mega équipée d'un Shield Ethernet et une librairie OSC (Open Sound Control), j'envoie des données à un premier équipement recevant l'OSC, et j'active aussi des opto-coupleurs sur un second équipement.
En plus de cela, j'ai un Arduino NANO + boutons, équipé d'un module Bluetooth HC-05 qui transmet au MEGA, lui aussi équipé d'un HC-05, des commandes pour actionner les optos.
Les modules Bluetooth sont reliés sur les Pin RX/TX des Arduino, et il y a un pont diviseur sur la pin RX des HC-05.

En résumé :

Arduino Nano -> Bluetooth HC-05 Bluetooth HC-05 ou Bouton -> Arduino MEGA -> OSC

-> Boucle sèche vers opto

Mon problème : Tout fonctionne bien, jusqu'à ce que, pour une raison que j'ignore, les commandes ne répondent plus, la communication Bluetooth s'arrête et plus rien ne fonctionne... Je dois reset la carte pour réussir à nouveau.

J'imagine qu'il y a un problème dans mon code mais impossible de trouver où...

Voici mon code :

 //INCLUDE POUR MESSAGE OSC / SHIELD ETHERNET
#include <OSCMessage.h>

/*
    Parametrage pour fair un messace OSC message et l'envoyer via UDP
*/

#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>    

  EthernetUDP Udp;

  //the Arduino's IP
  IPAddress ip(192, 168, 1, 18);      //Adresse que nous donnons à notre Arduino
  //destination IP
  IPAddress outIp(192, 168, 1, 1);    //Adresse de la Midas
  const unsigned int outPort = 10024; //Port de communication de la Midas

  byte mac[] = {  
      0xA8, 0x61, 0x0A, 0xAE, 0x3D, 0x26 }; // Inscrit au dos du shield Ethernet

//---------------------------------------------FIN DE PARAMETRAGE ETHERNET/OSC---------------------------------------------------------

#define pinANIM  22     //BOUTON ANIM
#define pinINVITE 23   //BOUTON INVITE
#define pinHF 24       //BOUTON HF
#define pinRACCRO 25   //BOUTON RACCRO
#define pinREGIE 26   //BOUTON REGIE
#define pinACCUEIL 27  //BOUTON ACCUEIL
  
  // Declaration des variable pour le C11
#define pinRaccroC11 36
#define pinAccueilC11 31
  //int  pinRougeC11 = 37;  

  //Declaration de la variable pour lire la liaison série (Bluetooth) avec le Nano
int state = 0;

  //Declaration des variables "Bouton"
  
  boolean BoutonANIM;
  boolean BoutonREGIE;
  boolean BoutonINVITE;
  boolean BoutonHF;
  boolean BoutonACCUEIL;
  boolean BoutonRACCRO;

void setup() {
  
  //initialisation Ethernet
    Ethernet.begin(mac,ip);
    Udp.begin(8888);

// définition des modes pour les PIN en INPUT pour recevoir les messages des boutons

// /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\/
// /!\ INPUT_PULLUP inverse l'état des entrées (HIGH = LOW et LOW = HIGH)
// /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\

    pinMode(pinANIM, INPUT_PULLUP);
    pinMode(pinINVITE, INPUT_PULLUP);
    pinMode(pinHF, INPUT_PULLUP);
    pinMode(pinREGIE, INPUT_PULLUP);
    pinMode(pinACCUEIL, INPUT_PULLUP);
    pinMode(pinRACCRO, INPUT_PULLUP);

  //C11
    pinMode(pinRaccroC11, OUTPUT);
    pinMode(pinAccueilC11, OUTPUT);
    
    digitalWrite(pinRaccroC11, LOW);
    digitalWrite(pinAccueilC11, LOW);
        
    Serial.begin(9600); // Ratio de communication par défaut des modules Bluetooth

}

void loop() {

  //lecture de l'état des boutons
  BoutonANIM = digitalRead(pinANIM);
  BoutonREGIE = digitalRead(pinREGIE);
  BoutonINVITE = digitalRead(pinINVITE);
  BoutonHF = digitalRead(pinHF);
  BoutonACCUEIL = digitalRead(pinACCUEIL);
  BoutonRACCRO = digitalRead(pinRACCRO);

 if(Serial.available() > 0){ // Checks whether data is comming from the serial port
    state = Serial.read(); // Reads the data from the serial port
 }

 delay(10);
 
//-------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------PUPITRE TALKBACK OU ANIM-----------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------

//--------------------------------------------------RACCRO = '1'-----ACCUEIL = '2'-----------------------------------------------------------------
  if ((BoutonACCUEIL==LOW) || (state == '2'))//test si bouton appuyé ou si Bouton BT
  {
    digitalWrite(pinAccueilC11,HIGH); 
    state = 0;   
    //Actionne Opto du C11 pour ACCUEIL
  }

  else if ((BoutonRACCRO==LOW) || (state == '1'))
  {
     digitalWrite(pinRaccroC11,HIGH);
     state = 0;
  }
      
  else if (state=='0')
  {
    digitalWrite(pinRaccroC11,LOW);
    digitalWrite(pinAccueilC11,LOW);
    state = 0;
  } 
    
  //---------------------------------------------------------------- ---------------------------------------------------------------
  //--------------------------------------------------PUPITRE TALKBACK-------------------------------------------------------------
  //-------------------------------------------------------------------------------------------------------------------------------
   if (BoutonANIM==HIGH)//test si bouton levé
  {
    OSCMessage msg("/ch/16/mix/01/level");
    msg.add((float)0); //(fader à -infini)
  
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }

  if (BoutonANIM==LOW)//test si bouton appuyé
  {
    OSCMessage msg("/ch/16/mix/01/level");
    msg.add((float)0.75); //(fader à Zéro
  
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }

  if (BoutonREGIE==HIGH)//test si bouton levé
  {
    OSCMessage msg("/ch/16/mix/fader");
    msg.add((float)0);
  
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }
 
  if (BoutonREGIE==LOW)//test si bouton appuyé
  {
    OSCMessage msg("/ch/16/mix/fader");
    msg.add((float)0.75);
    
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }
  
  if (BoutonINVITE==HIGH)//test si bouton levé
  {
    OSCMessage msg("/ch/16/mix/02/level");
    msg.add((float)0);
    
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }
  
  if (BoutonINVITE==LOW)//test si bouton appuyé
  {
    OSCMessage msg("/ch/16/mix/02/level");
    msg.add((float)0.75);
    
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message    
  }

  if (BoutonHF==HIGH)//test si bouton levé
  {
    OSCMessage msg("/ch/16/mix/03/level");
    msg.add((float)0);
    
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message    
  }
  
  if (BoutonHF==LOW)//test si bouton appuyé
  {
    OSCMessage msg("/ch/16/mix/03/level");
    msg.add((float)0.75);
    
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message
  }

  delay(10);

}

J'espère avoir été complet dans ce tout premier post.
Je continue à chercher de mon côté et je vous remercie d'avance pour votre aide.

Matériel utilisé :

MEGA

SHIELD ETHERNET

NANO

HC-05

OSC Library

Bonjour
Utilise pour communiquer avec le BT une autre porte que Serial (Ex Serial2).
puis:

if(Serial2.available() > 0){ // Checks whether data is comming from the serial port
    state = Serial.read(); // Reads the data from the serial port
   Serial.println(state);
 }

Pour voir si vraiment le bt se bloque.
Autre chose:

 if ((BoutonACCUEIL==LOW) || (state == '2'))//test si bouton appuyé ou si Bouton BT
  {

state c'est un int pas un char! çà fonctionne quand même?

savoriano:
state c'est un int pas un char! çà fonctionne quand même?

le c/c++ est très permissif avec les types de données, oui ça cela fonctionne. après tout, un char ce n'est jamais qu'un entier sur 8 bits.

en revanche que le test soit valide en C++ ne veut pas dire qu'il est juste sur le plan intellectuel. Est-ce qu'il faut savoir si state contient la valeur 2 ou la valeur en ascii correspondant au chiffre 2 ?

bricofoy:
Est-ce qu'il faut savoir si state contient la valeur 2 ou la valeur en ascii correspondant au chiffre 2 ?

J'ai oublié de fournir le code de mon Nano qui envoi différentes valeurs ('1' '2' ou '3') via la liaison Série (BT). A vrai dire, j'ai simplement suivi un tuto où il utilisait cette méthode pour communiquer des commandes en BT...

Le voici :

/*
 
#include <Servo.h>
#define pinRACCRO 2
#define pinACCUEIL 5
#define pinSONO 4
#define pinON 7

int state = 20;
int stateRACCRO = 0;
int stateACCUEIL = 0;
int stateSONO = 0;

void setup() {
  pinMode(pinRACCRO, INPUT_PULLUP);
  pinMode(pinACCUEIL, INPUT_PULLUP);
  pinMode(pinSONO, INPUT_PULLUP);
  pinMode(pinON, OUTPUT);

  digitalWrite(pinON, HIGH);

  Serial.begin(9600); // Default communication rate of the Bluetooth module
}
void loop() {
 if(Serial.available() > 0){ // Checks whether data is comming from the serial port
    state = Serial.read(); // Reads the data from the serial port
 }

 delay(10);
 
 // Reading the button
 stateRACCRO = digitalRead(pinRACCRO);
 stateACCUEIL = digitalRead(pinACCUEIL);
 stateSONO = digitalRead(pinSONO); 
 
 if (stateRACCRO == LOW) {
   Serial.write('1'); // Sends '1' to the master to turn on LED
 }

  else if (stateACCUEIL == LOW) {
   Serial.write('2'); // Sends '1' to the master to turn on LED
 }

  else if (stateSONO == LOW) {
   Serial.write('3'); // Sends '1' to the master to turn on LED
 }
 
 else {
   Serial.write('0');
 }  
}

savoriano:
Utilise pour communiquer avec le BT une autre porte que Serial (Ex Serial2).
puis:

if(Serial2.available() > 0){ // Checks whether data is comming from the serial port

state = Serial.read(); // Reads the data from the serial port
  Serial.println(state);
}



Pour voir si vraiment le bt se bloque.

J'ai essayé en changeant les pin TX/RX (16/17 sur le MEGA si je ne me trompe pas ?), je n'ai rien qui arrive dans le moniteur série et les commandes BT venant du Nano ne fonctionnent pas, même si la liaison est établie (j'ai une LED sur la pin State). Enfin la liaison ne tient pas longtemps et tout plante comme avant...
Je suis un peu perdu...

t'as fait un serial2.begin(9600); ?

dans mon code il y a aussi un erreur
voila:

if(Serial2.available() > 0){ // Checks whether data is comming from the serial port
    state = Serial2.read(); // Reads the data from the serial port
   Serial.println(state);
 }

Je declarerais, pour des raisons esthetiques, state comme un char, un byte ou un uint8_t.
Ce serait des raisons purement esthetiques....(les rares affectations de state ne me choquent en aucune manière: au pire, on a alloué UN octet de trop)
Je ne pense pas que ce soit une source de blocage en cours de route (une fuite mémoire donnerait des symptomes compatibles avec l'exposé en #1 et ne peut pas être imputée -si fuite mémoire il y a- à un choix de types maladroit)

Tu utilises la bibliothèque OSCMessage. J'ai jeté un œil dans le fichier OSCMessage.h (est-ce bien celui-là ?) et il semble que cette bibliothèque utilise des String.

La classe String est connue dans le monde Arduino pour provoquer des problèmes de mémoire après une longue utilisation. Ça pourrait venir de ça (ou pas :confused: ).

C'est l'impression (pessimiste : ça impliquerait plus que des réécritures esthetiques) que j'avais.... (in peut avoir des fuites de mémoire sur PC, menant à des comportements très corrects au début, puis shadokesques -blocages-) The Evils of Arduino Strings | Majenko's Hardware Hacking Blog...

pour détecter des soucis de mémoire, un petit bout de code utile dont je me sert souvent :

//from http://jeelabs.org/2011/05/22/atmega-memory-use/
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

tu place cette fonction dans ton code, et de temps en temps tu fais un serial.Print(freeRam());

la fonction retourne le nombre d'octets de ram disponibles

quand tu commence à voir des valeurs en dessous de 100, la fin est proche...

pour détecter des soucis de mémoire, un petit bout de code utile dont je me sert souvent :

+1

Il y a rien sur le net qui dénonce un problème avec cette librairie!

La présence (ou pas ) d'une eventuelle horreur dans une bibliothèque ne se verifie pas par un referendum sur le net....

On trouve la fonction freeram sur la référence Arduino et même dans une bibliothèque spécifique

L'image suivante explique assez bien la structure de la RAM et le problème de fragmentation qu'on observe avec les String :

Celle-ci explique les variables utilisées dans la fonction freeRam :


freeRam crée une variable v qui se met dans la stack, tout en bas, puis calcule la différence entre l'adresse de cette variable &v et le haut du heap s'il existe.

Ça ne prend pas en compte la fragmentation du heap. freeRam() ne retourne que l'espace libre entre le heap et la pile, mais c'est la valeur la plus importante à vérifier, car l'autre espace libre qui peut exister à l'intérieur du heap, causé par sa fragmentation, a pour effet réduire l'espace entre le tas/la pile.

Donc:
1: Il n'y à jamais une défragmentation des variables.
2: Le processeur perd un temps fou pour aller chercher une variable fragmenté.
3: Ca peut crasher!

Il faut retourner sur le problème de QuenG:
Vérifier avec la fonction freeram si le problème vient de la.
Et si c'est le cas il doit abandonner l'idée d'utiliser cette librairie?

... si le problème vient bien de là ...

2: Le processeur perd un temps fou pour aller chercher une variable fragmenté.

Non: le processeur n'a aucune information sur le caractère fragmenté ou pas d'une variable.... et ne va pas perdre son temps à une mission impossible (sur un PC, c'est différent: la mémoire (des centaines de milliers de fois + abondante que sur arduini- est allouée par blocs, et, si on la libère, le bloc finit par être declaré vierge... là, certains defragmenteurs peuvent exister et, effectivement, passer beaucoup de temps à défragmenter-et c'est vu comme un inconvenient si on veut faire du temps réel)

3: Ca peut crasher!

:
si c'est une fuite mémoire , ce n'est pas une possibilité, mais une certitude.... (sur les PC, chercher une fuite memoire -oubli de desallouer un tableau alloué, dans les cas simples- est une horreur nécessaire)

Et si c'est le cas il doit abandonner l'idée d'utiliser cette librairie?

Peut être pas (m^me si c'est une panne très désagréable):
ceite bibliothèque est peu utilisée (besoin bien particulier), maintenue activement.
Si le comportement bizarroîde peut être confirmé sur un code simplifié (je vois mal comment solliciter un developpeur pour acquerir un bluetooth, ou plus généralement recopier le materiel tel qu'il est)

et

si c'est une fuite memoire (à ce stade, ce sont des soupçons basés sur la similitude de symptômes et l'appel à une classe suspecte)
on peut tenter de profiter du fait qu'elle soit maintenue activement pour demander à l'auteur (ça profiterait à d'autres que les lecteurs du blog francophone...) de faire quelque chose....

lesept:
freeRam crée une variable v qui se met dans la stack, tout en bas, puis calcule la différence entre l'adresse de cette variable &v et le haut du heap s'il existe.

Merci pour l'explication, je m'en servais sans avoir bien compris son fonctionnement.

Bonjour à tous,

Déjà, merci beaucoup pour vos nombreuses réponses et vos pistes de réflexion.

J'ai changé le type de state en char et j'utilise le Serial2 pour le BT (j'ai enfin réussi, merci @savoriano). J'avais bien mis le Serial2.begin(9600); mais j'avais recopié la coquille... C'est ça de copier/coller sans réfléchir...

Pour le freeRam, il m'affiche 7411 puis 7352. Je ne descend pas en dessous.

J'ai aussi changer une Pin, la 36, utilisée pour envoyer une boucle sèche à un opto, elle avait une tension en sortie de 2.3V, qui ne voulait ni se mettre à 0 ni à 5V. Peut être que ma carte à un problème ? Ce n'est pas la seule Pin à délivrer une tension alors que je ne lui demande rien...

Toujours est-il que le sketch fonctionne un peu plus longtemps, une vingtaine de minute, puis le moniteur série perd la connexion (plus de port COM disponible dans l'IDE), et ça plante... La dernière valeur de FreeRam est 7411.

J'ai quand même peur que le problème vienne de ma carte...

Je garde en tête que la librairie que j'utilise est peut être bancale, j'aurais au moins appris que les String doivent être manier avec précautions (voir interdite). Je vais essayer de trouver une autre librairie OSC pour avoir quelques chose de plus stable.

Je n'ai pas l'occasion, pour l'instant, de tester avec une autre carte. J'essaie dès que possible pour mettre le sujet résolu le cas échéant.

Encore merci à tous.

QuenG:
Toujours est-il que le sketch fonctionne un peu plus longtemps, une vingtaine de minute, puis le moniteur série perd la connexion (plus de port COM disponible dans l'IDE), et ça plante... La dernière valeur de FreeRam est 7411.

plus de port COM dispo = plantage de la liaison USB, tu as sans doute un problème d'alimentation de la carte, ou alors il y a des parasites électromagnétiques générés par un relais, un moteur ou autre qui serait trop proche ?

Pour l'alimentation, j'utilise celle ci, en 9V

ALIM

Pour ce qui est des parasites, c'est possible, la carte est reliée à un équipement avec relais via une liaison Sub-D 15. La carte en elle même est à une trentaine de cm de cet équipement. Je vais re-tester en éloignant la carte.

éloigner la carte si elle y est physiquement reliée par un câble ne changera pas grand chose je crains... peut-être qu'il faudrait ajouter quelques condensateurs de filtrage au autre, mais je ne suis pas la bonne personne pour expliquer ça ou expliquer précisément quoi surveiller pour confirmer que le pb vient de là.

il faudrait demander ça à 68tjs par exemple