Delay Wanted in Reading IRMS values

Looking for some guidance on a project. I’ve built a dust collection system using an Arduino Mega 2560, and some AC current sensors. For all intents and purposes, it is working as expected.

My plan is to keep the Arduino powered off when not in use. Each time I power on, the sensors are read and I see a value of approx. 138 for each of the four sensors and then they return to near zero.

I’ve set my IRMS values to min value of 150, so that the dust collector does not turn on until the set value for each piece of equipment is reached.

Regardless of the min. value set, for the ‘boot’ time of the Arduino, and the reading of the sensors, the dust collector will turn on and quickly off.

I’m looking for a way to prevent this short on/off cycle of the dust collector when I turn on the Arduino. Any help would be appreciated. I’m just an old guy with a shop, trying to learn some new stuff, so not really a programmer.

Sketch Repository

// Dust Collection System for Shop

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 4 line display
/*********************************************************/

/* Program for Dust Collection System - Trent Badger's shop */

#include "EmonLib.h"          // Include Emon Library
EnergyMonitor tool1, tool2, tool3, tool4;   // Create instances - Table Saw, Miter Saw, CNC Router

const int dustCollectionRelayPin = 51; //Relay to Dust collector
const int blastGate1Pin = 27; // DC Leg 1 gate
const int blastGate2Pin = 35; // Table saw gate
const int blastGate3Pin = 39; // Miter Saw gate
const int blastGate4Pin = 43; // CNC Router gate
const int blastGate5Pin = 47; // Optional gate

void setup()
{
  Serial.begin(9600);
  pinMode(dustCollectionRelayPin,INPUT_PULLUP);
  pinMode(blastGate1Pin,INPUT_PULLUP);
  pinMode(blastGate2Pin,INPUT_PULLUP);
  pinMode(blastGate3Pin,INPUT_PULLUP);
  pinMode(blastGate4Pin,INPUT_PULLUP);
  pinMode(blastGate5Pin,INPUT_PULLUP);
  
  pinMode(dustCollectionRelayPin,OUTPUT);
  pinMode(blastGate1Pin,OUTPUT);
  pinMode(blastGate2Pin,OUTPUT);
  pinMode(blastGate3Pin,OUTPUT);
  pinMode(blastGate4Pin,OUTPUT);
  pinMode(blastGate5Pin,OUTPUT);
      
  digitalWrite(dustCollectionRelayPin,HIGH);  // enable off
  digitalWrite(blastGate1Pin,HIGH);           // enable off
  digitalWrite(blastGate2Pin,HIGH);           // enable off
  digitalWrite(blastGate3Pin,HIGH);           // enable off
  digitalWrite(blastGate4Pin,HIGH);           // enable off
  digitalWrite(blastGate5Pin,HIGH);           // enable off
  
  double Irms1 = 0;
  double Irms2 = 0;
  double Irms3 = 0;
  double Irms4 = 0;
   
  lcd.init();       //initialize the lcd
  lcd.backlight();  //open the backlight 

  lcd.clear();
  lcd.setCursor(0,0);           // set cursor to column 0, row 0 (the first row)
  lcd.print("DC X");
  lcd.setCursor(0,1);
  lcd.print("ShopTool Monitor");
  delay(4000);

  tool1.current(0, 111.1);  // Current: input pin, calibration for table saw
  tool2.current(1, 111.1);  // Current: input pin, calibration for miter saw
  tool3.current(2, 111.1);  // Current: input pin, calibration for cnc router
  tool4.current(3, 111.1);  // Current: input pin, calibration for cnc router
}

void loop()
{
  double Irms1 = tool1.calcIrms(1480);  // Calculate Irms only
  double Irms2 = tool2.calcIrms(1480);  // Calculate Irms only
  double Irms3 = tool3.calcIrms(1480);  // Calculate Irms only
  double Irms4 = tool4.calcIrms(1480);  // Calculate Irms only
 
  lcd.clear();
  lcd.setCursor(0,3);
  lcd.print ("Dust Collection OFF");
  
  lcd.setCursor (0,0);
  lcd.print("TS: ");
  lcd.setCursor (4,0);
  lcd.print(Irms1);
  
  lcd.setCursor (10,0);
  lcd.print("MS: ");
  lcd.setCursor (14,0);
  lcd.print(Irms2);

  lcd.setCursor (0,1);
  lcd.print("RT: ");
  lcd.setCursor (4,1);
  lcd.print(Irms3);
  
  lcd.setCursor (10,1);
  lcd.print("MT: ");
  lcd.setCursor (14,1);
  lcd.print(Irms4);
  
    if (Irms1 > 250) {  //set to range on startup of table saw ~250
      digitalWrite(blastGate1Pin,LOW); // enable on
      digitalWrite(blastGate2Pin,LOW); // enable on
      clearRow(3);
      lcd.setCursor(0,3);
      lcd.print ("Table Saw (IRMS1)");
      delay(2000);
      dustOn();
      
    } else 
    
    if (Irms2 > 150) { //set to range on startup of CNC Spindle ~150
      digitalWrite(blastGate1Pin,LOW); // enable on
      digitalWrite(blastGate3Pin,LOW); // enable on
      clearRow(3);
      lcd.setCursor(0,3);
      lcd.print ("DC ON IMRS2  ");
      delay(2000);
      dustOn(); 

    } else

     if (Irms3 > 150) { //set to range greater than 138 on startup of controller ~150
      digitalWrite(blastGate4Pin,LOW); // enable on
      clearRow(3);
      lcd.setCursor(0,3);
      lcd.print ("DC ON IRMS3  ");
      delay(2000);
      dustOn(); 

    } else

     if (Irms4 > 150) { //set to range greater than 138 on startup of controller ~150
      digitalWrite(blastGate5Pin,LOW); // enable on
      lcd.setCursor(0,3);
      clearRow(3);
      lcd.print ("DC ON IRMS4  ");
      delay(2000);
      dustOn();  
      
    } else {
      dustOff();
      delay(2000);
      digitalWrite(blastGate1Pin,HIGH); // enable off
      digitalWrite(blastGate2Pin,HIGH); // enable off
      digitalWrite(blastGate3Pin,HIGH); // enable off
      digitalWrite(blastGate4Pin,HIGH); // enable off
      digitalWrite(blastGate5Pin,HIGH); // enable off
     }
}

void dustOn()
{
   digitalWrite(dustCollectionRelayPin,LOW); // enable on
}

void dustOff()
{
   digitalWrite(dustCollectionRelayPin,HIGH); // enable off
}

void clearRow(byte rowToClear)
{
  lcd.setCursor(0, rowToClear);
  lcd.print("                    ");  
}

Welcome @retired_badger - could you add a schematic as well? I’m inferring that the relays are turned on when the output is LOW.

I suspect the issue is setting the relay drivers as inputs before setting them as outputs. I can’t see why you’re doing that, but you can try removing the 6 lines after Serial.begin(9600);.

I’ll remove the 6 lines first and give that a shot. Will take a bit to draw up a schematic.

Thanks @awjlogan for the input.

It could also be the software filter which removes the artificial bias added by the electronics to bring the c.t. output into the middle of the input range (see the ‘Learn’ part of Docs here for a full explanation). It can generate a number of false high readings which gradually tail away as the circuit stabilises. Generally, it’s not a problem because when used for energy monitoring, the power is applied permanently and so your situation arises only once in months or years.
EmonLib is quite an old piece of software now and it’s unlikely it will ever get modified or updated.

The answer will be to let it read the currents for a few times and only after the delay has expired do you do the section in your sketch where you decide one of the machines is running. It looks as if you update everything every 2 s, so I’d guess that delaying by 5 times around loop( ) should be enough.

What sort of time does it run for when “the dust collector will turn on and quickly off”? if it’s 4 - 6 seconds, then I think this is likely to be what’s happening.

Slightly interesting sidebar (@retired_badger ignore the timings in my post here and follow Robert’s advice above) I have to do the exact same thing when dealing with my energy IC. Just goes to show how similar all these implementations are:

#define RMS_SETTLING_TIME  440                // 440 msecs (see datasheet)

    //
    // If we're just booting, ignore the Irms values until the 7816 filters settle.
    // Otherwise they're big enough to start us off with false LED indications
    //
    if ((millis() - _7816_started[device]) < RMS_SETTLING_TIME)
      continue;

1 Like

Yep, there aren’t too many different ways of achieving what we’re trying to do.

The initial problem is it takes time for the midpoint d.c. bias to get to its final value, and in doing so, the filter (whatever sort it is) in the software, whose job it is to remove that bias to recover the original waveform, is chasing a moving target. The best solution is to not require a bias at all, but this adds a lot of complication and cost to the hardware. The next best is, wait until it’s settled down and then never switch it off.

And one point to add: In the hardware, the bias time constant is around 2 s, so it settles reasonably closely to its quiescent value in about 10 s. In emonLib, the software filter extracts the d.c. level and then subtracts it, and it only works while it’s doing its 1480 zero crossings sample. This is why I said n times around the loop - because while it’s frozen during the 2 s delay in the sketch, the hardware target has moved.

Removing the six lines of code did not have any impact. Thanks for the suggestion. I don’t know why I did this (5 years ago), but had followed some tutorial that had that code specifically included that.

@Robert.Wall, the dust collector turns on for less than 2 seconds, if that before it turns off.

I’ve set all delays to 10 seconds (10000), but that doesn’t change things either. I’ve also changed the original delay of 4 seconds after 'lcd.print(“ShopTool Monitor”); to 10 seconds, which also did not have any impact.

I may have to live with the brief startup of the dust collector when I turn things on. I didn’t want to leave the system on because I don’t want any long term burn in on the LCD.

Can you clarify where I’d place this in the sketch, if it were not the delay in each of the “if” statements for the IRMS? Not being a programmer and understanding all of this stuff, my 63+ year old brain got me this far with dozens of tutorials and videos. But I’m still limited in knowing where to start on “n” times around the loop if adjusting the delays did not work.

I’ve got a decade and a bit start on you. :face_with_hand_over_mouth:

Before we go any further, here’s what happens to the input of an emonTx V2 at power-up. It takes about 10 s to reach its quiescent operating point of half the supply (1.65 V). I’m guessing you copied your input circuit from this, or something similar.

I don’t think you understood these two bits of information taken together.

What I originally suggested was leave your 2 s delays - you clearly want those.
What you need to do is all this section:

  double Irms1 = tool1.calcIrms(1480);  // Calculate Irms only
  double Irms2 = tool2.calcIrms(1480);  // Calculate Irms only
  double Irms3 = tool3.calcIrms(1480);  // Calculate Irms only
  double Irms4 = tool4.calcIrms(1480);  // Calculate Irms only

but not the section where you decide to run the extractor until you’ve done that first part a few times. The easy way is at the top of the sketch, anywhere before setup( ), create a counter:

unsigned long startupCounter = 0;

after the section I quoted above, increment the counter:

startupCounter++;

Make an “if” block of all of loop( ) from and including if (Irms1 > 250) { up to but not including the final } before void dustOn(), with an else block in which it will do only a delay instead:

if (startupCounter > 20)
{

[all the 4 sets of LCD commands and 'dust on - dust off' etc 
 goes in here]

}
else 
{
   delay(500);
}

This substitutes a ½ s delay instead of your 2 s only during the startup, and after reading all the currents 20 times and delaying for 20 × 500 ms (so about 20 - 25 seconds in total) it will switch to doing what you want - which is acting on the measured currents to turn the extractor on or off.

The overall effect of all this is:
At power-up, it will rapidly read and display all the currents for about 20-25 seconds but do nothing else. (I assume you probably won’t start a machine during that period anyway - but if you do, the extractor won’t run.)
At the end of this wait, it will act on the currents it’s measured - if a machine is running, it will put the machine name on the display and after 2 s, start the extractor. Or if nothing is running, it will stop the extractor and do the blast gates.

Nailed it. :rofl:

Getting my son over in the next few days, he’s a python programmer, and he’ll be able to help me work through this. I’m sure it will make total sense to him.

Thanks for your input, assistance, and patience.

1 Like

I gave this a go (on my own), and it works! Thank you so much @Robert.Wall! :grin: :tada: There are a few more things I want to add, like an override to turn on the dust collector with a button and no tool on, and a few more like things, as well as what he calls “dry” programming. Definitely will have the programmer in the family help me out with that. Again, thanks for your help. Made my day.

2 Likes

Coupled with you extending your timers to 10 s to no avail, I think this is conclusive evidence that it was indeed the inflated current readings whilst the bias circuit and the filter to remove the bias stabilised which caused to dust collector to fire up.

1 Like

After reviewing the code and what some of the settings mean, these lines initialize the digital pins as an input with the internal pull-up resistor enabled. Therefore, Arduino reads them as HIGH or “off”. So it is working as I expected. As noted in another thread of comments, it was the initial reading and stabilizing of the sensors that was causing the “on” or “LOW” state of the relay. That has been corrected and now is resolved.

  pinMode(dustCollectionRelayPin,INPUT_PULLUP);
  pinMode(blastGate1Pin,INPUT_PULLUP);
  pinMode(blastGate2Pin,INPUT_PULLUP);
  pinMode(blastGate3Pin,INPUT_PULLUP);
  pinMode(blastGate4Pin,INPUT_PULLUP);
  pinMode(blastGate5Pin,INPUT_PULLUP);

@awjlogan, thanks for your input. I’m taking some time going through the code and documenting the settings and values so that in the future I understand what things are doing.

tb

Glad it’s working - I wasn’t clear why they were being set as inputs then immediately set as outputs, but wondered if the pull ups were causing the motors to start up. Enjoy the rest of the project, lots of good things to learn :slight_smile:

It doesn’t make sense to me either. It might have made sense for an experimental breadboard, because an input pin is high impedance and if unused but accidentally shorted to either supply rail, no damage will be caused. I had a feeling that there was an arcane reason buried in the data sheet, but I can’t see anything - all I can see is about unconnected pins, and these aren’t. (Atmel data sheet ATmega48PA/88PA/168PA/328P, section 13.2.6.) It might have been this that I had at the back of my mind.

Min value 20 kΩ, max 50 kΩ ? Maybe. But as logic HIGH is off, that doesn’t make sense either. They’ll be tri-state during the reset on startup - but would a relay pull in during reset, I doubt it would notice.

One thing I ought to mention - your number in calcIrms( ) of 1480 samples might not be optimal. The intention is to sample for a whole number of cycles. The sampling rate of emonLib, measured with a standard emonTx V3.4 (and if your Arduino uses the AtMega 328P, it’s the same processor) is approx 5588 current samples per second. This gives you 93.1333 samples per mains cycle, and 1397 would give you exactly 15 cycles, or 250 ms sampling period. (With 1480, it falls a little more than a tenth of a cycle short of 16.)

If you notice the current measurements fluctuate from reading to reading for no apparent reason, this might be the cause, and it’s worth changing the value. If you don’t see a cause for concern, it’s not worth the trouble of changing it.

1 Like

I think the code is best practice as written. The power on reset state of those pins is INPUT with no pull-ups. In this application the desired starting state is OUTPUT HIGH. That first block of pinMode() calls isn’t about making them inputs (they already are) but rather about switching the pull-ups on. The next block switches them all to OUTPUT so they’ll seamlessly transfer from being pulled high to being driven high. The final block of digitalWrite() calls drives them all high - that code is redundant (but doesn’t hurt) as they’ll already be high thanks to the pullups being enabled earlier.

If you remove that first block of pinModes(INPUT_PULLUP) calls then you’ll transition from INPUT with no pull-ups to OUTPUT LOW as you switch them all to OUTPUT. In that case the following block of digitalWrite(HIGH) calls does become vital in order to fix the LOW glitch you’ve just generated.

See 13.2.3 Switching Between Input and Output.

1 Like

This diagram helps explain what’s going on…

Setting the bit in the PORT register turns the pull-up on, or turns the pin on, depending on the corresponding bit in the DD register. The power-up state of both bits is 0 so the pin is Hi-Z. The desired initial state in this applications is OUTPUT HIGH, i.e. both bits set but you can only write one bit at a time. By writing the PORT bit first (i.e. turning the pull-up on) you avoid visiting the OUTPUT LOW state on the way to your desired state of OUTPUT HIGH.

1 Like

Thanks @dBC, all makes sense - should have read the datasheet, haven’t used AVRs is a long time :slight_smile: