Skip to content
asservissement.cpp 18 KiB
Newer Older
#include "asservissement.h"
hilnius's avatar
hilnius committed
#include "strategieV2.h"
#include "ascenseur.h"

#include "clock.h"
hilnius's avatar
hilnius committed
#include "capteurCouleur.h"

Alexandre Manoury's avatar
Alexandre Manoury committed
#ifndef NO_REMOTE
    #include "remote.h"
hilnius's avatar
hilnius committed

Alexandre Manoury's avatar
Alexandre Manoury committed
#define DEBUG_ODOMEDTRIE 0
hilnius's avatar
hilnius committed

#define DEBUG_ASSERV 0
#define DEBUG_ASSERV_SIZE 1200
hilnius's avatar
hilnius committed

Alexandre Manoury's avatar
Alexandre Manoury committed
#define DEBUG_BLINK_EACH_SECOND 1
hilnius's avatar
hilnius committed

//#if DEBUG_ASSERV == 1
    //int roueGauche[DEBUG_ASSERV_SIZE];
    //int roueDroite[DEBUG_ASSERV_SIZE];
    /*float vitesseLin[DEBUG_ASSERV_SIZE];
    float vitesseLinE[DEBUG_ASSERV_SIZE];
    float linearDuty[DEBUG_ASSERV_SIZE];
    float vitesseAng[DEBUG_ASSERV_SIZE];
    float vitesseAngE[DEBUG_ASSERV_SIZE];
    float angularDuty[DEBUG_ASSERV_SIZE];
Pika's avatar
Pika committed

    float posx[DEBUG_ASSERV_SIZE];
    float posy[DEBUG_ASSERV_SIZE];
    float angle[DEBUG_ASSERV_SIZE];

    uint32_t dbgInc = 0;*/

    float vitesseLin[DEBUG_ASSERV_SIZE];
    float vitesseLinE[DEBUG_ASSERV_SIZE];
    float linearDuty[DEBUG_ASSERV_SIZE];

    float vitesseAng[DEBUG_ASSERV_SIZE];
    float vitesseAngE[DEBUG_ASSERV_SIZE];
    float angularDuty[DEBUG_ASSERV_SIZE];
//#endif

Asservissement * Asservissement::asservissement = NULL; //Pour que nos variables static soient défini
bool Asservissement::matchFini = false;
const uint16_t Asservissement::nb_ms_between_updates = MS_BETWEEN_UPDATE;

Asservissement::Asservissement(Odometrie* _odometrie) : testMod(false), testRunning(false), stopped(false), testDataSent(0), testDataToSend(0), engineLimit(0.5f)
    seuil_collision(SEUIL_COLISION),
Cecile Bouette's avatar
Cecile Bouette committed
    buffer_collision(0xffffffff)*/
hilnius's avatar
hilnius committed
    vitesseLineaire = 0;
hilnius's avatar
hilnius committed
    vitesseAngulaire = 0;
hilnius's avatar
hilnius committed

    activePIDDistance = true;
    activePIDAngle = true;

    resetFixedDuty();

    linearDutySent = 0;
    angularDutySent = 0;

    if(asservissement == 0)
    {
        Asservissement::asservissement = this;
    }
Alexandre Manoury's avatar
Alexandre Manoury committed
    asserCount = 0;

    nombreQuatumParDixiemeDeSeconde = 1000/(NB_VERIFICATION_BLOQUAGE_PAR_SECONDE*MS_BETWEEN_UPDATE);
    obstacleDetecte = false;
    nbUpdateDepuisObstacleDetecte = 0;
    positionPlusAnglePrecedenteX = 0;
    positionPlusAnglePrecedenteY = 0;
    positionPlusAnglePrecedenteAngle = 0;

    for(int initTableaux = 0 ; initTableaux < NB_VERIFICATION_BLOQUAGE_PAR_SECONDE ; initTableaux++)
    {
        deplacementLineaires[initTableaux] = 0;
        deplacementAngulaire[initTableaux] = 0;
        accelerationLineaires[initTableaux] = 0;
        accelerationAngulaires[initTableaux] = 0;
    }
Cecile Bouette's avatar
Cecile Bouette committed

#ifdef CAPTEURS
    sensors = Sensors::getSensors();
#endif

#ifdef ROBOTHW  //on définie les interruptions possibles dues à certains ports
    *((uint32_t *)(STK_CTRL_ADDR)) = 0x03; // CLKSOURCE:0 ; TICKINT: 1 ; ENABLE:1
#ifdef STM32F40_41xxx
    *((uint32_t *)(STK_LOAD_ADDR)) = 21000*nb_ms_between_updates; // valeur en ms*9000 (doit etre inférieur à 0x00FFFFFF=16 777 215)
#else
hilnius's avatar
hilnius committed
    *((uint32_t *)(STK_LOAD_ADDR)) = 9000*nb_ms_between_updates; // valeur en ms*9000 (doit etre inférieur à 0x00FFFFFF=16 777 215)
#endif
hilnius's avatar
hilnius committed
    // le micro controlleur tourne à une frequence f (72Mhz ici), la valeur à mettre est (0.001*(f/8))*(temps en ms entre chaque update)
Alex's avatar
Alex committed
    // voir p190 de la doc

    NVIC_InitTypeDef SysTick_IRQ;

    SysTick_IRQ.NVIC_IRQChannel = SysTick_IRQn;
    SysTick_IRQ.NVIC_IRQChannelCmd = ENABLE;
    SysTick_IRQ.NVIC_IRQChannelPreemptionPriority = 0;
    SysTick_IRQ.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&SysTick_IRQ);
#endif
hilnius's avatar
hilnius committed
}

void Asservissement::setLinearSpeed(Vitesse vitesse)
{
    vitesseLineaire = vitesse;
    //setEnabledPIDDistance(true);
hilnius's avatar
hilnius committed
}

void Asservissement::setAngularSpeed(VitesseAngulaire vitesse)
{
    vitesseAngulaire = vitesse;
    //setEnabledPIDAngle(true);
hilnius's avatar
hilnius committed
}

void Asservissement::stop()
{
    stopped = true;
    testRunning = false;
}

void Asservissement::resume()
{
    stopped = false;
}

hilnius's avatar
hilnius committed
void Asservissement::setCommandSpeeds(Command* command)
{
    if (command != NULL)
    {
        setLinearSpeed(command->getLinearSpeed());
        setAngularSpeed(command->getAngularSpeed());
    }
    else
    {
        setLinearSpeed(0.0f);
        setAngularSpeed(0.0f);
    }

    /*setEnabledPIDDistance(true);
    setEnabledPIDAngle(true);
    resetFixedDuty();*/
hilnius's avatar
hilnius committed
}
hilnius's avatar
hilnius committed

void Asservissement::runTest(int duration, float linSpeed, float angSpeed, float limit)
    testDuration = duration;
    testIndex = 0;

    testLinearSpeed = linSpeed;
    testAngularSpeed = angSpeed;

    testRunning = true;
    testMod = true;
    stopped = false;

    engineLimit = limit;

    testDataSent = 0;
    testDataToSend = 0;
Distance Asservissement::getLinearSpeed()
{
    if (testMod)
        return testRunning ? testLinearSpeed : 0.f;
    else
        return vitesseLineaire;
}

Angle Asservissement::getAngularSpeed()
{
    if (testMod)
        return testRunning ? testAngularSpeed : 0.f;
    else
        return vitesseAngulaire;
}

void Asservissement::setPIDDistance(bool enabled)
{
    activePIDDistance = enabled;
}

void Asservissement::setPIDAngle(bool enabled)
{
    activePIDAngle = enabled;
}

void Asservissement::update(void)
hilnius's avatar
hilnius committed
{
#ifdef ROBOTHW
    #if DEBUG_ODOMEDTRIE == 1
    PositionPlusAngle pos = Odometrie::odometrie->getPos();
    Angle absAngle = Odometrie::odometrie->getAbsoluteAngle();
    if ( pos.position.x > 400. /* absAngle > 3.14159265358979323846*2.*/)
        Led::setOn(0);
    else
        Led::setOff(0);
    #endif
hilnius's avatar
hilnius committed

    asserCount++;
/*#ifdef ROUES
    if (!stopped)
hilnius's avatar
hilnius committed
    {
        roues.gauche.tourne(0.6);
        roues.droite.tourne(0.6);
    }
    else
    {
        roues.gauche.tourne(0.0);
        roues.droite.tourne(0.0);
    }
    if (testMod && testRunning)
    {
        testIndex++;
        if (testIndex >= testDuration)
        {
            stopped = true;
            testRunning = false;
        }
    }
    return;
#endif*/

    if (!stopped)
    {
        PositionPlusAngle positionPlusAngleActuelle = odometrie->getPos();      //Variable juste pour avoir un code plus lisible par la suite
        Angle vitesse_angulaire_atteinte = odometrie->getVitesseAngulaire();    //idem
hilnius's avatar
hilnius committed
        Distance vitesse_lineaire_atteinte = odometrie->getVitesseLineaire();   //idem
hilnius's avatar
hilnius committed

        float vitesse_lineaire_a_atteindre = getLinearSpeed();
        float vitesse_angulaire_a_atteindre = getAngularSpeed();

        //qDebug() << fixedLinearDuty << " = " << activePIDAngle;

#ifdef ROUES

        //on filtre l'erreur de vitesse lineaire et angulaire
        linearDutySent = activePIDDistance ? pid_filter_distance.getFilteredValue(vitesse_lineaire_a_atteindre-vitesse_lineaire_atteinte) : 0.f;
        angularDutySent = activePIDAngle ? pid_filter_angle.getFilteredValue(vitesse_angulaire_a_atteindre-vitesse_angulaire_atteinte) : 0.f;
Pika's avatar
Pika committed
        //Et on borne la somme de ces valeurs filtrée entre -> voir ci dessous
Alexandre Manoury's avatar
Alexandre Manoury committed
        #ifdef RRD2
            engineLimit = 0.5f;
Alexandre Manoury's avatar
Alexandre Manoury committed
        #endif

Cecile Bouette's avatar
Cecile Bouette committed

        /*linearDutySent = MIN(MAX(linearDutySent, -engineLimit), engineLimit);
        angularDutySent = MIN(MAX(angularDutySent, -engineLimit), engineLimit);*/
        /*computeObstacleDetecte(linearDutySent, angularDutySent, &positionPlusAngleActuelle);
Alexandre Manoury's avatar
Alexandre Manoury committed

        if(obstacleDetecte)
        {
            linearDutySent = 0;
            angularDutySent = 0;

        //On évite que le robot fasse du bruit quand il est à l'arrêt
 //       linearDutySent = fabs(linearDutySent) > 0.05 || vitesse_lineaire_a_atteindre > 0.01 ? linearDutySent : 0;
hilnius's avatar
hilnius committed
 //       angularDutySent = fabs(angularDutySent) > 0.05 || vitesse_angulaire_a_atteindre > 0.0001 ? angularDutySent : 0;


        // test d'arret complet si c'est l'ordre qu'on lui donne
        if (vitesse_lineaire_a_atteindre == 0.0f && vitesse_angulaire_a_atteindre == 0.0f)
hilnius's avatar
hilnius committed
        {
            linearDutySent = 0.0f;
            angularDutySent = 0.0f;
        // Tourne de façon borné et le fais d'avoir filtrées les valeurs permet de compenser les erreurs
        // passées et de faire tourner chaque roues de façon à tourner et avancer correctement
        /*if (Remote::getSingleton()->isRemoteMode())
        {
            roues.droite.tourne(Remote::getSingleton()->getRightPWM());
            roues.gauche.tourne(Remote::getSingleton()->getLeftPWM());
        }
        else*/
        {
        #if defined(STM32F40_41xxx) || defined(STM32F10X_MD)
            roues.droite.tourne(0.8*MIN(MAX(+linearDutySent-angularDutySent, -engineLimit), engineLimit));
            roues.gauche.tourne(0.8*MIN(MAX(+linearDutySent+angularDutySent, -engineLimit), engineLimit));
        #else
            roues.droite.tourne(MIN(MAX(linearDutySent+angularDutySent, -engineLimit), engineLimit));//*1
            roues.gauche.tourne(MIN(MAX(linearDutySent-angularDutySent, -engineLimit), engineLimit));//*1
        if (testMod && testRunning)
        {
            vitesseLin[testDataToSend] = vitesse_lineaire_atteinte;
            vitesseLinE[testDataToSend] = vitesse_lineaire_a_atteindre;
            linearDuty[testDataToSend] = linearDutySent;

            vitesseAng[testDataToSend] = vitesse_angulaire_atteinte;
            vitesseAngE[testDataToSend] = vitesse_angulaire_a_atteindre;
            angularDuty[testDataToSend] = angularDutySent;
            testDataToSend++;
        }

        #if DEBUG_ASSERV == 1
        /** Pour afficher les courbes d'asservissement : **/
            if(dbgInc<DEBUG_ASSERV_SIZE)
            {
                int index = dbgInc/4;
Pika's avatar
Pika committed

                vitesseLin[index] = vitesse_lineaire_atteinte;
                vitesseLinE[index] = vitesse_lineaire_a_atteindre;
                linearDuty[index] = linearDutySent;
Pika's avatar
Pika committed

                vitesseAng[index] = vitesse_angulaire_atteinte;
                vitesseAngE[index] = vitesse_angulaire_a_atteindre;
                angularDuty[index] = angularDutySent;
                PositionPlusAngle pos = Odometrie::odometrie->getPos();
hilnius's avatar
hilnius committed

                posx[index] = pos.position.x;
                posy[index] = pos.position.y;
                angle[index] = pos.angle;
hilnius's avatar
hilnius committed

Pika's avatar
Pika committed
                dbgInc++;
hilnius's avatar
hilnius committed

hilnius's avatar
hilnius committed
            }
            else
            {

                roues.gauche.tourne(0.0);
                roues.droite.tourne(0.0);
                dbgInc++;
Pika's avatar
Pika committed

            }
        /** FIN **/
        #endif
        roues.gauche.tourne(0.);
        roues.droite.tourne(0.);

    /*** tests ***/
    if (testMod && testRunning)
    {
        testIndex++;
        if (testIndex >= testDuration)
        {
            stopped = true;
            testRunning = false;
            testDataSent = 0;
    if (testMod && !testRunning && testDataSent < testDataToSend && (Clock::getInstance()->elapsedSinceStartup() % (10*Clock::MS_PER_TICK) == 0))
    {
        // send data
#ifndef NO_REMOTE
        KrabiPacket p(KrabiPacket::ASSERV_RESULT);
        p.add((uint32_t) testDataSent);
        p.add(vitesseLin[testDataSent]);
        p.add(vitesseLinE[testDataSent]);
        p.add(linearDuty[testDataSent]);
        p.add(vitesseAng[testDataSent]);
        p.add(vitesseAngE[testDataSent]);
        p.add(angularDuty[testDataSent]);

        Remote::getSingleton()->send(p);

        //Remote::getSingleton()->log("Pika %d / %d", testDataSent, testDataToSend);

        testDataSent++;
#endif
    }
hilnius's avatar
hilnius committed

Pika's avatar
Pika committed

hilnius's avatar
hilnius committed
#endif

void Asservissement::finMatch()
{
    Asservissement::matchFini = true;
    #ifdef ROBOTHW
hilnius's avatar
hilnius committed

Alex's avatar
Alex committed


void Asservissement::setEnabledPIDDistance(bool enabled)
{
    activePIDDistance = enabled;
}

void Asservissement::setEnabledPIDAngle(bool enabled)
{
    activePIDAngle = enabled;
}

void Asservissement::setLinearDuty(float duty)
{
    setEnabledPIDDistance(false);
    fixedLinearDuty = MAX( MIN( duty, FIXED_LINEAR_DUTY_MAX), -FIXED_LINEAR_DUTY_MAX);
}

void Asservissement::setAngularDuty(float duty)
{
    setEnabledPIDAngle(false);
    fixedAngularDuty = MAX( MIN( duty, FIXED_ANGULAR_DUTY_MAX), -FIXED_ANGULAR_DUTY_MAX);
}

void Asservissement::resetFixedDuty()
{
    fixedLinearDuty = 0.;
    fixedAngularDuty = 0.;
}
Alexandre Manoury's avatar
Alexandre Manoury committed

void Asservissement::computeObstacleDetecte(float linearDutySentArgument, float angularDutySentArgument, PositionPlusAngle* positionPlusAngleActuelleArgument)
{
    //Si on a vu un obstacle recemment
    if(this->obstacleDetecte)
    {
        nbUpdateDepuisObstacleDetecte++;

        //Si ça fait longtemps
        if(nbUpdateDepuisObstacleDetecte > (1000/MS_BETWEEN_UPDATE * 5))//5 secondes
        {
            this->obstacleDetecte = false;
            nbUpdateDepuisObstacleDetecte = 0;
            Asservissement::asservissement->resetAsserv();
        }
    }
    else
    {

        //On ajoute les déplacements élémentaires depuis la dernière boucle
        float variationLineaireX = positionPlusAngleActuelleArgument->position.getX()-positionPlusAnglePrecedenteX;
        float variationLineaireY = positionPlusAngleActuelleArgument->position.getY()-positionPlusAnglePrecedenteY;
        float variationAngulaire = positionPlusAngleActuelleArgument->position.getAngle()-positionPlusAnglePrecedenteAngle;

        //En valeur absolue
        if(variationLineaireX < 0)
        {
            variationLineaireX = -variationLineaireX;
        }
        if(variationLineaireY < 0)
        {
            variationLineaireY = -variationLineaireY;
        }
        if(variationAngulaire < 0)
        {
            variationAngulaire = -variationAngulaire;
        }

        deplacementLineaires[0] += variationLineaireX + variationLineaireY;
        deplacementAngulaire[0] += variationAngulaire;

        positionPlusAnglePrecedenteX = positionPlusAngleActuelleArgument->position.getX();
        positionPlusAnglePrecedenteY = positionPlusAngleActuelleArgument->position.getY();
        positionPlusAnglePrecedenteAngle = positionPlusAngleActuelleArgument->position.getAngle();

        //On ajoute les accélérations élémentaires depuis la dernière boucle
        accelerationLineaires[0]+=linearDutySentArgument;

        accelerationAngulaires[0]+=angularDutySentArgument;

        compteurRemplissageQuatum++;

        //Si ça fait un dixième de seconde, on vérifie qu'on n'est pas bloqué
        if(compteurRemplissageQuatum > nombreQuatumParDixiemeDeSeconde)
        {
            compteurRemplissageQuatum = 0;
            float sommageDeplacementLineaires = 0;
            float sommageDeplacementAngulaire = 0;
            float sommageAccelerationLineaires = 0;
            float sommageAccelerationAngulaires = 0;

            //Sommage des 10 derniers 10èmes
            for(int sommage = 0 ; sommage < NB_VERIFICATION_BLOQUAGE_PAR_SECONDE ; sommage++)
            {
                sommageDeplacementLineaires+=deplacementLineaires[sommage];
                sommageDeplacementAngulaire+=deplacementAngulaire[sommage];
                sommageAccelerationLineaires+=accelerationLineaires[sommage];
                sommageAccelerationAngulaires+=accelerationAngulaires[sommage];
            }

            float accelerationLineaireLimite = ACCELER_LIN_MINIMALE_DETECTION_BLOQUAGE * NB_VERIFICATION_BLOQUAGE_PAR_SECONDE * nombreQuatumParDixiemeDeSeconde;
            float accelerationAngulaireLimite = ACCELER_ANG_MINIMALE_DETECTION_BLOQUAGE * NB_VERIFICATION_BLOQUAGE_PAR_SECONDE * nombreQuatumParDixiemeDeSeconde;

            //Si on accélère à fond en ne bougeant pas plus d'un centimètre en une seconde
//            if(((sommageAccelerationLineaires > accelerationLineaireLimite) && (abs(sommageDeplacementLineaires) < 10)) ||
//               ((sommageAccelerationAngulaires > accelerationAngulaireLimite) && (abs(sommageDeplacementAngulaire) < 3)))

            bool stop = false;

            if(sommageAccelerationLineaires > accelerationLineaireLimite)
            {
                if(sommageDeplacementLineaires < DISTANCE_MINIMALE_DETECTION_BLOQUAGE)
                {
                    stop = true;
                }
            }
            else if(sommageAccelerationAngulaires > accelerationAngulaireLimite)
            {
                if(sommageDeplacementAngulaire < ANGLE_MINIMAL_DETECTION_BLOQUAGE)
                {
                    stop = true;
                }
            }

            if(stop)
            {
                obstacleDetecte = true;
                nbUpdateDepuisObstacleDetecte = 0;

//                //Remise à 0 du tableau
                for(int initTableaux = 0 ; initTableaux < NB_VERIFICATION_BLOQUAGE_PAR_SECONDE ; initTableaux++)
                {
                    deplacementLineaires[initTableaux] = 0;
                    deplacementAngulaire[initTableaux] = 0;
                    accelerationLineaires[initTableaux] = 0;
                    accelerationAngulaires[initTableaux] = 0;
                }
                return;
            }

            //Shift du tableau, les valeurs sont plus vieilles
            for(int raz = NB_VERIFICATION_BLOQUAGE_PAR_SECONDE-1 ; raz > 0 ; raz--)
            {
                deplacementLineaires[raz]=deplacementLineaires[raz-1];
                deplacementAngulaire[raz]=deplacementAngulaire[raz-1];
                accelerationLineaires[raz]=accelerationLineaires[raz-1];
                accelerationAngulaires[raz]=accelerationAngulaires[raz-1];
            }

            //Remise à 0 de la case 1
            deplacementLineaires[0] = 0;
            deplacementAngulaire[0] = 0;
            accelerationLineaires[0] = 0;
            accelerationAngulaires[0] = 0;
        }
    }
    return;
}

void Asservissement::resetAsserv()
{
    pid_filter_distance.resetErrors();
    pid_filter_angle.resetErrors();
}

PIDFilterDistance &Asservissement::getPIDDistance()
{
    return pid_filter_distance;
}

PIDFilterAngle &Asservissement::getPIDAngle()
{
    return pid_filter_angle;
}