Go Down

Topic: digitalWrite en 0 ou LOW ne répond pas (Read 801 times) previous topic - next topic

bidouilleelec

Bonjour Zlika,
........Si, dans une fonction, la comparaison se limite à 0 et not(0), pas de problèmes car on englobe toutes les valeurs possibles..................
Il se trouve que c'est exactement le test effectué par digitalWrite() pour l'Arduino.
Mais je suis tout à fait en accord avec l'ensemble de votre post.

Cordialement,
bidouilleelec

bidouilleelec

#16
Jul 26, 2019, 05:50 am Last Edit: Jul 26, 2019, 09:25 am by bidouilleelec
Bonjour Zlika
Le dernier code ne fonctionnera pas je pense.
Code: [Select]
readString = "";
 sera exécuté à chaque fois que le buffer de réception sera vide.
Ce sera sûrement la cas si on compare la vitesse de réception des données et la vitesse d'exécution de la boucle.
Peu de chance que la chaine de commande soit complètement reçu en une seule loop.
Il faudrait la placer après chaques commandes validées.
Toute la chaine de caractères est reçue dans le
Code: [Select]
while (Serial.available()) {

delay(3) n'est pas utile.

Code: [Select]
readString = "";

"Il faudrait la placer après chaques commandes validées."  :
C'est plus joli mais pas nécessaire et ça n'use pas beaucoup plus l'Arduino.
Au moins on est certain que la String (horreur!) est réinitialisée!

Cordialement,
bidouilleelec

J-M-L

#17
Jul 26, 2019, 08:31 am Last Edit: Jul 26, 2019, 08:32 am by J-M-L
Comme un parfait newbin moi je ferais ça:
Code: [Select]
void loop() {
  while (Serial.available()) {
    delay(3);
    char c = Serial.read();
    readString += c;
  }
....
}

Ne jamais se croire plus intelligent qu'un protocole asynchrone et faire un delay() pour attendre que les caractères arrivent... si available dit qu'il y a quelque chose, alors il faut le lire et attendre le prochain en regardant si available est non nul (ou si read ne retourne pas -1).
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

savoriano

Quote
dans le cas d'une comparaison avec la constante HIGH qui vaut 1, une valeur autre que 1 et 0 ne donnera pas forcément une égalité à HIGH.
C'est dans les posts comme celui-ici qu'on apprends le plus.

Quote
et faire un delay() pour attendre que les caractères arrivent
J'avais juste ajouté au code un serial.println(readString) pour voir justement si la transmission était juste.

Quote
String (horreur!)
Ça, ça mérite un post! je vais chercher d'abord s'il n'y eu un dans le passé.

J-M-L

Si vous voulez comprendre comment bien écouter le port série (ou gérer un flux asynchrone genre keypad) vous pouvez jeter un oeil à mon petit tuto sur le sujet
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Zlika

Bonjour bidouilleelec et les autres,

Comme très bien écrit dans le tuto de J-M-L, on ne peut pas garantir la transmission du message de commande en un temps minimum, pour le traiter dans une seule loop.

C'est ce côté sensible aux problèmes (et généralement la loi de Murphy non le rappelle toujours  :smiley-wink:) qui rends ce code bancal.

Certe, on pourrait toujours augmenter le débit de la transmission (malheureusement pas possible avec certains modules), mais on ne pourra pas prévoir une interruption momentanée de la transmission de l'émetteur (ressources partagées, interférences, code bloquant).

Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

savoriano

Pour que notre ami ArduinoTesteur09 comprends aussi j'ai fait ça:
Code: [Select]
const int A1A = 10;//define pin 2 for A1A
const int A1B = 11;//define pin 3 for A1B

const int B1A = 8;//define pin 8 for B1A
const int B1B = 9;//define pin 9 for B1B
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(B1A, OUTPUT); // define pin as output
  pinMode(B1B, OUTPUT);

  pinMode(A1A, OUTPUT);
  pinMode(A1B, OUTPUT);
}
void loop() {
  while (Serial.available()) {
    //delay(3);
    char c = Serial.read();
    readString += c;
  }
  readString.trim();
  if (readString.length() > 0) {
    Serial.println(readString);
    if (readString == "avancerdrone") {
      AvancerDrone();
      readString = "";
    }
    if (readString == "reculerdrone") {
      ReculerDrone();
      readString = "";
    }
    if (readString == "stoperdrone") {
      StoperDrone();
      readString = "";
    }
  }
//  readString = "";

}

void AvancerDrone() {
  Serial.println("Avancer");
  motorA('R');// Turn motor A to RIGHT
  motorB('R'); // Turn motor A to RIGHT
}
void ReculerDrone() {
  Serial.println("Reculer");
  motorA('L');// Turn motor A to RIGHT
  motorB('L'); // Turn motor A to RIGHT
}
void StoperDrone() {
  Serial.println("Stoper");
  motorA('0');// Turn motor A OFF
  motorB('0');// Turn motor B OFF
}

void motorA(char d) {
  if (d == 'R') {
    digitalWrite(A1A, LOW);//10
    digitalWrite(A1B, HIGH);//11
  } else if (d == 'L') {
    digitalWrite(A1A, HIGH);
    digitalWrite(A1B, LOW);
  } else {
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF
    digitalWrite(A1A, LOW);
    digitalWrite(A1B, LOW);
  }
}

void motorB(char d) {

  if (d == 'R') {
    digitalWrite(B1A, LOW);//8
    digitalWrite(B1B, HIGH);//9
  } else if (d == 'L') {
    digitalWrite(B1A, HIGH);
    digitalWrite(B1B, LOW);
  } else {
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF
    digitalWrite(B1A, LOW);
    digitalWrite(B1B, LOW);
  }

}

résultat en envoyant "stoperdrone":
s
s
s
s
s
s
s
s
s
s
s
st
stoper
stoperdrone
Stoper

ArduinoTesteur09

L'objectif de la refonte du code :

Code: [Select]

digitalWrite(B1A,LOW);


vers

Code: [Select]

digitalAnalog(B1A, 255);


était de pouvoir contrôler la puissance des moteurs, avec

Code: [Select]

digitalAnalog(B1A, 127);


M'aurai permit de faire fonctionner mes moteurs a 50%

Je suis repassé sur mon précédent code fonctionelle et je vais chercher une autre façon de faire

Code: [Select]

void motorA(char d)
{
  if(d =='R'){
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,HIGH);
  }else if (d =='L'){
    digitalWrite(A1A,HIGH);
    digitalWrite(A1B,LOW);   
  }else if (d =='S'){
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,LOW);   
  }
}// motorA end


/*
 * @motorB
 * activation rotation of motor B
 * d is the direction
 * R = Right
 * L = Left
 */
void motorB(char d)
{

    if(d =='R'){
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,HIGH);
    }else if(d =='L'){
      digitalWrite(B1A,HIGH);
      digitalWrite(B1B,LOW);   
    }else if (d =='S'){
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF     
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,LOW);     
    }

}// motorB end



Merci à tous pour vos retours c'était très instructif

cdlt

Zlika

#23
Jul 26, 2019, 01:26 pm Last Edit: Jul 26, 2019, 01:44 pm by Zlika
Oui

On voit bien la progression de la réception de la commande à chaque loop.

Tu as envoyé la même commande une deuxième fois derrière ?

Si c'est le cas, il faut donc interpréter que la première commande, une fois complétée et exécutée, à provoquée l'effacement de la variable 'readString'.
Et la valeur qui suit (Stoper) est le début de la commande suivante en cours de transmission.

L'inconvénient de ce code et qu'il ne sait pas écarter les commandes non valides.

On peut par exemple imaginer une octet mal interprété.

On a le cas peu probable, mais possible, qu'une deuxième commande est déjà en cours de transmission et remplie déjà le buffer.

Comme on utilise une boucle while qui vide le buffer et range tous les caractères dans la variable 'readString', le résultat serait alors une concaténation de 2 commandes (la deuxième pas forcément complète).

Dans les deux cas, le code ne videra la variable 'readString' qu'à la réception d'une commande valide.
Ce qui n'arrivera plus jamais car, la valeur stocker actuellement dans 'readString' ne correspondra jamais aux commandes validés, quelques soient les caractères ajoutés.

D'où l'intérêt d'utiliser un caractère spécifique (comme dans l'exemple de J-M-L):
- qui sera utilisé pour définir le moment où la comparaison avec les commandes valides peut être faite (gain de temps d'exécution ).
- pourra réinitialisation la variable 'readString' et attendre la commande suivante, dans le cas où la commande n'est pas valide.

Cela impose de tester chaque caractère que l'on prend dans le buffer et, le cas échéant, de sortir de la boucle de lecture si une comparaison est nécessaire.

Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

Zlika

#24
Jul 26, 2019, 01:35 pm Last Edit: Jul 26, 2019, 01:40 pm by Zlika
@ArduinoTesteur09: pourquoi revenir en arrière, votre idée était bonne.

Il faut juste aller au bout de la transition en remplaçant les digitalWrite par des analogWrite qui accepte des valeurs de 0 à 255.

Vous pouvez utiliser les valeurs 0 et 255 dans un premier temps pour simuler l'instruction digitalWrite.

Mais n'oubliez pas de vérifier que vos broches utilisées sur votre carte sont bien compatibles avec le mode PWM.
Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

lesept

J'ai lu les messages en diagonale, donc je vais peut-être être à côté de la plaque, mais as tu besoin de lui envoyer un roman à chaque commande ? Il me semble plus simple d'envoyer S pour stop, A pour avancer, G pour gauche, etc.
Et pour varier la vitesse, tu envoies un nombre entre 1 et 10 par exemple, et tu ajustes le paramètre du analogWrite en fonction.
Tu peux aussi envoyer les commandes entre des délimiteurs de début et de fin de message, par exemple %A5* pour avancer à vitesse moyenne.

Ensuite tu peux ajouter une notion de temps, pour le faire avancer pendant dix secondes, puis tourner à droite, puis avancer cinq secondes et s'arrêter. Tout ça avec une seule liste de commandes, T pour indiquer une durée : %A5T10DT3AT5S*
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

ArduinoTesteur09

#26
Jul 27, 2019, 04:36 pm Last Edit: Jul 27, 2019, 04:49 pm by ArduinoTesteur09
je le contrôle en temps reel via un frontend web et clavier connecté en websocket avec jquery en client et nodejs en serveur sur mon raspberry qui s'occupe de faire passer les commandes via le port serie à l'arduino

pour l'instant je suis en phase de débug uniquement sur l'arduino

pour le roman sur les commandes, ca ne change rien à ma problématique l'objectif étant qu'il réagisse simplement à la commande demandé, je verrai une fois que c'est fonctionnel pour l'optimisation du code pour gagner en mémoire sur l'arduino

Actuellement sur ce code ci, j'ai toujours le bug ou le drone repart systématiquement en marche avant après réception de commandes

Code: [Select]

const int A1A = 10;//define pin 2 for A1A
const int A1B = 11;//define pin 3 for A1B

const int B1A = 8;//define pin 8 for B1A
const int B1B = 9;//define pin 9 for B1B
String readString;

void setup(){
  Serial.begin(9600);
  pinMode(B1A,OUTPUT);// define pin as output
  pinMode(B1B,OUTPUT);
 
  pinMode(A1A,OUTPUT);
  pinMode(A1B,OUTPUT);
}
void loop(){
  while (Serial.available()) {
    delay(3); 
    char c = Serial.read();
    readString += c;
  }
  readString.trim();
    if (readString.length() >0) {
    if (readString == "avancerdrone"){
        AvancerDrone();
        readString ="";
    }
     if (readString == "reculerdrone"){
        ReculerDrone();
        readString ="";
    }
    if (readString == "stoperdrone"){
        StoperDrone();
        readString ="";
    }
  }
}

void AvancerDrone(){
   Serial.println("Avancer");
   motorA('R');// Turn motor A to RIGHT
   motorB('R'); // Turn motor A to RIGHT
}
void ReculerDrone(){
   Serial.println("Reculer");
   motorA('L');// Turn motor A to RIGHT
   motorB('L'); // Turn motor A to RIGHT
}
void StoperDrone(){
   Serial.println("Stoper");
    motorA('S');// Turn motor A OFF
    motorB('S');// Turn motor B OFF
}

/*
 * @motorA
 * activation rotation of motor A
 * d is the direction
 * R = Right
 * L = Left
 */
void motorA(char d)
{
  if(d =='R'){
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,HIGH);
  }else if (d =='L'){
    digitalWrite(A1A,HIGH);
    digitalWrite(A1B,LOW);   
  }else if (d =='S'){
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,LOW);   
  }
}// motorA end


/*
 * @motorB
 * activation rotation of motor B
 * d is the direction
 * R = Right
 * L = Left
 */
void motorB(char d)
{

    if(d =='R'){
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,HIGH);
    }else if(d =='L'){
      digitalWrite(B1A,HIGH);
      digitalWrite(B1B,LOW);   
    }else if (d =='S'){
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF     
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,LOW);     
    }

}// motorB end







pour mon schéma de cablage j'ai reproduis ce projet trouvé sur google avec comme carte une :L9110S H-pont , uniquement la partie sur les deux moteurs cc, le drone ne possède pas de servo moteurs comme dans l'exemple de cablage
dans l'exemple les moteurs sont alimentés via une pin 5v sur l'arduino, j'ai modifié avec une alimentation externe en 12v (sinon les moteurs tournaient à peine)

https://www.laintimes.com/robot-sur-chassis-chenille-et-bras-robotique-avec-arduino-et-raspberry-version-2/


lesept

Mon idée était de simplifier la loop
Code: [Select]

if (Serial.available ()) {
char c=Serial.read () ;
switch c;
  case 'a' :
    AvancerDrone () ;
    break :
  case 'r' :
    ReculerDrone () ;
    break :
  case 's' :
    StoperDrone () ;
    break ;
}
Vérifier la syntaxe du switch car j'ai un accès à internet et à ma mémoire assez limité...
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

J-M-L

oui la syntaxe n'est pas tout à fait cela:
Code: [Select]
  switch (Serial.read ()) {
    case 'a':
      AvancerDrone () ;
      break;
    case 'r':
      ReculerDrone () ;
      break;
    case 's':
      StoperDrone () ;
      break;
  }
comme la valeur lue n'est pas spécialement à sauvegarder, on peut se passer de tester available() et read() retournera -1, qui n'est pas pris dans le switch()

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

ArduinoTesteur09

Je vais tester cette syntaxe en conservant le Serial.available () qui me parait indispensable afin de vérifier que la liaison serie est bien disponible, je vous fais un retour

Go Up