Ceci est une ancienne révision du document !
Table des matières
Objectifs et organisation des séances
Cette formation a pour but formaliser de façon ludique des concepts clés liés au mouvement des bras des robots. Elle sera divisé en trois parties :
* Partie 1 - Introduction à l'informatique industrielle * Partie 2 - Introduction au servomoteur et leur asservissement * Partie 3 - Application de l'asservissement à un bras de robot
Emplacement et horaire
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 manip
Prérequis Initiation programmation et E/S arduino
Prérequis carte E/S
Présentation 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.
Réalisation du Servomoteur
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
http://wiki.sunfounder.cc/index.php?title=L293D_Motor_Driver_Shield
librairie du shield : https://learn.adafruit.com/adafruit-motor-shield/library-install
Asservissement PID
Mettre ici des liens sur les fonctions de librairies Arduino à utiliser
https://www.arduino.cc/reference/fr/
https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
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();
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