Ceci est une ancienne révision du document !
Table des matières
Objectifs et organisation des séances
Cette de ces deux séances est d'étudier un servomoteur de façon ludique. Cette étude sera faite à travers une maquette de moteur à courant continu réductée asservie par un Arduino. Les séances seront divisées en trois parties :
- Partie 1 - Présentation générale de la maquette et son environnement
- Partie 2 - Contrôle du moteur en vitesse, en sens et en position
- Partie 3 - Consommation électrique du moteur
Cette page expliquera les différentes parties et donnera des liens utiles aux séances. Pour suivre ses séances, les stagiaires doivent avoir fini le cours d'initiation à la programmation et au shield E/S donné par M. Vandeportaele
Partie 1 - Présentation générale de la maquette
Contexte - le servomoteur
Un servomoteur …
Présenter le servomoteur et expliquer comment il se pilote: https://www.tutorialspoint.com/arduino/arduino_servo_motor.htm
Dire qu'on en construit un sur la base d'un moteur DC réducté avec asservissement numérique.
Schéma-blocs de la maquette à étudier
La maquette étudiée lors de ses deux séances peut être résumée dans le schémas-bloc ci-dessous :
Inclure une image avec les blocs
Décrire les blocs
Liste des composants
La maquette étudie lors de ces deux séances est composée de :
- Une carte Aduino Uno (lien arduino)
- Un moteur à courant continu réducté
- Deux potentiomètres
- Des pièces imprimées en 3D pour coupler le potentiomètre au moteur
- Une aiguille imprimée en 3D
Vue d'ensemble de la maquette
Mettre une image qui montre chaque composant
Les librairies nécessaires pour piloter la maquette
Pendant les séances, un certain nombre de libraries spécialisés seront nécessaires à l'étude de le maquette.
- Librairie du shield de pilotage du moteur: https://learn.adafruit.com/adafruit-motor-shield/library-install
- Librairie de lecture des données à l'entrée analogique d'Arduino : https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
- Référence générale des librairies d'Arduino : https://www.arduino.cc/reference/fr/
Partie 2 - Contrôle du moteur en vitesse, en sens et en position
Contrôle de la vitesse du moteur
Décrire en pas à pas :
- L'assemblage mécanique (pas de potentiomètre de position)
- Quelques principes de code à faire pour étudier la vitesse
- Des idées libres d'étude de la vitesse
- Un contrôle par le potentiomètre de signal
- Un contrôle par les entrées de la carte E/S
- Une vidéo de fonctionnement
Contrôle du sens de rotation du moteur
Décrire en pas à pas :
- L'assemblage mécanique (pas de potentiomètre de position)
- Quelques principes de code à faire pour étudier le sens
- Des idées libres d'étude du sens
- Un contrôle par les entrées de la carte E/S
- Une vidéo de fonctionnement
Contrôle de la position angulaire du moteur
Décrire en pas à pas :
- L'assemblage mécanique (avec de potentiomètre de position)
- Quelques principes de code à faire pour étudier le sens
- Des idées libres d'étude de la position
- Un contrôle par le potentiomètre de signal
- Un contrôle par les entrées de la carte E/S
- Un contrôle automatique par génération de consigne par l'Arduino
- Une vidéo de fonctionnement
Partie 3 - Consommation électrique du moteur
La consommation électrique
Consommation à vide
Décrire en pas à pas :
- L'assemblage mécanique (avec de potentiomètre de position)
- Quelques principes de code à faire pour étudier la consommation
- Des idées libres d'étude de la consommation
- Un contrôle par le potentiomètre de signal
- Un contrôle par les entrées de la carte E/S
- Un contrôle automatique par génération de consigne par l'Arduino
- Une vidéo de fonctionnement
Consommation avec une charge mécanique légère
Décrire en pas à pas :
- L'assemblage mécanique (ficelle et petit poids)
- Quelques principes de code à faire pour étudier la consommation
- Des idées libres d'étude de la consommation
- Un contrôle par le potentiomètre de signal
- Un contrôle par les entrées de la carte E/S
- Un contrôle automatique par génération de consigne par l'Arduino
- Une vidéo de fonctionnement
Consommation avec une charge mécanique forte
Décrire en pas à pas :
- L'assemblage mécanique (ficelle et gros poids)
- Quelques principes de code à faire pour étudier la consommation
- Des idées libres d'étude de la consommation
- Un contrôle par le potentiomètre de signal
- Un contrôle par les entrées de la carte E/S
- Un contrôle automatique par génération de consigne par l'Arduino
- Une vidéo de fonctionnement
Ancienne version à intégrer
Vidéo de démonstration de la maquette
vidéo de la manip en fonctionnement: https://www.youtube.com/watch?v=3goxHKO2iuE
Controle du moteur en vitesse et en sens
Controle du moteur en position
Installation de la librarie pour le shield moteur
Schéma du shield
Asservissement PID
Mettre ici des liens sur les fonctions de librairies Arduino à utiliser
CODE DE TEST Bertrand
- motor_shield.ino
//B. Vandeportaele 09/2020 //done: gestion du temps pour que l'asservissement ait des paramètres fixes/ contenu du programme #include <AFMotor.h> //Servo myservo; #include <Wire.h> //adresses codées sur 7bits #define SLAVE_ADDR_8574_A 0x38+6 #define SLAVE_ADDR_8574_B 0x38+7 //AF_DCMotor motor(3,MOTOR34_1KHZ);//, MOTOR12_8KHZ); AF_DCMotor motor(1,MOTOR12_1KHZ);//, MOTOR12_8KHZ); int led = 13; //numéro de la broche Arduino pilotant la LED sur le shield PERIPH ////////////////////////////////////////// char readPort8574(char addr, char * ptr_value) /*addr, l'adresse du PCF8574 ptr_value, pointeur pour renvoyer la valeur lue sur le port retourne -1 si échec 0 sinon*/ { Wire.requestFrom((byte)addr, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique if (Wire.available()==1) //si l'octet est disponible { (* ptr_value) = Wire.read(); // lire l'octet return 0; } else { (* ptr_value) =0; //valeur par défaut si le composant n'a pas acquité return -1; } } ////////////////////////////////////////// char writePort8574(char addr, char value) /*addr, l'adresse du PCF8574 value, la valeur à écrire sur le port retourne -1 si échec 0 sinon */ { Wire.beginTransmission(addr);//démarre la transmission avec l'adresse du pérpiphérique Wire.write((byte)value); //envoie la donnée if (Wire.endTransmission()==0) //stoppe la transmission return 0; else return -1; } ////////////////////////////////////////// #define TAB_SIZE 10 int16_t erreur_tab[TAB_SIZE]; uint8_t ind_ecr_erreur_tab=0; int16_t integrale_erreur=0; int16_t derivee_erreur=0; void update_tab_erreur(int16_t new_erreur) { //calcul intégrale integrale_erreur=integrale_erreur-erreur_tab[ind_ecr_erreur_tab]; integrale_erreur=integrale_erreur+new_erreur; //calcul dérivée uint8_t ind_lec_erreur_tab=ind_ecr_erreur_tab+5; if (ind_lec_erreur_tab>=TAB_SIZE ) //gestion modulo ind_lec_erreur_tab-=TAB_SIZE; derivee_erreur=new_erreur-erreur_tab[ind_lec_erreur_tab]; //maj tableau erreur_tab[ind_ecr_erreur_tab]=new_erreur; ind_ecr_erreur_tab++; if (ind_ecr_erreur_tab>=TAB_SIZE) ind_ecr_erreur_tab=0; } ////////////////////////////////////////// void setup() { // myservo.attach(9); // initialize the digital pin as an output. pinMode(led, OUTPUT); Serial.begin(115200); // start serial port at 9600 bps: // Serial.print("Bonjour"); Wire.begin(); // joindre le bus i2c en tant que maître writePort8574( SLAVE_ADDR_8574_B , 0xff); //configure le composant B en entrée writePort8574(SLAVE_ADDR_8574_A,~0); //eteind les leds for (int i=0;i<TAB_SIZE;i++) erreur_tab[i]=0; } //unité en milliseconde uint32_t cadence_it=3; uint32_t time_next_it=0; void loop() { if (millis()>=time_next_it) { time_next_it=time_next_it+cadence_it; controleur() ; //test si la cadence peut etre tenue if (millis()>=time_next_it) writePort8574(SLAVE_ADDR_8574_A,~0xFF); } } void controleur() { /* digitalWrite(led, HIGH); // turn the LED off by making the voltage LOW delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW delay(1000); */ //Serial.write('X'); // delay(100); //motor.setSpeed(255); /*delay(1000); motor.run(BACKWARD); delay(1000); motor.run(RELEASE); delay(1000); */ static uint8_t vitesse=100; static double t=0; t=t+0.01; //vitesse+=155+(100*sin(t)); //Serial.println(vitesse); vitesse=vitesse+1; if (vitesse==255) vitesse=100; byte port_in; readPort8574(SLAVE_ADDR_8574_B,(char*)&port_in); //writePort8574(SLAVE_ADDR_8574_A,~port_in); int16_t sens; uint16_t consigne_position; if ((port_in&1)!=0) { //lecture consigne sur potentiomètre consigne_position= analogRead(A0); }else{ //génération échelons périodiques unsigned long time; time = millis(); if(((time/1000)%2)==0) consigne_position=512-250; else consigne_position=512+250; } uint16_t position= analogRead(A1); int16_t erreur=position-consigne_position; update_tab_erreur(erreur); /* //type commande toute simple en proportionnel avec valeur min pour vaincre les frottements int16_t commande_min=60; //pour vaincre les frottements int16_t commande=abs(erreur)+commande_min; int16_t commande_max=250; if (commande>commande_max) commande=commande_max; */ int16_t Kd=10; //de 0 à 50 int16_t Ki=2; int16_t Kp=1; //erreur=erreur+4*derivee_erreur+integrale_erreur/8; if ((port_in&2)!=0) { erreur=erreur*Kp; } if ((port_in&4)!=0) { erreur+=Kd*derivee_erreur; //quand l'erreur diminue, ce terme est négatif et permet d'éviter le dépassement } if ((port_in&8)!=0) { erreur+=(Ki*integrale_erreur)/TAB_SIZE; } int16_t commande=abs(erreur); int16_t commande_max=250; if (commande>commande_max) commande=commande_max; if (abs(erreur)<3) { motor.run(RELEASE); motor.setSpeed(0); sens=0; } else if (erreur<0) { motor.run(FORWARD); motor.setSpeed(commande); sens=-1; } else { motor.run(BACKWARD); motor.setSpeed(commande); sens=1; } /* Serial.print("consigne_position: "); Serial.print(consigne_position,DEC); Serial.print(" position: "); Serial.print(position,DEC); Serial.print(" erreur: "); Serial.print(erreur,DEC); Serial.print(" commande: "); Serial.print(commande,DEC); Serial.print(" sens: "); Serial.print(sens,DEC); Serial.println(""); */ Serial.print(consigne_position,DEC); Serial.print("\t"); Serial.print(position,DEC); Serial.print("\t"); Serial.print(erreur,DEC); Serial.print("\t"); Serial.print(0,DEC); Serial.print("\t"); Serial.print(1024,DEC); Serial.print("\t"); /*Serial.print(erreur,DEC); Serial.print("\t"); Serial.print(commande,DEC); Serial.print("\t"); Serial.print(sens,DEC); */ Serial.println(""); //delay(10); /* motor.run(BACKWARD); motor.setSpeed(120); /* uint16_t adc= analogRead(A0); if (adc>=512) { if (adc>1023) adc=1022; vitesse=(adc-512)/2; motor.run(FORWARD); motor.setSpeed(vitesse); } else { if (adc<2) adc=2; vitesse=(512-adc)/2; motor.run(BACKWARD); motor.setSpeed(vitesse); } /* vitesse=analogRead(A0)/4; motor.run(FORWARD); motor.setSpeed(vitesse); Serial.println(vitesse); */ /* char val; if (readPort8574(SLAVE_ADDR_8574_B,&val)==0) { Serial.print("lecture 8574 OK, "); if (writePort8574(SLAVE_ADDR_8574_A,val)==0) Serial.println("ecriture 8574 OK"); else Serial.println("ecriture 8574 NOK"); } else Serial.println("lecture 8574 NOK,"); */ //writePort8574(SLAVE_ADDR_8574_A,~vitesse); }
Modèles des pièces 3D
- connecteur_moteur_potar_2.scad
//B. Vandeportaele 09/2020 //jeu=0.5; //pour connecteur jeu=0.3; //pour chape ///////////////////////////// module tige_biseau(){ difference(){ cylinder(h=20,d=5.5+jeu,$fn=120); //3.8mm en elevant les 2 biseaux 5.5-2*biseau=3.8=> biseau=0.85 for (i=[0:1]){ //2 biseaux echo(i); rotate([0,0,i*180]) translate([((5.5/2)-0.85)+jeu/2,-5,-1]) cube([10,10,25]); } } } ///////////////////////////// module tige_biseau2(){ difference(){ cylinder(h=20,d=6+jeu,$fn=120); //4.5mm en elevant le biseau translate([1.5+jeu/2,-5,-1]) cube([10,10,25]); } } ///////////////////////////// module connecteur(){ difference(){ cylinder(h=20,d=13,$fn=120); translate([0,0,-10]) tige_biseau2(); //#cylinder(h=20,d=6,$fn=120); translate([0,0,+12]) tige_biseau(); } } ///////////////////////////// module chape(ep=3,long=30){ difference(){ hull() { cylinder(h=3,d=10,$fn=120); translate([long,0,0]) cylinder(h=3,d=4,$fn=120); } translate([0,0,-10]) tige_biseau(); translate([long,0,-10]) cylinder(h=20,d=2,$fn=120); } } ///////////////////////////// module equerre(){ //distance entre axe vis fixation et potar=22mm eps=0.01; h=21.4; ep=2; entraxe=11; diamvis=2.8; hauteur=36.5; union(){ difference(){ translate([-eps,-h/2,0]) cube([16,h,ep]); for (i=[-1:2:1]){ translate([13.5,i*entraxe/2,-5]) #cylinder(h=10,d=diamvis,$fn=30); } translate([2,0,-5]) #cylinder(h=10,d=4.5,$fn=30); } translate([0,-h/2,ep-eps]) cube([ep,h,hauteur]); translate([-22+ep,-h/2,ep+hauteur-eps-eps]) difference(){ cube([22,h,ep]); translate([33.5-22,h/2,-50]) #cylinder(h=100,d=8,$fn=180); } } } ///////////////////////////// //tige_biseau2(); //connecteur(); //chape(); rotate([90,0,0]) equerre();
Informations pratiques
Emplacement et horaires
Cette formation aura lieu à deux endroits différents, à savoir le département GEII de l'IUT Paul Sabatier et ….. au CPPU.
La séance du XX/XX/XXXX se déroulera à :
Salle Objets Connectés, 1er étage du département GEII de l'IUT de Toulouse 3
8-12h le matin
13h30-17h30 l'après midi
La séances du XX/XX/XXXX se déroulera à :
?????, CPPU
8-12h le matin
13h30-17h30 l'après midi
Achat de matériel
Alternativement: Servo option 2 https://www.amazon.fr/ALLOMN-H%C3%A9licopt%C3%A8re-Beaucoup-Ambition-V%C3%A9hicule/dp/B07Q1GJJZS/ref=sr_1_5?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=159NDCTN6FY4Z&dchild=1&keywords=servo+moteur&qid=1601451911&sprefix=servo+moteu%2Caps%2C175&sr=8-5
1x Alim option 2 (pour le robot): Alimentation de laboratoire 10A (prévoir cable pour distribution 5V): https://www.amazon.fr/Alimentation-Laboratoire-KAIWEETS-stabilis%C3%A9e-Commutation/dp/B085S34NNW/ref=sr_1_3_sspa?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=alimentation+laboratoire&qid=1600841001&sr=8-3-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUFVUzNISUhVTlRYVE4mZW5jcnlwdGVkSWQ9QTAyMzY4NzQzTzJOU09RT0VYQUJUJmVuY3J5cHRlZEFkSWQ9QTA0NzEwNzdRMUNGTFBFU0lRWlkmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl
2x Carte shield motor L293D (16euros les 5): https://www.amazon.fr/AZDelivery-L293D-4-Channel-Diecimila-Duemilanove/dp/B07YWX7S9T/ref=pd_day0_107_6/259-9773987-6397531?_encoding=UTF8&pd_rd_i=B07YWX6N8B&pd_rd_r=09fb95fc-47a3-4712-9977-1d5df52c6ae9&pd_rd_w=Eyhez&pd_rd_wg=atieP&pf_rd_p=95f2fa2e-1e8f-4cae-bf89-355fdf5bbe96&pf_rd_r=BRJ769C5N9Q23VS6Y1ZJ&refRID=BRJ769C5N9Q23VS6Y1ZJ&th=1
3x Potentiomètre rotatif linéaire 10KOhm (7 euros les 5, en prendre 2 par manip): https://www.amazon.fr/potentiom%C3%A8tre-Arduino-Raspberry-dautres-projets/dp/B07B2TSDVF/ref=sr_1_8?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=arduino+potentiometre&qid=1600845741&sr=8-8
alternativement: https://www.sparkfun.com/products/9939
1x moteur avec réducteur (13 euros les 8) : https://www.amazon.fr/Gebildet-DC3V-6V-Voiture-motrices-robotique/dp/B07Z4PYJY4/ref=sr_1_16?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=arduino+motor&qid=1600845585&sr=8-16
1x moteur avec réducteur + roues (7.6 euros les 4) : https://www.amazon.fr/Nrpfell-Arduino-Intelligente-Plastique-Motoreducteur/dp/B07LGYTM57/ref=pd_sbs_60_5/260-0495266-0214753?_encoding=UTF8&pd_rd_i=B07LGYTM57&pd_rd_r=87808a76-98a5-4d65-be1b-011ed5a578e0&pd_rd_w=4KoNy&pd_rd_wg=qElsb&pf_rd_p=5df3b724-4d3e-4605-89d0-6cb31bf88ddc&pf_rd_r=YT9XJBA5JFAPWW2B31SJ&psc=1&refRID=YT9XJBA5JFAPWW2B31SJ
1x jeu de fils dupont (6euros les 3*40pièces): https://www.amazon.fr/AZDelivery-Jumper-Cavalier-C%C3%A2ble-Arduino/dp/B074P726ZR/ref=sr_1_7?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=dupont+wire&qid=1601414268&s=industrial&sr=1-7
1x petite centrale inertielle (18euros pièce): https://www.amazon.fr/MPI9250-CJMCU-117-dattitude-pr%C3%A9cision-communication/dp/B08289XC6V/ref=sr_1_2?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=CJMCU+117&qid=1601414477&sr=8-2
1x module récepteur GPS (7euros pièce): https://www.amazon.fr/Semoic-navigateur-positionnement-Satellite-Remplacement/dp/B07MZJSGKN/ref=sr_1_5?__mk_fr_FR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=GPS+ATGM336H&qid=1601414739&sr=8-5