Position imprécise avec un servomoteur

Bonjour,
Après avoir cherché dans le forum sans trouver de sujet correspondant, je fais donc appel à vos compétences pour m'aider.
Je souhaite faire un pont tournant pour mon petit réseau ferroviaire et, après avoir testé diverses solutions (moteur pas à pas, servo 360, micro servomoteur sg90) ,je me suis arrêté sur un servomoteur un peu plus puissant, le " AZDelivery 5 x MG995".
J'ai 4 boutons pour choisir la position et le sens de la rotation (le sens dépend de la position actuelle par rapport à celle demandée). Je fixe les différentes positions par constantes et mon souci est que le moteur ne s'arrête pas exactement au même endroit selon qu'il tourne dans un sens ou dans l'autre. Exemple, en passant de la position 1 à la 2, je note précisément, en passant de 2 à 3, je note également, mais en revenant de 3 vers 2 il y a un petit décalage (1 ou 2 degrés). Comme il est essentiel que la voie sur le pont tombe parfaitement en face des voies fixes extérieures, ce décalage n'est pas acceptable.
Voici mon code :

/*
  Utilisation servo-moteur
  piloté par bouton 1 2 3 4 pour le choix de la rotation
  conservation de la position du moteur en EPROM
  4 positions
   1 2 et 3 = 3 voies de sortie
   4 = voies d'entree et de sortie si retournement
  Les positions sont contenues dans les variables val1, val2, val3, val4
  Valx = pos_prec retenue pour la positiion de départ des boucles de rotation la plus petite
       entre la position theorique et la position réelle
*/

#include <EEPROM.h>
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

const int bout1 = 8;        //  position interrupteur fin course 1
const int bout2 = 4;        //  position interrupteur fin course 2
const int bout3 = 7;        //  position interrupteur fin course 3
const int bout4 = 11;       //  position interrupteur fin course 14
const int val4 = 90;        //  Position du moteur sortie 1
const int val3 = 102;       //  Position du moteur sortie 2
const int val2 = 120;       //  Position du moteur sortie 3
const int val1 = 135;       //  Position du moteur sortie 4 retournement
int val = 0;                //  conserve la pos_prec du bouton saisie pour les traitements
int valx = 0;               //  pos_prec retenue pour la positiion de départ des boucles de rotation
int vitesse = 1;            //  détermine la vitesse de rotation du pont
int etat = 0;               //  variable pour les boucles de rotation
int i = 0;                  //  variable pour la boucle de déplacement du bras
int caractere = 0;          //  pos_prec du bouton actionne
int pos_prec;               //  pos_prec recupérée de l'EEPROM, derniere position connue
int pos_read;               //  pos_read valeur renvoyee par servo_read
int adresse = 14;           //  adresse de stockage dans EEPROM

void setup() {
  Serial.begin(9600);
  //  attachInterrupt(digitalPinToInterrupt(SENSOR_PIN_2), blink, CHANGE); // attache l’interruption externe n°0 à la fonction blink
  //  pinMode(SENSOR_PIN_2, INPUT);
  pinMode(bout1, INPUT_PULLUP);
  pinMode(bout2, INPUT_PULLUP);
  pinMode(bout3, INPUT_PULLUP);
  pinMode(bout4, INPUT_PULLUP);
  pos_prec = EEPROM.read(adresse);  // Retourne la pos_prec contenue dans l'eeprom, à l’adresse "14"
  myservo.write(pos_prec);          // le moteur a la derniere position memorisee
  myservo.attach(3);                // attache l'objet servo à la pin 3 Rotation

}

void loop() {
  caractere = 0;
  Serial.print(" caractere0 = ");
  Serial.println(caractere);
  Serial.print("     bout1 = ");
  Serial.println(digitalRead(bout1));
  Serial.print("     bout2 = ");
  Serial.println(digitalRead(bout2));
  Serial.print("     bout3 = ");
  Serial.println(digitalRead(bout3));
  Serial.print("     bout4 = ");
  Serial.println(digitalRead(bout4));

  /**** récupération de la pos_prec du bouton saisie et affectation des variables associées */
  if (digitalRead(bout1) == 1)
  {
    caractere = 1;
    val = val1;
  }
  else if (digitalRead(bout2) == 1)
  {
    val = val2;
    caractere = 2;
  }
  else if (digitalRead(bout3) == 1)
  {
    caractere = 3;
    val = val3;
  }
  else if (digitalRead(bout4) == 1)
  {
    caractere = 4;
    val = val4;
  }
  /*********************************************/
  // si un bouton a ete actionne ***************
  if (caractere != 0)
  {
    Serial.print(" caractere = ");
    Serial.println(caractere);
    Serial.println(" ");
    pos_prec = EEPROM.read(adresse);              //  lecture derniere position connu
    pos_read = myservo.read();                    //  lecture position du moteur
    if (pos_read <= pos_prec) {
      valx = pos_read; //  renseigne le debut de la boucle de rotation
    }
    else {
      valx = pos_prec; //  renseigne le debut de la boucle de rotation
    }
    if (pos_read <= val) {                        //  definit le sens de rotation
      for (etat = valx; etat <= val; etat += vitesse) {
        Serial.print(" caractere = ");
        Serial.print(caractere);
        Serial.print("  pos_prec = ");
        Serial.print(pos_prec);
        Serial.print("  pos_read = ");
        Serial.print(pos_read);
        Serial.print("  val = ");
        Serial.print(val);
        Serial.print("  valx = ");
        Serial.print(valx);
        if (etat > val) {
          myservo.write(etat);
          EEPROM.write(adresse, etat);
          Serial.print("  etatA = ");
          Serial.println(etat);
          break;
        }
        else {
          myservo.write(etat);
          EEPROM.write(adresse, etat);
          Serial.print("  etatB = ");
          Serial.println(etat);
          delay(30);
        }
      }
    }
    else {
      for (etat = valx; etat >= val; etat -= vitesse) {
        Serial.print(" caractere = ");
        Serial.print(caractere);
        Serial.print("  pos_prec = ");
        Serial.print(pos_prec);
        Serial.print("  pos_read = ");
        Serial.print(pos_read);
        Serial.print("  val = ");
        Serial.print(val);
        Serial.print("  valx = ");
        Serial.print(valx);
        if (etat > val) {
          myservo.write(etat);
          EEPROM.write(adresse, etat);
          Serial.print("  etatC = ");
          Serial.println(etat);
        }
        else {
          myservo.write(etat);
          EEPROM.write(adresse, etat);
          Serial.print("  etatD = ");
          Serial.println(etat);
          delay(30);
        }
      }
    }
  }
}

Merci pour votre aide.

J'ai bien peur qu'il n'y ait pas de solution parfaite avec un servomoteur. Ce dernier est constitué d'un moteur CC que l'on asservit, en principe, si on est loin de la position, on met la tension maxi, plus on se rapproche, plus on diminue la tension. Et il y a une zone pour laquelle le moteur n'est pas alimenté. Sans cela le bruit sur le potentiomètre capteur de position et le bruit de l'électronique ferait que le moteur vibrerait sans cesse (un petit peu dans un sens, un petit peu dans l'autre).

Une amélioration possible est d'avoir un petit incrément que l'on rajoute ou que l'on soustrait à la position en fonction du sens. Sinon pour un des deux sens, on va un peu trop loin et on revient. Mais rien ne garanti que l'erreur de positionnement soit toujours la même

Bonjour jcg95

Le servo n'est pas la bonne solution du fait de son imprécision, l'idéal est le moteur pas à pas. J'ai participé à un sujet équivalent sur ce forum Pont transbordeur en N, ce sujet qui s'est poursuivi en message privé, est très avancé.
Il s'agit d'un transbordeur latéral mais qui pourrait aisément être transformé en pont tournant, il est entraîné par un moteur NEMA17. Ici le montage qui m'a permis de développer le programme pour @nico78340 (la vis a un peu la danse de Saint-Guy, je l'ai malheureusement pliée).
Le système se commande par des boutons poussoir ou une télécommande IR ou par ordres via la console de l'IDE Arduino. Il conserve, en mémoire permanente, la dernière position de telle façon qu'il la retrouve au redémarrage du programme.

Si tu est intéressé?

Cordialement
jpbbricole

Bonsoir jpbbricole,
J’avais vue ton dossier et j’avais noté un grand intérêt mais qui ne me conveypas car il me faut absolument un pont tournant.
J’ai rencontré un certain nombre de problèmes et j’ai trouvé diverses solutions sans être tout à fait satisfait.
Je suis OK pour un échange privé si cela te convient.
Comment peut-on procéder ?
Cordialement.

C'est totalement à l'inverse de l'esprit de ce forum.
Je vais même jusqu'à dire que cela me dégoute profondément.

Ici l'information, l'aide est gratuite et DOIT ETRE destinée au plus grand nombre.
Je trouve révoltant que l'on vienne chercher de l'information et que l'on garde les réponses secrètes.

Cela devient du chacun pour soi immonde, je dis bien immonde.
J'avais 22 ans en 68 et plein d'espoir surtout que les Hommes respectent leurs congénères et ne tirent pas la couverture à soi.
Je n'ai pas changé et je suis toujours révolté par certaines attitudes
Si j'ai quelque espoir de vieillir un peu plus, c'est foutu, jamais je ne changerais.

Bonjour 68tjs,
Le fait d’échanger en privé n’empêche pas le partage. A l’inverse de ton opinion je trouve parfois les échanges sur les forums un peu trop verbeux et finissent par ne plus être compréhensibles.
En ce qui concerne le sujet abordé ici, je n’ai pas trouvé dans ton message d’informations qui ont fait avancer mon problème. Donc je confirme qu’un échange privé qui peut (et doit) être suivi d’une synthèse dans CE forum reste la meilleure solution. C’est une procédure que j’ai déjà eu l’occasion de suivre à plusieurs reprises en évitant la surcharge des échanges qui se multiplient inutilement.
De plus je trouve les termes utilisés bien excessifs dans forum qui doit rester cordial, comme tu sembles le souhaiter. Une simple expression modérée pour signaler l’intérêt que tu portes au sujet abordé et ton souhait d’y participer aurait été bien plus efficace et moins violent. L’âge ne donne pas tous les droits (sachant que j’ai un âge proche du tien).
Donc as-tu un intérêt ou une proposition quelconque pour faire avancer mon problème ?
Merci.
Cordialement (une formule de politesse ne coûte pas cher)

Bien d'accord avec @68tjs !

Le fait de passer par le forum permet à plein de personnes de progresser. 43 personnes sont passées par là, mais il n'y a que 5 posts.

Je suppose que si on te propose de passer en messages privés, c'est pour s'affranchir des remarques concernant les incorrections qu'il va se produire. Dans ce cas, il ne peut plus y avoir de point de vue différents et il faudra que tu acceptes sans broncher tout ce qu'on te diras.
Pose-toi cette question: pourquoi on te propose de passer en messages privés?

Bonsoir Vileroi ,
Je peux comprendre ton point de vue (mais pas la façon de le dire de 68tjs) mais si je dois rédiger le détail de tous mes essais ce topic sera vite indigeste.
Si vous souhaitez tout savoir, OK, je vais essayer de faire cette rédaction (il me faudra un peu de temps) mais je ne suis pas certain que cela intéressera grand monde.
Je suis en attente de votre retour.
Cordialement

Bonjour jcg95

Ce n'était pas le sens de ma réponse, je signalais simplement que le dit sujet s'était poursuivi en privé, pour ce qui nous concerne, pour le moment, ce n'est pas nécessaire.

Pour moi, ce n'est pas nécessaire, mon programme s'adapterai, sans modifications, à la gestion d'une plaque tournante.
Ma question est, si l'option moteur pas à pas est retenue, comment penses tu entraîner ta plaque.
Quel est l'écartement de ton réseau et quel est le diamètre de ta plaque tournante.

Cordialement
jpbbricole

Bonjour jpbbricole,
Mes réponses à tes questions :

  • Mon réseau est en N (1/160)

  • Ma plaque fait 20 cm

  • Pour ce qui est de l'entrainement depuis un moteur pas à pas j'ai fait plusieurs essais dont voici une synthèse :

    • Petit moteur 28BYJ-48 5V mais pas assez puissant pour entrainer le plateau avec la locomotive dessus
    • Puis moteur NEMA 17 de 9v ou 12 v
    • Premier essai avec courant d'entrainement sur un montage créé et généré en impression 3 D. Le réglage très compliqué car la courroie et très courte et la tension sur les axes est également très (trop) importante, donc abandon.
    • Deuxième essai avec un système d'engrenage avec un peu les mêmes soucis (tension sur les axes, fixation des roues sur l'axe du moteur) mais aussi un problème de dimension car la roue d'entrainement doit être petite et celle fixée au plateau trop grande pour parfaitement tenir dans mon ensemble.
    • J'ai aussi beaucoup de difficultés pour régler les positions exactes et fiables de mes rotations qui doivent correspondre exactement aux positions des voies d'entrée et de sortie.

Je suis alors passé au servomoteur en rotation continue (360 DS04-NFC) où l'axe du moteur correspondait précisément au centre de mon plateau, donc sans système d'entraînement ajouté. Comme j'avais des difficultés à régler les positions exactes, j'avais abandonné l'option.
Comme mon projet ne prévoyait que peu de voies de sortie (4) et que le plateau ne devait jamais faire plus de 180°, Je suis passé au servomoteur "normal" en oubliant le sg90 bien trop faible pour le travail à faire. J'ai alors opté pour un servomoteur plus puissant (AZDelivery MG995) mais là encore j'ai des soucis de précisions, car pour une même position d'arrêt demandée, celle-ci est légèrement différente selon le sens de rotation (objet original du topic en cours).
Je reviens donc au servomoteur 360 pour lequel j'ai poussé mes recherches un peu plus et qui me donnerai presque satisfaction pour la vitesse de rotation et la précision.
Pour le choix de la position demandée, j'ai essayé la télécommande qui fonctionnait pas mal, mais qui manquait de réaction parfois. Je suis maintenant sur les boutons pressoirs qui là encore me donneraient satisfaction si ce n'était un manque de réaction fiable.

Voilà j'en suis là actuellement et je continue mes tests. Je vous tiens au courant, pour ceux que cela intéresse.
Cordialement.
jcg95

Vrai en théorie, Faux dans la vie réelle.
Un certain nombre de membres sont intervenus sur le projet de pont tournant.
Soudainement, le demandeur a cessé de répondre.
Quelques mois plus tard, nous découvrons, par hasard, que ce projet s'est terminé en privé.
Aucun retour n'a été fait en direction du forum.
Ce forum est un forum de partage, il ne faut pas l'oublier et le but de mon intervention était de le rappeler. Mais comme ce n'est pas la première fois, je me suis senti obligé de ne pas faire dans la dentelle.

Parfaitement, et cela s'appliquait à ce projet.

Le politiquement correct qui nous vient des USA est pénible.
Ici, nous ne sommes pas dans un salon littéraire, je considère que nous sommes dans un labo de développement.

Quand c'est moi qui initie un nouveau sujet, je considère que j'entre dans le labo et je dis bonjour à ses occupants. Personne n'est obligé de me répondre, c'est bien à moi à donner envie aux autres de répondre.
Par contre, quand je réponds, je considère que je suis déjà dans le labo et que les salutations sont déjà faites.
C'est ma conception.

J'ai déjà expliqué le pourquoi de mon intervention.
Pour ton projet :

Dans une chaine de positionnement, les erreurs de positionnement s'additionnent.
Avant de parler composant, à combien évalues-tu le jeu mécanique de ta réalisation ?
As-tu procédé comme le faisait les fraiseurs sur métaux : toujours positionner en tournant le vernier dans le même sens : technique dite de "rattrapage de jeu" ?
Au besoin, on dépasse la position pour y revenir dans le bon sens.

Un servo moteur 360 n'est pas un servomoteur.
C'est un moteur classique auquel on a associé une commande électronique en vitesse basée sur les signaux des vrais servomoteurs. Il n'y a aucun asservissement en position. L'asservissement de position est à concevoir. Solution que je déconseille.

Un "vrai" servomoteur contient un asservissement.
Comme tout asservissement, il a des limites (jeu mécanique, erreur due au manque de gain, zone morte due au bruit de l'électronique interne, etc...).
Quand le produit est fini, on le prend comme il est ou on en change pour mieux, mais plus cher.

Moteur pas à pas.
Toujours le jeu mécanique à gérer surtout s'il faut ajouter une démultiplication.
Il faut aussi un dispositif qui permette une Raz (Remise A Zéro). S'il se produit un arrêt sur une position inconnue, sur coupure électrique par exemple, il faut pouvoir replacer le moteur sur une position connue.

C'est sur cette voie qu'était parti le projet qui a été "happé par un trou noir" et dont nous n'avons plus eu de nouvelles.
Tu auras peut-être plus de chance.

Bonne chance.

1 Like

Bonjour jcg95

Aurais-tu une photo de ton montage?
La courroie crantée entraîne la plaque sur son axe ou sur la périférie?
Combien pèse l'ensemble plaque, rail et locomotive, on pourrait envisager un entraînement direct avec micro-pas.
Où doit se trouver le moteur, si c'est possible à l'extérieur de la plaque, on pourrait transformer sa périphérie en roue dentée en y collant de la courroie crantée à l'envers et tu pourrais utiliser ce type de kit,
image

je t'indiquerait comment faire des courroies "à la demande".
L'avantage d'une grande démultiplication est la précision du positionnement. Dans mon programme l'arrêt du mouvement se fait toujours dans le même sens (voire 1:22) afin de compenser d'éventuels jeux.

A+
Cordialement
jpbbricole


Voici le montage dans l'état actuel. Tout est fait en bois découpé au laser ? Le boitier a pour vocation de s'insérer dans le plateau du réseau le moment venu. Je n'ai donc pas la possibilité d'externaliser le moteur. Le boitier est composé de 2 "étages" : dessous (invisible ici) le montage arduino et moteur, le dessus avec le plateau tournant.
Ici, le plateau est positionné et peut tourner.


Ici, la vue sous le plateau. Le A est un système en impression 3D qui permet de recevoir facilement, avec une marge de hauteur la liaison avec le plateau lui-même (ici coté femelle). Il permet de rendre le plateau amovible en cas de besoin. Le B est l'alimentation d'un système de "crochet" pour assurer la bonne position en face des voies. Explication à suivre.
Les traces sur le "sol" viennent des différents essais avec collage, décollage, etc... Les trous viennent aussi des essais de position des différents moteurs dont le NEMA17 excentré. Je n'ai plus le montage avec ce moteur et je n'en ai pas de photos.


Vue du dessous du plateau. Le A est le côté "mâle" du système de transmission de la rotation. Plus de détails possibles si demandés.
Le B est le système de translation du bras de positionnement et de blocage du plateau. Il y a des "plots" fixés sur la partie fixe du montage dans lesquels la fourche du bras vient s'emmancher à la fin de la rotation. Des roues sont positionnées aux 4 pôles du plateau, elles viennent se poser et rouler sur le "sol" du montage et assurer une bonne stabilité du plateau.

montage_dessous
Le moteur vient se fixer en dessous au centre du montage. Les trous sont des résidus des différents essais. Une reconstruction propre aux bonnes dimensions sera réalisée une fois tous les problèmes réglés.

Je dispose déjà du kit que tu proposes avec la courroie, les roues crantées et les tendeurs. Je reste évidemment intéressé par tes travaux et je ferai de nouvelles tentatives dans quelque temps avec une solution de ce type mais pour le moment je vais finaliser avec le servomoteur 360 qui me donne vraiment satisfaction. La solution avec une roue crantée sur l'extérieur du plateau avec le moteur directement associé à cette "roue" me semble une bonne piste que j'avais envisagée mais laissé tomber dans l'état actuel de mes essais.

Bonjour jc95

Avec ta fourchette de vérouillage, plus besoin de moteur pas à pas, un moteur CC et une mesure de position suffirait. Je développerai mon idée cet après-midi.

A+
Cordialement
jpbbricole

jpbbricole,
Je suis preneur de ta méthode pour faire des courroies à la bonne taille. Je vais faire des essais pas à pas dès cette après-midi. Par contre, les "roues" crantées pour cette technique sont de taille identique sur les deux axes. Comment faire pour jouer avec une roue normale sur le moteur et une plus grande sur le plateau afin de démultiplier la force de rotation, affiner la précision et ralentir la rotation. As-tu une idée ? Faire une roue plus grande avec la même taille de crans ???? Via impression 3D et aurais-tu un modèle ?

Cordialement
jcg95

En collant une courroie crantée sur un disque de la taille que tu veux pour avoir la bonne démultiplication par exemple.

Excellente idée je teste dans l’après-midi.
Merci

Bonjour jcg95

J'avais fait un descriptif ici, la colle que j'utilise, maintenant, est la Pattex Repair 100% qui reste souple.

Au vu de tes images du post #13 et de ta fourche de positionnement, ça serait possible de se passer de moteur pas à pas et de faire un positionnement "approximatif" qui serait finalisé par cette fourche. Ainsi, tu entraînerai ta plaque tournante au moyen de ton servo 360° muni d'une roue caoutchouc, entraînement direct sur la plaque, dessous ou de côté. Pour gérer le servo 360°, il y a la bibliothèque VarSpeedServo.h qui permet de régler la vitesse assez finement, tu pourrais même ralentir au vu de l'arrivée en position (et bien d'autres possibilités).
Sur le plateau, à l'axe, mettre un capteur de position comme le AS5600 qui est un encodeur de position 12 bits. Ce capteur garde sa position, donc il "sait" toujours où il est, même après extinction du système. Prendre le modèle livré avec l'aimant.
Quel est le jeux acceptable permis par la fourche de positionnement.

A+
Cordialement
jpbbricole

Re bonjour jpbbricole,
Actuellement, la position avant enfourchement doit être assez précise car l'évasement est limité. On peut améliorer le système en allant plus vers un triangle qu'une fourche, ainsi être plus large au niveau erreur.
Voici un petit montage photos pour te montrer tout cela :






La cale fixée à l'extérieur du plateau est ajustée à la fourche, mais mes essais m'ont démontré qu'il fallait que la position d'arrêt soit déjà très précise sinon le bout de la fourche presse sur la cale et tout le système est perturbé.
Je suis en train de réaliser un petit montage avec un pas à pas et une courroie. Je te montre ça dès que j'ai fini.
A+
jcg95

Avec ces photos, on voit qu'il n'y a pas vraiment de possibilité d'imposer par le doigt un positionnement précis qui aurait donner son sens à un montage servo+doigt. Il y a déjà le problème du guidage en translation qui va introduire un jeu, et le doigt va introduire une deuxième incertitude. Je crois que si on veut mettre un doigt d'arrêt, il faut que celui-ci (ou la fourche, au choix) soit monté sur ressort. Le servo ne servirait que pour retirer le doigt.

Deux grandes familles de solutions sont à choisir:
~ un servo et une fourche ou un doigt mais quasiment sans jeu. On n'a pas besoin d'initialiser la position à la mise sous tension, le servo donnant directement l'angle approximatif. Et le doigt fait l'ajustage. Il vaut mieux quand même avoir un servo à 4 fils car à la mise sous tension l'ensemble ira dans la position initiale avec la vitesse maximale. Il est peut être intéressant de prévoir de déconnecter l'alimentation du servo au départ si c'est un 3 fils, le temps de débloquer le doigt, et lors d'un positionnement avec le doigt pour que le servo ne force pas.
~ un pas à pas, mais qui nécessite une initialisation pour être dans une position connue à la mise sous tension. Il faut donc un capteur de fin de course sur une voie extérieure. Dans ce cas le doigt devient presque inutile.