- Move legacy FreeCAD files to v1/ - Add OpenSCAD programmatic CAD designs - Add README and AGENTS.md documentation - Add .gitignore - Update firmware to v2 architecture
554 lines
18 KiB
OpenSCAD
554 lines
18 KiB
OpenSCAD
/* [Siren General Parameters] */
|
|
siren_diameter = 125; // Base diameter
|
|
siren_height = 50; // Height of the rotor
|
|
number_of_ports = 5; // Number of ports
|
|
tolerance = 2; // Tolerance between stator and rotor
|
|
pressure_zone = 0.4; // Percentage of diameter
|
|
round_radius = 4; // Rounding of top/bottom
|
|
$fn = $preview ? 32 : 128; // Number of fragments
|
|
|
|
/* [Stator Parameters] */
|
|
stator_wall_thickness = 8; // Stator wall thickness
|
|
number_of_mounting_holes = 4; // Number of mounting holes
|
|
screw_diameter = 3.2; // Diameter of screws - M3 clearance hole (3.2mm diameter)
|
|
screw_bore_diameter = 6.5;
|
|
screw_insert_diameter = 4;
|
|
screw_bore_depth = 3;
|
|
screw_length = 10 - (stator_wall_thickness - screw_bore_depth);
|
|
stator_screw_offset = siren_diameter/2 - stator_wall_thickness/2; //distance to screws
|
|
|
|
/* [Rotor Parameters] */
|
|
rotor_wall_thickness = 3; // Rotor wall thickness
|
|
hub_height = 5;
|
|
hub_diameter = 12;
|
|
blade_angle = 15;
|
|
port_height = siren_height - (rotor_wall_thickness * 2) - (tolerance * 2); // Height of the port
|
|
|
|
/* [Motor Parameters] */
|
|
motor_shaft_diameter = 8; // Diameter of the motor body
|
|
motor_frame_diameter = 60;
|
|
motor_diameter = 28; // Diameter of the motor body
|
|
motor_height = 45;
|
|
magnet_diameter = 7;
|
|
motor_screw_x_offset = 9.5;
|
|
motor_screw_y_offset = 8;
|
|
motor_screw_offset = 8;
|
|
motor_frame_screw_offset = motor_frame_diameter/2 - stator_wall_thickness/2; //distance to screws
|
|
|
|
// helper functions
|
|
module ports(diameter, height, ports) {
|
|
radius = diameter / 2;
|
|
angle = 180 / ports;
|
|
|
|
rotate([0, 0, 180 / ports])
|
|
for (i = [0:360/ports:360]) {
|
|
rotate([0, 0, i])
|
|
linear_extrude(height)
|
|
polygon(concat(
|
|
[[0, 0]], // Center point
|
|
[for (j = [0 : $fn])
|
|
[radius * cos(angle * j / $fn),
|
|
radius * sin(angle * j / $fn)]]
|
|
));
|
|
}
|
|
}
|
|
|
|
module column(outer_diameter, inner_diameter, height) {
|
|
difference(){
|
|
// Outer cylinder
|
|
cylinder(d = outer_diameter, h = height);
|
|
// Subtract inner cylinder
|
|
cylinder(d = inner_diameter, h = height);
|
|
}
|
|
}
|
|
|
|
// Linear Interpolation
|
|
function lerp(a, b, t) = a * (1 - t) + b * t;
|
|
|
|
// Arc between points function
|
|
function arc_between_points(p1, p2, height, steps=20) =
|
|
[for(t = [0:1/steps:1])
|
|
let(
|
|
x = lerp(p1.x, p2.x, t),
|
|
y = lerp(p1.y, p2.y, t),
|
|
// Parabolic arc height calculation
|
|
arc_height = height * (1 - pow(2*t-1, 2))
|
|
)
|
|
[x, y + arc_height]
|
|
];
|
|
|
|
function bezier_curve(t, p0, p1, p2, p3, p4) =
|
|
pow(1-t, 4) * p0 +
|
|
4 * pow(1-t, 3) * t * p1 +
|
|
6 * pow(1-t, 2) * pow(t, 2) * p2 +
|
|
4 * (1-t) * pow(t, 3) * p3 +
|
|
pow(t, 4) * p4;
|
|
|
|
function curved_polygon(points, steps, x_shift, y_shift) =
|
|
let(
|
|
left_curve = [for (t = [0 : 1/steps : 1])
|
|
bezier_curve(t, points[0], points[1], points[2], points[3], points[4])
|
|
],
|
|
right_curve = [for (pt = left_curve)
|
|
[pt[0] + x_shift, pt[1] + y_shift]
|
|
]
|
|
)
|
|
concat(left_curve, [for (i = [len(right_curve)-1 : -1 : 0]) right_curve[i]]);
|
|
|
|
module stator(diameter, height, p_height, ports) {
|
|
difference() {
|
|
|
|
// Create column
|
|
column(diameter, diameter - (stator_wall_thickness * 2), height);
|
|
|
|
// Subtract ports
|
|
translate([0, 0, (height - p_height) / 2])
|
|
ports(diameter, p_height, number_of_ports);
|
|
|
|
// 4 M3 mounting holes
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
// Top
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, -1])
|
|
cylinder(d = screw_insert_diameter, h = screw_length + 1);
|
|
|
|
// Bottom
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, height - screw_length]) // Adjust position as needed
|
|
cylinder(d = screw_insert_diameter, h = screw_length + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
module impeller_blades_straight(rotor_inner_diameter, rotor_height) {
|
|
difference() {
|
|
intersection() {
|
|
// Column with full diameter
|
|
cylinder(d = rotor_inner_diameter, h = rotor_height);
|
|
|
|
// Blades
|
|
union() {
|
|
for (i = [0:360/number_of_ports:360]) {
|
|
rotate([0, 0, i - 90])
|
|
translate([0, rotor_inner_diameter / 2, 0])
|
|
rotate([0, 0, blade_angle])
|
|
|
|
translate([-rotor_wall_thickness, -(rotor_inner_diameter / 2), 0])
|
|
linear_extrude(height = rotor_height, twist = 0, slices=360)
|
|
square([rotor_wall_thickness, diameter]);
|
|
}
|
|
}
|
|
}
|
|
// Subtract core cylinder
|
|
translate([0, 0, -1])
|
|
cylinder(d = diameter * pressure_zone, h = height + 10);
|
|
}
|
|
}
|
|
|
|
module impeller_blade(radius, rotor_height){
|
|
// Generate points
|
|
points1 = arc_between_points([0, -hub_diameter / 2], [radius, 0], -blade_angle);
|
|
points2 = [for(p = [len(points1)-1:-1:0]) points1[p] - [0, -rotor_wall_thickness]];
|
|
|
|
// Create the blade by combining top and bottom points
|
|
linear_extrude(height = rotor_height)
|
|
polygon(concat(
|
|
points1,
|
|
points2
|
|
));
|
|
}
|
|
|
|
module impeller_blades_curved(radius, rotor_height){
|
|
difference() {
|
|
|
|
union() {
|
|
// Rotate and create blades
|
|
for (i = [0:360/number_of_ports:360]) {
|
|
rotate([0, 0, i])
|
|
impeller_blade(radius, rotor_height);
|
|
}
|
|
}
|
|
|
|
// Subtract core cylinder
|
|
/*
|
|
rounding_radius = 25;
|
|
translate([0, 0, rotor_wall_thickness + rounding_radius])
|
|
minkowski() {
|
|
// Original cylinder, reduced by twice the rounding radius
|
|
cylinder(
|
|
d = diameter * pressure_zone - (2 * rounding_radius),
|
|
h = 1000
|
|
);
|
|
|
|
// Sphere for rounding
|
|
sphere(r = rounding_radius);
|
|
}
|
|
*/
|
|
|
|
top_rounding_radius = 5;
|
|
bottom_rounding_radius = rotor_height / 2 - 1;
|
|
translate([0, 0, rotor_height - top_rounding_radius - 0])
|
|
union(){
|
|
difference() {
|
|
// Column with diameter = 2 * top_rounding_radius
|
|
cylinder(d = (diameter * pressure_zone) + (top_rounding_radius * 2), h = top_rounding_radius + 10);
|
|
|
|
// Top torus
|
|
rotate_extrude()
|
|
translate([((diameter * pressure_zone) + (top_rounding_radius * 2)) / 2, 0, 0])
|
|
circle(r = top_rounding_radius);
|
|
}
|
|
|
|
rotate([180, 0, 0])
|
|
minkowski() {
|
|
// Original cylinder, reduced by twice the rounding radius
|
|
cylinder(
|
|
d = (diameter * pressure_zone) - (2 * bottom_rounding_radius),
|
|
h = rotor_height - bottom_rounding_radius - (top_rounding_radius * 2) + 2
|
|
);
|
|
|
|
// Sphere for rounding
|
|
sphere(r = bottom_rounding_radius);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
module rotor() {
|
|
rotor_diameter = diameter - (stator_wall_thickness * 2) - (tolerance * 2);
|
|
rotor_height = height - (tolerance * 2);
|
|
rotor_inner_diameter = rotor_diameter - (rotor_wall_thickness * 2);
|
|
|
|
difference() {
|
|
union(){
|
|
difference() {
|
|
// Outer cylinder
|
|
cylinder(d = rotor_diameter, h = rotor_height);
|
|
|
|
// Subtract inner cylinder
|
|
translate([0, 0, rotor_wall_thickness])
|
|
cylinder(d = rotor_inner_diameter, h = rotor_height + 2);
|
|
|
|
// Subtract ports
|
|
translate([0, 0, -tolerance])
|
|
ports();
|
|
}
|
|
|
|
/*
|
|
// Central column for hub added after subtraction
|
|
translate([0, 0, rotor_wall_thickness])
|
|
cylinder(d = hub_diameter, h = hub_height);
|
|
*/
|
|
|
|
// Add blades
|
|
impeller_blades_curved(rotor_inner_diameter / 2, rotor_height);
|
|
}
|
|
|
|
translate([0, 0, -10])
|
|
cylinder(d = hub_diameter, h = 100);
|
|
|
|
translate([0, 0, 0])
|
|
hub_attachment(0.2);
|
|
|
|
/*
|
|
// Subtract motor shaft hole
|
|
translate([0, 0, -10])
|
|
intersection(){
|
|
cylinder(d = motor_shaft_diameter, h = 100);
|
|
cube([motor_shaft_diameter, motor_shaft_diameter-1, 100], center = true);
|
|
}
|
|
*/
|
|
|
|
}
|
|
}
|
|
|
|
module hub() {
|
|
// Subtract motor shaft hole
|
|
difference(){
|
|
cylinder(d = hub_diameter, h = hub_height + 3);
|
|
translate([0, 0, -1])
|
|
intersection(){
|
|
cylinder(d = motor_shaft_diameter, h = 100);
|
|
cube([motor_shaft_diameter, motor_shaft_diameter-1, 100], center = true);
|
|
};
|
|
cylinder(d = motor_shaft_diameter, h = 2);
|
|
}
|
|
hub_attachment();
|
|
}
|
|
|
|
module hub_attachment(aug = 0) {
|
|
outer_diameter = hub_diameter + (tolerance * 6) + (aug * 2);
|
|
mid_diameter = hub_diameter + (tolerance * 2) + (aug * 2);
|
|
inner_diameter = outer_diameter - (tolerance * 2) - (aug * 2);
|
|
difference(){
|
|
column(outer_diameter, inner_diameter, rotor_wall_thickness);
|
|
translate([0, 0, -10])
|
|
ports();
|
|
}
|
|
translate([0, 0, rotor_wall_thickness])
|
|
column(outer_diameter, mid_diameter, rotor_wall_thickness);
|
|
column(mid_diameter, hub_diameter - (aug * 2), rotor_wall_thickness * 2);
|
|
}
|
|
|
|
module stator_top() {
|
|
difference() {
|
|
// Rounded top
|
|
intersection() {
|
|
// Unrounded full cylinder
|
|
cylinder(d = diameter, h = stator_wall_thickness);
|
|
|
|
// Add Minkowski rounded version
|
|
minkowski() {
|
|
cylinder(h = stator_wall_thickness - round_radius, d = diameter - round_radius * 2);
|
|
sphere(r = round_radius);
|
|
}
|
|
}
|
|
|
|
// Subtract central opening for pressure zone
|
|
translate([0, 0, -1])
|
|
cylinder(d = diameter * pressure_zone, h = stator_wall_thickness + 2);
|
|
|
|
// Subtract mounting holes for stator
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
// Subtract screw hole
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, -1]) // Adjusted position
|
|
cylinder(d = screw_diameter, h = stator_wall_thickness + 2);
|
|
|
|
// Subtract counterbore
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, stator_wall_thickness - screw_bore_depth]) // Adjusted position
|
|
cylinder(d = screw_bore_diameter, h = stator_wall_thickness);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
module stator_bottom() {
|
|
difference() {
|
|
// Rounded bottom
|
|
intersection() {
|
|
// Unrounded full cylinder
|
|
cylinder(d = diameter, h = stator_wall_thickness);
|
|
|
|
// Minkowski rounded version
|
|
minkowski() {
|
|
cylinder(h = stator_wall_thickness - round_radius, d = diameter - round_radius * 2);
|
|
sphere(r = round_radius);
|
|
}
|
|
}
|
|
|
|
// Subtract central hole for motor
|
|
translate([0, 0, -1])
|
|
cylinder(d = motor_diameter + (tolerance * 2), h = stator_wall_thickness + 5);
|
|
|
|
// Subtract mounting holes for stator
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
// Subtract screw hole
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, -1]) // Adjusted position
|
|
cylinder(d = screw_diameter, h = stator_wall_thickness + 2);
|
|
|
|
// Subtract counterbore
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, stator_wall_thickness - screw_bore_depth]) // Adjusted position
|
|
cylinder(d = screw_bore_diameter, h = stator_wall_thickness);
|
|
}
|
|
|
|
// Subtract mounting holes for motor frame
|
|
rotate([180, 0, 0])
|
|
translate([0, 0, -stator_wall_thickness])
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
// Subtract screw hole
|
|
rotate([0, 0, i])
|
|
translate([motor_frame_screw_offset, 0, -1]) // Adjusted position
|
|
cylinder(d = screw_diameter, h = stator_wall_thickness + 2);
|
|
|
|
// Subtract counterbore
|
|
rotate([0, 0, i])
|
|
translate([motor_frame_screw_offset, 0, stator_wall_thickness - screw_bore_depth]) // Adjusted position
|
|
cylinder(d = screw_bore_diameter, h = stator_wall_thickness);
|
|
}
|
|
}
|
|
}
|
|
|
|
module motor_frame() {
|
|
difference() {
|
|
intersection(){
|
|
union(){
|
|
|
|
// Rounded base
|
|
rotate([180, 0, 0])
|
|
translate([0, 0, -stator_wall_thickness])
|
|
intersection() {
|
|
// Unrounded full cylinder
|
|
cylinder(d = motor_frame_diameter, h = stator_wall_thickness);
|
|
|
|
// Minkowski rounded version
|
|
minkowski() {
|
|
cylinder(h = stator_wall_thickness - round_radius, d = motor_frame_diameter - round_radius * 2);
|
|
sphere(r = round_radius);
|
|
}
|
|
}
|
|
|
|
translate([0, 0, stator_wall_thickness])
|
|
// Outer cylinder
|
|
cylinder(d = motor_frame_diameter, h = motor_height);
|
|
}
|
|
|
|
// Outer cylinder
|
|
cylinder(d = motor_frame_diameter, h = motor_height);
|
|
}
|
|
|
|
// Subtract inner cylinder
|
|
translate([0, 0, stator_wall_thickness])
|
|
cylinder(d = motor_frame_diameter - (stator_wall_thickness * 2), h = motor_height + 2);
|
|
|
|
// Subtract ports
|
|
rotate([0, 0, -90/number_of_mounting_holes])
|
|
ports(number_of_mounting_holes);
|
|
|
|
intersection(){
|
|
difference() {
|
|
// Inner cylinder (subtract)
|
|
translate([0, 0, -1])
|
|
cylinder(d = (motor_frame_screw_offset * 2) - stator_wall_thickness, h = motor_height + 2);
|
|
|
|
translate([0, 0, 0])
|
|
cylinder(d = (motor_screw_y_offset * 2) + stator_wall_thickness, h = motor_height + 2);
|
|
}
|
|
|
|
// Subtract ports
|
|
translate([0, 0, -stator_wall_thickness - 2])
|
|
rotate([0, 0, -90/number_of_mounting_holes])
|
|
ports(number_of_mounting_holes);
|
|
}
|
|
|
|
// Subtract mounting holes for frame
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
rotate([0, 0, i])
|
|
translate([motor_frame_screw_offset, 0, motor_height - screw_length - 5]) // Adjusted position
|
|
cylinder(d = screw_insert_diameter, h = 15);
|
|
}
|
|
|
|
// Subtract magnet hole
|
|
translate([0, 0, -10])
|
|
cylinder(d = magnet_diameter + (tolerance * 2), h = 100);
|
|
|
|
// Subtract mounting holes for motor
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
rotate([0, 0, i]) {
|
|
// Use modulo to alternate between x and y offsets
|
|
motor_screw_offset = (floor(i / (360/number_of_mounting_holes)) % 2 == 0) ?
|
|
motor_screw_x_offset : motor_screw_y_offset;
|
|
|
|
translate([motor_screw_offset, 0, -1])
|
|
cylinder(d = screw_diameter, h = 15);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module base() {
|
|
union(){
|
|
difference(){
|
|
rotate_extrude() {
|
|
polygon(curved_polygon(
|
|
points = [
|
|
[diameter / 3, motor_height],
|
|
[motor_frame_diameter / 2, motor_height - 5],
|
|
[motor_frame_diameter / 2, 0],
|
|
[motor_frame_diameter / 2, -10],
|
|
[diameter / 3, -15]
|
|
],
|
|
steps = 100,
|
|
x_shift = -stator_wall_thickness,
|
|
y_shift = 0
|
|
));
|
|
}
|
|
// Subtract ports
|
|
translate([0, 0, -25])
|
|
rotate([0, 0, -90/number_of_mounting_holes])
|
|
ports(number_of_mounting_holes, 45);
|
|
|
|
/*
|
|
translate([0, 0, -19])
|
|
// Subtract mounting holes for stator
|
|
for (i = [0:360/number_of_mounting_holes:360]) {
|
|
// Subtract screw hole
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, -1]) // Adjusted position
|
|
cylinder(d = screw_diameter, h = stator_wall_thickness + 2);
|
|
|
|
// Subtract counterbore
|
|
rotate([0, 0, i])
|
|
translate([stator_screw_offset, 0, stator_wall_thickness - screw_bore_depth]) // Adjusted position
|
|
cylinder(d = screw_bore_diameter, h = stator_wall_thickness);
|
|
}
|
|
*/
|
|
}
|
|
motor_frame();
|
|
translate([0, 0, -23])
|
|
stator_top();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
stator(siren_diameter, siren_height, port_height, number_of_ports);
|
|
//translate([diameter - 10, 0, tolerance])
|
|
/*
|
|
intersection(){
|
|
cylinder(h = 30, d = 30);
|
|
rotor();
|
|
}
|
|
*/
|
|
|
|
rotor();
|
|
/*
|
|
translate([diameter - 10, 0, height + 10])
|
|
hub_attachment();
|
|
*/
|
|
/*
|
|
translate([0, 0, height + 2])
|
|
stator_top();
|
|
rotate([180, 0, 0])
|
|
translate([0, 0, 2])
|
|
stator_bottom();
|
|
//translate([0, 0, -motor_height - 10])
|
|
//motor_frame();
|
|
translate([0, 0, -motor_height - 15])
|
|
base();
|
|
*/
|
|
|
|
/*
|
|
stator();
|
|
translate([diameter + 10, 0, tolerance])
|
|
rotor();
|
|
translate([diameter * 2 + 10, 0, height + 2])
|
|
stator_top();
|
|
rotate([180, 0, 0])
|
|
translate([-diameter - 10, 0, 2])
|
|
stator_bottom();
|
|
translate([-diameter * 2 - 10, 0, -motor_height - 10])
|
|
motor_frame();
|
|
translate([-diameter * 3 - 10, 0, -motor_height - 10])
|
|
base();
|
|
*/
|
|
|
|
/*
|
|
// for testing
|
|
difference(){
|
|
cylinder(h=5.5, d=20);
|
|
translate([-5, 0, -1])
|
|
cylinder(h=10, d=screw_diameter);
|
|
translate([-5, 0, 3])
|
|
cylinder(h=5, d=screw_bore_diameter);
|
|
|
|
translate([5, 0, -1])
|
|
cylinder(h=10, d=screw_insert_diameter);
|
|
}
|
|
*/
|
|
|