Controlling servos with current detectors

Hi I'm new to this Forum and to the Arduino world.

I'm trying to automate the dust collection in mi woodshop.
I have 5 machines and for each a blast gate.

I have an Arduino UNO board.
5 ACS 712 20A current sensors.
5 DM996 servo moters.

The goal is to detect if a machine is on and then open the correct blast gate ans close the rest.
I don't want the blast gate to close when the machine stops.

GND and 5V is wired to external power.
I have wired 1 sensor to GND and 5V and the output to A0
I have wired 1 servo to GND and 5V and the input to pin 9

I have found code to read sensor output ant print it to "Serial.print( Amps_TRMSS1 )"
I have made code to controle the servo using angel 0-180.
I have made an " if (Amps_TRMSS2 >11) " to trigger the servo to open.

This all works super with just one sensor and on servo.

I want to wire all 5 machines and 5 servos to one Arduino board.
sensor 1: ACS_PinS1 - A0
sensor 2 : ACS_PinS2 - A1
sensor 3: ACS_PinS3 - A2
sensor 4: ACS_PinS4 - A3
sensor 5: ACS_PinS5 - A4

Servo 1: Servo myservoG1 - pin 9
Servo 2: Servo myservoG2 - pin 10
Servo 3: Servo myservoG3 - pin 11
Servo 4: Servo myservoG4 - pin 12
Servo 5: Servo myservoG5 - pin 13

I have code fore the 2 first machines and the both run fine when i loade the independently to the Arduino ONE bord.

Machine and gate 1

Code:

// Code for the 1. mashine and gate


/* This code works with ACS712 current sensor, it permits the calculation   of the signal TRMS
 * Visit www.surtrtech.com for more details
 */

#include   <Filters.h>                      //This library does a massive work check it's .cpp   file

#define ACS_PinS1 A0                        //Sensor data pin on A0 analog   input

float ACS_ValueS1;                              //Here we keep the raw   data valuess
float testFrequency = 50;                    // test signal frequency   (Hz)
float windowLength = 40.0/testFrequency;     // how long to average the   signal, for statistist


float intercept = 0; // to be adjusted based   on calibration testing
float slope = 0.0752; // to be adjusted based on calibration   testing                      
//Please check the ACS712 Tutorial video by SurtrTech   to see how to get them because it depends on your sensor, or look below


float   Amps_TRMSS1; // estimated actual current in amps


unsigned long printPeriod   = 1000; // in milliseconds
// Track time in milliseconds since last reading 
unsigned   long previousMillis = 0;

// servo setup

#include <Servo.h>

Servo myservoG1;  // create servo object to control a servo
Servo myservoG2;

int Open = 84;
int Close = 0;


void setup() 
{
  Serial.begin( 9600 );    //   Start the serial port
  pinMode(ACS_PinS1,INPUT);  //Define the pin mode

  myservoG1.attach(9);  // attaches the servo on pin 9 to the servo object

  myservoG1.write(Close);
  myservoG2.write(Close);
}

void   loop() 
{
  
  RunningStatistics inputStats;                 // create statistics   to look at the raw test signal
  inputStats.setWindowSecs( windowLength );     //Set   the window length
   
  while( true ) 
  {   
    ACS_ValueS1 = analogRead(ACS_PinS1);   // read the analog in value:
    inputStats.input(ACS_ValueS1);  // log to Stats   function
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod)   
    { //every second we do the calculation
      previousMillis = millis();   //   update time
      
      Amps_TRMSS1 = intercept + slope * inputStats.sigma();

      Serial.print( "\	 Amps: " ); 
      Serial.print( Amps_TRMSS1 );

    }


   if (Amps_TRMSS1 >11)
   {
     myservoG1.write(Open);
     myservoG2.write(Close);
   }
     
  }

} 

Machine and gate 2

Code:


// Code for the 2. mashine and gate


/* This code works with ACS712 current sensor, it permits the calculation   of the signal TRMS
 * Visit www.surtrtech.com for more details
 */

#include   <Filters.h>                      //This library does a massive work check it's .cpp   file

#define ACS_PinS2 A1                        //Sensor data pin on A0 analog   input

float ACS_ValueS2;                              //Here we keep the raw   data valuess
float testFrequency = 50;                    // test signal frequency   (Hz)
float windowLength = 40.0/testFrequency;     // how long to average the   signal, for statistist


float intercept = 0; // to be adjusted based   on calibration testing
float slope = 0.0752; // to be adjusted based on calibration   testing                      
//Please check the ACS712 Tutorial video by SurtrTech   to see how to get them because it depends on your sensor, or look below


float   Amps_TRMSS2; // estimated actual current in amps


unsigned long printPeriod   = 1000; // in milliseconds
// Track time in milliseconds since last reading 
unsigned   long previousMillis = 0;

// servo setup

#include <Servo.h>

Servo myservoG1;
Servo myservoG2;  // create servo object to control a servo


int Open = 84;
int Close = 0;


void setup() 
{
  Serial.begin( 9600 );    //   Start the serial port
  pinMode(ACS_PinS2,INPUT);  //Define the pin mode

  myservoG1.attach(9);
  myservoG2.attach(10);  // attaches the servo on pin 9 to the servo object
 

  myservoG1.write(Close);
  myservoG2.write(Close);
  
}

void   loop() 
{

  RunningStatistics inputStats;                 // create statistics   to look at the raw test signal
  inputStats.setWindowSecs( windowLength );     //Set   the window length
   
  while( true ) 
  {   
    ACS_ValueS2 = analogRead(ACS_PinS2);   // read the analog in value:
    inputStats.input(ACS_ValueS2);  // log to Stats   function
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod)  
    { //every second we do the calculation
      previousMillis = millis();   //   update time
      
     Amps_TRMSS2 = intercept + slope * inputStats.sigma();

     Serial.print( "\	 Amps: " ); 
     Serial.print( Amps_TRMSS2 );
    }

   if (Amps_TRMSS2 >11)
   {
     myservoG1.write(Close);
     myservoG2.write(Open);
   }
     
  }

} 

My problem is when I try to run them in the same code
Here is my attempt to make them run one after another:

Code:

// Code for the 2. mashine and gate


/* This code works with ACS712 current sensor, it permits the calculation   of the signal TRMS
 * Visit www.surtrtech.com for more details
 */

#include   <Filters.h>                      //This library does a massive work check it's .cpp   file

#define ACS_PinS2 A1                        //Sensor data pin on A0 analog   input

float ACS_ValueS2;                              //Here we keep the raw   data valuess
float testFrequency = 50;                    // test signal frequency   (Hz)
float windowLength = 40.0/testFrequency;     // how long to average the   signal, for statistist


float intercept = 0; // to be adjusted based   on calibration testing
float slope = 0.0752; // to be adjusted based on calibration   testing                      
//Please check the ACS712 Tutorial video by SurtrTech   to see how to get them because it depends on your sensor, or look below


float   Amps_TRMSS2; // estimated actual current in amps


unsigned long printPeriod   = 1000; // in milliseconds
// Track time in milliseconds since last reading 
unsigned   long previousMillis = 0;

// servo setup

#include <Servo.h>

Servo myservoG1;
Servo myservoG2;  // create servo object to control a servo


int Open = 84;
int Close = 0;


void setup() 
{
  Serial.begin( 9600 );    //   Start the serial port
  pinMode(ACS_PinS2,INPUT);  //Define the pin mode

  myservoG1.attach(9);
  myservoG2.attach(10);  // attaches the servo on pin 9 to the servo object
 

  myservoG1.write(Close);
  myservoG2.write(Close);
  
}

void   loop() 
{

  RunningStatistics inputStats;                 // create statistics   to look at the raw test signal
  inputStats.setWindowSecs( windowLength );     //Set   the window length
   
  while( true ) 
  {   
    ACS_ValueS2 = analogRead(ACS_PinS2);   // read the analog in value:
    inputStats.input(ACS_ValueS2);  // log to Stats   function
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod)  
    { //every second we do the calculation
      previousMillis = millis();   //   update time
      
     Amps_TRMSS2 = intercept + slope * inputStats.sigma();

     Serial.print( "\	 Amps: " ); 
     Serial.print( Amps_TRMSS2 );
    }

   if (Amps_TRMSS2 >11)
   {
     myservoG1.write(Close);
     myservoG2.write(Open);
   }
     
  }

} 



So what's your question?

You should describe how your code is behaving.
You should ask a specific question

Hello
I haven't read everything but for sure I've never seen something about a class "mashine and gate"
unfortunately, I dn't thing you can avoid this concept in such a case...

First of all an arduino Uno can do this. But it is a somehow advanced functionality.
An advanced functionality needs more lines of code and needs more understanding how programming works.

From your description:
detect if a machine is running through measuring the current.
All five machines need the same pattern
if current detected open the blast gate of the running machine

this means you have to measure the current of all 5 machines all the time

As soon as on one machine current is measured open the blast-gate of this machine and close all other four gates.

what shall happen if you switch on a second machine while a first machine is already running?

Just not opening a second blast gate ?
If not you need an indicator "machineRunning" which makes the code not open a second blast gate.

But maybe instead switching on a signal lamp indicating "no dust suction"

Maybe locking all other four machines against switching them on.

best regards Stefan

consider

// control servo based on current measurement

#include <Servo.h>

const int   ServoOpen   = 84;       // servo positions
const int   ServoClose  = 0;

const float intercept = 0; // to be adjusted based   on calibration testing
const float slope = 0.0752; // to be adjusted based on calibration   testing

const float AmpHi  = 11;
const float AmpLow = 10;

// define Gate structure capturing all infor for each gate
struct Gate {
    const byte  PinServo;
    const byte  PinAcs;
    bool        state;
    Servo       servo;

    int         analg;
    float       amps;
    char        t [20];
};

Gate gate [] = {    // initialize pins for each gate
    {  9, A0 },
    { 10, A1 },
    { 11, A2 },
    { 12, A3 },
    { 13, A4 },
};
const unsigned Ngate = sizeof(gate) / sizeof(Gate);     // # of gates

enum { Open = true, Closed = false };       // values for gate state

const unsigned long MsecPeriod = 5000;      // timer parameters
      unsigned long msecLst;

char s [80];                                // used for prints

// -----------------------------------------------------------------------------
void loop ()
{
    // monitor each gate current
    for (unsigned n = 0; n < Ngate; n++)  {
        int   analg  = analogRead (gate [n].PinAcs);
        float amps   = intercept + (slope * analg);

        gate [n].analg = analg;     // update info for prints
        gate [n].amps  = amps;
        dtostrf (amps, 6, 2, gate [n].t);

        // check if power on & open gate
        if (Closed == gate [n].state && AmpHi <= amps) {
            gate [n].servo.write (ServoOpen);
            gate [n].state = Open;

            sprintf (s, " %d: %s Open", n, gate [n].t);
            Serial.println (s);
        }
        // check if power off & close gate
        else if (Open == gate [n].state && AmpLow > amps)  {
            gate [n].servo.write (ServoClose);
            gate [n].state = Closed;

            sprintf (s, " %d: %s Close", n, gate [n].t);
            Serial.println (s);
        }
    }
    
    // periodically report gate status and values
    unsigned long msec = millis ();
    if (msec - msecLst >= MsecPeriod)  {
        msecLst = msec;

        for (unsigned n = 0; n < Ngate; n++)  {
            sprintf (s, " %d: %6d %s %s", n, gate [n].analg,
                    gate [n].t, gate [n].state ? "Open" : "Closed");
            Serial.println (s);
        }
        Serial.println ();
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin ( 9600 );    //   Start the serial port
    Serial.println ("current controlled servos");

    // initialize hardware for each gate
    for (unsigned n = 0; n < Ngate; n++)  {
        gate [n].servo.attach (gate [n].PinServo);
        gate [n].servo.write  (ServoClose);
        gate [n].state = Closed;

        // pin w/ button configured w/ pullup ... can be deleted
        pinMode (gate [n].PinAcs, INPUT_PULLUP);
    }
}
2 Likes

Hello mads_bennicke

Do you have experience with programming in C++?

Make the following abtraction simply:

You have n-sets of one current sensor and one associated servo.

The task can easily be realised with an object.
A structured array contains all the information, such as the pin addresses for the I/O devices, as well as the information for the timing.
One single service, aka method, takes care of this information and initiates the intended action.
The structured array makes the sketch scalable until all I/O pins are used up without having to adapt the code for the service.
It is cool stuff, isn´t it?

Have a nice day and enjoy coding in C++.

I don't have much experience with programming in C++
The code fore the current sensors i have found in an article on the sensor.

I am alone in the shop and can only use one machine at a time. So only one machine will be on at any given time.

@mads_bennicke

simplyifying your code:
The demo-code that you used as base calculates the real current in Ampere.

For your functionality it would be sufficient to detect

  • machine running
  • machine not running

and therefore to use the raw ADC-value you get from the line of code

ACS_ValueS1 = analogRead(ACS_PinS1);

To find out If avergeing is nescessary you could run a testcode that just prints the values of the analogInput-reading to the serial monitor.
You switch on the machine and then run the testcode

The analogInput-reading is this line of code

ACS_ValueS2 = analogRead(ACS_PinS2);

Do you know how to use the serial monitor?
Do you know how to code this testprogram?

best regards Stefan

Hello mads_bennicke

No problem at all.

Take some time and describe the desired function of the sketch in simple words and do this very simply words to get a common start point.

What should happen under which conditions, for how long and with what?

Have a nice day and enjoy coding in C++.

Hi StefanL38

will this code print al the currents of all the sensors.

#define ACS_PinS1 = A0                        //Sensor data pin on A0 analog   input
#define ACS_PinS2 = A1   
#define ACS_PinS3 = A2                        //Sensor data pin on A0 analog   input
#define ACS_PinS4 = A3 
#define ACS_PinS5 = A4 


float ACS_ValueS1;  
float ACS_ValueS2;
float ACS_ValueS3;
float ACS_ValueS4;
float ACS_ValueS5;

void setup() 
{
  Serial.begin( 9600 );    //   Start the serial port
  pinMode(ACS_PinS1,INPUT);
  pinMode(ACS_PinS2,INPUT);
  pinMode(ACS_PinS3,INPUT);
  pinMode(ACS_PinS4,INPUT);
  pinMode(ACS_PinS5,INPUT);

}  
void   loop() 
{
      Serial.print( "\	 Amps S1: " ); 
      Serial.print( Amps_TRMSS1 );

      Serial.print( "\	 Amps S2: " ); 
      Serial.print( Amps_TRMSS2 );

      Serial.print( "\	 Amps S3: " ); 
      Serial.print( Amps_TRMSS3 );

      Serial.print( "\	 Amps S4: " ); 
      Serial.print( Amps_TRMSS4 );

      Serial.print( "\	 Amps S5: " ); 
      Serial.print( Amps_TRMSS5 );

}

Hi @mads_bennicke
very good that you posted a first attempt how to print the measured values.
This example shows very important information in an effective way.
It shows at what knowledge-level you are and where explanations should start.

The lines

only define a replacemenet

#define ACS_PinS1 A0 without the equalsin

commands the compiler whenever you find the name "ACS_PinS1" replace the name
"ACS_PinS1"
with
"A0"

not more
It is defining a name that makes the code easier to understand
what is analog input "A0" used for?
answer
"your ACS sensor 1"

define IO-pins as input

print value of variable with name "Amps_TRMSS1" to the serial monitor.
The value of variable "Amps_TRMSS1" has not been calulcated
The calculation is this

This does calculate the current in ampere with averaging
But as I said you don't need the current in ampere.
It is sufficient to have an ADC-value that indicates "machine running"

reading in the ADC-value is the line of code

ACS_ValueS1 = analogRead(ACS_PinS1);

printing this value to the serial monitor can be done with

  Serial.print("this is the fixed text Sensor 1=");
  Serial.println(ACS_ValueS1); // println  printLN print and then jump down to a NEW line

best regards Stefan

are you interested in the code in post #8 which does what you ask?

Hi Stefan

her is my next attempt

#include   <Filters.h>   

#define ACS_PinS1 A0
#define ACS_PinS2 A1
#define ACS_PinS3 A2
#define ACS_PinS4 A3
#define ACS_PinS5 A4


float ACS_ValueS1;
float ACS_ValueS2;
float ACS_ValueS3;
float ACS_ValueS4;
float ACS_ValueS5;

void setup() 
{
  Serial.begin( 9600 );    //   Start the serial port
  pinMode(ACS_PinS1,INPUT);
  pinMode(ACS_PinS2,INPUT);
  pinMode(ACS_PinS3,INPUT);
  pinMode(ACS_PinS4,INPUT);
  pinMode(ACS_PinS5,INPUT);

}  
void   loop() 
{
  

  ACS_ValueS1 = analogRead(ACS_PinS1);
  Serial.print("Sensor 1=");
  Serial.println(ACS_ValueS1); // println  printLN print and then jump down to a NEW line

  ACS_ValueS2 = analogRead(ACS_PinS2);
  Serial.print("Sensor 2=");
  Serial.println(ACS_ValueS2); // println  printLN print and then jump down to a NEW line

  ACS_ValueS3 = analogRead(ACS_PinS3);
  Serial.print("Sensor 3=");
  Serial.println(ACS_ValueS3); // println  printLN print and then jump down to a NEW line

  ACS_ValueS4 = analogRead(ACS_PinS4);
  Serial.print("Sensor 4=");
  Serial.println(ACS_ValueS4); // println  printLN print and then jump down to a NEW line

  ACS_ValueS5 = analogRead(ACS_PinS5); 
  Serial.print("Sensor 5=");
  Serial.println(ACS_ValueS5); // println  printLN print and then jump down to a NEW line


     

}

This is what i get with no sensors wired to the bord

0.00

this is the fixed text Sensor 5=317.00

this is the fixed text Sensor 1=311.00

this is the fixed text Sensor 2=321.00

this is the fixed text Sensor 3=316.00

this is the fixed text Sensor 4=310.00

this is the fixed text Sensor 5=317.00

this is the fixed text Sensor 1=311.00

this is the fixed text Sensor 2=322.00

this is the fixed text Sensor 3=317.00

this is the fixed text Sensor 4=312.00

this is the fixed text Sensor 5=319.00

this is the fixed text Sensor 1=312.00

this is the fixed text Sensor 2=321.00

this is the fixed text Sensor 3=316.00

this is the fixed text Sensor 4=310.00

Aha. pure Arduino or are there wires connected to A0,A1,A2,A3,A4?

Your code is repetetive always the same except to sensor number in the name of the variables.

This is a case for arrays.

the following code defines arrays for each

  • sensor-input-pin
  • servo-output pins
  • array for summarised values
  • array for averaged values

The code repeats reading in the values from the analog inputs 200 times
then calcutes the averages and prints the averages for each input-pin

You should use the serial monitor a lot for debugging

// defining an array where each element of the array
// holds one IO-pin-number symbolised through A0,..A4
// REMARK A0,...A4 etc are again symbols for numbers
const byte ACS_PinS[5] = {A0, A1, A2, A3, A4};
const byte myservoG[5] = {9, 10, 11, 12, 13};

const int numberOfSamples = 200;

int ADC_Val[5] = {0 , 0 , 0 , 0 , 0};

unsigned long ADC_Val_Sum[5] = {0 , 0 , 0 , 0 , 0};

float averagedADC_Val[5] = {0 , 0 , 0 , 0 , 0};
long sampleCounter = 0;


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  Serial.println("explainig arrays");
  printACS_Pin_Numbers();
  print_MyservoG_Pin_Numbers();

  Serial.print("code reads in ");
  Serial.print(numberOfSamples);
  Serial.println(" samples from each sensor");
  Serial.println("and prints calculated averages");
  
  readInAndPrintAverages();
  Serial.println("restart code by pressing the resetbutton");
}


void loop() {
  // empty loop does nothing
}


void readInAndPrintAverages() {
  // clear sums
  for (byte IndexNr = 0; IndexNr < 5; IndexNr++) {
    ADC_Val_Sum[IndexNr] = 0;
  }


  sampleCounter = 0; // reset sampleCounter to zero
  // read in 200 samples and summarise the samples
  while (sampleCounter < numberOfSamples) {

    // read in all 5 analog-input channels
    // count variable IndexNr from 0 to 4
    for (byte IndexNr = 0; IndexNr < 5; IndexNr++) {
      ADC_Val[IndexNr] = analogRead(ACS_PinS[IndexNr]);
      // add value to sum
      ADC_Val_Sum[IndexNr] += ADC_Val[IndexNr];
    }
    sampleCounter++;
  }

  // calculate averages for each sensor
  for (byte IndexNr = 0; IndexNr < 5; IndexNr++) {
    averagedADC_Val[IndexNr] = ADC_Val_Sum[IndexNr] / numberOfSamples;
    Serial.print("Sensor No");
    Serial.print(IndexNr);
    Serial.print(" average=");
    Serial.println(averagedADC_Val[IndexNr]);
  }
  Serial.println();
}


void printACS_Pin_Numbers() {
  for ( byte IndexNr = 0; IndexNr < 5; IndexNr++) {
    Serial.print("ACS_PinS["); // print text between ""
    Serial.print(IndexNr);     // print value of variable named IndexNr
    Serial.print("] holds IO-Pin Nr:"); // print text between ""
    // print value of array-ELEMENT specified by the value of variable IndexNr
    Serial.println(ACS_PinS[IndexNr]);
  }
  Serial.println();
}


void print_MyservoG_Pin_Numbers() {
  for ( byte IndexNr = 0; IndexNr < 5; IndexNr++) {
    Serial.print("myservoG["); // print text between ""
    Serial.print(IndexNr);     // print value of variable named IndexNr
    Serial.print("] holds IO-Pin Nr:"); // print text between ""
    // print value of array-ELEMENT specified by the value of variable IndexNr
    Serial.println(myservoG[IndexNr]);
  }
  Serial.println();
}

Now wire the sensors to the board to see if you get useful data.
The data would probably be easier to interpret if you put all 5 values on one line:

void loop()
{
  Serial.print(analogRead(ACS_PinS1));
  Serial.print("\t");  // TAB charcter
  Serial.print(analogRead(ACS_PinS2));
  Serial.print("\t");  // TAB charcter
  Serial.print(analogRead(ACS_PinS3));
  Serial.print("\t");  // TAB charcter
  Serial.print(analogRead(ACS_PinS4));
  Serial.print("\t");  // TAB charcter
  Serial.println(analogRead(ACS_PinS5));
  Serial.print("\t");  // TAB charcter
}
1 Like

Hi Stefan

Here is what i get with 2 sensors and no 230v connected throw the sensors

0.00
this is the fixed text Sensor 5=317.00
this is the fixed text Sensor 1=311.00
this is the fixed text Sensor 2=321.00
this is the fixed text Sensor 3=316.00
this is the fixed text Sensor 4=310.00
this is the fixed text Sensor 5=317.00
this is the fixed text Sensor 1=311.00
this is the fixed text Sensor 2=322.00
this is the fixed text Sensor 3=317.00
this is the fixed text Sensor 4=312.00
this is the fixed text Sensor 5=319.00

Hi Stefan

That is with the code you postet