You are reading a single comment by @Gordon and its replies. Click here to read the full conversation.
  • 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.

About

Avatar for Gordon @Gordon started