Amperímetro AC/DC con Arduino Mega y ACS712 [Compartir proyecto]

Qué tal amigos, acabo de ingresar al foro para compartir un proyecto de amperímetro de corriente alterna y continua con Arduino, realizado para la materia Medidas Electrónicas de la carrera Ingeniería Electrónica de UTN-FRM Mendoza, Argentina.

Se utilizó un Arduino Mega 2560 R3 y un sensor de efecto hall ACS712.

Para no hacer extenso por demás el post adjunto un pdf con un informe detallado y completo del proyecto donde encontrarán información teórica y práctica sobre el desarrollo y prueba del instrumento. Además dejo un link de YouTube con un video que explica el código, el informe y su uso de forma cuasi resumida.

Video:

Video para descarga de GoogleDrive:
https://drive.google.com/open?id=1-bwsfvr37QqVVVzG-siFXskZtmVbQqKM

Código (Sketch):
https://drive.google.com/open?id=1LIh-4gEHNhsWl62abvqe59TkK7a6QGqh

Por supuesto que ésto necesitará revisiones y correcciones para lograr un código más eficiente y un instrumento más exacto, pero como desarrollo básico creo que puede servir.
No duden en consultarme ante cualquier corrección o duda.
Espero haber hecho la publicación de manera correcta, sino espero recomendaciones.

Espero les guste y sirva! Saludos! :wink:

IMG_20171126_215815102.jpg

Amperímetro AC-DC ArduinoMega y ACS712.pdf (1.12 MB)

Gracias por compartir, a mas de uno le puede servir.

Como con el tiempo las PC necesitan recambiar Sistema Operativo, las cuentas caen y links como el que has puesto tmb yo prefiero el respositorio de este blog. Asi que descargué tu código y lo posteo acá.
Luego haré algunas observaciones y/o consultas.

#include "LiquidCrystal.h"
LiquidCrystal lcd(8,9,4,5,6,7);

float Sensibilidadcc = 0.063; // Modelo 30A [A/A]
float Sensibilidadca = 0.055; // Modelo 30A [A/A]
int NumMuestras = 100; //muestras del conversorADC
const int PulsadorPin = 52;
int Pulsador = 0;

 
void setup() 
{
   Serial.begin(9600); //Config velocidad comunicacion serie
   lcd.begin(16,2);
   pinMode(PulsadorPin, INPUT);
   intro();
}

void intro()
{
lcd.clear();
lcd.setCursor(4,0);
lcd.print("Medidas");
lcd.setCursor(1,1);
lcd.print("Electronicas I");
delay(3000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("Amperimetro");
lcd.setCursor(2,1);
lcd.print("Efecto Hall");
delay(3000);}

void MostrarMedicion(String magnitud, float valor, String unidad)
{
   Serial.print(magnitud);
   Serial.print(valor, 3);
   Serial.println(unidad);
}
 
void loop()
{
   Pulsador = digitalRead(PulsadorPin);
   delay(200);
   if (Pulsador == LOW)
    {
    float voltaje;
    float corrienteSuma = 0;
    for (int i = 0; i < NumMuestras; i++)
    {
      voltaje = analogRead(A0) * 5.0 / 1023.0;
      corrienteSuma += (voltaje - 2.4955) / Sensibilidadcc;
    }
   float corriente = (corrienteSuma / NumMuestras);
    
   MostrarMedicion("Intensidad: ", corriente, " A ,");
   MostrarMedicion("SalidaSensor: ", voltaje, " V");

   if ( (corriente < 0.100) && (corriente > -0.100) )
        {
          lcd.clear();
          lcd.setCursor(2,0);
          lcd.print("Sin lectura");
          lcd.setCursor(6,1);
          lcd.print("CC");
          delay(1000);
        }
    else
        {
          lcd.clear();
          lcd.setCursor(14,0);
          lcd.print("CC");
            
          lcd.setCursor(0,1);
          lcd.print("I= ");
          lcd.print(corriente,3);
          lcd.print(" A");
          delay(1000);
         }
    }
  
  else //Pulsador
  {
    float voltaje;
    float get_corriente();
    float corriente=get_corriente();//obtenemos la corriente pico
    float corrienteRMS=corriente*0.707; //Intensidad RMS = Ipico/(2^1/2)
    float potencia=corrienteRMS*223.2; // P=IV watts
    
    MostrarMedicion("Intensidad: ", corriente, "A ,");
    MostrarMedicion("Irms: ", corrienteRMS, "A ,");
    MostrarMedicion("Potencia: ", potencia, "W");
    
    
    
  if ( (corriente < 0.100) && (corriente > -0.100) )
        {
          lcd.clear();
          lcd.setCursor(2,0);
          lcd.print("Sin lectura");
          lcd.setCursor(6,1);
          lcd.print("CA");
          delay(1000);
        }
  else
        {
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("Irms= ");
          lcd.print(corrienteRMS,3);
          lcd.print(" A");
          lcd.setCursor(14,0);
          lcd.print("CA");
            
          lcd.setCursor(0,1);
          lcd.print("Prms= ");
          lcd.print(potencia,3);
          lcd.print(" W");
          delay(1000);
        }
     }

}

float get_corriente()

  {
  float voltaje;
  float corriente=0;
  long tiempo=millis();
  float Imax=0;
  float Imin=0;
  while(millis()-tiempo<500)//realizamos mediciones durante 0.5 segundos
  { 
    voltaje = analogRead(A0) * (5.0 / 1023.0);//lectura del sensor
    corriente=0.9*corriente+0.1*((voltaje-2.4955)/Sensibilidadca); //Ecuación  para obtener la corriente
    if(corriente>Imax)Imax=corriente;
    if(corriente<Imin)Imin=corriente;
   }
  return((Imax-Imin)/2);
  }

Primero felicitarlos por el trabajo, me gustó y me voy a permitir hacerte algunas sugerencias solo para mejorar su funcionalidad. Son consejos, tu código esta bien en líneas generales.

  1. Promedio
    La rutina en la que calculas el promedio puede mejorarse y hacerse mas rapida de varias maneras.
    1.1 No hace falta calcular el valor de cada muestra si no lo vas a presentar, si no lo almacenas. Entonces esto es mas eficiente. Tomas la muestra, las guardas en un sumador y luego promedias y calulas la corriente del valor promediado. No sumas los valores de corrientes de cada muestra como en tu caso.
   float voltaje;
    unsigned long corrienteSuma = 0;
    for (int i = 0; i < NumMuestras; i++) {
     corrienteSuma += analogRead(A0);
    }
    voltaje = (float) (corrienteSuma/ NumMuestras) * 5.0 / 1023.0;
        float corriente += (voltaje - 2.4955) / Sensibilidadcc;

Es lo mismo con muchas menos cuentas para el microcontrolador.

1.2 Esto mismo se puede hacer con promedio movil. Si te interesa te lo indico pero hace días lo he respondido. Solo búscalo.

float get_corriente();

en la linea 79 no tiene razón de ser. Bórralo

  1. Solucion de compromiso.
    Evidentemente esto
if (corriente < 0.100 && corriente > -0.100) {
 lcd.clear();
 lcd.setCursor(2,0);
 lcd.print("Sin lectura");
 lcd.setCursor(6,1);
 lcd.print("CA");
 delay(1000);
 }

fue una solución de compromsio para que no se vean digitos cambiando en torno a 0.
En lo personal yo pondría una opción por software que permitiera ver el 0 o "Sin Lectura" como opciones.

  1. long tiempo = millis();
    Siempre que uses millis() los valores con los que operes deben definirse como unsigned long.

  2. get_corriente()
    De nuevo calculas cada corriente muestreada y se supone que quieres tomar la mayor cantidad de muestras en 500 mseg.
    yo modificaría esa rutina sin hacer tanta cuenta. Las cuentas cuando tenga Imax e Imin una sola vez.
    Incluso hablas de AC de modo que pondria el ADC en freewheeling.
    Sin embargo el ADC tarda 100useg en cada conversión en modo normal asi que en 500mseg dudo que no capture correctamente los máx y min de la corriente.
    Esta observación sobre poner el ADC en modo libre podria pasarse por alto.

  3. 220VAC
    Queda para la versión 2.0 la medición de tensión con lo que obtendrás un medidor de potencia completo.

Error
Rescato la medición de error tipica de la materia Mediciones Electrónicas alias Instumentitos como le decíamos nosotros en la Universidad (UBA Bs As).

No vi que el Tektronix TX1 TrueRMS Multimeter que usan como elemento comparativo tuviera un certificado de calibración.
Se usó el provisto por el fabricante?

Disipación de la resistencia de carga :

Al realizar la contrastación teníamos errores inaceptables a medida que la medida progresaba en el tiempo, además de una varianza en la medición azarosa, dejando una precisión totalmente variable. Se descubrió que el problema se debía a que la carga utilizada en prueba fue una resistencia de 100Ω/7W. Por ser tan baja la capacidad de disipación de potencia, el calor en aumento distorsionaba toda medición, haciendo imposible la contrastación y calibración del amperímetro. Esto se corrigió utilizando una serie de resistencia de 8Ω con gran poder de disipación, manteniéndose casi “fría” a lo largo del nuevo ensayo.

Es una experiencía práctica que muestra como las cosas en el papel(diseño o laboratorio) son de un modo y en la práctica de otro a pesar que sea coherente, la observación. Muy pocos a menos que hayan pasado por una falla de este tipo considerarían la carga tal como uds optaron luego de los primeros errores. Para destacar

Sensibilidad

La medición de corriente alterna presentaba un gran error, cercano al 20%. Al
cálculo realizado por el algoritmo en el código de Arduino, se le asignó una nueva
sensibilidad distinta a la sensibilidad de continua, para corregir dicha desviación,
logrando disminuir el error muy por debajo de 10%.

Este es otro aporte para considerar.

CONCLUSIONES:

Hubiera usado un DUE en lugar de un MEGA porque dispone de un ADC de 12 bits, 2 bits de mejora respecto del MEGA.

El trabajo me gusta mucho y tiene cuestiones que me llamaron la atención como este recurso simple pero efectivo

Pulsador = digitalRead(PulsadorPin);
    
    delay(200);
    if (Pulsador == LOW)  { // MODO DC

Toma el valor del pulsador. espera 200 para estabilizarsarlo por si hay rebotes y luego pregunta por un estado.
Me pareció interesante!!

Todos tenemos proyectos pero este merece completarse.. a tener en cuenta y como la Universidad exige trabajos, sería bueno que a la primer oportunidad retomen este buen trabajo y lo potencien.
Hoy con el aumento del costo de la energia en $/Kwatt saber el consumo en una vivienda es importante.
Tienen algo bueno entre manos.

Antes que mil gracias por tomarte el tiempo en ver el trabajo.

surbyte:
Primero felicitarlos por el trabajo, me gustó y me voy a permitir hacerte algunas sugerencias solo para mejorar su funcionalidad. Son consejos, tu código esta bien en líneas generales.

  1. Promedio

Es cierto! Analizando esas opciones que presentas se logra economizar en tiempo y cálculo.

  1. Solucion de compromiso.

La verdad que sí, quedaría más prolijo y entendible.

  1. long tiempo = millis();

Bien, eso no lo sabia, tomé eso de un ejemplo y la verdad no corroboré con la teoría muy bien su utilización.

  1. get_corriente()

Justo estaba leyendo un poco de ACD en modo libre, hace sólo unos días que arranco con arduino y he pasado eso por alto.
Y esta parte del código junto a la manera de muestrear la alterna, fue sacada de otro trabajo y lamentablemente poco analizada antes de incorporarla al código.

  1. 220VAC

Sí, la verdad que eso daría un buen complemento.

Error

La mayoría de errores creo que se han debido a un factor casi único y determinante, y es el tiempo. Habíamos empezado con otro proyecto, luego mis compañeros de grupo no pudieron continuar ayudándome y cambié el proyecto a amperímetro. Sólo tuve unos días para ponerme al 100% a tratar de concluirlo antes de la fecha de presentación, y las cosas a las apuradas no salen del todo bien. Esto viene referido al multímetro utilizado como patrón. Necesitaba en realidad un amperímetro considerado patrón que en el momento de encontrarme en el laboratorio no estaba disponible. Sólo tenía ese día para la contrastación por lo que me quedaba utilizar ese Tektronix. De manera arbitraria y a criterio decidí utilizarlo como patrón, aunque no sea lo indicado. Sería otra mejora a realizar: utilizar un amperímetro de mejor calidad y calibrado con documentos de fábrica que avalen esa exactitud, para poder hacer una contrastación más justa.

Disipación de la resistencia de carga :

Exacto, son de esas cosas experimentales que creí que llevaría menos tiempo y sería más simple, hasta que realmente lo ponemos en práctica jaja.

CONCLUSIONES:

Sí, es cierto! Pasa que disponía del Mega y decidí directamente utilizar ese. Para una implementación final sería buena tu consideración sobretodo por la manera operativa del DUE.

En PIC en otro proyecto había utilizado demoras para solucionar rebotes y vi que acá podía funcionar también.

Sí, en el margen de una carrera universitaria sobretodo de ingeniería, merece mayor ajustes y afinaciones como las que me has mencionado y otras. Creo que si lo hubiésemos arrancado desde principio de año y no en unos días, el resultado hubiera sido un poco mejor y más completo. De hecho, la idea en un principio era justamente hacer un contador de energía con Arduino, justo que lo mencionas, y tengo idea de una vez que termine con finales ponerme con eso.

Te agradezco enormemente cada una de tus observaciones y menciones, la verdad que ayudan muchísimo, y serán tenidas muy en cuenta.
Seguiré profundizando en conocimiento sobre Arduino ya que aún me queda muchísimo por delante, y compartiendo o colaborando en lo que puedo en el foro.
Nuevamente gracias!