New to the Arduino forum so please take it easy on me as this is my first post here. I'm sure questions revolving around this type of project have been pretty well beaten to death but I'm hoping that as I write the code for my project I can get some input from here regarding hurdles that I encounter.
I'm learning as I go and understand that the best way to learn the Arduino language is to create it yourself and not have others do the work for you. That being said here is a quick description of my project and where I am at currently.
Basic project is to use an Arduino Uno to control the powering of my dust collector by using a SSR-40 DA solid state relay to cycle on & off the actual dust collector. This should be accomplished by using a current sensing switch at each tool that needs dust collection. The current sensing switch will send a signal to the Arduino telling it that a particular tool has been turned on. In turn, the Arduino with then complete 2 tasks. 1. It powers a low current relay module to ultimately turn on a pneumatic solenoid which activates a pneumatic air cylinder used to open the appropriate blast gate.
2. It also powers the low current side of a solid state relay to ultimately turn on the dust collector.
I have been successful so far in writing the code so the Arduino will recognize when a tool is powered on utilizing the current sensing switch (only one current sensing switch is being utilized at this point, but will ultimately use 6 switches and 6 relays for the pneumatic solenoids). I have also been successful in writing the code to activate the low current relay that activates the pneumatic solenoid for the blast gate.
My real first question is this: Is it best to use the "BlinkWithoutDelay" command to add a specific time delay before turning off the command to shut down the solid state relay that will power down the dust collector? I have played around with the basic command "Delay" but it appears to have an effect on other functions during the sequence. Where is the best location to place the "Delay" or "BlinkWithoutDelay" into the loop. If "BlinkWithoutDelay" is the better choice, does someone have a simple example of code that would accomplish what I am looking to do which is to add approx. a 10 second delay to shutting off the dust collector.
I've also tried to create meaningful code that displays a few bits of data on the Serial Monitor to hopefully check to see that the code is doing what I would like to do. Please feel free to critique my work as I am positive there are many ways to accomplish what I am looking to doing and there is a good possibility that I have not chosen the best options.
Here is the current code as it exists right now. I hope that I posted the code properly here...
//THESE CONSTANTS WON'T CHANGE:
//Digital pin 2 has the current sensor #1 attached
// to it & it's named CURRENT_SENSOR_1:
const int CURRENT_SENSOR_1 = 2;
//Digital pin 13 has the dust collector power relay
// attached to it and it's named DUST_COLLECTOR_RELAY:
const int DUST_COLLECTOR_RELAY = 13;
//THIS VARIABLE WILL CHANGE:
//Current state of the current_sensor_1:
int buttonState = 0;
//The setup routine runs once when uploaded:
void setup() {
// put your setup code here, to run once:
//initilizes serial communication at 9600 baud to the Serial Monitor:
Serial.begin(19200);
//Initilizes the CURRENT_SENSOR_1 as an input:
pinMode(CURRENT_SENSOR_1,INPUT);
//Initilizes the DUST_COLLECTOR_RELAY as an output:
pinMode(DUST_COLLECTOR_RELAY,OUTPUT);
}
//The loop routine runs over & over:
void loop() {
//Reads the input pin:
buttonState = digitalRead(CURRENT_SENSOR_1);
//If current sensor 1 reads current, display "CURRENT_SENSOR_1: ON" on
// the Serial Monitor:
if (buttonState == HIGH) {
Serial.println ("CURRENT_SENSOR_1: ON");
//If current sensor 1 does not read current, display "CURRENT_SENSOR_1: OFF" on
// the Sertial Monitor:
} else {
Serial.println("CURRENT_SENSOR_1: OFF");
}
//sends the state of CURRENT_SENSOR_1 to be displayed on the Serial Monitor
Serial.println(buttonState);
//If CURRENT_SENSOR_1 senses current, it turns on power to the
// DUST_COLLECTOR_RELAY and display "DUST_COLLECTOR_RELAY: ON" on the Serial Monitor
if (buttonState == HIGH) {
Serial.println ("DUST_COLLECTOR_RELAY: ON");
} else {
Serial.println ("DUST_COLLECTOR_RELAY: OFF");
//Adds a 1/2 second delay between display values on Serial Monitor
delay(500);
}
//Turns on the DUST_COLLECTOR_RELAY if the CURRENT_SENSOR_1 sense current flowing:
if (buttonState == HIGH) {
digitalWrite(DUST_COLLECTOR_RELAY, HIGH);
//Turns off the DUST_COLLECTOR_RELAY if CURRENT_SENSOR_1 does not sense
// current flowing and adds a delay of 5 seconds before turning it off:
} else {
delay(5000);
digitalWrite(DUST_COLLECTOR_RELAY, LOW);
}
}/code]
Thanks for any assistance any of you may offer up!
Congrats on the code tags on your first post, a rare accomplishment sadly.
Blink without delay is almost certainly the way to go. Even if it doesn't seem like it is absolutely necessary now, it probably will later. Most projects evolve and eventually you will need to react quickly to a user input. Use of long delays will make that impossible.
In your case, unless you always work alone, you may need to consider that a second tool will call for dust extraction. Use of delay would cause that call to be well, delayed.
I suggest that you implement the hardware and code for a second blast gate. Preferably the furthest from the Arduino. I would want to know that the wire run length is ok. Also that your code can handle multiple tools. As mentioned, with the delay you're using, it won't do it well.
Comments are good. Comments that echo the code, not so much. I noticed one where the code has evolved away from the comment (baud rate). Comments should tell the reader something they can't tell from the code; why are we doing this, not how.
As a first go at it, I'd keep a count of tools that are on. Whenever one goes off, note the time using millis. If none are on and millis()-time_recorded > some_threshold, turn off the dust collection.
Since this shop setup is located in my garage, the thought is that only one power tool (and therefore only one blast gate) will be operated at any given time. There is always a possibility that there may be another person operating a tool that requires dust collection, but I am currently okay with not being able to activate multiple blast gates at the same time. I suppose I will need to think about this more throughly, but current plan is one tool only. Not sure how multiple tools on at once would affect the programming required to make that happen.
The size of the shop is relatively small (approx 25'x30'). I plan on running 18 awg to/from each device. I can't see the longest run being more than 40 feet.
I will continue to cleanup/refine my comments before each line of code. This is my first real go at it so I'm definitely learning as I go.
Looks like I need to dive into the BlinkWithoutDelay command to better understand just how that works. Thanks again for your suggestions!
Okay..I changed a few commands around and cleaned things up a bit as well as the comments and the program seems to operate properly in terms of turning on the pneumatic solenoid relay 1 and the dust collector relay when a power tool is turned on and the current sensing switch 1 senses current.
The "Delay" command as mentioned before, makes things act a little wonky and I need to learn more about the "BlinkWithoutDelay" command before I try to replace the "Delay" command with it.
Any suggestions for improvements with what I have so far??? Is there a good tutorial to help better understand the "BlinkWithoutDelay" command???
//THESE CONSTANTS WON'T CHANGE:
//Digital pin 2 has the current sensor #1 attached
// to it & it's named CURRENT_SENSOR_1:
const int CURRENT_SENSOR_1 = 2;
//Digital pin 13 has the dust collector power relay
// attached to it and it's named DUST_COLLECTOR_RELAY:
const int DUST_COLLECTOR_RELAY = 13;
//Digital pin 12 has the pnuematic solenoid relay #1
// attached to it and it's named PNEUMATIC_SOLENOID_RELAY_1:
const int PNUEMATIC_SOLENOID_RELAY_1 = 12;
//THIS VARIABLE WILL CHANGE:
//Current state of the current_sensor_1:
int buttonState = 0;
void setup() {
// put your setup code here, to run once:
//initilizes serial communication at 19200 baud to the Serial Monitor:
Serial.begin(19200);
//Initilizes the CURRENT_SENSOR_1 as an input:
pinMode(CURRENT_SENSOR_1,INPUT);
//Initilizes the DUST_COLLECTOR_RELAY as an output:
pinMode(DUST_COLLECTOR_RELAY,OUTPUT);
//Initilizes the PNUEMATIC_SOLENOID_RELAY_1 as output:
pinMode(PNUEMATIC_SOLENOID_RELAY_1,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
//Reads the input pin:
buttonState = digitalRead(CURRENT_SENSOR_1);
//Adds a 1/2 second delay between display values on Serial Monitor:
delay(1000);
//If CURRENT_SENSOR_1 is reading current from power tool,
// it displays "CURRENT_SENSOR_1: ON" on the Serial Monitor:
if (buttonState == HIGH) {
Serial.println("CURRENT_SENSOR_1: ON");
//If CURRENT_SENSOR_1 is reading current from power tool,
// it displays "DUST_COLLECTOR_RELAY: ON" on the Serial Monitor:
Serial.println("DUST_COLLECTOR_RELAY: ON");
//If CURRENT_SENSOR_1 is reading current from power tool, it displays
// "PNUEMATIC_SOLENOID_RELAY_1: ON" on the Serial Monitor:
Serial.println("PNUEMATIC_SOLENOID_1: ON");
//If CURRENT_SENSOR_1 is reading current from power tool, it supplies
// 5 volts to terminal #13 to power the DUST_COLLECTOR_RELAY:
digitalWrite(DUST_COLLECTOR_RELAY, HIGH);
//If CURRENT_SENSOR_1 is reading current from power tool, it supplies
// 5 volts to terminal #12 to power the PNUEMATIC_SOLENOID_RELAY_1:
digitalWrite(PNUEMATIC_SOLENOID_RELAY_1, HIGH);
//If CURRENT_SENSOR_1 does not read current, it displays
// "CURRENT_SENSOR_1: OFF" on the Sertial Monitor:
} else {
Serial.println("CURRENT_SENSOR_1: OFF");
//If CURRENT_SENSOR_1 does not read current from power tool, it displays
// "DUST_COLLECTOR_RELAY: OFF" on the Serial Monitor:
Serial.println("DUST_COLLECTOR_RELAY: OFF");
//If CURRENT_SENSOR_1 does not read current from power tool, it displays
// "PNUEMATIC_SOLENOID_RELAY_1: OFF" on the Serial Monitor:
Serial.println("PNUEMATIC_SOLENOID_RELAY_1: OFF");
//Adds a 5 second delay before turning off Dust Collector:
delay(5000);
//If CURRENT_SENSOR_1 does not read current from power tool, it supplies
// 0 volts to terminal #13 to power off the DUST_COLLECTOR_RELAY:
digitalWrite(DUST_COLLECTOR_RELAY, LOW);
//Adds a 10 second delay before pnuematic solenoid relay:
delay(10000);
//If CURRENT_SENSOR_1 does not read current from power tool, it supplies
// 0 volts to terminal #12 to power off the PNUEMATIC_SOLENOID_RELAY_1:
digitalWrite(PNUEMATIC_SOLENOID_RELAY_1, LOW);
}
}/code]
Take a look at arrays. It may not be obvious yet but you're going to need them. It's one of the reasons I suggested that it's time to add a second tool into the mix, at least in the code.
wildbill:
Take a look at arrays. It may not be obvious yet but you're going to need them. It's one of the reasons I suggested that it's time to add a second tool into the mix, at least in the code.
Thanks Wildbill...
I understand that one set of commands for controlling a device is relatively simple, but when you start to add multiple inputs and/or outputs things change in a hurry. Not sure if my current code will allow for multiple tools. I plan on trying to write some additional code for this today to see what happens.
injurer:
Is there a good tutorial to help better understand the "BlinkWithoutDelay" command???
The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.
Note how each function in "Several things" runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.
I dont see anyone mention it here, but ssrs need special precautions when used. They are basically NOT designed to be used with inductive loads such as motors. Plus they need a capable heatsink adjusted with the load's current draw.
Motors have something called a Full Load Amp and Locked Rotor Amp. The latter is the current the motor draws at startup, and it is generally 4 to 8 times larger then the amp that the motor is rated in, and thats our FLA.
Cheap chinese ssrs comes up when searching for ssr 40 DA, i know thats not what it means, but still.. They never mostly have any capable Triac inside them. They are a fire hazard so tread VERY lightly.
SSR's need to be selected way over the rated current for inductive loads. Refer to this pdf by crydom.
I'm at the point in writing the code for this project that needs to do the following:
Recognize when a tool is turned off (current sensing switch goes to "low") and adds a "delay" to the command to shut off the dust collector by several seconds.
I have researched the use of millis(), but so far it appears that this is used for timed events based upon the initial start of the program running and not the change of state of a device being controlled in the program.
In a more simpler form, how would one make millis () start its countdown not from the moment the arduino was launched, but from the moment the button was pressed? For example, when a button is pressed, the LED turns on and turns off after 2 seconds?
I'm sure this is a simple operation to program, I just haven't found and examples of doing what I need from any of the searches I've done so far.
When you detect that the tool has gone off, store the current value of millis in a variable. Each time around loop, check to see what the difference is now between millis and what you saved. When it's big enough, turn the dust extraction off.
I've started a similar project myself, but slightly different approach. It's stalled as I'm waiting for the electricians to install the power supplies; it's pretty much a complete shop build.
Each tool will get a blast gate - operated by either a current sensor or a switch (for e.g. sanders, or just a vacuum cleaner attachment). Blast gates will be operated by a servo, no pneumatics here. Also I found a very nice panel mounted red/green LED which I'm going to use to indicate the status of that particular gate.
A major difference to the approach is that each blast gate will have it's own controller (ATtiny84a on custom PCB). There's going to be a single signal line, with the PCBs daisy chained and relaying the upstream signal - a simple high/low voltage to signal whether the dust extractor should be on or not. Should be reliable. All signal wires have a simple RC filter on both ends to help quench noise.
For the switching of the dust extractor itself I've opted for a contactor, that is sufficiently rated for the 2.2 kW 3 phase extraction fan. Basically a relay on steroids, designed to handle inductive loads. Cheaper than an SSR and no heat. The main issue there is that contactors are almost impossible to find with a 5V coil, so instead I went for a 220V coil which in turn is switched by a TRIAC.
For the programming: indeed there will be a delay in switching the fan. There must be at least 10 seconds between switching: the fan will switch off 10 seconds after the last tool has switched off (i.e. 10 seconds after the signal went low), and it will not switch on within 10 seconds of being switched off. That indeed is using the Blink Without Delay technique, setting the timer based on the signal every time loop() runs.
The delay times I may want to fine tune later (it's only in the design stage), and come to think of it maybe I should make the fan activation signal active low, to be able to use the internal pull-up of the ATtiny and ensure the fan remains off when there is no input signal present (or the wire is broken).
wvmarle:
I've started a similar project myself, but slightly different approach. It's stalled as I'm waiting for the electricians to install the power supplies; it's pretty much a complete shop build.
Each tool will get a blast gate - operated by either a current sensor or a switch (for e.g. sanders, or just a vacuum cleaner attachment). Blast gates will be operated by a servo, no pneumatics here. Also I found a very nice panel mounted red/green LED which I'm going to use to indicate the status of that particular gate.
A major difference to the approach is that each blast gate will have it's own controller (ATtiny84a on custom PCB). There's going to be a single signal line, with the PCBs daisy chained and relaying the upstream signal - a simple high/low voltage to signal whether the dust extractor should be on or not. Should be reliable. All signal wires have a simple RC filter on both ends to help quench noise.
For the switching of the dust extractor itself I've opted for a contactor, that is sufficiently rated for the 2.2 kW 3 phase extraction fan. Basically a relay on steroids, designed to handle inductive loads. Cheaper than an SSR and no heat. The main issue there is that contactors are almost impossible to find with a 5V coil, so instead I went for a 220V coil which in turn is switched by a TRIAC.
For the programming: indeed there will be a delay in switching the fan. There must be at least 10 seconds between switching: the fan will switch off 10 seconds after the last tool has switched off (i.e. 10 seconds after the signal went low), and it will not switch on within 10 seconds of being switched off. That indeed is using the Blink Without Delay technique, setting the timer based on the signal every time loop() runs.
The delay times I may want to fine tune later (it's only in the design stage), and come to think of it maybe I should make the fan activation signal active low, to be able to use the internal pull-up of the ATtiny and ensure the fan remains off when there is no input signal present (or the wire is broken).
wvmarle-
Sounds like you have some great ideas planned. It's interesting to see that there are so many different approaches to create something and that all of them can/will work. Hope it all comes together for you.
Since I'm new to the Arduino programming world, I sometimes struggle to fully understand some code and how best to use it. I do understand Wildbill's suggestion for the delay in turning off the dust collector, but have a difficult time creating the code to do so. I seem to do best when I have an example in front of me that is doing something similar so that I can study it first and then write my own version. So far I have not been successful in finding any examples of creating a delay based upon a particular event rather having it based off the initial start of the program. I know it's probably a simple concept that I'm overlooking, but nevertheless, I haven't gotten anything work nor fully understand it yet.
Here is some basic code. It started out as the state change example from the IDE and I tweaked it to do the dust collection delay mechanism using millis. It illustrates the general technique for using millis for timing as in the threads Robin2 linked, but with a specific application (workshop) in mind.
const byte CurrentSensorPin = 2; // the pin that the CurrentSensor is attached to
const byte DustCollectorPin = 13; // the pin that the Dust collector relay is attached to
const unsigned long DustCollectionDelay=5000;
int CurrentSensorState = LOW;
int lastCurrentSensorState = LOW;
unsigned long ToolOffTime=0;
bool RunningDustCollectionDelay=false;
void setup()
{
Serial.begin(115200);
pinMode(CurrentSensorPin, INPUT);
pinMode(DustCollectorPin, OUTPUT);
}
void loop()
{
CurrentSensorState = digitalRead(CurrentSensorPin);
if (CurrentSensorState != lastCurrentSensorState)
{
if (CurrentSensorState == HIGH) // Tool just came on
{
digitalWrite(DustCollectorPin,HIGH); // Start dust collector
}
else
{
ToolOffTime=millis();
RunningDustCollectionDelay=true;
}
delay(20); // debounce
lastCurrentSensorState = CurrentSensorState;
}
if(RunningDustCollectionDelay && (millis()-ToolOffTime > DustCollectionDelay))
{
digitalWrite(DustCollectorPin,LOW); // Stop dust collector
RunningDustCollectionDelay=false;
}
}
JCA34F:
What kind of output signal does your current sensor produce? Post a link to datasheet or seller's web page.
JCA34F-
The current sensor is quite simple as it is has a set of contacts that are normally open. When it senses current flow, the contacts close. I use this connected to the Arduino board where that pin usually sees 0v when the current switch is "open", and 5v when the current with is "closed".
wildbill:
Here is some basic code. It started out as the state change example from the IDE and I tweaked it to do the dust collection delay mechanism using millis. It illustrates the general technique for using millis for timing as in the threads Robin2 linked, but with a specific application (workshop) in mind.
const byte CurrentSensorPin = 2; // the pin that the CurrentSensor is attached to
const byte DustCollectorPin = 13; // the pin that the Dust collector relay is attached to
const unsigned long DustCollectionDelay=5000;
int CurrentSensorState = LOW;
int lastCurrentSensorState = LOW;
unsigned long ToolOffTime=0;
bool RunningDustCollectionDelay=false;
YES...thank you! That's what I was looking for. I believe I was "close" with what I created, but my programming skills a still pretty shallow, so it's easy to overlook some necessary details. I will play around with this and I feel confident I can get the delay to work as it should. Thanks again!
I doubt the switch in that device are dry relay contacts, probably an open collector / drain transistor and may not work like @wildbill's sketch. I would like to see the datasheet.
After playing around with the code a bit, I find that it works sort of...
If the current sensor state is high, it tells the dust collector relay to turn on - perfect!
If the current sensor state goes low WITHIN 5 seconds of it going high, it delays the dust collector relay from actually being turned off - perfect!
But...If the current sensor state stays high for greater than 5 seconds (tool is run for more than 5 seconds), it turns the dust collector relay off immediately (no delay).
const byte CurrentSensorPin = 2; // the pin that the CurrentSensor is attached to
const byte DustCollectorPin = 13; // the pin that the Dust collector relay is attached to
const unsigned long DustCollectionDelay=5000;
int CurrentSensorState = LOW;
int lastCurrentSensorState = LOW;
unsigned long ToolOffTime=0;
bool RunningDustCollectionDelay=false;
void setup()
{
Serial.begin(9600);
pinMode(CurrentSensorPin, INPUT);
pinMode(DustCollectorPin, OUTPUT);
}
c
void loop()
{
CurrentSensorState = digitalRead(CurrentSensorPin);
if (CurrentSensorState != lastCurrentSensorState)
{
if (CurrentSensorState == HIGH) // Tool just came on
{
digitalWrite(DustCollectorPin,HIGH); // Start dust collector
}
else
{
ToolOffTime=millis();
RunningDustCollectionDelay=true;
}
delay(20); // debounce
lastCurrentSensorState = CurrentSensorState;
}
if(RunningDustCollectionDelay && (millis()-ToolOffTime > DustCollectionDelay))
{
digitalWrite(DustCollectorPin,LOW); // Stop dust collector
RunningDustCollectionDelay=false;
}
}