Skip to main content

Retour sur la vitesse en X

Pour améliorer le déplacement en X, j'extrapole le temps de parcours pour une fréquence 10 kHz (cf. cette étape) :FX-XRF_fit.png

J'obtiens 12 s. A partir de toutes ces valeurs, je calcule la vitesse en fonction de la fréquence pour chaque fréquence : calcul_rapport_v-f.csv

v8,0×106f

où la vitesse et en m.s-1 et la fréquence en Hz.

Pour 10 kHz, on observe en effet à peu près 8 cm.s-1.

verification.png

Ainsi, dans la phase de déplacement uniforme, on se rapproche du but de 3,69 mm par itération, soit 21 itérations par secondes, soit 46 ms par itération (qu'on pourrait vérifier...). 

L'idée est donc (si la distance le permet) d'avoir une accélération, une vitesse uniforme, puis une décélération : croquis-vitesse-positionen bleu : la vitesse, qui atteint un plateau, et en gris, la position, en fonction du temps.

La courbe bleue peut se modéliser de nombreuses façons. La plus évidente est celle d'une différence entre deux distributions de Fermi-Dirac :

g1(t)=11+ea(t1t);g2(t)=11+ea(t2t)

et

V(t)=Vmax(g1(t)g2(t))

En intégrant, on obtient :

x(t)=τ=0τ=tV(t)dτ=Vmax[ln(1+ea(t1t))ln(1+ea(t2t))]+C

La constante d'intégration C s'identifie à x(0).

Or, dans l'approximation limite a

t2=t1+x1x2Vmax

On a donc tout pour, au début de smoveXto

  1. Fixer a et t1
  2. Calculer t2
  3. Tabuler, en fonction de t, les valeurs de x, au mm près.
  4. En fonction de t, calculer les valeurs de v.
  5. Puis pendant smoveXto prendre la valeur de x (ou t si c'est plus commode) et imposer v.

La feuille Geogebra de mes errements

Au final, on fait deux parcours tests pour régler les paramètres t1 et Vmax

On fixe a = 0,01 et t1 = t0 + 100

 D'abord grossièrement (à gauche, avec un arrêt brutal) puis finement (à droite) :

run-400-600.pngrun-600-200.png

On déduit de la Vmax = 76,4 mm.s-1 (précédemment estimé à 80), et un temps d'accélération/décelération de 2x580 = 1160 ms

La distance restant à parcourir au début du freinage (dans la figure de droite) est de 84mm.

On en déduit donc que t1 était sous estimé.

Après avoir un peu galéré et discuté avec les étudiants de TopAéro (qui sortiraient volontiers l'artillerie lourde), je reviens à l'idée  d'indexer la fréquence (et donc la vitesse) sur la position mesurée.

On crée un tableau GLOBAL (sinon la pile réservée aux variables locales explose, même si le tableau ne fait que 40 ko, voir par exemple cette discussion). Le tableau est rempli en précalculant la trajectoire : on  itère sur t suivant les explications ci-dessus, et à chaque t, on calcule à la fois v(t) et x(t), obtenu par l'intégration analytique. Dans certains intervalles, on obtient de trop nombreuses valeurs de x très proches les unes des autres. Mais comme la mesure de distance retournera un entier, c'est tout à fait inutile d'avoir une telle précision : on écrase donc les valeurs calculées de la vitesse jusqu'à ce qu'on passe à la distance entière suivante (je ne sais pas si c'est très clair).

int nb = 2000;

//Serial.println("preparing f array");
for (int i = 0 ; i < 2000 ; i++) {
  f[i] = 0;
}

int step = ( tf - t0 ) / nb ;

double deltat1 = (double) (t1 - t0) ;
double deltat2 = (double) (t2 - t0) ;
double cc = currentDistance - sens * VMax * ( log (1.0 + exp(a*(deltat1))) - log (1.0 + exp(a*(deltat2)))) / 10 ;

for (int i = 0 ; i < nb ; i++) {
  int t = t0 + i * step;
  double deltat1 = (double) (t1 - t) ;
  double deltat2 = (double) (t2 - t) ;
  double df = FreqMax * ( 1.0 / ( 1.0 + exp(a * deltat1) ) - 1.0 / ( 1.0 + exp(a * deltat2) )) ;
  double dd = sens * VMax * ( log (1.0 + exp(a*(deltat1))) - log (1.0 + exp(a*(deltat2)))) / 10 + cc ;

  f[constrain((int) dd, 0, 2000)] = constrain((int) df, FreqMin, FreqMax);
}

Ensuite, la modification de la fréquence se fait de manière directe :

    currentDistance = Xsensor.getDistance();
    int actualFreq = f[currentDistance];
    ledcSetup(pwmChannelX, actualFreq, 8);
    ledcSetup(pwmChannelY, actualFreq, 8);  

Par ailleurs, c'est une bonne occasion de rappeler comment récupérer les infos venant du port série sur un Mac, autrement qu'en faisant des copier-coller à partir de l'IDE. Bien sûr, on peut installer des applications comme CoolTerm, ou SerialTools.

Mais on peut aussi faire les choses à la mode unix :

(stty speed 115200 >/dev/null && cat) </dev/cu.usbserial-54D80285741 | tee serial.log 

C'est officiel, j'ai ré-inventé la roue, et je me suis cassé la tête pour rien : un trapèze simple (accélération / décelérations constantes) suffirait largement (discussion avec Guillaume Morel qui me suggère de lire le papier de Hogan et Flash sur le minimum jerk et le livre de Dombre et Khalil (ainsi que son cours).

C'est d'ailleurs ce qui est fait sans le dire dans la version précédente de la routine smoveXto.

Soit a l'accélération, xi et xf les positions et Vmax. Il existe deux types de trajets : ceux pendant lesquels la vitesse maximale va être atteinte parce que la distance est suffisante (2) ; ceux pendant lesquels il faut commencer à freiner avant de l'avoir atteinte (1).

Cas 1 :  xf-xi est insuffisante pour atteindre Vmax.

v(t)=atpuisv(t)=v(t1/2)at

soit x(t)=at2+xipuisx(t)=xi+xfxi2+at1/22at2

On trouve t1/2 

x(t1/2)=xfxi2=at1/22+xi

d'où t1/2=xfxi2a

A la limite, où xf-xi est suffisante, on atteint Vmax  pile pour t1/2 :

Vmax=at1/2=axfxi2a=axfxi2

Cas 2 : si xf-xi est supérieure à la valeur trouvée ci-dessus, alors il faut définir t1 et t2 qui délimitent le plateau parcouru à vitesse max.