Digital signal processing and filtering – motor current sensing

After a recent post on current sensing, I talked to a couple of friends at NYC Resistor (my usual sounding board) and got some great advice (as usual).

One thing I didn’t remember was the difference between passive and active filtering, and that it might take more than a simple RC circuit to filter out the noise I was seeing. I was pointed to a few good reads:

http://ww1.microchip.com/downloads/en/devicedoc/41233A.pdf

http://www.maxim-ic.com/app-notes/index.mvp/id/1762

http://www.swarthmore.edu/NatSci/echeeve1/Ref/DataSheet/IntroToFilters.pdf

But before I got too far into digital signal processing land and making hardware based 2nd or 3rd order filters, I wanted to see if there was a better way. I got in touch with JD Warren, one of authors of Arduino Robotics. One of the projects in the book used a custom built motor driver with a hall effect current sensor. I’ve shied away from these until now because they seemed to be more voodoo than the more intuitive current sensing resistor method, but after reading parts of his book and talking with JD, I ordered up some ACS712s and some surface mount to breadboard adapters from Digikey. He always had good luck with them so hopefully that luck rubs off and they’ll be less noisy than the method I’m using now.

I also did some more research and found that the L298 h-bridge, basically the next step up from the L293 that comes on the Adafruit Motor Shield, has current sensing already built in! Luckily both the Sparkfun Ardumoto Shield and the Arduino Motor Shield use this h-bridge, but only the Arduino shield has those pins broken out. So I ordered both, figuring I could hack the Sparkfun one by cutting the traces and soldering some little jumper wires if necessary (I studied the schematics for quite a while before convincing myself this would be possible). From what I can gather from the datasheet, I still need to add a current sensing resistor, and it uses basically the same method I was using before, but something about the integrated solution I suppose could make a difference. We’ll see.

First Test: Arduino Motor Shield
The documentation on this shield is a little spotty, but from the schematic and Eagle files, I figured out that the current sensing resistors were already integrated along with an op-amp that presumably amplifies the tiny voltage drop. The hardware page says the resolution is 1.65 A/V, so it looks like they did the math already on what resistors and what gain was used to get an actual current rating from a detectable voltage drop. So I wrote up some code (below) and after a little tweaking got this:

Isn’t that beautiful?!? A little jumpy still but might be good. I think it’s time to swap this in where the Adafruit Shield is now and see what happens with the robot arm.

   
/*
Curent sensing with the Arduino Motor Shield: http://arduino.cc/it/Main/ArduinoMotorShieldR3
 
 One small DC motor attached to screw terminal block A
 External power from a 4 x AA batter pack
 
 CC-BY-SA
 by Dustyn Roberts
 6/12/2012
 */

// declare pins used on channel A
int directionPin = 12;
int pwmPin = 3;
int brakePin = 9;
int currentPin = A0;

int switchPin = 2; // motor on/off switch
// connect one side of switch to power, the other to ground through a 10k resistor
// read the switch state where the switch and resistor meet into digital pin 2
// similar to this lab: http://itp.nyu.edu/physcomp/Labs/DigitalInOut

// constants
float volt_per_amp = 1.65; // resolution according to hardware page

// variables
float currentRaw; // the raw analogRead ranging from 0-1023
float currentVolts; // raw reading changed to Volts
float currentAmps; // Voltage reading changed to Amps

void setup() {
  pinMode(directionPin, OUTPUT);
  pinMode(pwmPin, OUTPUT); // necessary according to forum post http://arduino.cc/forum/index.php/topic,89468.0.html
  Serial.begin(9600); 
}

void loop() {
  // read the switch input:
  if (digitalRead(switchPin) == HIGH) {
    // if the switch is closed:
    digitalWrite(pwmPin, HIGH); // necessary according to forum post http://arduino.cc/forum/index.php/topic,89468.0.html
    digitalWrite(directionPin, HIGH);
  }
  else {
    // if the switch is open:
    digitalWrite(pwmPin, LOW); // necessary according to forum post http://arduino.cc/forum/index.php/topic,89468.0.html
    digitalWrite(directionPin, LOW);
  }

  currentRaw = analogRead(currentPin);
  currentVolts = currentRaw *(5.0/1024.0);
  currentAmps = currentVolts/volt_per_amp;

  Serial.println(currentAmps);
}