Page 1 sur 3

Exposition Flop Avril 2022

Posté : jeu. 3 févr. 2022 20:46
par ronan
Tout sur la participation du Bricolab pour l'exposition de Flop

Re: Exposition Flop Avril 2022

Posté : jeu. 3 févr. 2022 21:46
par ronan
comment est foutu la pièce? électricité vient du plafond?

liste du matériel

cahier des charges
* 3 étages
* photo



contraintes

A valider
* piloter moteur pas à pas ou autre
https://electrotoile.eu/moteur-pas-a-pa ... rduino.php
https://www.aranacorp.com/fr/pilotez-un ... c-arduino/
* la luminosité : variable en tension ou en intensité
=> https://www.aranacorp.com/fr/utilisatio ... c-arduino/
https://abc-electronique.com/forum/show ... hp?t=88088
* capteur de proximité : ultrason?
https://zestedesavoir.com/tutoriels/343 ... ultrasons/

* pilotage par arduino? quel arduino

* plan caisson en bois?

Idées :
* cacher dans les montants le cablage, pvc pour les montants?


planning

* tester la faisabilité : moteur, arduino, variation de lumière, capteur de proximité (distance)
* monter le caisson en bois
* code arduino : lecteur de scenario?
* Mise au point scenario seloon les volontés de Flop et position des éléments? Visite de flop au bricolab?
*

Re: Exposition Flop Avril 2022

Posté : mer. 9 févr. 2022 11:06
par FabriceD
Bonjour à tous.

J'ai moi aussi réfléchi au système et j'ai un peu avancé. Je voulais faire ce mail plus tôt mais avec les préparatifs je n'ai pas eu le temps !

1ère bonne nouvelle, il y a des librairies Arduino qui font tout et même plus, ça marche tout seul !

Donc : j'ai profité des éléments du robot tondeuse qui n'est toujours pas assemblé pour faire quelques essais.

- ultrason SR04: ça marche par contre il faudra voir en pratique car lorsque l'on est proche et que l'on se décale un peu on sort vite du champ du capteur. Peut-être mettre 3 capteurs en arc de cercle ? (La librairie gère plusieurs capteurs)
- pilotage moteur L298N: nickel
- moteur à courant continu : je pilote le moto-réducteur (30 t/mn) avec variation de vitesse et sens.
- moteur pas à pas : ma méthode préférée, idem vitesse et sens et l'avantage sur le moteur à courant continu que l'on connaît la position sans avoir à rajouter de capteur.



Afficher le texte des messages précédents

Re: Exposition Flop Avril 2022

Posté : jeu. 3 mars 2022 16:40
par FabriceD
Pour info:
Au cas où j'ai trouvé la doc des circuits intégrés drivers des moteurs pas à pas du traceur A0.

Si besoin, on pourra (même pour un autre projet) extraire les moteurs, récupérer les drivers et faire fonctionner ces moteurs avec un arduino.

Re: Exposition Flop Avril 2022

Posté : lun. 14 mars 2022 22:45
par FabriceD

Re: Exposition Flop Avril 2022

Posté : jeu. 17 mars 2022 17:31
par ronan
T'avances super bien Fabrice.
Ce soir tout est fini donc :ugeek:

Re: Exposition Flop Avril 2022

Posté : sam. 19 mars 2022 01:23
par FabriceD
Pas de panique pour la lampe qui ne s'allume pas, j'ai trouvé : sur le site du fabricant le brochage de la carte de pilotage est faux !!!
:evil:

Re: Exposition Flop Avril 2022

Posté : ven. 25 mars 2022 16:31
par ronan
je me demande s'il ne faut pas séparer l'alim 12V de l'arduino, de l'alim 12V de puissance : lumière et moteur.
Nous avons pu observer des comportements bizarres du sonar.

Re: Exposition Flop Avril 2022

Posté : ven. 25 mars 2022 16:33
par ronan
Code de test unitaire


Code : Tout sélectionner

#include <AccelStepper.h>
#include <AsyncSonarLib.h>
#include <OneButton.h>

#define LIGHT_VEILLE 5
#define LIGHT_VEILLE_BLINK 10
#define LIGHT_ACTIVATION 255
#define LIGHT_VEILLE2 80
#define LIGHT_RAZ 80

#define MOTOR_POS_VEILLE 400


#define MOTOR_REF_0 0
#define MOTOR_REF_MAX 1000


#define DELAY_RAZ 20000

#define DELAY_LIGHT_VEILLE 5000
#define DELAY_LIGHT_VEILLE2 5000
#define DELAY_LIGHT_ACTIVATION 5000

#define DELAY_GO_VEILLE2 20000

#define DELTA_MOVE_MIN 50
#define DELTA_MOVE_MAX 300

#define DEBUG 1


#define WITH_MOTOR 0


// level de log debug
#define LOG_DEBUG 1

#define PIN_LAMP 11
#define PIN_STEP 8
#define PIN_DIR 4
#define PIN_UP A0
#define PIN_DOWN A1
#define PIN_SONAR A5
#define BANDGAP 10
#define MAXSPEED_WORKMDODE 500
#define MAXSPEED_TUNINGMODE 100

struct slope
{
    uint32_t startTime;
    uint8_t startValue;     // (0-255)
    uint8_t stopValue;      // (255-0)
    uint16_t slopeDuration; // (1-65535)
    int32_t currentValue;
};

struct variablesToSave
{
    uint16_t stepToFloor;
    byte dummy_1;     // just for note
    int dummy_2 = -8; // just for note
};

enum enumMotorState
{
    INIT,
    OFF,
    UP,
    DOWN,
};

enumMotorState motorState, previousMotorState;
boolean onEntryState;
int8_t sens;
slope lampSlope;
#ifdef DEBUG
uint32_t u32_cpu_load;
#endif
uint16_t toto, oldtoto, initMeasureRAZ, lastMeasureSensor;

unsigned long myTime, lastTimeStep;

variablesToSave eeprom;

enum enumOeuvreState
{
    VEILLE,
    ACTIVATION, // dès qu'on met la main
    VEILLE2,
    RAZ // on recherche la position 0
};

enumOeuvreState oeuvreState, previousOeuvreState;

enum enumScenarState
{
    INIT_SCENAR,
    RUN
};

enumScenarState scenarState;


enum enumSONARState
{
    INIT_SONAR,
    STABLE
};


struct scenar
{
    enumOeuvreState oeuvreState;
    enumScenarState scenarState;
    unsigned long timeValue; // valeur de temps utilisable pour contrôler ce que l'on veut
    long positionMotor; // position du moteur demandée, on ne change pas tant qu'on n'y est pas
    enumMotorState motorState;
};

scenar currentScenar;
enumSONARState sonarState;

unsigned long lastTSMesure=0;

/***** Prototype definition of code *****/
 void slopeInit(slope *thisSlope, uint16_t startValue, uint16_t stopValue, uint16_t slopeDuration);
  boolean slopeUpdate(slope *thisSlope);
 void PingRecieved(AsyncSonar &sonar);
 void TimeOut(AsyncSonar &sonar);
unsigned int getSonar();

void changeLight(int value);
void changeMotor(long value);
void scenarVeille();
void scenarActivation();
void scenarVeille2();
void scenarRAZ();
/***** Beginning of code *****/

AccelStepper stepper(AccelStepper::DRIVER, PIN_STEP, PIN_DIR);
//AccelStepper stepper(AccelStepper::FULL4WIRE, 2, 3, 5, 6);
AsyncSonar sonar(PIN_SONAR, PingRecieved, TimeOut);
OneButton buttonUp(PIN_UP, true, true);     // active low, pull-up
OneButton buttonDown(PIN_DOWN, true, true); // active low, pull-up

int currentPosition_light;
long currentPosition_motor;

boolean initStart;

unsigned int absTmp(int v){
    return (v>=0)?v:(-1*v);
}

void setup()
{
#ifdef DEBUG
    Serial.begin(250000); // for debug purposes
#endif
    // initialize lamp
    pinMode(PIN_LAMP, OUTPUT);
    analogWrite(PIN_LAMP, 0);

    // buttonUp.attachClick(clickbuttonUp);
    // buttonUp.attachDoubleClick(doubleclickbuttonUp);
    // buttonUp.attachLongPressStart(longPressStartbuttonUp);
    // buttonUp.attachLongPressStop(longPressStopbuttonUp);
    // buttonUp.attachDuringLongPress(longPressbuttonUp);

    // // link the button 2 functions.
    // buttonDown.attachClick(clickButtonDown);
    // buttonDown.attachDoubleClick(doubleclickButtonDown);
    // buttonDown.attachLongPressStart(longPressStartButtonDown);
    // buttonDown.attachLongPressStop(longPressStopButtonDown);
    // buttonDown.attachDuringLongPress(longPressButtonDown);

    // initialize stepper;
    stepper.setMaxSpeed(MAXSPEED_WORKMDODE);
    stepper.setAcceleration(500);

    // initialize sonar
    sonar.Start(500);
    sonarState = INIT_SONAR;

    // initialize motor state machine
    //motorState = INIT;
    //previousMotorState = ~INIT;

    // oeuvreState = RAZ;

    // myTime = millis();
    // changeScenar(RAZ);

    //lastTSMesure=myTime;
    initStart=true;

    // previousOeuvreState =

    // slopeInit(&lampSlope, 0, 10, 3000);
}

void loop()
{
    myTime = millis();

    if(lastTSMesure==myTime||initStart==true){
        initStart=false;
        Serial.println("TEST LUMIERE à 0 seconde");
        analogWrite(PIN_LAMP, LIGHT_VEILLE);

        Serial.println("TEST moteur move(-10)");
        //stepper.move(-10);
        stepper.move(100);
        
        Serial.print("sonar:");
        Serial.println(getSonar());
    }

    if(myTime==(lastTSMesure+5000)){
        Serial.println("TEST LUMIERE à 5 secondes");
        analogWrite(PIN_LAMP, LIGHT_VEILLE2);

        Serial.println("TEST Moteur move(10)");
        stepper.move(500);

        Serial.print("sonar:");
        Serial.println(getSonar());
    }


    if(myTime==(lastTSMesure+10000)){
        Serial.println("TEST LUMIERE à 10 secondes");
        analogWrite(PIN_LAMP, 0);

        Serial.println("TEST Moteur moveTo(0)");
        stepper.moveTo(0);

        Serial.print("sonar:");
        Serial.println(getSonar());
    }

    if(myTime==(lastTSMesure+15000)){
      Serial.println("Reinit myTime à 15s");
      lastTSMesure=myTime+10;
    }
      
  sonar.Update(&sonar);
    stepper.run();
    delay(1);
}


// ----- button Up callback functions

// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void clickbuttonUp()
{
    stepper.move(10);
    // analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //    if(oeuvreState == VEILLE){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //      oeuvreState = ACTIVATION;
    //      Serial.println("VEILLE");
    //    }else if(oeuvreState == ACTIVATION){
    //      analogWrite(PIN_LAMP, LIGHT_ACTIVATION);
    //      oeuvreState = VEILLE2;
    //      Serial.println("ACTIVATION");
    //    }else if(oeuvreState == VEILLE2){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE2);
    //      oeuvreState = RAZ;
    //      Serial.println("VEILLE2");
    //    }else if(oeuvreState == RAZ){
    //      analogWrite(PIN_LAMP, 0);
    //      oeuvreState = VEILLE;
    //      Serial.println("RAZ");
    //    }

} // clickUp

// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclickbuttonUp()
{
    // EEPROM.put(0, eeprom);
    Serial.println("Button up saveEEPROM.");
} // doubleclickbuttonUp

// This function will be called once, when the button1 is pressed for a long time.
void longPressStartbuttonUp()
{
    Serial.println("Button up longPress start");
} // longPressStart1

// This function will be called often, while the button1 is pressed for a long time.
void longPressbuttonUp()
{
    stepper.move(10);
} // longPressbuttonUp

// This function will be called once, when the button1 is released after beeing pressed for a long time.
void longPressStopbuttonUp()
{
    Serial.println("Button up longPress stop");
} // longPressStopbuttonUp

// ... and the same for button Down:

void clickButtonDown()
{
    stepper.move(-10);

    //    if(oeuvreState == VEILLE){
    //      //analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //      changeLight(LIGHT_VEILLE)
    //      oeuvreState = ACTIVATION;
    //      Serial.println("VEILLE");
    //    }else if(oeuvreState == ACTIVATION){
    //      analogWrite(PIN_LAMP, LIGHT_ACTIVATION);
    //      oeuvreState = VEILLE2;
    //      Serial.println("ACTIVATION");
    //    }else if(oeuvreState == VEILLE2){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE2);
    //      oeuvreState = RAZ;
    //      Serial.println("VEILLE2");
    //    }else if(oeuvreState == RAZ){
    //      analogWrite(PIN_LAMP, 0);
    //      oeuvreState = VEILLE;
    //      Serial.println("RAZ");
    //    }

} // clickButtonDown

/**
 * This function is called when the button is pressed. 
 * 
 * It saves the current state of the EEPROM to the EEPROM. 
 * 
 * It then prints a message to the serial monitor
 */
void doubleclickButtonDown()
{
    // EEPROM.put(0, eeprom);
    Serial.println("Button Down saveEEPROM.");
} // doubleclickButtonDown

void longPressStartButtonDown()
{
    Serial.println("Button down longPress start");
} // longPressStartButtonDown

/**
 * Move the stepper motor 10 steps backward.
 */
void longPressButtonDown()
{
    stepper.move(-10);
} // longPressButtonDown

void longPressStopButtonDown()
{
    Serial.println("Button down longPress stop");
} // longPressStopButtonDown

// slopeInit(&mySlope, maxValue, 0, 3000);
void slopeInit(slope *thisSlope, uint16_t startValue, uint16_t stopValue, uint16_t slopeDuration)
{
    thisSlope->startTime = millis();
    thisSlope->startValue = startValue;
    thisSlope->stopValue = stopValue;
    thisSlope->slopeDuration = slopeDuration;
    thisSlope->currentValue = startValue;
}

// slopeUpdate(&mySlope);
/**
 * If the current value is not equal to the stop value, then the current value is calculated by
 * multiplying the time elapsed by the slope duration, and then dividing that by the slope duration.
 * The current value is then added to the start value
 * 
 * @param thisSlope the slope object to update
 * 
 * @return A boolean value.
 */
boolean slopeUpdate(slope *thisSlope)
{
    if (thisSlope->currentValue != thisSlope->stopValue)
    {
        // if((millis() - thisSlope->startTime) <= thisSlope->slopeDuration) {
        thisSlope->currentValue = ((millis() - thisSlope->startTime) * (thisSlope->stopValue - thisSlope->startValue));
        thisSlope->currentValue /= thisSlope->slopeDuration;
        thisSlope->currentValue += thisSlope->startValue;
        return (false);
    }
    else
    {
        return (true);
    }
}

// ping callback
void PingRecieved(AsyncSonar &sonar2)
{
    //Serial.print("Ping: ");
    //Serial.println(sonar2.GetMeasureMM());

    sonarState = STABLE;
}

// timeout callback
void TimeOut(AsyncSonar &sonar2)
{
    sonarState = INIT_SONAR;
    //Serial.println("TimeOut");
}

// enumOeuvreState oeuvreState;
// enumScenarState scenarState;
// unsigned long timeValue; // valeur de temps utilisable pour contrôler ce que l'on veut

/**
 * It changes the state of the current scenar.
 *
 * @param oeuvreState the state of the oeuvre (INIT, PLAY, PAUSE, STOP)
 */
void changeScenar(enumOeuvreState oeuvreState)
{
    currentScenar.oeuvreState = oeuvreState;
    currentScenar.scenarState = INIT_SCENAR;
    currentScenar.timeValue = myTime;
    currentScenar.positionMotor = 0;
    currentScenar.motorState=INIT;

    Serial.println("changeScenar: ");
    switch (currentScenar.oeuvreState)
    {
    case VEILLE:
        Serial.println("VEILLE");
        break;
    case ACTIVATION:
        Serial.println("ACTIVATION");
        break;
    case VEILLE2:
        Serial.println("VEILLE2");
        break;
    case RAZ:
        Serial.println("RAZ");
        break;
    default:
        break;
    }
}

/**
 * Change the light to the value given in parameter.
 *
 * @param value The value to set the pin to.
 */
void changeLight(int value)
{
    // si la valeur est la même que l'actuelle on ne fait rien
    if (value != currentPosition_light)
    {
        analogWrite(PIN_LAMP, value);
        currentPosition_light = value;
        #ifdef LOG_DEBUG
            Serial.print("changeLight: ");
            Serial.println(currentPosition_light);
        #endif
    }
}

/**
 * If the value is different from the current position, move the motor to the new position
 * 
 * @param value the value of the input
 */
void changeMotor(long value)
{
    if(value < MOTOR_REF_0)value=MOTOR_REF_0;
    if(value > MOTOR_REF_MAX)value=MOTOR_REF_MAX;

    // si la valeur est la même que l'actuelle on ne fait rien
    if (value != currentPosition_motor)
    {
        #ifdef WITH_MOTOR
            stepper.moveTo(value);
        #endif
        if(value>currentPosition_motor)currentScenar.motorState=UP;
        else currentScenar.motorState=DOWN;

        currentPosition_motor = value;
        currentScenar.positionMotor = currentPosition_motor;
    // INIT,
    // OFF,
    // UP,
    // DOWN,
        
        #ifdef LOG_DEBUG
            Serial.print("changeMotor: ");
            Serial.println(currentPosition_motor);
        #endif
    }else{
        currentScenar.motorState=OFF;
    }
}

// Vérifie si le moteur est arrivé à destination ou bien?
enumMotorState updateStateMotor(){
    if (currentScenar.positionMotor == stepper.currentPosition()){
        currentScenar.motorState=OFF;
    }
    return currentScenar.motorState;
}



// TODO : permettre d'indiquer si la valeur est correcte ou pas?
unsigned int getSonar(){
    // on retourne
    return sonar.GetMeasureMM();
}


/**
 * If the time is greater than or equal to the delayStop, return true
 * 
 * @param timeStart the time at which the timer starts
 * @param delayStop The time in milliseconds that you want to delay the program.
 * 
 * @return A boolean value.
 */
boolean diffTime(unsigned long timeStart, unsigned long delayStop){
    if (myTime - timeStart >= delayStop){
        return true;
    }
    return false;
}


/**
 * Scenario de veille déclenché après un temps non négligeable 30 secondes
 */
void scenarVeille()
{
    if (currentScenar.scenarState == INIT_SCENAR)
    {
        // on accèlère le mouvement
        stepper.setMaxSpeed(1000);
        stepper.setAcceleration(500);
        changeMotor(MOTOR_POS_VEILLE);
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_VEILLE, DELAY_LIGHT_VEILLE);
        initMeasureRAZ=getSonar();
        currentScenar.scenarState=RUN;
    }
    else
    {
        if(!slopeUpdate(&lampSlope)){            
            changeLight(int(lampSlope.currentValue));
        }else
        {
            //Effet clignotement
            // on peut fare varier la lumière ici
            int lightTmp=int(lampSlope.currentValue)==LIGHT_VEILLE?LIGHT_VEILLE_BLINK:LIGHT_VEILLE;
            slopeInit(&lampSlope, currentPosition_light, lightTmp, DELAY_LIGHT_VEILLE);
        }

        if (sonarState == STABLE)
        {
            // si le sonar est coupé par qq1, on passe en Activation
            // et que la position du moteur est là où on l'a demandé
            if(getSonar() < 1500 && updateStateMotor() == OFF){
                changeScenar(ACTIVATION);
            }
        }
    }

    // uint16_t mesureTmp = sonar.GetMeasureMM();

    // // lumière LIGHT_VEILLE

    // if (mesureTmp < initMeasureRAZ && mesureTmp > 1500 && initMeasureRAZ - mesureTmp > 100)
    // {
    //     // on passe en activation
    //     changeLight(LIGHT_ACTIVATION);
    //     oeuvreState = ACTIVATION;
    //     lastMeasureSensor = mesureTmp;
    //     stepper.moveTo(0);
    //     Serial.println("oeuvreState = ACTIVATION;");
    // }
    // else
    // {
    //     changeLight(LIGHT_VEILLE);
    // }

    // position POSITION_VEILLE
    // lumière LIGHT_VEILLE
}

/**
 * Scenario d'activation
 */
unsigned long lastMoves=0; // dernier mouveent enregistrés que ça soit le moteur qui bouge ou le sonar


void scenarActivation()
{
    // on allume la lumière à la valeur max

    // on fait bouger selon le sonar

    // Si rien pendant 30S on va en veille2

    if (currentScenar.scenarState == INIT_SCENAR)
    {
        // changeMotor(MOTOR_POS_VEILLE);
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_ACTIVATION, DELAY_LIGHT_ACTIVATION);
        lastMeasureSensor = getSonar();
        currentScenar.scenarState = RUN;
    }
    else
    {
        if (!slopeUpdate(&lampSlope))
        {
            lastMoves = myTime;
            changeLight(int(lampSlope.currentValue));
        }
        else
        {
            // si le moteur n'est pas en déplacement : càd dire qu'il a atteint sa position
            if (updateStateMotor() == OFF)
            {
                if (sonarState == STABLE)
                {
                    uint16_t mesureTmp = getSonar();
                    int diffMesure = lastMeasureSensor - mesureTmp;

                    // FIXME : gérer une fonction ABS
                    int absDiffMesure = absTmp(diffMesure);

                    // FIXME : régler les valeurs MIN et MAX
                    if (absDiffMesure > DELTA_MOVE_MIN && diffMesure < DELTA_MOVE_MAX)
                    {
                        changeMotor(currentScenar.positionMotor + diffMesure);
                        lastMoves = myTime;
#ifdef LOG_DEBUG
                        Serial.print("diffMesure > 50 < 500 : ");
                        Serial.println(diffMesure);
#endif
                    }
                    else
                    {
#ifdef LOG_DEBUG
                        Serial.print("diffMesure < 50 || > 500 : ");
                        Serial.println(diffMesure);
#endif
                    }
                }
            }
            else
            {
                // on bouge donc on met à jour le lastMoves
                lastMoves = myTime;
            }
        }

        // si pas de modif du sonar et pas d'action depuis
        if(myTime-lastMoves>DELAY_GO_VEILLE2){
            changeScenar(VEILLE2);
        }



        // // si le sonar est coupé, on passe en Activation
        // if (getSonar() < 1500)
        // {
        //     changeScenar(ACTIVATION);
        // }
    }

}

void scenarVeille2()
{
    // on allume la lumière à la valeur veille2
    // et si on bouge devant le capteur on revient 
    if (currentScenar.scenarState == INIT_SCENAR)
    {
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_VEILLE2, DELAY_LIGHT_VEILLE2);
        initMeasureRAZ=getSonar();
        currentScenar.scenarState=RUN;
    }
    else
    {
        if(!slopeUpdate(&lampSlope)){            
            changeLight(int(lampSlope.currentValue));
        }else
        {
            //Effet clignotement
            // on peut fare varier la lumière ici
            // int lightTmp=int(lampSlope.currentValue)===LIGHT_VEILLE?LIGHT_VEILLE_BLINK:LIGHT_VEILLE;
            // slopeInit(&lampSlope, currentPosition_light, lightTmp, DELAY_LIGHT_VEILLE);
        }
        // si le sonar est coupé par qq1, on passe en Activation
        if(getSonar() < 1500){
            changeScenar(ACTIVATION);
        }
    }
}

/**
 * Scenaria RAZ fait au démarrage du bouzin
 */

void scenarRAZ()
{
    
    // Serial.print("initMeasureRAZ : ");
    // Serial.println(initMeasureRAZ);

    if (currentScenar.scenarState == INIT_SCENAR)
    {
        changeLight(LIGHT_RAZ);

        slopeInit(&lampSlope, 0, LIGHT_VEILLE, DELAY_RAZ);

        // FIXME : RAZ

        // On doit faire remonter jusqu'à 0;
        // on force de -10 
        stepper.moveTo(MOTOR_REF_0);
        currentScenar.scenarState=RUN;

    }
    // On attend 10 secondes
    // else if (diffTime(currentScenar.timeValue,DELAY_RAZ)==TRUE) // && initMeasureRAZ > 2000)
    // {
    //     changeScenar(VEILLE);
    //}
    else
    {
        // on fait une pente pour atteindre la luminosité de VEILLE
        // FIXME  : il faut attendre que le sonar se stabilise
        if(slopeUpdate(&lampSlope) && sonarState == STABLE){
            
            // on va tenter du bloquant
            if(stepper.currentPosition()==MOTOR_REF_0){
                
                
                Serial.print(millis());
                Serial.println(" move -10");
                
                // déplacement relatif de -10
                stepper.move(-10);
                
                // fonction bloquante
                stepper.runToPosition();
                Serial.print(millis());
                Serial.println(" After runToPosition");

                stepper.setCurrentPosition(MOTOR_REF_0);

                initMeasureRAZ = sonar.GetMeasureMM();
                Serial.print("initMeasureRAZ : ");
                Serial.println(initMeasureRAZ);

                // on initialise le current position
                currentPosition_motor=MOTOR_REF_0;

                myTime=millis();
                // on a fini la pente, on y va
                changeScenar(VEILLE);
            }
        }else{
            changeLight(int(lampSlope.currentValue));
        }
    }




    // if (myTime - lastTimeStep > 10000 && initMeasureRAZ > 2000)
    // {
    //     // initMeasureRAZ=sonar.GetMeasureMM();
    //     //  Serial.print("initMeasureRAZ: ");
    //     //  Serial.println(initMeasureRAZ);
    //     //  oeuvreState = VEILLE;
    //     //  scenarState = INIT;
    //     //  stepper.moveTo(-200);
    //     //  Serial.println("oeuvreState = VEILLE;");
    //     changeScenar(VEILLE);
    // }
    // else
    // {





    //     // // on positionne tout en haut avec +10 pas
    //     // // après la position mettre en pause pour éviter que ça bascule
    //     // // initMeasureRAZ=sonar.GetMeasureMM();
    //     // if (currentPosition_light != 1)
    //     // {
    //     //     lastTimeStep = myTime;
    //     // }

    //     // changeLight(1);

    //     // // if(stepper.getCurrentPosition()==0){
    //     // //  on le remonte de 10

    //     // //}
    //     // // TODO : faire remonter et stopper
    //     // stepper.move(0);

    //     // stepper.setCurrentPosition(0);
    //     // // stepper.moveTo(0);
    //     // // Serial.println("oeuvreState = RAZ;");
    //     // // lastTimeStep = myTime;
    // }
}

Re: Exposition Flop Avril 2022

Posté : ven. 25 mars 2022 16:34
par ronan
code avec les scénarios finaux à mettre au point

Code : Tout sélectionner

#include <AccelStepper.h>
#include <AsyncSonarLib.h>
#include <OneButton.h>

#define LIGHT_VEILLE 2
#define LIGHT_VEILLE_BLINK 150
#define LIGHT_ACTIVATION 255
#define LIGHT_VEILLE2 80
#define LIGHT_RAZ 80

#define MOTOR_POS_VEILLE 400


#define MOTOR_REF_0 0
#define MOTOR_REF_MAX 1000


#define DELAY_RAZ 20000

#define DELAY_LIGHT_VEILLE 1500
#define DELAY_LIGHT_VEILLE2 5000
#define DELAY_LIGHT_ACTIVATION 5000

#define DELAY_GO_VEILLE2 20000

#define DELTA_MOVE_MIN 50
#define DELTA_MOVE_MAX 300

#define DEBUG 1


#define WITH_MOTOR 1


// level de log debug
#define LOG_DEBUG 1

#define PIN_LAMP 11
#define PIN_STEP 8
#define PIN_DIR 4
#define PIN_UP A0
#define PIN_DOWN A1
#define PIN_SONAR A5
#define BANDGAP 10
#define MAXSPEED_WORKMDODE 500
#define MAXSPEED_TUNINGMODE 100

struct slope
{
    uint32_t startTime;
    uint8_t startValue;     // (0-255)
    uint8_t stopValue;      // (255-0)
    uint16_t slopeDuration; // (1-65535)
    int32_t currentValue;
};

struct variablesToSave
{
    uint16_t stepToFloor;
    byte dummy_1;     // just for note
    int dummy_2 = -8; // just for note
};

enum enumMotorState
{
    INIT,
    OFF,
    UP,
    DOWN,
};

enumMotorState motorState, previousMotorState;
boolean onEntryState;
int8_t sens;
slope lampSlope;
#ifdef DEBUG
uint32_t u32_cpu_load;
#endif
uint16_t toto, oldtoto, initMeasureRAZ, lastMeasureSensor;

unsigned long myTime, lastTimeStep;

variablesToSave eeprom;

enum enumOeuvreState
{
    VEILLE = 0,
    ACTIVATION, // dès qu'on met la main
    VEILLE2,
    RAZ // on recherche la position 0
};

enumOeuvreState oeuvreState, previousOeuvreState;

enum enumScenarState
{
    INIT_SCENAR,
    RUN
};

enumScenarState scenarState;


enum enumSONARState
{
    INIT_SONAR,
    STABLE
};


struct scenar
{
    enumOeuvreState oeuvreState;
    enumScenarState scenarState;
    unsigned long timeValue; // valeur de temps utilisable pour contrôler ce que l'on veut
    long positionMotor; // position du moteur demandée, on ne change pas tant qu'on n'y est pas
    enumMotorState motorState;
};

scenar currentScenar;
enumSONARState sonarState;

unsigned long lastTSMesure=0;

/***** Prototype definition of code *****/
void slopeInit(slope *thisSlope, uint16_t startValue, uint16_t stopValue, uint16_t slopeDuration);
boolean slopeUpdate(slope *thisSlope);
void PingRecieved(AsyncSonar &sonar);
void TimeOut(AsyncSonar &sonar);

void changeLight(int value);
void changeMotor(long value);
void scenarVeille();
void scenarActivation();
void scenarVeille2();
void scenarRAZ();

AccelStepper stepper(AccelStepper::DRIVER, PIN_STEP, PIN_DIR);
// AccelStepper stepper(AccelStepper::FULL4WIRE, 2, 3, 4, 5);
AsyncSonar sonar(PIN_SONAR, PingRecieved, TimeOut);
OneButton buttonUp(PIN_UP, true, true);     // active low, pull-up
OneButton buttonDown(PIN_DOWN, true, true); // active low, pull-up

int currentPosition_light;
long currentPosition_motor;

unsigned int absTmp(int v){
    return (v>=0)?v:(-1*v);
}

void setup()
{
#ifdef DEBUG
    Serial.begin(250000); // for debug purposes
#endif
    // initialize lamp
    pinMode(PIN_LAMP, OUTPUT);
    analogWrite(PIN_LAMP, 0);

    // initialize stepper;
    stepper.setMaxSpeed(MAXSPEED_WORKMDODE);
    stepper.setAcceleration(500);

    // initialize sonar
    sonar.Start(500);
    sonarState = INIT_SONAR;

    // initialize motor state machine
    motorState = INIT;
    previousMotorState = ~INIT;

    myTime = millis();
    

    //Serial.println("Before Delay setup");
    //delay(10000);
    //Serial.println("After Delay setup");
    changeScenar(RAZ);
}

void loop()
{
    myTime = millis();

    switch (currentScenar.oeuvreState)
    {
        case VEILLE:
            scenarVeille();
            break;
        case ACTIVATION:
            scenarActivation();
            break;
        case VEILLE2:
            scenarVeille2();
            break;
        case RAZ:
            scenarRAZ();
            break;
        default:
            break;
    }

    sonar.Update(&sonar);

    stepper.run();

   // delay(10);
   
}

// ----- button Up callback functions

// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void clickbuttonUp()
{
    // stepper.move(10);
    // analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //    if(oeuvreState == VEILLE){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //      oeuvreState = ACTIVATION;
    //      Serial.println("VEILLE");
    //    }else if(oeuvreState == ACTIVATION){
    //      analogWrite(PIN_LAMP, LIGHT_ACTIVATION);
    //      oeuvreState = VEILLE2;
    //      Serial.println("ACTIVATION");
    //    }else if(oeuvreState == VEILLE2){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE2);
    //      oeuvreState = RAZ;
    //      Serial.println("VEILLE2");
    //    }else if(oeuvreState == RAZ){
    //      analogWrite(PIN_LAMP, 0);
    //      oeuvreState = VEILLE;
    //      Serial.println("RAZ");
    //    }

} // clickUp

// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclickbuttonUp()
{
    // EEPROM.put(0, eeprom);
    Serial.println("Button up saveEEPROM.");
} // doubleclickbuttonUp

// This function will be called once, when the button1 is pressed for a long time.
void longPressStartbuttonUp()
{
    Serial.println("Button up longPress start");
} // longPressStart1

// This function will be called often, while the button1 is pressed for a long time.
void longPressbuttonUp()
{
    // stepper.move(10);
} // longPressbuttonUp

// This function will be called once, when the button1 is released after beeing pressed for a long time.
void longPressStopbuttonUp()
{
    Serial.println("Button up longPress stop");
} // longPressStopbuttonUp

// ... and the same for button Down:

void clickButtonDown()
{
    stepper.move(-10);

    //    if(oeuvreState == VEILLE){
    //      //analogWrite(PIN_LAMP, LIGHT_VEILLE);
    //      changeLight(LIGHT_VEILLE)
    //      oeuvreState = ACTIVATION;
    //      Serial.println("VEILLE");
    //    }else if(oeuvreState == ACTIVATION){
    //      analogWrite(PIN_LAMP, LIGHT_ACTIVATION);
    //      oeuvreState = VEILLE2;
    //      Serial.println("ACTIVATION");
    //    }else if(oeuvreState == VEILLE2){
    //      analogWrite(PIN_LAMP, LIGHT_VEILLE2);
    //      oeuvreState = RAZ;
    //      Serial.println("VEILLE2");
    //    }else if(oeuvreState == RAZ){
    //      analogWrite(PIN_LAMP, 0);
    //      oeuvreState = VEILLE;
    //      Serial.println("RAZ");
    //    }

} // clickButtonDown

/**
 * This function is called when the button is pressed. 
 * 
 * It saves the current state of the EEPROM to the EEPROM. 
 * 
 * It then prints a message to the serial monitor
 */
void doubleclickButtonDown()
{
    // EEPROM.put(0, eeprom);
    Serial.println("Button Down saveEEPROM.");
} // doubleclickButtonDown

void longPressStartButtonDown()
{
    Serial.println("Button down longPress start");
} // longPressStartButtonDown

/**
 * Move the stepper motor 10 steps backward.
 */
void longPressButtonDown()
{
    stepper.move(-10);
} // longPressButtonDown

void longPressStopButtonDown()
{
    Serial.println("Button down longPress stop");
} // longPressStopButtonDown

// slopeInit(&mySlope, maxValue, 0, 3000);
void slopeInit(slope *thisSlope, uint16_t startValue, uint16_t stopValue, uint16_t slopeDuration)
{
    thisSlope->startTime = millis();
    thisSlope->startValue = startValue;
    thisSlope->stopValue = stopValue;
    thisSlope->slopeDuration = slopeDuration;
    thisSlope->currentValue = startValue;
}

// slopeUpdate(&mySlope);
/**
 * If the current value is not equal to the stop value, then the current value is calculated by
 * multiplying the time elapsed by the slope duration, and then dividing that by the slope duration.
 * The current value is then added to the start value
 * 
 * @param thisSlope the slope object to update
 * 
 * @return A boolean value.
 */
boolean slopeUpdate(slope *thisSlope)
{
    if (thisSlope->currentValue != thisSlope->stopValue)
    {
        // if((millis() - thisSlope->startTime) <= thisSlope->slopeDuration) {
        thisSlope->currentValue = ((millis() - thisSlope->startTime) * (thisSlope->stopValue - thisSlope->startValue));
        thisSlope->currentValue /= thisSlope->slopeDuration;
        thisSlope->currentValue += thisSlope->startValue;
        return (false);
    }
    else
    {
        return (true);
    }
}

// ping callback
/**
 * When the sonar sends a ping, print the distance to the object
 * 
 * @param sonar The sonar object that is being used.
 */
void PingRecieved(AsyncSonar &sonar)
{
    //Serial.print("Ping: ");
    //Serial.println(sonar.GetMeasureMM());
    if(sonarState != STABLE)Serial.println("Sonar stable");
    sonarState = STABLE;
}

// timeout callback
void TimeOut(AsyncSonar &sonar)
{
    if(sonarState != INIT_SONAR)Serial.println("Sonar INIT_SONAR");
    sonarState = INIT_SONAR;
    //Serial.println("TimeOut");
}

/**
 * It changes the state of the current scenar.
 *
 * @param oeuvreState the state of the oeuvre (INIT, PLAY, PAUSE, STOP)
 */
void changeScenar(enumOeuvreState oeuvreState)
{
    currentScenar.oeuvreState = oeuvreState;
    currentScenar.scenarState = INIT_SCENAR;
    currentScenar.timeValue = myTime;
    currentScenar.positionMotor = 0;
    currentScenar.motorState=INIT;

    Serial.println("changeScenar: ");
    switch (currentScenar.oeuvreState)
    {
    case VEILLE:
        Serial.println("VEILLE");
        break;
    case ACTIVATION:
        Serial.println("ACTIVATION");
        break;
    case VEILLE2:
        Serial.println("VEILLE2");
        break;
    case RAZ:
        Serial.println("RAZ");
        break;
    default:
        break;
    }
}

/**
 * Change the light to the value given in parameter.
 *
 * @param value The value to set the pin to.
 */
void changeLight(int value)
{
    // si la valeur est la même que l'actuelle on ne fait rien
    if (value != currentPosition_light)
    {
        analogWrite(PIN_LAMP, value);
        currentPosition_light = value;
        #ifdef LOG_DEBUG
            Serial.print("changeLight: ");
            Serial.println(currentPosition_light);
        #endif
    }
}

/**
 * If the value is different from the current position, move the motor to the new position
 * 
 * @param value the value of the input
 */
void changeMotor(long value)
{
    if(value < MOTOR_REF_0)value=MOTOR_REF_0;
    if(value > MOTOR_REF_MAX)value=MOTOR_REF_MAX;

    // si la valeur est la même que l'actuelle on ne fait rien
    if (value != currentPosition_motor)
    {
        #ifdef WITH_MOTOR
            stepper.moveTo(value);
        #endif
        if(value>currentPosition_motor)currentScenar.motorState=UP;
        else currentScenar.motorState=DOWN;

        currentPosition_motor = value;
        currentScenar.positionMotor = currentPosition_motor;
    // INIT,
    // OFF,
    // UP,
    // DOWN,
        
        #ifdef LOG_DEBUG
            Serial.print("changeMotor: ");
            Serial.println(currentPosition_motor);
        #endif
    }else{
        currentScenar.motorState=OFF;
    }
}

// Vérifie si le moteur est arrivé à destination ou bien?
enumMotorState updateStateMotor(){
    if (currentScenar.positionMotor == stepper.currentPosition()){
        currentScenar.motorState=OFF;
    }
    return currentScenar.motorState;
}



// TODO : permettre d'indiquer si la valeur est correcte ou pas?
unsigned int getSonar(){
    // on retourne
    return sonar.GetMeasureMM();
}


/**
 * If the time is greater than or equal to the delayStop, return true
 * 
 * @param timeStart the time at which the timer starts
 * @param delayStop The time in milliseconds that you want to delay the program.
 * 
 * @return A boolean value.
 */
boolean diffTime(unsigned long timeStart, unsigned long delayStop){
    if (myTime - timeStart >= delayStop){
        return true;
    }
    return false;
}


/**
 * Scenario de veille déclenché après un temps non négligeable 30 secondes
 */
void scenarVeille()
{
    if (currentScenar.scenarState == INIT_SCENAR)
    {
       // Serial.println("scenarVeille INIT_SCENAR");
        // on accèlère le mouvement
        stepper.setMaxSpeed(1000);
        stepper.setAcceleration(500);
        changeMotor(MOTOR_POS_VEILLE);
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_VEILLE, DELAY_LIGHT_VEILLE);
        initMeasureRAZ=getSonar();
        currentScenar.scenarState=RUN;
    }
    else
    {
        //Serial.println("scenarVeille RUN");
        if(!slopeUpdate(&lampSlope)){            
            changeLight(int(lampSlope.currentValue));
        }else
        {
            //Effet clignotement
            // on peut fare varier la lumière ici
            int lightTmp=int(lampSlope.currentValue)==LIGHT_VEILLE?LIGHT_VEILLE_BLINK:LIGHT_VEILLE;
            slopeInit(&lampSlope, currentPosition_light, lightTmp, DELAY_LIGHT_VEILLE);
        }

        if (sonarState == STABLE)
        {
            // si le sonar est coupé par qq1, on passe en Activation
            // et que la position du moteur est là où on l'a demandé
            if(getSonar() < 1500 && updateStateMotor() == OFF){
                changeScenar(ACTIVATION);
            }
        }
    }

    // uint16_t mesureTmp = sonar.GetMeasureMM();

    // // lumière LIGHT_VEILLE

    // if (mesureTmp < initMeasureRAZ && mesureTmp > 1500 && initMeasureRAZ - mesureTmp > 100)
    // {
    //     // on passe en activation
    //     changeLight(LIGHT_ACTIVATION);
    //     oeuvreState = ACTIVATION;
    //     lastMeasureSensor = mesureTmp;
    //     stepper.moveTo(0);
    //     Serial.println("oeuvreState = ACTIVATION;");
    // }
    // else
    // {
    //     changeLight(LIGHT_VEILLE);
    // }

    // position POSITION_VEILLE
    // lumière LIGHT_VEILLE
}

/**
 * Scenario d'activation
 */
unsigned long lastMoves=0; // dernier mouveent enregistrés que ça soit le moteur qui bouge ou le sonar


void scenarActivation()
{
    //#ifdef LOG_DEBUG
      
    //#endif
    // on allume la lumière à la valeur max

    // on fait bouger selon le sonar

    // Si rien pendant 30S on va en veille2

    if (currentScenar.scenarState == INIT_SCENAR)
    {
        Serial.println("scenarActivation INIT_SCENAR");
        // changeMotor(MOTOR_POS_VEILLE);
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_ACTIVATION, DELAY_LIGHT_ACTIVATION);
        lastMeasureSensor = getSonar();
        currentScenar.scenarState = RUN;
    }
    else
    {
        //Serial.println("scenarActivation RUN");
        if (!slopeUpdate(&lampSlope))
        {
            lastMoves = myTime;
            Serial.println("!slopeUpdate(&lampSlope) move");
            changeLight(int(lampSlope.currentValue));
        }
        else
        {
            // si le moteur n'est pas en déplacement : càd dire qu'il a atteint sa position
            if (updateStateMotor() == OFF)
            {
                if (sonarState == STABLE)
                {
                    uint16_t mesureTmp = getSonar();
                    int diffMesure = lastMeasureSensor - mesureTmp;

                    // FIXME : gérer une fonction ABS
                    int absDiffMesure = absTmp(diffMesure);

                    // FIXME : régler les valeurs MIN et MAX
                    if (absDiffMesure > DELTA_MOVE_MIN && diffMesure < DELTA_MOVE_MAX)
                    {
                        changeMotor(currentScenar.positionMotor + diffMesure);
                        //Serial.println("lastMoves 2");
                        lastMoves = myTime;
                        Serial.print("lastMoves 2 ");
                        Serial.println(lastMoves);
#ifdef LOG_DEBUG
                        Serial.print("diffMesure > 50 < 500 : ");
                        Serial.println(diffMesure);
#endif
                    }
                    else
                    {
#ifdef LOG_DEBUG
                        Serial.print("diffMesure < 50 || > 500 : ");
                        Serial.println(diffMesure);
#endif
                    }
                }
            }
            else
            {
                // on bouge donc on met à jour le lastMoves
                lastMoves = myTime;
                Serial.print("lastMoves 3 ");
                Serial.println(lastMoves);
            }
        }

        // si pas de modif du sonar et pas d'action depuis
        if(myTime-lastMoves>DELAY_GO_VEILLE2){
            changeScenar(VEILLE2);
        }



        // // si le sonar est coupé, on passe en Activation
        // if (getSonar() < 1500)
        // {
        //     changeScenar(ACTIVATION);
        // }
    }

}

void scenarVeille2()
{
    // on allume la lumière à la valeur veille2
    // et si on bouge devant le capteur on revient 
    if (currentScenar.scenarState == INIT_SCENAR)
    {
        Serial.println("scenarVeille2 INIT_SCENAR");
        // On remet la lumière si besoin
        slopeInit(&lampSlope, currentPosition_light, LIGHT_VEILLE2, DELAY_LIGHT_VEILLE2);
        initMeasureRAZ=getSonar();
        currentScenar.scenarState=RUN;
    }
    else
    {
        Serial.println("scenarVeille2 RUN");
        if(!slopeUpdate(&lampSlope)){            
            changeLight(int(lampSlope.currentValue));
        }else
        {
            //Effet clignotement
            // on peut fare varier la lumière ici
            // int lightTmp=int(lampSlope.currentValue)===LIGHT_VEILLE?LIGHT_VEILLE_BLINK:LIGHT_VEILLE;
            // slopeInit(&lampSlope, currentPosition_light, lightTmp, DELAY_LIGHT_VEILLE);
        }
        // si le sonar est coupé par qq1, on passe en Activation
        if(getSonar() < 1500){
            changeScenar(ACTIVATION);
        }
    }
}

/**
 * Scenaria RAZ fait au démarrage du bouzin
 */

void scenarRAZ()
{
    
    // Serial.print("initMeasureRAZ : ");
    // Serial.println(initMeasureRAZ);

    if (currentScenar.scenarState == INIT_SCENAR)
    {
        //Serial.println("scenarRAZ INIT_SCENAR");
        changeLight(0);

        slopeInit(&lampSlope, 0, LIGHT_RAZ, DELAY_RAZ);

        // FIXME : RAZ

        // On doit faire remonter jusqu'à 0;
        // on force de -10 
        stepper.moveTo(MOTOR_REF_0);
        currentScenar.scenarState=RUN;

    }
    // On attend 10 secondes
    // else if (diffTime(currentScenar.timeValue,DELAY_RAZ)==TRUE) // && initMeasureRAZ > 2000)
    // {
    //     changeScenar(VEILLE);
    //}
    else
    {
        // Serial.println("scenarRAZ RUN");
        // on fait une pente pour atteindre la luminosité de VEILLE
        // FIXME  : il faut attendre que le sonar se stabilise
        if(slopeUpdate(&lampSlope) && sonarState == STABLE){
            
            // on va tenter du bloquant
            if(stepper.currentPosition()==MOTOR_REF_0){
                
                
                Serial.print(millis());
                Serial.println(" move -10");
                
                // déplacement relatif de -10
                stepper.move(-10);
                
                Serial.println(" before runToPosition");
                // fonction bloquante
                stepper.runToPosition();
                Serial.print(millis());
                Serial.println(" After runToPosition");

                stepper.setCurrentPosition(MOTOR_REF_0);

                initMeasureRAZ = sonar.GetMeasureMM();
                Serial.print("initMeasureRAZ : ");
                Serial.println(initMeasureRAZ);

                // on initialise le current position
                currentPosition_motor=MOTOR_REF_0;

                myTime=millis();
                // on a fini la pente, on y va
               changeScenar(VEILLE);
            }
        }else{
            changeLight(int(lampSlope.currentValue));
        }
    }




    // if (myTime - lastTimeStep > 10000 && initMeasureRAZ > 2000)
    // {
    //     // initMeasureRAZ=sonar.GetMeasureMM();
    //     //  Serial.print("initMeasureRAZ: ");
    //     //  Serial.println(initMeasureRAZ);
    //     //  oeuvreState = VEILLE;
    //     //  scenarState = INIT;
    //     //  stepper.moveTo(-200);
    //     //  Serial.println("oeuvreState = VEILLE;");
    //     changeScenar(VEILLE);
    // }
    // else
    // {





    //     // // on positionne tout en haut avec +10 pas
    //     // // après la position mettre en pause pour éviter que ça bascule
    //     // // initMeasureRAZ=sonar.GetMeasureMM();
    //     // if (currentPosition_light != 1)
    //     // {
    //     //     lastTimeStep = myTime;
    //     // }

    //     // changeLight(1);

    //     // // if(stepper.getCurrentPosition()==0){
    //     // //  on le remonte de 10

    //     // //}
    //     // // TODO : faire remonter et stopper
    //     // stepper.move(0);

    //     // stepper.setCurrentPosition(0);
    //     // // stepper.moveTo(0);
    //     // // Serial.println("oeuvreState = RAZ;");
    //     // // lastTimeStep = myTime;
    // }
}