Measuring current through DC motors

My project is the entrance gate of my property, two 6 ft steel doors powered by 12V electric motors.
The Arduino Uno has 4 optically isolated 30 Amp relays with limit switches in the coil circuits.

To maintain isolation I cannot any of the limit switches to Arduino pins, so I use 4 current sensor boards (ACS-712) with an extra shunt to protect them against the inrush current. The raw output of the sensors is approx. 515, how that converts to Amps is irrelevant in my application:

in setup
int leftmaxCurrent = 750; //the left motor is larger than the right one
int rightmaxCurrent = 650;
int minCurrent = 525;

in loop
/* There are 2 limit switches on each gate, interrupting the power to
the relay coils when the end of the travel is reached. That can be detected
by the drop of current flowing to the electric motors. If that does not happen because
of a mechanical malfunction, the time-out function will terminate the process.
An increase of current, caused by mechanical obstruction triggers the safety
routine. */

leftCurrent = analogRead (leftcurrentPin); //to be measured on each loop
rightCurrent = analogRead (rightcurrentPin); //to be measured on each loop
if (leftCurrent >= leftmaxCurrent) //abnormally high current measured
safety();
if (rightCurrent >= rightmaxCurrent) //abnormally high current measured
safety();

safetyFlag = digitalRead (safetyPin);
if (safetyFlag == HIGH) //one or more safety devices activated
safety();

/* The next steps are part of a normal operation to determine when a particular
operation has been completed and the corresponding relay signals can be
turned off.

This is for any situation where one or two gates have been opening: */

if (leftCurrent <= minCurrent && gateOpening == HIGH) //end of travel reached
{
digitalWrite (leftgateopenPin, HIGH);
pedestrian = false; // If this was a pedestrian cycle, it has been completed
}
if (rightCurrent <= minCurrent && gateOpening == HIGH) //end of travel reached
{
digitalWrite (rightgateopenPin, HIGH); //release the relay
gateOpening = LOW; //completes both car and pedestrian opening cycle
}

The high current sensing works as expected, but low current sensing doesn’t.
During normal operation the gates stop at random because the current seems to have been below the threshold for a fraction of a second. I probably could insert a resistor and a capacitor between the sensor boards and the analog inputs, but I would prefer a software solution where a few measurements are made in succession and the average value is used in the IF statement.

How do I accomplish that?

Use a law pass filter.

Something like this

accumulator = (a* measurement) + (1.0f - a) * accumulator;

Where a is the filter gain between 0 and 1.0
and accumulator is the filtered result

Or the simpler form:

  accumulator += a * (measurement - accumulator) ;

where a appears only once and the second multiply is avoided.

You want to use overcurrent detection in place of limit switches?

Don't.

Either add more limit switches of your own or use optoisolators on the existing switches. Adding more switches is usually a good idea because then you can have an initial 'soft limit' but the original switches are still there to disconnect the motor when your system screws up.

Yes, you are going to make a screwup while you're testing. You will drive a motor into the limit and you won't know it's still getting power until the smoke comes out of it.

By the way there is no guarantee the current doesn’t flow backwards in your system - motors act
as generators too, and if moving a heavy load deceleration will result in generator action as the
motor brakes the motion.

Your criterion for detecting the relays being open should be by measuring the voltage to the motor
using a voltage divider - unless you really need opto-isolation. This won’t be confused by fluctuations
in motor current.

Thank you for your replies.
Let me try to understand this simpler form....

"accumulator" is a field defined in setup, the code line is in loop.

If a=3 and measurement=500 the 1th pass gives 3*(500-0)=1500, the 2nd 3*(500-1500)=-3000 and the 3rd
3*(500+3000)=10500.

Either this is wrong or I don't understand any of it (most probably).

MarkT:
By the way there is no guarantee the current doesn’t flow backwards in your system - motors act
as generators too, and if moving a heavy load deceleration will result in generator action as the
motor brakes the motion.

Your criterion for detecting the relays being open should be by measuring the voltage to the motor
using a voltage divider - unless you really need opto-isolation. This won’t be confused by fluctuations
in motor current.

Yes, current will flow back the moment a limit switch has cut power to the relay and the motor sees a short circuit. But the polarity has changed, so the next reading is a value way under 525 and the Arduino makes the right decision.
Using voltage dividers is not an option, the Arduino goes crazy. There is a remote control receiver with relays that send 12V pulses to the Arduino. I use voltage dividers there, causing erratic results at startup, so I must employ optocouplers there.

The current sensors do a good job. If I hold a moving gate, the current is immediately detected and the sketch goes to the “safety” routine. They also detect the opening of a limit switch.
The issue is with normal operation, when the permanent magnet motors sometimes draw less current for a millisecond and the measurement is below the threshold.
So instead of basing the decision on a single measurement I want to make 3 measurements in rapid succession, add them to a field and divide the result by 3. Or maybe just add them and increase the value of the minCurrent field from 525 to 1575.

Camel:
Use a law pass filter.

Then the case has to go before a circuit judge.

Regards reply #5, you can't use a filter gain greater than one.

If a=3 and measurement=500 the 1th pass gives 3*(500-0)=1500, the 2nd 3*(500-1500)=-3000 and the 3rd
3*(500+3000)=10500.

Either this is wrong or I don’t understand any of it (most probably).

Some of both. “a” is chosen to be between 0.0 and 1.0, usually small (like 0.2). So the progression for

accumulator += a * (measurement - accumulator) ;

with accumulator initially = 0 and all measurements = 500, would be

0 + 0.2*(500-0) = 100
100 + 0.2*(500-100) = 180
180 + 0.2*(500-180) = 244

etc.

Thanks for the detailed explanation jremington, it clearly shows this is not the kind of filter I need.

I will try to write a subroutine that takes 3 measurements, compare their values and use only the highest one. When a gate has moved to its end position, the limit switch has cut power to the relay coil, so even the highest reading will be below the threshold.
I've read somewhere in the "learning" section that there must be a small delay between measurements to prevent jitter, so I will start with 10 millis.

There also is an issue with the upper current limit that triggers the safety routine if the gate encounters an obstruction like a car standing between the closing gates.
The installation is powered by a car battery and a solar panel. Daylight is short now and the battery voltage drops well below 12V when both motors are running. I must find a way to modify the maxCurrent limit automatically to cope with the changed condition.

Thanks for the detailed explanation jremington, it clearly shows this is not the kind of filter I need.

Tell us what you want and we can probably suggest a better option.

However, the low pass filter is very commonly used to keep a "running average" of measurements, with selectable amount of jitter. The "strength" of the filter is determined by the choice of a. If a = 1.0, there is no filtering; if a is very small, the response time to a change in the average value is very long.

I use it all the time to (1) compute smooth averages of measurements and (2) look for sudden large (significant) deviations in a measured quantity whose average value changes slowly.

The latter process is to first compare the measurement to the filtered value, and do something if there is a large difference. If not, add the measurement in to the filter and continue.

jremington:
I use it all the time to (1) compute smooth averages of measurements and (2) look for sudden large (significant) deviations in a measured quantity whose average value changes slowly.

The latter process is to first compare the measurement to the filtered value, and do something if there is a large difference. If not, add the measurement in to the filter and continue.

When it comes to writing in C++ I feel like a child learning English.
So I made a subroutine I don't dare to show here, but it does measure current 3 times with a 5 msec delay and stores the largest value in the field where the decision is based upon. This greatly improved the performance of the gates, but it is not yet perfect.
After a few times opening and closing, the battery voltage has dropped and a gate stops in a random position because the Arduino thinks an end position has been reached. Taking more measurements or adding delay is not an option because a quick reaction is required in case of an obstruction.

The installation has been in place for over 12 years now, controlled by a lot of relays and some analog circuits. One grandchild had a few crushed ribs once and my own car suffered extensive tail light damage when I pressed the (remote) close button and forgot to drive away. I want to avoid such mishaps in the future by using a micro.
Maybe it is better to use the current sensors for the safety routine only and use opto couplers to signal the end of travel to the Arduino. My wife suggested I throw the whole control unit in the dumpster and operate the gates manually!