Apertura automatica del gradino del camper

Ciao a tutti, mi rivolgo ancora a voi in quanto mi sono bloccato. A forza di copia ed incolla ho questo codice che vorrei usare per l'apertura automatica del gradino del camper quando apro la porta e la successiva chiusura del gradino alla chiusura della porta.
Montero uno switch magnetico alla porta.

Ora il software "a banco" fa bene il suo lavoro nel senso che se apro la porta il gradino scende e se richiudo in gradino sale.
L'alimentazione del motore deve durare 4" e poi interrompersi in automatico.

/*
  SCALA AUTOMATICA CAMPER

  The circuit:
  - pushbutton attached to pin 2 from +5V
  - 10 kilohm resistor attached to pin 2 from ground
  - LED attached from pin 13 to ground (or use the built-in LED on most
    Arduino boards)

*/

// Variables will change:
int ledState = LOW;             // ledState used to set the LED

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int  RELE_APERTURA_1 = 4;   // RELE APERTURA
const int  RELE_CHIUSURA_1 = 5;   // RELE CHIUSURA
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button


void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(RELE_APERTURA_1, OUTPUT);
  pinMode(RELE_CHIUSURA_1, OUTPUT);

  // initialize serial communication:
  Serial.begin(9600);

  
}


void loop() {

  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState){
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("PORTA CHIUSA");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
      digitalWrite(ledPin, HIGH);
      digitalWrite(RELE_APERTURA_1, HIGH);
      Serial.println("CHIUSURA SCALA");
      delay(4000);
      digitalWrite(ledPin, LOW);
      digitalWrite(RELE_APERTURA_1, LOW);
      Serial.println("SCALA CHIUSA DOPO MOVIMENTO");

    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("PORTA APERTA");
      digitalWrite(ledPin, HIGH);
      digitalWrite(RELE_CHIUSURA_1, HIGH);
      Serial.println("APERTURA SCALA");
      delay(4000);
      digitalWrite(ledPin, LOW);
      digitalWrite(RELE_CHIUSURA_1, LOW);
      Serial.println("SCALA APERTA DOPO MOVIMENTO");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


}

Ciò che vorrei implementare è la possibilità che nel caso in cui apra e richiuda subito la porta il gradino rientri immediatamente e non debba aspettare l'apertura completa per rientrare come accade adesso avendo usato "DELAY".

Ora, so che esiste questa famosa Millis(), sto provando a inserirla nel codice ma è un disastro...
Avete qualche suggerimento?
Vi ringrazio

Buongiorno,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Buongiorno Guglielmo,
ho seguito il tuo prezioso consiglio e mi sono presentato nell’apposita sezione.
Mi voglio scusare per non averlo fatto prima.
Un saluto.

ElvisinLondon:
Ora, so che esiste questa famosa Millis(), sto provando a inserirla nel codice ma è un disastro...
Avete qualche suggerimento?

SI, quello di suggerirti di studiare come si usa la suddetta funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... vedrai che poi ti sarà tutto più chiaro :wink:

Guglielmo

Ok!
Ci provo subito.

Prima di introdurre la nuova funzione che ti interessa, prova a calcolare il tempo di accensione/spegnimento del motore con millis() anziché con delay(). Vedi negli esempi dell'IDE Blink e BlinkWithoutDelay.

Se ci riesci vedrai che la soluzione ti balza agli occhi. Altrimenti posta qui.

Ciao,
P.

Dopo molti tentativi ho dato forma a questo che... NON funziona

/*
  SCALA AUTOMATICA CAMPER

  The circuit:
  - pushbutton attached to pin 2 from +5V
  - 10 kilohm resistor attached to pin 2 from ground
  - LED attached from pin 13 to ground (or use the built-in LED on most
    Arduino boards)
*/

// Variables will change:
int ledState = LOW;             // ledState used to set the LED

// this constant won't change:
const int  buttonPin = 2;                       // interruttore magnetico porta
const int  RELE_APERTURA_1 = 4;   // RELE 1 APERTURA
const int  RELE_CHIUSURA_1 = 5;   // RELE 2 CHIUSURA
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;               // current state of the button
int lastButtonState = 0;        // previous state of the button
int Rele_APERTURA_1_State = 0;
int Last_Rele_APERTURA_1_State = 0;
int Rele_CHIUSURA_1_State = 0; 
int Last_Rele_CHIUSURA_1_State = 0;


unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 4000;           // interval at which to blink (milliseconds)


void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(RELE_APERTURA_1, OUTPUT);
  pinMode(RELE_CHIUSURA_1, OUTPUT);

  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {

  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
     if (buttonState != lastButtonState)
     {  
    // if the state has changed, increment the counter
       if (buttonState == HIGH) 
       {
       // if the current state is HIGH then the button went from off to on:
      // buttonPushCounter++;
       Serial.println("CONTATTO MAGNETICO APERTO");
       Serial.println("PORTA APERTA - APERTURA SCALA");
       Serial.print("number of button pushes: ");
       Serial.println(buttonPushCounter);
       digitalWrite(ledPin, HIGH);
       digitalWrite(RELE_CHIUSURA_1, LOW);        // comando di sicurezza per evitare cortocircuito del motore CC
       delay (200);
       digitalWrite(RELE_APERTURA_1, HIGH);
       Serial.println("DISCESA SCALA");
       //delay(4000);
           if (millis() - previousMillis > interval) 
           {
           previousMillis = millis();        
           digitalWrite(RELE_APERTURA_1, LOW);
           Serial.println("SCALA APERTA - MOTORE SPENTO");
           }
          
       } else 
       {
       Serial.println("CONTATTO MAGNETICO CHIUSO");
       Serial.println("PORTA CHIUSA - CHIUSURA SCALA");
       digitalWrite(ledPin, LOW);
       digitalWrite(RELE_APERTURA_1, LOW);               // comando di sicurezza per evitare cortocircuito del motore CC
       delay (200); 
       digitalWrite(RELE_CHIUSURA_1, HIGH);  
       Serial.println("SALITA SCALA");
       delay(4000);
       digitalWrite(RELE_CHIUSURA_1, LOW);
       Serial.println("SCALA CHIUSA DOPO MOVIMENTO");
       }
    // Delay a little bit to avoid bouncing
    delay(50);
   }
  // save the current state as the last state, for next time through the loop
    lastButtonState = buttonState;
}

![](https://forum.arduino.cc/Users/ISS/Desktop/Schermata 2020-03-29 alle 09.54.22.png)

dal comando "digitalWrite(RELE_APERTURA_1, HIGH);" a "Serial.println("SCALA APERTA - MOTORE SPENTO");" non c'è un tempo di attesa ed io ho bisogno che il motore venga alimentato per 4"

Ho fatto veramente tanti tentativi ma non ne esco...

ElvisinLondon:
Dopo molti tentativi ho dato forma a questo che... NON funziona

Non funziona per diversi motivi. Intanto le operazioni di apertura vengono attivate una sola volta nel momento in cui 'buttonPin' passa da LOW a HIGH, poi quel ramo non viene più eseguito. Inoltre la condizione (millis()-previousMillis>interval) risulta sempre vera perché nel momento in cui viene valutata il valore 'previousMillis' non contiene il tempo di inizio da cui misurare i quattro secondi. In pratica hai cercato di sostituire delay con millis, per usare millis esattamente con la stessa logica di delay (che è quanto si vuole evitare).

È un problema di impostazione logica (descritto qui). Il programma va progettato in modo diverso, e in un modo o nell'altro, più o meno esplicitamente, più o meno in modo semplice o complicato, deve gestire quattro situazioni/fasi diverse e sei eventi:

londonstate.png

Gli eventi e1 e5 avvengono quando si apre la porta
Gli eventi e3 e6 avvengono quando si chiude la porta
Gli eventi e2 e4 avvengono quando scadono i 4 secondi

Visto che la struttura attuale che hai impostato è questa:

SE variazione stato porta:

    SE apertura porta:
        ....

    ALTRIMENTI:
        ....

...volendola mantenere si può pensare ad una logica tipo:

SE variazione stato porta:

    SE apertura porta:
        SE fase CHIUSO:               (evento1)
           relé apertura ON
           memorizza tempo inizio
           fase = APERTURA
        ALTRIMENTI SE fase CHIUSURA:  (evento5)
           relé chiusura OFF
           delay 200
           relé apertura ON
           memorizza tempo inizio
           fase = APERTURA
    
    ALTRIMENTI:
        SE fase APERTO:                (evento3)
           relé chiusura ON
           memorizza tempo inizio
           fase = CHIUSURA
        ALTRIMENTI SE fase APERTURA:   (evento6)
           relé apertura OFF
           delay 200
           relé chiusura ON
           memorizza tempo inizio
           fase = CHIUSURA


SE fase APERTURA  E  trascorso > 4s:   (evento2)
    relé apertura OFF
    delay 200
    fase = APERTO


SE fase CHIUSURA  E  trascorso > 4s:   (evento4)
    relé chiusura OFF
    delay 200
    fase = CHIUSO

Personalmente però trovo più comodo/chiaro ragionare per fasi esplicite ed eventi che avvengono nelle varie fasi:

SE fase CHIUSO:
    SE porta aperta:             (evento1)
       relé apertura ON
       memorizza tempo inizio
       fase = APERTURA
   
ALTRIMENTI SE fase APERTURA:
    SE trascorso > 4s:           (evento2)
       relé apertura OFF
       delay 200
       fase = APERTO
    ALTRIMENTI SE porta chiusa:  (evento6)
       relé apertura OFF
       delay 200
       relé chiusura ON
       memorizza tempo inizio
       fase = CHIUSURA
   
ALTRIMENTI SE fase APERTO:
    SE porta chiusa:             (evento3)
       relé chiusura ON
       memorizza tempo inizio
       fase = CHIUSURA
   
ALTRIMENTI SE fase CHIUSURA:
    SE trascorso > 4s:           (evento4)
       relé chiusura OFF
       delay 200
       fase = CHIUSO
    ALTRIMENTI SE porta aperta:  (evento5)
       relé chiusura OFF
       delay 200
       relé apertura ON
       memorizza tempo inizio
       fase = APERTURA

londonstate.png

Ciao Claudio FF,
ti ringrazio veramente della tua disponibilità... ma non mi è molto chiaro ciò che mi stai guidando a fare...
Mi dispiace.

Ciò che vorrei fare è:
far si che nel caso in cui veda un ostacolo all'apertura della porta( e simultanea discesa del gradino), chiudendo la porta (switch magnetico) il gradino si richiuda subito.

Comprendo però che è ben oltre le mie conoscenze...

Il post #8 è un'analisi del funzionamento che hai descritto, indipendente dal linguaggio di programmazione. Il disegno rappresenta tutte le situazioni di funzionamento possibili. Lo pseudocodice in italiano a fine post è la procedura da eseguire già impostata secondo la logica macchina "se questo allora quello", basta tradurla uno a uno in istruzioni.

SE fase CHIUSO:
    SE porta aperta:
       relé apertura ON
       memorizza tempo inizio
       fase = APERTURA

ALTRIMENTI SE fase APERTURA:
    ....
if (fase == 0)                     // 0 rappresenta chiuso ma si puo` usare una costante
{
    if (digitalRead(...) == ...)   // inserire pin e livello a porta aperta
    {
        digitalWrite(..., ...);    // inserire pin rele' apertura e livello acceso
        previousMillis = millis(); // memorizza tempo inizio
        fase = 1;                  // 1 rappresenta apertura ma si puo` usare una costante
    }
}
else if (fase == 1)
{
    ........

ecc ecc

@Claudio_ff
... non sono scomparso... ci sto lavorando...
Ti ringrazio comunque dei consigli.

Sono arrivato qui...

int stato = 1;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(4, OUTPUT);  // Motore che apre
  pinMode(5, OUTPUT);  // Motore che chiude
  pinMode(13, OUTPUT); // segnalazione porta Aperta

  stato = 0;   // si posiziona sul case 0
}

void loop() {
  //leggo stato interruttore
  int Switch_Magnetico = digitalRead(2);
  Serial.print("Switch_Magnetico: ");
  Serial.println(Switch_Magnetico);
 
  switch (stato) {

    case 0: 
    if (Switch_Magnetico == HIGH) stato = 1;
    if (Switch_Magnetico == LOW) stato = 3;
    break;
    
    case 1:    //PORTA CHIUSA
    Serial.print(" PORTA CHIUSA ");
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    if (Switch_Magnetico == LOW) stato = 2;
    break;

    case 2:  // DISCESA GRADINO
    digitalWrite(4, HIGH);
    delay (4000);
    stato = 3;
    break;
    
    case 3:   // STOP MOTORE DISCESA GRADINO
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
     if (Switch_Magnetico == HIGH) stato = 4;
    break;

    case 4:   // SALITA GRADINO
     digitalWrite(5, HIGH);
    delay 4000);
    stato = 5;
    break;

    case 5:   // STOP MOTORE SALITA GRADINO
    digitalWrite(5, LOW);
    delay(100);
    stato = 1;
    break;
  }
}

ora rimane da inserire Millis();

il problema è che non ho ancora capito dove e come "ancorare" l'inizio del conteggio che per me sarà di 4sec!

Accetto volentieri suggerimenti...

ElvisinLondon:
il problema è che non ho ancora capito dove e come "ancorare" l'inizio del conteggio che per me sarà di 4sec!

Nelle fasi 1 e 3, quando si rileva la condizione di cambio stato di deve anche memorizzare il tempo attuale.

Nelle fasi 2 e 4 al posto del delay si verifica se trascorso il periodo voluto, e solo in quel caso si cambia stato.

Fatto!
Sono felice d'aver lo sketch che funziona come desideravo

/*
 * REALIZZATO CON IDE 1.8.12
 * IL 02 APRILE 2020
 * 
 * Questo sketch fa si che una volta che il contatto magnetico posizionato sulla posta del camper 
 * viene aperto, i relè faranno attivare il motore di discesa del gradino elettrico.
 * Alla chiusura della porta il motore a 12v CC verrà alimentato al contrario in modo tale da far
 * risalire il gradino.
 * 
 * Il tempo di alimentazione è di circa 4sec
 * 
 */





int stato = 1;        //variabile di stato ad 1
unsigned long t0 = 0; // "ancora" per calcolo ritardo di millis
unsigned long t1 = 0; // "ancora" per calcolo ritardo di millis
const long Movimento = 4000; // tempo di movimento del motore 12vCC
const long Delay = 300;      // delay impostato a questo valore

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);   // Switch magnetico posizionato sulla porta del camper
  pinMode(4, OUTPUT);  // Motore che apre
  pinMode(5, OUTPUT);  // Motore che chiude
  pinMode(13, OUTPUT); // segnalazione porta Aperta

  stato = 1;   // ALL'ACCENSIONE,si posiziona sul case 1. questo perche se accendo il 
               // circuito con la porta aperta mi aspetto che il gradino scenda
}

void loop() {
  //leggo stato interruttore
  int Switch_Magnetico = digitalRead(2);
  Serial.print("Switch_Magnetico: ");
  Serial.println(Switch_Magnetico);
 
  switch (stato) {

    case 0: 
    if (Switch_Magnetico == HIGH) stato = 1;  // se porta chiusa vai a case 1
    if (Switch_Magnetico == LOW) stato = 3;   // se porta aperta vai a case 3
    delay(Delay); 
    break;
    
    case 1:    //PORTA CHIUSA
    Serial.print(" PORTA CHIUSA ");
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    Serial.print(" MOTORI SPENTI ");
    if (Switch_Magnetico == LOW) stato = 2;   // se la porta viene aperta vai a case 2
    t0 = millis();
    Serial.print(" t0: ");
    Serial.println(t0);
    delay(Delay);
    break;

    case 2:  // DISCESA GRADINO
    Serial.print(" PORTA APERTA ");
    digitalWrite(4, HIGH);
    digitalWrite(5, LOW);
    Serial.print(" MOTORI DISCESA ACCESO ");
    if (millis() - t0 >= Movimento) stato = 3; // se il tempo di movimento è >= a 4sec vai al case 3
    if (Switch_Magnetico == HIGH) stato = 3; // se la porta si chiude, vai al case 3 
    delay(Delay);
    break;
    
    case 3:   // STOP MOTORE DISCESA GRADINO
    Serial.print(" PORTA APERTA ");
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    Serial.print(" MOTORI SPENTI ");
    if (Switch_Magnetico == HIGH) stato = 4; // se la porta si chiude, vai al case 4
    t1 = millis();
    delay(Delay);
    break;

    case 4:   // SALITA GRADINO
    Serial.print(" PORTA CHIUSA ");
    digitalWrite(4, LOW);
    digitalWrite(5, HIGH);
    Serial.print(" MOTORI SALITA ACCESO ");
    if (millis() - t1 >= Movimento) stato = 1;  // se il tempo di movimento è >= a 4sec vai al case 1
    delay(Delay);
    break;

  }
}

Ora cio che mi piacerebbe implementare è un case 5 che utilizzo solo quando il gradino rientra prima d'aver fatto tutta la discesa.
Ora il motore di rientro rimane alimentato per 4 sec come se avesse fatto tutta la corsa in discesa, per pignoleria mi piacerebbe che il tempo di alimentazione del rientro fosse solo leggermente più lunga del tempo di uscita.

Grazie Claudio_FF dei consigli grazie ai quali ho scoperto il metodo "Macchina a stati".

Il tempo di apertura trascorso già lo hai: millis() - t

Si potrebbe trasformare 'Movimento' da costante a variabile per poter modificare il suo valore, e dove rilevi l'apertura della porta lo puoi variare, in modo che la chiusura avvenga con il nuovo tempo.

Successivamente va riportato al valore 4000.

Problema!
A volte lo sketch si blocca!

Ho installato tutto sul camper, a volte funziona ed ogni tanto si blocca e finche non si ricollega il PC e si ricarica lo sketch non c'è niente da fare. Non cambia nulla neanche togliendo alimentazione o schiacciando il reset. Bisogna ricaricare lo sketch e poi riprende a funzionare perfettamente... per un po'...

Fin'ora si è sempre bloccato a porta aperta e gradino aperto.
Succede che:

  • a porta aperta: ogni due secondi accende e spegne dei relè.
  • a porta chiusa: non succede nulla.

Cosa può essere? E' un problema hardware o ci sono delle criticità nello sketch?
Ho usato un Arduino UNO originale (ma ce l'ho in casa da un po' e potrei averlo danneggiato in passato in qualche strano esperimento...)

Un'altro fattore curioso è che nel momento in cui collego il PC, per caricare lo sketch devo fare vari tentativi, sembra che il PC non comunichi con la scheda.

In un paio di occasioni di "blocco", con pc connesso ad Arduino, ho notato che quando va in tilt, si blocca l'invio dei dati al monitor seriale.

/*
 * REALIZZATO CON IDE 1.8.12
 * IL 02 APRILE 2020
 * 
 * Questo sketch fa si che una volta che il contatto magnetico posizionato sulla posta del camper 
 * viene aperto, i relè faranno attivare il motore di discesa del gradino elettrico.
 * Alla chiusura della porta il motore a 12v CC verrà alimentato al contrario in modo tale da far
 * risalire il gradino.
 * 
 * Il tempo di alimentazione è di circa 4sec
 * 
 */





int stato = 1;        //variabile di stato ad 1
unsigned long t0 = 0; // "ancora" per calcolo ritardo di millis
unsigned long t1 = 0; // "ancora" per calcolo ritardo di millis
const long Movimento = 2000; // tempo di movimento del motore 12vCC
const long Delay = 300;      // delay impostato a questo valore
const long Delay_Pulsante = 200;      // delay impostato a questo valore

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);   // Switch magnetico posizionato sulla porta del camper
  pinMode(4, OUTPUT);  // Motore che apre
  pinMode(5, OUTPUT);  // Motore che chiude
  pinMode(6, OUTPUT);  // Relè che scollega il pulsante a bilancere. Senza questo c'è un corto sulla linea 
                       // data dal cablaggio interno del pulsante
  pinMode(13, OUTPUT); // segnalazione porta Aperta

  stato = 1;   // ALL'ACCENSIONE,si posiziona sul case 1. questo perche se accendo il 
               // circuito con la porta aperta mi aspetto che il gradino scenda
}

void loop() {
  //leggo stato interruttore
  int Switch_Magnetico = digitalRead(2);
  Serial.print("Switch_Magnetico: ");
  Serial.println(Switch_Magnetico);
 
  switch (stato) {

    case 0: 
    if (Switch_Magnetico == HIGH) stato = 1;  // se porta chiusa vai a case 1
    if (Switch_Magnetico == LOW) stato = 3;   // se porta aperta vai a case 3
    delay(Delay); 
    break;
    
    case 1:    //PORTA CHIUSA
    Serial.print(" PORTA CHIUSA ");
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    delay(Delay_Pulsante);
    digitalWrite(6, LOW);
    Serial.print(" MOTORI SPENTI ");
    if (Switch_Magnetico == LOW) stato = 2;   // se la porta viene aperta vai a case 2
    t0 = millis();
    Serial.print(" t0: ");
    Serial.println(t0);
    delay(Delay);
    break;

    case 2:  // DISCESA GRADINO
    Serial.print(" PORTA APERTA ");
    digitalWrite(6, HIGH);
    delay(Delay_Pulsante);
    digitalWrite(4, HIGH);
    digitalWrite(5, LOW);
    Serial.print(" MOTORI DISCESA ACCESO ");
    if (millis() - t0 >= Movimento) stato = 3; // se il tempo di movimento è >= a 4sec vai al case 3
    if (Switch_Magnetico == HIGH) stato = 3; // se la porta si chiude, vai al case 3 
    delay(Delay);
    break;
    
    case 3:   // STOP MOTORE DISCESA GRADINO
    Serial.print(" PORTA APERTA ");
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    delay(Delay_Pulsante);
    digitalWrite(6, LOW);
    Serial.print(" MOTORI SPENTI ");
    if (Switch_Magnetico == HIGH) stato = 4; // se la porta si chiude, vai al case 4
    t1 = millis();
    delay(Delay);
    break;

    case 4:   // SALITA GRADINO
    Serial.print(" PORTA CHIUSA ");
    digitalWrite(6, HIGH);
    delay(Delay_Pulsante);
    digitalWrite(4, LOW);
    digitalWrite(5, HIGH);
    Serial.print(" MOTORI SALITA ACCESO ");
    if (millis() - t1 >= Movimento) stato = 1;  // se il tempo di movimento è >= a 2sec vai al case 1
    delay(Delay);
    break;

  }
}

A me sembra qualche grosso problema hardware, ovvero qualche collegamento sbagliato.

Ho controllato i cablaggi e mi sembra tutto ok. Considera anche che fa molti movimenti senza problemi e poi ad un certo punto di inchioda in un loop tutto suo.
Per controllare i relè 12v “da auto” uso la scheda relè che vedi in allegato e che è applicata direttamente su Arduino. Oltre a ciò ho un cablaggio del contatto magnetico con una resistenza da 10k verso massa e 330 verso D2 da +5v.
Potrebbe essere Arduino che ha qualche problema o potrebbe essere la scheda Relè?
Nei relè da auto dovrei montare un diodo tra + e - ?

Scanbot 8 apr 2020 23.03.pdf (122 KB)

Se metti Arduino sul camper e fai delle prove di funzionamento SENZA collegare nulla ai relé si inchioda? Pensoche la risposta possa essere no, se sperimenti ed è così allora quasi certamente dipende da disturbi elettromagnetici indotti e la scheda che usi è abbastanza una ciofeca, non ha optoisolatori, l'alimentazione è in comune con Arduino e non è separabile il che può provocare il blocco della MCU in caso di disturbi provenienti da mtori, attuatori, ecc.
Fai la prova senza collegare nulla ai relé e vedi, se smette di bloccarsi sai dove risiede il problema e si può iniziare ad intervenire in modo mirato.