output_devices/Motor.js

const inherit = require('../tools.js').inherit;
const PWMOutputDevice = require('./PWMOutputDevice.js').PWMOutputDevice;
const DigitalOutputDevice = require('./DigitalOutputDevice.js').DigitalOutputDevice;
const OutputDevice = require('./OutputDevice.js').OutputDevice;
const CompositeDevice = require('../devices/CompositeDevice.js').CompositeDevice;
const exc = require('../exc.js');

exports.Motor = Motor;

/**
 * Represents a generic motor connected to a bi-directional motor driver circuit (i.e.  an `H-bridge`_).
 * Attach an `H-bridge`_ motor controller to your Pi; connect a power source (e.g. a battery pack or the 5V pin) to the controller; connect the outputs
 * of the controller board to the two terminals of the motor; connect the inputs of the controller board to two GPIO pins.
 *
 * @param {int} forward - The GPIO pin that the forward input of the motor driver chip is connected to.
 * @param {int} backward - The GPIO pin that the backward input of the motor driver chip is connected to.
 * @param {boolean} [pwm] - If ``true`` (the default), construct {@link PWMOutputDevice} instances for the motor controller pins, allowing both direction and variable speed control. If ``False``, construct {@link DigitalOutputDevice} instances, allowing only direction control.
 * @class
 * @augments CompositeDevice
 * @throws GPIOPinMissing - If either Forward or Backward pin is not provided.
 */
function Motor(forward, backward, pwm) {
    if (forward === undefined || backward === undefined) {
        throw new exc.GPIOPinMissing('Forward and Backward pins must be provided');
    }
    if (pwm === undefined || pwm === true) {
        CompositeDevice.call(this,undefined, [['forward_device', new PWMOutputDevice(forward)],
            ['backward_device', new PWMOutputDevice(backward)]]);
    } else {
        CompositeDevice.call(this, undefined, [['forward_device', new DigitalOutputDevice(forward)],
            ['backward_device', new DigitalOutputDevice(backward)]]);
    }
}

Motor.prototype = inherit(CompositeDevice.prototype);
Motor.prototype.constructor = Motor;

/**
 * Close down the output devices and release the pins.
 */
Motor.prototype.close = function() {
    if (this.forward_device !== undefined) {
        this.forward_device.close();
        this.forward_device = undefined;
    }

    if (this.backward_device !== undefined) {
        this.backward_device.close();
        this.backward_device = undefined;
    }
    OutputDevice.prototype.close.call(this);
};

/**
 *
 * @returns {boolean} - If true then the forward and backward devices are undefined.
 */
Motor.prototype.closed = function() {
    return (this.forward_device === undefined && this.backward_device === undefined);
};
/**
 * Gets and Sets the motor speed between -1 (full backwards) and 1 (full forwards).
 *
 * @param {int} [value] - Motor speed.
 * @returns {number} - If value is undefined then returns the current speed.
 * @throws OutputDeviceBadValue - If the value is defined but not between 1 and -1.
 */
Motor.prototype.value = function(value) {
    if (value === undefined) {
        return this.forward_device.value() - this.backward_device.value();
    }

    if (value > 1 || value < -1) {
        throw new exc.OutputDeviceBadValue("Motor value must be between -1 and 1, actual=:" + value);
    }

    if (value > 0) {
        this.forward(value);
    } else if (value < 0) {
        this.backward(-value);
    } else {
        this.stop();
    }
};
/**
 *
 * @returns {boolean} - If the motor is currently running then ``true`` otherwise ``false``.
 */
Motor.prototype.is_active = function() {
    /*

     */
    return this.value() !== 0;
};

/**
 * Drive the motor forwards.
 *
 * @param {float} speed - The speed at which the motor should turn. Can be any value between 0 (stopped)
 * and the default 1 (maximum speed) if ``pwm`` was ``true`` when the class was constructed (and only 0 or 1 if not).
 *
 * @throws ValueError - When the speed is less than 0 or greater than 1.
 * @throws ValueError - When the speed is between 0 and 1 on non-pwm motors.
 */
Motor.prototype.forward = function(speed) {
    if (speed === undefined) {
        speed = 1;
    }

    if (speed < 0 || speed > 1) {
        throw new exc.ValueError('forward speed must be between 0 and 1');
    }

    if (this.forward_device instanceof DigitalOutputDevice && speed !== 1 && speed !== 0) {
        throw new exc.ValueError('forward speed must be 0 or 1 with non-PWM Motors');
    }

    this.backward_device.off();
    this.forward_device.value(speed);
};

/**
 * Drive the motor backwards.
 *
 * @param {float} speed - The speed at which the motor should turn. Can be any value between 0 (stopped)
 * and the default 1 (maximum speed) if ``pwm`` was ``true`` when the class was constructed (and only 0 or 1 if not).
 *
 * @throws ValueError - When the speed is less than 0 or greater than 1.
 * @throws ValueError - When the speed is between 0 and 1 on non-pwm motors.
 */
Motor.prototype.backward = function(speed) {
    if (speed === undefined) {
        speed = 1;
    }

    if (speed < 0 || speed > 1) {
        throw new exc.ValueError('backward speed must be between 0 and 1');
    }

    if (this.backward_device instanceof DigitalOutputDevice && speed !== 1 && speed !== 0) {
        throw new exc.ValueError('backward speed must be 0 or 1 with non-PWM Motors');
    }

    this.forward_device.off();
    this.backward_device.value(speed);
};

/**
 *     Reverse the current direction of the motor. If the motor is currently
 *     idle this does nothing. Otherwise, the motor's direction will be
 *     reversed at the current speed.
 */
Motor.prototype.reverse = function() {
    this.value(-1 * this.value());
};

/**
 * Stop the motor.
 */
Motor.prototype.stop = function() {
    this.forward_device.off();
    this.backward_device.off();
};