-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcorkscrew filter.scad
More file actions
492 lines (437 loc) · 17.9 KB
/
corkscrew filter.scad
File metadata and controls
492 lines (437 loc) · 17.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
// This file is Copyright Robert L. Read 2025.
// Although Public Invention does everything open source, this file is an
// exception.
// MODIFIED by Gemini.
// VERSION 21: Corrected spacer alignment, helical void concentricity, and support visibility.
// --- Model Precision ---
high_res_fn = 150;
low_res_fn = 30;
$fn = $preview ? low_res_fn : high_res_fn;
// --- Main Parameters ---
num_bins = 3;
number_of_complete_revolutions = 12;
screw_OD_mm = 1.8;
screw_ID_mm = 1;
scale_ratio = 1.4;
// --- NEW PARAMETERS for Tube Filter ---
tube_od_mm = 32;
tube_wall_mm = 1;
insert_length_mm = 350/2;
oring_cross_section_mm = 1.5;
spacer_height_mm = 5;
adapter_hose_id_mm = 30;
support_rib_thickness_mm = 2.5;
support_revolutions = 4;
support_density = 4; // NEW: Number of support bundles around the circumference
flange_od = 20; // Outer diameter of the hose adapter flange
flange_height = 5; // Height of the hose adapter flange
// --- Tolerances & Fit ---
// Adjust these values based on your printer's calibration
tolerance_tube_fit = 0.2; // Clearance between the spacers and the inner wall of the tube
tolerance_socket_fit = 0.4; // Clearance between the screw and the spacer socket
tolerance_channel = 0.1; // Extra clearance for the airflow channel to prevent binding
// --- Config File ---
// Include a configuration file to override the default parameters below.
config_file = "default.scad";
include <config_file>
// --- CONTROL_VARIABLES ---
GENERATE_CFD_VOLUME = false; // NEW: Set to true to generate the internal fluid volume for CFD analysis
USE_MASTER_HELIX_METHOD = true; // NEW: Switch between assembly strategies
USE_MODULAR_FILTER = 1;
USE_HOSE_ADAPTER_CAP = 0;
THREADED_INLET = false ;
// Visual Options
ADD_HELICAL_SUPPORT = true;
USE_TRANSLUCENCY = false;
SHOW_O_RINGS = true;
// ===============================================================
// === Main Logic ================================================
// ===============================================================
if (GENERATE_CFD_VOLUME) {
tube_id = tube_od_mm - (2 * tube_wall_mm);
difference() {
// 1. Start with a solid cylinder representing the inner volume of the tube
cylinder(d = tube_id, h = insert_length_mm, center = true);
// 2. Subtract the entire filter assembly
ModularFilterAssembly(tube_id, insert_length_mm, num_bins, spacer_height_mm, oring_cross_section_mm);
}
} else {
// Logic to generate the solid parts for printing
if (USE_MODULAR_FILTER) {
if (USE_MASTER_HELIX_METHOD) {
// New, more robust assembly method
ModularFilterAssembly(tube_od_mm - (2 * tube_wall_mm), insert_length_mm, num_bins, spacer_height_mm, oring_cross_section_mm);
} else {
// Old method kept for debugging
ModularFilterAssembly_Rotational(tube_od_mm - (2 * tube_wall_mm), insert_length_mm, num_bins, spacer_height_mm, oring_cross_section_mm);
}
} else if (USE_HOSE_ADAPTER_CAP) {
HoseAdapterEndCap(tube_od_mm, adapter_hose_id_mm, oring_cross_section_mm);
}
}
// ===== Rob's definitions ======
// coordinate system: Gravity points in the -Z direction. +Z is up.abs
// The left-right dimentions is considered X. Air flow is in the positive Y
// direction. The is a right-handed coordinate system.
module Corkscrew(h,twist) {
rotate([90,0,0])
linear_extrude(height = h, center = true, convexity = 10, twist = twist, $fn = FN_RES)
translate([screw_OD_mm, 0, 0])
scale([1,scale_ratio])
circle(r = screw_OD_mm);
}
//module CorkscrewSlitKnife(twist,depth,num_bins) {
// de = depth/num_bins;
// yrot = 360*(1 / pitch_mm)*de;
//
// // Note: The computation of the slit angle
// // is a complicated. We create a triangle that
// // we linearly extruide (in the "polygon" state below.)
// D = 5*screw_OD_mm;
// W = D * tan(slit_knife_angle);
// // translate([10,0,0])
//// polygon(points = [[0,0],[D,-W],[D,W]]);
// echo("twist",twist);
// echo("W",W);
// echo("yrot",yrot);
// echo("de",de);
// echo("slit_axial_length_mm",slit_axial_length_mm);
// echo("screw_OD_mm",screw_OD_mm);
// echo("num_bins",num_bins);
// echo("depth",depth);
// echo("FN_RES",FN_RES);
// rotate([90,270,0])
// for(i = [0:num_bins -1]) {
// translate([0,0,-de])
// rotate([0,0,-yrot*(i+1)])
// translate([0,0,(i+1)*de])
// difference() {
// linear_extrude(height = depth, center = true, convexity = 10, twist = twist, $fn = FN_RES)
// translate([screw_OD_mm,0,0])
// rotate([0,0,0])
// polygon(points = [[0,0],[D,-W],[D,W]]);
// color("blue",0.3)
// translate([0,0,slit_axial_length_mm])
// cylinder(d=screw_ID_mm*8,h=depth,center=true);
// }
// }
//
//}
module CorkscrewSlitKnife(twist,depth,num_bins) {
de = depth/num_bins;
yrot = 360*(1 / pitch_mm)*de;
// Note: The computation of the slit angle
// is a complicated. We create a triangle that
// we linearly extruide (in the "polygon" state below.)
D = 20;
W = D * tan(slit_knife_angle);
echo("twist",twist);
echo("W",W);
echo("yrot",yrot);
echo("de",de);
echo("slit_axial_length_mm",slit_axial_length_mm);
echo("screw_OD_mm",screw_OD_mm);
echo("num_bins",num_bins);
echo("depth",depth);
echo("FN_RES",FN_RES);
echo("pitch_mm",pitch_mm);
// This should be the position of the helix at the "end"
// where we need to start the slit.
angle_of_knife_at_end = depth * 360 / pitch_mm;
echo("angle_of_knife_at_end",angle_of_knife_at_end);
rotate([90,0,0])
for(i = [0:num_bins -1]) {
translate([0,0,-de])
rotate([0,0,-yrot*(i+1)])
translate([0,0,(i+1)*de])
difference() {
linear_extrude(height = depth, center = true, convexity = 10, twist = twist, $fn = 200)
rotate([0,0,angle_of_knife_at_end])
translate([screw_OD_mm,0,0])
polygon(points = [[0,0],[D,-W],[D,W]]);
color("blue",0.3)
translate([0,0,slit_axial_length_mm])
cube([150,150,depth],center=true);
}
}
}
module CorkscrewWithVoid(h,twist) {
rotate([90,0,0])
linear_extrude(height = h, center = true, convexity = 10, twist = twist, $fn = FN_RES)
translate([screw_OD_mm, 0, 0])
difference() {
scale([1,scale_ratio])
circle(r = screw_OD_mm);
scale([1,scale_ratio])
circle(r = screw_ID_mm);
}
}
module CorkscrewVoid(h,twist) {
rotate([90,0,0])
linear_extrude(height = h, center = true, convexity = 10, twist = twist, $fn = FN_RES)
translate([screw_OD_mm, 0, 0])
scale([1,scale_ratio])
circle(r = screw_ID_mm);
}
module CorkscrewWithoutVoid(h,twist) {
echo("CorkscrewWithoutTwist");
echo(scale_ratio);
rotate([90,0,0])
linear_extrude(height = h, center = true, convexity = 10, twist = twist, $fn = FN_RES)
translate([screw_OD_mm, 0, 0])
scale([1,scale_ratio])
circle(r = screw_OD_mm);
}
module CorkscrewWithoutVoidExcess(h,twist) {
CorkscrewWithoutVoid(h*2,twist*2);
}
module CorkscrewInnerVoidVoidExcess(h,twist) {
CorkscrewVoid(h*2,twist*2);
}
module CorkscrewWithSlit(depth,numbins) {
echo("Filter_twist_degrees",filter_twist_degrees);
difference() {
CorkscrewWithVoid(depth,filter_twist_degrees);
echo("spud");
CorkscrewSlitKnife(filter_twist_degrees,depth,numbins);
}
}
// ===============================================================
// === Module Definitions ========================================
// ===============================================================
// Unified module to generate a helical shape with a given radius.
// This ensures the solid and void helices are generated with identical logic.
module HelicalShape(h, twist, r) {
echo(str("Generating HelicalShape: r=", r, ", center=[", screw_OD_mm, ", 0, 0]"));
linear_extrude(height = h, center = true, convexity = 10, twist = twist) {
translate([screw_OD_mm, 0, 0]) {
scale([1, scale_ratio]) {
circle(r = r);
}
}
}
}
// Creates the helical cutting tool for the void.
module CorkscrewVoid(h, twist) {
HelicalShape(h, twist, screw_ID_mm + tolerance_channel);
}
// This module creates the solid part of the helical screw.
module CorkscrewSolid(h, twist) {
HelicalShape(h, twist, screw_OD_mm);
}
// Assembles the complete filter using the "Master Helix" method for robust alignment.
module ModularFilterAssembly(tube_id, total_length, bin_count, spacer_h, oring_cs) {
total_spacer_length = (bin_count + 1) * spacer_h;
total_screw_length = total_length - total_spacer_length;
bin_length = total_screw_length / bin_count;
twist_rate = (360 * number_of_complete_revolutions) / total_length;
// --- Define Master Helices ---
module MasterSolidHelix() {
CorkscrewSolid(total_length + 2, twist_rate * (total_length + 2));
}
module MasterVoidHelix() {
CorkscrewVoid(total_length + 2, twist_rate * (total_length + 2));
}
// --- Main Assembly ---
difference() {
// 1. Union all the solid parts together
union() {
// 2. Create the screw segments
for (i = [0 : bin_count - 1]) {
z_pos = -total_length/2 + spacer_h + i * (bin_length + spacer_h) + bin_length/2;
rot = twist_rate * z_pos;
// Create the part at the origin, then move it into place.
translate([0, 0, z_pos]) rotate([0,0,rot]) {
intersection() {
// To use the master helix, we must "un-transform" it back to the origin.
rotate([0,0,-rot]) translate([0,0,-z_pos]) MasterSolidHelix();
// This cylinder is at the origin and defines the bin's extent.
cylinder(h = bin_length + 0.1, d = tube_id * 2, center=true);
}
}
}
// 3. Create the spacers
for (i = [0 : bin_count]) {
z_pos = -total_length/2 + i * (bin_length + spacer_h) + spacer_h/2;
rot = twist_rate * z_pos;
is_base = (i == 0);
is_top = (i == bin_count);
spacer_od = tube_id - tolerance_tube_fit;
// Create the part at the origin, then move it into place.
translate([0, 0, z_pos]) rotate([0,0,rot]) {
union() {
difference() {
cylinder(d = spacer_od, h = spacer_h, center=true);
// Un-transform the master helix to align with the cylinder at the origin
rotate([0,0,-rot]) translate([0,0,-z_pos]) MasterSolidHelix();
OringGroove_OD_Cutter(spacer_od, oring_cross_section_mm);
if (is_top && THREADED_INLET) {
translate([0, 0, spacer_h/2])
cylinder(d = 4*screw_OD_mm + tolerance_socket_fit, h = spacer_h/2 + 0.1);
}
if (is_base && THREADED_INLET) {
translate([0, 0, -spacer_h/2])
cylinder(d = 4*screw_OD_mm + tolerance_socket_fit, h = spacer_h/2 + 0.1);
}
}
if (SHOW_O_RINGS) {
OringVisualizer(spacer_od, oring_cross_section_mm);
}
if (ADD_HELICAL_SUPPORT && !is_top) {
// The support doesn't need to be rotated because the whole spacer is now rotated.
translate([0,0,spacer_h/2])
HelicalOuterSupport(spacer_od, bin_length, support_rib_thickness_mm, support_revolutions);
}
}
}
}
} // End of solid union
// 4. Subtract the Master Void from the entire solid assembly.
MasterVoidHelix();
}
}
// Creates a corkscrew with perfectly flat ends.
// It now takes a pre-calculated twist and the number of bins.
module FlatEndScrew(h, twist, num_bins) {
screw_outer_dia = 4 * screw_OD_mm;
intersection() {
difference() {
// Create the main helical body, add a small tolerance
CorkscrewSolid(h + 0.5, twist);
// Cut slits into the helix to separate the bins
CorkscrewSlitKnife(twist, h, num_bins);
}
// Use a cylinder intersection to ensure the ends are perfectly flat
cylinder(d = screw_outer_dia + 2, h = h, center = true);
}
}
// ... (Rest of modules are unchanged and included for completeness) ...
// This module creates the helical support structure between spacers.
// It now uses the master twist_rate to ensure its pitch matches the main helix.
module HelicalOuterSupport(target_dia, target_height, rib_thickness, twist_rate) {
twist_angle = twist_rate * target_height;
radius = target_dia / 2 - rib_thickness;
// The for-loop creates rotational symmetry based on support_density
for( i = [0:1:support_density-1]){
rotate([0,0,i*(360/support_density)]) {
// This union creates a bundle of 3 struts at different angles
union() {
// Left-handed helix
linear_extrude(height = target_height, center = false, convexity = 10, twist = -twist_angle)
rotate([0,0,0])
translate([radius,0,0])
circle(d=rib_thickness);
// Right-handed helix
linear_extrude(height = target_height, center = false, convexity = 10, twist = twist_angle)
rotate([0,0,120])
translate([radius,0,0])
circle(d=rib_thickness);
// Straight strut
linear_extrude(height = target_height, center = false, convexity = 10, twist = 0)
rotate([0,0,240])
translate([radius,0,0])
circle(d=rib_thickness);
}
}
}
}
module OringGroove_OD_Cutter(object_dia, oring_cs) {
groove_depth = oring_cs * 0.8;
groove_width = oring_cs * 1.1;
difference() {
cylinder(d = object_dia + 0.2, h = groove_width, center = true);
cylinder(d = object_dia - 2 * groove_depth, h = groove_width + 0.2, center = true);
}
}
module OringVisualizer(object_dia, oring_cs) {
groove_depth = oring_cs * 0.8;
torus_radius = object_dia/2 - groove_depth/2;
color("IndianRed")
rotate_extrude(convexity=10)
translate([torus_radius, 0, 0])
circle(r = oring_cs / 2);
}
// Creates the cutting tool for an internal O-ring groove.
module OringGroove_ID_Cutter(object_id, oring_cs) {
groove_depth = oring_cs * 0.8;
groove_width = oring_cs * 1.1;
rotate_extrude(convexity=10) {
translate([object_id/2 + groove_depth, 0, 0])
square([groove_depth, groove_width], center=true);
}
}
// Creates a hose adapter that caps the end of the tube.
module HoseAdapterEndCap(tube_od, hose_id, oring_cs) {
cap_inner_dia = tube_od + tolerance_tube_fit;
cap_wall = 3;
cap_outer_dia = cap_inner_dia + 2 * cap_wall;
cap_sleeve_height = 20;
cap_end_plate_thick = 3;
color(USE_TRANSLUCENCY ? [0.9, 0.9, 0.9, 0.5] : "Gainsboro")
difference() {
union() {
cylinder(r = cap_outer_dia / 2, h = cap_sleeve_height);
translate([0,0,cap_sleeve_height])
cylinder(r = cap_outer_dia/2, h = cap_end_plate_thick);
// Add the new flange for the hose barb
translate([0,0,cap_sleeve_height + cap_end_plate_thick])
cylinder(d = flange_od, h = flange_height);
}
translate([0, 0, -1])
cylinder(r = cap_inner_dia / 2, h = cap_sleeve_height + 2);
translate([0, 0, cap_sleeve_height / 2])
OringGroove_ID_Cutter(cap_inner_dia, oring_cs);
translate([0, 0, cap_sleeve_height])
cylinder(r = hose_id / 2, h = cap_end_plate_thick + 2);
}
translate([0, 0, cap_sleeve_height + cap_end_plate_thick])
barb(hose_id, 4);
}
module CorkscrewSlitKnife(twist,depth,num_bins) {
pitch_mm = twist == 0 ? 1e9 : depth / (twist / 360);
de = depth/num_bins;
yrot = 360*(1 / pitch_mm)*de;
slit_axial_length_mm = 1 + 0.5;
// The user wants only one slit per segment, so we will just run the loop once.
for(i = [0:0]) {
j = -(num_bins-1)/2 + i;
rotate([0,0,-yrot*(j+1)])
translate([0,0,(j+1)*de])
difference() {
linear_extrude(height = depth, center = true, convexity = 10, twist = twist)
translate([screw_OD_mm,0,0])
polygon(points = [[0,0],[4,-2],[4,2]]);
translate([0,0,slit_axial_length_mm])
cube([15,15,depth],center=true);
}
}
}
// --- Barb library modules ---
module barbnotch( inside_diameter ) {
cylinder(
h = inside_diameter * 1.0,
r1 = inside_diameter * 1.16 / 2, // Lip of the barb (wider)
r2 = inside_diameter * 0.85 / 2, // Ramp of the barb (narrower)
$fa = $preview ? 10 : 2,
$fs = $preview ? 2 : 0.5
);
}
module solidbarbstack( inside_diameter, count ) {
union() {
barbnotch( inside_diameter );
for (i=[2:count]) {
translate([0,0,(i-1) * inside_diameter * 0.9]) barbnotch( inside_diameter );
}
}
}
module barb( inside_diameter, count ) {
difference() {
solidbarbstack( inside_diameter, count );
translate([0,0,-0.3]) cylinder(
h = inside_diameter * (count + 1),
r = inside_diameter * 0.75 / 2,
$fa = $preview ? 10 : 2,
$fs = $preview ? 2 : 0.5
);
}
}