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

C Discussion :

Calcul d'incrémentation pour compteur


Sujet :

C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut Calcul d'incrémentation pour compteur
    Bonjour à tous,

    Je galère sur un petit bout de mon programme et là j'avoue que sans aide extérieure, des idées fraîches , je n'y arriverai pas.

    Pour le background je peux dire que mon projet est un petit robot qui met en œuvre 2 compteurs (roue droite et gauche) qui servent à compter la distance et le sens de rotation. Ces compteurs comptent entre 0 et 65535. Si ils arrivent à 65535 ils retournent à 0. De la même manière si une roue recule le compteur décompte.

    J'ai donc besoin d'une variable qui évolue entre -32767 et 32767 pour l'asservissement en position et, c'est là qu'est mon problème, d'une seconde variable qui évolue toujours positivement (même si le robot recule et que les compteurs décomptent) pour l'asservissement en vitesse.

    par exemple si le compteur évolue de la sorte : 1, 2, 4, 3, 1, 65530, 65500
    alors la variable pour l'asser en position donne: 1, 2, 4, 3, 1, -5, -35
    puis la variable pour l'asserv en vitesse donne: 1, 2, 4, 5, 7, 12, 42
    (Légende : Rouge : valeur qui croît; Bleu : valeur qui décroît)

    Voici la fonction que j'ai réalisé jusqu'à présent. Pour incrémenter constamment ces variables de vitesse (CmptVD et CmptVG) j'ai tenté une comparaison entre l'itération actuelle et précédente mais la variable décroit tout de même. C'est un échec.

    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
     
    //---------------------------------------------------------------------------
    // 							FONCTION COMPTAGE 								-
    //	En entrée : compteurs hardware ls7366 allant de 0 à 65535				-
    //	En sortie : CmptD, CmptG allant de -32767 à +32767						-
    //				CmptVG, CmptVG allant de 0 à 65535 quelque soit le sens 	-
    //
    //					   [0]------------------------[65535]>		-
    //			<[-32767]----------[0]----------[32767]>					-
    //---------------------------------------------------------------------------
    void Comptage(void)
    {
     
    	CmptD = Qcntr_Read(QcntrD); // charger le compteur Droit
    	CmptG = Qcntr_Read(QcntrG);
    	CmptVD = CmptD;
    	CmptVG = CmptG;
     
    //---------- variable asservissement position
    		if (Qcntr_Read_Sens(QcntrD) == 0) 							// AVANCER
    		{
    			if (CmptD > 32767){CmptD = 0;}							// et dépasser 32767 = retour à 0
    		} 
    			else 													// RECULER
    			{
    				if (CmptD > 32767){CmptD = CmptD - 65535;}			// et dépasser 32767 = compter sous 0
    				if (CmptD < -32767){CmptD = 0;}
    			}
     
     
    		if (Qcntr_Read_Sens(QcntrG) == 0) 							// AVANCER
    		{
    			if (CmptG > 32767){CmptG = 0;}							// et dépasser 32767
    		} 
    			else 													// RECULER
    			{
    				if (CmptG > 32767){CmptG = CmptG - 65535;}			// et dépasser 32767
    				if (CmptG < -32767){CmptG = 0;}
    			}
     
    //---------- variable asservissement vitesse
    	if (CmptD < OldCmptD )  { CmptVD += CmptVD + (OldCmptD - CmptD) ; } else {CmptVD = CmptD;}  // calculer compteur vitesse
    	OldCmptD = CmptD; // actualiser itération précédente
     
    }
    Merci à vous!

  2. #2
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Il nous manque le plus important : les déclarations et donc les types des variables entières que tu manipules.

    Tu peux t'en sortir en détournant à ton profit le dépassement de capacité d'un entier - integer overflow, en anglais - sur des variables de type uint16_t (defini dans stdint.h / inttypes.h). Attention : en C le comportement d'un dépassement n'est défini que pour des opérations arithmétiques sur des entiers non signés. Il faudra ajouter une petit manip afin d'obtenir une variable bouclant entre -32767 (-32768 ?) et +32767.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Il nous manque le plus important : les déclarations et donc les types des variables entières que tu manipules.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    float CmptG, CmptVG ; 		// Compteur position gauche, compteur vitesse gauche
    float CmptD, CmptVD ;
    float OldCmptD , OldCmptG ;

  4. #4
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Une raison particulière pour en faire des float ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if (CmptD > 32767)
    {
        CmptD = CmptD - 65535;
    }
    if (CmptD < -32767)
    {
        CmptD = 0;
    }
    Ces deux blocs :

    • sont interdépendants (peut-être faudrait-il un else ?) ;
    • ne sont pas symétriques du point de vue logique : les deux traitements ne sont pas équivalents.


    Tu as du code dupliqué : fais une fonction si tu dois appliquer l'invariant à plus d'une variable.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Pas de raison particulière non.

    Tu as du code dupliqué : fais une fonction si tu dois appliquer l'invariant à plus d'une variable.
    Pardon mais je ne comprend pas cette phrase.

    De toute manière ce qui m’amène ici c'est l'autre partie du programme qui concerne la variable CmptVD :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //---------- variable asservissement vitesse
    	if (CmptD < OldCmptD )  { CmptVD = CmptVD + (OldCmptD - CmptD) ; } else {CmptVD = CmptD;}  // calculer compteur vitesse
    	OldCmptD = CmptD; // actualiser itération précédente

  6. #6
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par fred7 Voir le message
    Pas de raison particulière non.
    Alors ne les utilise pas les float sont fait pour faire des calculs mathématique plus poussé , mais ne sont pas très précis les comparaison avec des nombre entier peut causer quelque souci.

    Sinon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (CmptD > 32767){CmptD = 0;}							// et dépasser 32767 = retour à 0
    		} 
    			else 													// RECULER
    			{
    				if (CmptD > 32767){CmptD = CmptD - 65535;}			// et dépasser 32767 = compter sous 0
    				if (CmptD < -32767){CmptD = 0;}
    			}
    utilise un short , ça t'évitera ce genre de calcul !

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Euh, non.
    La taille de short n'est pas limité par la norme, et les "overflow" sont des "undefined behaviours".
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Effectivement un short de soulage de ces tests.
    Reste plus que le problème de base

  9. #9
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Citation Envoyé par fred7 Voir le message
    Pas de raison particulière non.
    Alors utilise plutôt un type adapté : tiens t'en à celui que te renvoie Qcntr_Read.


    Citation Envoyé par fred7 Voir le message
    Tu as du code dupliqué : fais une fonction si tu dois appliquer l'invariant à plus d'une variable.
    Pardon mais je ne comprend pas cette phrase.
    Un invariant est une contrainte que tu fais respecter à une variable et aux transformations qu'elle subit. Comme tu cherches à appliquer cet invariant à plusieurs endroits et à plusieurs propriétés (CmptD et CmptG), tu es amené à dupliquer du code : c'est signe qu'il faut écrire une fonction.


    Citation Envoyé par fred7 Voir le message
    Effectivement un short de soulage de ces tests.
    short, non. unsigned short, peut-être. uint16_t, certainement. As-tu lu tous les messages du fil ?


    Citation Envoyé par fred7 Voir le message
    De toute manière ce qui m’amène ici c'est l'autre partie du programme qui concerne la variable CmptVD :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //---------- variable asservissement vitesse
    	if (CmptD < OldCmptD )  { CmptVD = CmptVD + (OldCmptD - CmptD) ; } else {CmptVD = CmptD;}  // calculer compteur vitesse
    	OldCmptD = CmptD; // actualiser itération précédente
    [...]

    Reste plus que le problème de base
    Justement : quel est-il au final ? Procédons par étape, et résolvons les problèmes dans l'ordre où ils se présentent. La première partie de ta fonction est erronée, commençons par là.

  10. #10
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par ternel Voir le message
    Euh, non.
    La taille de short n'est pas limité par la norme, et les "overflow" sont des "undefined behaviours".
    Exact mais j'avais bien la flemme de lui balancer la norme et de lui expliquer en détail , mais il y'a de grande chance que son short fasse 2 octet sauf s'il code sur une machine assez particulière qui supporte pas les 2 octets (parce que de mon point de vue si la norme ne le précise pas clairement c'est bien pour des raisons hardware avant tout).

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Oui j'ai tout lu (je ne suis pas un sale gosse hein, des gens prennent la peine de me répondre donc je lis ).

    Pour clarifier la chose ma fonction Qcntr_Read(); me renvoie une valeur de type unsigned short du coup j'ai suivi le conseil de Kannagi et j'ai utiliser un short pour CmptD afin de me passer de ma structure conditionnelle.

    Et effectivement après essai ça marche et ça donne donc ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    short CmptD;
     
    void Comptage(void)
    {
    CmptD = Qcntr_Read(QcntrD);
    }
    A ce stade j'ose imaginer que cette partie de code ne comporte plus d'erreurs...

  12. #12
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Ça dépend du point de vue.
    Pour la norme, son comportement est indéfini (non spécifié par la norme ni le compilateur). Donc, il peut marcher ce matin, et pas ce soir.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Citation Envoyé par ternel Voir le message
    Ça dépend du point de vue.
    Pour la norme, son comportement est indéfini (non spécifié par la norme ni le compilateur). Donc, il peut marcher ce matin, et pas ce soir.
    Comme ça c'est mieux ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int16_t CmptD;
     
    void Comptage(void)
    {
    CmptD = Qcntr_Read(QcntrD);
    }

  14. #14
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Mais où est passé le reste du code de la fonction ?

    Si ton API te renvoie un entier non signé (unsigned short), ce n'est nullement un hasard. Pour quelle raison places-tu la valeur de retour dans un entier signé (short, int16_t..) ? Ce genre de décision qui peut avoir des conséquences.. « palpables » doit toujours se justifier.

    Pour résumer, tu as deux choix :

    • soit tu fais déborder un entier non signé - parce que sinon, c'est un comportement indéfini comme nous l'avons précisé - avec une petite manip pour obtenir un entier signé sur un intervalle de valeurs « décalé » (centré sur zéro) ;
    • soit tu réalises explicitement des transformations comme tu l'as proposé initialement mais sur un entier de capacité supérieure à celui que tu reçois (si sizeof(unsigned short) == 2, alors int_least32_t par exemple), si un tel type existe.

Discussions similaires

  1. Problème de calcule en SQL !
    Par FilipeVV dans le forum Langage SQL
    Réponses: 3
    Dernier message: 02/09/2005, 11h45
  2. Problème de calcul matricielle
    Par Clad3 dans le forum Algorithmes et structures de données
    Réponses: 21
    Dernier message: 29/06/2005, 21h45
  3. problème de calcul des normales par sommet
    Par captainSeb dans le forum OpenGL
    Réponses: 2
    Dernier message: 21/01/2005, 13h42
  4. [Calendar]Problème de calcul de date
    Par valerie90 dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 08/12/2004, 12h13
  5. Problème de calcul unix_timestamp
    Par petit_stagiaire dans le forum Administration
    Réponses: 2
    Dernier message: 28/04/2004, 15h27

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