Skip to content
commandAllerA.cpp 15.3 KiB
Newer Older
hilnius's avatar
hilnius committed
#include "commandAllerA.h"
#include "odometrie.h"
#include <math.h>
hilnius's avatar
hilnius committed
#include "strategieV2.h"

#ifndef abs
#define abs(x) fabs(x)
#endif
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
float diffAngle(float a, float b)
{
    float t = a-b;
    while (t > M_PI)
    {
        t -= 2*M_PI;
    }
    while (t < -M_PI)
    {
        t += 2*M_PI;
    }
    return t;
}
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
enum Signe
{
    SGN_NEG = -1,
    SGN_UNDEF = 0,
    SGN_POS = 1
};
hilnius's avatar
hilnius committed


Alex's avatar
Alex committed
    ////////////////////////////////
    //    CommandAllerEnArcA      //
    ////////////////////////////////
hilnius's avatar
hilnius committed

CommandAllerEnArcA::CommandAllerEnArcA(Position p, Position c, float v, bool reculer)
    : Command()
{
    but = p;
    centre = c;
    vMax = v;
    m_reculer = reculer;
    linSpeed = Odometrie::odometrie->getVitesseLineaire();
    angSpeed = Odometrie::odometrie->getVitesseAngulaire();
    bonAngle = false;
Alex's avatar
Alex committed

    m_fini = false;

    Position pos = Odometrie::odometrie->getPos().getPosition();
    float pmcx = pos.x-centre.x;
    float pmcy = pos.y-centre.y;
    float bmcx = but.x-centre.x;
    float bmcy = but.y-centre.y;
    if (pmcx*bmcy-pmcy*bmcx > 0.0f)
        cote = SGN_POS;
    else
        cote = SGN_NEG;
hilnius's avatar
hilnius committed
}

void CommandAllerEnArcA::update()
{
    float accAngMax = ACCELERATION_ANGULAIRE_MAX;
    float vitAngMax = VITESSE_ANGULAIRE_MAX;
    float accLinMax = ACCELERATION_LINEAIRE_MAX;
    float decLinMax = DECELERATION_LINEAIRE_MAX;
    float vitLinMax = vMax;//VITESSE_LINEAIRE_MAX;

    float angle = Odometrie::odometrie->getPos().getAngle();
    Position pos = Odometrie::odometrie->getPos().getPosition();

    float rayon = (centre-but).getNorme();

/*
    float vdx = pos.y-but.y;
    float vdy = but.x-pos.x;
    float pmcx = pos.x-centre.x;
    float pmcy = pos.y-centre.y;
    float vdnorme = rayon/sqrt(vdx*vdx+vdy*vdy);
    if (pmcy*vdx+pmcx*vdy < 0) // determinant pour connaitre le sens
        vdnorme = -vdnorme;
    Position pInter(centre.x + vdnorme*vdx, centre.y + vdnorme*vdy);
*/
Pika's avatar
Pika committed

hilnius's avatar
hilnius committed
    float pmcx = pos.x-centre.x;
    float pmcy = pos.y-centre.y;
    float bmcx = but.x-centre.x;
    float bmcy = but.y-centre.y;
    float sintheta = (pmcx*bmcy-pmcy*bmcx)/(rayon*sqrt(pmcx*pmcx+pmcy*pmcy));
    float theta = asin(sintheta);
    float aVise = atan2(pmcy,pmcx)+0.85f*theta;
    Position pVise(centre.x+rayon*cos(aVise), centre.y+rayon*sin(aVise));
    float vmpx = pVise.x-pos.x;
    float vmpy = pVise.y-pos.y;
    float d2 = sqrt(vmpx*vmpx+vmpy*vmpy);
    float an = atan2(vmpy,vmpx);
    float rVise = 0.5f*d2/sin(an-angle);

    float linSpeedVise = vitLinMax;
    float angSpeedVise = vitLinMax/rVise;
    if (angSpeedVise > vitAngMax)
    {
        linSpeedVise *= vitAngMax/angSpeedVise;
        angSpeedVise = vitAngMax;
    }

Alex's avatar
Alex committed
    // test si la commande a fini
    if ((cote == SGN_POS && sintheta < 0.0f) || (cote == SGN_NEG && sintheta > 0.0f) || (abs(sintheta) < M_PI/180.0f))
        m_fini = true;

hilnius's avatar
hilnius committed
    float distance = theta*rVise; // (Odometrie::odometrie->getPos().getPosition() - but).getNorme();
    float distanceVitesseMax = 0.5f*vitLinMax*vitLinMax/decLinMax;
    if (distance < distanceVitesseMax)
    {
        linSpeedVise = sqrt(2*distance*decLinMax);
        angSpeedVise = linSpeedVise/rVise;
    }
    if (linSpeed > linSpeedVise)
    {
        if (linSpeed-linSpeedVise < decLinMax)
            linSpeed = linSpeedVise;
        else
            linSpeed -= decLinMax;
    }
    else
    {
        if (linSpeedVise-linSpeed < accLinMax)
            linSpeed = linSpeedVise;
        else
            linSpeed += accLinMax;
    }

    if (angSpeed > angSpeedVise)
    {
        if (angSpeed-angSpeedVise < accAngMax)
            angSpeed = angSpeedVise;
        else
            angSpeed -= accAngMax;
    }
    else
    {
        if (angSpeedVise-angSpeed < accAngMax)
            angSpeed = angSpeedVise;
        else
            angSpeed += accAngMax;
    }
Pika's avatar
Pika committed

hilnius's avatar
hilnius committed
    // pour garder la trajectoire de cercle
//    std::cout << linSpeed << std::endl;
Pika's avatar
Pika committed

hilnius's avatar
hilnius committed
    if (abs(angSpeed) > abs(linSpeed/rVise))
        angSpeed = linSpeed/rVise;
    else if (abs(linSpeed) > abs(rVise*angSpeed))
Pika's avatar
Pika committed
        linSpeed = rVise*angSpeed;
hilnius's avatar
hilnius committed


}

Vitesse CommandAllerEnArcA::getLinearSpeed()
{
    return linSpeed;
}

Angle CommandAllerEnArcA::getAngularSpeed()
{
    return angSpeed;
}

Alex's avatar
Alex committed
// est ce que la commande a fini ?
bool CommandAllerEnArcA::fini() const
{
    return m_fini;
}
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
    ////////////////////////////////
    //       CommandAllerA        //
    ////////////////////////////////
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
CommandAllerA::CommandAllerA(Position p, bool reculer, float vitesseLineaireMax, float vitesseFin)
hilnius's avatar
hilnius committed
    : Command()
{
    but = p;
Alex's avatar
Alex committed
    vitesseLinMax = vitesseLineaireMax;
Alex's avatar
Alex committed
    vFin2 = vitesseFin*vitesseFin;
hilnius's avatar
hilnius committed
    m_reculer = reculer;
    linSpeed = Odometrie::odometrie->getVitesseLineaire();
    angSpeed = Odometrie::odometrie->getVitesseAngulaire();
    bonAngle = false;
Alex's avatar
Alex committed

    m_fini = false;
hilnius's avatar
hilnius committed
}

void CommandAllerA::update()
{
    float accAngMax = ACCELERATION_ANGULAIRE_MAX;
    float vitAngMax = VITESSE_ANGULAIRE_MAX;
    float accLinMax = ACCELERATION_LINEAIRE_MAX;
    float decLinMax = DECELERATION_LINEAIRE_MAX;
Alex's avatar
Alex committed
    float vitLinMax = vitesseLinMax;//VITESSE_LINEAIRE_MAX;
hilnius's avatar
hilnius committed

    //float angleVitesseMax = M_PI/10.0f;
    float angleVitesseMax = 0.5f*vitAngMax*vitAngMax/accAngMax;
    //float distanceVitesseMax = 350.0f;
Alex's avatar
Alex committed
    float distanceVitesseMax = 0.5f*(vitLinMax*vitLinMax-vFin2)/decLinMax;
hilnius's avatar
hilnius committed
    float angle = Odometrie::odometrie->getPos().getAngle();
    Position pos = Odometrie::odometrie->getPos().getPosition();
    Position delta = but-pos;
    float angleVise = atan2(delta.getY(),delta.getX());

    if (m_reculer)
        angleVise += M_PI;

    float diffAng = diffAngle(angleVise,angle);

    // vitesse angulaire
    if (abs(diffAng) > angleVitesseMax)
    {
         if (diffAng > 0)
            angSpeed += accAngMax;
         else
            angSpeed -= accAngMax;

        if (angSpeed > vitAngMax)
            angSpeed = vitAngMax;
        else if (angSpeed < -vitAngMax)
            angSpeed = -vitAngMax;
    }
    else
    {
        angSpeed = diffAng*vitAngMax/angleVitesseMax;
    }

    // reste sur place tant que le robot n'a pas le bon angle
Alex's avatar
Alex committed
    float angleMaxPourAvancer = M_PI/25.0f;//25.0f;
hilnius's avatar
hilnius committed
    if (!bonAngle)
    {
Pika's avatar
Pika committed
        //StrategieV2::setTourneSurSoiMeme(true);
hilnius's avatar
hilnius committed
        if (abs(diffAng) < angleMaxPourAvancer)
        {
            bonAngle = true;
Alex's avatar
Alex committed
            derniereDistance = 1000000.0f;
hilnius's avatar
hilnius committed
        }
        else
        {
            linSpeed *= 0.95f;
            return;
        }
    }
Pika's avatar
Pika committed
    //StrategieV2::setTourneSurSoiMeme(false);
hilnius's avatar
hilnius committed

    // vitesse linéaire
    float distanceBut = delta.getNorme();

Alex's avatar
Alex committed
    if (distanceBut > derniereDistance || distanceBut < 10.0f)
Alex's avatar
Alex committed
    {
        m_fini = true;
    }

hilnius's avatar
hilnius committed
    if (abs(diffAng) > angleMaxPourAvancer)
    {
        linSpeed *= 0.97f;
    }
    else if (distanceBut > distanceVitesseMax)
    {
         if (m_reculer)
            linSpeed -= accLinMax;
         else
            linSpeed += accLinMax;

        if (linSpeed > vitLinMax)
            linSpeed = vitLinMax;
        else if (linSpeed < -vitLinMax)
            linSpeed = -vitLinMax;
    }
    else
    {
Pika's avatar
Pika committed
        if (m_reculer)
        {
            float linSpeedVisee = -sqrt(vFin2+2.0f*distanceBut*decLinMax);
            if (linSpeed - accLinMax < linSpeedVisee)
                linSpeed = linSpeedVisee;
            else
                linSpeed -= accLinMax;
        }
        else
        {
            float linSpeedVisee = sqrt(vFin2+2.0f*distanceBut*decLinMax);
            if (linSpeed + accLinMax > linSpeedVisee)
                linSpeed = linSpeedVisee;
            else
                linSpeed += accLinMax;
        }
        /*float linSpeedVisee;
hilnius's avatar
hilnius committed
        if (m_reculer)
hilnius's avatar
hilnius committed
            linSpeedVisee = -sqrt(vFin2+2.0f*distanceBut*decLinMax);
hilnius's avatar
hilnius committed
        else
hilnius's avatar
hilnius committed
            linSpeedVisee = sqrt(vFin2+2.0f*distanceBut*decLinMax);
Pika's avatar
Pika committed

hilnius's avatar
hilnius committed
         if (m_reculer)
            linSpeed -= accLinMax;
         else
            linSpeed += accLinMax;

        if (abs(linSpeed) > abs(linSpeedVisee))
Pika's avatar
Pika committed
            linSpeed = linSpeedVisee;*/
hilnius's avatar
hilnius committed
void CommandAllerA::resetSpeeds()
{
    linSpeed = Odometrie::odometrie->getVitesseLineaire();
    angSpeed = Odometrie::odometrie->getVitesseAngulaire();
}

hilnius's avatar
hilnius committed
Vitesse CommandAllerA::getLinearSpeed()
{
    return linSpeed;
}

Angle CommandAllerA::getAngularSpeed()
{
    return angSpeed;
}

Alex's avatar
Alex committed
bool CommandAllerA::fini() const
{
    return m_fini;
}


hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
    ////////////////////////////////
    //    CommandTournerVers      //
    ////////////////////////////////
hilnius's avatar
hilnius committed

CommandTournerVers::CommandTournerVers(Position p)
    : Command()
{
    but = p;
    angSpeed = 0;
Alex's avatar
Alex committed

    m_fini = false;
    signeAngle = SGN_UNDEF;
hilnius's avatar
hilnius committed
}

void CommandTournerVers::update()
{
    float accAngMax = ACCELERATION_ANGULAIRE_MAX;
    float vitAngMax = VITESSE_ANGULAIRE_MAX;
    // float angleVitesseMax = M_PI/6.0f;
    float angleVitesseMax = 0.5f*vitAngMax*vitAngMax/accAngMax;
    float angle = Odometrie::odometrie->getPos().getAngle();
    Position pos = Odometrie::odometrie->getPos().getPosition();
    Position delta = but-pos;
    float angleVise = atan2(delta.getY(),delta.getX());
    float diff = diffAngle(angleVise,angle);

Alex's avatar
Alex committed
    // gestion de si la commande a fini
    if (abs(diff) < M_PI/90.0f)// || (signeAngle == SGN_NEG && diff > 0.0f) || (signeAngle == SGN_POS && diff < 0.0f))
    {
        m_fini = true;
    }
    else if (signeAngle == SGN_UNDEF && abs(diff) < 1.0f)
    {
        if (diff > 0.0f)
            signeAngle = SGN_POS;
        else
            signeAngle = SGN_NEG;
    }

    // calcul de la vitesse angulaire
hilnius's avatar
hilnius committed
    if (abs(diff) > angleVitesseMax)
    {
         if (diff > 0)
            angSpeed += accAngMax;
         else if (diff < 0)
            angSpeed -= accAngMax;

        if (angSpeed > vitAngMax)
            angSpeed = vitAngMax;
        else if (angSpeed < -vitAngMax)
            angSpeed = -vitAngMax;
    }
    else
    {
Pika's avatar
Pika committed
        /*if (diff >= 0)
hilnius's avatar
hilnius committed
            angSpeed = sqrt(2.0f*diff*accAngMax);
        else
Pika's avatar
Pika committed
            angSpeed = -sqrt(-2.0f*diff*accAngMax);*/
        if (diff >= 0)
        {
            float angSpeedVisee = sqrt(2.0f*diff*accAngMax);

            if (angSpeed + accAngMax > angSpeedVisee)
                angSpeed = angSpeedVisee;
            else
                angSpeed += accAngMax;

        }
        else
        {
            float angSpeedVisee = -sqrt(-2.0f*diff*accAngMax);

            if (angSpeed - accAngMax < angSpeedVisee)
                angSpeed = angSpeedVisee;
            else
                angSpeed -= accAngMax;
        }
hilnius's avatar
hilnius committed
    }

}

Vitesse CommandTournerVers::getLinearSpeed()
{
    return 0.0f;
}

Angle CommandTournerVers::getAngularSpeed()
{
    return angSpeed;
}

Alex's avatar
Alex committed
bool CommandTournerVers::fini() const
{
    return m_fini;
}

Alex's avatar
Alex committed

Pika's avatar
Pika committed
    ////////////////////////////////
    //   CommandTournerVersAngle  //
    ////////////////////////////////

CommandTournerVersAngle::CommandTournerVersAngle(float angleVise)
    : Command()
{
    but = angleVise;
    angSpeed = 0;

    m_fini = false;
    signeAngle = SGN_UNDEF;
}

void CommandTournerVersAngle::update()
{
    float accAngMax = ACCELERATION_ANGULAIRE_MAX;
    float vitAngMax = VITESSE_ANGULAIRE_MAX;
    // float angleVitesseMax = M_PI/6.0f;
    float angleVitesseMax = 0.5f*vitAngMax*vitAngMax/accAngMax;
    float angle = Odometrie::odometrie->getPos().getAngle();
    float angleVise = but;
    float diff = diffAngle(angleVise,angle);

    // gestion de si la commande a fini
    if (abs(diff) < M_PI/90.0f)// || (signeAngle == SGN_NEG && diff > 0.0f) || (signeAngle == SGN_POS && diff < 0.0f))
    {
        m_fini = true;
    }
    else if (signeAngle == SGN_UNDEF && abs(diff) < 1.0f)
    {
        if (diff > 0.0f)
            signeAngle = SGN_POS;
        else
            signeAngle = SGN_NEG;
    }

    // calcul de la vitesse angulaire
    if (abs(diff) > angleVitesseMax)
    {
         if (diff > 0)
            angSpeed += accAngMax;
         else if (diff < 0)
            angSpeed -= accAngMax;

        if (angSpeed > vitAngMax)
            angSpeed = vitAngMax;
        else if (angSpeed < -vitAngMax)
            angSpeed = -vitAngMax;
    }
    else
    {
        if (diff >= 0)
            angSpeed = sqrt(2.0f*diff*accAngMax);
        else
            angSpeed = -sqrt(-2.0f*diff*accAngMax);
    }

}

Vitesse CommandTournerVersAngle::getLinearSpeed()
{
    return 0.0f;
}

Angle CommandTournerVersAngle::getAngularSpeed()
{
    return angSpeed;
}

bool CommandTournerVersAngle::fini() const
{
    return m_fini;
}


Alex's avatar
Alex committed
    ////////////////////////////////
    //       CommandVirage        //
    ////////////////////////////////


// rayon > 0
// angle > 0 : vers la gauche, angle < 0 : vers la droite
Alex's avatar
Alex committed
CommandVirage::CommandVirage(float rayon, float angle, float vitesseLineaireMax, float vitesseFin)
Alex's avatar
Alex committed
{
    if (angle > 0.0f)
        rayonCourbure = rayon;
    else
        rayonCourbure = -rayon;
    linSpeed = Odometrie::odometrie->getVitesseLineaire();
    angSpeed = Odometrie::odometrie->getVitesseAngulaire();
    angleVise = angle + Odometrie::odometrie->getPos().getAngle();
    vFin2 = vitesseFin*vitesseFin;
Alex's avatar
Alex committed
    vitesseLinMax = vitesseLineaireMax;
Alex's avatar
Alex committed

    m_fini = false;
}

void CommandVirage::update()
{
    float accLinMax = ACCELERATION_LINEAIRE_MAX;
    float decLinMax = DECELERATION_LINEAIRE_MAX;
Alex's avatar
Alex committed
    float vitLinMax = vitesseLinMax;//VITESSE_LINEAIRE_MAX;
Alex's avatar
Alex committed

    float distanceVitesseMax = 0.5f*(vitLinMax*vitLinMax-vFin2)/decLinMax;

    float angleRestant = diffAngle(angleVise, Odometrie::odometrie->getPos().getAngle());
    float distanceRestante = abs(rayonCourbure*angleRestant);

    // gestion de si la commande a fini
    // si l'angle restant est bon ou si on a dépassé l'angle visé
    if (abs(angleRestant) < M_PI/90.0f || ((angleRestant > 0.0f) != (rayonCourbure > 0.0f)))
    {
        m_fini = true;
    }

    // phase de vitesse max
    if (distanceRestante > distanceVitesseMax)
    {
            linSpeed += accLinMax;
        if (linSpeed > vitLinMax)
            linSpeed = vitLinMax;
    }

    // phase de décéleration
    else
    {
        linSpeed = sqrt(vFin2+2.0f*distanceRestante*decLinMax);
    }

    // calcul de la vitesse angulaire
    angSpeed = linSpeed/rayonCourbure;
}
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
Vitesse CommandVirage::getLinearSpeed()
{
    return linSpeed;
}
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed
Angle CommandVirage::getAngularSpeed()
{
    return angSpeed;
}

// est ce que la commande a fini ?
bool CommandVirage::fini() const
{
    return m_fini;
}


Alex's avatar
Alex committed
    ////////////////////////////////
    //      CommandAttendre       //
    ////////////////////////////////

CommandAttendre::CommandAttendre(int nbUpdates)
    : Command(), compte(nbUpdates)
{
}

void CommandAttendre::update()
{
    compte--;
}

Vitesse CommandAttendre::getLinearSpeed()
{
    return 0.0f;
}

Angle CommandAttendre::getAngularSpeed()
{
    return 0.0f;
}

bool CommandAttendre::fini() const
{
    return (compte <= 0);
}
Alex's avatar
Alex committed
    ////////////////////////////////
    //      CommandTestAvancer    //
    ////////////////////////////////
hilnius's avatar
hilnius committed

CommandTestAvancer::CommandTestAvancer()
    : Command()
{
}

void CommandTestAvancer::update()
{
}

Vitesse CommandTestAvancer::getLinearSpeed()
{
    return VITESSE_LINEAIRE_MAX;
}

Angle CommandTestAvancer::getAngularSpeed()
{
    return 0.0f;
}

Alex's avatar
Alex committed
    ////////////////////////////////
    //  CommandTestTournerGauche  //
    ////////////////////////////////
hilnius's avatar
hilnius committed


CommandTestTournerGauche::CommandTestTournerGauche()
    : Command()
{
}

void CommandTestTournerGauche::update()
{
}

Vitesse CommandTestTournerGauche::getLinearSpeed()
{
    return 0.0f;
}

Angle CommandTestTournerGauche::getAngularSpeed()
{
    return VITESSE_ANGULAIRE_MAX;
}