Created
September 14, 2024 20:40
-
-
Save pingbird/01593ad3cf89f99616cbdef929df9237 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:io'; | |
import 'dart:math'; | |
const prologue = ''' | |
M201 X2500 Y2500 Z400 E5000 ; sets maximum accelerations, mm/sec^2 | |
M203 X180 Y180 Z12 E80 ; sets maximum feedrates, mm / sec | |
M204 P2000 R1250 T2500 ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2 | |
M205 X8.00 Y8.00 Z2.00 E10.00 ; sets the jerk limits, mm/sec | |
M205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec | |
;TYPE:Custom | |
M862.3 P "MINI" ; printer model check | |
G90 ; use absolute coordinates | |
M83 ; extruder relative mode | |
M104 S170 ; set extruder temp for bed leveling | |
M140 S60 ; set bed temp | |
M109 R170 ; wait for bed leveling temp | |
M190 S60 ; wait for bed temp | |
M204 T1250 ; set travel acceleration | |
G28 ; home all without mesh bed level | |
G29 ; mesh bed leveling | |
M204 T2500 ; restore travel acceleration | |
M104 S215 ; set extruder temp | |
G92 E0 | |
G1 Y-2 X179 F2400 | |
G1 Z3 F720 | |
M109 S215 ; wait for extruder temp | |
; intro line | |
G1 X170 F1000 | |
G1 Z0.2 F720 | |
G1 X110 E8 F900 | |
G1 X40 E10 F700 | |
G92 E0 | |
M221 S95 ; set flow | |
G21 ; set units to millimeters | |
G90 ; use absolute coordinates | |
M83 ; use relative distances for extrusion | |
M900 K0.2 ; Filament gcode LA 1.5 | |
; ; Filament gcode LA 1.0 | |
'''; | |
const epilogue = ''' | |
G1 E-2 F2100 ; retract | |
G1 Z10 F720 ; Move print head up | |
G1 X178 Y178 F4200 ; park print head | |
G1 Z30.2 F720 ; Move print head further up | |
G4 ; wait | |
M104 S0 ; turn off temperature | |
M140 S0 ; turn off heatbed | |
M107 ; turn off fan | |
M221 S100 ; reset flow | |
M900 K0 ; reset LA | |
M84 ; disable motors | |
'''; | |
void main() { | |
var originX = 16.0; | |
var originY = 16.0; | |
var scale = 4.0; | |
late double perimeterWidth; | |
late double layerHeight; | |
late double filamentWidth; | |
late double filamentCrossArea; | |
late double perimeterCrossArea; | |
late double solidOverlap; | |
late double extrusion; | |
late double liftHeight; | |
var retractLength = 2; | |
var retractExtraExtrusion = 0.0; | |
filamentWidth = 1.75; | |
void recalculateFilament() { | |
filamentCrossArea = pi * pow(filamentWidth / 2, 2); | |
perimeterCrossArea = (perimeterWidth - layerHeight) * layerHeight + | |
pi * pow(layerHeight / 2, 2); | |
extrusion = perimeterCrossArea / filamentCrossArea; | |
liftHeight = layerHeight * 2; | |
solidOverlap = perimeterCrossArea / (layerHeight * perimeterWidth); | |
} | |
// Feed rates are in mm/min | |
var feed = 10.0 * 60; | |
var liftFeed = 12.0 * 60; | |
var transitionFeed = 150.0 * 60; | |
String fmt(num x) { | |
var t = x.toStringAsFixed(5); | |
if (t.contains('.')) { | |
t = t.replaceAll(RegExp(r'0*$'), '').replaceAll(RegExp(r'\.$'), ''); | |
} | |
return t; | |
} | |
String fmtInline(num x) { | |
var t = fmt(x); | |
if (t.startsWith('0.')) { | |
t = t.substring(1); | |
} | |
return t; | |
} | |
var out = StringBuffer(); | |
out.write(prologue); | |
out.writeln('M106 S255 ; turn on fan'); | |
String transformX(double x) => fmtInline(x * scale + originX); | |
String transformY(double y) => fmtInline(y * scale + originY); | |
var currentZ = 0.0; | |
var retracted = false; | |
void retract() { | |
if (retracted) return; | |
out.writeln('G1 E${fmtInline(-retractLength)} F2100'); | |
out.writeln('G1 F${fmtInline(feed)}'); | |
retracted = true; | |
} | |
void unretract() { | |
if (!retracted) return; | |
out.writeln( | |
'G1 E${fmtInline(retractLength + retractExtraExtrusion)} F2100'); | |
out.writeln('G1 F${fmtInline(feed)}'); | |
retracted = false; | |
} | |
void nextLayer() { | |
recalculateFilament(); | |
currentZ += layerHeight; | |
out.writeln('; next layer'); | |
out.writeln(';LAYER_CHANGE'); | |
out.writeln(';Z:${fmt(currentZ)}'); | |
out.writeln(';HEIGHT:${fmt(layerHeight)}'); | |
out.writeln('G1 Z${fmtInline(currentZ)} F${fmtInline(liftFeed)}'); | |
out.writeln('G1 F${fmtInline(feed)}'); | |
out.writeln('G92 E0.0'); | |
out.writeln(); | |
} | |
void g0(double x, double y) { | |
out.writeln('G0 X${transformX(x)} Y${transformY(y)}'); | |
} | |
void g1(double x, double y, double dist) { | |
unretract(); | |
out.writeln( | |
'G1 X${transformX(x)} Y${transformY(y)} E${fmtInline(dist * scale * extrusion)}'); | |
} | |
// Lift nozzle and move it to the next position | |
void transition(double x, double y) { | |
out.writeln('; transition'); | |
retract(); | |
out.writeln('G1 Z${fmtInline(currentZ + liftHeight)} F$liftFeed'); | |
out.writeln('G1 X${transformX(x)} Y${transformY(y)} F$transitionFeed'); | |
out.writeln('G1 Z${fmtInline(currentZ)} F$liftFeed'); | |
out.writeln('G1 F${fmtInline(feed)}'); | |
out.writeln(); | |
} | |
void line(double x0, double y0, double x1, double y1, bool trans) { | |
if (trans) { | |
transition(x0, y0); | |
} | |
final distance = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2)); | |
g1(x0, y0, 0); | |
g1(x1, y1, distance); | |
} | |
const w = 32; | |
const h = 32; | |
final wD = w.toDouble(); | |
final hD = h.toDouble(); | |
var depth = 2.5; | |
const bottomPerimeterWidth = 0.8; | |
const topPerimeterWidth = 0.25; | |
const chamferDepth = 0.4; | |
void mkSquare(double x, double y, double w, double h) { | |
out.writeln('; square'); | |
line(x, y, x + w, y, true); | |
line(x + w, y, x + w, y + h, false); | |
line(x + w, y + h, x, y + h, false); | |
line(x, y + h, x, y, false); | |
out.writeln(); | |
} | |
void sheet() { | |
final inset = (perimeterWidth / 2) - (0.25 / 2); | |
scale = 1.0; | |
mkSquare(inset, inset, wD * 4.0 - (inset * 2), hD * 4.0 - (inset * 2)); | |
final overlap = (perimeterCrossArea / (layerHeight * perimeterWidth)); | |
print('overlap: $overlap'); | |
final fillX = (perimeterWidth / 2) * overlap; | |
final fillY = (perimeterWidth / 2) * overlap; | |
final fillW = wD * 4.0 - (fillX * 2); | |
final fillH = hD * 4.0 - (fillY * 2); | |
final fillLines = (fillW / perimeterWidth).round(); | |
final lineWidth = fillW / fillLines; | |
perimeterWidth = lineWidth / (overlap * 1.1); | |
for (var i = 0; i < fillLines; i++) { | |
if (i % 2 == 0) { | |
line(fillX + (i + 0.5) * lineWidth, fillY, | |
fillX + (i + 0.5) * lineWidth, fillY + fillH, false); | |
} else { | |
line(fillX + (i + 0.5) * lineWidth, fillY + fillH, | |
fillX + (i + 0.5) * lineWidth, fillY, false); | |
} | |
} | |
} | |
void grid() { | |
// Thicc first layer | |
currentZ = 0.0; | |
feed = 30 * 60; | |
perimeterWidth = 0.6; | |
retractExtraExtrusion = 0.1; | |
layerHeight = 0.2; | |
retract(); | |
nextLayer(); | |
g0(0, 0); | |
// Skirt | |
mkSquare(-1, -1, wD + 2, hD + 2); | |
sheet(); | |
scale = 4.0; | |
const gridLayerHeight = 0.15; | |
final numLayers = depth ~/ gridLayerHeight; | |
final topZ = (numLayers - 1) * gridLayerHeight; | |
for (var layer = 0; layer < numLayers; layer++) { | |
var z = layer * gridLayerHeight; | |
final gridPerimeterWidth = topPerimeterWidth + | |
(bottomPerimeterWidth - topPerimeterWidth) * | |
(z / chamferDepth).clamp(0, 1); | |
layerHeight = gridLayerHeight; | |
final p1 = topPerimeterWidth; | |
final p2 = gridPerimeterWidth; | |
final p3 = (p1 + p2) / 2; | |
final inset = ((p2 - p1) / 4) / scale; | |
final gridInset = ((p2 / 2) - (p1 / 2)) / scale; | |
perimeterWidth = p3; | |
retractExtraExtrusion = 0.05; | |
feed = 50 * 60; | |
retract(); | |
nextLayer(); | |
g0(0, 0); | |
mkSquare(inset, inset, wD - (inset * 2), hD - (inset * 2)); | |
perimeterWidth = gridPerimeterWidth; | |
retractExtraExtrusion = 0.1; | |
recalculateFilament(); | |
retract(); | |
if (layer % 2 == 1) { | |
g1(0, hD, 0); | |
} | |
out.writeln('; vertical lines'); | |
var dir = layer % 2 == 0; | |
for (var i = 1; i < w; i++) { | |
if (dir) { | |
line(i.toDouble(), gridInset, i.toDouble(), hD - gridInset, i == 1); | |
} else { | |
line(i.toDouble(), hD - gridInset, i.toDouble(), gridInset, i == 1); | |
} | |
dir = !dir; | |
retract(); | |
} | |
// Avoid crossing the perimeter | |
dir = layer % 2 == 0; | |
if (dir) { | |
g1(wD - gridInset, hD - gridInset, 0); | |
} else { | |
g1(gridInset, gridInset, 0); | |
} | |
out.writeln('; horizontal lines'); | |
for (var i = 1; i < w; i++) { | |
if (dir) { | |
line(wD - gridInset, hD - i, gridInset, hD - i, i == 1); | |
} else { | |
line(gridInset, hD - i, wD - gridInset, hD - i, i == 1); | |
} | |
dir = !dir; | |
retract(); | |
} | |
// if (layer == 0) { | |
// retract(); | |
// retractExtraExtrusion = 0; | |
// final insetStep = ((perimeterWidth / solidOverlap) / 2) / scale; | |
// for (var i = 0; i < w; i++) { | |
// for (var j = 0; j < h; j++) { | |
// for (var r = 0; r < 2; r++) { | |
// final inset = insetStep * (r + 1); | |
// mkSquare( | |
// i + inset, | |
// j + inset, | |
// 1 - inset * 2, | |
// 1 - inset * 2, | |
// ); | |
// retract(); | |
// } | |
// } | |
// } | |
// } | |
} | |
} | |
// calibration stuff | |
// void row(double gridPerimeterWidth) { | |
// originX = 16 + 40 * 3; | |
// grid( | |
// gridPerimeterWidth, | |
// 0, | |
// ); | |
// | |
// originX = 16 + 40 * 2; | |
// grid( | |
// gridPerimeterWidth, | |
// 0.05, | |
// ); | |
// | |
// originX = 16 + 40; | |
// grid( | |
// gridPerimeterWidth, | |
// 0.1, | |
// ); | |
// | |
// originX = 16; | |
// grid( | |
// gridPerimeterWidth, | |
// 0.15, | |
// ); | |
// } | |
// | |
// originY = 16; | |
// row(0.15); | |
// | |
// originY = 16 + 40; | |
// row(0.20); | |
// | |
// originY = 16 + 40 * 2; | |
// row(0.2); | |
// | |
// originY = 16 + 40 * 3; | |
// row(0.25); | |
originX = 8; | |
originY = 8; | |
grid(); | |
out.write(epilogue); | |
File('grid.gcode').writeAsStringSync(out.toString()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment