Un servo moteur , permet de contrôler une position en fonction d’une consigne , très pratique en robotique et dans d’autres projets.

Servo vient du mot asservissement

Caractèristiques du FS90

Le signal de commande (fil orange) est de fréquence 50 Hz. T=20ms

l’impusion va donner la consigne de position du Servo Moteur (état haut)

const int FS90_MIN = 500 ou 0.5 ms; # angle 0 ° ou 0 radian
const int FS90_MAX = 2400 ou 2.4ms ; # angle 180° ou pi radian

Le fil rouge est l’alimentation en 5V à 7V max.

Le fil marron ou noir , le GND , le 0 , la masse !

Le fil orange la consigne en PWM du servo-moteur

la consigne ici est envoyé sur le fil orange c’est une PWM , impulsion de 500 à 2400 micro seconde

Vision réelle d’un Servo moteur type FS90
Vision par Gemini du servo moteur

Durées d’impulsion en MICROSECONDES (µs) :

« Le FS90 utilise un circuit intégré spécialisé et dédié, souvent un NE544 ou un équivalent, qui agit comme le cerveau analogique du servo. Ce n’est pas un microcontrôleur programmable, mais une puce câblée pour exécuter une seule tâche : la commande en boucle fermée d’un moteur pour atteindre une position définie par un signal PWM. »

Angle 0 degré: T=500us

Fréquence 50Hz (T=20ms), 180 degrés (2400uS)

Commutation de 0 degré à 180 degré :


Solution en C , la plus simple

/***************************************************/
/* Code pour maîtriser un SERVO_MOTEUR FS90        */
/* en C simple , signal PWM réalisé dans le loop() */
/***************************************************/
#define signal 10
#define imp 500
/* 0.5 <  imp  <2,4 */
/* 500 uS à 24000 uS */


/* tempo risation en microsecond pouvant etre supèrieur a 1600 ms */
void tempo_ms(int temps)
{
  if (temps < 1600 )
  {
    delayMicroseconds (temps); /* fini */
  }
  else
  {
      do
      {
       delayMicroseconds(1600);
       temps=temps-1600;
      }
      while (temps > 1600);
      delayMicroseconds(temps);
  }
}
/* mise en sortie la broche de commande du servo moteur */
void setup() 
{
  pinMode(signal, OUTPUT);
}


/* boucle de commande du SERVO_Moteur fréquence 50Hz */
void loop() 
{  /* boucle de 20ms */
  digitalWrite(signal, HIGH);
  tempo_ms(imp);  
  digitalWrite(signal, LOW);
  tempo_ms(20000-imp);      /* 20ms -imp */
}

Donner l’organigramme et le PL de ce code

Expliquer clairement comment fonctionne ce code par rapport au servo moteur

Relever avec la sonde numérique le signal de la broche 10 de l’arduino

Donner la fréquance et le Rc

Donner un code donnant un angle de 0

Tester et relever avec la sonde logique la fréquence et le Rc

Donner un code donnant un angle de moitié.

Tester et relever avec la sonde logique la fréquence et le Rc

Donner un code donnant un angle Maximum

Tester et relever avec la sonde logique la fréquence et le Rc

Réaliser un code « métronome » qui bascule le servo moteur de l’angle 0 à l’angle 180° et de 180° à 0 toute les 2 secondes !

Solution
/***************************************************/
/* Code pour maîtriser un SERVO_MOTEUR FS90        */
/* en C simple , signal PWM réalisé dans le loop() */
/***************************************************/
#define signal 10
#define imp 500+950+950
#define imp0 500
#define imp180 2400
#define temps 100
/* 500  minimum 500+950 milieu et 500+950+950 (2400) MAX*/
int cpt;
/* temporisation en microsecond pouvant etre supèrieur a 1600 ms */
void tempo_ms(int tmp)
{
  if (tmp < 1600 )
  {
    delayMicroseconds (tmp); /* fini */
  }
  else
  {
      do
      {
       delayMicroseconds(1600);
       tmp=tmp-1600;
      }
      while (tmp > 1600);
      delayMicroseconds(tmp);
  }
}

/* mise en sortie la broche de commande du servo moteur */
void setup() 
{
  pinMode(signal, OUTPUT);
  cpt=0;
}


/* boucle de commande du SERVO_Moteur fréquence 50Hz */
void loop() 
{
if (cpt<temps)
{  
  digitalWrite(signal, HIGH);
  tempo_ms(imp0);  
  digitalWrite(signal, LOW);
  tempo_ms(20000-imp0);
}
else
{  
  digitalWrite(signal, HIGH);
  tempo_ms(imp180);  
  digitalWrite(signal, LOW);
  tempo_ms(20000-imp180);
}
cpt++;
if (cpt>(2*temps))
  {
    cpt=0;
  }      
}

Pour les plus curieux on va programmer le TWI , le timer de l’atmega328p

C’est hors programme ! mais c’est comme cela que ca fonctionne. On va utiliser les registres internes du timer …

on note que Timer (TWI) va générer le signal pwm de commande , et le processeur de l’atmega328p est totalement disponible (loop() vide)


// Configuration du servo FS90 avec Timer1 sur la broche 10
// Signal : 50Hz (période 20ms)
// Impulsion : 500µs à 2500µs (position 0° à 180°)

volatile uint16_t pulseWidth = 1500; // Position initiale : 1500µs (90°)

void setup() {
  // Configurer la broche 10 (OC1B) comme sortie
  pinMode(10, OUTPUT);
  
  // Désactiver les interruptions globales pendant la configuration
  cli();
  
  // Configurer Timer1 en mode Fast PWM 8-bit (mode 14)
  // WGM13:1, WGM12:1, WGM11:1, WGM10:0 -> Mode 14 (Fast PWM, TOP = ICR1)
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A |= (1 << WGM11);              // Mode 14: Fast PWM
  TCCR1B |= (1 << WGM13) | (1 << WGM12); // TOP = ICR1
  
  // Configurer la sortie OC1B (broche 10) en mode non-inversé
  TCCR1A |= (1 << COM1B1);  // Clear OC1B on compare match, set at BOTTOM
  
  // Définir TOP pour une fréquence de 50Hz
  // Fréquence = 16MHz / (prescaler * (1 + ICR1))
  // Pour 50Hz : 16MHz / (prescaler * (1 + ICR1)) = 50
  // Avec prescaler = 8 : 1 + ICR1 = 16000000 / (8 * 50) = 40000
  // Donc ICR1 = 39999
  ICR1 = 39999;  // TOP pour 50Hz avec prescaler 8
  
  // Définir le prescaler à 8
  TCCR1B |= (1 << CS11);  // CS11=1, CS10=0 -> Prescaler 8
  
  // Définir la largeur d'impulsion initiale
  // OCR1B = (pulseWidth / 20000) * (ICR1 + 1)
  // Pour 500µs : OCR1B = (500/20000) * 40000 = 1000
  // Pour 1500µs : OCR1B = (1500/20000) * 40000 = 3000
  // Pour 2500µs : OCR1B = (2500/20000) * 40000 = 5000
  updatePulseWidth(pulseWidth);
  
  // Réactiver les interruptions
  sei();
}

// Fonction pour mettre à jour la position du servo
void setServoPosition(uint16_t microseconds) {
  // Limiter la valeur entre 500µs et 2500µs
  if (microseconds < 500) microseconds = 500;
  if (microseconds > 2500) microseconds = 2500;
  
  pulseWidth = microseconds;
  updatePulseWidth(pulseWidth);
}

// Mettre à jour OCR1B avec la nouvelle valeur
void updatePulseWidth(uint16_t microseconds) {
  // Calculer OCR1B en fonction de la largeur d'impulsion souhaitée
  // OCR1B = (microseconds / 20000) * (ICR1 + 1)
  uint16_t ocrValue = (uint32_t)microseconds * (ICR1 + 1) / 20000;
  OCR1B = ocrValue;
}

void loop() {
  // Le loop ne fait rien comme demandé
  // Vous pouvez éventuellement ajouter un délai pour économiser l'énergie
  delay(10);
}

C++ et objet

Code avec un Timer (Circuit intégré dans le Microcontrôleur TWI sur l’atmega328p) et nous allons découvrir l’objet en C++

Et la on va utiliser le C++ (car oui le compilateur pour arduino est g++), car l’objet Servo est introduit ! (ca utilise les registres du timer comme dans l’exemple précédent) mais c’est caché dans la classe servo (plus facile à faire ,car quelqu’un à codé pour vous)

Dans la librairie Servo.h

Sachant que cet objet n’est utilisable que tu les broches possédant un TILDA ~ car si on regarde la documentation de l’ATMEGA328P seul ces broches sont connectable sur un Timer capable de gérer les Temps sans prendre de ressource au microprocesseur du microcontrôleur.

broche à utiliser pour la PWM

~3  ~5  ~6  ~9  ~10  ~11

L’objet Servo() et oui la on va faire du C++ et utiliser un objet et découvrir ce qu’est un objet !

Fréquence de 50Hz par et on règle la valeur min et max de l’impulsion à 1, le premier paramètre est la PIN utilisée.

#include <Servo.h>

Servo monServo;  /* Créer un objet servo , instanciation de l'objet , appel du constructeur */

void setup() 
{
  monServo.attach(9, 500, 2400);  /* initialisation de l'objet */
  // Positionner à 0° (500µs)
  monServo.writeMicroseconds(500);
  
  delay(1000);  /* Attendre 1 seconde pour la stabilisation */
}

void loop() 
{
  /* Le servo reste à 0°
     et le processeur ne fait rien , il est tout pour vous dans le loop()
     Pas besoin de répéter l'instruction
     le signal PWM est gérer automatiquement par l'objet monServo qui a programmé un circuit dédié Timer (TWI)
   */
}

Maintenant on va utiliser la méthode write qui permet de transmettre l’angle de consigne du servo-moteur

#include <Servo.h>

Servo monServo;  /* Créer un objet servo , instanciation de l'objet , appel du constructeur */
                              /* Le constructeur par défaut est appelé automatiquement */
void setup() 
{
  monServo.attach(9, 500, 2400);  /* initialisation de l'objet  le premier paramètre est obligatoire (la broche) */
  // Positionner à 0° (500µs)
  monServo.write(0);
  
  delay(1000);  /* Attendre 1 seconde pour la stabilisation et retour à zero*/
}

void loop() 
{
int angle;

for (angle=0;angle<180;angle++)
    {
    monServo.write(angle);
    delay(10);
    }
delay(1000);
monServo.write(0);
delay(1000);
}
Que fais ce code ?

Donner un code utilisant la librairie servo.h , qui réalise le métronome de 2 secondes. comme dans l’exemple en C simple !

Donner les avantages