Robot, capteurs et binaires: quel foutoir!

Salut!

J'ai reconstruit mon proto. Pour ceux qui ont suivi, on faisait du signal de mes 5 capteurs un seul "code" type B00000. C'était lent et j'ai pensé à une astuce.
J'ai gardé 3 capteurs côte à côte, et un devant, il anticipe les virages :smiley: (ouais je sais ... :smiley: )

Le capteur de tête b0 (ou FRONT dans les commentaires) évite bien des calculs. S'il voit une ligne noire, on fonce, et basta.
Dès que b0 devient 1 (donc il n'est plus sur la ligne noire), on entame un switch case.

b1 b2 et b3 devraient me renvoyer un "code" type B000

Seulement, n'ayant pas vraiment encore tout bien compris (et ayant passé 1 journée et demi à tout démonter et recoller sur un nouveau châssis), je me retrouve avec des bizarreries inexploitables.

POUR RESUMER:
b0, du capteur FF est traité à part avec un if
b1 b2 et b3 devraient se retrouver dans un bon B000 pour pouvoir traiter les combinaisons en switch case.

Voici mon code

//LINE TRACKER BY KAMMO

//STEPPER, définition des pins

#define E1 10    // Enable PWM Pin for motor 1
#define E2 11    // Enable PWM Pin for motor 2
#define I1 8     // Control pin a for motor 1
#define I2 9     // Control pin b for motor 1
#define I3 5    // Control pin a for motor 2
#define I4 6    // Control pin b for motor 2

//Définition des pins
//Pins Capteurs:  LL LC CC CR RR
byte PinFF = 7; //Front sensor
byte PinLL = 2; //LPin capteur Left Left
byte PinCC = 3; //Center Center
byte PinRR = 4; //Right Right

//Déclaration des variables de lecture binaire
boolean b3, b2, b1, b0;
byte b = 0;


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

  //Pins Moteurs
  pinMode(E1, OUTPUT);
  pinMode(E2, OUTPUT);
  pinMode(I1, OUTPUT);
  pinMode(I2, OUTPUT);
  pinMode(I3, OUTPUT);
  pinMode(I4, OUTPUT);

  //Pins digitaux capteurs
  pinMode ( PinLL , INPUT) ;
  pinMode ( PinCC , INPUT) ;
  pinMode ( PinRR , INPUT) ;
  pinMode ( PinFF , INPUT) ;
  delay(2000);


}

void loop() {

  // Lire les valeurs des capteurs et en faire des valeurs binaires
  b0 = (digitalRead (PinFF) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b1 = (digitalRead (PinLL) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b2 = (digitalRead (PinCC) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b3 = (digitalRead (PinRR) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  // on construit un octet avec des 1 pour chaque booléen qui est à vrai
  b = (b3 ? B1000 : B0) | (b2 ? B100 : B0) | (b1 ? B10 : B0) ;


  print5bits(b);  //fonction qui construit une chaine binaire de type B00000

  if ((b0 = HIGH) && (b2 = HIGH)) {
    //vitesse max
    analogWrite(E1, 250);
    analogWrite(E2, 250);
  }
  else {
    //vitesse max
    analogWrite(E1, 170);
    analogWrite(E2, 170);

  }
}


void print5bits(byte aByte)
{
  Serial.println(F("B"));
  for (int8_t aBit = 3; aBit >= 1; aBit--) {
    Serial.println(bitRead(aByte, aBit) == 0 ? F("0") : F("1")); //
  Serial.println();
  Serial.print (b0,BIN);
  Serial.println(aByte,BIN);
  Serial.println(" ");
  delay(500);
}
//si le capteur FRONT est sur la ligne, on bourre à fond les bananes
if (b0 == 0) {
//  VITMAX();
Serial.println("A FOND LES BANANES");
}
else {
//  VITMED(); //anticiper une manoeuvre en ralentissant

  //on compare les possibilités

  switch (aByte) {
  case B011 :
      Serial.println("Braquer à gauche");
    break;
    case B001 :
        Serial.println("courbe à gauche");
    break;
    case B100 :
        Serial.println("courbe à droite");
    break;
    case B110 :
        Serial.println("braquer à droite");
    break;
    case B111 : //tout blanc=hors piste
        Serial.println("hors piste");
    break;
    case B000 : //intersection, impossible d'avancer
        Serial.println("intersection, impossible d'avancer");
    break;
  }
}}

// VITMED();
//}


//On compare le résultat
//1= blanc 0=ligne noire
//B1234 1=G 2=C 3=D 4=F

/*switch (aByte) {


  //SANS VIRAGE ////////////////////


  case B1000:  //virage en approche
  VITMED();
  TOUTDROIT(); //
  break;

  case B11111:  //sortie de circuit=marche arrière
  VITMED();
  ARRIERE();
  break;

  //VIRAGES
  case B0001:
  VIRAGE90(00011);
  break;
  case B11000:
  VIRAGE90(11000);
  break;

  //EPINGLES //////////////////////
  case B00001:
  EPINGLE(00001);
  break;
  case B10000:
  EPINGLE(10000);
  break;

  //VIRAGES à droite/////////////////
  case B10011:  //vir droite 15deg
  VIRAGEDROITE(15);
  break;
  case B10111:  //vir40
  VIRAGEDROITE(40);
  break;
  case B00111:  //vir60
  VIRAGEDROITE(60);
  break;
  case B01111:  //vir75
  VIRAGEDROITE(75);
  break;

  //VIRAGES à gauche//////////////////
  case B11001:  //vir gauche 15deg
  VIRAGEGAUCHE(15);
  break;
  case B11101:  //vir40
  VIRAGEGAUCHE(40);
  break;
  case B11100:  //vir60
  VIRAGEGAUCHE(60);
  break;
  case B11110:  //vir75
  VIRAGEGAUCHE(75);
  break;

  default:  //commande inconnue
  ARRET();
  break;
  }//fin de switchcase
  }

  // Fonctions différentielles

  void TOUTDROIT() {  //pour aller tout droit
  //vitesse max
  analogWrite(E1, 200);
  analogWrite(E2, 200);
  //marche avant
  digitalWrite(I1, HIGH);
  digitalWrite(I2, LOW);
  digitalWrite(I3, HIGH);
  digitalWrite(I4, LOW);
  }

  void ARRIERE() {  //pour reculer
  //vitesse moyenne
  analogWrite(E1, 100);
  analogWrite(E2, 100);
  //marche arr
  digitalWrite(I1, LOW);
  digitalWrite(I2, HIGH);
  digitalWrite(I3, LOW);
  digitalWrite(I4, HIGH);
  }

  void ARRET() {  //stopper
  //vitesse zero
  COUPDEFREIN();
  analogWrite(E1, 0);
  analogWrite(E2, 0);
  //moteur éteints
  digitalWrite(I1, LOW);
  digitalWrite(I2, LOW);
  digitalWrite(I3, LOW);
  digitalWrite(I4, LOW);
  }
  void VIRAGE90(byte sens) { // virage 90°
  COUPDEFREIN(); //un bon coup de patins
  //vitesse max
  analogWrite(E1, 120);
  analogWrite(E2, 120);

  //pivoter
  switch (sens) {
    case 00011:
      digitalWrite(I1, HIGH);
      digitalWrite(I2, LOW);
      digitalWrite(I3, LOW);
      digitalWrite(I4, HIGH);
      break;
    case 11000:
      digitalWrite(I1, LOW);
      digitalWrite(I2, HIGH);
      digitalWrite(I3, HIGH);
      digitalWrite(I4, LOW);
      break;
  }
  }

  //épingle
  void EPINGLE(byte sens) {
  COUPDEFREIN(); //un bon coup de patins

  switch (sens) {

    case 00001:
      analogWrite(E1, 155);
      analogWrite(E2, 40);
      digitalWrite(I1, HIGH);
      digitalWrite(I2, LOW);
      digitalWrite(I3, LOW);
      digitalWrite(I4, HIGH);
      break;
    case 10000:
      analogWrite(E1, 40);
      analogWrite(E2, 155);
      digitalWrite(I1, LOW);
      digitalWrite(I2, HIGH);
      digitalWrite(I3, HIGH);
      digitalWrite(I4, LOW);
      break;
  }
  }

  void VIRAGEGAUCHE(byte angle) {  //tourner en fonction d'un angle
  COUPDEFREIN(); //un bon coup de patins

  //définir la vitesse de la roue gauche
  int vitesse = map(angle, 0, 90, 255, 0); //détermine la vitesse de la roue intérieure proportionnellement à l'angle

  analogWrite(E1, vitesse);
  analogWrite(E2, 200);
  //marche avant
  digitalWrite(I1, HIGH);
  digitalWrite(I2, LOW);
  digitalWrite(I3, HIGH);
  digitalWrite(I4, LOW);


  }

  void VIRAGEDROITE (byte angle) {
  COUPDEFREIN(); //un bon coup de patins

  //définir la vitesse de la roue gauche
  int vitesse = map(angle, 0, 90, 255, 0); //détermine la vitesse de la roue intérieure proportionnellement à l'angle

  analogWrite(E1, 200);
  analogWrite(E2, vitesse);
  //marche avant
  digitalWrite(I1, HIGH);
  digitalWrite(I2, LOW);
  digitalWrite(I3, HIGH);
  digitalWrite(I4, LOW);
  }


  /////////////GESTION DE LA VITESSE

  void VITMAX() { //met la vitesse au max
  analogWrite(E1, 255);
  analogWrite(E2, 255);
  }

  void VITMED() {  //vitesse à moitié
  analogWrite(E1, 125);
  analogWrite(E2, 125);
  }

*/

Il doit encore traîner des tas de commentaires à effacer, désolé pour le désordre.

Merci

Mais c'est quoi le problème ?

Bonsoir lesept,
Le problème c'est que, lorsque je traite ma variable aByte (si c'est bien celle là) dans mon switchcase, je cherche à comparer quelque chose sous la forme B000, or, ce n'est pas ce que j'obtiens.
Je voudrais que ça se présente comme l'attendent mes case, c'est pas le cas.

Extrait de la doc :

Syntax
switch (var) {
  case label1:
    // statements
    break;
  case label2:
    // statements
    break;
  default:
    // statements
}
Parameters
var: a variable whose value to compare with various cases. Allowed data types: int, char
label1, label2: constants. Allowed data types: int, char

Ta variable aByte est un byte, ça peut pas marcher. Déclare la en int.
Si ça ne suffit pas, de même les labels doivent être des int ou des char. Essaye de remplacer tes "Bxx" par leurs valeurs int. Exemple B011 = 3

Hmmm JML avait trouvé une solution.
Celle que tu proposes, je l'ai testée, mais question programmation c'est moins clair.
B000 a l'avantage d'être très compréhensible par rapport à 18 par exemple.
J'ai du supprimer ou modifier une ligne en recopiant le code.
Je dois comparer avec l'ancien code, mais j'ai du mal.

Ca doit venir de ce charabia ^^

void print5bits(byte aByte)
{
 Serial.print(F("B"));
  for (int8_t aBit = 3; aBit >= 0; aBit--)
  Serial.print(bitRead(aByte, aBit) == 0 ? F("0") : F("1")); //
 Serial.println();

  //On compare le résultat

  

  switch (aByte) {


    //SANS VIRAGE ////////////////////
    case B11011:  //tout droit
      TOUTDROIT();
      break;

Je ne comprends pas bien ce for sans accolades ...
J'en ai mis ça marche aussi... Je comprends pas ce qu'il fait.

ou de là quand on construit les binaires

void loop() {

  // Lire les valeurs des capteurs et en faire des valeurs binaires
  b0 = (digitalRead (PinFF) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b1 = (digitalRead (PinLL) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b2 = (digitalRead (PinCC) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  b3 = (digitalRead (PinRR) == HIGH); // HIGH ou LOW suivant comment c'est configuré
  // on construit un octet avec des 1 pour chaque booléen qui est à vrai
  b = (b3 ? B1000 : B0) | (b2 ? B100 : B0) | (b1 ? B10 : B0) | (b0 ? B1 : B0) ;


  print5bits(b);  //fonction qui construit une chaine binaire de type B00000

Il construit si c'est VRAI
J'ai aucune idée de si c'est VRAI HIGH ou1 ...

Rahhh c'est rageant ^^

Un for sans accolade n'exécute qu'une seule instruction dans la boucle

  for (int8_t aBit = 3; aBit >= 0; aBit--)
  Serial.print(bitRead(aByte, aBit) == 0 ? F("0") : F("1"));

La boucle ne fait que le Serial.println.

Le Serial.println fait un test et affiche le résultat. Le test c'est

bitRead(aByte, aBit) == 0 ? F("0") : F("1"));

Si bitRead(aByte, aBit) vaut 0 il affiche 0 sinon 1.
bitRead lit le bit numéro "aBit" de la variable "aByte". Le println affiche le bit en question, mais sus forme d'un caractère.
Pour le reste:
b0 = (digitalRead (PinFF) == HIGH);affecte à b0 la valeur 1 si pinFF est HIGH, sinon 0.
idem pour les autres. Ensuite

  b = (b3 ? B1000 : B0) | (b2 ? B100 : B0) | (b1 ? B10 : B0) | (b0 ? B1 : B0) ;

crée le binaire sur 4 bits b3 b2 b1 b0. C'est assez sioux comme truc : il fait pour chaque bit un test similaire à celui que j'ai expliqué au début mais affecte 1000 (en binaire) ou 100 ou 10 ou 1 si le bit est à 1. Il fait ensuite la somme (ou logique) de tous ces binaires pour créer la variable b.

Déjà, ici

  print5bits(b);  //fonction qui construit une chaine binaire de type B00000

  if ((b0 = HIGH) && (b2 = HIGH)) {

il y a un problème, tu devrais écrire

  print5bits(b);  //fonction qui construit une chaine binaire de type B00000

  if ((b0 == HIGH) && (b2 == HIGH)) {

sinon tu modifies les variables pendant le test.

L'écriture B000 est valide c'est une constante entière

Autrement, ton codes est un beau bordel et ce serait bien de ne publier que le code "actif" sans les lignes de code mises en commentaires parce que ça le rend difficile à lire. Je ne l'ai compris qu'après l'avoir recopié dans un éditeur avec la coloration syntaxique.

Par pitié, indente correctement ton code !
Il suffit de taper Control-T dans l'IDE, c'est pas vraiment dur, non ?
Quand je vois des lignes comme ça:

}}

je pars en courant !

Un truc que j'ai vu avant de m'enfuir : :slight_smile:

  if ((b0 = HIGH) && (b2 = HIGH)) {

D'abord ce n'est pas = qu'i faut employer c'est ==
ensuite b0 est un booléen, ses valeurs possibles sont true ou false.
TU as déjà traité la comparaison à HIGH/LOW dans la ligne

  b0 = (digitalRead (PinFF) == HIGH);

Merci lesept pour le décryptage, j'ai tout ce qu'il faut pour que ça tourne.

Côté code en foutoir, c'est marqué dans le titre.
Le comparateur avec les HIGH et les = au lieu des ==, ouais, je sais, j'étais en train de rectifier le code. Notons d'ailleurs que cette ligne est une erreur, puisqu'elle n'existe plus ce matin dans mon code. Elle ne répondait pas à mon problème. J'espérais qu'elle m'aide à mettre le doigt sur un problème.

Les accolades, quand je cherche d'où vient un souci, une erreur, je les mets à la suite, ça fait moins mal aux yeux à compter.

Cela dit, c'est pas très agréable de se faire engueuler en ouvrant le forum. C'est pas ça qui aide le plus...

Ceci dit, merci :slight_smile:
Je retourne à mon code en foutoir.

biggil:
ensuite b0 est un booléen, ses valeurs possibles sont true ou false.
TU as déjà traité la comparaison à HIGH/LOW dans la ligne

  b0 = (digitalRead (PinFF) == HIGH);

En effet. D'ailleurs, je crois bien que je n'ai pas besoin d'une variable ici, il suffit que je lise à la volée la valeur HIGH/LOW, ça fait économiser une variable... Peut-être mieux.

kammo:
Les accolades, quand je cherche d'où vient un souci, une erreur, je les mets à la suite, ça fait moins mal aux yeux à compter.

Si tu indentes correctement ton code tu n'as justement pas à compter les accolades c'est l'indentation qui t'indique le niveau d'imbrication.
Le plus simple c'est de prendre l'habitude d'ajouter une tabulation à la ligne suivante lorsque tu ouvres une accolade et de la supprimer lorsque tu la fermes. Si tu te foires à un moment l'option de reformatage du code de l'IDE fait le travail pour toi. (et il le fait plutôt bien)

Oui. Entre le moment où j'ai commencé ce code et aujourd'hui j'ai appris.
Le fait est qu'IDE prend parfois l'initiative d'ajouter une accolade, lorsqu'on ouvre un if notamment. Du coup je crée des doublons en les rentrant manuellement.
J'indente mon code, prochaine fois que j'ai besoin d'un coup de mains je ferai bien attention à la présentation et j'y mettrai un petit nœud de couleur.

En attendant, j'ai pris la solution de lesept. Je traite des chiffres tout simples de 1 à 7. Moins fun, moins clair, mais ça fonctionne.

hello
je ne suis pas sur d'avoir bien compris ce que tu voulais faire
je pensais à un code de ce genre

/*
  #define E1 5    // Enable PWM Pin for motor 1
  #define E2 6    // Enable PWM Pin for motor 2
  #define I1 2     // Control pin a for motor 1
  #define I2 3     // Control pin b for motor 1
  #define I3 4    // Control pin a for motor 2
  #define I4 7    // Control pin b for motor 2

  //Définition des pins
  //Pins Capteurs:  LL LC CC CR RR
  byte PinFF =  8; // PB0 //Front sensor
  byte PinLL =  9; // PB1 //LPin capteur Left Left
  byte PinCC = 10; // PB2 //Center Center
  byte PinRR = 11; // PB3 //Right Right
*/
void setup() {
  Serial.begin(115200);
  for (int f = 2; f <= 7; f++) {
    pinMode(f, OUTPUT);
  }
  for (int f = 8; f <= 11; f++) {
    pinMode(f, OUTPUT);
  }
  delay(2000);
}

void loop() {
  byte capteurs = PINB & 0b00001111; //Serial.print("capteurs = ");Serial.println(capteurs);

  switch (capteurs) {
    case 0b0000 :
      Serial.println("a fond");
      break;
    case 0b0001 :
      Serial.println("Braquer à gauche");
      break;
    case 0b0010 :
      Serial.println("courbe à gauche");
      break;
    case 0b0011 :
      Serial.println("courbe à droite");
      break;
    case 0b0100 :
      Serial.println("braquer à droite");
      break;
    case 0b0101 :
      Serial.println("hors piste");
      break;
    case 0b0110 :
      Serial.println("case 6");
      break;
    case 0b0111 :
      Serial.println("case 7");
      break;
    case 0b1000 :
      Serial.println("case 8");
      break;
    case 0b1001 :
      Serial.println("case 9");
      break;
    case 0b1010 :
      Serial.println("case 10");
      break;
    case 0b1011 :
      Serial.println("case 11");
      break;
    case 0b1100 :
      Serial.println("case 12");
      break;
    case 0b1101 :
      Serial.println("case 13");
      break;
    case 0b1110 :
      Serial.println("case 14");
      break;
    case 0b1111 :
      Serial.println("case 15");
      break;

  } delay(2000);
}

Je croyais que switch ne fonctionnait qu'avec une variable de type int ou char. Non ?

hello lesept
j'ai testé le code sur une breadboard et simulé les capteurs avec des fils portés soit à 5V soit à GND,
le résultat s'affiche sur le moniteur, c'est ok
la seule contrainte est de respecter l'implantation des capteurs pour avoir les 4 premiers bits du port B.
je ne suis pas un spécialiste du codage, mais l'insistance de kammo pour coder en utilisant le binaire m'a tellement intrigué que j'ai voulu tester.
edit:
ceci dit, ce n'est peut être pas ce que Kammo voulait faire

Bon à savoir, merci

lesept:
Je croyais que switch ne fonctionnait qu'avec une variable de type int ou char. Non ?

Non la spécification dit

any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type,

donc un byte va très bien aussi

lesept:
Je croyais que switch ne fonctionnait qu'avec une variable de type int ou char. Non ?

De base, switch attend un argument de type int.
Donc, tout type qui peut être converti implicitement en un int (char, unsigned char, byte, short...) fonctionne aussi.
Avec un long ça va marcher aussi mais le compilo devrait mettre un warning (possibilité de troncature)

Arrgghhh, grillé par J-M-L !

biggil:
Arrgghhh, grillé par J-M-L !

:slight_smile:

et non, on ne peut pas dire que

De base, switch attend un argument de type int.

je vous ai mis la définition ci dessus. Un integral type en C++ est un élément de type bool, char, signed char, unsigned char, char16_t, char32_t, wchar_t, short, int, long, long long, unsigned short, unsigned int, unsigned long, unsigned long long

donc aucun soucis avec un long, le compilateur ne se plaindra absolument pas.