7 Commits

Author SHA1 Message Date
kellervater
4ebbd43426 fix(wallmount): orientation 2025-05-03 23:28:36 +02:00
kellervater
acd7403101 feat: wallmount 2025-05-03 12:15:09 +02:00
kellervater
b5508af9d3 fix(unimount): typo 2025-04-27 17:22:40 +02:00
kellervater
beb5f39722 feat(rackmount_ears): option to show actual ear distance 2025-04-27 12:56:06 +02:00
kellervater
a1a6777aea fix(rackmountears): sane defaults 2025-04-27 12:46:13 +02:00
Patrick Pötz
ebeb258d60 feat(rackmount_ears): asymetry slider (#13)
Added "insane" asymetry slider to create differently sized rackmount
ears.
2025-04-27 12:42:26 +02:00
kellervater
98e19efa60 feat: flexmount bracket 2025-04-27 11:28:55 +02:00
4 changed files with 205 additions and 75 deletions

View File

@@ -1,5 +0,0 @@
Fully customizable mount to be used with HomeRacker.
It's intended for non-standard devices you want to mount on HomeRacker.
Non-standard being devices which aren't originally meant to be mounted in 10 or 19" racks.
Devices might be PSU's for Raspberry Pis or small smart switches like on these pictures:
<TODO: insert pics here>

View File

@@ -1,10 +1,11 @@
// import BOSL2 // import BOSL2
include <BOSL2/std.scad> include <BOSL2/std.scad>
$fn=100;
/* [Hidden] */ /* [Hidden] */
// constants which shouldn't be changed // constants which shouldn't be changed
$fn=100;
// This is the HomeRacker base unit. don't change this! // This is the HomeRacker base unit. don't change this!
BASE_UNIT=15; // mm BASE_UNIT=15; // mm
@@ -19,23 +20,20 @@ LOCK_PIN_SIDE=4; // mm
// lock pin edge distance // lock pin edge distance
LOCK_PIN_EDGE_DISTANCE=5.5; // mm LOCK_PIN_EDGE_DISTANCE=5.5; // mm
/* [Base] */
// If set to true, the mount will be fitted to align with the 10/19 inch HomRacker rackmount kit.
//fit_to_rack=true;
/* [Device Measurements] */ /* [Device Measurements] */
// Width of the device in mm. Will determine how far apart the actual mounts are in width. // Width of the device in mm. Will determine how far apart the actual mounts are in width.
device_width=100 // [20:0.1:500] device_width=100; // [20:0.1:500]
; // TODO test for zero cube // TODO test for zero cube
// Depth of the device in mm. Will determine how far apart the actual mounts are in depth. // Depth of the device in mm. Will determine how far apart the actual mounts are in depth.
device_depth=99; // [54:0.1:500] device_depth=99; // [54:0.1:400]
// Height of the device in mm. Will determine how far apart the actual mounts are in height. // Height of the device in mm. Will determine how far apart the actual mounts are in height.
device_height=25.5; // [15:0.1:500] device_height=25.5; // [10:0.1:400]
/* [Bracket] */ /* [Bracket] */
// Defines the bracket thickness on top of the device. // Defines the bracket thickness on top of the device.
bracket_strength_top=7.5; // [4:0.1:20] bracket_strength_top=7.5; // [1:0.1:50]
bracket_strength_sides=7.5; // [4:0.1:20] // Defines how much the bracket will overlap to the sides of the device.
bracket_strength_sides=7.5; // [2:0.1:50]
// diff_width resembles the gap between the device and the mount. This gap will be filled with a cuboid // diff_width resembles the gap between the device and the mount. This gap will be filled with a cuboid
modulo_width=(BASE_UNIT - ( device_width + TOLERANCE ) % BASE_UNIT); modulo_width=(BASE_UNIT - ( device_width + TOLERANCE ) % BASE_UNIT);
@@ -58,6 +56,10 @@ module bracket(width,depth,height) {
outer_width=width+BASE_STRENGTH*2+TOLERANCE; outer_width=width+BASE_STRENGTH*2+TOLERANCE;
outer_depth=depth+BASE_STRENGTH*2+TOLERANCE; outer_depth=depth+BASE_STRENGTH*2+TOLERANCE;
outer_height=height+BASE_STRENGTH; outer_height=height+BASE_STRENGTH;
inner_width=width-bracket_strength_top*2+TOLERANCE;
inner_depth=depth-bracket_strength_top*2+TOLERANCE;
bottom_recess_height=height-bracket_strength_sides;
intersection(){ intersection(){
difference() { difference() {
// Outer // Outer
@@ -66,36 +68,33 @@ module bracket(width,depth,height) {
anchor=BOTTOM, anchor=BOTTOM,
chamfer=CHAMFER, edges=[TOP,FRONT,BACK,LEFT,RIGHT], except=[BOTTOM] chamfer=CHAMFER, edges=[TOP,FRONT,BACK,LEFT,RIGHT], except=[BOTTOM]
); );
// Top Skeleton // Top Skeleton (cut the middle to leave only a bracket to the sides)
cuboid( cuboid(
size=[width-bracket_strength_top,depth-bracket_strength_top,outer_height], size=[inner_width,inner_depth,outer_height],
anchor=BOTTOM, anchor=BOTTOM,
chamfer=-CHAMFER, edges=[TOP] chamfer=-CHAMFER, edges=[TOP]
); );
// Bottom Recess // Bottom Recess (cut the cube to leave only a top bracket)
cuboid( cuboid(
size=[outer_width,outer_depth,height-bracket_strength_sides], size=[outer_width,outer_depth,bottom_recess_height],
anchor=BOTTOM anchor=BOTTOM
); );
// Subtract Device to from bracket (cut the device into the bracket)
cuboid(
size=[width+TOLERANCE,depth+TOLERANCE,height+TOLERANCE/2],
anchor=BOTTOM
);
} }
// chamfer intersection for the outer bottom chamfer of the bracket
translate([0,0,outer_height]) translate([0,0,outer_height])
cuboid( cuboid(
size=[outer_width,outer_depth,bracket_strength_sides], size=[outer_width,outer_depth,bracket_strength_sides+BASE_STRENGTH-TOLERANCE/2],
anchor=TOP, anchor=TOP,
chamfer=CHAMFER, edges=[BOTTOM] chamfer=CHAMFER, edges=[BOTTOM]
); );
} }
} }
// device module adds TOLERANCE to the device size and creates a cuboid with the device size
// this is used to create the device in the mount and add TOLERANCE to the device size for spacing
module device(width,depth,height) {
// Device
cuboid(
size=[width+TOLERANCE,depth+TOLERANCE,height+TOLERANCE],
anchor=BOTTOM
);
}
// Mount // Mount
module mount(){ module mount(){
@@ -185,12 +184,8 @@ module mirror_mount_x_plane(){
// Assembly // Assembly
rotate([180,0,0]) rotate([180,0,0])
union() { union() {
bracket(device_width,device_depth,device_height);
difference() {
bracket(device_width,device_depth,device_height);
device(device_width,device_depth,device_height);
}
// Mount Right // Mount Right
mirror_mount_x_plane(); mirror_mount_x_plane();

View File

@@ -1,13 +1,28 @@
// import BOSL2 // import BOSL2
include <BOSL2/std.scad> include <BOSL2/std.scad>
/* [Hidden] */
$fn=100; $fn=100;
CAGE_BOLT_DIAMETER=6.5;
RACK_BORE_DISTANCE_VERTICAL=15.875;
RACK_BORE_DISTANCE_TOP_BOTTOM=6.35;
RACK_MOUNT_SURFACE_WIDTH=15.875;
RACK_BORE_DISTANCE_HORIZONTAL=RACK_MOUNT_SURFACE_WIDTH/2;
RACK_HEIGHT_UNIT=44.5; // mm
RACK_WIDTH_10_INCH_INNER=222.25; // mm
RACK_WIDTH_10_INCH_OUTER=254; // mm
RACK_WIDTH_19_INCH=482.6; // mm
/* [Base] */ /* [Base] */
// automatically chooses the tightest fit for the rackmount ears based on the device width. If true, rack_size will be ignored. // automatically chooses the tightest fit for the rackmount ears based on the device width. If true, rack_size will be ignored.
autosize=true; autosize=true;
// rack size in inches. If autosize is true, this value will be ignored. Only 10 and 19 inch racks are supported. // rack size in inches. If autosize is true, this value will be ignored. Only 10 and 19 inch racks are supported.
rack_size=10; // [10:10 inch,19:19 inch] rack_size=10; // [10:10 inch,19:19 inch]
// Asymetry Slider. CAUTION: there's no sanity check for this slider!
asymetry=0; // [-150:0.1:150]
// shows the distance between the rackmount ears considering the device width.
show_distance=false;
// Width of the device in mm. Will determine the width of the rackmount ears depending on rack_size. // Width of the device in mm. Will determine the width of the rackmount ears depending on rack_size.
device_width=201; device_width=201;
@@ -38,44 +53,18 @@ device_bore_rows=2;
// If true, the device will be aligned to the center of the rackmount ear. Otherwise it will be aligned to the bottom of the rackmount ear. // If true, the device will be aligned to the center of the rackmount ear. Otherwise it will be aligned to the bottom of the rackmount ear.
center_device_bore_alignment=false; center_device_bore_alignment=false;
/* [Derived] */
/* [CONSTANTS (shouldn't need to be changed)] */
CAGE_BOLT_DIAMETER=6.5;
CHAMFER=min(strength/3,0.5); CHAMFER=min(strength/3,0.5);
RACK_BORE_DISTANCE_VERTICAL=15.875;
RACK_BORE_DISTANCE_TOP_BOTTOM=6.35;
RACK_MOUNT_SURFACE_WIDTH=15.875;
RACK_BORE_DISTANCE_HORIZONTAL=RACK_MOUNT_SURFACE_WIDTH/2;
RACK_BORE_WIDTH=RACK_MOUNT_SURFACE_WIDTH-2*max(strength,2); RACK_BORE_WIDTH=RACK_MOUNT_SURFACE_WIDTH-2*max(strength,2);
RACK_HEIGHT_UNIT=44.5; // mm
RACK_HEIGHT_UNIT_COUNT=max(1,ceil(device_height/RACK_HEIGHT_UNIT)); RACK_HEIGHT_UNIT_COUNT=max(1,ceil(device_height/RACK_HEIGHT_UNIT));
RACK_HEIGHT=RACK_HEIGHT_UNIT_COUNT*RACK_HEIGHT_UNIT; // actual height calculated by height unit size x number of units RACK_HEIGHT=RACK_HEIGHT_UNIT_COUNT*RACK_HEIGHT_UNIT; // actual height calculated by height unit size x number of units
RACK_BORE_COUNT=RACK_HEIGHT_UNIT_COUNT*3; // 3 holes for each units RACK_BORE_COUNT=RACK_HEIGHT_UNIT_COUNT*3; // 3 holes for each units
RACK_WIDTH_10_INCH_INNER=222.25; // mm
RACK_WIDTH_10_INCH_OUTER=254; // mm
RACK_WIDTH_19_INCH=482.6; // mm
// Base assertions
module validate_params() {
valid_rack_sizes=[10,19];
if(autosize == false){
assert(rack_size == 10 || rack_size == 19, "Invalid rack_size. Only 10 and 19 inch racks are supported. Choose a valid one or set autosize to true.");
}
}
validate_params();
// Debug // Debug
echo("Height: ", RACK_HEIGHT); echo("Height: ", RACK_HEIGHT);
echo("Rack Bore Count: ", RACK_BORE_COUNT); echo("Rack Bore Count: ", RACK_BORE_COUNT);
// Calculate the width of the ear
function get_ear_width(device_width) =
device_width > RACK_WIDTH_10_INCH_INNER || autosize == false && rack_size == 19 ?
(RACK_WIDTH_19_INCH - device_width) / 2 :
(RACK_WIDTH_10_INCH_OUTER - device_width) / 2
;
rack_ear_width = get_ear_width(device_width);
function get_bore_depth(device_bore_margin_horizontal,device_bore_columns) = function get_bore_depth(device_bore_margin_horizontal,device_bore_columns) =
(device_bore_columns - 1) * device_bore_margin_horizontal (device_bore_columns - 1) * device_bore_margin_horizontal
@@ -92,7 +81,7 @@ device_screw_alignment = [strength,depth/2,device_screw_alignment_vertical];
module base_ear(width,strength,height) { module base_ear(width,strength,height) {
union() { union() {
// Front face // Front face
cuboid([rack_ear_width,strength,height],anchor=LEFT+BOTTOM+FRONT,chamfer=CHAMFER); cuboid([width,strength,height],anchor=LEFT+BOTTOM+FRONT,chamfer=CHAMFER);
// Side face // Side face
cuboid([strength,depth,height],anchor=LEFT+BOTTOM+FRONT,chamfer=CHAMFER); cuboid([strength,depth,height],anchor=LEFT+BOTTOM+FRONT,chamfer=CHAMFER);
} }
@@ -110,15 +99,36 @@ module screws_countersunk(length, diameter_head, length_head, diameter_shaft) {
// Assemble the rackmount ear // Assemble the rackmount ear
difference() { module rackmount_ear(asym=0){
ear_width_19_inch=(RACK_WIDTH_19_INCH - device_width) / 2 + asym;
ear_width_10_inch=(RACK_WIDTH_10_INCH_OUTER - device_width) / 2 + asym;
// Calculate the width of the ear
rack_ear_width = device_width > RACK_WIDTH_10_INCH_INNER || autosize == false && rack_size == 19 ?
ear_width_19_inch:
ear_width_10_inch
;
difference() { difference() {
// Create the base of the ear difference() {
base_ear(device_width,strength,RACK_HEIGHT); // Create the base of the ear
// Create the holes for the device screws base_ear(rack_ear_width,strength,RACK_HEIGHT);
screws_countersunk(length=strength,diameter_head=device_bore_hole_head_diameter,length_head=device_bore_hole_head_length,diameter_shaft=device_bore_hole_diameter); // Create the holes for the device screws
screws_countersunk(length=strength,diameter_head=device_bore_hole_head_diameter,length_head=device_bore_hole_head_length,diameter_shaft=device_bore_hole_diameter);
}
// Create the holes for the rackmount screws
zcopies(spacing=RACK_HEIGHT_UNIT,n=RACK_HEIGHT_UNIT_COUNT,sp=[0,0,0])
zcopies(spacing=RACK_BORE_DISTANCE_VERTICAL,n=3,sp=[rack_ear_width-RACK_BORE_DISTANCE_HORIZONTAL,0,RACK_BORE_DISTANCE_TOP_BOTTOM])
cuboid([RACK_BORE_WIDTH,strength+1,CAGE_BOLT_DIAMETER], rounding=CAGE_BOLT_DIAMETER/2, edges=[TOP+LEFT,TOP+RIGHT,BOTTOM+LEFT,BOTTOM+RIGHT], anchor=FRONT);
} }
// Create the holes for the rackmount screws }
zcopies(spacing=RACK_HEIGHT_UNIT,n=RACK_HEIGHT_UNIT_COUNT,sp=[0,0,0])
zcopies(spacing=RACK_BORE_DISTANCE_VERTICAL,n=3,sp=[rack_ear_width-RACK_BORE_DISTANCE_HORIZONTAL,0,RACK_BORE_DISTANCE_TOP_BOTTOM]) // Ear distance
cuboid([RACK_BORE_WIDTH,strength+1,CAGE_BOLT_DIAMETER], rounding=CAGE_BOLT_DIAMETER/2, edges=[TOP+LEFT,TOP+RIGHT,BOTTOM+LEFT,BOTTOM+RIGHT], anchor=FRONT); ear_distance = show_distance ? -device_width : -CAGE_BOLT_DIAMETER;
// Place the ears
rackmount_ear(asymetry);
x_mirror_plane = [1,0,0];
translate([ear_distance,0,0])
mirror(x_mirror_plane){
rackmount_ear(-asymetry);
} }

View File

@@ -0,0 +1,130 @@
// import BOSL2
include <BOSL2/std.scad>
/* [Hidden] */
// constants which shouldn't be changed
$fn=100;
// This is the HomeRacker base unit. don't change this!
BASE_UNIT=15; // mm
// Standard tolerance for the mount. This is a sane default.
TOLERANCE=0.2; // mm
// Base strength. This is a sane default.
BASE_STRENGTH=2; // mm
// Chamfer size. This is a sane default.
CHAMFER=1; // mm
// Lock Pin side length
LOCK_PIN_SIDE=4; // mm
// lock pin edge distance
LOCK_PIN_EDGE_DISTANCE=5.5; // mm
// lock pin chamfer
LOCK_PIN_CHAMFER=0.8; // mm
// Negative chamfer fix:
NEGATIVE_CHAMFER_TRANSLATE=0.01;
mount_units=2;
/* [Base] */
// TODO: enable mount units
// How many units shall the mount span across the support
//mount_units=2; //[2:1:10]
// Shall bores be countersunk or flathead
bore_type="flathead"; //[flathead,countersunk]
// Bore Shaft Diameter in mm
bore_shaft_diameter=4;
// Bore Head Diameter in mm (only relevant if bore_type=countersunk)
bore_head_diameter=8.5;
/* [Finetuning] */
// Defines the angle of the head rejuvenation. 90° is ISO standard. (only relevant if bore_type=countersunk)
countersunk_angle=90;
// Tolerance (in mm) for the bore holes. This is a sane default.
bore_tolerance=0.2;
// Calculate the head depth based on the countersunk angle.
head_depth = bore_head_diameter/2 - bore_shaft_diameter/2 * tan( countersunk_angle/2 );
echo("head_depth: ", head_depth);
connector_width_net=BASE_UNIT+TOLERANCE;
connector_width_gross=connector_width_net+BASE_STRENGTH*2;
//Wall Mount
mount_thickness=head_depth+BASE_STRENGTH;
mount_height=mount_units*BASE_UNIT;
mount_width=mount_units*2*BASE_UNIT+connector_width_gross;
// Support Interface
module mount(){
difference() {
union(){
cuboid([mount_width,mount_height,mount_thickness],anchor=CENTER+BOTTOM,chamfer=CHAMFER);
cuboid([connector_width_gross,mount_height,connector_width_gross],anchor=CENTER+BOTTOM,chamfer=CHAMFER);
}
translate([0,0,BASE_STRENGTH])
cuboid([connector_width_net,mount_height,connector_width_net],anchor=CENTER+BOTTOM);
}
}
// Lock pin Holes
module lock_pin_hole(){
// fix for negative chamfer. Otherwise the holes would not reach the surface
translate([0,0,-NEGATIVE_CHAMFER_TRANSLATE/2])
cuboid(
size=[LOCK_PIN_SIDE,LOCK_PIN_SIDE,connector_width_gross+0.01],
anchor=CENTER+BOTTOM,
chamfer=-LOCK_PIN_CHAMFER,edges=[TOP,BOTTOM]
);
}
module lock_pin_holes(){
// ycopies
ycopies(BASE_UNIT,mount_units)
// Create cross
union(){
lock_pin_hole();
yrot(90,cp=[0,0,connector_width_gross/2])
lock_pin_hole();
}
}
//// Bores
// Shafts
module bore(){
bore_shaft_radius=(bore_shaft_diameter+bore_tolerance)/2;
bore_head_radius=(bore_head_diameter+bore_tolerance)/2;
if (bore_type=="flathead") {
cylinder(r=bore_shaft_radius,h=mount_thickness,anchor=CENTER+BOTTOM);
} else if (bore_type=="countersunk") {
// Countersunk
union() {
// Head
translate([0,0,mount_thickness])
cylinder(r1=bore_shaft_radius,r2=bore_head_radius,h=head_depth,anchor=CENTER+TOP);
// Shaft
cylinder(r=bore_shaft_radius,h=mount_thickness,anchor=CENTER+BOTTOM);
}
}
}
bore_position_x=BASE_STRENGTH+BASE_UNIT/2+TOLERANCE/2+BASE_UNIT;
echo("bore_position_x: ", bore_position_x);
// Assembly
translate([0,0,BASE_UNIT]) rotate([90,0,0])
union(){
difference() {
mount();
translate([-bore_position_x,0,0])
bore();
translate([bore_position_x,0,0])
bore();
// Lock Pin Holes
lock_pin_holes();
}
}