Show:

File: src/io/GyroITG3200.js

/**
 * Based in part on Filipe Vieira'a ITG3200 library for Arduino.
 *
 * Copyright (c) 2011-2012 Jeff Hoefs <soundanalogous@gmail.com>
 * Released under the MIT license. See LICENSE file for details.
 */

JSUTILS.namespace('BO.io.GyroITG3200');

BO.io.GyroITG3200 = (function() {
  "use strict";

  var GyroITG3200;

  // private static constants
  var STARTUP_DELAY = 70,
    SMPLRT_DIV = 0x15,
    DLPF_FS = 0x16,
    INT_CFG = 0x17,
    GYRO_XOUT = 0x1D,
    GYRO_YOUT = 0x1F,
    GYRO_ZOUT = 0x21,
    PWR_MGM = 0x3E,
    NUM_BYTES = 6;

  // dependencies
  var I2CBase = BO.I2CBase,
    Event = JSUTILS.Event,
    GyroEvent = BO.io.GyroEvent;

  /**
   * Creates an interface to an ITG3200 3-axis gyroscope. This gyro measures
   * angular acceleration around the x, y, and z axis. This object provides
   * the angular velocity of each axis. Proper calibration is required for an
   * accurate reading. See [Breakout/examples/sensors/itg3200.html](https://github.com/soundanalogous/Breakout/blob/master/examples/sensors/itg3200.html) and
   * [Breakout/examples/processing\_js/gyro.html](https://github.com/soundanalogous/Breakout/blob/master/examples/processing_js/gyro.html) for example applications.
   *
   * @class GyroITG3200
   * @constructor
   * @extends BO.I2CBase
   * @param {IOBoard} board The IOBoard instance
   * @param {Boolean} autoStart True if read continuous mode should start automatically upon instantiation (default is true)
   * @param {Number} address The i2c address of the accelerometer. If pin 9 (AD0) of the module is tied to VDD, then use
   * `GyroITG3200.ID_AD0_DVV` (0x69), if pin 9 (AD0) is tied to GND, then use `GyroITG3200.ID_AD0_GND`.
   * Default = `GyroITG3200.ID_AD0_VDD`
   */
  GyroITG3200 = function(board, autoStart, address) {

    if (autoStart === undefined) {
      autoStart = true;
    }
    address = address || GyroITG3200.ID_AD0_VDD;

    I2CBase.call(this, board, address);

    this.name = "GyroITG3200";

    // private properties
    this._autoStart = autoStart;
    this._isReading = false;
    this._tempOffsets = {};
    this._startupTimer = null;
    this._debugMode = BO.enableDebugging;

    this._x = 0;
    this._y = 0;
    this._z = 0;

    this._gains = {
      x: 1.0,
      y: 1.0,
      z: 1.0
    };
    this._offsets = {
      x: 0.0,
      y: 0.0,
      z: 0.0
    };
    this._polarities = {
      x: 0,
      y: 0,
      z: 0
    };

    this.setRevPolarity(false, false, false);

    this.init();

  };

  GyroITG3200.prototype = JSUTILS.inherit(I2CBase.prototype);
  GyroITG3200.prototype.constructor = GyroITG3200;


  Object.defineProperties(GyroITG3200.prototype, {
    /**
     * [read-only] The x axis output value in degrees.
     * @property x
     * @type Number
     */
    x: {
      get: function() {
        return this._x / 14.375 * this._polarities.x * this._gains.x + this._offsets.x;
      }
    },

    /**
     * [read-only] The y axis output value in degrees.
     * @property y
     * @type Number
     */
    y: {
      get: function() {
        return this._y / 14.375 * this._polarities.y * this._gains.y + this._offsets.y;
      }
    },

    /**
     * [read-only] The z axis output value in degrees.
     * @property z
     * @type Number
     */
    z: {
      get: function() {
        return this._z / 14.375 * this._polarities.z * this._gains.z + this._offsets.z;
      }
    },

    /**
     * [read-only] The raw value of the x axis
     * @property rawX
     * @type Number
     */
    rawX: {
      get: function() {
        return this._rawX;
      }
    },

    /**
     * [read-only] The raw value of the y axis
     * @property rawY
     * @type Number
     */
    rawY: {
      get: function() {
        return this._rawY;
      }
    },

    /**
     * [read-only] The raw value of the z axis
     * @property rawZ
     * @type Number
     */
    rawZ: {
      get: function() {
        return this._rawZ;
      }
    },

    /**
     * [read-only] The state of continuous read mode. True if continuous read mode
     * is enabled, false if it is disabled.
     * @property isRunning
     * @type Boolean
     */
    isRunning: {
      get: function() {
        return this._isReading;
      }
    }
  });

  /**
   * Set the polarity of the x, y, and z output values.
   *
   * @method setRevPolarity
   * @param {Boolean} xPol Polarity of the x axis
   * @param {Boolean} yPol Polarity of the y axis
   * @param {Boolean} zPol Polarity of the z axis
   */
  GyroITG3200.prototype.setRevPolarity = function(xPol, yPol, zPol) {
    this._polarities.x = xPol ? -1 : 1;
    this._polarities.y = yPol ? -1 : 1;
    this._polarities.z = zPol ? -1 : 1;
  };

  /**
   * Offset the x, y, or z output by the respective input value.
   *
   * @method setOffsets
   * @param {Number} xOffset
   * @param {Number} yOffset
   * @param {Number} zOffset
   */
  GyroITG3200.prototype.setOffsets = function(xOffset, yOffset, zOffset) {
    this._offsets.x = xOffset;
    this._offsets.y = yOffset;
    this._offsets.z = zOffset;
  };

  /**
   * Set the gain value for the x, y, or z output.
   *
   * @method setGains
   * @param {Number} xGain
   * @param {Number} yGain
   * @param {Number} zGain
   */
  GyroITG3200.prototype.setGains = function(xGain, yGain, zGain) {
    this._gains.x = xGain;
    this._gains.y = yGain;
    this._gains.z = zGain;
  };

  /**
   * Start continuous reading of the sensor.
   * @method startReading
   */
  GyroITG3200.prototype.startReading = function() {
    if (!this._isReading) {
      this._isReading = true;
      this.sendI2CRequest([I2CBase.READ_CONTINUOUS, this.address, GYRO_XOUT, NUM_BYTES]);
    }
  };

  /**
   * Stop continuous reading of the sensor.
   * @method stopReading
   */
  GyroITG3200.prototype.stopReading = function() {
    this._isReading = false;
    this.sendI2CRequest([I2CBase.STOP_READING, this.address]);
  };


  /**
   * Sends read request to accelerometer and updates accelerometer values.
   * @method update
   */
  GyroITG3200.prototype.update = function() {

    if (this._isReading) {
      this.stopReading();
    }
    // read data: contents of X, Y, and Z registers
    this.sendI2CRequest([I2CBase.READ, this.address, GYRO_XOUT, NUM_BYTES]);
  };

  /**
   * @private
   * @method init
   */
  GyroITG3200.prototype.init = function() {
    // set fast sample rate divisor = 0
    this.sendI2CRequest([I2CBase.WRITE, this.address, SMPLRT_DIV, 0x00]);

    // set range to +-2000 degrees/sec and low pass filter bandwidth to 256Hz and internal sample rate to 8kHz
    this.sendI2CRequest([I2CBase.WRITE, this.address, DLPF_FS, 0x18]);

    // use internal oscillator
    this.sendI2CRequest([I2CBase.WRITE, this.address, PWR_MGM, 0x00]);

    // enable ITG ready bit and raw data ready bit
    // note: this is probably not necessary if interrupts aren't used
    this.sendI2CRequest([I2CBase.WRITE, this.address, INT_CFG, 0x05]);


    this._startupTimer = setTimeout(this.onGyroReady.bind(this), STARTUP_DELAY);
  };

  /**
   * @private
   * @method onGyroReady
   */
  GyroITG3200.prototype.onGyroReady = function() {
    this._startupTimer = null;

    this.dispatchEvent(new GyroEvent(GyroEvent.GYRO_READY));
    if (this._autoStart) {
      this.startReading();
    }
  };

  /**
   * @private
   * @method setRegisterBit
   */
  GyroITG3200.prototype.setRegisterBit = function(regAddress, bitPos, state) {
    var value;

    if (state) {
      value |= (1 << bitPos);
    } else {
      value &= ~(1 << bitPos);
    }
    this.sendI2CRequest([I2CBase.WRITE, this.address, regAddress, value]);
  };


  /**
   * @private
   * @method handleI2C
   */
  GyroITG3200.prototype.handleI2C = function(data) {

    switch (data[0]) {
      case GYRO_XOUT:
        this.readGyro(data);
        break;
      default:
        this.debug("Got unexpected register data");
        break;
    }
  };

  /**
   * @private
   * @method readGyro
   */
  GyroITG3200.prototype.readGyro = function(data) {

    var x_val,
      y_val,
      z_val;

    if (data.length != NUM_BYTES + 1) {
      throw new Error("Incorrecte number of bytes returned");
    }

    x_val = (data[1] << 8) | (data[2]);
    y_val = (data[3] << 8) | (data[4]);
    z_val = (data[5] << 8) | (data[6]);

    if (x_val >> 15) {
      this._x = ((x_val ^ 0xFFFF) + 1) * -1;
    } else {
      this._x = x_val;
    }
    if (y_val >> 15) {
      this._y = ((y_val ^ 0xFFFF) + 1) * -1;
    } else {
      this._y = y_val;
    }
    if (z_val >> 15) {
      this._z = ((z_val ^ 0xFFFF) + 1) * -1;
    } else {
      this._z = z_val;
    }

    this.dispatchEvent(new GyroEvent(GyroEvent.UPDATE));
  };

  /**
   * for debugging
   * @private
   */
  GyroITG3200.prototype.debug = function(str) {
    if (this._debugMode) {
      console.log(str);
    }
  };

  // public static constants

  /**
   * ID = 0x69 if sensor pin 9 (AD0) is tied to Power.
   * @property GyroITG3200.ID_AD0_VDD
   * @static
   */
  GyroITG3200.ID_AD0_VDD = 0x69;

  /**
   * ID = 0x68 if sensor pin 9 (AD0) is tied to Ground.
   * @property GyroITG3200.ID_AD0_VDD
   * @static
   */
  GyroITG3200.ID_AD0_GND = 0x68;


  // document events

  /**
   * The update event is dispatched when the accelerometer values are updated.
   * @type BO.io.GyroEvent.UPDATE
   * @event update
   * @param {BO.io.GyroITG3200} target A reference to the GyroITG3200 object.
   */

  return GyroITG3200;

}());