update stl build dir structure
37
README.md
@ -14,44 +14,53 @@ See the [renders for difference parametric profiles here](media/renders)
|
|||||||
|
|
||||||
## Assembly
|
## Assembly
|
||||||
|
|
||||||
Pre-generated STLs for roughly 200mm^3, and 100mm^3 rack frames can be found in [stl/rack](stl/rack).
|
Pre-generated STLs for roughly 200mm^3 (mini), 170mm^3 (micro), and 100mm^3 (nano) rack frames can be found in [stl](stl).
|
||||||
These STLs are generated from the files in [rack/print](rack/print), and [rack-mount/print](rack-mount/print) - further information about printing these parts
|
These STLs are generated from the files in [rack/print](rack/print), and [rack-mount/print](rack-mount/print) - further information about printing these parts
|
||||||
(supports, orientation) can be found in their respective `.scad` files.
|
(supports, orientation) can be found in these files.
|
||||||
|
|
||||||
### Assembly Instructions
|
### Assembly Instructions
|
||||||
Please see [the assembly README here](./assembly)
|
Please see [the assembly README here](./assembly-guide)
|
||||||
|
|
||||||
### Required Tools:
|
### Required Tools:
|
||||||
- 3d FDM Printer - build size requirements depend on configure rack size. (TODO explain)
|
- 3d FDM Printer - build size requirements depend on configured rack profile
|
||||||
- M3 Allen Key
|
- M3 Allen Key
|
||||||
- M4 Allen Key
|
- M4 Allen Key
|
||||||
|
|
||||||
### BOM - Single Rack:
|
### BOM - Single Rack:
|
||||||
|
|
||||||
| Item | Name | Quantity | Comment |
|
| Item | Name | Quantity | Comment |
|
||||||
|----------------------------------------------------------|---------------------------|----------|---------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------|---------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| <img src="media/bom/m3_8.gif" height="60" width="72"> | M3x8 FHCS | 16 | Spares are useful and inexpensive. If you plan on eventually stacking multiple racks together don't hesitate to get more. |
|
| <img src="media/bom/fhcs_medium.gif" height="60" width="72"> | M3x12 FHCS | 20 | Spares are useful and inexpensive. If you plan on eventually stacking multiple racks together don't hesitate to get a lot more. |
|
||||||
| <img src="media/bom/m3_10.gif" height="60" width="72"> | M3x10 FHCS | 4 | ☝️ |
|
| <img src="media/bom/fhcs_long.gif" height="60" width="72"> | M3x16 FHCS | 16 | ☝️ |
|
||||||
| <img src="media/bom/m3_12.gif" height="60" width="72"> | M3x12 FHCS | 16 | ☝️ |
|
| <img src="media/bom/hex_nut.gif" height="60" width="72"> | M3 hex nut | 36 | ☝️ |
|
||||||
| <img src="media/bom/m3_hex.gif" height="60" width="72"> | M3 hex nut | 36 | ☝️ |
|
|
||||||
| <img src="media/bom/dowel.gif" height="60" width="72"> | 3x10 steel dowel pin | 4 | 3mm diameter, 10mm height |
|
| <img src="media/bom/dowel.gif" height="60" width="72"> | 3x10 steel dowel pin | 4 | 3mm diameter, 10mm height |
|
||||||
| <img src="media/bom/magnet.gif" height="60" width="72"> | 6x2 neodymium disc magnet | 8 | 6mm diameter, 2mm height |
|
| <img src="media/bom/magnet.gif" height="60" width="72"> | 6x2 neodymium disc magnet | 8 | 6mm diameter, 2mm height |
|
||||||
|
| | super glue | | |
|
||||||
|
|
||||||
#### Notes:
|
#### Notes:
|
||||||
|
|
||||||
- Omitted actual plastic for printing. Any conventional 3d printing plastic should do (PLA, PETG, ABS),
|
- Omitted actual plastic for printing. Any conventional 3d printing plastic should do (PLA, PETG, ABS),
|
||||||
but beware of PLA's thermal limits. Higher infill is recommended for all parts.
|
but beware of PLA's thermal limits. Higher infill is recommended for all parts.
|
||||||
- For joining two racks, you will need 8 M3 hex nuts, and 8 M3x10 FHCS (TODO confirm)
|
- For joining two racks, you will need 8 M3 hex nuts, and 8 M3x12 FHCS.
|
||||||
- Main front rails use M4 hex nuts and screws.
|
- Main front rails use M4 hex nuts and screws.
|
||||||
- Side rails are mounted using M3 hex nuts and screws
|
- Side rails are mounted using M3 hex nuts and screws.
|
||||||
|
|
||||||
|
|
||||||
## Configuring + Generating STLs
|
## Configuring + Generating STLs
|
||||||
|
A python script: `rbuild.py` is provided to generate different project stls.
|
||||||
WIP
|
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
- `openscad` cli command (Only runs on Linux)
|
- `openscad` cli command (Only runs on Linux)
|
||||||
- `python3`
|
- `python3`
|
||||||
|
|
||||||
`python3 rbuild.py --help`
|
### Examples:
|
||||||
|
Generate all project files for the `mini` profile:
|
||||||
|
|
||||||
|
`python3 rbuild.py -b all -c micro`
|
||||||
|
|
||||||
|
Generate specific part:
|
||||||
|
|
||||||
|
`python3 rbuild.py -b yBar`
|
||||||
|
|
||||||
|
Generated stls are put into the `stl/` directories. The actual variable values for different profiles can be found in
|
||||||
|
[rack/profiles.scad](rack/profiles.scad).
|
||||||
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 410 KiB |
|
Before Width: | Height: | Size: 470 KiB |
|
Before Width: | Height: | Size: 348 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 203 KiB |
@ -8,7 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
include <./profiles.scad>
|
include <./profiles.scad>
|
||||||
|
|
||||||
|
// Manually set this variable to toggle profiles
|
||||||
profileName = "micro";
|
profileName = "micro";
|
||||||
|
|
||||||
profile = getProfile(profileName);
|
profile = getProfile(profileName);
|
||||||
|
|
||||||
defaultLayerHeight = 0.3;
|
defaultLayerHeight = 0.3;
|
||||||
|
|||||||
@ -66,6 +66,8 @@ module connectorPositive(on, to) {
|
|||||||
onYBarToXBarPositive();
|
onYBarToXBarPositive();
|
||||||
} else if (on == "yBar" && to == "basePlate") {
|
} else if (on == "yBar" && to == "basePlate") {
|
||||||
onYBarBasePlateConnectorPositive();
|
onYBarBasePlateConnectorPositive();
|
||||||
|
} else if (on == "xBar" && to == "yBar") {
|
||||||
|
onXBarToYBarPositive();
|
||||||
} else if (on == "mainRail" && to == "yBar") {
|
} else if (on == "mainRail" && to == "yBar") {
|
||||||
onMainRailYBarConnectorPositive();
|
onMainRailYBarConnectorPositive();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,16 @@ module onXBarToYBarNegative() {
|
|||||||
translate(v = [-xBarSideThickness, y, z])
|
translate(v = [-xBarSideThickness, y, z])
|
||||||
rotate(a = [0, -90, 0])
|
rotate(a = [0, -90, 0])
|
||||||
counterSunkHead_N(rackFrameScrewType, screwExtension=inf10, headExtension=inf10);
|
counterSunkHead_N(rackFrameScrewType, screwExtension=inf10, headExtension=inf10);
|
||||||
|
|
||||||
|
// lugs for snap fit and hold in place
|
||||||
|
translate(v=[-0.1,26,13.5])
|
||||||
|
lug();
|
||||||
|
}
|
||||||
|
|
||||||
|
module onXBarToYBarPositive() {
|
||||||
|
// lugs for snap fit and hold in place
|
||||||
|
translate(v=[-0.1,26,2])
|
||||||
|
lug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +56,10 @@ module onYBarToXBarNegative() {
|
|||||||
rotate(a = [180, 0, 0])
|
rotate(a = [180, 0, 0])
|
||||||
rotate(a = [0, 90, 0])
|
rotate(a = [0, 90, 0])
|
||||||
hexNutPocket_N("m3", openSide=false, backSpace=5);
|
hexNutPocket_N("m3", openSide=false, backSpace=5);
|
||||||
|
|
||||||
|
// lugs for snap fit and hold in place
|
||||||
|
translate(v=[-0.1,26,2])
|
||||||
|
lug();
|
||||||
}
|
}
|
||||||
|
|
||||||
module onYBarToXBarPositive() {
|
module onYBarToXBarPositive() {
|
||||||
@ -64,8 +78,22 @@ module onYBarToXBarPositive() {
|
|||||||
backFaceLength = 5,
|
backFaceLength = 5,
|
||||||
backFaceScale = 1.2
|
backFaceScale = 1.2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// lugs for snap fit and hold in place
|
||||||
|
translate(v=[-0.1,26,13.5])
|
||||||
|
lug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
xBarConnectorToYBarConnectorTrans = mirror(v=[1,0,0]);
|
xBarConnectorToYBarConnectorTrans = mirror(v=[1,0,0]);
|
||||||
yBarConnectorToXBarConnectorTrans = mirror(v=[-1,0,0]);
|
yBarConnectorToXBarConnectorTrans = mirror(v=[-1,0,0]);
|
||||||
|
|
||||||
|
|
||||||
|
module lug() {
|
||||||
|
hull() {
|
||||||
|
sphere(r=0.5);
|
||||||
|
|
||||||
|
translate(v=[0,2,0])
|
||||||
|
sphere(r=0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,26 +12,29 @@
|
|||||||
|
|
||||||
_profileConfigs = [
|
_profileConfigs = [
|
||||||
["default", [
|
["default", [
|
||||||
["maxUnitWidth", 205],
|
["maxUnitWidth", 170],
|
||||||
["maxUnitDepth", 205],
|
["maxUnitDepth", 180],
|
||||||
|
["numRailScrews", 18],
|
||||||
["screwDiff", 10],
|
["screwDiff", 10],
|
||||||
["numRailScrews", 20],
|
|
||||||
["mainRailScrewType", "m4"],
|
["mainRailScrewType", "m4"],
|
||||||
["mainRailSideMountScrewType", "m4"],
|
["mainRailSideMountScrewType", "m4"],
|
||||||
["rackFrameScrewType", "m3"],
|
["rackFrameScrewType", "m3"],
|
||||||
["baseRoundness", 5],
|
["baseRoundness", 5],
|
||||||
]],
|
]],
|
||||||
["micro", [
|
["nano", [
|
||||||
["maxUnitWidth", 105],
|
["maxUnitWidth", 105],
|
||||||
["maxUnitDepth", 105],
|
["maxUnitDepth", 105],
|
||||||
["numRailScrews", 10],
|
["numRailScrews", 10]
|
||||||
["baseRoundness", 5]
|
]],
|
||||||
|
["micro", [
|
||||||
|
["maxUnitWidth", 170],
|
||||||
|
["maxUnitDepth", 180],
|
||||||
|
["numRailScrews", 18]
|
||||||
]],
|
]],
|
||||||
["mini", [
|
["mini", [
|
||||||
["maxUnitWidth", 205],
|
["maxUnitWidth", 205],
|
||||||
["maxUnitDepth", 205],
|
["maxUnitDepth", 205],
|
||||||
["numRailScrews", 20],
|
["numRailScrews", 20]
|
||||||
["baseRoundness", 5]
|
|
||||||
]]
|
]]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
51
rbuild.py
@ -4,21 +4,22 @@ import argparse
|
|||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from stl import mesh, stl
|
|
||||||
|
|
||||||
|
|
||||||
# For actual dimensions, please see profiles.scad.
|
# For actual dimensions, please see profiles.scad.
|
||||||
class BuildSizeConfig:
|
class BuildSizeConfig:
|
||||||
|
NANO = 'nano'
|
||||||
MINI = 'mini'
|
MINI = 'mini'
|
||||||
MICRO = 'micro'
|
MICRO = 'micro'
|
||||||
DEFAULT = 'default'
|
|
||||||
|
|
||||||
|
|
||||||
RACK_BUILD_DIR = './rack/print'
|
RACK_BUILD_DIR = './rack/print'
|
||||||
RACK_MOUNT_BUILD_DIR = './rack-mount/print'
|
RACK_MOUNT_BUILD_DIR = './rack-mount/print'
|
||||||
|
|
||||||
RACK_BUILD_TARGET_DIR = './stl/rack'
|
BUILD_PARENT_DIR = './stl'
|
||||||
RACK_MOUNT_BUILD_TARGET_DIR = './stl/rack-mount'
|
|
||||||
|
RACK_BUILD_TARGET_SUB_DIR = 'rack'
|
||||||
|
RACK_MOUNT_BUILD_TARGET_SUB_DIR = 'rack-mount'
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -43,8 +44,8 @@ def main():
|
|||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-c',
|
'-c',
|
||||||
default='default',
|
default=BuildSizeConfig.MINI,
|
||||||
choices=[BuildSizeConfig.MINI, BuildSizeConfig.MICRO, BuildSizeConfig.DEFAULT],
|
choices=[BuildSizeConfig.NANO, BuildSizeConfig.MINI, BuildSizeConfig.MICRO],
|
||||||
help='Build size config profile. This will determine the size of the rack you wish to generate. '
|
help='Build size config profile. This will determine the size of the rack you wish to generate. '
|
||||||
'For actual dimensions, please see profiles.scad.'
|
'For actual dimensions, please see profiles.scad.'
|
||||||
)
|
)
|
||||||
@ -58,13 +59,22 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
def run_build(build_var, config_var):
|
def run_build(build_var, config_var):
|
||||||
|
|
||||||
|
rackBuildDirFull = os.path.join(BUILD_PARENT_DIR, config_var, RACK_BUILD_TARGET_SUB_DIR)
|
||||||
|
rackMountBuildDirFull = os.path.join(BUILD_PARENT_DIR, config_var, RACK_MOUNT_BUILD_TARGET_SUB_DIR)
|
||||||
|
|
||||||
|
if not os.path.exists(rackBuildDirFull):
|
||||||
|
os.makedirs(rackBuildDirFull)
|
||||||
|
|
||||||
|
if not os.path.exists(rackMountBuildDirFull):
|
||||||
|
os.makedirs(rackMountBuildDirFull)
|
||||||
|
|
||||||
if build_var == 'all':
|
if build_var == 'all':
|
||||||
for dir_file in os.listdir(RACK_BUILD_DIR):
|
for dir_file in os.listdir(RACK_BUILD_DIR):
|
||||||
build_single(RACK_BUILD_DIR, RACK_BUILD_TARGET_DIR, dir_file, config_var)
|
build_single(RACK_BUILD_DIR, rackBuildDirFull, dir_file, config_var)
|
||||||
|
|
||||||
for dir_file in os.listdir(RACK_MOUNT_BUILD_DIR):
|
for dir_file in os.listdir(RACK_MOUNT_BUILD_DIR):
|
||||||
build_single(RACK_MOUNT_BUILD_DIR, RACK_MOUNT_BUILD_TARGET_DIR, dir_file, config_var)
|
build_single(RACK_MOUNT_BUILD_DIR, rackMountBuildDirFull, dir_file, config_var)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
filename_rack = find_rack(build_var)
|
filename_rack = find_rack(build_var)
|
||||||
@ -75,10 +85,10 @@ def run_build(build_var, config_var):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if filename_rack:
|
if filename_rack:
|
||||||
build_single(RACK_BUILD_DIR, RACK_BUILD_TARGET_DIR, filename_rack, config_var)
|
build_single(RACK_BUILD_DIR, rackBuildDirFull, filename_rack, config_var)
|
||||||
|
|
||||||
if filename_rack_mount:
|
if filename_rack_mount:
|
||||||
build_single(RACK_MOUNT_BUILD_DIR, RACK_MOUNT_BUILD_TARGET_DIR, filename_rack, config_var)
|
build_single(RACK_MOUNT_BUILD_DIR, rackMountBuildDirFull, filename_rack, config_var)
|
||||||
|
|
||||||
|
|
||||||
def build_single(build_dir, target_dir, filename, config):
|
def build_single(build_dir, target_dir, filename, config):
|
||||||
@ -86,14 +96,12 @@ def build_single(build_dir, target_dir, filename, config):
|
|||||||
openscad_args = construct_openscad_args(build_dir, target_dir, filename, config)
|
openscad_args = construct_openscad_args(build_dir, target_dir, filename, config)
|
||||||
run_openscad(openscad_args)
|
run_openscad(openscad_args)
|
||||||
|
|
||||||
convert_text_stl_to_binary(openscad_args[1])
|
|
||||||
|
|
||||||
|
|
||||||
def construct_openscad_args(build_dir, target_dir, filename, config):
|
def construct_openscad_args(build_dir, target_dir, filename, config):
|
||||||
source = os.path.join(build_dir, filename)
|
source = os.path.join(build_dir, filename)
|
||||||
target = os.path.join(target_dir, os.path.splitext(filename)[0] + '.stl')
|
target = os.path.join(target_dir, os.path.splitext(filename)[0] + '.stl')
|
||||||
|
|
||||||
return ['-o', target, source]
|
return ['-D', 'profileName=\"' + config + '\"', '-o', target, source]
|
||||||
|
|
||||||
|
|
||||||
def find_rack(filename):
|
def find_rack(filename):
|
||||||
@ -121,24 +129,15 @@ def find_scad_file(directory, filename):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def run_openscad(options=['-h']):
|
def run_openscad(options):
|
||||||
command = ['openscad', '-q'] + options
|
command = ['openscad', '-q', '--export-format', 'binstl'] + options
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(command, universal_newlines=True, stderr=subprocess.DEVNULL)
|
subprocess.check_output(command, universal_newlines=True, stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print('OpenSCAD command not found! '
|
print('OpenSCAD command not found! '
|
||||||
'Please make sure that you have OpenSCAD installed and can run OpenSCAD CLI commands. '
|
'Please make sure that you have OpenSCAD installed and can run OpenSCAD CLI commands. '
|
||||||
'(Currently need Linux for this)')
|
'(Currently needs Linux for this)')
|
||||||
|
|
||||||
|
|
||||||
def convert_text_stl_to_binary(file_path):
|
|
||||||
mesh_data = mesh.Mesh.from_file(file_path)
|
|
||||||
|
|
||||||
# Remove the original file
|
|
||||||
os.remove(file_path)
|
|
||||||
|
|
||||||
mesh_data.save(file_path, mode=stl.Mode.BINARY)
|
|
||||||
|
|
||||||
|
|
||||||
def assert_os():
|
def assert_os():
|
||||||
|
|||||||