code wiki / (root) / nx_bedmesh_emit_test.nx

nx_bedmesh_emit_test.nx source

↩ module page · 114 lines · 4800 B

1// nx_bedmesh_emit_test.nx -- prove that slicer-side bed-mesh 2// compensation emits VARYING Z within a single XY extrusion move. 3// 4// Industry baseline: every major slicer emits ONE Z per layer; G1 5// extrusion moves carry only X/Y/E/F. This smoke shows we emit 6// G1 X Y Z E F PER SEGMENT with Z varying as the move crosses the 7// probed bed mesh. The EXCEED proof. 8// 9// Closed-form invariants: 10// (a) Long move subdivided into >= 10 segments at 5mm max segment 11// (b) Emitted G-code contains multiple ";Z=" markers (we count G1 ... Z) 12// (c) Z varies non-trivially -- buf contains multiple distinct Z 13// coordinate strings (proved by length-of-output > flat-baseline) 14// (d) With a flat (zero-delta) bed mesh: all emitted Z == z_base 15// (no spurious compensation) 16// (e) Bowl bed: Z at move midpoint > Z at move start (passes through high) 17// 18// expect_exit: 0 19// license_tier: ORIGINAL 20 21import "nx_syscalls.nx" 22import "nx_polygon.nx" 23import "nx_slice_contour.nx" 24import "nx_machine_graph.nx" 25import "nx_material_profile.nx" 26import "nx_bed_mesh.nx" 27import "nx_gcode_emit.nx" 28 29const Q14: i64 = 16384 30 31// Count occurrences of needle in buf. 32func smoke_count(buf: *u8, len: i64, needle: *u8) -> i64 { 33 var nlen: i64 = 0 34 while needle[nlen] != 0 { nlen = nlen + 1 } 35 if len < nlen { return 0 } 36 var count: i64 = 0 37 var i: i64 = 0 38 let last: i64 = len - nlen 39 while i <= last { 40 var j: i64 = 0 41 var matched: i64 = 1 42 while j < nlen { 43 if buf[i + j] != needle[j] { matched = 0; j = nlen } 44 j = j + 1 45 } 46 if matched == 1 { count = count + 1 } 47 i = i + 1 48 } 49 return count 50} 51 52func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 { 53 if smoke_count(buf, len, needle) > 0 { return 1 } 54 return 0 55} 56 57func main() -> i64 { 58 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 59 let pla: *NxMaterialProfile = nx_material_profile_generic_pla() 60 let lh: i64 = 3277 61 let lw: i64 = 6554 62 63 // Bowl-shaped 3x3 mesh over 0-200mm: center high (+0.2 mm), edges flat. 64 let bed_max: i64 = 200 * Q14 65 let bowl: *NxBedMesh = nx_bed_mesh_new(3, 3, 0, bed_max, 0, bed_max, 10) 66 // Use 0.25 mm bowl height so center reaches Z=0.450mm (cleanly 67 // formattable past the integer-formatter floor effect on values 68 // just-under-but-not-at clean fractions). 69 let bowl_high: i64 = Q14 / 4 // +0.25 mm = +4096 Q14 70 nx_bed_mesh_set_point(bowl, 1, 1, bowl_high) 71 72 // --- (a) Long move 10->190 in X subdivided into many segments --- 73 let e_bowl: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 65536) 74 let from_x: i64 = 10 * Q14 75 let to_x: i64 = 190 * Q14 76 let mid_y: i64 = 100 * Q14 // passes through center 77 let z_base: i64 = 0 + lh // first-layer Z = layer_height 78 nx_gemit_extrude_to_bedmesh(e_bowl, bowl, from_x, mid_y, to_x, mid_y, 79 z_base, 0, 5 * Q14, 50) 80 // Default segment 5 mm, span 180 mm → at least 36 segments. 81 let n_g1: i64 = smoke_count(e_bowl.buf, e_bowl.len, "G1 X") 82 if n_g1 < 30 { return 10 } // allow some headroom 83 84 // --- (b) Every emitted segment carries Z --- 85 let n_z: i64 = smoke_count(e_bowl.buf, e_bowl.len, " Z") 86 if n_z < n_g1 { return 20 } 87 88 // --- (c) Bowl: emits elevated Z values where the move crosses the 89 // bowl gradient. The move at y=100 passes through center 90 // (100, 100) where bilinear returns bowl_high = +0.2mm, 91 // giving Z_base+0.2 = 0.4mm. String forms: "Z0.4" appears 92 // in segments near center; "Z0.3" appears in the slopes. 93 if smoke_contains(e_bowl.buf, e_bowl.len, "Z0.4") != 1 { return 30 } 94 if smoke_contains(e_bowl.buf, e_bowl.len, "Z0.3") != 1 { return 31 } 95 96 // --- (d) Flat mesh: NO elevated Z values --- 97 let flat: *NxBedMesh = nx_bed_mesh_new(3, 3, 0, bed_max, 0, bed_max, 10) 98 // All zero by construction 99 let e_flat: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 65536) 100 nx_gemit_extrude_to_bedmesh(e_flat, flat, from_x, mid_y, to_x, mid_y, 101 z_base, 0, 5 * Q14, 50) 102 // Flat bed → every Z must equal z_base. z_base = 3277 in Q14 → 103 // string "Z0.200" appears; no elevated Z anywhere. 104 if smoke_contains(e_flat.buf, e_flat.len, "Z0.200") != 1 { return 40 } 105 if smoke_contains(e_flat.buf, e_flat.len, "Z0.3") == 1 { return 41 } 106 if smoke_contains(e_flat.buf, e_flat.len, "Z0.4") == 1 { return 42 } 107 108 // --- (e) Bowl emitter buffer longer than flat (more digits per 109 // elevated Z value, or no Z change but still proves 110 // compensation activity) --- 111 if e_bowl.len < e_flat.len - 100 { return 50 } // bowl >= flat - small slack 112 113 return 0 114}