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 :
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
L'énergie est la somme dans le temps des contributions instantanées de la puissance. Cela veut dire que l'énergie est exprimé par le produit de la puissance et le temps :
<latex>
\begin{center}
\begin{equation} E_{X} = P_{X} \cdot temps \end{equation}
\end{center} </latex>
Où :
Les génies électrique et mécaniques se consacrent à créer des sources qui délivrent leur puissance correspondante.
La puissance électrique est décrite par l'équation suivante :
<latex>
\begin{center}
\begin{equation} P_{électrique} = V \cdot i \end{equation}
\end{center} </latex>
Où :
La tension électrique représente la différence d'accumulation des charges qui existent entre deux fils électriques. En courant continu on parle suivant du pôle positif (+) et du pôle négatif (-). Le courant électrique représente la quantité de charges qui sortent d'un fil pour aller vers l'autre. La puissance électrique est dite positive lorsque le courant sort du fil positif vers le négatif.
Une source électrique capable de délivrer un grand courant (donc une grande quantité de charges) sans pour autant présenter une diminution dans sa tension (la différence de concentration de charges) a une très forte puissance nominale. Si cette source est capable de délivrer cette puissance pendant un temps très long, cette source a une grande capacité d'énergie.
La puissance mécanique est décrite par l'équation suivante :
<latex>
\begin{center}
\begin{equation} P_{mécanique} = \Gamma_{mot} \cdot \omega_{mot} \end{equation}
\end{center} </latex>
Où :
La vitesse angulaire représente l'allure dont un moteur tourne. Dans certains domaines on parle en rotations par minutes ou RPM. Le couple est la capacité d'un moteur à délivrer une force sur son axe. La puissance mécanique est dite positive lorsque le couple est dans le même sens que la vitesse.
Une source mécanique capable de délivrer un couple (une force sur son axe) sans pour autant perdre de la vitesse angulaire (l'allure de ses rotations) a une très forte puissance nominale. Si cette source est capable de délivrer cette puissance pendant très longtemps, cette source a une grande capacité d'énergie.
Un moteur à courant continu permet de convertir l'énergie électrique en énergie mécanique. Mathématiquement nous pouvons exprimer cela par le jeu d'équation ci-dessous :
<latex>
\begin{center}
\begin{equation} E_{elec} = E_{meca} \end{equation} \begin{equation} P_{elec} \cdot temps = P_{meca} \cdot temps \end{equation} \begin{equation} P_{elec} = P_{meca} \end{equation} \begin{equation} V_{mot} \cdot i_{mot} = \Gamma_{mot} \cdot \omega_{mot} \end{equation}
\end{center} </latex>
Où:
Ce transfert de puissance est illustré par la figure ci-dessous :
A partir de maintenant nous pouvons réfléchir en terme de point d'opération ou point d'équilibre. Une fois que la source mécanique est connéctée à une charge, une puissance mécanique lui sera délivré. En pratique cela signifie que le point d'opération ou le point d'équilibre du système change. Cela implique des changements dans la tension, le courant, le couple et la vitesse. Nous pouvons vite être dans des situations très complexes à comprendre.
Pour simplifier l'analyse, nous pouvons fixer des grandeur physiques. La tension peut suivant être considérée comme fixe pour une source électrique. La vitesse nominal d'un moteur est aussi suivant fixée. Cela est répresenté par la figure ci-dessous :
Nous pouvons faire un parallèle entre les grandeur électriques et mécaniques.
La tension électrique est liée à la vitesse de rotation. Pour une tension $V_{mot}$ donnée, le moteur tournera à une vitesse $\omega_{mot}$ spécifique.
Le courant est lié au couple. Lorqu'un moteur est à vide, le couple sur son arbre est très faible (frottement internes), donc le courant délivré par la source électrique est aussi très faible. Lorsqu'un moteur est mis sous charge, le couple sur son axe augmente et la source électrique délivre un courant plus important.
Un moteur à courant continu a un point d'opération qui dépend de sa tension d'entrée et de son couple résistant. Normalement nous ne pouvons pas anticiper comment la charge mécanique va se comporter, donc on a très peu de contrôle sur celle-ci. Il nous reste à contrôler la tension d'entrée du moteur.
D'un point de vue global, nous pouvons illustrer un moteur commandé par le schémas blocs ci-dessous.
Le système appelé “commande” adapte la tension à l'entrée du moteur en fonction des signaux de commande qu'il reçoit. Il utilise une source d'énergie électrique extérieure dont la tension est constante et nommée VCC.
Le bloc appelé “reducteur” permet de changer le rapport de vitesse angulaire et couple sans pour autant changer la puissance. Dans notre cas le “réducteur” diminue la vitesse et augmente le couple.
Un servomoteur est un moteur à courant continu dont le mouvement de rotation est contrôlé en termes d'angle plutôt qu'en vitesse. Le schématique ci-dessous illustre ce type de moteur :
Un potentiomètre est installé sur l'axe du servomoteur et lui donne une mesure sur l'angle de cet axe. Cette mesure représente une tension électrique qui varie avec l'angle de l'axe. La mesure set récupérée par le bloc de commande et utilisée pour contrôler la tension du moteur.
Le fait de récupérer une mesure et l'utiliser pour contrôler un système est appelé “asservissement”. Dans le cas de cet enseignement l'asservissement sera numérique.
La maquette étudiée lors de ses deux séances peut être résumée dans le schémas-bloc ci-dessous :
Vous pouvez remarquer une différence par rapport au modèle de servomoteur présenté. Notre maquette découpe la commande dans deux parties, l'Arduino+E/S et le shield moteur.
Le bloc Arduino+E/S reçoit la mesure du potentiomètre et génère des signaux de commande. Le shield du moteur reçoit les signaux de commande de l'Arduino et pilote la tension et le courant du moteur en fonction de ce signaux.
Ce découplage s'impose du fait que la carte Arduino n'est pas capable de générer les courant nécessaires au pilotage du moteur.
La maquette étudie lors de ces deux séances est composée de :
Les composants de la maquette sont montrés dans l'image ci-dessous:
Mettre une image qui montre chaque composant
Pendant les séances, un certain nombre de libraries spécialisés seront nécessaires à l'étude de le maquette.
Pour prendre en main la maquette et comprendre le fonctionnement d'un moteur, nous allons procéder par petit pas.
La première étape de notre étude est nous familiariser avec le contrôle de vitesse du moteur à courant continu.
La carte shield et sa librairie associé facilitent énormément l'envoi des consignes de vitesse. Les commandes les plus importantes sont résumées ci-dessous :
#include <AFMotor.h> //inclusion de la librairie du moteur à utiliser motor_id = 1; //identifiant moteur AF_DCMotor motor(motor_id,MOTOR12_1KHZ);//, MOTOR12_8KHZ); // déclaration du moteur à utiliser motor.setSpeed(consigne_vitesse); // passage de la valeur de la vitesse à la variable motor.run(FORWARD); // choix du sense : avant motor.run(RELEASE); // choix du sense : axe libre motor.run(BACKWARD); // choix du sense : arrière
A l'aide de la carte Arduino, créez un programme qui vous permet :
A l'aide de votre programme étudiez :
Voici une vidéo exemple de fonctionnement :
mettre un lien vidéo ici
Maintenant que nous pouvons contrôler la vitesse du moteur, nous allons étudier comment utiliser un potentiomètre et sa mesure de tension associée pour piloter la position angulaire de l'axe du moteur.
Le schématique ci-dessus donne une vue d'ensemble du montage à faire pour cette étude.
On remarque bien que le potentiomètre n'est pas encore connecté mécaniquement au moteur à courant continu. Nous allons utiliser ce découplage pour illustrer le fonctionnement de l'asservissement.
L'idée centrale à tout asservissement est de minimiser l'erreur entre une mesure et une consigne.
S'il est possible d'asservir directement la variable d'intérêt (dans notre cas précédent c'était la vitesse) aucune astuce mathématique est nécessaire, comme nous avons vu précédement. Cela s'exprime par le schéma directe ci-dessous.
Si nous n'avons pas accès à la variable asservie, les choses sont plus compliqués. Ceci est le cas maintenant où nous souhaitons asservir un déplacement angulaire en agissant sur une vitesse angulaire. Cela s'exprime par le schéma indirect ci-dessous.
La difficulté est de trouver le moyen de “traduire” une consigne en déplacement dans une consigne en vitesse. Cette traduction est faite par un correcteur qui a pour but de minimiser l'erreur entre le déplacement de sortie et la consigne de déplacement. Cette “traduction” est illustrée par l'image ci-dessous.
La nature de la “traduction” faite par le correcteur dépend des types de variables en entrée en en sortie. Il existe une technique qui s'applique à tout cas de figure sans pour autant nécessiter de connaissances claires sur le système. Ce correcteur s'appelle PID.
Le correcteur PID applique un traitement mathématique directement à l'erreur. Il consiste en trois termes différents qui vont appliquer des corrections différentes. Ces termes sont Kp, Ki et Kd comme montre l'image ci-dessous.
Où :
En pratique nous allons utiliser un PID numérique. Il consiste dans une suite de valeurs d'erreur appelée “buffer circulaire”. Il est circulaire car le nombre de valeurs admissibles est limitées et lorsque le programme arrive à la fin de la suite il continue à enregistrer les valeurs par l'écrasement des premières valeurs mesurées. Le buffer circulaire est illustré par l'image ci-dessous.
Dans notre application, si nous sommes à la case 1 du buffer circulaire, les valeurs nécessaires à la correction son calculés comme montre l'image ci-dessous :
Il nous reste de choisir les valeurs de Kp, Ki et Kd. Cela se fait par une méthode itérative qui sera décrite ci-dessous.
//-------------PID CONTROL------------------------------ // PID CONTROL VARIABLES DECLARATION #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; int16_t Kd=0; //de 0 à 50 int16_t Ki=0; int16_t Kp=10; uint16_t consigne_posit = 0; // variable that holds the value of the position reference uint16_t posit = 0; //variable that holds the value of the position measurement int16_t erreur = 0; // variable that calculates the error 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; }//end of update_tab_erreur //----------------------------------------------- void pid_correction(int16_t erreur){ int16_t commande=0; //control signal int16_t commande_max=250; //maximum control signal erreur = erreur*Kp; erreur += Kd*derivee_erreur; //quand l'erreur diminue, ce terme est négatif et permet d'éviter le dépassement erreur += (Ki*integrale_erreur)/TAB_SIZE; commande=abs(erreur); // updates the control signal if (commande>commande_max) commande=commande_max; // checks for saturation if (commande<3) { motor.run(RELEASE); motor.setSpeed(0); } else if (erreur<0) { motor.run(FORWARD); motor.setSpeed(commande); } else { motor.run(BACKWARD); motor.setSpeed(commande); } }//end of pid_correction //------------------------------------------------
void setup() { // setup control table for (int i=0;i<TAB_SIZE;i++) erreur_tab[i]=0; } void loop() { consigne_posit = analogRead(A0); //reads the position reference posit = analogRead(A1); // reads the position erreur = posit - consigne_posit; // calculates the error update_tab_erreur(erreur); // updates the tab pid_correction(erreur); // updates the control // Prints system variables Serial.print(consigne_posit,DEC); //prints the position reference Serial.print("\t"); Serial.print(erreur,DEC); //prints the erro Serial.print("\t"); Serial.print(posit,DEC); //prints the position Serial.print("\t"); Serial.println(""); delay(10); }
A l'aide de la carte Arduino, et le squelette de programme avec le PID intégré écrivez un programme que vous permet:
A l'aide de votre programme étudiez :
Voici une vidéo exemple de fonctionnement :
mettre un lien vidéo ici
Décrire en pas à pas :
Décrire en pas à pas :
Décrire en pas à pas :
vidéo de la manip en fonctionnement: https://www.youtube.com/watch?v=3goxHKO2iuE
//B. Vandeportaele 09/2020 //L. Villa 10/2020 //Todo gestion du temps pour que l'asservissement ait des paramètres fixes/ contenu du programme #include <AFMotor.h> #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(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; } ////////////////////////////////////////// //unité en milliseconde uint32_t cadence_it=3; uint32_t time_next_it=0; void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); Serial.begin(115200); // start serial port at 9600 bps: 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); //allume les leds delay(1000); writePort8574(SLAVE_ADDR_8574_A,~0); //eteind les leds } void loop() { controleur(); } void controleur() { byte consigne_vitesse; // une variable pour récupérer la valeur de la vitesse readPort8574(SLAVE_ADDR_8574_B,&consigne_vitesse); // contrôle de la valeur de la vitesse writePort8574(SLAVE_ADDR_8574_A,~consigne_vitesse); // affichage de la valeur de la vitesse Serial.println(consigne_vitesse); // affichage de la valeur de la vitesse motor.setSpeed(consigne_vitesse); // passage de la valeur de la vitesse à la variable motor.run(FORWARD); // choix du sense : avant delay(1000); motor.run(RELEASE); // choix du sense : lâcher l'axe delay(1000); motor.run(BACKWARD); // choix du sense : arrière delay(1000); motor.run(RELEASE); // choix du sense : lâcher l'axe delay(1000); }
//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); }
#include <Wire.h> //adresses codées sur 7bits #define SLAVE_ADDR_8574_A 0x3E #define SLAVE_ADDR_8574_B 0x3F ////////////////////////////////////////// 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((byte)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; } ////////////////////////////////////////// void setup() { Serial.begin(9600); // 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 } ////////////////////////////////////////// void loop() { char val; if (Serial.available() > 0) { val = Serial.read(); writePort8574(SLAVE_ADDR_8574_A, &val); switch (val) { case '0': break; case '1': break; case '2': break; default: break; } Serial.println((int)val, DEC); } /* if (readPort8574(SLAVE_ADDR_8574_B,&val)==0) { // Serial.print("lecture 8574 OK, "); writePort8574(SLAVE_ADDR_8574_A,val); } delay(100);*/ }
//B. Vandeportaele 09/2020 //jeu=0.5; //pour connecteur jeu=0.3; //pour chape ///////////////////////////// module tige_biseau(){ // coté moteur 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(){ //coté potar 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(){ rotate([180,0,0]) difference(){ cylinder(h=16,d=11,$fn=120); translate([0,0,-12]) //tige_biseau2(); #cylinder(h=20,d=6.40,$fn=120); translate([0,0,+7.95]) tige_biseau(); } } ///////////////////////////// module chape(angle=0,ep=3,long=30){ difference(){ hull() { cylinder(h=ep,d=10,$fn=120); translate([long,0,0]) cylinder(h=ep,d=4,$fn=120); } translate([0,0,-10]) rotate([0,0,angle]) 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.5; diamvis=2.8; hauteur=21; 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); translate([33.5-22,h/2+8,-50]) #cylinder(h=100,d=2.9,$fn=18); } } } ///////////////////////////// ///////////////////////////// //pour 75mm de long+15mm partie male et - 7mm partie femelle module rallonge(longueur){ union(){ difference(){ cylinder(h=longueur,d=13,$fn=120); translate([0,0,+longueur-7]) //scale([1,1,5]) tige_biseau(); } translate([0,0,-15]) tige_biseau(); //de base il fait 20 de long } } ///////////////////////////// //rotate([90,0,0]) rallonge(75); //tige_biseau(); //tige_biseau2(); //connecteur(); //chape(); chape(90,4,40); /*for (i=[1:1:10]){ translate([0,i*15,0]) chape(90,4,20+i*10); } */ //rotate([90,0,0]) equerre(); //connecteur();
Cette formation aura lieu à deux endroits différents, à savoir le département GEII de l'IUT Paul Sabatier et au CPPU 3 Rue Jules Raimu: https://www.google.fr/maps/place/3+Rue+Jules+Raimu,+31200+Toulouse/@43.6049444,1.4020718,11z/data=!4m5!3m4!1s0x12aea32fbaa81f85:0xa1533a58a9f6f9b!8m2!3d43.6358301!4d1.4743211
Les enseignements auront lieu au département GEII de l'IUT de Toulouse 3 dans les salles Objets Connectés et Micro 2, situées au rez de chaussée. Le rendez vous est dans le hall d'entrée du département à 7h50. https://www.google.com/maps/place/IUT+Paul+Sabatier+:+G%C3%A9nie+Electrique+et+Informatique+Industrielle/@43.5649614,1.4547926,17z/data=!3m1!4b1!4m5!3m4!1s0x12aebc16a031ce37:0x7c224bf38a08976!8m2!3d43.5649575!4d1.4569813
Pour se garer, les stagiaires pourront utiliser le parking du restaurant universitaire de médecine:
mardi 20/10
8h-12h: GEII Salle objets connectés
13h30-17h30: GEII Salle micro 2 (ce sera l'occasion de leur montrer les manips de la salle ER2AU)
mercredi 21/10 CPPU
mardi 27/10 (marqué en congés sur Celcat, ce n'est pas un problème?)
8h-12h: GEII Salle objets connectés
13h30-17h30: GEII Salle objets connectés
mercredi 28/10
8h-12h: CPPU
13h30-17h30: CPPU
Jeudi 12/11
13h30-17h30: GEII Salle objets connectés
Jeudi 19/11
13h30-17h30: CPPU
Jeudi 26/11
13h30-17h30: GEII Salle objets connectés
Jeudi 3/12
13h30-17h30: CPPU
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
3x jeu de fils dupont (9.99euros les 3*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