Hardware ESP8266 pour rObOtscratch II

l’ESP8266-1

L’ ESP8266-01 est la plus petite ESP8266 : elle ne dispose que de 8 broches. Parmi celles ci, Vcc, GND, RST (reset) et CH_PD (chip select) ne sont pas des entrées/sorties mais servent au fonctionnement u module. Cela laisse GPIO0, GPIO2, Tx et Rx comme entrées/sorties possibles.



Mais même ces 4 broches ont des rôles spécifiques: GPIO0 et GPIO2 déterminent le mode de démarrage du module, alors que Tx,Rx sont utilisés pour la programmation du module et la communication série.

GPIO0 and GPIO2 doivent être câblés avec des résistances de pull-up pour garantir le démarrage de la carte sur le programme chargé.

Le double driver YL-86 (à base de L9110)

Le L9110 est un driver très compact qui peut travailler avec des tensions d’alimentation allant de 2.5V à 12V, avec un courant de 800mA. Il intègre des diodes de protection, qui préservent l’électronique.


La carte utilisée ici comporte 2 drivers indépendants, ce qui permet de commander 2 moteurs cc.

IA1 IB1 IA2 IB2 sortie
0 0 x x Moteur 1 à l’arrêt
0 1 x x Moteur 1 en avant
1 0 x x Moteur 1 en arrière
1 1 x x Moteur 1 à l’arrêt
x x 0 0 Moteur 2 à l’arrêt
x x 0 1 Moteur 2 en avant
x x 1 0 Moteur 2 en arrière
x x 1 1 Moteur 2 à l’arrêt

Remarque : les notions « avant » et « arrière » dépendent bien sûr du câblage du moteur.

Firmware ESP8266-1 pour rObOtscratch II

Câblage

/**
 *  C.G. 2017 - Firmware ESP 8266-1 pour rObOscratch II
**/
 
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* ssid = "rObOtScratch";
const char* password = "56claude";

ESP8266WebServer server(80);


int bAV_D = 1; // variable d'état : moteur droite en avant (1) ou arrière (0)
int vAV_D = 0; // nb de ticks en position haute pour le hacheur
int vAV_Dold = 4; // pour reprendre à la meme vitesse apres un arret

int bAV_G = 1;
int vAV_G = 0;
int vAV_Gold = 4;

int h = 0;

void handleRoot() {
  server.send(200, "text/plain", "CG 2017 PETIT ROBOT avec ESP8266");
}

void handleAV() {
  bAV_D = 1;
  vAV_D = vAV_Dold;
  bAV_G = 1;
  vAV_G = vAV_Gold;
   
}

void handleAR() {
  bAV_D = 0;
  vAV_D = vAV_Dold;
  bAV_G = 0;
  vAV_G = vAV_Gold;
}

void handleDR() {
  bAV_D = 1;
  vAV_D = vAV_Dold;
  bAV_G = 0;
  vAV_G = vAV_Gold;  
}

void handleGA() {
   bAV_D = 0;
   vAV_D = vAV_Dold;
   bAV_G = 1;
   vAV_G = vAV_Gold;
}

void handlePlus() {
    vAV_D++; if (vAV_D>10) vAV_D=10;
    vAV_G++; if (vAV_G>10) vAV_G=10;
    vAV_Dold = vAV_D;
    vAV_Gold = vAV_G;
}

void handleMoins() {
    vAV_D--; if (vAV_D<0) vAV_D=0;
    vAV_G--; if (vAV_G<0) vAV_G=0;
    vAV_Dold = vAV_D;
    vAV_Gold = vAV_G;
}

void handleStop() {
  vAV_Dold = vAV_D;
  vAV_D = 0;
  vAV_Gold = vAV_G;
  vAV_G = 0; 
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){ 
     message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; 
  } 
  server.send(404, "text/plain", message); 
} 


// HACHEUR 
volatile int toggle; 
void inline hacheur (void){ 
        h++; if (h>10) h=0;
	if (bAV_D == 1) { // moteur droite en avant
		if (h < vAV_D) { digitalWrite(0, 1);  digitalWrite(2, 0); } 
                else { digitalWrite(0, 0); digitalWrite(2, 0);}
	} else {
		if (h < vAV_D) { digitalWrite(0, 0); digitalWrite(2, 1);} 
                else { digitalWrite(0, 0); digitalWrite(2, 0);}
	}
	
	if (bAV_G == 1) { // moteur gauche en avant
		if (h < vAV_G) { digitalWrite(1, 1);  digitalWrite(3, 0);} 
                else { digitalWrite(1, 0); digitalWrite(3, 0);}
	} else {
		if (h < vAV_G) { digitalWrite(1, 0); digitalWrite(3, 1); } 
                else { digitalWrite(1, 0); digitalWrite(3, 0); } } 

       timer0_write(ESP.getCycleCount() + 80000); 
       // 80Mhz -> 80*10^6 = 1 seconde
       //          80*10^3 = 1 ms    
}

void setup(void){
   int i = 0;
   
   pinMode(0, OUTPUT);
   pinMode(1, OUTPUT);
   pinMode(2, OUTPUT);
   pinMode(3, OUTPUT);

   WiFi.begin(ssid, password);
   delay(500);
   // Attente de connexion
   while (WiFi.status() != WL_CONNECTED) delay(500);

   server.on("/", handleRoot);
   server.on("/av",[](){handleAV(); server.send(200, "text/plain", "AV");});
   server.on("/1", [](){server.send(200, "text/plain", "1");});
   server.on("/0", [](){server.send(200, "text/plain", "0");});
   server.on("/ar",[](){handleAR(); server.send(200, "text/plain", "AR");});
   server.on("/dr",[](){handleDR(); server.send(200, "text/plain", "DR");});
   server.on("/ga",[](){handleGA(); server.send(200, "text/plain", "GA");});
   server.on("/+", [](){handlePlus(); server.send(200, "text/plain", "+");});
   server.on("/-", [](){handleMoins(); server.send(200, "text/plain", "-");});
   server.on("/st",[](){handleStop(); server.send(200, "text/plain", "STOP");});
   server.onNotFound(handleNotFound);
   server.begin();  
   
   noInterrupts();
   timer0_isr_init();
   timer0_attachInterrupt(hacheur);
   timer0_write(ESP.getCycleCount() + 80000000);
   interrupts();
 
}

void loop(void){
  server.handleClient();
}

Maxima: champs tournants

Théorème de Ferraris – champs tournants

Le théorème de Ferraris démontre qu’un champ tournant peut être créé par trois bobines positionnées en arc de cercle avec un décalage de 120°, chacune alimentées par une phase d’un courant électrique triphasé1. La fréquence de rotation est alors égale à la fréquence de courants d’alimentation. Il démontre également que 3p bobines alimentées en triphasé et décalées de 120°/p permettent d’obtenir un champ tournant avec une fréquence de rotation f/p, f étant la fréquence des courants d’alimentation.

Définition de trois champs périodiques dans l’espace, période = D
champs B1, B2, B3 décalés de D/3


(%i3)

B1(B, D, x) := B·sin(2·%pi·x/D) ;
B2(B, D, x) := B·sin(2·%pi/D·(x D/3));
B3(B, D, x) := B·sin(2·%pi/D·(x 2·D/3));

(%o1) B1(B,D,x):=B*sin((2*%pi*x)/D)

(%o2) B2(B,D,x):=B*sin((2*%pi)/D*(x-D/3))

(%o3) B3(B,D,x):=B*sin((2*%pi)/D*(x-(2*D)/3))


(%i4)

sommeB(B, D, x) := B1(B,D,x) + B2(B,D,x) + B3(B,D,x);

(%o4) sommeB(B,D,x):=B1(B,D,x)+B2(B,D,x)+B3(B,D,x)


(%i6)

f : 50; T: 1/f;

(f) 50

(T) 1/50


(%i10)

load(draw);
D : 1;
line : [[D/4, 1], [D/3+D/4, 1], [2·D/3 + D/4, 1]];
wxdraw2d(
grid = true,
color=blue,  explicit(B1(1, 1,x), x, 1, 1),
color=green, explicit(B2(1,1,x),x, 1, 1),
color=black, explicit(B3(1,1,x),x, 1, 1),
color=red,   explicit(sommeB(1,1,x),x, 1, 1),
color=orange, point_type=7, points(line)
);

0 errors, 0 warnings

(%o7) "/usr/local/share/maxima/5.41.0/share/draw/draw.lisp"

(D) 1

(line) [[1/4,1],[7/12,1],[11/12,1]]

(%t10)

 (Graphics)

(%o10)


(%i11)

omega : 2·%pi·f;

(omega) 100*%pi


(%i12)

A0 : 1;

(A0) 1


(%i15)

A1(t) := A0·cos(omega·t); A2(t) := A0·cos(omega·t 2·%pi/3); A3(t) := A0·cos(omega·t 4·%pi/3);

(%o13) A1(t):=A0*cos(omega*t)

(%o14) A2(t):=A0*cos(omega*t-(2*%pi)/3)

(%o15) A3(t):=A0*cos(omega*t-(4*%pi)/3)


(%i18)

champ1(x, t) := B1( A1(t), 1, x); champ2(x, t) := B2( A2(t), 1, x); champ3(x, t) := B3( A3(t), 1, x);

(%o16) champ1(x,t):=B1(A1(t),1,x)

(%o17) champ2(x,t):=B2(A2(t),1,x)

(%o18) champ3(x,t):=B3(A3(t),1,x)

Traçage des 3 champs séparés, et de leur somme (en rouge).


(%i19)

with_slider_draw(k, makelist(i·T/32, i, 0, 32),
xrange=[0, 1], yrange=[1.5, 1.5],
xaxis = true, yaxis = true,
color = blue, explicit(champ1(x, k),x,0,1),
color = green, explicit(champ2(x, k),x,0,1),
color = black, explicit(champ3(x, k),x,0,1),
color=red,  explicit(  champ1(x, k)+champ2(x, k)+champ3(x, k)    , x,  0,  1)
);

(%t19)

Animated Diagram
(%o19)

À faire :

  1. Voyez ce qui ce passe lorsqu’on inverse deux champs
    par exemple, champ1(x, t) := B1( A2(t), 1, x);
    et champ2(x, t) := B2( A1(t), 1, x);
  2. Proposez un moteur à 2 phases.