dynanode
Version:
Node.js library for Dynamixel motors
770 lines (642 loc) • 23.1 kB
JavaScript
/* DynaNode - v0.1
* 2013-02-09 - dynaNode@zmhenkel.com - Zachary Henkel
* Free to use without restriction.
*
* Library for controlling Dynamixel Motors using Node.js
*/
//Namespace for DynaNode
var DynaNode = DynaNode || {};
//Requires for DynaNode
DynaNode.Requires = DynaNode.Requires || {};
DynaNode.Requires.Util = require("util");
DynaNode.Requires.Events = require("events");
DynaNode.Requires.SerialPort = require("serialport");
DynaNode.Requires.ChildProcess = require("child_process");
//Workers (for serialport)
DynaNode.Workers = DynaNode.Workers || {};
DynaNode.Workers.SerialPort = "./DynaSerialWorker.js";
//Represents a Register (Address & Size in Bytes)
DynaNode.Register = function(registerID,byteLength) {
this.registerID = registerID;
this.byteLength = byteLength;
};
//Register and value pair
DynaNode.Data = function(register,value) {
this.register = register;
this.value = value;
};
//Dynamixel Standard Registers & Byte Sizes
DynaNode.Registers = DynaNode.Registers || {};
DynaNode.Registers.MODEL_NUMBER = new DynaNode.Register(0,2);
DynaNode.Registers.FIRMWARE_VERSION = new DynaNode.Register(2,1);
DynaNode.Registers.MOTOR_ID = new DynaNode.Register(3,1);
DynaNode.Registers.BAUD_RATE = new DynaNode.Register(4,1);
DynaNode.Registers.RETURN_DELAY_TIME = new DynaNode.Register(5,1);
DynaNode.Registers.CW_ANGLE_LIMIT = new DynaNode.Register(6,2);
DynaNode.Registers.CCW_ANGLE_LIMIT = new DynaNode.Register(8,2);
DynaNode.Registers.MODE = new DynaNode.Register(10,1);
DynaNode.Registers.HIGH_TEMP_LIMIT = new DynaNode.Register(11,1);
DynaNode.Registers.LOW_VOLTAGE_LIMIT = new DynaNode.Register(12,1);
DynaNode.Registers.HIGH_VOLTAGE_LIMIT = new DynaNode.Register(13,1);
DynaNode.Registers.MAX_TORQUE = new DynaNode.Register(14,2);
DynaNode.Registers.STATUS_RETURN_LEVEL = new DynaNode.Register(16,1);
DynaNode.Registers.ALARM_LED = new DynaNode.Register(17,1);
DynaNode.Registers.ALARM_SHUTDOWN = new DynaNode.Register(18,1);
DynaNode.Registers.TORQUE_ENABLE = new DynaNode.Register(24,1);
DynaNode.Registers.LED = new DynaNode.Register(25,1);
DynaNode.Registers.CW_COMPLIANCE_MARGIN = new DynaNode.Register(26,1);
DynaNode.Registers.CCW_COMPLIANCE_MARGIN= new DynaNode.Register(27,1);
DynaNode.Registers.CW_COMPLIANCE_SLOPE = new DynaNode.Register(28,1);
DynaNode.Registers.CCW_COMPLIANCE_SLOPE = new DynaNode.Register(29,1);
DynaNode.Registers.GOAL_POSITION = new DynaNode.Register(30,2);
DynaNode.Registers.MOVING_SPEED = new DynaNode.Register(32,2);
DynaNode.Registers.TORQUE_LIMIT = new DynaNode.Register(34,2);
DynaNode.Registers.PRESENT_POSITION = new DynaNode.Register(36,2);
DynaNode.Registers.PRESENT_SPEED = new DynaNode.Register(38,2);
DynaNode.Registers.PRESENT_LOAD = new DynaNode.Register(40,2);
DynaNode.Registers.PRESENT_VOLTAGE = new DynaNode.Register(42,1);
DynaNode.Registers.PRESENT_TEMP = new DynaNode.Register(43,1);
DynaNode.Registers.REGISTERED_INS = new DynaNode.Register(44,1);
DynaNode.Registers.RESERVED = new DynaNode.Register(45,1);
DynaNode.Registers.MOVING = new DynaNode.Register(46,1);
DynaNode.Registers.LOCK = new DynaNode.Register(47,1);
DynaNode.Registers.PUNCH = new DynaNode.Register(48,2);
//Dynamixel Standard Instruction Codes
DynaNode.Instruction = DynaNode.Instruction || {};
DynaNode.Instruction.PING = 0x01;
DynaNode.Instruction.READ_DATA = 0x02;
DynaNode.Instruction.WRITE_DATA = 0x03;
//Dynamixel Model Numbers
DynaNode.ModelNumbers = DynaNode.ModelNumbers || {};
DynaNode.ModelNumbers.AX12 = 12;
DynaNode.ModelNumbers.RX64 = 64;
DynaNode.ModelNumbers.MX64 = 54;
DynaNode.ModelNumbers.EX106 = 107;
DynaNode.ModelNumbers.DX113 = 113;
DynaNode.ModelNumbers.DX116 = 116;
DynaNode.ModelNumbers.DX117 = 117;
DynaNode.ModelNumbers.AX18 = 18;
DynaNode.ModelNumbers.RX10 = 10;
DynaNode.ModelNumbers.RX24 = 24;
DynaNode.ModelNumbers.RX28 = 28;
DynaNode.ModelNumbers.MX28 = 29;
DynaNode.ModelNumbers.MX106 = 320;
//Dynamixel Status Return Levels
DynaNode.StatusReturnLevels = DynaNode.StatusReturnLevels || {};
DynaNode.StatusReturnLevels.NONE = 0;
DynaNode.StatusReturnLevels.READ_DATA = 1;
DynaNode.StatusReturnLevels.ALL = 2;
//Make a global list of all registers
DynaNode.AllRegisters = [];
DynaNode.AllRegisters.push(DynaNode.Registers.MODEL_NUMBER);
DynaNode.AllRegisters.push(DynaNode.Registers.FIRMWARE_VERSION);
DynaNode.AllRegisters.push(DynaNode.Registers.MOTOR_ID);
DynaNode.AllRegisters.push(DynaNode.Registers.BAUD_RATE);
DynaNode.AllRegisters.push(DynaNode.Registers.RETURN_DELAY_TIME);
DynaNode.AllRegisters.push(DynaNode.Registers.CW_ANGLE_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.CCW_ANGLE_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.MODE);
DynaNode.AllRegisters.push(DynaNode.Registers.HIGH_TEMP_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.LOW_VOLTAGE_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.HIGH_VOLTAGE_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.MAX_TORQUE);
DynaNode.AllRegisters.push(DynaNode.Registers.STATUS_RETURN_LEVEL);
DynaNode.AllRegisters.push(DynaNode.Registers.ALARM_LED);
DynaNode.AllRegisters.push(DynaNode.Registers.ALARM_SHUTDOWN);
DynaNode.AllRegisters.push(DynaNode.Registers.TORQUE_ENABLE);
DynaNode.AllRegisters.push(DynaNode.Registers.LED);
DynaNode.AllRegisters.push(DynaNode.Registers.CW_COMPLIANCE_MARGIN);
DynaNode.AllRegisters.push(DynaNode.Registers.CCW_COMPLIANCE_MARGIN);
DynaNode.AllRegisters.push(DynaNode.Registers.CW_COMPLIANCE_SLOPE);
DynaNode.AllRegisters.push(DynaNode.Registers.CCW_COMPLIANCE_SLOPE);
DynaNode.AllRegisters.push(DynaNode.Registers.GOAL_POSITION);
DynaNode.AllRegisters.push(DynaNode.Registers.TORQUE_LIMIT);
DynaNode.AllRegisters.push(DynaNode.Registers.MOVING_SPEED);
DynaNode.AllRegisters.push(DynaNode.Registers.PRESENT_POSITION);
DynaNode.AllRegisters.push(DynaNode.Registers.PRESENT_SPEED);
DynaNode.AllRegisters.push(DynaNode.Registers.PRESENT_LOAD);
DynaNode.AllRegisters.push(DynaNode.Registers.PRESENT_VOLTAGE);
DynaNode.AllRegisters.push(DynaNode.Registers.PRESENT_TEMP);
DynaNode.AllRegisters.push(DynaNode.Registers.REGISTERED_INS);
DynaNode.AllRegisters.push(DynaNode.Registers.RESERVED);
DynaNode.AllRegisters.push(DynaNode.Registers.MOVING);
DynaNode.AllRegisters.push(DynaNode.Registers.LOCK);
DynaNode.AllRegisters.push(DynaNode.Registers.PUNCH);
/* ReadParameter
* Used to indicate the range of registers to read
* stopRegister should be >= startRegister
*
* startRegister (DynaNode.Register)
* stopRegister (DynaNode.Register)
*/
DynaNode.ReadParameter = function(startRegister,stopRegister) {
var that = this;
this.startRegisterID = startRegister.registerID;
this.stopRegisterID = stopRegister.registerID;
var numStopBytes = stopRegister.byteLength;
this.getNumberOfBytes = function() {
return that.stopRegisterID - that.startRegisterID + numStopBytes;
};
};
/* WriteParameter
* For listing values to write to motor
* auto detects range, based on values input
*
* startRegister (DynaNode.Register)
* values = int or [int] (do not separate bytes manually)
*/
DynaNode.WriteParameter = function(startRegister,values) {
var that = this;
this.startRegister = startRegister;
this.registerID = startRegister.registerID;
this.values = values;
this.valueBuffer = new Buffer(0);
//IF Sent a Single Number as Value
if(!isNaN(values)) {
if(this.startRegister.byteLength === 1) {
var buff = new Buffer(1);
buff.writeUInt8(parseInt(this.values),0);
that.valueBuffer = Buffer.concat([that.valueBuffer,buff]);
}
if(this.startRegister.byteLength === 2) {
var buff = new Buffer(2);
buff.writeUInt16LE(parseInt(this.values),0);
that.valueBuffer = Buffer.concat([that.valueBuffer,buff]);
}
} else {
var cReg = that.registerID;
for(var i=0; i<that.value.length; i++) {
//Find The Register Object
var reg = null;
for(var j=0; j<DynaNode.AllRegisters.length; j++)
if(DynaNode.AllRegisters[j].registerID === cReg) {
reg = DynaNode.AllRegisters[j];
break;
}
var len = reg.byteLength;
cReg += len;
var buff = new Buffer(len);
if(len === 1 ) {
buff.readUInt8(that.value[i],0);
}
if(len === 2) {
buff.readUInt16LE(that.value[i],0);
}
that.valueBuffer = Buffer.concat([that.valueBuffer,buff]);
}
}
};
/*
* Class: DynaNode.InstructionPacket
* Builds a packet to send to the Dynamixel Network.
*
* dynamixelID (int)
* instruction (DynaNode.Instructions.*)
* parameter (DynaNode.ReadParameter or DynaNode.WriteParameter)
*/
DynaNode.InstructionPacket = function(dynamixelID,instruction,parameter) {
var that = this;
this.dynamixelID = dynamixelID;
this.instruction = instruction;
this.parameter = parameter;
this.getBuffer = function() {
if(this.instruction === DynaNode.Instruction.PING) {
//0xFF 0xFF ID 0x02 0x01 Checksum
var indx = 0;
var checkSum = 0;
var buffer = new Buffer(6);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(that.dynamixelID,indx++);
checkSum += that.dynamixelID;
buffer.writeUInt8(0x02,indx++);
checkSum += 0x02;
buffer.writeUInt8(that.instruction,indx++);
checkSum += that.instruction;
buffer.writeUInt8((-1*(checkSum+1)) & 255,indx++);
return buffer;
}
if(this.instruction === DynaNode.Instruction.READ_DATA && that.parameter instanceof DynaNode.ReadParameter) {
//0xFF 0xFF ID 0x04 0x02 StartLocation AmountToRead Checksum
var indx = 0;
var checkSum = 0;
var buffer = new Buffer(8);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(that.dynamixelID,indx++);
checkSum += that.dynamixelID;
buffer.writeUInt8(0x04,indx++);
checkSum += 0x04;
buffer.writeUInt8(that.instruction,indx++);
checkSum += that.instruction;
buffer.writeUInt8(that.parameter.startRegisterID,indx++);
checkSum += that.parameter.startRegisterID;
var bts = that.parameter.getNumberOfBytes();
buffer.writeUInt8(bts,indx++);
checkSum += bts;
buffer.writeUInt8((-1*(checkSum+1)) & 255,indx++);
return buffer;
}
if(this.instruction === DynaNode.Instruction.WRITE_DATA && that.parameter instanceof DynaNode.WriteParameter) {
//0xFF 0xFF ID (N+3) 0x03 StartingAddress [Data] Checksum
var indx = 0;
var checkSum = 0;
var length = 3 + that.parameter.valueBuffer.length;
var buffer = new Buffer(4 + length);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(0xFF,indx++);
buffer.writeUInt8(that.dynamixelID,indx++);
checkSum += that.dynamixelID;
buffer.writeUInt8(length,indx++);
checkSum += length;
buffer.writeUInt8(that.instruction,indx++);
checkSum += that.instruction;
buffer.writeUInt8(that.parameter.registerID,indx++);
checkSum += that.parameter.registerID;
for(var i=0;i<that.parameter.valueBuffer.length;i++) {
buffer[indx++] = that.parameter.valueBuffer[i];
checkSum += that.parameter.valueBuffer[i];
}
buffer.writeUInt8((-1*(checkSum+1)) & 255,indx++);
return buffer;
}
};
};
/*
* Class: DynaNode.ResponsePacket
* Assembles a response based on Dynamixel feedback and original
* request packet that was sent.
*
* bufferInput (Buffer) from Dynamixel
* sendPacket (DynaNode.InstructionPacket) that corresponds to sent command
*/
DynaNode.ResponsePacket = function(bufferInput,sendPacket) {
var that = this;
this.dynamixelID = 0;
this.error = 0;
this.data = [];
this.isValid = false;
//0xFF 0xFF ID LENGTH ERROR [Parameters] Checksum
if(bufferInput.length >= 6 && sendPacket !== null) {
var indx = 2;
var checkSum = 0;
that.dynamixelID = bufferInput.readUInt8(indx++);
var length = bufferInput.readUInt8(indx++) - 2;
that.error = bufferInput.readUInt8(indx++);
checkSum += that.dynamixelID + (length+2) + that.error;
var runningReg = sendPacket.parameter.startRegisterID;
for(var i=0;i<length;i++) {
//Find The Register
var reg = null;
for(var j=0;j<DynaNode.AllRegisters.length;j++)
if(DynaNode.AllRegisters[j].registerID === runningReg) {
reg = DynaNode.AllRegisters[j];
break;
}
var val = 0;
if(reg.byteLength == 1) {
val = bufferInput.readUInt8(indx++);
checkSum+=val;
runningReg++;
}
if(reg.byteLength == 2) {
val = bufferInput.readUInt16LE(indx);
checkSum+=bufferInput[indx];
checkSum+=bufferInput[indx+1];
indx+=2;
i++;
runningReg+=2;
}
that.data.push(new DynaNode.Data(reg,val));
}
var rsum = bufferInput.readUInt8(indx++);
checkSum = (-1*(checkSum+1)) & 255;
if(checkSum === rsum)
that.isValid = true;
else
that.isValid = false;
} else {
that.isValid = false;
}
};
/**
* Dynamixel class
* Represents a single Dynamixel Motor. Has a ref to its Network.
* Responsible for sending commands to read registers @ reg intervals.
* IMPORTANT: only created by DynaNode.DynamixelNetwork, not directly
*
* dynaNetwork (DynaNode.DynamixelNetwork)
* motorID (int)
*
* Events
* registerUpdate
* motorStatus
*/
DynaNode.Dynamixel = function(dynaNetwork,motorID){
var that = this;
this.motorID = motorID;
var theNetwork = dynaNetwork;
var motorData = []; motorData.length = 50;
var regularPoll = null;
var online = true;
var lastUpdateTime = -1;
DynaNode.Requires.Events.EventEmitter.call(this);
this.initMotor = function() {
//One-time Poll
var param = new DynaNode.ReadParameter(DynaNode.Registers.MODEL_NUMBER,DynaNode.Registers.ALARM_SHUTDOWN);
var ip = new DynaNode.InstructionPacket(that.motorID,DynaNode.Instruction.READ_DATA,param);
theNetwork.writeInstructionPacket(ip);
//Regular Polling (every 16ms)
var rp = new DynaNode.ReadParameter(DynaNode.Registers.TORQUE_ENABLE,DynaNode.Registers.PUNCH);
var rip = new DynaNode.InstructionPacket(that.motorID,DynaNode.Instruction.READ_DATA,rp);
regularPoll = setInterval(function(){
theNetwork.writeInstructionPacket(rip);
},16);
online = true;
that.emit("motorStatus","online");
};
//Writes To Motor Register
this.writeRegister = function(dynaData) {
var param = new DynaNode.WriteParameter(dynaData.register,dynaData.value);
var ip = new DynaNode.InstructionPacket(that.motorID,DynaNode.Instruction.WRITE_DATA,param);
theNetwork.writeInstructionPacket(ip);
};
this.writeRegisters = function(startRegister,values) {
var param = new DynaNode.WriteParameter(startRegister,values);
var ip = new DynaNode.InstructionPacket(that.motorID,DynaNode.Instruction.WRITE_DATA,param);
theNetwork.writeInstructionPacket(ip);
};
//Receives Data From Network
this.updateRegister = function(dynaData) {
lastUpdateTime = (new Date()).getTime();
var oldData = motorData[dynaData.register.registerID];
motorData[dynaData.register.registerID] = dynaData.value;
if(oldData !== dynaData.value)
that.emit("registerUpdate",{register:dynaData.register.registerID, value:dynaData.value});
};
this.terminate = function() {
clearInterval(regularPoll);
online = false;
that.emit("motorStatus","offline");
};
this.isOnline = function() {
return online;
};
this.getLastUpdateTime = function() {
return lastUpdateTime;
};
this.getCurrentValue = function(registerAddress) {
if(registerAddress < motorData.length)
return motorData[registerAddress];
else
return null;
};
};
DynaNode.Requires.Util.inherits(DynaNode.Dynamixel,DynaNode.Requires.Events.EventEmitter);
//----------A Few "static" methods for Dynamixel -------------------
DynaNode.Dynamixel.getBaudRateConversion = function(regValue) {
return 2000000 / (regValue + 1);
};
DynaNode.Dynamixel.getReturnDelayTimeConversion = function(regValue) {
return 2*regValue;
};
DynaNode.Dynamixel.getLoadConversion = function(regValue) {
//BITS: 15 - 11 10 9-0
// 0 Direction Load Value
// 0 = CCW, 1 = CW
var loadValue = regValue & 511;
var cw = regValue & 2048 === 2048?1:-1;
return cw*loadValue;
};
DynaNode.Dynamixel.getVoltageConversion = function(regValue) {
return (regValue *1.0) / 10.0;
};
/* DynamixelNetwork
* Represents a single USB2Dynamixel or COM port connection to a
* motor network. Use startRange/endRange to specify scanning range.
*
* portName (string) name of COM port for Dynamixel Network
* startRange (int) <=endRange, >=0, <=253
* endRange (int) >=startRange, >=0, <=253
*
* Events
* portOpened - fires when the serial port is successfully opened
* scanCompleted - fires after the motor network has been scaned
* portClosed
* motorAdded
*/
DynaNode.DynamixelNetwork = function(portName,startRange,endRange,timeout){
var that = this;
var port = null;
var start = 1;
var end = 253;
var motors = [];
var runningBuffer = new Buffer(0);
var packetQueue = [];
var currentPacket = null;
var currentPacketTimeout = null;
var portOpened = false;
var inScanMode = true;
var scanBuffer = new Buffer(0);
var scanTimeout = 3000;
timeout = parseInt(timeout);
if(!isNaN(timeout))
scanTimeout = timeout;
//TODO: Add Custom Scan Ranges
if(startRange<=endRange && startRange>=1)
start = startRange;
if(endRange>=startRange && endRange<=253)
end = endRange;
DynaNode.Requires.Events.EventEmitter.call(this);
port = DynaNode.Requires.ChildProcess.fork(DynaNode.Workers.SerialPort);
console.log("start scanner");
port.on("message",function(m){
console.log(m.action);
if(m.action === "open") {
portOpened = true;
that.emit("portOpened");
//Scan For Motors: 3 second timeout, checks
var ip = new DynaNode.InstructionPacket(0xFE,DynaNode.Instruction.PING);
currentPacket = ip;
that.writeInstructionPacketToPort(ip);
//The timeout for the motor scan
setTimeout(function() {
inScanMode = false;
currentPacket = null;
that.emit("scanCompleted",motors);
},scanTimeout);
}
if(m.action === "error") {
portOpened = false;
that.terminateAllMotors();
if(port!==null) {
port.kill();
port = null;
}
if(inScanMode)
that.emit("scanError");
that.emit("portClosed");
}
if(m.action === "end") {
portOpened = false;
that.terminateAllMotors();
if(port!==null) {
port.kill();
port = null;
}
that.emit("portClosed");
}
if(m.action === "close") {
portOpened = false;
that.terminateAllMotors();
if(port!==null) {
port.kill();
port = null;
}
that.emit("portClosed");
}
if(m.action === "data" && inScanMode) {
//Response To Scan
var buffer = new Buffer(m.bufferData);
scanBuffer = Buffer.concat([scanBuffer,buffer]);
scanBuffer = that.removeStartGarbageFromBuffer(scanBuffer);
var rb = that.extractPacketFromBuffer(scanBuffer);
if(rb !== null && rb.length >= 3) {
scanBuffer = scanBuffer.slice(rb.length-1);
//Just Need An ID
var theID = rb[2];
//TODO: Check if motor exists first
var dn = new DynaNode.Dynamixel(that,theID);
motors.push(dn);
that.emit("motorAdded",dn);
}
}
if(m.action === "data" && !inScanMode) {
var buffer = new Buffer(m.bufferData);
runningBuffer = Buffer.concat([runningBuffer,buffer]);
runningBuffer = that.removeStartGarbageFromBuffer(runningBuffer);
var rb = that.extractPacketFromBuffer(runningBuffer);
if(rb !== null) {
runningBuffer = runningBuffer.slice(rb.length-1);
var respPacket = new DynaNode.ResponsePacket(rb,currentPacket);
currentPacket = null;
clearTimeout(currentPacketTimeout);
if(respPacket.isValid) {
//Find Motor To Send Data To
var sendTo = null;
for(var i=0; i<motors.length; i++) {
if(motors[i].motorID === respPacket.dynamixelID) {
sendTo = motors[i];
break;
}
}
if(sendTo !== null) {
//Send Response Data
for(var i=0; i<respPacket.data.length; i++)
sendTo.updateRegister(respPacket.data[i]);
}
}
that.processQueue();
}
}
});
//Creates the actual port connection
port.send({action:"create",comName:portName,baudRate:1000000});
this.removeStartGarbageFromBuffer = function(theBuffer) {
var startIndex = 0;
for(var i=0; i<theBuffer.length; i++) {
if(theBuffer[i] === 0xFF && i+1 >= theBuffer.length) {
startIndex = i;
break;
}
if(i+1 < theBuffer.length && theBuffer[i] === 0xFF && theBuffer[i+1] === 0xFF) {
startIndex = i;
break;
}
startIndex = i;
}
return theBuffer.slice(startIndex);
};
this.extractPacketFromBuffer = function(theBuffer) {
//0xFF 0xFF ID LENGTH ERROR [Parameters] CheckSum
if(theBuffer.length < 6) {
return null;
}
var len = (6+ (theBuffer[3] - 2));
if(theBuffer.length < len) {
return null;
}
return theBuffer.slice(0,len);
};
this.processQueue = function() {
//Move On To Next Message In Queue
for(var i=0; i<packetQueue.length; i++) {
if(currentPacket !== null)
break;
if(packetQueue[i].instruction === DynaNode.Instruction.WRITE_DATA) {
//Write without response expected
that.writeInstructionPacketToPort(packetQueue[i]);
packetQueue.splice(i,1);
i--;
continue;
}
if(packetQueue[i].instruction === DynaNode.Instruction.READ_DATA) {
//Place in currentPacket, then write
currentPacket = packetQueue[i];
that.writeInstructionPacketToPort(packetQueue[i]);
currentPacketTimeout = setTimeout(function(){
that.readDataTimeout();
},128);
packetQueue.splice(i,1);
break;
}
}
};
this.writeInstructionPacket = function(instructionPacket) {
if(!inScanMode) {
packetQueue.push(instructionPacket);
that.processQueue();
}
};
this.readDataTimeout = function() {
//Remove Current Waiting Object, Process Next In Queue
currentPacket = null;
that.processQueue();
};
this.writeInstructionPacketToPort = function(instructionPacket) {
if(port!=null && port.connected)
port.send({action:"transmit",message:instructionPacket.getBuffer()});
};
this.terminateAllMotors = function() {
for(var i=0; i<motors.length; i++)
motors[i].terminate();
};
this.terminate = function() {
portOpened = false;
that.terminateAllMotors();
if(port!=null && port.connected)
port.send({action:"disconnect"});
if(port!==null) {
port.kill();
port = null;
}
that.emit("portClosed");
};
};
DynaNode.Requires.Util.inherits(DynaNode.DynamixelNetwork, DynaNode.Requires.Events.EventEmitter);
//"static" method for DynamixelNetwork, lists all COM ports on system
DynaNode.Utils = DynaNode.Utils || {};
DynaNode.Utils.getAllPorts = function(callBack) {
var retPorts = [];
DynaNode.Requires.SerialPort.list(function(err,ports){
if(err) {
callBack(retPorts);
} else {
for(var i=0;i<ports.length;i++) {
retPorts.push(ports[i].comName);
}
callBack(retPorts);
}
});
};
module.exports = DynaNode;