// our point structure to make things nice. struct LongPoint { long x; long y; long z; }; struct FloatPoint { float x; float y; float z; }; FloatPoint current_units; FloatPoint target_units; FloatPoint delta_units; FloatPoint current_steps; FloatPoint target_steps; FloatPoint delta_steps; boolean abs_mode = false; //0 = incremental; 1 = absolute //default to inches for units float x_units = X_STEPS_PER_INCH; float y_units = Y_STEPS_PER_INCH; float z_units = Z_STEPS_PER_INCH; float curve_section = CURVE_SECTION_INCHES; //our direction vars byte x_direction = 1; byte y_direction = 1; byte z_direction = 1; //init our string processing void init_process_string() { //init our command for (byte i=0; i 0) feedrate_micros = calculate_feedrate_delay(feedrate); //nope, no feedrate else feedrate_micros = getMaxSpeed(); } //use our max for normal moves. else feedrate_micros = getMaxSpeed(); } //nope, just coordinates! else { //do we have a feedrate yet? if (feedrate > 0) feedrate_micros = calculate_feedrate_delay(feedrate); //nope, no feedrate else feedrate_micros = getMaxSpeed(); } //finally move. dda_move(feedrate_micros); break; //Clockwise arc case 2: //Counterclockwise arc case 3: FloatPoint cent; // Centre coordinates are always relative cent.x = search_string('I', instruction, size) + current_units.x; cent.y = search_string('J', instruction, size) + current_units.y; float angleA, angleB, angle, radius, length, aX, aY, bX, bY; aX = (current_units.x - cent.x); aY = (current_units.y - cent.y); bX = (fp.x - cent.x); bY = (fp.y - cent.y); if (code == 2) { // Clockwise angleA = atan2(bY, bX); angleB = atan2(aY, aX); } else { // Counterclockwise angleA = atan2(aY, aX); angleB = atan2(bY, bX); } // Make sure angleB is always greater than angleA // and if not add 2PI so that it is (this also takes // care of the special case of angleA == angleB, // ie we want a complete circle) if (angleB <= angleA) angleB += 2 * M_PI; angle = angleB - angleA; radius = sqrt(aX * aX + aY * aY); length = radius * angle; int steps, s, step; steps = (int) ceil(length / curve_section); FloatPoint newPoint; for (s = 1; s <= steps; s++) { step = (code == 3) ? s : steps - s; // Work backwards for CW newPoint.x = cent.x + radius * cos(angleA + angle * ((float) step / steps)); newPoint.y = cent.y + radius * sin(angleA + angle * ((float) step / steps)); set_target(newPoint.x, newPoint.y, fp.z); // Need to calculate rate for each section of curve if (feedrate > 0) feedrate_micros = calculate_feedrate_delay(feedrate); else feedrate_micros = getMaxSpeed(); // Make step dda_move(feedrate_micros); } break; //Dwell case 4: delay((int)search_string('P', instruction, size)); break; //Inches for Units case 20: x_units = X_STEPS_PER_INCH; y_units = Y_STEPS_PER_INCH; z_units = Z_STEPS_PER_INCH; curve_section = CURVE_SECTION_INCHES; calculate_deltas(); break; //mm for Units case 21: x_units = X_STEPS_PER_MM; y_units = Y_STEPS_PER_MM; z_units = Z_STEPS_PER_MM; curve_section = CURVE_SECTION_MM; calculate_deltas(); break; //go home. case 28: set_target(0.0, 0.0, 0.0); dda_move(getMaxSpeed()); break; //go home via an intermediate point. case 30: fp.x = search_string('X', instruction, size); fp.y = search_string('Y', instruction, size); fp.z = search_string('Z', instruction, size); //set our target. if(abs_mode) { if (!has_command('X', instruction, size)) fp.x = current_units.x; if (!has_command('Y', instruction, size)) fp.y = current_units.y; if (!has_command('Z', instruction, size)) fp.z = current_units.z; set_target(fp.x, fp.y, fp.z); } else set_target(current_units.x + fp.x, current_units.y + fp.y, current_units.z + fp.z); //go there. dda_move(getMaxSpeed()); //go home. set_target(0.0, 0.0, 0.0); dda_move(getMaxSpeed()); break; //Absolute Positioning case 90: abs_mode = true; break; //Incremental Positioning case 91: abs_mode = false; break; //Set as home case 92: set_position(0.0, 0.0, 0.0); break; /* //Inverse Time Feed Mode case 93: break; //TODO: add this //Feed per Minute Mode case 94: break; //TODO: add this */ default: Serial.print("huh? G"); Serial.println(code,DEC); } } //find us an m code. if (has_command('M', instruction, size)) { code = search_string('M', instruction, size); switch (code) { //TODO: this is a bug because search_string returns 0. gotta fix that. case 0: true; break; /* case 0: //todo: stop program break; case 1: //todo: optional stop break; case 2: //todo: program end break; */ //set max extruder speed, 0-255 PWM case 100: extruder_speed = (int)(search_string('P', instruction, size)); break; //turn extruder on, forward case 101: extruder_set_direction(1); extruder_set_speed(extruder_speed); break; //turn extruder on, reverse case 102: extruder_set_direction(0); extruder_set_speed(extruder_speed); break; //turn extruder off case 103: extruder_set_speed(0); break; //custom code for temperature control case 104: extruder_set_temperature((int)search_string('P', instruction, size)); //warmup if we're too cold. while (extruder_get_temperature() < extruder_target_celsius) { extruder_manage_temperature(); Serial.print("T:"); Serial.println(extruder_get_temperature()); delay(1000); } break; //custom code for temperature reading case 105: Serial.print("T:"); Serial.println(extruder_get_temperature()); break; //turn fan on case 106: extruder_set_cooler(255); break; //turn fan off case 107: extruder_set_cooler(0); break; default: Serial.print("Huh? M"); Serial.println(code); } } //tell our host we're done. Serial.println("ok"); // Serial.println(line, DEC); } //look for the number that appears after the char key and return it double search_string(char key, char instruction[], int string_size) { char temp[10] = ""; for (byte i=0; i