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

Embarqué Discussion :

Temporisation de signaux


Sujet :

Embarqué

  1. #1
    Invité
    Invité(e)
    Par défaut Temporisation de signaux
    Bonjour,

    Je viens poster sur le forum car, après plusieurs semaines de recherches et vains tripatouillages, je ne sais plus que faire pour résoudre mon problème.

    Le projet concerné est un système embarqué contrôlé par une developpement board (Olimex A20) avec un système Debian (3.4) sur micro-SD fourni par le constructeur de la board.

    Un programme en C++/Qt4 contrôle un moteur pas-à-pas en envoyant des ordres réguliers (il faut envoyer un ordre pour chaque pas).

    Je précise pour détail de programmation que la boucle de contrôle a son propre thread et ne fait rien d'autre qu'envoyer l'ordre puis attendre une durée précise.

    Le problème que j'ai se situe au niveau de cette durée qui, justement, n'est pas précise du tout. Pour être plus exact, j'ai pu mesurer à l'oscilloscope que l'attente effective sera systématiquement supérieure à l'attente ordonnée. Comme c'est cette durée qui conditionne la vitesse de déplacement du moteur, cela pose un sérieux problème car, non seulement il ne se déplace pas à la vitesse souhaitée, mais en plus il plafonne bien avant d'atteindre sa vitesse maximale.

    J'ai pu constater également que cela ne semble pas être une limitation matérielle car, en supprimant la fonction d'attente (on envoie les ordres successifs aussi rapidement que le système en est capable), la fréquence des ordres est nettement supérieure à ce dont j'ai besoin. Mais dès que j'ordonne une attente entre les signaux, je vois apparaître une latence supplémentaire à l'attente. Par exemple, si j'ordonne 2 ms se latence, j'en aurais 5, et si j'ordonne 200 ms de latence, j'en aurait 250.

    C'est pour moi un problème bloquant et là je suis... ben bloqué.

  2. #2
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Migrer vers un système d'exploitation temps réel si tu veux un ordre de grandeur de la milliseconde ou en dessous dans la marge d'erreur.

    Si tu peux accepter plusieurs dizaines de milliseconde d'écart dans ce cas tu peux rester sur une Debian.
    Et il faudra donc regarder les différentes tâches du système pour comprendre pourquoi ton thread ne reprend pas la main assez vite.

    M'enfin... Utiliser un OS pour faire tourner un moteur...
    Un simple microcontroleur aurait suffit...

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  3. #3
    Invité
    Invité(e)
    Par défaut
    M'enfin... Utiliser un OS pour faire tourner un moteur...
    Un simple microcontroleur aurait suffit...
    Cela suffisait, jusqu'à ce qu'on décide d'ajouter des caméras et une IHM dynamique style tablette (de plus, j'ai dit un moteur, mais en fait il y en a 10 à contrôler).

    Pour ce qui est du changement d'OS, j'y connais pas grand chose, mais j'ai peur de tout foutre en l'air si je n'utilise pas l'OS fourni par le constructeur de la board, j'entend par là le risque par exemple de perdre le système de paramétrage de l'écran par fichier fex, ou l'utilisation des GPIO et SPI (juste deux exemples parmi d'autres).

    Après recherche, j'ai vu qu'il est possible de patcher un noyau pour le rendre temps réel (par exemple avec RT-PREEMPT), ce serait viable ça ?

    Ce serait déjà peut-être moins compliqué, bien que très loin d'être gagné vu que même après plusieurs tentatives, je n'ai toujours pas réussi à recompiler un noyau (en cross-compil).

  4. #4
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 148
    Points : 28 113
    Points
    28 113
    Par défaut
    Bonjour,

    Un temps d'attente est toujours un temps minimal. En (très) gros, l'algorithme du sleep est le suivant :
    • recuperer l'heure
    • ajouter le temps d'endormissement
    • Tant que ce moment n'est pas atteint, attendre


    Ce dernier point a pour effet de marquer le processus comme "en attente", et donc il se voit remis à la fin de la liste des processus à exécuter (l'OS peut aussi noter qu'il n'a pas exécuté son quantum de temps, et donc qu'il est un peu plus prioritaire pour les prochaines fois).

    Dans le cas d'un micro-sleep, tu peux par exemple voir qu'il n'est pas possible (sur les OS basiques) d'attendre moins longtemps qu'un quantum de temps [du moins, c'est ce qu'ont montré les tests que j'avais fait à l'époque].

    Dans ton cas, il te faut effectivement te rapprocher du temps réel (soft real-time). Sous Unixoïde, il existe un moyen pour lancer un processus en (faux) temps-réel, ce qui revient en fait à modifier l'ordonnanceur du système pour que ton processus soit tout le temps prioritaire.
    Attention, si ton process part en cacahuète et consomme 100% du CPU, tu ne pourras l'arréter qu'avec un autre process temps-réel, ou bien en arrétant/rebootant la machine.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  5. #5
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 646
    Points : 11 135
    Points
    11 135
    Par défaut
    bonjour,

    Comme indiqué par gangsoleil, la fonction Sleep démarre un thread donc il ne faut pas compter sur elle pour avoir des timings précis.

    Pour avoir été confronté à ce problème sous Windows, j'ai utilisé les fonctions QueryPerformanceFrequency et QueryPerformanceCounter qui permettent d'avoir de très bons timings. Le problème est que cette attente est active (une boucle while qui regarde le temps restant). Mais dans ton cas, pour 2ms ou 250ms, cela ne devrait pas poser de soucis (et en plus tu es déjà dans un thread).

    Regarde si pour en C++ sous Debian et accessoirement avec QT tu n'as pas des fonctions similaires à celles que j'ai évoquées.
    J'ai trouvé ceci :
    http://man7.org/linux/man-pages/man2...gettime.2.html
    http://qt-project.org/doc/qt-4.8/qelapsedtimer.html

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 62
    Points : 162
    Points
    162
    Par défaut
    Bonjour,
    J'ai une solution simpliste à proposer. Plutôt que demander un temps d'attente fixe, il faudrait faire varier le temps d'attente en fonction des erreurs précédentes.
    Au début de ton asservissement tu connais l'heure. Tu dois effectuer une action toute les 2ms. Au lieu de dormir 2 ms après chaque action, ton thread peux dormir le temps entre l'instant actuelle et le prochain instant programmé.

    En version pseudo code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    delta = 2
    next = now()
     do
         action()
         next += delta
         sleep(next - now())
     while (!stop)

  7. #7
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponses.

    Je vais explorer ces deux pistes dès que j'aurais un peu de temps et je reviendrais vous dire ce qu'il en est.

    Instinctivement et sans avoir essayé, j'ai quand même une légère préférence pour la solution de schonai, car, comme le dit Auetur, mesurer le temps même de façon précise implique nécessairement une boucle d'attente active. Et comme il s'agit ici de piloter des moteurs pas-à-pas, cette attente doit être répétée à chaque pas, sur toute la durée du déplacement (sachant qu'un pas correspond à un déplacement de l'ordre de 10 microns, ça en fait). Du coup, j'ai peur que cette solution ne mobilise beaucoup trop de ressource processeur pour être viable (sachant que le logiciel ne fait pas que piloter les moteurs.

    Je vais donc tester en priorité l'attente au delta, qui est à mon sens plus futée.
    Cela dit, cette classe QElapsedTime va m'être très utile pour la mettre en place.
    Dernière modification par Invité ; 27/08/2014 à 11h55.

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Salut,

    En général, pour piloter un moteur pas-à-pas, on utilise une interface PWM qui te permet de résoudre en partie les problèmes de timming : ta carte n'en possède pas ?
    Si elle n'en possède pas, tu peux utiliser un µControlleur (possédant une PWM) à 1 ou 2€ que tu fais communiquer avec ta carte

  9. #9
    Invité
    Invité(e)
    Par défaut
    L'une des cartes testées a des interfaces PWM, mais cela ne répond pas à mon besoin car elle ne permet pas de changer la fréquence du duty cycle (la vitesse du moteur, qu'il faut pouvoir modifier à tout moment, étant conditionnée par la fréquence des fronts montants).

    J'explore actuellement une autre voie. Affaire à suivre.
    Dernière modification par Invité ; 02/09/2014 à 18h55.

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    ça m'étonne que tes interfaces PWM ne puissent pas faire ça : normalement, tu peux configurer la frequence et le duty cycle

  11. #11
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 646
    Points : 11 135
    Points
    11 135
    Par défaut
    boboss123 : pas toujours. Sur certaines cartes tu ne peux modifier que le rapport cyclique, pas la fréquence.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Amstrad] Signaux à gérer port E/S pour lire ROM
    Par Masterglob dans le forum Autres architectures
    Réponses: 7
    Dernier message: 12/01/2005, 13h03
  2. [C#] Gérer les signaux genre ctrl+c?
    Par BleudeBromothymol dans le forum Windows Forms
    Réponses: 8
    Dernier message: 17/11/2004, 16h32
  3. [debutant]temporisation
    Par sly33 dans le forum Débuter
    Réponses: 4
    Dernier message: 12/08/2004, 14h56
  4. Temporisation pendant verouillage de l'objet matable
    Par Rdjedidene dans le forum Administration
    Réponses: 14
    Dernier message: 09/06/2004, 11h52
  5. temporisation
    Par forthx dans le forum C
    Réponses: 5
    Dernier message: 25/06/2003, 16h49

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