Import LinuxCNC source tree

This commit is contained in:
Wang Dequan
2026-08-20 06:17:39 +08:00
commit 2c814634c3
9429 changed files with 10556013 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
/* renamed from cc_hole.gcmc for clarity
*
* G-code meta compiler
*
* Copyright (C) 2014 B. Stultiens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Hole milling example
* --------------------
* Mill a hole in continuous curvature movements. Not a single straight line is
* required to mill an arbitrary large hole from any size milling bit.
* Continuous curvature milling reduces the stress on the mill, bit and object
* by preventing any jerking.
*
* A hole is milled at a given center and depth with a target radius. The
* milling-bit radius and the cutting step define how many turning cycles are
* required to finish the hole. The mill is retracted with a helical move back
* to the center and starting Z-position.
*
* @@@--svg-toolwidth 6.0 --svg-opacity 0.2@@@
*/
feedrate(600mm);
function cc_hole(center, targetradius, toolradius, cutstep, cutz)
{
local mkunitsum = ismodemm() ? 0.0mm : 0.0in;
local oldz = position()[2];
if(!isvector(center) || count(center) < 1) {
error("Center argument must be a vector and must have at least one X or Y coordinate");
return;
}
if(count(center) > 3) {
error("Center argument has more than 3 axes defined, may cause unforeseen problems");
return;
}
if(count(center) > 2 && !isundef(center[2])) {
warning("Center argument has a Z-coordinate, ignoring to prevent plowing into object");
center = head(center, 2);
}
if((count(center) == 1 && isundef(center[0])) || (count(center) > 1 && isundef(center[0]) && isundef(center[1]))) {
warning("Center argument has neither X nor Y coordinate, using current position");
center = head(position(), 2);
}
if(!isscalar(targetradius)) {
error("Target radius argument must be scalar");
return;
}
if(!isnone(targetradius) && !isdistance(targetradius)) {
error("Target radius argument must be a distance");
return;
}
targetradius += mkunitsum; // Make sure we have units
if(targetradius <= 0.0mm) {
error("Target radius argument must be larger than zero");
return;
}
if(!isscalar(toolradius)) {
error("Tool radius argument must be scalar");
return;
}
if(!isnone(toolradius) && !isdistance(toolradius)) {
error("Tool radius argument must be a distance");
return;
}
toolradius += mkunitsum; // Make sure we have units
if(toolradius <= 0.0mm) {
error("Tool radius argument must be larger than zero");
return;
}
if(targetradius <= toolradius) {
error("Hole target radius (", targetradius, ") must be larger than tool radius (", toolradius, ")");
return;
}
if(!isscalar(cutstep)) {
error("Cutting step argument must be scalar");
return;
}
if(!isnone(cutstep) && !isdistance(cutstep)) {
error("Cutting step must be a distance");
return;
}
cutstep += mkunitsum; // Make sure we have units
if(cutstep <= 0.0mm) {
error("Cutting step argument must be larger than zero");
return;
}
if(!isscalar(cutz)) {
error("Cutting depth argument must be scalar");
return;
}
if(!isnone(cutz) && !isdistance(cutz)) {
error("Cutting depth must be a distance");
return;
}
cutz += mkunitsum; // Make sure we have units
if(cutstep > 2.0*toolradius) {
warning("Cutting step is larger than twice the tool radius, not all material will be removed");
} elif(cutstep == 2.0*toolradius) {
warning("Cutting step is exactly twice the tool radius, material may be left at the inner edge");
}
comment("-- cc_hole center=", center, " targetradius=", targetradius, " toolradius=", toolradius, " cutstep=", cutstep, " cutz=", cutz, " --");
goto(center); // Center of the hole
move([-, -, cutz]); // Start the initial cut at the center; r = toolradius
local r = toolradius; // Keep track how big the hole is
local n = 1;
local dir = -1.0; // Alternating end-point tracking (=> (-1)^n sign shift)
local p; // endpoint for new arc into next hole circle
// We have to circle 1..n times to make the hole
while(r < targetradius) {
if(targetradius - r >= cutstep) {
// Take a full cutting step because space allows
p = (2*n-1) * cutstep;
r += cutstep;
} else {
// Last cut is under cutstep in size
p = (2*n-2) * cutstep + targetradius - r;
r += targetradius - r;
}
arc_cw_r([0.0mm, dir * p], p/2.0); // Arc into the next circle
circle_cw(center); // Widen the hole
n++;
dir = -dir; // Arc endpoint alternate
}
// Curve _out_ of the hole by helical arc move back to center and oldz
arc_cw_r([0.0mm, dir * (targetradius - toolradius), oldz-cutz], (targetradius - toolradius)/2.0);
comment("-- end cc_hole --");
return;
}
/* -------------------- Main Program -------------------- */
//ngcgui: info: Circular pocket with continuous curvature movements
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: xctr = 0; //, x center
//ngcgui: yctr = 0; //, y center
//ngcgui: diameter = 10; //, diameter
//ngcgui: tool_diameter = 2; //, tool_diameter
//ngcgui: step = 1; //, step
//ngcgui: cutdepth = -1; //, cutdepth
//ngcgui: xfinal = 0; //
//ngcgui: yfinal = 0; //
//ngcgui: zfinal = 1; //
//ngcgui: verbose = 0; // precede ensure_units
include("ensure_units.gcmc"); // avoid preamble conflict
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
xctr = zero + xctr;
yctr = zero + yctr;
diameter = zero + diameter;
tool_diameter = zero + tool_diameter;
step = zero + step;
cutdepth = zero + cutdepth;
xfinal = zero + xfinal;
yfinal = zero + xfinal;
zfinal = zero + xfinal;
location = [xctr,yctr];
FINALPOS = [xfinal,yfinal,zfinal];
goto(FINALPOS);
if(!issvg()) {
move(FINALPOS); // To visualize subsequent rapids in LinuxCNC
}
// Center R_hole R_tool Step Cutting-Z
cc_hole(location, diameter/2, tool_diameter/2, step, cutdepth);
goto(FINALPOS);

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,58 @@
/*******************************************************
The following //comment lines identify ngcgui inputs:
example option:
//ngcgui: --precision 6
info message (appears on ngcgui tab page):
//ngcgui: info: gcmc drill example
variables with defaults:
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: nx=4; //
//ngcgui: ny=3; //
//ngcgui: xstart=1; //
//ngcgui: ystart=1; //
//ngcgui: xspacing=0.5; //
//ngcgui: yspacing=1.0; //
//ngcgui: retract=0.1; //
//ngcgui: increment=0.5; //
//ngcgui: repeatct=1; //
//ngcgui: fr=10,feedrate; //
variable with comment text:
//ngcgui: zdepth=0 , z(neg typ)
//ngcgui: verbose = 0; //precede ensure_units
*******************************************************/
include("ensure_units.gcmc"); //avoid preamble conflict
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
xstart = zero + xstart;
ystart = zero + ystart;
xspacing = zero + xspacing;
yspacing = zero + yspacing;
retract = zero + retract;
increment = zero + increment;
fr = zero + fr;
feedrate(fr);
x=xstart;
y=ystart;
sign = 1;
for (i = 0; i < nx ; i++) {
for (j = 0; j < ny; j++) {
drill([x, y, zdepth], retract, increment, repeatct);
y = y + sign * yspacing;
}
y = y - sign * yspacing;
sign = -1 *sign;
x = x + xspacing;
}

BIN
nc_files/gcmc_lib/drill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,35 @@
// gcmc include file
// ensure gcmc units mode agrees with g20,g21 at runtime
// in case a preamble conflicts with gcmc program
if (ismodemm()) {
if (isdefined("verbose") && verbose == 1) {
literal("\
o1 if [#<_metric> ne 1]\n\
(debug, !!!ensure_units.gcmc: set g21)\n\
g21\n\
o1 endif\n\
");
} else {
literal("\
o1 if [#<_metric> ne 1]\n\
g21\n\
o1 endif\n\
");
}
} else {
if (isdefined("verbose") && verbose == 1) {
literal("\
o1 if [#<_imperial> ne 1]\n\
(debug, !!!ensure_units.gcmc: set g20)\n\
g20\n\
o1 endif\n\
");
} else {
literal("\
o1 if [#<_imperial> ne 1]\n\
g20\n\
o1 endif\n\
");
}
}

View File

@@ -0,0 +1,240 @@
/*
* G-code meta compiler
*
* Copyright (C) 2014 B. Stultiens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Gear example
* ------------
* This example is by no means a complete or correct implementation of gears in
* any generic form. It is primarily for inspiration and to show what gcmc can
* do with relatively little coding. You may use this script as inspiration to
* create a better implementation if you like.
*
* Please note: The below parameters will shift the examples with an XY offset
* as indicated by the options. These are passed on the command-line when the
* examples are generated.
*
* @@@--svg-toolwidth 0.1 --svg-opacity 1 --svg-no-movelayer -x 110 -y 70@@@
*/
/*
* Gear terms:
* N - Number of Teeth
* Pa - Pressure Angle
* D - Pitch Diameter - D = N/P = Do - 2/P (Gear radius at center of the teeth)
* P - Diametral Pitch - P = N/D
* p - Circular Pitch - p = pi() / P
* Db - Base Diameter - Db = D * cos(Pa) (Bottom of teeth insertion)
* Dr - Root Diameter - Dr = D - 2b (Bottom of tooth cutout)
* Do - Outside Diameter - Do = D + 2a
* a - Addendum - a = 1/P
* b - Dedendum - b = ht - a
* ht - Whole Depth (Pa<20) - 2.157/P
* ht - Whole Depth (Pa>=20) - 2.2/P + 0.05mm (Total depth from outer dia to bottom)
* t - Tooth Thickness - t = pi()/(2*P) (Thinckness at Pitch Diameter)
*/
__ang_step = 2.0deg; /* Trace interval for curves */
/*
* Point on involute curve at specified angle, see https://en.wikipedia.org/wiki/Involute
* Cartesian:
* x = a * ( cos(t) + t * sin(t))
* y = a * ( sin(t) - t * cos(t))
* Polar:
* r = a * sqrt(1 + t^2) = sqrt(a^2 + (a*t)^2)
* phi = t - atan(t)
* where:
* - a = circle radius
* - t = angle (radians)
*
* For angle from circle radius: t^2 = (r/a)^2 - 1
*/
function involute_point(angle, radius)
{
angle = to_rad(angle); /* Multiplication must be in radians */
return radius * [cos(angle) + to_none(angle) * sin(angle), sin(angle) - to_none(angle) * cos(angle)];
}
function involute_angle(radius, outrad)
{
return to_rad(sqrt(pow(outrad/radius, 2.0) - 1));
}
/*
* Make a gear with:
* - nteeth Number of teeth
* - pressure_angle Teeth contact pressure angle
* - diametral_pitch Diametral pitch (teets/length)
*
* Return a vectorlist with outer points of the gear centered at [0,0]
*/
function gear_P(nteeth, pressure_angle, diametral_pitch)
{
/* The routine gets is serious trouble if you make the pressure angle
* too large or too small. Warn the user if such case occurs.
*/
if(pressure_angle > 24.6deg) {
warning("Pressure angle (", pressure_angle, ") too large, cannot fit teeth inside the set outside diameter");
}
if(pressure_angle < 12.0deg) {
warning("Pressure angle (", pressure_angle, ") too small, teeth may get stuck at pitch radius");
}
local i;
local pitch_diameter = nteeth / diametral_pitch;
local base_diameter = pitch_diameter * cos(pressure_angle);
local addendum = 1.0/diametral_pitch;
local ht = 2.157 / diametral_pitch;
local dedendum = ht - addendum;
local outside_diameter = pitch_diameter + 2.0*addendum;
local root_diameter = base_diameter - 2.0*dedendum;
local work_diameter = outside_diameter - 4.0*addendum;
local tooth = {}; // The curve for one tooth
/*
* message("nteeth=", nteeth, " pressure_angle=", pressure_angle, " diametral_pitch=", diametral_pitch);
* message("addendum=", addendum, " dedendum=", dedendum, " ht=", ht);
* message("pitch_diameter=", pitch_diameter);
* message("base_diameter=", base_diameter);
* message("outside_diameter=", outside_diameter);
* message("root_diameter=", root_diameter);
* message("work_diameter=", work_diameter);
*/
/*
* Show the different diameters:
* hole([0, 0], pitch_diameter/2.0);
* hole([0, 0], base_diameter/2.0);
* hole([0, 0], outside_diameter/2.0);
* hole([0, 0], root_diameter/2.0);
* hole([0, 0], work_diameter/2.0);
*/
// Fillet radius is approx. Will not reach root exactly, but close enough
// Otherwise need to calculate intersection with root-circle
local filletrad = (base_diameter - root_diameter)/8.0;
// Center of the fillet arc, involute makes a ~240deg angle with fillet arc
// The fillet arc runs from the root to the working depth of the gear
local center = rotate_xy([-filletrad, 0.0mm], 60.0deg) + [work_diameter/2.0, 0];
// Trace the fillet arc from ~root-circle to working depth at involute arc starting Y-level
for(i = 180.0deg; i > 60.0deg; i -= __ang_step*2.5) {
tooth += { [cos(i), sin(i)] * filletrad + center };
}
if(i != 60.0deg) {
// Add the last point if we did not reach the working depth
tooth += { [cos(60.0deg), sin(60.0deg)] * filletrad + center };
}
// Calculate the maximum involute angle to intersect at the outside radius
local max_a = involute_angle(base_diameter/2.0, outside_diameter/2.0);
// Trace the involute arc from the base up to outside radius
for(i = 0.0deg; i < max_a; i += __ang_step) {
tooth += { involute_point(i, base_diameter/2.0)};
}
if(i != max_a) {
// Add the last point if we did not reach the outside radius
tooth += { involute_point(max_a, base_diameter/2.0)};
}
// We now have one side of the tooth. Rotate to be at tooth-symmetry on X-axis
tooth = rotate_xy(tooth, -90.0deg / nteeth);
// Add the same curve mirrored to make the other side of the tooth
// Coordinates reverse to have them all in one direction only
tooth += reverse(scale(tooth, [1, -1]));
// Create all teeth of the gear by adding each tooth at correct angle
local gear = {};
repeat(nteeth; i) {
gear += rotate_xy(tooth, 360.0deg * i / nteeth);
}
return gear;
}
/* -------------------- Helper Functions -------------------- */
/*
* Trace a path at given offset
*/
function trace(path, offset)
{
goto(path[-1] + offset);
foreach(path; v) {
move(v + offset);
}
}
/*
* Make a hole at center point with given radius
*/
function hole(point, radius)
{
goto(point - [radius]);
circle_cw_r([radius, 0]);
}
/* -------------------- Main Program -------------------- */
//ngcgui: info: Involute-gear example
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: D = 100.0; //, Pitch Dia
//ngcgui: HD = 6.0; //, Hole Dia
//ngcgui: N = 9; //, Number of teeth
//ngcgui: PA = 20.0; //, Pressure Angle (deg)
//ngcgui: frate = 600; //, Feedrate
//ngcgui: xoffset = 0;
//ngcgui: yoffset = 0;
//ngcgui: howmany = 1; //, howmany (1 | 2)
//ngcgui: verbose = 0;
include("ensure_units.gcmc"); //avoid preamble conflict
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
frate = frate + zero;
HD = HD + zero;
D = D + zero;
PA = PA + 0.0deg;
P = N/D; // Diametral pitch
feedrate(frate);
location = [xoffset,yoffset];
if (howmany == 1) {
hole(location, HD/2.0);
trace(gear_P(N, PA, P), location);
} elif (howmany == 2) {
hole(location + [D/2.0, 0.0mm], HD/2.0);
trace(gear_P(N, PA, P), location + [D/2.0, 0.0mm]);
hole(location + [-D/2.0, 0.0mm], HD/2.0);
trace(gear_P(N, PA, P), location + [-D/2, 0.0mm]);
} else {
error("howmany must be 1 or 2");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,70 @@
//ngcgui: info: Rectangle -- simple gcmc example
/*COPY this file to a directory in your subroutine search path that
* precedes the directory of this library file and edit as
* required
*
* ngcgui uses the editor specified by $VISUAL
*/
//--------------------------------------------------------------------
// Variables
// Precede any of the following lines with
// //ngcgui:
// to make an entry box
// Omit the "//ngcgui:" to use the hard-coded value
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: frate = 100; //, Feed Rate
//ngcgui: x1 = 0; //, xoffset
//ngcgui: y1 = 0; //, yoffset
//ngcgui: width = 1;
//ngcgui: height = 1;
//ngcgui: zsafe = 0.1;
//ngcgui: zcut = -0.1; //, zcut (neg)
//ngcgui: verbose = 0; // precede ensure_units
include("ensure_units.gcmc"); // avoid preamble conflict
//--------------------------------------------------------------------
if (verbose) {comment("debug, rectangle.gcmc:start");}
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
frate = zero + frate;
x1 = zero + x1;
y1 = zero + y1;
width = zero + width;
height = zero + height;
zsafe = zero + zsafe;
zcut = zero + zcut;
feedrate(frate);
goto([x1, y1, zsafe]);
move([x1, y1, zcut]);
move([x1 + width, y1, zcut]);
move([x1 + width, y1 + height, zcut]);
move([x1, y1 + height, zcut]);
move([x1, y1, zcut]);
goto([-, -, zsafe]);
if (verbose) {comment("debug, rectangle.gcmc:end");}
// uncomment to see how message()s are handled:
if (verbose) {
message("1test message in gcmc file");
message("2test message in gcmc file");
}
// uncomment to see how warning()s are handled:
//warning("1test warning in gcmc file");
//warning("2test warning in gcmc file");
// uncomment to see how error()s are handled:
//error("1test error in gcmc file");
//error("2test error in gcmc file");

123
nc_files/gcmc_lib/star.gcmc Normal file
View File

@@ -0,0 +1,123 @@
/* demo for using gcmc file with [py]ngcgui
ngcgui tags follow:
info: message to appear on ngcgui tab page:
format is: ^//ngcgui: info: info text
//ngcgui: info: STAR (gcmc G-Code Meta Compiler)
gcmc options (start with hyphen):
format is: ^//ngcgui: -optioname [optionvalue]
//ngcgui: --precision 5
Variables to present in ngcgui with optional default value and comment
format is ^//ngcgui: vname [= value , [comment text]]
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: feedr=100,Feed Rate
//ngcgui: zsafe = 1 ; //,zsafe
//ngcgui: zcut = -1 ; //,zcut (neg typ)
//ngcgui: x1=0,Xoffset
//ngcgui: y1=0,Yoffset
//ngcgui: myscale=1,scale
//ngcgui: n_erodes = 4; //, Erodes
//ngcgui: erode_width = 2; //,width (+/-)
//ngcgui: verbose = 0; //precede ensure_units
*/
include("ensure_units.gcmc"); //avoid preamble conflict
//example below derived from: http://www.vagrearg.org/content/gcmc#running
/*
Copyright: 2013
Author: Bertho Stultiens <bertho@vagrearg.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Return new path from 'srcpath' traced internally offset by 'width' */
function erode(srcpath, width)
{
local n, i, pp, pc, pn, v1, v2, bisect, newpoint, crossp, res;
n = count(srcpath);
res = {};
for(i = 0; i < n; i++) {
pp = srcpath[(i-1+n)%n]; /* Previous point */
pc = srcpath[i]; /* Current point */
pn = srcpath[(i+1+n)%n]; /* Next point */
v1 = normalize(pp - pc);
v2 = normalize(pn - pc);
bisect = width * normalize(v1 + v2);
newpoint = bisect + pc;
if(i > 0) {
/* Check convex polygon interior angle */
crossp = v1[0] * v2[1] - v1[1] * v2[0];
if(crossp < 0.0) {
newpoint = -bisect + pc;
}
}
res += { newpoint };
}
return res;
}
/* Trace the path at offset */
function tracepath(path, offset)
{
move(path[count(path)-1] + offset);
dwell(0);
foreach(path; p) {
move(p + offset);
dwell(0);
}
}
/* A nice star */
starpath = {
[ 1, 1], [ 0, 3],
[-1, 1], [-3, 0],
[-1, -1], [ 0, -3],
[ 1, -1], [ 3, 0]
};
if (umode == 1) {
fix = 0.0mm;
} else {
fix = 0.0in;
}
x1 = fix + x1;
y1 = fix + y1;
frate = fix + feedr;
zsafe = fix + zsafe;
zcut = fix + zcut;
erode_width = fix + erode_width;
theoffset = [x1,y1];
/******************** Program start ********************/
feedrate(feedr);
goto([-,-,zsafe]); /* Safe Z */
starpath *= myscale*10.0; /* Scale the star */
goto(starpath[count(starpath)-1]); /* First coordinate */
move([-,-,zcut]); /* Goto cutting depth */
/* Cut the stars smaller and smaller */
for(i = 0; i < n_erodes; i++) {
tracepath(erode(starpath, erode_width * -i), theoffset);
}
move([-,-,zsafe]); /* Back to safe Z */

BIN
nc_files/gcmc_lib/star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,198 @@
/*
* G-code meta compiler
*
* Copyright (C) 2014 B. Stultiens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Trochoidal example
* ------------------
* Trochoidal movement for high-speed milling. A path is followed in a circular
* pattern with given radius and increment. Afterwards, a clean cut is
* performed to remove the residuals.
*
* NOTE: To take full advantage of trochoidal milling, you need to have a CNC
* program that can look ahead to keep the speed high. For LinuxCNC that means
* you will need the git version on branch circular-blend-arc-rc3 (or any later
* branch thereof, until it is merges into the master branch).
*
* @@@--svg-toolwidth 0.5 --svg-opacity 0.25@@@
*/
/*
* Trochoidal point calculation.
* See: https://en.wikipedia.org/wiki/Trochoid
*/
function trochoid_point(ang, a, b)
{
ang = to_rad(ang); // Trochoids are defined in radians
// The first part is the trochoid, the second part moves the first 180
// degree point at a relative "0, 0" location so we can scale in any
// way without having to do hard math
return [ a * to_none(ang) - b * sin(ang), b - b * cos(ang) ] - [a*pi(), 2.0*b];
}
/*
* Perform a move from startpoint to endpoint using a trochoidal path.
* - Cutting at depth cutz (returns to old Z)
* - Trochoid radius as specified
* - Increment for each turn as specified
*/
function trochoid_move(startpoint, endpoint, cutz, radius, increment)
{
local min_ainc = .1deg; // avoid too long compute times (and log( value<=1))
local min_rotations = 5; // avoid confusing appearance if too small
local i;
local a = increment/(2.0*pi()); // Trochoid step parameter
local ainc = log10(to_mm(radius)) * 5.0deg; // Steps are logarithmic based on the radius to reduce small steps
local oldz = position()[2];
local vec = endpoint - startpoint; // Vector denoting path to move
if (ainc < min_ainc) {
error("ainc too small: ",ainc," (try: increase trochoid radius)");
return;
}
// If we are not moving, it is an error
if(length(vec) <= zero) {
error("trochoid move is not going anywhere");
return;
}
comment("-- trochoid_move at ", cutz, " from ", startpoint, " to ", endpoint, " radius=", radius, " increment=", increment, " --");
// Calculate the number of *whole* rotations, rounded up, we need to make
local n = 2.0rad * pi() * to_none(ceil(length(vec) / increment));
local nrotations = n/(2.0rad * pi());
if (nrotations < min_rotations) {
error("too few rotations= ",nrotations," (try: decrease trochoid increment)");
return;
}
if (verbose) {
comment("debug, rotations= ",nrotations);
comment("debug, ainc= ",ainc);
}
// The path may be arbitrary angled, get the angle for rotating the trochoid
local rot = atan(vec[1], vec[0]);
// Go to the trochoid entry-point and move to cutting deph
goto(startpoint + rotate_xy(trochoid_point(0.0rad, a, radius), rot));
move([-, -, cutz]);
// Calculate each next point of the trochoid until we traversed the whole path to the endpoint
for(i = 0.0deg; i < n; i += ainc) {
move(startpoint + rotate_xy(trochoid_point(i, a, radius), rot));
}
// Return to old Z so we will not bump into stuff
goto([-, -, oldz]);
comment("-- trochoid_move end --");
}
/* -------------------- Main Program -------------------- */
//ngcgui: info: troichoid-path example (mm or inch per parm#1 (units) setting, !! DEFAULTS are in mm !!)
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: trochoid_r = 5; //, trochoidal radius
//ngcgui: trochoid_incr = 2; //, trochoidal increment
//ngcgui: path_scale = 25; //, path scale (all xi,yi)
//ngcgui: xoffset = 0; //, path x offset
//ngcgui: yoffset = 0; //, path y offset
//ngcgui: x0 = 0; //, path x0
//ngcgui: y0 = 1; //, path y0
//ngcgui: x1 = 2; //, path x1
//ngcgui: y1 = 2; //, path y1
//ngcgui: x2 = 0; //, path x2
//ngcgui: y2 = 4; //, path y2
//ngcgui: x3 = -1; //, path x3
//ngcgui: y3 = 2; //, path y3
//ngcgui: cutdepth = -1; //
//ngcgui: safez = 5; // z safe
//ngcgui: x_return = 0; // x return
//ngcgui: y_return = 0; // y return
//ngcgui: fnormal = 300; //, feed normal
//ngcgui: fslow = 150; //, feed slow
//ngcgui: ffast = 3000; //, feed fast
//ngcgui: verbose = 1;
include("ensure_units.gcmc"); //avoid preamble conflict
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
trochoid_r = zero + trochoid_r;
trochoid_incr = zero + trochoid_incr;
xoffset = zero + xoffset;
yoffset = zero + yoffset;
x0 = zero + x0;
y0 = zero + y0;
x1 = zero + x1;
y1 = zero + y1;
x2 = zero + x2;
y2 = zero + y2;
x3 = zero + x3;
y3 = zero + y3;
cutdepth = zero + cutdepth;
safez = zero + safez;
x_return = zero + x_return;
y_return = zero + y_return;
fnormal = zero + fnormal;
fslow = zero + fslow;
ffast = zero + ffast;
CUTZ = cutdepth;
SAFEZ = safez;
HOME = [x_return, y_return, safez];
path = { [xoffset + x0, yoffset + y0],
[xoffset + x1, yoffset + y1],
[xoffset + x2, yoffset + y2],
[xoffset + x3, yoffset + y3] };
path *= path_scale; //path_scale is dimensionless
feedrate(fnormal);
if (verbose) {
comment("debug, feed normal= ",fnormal);
}
goto([-, -, SAFEZ]);
move([-, -, SAFEZ]);
goto(HOME);
/* Trochoidal high-speed milling of the outline */
if (verbose) {
comment("debug, feed fast= ",ffast);
}
feedrate(ffast); // *Really* high-speed milling
repeat(count(path); i) {
trochoid_move(path[i-2], path[i-1], CUTZ, trochoid_r, trochoid_incr);
}
/* Clean-cutting the object */
if (verbose) {
comment("debug, feed slow= ",fslow);
}
feedrate(fslow); // "Finishing the edge" speed
pathmode(1); // Exact path mode so we hit the corners exactly
move([-, -, CUTZ]); // We are at the "outside" of the path, reenter cutting depth
move(path[-1]); // The first corner
foreach(path; v) {
move(v); // Trace the object
}
goto([-, -, SAFEZ]);
goto(HOME);

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,167 @@
/* demo for using gcmc file with [py]ngcgui
//ngcgui: info: WHEELS (gcmc G-Code Meta Compiler)
//ngcgui: umode = 1; //, units: 1:mm, 0:inch
//ngcgui: r1=10; //,Radius 1 (10mm = .39370 in)
//ngcgui: r2= 5; //,Radius 2 ( 5mm = .19685 in)
//ngcgui: r3= 3.333; //,Radius 3 ( 3.333mm = .13122 in)
//ngcgui: s1= 1 ,Speed 1 (ratio, nounits)
//ngcgui: s2= 7 ,Speed 2 (ratio, nounits)
//ngcgui: s3= -17 ,Speed 3 (ratio, nounits)
//ngcgui: p1= 0 ,Phase 1 (angle, degrees)
//ngcgui: p2= 0 ,Phase 2 (angle, degrees)
//ngcgui: p3= 90 ,Phase 3 (angle, degrees)
//ngcgui: zsafe = 1; //, zsafe
//ngcgui: zcut = -1; //, zcut (neg)
//ngcgui: xoffset = 0;
//ngcgui: yoffset = 0;
//ngcgui: scalex = 5;
//ngcgui: scaley = 5;
//ngcgui: scalez = 1;
//ngcgui: frate = 60; //, feedrate
//ngcgui: verbose = 0; // precede ensure_units
*/
include("ensure_units.gcmc"); //avoid preamble conflict
/*
Copyright: 2013
Author: Alan Battersby <alan.battersby@virginmedia.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/********************************************************/
/* Code to produce wheels paths */
/* Using GCMC Compiler */
/* Author: Alan Battersby */
/* Version: 1.0 */
/********************************************************/
/********************************************************/
/* Each wheel is a vector of three components */
/* Radius - The radius of the wheel */
/* Speed - The speed of the wheel */
/* Phase - The phase of the wheel */
function Radius(wheel)
{
return wheel[0];
}
function Speed(wheel)
{
return wheel[1];
}
function Phase(wheel)
{
return wheel[2];
}
function CreateWheel(r, s, p)
{
return [r,s,p];
}
/* Wheels are held in global vector list called wheels */
function CalcPoint(wheels, angle)
{
local at, posn, r, s, p, w;
posn = [0, 0];
foreach (wheels; w)
{
r = Radius(w);
s = Speed(w);
p = Phase(w);
at = s * angle + p;
posn += [r * cos(at), r * sin(at) ];
}
return posn;
}
function CutPath(wheels, start, inc, end, cdepth, scale)
{
local angle, point;
/* move to first point at safe height */
for(angle = start; angle <= end; angle += inc)
{
if (angle == start)
{
/* we should be at safe height */
/* so move to cutting depth */
point = scale(CalcPoint(wheels, angle), scale);
goto(point + theoffset);
goto([-,-,cdepth * scale[2]]);
}
else
{
point = scale(CalcPoint(wheels, angle), scale);
move(point + theoffset);
}
}
}
/******************* Library ****************************/
function GoAtSafeHeight(x,y)
{
goto([-,-,safeheight]);
goto([x,y,safeheight]);
}
/******************* main program ***********************/
if (umode == 1) {
zero = 0.0mm;
} else {
zero = 0.0in;
}
// ngcgui entries are unitless so these additions are used
// to ensure 1) floatingpoint and 2) units per umode setting
xoffset = zero + xoffset;
yoffset = zero + yoffset;
zsafe = zero + zsafe;
zcut = zero + zcut;
r1 = zero + r1;
r2 = zero + r2;
r3 = zero + r3;
s1 = 0.0 + s1; //angular speed ratio (unitless)
s2 = 0.0 + s2; //angular speed ratio (unitless)
s3 = 0.0 + s3; //angular speed ratio (unitless)
theoffset = [xoffset, yoffset];
safeheight = zsafe;
cuttingdepth = zcut;
svec = [scalex, scaley ,scalez ];
wheels = {
CreateWheel(r1, s1, p1 * 1deg),
CreateWheel(r2, s2, p2 * 1deg),
CreateWheel(r3, s3, p3 * 1deg)
};
feedrate(frate);
GoAtSafeHeight(0, 0);
CutPath(wheels, 0deg, 0.01deg, 360deg, cuttingdepth, svec);
GoAtSafeHeight(0, 0);