Compare commits
208 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
73d814d2fe | ||
|
fa658d9eaa | ||
|
6d3f54b7a5 | ||
|
157ff60e19 | ||
|
cbd3cf29af | ||
|
bf618bb482 | ||
|
1e6f0a5c4d | ||
|
53c3cdb598 | ||
|
f4857f6862 | ||
|
1acc8d01c0 | ||
|
344e8d1583 | ||
|
dd757a1461 | ||
|
b4f8892b1a | ||
|
4b033d9945 | ||
|
d5a711f4cc | ||
|
42b76ab8d3 | ||
|
f18044915d | ||
|
17b12c7f31 | ||
|
18ff4c6d46 | ||
|
2eecce819c | ||
|
f7d81738bb | ||
|
6d44124bab | ||
|
9bb9f09dca | ||
|
773a53829f | ||
|
07766d8cf0 | ||
|
ceac5cdb27 | ||
|
c5b35daeac | ||
|
ffb4512523 | ||
|
35ffbad74c | ||
|
fb685a0f42 | ||
|
5d42b2e1ab | ||
|
2fe815d1bd | ||
|
5c577cccd0 | ||
|
1dbfafd366 | ||
|
68b3dfb098 | ||
|
25dceee20a | ||
|
d70ddf5359 | ||
|
70b60522ce | ||
|
ecba7eaea4 | ||
|
f751dd9a73 | ||
|
3f359f6839 | ||
|
3e5947c161 | ||
|
66dc430541 | ||
|
4dc83d62cb | ||
|
ebbec3c903 | ||
|
9944aab73e | ||
|
eb9bcf0ada | ||
|
ff5e8c0372 | ||
|
17ebf36e27 | ||
|
e38d9abfa0 | ||
|
fc7fd5482e | ||
|
cee1202fd9 | ||
|
6e342441c6 | ||
|
072c38f955 | ||
|
b342549d74 | ||
|
2b83a15e5d | ||
|
ab81c6538c | ||
|
27b0a442e4 | ||
|
38acef9e27 | ||
|
5415beb80d | ||
|
040985c0db | ||
|
0216093a68 | ||
|
30302431c0 | ||
|
1fb429e9a5 | ||
|
9571e68629 | ||
|
b01e6a673c | ||
|
9239c6da3c | ||
|
ba5e5fa390 | ||
|
c7dfdd0fb9 | ||
|
814ce4f15d | ||
|
f661cf6934 | ||
|
305d2146f2 | ||
|
e39ee1797d | ||
|
520569cb30 | ||
|
f73a7b46a2 | ||
|
fb9eca85c6 | ||
|
166ed05d4a | ||
|
ce6aec428d | ||
|
4e9d169c31 | ||
|
1810160103 | ||
|
0c9ae8d60c | ||
|
9a0bad4e61 | ||
|
90047815b0 | ||
|
b583202fb7 | ||
|
eac0086199 | ||
|
03beaec470 | ||
|
51c649cc53 | ||
|
5fa33d7c4d | ||
|
78ce51d045 | ||
|
23cbadf6df | ||
|
c9c2ffafba | ||
|
2e0e833d40 | ||
|
6c51f8726c | ||
|
0b035dbd15 | ||
|
34b58e3b64 | ||
|
df43fe7dc6 | ||
|
b5fe03fcb2 | ||
|
1658f6f0b4 | ||
|
7b126f9792 | ||
|
479207fd4f | ||
|
3ee55981f9 | ||
|
8c2b4a20fe | ||
|
1529759406 | ||
|
c4a986aa21 | ||
|
ebee729d08 | ||
|
90e7f1a315 | ||
|
e39af154bb | ||
|
933fea687c | ||
|
a7803b1efb | ||
|
1255e71271 | ||
|
b11c5914b3 | ||
|
ac60057801 | ||
|
332933a4fd | ||
|
6b0132c32e | ||
|
afac5f9737 | ||
|
8d8df3cb8a | ||
|
81eb183db9 | ||
|
c99ed98a64 | ||
|
7f65e5d539 | ||
|
ffb7f87cc5 | ||
|
d0513c7299 | ||
|
d1429a3b7d | ||
|
70513993bd | ||
|
9eb35accfd | ||
|
7276f18566 | ||
|
d944198dc4 | ||
|
04f2499a9e | ||
|
1eb8b378e9 | ||
|
362dbdb4fc | ||
|
57d223d84b | ||
|
699385342f | ||
|
547a418cea | ||
|
b6d25048bc | ||
|
4cdab218d9 | ||
|
b6147e5684 | ||
|
966ba536ed | ||
|
2419d50641 | ||
|
02211c2034 | ||
|
77d73b075d | ||
|
cb54a3131b | ||
|
3cf275579c | ||
|
fb41f218fe | ||
|
e6a26bc7b1 | ||
|
cb4fa40643 | ||
|
6a26903514 | ||
|
d08d949887 | ||
|
574a73e527 | ||
|
87a35126de | ||
|
1ca485b66b | ||
|
bc919529d3 | ||
|
9f4ed2b915 | ||
|
7ce055373a | ||
|
71ac571346 | ||
|
e4d93366fa | ||
|
f047ac27f7 | ||
|
a9e479d971 | ||
|
47b01af1ea | ||
|
fe19eba237 | ||
|
235f7b86e3 | ||
|
92d7e18b16 | ||
|
6a7226120f | ||
|
8aa00cd041 | ||
|
f6b512da1f | ||
|
c7ea0939b9 | ||
|
265b5ab555 | ||
|
186dbbfd08 | ||
|
60659a43f8 | ||
|
f412cb1736 | ||
|
2b878556fc | ||
|
1f1a360b7c | ||
|
a547c98995 | ||
|
d9fa8c8668 | ||
|
bf5b6d7c30 | ||
|
9cfde7f524 | ||
|
184f19ef04 | ||
|
c88472121e | ||
|
a74bf094aa | ||
|
5a06f79466 | ||
|
98e17080d8 | ||
|
d3f308a45e | ||
|
fe454884e0 | ||
|
c019448dd3 | ||
|
eadc541e8f | ||
|
02791c40ac | ||
|
85b8ffbbc3 | ||
|
dd5d3869ad | ||
|
b84eb3cf31 | ||
|
0ec7aabcfb | ||
|
baa737c4d8 | ||
|
70b13d2f27 | ||
|
c9aad0178e | ||
|
df96551b11 | ||
|
a5a360e0d1 | ||
|
828e5ad36e | ||
|
cedaafed3d | ||
|
0d38d82416 | ||
|
041341b946 | ||
|
70622ba8de | ||
|
4ab0a981ef | ||
|
bb7dd51270 | ||
|
48293b9abd | ||
|
c9d10eeb8b | ||
|
192460c0fa | ||
|
d4402c6713 | ||
|
b9890ca589 | ||
|
026b9daf59 | ||
|
2afc00cfa9 | ||
|
84b5686af6 |
@@ -18,7 +18,7 @@
|
||||
//
|
||||
|
||||
//
|
||||
// Include this file to use the miniumum library plus screws, nuts and washers
|
||||
// Include this file to use the minimum library plus screws, nuts and washers
|
||||
//
|
||||
include <utils/core/core.scad>
|
||||
//
|
||||
|
@@ -52,7 +52,7 @@ iec = IEC_inlet_atx;
|
||||
socket = Contactum;
|
||||
|
||||
|
||||
foot = [20, 8, 3, 1, M3_dome_screw, 10];
|
||||
foot = Foot(d = 20, h = 8, t = 3, r = 1, screw = M3_dome_screw);
|
||||
|
||||
module foot_stl() foot(foot);
|
||||
|
||||
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 290 KiB |
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 293 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 236 KiB |
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 202 KiB |
@@ -33,10 +33,10 @@ $exploded = is_undef($explode) ? 0 : $explode; // 1 f
|
||||
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth 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; // miniumum tool radius when milling 2D objects
|
||||
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) ? [0, 146/255, 0] : $pp1_colour; // printed part colour 1, RepRap logo colour
|
||||
pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // printed part colour 2
|
||||
pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3
|
||||
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
|
||||
@@ -52,14 +52,7 @@ $fs = extrusion_width / 2;
|
||||
|
||||
function round_to_layer(z) = ceil(z / layer_height) * layer_height;
|
||||
// Some additional named colours
|
||||
grey20 = [0.2, 0.2, 0.2];
|
||||
grey30 = [0.3, 0.3, 0.3];
|
||||
grey40 = [0.4, 0.4, 0.4];
|
||||
grey50 = [0.5, 0.5, 0.5];
|
||||
grey60 = [0.6, 0.6, 0.6];
|
||||
grey70 = [0.7, 0.7, 0.7];
|
||||
grey80 = [0.8, 0.8, 0.8];
|
||||
grey90 = [0.9, 0.9, 0.9];
|
||||
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];
|
||||
|
7
lib.scad
@@ -29,6 +29,7 @@ include <vitamins/batteries.scad>
|
||||
include <vitamins/blowers.scad>
|
||||
include <vitamins/bulldogs.scad>
|
||||
include <vitamins/buttons.scad>
|
||||
include <vitamins/cameras.scad>
|
||||
include <vitamins/components.scad>
|
||||
include <vitamins/displays.scad>
|
||||
include <vitamins/extrusions.scad>
|
||||
@@ -40,9 +41,12 @@ include <vitamins/inserts.scad>
|
||||
include <vitamins/kp_pillow_blocks.scad>
|
||||
include <vitamins/ldrs.scad>
|
||||
include <vitamins/leadnuts.scad>
|
||||
include <vitamins/led_meter.scad>
|
||||
include <vitamins/light_strips.scad>
|
||||
include <vitamins/magnets.scad>
|
||||
include <vitamins/mains_sockets.scad>
|
||||
include <vitamins/modules.scad>
|
||||
include <vitamins/panel_meters.scad>
|
||||
include <vitamins/pillars.scad>
|
||||
include <vitamins/pin_headers.scad>
|
||||
include <vitamins/pulleys.scad>
|
||||
@@ -50,6 +54,7 @@ include <vitamins/ring_terminals.scad>
|
||||
include <vitamins/rails.scad>
|
||||
include <vitamins/rod.scad>
|
||||
include <vitamins/scs_bearing_blocks.scad>
|
||||
include <vitamins/shaft_couplings.scad>
|
||||
include <vitamins/sheets.scad>
|
||||
include <vitamins/sk_brackets.scad>
|
||||
include <vitamins/spools.scad>
|
||||
@@ -63,7 +68,6 @@ include <vitamins/variacs.scad>
|
||||
include <vitamins/zipties.scad>
|
||||
|
||||
use <vitamins/jack.scad>
|
||||
use <vitamins/meter.scad>
|
||||
use <vitamins/fuseholder.scad>
|
||||
use <vitamins/hygrometer.scad>
|
||||
|
||||
@@ -82,6 +86,7 @@ use <utils/rounded_cylinder.scad>
|
||||
use <utils/dogbones.scad>
|
||||
use <utils/tube.scad>
|
||||
use <utils/quadrant.scad>
|
||||
use <utils/gears.scad>
|
||||
use <utils/hanging_hole.scad>
|
||||
use <utils/fillet.scad>
|
||||
use <utils/rounded_polygon.scad>
|
||||
|
BIN
libtest.png
Before Width: | Height: | Size: 787 KiB After Width: | Height: | Size: 854 KiB |
83
libtest.scad
@@ -17,6 +17,23 @@
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//!# NopSCADlib
|
||||
//! An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
|
||||
//!
|
||||
//! It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and some utilities.
|
||||
//! There are also Python scripts to generate Bills of Materials (BOMs),
|
||||
//! STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
|
||||
//! instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md).
|
||||
//!
|
||||
//! A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
|
||||
//!
|
||||
//! For more examples of what it can make see the [gallery](gallery/readme.md).
|
||||
//!
|
||||
//! The license is GNU General Public License v3.0, see [COPYING](COPYING).
|
||||
//!
|
||||
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
//!
|
||||
//! <img src="libtest.png" width="100%"/>
|
||||
//
|
||||
// This file shows all the parts in the library.
|
||||
//
|
||||
@@ -29,10 +46,13 @@ use <tests/blowers.scad>
|
||||
use <tests/bulldogs.scad>
|
||||
use <tests/buttons.scad>
|
||||
use <tests/cable_strips.scad>
|
||||
use <tests/cameras.scad>
|
||||
use <tests/camera_housing.scad>
|
||||
use <tests/circlips.scad>
|
||||
use <tests/components.scad>
|
||||
use <tests/d_connectors.scad>
|
||||
use <tests/displays.scad>
|
||||
use <tests/drag_chain.scad>
|
||||
use <tests/extrusions.scad>
|
||||
use <tests/extrusion_brackets.scad>
|
||||
use <tests/fans.scad>
|
||||
@@ -48,14 +68,17 @@ use <tests/LDRs.scad>
|
||||
use <tests/LEDs.scad>
|
||||
use <tests/light_strips.scad>
|
||||
use <tests/linear_bearings.scad>
|
||||
use <tests/meter.scad>
|
||||
use <tests/LED_meters.scad>
|
||||
use <tests/magnets.scad>
|
||||
use <tests/microswitches.scad>
|
||||
use <tests/modules.scad>
|
||||
use <tests/nuts.scad>
|
||||
use <tests/o_ring.scad>
|
||||
use <tests/opengrab.scad>
|
||||
use <tests/panel_meters.scad>
|
||||
use <tests/PCBs.scad>
|
||||
use <tests/pillars.scad>
|
||||
use <tests/press_fit.scad>
|
||||
use <tests/PSUs.scad>
|
||||
use <tests/pulleys.scad>
|
||||
use <tests/rails.scad>
|
||||
@@ -65,13 +88,14 @@ use <tests/rod.scad>
|
||||
use <tests/screws.scad>
|
||||
use <tests/SCS_bearing_blocks.scad>
|
||||
use <tests/sealing_strip.scad>
|
||||
use <tests/shaft_couplings.scad>
|
||||
use <tests/sheets.scad>
|
||||
use <tests/SK_brackets.scad>
|
||||
use <tests/spades.scad>
|
||||
use <tests/springs.scad>
|
||||
use <tests/SSRs.scad>
|
||||
use <tests/stepper_motors.scad>
|
||||
use <tests/swiss_clips.scad>
|
||||
use <tests/Swiss_clips.scad>
|
||||
use <tests/toggles.scad>
|
||||
use <tests/transformers.scad>
|
||||
use <tests/tubings.scad>
|
||||
@@ -114,17 +138,20 @@ cable_grommets_y = 0;
|
||||
translate([x5, cable_grommets_y])
|
||||
cable_grommets();
|
||||
|
||||
translate([x5, cable_grommets_y + 50])
|
||||
feet();
|
||||
translate([x5 + 50, cable_grommets_y])
|
||||
ribbon_clamps();
|
||||
|
||||
translate([x5, cable_grommets_y + 75])
|
||||
translate([x5 + 95, cable_grommets_y])
|
||||
press_fits();
|
||||
|
||||
translate([x5, cable_grommets_y + 60])
|
||||
fixing_blocks();
|
||||
|
||||
translate([x5, cable_grommets_y + 100])
|
||||
translate([x5, cable_grommets_y + 90])
|
||||
corner_blocks();
|
||||
|
||||
translate([x5, cable_grommets_y + 150])
|
||||
ribbon_clamps();
|
||||
feet();
|
||||
|
||||
translate([x5 + 70, cable_grommets_y + 150])
|
||||
screw_knobs();
|
||||
@@ -269,8 +296,9 @@ translate([x1, leadnuts_y])
|
||||
|
||||
leds_y = 0;
|
||||
carriers_y = leds_y + 40;
|
||||
spades_y = carriers_y + 40;
|
||||
buttons_y = spades_y + 40;
|
||||
magnets_y = carriers_y + 40;
|
||||
spades_y = magnets_y + 20;
|
||||
buttons_y = spades_y + 20;
|
||||
jacks_y = buttons_y + 40;
|
||||
microswitches_y = jacks_y + 40;
|
||||
rockers_y = microswitches_y + 40;
|
||||
@@ -280,16 +308,19 @@ components_y = toggles_y + 40;
|
||||
translate([x2, leds_y])
|
||||
leds();
|
||||
|
||||
translate([x2 + 40, leds_y])
|
||||
translate([x2 + 35, leds_y])
|
||||
ldrs();
|
||||
|
||||
translate([x2 + 8, carriers_y])
|
||||
carriers();
|
||||
|
||||
translate([x2+ 38, carriers_y])
|
||||
meters();
|
||||
translate([x2, magnets_y])
|
||||
magnets();
|
||||
|
||||
translate([x2 + 68, carriers_y])
|
||||
translate([x2 + 20, carriers_y])
|
||||
led_meters();
|
||||
|
||||
translate([x2 + 70, leds_y])
|
||||
fuseholders();
|
||||
|
||||
translate([x2, spades_y])
|
||||
@@ -321,7 +352,8 @@ ssrs_y = modules_y + 80;
|
||||
blowers_y = ssrs_y + 60;
|
||||
batteries_y = blowers_y + 100;
|
||||
steppers_y = batteries_y + 70;
|
||||
extrusions_y = steppers_y + 100;
|
||||
panel_meters_y = steppers_y + 70;
|
||||
extrusions_y = panel_meters_y + 80;
|
||||
|
||||
translate([x3, veroboard_y])
|
||||
veroboard_test();
|
||||
@@ -332,9 +364,15 @@ translate([x3 + 70, veroboard_y + 30])
|
||||
translate([x3 + 140, veroboard_y + 20])
|
||||
pcb_mounts();
|
||||
|
||||
translate([x3 + 170, veroboard_y + 16])
|
||||
cameras();
|
||||
|
||||
translate([x3, d_connectors_y])
|
||||
d_connectors();
|
||||
|
||||
translate([x3 + 170, d_connectors_y - 10])
|
||||
camera_housings();
|
||||
|
||||
translate([x3, iecs_y])
|
||||
iecs();
|
||||
|
||||
@@ -362,9 +400,11 @@ translate([x3, batteries_y])
|
||||
translate([x2, steppers_y]) // interloper
|
||||
stepper_motors();
|
||||
|
||||
translate([x2, extrusions_y]) {
|
||||
translate([x2, panel_meters_y])
|
||||
panel_meters();
|
||||
|
||||
translate([x2, extrusions_y])
|
||||
extrusions();
|
||||
}
|
||||
|
||||
translate([x3, transformers_y])
|
||||
transformers();
|
||||
@@ -377,17 +417,21 @@ sk_brackets_y = extrusion_brackets_y + 80;
|
||||
kp_pillow_blocks_y = sk_brackets_y + 50;
|
||||
scs_bearing_blocks_y = kp_pillow_blocks_y + 60;
|
||||
|
||||
translate([x4 + 150, belts_y + 58]) {
|
||||
translate([x4 + 200, belts_y + 58]) {
|
||||
belt_test();
|
||||
|
||||
translate([0, 60])
|
||||
opengrab_test();
|
||||
|
||||
}
|
||||
|
||||
translate([x4 + 175, belts_y, -20])
|
||||
drag_chains();
|
||||
|
||||
translate([x4, rails_y + 130])
|
||||
rails();
|
||||
|
||||
translate([800, fans_y + 50])
|
||||
translate([770, fans_y + 50])
|
||||
cable_strips();
|
||||
|
||||
translate([x4, kp_pillow_blocks_y])
|
||||
@@ -399,6 +443,9 @@ translate([x4, sk_brackets_y])
|
||||
translate([x4, extrusion_brackets_y])
|
||||
extrusion_brackets();
|
||||
|
||||
translate([x4 + 120, extrusion_brackets_y])
|
||||
shaft_couplings();
|
||||
|
||||
translate([x4, scs_bearing_blocks_y])
|
||||
scs_bearing_blocks();
|
||||
|
||||
|
233
printed/box.scad
@@ -31,26 +31,29 @@
|
||||
//!
|
||||
//! Normally the side sheets are the same type but they can be overridden individually as long as the substitute has the same thickness.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
include <../core.scad>
|
||||
use <../vitamins/sheet.scad>
|
||||
use <../vitamins/screw.scad>
|
||||
use <../vitamins/washer.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
use <../utils/quadrant.scad>
|
||||
use <../utils/round.scad>
|
||||
|
||||
bezel_clearance = 0.2;
|
||||
sheet_end_clearance = 1;
|
||||
sheet_slot_clearance = 0.2;
|
||||
|
||||
function box_screw(type) = type[0]; //! Screw type to be used at the corners
|
||||
function box_wall(type) = type[1]; //! Wall thickness of 3D parts
|
||||
function box_sheets(type) = type[2]; //! Sheet type used for the sides
|
||||
function box_top_sheet(type) = type[3]; //! Sheet type for the top
|
||||
function box_base_sheet(type)= type[4]; //! Sheet type for the bottom
|
||||
function box_feet(type) = type[5]; //! True to enable feet on the bottom bezel
|
||||
function box_width(type) = type[6]; //! Internal width
|
||||
function box_depth(type) = type[7]; //! Internal depth
|
||||
function box_height(type) = type[8]; //! Internal height
|
||||
function box_screw(type) = type[0]; //! Screw type to be used at the corners
|
||||
function box_shelf_screw(type) = type[1]; //! Screw type to hold a shelf
|
||||
function box_wall(type) = type[2]; //! Wall thickness of 3D parts
|
||||
function box_sheets(type) = type[3]; //! Sheet type used for the sides
|
||||
function box_top_sheet(type) = type[4]; //! Sheet type for the top
|
||||
function box_base_sheet(type) = type[5]; //! Sheet type for the bottom
|
||||
function box_feet(type) = type[6]; //! True to enable feet on the bottom bezel
|
||||
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_bezel_clearance(type) = bezel_clearance;
|
||||
|
||||
@@ -59,6 +62,7 @@ function box_profile_overlap(type) = 3 + sheet_end_clearance / 2;
|
||||
|
||||
function box_washer(type) = screw_washer(box_screw(type));
|
||||
function box_insert(type) = screw_insert(box_screw(type));
|
||||
function box_shelf_insert(type) = screw_insert(box_shelf_screw(type));
|
||||
|
||||
function box_hole_inset(type) = washer_radius(box_washer(type)) + 1;
|
||||
function box_insert_r(type) = insert_hole_radius(box_insert(type));
|
||||
@@ -87,32 +91,42 @@ function box_bezel_height(type, bottom) = //! Bezel height for top or bottom
|
||||
|
||||
grill_hole = 5;
|
||||
grill_gap = 1.9;
|
||||
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
|
||||
|
||||
function box_grill_hole_r() = grill_hole / 2;
|
||||
|
||||
module grill_hole_positions(width, height, r = 1000) {
|
||||
nx = floor(width / (grill_hole + grill_gap));
|
||||
xpitch = width / nx;
|
||||
ny = floor(height / ((grill_hole + grill_gap) * cos(30)));
|
||||
ypitch = height / ny;
|
||||
|
||||
for(y = [0 : ny - 1], x = [0 : nx - 1 - (y % 2)]) {
|
||||
$x = -width / 2 + (x + 0.5 + (y % 2) / 2) * xpitch;
|
||||
$y = -height / 2 + (y + 0.5) * ypitch;
|
||||
if(sqrt(sqr($x) + sqr($y)) + grill_hole / 2 <= r)
|
||||
translate([$x, $y])
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
|
||||
extrude_if(h)
|
||||
for(y = [0 : ny - 1], x = [0 : nx - 1 - (y % 2)]) {
|
||||
x = -width / 2 + (x + 0.5 + (y % 2) / 2) * xpitch;
|
||||
y = -height / 2 + (y + 0.5) * ypitch;
|
||||
if(sqrt(sqr(x) + sqr(y)) + grill_hole / 2 <= r)
|
||||
translate([x, y])
|
||||
if(poly)
|
||||
poly_circle(r = grill_hole / 2);
|
||||
else
|
||||
circle(d = grill_hole);
|
||||
}
|
||||
if(poly)
|
||||
grill_hole_positions(width, height, r)
|
||||
poly_circle(r = grill_hole / 2);
|
||||
else
|
||||
grill_hole_positions(width, height, r)
|
||||
circle(d = grill_hole);
|
||||
}
|
||||
|
||||
module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
|
||||
t = box_sheet_slot(type);
|
||||
inset = box_corner_gap(type) + box_profile_overlap(type);
|
||||
difference() {
|
||||
union() {
|
||||
quadrant(box_hole_inset(type) + box_boss_r(type), box_boss_r(type)); // inside corner
|
||||
|
||||
translate([box_corner_gap(type) + box_profile_overlap(type), box_corner_gap(type) + box_profile_overlap(type)])
|
||||
translate([inset, inset])
|
||||
rotate(180)
|
||||
quadrant(box_profile_overlap(type) + box_corner_rad(type), box_corner_rad(type)); // outside corner
|
||||
}
|
||||
@@ -175,6 +189,15 @@ module box_corner_profile_section(type, section, sections) { //! Generates inter
|
||||
}
|
||||
}
|
||||
|
||||
module box_corner_profile_sections(type, section, sections) { //! Generate four copies of a corner profile section
|
||||
stl("box_corner_profile");
|
||||
offset = box_boss_r(type) + 1;
|
||||
for(i = [0 : 3])
|
||||
rotate(i * 90)
|
||||
translate([offset, offset])
|
||||
box_corner_profile_section(type, section, sections);
|
||||
}
|
||||
|
||||
module box_corner_quadrants(type, width, depth)
|
||||
for(corner = [0:3]) {
|
||||
x = [-1,1,1,-1][corner];
|
||||
@@ -190,33 +213,39 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
feet = bottom && box_feet(type);
|
||||
t = box_sheet_slot(type);
|
||||
outset = box_outset(type);
|
||||
inset = box_inset(type);
|
||||
inner_r = box_sheet_r(type);
|
||||
foot_height = box_corner_gap(type) + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
|
||||
cgap = box_corner_gap(type);
|
||||
foot_height = cgap + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
|
||||
foot_length = box_corner_rad(type) * 2;
|
||||
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() {
|
||||
rounded_rectangle([box_width(type) + 2 * outset, box_depth(type) + 2 * outset, feet ? foot_height : height], box_corner_rad(type), false);
|
||||
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([box_width(type) - 2 * foot_length, box_depth(type) + 2 * outset + 1, 1], center = true);
|
||||
cube([w - 2 * foot_length, td + 1, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([box_width(type) - 2 * (foot_length - foot_extension), box_depth(type) + 2 * outset + 1, 1], center = true);
|
||||
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
|
||||
}
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * foot_length, 1], center = true);
|
||||
cube([tw + 1, d - 2 * foot_length, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -225,28 +254,28 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
translate_z(-box_profile_overlap(type))
|
||||
linear_extrude(2 * box_profile_overlap(type), center = true)
|
||||
for(i = [-1, 1]) {
|
||||
translate([i * (box_width(type) / 2 + t / 2 - sheet_slot_clearance / 2), 0])
|
||||
square([t, box_depth(type) - 2 * box_corner_gap(type)], center = true);
|
||||
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
|
||||
square([t, d - 2 * cgap], center = true);
|
||||
|
||||
translate([0, i * (box_depth(type) / 2 + t / 2 - sheet_slot_clearance / 2)])
|
||||
square([box_width(type) - 2 * box_corner_gap(type), t], 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(box_corner_gap(type))
|
||||
rounded_rectangle([box_width(type) + bezel_clearance, box_depth(type) + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
|
||||
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) + box_corner_gap(type) + 2)
|
||||
linear_extrude(box_profile_overlap(type) + cgap + 2)
|
||||
union() {
|
||||
difference() {
|
||||
square([box_width(type) - 2 * box_inset(type),
|
||||
box_depth(type) - 2 * box_inset(type)], center = true);
|
||||
square([w - 2 * inset,
|
||||
d - 2 * inset], center = true);
|
||||
|
||||
box_corner_quadrants(type, box_width(type), box_depth(type));
|
||||
box_corner_quadrants(type, w, d);
|
||||
}
|
||||
box_screw_hole_positions(type)
|
||||
poly_circle(screw_clearance_radius(box_screw(type)));
|
||||
@@ -258,17 +287,20 @@ dowel_length = 20;
|
||||
dowel_wall = extrusion_width * 3;
|
||||
dowel_h_wall = layer_height * 6;
|
||||
|
||||
|
||||
module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlocking sections of the bezel to allow it to be bigger than the printer
|
||||
w = (box_width(type) + 2 * box_outset(type)) / cols;
|
||||
h = (box_depth(type) + 2 * box_outset(type)) / rows;
|
||||
tw = box_width(type) + 2 * box_outset(type);
|
||||
w = tw / cols;
|
||||
th = box_depth(type) + 2 * box_outset(type);
|
||||
h = th / rows;
|
||||
bw = box_outset(type) - bezel_clearance / 2;
|
||||
bw2 = box_outset(type) + box_inset(type);
|
||||
|
||||
dw = bw - 2 * dowel_wall;
|
||||
dh = box_bezel_height(type, bottom) - dowel_h_wall;
|
||||
|
||||
dh2 = box_profile_overlap(type) + box_corner_gap(type) - dowel_h_wall;
|
||||
profile_overlap = box_profile_overlap(type);
|
||||
|
||||
dh2 = profile_overlap + box_corner_gap(type) - dowel_h_wall;
|
||||
|
||||
end_clearance = 0.5;
|
||||
module male() {
|
||||
@@ -276,14 +308,14 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
|
||||
linear_extrude(dowel_length - 2 * end_clearance, center = true)
|
||||
difference() {
|
||||
union() {
|
||||
h = dh - layer_height;
|
||||
h1 = dh - layer_height;
|
||||
h2 = dh2 - layer_height;
|
||||
hull() {
|
||||
translate([bw / 2, h / 2])
|
||||
square([dw - 1, h], center = true);
|
||||
translate([bw / 2, h1 / 2])
|
||||
square([dw - 1, h1], center = true);
|
||||
|
||||
translate([bw / 2, (h - 1) / 2])
|
||||
square([dw, h - 1], center = true);
|
||||
translate([bw / 2, (h1 - 1) / 2])
|
||||
square([dw, h1 - 1], center = true);
|
||||
}
|
||||
|
||||
hull() {
|
||||
@@ -295,7 +327,7 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
|
||||
}
|
||||
}
|
||||
translate([bw2 / 2, 0])
|
||||
square([box_sheet_slot(type), 2 * box_profile_overlap(type)], center = true);
|
||||
square([box_sheet_slot(type), 2 * profile_overlap], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +368,7 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
|
||||
render() difference() {
|
||||
union() {
|
||||
clip(xmin = 0, xmax = w, ymin = 0, ymax = h)
|
||||
translate([box_width(type) / 2 + box_outset(type) - x * w, box_depth(type) / 2 + box_outset(type) - y * h, box_profile_overlap(type)])
|
||||
translate([tw / 2 - x * w, th / 2 - y * h, profile_overlap])
|
||||
box_bezel(type, bottom);
|
||||
|
||||
if(x < cols - 1 && y == 0)
|
||||
@@ -396,11 +428,14 @@ module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module box_screw_hole_positions(type)
|
||||
module box_screw_hole_positions(type) {
|
||||
inset = box_hole_inset(type);
|
||||
w = box_width(type) / 2 - inset;
|
||||
d = box_depth(type) / 2 - inset;
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (box_width(type) / 2 - box_hole_inset(type)), y * (box_depth(type) / 2 - box_hole_inset(type))])
|
||||
translate([x * w, y * d])
|
||||
children();
|
||||
}
|
||||
|
||||
module box_base_blank(type) { //! Generates a 2D template for the base sheet
|
||||
dxf("box_base");
|
||||
@@ -439,6 +474,96 @@ module box_shelf_blank(type, sheet = false) { //! Generates a 2D template for a
|
||||
}
|
||||
}
|
||||
|
||||
module box_shelf_screw_positions(type, screw_positions, thickness = 0, wall = undef) { //! Place children at the shelf screw positions
|
||||
w = is_undef(wall) ? box_wall(type) : wall;
|
||||
insert = box_shelf_insert(type);
|
||||
translate_z(-insert_boss_radius(insert, w))
|
||||
for(p = screw_positions)
|
||||
multmatrix(p)
|
||||
translate_z(thickness)
|
||||
children();
|
||||
}
|
||||
|
||||
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);
|
||||
width = insert_length(insert) + w;
|
||||
|
||||
module shape()
|
||||
difference() {
|
||||
square([box_width(type), box_depth(type)], center = true);
|
||||
|
||||
offset(bezel_clearance / 2)
|
||||
box_corner_quadrants(type, box_width(type), box_depth(type));
|
||||
|
||||
if($children)
|
||||
hflip()
|
||||
children();
|
||||
}
|
||||
|
||||
module boss()
|
||||
translate_z(-width + eps)
|
||||
linear_extrude(width - 2 * eps)
|
||||
hull() {
|
||||
circle4n(r = lip / 2 - eps);
|
||||
|
||||
translate([-lip / 2, -lip / 2 + eps])
|
||||
square([lip, eps]);
|
||||
}
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(w)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
|
||||
round(2) offset(-width)
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
tw = box_width(type);
|
||||
w = tw / cols;
|
||||
th = box_depth(type);
|
||||
h = th / rows;
|
||||
|
||||
clip(xmin = 0, xmax = w, ymin = 0, ymax = h)
|
||||
translate([tw / 2 - x * w, th / 2 - y * h])
|
||||
children();
|
||||
}
|
||||
|
||||
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, ```sheet``` can be set to override the type
|
||||
dxf("box_left");
|
||||
|
||||
|
@@ -50,6 +50,9 @@ function bbox_name(type) = type[8] ? type[8] : "bbox"; //! Optional name i
|
||||
function bbox_skip_blocks(type)= type[9] ? type[9] : []; //! List of fixing blocks to skip, used to allow a hinged panel for example
|
||||
function star_washers(type) = type[10] ? type[10] : is_undef(type[10]); //! Set to false to remove star washers.
|
||||
|
||||
function bbox(screw, sheets, base_sheet, top_sheet, span, size, name = "bbox", skip_blocks = [], star_washers = true) = //! Construct the property list for a butt_box
|
||||
[ 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
|
||||
2 * (w * d + w * h + d * h) / 1000000;
|
||||
@@ -107,12 +110,9 @@ function fixing_block_positions(type) = let(
|
||||
|
||||
function side_holes(type) = [for(p = fixing_block_positions(type), q = fixing_block_holes(bbox_screw(type))) p * q];
|
||||
|
||||
module drill_holes(type, t)
|
||||
for(list = [corner_holes(type), side_holes(type)], p = list)
|
||||
let(q = t * p)
|
||||
if(abs(transform([0, 0, 0], q).z) < eps)
|
||||
multmatrix(q)
|
||||
drill(screw_clearance_radius(bbox_screw(type)), 0);
|
||||
module bbox_drill_holes(type, t)
|
||||
position_children(concat(corner_holes(type), side_holes(type)), t)
|
||||
drill(screw_clearance_radius(bbox_screw(type)), 0);
|
||||
|
||||
module bbox_base_blank(type) { //! 2D template for the base
|
||||
dxf(str(bbox_name(type), "_base"));
|
||||
@@ -120,7 +120,7 @@ module bbox_base_blank(type) { //! 2D template for the base
|
||||
difference() {
|
||||
sheet_2D(bbox_base_sheet(type), bbox_width(type), bbox_depth(type), 1);
|
||||
|
||||
drill_holes(type, translate(bbox_height(type) / 2));
|
||||
bbox_drill_holes(type, translate(bbox_height(type) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ module bbox_top_blank(type) { //! 2D template for the top
|
||||
translate([0, t / 2])
|
||||
sheet_2D(bbox_top_sheet(type), bbox_width(type) + 2 * t, bbox_depth(type) + t);
|
||||
|
||||
drill_holes(type, translate(-bbox_height(type) / 2));
|
||||
bbox_drill_holes(type, translate(-bbox_height(type) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ module bbox_left_blank(type, sheet = false) { //! 2D template for the left side
|
||||
translate([-t / 2, -bb / 2])
|
||||
sheet_2D(subst_sheet(type, sheet), bbox_depth(type) + t, bbox_height(type) + bb);
|
||||
|
||||
drill_holes(type, rotate([0, 90, 90]) * translate([bbox_width(type) / 2, 0]));
|
||||
bbox_drill_holes(type, rotate([0, 90, 90]) * translate([bbox_width(type) / 2, 0]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ module bbox_right_blank(type, sheet = false) { //! 2D template for the right sid
|
||||
translate([t / 2, -bb / 2])
|
||||
sheet_2D(subst_sheet(type, sheet), bbox_depth(type) + t, bbox_height(type) + bb);
|
||||
|
||||
drill_holes(type, rotate([0, 90, 90]) * translate([-bbox_width(type) / 2, 0]));
|
||||
bbox_drill_holes(type, rotate([0, 90, 90]) * translate([-bbox_width(type) / 2, 0]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ module bbox_front_blank(type, sheet = false, width = 0) { //! 2D template for th
|
||||
translate([0, (bt - bb) / 2])
|
||||
sheet_2D(subst_sheet(type, sheet), max(bbox_width(type) + 2 * t, width), bbox_height(type) + bb + bt);
|
||||
|
||||
drill_holes(type, rotate([-90, 0, 0]) * translate([0, bbox_depth(type) / 2]));
|
||||
bbox_drill_holes(type, rotate([-90, 0, 0]) * translate([0, bbox_depth(type) / 2]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ module bbox_back_blank(type, sheet = false) { //! 2D template for the back
|
||||
translate([0, -bb / 2])
|
||||
sheet_2D(subst_sheet(type, sheet), bbox_width(type), bbox_height(type) + bb);
|
||||
|
||||
drill_holes(type, rotate([-90, 0, 0]) * translate([0, -bbox_depth(type) / 2]));
|
||||
bbox_drill_holes(type, rotate([-90, 0, 0]) * translate([0, -bbox_depth(type) / 2]));
|
||||
}
|
||||
}
|
||||
|
||||
|
392
printed/camera_housing.scad
Normal file
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Housings for PCB cameras.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/cameras.scad>
|
||||
use <../vitamins/pcb.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
|
||||
wall = 1.75;
|
||||
min_wall = 2 * extrusion_width;
|
||||
clearance = 0.2;
|
||||
|
||||
connector_size = [23, 6, 2.65]; // Worst case size of flat flex connector
|
||||
|
||||
cam_back_clearance = round_to_layer(1.5); // Clearance for components on the back of the pcb
|
||||
cam_back_overlap = 1; // How much the back overlaps the edge of the pcb
|
||||
cam_back_wall = min_wall;
|
||||
|
||||
function cam_front_clearance(cam) = round_to_layer(camera_connector_size(cam).z + clearance);
|
||||
|
||||
function cam_back_size(cam) = let(
|
||||
pcb = camera_pcb(cam),
|
||||
pcb_size = pcb_size(pcb),
|
||||
nut = screw_nut(pcb_screw(pcb)),
|
||||
holes = [for(h = pcb_holes(pcb)) pcb_coord(pcb, h).x],
|
||||
pitch = max(holes) - min(holes),
|
||||
length = pitch + 2 * (nut_radius(nut) + min_wall),
|
||||
width = pcb_size.y + (length - pcb_size.x) * cos(30)
|
||||
) [length, width, wall + max(connector_size.z, cam_back_clearance + nut_trap_depth(nut))];
|
||||
|
||||
|
||||
function cam_front_size(cam) = cam_back_size(cam) + [ //! Outside dimensions of the case
|
||||
2 * (wall + clearance),
|
||||
2 * (wall + clearance),
|
||||
pcb_thickness(camera_pcb(cam)) + cam_front_clearance(cam) + wall
|
||||
];
|
||||
|
||||
hinge_screw = M2_cap_screw;
|
||||
hinge_nut = screw_nut(hinge_screw);
|
||||
hinge_screw_length = 12;
|
||||
|
||||
hinge_r = nut_trap_radius(hinge_nut) + 3 * extrusion_width;
|
||||
hinge_h = wall + nut_trap_depth(hinge_nut);
|
||||
hinge_offset = hinge_r + 1;
|
||||
|
||||
bracket_screw = M3_dome_screw;
|
||||
|
||||
function cam_screw_length(cam) = let(
|
||||
front = cam_front_size(cam),
|
||||
screw = pcb_screw(camera_pcb(cam)),
|
||||
nut = screw_nut(screw)
|
||||
) screw_longer_than(front.z + washer_thickness(screw_washer(screw)) - nut_trap_depth(nut) + nut_thickness(nut, true));
|
||||
|
||||
function hinge_z(cam) = cam_screw_length(cam) - hinge_r;
|
||||
|
||||
module cam_holes(cam) {
|
||||
pcb = camera_pcb(cam);
|
||||
lens_y = camera_lens_offset(cam).y;
|
||||
two_holes = !!len([for (h = pcb_holes(pcb)) if(abs(pcb_coord(pcb, h).y - lens_y) < 1) true]);
|
||||
pcb_screw_positions(pcb) // screw holes
|
||||
if($i > 1 || !two_holes)
|
||||
children();
|
||||
}
|
||||
|
||||
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;
|
||||
hole_r2 = 5 / 2;
|
||||
thickness = 3;
|
||||
flutes = 8;
|
||||
angle = 180 / flutes;
|
||||
x = rad / (sin(angle / 2) + cos(angle / 2));
|
||||
r = x * sin(angle / 2);
|
||||
|
||||
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 + angle])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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_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);
|
||||
pcb_size = pcb_size(pcb);
|
||||
lens_offset = camera_lens_offset(cam);
|
||||
screw = pcb_screw(pcb);
|
||||
|
||||
shelf = front.z - back.z;
|
||||
|
||||
connector_slot = connector_size + 2 * [clearance, 0, layer_height];
|
||||
rad = wall;
|
||||
led_hole_r = 1;
|
||||
led_clearance = [5, 2, 1 * 2];
|
||||
res_clearance = [3.5, 2, 1 * 2];
|
||||
|
||||
conn_pos = camera_connector_pos(cam);
|
||||
conn = camera_connector_size(cam);
|
||||
sensor_length = conn_pos.y + conn.y / 2 - lens_offset.y + clearance;
|
||||
|
||||
module hinge_pos()
|
||||
if(!is_undef(hinge))
|
||||
rotate(hinge * 90)
|
||||
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);
|
||||
|
||||
translate_z(rad)
|
||||
sphere(rad);
|
||||
|
||||
cylinder(r = rad * (sqrt(2) - 1), h = eps);
|
||||
}
|
||||
|
||||
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([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);
|
||||
|
||||
hflip()
|
||||
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));
|
||||
|
||||
module camera_bracket_screw_positions(cam) { //! Position children at the bracket screw positions
|
||||
r = washer_radius(screw_washer(bracket_screw)) + 0.5;
|
||||
wide = bracket_thickness(cam) == wall;
|
||||
pitch = wide ? cam_front_size(cam).x / 2 - r : hinge_h + 1 + r;
|
||||
|
||||
for(side = [-1, 1])
|
||||
translate([side * pitch, 0])
|
||||
children();
|
||||
}
|
||||
|
||||
module camera_bracket_position(cam) //! Position children at the bracket position
|
||||
translate([0, cam_front_size(cam).y / 2 + hinge_offset])
|
||||
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);
|
||||
}
|
||||
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()
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
module camera_assembly(cam, angle = 0) //! Camera case assembly
|
||||
assembly(str("camera_", cam[0])) {
|
||||
front = cam_front_size(cam);
|
||||
screw = pcb_screw(camera_pcb(cam));
|
||||
nut = screw_nut(screw);
|
||||
screw_length = cam_screw_length(cam);
|
||||
hinge_z = hinge_z(cam);
|
||||
hinge_pos = [0, front.y / 2 + hinge_offset, -hinge_r];
|
||||
|
||||
camera_bracket_position(cam) {
|
||||
nut = screw_nut(hinge_screw);
|
||||
|
||||
stl_colour(pp1_colour) render()
|
||||
camera_bracket(cam);
|
||||
|
||||
translate([-hinge_h, 0, hinge_z(cam)])
|
||||
rotate([-90, 0, 90]) {
|
||||
vflip()
|
||||
translate_z(2 * hinge_h - nut_trap_depth(nut))
|
||||
nut(nut, true);
|
||||
|
||||
screw_and_washer(hinge_screw, screw_longer_than(2 * hinge_h));
|
||||
}
|
||||
}
|
||||
|
||||
translate_z(hinge_z(cam) + hinge_r)
|
||||
translate(hinge_pos)
|
||||
rotate([-angle, 0, 0])
|
||||
translate(-hinge_pos) {
|
||||
translate_z(cam_back_size(cam).z - front.z)
|
||||
camera(cam);
|
||||
|
||||
stl_colour(pp1_colour) render()
|
||||
translate_z(-front.z)
|
||||
camera_back(cam);
|
||||
|
||||
cam_holes(cam) {
|
||||
screw_and_washer(screw, screw_length);
|
||||
|
||||
translate_z(-front.z + nut_trap_depth(nut))
|
||||
vflip()
|
||||
nut(nut, true);
|
||||
}
|
||||
|
||||
*translate(camera_lens_offset(cam))
|
||||
translate_z(1.5)
|
||||
stl_colour(pp1_colour) render()
|
||||
rpi_camera_focus_ring_stl();
|
||||
|
||||
stl_colour(pp2_colour) render()
|
||||
hflip()
|
||||
camera_front(cam, 0);
|
||||
}
|
||||
}
|
||||
|
||||
module camera_fastened_assembly(cam, thickness, angle = 0) {
|
||||
camera_assembly(cam, angle);
|
||||
|
||||
camera_bracket_position(cam)
|
||||
camera_bracket_screw_positions(cam) {
|
||||
nut = screw_nut(bracket_screw);
|
||||
washer = screw_washer(bracket_screw);
|
||||
t = bracket_thickness(cam);
|
||||
screw_length = screw_longer_than(thickness + t + nut_thickness(nut, true) + 2 * washer_thickness(washer));
|
||||
vflip()
|
||||
translate_z(thickness)
|
||||
screw_and_washer(bracket_screw, screw_length);
|
||||
|
||||
translate_z(t)
|
||||
nut_and_washer(nut, true);
|
||||
}
|
||||
}
|
||||
|
||||
module camera_back_rpi_camera_stl() camera_back(rpi_camera);
|
||||
module camera_back_rpi_camera_v1_stl() camera_back(rpi_camera_v1);
|
||||
module camera_back_rpi_camera_v2_stl() camera_back(rpi_camera_v2);
|
||||
|
||||
module camera_front_rpi_camera_stl() camera_front(rpi_camera);
|
||||
module camera_front_rpi_camera_v1_stl() camera_front(rpi_camera_v1);
|
||||
module camera_front_rpi_camera_v2_stl() camera_front(rpi_camera_v2);
|
||||
|
||||
module camera_bracket_rpi_camera_stl() camera_bracket(rpi_camera);
|
||||
module camera_bracket_rpi_camera_v1_stl() camera_bracket(rpi_camera_v1);
|
||||
module camera_bracket_rpi_camera_v2_stl() camera_bracket(rpi_camera_v2);
|
||||
|
||||
module camera_rpi_camera_assembly() camera_assembly(rpi_camera);
|
||||
module camera_rpi_camera_v1_assembly() camera_assembly(rpi_camera_v1);
|
||||
module camera_rpi_camera_v2_assembly() camera_assembly(rpi_camera_v2);
|
||||
|
||||
module camera_housing(cam) {
|
||||
front = cam_front_size(cam);
|
||||
|
||||
camera_front(cam, 0);
|
||||
|
||||
translate([front.x, 0])
|
||||
camera_back(cam);
|
||||
|
||||
translate([-front.x / 2 - 2 - hinge_r, 0])
|
||||
rotate(90)
|
||||
camera_bracket(cam);
|
||||
}
|
||||
|
||||
cam = rpi_camera_v2;
|
||||
if($preview)
|
||||
camera_fastened_assembly(cam, 3);
|
||||
else
|
||||
camera_housing(cam);
|
@@ -74,7 +74,7 @@ module door_hinge(door_thickness) { //! Generates STL fo
|
||||
square([1, thickness + door_thickness]);
|
||||
}
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
}
|
||||
linear_extrude(thickness)
|
||||
difference() {
|
||||
@@ -127,7 +127,7 @@ module door_hinge_stat_stl() { //! Generates the STL for the stationary part
|
||||
square([dia, 1], center = true);
|
||||
}
|
||||
translate([0, dia / 2 + stat_clearance])
|
||||
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
321
printed/drag_chain.scad
Normal file
@@ -0,0 +1,321 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! 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.
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! The ends can have screw lugs with four screw positions to choose from, specified by a list of two arrays of four bools.
|
||||
//! If none are enabled then a child object is expected to customise the end and this gets unioned with the blank end.
|
||||
//! If both ends are customised then two children are expected.
|
||||
//! Each child is called twice, once with ```$fasteners``` set to 0 to augment the STL and again with ```$fasteners``` set to 1 to add
|
||||
//! to the assembly, for example to add inserts.
|
||||
//
|
||||
|
||||
include <../core.scad>
|
||||
use <../utils/horiholes.scad>
|
||||
use <../utils/maths.scad>
|
||||
|
||||
clearance = 0.1;
|
||||
|
||||
function drag_chain_name(type) = type[0]; //! The name to allow more than one in a project
|
||||
function drag_chain_size(type) = type[1]; //! The internal size and link length
|
||||
function drag_chain_travel(type) = type[2]; //! X travel
|
||||
function drag_chain_wall(type) = type[3]; //! Side wall thickness
|
||||
function drag_chain_bwall(type) = type[4]; //! Bottom wall
|
||||
function drag_chain_twall(type) = type[5]; //! Top wall
|
||||
function drag_chain_screw(type) = type[6]; //! Mounting screw for the ends
|
||||
function drag_chain_screw_lists(type) = type[7]; //! Two lists of four bools to say which screws positions are used
|
||||
|
||||
function drag_chain_clearance() = clearance; //! Clearance around joints.
|
||||
|
||||
function drag_chain_radius(type) = //! The bend radius at the pivot centres
|
||||
let(s = drag_chain_size(type))
|
||||
s.x / 2 / sin(360 / 16);
|
||||
|
||||
function drag_chain_z(type) = //! Outside dimension of a 180 bend
|
||||
let(os = drag_chain_outer_size(type), s = drag_chain_size(type))
|
||||
2 * drag_chain_radius(type) + os.z;
|
||||
|
||||
function drag_chain(name, size, travel, wall = 1.6, bwall = 1.5, twall = 1.5, screw = M2_cap_screw, screw_lists = [[1,0,0,1],[1,0,0,1]]) = //! Constructor
|
||||
[name, size, travel, wall, bwall, twall, screw, screw_lists];
|
||||
|
||||
function drag_chain_outer_size(type) = //! Link outer dimensions
|
||||
let(s = drag_chain_size(type), z = s.z + drag_chain_bwall(type) + drag_chain_twall(type))
|
||||
[s.x + z, s.y + 4 * drag_chain_wall(type) + 2 * clearance, z];
|
||||
|
||||
function screw_lug_radius(screw) = //! Radius of a screw lug
|
||||
corrected_radius(screw_clearance_radius(screw)) + 3.1 * extrusion_width;
|
||||
|
||||
module screw_lug(screw, h = 0) //! Create a D shaped lug for a screw
|
||||
extrude_if(h, center = false)
|
||||
difference() {
|
||||
r = screw_lug_radius(screw);
|
||||
hull() {
|
||||
circle4n(r);
|
||||
|
||||
translate([-r, -r])
|
||||
square([2 * r, eps]);
|
||||
}
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
|
||||
function bool2int(b) = b ? 1 : 0;
|
||||
|
||||
module drag_chain_screw_positions(type, end) { //! Place children at the screw positions, end = 0 for the start, 1 for the end
|
||||
r = screw_lug_radius(drag_chain_screw(type));
|
||||
s = drag_chain_size(type);
|
||||
os = drag_chain_outer_size(type);
|
||||
R = os.z / 2;
|
||||
x0 = end ? R + norm([drag_chain_cam_x(type), R - drag_chain_twall(type)]) + clearance + r : r;
|
||||
x1 = end ? os.x - r : os.x - 2 * R - clearance - r;
|
||||
for(i = [0 : 3], x = [x0, x1, x0, x1][i], y = [-1, -1, 1, 1][i])
|
||||
if(drag_chain_screw_lists(type)[bool2int(end)][i])
|
||||
translate([x, y * (s.y / 2 + r)])
|
||||
let($a = [180, 0, 180, 0][i])
|
||||
children();
|
||||
}
|
||||
|
||||
function drag_chain_cam_x(type) = // how far the cam sticks out
|
||||
let(s = drag_chain_size(type),
|
||||
r = drag_chain_outer_size(type).z / 2,
|
||||
wall = drag_chain_wall(type),
|
||||
cam_r = s.x - 2 * clearance - wall - r, // inner_x_normal - clearance - r
|
||||
twall = drag_chain_twall(type)
|
||||
) min(sqrt(max(sqr(cam_r) - sqr(r - twall), 0)), r);
|
||||
|
||||
module drag_chain_link(type, start = false, end = false, check_kids = true) { //! One link of the chain, special case for start and end
|
||||
stl(str(drag_chain_name(type), "_drag_chain_link", start ? "_start" : end ? "_end" : ""));
|
||||
|
||||
s = drag_chain_size(type);
|
||||
wall = drag_chain_wall(type);
|
||||
bwall = drag_chain_bwall(type);
|
||||
twall = drag_chain_twall(type);
|
||||
os = drag_chain_outer_size(type);
|
||||
r = os.z / 2;
|
||||
pin_r = r / 2;
|
||||
|
||||
socket_x = r;
|
||||
pin_x = socket_x + s.x;
|
||||
|
||||
outer_normal_x = pin_x - r - clearance; // s.x - clearance
|
||||
outer_end_x = end ? os.x : outer_normal_x;
|
||||
|
||||
inner_x = start ? 0 : outer_normal_x - wall; // s.x - clearance - wall
|
||||
|
||||
roof_x_normal = 2 * r - twall;
|
||||
roof_x = start ? 0 : roof_x_normal;
|
||||
|
||||
floor_x = start ? 0 : 2 * r;
|
||||
cam_x = drag_chain_cam_x(type);
|
||||
assert(r + norm([drag_chain_cam_x(type), r - drag_chain_twall(type)]) + clearance <= inner_x || start, "Link must be longer");
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
rotate([90, 0, 0]) {
|
||||
// Outer cheeks
|
||||
translate_z(side * (os.y / 2 - wall / 2))
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
hull() {
|
||||
if(start)
|
||||
square([eps, os.z]);
|
||||
else
|
||||
translate([socket_x, r])
|
||||
rotate(180)
|
||||
teardrop(r = r, h = 0);
|
||||
|
||||
translate([outer_end_x - eps, 0])
|
||||
square([eps, os.z]);
|
||||
}
|
||||
if(!start)
|
||||
translate([socket_x, r])
|
||||
horihole(pin_r, r);
|
||||
}
|
||||
// Inner cheeks
|
||||
translate_z(side * (s.y / 2 + wall / 2))
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
if(!end) {
|
||||
translate([pin_x, r])
|
||||
rotate(180)
|
||||
teardrop(r = r, h = 0);
|
||||
|
||||
translate([pin_x, twall])
|
||||
square([cam_x, eps]);
|
||||
}
|
||||
else
|
||||
translate([os.x - eps, 0])
|
||||
square([eps, os.z]);
|
||||
|
||||
translate([inner_x, 0])
|
||||
square([eps, os.z]);
|
||||
}
|
||||
}
|
||||
// Cutout for top wall
|
||||
if(!end)
|
||||
intersection() {
|
||||
translate([pin_x - r, 0])
|
||||
square([3 * r, twall]); // When straight
|
||||
|
||||
translate([pin_x, r])
|
||||
rotate(-45)
|
||||
translate([-r + roof_x_normal, -r - twall]) // When bent fully
|
||||
square(os.z);
|
||||
}
|
||||
}
|
||||
// Pin
|
||||
if(!end)
|
||||
translate([pin_x, r, side * (s.y / 2 + wall + clearance)])
|
||||
horicylinder(r = pin_r, z = r, h = 2 * wall);
|
||||
|
||||
// Cheek joint
|
||||
translate([inner_x, 0, side * (s.y / 2 + wall) - 0.5])
|
||||
cube([outer_end_x - inner_x, os.z, 1]);
|
||||
}
|
||||
|
||||
// Roof, actually the floor when printed
|
||||
roof_end = end ? s.x + 2 * r : s.x + r - twall - clearance;
|
||||
translate([roof_x, -s.y / 2 - 0.5])
|
||||
cube([roof_end - roof_x , s.y + 1, twall]);
|
||||
|
||||
translate([roof_x, -os.y / 2 + 0.5])
|
||||
cube([s.x - clearance - roof_x, os.y - 1, twall]);
|
||||
|
||||
// Floor, actually the roof when printed
|
||||
floor_end = end ? s.x + 2 * r : s.x + r;
|
||||
translate([floor_x, -s.y / 2 - wall, os.z - bwall])
|
||||
cube([floor_end - floor_x, s.y + 2 * wall, bwall]);
|
||||
|
||||
translate([floor_x, -os.y / 2 + 0.5, os.z - bwall])
|
||||
cube([s.x - floor_x - clearance, os.y -1, bwall]);
|
||||
|
||||
if(start || end) {
|
||||
drag_chain_screw_positions(type, end)
|
||||
rotate($a)
|
||||
screw_lug(drag_chain_screw(type), os.z);
|
||||
|
||||
if(check_kids) {
|
||||
custom = drag_chain_screw_lists(type)[bool2int(end)] == [0, 0, 0, 0];
|
||||
assert($children == bool2int(custom), str("wrong number of children for ", end ? "end" : "start", " STL customisation: ", $children));
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
if(start || end)
|
||||
translate_z(-eps)
|
||||
drag_chain_screw_positions(type, end)
|
||||
rotate($a)
|
||||
poly_cylinder(r = screw_clearance_radius(drag_chain_screw(type)), h = os.z + 2 * eps, center = false);
|
||||
|
||||
}
|
||||
|
||||
if(show_supports() && !end) {
|
||||
for(side = [-1, 1]) {
|
||||
w = 2.1 * extrusion_width;
|
||||
translate([s.x + r + cam_x - w / 2, side * (s.y / 2 + wall / 2), twall / 2])
|
||||
cube([w, wall, twall], center = true);
|
||||
|
||||
h = round_to_layer(r - pin_r / sqrt(2));
|
||||
y = s.y / 2 + max(wall + w / 2 + clearance, 2 * wall + clearance - w / 2);
|
||||
translate([s.x + r, side * y, h / 2])
|
||||
cube([pin_r * sqrt(2), w, h], center = true);
|
||||
|
||||
gap = cam_x - pin_r / sqrt(2) + extrusion_width;
|
||||
translate([s.x + r + cam_x - gap / 2, side * (s.y / 2 + wall + clearance / 2), layer_height / 2])
|
||||
cube([gap, 2 * wall + clearance, layer_height], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to use a wrapper because can't define nested modules in an assembly
|
||||
module _drag_chain_assembly(type, pos = 0) {
|
||||
s = drag_chain_size(type);
|
||||
x = (1 + exploded()) * s.x;
|
||||
r = drag_chain_radius(type) * x / s.x;
|
||||
travel = drag_chain_travel(type);
|
||||
links = ceil(travel / s.x);
|
||||
actual_travel = links * s.x;
|
||||
z = drag_chain_outer_size(type).z;
|
||||
|
||||
zb = z / 2; // z of bottom track
|
||||
c = [actual_travel / 2 + pos / 2, 0, r + zb]; // centre of bend
|
||||
|
||||
points = [ // Calculate list of hinge points
|
||||
for(i = 0, p = [0, 0, z / 2 + 2 * r]; i < links + 5;
|
||||
i = i + 1,
|
||||
dx = p.z > c.z ? x : -x,
|
||||
p = max(p.x + dx, p.x) <= c.x ? p + [dx, 0, 0] // Straight sections
|
||||
: let(q = circle_intersect(p, x, c, r))
|
||||
q.x <= c.x ? [p.x - sqrt(sqr(x) - sqr(p.z - zb)), 0, zb] // Transition back to straight
|
||||
: q) // Circular section
|
||||
p
|
||||
];
|
||||
npoints = len(points);
|
||||
|
||||
module link(n) // Position and colour link with origin at the hinge hole
|
||||
translate([-z / 2, 0, -z / 2]) {
|
||||
stl_colour(n < 0 || n == npoints - 1 ? pp3_colour : n % 2 ? pp1_colour : pp2_colour)
|
||||
drag_chain_link(type, start = n == -1, end = n == npoints - 1, check_kids = false)
|
||||
let($fasteners = 0) children();
|
||||
let($fasteners = 1) children();
|
||||
}
|
||||
|
||||
screws = drag_chain_screw_lists(type);
|
||||
custom_start = screws[0] == [0, 0, 0, 0];
|
||||
custom_end = screws[1] == [0, 0, 0, 0];
|
||||
assert($children == bool2int(custom_start) + bool2int(custom_end), str("wrong number of children for end customisation: ", $children));
|
||||
|
||||
for(i = [0 : npoints - 2]) let(v = points[i + 1] - points[i])
|
||||
translate(points[i])
|
||||
rotate([0, -atan2(v.z, v.x), 0])
|
||||
link(i);
|
||||
|
||||
translate(points[0] - [x, 0, 0])
|
||||
link(-1)
|
||||
if(custom_start)
|
||||
children(0);
|
||||
|
||||
translate(points[npoints - 1])
|
||||
hflip()
|
||||
link(npoints - 1)
|
||||
if(custom_end)
|
||||
children(custom_start ? 1 : 0);
|
||||
}
|
||||
|
||||
//! 1. Remove the support material from the links with side cutters.
|
||||
//! 1. Clip the links together with the special ones at the ends.
|
||||
module drag_chain_assembly(type, pos = 0) //! Drag chain assembly
|
||||
assembly(str(drag_chain_name(type), "_drag_chain"), big = true)
|
||||
if($children == 2)
|
||||
_drag_chain_assembly(type, pos) {
|
||||
children(0);
|
||||
children(1);
|
||||
}
|
||||
else if($children == 1)
|
||||
_drag_chain_assembly(type, pos)
|
||||
children(0);
|
||||
else
|
||||
_drag_chain_assembly(type, pos);
|
@@ -42,6 +42,9 @@ 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 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];
|
||||
|
||||
function hinge_radius(type) = washer_radius(screw_washer(hinge_screw(type))) + 1;
|
||||
|
||||
module hinge_screw_positions(type) { //! Place children at the screw positions
|
||||
|
@@ -24,8 +24,10 @@
|
||||
include <../core.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
|
||||
foot = [25, 12, 3, 2, M4_cap_screw, 10];
|
||||
insert_foot = [20, 10, 0, 2, M3_cap_screw, 10];
|
||||
function Foot(d, h, t, r, screw, slant = 10) = [d, h, t, r, screw, slant]; //! Construct a foot property list
|
||||
|
||||
foot = Foot(25, 12, 3, 2, M4_cap_screw);
|
||||
insert_foot = Foot(20, 10, 0, 2, M3_cap_screw);
|
||||
|
||||
function insert_foot() = insert_foot; //! Default foot with insert
|
||||
|
||||
|
50
printed/press_fit.scad
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Utility for making printed press fit connectors to join printed parts.
|
||||
//!
|
||||
//! Add solvent or glue to make a permanent fixture.
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
interference = 0.0;
|
||||
|
||||
bridge_droop = layer_height; //sqrt(4 * layer_height * filament_width / PI) - layer_height;
|
||||
|
||||
module press_fit_socket(w = 5, h = 50, horizontal = false) { //! Make a square hole to accept a peg
|
||||
h = horizontal ? h : h + bridge_droop;
|
||||
|
||||
cube([w, w, 2 * h], center = true);
|
||||
}
|
||||
|
||||
module press_fit_peg(h, w = 5, horizontal = false) { //! Make a rounded chamfered peg for easy insertion
|
||||
module chamfered_square(w, horizontal) {
|
||||
h = horizontal ? w - bridge_droop : w;
|
||||
rounded_square([w, h], 1);
|
||||
}
|
||||
|
||||
translate_z(-eps)
|
||||
linear_extrude(height = h + eps - layer_height)
|
||||
chamfered_square(w + interference, horizontal);
|
||||
|
||||
translate_z(h - layer_height - eps)
|
||||
linear_extrude(height = layer_height + eps)
|
||||
chamfered_square(w - layer_height, horizontal);
|
||||
}
|
@@ -30,6 +30,9 @@ include <../core.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
use <foot.scad>
|
||||
|
||||
function pbox(name, wall, top_t, base_t, radius, size, foot = false, screw = false, ridges = [0, 0]) //! Construct a printed box property list
|
||||
= concat([name, wall, top_t, base_t, foot, screw, radius, ridges], size);
|
||||
|
||||
function pbox_name(type) = type[0]; //! Name to allow more than one box in a project
|
||||
function pbox_wall(type) = type[1]; //! Wall thickness
|
||||
function pbox_top(type) = type[2]; //! Top thickness
|
||||
@@ -71,11 +74,11 @@ function pbox_mid_offset(type) = pbox_ridges(type).y + pbox_wall(type) / 2; // O
|
||||
|
||||
function pbox_screw_inset(type) = //! How far the base screws are inset
|
||||
let(foot = pbox_foot(type),
|
||||
r = foot ? foot_diameter(foot) / 2 : washer_radius(pbox_washer(type)),
|
||||
r = foot ? foot_diameter(foot) / 2 : pbox_base(type) ? washer_radius(pbox_washer(type)) : insert_hole_radius(pbox_insert(type)),
|
||||
R = pbox_radius(type)
|
||||
) max(r, R - (R - r) / sqrt(2));
|
||||
|
||||
module pbox_screw_positions(type) {
|
||||
module pbox_screw_positions(type) { //! Place children at base screw positions
|
||||
foot = pbox_foot(type);
|
||||
inset = pbox_screw_inset(type);
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
@@ -124,6 +127,9 @@ module pbox_inner_shape(type) {
|
||||
rounded_square([w, d], rad, center = true);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -158,7 +164,7 @@ module pbox(type) { //! Generate the STL for the main case
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(total_height)
|
||||
offset(wall / 2) pbox_mid_shape(type);
|
||||
pbox_outer_shape(type);
|
||||
|
||||
if($children > 2)
|
||||
children(2);
|
||||
|
@@ -24,69 +24,72 @@ include <../core.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
use <../vitamins/cable_strip.scad>
|
||||
|
||||
wall = 2;
|
||||
wall = 1.6;
|
||||
min_wall = 2 * extrusion_width;
|
||||
screw = M3_cap_screw;
|
||||
insert = screw_insert(screw);
|
||||
screw_depth = insert_length(insert) + 1;
|
||||
|
||||
function ribbon_clamp_hole_pitch(ways) = ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(insert)); //! Hole pitch
|
||||
function ribbon_clamp_width() = 2 * (insert_hole_radius(insert) + 2); //! Width
|
||||
function ribbon_clamp_length(ways) = ribbon_clamp_hole_pitch(ways) + ribbon_clamp_width(); //! Length given ways
|
||||
function ribbon_clamp_height() = screw_depth + 1; //! Height
|
||||
function ribbon_clamp_screw_depth(screw = screw) = insert_length(screw_insert(screw)) + 1;
|
||||
function ribbon_clamp_hole_pitch(ways, screw = screw) =
|
||||
ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(screw_insert(screw))); //! Hole pitch
|
||||
|
||||
module ribbon_clamp_hole_positions(ways, side = undef) //! Place children at hole positions
|
||||
function ribbon_clamp_width(screw = screw) = 2 * (insert_hole_radius(screw_insert(screw)) + wall); //! Width
|
||||
function ribbon_clamp_length(ways, screw = screw) = ribbon_clamp_hole_pitch(ways, screw) + ribbon_clamp_width(screw); //! Length given ways
|
||||
function ribbon_clamp_height(screw = screw) = ribbon_clamp_screw_depth(screw) + 1; //! Height
|
||||
|
||||
module ribbon_clamp_hole_positions(ways, screw = screw, side = undef) //! Place children at hole positions
|
||||
for(x = is_undef(side) ? [-1, 1] : side)
|
||||
translate([x * ribbon_clamp_hole_pitch(ways) / 2, 0])
|
||||
translate([x * ribbon_clamp_hole_pitch(ways, screw) / 2, 0])
|
||||
children();
|
||||
|
||||
module ribbon_clamp_holes(ways, h = 20) //! Drill screw holes
|
||||
ribbon_clamp_hole_positions(ways)
|
||||
module ribbon_clamp_holes(ways, h = 20, screw = screw) //! Drill screw holes
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
drill(screw_clearance_radius(screw), h);
|
||||
|
||||
module ribbon_clamp(ways) { //! Generate STL for given number of ways
|
||||
stl(str("ribbon_clamp_", ways));
|
||||
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);
|
||||
d = ribbon_clamp_width();
|
||||
h = ribbon_clamp_height();
|
||||
t = h - ribbon_clamp_slot_depth() - wall;
|
||||
pitch = ribbon_clamp_hole_pitch(ways, screw);
|
||||
d = ribbon_clamp_width(screw);
|
||||
h = ribbon_clamp_height(screw);
|
||||
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), d, t], center = true);
|
||||
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);
|
||||
}
|
||||
ribbon_clamp_hole_positions(ways, -1)
|
||||
ribbon_clamp_hole_positions(ways, screw, -1)
|
||||
cylinder(d = d, h = h);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, 1)
|
||||
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)
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
translate_z(h)
|
||||
rotate(22.5)
|
||||
insert_hole(insert, screw_depth - insert_length(insert));
|
||||
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
|
||||
}
|
||||
}
|
||||
|
||||
module ribbon_clamp_assembly(ways) pose([55, 180, 25]) //! Printed part with inserts in place
|
||||
assembly(str("ribbon_clamp_", ways)) {
|
||||
h = ribbon_clamp_height();
|
||||
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) : "")) {
|
||||
h = ribbon_clamp_height(screw);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
stl_colour(pp1_colour) render()
|
||||
translate_z(h) vflip() ribbon_clamp(ways);
|
||||
translate_z(h) vflip() ribbon_clamp(ways, screw);
|
||||
|
||||
ribbon_clamp_hole_positions(ways)
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
vflip()
|
||||
insert(insert);
|
||||
}
|
||||
@@ -99,20 +102,28 @@ module ribbon_clamp_fastened_assembly(ways, thickness, screw = screw) { //! Clam
|
||||
vitamin(str(": Tape self amalgamating silicone ",tape_l," x 25mm"));
|
||||
|
||||
washer = screw_washer(screw);
|
||||
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + screw_depth);
|
||||
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + ribbon_clamp_screw_depth(screw));
|
||||
|
||||
ribbon_clamp_assembly(ways);
|
||||
ribbon_clamp_assembly(ways, screw);
|
||||
|
||||
color("red") translate_z(tape_thickness / 2)
|
||||
cube([tape_l, tape_width, tape_thickness], center = true);
|
||||
|
||||
ribbon_clamp_hole_positions(ways)
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
vflip()
|
||||
translate_z(thickness)
|
||||
screw_and_washer(screw, screw_length, true);
|
||||
}
|
||||
|
||||
module ribbon_clamp_20_stl() ribbon_clamp(20);
|
||||
module ribbon_clamp_8_2_stl() ribbon_clamp(8, M2_dome_screw);
|
||||
module ribbon_clamp_7_2_stl() ribbon_clamp(8, M2_dome_screw);
|
||||
|
||||
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200°C.
|
||||
module ribbon_clamp_20_assembly() ribbon_clamp_assembly(20);
|
||||
|
||||
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200°C.
|
||||
module ribbon_clamp_8_2_assembly() ribbon_clamp_assembly(8, M2_dome_screw);
|
||||
|
||||
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200°C.
|
||||
module ribbon_clamp_7_2_assembly() ribbon_clamp_assembly(8, M2_dome_screw);
|
||||
|
@@ -135,7 +135,7 @@ module ssr_shroud_fastened_assembly(type, cable_d, thickness, name) //! Assembly
|
||||
|
||||
*translate_z(cable_d / 2)
|
||||
rotate([90, 0, 0])
|
||||
stl_colour(grey20)
|
||||
stl_colour(grey(20))
|
||||
cylinder(d = cable_d, h = 20, center = true);
|
||||
}
|
||||
}
|
||||
|
@@ -24,8 +24,7 @@
|
||||
include <../core.scad>
|
||||
use <../vitamins/insert.scad>
|
||||
|
||||
strap = [18, 2, M3_pan_screw, 3, 25];
|
||||
function strap() = strap;
|
||||
strap = strap();
|
||||
|
||||
wall = 2;
|
||||
clearance = 0.5;
|
||||
@@ -40,6 +39,10 @@ function strap_screw(type = strap) = type[2]; //! Screw type
|
||||
function strap_panel(type = strap) = type[3]; //! Panel thickness
|
||||
function strap_extension(type = strap) = type[4]; //! How much length of the strap that can pull out
|
||||
|
||||
|
||||
function strap(width = 18, thickness = 2, screw = M3_pan_screw, panel_thickness = 3, extension = 25) = //! Construct a property list for a strap
|
||||
[ width, thickness, screw, panel_thickness, extension ];
|
||||
|
||||
function strap_insert(type) = screw_insert(strap_screw(type)); //! The insert type
|
||||
function strap_key(type) = strap_panel(type) - panel_clearance;
|
||||
function strap_height(type) = wall + max(insert_length(strap_insert(type)) - strap_key(type), strap_thickness(type) + clearance); //! Height of the ends
|
||||
|
@@ -213,7 +213,7 @@ def parse_bom(file = "openscad.log", name = None):
|
||||
main.assemblies[stack[-1]].add_part(s)
|
||||
else:
|
||||
if 'ERROR:' in line or 'WARNING:' in line:
|
||||
print(line[:-1])
|
||||
raise Exception(line[:-1])
|
||||
return main
|
||||
|
||||
def usage():
|
||||
@@ -221,53 +221,57 @@ def usage():
|
||||
sys.exit(1)
|
||||
|
||||
def boms(target = None, assembly = None):
|
||||
bom_dir = set_config(target, usage) + "bom"
|
||||
if assembly:
|
||||
bom_dir += "/accessories"
|
||||
if not os.path.isdir(bom_dir):
|
||||
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)
|
||||
else:
|
||||
assembly = "main_assembly"
|
||||
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
|
||||
#
|
||||
scad_file = find_scad_file(assembly)
|
||||
if not scad_file:
|
||||
raise Exception("can't find source for " + assembly)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
bom_maker_name = source_dir + "/bom.scad"
|
||||
with open(bom_maker_name, "w") as f:
|
||||
f.write("use <%s>\n" % scad_file)
|
||||
f.write("%s();\n" % assembly);
|
||||
#
|
||||
# Run openscad
|
||||
#
|
||||
openscad.run("-D", "$bom=2", "-D", "$preview=true", "--hardwarnings", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
|
||||
os.remove(bom_maker_name)
|
||||
print("Generating bom ...", end=" ")
|
||||
#
|
||||
# Find the scad file that makes the module
|
||||
#
|
||||
scad_file = find_scad_file(assembly)
|
||||
if not scad_file:
|
||||
raise Exception("can't find source for " + assembly)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
bom_maker_name = source_dir + "/bom.scad"
|
||||
with open(bom_maker_name, "w") as f:
|
||||
f.write("use <%s>\n" % scad_file)
|
||||
f.write("%s();\n" % assembly);
|
||||
#
|
||||
# Run openscad
|
||||
#
|
||||
openscad.run("-D", "$bom=2", "-D", "$preview=true", "--hardwarnings", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
|
||||
os.remove(bom_maker_name)
|
||||
print("Generating bom ...", end=" ")
|
||||
|
||||
main = parse_bom("openscad.echo", assembly)
|
||||
main = parse_bom("openscad.echo", assembly)
|
||||
|
||||
if assembly == "main_assembly":
|
||||
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
|
||||
if assembly == "main_assembly":
|
||||
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
|
||||
|
||||
for ass in main.assemblies:
|
||||
with open(bom_dir + "/" + ass + ".txt", "wt") as f:
|
||||
bom = main.assemblies[ass]
|
||||
print(bom.make_name(ass) + ":", file=f)
|
||||
bom.print_bom(False, f)
|
||||
for ass in main.assemblies:
|
||||
with open(bom_dir + "/" + ass + ".txt", "wt") as f:
|
||||
bom = main.assemblies[ass]
|
||||
print(bom.make_name(ass) + ":", file=f)
|
||||
bom.print_bom(False, f)
|
||||
|
||||
data = [main.assemblies[ass].flat_data() for ass in main.ordered_assemblies]
|
||||
with open(bom_dir + "/bom.json", 'w') as outfile:
|
||||
json.dump(data, outfile, indent = 4)
|
||||
data = [main.assemblies[ass].flat_data() for ass in main.ordered_assemblies]
|
||||
with open(bom_dir + "/bom.json", 'w') as outfile:
|
||||
json.dump(data, outfile, indent = 4)
|
||||
|
||||
print("done")
|
||||
print("done")
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 3: usage()
|
||||
@@ -286,8 +290,4 @@ if __name__ == '__main__':
|
||||
if assembly:
|
||||
if assembly[-9:] != "_assembly": usage()
|
||||
|
||||
try:
|
||||
boms(target, assembly)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
sys.exit(1)
|
||||
boms(target, assembly)
|
||||
|
@@ -27,6 +27,7 @@ import c14n_stl
|
||||
from set_config import *
|
||||
from deps import *
|
||||
from shutil import copyfile
|
||||
import re
|
||||
|
||||
source_dirs = { "stl" : "platters", "dxf" : "panels" }
|
||||
target_dirs = { "stl" : "printed", "dxf" : "routed" }
|
||||
@@ -38,61 +39,73 @@ def plateup(target, part_type, usage = None):
|
||||
top_dir = set_config(target, usage)
|
||||
parts_dir = top_dir + part_type + 's'
|
||||
target_dir = parts_dir + '/' + target_dirs[part_type]
|
||||
source_dir = top_dir + source_dirs[part_type]
|
||||
deps_dir = source_dir + "/deps"
|
||||
if not os.path.isdir(source_dir):
|
||||
return
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
source_dir1 = source_dirs[part_type]
|
||||
source_dir2 = top_dir + source_dirs[part_type]
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
sources = [file for file in os.listdir(source_dir) if file.endswith('.scad')]
|
||||
#
|
||||
# Run OpenSCAD on the source files to make the targets
|
||||
# Loop through source directories
|
||||
#
|
||||
used = []
|
||||
for src in sources:
|
||||
src_file = source_dir + '/' + src
|
||||
part_file = target_dir + '/' + src[:-4] + part_type
|
||||
dname = deps_name(deps_dir, src)
|
||||
changed = check_deps(part_file, dname)
|
||||
if changed:
|
||||
print(changed)
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, src_file)
|
||||
if part_type == 'stl':
|
||||
c14n_stl.canonicalise(part_file)
|
||||
log_name = 'openscad.log'
|
||||
else:
|
||||
log_name = 'openscad.echo'
|
||||
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
|
||||
all_sources = []
|
||||
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)
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
# Make the deps dir
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
if line.startswith('ECHO: "~') and line.endswith('.' + part_type + '"\n'):
|
||||
used.append(line[8:-2])
|
||||
#
|
||||
# Copy file that are not included
|
||||
#
|
||||
deps_dir = dir + "/deps"
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
sources = [file for file in os.listdir(dir) if file.endswith('.scad')]
|
||||
all_sources += sources
|
||||
#
|
||||
# Run OpenSCAD on the source files to make the targets
|
||||
#
|
||||
for src in sources:
|
||||
src_file = dir + '/' + src
|
||||
part_file = target_dir + '/' + src[:-4] + part_type
|
||||
dname = deps_name(deps_dir, src)
|
||||
changed = check_deps(part_file, dname)
|
||||
if changed:
|
||||
print(changed)
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, src_file)
|
||||
if part_type == 'stl':
|
||||
c14n_stl.canonicalise(part_file)
|
||||
log_name = 'openscad.log'
|
||||
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))
|
||||
copied = []
|
||||
for file in os.listdir(parts_dir):
|
||||
if file.endswith('.' + part_type) and not file in used:
|
||||
src = parts_dir + '/' + file
|
||||
dst = target_dir + '/' + file
|
||||
if mtime(src) > mtime(dst):
|
||||
print("Copying %s to %s" % (src, dst))
|
||||
copyfile(src, dst)
|
||||
copied.append(file)
|
||||
#
|
||||
# Remove any cruft
|
||||
#
|
||||
targets = [file[:-4] + part_type for file in sources]
|
||||
for file in os.listdir(target_dir):
|
||||
if file.endswith('.' + part_type):
|
||||
if not file in targets and not file in copied:
|
||||
print("Removing %s" % file)
|
||||
os.remove(target_dir + '/' + file)
|
||||
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:
|
||||
src = parts_dir + '/' + file
|
||||
dst = target_dir + '/' + file
|
||||
if mtime(src) > mtime(dst):
|
||||
print("Copying %s to %s" % (src, dst))
|
||||
copyfile(src, dst)
|
||||
copied.append(file)
|
||||
#
|
||||
# Remove any cruft
|
||||
#
|
||||
targets = [file[:-4] + part_type for file in all_sources]
|
||||
for file in os.listdir(target_dir):
|
||||
if file.endswith('.' + part_type):
|
||||
if not file in targets and not file in copied:
|
||||
print("Removing %s" % file)
|
||||
os.remove(target_dir + '/' + file)
|
||||
|
@@ -30,7 +30,7 @@ def usage():
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 2: usage()
|
||||
if len(sys.argv) > 2: usage()
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
target = sys.argv[1]
|
||||
|
@@ -97,7 +97,6 @@ def tests(tests):
|
||||
for dir in [deps_dir, png_dir, bom_dir]:
|
||||
if not os.path.isdir(dir):
|
||||
os.makedirs(dir)
|
||||
doc_name = "readme.md"
|
||||
index = {}
|
||||
bodies = {}
|
||||
done = []
|
||||
@@ -108,19 +107,33 @@ def tests(tests):
|
||||
#
|
||||
png_name = "libtest.png"
|
||||
scad_name = "libtest.scad"
|
||||
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);
|
||||
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
|
||||
if os.path.isfile(scad_name):
|
||||
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);
|
||||
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
|
||||
else:
|
||||
#
|
||||
# Project tests so just a title
|
||||
#
|
||||
libtest = False
|
||||
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
|
||||
lib_blurb = '#' + project + ' Tests\n'
|
||||
|
||||
doc_base_name = "readme" if libtest else "tests"
|
||||
doc_name = doc_base_name + ".md"
|
||||
#
|
||||
# List of individual part files
|
||||
#
|
||||
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
|
||||
|
||||
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
|
||||
types = []
|
||||
for scad in scads:
|
||||
base_name = scad[:-5]
|
||||
if not tests or base_name in tests:
|
||||
done.append(base_name)
|
||||
print(base_name)
|
||||
print('\n'+base_name)
|
||||
cap_name = base_name[0].capitalize() + base_name[1:]
|
||||
base_name = base_name.lower()
|
||||
scad_name = scad_dir + '/' + scad
|
||||
@@ -132,29 +145,42 @@ def tests(tests):
|
||||
if is_plural(base_name) and os.path.isfile(vits_name):
|
||||
objects_name = vits_name
|
||||
|
||||
locations = [
|
||||
('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'),
|
||||
('printed/' + base_name + '.scad', 'Printed'),
|
||||
('utils/' + base_name + '.scad', 'Utilities'),
|
||||
('utils/core/' + base_name + '.scad', 'Core Utilities'),
|
||||
]
|
||||
locations = []
|
||||
if os.path.isdir('vitamins'):
|
||||
locations.append(('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'))
|
||||
if os.path.isdir('printed'):
|
||||
locations.append(('printed/' + base_name + '.scad', 'Printed'))
|
||||
if os.path.isdir('utils'):
|
||||
locations.append(('utils/' + base_name + '.scad', 'Utilities'))
|
||||
if libtest and os.path.isdir('utils/core'):
|
||||
locations.append(('utils/core/' + base_name + '.scad', 'Core Utilities'))
|
||||
|
||||
for name, type in locations:
|
||||
if os.path.isfile(name):
|
||||
impl_name = name
|
||||
break
|
||||
else:
|
||||
print("Can't find implementation!")
|
||||
continue
|
||||
if libtest:
|
||||
print("Can't find implementation!")
|
||||
continue
|
||||
else:
|
||||
type = 'Tests' # OK when testing part of a project
|
||||
impl_name = None
|
||||
|
||||
vsplit = "AJR" + 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:
|
||||
for i in range(1, len(vsplit)):
|
||||
if cap_name[0] < vsplit[i]:
|
||||
type = types[i - 1]
|
||||
break
|
||||
if libtest:
|
||||
vsplit = "AJR" + 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:
|
||||
for i in range(1, len(vsplit)):
|
||||
if cap_name[0] < vsplit[i]:
|
||||
type = types[i - 1]
|
||||
break
|
||||
else:
|
||||
if not types:
|
||||
types = [loc[1] for loc in locations] # No need to split up the vitamin list
|
||||
if not type in types: # Will happen when implementation is not found and type is set to Tests
|
||||
types.append(type)
|
||||
|
||||
for t in types:
|
||||
if not t in bodies:
|
||||
@@ -250,24 +276,7 @@ def tests(tests):
|
||||
usage()
|
||||
|
||||
with open(doc_name, "wt") as doc_file:
|
||||
print('# NopSCADlib', file = doc_file)
|
||||
print('''\
|
||||
An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
|
||||
|
||||
It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and
|
||||
some utilities. There are also Python scripts to generate Bills of Materials (BOMs),
|
||||
STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
|
||||
instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md). A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
|
||||
|
||||
For more examples of what it can make see the [gallery](gallery/readme.md).
|
||||
|
||||
The license is GNU General Public License v3.0, see [COPYING](COPYING).
|
||||
|
||||
See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
|
||||
<img src="libtest.png" width="100%"/>\n
|
||||
''', file = doc_file)
|
||||
|
||||
print(lib_blurb, file = doc_file)
|
||||
print('## Table of Contents<a name="top"/>', file = doc_file)
|
||||
print('<table><tr>', file = doc_file)
|
||||
n = 0
|
||||
@@ -288,10 +297,10 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
|
||||
for type in types:
|
||||
for line in bodies[type]:
|
||||
print(line, file = doc_file)
|
||||
with open("readme.html", "wt") as html_file:
|
||||
do_cmd("python -m markdown -x tables readme.md".split(), html_file)
|
||||
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()
|
||||
do_cmd('codespell -L od readme.md'.split())
|
||||
do_cmd(('codespell -L od ' + doc_name).split())
|
||||
|
||||
if __name__ == '__main__':
|
||||
for arg in sys.argv[1:]:
|
||||
|
@@ -308,8 +308,7 @@ def views(target, do_assemblies = None):
|
||||
if printed:
|
||||
print('### 3D Printed parts', file = doc_file)
|
||||
keys = sorted(list(printed.keys()))
|
||||
for i in range(len(keys)):
|
||||
p = keys[i]
|
||||
for i, p in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(printed) - 1:
|
||||
n = (i % 3) + 1
|
||||
@@ -324,8 +323,7 @@ def views(target, do_assemblies = None):
|
||||
if routed:
|
||||
print("### CNC Routed parts", file = doc_file)
|
||||
keys = sorted(list(routed.keys()))
|
||||
for i in range(len(keys)):
|
||||
r = keys[i]
|
||||
for i, r in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(routed) - 1:
|
||||
n = (i % 3) + 1
|
||||
@@ -340,8 +338,7 @@ def views(target, do_assemblies = None):
|
||||
if sub_assemblies:
|
||||
print("### Sub-assemblies", file = doc_file)
|
||||
keys = sorted(list(sub_assemblies.keys()))
|
||||
for i in range(len(keys)):
|
||||
a = keys[i]
|
||||
for i, a in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(keys) - 1:
|
||||
n = (i % 3) + 1
|
||||
|
37
tests/LED_meters.scad
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2018
|
||||
// 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>
|
||||
include <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/led_meters.scad>
|
||||
|
||||
module led_meters()
|
||||
layout([for(m = led_meters) meter_bezel_length(m)], 5) let(m = led_meters[$i])
|
||||
if($preview) {
|
||||
hflip()
|
||||
meter(m, colour = "blue", value = "123");
|
||||
|
||||
if(!$i)
|
||||
translate([0, meter_bezel_width(m)])
|
||||
meter_assembly(m, value = "123");
|
||||
}
|
||||
else
|
||||
meter_bezel(m);
|
||||
|
||||
led_meters();
|
@@ -21,6 +21,7 @@ include <../vitamins/microswitches.scad>
|
||||
include <../vitamins/d_connectors.scad>
|
||||
include <../vitamins/leds.scad>
|
||||
include <../vitamins/axials.scad>
|
||||
include <../vitamins/smds.scad>
|
||||
|
||||
use <../vitamins/pcb.scad>
|
||||
|
||||
@@ -33,7 +34,7 @@ TMC2130 = ["TMC2130", "TMC2130",
|
||||
[
|
||||
[ 10, 1, 0, "-2p54header", 8, 1 ,undef, "blue" ],
|
||||
[ 10, 13, 0, "-2p54header", 8, 1],
|
||||
[ 12, 7, 0, "-chip", 6, 4, 1, grey20 ],
|
||||
[ 12, 7, 0, "-chip", 6, 4, 1, grey(20) ],
|
||||
// mock up a heat sink
|
||||
[ 10, 7, 0, "block", 9, 9, 2, TMC2130HeatSinkColor ],
|
||||
[ 10, 11, 0, "block", 9, 1, 11, TMC2130HeatSinkColor ],
|
||||
@@ -57,45 +58,54 @@ test_pcb = ["TestPCB", "Test PCB",
|
||||
// components
|
||||
[
|
||||
[ 20, -5, 180, "trimpot10"],
|
||||
[ 20, -15, 0, "trimpot10", true],
|
||||
|
||||
[ 20, -15, 90, "trimpot10", true],
|
||||
[ 10, 2, 90, "smd_led", LED0805, "red"],
|
||||
[ 13, 2, 90, "smd_led", LED0603, "orange"],
|
||||
[ 16, 2, 90, "smd_res", RES1206, "1K"],
|
||||
[ 19, 2, 90, "smd_res", RES0805, "1K"],
|
||||
[ 22, 2, 90, "smd_res", RES0603, "1K"],
|
||||
[ 10, 10, 0, "2p54header", 4, 1],
|
||||
[ 25, 10, 0, "2p54header", 5, 1, undef, "blue" ],
|
||||
[ 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, undef, undef, undef, "red" ],
|
||||
[ 10, 40, 0, "chip", 10, 5, 1, grey20],
|
||||
[ 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"],
|
||||
[ 8, 105, 180, "usb_Ax2"],
|
||||
[ 3, 125, 180, "usb_uA"],
|
||||
[ 8, 140, 180, "usb_B"],
|
||||
[ 5, 160, 0, "buzzer", 4.5, 8.5],
|
||||
[ 20, 160, 0, "buzzer"],
|
||||
[ 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"],
|
||||
[ 6, 200, 180, "barrel_jack"],
|
||||
[ 5, 218, 180, "hdmi"],
|
||||
[ 3, 235, 180, "mini_hdmi"],
|
||||
[ 6, 175, 180, "uSD", [12, 11.5, 1.4]],
|
||||
|
||||
[ 65, 9, 0, "link", inch(0.4)],
|
||||
[ 65, 12, 0, "ax_res", res1_8, 1000],
|
||||
[ 65, 17, 0, "ax_res", res1_4, 10000],
|
||||
[ 65, 22, 0, "ax_res", res1_2, 100000],
|
||||
|
||||
[ 80, 9, 0, "link", inch(0.2), inch(0.4)],
|
||||
[ 80, 12, 0, "ax_res", res1_8, 1000000, 1, inch(0.1)],
|
||||
[ 80, 17, 0, "ax_res", res1_4, 100, 2, inch(0.1)],
|
||||
[ 80, 22, 0, "ax_res", res1_2, 10, 10, inch(0.2)],
|
||||
|
||||
[ 60, 3, 0, "flex"],
|
||||
[ 50, 15, 0, "flat_flex"],
|
||||
[ 50, 15, -90, "flat_flex"],
|
||||
[ 40, 15, -90, "flat_flex", true],
|
||||
[ 60, 35, 0, "D_plug", DCONN9],
|
||||
|
||||
[ 50, 50, 0, "molex_hdr", 2],
|
||||
[ 50, 60, 0, "jst_xh", 2],
|
||||
[ 50, 70, 180, "term254", 3],
|
||||
[ 63, 70, 180, "term254", 3, undef, grey20],
|
||||
[ 63, 70, 180, "term254", 3, undef, grey(20)],
|
||||
[ 75, 70, 180, "gterm508",2, undef, "blue"],
|
||||
|
||||
[ 50, 90, 180, "gterm35", 4, [1,2]],
|
||||
@@ -105,19 +115,20 @@ test_pcb = ["TestPCB", "Test PCB",
|
||||
|
||||
[ 55, 110, 180, "gterm635", 2],
|
||||
[ 75, 110, 180, "gterm635", 2, undef, "blue"],
|
||||
[ 90, 110, 180, "gterm", gt_5x17, 2, undef, grey20],
|
||||
[ 90, 110, 180, "gterm", gt_5x17, 2, undef, grey(20)],
|
||||
|
||||
[ 50, 130, 180, "term35", 4],
|
||||
[ 70, 130, 180, "term35", 3, "lime"],
|
||||
[ 50, 150, 0, "transition", 5],
|
||||
[ 50, 160, 0, "block", 10, 5, 8, "orange"],
|
||||
[ 50, 170, 0, "button_6mm"],
|
||||
[ 45, 170, 0, "button_6mm"],
|
||||
[ 55, 170, 0, "button_4p5mm"],
|
||||
[ 50, 185, 0, "microswitch", small_microswitch],
|
||||
[ 52, 200, 0, "pcb", 11, TMC2130 ],
|
||||
[ 80, 200, 0, "pdip", 24, "27C32", true, inch(0.6) ],
|
||||
[ 80, 170, 0, "pdip", 8, "NE555" ],
|
||||
[ 52, 206, 0, "2p54socket", 8, 1 ],
|
||||
[ 52, 194, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 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],
|
||||
|
34
tests/SMDs.scad
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// 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 <../utils/core/core.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/smds.scad>
|
||||
|
||||
module smds() {
|
||||
layout([for(r = smd_resistors) smd_res_size(r).x], 1)
|
||||
smd_resistor(smd_resistors[$i], ["1R0", "10M", "100K"][$i % 3]);
|
||||
|
||||
translate([0, 3])
|
||||
layout([for(l = smd_leds) smd_led_size(l).x], 1)
|
||||
smd_led(smd_leds[$i], ["green", "blue", "red"][$i % 3]);
|
||||
}
|
||||
|
||||
if($preview)
|
||||
smds();
|
@@ -23,49 +23,55 @@ use <../vitamins/insert.scad>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
module belt_test() {
|
||||
p1 = [75, -50];
|
||||
p2 = [-75, -50];
|
||||
p3 = [-75, 100];
|
||||
p4 = [75, 100];
|
||||
|
||||
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)];
|
||||
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)];
|
||||
|
||||
translate(p1) pulley_assembly(GT2x20ob_pulley);
|
||||
translate(p2) pulley_assembly(GT2x20ob_pulley);
|
||||
translate(p3) pulley_assembly(GT2x20_toothed_idler);
|
||||
translate(p4) pulley_assembly(GT2x20_toothed_idler);
|
||||
module pulleys(flip = false) {
|
||||
translate(p2) rotate([0, flip ? 180 : 0, 0]) pulley_assembly(GT2x20ob_pulley);
|
||||
translate(p3) pulley_assembly(GT2x20_toothed_idler);
|
||||
translate(p4) pulley_assembly(GT2x20_toothed_idler);
|
||||
translate(p5) {
|
||||
pulley = GT2x16_toothed_idler;
|
||||
screw = find_screw(hs_cs_cap, pulley_bore(pulley));
|
||||
insert = screw_insert(screw);
|
||||
|
||||
translate(p5) {
|
||||
pulley = GT2x16_plain_idler;
|
||||
screw = find_screw(hs_cs_cap, pulley_bore(pulley));
|
||||
insert = screw_insert(screw);
|
||||
|
||||
pulley_assembly(pulley);
|
||||
translate_z(pulley_height(pulley) + pulley_offset(pulley) + screw_head_depth(screw, pulley_bore(pulley)))
|
||||
screw(screw, 20);
|
||||
|
||||
translate_z(pulley_offset(pulley) - insert_length(insert))
|
||||
vflip()
|
||||
insert(insert);
|
||||
hflip(flip) {
|
||||
pulley_assembly(pulley);
|
||||
translate_z(pulley_height(pulley) + pulley_offset(pulley) + screw_head_depth(screw, pulley_bore(pulley)))
|
||||
screw(screw, 20);
|
||||
|
||||
translate_z(pulley_offset(pulley) - insert_length(insert))
|
||||
vflip()
|
||||
insert(insert);
|
||||
}
|
||||
}
|
||||
translate(p6) pulley_assembly(GT2x16_plain_idler);
|
||||
}
|
||||
translate(p6) pulley_assembly(GT2x16_plain_idler);
|
||||
|
||||
path = [ [p1.x, p1.y, pulley_pr(GT2x20ob_pulley)],
|
||||
[p5.x, p5.y, -pulley_pr(GT2x16_plain_idler)],
|
||||
path = [ [p5.x, p5.y, pulley_pr(GT2x16_plain_idler)],
|
||||
[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)]
|
||||
];
|
||||
belt = GT2x6;
|
||||
belt(belt, path, 80, [0, belt_pitch_height(belt) - belt_thickness(belt) / 2]);
|
||||
|
||||
translate([-25, 0])
|
||||
belt = GT2x6;
|
||||
belt(belt, path, 80, [0, 0]);
|
||||
pulleys();
|
||||
translate_z(20)
|
||||
hflip() {
|
||||
belt(belt, path, 80, [0, 0], belt_colour = grey(90), tooth_colour = grey(50));
|
||||
pulleys(flip=true);
|
||||
}
|
||||
|
||||
translate([-25, 0, 10])
|
||||
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 ? grey90 : grey20, tooth_colour = $i%2==0 ? grey70 : grey50);
|
||||
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));
|
||||
}
|
||||
|
||||
if($preview)
|
||||
|
@@ -23,7 +23,7 @@ use <../vitamins/insert.scad>
|
||||
|
||||
use <../printed/box.scad>
|
||||
|
||||
box = [M3_dome_screw, 3, DiBond, PMMA3, DiBond6, true, 150, 100, 70];
|
||||
box = box(screw = M3_dome_screw, wall = 3, sheets = DiBond, top_sheet = PMMA3, base_sheet = DiBond6, feet = true, size = [150, 100, 70]);
|
||||
|
||||
include <../printed/box_assembly.scad>
|
||||
|
||||
|
@@ -25,7 +25,7 @@ include <../printed/butt_box.scad>
|
||||
|
||||
$explode = 0;
|
||||
|
||||
box = [M3_dome_screw, DiBond, DiBond6, PMMA3, 250, 400, 300, 120];
|
||||
box = bbox(screw = M3_dome_screw, sheets = DiBond, base_sheet = DiBond6, top_sheet = PMMA3, span = 250, size = [400, 300, 120]);
|
||||
|
||||
module bbox_assembly() _bbox_assembly(box);
|
||||
|
||||
|
33
tests/camera_housing.scad
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// 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>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
use <../printed/camera_housing.scad>
|
||||
|
||||
include <../vitamins/cameras.scad>
|
||||
|
||||
use <../vitamins/pcb.scad>
|
||||
|
||||
module camera_housings()
|
||||
layout([for(c = cameras) pcb_length(camera_pcb(c))], 15, false) let(c = cameras[$i])
|
||||
camera_fastened_assembly(c, 3);
|
||||
|
||||
if($preview)
|
||||
camera_housings();
|
31
tests/cameras.scad
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// 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>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/cameras.scad>
|
||||
|
||||
use <../vitamins/pcb.scad>
|
||||
|
||||
module cameras()
|
||||
layout([for(c = cameras) pcb_length(camera_pcb(c))], 15, false) let(c = cameras[$i])
|
||||
camera(c);
|
||||
|
||||
if($preview)
|
||||
cameras();
|
56
tests/catenary.scad
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
l = 250; // [1: 1000]
|
||||
x = 200; // [1: 1000]
|
||||
y = 50; //[-500 : 500]
|
||||
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/catenary.scad>
|
||||
use <../utils/sweep.scad>
|
||||
use <../utils/annotation.scad>
|
||||
|
||||
module catenaries() {
|
||||
//
|
||||
// catenary curve path from control points
|
||||
//
|
||||
curve = [for(p = catenary_points(l, x, y)) [p.x, p.y, 0]];
|
||||
//
|
||||
// Draw the curve
|
||||
//
|
||||
r = 0.5;
|
||||
sweep(curve, circle_points(r, $fn = 64));
|
||||
//
|
||||
// Minimum Z
|
||||
//
|
||||
min_z = catenary_points(l, x, y, 0);
|
||||
|
||||
color("blue") {
|
||||
translate([min_z.x, min_z.y + r])
|
||||
rotate([-90, 0, 0])
|
||||
arrow();
|
||||
|
||||
translate([min_z.x, min_z.y - r])
|
||||
rotate([90, 0, 0])
|
||||
arrow();
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
rotate(is_undef($bom) ? 0 : [70, 0, 315])
|
||||
catenaries();
|
@@ -41,9 +41,12 @@ module components() {
|
||||
translate([0, 50])
|
||||
TO220("Generic TO220 package");
|
||||
|
||||
translate([50, 50])
|
||||
translate([40, 50])
|
||||
panel_USBA();
|
||||
|
||||
translate([80, 50])
|
||||
fack2spm();
|
||||
|
||||
translate([0,80])
|
||||
thermal_cutouts();
|
||||
|
||||
|
59
tests/drag_chain.scad
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
// Link length between hinges
|
||||
x = 10; //[8 : 30]
|
||||
|
||||
// Link inner width
|
||||
y = 10; //[5 : 30]
|
||||
|
||||
// Link inner height
|
||||
z = 5; //[4 : 11]
|
||||
// Side wall thickness
|
||||
wall = 1.6; //[0.9: 0.1: 3]
|
||||
// Bottom wall thickness
|
||||
bwall = 1.5; //[1: 0.25: 3]
|
||||
// Top wall thickness
|
||||
twall = 1.5; //[1: 0.25: 3]
|
||||
// Max travel in each direction
|
||||
travel = 100;
|
||||
// Current position
|
||||
pos = 50; // [-100 : 1 : 100]
|
||||
|
||||
include <../core.scad>
|
||||
use <../printed/drag_chain.scad>
|
||||
|
||||
include <../vitamins/leadnuts.scad>
|
||||
|
||||
drag_chain = drag_chain("x", [x, y, z], travel, wall = wall, bwall = bwall, twall = twall);
|
||||
|
||||
module drag_chains()
|
||||
drag_chain_assembly(drag_chain, pos);
|
||||
|
||||
if($preview)
|
||||
drag_chains();
|
||||
else {
|
||||
drag_chain_link(drag_chain);
|
||||
|
||||
translate([-x * 2, 0])
|
||||
drag_chain_link(drag_chain, start = true);
|
||||
|
||||
translate([x * 2, 0])
|
||||
drag_chain_link(drag_chain, end = true);
|
||||
}
|
@@ -32,8 +32,8 @@ clearance = 0.2;
|
||||
|
||||
angle = 0; // [-90 : 180]
|
||||
|
||||
big_hinge = ["big", width, depth, thickness, pin_diameter, knuckle_diameter, knuckles, M3_dome_screw, screws, clearance, margin];
|
||||
small_hinge = ["small", 20, 16, 2, 2.85, 7, 3, M3_dome_screw, 2, 0.2, 0];
|
||||
big_hinge = flat_hinge(name = "big", size = [width, depth, thickness], pin_d = pin_diameter, knuckle_d = knuckle_diameter, knuckles = knuckles, screw = M3_dome_screw, screws = screws, clearance = clearance, margin = margin);
|
||||
small_hinge = flat_hinge(name = "small", size =[ 20, 16, 2], pin_d = 2.85, knuckle_d = 7, knuckles = 3, screw = M3_dome_screw, screws = 2, clearance = 0.2, margin = 0);
|
||||
|
||||
hinges = [small_hinge, big_hinge];
|
||||
|
||||
|
@@ -21,14 +21,14 @@ use <../printed/foot.scad>
|
||||
|
||||
module feet()
|
||||
if($preview) {
|
||||
translate([50, 0])
|
||||
translate([40, 0])
|
||||
foot_assembly(3);
|
||||
|
||||
translate([foot_diameter(insert_foot()) / 2, 0])
|
||||
fastened_insert_foot_assembly(3);
|
||||
}
|
||||
else {
|
||||
translate([50, 0])
|
||||
translate([40, 0])
|
||||
foot();
|
||||
|
||||
insert_foot();
|
||||
|
66
tests/gears.scad
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// 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 <../utils/core/core.scad>
|
||||
use <../utils/gears.scad>
|
||||
|
||||
// left gear teeth
|
||||
z1 = 39; // [7 : 1 : 99]
|
||||
|
||||
// Right gear teeth
|
||||
z2 = 7; // [7 : 1 : 99]
|
||||
|
||||
// Modulus
|
||||
m = 2.0; // [0.1 : 0.1 : 5.0]
|
||||
|
||||
// Pressure angle
|
||||
pa = 20; // [14.5, 20, 22.5, 25]
|
||||
|
||||
$show_numbers = false;
|
||||
|
||||
module gears() {
|
||||
color(pp1_colour)
|
||||
rotate(-$t * 360)
|
||||
linear_extrude(eps, center = true, convexity = z1)
|
||||
difference() {
|
||||
involute_gear_profile(m, z1, pa);
|
||||
|
||||
circle(r = m * z1 / 10);
|
||||
}
|
||||
|
||||
color(pp2_colour)
|
||||
translate([centre_distance(m, z1, z2, pa), 0])
|
||||
rotate(180 + 180 / z2 + $t * 360 * z1 / z2)
|
||||
linear_extrude(eps, center = true, convexity = z2)
|
||||
difference() {
|
||||
involute_gear_profile(m, z2, pa);
|
||||
|
||||
circle(r = m * z2 / 10);
|
||||
}
|
||||
|
||||
z3 = floor((z1 + z2) / PI);
|
||||
angle = -$t * 360 + 90 - floor(z1 / 4) * 360 / z1; // Line up the rack 1/4 turn around the gear
|
||||
pitch = m * PI;
|
||||
color(pp3_colour)
|
||||
translate([(angle % ((z3 / z1) * 360)) / 360 * z1 * pitch, -centre_distance(m, z1, 0, pa)])
|
||||
linear_extrude(eps, center = true)
|
||||
involute_rack_profile(m, z3, 3 * m, pa);
|
||||
}
|
||||
|
||||
rotate(is_undef($bom) ? 0 : [70, 0, 315])
|
||||
gears();
|
@@ -29,6 +29,23 @@ module globals() {
|
||||
translate([50, 0])
|
||||
right_triangle(10, 20, 0);
|
||||
}
|
||||
assert(slice("ABCD") == "ABCD");
|
||||
assert(slice("ABCD", 1) == "BCD");
|
||||
assert(slice("ABCD", 2) == "CD");
|
||||
assert(slice("ABCD", 3) == "D");
|
||||
assert(slice("ABCD", 4) == "");
|
||||
assert(slice("ABCD", 1, -1) == "BC");
|
||||
assert(slice("ABCD", 2, -1) == "C");
|
||||
assert(slice("ABCD", 3, -1) == "");
|
||||
assert(slice("ABCD", 4, -1) == "");
|
||||
assert(slice("ABCD", 0, -1) == "ABC");
|
||||
assert(slice("ABCD", 0, -2) == "AB");
|
||||
assert(slice("ABCD", 0, -3) == "A");
|
||||
assert(slice("ABCD", 0, -4) == "");
|
||||
assert(slice("ABCD", 0, 0) == "");
|
||||
assert(slice("ABCD", 0, 1) == "A");
|
||||
assert(slice("ABCD", 0, 2) == "AB");
|
||||
assert(slice("ABCD", 0, 3) == "ABC");
|
||||
}
|
||||
|
||||
rotate([70, 0, 315]) globals();
|
||||
|
94
tests/horiholes.scad
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// 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/>.
|
||||
//
|
||||
$layer_height = 0.25;
|
||||
include <../utils/core/core.scad>
|
||||
use <../utils/horiholes.scad>
|
||||
|
||||
show_disc = true;
|
||||
use_horihole = true;
|
||||
thickness = 6;
|
||||
length = 60;
|
||||
height = 20;
|
||||
overlap_x = 15;
|
||||
overlap_y = 10;
|
||||
|
||||
module hole_positions() {
|
||||
x0 = (length - 40) / 2;
|
||||
for($i = [0 : 4], $z = 5 + $i * layer_height / 5, $r = 3)
|
||||
translate([x0 + $i * 10, $z])
|
||||
children();
|
||||
|
||||
for($i = [0 : 4], $z = 15 + $i * layer_height / 5, $r = 0.5 + $i / 2)
|
||||
translate([x0 + $i * 10, $z])
|
||||
children();
|
||||
}
|
||||
|
||||
module horiholes_stl(t = thickness) {
|
||||
rotate([90, 0, 0])
|
||||
difference() {
|
||||
linear_extrude(t, center = true) {
|
||||
difference() {
|
||||
square([length, height]);
|
||||
|
||||
hole_positions()
|
||||
if(use_horihole)
|
||||
horihole($r, $z);
|
||||
else
|
||||
teardrop_plus(h = 0, r = $r);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(t == thickness)
|
||||
translate([length / 2, 0])
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5);
|
||||
}
|
||||
|
||||
module horiholes() {
|
||||
stl_colour(pp1_colour)
|
||||
rotate([-90, 0, 0])
|
||||
horiholes_stl(eps);
|
||||
|
||||
if(show_disc)
|
||||
hole_positions()
|
||||
color(silver)
|
||||
cylinder(r = $r, h = eps, center = true, $fn = 360);
|
||||
|
||||
hole_positions()
|
||||
color("blue")
|
||||
horicylinder(r = $r, z = $z, h = 2 * eps, center = true, $fn = 360);
|
||||
|
||||
hole_positions()
|
||||
color("red")
|
||||
linear_extrude(3 * eps, center = true)
|
||||
intersection() {
|
||||
difference() {
|
||||
square(8, center = true);
|
||||
|
||||
horihole($r, $z);
|
||||
}
|
||||
|
||||
circle($r, $fn = 360);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
rotate(is_undef($bom) ? 0 : [70, 0, 315])
|
||||
horiholes();
|
||||
else
|
||||
horiholes_stl();
|
@@ -25,7 +25,7 @@ module hot_ends()
|
||||
layout([for(h = hot_ends) 40])
|
||||
translate([-20, 0])
|
||||
rotate(90)
|
||||
hot_end(hot_ends[$i], 3);
|
||||
hot_end(hot_ends[$i], 3, bowden = $i == 3);
|
||||
|
||||
if($preview)
|
||||
hot_ends();
|
||||
|
29
tests/magnets.scad
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// 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>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/magnets.scad>
|
||||
|
||||
module magnets()
|
||||
layout([for(m = magnets) magnet_od(m)], 5)
|
||||
magnet(magnets[$i]);
|
||||
|
||||
if($preview)
|
||||
magnets();
|
@@ -69,6 +69,33 @@ module maths() {
|
||||
// Test Euler
|
||||
//
|
||||
assert(euler(rotate(r)) == r, "euler() failed");
|
||||
//
|
||||
// Circle intersect
|
||||
//
|
||||
r1 = 10;
|
||||
c1 = [50, 0, 10];
|
||||
r2 = 20;
|
||||
c2 = [67, 0, 0];
|
||||
p1 = circle_intersect(c1, r1, c2, r2);
|
||||
p2 = circle_intersect(c2, r2, c1, r1);
|
||||
|
||||
rotate(90) {
|
||||
color(grey(90))
|
||||
translate(c1) rotate([90, 0, 0]) cylinder(r = r1, h = 4 * eps, center = true);
|
||||
|
||||
color(grey(80))
|
||||
translate(c2) rotate([90, 0, 0]) cylinder(r = r2, h = eps, center = true);
|
||||
|
||||
color("red")
|
||||
translate(p1) rotate([90, 0, 0]) cylinder(r = 0.1, h = 6 * eps, center = true);
|
||||
|
||||
color("blue")
|
||||
translate(p2) rotate([90, 0, 0]) cylinder(r = 0.1, h = 6 * eps, center = true);
|
||||
|
||||
translate(p1) arrow();
|
||||
|
||||
translate(p2) vflip() arrow();
|
||||
}
|
||||
}
|
||||
|
||||
rotate(45)
|
||||
|
@@ -21,11 +21,11 @@ include <../utils/core/core.scad>
|
||||
use <../vitamins/opengrab.scad>
|
||||
|
||||
module opengrab_test() {
|
||||
opengrab_target();
|
||||
|
||||
rotate(45)
|
||||
translate_z(opengrab_target_thickness())
|
||||
opengrab();
|
||||
opengrab_target();
|
||||
|
||||
translate_z(opengrab_target_thickness())
|
||||
opengrab();
|
||||
}
|
||||
|
||||
if($preview)
|
||||
|
29
tests/panel_meters.scad
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// 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>
|
||||
use <../utils/layout.scad>
|
||||
|
||||
include <../vitamins/panel_meters.scad>
|
||||
|
||||
module panel_meters()
|
||||
layout([for(p = panel_meters) pmeter_bezel(p).x], 10)
|
||||
panel_meter(panel_meters[$i]);
|
||||
|
||||
if($preview)
|
||||
panel_meters();
|
@@ -23,26 +23,56 @@ include <../vitamins/pin_headers.scad>
|
||||
|
||||
pins = 10;
|
||||
|
||||
module pin_headers()
|
||||
module pin_headers() {
|
||||
layout([for(p = pin_headers) hdr_pitch(p) * pins], 15) {
|
||||
idc_transition(pin_headers[$i], 10);
|
||||
|
||||
translate([0, 20])
|
||||
pin_header(pin_headers[$i], 10, 2, right_angle = true);
|
||||
pin_header(pin_headers[$i], 3, 2, right_angle = true);
|
||||
|
||||
translate([-10, 20])
|
||||
pin_header(pin_headers[$i], 3, 1, right_angle = true);
|
||||
|
||||
translate([10, 20])
|
||||
pin_header(pin_headers[$i], 3, 3, right_angle = true);
|
||||
|
||||
translate([0, 30])
|
||||
pin_header(pin_headers[$i], 8, 1);
|
||||
|
||||
translate([0, 40])
|
||||
pin_header(pin_headers[$i], 10, 2);
|
||||
|
||||
translate([0, 50])
|
||||
box_header(pin_headers[$i], 8, 1);
|
||||
|
||||
translate([0, 60])
|
||||
box_header(pin_headers[$i], 10, 2);
|
||||
|
||||
translate([0, 70])
|
||||
pin_socket(pin_headers[$i], 8, 1);
|
||||
|
||||
translate([0, 80])
|
||||
pin_socket(pin_headers[$i], 10, 2);
|
||||
|
||||
translate([0, 110])
|
||||
pin_socket(pin_headers[$i], 10, 2, right_angle = true);
|
||||
translate([-10, 105])
|
||||
pin_socket(pin_headers[$i], 3, 1, right_angle = true);
|
||||
|
||||
translate([0, 105])
|
||||
pin_socket(pin_headers[$i], 3, 2, right_angle = true);
|
||||
|
||||
translate([10, 105])
|
||||
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];
|
||||
translate([-20 * (i + 1), 0 + j * 40])
|
||||
jst_xh_header(h, p);
|
||||
|
||||
translate([-20 * (i + 1), 20 + j * 40])
|
||||
jst_xh_header(h, p, true);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
pin_headers();
|
||||
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 251 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 68 KiB |
BIN
tests/png/camera_housing.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
tests/png/cameras.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
tests/png/catenary.png
Normal file
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 76 KiB |
BIN
tests/png/drag_chain.png
Normal file
After Width: | Height: | Size: 154 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 102 KiB |
BIN
tests/png/gears.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
tests/png/horiholes.png
Normal file
After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
BIN
tests/png/led_meters.png
Normal file
After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
BIN
tests/png/magnets.png
Normal file
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 97 KiB |
BIN
tests/png/panel_meters.png
Normal file
After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 136 KiB |
BIN
tests/png/press_fit.png
Normal file
After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 90 KiB |