I have a brush DC motor with a PWM controller to manage motor speed (the pwm uses mosfets to send the flyback voltage back through the motor and switches at 20K). The power source is 2 x 12 VDC batteries in series (size is what you would find in a motor cycle). All works well. I'm trying to measure volts, amps, and RPM using an arduino. I have a buck converter hooked to the battery (24 VDC) and dropping the voltage to 5VDC and connected to +5 to power the arduino, and i'm using a simple voltage divider to drop the 24 VDC to around 4 so my arduino can read the batttery voltage (then in software i compute the voltage based on R1 and R1), note my voltage divider is connected directly to the batter, no filtering. My amp meter is a hall effect sensor with a low pass filter to smooth the output signal.
I have several issues
My issue is the arduino "locks up" and I suspect is just spiky, noisy voltage caused by the motor and controller. I added a home made inductor (wire wrapped through a washer, and connected it in series to the ground (read that tip somewhere) and while the arduino no longer locks up, it does restart (as if the battery were unplugged and plugged in again. I still suspect the issue is very spiky voltage caused by the pwm controller and motor. I can only hope my buck converter is filtering out all the junk, but I now suspect connecting the noisy battery directly to the arduino input w/o any type of filtering, may be causing issues.
a plot of the input voltage (the ~4 VDC signal from the voltage divider) over time is a sine wave with about .05 volts peak to peak--again I suspect its due to the noise and spikes of the pwm controller. The sine nature really makes me suspicious.
I've tried dozens of things like shielding wires, twisting wires. etc. maybe i can
add a low pass filter to the positive (before the buck converter and the input to the voltage divider
connect the power and voltage measurement the the point between the batteries (12 VDC).
It feels like #2 will give the cleanest DC signal because one large battery should isolate the spikes, but this is a bit over my head.
I'm back with more data--hopefully someone can help me out.
Just a reminder i have a brush-type 25 VDC motor with a 20kHz PWM speed controller and i"m trying to measure battery levels over time...buy my measured data is very very noisy--and it at times my Arduino restarts.
I ran my project for 2 hours capturing voltage readings across the battery every second--yea a lot of points. Have a look at the graph--when the PWM is 0 the voltage is smooth like I would expect, any duty cycle >0 the data is a mess. My code is dead simple, i really think this is a hard ware problem.
I've tried all above suggestions and more
perhaps I need a low pass filter before my voltage divider
an opto-isoloator somewhere
I'm stuck...
#include <Wire.h>
#include <SD.h>
#define VM_PIN A1
#define CS_PIN 4
#define R2 46000
#define R1 10000
double vvolts = 0.0; // measured pin output (0-1023)
double volts = 0.0; // computed volts
long curtime, pretime;
int i;
File dataFile;
String filename = "data.csv";
void setup() {
pinMode(VM_PIN, INPUT);
// initialize the card
if (!SD.begin(CS_PIN)) {
// bad news...
}
}
void loop() {
curtime = millis() ;
if (curtime - pretime >= 1000 ) {
pretime = curtime;
// get battery volts
// reset my average counter
vvolts = 0.0;
// get 10 points and average--maybe that will help...
for (i = 1; i <= 10; i++) {
vvolts = vvolts + analogRead(VM_PIN);
// small delay---someone said this may help
delay(10);
}
//convert to volts
vvolts = vvolts / (10.0 * 204.6);
//scale up by the voltage divider
volts = (vvolts * (R1 + R2)) / R2;
// write the data to the SD card
dataFile = SD.open(filename.c_str(), FILE_WRITE);
dataFile.print(curtime / 1000);
dataFile.print("," );
dataFile.print(volts, 2);
dataFile.close();
}
}
I don't know whether the String library will reuse the same space when converting filename from String to (char *). If it doesn't, it could be the cause of the crashes because it does the conversion every time through loop().
If you are really intent on using String, you could still fix this up a bit by doing the conversion once, in setup().
I'm back with more data--hopefully someone can help me out.
Just a reminder i have a brush-type 25 VDC motor with a 20kHz PWM speed controller and i"m trying to measure battery levels over time...buy my measured data is very very noisy--and it at times my Arduino restarts.
Can you post a link to your PWM controller? It sounds like it needs some Input Capacitance between it and the battery.
The only way that a battery voltage can have AC on it is if it's providing an AC current. From your data, I'd believe that you actually have 20kHz currents coming out of the battery. A large bypass cap on your PWM controller input should reduce your battery current to ~DC.
KrisKasprzak:
So you are saying I can't measure voltages reliably? Or at least every second.
I don't believe that is correct, look at the smooth data when the controller is off.
Your battery is not a perfect energy storage device. If you are switching a heavy load fast (20khz), the battery voltage is affected by the current draw. Batteries and capacitors have ESR, (Effective Series Resistance).
If you don't want to see the instantaneous battery voltage, add a filter, a simple RC to cut out the high frequency noise.
bat -> 100 ohm -> +100uf (neg to gnd) -> analog input.
The RC network has a cutof freq(Fc) of 15hz Fc = 1/(2piR*C)
Fc in hertz
R in ohms
C in Farad
I had a powersupply problem, I was driving a 15A brushed motor, I was using an unregulated DC supply,
twin 8A 12V transformers, feeding 50A bridge rectifiers feeding 40,000uF caps. The unregulated voltage was about 19V unloaded and 13V loaded. But, my 50A bridges were exploding. The solution was to add 1in ferrite rings wrapped 23 times with 16ga wire. This simple LC network reduced the inrush current below the bridges maximum 50A.
Thanks for the responses. I'm thinking chucktodd is probably right. My motor draws between 10-30 amps.
I was thinking of adding a low pass filter then feed a diode and large cap on the +side of the buck converter--but since the buck is dropping the voltage to 5 i didn't think that would help. My other suspission is if i need to filter the +24 going to the voltage divider before it goes to the arduino--probably a ton of noise going right into pin A0.
Here's a link to the controller (i'm using the Porter 5).
Note this project is in support of a High School electric race car. I'm the teams coach and our first race was yesterday and we won! The car worked fine, but the logged data is a mess--so much noise and the data is useless. Another race in 3 weeks and I'm desperate to get this sorted out.
Just adding a small capacitance from A0 to GND would be all that's needed (i.e. 10nF). It would be good to know the values for the resistor divider. Then the RC time constant could be calculated.
You may be sampling once per second, but the a/d will only take a <10uS snapshot - so since the battery volts vary with current, and you have a pwm controller, the volts you see depends on when this <10uS snapshot hits the pwm cycle.
You can get an average either with a lowpass filter, or in sw with a many-sample memory.
Personally I think the data you've captured is very interesting - given you know the instantaneous peak current, you can figure the battery impedance. I notice that the p-p values increase as the battery is discharged - ie a higher impedance, which is exactly what you'd expect. The high values of the 'noise' are the battery off-load, the low parts when loaded.
regards
Allan.
ps to take advantage of the arduino's on-board regulator, supply say 9 v to the reg in supply. That way you let the arduino board clean up a load of psu rubbish. I'd use a linear regulator, as switchers can be noisy - try a LM317 or LM7809. The arduino won't take much current.
Note this project is in support of a High School electric race car. I'm the teams coach and our first race was yesterday and we won! The car worked fine, but the logged data is a mess--so much noise and the data is useless. Another race in 3 weeks and I'm desperate to get this sorted out.
Congrats on your win An electric race car...I guess that explains why you're almost always at full PWM. A couple years ago I assisted these guys with the FW in their battery. Maybe you're familiar with them?
While page 3 doesn't give values of the 2 capacitors in the Porter 5, I'm sure that they're not the ~10000uF that'd be necessary for your 30A/20kHz to not result in the ripple you're seeing on your battery voltage.
If you are happy just filtering out this ripple in your A/D monitoring circuit it's up to you, but personally I'd want to stop those currents from showing up at your battery. Every EV I've made a battery for had enough capacitance on its high voltage bus such that the switching frequency wasn't seen at the battery. For one thing, you don't want those high frequency currents running all through the car (for much the same reasons why the ICs on your Linduino have bypass caps). Next thing, batteries are damaged as their minimum voltage falls out of range as opposed to the average voltage. Lead Acid batteries are more tolerant of this than Li-Ion, but it's still better for you to monitor the actual DC value of the battery as opposed to the average of an AC value.
Your resistor values are quite high. This is OK as there will be more than adequate input protection because of this (about ±50VDC) and this will not be the cause of the system locking up.
However, it will be necessary to take multiple readings to get a stable result as it will extra take time for the internal ADC capacitance to charge. The extra readings will reduce the frequency response ... you will loose the 20kHz PWM ripple data as it will be smoothed in code.
If capacitance is used, the result will be the same (loss of PWM ripple data) however this will reduce the effective input impedance and the results will be more stable. Note that for stable results, the input impedance for ADC inputs should be <=10K.
The lockup issue is most likely due to EMI on the power rails and load.
Using this calculator (and circuit), you could use R1=10K, R2=4.7K and still have adequate over-voltage protection (the MCU's internal protection diode can handle about 1 mA). In your circuit, R1 and R2 are in swapped positions, so you would have R2=10K, R1=4.7K.
The readings will now be much more stable and the input impedance will be within specifications.
Note that these new values will mean that the voltage divider will consume about 0.82mA from the battery.