Automatización agrícola, problemas con millis

Hola a todo el mundo.
Soy un novato (quedará de manifiesto, estoy seguro), lo siento. Llevo unas semanas en esto y he llegado a un punto donde no logro avanzar.
Mi proyecto pretende automatizar un atomizador agrícola usado para tratar vid. El aparato cuenta con electroválvulas que te permiten, de forma manual, cerrar o abrir la pulverización a izquierda o derecha según necesidad.
La automatización consiste en instalar dos sensores ultrasónicos industriales a cada lado que se encarguen de abrir cuando se detecta una planta y de cerrar cuando no se detecte.
Como el sistema avanza montado en un tractor a una velocidad de entre 5 y 9 km/h y los sensores se montan ligeramente adelantados (en torno a 1m) respecto a la salida de pulverización, se ha de introducir un retardo de activación/cierre entre la detección del sensor y la apertura/cierre de la electroválvula.
La primera parte, es decir, detección y apertura o cierre, más o menos la tengo controlada (no estoy seguro de ello): He intercalado relés y resistencias a GND entre los sensores y Arduino así como entre Arduino y electroválvulas y he intentado hacer un sistema de detección de flancos o cambios de estado. Y mi intención era (y por aquí creo que tiene que andar el error), una vez detectado el cambio de estado en el sensor (cuando detecta pasa a 5V) intercalar millis con el retardo en tiempo correspondiente a una velocidad de avance fija.
Y esto es lo que no funciona. He logrado cierto retardo, pero en la práctica no resulta un tiempo estable: varía sin motivo aparente. Además, otro problema, si la señal del sensor dura menos que el retardo esta no se activa, cosa que me interesaría que no fuera así.

En principio el proyecto era más ambicioso, y es que en mi cabeza estaba la idea de añadir un modulo gps m8m (que ya tengo) para que el retardo se adaptara automáticamente a la velocidad de avance, y desligarlo de la velocidad constante.
No quedando hay, tengo una pantalla LCD1602 que refleje la velocidad y un contador de plantas tratadas.
En fin, esto lo dejaremos para un versión 2.0

Para resumir, lo ideal sería una especie de "espejo" o copia de las señales de cada sensor en su respectiva electroválvula pero con un retardo constante en el tiempo.
Creo que algo se me escapa con millis y no sé qué puede ser.

Aquí os dejo lo que hasta ahora he escrito, por si alguien tiene a bien guiarme:


//Sensores//

int digitalPinSensorDerecho = 6;//SENSOR DERECHO
int digitalPinSensorIzquierdo = 7;//SENSOR IZQUIERDO

int estadoSensorDerecho = 0; // Variable para almacenar valores leidos por el sensor
int estadoSensorIzquierdo = 0;

int lastestadoSensorDerecho = 0; // Variable para almacenar estados
int lastestadoSensorIzquierdo = 0; // Variable para almacenar estados

//Electrovávulas//

int digitalPinValvulaDerecha = 9; // ELECTROVALVULA DERECHA
int digitalPinValvulaIzquierda = 10; // ELECTROVALVULA IZQUIERDA

//Millis//

unsigned long TimeRefDerecho=0;//variable donde guardamos el tiempo 
unsigned long TimeRefIzquierdo=0;//
const unsigned long retardo =2200; //2.2 segundos a 8km/h y 1 metro entre sensor y linea de pulverizacion


void setup() {
 
    pinMode(digitalPinSensorDerecho, INPUT);  // SENSOR DERECHO
    pinMode(digitalPinSensorIzquierdo, INPUT);  // SENSOR IZQUIERDO

    pinMode(digitalPinValvulaDerecha, OUTPUT);   //ELECTROVALVULA DERECHA
    pinMode(digitalPinValvulaIzquierda, OUTPUT);  //ELECTROVALVULA IZQUIERDA}
    

   
    delay(100); //para evitar señales falsas a la activación

}
void loop() {
  
  estadoSensorDerecho = digitalRead(digitalPinSensorDerecho);//leer la función del sensor derecho  
  estadoSensorIzquierdo = digitalRead(digitalPinSensorIzquierdo);

//LADO DERECHO:

  if (estadoSensorDerecho != lastestadoSensorDerecho);{
           
       if(millis()- TimeRefDerecho >= retardo){
             
           
            
            if (estadoSensorDerecho == HIGH){ 
    
              digitalWrite(digitalPinValvulaDerecha,HIGH);
              }
              else {
              digitalWrite(digitalPinValvulaDerecha,LOW);}
              TimeRefDerecho = millis();
    }
  }
     
lastestadoSensorDerecho = estadoSensorDerecho;


//LADO IZQUIERDO:

  if (estadoSensorIzquierdo != lastestadoSensorIzquierdo);{
           
       if(millis()- TimeRefIzquierdo >= retardo){
             
           
            
            if (estadoSensorIzquierdo == HIGH){ 
    
              digitalWrite(digitalPinValvulaIzquierda,HIGH);
              }
              else {
              digitalWrite(digitalPinValvulaIzquierda,LOW);}
              TimeRefIzquierdo = millis();
    }
  }
     
lastestadoSensorIzquierdo = estadoSensorIzquierdo;
  }
         




Bienvenido!

Para empezar, ese punto y coma ahí sobra:

if (estadoSensorDerecho != lastestadoSensorDerecho);{

Esta anulando el IF y supongo que por eso hace cosas raras.

Luego aparte, alinea bien las llaves y el codigo en cada bloque o te volveras loco.
Con eso veras si hay algo mas mal, como esta linea que diria que deberia estar dentro de las llaves:

lastestadoSensorDerecho = estadoSensorDerecho;

Prueba a revisar todo eso. Y para encontrar errores pon Serial.println("Valvula derecha HIGH"); etc. Y prueba si puedes conectado al ordenador, activando el sensor manualmente, etc.

Más allá del error de sintaxis que te marca @anon27210439 tienes un error en el planteo, en la lógica y es por eso que si el pulso es muy corto no te funciona el retardo.

Te dejo una posible solución.
El botón simula el sensor, el LED de la placa es un testigo del estado del sensor, el LED externo simula la válvula (o relé). Puse un retardo de 2 segundos pero lo puedes cambiar, obviamente.

Edito:
Me di cuenta que, aunque la idea es que sirva de guía, el código tal como estaba tenía una utilidad relativa porque lo único que hacía era retrasar la señal.
Lo modifiqué para que además tenga un tiempo fijo de activación.

Con el interruptor a la izquierda funciona como la versión original, solo retrasa la señal.
Con el interruptor a la derecha genera una señal retrasada de duración fija que se dispara con el flanco ascendente.

Puse tiempos de retraso y duración exagerados para que sea más evidente el funcionamiento.
Por otro lado, separé en funciones distintas (aunque muy parecidas) ambos modos de funcionamiento para que resulte más sencillo de entender el funcionamiento de cada modo.
Incluso se podría solamente poner dentro de loop() el código de, por ejemplo, tiempo_fijo() y funcionaría sin problemas.

Espero que lo entiendas y te sea de utilidad.

Mil gracias a ambos. @anon27210439, No había caído en el ";",cosas de novatos.
@MaximoEsfuerzo, tu código inicial parece haber solucionado todos mis problemas hasta ahora. Esta es el híbrido que he hecho entre mi código inicial y el tuyo:


//Sensores//

int digitalPinSensorDerecho = 6;//SENSOR DERECHO
int digitalPinSensorIzquierdo = 7;//SENSOR IZQUIERDO

int estadoSensorDerecho = 0; // Variable para almacenar valores leidos por el sensor
int estadoSensorIzquierdo = 0;

int lastestadoSensorDerecho = 0; // Variable para almacenar estados
int lastestadoSensorIzquierdo = 0; // Variable para almacenar estados

//Electrovávulas//

int digitalPinValvulaDerecha = 9; // ELECTROVALVULA DERECHA
int digitalPinValvulaIzquierda = 10; // ELECTROVALVULA IZQUIERDA

//Millis//

const unsigned long retardo = 600UL; //0.6 segundos a 6km/h y 1 metro entre sensor y linea de pulverizacion.0.45 A 8KM/H. 0.72 a 5km/h
 
unsigned long tiempoHi;//variable donde guardames el tiempo DERECHA 
unsigned long tiempoLo;

bool flancoHi;
bool flancoLo;

unsigned long tiempoHi2;//variable donde guardames el tiempo IZQUIERDA 
unsigned long tiempoLo2;

bool flancoHi2;
bool flancoLo2;

void setup() {
 
    pinMode(digitalPinSensorDerecho, INPUT);  // SENSOR DERECHO
    pinMode(digitalPinSensorIzquierdo, INPUT);  // SENSOR IZQUIERDO

    pinMode(digitalPinValvulaDerecha, OUTPUT);   //ELECTROVALVULA DERECHA
    pinMode(digitalPinValvulaIzquierda, OUTPUT);  //ELECTROVALVULA IZQUIERDA}
    

   
    delay(100); //para evitar señales falsas a la activación

}
void loop() {

  estadoSensorDerecho = digitalRead(digitalPinSensorDerecho);//leer la función del sensor derecho  
  estadoSensorIzquierdo = digitalRead(digitalPinSensorIzquierdo);

//LADO DERECHO:

  if (estadoSensorDerecho != lastestadoSensorDerecho){

    lastestadoSensorDerecho = estadoSensorDerecho;

    if (estadoSensorDerecho == HIGH){ // flanco ascendente, se pulsa boton/sensor
      
      flancoHi = true;
      
      tiempoHi = millis(); 
    }   
    else {// flanco descendente, se libera boton/sensor
      
      flancoLo = true;
      
      tiempoLo = millis();
    }
  }

  if (flancoHi) {
    if (millis() - tiempoHi >= retardo) {
      digitalWrite(digitalPinValvulaDerecha,HIGH);
      flancoHi = false;
    }
  }

  if (flancoLo) {
    if (millis() - tiempoLo >= retardo) {
     digitalWrite(digitalPinValvulaDerecha,LOW);
      flancoLo = false;
    }
  }
  
//LADO IZQUIERDO:

  if (estadoSensorIzquierdo != lastestadoSensorIzquierdo){
           
    lastestadoSensorIzquierdo = estadoSensorIzquierdo; 
           
     if (estadoSensorIzquierdo == HIGH){ // flanco ascendente, se pulsa boton/sensor
    
      flancoHi2 = true;
      
      tiempoHi2 = millis(); 
    }   
    else {// flanco descendente, se libera boton/sensor
      
      flancoLo2 = true;
      
      tiempoLo2 = millis();
    }
  }

  if (flancoHi2) {
    if (millis() - tiempoHi2 >= retardo) {
      digitalWrite(digitalPinValvulaIzquierda,HIGH);
      flancoHi2 = false;
    }
  }

  if (flancoLo2) {
    if (millis() - tiempoLo2 >= retardo) {
     digitalWrite(digitalPinValvulaIzquierda,LOW);
      flancoLo2 = false;
    }
  }
  }
  

Al principio no iba realmente fino; El problema estaba en la duplicación de tu interruptor= dos sensores mandando señal aleatoriamente. No sé como se me ocurrió generar flancos y tiempos de referencia individuales para ambos lados y voilá, está vivoooo!

Llegados a este punto, voy a evolucionarlo poco a poco. Se me ocurre un paso intermedio entre el retardo fijo y la automatización por gps; es lo que montan habitualmente las soluciones comerciales: instalar un potenciómetro para variar el retardo de entrada y salida y poder adaptarse a las necesidades en campo y no necesitar actualizar el código con un pc. Si lo logro, lo siguiente será montar dos potenciómetros uno para el retardo de entrada(activación) y salida (desactivación). No tengo ni idea de cómo hacerlo pero no creo que sea nada difícil.
Os mantendré informados (más bien, solicitaré ayuda :wink:)

Gracias otra vez!

Buenos días! Me interesa ese proyecto!! Te funciona bien??

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.