Aller au contenu


Photo
- - - - -

"if" ou "switch case" ?


5 réponses à ce sujet

#1 thermo_nono

thermo_nono

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 783 messages

Posté 11 juin 2019 - 12:45

Salut, afin d'optimiser mes instructions I²C entre mon R-pi3 et des arduinos, j'ai recouru à une bidouille qui m'oblige, côté arduino à effectuer un traitement sur l'instruction reçue. 
Ce traitement utilise des instructions "if" et "else if"... je pourrai aussi utiliser l'instruction "switch... case" pour un résultat identique. 
Laquelle de ces deux instructions est la plus rapide ? 
je met le bout de code en question au cas ou ça serait utile pour la réponse... 
 

void loop() {
  int vitesseM1;
  int vitesseM2;  
  if (dataReceived){
    if(dataReceived < 32) {
      vitesseM1 = map(dataReceived, 0, 31, -60, -255);
    }
    else if(dataReceived == 32) {
      vitesseM1 = 0;
    }    
    else if(dataReceived > 32 and dataReceived < 64) {
      vitesseM1 = map(dataReceived, 32, 63, 60, 255);
    }
    else if(dataReceived > 63 and dataReceived < 96) {
      vitesseM2 = map(dataReceived, 64, 95, -60, -255); 
    }
    else if(dataReceived == 96) {
      vitesseM2 = 0;
    }    
    else if(dataReceived > 96 and dataReceived <= 127) {
      vitesseM2 = map(dataReceived, 97, 127, 60, 255);  
    }    
    setVitesseMoteur1(vitesseM1); // definir une vitesse entre -255 et 255 pour le moteur 1
    setVitesseMoteur2(vitesseM2); // definir une vitesse entre -255 et 255 pour le moteur 2    
  }
}

merci d'avance pour vos réponses. 

PS : je pense réduire le nombre de conditions en ne gardant qu'un moteur par arduino afin de résoudre le problème dû au manque de pins autorisant l'interruption hardware (PID).

 

 



#2 R1D1

R1D1

    Modérateur et Membre passionné

  • Modérateur
  • PipPipPipPipPip
  • 1 131 messages
  • Gender:Male
  • Location:Autriche

Posté 11 juin 2019 - 02:30

Tu ne peux pas utiliser de switch/case ici: switch/case fonctionne sur des valeurs fixes pré-définies ou utilise le comportement par défaut. En gros, tu peux dire "variable == valeur", mais pas "variable < valeur". Tout cas non-défini correspond à "case: default".
Par ailleurs, je doute qu'on observe des différences de vitesse de traitement entre if/else ou switch/case; Si tu penses que tu as ce problème, tu peux utiliser millis() et calculer le temps passé à exécuter la condition.
Si tu veux simplifier le code, tu peux utiilser une multimap (qui fait en gros ce que tu fais là mais avec une fonction déjà implémentée.
Par ailleurs, un encodage plus efficace de ta comm serait d'avoir un seul encodage de ta valeur de vitesse (de 0 à 32, avec 0==0, 1=60, 32=255, ou de lire directement la valeur x et de calculer vitesse = 0.159 * x + 60) et d'envoyer un code pour le signe et le moteur (peut-être tout directement en binaire pour combiner les infos). La fonction que tu mappes est simplifiable (si la comm du RPi le permet).
R1D1 - Calculo Sed Ergo Sum -- en ce moment, Projet Ballista
Avatar tiré du site bottlebot

#3 thermo_nono

thermo_nono

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 783 messages

Posté 11 juin 2019 - 04:25

oui, au départ j'étais parti sur l'idée du binaire mais de bidouille en bidouille j'en suis arrivé là... 
Je pense que je vais reprendre pour un seul moteur par arduino (après tout les clones de nano c'est pas cher à côté du prix d'un moteur avec réducteur et codeur et il y a toujours l'histoire des interruptions du PID ^^). 
donc je dois mapper mon entrée (de 0 à 127)
sur ma sortie dont les plages sont :  [-255, -60] U [0] U [60, 255]
Je pense que le plus rapide pour faire calculer ça serait de considérer les nombres impairs de mon entrée comme négatifs et les nombres pairs comme positifs.. ainsi le bit de poids faible indique la direction et il reste à effectuer une translation de mon nombre binaire (division par deux si je me souviens bien) pour connaitre la vitesse (et la remapper sur [60, 255]). 

... j'espère ne pas dire trop d'âneries, c'est tellement loin tout ça.. ^^



#4 Sandro

Sandro

    Nouveau membre

  • Membres
  • 59 messages

Posté 11 juin 2019 - 11:20

Bonjour,

Je confirme, utiliser le switch n'est possible que si tu as une seule valeur qui doit être égale aux valeurs de tes cas. Il est certes possible de bidouiller pour transformer des tests en une valeur unique, mais c'est peu lisible et probablement bien pire en terme de performance.

 

Après, au vue des informations que tu nous a donnée, je pense que tu te trompe de problème.

- Un if ou un switch sont extrêmement rapide (je pense moins d'une microseconde*). Calculer l'expression qui est dans le if/switch peut parfois être long (si par exemple c'est une fonction compliquée), mais dans ton cas, c'est aussi très rapide (je dirais 0.5 à 5 µs*). Donc je pense que tant que tu n'approche pas des 10 000 Hz (ie 10 000 tours de boucle par seconde), ça reste négligeable.           [* = je me bases uniquement sur le fait qu'un arduino fonctionne à 16MHz (ie 16 000 000 instructions assembleur par seconde) et sur une vague estimation de la complexité en assembleur d'un if ou d'un calcul : je n'ai ni testé, ni regardé à quel point c'est optimisé lors de la compilation]

- Les opérations entrée/sortie (par exemple le fait de commander le moteur depuis setVitesseMoteur1) sont en général beaucoup plus longues. Si vraiment tu es limite, et que tu dois faire ces opérations très souvent (ie >10 000Hz), alors tu peux envisager d'écrire directement sur les ports correspondants.

- en général, il est parfaitement inutile et contre-productif de vouloir optimiser ce genre de choses à la main : en général, si le programme est trop lent, il faut revoir l'algorithme, pas ce genre de détails.

- un moteur, ça a pas mal d'inertie : du coup, ça ne sert à rien de vouloir le commander très souvent car il n'aura pas le temps de changer vitesse. Du coup il est parfaitement inutile de vouloir exécuter ta boucle des milliers de fois par seconde (probablement 10 fois par seconde est suffisent). Et si tu exécute ta boucle moins de 1000 fois par seconde, alors optimiser les if ne donnera aucune différence perceptible.

 

En gros, à 99% sur, le bout de code que tu nous montre n'a absolument pas besoin d'être optimisé.

 

 

Si ton programme est trop lent, alors explique nous qu'est-ce que tu essaye de faire et donne nous tout le code, et on t'aidera volontiers à trouver quel est l'élément limitant (le seul pour lequel c'est une bonne idée de l'optimiser) et comment l'améliorer.

 

 

Bonne soirée

Sandro



#5 thermo_nono

thermo_nono

    Membre chevronné

  • Membres
  • PipPipPipPip
  • 783 messages

Posté 12 juin 2019 - 12:10

Merci pour ta réponse. 

 

En effet, pour le moment l'arduino ne s'occupe que d'un moteur, mais j'envisage de lui coller quelques capteurs à ultrasons pour (par la suite) faire quelques essais de "simulation de réflexes" si un obstacle est trop prêt du robot... mais dans un premier temps c'est surtout pour réduire le temps de réponse (l'arduino confirme qu'il a bien reçu l'instruction du R-pi, et pendant la réponse le R-pi devra attendre, et ce, pour chacune des 4 roues). Et c'est surtout sur le R-pi que je souhaite ne pas perdre trop de temps car il devra en plus analyser un flux vidéo via opencv (Merci au passage à L42Project pour ses super tutos sur opencv :  https://youtu.be/-3xbAkCWJCc  ). 
Ceci dit, je pense que tu as raison : Cette routine ne sera pas lancée des milliers de fois par seconde du coup c'est insignifiant au niveau du temps d’exécution.  

Merci pour ta réponse. 



#6 Sandro

Sandro

    Nouveau membre

  • Membres
  • 59 messages

Posté 12 juin 2019 - 06:34

Si le délai te semble critique, alors tu as plusieurs solutions:

coté arduino:

-tu peux utiliser une intéruption : dans l'intéruption, la seule chose que tu fais, c'est copier la commande et confirmer que tu l'a bien reçue. Tu traitera ensuite commande depuis la boucle loop()

- alternativement, il suffit de confirmer la reception de la commande avant de commencer à la traiter.

 

coté Rpi:

- si tu mets la communication dans un thread séparé, alors elle ne bloquera pas le reste. Alternativement, au lieu d'attendre pour la réponse, tu peux de temps à autre vérifier s'il y en a une (non bloquant).

- n'hésite pas à mettre le traitement vidéo dans un thread séparé aussi, comme ça il ne bloquera pas le reste du programme (et un Raspi récent a 4 coeurs, donc si tu es limite coté temps d'exécution, alors essaye de répartir le calculs sur plusieurs coeurs.





Répondre à ce sujet



  


0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users