1
votes

Interpoler linéairement d'une vitesse à l'autre en fonction du pourcentage

J'essaie de ralentir lentement en fonction d'un pourcentage.

En gros: si le pourcentage est égal à 0, la vitesse doit être speed_max , si le pourcentage atteint 85, la vitesse doit être speed_min , en continuant avec speed_min jusqu'à ce que le pourcentage atteigne 100%. À des pourcentages compris entre 0% et 85%, la vitesse doit être calculée avec le pourcentage.

J'ai déjà commencé à écrire le code, même si je ne sais pas comment continuer:

// Target 
int degrees = 90;

// Making sure we're at 0
resetGyro(0);

int speed_max = 450;
int speed_min = 150;

float currentDeg = 0;
float percentage = 0;

while(percentage < 100)
{   
    //??
    getGyroDeg(&currentDeg);
    percentage = (degrees/100)*currentDeg;
}
killMotors(1);

c

7 commentaires

Vous dites «lerp d'une vitesse»; Malheureusement, «lerp» n'est pas un verbe en anglais, donc ce que vous demandez du titre n'est pas clair. Vouliez-vous dire «bondir»?


C'est l'abréviation de l'interpolation linéaire.


Oh… eh bien, ce serait peut-être une bonne idée de dire cela dans la question; ce n'est pas un terme que j'ai rencontré (mais je ne travaille pas avec des gyroscopes sous contrôle informatique). Je vois que Wikipédia mentionne «lerp» dans son article sur interpolation linéaire .


Je ne comprends pas "si le pourcentage est égal à 0, la vitesse doit être speed_max" - cela n’a pas de sens


@barny: La valeur du pourcentage correspond au ralentissement par rapport à la vitesse maximale, 85 étant le nombre auquel vous atteignez la vitesse minimale.


Utiliser «puissance» (c'est-à-dire quelque chose que le code peut contrôler) au lieu de «vitesse» (quelque chose que le code ne peut que mesurer) a plus de sens pour moi.


Si vous souhaitez utiliser int , en.wikipedia.org/wiki/ Bresenham% 27s_line_algorithm utilise tous les int s pour interpoler, donnant les réponses exactes. Cela peut être intéressant surtout si vous travaillez sur du matériel limité (sans FPU?)


3 Réponses :


2
votes

En supposant que la vitesse est calculée linéairement sur la base de pourcentages de 0 à 85 (et reste à speed_min avec un pourcentage gt 85), voici votre formule pour calculer la vitesse:

if (percentage >= 85)
{
    speed = speed_min;
}
else
{
     speed = speed_max - (((speed_max - speed_min)*percentage)/85);
}


0 commentaires

1
votes

L'interpolation linéaire est assez simple.

  • À pourcentage 0, la vitesse doit être speed_max .
  • À pourcentage 85, la vitesse doit être de speed_min .
  • Pour des valeurs de pourcentage supérieures à 85, la vitesse doit toujours être de speed_min .
  • Entre 0 et 85, la vitesse doit être interpolée linéairement entre speed_max et speed_min , donc pourcentage est un 'montant de chute par rapport au maximum vitesse ».

En supposant que pourcentage est de type float:

return speed_max - (speed_max - speed_min) * percentage / 85.0;

Vous pouvez également remplacer le retour final avec l'équivalent:

float speed_from_percentage(float percent)
{
    if (percent <= 0.0)
        return speed_max;
    if (percent >= 85.0)
        return speed_min;
    return speed_min + (speed_max - speed_min) * (85.0 - percentage) / 85.0;
}

Si vous êtes vraiment pédant, toutes les constantes doivent être suffixées avec F pour indiquer float code > et donc utiliser l'arithmétique float au lieu de l'arithmétique double . Et par conséquent, vous devriez probablement également utiliser float pour speed_min et speed_max . Si tout est censé être de l'arithmétique entière, vous pouvez changer float en int et supprimer le .0 des expressions.


0 commentaires

1
votes

En supposant que getGyroDeg est entré par le contrôleur, ce que vous décrivez est un contrôle proportionnel. Une courbe de réponse constante, ie , 0 à 85 a une sortie de 450 à 150, et 150 après cela, est une approche ad-hoc , basée sur l'expérience. Cependant, un contrôleur PID correctement initialisé atteint généralement un temps de consigne plus rapide et une plus grande stabilité.

#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <stdlib.h>

static float sim_current = 0.0f;
static float sim_dt = 0.01f;
static float sim_speed = 0.0f /* 150.0f */;

static void getGyroDeg(float *const current) {
    assert(current);
    sim_current += sim_speed * sim_dt;
    /* Simulate measurement error. */
    *current = sim_current + 3.0 * ((2.0 * rand() / RAND_MAX) - 1.0);
}

static void setGyroSpeed(const float speed) {
    assert(speed >= /*150.0f*/-450.0f && speed <= 450.0f);
    sim_speed = speed;
}

int main(void) {
    /* https://en.wikipedia.org/wiki/PID_controller
     u(t) = K_p e(t) + K_i \int_0^t e(\theta)d\theta + K_d de(t)/dt */
    const float setpoint = 90.0f;
    const float max = 450.0f;
    const float min = -450.0f/* 150.0f */;
    /* Random value; actually get this number. */
    const float dt = 1.0f;
    /* Tune these. */
    const float kp = 30.0f, ki = 4.0f, kd = 2.0f;

    float current, last = 0.0f, integral = 0.0f;
    float t = 0.0f;
    float e, p, i, d, pid;

    size_t count;

    for(count = 0; count < 40; count++) {
        getGyroDeg(&current);
        e = setpoint - current;

        p = kp * e;
        i = ki * integral * dt;
        d = kd * (e - last) / dt;

        last = e;

        pid = p + i + d;
        if(pid > max) {
            pid = max;
        } else if(pid < min) {
            pid = min;
        } else {
            integral += e;
        }
        setGyroSpeed(pid);
        printf("%f\t%f\t%f\n", t, sim_current, pid);
        t += dt;
    }

    return EXIT_SUCCESS;
}

Ici, au lieu que la vitesse diminue linéairement, il calcule la vitesse dans une boucle de contrôle. Cependant, si le minimum est de 150, cela n'atteindra pas une plus grande stabilité; si vous dépassez 90, vous n'avez aucun moyen de revenir en arrière.

Contrôleur PID avec min 150, max 450.

Si les contrôles sont [-450, 450] , ça passe par zéro et c'est beaucoup plus agréable; Je pense que c'est peut-être ce que vous recherchez. Il corrige activement les erreurs.

 Régulateur PID avec min -450, max 450.


0 commentaires