entete

Xbot: utiliser le PWM

Rappelons que les pins 2 à 7 sont sur les bits 2 à 7 port D du processeur Avr368.
Les bits 4 à 7 commandent les moteurs, avec les bits 5 et 6 qui permettent le PWM Arduino, ils sont donc utilisés comme signaux pour faire avancer.

Sur le Xbot et le LCbot, activer les pins 5 et 6 allume une LED verte, que l'on pourra voir en intensité variable. Les pins 4 et 7 activent une LED rouge en tout-ou rien.

LcPins.gif

Utilisons le PWM

La commande des moteurs se fait de trois façons
1) en tout ou rien avec les macros Avance; Recule; TourneD; TourneG; Stop;
     (chapitre précédent)
2) en PWM avec les fonctions PwmGD (int,int); comme on va le voir
     (déclarés dans XBotPwm.h) valeur pwm entre –255 et +255
3) en PFM avec les fonctions VitD (byte);  VitG (byte);
     (prochain chapitre)

<td width="490" height="306" valign="top">

1. Fichiers de définitions 

Les fichiers XbotDef.het  XbotADef.h ont été utilisés dans XbotDebut avec les moteurs en tout-ou-rien.

Pour une vitesse proportionnelle, il faut de nouvelles définitions. La fonction Arduino analogWrite(pin,v8) travaille par interruption. La macro Stop(); que nous avons vue coupe le moteur, mais pour quelque millisecondes seulement si on ne donne pas l'instruction analogWrite(pin,0);

Rappelons que la fonction analogWrite() ne donne pas une sortie analogique entre 0 et 5V. Elle génère des impulsion de largeur variable. Le moteur va donc reçevoir une quantité d'énergie qui varie entre 0 et 99% si le paramètre vaut entre 0 et 255. En fait, de 0 à 10-30% selon la qualité du moteur, il n'y a pas assez d'énergie pour qu'il démarre. Le PFM que l'on verra dans le prochain chapitre n'a pas ce défaut

2. PWM  Arduino

Les pins 5 et 6 (AvG et AvD) acceptent l'ordre analogWrite (pin,byte); qui est géré par interruption et interrompt le programmes pour 10 microsecondes toutes les millisecondes environ.

La fonction analogWrite() n'est disponible que pour 5 pins sur les cartes Arduino simples. Il faut éviter d'utiliser les 3 autres.
C'est donc facile de programmer pour avancer à vitesse variable (supérieure à 10-30% de Pwm). Pour reculer, il faut une astuce vue plus loin.

Pour programmer le déplacement en cercle en Arduino débutant, il suffit d'écrire

// Cercle.ino| Vitesses fixe
#define RecD 4 // HIGH LOW
#define AvD 5 // pwm
#define AvG 6 // pwm
#define RecG 7
void setup()
{
pinMode(RecG,OUTPUT);
pinMode(AvG,OUTPUT);
pinMode(AvD,OUTPUT);
pinMode(RecD,OUTPUT);
}
byte vitG= 50;
byte vitD= 200;
void loop ()
{
digitalWrite (RecG,LOW);
digitalWrite (RecD,LOW);

analogWrite(AvG,vitG);
analogWrite(AvD,vitD);
}

Comment réduire le diamètre si le robot frotte la paroi?
Comment faire une spirale?

La question importante est comment reculer? Essayez d'activer RecD ou RecG et comprenez.

2. PWM avec  XbotPwm.h

Pour reculer, il faut une astuce expliquée dans www.didel.com/robots/MotorControl.pdf

Le fichier à inclure  XbotPwm.h en résulte. Il définit la fonctions PwmGD(vitG,vitD);
Elle s'applique aux moteurs du Xbot et il ne faut plus utiliser la librairie simple en tout-ou-rien. Les définitions des moustaches ont été conservées.

Les paramètres sont des entiers signés (int),  entre –255 et +255.

Programmer un cercle se fait en une instruction.

// CerclePWM.ino| Vitesses fixe
#include XbotPWM.h
void setup() {
SetupXbotPWM();
}

int vitG= 50; // entiers signés
int vitD= 200;

void loop () {
  VitGD(vitG,vitD);
}

 

On change de sens
void loop () {
 VitGD (vitG,vitD);

 delay (1000);
 VitGD (-vitG,-vitD);
 delay (1000);
}


// XbotPwm.h
#include <Arduino.h>
#define RecD 4 // HIGH LOW
#define AvD 5 // pwm
#define AvG 6 // pwm
#define RecG 7
void PwmGD (int pp, int qq) {
  if (pp==0) {
    analogWrite(AvG, 0);
    digitalWrite(RecG, LOW);
  } else if (pp > 0) {
    analogWrite(AvG, pp);
    digitalWrite(RecG, LOW);
  } else {
    analogWrite(AvG, 255+pp);
    digitalWrite(RecG, HIGH);
  }
  if (pp==0) {
    analogWrite(AvD, qq);
    digitalWrite(RecD, LOW);
  } else if (pp > 0) {
    analogWrite(AvD, qq);
    digitalWrite(RecD, LOW);
  } else {
    analogWrite(AvD, 255+qq);
    digitalWrite(RecD, HIGH);
  }
}

#define bMousD 3 // PORTD,3)
#define bMousG 2
#define ObsG !(PIND&1<<bMousG)
#define ObsD !(PIND&1<<bMousD)

void SetupXbotPwm() {// initialisation
 DDRD |= 0b11110000 ;
 DDRD &= 0b11110011 ;
}

Si on veut du tout-ou-rien, il suffit d'ajoute une macro ou une fonction:

Macro Fonction
#define Avance() PwmGD(255,255)

void Avance() {
  PwmGD(255,255);
}

Aller-retour en accélérant-déccélérant

// AllerRetPwm.ino aller-retour
#include "XbotPwm.h"
void setup() {
  SetupXBotPwm();
} //  accélère en 2.5s
int vit;
void loop() {
  for (vit=0; vit<255; vit++) {
    SetPwmG (vit); SetPwmD (vit);
    delay (10);
  }
  for (vit=255; vit>-255; vit--) {
    SetPwmG (vit); SetPwmD (vit);
    delay (10);   }
  for (vit=-255; vit<=0; vit++){
    SetPwmG (vit); SetPwmD (vit);
    delay (10);
  }
}

Utiliser le capteur de distance SR04 ou SR05

Ce capteur est bien connu. Les exemples Arduino sont "bloquants", c'est à dire que pendant 0.1 à 0.5secondes, le programme principal est bloqué en attente du résultat. Comme le PWM se fait par interruption, mettre à jour la vitesse après chaque mesure est suffisant.

Le programme suivant fait avancer le robot tant que la distance est supérieure à une certaine valeur. Il attend 1 seconde et décide à nouveau. On éloigne l'obstacle et on voit que le robot suit.

// ResteDistSR05.ino
// Je Xbot s'approche et s'arrête à la bonne distance
// PWM Arduino initialé d'office

#include "XbotPwm.h"
#include "SR05.h"
void setup() {
SetupXbotPwm();
SetupSR05();
}

#define Dist 100 // environ 15cm
#define Vit 50
void loop () {
while (GetSonar()>Dist) {PwmGD(Vit,Vit);}
PwmGD(1,1);
delay(2000);
}

//SR05.h Libraire Uson

void SetupSR05() {
pinMode(Trig,1);
pinMode(Echo,0);
}

int GetSonar () {
digitalWrite(Trig,HIGH);
delayMicroseconds(10);
digitalWrite(Trig,LOW);
return (pulseIn(Echo,HIGH));
}

Remarques

Pour faciliter la portabilité, les notations Arduino ne sont utilisées que dans les fichiers de définition, et dans des fonctions mises dans des "librairies" de bas niveau, qui dépendent du matériel et de la couche Arduino par dessus le C.

Les #define définissent soit des équivalences simples, soit des équivalent de fonctions appelés macros.
Par exemple Avance(); peut avoir été défini comme une macro ou comme une fonction. Les instructions de la macro sont répétées à chaque appel. La fonction est appelée et "coûte" 4-6 bytes mémoire. On ne fait donc que des macros de quelques instructions C. Mais une instruction Arduino est une fonction de 10-20 instructions C.

Comment continuer

Notre démarche est de tester les fonctions nouvelles dans un programme simple, et de les encapsuler dans un fichier inclus pour que le programme principal reste aussi proche que possible d'une description fonctionnelle de l'applications. Utiliser des librairies Arduino est toujours possible, mais souvent ces librairies sont surdimensionnées

Le document Exemples avec la librairie LibX montre l'avantage d'utiliser un afficheur simple pour visualiser la valeur des capteurs, l'état d'avancement, les erreurs.

Le document OledUtile vise un objectif similaire avec un affichage Oled.

Le 3e chapitre de cette série permet de faire de plus jolies applications en utilisant le PFM pour la commande de moteurs et les interruptions pour gérer plusieurs capteurs en parallèle.

jdn 170816