Problem in Computing the Energy in Energy Meter using ESP32 - arduino

So me and my groupmates are been working on with our thesis project about energy meter. In our project, the esp32 is the main board we are using. We also have voltage sensor (ZMPT101B) and current sensor (SCT013 100V:50mA) connected to our main board.
here is the link for the ZMPT101B... https://www.autobotic.com.my/ac-voltage-sensor-module-zmpt101b-single-phase
and here is the link for the SCT013... https://innovatorsguru.com/sct-013-000/
I am also using the Emon library from https://www.arduino.cc/reference/en/libraries/emonlib/ to read the value thrown by the current and voltage sensor.
To get the power, i will multiply the current and voltage values.
Then to get the value of the energy i will be needing the time because Energy = Power x time. I saw formula online, it uses millis () function to get the time... but to be honest i dont know how millis works.
last_time = current_time;
current_time = millis();
Wh = Wh + power *(( current_time -last_time) /3600000.0) ;
The value of the energy will be send to the database, in our case our database is the firebase realtime database. Using this code...
Firebase.setDouble(firebaseData, path , KWh);
If the electricity cuts off , ESP32 will also be dead and will stop working. So we decided to add this line of codes...
Firebase.getInt(firebaseData, path);
totalEnergyDB = (firebaseData.intData());
preKWh = totalEnergyDB;
.... once the esp32 is turned on again, this code is used to get the data from the firebase... wherein the data got from the firebase will be used as a pre-kwh.
I used this lines of code to add the current readings from the pre-kwh.
KWh = (Wh/1000) + preKWh;
I set the calibration for the voltage and current sensor high so the changes will be easy to be seen.
My problem is that i was able to get the value from the database but it seems the energy formula is not working properly.
this is the result from the serial monitor... (171 KWH is the initial value from the database)
enter image description here
i wasn't able to show you the result of the power but it say in the lcd that it is around 3000W! But still Energy reading is not changing even its been turned on for over an hour:(
Here is the complete code for our project...
#include "EmonLib.h"
#define VOLT_CAL 52.5000
#define CURRENT_CAL 10.07
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
EnergyMonitor emon1;
int i;
// Wifi
#include <WiFi.h>
#include "FirebaseESP32.h"
#define FIREBASE_HOST "#!##!#$!#a.firebaseio.com"
#define FIREBASE_AUTH "RRw3u$!#%!##%##%$#%^#$^oI8LpQyVo0AWBC"
#define WIFI_SSID "WIFI"
#define WIFI_PASSWORD "PASSWORD"
// Define Firebase Data object
FirebaseData firebaseData;
// Root Path
String path = "/USER INFO/jdc/totalEnergy";
unsigned long last_time =0;
unsigned long current_time =0;
int Wh = 0;
int preKWh;
int KWh;
int totalEnergyDB;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
initWifi();
lcd.init();
lcd.backlight();
lcd.begin(4, 20);
lcd.clear();
lcd.setCursor(1,4);
lcd.print("LOADING...");
Serial.print("LOADING...");
emon1.voltage(32, VOLT_CAL, 1.7); // Voltage: input pin, calibration, phase_shift
emon1.current(33, CURRENT_CAL);
for ( i = 0; i < 5; i++ ) {
emon1.calcVI(20,2000);
float currentDraw = emon1.Irms;
float supplyVoltage = emon1.Vrms;
}
delay(1);
Firebase.getInt(firebaseData, path);
totalEnergyDB = (firebaseData.intData());
preKWh = totalEnergyDB;
}
void loop() {
emon1.calcVI(20,2000);
float currentDraw = emon1.Irms; //extract Irms into Variable
float supplyVoltage = emon1.Vrms;
float power = currentDraw * supplyVoltage;
last_time = current_time;
current_time = millis();
Wh = Wh + power *(( current_time -last_time) /3600000.0) ;
KWh = (Wh/1000) + preKWh;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("VOLTAGE: ");
lcd.print(supplyVoltage);
lcd.print(" V");
lcd.setCursor(0,1);
lcd.print("CURRENT: ");
lcd.print(currentDraw);
lcd.print(" A");
lcd.setCursor(0,2);
lcd.print("POWER: ");
lcd.print(power);
lcd.print(" W");
lcd.setCursor(0,3);
lcd.print("ENERGY: ");
lcd.print(KWh);
lcd.print(" KWh");
delay(100);
if (isnan(Wh)) { // if Wh is Not A Number
Serial.println(F("Error reading Energy!"));
}
else {
Serial.print(F("preKWh: "));
Serial.print(preKWh);
Serial.println(F("KWH"));
Serial.print(F("Energy: "));
Serial.print(KWh);
Serial.println(F("KWH"));
Firebase.setDouble(firebaseData, path , KWh);
delay(100);
}
}
void initWifi(){
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
//Set database read timeout to 1 minute (max 15 minutes)
Firebase.setReadTimeout(firebaseData, 1000 * 60);
//tiny, small, medium, large and unlimited.
//Size and its write timeout e.g. tiny (1s), small (10s), medium (30s) and large (60s).
Firebase.setwriteSizeLimit(firebaseData, "tiny");
}
Can anyone help me with the code. What changes should be done?

Looking at your data types, you are storing Wh and KWh as an integer, and you are adding likely very small floats to them (imagine (current_time - last_time) being 1000 (1 second), then Wh would become Wh + power * 2.78e-5, which will result in rounding errors unless your power consumption is enormous. To solve this, you should not round to integers, and keep Wh and KWh as floats.

Related

warning: overflow in implicit constant conversion [-Woverflow] in Arduino Mega 2560 WI-Fi R3

i want to record a long data for like 2 to 3 hours using microcontroller Arduino Mega 2560 WI-FI R3 but I got this warning in my code
below is the picture of the warning i got.
enter image description here
the warning come up when I put the time out constant more than 30000 milliseconds
below is the code I used for the Arduino
#include "DHT.h"
// Pin Definitions
#define DHT_PIN_OUT A1
#define DHTTYPE DHT11
#define MQ3_PIN_OUT A2
#define MQ4_PIN_OUT A3
#define MQ7_PIN_OUT A4
// Global variables and defines
// object initialization
DHT dht(DHT_PIN_OUT, DHTTYPE);
// define vars for testing menu
const int timeout = 180000; //define timeout of 1 hour
char menuOption = 0;
long time0;
// Setup the essentials for your circuit to work. It runs first every time your circuit is powered with electricity.
void setup()
{
// Setup Serial which is useful for debugging
// Use the Serial Monitor to view printed messages
Serial.begin(9600);
while (!Serial) ; // wait for serial port to connect. Needed for native USB
Serial.println("start");
dht.begin();
menuOption = menu();
}
// Main logic of your circuit. It defines the interaction between the components you selected. After setup, it runs over and over again, in an eternal loop.
void loop(){
if(menuOption == '1') {
delay(500); //delay 0.5 second
// DHT11 Humidity and Temperature Sensor
// Reading humidity in %
float dhtHumidity = dht.readHumidity();
// Read temperature in Celsius, for Fahrenheit use .readTempF()
float dhtTempC = dht.readTemperature();
float Alcohol = analogRead(MQ3_PIN_OUT);
float Methane = analogRead(MQ4_PIN_OUT);
float CarbonMonoxide = analogRead(MQ7_PIN_OUT);
Serial.print(F("Humidity: ")); Serial.print(dhtHumidity); Serial.print(F("[%]\t"));
Serial.print(F("Temp: ")); Serial.print(dhtTempC); Serial.print(F("[C]\t"));
Serial.print(F("Alcohol: ")); Serial.print(Alcohol); Serial.print(F(" \t"));
Serial.print(F("Methane: ")); Serial.print(Methane); Serial.print(F(" \t"));
Serial.print(F("Carbon Monoxide: ")); Serial.println(CarbonMonoxide); Serial.println(F(" \t"));
}
if (millis() - time0 > timeout){
menuOption = menu();
}
}
// Menu function for selecting the components to be tested
// Follow serial monitor for instrcutions
char menu(){
Serial.println(F("\nSensor Array"));
Serial.println(F("Press (1) to start the sensor array"));
while (!Serial.available());
// Read data from serial monitor if received
while (Serial.available()){
char c = Serial.read();
if (isAlphaNumeric(c))
{
if(c == '1')
Serial.println(F("Now running the sensor array"));
else{
Serial.println(F("illegal input!"));
menuOption = menu();
return 0;
}
time0 = millis();
return c;
}
}
}
sorry for my bad programming and silly question, I'm new to this kind of thing. and I just found out that people usually get answers from StackOverflow, so I just wanted to try asking because I have tried to google the answer but I can't find it.

STM32H7 | BlockDevice & FatFs | SD card writing is very slow

I'm trying to implement SD card functionality on a portenta H7 (STM32H7). The SD card must save all ADC's data in real time (4Mbyte/sec). I saw the maximum data rate for a portenta is 200MByte/sec but I can't even reach 1Mbyte/s.
I'm using Arduino IDE, SDMMCBlockDevice.h and FATFileSystem.h librarys. I try to work with the MMC bus with 4-bit width. When I check the register's bits, my configuration is good. I tried to increase the clock speed but no result.
I don't have lot of skills in C++ so I think I miss something. Someone could help me?
Below my test code:
#include "SDMMCBlockDevice.h"
#include "FATFileSystem.h"
SDMMCBlockDevice block_device;
mbed::FATFileSystem fs("fs");
const int len = 8192;
uint16_t tab[len];
long int Time = 0;
void setup() {
for(int i=0; i<len; i++){
tab[i]=i;
}
Serial.begin(115200);
while (!Serial);
delay(1000);
Serial.println("Mounting SDCARD...");
int err = fs.mount(&block_device);
if (err) {
Serial.println("No SD Card filesystem found, please check SD Card on computer and manually format if needed.");
}
Serial.println(SDMMC2->CLKCR,BIN);
//SDMMC2->CLKCR |= SDMMC_CLKCR_WIDBUS_0 & ~SDMMC_CLKCR_WIDBUS_1;
//SDMMC2->CLKCR |= SDMMC_CLKCR_BUSSPEED;
//SDMMC2->CLKCR |= SDMMC_CLKCR_DDR;
//Serial.println(SDMMC2->CLKCR,BIN);
}
void loop() {
mkdir("fs/Serie",0777);
char myFileName[] = "fs/Serie/data.bin";
FILE *myFile = fopen(myFileName, "a");
Time = micros();
fwrite(&tab[0], 2, len, myFile);
Time = micros()-Time;
fclose(myFile);
Serial.print("Time : ");
Serial.println(Time);
delay(5000); // wait a bit
}

Pulsein() function blocks other tasks from running silmultaneously

I am using a zumo bot with a reflectance sensor used to follow a black line. I want to use an arduino to make the zumo bot stop once it gets a certain distance from an obstacle.
I have an ultrasonic sensor (HC-SR04) which ive connected to the bot.
Both of these tasks work independently but once i merge the code together(so it follows the line aswell as stoping when it detects an object using the ultrasonic sensor), it doesn't work properly.. (the zumo bot no longer follows the line)
I THINK it is to do with the pulsein() function blocking any other tasks but not sure.
My code is below. Can anyone help please?
#include <ZumoShield.h>
ZumoBuzzer buzzer;
ZumoReflectanceSensorArray reflectanceSensors;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
int lastError = 0;
// This is the maximum speed the motors will be allowed to turn.
// (400 lets the motors go at top speed; decrease to impose a speed limit)
const int MAX_SPEED = 400;
#define echoPin A4
#define trigPin A5
// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
void setup()
{
reflectanceSensors.init();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// Initialize the reflectance sensors module
// Wait for the user button to be pressed and released
button.waitForButton();
// Turn on LED to indicate we are in calibration mode
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
digitalWrite(13, LOW);
// Wait for the user button to be pressed and released
button.waitForButton();
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Arduino UNO R3");
}
void loop()
{
unsigned int sensors[6];
// Get the position of the line. Note that we *must* provide the "sensors"
// argument to readLine() here, even though we are not interested in the
// individual sensor readings
int position = reflectanceSensors.readLine(sensors);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Our "error" is how far we are away from the center of the line, which
// corresponds to position 2500.
int error = position - 2500;
// Get motor speed difference using proportional and derivative PID terms
// (the integral term is generally not very useful for line following).
// Here we are using a proportional constant of 1/4 and a derivative
// constant of 6, which should work decently for many Zumo motor choices.
int speedDifference = error / 4 + 6 * (error - lastError);
lastError = error;
// Get individual motor speeds. The sign of speedDifference
// determines if the robot turns left or right.
int m1Speed = MAX_SPEED + speedDifference;
int m2Speed = MAX_SPEED - speedDifference;
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
if (m1Speed > MAX_SPEED)
m1Speed = MAX_SPEED;
if (m2Speed > MAX_SPEED)
m2Speed = MAX_SPEED;
motors.setSpeeds(m1Speed, m2Speed);
//if (distance <20){
// motors.setSpeeds(0,0);
// }
////////////////////////////////////////////
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Displays the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
} ```
Of course pulseIn is blocking function. Arduino project is open source, you can easily check source code
Here is C equivalent countPulseASM function which does measurement.
unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
unsigned long width = 0;
// wait for any previous pulse to end
while ((*port & bit) == stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to start
while ((*port & bit) != stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (++width == maxloops)
return 0;
}
return width;
}
If you need measure pulse length in non blocking way, use hw counters.

Arduino Interfacing with Magnetic Pickup

Currently I have a diesel engine with magnetic pickup attached to it. I want to use Arduino (Uno/Nano) to measure engine RPM.
Magnetic Pickup Description: A magnetic pickup is installed over a gear, (most commonly the flywheel inside a vehicle’s bell housing) and as the gear turns the pickup will create an electric pulse for each tooth on the gear. These pulses are then read by the instrument which interprets it to indicate the correct RPMs or speed.The signal from the magnetic speed Sensor, teeth per second(HZ), is directly proportional to engine speed.
Magnetic Pickup Image:
MP - Self Powered
I've tried to rectify the signal using diode then limit the current using a resistor with .1Uf capacitor to filter the noise, then connected it to Optocopler 4N35 and the output from Opto to Arduino interrupt pin, by just observing Arduino interrupt ping is highly affected by surroundings.
Also I have tried to directly connect the magnetic pickup to "A0" pin and use analogue read and connect a led to pin 13 just to monitor the pulses from MP.
int sensorPin = A0;
int ledPin = 13;
int sensorValue = 0;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
digitalWrite(ledPin, HIGH);
delay(sensorValue);
digitalWrite(ledPin, LOW);
Serial.println(sensorValue);
Serial.println(" ");
}
Using analogueRead works with the LED as indicator for pulses generated by pickup. (Tested using small motor and small gear to protect Arduino).
Also I tried to use LM139 Comparator but the readings make no sense
(ex: 60 RPM, 1500 RPM,2150 RPM, 7150 RPM).
LM139 Circuit
Code used with LM139:
// read RPM
volatile int rpmcount = 0;
//see http://arduino.cc/en/Reference/Volatile
int rpm = 0;
unsigned long lastmillis = 0;
void setup() {
Serial.begin(9600);
attachInterrupt(0, rpm_fan, RISING);
//interrupt cero (0) is on pin two(2).
}
void loop() {
if (millis() - lastmillis == 500) {
/*Update every one second, this will be equal to reading frequency (Hz).*/
detachInterrupt(0); //Disable interrupt when calculating
rpm = rpmcount * 60;
/* Convert frequency to RPM, note: this works for one interruption per full rotation. For two interrupts per full rotation use rpmcount * 30.*/
Serial.print(rpm); // print the rpm value.
Serial.println(" ");
rpmcount = 0; // Restart the RPM counter
lastmillis = millis(); // Update lastmillis
attachInterrupt(0, rpm_fan, RISING); //enable interrupt
}
}
void rpm_fan() {
/* this code will be executed every time the interrupt 0 (pin2) gets low.*/
rpmcount++;
}
// Elimelec Lopez - April 25th 2013
What is the best way or approach to interface a magnetic pickup with Arduino to display RPM?
Your use of analogRead is wrong. Besides, analogRead will not get you anywhere close to what you want to achieve.
What you want from your pickup is a clear 0-5v digital signal. You can obtain that by playing with the input resistor on your opto-coupler. I'd do some measurements, and place a trimpot + resistors on the board do the actual value can be tweaked after the system is installed.
Once you get the electrical signal as clean as you can get, you can the use an interrupt pin on the Arduino to keep count of the number of pulses.
#define SENSOR_PIN (2) // using define instead of variable for constants save memory.
#define LED_PIN (13)
#define READ_DELAY (100) // in milliseconds.
// we'll get a reading every 100ms, so 8 bits are enough to keep
// track of time. You'd have to widen to unsigned int if you want
// READ_DELAY to exceed 255 ms.
//
typedef delay_type unsigned char;
typedef unsigned int counter_type; // You may want to use
// unsigned long, if you
// experience overflows.
volatile counter_type pulseCount = 0; // volatile is important here
counter_type lastCount = 0;
delay_type lastTime = 0;
// pulse interrupt callback, keep short.
void onSensorPulse()
{
++pulseCount;
// the following may already be too long. Use for debugging only
// digitalWrite() and digitalRead() are notoriously slow.
//
//
// digitalWrite(LED_PIN, !digitalRead(LED_PIN));
//
// using fastest direct port access instead. (for ATMega)
//
if (pulseCount & 1)
PORTB |= (1 << PB5);
else
PORTB &= ~(1 << PB5);
}
void setup()
{
pinMode(SENSOR_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), onSensorPulse, RISING);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
// control frequency of readings
//
delay_type now = (delay_type)millis();
if (now - lastTime < READ_DELAY)
{
return;
}
lastTime = now;
// get a reading. must disable interrupts while doing so.
// because pulseCount is multi-bytes.
//
noInterrupts();
counter_type curCount = pulseCount;
interrupts();
// get the number of pulses since last reading.
//
counter_type delta = curCount - lastCount;
lastCount = curCount;
// to convert to RPMs, you will need to use this formula:
// note the use of long (UL) to avoid overflows in the
// computation. 60000 = miliseconds per minute.
//
// RPM = delta * 60000UL / (READ_DELAY * TEETH_COUNT);
// send delta to client for now.
//
Serial.println(delta);
}

Beginner Arduino loop function and variable

This is the revised code, the initial value is reading ridiculously high without the conversion!! How do I get the conversion to apply to the initialTemp as well temperatureC?
The code you have helped with as far as I can tell is exactly what I was trying to achieve, but obviously.
Thanks again!!
int pin_tempRead = 0; // temperature sensor pin
int coolLED = 2; // cooling LED digital pin
int heatLED = 3; // heating LED digital pin
float initialTemp;
float cutOffTemp = 30; //cut off temperature = 30°C
void setup()
{
Serial.begin(9600); //Start the serial connection with the computer
pinMode(heatLED, OUTPUT); //initialise as OUTPUT
pinMode(coolLED, OUTPUT); //initialise as OUTPUT
initialTemp = analogRead(pin_tempRead); // read the initial temp
Serial.print("Initial temperature: "); Serial.print(initialTemp); Serial.println("C"); //prints out starting temperature
}
void loop() // run over and over again
{
//getting the voltage reading from the temperature sensor
float current_temp = analogRead(pin_tempRead);
// converting that reading to voltage
float voltage = current_temp * 5.0; voltage /= 1024.0;
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree with 500 mV offset
//to degrees ((voltage - 500mV) times 100)
if(temperatureC > cutOffTemp) {
// temp too high -> turn on the cooling system
digitalWrite(heatLED, LOW);
digitalWrite(coolLED, HIGH);
}else if (temperatureC < initialTemp) {
// temp too low -> turn on the heating system
digitalWrite(heatLED, HIGH);
digitalWrite(coolLED, LOW);
}
Serial.print("Current pump temperature: ");
Serial.print(temperatureC); Serial.println("C");
delay(1000);
}
the loop() function executes over and over, so it's not a good place to store initial values.
What you need to do is define a global variable, initialize it inside the setup() function and then you can read it in the loop() function
Minimalist example:
int pin_tempRead = 0; // temperature sensor pin
float initial_temp; // define a global variable
void setup() {
initial_temp = analogRead(pin_tempRead); // read the initial temp
}
void loop() {
float current_temp = analogRead(pin_tempRead);
// get the temperature difference respect to the initial one
float difference = initial_temp - current_temp;
delay(1000);
}
PD: Also is a good practice to distinguish the variables defining a hardware connection (pins) from the software ones. I usually append pin_ to the variables that define connections. Otherwise is not clear if tempRead is the value of the temperature or the pin where the sensor is attached.
Also, for the turning on and off of the heater/cooling system: You are already in a loop (the loop() function is a loop) so you don't need a while loop.
And you have some problem with our logic.
As I understood, you want to heat until the higher threshold (cutOff) is reached, then cool down until the lower threshold is reached (initialTemperature).
This is called Hysteresis, but your logic was wrong, here's the corrected one:
Just do:
void loop() {
if(temperatureC > cutOffTemp) {
// temp too high -> turn on the cooling system
digitalWrite(heatLED, LOW);
digitalWrite(coolLED, HIGH);
}else if (temperatureC < initialTemp) {
// temp too low -> turn on the heating system
digitalWrite(heatLED, HIGH);
digitalWrite(coolLED, LOW);
}
Serial.print("Current pump temperature: ");
Serial.print(temperatureC); Serial.println("C");
delay(1000);
}
By the way, you are using the initialTemperature as the low threshold for turning on the heating.
Is that what you really want?
What if the initial temperature is higher that the cutOffTemp? You will have problems in that case since the lower threshold is higher than the higher threshold.

Resources