nx_print_sim_spaghetti_test.nx source
↩ module page · 139 lines · 5783 B
1// nx_print_sim_spaghetti_test.nx -- verify the simulator predicts
2// spaghetti / halfway-failure progenitors with real physics:
3// ENVELOPE_VIOLATION move past machine build volume
4// BED_CRASH Z below 0 (nozzle into bed)
5// TIPOVER_RISK tall-narrow geometry vs machine accel
6//
7// Operator directive 2026-05-20: "i want especially spaghetti or
8// where it prints halfway and fails etc to be predicted and to get
9// the loop really really hammered out"
10//
11// Each predictor: NO heuristic threshold; the substrate's existing
12// machine + material fields supply the physical limit.
13//
14// expect_exit: 0
15// license_tier: ORIGINAL
16
17import "nx_syscalls.nx"
18import "nx_machine_graph.nx"
19import "nx_material_profile.nx"
20import "nx_print_sim.nx"
21
22const Q14: i64 = 16384
23
24func main() -> i64 {
25 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3()
26 let pla: *NxMaterialProfile = nx_material_profile_generic_pla()
27 let lw: i64 = 6554 // 0.4mm Q14
28 let lh: i64 = 3277 // 0.2mm Q14
29
30 // ===== (a) ENVELOPE_VIOLATION =====
31 let s_env: *NxPrintSim = nx_print_sim_new(qidi, pla)
32 // Qidi build_x_mm = 325. Move to X = 400 mm = past envelope.
33 // Move first to safe spot, then drive past x bound.
34 nx_print_sim_extrude_move(s_env, 100 * Q14, 100 * Q14, Q14,
35 lw, lh, 50)
36 if s_env.n_issues != 0 { return 10 } // safe move = no issues
37
38 // Now drive 400mm in X (past 325 build volume).
39 nx_print_sim_extrude_move(s_env, 400 * Q14, 0, 0,
40 lw, lh, 50)
41 if s_env.n_issues < 1 { return 11 }
42 var saw_env: i64 = 0
43 var i_e: i64 = 0
44 while i_e < s_env.n_issues {
45 let ip: *NxPrintSimIssue = nx_print_sim_get_issue(s_env, i_e)
46 if ip.kind == NX_SIM_ISSUE_ENVELOPE_VIOLATION { saw_env = 1 }
47 i_e = i_e + 1
48 }
49 if saw_env != 1 { return 12 }
50
51 // ===== (b) BED_CRASH =====
52 let s_bed: *NxPrintSim = nx_print_sim_new(qidi, pla)
53 // Move XY safely first, then drive Z negative.
54 nx_print_sim_extrude_move(s_bed, 50 * Q14, 50 * Q14, Q14,
55 lw, lh, 50)
56 if s_bed.n_issues != 0 { return 20 }
57
58 // Drive Z to -2mm.
59 nx_print_sim_extrude_move(s_bed, 0, 0, 0 - 3 * Q14,
60 lw, lh, 50)
61 if s_bed.n_issues < 1 { return 21 }
62 var saw_crash: i64 = 0
63 var i_c: i64 = 0
64 while i_c < s_bed.n_issues {
65 let ip2: *NxPrintSimIssue = nx_print_sim_get_issue(s_bed, i_c)
66 if ip2.kind == NX_SIM_ISSUE_BED_CRASH {
67 saw_crash = 1
68 if ip2.magnitude_q14 <= 0 { return 22 } // positive depth
69 }
70 i_c = i_c + 1
71 }
72 if saw_crash != 1 { return 23 }
73
74 // ===== (c) TIPOVER_RISK -- tall narrow geometry =====
75 //
76 // Simulate a 10mm × 10mm base × 200mm tall column.
77 // base_radius = 5mm, z_height = 200mm. Ratio z_height/base_r = 40.
78 // 2g/accel = 2 × 9810 / 5000 = 3.92. 40 > 3.92 -> TIPOVER.
79 let s_tall: *NxPrintSim = nx_print_sim_new(qidi, pla)
80 // Move to (50, 50, 0) start; then build bbox via 4 corner moves at
81 // various z heights to establish a 10x10x200 footprint.
82 nx_print_sim_extrude_move(s_tall, 50 * Q14, 50 * Q14, Q14,
83 lw, lh, 50)
84 nx_print_sim_extrude_move(s_tall, 10 * Q14, 0, 0,
85 lw, lh, 50)
86 nx_print_sim_extrude_move(s_tall, 0, 10 * Q14, 0,
87 lw, lh, 50)
88 nx_print_sim_extrude_move(s_tall, 0 - 10 * Q14, 0, 0,
89 lw, lh, 50)
90 // Now Z up 200mm
91 nx_print_sim_extrude_move(s_tall, 0, 0 - 10 * Q14, 200 * Q14,
92 lw, lh, 50)
93 let n_before: i64 = s_tall.n_issues
94 nx_print_sim_finalize(s_tall)
95 let n_after: i64 = s_tall.n_issues
96 if n_after <= n_before { return 30 } // finalize raised at least 1 issue
97 var saw_tip: i64 = 0
98 var i_t: i64 = 0
99 while i_t < s_tall.n_issues {
100 let ip3: *NxPrintSimIssue = nx_print_sim_get_issue(s_tall, i_t)
101 if ip3.kind == NX_SIM_ISSUE_TIPOVER_RISK {
102 saw_tip = 1
103 if ip3.magnitude_q14 <= 0 { return 31 }
104 }
105 i_t = i_t + 1
106 }
107 if saw_tip != 1 { return 32 }
108
109 // ===== (d) Safe geometry: WIDE base, short height -- no TIPOVER =====
110 //
111 // Qidi max_accel = 20000 mm/s² (aggressive CoreXY). Threshold:
112 // z_height < 2g × base_radius / accel = base_radius × 0.981
113 //
114 // 200mm × 200mm base × 50mm tall:
115 // base_radius = 100mm; threshold = 98.1mm; z_height = 50mm < 98.1 -> SAFE
116 let s_safe: *NxPrintSim = nx_print_sim_new(qidi, pla)
117 nx_print_sim_extrude_move(s_safe, 50 * Q14, 50 * Q14, Q14,
118 lw, lh, 50)
119 nx_print_sim_extrude_move(s_safe, 200 * Q14, 0, 0,
120 lw, lh, 50)
121 nx_print_sim_extrude_move(s_safe, 0, 200 * Q14, 0,
122 lw, lh, 50)
123 nx_print_sim_extrude_move(s_safe, 0 - 200 * Q14, 0, 0,
124 lw, lh, 50)
125 nx_print_sim_extrude_move(s_safe, 0, 0 - 200 * Q14, 50 * Q14,
126 lw, lh, 50)
127 let n_safe_before: i64 = s_safe.n_issues
128 nx_print_sim_finalize(s_safe)
129 let n_safe_after: i64 = s_safe.n_issues
130 // 50mm tall on 100mm base_radius @ 20000 accel -> ratio 0.5 < 0.981 -> SAFE
131 if n_safe_after != n_safe_before { return 40 }
132
133 // ===== (e) Sealed-enum range checks for ALL new constants =====
134 if nx_sim_issue_is_valid(NX_SIM_ISSUE_ENVELOPE_VIOLATION) != 1 { return 50 }
135 if nx_sim_issue_is_valid(NX_SIM_ISSUE_BED_CRASH) != 1 { return 51 }
136 if nx_sim_issue_is_valid(NX_SIM_ISSUE_TIPOVER_RISK) != 1 { return 52 }
137
138 return 0
139}