Compare commits
284 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
38c973b316 | ||
|
042d809ed0 | ||
|
3864839e52 | ||
|
2ba2c2c115 | ||
|
e3716ce8f9 | ||
|
c4f24974ab | ||
|
61dae9c7a4 | ||
|
41a26c453c | ||
|
bab4c8e8af | ||
|
a5c4bf05ad | ||
|
a65add65ac | ||
|
c449dd0a24 | ||
|
f16f7ddb09 | ||
|
9b5ec6af1a | ||
|
50958b064d | ||
|
c37373c920 | ||
|
700f5a2205 | ||
|
4993c3e82d | ||
|
c6b280f0e8 | ||
|
6012787781 | ||
|
30db66034c | ||
|
d6f344be3d | ||
|
f6aa3b3426 | ||
|
91c8c7bf4d | ||
|
dc93b8dcdf | ||
|
c9c094248e | ||
|
119c2cb6f4 | ||
|
24b391578b | ||
|
ec49ce1a6c | ||
|
f0c25d37b0 | ||
|
588a1edf62 | ||
|
3299aad5c8 | ||
|
74c52aac04 | ||
|
726d9ed2dc | ||
|
8a838dd1ce | ||
|
181c6ac624 | ||
|
e952aa7840 | ||
|
466ee31e10 | ||
|
4c926c529b | ||
|
edb1eccbf1 | ||
|
061812cc8b | ||
|
ce0c97b45e | ||
|
696b14699c | ||
|
2166a9be6a | ||
|
511729008d | ||
|
5111ec04bc | ||
|
cef3a620a6 | ||
|
da5191e52c | ||
|
d9af5b7f70 | ||
|
c30d7f1ad9 | ||
|
a5382cbe04 | ||
|
00c5c90a5e | ||
|
01c26d8a34 | ||
|
ef2102420b | ||
|
540f841163 | ||
|
1045502efb | ||
|
485184f092 | ||
|
b893c9069a | ||
|
69f4ced29d | ||
|
5c1aa849fe | ||
|
9d65f69bf3 | ||
|
515b99fdc0 | ||
|
631d052c68 | ||
|
1247303cb9 | ||
|
290be4beb6 | ||
|
24e941799d | ||
|
6a556c5879 | ||
|
14ab1bb8b6 | ||
|
be53547728 | ||
|
ba7d7d32ad | ||
|
d3049bc81b | ||
|
df35e14fc7 | ||
|
21c2aa5d62 | ||
|
c982876ebc | ||
|
5ccda42e5b | ||
|
92d0444e5f | ||
|
b239c1462e | ||
|
6413b7b2a0 | ||
|
0b0ce66c85 | ||
|
d38055c15c | ||
|
cf99418a19 | ||
|
0cd0e72d92 | ||
|
2c4a498a7a | ||
|
451101fcd6 | ||
|
c7a6d8164f | ||
|
8d7c44b80d | ||
|
dcfe4262c5 | ||
|
fe3b84f672 | ||
|
d1a17bd4ac | ||
|
b8efa11fd9 | ||
|
3bc8f35e37 | ||
|
39c11ef3b2 | ||
|
5a8a1da880 | ||
|
3147862212 | ||
|
4fc8a7f47d | ||
|
a9ed9944c3 | ||
|
9cd2dbc316 | ||
|
f3bfbbfcf2 | ||
|
baaa85ffed | ||
|
f1a49d4e28 | ||
|
0eed0673b0 | ||
|
9a4cc7ec42 | ||
|
2fb1185edf | ||
|
a782d43e67 | ||
|
ae934d47c7 | ||
|
823f3b936e | ||
|
3027b942a6 | ||
|
749a1f0648 | ||
|
5c898df217 | ||
|
7a566cc856 | ||
|
20d799a3c1 | ||
|
2ee95bba65 | ||
|
f49bb63266 | ||
|
258109811b | ||
|
b39fd536c2 | ||
|
a5a87d260d | ||
|
b09efb10e0 | ||
|
53acaac379 | ||
|
9b40e0dcef | ||
|
00ca412441 | ||
|
1e6d7f5dd6 | ||
|
ec07d95657 | ||
|
0dab0dca08 | ||
|
6e6cd45295 | ||
|
3a7fde6c56 | ||
|
c5bb898856 | ||
|
11ebe2225d | ||
|
a1e25bb878 | ||
|
9689683b7e | ||
|
08946e3d70 | ||
|
15c2946e91 | ||
|
34019196cd | ||
|
436fc71cf3 | ||
|
fd67c166f7 | ||
|
634deab911 | ||
|
e2feceb608 | ||
|
d1258e0b0c | ||
|
bd61a1dc55 | ||
|
055e83902f | ||
|
feec1e7ae5 | ||
|
be76af2fc4 | ||
|
9c1a9bf357 | ||
|
9647fb474b | ||
|
49fdfea792 | ||
|
ac0bacfeda | ||
|
6288059d99 | ||
|
0f1dff230a | ||
|
e379fa8ada | ||
|
313d7508df | ||
|
083caca4e8 | ||
|
49329df00c | ||
|
edc0b86bb1 | ||
|
5fbff060b0 | ||
|
b94ca4ad3a | ||
|
bc5515d35e | ||
|
44d213deaa | ||
|
145c5d9b1a | ||
|
7abbbd9b96 | ||
|
5b160cee88 | ||
|
3f31607840 | ||
|
1efed649cf | ||
|
b70c2f993c | ||
|
56e252f3dc | ||
|
f12b36ea04 | ||
|
bd5811e69b | ||
|
ede4da6f1d | ||
|
51cc2fd679 | ||
|
4ce2f53e20 | ||
|
e338c47e73 | ||
|
8328a70f42 | ||
|
cc794cd7c3 | ||
|
df28bd5116 | ||
|
61de6041d8 | ||
|
b2d712bca9 | ||
|
f3376edaf1 | ||
|
c073419c0b | ||
|
608168de8e | ||
|
fc45a40bd3 | ||
|
52e9c1d7fd | ||
|
ca1b34e9ca | ||
|
cbab9cea02 | ||
|
69cf998862 | ||
|
08bce9ec03 | ||
|
4aa7dbb416 | ||
|
7c7c2e5d3f | ||
|
f6f6664c0d | ||
|
2fd2e118a0 | ||
|
22c6fef113 | ||
|
dcf0c949b9 | ||
|
9ded315801 | ||
|
42e03679b4 | ||
|
d2c795f5f5 | ||
|
83b4ab2374 | ||
|
573c50774b | ||
|
4b93623492 | ||
|
d496898c80 | ||
|
544e69c71b | ||
|
240334784d | ||
|
516b225275 | ||
|
e46e6b6e5b | ||
|
4925979519 | ||
|
298d1f9284 | ||
|
fcf2f5f7f0 | ||
|
491c3b4ea8 | ||
|
94cb50f725 | ||
|
1d8275c061 | ||
|
3c605d608b | ||
|
9ba48c7e1a | ||
|
a6ebc5267b | ||
|
e9554ccffe | ||
|
0d179f3728 | ||
|
a94e462f34 | ||
|
7ce991e625 | ||
|
3e15be852f | ||
|
7c1c8e92f2 | ||
|
54c3b4f600 | ||
|
d80fc5709e | ||
|
30236046a8 | ||
|
93aeb4cf2c | ||
|
f62ca35c86 | ||
|
2320cbdbb8 | ||
|
769cb44207 | ||
|
f327df95a3 | ||
|
09956b6219 | ||
|
f8c9adca5a | ||
|
b83e56713f | ||
|
4c12d5fca4 | ||
|
da4f9fbdc3 | ||
|
614e5f3a72 | ||
|
a7eae4f549 | ||
|
3cd5769708 | ||
|
7b770abe12 | ||
|
31ab8562a7 | ||
|
db703379a3 | ||
|
cd925bc049 | ||
|
4a2951e22f | ||
|
a93a8f99fb | ||
|
73c436ee15 | ||
|
c69100bd71 | ||
|
e0b89359aa | ||
|
041d720c39 | ||
|
03a0c2fe98 | ||
|
7c2df8d36d | ||
|
8474718884 | ||
|
fe0f32ddc5 | ||
|
f191b9b0f4 | ||
|
2b3908b6fd | ||
|
0a84bf0927 | ||
|
da825b17ab | ||
|
ca153c971d | ||
|
0199587907 | ||
|
60350eb228 | ||
|
4f9729cf86 | ||
|
26f1338ca2 | ||
|
fc44b43638 | ||
|
182f39876a | ||
|
055e90cbb3 | ||
|
832380f893 | ||
|
929d082b25 | ||
|
57212b5701 | ||
|
1c3f136657 | ||
|
cfd2fd32a1 | ||
|
f573a91a09 | ||
|
d75aff2ccd | ||
|
491d85156c | ||
|
c89ce6843f | ||
|
1915dae034 | ||
|
05e8055ce2 | ||
|
21822b9abb | ||
|
d83d4b89bf | ||
|
613152f589 | ||
|
d90c00d140 | ||
|
b52ca9589a | ||
|
0d024060fc | ||
|
c4fe1d1098 | ||
|
a3ced6de45 | ||
|
1cdfe3267c | ||
|
b67cf4ce97 | ||
|
5bac2bf46d | ||
|
079168142b | ||
|
812fbc106c | ||
|
dd38fa6e5d | ||
|
5cdcd4ad37 | ||
|
22b7aa956c |
2067
CHANGELOG.md
Normal file
@@ -1,7 +1,7 @@
|
||||
# NopSCADlib usage
|
||||
|
||||
## Requirements
|
||||
1. OpenSCAD 2019.05 or later, download it from here: https://www.openscad.org/downloads.html
|
||||
1. OpenSCAD 2021.01 or later, download it from here: https://www.openscad.org/downloads.html
|
||||
1. Python 2.7+ or 3.6+ from https://www.python.org/downloads/
|
||||
1. ImageMagick 7 www.imagemagick.org
|
||||
|
||||
@@ -270,6 +270,22 @@ The target config file is selected by generating `target.scad` that includes `co
|
||||
The rest of the project includes `target.scad` to use the configuration.
|
||||
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc.) are placed in a sub-directory called `<target_name>`.
|
||||
|
||||
The build system will look for a `<target_name>_assembly` module and use it as the top level module instead of `main_assembly` if it it exists.
|
||||
That allows the project description to be target specific if the top level modules are in different scad files.
|
||||
The top level assembly instructions and assembly contents could also be different if appropriate.
|
||||
|
||||
If the top level module is just a shell wrapper that simply includes one other assembly, with no additional parts, then it is removed from the build instructions and
|
||||
the assembly it calls becomes the top level. This allows a different project description for each target but only one set of top level instructions without repeating them.
|
||||
|
||||
### Costed BOMs
|
||||
|
||||
A costed bill of materials can be made by opening the generated file `bom/bom.csv` in a spreadsheet program using a single quote as the string delimiter and comma as the field separator.
|
||||
That gets a list of part descriptions and quantities to which prices can be added to get the total cost and perhaps a URL of where to buy each part.
|
||||
|
||||
If a Python file called `parts.py` is found then `bom.py` will attempt to call functions for each part to get a price and URL.
|
||||
Any functions not found are printed, so you can see the format expected.
|
||||
The function are passed the quantity to allow them to calculate volume discounts, etc.
|
||||
|
||||
### Other libraries
|
||||
|
||||
The build scripts need to be able to locate the source files where the modules to generate the STL files and assemblies reside. They will search all the scad files
|
||||
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
16
examples/MainsBreakOutBox/bom/bom.csv
Normal file
@@ -0,0 +1,16 @@
|
||||
'Ferrule for 1.5mm^2 wire - not shown', 3
|
||||
'Wire blue 30/0.25mm strands, length 150mm - not shown', 2
|
||||
'Wire brown 30/0.25mm strands, length 150mm - not shown', 2
|
||||
'Wire green & yellow 30/0.25mm strands, length 150mm - not shown', 2
|
||||
'IEC inlet for ATX', 1
|
||||
'Heatfit insert M3', 2
|
||||
'4mm shielded jack socket blue', 2
|
||||
'4mm shielded jack socket brown', 1
|
||||
'4mm shielded jack socket green', 2
|
||||
'Mains socket 13A', 1
|
||||
'Nut M3 x 2.4mm nyloc', 6
|
||||
'Screw M3 cs cap x 12mm', 2
|
||||
'Screw M3 cs cap x 20mm', 2
|
||||
'Screw M3 dome x 10mm', 4
|
||||
'Heatshrink sleeving ID 3.2mm x 15mm - not shown', 8
|
||||
'Washer M3 x 7mm x 0.5mm', 10
|
|
@@ -3,6 +3,7 @@
|
||||
"name": "base_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {},
|
||||
"vitamins": {
|
||||
@@ -22,6 +23,7 @@
|
||||
"name": "feet_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"base_assembly": 1
|
||||
@@ -49,6 +51,7 @@
|
||||
"name": "mains_in_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"feet_assembly": 1
|
||||
@@ -86,6 +89,7 @@
|
||||
"name": "main_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"mains_in_assembly": 1
|
||||
|
11
examples/MainsBreakOutBox/platters/all.scad
Normal file
@@ -0,0 +1,11 @@
|
||||
include <NopSCADlib/core.scad>
|
||||
|
||||
*use_stl("socket_box"); // Importing the STL gives a CGAL error although NetFabb finds nothing wrong with it.
|
||||
|
||||
use <../scad/bob_main.scad>
|
||||
|
||||
render() socket_box_stl();
|
||||
|
||||
for(i = [0 : 3])
|
||||
translate([i * 25 - 1.5 * 25, -70])
|
||||
use_stl("foot");
|
@@ -31,7 +31,8 @@
|
||||
//! while its earth is disconnected. Don't be tempted to float the earth of an oscilloscope this way, use a mains isolation transformer to power the DUT instead.
|
||||
//! Earth leakage can be measured Canadian CSA style by disconnected the neutral link from the left socket and linking the central neutral to the live.
|
||||
//
|
||||
$extrusion_width = 0.5;
|
||||
$extrusion_width = 0.4;
|
||||
$layer_height = 0.2;
|
||||
$pp1_colour = "dimgrey";
|
||||
$pp2_colour = [0.9, 0.9, 0.9];
|
||||
|
||||
|
5
examples/MainsBreakOutBox/stls/deps/all.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
socket_box.stl
|
||||
foot.stl
|
||||
foot.stl
|
||||
foot.stl
|
||||
foot.stl
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
87250
examples/MainsBreakOutBox/stls/printed/all.stl
Normal file
@@ -1,40 +1,30 @@
|
||||
# A gallery of projects made with NopSCADlib
|
||||
<a name="TOP"></a>
|
||||
## ArduinoThermostat
|
||||
Arduino thermostat to control a beer fridge to use it as an environmental chamber.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## EnviroPlus
|
||||
Environmental monitor using Enviro+ sensor board and a Raspberry Pi Zero.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## FilamentDryBox
|
||||
A small fan oven with a spool holder to keep the filament warm and dry.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## HydraBot
|
||||
Current state of HydraRaptor after being modified for laser engraving.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## IOT 50V PSU
|
||||
WiFi controllable PSU
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Lab ATX PSU
|
||||
Bench power supply built around an ATX PSU.
|
||||
|
||||
@@ -47,15 +37,11 @@ Bench power supply built around an ATX PSU.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Laser Load
|
||||
15kV dummy load for testing CO2 laser PSUs
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## MainsBreakOutBox
|
||||
13A socket break out box with 4mm jacks to measure voltage and / or load current and earth leakage current.
|
||||
|
||||
@@ -72,8 +58,6 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Mains Box
|
||||
Mains isolated and variable supply with metering.
|
||||
|
||||
@@ -81,15 +65,11 @@ Mains isolated and variable supply with metering.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## SunBot
|
||||
A solar tracker to keep a solar panel pointing at the sun.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Turntable
|
||||
WiFi enabled remote control turntable for photography
|
||||
|
||||
@@ -97,8 +77,6 @@ WiFi enabled remote control turntable for photography
|
||||
|
||||
Was actually made from DiBond but shown made with carbon fibre here.
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Variac
|
||||
Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp8266-spi-spy](https://hydraraptor.blogspot.com/2018/04/esp8266-spi-spy.html)
|
||||
|
||||
@@ -106,4 +84,3 @@ Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp826
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -24,22 +24,22 @@
|
||||
// bom defaults to 0
|
||||
// Setting $bom on the command line or in the main file before including lib.scad overrides it everywhere.
|
||||
// Setting $bom after including lib overrides bom in the libs but not in the local file.
|
||||
// Setting $_bom in the local file overrides it in the local file but not in the libs.
|
||||
//
|
||||
rr_green = [0, 146/255, 0]; // RepRap logo colour
|
||||
crimson = [220/255, 20/255, 60/255];
|
||||
|
||||
$_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well
|
||||
$exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view
|
||||
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth when printing
|
||||
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer height when printing
|
||||
extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing
|
||||
nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle
|
||||
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects
|
||||
pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour
|
||||
pp2_colour = is_undef($pp2_colour) ? "Crimson" : $pp2_colour; // printed part colour 2
|
||||
pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour; // printed part colour 3
|
||||
pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4
|
||||
show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction
|
||||
show_threads = is_undef($show_threads) ? false : $show_threads; // show screw threads
|
||||
show_plugs = is_undef($show_plugs) ? false : $show_plugs; // plugs on headers
|
||||
pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour;// printed part colour 1, RepRap logo colour
|
||||
pp2_colour = is_undef($pp2_colour) ? crimson : $pp2_colour;// printed part colour 2
|
||||
pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour;// printed part colour 3
|
||||
pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4
|
||||
|
||||
|
||||
// Minimum wall is about two filaments wide but we extrude it closer to get better bonding
|
||||
squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4)
|
||||
@@ -50,12 +50,14 @@ eps = 1/128; // small fudge factor to stop CSG barfing on coincident faces.
|
||||
$fa = 6;
|
||||
$fs = extrusion_width / 2;
|
||||
|
||||
function round_to_layer(z) = ceil(z / layer_height) * layer_height;
|
||||
function round_to_layer(z) = ceil(z / layer_height) * layer_height; //! Round up to a multiple of layer_height.
|
||||
|
||||
// Some additional named colours
|
||||
function grey(n) = [0.01, 0.01, 0.01] * n; //! Generate a shade of grey to pass to color().
|
||||
gold = [255/255, 215/255, 0/255];
|
||||
brass = [255/255, 220/255, 100/255];
|
||||
silver = [0.75, 0.75, 0.75];
|
||||
function grey(n) = [0.01, 0.01, 0.01] * n; //! Generate a shade of grey to pass to color().
|
||||
silver = [0.75, 0.75, 0.75];
|
||||
gold = [255, 215, 0] / 255;
|
||||
brass = [255, 220, 100] / 255;
|
||||
copper = [230, 140, 51] / 255;
|
||||
|
||||
/*
|
||||
* Enums
|
||||
@@ -71,11 +73,6 @@ hs_grub = 4; // pulley set screw
|
||||
hs_cs_cap = 5;
|
||||
hs_dome = 6;
|
||||
//
|
||||
// Hot end descriptions
|
||||
//
|
||||
jhead = 1;
|
||||
e3d = 2;
|
||||
//
|
||||
// Face enumeration
|
||||
//
|
||||
f_bottom = 0;
|
||||
|
9
lib.scad
@@ -26,7 +26,10 @@ include <vitamins/psus.scad>
|
||||
include <vitamins/pcbs.scad>
|
||||
|
||||
include <vitamins/batteries.scad>
|
||||
include <vitamins/bearing_blocks.scad>
|
||||
include <vitamins/blowers.scad>
|
||||
include <vitamins/bldc_motors.scad>
|
||||
include <vitamins/box_sections.scad>
|
||||
include <vitamins/bulldogs.scad>
|
||||
include <vitamins/buttons.scad>
|
||||
include <vitamins/cameras.scad>
|
||||
@@ -37,7 +40,6 @@ include <vitamins/extrusion_brackets.scad>
|
||||
include <vitamins/geared_steppers.scad>
|
||||
include <vitamins/hot_ends.scad>
|
||||
include <vitamins/inserts.scad>
|
||||
include <vitamins/kp_pillow_blocks.scad>
|
||||
include <vitamins/ldrs.scad>
|
||||
include <vitamins/leadnuts.scad>
|
||||
include <vitamins/led_meter.scad>
|
||||
@@ -47,12 +49,13 @@ include <vitamins/mains_sockets.scad>
|
||||
include <vitamins/modules.scad>
|
||||
include <vitamins/panel_meters.scad>
|
||||
include <vitamins/pillars.scad>
|
||||
include <vitamins/pillow_blocks.scad>
|
||||
include <vitamins/pin_headers.scad>
|
||||
include <vitamins/pulleys.scad>
|
||||
include <vitamins/ring_terminals.scad>
|
||||
include <vitamins/rails.scad>
|
||||
include <vitamins/rod.scad>
|
||||
include <vitamins/scs_bearing_blocks.scad>
|
||||
include <vitamins/servo_motors.scad>
|
||||
include <vitamins/shaft_couplings.scad>
|
||||
include <vitamins/sheets.scad>
|
||||
include <vitamins/sk_brackets.scad>
|
||||
@@ -89,7 +92,7 @@ use <utils/gears.scad>
|
||||
use <utils/hanging_hole.scad>
|
||||
use <utils/fillet.scad>
|
||||
use <utils/rounded_polygon.scad>
|
||||
use <utils/rounded_right_triangle.scad>
|
||||
use <utils/rounded_triangle.scad>
|
||||
use <utils/layout.scad>
|
||||
use <utils/round.scad>
|
||||
use <utils/offset.scad>
|
||||
|
BIN
libtest.png
Before Width: | Height: | Size: 875 KiB After Width: | Height: | Size: 932 KiB |
87
libtest.scad
@@ -33,16 +33,22 @@
|
||||
//!
|
||||
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
//!
|
||||
//! A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
|
||||
//!
|
||||
//! <img src="libtest.png" width="100%"/>
|
||||
//
|
||||
// This file shows all the parts in the library.
|
||||
//
|
||||
include <lib.scad>
|
||||
|
||||
use <tests/7_segments.scad>
|
||||
use <tests/ball_bearings.scad>
|
||||
use <tests/batteries.scad>
|
||||
use <tests/bearing_blocks.scad>
|
||||
use <tests/belts.scad>
|
||||
use <tests/BLDC_motors.scad>
|
||||
use <tests/blowers.scad>
|
||||
use <tests/box_sections.scad>
|
||||
use <tests/bulldogs.scad>
|
||||
use <tests/buttons.scad>
|
||||
use <tests/cable_strips.scad>
|
||||
@@ -62,7 +68,6 @@ use <tests/hot_ends.scad>
|
||||
use <tests/IECs.scad>
|
||||
use <tests/inserts.scad>
|
||||
use <tests/jack.scad>
|
||||
use <tests/KP_pillow_blocks.scad>
|
||||
use <tests/leadnuts.scad>
|
||||
use <tests/LDRs.scad>
|
||||
use <tests/LEDs.scad>
|
||||
@@ -78,6 +83,8 @@ use <tests/opengrab.scad>
|
||||
use <tests/panel_meters.scad>
|
||||
use <tests/PCBs.scad>
|
||||
use <tests/pillars.scad>
|
||||
use <tests/pillow_blocks.scad>
|
||||
use <tests/potentiometers.scad>
|
||||
use <tests/press_fit.scad>
|
||||
use <tests/PSUs.scad>
|
||||
use <tests/pulleys.scad>
|
||||
@@ -86,8 +93,8 @@ use <tests/ring_terminals.scad>
|
||||
use <tests/rockers.scad>
|
||||
use <tests/rod.scad>
|
||||
use <tests/screws.scad>
|
||||
use <tests/SCS_bearing_blocks.scad>
|
||||
use <tests/sealing_strip.scad>
|
||||
use <tests/servo_motors.scad>
|
||||
use <tests/shaft_couplings.scad>
|
||||
use <tests/sheets.scad>
|
||||
use <tests/SK_brackets.scad>
|
||||
@@ -117,6 +124,7 @@ use <tests/flat_hinge.scad>
|
||||
use <tests/foot.scad>
|
||||
use <tests/handle.scad>
|
||||
use <tests/PCB_mount.scad>
|
||||
use <tests/pocket_handle.scad>
|
||||
use <tests/printed_box.scad>
|
||||
use <tests/printed_pulleys.scad>
|
||||
use <tests/ribbon_clamp.scad>
|
||||
@@ -180,13 +188,15 @@ translate([x5, cable_grommets_y + 250])
|
||||
translate([950, 600])
|
||||
box_test();
|
||||
|
||||
translate([890, 750])
|
||||
translate([900, 750])
|
||||
pocket_handles();
|
||||
|
||||
translate([900, 850])
|
||||
printed_boxes();
|
||||
|
||||
translate([850, 1330])
|
||||
translate([850, 1330 + 85])
|
||||
bbox_test();
|
||||
|
||||
|
||||
inserts_y = 0;
|
||||
nuts_y = inserts_y + 20;
|
||||
washers_y = nuts_y + 120;
|
||||
@@ -198,13 +208,14 @@ sealing_strip_y = springs_y + 20;
|
||||
tubings_y = sealing_strip_y + 20;
|
||||
pillars_y = tubings_y + 20;
|
||||
ball_bearings_y = pillars_y + 40;
|
||||
pulleys_y = ball_bearings_y +40;
|
||||
hot_ends_y = pulleys_y + 60;
|
||||
linear_bearings_y = hot_ends_y + 50;
|
||||
sheets_y = linear_bearings_y + 100;
|
||||
pcbs_y = sheets_y + 40;
|
||||
displays_y = pcbs_y + 170;
|
||||
fans_y = displays_y + 80;
|
||||
pulleys_y = ball_bearings_y + 40;
|
||||
leadnuts_y = pulleys_y + 60;
|
||||
linear_bearings_y = leadnuts_y + 50;
|
||||
steppers_y = linear_bearings_y + 110;
|
||||
sheets_y = steppers_y + 55;
|
||||
pcbs_y = sheets_y + 60;
|
||||
displays_y = pcbs_y + 140;
|
||||
fans_y = displays_y + 110;
|
||||
transformers_y = fans_y + 120;
|
||||
psus_y = transformers_y + 190;
|
||||
|
||||
@@ -247,13 +258,16 @@ translate([x0, ball_bearings_y])
|
||||
translate([x0, pulleys_y])
|
||||
pulleys();
|
||||
|
||||
translate([x0, leadnuts_y])
|
||||
leadnuts();
|
||||
|
||||
translate([x0, linear_bearings_y]) {
|
||||
linear_bearings();
|
||||
rods();
|
||||
}
|
||||
|
||||
translate([x0 + 10, hot_ends_y])
|
||||
hot_ends();
|
||||
translate([x0, steppers_y])
|
||||
stepper_motors();
|
||||
|
||||
translate([x0, sheets_y])
|
||||
sheets();
|
||||
@@ -271,7 +285,7 @@ translate([x0, fans_y]) {
|
||||
fan_guards();
|
||||
}
|
||||
|
||||
translate([x0, transformers_y])
|
||||
translate([760, fans_y])
|
||||
variacs();
|
||||
|
||||
translate([x0, psus_y]) {
|
||||
@@ -283,7 +297,6 @@ translate([x0, psus_y]) {
|
||||
zipties_y = 0;
|
||||
bulldogs_y = zipties_y + 30;
|
||||
swiss_clips_y = bulldogs_y + 35;
|
||||
leadnuts_y = swiss_clips_y + 50;
|
||||
|
||||
translate([x1, zipties_y])
|
||||
zipties();
|
||||
@@ -294,10 +307,6 @@ translate([x1, bulldogs_y])
|
||||
translate([x1, swiss_clips_y])
|
||||
swiss_clips();
|
||||
|
||||
translate([x1, leadnuts_y])
|
||||
leadnuts();
|
||||
|
||||
|
||||
leds_y = 0;
|
||||
carriers_y = leds_y + 40;
|
||||
magnets_y = carriers_y + 40;
|
||||
@@ -354,18 +363,18 @@ iecs_y = d_connectors_y + 80;
|
||||
modules_y = iecs_y + 60;
|
||||
ssrs_y = modules_y + 80;
|
||||
blowers_y = ssrs_y + 60;
|
||||
batteries_y = blowers_y + 100;
|
||||
steppers_y = batteries_y + 55;
|
||||
panel_meters_y = steppers_y + 70;
|
||||
hot_ends_y = blowers_y + 100;
|
||||
batteries_y = hot_ends_y + 55;
|
||||
panel_meters_y = batteries_y + 70;
|
||||
extrusions_y = panel_meters_y + 80;
|
||||
|
||||
translate([x3, veroboard_y])
|
||||
veroboard_test();
|
||||
|
||||
translate([x3 + 70, veroboard_y + 30])
|
||||
translate([x3 + 60, veroboard_y + 20])
|
||||
geared_steppers();
|
||||
|
||||
translate([x3 + 140, veroboard_y + 20])
|
||||
translate([x3 + 160, ssrs_y])
|
||||
pcb_mounts();
|
||||
|
||||
translate([x3 + 170, veroboard_y + 16])
|
||||
@@ -401,8 +410,8 @@ translate([x3, blowers_y])
|
||||
translate([x3, batteries_y])
|
||||
batteries();
|
||||
|
||||
translate([x2, steppers_y]) // interloper
|
||||
stepper_motors();
|
||||
translate([x3 + 10, hot_ends_y])
|
||||
hot_ends();
|
||||
|
||||
translate([x2, panel_meters_y])
|
||||
panel_meters();
|
||||
@@ -410,7 +419,7 @@ translate([x2, panel_meters_y])
|
||||
translate([x2, extrusions_y])
|
||||
extrusions();
|
||||
|
||||
translate([x3, transformers_y])
|
||||
translate([400, transformers_y])
|
||||
transformers();
|
||||
|
||||
|
||||
@@ -418,15 +427,21 @@ belts_y = 0;
|
||||
rails_y = belts_y + 200;
|
||||
extrusion_brackets_y = rails_y + 250;
|
||||
sk_brackets_y = extrusion_brackets_y + 80;
|
||||
kp_pillow_blocks_y = sk_brackets_y + 50;
|
||||
kp_pillow_blocks_y = sk_brackets_y + 60;
|
||||
scs_bearing_blocks_y = kp_pillow_blocks_y + 60;
|
||||
box_sections_y = batteries_y;
|
||||
BLDC_y = scs_bearing_blocks_y + 120;
|
||||
pot_y = BLDC_y + 40;
|
||||
cable_strip_y = pot_y + 50;
|
||||
|
||||
translate([0, transformers_y])
|
||||
servo_motors();
|
||||
|
||||
translate([x4 + 200, belts_y + 58]) {
|
||||
belt_test();
|
||||
|
||||
translate([0, 60])
|
||||
opengrab_test();
|
||||
|
||||
}
|
||||
|
||||
translate([x4 + 175, belts_y, -20])
|
||||
@@ -435,7 +450,7 @@ translate([x4 + 175, belts_y, -20])
|
||||
translate([x4, rails_y + 130])
|
||||
rails();
|
||||
|
||||
translate([770, fans_y + 50])
|
||||
translate([x4, cable_strip_y])
|
||||
cable_strips();
|
||||
|
||||
translate([x4, kp_pillow_blocks_y])
|
||||
@@ -447,12 +462,20 @@ translate([x4, sk_brackets_y])
|
||||
translate([x4, extrusion_brackets_y])
|
||||
extrusion_brackets();
|
||||
|
||||
translate([x4 + 120, extrusion_brackets_y])
|
||||
translate([x1, swiss_clips_y + 50])
|
||||
shaft_couplings();
|
||||
|
||||
translate([x4, scs_bearing_blocks_y])
|
||||
scs_bearing_blocks();
|
||||
|
||||
translate([x4, BLDC_y])
|
||||
bldc_motors();
|
||||
|
||||
translate([x4, pot_y])
|
||||
potentiometers();
|
||||
|
||||
translate([x2, box_sections_y])
|
||||
box_sections();
|
||||
|
||||
translate([x6, 125])
|
||||
light_strips();
|
||||
|
227
printed/box.scad
@@ -31,9 +31,11 @@
|
||||
//!
|
||||
//! Normally the side sheets are the same type but they can be overridden individually as long as the substitute has the same thickness.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
use <../vitamins/sheet.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
use <../vitamins/screw.scad>
|
||||
use <../vitamins/washer.scad>
|
||||
use <../utils/quadrant.scad>
|
||||
use <../utils/round.scad>
|
||||
|
||||
@@ -52,8 +54,8 @@ function box_width(type) = type[7]; //! Internal width
|
||||
function box_depth(type) = type[8]; //! Internal depth
|
||||
function box_height(type) = type[9]; //! Internal height
|
||||
|
||||
function box(screw, wall, sheets, top_sheet, base_sheet, size, feet = false, shelf_screw = M3_dome_screw) = //! Construct a property list for a box.
|
||||
concat([screw, shelf_screw, wall, sheets, top_sheet, base_sheet, feet], size);
|
||||
function box(screw, wall, sheets, top_sheet, base_sheet, size, feet = false, shelf_screw = undef) = //! Construct a property list for a box.
|
||||
concat([screw, is_undef(shelf_screw) ? screw : shelf_screw, wall, sheets, top_sheet, base_sheet, feet], size);
|
||||
|
||||
function box_bezel_clearance(type) = bezel_clearance;
|
||||
|
||||
@@ -139,17 +141,17 @@ module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
|
||||
}
|
||||
|
||||
module box_corner_profile(type) { //! Generates the corner profile STL for 3D printing.
|
||||
stl("box_corner_profile");
|
||||
|
||||
length = box_height(type) - 2 * box_margin(type);
|
||||
difference() {
|
||||
linear_extrude(length, center = true, convexity = 5)
|
||||
box_corner_profile_2D(type);
|
||||
|
||||
for(z = [-1, 1])
|
||||
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
|
||||
insert_hole(box_insert(type), 5);
|
||||
}
|
||||
stl("box_corner_profile")
|
||||
difference() {
|
||||
linear_extrude(length, center = true, convexity = 5)
|
||||
box_corner_profile_2D(type);
|
||||
|
||||
for(z = [-1, 1])
|
||||
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
|
||||
insert_hole(box_insert(type), 5);
|
||||
}
|
||||
}
|
||||
|
||||
module box_corner_profile_section(type, section, sections) { //! Generates interlocking sections of the corner profile to allow it to be taller than the printer
|
||||
@@ -209,7 +211,6 @@ module box_corner_quadrants(type, width, depth)
|
||||
}
|
||||
|
||||
module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
stl(bottom ? "bottom_bezel" : "top_bezel");
|
||||
feet = bottom && box_feet(type);
|
||||
t = box_sheet_slot(type);
|
||||
outset = box_outset(type);
|
||||
@@ -221,66 +222,67 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
height = box_bezel_height(type, bottom);
|
||||
foot_extension = foot_height - height;
|
||||
|
||||
difference() {
|
||||
w = box_width(type);
|
||||
d = box_depth(type);
|
||||
translate_z(-box_profile_overlap(type)) difference() {
|
||||
tw = w + 2 * outset;
|
||||
td = d + 2 * outset;
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type), false);
|
||||
//
|
||||
// Remove edges between the feet
|
||||
//
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([w - 2 * foot_length, td + 1, 1], center = true);
|
||||
stl(bottom ? "bottom_bezel" : "top_bezel")
|
||||
difference() {
|
||||
w = box_width(type);
|
||||
d = box_depth(type);
|
||||
translate_z(-box_profile_overlap(type)) difference() {
|
||||
tw = w + 2 * outset;
|
||||
td = d + 2 * outset;
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type));
|
||||
//
|
||||
// Remove edges between the feet
|
||||
//
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([w - 2 * foot_length, td + 1, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
|
||||
}
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([tw + 1, d - 2 * foot_length, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
}
|
||||
}
|
||||
//
|
||||
// slots for side panels
|
||||
//
|
||||
translate_z(-box_profile_overlap(type))
|
||||
linear_extrude(2 * box_profile_overlap(type), center = true)
|
||||
for(i = [-1, 1]) {
|
||||
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
|
||||
square([t, d - 2 * cgap], center = true);
|
||||
|
||||
translate([0, i * (d + t - sheet_slot_clearance) / 2])
|
||||
square([w - 2 * cgap, t], center = true);
|
||||
}
|
||||
//
|
||||
// recess for top / bottom panel
|
||||
//
|
||||
translate_z(cgap)
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
|
||||
//
|
||||
// leave plastic over the corner profiles
|
||||
//
|
||||
translate_z(-box_profile_overlap(type) - 1)
|
||||
linear_extrude(box_profile_overlap(type) + cgap + 2)
|
||||
union() {
|
||||
difference() {
|
||||
square([w - 2 * inset,
|
||||
d - 2 * inset], center = true);
|
||||
|
||||
box_corner_quadrants(type, w, d);
|
||||
translate_z(foot_height + 1)
|
||||
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
|
||||
}
|
||||
box_screw_hole_positions(type)
|
||||
poly_circle(screw_clearance_radius(box_screw(type)));
|
||||
}
|
||||
}
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([tw + 1, d - 2 * foot_length, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
}
|
||||
}
|
||||
//
|
||||
// slots for side panels
|
||||
//
|
||||
translate_z(-box_profile_overlap(type))
|
||||
linear_extrude(2 * box_profile_overlap(type), center = true)
|
||||
for(i = [-1, 1]) {
|
||||
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
|
||||
square([t, d - 2 * cgap], center = true);
|
||||
|
||||
translate([0, i * (d + t - sheet_slot_clearance) / 2])
|
||||
square([w - 2 * cgap, t], center = true);
|
||||
}
|
||||
//
|
||||
// recess for top / bottom panel
|
||||
//
|
||||
translate_z(cgap)
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2);
|
||||
//
|
||||
// leave plastic over the corner profiles
|
||||
//
|
||||
translate_z(-box_profile_overlap(type) - 1)
|
||||
linear_extrude(box_profile_overlap(type) + cgap + 2)
|
||||
union() {
|
||||
difference() {
|
||||
square([w - 2 * inset,
|
||||
d - 2 * inset], center = true);
|
||||
|
||||
box_corner_quadrants(type, w, d);
|
||||
}
|
||||
box_screw_hole_positions(type)
|
||||
poly_circle(screw_clearance_radius(box_screw(type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dowel_length = 20;
|
||||
@@ -485,7 +487,6 @@ module box_shelf_screw_positions(type, screw_positions, thickness = 0, wall = un
|
||||
}
|
||||
|
||||
module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a shelf bracket, the first optional child is a 2D cutout and the second 3D cutouts
|
||||
stl("shelf_bracket");
|
||||
w = is_undef(wall) ? box_wall(type) : wall;
|
||||
insert = box_shelf_insert(type);
|
||||
lip = 2 * insert_boss_radius(insert, w);
|
||||
@@ -513,44 +514,45 @@ module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a
|
||||
square([lip, eps]);
|
||||
}
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(w)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
|
||||
round(2) offset(-width)
|
||||
stl("shelf_bracket")
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(w)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
linear_extrude(lip)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
round(2) offset(-width)
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
offset(-w)
|
||||
linear_extrude(lip)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
offset(-w)
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
boss();
|
||||
}
|
||||
if($children > 1)
|
||||
hflip()
|
||||
children(1);
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
boss();
|
||||
insert_hole(insert, counterbore = 1, horizontal = true);
|
||||
}
|
||||
if($children > 1)
|
||||
hflip()
|
||||
children(1);
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
insert_hole(insert, counterbore = 1, horizontal = true);
|
||||
}
|
||||
}
|
||||
|
||||
module box_shelf_bracket_section(type, rows, cols, x, y) { //! Generates sections of the shelf bracket to allow it to be bigger than the printer
|
||||
@@ -588,9 +590,26 @@ module box_back_blank(type, sheet = false) { //! Generates a 2D template for the
|
||||
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
|
||||
}
|
||||
|
||||
module box_base(type) render_2D_sheet(box_base_sheet(type)) box_base_blank(type); //! Default base, can be overridden to customise
|
||||
module box_top(type) render_2D_sheet(box_top_sheet(type)) box_top_blank(type); //! Default top, can be overridden to customise
|
||||
module box_back(type) render_2D_sheet(box_sheets(type)) box_back_blank(type); //! Default back, can be overridden to customise
|
||||
module box_front(type) render_2D_sheet(box_sheets(type)) box_front_blank(type); //! Default front, can be overridden to customise
|
||||
module box_left(type) render_2D_sheet(box_sheets(type)) box_left_blank(type); //! Default left side, can be overridden to customise
|
||||
module box_right(type) render_2D_sheet(box_sheets(type)) box_right_blank(type); //! Default right side, can be overridden to customise
|
||||
module box_base(type) //! Default base, can be overridden to customise
|
||||
render_2D_sheet(box_base_sheet(type))
|
||||
box_base_blank(type);
|
||||
|
||||
module box_top(type) //! Default top, can be overridden to customise
|
||||
render_2D_sheet(box_top_sheet(type))
|
||||
box_top_blank(type);
|
||||
|
||||
module box_back(type) //! Default back, can be overridden to customise
|
||||
render_2D_sheet(box_sheets(type))
|
||||
box_back_blank(type);
|
||||
|
||||
module box_front(type) //! Default front, can be overridden to customise
|
||||
render_2D_sheet(box_sheets(type))
|
||||
box_front_blank(type);
|
||||
|
||||
module box_left(type) //! Default left side, can be overridden to customise
|
||||
render_2D_sheet(box_sheets(type))
|
||||
box_left_blank(type);
|
||||
|
||||
module box_right(type) //! Default right side, can be overridden to customise
|
||||
render_2D_sheet(box_sheets(type))
|
||||
box_right_blank(type);
|
||||
|
@@ -28,7 +28,7 @@ assembly("box") {
|
||||
|
||||
t = sheet_thickness(box_sheets(type));
|
||||
|
||||
for(corner = [0 : corners - 1]) {
|
||||
for(corner = [0 : 1 : corners - 1]) {
|
||||
x = [-1,1,1,-1][corner];
|
||||
y = [-1,-1,1,1][corner];
|
||||
translate([x * (box_width(type) / 2 + 25 * exploded()), y * (box_depth(type) / 2 + 25 * exploded())])
|
||||
|
@@ -54,7 +54,7 @@ function bbox(screw, sheets, base_sheet, top_sheet, span, size, name = "bbox", s
|
||||
[ screw, sheets, base_sheet, top_sheet, span, size.x, size.y, size.z, name, skip_blocks, star_washers ];
|
||||
|
||||
function bbox_volume(type) = bbox_width(type) * bbox_depth(type) * bbox_height(type) / 1000000; //! Internal volume in litres
|
||||
function bbox_area(type) = let(w = bbox_width(type), d = bbox_depth(type), h = bbox_height(type)) //! Internal surdface area in m^2
|
||||
function bbox_area(type) = let(w = bbox_width(type), d = bbox_depth(type), h = bbox_height(type)) //! Internal surface area in m^2
|
||||
2 * (w * d + w * h + d * h) / 1000000;
|
||||
|
||||
module bbox_shelf_blank(type) { //! 2D template for a shelf
|
||||
@@ -198,12 +198,29 @@ module bbox_back_blank(type, sheet = false) { //! 2D template for the back
|
||||
}
|
||||
}
|
||||
|
||||
module bbox_base(type) render_2D_sheet(bbox_base_sheet(type)) bbox_base_blank(type); //! Default base, can be overridden to customise
|
||||
module bbox_top(type) render_2D_sheet(bbox_top_sheet(type)) bbox_top_blank(type); //! Default top, can be overridden to customise
|
||||
module bbox_back(type) render_2D_sheet(bbox_sheets(type)) bbox_back_blank(type); //! Default back, can be overridden to customise
|
||||
module bbox_front(type) render_2D_sheet(bbox_sheets(type)) bbox_front_blank(type); //! Default front, can be overridden to customise
|
||||
module bbox_left(type) render_2D_sheet(bbox_sheets(type)) bbox_left_blank(type); //! Default left side, can be overridden to customise
|
||||
module bbox_right(type) render_2D_sheet(bbox_sheets(type)) bbox_right_blank(type); //! Default right side, can be overridden to customise
|
||||
module bbox_base(type) //! Default base, can be overridden to customise
|
||||
render_2D_sheet(bbox_base_sheet(type))
|
||||
bbox_base_blank(type);
|
||||
|
||||
module bbox_top(type) //! Default top, can be overridden to customise
|
||||
render_2D_sheet(bbox_top_sheet(type))
|
||||
bbox_top_blank(type);
|
||||
|
||||
module bbox_back(type) //! Default back, can be overridden to customise
|
||||
render_2D_sheet(bbox_sheets(type))
|
||||
bbox_back_blank(type);
|
||||
|
||||
module bbox_front(type) //! Default front, can be overridden to customise
|
||||
render_2D_sheet(bbox_sheets(type))
|
||||
bbox_front_blank(type);
|
||||
|
||||
module bbox_left(type) //! Default left side, can be overridden to customise
|
||||
render_2D_sheet(bbox_sheets(type))
|
||||
bbox_left_blank(type);
|
||||
|
||||
module bbox_right(type) //! Default right side, can be overridden to customise
|
||||
render_2D_sheet(bbox_sheets(type))
|
||||
bbox_right_blank(type);
|
||||
|
||||
module _bbox_assembly(type, top = true, base = true, left = true, right = true, back = true, front = true) { //! The box assembly, wrap with a local copy without parameters
|
||||
width = bbox_width(type);
|
||||
|
@@ -49,84 +49,84 @@ module ribbon_grommet_hole(ways, h = 50, expand = true) { //! Generate a hole fo
|
||||
}
|
||||
|
||||
module ribbon_grommet(ways, thickness) { //! Generate the STL for a printed ribbon grommet
|
||||
stl(str("ribbon_grommet_", ways, "_", thickness));
|
||||
|
||||
width = 2 * (wall + clearance) + thickness;
|
||||
slot_length = ribbon_clamp_slot(ways);
|
||||
length = slot_length + 2 * wall + 2 * overlap;
|
||||
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([-length / 2, 0])
|
||||
square([length, base]);
|
||||
stl(str("ribbon_grommet_", ways, "_", thickness))
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([-length / 2, 0])
|
||||
square([length, base]);
|
||||
|
||||
for(end = [-1, 1])
|
||||
translate([end * (length / 2 - rad), height - rad])
|
||||
semi_circle(rad);
|
||||
for(end = [-1, 1])
|
||||
translate([end * (length / 2 - rad), height - rad])
|
||||
semi_circle(rad);
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
|
||||
linear_extrude(width -1, center = true)
|
||||
difference() {
|
||||
ribbon_grommet_hole(ways, expand = false, h = 0);
|
||||
linear_extrude(width -1, center = true)
|
||||
difference() {
|
||||
ribbon_grommet_hole(ways, expand = false, h = 0);
|
||||
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module round_grommet_top(diameter, thickness, od = undef) { //! Generate the STL for a round grommet top half
|
||||
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness));
|
||||
chamfer = layer_height;
|
||||
h = wall + thickness + wall;
|
||||
r1 = diameter / 2;
|
||||
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
|
||||
r3 = r2 + overlap;
|
||||
r0 = r1 + 1;
|
||||
union() {
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r0, 0],
|
||||
[r3 - chamfer, 0],
|
||||
[r3, chamfer],
|
||||
[r3, wall],
|
||||
[r2, wall],
|
||||
[r2, h - chamfer],
|
||||
[r2 - chamfer, h],
|
||||
[r0, h],
|
||||
]);
|
||||
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness))
|
||||
union() {
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r0, 0],
|
||||
[r3 - chamfer, 0],
|
||||
[r3, chamfer],
|
||||
[r3, wall],
|
||||
[r2, wall],
|
||||
[r2, h - chamfer],
|
||||
[r2 - chamfer, h],
|
||||
[r0, h],
|
||||
]);
|
||||
|
||||
render() difference() {
|
||||
cylinder(r = r0 + eps, h = h);
|
||||
render() difference() {
|
||||
cylinder(r = r0 + eps, h = h);
|
||||
|
||||
poly_cylinder(r = r1, h = 100, center = true);
|
||||
poly_cylinder(r = r1, h = 100, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module round_grommet_bottom(diameter, od = undef) { //! Generate the STL for a round grommet bottom half
|
||||
stl(str("round_grommet_bottom_", round(diameter * 10)));
|
||||
chamfer = layer_height;
|
||||
r1 = diameter / 2;
|
||||
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
|
||||
r3 = r2 + max(overlap, wall + chamfer);
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r2, chamfer],
|
||||
[r2 + chamfer, 0],
|
||||
[r3, 0],
|
||||
[r3, wall - chamfer],
|
||||
[r3 - chamfer, wall],
|
||||
[r2, wall],
|
||||
]);
|
||||
stl(str("round_grommet_bottom_", round(diameter * 10)))
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r2, chamfer],
|
||||
[r2 + chamfer, 0],
|
||||
[r3, 0],
|
||||
[r3, wall - chamfer],
|
||||
[r3 - chamfer, wall],
|
||||
[r2, wall],
|
||||
]);
|
||||
}
|
||||
|
||||
module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
|
||||
@@ -161,30 +161,30 @@ module mouse_grommet_hole(r, h = 50, z = undef, expand = wall + clearance) //! M
|
||||
function mouse_grommet_offset(r) = r + wall;
|
||||
|
||||
module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
|
||||
stl(str("mouse_grommet_", r * 10, "_", thickness));
|
||||
|
||||
width = 2 * (wall + clearance) + thickness;
|
||||
length = 2 * r + 2 * wall + 2 * overlap;
|
||||
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
|
||||
stl(str("mouse_grommet_", r * 10, "_", thickness))
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
linear_extrude(width - 1, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
linear_extrude(width - 1, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module mouse_grommet_assembly(r, thickness)
|
||||
|
@@ -82,7 +82,6 @@ module cam_holes(cam) {
|
||||
}
|
||||
|
||||
module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
|
||||
stl("rpi_camera_focus_ring");
|
||||
|
||||
rad = 15 / 2;
|
||||
hole_r1 = 2.5 / 2;
|
||||
@@ -93,58 +92,58 @@ module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
|
||||
x = rad / (sin(angle / 2) + cos(angle / 2));
|
||||
r = x * sin(angle / 2);
|
||||
|
||||
difference() {
|
||||
linear_extrude(height = thickness, convexity = 5)
|
||||
difference() {
|
||||
union() {
|
||||
circle(x);
|
||||
stl("rpi_camera_focus_ring")
|
||||
difference() {
|
||||
linear_extrude(height = thickness, convexity = 5)
|
||||
difference() {
|
||||
union() {
|
||||
circle(x);
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i])
|
||||
rotate([0, 0, 2 * angle * i + angle])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i + angle])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
hull() {
|
||||
poly_cylinder(r = hole_r1, h = 0.1, center = true);
|
||||
hull() {
|
||||
poly_cylinder(r = hole_r1, h = 0.1, center = true);
|
||||
|
||||
translate([0, 0, thickness])
|
||||
poly_cylinder(r = hole_r2, h = 0.1, center = true);
|
||||
translate([0, 0, thickness])
|
||||
poly_cylinder(r = hole_r2, h = 0.1, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module camera_back(cam) { //! Make the STL for a camera case back
|
||||
stl(str("camera_back_", cam[0]));
|
||||
pcb = camera_pcb(cam);
|
||||
back = cam_back_size(cam);
|
||||
screw = pcb_screw(pcb);
|
||||
nut = screw_nut(screw);
|
||||
|
||||
translate_z(back.z)
|
||||
hflip()
|
||||
difference() {
|
||||
translate_z(back.z / 2)
|
||||
cube(back, center = true);
|
||||
stl(str("camera_back_", cam[0]))
|
||||
translate_z(back.z)
|
||||
hflip()
|
||||
difference() {
|
||||
translate_z(back.z / 2)
|
||||
cube(back, center = true);
|
||||
|
||||
translate([0, -cam_back_overlap])
|
||||
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
|
||||
translate([0, -cam_back_overlap])
|
||||
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
|
||||
|
||||
translate([0, -pcb_width(pcb) / 2])
|
||||
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
|
||||
translate([0, -pcb_width(pcb) / 2])
|
||||
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
|
||||
|
||||
translate_z(back.z)
|
||||
cam_holes(cam)
|
||||
hflip()
|
||||
nut_trap(screw, nut, supported = true);
|
||||
}
|
||||
translate_z(back.z)
|
||||
cam_holes(cam)
|
||||
hflip()
|
||||
nut_trap(screw, nut, supported = true);
|
||||
}
|
||||
}
|
||||
|
||||
module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
|
||||
stl(str("camera_front_", cam[0]));
|
||||
front = cam_front_size(cam);
|
||||
back = cam_back_size(cam);
|
||||
pcb = camera_pcb(cam);
|
||||
@@ -170,70 +169,71 @@ module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
|
||||
translate([0, (hinge ? front.x * hinge : front.y) / 2 + hinge_offset, hinge_r])
|
||||
children();
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
hull()
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
|
||||
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
|
||||
translate_z(front.z - 1)
|
||||
cylinder(r = rad, h = 1);
|
||||
stl(str("camera_front_", cam[0]))
|
||||
difference() {
|
||||
union() {
|
||||
hull()
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
|
||||
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
|
||||
translate_z(front.z - 1)
|
||||
cylinder(r = rad, h = 1);
|
||||
|
||||
translate_z(rad)
|
||||
sphere(rad);
|
||||
translate_z(rad)
|
||||
sphere(rad);
|
||||
|
||||
cylinder(r = rad * (sqrt(2) - 1), h = eps);
|
||||
}
|
||||
cylinder(r = rad * (sqrt(2) - 1), h = eps);
|
||||
}
|
||||
|
||||
hinge_pos()
|
||||
hull() {
|
||||
rotate([-90, 0, -90])
|
||||
teardrop(r = hinge_r, h = hinge_h, center = false);
|
||||
hinge_pos()
|
||||
hull() {
|
||||
rotate([-90, 0, -90])
|
||||
teardrop(r = hinge_r, h = hinge_h, center = false);
|
||||
|
||||
translate([0, -10, -hinge_r])
|
||||
cube([hinge_h, eps, 2 * hinge_r]);
|
||||
}
|
||||
}
|
||||
|
||||
hinge_pos()
|
||||
rotate([90, 0, 90])
|
||||
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
|
||||
|
||||
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
|
||||
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
|
||||
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(shelf)
|
||||
hflip() {
|
||||
pcb_component_position(pcb, "smd_led") // clearance for LED
|
||||
cube(led_clearance, center = true);
|
||||
|
||||
pcb_component_position(pcb, "smd_res") // clearance for resistor
|
||||
cube(res_clearance, center = true);
|
||||
translate([0, -10, -hinge_r])
|
||||
cube([hinge_h, eps, 2 * hinge_r]);
|
||||
}
|
||||
}
|
||||
|
||||
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
|
||||
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
|
||||
hinge_pos()
|
||||
rotate([90, 0, 90])
|
||||
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
|
||||
|
||||
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
|
||||
cube([connector_slot.x, connector_slot.y, front.z], center = true);
|
||||
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
|
||||
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(cam_back_clearance + layer_height)
|
||||
cam_holes(cam)
|
||||
rotate(90)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
|
||||
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
|
||||
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(shelf)
|
||||
hflip() {
|
||||
pcb_component_position(pcb, "smd_led") // clearance for LED
|
||||
cube(led_clearance, center = true);
|
||||
|
||||
pcb_component_position(pcb, "smd_res") // clearance for resistor
|
||||
cube(res_clearance, center = true);
|
||||
}
|
||||
|
||||
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
|
||||
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
|
||||
|
||||
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
|
||||
cube([connector_slot.x, connector_slot.y, front.z], center = true);
|
||||
|
||||
translate_z(cam_back_clearance + layer_height)
|
||||
cam_holes(cam)
|
||||
rotate(90)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
|
||||
|
||||
translate_z(shelf - pcb_size.z)
|
||||
hflip()
|
||||
camera_lens(cam, clearance);
|
||||
|
||||
translate_z(shelf - pcb_size.z)
|
||||
hflip()
|
||||
camera_lens(cam, clearance);
|
||||
|
||||
hflip()
|
||||
pcb_component_position(pcb, "smd_led")
|
||||
rotate(45)
|
||||
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
|
||||
}
|
||||
pcb_component_position(pcb, "smd_led")
|
||||
rotate(45)
|
||||
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
|
||||
}
|
||||
}
|
||||
|
||||
function bracket_thickness(cam) = max(wall, min(3.5, hinge_z(cam) - hinge_r - 1));
|
||||
@@ -253,34 +253,35 @@ module camera_bracket_position(cam) //! Position children at the bracket positio
|
||||
children();
|
||||
|
||||
module camera_bracket(cam) { //! Make the STL for the camera bracket
|
||||
stl(str("camera_bracket_", cam[0]));
|
||||
|
||||
t = bracket_thickness(cam);
|
||||
z = hinge_z(cam);
|
||||
translate([hinge_h / 2, 0])
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(eps / 2)
|
||||
cube([hinge_h, 2 * hinge_r, eps], center = true);
|
||||
|
||||
translate_z(z)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(r = hinge_r, h = hinge_h, center = true);
|
||||
stl(str("camera_bracket_", cam[0])) union() {
|
||||
translate([hinge_h / 2, 0])
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(eps / 2)
|
||||
cube([hinge_h, 2 * hinge_r, eps], center = true);
|
||||
|
||||
translate_z(z)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(r = hinge_r, h = hinge_h, center = true);
|
||||
}
|
||||
translate([hinge_h / 2, 0, z])
|
||||
rotate([90, 0, 90])
|
||||
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
|
||||
}
|
||||
translate([hinge_h / 2, 0, z])
|
||||
rotate([90, 0, 90])
|
||||
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
|
||||
}
|
||||
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull()
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull()
|
||||
camera_bracket_screw_positions(cam)
|
||||
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
|
||||
|
||||
camera_bracket_screw_positions(cam)
|
||||
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
|
||||
|
||||
camera_bracket_screw_positions(cam)
|
||||
poly_circle(screw_clearance_radius(bracket_screw));
|
||||
}
|
||||
poly_circle(screw_clearance_radius(bracket_screw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module camera_assembly(cam, angle = 0) //! Camera case assembly
|
||||
|
@@ -27,7 +27,6 @@ include <../utils/core/core.scad>
|
||||
function carrier_height() = 3; //! Height of PCB carrier
|
||||
|
||||
module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
|
||||
stl("ESP12F_carrier");
|
||||
pins = 8;
|
||||
pitch1 = 2;
|
||||
pitch2 = 2.54;
|
||||
@@ -43,29 +42,29 @@ module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
|
||||
width1 = wpitch1 + hole + squeezed_wall * 2;
|
||||
width2 = wpitch2 + hole2 + squeezed_wall * 2;
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width1, length1, eps], center = true);
|
||||
stl("ESP12F_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width1, length1, eps], center = true);
|
||||
|
||||
translate_z(eps / 2)
|
||||
cube([width2, length2, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
cube([width2, length2, eps], center = true);
|
||||
}
|
||||
|
||||
for(side = [-1, 1])
|
||||
for(i = [0 : pins - 1])
|
||||
hull() {
|
||||
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
|
||||
cube([hole2, hole2, eps], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
for(side = [-1, 1])
|
||||
for(i = [0 : pins - 1])
|
||||
hull() {
|
||||
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
|
||||
cube([hole2, hole2, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two required
|
||||
stl("TP4056_carrier");
|
||||
pitch = 2.54;
|
||||
outer_pitch = 13.9;
|
||||
inner_pitch = 7.54;
|
||||
@@ -78,30 +77,30 @@ module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two re
|
||||
width = hole + squeezed_wall * 2;
|
||||
spacing = inch(0.9);
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width, length1, eps], center = true);
|
||||
stl("TP4056_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width, length1, eps], center = true);
|
||||
|
||||
translate_z(eps / 2)
|
||||
cube([width, length2, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
cube([width, length2, eps], center = true);
|
||||
}
|
||||
|
||||
for(i = [0 : pins - 1])
|
||||
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
|
||||
if(x)
|
||||
hull() {
|
||||
translate([0, x, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, i * pitch - (pins - 1) * pitch / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = [0 : pins - 1])
|
||||
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
|
||||
if(x)
|
||||
hull() {
|
||||
translate([0, x, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, i * pitch - (pins - 1) * pitch / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two required
|
||||
stl("MT3608_carrier");
|
||||
pcb_width = 17;
|
||||
w_pitch_top = 6.81;
|
||||
w_pitch_bot = inch(0.3);
|
||||
@@ -113,21 +112,22 @@ module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two re
|
||||
width = hole + 2 * wall;
|
||||
offset = (l_pitch_top - l_pitch_bot) / 2;
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate([offset, 0, height - eps / 2])
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
|
||||
translate_z(eps / 2)
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
}
|
||||
for(side = [-1, 1])
|
||||
stl("MT3608_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate([offset, side * w_pitch_top / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
translate([offset, 0, height - eps / 2])
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
|
||||
translate([0, side * w_pitch_bot / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
}
|
||||
}
|
||||
for(side = [-1, 1])
|
||||
hull() {
|
||||
translate([offset, side * w_pitch_top / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, side * w_pitch_bot / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -72,8 +72,6 @@ module corner_block_holes(screw = def_screw) //! Place children at all the holes
|
||||
children();
|
||||
|
||||
module corner_block(screw = def_screw, name = false) { //! Generate the STL for a printed corner block
|
||||
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20));
|
||||
|
||||
r = 1;
|
||||
cb_width = corner_block_width(screw);
|
||||
cb_height = cb_width;
|
||||
@@ -81,39 +79,41 @@ module corner_block(screw = def_screw, name = false) { //! Generate the STL for
|
||||
insert = screw_insert(screw);
|
||||
corner_rad = insert_outer_d(insert) / 2 + wall;
|
||||
offset = corner_block_hole_offset(screw);
|
||||
difference() {
|
||||
hull() {
|
||||
translate([r, r])
|
||||
rounded_cylinder(r = r, h = cb_height, r2 = r);
|
||||
|
||||
translate([r, cb_depth - r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20))
|
||||
difference() {
|
||||
hull() {
|
||||
translate([r, r])
|
||||
rounded_cylinder(r = r, h = cb_height, r2 = r);
|
||||
|
||||
translate([cb_width - r, r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
translate([r, cb_depth - r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
|
||||
translate([offset, offset, offset])
|
||||
sphere(corner_rad);
|
||||
translate([cb_width - r, r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
|
||||
translate([offset, offset])
|
||||
cylinder(r = corner_rad, h = offset);
|
||||
translate([offset, offset, offset])
|
||||
sphere(corner_rad);
|
||||
|
||||
translate([offset, r, offset])
|
||||
rotate([-90, 0, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
translate([offset, offset])
|
||||
cylinder(r = corner_rad, h = offset);
|
||||
|
||||
translate([r, offset, offset])
|
||||
rotate([0, 90, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
translate([offset, r, offset])
|
||||
rotate([-90, 0, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
|
||||
translate([r, offset, offset])
|
||||
rotate([0, 90, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
}
|
||||
corner_block_v_hole(screw)
|
||||
insert_hole(insert, overshoot);
|
||||
|
||||
corner_block_h_holes(screw)
|
||||
insert_hole(insert, overshoot, true);
|
||||
|
||||
children();
|
||||
}
|
||||
corner_block_v_hole(screw)
|
||||
insert_hole(insert, overshoot);
|
||||
|
||||
corner_block_h_holes(screw)
|
||||
insert_hole(insert, overshoot, true);
|
||||
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
|
||||
|
@@ -45,7 +45,7 @@ function door_hinge_stat_screw() = stat_screw; //! Screw use to fas
|
||||
function door_hinge_stat_width() = stat_width; //! Width of the stationary part
|
||||
function door_hinge_stat_length() = stat_length; //! Length of the stationary part
|
||||
|
||||
module door_hinge_hole_positions(dir = 0) { //! Position chidren at the door hole positions
|
||||
module door_hinge_hole_positions(dir = 0) { //! Position children at the door hole positions
|
||||
hole_pitch = width - 10;
|
||||
|
||||
for(side = [-1, 1])
|
||||
@@ -54,44 +54,44 @@ module door_hinge_hole_positions(dir = 0) { //! Position chidren
|
||||
}
|
||||
|
||||
module door_hinge(door_thickness) { //! Generates STL for the moving part of the hinge
|
||||
stl(str("door_hinge_", door_thickness));
|
||||
|
||||
hole_pitch = width - 10;
|
||||
|
||||
union() {
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(width, center = true)
|
||||
stl(str("door_hinge_", door_thickness))
|
||||
union() {
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(width, center = true)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
intersection() {
|
||||
rotate(180)
|
||||
teardrop(r = dia / 2, h = 0, truncate = false);
|
||||
|
||||
square([dia + 1, 2 * thickness + door_thickness], center = true);
|
||||
}
|
||||
|
||||
square([1, thickness + door_thickness]);
|
||||
}
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
}
|
||||
linear_extrude(thickness)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
intersection() {
|
||||
rotate(180)
|
||||
teardrop(r = dia / 2, h = 0, truncate = false);
|
||||
translate([0, -width / 2])
|
||||
square([1, width]);
|
||||
|
||||
square([dia + 1, 2 * thickness + door_thickness], center = true);
|
||||
}
|
||||
|
||||
square([1, thickness + door_thickness]);
|
||||
for(side = [-1, 1])
|
||||
translate([-width + rad, side * (width / 2 - rad)])
|
||||
circle4n(rad);
|
||||
}
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
rotate(180)
|
||||
vflip()
|
||||
door_hinge_hole_positions()
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
linear_extrude(thickness)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([0, -width / 2])
|
||||
square([1, width]);
|
||||
|
||||
for(side = [-1, 1])
|
||||
translate([-width + rad, side * (width / 2 - rad)])
|
||||
circle4n(rad);
|
||||
}
|
||||
rotate(180)
|
||||
vflip()
|
||||
door_hinge_hole_positions()
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module door_hinge_6_stl() door_hinge(6);
|
||||
|
@@ -38,26 +38,26 @@ function door_latch_offset() = width / 2 + 1; //! Offset of the axle from the do
|
||||
nut_trap_depth = round_to_layer(screw_head_height(screw)) + 4 * layer_height;
|
||||
|
||||
module door_latch_stl() { //! Generates the STL for the printed part
|
||||
stl("door_latch");
|
||||
|
||||
ridge = 4;
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
|
||||
|
||||
translate_z(thickness / 2)
|
||||
cube([length, ridge, thickness], center = true);
|
||||
stl("door_latch")
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad);
|
||||
|
||||
translate_z(thickness / 2)
|
||||
cube([length, ridge, thickness], center = true);
|
||||
}
|
||||
|
||||
cylinder(d = width, h = height);
|
||||
}
|
||||
|
||||
cylinder(d = width, h = height);
|
||||
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
}
|
||||
|
||||
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickess
|
||||
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickness
|
||||
washer = screw_washer(screw);
|
||||
nut = screw_nut(screw);
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
//
|
||||
//! Parametric cable drag chain to limit the bend radius of a cable run.
|
||||
//!
|
||||
//! Each link has a maximum bend angle of 45°, so the mininium radius is proportional to the link length.
|
||||
//! Each link has a maximum bend angle of 45°, so the minimum radius is proportional to the link length.
|
||||
//!
|
||||
//! The travel property is how far it can move in each direction, i.e. half the maximum travel if the chain is mounted in the middle of the travel.
|
||||
//!
|
||||
|
@@ -17,7 +17,7 @@
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
//! Pintable fan finger guard to match the specified fan. To be `include`d, not `use`d.
|
||||
//! Printable fan finger guard to match the specified fan. To be `include`d, not `use`d.
|
||||
//!
|
||||
//! The ring spacing as well as the number of spokes can be specified, if zero a gasket is generated instead of a guard.
|
||||
//
|
||||
@@ -29,7 +29,7 @@ function fan_guard_wall() = extrusion_width - layer_height / 2 + nozzle / 2 + ex
|
||||
function fan_guard_corner_r(type) = washer_diameter(screw_washer(fan_screw(type))) / 2 + 0.5; //! Corner radius of the guard
|
||||
function fan_guard_width(type) = max(2 * (fan_hole_pitch(type) + fan_guard_corner_r(type)), fan_bore(type) + 4 * fan_guard_wall()); //! Width of the guard
|
||||
|
||||
module fan_guard(type, name = false, thickness = fan_guard_thickness(), spokes = 4, finger_width = 7, grill = false) { //! Generate the STL
|
||||
module fan_guard(type, name = false, thickness = fan_guard_thickness(), spokes = 4, finger_width = 7, grill = false, screws = true) { //! Generate the STL
|
||||
if(thickness)
|
||||
stl(name ? name : str("fan_guard_", fan_width(type)));
|
||||
hole_pitch = fan_hole_pitch(type);
|
||||
@@ -54,7 +54,7 @@ module fan_guard(type, name = false, thickness = fan_guard_thickness(), spokes =
|
||||
difference() {
|
||||
rounded_square([width, width], r = width / 2 - hole_pitch);
|
||||
|
||||
fan_holes(type, !grill, !grill, h = 0);
|
||||
fan_holes(type, !grill, !grill && screws, h = 0);
|
||||
}
|
||||
if(spokes) {
|
||||
intersection() {
|
||||
|
@@ -71,41 +71,42 @@ module fixing_block_h_hole_2D(screw = def_screw) //! Position 2D child on the ho
|
||||
children();
|
||||
|
||||
module fixing_block(screw = def_screw) { //! Generate the STL
|
||||
stl(str("fixing_block_M", screw_radius(screw) * 20));
|
||||
r = 1;
|
||||
r = 1;
|
||||
insert = screw_insert(screw);
|
||||
corner_rad = insert_outer_d(insert) / 2 + wall;
|
||||
fb_width = fixing_block_width(screw);
|
||||
fb_height = fixing_block_height(screw);
|
||||
fb_depth = fixing_block_depth(screw);
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(fb_height, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
|
||||
circle4n(corner_rad);
|
||||
stl(str("fixing_block_M", screw_radius(screw) * 20))
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(fb_height, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
|
||||
circle4n(corner_rad);
|
||||
|
||||
translate([side * (fb_width / 2 - r), r])
|
||||
circle4n(r);
|
||||
translate([side * (fb_width / 2 - r), r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
fixing_block_v_holes(screw)
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
fixing_block_v_holes(screw)
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
}
|
||||
translate_z(fb_height)
|
||||
fixing_block_v_holes(screw)
|
||||
insert_hole(insert);
|
||||
}
|
||||
translate_z(fb_height)
|
||||
fixing_block_v_holes(screw)
|
||||
insert_hole(insert);
|
||||
|
||||
fixing_block_h_hole(screw)
|
||||
insert_hole(insert, 10, true);
|
||||
}
|
||||
fixing_block_h_hole(screw)
|
||||
insert_hole(insert, 10, true);
|
||||
}
|
||||
}
|
||||
|
||||
module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8]) //! Printed part with the inserts inserted
|
||||
module fixing_block_assembly(screw = def_screw) //! Printed part with the inserts inserted
|
||||
pose([55, 180, 25], [0, 4.8, 4.8])
|
||||
assembly(str("fixing_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
translate_z(fixing_block_height(screw))
|
||||
rotate([0, 180, 0])
|
||||
|
@@ -40,7 +40,7 @@ function hinge_knuckles(type) = type[6]; //! How many knuckles
|
||||
function hinge_screw(type) = type[7]; //! Screw type to mount it
|
||||
function hinge_screws(type) = type[8]; //! How many screws
|
||||
function hinge_clearance(type) = type[9]; //! Clearance between knuckles
|
||||
function hinge_margin(type) = type[10]; //! How far to keep the screws from the knuckes
|
||||
function hinge_margin(type) = type[10]; //! How far to keep the screws from the knuckles
|
||||
|
||||
function flat_hinge(name, size, pin_d, knuckle_d, knuckles, screw, screws, clearance, margin) = //! Construct the property list for a flat hinge.
|
||||
[name, size.x, size.y, size.z, pin_d, knuckle_d, knuckles, screw, screws, clearance, margin];
|
||||
@@ -65,8 +65,6 @@ module hinge_screw_positions(type) { //! Place children at the screw positions
|
||||
}
|
||||
|
||||
module hinge_male(type, female = false) { //! The half with the stationary pin
|
||||
stl(str("hinge_", female ? "fe": "", "male_", type[0]));
|
||||
|
||||
r = hinge_radius(type);
|
||||
w = hinge_width(type);
|
||||
t = hinge_thickness(type);
|
||||
@@ -75,7 +73,7 @@ module hinge_male(type, female = false) { //! The half with the stationary
|
||||
assert(kr > pr, "knuckle diameter must be bigger than the pin diameter");
|
||||
|
||||
n = hinge_knuckles(type);
|
||||
assert(n >= 3, "must be at least three knuckes");
|
||||
assert(n >= 3, "must be at least three knuckles");
|
||||
mn = ceil(n / 2); // Male knuckles
|
||||
fn = floor(n / 2); // Female knuckles
|
||||
gap = hinge_clearance(type);
|
||||
@@ -85,37 +83,40 @@ module hinge_male(type, female = false) { //! The half with the stationary
|
||||
teardrop_r = kr / cos(22.5); // The corner on the teardrop
|
||||
inset = sqrt(sqr(teardrop_r + gap) - sqr(kr - t)) - kr;
|
||||
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1])
|
||||
translate([side * (w / 2 - r), hinge_depth(type) - r])
|
||||
circle4n(r);
|
||||
stl(str("hinge_", female ? "fe": "", "male_", type[0]))
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1])
|
||||
translate([side * (w / 2 - r), hinge_depth(type) - r])
|
||||
circle4n(r);
|
||||
|
||||
translate([-w / 2, inset])
|
||||
square([w, eps]);
|
||||
}
|
||||
hinge_screw_positions(type)
|
||||
poly_circle(screw_clearance_radius(hinge_screw(type)));
|
||||
translate([-w / 2, inset])
|
||||
square([w, eps]);
|
||||
}
|
||||
hinge_screw_positions(type)
|
||||
poly_circle(screw_clearance_radius(hinge_screw(type)));
|
||||
}
|
||||
|
||||
pitch = mw + gap + fw + gap;
|
||||
dir = female ? -1 : 1;
|
||||
translate([0, -kr, kr])
|
||||
rotate([90, 0, -90])
|
||||
for(z = [0 : (female ? fn : mn) - 1])
|
||||
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
|
||||
linear_extrude(female ? fw : mw)
|
||||
difference() {
|
||||
hull() {
|
||||
rotate(180)
|
||||
teardrop(r = kr, h = 0);
|
||||
|
||||
translate([-kr - 1, -kr])
|
||||
square(1);
|
||||
}
|
||||
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
|
||||
}
|
||||
}
|
||||
|
||||
pitch = mw + gap + fw + gap;
|
||||
dir = female ? -1 : 1;
|
||||
translate([0, -kr, kr])
|
||||
rotate([90, 0, -90])
|
||||
for(z = [0 : (female ? fn : mn) - 1])
|
||||
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
|
||||
linear_extrude(female ? fw : mw)
|
||||
difference() {
|
||||
hull() {
|
||||
rotate(180)
|
||||
teardrop(r = kr, h = 0);
|
||||
|
||||
translate([-kr - 1, -kr])
|
||||
square(1);
|
||||
}
|
||||
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
|
||||
}
|
||||
}
|
||||
|
||||
module hinge_female(type) hinge_male(type, true);
|
||||
|
@@ -39,7 +39,6 @@ function foot_screw(type = foot) = type[4]; //! Screw type
|
||||
function foot_slant(type = foot) = type[5]; //! Taper angle
|
||||
|
||||
module foot(type = foot) { //! Generate STL
|
||||
stl("foot");
|
||||
h = foot_height(type);
|
||||
t = foot_thickness(type);
|
||||
r1 = washer_radius(screw_washer(foot_screw(type)));
|
||||
@@ -47,24 +46,25 @@ module foot(type = foot) { //! Generate STL
|
||||
r2 = r3 - h * tan(foot_slant(type));
|
||||
r = foot_rad(type);
|
||||
|
||||
union() {
|
||||
rotate_extrude(convexity = 3) {
|
||||
hull() {
|
||||
translate([r1, 0])
|
||||
square([r3 - r1, eps]);
|
||||
stl("foot")
|
||||
union() {
|
||||
rotate_extrude(convexity = 3) {
|
||||
hull() {
|
||||
translate([r1, 0])
|
||||
square([r3 - r1, eps]);
|
||||
|
||||
for(x = [r1 + r, r2 - r])
|
||||
translate([x, h - r])
|
||||
circle4n(r);
|
||||
for(x = [r1 + r, r2 - r])
|
||||
translate([x, h - r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
circle(r1 + eps);
|
||||
|
||||
poly_circle( screw_clearance_radius(foot_screw(type)));
|
||||
}
|
||||
}
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
circle(r1 + eps);
|
||||
|
||||
poly_circle( screw_clearance_radius(foot_screw(type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with fasteners in place for specified sheet thickness
|
||||
@@ -93,7 +93,6 @@ module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with faste
|
||||
}
|
||||
|
||||
module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
|
||||
stl("insert_foot");
|
||||
h = foot_height(type);
|
||||
r3 = foot_diameter(type) / 2;
|
||||
r2 = r3 - h * tan(foot_slant(type));
|
||||
@@ -103,30 +102,31 @@ module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
|
||||
h2 = insert_hole_length(insert);
|
||||
r4 = insert_hole_radius(insert);
|
||||
r5 = r4 + 1;
|
||||
union() {
|
||||
rotate_extrude() {
|
||||
union() {
|
||||
hull() {
|
||||
translate([r5, 0]) {
|
||||
square([r3 - r5, eps]);
|
||||
square([eps, h]);
|
||||
}
|
||||
stl("insert_foot")
|
||||
union() {
|
||||
rotate_extrude() {
|
||||
union() {
|
||||
hull() {
|
||||
translate([r5, 0]) {
|
||||
square([r3 - r5, eps]);
|
||||
square([eps, h]);
|
||||
}
|
||||
|
||||
translate([r2 - r, h - r])
|
||||
circle4n(r);
|
||||
translate([r2 - r, h - r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
linear_extrude(h2 + eps)
|
||||
difference() {
|
||||
circle(r5 + eps);
|
||||
|
||||
poly_circle(r4);
|
||||
}
|
||||
|
||||
translate_z(h2)
|
||||
cylinder(r = r5 + eps, h = h - h2);
|
||||
}
|
||||
linear_extrude(h2 + eps)
|
||||
difference() {
|
||||
circle(r5 + eps);
|
||||
|
||||
poly_circle(r4);
|
||||
}
|
||||
|
||||
translate_z(h2)
|
||||
cylinder(r = r5 + eps, h = h - h2);
|
||||
}
|
||||
}
|
||||
//
|
||||
//! Place the insert in the bottom of the foot and push home with a soldering iron with a conical bit heated to 200°C.
|
||||
|
@@ -46,8 +46,6 @@ module handle_holes(h = 100) //! Drills holes for the screws
|
||||
drill(screw_clearance_radius(screw), h);
|
||||
|
||||
module handle_stl() { //! generate the STL
|
||||
stl("handle");
|
||||
|
||||
module end(end)
|
||||
translate([end * pitch / 2, 0])
|
||||
rotate_extrude()
|
||||
@@ -59,28 +57,30 @@ module handle_stl() { //! generate the STL
|
||||
square([dia / 2 + 1, dia + 1]);
|
||||
}
|
||||
|
||||
translate_z(dia / 2)
|
||||
union() {
|
||||
hull() {
|
||||
end(-1);
|
||||
stl("handle")
|
||||
translate_z(dia / 2)
|
||||
union() {
|
||||
hull() {
|
||||
end(-1);
|
||||
|
||||
end(1);
|
||||
}
|
||||
|
||||
handle_screw_positions()
|
||||
render() difference() {
|
||||
h = height + dia / 2;
|
||||
cylinder(d = dia, h = h);
|
||||
|
||||
translate_z(h)
|
||||
insert_hole(insert, 6);
|
||||
end(1);
|
||||
}
|
||||
}
|
||||
|
||||
handle_screw_positions()
|
||||
render() difference() {
|
||||
h = height + dia / 2;
|
||||
cylinder(d = dia, h = h);
|
||||
|
||||
translate_z(h)
|
||||
insert_hole(insert, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200°C.
|
||||
//
|
||||
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
|
||||
module handle_assembly() //! Printed part with inserts in place
|
||||
pose([225, 0, 150], [0, 0, 14])
|
||||
assembly("handle", ngb = true) {
|
||||
translate_z(handle_height())
|
||||
stl_colour(pp1_colour) vflip() handle_stl();
|
||||
|
@@ -66,35 +66,35 @@ module pcb_mount_washer_stl() //! A plastic washer to clamp a PCB
|
||||
pcb_mount_ring();
|
||||
|
||||
module pcb_mount(pcb, height = 5, washers = true) { //! Make the STL of a pcb mount for the specified PCB.
|
||||
stl(str("pcb_mount_", pcb[0], "_", height));
|
||||
|
||||
y_pitch = pcb_width(pcb) > 4 * pillar_r + 4 ? pillar_r + 1
|
||||
: pcb_width(pcb) / 2 + frame_w + 1 + pillar_r;
|
||||
|
||||
if(washers)
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (pillar_r + 1), y * y_pitch, 0])
|
||||
pcb_mount_washer_stl();
|
||||
stl(str("pcb_mount_", pcb[0], "_", height)) union() {
|
||||
if(washers)
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (pillar_r + 1), y * y_pitch, 0])
|
||||
pcb_mount_washer_stl();
|
||||
|
||||
for(x = [-1, 1])
|
||||
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
|
||||
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
|
||||
for(x = [-1, 1])
|
||||
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
|
||||
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
|
||||
|
||||
for(y = [-1, 1])
|
||||
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
|
||||
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
|
||||
for(y = [-1, 1])
|
||||
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
|
||||
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
|
||||
|
||||
pcb_mount_screw_positions(pcb)
|
||||
linear_extrude(height)
|
||||
pcb_mount_ring();
|
||||
|
||||
linear_extrude(height + pcb_thickness(pcb) - layer_height)
|
||||
difference() {
|
||||
pcb_mount_screw_positions(pcb)
|
||||
pcb_mount_screw_positions(pcb)
|
||||
linear_extrude(height)
|
||||
pcb_mount_ring();
|
||||
|
||||
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
|
||||
}
|
||||
linear_extrude(height + pcb_thickness(pcb) - layer_height)
|
||||
difference() {
|
||||
pcb_mount_screw_positions(pcb)
|
||||
pcb_mount_ring();
|
||||
|
||||
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly with fasteners
|
||||
|
154
printed/pocket_handle.scad
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Customisable pocket handle
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
function pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4) = //! Construct a pocket_handle property list
|
||||
[hand_size, slant, screw, panel_t, wall, rad];
|
||||
|
||||
function pocket_handle_hand_size(type) = type[0]; //! Size of the hole for the fingers
|
||||
function pocket_handle_slant(type) = type[1]; //! Upward slant of the hand hole
|
||||
function pocket_handle_screw(type) = type[2]; //! Screw type, can be countersunk or not
|
||||
function pocket_handle_panel_t(type) = type[3]; //! Thickness of the panel it is mounted in
|
||||
function pocket_handle_wall(type) = type[4]; //! Wall thickness
|
||||
function pocket_handle_rad(type) = type[5]; //! Min corner rad
|
||||
|
||||
function pocket_handle_flange(type) = //! Size of the flange
|
||||
let(w = pocket_handle_wall(type),
|
||||
f = washer_diameter(screw_washer(pocket_handle_screw(type))) + 2 + w,
|
||||
s = pocket_handle_hand_size(type))
|
||||
[s.x + 2 * f, s.y + 2 * f, w];
|
||||
|
||||
module pocket_handle_hole_positions(type) { //! Place children at screw hole positions
|
||||
f = pocket_handle_flange(type);
|
||||
h = pocket_handle_hand_size(type);
|
||||
x_pitch = (f.x + h.x) / 4;
|
||||
y_pitch = (f.y + h.y) / 4;
|
||||
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * x_pitch, y * y_pitch])
|
||||
children();
|
||||
}
|
||||
|
||||
module pocket_handle_holes(type, h = 0) { //! Panel cutout and screw holes
|
||||
hand = pocket_handle_hand_size(type);
|
||||
w = pocket_handle_wall(type);
|
||||
slot = [hand.x + 2 * w, hand.y + 2 * w];
|
||||
t = pocket_handle_panel_t(type);
|
||||
clearance = norm([slot.y, t]) - slot.y + 0.2; // has to be enough clearance for the diagonal to swing it in
|
||||
|
||||
extrude_if(h) {
|
||||
pocket_handle_hole_positions(type)
|
||||
drill(screw_clearance_radius(pocket_handle_screw(type)), 0);
|
||||
|
||||
rounded_square([slot.x + clearance, slot.y + clearance], pocket_handle_rad(type) + w + clearance / 2);
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle(type) { //! Generate STL for pocket_handle
|
||||
f = pocket_handle_flange(type);
|
||||
r = pocket_handle_rad(type);
|
||||
s = pocket_handle_slant(type);
|
||||
o = f.z * tan(s);
|
||||
h = pocket_handle_hand_size(type);
|
||||
t = pocket_handle_panel_t(type);
|
||||
w = pocket_handle_wall(type);
|
||||
screw = pocket_handle_screw(type) ;
|
||||
|
||||
stl("pocket_handle")
|
||||
union() {
|
||||
difference() {
|
||||
hull() {
|
||||
rounded_rectangle(f, r);
|
||||
|
||||
translate_z(f.z - eps)
|
||||
rounded_rectangle([f.x + 2 * o, f.y + 2 * o, eps], r + o);
|
||||
}
|
||||
hull() {
|
||||
rounded_rectangle([h.x, h.y, f.z + eps], r);
|
||||
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x + 2 * o, h.y + 2 * o, eps], r + o);
|
||||
}
|
||||
pocket_handle_hole_positions(type) {
|
||||
if(screw_head_height(screw))
|
||||
translate_z(-eps)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = f.z + 2 * eps, center = false);
|
||||
else
|
||||
screw_polysink(screw, h = 2 * f.z + eps, alt = true);
|
||||
}
|
||||
}
|
||||
|
||||
translate_z(f.z)
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
rounded_square([h.x + 2 * w, h.y + 2 * w], r + w);
|
||||
|
||||
rounded_square([h.x, h.y], r);
|
||||
}
|
||||
|
||||
translate_z(f.z + t)
|
||||
difference() {
|
||||
height = h.z - f.z - t;
|
||||
hull() {
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
|
||||
translate((height + w) * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
}
|
||||
|
||||
hull() {
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
|
||||
translate(height * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle_assembly(type) { //! Assembly with fasteners in place
|
||||
f = pocket_handle_flange(type);
|
||||
screw = pocket_handle_screw(type);
|
||||
nut = screw_nut(screw);
|
||||
t = pocket_handle_panel_t(type);
|
||||
washers = screw_head_height(screw) ? 2 : 1;
|
||||
screw_length = screw_length(screw, f.z + t, washers, nyloc = true);
|
||||
|
||||
translate_z(f.z + t / 2) hflip() {
|
||||
stl_colour(pp1_colour)
|
||||
pocket_handle(type);
|
||||
|
||||
pocket_handle_hole_positions(type) {
|
||||
translate_z(f.z + t)
|
||||
explode(15, true)
|
||||
nut_and_washer(nut, true);
|
||||
|
||||
vflip()
|
||||
if(washers == 2)
|
||||
screw_and_washer(screw, screw_length);
|
||||
else
|
||||
screw(screw, screw_length);
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@
|
||||
//!
|
||||
//! Add solvent or glue to make a permanent fixture.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
|
||||
interference = 0.0;
|
||||
|
||||
|
@@ -26,7 +26,9 @@
|
||||
//!
|
||||
//! It can also have printed feet on the base with the screws doubling up to hold the base on.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
use <../vitamins/screw.scad>
|
||||
use <../vitamins/washer.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
use <foot.scad>
|
||||
|
||||
@@ -129,28 +131,27 @@ module pbox_outer_shape(type) //! 2D outer shape of the box
|
||||
offset(pbox_wall(type) / 2) pbox_mid_shape(type);
|
||||
|
||||
module pbox_base(type) { //! Generate the STL for the base
|
||||
stl(str(pbox_name(type),"_base"));
|
||||
t = pbox_base(type);
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
offset(base_outset - 0.2)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
stl(str(pbox_name(type),"_base"))
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
offset(base_outset - 0.2)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
|
||||
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
|
||||
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
}
|
||||
|
||||
module pbox(type) { //! Generate the STL for the main case
|
||||
stl(pbox_name(type));
|
||||
|
||||
height = pbox_height(type);
|
||||
total_height = pbox_total_height(type);
|
||||
top_thickness = pbox_top(type);
|
||||
@@ -159,60 +160,61 @@ module pbox(type) { //! Generate the STL for the main case
|
||||
ledge_inset = base_outset - base_overlap;
|
||||
ledge_h = pbox_base(type) ? (ledge_outset - ledge_inset) * 2 : 0;
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(total_height)
|
||||
pbox_outer_shape(type);
|
||||
|
||||
if($children > 2)
|
||||
children(2);
|
||||
}
|
||||
stl(pbox_name(type))
|
||||
difference() {
|
||||
translate_z(top_thickness)
|
||||
union() {
|
||||
linear_extrude(height + eps)
|
||||
offset(-wall / 2) pbox_mid_shape(type);
|
||||
union() {
|
||||
linear_extrude(total_height)
|
||||
pbox_outer_shape(type);
|
||||
|
||||
translate_z(height) // Recess for the base
|
||||
linear_extrude(total_height - height)
|
||||
offset(base_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
// Ledge to support the lid
|
||||
if(ledge_h)
|
||||
translate_z(top_thickness + height - ledge_h)
|
||||
difference() {
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1, center = false);
|
||||
if($children > 2)
|
||||
children(2);
|
||||
}
|
||||
difference() {
|
||||
translate_z(top_thickness)
|
||||
union() {
|
||||
linear_extrude(height + eps)
|
||||
offset(-wall / 2) pbox_mid_shape(type);
|
||||
|
||||
hull() {
|
||||
linear_extrude(ledge_h + eps)
|
||||
offset(ledge_inset)
|
||||
translate_z(height) // Recess for the base
|
||||
linear_extrude(total_height - height)
|
||||
offset(base_outset)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
linear_extrude(eps)
|
||||
offset(ledge_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
insert_hole(pbox_insert(type));
|
||||
}
|
||||
// Ledge to support the lid
|
||||
if(ledge_h)
|
||||
translate_z(top_thickness + height - ledge_h)
|
||||
difference() {
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1);
|
||||
|
||||
// Corner lugs for inserts
|
||||
outset = wall + pbox_ridges(type).y;
|
||||
or = pbox_radius(type) + outset;
|
||||
inset = pbox_screw_inset(type) + outset;
|
||||
br = insert_boss_radius(pbox_insert(type), wall);
|
||||
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
|
||||
translate_z(height + top_thickness)
|
||||
pbox_screw_positions(type)
|
||||
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
|
||||
hull() {
|
||||
linear_extrude(ledge_h + eps)
|
||||
offset(ledge_inset)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
linear_extrude(eps)
|
||||
offset(ledge_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
insert_hole(pbox_insert(type));
|
||||
}
|
||||
|
||||
// Corner lugs for inserts
|
||||
outset = wall + pbox_ridges(type).y;
|
||||
or = pbox_radius(type) + outset;
|
||||
inset = pbox_screw_inset(type) + outset;
|
||||
br = insert_boss_radius(pbox_insert(type), wall);
|
||||
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
|
||||
translate_z(height + top_thickness)
|
||||
pbox_screw_positions(type)
|
||||
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
}
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
}
|
||||
|
||||
module pbox_inserts(type) //! Place the inserts for the base screws
|
||||
|
@@ -21,8 +21,8 @@
|
||||
//! Creative Commons - Attribution - Share Alike license (see <https://creativecommons.org/licenses/by-sa/3.0/>)
|
||||
//
|
||||
|
||||
include <../core.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
include <../utils/core/core.scad>
|
||||
use <../vitamins/pulley.scad>
|
||||
|
||||
printed_pulley_GT2_profile = [[0.747183,-0.5],[0.747183,0],[0.647876,0.037218],[0.598311,0.130528],[0.578556,0.238423],[0.547158,0.343077],[0.504649,0.443762],[0.451556,0.53975],[0.358229,0.636924],[0.2484,0.707276],[0.127259,0.750044],[0,0.76447],[-0.127259,0.750044],[-0.2484,0.707276],[-0.358229,0.636924],[-0.451556,0.53975],[-0.504797,0.443762],[-0.547291,0.343077],[-0.578605,0.238423],[-0.598311,0.130528],[-0.648009,0.037218],[-0.747183,0],[-0.747183,-0.5]];
|
||||
|
||||
@@ -93,7 +93,6 @@ module printed_pulley(type) { //! Draw a printable pulley
|
||||
or = pulley_od(type) / 2;
|
||||
screw_z = pulley_screw_z(type);
|
||||
|
||||
stl(str("printed_pulley_", type[0]));
|
||||
|
||||
module core() {
|
||||
translate_z(pulley_hub_length(type) + ft)
|
||||
@@ -129,54 +128,55 @@ module printed_pulley(type) { //! Draw a printable pulley
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? - hl : 0) {
|
||||
// hub
|
||||
if(hl)
|
||||
translate_z(printed_pulley_inverted(type) ? hl + w + 2 * ft : 0)
|
||||
if(screw_z && screw_z < hl)
|
||||
render()
|
||||
difference() {
|
||||
hub();
|
||||
stl(str("printed_pulley_", type[0]))
|
||||
translate_z(printed_pulley_inverted(type) ? - hl : 0) {
|
||||
// hub
|
||||
if(hl)
|
||||
translate_z(printed_pulley_inverted(type) ? hl + w + 2 * ft : 0)
|
||||
if(screw_z && screw_z < hl)
|
||||
render()
|
||||
difference() {
|
||||
hub();
|
||||
|
||||
screw_holes();
|
||||
}
|
||||
else
|
||||
hub();
|
||||
|
||||
// bottom flange
|
||||
translate_z(hl)
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(d = pulley_flange_dia(type));
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
// top flange
|
||||
translate_z(hl + ft + w) {
|
||||
// inner part, supported by core
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(r = or);
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
// outer part at 45 degrees for printing
|
||||
rotate_extrude()
|
||||
translate([or - eps, ft])
|
||||
vflip()
|
||||
right_triangle(ft, ft);
|
||||
}
|
||||
|
||||
if(screw_z && screw_z > hl)
|
||||
render()
|
||||
difference() { // T5 pulleys have screws through the teeth
|
||||
core();
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? pulley_height(type) + hl - 2 * screw_z : 0)
|
||||
screw_holes();
|
||||
}
|
||||
}
|
||||
else
|
||||
hub();
|
||||
|
||||
// bottom flange
|
||||
translate_z(hl)
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(d = pulley_flange_dia(type));
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
// top flange
|
||||
translate_z(hl + ft + w) {
|
||||
// inner part, supported by core
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(r = or);
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
// outer part at 45 degrees for printing
|
||||
rotate_extrude()
|
||||
translate([or - eps, ft])
|
||||
vflip()
|
||||
right_triangle(ft, ft);
|
||||
}
|
||||
|
||||
if(screw_z && screw_z > hl)
|
||||
render()
|
||||
difference() { // T5 pulleys have screws through the teeth
|
||||
core();
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? pulley_height(type) + hl - 2 * screw_z : 0)
|
||||
screw_holes();
|
||||
}
|
||||
else
|
||||
core();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module printed_pulley_assembly(type, colour = pp1_colour) //! Draw a printed pulley with its grub screws in place
|
||||
|
@@ -41,6 +41,7 @@ overlap = 6;
|
||||
cable_tie_inset = wall + 4;
|
||||
|
||||
function psu_shroud_extent(type) = 15 + wall; //! How far it extends beyond the PSU to clear the connections
|
||||
function psu_shroud_wall(type) = wall; //! The wall thickness
|
||||
function psu_shroud_depth(type) = //! Outside depth of the shroud
|
||||
psu_left_bay(type) + overlap + psu_shroud_extent(type);
|
||||
|
||||
@@ -79,8 +80,6 @@ module psu_shroud_holes(type, cable_d, cables = 1) {
|
||||
}
|
||||
|
||||
module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file for a specified ssr and cable
|
||||
stl(str("psu_shroud_", name));
|
||||
|
||||
extent = psu_shroud_extent(type);
|
||||
depth = psu_shroud_depth(type);
|
||||
width = psu_shroud_width(type);
|
||||
@@ -109,38 +108,40 @@ module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file f
|
||||
}
|
||||
}
|
||||
|
||||
// base and sides
|
||||
translate([centre_x, -centre_y]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
stl(str("psu_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([centre_x, -centre_y]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
linear_extrude(height)
|
||||
difference() {
|
||||
linear_extrude(height)
|
||||
difference() {
|
||||
shape();
|
||||
|
||||
translate([depth / 2, width / 2 - 5])
|
||||
square([2 * (depth - extent + terminal_clearance), 10], center = true);
|
||||
}
|
||||
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
|
||||
shape();
|
||||
|
||||
translate([depth / 2, width / 2 - 5])
|
||||
square([2 * (depth - extent + terminal_clearance), 10], center = true);
|
||||
}
|
||||
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
|
||||
shape();
|
||||
}
|
||||
// cable slots
|
||||
for(i = [0 : 1 : cables - 1])
|
||||
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
|
||||
rotate([90, 0, 90])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
// cable slots
|
||||
for(i = [0 : 1 : cables - 1])
|
||||
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
|
||||
rotate([90, 0, 90])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert lugs
|
||||
mirror([0, 1, 0])
|
||||
psu_shroud_hole_positions(type)
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert lugs
|
||||
mirror([0, 1, 0])
|
||||
psu_shroud_hole_positions(type)
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
}
|
||||
|
||||
module psu_shroud_assembly(type, cable_d, name, cables = 1) //! The printed parts with inserts fitted
|
||||
assembly(str("PSU_shroud_", name), ngb = true) {
|
||||
@@ -154,7 +155,7 @@ assembly(str("PSU_shroud_", name), ngb = true) {
|
||||
insert(insert);
|
||||
}
|
||||
|
||||
module psu_shroud_fastened_assembly(type, cable_d, thickness, name, cables = 1) //! Assembly with screws in place
|
||||
module psu_shroud_fastened_assembly(type, cable_d, thickness, name, cables = 1, screw = screw) //! Assembly with screws in place
|
||||
{
|
||||
screw_length = screw_length(screw,thickness + counter_bore, 2, true);
|
||||
|
||||
|
@@ -47,7 +47,6 @@ module ribbon_clamp_holes(ways, h = 20, screw = screw) //! Drill screw holes
|
||||
|
||||
module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of ways
|
||||
screw_d = screw_radius(screw) * 2;
|
||||
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""));
|
||||
|
||||
pitch = ribbon_clamp_hole_pitch(ways, screw);
|
||||
d = ribbon_clamp_width(screw);
|
||||
@@ -55,34 +54,36 @@ module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of
|
||||
t = round_to_layer(ribbon_clamp_slot_depth() + wall);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
translate_z(h - t / 2)
|
||||
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
|
||||
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""))
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
translate_z(h - t / 2)
|
||||
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
|
||||
|
||||
translate_z(1)
|
||||
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
|
||||
translate_z(1)
|
||||
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
|
||||
}
|
||||
ribbon_clamp_hole_positions(ways, screw, -1)
|
||||
cylinder(d = d, h = h);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw, 1)
|
||||
cylinder(d = d, h = h);
|
||||
}
|
||||
ribbon_clamp_hole_positions(ways, screw, -1)
|
||||
cylinder(d = d, h = h);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw, 1)
|
||||
cylinder(d = d, h = h);
|
||||
}
|
||||
|
||||
translate_z(h)
|
||||
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
translate_z(h)
|
||||
rotate(22.5)
|
||||
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
|
||||
}
|
||||
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
translate_z(h)
|
||||
rotate(22.5)
|
||||
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
|
||||
}
|
||||
}
|
||||
|
||||
module ribbon_clamp_assembly(ways, screw = screw) pose([55, 180, 25]) //! Printed part with inserts in place
|
||||
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""), ngb = true) {
|
||||
module ribbon_clamp_assembly(ways, screw = screw) //! Printed part with inserts in place
|
||||
pose([55, 180, 25])
|
||||
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""), ngb = true) {
|
||||
h = ribbon_clamp_height(screw);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
|
@@ -34,27 +34,26 @@ knob_height = knob_stem_h + knob_thickness;
|
||||
function knob_height() = knob_height;
|
||||
|
||||
module screw_knob(screw) { //! Generate the STL for a knob to fit the specified hex screw
|
||||
stl(str("screw_knob_M", screw_radius(screw) * 20));
|
||||
|
||||
knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;
|
||||
|
||||
function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;
|
||||
|
||||
union() {
|
||||
render() difference() {
|
||||
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
|
||||
stl(str("screw_knob_M", screw_radius(screw) * 20))
|
||||
union() {
|
||||
render() difference() {
|
||||
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
|
||||
|
||||
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
|
||||
rotate(45)
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
linear_extrude(knob_thickness, convexity = 3)
|
||||
difference() {
|
||||
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
|
||||
|
||||
circle(knob_stem_r - eps);
|
||||
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
|
||||
rotate(45)
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
}
|
||||
linear_extrude(knob_thickness, convexity = 3)
|
||||
difference() {
|
||||
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
|
||||
|
||||
circle(knob_stem_r - eps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Place the screw through the printed part
|
||||
|
@@ -41,7 +41,6 @@ height = base_thickness + box_height;
|
||||
function socket_box_depth() = height; //! Outside depth of the backbox
|
||||
|
||||
module socket_box(type) { //! Generate STL of the backbox for the specified socket
|
||||
stl(str("socket_box_",type[0]));
|
||||
|
||||
screw = mains_socket_screw(type);
|
||||
screw_clearance_radius = screw_clearance_radius(screw);
|
||||
@@ -51,37 +50,38 @@ module socket_box(type) { //! Generate STL of the backbox for the specified sock
|
||||
insert_boss = mains_socket_insert_boss(type);
|
||||
insert_hole_radius = insert_hole_radius(insert);
|
||||
|
||||
difference() {
|
||||
linear_extrude(height, convexity = 5)
|
||||
face_plate(type);
|
||||
|
||||
stl(str("socket_box_",type[0]))
|
||||
difference() {
|
||||
translate_z(base_thickness)
|
||||
linear_extrude(height, convexity = 5)
|
||||
offset(-wall) offset(1) face_plate(type);
|
||||
linear_extrude(height, convexity = 5)
|
||||
face_plate(type);
|
||||
|
||||
for(side = [-1, 1])
|
||||
hull()
|
||||
for(x = [1, 2])
|
||||
translate([side * mains_socket_pitch(type) / x, 0])
|
||||
cylinder(d = insert_boss, h = 100);
|
||||
}
|
||||
//
|
||||
// Socket holes
|
||||
//
|
||||
translate_z(height)
|
||||
mains_socket_hole_positions(type) {
|
||||
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
|
||||
difference() {
|
||||
translate_z(base_thickness)
|
||||
linear_extrude(height, convexity = 5)
|
||||
offset(-wall) offset(1) face_plate(type);
|
||||
|
||||
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
|
||||
for(side = [-1, 1])
|
||||
hull()
|
||||
for(x = [1, 2])
|
||||
translate([side * mains_socket_pitch(type) / x, 0])
|
||||
cylinder(d = insert_boss, h = 100);
|
||||
}
|
||||
//
|
||||
// Cable hole
|
||||
//
|
||||
translate([cable_x, cable_y(type), cable_z])
|
||||
rotate([90, 0, 0])
|
||||
teardrop_plus(r = cable_d / 2, h = 30);
|
||||
}
|
||||
//
|
||||
// Socket holes
|
||||
//
|
||||
translate_z(height)
|
||||
mains_socket_hole_positions(type) {
|
||||
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
|
||||
|
||||
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
|
||||
}
|
||||
//
|
||||
// Cable hole
|
||||
//
|
||||
translate([cable_x, cable_y(type), cable_z])
|
||||
rotate([90, 0, 0])
|
||||
teardrop_plus(r = cable_d / 2, h = 30);
|
||||
}
|
||||
}
|
||||
|
||||
module socket_box_MKLOGIC_stl() socket_box(MKLOGIC);
|
||||
|
@@ -61,49 +61,50 @@ module ssr_shroud_holes(type, cable_d) { //! Drill the screw and ziptie holes
|
||||
}
|
||||
|
||||
module ssr_shroud(type, cable_d, name) { //! Generate the STL file for a specified ssr and cable
|
||||
stl(str("ssr_shroud_", name));
|
||||
|
||||
width = ssr_shroud_width(type);
|
||||
depth = ssr_length(type) / 3 + ssr_shroud_extent(type, cable_d);
|
||||
height = ssr_shroud_height(type);
|
||||
cable_x = ssr_shroud_cable_x(type, cable_d);
|
||||
center_x = -ssr_length(type) / 6 - depth / 2;
|
||||
|
||||
// base and sides
|
||||
translate([center_x, 0]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
|
||||
linear_extrude(height) difference() {
|
||||
round(or = wall / 2 - eps, ir = 0) difference() {
|
||||
rounded_square([depth, width], rad);
|
||||
stl(str("ssr_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([center_x, 0]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
|
||||
linear_extrude(height) difference() {
|
||||
round(or = wall / 2 - eps, ir = 0) difference() {
|
||||
rounded_square([depth, width], rad);
|
||||
|
||||
translate([depth / 2, 0])
|
||||
square([2 * rad, width], center = true);
|
||||
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
|
||||
|
||||
translate([depth / 2, 0])
|
||||
square([2 * rad, width], center = true);
|
||||
|
||||
}
|
||||
translate([cable_x - center_x, 0])
|
||||
square([cable_d, width + 1], center = true);
|
||||
}
|
||||
translate([cable_x - center_x, 0])
|
||||
square([cable_d, width + 1], center = true);
|
||||
}
|
||||
}
|
||||
// cable slots
|
||||
for(side = [-1, 1])
|
||||
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
// cable slots
|
||||
for(side = [-1, 1])
|
||||
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert boss
|
||||
ssr_shroud_hole_positions(type)
|
||||
vflip()
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert boss
|
||||
ssr_shroud_hole_positions(type)
|
||||
vflip()
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
}
|
||||
|
||||
module ssr_shroud_assembly(type, cable_d, name) //! The printed parts with inserts fitted
|
||||
|
@@ -75,32 +75,29 @@ module strap_holes(length, type = strap, h = 100) //! The panel cut outs
|
||||
strap_boss_shape(type);
|
||||
|
||||
module strap(length, type = strap) { //! Generate the STL for the rubber strap
|
||||
stl("strap");
|
||||
|
||||
len = length - 2 * (wall + clearance);
|
||||
w = strap_width(type);
|
||||
|
||||
linear_extrude(strap_thickness(type), convexity = 3)
|
||||
difference() {
|
||||
rounded_square([len, w], w / 2 - eps);
|
||||
stl("strap")
|
||||
linear_extrude(strap_thickness(type), convexity = 3)
|
||||
difference() {
|
||||
rounded_square([len, w], w / 2 - eps);
|
||||
|
||||
for(end = [-1, 1])
|
||||
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
|
||||
rotate(end * 90 + 90)
|
||||
hull() {
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
|
||||
translate([strap_extension(type) / 2, 0])
|
||||
for(end = [-1, 1])
|
||||
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
|
||||
rotate(end * 90 + 90)
|
||||
hull() {
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
}
|
||||
}
|
||||
|
||||
translate([strap_extension(type) / 2, 0])
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module strap_end(type = strap) { //! Generate the STL for end piece
|
||||
stl("strap_end");
|
||||
|
||||
z1 = strap_height(type) - strap_thickness(type) - clearance;
|
||||
z2 = strap_height(type) + strap_key(type);
|
||||
r1 = strap_boss_r(type) - 1;
|
||||
@@ -121,42 +118,43 @@ module strap_end(type = strap) { //! Generate the STL for end piece
|
||||
circle(r1);
|
||||
}
|
||||
|
||||
union() {
|
||||
linear_extrude(z1)
|
||||
with_hole()
|
||||
outer();
|
||||
|
||||
translate_z(z1)
|
||||
linear_extrude(strap_height(type) - z1)
|
||||
difference() {
|
||||
stl("strap_end")
|
||||
union() {
|
||||
linear_extrude(z1)
|
||||
with_hole()
|
||||
outer();
|
||||
|
||||
hull() {
|
||||
translate([0, -strap_width(type) / 2 - clearance])
|
||||
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
|
||||
translate_z(z1)
|
||||
linear_extrude(strap_height(type) - z1)
|
||||
difference() {
|
||||
outer();
|
||||
|
||||
translate([-strap_extension(type) / 2, 0])
|
||||
circle(d = strap_width(type) + 2 * clearance);
|
||||
hull() {
|
||||
translate([0, -strap_width(type) / 2 - clearance])
|
||||
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
|
||||
|
||||
translate([-strap_extension(type) / 2, 0])
|
||||
circle(d = strap_width(type) + 2 * clearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linear_extrude(strap_height(type) - layer_height)
|
||||
with_hole()
|
||||
strap_boss_shape(type);
|
||||
linear_extrude(strap_height(type) - layer_height)
|
||||
with_hole()
|
||||
strap_boss_shape(type);
|
||||
|
||||
linear_extrude(z2)
|
||||
with_hole()
|
||||
offset(cnc_bit_r)
|
||||
offset(-step - cnc_bit_r)
|
||||
strap_boss_shape(type);
|
||||
linear_extrude(z2)
|
||||
with_hole()
|
||||
offset(cnc_bit_r)
|
||||
offset(-step - cnc_bit_r)
|
||||
strap_boss_shape(type);
|
||||
|
||||
render() difference() {
|
||||
cylinder(r = r1 + eps, h = z2);
|
||||
render() difference() {
|
||||
cylinder(r = r1 + eps, h = z2);
|
||||
|
||||
translate_z(z2)
|
||||
insert_hole(strap_insert(type), counterbore);
|
||||
translate_z(z2)
|
||||
insert_hole(strap_insert(type), counterbore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//! * Place the insert into the hole and push home with a soldering iron with a tapered bit heated to 200°C.
|
||||
|
@@ -81,7 +81,7 @@ def scrape_code(scad_file):
|
||||
match = re.match(r'^function (.*?\(.*?\)).*?(?://! ?(.*))$', line)
|
||||
if match:
|
||||
functions[match.group(1)] = match.group(2)
|
||||
match = re.match(r'^module (.*?\(.*?\)).*?(?://! ?(.*))$', line)
|
||||
match = re.match(r'^module (.*?\(.*\)).*?(?://! ?(.*))$', line)
|
||||
if match:
|
||||
modules[match.group(1)] = match.group(2)
|
||||
|
||||
|
@@ -31,6 +31,12 @@ from set_config import *
|
||||
import json
|
||||
import re
|
||||
|
||||
try:
|
||||
import parts
|
||||
got_parts_py = True
|
||||
except:
|
||||
got_parts_py = False
|
||||
|
||||
def find_scad_file(mname):
|
||||
for filename in os.listdir(source_dir):
|
||||
if filename[-5:] == ".scad":
|
||||
@@ -46,6 +52,18 @@ def find_scad_file(mname):
|
||||
return filename
|
||||
return None
|
||||
|
||||
def main_assembly(target):
|
||||
file = None
|
||||
if target:
|
||||
assembly = target + "_assembly"
|
||||
file = find_scad_file(assembly)
|
||||
if not file:
|
||||
assembly = "main_assembly"
|
||||
file = find_scad_file(assembly)
|
||||
if not file:
|
||||
raise Exception("can't find source for " + assembly)
|
||||
return assembly, file
|
||||
|
||||
class Part:
|
||||
def __init__(self, args):
|
||||
self.count = 1
|
||||
@@ -61,6 +79,7 @@ class BOM:
|
||||
self.name = name
|
||||
self.big = None
|
||||
self.ngb = False
|
||||
self.zoomed = 0
|
||||
self.count = 1
|
||||
self.vitamins = {}
|
||||
self.printed = {}
|
||||
@@ -75,6 +94,7 @@ class BOM:
|
||||
"name" : self.name,
|
||||
"big" : self.big,
|
||||
"ngb" : self.ngb,
|
||||
"zoomed" : self.zoomed,
|
||||
"count" : self.count,
|
||||
"assemblies" : assemblies,
|
||||
"vitamins" : {v : self.vitamins[v].data() for v in self.vitamins},
|
||||
@@ -115,6 +135,33 @@ class BOM:
|
||||
return ass
|
||||
return ass.replace("assembly", "assemblies")
|
||||
|
||||
def print_CSV(self, file = None):
|
||||
i = 0
|
||||
for part in sorted(self.vitamins):
|
||||
i += 1
|
||||
if ': ' in part:
|
||||
part_no, description = part.split(': ')
|
||||
else:
|
||||
part_no, description = "", part
|
||||
qty = self.vitamins[part].count
|
||||
if got_parts_py:
|
||||
match = re.match(r'^.*\((.*?)[,\)].*$', part_no)
|
||||
if match and not match.group(1).startswith('"'):
|
||||
part_no = part_no.replace('(' + match.group(1), '_' + match.group(1) + '(').replace('(, ', '(')
|
||||
func = 'parts.' + part_no.replace('(', '(%d, ' % qty).replace(', )', ')')
|
||||
func = func.replace('true', 'True').replace('false', 'False').replace('undef', 'None')
|
||||
try:
|
||||
price, url = eval(func)
|
||||
print("'%s',%3d,%.2f,'=B%d*C%d',%s" % (description, qty, price, i, i, url), file=file)
|
||||
except:
|
||||
if part_no:
|
||||
print("%s not found in parts.py" % func)
|
||||
print("'%s',%3d" % (description, qty), file=file)
|
||||
else:
|
||||
print("'%s',%3d" % (description, qty), file=file)
|
||||
if got_parts_py:
|
||||
print(",'=SUM(B1:B%d)',,'=SUM(D1:D%d)'" %(i, i), file=file)
|
||||
|
||||
def print_bom(self, breakdown, file = None):
|
||||
if self.vitamins:
|
||||
print("Vitamins:", file=file)
|
||||
@@ -219,28 +266,20 @@ def parse_bom(file = "openscad.log", name = None):
|
||||
return main
|
||||
|
||||
def usage():
|
||||
print("\nusage:\n\tbom [target_config] [<accessory_name>_assembly] - Generate BOMs for a project or an accessory to a project.")
|
||||
print("\nusage:\n\tbom [target_config] - Generate BOMs for a project.")
|
||||
sys.exit(1)
|
||||
|
||||
def boms(target = None, assembly = None):
|
||||
def boms(target = None):
|
||||
try:
|
||||
bom_dir = set_config(target, usage) + "bom"
|
||||
if assembly:
|
||||
bom_dir += "/accessories"
|
||||
if not os.path.isdir(bom_dir):
|
||||
os.makedirs(bom_dir)
|
||||
else:
|
||||
assembly = "main_assembly"
|
||||
if os.path.isdir(bom_dir):
|
||||
shutil.rmtree(bom_dir)
|
||||
sleep(0.1)
|
||||
os.makedirs(bom_dir)
|
||||
if os.path.isdir(bom_dir):
|
||||
shutil.rmtree(bom_dir)
|
||||
sleep(0.1)
|
||||
os.makedirs(bom_dir)
|
||||
#
|
||||
# Find the scad file that makes the module
|
||||
# Find the scad file that makes the main assembly
|
||||
#
|
||||
scad_file = find_scad_file(assembly)
|
||||
if not scad_file:
|
||||
raise Exception("can't find source for " + assembly)
|
||||
assembly, scad_file = main_assembly(target)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
@@ -257,8 +296,9 @@ def boms(target = None, assembly = None):
|
||||
|
||||
main = parse_bom("openscad.echo", assembly)
|
||||
|
||||
if assembly == "main_assembly":
|
||||
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
|
||||
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
|
||||
|
||||
main.print_CSV(open(bom_dir + "/bom.csv","wt"))
|
||||
|
||||
for ass in main.assemblies:
|
||||
with open(bom_dir + "/" + ass + ".txt", "wt") as f:
|
||||
@@ -276,20 +316,8 @@ def boms(target = None, assembly = None):
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 3: usage()
|
||||
if len(sys.argv) > 2: usage()
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
target, assembly = sys.argv[1], sys.argv[2]
|
||||
else:
|
||||
if len(sys.argv) == 2:
|
||||
if sys.argv[1][-9:] == "_assembly":
|
||||
target, assembly = None, sys.argv[1]
|
||||
else:
|
||||
target, assembly = sys.argv[1], None
|
||||
else:
|
||||
target, assembly = None, None
|
||||
target = sys.argv[1] if len(sys.argv) == 2 else None
|
||||
|
||||
if assembly:
|
||||
if assembly[-9:] != "_assembly": usage()
|
||||
|
||||
boms(target, assembly)
|
||||
boms(target)
|
||||
|
166
scripts/changelog.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
#! Creates the changelog from the git log
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
from tests import do_cmd
|
||||
|
||||
filename = 'CHANGELOG.md'
|
||||
|
||||
def tag_version(t):
|
||||
""" Format a version tag """
|
||||
return 'v%d.%d.%d' % t
|
||||
|
||||
def initials(name):
|
||||
""" Convert full name to initials with a tooltip """
|
||||
i = ''.join([n[0].upper() + '.' for n in name.split(' ')])
|
||||
return '[%s](# "%s")' % (i, name)
|
||||
|
||||
def get_remote_url():
|
||||
""" Get the git remote URL for the repository """
|
||||
url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"]).decode("utf-8").strip("\n")
|
||||
if url.startswith("git@"):
|
||||
url = url.replace(":", "/", 1).replace("git@", "https://", 1)
|
||||
if url.endswith(".git"):
|
||||
url = url[:-4]
|
||||
return url
|
||||
|
||||
def iscode(word):
|
||||
""" try to guess if the word is code """
|
||||
endings = ['()', '*']
|
||||
starts = ['$', '--']
|
||||
anywhere = ['.', '_', '=', '[', '/']
|
||||
words = ['center', 'false', 'true', 'ngb']
|
||||
|
||||
for w in words:
|
||||
if word == w:
|
||||
return True
|
||||
|
||||
for end in endings:
|
||||
if word.endswith(end):
|
||||
return True
|
||||
|
||||
for start in starts:
|
||||
if word.startswith(start):
|
||||
return True
|
||||
|
||||
for any in anywhere:
|
||||
if word.find(any) >= 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def codify(word, url):
|
||||
""" if a word is deemed code enclose it backticks """
|
||||
if word:
|
||||
if re.match(r'#[0-9]+', word):
|
||||
return '[%s](%s "show issue")' % (word, url + '/issues/' + word[1:])
|
||||
if iscode(word):
|
||||
return '`' + word + '`'
|
||||
return word
|
||||
|
||||
|
||||
def fixup_comment(comment, url):
|
||||
""" markup code words and fix new paragraphs """
|
||||
result = ''
|
||||
word = ''
|
||||
code = False
|
||||
for i, c in enumerate(comment):
|
||||
if c == '`' or code: # Already a code block
|
||||
result += c # Copy verbatim
|
||||
if c == '`': code = not code # Keep track of state
|
||||
else:
|
||||
if c in ' \n' or (c == '.' and (i + 1 == len(comment) or comment[i + 1] in ' \n')): # if a word terminator
|
||||
result += codify(word, url) + c # Add codified word before terminator
|
||||
word = ''
|
||||
else:
|
||||
word += c # Accumulate next word
|
||||
result += codify(word, url) # In case comment ends without a terminator
|
||||
return result.replace('\n\n','\n\n * ') # Give new paragraphs a bullet point
|
||||
|
||||
class Commit(): # members dynamically added from commit_fields
|
||||
pass
|
||||
|
||||
blurb = """
|
||||
# %s Changelog
|
||||
This changelog is generated by `changelog.py` using manually added semantic version tags to classify commits as breaking changes, additions or fixes.
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
url = get_remote_url()
|
||||
|
||||
commit_fields = {
|
||||
'hash': "%H|", # commit commit_hash
|
||||
'tag': "%D|", # tag
|
||||
'author': "%aN|", # author name
|
||||
'date': " %as|", # author date short form
|
||||
'comment': "%B~" # body
|
||||
}
|
||||
|
||||
# Produce the git log
|
||||
format = ''.join([v for k, v in commit_fields.items()])
|
||||
text = subprocess.check_output(["git", "log", "--topo-order", "--format=" + format]).decode("utf-8")
|
||||
|
||||
# Process the log into a list of Commit objects
|
||||
commits = []
|
||||
for line in text.split('~'):
|
||||
line = line.strip('\n')
|
||||
if line:
|
||||
fields = line.split('|')
|
||||
commit = Commit()
|
||||
for i, k in enumerate(commit_fields):
|
||||
exec('commit.%s = """%s"""' % (k, fields[i]), locals())
|
||||
# Convert version tag to tuple
|
||||
if commit.tag:
|
||||
match = re.match(r'.*tag: v([0-9]+)\.([0-9]+)\.([0-9]+).*', commit.tag)
|
||||
commit.tag = (int(match.group(1)), int(match.group(2)), int(match.group(3))) if match else ''
|
||||
commits.append(commit)
|
||||
|
||||
# Format the results from the Commit objects
|
||||
with open(filename, "wt") as file:
|
||||
print(blurb % url.split('/')[-1], file = file)
|
||||
for i, c in enumerate(commits):
|
||||
if c.tag:
|
||||
ver = tag_version(c.tag)
|
||||
level, type = (3, 'Fixes') if c.tag[2] else (2, 'Additions') if c.tag[1] else (1, 'Breaking Changes') if c.tag[0] else (1, 'First publicised version')
|
||||
|
||||
# Find the previous tagged commit
|
||||
j = i + 1
|
||||
diff = ''
|
||||
while j < len(commits):
|
||||
if commits[j].tag:
|
||||
last_ver = tag_version(commits[j].tag)
|
||||
diff = '[...](%s "diff with %s")' % (url + '/compare/' + last_ver + '...' + ver, last_ver)
|
||||
break
|
||||
j += 1
|
||||
|
||||
# Print verson info
|
||||
print('%s [%s](%s "show release") %s %s' % ('#' * (level + 1), ver, url + '/releases/tag/' + ver, type, diff), file = file)
|
||||
|
||||
# Print commits excluding merges
|
||||
|
||||
if not c.comment.startswith('Merge branch') and not c.comment.startswith('Merge pull') and not re.match(r'U..ated changelog.*', c.comment):
|
||||
print('* %s [`%s`](%s "show commit") %s %s\n' % (c.date, c.hash[:7], url + '/commit/' + c.hash, initials(c.author), fixup_comment(c.comment, url)), file = file)
|
||||
do_cmd(('codespell -w -L od ' + filename).split())
|
@@ -18,6 +18,7 @@
|
||||
#
|
||||
import os
|
||||
from set_config import source_dir
|
||||
from colorama import Fore
|
||||
|
||||
def mtime(file):
|
||||
if os.path.isfile(file):
|
||||
@@ -41,13 +42,13 @@ def read_deps(dname):
|
||||
def check_deps(target, dname):
|
||||
target_mtime = mtime(target)
|
||||
if not target_mtime:
|
||||
return target + " missing"
|
||||
return Fore.CYAN + target + " missing" + Fore.WHITE
|
||||
if not os.path.isfile(dname):
|
||||
return "no deps"
|
||||
return Fore.CYAN + "no deps" + Fore.WHITE
|
||||
deps = read_deps(dname)
|
||||
for dep in deps:
|
||||
if mtime(dep) > target_mtime:
|
||||
return dep + ' changed'
|
||||
return Fore.CYAN + dep + ' changed' + Fore.WHITE
|
||||
return None
|
||||
|
||||
def source_dirs(bom_dir):
|
||||
|
@@ -28,7 +28,10 @@ from set_config import *
|
||||
import time
|
||||
import times
|
||||
from deps import *
|
||||
from tmpdir import *
|
||||
import json
|
||||
import shutil
|
||||
from colorama import Fore, init
|
||||
|
||||
def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
#
|
||||
@@ -43,7 +46,7 @@ def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
if words:
|
||||
last_word = words[-1]
|
||||
if last_word.endswith(suffix):
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
return part_files
|
||||
|
||||
def usage(t):
|
||||
@@ -62,12 +65,20 @@ def make_parts(target, part_type, parts = None):
|
||||
#
|
||||
top_dir = set_config(target, lambda: usage(part_type))
|
||||
target_dir = top_dir + part_type + 's'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
old_deps = top_dir + 'deps' #old location
|
||||
if os.path.isdir(old_deps):
|
||||
shutil.rmtree(old_deps)
|
||||
|
||||
times.read_times(target_dir)
|
||||
#
|
||||
# Decide which files to make
|
||||
@@ -120,18 +131,19 @@ def make_parts(target, part_type, parts = None):
|
||||
changed = check_deps(part_file, dname)
|
||||
changed = times.check_have_time(changed, part)
|
||||
if part_type == 'stl' and not changed and not part in bounds_map:
|
||||
changed = "No bounds"
|
||||
changed = Fore.CYAN + "No bounds" + Fore.WHITE
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
part_maker_name = part_type + ".scad"
|
||||
part_maker_name = tmp_dir + '/' + part_type + ".scad"
|
||||
with open(part_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("include <NopSCADlib/global_defs.scad>\n")
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
|
||||
openscad.run("-o", part_file, part_maker_name, "-D$bom=1", "-d", dname)
|
||||
times.add_time(part, t)
|
||||
if part_type == 'stl':
|
||||
bounds = c14n_stl.canonicalise(part_file)
|
||||
@@ -145,6 +157,10 @@ def make_parts(target, part_type, parts = None):
|
||||
with open(bounds_fname, 'w') as outfile:
|
||||
json.dump(bounds_map, outfile, indent = 4)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# List the ones we didn't find
|
||||
#
|
||||
if targets:
|
||||
|
@@ -68,9 +68,10 @@ def gallery(force):
|
||||
match = re.match(r"^(#+).*$", line)
|
||||
if match:
|
||||
line = '#' + line
|
||||
if line == '---\n':
|
||||
break;
|
||||
print(line[:-1], file = output_file)
|
||||
if line == '---\n' or line == '<span></span>\n':
|
||||
break
|
||||
if line != '<a name="TOP"></a>\n':
|
||||
print(line[:-1], file = output_file)
|
||||
else:
|
||||
print(Fore.MAGENTA + "Can't find", document, Fore.WHITE);
|
||||
with open(target_dir + "/readme.html", "wt") as html_file:
|
||||
|
@@ -25,19 +25,25 @@ from __future__ import print_function
|
||||
import subprocess, sys
|
||||
|
||||
def run_list(args, silent = False, verbose = False):
|
||||
cmd = ["openscad", "--hardwarnings"] + args
|
||||
cmd = ["openscad"] + args + ["--hardwarnings"]
|
||||
if not silent:
|
||||
for arg in cmd:
|
||||
print(arg, end=" ")
|
||||
print()
|
||||
with open("openscad.log", "w") as log:
|
||||
rc = subprocess.call(cmd, stdout = log, stderr = log)
|
||||
for line in open("openscad.log", "rt"):
|
||||
log_file = "openscad.echo" if "openscad.echo" in cmd else "openscad.log"
|
||||
bad = False
|
||||
for line in open(log_file, "rt"):
|
||||
if verbose or 'ERROR:' in line or 'WARNING:' in line:
|
||||
bad = True
|
||||
print(line[:-1])
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
|
||||
if bad:
|
||||
sys.exit(1)
|
||||
|
||||
def run(*args):
|
||||
run_list(list(args), False)
|
||||
|
||||
|
@@ -17,9 +17,10 @@
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Set command line options from enviroment variables and check if they have changed
|
||||
# Set command line options from environment variables and check if they have changed
|
||||
|
||||
import json, os, deps
|
||||
from colorama import Fore, init
|
||||
|
||||
def check_options(dir = '.'):
|
||||
global options, options_mtime
|
||||
@@ -37,7 +38,7 @@ def check_options(dir = '.'):
|
||||
|
||||
def have_changed(changed, target):
|
||||
if not changed and deps.mtime(target) < options_mtime:
|
||||
return "command line options changed"
|
||||
return Fore.CYAN + "command line options changed" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def list():
|
||||
|
@@ -26,8 +26,10 @@ import sys
|
||||
import c14n_stl
|
||||
from set_config import *
|
||||
from deps import *
|
||||
from shutil import copyfile
|
||||
import shutil
|
||||
import re
|
||||
import time
|
||||
import times
|
||||
|
||||
source_dirs = { "stl" : "platters", "dxf" : "panels" }
|
||||
target_dirs = { "stl" : "printed", "dxf" : "routed" }
|
||||
@@ -41,22 +43,32 @@ def plateup(target, part_type, usage = None):
|
||||
target_dir = parts_dir + '/' + target_dirs[part_type]
|
||||
source_dir1 = source_dirs[part_type]
|
||||
source_dir2 = top_dir + source_dirs[part_type]
|
||||
|
||||
#
|
||||
# Loop through source directories
|
||||
#
|
||||
used = []
|
||||
all_used = []
|
||||
all_sources = []
|
||||
all_parts = []
|
||||
read_times = False
|
||||
for dir in [source_dir1, source_dir2]:
|
||||
if not os.path.isdir(dir):
|
||||
continue
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not read_times:
|
||||
times.read_times(target_dir)
|
||||
read_times = True
|
||||
#
|
||||
# Make the deps dir
|
||||
#
|
||||
deps_dir = dir + "/deps"
|
||||
deps_dir = parts_dir + "/deps"
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
if os.path.isdir(dir + '/deps'): #old deps
|
||||
shutil.rmtree(dir + '/deps')
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
@@ -65,40 +77,55 @@ def plateup(target, part_type, usage = None):
|
||||
#
|
||||
# Run OpenSCAD on the source files to make the targets
|
||||
#
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
for src in sources:
|
||||
src_file = dir + '/' + src
|
||||
part_file = target_dir + '/' + src[:-4] + part_type
|
||||
part = src[:-4] + part_type
|
||||
all_parts.append(part)
|
||||
part_file = target_dir + '/' + part
|
||||
uses_file = deps_dir + '/' + src[:-4] + 'txt'
|
||||
dname = deps_name(deps_dir, src)
|
||||
changed = check_deps(part_file, dname)
|
||||
oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
|
||||
changed = check_deps(oldest, dname)
|
||||
used = []
|
||||
if changed:
|
||||
print(changed)
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, src_file)
|
||||
t = time.time()
|
||||
openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
|
||||
if part_type == 'stl':
|
||||
c14n_stl.canonicalise(part_file)
|
||||
times.add_time(part, t)
|
||||
log_name = 'openscad.log'
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "wt") as file:
|
||||
for part in used:
|
||||
print(part, file = file)
|
||||
else:
|
||||
log_name = 'openscad.echo'
|
||||
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "rt") as file:
|
||||
for line in file:
|
||||
used.append(line[:-1])
|
||||
all_used += used
|
||||
|
||||
copied = []
|
||||
if all_sources:
|
||||
#
|
||||
# Copy files that are not included
|
||||
#
|
||||
for file in os.listdir(parts_dir):
|
||||
if file.endswith('.' + part_type) and not file in used:
|
||||
if file.endswith('.' + part_type) and not file in all_used:
|
||||
src = parts_dir + '/' + file
|
||||
dst = target_dir + '/' + file
|
||||
if mtime(src) > mtime(dst):
|
||||
print("Copying %s to %s" % (src, dst))
|
||||
copyfile(src, dst)
|
||||
shutil.copyfile(src, dst)
|
||||
copied.append(file)
|
||||
#
|
||||
# Remove any cruft
|
||||
@@ -109,3 +136,12 @@ def plateup(target, part_type, usage = None):
|
||||
if not file in targets and not file in copied:
|
||||
print("Removing %s" % file)
|
||||
os.remove(target_dir + '/' + file)
|
||||
|
||||
targets = [file[:-4] + 'txt' for file in all_sources]
|
||||
for file in os.listdir(deps_dir):
|
||||
if file.endswith('.' + 'txt'):
|
||||
if not file in targets:
|
||||
print("Removing %s" % file)
|
||||
os.remove(deps_dir + '/' + file)
|
||||
|
||||
times.print_times(all_parts)
|
||||
|
@@ -8,6 +8,7 @@ They should work with both Python 2 and Python 3.
|
||||
|:---|:---|
|
||||
| `bom.py` | Generates BOM files for the project. |
|
||||
| `c14n_stl.py` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
|
||||
| `changelog.py` | Creates the changelog from the git log |
|
||||
| `doc_scripts.py` | Makes this document and doc/usage.md. |
|
||||
| `dxfs.py` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
|
||||
| `gallery.py` | Finds projects and adds them to the gallery. |
|
||||
|
@@ -30,6 +30,7 @@ from tests import do_cmd, update_image, colour_scheme, background
|
||||
from deps import mtime
|
||||
from colorama import init
|
||||
import json
|
||||
from tmpdir import *
|
||||
|
||||
def usage():
|
||||
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
|
||||
@@ -40,6 +41,7 @@ def render(target, type):
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + type + 's'
|
||||
bom_dir = top_dir + 'bom'
|
||||
if not os.path.isdir(target_dir):
|
||||
@@ -80,7 +82,7 @@ def render(target, type):
|
||||
# make a file to import the stl
|
||||
#
|
||||
if mtime(part_file) > mtime(png_name):
|
||||
png_maker_name = "png.scad"
|
||||
png_maker_name = tmp_dir + "/png.scad"
|
||||
pp1 = [0, 146/255, 0]
|
||||
colour = pp1
|
||||
if part in colours:
|
||||
@@ -88,15 +90,21 @@ def render(target, type):
|
||||
if not '[' in colour:
|
||||
colour = '"' + colour + '"'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write('color(%s) import("%s");\n' % (colour, part_file))
|
||||
f.write('color(%s) import("%s");\n' % (colour, reltmp(part_file, target)))
|
||||
cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500"
|
||||
render = "--preview" if type == 'stl' or colour != pp1 else "--render"
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", tmp_name, png_maker_name);
|
||||
tmp_name = tmp_dir + '/' + part[:-4] + '.png'
|
||||
dummy_deps_name = tmp_dir + '/tmp.deps' # work around for OpenSCAD issue #3879
|
||||
openscad.run("-o", tmp_name, png_maker_name, colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-d", dummy_deps_name)
|
||||
do_cmd(("magick "+ tmp_name + " -trim -resize 280x280 -background %s -gravity Center -extent 280x280 -bordercolor %s -border 10 %s"
|
||||
% (background, background, tmp_name)).split())
|
||||
update_image(tmp_name, png_name)
|
||||
os.remove(png_maker_name)
|
||||
os.remove(dummy_deps_name)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
init()
|
||||
|
@@ -69,17 +69,22 @@ def set_config(target, usage = None):
|
||||
sys.exit(1)
|
||||
|
||||
fname = source_dir + "/target.scad"
|
||||
text = "include <config_%s.scad>\n" % target;
|
||||
line = ""
|
||||
text = ['include <config_%s.scad>\n' % target,
|
||||
'$target = "%s";\n' % target,
|
||||
'$cwd="%s";\n' % os.getcwd().replace('\\', '/')
|
||||
]
|
||||
|
||||
lines = [""]
|
||||
try:
|
||||
with open(fname,"rt") as f:
|
||||
line = f.read()
|
||||
lines = f.readlines()
|
||||
except:
|
||||
pass
|
||||
|
||||
if line != text:
|
||||
if lines != text:
|
||||
with open(fname,"wt") as f:
|
||||
f. write(text);
|
||||
for t in text:
|
||||
f. write(t);
|
||||
return target + "/"
|
||||
|
||||
def usage():
|
||||
|
@@ -34,6 +34,7 @@ import shutil
|
||||
from deps import *
|
||||
from blurb import *
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
w = 4096
|
||||
h = w
|
||||
@@ -59,7 +60,8 @@ def compare_images(a, b, c):
|
||||
with open(log_name, 'w') as output:
|
||||
do_cmd(("magick compare -metric AE -fuzz %d%% %s %s %s" % (fuzz, a, b, c)).split(), output = output)
|
||||
with open(log_name, 'r') as f:
|
||||
pixels = int(float(f.read().strip()))
|
||||
pixels = f.read().strip()
|
||||
pixels = int(float(pixels if pixels.isnumeric() else -1))
|
||||
os.remove(log_name)
|
||||
return pixels
|
||||
|
||||
@@ -70,6 +72,8 @@ def update_image(tmp_name, png_name):
|
||||
if pixels < 0 or pixels > threshold:
|
||||
shutil.copyfile(tmp_name, png_name)
|
||||
print(Fore.YELLOW + png_name + " updated" + Fore.WHITE, pixels if pixels > 0 else '')
|
||||
if png_name.endswith('_tn.png') and os.path.isfile(diff_name):
|
||||
os.remove(diff_name)
|
||||
else:
|
||||
os.utime(png_name, None)
|
||||
os.remove(diff_name)
|
||||
@@ -94,6 +98,7 @@ def usage():
|
||||
|
||||
def tests(tests):
|
||||
scad_dir = "tests"
|
||||
tmp_dir = mktmpdir(scad_dir + '/')
|
||||
deps_dir = scad_dir + "/deps"
|
||||
png_dir = scad_dir + "/png"
|
||||
bom_dir = scad_dir + "/bom"
|
||||
@@ -114,7 +119,7 @@ def tests(tests):
|
||||
libtest = True
|
||||
lib_blurb = scrape_blurb(scad_name)
|
||||
if not os.path.isfile(png_name):
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
|
||||
openscad.run(scad_name, "-o", png_name, colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall");
|
||||
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
|
||||
else:
|
||||
#
|
||||
@@ -170,7 +175,7 @@ def tests(tests):
|
||||
impl_name = None
|
||||
|
||||
if libtest:
|
||||
vsplit = "AJR" + chr(ord('Z') + 1)
|
||||
vsplit = "AIR" + chr(ord('Z') + 1)
|
||||
vtype = locations[0][1]
|
||||
types = [vtype + ' ' + vsplit[i] + '-' + chr(ord(vsplit[i + 1]) - 1) for i in range(len(vsplit) - 1)] + [loc[1] for loc in locations[1 :]]
|
||||
if type == vtype:
|
||||
@@ -234,8 +239,8 @@ def tests(tests):
|
||||
if changed:
|
||||
print(changed)
|
||||
t = time.time()
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run_list(options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, scad_name]);
|
||||
tmp_name = tmp_dir + '/tmp.png'
|
||||
openscad.run_list([scad_name, "-o", tmp_name] + options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname]);
|
||||
times.add_time(scad_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1000x600", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
@@ -303,6 +308,11 @@ def tests(tests):
|
||||
with open(doc_base_name + ".html", "wt") as html_file:
|
||||
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
|
||||
times.print_times()
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
do_cmd(('codespell -L od ' + doc_name).split())
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@@ -44,7 +44,7 @@ def got_time(name):
|
||||
|
||||
def check_have_time(changed, name):
|
||||
if not changed and not got_time(name):
|
||||
changed = "no previous time"
|
||||
changed = Fore.CYAN + "no previous time" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def add_time(name, start):
|
||||
|
41
scripts/tmpdir.py
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
"""
|
||||
Make a directory for tmp files.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
|
||||
def mktmpdir(top_dir):
|
||||
tmp_dir = top_dir + 'tmp'
|
||||
if not os.path.isdir(tmp_dir):
|
||||
time.sleep(0.1)
|
||||
os.makedirs(tmp_dir)
|
||||
else:
|
||||
for file in os.listdir(tmp_dir):
|
||||
os.remove(tmp_dir + '/' + file)
|
||||
return tmp_dir
|
||||
|
||||
def reltmp(dir, target):
|
||||
return dir if os.path.isabs(dir) else '../../' + dir if target else '../' + dir
|
||||
|
||||
def rmtmpdir(tmp_dir):
|
||||
os.rmdir(tmp_dir)
|
||||
while os.path.isdir(tmp_dir):
|
||||
time.sleep(0.1)
|
@@ -38,6 +38,7 @@ import shutil
|
||||
import re
|
||||
import copy
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
def is_assembly(s):
|
||||
return s[-9:] == '_assembly' or s[-11:] == '_assemblies'
|
||||
@@ -76,12 +77,12 @@ def bom_to_assemblies(bom_dir, bounds_map):
|
||||
#
|
||||
if flat_bom:
|
||||
ass = flat_bom[-1]
|
||||
if len(ass["assemblies"]) < 2 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]:
|
||||
if len(ass["assemblies"]) == 1 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]:
|
||||
flat_bom = flat_bom[:-1]
|
||||
return [assembly["name"] for assembly in flat_bom]
|
||||
|
||||
def eop(doc_file, last = False, first = False):
|
||||
print('<span></span>', file = doc_file) # An invisable marker for page breaks because markdown takes much longer if the document contains a div
|
||||
print('<span></span>', file = doc_file) # An invisible marker for page breaks because markdown takes much longer if the document contains a div
|
||||
if not first:
|
||||
print('[Top](#TOP)', file = doc_file)
|
||||
if not last:
|
||||
@@ -129,8 +130,9 @@ def views(target, do_assemblies = None):
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + 'assemblies'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
@@ -159,6 +161,7 @@ def views(target, do_assemblies = None):
|
||||
# Find all the scad files
|
||||
#
|
||||
main_blurb = None
|
||||
main_assembly, main_file = bom.main_assembly(target)
|
||||
pngs = []
|
||||
for dir in source_dirs(bom_dir):
|
||||
if os.path.isdir(dir):
|
||||
@@ -183,6 +186,7 @@ def views(target, do_assemblies = None):
|
||||
#
|
||||
for ass in flat_bom:
|
||||
if ass["name"] == real_name:
|
||||
zoomed = ass['zoomed']
|
||||
if not "blurb" in ass:
|
||||
ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no])
|
||||
break
|
||||
@@ -204,18 +208,22 @@ def views(target, do_assemblies = None):
|
||||
changed = check_deps(png_name, dname)
|
||||
changed = times.check_have_time(changed, png_name)
|
||||
changed = options.have_changed(changed, png_name)
|
||||
tmp_name = 'tmp.png'
|
||||
tmp_name = tmp_dir + '/' + real_name + '.png'
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
png_maker_name = 'png.scad'
|
||||
png_maker_name = tmp_dir + '/png.scad'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("include <NopSCADlib/global_defs.scad>\n")
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
openscad.run_list(options.list() + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name]);
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
view_def = ['--viewall', '--autocenter'] if not (zoomed & (1 << explode)) else ['--camera=0,0,0,55,0,25,140']
|
||||
openscad.run_list(["-o", tmp_name, png_maker_name] + options.list() + target_def + cwd_def + view_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "-d", dname]);
|
||||
times.add_time(png_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
@@ -226,7 +234,7 @@ def views(target, do_assemblies = None):
|
||||
update_image(tmp_name, tn_name)
|
||||
done_assemblies.append(real_name)
|
||||
else:
|
||||
if module == 'main_assembly':
|
||||
if module == main_assembly:
|
||||
main_blurb = blurb.scrape_module_blurb(lines[:line_no])
|
||||
line_no += 1
|
||||
#
|
||||
@@ -240,9 +248,6 @@ def views(target, do_assemblies = None):
|
||||
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
|
||||
print('<a name="TOP"></a>', file = doc_file)
|
||||
print('# %s' % project, file = doc_file)
|
||||
main_file = bom.find_scad_file('main_assembly')
|
||||
if not main_file:
|
||||
raise Exception("can't find source for main_assembly")
|
||||
text = blurb.scrape_blurb(source_dir + '/' + main_file)
|
||||
blurbs = blurb.split_blurb(text)
|
||||
if len(text):
|
||||
@@ -437,6 +442,10 @@ def views(target, do_assemblies = None):
|
||||
dst.write(line)
|
||||
i += 1
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# Spell check
|
||||
#
|
||||
do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())
|
||||
|
29
tests/7_segments.scad
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/7_segments.scad>
|
||||
|
||||
module 7_segments()
|
||||
layout([for(s = 7_segments) 7_segment_size(s).x * 2], 5) let(s = 7_segments[$i])
|
||||
7_segment_digits(s, 2);
|
||||
|
||||
if($preview)
|
||||
7_segments();
|
31
tests/BLDC_motors.scad
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/bldc_motors.scad>
|
||||
|
||||
module bldc_motors()
|
||||
layout([for(b = bldc_motors) BLDC_diameter(b)])
|
||||
rotate(-90)
|
||||
BLDC(bldc_motors[$i]);
|
||||
|
||||
if($preview)
|
||||
let($show_threads = 1)
|
||||
bldc_motors();
|
@@ -20,10 +20,10 @@
|
||||
//
|
||||
//! BOM and assembly demonstration
|
||||
//
|
||||
$explode = 1; // Normally set on the command line when generating assembly views with views.py
|
||||
include <../core.scad>
|
||||
include <../vitamins/sheets.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
$explode = 1; // Normally set on the command line when generating assembly views with views.py
|
||||
|
||||
screw = M3_cap_screw;
|
||||
sheet = PMMA3;
|
||||
@@ -43,31 +43,29 @@ module widget(thickness) {
|
||||
}
|
||||
}
|
||||
|
||||
module widgit_stl() {
|
||||
stl("widget");
|
||||
module widget_stl() {
|
||||
stl("widget")
|
||||
union() {
|
||||
rounded_rectangle([30, 30, 3], 2, true);
|
||||
|
||||
union() {
|
||||
rounded_rectangle([30, 30, 3], 2);
|
||||
|
||||
render() insert_boss(insert, height, 2.2);
|
||||
}
|
||||
render() insert_boss(insert, height, 2.2);
|
||||
}
|
||||
}
|
||||
|
||||
module widgit_dxf() {
|
||||
dxf("widget");
|
||||
module widget_dxf() {
|
||||
dxf("widget")
|
||||
difference() {
|
||||
sheet_2D(sheet, 20, 20, 1);
|
||||
|
||||
difference() {
|
||||
sheet_2D(sheet, 20, 20, 1);
|
||||
|
||||
drill(screw_clearance_radius(screw), 0);
|
||||
}
|
||||
drill(screw_clearance_radius(screw), 0);
|
||||
}
|
||||
}
|
||||
|
||||
//! * Push the insert into the base with a soldering iron heated to 200°C
|
||||
module widgit_base_assembly()
|
||||
assembly("widgit_base") {
|
||||
module widget_base_assembly()
|
||||
assembly("widget_base") {
|
||||
stl_colour(pp1_colour)
|
||||
widgit_stl();
|
||||
widget_stl();
|
||||
|
||||
translate_z(height)
|
||||
insert(insert);
|
||||
@@ -80,14 +78,14 @@ assembly("widget_top") {
|
||||
widget(sheet_thickness(sheet));
|
||||
|
||||
render_2D_sheet(sheet) // Must be last because it is transparent
|
||||
widgit_dxf();
|
||||
widget_dxf();
|
||||
}
|
||||
|
||||
//! * Screw the two assemblies together
|
||||
module widgit_assembly()
|
||||
assembly("wigdit") {
|
||||
module widget_assembly()
|
||||
assembly("widget") {
|
||||
|
||||
widgit_base_assembly(); // Note this is not exloded because it is sub-assembly
|
||||
widget_base_assembly(); // Note this is not exloded because it is sub-assembly
|
||||
|
||||
translate_z(height) {
|
||||
translate_z(sheet_thickness(sheet))
|
||||
@@ -100,7 +98,7 @@ assembly("wigdit") {
|
||||
}
|
||||
|
||||
module boms() {
|
||||
widgit_assembly();
|
||||
widget_assembly();
|
||||
}
|
||||
|
||||
boms();
|
||||
|
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
use <../vitamins/dip.scad>
|
||||
|
||||
dips = [[6, "OPTO"], [8, "NE555"], [14, "74HC00"], [16, "ULN2003"], [18, "ULN2803"], [20, "74HC245"], [28, "ATMEGA328"]];
|
||||
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
include <../vitamins/ldrs.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
@@ -22,6 +22,8 @@ include <../vitamins/d_connectors.scad>
|
||||
include <../vitamins/leds.scad>
|
||||
include <../vitamins/axials.scad>
|
||||
include <../vitamins/smds.scad>
|
||||
include <../vitamins/7_segments.scad>
|
||||
include <../vitamins/potentiometers.scad>
|
||||
|
||||
use <../vitamins/pcb.scad>
|
||||
|
||||
@@ -46,7 +48,7 @@ TMC2130 = ["TMC2130", "TMC2130",
|
||||
[]
|
||||
];
|
||||
|
||||
test_pcb = ["TestPCB", "Test PCB",
|
||||
test_pcb = ["test_pcb", "Test PCB",
|
||||
100, 250, 1.6, // length, width, thickness
|
||||
3, // Corner radius
|
||||
2.75, // Mounting hole diameter
|
||||
@@ -64,21 +66,25 @@ test_pcb = ["TestPCB", "Test PCB",
|
||||
[ 16, 2, 90, "smd_res", RES1206, "1K"],
|
||||
[ 19, 2, 90, "smd_res", RES0805, "1K"],
|
||||
[ 22, 2, 90, "smd_res", RES0603, "1K"],
|
||||
[ 25, 2, 90, "smd_cap", CAP1206, 1.5],
|
||||
[ 28, 2, 90, "smd_cap", CAP0805, 1.0],
|
||||
[ 31, 2, 90, "smd_cap", CAP0603, 0.7],
|
||||
|
||||
[ 10, 10, 0, "2p54header", 4, 1],
|
||||
[ 25, 10, 0, "2p54header", 5, 1, false, "blue" ],
|
||||
[ 10, 20, 0, "2p54boxhdr", 4, 2],
|
||||
[ 10, 30, 0, "2p54socket", 6, 1],
|
||||
[ 25, 30, 0, "2p54socket", 4, 1, false, 0, false, "red" ],
|
||||
[ 10, 40, 0, "chip", 10, 5, 1, grey(20)],
|
||||
[ 5, 50, 0, "led", LED3mm, "red"],
|
||||
[ 12, 50, 0, "led", LED5mm, "orange"],
|
||||
[ 25, 50, 0, "led", LED10mm, "yellow"],
|
||||
[ 10, 65, 180, "rj45"],
|
||||
[ 8, 85, 180, "usb_A"],
|
||||
[ 65, 50, 0, "led", LED3mm, "red"],
|
||||
[ 75, 50, 0, "led", LED5mm, "orange"],
|
||||
[ 90, 50, 0, "led", LED10mm, "yellow"],
|
||||
[ 10, 45, 180, "rj45"],
|
||||
[ 8, 65, 180, "usb_A"],
|
||||
[ 8, 105, 180, "usb_Ax2"],
|
||||
[ 7, 85, 180, "molex_usb_Ax1"],
|
||||
[ 8.5,125, 180, "molex_usb_Ax2"],
|
||||
[ 3, 140, 180, "usb_uA"],
|
||||
[ 8, 155, 180, "usb_B"],
|
||||
[ 8.5, 125, 180, "molex_usb_Ax2"],
|
||||
[ 25, 200, 0, "buzzer", 4.5, 8.5],
|
||||
[ 25, 218, 0, "buzzer"],
|
||||
[ 8, 190, 180, "jack"],
|
||||
@@ -91,6 +97,8 @@ test_pcb = ["TestPCB", "Test PCB",
|
||||
[ 65, 12, 0, "ax_res", res1_8, 1000],
|
||||
[ 65, 17, 0, "ax_res", res1_4, 10000],
|
||||
[ 65, 22, 0, "ax_res", res1_2, 100000],
|
||||
[ 55, 22, 0, "vero_pin"],
|
||||
[ 55, 17, 0, "vero_pin", true],
|
||||
|
||||
[ 80, 9, 0, "link", inch(0.2), inch(0.4)],
|
||||
[ 80, 12, 0, "ax_res", res1_8, 1000000, 1, inch(0.1)],
|
||||
@@ -127,11 +135,14 @@ test_pcb = ["TestPCB", "Test PCB",
|
||||
[ 52, 200, 0, "pcb", 11, TMC2130 ],
|
||||
[ 80, 200, 0, "pdip", 24, "27C32", true, inch(0.6) ],
|
||||
[ 80, 170, 0, "pdip", 8, "NE555" ],
|
||||
[ 80, 150, 0, "chip", 10, 5, 1, grey(20)],
|
||||
|
||||
[ 52, 206, 0, "2p54socket", 8, 1 ],
|
||||
[ 52, 194, 0, "2p54socket", 8, 1, false, 0, false, "red" ],
|
||||
[ 50, 220, 0, "standoff", 5, 4.5, 12.5, 2.54],
|
||||
[ 50, 240, 0, "potentiometer"],
|
||||
[ 75, 240, 0, "potentiometer", 7, 8],
|
||||
[ 75, 240, 0, "potentiometer", KY_040_encoder, 8],
|
||||
[ 30, 85, -90, "7seg", WT5011BSR, 2],
|
||||
],
|
||||
// accessories
|
||||
[]
|
||||
|
@@ -21,7 +21,7 @@ include <../vitamins/pcbs.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
||||
function spacing(p) = let(w = pcb_width(p)) w < 22 ? w + 3 : w + 10;
|
||||
function spacing(p) = let(w = pcb_width(p)) w < 22 ? w + 3 : w + 7;
|
||||
|
||||
module pcbs() {
|
||||
layout([for(p = pcbs) spacing(p)], 0)
|
||||
@@ -29,6 +29,11 @@ module pcbs() {
|
||||
rotate(90)
|
||||
pcb_assembly(pcbs[$i], 5 + $i, 3);
|
||||
|
||||
translate([0, 65])
|
||||
layout([for(p = tiny_pcbs) pcb_length(p)], 3)
|
||||
translate([0, -pcb_width(tiny_pcbs[$i]) / 2])
|
||||
pcb_assembly(tiny_pcbs[$i], 5 + $i, 3);
|
||||
|
||||
translate([0, 120])
|
||||
layout([for(p = perfboards) pcb_length(p)], 10)
|
||||
translate([0, -pcb_width(perfboards[$i]) / 2])
|
||||
|
@@ -22,18 +22,20 @@ include <../vitamins/extrusions.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
||||
module sk_brackets() {
|
||||
module sk_brackets(examples = false) {
|
||||
screws = [M4_dome_screw, M4_cap_screw, M5_cap_screw, M5_cap_screw];
|
||||
nuts = [M4_hammer_nut, M4_sliding_t_nut, M5_sliding_t_nut, undef];
|
||||
// channel depth = 6 for 2020 extrusion, 9 for 3030 extrusion
|
||||
depths = [6, 6, 9, 0];
|
||||
layout([for(s = sk_brackets) 1.5 * sk_size(s)[1]]) {
|
||||
sk_bracket_assembly(sk_brackets[$i], screw_type = screws[$i], nut_type = nuts[$i], max_screw_depth = depths[$i]);
|
||||
translate([0, -sk_hole_offset(sk_brackets[$i]) - extrusion_width($i < 2 ? E2020 : E3030) / 2, 0])
|
||||
rotate([0, 90, 0])
|
||||
extrusion($i < 2 ? E2020 : E3030, 20, false);
|
||||
|
||||
if(examples)
|
||||
translate([0, -sk_hole_offset(sk_brackets[$i]) - extrusion_width($i < 2 ? E2020 : E3030) / 2, 0])
|
||||
rotate([0, 90, 0])
|
||||
extrusion($i < 2 ? E2020 : E3030, 20, false);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
sk_brackets();
|
||||
sk_brackets(true);
|
||||
|
@@ -28,6 +28,11 @@ module smds() {
|
||||
translate([0, 3])
|
||||
layout([for(l = smd_leds) smd_led_size(l).x], 1)
|
||||
smd_led(smd_leds[$i], ["green", "blue", "red"][$i % 3]);
|
||||
|
||||
translate([0, 6])
|
||||
layout([for(c = smd_capacitors) smd_cap_size(c).x], 1)
|
||||
let(c = smd_capacitors[$i])
|
||||
smd_capacitor(c, smd_cap_size(c).y * 0.8);
|
||||
}
|
||||
|
||||
if($preview)
|
||||
|
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
include <../vitamins/ssrs.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/ball_bearings.scad>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/scs_bearing_blocks.scad>
|
||||
include <../vitamins/bearing_blocks.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
@@ -25,9 +25,9 @@ use <../utils/layout.scad>
|
||||
module belt_test() {
|
||||
p2 = [-75, -50];
|
||||
p3 = [-75, 100];
|
||||
p4 = [75, 100];
|
||||
p4 = [ 75, 100];
|
||||
|
||||
p5 = [75 + pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), +pulley_pr(GT2x16_plain_idler)];
|
||||
p5 = [ 75 + pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), +pulley_pr(GT2x16_plain_idler)];
|
||||
p6 = [-75 + pulley_pr(GT2x20ob_pulley) + pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)];
|
||||
|
||||
module pulleys(flip = false) {
|
||||
@@ -52,19 +52,21 @@ module belt_test() {
|
||||
translate(p6) pulley_assembly(GT2x16_plain_idler);
|
||||
}
|
||||
|
||||
path = [ [p5.x, p5.y, pulley_pr(GT2x16_plain_idler)],
|
||||
path = [ [-40, 0, 0],
|
||||
[p6.x, p6.y, -pulley_pr(GT2x16_plain_idler)],
|
||||
[p2.x, p2.y, pulley_pr(GT2x20ob_pulley)],
|
||||
[p3.x, p3.y, pulley_pr(GT2x20ob_pulley)],
|
||||
[p4.x, p4.y, pulley_pr(GT2x20ob_pulley)]
|
||||
[p4.x, p4.y, pulley_pr(GT2x20ob_pulley)],
|
||||
[p5.x, p5.y, pulley_pr(GT2x16_plain_idler)],
|
||||
[40, 0, 0],
|
||||
];
|
||||
|
||||
belt = GT2x6;
|
||||
belt(belt, path, 80, [0, 0]);
|
||||
belt(belt, path, open = true);
|
||||
pulleys();
|
||||
translate_z(20)
|
||||
hflip() {
|
||||
belt(belt, path, 80, [0, 0], belt_colour = grey(90), tooth_colour = grey(50));
|
||||
belt(belt, path, open = true, belt_colour = grey(90), tooth_colour = grey(50));
|
||||
pulleys(flip=true);
|
||||
}
|
||||
|
||||
@@ -72,6 +74,31 @@ module belt_test() {
|
||||
layout([for(b = belts) belt_width(b)], 10)
|
||||
rotate([0, 90, 0])
|
||||
belt(belts[$i], [[0, 0, 20], [0, 1, 20]], belt_colour = $i%2==0 ? grey(90) : grey(20), tooth_colour = $i%2==0 ? grey(70) : grey(50));
|
||||
|
||||
// new example with open loop - this is a simplified example of the style used for example for the BLV 3D printer
|
||||
pulley = GT2x20ob_pulley;
|
||||
idler = GT2x16_plain_idler;
|
||||
corners = [[-75,-50],[75,100]];
|
||||
carriagepos = [0,0];
|
||||
carriagew = 80;
|
||||
|
||||
points = [
|
||||
[carriagepos.x - carriagew / 2, carriagepos.y, 0],
|
||||
[corners[0].x + belt_pulley_pr(belt, pulley) + belt_pulley_pr(belt, idler), carriagepos.y - belt_pulley_pr(belt, idler), idler],
|
||||
[corners[0].x, corners[0].y, pulley],
|
||||
[corners[0].x, corners[1].y, idler],
|
||||
[corners[1].x, corners[1].y, idler],
|
||||
[corners[1].x, carriagepos.y + belt_pulley_pr(belt, idler), idler],
|
||||
[carriagepos.x + carriagew / 2, carriagepos.y, 0]
|
||||
];
|
||||
translate_z(-30) {
|
||||
belt(belt, points, open=true, auto_twist=true);
|
||||
for (p = points)
|
||||
if (is_list(p.z))
|
||||
translate([p.x, p.y, 0])
|
||||
pulley_assembly(p.z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($preview)
|
||||
|
@@ -22,7 +22,7 @@ use <../utils/layout.scad>
|
||||
include <../vitamins/blowers.scad>
|
||||
|
||||
module blowers()
|
||||
layout([for(b = blowers) blower_width(b)], 10, true) let(b = blowers[$i]){
|
||||
layout([for(b = blowers) blower_width(b)], 5, true) let(b = blowers[$i]){
|
||||
screw = blower_screw(b);
|
||||
h = blower_lug(b);
|
||||
|
||||
|
30
tests/box_sections.scad
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/box_sections.scad>
|
||||
|
||||
module box_sections() {
|
||||
layout([for(b = box_sections) box_section_size(b).x], 20)
|
||||
box_section(box_sections[$i], 100);
|
||||
}
|
||||
|
||||
if($preview)
|
||||
box_sections();
|
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
use <../printed/camera_housing.scad>
|
||||
|
@@ -42,6 +42,9 @@ module components() {
|
||||
TO220("Generic TO220 package");
|
||||
|
||||
translate([40, 50])
|
||||
TO247("Generic TO247 package");
|
||||
|
||||
translate([40, 80])
|
||||
panel_USBA();
|
||||
|
||||
translate([80, 50])
|
||||
|
133
tests/core_xy.scad
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2020
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
include <../core.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
include <../vitamins/stepper_motors.scad>
|
||||
include <../vitamins/washers.scad>
|
||||
|
||||
include <../utils/core_xy.scad>
|
||||
|
||||
|
||||
module coreXY_belts_test() {
|
||||
coreXY_type = coreXY_GT2_20_16;
|
||||
plain_idler = coreXY_plain_idler(coreXY_type);
|
||||
toothed_idler = coreXY_toothed_idler(coreXY_type);
|
||||
|
||||
coreXYPosBL = [0, 0, 0];
|
||||
coreXYPosTR = [200, 150, 0];
|
||||
separation = [0, coreXY_coincident_separation(coreXY_type).y, pulley_height(plain_idler) + washer_thickness(M3_washer)];
|
||||
pos = [100, 50];
|
||||
|
||||
upper_drive_pulley_offset = [40, 10];
|
||||
lower_drive_pulley_offset = [0, 0];
|
||||
|
||||
coreXY_belts(coreXY_type,
|
||||
carriagePosition = pos,
|
||||
coreXYPosBL = coreXYPosBL,
|
||||
coreXYPosTR = coreXYPosTR,
|
||||
separation = separation,
|
||||
x_gap = 10,
|
||||
upper_drive_pulley_offset = upper_drive_pulley_offset,
|
||||
lower_drive_pulley_offset = lower_drive_pulley_offset,
|
||||
show_pulleys = true);
|
||||
|
||||
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosTR.y + upper_drive_pulley_offset.y, separation.z/2]) {
|
||||
// add the upper drive pulley stepper motor
|
||||
translate([coreXY_drive_pulley_x_alignment(coreXY_type) + upper_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the upper drive offset idler pulleys if required
|
||||
if (upper_drive_pulley_offset.x > 0) {
|
||||
translate(coreXY_drive_plain_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (upper_drive_pulley_offset.x < 0) {
|
||||
translate([-pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosTR.y + lower_drive_pulley_offset.y, -separation.z/2]) {
|
||||
// add the lower drive pulley stepper motor
|
||||
translate([-coreXY_drive_pulley_x_alignment(coreXY_type) + lower_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the lower drive offset idler pulleys if required
|
||||
if (lower_drive_pulley_offset.x < 0) {
|
||||
translate([-coreXY_drive_plain_idler_offset(coreXY_type).x, coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (lower_drive_pulley_offset.x > 0) {
|
||||
translate([pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([-2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
// add the screw for the left upper idler pulley
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right upper idler pulley
|
||||
translate([coreXYPosTR.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
if (separation.x != 0) {
|
||||
// add the screw for the left lower idler pulley
|
||||
translate([coreXYPosBL.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right lower idler pulley
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
|
||||
translate([-separation.x/2, pos.y + coreXYPosBL.y -separation.y/2, -separation.z/2 + pulley_height(plain_idler)/2]) {
|
||||
// add the screw for the left Y carriage toothed idler
|
||||
translate([coreXYPosBL.x, coreXY_toothed_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the left Y carriage plain idler
|
||||
translate([coreXYPosBL.x + separation.x + coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage toothed idler
|
||||
translate([coreXYPosTR.x + separation.x, coreXY_toothed_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage plain idler
|
||||
translate([coreXYPosTR.x - coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
if ($preview)
|
||||
coreXY_belts_test();
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/displays.scad>
|
||||
@@ -23,7 +24,10 @@ use <../vitamins/pcb.scad>
|
||||
|
||||
module displays()
|
||||
layout([for(d = displays) pcb_length(display_pcb(d))], 10)
|
||||
display(displays[$i]);
|
||||
translate([0, pcb_width(displays[$i]) / 2])
|
||||
vflip()
|
||||
display(displays[$i]);
|
||||
|
||||
if($preview)
|
||||
displays();
|
||||
let($show_threads = true)
|
||||
displays();
|
||||
|
@@ -16,13 +16,51 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
include <../core.scad>
|
||||
|
||||
include <../vitamins/extrusion_brackets.scad>
|
||||
include <../vitamins/extrusions.scad>
|
||||
include <../vitamins/extrusion_brackets.scad>
|
||||
include <../vitamins/washers.scad>
|
||||
include <../vitamins/nuts.scad>
|
||||
|
||||
module inner_bracket_test(bracket, backwards = false)
|
||||
rotate([90, 0, 180]) {
|
||||
extrusion = extrusion_inner_corner_bracket_extrusion(bracket);
|
||||
eWidth = extrusion_width(extrusion);
|
||||
size = extrusion_inner_corner_bracket_size(bracket);
|
||||
tnut = extrusion_inner_corner_bracket_tnut(bracket);
|
||||
|
||||
translate([backwards ? -eWidth : 0, 0])
|
||||
extrusion_inner_corner_bracket(bracket, backwards = backwards);
|
||||
|
||||
translate([-eWidth / 2, 0])
|
||||
rotate([-90, 0, 0])
|
||||
extrusion(extrusion, size.x - nut_thickness(tnut) - extrusion_tab_thickness(extrusion), false, cornerHole = eWidth > 20);
|
||||
|
||||
translate([-eWidth, -eWidth / 2])
|
||||
rotate([0, 90, 0])
|
||||
extrusion(extrusion, eWidth + size.y - nut_thickness(tnut) - extrusion_tab_thickness(extrusion), false, cornerHole = eWidth > 20);
|
||||
}
|
||||
|
||||
|
||||
module bracket_test(bracket)
|
||||
rotate([90, 0, 180]) {
|
||||
extrusion = extrusion_corner_bracket_extrusion(bracket);
|
||||
eWidth = extrusion_width(extrusion);
|
||||
size = extrusion_corner_bracket_size(bracket);
|
||||
|
||||
extrusion_corner_bracket_assembly(bracket);
|
||||
|
||||
translate([-eWidth / 2, 0])
|
||||
rotate([-90, 0, 0])
|
||||
extrusion(extrusion, size.y, false, cornerHole = eWidth > 20);
|
||||
|
||||
translate([-eWidth, -eWidth / 2])
|
||||
rotate([0, 90, 0])
|
||||
extrusion(extrusion, eWidth + size.x, false, cornerHole = eWidth > 20);
|
||||
}
|
||||
|
||||
|
||||
module extrusion_brackets(examples = false) {
|
||||
extrusion_inner_corner_bracket(E20_inner_corner_bracket);
|
||||
|
||||
@@ -32,34 +70,30 @@ module extrusion_brackets(examples = false) {
|
||||
translate([60, 0])
|
||||
extrusion_corner_bracket_assembly(E20_corner_bracket);
|
||||
|
||||
eWidth = extrusion_width(E2020);
|
||||
translate([110, 0])
|
||||
extrusion_inner_corner_bracket(E40_inner_corner_bracket);
|
||||
|
||||
translate([140, 0])
|
||||
extrusion_corner_bracket_assembly(E40_corner_bracket);
|
||||
|
||||
if(examples) {
|
||||
translate([20, 60, 10]) rotate([90, 0, 180]) {
|
||||
extrusion_inner_corner_bracket(E20_inner_corner_bracket);
|
||||
translate([20, 50, 10])
|
||||
inner_bracket_test(E20_inner_corner_bracket, true);
|
||||
|
||||
translate([-eWidth / 2, 0, 0])
|
||||
rotate([-90, 0, 0])
|
||||
extrusion(E2020, 20, false);
|
||||
translate([20, 80, 10])
|
||||
inner_bracket_test(E20_inner_corner_bracket);
|
||||
|
||||
translate([-eWidth, -eWidth / 2, 0])
|
||||
rotate([0, 90, 0])
|
||||
extrusion(E2020, 40, false);
|
||||
}
|
||||
translate([20, 120, 10])
|
||||
bracket_test(E20_corner_bracket);
|
||||
|
||||
translate([100, 60, 10]) rotate([90, 0, 180]) {
|
||||
extrusion_corner_bracket_assembly(E20_corner_bracket);
|
||||
translate([100, 70, 10])
|
||||
inner_bracket_test(E40_inner_corner_bracket);
|
||||
|
||||
translate([-eWidth / 2, 0, 0])
|
||||
rotate([-90, 0, 0])
|
||||
extrusion(E2020, 30, false);
|
||||
|
||||
translate([-eWidth, -eWidth / 2, 0])
|
||||
rotate([0, 90, 0])
|
||||
extrusion(E2020, 50, false);
|
||||
}
|
||||
translate([100, 130, 10])
|
||||
bracket_test(E40_corner_bracket);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
extrusion_brackets(true);
|
||||
let($show_threads = true)
|
||||
extrusion_brackets(true);
|
||||
|
@@ -21,9 +21,24 @@ use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/extrusions.scad>
|
||||
|
||||
gap = 10;
|
||||
|
||||
module extrusions()
|
||||
layout([for(e = extrusions) extrusion_width(e)], 10)
|
||||
extrusion(extrusions[$i], 80, cornerHole = extrusion_width(extrusions[$i]) > 20);
|
||||
layout([for(e = extrusions) is_list(e[0]) ? extrusion_width(e[0]) : extrusion_width(e)], gap)
|
||||
let(e = extrusions[$i])
|
||||
if(is_list(e[0])) {
|
||||
list = e;
|
||||
heights = [for(e = list) extrusion_height(e)];
|
||||
l = len(heights) - 1;
|
||||
offset = (heights * [for(i = [0 : l]) 1] + l * gap) / 2;
|
||||
translate([0, -offset])
|
||||
rotate(90)
|
||||
layout(heights, gap)
|
||||
rotate(-90)
|
||||
extrusion(list[$i], 80, cornerHole = extrusion_width(list[$i]) > 20);
|
||||
}
|
||||
else
|
||||
extrusion(e, 80, cornerHole = extrusion_width(e) > 20);
|
||||
|
||||
if ($preview)
|
||||
extrusions();
|
||||
|
@@ -16,12 +16,13 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/geared_steppers.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
||||
module geared_steppers()
|
||||
layout([for(g = geared_steppers) gs_diameter(g)], 5)
|
||||
layout([for(g = geared_steppers) max(gs_diameter(g), gs_pitch(g) + gs_lug_w(g) / 2)], 5)
|
||||
geared_stepper(geared_steppers[$i]);
|
||||
|
||||
geared_steppers();
|
||||
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/green_terminals.scad>
|
||||
|
@@ -56,7 +56,7 @@ module horiholes_stl(t = thickness) {
|
||||
}
|
||||
if(t == thickness)
|
||||
translate([length / 2, 0])
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5);
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5, true);
|
||||
}
|
||||
|
||||
module horiholes() {
|
||||
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
use <../vitamins/hygrometer.scad>
|
||||
|
||||
if($preview)
|
||||
|
@@ -22,12 +22,15 @@ use <../vitamins/jack.scad>
|
||||
|
||||
module jacks() {
|
||||
translate([0, 0])
|
||||
jack_4mm("blue",3, "royalblue");
|
||||
jack_4mm_plastic("black",3, grey(20));
|
||||
|
||||
translate([20, 0])
|
||||
jack_4mm_shielded("brown", 3, "sienna");
|
||||
jack_4mm("blue",3, "royalblue");
|
||||
|
||||
translate([40, 0])
|
||||
jack_4mm_shielded("brown", 3, "sienna");
|
||||
|
||||
translate([60, 0])
|
||||
post_4mm("red",3);
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
use <../vitamins/microview.scad>
|
||||
|
||||
microview(!$preview);
|
||||
|
@@ -52,6 +52,12 @@ module nuts() {
|
||||
|
||||
if(n == M5_nut)
|
||||
sliding_t_nut(M5_sliding_t_nut);
|
||||
|
||||
if(n == M6_nut)
|
||||
sliding_t_nut(M6_sliding_t_nut);
|
||||
|
||||
if(n == M8_nut)
|
||||
sliding_t_nut(M8_sliding_ball_t_nut);
|
||||
}
|
||||
|
||||
translate([0, 80]) {
|
||||
|
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
use <../vitamins/o_ring.scad>
|
||||
|
||||
module o_rings()
|
||||
|
@@ -17,7 +17,7 @@
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/kp_pillow_blocks.scad>
|
||||
include <../vitamins/pillow_blocks.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
@@ -64,8 +64,9 @@ module pin_headers() {
|
||||
pin_socket(pin_headers[$i], 3, 3, right_angle = true);
|
||||
}
|
||||
|
||||
for(i = [0, 1], p = [5, 2][i], j = [0 , 1]) {
|
||||
h = [jst_ph_header, jst_xh_header][j];
|
||||
headers = [jst_zh_header, jst_ph_header, jst_xh_header];
|
||||
for(i = [0, 1], p = [5, 2][i], j = [0 : len(headers) - 1]) {
|
||||
h = headers[j];
|
||||
translate([-20 * (i + 1), 0 + j * 40])
|
||||
jst_xh_header(h, p);
|
||||
|
||||
|
BIN
tests/png/7_segments.png
Normal file
After Width: | Height: | Size: 37 KiB |