[RESOLU] Serial qui devient lent après un certain nombre de réceptions

Bonjour,

J'ai fait quelques recherches mais je ne trouve pas de solutions à mon problème, donc je viens demander de l'aide ici. J'ai un programme en Java qui envoie une suite de 368 caractères à l'arduino à l'aide de la librairie JSerialComm. Voila mon code sur l'arduino :

int incomingByte = 0;
int compteur = 0;

const int ledBleu = 6;                // affecte la led bleu au port 6
const int ledRouge = 2;               // affecte la led rouge au port 2
const int ledVert = 4;                // affecte la led verte au port 4

void setup() {
  Serial.begin(9600);
  pinMode (ledBleu, OUTPUT);          // port 3 en mode sortie
  pinMode (ledRouge, OUTPUT);         // port 5 en mode sortie
  pinMode (ledVert, OUTPUT);          // port 6 en mode sortie
  while (!Serial) {
  }

}

void loop() {

  if (Serial.available() > 0) {

    incomingByte = Serial.read();
    Serial.println(incomingByte);

    compteur++;
    Serial.println(compteur);

    switch(incomingByte) {

      case 82:
      Serial.println("R");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 0);
      break;
      
      case 83:
      Serial.println("R'");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 0);
      break;

      case 84:
      Serial.println("R2");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 0);
      break;

      case 85:
      Serial.println("U");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 255);
      break;

      case 86:
      Serial.println("U'");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 255);
      break;

      case 87:
      Serial.println("U2");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 255);break;

      case 76:
      Serial.println("L");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0);
      break;

      case 77:
      Serial.println("L'");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0);
      break;

      case 78:
      Serial.println("L2");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0);
      break;

      case 68:
      Serial.println("D");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0); 
      break;

      case 69:
      Serial.println("D'");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0); 
      break;

      case 90:
      Serial.println("D2");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 255);
      analogWrite(ledBleu , 0); 
      break;

      case 66:
      Serial.println("B");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255); 
      break;

      case 67:
      Serial.println("B'");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255); 
      break;

      case 65:
      Serial.println("B2");
      analogWrite(ledRouge, 0);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255); 
      break;

      case 70:
      Serial.println("F");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255);
      break;

      case 71:
      Serial.println("F'");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255);
      break;

      case 72:
      Serial.println("F2");
      analogWrite(ledRouge, 255);
      analogWrite(ledVert , 0);
      analogWrite(ledBleu , 255);
      break;
    }
  }
}

En fonction du caractère que je recois, qui est envoyé en ASCII, j'allume un bandeau de LED d'une certaine couleur.

Lorsque je reçois les caractères, j'en reçois à peu près 100 très rapidement ( moins d' 1 sec, le bandeau de led clignote très fortement ) mais ensuite il y en a une couleur qui reste très longtemps ( 5-7 sec environ ) puis ensuite les couleurs défilent mais de manière plus lente ( environ 1 couleur par seconde ). J'ai essayé de changer le nombre de baud mais je ne recevais que des caractères étranges.

Donc voila, quelqu'un sait - il d'où vient le problème et comment le régler ? Merci d'avance.

Bonsoir, refait ton code avec le binaire pour le changent de PIN (plus rapide) moins de demande a des fonctions Arduino.
Cdt.
Marcus.

marcus_95:
Bonsoir, refait ton code avec le binaire pour le changent de PIN (plus rapide) moins de demande a des fonctions Arduino.
Cdt.
Marcus.

Tout d'abord, merci de ta réponse mais je n'ai pas très bien compris ce que je dois refaire dans mon code. Je dois utiliser une autre fonction pour les PIN de sortie pour les LED ? Je dois envoyer mes caractères en binaire ?

OUI exemple DDRB = (1<<DDB0); broche 0 en sortie. PORTB &=~(1<<DDB0); état 0.

Merci, je vais essayer ça

cela marche avec tous les ports, attention le port D: 0 et 1 RX TX

Il n'utilise pas de digitalWrite donc l'accès par les registres ne devrait pas changer grand chose.
Par contre, il y a pas mal de Serial.print() dans la boucle loop() et ça c'est pas bien parce que pour un caractère reçu le soft en envoie une demi douzaine donc il n'est pas impossible que le buffer d'émission sature et bloque l'exécution.

Personnellement, je commencerais pas supprimer ces Serial.print() pour voir si le ralentissement se produit toujours.

+1 avec fdu

Changez Serial.begin(9600); en Serial.begin(115200); et limitez les print (bien sûr faut passer la console/le pgm qui lit la communication série à 115200 bauds aussi)

Serial.print() devient bloquant quand 64 caracteres sont dans le buffer de communication ce qui peut donner des lenteurs sur le reste du programme. En augmentant la vitesse de communication sur le port série vous repoussez le pb mais il faut bien en être conscient

Si vous ne voulez pas que vos print soient bloquants avant d'imprimer vous pouvez tester [

Serial.availableForWrite()

](Serial.availableForWrite() - Arduino Reference) pour voir s'il y a la place dans le buffer de sortie pour ce que voulez écrire

@pepe:

Or, le programme n'envoie qu'une douzaine de caractères au maximum durant chaque boucle loop(). Si le ralentissement constaté était dû au remplissage du tampon d'émission, on serait encore capable de réaliser 80 boucles loop() par seconde

--> Le post d'origine parle d'un burst à plus de 100 demandes par secondes et il dit aussi J'ai un programme en Java qui envoie une suite de 368 caractères à l'arduino

S'il s'agit d'un modèle de type Uno, Nano ou Mega, alors l'objet Serial pilote une interface UART sans signal de contrôle susceptible la ralentir. La vitesse d'émission minimale correspond alors pratiquement au débit paramétré dans Serial.begin() lorsque le tampon d'émission est plein, soit 960 caractères par seconde pour 9600 bauds

--> je ne sais pas ce que vous voulez dire par la partie en bleu. La fonction print de la classe HardwareSerial fait une attente active - bloque l'Arduino comme un appel à delay - si le buffer est plein. Selon votre propre calcul ci dessus ça arrivera assez vite. Pendant ce temps Le buffer d'entrée lui peut être saturé et donc passer en overflow et perdre des données. On ne sait pas ce que fait le programme Java qui je suppose écoute les "R", "R2",... etc?

Bref on manque un peu d'info

oui OK votre raisonnement se tient - je n'avais pas regardé en détail et zappé les 5-7 secondes. ça fait bcp.. on dirait le temps de rétablissement d'une connexion USB potentiellement après un reboot intempestif...

ce serait bien d'avoir une vision de ce qui est transmis par l'arduino pour voir ce qu'il se passe et savoir exactement ce que fait le pgm Java des infos qui sont retournées par l'arduino. mais l'OP semble aux abonnés absents...

Bonjour,

Tout d'abord merci à tous pour vos réponses, je vais tacher de répondre à tous le monde et d'apporter quelques informations.
Je suis un élève de 1erS SI, cette année, étant dans cette filière, nous devons réalisé un TPE ( Travau Personnel Encadré ). Pour ceux qui ne connaissent pas, c'est un projet en groupe où l'on doit mêler différentes matières ensemble ( Sciences de l'ingénieur, Maths ... ). Je me suis mis avec mon ami et aimant tout les deux le Rubik's Cube, nous avons décidé de créer un robot permettant de résoudre un Rubik's Cube. Nous savons que cela est compliqué mais nous sommes motivés et avons un minimum de connaissances. Notre programme Java permet de connaître le mélange de notre Rubik's Cube et le programme le résout virtuellement et enregistre les mouvements à faire pour résoudre le Rubik's Cube réellement. C'est donc ce que l'on envoie à l'arduino, chaque lettre représente un mouvement à faire. Notre méthode de résolution n'est pas très optimal car ce serait trop compliqué pour nous de faire un programme plus perfectionné. C'est donc pour cela qu'il faut un grand nombre de mouvements pour le résoudre ( 368 dans le cas du mélange que nous testons ).

Quelques autres précisions :

  • Nous utilisons une arduino MEGA

  • Voici la suite de caractères que nous envoyons à l'arduino :

TRUMWRVSWLRVTTSRUMWRVSWLRVTRFSRUMWRVSWLRVTRGRFRVSVRUSGRUSVSFRGSERUMWRVSWLRVTDDRFRVSVRUSGRUSVSFRGSERERFRVSVRUSGRUSVSFRGSDSZRUMWRVSWLRVTZZGFRVSVRUSGRUSVSFRGFZRUSGRWSWSFRURWSVDNRUSVSFTVSVRUSGNEUEBFUGVGLHVGVFUGMCDVWZRLUMVMBNVMVLUMCSZWLSGSFMHRGSHRLRMVSUMWRVSWRLLRUSVSFTVSVRUSGMSLRHSGRHMFSGLMRVDFBUCVCRAVCVBUCSGEUNDLSRHSGRHMFSGLRMENZNFCRFCDFCNGBDGBRGBWNZNFCRFCDFCNGBDGBRGBWN
  • Voici le code qui l'envoie :
for(int y = 0; y < arduinoResolution.length(); y++) {
	pw.write(arduinoResolution.charAt(y));
}

Je peux donner plus de détails si vous en avez besoin.

J-M-L:
+1 avec fdu

Changez Serial.begin(9600); en Serial.begin(115200); et limitez les print (bien sûr faut passer la console/le pgm qui lit la communication série à 115200 bauds aussi)

Serial.print() devient bloquant quand 64 caracteres sont dans le buffer de communication ce qui peut donner des lenteurs sur le reste du programme. En augmentant la vitesse de communication sur le port série vous repoussez le pb mais il faut bien en être conscient

Si vous ne voulez pas que vos print soient bloquants avant d'imprimer vous pouvez tester [

Serial.availableForWrite()

](Serial.availableForWrite() - Arduino Reference) pour voir s'il y a la place dans le buffer de sortie pour ce que voulez écrire

J'ai donc testé d'enlever tous les Serial.print() et le programme est juste plus rapide pour les premieres réceptions et la même chose se reproduit.
Lorsque je change le nombre de baud, je reçois des caractères étranges.

pepe:
D'après ce qu'il décrit, le burst des 100 premiers caractères est correctement traité, et le blocage semble correspondre à la réception des (268) caractères suivants.

Au niveau du nombre de réception, il n'est pas pile à 100, il tourne autour de 100, c'est souvent 116 ou 99.

J'ai testé de mettre un Thread.sleep(50) ( équivalent du Delay(50) ) dans le proramme Java pour ralentir l'envoi à l'arduino mais tant que les 368 caractères n'ont pas été envoyés, l'arduino ne fait rien. C'est une fois que tout est envoyé que les LED RX TX clignotent, qu'elle semble tout recevoir d'un seul coup, provoquant toujours le même problème.

Merci encore pour toutes vos réponses et désolé de ne pas avoir pu répondre plus tôt, j'étais au lycée ce matin.

'ai testé de mettre un Thread.sleep(50) ( équivalent du Delay(50) ) dans le proramme Java pour ralentir l'envoi à l'arduino mais tant que les 368 caractères n'ont pas été envoyés, l'arduino ne fait rien

je suppose que pw.write correspond à un java io PrintWriter.writer ? utilisez vous l'option avec autoFlush pour l'instancier?

PrintWriter(OutputStream out) // Creates a new PrintWriter, without automatic line flushing, from an existing OutputStream.
PrintWriter(OutputStream out, boolean autoFlush) // Creates a new PrintWriter from an existing OutputStream.

la signature complète d'u write est public void write(char[] buf,int off,int len) (avec un pointeur sur le tableau, l'offset par rapport au début du tableau et le nombre d'éléments à envoyer)

Généralement on fait un flush() ensuite pour s'assurer que le caractère ou la string est bien partie

char[] tableau = {'a', 'b', 'c', 'd', 'e', 'f'};
PrintWriter pw = new PrintWriter(System.out);// create a new writer
pw.write(tableau, 1, 3); // write char
pw.flush();     // flush the writer

--> au lieu de mettre un délai de 50, mettez le pw.flush(); dans la boucle.

Comme il n'y a pas de gestion de l'overflow, il serait bon de vous assurer que votre PC ne balance pas plus vite les caractères que votre arduino saura les traiter. ce sera important pour plus tard quand votre arduino commandera des mouvements physques d'un robot je suppose pour faire pivoter les faces. ça prendra du temps et donc il ne faut pas saturer le buffer d'entrée de l'arduino

En fait il se peut bien que l'intégralité de vos lettres aient été envoyées mais l'arduino n'en a vu qu'une centaine environ sur les 368 caractères le reste étant tombé dans la saturation du buffer d'entrée. Faites imprimer à votre programme Java un compte de ce qu'il envoie.

J-M-L:
je suppose que pw.write correspond à un java io PrintWriter.writer ? utilisez vous l'option avec autoFlush pour l'instancier?

PrintWriter(OutputStream out) // Creates a new PrintWriter, without automatic line flushing, from an existing OutputStream.

PrintWriter(OutputStream out, boolean autoFlush) // Creates a new PrintWriter from an existing OutputStream.




la signature complète d'u write est `public void write(char[] buf,int off,int len)` (avec un pointeur sur le tableau, l'offset par rapport au début du tableau et le nombre d'éléments à envoyer)

Généralement on fait un `flush()` ensuite pour s'assurer que le caractère ou la string est bien partie

char[] tableau = {'a', 'b', 'c', 'd', 'e', 'f'};
PrintWriter pw = new PrintWriter(System.out);// create a new writer
pw.write(tableau, 1, 3); // write char
pw.flush();    // flush the writer


--> au lieu de mettre un délai de 50, mettez le `pw.flush(); ` dans la boucle. 

Comme il n'y a pas de gestion de l'overflow, il serait bon de vous assurer que votre PC ne balance pas plus vite les caractères que votre arduino saura les traiter. ce sera important pour plus tard quand votre arduino commandera des mouvements physques d'un robot je suppose pour faire pivoter les faces. ça prendra du temps et donc il ne faut pas saturer le buffer d'entrée de l'arduino


En fait il se peut bien que l'intégralité de vos lettres aient été envoyées mais l'arduino n'en a vu qu'une centaine environ sur les 368 caractères le reste étant tombé dans la saturation du buffer d'entrée. Faites imprimer à votre programme Java un compte de ce qu'il envoie.

Je n'utilise pas l'option autoFlush pour créer le PrintWriter, qu'est-ce que cela change ? J'ai testé avec l'autre méthode .write et la même chose se produit.
J'ai testé de mettre le pw.flush() dans la boucle, mais toujours la même chose.
Si j'essaye d'imprimer ce qu'envoie mon programme, je ne peux que faire :

System.out.println(arduinoResolution.charAt(y));

Ce n'est pas réellement ce que le programme envoie mais plus ce qu'il devrait envoyer. Mais en tout cas, toutes les lettres apparaissent dans la console.

EDIT: En rajoutant le pw.flush; ainsi que le Thread.sleep(50), l'arduino semble tout recevoir, je vais vérifier.

EDIT: En rajoutant le pw.flush; ainsi que le Thread.sleep(50), l'arduino semble tout recevoir, je vais vérifier.

Cela semblerait donc indiquer que vous saturiez la buffer d'entrée de l'Arduino

Sans le flush tous les caractère partaient d'un coup de temps en temps, au bon vouloir de Java. avec le flush vous êtes sûr qu'ils sont envoyé avant d'envoyer le prochain.

Mais sans attente, votre PC reste bcp trop rapide pour votre Arduino et l'arduino ne reçoit pas tout. avec 50ms d'attente côté Java et le flush, vous êtes sans doute très large et donc en effet l'arduino doit tout recevoir et tout traiter

J-M-L:
Cela semblerait donc indiquer que vous saturiez la buffer d'entrée de l'Arduino

Sans le flush tous les caractère partaient d'un coup de temps en temps, au bon vouloir de Java. avec le flush vous êtes sûr qu'ils sont envoyé avant d'envoyer le prochain.

Mais sans attente, votre PC reste bcp trop rapide pour votre Arduino et l'arduino ne reçoit pas tout. avec 50ms d'attente côté Java et le flush, vous êtes sans doute très large et donc en effet l'arduino doit tout recevoir et tout traiter

En effet, le problème est réglé. Merci à tous pour votre aide.

Vous pourriez envisager d'avoir le code Java qui écoute aussi l'arduino et que l'arduino lui dise c'est bon, je suis dispo pour la prochaine commande. ça vous permettra d'être bcp plus générique dans votre code et pas mettre un délai arbitraire de 50 ou de 10, mais d'envoyer la prochaine commande quand l'arduino est prêt à la recevoir.

J-M-L:
Vous pourriez envisager d'avoir le code Java qui écoute aussi l'arduino et que l'arduino lui dise c'est bon, je suis dispo pour la prochaine commande. ça vous permettra d'être bcp plus générique dans votre code et pas mettre un délai arbitraire de 50 ou de 10, mais d'envoyer la prochaine commande quand l'arduino est prêt à la recevoir.

Bonne idée, on va sûrement essayer ça, merci pour la proposition.

bien sûr vous pourriez aussi avoir une petite caméra sur l'arduino qui regarde le Rubix Cube sous chaque face et calcule les mouvements puis les exécute - sans passer par le PC :slight_smile: