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

Compare commits

...

43 Commits

Author SHA1 Message Date
Chris Palmer
f73a7b46a2 Merge branch 'martinbudden-carbon_fiber_tube' 2020-11-13 10:51:24 +00:00
Chris Palmer
fb9eca85c6 Updated images and readme. 2020-11-13 10:50:29 +00:00
Chris Palmer
ce6aec428d Merge branch 'carbon_fiber_tube' of https://github.com/martinbudden/NopSCADlib into martinbudden-carbon_fiber_tube 2020-11-13 10:03:15 +00:00
Chris Palmer
4e9d169c31 Updated cover pic 2020-11-13 09:57:17 +00:00
Martin Budden
1810160103 Added carbon fiber tubing with woven pattern. 2020-11-13 09:35:56 +00:00
Chris Palmer
0c9ae8d60c PCBs now drawn before components so that transparent LEDs draw correctly. 2020-11-13 09:24:15 +00:00
Chris Palmer
9a0bad4e61 Made stepper motor encap paramatric.
Made connector position based on encap height and added PCB.
2020-11-12 23:36:35 +00:00
Chris Palmer
90047815b0 Added JST PH connectors.
Made jst_xh_header() more parametric and corrected pin positions.
2020-11-12 23:34:59 +00:00
Chris Palmer
eac0086199 tests.py now allows parts of projects to be tested without finding an implementation. 2020-11-10 12:01:57 +00:00
Chris Palmer
51c649cc53 Merge branch 'martinbudden-tests_script' 2020-11-09 16:19:45 +00:00
Chris Palmer
5fa33d7c4d Tests.py now works in projects and makes tests.md and tests.html.
NopSCADlib blurb now scraped from libtest.scad.
libtest.scad no longer required and lack of it is used to detect a project.
2020-11-09 16:17:02 +00:00
Chris Palmer
78ce51d045 Merge branch 'tests_script' of https://github.com/martinbudden/NopSCADlib into martinbudden-tests_script 2020-11-08 21:36:56 +00:00
Chris Palmer
23cbadf6df Merge branch 'martinbudden-stepper_motor_jst_connector' 2020-11-08 21:29:03 +00:00
Chris Palmer
c9c2ffafba Fixed connector position, fixed missing wires, updated images.
Reverted the jst header pin position change.
2020-11-08 21:28:08 +00:00
Martin Budden
2e0e833d40 Made jst_connector a parameter to NEMA. 2020-11-08 15:14:19 +00:00
Martin Budden
6c51f8726c Updated tests.py to better support generic testing. 2020-11-08 14:56:52 +00:00
Martin Budden
0b035dbd15 Added optional jst connector to stepper motors. 2020-11-08 12:20:15 +00:00
Chris Palmer
34b58e3b64 Added convexity parameter to sweep. 2020-11-04 22:27:31 +00:00
Chris Palmer
df43fe7dc6 Added list and string slicing. 2020-11-04 21:44:07 +00:00
Chris Palmer
b5fe03fcb2 Test image pixel differences due to switch to winter computer 2020-11-04 20:48:22 +00:00
Chris Palmer
1658f6f0b4 Sweep can now cope with the start having colinear points. 2020-11-04 19:56:51 +00:00
Chris Palmer
7b126f9792 More spelling 2020-11-04 19:50:35 +00:00
Chris Palmer
479207fd4f Spelling 2020-11-04 10:52:57 +00:00
Chris Palmer
3ee55981f9 Comment spelling. 2020-10-05 12:02:54 +01:00
Chris Palmer
8c2b4a20fe Added tesrdrop_minus() and horicylinder(). 2020-10-05 10:59:50 +01:00
Chris Palmer
1529759406 Fixes for lazy union. 2020-10-05 10:42:13 +01:00
Chris Palmer
c4a986aa21 Test for circle_intersect() 2020-10-05 10:41:27 +01:00
Chris Palmer
ebee729d08 Added MP1584EN PCB. Melzi no longer displayed. 2020-10-05 10:40:43 +01:00
Chris Palmer
90e7f1a315 Added circle_intersect() calculation to maths.scad. 2020-10-04 22:01:08 +01:00
Chris Palmer
e39af154bb Fixed use of intersection with conditional argument to suit new OpenSCAD behaviour. 2020-10-03 15:53:41 +01:00
Chris Palmer
933fea687c Removed debug code 2020-09-20 09:07:01 +01:00
Chris Palmer
a7803b1efb Improved numerical accuarcy of catenary calculations. 2020-09-19 23:52:57 +01:00
Chris Palmer
1255e71271 Added catenary curves. 2020-09-19 12:11:54 +01:00
Chris Palmer
b11c5914b3 Added hyperbolic maths functions 2020-09-15 20:58:39 +01:00
Chris Palmer
ac60057801 Fixes for additional warnings in OpenSCAD 2020.09.12.ci5914 2020-09-14 22:54:55 +01:00
Chris Palmer
332933a4fd Made ribbon_clamps parametric on screw size. 2020-09-11 19:53:14 +01:00
Chris Palmer
6b0132c32e Added chamfer option to poly_cylinder(). 2020-09-11 12:36:37 +01:00
Chris Palmer
afac5f9737 Added PCB components to OpenGrab and functions to access PCB. 2020-09-11 12:35:22 +01:00
Chris Palmer
8d8df3cb8a Added 4.5mm button to PCBs. 2020-09-11 12:30:00 +01:00
Chris Palmer
81eb183db9 Fixed PCB cutout for right angle pin headers. 2020-09-11 12:24:07 +01:00
Chris Palmer
c99ed98a64 Can now have right angle pin headers on PCBs.
Fixed bugs right angle pin headers with rows not equal to two.
Added more tests for pin headers.
2020-09-11 00:20:28 +01:00
Chris Palmer
7f65e5d539 Added M2 dome head screws. 2020-09-10 18:38:24 +01:00
Chris Palmer
ffb7f87cc5 Fixed typo in insert name. 2020-09-10 18:27:56 +01:00
70 changed files with 851 additions and 335 deletions

View File

@@ -18,7 +18,7 @@
//
//
// Include this file to use the miniumum library plus screws, nuts and washers
// Include this file to use the minimum library plus screws, nuts and washers
//
include <utils/core/core.scad>
//

View File

@@ -33,7 +33,7 @@ $exploded = is_undef($explode) ? 0 : $explode; // 1 f
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth when printing
extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing
nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // miniumum tool radius when milling 2D objects
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // minimum tool radius when milling 2D objects
pp1_colour = is_undef($pp1_colour) ? [0, 146/255, 0] : $pp1_colour; // printed part colour 1, RepRap logo colour
pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // printed part colour 2
pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 KiB

After

Width:  |  Height:  |  Size: 819 KiB

View File

@@ -17,6 +17,23 @@
// If not, see <https://www.gnu.org/licenses/>.
//
//!# NopSCADlib
//! An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
//!
//! It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and some utilities.
//! There are also Python scripts to generate Bills of Materials (BOMs),
//! STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
//! instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md).
//!
//! A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
//!
//! For more examples of what it can make see the [gallery](gallery/readme.md).
//!
//! The license is GNU General Public License v3.0, see [COPYING](COPYING).
//!
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
//!
//! <img src="libtest.png" width="100%"/>
//
// This file shows all the parts in the library.
//
@@ -117,17 +134,17 @@ cable_grommets_y = 0;
translate([x5, cable_grommets_y])
cable_grommets();
translate([x5, cable_grommets_y + 50])
feet();
translate([x5 + 80, cable_grommets_y])
ribbon_clamps();
translate([x5, cable_grommets_y + 75])
translate([x5, cable_grommets_y + 60])
fixing_blocks();
translate([x5, cable_grommets_y + 100])
translate([x5, cable_grommets_y + 90])
corner_blocks();
translate([x5, cable_grommets_y + 150])
ribbon_clamps();
feet();
translate([x5 + 70, cable_grommets_y + 150])
screw_knobs();

View File

@@ -24,69 +24,72 @@ include <../core.scad>
use <../vitamins/insert.scad>
use <../vitamins/cable_strip.scad>
wall = 2;
wall = 1.6;
min_wall = 2 * extrusion_width;
screw = M3_cap_screw;
insert = screw_insert(screw);
screw_depth = insert_length(insert) + 1;
function ribbon_clamp_hole_pitch(ways) = ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(insert)); //! Hole pitch
function ribbon_clamp_width() = 2 * (insert_hole_radius(insert) + wall); //! Width
function ribbon_clamp_length(ways) = ribbon_clamp_hole_pitch(ways) + ribbon_clamp_width(); //! Length given ways
function ribbon_clamp_height() = screw_depth + 1; //! Height
function ribbon_clamp_screw_depth(screw = screw) = insert_length(screw_insert(screw)) + 1;
function ribbon_clamp_hole_pitch(ways, screw = screw) =
ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(screw_insert(screw))); //! Hole pitch
module ribbon_clamp_hole_positions(ways, side = undef) //! Place children at hole positions
function ribbon_clamp_width(screw = screw) = 2 * (insert_hole_radius(screw_insert(screw)) + wall); //! Width
function ribbon_clamp_length(ways, screw = screw) = ribbon_clamp_hole_pitch(ways, screw) + ribbon_clamp_width(screw); //! Length given ways
function ribbon_clamp_height(screw = screw) = ribbon_clamp_screw_depth(screw) + 1; //! Height
module ribbon_clamp_hole_positions(ways, screw = screw, side = undef) //! Place children at hole positions
for(x = is_undef(side) ? [-1, 1] : side)
translate([x * ribbon_clamp_hole_pitch(ways) / 2, 0])
translate([x * ribbon_clamp_hole_pitch(ways, screw) / 2, 0])
children();
module ribbon_clamp_holes(ways, h = 20) //! Drill screw holes
ribbon_clamp_hole_positions(ways)
module ribbon_clamp_holes(ways, h = 20, screw = screw) //! Drill screw holes
ribbon_clamp_hole_positions(ways, screw)
drill(screw_clearance_radius(screw), h);
module ribbon_clamp(ways) { //! Generate STL for given number of ways
stl(str("ribbon_clamp_", ways));
module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of ways
screw_d = screw_radius(screw) * 2;
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""));
pitch = ribbon_clamp_hole_pitch(ways);
d = ribbon_clamp_width();
h = ribbon_clamp_height();
t = h - ribbon_clamp_slot_depth() - wall;
pitch = ribbon_clamp_hole_pitch(ways, screw);
d = ribbon_clamp_width(screw);
h = ribbon_clamp_height(screw);
t = round_to_layer(ribbon_clamp_slot_depth() + wall);
insert = screw_insert(screw);
difference() {
union() {
hull() {
translate_z(h - t / 2)
cube([ribbon_clamp_hole_pitch(ways), d, t], center = true);
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
translate_z(1)
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
}
ribbon_clamp_hole_positions(ways, -1)
ribbon_clamp_hole_positions(ways, screw, -1)
cylinder(d = d, h = h);
ribbon_clamp_hole_positions(ways, 1)
ribbon_clamp_hole_positions(ways, screw, 1)
cylinder(d = d, h = h);
}
translate_z(h)
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
ribbon_clamp_hole_positions(ways)
ribbon_clamp_hole_positions(ways, screw)
translate_z(h)
rotate(22.5)
insert_hole(insert, screw_depth - insert_length(insert));
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
}
}
module ribbon_clamp_assembly(ways) pose([55, 180, 25]) //! Printed part with inserts in place
assembly(str("ribbon_clamp_", ways)) {
h = ribbon_clamp_height();
module ribbon_clamp_assembly(ways, screw) pose([55, 180, 25]) //! Printed part with inserts in place
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : "")) {
h = ribbon_clamp_height(screw);
insert = screw_insert(screw);
stl_colour(pp1_colour) render()
translate_z(h) vflip() ribbon_clamp(ways);
translate_z(h) vflip() ribbon_clamp(ways, screw);
ribbon_clamp_hole_positions(ways)
ribbon_clamp_hole_positions(ways, screw)
vflip()
insert(insert);
}
@@ -99,20 +102,24 @@ module ribbon_clamp_fastened_assembly(ways, thickness, screw = screw) { //! Clam
vitamin(str(": Tape self amalgamating silicone ",tape_l," x 25mm"));
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + screw_depth);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + ribbon_clamp_screw_depth(screw));
ribbon_clamp_assembly(ways);
ribbon_clamp_assembly(ways, screw);
color("red") translate_z(tape_thickness / 2)
cube([tape_l, tape_width, tape_thickness], center = true);
ribbon_clamp_hole_positions(ways)
ribbon_clamp_hole_positions(ways, screw)
vflip()
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}
module ribbon_clamp_20_stl() ribbon_clamp(20);
module ribbon_clamp_8_2_stl() ribbon_clamp(8, M2_dome_screw);
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200&deg;C.
module ribbon_clamp_20_assembly() ribbon_clamp_assembly(20);
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200&deg;C.
module ribbon_clamp_8_2_assembly() ribbon_clamp_assembly(8, M2_dome_screw);

181
readme.md
View File

@@ -1,10 +1,12 @@
# NopSCADlib
An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and
some utilities. There are also Python scripts to generate Bills of Materials (BOMs),
STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md). A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and some utilities.
There are also Python scripts to generate Bills of Materials (BOMs),
STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md).
A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
For more examples of what it can make see the [gallery](gallery/readme.md).
@@ -20,23 +22,23 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
<th align="left"> Vitamins A-I </th><th align="left"> Vitamins J-Q </th><th align="left"> Vitamins R-Z </th><th align="left"> Printed </th><th align="left"> Utilities </th><th align="left"> Core Utilities </th></tr>
<tr><td> <a href = "#Axials">Axials</a> </td><td> <a href = "#Jack">Jack</a> </td><td> <a href = "#Rails">Rails</a> </td><td> <a href = "#Box">Box</a> </td><td> <a href = "#Annotation">Annotation</a> </td><td> <a href = "#BOM">BOM</a> </td></tr>
<tr><td> <a href = "#Ball_bearings">Ball_bearings</a> </td><td> <a href = "#KP_pillow_blocks">KP_pillow_blocks</a> </td><td> <a href = "#Ring_terminals">Ring_terminals</a> </td><td> <a href = "#Butt_box">Butt_box</a> </td><td> <a href = "#Bezier">Bezier</a> </td><td> <a href = "#Clip">Clip</a> </td></tr>
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Global">Global</a> </td></tr>
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Catenary">Catenary</a> </td><td> <a href = "#Global">Global</a> </td></tr>
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td></td><td></td><td></td></tr>
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Washers">Washers</a> </td><td></td><td></td><td></td></tr>
@@ -403,7 +405,7 @@ PCB mounted buttons. Can optionally have a coloured cap
## Cable_strips
A strip of polypropylene used with ribbon cable to make a cable flexible in one direction only.
Modelled with a Bezier spline, which is not quite the same as a miniumum energy curve but very close, epecially
Modelled with a Bezier spline, which is not quite the same as a minimum energy curve but very close, epecially
near the extreme positions, where the model needs to be accurate.
When the sides are constrained then a circular model is more accurate.
@@ -1268,7 +1270,7 @@ Heatfit threaded inserts. Can be pushed into thermoplastics using a soldering ir
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | ```insert(F1BM)``` | Heatfit insert M2 |
| 1 | ```insert(F1BM2)``` | Heatfit insert M2 |
| 1 | ```insert(F1BM2p5)``` | Heatfit insert M2.5 |
| 1 | ```insert(F1BM3)``` | Heatfit insert M3 |
| 1 | ```insert(F1BM4)``` | Heatfit insert M4 |
@@ -2010,6 +2012,8 @@ A permanent magnet that can be magnatized and de-magnatized electronically.
| Function | Description |
|:--- |:--- |
| ```opengrab_depth()``` | Module height |
| ```opengrab_pcb()``` | The PCB |
| ```opengrab_pcb_z()``` | PCB offset from the front |
| ```opengrab_target_thickness()``` | Target sheet thickness |
| ```opengrab_width()``` | Module width |
@@ -2212,6 +2216,7 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
| 1 | ```smd_resistor(RES0603, 1K)``` | SMD resistor 0603 1K 0.1W |
| 1 | ```smd_resistor(RES0805, 1K)``` | SMD resistor 0805 1K 0.125W |
| 1 | ```smd_resistor(RES1206, 1K)``` | SMD resistor 1206 1K 0.25W |
| 1 | ```square_button(button_4p5mm)``` | Square button 4.5mm |
| 1 | ```square_button(button_6mm)``` | Square button 6mm |
| 1 | ```pcb(TMC2130)``` | TMC2130 |
| 1 | ```green_terminal(gt_5p08, 2)``` | Terminal block 2 way 0.2" |
@@ -2329,14 +2334,14 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
| 1 | ```pcb(EnviroPlus)``` | Enviro+ |
| 1 | ```pcb(ExtruderPCB)``` | Extruder connection PCB |
| 1 | ```pcb(Keyes5p1)``` | Keyes5.1 Arduino Uno expansion board |
| 1 | ```pcb(MP1584EN)``` | MP1584EN 3A buck converter |
| 1 | ```pcb(MT3608)``` | MT3608 boost converter module |
| 1 | ```pcb(Melzi)``` | Melzi electronics |
| 5 | | Micro SD card |
| 4 | | Micro SD card |
| 1 | ```molex_254(2)``` | Molex KK header 2 way |
| 1 | ```molex_254(3)``` | Molex KK header 3 way |
| 16 | ```nut(M2_nut, nyloc = true)``` | Nut M2 x 1.6mm nyloc |
| 34 | ```nut(M2p5_nut, nyloc = true)``` | Nut M2.5 x 2.2mm nyloc |
| 16 | ```nut(M3_nut, nyloc = true)``` | Nut M3 x 2.4mm nyloc |
| 12 | ```nut(M3_nut, nyloc = true)``` | Nut M3 x 2.4mm nyloc |
| 12 | ```nut(M4_nut, nyloc = true)``` | Nut M4 x 3.2mm nyloc |
| 1 | ```pcb(PI_IO)``` | PI_IO V2 |
| 1 | ```pcb(PSU12V1A)``` | PSU 12V 1A |
@@ -2352,24 +2357,21 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
| 1 | ```pcb(RPI0)``` | Raspberry Pi Zero |
| 12 | ```screw(M2_cap_screw, 16)``` | Screw M2 cap x 16mm |
| 4 | ```screw(M2_cap_screw, 20)``` | Screw M2 cap x 20mm |
| 2 | ```screw(M2p5_cap_screw, 16)``` | Screw M2.5 cap x 16mm |
| 4 | ```screw(M2p5_cap_screw, 20)``` | Screw M2.5 cap x 20mm |
| 4 | ```screw(M2p5_cap_screw, 25)``` | Screw M2.5 cap x 25mm |
| 2 | ```screw(M2p5_cap_screw, 20)``` | Screw M2.5 cap x 20mm |
| 8 | ```screw(M2p5_cap_screw, 25)``` | Screw M2.5 cap x 25mm |
| 8 | ```screw(M2p5_cap_screw, 30)``` | Screw M2.5 cap x 30mm |
| 4 | ```screw(M2p5_pan_screw, 20)``` | Screw M2.5 pan x 20mm |
| 12 | ```screw(M2p5_pan_screw, 25)``` | Screw M2.5 pan x 25mm |
| 4 | ```screw(M3_cap_screw, 16)``` | Screw M3 cap x 16mm |
| 8 | ```screw(M3_cap_screw, 30)``` | Screw M3 cap x 30mm |
| 4 | ```screw(M3_cap_screw, 35)``` | Screw M3 cap x 35mm |
| 12 | ```screw(M4_cap_screw, 35)``` | Screw M4 cap x 35mm |
| 1 | ```pcb(TP4056)``` | TP4056 Li-lon Battery charger module |
| 3 | ```terminal_35(2)``` | Terminal block 2 way 3.5mm |
| 2 | ```green_terminal(gt_2p54, 4)``` | Terminal block 4 way 0.1" |
| 1 | | USB A to Mini B lead |
| 1 | ```pcb(WD2002SJ)``` | WD2002SJ Buck Boost DC-DC converter |
| 16 | ```washer(M2_washer)``` | Washer M2 x 5mm x 0.3mm |
| 34 | ```washer(M2p5_washer)``` | Washer M2.5 x 5.9mm x 0.5mm |
| 16 | ```washer(M3_washer)``` | Washer M3 x 7mm x 0.5mm |
| 12 | ```washer(M3_washer)``` | Washer M3 x 7mm x 0.5mm |
| 12 | ```washer(M4_washer)``` | Washer M4 x 9mm x 0.8mm |
| 1 | ```pcb(ZC_A0591)``` | ZC-A0591 ULN2003 driver PCB |
@@ -2380,22 +2382,21 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
| 4 | pcb_spacer2070.stl |
| 4 | pcb_spacer2080.stl |
| 4 | pcb_spacer2090.stl |
| 4 | pcb_spacer25100.stl |
| 4 | pcb_spacer25110.stl |
| 4 | pcb_spacer25120.stl |
| 4 | pcb_spacer25130_2.stl |
| 4 | pcb_spacer25130.stl |
| 4 | pcb_spacer25140_2.stl |
| 4 | pcb_spacer25150_2.stl |
| 4 | pcb_spacer25180.stl |
| 4 | pcb_spacer25160_2.stl |
| 4 | pcb_spacer25190.stl |
| 2 | pcb_spacer2570.stl |
| 4 | pcb_spacer30160.stl |
| 4 | pcb_spacer25200.stl |
| 2 | pcb_spacer2580.stl |
| 4 | pcb_spacer30170.stl |
| 4 | pcb_spacer30230.stl |
| 4 | pcb_spacer30180.stl |
| 4 | pcb_spacer3050.stl |
| 4 | pcb_spacer40200.stl |
| 4 | pcb_spacer40210.stl |
| 4 | pcb_spacer40220.stl |
| 4 | pcb_spacer40230.stl |
<a href="#top">Top</a>
@@ -2464,19 +2465,24 @@ Pin headers and sockets, etc.
| Function | Description |
|:--- |:--- |
| ```hdr_base_colour(type)``` | Header insulator colour |
| ```hdr_box_size(type)``` | Box header outside dimensions |
| ```hdr_box_wall(type)``` | Box header wall thickness |
| ```hdr_pin_below(type)``` | Header pin length underneath |
| ```hdr_pin_colour(type)``` | Header pin colour |
| ```hdr_pin_length(type)``` | Header pin length |
| ```hdr_pin_width(type)``` | Header pin size |
| ```hdr_pitch(type)``` | Header pitch |
| ```hdr_ra_box_offset(type)``` | Offset between back of the box and the pins |
| ```hdr_ra_height(type)``` | Height of right angle connector |
| ```hdr_socket_depth(type)``` | Socket depth for female housing |
| ```hdr_y_offset(type)``` | Y offset of pins from center of the box |
### Modules
| Module | Description |
|:--- |:--- |
| ```box_header(type, cols = 1, rows = 1, smt = false, cutout = false)``` | Draw box header |
| ```idc_transition(type, cols = 5, skip = [], cutout = false)``` | Draw IDC transition header |
| ```jst_xh_header(type, pin_count, right_angle=false, colour, pin_colour)``` | Draw JST XH connector |
| ```jst_xh_header(type, pin_count, right_angle = false, colour = false, pin_colour = false)``` | Draw JST XH connector |
| ```pin(type, length = undef)``` | Draw a header pin |
| ```pin_header(type, cols = 1, rows = 1, smt = false, right_angle = false, cutout = false, colour)``` | Draw pin header |
| ```pin_socket(type, cols = 1, rows = 1, right_angle = false, height = 0, smt = false, cutout = false, colour)``` | Draw pin socket |
@@ -2487,11 +2493,18 @@ Pin headers and sockets, etc.
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | ```box_header(2p54header, 10, 2)``` | Box header 10 x 2 |
| 1 | ```box_header(2p54header, 8, 1)``` | Box header 8 x 1 |
| 1 | ```idc_transition(2p54header, 10)``` | IDC transition header 10 x 2 |
| 1 | ```pin_header(2p54header, 10, 2)``` | Pin header 10 x 2 |
| 1 | ```pin_header(2p54header, 10, 2, right_angle = true)``` | Pin header 10 x 2 right_angle |
| 1 | ```pin_header(2p54header, 3, 1, right_angle = true)``` | Pin header 3 x 1 right_angle |
| 1 | ```pin_header(2p54header, 3, 2, right_angle = true)``` | Pin header 3 x 2 right_angle |
| 1 | ```pin_header(2p54header, 3, 3, right_angle = true)``` | Pin header 3 x 3 right_angle |
| 1 | ```pin_header(2p54header, 8, 1)``` | Pin header 8 x 1 |
| 1 | ```pin_socket(2p54header, 10, 2)``` | Pin socket 10 x 2 |
| 1 | ```pin_socket(2p54header, 10, 2, right_angle = true)``` | Pin socket 10 x 2 right_angle |
| 1 | ```pin_socket(2p54header, 3, 1, right_angle = true)``` | Pin socket 3 x 1 right_angle |
| 1 | ```pin_socket(2p54header, 3, 2, right_angle = true)``` | Pin socket 3 x 2 right_angle |
| 1 | ```pin_socket(2p54header, 3, 3, right_angle = true)``` | Pin socket 3 x 3 right_angle |
| 1 | ```pin_socket(2p54header, 8, 1)``` | Pin socket 8 x 1 |
<a href="#top">Top</a>
@@ -2922,6 +2935,7 @@ Machine screws and wood screws with various head styles.
| 1 | ```screw(No632_pan_screw, 30)``` | Screw 6-32 pan x 30mm |
| 1 | ```screw(M2_cap_screw, 10)``` | Screw M2 cap x 10mm |
| 1 | ```screw(M2_cs_cap_screw, 10)``` | Screw M2 cs cap x 10mm |
| 1 | ```screw(M2_dome_screw, 10)``` | Screw M2 dome x 10mm |
| 1 | ```screw(M2p5_cap_screw, 10)``` | Screw M2.5 cap x 10mm |
| 1 | ```screw(M2p5_pan_screw, 10)``` | Screw M2.5 pan x 10mm |
| 1 | ```screw(M3_cap_screw, 10)``` | Screw M3 cap x 10mm |
@@ -3399,6 +3413,7 @@ NEMA stepper motor model.
| ```NEMA_body_radius(type)``` | Body radius |
| ```NEMA_boss_height(type)``` | Boss height |
| ```NEMA_boss_radius(type)``` | Boss around the spindle radius |
| ```NEMA_cap_heights(type)``` | Height of the end cap at the corner and the side |
| ```NEMA_hole_pitch(type)``` | Screw hole pitch |
| ```NEMA_length(type)``` | Body length |
| ```NEMA_radius(type)``` | End cap radius |
@@ -3415,7 +3430,7 @@ NEMA stepper motor model.
### Modules
| Module | Description |
|:--- |:--- |
| ```NEMA(type, shaft_angle = 0)``` | Draw specified NEMA stepper motor |
| ```NEMA(type, shaft_angle = 0, jst_connector = false)``` | Draw specified NEMA stepper motor |
| ```NEMA_outline(type)``` | 2D outline |
| ```NEMA_screw_positions(type, n = 4)``` | Positions children at the screw holes |
| ```NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef)``` | Place screws and optional earth tag |
@@ -3637,6 +3652,7 @@ Tubing and sleeving. The internal diameter can be forced to stretch it over some
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 1 | ```tubing(CBNFIB10)``` | Carbon fiber OD 10mm ID 8mm x 15mm |
| 1 | ```tubing(HSHRNK16)``` | Heatshrink sleeving ID 1.6mm x 15mm |
| 1 | ```tubing(HSHRNK100)``` | Heatshrink sleeving ID 10mm x 15mm |
| 1 | ```tubing(HSHRNK24)``` | Heatshrink sleeving ID 2.4mm x 15mm |
@@ -4289,7 +4305,7 @@ Star washers can be omitted by setting ```star_washers``` to false.
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 3 | ```insert(F1BM)``` | Heatfit insert M2 |
| 3 | ```insert(F1BM2)``` | Heatfit insert M2 |
| 3 | ```insert(F1BM2p5)``` | Heatfit insert M2.5 |
| 3 | ```insert(F1BM3)``` | Heatfit insert M3 |
| 3 | ```insert(F1BM4)``` | Heatfit insert M4 |
@@ -4509,7 +4525,7 @@ Star washers can be omitted by setting ```star_washers``` to false.
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 3 | ```insert(F1BM)``` | Heatfit insert M2 |
| 3 | ```insert(F1BM2)``` | Heatfit insert M2 |
| 3 | ```insert(F1BM2p5)``` | Heatfit insert M2.5 |
| 3 | ```insert(F1BM3)``` | Heatfit insert M3 |
| 3 | ```insert(F1BM4)``` | Heatfit insert M4 |
@@ -4839,7 +4855,7 @@ It can also have printed feet on the base with the screws doubling up to hold th
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 4 | ```insert(F1BM)``` | Heatfit insert M2 |
| 4 | ```insert(F1BM2)``` | Heatfit insert M2 |
| 4 | ```insert(F1BM3)``` | Heatfit insert M3 |
| 4 | ```screw(M2_cap_screw, 6)``` | Screw M2 cap x 6mm |
| 3 | ```screw(M3_pan_screw, 6)``` | Screw M3 pan x 6mm |
@@ -4938,41 +4954,48 @@ Clamp for ribbon cable and polypropylene strip.
### Functions
| Function | Description |
|:--- |:--- |
| ```ribbon_clamp_height()``` | Height |
| ```ribbon_clamp_hole_pitch(ways)``` | Hole pitch |
| ```ribbon_clamp_length(ways)``` | Length given ways |
| ```ribbon_clamp_width()``` | Width |
| ```ribbon_clamp_height(screw = screw)``` | Height |
| ```ribbon_clamp_length(ways, screw = screw)``` | Length given ways |
| ```ribbon_clamp_width(screw = screw)``` | Width |
### Modules
| Module | Description |
|:--- |:--- |
| ```ribbon_clamp(ways)``` | Generate STL for given number of ways |
| ```ribbon_clamp_assembly(ways)``` | Printed part with inserts in place |
| ```ribbon_clamp(ways, screw = screw)``` | Generate STL for given number of ways |
| ```ribbon_clamp_assembly(ways, screw)``` | Printed part with inserts in place |
| ```ribbon_clamp_fastened_assembly(ways, thickness, screw = screw)``` | Clamp with fasteners in place |
| ```ribbon_clamp_hole_positions(ways, side = undef)``` | Place children at hole positions |
| ```ribbon_clamp_holes(ways, h = 20)``` | Drill screw holes |
| ```ribbon_clamp_hole_positions(ways, screw = screw, side = undef)``` | Place children at hole positions |
| ```ribbon_clamp_holes(ways, h = 20, screw = screw)``` | Drill screw holes |
![ribbon_clamp](tests/png/ribbon_clamp.png)
### Vitamins
| Qty | Module call | BOM entry |
| ---:|:--- |:---|
| 2 | ```insert(F1BM2)``` | Heatfit insert M2 |
| 2 | ```insert(F1BM3)``` | Heatfit insert M3 |
| 1 | | Ribbon cable 20 way 100mm |
| 1 | | Ribbon cable 8 way 100mm |
| 2 | ```screw(M2_dome_screw, 8)``` | Screw M2 dome x 8mm |
| 2 | ```screw(M3_cap_screw, 10)``` | Screw M3 cap x 10mm |
| 1 | | Tape self amalgamating silicone 11 x 25mm |
| 1 | | Tape self amalgamating silicone 26 x 25mm |
| 2 | ```washer(M2_washer)``` | Washer M2 x 5mm x 0.3mm |
| 2 | ```washer(M3_washer)``` | Washer M3 x 7mm x 0.5mm |
| 2 | ```star_washer(M2_washer)``` | Washer star M2 x 0.3mm |
| 2 | ```star_washer(M3_washer)``` | Washer star M3 x 0.5mm |
### Printed
| Qty | Filename |
| ---:|:--- |
| 1 | ribbon_clamp_20.stl |
| 1 | ribbon_clamp_8_2.stl |
### Assemblies
| Qty | Name |
| ---:|:--- |
| 1 | ribbon_clamp_20_assembly |
| 1 | ribbon_clamp_8_2_assembly |
<a href="#top">Top</a>
@@ -5227,6 +5250,36 @@ Bezier curves and function to get and adjust the length or minimum z point.
![bezier](tests/png/bezier.png)
<a href="#top">Top</a>
---
<a name="Catenary"></a>
## Catenary
Catenary curve to model hanging wires, etc.
Although the equation of the curve is simply ```y = a cosh(x / a)``` there is no explicit formula to calculate the constant ```a``` or the range of ```x``` given the
length of the cable and the end point coordinates. See <https://en.wikipedia.org/wiki/Catenary#Determining_parameters>. The Newton-Raphson method is used to find
```a``` numerically, see <https://en.wikipedia.org/wiki/Newton%27s_method>.
The coordinates of the lowest point on the curve can be retrieved by calling ```catenary_points()``` with ```steps``` equal to zero.
[utils/catenary.scad](utils/catenary.scad) Implementation.
[tests/catenary.scad](tests/catenary.scad) Code for this example.
### Functions
| Function | Description |
|:--- |:--- |
| ```catenary(t, a)``` | Parametric catenary function linear along the length of the curve. |
| ```catenary_ds_by_da(d, a)``` | First derivative of the length with respect to ```a```. |
| ```catenary_find_a(d, l, a = 1, best_e = inf, best_a = 1)``` | Find the catenary constant ```a```, given half the horizontal span and the length. |
| ```catenary_points(l, x, y, steps = 100)``` | Returns a list of 2D points on the curve that goes from the origin to ```(x,y)``` and has length ```l```. |
| ```catenary_s(d, a)``` | Length of a symmetric catenary with width ```2d```. |
![catenary](tests/png/catenary.png)
<a href="#top">Top</a>
---
@@ -5343,6 +5396,8 @@ Method to print holes in mid air. See <https://hydraraptor.blogspot.com/2014/03/
## Horiholes
Utilities for depicting the staircase slicing of horizontal holes made with [`teardrop_plus()`](#teardrops), see <https://hydraraptor.blogspot.com/2020/07/horiholes-2.html>
```horicylinder()``` makes cylinders that fit inside a round hole. Layers that are less than 2 filaments wide and layers that need more than a 45 degree overhang are omitted.
[utils/horiholes.scad](utils/horiholes.scad) Implementation.
@@ -5351,11 +5406,13 @@ Utilities for depicting the staircase slicing of horizontal holes made with [`te
### Functions
| Function | Description |
|:--- |:--- |
| ```teardrop_minus_x(r, y, h)``` | Calculate the ordinate of a compensated teardrop given y and layer height. |
| ```teardrop_plus_x(r, y, h)``` | Calculate the ordinate of a compensated teardrop given y and layer height. |
### Modules
| Module | Description |
|:--- |:--- |
| ```horicylinder(r, z, h = 0, center = true)``` | For making horizontal cylinders that don't need support material and are correct dimensions |
| ```horihole(r, z, h = 0, center = true)``` | For making horizontal holes that don't need support material and are correct dimensions |
![horiholes](tests/png/horiholes.png)
@@ -5402,7 +5459,14 @@ Maths utilities for manipulating vectors and matrices.
| Function | Description |
|:--- |:--- |
| ```angle_between(v1, v2)``` | Return the angle between two vectors |
| ```argcosh(x)``` | inverse hyperbolic cosine |
| ```argcoth(x)``` | inverse hyperbolic cotangent |
| ```argsinh(x)``` | inverse hyperbolic sine |
| ```argtanh(x)``` | inverse hyperbolic tangent |
| ```augment(m)``` | Augment a matrix by adding an identity matrix to the right |
| ```circle_intersect(c1, r1, c2, r2)``` | Calculate one point where two circles in the X-Z plane intersect, clockwise around c1 |
| ```cosh(x)``` | hyperbolic cosine |
| ```coth(x)``` | hyperbolic cotangent |
| ```degrees(radians)``` | Convert degrees to radians |
| ```euler(R)``` | Convert a rotation matrix to a Euler rotation vector. |
| ```identity(n, x = 1)``` | Construct an arbitrary size identity matrix |
@@ -5415,9 +5479,11 @@ Maths utilities for manipulating vectors and matrices.
| ```rotate(a, v)``` | Generate a 4x4 rotation matrix, ```a``` can be a vector of three angles or a single angle around ```z```, or around axis ```v``` |
| ```rowswap(m, i, j)``` | Swap two rows of a matrix |
| ```scale(v)``` | Generate a 4x4 matrix that scales by ```v```, which can be a vector of xyz factors or a scalar to scale all axes equally |
| ```sinh(x)``` | hyperbolic sine |
| ```solve(m, i = 0, j = 0)``` | Solve each row ensuring diagonal is not zero |
| ```solve_row(m, i)``` | Make diagonal one by dividing the row by it and subtract from other rows to make column zero |
| ```sqr(x)``` | Square x |
| ```tanh(x)``` | hyperbolic tangent |
| ```transform(v, m)``` | Apply 4x4 transform to a 3 vector by extending it and cropping it again |
| ```transform_points(path, m)``` | Apply transform to a path |
| ```translate(v)``` | Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z``` |
@@ -5607,7 +5673,7 @@ An additional twist around the path can be specified. If the path is closed this
### Modules
| Module | Description |
|:--- |:--- |
| ```sweep(path, profile, loop = false, twist = 0)``` | Draw a polyhedron that is the swept volume |
| ```sweep(path, profile, loop = false, twist = 0, convexity = 1)``` | Draw a polyhedron that is the swept volume |
![sweep](tests/png/sweep.png)
@@ -5675,6 +5741,7 @@ Simple tube or ring
|:--- |:--- |
| ```ring(or, ir)``` | Create a ring with specified external and internal radii |
| ```tube(or, ir, h, center = true)``` | Create a tube with specified external and internal radii and height ```h``` |
| ```woven_tube(or, ir, h, center= true, colour = grey(30)``` | Create a woven tube with specified external and internal radii, height ```h```, colours, warp and weft |
![tube](tests/png/tube.png)
@@ -5799,11 +5866,13 @@ Global constants, functions and modules. This file is used directly or indirectl
| ```foot(x)``` | Foot to mm conversion |
| ```in(list, x)``` | Returns true if ```x``` is an element in the ```list``` |
| ```inch(x)``` | Inch to mm conversion (For fractional inches, 'inch(1 + 7/8)' will work as expected.) |
| ```limit(x, min, max)``` | Force x in range min <= x <= max |
| ```m(x)``` | m to mm conversion |
| ```mm(x)``` | Explicit mm specified |
| ```no_point(str)``` | Replace decimal point in string with 'p' |
| ```r2sides(r)``` | Replicates the OpenSCAD logic to calculate the number of sides from the radius |
| ```r2sides4n(r)``` | Round up the number of sides to a multiple of 4 to ensure points land on all axes |
| ```slice(list, start = 0, end = undef)``` | Slice a list or string with Python type semantics |
| ```sqr(x)``` | Returns the square of ```x``` |
| ```yard(x)``` | Yard to mm conversion |
@@ -5849,7 +5918,7 @@ The module provides `poly_circle()`, `poly_cylinder()` and `poly_ring()` that is
|:--- |:--- |
| ```drill(r, h = 100, center = true)``` | Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle |
| ```poly_circle(r, sides = 0)``` | Make a circle adjusted to print the correct size |
| ```poly_cylinder(r, h, center = false, sides = 0)``` | Make a cylinder adjusted to print the correct size |
| ```poly_cylinder(r, h, center = false, sides = 0, chamfer = false)``` | Make a cylinder adjusted to print the correct size |
| ```poly_drill(r, h = 100, center = true)``` | Make a cylinder for drilling holes suitable for CNC routing if cnc_bit_r is non zero, otherwise a poly_cylinder. |
| ```poly_ring(or, ir, sides = 0)``` | Make a 2D ring adjusted to have the correct internal radius |
| ```poly_tube(or, ir, h, center = false)``` | Make a tube adjusted to have the correct internal radius |

View File

@@ -97,7 +97,6 @@ def tests(tests):
for dir in [deps_dir, png_dir, bom_dir]:
if not os.path.isdir(dir):
os.makedirs(dir)
doc_name = "readme.md"
index = {}
bodies = {}
done = []
@@ -108,19 +107,33 @@ def tests(tests):
#
png_name = "libtest.png"
scad_name = "libtest.scad"
if not os.path.isfile(png_name):
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
if os.path.isfile(scad_name):
libtest = True
lib_blurb = scrape_blurb(scad_name)
if not os.path.isfile(png_name):
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
else:
#
# Project tests so just a title
#
libtest = False
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
lib_blurb = '#' + project + ' Tests\n'
doc_base_name = "readme" if libtest else "tests"
doc_name = doc_base_name + ".md"
#
# List of individual part files
#
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
types = []
for scad in scads:
base_name = scad[:-5]
if not tests or base_name in tests:
done.append(base_name)
print(base_name)
print('\n'+base_name)
cap_name = base_name[0].capitalize() + base_name[1:]
base_name = base_name.lower()
scad_name = scad_dir + '/' + scad
@@ -132,29 +145,42 @@ def tests(tests):
if is_plural(base_name) and os.path.isfile(vits_name):
objects_name = vits_name
locations = [
('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'),
('printed/' + base_name + '.scad', 'Printed'),
('utils/' + base_name + '.scad', 'Utilities'),
('utils/core/' + base_name + '.scad', 'Core Utilities'),
]
locations = []
if os.path.isdir('vitamins'):
locations.append(('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'))
if os.path.isdir('printed'):
locations.append(('printed/' + base_name + '.scad', 'Printed'))
if os.path.isdir('utils'):
locations.append(('utils/' + base_name + '.scad', 'Utilities'))
if libtest and os.path.isdir('utils/core'):
locations.append(('utils/core/' + base_name + '.scad', 'Core Utilities'))
for name, type in locations:
if os.path.isfile(name):
impl_name = name
break
else:
print("Can't find implementation!")
continue
if libtest:
print("Can't find implementation!")
continue
else:
type = 'Tests' # OK when testing part of a project
impl_name = None
vsplit = "AJR" + chr(ord('Z') + 1)
vtype = locations[0][1]
types = [vtype + ' ' + vsplit[i] + '-' + chr(ord(vsplit[i + 1]) - 1) for i in range(len(vsplit) - 1)] + [loc[1] for loc in locations[1 :]]
if type == vtype:
for i in range(1, len(vsplit)):
if cap_name[0] < vsplit[i]:
type = types[i - 1]
break
if libtest:
vsplit = "AJR" + chr(ord('Z') + 1)
vtype = locations[0][1]
types = [vtype + ' ' + vsplit[i] + '-' + chr(ord(vsplit[i + 1]) - 1) for i in range(len(vsplit) - 1)] + [loc[1] for loc in locations[1 :]]
if type == vtype:
for i in range(1, len(vsplit)):
if cap_name[0] < vsplit[i]:
type = types[i - 1]
break
else:
if not types:
types = [loc[1] for loc in locations] # No need to split up the vitamin list
if not type in types: # Will happen when implementation is not found and type is set to Tests
types.append(type)
for t in types:
if not t in bodies:
@@ -250,24 +276,7 @@ def tests(tests):
usage()
with open(doc_name, "wt") as doc_file:
print('# NopSCADlib', file = doc_file)
print('''\
An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and
some utilities. There are also Python scripts to generate Bills of Materials (BOMs),
STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md). A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).
For more examples of what it can make see the [gallery](gallery/readme.md).
The license is GNU General Public License v3.0, see [COPYING](COPYING).
See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
<img src="libtest.png" width="100%"/>\n
''', file = doc_file)
print(lib_blurb, file = doc_file)
print('## Table of Contents<a name="top"/>', file = doc_file)
print('<table><tr>', file = doc_file)
n = 0
@@ -288,10 +297,10 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
for type in types:
for line in bodies[type]:
print(line, file = doc_file)
with open("readme.html", "wt") as html_file:
do_cmd("python -m markdown -x tables readme.md".split(), html_file)
with open(doc_base_name + ".html", "wt") as html_file:
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
times.print_times()
do_cmd('codespell -L od readme.md'.split())
do_cmd(('codespell -L od ' + doc_name).split())
if __name__ == '__main__':
for arg in sys.argv[1:]:

View File

@@ -121,7 +121,8 @@ test_pcb = ["TestPCB", "Test PCB",
[ 70, 130, 180, "term35", 3, "lime"],
[ 50, 150, 0, "transition", 5],
[ 50, 160, 0, "block", 10, 5, 8, "orange"],
[ 50, 170, 0, "button_6mm"],
[ 45, 170, 0, "button_6mm"],
[ 55, 170, 0, "button_4p5mm"],
[ 50, 185, 0, "microswitch", small_microswitch],
[ 52, 200, 0, "pcb", 11, TMC2130 ],
[ 80, 200, 0, "pdip", 24, "27C32", true, inch(0.6) ],

56
tests/catenary.scad Normal file
View File

@@ -0,0 +1,56 @@
//
// NopSCADlib Copyright Chris Palmer 2020
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
l = 250; // [1: 1000]
x = 200; // [1: 1000]
y = 50; //[-500 : 500]
include <../utils/core/core.scad>
use <../utils/catenary.scad>
use <../utils/sweep.scad>
use <../utils/annotation.scad>
module catenaries() {
//
// catenary curve path from control points
//
curve = [for(p = catenary_points(l, x, y)) [p.x, p.y, 0]];
//
// Draw the curve
//
r = 0.5;
sweep(curve, circle_points(r, $fn = 64));
//
// Minimum Z
//
min_z = catenary_points(l, x, y, 0);
color("blue") {
translate([min_z.x, min_z.y + r])
rotate([-90, 0, 0])
arrow();
translate([min_z.x, min_z.y - r])
rotate([90, 0, 0])
arrow();
}
}
if($preview)
rotate(is_undef($bom) ? 0 : [70, 0, 315])
catenaries();

View File

@@ -21,14 +21,14 @@ use <../printed/foot.scad>
module feet()
if($preview) {
translate([50, 0])
translate([40, 0])
foot_assembly(3);
translate([foot_diameter(insert_foot()) / 2, 0])
fastened_insert_foot_assembly(3);
}
else {
translate([50, 0])
translate([40, 0])
foot();
insert_foot();

View File

@@ -29,6 +29,23 @@ module globals() {
translate([50, 0])
right_triangle(10, 20, 0);
}
assert(slice("ABCD") == "ABCD");
assert(slice("ABCD", 1) == "BCD");
assert(slice("ABCD", 2) == "CD");
assert(slice("ABCD", 3) == "D");
assert(slice("ABCD", 4) == "");
assert(slice("ABCD", 1, -1) == "BC");
assert(slice("ABCD", 2, -1) == "C");
assert(slice("ABCD", 3, -1) == "");
assert(slice("ABCD", 4, -1) == "");
assert(slice("ABCD", 0, -1) == "ABC");
assert(slice("ABCD", 0, -2) == "AB");
assert(slice("ABCD", 0, -3) == "A");
assert(slice("ABCD", 0, -4) == "");
assert(slice("ABCD", 0, 0) == "");
assert(slice("ABCD", 0, 1) == "A");
assert(slice("ABCD", 0, 2) == "AB");
assert(slice("ABCD", 0, 3) == "ABC");
}
rotate([70, 0, 315]) globals();

View File

@@ -69,9 +69,13 @@ module horiholes() {
color(silver)
cylinder(r = $r, h = eps, center = true, $fn = 360);
hole_positions()
color("blue")
horicylinder(r = $r, z = $z, h = 2 * eps, center = true, $fn = 360);
hole_positions()
color("red")
linear_extrude(2 * eps, center = true)
linear_extrude(3 * eps, center = true)
intersection() {
difference() {
square(8, center = true);

View File

@@ -69,6 +69,33 @@ module maths() {
// Test Euler
//
assert(euler(rotate(r)) == r, "euler() failed");
//
// Circle intersect
//
r1 = 10;
c1 = [50, 0, 10];
r2 = 20;
c2 = [67, 0, 0];
p1 = circle_intersect(c1, r1, c2, r2);
p2 = circle_intersect(c2, r2, c1, r1);
rotate(90) {
color(grey(90))
translate(c1) rotate([90, 0, 0]) cylinder(r = r1, h = 4 * eps, center = true);
color(grey(80))
translate(c2) rotate([90, 0, 0]) cylinder(r = r2, h = eps, center = true);
color("red")
translate(p1) rotate([90, 0, 0]) cylinder(r = 0.1, h = 6 * eps, center = true);
color("blue")
translate(p2) rotate([90, 0, 0]) cylinder(r = 0.1, h = 6 * eps, center = true);
translate(p1) arrow();
translate(p2) vflip() arrow();
}
}
rotate(45)

View File

@@ -21,11 +21,11 @@ include <../utils/core/core.scad>
use <../vitamins/opengrab.scad>
module opengrab_test() {
opengrab_target();
rotate(45)
translate_z(opengrab_target_thickness())
opengrab();
opengrab_target();
translate_z(opengrab_target_thickness())
opengrab();
}
if($preview)

View File

@@ -23,26 +23,56 @@ include <../vitamins/pin_headers.scad>
pins = 10;
module pin_headers()
module pin_headers() {
layout([for(p = pin_headers) hdr_pitch(p) * pins], 15) {
idc_transition(pin_headers[$i], 10);
translate([0, 20])
pin_header(pin_headers[$i], 10, 2, right_angle = true);
pin_header(pin_headers[$i], 3, 2, right_angle = true);
translate([-10, 20])
pin_header(pin_headers[$i], 3, 1, right_angle = true);
translate([10, 20])
pin_header(pin_headers[$i], 3, 3, right_angle = true);
translate([0, 30])
pin_header(pin_headers[$i], 8, 1);
translate([0, 40])
pin_header(pin_headers[$i], 10, 2);
translate([0, 50])
box_header(pin_headers[$i], 8, 1);
translate([0, 60])
box_header(pin_headers[$i], 10, 2);
translate([0, 70])
pin_socket(pin_headers[$i], 8, 1);
translate([0, 80])
pin_socket(pin_headers[$i], 10, 2);
translate([0, 110])
pin_socket(pin_headers[$i], 10, 2, right_angle = true);
translate([-10, 105])
pin_socket(pin_headers[$i], 3, 1, right_angle = true);
translate([0, 105])
pin_socket(pin_headers[$i], 3, 2, right_angle = true);
translate([10, 105])
pin_socket(pin_headers[$i], 3, 3, right_angle = true);
}
for(i = [0, 1], p = [5, 2][i], j = [0 , 1]) {
h = [jst_ph_header, jst_xh_header][j];
translate([-20 * (i + 1), 0 + j * 40])
jst_xh_header(h, p);
translate([-20 * (i + 1), 20 + j * 40])
jst_xh_header(h, p, true);
}
}
if($preview)
pin_headers();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

BIN
tests/png/catenary.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -16,20 +16,22 @@
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
include <../utils/core/core.scad>
include <../core.scad>
use <../printed/ribbon_clamp.scad>
use <../vitamins/wire.scad>
ways = 20;
ways = [8, 20];
screws = [M2_dome_screw, M3_cap_screw];
module ribbon_clamps()
translate([ribbon_clamp_length(ways) / 2, 0])
if($preview) {
ribbon_clamp_fastened_assembly(ways, 3);
for(i = [0 : len(screws) - 1])
translate([ribbon_clamp_length(ways[i]) / 2, i * 30])
if($preview) {
ribbon_clamp_fastened_assembly(ways[i], 3, screws[i]);
ribbon_cable(ways, 100);
}
else
ribbon_clamp(ways);
ribbon_cable(ways[i], 100);
}
else
ribbon_clamp(ways[i], screws[i]);
ribbon_clamps();

View File

@@ -22,12 +22,12 @@ include <../vitamins/stepper_motors.scad>
use <../utils/layout.scad>
module stepper_motors()
layout([for(s = stepper_motors) NEMA_width(s)], 5) {
layout([for(s = stepper_motors) NEMA_width(s)], 5) let(m = stepper_motors[$i]) {
rotate(180)
NEMA(stepper_motors[$i]);
NEMA(m, 0, m == NEMA17M || m == NEMA17M8);
translate_z(4)
NEMA_screws(stepper_motors[$i], M3_pan_screw, n = $i, earth = $i > 4 ? undef : $i - 1);
NEMA_screws(m, M3_pan_screw, n = $i, earth = $i > 4 ? undef : $i - 1);
}
if($preview)

View File

@@ -22,7 +22,7 @@ use <../utils/layout.scad>
include <../vitamins/tubings.scad>
module tubings()
layout([for(t = tubings) tubing_od(t)], 10)
layout([for(t = tubings) tubing_od(t)], 8)
tubing(tubings[$i]);
if($preview)

52
utils/catenary.scad Normal file
View File

@@ -0,0 +1,52 @@
//
// 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/>.
//
//
//! Catenary curve to model hanging wires, etc.
//!
//! Although the equation of the curve is simply ```y = a cosh(x / a)``` there is no explicit formula to calculate the constant ```a``` or the range of ```x``` given the
//! length of the cable and the end point coordinates. See <https://en.wikipedia.org/wiki/Catenary#Determining_parameters>. The Newton-Raphson method is used to find
//! ```a``` numerically, see <https://en.wikipedia.org/wiki/Newton%27s_method>.
//!
//! The coordinates of the lowest point on the curve can be retrieved by calling ```catenary_points()``` with ```steps``` equal to zero.
//
include <core/core.scad>
use <maths.scad>
function catenary(t, a) = let(u = argsinh(t)) a * [u, cosh(u)]; //! Parametric catenary function linear along the length of the curve.
function catenary_s(d, a) = 2 * a * sinh(d / a); //! Length of a symmetric catenary with width ```2d```.
function catenary_ds_by_da(d, a) = 2 * sinh(d / a) - 2 * d / a * cosh(d / a); //! First derivative of the length with respect to ```a```.
function catenary_find_a(d, l, a = 1, best_e = inf, best_a = 1) = //! Find the catenary constant ```a```, given half the horizontal span and the length.
assert(l > 2 * d, "Not long enough to span the gap") assert(d) let(error = abs(catenary_s(d, a) - l))
error >= best_e && error < 0.0001 ? best_a
: catenary_find_a(d, l, max(a - (catenary_s(d, a) - l) / catenary_ds_by_da(d, a), d / argsinh(1e99)), error, a);
function catenary_points(l, x, y, steps = 100) = //! Returns a list of 2D points on the curve that goes from the origin to ```(x,y)``` and has length ```l```.
let(
d = x / 2,
a = catenary_find_a(d, sqrt(sqr(l) - sqr(y))), // Find a to get the correct length
offset = argsinh(y / catenary_s(d, a)),
t0 = sinh(-d / a + offset),
t1 = sinh( d / a + offset),
h = a * cosh(-d / a + offset) - a,
lowest = offset > d / a ? [0, 0] : offset < -d / a ? [x, y] : [d - offset * a, -h],
p0 = catenary(t0, a)
)
steps ? [for(t = [t0 : (t1 - t0) / steps : t1]) catenary(t, a) - p0] : lowest;

View File

@@ -18,7 +18,7 @@
//
//
// Include this file to use the miniumum library
// Include this file to use the minimum library
//
include <../../global_defs.scad>
//

View File

@@ -36,12 +36,22 @@ function in(list, x) = !!len([for(v = list) if(v == x) true]);
function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if ```x``` is not a list
function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius
function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes
function limit(x, min, max) = max(min(x, max), min); //! Force x in range min <= x <= max
module translate_z(z) translate([0, 0, z]) children(); //! Shortcut for Z only translations
module vflip() rotate([180, 0, 0]) children(); //! Invert children by doing a 180&deg; flip around the X axis
module hflip() rotate([0, 180, 0]) children(); //! Invert children by doing a 180&deg; flip around the Y axis
module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); //! Draw an ellipse
function slice_str(str, start, end, s ="") = start >= end ? s : slice_str(str, start + 1, end, str(s, str[start])); // Helper for slice()
function slice(list, start = 0, end = undef) = let( //! Slice a list or string with Python type semantics
len = len(list),
start = limit(start < 0 ? len + start : start, 0, len),
end = is_undef(end) ? len : limit(end < 0 ? len + end : end, 0, len)
) is_string(list) ? slice_str(list, start, end) : [for(i = [start : 1 : end - 1]) list[i]];
module extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D
if(h)
linear_extrude(h, center = center, convexity = 2) // 3D

View File

@@ -32,10 +32,14 @@ module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the corre
circle(r = corrected_radius(r,n), $fn = n);
}
module poly_cylinder(r, h, center = false, sides = 0) //! Make a cylinder adjusted to print the correct size
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false) {//! Make a cylinder adjusted to print the correct size
extrude_if(h, center)
poly_circle(r, sides);
if(h && chamfer)
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides ? sides : sides(r));
}
module poly_ring(or, ir, sides = 0) { //! Make a 2D ring adjusted to have the correct internal radius
cir = corrected_radius(ir, sides);
filaments = (or - cir) / extrusion_width;

View File

@@ -19,6 +19,8 @@
//
//! Utilities for depicting the staircase slicing of horizontal holes made with [`teardrop_plus()`](#teardrops), see <https://hydraraptor.blogspot.com/2020/07/horiholes-2.html>
//!
//! ```horicylinder()``` makes cylinders that fit inside a round hole. Layers that are less than 2 filaments wide and layers that need more than a 45 degree overhang are omitted.
//
include <../utils/core/core.scad>
@@ -53,3 +55,29 @@ module horihole(r, z, h = 0, center = true) { //! For making horizontal holes th
}
}
}
function teardrop_minus_x(r, y, h) = //! Calculate the ordinate of a compensated teardrop given y and layer height.
let(fr = h / 2,
hpot = r - fr,
x2 = sqr(hpot) - sqr(y),
x = x2 > 0 ? sqrt(x2) : 0,
X = y >= -hpot / sqrt(2) ? x + fr : 0
)
X >= extrusion_width ? X : 0;
module horicylinder(r, z, h = 0, center = true) { //! For making horizontal cylinders that don't need support material and are correct dimensions
bot_layer = floor((z - r) / layer_height);
top_layer = ceil((z + r) / layer_height);
render(convexity = 5)
extrude_if(h, center)
for(i = [bot_layer : top_layer]) {
Z = i * layer_height;
y = Z - z + layer_height / 2;
x = teardrop_minus_x(r, y, layer_height);
if(x >= extrusion_width)
hull()
for(end = [-1, 1])
translate([end * (x - layer_height / 2), y])
circle(d = layer_height, $fn = 32);
}
}

View File

@@ -24,6 +24,14 @@ function sqr(x) = x * x; //! Square x
function radians(degrees) = degrees * PI / 180; //! Convert radians to degrees
function degrees(radians) = radians * 180 / PI; //! Convert degrees to radians
function sinh(x) = (exp(x) - exp(-x)) / 2; //! hyperbolic sine
function cosh(x) = (exp(x) + exp(-x)) / 2; //! hyperbolic cosine
function tanh(x) = sinh(x) / cosh(x); //! hyperbolic tangent
function coth(x) = cosh(x) / sinh(x); //! hyperbolic cotangent
function argsinh(x) = ln(x + sqrt(sqr(x) + 1)); //! inverse hyperbolic sine
function argcosh(x) = ln(x + sqrt(sqr(x) - 1)); //! inverse hyperbolic cosine
function argtanh(x) = ln((1 + x) / (1 - x)) / 2;//! inverse hyperbolic tangent
function argcoth(x) = ln((x + 1) / (x - 1)) / 2;//! inverse hyperbolic cotangent
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z```
: v
@@ -138,3 +146,10 @@ function invert(m) = let(n =len(m), m = solve(augment(m))) [ //! Invert a matrix
each m[i][j]
]
];
function circle_intersect(c1, r1, c2, r2) = //! Calculate one point where two circles in the X-Z plane intersect, clockwise around c1
let(
v = c1 - c2, // Line between centres
d = norm(v), // Distance between centres
a = atan2(v.z, v.x) - acos((sqr(d) + sqr(r2) - sqr(r1)) / (2 * d * r2)) // Cosine rule to find angle from c2
) c2 + r2 * [cos(a), 0, sin(a)]; // Point on second circle

View File

@@ -34,14 +34,22 @@ function transpose3(m) = [ [m[0].x, m[1].x, m[2].x],
[m[0].y, m[1].y, m[2].y],
[m[0].z, m[1].z, m[2].z] ];
//
// Find the first non-colinear point
//
tiny = 0.00001;
function find_curve(tangents, i = 1) =
i >= len(tangents) - 1 || norm(cross(tangents[0], tangents[i] - tangents[0])) > tiny ? i
: find_curve(tangents, i + 1);
//
// Frenet-Serret frame
//
function fs_frame(tangents) =
let(tangent = tangents[0],
normal = tangents[1] - tangents[0],
i = find_curve(tangents),
normal = tangents[i] - tangents[0],
binormal = cross(tangent, normal),
z = unit(tangent),
x = assert(norm(binormal) > 0.00001, "first three points are colinear") unit(binormal),
x = assert(norm(binormal) > tiny, "all points are colinear") unit(binormal),
y = unit(cross(z, x))
) [[x.x, y.x, z.x],
[x.y, y.y, z.y],
@@ -70,7 +78,6 @@ function orientate(p, r) =
[x.y, y.y, z.y],
[x.z, y.z, z.z],
[p.x, p.y, p.z]];
//
// Rotate around z
//
@@ -145,10 +152,10 @@ function sweep(path, profile, loop = false, twist = 0) = //! Generate the point
faces = loop ? skin_faces : concat([cap(facets)], skin_faces, [cap(facets, npoints - 1)])
) [points, faces];
module sweep(path, profile, loop = false, twist = 0) { //! Draw a polyhedron that is the swept volume
module sweep(path, profile, loop = false, twist = 0, convexity = 1) { //! Draw a polyhedron that is the swept volume
mesh = sweep(path, profile, loop, twist);
polyhedron(points = mesh[0], faces = mesh[1]);
polyhedron(points = mesh[0], faces = mesh[1], convexity = convexity);
}
function path_length(path, i = 0, length = 0) = //! Calculated the length along a path

View File

@@ -31,3 +31,41 @@ module ring(or, ir) //! Create a ring with specified external and internal radii
module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height ```h```
linear_extrude(h, center = center, convexity = 5)
ring(or, ir);
module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2, weft) {//! Create a woven tube with specified external and internal radii, height ```h```, colours, warp and weft
colour2 = colour2 ? colour2 : colour * 0.8;
weft = weft ? weft : warp;
warp_count = max(floor(PI * or / warp), 0.5);
angle = 360 / (2 * warp_count);
module layer(weft) {
points = [[ir, weft / 2], [or, weft / 2], [or, -weft / 2], [ir, -weft / 2]];
color(colour)
for (i = [0 : warp_count])
rotate(2 * i * angle)
rotate_extrude(angle = angle)
polygon(points);
color(colour2)
for (i = [0 : warp_count])
rotate((2 * i + 1) * angle)
rotate_extrude(angle = angle)
polygon(points);
}
translate_z(center ? -h / 2 : 0) {
weft_count = floor(h / weft);
if (weft_count > 0)
for (i = [0 : weft_count - 1]) {
translate_z(i * weft + weft / 2)
rotate(i * angle)
layer(weft);
}
remainder = h - weft * weft_count;
if (remainder) {
translate_z(weft_count * weft + remainder / 2)
rotate(weft_count * angle)
layer(remainder);
}
}
}

View File

@@ -20,7 +20,7 @@
//
//! A strip of polypropylene used with ribbon cable to make a cable flexible in one direction only.
//!
//! Modelled with a Bezier spline, which is not quite the same as a miniumum energy curve but very close, epecially
//! Modelled with a Bezier spline, which is not quite the same as a minimum energy curve but very close, epecially
//! near the extreme positions, where the model needs to be accurate.
//!
//! When the sides are constrained then a circular model is more accurate.

View File

@@ -161,13 +161,13 @@ module al_clad_resistor(type, value, leads = true) { //! Draw an aluminium clad
}
linear_extrude(thickness)
difference() {
for(end = [-1, 1])
translate([end * (length - tab) / 2, end * (width - width / 2) / 2])
square([tab, width / 2], center = true);
union()
for(end = [-1, 1])
translate([end * (length - tab) / 2, end * (width - width / 2) / 2])
square([tab, width / 2], center = true);
al_clad_resistor_hole_positions(type)
circle(d = al_clad_hole(type));
}
if(leads) {
translate_z(height / 2)

View File

@@ -137,19 +137,26 @@ module insert_lug(insert, wall, counter_bore = 0, extension = 0, corner_r = 0, f
boss_h = insert_hole_length(insert);
boss_h2 = boss_h + counter_bore;
module shape()
intersection() {
module shape() {
module _shape()
hull() {
circle(boss_r);
translate([boss_r + extension - eps, 0])
square([eps, 2 * boss_r], center = true);
}
if(corner_r)
if(corner_r)
intersection() {
_shape();
translate([boss_r + extension - corner_r, 0])
rotate(-45)
quadrant(w = 100, r = corner_r - eps, center = true);
}
}
else
_shape();
}
translate_z(-boss_h)
linear_extrude(boss_h)

View File

@@ -29,7 +29,7 @@
// d d h d d
// d
//
F1BM2 = [ "F1BM", 4.0, 3.6, 3.2, 2, 3.0, 1.0, 3.4, 3.1 ];
F1BM2 = [ "F1BM2", 4.0, 3.6, 3.2, 2, 3.0, 1.0, 3.4, 3.1 ];
F1BM2p5 = [ "F1BM2p5", 5.8, 4.6, 4.0, 2.5, 3.65, 1.6, 4.4, 3.9 ];
F1BM3 = [ "F1BM3", 5.8, 4.6, 4.0, 3, 3.65, 1.6, 4.4, 3.9 ];
F1BM4 = [ "F1BM4", 8.2, 6.3, 5.6, 4, 5.15, 2.3, 6.0, 5.55 ];

View File

@@ -179,23 +179,27 @@ module jhead_hot_end_assembly(type, filament, naked = false) { //! Assembly with
//
// heater block
//
rotate(90)
translate([-nozzle_x(heater), 0, inset - insulator_length - heater_height(heater) / 2]) {
intersection() {
group() {
translate([resistor_x(heater), -exploded() * 15, 0])
rotate([90, 0, 0])
sleeved_resistor(resistor, PTFE20, bare = -10);
module heater_components() {
translate([resistor_x(heater), -exploded() * 15, 0])
rotate([90, 0, 0])
sleeved_resistor(resistor, PTFE20, bare = -10);
translate([-heater_length(heater) / 2 + resistor_length(thermistor) / 2 - exploded() * 10, thermistor_y(heater), 0])
rotate([90, 0, -90])
sleeved_resistor(thermistor, PTFE07, heatshrink = HSHRNK16);
}
rotate(90)
translate([-nozzle_x(heater), 0, inset - insulator_length - heater_height(heater) / 2])
if(exploded())
heater_components();
else
intersection() {
heater_components();
translate([-heater_length(heater) / 2 + resistor_length(thermistor) / 2 - exploded() * 10, thermistor_y(heater), 0])
rotate([90, 0, -90])
sleeved_resistor(thermistor, PTFE07, heatshrink = HSHRNK16);
}
if(!exploded())
if(naked)
color("grey") cylinder(r = 12, h = 100, center = true);
else
cube(1, true); // hide the wires when not exploded
}
}
}
}

View File

@@ -24,18 +24,27 @@
//
include <../utils/core/core.scad>
use <../utils/thread.scad>
use <pcb.scad>
include <smds.scad>
pitch = 33.8 / 2;
width = 40;
depth = 18;
magnet = 4.3;
pcb = 0.8;
pillar = 6;
target = 1;
pole_w = 2;
pole_l = 36;
poles = 15;
pcb = ["", "", width, width, 0.8, 0, 3.5, 0, "darkgreen", false, [],
[ [ 3.45, 19, 0, "button_4p5mm"],
[ 2.75, 24.5, 0, "smd_led", LED0805, "green"],
[ 2.75, 28.0, 0, "smd_led", LED0805, "red"],
[ 28.5, 13, 0, "2p54header", 3, 1, false, undef, true],
]];
module opengrab_hole_positions() //! Position children at the screw positions
let($d = 3.2)
for($x = [-pitch, pitch], $y = [-pitch, pitch])
@@ -48,9 +57,11 @@ module opengrab_side_hole_positions() //! Position children at the two 4mm hole
translate([$x, 0])
children();
function opengrab_width() = width; //! Module width
function opengrab_depth() = depth; //! Module height
function opengrab_target_thickness() = target; //! Target sheet thickness
function opengrab_width() = width; //! Module width
function opengrab_depth() = depth; //! Module height
function opengrab_target_thickness() = target; //! Target sheet thickness
function opengrab_pcb() = pcb; //! The PCB
function opengrab_pcb_z() = depth - pillar - pcb_thickness(pcb); //! PCB offset from the front
module opengrab() { //! Draw OpenGrab module
vitamin("opengrab(): OpenGrab V3 electro permanent magnet");
@@ -67,10 +78,9 @@ module opengrab() { //! Draw OpenGrab module
cube([pole_w, pole_l, 1], center = true);
}
color("darkgreen")
translate_z(depth - pillar - pcb / 2)
cube([width, width, pcb], center = true);
not_on_bom()
translate_z(opengrab_pcb_z())
pcb(pcb);
translate_z(1)
opengrab_hole_positions() {

View File

@@ -77,7 +77,6 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
tab_z = pmeter_tab_z(type);
pcb = pmeter_pcb(type);
ap2 = pmeter_inner_ap(type);
pcb_h = pmeter_pcb_h(type) - bezel.z;
buttons = pmeter_buttons(type);
color("#94A7AB")
@@ -146,15 +145,16 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
translate(pmeter_inner_ap_o(type))
square([ap2.x, ap2.y], center = true);
}
if(pcb)
if(pcb) {
vflip()
translate_z(h - pcb_thickness(pcb) - pmeter_pcb_z(type))
pcb(pcb);
if(pcb_h > 0)
%translate_z(-pcb_h / 2 - eps)
cube([size.x - 2 * t - eps, size.y - 2 * t - eps, pcb_h], center = true);
pcb_h = pmeter_pcb_h(type) - bezel.z;
if(pcb_h > 0)
%translate_z(-pcb_h / 2 - eps)
cube([size.x - 2 * t - eps, size.y - 2 * t - eps, pcb_h], center = true);
}
if(buttons)
for(b = buttons)
panel_meter_button(b);

View File

@@ -41,10 +41,10 @@ DSP5005 = ["DSP5005", "Ruideng DSP5005 Power supply module", [7
[[-25, 9, 0], [ 6.5, 4.5, 1], 0.5, "yellow"],
]];
DSN_VC288PCB = ["", "", 41, 21, 1, 0, 0, 0, "green", false, [], [[ 5, -3, 0, "jst_xh", 3], ], []];
DSN_VC288PCB = ["", "", 41, 21, 1, 0, 0, 0, "green", false, [], [[ 5, -3.525, 0, "jst_xh", 3], ], []];
DSN_VC288 = ["DSN_VC288","DSN-VC288 DC 100V 10A Voltmeter ammeter", [45.3, 26, 17.4], [47.8, 28.8, 2.5], 0, [1, 1.8], [36, 18, 2.5], [], 0, 2,
[], 0, DSN_VC288PCB, 5];
[], 0, DSN_VC288PCB, 5, 0];
panel_meters = [DSN_VC288, PZEM021, PZEM001, DSP5005];

View File

@@ -915,7 +915,7 @@ module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb compon
function param(n, default = 0) = len(comp) > n ? comp[n] : default;
rotate(comp.z) {
// Components that have a cutout parameter go in this section
if(show(comp, "2p54header")) pin_header(2p54header, comp[4], comp[5], param(6, false), false, cutouts, colour = param(7, undef));
if(show(comp, "2p54header")) pin_header(2p54header, comp[4], comp[5], param(6, false), param(8, false), cutouts, colour = param(7, undef));
if(show(comp, "2p54boxhdr")) box_header(2p54header, comp[4], comp[5], param(6, false), cutouts);
if(show(comp, "2p54socket")) pin_socket(2p54header, comp[4], comp[5], param(6, false), param(7, 0), param(8, false), cutouts, param(9, undef));
if(show(comp, "chip")) chip(comp[4], comp[5], comp[6], param(7, grey(30)), cutouts);
@@ -940,6 +940,7 @@ module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb compon
if(!cutouts) {
// Components that don't have a cutout parameter go in this section
if(show(comp, "button_6mm")) square_button(button_6mm);
if(show(comp, "button_4p5mm")) square_button(button_4p5mm);
if(show(comp, "microswitch")) translate_z(microswitch_thickness(comp[4])/2) microswitch(comp[4]);
if(show(comp, "pcb")) translate_z(comp[4]) pcb(comp[5]);
if(show(comp, "standoff")) standoff(comp[4], comp[5], comp[6], comp[7]);
@@ -1020,8 +1021,6 @@ module pcb(type) { //! Draw specified PCB
for(part = pcb_accessories(type))
vitamin(part);
pcb_components(type);
color(pcb_colour(type)) linear_extrude(t) difference() {
if(Len(pcb_polygon(type)))
polygon(pcb_polygon(type));
@@ -1075,6 +1074,8 @@ module pcb(type) { //! Draw specified PCB
circle(d = 2);
}
}
pcb_components(type);
}
module pcb_spacer(screw, height, wall = 1.8, taper = 0) { //! Generate STL for PCB spacer

View File

@@ -348,7 +348,7 @@ PI_IO = ["PI_IO", "PI_IO V2", 35.56, 25.4, 1.6, 0, 0, 0, "green", tru
], []];
ZC_A0591 = ["ZC_A0591", "ZC-A0591 ULN2003 driver PCB", 35, 32, 1.6, 0, 2.5, 0, "green", false, [[2.25, 3.25], [-2.25, 3.25], [2.25, -3.25], [-2.25, -3.25] ],
[ [ 12.25, 8.3, -90, "jst_xh", 5],
[ [ 11.725, 8.3, -90, "jst_xh", 5],
[ -6.5, 10, 0, "2p54header", 1, 4],
[ 20.4, -4.5, 0, "2p54header", 4, 1],
[ 20.4, 11, 180, "pdip", 16, "ULN2803AN", true],
@@ -385,6 +385,11 @@ WD2002SJ = ["WD2002SJ", "WD2002SJ Buck Boost DC-DC converter", 78, 47, 1.6, 0, 3
],
[]];
MP1584EN = ["MP1584EN", "MP1584EN 3A buck converter", 22, 17, 1.2, 0, 1, [2, 2], "green", false,
[[1.75, 1.75], [1.75, -1.75], [-1.75, 1.75], [-1.75, -1.75], [-1.75, -4.4], [-1.75, 4.48], [1.75, -4.4], [1.75, 4.4]],
[]
];
PERF80x20 = ["PERF80x20", "Perfboard 80 x 20mm", 80, 20, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]];
PERF70x50 = ["PERF70x50", "Perfboard 70 x 50mm", 70, 50, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]];
@@ -403,14 +408,14 @@ RAMPSEndstop = ["RAMPSEndstop", "RAMPS Endstop Switch",
[2, 2, false], [2, 13.5, false], [17, 13.5], [36, 13.5]
],
[
[ 12, 8, -90, "jst_xh", 3, true, "white", "silver"],
[ 11.6, 8, -90, "jst_xh", 3, true, "white", "silver"],
[ 26.5, 12.75, 0, "microswitch", small_microswitch],
[ 27.5, 17.5, 15, "chip", 15, 0.5, 4.5, "silver"],
],
[]];
pcbs = [TP4056, MT3608, RAMPSEndstop, ExtruderPCB, PI_IO, ZC_A0591, RPI0, EnviroPlus, ArduinoUno3, ArduinoLeonardo, Keyes5p1, PSU12V1A, WD2002SJ, RPI3, RPI4, DuetE, Duex2, Duex5, Melzi];
pcbs = [MP1584EN, TP4056, MT3608, RAMPSEndstop, ExtruderPCB, PI_IO, ZC_A0591, RPI0, EnviroPlus, ArduinoUno3, ArduinoLeonardo, Keyes5p1, PSU12V1A, WD2002SJ, RPI3, RPI4, DuetE, Duex2, Duex5];
perfboards = [PERF74x51, PERF70x50, PERF60x40, PERF70x30, PERF80x20];

View File

@@ -29,13 +29,18 @@ function hdr_pin_width(type) = type[4]; //! Header pin size
function hdr_pin_colour(type) = type[5]; //! Header pin colour
function hdr_base_colour(type) = type[6]; //! Header insulator colour
function hdr_socket_depth(type) = type[7]; //! Socket depth for female housing
function hdr_box_size(type) = type[8]; //! Box header outside dimensions
function hdr_box_wall(type) = type[9]; //! Box header wall thickness
function hdr_y_offset(type) = type[10]; //! Y offset of pins from center of the box
function hdr_ra_box_offset(type)= type[11]; //! Offset between back of the box and the pins
function hdr_ra_height(type) = type[12]; //! Height of right angle connector
module pin(type, length = undef) { //! Draw a header pin
w = hdr_pin_width(type);
l = length == undef ? hdr_pin_length(type) : length;
chamfer = w / 2;
color(hdr_pin_colour(type))
translate_z(l / 2 -hdr_pin_below(type))
translate_z(l / 2 - hdr_pin_below(type))
hull() {
cube([w, w, l - 2 * chamfer], center = true);
@@ -50,26 +55,37 @@ module pin_header(type, cols = 1, rows = 1, smt = false, right_angle = false, cu
ra_offset = 2.4;
width = pitch * rows;
if(cutout)
module cutout()
dogbone_rectangle([cols * pitch + 2 * panel_clearance, rows * pitch + 2 * panel_clearance, 100], center = false);
if(cutout) {
if(right_angle)
translate_z(width / 2)
rotate([-90, 0, 180])
cutout();
else
cutout();
}
else {
vitamin(str("pin_header(", type[0], ", ", cols, ", ", rows,
arg(smt, false, "smt"), arg(right_angle, false, "right_angle"), "): Pin header ", cols, " x ", rows, right_angle ? " right_angle" : ""));
translate_z(smt ? 3.5 - h : 0) {
for(x = [0 : cols - 1], y = [0 : rows - 1]) {
translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), 0])
// Vertical part of the pin
translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2)])
if(right_angle)
pin(type, hdr_pin_below(type) + width / 2 + (y - 0.5) * pitch);
pin(type, hdr_pin_below(type) + (y + 0.5) * pitch);
else
pin(type);
if(right_angle) {
w = hdr_pin_width(type);
// Horizontal part of the pin
rotate([-90, 0, 180])
translate([pitch * (x - (cols - 1) / 2), -pitch * (y - (rows - 1) / 2) -width / 2, hdr_pin_below(type) - (y - 0.5) * pitch])
translate([pitch * (x - (cols - 1) / 2), -pitch * (y - (rows - 1) / 2) - width / 2, hdr_pin_below(type) - (y - (rows - 1) / 2) * pitch])
pin(type, hdr_pin_length(type) - hdr_pin_below(type) + ra_offset + pitch / 2 + (y - 0.5) * pitch);
// corner
translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2) - w / 2, pitch * (y - (rows - 1) / 2) + width / 2 - w / 2])
rotate([0, -90, 0])
color(hdr_pin_colour(type))
@@ -78,7 +94,8 @@ module pin_header(type, cols = 1, rows = 1, smt = false, right_angle = false, cu
square(w);
}
}
translate([0, right_angle ? -ra_offset - pitch / 2 : 0, right_angle ? width / 2 : 0])
// Insulator
translate([0, right_angle ? -ra_offset - (rows - 1) * pitch / 2 : 0, right_angle ? width / 2 : 0])
rotate([right_angle ? 90 : 0, 0, 0])
color(base_colour)
linear_extrude(h)
@@ -96,9 +113,11 @@ module pin_header(type, cols = 1, rows = 1, smt = false, right_angle = false, cu
module box_header(type, cols = 1, rows = 1, smt = false, cutout = false) { //! Draw box header
pitch = hdr_pitch(type);
size = hdr_box_size(type);
w = cols * pitch + 7.62;
l = rows * pitch + 3.52;
h = 8.7;
h = size.z;
t = hdr_box_wall(type);
base = h - 6.4;
if(cutout)
@@ -119,7 +138,7 @@ module box_header(type, cols = 1, rows = 1, smt = false, cutout = false) { //! D
difference() {
square([w, l], center = true);
square([w - 2.4, l - 2.4], center = true);
square([w - t, l - t], center = true);
translate([0, -l / 2])
square([4.5, 4.5], center = true);
@@ -176,7 +195,7 @@ module pin_socket(type, cols = 1, rows = 1, right_angle = false, height = 0, smt
vitamin(str("pin_socket(", type[0], ", ", cols, ", ", rows, arg(right_angle, false, "right_angle"), arg(height, 0, "height"), arg(smt, false, "smt"),
"): Pin socket ", cols, " x ", rows, right_angle ? " right_angle" : ""));
color(base_colour)
translate([0, right_angle ? -ra_offset - pitch / 2 : 0, right_angle ? width / 2 : 0])
translate([0, right_angle ? -ra_offset - (rows - 1) * pitch / 2 : 0, right_angle ? width / 2 : 0])
rotate([right_angle ? 90 : 0, 0, 0])
translate_z(depth / 2)
linear_extrude(depth, center = true)
@@ -192,11 +211,11 @@ module pin_socket(type, cols = 1, rows = 1, right_angle = false, height = 0, smt
for(x = [0 : cols - 1], y = [0 : rows -1]) {
if(!smt)
translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), 0])
pin(type, hdr_pin_below(type) + width / 2 + (y - 0.5) * pitch);
pin(type, hdr_pin_below(type) + (y + 0.5) * pitch);
if(right_angle) {
rotate([-90, 0, 0])
translate([pitch * (x - (cols - 1) / 2), -pitch * (y - (rows - 1) / 2) -width / 2, 0])
rotate([-90, 0, 180])
translate([pitch * (x - (cols - 1) / 2), -pitch * (y - (rows - 1) / 2) - width / 2, hdr_pin_below(type) - (y - (rows - 1) / 2) * pitch])
pin(type, hdr_pin_below(type) + (y - 0.5) * pitch);
w = hdr_pin_width(type);
@@ -210,68 +229,98 @@ module pin_socket(type, cols = 1, rows = 1, right_angle = false, height = 0, smt
}
}
module jst_xh_header(type, pin_count, right_angle=false, colour, pin_colour) { //! Draw JST XH connector
module jst_xh_header(type, pin_count, right_angle = false, colour = false, pin_colour = false) { //! Draw JST XH connector
colour = colour ? colour : hdr_base_colour(type);
pin_colour = pin_colour ? pin_colour : hdr_pin_colour(type);
sizeY = 5.75;
pitch = hdr_pitch(type);
size = hdr_box_size(type) + [(pin_count - 1) * pitch, 0, 0];
pinOffsetX = hdr_box_size(type).x / 2; // Offset from last pin to box edge
wallThickness = hdr_box_wall(type);
y_offset = hdr_y_offset(type);
ra_box_offset = hdr_ra_box_offset(type);
ra_h = hdr_ra_height(type);
ra_z = ra_h - size.y / 2;
ra_extra = ra_h - size.y; // thicker base for right angle version
pinWidth = hdr_pin_width(type);
module jst_xh_socket(type, pin_count) {
socketSizeZ = hdr_socket_depth(type);
pinOffsetX = 2.45;
sizeY = 5.75;
wallThickness = 0.8;
size = [pinOffsetX * 2 + (pin_count - 1) * pitch, sizeY, socketSizeZ];
translate([-size[0] / 2, -size[1] / 2, 0]) {
// the base
cube([size[0], size[1], wallThickness]);
// the three full sides
translate([0, size[1] - wallThickness, 0])
cube([size[0], wallThickness, size[2]]);
cube([wallThickness, size[1], size[2]]);
translate([size[0] - wallThickness, 0, 0])
cube([wallThickness, size[1], size[2]]);
// the sides with cutouts
cube([size[0], wallThickness, 2]);
cutoutWidth = 1;
cutoutOffset = pinOffsetX - cutoutWidth / 2;
cube([cutoutOffset, wallThickness, size[2]]);
translate([size[0] - cutoutOffset, 0, 0])
cube([cutoutOffset, wallThickness, size[2]]);
cube([cutoutOffset, wallThickness, size[2]]);
translate([size[0]-cutoutOffset, 0, 0])
cube([cutoutOffset, wallThickness, size[2]]);
translate([cutoutOffset + cutoutWidth, 0, 0])
cube([size[0] - 2 * (cutoutWidth + cutoutOffset), wallThickness, size[2]]);
module jst_xh_socket(type, pin_count, ra = false) {
module wall() {
difference() {
square([size.x, size.y], center = true);
offset(-wallThickness)
square([size.x, size.y], center = true);
}
if(right_angle)
translate([0, size.y / 2 + ra_extra / 2])
square([size.x, ra_extra], center = true);
}
} // end module
module slots() {
cutoutWidth = 1.3;
cutoutOffset = pinOffsetX + cutoutWidth / 2 - hdr_pin_width(type) / 2;
for(side = [-1, 1])
translate([side * (size.x / 2 - cutoutOffset), -size.y / 2 + wallThickness / 2])
square([cutoutWidth, 2 * wallThickness], center = true);
}
linear_extrude(wallThickness)
square([size.x, size.y], center = true); // the base
linear_extrude(size.z / 2) // full walls up to the slots
wall();
linear_extrude(size.z) // slotted walls to the top
difference() {
wall();
if(type[0] == "jst_xh_header") {
if(pin_count > 2)
slots();
else
hull()
slots();
translate([0, -size.y / 2 + 3 * wallThickness / 2])
square([size.x + 1, wallThickness], center = true);
}
if(type[0] == "jst_ph_header") {
translate([0, -size.y / 2 + wallThickness / 2])
square([max((pin_count - 2) * pitch, 1), 2 * wallThickness], center = true);
translate([0, -y_offset / 2 - pinWidth / 4])
square([size.x + 1, y_offset + pinWidth / 2], center = true);
}
}
} // end module
color(colour)
if(right_angle)
translate([0, -1, sizeY / 2])
translate([0, -ra_box_offset, ra_z])
rotate([-90, 0, 180])
jst_xh_socket(type, pin_count);
jst_xh_socket(type, pin_count, true);
else
jst_xh_socket(type, pin_count);
translate([0, y_offset])
jst_xh_socket(type, pin_count);
color(pin_colour)
for(x = [0 : pin_count - 1]) {
pinWidth = hdr_pin_width(type);
verticalPinLength = right_angle ? hdr_pin_below(type) + sizeY / 2 : hdr_pin_length(type);
translate([pitch * (x - (pin_count - 1) / 2), 0, 0]) {
verticalPinLength = right_angle ? hdr_pin_below(type) + ra_z + y_offset : hdr_pin_length(type);
horizontalPinLength = hdr_pin_length(type) - hdr_pin_below(type) + ra_box_offset;
translate([pitch * (x - (pin_count - 1) / 2), 0]) {
pin(type, verticalPinLength);
if(right_angle) {
translate([0, -pinWidth / 2, sizeY / 2 - pinWidth / 2])
translate([0, -pinWidth / 2, ra_z - pinWidth / 2 + y_offset])
rotate([0, -90, 0])
rotate_extrude(angle = 90, $fn = 32)
translate([0, -pinWidth / 2])
square(pinWidth);
translate([0, -sizeY / 2 - 3 * pinWidth / 4, sizeY / 2])
rotate([90,0,0])
pin(type, hdr_pin_length(type) - hdr_pin_below(type));
translate([0, -hdr_pin_below(type), ra_z + y_offset])
rotate([90, 0, 0])
pin(type, horizontalPinLength);
}
}
}

View File

@@ -17,15 +17,16 @@
// If not, see <https://www.gnu.org/licenses/>.
//
// p p b p p b Socket depth
// i i e i i a
// t n l n n s
// c o e
// h l w w c
// c
//
2p54header = ["2p54header", 2.54, 11.6, 3.2, 0.66, "gold", grey(20), 8.5];
jst_xh_header = ["JST XH header",2.5,10,3.4, 0.64, "gold", grey(90), 7];
// p p b p p b s b b p r r
// i i e i i a o o o i a a
// t n l n n s c x x n
// c o e k b h
// h l w w c s t y
// c h z o
// f
2p54header = ["2p54header", 2.54, 11.6, 3.2, 0.66, "gold", grey(20), 8.5, [0, 0, 8.7], 2.4, 0, 0, 0 ];
jst_xh_header = ["jst_xh_header",2.5, 10, 3.4, 0.64, "gold", grey(90), 0, [4.9, 5.75, 7], 0.8, 0.525, 0.6, 6.1];
jst_ph_header = ["jst_ph_header",2.0, 9, 3.4, 0.64, silver, grey(90), 0, [3.9, 4.5, 6], 0.6, 0.55, 0.25, 4.8];
pin_headers = [ 2p54header ];

View File

@@ -175,12 +175,15 @@ module screw(type, length, hob_point = 0, nylon = false) { //! Draw specified sc
if(head_type == hs_dome) {
lift = 0.38;
h = head_height - lift;
r = min(2 * head_height, (sqr(head_rad) + sqr(h)) / 2 * h); // Special case for M2
y = sqrt(sqr(r) - sqr(head_rad));
color(colour) {
rotate_extrude() {
difference() {
intersection() {
translate([0, -head_height + lift])
circle(2 * head_height);
translate([0, -y + lift])
circle(r);
square([head_rad, head_height]);
}

View File

@@ -75,10 +75,11 @@ M5_cap_screw = ["M5_cap", "M5 cap", hs_cap, 5, 8.5, 5, 2.5, 4.0
M6_cap_screw = ["M6_cap", "M6 cap", hs_cap, 6, 10, 6, 3.3, 5.0, 24, M6_washer, M6_nut, M6_tap_radius, M6_clearance_radius];
M8_cap_screw = ["M8_cap", "M8 cap", hs_cap, 8, 13, 8, 4.3, 6.0, 28, M8_washer, M8_nut, M8_tap_radius, M8_clearance_radius];
M2_cs_cap_screw = ["M2_cs_cap","M2 cs cap", hs_cs_cap,2, 3.8, 0, 0.65,1.27,16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius];
M2_cs_cap_screw = ["M2_cs_cap","M2 cs cap", hs_cs_cap,2, 3.8, 0, 0.65,1.3, 16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius];
M3_cs_cap_screw = ["M3_cs_cap","M3 cs cap", hs_cs_cap,3, 6.0, 0, 1.05,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M4_cs_cap_screw = ["M4_cs_cap","M4 cs cap", hs_cs_cap,4, 8.0, 0, 1.49,2.5, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
M2_dome_screw = ["M2_dome", "M2 dome", hs_dome, 2, 3.5, 1.3, 0.6, 1.3, 16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius];
M3_dome_screw = ["M3_dome", "M3 dome", hs_dome, 3, 5.7, 1.65, 1.04,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M4_dome_screw = ["M4_dome", "M4 dome", hs_dome, 4, 7.6, 2.2, 1.3, 2.5, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
@@ -106,14 +107,14 @@ No6_screw = ["No6", "No6 pan wood", hs_pan, 3.5, 6.7, 2.2, 0, 0
No6_cs_screw = ["No6_cs", "No6 cs wood", hs_cs, 3.5, 7.0, 0, 0, 0, 0, M4_washer, false, No6_pilot_radius, No6_clearance_radius];
screw_lists = [
[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw],
[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw],
[ 0, 0, M3_low_cap_screw],
[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw],
[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, M5_pan_screw, M6_pan_screw, No632_pan_screw],
[ 0, No2_screw, No4_screw, No6_screw, No6_cs_screw],
[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw],
[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, M5_pan_screw, M6_pan_screw, No632_pan_screw],
[ 0, No2_screw, No4_screw, No6_screw, No6_cs_screw],
[ 0, M2_cs_cap_screw,M3_cs_cap_screw, M4_cs_cap_screw],
[ 0, 0, M3_dome_screw, M4_dome_screw],
[ 0, 0, M3_grub_screw, M4_grub_screw]
[ 0, M2_dome_screw, M3_dome_screw, M4_dome_screw],
[ 0, 0, M3_grub_screw, M4_grub_screw]
];
use <screw.scad>

View File

@@ -62,9 +62,10 @@ module smd_led(type, colour, cutout) { //! Draw an SMD LED with specified ```col
intersection() {
square([size.x, size.y], center = true);
for(end = [-1, 1])
translate([end * size.x / 2, 0])
ring(or = r, ir = r / 2);
union()
for(end = [-1, 1])
translate([end * size.x / 2, 0])
ring(or = r, ir = r / 2);
}
color(colour, 0.9)

View File

@@ -23,8 +23,10 @@
include <../core.scad>
include <ring_terminals.scad>
include <../vitamins/pin_headers.scad>
use <../utils/tube.scad>
use <../utils/thread.scad>
use <../utils/round.scad>
use <washer.scad>
use <rod.scad>
@@ -37,9 +39,10 @@ function NEMA_boss_height(type) = type[6]; //! Boss height
function NEMA_shaft_dia(type) = type[7]; //! Shaft diameter
function NEMA_shaft_length(type)= type[8]; //! Shaft length above the face, if a list then a leadscrew: length, lead, starts
function NEMA_hole_pitch(type) = type[9]; //! Screw hole pitch
function NEMA_cap_heights(type) = type[10]; //! Height of the end cap at the corner and the side
function NEMA_holes(type) = [-NEMA_hole_pitch(type) / 2, NEMA_hole_pitch(type) / 2]; //! Screw positions for for loop
function NEMA_big_hole(type) = NEMA_boss_radius(type) + 0.2; //! Clearance hole for the big boss
stepper_body_colour = "black";
stepper_cap_colour = grey(50);
stepper_machined_colour = grey(90);
@@ -52,19 +55,20 @@ module NEMA_outline(type) //! 2D outline
circle(NEMA_radius(type));
}
module NEMA(type, shaft_angle = 0) { //! Draw specified NEMA stepper motor
module NEMA(type, shaft_angle = 0, jst_connector = false) { //! Draw specified NEMA stepper motor
side = NEMA_width(type);
length = NEMA_length(type);
body_rad = NEMA_body_radius(type);
boss_rad = NEMA_boss_radius(type);
boss_height =NEMA_boss_height(type);
shaft_rad = NEMA_shaft_dia(type) / 2;
cap = 8;
cap = NEMA_cap_heights(type)[1];
cap2 = NEMA_cap_heights(type)[0];
vitamin(str("NEMA(", type[0], "): Stepper motor NEMA", round(NEMA_width(type) / 2.54), " x ", length, "mm"));
thread_d = 3; // Is this always the case?
thread_d = 3; // Is this always the case?
module cap_shape(end)
difference() {
round(0.5, $fn = 32) difference() {
intersection() {
square([side, side], center = true);
@@ -89,15 +93,44 @@ module NEMA(type, shaft_angle = 0) { //! Draw specified NEMA stepper motor
tube(or = boss_rad, ir = shaft_rad + 2, h = boss_height * 2); // raised boss
linear_extrude(eps)
cap_shape(true);
cap_shape(1);
}
color(stepper_cap_colour) // aluminium end caps
for(end = [-1, 1])
pcb_thickness = 1.6;
header = jst_ph_header;
socket_size = hdr_box_size(header);
tabSize = [16, 4, cap - hdr_ra_height(header) - pcb_thickness];
color(stepper_cap_colour) { // aluminium end caps
for(end = [-1, 1]) {
translate_z(-length / 2 + end * (length - cap) / 2)
linear_extrude(cap, center = true)
cap_shape(end);
translate_z(-length / 2 + end * (length - cap2) / 2)
linear_extrude(cap2, center = true)
difference() {
cap_shape(end);
circle(body_rad);
}
}
if(jst_connector)
translate([-tabSize.x / 2, side / 2, -length])
cube(tabSize);
}
if(jst_connector)
translate([0, side / 2, -length + cap - hdr_ra_height(header)]) {
rotate(180)
not_on_bom()
jst_xh_header(header, 6, true);
translate_z(-pcb_thickness / 2)
color("green")
cube([socket_size.x + 5 * 2, tabSize.y * 2, pcb_thickness], true);
}
if(show_threads)
for(x = NEMA_holes(type), y = NEMA_holes(type))
translate([x, y, -cap / 2])
@@ -111,15 +144,16 @@ module NEMA(type, shaft_angle = 0) { //! Draw specified NEMA stepper motor
cylinder(r = shaft_rad, h = shaft + 5); // shaft
else
not_on_bom()
leadscrew(shaft_rad * 2, shaft.x + 5, shaft.y, shaft.z, center = false)
leadscrew(shaft_rad * 2, shaft.x + 5, shaft.y, shaft.z, center = false);
translate([0, side / 2, -length + cap / 2])
rotate([90, 0, 0])
for(i = [0 : 3])
rotate(225 + i * 90)
color(["red", "blue","green","black"][i])
translate([1, 0, 0])
cylinder(r = 1.5 / 2, h = 12, center = true);
if(!jst_connector)
translate([0, side / 2, -length + cap / 2])
rotate([90, 0, 0])
for(i = [0 : 3])
rotate(225 + i * 90)
color(["red", "blue","green","black"][i])
translate([1, 0, 0])
cylinder(r = 1.5 / 2, h = 12, center = true);
}
module NEMA_screw_positions(type, n = 4) { //! Positions children at the screw holes

View File

@@ -22,14 +22,14 @@
//
// corner body boss boss shaft
// side, length, radius, radius, radius, depth, shaft, length, holes
NEMA17 = ["NEMA17", 42.3, 47, 53.6/2, 25, 11, 2, 5, 24, 31 ];
NEMA17M = ["NEMA17M", 42.3, 40, 53.6/2, 25, 11, 2, 5, 20, 31 ];
NEMA17M8= ["NEMA17M8", 42.3, 40, 53.6/2, 25, 11, 2, 8, [280, 8, 4], 31 ];
NEMA17S = ["NEMA17S", 42.3, 34, 53.6/2, 25, 11, 2, 5, 24, 31 ];
NEMA16 = ["NEMA16", 39.5, 19.2, 50.6/2, 50.6/2, 11, 2, 5, 12, 31 ];
NEMA14 = ["NEMA14", 35.2, 36, 46.4/2, 21, 11, 2, 5, 21, 26 ];
NEMA23 = ["NEMA23", 56.4, 51.2, 75.7/2, 35, 38.1/2, 1.6, 6.35, 24, 47.1 ];
// side, length, radius, radius, radius, depth, shaft, length, holes, cap heights
NEMA17 = ["NEMA17", 42.3, 47, 53.6/2, 25, 11, 2, 5, 24, 31, [11.5, 9]];
NEMA17M = ["NEMA17M", 42.3, 40, 53.6/2, 25, 11, 2, 5, 20, 31, [12.5, 11]];
NEMA17M8= ["NEMA17M8", 42.3, 40, 53.6/2, 25, 11, 2, 8, [280, 8, 4], 31, [12.5, 11]];
NEMA17S = ["NEMA17S", 42.3, 34, 53.6/2, 25, 11, 2, 5, 24, 31, [8, 8]];
NEMA16 = ["NEMA16", 39.5, 19.2, 50.6/2, 50.6/2, 11, 2, 5, 12, 31, [8, 8]];
NEMA14 = ["NEMA14", 35.2, 36, 46.4/2, 21, 11, 2, 5, 21, 26, [8, 8]];
NEMA23 = ["NEMA23", 56.4, 51.2, 75.7/2, 35, 38.1/2, 1.6, 6.35, 24, 47.1, [8, 8]];
stepper_motors = [NEMA14, NEMA16, NEMA17S, NEMA17M, NEMA17, NEMA23];

View File

@@ -21,6 +21,7 @@
//! Tubing and sleeving. The internal diameter can be forced to stretch it over something.
//
include <../utils/core/core.scad>
include <../utils/tube.scad>
function tubing_material(type) = type[1]; //! Material description
function tubing_od(type) = type[2]; //! Outside diameter
@@ -38,10 +39,15 @@ module tubing(type, length = 15, forced_id = 0, center = true) { //! Draw specif
vitamin(str("tubing(", type[0], arg(length, 15), "): ", tubing_material(type), " ID ", original_id, "mm x ",length, "mm"));
else
vitamin(str("tubing(", type[0], arg(length, 15), "): ", tubing_material(type), " OD ", original_od, "mm ID ", original_id,"mm x ",length, "mm"));
color(tubing_colour(type))
linear_extrude(length, center = center, convexity = 4)
difference() {
circle(d = od);
circle(d = id);
}
if(tubing_material(type) == "Carbon fiber")
woven_tube(od / 2, id /2, length, colour = tubing_colour(type));
else
color(tubing_colour(type))
linear_extrude(length, center = center, convexity = 4)
difference() {
circle(d = od);
circle(d = id);
}
}

View File

@@ -19,22 +19,23 @@
//
// Tubing and sleeving
//
PVC64 = ["PVC64", "PVC aquarium tubing", 6, 4, [0.8, 0.8, 0.8, 0.75 ]];
PVC85 = ["PVC85", "PVC aquarium tubing", 8, 5, [0.8, 0.8, 0.8, 0.75 ]];
NEOP85 = ["NEOP85", "Neoprene tubing", 8, 5, [0.2,0.2,0.2]];
PTFE07 = ["PTFE07", "PTFE sleeving", 1.2, 0.71, [0.95, 0.95, 0.95, 0.9]];
PTFE20 = ["PTFE20", "PTFE sleeving", 2.6, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE2_4 = ["PTFE2_4", "PTFE tubing", 4, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE2_3 = ["PTFE2_3", "PTFE tubing", 3, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE4_6 = ["PTFE4_6", "PTFE tubing", 6, 4, [0.95, 0.95, 0.95, 0.9]];
PF7 = ["PF7", "PTFE tubing", 46/10, 3.84, [0.95, 0.95, 0.95, 0.9]];
HSHRNK16 = ["HSHRNK16", "Heatshrink sleeving", 2.0, 1.6, "grey"];
HSHRNK24 = ["HSHRNK24", "Heatshrink sleeving", 2.8, 2.4, "grey"];
HSHRNK32 = ["HSHRNK32", "Heatshrink sleeving", 3.6, 3.2, "grey"];
HSHRNK64 = ["HSHRNK64", "Heatshrink sleeving", 6.8, 6.4, "grey"];
HSHRNK100 = ["HSHRNK100", "Heatshrink sleeving",10.4, 10.0, [0.2,0.2,0.2]];
// Description OD ID Colour
PVC64 = ["PVC64", "PVC aquarium tubing", 6, 4, [0.8, 0.8, 0.8, 0.75 ]];
PVC85 = ["PVC85", "PVC aquarium tubing", 8, 5, [0.8, 0.8, 0.8, 0.75 ]];
NEOP85 = ["NEOP85", "Neoprene tubing", 8, 5, [0.2,0.2,0.2]];
PTFE07 = ["PTFE07", "PTFE sleeving", 1.2, 0.71, [0.95, 0.95, 0.95, 0.9]];
PTFE20 = ["PTFE20", "PTFE sleeving", 2.6, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE2_4 = ["PTFE2_4", "PTFE tubing", 4, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE2_3 = ["PTFE2_3", "PTFE tubing", 3, 2, [0.95, 0.95, 0.95, 0.9]];
PTFE4_6 = ["PTFE4_6", "PTFE tubing", 6, 4, [0.95, 0.95, 0.95, 0.9]];
PF7 = ["PF7", "PTFE tubing", 46/10, 3.84, [0.95, 0.95, 0.95, 0.9]];
HSHRNK16 = ["HSHRNK16", "Heatshrink sleeving", 2.0, 1.6, "grey"];
HSHRNK24 = ["HSHRNK24", "Heatshrink sleeving", 2.8, 2.4, "grey"];
HSHRNK32 = ["HSHRNK32", "Heatshrink sleeving", 3.6, 3.2, "grey"];
HSHRNK64 = ["HSHRNK64", "Heatshrink sleeving", 6.8, 6.4, "grey"];
HSHRNK100 = ["HSHRNK100", "Heatshrink sleeving",10.4, 10.0, [0.2,0.2,0.2]];
CARBONFIBER10 = ["CBNFIB10", "Carbon fiber", 10.0, 8.0, [0.3,0.3,0.3]];
tubings = [PVC64, PVC85, NEOP85, PTFE07, PTFE20, PF7, PTFE2_3, PTFE2_4, PTFE4_6, HSHRNK16, HSHRNK24, HSHRNK64, HSHRNK100];
tubings = [PVC64, PVC85, NEOP85, PTFE07, PTFE20, PF7, PTFE2_3, PTFE2_4, PTFE4_6, HSHRNK16, HSHRNK24, HSHRNK64, HSHRNK100, CARBONFIBER10];
use <tubing.scad>