It's now reading gcode off an SD card and plotting graphics... So about all I have to do now is mount the laser and wire it up.
The code is now:
// plotmate
// connected right down one side
var pins = [C5,C6,C7,C8,C9,C10,C11,A8,A9,A10];
var ENDSTOP = pins[9]; // negated
// pins[8] = !pen down
// pins[9] = !axis hit
var motorx = pins.slice(0,4);
var xsteps = [14,13,9,3,2,0,8,4];
var motory = pins.slice(4,8);
var ysteps = [8,0,1,4,12,14,3,10];
var motorxoff = 10;
var motoryoff = 9;
// 3990 steps for width, which = 420mm (A3)
var stepsPerMM = 3990 / 420;
function Stepper(pins, pattern, offpattern) {
this.pins = pins;
this.pattern = pattern;
this.offpattern = offpattern;
this.pos = 0;
}
Stepper.prototype.setHome = function() {
this.pos = 0;
};
Stepper.prototype.stop = function(turnOff) {
if (this.interval) {
clearInterval(this.interval);
this.interval = undefined;
}
if (turnOff && this.offpattern)
digitalWrite(this.pins, this.offpattern);
};
Stepper.prototype.moveTo = function(pos, milliseconds, callback, turnOff) {
pos = 0|pos; // to int
if (milliseconds===undefined)
milliseconds = Math.abs(pos-this.pos)*5;
this.stop(turnOff);
if (pos != this.pos) {
var stepper = this;
var step = function() {
// remove interval if needed
if (stepper.pos == pos) {
stepper.stop(turnOff);
if (callback)
callback();
} else {
// move onwards
stepper.pos += (pos < stepper.pos) ? -1 : 1;
// now do step
digitalWrite(stepper.pins, stepper.pattern[ stepper.pos & (stepper.pattern.length-1) ]);
}
};
this.interval = setInterval(step, milliseconds / Math.abs(pos-this.pos));
step();
} else {
if (callback)
setTimeout(callback, milliseconds);
}
};
var x = new Stepper(motorx, xsteps, motorxoff);
var y = new Stepper(motory, ysteps, motoryoff);
function home(callback) {
x.moveTo(50,undefined,function() {
y.moveTo(50,undefined,function() {
setWatch(function() {
y.stop();
y.setHome();
y.moveTo(50,undefined,function() {
setWatch(function() {
x.stop();
x.setHome();
y.moveTo(0,undefined,callback,true);
}, ENDSTOP, {edge:falling, repeat:false});
x.moveTo(-10000);
});
}, ENDSTOP, {edge:falling, repeat:false});
y.moveTo(-10000);
});
});
}
function setPenDown(down) {
digitalWrite(pins[8], !down);
}
function moveTo(p, speed, callback) {
var dx = x.pos - p[0];
var dy = y.pos - p[1];
var d = Math.sqrt(dx*dx+dy*dy);
var time = d*speed;
x.moveTo(p[0],time, undefined, false);
y.moveTo(p[1],time, callback, false);
}
function plotGCodeLine(line, callback) {
if (line.length===0) {
callback();
return;
}
var numbers = "0123456789";
var codeLen = (numbers.indexOf(line[2])<0) ? 2 : 3;
var gcode = line.substr(0,codeLen);
while (line[codeLen]==" ") codeLen++;
var args = line.substr(codeLen);
switch(gcode) {
case "G90": // Simple cycle
case "G21": // In millimeters
case "M02": // End of program
// do nothing...
callback();break;
case "M03": // laser on
setPenDown(true);
setTimeout(callback, 500);
break;
case "M05": // laser off
setPenDown(false);
setTimeout(callback, 500);
break;
case "G0":
case "G1":
case "G00":
case "G01":
case "G02":
case "G03":
var d = {};
// decode arguments
if (args!==undefined) {
args.split(" ").map(function(a) {
d[a[0]] = a.substr(1);
});
}
if (d.X!==undefined && d.Y!==undefined)
moveTo([d.X*stepsPerMM, d.Y*stepsPerMM], 10, callback);
else
callback();
break;
default:
console.log("Unknown code "+JSON.stringify(gcode));
callback();
}
}
function plotGCodeFile(fileName, completeCallback) {
var f = E.openFile(fileName);
var buffer = f.read(64);
if (buffer===undefined) {
console.log("Couldn't load file");
completeCallback();
return;
}
function newLine() {
// get new data from file
while (buffer.indexOf("\n")<0) {
var r = f.read(64);
if (r===undefined) {
f.close();
break;
}
buffer += r;
}
// if we didn't get any data, finish...
if (buffer==="") {
// turn stuff off
setPenDown(false);
x.stop(true);
y.stop(true);
// call completion callback
completeCallback();
return;
}
// get new line
var eol = buffer.indexOf("\n");
if (eol<0) eol = buffer.length;
var line = buffer.substr(0,eol);
buffer = buffer.substr(eol+1);
// do stuff
plotGCodeLine(line, function() {
setTimeout(newLine, 5);
});
}
newLine();
}
//plotGCodeFile("espruino.nc", function() {print("Done");});
It doesn't do curve interpolation (just simple linear interpolation), but sub-200 lines still seems pretty good for something that can power a laser cutter and/or 3D printer.
Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
It's now reading gcode off an SD card and plotting graphics... So about all I have to do now is mount the laser and wire it up.
The code is now:
It doesn't do curve interpolation (just simple linear interpolation), but sub-200 lines still seems pretty good for something that can power a laser cutter and/or 3D printer.