arduino - arret des moteurs

recherche solution de silence

a marqué ce sujet comme résolu.

bonjour à tous.

je suis actuellement sur un projet animatronique (mouvements yeux gauche droite) pour un tournage et il est demandé entre autre que le système fasse le moins de bruit possible. ça a été galère a gérer mécaniquement mais j’y suis arrivé; le systeme utilise un potentiometre et un seul servo.

j’ai d’abord utilisé le programme classique (knob de mémoire) pour activer le servo via le potentiometre; mais le bruit electrique du servo créait trop de parasites sonores.

Un programmeur m’a proposé un programme qui arrête l’alimentation moteur dès non-utilisation. fantastique ! c’est ce qu’il me faut ! je n’ai pas le niveau pour comprendre son programme et je n’agis juste que sur les paramètres d’amplitude du servo. Seulement voila : ça fontcionne sur ce servo mais dès que j’utilise un autre servo (meme modele meme marque), le programme n’agit plus. là ça me laisse bouche bée. servo en question KST X08. j’ai testé sur un hitec 645 MG ça fonctionne.

voici le programme en question :

//void setup() 
{
  pinMode(2, OUTPUT);
  pinMode(A1, INPUT);
}

int v,n,b=0;

void loop() 
{
  v=0;
  for(n=0;n<32;n++) 
  {
    v+=analogRead(A1);
  }
  v=v>>5;
  v=map(v,0,1023,1050,1350);
  if (v!=b) {
    noInterrupts();
    digitalWrite(2, HIGH);
    delayMicroseconds(v);
    digitalWrite(2, LOW);
    interrupts();
    b=v;
  }

  delay(20);

}

Perso je n’y comprend pas grand chose, si quelqu’un peut m’expliquer pourquoi ce programme fonctionnerait sur un servo et pas sur son jumeau, je suis preneur.

merci d’avance. (mince je ne sais pas comment editer le programme pour qu’il soit lisible ici).

+0 -0

Bonjour,

Question bête : est-ce que tu as bien branché les fils sur les bons PIN ? Il faut que ce soit sur A1 pour l’entrée & sur le 2 pour la sortie. Ensuite l’entrée analogique doit détecter une variation pour déclencher l’interruption.

Je ne connais pas le mécanisme sous-jacent … le signal digitalWrite(2, HIGH); semble provoquer l’interruption, on peut imaginer qu’en augmentant le délai ça puisse aider -> remplacer la ligne delayMicroseconds(v); par delay(2);. A essayer. ;)

Au final, je penche plus pour un problème physique qu’un problème d’algorithme ; un matériel défectueux ou un mauvais montage.

+0 -0

Peux-tu ajouter la balise de code à ton message ? Pour qu’ils soient plus facilement compréhensible comme ceci :

```
//ton code
```
void setup() 
{
  pinMode(2, OUTPUT);
  pinMode(A1, INPUT);
}

int v,n,b=0;

void loop() 
{
  v=0;
  for(n=0;n<32;n++) 
  {
    v+=analogRead(A1);
  }
  v=v>>5;
  v=map(v,0,1023,1050,1350);
  if (v!=b) {
    noInterrupts();
    digitalWrite(2, HIGH);
    delayMicroseconds(v);
    digitalWrite(2, LOW);
    interrupts();
    b=v;
  }

  delay(20);

}
+0 -0

salut Yarflam; merci de ta réponse. en fait il ne peut y avoir de problème de pin puisque c’est le moteur que je débranche et que je remplace. Il m’avait parlé de particularité materielle mais là il s’agit du même moteur (marque, modèle) qui est changé.

je vais tester ta proposition.

test opéré : le servo se bloque et plus aucun mouvement.

merci

+0 -0

Peux-tu ajouter la balise de code à ton message ? Pour qu’ils soient plus facilement compréhensible comme ceci :

```
//ton code
```
void setup() 
{
  pinMode(2, OUTPUT);
  pinMode(A1, INPUT);
}

int v,n,b=0;

void loop() 
{
  v=0;
  for(n=0;n<32;n++) 
  {
    v+=analogRead(A1);
  }
  v=v>>5;
  v=map(v,0,1023,1050,1350);
  if (v!=b) {
    noInterrupts();
    digitalWrite(2, HIGH);
    delayMicroseconds(v);
    digitalWrite(2, LOW);
    interrupts();
    b=v;
  }

  delay(20);

}

A-312

je n’arrive pas à écrire le code comme il faudrait. désolé

Il faut que tu entoures ton code avec les ```, comme c’est fait sur les trois lignes citée par A-312.

Si j’ai bien compris, tes deux servo-moteurs sont des KST X08 et il n’y en a qu’un des deux qui fonctionne avec ton programme ? Tu es sûr qu’ils fonctionnent tous les deux, au moins ?

+0 -0

Il faut que tu entoures ton code avec les ```, comme c’est fait sur les trois lignes citée par A-312.

Si j’ai bien compris, tes deux servo-moteurs sont des KST X08 et il n’y en a qu’un des deux qui fonctionne avec ton programme ? Tu es sûr qu’ils fonctionnent tous les deux, au moins ?

Popiette

BOnjour. J’ai exactement 10 KST X08; ils fonctionnent tous sur ce programme. Un seul répond a ce que je cherchais : Coupure moture quand non utilisé; en gros plus d’alimentation dès que l’on arrete le potentiometre. J’ai testé cze programme sur d’autres servos (HITEC 685MG) et l’arret moteur se fait bien. je ne comprend pas pourquoi; mais il faut dire que je ne comprend pas non plus ce programme.

merci

Alors honnêtement … j’en sais rien du tout.

Voici le code commenté si ça peut t’aider :

void setup() 
{
  pinMode(2, OUTPUT); // PIN 2 sortie
  pinMode(A1, INPUT); // PIN A1 entrée analogique
}

int v, n, b=0; // déclaration des variables

void loop() // boucle principale, appel récurrent
{
  v=0; // remise à zéro de la variable v
  for(n=0; n < 32; n++) // boucle sur 32 octets récupéré depuis le capteur analogique (entrée A1)
  {
    v += analogRead(A1); // lecture de l'entrée analogique A1 & additionné à v
  }
  v = v>>5; // décalage de 5 bits vers la droite (c'est censé réduire l'entier)
  v = map(v,0,1023,1050,1350); // changement de grandeur, on passe v de [0;1023] à [1050;1350]
  if (v != b) { // si la donnée b stockée est différente de la nouvelle valeur
    noInterrupts(); // bloque les autres tâches de fond
    digitalWrite(2, HIGH); // envoie un signal vers le PIN 2
    delayMicroseconds(v); // Attendre v millisecondes (entre 1050 et 1350 ms)
    digitalWrite(2, LOW); // arrête le signal vers le PIN 2
    interrupts(); // relance les autres tâches de fond
    b = v; // enregistre la valeur actuelle (pour la tester de nouveau la prochaine fois)
  }
  delay(20); // Attendre 20s
}
+0 -0

Alors honnêtement … j’en sais rien du tout.

Voici le code commenté si ça peut t’aider :

void setup() 
{
  pinMode(2, OUTPUT); // PIN 2 sortie
  pinMode(A1, INPUT); // PIN A1 entrée analogique
}

int v, n, b=0; // déclaration des variables

void loop() // boucle principale, appel récurrent
{
  v=0; // remise à zéro de la variable v
  for(n=0; n < 32; n++) // boucle sur 32 octets récupéré depuis le capteur analogique (entrée A1)
  {
    v += analogRead(A1); // lecture de l'entrée analogique A1 & additionné à v
  }
  v = v>>5; // décalage de 5 bits vers la droite (c'est censé réduire l'entier)
  v = map(v,0,1023,1050,1350); // changement de grandeur, on passe v de [0;1023] à [1050;1350]
  if (v != b) { // si la donnée b stockée est différente de la nouvelle valeur
    noInterrupts(); // bloque les autres tâches de fond
    digitalWrite(2, HIGH); // envoie un signal vers le PIN 2
    delayMicroseconds(v); // Attendre v millisecondes (entre 1050 et 1350 ms)
    digitalWrite(2, LOW); // arrête le signal vers le PIN 2
    interrupts(); // relance les autres tâches de fond
    b = v; // enregistre la valeur actuelle (pour la tester de nouveau la prochaine fois)
  }
  delay(20); // Attendre 20s
}

Yarflam

Waw ! merci beaucoup; ça me fera ma leçon de la semaine.

Les commentaires indiquent des mauvaises unités: ce sont des µs et des ms, pas des ms et des secondes.

Pour détailler un peu les explications de loop, elle commence par lire 32 fois l’entrée analogique, additionner les 32 lectures, et diviser le résultat par 32 (décaler à droite de 5 bits et diviser par 32 a le même effet). Le résultat est la moyenne des 32 lectures. Le but est de réduire le bruit sur la lecture de la position du potentiomètre. Quand on lit une entrée analogique, le dernier chiffre est rarement stable, mais en faisant la moyenne de plusieurs valeurs, on obtient une valeur plus stable, qui va éviter de rallumer le moteur trop souvent.

Le map sert à convertir la valeur. Sur le potentiomètre, on lit de 0 à 1023, mais le servo se commande avec une impulsion électrique entre 1050 et 1350µs (normalement c’est entre 1000 et 2000µs, j’imagine qu’on n’utilise pas tout le débattement du servo ici, ou alors le servo n’est pas standard). map fait une conversion linéraire d’un intervalle vers l’autre.

Ensuite il y a une comparaison avec la valeur précédente. Si la valeur est la même, on ne fait rien, c’est ce qui permet que le moteur reste éteint et ne fasse pas de bruit. C’est aussi pour que ce test soit vrai qu’on a fait une moyenne de 32 valeurs précédemment, pour obtenir la même valeur quand on ne bouge pas le potentiomètre.

Quant au code de la boucle, il sert à envoyer une impulsion de v µs. les fonction noInterrupts et interrupts permettent de garantir que rien ne vient fausser le comptage du temps par le microcontrôleur pendant qu’il génère l’impulsion.

Quant au delay(20), c’est une attente de 20ms, qui est le temps à attendre entre deux impulsions de commande pour le servo. C’est le protocole de commande des servos, ça ne s’invente pas.

En résumé, toutes les 20ms, si la consigne a changé, on génère une nouvelle impulsion de contrôle du servo, et sinon on ne fait rien (et du coup le servo ne fait rien et ne fait pas de bruit)

Les commentaires indiquent des mauvaises unités: ce sont des µs et des ms, pas des ms et des secondes.

Ah oui, j’avais oublié que delay utilisait des millisecondes et j’ai ripé sur delayMicroseconds (c’est rare de calculer en 10^-6) que j’ai même pas pris la peine de vérifier la doc. :p mea culpa

Ton commentaire est parfait, il apporte toutes les infos qui me manquait, merci pour mozzZ (je n’ai jamais utilisé de servo moteur ni traité d’entrée analogique).

Petite question : pourquoi exactement 32 fois ? Est-ce un standard ? ou juste arbitraire.

+0 -0

C’est totalement arbitraire. Je pense même que l’auteur a du tester 8, 16, 32, 64, et prendre la valeur la plus faible qui donne un système stable. Plus on prend de valeur, plus le système met de temps à réagir, moins on en prend, moins il est stable (et plus il a tendance à rallumer le servo inutilement). Le seul choix qui ne soit pas arbitraire, c’est de prendre une puissance de 2. Divisier par une puissance de 2 en binaire, c’est aussi facile que de diviser par une puissance de 10 en décimal: il suffit de retirer les chiffres de droite (vu qu’on ne garde pas ce qui est après la virgule). C’est une opération qui prend beaucoup moins de temps au processeur qu’une division. Ici, ce n’est pas très important, vu qu’on attends de toutes façons 20ms à la fin, mais c’est habituel dans les systèmes embarqués.

C’est totalement arbitraire. Je pense même que l’auteur a du tester 8, 16, 32, 64, et prendre la valeur la plus faible qui donne un système stable. Plus on prend de valeur, plus le système met de temps à réagir, moins on en prend, moins il est stable (et plus il a tendance à rallumer le servo inutilement). Le seul choix qui ne soit pas arbitraire, c’est de prendre une puissance de 2. Divisier par une puissance de 2 en binaire, c’est aussi facile que de diviser par une puissance de 10 en décimal: il suffit de retirer les chiffres de droite (vu qu’on ne garde pas ce qui est après la virgule). C’est une opération qui prend beaucoup moins de temps au processeur qu’une division. Ici, ce n’est pas très important, vu qu’on attends de toutes façons 20ms à la fin, mais c’est habituel dans les systèmes embarqués.

Jacen

Merci Jacen; tes explications de LOOP sont conformes a ce que m’a expliqué le programmeur (meme je n’y comprend pas le quart).

Pour l’impulsion électrique c’est effectivement pour limiter le débattement du servo.

Pour la valeur 32 effectivement il a fait plusieurs tests en 8, 16, 32, 64, . bien vu.

Du coup je viens de penser à quelquechose. En fait ce servo, dont le programme agit bien, est celui qui a servi pour tous les prototypes que j’ai fait (8 au total) avant d’être remplacé par les nouveaux. Se pourrrait il qu’une usure soit à l’origine de la difference de comportement entre les servos neufs et celui ci ? Dès que possible, je vais tenter de modifier ces valeurs 8, 16, 32, 64, pour les servos neufs pour voir. Par contre, comme je l’ai dit precedement ce programme fonction aussi (arret des moteurs dès non utilisation) sur les servos hitec 685MG. quel mystere ! merci à tous en tout cas.

Le nombre d’itérations sur l’acquisition n’a aucun lien avec le servo, c’est un filtrage de la lecture du potentiomètre.

Est ce que tu testes bien les nouveaux servos sur le même circuit, en débranchant juste le servo pour brancher le nouveau sans modifier le reste du circuit ? Est ce que tu as essayé les servos sans les accoupler au reste de la mécanique ? Est ce que tu as essayé de les faire fonctionner avec "le programme classique" que tu avais utilisé précédemment ?

Chaque question est importante, elles visent à vérifier:

  • Que le problème ne vient pas d’une autre partie du circuit mal répliquée
  • Que le bon fonctionnement du servo n’est pas masqué par un accouplement différent
  • Que les servos sont fonctionnels et que le problème ne survient qu’avec ce programme
+0 -0

Le nombre d’itérations sur l’acquisition n’a aucun lien avec le servo, c’est un filtrage de la lecture du potentiomètre.

Est ce que tu testes bien les nouveaux servos sur le même circuit, en débranchant juste le servo pour brancher le nouveau sans modifier le reste du circuit ? Est ce que tu as essayé les servos sans les accoupler au reste de la mécanique ? Est ce que tu as essayé de les faire fonctionner avec "le programme classique" que tu avais utilisé précédemment ?

Chaque question est importante, elles visent à vérifier:

  • Que le problème ne vient pas d’une autre partie du circuit mal répliquée
  • Que le bon fonctionnement du servo n’est pas masqué par un accouplement différent
  • Que les servos sont fonctionnels et que le problème ne survient qu’avec ce programme
Jacen

la reponse est oui a toutes tes questions; c’est bien ce qui est étrange. la seule difference existante est que le servo qui "fonctionne" est celui qui a été le plus utilisé (le plus usé donc moins précis ?).

le mystere demeure a cause des hitec qui eux répondent bien comme le servo X08.

merci

Tu dis donc que les nouveaux servos fonctionnent avec "le programme classique" mais pas celui ci. Je suppose du coup que, même si la référence n’a pas changé, les nouveaux servos n’ont pas le même contrôleur. Ce genre de changements arrive sur de l’électronique consumer, pour faire des réductions de coût. Je te propose de tester le programme suivant, qui fait quasiment la même chose que le précédent, sauf qu’au lieu d’envoyer une impulsion de contrôle quand on touche le potentiomètre, il en envoie 5, étalées sur 100ms. Je suppose que le nouveau contrôleur se met en veille quand il n’a pas de signal de contrôle, et qu’il se réveille à la première impulsion quand le signal revient, ce qui ferait qu’il ne réagirait pas à une seule impulsion.

//void setup() 
{
  pinMode(2, OUTPUT);
  pinMode(A1, INPUT);
}

int v,n,b,iter=0;

void loop() 
{
  v=0;
  for(n=0;n<32;n++) 
  {
    v+=analogRead(A1);
  }
  v=v>>5;
  v=map(v,0,1023,1050,1350);
  if (v!=b) {
    iter=5;
  }

  if (iter>0) {
    noInterrupts();
    digitalWrite(2, HIGH);
    delayMicroseconds(v);
    digitalWrite(2, LOW);
    interrupts();
    b=v;
    iter--;
  }

  delay(19);

}
+0 -0

Tu dis donc que les nouveaux servos fonctionnent avec "le programme classique" mais pas celui ci. Je suppose du coup que, même si la référence n’a pas changé, les nouveaux servos n’ont pas le même contrôleur. Ce genre de changements arrive sur de l’électronique consumer, pour faire des réductions de coût. Je te propose de tester le programme suivant, qui fait quasiment la même chose que le précédent, sauf qu’au lieu d’envoyer une impulsion de contrôle quand on touche le potentiomètre, il en envoie 5, étalées sur 100ms. Je suppose que le nouveau contrôleur se met en veille quand il n’a pas de signal de contrôle, et qu’il se réveille à la première impulsion quand le signal revient, ce qui ferait qu’il ne réagirait pas à une seule impulsion.

//void setup() 
{
  pinMode(2, OUTPUT);
  pinMode(A1, INPUT);
}

int v,n,b,iter=0;

void loop() 
{
  v=0;
  for(n=0;n<32;n++) 
  {
    v+=analogRead(A1);
  }
  v=v>>5;
  v=map(v,0,1023,1050,1350);
  if (v!=b) {
    iter=5;
  }

  if (iter>0) {
    noInterrupts();
    digitalWrite(2, HIGH);
    delayMicroseconds(v);
    digitalWrite(2, LOW);
    interrupts();
    b=v;
    iter--;
  }

  delay(19);

}

Jacen

je testerai la semaine prochaine ce programme. pour info les 10 servos KSTX08 ont tous été achetés ensemble;

Merci Jacen;

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte