Files
linuxcncAllWasm/nc_files/gcmc_lib/trochoid-path.gcmc
2026-08-20 06:17:39 +08:00

199 lines
6.7 KiB
Plaintext

/*
* 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);