//------------------------------------------------------------------------------ // 2 Axis CNC Demo // dan@marginallyclever.com 2013-08-30 //------------------------------------------------------------------------------ // Copyright at end of file. // please see http://www.github.com/MarginallyClever/GcodeCNCDemo for more information. #include "config.h" //------------------------------------------------------------------------------ // GLOBALS //------------------------------------------------------------------------------ char serialBuffer[MAX_BUF]; // where we store the message until we get a newline int sofar; // how much is in the serialBuffer float px, py; // location // speeds float fr = 0; // human version long step_delay; // machine version // settings char mode_abs=1; // absolute mode? //------------------------------------------------------------------------------ // METHODS //------------------------------------------------------------------------------ /** * delay for the appropriate number of microseconds * @input ms how many milliseconds to wait */ void pause(long ms) { delay(ms/1000); delayMicroseconds(ms%1000); // delayMicroseconds doesn't work for values > ~16k. } /** * Set the feedrate (speed motors will move) * @input nfr the new speed in steps/second */ void feedrate(float nfr) { if(fr==nfr) return; // same as last time? quit now. if(nfr>MAX_FEEDRATE || nfr0?1:-1; #ifdef INVERT_Y int diry = dy>0?-1:1; // because the motors are mounted in opposite directions #else int diry = dy>0?1:-1; #endif dx = abs(dx); dy = abs(dy); if(dx>dy) { over = dx/2; for(i=0; i=dx) { over -= dx; m2step(diry); } pause(step_delay); } } else { over = dy/2; for(i=0; i= dy) { over -= dy; m1step(dirx); } pause(step_delay); } } px = newx; py = newy; } // returns angle of dy/dx as a value from 0...2PI float atan3(float dy,float dx) { float a = atan2(dy,dx); if(a<0) a = (PI*2.0)+a; return a; } // This method assumes the limits have already been checked. // This method assumes the start and end radius match. // This method assumes arcs are not >180 degrees (PI radians) // cx/cy - center of circle // x/y - end position // dir - ARC_CW or ARC_CCW to control direction of arc void arc(float cx,float cy,float x,float y,float dir) { // get radius float dx = px - cx; float dy = py - cy; float radius=sqrt(dx*dx+dy*dy); // find angle of arc (sweep) float angle1=atan3(dy,dx); float angle2=atan3(y-cy,x-cx); float theta=angle2-angle1; if(dir>0 && theta<0) angle2+=2*PI; else if(dir<0 && theta>0) angle1+=2*PI; theta=angle2-angle1; // get length of arc // float circ=PI*2.0*radius; // float len=theta*circ/(PI*2.0); // simplifies to float len = abs(theta) * radius; int i, segments = ceil( len * MM_PER_SEGMENT ); float nx, ny, angle3, scale; for(i=0;i 1 && (*ptr) && (long)ptr < (long)serialBuffer+sofar) { // walk to the end if(*ptr==code) { // if you find code on your walk, return atof(ptr+1); // convert the digits that follow into a float and return it } ptr=strchr(ptr,' ')+1; // take a step from here to the letter after the next space } return val; // end reached, nothing found, return default val. } /** * write a string followed by a float to the serial line. Convenient for debugging. * @input code the string. * @input val the float. */ void output(const char *code,float val) { Serial.print(code); Serial.println(val); } /** * print the current position, feedrate, and absolute mode. */ void where() { output("X",px); output("Y",py); output("F",fr); Serial.println(mode_abs?"ABS":"REL"); } /** * display helpful information */ void help() { Serial.print(F("GcodeCNCDemo2AxisV1 ")); Serial.println(VERSION); Serial.println(F("Commands:")); Serial.println(F("G00 [X(steps)] [Y(steps)] [F(feedrate)]; - line")); Serial.println(F("G01 [X(steps)] [Y(steps)] [F(feedrate)]; - line")); Serial.println(F("G02 [X(steps)] [Y(steps)] [I(steps)] [J(steps)] [F(feedrate)]; - clockwise arc")); Serial.println(F("G03 [X(steps)] [Y(steps)] [I(steps)] [J(steps)] [F(feedrate)]; - counter-clockwise arc")); Serial.println(F("G04 P[seconds]; - delay")); Serial.println(F("G90; - absolute mode")); Serial.println(F("G91; - relative mode")); Serial.println(F("G92 [X(steps)] [Y(steps)]; - change logical position")); Serial.println(F("M18; - disable motors")); Serial.println(F("M100; - this help message")); Serial.println(F("M114; - report position and feedrate")); Serial.println(F("All commands must end with a newline.")); } /** * Read the input buffer and find any recognized commands. One G or M command per line. */ void processCommand() { int cmd = parseNumber('G',-1); switch(cmd) { case 0: case 1: { // line feedrate(parseNumber('F',fr)); line( parseNumber('X',(mode_abs?px:0)) + (mode_abs?0:px), parseNumber('Y',(mode_abs?py:0)) + (mode_abs?0:py) ); break; } case 2: case 3: { // arc feedrate(parseNumber('F',fr)); arc(parseNumber('I',(mode_abs?px:0)) + (mode_abs?0:px), parseNumber('J',(mode_abs?py:0)) + (mode_abs?0:py), parseNumber('X',(mode_abs?px:0)) + (mode_abs?0:px), parseNumber('Y',(mode_abs?py:0)) + (mode_abs?0:py), (cmd==2) ? -1 : 1); break; } case 4: pause(parseNumber('P',0)*1000); break; // dwell case 90: mode_abs=1; break; // absolute mode case 91: mode_abs=0; break; // relative mode case 92: // set logical position position( parseNumber('X',0), parseNumber('Y',0) ); break; default: break; } cmd = parseNumber('M',-1); switch(cmd) { case 18: // disable motors disable(); break; case 100: help(); break; case 114: where(); break; default: break; } } /** * prepares the input buffer to receive a new message and tells the serial connected device it is ready for more. */ void ready() { sofar=0; // clear input buffer Serial.print(F(">")); // signal ready to receive input } /** * First thing this machine does on startup. Runs only once. */ void setup() { Serial.begin(BAUD); // open coms setup_controller(); position(0,0); // set staring position feedrate((MAX_FEEDRATE + MIN_FEEDRATE)/2); // set default speed help(); // say hello ready(); } /** * After setup() this machine will repeat loop() forever. */ void loop() { // listen for serial commands while(Serial.available() > 0) { // if something is available char c=Serial.read(); // get it Serial.print(c); // repeat it back so I know you got the message if(sofar. */