Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

servo-pca9685

Package Overview
Dependencies
Maintainers
3
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

servo-pca9685 - npm Package Compare versions

Comparing version 0.0.45 to 0.1.0

COPYRIGHT

56

examples/servo.js
/*********************************************
This servo module demo turns the servo around
18 degrees every 500ms, then resets it after
~18 degrees every 500ms, then resets it after
10 turns, reading out position to the console

@@ -8,32 +8,34 @@ at each movement.

// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
var tessel = require('tessel');
var servo = require('../');
var servo = require('../').use(tessel.port('A'));
var hardware = tessel.port('A');
// Initialize the servo.
console.log("Initalizing...");
var servoController = servo.use(hardware);
servoController.on('ready', function () {
servo.on('ready', function () {
var pos = 0; // Target position of the servo between 0 (min) and 1 (max).
setInterval(function () {
console.log("Deg rotation:", pos);
// Set servo #1 to position pos.
// servoController.configureServo(1, 0.05, 0.125);
servoController.setServo(1, pos, function() {
// Read the approximate target positon of servo #1 back from the module.
// Please refer to the docs if you plan to use this value for something.
// servoController.readServo(1, function(err, duty) {
// console.log('Read position:\t', duty);
// });
});
// Set the minimum and maximum duty cycle for servo 1.
// If the servo doesn't move to its full extent or stalls out
// and gets hot, try tuning these values (0.05 and 0.12).
// Moving them towards each other = less movement range
// Moving them apart = more range, more likely to stall and burn out
servo.configure(1, 0.05, 0.12, function () {
setInterval(function () {
console.log('% of full rotation:', pos);
// Set servo #1 to position pos.
servo.move(1, pos, function () {
// Read the approximate target positon of servo #1 back from the module.
// Please refer to the docs if you plan to use this value for something.
// servoController.read(1, function(err, duty) {
// console.log('Read position:\t', duty);
// });
});
// Increment by 10% (~18 deg for a normal servo)
pos += 0.1;
if (pos > 1) {
pos = 0;
}
}, 1000);
// Increment by 10% (~18 deg for a normal servo)
pos += 0.1;
if (pos > 1) {
pos = 0;
}
}, 500);
});
});

@@ -1,10 +0,10 @@

/**
Tessel servo-pca9685 module
// Copyright 2014 Technical Machine, Inc. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
References:
http://www.nxp.com/documents/data_sheet/PCA9685.pdf
http://en.wikipedia.org/wiki/Servo_control
https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
*/
var events = require('events');

@@ -23,5 +23,3 @@ var util = require('util');

function servoController (hardware, low, high, addr2, addr3)
{
function servoController (hardware, low, high, addr2, addr3) {
/**

@@ -48,3 +46,3 @@ Constructor

}
this.high = high || 0.2;
this.high = high || 0.12;

@@ -74,26 +72,9 @@ // Enable the outpts

servoController.prototype._readRegister = function (register, next)
{
// Reads fom the given registers on the PCA9685 via I2C and passes their replies to the callback
servoController.prototype._chainRead = function (registers, callback, replies) {
/**
Read from registers on the PCA9685 via I2C
Args
register
Register to read
next
Callback; gets reply byte as its arg
*/
this.i2c.transfer(new Buffer([register]), 1, function (err, data) {
next && next(err, data[0]);
});
}
servoController.prototype._chainRead = function (registers, next, replies) {
/**
Read from the given registers on the PCA9685 via I2C and pass thier replies to the callback
Args
registers
An array of registers to read
next
callback
Callback; gets an array of reply bytes as an arg

@@ -103,6 +84,8 @@ replies

*/
var replies = replies || [];
var replies = replies || []; // jshint ignore:line
var self = this;
if (registers.length == 0) {
next && next(null, replies);
if (registers.length === 0) {
if (callback) {
callback(null, replies);
}
}

@@ -112,32 +95,16 @@ else {

if (err) {
next && next(err, replies);
if (callback) {
callback(err, replies);
}
}
replies.push(data[0]);
self._chainRead(registers.slice(1), next, replies);
self._chainRead(registers.slice(1), callback, replies);
});
}
}
};
servoController.prototype._writeRegister = function (register, data, next)
{
// Makes multiple writes to the PCA9685's registers via I2C
servoController.prototype._chainWrite = function(registers, data, callback) {
/**
Write to registers on the PCA9685 via I2C
Args
register
Register to read
data
Bytes to send
next
Callback
*/
this.i2c.send(new Buffer([register, data]), next);
}
servoController.prototype._chainWrite = function(registers, data, next)
{
/**
Make multiple writes to the PCA9685's registers via I2C
Args
registers

@@ -147,57 +114,87 @@ An array of register addresses

Ana array of data payloads
next
callback
Callback
*/
var self = this;
if (registers.length == 0) {
next && next();
if (registers.length === 0) {
if (callback) {
callback();
}
}
else {
self.i2c.send(new Buffer([registers[0], data[0]]), function() {
self._chainWrite(registers.slice(1), data.slice(1), next);
self._chainWrite(registers.slice(1), data.slice(1), callback);
});
}
}
};
servoController.prototype.setFrequency = function (freq, next)
{
// Reads from registers on the PCA9685 via I2C
servoController.prototype._readRegister = function (register, callback) {
/**
Set the PWM frequency for the PCA9685 chip.
Args
freq
PWM frequency, in units of Hertz
next
Callback
register
Register to read
callback
Callback; gets reply byte as its arg
*/
var prescaleVal = (25000000 / MAX) / freq - 1;
var prescale = Math.floor(prescaleVal);
var self = this;
self._readRegister(MODE1, function (err, oldMode) {
if (err) {
next && next(err, null);
this.i2c.transfer(new Buffer([register]), 1, function (err, data) {
if (callback) {
callback(err, data[0]);
}
var newMode = oldMode | 0x10;
var registers = [MODE1, PRE_SCALE, MODE1, MODE1];
var data = [newMode, prescale, oldMode, 0xa1];
self._chainWrite(registers, data, next);
});
}
};
servoController.prototype.setServo = function (index, val, next)
{
// Writes to registers on the PCA9685 via I2C
servoController.prototype._writeRegister = function (register, data, callback) {
/**
Set the position of the specified servo
Args
register
Register to read
data
Bytes to send
callback
Callback
*/
this.i2c.send(new Buffer([register, data]), callback);
};
// Sets the PWM max and min for the specified servo
servoController.prototype.configure = function (index, low, high, callback) {
/**
Many hobby servos, motor speed controllers, etc. expect a nominal 20 ms
period and map duty cycles (% time the signal is high for a given period) of
10% and 20% to minimum and maximum positions, respectively. The protocol is
not particularly strict, though, so it is not uncommon for servos to respond
to duty cycles outside the 10%-20% range. This command allows each servo's
minimum and maximum PWM values to be controlled individually.
Args
index
Servo to configure
low
PWM lower bound (value for move(index, 0))
high
PWM upper bound (value for move(index, 1))
callback
Callback
*/
this.servoConfigurations[index] = [low, high];
if (callback) {
callback();
}
};
// Sets the position of the specified servo
servoController.prototype.move = function (index, val, callback) {
/**
Args
index
Index of the servo. NOTE: servos are 1-indexed
val
Position to which the the servo is to move. 0-1 of its full scale.
next
callback
Callback
*/
if (index < 1 || index > 16) {
throw "Servos are 1-indexed. Servos can be between 1-16.";
throw 'Servos are 1-indexed. Servos can be between 1-16.';
}

@@ -207,3 +204,3 @@

if (!this.servoConfigurations[index]) {
this.configureServo(index, this.low, this.high, null);
this.configure(index, this.low, this.high, null);
}

@@ -214,11 +211,56 @@

this.setDuty(index, (val * (high - low)) + low, next);
this.setDutyCycle(index, (val * (high - low)) + low, callback);
};
servoController.prototype.setDuty = function (index, on, next)
{
// Reads the current approximate position target for the specified servo
servoController.prototype.read = function (servo, callback) {
/**
Set the specified channel's duty cycle
For each channel on the PCA9685, there are two 12 bit registers that
correspond to the counter values at which the line is set high and low. This
function reads these registers, calculates the theoretical duty cycle, and
then maps it against the range of duty cycles to which the servo is
calibrated in ```configure```. The ratio of the true duty cycle to the
range of configured duty cycles is passed to the callback.
Because this function cannot determine the true position of a physical servo
and the math it does is inherently lossy, we do not recommend using this
function in feedback loops.
Args
servo
The servo index
callback
Callback; gets err, approximate position target as args
*/
if (!this.servoConfigurations[servo]) {
if (callback) {
callback(new Error('servo not configured'), null);
}
}
var self = this;
var registers = [LED0_ON_L + (servo - 1) * 4,
LED0_ON_H + (servo - 1) * 4,
LED0_OFF_L + (servo - 1) * 4,
LED0_OFF_H + (servo - 1) * 4];
self._chainRead(registers, function(err, replies) {
// When in the count cycle the pin goes high
var on = replies[0] + (replies[1] << 8);
// When it goes low
var off = replies[2] + (replies[3] << 8);
// Effective duty cycle
var duty = (off - on) / MAX;
var low = self.servoConfigurations[servo][0];
var high = self.servoConfigurations[servo][1];
var specificMaxDuty = (high - low);
// empirically determined fudge factors
callback(null, ((duty - low) / specificMaxDuty + 8 / 4096) * 1023/1024);
});
};
// Sets the duty cycle for the specified servo
servoController.prototype.setDutyCycle = function (index, on, callback) {
/**
Args
index

@@ -228,3 +270,3 @@ Servo index to set

Duty cycle (0-1) for the specified servo
next
callback
Callback

@@ -234,47 +276,47 @@ */

if (index < 1 || index > 16) {
throw "Servos are 1-indexed. Servos can be between 1-16.";
throw 'Servos are 1-indexed. Servos can be between 1-16.';
}
var convert_on = 0;
var convert_off = Math.floor(MAX * on);
var convertOn = 0;
var convertOff = Math.floor(MAX * on);
// Set up writes
var registers = [LED0_ON_L + (index - 1) * 4,
LED0_ON_H + (index - 1) * 4,
var registers = [LED0_ON_L + (index - 1) * 4,
LED0_ON_H + (index - 1) * 4,
LED0_OFF_L + (index - 1) * 4,
LED0_OFF_H + (index - 1) * 4];
var data = [convert_on,
convert_on >> 8,
convert_off,
convert_off >> 8];
this._chainWrite(registers, data, next);
}
var data = [convertOn,
convertOn >> 8,
convertOff,
convertOff >> 8];
this._chainWrite(registers, data, callback);
};
servoController.prototype.configureServo = function (index, low, high, next) {
// Sets the PWM frequency in Hz for the PCA9685 chip
servoController.prototype.setModuleFrequency = function (freq, callback) {
/**
Set the PWM max and min for the specified servo.
Many hobby servos, motor speed controllers, etc. expect a nominal 20 ms
period and map duty cycles (% time the signal is high for a given period) of
10% and 20% to minimum and maximum positions, respectively. The protocol is
not particularly strict, though, so it is not uncommon for servos to respond
to duty cycles outside the 10%-20% range. This command allows each servo's
minimum and maximum PWM values to be controlled individually.
Args
index
Servo to configure
low
PWM lower bound (value for setServo(index, 0))
high
PWM upper bound (value for setServo(index, 1))
next
freq
PWM frequency, in units of Hertz
callback
Callback
*/
this.servoConfigurations[index] = [low, high];
next && next();
}
var prescaleVal = (25000000 / MAX) / freq - 1;
var prescale = Math.floor(prescaleVal);
function use (hardware, low, high, next)
{
var self = this;
self._readRegister(MODE1, function (err, oldMode) {
if (err) {
if (callback) {
callback(err, null);
}
}
var newMode = oldMode | 0x10;
var registers = [MODE1, PRE_SCALE, MODE1, MODE1];
var data = [newMode, prescale, oldMode, 0xa1];
self._chainWrite(registers, data, callback);
});
};
function use (hardware, low, high, callback) {
/**

@@ -290,7 +332,7 @@ Connect to the Servo Module

Maximum duty cycle (should be between low and 1.0 for best results)
next
callback
Callback
*/
if (typeof low == 'function') {
next = low;
callback = low;
low = null;

@@ -300,3 +342,3 @@ }

var servos = new servoController(hardware, low, high);
servos.setFrequency(50, function(err) {
servos.setModuleFrequency(50, function(err) {
if (!err) {

@@ -313,5 +355,6 @@ servos._connected = true;

}
next && next();
if (callback) {
callback();
}
});

@@ -321,50 +364,3 @@ return servos;

servoController.prototype.readServo = function (servo, next) {
/**
Read the current approximate position target for the specified servo.
For each channel on the PCA9685, there are two 12 bit registers that
correspond to the counter values at which the line is set high and low. This
function reads these registers, calculates the theoretical duty cycle, and
then maps it against the range of duty cycles to which the servo is
calibrated in ```configureServo```. The ratio of the true duty cycle to the
range of configured duty cycles is passed to the callback.
Because this function cannot determine the true position of a physical servo
and the math it does is inherently lossy, we do not recommend using this
function in feedback loops.
Args
servo
The servo index
next
Callback; gets err, approximate position target as args
*/
if (!this.servoConfigurations[servo]) {
next && next(new Error('servo not configured'), null);
}
var self = this;
var registers = [LED0_ON_L + (servo - 1) * 4,
LED0_ON_H + (servo - 1) * 4,
LED0_OFF_L + (servo - 1) * 4,
LED0_OFF_H + (servo - 1) * 4];
self._chainRead(registers, function(err, replies) {
// When in the count cycle the pin goes high
var on = replies[0] + (replies[1] << 8);
// When it goes low
var off = replies[2] + (replies[3] << 8);
// Effective duty cycle
var duty = (off - on) / MAX;
var low = self.servoConfigurations[servo][0];
var high = self.servoConfigurations[servo][1];
var specificMaxDuty = (high - low);
// empirically determined fudge factors
next(null, ((duty - low) / specificMaxDuty + 8 / 4096) * 1023/1024);
});
}
exports.use = use;
exports.servoController = servoController;
exports.servoController = servoController;
{
"name": "servo-pca9685",
"version": "0.0.45",
"version": "0.1.0",
"description": "Library to run the PCA9685 PWM driver.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -15,14 +15,40 @@ #Servo

```js
/*********************************************
This servo module demo turns the servo around
~18 degrees every 500ms, then resets it after
10 turns, reading out position to the console
at each movement.
*********************************************/
var tessel = require('tessel');
var servo = require('servo-pca9685').use(tessel.port('A'));
var servo = require('servo-pca9685');
servo.on('ready', function () {
setInterval(function () {
servo.setServo(1, 0, function () {
setTimeout(function () {
servo.setServo(1, 1, function () {});
}, 500);
});
});
}, 1000);
var hardware = tessel.port('A');
// Initialize the servo.
console.log('Initalizing...');
var servoController = servo.use(hardware);
servoController.on('ready', function () {
var pos = 0; // Target position of the servo between 0 (min) and 1 (max).
// Set the minimum and maximum duty cycle for servo 1.
// If the servo doesn't move to its full extent or stalls out
// and gets hot, try tuning these values (0.05 and 0.12).
// Moving them towards each other = less movement range
// Moving them apart = more range, more likely to stall and burn out
servoController.configureServo(1, 0.05, 0.12, function () {
setInterval(function () {
console.log('% of full rotation:', pos);
// Set servo #1 to position pos.
servoController.move(1, pos);
// Increment by 10% (~18 deg for a normal servo)
pos += 0.1;
if (pos > 1) {
pos = 0;
}
}, 500);
});
});

@@ -33,52 +59,26 @@ ```

* **`servo`.setFrequency(Hertz)**
##### * `servo.configure(whichServo, minPWM, maxPWM, callback())` Sets the PWM max and min for the specified servo.
* **`servo`.setServo(servoNumber, %FullRotation)**
##### * `servo.move(whichServo, positionOrSpeed, callback())` `positionOrSpeed` is a value between 0 and 1. On a normal servo, this value is the position to move to as a percent of the total available rotational range. On a continuous rotation servo, this value represents the rotation speed: 0 is fast in one direction, 1 is fast in the other direction, and 0.5 is stopped.
* **`servo`.configureServo(servoNumber, lowestDutyCycle, highestDutyCycle, next)**
##### * `servo.read(whichServo, callback())` Reads the current approximate position target for the specified servo.
* **`servo`.readServo(servoNumber, next)**
##### * `servo.setDutyCycle(whichServo, on, callback())` Sets the duty cycle for the specified servo. `on` is duty cycle uptime, range from 0-1.
##### * `servo.setModuleFrequency(Hertz, callback())` Sets the PWM frequency in Hz for the PCA9685 chip.
##Events
* *ready*
* *error*
##### * `servo.on('error', callback(err))` Emitted upon error.
##### * `servo.on('ready', callback())` Emitted upon first successful communication between the Tessel and the module.
##Hardware/Advanced usage
* The servos used in conjucntion with this module should be powered through the 5.5 mm barrel jack.
* The servos used in conjunction with this module should be powered through the 5.5 mm barrel jack.
* The physical *module* is marked with "S", "+", and "-". These correspond to signal, power, and GND. On most *servos*, the GND wire will be black/brown and the signal wire will be yellow/white. Red typically denotes 5 V power.
* This module can be used to drive most speed controllers, which in turn can control a wide variety of actuators. It can also be used to drive small LEDs with current limiting resistors in series.
* The bare square pads by the barrel jack allow the addition of a capacitor to the input power rail if desired. The pad closest to the board edge is connected to GND, the other to the barrel jack's positive pin. This addition is not requred for proper module functionality.
* The bare square pads by the barrel jack allow the addition of a capacitor to the input power rail if desired. The pad closest to the board edge is connected to GND, the other to the barrel jack's positive pin. This addition is not required for proper module functionality.
## License
Software License Agreement (BSD License)
Copyright (c) 2012, Adafruit Industries
Copyright (c) 2014, Technical Machine
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MIT or Apache 2.0, at your option
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc