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

Compare commits

...

230 Commits

Author SHA1 Message Date
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
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
Chris Palmer
f573a91a09 Removed redundant rounded_rectangle center = false. 2021-02-08 09:41:07 +00:00
Chris Palmer
d75aff2ccd rounded_retangle() centre now defaults to false. 2021-02-08 09:24:00 +00:00
Chris Palmer
491d85156c Merge branch 'martinbudden-rounded_cubes' 2021-02-08 08:29:50 +00:00
Chris Palmer
c89ce6843f Updated images and readme. 2021-02-08 08:29:08 +00:00
Chris Palmer
1915dae034 Merge branch 'rounded_cubes' of https://github.com/martinbudden/NopSCADlib into martinbudden-rounded_cubes 2021-02-07 22:17:22 +00:00
Chris Palmer
05e8055ce2 Merge branch 'martinbudden-btt_skr_e3_turbo' 2021-02-07 22:01:41 +00:00
Chris Palmer
21822b9abb Updated pictures and readme. 2021-02-07 22:01:26 +00:00
Chris Palmer
d83d4b89bf Merge branch 'btt_skr_e3_turbo' of https://github.com/martinbudden/NopSCADlib into martinbudden-btt_skr_e3_turbo 2021-02-07 21:48:16 +00:00
Chris Palmer
613152f589 Merge branch 'martinbudden-bl30x10' 2021-02-07 21:46:28 +00:00
Chris Palmer
d90c00d140 Updated images and readme. 2021-02-07 21:46:15 +00:00
Chris Palmer
b52ca9589a Merge branch 'bl30x10' of https://github.com/martinbudden/NopSCADlib into martinbudden-bl30x10 2021-02-07 21:25:53 +00:00
Martin Budden
0d024060fc Added BTT_SKR_E3_TURBO. 2021-02-07 07:51:10 +00:00
Martin Budden
c4fe1d1098 Added assertion to check r value. Used extrud_if. 2021-02-07 07:29:02 +00:00
Chris Palmer
a3ced6de45 Merge branch 'martinbudden-mgn9_correction' 2021-02-06 15:29:51 +00:00
Chris Palmer
1cdfe3267c Merge branch 'mgn9_correction' of https://github.com/martinbudden/NopSCADlib into martinbudden-mgn9_correction 2021-02-06 15:28:49 +00:00
Chris Palmer
b67cf4ce97 Library printed parts now make use of stl() child. 2021-02-06 15:24:19 +00:00
Chris Palmer
5bac2bf46d stl() and dxf() can now have the code to make the STL or DXF as a child.
This allows them to be replaced by the STL or DXF when making assembly views.

use_dxf() and use_stl() make use of $cwd and $target, so can be in bom.scad
and be documented.

Corrected the spelling of widget in BOM test.
2021-02-06 15:23:10 +00:00
Chris Palmer
079168142b Views.py and plateup.py now define $cwd and $target. 2021-02-06 15:12:21 +00:00
Chris Palmer
cb30f0c63d Times for parts that no longer exist pruned from build times.
Now shows changes to the total time.
2021-02-06 10:39:39 +00:00
Martin Budden
812fbc106c Updated screw hole position. 2021-02-04 19:59:28 +00:00
Martin Budden
dd38fa6e5d Added 30x10 square radial fan. 2021-02-04 18:26:44 +00:00
Martin Budden
5cdcd4ad37 Corrected MGN9 rail end value. 2021-02-03 11:24:44 +00:00
Chris Palmer
4cb324ed37 Merge branch 'martinbudden-rails_rename' 2021-02-03 07:10:27 +00:00
Chris Palmer
eb997aa18c Updated readme for rails. Note interface change. 2021-02-03 07:10:07 +00:00
Chris Palmer
f09343a285 Merge branch 'rails_rename' of https://github.com/martinbudden/NopSCADlib into martinbudden-rails_rename 2021-02-03 06:38:07 +00:00
Chris Palmer
54aab027bd Merge branch 'martinbudden-skr_mini_e3_update' 2021-02-03 06:35:54 +00:00
Chris Palmer
cc61a11602 Updated PCB images. 2021-02-03 06:35:42 +00:00
Chris Palmer
9cf2e9d7c3 Merge branch 'skr_mini_e3_update' of https://github.com/martinbudden/NopSCADlib into martinbudden-skr_mini_e3_update 2021-02-03 06:26:36 +00:00
Chris Palmer
9da8a3cb26 Set ngb for most library assemblies. 2021-02-03 06:21:44 +00:00
Chris Palmer
36521cf0b9 Set ngb parameter of assembly() to remove it from the global BOM and merge
its parts into it parent's global BOM column.
2021-02-03 06:21:17 +00:00
Martin Budden
22b7aa956c Renamed rounded_rectangle_* to rounded_cube_*. 2021-02-02 17:32:44 +00:00
Martin Budden
f760aaa20a Changed carriage to specify its rail type. 2021-02-02 12:23:03 +00:00
Martin Budden
1c445385b4 Made C version of linear rails and carriages explicit. 2021-02-01 19:21:50 +00:00
Martin Budden
45f3fc275f BTT_SKR_MINI_E3_V2_0 tidy and correction. 2021-02-01 19:19:20 +00:00
Chris Palmer
f7fbbd5fe4 No longer runs markdown twice to make printme.html.
Instead uses empty spans to mark page breaks and then replaces them.
2021-02-01 00:10:54 +00:00
Chris Palmer
a769a38dff Generation of the html files included in the build times. 2021-01-31 10:52:26 +00:00
Chris Palmer
0485eeeb34 Removed page break at the end for printme.html 2021-01-31 10:50:20 +00:00
Chris Palmer
0a7208ff5a Fixed codespell path for multi-target builds. 2021-01-31 10:47:54 +00:00
Chris Palmer
f32182d6df Merge branch 'martinbudden-pulley_colour' 2021-01-26 17:35:02 +00:00
Chris Palmer
84fbd05f9b Updated readme for pulley colour. 2021-01-26 17:34:43 +00:00
Chris Palmer
2a1fa3fe6b Merge branch 'pulley_colour' of https://github.com/martinbudden/NopSCADlib into martinbudden-pulley_colour 2021-01-26 17:10:58 +00:00
Chris Palmer
176dc3231c Merge branch 'martinbudden-screw_m5_dome' 2021-01-26 17:03:32 +00:00
Chris Palmer
e7ac18e3c0 Updated images and readme. 2021-01-26 17:03:16 +00:00
Martin Budden
74b8dcb6d8 Added colour parameter to pulley. 2021-01-26 15:20:20 +00:00
Martin Budden
6269575fd4 Added M5_dome_screw. 2021-01-26 15:12:52 +00:00
Chris Palmer
2923e35725 Added microswitch_op_tol() and microswitch_fp_max() functions. 2021-01-24 21:44:57 +00:00
Chris Palmer
5a1b06fbb9 Merge branch 'martinbudden-BTT_SKR_MINI_E3_V2_0' 2021-01-24 11:20:37 +00:00
Chris Palmer
fd174bbfb4 Updated readme and images. 2021-01-24 11:20:01 +00:00
Chris Palmer
186f31bb09 Merge branch 'BTT_SKR_MINI_E3_V2_0' of https://github.com/martinbudden/NopSCADlib into martinbudden-BTT_SKR_MINI_E3_V2_0 2021-01-24 10:59:03 +00:00
Martin Budden
80f0490d58 Added BTT_SKR_MINI_E3_V2_0 pcb. 2021-01-24 10:55:49 +00:00
Chris Palmer
c9e9942070 Fixed some paths that used NopSCADlib instead of .. 2021-01-23 21:15:00 +00:00
Chris Palmer
e41366e20c Added explicit error message when tmp.png is not generated as expected.
Prints a newline after test runs rather than before.
2021-01-21 12:49:48 +00:00
Chris Palmer
0595fb5a92 Merge branch 'martinbudden-btt_skr_1_4' 2021-01-18 15:57:04 +00:00
Chris Palmer
abb676b75c Updated readme and cover picture for BTT_SKR_V1_4_TURBO PCB.
Added list of hidden pcbs to hide the boring ones.
Smaller PCBs closer together to make space.
2021-01-18 15:56:09 +00:00
Chris Palmer
19bae20e24 Merge branch 'btt_skr_1_4' of https://github.com/martinbudden/NopSCADlib into martinbudden-btt_skr_1_4 2021-01-18 12:54:03 +00:00
Chris Palmer
a7d181ffc4 Merge branch 'martinbudden-rectangular_tube' 2021-01-18 12:52:53 +00:00
Chris Palmer
6b2f8d282b Updated readme and images. 2021-01-18 12:52:41 +00:00
Chris Palmer
5bb95b2406 Merge branch 'rectangular_tube' of https://github.com/martinbudden/NopSCADlib into martinbudden-rectangular_tube 2021-01-18 10:34:51 +00:00
Chris Palmer
dc3905b284 Removed redundant longer = true with nyloc = true. 2021-01-18 10:33:17 +00:00
Martin Budden
bd2ea3f284 Added a rectangular tube. 2021-01-17 16:34:09 +00:00
Martin Budden
62183bcadc Added BTT SKR V1.4 Turbo pcb. 2021-01-17 16:29:42 +00:00
Chris Palmer
7f9122ae66 Added --hardwarnings to openscad.py 2021-01-15 18:13:20 +00:00
Chris Palmer
93b260b7b9 Added screw_length() to calculuate screw lengths includin washers, inserts and nuts. 2021-01-15 18:12:37 +00:00
Chris Palmer
c33876530e Merge branch 'martinbudden-green_terminals' 2021-01-13 21:31:25 +00:00
Chris Palmer
8fea8f437b Updated images and readme for green terminals. 2021-01-13 21:31:14 +00:00
Chris Palmer
bc3ef607af Merge branch 'green_terminals' of https://github.com/martinbudden/NopSCADlib into martinbudden-green_terminals 2021-01-13 21:17:08 +00:00
Chris Palmer
6bcdc24cd3 Updated readme an images for ESP-01. 2021-01-13 21:12:29 +00:00
Chris Palmer
b8b4232882 Merge branch 'ESP8266' of https://github.com/martinbudden/NopSCADlib 2021-01-13 20:21:43 +00:00
Chris Palmer
0394d9981f Merge branch 'martinbudden-tft35' 2021-01-13 20:20:24 +00:00
Chris Palmer
e4e7096e3c Merge branch 'martinbudden-ESP8266' 2021-01-13 20:18:13 +00:00
Chris Palmer
d71bb4bdfa Remove commented out code. 2021-01-13 20:17:43 +00:00
Chris Palmer
89c3767f21 Update image. 2021-01-13 20:09:16 +00:00
Martin Budden
c837de721d Renamed ESP8266 to ESP_01 and rotated. 2021-01-13 18:52:14 +00:00
Martin Budden
f8c87bd8e3 Added ESP8266. 2021-01-13 17:22:46 +00:00
Martin Budden
ef58fe5818 Minor corrections to positions on BigTreeTech_TFT35v3_0_PCB. 2021-01-13 15:57:27 +00:00
Martin Budden
9c0c0c0acf Added green terminals gt_5x11 and gt_5x17. 2021-01-13 15:51:41 +00:00
Chris Palmer
ac6e8e040a Fix for image magick returning non-integer pixels. 2021-01-12 14:51:55 +00:00
Chris Palmer
accf4f7bc1 Added printed pulleys to the big picture. 2021-01-10 22:31:14 +00:00
Chris Palmer
6bd4638e7d Fixed screw hole position of inverted printed_pulley.
Unexploded assembly view shows round screw holes to represent the tapped state.
2021-01-10 21:28:31 +00:00
Chris Palmer
4cca9d5285 Merge branch 'martinbudden-printed_pulleys' 2021-01-10 12:11:29 +00:00
Chris Palmer
c3fc352288 Fixed orientation of inverted pulley.
Added stl and assembly calls.
Same render handling as pulleys.
Updated pics and readme.
2021-01-10 12:11:03 +00:00
Chris Palmer
a8b634de39 Better pose for pulley test so screws can be seen. 2021-01-10 11:49:32 +00:00
Chris Palmer
1a55a08c59 Merge branch 'printed_pulleys' of https://github.com/martinbudden/NopSCADlib into martinbudden-printed_pulleys 2021-01-09 23:38:48 +00:00
Chris Palmer
8ca4bb5adc Merge branch 'martinbudden-linear_rails' 2021-01-09 23:37:26 +00:00
Chris Palmer
53e3378efe Updated images and readme 2021-01-09 23:37:06 +00:00
Chris Palmer
888199f698 Merge branch 'linear_rails' of https://github.com/martinbudden/NopSCADlib into martinbudden-linear_rails 2021-01-09 20:54:28 +00:00
Chris Palmer
f51e93969d Merge branch 'martinbudden-teardrop_chamfer' 2021-01-09 19:55:45 +00:00
Chris Palmer
757b808f07 Updated readme for teardrops chamfer one side. 2021-01-09 19:55:31 +00:00
Chris Palmer
eca8f2eccc Merge branch 'teardrop_chamfer' of https://github.com/martinbudden/NopSCADlib into martinbudden-teardrop_chamfer 2021-01-09 19:26:36 +00:00
Chris Palmer
450224ec39 Merge branch 'martinbudden-fan_rename' 2021-01-09 19:24:53 +00:00
Chris Palmer
dcd2624a12 Updated readme for blower(BL40x10). 2021-01-09 19:24:06 +00:00
Chris Palmer
83e8502ecb Merge branch 'fan_rename' of https://github.com/martinbudden/NopSCADlib into martinbudden-fan_rename 2021-01-09 19:22:51 +00:00
Chris Palmer
a722df0b2b J-head heater components now hidden when taped. 2021-01-09 19:21:49 +00:00
Chris Palmer
6d223c8d1f Added render to countersink. 2021-01-09 19:11:20 +00:00
Chris Palmer
6d59ea2bc8 Added render option to drag_chain_assembly(). 2021-01-09 18:43:43 +00:00
Martin Budden
b74cbee151 Rendering changes to match pulleys. 2021-01-09 18:15:19 +00:00
Martin Budden
9f7efd50fb Replaced poly_circle bores with circular bores. 2021-01-09 17:52:24 +00:00
Martin Budden
0b14d3fbc4 Added printable pulleys. 2021-01-09 17:52:24 +00:00
Martin Budden
8243b244af Clarified name of BL40x10 blower. 2021-01-09 13:02:57 +00:00
Martin Budden
1a2e04367d Added option to chamfer only one end of a teardrop. 2021-01-09 12:59:01 +00:00
Martin Budden
abc38f2744 Changed linear rails to use a v-slot rather than a square slot. 2021-01-09 12:08:45 +00:00
Chris Palmer
f97070099e Merge branch 'martinbudden-pulley_drawing_efficiency' 2021-01-09 11:15:08 +00:00
Chris Palmer
729891b675 Improved pulley.scad speed. 2021-01-09 11:13:14 +00:00
Chris Palmer
4b533cffd2 Merge branch 'pulley_drawing_efficiency' of https://github.com/martinbudden/NopSCADlib into martinbudden-pulley_drawing_efficiency 2021-01-08 22:06:31 +00:00
Chris Palmer
a40a2190dc Merge branch 'martinbudden-vero_size' 2021-01-08 21:26:32 +00:00
Chris Palmer
6556d14a11 Updated readme for veroboard_size(). 2021-01-08 21:26:18 +00:00
Chris Palmer
c7d12b20c9 Merge branch 'vero_size' of https://github.com/martinbudden/NopSCADlib into martinbudden-vero_size 2021-01-08 21:24:58 +00:00
Chris Palmer
545329b875 Bug fix hygrometer_hole() when h > 0. 2021-01-08 21:24:06 +00:00
Martin Budden
760e3a890d Added vero_size function. 2021-01-08 11:47:34 +00:00
Martin Budden
bd4f7b155b Conditionally rendered pulleys to speed up drawing. 2021-01-08 11:33:17 +00:00
Chris Palmer
16c1eeef27 Documented circle_tangent() and simplified it. 2021-01-06 10:54:21 +00:00
Chris Palmer
800bb89921 Added microswitch_size(). 2021-01-06 09:36:13 +00:00
Chris Palmer
41a0723362 Can now control the number of index_screws in rail_screws() 2021-01-04 15:26:29 +00:00
Chris Palmer
6b8ea9685e Fixed rail_hole_positions() bug. 2021-01-04 14:46:54 +00:00
Chris Palmer
0cf8cb7d28 Added missing vitamin() call in magnet.scad. 2021-01-04 01:04:04 +00:00
Chris Palmer
7c439a687f Fixed openscad.py on Linux. 2021-01-03 09:51:20 +00:00
Chris Palmer
4a95ce528e Merge branch 'martinbudden-pancake_stepper' 2021-01-02 11:02:27 +00:00
Chris Palmer
138f45730b Updated images and readme. 2021-01-02 11:02:06 +00:00
Chris Palmer
8d1ff3584c Merge branch 'pancake_stepper' of https://github.com/martinbudden/NopSCADlib into martinbudden-pancake_stepper 2021-01-02 10:38:27 +00:00
Chris Palmer
26b2b63b6e Merge branch 'martinbudden-rocker' 2021-01-02 10:13:23 +00:00
Chris Palmer
611772d960 Updated readme for rocker. 2021-01-02 10:12:54 +00:00
Chris Palmer
b6e648b485 Merge branch 'rocker' of https://github.com/martinbudden/NopSCADlib into martinbudden-rocker 2021-01-02 10:10:03 +00:00
Chris Palmer
e224ee0ad2 Removed z fight in printed box test. 2021-01-02 10:04:24 +00:00
Chris Palmer
10c3df466b screw_polysink can now have h = 0 to get just the cone. 2021-01-02 10:04:03 +00:00
Martin Budden
3e4eedc25f Added JST connector to NEMA17P in tests. 2020-12-31 12:30:06 +00:00
Chris Palmer
029265e1b9 Add rr_green to global_defs. 2020-12-31 12:27:46 +00:00
Martin Budden
7449857ab7 Added NEMA17P pancake stepper motor. 2020-12-31 12:20:11 +00:00
Martin Budden
49f6da767a Added size and slot convenience functions. Added non-rounded hole. 2020-12-31 11:59:41 +00:00
Chris Palmer
171dff723f Updated gallery pictures 2020-12-30 19:05:14 +00:00
Chris Palmer
85a7494813 Updated gallery images 2020-12-30 09:49:17 +00:00
Chris Palmer
46937e403e Better use of Python regex facilities. 2020-12-30 09:48:46 +00:00
Chris Palmer
8f2532d61b Merge branch 'martinbudden-gt2x16_pulley' 2020-12-29 22:29:57 +00:00
Chris Palmer
84fa528ff7 Updated images and readme for new pulley. 2020-12-29 22:29:11 +00:00
Chris Palmer
807850aac5 Merge branch 'gt2x16_pulley' of https://github.com/martinbudden/NopSCADlib into martinbudden-gt2x16_pulley 2020-12-29 21:45:47 +00:00
Chris Palmer
4ea0883965 Blurb divider now three or more asterisks. 2020-12-29 21:42:05 +00:00
Martin Budden
103ad1827e Added GT2x16_pulley. 2020-12-29 17:25:18 +00:00
Chris Palmer
816adb07e7 Typo. 2020-12-29 12:22:45 +00:00
Chris Palmer
06e1c1a3da Documented project description blurb and openscad.py. 2020-12-29 12:20:32 +00:00
Chris Palmer
46ff632bbb Better screw test layout. 2020-12-29 11:30:14 +00:00
Chris Palmer
fc47b1d9db Merge branch 'martinbudden-m5_cs_cap' 2020-12-28 21:25:11 +00:00
Chris Palmer
de6589a2ef Updated images and readme for M5_cs_cap_screw. 2020-12-28 21:24:04 +00:00
Chris Palmer
c2b3eb6580 Merge branch 'm5_cs_cap' of https://github.com/martinbudden/NopSCADlib into martinbudden-m5_cs_cap 2020-12-28 20:56:50 +00:00
Chris Palmer
ba586b3685 Example images update to match new contersink screws and teardrops. 2020-12-28 20:50:38 +00:00
Chris Palmer
8d22940506 Project blurb can now be split with into sections with markdown horizonal rules
made with asterisks.
If an image is include in the first section the default image is supressed.
2020-12-28 20:49:37 +00:00
Martin Budden
f6f4fcc7e8 Added M5_cs_cap screw 2020-12-28 20:24:46 +00:00
Chris Palmer
31bfa3b268 Merge branch 'master' of https://github.com/nophead/NopSCADlib.git 2020-12-26 20:09:06 +00:00
Chris Palmer
ec44fe96b4 openscad.py now works from the command line. 2020-12-26 20:08:47 +00:00
Chris
9e50d1217d Merge pull request #118 from martinbudden/carriage_fix
Fixed error in carriage_size function.
2020-12-26 19:46:20 +00:00
Martin Budden
87c8bbb9a5 Fixed error in carriage_size function. 2020-12-26 19:42:29 +00:00
Chris Palmer
ed1cc8b488 Fixed typo. 2020-12-24 16:23:22 +00:00
Chris Palmer
4cac382581 Single backtick now used for all code quotes. 2020-12-24 16:04:59 +00:00
Chris Palmer
04b98a3786 One backquote instead of three for code markup test. 2020-12-24 15:19:07 +00:00
Chris Palmer
6f8ff606fa Removed woven_sheet() from the readme.
Removed redundent code.
2020-12-24 09:01:51 +00:00
Chris Palmer
acd5de0fbd Fixed extra BOM entries for woven sheet.
Added render colour to BOM for 3D sheets.
2020-12-24 08:56:54 +00:00
Chris Palmer
cc1e3baaf6 Reimplemeted woven sheets with an eye to speed and interface consistancy. 2020-12-23 21:44:05 +00:00
Chris Palmer
ab50b6f9a6 Merge branch 'woven_sheet' of https://github.com/martinbudden/NopSCADlib 2020-12-23 16:50:30 +00:00
Chris Palmer
d9cb604f92 Merge branch 'martinbudden-carriage_size' 2020-12-23 16:48:55 +00:00
Chris Palmer
52d2a49e1c Updated readme for carriage_size(). 2020-12-23 16:48:26 +00:00
Martin Budden
85cb54ef31 Added sheet with checkerboard texture to simulate carbon fiber. 2020-12-23 07:47:41 +00:00
Martin Budden
cd4447a2e6 Added carriage_size convenience function. 2020-12-23 07:06:58 +00:00
Chris Palmer
9699a70cf5 Merge branch 'martinbudden-rounded_right_triangle' 2020-12-22 13:02:14 +00:00
Chris Palmer
6d79e587aa Updated readme and image for rounded_right_triangle. 2020-12-22 13:00:49 +00:00
Chris Palmer
15b3b3a8c2 Merge branch 'rounded_right_triangle' of https://github.com/martinbudden/NopSCADlib into martinbudden-rounded_right_triangle 2020-12-22 12:39:17 +00:00
Martin Budden
dad2bccbaa Added a rounded right triangle. 2020-12-22 00:02:00 +00:00
189 changed files with 10897 additions and 6632 deletions

1747
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,37 +22,37 @@ The 7 SEGMENT.TTF font from the docs directory is needed for simulating 7 segmen
## Installation
OpenSCAD has to be setup to find libraries by setting the ```OPENSCADPATH``` environment variable to where you want to file your libraries and NopSCADlib needs to be installed
in the directory it points to. This can be done with ```git clone https://github.com/nophead/NopSCADlib.git``` while in that directory or, if you don't want to use GIT,
OpenSCAD has to be setup to find libraries by setting the `OPENSCADPATH` environment variable to where you want to file your libraries and NopSCADlib needs to be installed
in the directory it points to. This can be done with `git clone https://github.com/nophead/NopSCADlib.git` while in that directory or, if you don't want to use GIT,
by downloading https://github.com/nophead/NopSCADlib/archive/master.zip and unzipping it to a directory called NopSCADlib.
The ```NopSCADlib/scripts``` directory needs to be added to the executable search path, ```PATH``` on Windows and ```path``` on Linux and Mac.
The `NopSCADlib/scripts` directory needs to be added to the executable search path, `PATH` on Windows and `path` on Linux and Mac.
The installation can be tested by opening ```NopSCADlib/libtest.scad``` in the OpenSCAD GUI. It should render all the objects in the library in about 1 minute.
The installation can be tested by opening `NopSCADlib/libtest.scad` in the OpenSCAD GUI. It should render all the objects in the library in about 1 minute.
Running ```tests``` from the command line will run all the tests in the ```tests``` directory and build the ```readme.md``` catalog for GitHub and render it to ```readme.html```
Running `tests` from the command line will run all the tests in the `tests` directory and build the `readme.md` catalog for GitHub and render it to `readme.html`
for local preview.
## Directory structure
| Path | Contents |
|:-----|:------|
| ```NopSCADlib``` | Top level scad files, e.g. ```lib.scad``` |
| ```NopSCADlib/doc``` | Documentation like this that is not automatically generated |
| ```NopSCADlib/examples``` | Example projects |
| ```NopSCADlib/gallery``` | Pictures of items that have been made with the library |
| ```NopSCADlib/printed``` | Scad files for making reusable printed parts |
| ```NopSCADlib/scripts``` | Python scripts |
| ```NopSCADlib/tests``` | A stand alone test for each type of vitamin and most of the utilities |
| ```NopSCADlib/utils``` | Utility scad files |
| ```NopSCADlib/utils/core``` | Core utilities used by nearly everything |
| ```NopSCADlib/vitamins``` | Generally a pair of .scad files for each type of vitamin. The plural version contains object definitions to be included and it uses the singular version. |
| `NopSCADlib` | Top level scad files, e.g. `lib.scad` |
| `NopSCADlib/doc` | Documentation like this that is not automatically generated |
| `NopSCADlib/examples` | Example projects |
| `NopSCADlib/gallery` | Pictures of items that have been made with the library |
| `NopSCADlib/printed` | Scad files for making reusable printed parts |
| `NopSCADlib/scripts` | Python scripts |
| `NopSCADlib/tests` | A stand alone test for each type of vitamin and most of the utilities |
| `NopSCADlib/utils` | Utility scad files |
| `NopSCADlib/utils/core` | Core utilities used by nearly everything |
| `NopSCADlib/vitamins` | Generally a pair of .scad files for each type of vitamin. The plural version contains object definitions to be included and it uses the singular version. |
## Making a project
Each project has its own directory and that is used to derive the project's name.
There should also be a subdirectory called ```scad``` with a scad file in it that contains the main assembly.
There should also be a subdirectory called `scad` with a scad file in it that contains the main assembly.
A skeleton project looks like this: -
//! Project description in Markdown format before the first include.
@@ -72,30 +72,30 @@ A skeleton project looks like this: -
Other scad files can be added to the scad directory and included or used as required.
* Subassemblies can be added in the same format as ```main_assembly()```, i.e. a module called ```something_assembly()```, taking no parameters and calling ```assembly("something")```
* Subassemblies can be added in the same format as `main_assembly()`, i.e. a module called `something_assembly()`, taking no parameters and calling `assembly("something")`
with the rest of its contents passed as children.
It needs to be called directly or indirectly from ```main_assembly()``` to appear in the view and on the BOM.
Assembly instructions should be added directly before the module definition in comments marked with ```//!```.
It needs to be called directly or indirectly from `main_assembly()` to appear in the view and on the BOM.
Assembly instructions should be added directly before the module definition in comments marked with `//!`.
* Any printed parts should be made by a module called ```something_stl()```, taking no parameters and calling ```stl("something")``` so they appear on the BOM when called from
an assembly. Printed parts are usually ```color```ed and ```render```ed at the point they are used in the assembly.
* Any printed parts should be made by a module called `something_stl()`, taking no parameters and calling `stl("something")` so they appear on the BOM when called from
an assembly. Printed parts are usually `color`ed and `render`ed at the point they are used in the assembly.
* Any 2D routed parts should be made by a module called ```something_dxf()```, taking no parameters and calling ```dxf("something")``` so they appear on the BOM when called from an
assembly. They are generally made from a ```sheet_2D()``` with holes subtracted from it. That will also put the sheet material on the BOM.
They are then expanded to 3D using ```render_2D_sheet()``` when they are placed in an assembly.
* Any 2D routed parts should be made by a module called `something_dxf()`, taking no parameters and calling `dxf("something")` so they appear on the BOM when called from an
assembly. They are generally made from a `sheet_2D()` with holes subtracted from it. That will also put the sheet material on the BOM.
They are then expanded to 3D using `render_2D_sheet()` when they are placed in an assembly.
When ```make_all``` is run from the top level directory of the project it will create the following sub-directories and populate them:-
When `make_all` is run from the top level directory of the project it will create the following sub-directories and populate them:-
| Directory | Contents |
|:----------|:---------|
| assemblies | For each assembly: an assembled view and an exploded assembly view, in large and small formats |
| bom | A flat BOM in ```bom.txt``` for the whole project, flat BOMs in text format for each assembly and a hierarchical BOM in JSON format: ```bom.json```.|
| bom | A flat BOM in `bom.txt` for the whole project, flat BOMs in text format for each assembly and a hierarchical BOM in JSON format: `bom.json`.|
| deps | Dependency files for each scad file in the project, so that subsequent builds can be incremental |
| dxfs | DXF files for all the CNC routed parts in the project and small PNG images of them |
| stls | STL files for all the printed parts in the project and small PNG images of them |
It will also make a Markdown assembly manual called ```readme.md``` suitable for GitHub, a version rendered to HTML for viewing locally called ```readme.html``` and a second
HTML version called ```printme.html```. This has page breaks instead of horizontal rules between sections and can be converted to PDF using Chrome to make a stand alone manual.
It will also make a Markdown assembly manual called `readme.md` suitable for GitHub, a version rendered to HTML for viewing locally called `readme.html` and a second
HTML version called `printme.html`. This has page breaks instead of horizontal rules between sections and can be converted to PDF using Chrome to make a stand alone manual.
Each time OpenSCAD is run to produce STL files, DXF files or assembly views, the time it takes is recorded and compared with the previous time.
At the end the times are printed with the delta from the last run and coloured red or green if they have got significantly faster or slower.
@@ -112,28 +112,38 @@ All the vitamins and utilities are included if you include [NopSCADlib/lib.scad]
Printed parts are not included and need to be used or included explicitly, their documentation states which files need to be included rather than used.
This is the easiest way to use the library and is reasonably efficient because the only files included are the object list definitions, all the functions and modules are used, so
get shared if other files in the project include ```lib.scad``` as well, or if you have multiple projects open in the same instance of OpenSCAD.
get shared if other files in the project include `lib.scad` as well, or if you have multiple projects open in the same instance of OpenSCAD.
One downside is that any change to the library will mean all the project files need regenerating.
A more optimised approach for large projects is to include [NopSCADlib/core.scad](../core.scad) instead.
That only has the a small set of utilities and the global settings in [global_defs.scad](../global_defs.scad) plus screws, nuts and washers that are required by a lot of other vitamins.
Any other vitamins used need to be included explicitly. One can copy the includes or use a line from [NopSCADlib/lib.scad](../lib.scad).
### Project Description
A description of the project can be placed in comments in Markdown format before the first include file.
By default this is followed by a picture of the main assembly unless the description contains any pictures.
The description can be divided into two or three sections using //! ***, which is a Markdown horizontal rule in a comment.
If there is a second section it is placed after the table of contents and a third section will be placed after the parts list.
If an actual horizontal rule is desired the alternative Markdown markup //! --- can be used.
### Parametric parts.
Modules that generate parts and assemblies need to take no parameters so that they can be called from the framework to make the STL files and assembly views, etc.
Sometimes parts or asemblies need to be parametric, for example fan guards take the fan as a parameter.
To work around this the ```fan_guard()``` module calls the ```stl()``` module with a variable name which has a suffix of the fan width, e.g. "fan_guard_60".
To work around this the `fan_guard()` module calls the `stl()` module with a variable name which has a suffix of the fan width, e.g. "fan_guard_60".
This ensures that if there are different sized fans in the same project the STL files have unique names.
It is then up to the user to add a wrapper to their project called ```fan_guard_60_stl()``` that calls ```fan_guard()``` with a 60mm fan: -
It is then up to the user to add a wrapper to their project called `fan_guard_60_stl()` that calls `fan_guard()` with a 60mm fan: -
module fan_guard_60_stl() fan_guard(fan60x15);
Calling ```fan_guard(fan60x15)``` draws a fan guard for a 60mm fan and puts ```fan_guard_60.stl``` on the BOM. The framework then looks for a module ```fan_guard_60_stl()``` to
Calling `fan_guard(fan60x15)` draws a fan guard for a 60mm fan and puts `fan_guard_60.stl` on the BOM. The framework then looks for a module `fan_guard_60_stl()` to
generate it.
This is OK if the fan will always be 60mm but what if the project is parametric and the fan size can vary?
To cater for that ```fan_guard()``` can be passed a ```name``` parameter to name the STL.
To cater for that `fan_guard()` can be passed a `name` parameter to name the STL.
For example a 3D printer might have a bed cooling fan and different sized machines might have different size fans.
bed_fan = fan80x38;
@@ -144,7 +154,7 @@ In this case the STL file has a constant name related to its use, regardless of
### Assembly boundaries
The ```assembly()``` module is used to mark assemblies that correspond to a step of construction.
The `assembly()` module is used to mark assemblies that correspond to a step of construction.
Each assembly named in this way gets a page in the build manual with a list of the parts and sub-assemblies that it uses, an exploded view,
some build instructions and then the assembled view.
This doesn't always correspond with how one would want to structure the code.
@@ -162,7 +172,7 @@ This is achieved by having a pair of modules: -
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200°C.
//
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") {
assembly("handle", ngb = true) {
translate_z(handle_height())
stl_colour(pp1_colour) vflip() handle_stl();
@@ -172,7 +182,7 @@ This is achieved by having a pair of modules: -
}
module handle_fastened_assembly(thickness) { //! Assembly with fasteners in place
screw_length = screw_longer_than(thickness + insert_length(insert) + 2 * washer_thickness(screw_washer(screw)));
screw_length = screw_length(screw, thickness, 2, true, longer = true);
handle_assembly();
@@ -182,26 +192,29 @@ This is achieved by having a pair of modules: -
screw_and_washer(screw, screw_length, true);
}
Notice how the first module ```handle_assembly()``` uses ```assembly()``` and has a build instruction. It isn't used directly in a project though, ```handle_fastened_assembly()``` is
Notice how the first module `handle_assembly()` uses `assembly()` and has a build instruction. It isn't used directly in a project though, `handle_fastened_assembly()` is
what is actually called from the parent assembly.
Because it doesn't have a call to ```assembly()```, the fasteners are added to the parent but the STL and the inserts become a sub-assembly.
Because it doesn't have a call to `assembly()`, the fasteners are added to the parent but the STL and the inserts become a sub-assembly.
When the parent assembly is shown exploded the handle's screws will be exploded but the inserts won't. They only explode when the sub-assembly is shown exloded.
Note also the ```pose([225, 0, 150], [0, 0, 14])``` call before the ```assembly()``` call. This allows the sub-assembly to be posed differently in its build step but doesn't
Note also the `pose([225, 0, 150], [0, 0, 14])` call before the `assembly()` call. This allows the sub-assembly to be posed differently in its build step but doesn't
affect its orientation in the parent assembly. The pose parameters are the rotation and the translation taken from the GUI.
Setting `ngb = true` in the `assembly()` prevents the handle assembly appearing as a columun in the top level BOM in the build instructions.
Instead its parts are merged into the parent BOM so the correct quantites are listed.
### Exploded diagrams
A lot of vitamins explode themselves when ```$explode=1```. This is done with module ```explode()``` that can be passed a Z offset, or a 3D vector that gives the displacement
and it draws a line from the origial position to the exploded position. The line can be offset from the origin of the component by specifying an offset vector.
A lot of vitamins explode themselves when `$explode=1`. This is done with module `explode()` that can be passed a Z offset, or a 3D vector that gives the displacement
and it draws a line from the original position to the exploded position. The line can be offset from the origin of the component by specifying an offset vector.
Often user assemblies need to add ```explode()``` in various places to explode printed parts, for example.
Often user assemblies need to add `explode()` in various places to explode printed parts, for example.
### Creating vitamins
Most vitamins are parametric and use a named list of properties to describe them is a pseudo OO style.
These lists are passed to every function or module related to the vitamin as the first parameter called ```type```.
These lists are passed to every function or module related to the vitamin as the first parameter called `type`.
They need to be included in the user code, so that the list names are visible. The functions and modules however only need to be used, not included.
This leads to a pair of files for each vitamin. One with a plural name that defines the objects and then uses the file with a singular name
@@ -216,50 +229,50 @@ These functions take a particular form, so they can be scraped out and added to
function spring_od(type) = type[1]; //! Outside diameter
Other functions and modules with ```//!``` comments will be added to the documentation as functions and modules.
Other functions and modules with `//!` comments will be added to the documentation as functions and modules.
Functions and modules without these special comments are considered private and do not appear in the documentation.
A vitamin announces itself to the BOM by calling the ```vitamin()``` module with a string description composed of two parts separated by a colon.
A vitamin announces itself to the BOM by calling the `vitamin()` module with a string description composed of two parts separated by a colon.
The first part is a string representation of the module instantiation.
This is used in the documentation to show how to instantiate every part available.
To facilitate this the first element in the type list is the name of the list as a string and is simply accessed as ```type[0]```.
To facilitate this the first element in the type list is the name of the list as a string and is simply accessed as `type[0]`.
The part of the description after the colon is free format text that appears on the BOM. Since vitamins are listed alphabetically starting the description with the broad
category of the part and leaving the more refined description to the end generates tidier parts lists.
For example ```Screw M3 pan x 30mm``` ensures all the screws appear together and are ordered by their diameter before length, although ```M3 x 30mm pan screw``` would be
For example `Screw M3 pan x 30mm` ensures all the screws appear together and are ordered by their diameter before length, although `M3 x 30mm pan screw` would be
more natural.
Vitamins are only ever previewed, so they are optimised to draw quickly in F5 and don't need to worry about being manifold.
In OpenCSG 3D difference and intersection are relatively slow and the negative volumes interfere with nearby objects when they are composed into assemblies. For this reason as much
as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in ```render()``` so that CGAL will compute a polyhedron
as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in `render()` so that CGAL will compute a polyhedron
that is cached and reused. This will be very slow the first time it renders but very fast afterwards.
### Panels and Platters
The ```stls``` and ```dxfs``` scripts produce a file for each part but often it is desirable to print or route collections of parts laid out together.
This can be done by adding scad files to folders called ```platters``` for STL files and ```panels``` for DXF files.
These can aggregate and lay out parts by including ```NopSCADlib/core.scad``` and using modules ```use_stl(name)``` and ```use_dxf(name)```.
The `stls` and `dxfs` scripts produce a file for each part but often it is desirable to print or route collections of parts laid out together.
This can be done by adding scad files to folders called `platters` for STL files and `panels` for DXF files.
These can aggregate and lay out parts by including `NopSCADlib/core.scad` and using modules `use_stl(name)` and `use_dxf(name)`.
These modules import the already generated singular STL and DXF files, so they are relatively fast. The name does not include the suffix.
The scad files typically also need to include other files from the project to get the dimensions of the parts to calculate their positions.
The composite part files have the same name as the scad file that generates them, with the suffix changed to ```.stl``` or ```.dxf```.
The composite part files have the same name as the scad file that generates them, with the suffix changed to `.stl` or `.dxf`.
The generated files are placed in ```stls/printed``` and ```dxfs/routed```.
Any parts that are not covered by the platters / panels are copied into the ```printed``` / ```routed``` directories, so that they contain everything to be made.
The generated files are placed in `stls/printed` and `dxfs/routed`.
Any parts that are not covered by the platters / panels are copied into the `printed` / `routed` directories, so that they contain everything to be made.
### Multiple configurations
Some parametric designs might have several configurations, for example a 3D printer with different size options. If several configurations need to be supported at the
same time multiple sets of BOMS, STLS and DXFs need to be generated in separate diectories. NopSCADlib supports this by having multiple configuration files named
```config_<target_name>.scad```. All the scripts take an optional first parameter that selects one of these config files by specifying ```target_name```.
`config_<target_name>.scad`. All the scripts take an optional first parameter that selects one of these config files by specifying `target_name`.
The target config file is selected by generating ```target.scad``` that includes ```config_<target_name>.scad```.
The rest of the project includes ```target.scad``` to use the configuration.
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc.) are placed in a sub-directory called ```<target_name>```.
The target config file is selected by generating `target.scad` that includes `config_<target_name>.scad`.
The rest of the project includes `target.scad` to use the configuration.
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc.) are placed in a sub-directory called `<target_name>`.
### Other libraries
The build scripts need to be able to locate the source files where the modules to generate the STL files and assemblies reside. They will search all the scad files
in the project plus any ```printed``` directories outside the project. This covers the printed parts in NopSCADlib but also allows other libraries of printed parts.
in the project plus any `printed` directories outside the project. This covers the printed parts in NopSCADlib but also allows other libraries of printed parts.
Other libraries of vitamins and utilities can be used provided they follow the same convensions of NopSCADlib. The build scripts don't need to search those.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -2,6 +2,8 @@
{
"name": "base_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {},
"vitamins": {
@@ -20,6 +22,8 @@
{
"name": "feet_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"base_assembly": 1
@@ -46,6 +50,8 @@
{
"name": "mains_in_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"feet_assembly": 1
@@ -82,6 +88,8 @@
{
"name": "main_assembly",
"big": null,
"ngb": false,
"zoomed": 0,
"count": 1,
"assemblies": {
"mains_in_assembly": 1

View File

@@ -15,6 +15,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![Main Assembly](assemblies/main_assembled.png)
<span></span>
---
## Table of Contents
@@ -24,6 +25,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
1. [Mains In Assembly](#mains_in_assembly)
1. [Main Assembly](#main_assembly)
<span></span>
[Top](#TOP)
---
@@ -54,6 +56,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
| &nbsp;&nbsp;1&nbsp; | &nbsp;&nbsp;.&nbsp; | &nbsp;&nbsp;.&nbsp; | &nbsp;&nbsp;.&nbsp; | &nbsp;&nbsp;1&nbsp; | &nbsp;&nbsp;socket_box.stl |
| &nbsp;&nbsp;1&nbsp; | &nbsp;&nbsp;4&nbsp; | &nbsp;&nbsp;.&nbsp; | &nbsp;&nbsp;.&nbsp; | &nbsp;&nbsp;5&nbsp; | &nbsp;&nbsp;Total 3D printed parts count |
<span></span>
[Top](#TOP)
---
@@ -81,6 +84,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![base_assembled](assemblies/base_assembled.png)
<span></span>
[Top](#TOP)
---
@@ -117,6 +121,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![feet_assembled](assemblies/feet_assembled.png)
<span></span>
[Top](#TOP)
---
@@ -156,6 +161,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![mains_in_assembled](assemblies/mains_in_assembled.png)
<span></span>
[Top](#TOP)
---
@@ -199,4 +205,5 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
![main_assembled](assemblies/main_assembled.png)
<span></span>
[Top](#TOP)

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

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.
@@ -43,19 +33,15 @@ Bench power supply built around an ATX PSU.
* The green LED shows the power good signal.
* Dummy loads keep the outputs in range.
![](Lab_ATX_PSU.png)
<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,36 +58,29 @@ 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.
![](Mains_Box.png)
<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
![](Turntable.png)
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)
![](Variac.png)

View File

@@ -26,7 +26,7 @@
// Setting $bom after including lib overrides bom in the libs but not in the local file.
// Setting $_bom in the local file overrides it in the local file but not in the libs.
//
//function is_undef(x) = x == undef;
rr_green = [0, 146/255, 0]; // RepRap logo colour
$_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
@@ -34,7 +34,7 @@ layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // lay
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) ? [0, 146/255, 0] : $pp1_colour; // printed part colour 1, RepRap logo colour
pp1_colour = is_undef($pp1_colour) ? rr_green : $pp1_colour; // printed part colour 1, RepRap logo colour
pp2_colour = is_undef($pp2_colour) ? "Crimson" : $pp2_colour; // printed part colour 2
pp3_colour = is_undef($pp3_colour) ? "SteelBlue" : $pp3_colour; // printed part colour 3
pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4

View File

@@ -26,6 +26,7 @@ include <vitamins/psus.scad>
include <vitamins/pcbs.scad>
include <vitamins/batteries.scad>
include <vitamins/bearing_blocks.scad>
include <vitamins/blowers.scad>
include <vitamins/bulldogs.scad>
include <vitamins/buttons.scad>
@@ -35,10 +36,8 @@ include <vitamins/displays.scad>
include <vitamins/extrusions.scad>
include <vitamins/extrusion_brackets.scad>
include <vitamins/geared_steppers.scad>
include <vitamins/green_terminals.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>
@@ -48,12 +47,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>
@@ -90,6 +89,7 @@ use <utils/gears.scad>
use <utils/hanging_hole.scad>
use <utils/fillet.scad>
use <utils/rounded_polygon.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: 854 KiB

After

Width:  |  Height:  |  Size: 884 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,6 +43,7 @@ include <lib.scad>
use <tests/ball_bearings.scad>
use <tests/batteries.scad>
use <tests/bearing_blocks.scad>
use <tests/belts.scad>
use <tests/blowers.scad>
use <tests/bulldogs.scad>
@@ -62,7 +65,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 +80,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 +89,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,7 +119,9 @@ 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>
use <tests/screw_knob.scad>
use <tests/socket_box.scad>
@@ -170,13 +174,19 @@ translate([x5, cable_grommets_y + 370])
translate([x5 + 60, cable_grommets_y + 200])
strap_handles();
translate([640, cable_grommets_y + 200])
printed_pulley_test();
translate([x5, cable_grommets_y + 250])
handle();
translate([950, 600])
box_test();
translate([890, 750])
translate([830, 770])
pocket_handles();
translate([950, 750])
printed_boxes();
translate([850, 1330])
@@ -197,8 +207,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;
@@ -351,7 +361,7 @@ modules_y = iecs_y + 60;
ssrs_y = modules_y + 80;
blowers_y = ssrs_y + 60;
batteries_y = blowers_y + 100;
steppers_y = batteries_y + 70;
steppers_y = batteries_y + 55;
panel_meters_y = steppers_y + 70;
extrusions_y = panel_meters_y + 80;

View File

@@ -23,7 +23,7 @@
//! together. The box panels can be customised to have holes and parts mounted on them by overriding the
//! definitions of `box_base()`, `box_front()`, etc.
//!
//! `box.scad` should be ```use```d and `box_assembly.scad` ```include```d.
//! `box.scad` should be `use`d and `box_assembly.scad` `include`d.
//!
//! A box is defined with a list that specifies the inside dimensions, top, bottom and side sheet materials, the
//! screw type and printed part wall thickness. This diagram shows how the various dimensions are labelled:
@@ -75,9 +75,9 @@ function box_corner_overlap(type) = box_wall(type);
function box_corner_rad(type) = box_sheet_slot(type) - sheet_slot_clearance / 2 + box_corner_gap(type) + box_corner_overlap(type);
function box_sheet_r(type) = box_corner_rad(type) - box_sheet_slot(type) - box_corner_overlap(type);
function box_screw_length(type, top) = screw_longer_than(2 * washer_thickness(box_washer(type))
+ sheet_thickness(top ? box_top_sheet(type) : box_base_sheet(type))
+ box_corner_gap(type) + box_profile_overlap(type) + box_insert_l(type) - 1);
function box_screw_length(type, top) =
let(s = top ? box_top_sheet(type) : box_base_sheet(type))
screw_length(box_screw(type), sheet_thickness(s) + box_corner_gap(type) + box_profile_overlap(type) - 1, washers = 2, insert = true, longer = true);
function box_wall_clearance(type) = box_sheet_slot(type) / 2 - sheet_thickness(box_sheets(type)) / 2;
function box_margin(type) = box_profile_overlap(type) + box_corner_gap(type); //! How much the bezel intrudes on the specified height
@@ -109,7 +109,7 @@ module grill_hole_positions(width, height, r = 1000) {
}
}
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set `poly` `true` for printing, `false` for milling.
extrude_if(h)
if(poly)
grill_hole_positions(width, height, r)
@@ -139,17 +139,17 @@ module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
}
module box_corner_profile(type) { //! Generates the corner profile STL for 3D printing.
stl("box_corner_profile");
length = box_height(type) - 2 * box_margin(type);
difference() {
linear_extrude(length, center = true, convexity = 5)
box_corner_profile_2D(type);
for(z = [-1, 1])
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
insert_hole(box_insert(type), 5);
}
stl("box_corner_profile")
difference() {
linear_extrude(length, center = true, convexity = 5)
box_corner_profile_2D(type);
for(z = [-1, 1])
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
insert_hole(box_insert(type), 5);
}
}
module box_corner_profile_section(type, section, sections) { //! Generates interlocking sections of the corner profile to allow it to be taller than the printer
@@ -209,7 +209,6 @@ module box_corner_quadrants(type, width, depth)
}
module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
stl(bottom ? "bottom_bezel" : "top_bezel");
feet = bottom && box_feet(type);
t = box_sheet_slot(type);
outset = box_outset(type);
@@ -221,66 +220,67 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
height = box_bezel_height(type, bottom);
foot_extension = foot_height - height;
difference() {
w = box_width(type);
d = box_depth(type);
translate_z(-box_profile_overlap(type)) difference() {
tw = w + 2 * outset;
td = d + 2 * outset;
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type), false);
//
// Remove edges between the feet
//
if(feet)
hull() {
translate_z(height + 0.5)
cube([w - 2 * foot_length, td + 1, 1], center = true);
stl(bottom ? "bottom_bezel" : "top_bezel")
difference() {
w = box_width(type);
d = box_depth(type);
translate_z(-box_profile_overlap(type)) difference() {
tw = w + 2 * outset;
td = d + 2 * outset;
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type));
//
// Remove edges between the feet
//
if(feet)
hull() {
translate_z(height + 0.5)
cube([w - 2 * foot_length, td + 1, 1], center = true);
translate_z(foot_height + 1)
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
}
if(feet)
hull() {
translate_z(height + 0.5)
cube([tw + 1, d - 2 * foot_length, 1], center = true);
translate_z(foot_height + 1)
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
}
}
//
// slots for side panels
//
translate_z(-box_profile_overlap(type))
linear_extrude(2 * box_profile_overlap(type), center = true)
for(i = [-1, 1]) {
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
square([t, d - 2 * cgap], center = true);
translate([0, i * (d + t - sheet_slot_clearance) / 2])
square([w - 2 * cgap, t], center = true);
}
//
// recess for top / bottom panel
//
translate_z(cgap)
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
//
// leave plastic over the corner profiles
//
translate_z(-box_profile_overlap(type) - 1)
linear_extrude(box_profile_overlap(type) + cgap + 2)
union() {
difference() {
square([w - 2 * inset,
d - 2 * inset], center = true);
box_corner_quadrants(type, w, d);
translate_z(foot_height + 1)
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
}
box_screw_hole_positions(type)
poly_circle(screw_clearance_radius(box_screw(type)));
}
}
if(feet)
hull() {
translate_z(height + 0.5)
cube([tw + 1, d - 2 * foot_length, 1], center = true);
translate_z(foot_height + 1)
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
}
}
//
// slots for side panels
//
translate_z(-box_profile_overlap(type))
linear_extrude(2 * box_profile_overlap(type), center = true)
for(i = [-1, 1]) {
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
square([t, d - 2 * cgap], center = true);
translate([0, i * (d + t - sheet_slot_clearance) / 2])
square([w - 2 * cgap, t], center = true);
}
//
// recess for top / bottom panel
//
translate_z(cgap)
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2);
//
// leave plastic over the corner profiles
//
translate_z(-box_profile_overlap(type) - 1)
linear_extrude(box_profile_overlap(type) + cgap + 2)
union() {
difference() {
square([w - 2 * inset,
d - 2 * inset], center = true);
box_corner_quadrants(type, w, d);
}
box_screw_hole_positions(type)
poly_circle(screw_clearance_radius(box_screw(type)));
}
}
}
dowel_length = 20;
@@ -485,7 +485,6 @@ module box_shelf_screw_positions(type, screw_positions, thickness = 0, wall = un
}
module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a shelf bracket, the first optional child is a 2D cutout and the second 3D cutouts
stl("shelf_bracket");
w = is_undef(wall) ? box_wall(type) : wall;
insert = box_shelf_insert(type);
lip = 2 * insert_boss_radius(insert, w);
@@ -513,44 +512,45 @@ module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a
square([lip, eps]);
}
difference() {
union() {
linear_extrude(w)
difference() {
shape()
if($children)
children(0);
round(2) offset(-width)
stl("shelf_bracket")
difference() {
union() {
linear_extrude(w)
difference() {
shape()
if($children)
children(0);
}
linear_extrude(lip)
difference() {
shape()
if($children)
children(0);
round(2) offset(-width)
shape()
if($children)
children(0);
}
offset(-w)
linear_extrude(lip)
difference() {
shape()
if($children)
children(0);
}
offset(-w)
shape()
if($children)
children(0);
}
hflip()
box_shelf_screw_positions(type, screw_positions, 0, w)
boss();
}
if($children > 1)
hflip()
children(1);
hflip()
box_shelf_screw_positions(type, screw_positions, 0, w)
boss();
insert_hole(insert, counterbore = 1, horizontal = true);
}
if($children > 1)
hflip()
children(1);
hflip()
box_shelf_screw_positions(type, screw_positions, 0, w)
insert_hole(insert, counterbore = 1, horizontal = true);
}
}
module box_shelf_bracket_section(type, rows, cols, x, y) { //! Generates sections of the shelf bracket to allow it to be bigger than the printer
@@ -564,25 +564,25 @@ module box_shelf_bracket_section(type, rows, cols, x, y) { //! Generates section
children();
}
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, ```sheet``` can be set to override the type
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, `sheet` can be set to override the type
dxf("box_left");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, ```sheet``` can be set to override the type
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, `sheet` can be set to override the type
dxf("box_right");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, ```sheet``` can be set to override the type
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, `sheet` can be set to override the type
dxf("box_front");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, ```sheet``` can be set to override the type
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, `sheet` can be set to override the type
dxf("box_back");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);

View File

@@ -18,7 +18,7 @@
//
//
// The assembly is ```include```d so the panel definitions can be overridden to add holes and components.
// The assembly is `include`d so the panel definitions can be overridden to add holes and components.
// The _box_module also needs to be wrapped in the file that uses it so it can be called without
// parameters to make the assembly views. E.g. module box_assembly() _box_assembly(box);
//

View File

@@ -21,7 +21,7 @@
//! A box made from CNC cut panels butted together using printed fixing blocks. Useful for making large
//! boxes with minimal 3D printing. More blocks are added as the box gets bigger.
//!
//! Needs to be ```include```d rather than ```use```d to allow the panel definitions to be overridden to add holes
//! Needs to be `include`d rather than `use`d to allow the panel definitions to be overridden to add holes
//! and mounted components.
//!
//! A list specifies the internal dimensions, screw type, top, bottom and side sheet types and the block

View File

@@ -49,84 +49,84 @@ module ribbon_grommet_hole(ways, h = 50, expand = true) { //! Generate a hole fo
}
module ribbon_grommet(ways, thickness) { //! Generate the STL for a printed ribbon grommet
stl(str("ribbon_grommet_", ways, "_", thickness));
width = 2 * (wall + clearance) + thickness;
slot_length = ribbon_clamp_slot(ways);
length = slot_length + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(wall, center = true, convexity = 5)
difference() {
hull() {
translate([-length / 2, 0])
square([length, base]);
stl(str("ribbon_grommet_", ways, "_", thickness))
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(wall, center = true, convexity = 5)
difference() {
hull() {
translate([-length / 2, 0])
square([length, base]);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
semi_circle(rad);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
semi_circle(rad);
}
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
linear_extrude(width -1, center = true)
difference() {
ribbon_grommet_hole(ways, expand = false, h = 0);
linear_extrude(width -1, center = true)
difference() {
ribbon_grommet_hole(ways, expand = false, h = 0);
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
}
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
}
}
module round_grommet_top(diameter, thickness, od = undef) { //! Generate the STL for a round grommet top half
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness));
chamfer = layer_height;
h = wall + thickness + wall;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + overlap;
r0 = r1 + 1;
union() {
rotate_extrude()
polygon([
[r0, 0],
[r3 - chamfer, 0],
[r3, chamfer],
[r3, wall],
[r2, wall],
[r2, h - chamfer],
[r2 - chamfer, h],
[r0, h],
]);
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness))
union() {
rotate_extrude()
polygon([
[r0, 0],
[r3 - chamfer, 0],
[r3, chamfer],
[r3, wall],
[r2, wall],
[r2, h - chamfer],
[r2 - chamfer, h],
[r0, h],
]);
render() difference() {
cylinder(r = r0 + eps, h = h);
render() difference() {
cylinder(r = r0 + eps, h = h);
poly_cylinder(r = r1, h = 100, center = true);
poly_cylinder(r = r1, h = 100, center = true);
}
}
}
}
module round_grommet_bottom(diameter, od = undef) { //! Generate the STL for a round grommet bottom half
stl(str("round_grommet_bottom_", round(diameter * 10)));
chamfer = layer_height;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + max(overlap, wall + chamfer);
rotate_extrude()
polygon([
[r2, chamfer],
[r2 + chamfer, 0],
[r3, 0],
[r3, wall - chamfer],
[r3 - chamfer, wall],
[r2, wall],
]);
stl(str("round_grommet_bottom_", round(diameter * 10)))
rotate_extrude()
polygon([
[r2, chamfer],
[r2 + chamfer, 0],
[r3, 0],
[r3, wall - chamfer],
[r3 - chamfer, wall],
[r2, wall],
]);
}
module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
@@ -161,30 +161,30 @@ module mouse_grommet_hole(r, h = 50, z = undef, expand = wall + clearance) //! M
function mouse_grommet_offset(r) = r + wall;
module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
stl(str("mouse_grommet_", r * 10, "_", thickness));
width = 2 * (wall + clearance) + thickness;
length = 2 * r + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(wall, center = true)
difference() {
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
stl(str("mouse_grommet_", r * 10, "_", thickness))
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(wall, center = true)
difference() {
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
linear_extrude(width - 1, center = true)
difference() {
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
linear_extrude(width - 1, center = true)
difference() {
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
}
}
}
module mouse_grommet_assembly(r, thickness)

View File

@@ -68,7 +68,7 @@ function cam_screw_length(cam) = let(
front = cam_front_size(cam),
screw = pcb_screw(camera_pcb(cam)),
nut = screw_nut(screw)
) screw_longer_than(front.z + washer_thickness(screw_washer(screw)) - nut_trap_depth(nut) + nut_thickness(nut, true));
) screw_length(screw, front.z - nut_trap_depth(nut), 1, nyloc = true);
function hinge_z(cam) = cam_screw_length(cam) - hinge_r;
@@ -82,7 +82,6 @@ module cam_holes(cam) {
}
module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
stl("rpi_camera_focus_ring");
rad = 15 / 2;
hole_r1 = 2.5 / 2;
@@ -93,58 +92,58 @@ module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
x = rad / (sin(angle / 2) + cos(angle / 2));
r = x * sin(angle / 2);
difference() {
linear_extrude(height = thickness, convexity = 5)
difference() {
union() {
circle(x);
stl("rpi_camera_focus_ring")
difference() {
linear_extrude(height = thickness, convexity = 5)
difference() {
union() {
circle(x);
for(i = [0 : flutes - 1])
rotate([0, 0, 2 * angle * i])
translate([x, 0])
circle(r);
}
for(i = [0 : flutes - 1])
rotate([0, 0, 2 * angle * i])
rotate([0, 0, 2 * angle * i + angle])
translate([x, 0])
circle(r);
}
for(i = [0 : flutes - 1])
rotate([0, 0, 2 * angle * i + angle])
translate([x, 0])
circle(r);
}
hull() {
poly_cylinder(r = hole_r1, h = 0.1, center = true);
hull() {
poly_cylinder(r = hole_r1, h = 0.1, center = true);
translate([0, 0, thickness])
poly_cylinder(r = hole_r2, h = 0.1, center = true);
translate([0, 0, thickness])
poly_cylinder(r = hole_r2, h = 0.1, center = true);
}
}
}
}
module camera_back(cam) { //! Make the STL for a camera case back
stl(str("camera_back_", cam[0]));
pcb = camera_pcb(cam);
back = cam_back_size(cam);
screw = pcb_screw(pcb);
nut = screw_nut(screw);
translate_z(back.z)
hflip()
difference() {
translate_z(back.z / 2)
cube(back, center = true);
stl(str("camera_back_", cam[0]))
translate_z(back.z)
hflip()
difference() {
translate_z(back.z / 2)
cube(back, center = true);
translate([0, -cam_back_overlap])
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
translate([0, -cam_back_overlap])
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
translate([0, -pcb_width(pcb) / 2])
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
translate([0, -pcb_width(pcb) / 2])
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
translate_z(back.z)
cam_holes(cam)
hflip()
nut_trap(screw, nut, supported = true);
}
translate_z(back.z)
cam_holes(cam)
hflip()
nut_trap(screw, nut, supported = true);
}
}
module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
stl(str("camera_front_", cam[0]));
front = cam_front_size(cam);
back = cam_back_size(cam);
pcb = camera_pcb(cam);
@@ -170,70 +169,71 @@ module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
translate([0, (hinge ? front.x * hinge : front.y) / 2 + hinge_offset, hinge_r])
children();
difference() {
union() {
hull()
for(x = [-1, 1], y = [-1, 1])
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
translate_z(front.z - 1)
cylinder(r = rad, h = 1);
stl(str("camera_front_", cam[0]))
difference() {
union() {
hull()
for(x = [-1, 1], y = [-1, 1])
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
translate_z(front.z - 1)
cylinder(r = rad, h = 1);
translate_z(rad)
sphere(rad);
translate_z(rad)
sphere(rad);
cylinder(r = rad * (sqrt(2) - 1), h = eps);
}
cylinder(r = rad * (sqrt(2) - 1), h = eps);
}
hinge_pos()
hull() {
rotate([-90, 0, -90])
teardrop(r = hinge_r, h = hinge_h, center = false);
hinge_pos()
hull() {
rotate([-90, 0, -90])
teardrop(r = hinge_r, h = hinge_h, center = false);
translate([0, -10, -hinge_r])
cube([hinge_h, eps, 2 * hinge_r]);
}
}
hinge_pos()
rotate([90, 0, 90])
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
translate_z(shelf)
hflip() {
pcb_component_position(pcb, "smd_led") // clearance for LED
cube(led_clearance, center = true);
pcb_component_position(pcb, "smd_res") // clearance for resistor
cube(res_clearance, center = true);
translate([0, -10, -hinge_r])
cube([hinge_h, eps, 2 * hinge_r]);
}
}
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
hinge_pos()
rotate([90, 0, 90])
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
cube([connector_slot.x, connector_slot.y, front.z], center = true);
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
translate_z(cam_back_clearance + layer_height)
cam_holes(cam)
rotate(90)
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
translate_z(shelf)
hflip() {
pcb_component_position(pcb, "smd_led") // clearance for LED
cube(led_clearance, center = true);
pcb_component_position(pcb, "smd_res") // clearance for resistor
cube(res_clearance, center = true);
}
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
cube([connector_slot.x, connector_slot.y, front.z], center = true);
translate_z(cam_back_clearance + layer_height)
cam_holes(cam)
rotate(90)
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
translate_z(shelf - pcb_size.z)
hflip()
camera_lens(cam, clearance);
translate_z(shelf - pcb_size.z)
hflip()
camera_lens(cam, clearance);
hflip()
pcb_component_position(pcb, "smd_led")
rotate(45)
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
}
pcb_component_position(pcb, "smd_led")
rotate(45)
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
}
}
function bracket_thickness(cam) = max(wall, min(3.5, hinge_z(cam) - hinge_r - 1));
@@ -253,38 +253,39 @@ module camera_bracket_position(cam) //! Position children at the bracket positio
children();
module camera_bracket(cam) { //! Make the STL for the camera bracket
stl(str("camera_bracket_", cam[0]));
t = bracket_thickness(cam);
z = hinge_z(cam);
translate([hinge_h / 2, 0])
difference() {
hull() {
translate_z(eps / 2)
cube([hinge_h, 2 * hinge_r, eps], center = true);
translate_z(z)
rotate([0, 90, 0])
cylinder(r = hinge_r, h = hinge_h, center = true);
stl(str("camera_bracket_", cam[0])) union() {
translate([hinge_h / 2, 0])
difference() {
hull() {
translate_z(eps / 2)
cube([hinge_h, 2 * hinge_r, eps], center = true);
translate_z(z)
rotate([0, 90, 0])
cylinder(r = hinge_r, h = hinge_h, center = true);
}
translate([hinge_h / 2, 0, z])
rotate([90, 0, 90])
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
}
translate([hinge_h / 2, 0, z])
rotate([90, 0, 90])
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
}
linear_extrude(t)
difference() {
hull()
linear_extrude(t)
difference() {
hull()
camera_bracket_screw_positions(cam)
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
camera_bracket_screw_positions(cam)
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
camera_bracket_screw_positions(cam)
poly_circle(screw_clearance_radius(bracket_screw));
}
poly_circle(screw_clearance_radius(bracket_screw));
}
}
}
module camera_assembly(cam, angle = 0) //! Camera case assembly
assembly(str("camera_", cam[0])) {
assembly(str("camera_", cam[0]), ngb = true) {
front = cam_front_size(cam);
screw = pcb_screw(camera_pcb(cam));
nut = screw_nut(screw);
@@ -344,9 +345,8 @@ module camera_fastened_assembly(cam, thickness, angle = 0) {
camera_bracket_position(cam)
camera_bracket_screw_positions(cam) {
nut = screw_nut(bracket_screw);
washer = screw_washer(bracket_screw);
t = bracket_thickness(cam);
screw_length = screw_longer_than(thickness + t + nut_thickness(nut, true) + 2 * washer_thickness(washer));
screw_length = screw_length(bracket_screw, thickness + t, 2, nyloc = true);
vflip()
translate_z(thickness)
screw_and_washer(bracket_screw, screw_length);

View File

@@ -27,7 +27,6 @@ include <../utils/core/core.scad>
function carrier_height() = 3; //! Height of PCB carrier
module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
stl("ESP12F_carrier");
pins = 8;
pitch1 = 2;
pitch2 = 2.54;
@@ -43,29 +42,29 @@ module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
width1 = wpitch1 + hole + squeezed_wall * 2;
width2 = wpitch2 + hole2 + squeezed_wall * 2;
difference() {
hull() {
translate_z(height - eps / 2)
cube([width1, length1, eps], center = true);
stl("ESP12F_carrier")
difference() {
hull() {
translate_z(height - eps / 2)
cube([width1, length1, eps], center = true);
translate_z(eps / 2)
cube([width2, length2, eps], center = true);
translate_z(eps / 2)
cube([width2, length2, eps], center = true);
}
for(side = [-1, 1])
for(i = [0 : pins - 1])
hull() {
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
cube([hole, hole, eps], center = true);
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
cube([hole2, hole2, eps], center = true);
}
}
for(side = [-1, 1])
for(i = [0 : pins - 1])
hull() {
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
cube([hole, hole, eps], center = true);
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
cube([hole2, hole2, eps], center = true);
}
}
}
module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two required
stl("TP4056_carrier");
pitch = 2.54;
outer_pitch = 13.9;
inner_pitch = 7.54;
@@ -78,30 +77,30 @@ module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two re
width = hole + squeezed_wall * 2;
spacing = inch(0.9);
difference() {
hull() {
translate_z(height - eps / 2)
cube([width, length1, eps], center = true);
stl("TP4056_carrier")
difference() {
hull() {
translate_z(height - eps / 2)
cube([width, length1, eps], center = true);
translate_z(eps / 2)
cube([width, length2, eps], center = true);
translate_z(eps / 2)
cube([width, length2, eps], center = true);
}
for(i = [0 : pins - 1])
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
if(x)
hull() {
translate([0, x, height])
cube([hole, hole, eps], center = true);
translate([0, i * pitch - (pins - 1) * pitch / 2])
cube([hole, hole, eps], center = true);
}
}
for(i = [0 : pins - 1])
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
if(x)
hull() {
translate([0, x, height])
cube([hole, hole, eps], center = true);
translate([0, i * pitch - (pins - 1) * pitch / 2])
cube([hole, hole, eps], center = true);
}
}
}
module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two required
stl("MT3608_carrier");
pcb_width = 17;
w_pitch_top = 6.81;
w_pitch_bot = inch(0.3);
@@ -113,21 +112,22 @@ module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two re
width = hole + 2 * wall;
offset = (l_pitch_top - l_pitch_bot) / 2;
difference() {
hull() {
translate([offset, 0, height - eps / 2])
rounded_rectangle([width, pcb_width - 2, eps], 1);
translate_z(eps / 2)
rounded_rectangle([width, pcb_width - 2, eps], 1);
}
for(side = [-1, 1])
stl("MT3608_carrier")
difference() {
hull() {
translate([offset, side * w_pitch_top / 2, height])
cube([hole, hole, eps], center = true);
translate([offset, 0, height - eps / 2])
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
translate([0, side * w_pitch_bot / 2])
cube([hole, hole, eps], center = true);
translate_z(eps / 2)
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
}
}
for(side = [-1, 1])
hull() {
translate([offset, side * w_pitch_top / 2, height])
cube([hole, hole, eps], center = true);
translate([0, side * w_pitch_bot / 2])
cube([hole, hole, eps], center = true);
}
}
}

View File

@@ -25,10 +25,10 @@
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//!
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting ```show_block``` to false.
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting `show_block` to false.
//! This allows the block and one set of fasteners to be on one assembly and the other fasteners on the mating assemblies.
//!
//! Star washers can be omitted by setting ```star_washers``` to false.
//! Star washers can be omitted by setting `star_washers` to false.
//
include <../core.scad>
use <../vitamins/insert.scad>
@@ -72,8 +72,6 @@ module corner_block_holes(screw = def_screw) //! Place children at all the holes
children();
module corner_block(screw = def_screw, name = false) { //! Generate the STL for a printed corner block
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20));
r = 1;
cb_width = corner_block_width(screw);
cb_height = cb_width;
@@ -81,43 +79,45 @@ module corner_block(screw = def_screw, name = false) { //! Generate the STL for
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
offset = corner_block_hole_offset(screw);
difference() {
hull() {
translate([r, r])
rounded_cylinder(r = r, h = cb_height, r2 = r);
translate([r, cb_depth - r])
cylinder(r = r, h = cb_height - corner_rad);
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20))
difference() {
hull() {
translate([r, r])
rounded_cylinder(r = r, h = cb_height, r2 = r);
translate([cb_width - r, r])
cylinder(r = r, h = cb_height - corner_rad);
translate([r, cb_depth - r])
cylinder(r = r, h = cb_height - corner_rad);
translate([offset, offset, offset])
sphere(corner_rad);
translate([cb_width - r, r])
cylinder(r = r, h = cb_height - corner_rad);
translate([offset, offset])
cylinder(r = corner_rad, h = offset);
translate([offset, offset, offset])
sphere(corner_rad);
translate([offset, r, offset])
rotate([-90, 0, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
translate([offset, offset])
cylinder(r = corner_rad, h = offset);
translate([r, offset, offset])
rotate([0, 90, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
translate([offset, r, offset])
rotate([-90, 0, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
translate([r, offset, offset])
rotate([0, 90, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
}
corner_block_v_hole(screw)
insert_hole(insert, overshoot);
corner_block_h_holes(screw)
insert_hole(insert, overshoot, true);
children();
}
corner_block_v_hole(screw)
insert_hole(insert, overshoot);
corner_block_h_holes(screw)
insert_hole(insert, overshoot, true);
children();
}
}
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
assembly(str("corner_block_M", 20 * screw_radius(screw))) {
assembly(str("corner_block_M", 20 * screw_radius(screw)), ngb = true) {
insert = screw_insert(screw);
stl_colour(name ? pp2_colour : pp1_colour)
@@ -133,12 +133,10 @@ assembly(str("corner_block_M", 20 * screw_radius(screw))) {
module fastened_corner_block_assembly(thickness, screw = def_screw, thickness_below = undef, thickness_side2 = undef, name = false, show_block = true, star_washers = true) { //! Printed block with all fasteners
thickness2 = !is_undef(thickness_below) ? thickness_below : thickness;
thickness3 = !is_undef(thickness_side2) ? thickness_side2 : thickness;
washer = screw_washer(screw);
insert = screw_insert(screw);
function screw_length(t) = screw_shorter_than((star_washers ? 2 : 1) * washer_thickness(washer) + t + insert_length(insert) + overshoot);
screw_length = screw_length(thickness);
screw_length2 = screw_length(thickness2);
screw_length3 = screw_length(thickness3);
function screw_len(t) = screw_length(screw, t + overshoot, star_washers ? 2 : 1, true);
screw_length = screw_len(thickness);
screw_length2 = screw_len(thickness2);
screw_length3 = screw_len(thickness3);
if(show_block)
corner_block_assembly(screw, name) children();

View File

@@ -54,44 +54,44 @@ module door_hinge_hole_positions(dir = 0) { //! Position chidren
}
module door_hinge(door_thickness) { //! Generates STL for the moving part of the hinge
stl(str("door_hinge_", door_thickness));
hole_pitch = width - 10;
union() {
rotate([90, 0, 0])
linear_extrude(width, center = true)
stl(str("door_hinge_", door_thickness))
union() {
rotate([90, 0, 0])
linear_extrude(width, center = true)
difference() {
hull() {
translate([dia / 2, thickness + door_thickness / 2])
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0, truncate = false);
square([dia + 1, 2 * thickness + door_thickness], center = true);
}
square([1, thickness + door_thickness]);
}
translate([dia / 2, thickness + door_thickness / 2])
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
}
linear_extrude(thickness)
difference() {
hull() {
translate([dia / 2, thickness + door_thickness / 2])
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0, truncate = false);
translate([0, -width / 2])
square([1, width]);
square([dia + 1, 2 * thickness + door_thickness], center = true);
}
square([1, thickness + door_thickness]);
for(side = [-1, 1])
translate([-width + rad, side * (width / 2 - rad)])
circle4n(rad);
}
translate([dia / 2, thickness + door_thickness / 2])
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
rotate(180)
vflip()
door_hinge_hole_positions()
poly_circle(screw_clearance_radius(screw));
}
linear_extrude(thickness)
difference() {
hull() {
translate([0, -width / 2])
square([1, width]);
for(side = [-1, 1])
translate([-width + rad, side * (width / 2 - rad)])
circle4n(rad);
}
rotate(180)
vflip()
door_hinge_hole_positions()
poly_circle(screw_clearance_radius(screw));
}
}
}
}
module door_hinge_6_stl() door_hinge(6);
@@ -136,8 +136,7 @@ module door_hinge_assembly(top, door_thickness = 6) { //! The moving assembly th
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
pin_y = door_hinge_pin_y();
washer = screw_washer(screw);
screw_length = screw_shorter_than(thickness + door_thickness + washer_thickness(washer));
screw_length = screw_length(screw, thickness + door_thickness, 1);
translate([0, pin_y - (thickness + door_thickness / 2), dir * width / 2]) {
rotate([90, 0, 180])
@@ -148,20 +147,20 @@ module door_hinge_assembly(top, door_thickness = 6) { //! The moving assembly th
screw_and_washer(screw, screw_length);
}
translate([pin_x, pin_y, top ? 0 : -washer_thickness(screw_washer(pin_screw))])
washer(screw_washer(pin_screw));
washer = screw_washer(pin_screw);
wt = washer_thickness(washer);
translate([pin_x, pin_y, top ? 0 : -wt])
washer(washer);
translate([pin_x, pin_y, top ? washer_thickness(screw_washer(pin_screw)) + stat_width : width])
screw_and_washer(pin_screw, screw_longer_than(2 * washer_thickness(screw_washer(pin_screw)) + width + stat_width));
translate([pin_x, pin_y, top ? wt + stat_width : width])
screw_and_washer(pin_screw, screw_length(pin_screw, width + stat_width, 2, longer = true));
}
module door_hinge_static_assembly(top, sheet_thickness = 3) { //! The stationary assembly
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
stat_washer = screw_washer(stat_screw);
stat_nut = screw_nut(stat_screw);
stat_screw_length = screw_longer_than(thickness + sheet_thickness + 2 * washer_thickness(stat_washer) + nut_thickness(stat_nut, true));
stat_screw_length = screw_length(stat_screw, thickness + sheet_thickness, 2, nyloc = true);
translate([pin_x, 0, -dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw)))])
rotate([90, 0, 0]) {
@@ -169,9 +168,10 @@ module door_hinge_static_assembly(top, sheet_thickness = 3) { //! The stationary
door_hinge_stat_hole_positions() {
screw_and_washer(stat_screw, stat_screw_length);
translate_z(-thickness - sheet_thickness)
vflip()
nut_and_washer(stat_nut, true);
nut_and_washer(screw_nut(stat_screw), true);
}
}
}

View File

@@ -38,30 +38,30 @@ function door_latch_offset() = width / 2 + 1; //! Offset of the axle from the do
nut_trap_depth = round_to_layer(screw_head_height(screw)) + 4 * layer_height;
module door_latch_stl() { //! Generates the STL for the printed part
stl("door_latch");
ridge = 4;
difference() {
union() {
hull() {
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
translate_z(thickness / 2)
cube([length, ridge, thickness], center = true);
stl("door_latch")
difference() {
union() {
hull() {
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad);
translate_z(thickness / 2)
cube([length, ridge, thickness], center = true);
}
cylinder(d = width, h = height);
}
cylinder(d = width, h = height);
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickess
washer = screw_washer(screw);
nut = screw_nut(screw);
screw_length = screw_longer_than(height - nut_trap_depth + sheet_thickness + 2 * washer_thickness(washer) + nut_thickness(nut, true));
screw_length = screw_length(screw, height - nut_trap_depth + sheet_thickness, 2, nyloc = true);
translate([0, -height - washer_thickness(washer)])
rotate([-90, 0, 0]) {

View File

@@ -27,7 +27,7 @@
//! The ends can have screw lugs with four screw positions to choose from, specified by a list of two arrays of four bools.
//! If none are enabled then a child object is expected to customise the end and this gets unioned with the blank end.
//! If both ends are customised then two children are expected.
//! Each child is called twice, once with ```$fasteners``` set to 0 to augment the STL and again with ```$fasteners``` set to 1 to add
//! Each child is called twice, once with `$fasteners` set to 0 to augment the STL and again with `$fasteners` set to 1 to add
//! to the assembly, for example to add inserts.
//
@@ -251,7 +251,7 @@ module drag_chain_link(type, start = false, end = false, check_kids = true) { //
}
// Need to use a wrapper because can't define nested modules in an assembly
module _drag_chain_assembly(type, pos = 0) {
module _drag_chain_assembly(type, pos = 0, render = false) {
s = drag_chain_size(type);
x = (1 + exploded()) * s.x;
r = drag_chain_radius(type) * x / s.x;
@@ -278,8 +278,11 @@ module _drag_chain_assembly(type, pos = 0) {
module link(n) // Position and colour link with origin at the hinge hole
translate([-z / 2, 0, -z / 2]) {
stl_colour(n < 0 || n == npoints - 1 ? pp3_colour : n % 2 ? pp1_colour : pp2_colour)
drag_chain_link(type, start = n == -1, end = n == npoints - 1, check_kids = false)
let($fasteners = 0) children();
render_if(render)
drag_chain_link(type, start = n == -1, end = n == npoints - 1, check_kids = false)
let($fasteners = 0)
children();
let($fasteners = 1) children();
}
@@ -307,15 +310,15 @@ module _drag_chain_assembly(type, pos = 0) {
//! 1. Remove the support material from the links with side cutters.
//! 1. Clip the links together with the special ones at the ends.
module drag_chain_assembly(type, pos = 0) //! Drag chain assembly
assembly(str(drag_chain_name(type), "_drag_chain"), big = true)
module drag_chain_assembly(type, pos = 0, render = false) //! Drag chain assembly
assembly(str(drag_chain_name(type), "_drag_chain"), big = true, ngb = true)
if($children == 2)
_drag_chain_assembly(type, pos) {
_drag_chain_assembly(type, pos, render) {
children(0);
children(1);
}
else if($children == 1)
_drag_chain_assembly(type, pos)
_drag_chain_assembly(type, pos, render)
children(0);
else
_drag_chain_assembly(type, pos);
_drag_chain_assembly(type, pos, render);

View File

@@ -17,7 +17,7 @@
// If not, see <https://www.gnu.org/licenses/>.
//
//! Pintable fan finger guard to match the specified fan. To be ```include```d, not ```use```d.
//! Pintable fan finger guard to match the specified fan. To be `include`d, not `use`d.
//!
//! The ring spacing as well as the number of spokes can be specified, if zero a gasket is generated instead of a guard.
//

View File

@@ -25,10 +25,10 @@
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//!
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting ```show_block``` to false.
//! Specific fasteners can be omitted by setting a side's thickness to 0 and the block omitted by setting `show_block` to false.
//! This allows the block and one set of fasteners to be on one assembly and the other fasteners on the mating assemblies.
//!
//! Star washers can be omitted by setting ```star_washers``` to false.
//! Star washers can be omitted by setting `star_washers` to false.
//
include <../core.scad>
use <../vitamins/insert.scad>
@@ -71,42 +71,42 @@ module fixing_block_h_hole_2D(screw = def_screw) //! Position 2D child on the ho
children();
module fixing_block(screw = def_screw) { //! Generate the STL
stl(str("fixing_block_M", screw_radius(screw) * 20));
r = 1;
r = 1;
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
fb_width = fixing_block_width(screw);
fb_height = fixing_block_height(screw);
fb_depth = fixing_block_depth(screw);
difference() {
union() {
linear_extrude(fb_height, convexity = 5)
difference() {
hull() {
for(side = [-1, 1]) {
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
circle4n(corner_rad);
stl(str("fixing_block_M", screw_radius(screw) * 20))
difference() {
union() {
linear_extrude(fb_height, convexity = 5)
difference() {
hull() {
for(side = [-1, 1]) {
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
circle4n(corner_rad);
translate([side * (fb_width / 2 - r), r])
circle4n(r);
translate([side * (fb_width / 2 - r), r])
circle4n(r);
}
}
fixing_block_v_holes(screw)
poly_circle(screw_clearance_radius(screw));
}
fixing_block_v_holes(screw)
poly_circle(screw_clearance_radius(screw));
}
}
translate_z(fb_height)
fixing_block_v_holes(screw)
insert_hole(insert);
}
translate_z(fb_height)
fixing_block_v_holes(screw)
insert_hole(insert);
fixing_block_h_hole(screw)
insert_hole(insert, 10, true);
}
fixing_block_h_hole(screw)
insert_hole(insert, 10, true);
}
}
module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8]) //! Printed part with the inserts inserted
assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
assembly(str("fixing_block_M", 20 * screw_radius(screw)), ngb = true) {
translate_z(fixing_block_height(screw))
rotate([0, 180, 0])
stl_colour(pp1_colour) render() fixing_block(screw);
@@ -122,9 +122,7 @@ assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
module fastened_fixing_block_assembly(thickness, screw = def_screw, screw2 = undef, thickness2 = undef, show_block = true, star_washers = true) { //! Assembly with fasteners in place
module fb_screw(screw, thickness) {
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_longer_than((star_washers ? 2 : 1) * washer_thickness(washer) + thickness + insert_length(insert));
screw_length = screw_length(screw, thickness, star_washers ? 2 : 1, true, longer = true);
if(thickness)
translate_z(thickness)

View File

@@ -25,8 +25,8 @@
//!
//! Opening the test in OpenSCAD with its customiser enabled allows these parameters to be played with.
//!
//! Note setting ```thickness1``` or ```thickness2``` to zero in the ```hinge_fastened_assembly()``` removes the screws from one side or the other and
//! setting ```show_hinge``` to false removes the hinge.
//! Note setting `thickness1` or `thickness2` to zero in the `hinge_fastened_assembly()` removes the screws from one side or the other and
//! setting `show_hinge` to false removes the hinge.
//! This allows the hinges and one set of screws to belong to one assembly and the other set of screws to another assembly.
//
include <../core.scad>
@@ -65,8 +65,6 @@ module hinge_screw_positions(type) { //! Place children at the screw positions
}
module hinge_male(type, female = false) { //! The half with the stationary pin
stl(str("hinge_", female ? "fe": "", "male_", type[0]));
r = hinge_radius(type);
w = hinge_width(type);
t = hinge_thickness(type);
@@ -85,37 +83,40 @@ module hinge_male(type, female = false) { //! The half with the stationary
teardrop_r = kr / cos(22.5); // The corner on the teardrop
inset = sqrt(sqr(teardrop_r + gap) - sqr(kr - t)) - kr;
linear_extrude(t)
difference() {
hull() {
for(side = [-1, 1])
translate([side * (w / 2 - r), hinge_depth(type) - r])
circle4n(r);
stl(str("hinge_", female ? "fe": "", "male_", type[0]))
union() {
linear_extrude(t)
difference() {
hull() {
for(side = [-1, 1])
translate([side * (w / 2 - r), hinge_depth(type) - r])
circle4n(r);
translate([-w / 2, inset])
square([w, eps]);
}
hinge_screw_positions(type)
poly_circle(screw_clearance_radius(hinge_screw(type)));
translate([-w / 2, inset])
square([w, eps]);
}
hinge_screw_positions(type)
poly_circle(screw_clearance_radius(hinge_screw(type)));
}
pitch = mw + gap + fw + gap;
dir = female ? -1 : 1;
translate([0, -kr, kr])
rotate([90, 0, -90])
for(z = [0 : (female ? fn : mn) - 1])
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
linear_extrude(female ? fw : mw)
difference() {
hull() {
rotate(180)
teardrop(r = kr, h = 0);
translate([-kr - 1, -kr])
square(1);
}
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
}
}
pitch = mw + gap + fw + gap;
dir = female ? -1 : 1;
translate([0, -kr, kr])
rotate([90, 0, -90])
for(z = [0 : (female ? fn : mn) - 1])
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
linear_extrude(female ? fw : mw)
difference() {
hull() {
rotate(180)
teardrop(r = kr, h = 0);
translate([-kr - 1, -kr])
square(1);
}
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
}
}
module hinge_female(type) hinge_male(type, true);
@@ -129,7 +130,7 @@ module hinge_both(type) { //! Both parts together for printing
}
module hinge_assembly(type, angle = 0)
assembly(str("hinge_", type[0])) { //! Assembled hinge
assembly(str("hinge_", type[0]), ngb = true) { //! Assembled hinge
kr = hinge_knuckle_dia(type) / 2;
hr = hinge_pin_dia(type) / 2;
w = hinge_width(type);
@@ -155,9 +156,7 @@ module hinge_fastened_assembly(type, thickness1, thickness2, angle, show_hinge =
hinge_assembly(type, angle);
screw = hinge_screw(type);
washer_t = 2 * washer_thickness(screw_washer(screw));
nut = screw_nut(screw);
nut_t = nut_thickness(nut, true);
t = hinge_thickness(type);
kr = hinge_knuckle_dia(type) / 2;
@@ -165,7 +164,7 @@ module hinge_fastened_assembly(type, thickness1, thickness2, angle, show_hinge =
if(thickness)
hinge_screw_positions(type) {
translate_z(t)
screw_and_washer(screw, screw_longer_than(t + thickness + washer_t + nut_t));
screw_and_washer(screw, screw_length(screw, t + thickness, 2, nyloc = true));
translate_z(-thickness)
vflip()

View File

@@ -39,7 +39,6 @@ function foot_screw(type = foot) = type[4]; //! Screw type
function foot_slant(type = foot) = type[5]; //! Taper angle
module foot(type = foot) { //! Generate STL
stl("foot");
h = foot_height(type);
t = foot_thickness(type);
r1 = washer_radius(screw_washer(foot_screw(type)));
@@ -47,32 +46,32 @@ module foot(type = foot) { //! Generate STL
r2 = r3 - h * tan(foot_slant(type));
r = foot_rad(type);
union() {
rotate_extrude(convexity = 3) {
hull() {
translate([r1, 0])
square([r3 - r1, eps]);
stl("foot")
union() {
rotate_extrude(convexity = 3) {
hull() {
translate([r1, 0])
square([r3 - r1, eps]);
for(x = [r1 + r, r2 - r])
translate([x, h - r])
circle4n(r);
for(x = [r1 + r, r2 - r])
translate([x, h - r])
circle4n(r);
}
}
linear_extrude(t)
difference() {
circle(r1 + eps);
poly_circle( screw_clearance_radius(foot_screw(type)));
}
}
linear_extrude(t)
difference() {
circle(r1 + eps);
poly_circle( screw_clearance_radius(foot_screw(type)));
}
}
}
module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
nut = screw_nut(screw);
squeeze = 0.5;
screw_length = screw_longer_than(foot_thickness(type) + t + 2 * washer_thickness(washer) + nut_thickness(nut, true) - squeeze);
screw_length = screw_length(screw, foot_thickness(type) + t - squeeze, 2, nyloc = true);
vflip() explode(15, true) {
stl_colour(pp4_colour) foot(type);
@@ -94,7 +93,6 @@ module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with faste
}
module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
stl("insert_foot");
h = foot_height(type);
r3 = foot_diameter(type) / 2;
r2 = r3 - h * tan(foot_slant(type));
@@ -104,36 +102,37 @@ module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
h2 = insert_hole_length(insert);
r4 = insert_hole_radius(insert);
r5 = r4 + 1;
union() {
rotate_extrude() {
union() {
hull() {
translate([r5, 0]) {
square([r3 - r5, eps]);
square([eps, h]);
}
stl("insert_foot")
union() {
rotate_extrude() {
union() {
hull() {
translate([r5, 0]) {
square([r3 - r5, eps]);
square([eps, h]);
}
translate([r2 - r, h - r])
circle4n(r);
translate([r2 - r, h - r])
circle4n(r);
}
}
}
linear_extrude(h2 + eps)
difference() {
circle(r5 + eps);
poly_circle(r4);
}
translate_z(h2)
cylinder(r = r5 + eps, h = h - h2);
}
linear_extrude(h2 + eps)
difference() {
circle(r5 + eps);
poly_circle(r4);
}
translate_z(h2)
cylinder(r = r5 + eps, h = h - h2);
}
}
//
//! Place the insert in the bottom of the foot and push home with a soldering iron with a conical bit heated to 200&deg;C.
//
module insert_foot_assembly(type = insert_foot) //! Printed part with insert in place
assembly("insert_foot") {
assembly("insert_foot", ngb = true) {
screw = foot_screw(type);
insert = screw_insert(screw);
@@ -146,9 +145,7 @@ assembly("insert_foot") {
module fastened_insert_foot_assembly(t = 3, type = insert_foot) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_shorter_than(insert_length(insert) + t + 2 * washer_thickness(washer));
screw_length = screw_length(screw, t, 2, insert = true);
explode(-10) insert_foot_assembly(type);

View File

@@ -46,8 +46,6 @@ module handle_holes(h = 100) //! Drills holes for the screws
drill(screw_clearance_radius(screw), h);
module handle_stl() { //! generate the STL
stl("handle");
module end(end)
translate([end * pitch / 2, 0])
rotate_extrude()
@@ -59,29 +57,30 @@ module handle_stl() { //! generate the STL
square([dia / 2 + 1, dia + 1]);
}
translate_z(dia / 2)
union() {
hull() {
end(-1);
stl("handle")
translate_z(dia / 2)
union() {
hull() {
end(-1);
end(1);
}
handle_screw_positions()
render() difference() {
h = height + dia / 2;
cylinder(d = dia, h = h);
translate_z(h)
insert_hole(insert, 6);
end(1);
}
}
handle_screw_positions()
render() difference() {
h = height + dia / 2;
cylinder(d = dia, h = h);
translate_z(h)
insert_hole(insert, 6);
}
}
}
//
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") {
assembly("handle", ngb = true) {
translate_z(handle_height())
stl_colour(pp1_colour) vflip() handle_stl();
@@ -91,7 +90,7 @@ assembly("handle") {
}
module handle_fastened_assembly(thickness) { //! Assembly with fasteners in place
screw_length = screw_longer_than(thickness + insert_length(insert) + 2 * washer_thickness(screw_washer(screw)));
screw_length = screw_length(screw, thickness, 2, true, longer = true);
handle_assembly();

View File

@@ -66,35 +66,35 @@ module pcb_mount_washer_stl() //! A plastic washer to clamp a PCB
pcb_mount_ring();
module pcb_mount(pcb, height = 5, washers = true) { //! Make the STL of a pcb mount for the specified PCB.
stl(str("pcb_mount_", pcb[0], "_", height));
y_pitch = pcb_width(pcb) > 4 * pillar_r + 4 ? pillar_r + 1
: pcb_width(pcb) / 2 + frame_w + 1 + pillar_r;
if(washers)
for(x = [-1, 1], y = [-1, 1])
translate([x * (pillar_r + 1), y * y_pitch, 0])
pcb_mount_washer_stl();
stl(str("pcb_mount_", pcb[0], "_", height)) union() {
if(washers)
for(x = [-1, 1], y = [-1, 1])
translate([x * (pillar_r + 1), y * y_pitch, 0])
pcb_mount_washer_stl();
for(x = [-1, 1])
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
for(x = [-1, 1])
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
for(y = [-1, 1])
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
for(y = [-1, 1])
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
pcb_mount_screw_positions(pcb)
linear_extrude(height)
pcb_mount_ring();
linear_extrude(height + pcb_thickness(pcb) - layer_height)
difference() {
pcb_mount_screw_positions(pcb)
pcb_mount_screw_positions(pcb)
linear_extrude(height)
pcb_mount_ring();
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
}
linear_extrude(height + pcb_thickness(pcb) - layer_height)
difference() {
pcb_mount_screw_positions(pcb)
pcb_mount_ring();
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
}
}
}
module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly with fasteners
@@ -103,10 +103,9 @@ module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly
stl_colour(pp1_colour) pcb_mount(pcb, washers = false);
washer = screw_washer(screw);
nut = screw_nut(screw);
t = pcb_thickness(pcb);
screw_length = screw_longer_than(height + t + washer_thickness + thickness + washer_thickness(washer) + nut_thickness(nut, true));
screw_length = screw_length(screw, height + t + washer_thickness + thickness, 1, nyloc = true);
pcb_mount_screw_positions(pcb) {
translate_z(height + t) {

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);
}
}
}

View File

@@ -65,10 +65,8 @@ function pbox_insert(type) = screw_insert(pbox_screw(type)); //! The insert for
function pbox_washer(type) = screw_washer(pbox_screw(type)); //! The washer for the base screws
function pbox_screw_length(type, panel_thickness = 0) = //! Length of the base screw
let(foot = pbox_foot(type))
screw_shorter_than(pbox_base(type) + washer_thickness(pbox_washer(type))
+ insert_length(pbox_insert(type))
+ (foot ? foot_thickness(foot) : panel_thickness));
let(foot = pbox_foot(type), screw = pbox_screw(type))
screw_length(screw, pbox_base(type) + (foot ? foot_thickness(foot) : panel_thickness), 1, true);
function pbox_mid_offset(type) = pbox_ridges(type).y + pbox_wall(type) / 2; // Offset to wall midpoint
@@ -131,28 +129,27 @@ module pbox_outer_shape(type) //! 2D outer shape of the box
offset(pbox_wall(type) / 2) pbox_mid_shape(type);
module pbox_base(type) { //! Generate the STL for the base
stl(str(pbox_name(type),"_base"));
t = pbox_base(type);
difference() {
union() {
linear_extrude(t)
offset(base_outset - 0.2)
pbox_inner_shape(type);
if($children > 0)
children(0);
stl(str(pbox_name(type),"_base"))
difference() {
union() {
linear_extrude(t)
offset(base_outset - 0.2)
pbox_inner_shape(type);
if($children > 0)
children(0);
}
pbox_screw_positions(type)
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
if($children > 1)
children(1);
}
pbox_screw_positions(type)
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
if($children > 1)
children(1);
}
}
module pbox(type) { //! Generate the STL for the main case
stl(pbox_name(type));
height = pbox_height(type);
total_height = pbox_total_height(type);
top_thickness = pbox_top(type);
@@ -161,60 +158,61 @@ module pbox(type) { //! Generate the STL for the main case
ledge_inset = base_outset - base_overlap;
ledge_h = pbox_base(type) ? (ledge_outset - ledge_inset) * 2 : 0;
difference() {
union() {
linear_extrude(total_height)
pbox_outer_shape(type);
if($children > 2)
children(2);
}
stl(pbox_name(type))
difference() {
translate_z(top_thickness)
union() {
linear_extrude(height + eps)
offset(-wall / 2) pbox_mid_shape(type);
union() {
linear_extrude(total_height)
pbox_outer_shape(type);
translate_z(height) // Recess for the base
linear_extrude(total_height - height)
offset(base_outset)
pbox_inner_shape(type);
}
// Ledge to support the lid
if(ledge_h)
translate_z(top_thickness + height - ledge_h)
difference() {
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1, center = false);
if($children > 2)
children(2);
}
difference() {
translate_z(top_thickness)
union() {
linear_extrude(height + eps)
offset(-wall / 2) pbox_mid_shape(type);
hull() {
linear_extrude(ledge_h + eps)
offset(ledge_inset)
translate_z(height) // Recess for the base
linear_extrude(total_height - height)
offset(base_outset)
pbox_inner_shape(type);
linear_extrude(eps)
offset(ledge_outset)
pbox_inner_shape(type);
}
pbox_screw_positions(type)
insert_hole(pbox_insert(type));
}
// Ledge to support the lid
if(ledge_h)
translate_z(top_thickness + height - ledge_h)
difference() {
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1);
// Corner lugs for inserts
outset = wall + pbox_ridges(type).y;
or = pbox_radius(type) + outset;
inset = pbox_screw_inset(type) + outset;
br = insert_boss_radius(pbox_insert(type), wall);
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
translate_z(height + top_thickness)
pbox_screw_positions(type)
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
hull() {
linear_extrude(ledge_h + eps)
offset(ledge_inset)
pbox_inner_shape(type);
if($children > 0)
children(0);
linear_extrude(eps)
offset(ledge_outset)
pbox_inner_shape(type);
}
pbox_screw_positions(type)
insert_hole(pbox_insert(type));
}
// Corner lugs for inserts
outset = wall + pbox_ridges(type).y;
or = pbox_radius(type) + outset;
inset = pbox_screw_inset(type) + outset;
br = insert_boss_radius(pbox_insert(type), wall);
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
translate_z(height + top_thickness)
pbox_screw_positions(type)
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
if($children > 0)
children(0);
}
if($children > 1)
children(1);
}
if($children > 1)
children(1);
}
}
module pbox_inserts(type) //! Place the inserts for the base screws

View File

@@ -0,0 +1,200 @@
//
// 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/>.
//
//! Printed pulleys are a remix of droftarts's (see <https://www.thingiverse.com/droftarts/designs>) Parametric Pulleys
//! on Thingiverse (see <https://www.thingiverse.com/thing:16627>) and are licensed under the
//! Creative Commons - Attribution - Share Alike license (see <https://creativecommons.org/licenses/by-sa/3.0/>)
//
include <../core.scad>
include <../vitamins/pulleys.scad>
printed_pulley_GT2_profile = [[0.747183,-0.5],[0.747183,0],[0.647876,0.037218],[0.598311,0.130528],[0.578556,0.238423],[0.547158,0.343077],[0.504649,0.443762],[0.451556,0.53975],[0.358229,0.636924],[0.2484,0.707276],[0.127259,0.750044],[0,0.76447],[-0.127259,0.750044],[-0.2484,0.707276],[-0.358229,0.636924],[-0.451556,0.53975],[-0.504797,0.443762],[-0.547291,0.343077],[-0.578605,0.238423],[-0.598311,0.130528],[-0.648009,0.037218],[-0.747183,0],[-0.747183,-0.5]];
function printed_pulley_inverted(type) = pulley_hub_dia(type) < pulley_flange_dia(type); //! Need to print upside down to prevent overhang
function printed_pulley_od(tooth_count, tooth_pitch, pitch_line_offset)
= tooth_count * tooth_pitch / PI - 2 * pitch_line_offset;
module printed_pulley_teeth_from_profile(tooth_count, tooth_depth, tooth_width, tooth_profile) {
pulley_od = printed_pulley_od(tooth_count, 2, 0.254);
difference() {
rotate (90 / tooth_count)
circle(r = pulley_od / 2, $fn = tooth_count * 4);
tooth_distance_from_centre = sqrt(pulley_od * pulley_od - (tooth_width + 0.2) * (tooth_width + 0.2)) / 2;
for(i = [1 : tooth_count])
rotate(i * 360 / tooth_count)
translate([0, -tooth_distance_from_centre])
scale([(tooth_width + 0.2) / tooth_width, 1])
polygon(tooth_profile);
}
}
module printed_pulley_GT2_teeth(type) {
tooth_count = pulley_teeth(type);
if (tooth_count == 0)
circle(r = pulley_od(type) / 2);
else
printed_pulley_teeth_from_profile(tooth_count, 0.764, 1.494, printed_pulley_GT2_profile);
}
module printed_pulley_teeth(type) { //! Draw the pulley's teeth
tooth_count = pulley_teeth(type);
tw = pulley_od(type) * PI / (tooth_count * 2);
ir = pulley_ir(type);
or = pulley_od(type) / 2;
T_angle = 40;
GT_r = 0.555;
for (i = [0 : 1 : tooth_count - 1])
rotate(i * 360 / tooth_count)
if (pulley_type(type)[0] == "G")
translate([0, ir + GT_r])
hull() {
circle(GT_r);
translate([0, GT_r])
square(2 * GT_r, center = true);
}
else
translate([0, (ir + or) / 2])
hull() {
for(side = [-1, 1])
translate([side * tw / 2, 0])
rotate(-side * T_angle / 2)
square([eps, (or - ir)], center = true);
translate([0, 1])
square([tw, eps], center = true);
}
}
module printed_pulley(type) { //! Draw a printable pulley
ft = pulley_flange_thickness(type);
hl = pulley_hub_length(type);
w = pulley_width(type);
r1 = pulley_bore(type) / 2;
or = pulley_od(type) / 2;
screw_z = pulley_screw_z(type);
module core() {
translate_z(pulley_hub_length(type) + ft)
linear_extrude(w + 1) let($fa = 1, $fs = 0.1)
if ("GT2" == str(pulley_type(type)[0], pulley_type(type)[1], pulley_type(type)[2]))
difference() {
printed_pulley_GT2_teeth(type);
circle(d = pulley_bore(type));
}
else
difference() {
circle(or);
printed_pulley_teeth(type);
circle(d = pulley_bore(type));
}
}
module screw_holes() {
if(pulley_screws(type))
translate_z(screw_z)
for(i = [0 : pulley_screws(type) - 1])
rotate([-90, 180, i * -90])
if(show_supports())
teardrop(r = screw_pilot_hole(pulley_screw(type)), h = pulley_flange_dia(type) / 2 + 1, center = false);
else
cylinder(r = screw_radius(pulley_screw(type)), h = pulley_flange_dia(type) / 2 + 1);
}
module hub()
linear_extrude(hl)
difference() {
circle(d= pulley_hub_dia(type));
circle(d = pulley_bore(type));
}
stl(str("printed_pulley_", type[0]))
translate_z(printed_pulley_inverted(type) ? - hl : 0) {
// hub
if(hl)
translate_z(printed_pulley_inverted(type) ? hl + w + 2 * ft : 0)
if(screw_z && screw_z < hl)
render()
difference() {
hub();
screw_holes();
}
else
hub();
// bottom flange
translate_z(hl)
linear_extrude(ft)
difference() {
circle(d = pulley_flange_dia(type));
circle(d = pulley_bore(type));
}
// top flange
translate_z(hl + ft + w) {
// inner part, supported by core
linear_extrude(ft)
difference() {
circle(r = or);
circle(d = pulley_bore(type));
}
// outer part at 45 degrees for printing
rotate_extrude()
translate([or - eps, ft])
vflip()
right_triangle(ft, ft);
}
if(screw_z && screw_z > hl)
render()
difference() { // T5 pulleys have screws through the teeth
core();
translate_z(printed_pulley_inverted(type) ? pulley_height(type) + hl - 2 * screw_z : 0)
screw_holes();
}
else
core();
}
}
module printed_pulley_assembly(type, colour = pp1_colour) //! Draw a printed pulley with its grub screws in place
assembly(str("printed_pulley_", type[0]), ngb = true) {
translate_z(pulley_offset(type)) {
stl_colour(colour)
if(printed_pulley_inverted(type))
translate_z(pulley_height(type))
hflip()
printed_pulley(type);
else
printed_pulley(type);
if(pulley_screws(type))
translate_z(pulley_screw_z(type))
for(i = [0 : pulley_screws(type) - 1])
rotate([-90, 0, i * -90])
translate_z(pulley_bore(type) / 2 + pulley_screw_length(type))
screw(pulley_screw(type), pulley_screw_length(type));
}
}

View File

@@ -79,8 +79,6 @@ module psu_shroud_holes(type, cable_d, cables = 1) {
}
module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file for a specified ssr and cable
stl(str("psu_shroud_", name));
extent = psu_shroud_extent(type);
depth = psu_shroud_depth(type);
width = psu_shroud_width(type);
@@ -109,41 +107,43 @@ module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file f
}
}
// base and sides
translate([centre_x, -centre_y]) {
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
stl(str("psu_shroud_", name)) {
// base and sides
translate([centre_x, -centre_y]) {
rounded_rectangle([depth - eps, width - eps, top], rad);
linear_extrude(height)
difference() {
linear_extrude(height)
difference() {
shape();
translate([depth / 2, width / 2 - 5])
square([2 * (depth - extent + terminal_clearance), 10], center = true);
}
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
shape();
translate([depth / 2, width / 2 - 5])
square([2 * (depth - extent + terminal_clearance), 10], center = true);
}
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
shape();
}
// cable slots
for(i = [0 : 1 : cables - 1])
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
rotate([90, 0, 90])
linear_extrude(wall, center = true)
difference() {
square([cable_d + eps, height], center = true);
// cable slots
for(i = [0 : 1 : cables - 1])
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
rotate([90, 0, 90])
linear_extrude(wall, center = true)
difference() {
square([cable_d + eps, height], center = true);
translate([0, height / 2])
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
}
// insert lugs
mirror([0, 1, 0])
psu_shroud_hole_positions(type)
translate_z(height)
rotate($side * 90)
insert_lug(insert, wall, counter_bore);
}
translate([0, height / 2])
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
}
// insert lugs
mirror([0, 1, 0])
psu_shroud_hole_positions(type)
translate_z(height)
rotate($side * 90)
insert_lug(insert, wall, counter_bore);
}
}
module psu_shroud_assembly(type, cable_d, name, cables = 1) //! The printed parts with inserts fitted
assembly(str("PSU_shroud_", name)) {
assembly(str("PSU_shroud_", name), ngb = true) {
translate_z(psu_shroud_height(type))
vflip()
@@ -156,8 +156,7 @@ assembly(str("PSU_shroud_", name)) {
module psu_shroud_fastened_assembly(type, cable_d, thickness, name, cables = 1) //! Assembly with screws in place
{
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + insert_length(insert) + counter_bore);
screw_length = screw_length(screw,thickness + counter_bore, 2, true);
psu_shroud_assembly(type, cable_d, name, cables);

View File

@@ -47,7 +47,6 @@ module ribbon_clamp_holes(ways, h = 20, screw = screw) //! Drill screw holes
module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of ways
screw_d = screw_radius(screw) * 2;
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""));
pitch = ribbon_clamp_hole_pitch(ways, screw);
d = ribbon_clamp_width(screw);
@@ -55,34 +54,35 @@ module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of
t = round_to_layer(ribbon_clamp_slot_depth() + wall);
insert = screw_insert(screw);
difference() {
union() {
hull() {
translate_z(h - t / 2)
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""))
difference() {
union() {
hull() {
translate_z(h - t / 2)
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
translate_z(1)
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
translate_z(1)
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
}
ribbon_clamp_hole_positions(ways, screw, -1)
cylinder(d = d, h = h);
ribbon_clamp_hole_positions(ways, screw, 1)
cylinder(d = d, h = h);
}
ribbon_clamp_hole_positions(ways, screw, -1)
cylinder(d = d, h = h);
ribbon_clamp_hole_positions(ways, screw, 1)
cylinder(d = d, h = h);
}
translate_z(h)
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
ribbon_clamp_hole_positions(ways, screw)
translate_z(h)
rotate(22.5)
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
}
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
ribbon_clamp_hole_positions(ways, screw)
translate_z(h)
rotate(22.5)
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
}
}
module ribbon_clamp_assembly(ways, screw = screw) pose([55, 180, 25]) //! Printed part with inserts in place
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : "")) {
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""), ngb = true) {
h = ribbon_clamp_height(screw);
insert = screw_insert(screw);
@@ -101,8 +101,7 @@ module ribbon_clamp_fastened_assembly(ways, thickness, screw = screw) { //! Clam
vitamin(str(": Tape self amalgamating silicone ",tape_l," x 25mm"));
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + ribbon_clamp_screw_depth(screw));
screw_length = screw_length(screw, thickness + ribbon_clamp_screw_depth(screw), 2);
ribbon_clamp_assembly(ways, screw);

View File

@@ -34,32 +34,31 @@ knob_height = knob_stem_h + knob_thickness;
function knob_height() = knob_height;
module screw_knob(screw) { //! Generate the STL for a knob to fit the specified hex screw
stl(str("screw_knob_M", screw_radius(screw) * 20));
knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;
function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;
union() {
render() difference() {
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
stl(str("screw_knob_M", screw_radius(screw) * 20))
union() {
render() difference() {
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
linear_extrude(knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
circle(knob_stem_r - eps);
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}
linear_extrude(knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
circle(knob_stem_r - eps);
}
}
}
//! Place the screw through the printed part
module screw_knob_assembly(screw, length) //! Assembly with the screw in place
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length)) {
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length), ngb = true) {
translate_z(knob_height)
vflip()
stl_colour(pp1_colour) screw_knob(screw);

View File

@@ -41,7 +41,6 @@ height = base_thickness + box_height;
function socket_box_depth() = height; //! Outside depth of the backbox
module socket_box(type) { //! Generate STL of the backbox for the specified socket
stl(str("socket_box_",type[0]));
screw = mains_socket_screw(type);
screw_clearance_radius = screw_clearance_radius(screw);
@@ -51,37 +50,38 @@ module socket_box(type) { //! Generate STL of the backbox for the specified sock
insert_boss = mains_socket_insert_boss(type);
insert_hole_radius = insert_hole_radius(insert);
difference() {
linear_extrude(height, convexity = 5)
face_plate(type);
stl(str("socket_box_",type[0]))
difference() {
translate_z(base_thickness)
linear_extrude(height, convexity = 5)
offset(-wall) offset(1) face_plate(type);
linear_extrude(height, convexity = 5)
face_plate(type);
for(side = [-1, 1])
hull()
for(x = [1, 2])
translate([side * mains_socket_pitch(type) / x, 0])
cylinder(d = insert_boss, h = 100);
}
//
// Socket holes
//
translate_z(height)
mains_socket_hole_positions(type) {
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
difference() {
translate_z(base_thickness)
linear_extrude(height, convexity = 5)
offset(-wall) offset(1) face_plate(type);
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
for(side = [-1, 1])
hull()
for(x = [1, 2])
translate([side * mains_socket_pitch(type) / x, 0])
cylinder(d = insert_boss, h = 100);
}
//
// Cable hole
//
translate([cable_x, cable_y(type), cable_z])
rotate([90, 0, 0])
teardrop_plus(r = cable_d / 2, h = 30);
}
//
// Socket holes
//
translate_z(height)
mains_socket_hole_positions(type) {
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
}
//
// Cable hole
//
translate([cable_x, cable_y(type), cable_z])
rotate([90, 0, 0])
teardrop_plus(r = cable_d / 2, h = 30);
}
}
module socket_box_MKLOGIC_stl() socket_box(MKLOGIC);
@@ -105,8 +105,7 @@ module socket_box_MKLOGIC_assembly() socket_box_assembly(MKLOGIC);
module socket_box_fastened_assembly(type, thickness) { //! The socket and backbox on each side of the specified panel thickness
screw = mains_socket_screw(type);
insert = screw_insert(screw);
screw_length = screw_longer_than(mains_socket_height(type) + thickness + insert_length(insert));
screw_length = screw_length(screw, mains_socket_height(type) + thickness, 0, true, longer = true);
explode(-50)
translate_z(-height - thickness)

View File

@@ -61,53 +61,54 @@ module ssr_shroud_holes(type, cable_d) { //! Drill the screw and ziptie holes
}
module ssr_shroud(type, cable_d, name) { //! Generate the STL file for a specified ssr and cable
stl(str("ssr_shroud_", name));
width = ssr_shroud_width(type);
depth = ssr_length(type) / 3 + ssr_shroud_extent(type, cable_d);
height = ssr_shroud_height(type);
cable_x = ssr_shroud_cable_x(type, cable_d);
center_x = -ssr_length(type) / 6 - depth / 2;
// base and sides
translate([center_x, 0]) {
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
linear_extrude(height) difference() {
round(or = wall / 2 - eps, ir = 0) difference() {
rounded_square([depth, width], rad);
stl(str("ssr_shroud_", name)) {
// base and sides
translate([center_x, 0]) {
rounded_rectangle([depth - eps, width - eps, top], rad);
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
linear_extrude(height) difference() {
round(or = wall / 2 - eps, ir = 0) difference() {
rounded_square([depth, width], rad);
translate([depth / 2, 0])
square([2 * rad, width], center = true);
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
translate([depth / 2, 0])
square([2 * rad, width], center = true);
}
translate([cable_x - center_x, 0])
square([cable_d, width + 1], center = true);
}
translate([cable_x - center_x, 0])
square([cable_d, width + 1], center = true);
}
}
// cable slots
for(side = [-1, 1])
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
rotate([90, 0, 0])
linear_extrude(wall, center = true)
difference() {
square([cable_d + eps, height], center = true);
// cable slots
for(side = [-1, 1])
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
rotate([90, 0, 0])
linear_extrude(wall, center = true)
difference() {
square([cable_d + eps, height], center = true);
translate([0, height / 2])
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
}
// insert boss
ssr_shroud_hole_positions(type)
vflip()
translate_z(height)
rotate($side * 90)
insert_lug(insert, wall, counter_bore);
translate([0, height / 2])
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
}
// insert boss
ssr_shroud_hole_positions(type)
vflip()
translate_z(height)
rotate($side * 90)
insert_lug(insert, wall, counter_bore);
}
}
module ssr_shroud_assembly(type, cable_d, name) //! The printed parts with inserts fitted
assembly(str("SSR_shroud_", name)) {
assembly(str("SSR_shroud_", name), ngb = true) {
translate_z(ssr_shroud_height(type))
vflip()
@@ -119,8 +120,7 @@ assembly(str("SSR_shroud_", name)) {
module ssr_shroud_fastened_assembly(type, cable_d, thickness, name) //! Assembly with screws in place
{
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + insert_length(insert) + counter_bore);
screw_length = screw_length(screw, thickness + counter_bore, 2, true);
ssr_shroud_assembly(type, cable_d, name);

View File

@@ -75,32 +75,29 @@ module strap_holes(length, type = strap, h = 100) //! The panel cut outs
strap_boss_shape(type);
module strap(length, type = strap) { //! Generate the STL for the rubber strap
stl("strap");
len = length - 2 * (wall + clearance);
w = strap_width(type);
linear_extrude(strap_thickness(type), convexity = 3)
difference() {
rounded_square([len, w], w / 2 - eps);
stl("strap")
linear_extrude(strap_thickness(type), convexity = 3)
difference() {
rounded_square([len, w], w / 2 - eps);
for(end = [-1, 1])
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
rotate(end * 90 + 90)
hull() {
offset(clearance)
strap_boss_shape(type);
translate([strap_extension(type) / 2, 0])
for(end = [-1, 1])
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
rotate(end * 90 + 90)
hull() {
offset(clearance)
strap_boss_shape(type);
}
}
translate([strap_extension(type) / 2, 0])
offset(clearance)
strap_boss_shape(type);
}
}
}
module strap_end(type = strap) { //! Generate the STL for end piece
stl("strap_end");
z1 = strap_height(type) - strap_thickness(type) - clearance;
z2 = strap_height(type) + strap_key(type);
r1 = strap_boss_r(type) - 1;
@@ -121,48 +118,49 @@ module strap_end(type = strap) { //! Generate the STL for end piece
circle(r1);
}
union() {
linear_extrude(z1)
with_hole()
outer();
translate_z(z1)
linear_extrude(strap_height(type) - z1)
difference() {
stl("strap_end")
union() {
linear_extrude(z1)
with_hole()
outer();
hull() {
translate([0, -strap_width(type) / 2 - clearance])
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
translate_z(z1)
linear_extrude(strap_height(type) - z1)
difference() {
outer();
translate([-strap_extension(type) / 2, 0])
circle(d = strap_width(type) + 2 * clearance);
hull() {
translate([0, -strap_width(type) / 2 - clearance])
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
translate([-strap_extension(type) / 2, 0])
circle(d = strap_width(type) + 2 * clearance);
}
}
}
linear_extrude(strap_height(type) - layer_height)
with_hole()
strap_boss_shape(type);
linear_extrude(strap_height(type) - layer_height)
with_hole()
strap_boss_shape(type);
linear_extrude(z2)
with_hole()
offset(cnc_bit_r)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
linear_extrude(z2)
with_hole()
offset(cnc_bit_r)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
render() difference() {
cylinder(r = r1 + eps, h = z2);
render() difference() {
cylinder(r = r1 + eps, h = z2);
translate_z(z2)
insert_hole(strap_insert(type), counterbore);
translate_z(z2)
insert_hole(strap_insert(type), counterbore);
}
}
}
}
//
//! * Place the insert into the hole and push home with a soldering iron with a tapered bit heated to 200&deg;C.
//
module strap_end_assembly(type = strap)
assembly("strap_end") {
assembly("strap_end", ngb = true) {
stl_colour(pp1_colour)
strap_end(type);
@@ -172,11 +170,9 @@ assembly("strap_end") {
module strap_assembly(length, type = strap) { //! Assembly with screws in place
screw = strap_screw(type);
washer = screw_washer(screw);
penny = penny_washer(washer);
insert = strap_insert(type);
penny = penny_washer(screw_washer(screw));
screw_length = screw_shorter_than(washer_thickness(washer) + washer_thickness(penny) + insert_length(insert) + panel_clearance + counterbore);
screw_length = screw_length(screw, washer_thickness(penny) + panel_clearance + counterbore, 1, true);
stl_colour(pp4_colour) strap(length, type);

5159
readme.md

File diff suppressed because it is too large Load Diff

View File

@@ -39,8 +39,6 @@ def _scrape_blurb(lines):
if b:
break
text += t
if len(text):
text += '\n'
return text
def scrape_blurb(scad_file):
@@ -49,6 +47,16 @@ def scrape_blurb(scad_file):
lines = file.readlines()
return _scrape_blurb(lines)
def split_blurb(lines):
""" Split blurb on horizontal rules."""
blurbs = [""]
for line in lines.split('\n')[:-1]:
if re.match(r'\*{3,}',line):
blurbs.append("")
else:
blurbs[-1] += line + '\n'
return blurbs
def scrape_module_blurb(lines):
""" Find the Markup lines before the last function or module. """
text = ""

View File

@@ -60,6 +60,8 @@ class BOM:
def __init__(self, name):
self.name = name
self.big = None
self.ngb = False
self.zoomed = 0
self.count = 1
self.vitamins = {}
self.printed = {}
@@ -73,6 +75,8 @@ class BOM:
return {
"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},
@@ -249,7 +253,7 @@ def boms(target = None, assembly = None):
#
# Run openscad
#
openscad.run("-D", "$bom=2", "-D", "$preview=true", "--hardwarnings", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
openscad.run("-D", "$bom=2", "-D", "$preview=true", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
os.remove(bom_maker_name)
print("Generating bom ...", end=" ")

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

@@ -36,7 +36,7 @@ def doc_scripts():
print(
'''
# Python scripts
These are located in the ```scripts``` subdirectory, which needs to be added to the program search path.
These are located in the `scripts` subdirectory, which needs to be added to the program search path.
They should work with both Python 2 and Python 3.
@@ -60,7 +60,8 @@ They should work with both Python 2 and Python 3.
break
if not blurb:
print("Missing description for", file)
print("| ```%s``` | %s |" % (file, blurb), file = doc_file)
else:
print("| `%s` | %s |" % (file, blurb), file = doc_file)
with open(dir + "/readme.html", "wt") as html_file:
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)

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,20 +65,29 @@ 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
#
all_parts = bom_to_parts(bom_dir, part_type)
if parts:
targets = list(parts) #copy the list so we dont modify the list passed in
else:
targets = bom_to_parts(bom_dir, part_type)
targets = list(all_parts)
for file in os.listdir(target_dir):
if file.endswith('.' + part_type):
if not file in targets:
@@ -119,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)
@@ -144,10 +156,14 @@ 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:
for part in targets:
print("Could not find a module called", part[:-4] + module_suffix, "to make", part)
usage(part_type)
times.print_times()
times.print_times(all_parts)

View File

@@ -52,7 +52,7 @@ def gallery(force):
if os.path.isfile(document):
with open(document, 'rt') as readme:
for line in readme.readlines():
match = re.match(r"^.*!(\[.*\]\(.*\)).*$", line)
match = re.search(r"!(\[.*\]\(.*\))", line)
if match:
image = match.group(0)
if image.startswith('![Main Assembly](assemblies/'):
@@ -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

@@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Generates all the files for a project by running ```bom.py```, ```stls.py```, ```dxfs.py```, ```render.py``` and ```views.py```.
#! Generates all the files for a project by running `bom.py`, `stls.py`, `dxfs.py`, `render.py` and `views.py`.
import sys

View File

@@ -18,28 +18,37 @@
#
#
# Run openscad
#! Run `openscad.exe` and capture `stdout` and `stderr` in `openscad.log` as well as printing to the console.
#
from __future__ import print_function
import subprocess, sys
def run_list(args, silent = False):
cmd = ["openscad"] + args
def run_list(args, silent = False, verbose = False):
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"):
if 'ERROR:' in line or 'WARNING:' in line:
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)
def run_silent(*args):
run_list(list(args), True);
if __name__ == '__main__':
run_list(sys.argv[1:], True, True)

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

@@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Panelises DXF files so they can be routed together by running scad files found in the ```panels``` directory.
#! Panelises DXF files so they can be routed together by running scad files found in the `panels` directory.
from __future__ import print_function
import sys

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,40 +77,55 @@ def plateup(target, part_type, usage = None):
#
# Run OpenSCAD on the source files to make the targets
#
target_def = ['-D$target="%s"' % target] if target else []
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
for src in sources:
src_file = dir + '/' + src
part_file = target_dir + '/' + src[:-4] + part_type
part = src[:-4] + part_type
all_parts.append(part)
part_file = target_dir + '/' + part
uses_file = deps_dir + '/' + src[:-4] + 'txt'
dname = deps_name(deps_dir, src)
changed = check_deps(part_file, dname)
oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
changed = check_deps(oldest, dname)
used = []
if changed:
print(changed)
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, src_file)
t = time.time()
openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
if part_type == 'stl':
c14n_stl.canonicalise(part_file)
times.add_time(part, t)
log_name = 'openscad.log'
#
# Add the files on the BOM to the used list
#
with open(log_name) as file:
for line in file.readlines():
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
if match:
used.append(match.group(1))
with open(uses_file, "wt") as file:
for part in used:
print(part, file = file)
else:
log_name = 'openscad.echo'
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
#
# Add the files on the BOM to the used list
#
with open(log_name) as file:
for line in file.readlines():
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
if match:
used.append(match.group(1))
with open(uses_file, "rt") as file:
for line in file:
used.append(line[:-1])
all_used += used
copied = []
if all_sources:
#
# Copy files that are not included
#
for file in os.listdir(parts_dir):
if file.endswith('.' + part_type) and not file in used:
if file.endswith('.' + part_type) and not file in all_used:
src = parts_dir + '/' + file
dst = target_dir + '/' + file
if mtime(src) > mtime(dst):
print("Copying %s to %s" % (src, dst))
copyfile(src, dst)
shutil.copyfile(src, dst)
copied.append(file)
#
# Remove any cruft
@@ -109,3 +136,12 @@ def plateup(target, part_type, usage = None):
if not file in targets and not file in copied:
print("Removing %s" % file)
os.remove(target_dir + '/' + file)
targets = [file[:-4] + 'txt' for file in all_sources]
for file in os.listdir(deps_dir):
if file.endswith('.' + 'txt'):
if not file in targets:
print("Removing %s" % file)
os.remove(deps_dir + '/' + file)
times.print_times(all_parts)

View File

@@ -18,7 +18,7 @@
# You should have received a copy of the GNU General Public License along with NopSCADlib.
# If not, see <https://www.gnu.org/licenses/>.
#
#! Generates build plates of STL files for efficient printing by running scad files found in the ```platters``` directory.
#! Generates build plates of STL files for efficient printing by running scad files found in the `platters` directory.
from __future__ import print_function
import sys

View File

@@ -1,22 +1,24 @@
# Python scripts
These are located in the ```scripts``` subdirectory, which needs to be added to the program search path.
These are located in the `scripts` subdirectory, which needs to be added to the program search path.
They should work with both Python 2 and Python 3.
| Script | Function |
|:---|:---|
| ```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. |
| ```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. |
| ```make_all.py``` | Generates all the files for a project by running ```bom.py```, ```stls.py```, ```dxfs.py```, ```render.py``` and ```views.py```. |
| ```panels.py``` | Panelises DXF files so they can be routed together by running scad files found in the ```panels``` directory. |
| ```platters.py``` | Generates build plates of STL files for efficient printing by running scad files found in the ```platters``` directory. |
| ```render.py``` | Renders STL and DXF files to PNG for inclusion in the build instructions. |
| ```set_config.py``` | Sets the target configuration for multi-target projects that have variable configurations. |
| ```stls.py``` | Generates STL files for all the printed parts listed on the BOM or a specified list. |
| ```svgs.py``` | Generates SVG files for all the routed parts listed on the BOM or a specified list. |
| ```tests.py``` | Runs all the tests in the tests directory and makes the readme file with a catalog of the results. |
| ```views.py``` | Generates exploded and unexploded assembly views and scrapes build instructions to make readme.md, readme.html and printme.html files for the project. |
| `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. |
| `make_all.py` | Generates all the files for a project by running `bom.py`, `stls.py`, `dxfs.py`, `render.py` and `views.py`. |
| `openscad.py` | Run `openscad.exe` and capture `stdout` and `stderr` in `openscad.log` as well as printing to the console. |
| `panels.py` | Panelises DXF files so they can be routed together by running scad files found in the `panels` directory. |
| `platters.py` | Generates build plates of STL files for efficient printing by running scad files found in the `platters` directory. |
| `render.py` | Renders STL and DXF files to PNG for inclusion in the build instructions. |
| `set_config.py` | Sets the target configuration for multi-target projects that have variable configurations. |
| `stls.py` | Generates STL files for all the printed parts listed on the BOM or a specified list. |
| `svgs.py` | Generates SVG files for all the routed parts listed on the BOM or a specified list. |
| `tests.py` | Runs all the tests in the tests directory and makes the readme file with a catalog of the results. |
| `views.py` | Generates exploded and unexploded assembly views and scrapes build instructions to make readme.md, readme.html and printme.html files for the project. |

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
@@ -50,13 +51,17 @@ def do_cmd(cmd, output = sys.stdout):
return subprocess.call(cmd, stdout = output, stderr = output)
def compare_images(a, b, c):
if not os.path.isfile(b):
print(Fore.MAGENTA + "Failed to generate %s while making %s" % (b, a), Fore.WHITE)
sys.exit(1)
if not os.path.isfile(a):
return -1
log_name = 'magick.log'
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(f.read().strip())
pixels = f.read().strip()
pixels = int(float(pixels if pixels.isnumeric() else -1))
os.remove(log_name)
return pixels
@@ -91,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"
@@ -111,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:
#
@@ -126,14 +132,13 @@ def tests(tests):
#
# List of individual part files
#
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
types = []
for scad in scads:
base_name = scad[:-5]
if not tests or base_name in tests:
done.append(base_name)
print('\n'+base_name)
print(base_name)
cap_name = base_name[0].capitalize() + base_name[1:]
base_name = base_name.lower()
scad_name = scad_dir + '/' + scad
@@ -219,7 +224,7 @@ def tests(tests):
if things:
body += ['### %s\n| %s | Description |\n|:--- |:--- |' % (thing.title(), heading)]
for item in sorted(things):
body += ['| ```%s``` | %s |' % (item, things[item])]
body += ['| `%s` | %s |' % (item, things[item])]
body += ['']
body += ["![%s](%s)\n" %(base_name, png_name)]
@@ -232,14 +237,15 @@ 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)
BOM = bom.parse_bom()
with open(bom_name, 'wt') as outfile:
json.dump(BOM.flat_data(), outfile, indent = 4)
print()
with open(bom_name, "rt") as bom_file:
BOM = json.load(bom_file)
@@ -252,7 +258,7 @@ def tests(tests):
desc = ''
if thing == "vitamins":
vit = item.split(':')
name = '```' + vit[0] + '```' if vit[0] else ''
name = '`' + vit[0] + '`' if vit[0] else ''
while '[[' in name and ']]' in name:
i = name.find('[[')
j = name.find(']]') + 2
@@ -300,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):
@@ -52,23 +52,34 @@ def add_time(name, start):
del times[name.lower()]
times[name] = round(time.time() - start, 3)
def print_times():
write_times()
def print_times(files = None):
sorted_times = sorted(times.items(), key=lambda kv: kv[1])
total = 0
old_total = 0
for entry in sorted_times:
colour = Fore.WHITE
key = entry[0]
new = entry[1]
delta = 0
if key in last_times:
old = last_times[key]
delta = new - old
if delta > 0.3:
colour = Fore.RED
if delta < -0.3:
colour = Fore.GREEN
print(colour + "%5.1f %5.1f %s" % (new, delta, key))
total += new
if files and not key in files:
del times[key]
else:
new = entry[1]
delta = 0
colour = Fore.WHITE
if key in last_times:
old = last_times[key]
old_total += old
delta = new - old
if delta > 0.3:
colour = Fore.RED
if delta < -0.3:
colour = Fore.GREEN
print(colour + "%6.1f %5.1f %s" % (new, delta, key))
total += new
write_times()
if sorted_times:
print(Fore.WHITE + "%5.1f" % total)
colour = Fore.WHITE
delta = total - old_total
if delta > 1:
colour = Fore.RED
if delta < -1:
colour = Fore.GREEN
print(colour + "%6.1f %5.1f TOTAL%s" % (total, delta, Fore.WHITE))

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

@@ -35,7 +35,10 @@ import json
import blurb
import bom
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'
@@ -73,19 +76,17 @@ def bom_to_assemblies(bom_dir, bounds_map):
# Remove the main assembly if it is a shell
#
if flat_bom:
ass = flat_bom[-1]
ass = flat_bom[-1]
if len(ass["assemblies"]) < 2 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]:
flat_bom = flat_bom[:-1]
return [assembly["name"] for assembly in flat_bom]
def eop(print_mode, doc_file, last = False, first = False):
if print_mode:
print('\n<div style="page-break-after: always;"></div>', file = doc_file)
else:
if not first:
print('[Top](#TOP)', file = doc_file)
if not last:
print("\n---", file = doc_file)
def eop(doc_file, last = False, first = False):
print('<span></span>', file = doc_file) # An invisable marker for page breaks because markdown takes much longer if the document contains a div
if not first:
print('[Top](#TOP)', file = doc_file)
if not last:
print("\n---", file = doc_file)
def pad(s, before, after = 0):
return '&nbsp;' * before + str(s) + '&nbsp;' * after
@@ -102,14 +103,36 @@ def usage():
print("\nusage:\n\t views [target_config] [<name1>_assembly] ... [<nameN>_assembly] - Create assembly images and readme.")
sys.exit(1)
types = ["vitamins", "printed", "routed"]
def merged(bom):
bom = copy.deepcopy(bom)
for aname in bom["assemblies"]:
count = bom["assemblies"][aname]
for ass in flat_bom:
if ass['name'] == aname and ass['ngb']:
merged_assembly = merged(ass)
total = ass['count']
for t in types:
for thing in merged_assembly[t]:
items = merged_assembly[t][thing]['count'] * count // total
if thing in bom[t]:
bom[t][thing]['count'] += items
else:
bom[t][thing] = merged_assembly[t][thing]
bom[t][thing]['count'] = items
break
return bom
def views(target, do_assemblies = None):
done_assemblies = []
#
# 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)
@@ -138,6 +161,7 @@ def views(target, do_assemblies = None):
# Find all the scad files
#
main_blurb = None
pngs = []
for dir in source_dirs(bom_dir):
if os.path.isdir(dir):
for filename in os.listdir(dir):
@@ -161,33 +185,43 @@ 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
if not do_assemblies or real_name in do_assemblies:
#
# Run openscad on the created file
#
dname = deps_name(deps_dir, filename)
for explode in [0, 1]:
#
# Run openscad on the created file
# Generate png name
#
dname = deps_name(deps_dir, filename)
for explode in [0, 1]:
png_name = target_dir + '/' + real_name + '.png'
if not explode:
png_name = png_name.replace('_assembly', '_assembled')
png_name = target_dir + '/' + real_name + '.png'
if not explode:
png_name = png_name.replace('_assembly', '_assembled')
pngs.append(png_name)
if not do_assemblies or real_name in do_assemblies:
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()
openscad.run_list(options.list() + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name]);
target_def = ['-D$target="%s"' % target] if target else []
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
view_def = ['--viewall', '--autocenter'] if not (zoomed & (1 << explode)) else ['--camera=0,0,0,55,0,25,140']
openscad.run_list(["-o", tmp_name, png_maker_name] + options.list() + target_def + cwd_def + view_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "-d", dname]);
times.add_time(png_name, t)
do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name])
update_image(tmp_name, png_name)
@@ -201,184 +235,221 @@ def views(target, do_assemblies = None):
if module == 'main_assembly':
main_blurb = blurb.scrape_module_blurb(lines[:line_no])
line_no += 1
times.print_times()
#
# Build the document
#
for print_mode in [True, False]:
doc_name = top_dir + "readme.md"
with open(doc_name, "wt") as doc_file:
#
# Title, description and picture
#
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
print('<a name="TOP"></a>\n# %s' % project, file = doc_file)
main_file = bom.find_scad_file('main_assembly')
if not main_file:
raise Exception("can't find source for main_assembly")
text = blurb.scrape_blurb(source_dir + '/' + main_file)
if len(text):
print(text, file = doc_file, end = '')
else:
if print_mode:
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
doc_name = top_dir + "readme.md"
with open(doc_name, "wt") as doc_file:
#
# Title, description and picture
#
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
print('<a name="TOP"></a>', file = doc_file)
print('# %s' % project, file = doc_file)
main_file = bom.find_scad_file('main_assembly')
if not main_file:
raise Exception("can't find source for main_assembly")
text = blurb.scrape_blurb(source_dir + '/' + main_file)
blurbs = blurb.split_blurb(text)
if len(text):
print(blurbs[0], file = doc_file)
else:
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
#
# Only add the image if the first blurb section doesn't contain one.
#
if not re.search(r'\!\[.*\]\(.*\)', blurbs[0], re.MULTILINE):
print('![Main Assembly](assemblies/%s.png)\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file)
eop(print_mode, doc_file, first = True)
#
# Build TOC
#
print('## Table of Contents', file = doc_file)
print('1. [Parts list](#Parts_list)', file = doc_file)
for ass in flat_bom:
name = ass["name"]
cap_name = titalise(name)
print('1. [%s](#%s)' % (cap_name, name), file = doc_file)
print(file = doc_file)
eop(print_mode, doc_file)
#
# Global BOM
#
print('<a name="Parts_list"></a>\n## Parts list', file = doc_file)
types = ["vitamins", "printed", "routed"]
headings = {"vitamins" : "vitamins", "printed" : "3D printed parts", "routed" : "CNC routed parts"}
things = {}
eop(doc_file, first = True)
#
# Build TOC
#
print('## Table of Contents', file = doc_file)
print('1. [Parts list](#Parts_list)', file = doc_file)
for ass in flat_bom:
name = ass["name"]
cap_name = titalise(name)
print('1. [%s](#%s)' % (cap_name, name), file = doc_file)
print(file = doc_file)
if len(blurbs) > 1:
print(blurbs[1], file = doc_file)
eop(doc_file)
#
# Global BOM
#
global_bom = [merged(ass) for ass in flat_bom if not ass['ngb']]
print('<a name="Parts_list"></a>\n## Parts list', file = doc_file)
headings = {"vitamins" : "vitamins", "printed" : "3D printed parts", "routed" : "CNC routed parts"}
things = {}
for t in types:
things[t] = {}
for ass in flat_bom:
for t in types:
things[t] = {}
for ass in flat_bom:
for t in types:
for thing in ass[t]:
if thing in things[t]:
things[t][thing] += ass[t][thing]["count"]
else:
things[t][thing] = ass[t][thing]["count"]
for ass in flat_bom:
name = titalise(ass["name"][:-9]).replace(' ','&nbsp;')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> | |', file = doc_file)
for thing in ass[t]:
if thing in things[t]:
things[t][thing] += ass[t][thing]["count"]
else:
things[t][thing] = ass[t][thing]["count"]
for ass in global_bom:
name = titalise(ass["name"][:-9]).replace(' ','&nbsp;')
if ass["count"] > 1:
name = "%d x %s" % (ass["count"], name)
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> | |', file = doc_file)
print(('|---:' * len(global_bom) + '|---:|:---|'), file = doc_file)
print(('|---:' * len(flat_bom) + '|---:|:---|'), file = doc_file)
for t in types:
if things[t]:
totals = {}
heading = headings[t][0:1].upper() + headings[t][1:]
print(('| ' * len(flat_bom) + '| | **%s** |') % heading, file = doc_file)
for thing in sorted(things[t], key = lambda s: s.split(":")[-1]):
for ass in flat_bom:
count = ass[t][thing]["count"] if thing in ass[t] else 0
print('| %s ' % pad(count if count else '.', 2, 1), file = doc_file, end = '')
name = ass["name"]
if name in totals:
totals[name] += count
else:
totals[name] = count
print('| %s | %s |' % (pad(things[t][thing], 2, 1), pad(thing.split(":")[-1], 2)), file = doc_file)
grand_total = 0
for ass in flat_bom:
for t in types:
if things[t]:
totals = {}
grand_total2 = 0
heading = headings[t][0].upper() + headings[t][1:]
print(('| ' * len(global_bom) + '| | **%s** |') % heading, file = doc_file)
for thing in sorted(things[t], key = lambda s: s.split(":")[-1]):
for ass in global_bom:
count = ass[t][thing]["count"] if thing in ass[t] else 0
print('| %s ' % pad(count if count else '.', 2, 1), file = doc_file, end = '')
name = ass["name"]
total = totals[name] if name in totals else 0
print('| %s ' % pad(total if total else '.', 2, 1), file = doc_file, end = '')
grand_total += total
print("| %s | %s |" % (pad(grand_total, 2, 1), pad('Total %s count' % headings[t], 2)), file = doc_file)
if name in totals:
totals[name] += count
else:
totals[name] = count
grand_total2 += count
print('| %s | %s |' % (pad(things[t][thing], 2, 1), pad(thing.split(":")[-1], 2)), file = doc_file)
print(file = doc_file)
eop(print_mode, doc_file)
#
# Assembly instructions
#
for ass in flat_bom:
name = ass["name"]
cap_name = titalise(name)
if ass["count"] > 1:
print('<a name="%s"></a>\n## %d x %s' % (name, ass["count"], cap_name), file = doc_file)
else:
print('<a name="%s"></a>\n## %s' % (name, cap_name), file = doc_file)
vitamins = ass["vitamins"]
if vitamins:
print("### Vitamins", file = doc_file)
print("|Qty|Description|", file = doc_file)
print("|---:|:----------|", file = doc_file)
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]), file = doc_file)
print("\n", file = doc_file)
printed = ass["printed"]
if printed:
print('### 3D Printed parts', file = doc_file)
keys = sorted(list(printed.keys()))
for i, p in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
if (i % 3) == 2 or i == len(printed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
part = keys[i - n + j + 1]
print('| ![%s](stls/%s) %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
routed = ass["routed"]
if routed:
print("### CNC Routed parts", file = doc_file)
keys = sorted(list(routed.keys()))
for i, r in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
if (i % 3) == 2 or i == len(routed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
part = keys[i - n + j + 1]
print('| ![%s](dxfs/%s) %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
sub_assemblies = ass["assemblies"]
if sub_assemblies:
print("### Sub-assemblies", file = doc_file)
keys = sorted(list(sub_assemblies.keys()))
for i, a in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
if (i % 3) == 2 or i == len(keys) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
a = keys[i - n + j + 1].replace('_assembly', '_assembled')
print('| ![%s](assemblies/%s) %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
small = not ass["big"]
suffix = '_tn.png' if small else '.png'
print('### Assembly instructions', file = doc_file)
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
if "blurb" in ass and ass["blurb"]:
print(ass["blurb"], file = doc_file)
else:
if print_mode:
print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE)
name = name.replace('_assembly', '_assembled')
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
eop(print_mode, doc_file, last = ass == flat_bom[-1] and not main_blurb)
#
# If main module is suppressed print any blurb here
#
if main_blurb:
print(main_blurb, file = doc_file)
eop(print_mode, doc_file, last = True)
grand_total = 0
for ass in global_bom:
name = ass["name"]
total = totals[name] if name in totals else 0
print('| %s ' % pad(total if total else '.', 2, 1), file = doc_file, end = '')
grand_total += total
print("| %s | %s |" % (pad(grand_total, 2, 1), pad('Total %s count' % headings[t], 2)), file = doc_file)
assert grand_total == grand_total2
print(file = doc_file)
if len(blurbs) > 2:
print(blurbs[2], file = doc_file)
eop(doc_file)
#
# Convert to HTML
# Assembly instructions
#
html_name = "printme.html" if print_mode else "readme.html"
with open(top_dir + html_name, "wt") as html_file:
do_cmd(("python -m markdown -x tables -x sane_lists " + doc_name).split(), html_file)
for ass in flat_bom:
name = ass["name"]
cap_name = titalise(name)
print('<a name="%s"></a>' % name, file = doc_file)
if ass["count"] > 1:
print('## %d x %s' % (ass["count"], cap_name), file = doc_file)
else:
print('## %s' % cap_name, file = doc_file)
vitamins = ass["vitamins"]
if vitamins:
print("### Vitamins", file = doc_file)
print("|Qty|Description|", file = doc_file)
print("|---:|:----------|", file = doc_file)
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]), file = doc_file)
print("\n", file = doc_file)
printed = ass["printed"]
if printed:
print('### 3D Printed parts', file = doc_file)
keys = sorted(list(printed.keys()))
for i, p in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
if (i % 3) == 2 or i == len(printed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
part = keys[i - n + j + 1]
print('| ![%s](stls/%s) %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
routed = ass["routed"]
if routed:
print("### CNC Routed parts", file = doc_file)
keys = sorted(list(routed.keys()))
for i, r in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
if (i % 3) == 2 or i == len(routed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
part = keys[i - n + j + 1]
print('| ![%s](dxfs/%s) %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
sub_assemblies = ass["assemblies"]
if sub_assemblies:
print("### Sub-assemblies", file = doc_file)
keys = sorted(list(sub_assemblies.keys()))
for i, a in enumerate(keys):
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
if (i % 3) == 2 or i == len(keys) - 1:
n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file)
for j in range(n):
a = keys[i - n + j + 1].replace('_assembly', '_assembled')
print('| ![%s](assemblies/%s) %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
print('\n', file = doc_file)
small = not ass["big"]
suffix = '_tn.png' if small else '.png'
print('### Assembly instructions', file = doc_file)
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
if "blurb" in ass and ass["blurb"]:
print(ass["blurb"], file = doc_file)
else:
print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE)
name = name.replace('_assembly', '_assembled')
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
eop(doc_file, last = ass == flat_bom[-1] and not main_blurb)
#
# If main module is suppressed print any blurb here
#
if main_blurb:
print(main_blurb, file = doc_file)
eop(doc_file, last = True)
#
# Convert to HTML
#
html_name = top_dir + 'readme.html'
t = time.time()
with open(html_name, "wt") as html_file:
do_cmd(("python -m markdown -x tables -x sane_lists " + doc_name).split(), html_file)
times.add_time(html_name, t)
times.print_times(pngs + [html_name])
#
# Make the printme.html by replacing empty spans that invisbly mark the page breaks by page break divs.
#
with open(html_name, 'rt') as src:
lines = src.readlines()
i = 0
with open(top_dir + 'printme.html', 'wt') as dst:
while i < len(lines):
line = lines[i]
if line.startswith('<p><span></span>'): # Empty span used to mark page breaks
i += 1
if lines[i].startswith('<a href="#TOP">Top</a>'): # The first page break won't have one
i += 1
if i < len(lines) and lines[i] == '<hr />\n': # The last page break doesn't have one
dst.write('<div style="page-break-after: always;"></div>\n')
i += 1
else:
dst.write(line)
i += 1
#
# Remove tmp dir
#
rmtmpdir(tmp_dir)
#
# Spell check
#
do_cmd('codespell -L od readme.md'.split())
do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())
#
# List the ones we didn't find
#

View File

@@ -30,7 +30,6 @@ sheet = PMMA3;
height = 10;
insert = screw_insert(screw);
washer = screw_washer(screw);
module widget(thickness) {
vitamin(str("widget(", thickness, "): Rivit like thing for ", thickness, "mm sheets"));
@@ -44,31 +43,29 @@ module widget(thickness) {
}
}
module widgit_stl() {
stl("widget");
module widget_stl() {
stl("widget")
union() {
rounded_rectangle([30, 30, 3], 2, true);
union() {
rounded_rectangle([30, 30, 3], 2);
render() insert_boss(insert, height, 2.2);
}
render() insert_boss(insert, height, 2.2);
}
}
module widgit_dxf() {
dxf("widget");
module widget_dxf() {
dxf("widget")
difference() {
sheet_2D(sheet, 20, 20, 1);
difference() {
sheet_2D(sheet, 20, 20, 1);
drill(screw_clearance_radius(screw), 0);
}
drill(screw_clearance_radius(screw), 0);
}
}
//! * Push the insert into the base with a soldering iron heated to 200&deg;C
module widgit_base_assembly()
assembly("widgit_base") {
module widget_base_assembly()
assembly("widget_base") {
stl_colour(pp1_colour)
widgit_stl();
widget_stl();
translate_z(height)
insert(insert);
@@ -81,18 +78,18 @@ assembly("widget_top") {
widget(sheet_thickness(sheet));
render_2D_sheet(sheet) // Must be last because it is transparent
widgit_dxf();
widget_dxf();
}
//! * Screw the two assemblies together
module widgit_assembly()
assembly("wigdit") {
module widget_assembly()
assembly("widget") {
widgit_base_assembly(); // Note this is not exloded because it is sub-assembly
widget_base_assembly(); // Note this is not exloded because it is sub-assembly
translate_z(height) {
translate_z(sheet_thickness(sheet))
screw_and_washer(screw, screw_longer_than(sheet_thickness(sheet) + 2 * washer_thickness(washer) + 3), true);
screw_and_washer(screw, screw_length(screw, sheet_thickness(sheet) + 3, 2, longer = true), true);
explode(5)
translate_z(sheet_thickness(sheet) / 2 + eps)
@@ -101,7 +98,7 @@ assembly("wigdit") {
}
module boms() {
widgit_assembly();
widget_assembly();
}
boms();

View File

@@ -21,16 +21,22 @@ include <../vitamins/pcbs.scad>
use <../utils/layout.scad>
function spacing(p) = let(w = pcb_width(p)) w < 22 ? w + 3 : w + 10;
module pcbs() {
layout([for(p = pcbs) pcb_width(p)], 10)
layout([for(p = pcbs) spacing(p)], 0)
translate([0, pcb_length(pcbs[$i]) / 2])
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);
for(p = pcbs_not_shown)
hidden()
pcb(p);
}
if($preview)
pcbs();

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

@@ -22,18 +22,15 @@ use <../utils/layout.scad>
include <../vitamins/blowers.scad>
module blowers()
layout([for(b = blowers) blower_width(b)], 10, true) let(b = blowers[$i]){
layout([for(b = blowers) blower_width(b)], 5, true) let(b = blowers[$i]){
screw = blower_screw(b);
washer = screw_washer(screw);
h = blower_lug(b);
blower(b);
blower_hole_positions(b)
translate_z(h)
screw_and_washer(screw, screw_longer_than(h + washer_thickness(washer) + 5));
screw_and_washer(screw, screw_length(screw, h + 5, 1, longer = true));
}
if($preview)

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

@@ -56,7 +56,7 @@ module horiholes_stl(t = thickness) {
}
if(t == thickness)
translate([length / 2, 0])
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5);
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5, true);
}
module horiholes() {

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: 49 KiB

After

Width:  |  Height:  |  Size: 51 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: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 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

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: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

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