Combinare due codici, come e dove

Gentili Utenti,

Io come molti altri mi ritrovo al classico bivio in cui si devono unire due codici differenti. Sebbene questi siano stati testati singolarmente, con successo si spera, risulta complicato capire come far combaciare gli stessi in un unico codice.
Vi chiedo supporto in quanto seppur abbia provato a combinarli, nessuna versione ha avuto successo :upside_down_face:

Il primo codice controlla il Solar Tracking monoasse attraverso 4 motori e due fotodiodi (qua versione solo"manuale").

#define enA 9
#define in1 4
#define in2 5
#define fotodiodoPin1 A0
#define fotodiodoPin2 A1
#define buzzerPin 3

int motorSpeedA = 0;

void setup() {
  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(9600);
  
  analogWrite(enA, 0);
}

void loop() {
  int intensitaFotodiodo1 = analogRead(fotodiodoPin1);
  int intensitaFotodiodo2 = analogRead(fotodiodoPin2);
  int differenzaIntensita = abs(intensitaFotodiodo1 - intensitaFotodiodo2);

  Serial.print("Intensita Fotodiodo 1: ");
  Serial.print(intensitaFotodiodo1);
  Serial.print(" - Intensita Fotodiodo 2: ");
  Serial.print(intensitaFotodiodo2);
  Serial.print(" - Differenza di intensita: ");
  Serial.println(differenzaIntensita);

  if (differenzaIntensita > 25) {
    Serial.println("Modalita manuale attivata.");
    tone(buzzerPin, 500, 2000); // Suono di 2 secondi
    activateManualMode();
    noTone(buzzerPin);
  }
}

void activateManualMode() {
  Serial.println("Modalita manuale attivata. Motori inizieranno a ruotare dopo 3 secondi.");
  
  delay(3000); // Attendi 3 secondi prima di far partire i motori

  unsigned long startTime = millis();

  while (millis() - startTime < 43200000) { // 12 ore in millisecondi
    // Imposta i valori delle velocità e delle direzioni dei motori manualmente
  // Puoi modificare questi valori per controllare i motori come desideri
  // Ho modificato la rotazione delle ruote B ossia 1 e 4 in modo che sia maggiore delle altre e che facciano da perno.
  motorSpeedA = 100; // Velocità del motore A (0 = fermo, 255 = velocità massima)
 

  // Controlla che la velocità sia sempre positiva (valore assoluto) per evitare problemi di direzione
  motorSpeedA = abs(motorSpeedA);

  // Imposta la direzione dei motori (avanti o indietro)
  //Ho cambiato io il codice originale in motorspeedB che aveva ">0" con<0 per invertire la rotazione dei motori 2 e 3
  if (motorSpeedA > 0) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
  } else {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
  }

  // Aggiorna i motori con i valori calcolati
  analogWrite(enA, motorSpeedA);

    Serial.println("Motori attivi.");

    delay(500); // Attiva i motori per 0.5 secondi
    motorSpeedA = 0;
   
    analogWrite(enA, motorSpeedA);
    

    Serial.println("Motori fermati.");

    delay(299500); // Fermati per 299.5 secondi (5 minuti)
  }
}

Mentre il secondo codice controlla la velocità di rotazione di una ventola attraverso un mosfet e un sensore di temperatura.

#define PIN_LM35 A3
float temperatura;
const int fan_control_pin = 7;

void setup() {
  pinMode(fan_control_pin, OUTPUT);
  analogWrite(fan_control_pin, 0);  // Inizializza la velocità a 0 (ventola spenta)
  Serial.begin(9600);
}

void loop() {
  int valore = analogRead(PIN_LM35);
  float temperatura = valore / 2.046;

  Serial.print("Temperatura: ");
  Serial.print(temperatura);
  Serial.println("°C");

  if (temperatura > 50.0) {
    analogWrite(fan_control_pin, 255);   
  } else if (temperatura > 48.0) {
    analogWrite(fan_control_pin, 250);   
  } else if (temperatura > 46.0) {
    analogWrite(fan_control_pin, 240);   
  } else if (temperatura > 44.0) {
    analogWrite(fan_control_pin, 230);   
  } else if (temperatura > 42.0) {
    analogWrite(fan_control_pin, 220);   
  } else if (temperatura > 40.0) {
    analogWrite(fan_control_pin, 210);   
  } else if (temperatura > 38.0) {
    analogWrite(fan_control_pin, 200);   
  } else if (temperatura > 36.0) {
    analogWrite(fan_control_pin, 190);   
  } else if (temperatura > 34.0) {
    analogWrite(fan_control_pin, 180);   
  } else if (temperatura > 32.0) {
    analogWrite(fan_control_pin, 160);   
  } else if (temperatura > 31.0) {
    analogWrite(fan_control_pin, 140);   
  } else if (temperatura > 30.0) {
    analogWrite(fan_control_pin, 120);   
  } else if (temperatura > 29.0) {
    analogWrite(fan_control_pin, 90);    
  } else {
    analogWrite(fan_control_pin, 0);     
  }
  
  delay(1000);
  
}

Vorrei che i due riescano a lavorare indipendentemente l'uno dall'altro, in modo che sia possibile usare un solo arduino invece che due. Chiedo perdono se la domanda può risultare troppo facile, ma sono sicuro di non essere l'unico in questa situazione.

Ogni consiglio è più che accetto.

Grazie molte!

Ciao, premesso che sono un neofita e solitamente sono io a fare domande, do comunque il mio pensiero. Credo proprio tu debba sostituire i delay con la millis, almeno io farei così per cominciare, poi credo ti basti "spostare " uno dei due codici nell'altro.
Ciao

Come dice lcdsun, con dei delay di 0,5s, 3s e 5 minuti(!) non puoi pensare di fare altro durante quelle pause. Devi reimpostare il programma in maniera che non si fermi mai, ma giri sempre velocemente controllando continuamente se sono trascorsi quei 3 secondi o quei 5 minuti, eventualmente facendo uso di una macchina a stati finiti, cioè facendo scorrere degli stati numerici ed eseguendo il necessario in ogni stato.

il secondo potrebbe andare, è mal pensato e peggio realizzato, ma potrebbe andare, meglio sarebbe stato dedicare un po' di tempo allo studio del linguaggio e usare map e constrain, comunque così dovrebbe andare, e pure essere integrabile senza problemi

il primo invece è un museo degli errori, alcuni tali da essere veri e propri "orrori"
oltretutto non va, nel senso che non solo è "orrendo", ma proprio non fa il suo lavoro,

serve ancora molto studio del linguaggio e anche molto "studio del problema" per poter scrivere due programmi tra loro integrabili

il consiglio è di ricominciare ex-novo i due programmi e ridurli ai loro minimi termini, collaudarli bene, visto che per ora il numero uno non supererebbe il collaudo, e solo dopo riunirli

consigli sul 2 li abbiamo dati
consigli sull'uno?
buttarlo via e ripensarlo da capo

PS
sulla base dlla nostra esperienza non vale mai la pena di "integrare due programmi", si fa prima a scriverne ex-novo uno che fa le due cose assieme ed in maniera organica

PPS
non ci credete al "museo degli errori"?

 motorSpeedA = 100; // Velocità del motore A (0 = fermo, 255 = velocità massima)
 

  // Controlla che la velocità sia sempre positiva (valore assoluto) per evitare problemi di direzione
  motorSpeedA = abs(motorSpeedA)

magari si fosse pensato a quello che si era scritto una riga prima

e dopo se ne trovano ancora

PPPS
come indicazione, i due programmi, ai minimi termini, non supererebbero un decimo della loro lunghezza attuale,

Anzi, è il tormentone comune :slightly_smiling_face: Ora la soluzione è quanto descritto in questo post: https://forum.arduino.cc/t/consiglio-su-come-sostituire-delay-con-millis/500228/9

Nel caso specifico, visto che il primo codice è un abbozzo, una traduzione in macchina a stati (che esegue le stesse operazioni con le stesse temporizzazioni su cui non entro nel merito della correttezza) potrebbe essere questa:

#define enA 9
#define in1 4
#define in2 5
#define fotodiodoPin1 A0
#define fotodiodoPin2 A1
#define buzzerPin 3
#define SECOND 1000UL
#define MINUTE 60000UL
#define HOUR   3600000UL

int motorSpeedA = 0;
int st_inseguitore = 0;  // stato processo inseguitore da 0 a 4
unsigned long t1;
unsigned long startTime;

//------------------------------------------------------------

void setup() {
    pinMode(enA, OUTPUT);
    pinMode(in1, OUTPUT);
    pinMode(in2, OUTPUT);
    pinMode(buzzerPin, OUTPUT);
    Serial.begin(9600);
    analogWrite(enA, 0);
}

//------------------------------------------------------------

void loop() {
    switch (st_inseguitore)
    {
        case 0:  // Misure iniziali, attesa differenza intensità > 25
        {
            int intensitaFotodiodo1 = analogRead(fotodiodoPin1);
            int intensitaFotodiodo2 = analogRead(fotodiodoPin2);
            int differenzaIntensita = abs(intensitaFotodiodo1 - intensitaFotodiodo2);
            Serial.print("Intensita Fotodiodo 1: ");
            Serial.print(intensitaFotodiodo1);
            Serial.print(" - Intensita Fotodiodo 2: ");
            Serial.print(intensitaFotodiodo2);
            Serial.print(" - Differenza di intensita: ");
            Serial.println(differenzaIntensita);
            if (differenzaIntensita > 25) {
                Serial.println("Modalita manuale attivata.");
                tone(buzzerPin, 500, 2000); // Suono di 2 secondi
                Serial.println("Modalita manuale attivata. Motori inizieranno a ruotare dopo 3 secondi.");
                t1 = millis();
                st_inseguitore = 1;
            }
            break;    
        }

        case 1: // Attendi 3 secondi prima di far partire i motori
            if (millis()-t1  >=  3*SECOND) {
                startTime = millis();
                st_inseguitore = 2;
            }
            break;            
        
        case 2:
            motorSpeedA = 100; // Velocità del motore A (0 = fermo, 255 = max)
            motorSpeedA = abs(motorSpeedA);
            if (motorSpeedA > 0) {
                digitalWrite(in1, LOW);
                digitalWrite(in2, HIGH);
            } else {
                digitalWrite(in1, HIGH);
                digitalWrite(in2, LOW);
            }
            analogWrite(enA, motorSpeedA);
            Serial.println("Motori attivi.");
            t1 = millis();
            st_inseguitore = 3;
            break;
            
        case 3: // Attende 0.5 secondi con motori attivi
            if (millis() - t1  >= 500) {
                motorSpeedA = 0;
                analogWrite(enA, motorSpeedA);
                Serial.println("Motori fermati.");
                st_inseguitore = 4;
            }
            break;            
            
        case 4: // Attende per 5 minuti (compresi i 0.5 precedenti)
            if (millis()-t1  >=  5*MINUTE) {
                if (millis()-startTime  >=  12*HOUR)
                    st_inseguitore = 0;
                else
                    st_inseguitore = 2;
            }
            break;            
    }//end switch
}

Nota che l'esecuzione avviene attraverso un selettore di stato attivo realizzato con switch, e una variabile di controllo: 'st_inseguitore'. Il tutto realizza una macchina a stati rappresentabile così:

678543345345

Solo lo stato 2 è "anomalo" in quanto non attende qualcosa, ma esegue una serie di operazioni comuni per passare subito allo stato 3 (scritto in forma più "canonica" quello stato dovrebbe sparire ed essere accorpato nel 3 come operazioni da eseguire una volta sola all'attivazione dello stato).

La cosa importante è che nessuno stato blocca mai l'esecuzione con delay o con cicli for/while, quindi il loop gira sempre alla massima velocità possibile. Questo permette di aggiungere altri processi (sempre a stati) indipendenti.

Attenzione alla dichiarazione di variabili dentro il case. Nel case 0: ci sono tre dichiarazioni, se proprio sono necessarie racchiudi il codice tra le graffe.
Io da recente ho commesso questo errore, compilava correttamente ma non eseguiva il case 1:

Ciao.

Vero, ci casco sempre :roll_eyes: è che solitamente non mi serve fare dichiarazioni dentro ai case. Grazie ho aggiunto le due graffe al case 0.

Al posto di quelle serie di if puoi provare il codice seguente?

uint16_t calPwm(float th, float stp) {
    float dth = th - stp;
    uint16_t pwm = dth * 6.8 + 90;
    if (pwm > 255)
        pwm = 255;
    return pwm;
}

La chiamata a funzione richiede 2 argomenti:

  • th è la temperatura misurata che nel tuo caso equivale alla variabile
    temperatura
  • stp è il setpoint, cioè la temperatura che si desidera mantenere ad esmpio 25°

Ad esempio se metti il seguente codice alla fine del setup():

float temperatura = 25;
    for (byte i=0; i<255; i++) {
        
        Serial.print(temperatura);
        Serial.print("\t");
        Serial.println(calPwm(temperatura, 25));
        temperatura += 0.1; 
    }

Ottieni questo output parzialmente riportato:

25.00	90
25.10	90
25.20	91
25.30	92
25.40	92
25.50	93
25.60	94
25.70	94
25.80	95
25.90	96
26.00	96
26.10	97
26.20	98
26.30	98
26.40	99
26.50	100
26.60	100
26.70	101
26.80	102
26.90	102
27.00	103
27.10	104

temeprature > 49.40°C pwm=255

Ciao.