//=========================================================================================================== // This program produces the toolpaths for the ShopBot to cut the board to make my socket holder // It reads the cutting specs from "readme.txt" and outputs guts of the toolpath in "out.txt". // This toolpath is then manually pasted into my "empty" toolpath header/footer file. // // For pine I'm having good luck at: 8000 RPM and 4.0 inch/sec in X/Y (2.0 inch/sec plunge) - using a 1/2" // diameter 2 flute bit. //=========================================================================================================== #include #include #include #include #define R2D (57.295779513) #define BIT_RADIUS (0.125) #define SURFACE_HGT (0.79) double clearing_hgt = 1.00; int debug_print = 1; void cut_circle(double x_ctr, double y_ctr, double radius, double cut_hgt, int raise_bit); void cut_circle_w_tabs(double x_ctr, double y_ctr, double radius, double cut_hgt, int raise_bit); void cut_out_disk(double x_ctr, double y_ctr, double radius, double cut_hgt); void cut_out_disk_to_depth(double x_ctr, double y_ctr, double radius, double cut_hgt); void cut_rectangle(double xmin, double ymin, double xmax, double ymax, double cut_hgt, int raise_bit); void cut_out_rectangle(double xmin, double ymin, double xmax, double ymax, double cut_hgt); void cut_out_rectangle_to_depth(double xmin, double ymin, double xmax, double ymax, double cut_hgt); FILE *infile; FILE *outfile; FILE *debugfile; //----------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------- void main() { double x_ctr, y_ctr, radius, cut_hgt; double xmin, xmax, ymin, ymax; char record[200]; double dia, wid, hgt, depth; long rec_count = 0; infile = fopen("readme.txt", "r"); if (infile == NULL) { printf("\n Failed to open 'readme.txt'\n"); exit(0); } outfile = fopen("out.txt", "w"); if (outfile == NULL) { printf("\n Failed to open out.txt\n"); exit(0); } debugfile = fopen("debug.agr", "w"); // ======================================================================================================= // Make finger-grab slot // ======================================================================================================= cut_hgt = SURFACE_HGT - (9.0 / 25.4); x_ctr = 178.4; xmin = (x_ctr - 22.0)/25.4 + BIT_RADIUS; xmax = (x_ctr + 22.0)/25.4 - BIT_RADIUS; ymin = 153.8 / 25.4; ymax = 193.1 / 25.4; cut_out_rectangle_to_depth(xmin, ymin, xmax, ymax, cut_hgt); radius = (22.0/25.4) - BIT_RADIUS; x_ctr = 178.4 / 25.4; y_ctr = 193.1 / 25.4; cut_out_disk_to_depth(x_ctr, y_ctr, radius, cut_hgt); y_ctr = 153.8 / 25.4; cut_out_disk_to_depth(x_ctr, y_ctr, radius, cut_hgt); if (1) exit(0); // ======================================================================================================= while(1) { if (fgets(record, 200, infile) == 0) { printf("\n Processed %ld records\n", rec_count); break; } if (record[0] == 'z' || record[0] == 'Z') // End of file. Everything after this is notes/comments { printf("\n Processed %ld records\n", rec_count); break; } else if (record[0] == 'r') // rectangle { sscanf(record, "rect:%lf %lf %lf %lf %lf", &x_ctr, &y_ctr, &wid, &hgt, &depth); // draw_a_rectangle(x_ctr, y_ctr, wid, hgt); xmin = (x_ctr - wid/2.0) / 25.4; xmax = (x_ctr + wid/2.0) / 25.4; ymin = ((y_ctr - hgt/2.0) / 25.4) + BIT_RADIUS; ymax = ((y_ctr + hgt/2.0) / 25.4) - BIT_RADIUS; cut_hgt = SURFACE_HGT - (depth / 25.4); cut_out_rectangle_to_depth(xmin, ymin, xmax, ymax, cut_hgt); } else if (record[0] == 'c') // circle { sscanf(record, "circ:%lf %lf %lf %lf", &x_ctr, &y_ctr, &dia, &depth); x_ctr = x_ctr / 25.4; y_ctr = y_ctr / 25.4; dia = (dia + 1.0) / 25.4; // added 1 mm for clearance radius = dia/2.0 - BIT_RADIUS; cut_hgt = SURFACE_HGT - (depth / 25.4); if (cut_hgt < 0.0) cut_hgt = 0.0; cut_out_disk_to_depth(x_ctr, y_ctr, radius, cut_hgt); } else { printf("ERROR: Neither a rectangle nor cirlce (record: %ld)\n", rec_count); continue; } rec_count++; } } //----------------------------------------------------------------------------------------------- // This routine cuts out a rectangle and removes the material inside the rectangle. It removes // material down to "cut_hgt" (in several passes if need be). // // NOTES: // - The outside perimeter of the rectangle is made with a climbing cut. This tends to // minimize splintering // - It starts cutting at SURFACE_HGT // - xmin, ymin, xmax, and ymax are at the CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_out_rectangle_to_depth(double xmin, double ymin, double xmax, double ymax, double cut_hgt) { double tmp_hgt; int last_pass = 0; // go to clearance height fprintf(outfile, "JZ,%lf\n", clearing_hgt); tmp_hgt = SURFACE_HGT - BIT_RADIUS; if (tmp_hgt < cut_hgt) { tmp_hgt = cut_hgt; last_pass = 1; } while(1) { cut_out_rectangle(xmin, ymin, xmax, ymax, tmp_hgt); if (last_pass) break; tmp_hgt -= BIT_RADIUS; if (tmp_hgt < cut_hgt) { tmp_hgt = cut_hgt; last_pass = 1; } } // go to clearance height fprintf(outfile, "JZ,%lf\n", clearing_hgt); } //----------------------------------------------------------------------------------------------- // This routine cuts out a rectangle and removes the material inside the rectangle. // // NOTES: // - The outside perimeter of the rectangle is made with a climbing cut. This tends to // minimize splintering // - It cuts to "cut_hgt" (relative to 0.0). // - It's up to the user to make sure the cut_hgt is not too deep for a single pass. // - xmin, ymin, xmax, and ymax are at the CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_out_rectangle(double xmin, double ymin, double xmax, double ymax, double cut_hgt) { int last_pass = 0; double x1, x2, y1, y2; x1 = xmin; x2 = xmax; y1 = ymin; y2 = ymax; while(1) { cut_rectangle(x1, y1, x2, y2, cut_hgt, 0); if (last_pass) break; x1 += 0.75 * BIT_RADIUS; x2 -= 0.75 * BIT_RADIUS; y1 += 0.75 * BIT_RADIUS; y2 -= 0.75 * BIT_RADIUS; if (x1 > x2) { x1 = (x1 + x2) / 2.0; x2 = x1; last_pass = 1; } if (y1 > y2) { y1 = (y1 + y2) / 2.0; y2 = y1; last_pass = 1; } } } //----------------------------------------------------------------------------------------------- // This routine cuts out a rectangle - but does not remove the material inside the rectangle. // // If "raise_bit" is non-zero this routine will raise the bit to clearing_hgt before moving // in X-Y, and after completing the rectangle. If you are SURE you don't need these steps, and // you want to save time, set raise_bit to 0 // // NOTES: // - The outside perimeter of the rectangle is made with a climbing cut. This tends to // minimize splintering. // - It cuts to "cut_hgt" (relative to 0.0). // - It's up to the user to make sure the cut_hgt is not too deep for a single pass. // - xmin, ymin, xmax, and ymax are at the CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_rectangle(double xmin, double ymin, double xmax, double ymax, double cut_hgt, int raise_bit) { double x, y, z; if (debug_print) { fprintf(debugfile, "%lf %lf\n", xmin*25.4, ymin*25.4); fprintf(debugfile, "%lf %lf\n", xmax*25.4, ymin*25.4); fprintf(debugfile, "%lf %lf\n", xmax*25.4, ymax*25.4); fprintf(debugfile, "%lf %lf\n", xmin*25.4, ymax*25.4); fprintf(debugfile, "%lf %lf\n", xmin*25.4, ymin*25.4); fprintf(debugfile, "m\n"); } // go to clearance height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); // Go to starting point (above material) x = xmin; y = ymin; fprintf(outfile, "M2,%lf,%lf\n", x, y); // plunge to cutting height z = cut_hgt; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); x = xmax; y = ymin; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); x = xmax; y = ymax; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); x = xmin; y = ymax; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); x = xmin; y = ymin; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); // raise bit to clearing height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); } //----------------------------------------------------------------------------------------------- // This routine cuts out a disk to the specified depth. It cuts out the circle and the material // inside the circle. It cuts from SURFACE_HGT to cut_hgt in several passes if need be. // // NOTES: // - The outside perimeter of the circle is made with a climbing cut. This tends to // minimize splintering // - "radius" is radius of cirlce to be cut at CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_out_disk_to_depth(double x_ctr, double y_ctr, double radius, double cut_hgt) { int last_pass = 0; double tmp_hgt; // go to clearance height fprintf(outfile, "JZ,%lf\n", clearing_hgt); tmp_hgt = SURFACE_HGT - BIT_RADIUS; if (tmp_hgt < cut_hgt) { tmp_hgt = cut_hgt; last_pass = 1; } while(1) { cut_out_disk(x_ctr, y_ctr, radius, tmp_hgt); if (last_pass) break; tmp_hgt -= BIT_RADIUS; if (tmp_hgt < cut_hgt) { tmp_hgt = cut_hgt; last_pass = 1; } } // go to clearance height fprintf(outfile, "JZ,%lf\n", clearing_hgt); } //----------------------------------------------------------------------------------------------- // This routine cuts out a disk (a circle and all the material inside it). // It cuts to "cut_hgt" (relative to 0.0). // // NOTES: // - The outside perimeter of the circle is made with a climbing cut. This tends to // minimize splintering // - It's up to the user to make sure cut_hgt is not too deep for a single cut. // - "radius" is outer-most radius of cirlce to be cut at CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_out_disk(double x_ctr, double y_ctr, double radius, double cut_hgt) { int last_pass = 0; while(1) { cut_circle(x_ctr, y_ctr, radius, cut_hgt, 0); if (last_pass) break; radius -= 1.5*BIT_RADIUS; if (radius < BIT_RADIUS/2.0) { last_pass = 1; radius = BIT_RADIUS/2.0; } } } //----------------------------------------------------------------------------------------------- // This routine cuts out a circle. It does not remove the material inside the circle. // It cuts to "cut_hgt" (relative to 0.0). // // If "raise_bit" is non-zero this routine will raise the bit to clearing_hgt before moving // in X-Y, and after completing the circle. If you are SURE you don't need these steps, and // you want to save time, set raise_bit to 0 // // NOTES: // - The outside perimeter of the circle is made with a climbing cut. This tends to // minimize splintering // - It's up to the user to make sure cut_hgt is not too deep for a single cut. // - "radius" is radius of cirlce to be cut at CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_circle(double x_ctr, double y_ctr, double radius, double cut_hgt, int raise_bit) { int i; double theta, x, y, z; // Go to clearance height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); // Go to starting point (above material) x = x_ctr + radius; y = y_ctr; fprintf(outfile, "M2,%lf,%lf\n", x, y); // plunge to cutting height z = cut_hgt; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); theta = 0.0; for(i=0; i<=360; i++) { theta = (double)i/R2D; x = x_ctr + radius*cos(theta); y = y_ctr + radius*sin(theta); fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); if (debug_print) fprintf(debugfile, "%lf %lf\n", x*25.4, y*25.4); } fprintf(debugfile, "m\n"); // raise bit to clearing height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); } //----------------------------------------------------------------------------------------------- // This routine cuts out a circle, but leaves two tabs. // It does not remove the material inside the circle. // It cuts to "cut_hgt" (relative to 0.0). // // If "raise_bit" is non-zero this routine will raise the bit to clearing_hgt before moving // in X-Y, and after completing the circle. If you are SURE you don't need these steps, and // you want to save time, set raise_bit to 0 // // NOTES: // - Tab width, thickness, and placement is hard-coded. Perhaps this should be fixed. // - It's up to the user to make sure cut_hgt is not too deep for a single cut. // - "radius" is radius of cirlce to be cut at CENTER of cutting bit. //----------------------------------------------------------------------------------------------- void cut_circle_w_tabs(double x_ctr, double y_ctr, double radius, double cut_hgt, int raise_bit) { int i, first_pass = 1; double theta, x, y, z; // go to clearance height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); // Go to starting point (above material) x = x_ctr + radius; y = y_ctr; fprintf(outfile, "M2,%lf,%lf\n", x, y); for(i=10; i<=170; i++) { theta = (double)i/R2D; x = x_ctr + radius*cos(theta); y = y_ctr + radius*sin(theta); if (first_pass) { // Go to starting point (above material) fprintf(outfile, "M2,%lf,%lf\n", x, y); // plunge to cutting height z = cut_hgt; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); first_pass = 0; } fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); } // raise bit to clearing height fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, clearing_hgt); first_pass = 1; for(i=190; i<=350; i++) { theta = (double)i/R2D; x = x_ctr + radius*cos(theta); y = y_ctr + radius*sin(theta); if (first_pass) { // Go to starting point (above material) fprintf(outfile, "M2,%lf,%lf\n", x, y); // plunge to cutting height z = cut_hgt; fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); first_pass = 0; } fprintf(outfile, "M3,%lf,%lf,%lf\n", x, y, z); } // raise bit to clearing height if (raise_bit) fprintf(outfile, "JZ,%lf\n", clearing_hgt); }