IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Problème de vitesse de détection des impulsions d'un encodeur rotatif


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2014
    Messages : 8
    Par défaut Problème de vitesse de détection des impulsions d'un encodeur rotatif
    Bonjour,

    Je suis débutant en arduino (mais pas en programmation). Je suis en train de tester un systeme qui me permettrait d'indiquer les coordonnées d'un astre visé avec un télescope. Dans ce but j'ai mis en place un Arduino Mega 2560 que j'avais sous la main et j'ai réussi à récupérer 2 encodeurs rotatif de la marque Sick qui ont 10000 pas par tour, soit un resolution d'environ 2 Arcminute par impulsion

    Voici les encodeurs: https://www.sick.com/fr/fr/codeurs/c...0000/p/p293589

    Le but est donc de me donner l'angle horizontale (Azimut) et l'angle vertical (Altitude). J'ai donc Ecrit un bout de code classique pour des encodeurs avec gestion des impulsions par interruption. Ça ne marche pas trop mal si je tourne très doucement mais dès que j'accélère, je perd vraiment beaucoup d'impulsion (jusqu'à 50% si je tourne très vite).

    Quelle est la cause de ce phénomène: Encodeurs trop précis et/ Arduino trop lent? ou un problème de code (que je joins ci dessous)? Y-a-t-il une solution pour régler ce soucis ou tout au moins le réduire de façon conséquente. Pour ceux qui connaissent, le télescope est un Dobson, donc tourner à la main.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    / CONSTANTES
    #define ENC_AZIM_A 2	                                      // Port signal A encodeur Azimut
    #define ENC_AZIM_B 22                                       // Port signal B encodeur Azimut
    #define NB_IMP_ENC 10000.0                                  // Nb impulsions par tour encodeur
    #define ENC_ALTI_A 3                                        // Port signal A encodeur Altitude
    #define ENC_ALTI_B 23                                       // Port signal B encodeur Altitudeaison
    #define SEC_PAR_TR 360.0*60*60                              // Nbre d'Arseconde par tour
    #define INC_SEC SEC_PAR_TR/NB_IMP_ENC                       // Angle en Arcseconde par pas de l'encodeur
     
    // VARIABLES GLOBALES
    volatile long ComptImpAzim;                          // Compteur d'impulsions en Azimut
    volatile long ComptImpAlti;                          // Compteur d'impulsions en Altitude
    unsigned long AncienMillis;                          // Pour tempo non bloquante
     
    // PROTO FONCTIONS
    char *arcsec2str( double arcsec);                    
    void Move_Azim();
    void Move_Alti();
     
     
    // Récupération des mouvements de l'azimut
    void Move_Azim()
    {
    	if (digitalRead(ENC_AZIM_B))
    		ComptImpAzim--;
        if (ComptImpAzim < 0) ComptImpAzim += NB_IMP_ENC;
    	else
    		ComptImpAzim++;
       if (ComptImpAzim >= NB_IMP_ENC) ComptImpAzim -= NB_IMP_ENC;
    }
     
    // Récupération des mouvements de l'altitude
    void Move_Alti()
    {
      if (digitalRead(ENC_ALTI_B))
        ComptImpAlti--;
        if (ComptImpAlti < 0) ComptImpAlti += NB_IMP_ENC;
      else
        ComptImpAlti++;
       if (ComptImpAlti >= NB_IMP_ENC) ComptImpAlti -= NB_IMP_ENC;
    }
     
    // Transforme l'angle en arcsec vers une chaine [+ddd° mm' ss.ss"]
    char *arcsec2str(double arsec )
    {
    	int degre;
    	int minute;
    	double seconde;
    	static char rep[20];
      char secch[5];
    	char minch[2];
     
    	degre = int(arsec/3600);
    	minute = int((arsec - (degre*3600)) /60);
    	seconde = (arsec - (degre*3600) - (minute*60));
     
      dtostrf(seconde, 5, 2, secch);
      dtostrf(minute, 2, 0, minch);
      // 
    	sprintf(rep,"%4d° %s' %s""",degre, minch, secch);
     
    	return rep;
    }
     
     
    void setup()
    {
    	// Pin A et B encodeur Az en entrée
    	pinMode(ENC_AZIM_A, INPUT);
    	pinMode(ENC_AZIM_B, INPUT);
     // Pin A et B encodeur AltC en entrée
      pinMode(ENC_ALTI_A, INPUT);
      pinMode(ENC_ALTI_B, INPUT);
    	// Pull up 
    	digitalWrite(ENC_AZIM_A, HIGH);
    	digitalWrite(ENC_AZIM_B, HIGH); 
    	digitalWrite(ENC_ALTI_A, HIGH);
      digitalWrite(ENC_ALTI_B, HIGH);
     
      // Init port série 0 pour moniteur
    	Serial.begin (9600);
     
      // Init à 0 des compteurs d'impulsions
      ComptImpAzim = 0;
      ComptImpAlti = 0;
     
      // Detection des mouvements d'encodeurs par interruption sur front descendant sur signal A
    	attachInterrupt(digitalPinToInterrupt(ENC_AZIM_A), Move_Azim, FALLING);
    	attachInterrupt(digitalPinToInterrupt(ENC_ALTI_A), Move_Alti, FALLING);
     
    }
     
     
     
    void loop()
    {
      float Ang_Azim;
      float Ang_Alti;
     
      AncienMillis = millis();
     
      // Affichage des angles toutes les 500ms sans blocage
      if ( (millis() - AncienMillis) > 500) {
        // Angle d'azimut
        Ang_Azim = ComptImpAzim*INC_SEC;
        Serial.print("Azim: ");
    	  Serial.print(arcsec2str(Ang_Azim));
     
        // Angle d'azimut
        Ang_Alti = ComptImpAlti*INC_SEC;
        Serial.print(" - Alt: ");
        Serial.print(arcsec2str(Ang_Alti));
     
        AncienMillis = millis();
      }
     
    /*
        * AUTRES TRAITEMENTS ET CALCUL FAIT ICI
        * Avec des tempo non bloquantes (millis())
        * 
        *
     */  
     
     
    }

  2. #2
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 017
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 017
    Par défaut
    Bonjour amathieu

    Peut être essayer avec la bibliothèque digitalWriteFast.h
    Le lecture/écriture des ports est ~10* plus rapide.

    digitalRead 1000 x
    3592 uSec.

    digitalReadFast 1000 x
    348 uSec.

    ou la bibliothèque Encoder qui est, elle, assez rapide et simplifie le code.

    Cordialement
    jpbbricole

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2014
    Messages : 8
    Par défaut
    Merci pour les conseils Jpp, je vais essayé cela dès que possible.

  4. #4
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 250
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 250
    Par défaut
    Salut,
    Quel est l'intérêt de lire l'état d'une broche dans une interruption ? C'est une perte de temps.

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Move_Azim()
    {
    	... // quand tu es ici, généralement il faut faire le moins de chose possible pour ne pas louper l'interruption suivante
    }

    Pourquoi relire l'état de la broche ?

  5. #5
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 017
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 017
    Par défaut
    Bonjour Vincent
    Citation Envoyé par Vincent PETIT Voir le message
    Pourquoi relire l'état de la broche ?
    Pour connaître le sens de rotation?
    L'interrupt se fait sur la pin ENC_AZIM_A et dans l'interrupt il relis ENC_AZIM_B.
    Resp ENC_ALTI_A, ENC_ALTI_B

    Cordialement
    jpbbricole

  6. #6
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 250
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 250
    Par défaut
    Citation Envoyé par jpbbricole Voir le message
    Pour connaître le sens de rotation?

    Bien vu

    La prochaine fois je prendrai plus de temps avant de répondre.

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2014
    Messages : 8
    Par défaut
    Bonsoir,

    Suite à vos conseils, j'ai essayé la library encodeur que vous m'avez conseillé. Je ne recevais que des valeurs vraiment bizarre. Après plusieurs essais j'ai décidé de créer ma librairie (surtout à des fins didactitielles, vu ce qu'il y a déjà sur le marché). Je rappelle que j'ai des notions de programmations, mais pas de classes ni de C++.

    J'ai quelque chose de simple mais .... Ca ne marche pas. Le problème des interruptions dans des classes est (si j'ai bien compris tout ce que j'ai lu) STATIC mais l'interet est bien de différencier les 2 encodeurs. Donc d'y perd mon latin (et même mon C++) et je sollicites donc votre aide.


    Pour mon sketch, j'ai cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #include <simpleMinuteur.h>
    #include "DSC_Encoder.h"
     
    #define TMR_ENC 500		// Durée du Timer de lecture des positions
     
    // Déclaration des pins de l'arduino utilisées
    #define AZpinA 2		
    #define ALTpinA 3
    #define AZpinB 22
    #define ALTpinB 23
     
    // Création du Timer pour la lecture des encodeurs
    simpleMinuteur TMREncodeur(TMR_ENC); 
     
    // création des 2 encodeurs
    encodeur EncAzim(AZpinA, AZpinB);
    encodeur EncAlti(ALTpinA, ALTpinB);
     
    // Variables pour stocker les positions lues des encodeurs
    long PosAZ, PosALT;
     
    // Initialisations
    void setup()
    {
    	Serial.begin(115200);
     
    }
     
    // Boucle principales
    void loop(){
    	// Si Timee encodeur écoulé
    	if (TMREncodeur.estTermine()){
    		// Lectures des positions des 2 encodeurs
    		PosAZ = EncAzim.read();
    		PosALT = EncAlti.read();
    		// Affichage des positions sur moniteur série
    		Serial.print("Azimut: ");
    		Serial.print(PosAZ);
    		Serial.print(" - Altitude: ");
    		Serial.print(PosALT);
    		// Redémarre le timer encodeur
    		TMREncodeur.redemarrer();
    	}
     
    }

    ensuite mon entete (.h) donne ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #ifndef DSC_ENCODER_H
     
    #define DSC_ENCODER_H
    #include <arduino.h> 
     
     
    class encodeur 
    {
     
    	public :
     
    		// Constructeur
    		encodeur(int pin1, int pinB);  	// Création d'un encodeur sur les pin spécifiées
    		long read();					// Lecture de la postition d'un encodeur
    		void write(long p);				// Force la position d'un encodeur
    		void RAZ();						// Remise à 0 de la position de l'encodeur
     
     
     
     
        private:
     
    		int _pA, _pB;					// N° de pin en interne
        	volatile long position;			// Position courante de l'encodeur
        	static void FctInt();			// Fonction privée STATIC qui lance la procédure ISR
        	void encodeur_ISR();			// Traitement à faire lors d'une interruption (Incrémente Décrémente la position)
     
    };
     
     
    #endif

    et finalement le code proprement dit de la lib:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include <arduino.h>
    #include "DSC_encoder.h"
     
     
     
     
    encodeur::encodeur(int pinA, int pinB) {
     
    		_pA = pinA;														// Récupération des pin
    		_pB = pinB;
    		pinMode(_pA, INPUT);											// Pin A en entrée
    		digitalWrite(_pA, HIGH);										// Pull Up
    		pinMode(_pB, INPUT);											// Pin B en entrée 
    		digitalWrite(_pB, HIGH);										// Pull Up
    		position = 0;													// Initialisation de la position à 0
    		attachInterrupt( digitalPinToInterrupt(_pA), FctInt, CHANGE );  // Déclenche la fonction FctInt à changement de la pin A
    }
     
     
    // Renvoie la position de l'encodeur en nombre de pas
    long encodeur::read(){
    	long Valrtn;
    	noInterrupts();			// Bloque les interruptions
    	Valrtn = position;		// Recupère la position
    	interrupts();			// ReAutorise les interruptions
    	return Valrtn;			// Renvoie la valeur lue
    }
     
    // Force la position de l'encodeur en nombre de pas
    void encodeur::write(long p){
    	noInterrupts();			// Bloque les interruptions
    	position = p;			// Modifie la valeur de la position arduinovec la valeur passée en parametre
    	interrupts();			// ReAutorise les interruptions
    }
     
    // Remet la position de l'encodeur à 0 
    void encodeur::RAZ(){
    	write(0);				// Met à 0 la position courante
    }
     
     
    // Lancement de la fonction ISR sur l'interruption
    void FctInt(){
    	encodeur_ISR();	// Lance la fonction ISR 
    }
     
     
    // Traitement à reception de l'interruption
    void encodeur::encodeur_ISR(){
    	int etatB, etatA;
     
    	// Récupère les états des 2 pins
    	etatA = digitalRead(_pA);
    	etatB = digitalRead(_pB);
     
    	// Si les pins sont dans le même état
    	if (etatA == etatB )
    	{	
    		noInterrupts();		// Bloque les interruptions
    		position++;			// Incrémente la position
    		interrupts();		// re Autorise les interruptions
    	}
    	else // Si les états sont différents
    	{
    		noInterrupts();		// Bloque les interruptions
    		position--;			// Décrémente la position
    		interrupts();		// re Autorise les interruptions
    	}
     
     
     
     
    }
    J'ai bien noté, en parcourant certains articles, que la fonction d'interruption devait etre static . Mais l'interet étant bien évidemment pas que les 2 encodeurs soient complètement indépendant, j'ai créer comme conseillé une fonction static privée qui appelle la fonction public qui réalise le traitement à proprement parlé.
    Ceci dit le compilateur me renvoie ce message alors que la fonction est bien déclaré:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    [Build] F:/Users/Anthony/Documents/Arduino/DSCOO...
    [Step 1] Check Toolchain.
    [Step 2] Find all source files.
    [Step 3] Start building.
    [3.3%] Compiling DSCOO.ino.cpp...
    [6.7%] Compiling DSC_encoder.cpp...
    F:/Users/Anthony/Documents/Arduino/DSCOO/DSC_encoder.cpp: In function 'void FctInt()':
    F:/Users/Anthony/Documents/Arduino/DSCOO/DSC_encoder.cpp:44:15: error: 'encodeur_ISR' was not declared in this scope
      encodeur_ISR(); // Lance la fonction ISR 
                   ^
    [Build] Error occurred.

    Merci d'avance pour le temps que vous pourrez me consacrer.

Discussions similaires

  1. [Selenium] Problème détection des fenêtres
    Par hbennou dans le forum Tests et Performance
    Réponses: 1
    Dernier message: 02/12/2010, 14h53
  2. Problème métadonnée oracle (Détection des MAJ)
    Par Bouga74 dans le forum Développement de jobs
    Réponses: 6
    Dernier message: 22/04/2010, 09h08
  3. Réponses: 4
    Dernier message: 13/02/2008, 12h53
  4. [RegEx] problème de détection des accents
    Par benoitB dans le forum Langage
    Réponses: 1
    Dernier message: 01/01/2008, 23h43
  5. Réponses: 14
    Dernier message: 12/04/2007, 20h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo