traducteur braille

Bonjours, je travail actuellement sur un projet qui a pour but de traduire un texte numérique en language braille à l’aide de 2 moteurs. Le texte est envoyé depuis une application créée à l’aide d’app inventor, les caractères du texte sont classés un à un dans un tableau à deux dimensions et le programme va ensuite associé chaque lettre à un certain déplacement pour les moteurs. Mon problème est le suivant: j’arrive à classé mon texte dans le tableau avec ce programme :

#include <SoftwareSerial.h>
SoftwareSerial HC06(11, 10);
char texte[4][16];
int idx1 = 0;
int idx2 = 0;

void setup() {
  Serial.begin(9600);
  HC06.begin(9600);
}

void loop() {

  while (HC06.available() > 0) {
    if ( idx1 < 16 ) {
      idx1++;
      texte[idx2][idx1] = HC06.read();
      Serial.print(texte[idx2][idx1]);
    }

    else if ( idx2 < 4 ) {
      idx2++;
      idx1 = 0;
      Serial.println(" ");
    }
  }
}

Mais lorsque j’ajoute ma partie traitement du tableau, plus rien ne marche, mon message bluetooth n’est même pas reçu ni classé donc pas traité par la suite voici le code:

#include <SoftwareSerial.h>
char texte[4][16];
SoftwareSerial HC06(11, 10);

int face[7];
int MemDisk[32];
int Edisque[1];
int x = 0;
int suite_txt = 0;
int idx1 = 0;
int idx2 = 0;
int idx3 = 0;
int idx4 = 0;


void setup() {
Serial.begin(9600);
HC06.begin(9600);

for (int indice0 = 0; indice0 < 7; indice0++) {      
    face[indice0] = 256 * indice0;
  }

  for (int indice1 = 0; indice1 < 32; indice1++) {    
    MemDisk[indice1] = 0;
  }
}

void loop() {
  while (HC06.available()>0){
    if ( idx1 < 16 ) {
      idx1++;
      texte[idx2][idx1] = HC06.read();
      Serial.print(texte[idx2][idx1]);
    }

    else if ( idx2 < 4 ) {
      idx2++;
      idx1 = 0;
      Serial.println(" ");
    }
  }
   while (idx4<3 & idx3<16) {
  if (texte[idx4][idx3] == 'a') {
    Serial.println("a ->");
    Serial.print(face[1] - face[MemDisk[x]]);
    MemDisk[x] = 1;
    x++;
    Serial.print(face[0] - face[MemDisk[x]]);
    MemDisk[x] = 0;
    x++;
    idx3++;
  }

  if (texte[idx4][idx3] == 'b') {
    Serial.println("b ->");
    Serial.print(face[2] - face[MemDisk[x]]);
    MemDisk[x] = 2;
    x++;
    Serial.print(face[0] - face[MemDisk[x]]);
    MemDisk[x] = 0;
    x++;
    idx3++;
  }

  if (texte[idx4][idx3] == 'c') {
    Serial.println("c ->");
    Serial.print(face[1] - face[MemDisk[x]]);
    MemDisk[x] = 1;
    x++;
    Serial.print(face[1] - face[MemDisk[x]]);
    MemDisk[x] = 1;
    x++;
    idx3++;
  }

  if (texte[idx4][idx3] == 'd'){
    Serial.println("d ->");
    Serial.print(face[1] - face[MemDisk[x]]);
    MemDisk[x] = 1;
    x++;
    Serial.print(face[2] - face[MemDisk[x]]);
    MemDisk[x] = 2;
    x++;
    idx3++;
  }
 }
}

Si vous pouviez m’aider à résoudre mon problème, merci d’avance. :slight_smile:

Dans ta loop, si aucun caractère n’arrive par le HC06, tu rentres dans une boucle while :

while (idx4<3 & idx3<16) {

dont tu ne sors jamais car idx3 et idx4 ne sont pas changés.

Et ceci se passe dès le début, car tu n’as pas le temps d’envoyer du texte avant d’entrer dans cette boucle. Donc tu as l’impression qu’aucun texte n’est reçu.

Merci de ta réponse, en effet j’ai manqué de logique sur ce point, j’ai retravaillé un peu mon programme, j’ai ajouter une temporisation dans la partie “affectation des caractères dans le tableau” afin de pouvoir rentrer tous mes caractères, sans celle ci je recevais un seul caractère. En revanche je n’arrive toujours pas a rentrer dans la partie “traitement” de mon tableau si vous pouviez m’aider merci d’avance.

#include <SoftwareSerial.h>
char texte[4][16];
SoftwareSerial HC06(11, 10);
const int bouton_suite_txt = 8;

int face[7];
int MemDisk[32];
int Edisque[1];
int x = 0;
int suite_txt = 0;
int idx1 = 0;
int idx2 = 0;
int idx3 = 0;
int idx4 = 0;
int Etatbouton_suite_txt = 0;


void setup() {
  Serial.begin(9600);
  HC06.begin(9600);

  for (int indice0 = 0; indice0 < 7; indice0++) {
    face[indice0] = 256 * indice0;
  }

  for (int indice1 = 0; indice1 < 32; indice1++) {
    MemDisk[indice1] = 0;
  }
}

void loop() {
  while (HC06.available() > 0) {
    if ( idx1 < 16 ) {
      idx1++;
      texte[idx2][idx1] = HC06.read();
      Serial.print(texte[idx2][idx1]);
      delay(3);
    }

    else if ( idx2 < 4 ) {
      idx2++;
      idx1 = 0;
      Serial.println("");
    }
  }
  if (idx2 != 0 || idx1 != 0) {
    idx2 = 0;
    idx1 = 0;
    while (idx4 < 3 && idx3 < 16) {
      if (idx3 > 15) {
        Etatbouton_suite_txt = digitalRead(bouton_suite_txt); //attendre que le système soit arriver en bout de ligne avant d'accioner le bouton
        if (Etatbouton_suite_txt == HIGH) {
          Serial.println("suite du texte");
          idx4++;
          idx3 = 0;
          x = 0;
          if (idx4 > 3) {
            Serial.println("fin du message");

          }
        }
      }
      if (texte[idx4][idx3] == 'a') {
        Serial.println("a ->");
        Serial.print(face[1] - face[MemDisk[x]]);
        MemDisk[x] = 1;
        x++;
        Serial.print(face[0] - face[MemDisk[x]]);
        MemDisk[x] = 0;
        x++;
        idx3++;
      }

      if (texte[idx4][idx3] == 'b') {
        Serial.println("b ->");
        Serial.print(face[2] - face[MemDisk[x]]);
        MemDisk[x] = 2;
        x++;
        Serial.print(face[0] - face[MemDisk[x]]);
        MemDisk[x] = 0;
        x++;
        idx3++;
      }

      if (texte[idx4][idx3] == 'c') {
        Serial.println("c ->");
        Serial.print(face[1] - face[MemDisk[x]]);
        MemDisk[x] = 1;
        x++;
        Serial.print(face[1] - face[MemDisk[x]]);
        MemDisk[x] = 1;
        x++;
        idx3++;
      }

      if (texte[idx4][idx3] == 'd') {
        Serial.println("d ->");
        Serial.print(face[1] - face[MemDisk[x]]);
        MemDisk[x] = 1;
        x++;
        Serial.print(face[2] - face[MemDisk[x]]);
        MemDisk[x] = 2;
        x++;
        idx3++;


      }
    }
  }
}

attention avec

    if ( idx1 < 16 ) {
      idx1++;
      texte[idx2][idx1]
...

si idx1 vaut 15 on rentre dans le if, vous le passez à 16 et vous essayez d’écrire dans texte[idx2][16]. Hors vous avez déclaré char texte[4][16]; donc vous n’avez pas 17 cases (de 0 à 16 ça ferait 17 valeurs, le dernier indice possible et 15)…

même chose pour idx2

    else if ( idx2 < 4 ) {
      idx2++;

→ il peut passer à 4

→ débordement de tableau = comportement erratique garanti

Quand on appelle print sur un tableau de caractères il faut s’assurer qu’il se termine bien par un caractère nul. ‘\0’.

il ne faut pas mettre de délai dans le code quand on travaille avec le port Série. essayer de deviner quand des caractères vont arriver dans un protocole asynchrone, ça ne marche pas.

Si vous voulez comprendre comment bien écouter le port série vous pouvez jeter un oeil à mon petit tuto sur le sujet

Merci de la réponse, j’ai lu votre sujet, très intéressant et je l’ai adapté à mon cas. Il me reste quelques questions :
-Comment réserver une seul case au caractère de fin de chaîne (\0) ? Parceque moi je lui est réservé une ligne entière soit 16 cases.
Je pense qu’il faut réutiliser la constante “tailleMessageMax” pour ma question mais je sais pas trop comment m’y prendre.

-Il semble que le caractère en bout de ligne disparaît, comment résoudre ce problème ?

-A quoi servent les “F” dans les “Serial.print” ?
Sinon c’est parfait, j’ai essayé de traiter le premier caractère de mon tableau cela fonctionnait. Voici le programme que j’ai adapté :

#include <SoftwareSerial.h>
SoftwareSerial HC06(11, 10);
const byte tailleMessageMax = 63;
char texte[5][16];

const char marqueurDeFin = '#';

boolean ecouter()
{
  static byte idx1 = 0; 
  static byte idx2 = 0;
  boolean messageEnCours = true;

  while (HC06.available() && messageEnCours) {
    int c = HC06.read();
    if (c != -1) {
      Serial.print(F("Octet lu: 0x")); Serial.print(c, HEX); // ici c est un entier, on affiche le code ASCII en Hexadécimal
      Serial.print(F("\t[")); Serial.print((char) c); Serial.println(F("]"));
      switch (c) {
        case marqueurDeFin:
          Serial.println(F("Fin de chaine"));
          texte[idx2][idx1] = '\0'; // on termine la c-string
          idx1 = 0;
          idx2 = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (idx1 < 15)
          texte[idx2][idx1++] = (char) c; // on stocke le caractère et on passe à la case suivante
          else if ( idx2 < 3 ) {
            idx2++;
            idx1 = 0;
          }
          else  Serial.println(F("j'ignore!"));
          break;
      }
    }
  }
  return messageEnCours;
}

void setup() {
  Serial.begin(9600);
  HC06.begin(9600);
}

void loop() {
  if (! ecouter()) {
    // si on a reçu le marqueur de fin
    Serial.print(F("Phrase: [")); Serial.print(texte[0]); Serial.print(texte[1]);
    Serial.print(texte[2]); Serial.print(texte[3]); Serial.println(F("]"));
  
    }
  }

je n'ai pas bien compris pourquoi vous devez avoir un tableau à 2 dimensions.

vous recevez des caractères, gardez les juste dans un buffer avec la fonction écouter et quand vous avez reçu le marqueur de fin (qui est ignoré exprès) vous parcourez la chaîne reçue caractère par caractère et vous générez le comportement moteur associé.

j'ai raté un truc ?

Ma machine est capable d'afficher 16 caractères en même temps donc dès que je reçois un message par bluetooth elle se met en marche et affiche les caractères braille correspondant à la première ligne de mon tableau. Ensuite, on appui sur un bouton, la machine se remet à 0 et affiche la deuxième ligne et ainsi de suite jusqu'à afficher mes 4 lignes. Je pensais alors plus simple de faire un tableau à 2 dimensions et incrémenter l'indice des ligne lorsqu'on appui sur le bouton pour afficher les 16 caractères suivant.

votre arduino a peu de mémoire, qui va envoyer les données et à quel rythme ?

(vous avez un processus d'un côté qui envoie du texte et de l'autre j'imagine un humain qui appuie sur le bouton pour "voir" la ligne suivante.

Comment allez vous garantir que trop de données ne sont pas envoyées ?

Pour le moment j'utilise environ la moitié de la mémoire dynamique et de la mémoire de stockage pour le programme sur un arduino uno sachant que je pense être assez proche de la fin mais je vais devoir passer sur une mega vu mon nombre de pins, la mémoire sur la méga étant plus grande sa ne va pas être un problème. J'ai aussi limité le nombre de caractères reçu à 64 en comptant le marqueur de fin.
L'utilisateur dispose de son smartphone avec une appli qui en gros est un terminal qui envoi du texte à l'arduino, elle dispose d'un compteur de caractère afin de bloquer la saisie lorsque le paramètre choisi est dépassé.

J-M-L:
vous avez un processus d'un côté qui envoie du texte et de l'autre j'imagine un humain qui appuie sur le bouton pour "voir" la ligne suivante.

C'est à peu prêt cela, mon objectif est d'utiliser le braille pour communiquer avec une personne sourde et aveugle à la fois. D'un côté une personne avec son smartphone et de l'autre une personnes sachant lire le braille.

OK

une façon de faire est de conserver la fonction qui écoute le port série “propre”, avec son buffer et dans la loop() quand vous avez reçu une nouvelle ligne de texte vous l’enregistrez

J’avais partagé sur le forum anglais récemment un bout de code qui enregistrait ce qui arrivait du moniteur Série dans un tableau, soit avec 2 dimension statiques, soit en utilisant de l’allocation mémoire dynamique, ce qui pourrait conduite à de l’instabilité dans votre cas car il faudra libérer la mémoire.

voilà le code

#define PRE_ALLOCATE_MEMORY true // set it to false if you want to use dynamic memory allocation through strdup()

const uint8_t maxNbofCommand = 10;
const uint8_t maxLengthofCommand = 63;

char serialBuffer[maxLengthofCommand + 1];  // +1 as we want to add a trailing '\0' to terminate a cSrting
uint8_t commandIndex = 0;

#if PRE_ALLOCATE_MEMORY
char listOfCommands[maxNbofCommand][maxLengthofCommand + 1];// +1 as we want to add a trailing '\0' to terminate a cSrting
#else
char* listOfCommands[maxNbofCommand];
#endif


boolean getCommand()
{
  static byte currentIndex = 0;
  boolean commandReady = false;

  while (!commandReady) {
    int c = Serial.read();
    if (c != -1) { // -1 means nothing to read
      switch (c) {
        case '\n':         // end marker --> command complete?
          serialBuffer[currentIndex] = '\0'; // terminate the c-string
          currentIndex = 0; // get ready for next time
          commandReady = true;
          break;

        case '\r':         // ignore CR
          break;

        default:         // otherwise if we have room left, store the incoming char
          if (currentIndex < maxLengthofCommand) serialBuffer[currentIndex++] = (char) c;
          break;
      }
    } else break;
  }
  return commandReady;
}

bool addCommandToList(const char* aCommand)
{
  bool commandAdded = false;
  if (commandIndex < maxNbofCommand) {
#if PRE_ALLOCATE_MEMORY
    strncpy(listOfCommands[commandIndex], aCommand, maxLengthofCommand); // http://www.cplusplus.com/reference/cstring/strncpy/
    listOfCommands[commandIndex][maxLengthofCommand] = '\0'; // to be sure it's properly terminated
    commandIndex++;
    commandAdded = true;
#else
    listOfCommands[commandIndex] = strdup(aCommand); // https://en.cppreference.com/w/c/experimental/dynamic/strdup
    if (listOfCommands[commandIndex] == NULL) {
      Serial.println(F("ERROR: SRAM IS FULL"));
    } else {
      commandIndex++;
      commandAdded = true;
    }
#endif
  } else {
    Serial.println(F("ERROR: COMMAND BUFFER FULL"));
  }
  return commandAdded;
}

void printListOfCommands()
{
  for (byte i = 0; i < commandIndex; i++) {
    Serial.print(i);
    Serial.write('\t');
    Serial.println(listOfCommands[i]);
  }
  Serial.println(F("--------------------------"));
}

void setup()
{
  Serial.begin(115200);
#if PRE_ALLOCATE_MEMORY
  Serial.println(F("STATIC ALLOCATION"));
#else
  Serial.println(F("DYNAMIC ALLOCATION"));
#endif
  Serial.println(F("Ready"));
}

void loop()
{
  if (getCommand())
    if (addCommandToList(serialBuffer)) printListOfCommands();
}

vous ouvrez la console à 115200 bauds (en envoyant CR+LF comme fin de ligne), tapez un message (63 caractères max) et il s’enregistre dans le tableau listOfCommands[] et s’affiche. Tapez un nouveau message et il se rajoutera. ici je garde 10 messages seulement (c’est défini dans la constante maxNbofCommand)

→ il faudra modifier le fonctionnement pour revenir au début du tableau (gestion circulaire) une fois qu’il est plein mais ça pourrait vous donner des idées