dimanche 18 décembre 2011

Améliorations pour faire du debugging

Introduction
Après avoir corrigé un problème de détection sur le capteur infra-rouge droit (ArduinoCar ne faisait que des détections à gauche), j'ai re-téléchargé le programme sur Arduino.

Malgré cette correction ma voiture persiste à croire qu'elle a des obstacles devant elle et forcément passe son temps en marche arrière.
C'est ennuyant... encore plus à cause d'un défaut de conception majeur qui provoque une décharge rapide de mes accus.
Il est donc difficile de débugger mon programme longtemps... encore plus parce que la voiture prend le large... difficile à suivre avec le cable USB qui lui est pourtant nécessaire pour voir les messages de Debug.

J'ai donc décidé de corriger ce défaut de conception afin de m'aider a débugger mes problèmes.

Erreur de conception
L'erreur de conception est la suivante: "je n'ai pas de bouton start/stop".
En effet, le programme démarre directement dès la mise sous tension d'Arduino (pour une durée de 60 sec).
A la fin du programme, si je veux recommencer, il me faut appuyer sur le bouton "reset" d'Arduino.
Mais en quoi est-ce une erreur de conception?
  1. Parce qu'il ne faut pas oublier de mettre le circuit de puissance sous tension... sinon, c'est l'alimentation d'Arduino qui se décharge dans le circuit de puissance.
  2. Dès que je branche le cable USB pour faire du debuging, Arduino est mis sous tension et le programme démarre immédiatement.
    En plus de m'imposer la mise sous tension du circuit de puissance (sinon c'est le régulateur d'Arduino qui alimente l'étage de puissance... à éviter donc!), je peux difficilement placer ArduinoCar dans certaines conditions initiales.
Une seconde erreur ergonomique est également présente: "Il n'est pas possible de désactiver l'étage de puissance" (à comprendre comme "il n'est pas possible d'interrompre la commande moteur") pendant le fonctionnement du programme.

C'est un problème ergonomique du point de vue de la mise au point/Debugging.
Il n'est pas facile de faire le monitoring du programme (via le port série) lorsque l'étage des moteurs (avancer/reculer) est alimenté.
Imaginez-vous courir avec votre pc portable derrière votre véhicule entrain de circuler dans le salon au bout du câble USB. Difficile de lire les messages de Log qui passent à l'écran!

Amélioration de la conception
Pin 7: Marche/Arret - Bouton Pull Down
Je vais donc ajouter un bouton marche/arrêt (pull-down) pour commander le démarrage , l'arrêt et le redémarrage du programme.

Une fois le bouton pressé, la Led de contôle (voir plus loin) s'allumera (ou s'éteindra selon l'état), le programme démarre 3 secondes plus tard.


Pin 8: Debug Start/Stop - Bouton Pull Down
Bouton qui va activer ou désactiver le mode de debug.
En mode débug, les fonctions marche et arret ne commandent plus les pins de sorties des moteurs de propulsion. Autrement dit, la voiture ni n'avancera, ni ne reculera.
Cela pourrait être pratique pour faire du monitoring avec un PC.

En sortant du mode debug, le programme s'arrête (état asEnd).


Pin 9: Led de contrôle
Indique l'état du programme Arduino.
  • Éteinte: Véhicule en attente de mise en marche.
  • Allumée continu: Programme en court de démarrage (1 sec) ou en cours d'exécution (pendant 60 sec)
  • Allumée clignotante: idem allumage continu mais en mode Debuging (pas de commande effective de la propulsion avant/arrière, juste une commande logique).
Schéma de montage
Voici le complément de montage aux précédents schéma déjà publiés.
Ajout des boutons start/stop, debug/no-debug
et de la led de contrôle.
Bien entendu, ce dernier schéma vient se greffer sur les autres schéma existant...
Etage de puissance (voir cet article, mais aussi celui-ci)
Des yeux pour ArduinoCar (voir cet article)
Bornier moteurs (voir cet article)


Nouveaux états
Il faudra également compléter la liste des états affichés dans le précédent article "Premier essai avec les détecteur infrarouge".
Il faut en effet tenir compte des conditions de démarrage et d'arrêt comme par exemple attendre que l'utilisateur presse le bouton "start" :-) .
Le nouveau diagramme d'état est disponible un peu plus loin.

Modification d'état existant:
L'état asInitialized a été modifié et ne correspond plus à la description faite dans l'article "Premier essai avec les detecteur infrarouge".

asInitialized:
La machine à état fini reste dans l'état asInitialized jusqu'au moment ou le bouton start/stop est pressé.
Il passe ensuite dans l'état asWaitToGo.

Nouveaux états:
En plus des états décrits dans les précédents articles (et toujours utilisés), la machine à état fini se voit agrémentée de nouveaux états pour supporter les nouvelles fonctionnalités.

asWaitToGo:
Etat intermédiaire destiné à installer un temps de pause de deux secondes entre le moment ou l'utilisateur démarre le programme (utilisateur presse le bouton start depuis l'état asInitialized) et le démarrage effectif du programme (mise en mouvement du véhicule correspondant à l'état asMove).
asWaitToGo attends deux secondes et passe automatiquement à l'état asMove.

asToggleDebug:
Etat atteignable uniquement depuis asInitialized (donc aussi longtemps que le bouton start n'est pas pressé).
Sa seule action est d'inverser la variable debugState pour ensuite revenir à l'état asInitialized.
Avant de retourner à l'état asInitialized, le programme prend le contrôle de la LED pour indiquer, sans équivoque possible, l'état de la variable debugState (voir diagramme ci-dessous)

asToggleDebugOnRunning:
Tout comme pour asToggleDebug, la seule action de l'état est d'inverser la variable debugState et de prendre le contrôle de la LED pour indiquer, sans équivoque possible, l'état de la variable debugState (voir diagramme ci-dessous).
Seulement, asToggleDebugOnRunning est atteignable uniquement depuis les états asWaitToGo (avant que le programme ne démarre réellement) ou asMove (en attente de détection d'obstacle pendant la marche du véhicule).

Note: Il n'est donc pas possible d'activer le mode Debug pendant que le véhicule est en phase d'évitement.

Ensuite le programme retourner à l'état asEnd (donc arrêt moteur) avant transition vers asInitialized (ce qui revient à une pseudo initialization et un redémarrage du programme dès que l'utilisateur presse le bouton start).

Le nouveau diagramme d'états:
Vous constaterez sans mal que la machine à état fini est sensiblement plus complexe que la précédente version.
Cliquer pour agrandir
Erratum: dans le schéma ci-dessus, j'ai oublié de placer la transistion de asMove vers asToggleDebugOnRunning.

Une nouvelle version logiciel
Cette nouvelle version logiciel inclus les modifications nécessaire à l'intégration des améliorations de conception.
Les classes PushButton et MonoLed (voir article précédent "Inclusion des librairies LedTools et ButtonTools") sont respectivement utilisées pour pour détecter la pression des boutons et faire clignoter la Led (lorsque cela s'applique) de façon non bloquante.

Le code contient également la correction concernant la détection infra-rouge défaillante à droite...
Par contre, la correction du comportement anormal fera, lui, l'objet d'un autre article.
Code Source: a venir

mardi 11 octobre 2011

Inclusion des librairies LedTools et ButtonTools

Je me suis mis en tête de développer deux librairies afin de me faciliter la tâche avec ArduinoCar.
Cela à produit les librairies LedTools et ButtonTools publiées sur Arduino Notepad
Les articles de conception de ces librairies sont également disponibles sur Arduino Notepad:

dimanche 7 août 2011

Premier essai avec les detecteur infrarouge

Introduction
Après avoir monté et testé les détecteurs infrarouge (voir article précédent), j'ai décidé de mettre en place mon premier programme de commande pour Arduino Car.


Principes du programme
Le principe est simple, avancer tout droit jusqu'à rencontrer un obstacle.
Lorsqu'un obstacle est rencontré, le véhicule entame une marche arrière en tournant. Suivant que cela soit le détecteur droit ou gauche ou les deux, le changement de direction en marche arrière est différent.
Finalement, le programme cesse toute activité après 60 secondes (histoire que la voiture ne se mette pas à dévaler toute seule tout le quartier :-) 

Une machine à état fini
Pour facilité la prise en mains, j'ai réduit le fonctionnement d'ArduinoCar en différents états (asSetup, asInitialized, asMove, asChangeDir, asEnd).
La machine peut passer d'un état à l'autre en fonction de conditions visibles sur le graphique.

Différents états de l'ArduinoCar

A chaque étape correspond une ou plusieurs actions exécutées par ArduinoCar.
Dès que l'exécution des actions (correspondant à un état) sont terminés le programme principale termine l'exécution de loop() et rend la main à la couche hardware/logiciel Arduino.
Lorsque qu'Arduino ré-exécutera une nouvelle fois la fonction loop(), l'état de la "machine à état fini" sera très utile pour savoir quelles actions loop() doit entreprendre/exécuter.

Voici une liste des différents états accompagnés d'une description et des actions effectuée par l'état.

asSetup
ArduinoCar entame son initialisation, phase durant laquelle le logiciel configure les pins et initialise les différentes variables/structures.
Cet état est assigné à la première ligne de la fonction Setup().
Si plus tard j'utilise des interruptions, cela permettra au code d'interruption de savoir qu'ArduinoCar n'est pas encore initialisée.

asInitialized
Cet état est assigné à la dernière ligne de la fonction setup().
Cela permet de savoir que tout le processus d'initialisation est terminé... et ArduinoCar peut commencer à fonctionner.
asInitialized n'est qu'un état transitoire destiné à la phase d'initialisation matérielle.
Dès que cette valeur est détecté dans la fonction loop(), ArduinoCar passe automatiquement de l'état asInitialized --> asMove

asMove
Etat quasi permanent d'ArduinoCar.
Dans cet état, ArduinoCar avance en ligne droite et effectue une détection d'obstacle à chaque exécution de loop().
Pour le moment, la détection d'obstacle consiste à tester la proximité des deux premiers détecteurs Infra-Rouge à l'aide de la fonction hasProximity().

Dès qu'un obstacle est détecté, ArduinoCar passe immédiatement dans l'état asChangeDir.

asChangeDir
Etat qui n'intervient que lorsque ArduinoCar à détecté un obstacle.
Le but de cet état est de mettre en place une stratégie d'évitemment qui pour le moment se résume à:
  • Arrêter la marche avant.
  • Entamer une marche arrière.
  • Braquer en marche arrière en fonction du/des détecteurs IR activés.
  • Faire une marche arrière pendant une seconde.
Le but étant de faire 1/4 de tour pour partir dans la direction opposée du détecteur IR activé.
Si les deux détecteurs sont activé, la voiture part vers la gauche.

Lorsqu'ArduinoCar a terminé sa phase d'évitement, le code termine son éxécution en réactivant l'état asMove.

asEnd
Permet d'arrêté ArduinoCar après un temps de fonctionnement défini (60 secondes).
Cet état spécial est activé dans la loop() lorsque le temps d'exécution maximim est atteind.
Lorsque cet état est activé, ArduinoCar arrête les moteurs et replace la direction dans le sens "tout droit".

A part cela, l'état asEnd ne fait rien d'autre que de systématiquement terminer l'exécution de loop().

Premiers résultats
Voici une vidéo du premier résultat obtenu.
De prime abord, je suis assez content de moi... mais... visiblement, cette voiture à un problème!
Elle passe son temps à reculer... comme s'il y avait toujours un obstacle devant elle! Cela me fait penser à un chien atteint de la maladie du carré et donc qui se comporte en dépit de tout sens logique :-)

C'est en fait un bug de conversion-comparaison dans la détection de proximité (voir plus loin... c'est très instructif)



Bug de conversion-comparaison

Comme précisé, ArduinoCar passait son temps a reculer... comme si elle détectait constamment un obstacle!
Sur base de ce constat, j'ai jeter un oeil sur la fonction qui détecte la proximité d'un objet hasProximity().
Le code est assez simple à la base:

boolean hasProximity( byte Proximity ){
  return (Proximity < 255);
}

Cela semble enfantin, pourtant il y a un gros bug!
En effet, la variable Proximity est de type Byte... et par conséquent le compilateur fait le nécessaire pour convertir un Byte (non signé) en un entier (signé) avant de faire la comparaison < 255.
Et comme il y a une différence d'encodage binaire, la valeur Proximity prise telle quelle comme un nombre entier signé apparaît comme négative (si je ne me trompe pas).
En conséquence, hasProximity() est toujours vrai... même s'il n'y a pas d'obstacle.

Pour résoudre le problème, il suffit de faire une conversion explicite vers le type entier signé int :-)
Cela produit le code suivant:

boolean hasProximity( byte Proximity ){
  return ((int)Proximity < (int)255);
}

Il est peut être un peu excessif de forcer explicitement la conversion de 255.
Heureusement que j'ai eu l'occasion de rencontrer des articles mentionnant les problèmes de conversion implicite.

Premières conclusions
Mais aussi premières conclusions.

Conclusion 1: l'arrêt
Ne pas oublier de couper la motorisation quand on passe dans l'état asEnd.
Si cela semble évident, je n'y avais pas pensé dans mon empressement à tester mon premier jet de code.
Comme ArduinoCar est passer de l'état asMove vers asEnd après 60 secondes, j'ai dut me mettre à galoper dans le quartier pour la rattraper... en effet, je n'avais pas pensé à positionner la marche sur arrêt en passant à l'état asEnd!
Ce bug là est déjà corrigé :-)

Conclusion 2: Led et bouton
Il serait bien d'utiliser une led pour indiquer la fin de l'exécution du programme (état asEnd).
Eteind = en cours de fonctionnement
Clignotante = fin de programme.
De même, utiliser un bouton pour démarrer/arrêter la séquence serait plus approprié que d'utiliser le bouton Reset (pour recommencer)


Conclusion 3: Apprendre à freiner et a ralentir
Sur sol plat, la marche à 100 % est très efficace.
Le temps qu'ArduinoCar détecte l'obstacle et passe la marche arrière, le véhicule se fracasse sur l'obstacle du seul fait de son inertie.
Le problème est identique si l'obstacle arrive de biais.

Il y a plusieurs options pour corriger ce problème:
  1. Freiner à la détection de l'obstacle
  2. Diminuer la vitesse de Marche.
    Inférieur à 100% de régime, soit configurable avec un bouton.
Conclusion 4: Obstacle de biais en reculant
Après un changement de direction, il faut avancer un peu avant de faire une nouvelles détection d'obstacle.
En effet, si ArduinoCar recule sur une bordure de trottoir de biais (ou une rigole), les détecteurs sont dirigés vers le sol.
Il en resulte donc une nouvelle détection d'obstacle et une nouvelle tentative de recul et changement de direction.
Pour contourner ce problème facilement, ArduinoCar devrait avancer un peu avant de quitter l'état asChangeDir.

D'autres stratégies pourraient également se monter efficaces.
L'utilisation d'un IMU (inertial measurement unit) pourraient également faciliter la détection d'une telle situation (car modification d'angle du véhicule durant le retour).

Conclusion 5: Redresser la direction
Le redressement de la direction est assuré par un moyen mécanique (ressort).
Ce n'est pas toujours très efficace lorsque le véhicule se déplace.
Il faudrait aider la direction à se redresser en envoyant une impulsion de changement de direction dans l'autre sens.
Il est également possible d'envisager l'usage d'un capteur a effet Hall (et d'un aimant placé sur l'arbre de direction) pour savoir si la direction est bien revenue au point mort.

Conclusion 6: Se méfier de la détection Infrarouge
A plein régime, le véhicule tressaute un peu dans tous les sens.
Cela crée des faux positif de détection d'obstacle (suivant le sens dans lequel le véhicule est bousculer)... et elle se met à faire un changement de direction spontanément.
Pour résoudre ce problème, il faudrait faire un déparasitage logiciel (comme pour les boutons).
Dans ce cas-ci, plutôt que de bloquer l'exécution 10 ms, il serait plus approprié de s'assurer qu'il y ait deux détections consécutives.
A noter qu'après avoir tourné, il faut annuler la dernière détection en date (puisque l'on a changé de direction).

Code Source
Sources: ArduinoCar_StateMachine_v1.zip
Cette archive contient un répertoire avec les deux fichiers sources que j'utilise (en autre ArduinoStates.h qui contient la définition des états sous forme d'un enum).
Il suffit de dézipper le répertoire et ses fichiers dans votre répertoire sketchbook.

Informations utiles sur le code source
La fonction irProximity( int pinIr )
Cette fonction   fait une capture de la proximité à l'aide d'un senseur infrarouge Sharp 2Y0A21 branché sur la pin pinIr.
Cette valeur est transformée en indice de proximité (voir les valeurs de retour).
Pour info, la tension de reférence ARef d'Arduino est fixé à 3.3v pour augmenter la précision de la lecture.

Paramètres:
pinIr - pin analogique sur laquelle le senseur est branché (ex: pinIrGauche, pinIrGauche)

Résultat:Retourne un byte qui représente un indice de proximité.
  • 255: hors du champs de détection
  • 24: 24 cm ou moins
  • 15: 15 cm ou moins
La fonction hasProximity( byte Proximity )
Fonction très simple qui prend l'indice de proximité en paramètre (valeur retournée par la fonction irProximity.

Résultat:Retourne un booléen à  true s'il y a quelque-chose à proximité.

La fonction DoMove()
Cette fonction, appelée continuellement lorsque la voiture est dans l'état asMove à pour principale utilité:
  1. De donner l'ordre de déplacement d'ArduinoCar
  2. De détecter les objets à proximité (appel à irProximity et hasProximity)
  3. De faire le nécessaire pour changer l'état vers asChangeDir si un obstacle est détecté.
Voici le détail de la fonction DoMove():
enum ArduinoState doMove(){
  // Detection de proximité
  irGaucheProximity = irProximity( pinIrGauche );
  irDroiteProximity = irProximity( pinIrDroite );
 
  // Changement de direction ?
  if( hasProximity( irGaucheProximity ) || hasProximity( irDroiteProximity ) )
    return asChangeDir;
 
  marche( AVANT, 100 );
   
  return asMove;
}


Variables volatiles
Dans le point précédent, la fonction DoMove capture les indices de proximités sur les deux détecteurs infrarouges.
Les deux valeurs sont stockées dans les variables globales irGaucheProximity et irDroiteProximity qui sont déclarées comme suit:

volatile byte irGaucheProximity;
volatile byte irDroiteProximity;


Le mot clé volatile informe le compilateur qu'il ne faut pas optimiser le code relatif à l'utilisation des variables en questions.
En effet, sans volatile, le compilateur pourrait décider de changer l'ordre des instructions pour amélioré la rapidité d'exécution.
C'est ainsi que par exemple, le compilateur pourrait changer l'ordre d'exécution d'une boucle for pour qu'elle "décompte" au lieu de "compter". Si en générale cela à peu d'implication sur l'exécution du programme, cela peut avoir des conséquences importantes dans d'autres cas.

Dans le cas d'utilisation de variables tels que irGaucheProximity et irDroiteProximity, l'optimisation du code par le compilateur pourrait réserver des surprises.

Finalement, l'usage d'une variable globale pour le stockage de irGaucheProximity et irDroiteProximity peu paraître à première vue comme "une lacune".
Cependant, à terme, j'ai l'intention de faire une moyenne des deux ou trois dernières lectures de proximité pour éliminer les faux positifs (voir plus haut dans l'article).
Dans ce cas, l'utilisation d'un tableau en variable globale sera approprié... la raison pour laquelle les variables sont déjà déclarées comme globales.

vendredi 22 juillet 2011

Des yeux pour Arduino Car

Introduction
Jusqu'a maintenant, je me suis focalisé sur la propulsion d'Arduino Car.
Si cela en fait un véhicule capable de se déplacer seul, il est aussi terriblement stupide dans ce sens ou il ira se jeter sur le premier obstacle sans même s'en rendre compte.

Voila pourquoi je vais équiper Arduino Car de senseur.
Mon dévolu se porte sur les capteurs infrarouge gp2y0a21 de Sharp.


Capteur infrarouge Sharp gp2y0a21
J'ai justement eu l'occasion d'en acheter 4 chez Antratek.
J'ai d'ailleurs écris l'article "Detecteur de proximité infrarouge - Sharp gp2y0a21" sur Arduino Notepad, un occasion unique pour se faire la main dessus.
L'article précité indique d'ailleurs ou se fournir ce type de capteur.


Montage des capteurs
Je vais commencer par monter deux capteurs sur l'avant de la voiture histoire de détecter les obstacles frontaux.
Une bonne partie de l'article sera consacré à ce montage et aux tests des capteurs.

D'autres capteurs seront nécessaires

Par contre, je sais déjà qu'il me faudra envisager deux autres capteurs, ce que viendra confirmer les premiers tests.
Ces capteurs serviront:
  • Détecter les obstacles en hauteur (pour éviter à la voiture de se jeter sous les meubles bas ou les voitures).
  • Un détecteur de profondeur (orienté vers le sol) pour détecter les trous ou simplement les bordures de trottoir en oblique (45°).
  • Si le détecteur de profondeur est placé au centre de pare-chocs, cela permettra aussi de détecter des objets tels que des pieds de chaises ayant échappé aux deux premiers détecteurs.
Truc et astuces
Pour faciliter le montage, je vous suggère de préparer:
  1. L'utilisation de tout petits colsons (exemple ici) pour faciliter le montage. 
  2. Un fer à souder pour marquer les emplacements des trous à forer pour placer les senseurs infrarouges.
  3. Une mèche pour faire les trous en vue de laisser passer les colsons.
  4. Du fil et des pins headers pour le raccordement sur les entrées A0 et A1 d'Arduino.
Le montage en images
Eléments du montage

Percage des trous de fixation

Fixation à l'aide de Colsons

Autre vue de la fixation

Raccordement électrique

Détail du raccordement

Placement sur la voiture

Raccordement Arduino
  • Entrée Analogique A0 : Senseur Gauche (fil brun)
  • Entrée Analogique A1 : Senseur Droit (fil orange)
  • Sortie 3.3V raccordée sur entrée AREF.
    Comme les capteurs infrarouges ne retournent pas une tension supérieure à 3.3V, cet important raccordement permet d'augmenter la précision des lectures analogiques.
Schéma de raccordement des détecteurs
Test de la détection
Pour faire les tests de détections, j'ai créé un petit logiciel spécifique lit les valeurs analogiques sur A0 et A1 et envoi l'information sur le port série (qu'il est possible de visualiser avec le moniteur d'Arduino IDE).
L'information est lue toutes les secondes et envoyées sur le port série comme suit:
----------------------------
GAUCHE 478, volt=1.54, prox=24
DROITE 71, volt=0.23, prox=255
-----------------------------
GAUCHE 470, volt=1.51, prox=24
DROITE 232, volt=0.75, prox=255

A savoir:
  • Détecteur de Gauche
    • Valeur lue sur le port analogique (0 à 1024)
    • Conversion en volts (sur base de la tension de référence de 3.3v)
    • Un indice de proximité (voir documentation plus loin).
  • Détecteur Droit
    Idem
Indice de proximité
Sur base du graphique suivant disponible dans la datasheet (accessible depuis cet article) et sachant que la dite "distance de jugement" est de ~24cm, j'ai écris un bout de code évaluant grossièrement la proximité d'un objet (l'indice de proximité).
Source: datasheet
Ce bout de code retourne les valeurs suivantes:
  • 255: hors du champs de proximité. Pas d'évaluation plus précise.
  • 24: distance de jugement atteinte. Soit 24 cm ou moins.
  • 15: distance proche atteinte. Soit 15cm ou moins (il est grand temps d'agir!).
Code source
Source: Infrared_Sensor_Test.pde
/*
    ArduinoCar - http://arduinocar103.blogspot.com
    Test des detecteurs Infra-rouge Avant  d'ArduinoCar
    
    Date: 21 juillet 2011
      
    Description:
      Ce programme affiche les valeurs detectées par les deux 
      détecteurs IR placé à l'avant de la voiture (branchés 
      sur A0 et A1).
      
      Les valeurs sont écrites sur le port série
    
    Montage:
      ARef = 3.3 volts
      Infrared left=pin A0
      Infrared right=Pin A1
 */
 
 int pinIrGauche = 0; // détecteur Infrarouge a Gauche
 int pinIrDroite = 1; // détecteur Infrarouge a Droite
 
 void setup(){
     analogReference( EXTERNAL );
     Serial.begin( 9600 );
 }
 
 void loop(){
   // Capture de la valeur
   int valeurIrGauche = analogRead( pinIrGauche );
   int valeurIrDroite = analogRead( pinIrDroite );
   
   // Transformation en volts (référence=3.3v)
   float voltIrGauche = ((float)valeurIrGauche)*3.3/1024;
   float voltIrDroite = ((float)valeurIrDroite)*3.3/1024;
   
   // Evaluation de la proximité (par ordre de grandeur en CM)
   // Les valeurs possibles sont:
   //  * 255 = valeur maximale, hors du champs de la perception
   //  * 24  = objet à la distance de jugement (24 cm ou moins)
   //  * 15  = objet très proche (15 cm ou moins)
   // 
   byte proximiteGauche = 255; // distance > 24 cm
   if( voltIrGauche > 1.6 ) 
     proximiteGauche = 15; // distance < 15 cm
   else
     if( voltIrGauche > 1.1 ) // distance de jugement +/- 24 cm
       proximiteGauche = 24;

   byte proximiteDroite = 255; // distance > 24 cm
   if( voltIrDroite > 1.6 ) 
     proximiteDroite = 15; // distance < 15 cm
   else
     if( voltIrDroite > 1.1 ) // distance de jugement +/- 24 cm
       proximiteDroite = 24;
   
   // Affichage des valeurs
   Serial.print( "GAUCHE " );
   Serial.print( valeurIrGauche ); Serial.print( ", volt=" ); 
   Serial.print( voltIrGauche ); Serial.print( ", prox=" ); Serial.println( (int)proximiteGauche );

   Serial.print( "DROITE " );
   Serial.print( valeurIrDroite ); Serial.print( ", volt=" ); 
   Serial.print( voltIrDroite ); Serial.print( ", prox=" ); Serial.println( (int)proximiteDroite );
   
   // Affichage d'un séparateur
   Serial.println( "-----------------------------" );
   
   delay( 1000 ); // attendre 1 seconde avant lecture suivante.
 }

Conclusions
Premièrement: la fonction de proximité
Le code de détection de proximité va grandement facilité la détection d'objet.
Il faudra donc en faire une fonction.

Deuxièmement: les défauts de détections
Il existe des situations dans lesquelles la détection de proximité est peu inefficace, voire pas du tout.
Certaines imperfections peuvent être palliées par une action logicielle... d'autres nécessiterons des capteurs complémentaires.

La bordure de trottoir en biais:
Dans ce cas, la détection des 24 cm n'intervient que très tard... très vite suivie par la détection des 15 cm (pour une avancée du véhicule d'un cm seulement).
ArduinoCar détecte pas rapidement les bordures en biais.

Dans ce cas, la détection est tellement tardive que le véhicule ira se jeter dans la bordure rien qu'avec son inertie.
Il faudra donc prévoir un système de freinage pour que le véhicule (une impulsion en marche arrière par exemple :-) ).

Les objets au dessus des détecteurs:
C'est le cas des dessous d'armoire, ou de voiture.
Si les senseurs passent, ce n'est pas forcement la cas du restant du véhicule exemple.
Arduino Car ne détecte pas les objets en hauteur
Il est possible de résoudre cet inconvénient en plaçant un senseur en hauteur.
 
Les objects sous les détecteur:
Voici un cas pratique
Arduino Car ne détecte pas les objets au ras du sol
Ce cas de figure (tout comme la bordure de trottoir en biais) peu être contourné en plaçant un détecteur infrarouge pointant vers le bas.

Le pied de chaise:
Encore un autre cas pratique...
La pied de chaise n'est pas détecté!
Ce problème, tout comme celui des objets au dessus des détecteurs peuvent être résolu à l'aide d'un senseur infrarouge en hauteur (et orientable).


... il ne reste plus qu'a passer à la suite

mercredi 20 juillet 2011

Premières constatations d'ordre technique

J'ai eu l'occasion de faire quelques essais avec Arduino Car maintenant que la motorisation est terminée.

Et trois choses sautent immédiatement aux yeux.

Premièrement: détection des obstacles
C'est prévu depuis le début mais il faudra vraiment que j'ajoute des détecteurs infrarouge sur Arduino Car.
Lorsque l'accu est bien chargé, une marche avant de 4 secondes est suffisant pour que la voiture quitte le parking (pour aller s'encastrer sous un autre véhicule).

Deuxièmement: autonomie, une histoire d'accu
Le véhicule ne dispose pas d'une très longue autonomie.
En moins de 10 minutes, l'accumulateur est suffisamment a plat pour que la voiture n'avance presque plus à régime de 78% alors que c'est honorable à pleine charge.
Ensuite, comme le véhicule manque de nerf, la direction ne se redresse pas vraiment bien... probablement que le fait d'avancer aide la direction à se redresser.

L'accumulateur à une autonomie de 650mAh.
Les précédentes mesures ont démontrés que la propulsion consomme environ 800mA en charge et que chaque train de direction consomme ~330mA en butée.
Comme il y a deux trains de directions, cela fait 660 mA
Dans la pire des situations, la consommation globale est de  ~ 800 + (330 * 2) = 1460mA.
Si je veux faire fonctionne mon montage pendant une heure, j'ai besoin d'un accu de 1500 mAh.
Hors, je n'ai qu'un accu de 650mAh (usagé). Je ne peux compter au mieux que sur 30 minutes d'activité.
Quoi que 15 à 20 min semble plus vraisemblable!


Troisièmement: la distance parcourue
C'est bien beau de faire une marche arrière pour changer de direction (face a un mur par exemple).
Mais la distance parcourue lors de la marche arrière dépends de la charge de batterie.
Lorsque la batterie est presque morte, le véhicule ne parcours par 1/4 de tour en 2.5 secondes... alors qu'a pleine charge, elle fait plus d'un tour sur le même laps de temps.
Il faudra donc un moyen pour mesurer/estimer la distance parcourue... probablement d'un capteur à effet Hall et de quelques aimants permanent sur la roue.

En conclusion, je dirais qu'il y a encore du boulot :-D

Commande de la motorisation

Introduction
Après le montage place à la programmation de l'Arduino Car.
Pour le moment, il ne sera malheureusement possible que de se concentrer sur la mise en marche et la commande des trains de direction.

La voiture étant encore dépourvue de détecteurs, il ne peut malheureusement pas interagir avec le monde extérieur.
J'entends par interaction le fait de ne pas aller se jeter bêtement dans dans un mur ou un arbre... mais chaque chose en son temps -);

Quoi qu'il en soit, cela n'empêche pas de préparer un code relativement correcte et faisant preuve d'une certaine lisibilité.


Résultats
Voici la vidéo du résultat obtenu histoire de se mettre un peu l'eau à la bouche ;-)


Informations techniques
Le code à été rédigé de manière à rendre son utilisation la plus "simple" et "évidente" possible.
Ainsi, lorsque les choses se compliquerons un peu, il n'y aura pas lieu de se demander comment on fait avancer la voiture... de simple appels de fonction tel que marche( AVANT, 100 ) (pour une avance à 100% de régime) me simplifiera grandement la vie.

Constantes
J'ai ajouté quelques définitions de constantes pour améliorer la lisibilité du code.
Concernant la direction:
  • DROITE: pour tourner à droite.
  • GAUCHE: pour tourner à gauche. 
  • AUCUN: Pour aller tout droit (abandonner tout changement de direction).
Il est également possible de commander chaque train de direction indépendamment... dans ce cas, j'utilise les constantes AVANT & ARRIERE décrites plus loin pour indiquer le train de direction à commander.

Concernant le déplacement:
  • AVANT: Marche avant OU Commande Direction Avant.
  • ARRIERE:  Marche Arrière OU Commande Direction Arrière
  • ARRET: Passer à l'arrêt
L'instruction marche
Mise en marche du moteur de propulsion dans un sens et a un régime déterminé.

void marche( byte Sens, byte Regime)

Paramètres:
  • Sens: Direction de déplacement (AVANT/ARRIERE/ARRET)
  • Regime: Regime moteur en % (de 0 à 100)
Note:
Pour un arrêt de la marche, il suffit d'indiquer un régime moteur de 0% (peu importe le sens).

L'instruction arret
Signifie l'arrêt du moteur de propulsion!

void arret()

Note:
Effectue l'appel  marche( ARRET, 0 );

L'instruction tourner - première forme
Commande du train de direction avant ou arrière dans le but de faire tourner le véhicule dans une direction désirée (vers la droite ou la gauche).

void tourner( byte Train, byte Direction )

Paramètres:
  • Train: Train de direction à commander (AVANT ou ARRIERE).
  • Direction: Direction que doit prendre le véhicule (DROITE, GAUCHE, ou AUCUN pour "tout droit").
Exemple:
tourner( AVANT, DROITE)

L'instruction tourner - deuxième forme
Coordonne les deux trains de directions (avant et arrière) dans le but de faire tourner le véhicule dans la direction voulue.

void tourner( byte Direction )

Paramètres:
  • Direction: Direction souhaitée pour le véhicule. DROITE, GAUCHE, AUCUN (pour "tout droit")
Exemple:
tourner( GAUCHE )

Code source
Source: ArduinoCar_Test_Moteur.pde
 
Code d'exemple
Dans un premier temps, le code initialise toutes les sorties dans la fonction setup().
Et bien que cela n'est pas conforme à l'utilisation générale d'Arduino, la fonction setup() appelle la fonction de test testMoteur().
En faisant de la sorte, la routine de test ne fonctionne qu'une seule et unique fois (ce qui est bien pratique) et est réactivable en pressant le bouton reset :-)

void setup(){
  // Direction
  pinMode( pinFrontDir1, OUTPUT );
  pinMode( pinFrontDir2, OUTPUT );
  pinMode( pinBackDir1, OUTPUT );
  pinMode( pinBackDir2, OUTPUT );
  // Motor 
  pinMode( pinMotor1, OUTPUT );
  pinMode( pinMotor2, OUTPUT );
  // La commande PWM est assurée à l'aide d'AnalogWrite
  
  testMoteur();
}

void testMoteur() {
  // Avance mis regime apparent
  marche( AVANT, 78 );
  delay( 5000 );
  
  // Demi-tour
  tourner( DROITE );
  marche( AVANT, 78 );
  delay(3200);
  arret();
  tourner( GAUCHE );
  marche( ARRIERE, 78 );
  delay(3200);
  arret();
  tourner( AUCUN );
 
  // Avance rapide
  marche( AVANT, 100 );
  delay( 3000 );
  arret();
  
  // Deplacement de travers
  tourner( AVANT, DROITE );
  tourner( ARRIERE, GAUCHE );
  marche( ARRIERE, 100 );
  delay( 4000 );
  tourner( AVANT, GAUCHE );
  tourner( ARRIERE, DROITE );
  marche( ARRIERE, 1000 );
  delay( 3000 );
  
  // Arret definitif
  arret();
  tourner( AUCUN );
}

Assemblage des composants de motorisation

Introduction
Voici donc le moment de placer un Arduino sur Arduino Car et d'effectuer les différents raccordements des prototypes boards destiné à la propulsion de l'engin.

Nous verrons plus tard comment monter des dispositifs de détections pour éviter les murs et autres objets placés sur le parcours d'Arduino Car?

Pour facilité le montage et les raccordements, je vais commencer par une section truc et astuce qui sera bien utile pour vous facilité la tâche.

Trucs et Astuces
Fixation d'Arduino
Pour la fixation d'Arduino, j'utilise des petites vis type vis à bois que l'on retrouve sur tous les types d'appareils électroménager. Ce type de vis rentre assez facilement dans le plastique.
Pour faire les trous, le plus simple est encore d'utiliser la pane pointue & bien chaude de votre fer à souder.
En y allant pas trop fort, il est possible de faire un avant trou de taille raisonnable où l'on peut y présenter la future vis. Après refroidissement du plastique, il sera plus facile de l'y visser.
De même, il est possible de placer Arduino à sa position finale et d'utiliser la pane du fer à souder pour marquer l'emplacement des trous.
et comme déjà précisé, il suffit d'un bon coup de chiffon à chaud et immédiatement après la fonte du plastique pour nettoyer la pane du fer à souder.

Alimentation d'Arduino
Juste une petite note pour précisé le raccordement de l'alimentation 9 Volts sur Arduino.
Il est toujours possible d'utiliser une prise jack comme décris sur l'article "Alimentation externe pour Arduino" mais il est tout aussi simple (dans notre cas) de:
  • raccorder le "-" de la pile 9v sur une broche GND d'Arduino
  • raccorder le "+" de la pile de 9v sur la broche Vin d'Arduino
En fait la broche Vin est branchée sur le centre le la prise Jack (juste avant le régulateur de tension d'Arduino.

Raccordement des prototypes boards
Les différents prototypes board d'Arduino Car sont équipés de Pin Header (mâles) tandis qu'Arduino est équipé de bornes de raccordement femelle.

Raccorder le tout peut paraître fastidieux. Pourtant, il est possible de se simplifier la tâche assez facilement.

Il est possible de se fournir des "fiches femelles" correspondant au Pin Header sur des PC hors d'usage (surtout sur les raccordement utilisés pour les boutons et les leds en façades).


Avec un peu d'imagination, un fer à souder et du thermo-rétractable, il est possible de monter:
  • Des câbles "femelle-femelle" pour raccorder les prototypes board entre eux.
  • Des câbles "mâle-femelle" (en utilisant quelques pin header) pour raccorder les prototypes board sur Arduino.
Si vous éprouvez du mal à vous fournir des fiches/contacts mâles, vous pouvez toujours en acheter en fourniture électronique:
  • Chez Cotubex (pour la belgique) dans la gamme CO36
  • Autres suggestions encore à venir
Assemblage
Après les recommandations, voici les différents raccordements entre les prototypes boards de l'Arduino Car
Raccordements des prototypes board de l'Arduino Car
 Informations sur le montage
  • Les masses des alimentations +9v et +7.2v sont raccordées ensemble sous le prototype board.
  • Arduino est alimenté en +9v via la pin Vin
  • La logique du L293E et du L298HN sont alimentés par le régulateur d'Arduino (broche +5v d'Arduino).
  • Je n'utilise pas de commande PWM pour la direction. C'est pour cette raison que les deux broches "Chip Enabled" du L293E sont directement raccordées au +5v.
  • Le moteur de propulsion sera commandé en PWM. C'est pour cette raison que la broche "Chip Enabled" du L298HN est raccordée sur sur sortir PWM d'Arduino.
Arduino - branchement des broches de commande
  • Arduino Pin 2 & 3 : Commande de direction du train avant.
    • Pin 2=High + Pin 3=Low => une direction
    • Pin 2=Low + Pin 3=High => autre direction
    • Pin 2=Low + Pin 3=Low => mouvement libre, c'est la mécanique de rappel qui recentre les roues dans l'axe du véhicule.
    • Si le véhicule tourne dans la mauvaise direction, il faut soit inverser le raccordement des pin 2 & 3, soit inverser la logique de commande du programme Arduino.
  • Arduino Pin 12 & 13 : Commande de direction du train arrière
    Mêmes indications que pour les pins 2 & 3
  • Arduino Pin 4 & 5 : Commande du sens de marche
    • Pin 2=High + Pin 3=Low => Avant
    • Pin 2=Low + Pin 3=High => Arrière
    • Pin 2=Low + Pin 3=Low => Pas de déplacement.
    • Attention: l'ordre de mise en mouvement est commandé par la pin PWM 11.
    • Tout comme pour la direction, si le sens de déplacement physique est incorrect, il suffit d'inverser le raccordement de la pin 4 & 5 ou de modifier la logique du code.
  • Arduino Pin 11: Commande du moteur de propulsion en modulation de largeur d'impulsion.
    La commande du "Chip Enabled" du L298HN en PWM permet de moduler la puissance moteur d'Arduino.
    A PWM = 200 (soit 78%) donne une propulsion apparente à mis régime.
    A PWM = 255 (soit 100%) donne une propulsion a plein régime.
Résultat final
Voici l'encombrement final.
Seul l'alimentation est raccordée sur Arduino... le restant des branchements n'est pas encore fait.
Encombrement de l'Arduino Car
(manque encore les raccordements sur Arduino)

lundi 18 juillet 2011

Etage de puissance - Montage

Introduction
Après le montage du bornier moteur, il est temps de penser à l'étage de puissance.
Après avoir fait les différents essais (voir "Test des étages de puissance"), j'ai décidé de monter l'étage de puissance sur un prototype board avec les spécifications suivantes:
  • Utiliser un L293E (moteurs de directions) et un L298HN (moteur de propulsion)
  • Pas d'utilisation des circuit senseurs du L293E et L298HN (raccordement des broches senseurs à la masse).
  • Faire un montage sur un autre prototype board 2.54 mm.
    Ainsi, il sera facilement de le démonter de l'Arduino Car pour l'utiliser temporairement avec un autre montage.
  • Utiliser des "pin header" pour les différents raccordements.
    A la fois avantageux pour sa légèreté et sa facilité d'assemblage.
  • Séparation complète des circuits L293 et L298.
    Cela permettrait éventuellement d'utiliser le L293 avec une alimentation de puissance différentes (en puissance et tension) de l'étage de puissance du L298.
    Cela peut s'avérer très pratique si je réutilise l'étage de puissance sur un autre montage.
  • Utilisation de diode de protection de type "Fast".
    BYV27-100-TAP: Diode Ultrafast, 2A, 100V. Farnell #1469371
Composition de l'étage
Les différentes instructions de montages sont accessibles depuis l'article "Test des étages de puissance".
Ainsi donc, je vais me contenter de décrire les différentes connexion de l'étage assemblé sur le prototype board.
La logique de commande est alimentée à l'aide de la sortie +5V d'Arduino.
Toutes les masses ont étés raccordées entre-elles.
Concernant les cavalier, je regrette de ne pas avoir pensé à faire la même chose pour VSS (l'alimentation de la logique de commande).
Cela aurait été bien pratique :-/

Détail du brochage
Voici le détail du pinning de raccordement du L298HN et L293E sur le prototype board

Fixation sur l'Arduino Car
Dans le cas ci-présent, j'avais anticipé la fixation du prototype board sur l'Arduino Car.
C'est la raison pour laquelle il y a deux sections au feutre rouge, endroit où je ne pouvais rien souder car il reposaient directement sur la voiture.
La fixation est assurée par de simple vis de type mécano.

Au final cela ressemble à cela.

Il reste encore de la place au milieu pour placer un Arduino et à l'avant pour un périphérique de détection de proximité :-)

Truc et astuces
Protection et isolation
Les différentes soudures du L298 et du L293 et raccordements sont assez proches.
Il n'est pas toujours facile de travailler avec du fil téléphonique tout en étant certain de ne pas faire fondre la partie isolante du fil...
De même, au montage (ou lors d'incident avec l'Arduino Car), une pression pourrait causé de faux contacts dans la partie de puissance.
Pour éviter facilement ce problème, il suffit d'utiliser un pistolet à colle chaude pour enduire les différents points/soudures sensibles. Cela assure autant la stabilité du montage que son isolation (d'un contact/fil par rapport à l'autre).

Circuit de dissipation du L293
N'oubliez pas de souder les pins GND du L293 et de lui assurer une surface de dissipation minimal.
Voir section "Le refroidissement" dans l'article "Contrôle Moteur DC via L293E"

Ou trouver des cavaliers
Les cavaliers permettant de raccorder ensembles les étages VS du L293E et L298HN peuvent, comme souvent, être dégotés au parc à container.
Les disques durs et lecteurs CD des ordinateurs disposent souvent quelques cavaliers de 2.54 mm d'espacement :-)



dimanche 17 juillet 2011

Bornier moteur

Description
Monter un "bornier" de raccordement moteur sur l'ancienne voiture télécommandée permet de faciliter le raccordement des différents moteurs sur l'étage de puissance (encore à venir).

C'est aussi l'occasion d'ajouter une pile de 9 volts qui fournira une alimentation séparée pour la logique de commande (à savoir Arduino).
Séparer les alimentations de l'étage de puissance et de la logique de commande est une recommandation assez courante, cela permet de maîtriser les interférences dues aux parasites (voir recommandation de séparer les alimentations de l'article "Montage Moteur DC - Recommandations").

Montage du bornier
Le bornier est constitué d'un morceau de prototype board et de "Pin Header" (plus léger qu'un vrai bornier à vis).

Les deux premières étapes furent:
  1. De rallonger les câbles moteurs.
    • Avec du fil récupéré dans un PC au parc à container (cela fera très bien l'affaire).
    • Préserver les selfs (ou en ajouter soi même) sur le moteur de propulsion est tout à fait approprié.
    • Un peu de gaine thermo-rétractable assurera l'isolation.
  2. De percer un trou (à la foreuse) sur le dessus du boîtier pour faire passer les câbles.
    Plusieurs trous en cercle peuvent être nécessaire... il est possible d'éliminer les rugosités en faisant fondre le plastique avec un fer à souder.
Rallonger les fils moteurs
Préserver les selfs (à enfermer dans
de la gaine thermo-rétractable)
Utiliser de la gaine thermo pour isoler (en blanc ici)
Détail important
Il est très important de raccorder ensemble toutes les masses.
C'est à dire celles des moteurs et celles de l'accumulateur 7.2 volts



Fermeture du bloc principal

Mise en place du bornier
Détail du bornier
Détail toujours aussi important
Il faut également raccorder ensemble les masses des alimentations de puissance et de logique de commande.
Le "-" de la pile de 9 volts doit donc être raccordée au "-" de l'accumulateur de 7.2 volts (tout comme cette dernière masse doit être connectée aux masses des moteurs)

Truc et astuces
Placer le bornier à l'arrière
Le bornier est placé à l'arrière car il faut encore assembler et placer:
  1. Un étage de puissance constitué d'un L293E et d'un L298HN.
  2. Un Arduino
  3. Divers détecteurs de proximités (on en parlera bien plus tard).
Fixation du bornier
Quelques pièces de mécano sont toujours les bien venues surtout les petits tubes en plastiques qui permettent d'insérer une séparation physique entre le prototype board et le support en plastique de la voiture.
C'est plus propre et cela laisse de la place pour le passage des câbles sous le prototype board.
Pour la fixation, vous pouvez opter pour de petites vis type "bois", de celle utilisée dans les différents appareils ménagés (récup. au parc a container).
Ce type fixation est assez discrète et rentre assez facilement dans le plastique.

Un petit truc:
Vous pouvez faire un petit avant trou avec votre fer à souder.
Vous remarquerez avec le temps que fer a souder et plastique font bons ménages.
Il suffit de passer un chiffon sur le fer (juste après opérations) pour retirer les déchets de plastiques collés sur la pane.

Connecteur 9 Volts
Le connecteur 9 volts peut aussi être récupéré sur n'importe quel rechargeur de piles ou certaines télécommandes.
Encore une fois, c'est un article (le rechargeur de pile) que l'on trouve assez souvent dans un parc a container.
Pensez aussi a placer un petit interrupteur pour couper facilement l'alimentation 9 volts. J'en ai rajouter un depuis l'écriture de l'article ;-)

samedi 16 juillet 2011

Test des étages de puissance

Dans l'article précédent, je mentionnais le choix d'un L293 pour la commande des trains de direction et celui d'un L298HN pour la commande de la propulsion.

Après avoir acheter les composants chez Farneel Belgique (via be.farnell.com), j'ai effectué les différents montages de test.
Montage avec lesquels j'ai, entre autre, mesuré les différentes tensions et différents courant de fonctionnement.

Ces montages sont décrits sur Arduino103.blogspot.com (blog.domeu.net) un blog plus général consacré à Arduino.

Je vous propose donc la lecture des articles suivants:
  1. Contrôle Moteur DC via L293D (H Bridge Driver, Circuit Intégré Pont H)
  2. Contrôle Moteur DC via L293E
    Le L293E est la version du circuit utilisé pour le contrôle des trains de direction.
  3. Contrôle Moteur DC via L298
    Le L298HN utilisé pour la propulsion du véhicule.
    Si le L298N est disponible chez Farnell il faut rallonger 25 eur pour le faire venir des Etats-Unis.
    Par contre, le modèle L298HN (H=Horizontal) est disponible sur le sol Belge sans surcoût :-) .
    Finalement, je vous suggère de lire l'article référencé car l'adaptation d'un L298 sur un board 2.54mm réclame quelques manipulations.
  4. Pour les plus mordu, l'article "Pont H à transistor pour contrôler un Moteur DC dans les deux sens" qui aborde le fonctionnement technique des Pont-H.
  5. Un passage par l'article "Montage Moteur DC - Recommandations" peut également vous apprendre quelques informations utiles.
Au final, voici le résultat "visuel" de mes différents essais de montage du L293E (en premier) et L298HN (en deuxième).
 


Restera plus qu'a prévoir un montage définitif sur un board de prototypage... mais ce sera pour plus tard.

Première mesure et premières erreurs

Pourquoi faire des mesures
Il faudra utiliser pour commander le moteur principal et les trains de directions.
Bien entendu, il serait possible d'utiliser des pont-H fait main ... mais le plus facile serait encore d'utiliser des circuits intégrés à Pont-H histoire de se simplifier la vie.
La plupart des pont-H supportent facilement plus de 40 Volts, des mesures de tension de fonctionnement ne sont pas nécessaires.

Par contre, le choix du circuit intégré dépendra principalement de le puissance requise... et donc du courant de charge du moteur.
C'est pour cela qu'une série de mesure s'impose pour connaître les courant de fonctionnement.

Premières mesures, premières erreurs
Ma première erreur est grosse comme une porte de maison !
Armé de mon multimètre, je me suis mis en tête de mesurer les courants de fonctionnement des différents moteurs (propulsion, direction avant et direction arrière).
Ayant déjà constaté que la direction n'est pas prise en charge par un servo-moteur, je sais déjà que le moteur DC ira jusqu'à butée et qu'a butée, j'aurais un courant proche d'un courant de court circuit (limité par une résistance de 2.2 Ohms).
 
Mon accumulateur faisant 7.2 volts, j'ai utilisé une alimentation stabilisée de 7.5 volts que j'ai branché directement sur mes différents moteurs tout en faisant les mesures de courant.

Pour le moteur de propulsion, j'ai mesuré le courant a vide, en charge (en freinant volontairement les roues) et le courant maximum (en bloquant les roues).
C'est ainsi que je découvre les valeurs suivantes:
Pour la direction:
  • Imax = 300 mA en butée
Pour la propulsion:
  • I_a_vide = 250 mA
  • I_en_charge = 1A à 1.5A en fonction de la charge
  • Imax (bloqué) = 2A
Le courant maximum apparait lorsque le moteur est bloqué (par exemple lors de la rencontre d'un mur)... et il atteint 2 Ampères.
Ce n'est pas rien!

Sur base de ces informations, j'ai sélectionné les circuits intégré suivants dans la liste "Quelques H Bridge Drivers" de l'article "Contrôle Moteur DC via L293D (H Bridge Driver, Circuit Intégré Pont H)":
  • un L293 pour la commande des directions (avec une commande indépendante pour chaque direction)
  • L298 supportant des courants plus important pour la commande de la propulsion.
Où est donc l'erreur?
Si elle ne vous paraît pas évidente, il faut se souvenir que dans une voiture téléguidée, les différents moteurs sont également contrôlés à l'aide de Pont-H.
Ceux-ci sont plus souvent constitués de Pont-H à transistors (car plus économiques).
La principale caractéristique d'un Pont-H, c'est qu'il induit une chute de tension égale à 2 fois Vce_sat (Voir informations relatives aux chutes de tensions dans l'article "Pont H à transistor pour contrôler un Moteur DC dans les deux sens").

En considérant une chute de tension VCE_sat de ~1 volt, la tension aux bornes des moteurs seraient alors de 7.2v - 2 * ~1v = ~ 5.2 volts.
C'est la raison pour laquelle la batterie fait 7.2 volts car cela permet d'anticiper la chute de tension du pont-H et de fournir une tension de fonctionnement suffisante pour les moteurs!
 
En somme, la tension de fonctionnement est plus faible que dans mes tests... et en conséquences les différents courants également plus faibles.

Pour éviter l'erreur
Une mesure de la tension aux bornes des moteurs (à vide) m'aurait permis de me rendre compte de mon erreur initiale.
En effet, je n'aurais pas du faire un test sous 7.5 volts mais plutôt à l'aide d'une alimentation en 5 volts ou en 6 volts.
Mais ne disposant pas de la télécommande, une telle mesure aurait été difficile à faire.
Par contre, les prochaines fois, je penserais à la règle d'or "anticiper la chute de tension du Pont-H"

De nouvelles mesures des courants
Ce que je n'ai pas dit, c'est que je me suis aperçu de mon erreur en faisant des mesures de courant sur mes montages du L293 et du L298.
Les courants ne correspondaient absolument pas! C'est en mesurant les tensions aux bornes de mes moteurs que j'ai compris l'énormité de l'erreur lors de mes premiers tests.

Le montage du L293E et L298HN seront abordés dans un futur article.

Commande de direction:
Mesure effectuée avec un L293, direction en butée.
  • Tension: 5.5 v 
  • Imax: 330mA
  • I à PWM=180/255: 150 mA
  • I à PWM=210/255: 180 mA
Une commande PWM pour la direction n'est cependant pas vraiment appropriée.
Car la direction prise par les roues de direction dépendra directement de la charge de l'accumulateur. Plus l'accu sera à plat et plus la commande de direction en PWM manquera d'efficacité!
A PWM = 180, les roues tournent légèrement, à PWM=210 les roues trounent à fond et à PWM=255 (100%), les roues tournent à fond (et brutalement).

Commande de propulsion:
La datasheet du L298HN mentionne un VCEsat typique de 1.8v.
En fonctionnement normal, le moteur est alimenté en 7.2-1.8=5.4 Volts.
VceSat augmente avec l'augmentation du courant. Pour I=1A, VceSat=3.2v et pour I=2A, VceSat=4.9v.
Ce qui peut sembler un désavantage, aura un effet bénéfique.
Cette augmentation de la chute de tension VceSat aura pour effet immédiat de diminuer le courant de charge du moteur (par exemple quand il est bloqué) et de trouver un nouveau point d'équilibre pour le couple VceSat & I où le courant sera moins important.
Au final, cet effet indésirable protègera le circuit de puissance.

Mesure effectuée avec un L298HN sous différentes conditions.
  • Fonctionnement à vide
    • Vmoteur (tension aux bornes du moteur) = 5.4~5.5v
    • I (courant de charge du moteur) =300mA
  • Fonctionnement en charge
    • Vmoteur=3v
    • I=800mA -> 1A
  • Moteur bloqué
    • Vmoteur = 1.5 v
    • I=1.1A (le courant est limité!)
Booster l'Arduino Car
A contrario, ce que mon erreur m'aura appris, c'est que les différents moteurs supportent assez bien une tension de fonctionnement de 7.5v.
Ainsi donc, si j'ai un jour besoin de booster un peu le véhicule, je pourrai toujours considérer faire des essais (et mesures) avec un accumulateur de 9 Volts.

Via le L298HN, la tension de fonctionnement du moteur serait alors de 9-1.8 = 7.2 volts.