Go Down

Topic: Bogue avec la bibliothèque Servo, comment corriger ce problème ??? (Read 10047 times) previous topic - next topic

LamiRene

Sep 08, 2013, 11:33 am Last Edit: Sep 09, 2013, 04:16 am by LamiRene Reason: 1
Bonjour,

Je suis à me construire un petit véhicule autonome à deux roues, mais je suis embêté avec un bogue dans la bibliothèque « Servo » qui me désactive la fonctionnalité de mes ports PWM pour le contrôle de deux moteurs CC avec engrenage démultiplicateur.

Comme bien des petits robots mobiles, j'utilise un capteur à ultrason sur un petit servomoteur TowerPro SG90 9G et un contrôleur moteur L298N (H-Bridge) pour les moteurs CC.

J'utilise les trois broche par moteur du contrôleur (ENA, ENB, IN1, IN2, IN3, IN4), pour contrôler la vitesse des  moteurs CC, mais après une commande du genre « UnServo.attach (46,0,180); », je perds l'usage des moteurs CC en mode vitesses variables sur le contrôleur, sauf si la valeur de  ENA, ENB est au maximum soit 255, ils passent donc du mode vitesse variable au mode binaire On/Off.

C'est comme si le mode PWM des Arduino (tester avec deux Mega, pour les autres je ne sais pas) était déréglé par l'utilisation de la librairie « Servo ».

Je suis actuellement en recherche d'autres cas similaires dans la francophonie (je suis unilingue francophone).

Pour info, je rencontre ce problème avec toutes les versions de l'IDE d'Arduino (1.0.3, 1.0.5, 1.5.2 et 1.5.3) et je suis sous Linux Kubuntu 12.04, 64 bits.

En fichier joint, mon code source avec le détail des pièces utilisées et des branchements (brouillon didactique pour un véhicule autonome à deux roues).

Dans la description de la bibliothèque, il y a bien une limitation et une désactivation du mode PWM de la broche 11 et 12 avec une carte Arduino Mega, mais seulement si plus de 12 servomoteurs sont utilisés, je n'en ai qu'un :

Quote
A partir d'Arduino 0017, la librairie Servo supporte jusqu'à 12 servomoteurs sur la plupart des cartes Arduino (la Duemilanove par exemple) et 48 sur l'Arduino Mega. Sur les cartes autres que la Mega, l'utilisation de la librairie Servo désactive l'instruction analogWrite() sur les broches 9 et 10, qu'il y ait ou non un servomoteur sur ces broches. Sur la Mega, jusqu'à 12 servomoteurs peuvent être utilisés sans interférer avec la fonction PWM (càd avec l'instruction analogWrite); utiliser de 12 à 23 servomoteurs désactivera les impulsions PWM sur les broches 11 et 12. (Note : PWM pour Pulse Width Modulation ou Modulation de Largeur d'Impulsion).


Référence : http://arduino.cc/fr/Main/LibrairieServo


Est-ce que je suis le seul à expérimenter ce problème ?

Existe-t-il une parade à ce problème ?

Est-ce qu'il n'y aurait pas une âme charitable qui pourrait nous corriger ce problème récurrent dans les versions de cette bibliothèque. Je lui serais éternellement reconnaissant !  ;-)

L'ami René
(M-à-j code source : 2013-09-09)
Tous pour un et un pour tous !

skywodd

Bonjour,

Quoi qu'il arrive les broches 9 et 10 ne peuvent plus faire de PWM dés que la librairie Servo est utilisée.
Pour les broches 11 et 12 c'est vraiment QUE si tu utilises plus de 12 servomoteurs, pour le coup même la doc anglaise est d'accord là dessus.
Tu est sûr et certain que la PWM ne marche plus du tout ?
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

LamiRene

Bonjour skywodd,

Voici les connexions que j'ai pour le montage des deux moteurs CC :

Code: [Select]
// Broche d'Arduino pour le controleur moteur 1 (double Pont en H avec un L298N).
const byte CONTROLE_MOTEUR_1_ENA = 44;
const byte CONTROLE_MOTEUR_1_ENB = 45;
const byte CONTROLE_MOTEUR_1_IN1 = 34;
const byte CONTROLE_MOTEUR_1_IN2 = 32;
const byte CONTROLE_MOTEUR_1_IN3 = 30;
const byte CONTROLE_MOTEUR_1_IN4 = 28;


J'utilise un module d'extension "Shield" d'un écran LCD 16 colonnes 2 lignes à 6 boutons et je dois donc configurer la broche 10 pour la luminosité du fond de l'écran et effectivement la mode PWM de cette broche 10 est désactivée. La preuve en est qu'il y a un rétroéclairage que si je mais la valeur 255 à la fonction « analogWrite (LCD_1_A, LCD_1FondEcranValeur); ».

Voici toutes les connexions pour le montage (qui confirme que je suis dans les limites exigées pour les modes PWM des broches 28, 30, 32, 34, 44 et 45) :

Code: [Select]
//*****************************************************************************
// Déclaration des constantes des connecteurs Arduino.
//*****************************************************************************
// En prévision d'un ARDUINO_RESET par télécommande.
const byte ARDUINO_RESET = A7;

// Broche d'Arduino pour le controleur moteur 1 (double Pont en H).
const byte CONTROLE_MOTEUR_1_ENA = 44;
const byte CONTROLE_MOTEUR_1_ENB = 45;
const byte CONTROLE_MOTEUR_1_IN1 = 34;
const byte CONTROLE_MOTEUR_1_IN2 = 32;
const byte CONTROLE_MOTEUR_1_IN3 = 30;
const byte CONTROLE_MOTEUR_1_IN4 = 28;

// Pour gérer l'action d'humains le bouton de la planche d'expérimentation.
const byte BOUTON_1_SORTIE = 15;

// Broche d'Arduino pour recevoir le signale du capteur infrarouge.
const byte CAPTEUR_IR_1_1SORTIE = 14;

// Câblage pour la DEL verte sur la planche d'expérimentation et l'Arduino
const byte DEL_1_PLUS = 13;

// Broche d'Arduino pour le capteur a ultrason 1, le sonar.
const byte Sonar_1_TRIG = 22;
const byte Sonar_1_ECHO = 23;

// Broche d'Arduino pour le capteur a ultrason 2, le sonar.
const byte Sonar_2_TRIG = 24;
const byte Sonar_2_ECHO = 25;

// Broche d'Arduino pour le capteur a ultrason 3, le sonar.
const byte Sonar_3_TRIG = 26;
const byte Sonar_3_ECHO = 27;

// Constantes des broches sur l'Arduino pour une carte LCD1602.
const byte LCD_1_RS      = 8;// Écran LCD.
const byte LCD_1_E       = 9;// Écran LCD.
const byte LCD_1_D4      = 4;// Écran LCD.
const byte LCD_1_D5      = 5;// Écran LCD.
const byte LCD_1_D6      = 6;// Écran LCD.
const byte LCD_1_D7      = 7;// Écran LCD.
const byte LCD_1_A       = 10;// Écran LCD controle la liminosité arrière.
const byte LCD_1_SELECT  = A0;// Carte écran LCD 1 boutons
const byte LCD_1_UP      = A0;// Carte écran LCD 2 boutons
const byte LCD_1_RIGHT   = A0;// Carte écran LCD 3 boutons
const byte LCD_1_DOWN    = A0;// Carte écran LCD 4 boutons
const byte LCD_1_LEFT    = A0;// Carte écran LCD 5 boutons
const byte LCD_1_BOUTONS = A0;// Pour la gestion des boutons

// Câblage pour le Buzzer sur la planche d'expérimentation et l'Arduino :
const byte BOZZER_1_PLUS = 52;

// Attribution du port Arduino controlent le servo moteur.
const byte SERVO_MOTEUR_SONAR_1 = 46;// DigitalPWM
//*****************************************************************************


Je suis très loin des 12 servomoteurs, je n'en utilise que 1.

Et c'est avec la fonction « Servo.attach » que tout se dérègle.

Auriez-vous une suggestion de solution ?

L'ami René
Tous pour un et un pour tous !

LamiRene

Et pour le mode PWM des moteurs CC, pour qu'ils fonctionnent, je dois mettre la valeur 255 à la fonction « analogWrite (CONTROLE_MOTEUR_1_ENA, MOTEUR_1_VITESSE_MAXIMUM); », à 254 les roues ne bougent pas. C'est exactement comme pour la broche 10 et le rétroéclairage.

L'ami René
Tous pour un et un pour tous !

skywodd

Une bride de code comme ça c'est sans intérêt ;)
-> code complet.

si ça ce trouve c'est pas Servo qui bug mais une autre librairie qui utilise le même timer que Servo.
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

LamiRene

Bonjour skywodd,

Le code complet est déjà dans le premier message de cette discussion, mais voici en pièce jointe la toute dernière version.

Merci pour ton aide, comme je suis débutant avec Arduino, j'apprécie grandement !

L'ami René
Tous pour un et un pour tous !

skywodd

Tout devient plus clair.
C'est surement la librairie IRremote qui utilise un timer dont tu as besoin ;)

Regarde dans IRremoteInt.h au début tu doit avoir un truc du style :
Code: [Select]
// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  //#define IR_USE_TIMER1   // tx = pin 11
  #define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  //#define IR_USE_TIMER5   // tx = pin 46

Essaye avec un autre timer voir ce qui ce passe.

D'après http://arduino.cc/en/Hacking/PinMapping2560 :
Pins 11, 12 -> timer 1 // Lib IRremote actuellement (?)
Pins 9, 10 -> timer 2   // Lib Servo
Pins 2, 3, 5 -> timer 3
Pins 6, 7, 8 -> timer 4
Pins 44, 45, 46 -> timer 5

Pin 13 -> timer 0 et timer 1
Pin 4 -> timer 0
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

LamiRene

Bonjour skywodd,

Je suis très, très, très impressionné !

Il est clair pour moi qu'à ce niveau, cela dépasse largement mes connaissances et sans votre aide je ne pourrais trouver une solution de ce niveau, mais je cherche a comprendre du mieux que je peux.

Pour ce qui est du fichier « IRremoteInt.h », j'ai effectivement (voici un copier/coller de mon fichier) :

Code: [Select]
// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  //#define IR_USE_TIMER1   // tx = pin 11
  #define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  //#define IR_USE_TIMER5   // tx = pin 46


Et si j'utilise un autre que "IR_USE_TIMER2", j'ai des erreurs de compilation du genre :

Avec « #define IR_USE_TIMER5   // tx = pin 46) » :

Code: [Select]
Servo/Servo.cpp.o: In function `__vector_17':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/Servo/Servo.cpp:103: multiple definition of `__vector_47'
IRremote/IRremote.cpp.o:/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:70: first defined here
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/bin/ld: Disabling relaxation: it will not work with multiple definitions


Et c'est la même chose avec :

« #define IR_USE_TIMER4   // tx = pin 6 »
« #define IR_USE_TIMER3   // tx = pin 5 »
« #define IR_USE_TIMER1   // tx = pin 11 »

Et avec « #define IR_USE_TIMER0 » :

Code: [Select]
Dans le fichier inclus à partir de /home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:20:
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremoteInt.h:441:2: erreur: #error "Internal code configuration error, no known IR_USE_TIMER# defined\n"
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp: In member function 'void IRsend::mark(int)':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:227: error: 'TIMER_ENABLE_PWM' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp: In member function 'void IRsend::space(int)':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:235: error: 'TIMER_DISABLE_PWM' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp: In member function 'void IRsend::enableIROut(int)':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:253: error: 'TIMER_DISABLE_INTR' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:255: error: 'TIMER_PWM_PIN' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:263: error: 'TIMER_CONFIG_KHZ' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp: In member function 'void IRrecv::enableIRIn()':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:279: error: 'TIMER_CONFIG_NORMAL' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:282: error: 'TIMER_ENABLE_INTR' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:284: error: 'TIMER_RESET' was not declared in this scope
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp: In function 'void TIMER_INTR_NAME()':
/home/rene/sda6/Électroniques/Arduino_Linux/libraries/IRremote/IRremote.cpp:313: error: 'TIMER_RESET' was not declared in this scope


Je ne sais pas quoi faire d'autres.

J'ai regardé le contenu du fichier « IRremote.cpp » et j'ai trouvé ce code qui pourrait-être la confirmation de mon problème de PWM :

Code: [Select]
/* Leave pin off for time (given in microseconds) */
void IRsend::space(int time) {
  // Sends an IR space for the specified number of microseconds.
  // A space is no output, so the PWM output is disabled.
  TIMER_DISABLE_PWM; // Disable pin 3 PWM output
  delayMicroseconds(time);
}


Mais pour l'instant, je suis dans la mélasse, j'espère que vous pourrez m'aider à me sortir de ce bourbier !

Au-delà d'être impressionné par l'étendue de vos connaissances et vos compétences, j'apprécie grandement votre aide !

L'ami René
Tous pour un et un pour tous !

LamiRene

Rebonjour,

J'ai fait une version de mon Arduinobot sans télécommande et donc sans la bibliothèque « IRremote » et malheureusement, le problème persiste.

J'en déduis qu'il y aurait une ou plusieurs autres bibliothèques qui interfèrent avec les "TIMERx" ou les "INTx" et le mode PWM !

Il me reste comme coupable potentiel la bibliothèque "LiquidCrystal.h" ou "Servo.h".

Monsieur le Juge, quel est votre verdict ?

L'ami René
Tous pour un et un pour tous !

LamiRene

Rebonjour,

J'ai fait une version de mon Arduinobot sans télécommande et donc sans la bibliothèque « IRremote » et sans la bibliothèque "LiquidCrystal.h", malheureusement, le problème persiste.

J'en déduis qu'il y a interfèrent avec les "TIMERx" ou les "INTx" et le mode PWM causé par la bibliothèque "Servo.h".

Monsieur le Juge, vous avez le même verdict assurément, mais quelle serait la solution au problème ?

L'ami René
Tous pour un et un pour tous !

LamiRene

#10
Sep 13, 2013, 10:20 am Last Edit: Sep 13, 2013, 12:04 pm by LamiRene Reason: 1
Bonjour,

Cherchant à remplacer la bibliothèque « Servo », j'ai produit le code qui suit, mais le servomoteur reste inerte. Où est l'erreur dans mon code (je suis avec une carte Mega, voire tout le code en pièce jointe).

Le nouveau bout de code :

Code: [Select]

// Pour attribution du port Arduino contrôlent le servo moteur.
const byte SERVO_MOTEUR_SONAR_1 = 19;// DigitalPWM

//*****************************************************************************
void setup ()
//*****************************************************************************
{
 // Initialiser le port Arduino pour un servomoteur et centrage de l'angle du moteur.
 pinMode (SERVO_MOTEUR_SONAR_1, OUTPUT);
}

//*****************************************************************************
void loop()
//*****************************************************************************
{
 for (int i = 0; i < 180; i = i +1)
 {
   ServoMoteur (SERVO_MOTEUR_SONAR_1, i);
 }
}
//*****************************************************************************

//*****************************************************************************
// FONCTION ServoMoteur
//*****************************************************************************
void ServoMoteur (byte UnServoMoteur, int Angle)
{
 Angle = map (Angle, 0, 180, 0, 255);
 analogWrite (UnServoMoteur, Angle);
}


Merci d'avance pour votre aide inestimable !

L'ami René
Tous pour un et un pour tous !

skywodd

Désolé pour le retard je suis overbooké :smiley-mr-green:

Bon donc :
1) La lib IRremote était bien en conflit avec Servo (toutes les deux sur le Timer2)
2) L'erreur de redéfinition multiple vient de la lib Servo qui déclare des handler d'interruptions inutiles pour ton utilisation.

Solution :
1) utilise un autre timer que le n°2 (disont #define IR_USE_TIMER5)
2) utilise une lib plus simple du genre "ServoTimer2" (elle porte bien son nom au moins celle là ;))
https://github.com/DerekK19/Arduino/tree/master/libraries/ServoTimer2
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

LamiRene

Bonjour skywodd,

Un très grand merci pour votre aide, c'est très apprécié !

J'ai procédé comme vous l'indiquez, mais cela ne change pas le problème et en plus le servomoteur ne fonctionne pas avec la nouvelle bibliothèque.

Voici en détail ce que j'ai fait (voir en pièces jointes tous les fichiers utilisés).

1) Utiliser un autre timer que le n°2, le « #define IR_USE_TIMER5 » :

Donc, changer dans le fichier « IRremoteInt.h » le code :

Code: [Select]
// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  //#define IR_USE_TIMER1   // tx = pin 11
  #define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  //#define IR_USE_TIMER5   // tx = pin 46


Pour le code :

Code: [Select]
// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  //#define IR_USE_TIMER1   // tx = pin 11
  //#define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  #define IR_USE_TIMER5   // tx = pin 46


2) Utiliser la bibliothèque plus simple "ServoTimer2" :

https://github.com/DerekK19/Arduino/tree/master/libraries/ServoTimer2

Donc, télécharger et installer dans le dossier « ~/Arduino_Linux/libraries ».

3) Dans mon code source, modifier la ligne # 423, pour la nouvelle bibliothèque :

Code: [Select]
#include "Servo.h"

Par la ligne :

Code: [Select]
#include "ServoTimer2.h"

4) Toujours dans mon code source, modifier la ligne # 702 de la création de l'objet Servomoteur :

Code: [Select]
Servo ServoMoteurSonar_1;

Par la ligne :

Code: [Select]
ServoTimer2 ServoMoteurSonar_1;

5) Fermer l'IDE d'Arduino pour m'assurer que tous les changements de bibliothèque soient pris en compte.

6) Au relancement de l'IDE d'Arduino et à la compilation, il y a l'erreur suivante :

Code: [Select]
Arduinobot_Travail.cpp.o: In function `setup':
/home/rene/sda6/Électroniques/Arduino_Linux/Arduinobot_Travail.ino:830: undefined reference to `ServoTimer2::attach(int, int, int)'


7) Toujours dans mon code source, modifier la ligne # 806 de la création de l'objet Servomoteur :

Code: [Select]
ServoMoteurSonar_1.attach (SERVO_MOTEUR_SONAR_1, ServoMoteurSonar_1PositionMinimum, ServoMoteurSonar_1PositionMaximum);

8) Donc, il semble que le type de variable pourrait être en cause, car « `ServoTimer2::attach(int, int, int)' » :

Code: [Select]
const byte SERVO_MOTEUR_SONAR_1 = 19;// DigitalPWM

Que je remplace par (ligne # 620) :

Code: [Select]
const int SERVO_MOTEUR_SONAR_1 = 19;// DigitalPWM

9) Pour les deux autres variables, c'est correct (ligne # 667) :

Code: [Select]
int ServoMoteurSonar_1PositionMinimum = 500;

Et  (ligne # 669) :

Code: [Select]
int ServoMoteurSonar_1PositionMaximum = 2400;

10) À la recompilation, même erreur :

Code: [Select]
Arduinobot_Travail.cpp.o: In function `setup':
/home/rene/sda6/Électroniques/Arduino_Linux/Arduinobot_Travail.ino:830: undefined reference to `ServoTimer2::attach(int, int, int)'


Après étude du code de la nouvelle bibliothèque, je décide d'essayer sans les deux derniers paramètres de « attach ».

11) Alors, je modifie la ligne # 828 :

Code: [Select]
ServoMoteurSonar_1.attach (SERVO_MOTEUR_SONAR_1,
                             ServoMoteurSonar_1PositionMinimum,
                             ServoMoteurSonar_1PositionMaximum);


Sans les deux derniers paramètres :

Code: [Select]
ServoMoteurSonar_1.attach (SERVO_MOTEUR_SONAR_1);

12) À la compilation, pas d'erreurs, alors je charge la compilation sur le Mega.

Et c'est là que je constate que :

A) Le problème de base reste entier, c'est-à-dire que le fonctionnement du mode PWM est désactivé et que je ne peux utiliser une vitesse variable pour mes deux moteurs CC. Normalement, c'est deux moteurs à courant continu devraient se mettent en mouvement avec un PWM au alentour de 110, mais même à 254, il ne bougent pas. Je dois passer à 255 pour qu'ils se mettent en action.

B) Le servomoteur du capteur sonar HR-SC04 ne fonctionne plus, pas un bruit, pas un mouvement.

C) En reprenant l'ancienne version du code source, le servomoteur du capteur sonar HR-SC04 fonctionne de nouveau.

Je sens bien que l'on est sur la bonne piste, mais pour le moment ça ne fonctionne pas.

Qu'en pensez-vous, une piste de solution ?

L'ami René
P.-S. : Votre aide est grandement appréciée...
Tous pour un et un pour tous !

skywodd

Bizarre bizarre, ServoTimer2 a pourtant une version de attach() à trois arguments (pin, min, max).
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

LamiRene

Bonjour skywodd,

Oui, bizarre et je respecte pourtant les indications et types de variable, mais ... bogue !!!

Il ne faut pas oublier que j'ai fait une version de mon Arduinobot sans la bibliothèque « IRremote » et sans la bibliothèque "LiquidCrystal.h", malheureusement, le problème persiste.

J'en déduis qu'il y a interfèrent avec les "TIMERx" ou les "INTx" et le mode PWM causé par la bibliothèque "Servo.h".

Mais quelle serait la solution au problème ?

En attendant une autre piste de solution, je recherche une autre bibliothèque type « Servo ».

Merci pour votre aide !

L'ami René
Tous pour un et un pour tous !

Go Up