On the Raspberry PI I run the below code. I keep it in a file /home/pi/dev/excavator/control.js
To run this program automatically when the Raspberry Pi gets power applied, just add this one line to /etc/rc.local (just before the "exit 0" line):
Code:
cd /home/pi/dev/excavator/ && sudo /usr/local/bin/node control.js &
The contents of /home/pi/dev/excavator/control.js:
Code:
var fs = require('fs');
// Set a deadzone of +/-0 (no deadzone) (out of +/-32k) and a sensitivty of 100 to reduce signal noise in joystick axis
var joystick = new (require('joystick'))(0, 0, 100);
// State / config
var speeds = {
leftTrack: { current: 0, wanted: 0, accel: 1 },
rightTrack: { current: 0, wanted: 0, accel: 1 },
swing: { current: 0, wanted: 0, accel: 1 },
boom: { current: 0, wanted: 0, accel: 1 },
stick: { current: 0, wanted: 0, accel: 1 },
bucket: { current: 0, wanted: 0, accel: 1 }
}
// Upate current speeds based on wanted speed from joystick and accelleration limits
var accelInterval = 20;
setInterval(function () {
for (var propName in speeds) {
if (speeds.hasOwnProperty(propName)) {
var speed = speeds[propName];
var accel = speed.accel * accelInterval / 1000;
if (Math.abs(speed.current - speed.wanted) < accel) {
speed.current = speed.wanted;
} else {
speed.current += speed.current > speed.wanted ? -accel : accel;
}
}
}
}, accelInterval);
var leftTrackReverse = false;
var rightTrackReverse = false;
// Read the remote control
joystick.on('axis', function (event) {
// console.log(JSON.stringify(event));
// Typical event: { time: 1585158, value: 8783, number: 0, type: 'axis', id: 0 }
var value = event.value / 32768; // Now in the -1 -> 0 -> 1 range
value = value * Math.abs(value); // Exponential
switch (event.number) {
case 0: speeds.swing.wanted = -value; break; // Left stick horizontal / swing
case 1: speeds.stick.wanted = -value; break; // Left stick vertical / stick
case 3: speeds.bucket.wanted = -value; break; // Rigth stick horizontal / bucket
case 4: speeds.boom.wanted = -value; break; // Rigth stick verical / boom
case 2: speeds.leftTrack.wanted = (leftTrackReverse ? -1 : 1) * ((value + 1) / 2); break;
case 5: speeds.rightTrack.wanted = (rightTrackReverse ? -1 : 1) * ((value + 1) / 2); break;
}
});
joystick.on('button', function (event) {
// console.log(JSON.stringify(event));
// Typical event: { time: 1607722, value: 0, number: 0, type: 'button', id: 0 }
if (event.number === 4) { // Left top shoulder
leftTrackReverse = event.value !== 0;
}
if (event.number === 5) { // Rigt top shoulder
rightTrackReverse = event.value !== 0;
}
});
// The motor controllers
var SerialPort = require("serialport").SerialPort;
function startMotorControllerOn(devicePath) {
var serialPort = new SerialPort(devicePath, { baudrate: 9600 });
serialPort.on('open', function () {
serialPort.on('data', function (data) {
var deviceId = data[0];
console.log('Got device id: ' + deviceId + ' from ' + devicePath);
clearInterval(idInterval);
setInterval(function () {
var motor0Speed = 0;
var motor1Speed = 0;
switch (deviceId) {
case 10: motor0Speed = speeds.leftTrack.current; motor1Speed = speeds.rightTrack.current; break;
case 11: motor0Speed = speeds.swing.current; motor1Speed = speeds.boom.current; break;
case 12: motor0Speed = speeds.stick.current; motor1Speed = speeds.bucket.current; break;
}
var cmd = motor0Speed >= 0 ? 0x88 : 0x8A;
serialPort.write([cmd, Math.abs(motor0Speed) * 127]);
cmd = motor1Speed >= 0 ? 0x8C : 0x8E;
serialPort.write([cmd, Math.abs(motor1Speed) * 127]);
// console.log(JSON.stringify({ d: deviceId, a: motor0Speed, b: motor1Speed}));
}, 50);
});
var idInterval = setInterval(function () {
console.log('Sending request for device id... to ' + devicePath);
serialPort.write([0x83, 0]);
console.log('Sent request for device id... to ' + devicePath);
}, 1000);
});
}
startMotorControllerOn('/dev/ttyUSB0');
startMotorControllerOn('/dev/ttyUSB1');
startMotorControllerOn('/dev/ttyUSB2');