Proyecto arranque generador eléctrico en instalación fotovoltaica

Hola a todos. Este es mi primer post en el foro, hace poco que me he inmerso en el mundo Arduino.
Mi primer proyecto controlará el arranque y parada de un generador eléctrico Genery jaca de gasolina con arranque electrónico. Será necesario controlatar la palanca del aire del carburador para arrancar en frio. El generador esta conectado a un inversor- regulador voltronic para realizar la carga de baterías cuando hay varios días sin sol. Utilizaré una señal de contacto seco a 220v que posee el inversor para controlar el arranque y parada del generador. Cuando las baterías presenten un voltaje bajo el contacto esta cerrado y hay voltaje, cuando las baterías alcance el voltaje de flotación el contacto se abre.
Los materiales serán:
-placa arduino UNO
-servo motor 9g SG90
-modulo sensor de infrarrojos
-relé de 220v
-2 modulo rele 5v
-resistencia 10 Ohms
-protoboard
El funcionamiento será:
1º el relé de 220 se cerrará y funcionara como el interruptor de inicio de programa.
3º el servo motor moverá la palanca del aire del motor del generador a la posición de cerrado.
2º el relé de 5v se cerrará y pulsara el botón de arranque durante 2 seg.
4º el sensor de infrarrojos comprobará que hay arranque a través de las revoluciones.
5º si hay revoluciones la palanca volverá a la posición de abierto, de lo contrario se repetirá el punto 2.
6º cuando el relé de 220 se abra, el relé de 5 v pulsara el botón de parada 3 seg.

Adjunto imagen de un diseño aproximado en protoboard.

Este sería el codigo:

// SISTEMA DE ARRANQUE DE GENERADOR ELECTRICO DE GASOLINA CON PALANCA DE AIRE


#include <Servo.h> // incluimos la libreria de servo
Servo myservo;  // Crear el objeto servo para controlar el servo

// Constantes que no cambian:
const int releOn = 2;       // EL pin del rele de inicio de sistema
const int releArranque =  13;      // El pin  del rele de arranque
const int releParo = 6;           // El pin del rele de paro
const int sensor = 5;          // El pin del sensor de infrarrojoS  RPM PARA DETERMINAR SI EL MOTOR HA ARRANCADO
// variables que cambiarán:
int estadoReleOn = 0;         // variable para leer el stado del rele de inicio
int posServo = 0;    // variable para almacenar la posicion del servo 
int rpm ; // variable del cuenta kilometro 

void setup() {
  // seleccionamos los pines que sera de salida:
  pinMode(releArranque, OUTPUT); // 
  pinMode(releParo, OUTPUT);
  myservo.attach(9);  // el servo se atacara por el pin 9
  // seleccionamos los pines  de entrada:
  pinMode(releOn, INPUT);
  pinMode(sensor, INPUT);
}

void loop() {
  // leer el estado del valor de rele de inicio de sistema
  estadoReleOn= digitalRead(releOn);
  rpm= digitalRead(sensor);
  // chequear si el rele de inicio esta cerrado. Si lo está, el estadoRele es HIGH:
  if (estadoReleOn == HIGH) {
      //1º paso: mover la palanca del aire a cerrado a través del servo. Pasar de 0(abierto) grados a 90º(cerrado)
    
       for (posServo = 0; posServo <= 90; posServo += 1) ;  //ir de 0 a 90 grados  // en pasos de un grado
       myservo.write(posServo);                            // decirle al servo que vaya a la posicion 'posServo'
       delay(2000);                                      //esperar 2 seg  para que el servo alcance la posicion
    
    // 2º paso: pulsar el boton de arranque mediante el rele 1,5 seg y soltarlo.
    digitalWrite(releArranque, HIGH);
    delay(1500);
    digitalWrite(releArranque,LOW);
   
    // 3º paso: conprobar si hay revoluciones en el motor y por lo tanto ha arrancado. si no hay revoluciones volver al 2º paso y repetir 3 veces.

    

      if (rpm >=100) {    // las rpm son mayores a 100 y entonces ha arrancado
            // 4º paso: mover la palanca de aire a abierto a traves del servo. Pasar de 90º( cerrado) a 0º (abierto)
       for (posServo = 90; posServo <= 0; posServo += 1) ;  //ir de 90 a 0 grados  // en pasos de un grado
       myservo.write(posServo);                            // decirle al servo que vaya a la posicion 'posServo'
       delay(500);                                      //esperar 2 mseg  para que el servo alcance la posicio
        
      }
      else { // repetir el proceso otra vez
        digitalWrite(releArranque, HIGH);
        delay(1500);
        digitalWrite(releArranque,LOW);

               if (rpm >=100) {    // las rpm son mayores a 100 y entonces ha arrancado
              // 4º paso: mover la palanca de aire a abierto a traves del servo. Pasar de 90º( cerrado) a 0º (abierto)
             for (posServo = 90; posServo <= 0; posServo += 1) ;  //ir de 90 a 0 grados  // en pasos de un grado
              myservo.write(posServo);                            // decirle al servo que vaya a la posicion 'posServo'
              delay(500);   //esperar 2 mseg  para que el servo alcance la posicion

               }
        
    
  } 
  }
  else {
    // soltar el boton de arranque mediante rele
   digitalWrite(releParo, HIGH);
   delay(4000);
   digitalWrite(releParo,LOW);
    
  }
}

He verificado el código y no presenta errores, pero necesito que me echéis una mano con una dudas.
La primera es si el proceso" loop" se va a efectuar solo una vez, o se repetirá.
El servo seleccionado no se si tendrá la suficiente fuerza, ya que nunca lo he probado y la palanca necesita un poco de fuerza para moverse.
Quisiera que intentara hacer el proceso de arranque y comprobación de rpm unas 5 veces ; en el código se repite el proceso solo una vez a través de" if "copiado en el código. ¿Existe otra manera de repetir un proceso sin utilizar varias veces "if" en el mismo código?.
Espero vuestras opiniones.
Un Saludo.

Colega antes de responder sus preguntas, su código presenta varios errores

Primero,

rpm= digitalRead(sensor);

Con esa instrucción rpm sera HIGH o LOW. No valores numéricos como los que usted quiere para usar en las sentencias if. Se supone que la variable rpm almacenará las rpm (valga la redundancia) por lo que debe usar es

rpm = analogRead(sensor)

Por lo tanto también debe cambiar conectar el sensor a un pin analógico (A0, A1, etc). Ahora, analogRead da como resultado un valor entre 0 y 1023 por lo que debe aplicar una ecuación que le permita equivaler las rpm con esos valores discretos para poder usar estas sentencias

if (rpm >= 100)

También puede cambiar la posición de la sentencia. Como esta ahora, usted lee las rpm (que inicialmente son 0), luego ejecuta el arranque y luego ejecuta el if. Cuando se ejecute el if, el valor rpm sera 0 porque el analogRead se llamo antes del arranque y tendrá que esperar el segundo ciclo de ejecución para que el valor rpm cambie. Por lo tanto es mejor:

  1. Leer el estado de releOn
  2. Ejecutar el arranque
  3. Leer las rpm
  4. Ejecutar if de las rpm

Segundo, ajustar la sintaxis de las sentencias for porque las instrucciones quedaron por fuera de estas y no se van a ejecutar. Se puede escribir mejor así:

for (posServo = 0; posServo <= 90; posServo ++)  //ir de 0 a 90 grados  // en pasos de un grado
{
  myservo.write(posServo);// decirle al servo que vaya a la posición 'posServo'
  delay(22); //esperar 22 ms entre avance y avance
}
for (posServo = 90; posServo >= 0; posServo --)  //ir de 90 a 0 grados  // en pasos de un grado
{
  myservo.write(posServo);// decirle al servo que vaya a la posición 'posServo'
  delay(22); //esperar 22 ms entre avance y avance
}

Aunque acá si aclaró que nunca he trabajado con la libreria Servo por lo que desconozco si se requieren sentencias for para controlar los servos usando dichas librería. En caso de que si se requieran for, si debe corregir su código.

Por último, como entendí el diagrama, creo que el uso de botones es redundante pues los reles ya actúan como interruptores. Es decir, se puede conectar los reles directamente a lo que quiere controlar

Respondiendo ahora si sus preguntas

  1. Regla de Arduino:
    Todo lo declarado por fuera de Setup y Loop, por ejemplo la declaración de variables y pines --> Se ejecuta 1 vez (NO aplica para funciones)
    Setup -> Se ejecuta 1 vez
    Loop -> Se ejecuta "infinitamente".
    Por lo que la respuesta es si. Mientras el Arduino este energizado, por lo general todo lo que este dentro del Loop se ejecutará infinitamente (bucle). En su caso, el loop terminará con el último else y volverá a comenzar en la instrucción estadoReleOn

  2. La verdad, teniendo en cuenta todo los detalles que da, no creo que el SG90 sirva para mover la palanca pues este es un microservo y por lo tanto el torque que pueden ejercer es mínimo. Por lo tanto, es mejor cambiarlo por un servomotor de mucho mas torque. Igualmente también verificar lo del sensor infrarrojo. Hay sensores especializados para medir RPM por lo que sería mas óptimo ello. Si va es a usar un sensor IR de obstáculos o seguidor de línea, se debe hace un montaje especial para que el sensor pueda medir la rotación.

  3. El código puede mejorarse sustancialmente si hace uso de Funciones. Esto es un poco intermedio por lo que es bueno que consulte documentación sobre ello. Puede implementar una función de arranque, otra de parada, y otra de sensado y llamarlas en el loop según desee. Si de pronto es muy complejo ello, entonces puede implementar un while o for para comprobar las rpm varias veces antes de accionar el servo.

While es poderoso si quiere obligar al programa a que solo ejecute el control del servo cuando las rpm sean mayor o igual a 100. Si las rpm son menores a 100, que ejecute el control del rele de arranque. Con ello se ahorra buena parte del código (en especial los else)

rpm = analogRead(sensor);

while (rpm < 100)
{
  ...instrucciones de arranque...
  rpm = analogRead(sensor);
}
if (rpm >= 100) {
...instrucciones del if...

For es mas laxo en ese sentido pero sirve para lo que usted quiere. Puede ejecutar 5 veces el sensado de rpm, por ejemplo, cada segundo.

for (int i = 0; i <= 5; i++)
{
 rpm = analogRead(sensor);
 delay(1000)
}
...demás instrucciones...

Finalmente, la idea del montaje es muy buena para lo que quiere hacer. Lo invito a como decimos en Colombia, "cacharrearle" al proyecto: Leer sobre toda la programación en Arduino (así aprendí yo muchas cosas "ocultas" que me ayudaron a mejorar sustancialmente la forma en que escribo códigos), ver ejemplos en Internet, usar simuladores como Proteous o Tinkercad que le permiten ir probando su montaje y código antes de pasarlo a la práctica (y ahorrarse siempre desastres y gastos económicos en caso de alguna falla), y como no, usar estos foros para resolver duras.

Bueno, yo voy a ser mas puntual que @yiosef que dio por sentado que el modulo de rpm entrega un valor analógico, algo digamos poco probable.

Por lo que vi en la imagen ampliada tienes un modulo IR indicado como KeyesISR, el mismo esta conectado al pin 5.
Defines dicho pin como entrada INPUT.

En tu código tienes numeros delay() que solo complicarán las cosas, ya te lo adelanto.

Te hace falta una rutina de interrupción que se active con cada flanco del sensor de RPM o nunca vas a contar RPM.
Un modulo digital jamas entrega señales analógicas asi que todo lo que veo a continuación esta mal salvo por el hecho que te estoy mencionando.
Lo primero es que cambies el pin 5 del sensor RPM al pin 2 o 3. Tu elige pero esos son los adecuados para un UNO.

Como en el pin 2 tienes un rele y eso no es relevante lo envias al pin 12 y listo.
Liberado el pin 2, conecta ahi el sensor del modulo IR.

Iba a darte consejos de como modificar tu código pero mejor te digo como medir rpm e intenta agregarlo a tu código porque la verdad no entiendo que quieres hacer.

const int sensor = 2; // Hall sensor at pin 2
volatile byte counts;
unsigned int rpm; //unsigned gives only positive values
unsigned long previoustime;

void count_function() { //The ISR function Called on Interrupt Update counts
  counts++;
}

void setup() {
  Serial.begin(9600);
  //Intiates Serial communications
  attachInterrupt(0, count_function, RISING); //Interrupts are called on Rise of Input
  pinMode(sensor, INPUT); //Sets sensor as input
  counts  = 0;
  rpm     = 0;
  previoustime = 0; //Initialise the values
}
void loop() {
  mido_rpm();
}

void mido_rpm() {
  delay(1000);//Update RPM every second
  detachInterrupt(0); //Interrupts are disabled
  rpm = 60*1000/(millis() - previoustime)*counts;
  previoustime = millis(); //Resets the clock
  counts = 0; //Resets the counter
  Serial.print("RPM=");
  Serial.println(rpm); //Calculated values are displayed
  attachInterrupt(0, count_function, RISING); //Counter restarted
}

Mi consejo es que tomes este código, verifiques que lee RPM y luego sigue desde acá agregando las condiciones para actuar en consecuencia con el servo

Gracias por vuestros consejos yiosef y surbyte.
Yiosef he realizado los cambios que estaban mal en el código y me sugeriste que cambiara. La verdad que estoy un poco verde y me he estado documentando estos días para ver como ir puliendo el código. Y gracias por responder a mis cuestiones. Voy a probar con un servo motor con mayor torque, un mg996.
Surbyte he modificado el input del sensor al pin 2 y he agregado la rutina que me aconsejastes para la lectura de las rpm. La medicion de las rpm es para detectar que hay giros suficientes en el motor y por lo tanto ha arrancado, y enviar la señal al sevo para mover la palanca.
Estoy a la espera de recibir el modulo IR y un modulo hall y hacer pruebas para ver cual puedo adaptar mejor al volante de giro de motor.

En tu código, tu haces mediciones de RPM o eso entiendo yo, no entendi que tengas un sensor que te dice, hay RPM no hay RPM y menos aún qu elo haga en forma analógica.

Estoy en lo correcto o te he malentendido?

Qué módulo estas usando, indentifícalo por favor?

kendoktrue:
Los materiales serán:
...
-modulo sensor de infrarrojos
...
El funcionamiento será:
...
4º el sensor de infrarrojos comprobará que hay arranque a través de las revoluciones.
...

:wink:

Bien y con un sensor digital mide con analogRead(A0) y con eso qué lee RPM? De ningún modo.

En todo caso lee que algo paso o no pasó, ok!

Pero que no haga esto

if (rpm >=100) {    // las rpm son mayores a 100 y entonces ha arrancado

no tiene sentido tal como lo plantea.

Fijate que en el código lo lee como corresponde, @yiosef equivocadamente sugirió la lectura analógica.

Totalmente de acuerdo en que ningún lado cuenta los pulsos por lo tanto no hay forma de comparar con nada.

Hay mezcla de errores de @yiosef y @kendoktrue.

Kendoktru pone

rpm= digitalRead(sensor);

con eso lees SI o NO, y supongamos que este bien, hacerlo.
Pero luego pregunta

if (rpm >100)

y como no hay un contador es imposible que se compatibilice con lo anterior?
Ademas el código tiene muchos delay() que alterarían cualquier cosa mas o menso decente.

En resumidadas cuentas algo esta mal.
Si usa el sensor para detectar que se movió el volante.. oka. Bien, pero nada de rpm>100.

Para rpm> 100 medir rpm como le sugiero.

Hi
Aqui aunque un poco tarde creo que si usas un opto coupler para leer la senal sinoidal de la salida del generador seria mas ideal ya que solamente necesitas un opto coupler para lee la salida. Dependiendo el paiz que vives la salida puede ser 120 o 220 voltios con una frequencia de 50 o 60 ciclos. Para leer los rpm solamente lees los pulsos de la salida del generador usando el opto couple y usas la instrucion pulseIn() para leer los pulsos. Esta instruccion te va a dar el largo del pulso y como ejemplo voy a usa 60 ciclos por lo tanto 1/60 ciclos = 16.66 milisegundos para un ciclo completo. Aqui se usaria solamente el ciclo positivo por la tanto cuando la salida del pulseIn() = 8.33 milisegundos quere decir que el generador esta produciendo voltaje y tiene una frecuencia de 60 ciclos.Solamente una sugerencia para tu consideracion.

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