From a26b1d6bef0a741ce667a7a1792f30afa033ee9c Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Thu, 16 Oct 2025 21:39:24 -0400 Subject: [PATCH] add fdm volumetric flow output caps --- package.json | 2 +- src/kiri/core/conf.js | 1 + src/kiri/mode/cam/topo4.js | 7 ++++--- src/kiri/mode/fdm/driver-be.js | 1 + src/kiri/mode/fdm/export.js | 11 ++-------- src/kiri/mode/fdm/init-menu.js | 1 + src/kiri/mode/fdm/prepare.js | 37 ++++++++++++++++++++++++++++++++-- web/boot/service.js | 6 +----- web/kiri/lang/en.js | 2 ++ 9 files changed, 48 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 1f9a9bca..0720297b 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "three": "^0.178.0", "three-mesh-bvh": "^0.7.6", "uglify-js": "3.14.5", - "validator": ">=13.7.0", + "validator": ">=13.15.15", "ws": "^8.18.2" }, "devDependencies": { diff --git a/src/kiri/core/conf.js b/src/kiri/core/conf.js index a66aa09d..bc3729bf 100644 --- a/src/kiri/core/conf.js +++ b/src/kiri/core/conf.js @@ -293,6 +293,7 @@ export const conf = { outputInvertY: false, outputLayerRetract: false, outputLoops: 0, + outputMaxFlowrate: 15, outputMinLayerTime: 10, outputMinSpeed: 5.0, outputPurgeTower: 0, diff --git a/src/kiri/mode/cam/topo4.js b/src/kiri/mode/cam/topo4.js index 95053024..3a60e611 100644 --- a/src/kiri/mode/cam/topo4.js +++ b/src/kiri/mode/cam/topo4.js @@ -38,7 +38,6 @@ export class Topo { x: axis === "x", y: axis === "y" }, - zMin = min.z + 0.0001, tolerance = op.tolerance, resolution = tolerance ? tolerance : 1 / Math.sqrt(density / (span.x * span.y)), step = this.step = (tool.traceOffset() * 2) * op.step, @@ -123,7 +122,9 @@ export class Topo { let slices = this.slices = []; let slice = { min: range.min, max: range.min + step, index }; - for (let z = range.min; z < range.max; z += resolution) { + // console.log({ shards, step, range, resolution }); + for (let z = range.min; z <= range.max; z += resolution) { + // console.log({ z }); if (z > slice.max) { slices.push(slice); slice = { min: z, max: z + step, index }; @@ -131,7 +132,7 @@ export class Topo { index++; } slices.push(slice); - // console.log({ shards, range, step, slices }); + // console.log({ shards, range, step, slices: slices.slice() }); const { minions } = self.kiri_worker; if (minions?.running > 1) { diff --git a/src/kiri/mode/fdm/driver-be.js b/src/kiri/mode/fdm/driver-be.js index f1164acc..2efb734d 100644 --- a/src/kiri/mode/fdm/driver-be.js +++ b/src/kiri/mode/fdm/driver-be.js @@ -9,6 +9,7 @@ import { fdm_export } from './export.js'; // fil = filament diameter // slice = slice height function extrudePerMM(noz, fil, slice) { + // (ratio of nozzle to filament) * (ratio of slice to nozzle) return ((Math.PI * util.sqr(noz / 2)) / (Math.PI * util.sqr(fil / 2))) * (slice / noz); }; diff --git a/src/kiri/mode/fdm/export.js b/src/kiri/mode/fdm/export.js index 6b359f56..a65d6ca9 100644 --- a/src/kiri/mode/fdm/export.js +++ b/src/kiri/mode/fdm/export.js @@ -26,7 +26,6 @@ export function fdm_export(print, online, ondone, ondebug) { { extrudeAbs } = device, { exportThumb } = controller, { extrudeMM, extrudePerMM } = FDM, - extused = Object.keys(print.extruders).map(v => parseInt(v)), timeFactor = (device.gcodeTime || 1) * 1.5, decimals = config.gcode_decimals || 4, zMoveMax = device.deviceZMax || 0, @@ -49,7 +48,6 @@ export function fdm_export(print, online, ondone, ondebug) { last = null, zpos = 0, bmax = 0, - blastz = 0, belt_add_y = (process.firstLayerYOffset || 0) - (belty || 0), oloops = process.outputLoops || 0, zhop = process.zHopDistance || 0, // range @@ -58,10 +56,8 @@ export function fdm_export(print, online, ondone, ondebug) { retDist = process.outputRetractDist || 0, // range retSpeed = process.outputRetractSpeed * 60 || 1, // range retDwell = process.outputRetractDwell || 0, // range - timeDwell = retDwell / 1000, scarfZ = process.outputScarfLength ? true : false, arcDist = isBelt || scarfZ ? 0 : (process.arcTolerance || 0), - arcMin = 1, arcRes = 20, arcDev = 0.5, arcMax = 40, @@ -85,7 +81,6 @@ export function fdm_export(print, online, ondone, ondebug) { fanSpeedSave = undefined, fanSpeedBase = 0, fanSpeed = 0, - lastType = undefined, lastNozzleTemp = nozzleTemp, lastBedTemp = bedTemp, lastFanSpeed = fanSpeed, @@ -169,7 +164,6 @@ export function fdm_export(print, online, ondone, ondebug) { retDist = params.outputRetractDist || 0; // range retSpeed = params.outputRetractSpeed * 60 || 1; // range retDwell = params.outputRetractDwell || 0; // range - timeDwell = retDwell / 1000; nozzleTemp = layer === 0 ? params.firstLayerNozzleTemp || params.outputTemp : params.outputTemp || params.firstLayerNozzleTemp; @@ -470,7 +464,7 @@ export function fdm_export(print, online, ondone, ondebug) { if (isBelt) { let zheight = path ? path.height || 0 : 0; epos.x = originCenter ? -pos.x : device.bedWidth - pos.x; - epos.z = blastz = pos.z * icos; + epos.z = pos.z * icos; epos.y = -pos.y + epos.z * bcos + belt_add_y; lout = epos; } @@ -635,7 +629,7 @@ export function fdm_export(print, online, ondone, ondebug) { // emit comment on output type chage if (last && out.type !== last.type) { - lastType = subst.feature = out.type; + subst.feature = out.type; if (gcodeFeature && gcodeFeature.length) { appendAllSub(gcodeFeature); } else { @@ -752,7 +746,6 @@ export function fdm_export(print, online, ondone, ondebug) { } // if new point is off the arc - // if (deem || depm || desp || dc > arcDist || cc.r < arcMin || cc.r > arcMax || dist > cc.r) { if (deem || depm || desp || dc * arcQ.center.length / arcQ.rSum > arcDist || dist > cc.r || cc.r > arcMax || radFault || !arcValid()) { // let debug = [deem, depm, desp, dc * arcQ.center.length / arcQ.rSum > arcDist, dist > cc.r, cc.r > arcMax, radFault]; if (arcQ.length === 4) { diff --git a/src/kiri/mode/fdm/init-menu.js b/src/kiri/mode/fdm/init-menu.js index 07571f0b..dc062c28 100644 --- a/src/kiri/mode/fdm/init-menu.js +++ b/src/kiri/mode/fdm/init-menu.js @@ -177,6 +177,7 @@ export function menu() { arcTolerance: newInput(LANG.ad_arct_s, {title:LANG.ad_arct_l, convert:toFloat, bound:bound(0,1.0), show:() => { return isNotBelt() }}), outputRetractDwell: newInput(LANG.ad_rdwl_s, {title:LANG.ad_rdwl_l, convert:toInt}), outputMinSpeed: newInput(LANG.ad_mins_s, {title:LANG.ad_mins_l, convert:toFloat, bound:bound(1,200)}), + outputMaxFlowrate: newInput(LANG.ad_maxf_s, {title:LANG.ad_maxf_l, convert:toFloat, bound:bound(1,200)}), outputPurgeTower: newInput(LANG.ad_purg_s, {title:LANG.ad_purg_l, convert:toInt, bound:bound(0,1000)}), outputScarfLength: newInput(LANG.ad_scar_s, {title:LANG.ad_scar_l, convert:toFloat, bound:bound(0,1000)}), outputShortPoly: newInput(LANG.ad_spol_s, {title:LANG.ad_spol_l, convert:toFloat, bound:bound(0,10000)}), diff --git a/src/kiri/mode/fdm/prepare.js b/src/kiri/mode/fdm/prepare.js index 7152f12a..1a46dea0 100644 --- a/src/kiri/mode/fdm/prepare.js +++ b/src/kiri/mode/fdm/prepare.js @@ -1,5 +1,6 @@ /** Copyright Stewart Allen -- All Rights Reserved */ +import { FDM } from './driver-be.js'; import { base, util } from '../../../geo/base.js'; import { poly2polyEmit, tip2tipEmit } from '../../../geo/paths.js'; import { newBounds } from '../../../geo/bounds.js'; @@ -794,10 +795,22 @@ export async function fdm_prepare(widgets, settings, update) { } }; + +/** + * Output and route Slice (shell,fill) paths for a single Slice + * + * @param {*} print Print output Object + * @param {*} slice current slice being Output + * @param {*} startPoint starting point for this layer + * @param {*} offset start point offset + * @param {*} output output prebuffer + * @param {*} opt options + */ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { const { settings } = print; const { device } = settings; const { bedWidth, bedDepth, bedRound } = device; + const { extrudePerMM } = FDM; let preout = [], process = opt.params || settings.process, @@ -806,6 +819,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { scarfLength = process.outputScarfLength || 0, minLayerTime = process.outputMinLayerTime || 0, nozzleSize = process.sliceLineWidth || device.extruders[extruder].extNozzle, + nozzles = device.extruders.map(e => e.extNozzle), firstLayer = (opt.first || false) && !opt.support, thinWall = nozzleSize * (opt.thinWall || 1.75), retractDist = opt.retractOver || (nozzleSize * 5), @@ -828,6 +842,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { zhop = process.zHopDistance || 0, zmax = opt.zmax, antiBacklash = process.antiBacklash, + maxFlowRate = process.outputMaxFlowrate, wipeDist = process.outputRetractWipe || 0, isBelt = device.bedBelt, bedOffset = originCenter ? { @@ -1595,16 +1610,34 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { if (!p.emit) continue; let mms = p.speed ?? 1; let dst = lp?.distTo2D(p.point) ?? 0; + lp = p.point; if (dst) { tt += (dst/mms); td += dst; + p.dst = dst; } - lp = p.point; } if (minLayerTime && tt < minLayerTime) { let fact = tt / minLayerTime; for (let p of preout) { - if (p.emit) p.speed = Math.max(p.speed * fact, minSpeed); + if (p.emit) { + p.speed = Math.max(p.speed * fact, minSpeed); + } + } + } + + // apply speed damping when output exceeds volumetric flowrate cap + if (maxFlowRate) { + for (let p of preout) { + if (p.emit && p.dst) { + let vfr = nozzles[p.tool] * slice.height * p.speed; + if (vfr > maxFlowRate) { + let old = p.speed; + let damp = maxFlowRate / vfr; + p.speed = p.speed * damp; + // console.log({ vfr, damp, old, new: p.speed }); + } + } } } diff --git a/web/boot/service.js b/web/boot/service.js index c32533d2..8d0f405a 100644 --- a/web/boot/service.js +++ b/web/boot/service.js @@ -127,16 +127,12 @@ async function redirectOr404(path) { } } -async function fromCacheOrNetwork(req, test) { +async function fromCacheOrNetwork(req) { const cache = await caches.open(CACHE_VERSION); const hit = await cache.match(req, { ignoreSearch: true }); if (hit) { - // log(`hit: ${req.url}`); return hit; } - if (test) { - return test; - } const net = await fetch_safe(req); cache.put(req, net.clone()); log(`put: ${net.url}`); diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 39eb200d..c73e00ca 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -868,6 +868,8 @@ self.lang['en-us'] = { ad_msol_l: ["minimum area (mm^2)","required to keep solid","must be > 0.1"], ad_mins_s: "min speed", ad_mins_l: ["minimum speed","for short segments"], + ad_maxf_s: "max flowrate", + ad_maxf_l: ["maximum volumetric flowrate supported by this print head and filament","in millimeters^3 / second"], ad_scar_s: "scarf length", ad_scar_l: ["ease up length for scarf joint. disables arc detection","0 = disabled"], ad_spol_s: "short path",