Go Down

Topic: Current Sensing Problem with ACS712 ? (Read 3973 times) previous topic - next topic

Dileesha

Apr 30, 2013, 01:59 pm Last Edit: Apr 30, 2013, 02:00 pm by Dileesha Reason: 1
Hellow Friends !

I connected ACS712-20A sensor to my home made arduino ( arduino uno ).
( for ACS712 sensor, i bought only the sensor and made the circuitry my self as mentioned in the datasheet )
* for Cf --- > i used 0.1uF instead of 1nF cap

Source connected is 230V AC / 50Hz
Load connected is a 230V AC / 1500W water heater

..........................................................

My problem is the voltage readings are not stable as I was expecting.


My code is below ...
Quote

// the setup routine runs once when you press reset:
void setup() {
 // initialize serial communication at 9600 bits per second:
 Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
 // read the input on analog pin 0:
 int sensorValue = analogRead(A3);
 delay(1);
 // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
 float voltage = sensorValue * (5.0 / 1023.0);
 // print out the value you read:
 Serial.println(voltage);
 delay(500);
}


Serial monitor outputs are as below

Quote
before connecting the load
2.48
2.48
2.48
2.48
2.51
2.50
2.50
2.50
2.51
2.52
2.53
2.48
after connecting the load
2.47
2.50
2.93
3.07
3.00
2.72
2.36
2.05
1.93
2.05
2.37
2.77
2.99
3.06
2.87
2.52
2.06
1.94
1.94
2.22
2.64


I also tried using the EmonLib from openenergymonitor.org . But it didn't work as well.

Your comments are highly appreciated.


Thanks,
Dileesha.
Dileesha Amarasena

Dileesha

#1
Apr 30, 2013, 04:07 pm Last Edit: Apr 30, 2013, 04:17 pm by Dileesha Reason: 1
Hi friends,

Then i tried EmonLib again . I didnt make any change, i just uploaded the EmonLib example ( emonLib > examples > voltage_and_current.ino ) into the arduino ic.

I get some output but it's fluctuating a lot . Please see the results i got in Serial Monitor .

Quote

WITHOUT LOAD
rmsVoltage : 267.22 rmsCurrent : 0.04
rmsVoltage : 268.10 rmsCurrent : 0.04
rmsVoltage : 266.13 rmsCurrent : 0.04 
rmsVoltage : 277.60 rmsCurrent : 0.04
rmsVoltage : 271.81 rmsCurrent : 0.04
rmsVoltage : 219.10 rmsCurrent : 0.03 ( voltage has dropped )
rmsVoltage : 271.05 rmsCurrent : 0.04
rmsVoltage : 259.77 rmsCurrent : 0.04
rmsVoltage : 267.94 rmsCurrent : 0.04


WITH LOAD

rmsVoltage : 254.26 rmsCurrent : 0.44
rmsVoltage : 253.22 rmsCurrent : 0.44
rmsVoltage : 202.97 rmsCurrent : 0.35  ( voltage has dropped )
rmsVoltage : 256.09 rmsCurrent : 0.43
rmsVoltage : 255.41 rmsCurrent : 0.45
rmsVoltage : 251.49 rmsCurrent : 0.43
rmsVoltage : 254.72 rmsCurrent : 0.43



Used arduino CODE is below

Quote
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include "EmonLib.h"             // Include Emon Library
EnergyMonitor emon1;             // Create an instance

void setup()

  Serial.begin(9600);
 
  emon1.voltage(2, 6340.26, 1.7);  // Voltage: input pin, calibration, phase_shift
  emon1.current(3, 1.1);       // Current: input pin, calibration.
}

void loop()
{
  emon1.calcVI(20,2000);         // Calculate all. No.of half wavelengths (crossings), time-out
  emon1.serialprint();           // Print out all variables
}



Your help will be highly appreciated .

Thanks,
Dileesha.
Dileesha Amarasena

Riva

You could try doing a average reading to smooth out glitches. Try either a rolling average (2 samples) or sample and add the value x times then divide by x to get average.

Dileesha

@Riva

Thanks for your comment.

Could you please show me how to make that change to the code ?

Im a newbie, so i don't know much coding work.

Thanks.
Dileesha Amarasena

Riva

#4
Apr 30, 2013, 05:52 pm Last Edit: Apr 30, 2013, 05:57 pm by Riva Reason: 1

Could you please show me how to make that change to the code ?


Untested rolling average code.
Code: [Select]
int sensorValue;
// the setup routine runs once when you press reset:
void setup() {
 // initialize serial communication at 9600 bits per second:
 Serial.begin(9600);
 sensorValue = analogRead(A3); // Prime rolling average
}

// the loop routine runs over and over again forever:
void loop() {
 // read the input on analog pin 3:
 sensorValue += (analogRead(A3) / 2); // get rolling average
 // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
 float voltage = sensorValue * (5.0 / 1023.0);
 // print out the value you read:
 Serial.println(voltage);
 delay(500);
}


Untested average of 20 readings code
Code: [Select]
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = 0;
  for (byte x = 0; x < 20; x++) {
    sensorValue += analogRead(A3);
  }
  sensorValue = sensorValue / 20;
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
  delay(500);
}

Dileesha

@Riva

I tried that . Below is what i got in serial printer .

without a load
Quote
3.77
5.05
6.32
7.51
8.75
10.00
11.24
12.48
13.71
14.97
16.17
17.42
18.67
19.92
21.18
22.45
23.69
24.93
26.17
27.41
28.67
29.92
31.17
32.42
33.68
34.93
36.21
37.47
38.69
39.93
41.17
42.41
43.65
44.89
46.13
47.38
48.62
49.86
51.10
52.35
53.59
54.83
56.07
57.31
58.55
59.79
61.04
62.28
63.52
64.76
65.99
67.23
68.47
69.73
70.98
72.24
73.43
74.68
75.93
77.18
78.43
79.68
80.93
82.19
83.47
84.68
85.92
87.17
88.41
89.65
90.88
92.14
93.31
94.56
95.82
97.07
98.32
99.60
100.87
102.11
103.35
104.59
105.83
107.07
108.31
109.56
110.82
112.02
113.27
114.52
115.77
117.02
118.27
119.53
120.78
122.04
123.32
124.60
125.87
127.05
128.29
129.53
130.77
132.01
133.26
134.50
135.74
136.98
138.22
139.46
140.70
141.95
143.19
144.43
145.67
146.91
148.15
149.39
150.63
151.86
153.10
154.34
155.57
156.81
158.04
159.28
-159.79
-158.56
-157.32
-156.09
-154.85
-153.61
-152.38
-151.14
-149.90
-148.67
-147.42
-146.16
-144.91
-143.65
-142.39
-141.14
-139.94
-138.73
-137.48
-136.23
-134.98
-133.73
-132.48
-131.23
-129.98
-128.72
-127.47
-126.22
-124.97
-123.72
-122.47
-121.21
-119.96
-118.70
-117.45
-116.20
-114.95
-113.70
-112.44
-111.19
-109.94


with a load
Quote
5.00
6.26
7.51
8.76
10.01
11.27
12.61
13.92
15.19
16.42
17.64
18.84
20.04
21.23
22.43
23.64
24.85
26.09
27.35
28.64
29.97
31.31
32.68
34.08
35.50
36.95
38.41
39.90
41.42
42.95
44.47
45.99
47.51
49.02
50.50
51.96
53.39
54.73
56.10
57.43
58.72
59.94
61.08
62.17
63.20
64.18
65.15
66.12
67.09
68.06
69.05
70.05
71.08
72.11
73.12
74.17
75.32
76.51
77.75
79.06
80.40
81.78
83.20
84.64
86.11
87.60
89.10
90.62
92.15
93.67
95.20
96.72
98.25
99.77
101.30
102.82
104.31
105.79
107.24
108.66
110.05
111.41
112.73
114.00
115.22
116.38
117.51
118.55
119.56
120.60
121.63
122.65
123.67
124.67
125.65
126.63
127.60
128.56
129.53
130.50
131.50
132.54
133.63
134.78
136.03
137.34
138.71
140.05
141.51
143.01
144.53
146.05
147.58
149.05
150.46
151.84
153.18
154.47
155.71
156.91
158.08
159.23
-159.96
-158.90
-157.88
-156.90
-155.87
-154.84
-153.81
-152.78
-151.76
-150.75
-149.75
-148.76


Please help ?
Dileesha Amarasena

retrolefty

So you are measuring a AC current and expecting a steady measurement voltage? I would think the values would track the rms AC current as it goes positive and negative at a 60Hz rate?

Lefty

Dileesha

@Riva

Then i just now tried your modified code ( second code you have put )

It gave me below result . But still its fluctuating ..

with load
Quote
2.48
2.02
1.95
2.32
2.76
3.03
2.92
2.49
2.03
1.94
2.22
2.68
2.99
3.01
2.67
2.17
1.96
2.01
2.45
2.80
3.03
2.94


with load no load
Quote
2.48
2.48
2.50
2.46
2.50
2.50
2.55
2.44
2.48
2.48
2.46
2.50
2.50
2.54
2.44
2.48


Any suggestion ?
Dileesha Amarasena

Dileesha

@Lefty

Yes I want to measure 50Hz AC voltage . And yes I got the rms values and did the math ( i uploaded the EmonLib library example which has all math in it ) .

For your reference ill post the complete library ..

EmonLib.cpp / EmonLib.h are below


------------- H File ---------------------
Quote
/*
 Emon.h - Library for openenergymonitor
 Created by Trystan Lea, April 27 2010
 GNU GPL
*/

#ifndef EmonLib_h
#define EmonLib_h

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

class EnergyMonitor
{
 public:

   void voltage(int _inPinV, double _VCAL, double _PHASECAL);
   void current(int _inPinI, double _ICAL);

   void voltageTX(double _VCAL, double _PHASECAL);
   void currentTX(int _channel, double _ICAL);

   void calcVI(int crossings, int timeout);
   double calcIrms(int NUMBER_OF_SAMPLES);
   void serialprint();

   long readVcc();
   //Useful value variables
   double realPower,
      apparentPower,
      powerFactor,
      Vrms,
      Irms;

 private:

   //Set Voltage and current input pins
   int inPinV;
   int inPinI;
   //Calibration coeficients
   //These need to be set in order to obtain accurate results
   double VCAL;
   double ICAL;
   double PHASECAL;

   //--------------------------------------------------------------------------------------
   // Variable declaration for emon_calc procedure
   //--------------------------------------------------------------------------------------
   int lastSampleV,sampleV;   //sample_ holds the raw analog read value, lastSample_ holds the last sample
   int lastSampleI,sampleI;                      

   double lastFilteredV,filteredV;                   //Filtered_ is the raw analog value minus the DC offset
   double lastFilteredI, filteredI;                  

   double phaseShiftedV;                             //Holds the calibrated phase shifted voltage.

   double sqV,sumV,sqI,sumI,instP,sumP;              //sq = squared, sum = Sum, inst = instantaneous

   int startV;                                       //Instantaneous voltage at start of sample window.

   boolean lastVCross, checkVCross;                  //Used to measure number of times threshold is crossed.
   int crossCount;                                   // ''


};

#endif


Dileesha Amarasena

Dileesha

---------- .CPP file ( i will put as two parts ) --------------------------

Quote

Quote
/*
 Emon.cpp - Library for openenergymonitor
 Created by Trystan Lea, April 27 2010
 GNU GPL
*/

//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL)
{
  inPinV = _inPinV;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
}

void EnergyMonitor::current(int _inPinI, double _ICAL)
{
  inPinI = _inPinI;
  ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors based on emontx pin map
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
  inPinV = 2;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
}

void EnergyMonitor::currentTX(int _channel, double _ICAL)
{
  if (_channel == 1) inPinI = 3;
  if (_channel == 2) inPinI = 0;
  if (_channel == 3) inPinI = 1;
  ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kwh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcVI(int crossings, int timeout)
{
 int SUPPLYVOLTAGE = readVcc();
 int crossCount = 0;                             //Used to measure number of times threshold is crossed.
 int numberOfSamples = 0;                        //This is now incremented  

 //-------------------------------------------------------------------------------------------------------------------------
 // 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve.
 //-------------------------------------------------------------------------------------------------------------------------
 boolean st=false;                                  //an indicator to exit the while loop

 unsigned long start = millis();    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

 while(st==false)                                   //the while loop...
 {
    startV = analogRead(inPinV);                    //using the voltage waveform
    if ((startV < 550) && (startV > 440)) st=true;  //check its within range
    if ((millis()-start)>timeout) st = true;
 }
 
 //-------------------------------------------------------------------------------------------------------------------------
 // 2) Main measurment loop
 //-------------------------------------------------------------------------------------------------------------------------
 start = millis();

 while ((crossCount < crossings) && ((millis()-start)<timeout))
 {
   numberOfSamples++;                            //Count number of times looped.

   lastSampleV=sampleV;                          //Used for digital high pass filter
   lastSampleI=sampleI;                          //Used for digital high pass filter
   
   lastFilteredV = filteredV;                    //Used for offset removal
   lastFilteredI = filteredI;                    //Used for offset removal  
   
   //-----------------------------------------------------------------------------
   // A) Read in raw voltage and current samples
   //-----------------------------------------------------------------------------
   sampleV = analogRead(inPinV);                 //Read in raw voltage signal
   sampleI = analogRead(inPinI);                 //Read in raw current signal

   //-----------------------------------------------------------------------------
   // B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
   //-----------------------------------------------------------------------------
   filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
   filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);
 
   //-----------------------------------------------------------------------------
   // C) Root-mean-square method voltage
   //-----------------------------------------------------------------------------  
   sqV= filteredV * filteredV;                 //1) square voltage values
   sumV += sqV;                                //2) sum
   
   //-----------------------------------------------------------------------------
   // D) Root-mean-square method current
   //-----------------------------------------------------------------------------  
   sqI = filteredI * filteredI;                //1) square current values
   sumI += sqI;                                //2) sum
see part 2
 
Dileesha Amarasena

Dileesha

----------------- .CPP file part 2 --------------------------------
Quote

//-----------------------------------------------------------------------------
   // E) Phase calibration
   //-----------------------------------------------------------------------------
   phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);
   
   //-----------------------------------------------------------------------------
   // F) Instantaneous power calc
   //-----------------------------------------------------------------------------  
   instP = phaseShiftedV * filteredI;          //Instantaneous Power
   sumP +=instP;                               //Sum  
   
   //-----------------------------------------------------------------------------
   // G) Find the number of times the voltage has crossed the initial voltage
   //    - every 2 crosses we will have sampled 1 wavelength
   //    - so this method allows us to sample an integer number of half wavelengths which increases accuracy
   //-----------------------------------------------------------------------------      
   lastVCross = checkVCross;                    
   if (sampleV > startV) checkVCross = true;
                    else checkVCross = false;
   if (numberOfSamples==1) lastVCross = checkVCross;                  
                   
   if (lastVCross != checkVCross) crossCount++;
 }

 //-------------------------------------------------------------------------------------------------------------------------
 // 3) Post loop calculations
 //-------------------------------------------------------------------------------------------------------------------------
 //Calculation of the root of the mean of the voltage and current squared (rms)
 //Calibration coeficients applied.
 
 double V_RATIO = VCAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Vrms = V_RATIO * sqrt(sumV / numberOfSamples);
 
 double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Irms = I_RATIO * sqrt(sumI / numberOfSamples);

 //Calculation power values
 realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
 apparentPower = Vrms * Irms;
 powerFactor=realPower / apparentPower;

 //Reset accumulators
 sumV = 0;
 sumI = 0;
 sumP = 0;
//--------------------------------------------------------------------------------------      
}

//--------------------------------------------------------------------------------------
double EnergyMonitor::calcIrms(int NUMBER_OF_SAMPLES)
{
 
int SUPPLYVOLTAGE = readVcc();

 
 for (int n = 0; n < NUMBER_OF_SAMPLES; n++)
 {
   lastSampleI = sampleI;
   sampleI = analogRead(inPinI);
   lastFilteredI = filteredI;
   filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

   // Root-mean-square method current
   // 1) square current values
   sqI = filteredI * filteredI;
   // 2) sum
   sumI += sqI;
 }

 double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

 //Reset accumulators
 sumI = 0;
//--------------------------------------------------------------------------------------      

 return Irms;
}

void EnergyMonitor::serialprint()
{
 //  Serial.print(realPower);
  // Serial.print(' ');
   //Serial.print(apparentPower);
   //Serial.print(' ');
   Serial.print(Vrms);
   Serial.print(' ');
   Serial.print(Irms);
   Serial.print(' ');
   //Serial.print(powerFactor);
   //Serial.println(' ');
   delay(2);
}

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

long EnergyMonitor::readVcc() {
 long result;

 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  
/* #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
 ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
 #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
 ADMUX = _BV(MUX5) | _BV(MUX0);
 #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
 ADMUX = _BV(MUX3) | _BV(MUX2);*/
 #endif

 delay(2);               // Wait for Vref to settle
 ADCSRA |= _BV(ADSC);            // Convert
 while (bit_is_set(ADCSRA,ADSC));
 result = ADCL;
 result |= ADCH<<8;
 result = 1126400L / result;         //1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
 return result;
}

Dileesha Amarasena

dc42

One problem I can see with the open energy monitor library is that the values computers by calcVI will be disturbed if an interrupt (e.g. serial or timer) occurs when calcVI is not waiting for an ADC conversion to complete. To get accurate RMS readings, it should take samples at regular intervals over a whole number of half cycles. It does the whole-number-of-half-cycles bit, but it relies on there being no interruptions to get the regular intervals. When I built a project that included a mains voltage monitor, I used an interrupt to take regular samples (every 500us AFAIR) to try to get regular sample intervals. Even better would be to trigger the ADC conversions from a free-running counter/timer.

You may get more consistent readings if you pass a larger number of crossings (and a correspondingly larger timeout) to calcVI.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Dileesha

@DC42

Thanks much to you !

I followed you and increased the number of crossings . But i reduced the timeout . Then it seems to work better than earlier time .

Still there is a fluctuation that happens once for every 8 or 10 seconds . I think that's because of the capacitor I used ( i used a 0.1uF capacitor instead of 1nF capacitor for Cf value / in data sheet they have asked to use a 1nF cap ).

Below is the code after modification

Quote
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include "EmonLib.h"             // Include Emon Library
EnergyMonitor emon1;             // Create an instance

void setup()

  Serial.begin(9600);
 
  emon1.voltage(2, 6340.26, 1.7);  // Voltage: input pin, calibration, phase_shift
  emon1.current(3, 1.1);       // Current: input pin, calibration.
}

void loop()
{
  emon1.calcVI(200,1000);         // Calculate all. No.of half wavelengths (crossings), time-out
  emon1.serialprint();           // Print out all variables
}


And also I have another problem . I think that must be posted in the programming category . So I posted there . Please use this link to that post .
[url]http://arduino.cc/forum/index.php/topic,163843.0.html/url]
Dileesha Amarasena

dc42

200 half cycles takes 2000ms for a 50Hz mains, plus the sampling code needs time to wait for a zero crossing at the start. So you should increase the timeout to something higher, say 2500ms.

Using a 0.1uF filter capacitor instead of 1nF will slightly reduce the sensitivity at 50Hz and also introduce a small phase shift, but it doesn't account for your occasional low readings. You are getting both low voltage and low current readings at the same time, so either the mains really is dropping for short periods quite often, or something is wrong with the sampling code.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Go Up