JavaScript: Current Detection and Measurement with Johnny-Five on Node.js

The Johnny-Five Tutorial Series is geared towards Arduino programming on Node.js, using the Johnny-Five framework. Get caught up here.


In certain cases, it may be useful to know how much current is drawn from a specific load in a circuit. In this article, we’ll measure current draw, with and without a load. The load will be a Brushless DC motor paired with an Electronic Speed Control (or ESC for short), which is itself controlled with a field programmer (the behavior we’ll create can easily be programmed via Johnny-Five’s ESC class). The program will calculate the current draw from a LiPo battery in milli-amps and then output a rudimentary chart to the terminal. To make this measurement, we’ll place a hall effect current sensor on the positive line between the battery and the ESC.


Parts:

Connect the following:

  • ACS712
    • LiPo + to Right screw terminal
    • Left screw terminal to ESC +
    • LiPo - to ESC -
    • VCC to 5V (on board)
    • OUT to A0 (on board)
    • GND to GND (on board)

For reference, here’s what my own build looked like:

Save the following as current-monitor.js:

var five = require("johnny-five");
var scale = five.Fn.scale;
var board = new five.Board();
// Measured with multimeter @ 4.440V
var VCC = 4440;

function toMV(value) {
  // Scale an ADC reading to milli-volts.
  return scale(value, 0, 1023, 0, VCC) | 0;
}

function render(mA) {
  // mA means milli-amps
  var mAF = mA.toFixed(2);

  mA = Number(mAF);

  // Limit bar rendering to values that are unique from the
  // previous reading. This prevents an overwhelming number
  // of duplicate bars from being displayed.
  if (render.last !== mA) {
    console.log(
      mAF + ": " + "".repeat(scale(mA, 0.03, 2, 1, 50))
    );
  }
  render.last = mA;
}

board.on("ready", function() {
  // Set up a 1kHz frequency sensor, with a name 
  // that's similar to the type of sensor we're using. 
  // This is a smart way to keep track of your physical
  // devices throughout the program.
  var acs = new five.Sensor({
    pin: "A0",
    freq: 1
  });
  var time = Date.now();
  var samples = 100;
  var accumulator = 0;
  var count = 0;
  var amps = 0;
  var qV = 0;

  acs.on("data", function() {
    // ADC stands for Analog-to-Digital Converter 
    // (https://en.wikipedia.org/wiki/Analog-to-digital_converter)
    // which reads the voltage returning to an analog pin from 
    // a sensor circuit. The value is a 10-bit representation 
    // (0-1023) of a voltage quantity from 0V-5V.
    var adc = 0;
    var currentAmps = 0;

    // The "amps factor" or `aF` is calculated by dividing the
    // the voltage by the max ADC value to produce the 
    // incremental value, which is ~0.0049V for each step 
    // from 0-1023. 
    // Use real VCC (from milli-volts)
    var aF = (VCC / 100) / 1023;


    // 1. Measure the the ACS712 reading with no load (0A);
    //    this is known as the quiescent output voltage, 
    //    which is named `qV` in this program.
    if (!qV) {
      if (!count) {
        console.log("Calibrating...");
      }
      // Calibration phase takes measurements for ~5 seconds
      if (count < (samples * 40)) {
        count++;
        accumulator += this.value;
      } else {
        qV = Math.max(512, (accumulator / (samples * 40)) | 0);
        accumulator = count = 0;

        console.log("qV: %d (%d) ", toMV(qV), qV);
        console.log("Elapsed: ", Date.now() - time);
      }
    } else {
    
      if (count < samples) {
        // 2. Collect readings to calculate a current value
        count++;
        adc = this.value - qV;
        accumulator += adc * adc;
      } else {
        // 3. Update the running root mean square value        
        currentAmps = Math.sqrt(accumulator / samples) * aF;
        accumulator = count = 0;

        // ACS is fairly innaccurate below 0.03
        if (currentAmps < 0.03) {
          currentAmps = 0;
        }
      }

      // If there is a currentAmps value:
      //    If there is an amps value:
      //      return average of currentAmps and amps
      //    Else:
      //      return currentAmps
      // Else:
      //    return amps
      amps = currentAmps ?
        (amps ? (currentAmps + amps) / 2 : currentAmps) :
        amps;

      if (qV && amps) {
        render(amps);
      }
    }
  });
});

Run node current-monitor.js to see the program in action! Adjust the field programmer’s potentiometer to see the current draw charted in the terminal.

Homework

Based on the program and breadboard above, how might these be modified to use a potentiometer instead of the field programmer? How might they be modified to use the ESC class for programmatic control of the Brushless DC motor?

This entry was posted by Rick Waldron (@rwaldron) on July 22, 2014 in JavaScript, Node.js, Arduino, Johnny-Five, NodeBots and Feature.

Comments