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


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
