1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-09-03 20:32:35 +02:00

Compare commits

...

152 Commits

Author SHA1 Message Date
Chris Palmer
20d799a3c1 IEC_320_C14_switched_fused_inlet now shows the correct object name in the example. 2021-06-01 08:18:57 +01:00
Chris Palmer
2ee95bba65 Updated changelog. 2021-05-31 17:24:31 +01:00
Chris Palmer
f49bb63266 Merge branch 'martinbudden-bldc_motors' 2021-05-31 17:22:43 +01:00
Chris Palmer
258109811b Added uppercase version of BLCD_motors.scad. 2021-05-31 17:21:49 +01:00
Chris Palmer
b39fd536c2 Removed lower case version of bldc_motors.scad. 2021-05-31 17:21:03 +01:00
Chris Palmer
a5a87d260d Updated images and readme. 2021-05-31 17:19:56 +01:00
Chris Palmer
b09efb10e0 Merge branch 'bldc_motors' of https://github.com/martinbudden/NopSCADlib into martinbudden-bldc_motors 2021-05-31 16:25:23 +01:00
Chris Palmer
53acaac379 Updated changelog 2021-05-31 16:22:52 +01:00
Chris Palmer
9b40e0dcef Merge branch 'martinbudden-thread_colour_assert' 2021-05-31 16:20:29 +01:00
Martin Budden
00ca412441 Added BLDC3548 motor. 2021-05-30 18:58:55 +01:00
Martin Budden
1e6d7f5dd6 Brushless DC motors. 2021-05-30 18:55:32 +01:00
Martin Budden
ec07d95657 Added assertion to check colour format in module thread. 2021-05-30 16:00:13 +01:00
Chris Palmer
0dab0dca08 Added missing includes core.scad which generates warnings with latest OpenSCAD snapshots.
Note, however, NopSCADlib does not work with the current OpenSCAD snapshot.
2021-05-19 17:54:31 +01:00
Chris Palmer
6e6cd45295 Updated changelog 2021-05-18 23:21:40 +01:00
Chris Palmer
3a7fde6c56 Merge branch 'master' of https://github.com/nophead/NopSCADlib.git 2021-05-18 23:18:18 +01:00
Chris Palmer
c5bb898856 Updated changelog. 2021-05-18 23:16:15 +01:00
Chris Palmer
11ebe2225d Removed spurious convexity in difference from rounded_polygon(). 2021-05-18 23:14:34 +01:00
Chris
a1e25bb878 Merge pull request #180 from martinbudden/global_defs_typo
Typo in global_defs.
2021-05-15 14:36:58 +01:00
Martin Budden
9689683b7e Typo in global_defs. 2021-05-15 11:42:24 +01:00
Chris Palmer
08946e3d70 Updated changelog. 2021-05-02 17:16:21 +01:00
Chris Palmer
15c2946e91 Merge branch 'martinbudden-blower_size' 2021-05-02 17:14:28 +01:00
Chris Palmer
34019196cd Updated readme 2021-05-02 17:14:14 +01:00
Martin Budden
436fc71cf3 Added blower_size function. 2021-05-02 15:27:44 +01:00
Chris Palmer
fd67c166f7 Updated changelog 2021-04-26 00:02:59 +01:00
Chris Palmer
634deab911 Merge branch 'martinbudden-core_xy_orientation' 2021-04-26 00:01:40 +01:00
Chris Palmer
e2feceb608 Updated readme 2021-04-26 00:00:41 +01:00
Chris Palmer
d1258e0b0c Merge branch 'core_xy_orientation' of https://github.com/martinbudden/NopSCADlib into martinbudden-core_xy_orientation 2021-04-25 23:57:44 +01:00
Chris Palmer
bd61a1dc55 Updated changelog 2021-04-25 23:56:47 +01:00
Chris Palmer
055e83902f Merge branch 'martinbudden-leadnut_typo' 2021-04-25 23:38:27 +01:00
Chris Palmer
feec1e7ae5 Updated readme. 2021-04-25 23:37:48 +01:00
Martin Budden
be76af2fc4 Fixed typo in leadnut.scad. 2021-04-25 18:31:51 +01:00
Martin Budden
9c1a9bf357 Add facility to orient core_xy with left motor being lower or upper motor. 2021-04-25 17:56:24 +01:00
Chris Palmer
9647fb474b Updated changelog 2021-04-25 00:08:57 +01:00
Chris Palmer
49fdfea792 Added 35BYGHJ75 geared stepper. 2021-04-25 00:07:22 +01:00
Chris Palmer
ac0bacfeda Removed echo in rails test. 2021-04-25 00:02:05 +01:00
Chris Palmer
6288059d99 Updated changelog. 2021-04-13 15:07:09 +01:00
Chris Palmer
0f1dff230a Merge branch 'martinbudden-pcb_component' 2021-04-13 15:05:18 +01:00
Chris Palmer
e379fa8ada Updated readme. 2021-04-13 15:05:12 +01:00
Chris Palmer
313d7508df Merge branch 'pcb_component' of https://github.com/martinbudden/NopSCADlib into martinbudden-pcb_component 2021-04-13 15:01:27 +01:00
Chris Palmer
083caca4e8 Updated changelog. 2021-04-13 15:00:37 +01:00
Chris Palmer
49329df00c Merge branch 'martinbudden-box_section' 2021-04-13 14:57:35 +01:00
Chris Palmer
edc0b86bb1 Updated images and readme. 2021-04-13 14:56:08 +01:00
Martin Budden
5fbff060b0 Added a pcb_component function. 2021-04-13 14:42:00 +01:00
Chris Palmer
b94ca4ad3a Merge branch 'box_section' of https://github.com/martinbudden/NopSCADlib into martinbudden-box_section 2021-04-12 22:35:01 +01:00
Chris Palmer
bc5515d35e Updated changelog. 2021-04-12 22:31:23 +01:00
Chris Palmer
44d213deaa Merge branch 'martinbudden-psu_size' 2021-04-12 22:29:41 +01:00
Chris Palmer
145c5d9b1a Updated readme. 2021-04-12 22:29:20 +01:00
Chris Palmer
7abbbd9b96 Merge branch 'psu_size' of https://github.com/martinbudden/NopSCADlib into martinbudden-psu_size 2021-04-12 22:26:25 +01:00
Chris Palmer
5b160cee88 Updated changelog. 2021-04-12 22:23:58 +01:00
Chris Palmer
3f31607840 Added No8 screws. 2021-04-12 22:22:25 +01:00
Martin Budden
1efed649cf Added PSU size function. 2021-04-12 17:52:57 +01:00
Martin Budden
b70c2f993c Added box sections. 2021-04-12 17:47:35 +01:00
Chris Palmer
56e252f3dc Updated changelog 2021-04-05 16:54:31 +01:00
Chris Palmer
f12b36ea04 Corrected MGN12 rail end value.
Added assert for rail end value too big.
2021-04-05 16:45:23 +01:00
Chris Palmer
bd5811e69b Updated changelog 2021-04-03 12:17:54 +01:00
Chris Palmer
ede4da6f1d Merge branch 'martinbudden-MGN7Hand9H_carriages' 2021-04-03 12:16:07 +01:00
Chris Palmer
51cc2fd679 Carriages now appear on the BOM and both variants are shown in the rail test. 2021-04-03 12:14:36 +01:00
Chris Palmer
4ce2f53e20 Merge branch 'MGN7Hand9H_carriages' of https://github.com/martinbudden/NopSCADlib into martinbudden-MGN7Hand9H_carriages 2021-04-02 19:53:41 +01:00
Chris Palmer
e338c47e73 Updated changelog 2021-04-02 19:52:15 +01:00
Chris Palmer
8328a70f42 Merge branch 'martinbudden-pulley_children' 2021-04-02 19:49:27 +01:00
Chris Palmer
cc794cd7c3 Updated readme. 2021-04-02 19:48:35 +01:00
Chris Palmer
df28bd5116 Merge branch 'pulley_children' of https://github.com/martinbudden/NopSCADlib into martinbudden-pulley_children 2021-04-02 19:39:28 +01:00
Chris Palmer
61de6041d8 Updated changelog. 2021-04-02 19:31:33 +01:00
Chris Palmer
b2d712bca9 Added quadratic_real_roots() and cubic_real_roots(). 2021-04-02 19:30:38 +01:00
Chris Palmer
f3376edaf1 Documented xor() function. 2021-04-02 19:28:49 +01:00
Chris Palmer
c073419c0b Added opengrab_screw_depth() function. 2021-04-02 19:25:42 +01:00
Martin Budden
608168de8e Added MGN7H and MGN9H carriages. 2021-03-31 01:46:18 +01:00
Martin Budden
fc45a40bd3 Added translated children to pulley. 2021-03-31 01:40:06 +01:00
Chris Palmer
52e9c1d7fd Updated changelog 2021-03-22 16:15:09 +00:00
Chris Palmer
ca1b34e9ca Added sink parameter to screw_polysink() to recess the head. 2021-03-22 16:11:51 +00:00
Chris Palmer
cbab9cea02 Fixed M6_cs_cap_screw. 2021-03-22 12:27:11 +00:00
Chris Palmer
69cf998862 Updated changelog 2021-03-21 18:50:14 +00:00
Chris Palmer
08bce9ec03 Updated changelog 2021-03-21 18:45:01 +00:00
Chris Palmer
4aa7dbb416 Added M6_cs_cap_screw. 2021-03-21 18:37:17 +00:00
Chris Palmer
7c7c2e5d3f Pixel changes due to switch to summer computer. 2021-03-21 17:57:46 +00:00
Chris Palmer
f6f6664c0d Updated OpenSCAD version required. 2021-03-15 00:24:14 +00:00
Chris Palmer
2fd2e118a0 Updated changelog 2021-03-14 19:04:00 +00:00
Chris Palmer
22c6fef113 Updated changelog 2021-03-14 18:56:50 +00:00
Chris Palmer
dcf0c949b9 Merge branch 'SmoothieAq-open_belt' 2021-03-14 18:54:28 +00:00
Chris Palmer
9ded315801 Removed the belt gap options and changed the tests to use open loops instead.
Note previous belt lengths were incorrect with negative turns.
Fixed spelling typos.
_belt_length() no longer needs belt type.
Uptated images and readme.
2021-03-14 18:53:37 +00:00
Chris Palmer
42e03679b4 Merge branch 'open_belt' of https://github.com/SmoothieAq/NopSCADlib into SmoothieAq-open_belt 2021-03-14 14:39:05 +00:00
SmoothieAq
d2c795f5f5 fix nan angle (hopefully) 2021-03-14 14:18:05 +01:00
Chris Palmer
83b4ab2374 Merge branch 'open_belt' of https://github.com/SmoothieAq/NopSCADlib into SmoothieAq-open_belt 2021-03-14 12:33:46 +00:00
SmoothieAq
573c50774b changes after review 2021-03-14 12:48:14 +01:00
Chris Palmer
4b93623492 changelog.py now omits "Updated changelog" commits. 2021-03-13 11:19:59 +00:00
Chris Palmer
d496898c80 Updated changelog 2021-03-13 10:46:30 +00:00
Chris Palmer
544e69c71b pulley_pr() now has an optional belt type for non-standard belt over smooth pulleys. 2021-03-13 10:45:54 +00:00
SmoothieAq
240334784d Extension to belt.scad
Can now:
- render open loops
- twist the belt
- use pulleys instead of radius in the points list

Fixes some precision a few places
Breaking change in belt_length(); now requires a type argument
2021-03-11 13:40:17 +01:00
SmoothieAq
516b225275 Merge pull request #1 from nophead/master
update fork
2021-03-10 09:11:48 +01:00
Chris Palmer
e46e6b6e5b Fixed markdown numbered points in core_xy. 2021-03-08 22:57:00 +00:00
Chris Palmer
4925979519 Updated changelog. 2021-03-06 21:41:15 +00:00
Chris Palmer
298d1f9284 Interface is the same but filenames to be included or used changed.
Changlog upated.
2021-03-06 21:31:53 +00:00
Chris Palmer
fcf2f5f7f0 Merge branch 'martinbudden-rounded_triangle_rename' 2021-03-06 21:25:25 +00:00
Chris Palmer
491c3b4ea8 Updated readme, lib.scad and image. 2021-03-06 21:24:57 +00:00
Chris Palmer
94cb50f725 Merge branch 'rounded_triangle_rename' of https://github.com/martinbudden/NopSCADlib into martinbudden-rounded_triangle_rename 2021-03-06 20:17:00 +00:00
Chris Palmer
1d8275c061 Merge branch 'martinbudden-scs_bearing_blocks_rename' 2021-03-06 20:14:42 +00:00
Chris Palmer
3c605d608b Updated path, readme and image 2021-03-06 20:11:55 +00:00
Chris Palmer
9ba48c7e1a Merge branch 'scs_bearing_blocks_rename' of https://github.com/martinbudden/NopSCADlib into martinbudden-scs_bearing_blocks_rename 2021-03-06 17:03:25 +00:00
Chris Palmer
a6ebc5267b Merge branch 'martinbudden-pillow_blocks_rename' 2021-03-06 17:00:46 +00:00
Chris Palmer
e9554ccffe Fixed paths and image. 2021-03-06 17:00:16 +00:00
Chris Palmer
0d179f3728 Merge branch 'pillow_blocks_rename' of https://github.com/martinbudden/NopSCADlib into martinbudden-pillow_blocks_rename 2021-03-06 16:49:21 +00:00
Chris Palmer
a94e462f34 Merge branch 'martinbudden-coreXY_belts' 2021-03-06 16:39:44 +00:00
Chris Palmer
7ce991e625 Updated readme for pulleys on BOM. 2021-03-06 16:37:54 +00:00
Chris Palmer
3e15be852f Merge branch 'coreXY_belts' of https://github.com/martinbudden/NopSCADlib into martinbudden-coreXY_belts 2021-03-06 16:35:52 +00:00
Martin Budden
7c1c8e92f2 Removed green code. 2021-03-06 16:35:46 +00:00
Chris Palmer
54c3b4f600 Fixed path, updated readme and picture. 2021-03-06 16:35:44 +00:00
Martin Budden
d80fc5709e Left pulleys on BOM when show_pulleys true. 2021-03-06 16:32:36 +00:00
Martin Budden
30236046a8 Renamed rounded_right_triangle files to rounded_triangle. 2021-03-06 16:22:41 +00:00
Martin Budden
93aeb4cf2c Renamed scs_bearing_blocks files to bearing_blocks. 2021-03-06 16:16:43 +00:00
Chris Palmer
f62ca35c86 Merge branch 'coreXY_belts' of https://github.com/martinbudden/NopSCADlib into martinbudden-coreXY_belts 2021-03-06 16:14:23 +00:00
Martin Budden
2320cbdbb8 Renamed kp_pillow_blocks files to pillow_blocks. 2021-03-06 16:13:09 +00:00
Martin Budden
769cb44207 Renamed core_xy files. 2021-03-06 16:06:25 +00:00
Chris
f327df95a3 Merge pull request #162 from martinbudden/tests_py
Improved resilience of compare_images.
2021-03-06 15:58:38 +00:00
Martin Budden
09956b6219 Improved resilience of compare_images. 2021-03-06 15:36:49 +00:00
Chris
f8c9adca5a Merge pull request #161 from martinbudden/cmdline_reorder
Reordered openscad command line parameters to put output name first.
2021-03-06 15:06:03 +00:00
Martin Budden
b83e56713f Reordered openscad command line parameters. 2021-03-06 14:30:35 +00:00
Martin Budden
4c12d5fca4 Added parameterised CoreXY. 2021-03-06 10:10:28 +00:00
Chris Palmer
da4f9fbdc3 Typo in changlog.py doc string. 2021-03-04 09:14:27 +00:00
Chris Palmer
614e5f3a72 Issues in the changelog now link to to the issue. 2021-03-03 19:27:25 +00:00
Chris Palmer
a7eae4f549 Neater changlog format. 2021-03-03 19:10:27 +00:00
Chris Palmer
3cd5769708 Merge branch 'martinbudden-cf_contrast' 2021-03-03 14:32:19 +00:00
Chris Palmer
7b770abe12 Udpated changelog 2021-03-03 14:31:38 +00:00
Chris Palmer
31ab8562a7 Updated images 2021-03-03 14:29:32 +00:00
Chris Palmer
db703379a3 Merge branch 'cf_contrast' of https://github.com/martinbudden/NopSCADlib into martinbudden-cf_contrast 2021-03-03 14:17:48 +00:00
Chris Palmer
cd925bc049 Added changelog link to readme. 2021-03-03 14:12:21 +00:00
Chris Palmer
4a2951e22f Fixed changelog.py for when HEAD doesn't have tag. 2021-03-03 13:51:22 +00:00
Chris Palmer
a93a8f99fb Added CHANGELOG.md for #154 2021-03-03 13:47:09 +00:00
Martin Budden
73c436ee15 Improved contrast of carbon fiber sheets. 2021-02-27 16:34:27 +00:00
Chris Palmer
c69100bd71 Added spring steel and silicone sheets. 2021-02-22 15:26:19 +00:00
Chris Palmer
e0b89359aa Fixed plateup using target dir when no panels or platters. 2021-02-21 14:18:41 +00:00
Chris Palmer
041d720c39 Updated example bom.json. 2021-02-21 14:17:09 +00:00
Chris Palmer
03a0c2fe98 Fixed typo. 2021-02-20 20:13:36 +00:00
Chris Palmer
7c2df8d36d The pose module can now specify the camera distance supressing viewall and
autocentre.
2021-02-20 19:28:52 +00:00
Chris Palmer
8474718884 Added printed pocket_handle(). 2021-02-17 13:20:39 +00:00
Chris Palmer
fe0f32ddc5 Merge branch 'martinbudden-polyholes' 2021-02-11 09:41:27 +00:00
Chris Palmer
f191b9b0f4 Updated readme 2021-02-11 09:40:18 +00:00
Chris Palmer
2b3908b6fd Merge branch 'polyholes' of https://github.com/martinbudden/NopSCADlib into martinbudden-polyholes 2021-02-11 09:11:42 +00:00
Chris Palmer
0a84bf0927 plateup.py now saves the used files to speed up processing when a part hasn't changed.
Added times to plateup.py.
2021-02-11 09:10:15 +00:00
Chris Palmer
da825b17ab Added colorama.init() to plateup.py to handle new coloured changed messages. 2021-02-10 10:22:38 +00:00
Chris Palmer
ca153c971d Fixed platters and panels not working in the GUI, a regression.
set_config() now puts $cwd in target.scad.
use_stl() and use_dxf() included again instead of used.
2021-02-10 10:17:03 +00:00
Martin Budden
0199587907 Allow poly_shapes to collapse to non-poly form. 2021-02-10 08:29:15 +00:00
Chris Palmer
60350eb228 Updated gallery.py for new page break format. 2021-02-09 23:44:03 +00:00
Chris Palmer
4f9729cf86 Now shows what changed to trigger an openscad invocation in cyan. 2021-02-09 23:32:53 +00:00
Chris Palmer
26f1338ca2 Fixed removal of old deps 2021-02-09 14:34:27 +00:00
Chris Palmer
fc44b43638 Temporary files used during make_all and tests now in tmp dir. 2021-02-09 09:52:26 +00:00
Chris Palmer
182f39876a Moved deps directories to separate stl deps from views deps. 2021-02-09 09:18:30 +00:00
Chris Palmer
055e90cbb3 /stls/ and /dxfs/ excluded from deps to prevent circular dependencies. 2021-02-08 22:44:21 +00:00
Chris Palmer
832380f893 Fixed set_config always writing to target.scad. 2021-02-08 20:31:10 +00:00
Chris Palmer
929d082b25 openscad.py now quits if there are errors or warnings in the log.
This is because the exit status is not always set correctly.
2021-02-08 16:03:59 +00:00
Chris Palmer
57212b5701 set_config.py now defines $target. 2021-02-08 15:00:44 +00:00
Chris Palmer
1c3f136657 Fixed $cwd and $target not defined during silent run. 2021-02-08 15:00:01 +00:00
Chris Palmer
cfd2fd32a1 Now checks openscad.echo for warnings when used instead of openscad.log. 2021-02-08 14:58:50 +00:00
101 changed files with 4198 additions and 497 deletions

1872
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
# NopSCADlib usage
## Requirements
1. OpenSCAD 2019.05 or later, download it from here: https://www.openscad.org/downloads.html
1. OpenSCAD 2021.01 or later, download it from here: https://www.openscad.org/downloads.html
1. Python 2.7+ or 3.6+ from https://www.python.org/downloads/
1. ImageMagick 7 www.imagemagick.org

View File

@@ -3,6 +3,7 @@
"name": "base_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {},
"vitamins": {
@@ -22,6 +23,7 @@
"name": "feet_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"base_assembly": 1
@@ -49,6 +51,7 @@
"name": "mains_in_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"feet_assembly": 1
@@ -86,6 +89,7 @@
"name": "main_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"mains_in_assembly": 1

View File

@@ -1,40 +1,30 @@
# A gallery of projects made with NopSCADlib
<a name="TOP"></a>
## ArduinoThermostat
Arduino thermostat to control a beer fridge to use it as an environmental chamber.
![](ArduinoThermostat.png)
<a name="TOP"></a>
## EnviroPlus
Environmental monitor using Enviro+ sensor board and a Raspberry Pi Zero.
![](EnviroPlus.png)
<a name="TOP"></a>
## FilamentDryBox
A small fan oven with a spool holder to keep the filament warm and dry.
![](FilamentDryBox.png)
<a name="TOP"></a>
## HydraBot
Current state of HydraRaptor after being modified for laser engraving.
![](HydraBot.png)
<a name="TOP"></a>
## IOT 50V PSU
WiFi controllable PSU
![](IOT_50V_PSU.png)
<a name="TOP"></a>
## Lab ATX PSU
Bench power supply built around an ATX PSU.
@@ -47,15 +37,11 @@ Bench power supply built around an ATX PSU.
<a name="TOP"></a>
## Laser Load
15kV dummy load for testing CO2 laser PSUs
![](Laser_load.png)
<a name="TOP"></a>
## MainsBreakOutBox
13A socket break out box with 4mm jacks to measure voltage and / or load current and earth leakage current.
@@ -72,8 +58,6 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![](MainsBreakOutBox.png)
<a name="TOP"></a>
## Mains Box
Mains isolated and variable supply with metering.
@@ -81,15 +65,11 @@ Mains isolated and variable supply with metering.
<a name="TOP"></a>
## SunBot
A solar tracker to keep a solar panel pointing at the sun.
![](SunBot.png)
<a name="TOP"></a>
## Turntable
WiFi enabled remote control turntable for photography
@@ -97,8 +77,6 @@ WiFi enabled remote control turntable for photography
Was actually made from DiBond but shown made with carbon fibre here.
<a name="TOP"></a>
## Variac
Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp8266-spi-spy](https://hydraraptor.blogspot.com/2018/04/esp8266-spi-spy.html)
@@ -106,4 +84,3 @@ Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp826

View File

@@ -27,15 +27,16 @@
// Setting $_bom in the local file overrides it in the local file but not in the libs.
//
rr_green = [0, 146/255, 0]; // RepRap logo colour
crimson = [220/255, 20/255, 60/255];
$_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well
$exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth when printing
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer height when printing
extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing
nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects
pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour
pp2_colour = is_undef($pp2_colour) ? "Crimson" : $pp2_colour; // printed part colour 2
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

View File

@@ -26,7 +26,10 @@ include <vitamins/psus.scad>
include <vitamins/pcbs.scad>
include <vitamins/batteries.scad>
include <vitamins/bearing_blocks.scad>
include <vitamins/blowers.scad>
include <vitamins/bldc_motors.scad>
include <vitamins/box_sections.scad>
include <vitamins/bulldogs.scad>
include <vitamins/buttons.scad>
include <vitamins/cameras.scad>
@@ -37,7 +40,6 @@ include <vitamins/extrusion_brackets.scad>
include <vitamins/geared_steppers.scad>
include <vitamins/hot_ends.scad>
include <vitamins/inserts.scad>
include <vitamins/kp_pillow_blocks.scad>
include <vitamins/ldrs.scad>
include <vitamins/leadnuts.scad>
include <vitamins/led_meter.scad>
@@ -47,12 +49,12 @@ include <vitamins/mains_sockets.scad>
include <vitamins/modules.scad>
include <vitamins/panel_meters.scad>
include <vitamins/pillars.scad>
include <vitamins/pillow_blocks.scad>
include <vitamins/pin_headers.scad>
include <vitamins/pulleys.scad>
include <vitamins/ring_terminals.scad>
include <vitamins/rails.scad>
include <vitamins/rod.scad>
include <vitamins/scs_bearing_blocks.scad>
include <vitamins/shaft_couplings.scad>
include <vitamins/sheets.scad>
include <vitamins/sk_brackets.scad>
@@ -89,7 +91,7 @@ use <utils/gears.scad>
use <utils/hanging_hole.scad>
use <utils/fillet.scad>
use <utils/rounded_polygon.scad>
use <utils/rounded_right_triangle.scad>
use <utils/rounded_triangle.scad>
use <utils/layout.scad>
use <utils/round.scad>
use <utils/offset.scad>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 882 KiB

After

Width:  |  Height:  |  Size: 908 KiB

View File

@@ -33,6 +33,8 @@
//!
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
//!
//! A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
//!
//! <img src="libtest.png" width="100%"/>
//
// This file shows all the parts in the library.
@@ -41,8 +43,11 @@ include <lib.scad>
use <tests/ball_bearings.scad>
use <tests/batteries.scad>
use <tests/bearing_blocks.scad>
use <tests/belts.scad>
use <tests/BLDC_motors.scad>
use <tests/blowers.scad>
use <tests/box_sections.scad>
use <tests/bulldogs.scad>
use <tests/buttons.scad>
use <tests/cable_strips.scad>
@@ -62,7 +67,6 @@ use <tests/hot_ends.scad>
use <tests/IECs.scad>
use <tests/inserts.scad>
use <tests/jack.scad>
use <tests/KP_pillow_blocks.scad>
use <tests/leadnuts.scad>
use <tests/LDRs.scad>
use <tests/LEDs.scad>
@@ -78,6 +82,7 @@ use <tests/opengrab.scad>
use <tests/panel_meters.scad>
use <tests/PCBs.scad>
use <tests/pillars.scad>
use <tests/pillow_blocks.scad>
use <tests/press_fit.scad>
use <tests/PSUs.scad>
use <tests/pulleys.scad>
@@ -86,7 +91,6 @@ use <tests/ring_terminals.scad>
use <tests/rockers.scad>
use <tests/rod.scad>
use <tests/screws.scad>
use <tests/SCS_bearing_blocks.scad>
use <tests/sealing_strip.scad>
use <tests/shaft_couplings.scad>
use <tests/sheets.scad>
@@ -117,6 +121,7 @@ use <tests/flat_hinge.scad>
use <tests/foot.scad>
use <tests/handle.scad>
use <tests/PCB_mount.scad>
use <tests/pocket_handle.scad>
use <tests/printed_box.scad>
use <tests/printed_pulleys.scad>
use <tests/ribbon_clamp.scad>
@@ -180,7 +185,10 @@ translate([x5, cable_grommets_y + 250])
translate([950, 600])
box_test();
translate([890, 750])
translate([830, 770])
pocket_handles();
translate([950, 750])
printed_boxes();
translate([850, 1330])
@@ -201,8 +209,8 @@ ball_bearings_y = pillars_y + 40;
pulleys_y = ball_bearings_y +40;
hot_ends_y = pulleys_y + 60;
linear_bearings_y = hot_ends_y + 50;
sheets_y = linear_bearings_y + 100;
pcbs_y = sheets_y + 40;
sheets_y = linear_bearings_y + 90;
pcbs_y = sheets_y + 60;
displays_y = pcbs_y + 170;
fans_y = displays_y + 80;
transformers_y = fans_y + 120;
@@ -362,10 +370,10 @@ extrusions_y = panel_meters_y + 80;
translate([x3, veroboard_y])
veroboard_test();
translate([x3 + 70, veroboard_y + 30])
translate([x3 + 60, veroboard_y + 20])
geared_steppers();
translate([x3 + 140, veroboard_y + 20])
translate([x3 + 160, ssrs_y])
pcb_mounts();
translate([x3 + 170, veroboard_y + 16])
@@ -420,6 +428,9 @@ extrusion_brackets_y = rails_y + 250;
sk_brackets_y = extrusion_brackets_y + 80;
kp_pillow_blocks_y = sk_brackets_y + 50;
scs_bearing_blocks_y = kp_pillow_blocks_y + 60;
cable_strip_y = fans_y + 50;
box_sections_y = cable_strip_y;
BLDC_y = sheets_y;
translate([x4 + 200, belts_y + 58]) {
belt_test();
@@ -435,7 +446,7 @@ translate([x4 + 175, belts_y, -20])
translate([x4, rails_y + 130])
rails();
translate([770, fans_y + 50])
translate([770, cable_strip_y])
cable_strips();
translate([x4, kp_pillow_blocks_y])
@@ -453,6 +464,11 @@ translate([x4 + 120, extrusion_brackets_y])
translate([x4, scs_bearing_blocks_y])
scs_bearing_blocks();
translate([x4, BLDC_y])
bldc_motors();
translate([x6, box_sections_y])
box_sections();
translate([x6, 125])
light_strips();

154
printed/pocket_handle.scad Normal file
View File

@@ -0,0 +1,154 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
//! Customisable pocket handle
//
include <../core.scad>
function pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4) = //! Construct a pocket_handle property list
[hand_size, slant, screw, panel_t, wall, rad];
function pocket_handle_hand_size(type) = type[0]; //! Size of the hole for the fingers
function pocket_handle_slant(type) = type[1]; //! Upward slant of the hand hole
function pocket_handle_screw(type) = type[2]; //! Screw type, can be countersunk or not
function pocket_handle_panel_t(type) = type[3]; //! Thickness of the panel it is mounted in
function pocket_handle_wall(type) = type[4]; //! Wall thickness
function pocket_handle_rad(type) = type[5]; //! Min corner rad
function pocket_handle_flange(type) = //! Size of the flange
let(w = pocket_handle_wall(type),
f = washer_diameter(screw_washer(pocket_handle_screw(type))) + 2 + w,
s = pocket_handle_hand_size(type))
[s.x + 2 * f, s.y + 2 * f, w];
module pocket_handle_hole_positions(type) { //! Place children at screw hole positions
f = pocket_handle_flange(type);
h = pocket_handle_hand_size(type);
x_pitch = (f.x + h.x) / 4;
y_pitch = (f.y + h.y) / 4;
for(x = [-1, 1], y = [-1, 1])
translate([x * x_pitch, y * y_pitch])
children();
}
module pocket_handle_holes(type, h = 0) { //! Panel cutout and screw holes
hand = pocket_handle_hand_size(type);
w = pocket_handle_wall(type);
slot = [hand.x + 2 * w, hand.y + 2 * w];
t = pocket_handle_panel_t(type);
clearance = norm([slot.y, t]) - slot.y + 0.2; // has to be enough clearance for the diagonal to swing it in
extrude_if(h) {
pocket_handle_hole_positions(type)
drill(screw_clearance_radius(pocket_handle_screw(type)), 0);
rounded_square([slot.x + clearance, slot.y + clearance], pocket_handle_rad(type) + w + clearance / 2);
}
}
module pocket_handle(type) { //! Generate STL for pocket_handle
f = pocket_handle_flange(type);
r = pocket_handle_rad(type);
s = pocket_handle_slant(type);
o = f.z * tan(s);
h = pocket_handle_hand_size(type);
t = pocket_handle_panel_t(type);
w = pocket_handle_wall(type);
screw = pocket_handle_screw(type) ;
stl("pocket_handle")
union() {
difference() {
hull() {
rounded_rectangle(f, r);
translate_z(f.z - eps)
rounded_rectangle([f.x + 2 * o, f.y + 2 * o, eps], r + o);
}
hull() {
rounded_rectangle([h.x, h.y, f.z + eps], r);
translate_z(-eps)
rounded_rectangle([h.x + 2 * o, h.y + 2 * o, eps], r + o);
}
pocket_handle_hole_positions(type) {
if(screw_head_height(screw))
translate_z(-eps)
poly_cylinder(r = screw_clearance_radius(screw), h = f.z + 2 * eps, center = false);
else
screw_polysink(screw, h = 2 * f.z + eps, alt = true);
}
}
translate_z(f.z)
linear_extrude(t)
difference() {
rounded_square([h.x + 2 * w, h.y + 2 * w], r + w);
rounded_square([h.x, h.y], r);
}
translate_z(f.z + t)
difference() {
height = h.z - f.z - t;
hull() {
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
translate((height + w) * [0, sin(s), cos(s)])
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
}
hull() {
translate_z(-eps)
rounded_rectangle([h.x, h.y, eps], r);
translate(height * [0, sin(s), cos(s)])
rounded_rectangle([h.x, h.y, eps], r);
}
}
}
}
module pocket_handle_assembly(type) { //! Assembly with fasteners in place
f = pocket_handle_flange(type);
screw = pocket_handle_screw(type);
nut = screw_nut(screw);
t = pocket_handle_panel_t(type);
washers = screw_head_height(screw) ? 2 : 1;
screw_length = screw_length(screw, f.z + t, washers, nyloc = true);
translate_z(f.z + t / 2) hflip() {
stl_colour(pp1_colour)
pocket_handle(type);
pocket_handle_hole_positions(type) {
translate_z(f.z + t)
explode(15, true)
nut_and_washer(nut, true);
vflip()
if(washers == 2)
screw_and_washer(screw, screw_length);
else
screw(screw, screw_length);
}
}
}

628
readme.md
View File

@@ -14,36 +14,38 @@ 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.
A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
<img src="libtest.png" width="100%"/>
## Table of Contents<a name="top"/>
<table><tr>
<th align="left"> Vitamins A-I </th><th align="left"> Vitamins J-Q </th><th align="left"> Vitamins R-Z </th><th align="left"> Printed </th><th align="left"> Utilities </th><th align="left"> Core Utilities </th></tr>
<tr><td> <a href = "#Axials">Axials</a> </td><td> <a href = "#Jack">Jack</a> </td><td> <a href = "#Rails">Rails</a> </td><td> <a href = "#Box">Box</a> </td><td> <a href = "#Annotation">Annotation</a> </td><td> <a href = "#BOM">BOM</a> </td></tr>
<tr><td> <a href = "#Ball_bearings">Ball_bearings</a> </td><td> <a href = "#KP_pillow_blocks">KP_pillow_blocks</a> </td><td> <a href = "#Ring_terminals">Ring_terminals</a> </td><td> <a href = "#Butt_box">Butt_box</a> </td><td> <a href = "#Bezier">Bezier</a> </td><td> <a href = "#Clip">Clip</a> </td></tr>
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Catenary">Catenary</a> </td><td> <a href = "#Global">Global</a> </td></tr>
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_right_triangle">Rounded_right_triangle</a> </td><td></td></tr>
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Inserts">Inserts</a> </td><td></td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
<tr><td></td><td></td><td> <a href = "#Zipties">Zipties</a> </td><td></td><td></td><td></td></tr>
<th align="left"> Vitamins A-H </th><th align="left"> Vitamins I-Q </th><th align="left"> Vitamins R-Z </th><th align="left"> Printed </th><th align="left"> Utilities </th><th align="left"> Core Utilities </th></tr>
<tr><td> <a href = "#Axials">Axials</a> </td><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Rails">Rails</a> </td><td> <a href = "#Box">Box</a> </td><td> <a href = "#Annotation">Annotation</a> </td><td> <a href = "#BOM">BOM</a> </td></tr>
<tr><td> <a href = "#BLDC_motors">BLDC_motors</a> </td><td> <a href = "#Inserts">Inserts</a> </td><td> <a href = "#Ring_terminals">Ring_terminals</a> </td><td> <a href = "#Butt_box">Butt_box</a> </td><td> <a href = "#Bezier">Bezier</a> </td><td> <a href = "#Clip">Clip</a> </td></tr>
<tr><td> <a href = "#Ball_bearings">Ball_bearings</a> </td><td> <a href = "#Jack">Jack</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Catenary">Catenary</a> </td><td> <a href = "#Global">Global</a> </td></tr>
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Core_xy">Core_xy</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
<tr><td> <a href = "#Bearing_blocks">Bearing_blocks</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
<tr><td> <a href = "#Box_sections">Box_sections</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td></td></tr>
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Pocket_handle">Pocket_handle</a> </td><td> <a href = "#Rounded_triangle">Rounded_triangle</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Pillow_blocks">Pillow_blocks</a> </td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Zipties">Zipties</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td></td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
</table>
---
@@ -198,18 +200,89 @@ exposing enough information to make a battery box.
| 1 | `battery(S25R18650)` | Cell Samsung 25R 18650 LION |
<a href="#top">Top</a>
---
<a name="Bearing_blocks"></a>
## Bearing_blocks
SCSnUU and SCSnLUU bearing blocks
[vitamins/bearing_blocks.scad](vitamins/bearing_blocks.scad) Object definitions.
[vitamins/bearing_block.scad](vitamins/bearing_block.scad) Implementation.
[tests/bearing_blocks.scad](tests/bearing_blocks.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `scs_bearing(type)` | Linear bearing used |
| `scs_block_center_height(type)` | Height of the center of the block |
| `scs_block_side_height(type)` | Height of the side of the block, this determines the minimum screw length |
| `scs_circlip(type)` | Circlip used |
| `scs_hole_offset(type)` | Offset of bearing hole from base of block |
| `scs_screw(type)` | Screw type |
| `scs_screw_separation_x(type)` | Screw separation in X direction |
| `scs_screw_separation_z(type)` | Screw separation in Z direction |
| `scs_spacer(type)` | Spacer used in long bearings |
### Functions
| Function | Description |
|:--- |:--- |
| `scs_size(type)` | Size of scs bracket bounding block |
### Modules
| Module | Description |
|:--- |:--- |
| `scs_bearing_block(type)` | Draw the specified SCS bearing block |
| `scs_bearing_block_assembly(type, part_thickness, screw_type, nut_type)` | Assembly with screws and nuts in place |
| `scs_bearing_block_hole_positions(type)` | Place children at hole positions |
![bearing_blocks](tests/png/bearing_blocks.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 12 | `nut(M4_nut)` | Nut M4 x 3.2mm |
| 24 | `nut(M5_nut)` | Nut M5 x 4mm |
| 1 | `scs_bearing_block(SCS10LUU)` | SCS10LUU bearing block |
| 1 | `scs_bearing_block(SCS10UU)` | SCS10UU bearing block |
| 1 | `scs_bearing_block(SCS12LUU)` | SCS12LUU bearing block |
| 1 | `scs_bearing_block(SCS12UU)` | SCS12UU bearing block |
| 1 | `scs_bearing_block(SCS16LUU)` | SCS16LUU bearing block |
| 1 | `scs_bearing_block(SCS16UU)` | SCS16UU bearing block |
| 1 | `scs_bearing_block(SCS6UU)` | SCS6UU bearing block |
| 1 | `scs_bearing_block(SCS8LUU)` | SCS8LUU bearing block |
| 1 | `scs_bearing_block(SCS8UU)` | SCS8UU bearing block |
| 4 | `screw(M4_cap_screw, 25)` | Screw M4 cap x 25mm |
| 8 | `screw(M4_cap_screw, 30)` | Screw M4 cap x 30mm |
| 16 | `screw(M5_cap_screw, 35)` | Screw M5 cap x 35mm |
| 8 | `screw(M5_cap_screw, 45)` | Screw M5 cap x 45mm |
| 12 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
| 24 | `washer(M5_washer)` | Washer M5 x 10mm x 1mm |
<a href="#top">Top</a>
---
<a name="Belts"></a>
## Belts
Models timing belt running over toothed or smooth pulleys and calculates an accurate length.
Only models 2D paths, so not crossed belt core XY!
Models timing belt running in a path over toothed or smooth pulleys and calculates an accurate length.
Only models 2D paths, belt may twist to support crossed belt core XY and other designes where the belt twists!
By default the path is a closed loop. An open loop can be specified by specifying `open=true`, and in that case the start and end points are not connected, leaving the loop open.
To get a 180 degree twist of the loop, you can use the `twist` argument. `Twist` can be a single number, and in that case the belt will twist after
the position with that number. Alternatively `twist` can be a list of boolean values with a boolean for each position; the belt will then twist after
the position that have a `true` value in the `twist` list. If the path is specified with pulley/idler types, then you can use `auto_twist=true`; in
that case the belt will automatically twist so the back of the belt always runs against idlers and the tooth side runs against pullies. If you use
`open=true` then you might also use `start_twist=true` to let the belt start the part with the back side out.
The path must be specified as a list of positions. Each position should be either a vector with `[x, y, pulley]` or `[x, y, r]`. A pully is a type from
`pulleys.scad`, and correct radius and angle will automatically be calculated. Alternatively a radius can be specified directly.
To make the back of the belt run against a smooth pulley on the outside of the loop specify a negative pitch radius.
By default the path is a closed loop but a gap length and position can be specified to make open loops.
To draw the gap its XY position is specified by `gap_pos`. `gap_pos.z` can be used to specify a rotation if the gap is not at the bottom of the loop.
Alternativley you can just specify smooth pulleys in the path, and it will then happen automatically.
Individual teeth are not drawn, instead they are represented by a lighter colour.
@@ -231,13 +304,15 @@ Individual teeth are not drawn, instead they are represented by a lighter colour
### Functions
| Function | Description |
|:--- |:--- |
| `belt_length(points, gap = 0)` | Compute belt length given path and optional gap |
| `_belt_points_info(type, points, open, twist, auto_twist, start_twist)` | Helper function that calculates [twist, istwisted, points, tangents, arcs] |
| `belt_length(type, points, open = false)` | Compute belt length given path |
| `belt_pitch_to_back(type)` | Offset of the back from the pitch radius |
| `belt_pulley_pr(type, pulley, twisted=false)` | Pitch radius. Default it expects the belt tooth to be against a toothed pulley an the backside to be against a smooth pulley (an idler). If `twisted` is true, the the belt is the other way around. |
### Modules
| Module | Description |
|:--- |:--- |
| `belt(type, points, gap = 0, gap_pos = undef, belt_colour = grey(20)` | Draw a belt path given a set of points and pitch radii where the pulleys are. Closed loop unless a gap is specified |
| `belt(type, points, belt_colour = grey(20)` | Draw a belt path given a set of points and pitch radii where the pulleys are. Closed loop unless open is specified |
![belts](tests/png/belts.png)
@@ -245,17 +320,85 @@ Individual teeth are not drawn, instead they are represented by a lighter colour
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `belt(GT2x6, [ ... ])` | Belt GT2 x 6mm x 128mm |
| 2 | `belt(GT2x6, [ ... ], 80, [0, 0])` | Belt GT2 x 6mm x 572mm |
| 1 | `belt(GT2x6, [ ... ])` | Belt GT2 x 6mm x 552mm |
| 2 | `belt(GT2x6, [ ... ])` | Belt GT2 x 6mm x 556mm |
| 1 | `belt(T2p5x6, [ ... ])` | Belt T2.5 x 6mm x 130mm |
| 1 | `belt(T5x10, [ ... ])` | Belt T5 x 10mm x 130mm |
| 1 | `belt(T5x6, [ ... ])` | Belt T5 x 6mm x 130mm |
| 2 | `insert(F1BM3)` | Heatfit insert M3 |
| 2 | `pulley(GT2x16_toothed_idler)` | Pulley GT2 idler 16 teeth |
| 4 | `pulley(GT2x20_toothed_idler)` | Pulley GT2 idler 20 teeth |
| 2 | `pulley(GT2x16_plain_idler)` | Pulley GT2 idler smooth 9.63mm |
| 2 | `pulley(GT2x20ob_pulley)` | Pulley GT2OB 20 teeth |
| 6 | `pulley(GT2x16_plain_idler)` | Pulley GT2 idler smooth 9.63mm |
| 3 | `pulley(GT2x20ob_pulley)` | Pulley GT2OB 20 teeth |
| 2 | `screw(M3_cs_cap_screw, 20)` | Screw M3 cs cap x 20mm |
| 4 | `screw(M3_grub_screw, 6)` | Screw M3 grub x 6mm |
| 6 | `screw(M3_grub_screw, 6)` | Screw M3 grub x 6mm |
<a href="#top">Top</a>
---
<a name="BLDC_motors"></a>
## BLDC_motors
Brushless DC electric motor
[vitamins/bldc_motors.scad](vitamins/bldc_motors.scad) Object definitions.
[vitamins/bldc_motor.scad](vitamins/bldc_motor.scad) Implementation.
[tests/BLDC_motors.scad](tests/BLDC_motors.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `BLDC_base_diameter(type)` | Base diameter |
| `BLDC_base_height_1(type)` | Base height 1 |
| `BLDC_base_height_2(type)` | Base height 2 |
| `BLDC_base_hole_diameter(type)` | Base hole diameter |
| `BLDC_base_holes(type)` | Base holes |
| `BLDC_base_open(type)` | Base open |
| `BLDC_bell_diameter(type)` | Bell diameter |
| `BLDC_bell_height_1(type)` | Bell height 1 |
| `BLDC_bell_height_2(type)` | Bell height 2 |
| `BLDC_bell_hole_diameter(type)` | Bell hole diameter |
| `BLDC_bell_holes(type)` | Bell holes |
| `BLDC_bell_spokes(type)` | Bell spoke count |
| `BLDC_body_colour(type)` | Body colour |
| `BLDC_boss_diameter(type)` | Boss diameter |
| `BLDC_boss_height(type)` | Boss height |
| `BLDC_diameter(type)` | Diameter of motor |
| `BLDC_height(type)` | Height of motor including boss, if any, but excluding prop shaft |
| `BLDC_prop_shaft_diameter(type)` | Diameter of unthreaded portion of prop shaft |
| `BLDC_prop_shaft_length(type)` | Prop shaft length, including threaded section |
| `BLDC_prop_shaft_thread_diameter(type)` | Diameter of threaded section of prop shaft |
| `BLDC_prop_shaft_thread_length(type)` | Length of threaded section of prop shaft |
| `BLDC_shaft_diameter(type)` | shaft diameter |
| `BLDC_shaft_length(type)` | Total shaft length |
| `BLDC_shaft_offset(type)` | shaft offset from base |
| `BLDC_side_colour(type)` | Side colour |
| `BLDC_wire_diameter(type)` | Wire diameter |
### Modules
| Module | Description |
|:--- |:--- |
| `BLDC(type)` | Draw specified BLDC motor |
| `BLDC_base_screw_positions(type, n = 4)` | Positions children at the base screw holes |
| `BLDC_bell_screw_positions(type, n = 4)` | Positions children at the bell screw holes |
| `BLDC_screw_positions(holes, n = 4)` | Screw positions utility function |
![bldc_motors](tests/png/bldc_motors.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `BLDC(BLDC0603)` | Brushless DC motor BLDC0603 |
| 1 | `BLDC(BLDC0802)` | Brushless DC motor BLDC0802 |
| 1 | `BLDC(BLDC1105)` | Brushless DC motor BLDC1105 |
| 1 | `BLDC(BLDC1306)` | Brushless DC motor BLDC1306 |
| 1 | `BLDC(BLDC1804)` | Brushless DC motor BLDC1804 |
| 1 | `BLDC(BLDC2205)` | Brushless DC motor BLDC2205 |
| 1 | `BLDC(BLDC2212)` | Brushless DC motor BLDC2212 |
| 1 | `BLDC(BLDC3548)` | Brushless DC motor BLDC3548 |
| 1 | `BLDC(BLDC4250)` | Brushless DC motor BLDC4250 |
<a href="#top">Top</a>
@@ -297,6 +440,7 @@ Models of radial blowers.
|:--- |:--- |
| `blower_casing_is_square(type)` | True for square radial fans, false for spiral shape radial blowers |
| `blower_exit_offset(type)` | Offset of exit's centre from the edge |
| `blower_size(type)` | Size |
### Modules
| Module | Description |
@@ -323,6 +467,44 @@ Models of radial blowers.
| 2 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
<a href="#top">Top</a>
---
<a name="Box_sections"></a>
## Box_sections
Box sections.
[vitamins/box_sections.scad](vitamins/box_sections.scad) Object definitions.
[vitamins/box_section.scad](vitamins/box_section.scad) Implementation.
[tests/box_sections.scad](tests/box_sections.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `box_section_colour(type)` | Colour |
| `box_section_colour2(type)` | Colour2, for woven box section |
| `box_section_fillet(type)` | Fillet |
| `box_section_material(type)` | Material description |
| `box_section_size(type)` | Size |
| `box_section_thickness(type)` | Wall thickness |
### Functions
| Function | Description |
|:--- |:--- |
| `box_section_is_woven(type)` | Box section is woven, eg carbon fiber |
![box_sections](tests/png/box_sections.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `box_section(AL12x8x1, 100)` | Aluminium rectangular box section 12mm x 8mm x 1mm, length 100mm |
| 1 | `box_section(AL20x20x2, 100)` | Aluminium rectangular box section 20mm x 20mm x 2mm, length 100mm |
| 1 | `box_section(CF10x10x1, 100)` | Carbon fiber rectangular box section 10mm x 10mm x 1mm, length 100mm |
<a href="#top">Top</a>
---
@@ -977,23 +1159,23 @@ Geared tin can steppers
|:--- |:--- |
| `gs_boss_d(type)` | Boss around the shaft diameter |
| `gs_boss_h(type)` | Boss around the shaft height |
| `gs_bulge2_d(type)` | Plastic rear bulge depth from centre |
| `gs_bulge2_h(type)` | Plastic rear bulge height |
| `gs_bulge2_w(type)` | Plastic rear bulge width |
| `gs_bulge_d(type)` | Plastic bulge depth from centre |
| `gs_bulge_h(type)` | Plastic bulge height |
| `gs_bulge_w(type)` | Plastic bulge width |
| `gs_bulge(type)` | Plastic bulge width, depth, height, z offset |
| `gs_bulge2(type)` | Plastic rear bulge width, depth, height |
| `gs_diameter(type)` | Can diameter |
| `gs_flat_length(type)` | Shaft flat length |
| `gs_height(type)` | Can height |
| `gs_hole_d(type)` | Screw hole diameter |
| `gs_lug_t(type)` | Screw lug thickness |
| `gs_lug_w(type)` | Screw lug width |
| `gs_motor(type)` | Motor diameter and height if separate from gearbox |
| `gs_offset(type)` | Offset of the shaft from the centre of the can |
| `gs_pitch(type)` | Screw pitch |
| `gs_radius(type)` | Top - or bottom + corner radius |
| `gs_shaft_d(type)` | Shaft diameter |
| `gs_shaft_flat(type)` | Shaft width across the flats |
| `gs_shaft_length(type)` | Shaft length |
| `gs_wire_d(type)` | Wire diameter |
| `gs_wires(type)` | Wire colours and grouping |
### Modules
| Module | Description |
@@ -1007,6 +1189,7 @@ Geared tin can steppers
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `geared_stepper(28BYJ_48)` | Geared stepper - 28BYJ-48 5V |
| 1 | `geared_stepper(35BYGHJ75)` | Geared stepper - 35BYGHJ75 0.4A |
<a href="#top">Top</a>
@@ -1213,7 +1396,7 @@ IEC mains inlets and outlet.
| 1 | `iec(IEC_inlet)` | IEC inlet |
| 1 | `iec(IEC_inlet_atx)` | IEC inlet for ATX |
| 1 | `iec(IEC_outlet)` | IEC outlet RS 811-7193 |
| 1 | `iec(IEC_switched_fused_inlet)` | IEC320 C14 switched fused inlet module |
| 1 | `iec(IEC_320_C14_switched_fused_inlet)` | IEC320 C14 switched fused inlet module |
| 12 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
| 4 | `screw(M3_cs_cap_screw, 10)` | Screw M3 cs cap x 10mm |
| 8 | `screw(M3_cs_cap_screw, 12)` | Screw M3 cs cap x 12mm |
@@ -1307,58 +1490,6 @@ E.g. a "brown" socket for mains live needs to be displayed as "sienna" to look r
| 1 | `jack_4mm_shielded("brown", 3, "sienna")` | 4mm shielded jack socket brown |
<a href="#top">Top</a>
---
<a name="KP_pillow_blocks"></a>
## KP_pillow_blocks
KP pillow block bearings
[vitamins/kp_pillow_blocks.scad](vitamins/kp_pillow_blocks.scad) Object definitions.
[vitamins/kp_pillow_block.scad](vitamins/kp_pillow_block.scad) Implementation.
[tests/KP_pillow_blocks.scad](tests/KP_pillow_blocks.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `kp_base_height(type)` | Height of base containing the bolts |
| `kp_diameter(type)` | Rod hole diameter |
| `kp_hole_offset(type)` | Rod hole offset |
| `kp_screw_separation(type)` | Separation of bolts in the base |
### Functions
| Function | Description |
|:--- |:--- |
| `kp_size(type)` | Size of bracket |
### Modules
| Module | Description |
|:--- |:--- |
| `kp_pillow_block(type)` | Draw the KP pillow block |
| `kp_pillow_block_assembly(type, part_thickness = 2, screw_type = M5_cap_screw, nut_type = undef)` | Assembly with fasteners in place |
| `kp_pillow_block_hole_positions(type)` | Place children at hole positions |
![kp_pillow_blocks](tests/png/kp_pillow_blocks.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `kp_pillow_block(KP000)` | KP000 pillow block |
| 1 | `kp_pillow_block(KP001)` | KP001 pillow block |
| 1 | `kp_pillow_block(KP08_15)` | KP08_15 pillow block |
| 1 | `kp_pillow_block(KP08_18)` | KP08_18 pillow block |
| 2 | `sliding_t_nut(M4_hammer_nut)` | Nut M4 hammer |
| 2 | `sliding_t_nut(M4_sliding_t_nut)` | Nut M4 sliding T |
| 2 | `sliding_t_nut(M5_sliding_t_nut)` | Nut M5 sliding T |
| 2 | `nut(M5_nut, nyloc = undef)` | Nut M5 x 4mm |
| 4 | `screw(M4_cap_screw, 10)` | Screw M4 cap x 10mm |
| 4 | `screw(M5_cap_screw, 12)` | Screw M5 cap x 12mm |
| 4 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
| 6 | `washer(M5_washer)` | Washer M5 x 10mm x 1mm |
<a href="#top">Top</a>
---
@@ -1421,7 +1552,7 @@ Nuts for leadscrews.
| `leadnut_flange_t(type)` | Flange thickness |
| `leadnut_height(type)` | Total height |
| `leadnut_hole_dia(type)` | The diameter of the screw holes |
| `leadnut_hole_pitch(type)` | The radia pitch of the screw holes |
| `leadnut_hole_pitch(type)` | The radial pitch of the screw holes |
| `leadnut_holes(type)` | The number of screw holes |
| `leadnut_lead(type)` | Screw lead |
| `leadnut_od(type)` | Outer diameter of the shank |
@@ -2006,6 +2137,7 @@ A permanent magnet that can be magnatized and de-magnatized electronically.
| `opengrab_depth()` | Module height |
| `opengrab_pcb()` | The PCB |
| `opengrab_pcb_z()` | PCB offset from the front |
| `opengrab_screw_depth()` | Max screw depth in pillars |
| `opengrab_target_thickness()` | Target sheet thickness |
| `opengrab_width()` | Module width |
@@ -2132,6 +2264,7 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
### Functions
| Function | Description |
|:--- |:--- |
| `pcb_component(type, name, index = 0)` | Return the component specified by name and index |
| `pcb_component_position(type, name, index = 0)` | Return x y position of specified component |
| `pcb_coord(type, p)` | Convert offsets from the edge to coordinates relative to the centre |
| `pcb_grid_pos(type, x, y, z = 0)` | Returns a pcb grid position |
@@ -2268,6 +2401,7 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
### Functions
| Function | Description |
|:--- |:--- |
| `pcb_component(type, name, index = 0)` | Return the component specified by name and index |
| `pcb_component_position(type, name, index = 0)` | Return x y position of specified component |
| `pcb_coord(type, p)` | Convert offsets from the edge to coordinates relative to the centre |
| `pcb_grid_pos(type, x, y, z = 0)` | Returns a pcb grid position |
@@ -2442,6 +2576,58 @@ Threaded pillars. Each end can be male or female.
| 1 | `pillar(M4x17_nylon_pillar)` | Pillar nylon M/F M4x20 |
<a href="#top">Top</a>
---
<a name="Pillow_blocks"></a>
## Pillow_blocks
KP pillow block bearings
[vitamins/pillow_blocks.scad](vitamins/pillow_blocks.scad) Object definitions.
[vitamins/pillow_block.scad](vitamins/pillow_block.scad) Implementation.
[tests/pillow_blocks.scad](tests/pillow_blocks.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `kp_base_height(type)` | Height of base containing the bolts |
| `kp_diameter(type)` | Rod hole diameter |
| `kp_hole_offset(type)` | Rod hole offset |
| `kp_screw_separation(type)` | Separation of bolts in the base |
### Functions
| Function | Description |
|:--- |:--- |
| `kp_size(type)` | Size of bracket |
### Modules
| Module | Description |
|:--- |:--- |
| `kp_pillow_block(type)` | Draw the KP pillow block |
| `kp_pillow_block_assembly(type, part_thickness = 2, screw_type = M5_cap_screw, nut_type = undef)` | Assembly with fasteners in place |
| `kp_pillow_block_hole_positions(type)` | Place children at hole positions |
![pillow_blocks](tests/png/pillow_blocks.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `kp_pillow_block(KP000)` | KP000 pillow block |
| 1 | `kp_pillow_block(KP001)` | KP001 pillow block |
| 1 | `kp_pillow_block(KP08_15)` | KP08_15 pillow block |
| 1 | `kp_pillow_block(KP08_18)` | KP08_18 pillow block |
| 2 | `sliding_t_nut(M4_hammer_nut)` | Nut M4 hammer |
| 2 | `sliding_t_nut(M4_sliding_t_nut)` | Nut M4 sliding T |
| 2 | `sliding_t_nut(M5_sliding_t_nut)` | Nut M5 sliding T |
| 2 | `nut(M5_nut, nyloc = undef)` | Nut M5 x 4mm |
| 4 | `screw(M4_cap_screw, 10)` | Screw M4 cap x 10mm |
| 4 | `screw(M5_cap_screw, 12)` | Screw M5 cap x 12mm |
| 4 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
| 6 | `washer(M5_washer)` | Washer M5 x 10mm x 1mm |
<a href="#top">Top</a>
---
@@ -2550,6 +2736,7 @@ Face order is bottom, top, left, right, front, back.
| Function | Description |
|:--- |:--- |
| `psu_face_transform(type, face)` | Returns a transformation matrix to get to the specified face |
| `psu_size(type)` | Size |
| `terminal_block_length(type, ways)` | Total length of terminal block |
### Modules
@@ -2617,12 +2804,12 @@ Timing belt pulleys, both toothed and plain with internal bearings for idlers.
| `pulley_height(type)` | Total height of pulley |
| `pulley_ir(type)` | Inside radius of the teeth |
| `pulley_offset(type)` | Offset of the belt path centre |
| `pulley_pr(type)` | Pitch radius |
| `pulley_pr(type, belt = undef)` | Pitch radius, `belt` only needed for non-standard belt over smooth pulleys |
### Modules
| Module | Description |
|:--- |:--- |
| `pulley(type, colour = silver)` | Draw a pulley |
| `pulley(type, colour = silver)` | Draw a pulley, any children are placed above. |
| `pulley_assembly(type, colour = silver)` | Draw a pulley with its grub screws in place |
![pulleys](tests/png/pulleys.png)
@@ -2709,26 +2896,35 @@ Linear rails with carriages.
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 2 | `rail(MGN12, 200)` | Linear rail MGN12 x 200mm |
| 1 | `rail(MGN12, 200)` | Linear rail MGN12 x 200mm |
| 1 | `rail(MGN15, 200)` | Linear rail MGN15 x 200mm |
| 1 | `rail(MGN5, 200)` | Linear rail MGN5 x 200mm |
| 1 | `rail(MGN7, 200)` | Linear rail MGN7 x 200mm |
| 1 | `rail(MGN9, 200)` | Linear rail MGN9 x 200mm |
| 1 | `rail(SSR15, 200)` | Linear rail SSR15 x 200mm |
| 1 | `carriage(MGN12C_carriage)` | Linear rail carriage MGN12C |
| 1 | `carriage(MGN12H_carriage)` | Linear rail carriage MGN12H |
| 1 | `carriage(MGN15C_carriage)` | Linear rail carriage MGN15C |
| 1 | `carriage(MGN5C_carriage)` | Linear rail carriage MGN5C |
| 1 | `carriage(MGN7C_carriage)` | Linear rail carriage MGN7C |
| 1 | `carriage(MGN7H_carriage)` | Linear rail carriage MGN7H |
| 1 | `carriage(MGN9C_carriage)` | Linear rail carriage MGN9C |
| 1 | `carriage(MGN9H_carriage)` | Linear rail carriage MGN9H |
| 1 | `carriage(SSR15_carriage)` | Linear rail carriage SSR15 |
| 26 | `nut(M2_nut, nyloc = true)` | Nut M2 x 1.6mm nyloc |
| 31 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
| 23 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
| 4 | `nut(M4_nut, nyloc = true)` | Nut M4 x 3.2mm nyloc |
| 11 | `screw(M2_cap_screw, 10)` | Screw M2 cap x 10mm |
| 15 | `screw(M2_cs_cap_screw, 10)` | Screw M2 cs cap x 10mm |
| 8 | `screw(M3_cap_screw, 10)` | Screw M3 cap x 10mm |
| 12 | `screw(M3_cap_screw, 12)` | Screw M3 cap x 12mm |
| 6 | `screw(M3_cap_screw, 12)` | Screw M3 cap x 12mm |
| 3 | `screw(M3_cap_screw, 16)` | Screw M3 cap x 16mm |
| 2 | `screw(M3_cs_cap_screw, 12)` | Screw M3 cs cap x 12mm |
| 6 | `screw(M3_cs_cap_screw, 16)` | Screw M3 cs cap x 16mm |
| 4 | `screw(M3_cs_cap_screw, 16)` | Screw M3 cs cap x 16mm |
| 2 | `screw(M4_cap_screw, 16)` | Screw M4 cap x 16mm |
| 2 | `screw(M4_cs_cap_screw, 20)` | Screw M4 cs cap x 20mm |
| 26 | `washer(M2_washer)` | Washer M2 x 5mm x 0.3mm |
| 31 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
| 23 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
| 4 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
@@ -2929,7 +3125,7 @@ For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2
| `screw(type, length, hob_point = 0, nylon = false)` | Draw specified screw, optionally hobbed or nylon |
| `screw_and_washer(type, length, star = false, penny = false)` | Screw with a washer which can be standard or penny and an optional star washer on top |
| `screw_countersink(type, drilled = true)` | Countersink shape |
| `screw_polysink(type, h = 100, alt = false)` | A countersink hole made from stacked polyholes for printed parts |
| `screw_polysink(type, h = 100, alt = false, sink = 0)` | A countersink hole made from stacked polyholes for printed parts, default is flush, `sink` can be used to recess the head |
![screws](tests/png/screws.png)
@@ -2961,6 +3157,7 @@ For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2
| 1 | `screw(M5_hex_screw, 30)` | Screw M5 hex x 30mm |
| 1 | `screw(M5_pan_screw, 30)` | Screw M5 pan x 30mm |
| 1 | `screw(M6_cap_screw, 30)` | Screw M6 cap x 30mm |
| 1 | `screw(M6_cs_cap_screw, 30)` | Screw M6 cs cap x 30mm |
| 1 | `screw(M6_hex_screw, 30)` | Screw M6 hex x 30mm |
| 1 | `screw(M6_pan_screw, 30)` | Screw M6 pan x 30mm |
| 1 | `screw(M8_cap_screw, 35)` | Screw M8 cap x 35mm |
@@ -2969,6 +3166,7 @@ For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2
| 1 | `screw(No4_screw, 10)` | Screw No4 pan wood x 10mm |
| 1 | `screw(No6_cs_screw, 30)` | Screw No6 cs wood x 30mm |
| 1 | `screw(No6_screw, 30)` | Screw No6 pan wood x 30mm |
| 1 | `screw(No8_screw, 30)` | Screw No8 pan wood x 30mm |
### Printed
| Qty | Filename |
@@ -2976,68 +3174,6 @@ For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2
| 1 | polysink.stl |
<a href="#top">Top</a>
---
<a name="SCS_bearing_blocks"></a>
## SCS_bearing_blocks
SCSnUU and SCSnLUU bearing blocks
[vitamins/scs_bearing_blocks.scad](vitamins/scs_bearing_blocks.scad) Object definitions.
[vitamins/scs_bearing_block.scad](vitamins/scs_bearing_block.scad) Implementation.
[tests/SCS_bearing_blocks.scad](tests/SCS_bearing_blocks.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `scs_bearing(type)` | Linear bearing used |
| `scs_block_center_height(type)` | Height of the center of the block |
| `scs_block_side_height(type)` | Height of the side of the block, this determines the minimum screw length |
| `scs_circlip(type)` | Circlip used |
| `scs_hole_offset(type)` | Offset of bearing hole from base of block |
| `scs_screw(type)` | Screw type |
| `scs_screw_separation_x(type)` | Screw separation in X direction |
| `scs_screw_separation_z(type)` | Screw separation in Z direction |
| `scs_spacer(type)` | Spacer used in long bearings |
### Functions
| Function | Description |
|:--- |:--- |
| `scs_size(type)` | Size of scs bracket bounding block |
### Modules
| Module | Description |
|:--- |:--- |
| `scs_bearing_block(type)` | Draw the specified SCS bearing block |
| `scs_bearing_block_assembly(type, part_thickness, screw_type, nut_type)` | Assembly with screws and nuts in place |
| `scs_bearing_block_hole_positions(type)` | Place children at hole positions |
![scs_bearing_blocks](tests/png/scs_bearing_blocks.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 12 | `nut(M4_nut)` | Nut M4 x 3.2mm |
| 24 | `nut(M5_nut)` | Nut M5 x 4mm |
| 1 | `scs_bearing_block(SCS10LUU)` | SCS10LUU bearing block |
| 1 | `scs_bearing_block(SCS10UU)` | SCS10UU bearing block |
| 1 | `scs_bearing_block(SCS12LUU)` | SCS12LUU bearing block |
| 1 | `scs_bearing_block(SCS12UU)` | SCS12UU bearing block |
| 1 | `scs_bearing_block(SCS16LUU)` | SCS16LUU bearing block |
| 1 | `scs_bearing_block(SCS16UU)` | SCS16UU bearing block |
| 1 | `scs_bearing_block(SCS6UU)` | SCS6UU bearing block |
| 1 | `scs_bearing_block(SCS8LUU)` | SCS8LUU bearing block |
| 1 | `scs_bearing_block(SCS8UU)` | SCS8UU bearing block |
| 4 | `screw(M4_cap_screw, 25)` | Screw M4 cap x 25mm |
| 8 | `screw(M4_cap_screw, 30)` | Screw M4 cap x 30mm |
| 16 | `screw(M5_cap_screw, 35)` | Screw M5 cap x 35mm |
| 8 | `screw(M5_cap_screw, 45)` | Screw M5 cap x 45mm |
| 12 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
| 24 | `washer(M5_washer)` | Washer M5 x 10mm x 1mm |
<a href="#top">Top</a>
---
@@ -3154,6 +3290,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
| 1 | `sheet(FoilTape, 30, 30, 2)` | Aluminium foil tape 30mm x 30mm x 0.05mm |
| 1 | `sheet(AL6, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 6mm |
| 1 | `sheet(AL8, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 8mm |
| 1 | `sheet(Spring05, 30, 30, 2)` | Bi-metal saw blade 30mm x 30mm x 0.5mm |
| 1 | `sheet(Cardboard, 30, 30, 2)` | Corrugated cardboard 30mm x 30mm x 5mm |
| 1 | `sheet(Foam20, 30, 30, 2)` | Foam sponge 30mm x 30mm x 20mm |
| 1 | `sheet(DiBond, 30, 30, 2)` | Sheet DiBond 30mm x 30mm x 3mm |
@@ -3172,6 +3309,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
| 1 | `sheet(CF3, 30, 30, 2)` | Sheet carbon fiber 30mm x 30mm x 3mm |
| 1 | `sheet(glass2, 30, 30, 2)` | Sheet glass 30mm x 30mm x 2mm |
| 1 | `sheet(Steel06, 30, 30, 2)` | Sheet mild steel 30mm x 30mm x 0.6mm |
| 1 | `sheet(Silicone3, 30, 30, 2)` | Sheet silicone 30mm x 30mm x 3mm |
<a href="#top">Top</a>
@@ -4956,6 +5094,56 @@ The stl must be given a parameterless wrapper in the project that uses it.
| 1 | pcb_mount_PI_IO_5.stl |
<a href="#top">Top</a>
---
<a name="Pocket_handle"></a>
## Pocket_handle
Customisable pocket handle
[printed/pocket_handle.scad](printed/pocket_handle.scad) Implementation.
[tests/pocket_handle.scad](tests/pocket_handle.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `pocket_handle_hand_size(type)` | Size of the hole for the fingers |
| `pocket_handle_panel_t(type)` | Thickness of the panel it is mounted in |
| `pocket_handle_rad(type)` | Min corner rad |
| `pocket_handle_screw(type)` | Screw type, can be countersunk or not |
| `pocket_handle_slant(type)` | Upward slant of the hand hole |
| `pocket_handle_wall(type)` | Wall thickness |
### Functions
| Function | Description |
|:--- |:--- |
| `pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4)` | Construct a pocket_handle property list |
| `pocket_handle_flange(type)` | Size of the flange |
### Modules
| Module | Description |
|:--- |:--- |
| `pocket_handle(type)` | Generate STL for pocket_handle |
| `pocket_handle_assembly(type)` | Assembly with fasteners in place |
| `pocket_handle_hole_positions(type)` | Place children at screw hole positions |
| `pocket_handle_holes(type, h = 0)` | Panel cutout and screw holes |
![pocket_handle](tests/png/pocket_handle.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 4 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
| 4 | `screw(M3_cs_cap_screw, 12)` | Screw M3 cs cap x 12mm |
| 4 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
### Printed
| Qty | Filename |
| ---:|:--- |
| 1 | pocket_handle.stl |
<a href="#top">Top</a>
---
@@ -5520,6 +5708,70 @@ The coordinates of the lowest point on the curve can be retrieved by calling `ca
![catenary](tests/png/catenary.png)
<a href="#top">Top</a>
---
<a name="Core_xy"></a>
## Core_xy
Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
Implementation has the following features:
1. The drive and idler pulleys may be different sizes.
2. The belt separation is parameterised.
3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
allows flexible positioning of the motors.
[utils/core_xy.scad](utils/core_xy.scad) Implementation.
[tests/core_xy.scad](tests/core_xy.scad) Code for this example.
### Properties
| Function | Description |
|:--- |:--- |
| `coreXY_belt(type)` | Belt type |
| `coreXY_drive_pulley(type)` | Drive pulley type |
| `coreXY_lower_belt_colour(type)` | Colour of the lower belt |
| `coreXY_lower_tooth_colour(type)` | Colour of the lower belt's teeth |
| `coreXY_plain_idler(type)` | Plain idler type |
| `coreXY_toothed_idler(type)` | Toothed idler type |
| `coreXY_upper_belt_colour(type)` | Colour of the upper belt |
| `coreXY_upper_tooth_colour(type)` | Colour of the upper belt's teeth |
### Functions
| Function | Description |
|:--- |:--- |
| `coreXY_coincident_separation(type)` | Value of x, y separation to make y-carriage pulleys coincident |
| `coreXY_drive_plain_idler_offset(type)` | Offset of plain drive idler pulley |
| `coreXY_drive_pulley_x_alignment(type)` | Belt alignment offset of the drive pulley relative to the anchor pulley |
| `coreXY_drive_toothed_idler_offset(type)` | Offset of toothed drive idler pulley |
| `coreXY_plain_idler_offset(type)` | Offset of y-carriage plain idler |
| `coreXY_toothed_idler_offset(type)` | offset of y-carriage toothed idler |
### Modules
| Module | Description |
|:--- |:--- |
| `coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false, left_lower = false)` | Wrapper module to draw both belts of a coreXY setup |
| `coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false, left_lower = false)` | Draw the coreXY belts |
| `coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false)` | Draw one belt of a coreXY setup |
![core_xy](tests/png/core_xy.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | `belt(GT2x6, [ ... ])` | Belt GT2 x 6mm x 728mm |
| 1 | `belt(GT2x6, [ ... ])` | Belt GT2 x 6mm x 824mm |
| 7 | `pulley(GT2x16_toothed_idler)` | Pulley GT2 idler 16 teeth |
| 3 | `pulley(GT2x16_plain_idler)` | Pulley GT2 idler smooth 9.63mm |
| 2 | `pulley(GT2x20ob_pulley)` | Pulley GT2OB 20 teeth |
| 8 | `screw(M3_cap_screw, 20)` | Screw M3 cap x 20mm |
| 4 | `screw(M3_grub_screw, 6)` | Screw M3 grub x 6mm |
| 2 | `NEMA(NEMA17M)` | Stepper motor NEMA17 x 40mm |
<a href="#top">Top</a>
---
@@ -5702,12 +5954,17 @@ Maths utilities for manipulating vectors and matrices.
| `circle_intersect(c1, r1, c2, r2)` | Calculate one point where two circles in the X-Z plane intersect, clockwise around c1 |
| `cosh(x)` | hyperbolic cosine |
| `coth(x)` | hyperbolic cotangent |
| `cubic_real_roots(a, b, c, d)` | Returns real roots of cubic equation |
| `degrees(radians)` | Convert degrees to radians |
| `euler(R)` | Convert a rotation matrix to a Euler rotation vector. |
| `identity(n, x = 1)` | Construct an arbitrary size identity matrix |
| `invert(m)` | Invert a matrix |
| `map(v, func)` | make a new vector where the func function argument is applied to each element of the vector v |
| `mapi(v, func)` | make a new vector where the func function argument is applied to each element of the vector v. The func will get the index number as first argument, and the element as second argument. |
| `nearly_zero(x)` | True if x is close to zero |
| `quadratic_real_roots(a, b, c)` | Returns real roots of a quadratic equation, biggest first. Returns empty list if no real roots |
| `radians(degrees)` | Convert radians to degrees |
| `reduce(v, func, unity)` | reduce a vector v to a single entity by applying the func function recursively to the reduced value so far and the next element, starting with unity as the initial reduced value |
| `reverse(v)` | Reverse a vector |
| `rot2_z(a)` | Generate a 2x2 matrix to rotate around z |
| `rot3_z(a)` | Generate a 3x3 matrix to rotate around z |
@@ -5718,14 +5975,17 @@ Maths utilities for manipulating vectors and matrices.
| `solve(m, i = 0, j = 0)` | Solve each row ensuring diagonal is not zero |
| `solve_row(m, i)` | Make diagonal one by dividing the row by it and subtract from other rows to make column zero |
| `sqr(x)` | Square x |
| `sumv(v)` | sum a vector of values that can be added with "+" |
| `tanh(x)` | hyperbolic tangent |
| `transform(v, m)` | Apply 4x4 transform to a 3 vector by extending it and cropping it again |
| `transform_points(path, m)` | Apply transform to a path |
| `translate(v)` | Generate a 4x4 translation matrix, `v` can be `[x, y]`, `[x, y, z]` or `z` |
| `transpose(m)` | Transpose an arbitrary size matrix |
| `unit(v)` | Convert `v` to a unit vector |
| `vec2(v)` | Return a 2 vector with the first two elements of `v` |
| `vec3(v)` | Return a 3 vector with the first three elements of `v` |
| `vec4(v)` | Return a 4 vector with the first three elements of `v` |
| `xor(a,b)` | Logical exclusive OR |
### Modules
| Module | Description |
@@ -5839,8 +6099,9 @@ Because the tangents need to be calculated to find the length these can be calcu
| Function | Description |
|:--- |:--- |
| `circle_tangent(p1, p2)` | Compute the clockwise tangent between two circles represented as [x,y,r] |
| `rounded_polygon_arcs(points, tangents)` | Compute the arcs at the points, for each point [angle, rotate_angle, length] |
| `rounded_polygon_length(points, tangents)` | Calculate the length given the point list and the list of tangents computed by ` rounded_polygon_tangents` |
| `rounded_polygon_tangents(points)` | Compute the straight sections needed to draw and to compute the lengths |
| `rounded_polygon_tangents(points)` | Compute the straight sections between a point and the next point, for each section [start_point, end_point, length] |
### Modules
| Module | Description |
@@ -5853,20 +6114,20 @@ Because the tangents need to be calculated to find the length these can be calcu
<a href="#top">Top</a>
---
<a name="Rounded_right_triangle"></a>
## Rounded_right_triangle
<a name="Rounded_triangle"></a>
## Rounded_triangle
Draw a 3D right triangle with rounded edges. Intended to be embedded in other parts. Can be optionally offset by the filleted amount.
[utils/rounded_right_triangle.scad](utils/rounded_right_triangle.scad) Implementation.
[utils/rounded_triangle.scad](utils/rounded_triangle.scad) Implementation.
[tests/rounded_right_triangle.scad](tests/rounded_right_triangle.scad) Code for this example.
[tests/rounded_triangle.scad](tests/rounded_triangle.scad) Code for this example.
### Modules
| Module | Description |
|:--- |:--- |
| `rounded_right_triangle(x, y, z, fillet, center = true, offset = false)` | Draw a 3D right triangle with rounded edges. |
![rounded_right_triangle](tests/png/rounded_right_triangle.png)
![rounded_triangle](tests/png/rounded_triangle.png)
<a href="#top">Top</a>
@@ -6016,6 +6277,13 @@ If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` modu
it with code.
This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
* Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
* If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
* To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
* Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
[utils/core/bom.scad](utils/core/bom.scad) Implementation.
[tests/BOM.scad](tests/BOM.scad) Code for this example.
@@ -6039,7 +6307,7 @@ This can speed up the generation of the build instructions greatly but isn't com
| `no_explode()` | Prevent children being exploded |
| `no_pose()` | Force children not to be posed even if parent is |
| `not_on_bom(on = false)` | Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled |
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only. |
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only. |
| `pose_hflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
| `pose_vflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the X axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
| `stl(name)` | Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it |
@@ -6173,18 +6441,18 @@ leaving a scar on either surface.
### Functions
| Function | Description |
|:--- |:--- |
| `corrected_diameter(d, n = 0)` | Adjusted diameter to make flats lie on the circle |
| `corrected_radius(r, n = 0)` | Adjusted radius to make flats lie on the circle |
| `sides(r)` | Optimium number of sides for specified radius |
| `corrected_diameter(d, n = undef)` | Adjusted diameter to make flats lie on the circle |
| `corrected_radius(r, n = undef)` | Adjusted radius to make flats lie on the circle |
| `sides(r, n = undef)` | Optimium number of sides for specified radius |
### Modules
| Module | Description |
|:--- |:--- |
| `drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle |
| `poly_circle(r, sides = 0)` | Make a circle adjusted to print the correct size |
| `poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
| `poly_circle(r, sides = undef)` | Make a circle adjusted to print the correct size |
| `poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
| `poly_drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing if cnc_bit_r is non zero, otherwise a poly_cylinder. |
| `poly_ring(or, ir, sides = 0)` | Make a 2D ring adjusted to have the correct internal radius |
| `poly_ring(or, ir, sides = undef)` | Make a 2D ring adjusted to have the correct internal radius |
| `poly_tube(or, ir, h, center = false)` | Make a tube adjusted to have the correct internal radius |
| `slot(r, l, h = 100)` | Make a horizontal slot suitable for CNC routing, set h = 0 for 2D version |

View File

@@ -61,6 +61,7 @@ class BOM:
self.name = name
self.big = None
self.ngb = False
self.zoomed = 0
self.count = 1
self.vitamins = {}
self.printed = {}
@@ -75,6 +76,7 @@ class BOM:
"name" : self.name,
"big" : self.big,
"ngb" : self.ngb,
"zoomed" : self.zoomed,
"count" : self.count,
"assemblies" : assemblies,
"vitamins" : {v : self.vitamins[v].data() for v in self.vitamins},

164
scripts/changelog.py Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2021
# nop.head@gmail.com
# hydraraptor.blogspot.com
#
# This file is part of NopSCADlib.
#
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Creates the changelog from the git log
from __future__ import print_function
import sys
import subprocess
import re
filename = 'CHANGELOG.md'
def tag_version(t):
""" Format a version tag """
return 'v%d.%d.%d' % t
def initials(name):
""" Convert full name to initials with a tooltip """
i = ''.join([n[0].upper() + '.' for n in name.split(' ')])
return '[%s](# "%s")' % (i, name)
def get_remote_url():
""" Get the git remote URL for the repository """
url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"]).decode("utf-8").strip("\n")
if url.startswith("git@"):
url = url.replace(":", "/", 1).replace("git@", "https://", 1)
if url.endswith(".git"):
url = url[:-4]
return url
def iscode(word):
""" try to guess if the word is code """
endings = ['()', '*']
starts = ['$', '--']
anywhere = ['.', '_', '=', '[', '/']
words = ['center', 'false', 'true', 'ngb']
for w in words:
if word == w:
return True
for end in endings:
if word.endswith(end):
return True
for start in starts:
if word.startswith(start):
return True
for any in anywhere:
if word.find(any) >= 0:
return True
return False
def codify(word, url):
""" if a word is deemed code enclose it backticks """
if word:
if re.match(r'#[0-9]+', word):
return '[%s](%s "show issue")' % (word, url + '/issues/' + word[1:])
if iscode(word):
return '`' + word + '`'
return word
def fixup_comment(comment, url):
""" markup code words and fix new paragraphs """
result = ''
word = ''
code = False
for i, c in enumerate(comment):
if c == '`' or code: # Already a code block
result += c # Copy verbatim
if c == '`': code = not code # Keep track of state
else:
if c in ' \n' or (c == '.' and (i + 1 == len(comment) or comment[i + 1] in ' \n')): # if a word terminator
result += codify(word, url) + c # Add codified word before terminator
word = ''
else:
word += c # Accumulate next word
result += codify(word, url) # In case comment ends without a terminator
return result.replace('\n\n','\n\n * ') # Give new paragraphs a bullet point
class Commit(): # members dynamically added from commit_fields
pass
blurb = """
# %s Changelog
This changelog is generated by `changelog.py` using manually added semantic version tags to classify commits as breaking changes, additions or fixes.
"""
if __name__ == '__main__':
url = get_remote_url()
commit_fields = {
'hash': "%H|", # commit commit_hash
'tag': "%D|", # tag
'author': "%aN|", # author name
'date': " %as|", # author date short form
'comment': "%B~" # body
}
# Produce the git log
format = ''.join([v for k, v in commit_fields.items()])
text = subprocess.check_output(["git", "log", "--topo-order", "--format=" + format]).decode("utf-8")
# Process the log into a list of Commit objects
commits = []
for line in text.split('~'):
line = line.strip('\n')
if line:
fields = line.split('|')
commit = Commit()
for i, k in enumerate(commit_fields):
exec('commit.%s = """%s"""' % (k, fields[i]), locals())
# Convert version tag to tuple
if commit.tag:
match = re.match(r'.*tag: v([0-9]+)\.([0-9]+)\.([0-9]+).*', commit.tag)
commit.tag = (int(match.group(1)), int(match.group(2)), int(match.group(3))) if match else ''
commits.append(commit)
# Format the results from the Commit objects
with open(filename, "wt") as file:
print(blurb % url.split('/')[-1], file = file)
for i, c in enumerate(commits):
if c.tag:
ver = tag_version(c.tag)
level, type = (3, 'Fixes') if c.tag[2] else (2, 'Additions') if c.tag[1] else (1, 'Breaking Changes') if c.tag[0] else (1, 'First publicised version')
# Find the previous tagged commit
j = i + 1
diff = ''
while j < len(commits):
if commits[j].tag:
last_ver = tag_version(commits[j].tag)
diff = '[...](%s "diff with %s")' % (url + '/compare/' + last_ver + '...' + ver, last_ver)
break
j += 1
# Print verson info
print('%s [%s](%s "show release") %s %s' % ('#' * (level + 1), ver, url + '/releases/tag/' + ver, type, diff), file = file)
# Print commits excluding merges
if not c.comment.startswith('Merge branch') and not c.comment.startswith('Merge pull') and not re.match(r'U..ated changelog.*', c.comment):
print('* %s [`%s`](%s "show commit") %s %s\n' % (c.date, c.hash[:7], url + '/commit/' + c.hash, initials(c.author), fixup_comment(c.comment, url)), file = file)

View File

@@ -18,6 +18,7 @@
#
import os
from set_config import source_dir
from colorama import Fore
def mtime(file):
if os.path.isfile(file):
@@ -41,13 +42,13 @@ def read_deps(dname):
def check_deps(target, dname):
target_mtime = mtime(target)
if not target_mtime:
return target + " missing"
return Fore.CYAN + target + " missing" + Fore.WHITE
if not os.path.isfile(dname):
return "no deps"
return Fore.CYAN + "no deps" + Fore.WHITE
deps = read_deps(dname)
for dep in deps:
if mtime(dep) > target_mtime:
return dep + ' changed'
return Fore.CYAN + dep + ' changed' + Fore.WHITE
return None
def source_dirs(bom_dir):

View File

@@ -28,7 +28,10 @@ from set_config import *
import time
import times
from deps import *
from tmpdir import *
import json
import shutil
from colorama import Fore, init
def bom_to_parts(bom_dir, part_type, assembly = None):
#
@@ -43,7 +46,7 @@ def bom_to_parts(bom_dir, part_type, assembly = None):
if words:
last_word = words[-1]
if last_word.endswith(suffix):
part_files.append(last_word[:-4] + '.' + part_type)
part_files.append(last_word[:-4] + '.' + part_type)
return part_files
def usage(t):
@@ -62,12 +65,20 @@ def make_parts(target, part_type, parts = None):
#
top_dir = set_config(target, lambda: usage(part_type))
target_dir = top_dir + part_type + 's'
deps_dir = top_dir + "deps"
deps_dir = target_dir + "/deps"
bom_dir = top_dir + "bom"
tmp_dir = mktmpdir(top_dir)
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
if not os.path.isdir(deps_dir):
os.makedirs(deps_dir)
old_deps = top_dir + 'deps' #old location
if os.path.isdir(old_deps):
shutil.rmtree(old_deps)
times.read_times(target_dir)
#
# Decide which files to make
@@ -120,18 +131,18 @@ def make_parts(target, part_type, parts = None):
changed = check_deps(part_file, dname)
changed = times.check_have_time(changed, part)
if part_type == 'stl' and not changed and not part in bounds_map:
changed = "No bounds"
changed = Fore.CYAN + "No bounds" + Fore.WHITE
if changed:
print(changed)
#
# make a file to use the module
#
part_maker_name = part_type + ".scad"
part_maker_name = tmp_dir + '/' + part_type + ".scad"
with open(part_maker_name, "w") as f:
f.write("use <%s/%s>\n" % (dir, filename))
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
f.write("%s();\n" % module);
t = time.time()
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
openscad.run("-o", part_file, part_maker_name, "-D$bom=1", "-d", dname)
times.add_time(part, t)
if part_type == 'stl':
bounds = c14n_stl.canonicalise(part_file)
@@ -145,6 +156,10 @@ def make_parts(target, part_type, parts = None):
with open(bounds_fname, 'w') as outfile:
json.dump(bounds_map, outfile, indent = 4)
#
# Remove tmp dir
#
rmtmpdir(tmp_dir)
#
# List the ones we didn't find
#
if targets:

View File

@@ -68,9 +68,10 @@ def gallery(force):
match = re.match(r"^(#+).*$", line)
if match:
line = '#' + line
if line == '---\n':
break;
print(line[:-1], file = output_file)
if line == '---\n' or line == '<span></span>\n':
break
if line != '<a name="TOP"></a>\n':
print(line[:-1], file = output_file)
else:
print(Fore.MAGENTA + "Can't find", document, Fore.WHITE);
with open(target_dir + "/readme.html", "wt") as html_file:

View File

@@ -25,19 +25,25 @@ from __future__ import print_function
import subprocess, sys
def run_list(args, silent = False, verbose = False):
cmd = ["openscad", "--hardwarnings"] + args
cmd = ["openscad"] + args + ["--hardwarnings"]
if not silent:
for arg in cmd:
print(arg, end=" ")
print()
with open("openscad.log", "w") as log:
rc = subprocess.call(cmd, stdout = log, stderr = log)
for line in open("openscad.log", "rt"):
log_file = "openscad.echo" if "openscad.echo" in cmd else "openscad.log"
bad = False
for line in open(log_file, "rt"):
if verbose or 'ERROR:' in line or 'WARNING:' in line:
bad = True
print(line[:-1])
if rc:
sys.exit(rc)
if bad:
sys.exit(1)
def run(*args):
run_list(list(args), False)

View File

@@ -20,6 +20,7 @@
# Set command line options from enviroment variables and check if they have changed
import json, os, deps
from colorama import Fore, init
def check_options(dir = '.'):
global options, options_mtime
@@ -37,7 +38,7 @@ def check_options(dir = '.'):
def have_changed(changed, target):
if not changed and deps.mtime(target) < options_mtime:
return "command line options changed"
return Fore.CYAN + "command line options changed" + Fore.WHITE
return changed
def list():

View File

@@ -26,8 +26,10 @@ import sys
import c14n_stl
from set_config import *
from deps import *
from shutil import copyfile
import shutil
import re
import time
import times
source_dirs = { "stl" : "platters", "dxf" : "panels" }
target_dirs = { "stl" : "printed", "dxf" : "routed" }
@@ -41,22 +43,32 @@ def plateup(target, part_type, usage = None):
target_dir = parts_dir + '/' + target_dirs[part_type]
source_dir1 = source_dirs[part_type]
source_dir2 = top_dir + source_dirs[part_type]
#
# Loop through source directories
#
used = []
all_used = []
all_sources = []
all_parts = []
read_times = False
for dir in [source_dir1, source_dir2]:
if not os.path.isdir(dir):
continue
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
if not read_times:
times.read_times(target_dir)
read_times = True
#
# Make the deps dir
#
deps_dir = dir + "/deps"
deps_dir = parts_dir + "/deps"
if not os.path.isdir(deps_dir):
os.makedirs(deps_dir)
if os.path.isdir(dir + '/deps'): #old deps
shutil.rmtree(dir + '/deps')
#
# Decide which files to make
#
@@ -65,42 +77,55 @@ def plateup(target, part_type, usage = None):
#
# Run OpenSCAD on the source files to make the targets
#
target_def = ['-D$target="%s"' % target] if target else []
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
for src in sources:
src_file = dir + '/' + src
part_file = target_dir + '/' + src[:-4] + part_type
part = src[:-4] + part_type
all_parts.append(part)
part_file = target_dir + '/' + part
uses_file = deps_dir + '/' + src[:-4] + 'txt'
dname = deps_name(deps_dir, src)
changed = check_deps(part_file, dname)
oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
changed = check_deps(oldest, dname)
used = []
if changed:
print(changed)
target_def = ['-D$target="%s"' % target] if target else []
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
t = time.time()
openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
if part_type == 'stl':
c14n_stl.canonicalise(part_file)
times.add_time(part, t)
log_name = 'openscad.log'
#
# Add the files on the BOM to the used list
#
with open(log_name) as file:
for line in file.readlines():
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
if match:
used.append(match.group(1))
with open(uses_file, "wt") as file:
for part in used:
print(part, file = file)
else:
log_name = 'openscad.echo'
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
#
# Add the files on the BOM to the used list
#
with open(log_name) as file:
for line in file.readlines():
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
if match:
used.append(match.group(1))
with open(uses_file, "rt") as file:
for line in file:
used.append(line[:-1])
all_used += used
copied = []
if all_sources:
#
# Copy files that are not included
#
for file in os.listdir(parts_dir):
if file.endswith('.' + part_type) and not file in used:
if file.endswith('.' + part_type) and not file in all_used:
src = parts_dir + '/' + file
dst = target_dir + '/' + file
if mtime(src) > mtime(dst):
print("Copying %s to %s" % (src, dst))
copyfile(src, dst)
shutil.copyfile(src, dst)
copied.append(file)
#
# Remove any cruft
@@ -111,3 +136,12 @@ def plateup(target, part_type, usage = None):
if not file in targets and not file in copied:
print("Removing %s" % file)
os.remove(target_dir + '/' + file)
targets = [file[:-4] + 'txt' for file in all_sources]
for file in os.listdir(deps_dir):
if file.endswith('.' + 'txt'):
if not file in targets:
print("Removing %s" % file)
os.remove(deps_dir + '/' + file)
times.print_times(all_parts)

View File

@@ -8,6 +8,7 @@ They should work with both Python 2 and Python 3.
|:---|:---|
| `bom.py` | Generates BOM files for the project. |
| `c14n_stl.py` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
| `changelog.py` | Creates the changelog from the git log |
| `doc_scripts.py` | Makes this document and doc/usage.md. |
| `dxfs.py` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
| `gallery.py` | Finds projects and adds them to the gallery. |

View File

@@ -30,6 +30,7 @@ from tests import do_cmd, update_image, colour_scheme, background
from deps import mtime
from colorama import init
import json
from tmpdir import *
def usage():
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
@@ -40,6 +41,7 @@ def render(target, type):
# Make the target directory
#
top_dir = set_config(target, usage)
tmp_dir = mktmpdir(top_dir)
target_dir = top_dir + type + 's'
bom_dir = top_dir + 'bom'
if not os.path.isdir(target_dir):
@@ -80,7 +82,7 @@ def render(target, type):
# make a file to import the stl
#
if mtime(part_file) > mtime(png_name):
png_maker_name = "png.scad"
png_maker_name = tmp_dir + "/png.scad"
pp1 = [0, 146/255, 0]
colour = pp1
if part in colours:
@@ -88,15 +90,19 @@ def render(target, type):
if not '[' in colour:
colour = '"' + colour + '"'
with open(png_maker_name, "w") as f:
f.write('color(%s) import("%s");\n' % (colour, part_file))
f.write('color(%s) import("%s");\n' % (colour, reltmp(part_file, target)))
cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500"
render = "--preview" if type == 'stl' or colour != pp1 else "--render"
tmp_name = 'tmp.png'
openscad.run(colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", tmp_name, png_maker_name);
tmp_name = tmp_dir + '/' + part[:-4] + '.png'
openscad.run("-o", tmp_name, png_maker_name, colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall");
do_cmd(("magick "+ tmp_name + " -trim -resize 280x280 -background %s -gravity Center -extent 280x280 -bordercolor %s -border 10 %s"
% (background, background, tmp_name)).split())
update_image(tmp_name, png_name)
os.remove(png_maker_name)
#
# Remove tmp dir
#
rmtmpdir(tmp_dir)
if __name__ == '__main__':
init()

View File

@@ -69,17 +69,22 @@ def set_config(target, usage = None):
sys.exit(1)
fname = source_dir + "/target.scad"
text = "include <config_%s.scad>\n" % target;
line = ""
text = ['include <config_%s.scad>\n' % target,
'$target = "%s";\n' % target,
'$cwd="%s";\n' % os.getcwd().replace('\\', '/')
]
lines = [""]
try:
with open(fname,"rt") as f:
line = f.read()
lines = f.readlines()
except:
pass
if line != text:
if lines != text:
with open(fname,"wt") as f:
f. write(text);
for t in text:
f. write(t);
return target + "/"
def usage():

View File

@@ -34,6 +34,7 @@ import shutil
from deps import *
from blurb import *
from colorama import Fore
from tmpdir import *
w = 4096
h = w
@@ -59,7 +60,8 @@ def compare_images(a, b, c):
with open(log_name, 'w') as output:
do_cmd(("magick compare -metric AE -fuzz %d%% %s %s %s" % (fuzz, a, b, c)).split(), output = output)
with open(log_name, 'r') as f:
pixels = int(float(f.read().strip()))
pixels = f.read().strip()
pixels = int(float(pixels if pixels.isnumeric() else -1))
os.remove(log_name)
return pixels
@@ -94,6 +96,7 @@ def usage():
def tests(tests):
scad_dir = "tests"
tmp_dir = mktmpdir(scad_dir + '/')
deps_dir = scad_dir + "/deps"
png_dir = scad_dir + "/png"
bom_dir = scad_dir + "/bom"
@@ -114,7 +117,7 @@ def tests(tests):
libtest = True
lib_blurb = scrape_blurb(scad_name)
if not os.path.isfile(png_name):
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
openscad.run(scad_name, "-o", png_name, colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall");
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
else:
#
@@ -170,7 +173,7 @@ def tests(tests):
impl_name = None
if libtest:
vsplit = "AJR" + chr(ord('Z') + 1)
vsplit = "AIR" + chr(ord('Z') + 1)
vtype = locations[0][1]
types = [vtype + ' ' + vsplit[i] + '-' + chr(ord(vsplit[i + 1]) - 1) for i in range(len(vsplit) - 1)] + [loc[1] for loc in locations[1 :]]
if type == vtype:
@@ -234,8 +237,8 @@ def tests(tests):
if changed:
print(changed)
t = time.time()
tmp_name = 'tmp.png'
openscad.run_list(options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, scad_name]);
tmp_name = tmp_dir + '/tmp.png'
openscad.run_list([scad_name, "-o", tmp_name] + options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname]);
times.add_time(scad_name, t)
do_cmd(["magick", tmp_name, "-trim", "-resize", "1000x600", "-bordercolor", background, "-border", "10", tmp_name])
update_image(tmp_name, png_name)
@@ -303,6 +306,11 @@ def tests(tests):
with open(doc_base_name + ".html", "wt") as html_file:
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
times.print_times()
#
# Remove tmp dir
#
rmtmpdir(tmp_dir)
do_cmd(('codespell -L od ' + doc_name).split())
if __name__ == '__main__':

View File

@@ -44,7 +44,7 @@ def got_time(name):
def check_have_time(changed, name):
if not changed and not got_time(name):
changed = "no previous time"
changed = Fore.CYAN + "no previous time" + Fore.WHITE
return changed
def add_time(name, start):

40
scripts/tmpdir.py Normal file
View File

@@ -0,0 +1,40 @@
#
# NopSCADlib Copyright Chris Palmer 2021
# nop.head@gmail.com
# hydraraptor.blogspot.com
#
# This file is part of NopSCADlib.
#
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
"""
Make a directory for tmp files.
"""
import os
import time
def mktmpdir(top_dir):
tmp_dir = top_dir + 'tmp'
if not os.path.isdir(tmp_dir):
os.makedirs(tmp_dir)
else:
for file in os.listdir(tmp_dir):
os.remove(tmp_dir + '/' + file)
return tmp_dir
def reltmp(dir, target):
return dir if os.path.isabs(dir) else '../../' + dir if target else '../' + dir
def rmtmpdir(tmp_dir):
os.rmdir(tmp_dir)
while os.path.isdir(tmp_dir):
time.sleep(0.1)

View File

@@ -38,6 +38,7 @@ import shutil
import re
import copy
from colorama import Fore
from tmpdir import *
def is_assembly(s):
return s[-9:] == '_assembly' or s[-11:] == '_assemblies'
@@ -129,8 +130,9 @@ def views(target, do_assemblies = None):
# Make the target directory
#
top_dir = set_config(target, usage)
tmp_dir = mktmpdir(top_dir)
target_dir = top_dir + 'assemblies'
deps_dir = top_dir + "deps"
deps_dir = target_dir + "/deps"
bom_dir = top_dir + "bom"
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
@@ -183,6 +185,7 @@ def views(target, do_assemblies = None):
#
for ass in flat_bom:
if ass["name"] == real_name:
zoomed = ass['zoomed']
if not "blurb" in ass:
ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no])
break
@@ -204,20 +207,21 @@ def views(target, do_assemblies = None):
changed = check_deps(png_name, dname)
changed = times.check_have_time(changed, png_name)
changed = options.have_changed(changed, png_name)
tmp_name = 'tmp.png'
tmp_name = tmp_dir + '/' + real_name + '.png'
if changed:
print(changed)
#
# make a file to use the module
#
png_maker_name = 'png.scad'
png_maker_name = tmp_dir + '/png.scad'
with open(png_maker_name, "w") as f:
f.write("use <%s/%s>\n" % (dir, filename))
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
f.write("%s();\n" % module);
t = time.time()
target_def = ['-D$target="%s"' % target] if target else []
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
openscad.run_list(options.list() + target_def + cwd_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name]);
view_def = ['--viewall', '--autocenter'] if not (zoomed & (1 << explode)) else ['--camera=0,0,0,55,0,25,140']
openscad.run_list(["-o", tmp_name, png_maker_name] + options.list() + target_def + cwd_def + view_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "-d", dname]);
times.add_time(png_name, t)
do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name])
update_image(tmp_name, png_name)
@@ -439,6 +443,10 @@ def views(target, do_assemblies = None):
dst.write(line)
i += 1
#
# Remove tmp dir
#
rmtmpdir(tmp_dir)
#
# Spell check
#
do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())

31
tests/BLDC_motors.scad Normal file
View File

@@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../utils/layout.scad>
include <../vitamins/bldc_motors.scad>
module bldc_motors()
layout([for(b = bldc_motors) BLDC_diameter(b)])
rotate(-90)
BLDC(bldc_motors[$i]);
if($preview)
let($show_threads = 1)
bldc_motors();

View File

@@ -20,10 +20,10 @@
//
//! BOM and assembly demonstration
//
$explode = 1; // Normally set on the command line when generating assembly views with views.py
include <../core.scad>
include <../vitamins/sheets.scad>
use <../vitamins/insert.scad>
$explode = 1; // Normally set on the command line when generating assembly views with views.py
screw = M3_cap_screw;
sheet = PMMA3;

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/ldrs.scad>
use <../utils/layout.scad>

View File

@@ -29,7 +29,7 @@ module pcbs() {
rotate(90)
pcb_assembly(pcbs[$i], 5 + $i, 3);
translate([0, 120])
translate([0, 110])
layout([for(p = perfboards) pcb_length(p)], 10)
translate([0, -pcb_width(perfboards[$i]) / 2])
pcb_assembly(perfboards[$i], 5 + $i, 3);

View File

@@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../utils/layout.scad>
include <../vitamins/ball_bearings.scad>

View File

@@ -17,7 +17,7 @@
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/scs_bearing_blocks.scad>
include <../vitamins/bearing_blocks.scad>
use <../utils/layout.scad>

View File

@@ -25,9 +25,9 @@ use <../utils/layout.scad>
module belt_test() {
p2 = [-75, -50];
p3 = [-75, 100];
p4 = [75, 100];
p4 = [ 75, 100];
p5 = [75 + pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), +pulley_pr(GT2x16_plain_idler)];
p5 = [ 75 + pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), +pulley_pr(GT2x16_plain_idler)];
p6 = [-75 + pulley_pr(GT2x20ob_pulley) + pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)];
module pulleys(flip = false) {
@@ -52,19 +52,21 @@ module belt_test() {
translate(p6) pulley_assembly(GT2x16_plain_idler);
}
path = [ [p5.x, p5.y, pulley_pr(GT2x16_plain_idler)],
path = [ [-40, 0, 0],
[p6.x, p6.y, -pulley_pr(GT2x16_plain_idler)],
[p2.x, p2.y, pulley_pr(GT2x20ob_pulley)],
[p3.x, p3.y, pulley_pr(GT2x20ob_pulley)],
[p4.x, p4.y, pulley_pr(GT2x20ob_pulley)]
[p4.x, p4.y, pulley_pr(GT2x20ob_pulley)],
[p5.x, p5.y, pulley_pr(GT2x16_plain_idler)],
[40, 0, 0],
];
belt = GT2x6;
belt(belt, path, 80, [0, 0]);
belt(belt, path, open = true);
pulleys();
translate_z(20)
hflip() {
belt(belt, path, 80, [0, 0], belt_colour = grey(90), tooth_colour = grey(50));
belt(belt, path, open = true, belt_colour = grey(90), tooth_colour = grey(50));
pulleys(flip=true);
}
@@ -72,6 +74,31 @@ module belt_test() {
layout([for(b = belts) belt_width(b)], 10)
rotate([0, 90, 0])
belt(belts[$i], [[0, 0, 20], [0, 1, 20]], belt_colour = $i%2==0 ? grey(90) : grey(20), tooth_colour = $i%2==0 ? grey(70) : grey(50));
// new example with open loop - this is a simplified example of the style used for example for the BLV 3D printer
pulley = GT2x20ob_pulley;
idler = GT2x16_plain_idler;
corners = [[-75,-50],[75,100]];
carriagepos = [0,0];
carriagew = 80;
points = [
[carriagepos.x - carriagew / 2, carriagepos.y, 0],
[corners[0].x + belt_pulley_pr(belt, pulley) + belt_pulley_pr(belt, idler), carriagepos.y - belt_pulley_pr(belt, idler), idler],
[corners[0].x, corners[0].y, pulley],
[corners[0].x, corners[1].y, idler],
[corners[1].x, corners[1].y, idler],
[corners[1].x, carriagepos.y + belt_pulley_pr(belt, idler), idler],
[carriagepos.x + carriagew / 2, carriagepos.y, 0]
];
translate_z(-30) {
belt(belt, points, open=true, auto_twist=true);
for (p = points)
if (is_list(p.z))
translate([p.x, p.y, 0])
pulley_assembly(p.z);
}
}
if($preview)

30
tests/box_sections.scad Normal file
View File

@@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../utils/core/core.scad>
use <../utils/layout.scad>
include <../vitamins/box_sections.scad>
module box_sections() {
layout([for(b = box_sections) box_section_size(b).x], 20)
box_section(box_sections[$i], 100);
}
if($preview)
box_sections();

134
tests/core_xy.scad Normal file
View File

@@ -0,0 +1,134 @@
//
// NopSCADlib Copyright Chris Palmer 2020
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/pulleys.scad>
include <../vitamins/screws.scad>
include <../vitamins/stepper_motors.scad>
include <../vitamins/washers.scad>
include <../utils/core_xy.scad>
module coreXY_belts_test() {
coreXY_type = coreXY_GT2_20_16;
plain_idler = coreXY_plain_idler(coreXY_type);
toothed_idler = coreXY_toothed_idler(coreXY_type);
coreXYPosBL = [0, 0, 0];
coreXYPosTR = [200, 150, 0];
separation = [0, coreXY_coincident_separation(coreXY_type).y, pulley_height(plain_idler) + washer_thickness(M3_washer)];
pos = [100, 50];
upper_drive_pulley_offset = [40, 10];
lower_drive_pulley_offset = [0, 0];
coreXY_belts(coreXY_type,
carriagePosition = pos,
coreXYPosBL = coreXYPosBL,
coreXYPosTR = coreXYPosTR,
separation = separation,
x_gap = 10,
upper_drive_pulley_offset = upper_drive_pulley_offset,
lower_drive_pulley_offset = lower_drive_pulley_offset,
show_pulleys = true);
translate([coreXYPosBL.x + separation.x/2, coreXYPosTR.y + upper_drive_pulley_offset.y, separation.z/2]) {
// add the upper drive pulley stepper motor
translate([coreXY_drive_pulley_x_alignment(coreXY_type) + upper_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
NEMA(NEMA17M);
// add the screws for the upper drive offset idler pulleys if required
if (upper_drive_pulley_offset.x > 0) {
translate(coreXY_drive_plain_idler_offset(coreXY_type))
translate_z(-pulley_offset(plain_idler))
screw(M3_cap_screw, 20);
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
translate_z(-pulley_offset(toothed_idler))
screw(M3_cap_screw, 20);
} else if (upper_drive_pulley_offset.x < 0) {
translate([-pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
translate_z(-pulley_offset(plain_idler))
screw(M3_cap_screw, 20);
translate([2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
translate_z(-pulley_offset(toothed_idler))
screw(M3_cap_screw, 20);
}
}
translate([coreXYPosTR.x - separation.x/2, coreXYPosTR.y + lower_drive_pulley_offset.y, -separation.z/2]) {
// add the lower drive pulley stepper motor
translate([-coreXY_drive_pulley_x_alignment(coreXY_type) + lower_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
NEMA(NEMA17M);
// add the screws for the lower drive offset idler pulleys if required
if (lower_drive_pulley_offset.x < 0) {
translate([-coreXY_drive_plain_idler_offset(coreXY_type).x, coreXY_drive_plain_idler_offset(coreXY_type).y])
translate_z(-pulley_offset(plain_idler))
screw(M3_cap_screw, 20);
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
translate_z(-pulley_offset(toothed_idler))
screw(M3_cap_screw, 20);
} else if (lower_drive_pulley_offset.x > 0) {
translate([pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
translate_z(-pulley_offset(plain_idler))
screw(M3_cap_screw, 20);
translate([-2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
translate_z(-pulley_offset(toothed_idler))
screw(M3_cap_screw, 20);
}
}
// add the screw for the left upper idler pulley
translate([coreXYPosBL.x + separation.x/2, coreXYPosBL.y, separation.z])
screw(M3_cap_screw, 20);
// add the screw for the right upper idler pulley
translate([coreXYPosTR.x + separation.x/2, coreXYPosBL.y, separation.z])
screw(M3_cap_screw, 20);
if (separation.x != 0) {
// add the screw for the left lower idler pulley
translate([coreXYPosBL.x - separation.x/2, coreXYPosBL.y, 0])
screw(M3_cap_screw, 20);
// add the screw for the right lower idler pulley
translate([coreXYPosTR.x - separation.x/2, coreXYPosBL.y, 0])
screw(M3_cap_screw, 20);
}
translate([-separation.x/2, pos.y + coreXYPosBL.y -separation.y/2, -separation.z/2 + pulley_height(plain_idler)/2]) {
// add the screw for the left Y carriage toothed idler
translate([coreXYPosBL.x, coreXY_toothed_idler_offset(coreXY_type).y, 0])
screw(M3_cap_screw, 20);
// add the screw for the left Y carriage plain idler
translate([coreXYPosBL.x + separation.x + coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, separation.z])
screw(M3_cap_screw, 20);
// add the screw for the right Y carriage toothed idler
translate([coreXYPosTR.x + separation.x, coreXY_toothed_idler_offset(coreXY_type).y, separation.z])
screw(M3_cap_screw, 20);
// add the screw for the right Y carriage plain idler
translate([coreXYPosTR.x - coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, 0])
screw(M3_cap_screw, 20);
}
}
if ($preview)
coreXY_belts_test();

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../utils/layout.scad>
include <../vitamins/displays.scad>

View File

@@ -16,12 +16,13 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/geared_steppers.scad>
use <../utils/layout.scad>
module geared_steppers()
layout([for(g = geared_steppers) gs_diameter(g)], 5)
layout([for(g = geared_steppers) max(gs_diameter(g), gs_pitch(g) + gs_lug_w(g) / 2)], 5)
geared_stepper(geared_steppers[$i]);
geared_steppers();

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../utils/layout.scad>
include <../vitamins/green_terminals.scad>

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../vitamins/hygrometer.scad>
if($preview)

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../vitamins/microview.scad>
microview(!$preview);

View File

@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
use <../vitamins/o_ring.scad>
module o_rings()

View File

@@ -17,7 +17,7 @@
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/kp_pillow_blocks.scad>
include <../vitamins/pillow_blocks.scad>
use <../utils/layout.scad>

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 162 KiB

BIN
tests/png/bldc_motors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
tests/png/box_sections.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
tests/png/core_xy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 153 KiB

BIN
tests/png/pillow_blocks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

BIN
tests/png/pocket_handle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 181 KiB

40
tests/pocket_handle.scad Normal file
View File

@@ -0,0 +1,40 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../core.scad>
include <../vitamins/sheets.scad>
use <../printed/pocket_handle.scad>
show_holes = false;
handle = pocket_handle();
module pocket_handles() {
if($preview) {
pocket_handle_assembly(handle);
if(show_holes)
#pocket_handle_holes(handle);
}
else
pocket_handle(handle);
}
pocket_handles();

View File

@@ -16,8 +16,8 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../printed/press_fit.scad>
include <../core.scad>
use <../printed/press_fit.scad>
module press_fits()
{

View File

@@ -22,21 +22,28 @@ include <../vitamins/rails.scad>
use <../utils/layout.scad>
use <../vitamins/nut.scad>
length = 200;
sheet = 3;
pos = 1; //[-1 : 0.1 : 1]
function rail_carriages(rail) = [for(c = carriages) if(carriage_rail(c) == rail) c];
module rails()
layout([for(l = carriages) carriage_width(l)], 20)
layout([for(r = rails) carriage_width(rail_carriages(r)[0])], 20)
rotate(-90) {
carriage = carriages[$i];
rail = carriage_rail(carriage);
length = 200;
rail = rails[$i];
carriages = rail_carriages(rail);
carriage = carriages[0];
screw = rail_screw(rail);
nut = screw_nut(screw);
washer = screw_washer(screw);
rail_assembly(carriage, length, pos * carriage_travel(carriage, length) / 2, $i<2 ? grey(20) : "green", $i<2 ? grey(20) : "red");
if(len(carriages) > 1)
translate([-carriage_travel(carriages[1], length) / 2, 0])
carriage(carriages[1]);
rail_screws(rail, length, sheet + nut_thickness(nut, true) + washer_thickness(washer));
rail_hole_positions(rail, length, 0)

View File

@@ -18,7 +18,7 @@
//
include <../global_defs.scad>
use <../utils/rounded_right_triangle.scad>
use <../utils/rounded_triangle.scad>
module rounded_right_triangles() {

View File

@@ -16,6 +16,10 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
// Extra countersink depth
sink = 0; // [0 : 0.05: 1.0]
include <../core.scad>
module polysink_stl() {
@@ -32,9 +36,9 @@ module polysink_stl() {
let(s = cs_screws[i])
translate([i * 20, 0]) {
translate_z(size.z)
screw_polysink(s, 2 * size.z + 1);
screw_polysink(s, 2 * size.z + 1, sink = sink);
screw_polysink(s, 2 * size.z + 1, alt = true);
screw_polysink(s, 2 * size.z + 1, alt = true, sink = sink);
}
}
}

View File

@@ -25,25 +25,30 @@ include <../vitamins/screws.scad>
width = 30;
2d = true;
module sheets()
layout([for(s = sheets) width], 5)
let(sheet = sheets[$i], w = sheet_is_woven(sheet) ? width : undef)
if(2d)
render_2D_sheet(sheet, w = w, d = w)
difference() {
sheet_2D(sheet, width, width, 2);
module sheets() {
rows = 2;
n = ceil(len(sheets) / rows);
w = width + 5;
for(y = [0 : rows - 1], x = [0 : n - 1], s = y * n + x)
if(s < len(sheets))
translate([width / 2 + x * w, y * w])
let(sheet = sheets[s], w = sheet_is_woven(sheet) ? width : undef)
if(2d)
render_2D_sheet(sheet, w = w, d = w)
difference() {
sheet_2D(sheet, width, width, 2);
circle(3);
}
else
render_sheet(sheet, w = w, d = w)
difference() {
sheet(sheet, width, width, 2);
translate_z(sheet_thickness(sheet) / 2)
screw_countersink(M3_cs_cap_screw);
}
circle(3);
}
else
render_sheet(sheet, w = w, d = w)
difference() {
sheet(sheet, width, width, 2);
translate_z(sheet_thickness(sheet) / 2)
screw_countersink(M3_cs_cap_screw);
}
}
if($preview)
sheets();

View File

@@ -34,14 +34,19 @@
//! If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` module then the STL or DXF will be used in the assembly views generated by `views.py` instead of generating
//! it with code.
//! This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
//!
//! The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
//!
//! * Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
//! * If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
//! * To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
//! * Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
//
function bom_mode(n = 1) = $_bom >= n && (is_undef($on_bom) || $on_bom); //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of `$exploded` if it is defined, else `0`
function show_supports() = !$preview || exploded(); //! True if printed support material should be shown
module no_explode() let($exploded_parent = true) children(); //! Prevent children being exploded
module no_pose() let($posed = true) children(); //! Force children not to be posed even if parent is
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector `d`, option to explode grand children
v = is_list(d) ? d : [0, 0, d];
o = is_list(offset) ? offset : [0, 0, offset];
@@ -62,17 +67,29 @@ module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode
children();
}
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
let($posed = true) // only pose the top level
rotate([55, 0, 25])
rotate([-a.x, 0, 0])
rotate([0, -a.y, 0])
rotate([0, 0, -a.z])
translate(-t)
children();
module no_pose() let($posed = true, $zoomed = undef) children(); //! Force children not to be posed even if parent is
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only.
let($zoomed = is_undef(d)
? is_undef($zoomed)
? undef
: $zoomed
: is_undef(exploded)
? 3
: exploded
? 2
: 1)
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
let($posed = true) // only pose the top level
rotate([55, 0, 25])
translate_z(is_undef(d) ? 0 : 140 - d)
rotate([-a.x, 0, 0])
rotate([0, -a.y, 0])
rotate([0, 0, -a.z])
translate(-t)
children();
module pose_hflip(exploded = undef) //! Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
@@ -93,7 +110,9 @@ module pose_vflip(exploded = undef) //! Pose an STL or assembly for render
module assembly(name, big = undef, ngb = false) { //! Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams.
if(bom_mode()) {
args = is_undef(big) && !ngb ? "" : str("(big=", big, ", ngb=", ngb, ")");
zoom = is_undef($zoomed) ? 0 : $zoomed;
arglist = str(arg(big, undef, "big"), arg(ngb, false, "ngb"), arg(zoom, 0, "zoomed"));
args = len(arglist) ? str("(", slice(arglist, 2), ")") : "";
echo(str("~", name, "_assembly", args, "{"));
}
no_pose()
@@ -146,17 +165,11 @@ module dxf(name) { //! Name a dxf that will appear on the B
}
}
module use_stl(name) { //! Import an STL to make a build platter
stl(name);
path = is_undef($target) ? "/stls/" : str("/", $target, "/stls/");
import(str($cwd, path, name, ".stl"));
}
module use_stl(name) //! Import an STL to make a build platter
assert(false); // Here for documentation only, real version in core.scad
module use_dxf(name) { //! Import a DXF to make a build panel
dxf(name);
path = is_undef($target) ? "/dxfs/" : str("/", $target, "/dxfs/");
import(str($cwd, path, name, ".dxf"));
}
module use_dxf(name) //! Import a DXF to make a build panel
assert(false); // Here for documentation only, real version in core.scad
function value_string(value) = is_string(value) ? str("\"", value, "\"") : str(value); //! Convert `value` to a string or quote it if it is already a string

View File

@@ -25,3 +25,15 @@ include <../../global_defs.scad>
// Global functions and modules
//
use <global.scad>
module use_stl(name) { //! Import an STL to make a build platter
stl(name);
path = is_undef($target) ? "../stls/" : str($cwd, "/", $target, "/stls/");
import(str(path, name, ".stl"));
}
module use_dxf(name) { //! Import a DXF to make a build panel
dxf(name);
path = is_undef($target) ? "../dxfs/" : str($cwd, "/", $target, "/dxfs/");
import(str(path, name, ".dxf"));
}

View File

@@ -33,20 +33,20 @@
//! When `twist` is set the resulting cylinder is extended by `eps` at each end so that the exact length of the hole can be used without
//! leaving a scar on either surface.
//
function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius
function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle
function corrected_diameter(d, n = 0) = d / cos(180 / (n ? n : sides(d / 2))); //! Adjusted diameter to make flats lie on the circle
function sides(r, n = undef) = is_undef(n) ? max(round(4 * r), 3) : n ? max(n, 3) : r2sides(r); //! Optimium number of sides for specified radius
function corrected_radius(r, n = undef) = r / cos(180 / sides(r, n)); //! Adjusted radius to make flats lie on the circle
function corrected_diameter(d, n = undef) = 2 * corrected_radius(d / 2 , n); //! Adjusted diameter to make flats lie on the circle
module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the correct size
n = sides ? sides : sides(r);
circle(r = corrected_radius(r,n), $fn = n);
module poly_circle(r, sides = undef) { //! Make a circle adjusted to print the correct size
n = sides(r, sides);
circle(r = corrected_radius(r, n), $fn = n);
}
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
module poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
if(twist) {
slices = ceil(h / layer_height);
twists = min(twist + 1, slices);
sides = sides ? sides : sides(r);
sides = sides(r, sides);
rot = 360 / sides / twists * (twists < slices ? (1 + 1 / slices) : 1);
if(center)
for(side = [0, 1])
@@ -64,10 +64,10 @@ module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0
poly_circle(r, sides);
if(h && chamfer)
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides ? sides : sides(r));
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides(r, sides));
}
module poly_ring(or, ir, sides = 0) { //! Make a 2D ring adjusted to have the correct internal radius
module poly_ring(or, ir, sides = undef) { //! Make a 2D ring adjusted to have the correct internal radius
cir = corrected_radius(ir, sides);
filaments = (or - cir) / extrusion_width;
if(filaments > 3 + eps)

204
utils/core_xy.scad Normal file
View File

@@ -0,0 +1,204 @@
//
// 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/>.
//
//
//! Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
//!
//! The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
//! Implementation has the following features:
//!
//! 1. The drive and idler pulleys may be different sizes.
//! 2. The belt separation is parameterised.
//! 3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
//! 4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
//! allows flexible positioning of the motors.
//
include <../core.scad>
include <../vitamins/belts.scad>
include <../vitamins/pulleys.scad>
coreXY_GT2_20_20 = ["coreXY_20_20", GT2x6, GT2x20ob_pulley, GT2x20_toothed_idler, GT2x20_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
coreXY_GT2_20_16 = ["coreXY_20_16", GT2x6, GT2x20ob_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
coreXY_GT2_16_16 = ["coreXY_16_16", GT2x6, GT2x16_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
function coreXY_belt(type) = type[1]; //! Belt type
function coreXY_drive_pulley(type) = type[2]; //! Drive pulley type
function coreXY_toothed_idler(type) = type[3]; //! Toothed idler type
function coreXY_plain_idler(type) = type[4]; //! Plain idler type
function coreXY_upper_belt_colour(type) = type[5]; //! Colour of the upper belt
function coreXY_upper_tooth_colour(type) = type[6]; //! Colour of the upper belt's teeth
function coreXY_lower_belt_colour(type) = type[7]; //! Colour of the lower belt
function coreXY_lower_tooth_colour(type) = type[8]; //! Colour of the lower belt's teeth
// used to offset the position of the drive pulley and the y-carriage plain idler pulley
// relative to the anchor pulley so that the belts align properly
function coreXY_drive_pulley_x_alignment(type) = //! Belt alignment offset of the drive pulley relative to the anchor pulley
(pulley_od(coreXY_drive_pulley(type)) - pulley_od(coreXY_toothed_idler(type))) / 2;
function coreXY_coincident_separation(type) = //! Value of x, y separation to make y-carriage pulleys coincident
[ -coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_toothed_idler(type)))/2, 0 ];
function coreXY_plain_idler_offset(type) = //! Offset of y-carriage plain idler
[ (pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2 + coreXY_drive_pulley_x_alignment(type), pulley_od(coreXY_plain_idler(type))/2, 0 ];
function coreXY_toothed_idler_offset(type) = //! offset of y-carriage toothed idler
[ 0, -pulley_pr(coreXY_toothed_idler(type)), 0 ];
// helper functions for positioning idlers when the stepper motor drive pulley is offset
function coreXY_drive_toothed_idler_offset(type) = //! Offset of toothed drive idler pulley
[ 0, coreXY_drive_pulley_x_alignment(type), 0 ];
function coreXY_drive_plain_idler_offset(type) = //! Offset of plain drive idler pulley
[ coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2, 0 ];
module coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false) { //! Draw one belt of a coreXY setup
// y-carriage toothed pulley
p0_type = coreXY_toothed_idler(type);
p0 = [ size.x / 2, -size.y / 2 - pulley_od(p0_type) / 2 + pos.y - separation_y / 2 ];
// bottom right toothed idler pulley
p1_type = p0_type;
p1 = [ size.x / 2, -size.y / 2 ];
// bottom left anchor toothed idler pulley
p2_type = p0_type;
p2 = [ -size.x / 2, -size.y / 2 ];
// stepper motor drive pulley
p3d_type = coreXY_drive_pulley(type);
p3d = [ -size.x / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.x,
size.y / 2 + drive_pulley_offset.y
];
// toothed idler for offset stepper motor drive pulley
p3t_type = coreXY_toothed_idler(type);
p3t = [ -size.x / 2 + (drive_pulley_offset.x > 0 ? 0 : 2 * coreXY_drive_pulley_x_alignment(type)),
size.y / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.y
];
// y-carriage plain pulley
p4_type = coreXY_plain_idler(type);
p4 = [ -size.x / 2 + pulley_od(p4_type) / 2 + pulley_od(p3d_type) / 2 + coreXY_drive_pulley_x_alignment(type) + plain_idler_offset,
-size.y / 2 + pulley_od(p4_type) / 2 + pos.y + separation_y / 2
];
// plain idler for offset stepper motor drive pulley
p3p_type = p4_type;
p3p = [ drive_pulley_offset.x > 0 ? p4.x : -p0.x - pulley_od(p0_type),
size.y / 2 - pulley_od(p3p_type) / 2 - pulley_od(p3d_type) / 2 + drive_pulley_offset.y
];
// Start and end points
start_p = [ pos.x - size.x / 2 + x_gap / 2, -size.y / 2 + pos.y - separation_y / 2, 0 ];
end_p = [ pos.x - size.x / 2 - x_gap / 2, -size.y / 2 + pos.y + separation_y / 2, 0 ];
//p6_type = p0_type;
module show_pulleys(show_pulleys) {// Allows the pulley colour to be set for debugging
if (is_list(show_pulleys))
color(show_pulleys)
children();
else if (show_pulleys)
children();
}
show_pulleys(show_pulleys) {
translate(p0)
pulley_assembly(p0_type); // y-carriage toothed pulley
translate(p1)
pulley_assembly(p1_type); // bottom right toothed idler pulley
translate(p2)
pulley_assembly(p2_type); // bottom left anchor toothed idler pulley
translate(p3d)
hflip(hflip)
pulley_assembly(p3d_type); // top left stepper motor drive pulley
if (drive_pulley_offset.x) { // idler pulleys for offset stepper motor drive pulley
translate(p3t)
pulley_assembly(p3t_type); // toothed idler
translate(p3p)
pulley_assembly(p3p_type); // plain idler
}
translate(p4)
pulley_assembly(p4_type); // y-carriage plain pulley
}
path0a = [
[ p0.x, p0.y, pulley_od(p0_type) / 2 ],
[ p1.x, p1.y, pulley_od(p1_type) / 2 ],
[ p2.x, p2.y, pulley_od(p2_type) / 2 ]
];
path0b = [
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
];
path0c = [
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
];
path0d = [
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
];
belt = coreXY_belt(type);
path0 = drive_pulley_offset.x == 0 ? concat(path0a, path0b) : drive_pulley_offset.x > 0 ? concat(path0a, path0c) : concat(path0a, path0d);
path = concat([start_p], path0, [end_p]);
belt(type = belt,
points = path,
open = true,
belt_colour = lower_belt ? coreXY_lower_belt_colour(type) : coreXY_upper_belt_colour(type),
tooth_colour = lower_belt ? coreXY_lower_tooth_colour(type) : coreXY_upper_tooth_colour(type));
}
module coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false, left_lower = false) { //! Wrapper module to draw both belts of a coreXY setup
translate([size.x / 2 - separation.x / 2, size.y / 2, -separation.z / 2]) {
// lower belt
hflip(!left_lower)
explode(25)
coreXY_half(type, size, [size.x - pos.x - separation.x/2 - (left_lower ? x_gap : 0), pos.y], separation.y, x_gap, plain_idler_offset, [-lower_drive_pulley_offset.x, lower_drive_pulley_offset.y], show_pulleys, lower_belt = true, hflip = true);
// upper belt
translate([separation.x, 0, separation.z])
hflip(left_lower)
explode(25)
coreXY_half(type, size, [pos.x + separation.x/2 + (left_lower ? x_gap : 0), pos.y], separation.y, x_gap, plain_idler_offset, upper_drive_pulley_offset, show_pulleys, lower_belt = false, hflip = false);
}
}
module coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false, left_lower = false) { //! Draw the coreXY belts
assert(coreXYPosBL.z == coreXYPosTR.z);
coreXYSize = coreXYPosTR - coreXYPosBL;
translate(coreXYPosBL)
coreXY(type, coreXYSize, [carriagePosition.x - coreXYPosBL.x, carriagePosition.y - coreXYPosBL.y], separation = separation, x_gap = x_gap, plain_idler_offset = 0, upper_drive_pulley_offset = upper_drive_pulley_offset, lower_drive_pulley_offset = lower_drive_pulley_offset, show_pulleys = show_pulleys, left_lower = left_lower);
}

View File

@@ -88,6 +88,7 @@ function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matr
[0, 0, 0, 1]
];
function vec2(v) = [v.x, v.y]; //! Return a 2 vector with the first two elements of `v`
function vec3(v) = [v.x, v.y, v.z]; //! Return a 3 vector with the first three elements of `v`
function vec4(v) = [v.x, v.y, v.z, 1]; //! Return a 4 vector with the first three elements of `v`
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]); //! Apply 4x4 transform to a 3 vector by extending it and cropping it again
@@ -153,3 +154,36 @@ function circle_intersect(c1, r1, c2, r2) = //! Calculate one point where tw
d = norm(v), // Distance between centres
a = atan2(v.z, v.x) - acos((sqr(d) + sqr(r2) - sqr(r1)) / (2 * d * r2)) // Cosine rule to find angle from c2
) c2 + r2 * [cos(a), 0, sin(a)]; // Point on second circle
function map(v, func) = [ for (e = v) func(e) ]; //! make a new vector where the func function argument is applied to each element of the vector v
function mapi(v, func) = [ for (i = [0:len(v)-1]) func(i,v[i]) ]; //! make a new vector where the func function argument is applied to each element of the vector v. The func will get the index number as first argument, and the element as second argument.
function reduce(v, func, unity) = let ( r = function(i,val) i == len(v) ? val : r(i + 1, func(val, v[i])) ) r(0, unity); //! reduce a vector v to a single entity by applying the func function recursively to the reduced value so far and the next element, starting with unity as the initial reduced value
function sumv(v) = reduce(v, function(a, b) a + b, 0); //! sum a vector of values that can be added with "+"
function xor(a,b) = (a && !b) || (!a && b); //! Logical exclusive OR
function cuberoot(x)= sign(x)*abs(x)^(1/3);
function quadratic_real_roots(a, b, c) = //! Returns real roots of a quadratic equation, biggest first. Returns empty list if no real roots
let(2a = 2 * a,
2c = 2 * c,
det = b^2 - 2a * 2c
) det < 0 ? [] :
let(r = sqrt(det),
x1 = b < 0 ? 2c / (-b + r) : (-b - r) / 2a,
x2 = b < 0 ? (-b + r) / 2a : 2c / (-b - r)
) [x2, x1];
function cubic_real_roots(a, b, c, d) = //! Returns real roots of cubic equation
let(b = b / a,
c = c / a,
d = d / a,
inflection = -b / 3,
p = c - b^2 / 3,
q = 2 * b^3 / 27 - b * c / 3 + d,
det = q^2 / 4 + p^3 / 27,
roots = !p && !q ? 1 : nearly_zero(det) ? 2 : det < 0 ? 3 : 1,
r = sqrt(det),
x = cuberoot(-q / 2 - r) + cuberoot(-q / 2 + r)
) roots == 1 ? [x] :
roots == 2 ? [3 * q /p + inflection, -3 * q / p / 2 + inflection] :
[for(i = [0 : roots - 1]) 2 * sqrt(-p / 3) * cos(acos(3 * q * sqrt(-3 / p) / p / 2) - i * 120) + inflection];

View File

@@ -24,6 +24,7 @@
//! Because the tangents need to be calculated to find the length these can be calculated separately and re-used when drawing to save calculating them twice.
//
include <../utils/core/core.scad>
use <../utils/maths.scad>
function circle_tangent(p1, p2) = //! Compute the clockwise tangent between two circles represented as [x,y,r]
let(
@@ -36,44 +37,54 @@ function circle_tangent(p1, p2) = //! Compute the clockwise tangent between two
v = [cos(theta), sin(theta)]
)[ p1 + r1 * v, p2 + r2 * v ];
function rounded_polygon_tangents(points) = //! Compute the straight sections needed to draw and to compute the lengths
let(len = len(points))
[for(i = [0 : len - 1])
let(ends = circle_tangent(points[i], points[(i + 1) % len]))
for(end = [0, 1])
ends[end]];
function rounded_polygon_arcs(points, tangents) = //! Compute the arcs at the points, for each point [angle, rotate_angle, length]
let(
len = len(points)
) [ for (i = [0: len-1])
let(
p1 = vec2(tangents[(i - 1 + len) % len][1]),
p2 = vec2(tangents[i][0]),
p = vec2(points[i]),
v1 = p1 - p,
v2 = p2 - p,
sr = points[i][2],
r = abs(sr),
a = r < 0.001 ? 0 : let( aa = acos((v1 * v2) / sqr(r)) ) cross(v1, v2) * sign(sr) <= 0 ? aa : 360 - aa,
l = PI * a * r / 180,
v0 = [r, 0],
v = let (
vv = norm(v0 - v2) < 0.001 ? 0 : abs(v2.y) < 0.001 ? 180 :
let( aa = acos((v0 * v2) / sqr(r)) ) cross(v0, v2) * sign(sr) <= 0 ? aa : 360 - aa
) sr > 0 ? 360 - vv : vv - a
) [a, v, l]
];
function sumv(v, i = 0, sum = 0) = i == len(v) ? sum : sumv(v, i + 1, sum + v[i]);
function rounded_polygon_tangents(points) = //! Compute the straight sections between a point and the next point, for each section [start_point, end_point, length]
let(len = len(points))
[ for(i = [0 : len - 1])
let(ends = circle_tangent(points[i], points[(i + 1) % len]))
[ends[0], ends[1], norm(ends[0] - ends[1])]
];
// the cross product of 2D vectors is the area of the parallelogram between them. We use the sign of this to decide if the angle is bigger than 180.
function rounded_polygon_length(points, tangents) = //! Calculate the length given the point list and the list of tangents computed by ` rounded_polygon_tangents`
let(
len = len(points),
indices = [0 : len - 1],
straights = [for(i = indices) norm(tangents[2 * i] - tangents[2 * i + 1])],
arcs = [for(i = indices) let(p1 = tangents[2 * i + 1],
p2 = tangents[(2 * i + 2) % (2 * len)],
corner = points[(i + 1) % len],
c = [corner.x, corner.y],
v1 = p1 - c,
v2 = p2 - c,
r = abs(corner.z),
a = acos((v1 * v2) / sqr(r))) r ? PI * (cross(v1, v2) <= 0 ? a : 360 - a) * r / 180 : 0]
)
sumv(concat(straights, arcs));
arcs = rounded_polygon_arcs(points, tangents)
) sumv( map( concat(tangents, arcs), function(e) e[2] ) );
module rounded_polygon(points, _tangents = undef) { //! Draw the rounded polygon from the point list, can pass the tangent list to save it being calculated
len = len(points);
indices = [0 : len - 1];
tangents = _tangents ? _tangents : rounded_polygon_tangents(points);
tangents = [ for (t = _tangents ? _tangents : rounded_polygon_tangents(points)) each [t.x, t.y] ];
difference(convexity = points) {
difference() {
union() {
for(i = indices)
if(points[i][2] > 0)
hull() {
translate([points[i].x, points[i].y])
circle(points[i][2]);
polygon([tangents[(2 * i - 1 + 2 * len) % (2 * len)], tangents[2 * i], [points[i].x, points[i].y]]);
}
@@ -85,7 +96,7 @@ module rounded_polygon(points, _tangents = undef) { //! Draw the rounded polygon
translate([points[i].x, points[i].y])
circle(-points[i][2]);
polygon([tangents[(2 * i - 1 + 2 * len) % (2 *len)], tangents[2 * i], [points[i].x, points[i].y]]);
polygon([tangents[(2 * i - 1 + 2 * len) % (2 * len)], tangents[2 * i], [points[i].x, points[i].y]]);
}
}
}

View File

@@ -21,7 +21,6 @@
//! Draw a 3D right triangle with rounded edges. Intended to be embedded in other parts. Can be optionally offset by the filleted amount.
//
include <../utils/core/core.scad>
include <..//utils/core/rounded_rectangle.scad>
module rounded_right_triangle(x, y, z, fillet, center = true, offset = false) { //! Draw a 3D right triangle with rounded edges.
fillet = max(fillet, eps);

View File

@@ -50,6 +50,7 @@ function thread_profile(h, crest, angle, overlap = 0.1) = //! Create thread prof
[[-base / 2, -overlap, 0], [-crest / 2, h, 0], [crest / 2, h, 0], [base / 2, -overlap, 0]];
module thread(dia, pitch, length, profile, center = true, top = -1, bot = -1, starts = 1, solid = true, female = false, colour = undef) { //! Create male or female thread, ends can be tapered, chamfered or square
assert(is_undef(colour) || is_list(colour), "Thread colour must be in [r, g, b] form");
//
// Apply colour if defined
//
@@ -190,7 +191,8 @@ module female_metric_thread(d, pitch, length, center = true, top = -1, bot = -1,
}
function metric_coarse_pitch(d) //! Convert metric diameter to pitch
= d == 1.6 ? 0.35 // M1.6
= d == 1.4 ? 0.3 // M1.4
: d == 1.6 ? 0.35 // M1.6
: [0.4, // M2
0.45,// M2.5
0.5, // M3

View File

@@ -40,4 +40,4 @@ SCS16LUU = ["SCS16LUU", 9, 19, 25, 50, 85, 38.5, 32.5, 36, 60, 7, M5_cap_sc
scs_bearing_blocks = [SCS6UU, SCS8UU, SCS10UU, SCS12UU, SCS16UU];
scs_bearing_blocks_long = [SCS8LUU, SCS10LUU, SCS12LUU, SCS16LUU];
use <scs_bearing_block.scad>
use <bearing_block.scad>

View File

@@ -18,19 +18,29 @@
//
//
//! Models timing belt running over toothed or smooth pulleys and calculates an accurate length.
//! Only models 2D paths, so not crossed belt core XY!
//! Models timing belt running in a path over toothed or smooth pulleys and calculates an accurate length.
//! Only models 2D paths, belt may twist to support crossed belt core XY and other designes where the belt twists!
//!
//! By default the path is a closed loop. An open loop can be specified by specifying `open=true`, and in that case the start and end points are not connected, leaving the loop open.
//!
//! To get a 180 degree twist of the loop, you can use the `twist` argument. `Twist` can be a single number, and in that case the belt will twist after
//! the position with that number. Alternatively `twist` can be a list of boolean values with a boolean for each position; the belt will then twist after
//! the position that have a `true` value in the `twist` list. If the path is specified with pulley/idler types, then you can use `auto_twist=true`; in
//! that case the belt will automatically twist so the back of the belt always runs against idlers and the tooth side runs against pullies. If you use
//! `open=true` then you might also use `start_twist=true` to let the belt start the part with the back side out.
//!
//! The path must be specified as a list of positions. Each position should be either a vector with `[x, y, pulley]` or `[x, y, r]`. A pully is a type from
//! `pulleys.scad`, and correct radius and angle will automatically be calculated. Alternatively a radius can be specified directly.
//!
//! To make the back of the belt run against a smooth pulley on the outside of the loop specify a negative pitch radius.
//!
//! By default the path is a closed loop but a gap length and position can be specified to make open loops.
//! To draw the gap its XY position is specified by `gap_pos`. `gap_pos.z` can be used to specify a rotation if the gap is not at the bottom of the loop.
//! Alternativley you can just specify smooth pulleys in the path, and it will then happen automatically.
//!
//! Individual teeth are not drawn, instead they are represented by a lighter colour.
//
include <../utils/core/core.scad>
use <../utils/rounded_polygon.scad>
use <../utils/maths.scad>
use <pulley.scad>
function belt_pitch(type) = type[1]; //! Pitch in mm
function belt_width(type) = type[2]; //! Width in mm
@@ -41,47 +51,102 @@ function belt_pitch_height(type) = type[5] + belt_tooth_height(type); //! Offset
function belt_pitch_to_back(type) = belt_thickness(type) - belt_pitch_height(type); //! Offset of the back from the pitch radius
//
// We model the belt path at the pitch radius of the pulleys and the pitch line of the belt to get an accurate length.
// The belt is then drawn by offseting each side from the pitch line.
//
module belt(type, points, gap = 0, gap_pos = undef, belt_colour = grey(20), tooth_colour = grey(50)) { //! Draw a belt path given a set of points and pitch radii where the pulleys are. Closed loop unless a gap is specified
module belt(type, points, belt_colour = grey(20), tooth_colour = grey(50), open = false, twist = undef, auto_twist = false, start_twist = false) { //! Draw a belt path given a set of points and pitch radii where the pulleys are. Closed loop unless open is specified
width = belt_width(type);
pitch = belt_pitch(type);
thickness = belt_thickness(type);
info = _belt_points_info(type, points, open, twist, auto_twist, start_twist);
dotwist = info[0]; // array of booleans, true if a twist happen after the position
twisted = info[1]; // array of booleans, true if the belt is twisted at the position
pointsx = info[2]; // array of [x,y,r], r is negative if left-angle (points may have pulleys as third element, but pointsx have radi)
tangents = info[3];
arcs = info[4];
length = ceil(_belt_length(info, open) / pitch) * pitch;
part = str(type[0],pitch);
vitamin(str("belt(", no_point(part), "x", width, ", ", points, arg(gap, 0), arg(gap_pos, undef), "): Belt ", part," x ", width, "mm x ", length, "mm"));
vitamin(str("belt(", no_point(part), "x", width, ", ", pointsx, "): Belt ", part," x ", width, "mm x ", length, "mm"));
len = len(points);
tangents = rounded_polygon_tangents(points);
length = ceil((rounded_polygon_length(points, tangents) - (is_list(gap) ? gap.x + gap.y : gap)) / pitch) * pitch;
module shape() rounded_polygon(points, tangents);
ph = belt_pitch_height(type);
th = belt_tooth_height(type);
module gap()
if(gap)
translate([gap_pos.x, gap_pos.y])
rotate(is_undef(gap_pos.z) ? 0 : gap_pos.z)
translate([0, ph - thickness / 2])
square(is_list(gap) ? [gap.x, gap.y + thickness + eps] : [gap, thickness + eps], center = true);
ph = belt_pitch_height(type);
module beltp() translate([ph - th, -width / 2]) square([th, width]);
module beltb() translate([ph - thickness, -width / 2]) square([thickness - th, width]);
color(belt_colour)
linear_extrude(width, center = true)
difference() {
offset(-ph + thickness ) shape();
offset(-ph + th) shape();
gap();
}
for (i = [0 : len - (open ? 2 : 1)]) {
p1 = tangents[i].x;
p2 = tangents[i].y;
v = p2-p1;
a = atan(v.y / v.x) - (v.x < 0 ? 180 : 0); //a2(p2-p1);
l = norm(v);
translate(p1) rotate([-90, 0, a - 90]) {
twist = dotwist[i] ? 180 : 0;
mirrored = twisted[i] ? 1 : 0;
color(tooth_colour) linear_extrude(l, twist = twist) mirror([mirrored, 0, 0]) beltp();
color(belt_colour) linear_extrude(l, twist = twist) mirror([mirrored, 0, 0]) beltb();
}
}
color(tooth_colour)
linear_extrude(width, center = true)
difference() {
offset(-ph + th) shape();
offset(-ph) shape();
gap();
}
for (i = [(open ? 1 : 0) : len - (open ? 2 : 1)]) {
p = pointsx[i];
arc = arcs[i];
translate([p.x, p.y]) rotate([0, 0, arc[1]]) {
mirrored = xor(twisted[i], p[2] < 0) ? 0 : 1;
color(tooth_colour) rotate_extrude(angle = arc[0]) translate([abs(p[2]), 0, 0]) mirror([mirrored, 0, 0]) beltp();
color(belt_colour) rotate_extrude(angle = arc[0]) translate([abs(p[2]), 0, 0]) mirror([mirrored, 0, 0]) beltb();
}
}
}
function belt_length(points, gap = 0) = rounded_polygon_length(points, rounded_polygon_tangents(points)) - gap; //! Compute belt length given path and optional gap
function _belt_points_info(type, points, open, twist, auto_twist, start_twist) = //! Helper function that calculates [twist, istwisted, points, tangents, arcs]
let(
len = len(points),
isleft = function(i) let(
p = vec2(points[i]),
p0 = vec2(points[(i - 1 + len) % len]),
p1 = vec2(points[(i + 1) % len])
) cross(p-p0,p1-p) > 0,
dotwist = function(i, istwisted) let( in = (i + 1) % len )
is_list(twist) ? twist[i] :
!is_undef(twist) ? i == twist :
open && is_list(points[in][2]) && auto_twist ? !pulley_teeth(points[in][2]) && !xor(isleft(in), istwisted) :
false,
twisted = [
for (
i = 0,
istwisted = start_twist,
twist = dotwist(i, istwisted),
nexttwisted = xor(twist, istwisted);
i < len;
i = i + 1,
istwisted = nexttwisted,
twist = dotwist(i, istwisted),
nexttwisted = xor(twist, istwisted)
) [twist, istwisted] ],
pointsx = mapi(points, function(i, p) !is_list(p[2]) ? p : [p.x, p.y, let( // if p[2] is not a list it is just r, otherwise it is taken to be a pulley and we calculate r
isleft = isleft(i),
r = belt_pulley_pr(type, p[2], twisted = !xor(pulley_teeth(p[2]), xor(isleft, twisted[i][1])))
) isleft ? -r : r ] ),
tangents = rounded_polygon_tangents(pointsx),
arcs = rounded_polygon_arcs(pointsx, tangents)
) [ [ for (t = twisted) t[0] ], [ for (t = twisted) t[1] ], pointsx, tangents, arcs];
function belt_pulley_pr(type, pulley, twisted=false) = //! Pitch radius. Default it expects the belt tooth to be against a toothed pulley an the backside to be against a smooth pulley (an idler). If `twisted` is true, the the belt is the other way around.
let(
thickness = belt_thickness(type),
ph = belt_pitch_height(type)
) pulley_teeth(pulley)
? pulley_pr(pulley) + (twisted ? thickness - ph : 0 )
: pulley_ir(pulley) + (twisted ? ph : thickness - ph );
function belt_length(type, points, open = false) = _belt_length(_belt_points_info(type, points, open), open); //! Compute belt length given path
function _belt_length(info, open) = let(
len = len(info[0]),
d = open ? 1 : 0,
tangents = slice(info[3], 0, len - d) ,
arcs = slice(info[4], d, len - d)
) sumv( map( concat(tangents, arcs), function(e) e[2] ));

286
vitamins/bldc_motor.scad Normal file
View File

@@ -0,0 +1,286 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
//! Brushless DC electric motor
//
include <NopSCADlib/core.scad>
use <NopSCADlib/vitamins/rod.scad>
use <NopSCADlib/utils/thread.scad>
use <NopSCADlib/utils/tube.scad>
function BLDC_diameter(type) = type[1]; //! Diameter of motor
function BLDC_height(type) = type[2]; //! Height of motor including boss, if any, but excluding prop shaft
function BLDC_shaft_diameter(type) = type[3]; //! shaft diameter
function BLDC_shaft_length(type) = type[4]; //! Total shaft length
function BLDC_shaft_offset(type) = type[5]; //! shaft offset from base
function BLDC_body_colour(type) = type[6]; //! Body colour
function BLDC_base_diameter(type) = type[7]; //! Base diameter
function BLDC_base_height_1(type) = type[8]; //! Base height 1
function BLDC_base_height_2(type) = type[9]; //! Base height 2
function BLDC_base_hole_diameter(type) = type[10]; //! Base hole diameter
function BLDC_base_holes(type) = type[11]; //! Base holes
function BLDC_base_open(type) = type[12]; //! Base open
function BLDC_wire_diameter(type) = type[13]; //! Wire diameter
function BLDC_side_colour(type) = type[14]; //! Side colour
function BLDC_bell_diameter(type) = type[15]; //! Bell diameter
function BLDC_bell_height_1(type) = type[16]; //! Bell height 1
function BLDC_bell_height_2(type) = type[17]; //! Bell height 2
function BLDC_bell_hole_diameter(type) = type[18]; //! Bell hole diameter
function BLDC_bell_holes(type) = type[19]; //! Bell holes
function BLDC_bell_spokes(type) = type[20]; //! Bell spoke count
function BLDC_boss_diameter(type) = type[21]; //! Boss diameter
function BLDC_boss_height(type) = type[22]; //! Boss height
function BLDC_prop_shaft_length(type) = type[23]; //! Prop shaft length, including threaded section
function BLDC_prop_shaft_diameter(type) = type[24]; //! Diameter of unthreaded portion of prop shaft
function BLDC_prop_shaft_thread_length(type) = type[25]; //! Length of threaded section of prop shaft
function BLDC_prop_shaft_thread_diameter(type) = type[26]; //! Diameter of threaded section of prop shaft
bldc_cap_colour = grey(50);
bldc_shaft_colour = grey(90);
bldc_bearing_colour = grey(80);
module BLDC(type) { //! Draw specified BLDC motor
vitamin(str("BLDC(", type[0], "): Brushless DC motor ", type[0]));
body_colour = BLDC_body_colour(type);
side_colour = BLDC_side_colour(type);
body_diameter = BLDC_diameter(type);
wall_thickness = 1;
height = BLDC_height(type) - BLDC_boss_height(type);
module feet(base_diameter) {
holes = BLDC_base_holes(type);
hole_count = is_list(holes) ? len(holes) : 4;
for(i = [0 : 1 : hole_count - 1]) {
spacing = is_list(holes) ? holes[i] : holes;
radius = base_diameter / 2 - spacing / 2;
rotate(i * 360 / hole_count + (hole_count == 4 ? 45 : 0))
difference() {
hull() {
circle(r = radius);
translate([-spacing / 2, 0])
circle(r = radius);
}
translate([-spacing / 2, 0])
circle(d = BLDC_base_hole_diameter(type));
}
}
}
module cutout(d1, d2, r, h) {
translate_z(-eps)
linear_extrude(h + 2 * eps)
hull() {
translate([d1 / 2, 0])
circle(r = r);
translate([d2 / 2, -r])
square([eps, 2 * r]);
}
}
module cutout2(d1, r1, d2, r2, h) {
translate_z(-eps)
linear_extrude(h + 2 * eps)
hull() {
translate([d1 / 2, 0])
circle(r = r1);
translate([d2 / 2, 0])
circle(r = r2);
}
}
module base() {
base_diameter = BLDC_base_diameter(type);
h1 = BLDC_base_height_1(type);
h2 = BLDC_base_height_2(type);
color(body_colour)
if (BLDC_base_open(type)) {
linear_extrude(h1)
difference() {
union() {
feet(base_diameter);
circle(d = 3 * BLDC_shaft_diameter(type));
}
circle(d = 2 * BLDC_shaft_diameter(type));
}
translate_z(h1)
cylinder(d = 3 * BLDC_shaft_diameter(type), h = h2);
} else {
difference() {
union() {
render(convexity = 8)
linear_extrude(h1)
difference() {
circle(d = base_diameter);
circle(d = 2 * BLDC_shaft_diameter(type));
BLDC_base_screw_positions(type)
circle(d = BLDC_base_hole_diameter(type));
}
rotate_extrude()
polygon([ [base_diameter / 2, 0], [body_diameter / 2, h1], [body_diameter / 2, h1+h2], [body_diameter / 2 - wall_thickness, h1 + h2], [body_diameter / 2 - wall_thickness, h1], [base_diameter / 2, h1] ]);
}
r = body_diameter > 40 ? 2 : body_diameter * PI / (8 * 3);
if (body_diameter > 40) {
r = 2;
// cutout for wires
translate_z(h2 /2)
cutout(base_diameter, body_diameter, 6, h1);
for (a = [90, 180, 270])
rotate(a) {
cutout(base_diameter - 2 * r, body_diameter, r, h1 + h2 / 2);
for (b = [-90 / 4, 90 / 4])
rotate(b)
cutout(base_diameter - 5 * r, body_diameter, r, h1 + h2 / 2);
}
} else {
r = body_diameter * PI / (8 * 3);
for (a = [0, 90, 180, 270])
rotate(a)
cutout(base_diameter, body_diameter, r, h1);
}
}
}
color(bldc_bearing_colour)
translate_z(0.25)
tube(or = BLDC_shaft_diameter(type), ir = BLDC_shaft_diameter(type) / 2, h = h1, center = false);
if (show_threads)
BLDC_base_screw_positions(type)
female_metric_thread(BLDC_base_hole_diameter(type), metric_coarse_pitch(BLDC_base_hole_diameter(type)), h1, center = false, colour = body_colour);
wire_diameter = BLDC_wire_diameter(type);
for (i = [0 : 2])
color(wire_diameter >= 3 ? ["yellow", grey(20), "red"][i] : grey(20))
translate([body_diameter / 5, (i - 1) * wire_diameter, wire_diameter / 2 + 0.25 + (body_diameter > 40 ? h2/2 : 0)])
rotate([0, 90, 0])
cylinder(r = wire_diameter / 2, h = body_diameter / 2, center = false);
} // end module base
module bell() {
bell_diameter = BLDC_bell_diameter(type);
h1 = BLDC_bell_height_1(type);
h2 = BLDC_bell_height_2(type);
gap = BLDC_base_open(type) ? 0 : height > 20 ? 0.5 : 0.25;
side_length = height - h2 - h1 - gap - BLDC_base_height_1(type) - BLDC_base_height_2(type);
color(body_colour) {
translate_z(height - h2) {
difference() {
union() {
top_thickness = min(h2, 2);
render(convexity = 8)
translate_z(h2 - top_thickness)
linear_extrude(top_thickness)
difference() {
circle(d = bell_diameter);
if (BLDC_shaft_length(type) > height)
circle(d = BLDC_shaft_diameter(type));
BLDC_bell_screw_positions(type)
circle(d = BLDC_bell_hole_diameter(type));
}
rotate_extrude()
polygon([ [bell_diameter/2, h2], [body_diameter/2, 0], [body_diameter/2, -h1], [body_diameter/2 - wall_thickness, -h1], [body_diameter/2 - wall_thickness, 0], [bell_diameter/2, h2 - top_thickness] ]);
}
spoke_count = BLDC_bell_spokes(type);
if (spoke_count % 4 == 0) {
r = body_diameter > 40 ? body_diameter / 15 : 2.5;
for (a = [0, 90, 180, 270])
rotate(a) {
cutout(bell_diameter + 2 * r, body_diameter, r, h2);
rotate(45) {
cutout(bell_diameter, body_diameter, r, h2);
}
}
} else {
r1 = bell_diameter * PI / (spoke_count * 3);
r2 = body_diameter * PI / (spoke_count * 3);
for (i = [0 : 1 : spoke_count - 1])
rotate(i * 360 / spoke_count)
cutout2(bell_diameter, r1, body_diameter, r2, h2);
}
} // end difference
} // end translate
if (BLDC_boss_height(type))
translate_z(height)
tube(or = BLDC_boss_diameter(type)/2, ir = BLDC_shaft_diameter(type)/2, h = BLDC_boss_height(type), center = false);
if (BLDC_prop_shaft_diameter(type))
translate_z(height + BLDC_boss_height(type)) {
thread_diameter = BLDC_prop_shaft_thread_diameter(type);
unthreaded_length = BLDC_prop_shaft_length(type) - BLDC_prop_shaft_thread_length(type);
cylinder(d=BLDC_prop_shaft_diameter(type), h = unthreaded_length);
translate_z(unthreaded_length)
if (show_threads)
male_metric_thread(thread_diameter, metric_coarse_pitch(thread_diameter), BLDC_prop_shaft_thread_length(type), center = false);
else
cylinder(d = thread_diameter, h = BLDC_prop_shaft_thread_length(type));
}
} // end colour
color(side_colour)
translate_z(height - h2 - h1 -side_length)
tube(body_diameter/2, body_diameter/2 - wall_thickness, side_length, center = false);
if (show_threads)
translate_z(height)
BLDC_bell_screw_positions(type)
vflip()
female_metric_thread(BLDC_bell_hole_diameter(type), metric_coarse_pitch(BLDC_bell_hole_diameter(type)), h2, center = false, colour = body_colour);
} // end module bell
base();
bell();
color(bldc_shaft_colour)
translate_z(-BLDC_shaft_offset(type) - eps)
not_on_bom()
rod(d = BLDC_shaft_diameter(type), l = BLDC_shaft_length(type), center = false);
}
module BLDC_screw_positions(holes, n = 4) { //! Screw positions utility function
hole_count = is_list(holes) ? len(holes) : 4;
for($i = [0 : min(n, hole_count) - 1]) {
spacing = is_list(holes) ? holes[$i] : holes;
rotate($i * 360 / hole_count)
translate([spacing / 2, 0])
rotate(-$i * 90)
children();
}
}
module BLDC_base_screw_positions(type, n = 4) { //! Positions children at the base screw holes
if (BLDC_base_holes(type))
rotate(is_list(BLDC_base_holes(type)) && len(BLDC_base_holes(type)) == 3 ? 180 : 45)
BLDC_screw_positions(BLDC_base_holes(type), n)
children();
}
module BLDC_bell_screw_positions(type, n = 4) { //! Positions children at the bell screw holes
if (BLDC_bell_holes(type))
rotate(is_list(BLDC_bell_holes(type)) && len(BLDC_bell_holes(type)) == 3 ? 30 : 0)
BLDC_screw_positions(BLDC_bell_holes(type), n)
children();
}

37
vitamins/bldc_motors.scad Normal file
View File

@@ -0,0 +1,37 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
// Brushless DC electric motors
//
// shaft shaft shaft body base holes base side bell holes boss prop shaft thread
// diameter height diam length offset colour diam h1 h2 diam position open wire colour diam h1 h1 d pos spokes d h length diam length diam
BLDC0603 = ["BLDC0603", 9.0, 8, 1, 15.5, 1, crimson, 10, 1, 1.5, 1.4, [6,6,6], true, 0.8, grey(20), 9, 1, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0];
BLDC0802 = ["BLDC0802", 11.5, 9.5, 1.5, 12, 0.5, grey(20), 9, 1, 2, 1.6, [6,6,6], true, 1.0, grey(20), 11, 2, 0.75, 0, 0, 3, 0, 0, 0, 0, 0, 0];
BLDC1105 = ["BLDC1105", 14.0, 11.75, 1.5, 11, 0, grey(90), 12.5, 1.6, 1.4, 2, 9, true, 1.0, grey(90), 12, 1, 1, 2, [5,5], 4, 0, 0, 0, 0, 0, 0];
BLDC1306 = ["BLDC1306", 17.75, 14.5, 2, 14, 0, crimson, 16, 1.5, 1, 2, 12, false, 1.0, grey(20), 12, 1, 1, 0, 0, 6, 8, 1, 11.5, 5, 6.5, 5];
BLDC1804 = ["BLDC1804", 23.0, 12, 2, 11, 0, grey(20), 19, 2.5, 1.5, 2, 12, false, 1.5, grey(20), 18, 1, 2.5, 0, 0, 6, 9, 1, 12, 5, 6, 5];
BLDC2205 = ["BLDC2205", 28.0, 17.25, 3, 16, 0, crimson, 26, 2, 3, 3, [19,16,19,16], false, 1.6, grey(20), 22.5, 1, 3.75, 0, 0, 6, 0, 0, 14, 5, 9, 5];
BLDC2212 = ["BLDC2212", 28.0, 27, 3, 26, 0, grey(20), 23, 4, 2, 3, [19,16,19,16], false, 2.0, grey(20), 18, 2, 4, 0, 0, 6, 0, 0, 14, 8, 7, 6];
BLDC3548 = ["BLDC3548", 35.0, 45, 5, 65.5, 1, gold, 32, 7, 1, 3, [25,19,25,19], false, 3.0, grey(20), 32, 2, 4,2.5, [16,16,16],6,12, 3.4, 0, 0, 0, 0];
BLDC4250 = ["BLDC4250", 42.5, 48, 5, 70, 20, crimson, 38, 4, 6, 3, 25, false, 3.5, grey(20), 28, 3, 6, 3, 17, 8, 12, 2, 0, 0, 0, 0];
bldc_motors = [BLDC0603, BLDC0802, BLDC1105, BLDC1306, BLDC1804, BLDC2205, BLDC2212, BLDC3548, BLDC4250];
use <bldc_motor.scad>

View File

@@ -28,6 +28,7 @@ use <screw.scad>
function blower_length(type) = type[2]; //! Length of enclosing rectangle
function blower_width(type) = type[3]; //! Width of enclosing rectangle
function blower_depth(type) = type[4]; //! Height
function blower_size(type) = [blower_length(type), blower_width(type), blower_depth(type)]; //! Size
function blower_bore(type) = type[5]; //! The air intake hole diameter
function blower_screw(type) = type[6]; //! The type of screws needed
function blower_hub(type) = type[7]; //! Rotor hub diameter

58
vitamins/box_section.scad Normal file
View File

@@ -0,0 +1,58 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
//! Box sections.
//
include <../utils/core/core.scad>
include <../utils/tube.scad>
include <../vitamins/sheets.scad>
function box_section_material(type) = type[1]; //! Material description
function box_section_size(type) = type[2]; //! Size
function box_section_thickness(type) = type[3]; //! Wall thickness
function box_section_fillet(type) = type[4]; //! Fillet
function box_section_colour(type) = type[5]; //! Colour
function box_section_colour2(type) = type[6]; //! Colour2, for woven box section
function box_section_is_woven(type) = !is_undef(type[6]); //! Box section is woven, eg carbon fiber
module box_section(type, length, center = true) {
vitamin(str("box_section(", type[0], arg(length, 15), "): ", box_section_material(type), ", length ", length, "mm"));
size = box_section_size(type);
thickness = box_section_thickness(type);
if (box_section_is_woven(type))
translate_z(center ? 0 : length / 2) {
rotate([0, -90, 90])
for (z = [-size.y / 2, size.y / 2 - thickness])
translate_z(z)
woven_sheet(CF1, thickness, box_section_colour(type), box_section_colour2(type), length, size.x)
square([length, size.x], center=true);
rotate([0, -90, 0])
for (z = [-size.x / 2, size.x / 2 - thickness])
translate_z(z)
woven_sheet(CF1, thickness, box_section_colour(type), box_section_colour2(type), length, size.y)
square([length, size.y], center=true);
}
else
color(box_section_colour(type))
rectangular_tube([size.x, size.y, length], center, thickness, box_section_fillet(type));
}

View File

@@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
// Box sections
//
AL12x8x1 = ["AL12x8x1", "Aluminium rectangular box section 12mm x 8mm x 1mm", [12, 8], 1, 0.5, silver, undef];
AL20x20x2 = ["AL20x20x2", "Aluminium rectangular box section 20mm x 20mm x 2mm", [20, 20], 2, 0.5, silver, undef];
CF10x10x1 = ["CF10x10x1", "Carbon fiber rectangular box section 10mm x 10mm x 1mm", [10, 10], 1, 0.5, grey(35), grey(20)];
box_sections = [AL12x8x1, AL20x20x2, CF10x10x1];
use <box_section.scad>

View File

@@ -26,89 +26,138 @@ use <../utils/round.scad>
function gs_diameter(type) = type[2]; //! Can diameter
function gs_height(type) = type[3]; //! Can height
function gs_pitch(type) = type[4]; //! Screw pitch
function gs_lug_w(type) = type[5]; //! Screw lug width
function gs_lug_t(type) = type[6]; //! Screw lug thickness
function gs_hole_d(type) = type[7]; //! Screw hole diameter
function gs_offset(type) = type[8]; //! Offset of the shaft from the centre of the can
function gs_boss_d(type) = type[9]; //! Boss around the shaft diameter
function gs_boss_h(type) = type[10]; //! Boss around the shaft height
function gs_shaft_d(type) = type[11]; //! Shaft diameter
function gs_shaft_flat(type) = type[12]; //! Shaft width across the flats
function gs_shaft_length(type) = type[13]; //! Shaft length
function gs_flat_length(type) = type[14]; //! Shaft flat length
function gs_bulge_w(type) = type[15]; //! Plastic bulge width
function gs_bulge_d(type) = type[16]; //! Plastic bulge depth from centre
function gs_bulge_h(type) = type[17]; //! Plastic bulge height
function gs_bulge2_w(type) = type[18]; //! Plastic rear bulge width
function gs_bulge2_d(type) = type[19]; //! Plastic rear bulge depth from centre
function gs_bulge2_h(type) = type[20]; //! Plastic rear bulge height
function gs_radius(type) = type[4]; //! Top - or bottom + corner radius
function gs_motor(type) = type[5]; //! Motor diameter and height if separate from gearbox
function gs_pitch(type) = type[6]; //! Screw pitch
function gs_lug_w(type) = type[7]; //! Screw lug width
function gs_lug_t(type) = type[8]; //! Screw lug thickness
function gs_hole_d(type) = type[9]; //! Screw hole diameter
function gs_offset(type) = type[10]; //! Offset of the shaft from the centre of the can
function gs_boss_d(type) = type[11]; //! Boss around the shaft diameter
function gs_boss_h(type) = type[12]; //! Boss around the shaft height
function gs_shaft_d(type) = type[13]; //! Shaft diameter
function gs_shaft_flat(type) = type[14]; //! Shaft width across the flats
function gs_shaft_length(type) = type[15]; //! Shaft length
function gs_flat_length(type) = type[16]; //! Shaft flat length
function gs_bulge(type) = type[17]; //! Plastic bulge width, depth, height, z offset
function gs_bulge2(type) = type[18]; //! Plastic rear bulge width, depth, height
function gs_wire_d(type) = type[19]; //! Wire diameter
function gs_wires(type) = type[20]; //! Wire colours and grouping
module geared_stepper_screw_positions(type) //! Place children at the screw positions
for(side = [-1, 1])
translate([side * gs_pitch(type) / 2, -gs_offset(type)])
children();
motor_colour = "#9BA2AC";
gearbox_colour = "#FFF7EE";
module geared_stepper(type) { //! Draw the specified geared stepper
vitamin(str("geared_stepper(", type[0], "): Geared stepper - ", type[1]));
radius = gs_diameter(type) / 2;
height = gs_height(type);
motor = gs_motor(type);
height = gs_height(type) - motor.y;
offset = gs_offset(type);
color("silver") {
translate([0, -offset])
rounded_cylinder(r = radius, h = height, r2 = 1);
lug_t = gs_lug_t(type);
bulge = gs_bulge(type);
bulge_z = bulge[3];
bulge2 = gs_bulge2(type);
wires = gs_wires(type);
// Gearbox
color(motor.y ? gearbox_colour : motor_colour) {
difference() {
rad = gs_radius(type);
translate([0, -offset])
if(rad >= 0)
rounded_cylinder(r = radius, h = height, r2 = rad);
else
translate_z(height)
vflip()
rounded_cylinder(r = radius, h = height, r2 = -rad);
if(!lug_t)
geared_stepper_screw_positions(type)
cylinder(d = gs_hole_d(type), h = 10, center = true);
}
cylinder(d = gs_boss_d(type), h = 2 * gs_boss_h(type), center = true);
linear_extrude(gs_lug_t(type))
difference() {
hull()
if(lug_t)
linear_extrude(lug_t)
difference() {
hull()
geared_stepper_screw_positions(type)
circle(d = gs_lug_w(type));
geared_stepper_screw_positions(type)
circle(d = gs_lug_w(type));
circle(d = gs_hole_d(type));
}
geared_stepper_screw_positions(type)
circle(d = gs_hole_d(type));
}
translate([0, -offset - radius, eps])
cube([gs_bulge_w(type) - 2, 2 * (gs_bulge_d(type) - radius) - 2, 2 * eps], center = true);
if(!bulge_z)
translate([0, -offset - radius, eps])
cube([bulge.x - 2, 2 * (bulge.y - radius) - 2, 2 * eps], center = true);
}
// Motor
if(motor.y)
color("#9BA2AC")
translate([0, -offset, height])
rotate_extrude()
union() {
r = motor.x / 2;
rad = motor[2];
square([r - rad, rad]);
translate([0, motor.y - rad])
square([r - rad, rad]);
hull()
for(y = [2 * rad, motor.y - 2 * rad])
translate([r - rad, y])
circle(rad);
}
// Shaft
f = gs_shaft_flat(type);
two_flats = f < 0;
vflip()
color(brass) {
color(two_flats ? brass : gearbox_colour) {
d = gs_shaft_d(type);
h = gs_shaft_length(type);
linear_extrude(h)
intersection() {
circle(d = d);
square([d + 1, gs_shaft_flat(type)], center = true);
translate([0, two_flats ? 0 : (f - d) / 2])
square([d + 1, abs(f)], center = true);
}
cylinder(d = d, h = h - gs_flat_length(type));
}
color("skyblue") {
h1 = gs_bulge_h(type);
translate([0, - offset - radius, eps])
rounded_rectangle([gs_bulge_w(type), 2 * (gs_bulge_d(type) - radius), h1], 0.5, center = false);
// Wire block
color(bulge_z ? "white" : "skyblue") {
translate([0, - offset - radius, eps + bulge[3]])
rounded_rectangle([bulge.x, 2 * (bulge.y - radius), bulge.z], 0.5, center = false);
h2 = gs_bulge2_h(type);
translate([0, - offset, h1 + 1 - h2])
linear_extrude(h2)
round(0.5)
intersection() {
circle(gs_bulge2_d(type));
if(bulge2.z)
translate([0, - offset, bulge.z + 1 - bulge2.z])
linear_extrude(bulge2.z)
round(0.5)
intersection() {
circle(bulge2.y);
translate([0, -50])
square([gs_bulge2_w(type), 100], center = true);
}
translate([0, -50])
square([bulge2.x, 100], center = true);
}
}
translate_z(2.5)
for(i = [0 : 4])
translate([i - 2.5, 0])
rotate([90, 0, 0])
color(["yellow", "orange", "red", "pink", "blue"][i])
cylinder(d = 1, h = radius + offset + 10);
wire_d = gs_wire_d(type);
for(j = [0 : len(wires) - 1], i = [0 : len(wires[j]) - 1])
translate([(i - len(wires[j]) / 2 + 0.5) * wire_d, 0, bulge_z + (j ? bulge.z - 2.5 : 2.5)])
rotate([90, 0, 0])
color(wires[j][i])
cylinder(d = wire_d, h = radius + offset + 10);
}

View File

@@ -20,8 +20,16 @@
//
//! Geared tin can steppers
//
28BYJ_48 = ["28BYJ_48", "28BYJ-48 5V", 28, 19, 35, 7, 0.85, 4.2, 8, 9, 1.5, 5, 3, 10, 6, 14.7, 17, 16.5, 17.7, 15.5, 13.8 ];
// d h r m p l l h o b b s f s f b b w
// i e a o i u u o f o o h l h l u u i
// a i d t t g g l f s s a a a a l l r
// g i o c e s s s f t f t g g e
// h u r h w t e t t e e
// t s d t d h w l 2 d
// d h r d l w d h z w d h
28BYJ_48 = ["28BYJ_48", "28BYJ-48 5V", 28, 19, 1, [ 0, 0, 0], 35, 7, 0.85, 4.2, 8, 9, 1.5, 5,-3.0, 10, 6, [14.7, 17, 16.5, 0], [17.7, 15.5, 13.8], 1, [["yellow", "orange", "red", "pink", "blue"]] ];
35BYGHJ75 = ["35BYGHJ75", "35BYGHJ75 0.4A",37, 37, -2, [35, 22, 1], 27, 0, 0, 3.0, 7, 12, 3.0, 5, 4.5, 17, 10, [ 7.7, 20.7, 9.25, 21], [ 0, 0, 0], 1.3,[["brown", "red"], ["yellow", "green"]] ];
geared_steppers = [28BYJ_48];
geared_steppers = [28BYJ_48, 35BYGHJ75];
use <geared_stepper.scad>

View File

@@ -55,7 +55,7 @@ outlet_spades = [[spade4p8ll, 8, -7, -2, 90],
// w h r t
IEC_fused_inlet = ["IEC_fused_inlet", "IEC fused inlet JR-101-1F", M3_cs_cap_screw, 36, 27, 16, 31, 3, 28, 31, 2, 2.0, 30, 33, 4, 3.0, 44, 15, fused_spades, false ];
IEC_fused_inlet2= ["IEC_fused_inlet2","IEC fused inlet old", M3_cs_cap_screw, 36, 27, 14, 31, 3, 28, 31, 2, 2.5, 30, 33, 4, 2.5, 44, 18, fused_spades2, false ];
IEC_320_C14_switched_fused_inlet = ["IEC_switched_fused_inlet", "IEC320 C14 switched fused inlet module",
IEC_320_C14_switched_fused_inlet = ["IEC_320_C14_switched_fused_inlet", "IEC320 C14 switched fused inlet module",
M3_cs_cap_screw, 40, 27, 16,46.8,3,28, 48, 2.4, 1.0, 33, 57, 4, 3.0, 48,16.5, iec320c14FusedSwitchedSpades, false ];
IEC_inlet = ["IEC_inlet", "IEC inlet", M3_cs_cap_screw, 40, 28, 18, 20, 3, 28, 20.5, 4, 2.5, 37, 23, 1, 2.5, 48, 14, inlet_spades, false ];
IEC_inlet_atx = ["IEC_inlet_atx", "IEC inlet for ATX", M3_cs_cap_screw, 40, 27, 18, 19, 3, 30.5, 22, 2, 2.0, 30.5, 22, 2, 4.0, 50, 15, atx_spades, false ];

View File

@@ -32,7 +32,7 @@ function leadnut_flange_t(type) = type[6]; //! Flange thickness
function leadnut_flange_offset(type) = type[7]; //! Offset of the flange from the top
function leadnut_holes(type) = type[8]; //! The number of screw holes
function leadnut_hole_dia(type) = type[9]; //! The diameter of the screw holes
function leadnut_hole_pitch(type) = type[10]; //! The radia pitch of the screw holes
function leadnut_hole_pitch(type) = type[10]; //! The radial pitch of the screw holes
function leadnut_screw(type) = type[11]; //! The type of the fixing screws
function leadnut_pitch(type) = type[12]; //! Screw pitch
function leadnut_lead(type) = type[13]; //! Screw lead

View File

@@ -62,6 +62,7 @@ function opengrab_depth() = depth; //! Module heig
function opengrab_target_thickness() = target; //! Target sheet thickness
function opengrab_pcb() = pcb; //! The PCB
function opengrab_pcb_z() = depth - pillar - pcb_thickness(pcb); //! PCB offset from the front
function opengrab_screw_depth() = 4; //! Max screw depth in pillars
module opengrab() { //! Draw OpenGrab module
vitamin("opengrab(): OpenGrab V3 electro permanent magnet");

View File

@@ -55,6 +55,9 @@ function pcb_polygon(type) = type[14]; //! Optional outline polygon for odd
function pcb_screw(type, cap = hs_cap) = Len(type[15]) ? type[15] : find_screw(cap, screw_smaller_than(pcb_hole_d(type))); //! Mounting screw type
function pcb_size(type) = [pcb_length(type), pcb_width(type), pcb_thickness(type)]; //! Length, width and thickness in a vector
function pcb_component(type, name, index = 0) = //! Return the component specified by name and index
[for(component = pcb_components(type)) if(component[3] == name) component][index];
function pcb_grid_pos(type, x, y, z = 0) = //! Returns a pcb grid position
[-pcb_length(type) / 2 + pcb_grid(type).x + 2.54 * x,

View File

@@ -31,4 +31,4 @@ KP001 = ["KP001", 12, 19, 71, 56, 16, 7.0, 6, 38, 14.5, 4, 32, M6_clearanc
kp_pillow_blocks = [KP08_15, KP08_18, KP000, KP001];
use <kp_pillow_block.scad>
use <pillow_block.scad>

View File

@@ -44,6 +44,7 @@ function psu_name(type) = type[1]; //! The part name
function psu_length(type) = type[2]; //! Length
function psu_width(type) = type[3]; //! Width
function psu_height(type) = type[4]; //! Height
function psu_size(type) = [psu_length(type), psu_width(type), psu_height(type)]; //! Size
function psu_screw(type) = type[5]; //! Screw type
function psu_screw_hole_radius(type) = type[6]; //! Clearance hole for screw, bigger than normal on ATX
function atx_psu(type) = type[7]; //! True if an ATX style PSU

View File

@@ -42,7 +42,7 @@ function pulley_screw(type) = type[13]; //! Grub screw type
function pulley_screws(type) = type[14]; //! Number of grub screws
function pulley_ir(type) = pulley_od(type) / 2 - (pulley_teeth(type) ? belt_tooth_height(pulley_belt(type)) : 0); //! Inside radius of the teeth
function pulley_pr(type) = let(belt = pulley_belt(type)) //! Pitch radius
function pulley_pr(type, belt = undef) = let(belt = is_undef(belt) ? pulley_belt(type) : belt) //! Pitch radius, `belt` only needed for non-standard belt over smooth pulleys
pulley_teeth(type) ? pulley_teeth(type) * belt_pitch(belt) / 2 / PI
: pulley_ir(type) + belt_thickness(belt) - belt_pitch_height(belt);
@@ -53,7 +53,7 @@ function pulley_extent(type) = max(pulley_flange_dia(type), pulley_hub_dia(type)
T_angle = 40;
GT_r = 0.555;
module pulley(type, colour = silver) { //! Draw a pulley
module pulley(type, colour = silver) { //! Draw a pulley, any children are placed above.
teeth = pulley_teeth(type);
od = pulley_od(type);
@@ -138,6 +138,10 @@ module pulley(type, colour = silver) { //! Draw a pulley
else
core();
}
if($children)
translate_z(pulley_height(type))
children();
}
module pulley_assembly(type, colour = silver) { //! Draw a pulley with its grub screws in place

View File

@@ -37,18 +37,19 @@ function rail_groove_width(type)=type[11]; //! Groove width
function rail_screw_height(type, screw) = rail_height(type) - rail_bore_depth(type) + screw_head_depth(screw, rail_hole(type)); //! Position screw taking into account countersink into counterbored hole
function carriage_length(type) = type[0]; //! Overall length
function carriage_block_length(type) = type[1]; //! Length of the metal part
function carriage_width(type) = type[2]; //! Width of carriage
function carriage_height(type) = type[3]; //! Height of carriage
function carriage_size(type) = [ type[0], type[2], type[3] ]; //! Size of carriage
function carriage_clearance(type) = type[4]; //! Gap under the carriage
function carriage_pitch_x(type) = type[5]; //! Screw hole x pitch
function carriage_pitch_y(type) = type[6]; //! Screw hole y pitch
function carriage_screw(type) = type[7]; //! Carriage screw type
function carriage_rail(type) = type[8]; //! Rail type
function carriage_length(type) = type[1]; //! Overall length
function carriage_block_length(type) = type[2]; //! Length of the metal part
function carriage_width(type) = type[3]; //! Width of carriage
function carriage_height(type) = type[4]; //! Height of carriage
function carriage_clearance(type) = type[5]; //! Gap under the carriage
function carriage_pitch_x(type) = type[6]; //! Screw hole x pitch
function carriage_pitch_y(type) = type[7]; //! Screw hole y pitch
function carriage_screw(type) = type[8]; //! Carriage screw type
function carriage_rail(type) = type[9]; //! Rail type
function carriage_screw_depth(type) = 2 * screw_radius(carriage_screw(type)); //! Carriage thread depth
function carriage_travel(type, rail_length) = rail_length - carriage_length(type); //! How far the carriage can travel on a given length rail
function carriage_size(type) = [ carriage_length(type), carriage_width(type), carriage_height(type) ]; //! Size of carriage
function rail_holes(type, length) = //! Number of holes in a rail given its `length`
floor((length - 2 * rail_end(type)) / rail_pitch(type)) + 1;
@@ -74,6 +75,8 @@ module carriage_hole_positions(type) { //! Position children over screw holes
}
module carriage(type, end_colour = grey(20), wiper_colour = grey(20)) { //! Draw the specified carriage
vitamin(str("carriage(", type[0], "_carriage): Linear rail carriage ", type[0]));
total_l = carriage_length(type);
block_l = carriage_block_length(type);
block_w = carriage_width(type);
@@ -142,6 +145,7 @@ module rail(type, length, colour = grey(90), use_polycircles = false) { //! Draw
height = rail_height(type);
vitamin(str("rail(", type[0], ", ", length, "): Linear rail ", type[0], " x ", length, "mm"));
assert(rail_end(type) < (rail_pitch(type) - rail_bore(type)) / 2, type[0]);
color(colour) {
rbr = rail_bore(type) / 2;

View File

@@ -20,26 +20,29 @@
//
// Rails
//
// Wr Hr E P D d h go gw
// Wr Hr Emin P D d h go gw
MGN5 = [ "MGN5", 5, 3.6, 5, 15, 3.6, 2.4, 0.8, M2_cs_cap_screw, M2_cs_cap_screw, 1, 1 ]; // Screw holes too small for M2 heads
MGN7 = [ "MGN7", 7, 5, 5, 15, 4.3, 2.4, 2.6, M2_cap_screw, M2_cs_cap_screw, 1.5, 1.5 ];
MGN9 = [ "MGN9", 9, 6, 5, 20, 6.0, 3.5, 3.5, M3_cap_screw, M3_cs_cap_screw, 1.5, 1.5 ];
MGN12 =[ "MGN12", 12, 8, 10, 25, 6.0, 3.5, 4.5, M3_cap_screw, M3_cs_cap_screw, 2.25, 2.75];
MGN12 =[ "MGN12", 12, 8, 7.5, 25, 6.0, 3.5, 4.5, M3_cap_screw, M3_cs_cap_screw, 2.25, 2.75];
MGN15 =[ "MGN15", 15, 10, 10, 40, 6.0, 3.5, 5.0, M3_cap_screw, M3_cs_cap_screw, 2.5, 2.75 ];
SSR15= [ "SSR15", 15, 12.5, 10, 60, 7.5, 4.5, 5.3, M4_cap_screw, M4_cs_cap_screw, 2.5, 2.75 ];
//
// Carriages
//
// L L1 W H H1 C B
MGN5_carriage = [ 16, 9.6, 12, 6, 1.5, 0, 8, M2_cap_screw, MGN5 ];
MGN7C_carriage = [ 23, 14.3, 17, 8, 1.5, 8, 12, M2_cap_screw, MGN7 ];
MGN9C_carriage = [ 29.7, 20.8, 20, 10, 2, 10, 15, M3_cap_screw, MGN9 ];
MGN12C_carriage = [ 34.7, 21.7, 27, 13, 3, 15, 20, M3_cap_screw, MGN12 ];
MGN12H_carriage = [ 45.4, 32.4, 27, 13, 3, 20, 20, M3_cap_screw, MGN12 ];
MGN15C_carriage = [ 43.3, 27.7, 32, 16, 4, 20, 25, M3_cap_screw, MGN15 ];
SSR15_carriage = [ 40.3, 23.3, 34, 24, 4.5, 0, 26, M4_cap_screw, SSR15 ];
// L L1 W H H1 C B
MGN5C_carriage = ["MGN5C", 16, 9.6, 12, 6, 1.5, 0, 8, M2_cap_screw, MGN5 ];
MGN7C_carriage = ["MGN7C", 23, 14.3, 17, 8, 1.5, 8, 12, M2_cap_screw, MGN7 ];
MGN7H_carriage = ["MGN7H", 30.8, 21.8, 17, 8, 1.5,13, 12, M2_cap_screw, MGN7 ];
MGN9C_carriage = ["MGN9C", 29.7, 20.8, 20, 10, 2, 10, 15, M3_cap_screw, MGN9 ];
MGN9H_carriage = ["MGN9H", 39.9, 29.9, 20, 10, 2, 16, 15, M3_cap_screw, MGN9 ];
MGN12C_carriage = ["MGN12C", 34.7, 21.7, 27, 13, 3, 15, 20, M3_cap_screw, MGN12 ];
MGN12H_carriage = ["MGN12H", 45.4, 32.4, 27, 13, 3, 20, 20, M3_cap_screw, MGN12 ];
MGN15C_carriage = ["MGN15C", 43.3, 27.7, 32, 16, 4, 20, 25, M3_cap_screw, MGN15 ];
SSR15_carriage = ["SSR15", 40.3, 23.3, 34, 24, 4.5, 0, 26, M4_cap_screw, SSR15 ];
rails = [MGN5, MGN7, MGN9, MGN12, MGN15, SSR15];
carriages = [MGN5_carriage, MGN7C_carriage, MGN9C_carriage, MGN12C_carriage, MGN12H_carriage, MGN15C_carriage, SSR15_carriage];
carriages = [MGN5C_carriage, MGN7C_carriage, MGN7H_carriage, MGN9C_carriage, MGN9H_carriage, MGN12C_carriage, MGN12H_carriage, MGN12H_carriage, MGN15C_carriage, SSR15_carriage];
use <rail.scad>

View File

@@ -284,10 +284,10 @@ function screw_polysink_r(type, z) = //! Countersink hole profile corrected for
)
limit(head_rad + head_t - z + (sqrt(2) - 1) * layer_height / 2, screw_clearance_radius(type), head_rad);
module screw_polysink(type, h = 100, alt = false) { //! A countersink hole made from stacked polyholes for printed parts
module screw_polysink(type, h = 100, alt = false, sink = 0) { //! A countersink hole made from stacked polyholes for printed parts, default is flush, `sink` can be used to recess the head
head_depth = screw_head_depth(type);
assert(head_depth, "Not a countersunk screw");
layers = ceil(head_depth / layer_height);
layers = ceil((head_depth + sink) / layer_height);
rmin = screw_clearance_radius(type);
sides = sides(rmin);
lh = layer_height + eps;
@@ -295,7 +295,7 @@ module screw_polysink(type, h = 100, alt = false) { //! A countersink hole made
for(side = [0, 1]) mirror([0, 0, side]) {
for(i = [0 : layers - 1])
translate_z(i * layer_height) {
r = screw_polysink_r(type, i * layer_height + layer_height / 2);
r = screw_polysink_r(type, i * layer_height + layer_height / 2 - sink);
if(alt)
rotate(i % 2 == layers % 2 ? 180 / sides : 0)
poly_cylinder(r = r, h = lh, center = false, sides = sides);

View File

@@ -79,6 +79,7 @@ M2_cs_cap_screw = ["M2_cs_cap","M2 cs cap", hs_cs_cap,2, 3.8, 0, 0.65,1.3
M3_cs_cap_screw = ["M3_cs_cap","M3 cs cap", hs_cs_cap,3, 6.0, 0, 1.05,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M4_cs_cap_screw = ["M4_cs_cap","M4 cs cap", hs_cs_cap,4, 8.0, 0, 1.49,2.5, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
M5_cs_cap_screw = ["M5_cs_cap","M5 cs cap", hs_cs_cap,5,10.0, 0, 3.00,3.0, 22, M5_washer, M5_nut, M5_tap_radius, M5_clearance_radius];
M6_cs_cap_screw = ["M6_cs_cap","M6 cs cap", hs_cs_cap,6,12.0, 0, 3.00,4.0, 24, M6_washer, M6_nut, M6_tap_radius, M6_clearance_radius];
M2_dome_screw = ["M2_dome", "M2 dome", hs_dome, 2, 3.5, 1.3, 0.6, 1.3, 16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius];
M3_dome_screw = ["M3_dome", "M3 dome", hs_dome, 3, 5.7, 1.65, 1.04,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
@@ -107,15 +108,16 @@ No2_screw = ["No2", "No2 pan wood", hs_pan, 2.2, 4.2, 1.7, 0, 0
No4_screw = ["No4", "No4 pan wood", hs_pan, 3.0, 5.5, 2.0, 0, 0, 0 ,M3p5_washer, false, No4_pilot_radius, No4_clearance_radius];
No6_screw = ["No6", "No6 pan wood", hs_pan, 3.5, 6.7, 2.2, 0, 0, 0 , M4_washer, false, No6_pilot_radius, No6_clearance_radius];
No6_cs_screw = ["No6_cs", "No6 cs wood", hs_cs, 3.5, 7.0, 0, 0, 0, 0, M4_washer, false, No6_pilot_radius, No6_clearance_radius];
No8_screw = ["No8", "No8 pan wood", hs_pan, 4.2, 8.2, 3.05, 0, 0, 0 , M5_washer, false, No8_pilot_radius, No8_clearance_radius];
screw_lists = [
[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw],
[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw],
[ 0, 0, M3_low_cap_screw],
[ M2_cs_cap_screw, 0, M3_cs_cap_screw, M4_cs_cap_screw, M5_cs_cap_screw],
[ M2_cs_cap_screw, 0, M3_cs_cap_screw, M4_cs_cap_screw, M5_cs_cap_screw, M6_cs_cap_screw],
[ M2_dome_screw, 0, M3_dome_screw, M4_dome_screw, M5_dome_screw],
[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw],
[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, M5_pan_screw, M6_pan_screw, No632_pan_screw],
[ No2_screw, 0, No4_screw, No6_screw, No6_cs_screw],
[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw],
[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, M5_pan_screw, M6_pan_screw, No632_pan_screw],
[ No2_screw, 0, No4_screw, No6_screw, No8_screw, No6_cs_screw],
[ 0, 0, M3_grub_screw, M4_grub_screw]
];

Some files were not shown because too many files have changed in this diff Show More