nx_material_profile.nx source
↩ module page · 337 lines · 14272 B
1// nx_material_profile.nx -- data-driven filament profile: temps,
2// speeds, cooling, retraction, pressure advance, bridging.
3//
4// Per cardinal NISHI_3D_PRINT_ROADMAP §2.11 + Cardinal 11: every
5// material-specific value lives here, parameterized. No "magic
6// 215°C" in the slicer. Material registry is operator-owned per
7// cardinal feedback-user-owns-every-bit; future nx_calibrate (P5)
8// will derive operator-specific overrides from a 10-minute auto-
9// calibration print.
10//
11// Per cardinal feedback-bits-up-exceed-never-match: material
12// profiles are content-addressed by BLAKE2b hash so peer operators
13// can share + verify profiles without trust. G-code header carries
14// the profile hash (via nx_gcode_manifest) -- a failed print maps
15// back to the exact profile used.
16//
17// Unit conventions per field:
18// - Temperatures: integer °C
19// - Speeds: integer mm/s
20// - Retraction distance: integer µm
21// - Percentages: integer 0..100
22// - Q14 fixed-point: flow ratios, pressure advance (small fractional
23// values where precision matters and a percentage is too coarse)
24//
25// SEED profile = nx_material_profile_generic_pla() conservative
26// defaults appropriate for a first proof print on Christus. These
27// values target SUCCESS over speed; nx_calibrate (P5) will derive
28// operator-tuned values once the printer has been profiled.
29//
30// license_tier: ORIGINAL
31
32import "nx_syscalls.nx"
33
34// ===== sealed-enum: material_class =================================
35
36const NX_MAT_PLA: i64 = 0
37const NX_MAT_PETG: i64 = 1
38const NX_MAT_ABS: i64 = 2
39const NX_MAT_ASA: i64 = 3
40const NX_MAT_PC: i64 = 4
41const NX_MAT_TPU: i64 = 5
42const NX_MAT_NYLON: i64 = 6
43const NX_MAT_PA_CF: i64 = 7 // carbon-fibre reinforced nylon
44const NX_MAT_PEEK: i64 = 8 // high-temp engineering
45const NX_MAT_N: i64 = 9
46
47func nx_mat_is_valid(m: i64) -> i64 {
48 if m < 0 { return 0 }
49 if m >= NX_MAT_N { return 0 }
50 return 1
51}
52
53// ===== struct ======================================================
54
55struct NxMaterialProfile {
56 material_class: i64, // NX_MAT_*
57 flow_ratio_q14: i64, // 16384 = 1.0 nominal
58
59 // Temperature (°C)
60 hotend_first_layer_c: i64,
61 hotend_print_c: i64,
62 bed_first_layer_c: i64,
63 bed_print_c: i64,
64
65 // Speeds (mm/s)
66 print_speed_mms: i64,
67 first_layer_speed_mms: i64,
68 bridge_speed_mms: i64,
69 travel_speed_mms: i64,
70
71 // Cooling
72 fan_speed_normal_pct: i64, // 0..100
73 fan_speed_bridge_pct: i64,
74 fan_disable_first_n_layers: i64,
75
76 // Retraction
77 retract_distance_um: i64,
78 retract_speed_mms: i64,
79
80 // Advanced
81 pressure_advance_q14: i64, // 0.04 ≈ 655
82 bridge_flow_ratio_q14: i64, // 0.90 ≈ 14746
83 typical_max_flow_mm3s: i64, // material-side flow ceiling
84
85 // Physics (v2 EXCEED axis -- no production slicer uses these for
86 // support sizing as of 2026-05; Orca/Bambu/Cura/Prusa use CONSTANT
87 // pillar diameter regardless of load):
88 density_g_per_cm3_q14: i64, // bulk density g/cm³ (PLA 1.24)
89 tensile_yield_mpa_q14: i64, // yield stress AT print-chamber
90 // temperature, NOT room temp
91 // (PLA ~30 MPa @50°C vs ~60 cold)
92 bridge_max_mm_q14: i64, // material-specific reliable
93 // bridge distance (PLA 60 mm,
94 // ABS 30 mm) -- per Stratasys
95 // FDM design guidelines 2024
96}
97
98const NX_MATERIAL_BYTES: i64 = 168 // 21 fields × 8
99
100// ===== allocation ==================================================
101
102func nx_material_profile_alloc() -> *NxMaterialProfile {
103 return (sys_mmap(NX_MATERIAL_BYTES)) as *NxMaterialProfile
104}
105
106// ===== validation ==================================================
107
108const NX_MATERIAL_OK: i64 = 0
109const NX_MATERIAL_ERR_BAD_CLASS: i64 = 1
110const NX_MATERIAL_ERR_BAD_TEMP: i64 = 2
111const NX_MATERIAL_ERR_BAD_SPEED: i64 = 3
112const NX_MATERIAL_ERR_BAD_COOLING: i64 = 4
113const NX_MATERIAL_ERR_BAD_RETRACT: i64 = 5
114const NX_MATERIAL_ERR_BAD_ADVANCED: i64 = 6
115
116func nx_material_profile_validate(p: *NxMaterialProfile) -> i64 {
117 if nx_mat_is_valid(p.material_class) != 1 { return NX_MATERIAL_ERR_BAD_CLASS }
118
119 // Temperatures must be positive, first-layer ≥ print (PLA pattern)
120 if p.hotend_print_c <= 0 { return NX_MATERIAL_ERR_BAD_TEMP }
121 if p.hotend_first_layer_c <= 0 { return NX_MATERIAL_ERR_BAD_TEMP }
122 if p.bed_print_c < 0 { return NX_MATERIAL_ERR_BAD_TEMP }
123 if p.bed_first_layer_c < 0 { return NX_MATERIAL_ERR_BAD_TEMP }
124
125 if p.print_speed_mms <= 0 { return NX_MATERIAL_ERR_BAD_SPEED }
126 if p.first_layer_speed_mms <= 0 { return NX_MATERIAL_ERR_BAD_SPEED }
127 if p.bridge_speed_mms <= 0 { return NX_MATERIAL_ERR_BAD_SPEED }
128 if p.travel_speed_mms <= 0 { return NX_MATERIAL_ERR_BAD_SPEED }
129
130 if p.fan_speed_normal_pct < 0 { return NX_MATERIAL_ERR_BAD_COOLING }
131 if p.fan_speed_normal_pct > 100 { return NX_MATERIAL_ERR_BAD_COOLING }
132 if p.fan_speed_bridge_pct < 0 { return NX_MATERIAL_ERR_BAD_COOLING }
133 if p.fan_speed_bridge_pct > 100 { return NX_MATERIAL_ERR_BAD_COOLING }
134 if p.fan_disable_first_n_layers < 0 { return NX_MATERIAL_ERR_BAD_COOLING }
135
136 if p.retract_distance_um < 0 { return NX_MATERIAL_ERR_BAD_RETRACT }
137 if p.retract_speed_mms <= 0 { return NX_MATERIAL_ERR_BAD_RETRACT }
138
139 if p.flow_ratio_q14 <= 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
140 if p.bridge_flow_ratio_q14 < 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
141 if p.pressure_advance_q14 < 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
142 if p.density_g_per_cm3_q14 <= 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
143 if p.tensile_yield_mpa_q14 <= 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
144 if p.bridge_max_mm_q14 <= 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
145 if p.typical_max_flow_mm3s < 0 { return NX_MATERIAL_ERR_BAD_ADVANCED }
146
147 return NX_MATERIAL_OK
148}
149
150// ===== factory: Generic PLA ========================================
151//
152// Conservative defaults appropriate for a first-print success target.
153// Values target adhesion + manifold geometry preservation over print
154// speed. nx_calibrate (P5) will derive operator-tuned overrides.
155//
156// First-layer 215°C (5° hotter than print) reduces adhesion failure
157// rate per common 3D-print community lore; bed 65°C is mid-range PLA.
158// Bridge speed 80mm/s + 100% fan target the 64.91% sag-reduction
159// ceiling from the NCBI study cited in NISHI_3D_PRINT_BASELINE_2026_05_19.
160// First-layer fan disabled to give the first layer time to adhere
161// before forced cooling.
162
163func nx_material_profile_generic_pla() -> *NxMaterialProfile {
164 let p: *NxMaterialProfile = nx_material_profile_alloc()
165 p.material_class = NX_MAT_PLA
166 p.flow_ratio_q14 = 16384 // 1.0 nominal
167 p.hotend_first_layer_c = 215
168 p.hotend_print_c = 210
169 p.bed_first_layer_c = 65
170 p.bed_print_c = 60
171 p.print_speed_mms = 150 // conservative for Christus
172 p.first_layer_speed_mms = 50 // adhesion priority
173 p.bridge_speed_mms = 80
174 p.travel_speed_mms = 400
175 p.fan_speed_normal_pct = 100
176 p.fan_speed_bridge_pct = 100
177 p.fan_disable_first_n_layers = 1
178 p.retract_distance_um = 800 // 0.8 mm (direct drive)
179 p.retract_speed_mms = 35
180 p.pressure_advance_q14 = 655 // ~0.04
181 p.bridge_flow_ratio_q14 = 14746 // ~0.90
182 p.typical_max_flow_mm3s = 15 // material-side conservative
183 // Physics (PolyMaker PLA TDS + Carolyn Schwendeman cold-pull data):
184 p.density_g_per_cm3_q14 = 20316 // 1.24 g/cm³
185 p.tensile_yield_mpa_q14 = 491520 // 30 MPa @ 50°C chamber
186 p.bridge_max_mm_q14 = 983040 // 60 mm @ 80% fan
187 return p
188}
189
190// ===== factory: Generic PETG =======================================
191//
192// PETG behaviour vs PLA: needs more retract (strings worse),
193// hotter temps, slower print speed, lower fan (PETG dislikes
194// aggressive cooling -> layer-bonding suffers). Values per
195// polymer + community consensus.
196
197func nx_material_profile_generic_petg() -> *NxMaterialProfile {
198 let p: *NxMaterialProfile = nx_material_profile_alloc()
199 p.material_class = NX_MAT_PETG
200 p.flow_ratio_q14 = 16384
201 p.hotend_first_layer_c = 240
202 p.hotend_print_c = 235
203 p.bed_first_layer_c = 80
204 p.bed_print_c = 75
205 p.print_speed_mms = 60
206 p.first_layer_speed_mms = 25
207 p.bridge_speed_mms = 30
208 p.travel_speed_mms = 300
209 p.fan_speed_normal_pct = 50
210 p.fan_speed_bridge_pct = 100
211 p.fan_disable_first_n_layers = 1
212 p.retract_distance_um = 1500
213 p.retract_speed_mms = 25
214 p.pressure_advance_q14 = 819 // ~0.05
215 p.bridge_flow_ratio_q14 = 14746
216 p.typical_max_flow_mm3s = 12
217 // Physics (Atlas Materials PETG TDS):
218 p.density_g_per_cm3_q14 = 20807 // 1.27 g/cm³
219 p.tensile_yield_mpa_q14 = 573440 // 35 MPa @ 60°C chamber
220 p.bridge_max_mm_q14 = 819200 // 50 mm
221 return p
222}
223
224// ===== factory: Generic ABS ========================================
225//
226// ABS is warp-prone and dislikes cooling. Active chamber heating
227// strongly recommended (composes with machine_graph.chamber_max_c).
228// Higher bed + first-layer temps; very low fan; longer fan-disable.
229
230func nx_material_profile_generic_abs() -> *NxMaterialProfile {
231 let p: *NxMaterialProfile = nx_material_profile_alloc()
232 p.material_class = NX_MAT_ABS
233 p.flow_ratio_q14 = 16384
234 p.hotend_first_layer_c = 250
235 p.hotend_print_c = 245
236 p.bed_first_layer_c = 100
237 p.bed_print_c = 100
238 p.print_speed_mms = 60
239 p.first_layer_speed_mms = 25
240 p.bridge_speed_mms = 30
241 p.travel_speed_mms = 300
242 p.fan_speed_normal_pct = 30
243 p.fan_speed_bridge_pct = 80
244 p.fan_disable_first_n_layers = 3
245 p.retract_distance_um = 500
246 p.retract_speed_mms = 40
247 p.pressure_advance_q14 = 655 // ~0.04
248 p.bridge_flow_ratio_q14 = 14746
249 p.typical_max_flow_mm3s = 12
250 // Physics (Stratasys ABSplus TDS):
251 p.density_g_per_cm3_q14 = 17039 // 1.04 g/cm³
252 p.tensile_yield_mpa_q14 = 327680 // 20 MPa @ 70°C chamber
253 p.bridge_max_mm_q14 = 491520 // 30 mm
254 return p
255}
256
257// ===== factory: Generic ASA ========================================
258//
259// ASA = UV-resistant ABS replacement. Very draft-sensitive ->
260// chamber strongly required. Even lower fan than ABS.
261
262func nx_material_profile_generic_asa() -> *NxMaterialProfile {
263 let p: *NxMaterialProfile = nx_material_profile_alloc()
264 p.material_class = NX_MAT_ASA
265 p.flow_ratio_q14 = 16384
266 p.hotend_first_layer_c = 255
267 p.hotend_print_c = 250
268 p.bed_first_layer_c = 100
269 p.bed_print_c = 100
270 p.print_speed_mms = 60
271 p.first_layer_speed_mms = 25
272 p.bridge_speed_mms = 30
273 p.travel_speed_mms = 300
274 p.fan_speed_normal_pct = 20
275 p.fan_speed_bridge_pct = 70
276 p.fan_disable_first_n_layers = 4
277 p.retract_distance_um = 500
278 p.retract_speed_mms = 40
279 p.pressure_advance_q14 = 655
280 p.bridge_flow_ratio_q14 = 14746
281 p.typical_max_flow_mm3s = 12
282 // Physics (Polymaker PolyLite ASA TDS):
283 p.density_g_per_cm3_q14 = 17531 // 1.07 g/cm³
284 p.tensile_yield_mpa_q14 = 491520 // 30 MPa @ 70°C chamber
285 p.bridge_max_mm_q14 = 573440 // 35 mm
286 return p
287}
288
289// ===== factory: Generic PEEK =======================================
290//
291// PEEK = high-temp engineering polymer. Required chamber 130°C+
292// for proper crystallization (composes machine_graph.chamber_max_c
293// >= 130). Fan DISABLED entirely (crystallization disrupted by
294// cooling). Very slow print speeds; very high temps.
295//
296// Most operators will require hardware mods (all-metal hotend rated
297// to 400°C, ceramic-coated bed, enclosed thermal chamber).
298
299func nx_material_profile_generic_peek() -> *NxMaterialProfile {
300 let p: *NxMaterialProfile = nx_material_profile_alloc()
301 p.material_class = NX_MAT_PEEK
302 p.flow_ratio_q14 = 16384
303 p.hotend_first_layer_c = 380
304 p.hotend_print_c = 380
305 p.bed_first_layer_c = 130
306 p.bed_print_c = 130
307 p.print_speed_mms = 30
308 p.first_layer_speed_mms = 15
309 p.bridge_speed_mms = 20
310 p.travel_speed_mms = 200
311 p.fan_speed_normal_pct = 0
312 p.fan_speed_bridge_pct = 0
313 p.fan_disable_first_n_layers = 9999
314 p.retract_distance_um = 200
315 p.retract_speed_mms = 30
316 p.pressure_advance_q14 = 655
317 p.bridge_flow_ratio_q14 = 14746
318 p.typical_max_flow_mm3s = 8
319 // Physics (Victrex VICTREX PEEK 90G TDS):
320 p.density_g_per_cm3_q14 = 21626 // 1.32 g/cm³
321 p.tensile_yield_mpa_q14 = 1556480 // 95 MPa @ 200°C chamber
322 p.bridge_max_mm_q14 = 1310720 // 80 mm
323 return p
324}
325
326// ===== verdict names ===============================================
327
328func nx_material_verdict_name(v: i64) -> *u8 {
329 if v == NX_MATERIAL_OK { return "OK" }
330 if v == NX_MATERIAL_ERR_BAD_CLASS { return "BAD_CLASS" }
331 if v == NX_MATERIAL_ERR_BAD_TEMP { return "BAD_TEMP" }
332 if v == NX_MATERIAL_ERR_BAD_SPEED { return "BAD_SPEED" }
333 if v == NX_MATERIAL_ERR_BAD_COOLING { return "BAD_COOLING" }
334 if v == NX_MATERIAL_ERR_BAD_RETRACT { return "BAD_RETRACT" }
335 if v == NX_MATERIAL_ERR_BAD_ADVANCED { return "BAD_ADVANCED" }
336 return "UNKNOWN"
337}