Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a94e462f34 | ||
|
7ce991e625 | ||
|
3e15be852f | ||
|
7c1c8e92f2 | ||
|
54c3b4f600 | ||
|
d80fc5709e | ||
|
f62ca35c86 | ||
|
769cb44207 | ||
|
f327df95a3 | ||
|
09956b6219 | ||
|
f8c9adca5a | ||
|
b83e56713f | ||
|
4c12d5fca4 | ||
|
da4f9fbdc3 | ||
|
614e5f3a72 | ||
|
a7eae4f549 | ||
|
3cd5769708 | ||
|
7b770abe12 | ||
|
31ab8562a7 | ||
|
db703379a3 | ||
|
cd925bc049 | ||
|
4a2951e22f | ||
|
a93a8f99fb | ||
|
73c436ee15 | ||
|
c69100bd71 | ||
|
e0b89359aa | ||
|
041d720c39 | ||
|
03a0c2fe98 | ||
|
7c2df8d36d | ||
|
8474718884 | ||
|
fe0f32ddc5 | ||
|
f191b9b0f4 | ||
|
2b3908b6fd | ||
|
0a84bf0927 | ||
|
da825b17ab | ||
|
ca153c971d | ||
|
0199587907 | ||
|
60350eb228 | ||
|
4f9729cf86 | ||
|
26f1338ca2 | ||
|
fc44b43638 | ||
|
182f39876a | ||
|
055e90cbb3 | ||
|
832380f893 | ||
|
929d082b25 | ||
|
57212b5701 | ||
|
1c3f136657 | ||
|
cfd2fd32a1 | ||
|
f573a91a09 | ||
|
d75aff2ccd | ||
|
491d85156c | ||
|
c89ce6843f | ||
|
1915dae034 | ||
|
05e8055ce2 | ||
|
21822b9abb | ||
|
d83d4b89bf | ||
|
613152f589 | ||
|
d90c00d140 | ||
|
b52ca9589a | ||
|
0d024060fc | ||
|
c4fe1d1098 | ||
|
a3ced6de45 | ||
|
1cdfe3267c | ||
|
b67cf4ce97 | ||
|
5bac2bf46d | ||
|
079168142b | ||
|
cb30f0c63d | ||
|
812fbc106c | ||
|
dd38fa6e5d | ||
|
5cdcd4ad37 | ||
|
4cb324ed37 | ||
|
eb997aa18c | ||
|
f09343a285 | ||
|
54aab027bd | ||
|
cc61a11602 | ||
|
9cf2e9d7c3 | ||
|
9da8a3cb26 | ||
|
36521cf0b9 | ||
|
22b7aa956c | ||
|
f760aaa20a | ||
|
1c445385b4 | ||
|
45f3fc275f | ||
|
f7fbbd5fe4 | ||
|
a769a38dff | ||
|
0485eeeb34 | ||
|
0a7208ff5a | ||
|
f32182d6df | ||
|
84fbd05f9b | ||
|
2a1fa3fe6b | ||
|
176dc3231c | ||
|
e7ac18e3c0 | ||
|
74b8dcb6d8 | ||
|
6269575fd4 | ||
|
2923e35725 | ||
|
5a1b06fbb9 | ||
|
fd174bbfb4 | ||
|
186f31bb09 | ||
|
80f0490d58 | ||
|
c9e9942070 | ||
|
e41366e20c | ||
|
0595fb5a92 | ||
|
abb676b75c | ||
|
19bae20e24 | ||
|
a7d181ffc4 | ||
|
6b2f8d282b | ||
|
5bb95b2406 | ||
|
dc3905b284 | ||
|
bd2ea3f284 | ||
|
62183bcadc | ||
|
7f9122ae66 |
1705
CHANGELOG.md
Normal file
@@ -172,7 +172,7 @@ This is achieved by having a pair of modules: -
|
||||
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200°C.
|
||||
//
|
||||
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
|
||||
assembly("handle") {
|
||||
assembly("handle", ngb = true) {
|
||||
translate_z(handle_height())
|
||||
stl_colour(pp1_colour) vflip() handle_stl();
|
||||
|
||||
@@ -201,6 +201,9 @@ When the parent assembly is shown exploded the handle's screws will be exploded
|
||||
Note also the `pose([225, 0, 150], [0, 0, 14])` call before the `assembly()` call. This allows the sub-assembly to be posed differently in its build step but doesn't
|
||||
affect its orientation in the parent assembly. The pose parameters are the rotation and the translation taken from the GUI.
|
||||
|
||||
Setting `ngb = true` in the `assembly()` prevents the handle assembly appearing as a columun in the top level BOM in the build instructions.
|
||||
Instead its parts are merged into the parent BOM so the correct quantites are listed.
|
||||
|
||||
### Exploded diagrams
|
||||
|
||||
A lot of vitamins explode themselves when `$explode=1`. This is done with module `explode()` that can be passed a Z offset, or a 3D vector that gives the displacement
|
||||
|
@@ -2,6 +2,8 @@
|
||||
{
|
||||
"name": "base_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {},
|
||||
"vitamins": {
|
||||
@@ -20,6 +22,8 @@
|
||||
{
|
||||
"name": "feet_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"base_assembly": 1
|
||||
@@ -46,6 +50,8 @@
|
||||
{
|
||||
"name": "mains_in_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"feet_assembly": 1
|
||||
@@ -82,6 +88,8 @@
|
||||
{
|
||||
"name": "main_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"mains_in_assembly": 1
|
||||
|
@@ -15,6 +15,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
<span></span>
|
||||
|
||||
---
|
||||
## Table of Contents
|
||||
@@ -24,6 +25,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
1. [Mains In Assembly](#mains_in_assembly)
|
||||
1. [Main Assembly](#main_assembly)
|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
||||
---
|
||||
@@ -54,6 +56,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
| 1 | . | . | . | 1 | socket_box.stl |
|
||||
| 1 | 4 | . | . | 5 | Total 3D printed parts count |
|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
||||
---
|
||||
@@ -81,6 +84,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
||||
---
|
||||
@@ -117,6 +121,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
||||
---
|
||||
@@ -156,6 +161,7 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
||||
---
|
||||
@@ -199,4 +205,5 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
<span></span>
|
||||
[Top](#TOP)
|
||||
|
@@ -1,40 +1,30 @@
|
||||
# A gallery of projects made with NopSCADlib
|
||||
<a name="TOP"></a>
|
||||
## ArduinoThermostat
|
||||
Arduino thermostat to control a beer fridge to use it as an environmental chamber.
|
||||
|
||||

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

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

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

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

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

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

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

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Turntable
|
||||
WiFi enabled remote control turntable for photography
|
||||
|
||||
@@ -97,8 +77,6 @@ WiFi enabled remote control turntable for photography
|
||||
|
||||
Was actually made from DiBond but shown made with carbon fibre here.
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Variac
|
||||
Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp8266-spi-spy](https://hydraraptor.blogspot.com/2018/04/esp8266-spi-spy.html)
|
||||
|
||||
@@ -106,4 +84,3 @@ Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp826
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
lib.scad
@@ -35,7 +35,6 @@ include <vitamins/displays.scad>
|
||||
include <vitamins/extrusions.scad>
|
||||
include <vitamins/extrusion_brackets.scad>
|
||||
include <vitamins/geared_steppers.scad>
|
||||
include <vitamins/green_terminals.scad>
|
||||
include <vitamins/hot_ends.scad>
|
||||
include <vitamins/inserts.scad>
|
||||
include <vitamins/kp_pillow_blocks.scad>
|
||||
|
BIN
libtest.png
Before Width: | Height: | Size: 870 KiB After Width: | Height: | Size: 884 KiB |
12
libtest.scad
@@ -33,6 +33,8 @@
|
||||
//!
|
||||
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
//!
|
||||
//! A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
|
||||
//!
|
||||
//! <img src="libtest.png" width="100%"/>
|
||||
//
|
||||
// This file shows all the parts in the library.
|
||||
@@ -117,6 +119,7 @@ use <tests/flat_hinge.scad>
|
||||
use <tests/foot.scad>
|
||||
use <tests/handle.scad>
|
||||
use <tests/PCB_mount.scad>
|
||||
use <tests/pocket_handle.scad>
|
||||
use <tests/printed_box.scad>
|
||||
use <tests/printed_pulleys.scad>
|
||||
use <tests/ribbon_clamp.scad>
|
||||
@@ -180,7 +183,10 @@ translate([x5, cable_grommets_y + 250])
|
||||
translate([950, 600])
|
||||
box_test();
|
||||
|
||||
translate([890, 750])
|
||||
translate([830, 770])
|
||||
pocket_handles();
|
||||
|
||||
translate([950, 750])
|
||||
printed_boxes();
|
||||
|
||||
translate([850, 1330])
|
||||
@@ -201,8 +207,8 @@ ball_bearings_y = pillars_y + 40;
|
||||
pulleys_y = ball_bearings_y +40;
|
||||
hot_ends_y = pulleys_y + 60;
|
||||
linear_bearings_y = hot_ends_y + 50;
|
||||
sheets_y = linear_bearings_y + 100;
|
||||
pcbs_y = sheets_y + 40;
|
||||
sheets_y = linear_bearings_y + 90;
|
||||
pcbs_y = sheets_y + 60;
|
||||
displays_y = pcbs_y + 170;
|
||||
fans_y = displays_y + 80;
|
||||
transformers_y = fans_y + 120;
|
||||
|
190
printed/box.scad
@@ -139,17 +139,17 @@ module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
|
||||
}
|
||||
|
||||
module box_corner_profile(type) { //! Generates the corner profile STL for 3D printing.
|
||||
stl("box_corner_profile");
|
||||
|
||||
length = box_height(type) - 2 * box_margin(type);
|
||||
difference() {
|
||||
linear_extrude(length, center = true, convexity = 5)
|
||||
box_corner_profile_2D(type);
|
||||
|
||||
for(z = [-1, 1])
|
||||
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
|
||||
insert_hole(box_insert(type), 5);
|
||||
}
|
||||
stl("box_corner_profile")
|
||||
difference() {
|
||||
linear_extrude(length, center = true, convexity = 5)
|
||||
box_corner_profile_2D(type);
|
||||
|
||||
for(z = [-1, 1])
|
||||
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
|
||||
insert_hole(box_insert(type), 5);
|
||||
}
|
||||
}
|
||||
|
||||
module box_corner_profile_section(type, section, sections) { //! Generates interlocking sections of the corner profile to allow it to be taller than the printer
|
||||
@@ -209,7 +209,6 @@ module box_corner_quadrants(type, width, depth)
|
||||
}
|
||||
|
||||
module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
stl(bottom ? "bottom_bezel" : "top_bezel");
|
||||
feet = bottom && box_feet(type);
|
||||
t = box_sheet_slot(type);
|
||||
outset = box_outset(type);
|
||||
@@ -221,66 +220,67 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
height = box_bezel_height(type, bottom);
|
||||
foot_extension = foot_height - height;
|
||||
|
||||
difference() {
|
||||
w = box_width(type);
|
||||
d = box_depth(type);
|
||||
translate_z(-box_profile_overlap(type)) difference() {
|
||||
tw = w + 2 * outset;
|
||||
td = d + 2 * outset;
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type), false);
|
||||
//
|
||||
// Remove edges between the feet
|
||||
//
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([w - 2 * foot_length, td + 1, 1], center = true);
|
||||
stl(bottom ? "bottom_bezel" : "top_bezel")
|
||||
difference() {
|
||||
w = box_width(type);
|
||||
d = box_depth(type);
|
||||
translate_z(-box_profile_overlap(type)) difference() {
|
||||
tw = w + 2 * outset;
|
||||
td = d + 2 * outset;
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type));
|
||||
//
|
||||
// Remove edges between the feet
|
||||
//
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([w - 2 * foot_length, td + 1, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
|
||||
}
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([tw + 1, d - 2 * foot_length, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
}
|
||||
}
|
||||
//
|
||||
// slots for side panels
|
||||
//
|
||||
translate_z(-box_profile_overlap(type))
|
||||
linear_extrude(2 * box_profile_overlap(type), center = true)
|
||||
for(i = [-1, 1]) {
|
||||
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
|
||||
square([t, d - 2 * cgap], center = true);
|
||||
|
||||
translate([0, i * (d + t - sheet_slot_clearance) / 2])
|
||||
square([w - 2 * cgap, t], center = true);
|
||||
}
|
||||
//
|
||||
// recess for top / bottom panel
|
||||
//
|
||||
translate_z(cgap)
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
|
||||
//
|
||||
// leave plastic over the corner profiles
|
||||
//
|
||||
translate_z(-box_profile_overlap(type) - 1)
|
||||
linear_extrude(box_profile_overlap(type) + cgap + 2)
|
||||
union() {
|
||||
difference() {
|
||||
square([w - 2 * inset,
|
||||
d - 2 * inset], center = true);
|
||||
|
||||
box_corner_quadrants(type, w, d);
|
||||
translate_z(foot_height + 1)
|
||||
cube([w - 2 * (foot_length - foot_extension), td + 1, 1], center = true);
|
||||
}
|
||||
box_screw_hole_positions(type)
|
||||
poly_circle(screw_clearance_radius(box_screw(type)));
|
||||
}
|
||||
}
|
||||
if(feet)
|
||||
hull() {
|
||||
translate_z(height + 0.5)
|
||||
cube([tw + 1, d - 2 * foot_length, 1], center = true);
|
||||
|
||||
translate_z(foot_height + 1)
|
||||
cube([tw + 1, d - 2 * (foot_length - foot_extension), 1], center = true);
|
||||
}
|
||||
}
|
||||
//
|
||||
// slots for side panels
|
||||
//
|
||||
translate_z(-box_profile_overlap(type))
|
||||
linear_extrude(2 * box_profile_overlap(type), center = true)
|
||||
for(i = [-1, 1]) {
|
||||
translate([i * (w + t - sheet_slot_clearance) / 2, 0])
|
||||
square([t, d - 2 * cgap], center = true);
|
||||
|
||||
translate([0, i * (d + t - sheet_slot_clearance) / 2])
|
||||
square([w - 2 * cgap, t], center = true);
|
||||
}
|
||||
//
|
||||
// recess for top / bottom panel
|
||||
//
|
||||
translate_z(cgap)
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2);
|
||||
//
|
||||
// leave plastic over the corner profiles
|
||||
//
|
||||
translate_z(-box_profile_overlap(type) - 1)
|
||||
linear_extrude(box_profile_overlap(type) + cgap + 2)
|
||||
union() {
|
||||
difference() {
|
||||
square([w - 2 * inset,
|
||||
d - 2 * inset], center = true);
|
||||
|
||||
box_corner_quadrants(type, w, d);
|
||||
}
|
||||
box_screw_hole_positions(type)
|
||||
poly_circle(screw_clearance_radius(box_screw(type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dowel_length = 20;
|
||||
@@ -485,7 +485,6 @@ module box_shelf_screw_positions(type, screw_positions, thickness = 0, wall = un
|
||||
}
|
||||
|
||||
module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a shelf bracket, the first optional child is a 2D cutout and the second 3D cutouts
|
||||
stl("shelf_bracket");
|
||||
w = is_undef(wall) ? box_wall(type) : wall;
|
||||
insert = box_shelf_insert(type);
|
||||
lip = 2 * insert_boss_radius(insert, w);
|
||||
@@ -513,44 +512,45 @@ module box_shelf_bracket(type, screw_positions, wall = undef) { //! Generates a
|
||||
square([lip, eps]);
|
||||
}
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(w)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
|
||||
round(2) offset(-width)
|
||||
stl("shelf_bracket")
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(w)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
linear_extrude(lip)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
round(2) offset(-width)
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
offset(-w)
|
||||
linear_extrude(lip)
|
||||
difference() {
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
offset(-w)
|
||||
shape()
|
||||
if($children)
|
||||
children(0);
|
||||
}
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
boss();
|
||||
}
|
||||
if($children > 1)
|
||||
hflip()
|
||||
children(1);
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
boss();
|
||||
insert_hole(insert, counterbore = 1, horizontal = true);
|
||||
}
|
||||
if($children > 1)
|
||||
hflip()
|
||||
children(1);
|
||||
|
||||
hflip()
|
||||
box_shelf_screw_positions(type, screw_positions, 0, w)
|
||||
insert_hole(insert, counterbore = 1, horizontal = true);
|
||||
}
|
||||
}
|
||||
|
||||
module box_shelf_bracket_section(type, rows, cols, x, y) { //! Generates sections of the shelf bracket to allow it to be bigger than the printer
|
||||
|
@@ -49,84 +49,84 @@ module ribbon_grommet_hole(ways, h = 50, expand = true) { //! Generate a hole fo
|
||||
}
|
||||
|
||||
module ribbon_grommet(ways, thickness) { //! Generate the STL for a printed ribbon grommet
|
||||
stl(str("ribbon_grommet_", ways, "_", thickness));
|
||||
|
||||
width = 2 * (wall + clearance) + thickness;
|
||||
slot_length = ribbon_clamp_slot(ways);
|
||||
length = slot_length + 2 * wall + 2 * overlap;
|
||||
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([-length / 2, 0])
|
||||
square([length, base]);
|
||||
stl(str("ribbon_grommet_", ways, "_", thickness))
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([-length / 2, 0])
|
||||
square([length, base]);
|
||||
|
||||
for(end = [-1, 1])
|
||||
translate([end * (length / 2 - rad), height - rad])
|
||||
semi_circle(rad);
|
||||
for(end = [-1, 1])
|
||||
translate([end * (length / 2 - rad), height - rad])
|
||||
semi_circle(rad);
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
|
||||
linear_extrude(width -1, center = true)
|
||||
difference() {
|
||||
ribbon_grommet_hole(ways, expand = false, h = 0);
|
||||
linear_extrude(width -1, center = true)
|
||||
difference() {
|
||||
ribbon_grommet_hole(ways, expand = false, h = 0);
|
||||
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
}
|
||||
translate([-slot_length / 2, base])
|
||||
square([slot_length, slot_height]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module round_grommet_top(diameter, thickness, od = undef) { //! Generate the STL for a round grommet top half
|
||||
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness));
|
||||
chamfer = layer_height;
|
||||
h = wall + thickness + wall;
|
||||
r1 = diameter / 2;
|
||||
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
|
||||
r3 = r2 + overlap;
|
||||
r0 = r1 + 1;
|
||||
union() {
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r0, 0],
|
||||
[r3 - chamfer, 0],
|
||||
[r3, chamfer],
|
||||
[r3, wall],
|
||||
[r2, wall],
|
||||
[r2, h - chamfer],
|
||||
[r2 - chamfer, h],
|
||||
[r0, h],
|
||||
]);
|
||||
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness))
|
||||
union() {
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r0, 0],
|
||||
[r3 - chamfer, 0],
|
||||
[r3, chamfer],
|
||||
[r3, wall],
|
||||
[r2, wall],
|
||||
[r2, h - chamfer],
|
||||
[r2 - chamfer, h],
|
||||
[r0, h],
|
||||
]);
|
||||
|
||||
render() difference() {
|
||||
cylinder(r = r0 + eps, h = h);
|
||||
render() difference() {
|
||||
cylinder(r = r0 + eps, h = h);
|
||||
|
||||
poly_cylinder(r = r1, h = 100, center = true);
|
||||
poly_cylinder(r = r1, h = 100, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module round_grommet_bottom(diameter, od = undef) { //! Generate the STL for a round grommet bottom half
|
||||
stl(str("round_grommet_bottom_", round(diameter * 10)));
|
||||
chamfer = layer_height;
|
||||
r1 = diameter / 2;
|
||||
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
|
||||
r3 = r2 + max(overlap, wall + chamfer);
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r2, chamfer],
|
||||
[r2 + chamfer, 0],
|
||||
[r3, 0],
|
||||
[r3, wall - chamfer],
|
||||
[r3 - chamfer, wall],
|
||||
[r2, wall],
|
||||
]);
|
||||
stl(str("round_grommet_bottom_", round(diameter * 10)))
|
||||
rotate_extrude()
|
||||
polygon([
|
||||
[r2, chamfer],
|
||||
[r2 + chamfer, 0],
|
||||
[r3, 0],
|
||||
[r3, wall - chamfer],
|
||||
[r3 - chamfer, wall],
|
||||
[r2, wall],
|
||||
]);
|
||||
}
|
||||
|
||||
module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
|
||||
@@ -161,30 +161,30 @@ module mouse_grommet_hole(r, h = 50, z = undef, expand = wall + clearance) //! M
|
||||
function mouse_grommet_offset(r) = r + wall;
|
||||
|
||||
module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
|
||||
stl(str("mouse_grommet_", r * 10, "_", thickness));
|
||||
|
||||
width = 2 * (wall + clearance) + thickness;
|
||||
length = 2 * r + 2 * wall + 2 * overlap;
|
||||
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
|
||||
stl(str("mouse_grommet_", r * 10, "_", thickness))
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
for(side = [-1, 1])
|
||||
translate_z(side * (width - wall) / 2)
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, z = r + wall, h = 0, expand = wall + overlap);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
linear_extrude(width - 1, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
linear_extrude(width - 1, center = true)
|
||||
difference() {
|
||||
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
|
||||
|
||||
translate([0, wall])
|
||||
mouse_grommet_hole(r, h = 0, expand = 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module mouse_grommet_assembly(r, thickness)
|
||||
|
@@ -68,7 +68,7 @@ function cam_screw_length(cam) = let(
|
||||
front = cam_front_size(cam),
|
||||
screw = pcb_screw(camera_pcb(cam)),
|
||||
nut = screw_nut(screw)
|
||||
) screw_length(screw, front.z - nut_trap_depth(nut), 1, nyloc = true, longer = true);
|
||||
) screw_length(screw, front.z - nut_trap_depth(nut), 1, nyloc = true);
|
||||
|
||||
function hinge_z(cam) = cam_screw_length(cam) - hinge_r;
|
||||
|
||||
@@ -82,7 +82,6 @@ module cam_holes(cam) {
|
||||
}
|
||||
|
||||
module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
|
||||
stl("rpi_camera_focus_ring");
|
||||
|
||||
rad = 15 / 2;
|
||||
hole_r1 = 2.5 / 2;
|
||||
@@ -93,58 +92,58 @@ module rpi_camera_focus_ring_stl() { //! Focus ring the glue onto RPI lens
|
||||
x = rad / (sin(angle / 2) + cos(angle / 2));
|
||||
r = x * sin(angle / 2);
|
||||
|
||||
difference() {
|
||||
linear_extrude(height = thickness, convexity = 5)
|
||||
difference() {
|
||||
union() {
|
||||
circle(x);
|
||||
stl("rpi_camera_focus_ring")
|
||||
difference() {
|
||||
linear_extrude(height = thickness, convexity = 5)
|
||||
difference() {
|
||||
union() {
|
||||
circle(x);
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i])
|
||||
rotate([0, 0, 2 * angle * i + angle])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
for(i = [0 : flutes - 1])
|
||||
rotate([0, 0, 2 * angle * i + angle])
|
||||
translate([x, 0])
|
||||
circle(r);
|
||||
}
|
||||
hull() {
|
||||
poly_cylinder(r = hole_r1, h = 0.1, center = true);
|
||||
hull() {
|
||||
poly_cylinder(r = hole_r1, h = 0.1, center = true);
|
||||
|
||||
translate([0, 0, thickness])
|
||||
poly_cylinder(r = hole_r2, h = 0.1, center = true);
|
||||
translate([0, 0, thickness])
|
||||
poly_cylinder(r = hole_r2, h = 0.1, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module camera_back(cam) { //! Make the STL for a camera case back
|
||||
stl(str("camera_back_", cam[0]));
|
||||
pcb = camera_pcb(cam);
|
||||
back = cam_back_size(cam);
|
||||
screw = pcb_screw(pcb);
|
||||
nut = screw_nut(screw);
|
||||
|
||||
translate_z(back.z)
|
||||
hflip()
|
||||
difference() {
|
||||
translate_z(back.z / 2)
|
||||
cube(back, center = true);
|
||||
stl(str("camera_back_", cam[0]))
|
||||
translate_z(back.z)
|
||||
hflip()
|
||||
difference() {
|
||||
translate_z(back.z / 2)
|
||||
cube(back, center = true);
|
||||
|
||||
translate([0, -cam_back_overlap])
|
||||
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
|
||||
translate([0, -cam_back_overlap])
|
||||
cube([pcb_length(pcb) - 2 * cam_back_overlap, pcb_width(pcb), 2 * cam_back_clearance], center = true);
|
||||
|
||||
translate([0, -pcb_width(pcb) / 2])
|
||||
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
|
||||
translate([0, -pcb_width(pcb) / 2])
|
||||
cube([connector_size.x + 2 * clearance, 2 * connector_size.y + 1, 2 * round_to_layer(connector_size.z + clearance)], center = true);
|
||||
|
||||
translate_z(back.z)
|
||||
cam_holes(cam)
|
||||
hflip()
|
||||
nut_trap(screw, nut, supported = true);
|
||||
}
|
||||
translate_z(back.z)
|
||||
cam_holes(cam)
|
||||
hflip()
|
||||
nut_trap(screw, nut, supported = true);
|
||||
}
|
||||
}
|
||||
|
||||
module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
|
||||
stl(str("camera_front_", cam[0]));
|
||||
front = cam_front_size(cam);
|
||||
back = cam_back_size(cam);
|
||||
pcb = camera_pcb(cam);
|
||||
@@ -170,70 +169,71 @@ module camera_front(cam, hinge = 0) { //! Make the STL for a camera case front
|
||||
translate([0, (hinge ? front.x * hinge : front.y) / 2 + hinge_offset, hinge_r])
|
||||
children();
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
hull()
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
|
||||
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
|
||||
translate_z(front.z - 1)
|
||||
cylinder(r = rad, h = 1);
|
||||
stl(str("camera_front_", cam[0]))
|
||||
difference() {
|
||||
union() {
|
||||
hull()
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (front.x / 2 - rad), y * (front.y / 2 - rad)])
|
||||
hull() { // 3D truncated teardrop gives radiused edges without exceeding 45 degree overhang
|
||||
translate_z(front.z - 1)
|
||||
cylinder(r = rad, h = 1);
|
||||
|
||||
translate_z(rad)
|
||||
sphere(rad);
|
||||
translate_z(rad)
|
||||
sphere(rad);
|
||||
|
||||
cylinder(r = rad * (sqrt(2) - 1), h = eps);
|
||||
}
|
||||
cylinder(r = rad * (sqrt(2) - 1), h = eps);
|
||||
}
|
||||
|
||||
hinge_pos()
|
||||
hull() {
|
||||
rotate([-90, 0, -90])
|
||||
teardrop(r = hinge_r, h = hinge_h, center = false);
|
||||
hinge_pos()
|
||||
hull() {
|
||||
rotate([-90, 0, -90])
|
||||
teardrop(r = hinge_r, h = hinge_h, center = false);
|
||||
|
||||
translate([0, -10, -hinge_r])
|
||||
cube([hinge_h, eps, 2 * hinge_r]);
|
||||
}
|
||||
}
|
||||
|
||||
hinge_pos()
|
||||
rotate([90, 0, 90])
|
||||
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
|
||||
|
||||
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
|
||||
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
|
||||
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(shelf)
|
||||
hflip() {
|
||||
pcb_component_position(pcb, "smd_led") // clearance for LED
|
||||
cube(led_clearance, center = true);
|
||||
|
||||
pcb_component_position(pcb, "smd_res") // clearance for resistor
|
||||
cube(res_clearance, center = true);
|
||||
translate([0, -10, -hinge_r])
|
||||
cube([hinge_h, eps, 2 * hinge_r]);
|
||||
}
|
||||
}
|
||||
|
||||
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
|
||||
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
|
||||
hinge_pos()
|
||||
rotate([90, 0, 90])
|
||||
teardrop_plus(r = screw_clearance_radius(hinge_screw), h = 100, center = true);
|
||||
|
||||
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
|
||||
cube([connector_slot.x, connector_slot.y, front.z], center = true);
|
||||
translate_z(front.z / 2 + shelf - layer_height) // recess for the back
|
||||
cube([back.x + 2 * clearance, back.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(cam_back_clearance + layer_height)
|
||||
cam_holes(cam)
|
||||
rotate(90)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
|
||||
translate_z(front.z / 2 + shelf - pcb_size.z) // recess for PCB
|
||||
cube([pcb_size.x + 2 * clearance, pcb_size.y + 2 * clearance, front.z], center = true);
|
||||
|
||||
translate_z(shelf)
|
||||
hflip() {
|
||||
pcb_component_position(pcb, "smd_led") // clearance for LED
|
||||
cube(led_clearance, center = true);
|
||||
|
||||
pcb_component_position(pcb, "smd_res") // clearance for resistor
|
||||
cube(res_clearance, center = true);
|
||||
}
|
||||
|
||||
translate([conn_pos.x, lens_offset.y + sensor_length / 2, shelf - pcb_size.z]) // clearance for sensor connector
|
||||
cube([conn.x + 2 * clearance, sensor_length, 2 * cam_front_clearance(cam)], center = true);
|
||||
|
||||
translate([0, -front.y / 2, shelf + front.z / 2]) // slot for connector
|
||||
cube([connector_slot.x, connector_slot.y, front.z], center = true);
|
||||
|
||||
translate_z(cam_back_clearance + layer_height)
|
||||
cam_holes(cam)
|
||||
rotate(90)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
|
||||
|
||||
translate_z(shelf - pcb_size.z)
|
||||
hflip()
|
||||
camera_lens(cam, clearance);
|
||||
|
||||
translate_z(shelf - pcb_size.z)
|
||||
hflip()
|
||||
camera_lens(cam, clearance);
|
||||
|
||||
hflip()
|
||||
pcb_component_position(pcb, "smd_led")
|
||||
rotate(45)
|
||||
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
|
||||
}
|
||||
pcb_component_position(pcb, "smd_led")
|
||||
rotate(45)
|
||||
poly_cylinder(r = led_hole_r, h = 100, center = true); // hole for led
|
||||
}
|
||||
}
|
||||
|
||||
function bracket_thickness(cam) = max(wall, min(3.5, hinge_z(cam) - hinge_r - 1));
|
||||
@@ -253,38 +253,39 @@ module camera_bracket_position(cam) //! Position children at the bracket positio
|
||||
children();
|
||||
|
||||
module camera_bracket(cam) { //! Make the STL for the camera bracket
|
||||
stl(str("camera_bracket_", cam[0]));
|
||||
|
||||
t = bracket_thickness(cam);
|
||||
z = hinge_z(cam);
|
||||
translate([hinge_h / 2, 0])
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(eps / 2)
|
||||
cube([hinge_h, 2 * hinge_r, eps], center = true);
|
||||
|
||||
translate_z(z)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(r = hinge_r, h = hinge_h, center = true);
|
||||
stl(str("camera_bracket_", cam[0])) union() {
|
||||
translate([hinge_h / 2, 0])
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(eps / 2)
|
||||
cube([hinge_h, 2 * hinge_r, eps], center = true);
|
||||
|
||||
translate_z(z)
|
||||
rotate([0, 90, 0])
|
||||
cylinder(r = hinge_r, h = hinge_h, center = true);
|
||||
}
|
||||
translate([hinge_h / 2, 0, z])
|
||||
rotate([90, 0, 90])
|
||||
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
|
||||
}
|
||||
translate([hinge_h / 2, 0, z])
|
||||
rotate([90, 0, 90])
|
||||
nut_trap(hinge_screw, screw_nut(hinge_screw), horizontal = true);
|
||||
}
|
||||
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull()
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull()
|
||||
camera_bracket_screw_positions(cam)
|
||||
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
|
||||
|
||||
camera_bracket_screw_positions(cam)
|
||||
circle(washer_radius(screw_washer(bracket_screw)) + 0.5);
|
||||
|
||||
camera_bracket_screw_positions(cam)
|
||||
poly_circle(screw_clearance_radius(bracket_screw));
|
||||
}
|
||||
poly_circle(screw_clearance_radius(bracket_screw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module camera_assembly(cam, angle = 0) //! Camera case assembly
|
||||
assembly(str("camera_", cam[0])) {
|
||||
assembly(str("camera_", cam[0]), ngb = true) {
|
||||
front = cam_front_size(cam);
|
||||
screw = pcb_screw(camera_pcb(cam));
|
||||
nut = screw_nut(screw);
|
||||
|
@@ -27,7 +27,6 @@ include <../utils/core/core.scad>
|
||||
function carrier_height() = 3; //! Height of PCB carrier
|
||||
|
||||
module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
|
||||
stl("ESP12F_carrier");
|
||||
pins = 8;
|
||||
pitch1 = 2;
|
||||
pitch2 = 2.54;
|
||||
@@ -43,29 +42,29 @@ module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
|
||||
width1 = wpitch1 + hole + squeezed_wall * 2;
|
||||
width2 = wpitch2 + hole2 + squeezed_wall * 2;
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width1, length1, eps], center = true);
|
||||
stl("ESP12F_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width1, length1, eps], center = true);
|
||||
|
||||
translate_z(eps / 2)
|
||||
cube([width2, length2, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
cube([width2, length2, eps], center = true);
|
||||
}
|
||||
|
||||
for(side = [-1, 1])
|
||||
for(i = [0 : pins - 1])
|
||||
hull() {
|
||||
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
|
||||
cube([hole2, hole2, eps], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
for(side = [-1, 1])
|
||||
for(i = [0 : pins - 1])
|
||||
hull() {
|
||||
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
|
||||
cube([hole2, hole2, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two required
|
||||
stl("TP4056_carrier");
|
||||
pitch = 2.54;
|
||||
outer_pitch = 13.9;
|
||||
inner_pitch = 7.54;
|
||||
@@ -78,30 +77,30 @@ module TP4056_carrier_stl() { //! Generate the STL for an TP4056 carrier, two re
|
||||
width = hole + squeezed_wall * 2;
|
||||
spacing = inch(0.9);
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width, length1, eps], center = true);
|
||||
stl("TP4056_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate_z(height - eps / 2)
|
||||
cube([width, length1, eps], center = true);
|
||||
|
||||
translate_z(eps / 2)
|
||||
cube([width, length2, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
cube([width, length2, eps], center = true);
|
||||
}
|
||||
|
||||
for(i = [0 : pins - 1])
|
||||
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
|
||||
if(x)
|
||||
hull() {
|
||||
translate([0, x, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, i * pitch - (pins - 1) * pitch / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = [0 : pins - 1])
|
||||
let(x = [-outer_pitch / 2, - inner_pitch / 2, 0, 0, inner_pitch / 2, outer_pitch / 2][i])
|
||||
if(x)
|
||||
hull() {
|
||||
translate([0, x, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, i * pitch - (pins - 1) * pitch / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two required
|
||||
stl("MT3608_carrier");
|
||||
pcb_width = 17;
|
||||
w_pitch_top = 6.81;
|
||||
w_pitch_bot = inch(0.3);
|
||||
@@ -113,21 +112,22 @@ module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two re
|
||||
width = hole + 2 * wall;
|
||||
offset = (l_pitch_top - l_pitch_bot) / 2;
|
||||
|
||||
difference() {
|
||||
hull() {
|
||||
translate([offset, 0, height - eps / 2])
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
|
||||
translate_z(eps / 2)
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
}
|
||||
for(side = [-1, 1])
|
||||
stl("MT3608_carrier")
|
||||
difference() {
|
||||
hull() {
|
||||
translate([offset, side * w_pitch_top / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
translate([offset, 0, height - eps / 2])
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
|
||||
translate([0, side * w_pitch_bot / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
translate_z(eps / 2)
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
}
|
||||
}
|
||||
for(side = [-1, 1])
|
||||
hull() {
|
||||
translate([offset, side * w_pitch_top / 2, height])
|
||||
cube([hole, hole, eps], center = true);
|
||||
|
||||
translate([0, side * w_pitch_bot / 2])
|
||||
cube([hole, hole, eps], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -72,8 +72,6 @@ module corner_block_holes(screw = def_screw) //! Place children at all the holes
|
||||
children();
|
||||
|
||||
module corner_block(screw = def_screw, name = false) { //! Generate the STL for a printed corner block
|
||||
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20));
|
||||
|
||||
r = 1;
|
||||
cb_width = corner_block_width(screw);
|
||||
cb_height = cb_width;
|
||||
@@ -81,43 +79,45 @@ module corner_block(screw = def_screw, name = false) { //! Generate the STL for
|
||||
insert = screw_insert(screw);
|
||||
corner_rad = insert_outer_d(insert) / 2 + wall;
|
||||
offset = corner_block_hole_offset(screw);
|
||||
difference() {
|
||||
hull() {
|
||||
translate([r, r])
|
||||
rounded_cylinder(r = r, h = cb_height, r2 = r);
|
||||
|
||||
translate([r, cb_depth - r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20))
|
||||
difference() {
|
||||
hull() {
|
||||
translate([r, r])
|
||||
rounded_cylinder(r = r, h = cb_height, r2 = r);
|
||||
|
||||
translate([cb_width - r, r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
translate([r, cb_depth - r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
|
||||
translate([offset, offset, offset])
|
||||
sphere(corner_rad);
|
||||
translate([cb_width - r, r])
|
||||
cylinder(r = r, h = cb_height - corner_rad);
|
||||
|
||||
translate([offset, offset])
|
||||
cylinder(r = corner_rad, h = offset);
|
||||
translate([offset, offset, offset])
|
||||
sphere(corner_rad);
|
||||
|
||||
translate([offset, r, offset])
|
||||
rotate([-90, 0, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
translate([offset, offset])
|
||||
cylinder(r = corner_rad, h = offset);
|
||||
|
||||
translate([r, offset, offset])
|
||||
rotate([0, 90, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
translate([offset, r, offset])
|
||||
rotate([-90, 0, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
|
||||
translate([r, offset, offset])
|
||||
rotate([0, 90, 180])
|
||||
rounded_cylinder(r = corner_rad, h = r, r2 = r);
|
||||
}
|
||||
corner_block_v_hole(screw)
|
||||
insert_hole(insert, overshoot);
|
||||
|
||||
corner_block_h_holes(screw)
|
||||
insert_hole(insert, overshoot, true);
|
||||
|
||||
children();
|
||||
}
|
||||
corner_block_v_hole(screw)
|
||||
insert_hole(insert, overshoot);
|
||||
|
||||
corner_block_h_holes(screw)
|
||||
insert_hole(insert, overshoot, true);
|
||||
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
|
||||
assembly(str("corner_block_M", 20 * screw_radius(screw))) {
|
||||
assembly(str("corner_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
insert = screw_insert(screw);
|
||||
|
||||
stl_colour(name ? pp2_colour : pp1_colour)
|
||||
|
@@ -54,44 +54,44 @@ module door_hinge_hole_positions(dir = 0) { //! Position chidren
|
||||
}
|
||||
|
||||
module door_hinge(door_thickness) { //! Generates STL for the moving part of the hinge
|
||||
stl(str("door_hinge_", door_thickness));
|
||||
|
||||
hole_pitch = width - 10;
|
||||
|
||||
union() {
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(width, center = true)
|
||||
stl(str("door_hinge_", door_thickness))
|
||||
union() {
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(width, center = true)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
intersection() {
|
||||
rotate(180)
|
||||
teardrop(r = dia / 2, h = 0, truncate = false);
|
||||
|
||||
square([dia + 1, 2 * thickness + door_thickness], center = true);
|
||||
}
|
||||
|
||||
square([1, thickness + door_thickness]);
|
||||
}
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
}
|
||||
linear_extrude(thickness)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
intersection() {
|
||||
rotate(180)
|
||||
teardrop(r = dia / 2, h = 0, truncate = false);
|
||||
translate([0, -width / 2])
|
||||
square([1, width]);
|
||||
|
||||
square([dia + 1, 2 * thickness + door_thickness], center = true);
|
||||
}
|
||||
|
||||
square([1, thickness + door_thickness]);
|
||||
for(side = [-1, 1])
|
||||
translate([-width + rad, side * (width / 2 - rad)])
|
||||
circle4n(rad);
|
||||
}
|
||||
translate([dia / 2, thickness + door_thickness / 2])
|
||||
teardrop_plus(r = screw_clearance_radius(pin_screw), h = 0);
|
||||
rotate(180)
|
||||
vflip()
|
||||
door_hinge_hole_positions()
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
linear_extrude(thickness)
|
||||
difference() {
|
||||
hull() {
|
||||
translate([0, -width / 2])
|
||||
square([1, width]);
|
||||
|
||||
for(side = [-1, 1])
|
||||
translate([-width + rad, side * (width / 2 - rad)])
|
||||
circle4n(rad);
|
||||
}
|
||||
rotate(180)
|
||||
vflip()
|
||||
door_hinge_hole_positions()
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module door_hinge_6_stl() door_hinge(6);
|
||||
|
@@ -38,23 +38,23 @@ function door_latch_offset() = width / 2 + 1; //! Offset of the axle from the do
|
||||
nut_trap_depth = round_to_layer(screw_head_height(screw)) + 4 * layer_height;
|
||||
|
||||
module door_latch_stl() { //! Generates the STL for the printed part
|
||||
stl("door_latch");
|
||||
|
||||
ridge = 4;
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
|
||||
|
||||
translate_z(thickness / 2)
|
||||
cube([length, ridge, thickness], center = true);
|
||||
stl("door_latch")
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad);
|
||||
|
||||
translate_z(thickness / 2)
|
||||
cube([length, ridge, thickness], center = true);
|
||||
}
|
||||
|
||||
cylinder(d = width, h = height);
|
||||
}
|
||||
|
||||
cylinder(d = width, h = height);
|
||||
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
}
|
||||
|
||||
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickess
|
||||
|
@@ -311,7 +311,7 @@ module _drag_chain_assembly(type, pos = 0, render = false) {
|
||||
//! 1. Remove the support material from the links with side cutters.
|
||||
//! 1. Clip the links together with the special ones at the ends.
|
||||
module drag_chain_assembly(type, pos = 0, render = false) //! Drag chain assembly
|
||||
assembly(str(drag_chain_name(type), "_drag_chain"), big = true)
|
||||
assembly(str(drag_chain_name(type), "_drag_chain"), big = true, ngb = true)
|
||||
if($children == 2)
|
||||
_drag_chain_assembly(type, pos, render) {
|
||||
children(0);
|
||||
|
@@ -71,42 +71,42 @@ module fixing_block_h_hole_2D(screw = def_screw) //! Position 2D child on the ho
|
||||
children();
|
||||
|
||||
module fixing_block(screw = def_screw) { //! Generate the STL
|
||||
stl(str("fixing_block_M", screw_radius(screw) * 20));
|
||||
r = 1;
|
||||
r = 1;
|
||||
insert = screw_insert(screw);
|
||||
corner_rad = insert_outer_d(insert) / 2 + wall;
|
||||
fb_width = fixing_block_width(screw);
|
||||
fb_height = fixing_block_height(screw);
|
||||
fb_depth = fixing_block_depth(screw);
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(fb_height, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
|
||||
circle4n(corner_rad);
|
||||
stl(str("fixing_block_M", screw_radius(screw) * 20))
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(fb_height, convexity = 5)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1]) {
|
||||
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
|
||||
circle4n(corner_rad);
|
||||
|
||||
translate([side * (fb_width / 2 - r), r])
|
||||
circle4n(r);
|
||||
translate([side * (fb_width / 2 - r), r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
fixing_block_v_holes(screw)
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
fixing_block_v_holes(screw)
|
||||
poly_circle(screw_clearance_radius(screw));
|
||||
}
|
||||
}
|
||||
translate_z(fb_height)
|
||||
fixing_block_v_holes(screw)
|
||||
insert_hole(insert);
|
||||
}
|
||||
translate_z(fb_height)
|
||||
fixing_block_v_holes(screw)
|
||||
insert_hole(insert);
|
||||
|
||||
fixing_block_h_hole(screw)
|
||||
insert_hole(insert, 10, true);
|
||||
}
|
||||
fixing_block_h_hole(screw)
|
||||
insert_hole(insert, 10, true);
|
||||
}
|
||||
}
|
||||
|
||||
module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8]) //! Printed part with the inserts inserted
|
||||
assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
|
||||
assembly(str("fixing_block_M", 20 * screw_radius(screw)), ngb = true) {
|
||||
translate_z(fixing_block_height(screw))
|
||||
rotate([0, 180, 0])
|
||||
stl_colour(pp1_colour) render() fixing_block(screw);
|
||||
|
@@ -65,8 +65,6 @@ module hinge_screw_positions(type) { //! Place children at the screw positions
|
||||
}
|
||||
|
||||
module hinge_male(type, female = false) { //! The half with the stationary pin
|
||||
stl(str("hinge_", female ? "fe": "", "male_", type[0]));
|
||||
|
||||
r = hinge_radius(type);
|
||||
w = hinge_width(type);
|
||||
t = hinge_thickness(type);
|
||||
@@ -85,37 +83,40 @@ module hinge_male(type, female = false) { //! The half with the stationary
|
||||
teardrop_r = kr / cos(22.5); // The corner on the teardrop
|
||||
inset = sqrt(sqr(teardrop_r + gap) - sqr(kr - t)) - kr;
|
||||
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1])
|
||||
translate([side * (w / 2 - r), hinge_depth(type) - r])
|
||||
circle4n(r);
|
||||
stl(str("hinge_", female ? "fe": "", "male_", type[0]))
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
hull() {
|
||||
for(side = [-1, 1])
|
||||
translate([side * (w / 2 - r), hinge_depth(type) - r])
|
||||
circle4n(r);
|
||||
|
||||
translate([-w / 2, inset])
|
||||
square([w, eps]);
|
||||
}
|
||||
hinge_screw_positions(type)
|
||||
poly_circle(screw_clearance_radius(hinge_screw(type)));
|
||||
translate([-w / 2, inset])
|
||||
square([w, eps]);
|
||||
}
|
||||
hinge_screw_positions(type)
|
||||
poly_circle(screw_clearance_radius(hinge_screw(type)));
|
||||
}
|
||||
|
||||
pitch = mw + gap + fw + gap;
|
||||
dir = female ? -1 : 1;
|
||||
translate([0, -kr, kr])
|
||||
rotate([90, 0, -90])
|
||||
for(z = [0 : (female ? fn : mn) - 1])
|
||||
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
|
||||
linear_extrude(female ? fw : mw)
|
||||
difference() {
|
||||
hull() {
|
||||
rotate(180)
|
||||
teardrop(r = kr, h = 0);
|
||||
|
||||
translate([-kr - 1, -kr])
|
||||
square(1);
|
||||
}
|
||||
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
|
||||
}
|
||||
}
|
||||
|
||||
pitch = mw + gap + fw + gap;
|
||||
dir = female ? -1 : 1;
|
||||
translate([0, -kr, kr])
|
||||
rotate([90, 0, -90])
|
||||
for(z = [0 : (female ? fn : mn) - 1])
|
||||
translate_z(-dir * w / 2 + z * dir * pitch + (female ? -fw - mw - gap : 0))
|
||||
linear_extrude(female ? fw : mw)
|
||||
difference() {
|
||||
hull() {
|
||||
rotate(180)
|
||||
teardrop(r = kr, h = 0);
|
||||
|
||||
translate([-kr - 1, -kr])
|
||||
square(1);
|
||||
}
|
||||
teardrop_plus(r = pr + (female ? gap : 0), h = 0);
|
||||
}
|
||||
}
|
||||
|
||||
module hinge_female(type) hinge_male(type, true);
|
||||
@@ -129,7 +130,7 @@ module hinge_both(type) { //! Both parts together for printing
|
||||
}
|
||||
|
||||
module hinge_assembly(type, angle = 0)
|
||||
assembly(str("hinge_", type[0])) { //! Assembled hinge
|
||||
assembly(str("hinge_", type[0]), ngb = true) { //! Assembled hinge
|
||||
kr = hinge_knuckle_dia(type) / 2;
|
||||
hr = hinge_pin_dia(type) / 2;
|
||||
w = hinge_width(type);
|
||||
|
@@ -39,7 +39,6 @@ function foot_screw(type = foot) = type[4]; //! Screw type
|
||||
function foot_slant(type = foot) = type[5]; //! Taper angle
|
||||
|
||||
module foot(type = foot) { //! Generate STL
|
||||
stl("foot");
|
||||
h = foot_height(type);
|
||||
t = foot_thickness(type);
|
||||
r1 = washer_radius(screw_washer(foot_screw(type)));
|
||||
@@ -47,24 +46,25 @@ module foot(type = foot) { //! Generate STL
|
||||
r2 = r3 - h * tan(foot_slant(type));
|
||||
r = foot_rad(type);
|
||||
|
||||
union() {
|
||||
rotate_extrude(convexity = 3) {
|
||||
hull() {
|
||||
translate([r1, 0])
|
||||
square([r3 - r1, eps]);
|
||||
stl("foot")
|
||||
union() {
|
||||
rotate_extrude(convexity = 3) {
|
||||
hull() {
|
||||
translate([r1, 0])
|
||||
square([r3 - r1, eps]);
|
||||
|
||||
for(x = [r1 + r, r2 - r])
|
||||
translate([x, h - r])
|
||||
circle4n(r);
|
||||
for(x = [r1 + r, r2 - r])
|
||||
translate([x, h - r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
circle(r1 + eps);
|
||||
|
||||
poly_circle( screw_clearance_radius(foot_screw(type)));
|
||||
}
|
||||
}
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
circle(r1 + eps);
|
||||
|
||||
poly_circle( screw_clearance_radius(foot_screw(type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with fasteners in place for specified sheet thickness
|
||||
@@ -93,7 +93,6 @@ module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with faste
|
||||
}
|
||||
|
||||
module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
|
||||
stl("insert_foot");
|
||||
h = foot_height(type);
|
||||
r3 = foot_diameter(type) / 2;
|
||||
r2 = r3 - h * tan(foot_slant(type));
|
||||
@@ -103,36 +102,37 @@ module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
|
||||
h2 = insert_hole_length(insert);
|
||||
r4 = insert_hole_radius(insert);
|
||||
r5 = r4 + 1;
|
||||
union() {
|
||||
rotate_extrude() {
|
||||
union() {
|
||||
hull() {
|
||||
translate([r5, 0]) {
|
||||
square([r3 - r5, eps]);
|
||||
square([eps, h]);
|
||||
}
|
||||
stl("insert_foot")
|
||||
union() {
|
||||
rotate_extrude() {
|
||||
union() {
|
||||
hull() {
|
||||
translate([r5, 0]) {
|
||||
square([r3 - r5, eps]);
|
||||
square([eps, h]);
|
||||
}
|
||||
|
||||
translate([r2 - r, h - r])
|
||||
circle4n(r);
|
||||
translate([r2 - r, h - r])
|
||||
circle4n(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
linear_extrude(h2 + eps)
|
||||
difference() {
|
||||
circle(r5 + eps);
|
||||
|
||||
poly_circle(r4);
|
||||
}
|
||||
|
||||
translate_z(h2)
|
||||
cylinder(r = r5 + eps, h = h - h2);
|
||||
}
|
||||
linear_extrude(h2 + eps)
|
||||
difference() {
|
||||
circle(r5 + eps);
|
||||
|
||||
poly_circle(r4);
|
||||
}
|
||||
|
||||
translate_z(h2)
|
||||
cylinder(r = r5 + eps, h = h - h2);
|
||||
}
|
||||
}
|
||||
//
|
||||
//! Place the insert in the bottom of the foot and push home with a soldering iron with a conical bit heated to 200°C.
|
||||
//
|
||||
module insert_foot_assembly(type = insert_foot) //! Printed part with insert in place
|
||||
assembly("insert_foot") {
|
||||
assembly("insert_foot", ngb = true) {
|
||||
screw = foot_screw(type);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
|
@@ -46,8 +46,6 @@ module handle_holes(h = 100) //! Drills holes for the screws
|
||||
drill(screw_clearance_radius(screw), h);
|
||||
|
||||
module handle_stl() { //! generate the STL
|
||||
stl("handle");
|
||||
|
||||
module end(end)
|
||||
translate([end * pitch / 2, 0])
|
||||
rotate_extrude()
|
||||
@@ -59,29 +57,30 @@ module handle_stl() { //! generate the STL
|
||||
square([dia / 2 + 1, dia + 1]);
|
||||
}
|
||||
|
||||
translate_z(dia / 2)
|
||||
union() {
|
||||
hull() {
|
||||
end(-1);
|
||||
stl("handle")
|
||||
translate_z(dia / 2)
|
||||
union() {
|
||||
hull() {
|
||||
end(-1);
|
||||
|
||||
end(1);
|
||||
}
|
||||
|
||||
handle_screw_positions()
|
||||
render() difference() {
|
||||
h = height + dia / 2;
|
||||
cylinder(d = dia, h = h);
|
||||
|
||||
translate_z(h)
|
||||
insert_hole(insert, 6);
|
||||
end(1);
|
||||
}
|
||||
}
|
||||
|
||||
handle_screw_positions()
|
||||
render() difference() {
|
||||
h = height + dia / 2;
|
||||
cylinder(d = dia, h = h);
|
||||
|
||||
translate_z(h)
|
||||
insert_hole(insert, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200°C.
|
||||
//
|
||||
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
|
||||
assembly("handle") {
|
||||
assembly("handle", ngb = true) {
|
||||
translate_z(handle_height())
|
||||
stl_colour(pp1_colour) vflip() handle_stl();
|
||||
|
||||
|
@@ -66,35 +66,35 @@ module pcb_mount_washer_stl() //! A plastic washer to clamp a PCB
|
||||
pcb_mount_ring();
|
||||
|
||||
module pcb_mount(pcb, height = 5, washers = true) { //! Make the STL of a pcb mount for the specified PCB.
|
||||
stl(str("pcb_mount_", pcb[0], "_", height));
|
||||
|
||||
y_pitch = pcb_width(pcb) > 4 * pillar_r + 4 ? pillar_r + 1
|
||||
: pcb_width(pcb) / 2 + frame_w + 1 + pillar_r;
|
||||
|
||||
if(washers)
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (pillar_r + 1), y * y_pitch, 0])
|
||||
pcb_mount_washer_stl();
|
||||
stl(str("pcb_mount_", pcb[0], "_", height)) union() {
|
||||
if(washers)
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * (pillar_r + 1), y * y_pitch, 0])
|
||||
pcb_mount_washer_stl();
|
||||
|
||||
for(x = [-1, 1])
|
||||
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
|
||||
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
|
||||
for(x = [-1, 1])
|
||||
translate([x * pillar_x_pitch(pcb) / 2, 0, frame_t / 2])
|
||||
cube([frame_w, pillar_y_pitch(pcb) - 2 * wall, frame_t], center = true);
|
||||
|
||||
for(y = [-1, 1])
|
||||
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
|
||||
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
|
||||
for(y = [-1, 1])
|
||||
translate([0, y * pillar_y_pitch(pcb) / 2, frame_t / 2])
|
||||
cube([pillar_x_pitch(pcb) - 2 * wall, frame_w, frame_t], center = true);
|
||||
|
||||
pcb_mount_screw_positions(pcb)
|
||||
linear_extrude(height)
|
||||
pcb_mount_ring();
|
||||
|
||||
linear_extrude(height + pcb_thickness(pcb) - layer_height)
|
||||
difference() {
|
||||
pcb_mount_screw_positions(pcb)
|
||||
pcb_mount_screw_positions(pcb)
|
||||
linear_extrude(height)
|
||||
pcb_mount_ring();
|
||||
|
||||
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
|
||||
}
|
||||
linear_extrude(height + pcb_thickness(pcb) - layer_height)
|
||||
difference() {
|
||||
pcb_mount_screw_positions(pcb)
|
||||
pcb_mount_ring();
|
||||
|
||||
square([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly with fasteners
|
||||
|
154
printed/pocket_handle.scad
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Customisable pocket handle
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
function pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4) = //! Construct a pocket_handle property list
|
||||
[hand_size, slant, screw, panel_t, wall, rad];
|
||||
|
||||
function pocket_handle_hand_size(type) = type[0]; //! Size of the hole for the fingers
|
||||
function pocket_handle_slant(type) = type[1]; //! Upward slant of the hand hole
|
||||
function pocket_handle_screw(type) = type[2]; //! Screw type, can be countersunk or not
|
||||
function pocket_handle_panel_t(type) = type[3]; //! Thickness of the panel it is mounted in
|
||||
function pocket_handle_wall(type) = type[4]; //! Wall thickness
|
||||
function pocket_handle_rad(type) = type[5]; //! Min corner rad
|
||||
|
||||
function pocket_handle_flange(type) = //! Size of the flange
|
||||
let(w = pocket_handle_wall(type),
|
||||
f = washer_diameter(screw_washer(pocket_handle_screw(type))) + 2 + w,
|
||||
s = pocket_handle_hand_size(type))
|
||||
[s.x + 2 * f, s.y + 2 * f, w];
|
||||
|
||||
module pocket_handle_hole_positions(type) { //! Place children at screw hole positions
|
||||
f = pocket_handle_flange(type);
|
||||
h = pocket_handle_hand_size(type);
|
||||
x_pitch = (f.x + h.x) / 4;
|
||||
y_pitch = (f.y + h.y) / 4;
|
||||
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * x_pitch, y * y_pitch])
|
||||
children();
|
||||
}
|
||||
|
||||
module pocket_handle_holes(type, h = 0) { //! Panel cutout and screw holes
|
||||
hand = pocket_handle_hand_size(type);
|
||||
w = pocket_handle_wall(type);
|
||||
slot = [hand.x + 2 * w, hand.y + 2 * w];
|
||||
t = pocket_handle_panel_t(type);
|
||||
clearance = norm([slot.y, t]) - slot.y + 0.2; // has to be enough clearance for the diagonal to swing it in
|
||||
|
||||
extrude_if(h) {
|
||||
pocket_handle_hole_positions(type)
|
||||
drill(screw_clearance_radius(pocket_handle_screw(type)), 0);
|
||||
|
||||
rounded_square([slot.x + clearance, slot.y + clearance], pocket_handle_rad(type) + w + clearance / 2);
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle(type) { //! Generate STL for pocket_handle
|
||||
f = pocket_handle_flange(type);
|
||||
r = pocket_handle_rad(type);
|
||||
s = pocket_handle_slant(type);
|
||||
o = f.z * tan(s);
|
||||
h = pocket_handle_hand_size(type);
|
||||
t = pocket_handle_panel_t(type);
|
||||
w = pocket_handle_wall(type);
|
||||
screw = pocket_handle_screw(type) ;
|
||||
|
||||
stl("pocket_handle")
|
||||
union() {
|
||||
difference() {
|
||||
hull() {
|
||||
rounded_rectangle(f, r);
|
||||
|
||||
translate_z(f.z - eps)
|
||||
rounded_rectangle([f.x + 2 * o, f.y + 2 * o, eps], r + o);
|
||||
}
|
||||
hull() {
|
||||
rounded_rectangle([h.x, h.y, f.z + eps], r);
|
||||
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x + 2 * o, h.y + 2 * o, eps], r + o);
|
||||
}
|
||||
pocket_handle_hole_positions(type) {
|
||||
if(screw_head_height(screw))
|
||||
translate_z(-eps)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = f.z + 2 * eps, center = false);
|
||||
else
|
||||
screw_polysink(screw, h = 2 * f.z + eps, alt = true);
|
||||
}
|
||||
}
|
||||
|
||||
translate_z(f.z)
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
rounded_square([h.x + 2 * w, h.y + 2 * w], r + w);
|
||||
|
||||
rounded_square([h.x, h.y], r);
|
||||
}
|
||||
|
||||
translate_z(f.z + t)
|
||||
difference() {
|
||||
height = h.z - f.z - t;
|
||||
hull() {
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
|
||||
translate((height + w) * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
}
|
||||
|
||||
hull() {
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
|
||||
translate(height * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle_assembly(type) { //! Assembly with fasteners in place
|
||||
f = pocket_handle_flange(type);
|
||||
screw = pocket_handle_screw(type);
|
||||
nut = screw_nut(screw);
|
||||
t = pocket_handle_panel_t(type);
|
||||
washers = screw_head_height(screw) ? 2 : 1;
|
||||
screw_length = screw_length(screw, f.z + t, washers, nyloc = true);
|
||||
|
||||
translate_z(f.z + t / 2) hflip() {
|
||||
stl_colour(pp1_colour)
|
||||
pocket_handle(type);
|
||||
|
||||
pocket_handle_hole_positions(type) {
|
||||
translate_z(f.z + t)
|
||||
explode(15, true)
|
||||
nut_and_washer(nut, true);
|
||||
|
||||
vflip()
|
||||
if(washers == 2)
|
||||
screw_and_washer(screw, screw_length);
|
||||
else
|
||||
screw(screw, screw_length);
|
||||
}
|
||||
}
|
||||
}
|
@@ -129,28 +129,27 @@ module pbox_outer_shape(type) //! 2D outer shape of the box
|
||||
offset(pbox_wall(type) / 2) pbox_mid_shape(type);
|
||||
|
||||
module pbox_base(type) { //! Generate the STL for the base
|
||||
stl(str(pbox_name(type),"_base"));
|
||||
t = pbox_base(type);
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
offset(base_outset - 0.2)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
stl(str(pbox_name(type),"_base"))
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(t)
|
||||
offset(base_outset - 0.2)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
|
||||
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
poly_cylinder(r = screw_clearance_radius(pbox_screw(type)), h = 2 * t + eps, center = true);
|
||||
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
}
|
||||
|
||||
module pbox(type) { //! Generate the STL for the main case
|
||||
stl(pbox_name(type));
|
||||
|
||||
height = pbox_height(type);
|
||||
total_height = pbox_total_height(type);
|
||||
top_thickness = pbox_top(type);
|
||||
@@ -159,60 +158,61 @@ module pbox(type) { //! Generate the STL for the main case
|
||||
ledge_inset = base_outset - base_overlap;
|
||||
ledge_h = pbox_base(type) ? (ledge_outset - ledge_inset) * 2 : 0;
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(total_height)
|
||||
pbox_outer_shape(type);
|
||||
|
||||
if($children > 2)
|
||||
children(2);
|
||||
}
|
||||
stl(pbox_name(type))
|
||||
difference() {
|
||||
translate_z(top_thickness)
|
||||
union() {
|
||||
linear_extrude(height + eps)
|
||||
offset(-wall / 2) pbox_mid_shape(type);
|
||||
union() {
|
||||
linear_extrude(total_height)
|
||||
pbox_outer_shape(type);
|
||||
|
||||
translate_z(height) // Recess for the base
|
||||
linear_extrude(total_height - height)
|
||||
offset(base_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
// Ledge to support the lid
|
||||
if(ledge_h)
|
||||
translate_z(top_thickness + height - ledge_h)
|
||||
difference() {
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1, center = false);
|
||||
if($children > 2)
|
||||
children(2);
|
||||
}
|
||||
difference() {
|
||||
translate_z(top_thickness)
|
||||
union() {
|
||||
linear_extrude(height + eps)
|
||||
offset(-wall / 2) pbox_mid_shape(type);
|
||||
|
||||
hull() {
|
||||
linear_extrude(ledge_h + eps)
|
||||
offset(ledge_inset)
|
||||
translate_z(height) // Recess for the base
|
||||
linear_extrude(total_height - height)
|
||||
offset(base_outset)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
linear_extrude(eps)
|
||||
offset(ledge_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
insert_hole(pbox_insert(type));
|
||||
}
|
||||
// Ledge to support the lid
|
||||
if(ledge_h)
|
||||
translate_z(top_thickness + height - ledge_h)
|
||||
difference() {
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1);
|
||||
|
||||
// Corner lugs for inserts
|
||||
outset = wall + pbox_ridges(type).y;
|
||||
or = pbox_radius(type) + outset;
|
||||
inset = pbox_screw_inset(type) + outset;
|
||||
br = insert_boss_radius(pbox_insert(type), wall);
|
||||
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
|
||||
translate_z(height + top_thickness)
|
||||
pbox_screw_positions(type)
|
||||
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
|
||||
hull() {
|
||||
linear_extrude(ledge_h + eps)
|
||||
offset(ledge_inset)
|
||||
pbox_inner_shape(type);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
linear_extrude(eps)
|
||||
offset(ledge_outset)
|
||||
pbox_inner_shape(type);
|
||||
}
|
||||
pbox_screw_positions(type)
|
||||
insert_hole(pbox_insert(type));
|
||||
}
|
||||
|
||||
// Corner lugs for inserts
|
||||
outset = wall + pbox_ridges(type).y;
|
||||
or = pbox_radius(type) + outset;
|
||||
inset = pbox_screw_inset(type) + outset;
|
||||
br = insert_boss_radius(pbox_insert(type), wall);
|
||||
ext = sqrt(2) * inset - or * (sqrt(2) - 1) - br;
|
||||
translate_z(height + top_thickness)
|
||||
pbox_screw_positions(type)
|
||||
insert_lug(pbox_insert(type), wall, counter_bore = 0, extension = ext, corner_r = or);
|
||||
|
||||
if($children > 0)
|
||||
children(0);
|
||||
}
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
if($children > 1)
|
||||
children(1);
|
||||
}
|
||||
}
|
||||
|
||||
module pbox_inserts(type) //! Place the inserts for the base screws
|
||||
|
@@ -21,8 +21,8 @@
|
||||
//! Creative Commons - Attribution - Share Alike license (see <https://creativecommons.org/licenses/by-sa/3.0/>)
|
||||
//
|
||||
|
||||
include <NopSCADlib/core.scad>
|
||||
include <NopSCADlib/vitamins/pulleys.scad>
|
||||
include <../core.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
|
||||
printed_pulley_GT2_profile = [[0.747183,-0.5],[0.747183,0],[0.647876,0.037218],[0.598311,0.130528],[0.578556,0.238423],[0.547158,0.343077],[0.504649,0.443762],[0.451556,0.53975],[0.358229,0.636924],[0.2484,0.707276],[0.127259,0.750044],[0,0.76447],[-0.127259,0.750044],[-0.2484,0.707276],[-0.358229,0.636924],[-0.451556,0.53975],[-0.504797,0.443762],[-0.547291,0.343077],[-0.578605,0.238423],[-0.598311,0.130528],[-0.648009,0.037218],[-0.747183,0],[-0.747183,-0.5]];
|
||||
|
||||
@@ -93,7 +93,6 @@ module printed_pulley(type) { //! Draw a printable pulley
|
||||
or = pulley_od(type) / 2;
|
||||
screw_z = pulley_screw_z(type);
|
||||
|
||||
stl(str("printed_pulley_", type[0]));
|
||||
|
||||
module core() {
|
||||
translate_z(pulley_hub_length(type) + ft)
|
||||
@@ -129,58 +128,59 @@ module printed_pulley(type) { //! Draw a printable pulley
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? - hl : 0) {
|
||||
// hub
|
||||
if(hl)
|
||||
translate_z(printed_pulley_inverted(type) ? hl + w + 2 * ft : 0)
|
||||
if(screw_z && screw_z < hl)
|
||||
render()
|
||||
difference() {
|
||||
hub();
|
||||
stl(str("printed_pulley_", type[0]))
|
||||
translate_z(printed_pulley_inverted(type) ? - hl : 0) {
|
||||
// hub
|
||||
if(hl)
|
||||
translate_z(printed_pulley_inverted(type) ? hl + w + 2 * ft : 0)
|
||||
if(screw_z && screw_z < hl)
|
||||
render()
|
||||
difference() {
|
||||
hub();
|
||||
|
||||
screw_holes();
|
||||
}
|
||||
else
|
||||
hub();
|
||||
|
||||
// bottom flange
|
||||
translate_z(hl)
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(d = pulley_flange_dia(type));
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
// top flange
|
||||
translate_z(hl + ft + w) {
|
||||
// inner part, supported by core
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(r = or);
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
// outer part at 45 degrees for printing
|
||||
rotate_extrude()
|
||||
translate([or - eps, ft])
|
||||
vflip()
|
||||
right_triangle(ft, ft);
|
||||
}
|
||||
|
||||
if(screw_z && screw_z > hl)
|
||||
render()
|
||||
difference() { // T5 pulleys have screws through the teeth
|
||||
core();
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? pulley_height(type) + hl - 2 * screw_z : 0)
|
||||
screw_holes();
|
||||
}
|
||||
}
|
||||
else
|
||||
hub();
|
||||
|
||||
// bottom flange
|
||||
translate_z(hl)
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(d = pulley_flange_dia(type));
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
|
||||
// top flange
|
||||
translate_z(hl + ft + w) {
|
||||
// inner part, supported by core
|
||||
linear_extrude(ft)
|
||||
difference() {
|
||||
circle(r = or);
|
||||
circle(d = pulley_bore(type));
|
||||
}
|
||||
// outer part at 45 degrees for printing
|
||||
rotate_extrude()
|
||||
translate([or - eps, ft])
|
||||
vflip()
|
||||
right_triangle(ft, ft);
|
||||
}
|
||||
|
||||
if(screw_z && screw_z > hl)
|
||||
render()
|
||||
difference() { // T5 pulleys have screws through the teeth
|
||||
core();
|
||||
|
||||
translate_z(printed_pulley_inverted(type) ? pulley_height(type) + hl - 2 * screw_z : 0)
|
||||
screw_holes();
|
||||
}
|
||||
else
|
||||
core();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module printed_pulley_assembly(type, colour = pp1_colour) //! Draw a printed pulley with its grub screws in place
|
||||
assembly(str("printed_pulley_", type[0])) {
|
||||
assembly(str("printed_pulley_", type[0]), ngb = true) {
|
||||
translate_z(pulley_offset(type)) {
|
||||
stl_colour(colour)
|
||||
if(printed_pulley_inverted(type))
|
||||
|
@@ -79,8 +79,6 @@ module psu_shroud_holes(type, cable_d, cables = 1) {
|
||||
}
|
||||
|
||||
module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file for a specified ssr and cable
|
||||
stl(str("psu_shroud_", name));
|
||||
|
||||
extent = psu_shroud_extent(type);
|
||||
depth = psu_shroud_depth(type);
|
||||
width = psu_shroud_width(type);
|
||||
@@ -109,41 +107,43 @@ module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file f
|
||||
}
|
||||
}
|
||||
|
||||
// base and sides
|
||||
translate([centre_x, -centre_y]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
stl(str("psu_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([centre_x, -centre_y]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
linear_extrude(height)
|
||||
difference() {
|
||||
linear_extrude(height)
|
||||
difference() {
|
||||
shape();
|
||||
|
||||
translate([depth / 2, width / 2 - 5])
|
||||
square([2 * (depth - extent + terminal_clearance), 10], center = true);
|
||||
}
|
||||
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
|
||||
shape();
|
||||
|
||||
translate([depth / 2, width / 2 - 5])
|
||||
square([2 * (depth - extent + terminal_clearance), 10], center = true);
|
||||
}
|
||||
linear_extrude(height - terminal_block_height(tb) - psu_terminal_block_z(type) - terminal_clearance)
|
||||
shape();
|
||||
}
|
||||
// cable slots
|
||||
for(i = [0 : 1 : cables - 1])
|
||||
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
|
||||
rotate([90, 0, 90])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
// cable slots
|
||||
for(i = [0 : 1 : cables - 1])
|
||||
translate([centre_x - depth / 2 + wall / 2, -centre_y + (i - cables / 2 + 0.5) * psu_shroud_cable_pitch(cable_d), height / 2])
|
||||
rotate([90, 0, 90])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert lugs
|
||||
mirror([0, 1, 0])
|
||||
psu_shroud_hole_positions(type)
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert lugs
|
||||
mirror([0, 1, 0])
|
||||
psu_shroud_hole_positions(type)
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
}
|
||||
|
||||
module psu_shroud_assembly(type, cable_d, name, cables = 1) //! The printed parts with inserts fitted
|
||||
assembly(str("PSU_shroud_", name)) {
|
||||
assembly(str("PSU_shroud_", name), ngb = true) {
|
||||
|
||||
translate_z(psu_shroud_height(type))
|
||||
vflip()
|
||||
|
@@ -47,7 +47,6 @@ module ribbon_clamp_holes(ways, h = 20, screw = screw) //! Drill screw holes
|
||||
|
||||
module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of ways
|
||||
screw_d = screw_radius(screw) * 2;
|
||||
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""));
|
||||
|
||||
pitch = ribbon_clamp_hole_pitch(ways, screw);
|
||||
d = ribbon_clamp_width(screw);
|
||||
@@ -55,34 +54,35 @@ module ribbon_clamp(ways, screw = screw) { //! Generate STL for given number of
|
||||
t = round_to_layer(ribbon_clamp_slot_depth() + wall);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
translate_z(h - t / 2)
|
||||
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
|
||||
stl(str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""))
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
translate_z(h - t / 2)
|
||||
cube([ribbon_clamp_hole_pitch(ways, screw), d, t], center = true);
|
||||
|
||||
translate_z(1)
|
||||
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
|
||||
translate_z(1)
|
||||
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
|
||||
}
|
||||
ribbon_clamp_hole_positions(ways, screw, -1)
|
||||
cylinder(d = d, h = h);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw, 1)
|
||||
cylinder(d = d, h = h);
|
||||
}
|
||||
ribbon_clamp_hole_positions(ways, screw, -1)
|
||||
cylinder(d = d, h = h);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw, 1)
|
||||
cylinder(d = d, h = h);
|
||||
}
|
||||
|
||||
translate_z(h)
|
||||
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
translate_z(h)
|
||||
rotate(22.5)
|
||||
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
|
||||
}
|
||||
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
|
||||
|
||||
ribbon_clamp_hole_positions(ways, screw)
|
||||
translate_z(h)
|
||||
rotate(22.5)
|
||||
insert_hole(insert, ribbon_clamp_screw_depth(screw) - insert_length(insert));
|
||||
}
|
||||
}
|
||||
|
||||
module ribbon_clamp_assembly(ways, screw = screw) pose([55, 180, 25]) //! Printed part with inserts in place
|
||||
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : "")) {
|
||||
assembly(let(screw_d = screw_radius(screw) * 2)str("ribbon_clamp_", ways, screw_d != 3 ? str("_", screw_d) : ""), ngb = true) {
|
||||
h = ribbon_clamp_height(screw);
|
||||
insert = screw_insert(screw);
|
||||
|
||||
|
@@ -34,32 +34,31 @@ knob_height = knob_stem_h + knob_thickness;
|
||||
function knob_height() = knob_height;
|
||||
|
||||
module screw_knob(screw) { //! Generate the STL for a knob to fit the specified hex screw
|
||||
stl(str("screw_knob_M", screw_radius(screw) * 20));
|
||||
|
||||
knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;
|
||||
|
||||
function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;
|
||||
|
||||
union() {
|
||||
render() difference() {
|
||||
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
|
||||
stl(str("screw_knob_M", screw_radius(screw) * 20))
|
||||
union() {
|
||||
render() difference() {
|
||||
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
|
||||
|
||||
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
|
||||
rotate(45)
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
linear_extrude(knob_thickness, convexity = 3)
|
||||
difference() {
|
||||
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
|
||||
|
||||
circle(knob_stem_r - eps);
|
||||
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
|
||||
rotate(45)
|
||||
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
|
||||
}
|
||||
}
|
||||
linear_extrude(knob_thickness, convexity = 3)
|
||||
difference() {
|
||||
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
|
||||
|
||||
circle(knob_stem_r - eps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Place the screw through the printed part
|
||||
module screw_knob_assembly(screw, length) //! Assembly with the screw in place
|
||||
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length)) {
|
||||
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length), ngb = true) {
|
||||
translate_z(knob_height)
|
||||
vflip()
|
||||
stl_colour(pp1_colour) screw_knob(screw);
|
||||
|
@@ -41,7 +41,6 @@ height = base_thickness + box_height;
|
||||
function socket_box_depth() = height; //! Outside depth of the backbox
|
||||
|
||||
module socket_box(type) { //! Generate STL of the backbox for the specified socket
|
||||
stl(str("socket_box_",type[0]));
|
||||
|
||||
screw = mains_socket_screw(type);
|
||||
screw_clearance_radius = screw_clearance_radius(screw);
|
||||
@@ -51,37 +50,38 @@ module socket_box(type) { //! Generate STL of the backbox for the specified sock
|
||||
insert_boss = mains_socket_insert_boss(type);
|
||||
insert_hole_radius = insert_hole_radius(insert);
|
||||
|
||||
difference() {
|
||||
linear_extrude(height, convexity = 5)
|
||||
face_plate(type);
|
||||
|
||||
stl(str("socket_box_",type[0]))
|
||||
difference() {
|
||||
translate_z(base_thickness)
|
||||
linear_extrude(height, convexity = 5)
|
||||
offset(-wall) offset(1) face_plate(type);
|
||||
linear_extrude(height, convexity = 5)
|
||||
face_plate(type);
|
||||
|
||||
for(side = [-1, 1])
|
||||
hull()
|
||||
for(x = [1, 2])
|
||||
translate([side * mains_socket_pitch(type) / x, 0])
|
||||
cylinder(d = insert_boss, h = 100);
|
||||
}
|
||||
//
|
||||
// Socket holes
|
||||
//
|
||||
translate_z(height)
|
||||
mains_socket_hole_positions(type) {
|
||||
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
|
||||
difference() {
|
||||
translate_z(base_thickness)
|
||||
linear_extrude(height, convexity = 5)
|
||||
offset(-wall) offset(1) face_plate(type);
|
||||
|
||||
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
|
||||
for(side = [-1, 1])
|
||||
hull()
|
||||
for(x = [1, 2])
|
||||
translate([side * mains_socket_pitch(type) / x, 0])
|
||||
cylinder(d = insert_boss, h = 100);
|
||||
}
|
||||
//
|
||||
// Cable hole
|
||||
//
|
||||
translate([cable_x, cable_y(type), cable_z])
|
||||
rotate([90, 0, 0])
|
||||
teardrop_plus(r = cable_d / 2, h = 30);
|
||||
}
|
||||
//
|
||||
// Socket holes
|
||||
//
|
||||
translate_z(height)
|
||||
mains_socket_hole_positions(type) {
|
||||
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
|
||||
|
||||
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
|
||||
}
|
||||
//
|
||||
// Cable hole
|
||||
//
|
||||
translate([cable_x, cable_y(type), cable_z])
|
||||
rotate([90, 0, 0])
|
||||
teardrop_plus(r = cable_d / 2, h = 30);
|
||||
}
|
||||
}
|
||||
|
||||
module socket_box_MKLOGIC_stl() socket_box(MKLOGIC);
|
||||
|
@@ -61,53 +61,54 @@ module ssr_shroud_holes(type, cable_d) { //! Drill the screw and ziptie holes
|
||||
}
|
||||
|
||||
module ssr_shroud(type, cable_d, name) { //! Generate the STL file for a specified ssr and cable
|
||||
stl(str("ssr_shroud_", name));
|
||||
|
||||
width = ssr_shroud_width(type);
|
||||
depth = ssr_length(type) / 3 + ssr_shroud_extent(type, cable_d);
|
||||
height = ssr_shroud_height(type);
|
||||
cable_x = ssr_shroud_cable_x(type, cable_d);
|
||||
center_x = -ssr_length(type) / 6 - depth / 2;
|
||||
|
||||
// base and sides
|
||||
translate([center_x, 0]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
|
||||
linear_extrude(height) difference() {
|
||||
round(or = wall / 2 - eps, ir = 0) difference() {
|
||||
rounded_square([depth, width], rad);
|
||||
stl(str("ssr_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([center_x, 0]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
|
||||
linear_extrude(height) difference() {
|
||||
round(or = wall / 2 - eps, ir = 0) difference() {
|
||||
rounded_square([depth, width], rad);
|
||||
|
||||
translate([depth / 2, 0])
|
||||
square([2 * rad, width], center = true);
|
||||
rounded_square([depth - 2 * wall, width - 2 * wall], rad - wall);
|
||||
|
||||
translate([depth / 2, 0])
|
||||
square([2 * rad, width], center = true);
|
||||
|
||||
}
|
||||
translate([cable_x - center_x, 0])
|
||||
square([cable_d, width + 1], center = true);
|
||||
}
|
||||
translate([cable_x - center_x, 0])
|
||||
square([cable_d, width + 1], center = true);
|
||||
}
|
||||
}
|
||||
// cable slots
|
||||
for(side = [-1, 1])
|
||||
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
// cable slots
|
||||
for(side = [-1, 1])
|
||||
translate([cable_x, side * (width / 2 - wall / 2), height / 2])
|
||||
rotate([90, 0, 0])
|
||||
linear_extrude(wall, center = true)
|
||||
difference() {
|
||||
square([cable_d + eps, height], center = true);
|
||||
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert boss
|
||||
ssr_shroud_hole_positions(type)
|
||||
vflip()
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
translate([0, height / 2])
|
||||
vertical_tearslot(h = 0, r = cable_d / 2, l = cable_d);
|
||||
}
|
||||
// insert boss
|
||||
ssr_shroud_hole_positions(type)
|
||||
vflip()
|
||||
translate_z(height)
|
||||
rotate($side * 90)
|
||||
insert_lug(insert, wall, counter_bore);
|
||||
}
|
||||
}
|
||||
|
||||
module ssr_shroud_assembly(type, cable_d, name) //! The printed parts with inserts fitted
|
||||
assembly(str("SSR_shroud_", name)) {
|
||||
assembly(str("SSR_shroud_", name), ngb = true) {
|
||||
|
||||
translate_z(ssr_shroud_height(type))
|
||||
vflip()
|
||||
|
@@ -75,32 +75,29 @@ module strap_holes(length, type = strap, h = 100) //! The panel cut outs
|
||||
strap_boss_shape(type);
|
||||
|
||||
module strap(length, type = strap) { //! Generate the STL for the rubber strap
|
||||
stl("strap");
|
||||
|
||||
len = length - 2 * (wall + clearance);
|
||||
w = strap_width(type);
|
||||
|
||||
linear_extrude(strap_thickness(type), convexity = 3)
|
||||
difference() {
|
||||
rounded_square([len, w], w / 2 - eps);
|
||||
stl("strap")
|
||||
linear_extrude(strap_thickness(type), convexity = 3)
|
||||
difference() {
|
||||
rounded_square([len, w], w / 2 - eps);
|
||||
|
||||
for(end = [-1, 1])
|
||||
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
|
||||
rotate(end * 90 + 90)
|
||||
hull() {
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
|
||||
translate([strap_extension(type) / 2, 0])
|
||||
for(end = [-1, 1])
|
||||
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
|
||||
rotate(end * 90 + 90)
|
||||
hull() {
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
}
|
||||
}
|
||||
|
||||
translate([strap_extension(type) / 2, 0])
|
||||
offset(clearance)
|
||||
strap_boss_shape(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module strap_end(type = strap) { //! Generate the STL for end piece
|
||||
stl("strap_end");
|
||||
|
||||
z1 = strap_height(type) - strap_thickness(type) - clearance;
|
||||
z2 = strap_height(type) + strap_key(type);
|
||||
r1 = strap_boss_r(type) - 1;
|
||||
@@ -121,48 +118,49 @@ module strap_end(type = strap) { //! Generate the STL for end piece
|
||||
circle(r1);
|
||||
}
|
||||
|
||||
union() {
|
||||
linear_extrude(z1)
|
||||
with_hole()
|
||||
outer();
|
||||
|
||||
translate_z(z1)
|
||||
linear_extrude(strap_height(type) - z1)
|
||||
difference() {
|
||||
stl("strap_end")
|
||||
union() {
|
||||
linear_extrude(z1)
|
||||
with_hole()
|
||||
outer();
|
||||
|
||||
hull() {
|
||||
translate([0, -strap_width(type) / 2 - clearance])
|
||||
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
|
||||
translate_z(z1)
|
||||
linear_extrude(strap_height(type) - z1)
|
||||
difference() {
|
||||
outer();
|
||||
|
||||
translate([-strap_extension(type) / 2, 0])
|
||||
circle(d = strap_width(type) + 2 * clearance);
|
||||
hull() {
|
||||
translate([0, -strap_width(type) / 2 - clearance])
|
||||
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
|
||||
|
||||
translate([-strap_extension(type) / 2, 0])
|
||||
circle(d = strap_width(type) + 2 * clearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linear_extrude(strap_height(type) - layer_height)
|
||||
with_hole()
|
||||
strap_boss_shape(type);
|
||||
linear_extrude(strap_height(type) - layer_height)
|
||||
with_hole()
|
||||
strap_boss_shape(type);
|
||||
|
||||
linear_extrude(z2)
|
||||
with_hole()
|
||||
offset(cnc_bit_r)
|
||||
offset(-step - cnc_bit_r)
|
||||
strap_boss_shape(type);
|
||||
linear_extrude(z2)
|
||||
with_hole()
|
||||
offset(cnc_bit_r)
|
||||
offset(-step - cnc_bit_r)
|
||||
strap_boss_shape(type);
|
||||
|
||||
render() difference() {
|
||||
cylinder(r = r1 + eps, h = z2);
|
||||
render() difference() {
|
||||
cylinder(r = r1 + eps, h = z2);
|
||||
|
||||
translate_z(z2)
|
||||
insert_hole(strap_insert(type), counterbore);
|
||||
translate_z(z2)
|
||||
insert_hole(strap_insert(type), counterbore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//! * Place the insert into the hole and push home with a soldering iron with a tapered bit heated to 200°C.
|
||||
//
|
||||
module strap_end_assembly(type = strap)
|
||||
assembly("strap_end") {
|
||||
assembly("strap_end", ngb = true) {
|
||||
stl_colour(pp1_colour)
|
||||
strap_end(type);
|
||||
|
||||
|
285
readme.md
@@ -14,6 +14,8 @@ The license is GNU General Public License v3.0, see [COPYING](COPYING).
|
||||
|
||||
See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
|
||||
A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
<img src="libtest.png" width="100%"/>
|
||||
|
||||
## Table of Contents<a name="top"/>
|
||||
@@ -22,28 +24,28 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
|
||||
<tr><td> <a href = "#Axials">Axials</a> </td><td> <a href = "#Jack">Jack</a> </td><td> <a href = "#Rails">Rails</a> </td><td> <a href = "#Box">Box</a> </td><td> <a href = "#Annotation">Annotation</a> </td><td> <a href = "#BOM">BOM</a> </td></tr>
|
||||
<tr><td> <a href = "#Ball_bearings">Ball_bearings</a> </td><td> <a href = "#KP_pillow_blocks">KP_pillow_blocks</a> </td><td> <a href = "#Ring_terminals">Ring_terminals</a> </td><td> <a href = "#Butt_box">Butt_box</a> </td><td> <a href = "#Bezier">Bezier</a> </td><td> <a href = "#Clip">Clip</a> </td></tr>
|
||||
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Catenary">Catenary</a> </td><td> <a href = "#Global">Global</a> </td></tr>
|
||||
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
|
||||
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
|
||||
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
|
||||
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
|
||||
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_right_triangle">Rounded_right_triangle</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Inserts">Inserts</a> </td><td></td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td> <a href = "#Zipties">Zipties</a> </td><td></td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Core_xy">Core_xy</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
|
||||
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
|
||||
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
|
||||
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
|
||||
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Pocket_handle">Pocket_handle</a> </td><td> <a href = "#Rounded_right_triangle">Rounded_right_triangle</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Inserts">Inserts</a> </td><td></td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td> <a href = "#Zipties">Zipties</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
@@ -288,6 +290,8 @@ Models of radial blowers.
|
||||
| `blower_screw_holes(type)` | List of XY coordinates of the screw holes |
|
||||
| `blower_top(type)` | Thickness of the top |
|
||||
| `blower_wall(type)` | Side wall thickness |
|
||||
| `blower_wall_left(type)` | Left side wall thickness |
|
||||
| `blower_wall_right(type)` | Right wall thickness (for square fans) |
|
||||
| `blower_width(type)` | Width of enclosing rectangle |
|
||||
|
||||
### Functions
|
||||
@@ -311,10 +315,12 @@ Models of radial blowers.
|
||||
| 1 | `blower(PE4020)` | Blower Pengda Technology 4020 |
|
||||
| 1 | `blower(RB5015)` | Blower Runda RB5015 |
|
||||
| 4 | `screw(M2_cap_screw, 8)` | Screw M2 cap x 8mm |
|
||||
| 2 | `screw(M2_cap_screw, 10)` | Screw M2 cap x 10mm |
|
||||
| 3 | `screw(M3_cap_screw, 20)` | Screw M3 cap x 20mm |
|
||||
| 2 | `screw(M4_cap_screw, 25)` | Screw M4 cap x 25mm |
|
||||
| 1 | `blower(BL30x10)` | Square radial fan 3010 |
|
||||
| 1 | `blower(BL40x10)` | Square radial fan 4010 |
|
||||
| 4 | `washer(M2_washer)` | Washer M2 x 5mm x 0.3mm |
|
||||
| 6 | `washer(M2_washer)` | Washer M2 x 5mm x 0.3mm |
|
||||
| 3 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
|
||||
| 2 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
|
||||
|
||||
@@ -1750,7 +1756,11 @@ UK 13A sockets at the moment.
|
||||
---
|
||||
<a name="Microswitches"></a>
|
||||
## Microswitches
|
||||
Used for limit switches.
|
||||
Used for limit switches. Currently only the button type is supported as the lever and roller types are less accurate.
|
||||
|
||||
The switch is drawn with the button at the nominal operation point. This can be plus or minus `microswitch_op_tol(type)`.
|
||||
|
||||
When the button is released it comes out by a maximum of `microswitch_fp_max(type)` from the nominal operating point.
|
||||
|
||||
[vitamins/microswitches.scad](vitamins/microswitches.scad) Object definitions.
|
||||
|
||||
@@ -1763,14 +1773,16 @@ Used for limit switches.
|
||||
|:--- |:--- |
|
||||
| `microswitch_body_clr(type)` | Body colour |
|
||||
| `microswitch_button_clr(type)` | Button colour |
|
||||
| `microswitch_button_pos(type)` | Button position |
|
||||
| `microswitch_button_pos(type)` | Button position at operating point |
|
||||
| `microswitch_button_t(type)` | Button thickness |
|
||||
| `microswitch_button_w(type)` | Button width |
|
||||
| `microswitch_fp_max(type)` | Free position maximum |
|
||||
| `microswitch_hole_d(type)` | Screw hole diameter |
|
||||
| `microswitch_holes(type)` | Hole positions |
|
||||
| `microswitch_leg(type)` | Leg types |
|
||||
| `microswitch_legs(type)` | Leg positions |
|
||||
| `microswitch_length(type)` | Body length |
|
||||
| `microswitch_op_tol(type)` | Operating position +/- tolerance |
|
||||
| `microswitch_radius(type)` | Body corner radius |
|
||||
| `microswitch_thickness(type)` | Body thickness |
|
||||
| `microswitch_width(type)` | Body width |
|
||||
@@ -2305,26 +2317,31 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
|
||||
| ---:|:--- |:---|
|
||||
| 1 | `pcb(ArduinoLeonardo)` | Arduino Leonardo |
|
||||
| 1 | `pcb(ArduinoUno3)` | Arduino Uno R3 |
|
||||
| 1 | `pcb(BTT_SKR_E3_TURBO)` | BigTreeTech SKR E3 Turbo |
|
||||
| 1 | `pcb(BTT_SKR_MINI_E3_V2_0)` | BigTreeTech SKR Mini E3 v2.0 |
|
||||
| 1 | `pcb(BTT_SKR_V1_4_TURBO)` | BigTreeTech SKR v1.4 Turbo |
|
||||
| 1 | | Cat 5 patch cable 300mm |
|
||||
| 1 | `d_plug(DCONN15, pcb = true)` | D-type 15 way PCB mount plug |
|
||||
| 1 | `pcb(DuetE)` | Duet 2 Ethernet electronics |
|
||||
| 1 | `pcb(Duex2)` | Duex2 expansion board |
|
||||
| 1 | `pcb(Duex2)` | Duex2 expansion board - not shown |
|
||||
| 1 | `pcb(Duex5)` | Duex5 expansion board |
|
||||
| 1 | `pcb(ESP-01)` | ESP-01 |
|
||||
| 1 | `pcb(EnviroPlus)` | Enviro+ |
|
||||
| 1 | `pcb(ExtruderPCB)` | Extruder connection PCB |
|
||||
| 1 | `pcb(Keyes5p1)` | Keyes5.1 Arduino Uno expansion board |
|
||||
| 1 | `pcb(Keyes5p1)` | Keyes5.1 Arduino Uno expansion board - not shown |
|
||||
| 1 | `pcb(MP1584EN)` | MP1584EN 3A buck converter |
|
||||
| 1 | `pcb(MT3608)` | MT3608 boost converter module |
|
||||
| 1 | `pcb(Melzi)` | Melzi electronics - not shown |
|
||||
| 4 | | Micro SD card |
|
||||
| 1 | | Micro SD card - not shown |
|
||||
| 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 |
|
||||
| 12 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
|
||||
| 12 | `nut(M4_nut, nyloc = true)` | Nut M4 x 3.2mm nyloc |
|
||||
| 30 | `nut(M2p5_nut, nyloc = true)` | Nut M2.5 x 2.2mm nyloc |
|
||||
| 22 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
|
||||
| 8 | `nut(M4_nut, nyloc = true)` | Nut M4 x 3.2mm nyloc |
|
||||
| 1 | `pcb(PI_IO)` | PI_IO V2 |
|
||||
| 1 | `pcb(PSU12V1A)` | PSU 12V 1A |
|
||||
| 1 | `pcb(PSU12V1A)` | PSU 12V 1A - not shown |
|
||||
| 1 | `pcb(PERF60x40)` | Perfboard 60 x 40mm |
|
||||
| 1 | `pcb(PERF70x30)` | Perfboard 70 x 30mm |
|
||||
| 1 | `pcb(PERF70x50)` | Perfboard 70 x 50mm |
|
||||
@@ -2341,18 +2358,19 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
|
||||
| 8 | `screw(M2p5_cap_screw, 25)` | Screw M2.5 cap x 25mm |
|
||||
| 8 | `screw(M2p5_cap_screw, 30)` | Screw M2.5 cap x 30mm |
|
||||
| 12 | `screw(M2p5_pan_screw, 25)` | Screw M2.5 pan x 25mm |
|
||||
| 4 | `screw(M2p5_pan_screw, 30)` | Screw M2.5 pan x 30mm |
|
||||
| 4 | `screw(M3_cap_screw, 16)` | Screw M3 cap x 16mm |
|
||||
| 8 | `screw(M3_cap_screw, 30)` | Screw M3 cap x 30mm |
|
||||
| 12 | `screw(M4_cap_screw, 35)` | Screw M4 cap x 35mm |
|
||||
| 9 | `screw(M3_cap_screw, 30)` | Screw M3 cap x 30mm |
|
||||
| 9 | `screw(M3_cap_screw, 35)` | Screw M3 cap x 35mm |
|
||||
| 8 | `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 - not shown |
|
||||
| 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 |
|
||||
| 12 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
|
||||
| 12 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
|
||||
| 30 | `washer(M2p5_washer)` | Washer M2.5 x 5.9mm x 0.5mm |
|
||||
| 22 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
|
||||
| 8 | `washer(M4_washer)` | Washer M4 x 9mm x 0.8mm |
|
||||
| 1 | `pcb(ZC_A0591)` | ZC-A0591 ULN2003 driver PCB |
|
||||
|
||||
### Printed
|
||||
@@ -2367,14 +2385,14 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o
|
||||
| 4 | pcb_spacer25140.stl |
|
||||
| 4 | pcb_spacer25150_2.stl |
|
||||
| 4 | pcb_spacer25160_2.stl |
|
||||
| 4 | pcb_spacer25170_2.stl |
|
||||
| 4 | pcb_spacer25200.stl |
|
||||
| 4 | pcb_spacer25210.stl |
|
||||
| 2 | pcb_spacer2590.stl |
|
||||
| 4 | pcb_spacer30180.stl |
|
||||
| 4 | pcb_spacer30190.stl |
|
||||
| 4 | pcb_spacer25180.stl |
|
||||
| 4 | pcb_spacer25190.stl |
|
||||
| 2 | pcb_spacer2580.stl |
|
||||
| 4 | pcb_spacer30170.stl |
|
||||
| 5 | pcb_spacer30200.stl |
|
||||
| 5 | pcb_spacer30210.stl |
|
||||
| 4 | pcb_spacer30220.stl |
|
||||
| 4 | pcb_spacer3050.stl |
|
||||
| 4 | pcb_spacer40220.stl |
|
||||
| 4 | pcb_spacer40230.stl |
|
||||
| 4 | pcb_spacer40240.stl |
|
||||
|
||||
@@ -2606,8 +2624,8 @@ Timing belt pulleys, both toothed and plain with internal bearings for idlers.
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `pulley(type)` | Draw a pulley |
|
||||
| `pulley_assembly(type)` | Draw a pulley with its grub screws in place |
|
||||
| `pulley(type, colour = silver)` | Draw a pulley |
|
||||
| `pulley_assembly(type, colour = silver)` | Draw a pulley with its grub screws in place |
|
||||
|
||||

|
||||
|
||||
@@ -2654,11 +2672,11 @@ Linear rails with carriages.
|
||||
| `carriage_length(type)` | Overall length |
|
||||
| `carriage_pitch_x(type)` | Screw hole x pitch |
|
||||
| `carriage_pitch_y(type)` | Screw hole y pitch |
|
||||
| `carriage_rail(type)` | Rail type |
|
||||
| `carriage_screw(type)` | Carriage screw type |
|
||||
| `carriage_width(type)` | Width of carriage |
|
||||
| `rail_bore(type)` | Counter bore diameter for screw head |
|
||||
| `rail_bore_depth(type)` | Counter bore depth |
|
||||
| `rail_carriage(type)` | Carriage type |
|
||||
| `rail_end(type)` | Minimum distance screw can be from the end |
|
||||
| `rail_end_screw(type)` | Screw used for ends only (Countersink used for better location) |
|
||||
| `rail_groove_offset(type)` | Offset of centre of groove from top of rail |
|
||||
@@ -2674,17 +2692,17 @@ Linear rails with carriages.
|
||||
|:--- |:--- |
|
||||
| `carriage_screw_depth(type)` | Carriage thread depth |
|
||||
| `carriage_size(type)` | Size of carriage |
|
||||
| `carriage_travel(type, rail_length)` | How far the carriage can travel on a given length rail |
|
||||
| `rail_holes(type, length)` | Number of holes in a rail given its `length` |
|
||||
| `rail_screw_height(type, screw)` | Position screw taking into account countersink into counterbored hole |
|
||||
| `rail_travel(type, length)` | How far the carriage can travel |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `carriage(type, rail, end_colour = grey(20)` | Draw the specified carriage |
|
||||
| `carriage(type, end_colour = grey(20)` | Draw the specified carriage |
|
||||
| `carriage_hole_positions(type)` | Position children over screw holes |
|
||||
| `rail(type, length, colour = grey(90)` | Draw the specified rail |
|
||||
| `rail_assembly(type, length, pos, carriage_end_colour = grey(20)` | Rail and carriage assembly |
|
||||
| `rail_assembly(carriage, length, pos, carriage_end_colour = grey(20)` | Rail and carriage assembly |
|
||||
| `rail_hole_positions(type, length, first = 0, screws = 100, both_ends = true)` | Position children over screw holes |
|
||||
| `rail_screws(type, length, thickness, screws = 100, index_screws = undef)` | Place screws in the rail |
|
||||
|
||||
@@ -2693,8 +2711,7 @@ Linear rails with carriages.
|
||||
### Vitamins
|
||||
| Qty | Module call | BOM entry |
|
||||
| ---:|:--- |:---|
|
||||
| 1 | `rail(MGN12, 200)` | Linear rail MGN12 x 200mm |
|
||||
| 1 | `rail(MGN12H, 200)` | Linear rail MGN12H x 200mm |
|
||||
| 2 | `rail(MGN12, 200)` | Linear rail MGN12 x 200mm |
|
||||
| 1 | `rail(MGN15, 200)` | Linear rail MGN15 x 200mm |
|
||||
| 1 | `rail(MGN5, 200)` | Linear rail MGN5 x 200mm |
|
||||
| 1 | `rail(MGN7, 200)` | Linear rail MGN7 x 200mm |
|
||||
@@ -2942,6 +2959,7 @@ For an explanation of `screw_polysink()` see <https://hydraraptor.blogspot.com/2
|
||||
| 1 | `screw(M4_pan_screw, 30)` | Screw M4 pan x 30mm |
|
||||
| 1 | `screw(M5_cap_screw, 30)` | Screw M5 cap x 30mm |
|
||||
| 1 | `screw(M5_cs_cap_screw, 30)` | Screw M5 cs cap x 30mm |
|
||||
| 1 | `screw(M5_dome_screw, 30)` | Screw M5 dome x 30mm |
|
||||
| 1 | `screw(M5_hex_screw, 30)` | Screw M5 hex x 30mm |
|
||||
| 1 | `screw(M5_pan_screw, 30)` | Screw M5 pan x 30mm |
|
||||
| 1 | `screw(M6_cap_screw, 30)` | Screw M6 cap x 30mm |
|
||||
@@ -3138,6 +3156,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
|
||||
| 1 | `sheet(FoilTape, 30, 30, 2)` | Aluminium foil tape 30mm x 30mm x 0.05mm |
|
||||
| 1 | `sheet(AL6, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 6mm |
|
||||
| 1 | `sheet(AL8, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 8mm |
|
||||
| 1 | `sheet(Spring05, 30, 30, 2)` | Bi-metal saw blade 30mm x 30mm x 0.5mm |
|
||||
| 1 | `sheet(Cardboard, 30, 30, 2)` | Corrugated cardboard 30mm x 30mm x 5mm |
|
||||
| 1 | `sheet(Foam20, 30, 30, 2)` | Foam sponge 30mm x 30mm x 20mm |
|
||||
| 1 | `sheet(DiBond, 30, 30, 2)` | Sheet DiBond 30mm x 30mm x 3mm |
|
||||
@@ -3156,6 +3175,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
|
||||
| 1 | `sheet(CF3, 30, 30, 2)` | Sheet carbon fiber 30mm x 30mm x 3mm |
|
||||
| 1 | `sheet(glass2, 30, 30, 2)` | Sheet glass 30mm x 30mm x 2mm |
|
||||
| 1 | `sheet(Steel06, 30, 30, 2)` | Sheet mild steel 30mm x 30mm x 0.6mm |
|
||||
| 1 | `sheet(Silicone3, 30, 30, 2)` | Sheet silicone 30mm x 30mm x 3mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -3796,7 +3816,7 @@ Veroboard with mounting holes, track breaks, removed tracks, solder points and c
|
||||
| `vero_mounting_hole_positions(type)` | Positions children at the mounting holes |
|
||||
| `vero_mounting_holes(type, h = 100)` | Drill mounting holes in a panel |
|
||||
| `veroboard(type)` | Draw specified veroboard with missing tracks and track breaks |
|
||||
| `veroboard_assembly(type, height, thickness, flip = false)` | Draw the assembly with components and fasteners in place |
|
||||
| `veroboard_assembly(type, height, thickness, flip = false, ngb = false)` | Draw the assembly with components and fasteners in place |
|
||||
|
||||

|
||||
|
||||
@@ -4940,6 +4960,56 @@ The stl must be given a parameterless wrapper in the project that uses it.
|
||||
| 1 | pcb_mount_PI_IO_5.stl |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
<a name="Pocket_handle"></a>
|
||||
## Pocket_handle
|
||||
Customisable pocket handle
|
||||
|
||||
[printed/pocket_handle.scad](printed/pocket_handle.scad) Implementation.
|
||||
|
||||
[tests/pocket_handle.scad](tests/pocket_handle.scad) Code for this example.
|
||||
|
||||
### Properties
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle_hand_size(type)` | Size of the hole for the fingers |
|
||||
| `pocket_handle_panel_t(type)` | Thickness of the panel it is mounted in |
|
||||
| `pocket_handle_rad(type)` | Min corner rad |
|
||||
| `pocket_handle_screw(type)` | Screw type, can be countersunk or not |
|
||||
| `pocket_handle_slant(type)` | Upward slant of the hand hole |
|
||||
| `pocket_handle_wall(type)` | Wall thickness |
|
||||
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4)` | Construct a pocket_handle property list |
|
||||
| `pocket_handle_flange(type)` | Size of the flange |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle(type)` | Generate STL for pocket_handle |
|
||||
| `pocket_handle_assembly(type)` | Assembly with fasteners in place |
|
||||
| `pocket_handle_hole_positions(type)` | Place children at screw hole positions |
|
||||
| `pocket_handle_holes(type, h = 0)` | Panel cutout and screw holes |
|
||||
|
||||

|
||||
|
||||
### Vitamins
|
||||
| Qty | Module call | BOM entry |
|
||||
| ---:|:--- |:---|
|
||||
| 4 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
|
||||
| 4 | `screw(M3_cs_cap_screw, 12)` | Screw M3 cs cap x 12mm |
|
||||
| 4 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
|
||||
|
||||
### Printed
|
||||
| Qty | Filename |
|
||||
| ---:|:--- |
|
||||
| 1 | pocket_handle.stl |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
@@ -5504,6 +5574,69 @@ The coordinates of the lowest point on the curve can be retrieved by calling `ca
|
||||

|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
<a name="Core_xy"></a>
|
||||
## Core_xy
|
||||
Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
|
||||
|
||||
The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
|
||||
Implementation has the following features:
|
||||
1. The drive and idler pulleys may be different sizes.
|
||||
2. The belt separation is parameterised.
|
||||
3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
|
||||
4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
|
||||
allows flexible positioning of the motors.
|
||||
|
||||
[utils/core_xy.scad](utils/core_xy.scad) Implementation.
|
||||
|
||||
[tests/core_xy.scad](tests/core_xy.scad) Code for this example.
|
||||
|
||||
### Properties
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY_belt(type)` | Belt type |
|
||||
| `coreXY_drive_pulley(type)` | Drive pulley type |
|
||||
| `coreXY_lower_belt_colour(type)` | Colour of the lower belt |
|
||||
| `coreXY_lower_tooth_colour(type)` | Colour of the lower belt's teeth |
|
||||
| `coreXY_plain_idler(type)` | Plain idler type |
|
||||
| `coreXY_toothed_idler(type)` | Toothed idler type |
|
||||
| `coreXY_upper_belt_colour(type)` | Colour of the upper belt |
|
||||
| `coreXY_upper_tooth_colour(type)` | Colour of the upper belt's teeth |
|
||||
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY_coincident_separation(type)` | Value of x, y separation to make y-carriage pulleys coincident |
|
||||
| `coreXY_drive_plain_idler_offset(type)` | Offset of plain drive idler pulley |
|
||||
| `coreXY_drive_pulley_x_alignment(type)` | Belt alignment offset of the drive pulley relative to the anchor pulley |
|
||||
| `coreXY_drive_toothed_idler_offset(type)` | Offset of toothed drive idler pulley |
|
||||
| `coreXY_plain_idler_offset(type)` | Offset of y-carriage plain idler |
|
||||
| `coreXY_toothed_idler_offset(type)` | offset of y-carriage toothed idler |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false)` | Wrapper module to draw both belts of a coreXY setup |
|
||||
| `coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false)` | Draw the coreXY belts |
|
||||
| `coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false)` | Draw one belt of a coreXY setup |
|
||||
|
||||

|
||||
|
||||
### Vitamins
|
||||
| Qty | Module call | BOM entry |
|
||||
| ---:|:--- |:---|
|
||||
| 1 | `belt(GT2x6, [ ... ], [10.0078, 11.69], [0, -24.686])` | Belt GT2 x 6mm x 742mm |
|
||||
| 1 | `belt(GT2x6, [ ... ], [10.0078, 11.69], [0, -24.686])` | Belt GT2 x 6mm x 852mm |
|
||||
| 7 | `pulley(GT2x16_toothed_idler)` | Pulley GT2 idler 16 teeth |
|
||||
| 3 | `pulley(GT2x16_plain_idler)` | Pulley GT2 idler smooth 9.63mm |
|
||||
| 2 | `pulley(GT2x20ob_pulley)` | Pulley GT2OB 20 teeth |
|
||||
| 8 | `screw(M3_cap_screw, 20)` | Screw M3 cap x 20mm |
|
||||
| 4 | `screw(M3_grub_screw, 6)` | Screw M3 grub x 6mm |
|
||||
| 2 | `NEMA(NEMA17M)` | Stepper motor NEMA17 x 40mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
@@ -5970,6 +6103,7 @@ Simple tube or ring
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `rectangular_tube(size, center = true, thickness = 1, fillet = 0.5)` | Create a retangular tube with filleted corners |
|
||||
| `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 |
|
||||
@@ -5989,9 +6123,23 @@ Assembly views shown in the instructions can be large or small and this is deduc
|
||||
parts are used.
|
||||
This heuristic isn't always correct, so the default can be overridden by setting the `big` parameter of `assembly` to `true` or `false`.
|
||||
|
||||
Setting the `ngb` parameter of `assembly` to `true` removes its column from the global BOM and merges it parts into its parent assembly column of the global BOM.
|
||||
This is to prevent the global BOM page becoming too wide in large projects by having it include just the major assemblies.
|
||||
|
||||
The example below shows how to define a vitamin and incorporate it into an assembly with sub-assemblies and make an exploded view.
|
||||
The resulting flat BOM is shown but heirachical BOMs are also generated for real projects.
|
||||
|
||||
If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` module then the STL or DXF will be used in the assembly views generated by `views.py` instead of generating
|
||||
it with code.
|
||||
This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
|
||||
|
||||
The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
|
||||
|
||||
* Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
|
||||
* If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
|
||||
* To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
|
||||
* Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
|
||||
|
||||
[utils/core/bom.scad](utils/core/bom.scad) Implementation.
|
||||
|
||||
[tests/BOM.scad](tests/BOM.scad) Code for this example.
|
||||
@@ -6008,19 +6156,21 @@ The resulting flat BOM is shown but heirachical BOMs are also generated for real
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `assembly(name, big = undef)` | Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams. |
|
||||
| `assembly(name, big = undef, ngb = false)` | Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams. |
|
||||
| `dxf(name)` | Name a dxf that will appear on the BOM, there needs to a module named `<name>_dxf` to make it |
|
||||
| `explode(d, explode_children = false, offset = [0,0,0])` | Explode children by specified Z distance or vector `d`, option to explode grand children |
|
||||
| `hidden()` | Make item invisible, except on the BOM |
|
||||
| `no_explode()` | Prevent children being exploded |
|
||||
| `no_pose()` | Force children not to be posed even if parent is |
|
||||
| `not_on_bom(on = false)` | Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled |
|
||||
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose_hflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose_vflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the X axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `stl(name)` | Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it |
|
||||
| `stl_colour(colour = pp1_colour, alpha = 1)` | Colour an stl where it is placed in an assembly. `alpha` can be used to make it appear transparent. |
|
||||
| `vitamin(description)` | Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "wigit(42): Type 42 widget" |
|
||||
| `use_dxf(name)` | Import a DXF to make a build panel |
|
||||
| `use_stl(name)` | Import an STL to make a build platter |
|
||||
| `vitamin(description)` | Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "widget(42): Widget size 42" |
|
||||
|
||||

|
||||
|
||||
@@ -6047,9 +6197,9 @@ The resulting flat BOM is shown but heirachical BOMs are also generated for real
|
||||
### Assemblies
|
||||
| Qty | Name |
|
||||
| ---:|:--- |
|
||||
| 1 | widget_assembly |
|
||||
| 1 | widget_base_assembly |
|
||||
| 1 | widget_top_assembly |
|
||||
| 1 | widgit_base_assembly |
|
||||
| 1 | wigdit_assembly |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -6147,18 +6297,18 @@ leaving a scar on either surface.
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `corrected_diameter(d, n = 0)` | Adjusted diameter to make flats lie on the circle |
|
||||
| `corrected_radius(r, n = 0)` | Adjusted radius to make flats lie on the circle |
|
||||
| `sides(r)` | Optimium number of sides for specified radius |
|
||||
| `corrected_diameter(d, n = undef)` | Adjusted diameter to make flats lie on the circle |
|
||||
| `corrected_radius(r, n = undef)` | Adjusted radius to make flats lie on the circle |
|
||||
| `sides(r, n = undef)` | Optimium number of sides for specified radius |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle |
|
||||
| `poly_circle(r, sides = 0)` | Make a circle adjusted to print the correct size |
|
||||
| `poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
|
||||
| `poly_circle(r, sides = undef)` | Make a circle adjusted to print the correct size |
|
||||
| `poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
|
||||
| `poly_drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing if cnc_bit_r is non zero, otherwise a poly_cylinder. |
|
||||
| `poly_ring(or, ir, sides = 0)` | Make a 2D ring adjusted to have the correct internal radius |
|
||||
| `poly_ring(or, ir, sides = undef)` | Make a 2D ring adjusted to have the correct internal radius |
|
||||
| `poly_tube(or, ir, h, center = false)` | Make a tube adjusted to have the correct internal radius |
|
||||
| `slot(r, l, h = 100)` | Make a horizontal slot suitable for CNC routing, set h = 0 for 2D version |
|
||||
|
||||
@@ -6210,9 +6360,10 @@ Rectangle with rounded corners.
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `rounded_rectangle(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle_xz(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle_yz(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_xy(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_xz(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_yz(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle(size, r, center = false, xy_center = true)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_square(size, r, center = true)` | Like `square()` but with with rounded corners |
|
||||
|
||||

|
||||
|
@@ -60,6 +60,8 @@ class BOM:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.big = None
|
||||
self.ngb = False
|
||||
self.zoomed = 0
|
||||
self.count = 1
|
||||
self.vitamins = {}
|
||||
self.printed = {}
|
||||
@@ -73,6 +75,8 @@ class BOM:
|
||||
return {
|
||||
"name" : self.name,
|
||||
"big" : self.big,
|
||||
"ngb" : self.ngb,
|
||||
"zoomed" : self.zoomed,
|
||||
"count" : self.count,
|
||||
"assemblies" : assemblies,
|
||||
"vitamins" : {v : self.vitamins[v].data() for v in self.vitamins},
|
||||
@@ -249,7 +253,7 @@ def boms(target = None, assembly = None):
|
||||
#
|
||||
# Run openscad
|
||||
#
|
||||
openscad.run("-D", "$bom=2", "-D", "$preview=true", "--hardwarnings", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
|
||||
openscad.run("-D", "$bom=2", "-D", "$preview=true", "-o", "openscad.echo", "-d", bom_dir + "/bom.deps", bom_maker_name)
|
||||
os.remove(bom_maker_name)
|
||||
print("Generating bom ...", end=" ")
|
||||
|
||||
|
163
scripts/changelog.py
Normal file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
#! Creates the changelog from the git log
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
filename = 'CHANGELOG.md'
|
||||
|
||||
def tag_version(t):
|
||||
""" Format a version tag """
|
||||
return 'v%d.%d.%d' % t
|
||||
|
||||
def initials(name):
|
||||
""" Convert full name to initials with a tooltip """
|
||||
i = ''.join([n[0].upper() + '.' for n in name.split(' ')])
|
||||
return '[%s](# "%s")' % (i, name)
|
||||
|
||||
def get_remote_url():
|
||||
""" Get the git remote URL for the repository """
|
||||
url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"]).decode("utf-8").strip("\n")
|
||||
if url.startswith("git@"):
|
||||
url = url.replace(":", "/", 1).replace("git@", "https://", 1)
|
||||
if url.endswith(".git"):
|
||||
url = url[:-4]
|
||||
return url
|
||||
|
||||
def iscode(word):
|
||||
""" try to guess if the word is code """
|
||||
endings = ['()', '*']
|
||||
starts = ['$', '--']
|
||||
anywhere = ['.', '_', '=', '[', '/']
|
||||
words = ['center', 'false', 'true', 'ngb']
|
||||
|
||||
for w in words:
|
||||
if word == w:
|
||||
return True
|
||||
|
||||
for end in endings:
|
||||
if word.endswith(end):
|
||||
return True
|
||||
|
||||
for start in starts:
|
||||
if word.startswith(start):
|
||||
return True
|
||||
|
||||
for any in anywhere:
|
||||
if word.find(any) >= 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def codify(word, url):
|
||||
""" if a word is deemed code enclose it backticks """
|
||||
if word:
|
||||
if re.match(r'#[0-9]+', word):
|
||||
return '[%s](%s "show issue")' % (word, url + '/issues/' + word[1:])
|
||||
if iscode(word):
|
||||
return '`' + word + '`'
|
||||
return word
|
||||
|
||||
|
||||
def fixup_comment(comment, url):
|
||||
""" markup code words and fix new paragraphs """
|
||||
result = ''
|
||||
word = ''
|
||||
code = False
|
||||
for i, c in enumerate(comment):
|
||||
if c == '`' or code: # Already a code block
|
||||
result += c # Copy verbatim
|
||||
if c == '`': code = not code # Keep track of state
|
||||
else:
|
||||
if c in ' \n' or (c == '.' and (i + 1 == len(comment) or comment[i + 1] in ' \n')): # if a word terminator
|
||||
result += codify(word, url) + c # Add codified word before terminator
|
||||
word = ''
|
||||
else:
|
||||
word += c # Accumulate next word
|
||||
result += codify(word, url) # In case comment ends without a terminator
|
||||
return result.replace('\n\n','\n\n * ') # Give new paragraphs a bullet point
|
||||
|
||||
class Commit(): # members dynamically added from commit_fields
|
||||
pass
|
||||
|
||||
blurb = """
|
||||
# %s Changelog
|
||||
This changelog is generated by `changelog.py` using manually added semantic version tags to classify commits as breaking changes, additions or fixes.
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
url = get_remote_url()
|
||||
|
||||
commit_fields = {
|
||||
'hash': "%H|", # commit commit_hash
|
||||
'tag': "%D|", # tag
|
||||
'author': "%aN|", # author name
|
||||
'date': " %as|", # author date short form
|
||||
'comment': "%B~" # body
|
||||
}
|
||||
|
||||
# Produce the git log
|
||||
format = ''.join([v for k, v in commit_fields.items()])
|
||||
text = subprocess.check_output(["git", "log", "--topo-order", "--format=" + format]).decode("utf-8")
|
||||
|
||||
# Process the log into a list of Commit objects
|
||||
commits = []
|
||||
for line in text.split('~'):
|
||||
line = line.strip('\n')
|
||||
if line:
|
||||
fields = line.split('|')
|
||||
commit = Commit()
|
||||
for i, k in enumerate(commit_fields):
|
||||
exec('commit.%s = """%s"""' % (k, fields[i]), locals())
|
||||
# Convert version tag to tuple
|
||||
if commit.tag:
|
||||
match = re.match(r'.*tag: v([0-9]+)\.([0-9]+)\.([0-9]+).*', commit.tag)
|
||||
commit.tag = (int(match.group(1)), int(match.group(2)), int(match.group(3))) if match else ''
|
||||
commits.append(commit)
|
||||
|
||||
# Format the results from the Commit objects
|
||||
with open(filename, "wt") as file:
|
||||
print(blurb % url.split('/')[-1], file = file)
|
||||
for i, c in enumerate(commits):
|
||||
if c.tag:
|
||||
ver = tag_version(c.tag)
|
||||
level, type = (3, 'Fixes') if c.tag[2] else (2, 'Additions') if c.tag[1] else (1, 'Breaking Changes') if c.tag[0] else (1, 'First publicised version')
|
||||
|
||||
# Find the previous tagged commit
|
||||
j = i + 1
|
||||
diff = ''
|
||||
while j < len(commits):
|
||||
if commits[j].tag:
|
||||
last_ver = tag_version(commits[j].tag)
|
||||
diff = '[...](%s "diff with %s")' % (url + '/compare/' + last_ver + '...' + ver, last_ver)
|
||||
break
|
||||
j += 1
|
||||
|
||||
# Print verson info
|
||||
print('%s [%s](%s "show release") %s %s' % ('#' * (level + 1), ver, url + '/releases/tag/' + ver, type, diff), file = file)
|
||||
|
||||
# Print commits excluding merges
|
||||
if not c.comment.startswith('Merge branch') and not c.comment.startswith('Merge pull'):
|
||||
print('* %s [`%s`](%s "show commit") %s %s\n' % (c.date, c.hash[:7], url + '/commit/' + c.hash, initials(c.author), fixup_comment(c.comment, url)), file = file)
|
@@ -18,6 +18,7 @@
|
||||
#
|
||||
import os
|
||||
from set_config import source_dir
|
||||
from colorama import Fore
|
||||
|
||||
def mtime(file):
|
||||
if os.path.isfile(file):
|
||||
@@ -41,13 +42,13 @@ def read_deps(dname):
|
||||
def check_deps(target, dname):
|
||||
target_mtime = mtime(target)
|
||||
if not target_mtime:
|
||||
return target + " missing"
|
||||
return Fore.CYAN + target + " missing" + Fore.WHITE
|
||||
if not os.path.isfile(dname):
|
||||
return "no deps"
|
||||
return Fore.CYAN + "no deps" + Fore.WHITE
|
||||
deps = read_deps(dname)
|
||||
for dep in deps:
|
||||
if mtime(dep) > target_mtime:
|
||||
return dep + ' changed'
|
||||
return Fore.CYAN + dep + ' changed' + Fore.WHITE
|
||||
return None
|
||||
|
||||
def source_dirs(bom_dir):
|
||||
|
@@ -28,7 +28,10 @@ from set_config import *
|
||||
import time
|
||||
import times
|
||||
from deps import *
|
||||
from tmpdir import *
|
||||
import json
|
||||
import shutil
|
||||
from colorama import Fore, init
|
||||
|
||||
def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
#
|
||||
@@ -43,7 +46,7 @@ def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
if words:
|
||||
last_word = words[-1]
|
||||
if last_word.endswith(suffix):
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
return part_files
|
||||
|
||||
def usage(t):
|
||||
@@ -62,20 +65,29 @@ def make_parts(target, part_type, parts = None):
|
||||
#
|
||||
top_dir = set_config(target, lambda: usage(part_type))
|
||||
target_dir = top_dir + part_type + 's'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
old_deps = top_dir + 'deps' #old location
|
||||
if os.path.isdir(old_deps):
|
||||
shutil.rmtree(old_deps)
|
||||
|
||||
times.read_times(target_dir)
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
all_parts = bom_to_parts(bom_dir, part_type)
|
||||
if parts:
|
||||
targets = list(parts) #copy the list so we dont modify the list passed in
|
||||
else:
|
||||
targets = bom_to_parts(bom_dir, part_type)
|
||||
targets = list(all_parts)
|
||||
for file in os.listdir(target_dir):
|
||||
if file.endswith('.' + part_type):
|
||||
if not file in targets:
|
||||
@@ -119,18 +131,18 @@ def make_parts(target, part_type, parts = None):
|
||||
changed = check_deps(part_file, dname)
|
||||
changed = times.check_have_time(changed, part)
|
||||
if part_type == 'stl' and not changed and not part in bounds_map:
|
||||
changed = "No bounds"
|
||||
changed = Fore.CYAN + "No bounds" + Fore.WHITE
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
part_maker_name = part_type + ".scad"
|
||||
part_maker_name = tmp_dir + '/' + part_type + ".scad"
|
||||
with open(part_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
|
||||
openscad.run("-o", part_file, part_maker_name, "-D$bom=1", "-d", dname)
|
||||
times.add_time(part, t)
|
||||
if part_type == 'stl':
|
||||
bounds = c14n_stl.canonicalise(part_file)
|
||||
@@ -144,10 +156,14 @@ def make_parts(target, part_type, parts = None):
|
||||
with open(bounds_fname, 'w') as outfile:
|
||||
json.dump(bounds_map, outfile, indent = 4)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# List the ones we didn't find
|
||||
#
|
||||
if targets:
|
||||
for part in targets:
|
||||
print("Could not find a module called", part[:-4] + module_suffix, "to make", part)
|
||||
usage(part_type)
|
||||
times.print_times()
|
||||
times.print_times(all_parts)
|
||||
|
@@ -68,9 +68,10 @@ def gallery(force):
|
||||
match = re.match(r"^(#+).*$", line)
|
||||
if match:
|
||||
line = '#' + line
|
||||
if line == '---\n':
|
||||
break;
|
||||
print(line[:-1], file = output_file)
|
||||
if line == '---\n' or line == '<span></span>\n':
|
||||
break
|
||||
if line != '<a name="TOP"></a>\n':
|
||||
print(line[:-1], file = output_file)
|
||||
else:
|
||||
print(Fore.MAGENTA + "Can't find", document, Fore.WHITE);
|
||||
with open(target_dir + "/readme.html", "wt") as html_file:
|
||||
|
@@ -25,19 +25,25 @@ from __future__ import print_function
|
||||
import subprocess, sys
|
||||
|
||||
def run_list(args, silent = False, verbose = False):
|
||||
cmd = ["openscad"] + args
|
||||
cmd = ["openscad"] + args + ["--hardwarnings"]
|
||||
if not silent:
|
||||
for arg in cmd:
|
||||
print(arg, end=" ")
|
||||
print()
|
||||
with open("openscad.log", "w") as log:
|
||||
rc = subprocess.call(cmd, stdout = log, stderr = log)
|
||||
for line in open("openscad.log", "rt"):
|
||||
log_file = "openscad.echo" if "openscad.echo" in cmd else "openscad.log"
|
||||
bad = False
|
||||
for line in open(log_file, "rt"):
|
||||
if verbose or 'ERROR:' in line or 'WARNING:' in line:
|
||||
bad = True
|
||||
print(line[:-1])
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
|
||||
if bad:
|
||||
sys.exit(1)
|
||||
|
||||
def run(*args):
|
||||
run_list(list(args), False)
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
# Set command line options from enviroment variables and check if they have changed
|
||||
|
||||
import json, os, deps
|
||||
from colorama import Fore, init
|
||||
|
||||
def check_options(dir = '.'):
|
||||
global options, options_mtime
|
||||
@@ -37,7 +38,7 @@ def check_options(dir = '.'):
|
||||
|
||||
def have_changed(changed, target):
|
||||
if not changed and deps.mtime(target) < options_mtime:
|
||||
return "command line options changed"
|
||||
return Fore.CYAN + "command line options changed" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def list():
|
||||
|
@@ -26,8 +26,10 @@ import sys
|
||||
import c14n_stl
|
||||
from set_config import *
|
||||
from deps import *
|
||||
from shutil import copyfile
|
||||
import shutil
|
||||
import re
|
||||
import time
|
||||
import times
|
||||
|
||||
source_dirs = { "stl" : "platters", "dxf" : "panels" }
|
||||
target_dirs = { "stl" : "printed", "dxf" : "routed" }
|
||||
@@ -41,22 +43,32 @@ def plateup(target, part_type, usage = None):
|
||||
target_dir = parts_dir + '/' + target_dirs[part_type]
|
||||
source_dir1 = source_dirs[part_type]
|
||||
source_dir2 = top_dir + source_dirs[part_type]
|
||||
|
||||
#
|
||||
# Loop through source directories
|
||||
#
|
||||
used = []
|
||||
all_used = []
|
||||
all_sources = []
|
||||
all_parts = []
|
||||
read_times = False
|
||||
for dir in [source_dir1, source_dir2]:
|
||||
if not os.path.isdir(dir):
|
||||
continue
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not read_times:
|
||||
times.read_times(target_dir)
|
||||
read_times = True
|
||||
#
|
||||
# Make the deps dir
|
||||
#
|
||||
deps_dir = dir + "/deps"
|
||||
deps_dir = parts_dir + "/deps"
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
if os.path.isdir(dir + '/deps'): #old deps
|
||||
shutil.rmtree(dir + '/deps')
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
@@ -65,40 +77,55 @@ def plateup(target, part_type, usage = None):
|
||||
#
|
||||
# Run OpenSCAD on the source files to make the targets
|
||||
#
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
for src in sources:
|
||||
src_file = dir + '/' + src
|
||||
part_file = target_dir + '/' + src[:-4] + part_type
|
||||
part = src[:-4] + part_type
|
||||
all_parts.append(part)
|
||||
part_file = target_dir + '/' + part
|
||||
uses_file = deps_dir + '/' + src[:-4] + 'txt'
|
||||
dname = deps_name(deps_dir, src)
|
||||
changed = check_deps(part_file, dname)
|
||||
oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
|
||||
changed = check_deps(oldest, dname)
|
||||
used = []
|
||||
if changed:
|
||||
print(changed)
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, src_file)
|
||||
t = time.time()
|
||||
openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
|
||||
if part_type == 'stl':
|
||||
c14n_stl.canonicalise(part_file)
|
||||
times.add_time(part, t)
|
||||
log_name = 'openscad.log'
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "wt") as file:
|
||||
for part in used:
|
||||
print(part, file = file)
|
||||
else:
|
||||
log_name = 'openscad.echo'
|
||||
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "rt") as file:
|
||||
for line in file:
|
||||
used.append(line[:-1])
|
||||
all_used += used
|
||||
|
||||
copied = []
|
||||
if all_sources:
|
||||
#
|
||||
# Copy files that are not included
|
||||
#
|
||||
for file in os.listdir(parts_dir):
|
||||
if file.endswith('.' + part_type) and not file in used:
|
||||
if file.endswith('.' + part_type) and not file in all_used:
|
||||
src = parts_dir + '/' + file
|
||||
dst = target_dir + '/' + file
|
||||
if mtime(src) > mtime(dst):
|
||||
print("Copying %s to %s" % (src, dst))
|
||||
copyfile(src, dst)
|
||||
shutil.copyfile(src, dst)
|
||||
copied.append(file)
|
||||
#
|
||||
# Remove any cruft
|
||||
@@ -109,3 +136,12 @@ def plateup(target, part_type, usage = None):
|
||||
if not file in targets and not file in copied:
|
||||
print("Removing %s" % file)
|
||||
os.remove(target_dir + '/' + file)
|
||||
|
||||
targets = [file[:-4] + 'txt' for file in all_sources]
|
||||
for file in os.listdir(deps_dir):
|
||||
if file.endswith('.' + 'txt'):
|
||||
if not file in targets:
|
||||
print("Removing %s" % file)
|
||||
os.remove(deps_dir + '/' + file)
|
||||
|
||||
times.print_times(all_parts)
|
||||
|
@@ -8,6 +8,7 @@ They should work with both Python 2 and Python 3.
|
||||
|:---|:---|
|
||||
| `bom.py` | Generates BOM files for the project. |
|
||||
| `c14n_stl.py` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
|
||||
| `changelog.py` | Creates the changelog from the git log |
|
||||
| `doc_scripts.py` | Makes this document and doc/usage.md. |
|
||||
| `dxfs.py` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
|
||||
| `gallery.py` | Finds projects and adds them to the gallery. |
|
||||
|
@@ -30,6 +30,7 @@ from tests import do_cmd, update_image, colour_scheme, background
|
||||
from deps import mtime
|
||||
from colorama import init
|
||||
import json
|
||||
from tmpdir import *
|
||||
|
||||
def usage():
|
||||
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
|
||||
@@ -40,6 +41,7 @@ def render(target, type):
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + type + 's'
|
||||
bom_dir = top_dir + 'bom'
|
||||
if not os.path.isdir(target_dir):
|
||||
@@ -80,7 +82,7 @@ def render(target, type):
|
||||
# make a file to import the stl
|
||||
#
|
||||
if mtime(part_file) > mtime(png_name):
|
||||
png_maker_name = "png.scad"
|
||||
png_maker_name = tmp_dir + "/png.scad"
|
||||
pp1 = [0, 146/255, 0]
|
||||
colour = pp1
|
||||
if part in colours:
|
||||
@@ -88,15 +90,19 @@ def render(target, type):
|
||||
if not '[' in colour:
|
||||
colour = '"' + colour + '"'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write('color(%s) import("%s");\n' % (colour, part_file))
|
||||
f.write('color(%s) import("%s");\n' % (colour, reltmp(part_file, target)))
|
||||
cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500"
|
||||
render = "--preview" if type == 'stl' or colour != pp1 else "--render"
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", tmp_name, png_maker_name);
|
||||
tmp_name = tmp_dir + '/' + part[:-4] + '.png'
|
||||
openscad.run("-o", tmp_name, png_maker_name, colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall");
|
||||
do_cmd(("magick "+ tmp_name + " -trim -resize 280x280 -background %s -gravity Center -extent 280x280 -bordercolor %s -border 10 %s"
|
||||
% (background, background, tmp_name)).split())
|
||||
update_image(tmp_name, png_name)
|
||||
os.remove(png_maker_name)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
init()
|
||||
|
@@ -69,17 +69,22 @@ def set_config(target, usage = None):
|
||||
sys.exit(1)
|
||||
|
||||
fname = source_dir + "/target.scad"
|
||||
text = "include <config_%s.scad>\n" % target;
|
||||
line = ""
|
||||
text = ['include <config_%s.scad>\n' % target,
|
||||
'$target = "%s";\n' % target,
|
||||
'$cwd="%s";\n' % os.getcwd().replace('\\', '/')
|
||||
]
|
||||
|
||||
lines = [""]
|
||||
try:
|
||||
with open(fname,"rt") as f:
|
||||
line = f.read()
|
||||
lines = f.readlines()
|
||||
except:
|
||||
pass
|
||||
|
||||
if line != text:
|
||||
if lines != text:
|
||||
with open(fname,"wt") as f:
|
||||
f. write(text);
|
||||
for t in text:
|
||||
f. write(t);
|
||||
return target + "/"
|
||||
|
||||
def usage():
|
||||
|
@@ -34,6 +34,7 @@ import shutil
|
||||
from deps import *
|
||||
from blurb import *
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
w = 4096
|
||||
h = w
|
||||
@@ -50,13 +51,17 @@ def do_cmd(cmd, output = sys.stdout):
|
||||
return subprocess.call(cmd, stdout = output, stderr = output)
|
||||
|
||||
def compare_images(a, b, c):
|
||||
if not os.path.isfile(b):
|
||||
print(Fore.MAGENTA + "Failed to generate %s while making %s" % (b, a), Fore.WHITE)
|
||||
sys.exit(1)
|
||||
if not os.path.isfile(a):
|
||||
return -1
|
||||
log_name = 'magick.log'
|
||||
with open(log_name, 'w') as output:
|
||||
do_cmd(("magick compare -metric AE -fuzz %d%% %s %s %s" % (fuzz, a, b, c)).split(), output = output)
|
||||
with open(log_name, 'r') as f:
|
||||
pixels = int(float(f.read().strip()))
|
||||
pixels = f.read().strip()
|
||||
pixels = int(float(pixels if pixels.isnumeric() else -1))
|
||||
os.remove(log_name)
|
||||
return pixels
|
||||
|
||||
@@ -91,6 +96,7 @@ def usage():
|
||||
|
||||
def tests(tests):
|
||||
scad_dir = "tests"
|
||||
tmp_dir = mktmpdir(scad_dir + '/')
|
||||
deps_dir = scad_dir + "/deps"
|
||||
png_dir = scad_dir + "/png"
|
||||
bom_dir = scad_dir + "/bom"
|
||||
@@ -111,7 +117,7 @@ def tests(tests):
|
||||
libtest = True
|
||||
lib_blurb = scrape_blurb(scad_name)
|
||||
if not os.path.isfile(png_name):
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
|
||||
openscad.run(scad_name, "-o", png_name, colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall");
|
||||
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
|
||||
else:
|
||||
#
|
||||
@@ -126,14 +132,13 @@ def tests(tests):
|
||||
#
|
||||
# List of individual part files
|
||||
#
|
||||
|
||||
scads = [i for i in sorted(os.listdir(scad_dir), key = lambda s: s.lower()) if i[-5:] == ".scad"]
|
||||
types = []
|
||||
for scad in scads:
|
||||
base_name = scad[:-5]
|
||||
if not tests or base_name in tests:
|
||||
done.append(base_name)
|
||||
print('\n'+base_name)
|
||||
print(base_name)
|
||||
cap_name = base_name[0].capitalize() + base_name[1:]
|
||||
base_name = base_name.lower()
|
||||
scad_name = scad_dir + '/' + scad
|
||||
@@ -232,14 +237,15 @@ def tests(tests):
|
||||
if changed:
|
||||
print(changed)
|
||||
t = time.time()
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run_list(options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, scad_name]);
|
||||
tmp_name = tmp_dir + '/tmp.png'
|
||||
openscad.run_list([scad_name, "-o", tmp_name] + options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname]);
|
||||
times.add_time(scad_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1000x600", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
BOM = bom.parse_bom()
|
||||
with open(bom_name, 'wt') as outfile:
|
||||
json.dump(BOM.flat_data(), outfile, indent = 4)
|
||||
print()
|
||||
|
||||
with open(bom_name, "rt") as bom_file:
|
||||
BOM = json.load(bom_file)
|
||||
@@ -300,6 +306,11 @@ def tests(tests):
|
||||
with open(doc_base_name + ".html", "wt") as html_file:
|
||||
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
|
||||
times.print_times()
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
do_cmd(('codespell -L od ' + doc_name).split())
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@@ -44,7 +44,7 @@ def got_time(name):
|
||||
|
||||
def check_have_time(changed, name):
|
||||
if not changed and not got_time(name):
|
||||
changed = "no previous time"
|
||||
changed = Fore.CYAN + "no previous time" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def add_time(name, start):
|
||||
@@ -52,23 +52,34 @@ def add_time(name, start):
|
||||
del times[name.lower()]
|
||||
times[name] = round(time.time() - start, 3)
|
||||
|
||||
def print_times():
|
||||
write_times()
|
||||
def print_times(files = None):
|
||||
sorted_times = sorted(times.items(), key=lambda kv: kv[1])
|
||||
total = 0
|
||||
old_total = 0
|
||||
for entry in sorted_times:
|
||||
colour = Fore.WHITE
|
||||
key = entry[0]
|
||||
new = entry[1]
|
||||
delta = 0
|
||||
if key in last_times:
|
||||
old = last_times[key]
|
||||
delta = new - old
|
||||
if delta > 0.3:
|
||||
colour = Fore.RED
|
||||
if delta < -0.3:
|
||||
colour = Fore.GREEN
|
||||
print(colour + "%5.1f %5.1f %s" % (new, delta, key))
|
||||
total += new
|
||||
if files and not key in files:
|
||||
del times[key]
|
||||
else:
|
||||
new = entry[1]
|
||||
delta = 0
|
||||
colour = Fore.WHITE
|
||||
if key in last_times:
|
||||
old = last_times[key]
|
||||
old_total += old
|
||||
delta = new - old
|
||||
if delta > 0.3:
|
||||
colour = Fore.RED
|
||||
if delta < -0.3:
|
||||
colour = Fore.GREEN
|
||||
print(colour + "%6.1f %5.1f %s" % (new, delta, key))
|
||||
total += new
|
||||
write_times()
|
||||
if sorted_times:
|
||||
print(Fore.WHITE + "%5.1f" % total)
|
||||
colour = Fore.WHITE
|
||||
delta = total - old_total
|
||||
if delta > 1:
|
||||
colour = Fore.RED
|
||||
if delta < -1:
|
||||
colour = Fore.GREEN
|
||||
print(colour + "%6.1f %5.1f TOTAL%s" % (total, delta, Fore.WHITE))
|
||||
|
40
scripts/tmpdir.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
"""
|
||||
Make a directory for tmp files.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
|
||||
def mktmpdir(top_dir):
|
||||
tmp_dir = top_dir + 'tmp'
|
||||
if not os.path.isdir(tmp_dir):
|
||||
os.makedirs(tmp_dir)
|
||||
else:
|
||||
for file in os.listdir(tmp_dir):
|
||||
os.remove(tmp_dir + '/' + file)
|
||||
return tmp_dir
|
||||
|
||||
def reltmp(dir, target):
|
||||
return dir if os.path.isabs(dir) else '../../' + dir if target else '../' + dir
|
||||
|
||||
def rmtmpdir(tmp_dir):
|
||||
os.rmdir(tmp_dir)
|
||||
while os.path.isdir(tmp_dir):
|
||||
time.sleep(0.1)
|
453
scripts/views.py
@@ -36,7 +36,9 @@ import blurb
|
||||
import bom
|
||||
import shutil
|
||||
import re
|
||||
import copy
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
def is_assembly(s):
|
||||
return s[-9:] == '_assembly' or s[-11:] == '_assemblies'
|
||||
@@ -74,19 +76,17 @@ def bom_to_assemblies(bom_dir, bounds_map):
|
||||
# Remove the main assembly if it is a shell
|
||||
#
|
||||
if flat_bom:
|
||||
ass = flat_bom[-1]
|
||||
ass = flat_bom[-1]
|
||||
if len(ass["assemblies"]) < 2 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]:
|
||||
flat_bom = flat_bom[:-1]
|
||||
return [assembly["name"] for assembly in flat_bom]
|
||||
|
||||
def eop(print_mode, doc_file, last = False, first = False):
|
||||
if print_mode:
|
||||
print('\n<div style="page-break-after: always;"></div>', file = doc_file)
|
||||
else:
|
||||
if not first:
|
||||
print('[Top](#TOP)', file = doc_file)
|
||||
if not last:
|
||||
print("\n---", file = doc_file)
|
||||
def eop(doc_file, last = False, first = False):
|
||||
print('<span></span>', file = doc_file) # An invisable marker for page breaks because markdown takes much longer if the document contains a div
|
||||
if not first:
|
||||
print('[Top](#TOP)', file = doc_file)
|
||||
if not last:
|
||||
print("\n---", file = doc_file)
|
||||
|
||||
def pad(s, before, after = 0):
|
||||
return ' ' * before + str(s) + ' ' * after
|
||||
@@ -103,14 +103,36 @@ def usage():
|
||||
print("\nusage:\n\t views [target_config] [<name1>_assembly] ... [<nameN>_assembly] - Create assembly images and readme.")
|
||||
sys.exit(1)
|
||||
|
||||
types = ["vitamins", "printed", "routed"]
|
||||
|
||||
def merged(bom):
|
||||
bom = copy.deepcopy(bom)
|
||||
for aname in bom["assemblies"]:
|
||||
count = bom["assemblies"][aname]
|
||||
for ass in flat_bom:
|
||||
if ass['name'] == aname and ass['ngb']:
|
||||
merged_assembly = merged(ass)
|
||||
total = ass['count']
|
||||
for t in types:
|
||||
for thing in merged_assembly[t]:
|
||||
items = merged_assembly[t][thing]['count'] * count // total
|
||||
if thing in bom[t]:
|
||||
bom[t][thing]['count'] += items
|
||||
else:
|
||||
bom[t][thing] = merged_assembly[t][thing]
|
||||
bom[t][thing]['count'] = items
|
||||
break
|
||||
return bom
|
||||
|
||||
def views(target, do_assemblies = None):
|
||||
done_assemblies = []
|
||||
#
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + 'assemblies'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
@@ -139,6 +161,7 @@ def views(target, do_assemblies = None):
|
||||
# Find all the scad files
|
||||
#
|
||||
main_blurb = None
|
||||
pngs = []
|
||||
for dir in source_dirs(bom_dir):
|
||||
if os.path.isdir(dir):
|
||||
for filename in os.listdir(dir):
|
||||
@@ -162,33 +185,43 @@ def views(target, do_assemblies = None):
|
||||
#
|
||||
for ass in flat_bom:
|
||||
if ass["name"] == real_name:
|
||||
zoomed = ass['zoomed']
|
||||
if not "blurb" in ass:
|
||||
ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no])
|
||||
break
|
||||
if not do_assemblies or real_name in do_assemblies:
|
||||
|
||||
#
|
||||
# Run openscad on the created file
|
||||
#
|
||||
dname = deps_name(deps_dir, filename)
|
||||
for explode in [0, 1]:
|
||||
#
|
||||
# Run openscad on the created file
|
||||
# Generate png name
|
||||
#
|
||||
dname = deps_name(deps_dir, filename)
|
||||
for explode in [0, 1]:
|
||||
png_name = target_dir + '/' + real_name + '.png'
|
||||
if not explode:
|
||||
png_name = png_name.replace('_assembly', '_assembled')
|
||||
png_name = target_dir + '/' + real_name + '.png'
|
||||
if not explode:
|
||||
png_name = png_name.replace('_assembly', '_assembled')
|
||||
pngs.append(png_name)
|
||||
|
||||
if not do_assemblies or real_name in do_assemblies:
|
||||
changed = check_deps(png_name, dname)
|
||||
changed = times.check_have_time(changed, png_name)
|
||||
changed = options.have_changed(changed, png_name)
|
||||
tmp_name = 'tmp.png'
|
||||
tmp_name = tmp_dir + '/' + real_name + '.png'
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
png_maker_name = 'png.scad'
|
||||
png_maker_name = tmp_dir + '/png.scad'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
openscad.run_list(options.list() + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name]);
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
view_def = ['--viewall', '--autocenter'] if not (zoomed & (1 << explode)) else ['--camera=0,0,0,55,0,25,140']
|
||||
openscad.run_list(["-o", tmp_name, png_maker_name] + options.list() + target_def + cwd_def + view_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "-d", dname]);
|
||||
times.add_time(png_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
@@ -202,193 +235,221 @@ def views(target, do_assemblies = None):
|
||||
if module == 'main_assembly':
|
||||
main_blurb = blurb.scrape_module_blurb(lines[:line_no])
|
||||
line_no += 1
|
||||
times.print_times()
|
||||
#
|
||||
# Build the document
|
||||
#
|
||||
for print_mode in [True, False]:
|
||||
doc_name = top_dir + "readme.md"
|
||||
with open(doc_name, "wt") as doc_file:
|
||||
#
|
||||
# Title, description and picture
|
||||
#
|
||||
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
|
||||
print('<a name="TOP"></a>\n# %s' % project, file = doc_file)
|
||||
main_file = bom.find_scad_file('main_assembly')
|
||||
if not main_file:
|
||||
raise Exception("can't find source for main_assembly")
|
||||
text = blurb.scrape_blurb(source_dir + '/' + main_file)
|
||||
blurbs = blurb.split_blurb(text)
|
||||
if len(text):
|
||||
print(blurbs[0], file = doc_file)
|
||||
else:
|
||||
if print_mode:
|
||||
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
|
||||
#
|
||||
# Only add the image if the first blurb section doesn't contain one.
|
||||
#
|
||||
if not re.search(r'\!\[.*\]\(.*\)', blurbs[0], re.MULTILINE):
|
||||
print('\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file)
|
||||
eop(print_mode, doc_file, first = True)
|
||||
#
|
||||
# Build TOC
|
||||
#
|
||||
print('## Table of Contents', file = doc_file)
|
||||
print('1. [Parts list](#Parts_list)', file = doc_file)
|
||||
for ass in flat_bom:
|
||||
name = ass["name"]
|
||||
cap_name = titalise(name)
|
||||
print('1. [%s](#%s)' % (cap_name, name), file = doc_file)
|
||||
print(file = doc_file)
|
||||
if len(blurbs) > 1:
|
||||
print(blurbs[1], file = doc_file)
|
||||
eop(print_mode, doc_file)
|
||||
#
|
||||
# Global BOM
|
||||
#
|
||||
print('<a name="Parts_list"></a>\n## Parts list', file = doc_file)
|
||||
types = ["vitamins", "printed", "routed"]
|
||||
headings = {"vitamins" : "vitamins", "printed" : "3D printed parts", "routed" : "CNC routed parts"}
|
||||
things = {}
|
||||
doc_name = top_dir + "readme.md"
|
||||
with open(doc_name, "wt") as doc_file:
|
||||
#
|
||||
# Title, description and picture
|
||||
#
|
||||
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
|
||||
print('<a name="TOP"></a>', file = doc_file)
|
||||
print('# %s' % project, file = doc_file)
|
||||
main_file = bom.find_scad_file('main_assembly')
|
||||
if not main_file:
|
||||
raise Exception("can't find source for main_assembly")
|
||||
text = blurb.scrape_blurb(source_dir + '/' + main_file)
|
||||
blurbs = blurb.split_blurb(text)
|
||||
if len(text):
|
||||
print(blurbs[0], file = doc_file)
|
||||
else:
|
||||
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
|
||||
#
|
||||
# Only add the image if the first blurb section doesn't contain one.
|
||||
#
|
||||
if not re.search(r'\!\[.*\]\(.*\)', blurbs[0], re.MULTILINE):
|
||||
print('\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file)
|
||||
eop(doc_file, first = True)
|
||||
#
|
||||
# Build TOC
|
||||
#
|
||||
print('## Table of Contents', file = doc_file)
|
||||
print('1. [Parts list](#Parts_list)', file = doc_file)
|
||||
for ass in flat_bom:
|
||||
name = ass["name"]
|
||||
cap_name = titalise(name)
|
||||
print('1. [%s](#%s)' % (cap_name, name), file = doc_file)
|
||||
print(file = doc_file)
|
||||
if len(blurbs) > 1:
|
||||
print(blurbs[1], file = doc_file)
|
||||
eop(doc_file)
|
||||
#
|
||||
# Global BOM
|
||||
#
|
||||
global_bom = [merged(ass) for ass in flat_bom if not ass['ngb']]
|
||||
print('<a name="Parts_list"></a>\n## Parts list', file = doc_file)
|
||||
headings = {"vitamins" : "vitamins", "printed" : "3D printed parts", "routed" : "CNC routed parts"}
|
||||
things = {}
|
||||
for t in types:
|
||||
things[t] = {}
|
||||
for ass in flat_bom:
|
||||
for t in types:
|
||||
things[t] = {}
|
||||
for ass in flat_bom:
|
||||
for t in types:
|
||||
for thing in ass[t]:
|
||||
if thing in things[t]:
|
||||
things[t][thing] += ass[t][thing]["count"]
|
||||
else:
|
||||
things[t][thing] = ass[t][thing]["count"]
|
||||
for ass in flat_bom:
|
||||
name = titalise(ass["name"][:-9]).replace(' ',' ')
|
||||
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
|
||||
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> | |', file = doc_file)
|
||||
for thing in ass[t]:
|
||||
if thing in things[t]:
|
||||
things[t][thing] += ass[t][thing]["count"]
|
||||
else:
|
||||
things[t][thing] = ass[t][thing]["count"]
|
||||
for ass in global_bom:
|
||||
name = titalise(ass["name"][:-9]).replace(' ',' ')
|
||||
if ass["count"] > 1:
|
||||
name = "%d x %s" % (ass["count"], name)
|
||||
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
|
||||
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> | |', file = doc_file)
|
||||
print(('|---:' * len(global_bom) + '|---:|:---|'), file = doc_file)
|
||||
|
||||
print(('|---:' * len(flat_bom) + '|---:|:---|'), file = doc_file)
|
||||
|
||||
for t in types:
|
||||
if things[t]:
|
||||
totals = {}
|
||||
heading = headings[t][0:1].upper() + headings[t][1:]
|
||||
print(('| ' * len(flat_bom) + '| | **%s** |') % heading, file = doc_file)
|
||||
for thing in sorted(things[t], key = lambda s: s.split(":")[-1]):
|
||||
for ass in flat_bom:
|
||||
count = ass[t][thing]["count"] if thing in ass[t] else 0
|
||||
print('| %s ' % pad(count if count else '.', 2, 1), file = doc_file, end = '')
|
||||
name = ass["name"]
|
||||
if name in totals:
|
||||
totals[name] += count
|
||||
else:
|
||||
totals[name] = count
|
||||
print('| %s | %s |' % (pad(things[t][thing], 2, 1), pad(thing.split(":")[-1], 2)), file = doc_file)
|
||||
|
||||
grand_total = 0
|
||||
for ass in flat_bom:
|
||||
for t in types:
|
||||
if things[t]:
|
||||
totals = {}
|
||||
grand_total2 = 0
|
||||
heading = headings[t][0].upper() + headings[t][1:]
|
||||
print(('| ' * len(global_bom) + '| | **%s** |') % heading, file = doc_file)
|
||||
for thing in sorted(things[t], key = lambda s: s.split(":")[-1]):
|
||||
for ass in global_bom:
|
||||
count = ass[t][thing]["count"] if thing in ass[t] else 0
|
||||
print('| %s ' % pad(count if count else '.', 2, 1), file = doc_file, end = '')
|
||||
name = ass["name"]
|
||||
total = totals[name] if name in totals else 0
|
||||
print('| %s ' % pad(total if total else '.', 2, 1), file = doc_file, end = '')
|
||||
grand_total += total
|
||||
print("| %s | %s |" % (pad(grand_total, 2, 1), pad('Total %s count' % headings[t], 2)), file = doc_file)
|
||||
if name in totals:
|
||||
totals[name] += count
|
||||
else:
|
||||
totals[name] = count
|
||||
grand_total2 += count
|
||||
print('| %s | %s |' % (pad(things[t][thing], 2, 1), pad(thing.split(":")[-1], 2)), file = doc_file)
|
||||
|
||||
print(file = doc_file)
|
||||
if len(blurbs) > 2:
|
||||
print(blurbs[2], file = doc_file)
|
||||
eop(print_mode, doc_file)
|
||||
#
|
||||
# Assembly instructions
|
||||
#
|
||||
for ass in flat_bom:
|
||||
name = ass["name"]
|
||||
cap_name = titalise(name)
|
||||
|
||||
if ass["count"] > 1:
|
||||
print('<a name="%s"></a>\n## %d x %s' % (name, ass["count"], cap_name), file = doc_file)
|
||||
else:
|
||||
print('<a name="%s"></a>\n## %s' % (name, cap_name), file = doc_file)
|
||||
vitamins = ass["vitamins"]
|
||||
if vitamins:
|
||||
print("### Vitamins", file = doc_file)
|
||||
print("|Qty|Description|", file = doc_file)
|
||||
print("|---:|:----------|", file = doc_file)
|
||||
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
|
||||
print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]), file = doc_file)
|
||||
print("\n", file = doc_file)
|
||||
|
||||
printed = ass["printed"]
|
||||
if printed:
|
||||
print('### 3D Printed parts', file = doc_file)
|
||||
keys = sorted(list(printed.keys()))
|
||||
for i, p in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(printed) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
part = keys[i - n + j + 1]
|
||||
print('|  %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
routed = ass["routed"]
|
||||
if routed:
|
||||
print("### CNC Routed parts", file = doc_file)
|
||||
keys = sorted(list(routed.keys()))
|
||||
for i, r in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(routed) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
part = keys[i - n + j + 1]
|
||||
print('|  %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
sub_assemblies = ass["assemblies"]
|
||||
if sub_assemblies:
|
||||
print("### Sub-assemblies", file = doc_file)
|
||||
keys = sorted(list(sub_assemblies.keys()))
|
||||
for i, a in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(keys) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
a = keys[i - n + j + 1].replace('_assembly', '_assembled')
|
||||
print('|  %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
small = not ass["big"]
|
||||
suffix = '_tn.png' if small else '.png'
|
||||
print('### Assembly instructions', file = doc_file)
|
||||
print('\n' % (name, name + suffix), file = doc_file)
|
||||
|
||||
if "blurb" in ass and ass["blurb"]:
|
||||
print(ass["blurb"], file = doc_file)
|
||||
else:
|
||||
if print_mode:
|
||||
print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE)
|
||||
|
||||
name = name.replace('_assembly', '_assembled')
|
||||
print('\n' % (name, name + suffix), file = doc_file)
|
||||
eop(print_mode, doc_file, last = ass == flat_bom[-1] and not main_blurb)
|
||||
#
|
||||
# If main module is suppressed print any blurb here
|
||||
#
|
||||
if main_blurb:
|
||||
print(main_blurb, file = doc_file)
|
||||
eop(print_mode, doc_file, last = True)
|
||||
grand_total = 0
|
||||
for ass in global_bom:
|
||||
name = ass["name"]
|
||||
total = totals[name] if name in totals else 0
|
||||
print('| %s ' % pad(total if total else '.', 2, 1), file = doc_file, end = '')
|
||||
grand_total += total
|
||||
print("| %s | %s |" % (pad(grand_total, 2, 1), pad('Total %s count' % headings[t], 2)), file = doc_file)
|
||||
assert grand_total == grand_total2
|
||||
print(file = doc_file)
|
||||
if len(blurbs) > 2:
|
||||
print(blurbs[2], file = doc_file)
|
||||
eop(doc_file)
|
||||
#
|
||||
# Convert to HTML
|
||||
# Assembly instructions
|
||||
#
|
||||
html_name = "printme.html" if print_mode else "readme.html"
|
||||
with open(top_dir + html_name, "wt") as html_file:
|
||||
do_cmd(("python -m markdown -x tables -x sane_lists " + doc_name).split(), html_file)
|
||||
for ass in flat_bom:
|
||||
name = ass["name"]
|
||||
cap_name = titalise(name)
|
||||
|
||||
print('<a name="%s"></a>' % name, file = doc_file)
|
||||
if ass["count"] > 1:
|
||||
print('## %d x %s' % (ass["count"], cap_name), file = doc_file)
|
||||
else:
|
||||
print('## %s' % cap_name, file = doc_file)
|
||||
vitamins = ass["vitamins"]
|
||||
if vitamins:
|
||||
print("### Vitamins", file = doc_file)
|
||||
print("|Qty|Description|", file = doc_file)
|
||||
print("|---:|:----------|", file = doc_file)
|
||||
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
|
||||
print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]), file = doc_file)
|
||||
print("\n", file = doc_file)
|
||||
|
||||
printed = ass["printed"]
|
||||
if printed:
|
||||
print('### 3D Printed parts', file = doc_file)
|
||||
keys = sorted(list(printed.keys()))
|
||||
for i, p in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p]["count"], p), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(printed) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
part = keys[i - n + j + 1]
|
||||
print('|  %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
routed = ass["routed"]
|
||||
if routed:
|
||||
print("### CNC Routed parts", file = doc_file)
|
||||
keys = sorted(list(routed.keys()))
|
||||
for i, r in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r]["count"], r), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(routed) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
part = keys[i - n + j + 1]
|
||||
print('|  %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
sub_assemblies = ass["assemblies"]
|
||||
if sub_assemblies:
|
||||
print("### Sub-assemblies", file = doc_file)
|
||||
keys = sorted(list(sub_assemblies.keys()))
|
||||
for i, a in enumerate(keys):
|
||||
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', sub_assemblies[a], a), file = doc_file, end = '')
|
||||
if (i % 3) == 2 or i == len(keys) - 1:
|
||||
n = (i % 3) + 1
|
||||
print('\n|%s' % ('---|' * n), file = doc_file)
|
||||
for j in range(n):
|
||||
a = keys[i - n + j + 1].replace('_assembly', '_assembled')
|
||||
print('|  %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
print('\n', file = doc_file)
|
||||
|
||||
small = not ass["big"]
|
||||
suffix = '_tn.png' if small else '.png'
|
||||
print('### Assembly instructions', file = doc_file)
|
||||
print('\n' % (name, name + suffix), file = doc_file)
|
||||
|
||||
if "blurb" in ass and ass["blurb"]:
|
||||
print(ass["blurb"], file = doc_file)
|
||||
else:
|
||||
print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE)
|
||||
|
||||
name = name.replace('_assembly', '_assembled')
|
||||
print('\n' % (name, name + suffix), file = doc_file)
|
||||
eop(doc_file, last = ass == flat_bom[-1] and not main_blurb)
|
||||
#
|
||||
# If main module is suppressed print any blurb here
|
||||
#
|
||||
if main_blurb:
|
||||
print(main_blurb, file = doc_file)
|
||||
eop(doc_file, last = True)
|
||||
#
|
||||
# Convert to HTML
|
||||
#
|
||||
html_name = top_dir + 'readme.html'
|
||||
t = time.time()
|
||||
with open(html_name, "wt") as html_file:
|
||||
do_cmd(("python -m markdown -x tables -x sane_lists " + doc_name).split(), html_file)
|
||||
times.add_time(html_name, t)
|
||||
times.print_times(pngs + [html_name])
|
||||
#
|
||||
# Make the printme.html by replacing empty spans that invisbly mark the page breaks by page break divs.
|
||||
#
|
||||
with open(html_name, 'rt') as src:
|
||||
lines = src.readlines()
|
||||
|
||||
i = 0
|
||||
with open(top_dir + 'printme.html', 'wt') as dst:
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
if line.startswith('<p><span></span>'): # Empty span used to mark page breaks
|
||||
i += 1
|
||||
if lines[i].startswith('<a href="#TOP">Top</a>'): # The first page break won't have one
|
||||
i += 1
|
||||
if i < len(lines) and lines[i] == '<hr />\n': # The last page break doesn't have one
|
||||
dst.write('<div style="page-break-after: always;"></div>\n')
|
||||
i += 1
|
||||
else:
|
||||
dst.write(line)
|
||||
i += 1
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# Spell check
|
||||
#
|
||||
do_cmd('codespell -L od readme.md'.split())
|
||||
do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())
|
||||
#
|
||||
# List the ones we didn't find
|
||||
#
|
||||
|
@@ -43,31 +43,29 @@ module widget(thickness) {
|
||||
}
|
||||
}
|
||||
|
||||
module widgit_stl() {
|
||||
stl("widget");
|
||||
module widget_stl() {
|
||||
stl("widget")
|
||||
union() {
|
||||
rounded_rectangle([30, 30, 3], 2, true);
|
||||
|
||||
union() {
|
||||
rounded_rectangle([30, 30, 3], 2);
|
||||
|
||||
render() insert_boss(insert, height, 2.2);
|
||||
}
|
||||
render() insert_boss(insert, height, 2.2);
|
||||
}
|
||||
}
|
||||
|
||||
module widgit_dxf() {
|
||||
dxf("widget");
|
||||
module widget_dxf() {
|
||||
dxf("widget")
|
||||
difference() {
|
||||
sheet_2D(sheet, 20, 20, 1);
|
||||
|
||||
difference() {
|
||||
sheet_2D(sheet, 20, 20, 1);
|
||||
|
||||
drill(screw_clearance_radius(screw), 0);
|
||||
}
|
||||
drill(screw_clearance_radius(screw), 0);
|
||||
}
|
||||
}
|
||||
|
||||
//! * Push the insert into the base with a soldering iron heated to 200°C
|
||||
module widgit_base_assembly()
|
||||
assembly("widgit_base") {
|
||||
module widget_base_assembly()
|
||||
assembly("widget_base") {
|
||||
stl_colour(pp1_colour)
|
||||
widgit_stl();
|
||||
widget_stl();
|
||||
|
||||
translate_z(height)
|
||||
insert(insert);
|
||||
@@ -80,14 +78,14 @@ assembly("widget_top") {
|
||||
widget(sheet_thickness(sheet));
|
||||
|
||||
render_2D_sheet(sheet) // Must be last because it is transparent
|
||||
widgit_dxf();
|
||||
widget_dxf();
|
||||
}
|
||||
|
||||
//! * Screw the two assemblies together
|
||||
module widgit_assembly()
|
||||
assembly("wigdit") {
|
||||
module widget_assembly()
|
||||
assembly("widget") {
|
||||
|
||||
widgit_base_assembly(); // Note this is not exloded because it is sub-assembly
|
||||
widget_base_assembly(); // Note this is not exloded because it is sub-assembly
|
||||
|
||||
translate_z(height) {
|
||||
translate_z(sheet_thickness(sheet))
|
||||
@@ -100,7 +98,7 @@ assembly("wigdit") {
|
||||
}
|
||||
|
||||
module boms() {
|
||||
widgit_assembly();
|
||||
widget_assembly();
|
||||
}
|
||||
|
||||
boms();
|
||||
|
@@ -21,16 +21,22 @@ include <../vitamins/pcbs.scad>
|
||||
|
||||
use <../utils/layout.scad>
|
||||
|
||||
function spacing(p) = let(w = pcb_width(p)) w < 22 ? w + 3 : w + 10;
|
||||
|
||||
module pcbs() {
|
||||
layout([for(p = pcbs) pcb_width(p)], 10)
|
||||
layout([for(p = pcbs) spacing(p)], 0)
|
||||
translate([0, pcb_length(pcbs[$i]) / 2])
|
||||
rotate(90)
|
||||
pcb_assembly(pcbs[$i], 5 + $i, 3);
|
||||
|
||||
translate([0, 120])
|
||||
translate([0, 110])
|
||||
layout([for(p = perfboards) pcb_length(p)], 10)
|
||||
translate([0, -pcb_width(perfboards[$i]) / 2])
|
||||
pcb_assembly(perfboards[$i], 5 + $i, 3);
|
||||
|
||||
for(p = pcbs_not_shown)
|
||||
hidden()
|
||||
pcb(p);
|
||||
}
|
||||
if($preview)
|
||||
pcbs();
|
||||
|
@@ -22,7 +22,7 @@ use <../utils/layout.scad>
|
||||
include <../vitamins/blowers.scad>
|
||||
|
||||
module blowers()
|
||||
layout([for(b = blowers) blower_width(b)], 10, true) let(b = blowers[$i]){
|
||||
layout([for(b = blowers) blower_width(b)], 5, true) let(b = blowers[$i]){
|
||||
screw = blower_screw(b);
|
||||
h = blower_lug(b);
|
||||
|
||||
|
134
tests/core_xy.scad
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2020
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
include <../core.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
include <../vitamins/screws.scad>
|
||||
include <../vitamins/stepper_motors.scad>
|
||||
include <../vitamins/washers.scad>
|
||||
|
||||
include <../utils/core_xy.scad>
|
||||
|
||||
|
||||
module coreXY_belts_test() {
|
||||
coreXY_type = coreXY_GT2_20_16;
|
||||
plain_idler = coreXY_plain_idler(coreXY_type);
|
||||
toothed_idler = coreXY_toothed_idler(coreXY_type);
|
||||
|
||||
coreXYPosBL = [0, 0, 0];
|
||||
coreXYPosTR = [200, 150, 0];
|
||||
separation = [0, coreXY_coincident_separation(coreXY_type).y, pulley_height(plain_idler) + washer_thickness(M3_washer)];
|
||||
pos = [100, 50];
|
||||
|
||||
upper_drive_pulley_offset = [40, 10];
|
||||
lower_drive_pulley_offset = [0, 0];
|
||||
|
||||
coreXY_belts(coreXY_type,
|
||||
carriagePosition = pos,
|
||||
coreXYPosBL = coreXYPosBL,
|
||||
coreXYPosTR = coreXYPosTR,
|
||||
separation = separation,
|
||||
x_gap = 10,
|
||||
upper_drive_pulley_offset = upper_drive_pulley_offset,
|
||||
lower_drive_pulley_offset = lower_drive_pulley_offset,
|
||||
show_pulleys = true);
|
||||
|
||||
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosTR.y + upper_drive_pulley_offset.y, separation.z/2]) {
|
||||
// add the upper drive pulley stepper motor
|
||||
translate([coreXY_drive_pulley_x_alignment(coreXY_type) + upper_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the upper drive offset idler pulleys if required
|
||||
if (upper_drive_pulley_offset.x > 0) {
|
||||
translate(coreXY_drive_plain_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (upper_drive_pulley_offset.x < 0) {
|
||||
translate([-pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosTR.y + lower_drive_pulley_offset.y, -separation.z/2]) {
|
||||
// add the lower drive pulley stepper motor
|
||||
translate([-coreXY_drive_pulley_x_alignment(coreXY_type) + lower_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the lower drive offset idler pulleys if required
|
||||
if (lower_drive_pulley_offset.x < 0) {
|
||||
translate([-coreXY_drive_plain_idler_offset(coreXY_type).x, coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (lower_drive_pulley_offset.x > 0) {
|
||||
translate([pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([-2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
// add the screw for the left upper idler pulley
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right upper idler pulley
|
||||
translate([coreXYPosTR.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
if (separation.x != 0) {
|
||||
// add the screw for the left lower idler pulley
|
||||
translate([coreXYPosBL.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right lower idler pulley
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
|
||||
translate([-separation.x/2, pos.y + coreXYPosBL.y -separation.y/2, -separation.z/2 + pulley_height(plain_idler)/2]) {
|
||||
// add the screw for the left Y carriage toothed idler
|
||||
translate([coreXYPosBL.x, coreXY_toothed_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the left Y carriage plain idler
|
||||
translate([coreXYPosBL.x + separation.x + coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage toothed idler
|
||||
translate([coreXYPosTR.x + separation.x, coreXY_toothed_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage plain idler
|
||||
translate([coreXYPosTR.x - coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
if ($preview)
|
||||
coreXY_belts_test();
|
@@ -56,7 +56,7 @@ module horiholes_stl(t = thickness) {
|
||||
}
|
||||
if(t == thickness)
|
||||
translate([length / 2, 0])
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5);
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5, true);
|
||||
}
|
||||
|
||||
module horiholes() {
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 51 KiB |
BIN
tests/png/core_xy.png
Normal file
After Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 153 KiB |
BIN
tests/png/pocket_handle.png
Normal file
After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 43 KiB |
40
tests/pocket_handle.scad
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
include <../vitamins/sheets.scad>
|
||||
|
||||
use <../printed/pocket_handle.scad>
|
||||
|
||||
show_holes = false;
|
||||
|
||||
handle = pocket_handle();
|
||||
|
||||
module pocket_handles() {
|
||||
if($preview) {
|
||||
pocket_handle_assembly(handle);
|
||||
|
||||
if(show_holes)
|
||||
#pocket_handle_holes(handle);
|
||||
}
|
||||
else
|
||||
pocket_handle(handle);
|
||||
}
|
||||
|
||||
pocket_handles();
|
@@ -26,15 +26,16 @@ sheet = 3;
|
||||
pos = 1; //[-1 : 0.1 : 1]
|
||||
|
||||
module rails()
|
||||
layout([for(l = rails) carriage_width(rail_carriage(l))], 20)
|
||||
layout([for(l = carriages) carriage_width(l)], 20)
|
||||
rotate(-90) {
|
||||
rail = rails[$i];
|
||||
carriage = carriages[$i];
|
||||
rail = carriage_rail(carriage);
|
||||
length = 200;
|
||||
screw = rail_screw(rail);
|
||||
nut = screw_nut(screw);
|
||||
washer = screw_washer(screw);
|
||||
|
||||
rail_assembly(rail, length, pos * rail_travel(rail, length) / 2, $i<2 ? grey(20) : "green", $i<2 ? grey(20) : "red");
|
||||
rail_assembly(carriage, length, pos * carriage_travel(carriage, length) / 2, $i<2 ? grey(20) : "green", $i<2 ? grey(20) : "red");
|
||||
|
||||
rail_screws(rail, length, sheet + nut_thickness(nut, true) + washer_thickness(washer));
|
||||
|
||||
|
@@ -27,10 +27,13 @@ module rounded_rectangles() {
|
||||
rounded_rectangle([30, 20, 10], 3);
|
||||
|
||||
translate([80, 0])
|
||||
rounded_rectangle_xz([30, 20, 10], 3);
|
||||
rounded_cube_xy([30, 20, 10], 3);
|
||||
|
||||
translate([120, 0])
|
||||
rounded_rectangle_yz([30, 20, 10], 3);
|
||||
rounded_cube_xz([30, 20, 10], 3);
|
||||
|
||||
translate([160, 0])
|
||||
rounded_cube_yz([30, 20, 10], 3);
|
||||
}
|
||||
|
||||
rounded_rectangles();
|
||||
|
@@ -25,25 +25,30 @@ include <../vitamins/screws.scad>
|
||||
width = 30;
|
||||
2d = true;
|
||||
|
||||
module sheets()
|
||||
layout([for(s = sheets) width], 5)
|
||||
let(sheet = sheets[$i], w = sheet_is_woven(sheet) ? width : undef)
|
||||
if(2d)
|
||||
render_2D_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet_2D(sheet, width, width, 2);
|
||||
module sheets() {
|
||||
rows = 2;
|
||||
n = ceil(len(sheets) / rows);
|
||||
w = width + 5;
|
||||
for(y = [0 : rows - 1], x = [0 : n - 1], s = y * n + x)
|
||||
if(s < len(sheets))
|
||||
translate([width / 2 + x * w, y * w])
|
||||
let(sheet = sheets[s], w = sheet_is_woven(sheet) ? width : undef)
|
||||
if(2d)
|
||||
render_2D_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet_2D(sheet, width, width, 2);
|
||||
|
||||
circle(3);
|
||||
}
|
||||
else
|
||||
render_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet(sheet, width, width, 2);
|
||||
|
||||
translate_z(sheet_thickness(sheet) / 2)
|
||||
screw_countersink(M3_cs_cap_screw);
|
||||
}
|
||||
circle(3);
|
||||
}
|
||||
else
|
||||
render_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet(sheet, width, width, 2);
|
||||
|
||||
translate_z(sheet_thickness(sheet) / 2)
|
||||
screw_countersink(M3_cs_cap_screw);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
sheets();
|
||||
|
@@ -27,6 +27,9 @@ module tubes() {
|
||||
|
||||
translate([50, 10])
|
||||
tube(10, 8, 30);
|
||||
|
||||
translate([100, 10])
|
||||
rectangular_tube([10, 20, 30]);
|
||||
}
|
||||
|
||||
tubes();
|
||||
|
@@ -25,16 +25,28 @@
|
||||
//! parts are used.
|
||||
//! This heuristic isn't always correct, so the default can be overridden by setting the `big` parameter of `assembly` to `true` or `false`.
|
||||
//!
|
||||
//! Setting the `ngb` parameter of `assembly` to `true` removes its column from the global BOM and merges it parts into its parent assembly column of the global BOM.
|
||||
//! This is to prevent the global BOM page becoming too wide in large projects by having it include just the major assemblies.
|
||||
//!
|
||||
//! The example below shows how to define a vitamin and incorporate it into an assembly with sub-assemblies and make an exploded view.
|
||||
//! The resulting flat BOM is shown but heirachical BOMs are also generated for real projects.
|
||||
//!
|
||||
//! If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` module then the STL or DXF will be used in the assembly views generated by `views.py` instead of generating
|
||||
//! it with code.
|
||||
//! This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
|
||||
//!
|
||||
//! The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
|
||||
//!
|
||||
//! * Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
|
||||
//! * If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
|
||||
//! * To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
|
||||
//! * Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
|
||||
//
|
||||
function bom_mode(n = 1) = $_bom >= n && (is_undef($on_bom) || $on_bom); //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well
|
||||
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of `$exploded` if it is defined, else `0`
|
||||
function show_supports() = !$preview || exploded(); //! True if printed support material should be shown
|
||||
|
||||
module no_explode() let($exploded_parent = true) children(); //! Prevent children being exploded
|
||||
module no_pose() let($posed = true) children(); //! Force children not to be posed even if parent is
|
||||
|
||||
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector `d`, option to explode grand children
|
||||
v = is_list(d) ? d : [0, 0, d];
|
||||
o = is_list(offset) ? offset : [0, 0, offset];
|
||||
@@ -55,17 +67,29 @@ module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode
|
||||
children();
|
||||
}
|
||||
|
||||
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
children();
|
||||
else
|
||||
let($posed = true) // only pose the top level
|
||||
rotate([55, 0, 25])
|
||||
rotate([-a.x, 0, 0])
|
||||
rotate([0, -a.y, 0])
|
||||
rotate([0, 0, -a.z])
|
||||
translate(-t)
|
||||
children();
|
||||
module no_pose() let($posed = true, $zoomed = undef) children(); //! Force children not to be posed even if parent is
|
||||
|
||||
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
let($zoomed = is_undef(d)
|
||||
? is_undef($zoomed)
|
||||
? undef
|
||||
: $zoomed
|
||||
: is_undef(exploded)
|
||||
? 3
|
||||
: exploded
|
||||
? 2
|
||||
: 1)
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
children();
|
||||
else
|
||||
let($posed = true) // only pose the top level
|
||||
rotate([55, 0, 25])
|
||||
translate_z(is_undef(d) ? 0 : 140 - d)
|
||||
rotate([-a.x, 0, 0])
|
||||
rotate([0, -a.y, 0])
|
||||
rotate([0, 0, -a.z])
|
||||
translate(-t)
|
||||
children();
|
||||
|
||||
module pose_hflip(exploded = undef) //! Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
@@ -84,9 +108,11 @@ module pose_vflip(exploded = undef) //! Pose an STL or assembly for render
|
||||
children();
|
||||
|
||||
|
||||
module assembly(name, big = undef) { //! Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams.
|
||||
module assembly(name, big = undef, ngb = false) { //! Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams.
|
||||
if(bom_mode()) {
|
||||
args = is_undef(big) ? "" : str("(big=", big, ")");
|
||||
zoom = is_undef($zoomed) ? 0 : $zoomed;
|
||||
arglist = str(arg(big, undef, "big"), arg(ngb, false, "ngb"), arg(zoom, 0, "zoomed"));
|
||||
args = len(arglist) ? str("(", slice(arglist, 2), ")") : "";
|
||||
echo(str("~", name, "_assembly", args, "{"));
|
||||
}
|
||||
no_pose()
|
||||
@@ -108,21 +134,43 @@ module stl_colour(colour = pp1_colour, alpha = 1) { //! Colour an stl where it i
|
||||
}
|
||||
|
||||
module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it
|
||||
if(bom_mode()) {
|
||||
if(bom_mode() && is_undef($in_stl)) {
|
||||
colour = is_undef($stl_colour) ? pp1_colour : $stl_colour;
|
||||
echo(str("~", name, ".stl(colour='", colour, "')"));
|
||||
}
|
||||
if($children)
|
||||
if(is_undef($pose))
|
||||
let($in_stl = true)
|
||||
children();
|
||||
else {
|
||||
path = is_undef($target) ? "/stls/" : str("/", $target, "/stls/");
|
||||
import(str($cwd, path, name, ".stl"));
|
||||
}
|
||||
}
|
||||
|
||||
module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named `<name>_dxf` to make it
|
||||
if(bom_mode()) {
|
||||
if(bom_mode() && is_undef($in_dxf)) {
|
||||
if(is_undef($dxf_colour))
|
||||
echo(str("~", name, ".dxf"));
|
||||
else
|
||||
echo(str("~", name, ".dxf(colour='", $dxf_colour, "')"));
|
||||
}
|
||||
if($children)
|
||||
if(is_undef($pose))
|
||||
let($in_dfx = true)
|
||||
children();
|
||||
else {
|
||||
path = is_undef($target) ? "/dxfs/" : str("/", $target, "/dxfs/");
|
||||
import(str($cwd, path, name, ".dxf"));
|
||||
}
|
||||
}
|
||||
|
||||
module use_stl(name) //! Import an STL to make a build platter
|
||||
assert(false); // Here for documentation only, real version in core.scad
|
||||
|
||||
module use_dxf(name) //! Import a DXF to make a build panel
|
||||
assert(false); // Here for documentation only, real version in core.scad
|
||||
|
||||
function value_string(value) = is_string(value) ? str("\"", value, "\"") : str(value); //! Convert `value` to a string or quote it if it is already a string
|
||||
|
||||
function arg(value, default, name = "") = //! Create string for arg if not default, helper for `vitamin()`
|
||||
@@ -130,7 +178,7 @@ function arg(value, default, name = "") = //! Create string for arg if not def
|
||||
: name ? str(", ", name, " = ", value_string(value))
|
||||
: str(", ", value_string(value));
|
||||
|
||||
module vitamin(description) { //! Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "wigit(42): Type 42 widget"
|
||||
module vitamin(description) { //! Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "widget(42): Widget size 42"
|
||||
if(bom_mode(2))
|
||||
echo(str("~", description, !is_undef($hidden) ? " - not shown" : ""));
|
||||
}
|
||||
|
@@ -28,12 +28,12 @@ use <global.scad>
|
||||
|
||||
module use_stl(name) { //! Import an STL to make a build platter
|
||||
stl(name);
|
||||
path = is_undef($target) ? "../stls/" : str("../", $target, "/stls/");
|
||||
path = is_undef($target) ? "../stls/" : str($cwd, "/", $target, "/stls/");
|
||||
import(str(path, name, ".stl"));
|
||||
}
|
||||
|
||||
module use_dxf(name) { //! Import a DXF to make a build panel
|
||||
dxf(name);
|
||||
path = is_undef($target) ? "../dxfs/" : str("../", $target, "/dxfs/");
|
||||
path = is_undef($target) ? "../dxfs/" : str($cwd, "/", $target, "/dxfs/");
|
||||
import(str(path, name, ".dxf"));
|
||||
}
|
||||
|
@@ -33,20 +33,20 @@
|
||||
//! When `twist` is set the resulting cylinder is extended by `eps` at each end so that the exact length of the hole can be used without
|
||||
//! leaving a scar on either surface.
|
||||
//
|
||||
function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius
|
||||
function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle
|
||||
function corrected_diameter(d, n = 0) = d / cos(180 / (n ? n : sides(d / 2))); //! Adjusted diameter to make flats lie on the circle
|
||||
function sides(r, n = undef) = is_undef(n) ? max(round(4 * r), 3) : n ? max(n, 3) : r2sides(r); //! Optimium number of sides for specified radius
|
||||
function corrected_radius(r, n = undef) = r / cos(180 / sides(r, n)); //! Adjusted radius to make flats lie on the circle
|
||||
function corrected_diameter(d, n = undef) = 2 * corrected_radius(d / 2 , n); //! Adjusted diameter to make flats lie on the circle
|
||||
|
||||
module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the correct size
|
||||
n = sides ? sides : sides(r);
|
||||
circle(r = corrected_radius(r,n), $fn = n);
|
||||
module poly_circle(r, sides = undef) { //! Make a circle adjusted to print the correct size
|
||||
n = sides(r, sides);
|
||||
circle(r = corrected_radius(r, n), $fn = n);
|
||||
}
|
||||
|
||||
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
|
||||
module poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
|
||||
if(twist) {
|
||||
slices = ceil(h / layer_height);
|
||||
twists = min(twist + 1, slices);
|
||||
sides = sides ? sides : sides(r);
|
||||
sides = sides(r, sides);
|
||||
rot = 360 / sides / twists * (twists < slices ? (1 + 1 / slices) : 1);
|
||||
if(center)
|
||||
for(side = [0, 1])
|
||||
@@ -64,10 +64,10 @@ module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0
|
||||
poly_circle(r, sides);
|
||||
|
||||
if(h && chamfer)
|
||||
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides ? sides : sides(r));
|
||||
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides(r, sides));
|
||||
}
|
||||
|
||||
module poly_ring(or, ir, sides = 0) { //! Make a 2D ring adjusted to have the correct internal radius
|
||||
module poly_ring(or, ir, sides = undef) { //! Make a 2D ring adjusted to have the correct internal radius
|
||||
cir = corrected_radius(ir, sides);
|
||||
filaments = (or - cir) / extrusion_width;
|
||||
if(filaments > 3 + eps)
|
||||
|
@@ -22,26 +22,33 @@
|
||||
//
|
||||
module rounded_square(size, r, center = true) //! Like `square()` but with with rounded corners
|
||||
{
|
||||
assert(r < min(size.x, size.y) / 2);
|
||||
$fn = r2sides4n(r);
|
||||
offset(r) offset(-r) square(size, center = center);
|
||||
}
|
||||
|
||||
module rounded_rectangle(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
module rounded_rectangle(size, r, center = false, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
{
|
||||
linear_extrude(size.z, center = center)
|
||||
extrude_if(size.z, center = center)
|
||||
rounded_square([size.x, size.y], r, xy_center);
|
||||
}
|
||||
|
||||
module rounded_rectangle_xz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z.
|
||||
module rounded_cube_xy(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 0])
|
||||
rounded_rectangle([size.x, size.z, size.y], r, center = true, xy_center = true);
|
||||
extrude_if(size.z, center = z_center)
|
||||
rounded_square([size.x, size.y], r, xy_center);
|
||||
}
|
||||
|
||||
module rounded_rectangle_yz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z.
|
||||
module rounded_cube_xz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 90])
|
||||
rounded_rectangle([size.y, size.z, size.x], r, center = true, xy_center = true);
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 0])
|
||||
rounded_cube_xy([size.x, size.z, size.y], r, xy_center = true, z_center = true);
|
||||
}
|
||||
|
||||
module rounded_cube_yz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 90])
|
||||
rounded_cube_xy([size.y, size.z, size.x], r, xy_center = true, z_center = true);
|
||||
}
|
||||
|
196
utils/core_xy.scad
Normal file
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2020
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
|
||||
//!
|
||||
//! The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
|
||||
//! Implementation has the following features:
|
||||
//! 1. The drive and idler pulleys may be different sizes.
|
||||
//! 2. The belt separation is parameterised.
|
||||
//! 3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
|
||||
//! 4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
|
||||
//! allows flexible positioning of the motors.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/belts.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
|
||||
|
||||
coreXY_GT2_20_20 = ["coreXY_20_20", GT2x6, GT2x20ob_pulley, GT2x20_toothed_idler, GT2x20_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
coreXY_GT2_20_16 = ["coreXY_20_16", GT2x6, GT2x20ob_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
coreXY_GT2_16_16 = ["coreXY_16_16", GT2x6, GT2x16_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
|
||||
function coreXY_belt(type) = type[1]; //! Belt type
|
||||
function coreXY_drive_pulley(type) = type[2]; //! Drive pulley type
|
||||
function coreXY_toothed_idler(type) = type[3]; //! Toothed idler type
|
||||
function coreXY_plain_idler(type) = type[4]; //! Plain idler type
|
||||
function coreXY_upper_belt_colour(type) = type[5]; //! Colour of the upper belt
|
||||
function coreXY_upper_tooth_colour(type) = type[6]; //! Colour of the upper belt's teeth
|
||||
function coreXY_lower_belt_colour(type) = type[7]; //! Colour of the lower belt
|
||||
function coreXY_lower_tooth_colour(type) = type[8]; //! Colour of the lower belt's teeth
|
||||
|
||||
// used to offset the position of the drive pulley and the y-carriage plain idler pulley
|
||||
// relative to the anchor pulley so that the belts align properly
|
||||
function coreXY_drive_pulley_x_alignment(type) = //! Belt alignment offset of the drive pulley relative to the anchor pulley
|
||||
(pulley_od(coreXY_drive_pulley(type)) - pulley_od(coreXY_toothed_idler(type))) / 2;
|
||||
function coreXY_coincident_separation(type) = //! Value of x, y separation to make y-carriage pulleys coincident
|
||||
[ -coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_toothed_idler(type)))/2, 0 ];
|
||||
function coreXY_plain_idler_offset(type) = //! Offset of y-carriage plain idler
|
||||
[ (pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2 + coreXY_drive_pulley_x_alignment(type), pulley_od(coreXY_plain_idler(type))/2, 0 ];
|
||||
function coreXY_toothed_idler_offset(type) = //! offset of y-carriage toothed idler
|
||||
[ 0, -pulley_pr(coreXY_toothed_idler(type)), 0 ];
|
||||
// helper functions for positioning idlers when the stepper motor drive pulley is offset
|
||||
function coreXY_drive_toothed_idler_offset(type) = //! Offset of toothed drive idler pulley
|
||||
[ 0, coreXY_drive_pulley_x_alignment(type), 0 ];
|
||||
function coreXY_drive_plain_idler_offset(type) = //! Offset of plain drive idler pulley
|
||||
[ coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2, 0 ];
|
||||
|
||||
|
||||
module coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false) { //! Draw one belt of a coreXY setup
|
||||
|
||||
// y-carriage toothed pulley
|
||||
p0_type = coreXY_toothed_idler(type);
|
||||
p0 = [ size.x / 2, -size.y / 2 - pulley_od(p0_type) / 2 + pos.y - separation_y / 2 ];
|
||||
|
||||
// bottom right toothed idler pulley
|
||||
p1_type = p0_type;
|
||||
p1 = [ size.x / 2, -size.y / 2 ];
|
||||
|
||||
// bottom left anchor toothed idler pulley
|
||||
p2_type = p0_type;
|
||||
p2 = [ -size.x / 2, -size.y / 2 ];
|
||||
|
||||
// stepper motor drive pulley
|
||||
p3d_type = coreXY_drive_pulley(type);
|
||||
p3d = [ -size.x / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.x,
|
||||
size.y / 2 + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// toothed idler for offset stepper motor drive pulley
|
||||
p3t_type = coreXY_toothed_idler(type);
|
||||
p3t = [ -size.x / 2 + (drive_pulley_offset.x > 0 ? 0 : 2*coreXY_drive_pulley_x_alignment(type)),
|
||||
size.y / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// y-carriage plain pulley
|
||||
p4_type = coreXY_plain_idler(type);
|
||||
p4 = [ -size.x / 2 + pulley_od(p4_type) / 2 + pulley_od(p3d_type) / 2 + coreXY_drive_pulley_x_alignment(type) + plain_idler_offset,
|
||||
-size.y / 2 + pulley_od(p4_type) / 2 + pos.y + separation_y / 2
|
||||
];
|
||||
|
||||
// plain idler for offset stepper motor drive pulley
|
||||
p3p_type = p4_type;
|
||||
p3p = [ drive_pulley_offset.x > 0 ? p4.x : -p0.x - pulley_od(p0_type),
|
||||
size.y / 2 - pulley_od(p3p_type) / 2 - pulley_od(p3d_type) / 2 + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// dummy pulleys for y separation
|
||||
p5_type = p4_type;
|
||||
p5 = [ pos.x - size.x / 2, -size.y / 2 + pos.y + separation_y / 2 ];
|
||||
p6_type = p0_type;
|
||||
p6 = [ pos.x - size.x / 2, -size.y / 2 + pos.y - separation_y / 2 ];
|
||||
|
||||
module show_pulleys(show_pulleys) {// Allows the pulley colour to be set for debugging
|
||||
if (is_list(show_pulleys))
|
||||
color(show_pulleys)
|
||||
children();
|
||||
else if (show_pulleys)
|
||||
children();
|
||||
}
|
||||
|
||||
show_pulleys(show_pulleys) {
|
||||
translate(p0)
|
||||
pulley_assembly(p0_type); // y-carriage toothed pulley
|
||||
translate(p1)
|
||||
pulley_assembly(p1_type); // bottom right toothed idler pulley
|
||||
translate(p2)
|
||||
pulley_assembly(p2_type); // bottom left anchor toothed idler pulley
|
||||
translate(p3d)
|
||||
hflip(hflip)
|
||||
pulley_assembly(p3d_type); // top left stepper motor drive pulley
|
||||
if (drive_pulley_offset.x) { // idler pulleys for offset stepper motor drive pulley
|
||||
translate(p3t)
|
||||
pulley_assembly(p3t_type); // toothed idler
|
||||
translate(p3p)
|
||||
pulley_assembly(p3p_type); // plain idler
|
||||
}
|
||||
translate(p4)
|
||||
pulley_assembly(p4_type); // y-carriage plain pulley
|
||||
}
|
||||
|
||||
path0a = [
|
||||
[ p0.x, p0.y, pulley_od(p0_type) / 2 ],
|
||||
[ p1.x, p1.y, pulley_od(p1_type) / 2 ],
|
||||
[ p2.x, p2.y, pulley_od(p2_type) / 2 ]
|
||||
];
|
||||
path0b = [
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path0c = [
|
||||
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path0d = [
|
||||
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path1 = [ // use eps for corner radius to get sharp corners so this part of the belt is deleted by the gap
|
||||
[ p5.x, p5.y, eps ],
|
||||
[ p6.x, p6.y, eps ]
|
||||
];
|
||||
|
||||
belt = coreXY_belt(type);
|
||||
|
||||
path0 = drive_pulley_offset.x == 0 ? concat(path0a, path0b) : drive_pulley_offset.x > 0 ? concat(path0a, path0c) : concat(path0a, path0d);
|
||||
path = separation_y == 0 ? path0 : concat(path0, path1);
|
||||
|
||||
belt(type = belt,
|
||||
points = path,
|
||||
gap = [ x_gap + eps, abs(separation_y) + 2 ],
|
||||
gap_pos = [ pos.x - size.x / 2, pos.y - size.y / 2 + belt_pitch_height(belt) - belt_thickness(belt) / 2 ],
|
||||
belt_colour = lower_belt ? coreXY_lower_belt_colour(type) : coreXY_upper_belt_colour(type),
|
||||
tooth_colour = lower_belt ? coreXY_lower_tooth_colour(type) : coreXY_upper_tooth_colour(type));
|
||||
}
|
||||
|
||||
module coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false) { //! Wrapper module to draw both belts of a coreXY setup
|
||||
translate([size.x / 2 - separation.x / 2, size.y / 2, -separation.z / 2]) {
|
||||
// lower belt
|
||||
hflip()
|
||||
explode(25)
|
||||
coreXY_half(type, size, [size.x - pos.x - separation.x, pos.y], separation.y, x_gap, plain_idler_offset, [-lower_drive_pulley_offset.x, lower_drive_pulley_offset.y], show_pulleys, lower_belt = true, hflip = true);
|
||||
// upper belt
|
||||
translate([separation.x, 0, separation.z])
|
||||
explode(25)
|
||||
coreXY_half(type, size, [pos.x, pos.y], separation.y, x_gap, plain_idler_offset, upper_drive_pulley_offset, show_pulleys, lower_belt = false, hflip=false);
|
||||
}
|
||||
}
|
||||
|
||||
module coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false) { //! Draw the coreXY belts
|
||||
assert(coreXYPosBL.z == coreXYPosTR.z);
|
||||
|
||||
coreXYSize = coreXYPosTR - coreXYPosBL;
|
||||
translate(coreXYPosBL)
|
||||
coreXY(type, coreXYSize, [carriagePosition.x - coreXYPosBL.x + separation.x / 2, carriagePosition.y - coreXYPosBL.y], separation = separation, x_gap = x_gap, plain_idler_offset = 0, upper_drive_pulley_offset = upper_drive_pulley_offset, lower_drive_pulley_offset = lower_drive_pulley_offset, show_pulleys = show_pulleys);
|
||||
}
|
@@ -21,7 +21,7 @@
|
||||
//! Draw a 3D right triangle with rounded edges. Intended to be embedded in other parts. Can be optionally offset by the filleted amount.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
include <NopSCADlib/utils/core/rounded_rectangle.scad>
|
||||
include <..//utils/core/rounded_rectangle.scad>
|
||||
|
||||
module rounded_right_triangle(x, y, z, fillet, center = true, offset = false) { //! Draw a 3D right triangle with rounded edges.
|
||||
fillet = max(fillet, eps);
|
||||
@@ -31,16 +31,15 @@ module rounded_right_triangle(x, y, z, fillet, center = true, offset = false) {
|
||||
hull() {
|
||||
translate([0, fillet, size.z / 2])
|
||||
rotate([90, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([0, size.y, size.z / 2])
|
||||
rotate([90, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([fillet, 0, size.z / 2])
|
||||
rotate([0, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([size.x, 0, size.z / 2])
|
||||
rotate([0, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -68,3 +68,11 @@ module woven_tube(or, ir, h, center= true, colour = grey(30), colour2, warp = 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module rectangular_tube(size, center = true, thickness = 1, fillet = 0.5) { //! Create a retangular tube with filleted corners
|
||||
extrude_if(size.z, center = center)
|
||||
difference() {
|
||||
rounded_square([size.x, size.y], fillet);
|
||||
rounded_square([size.x - 2 * thickness, size.y - 2 * thickness], fillet);
|
||||
}
|
||||
}
|
||||
|
@@ -128,7 +128,7 @@ module battery_contact(type, pos = true) { //! Draw a positive or negative batte
|
||||
t = contact_thickness(type);
|
||||
|
||||
color("silver") {
|
||||
rounded_rectangle([contact_width(type), h, t], r = 1, center = false);
|
||||
rounded_rectangle([contact_width(type), h, t], r = 1);
|
||||
|
||||
translate([0, -h / 2, t])
|
||||
rotate([90, 0, 0])
|
||||
|
@@ -40,8 +40,10 @@ function blower_base(type) = type[13]; //! Thickness of the base
|
||||
function blower_top(type) = type[14]; //! Thickness of the top
|
||||
function blower_wall(type) = type[15]; //! Side wall thickness
|
||||
function blower_lug(type) = type[16]; //! Height of the lugs
|
||||
function blower_wall_left(type) = type[15]; //! Left side wall thickness
|
||||
function blower_wall_right(type) = type[17]; //! Right wall thickness (for square fans)
|
||||
|
||||
function blower_casing_is_square(type) = len(blower_screw_holes(type)) > 3; //! True for square radial fans, false for spiral shape radial blowers
|
||||
function blower_casing_is_square(type) = blower_depth(type) < 15; //! True for square radial fans, false for spiral shape radial blowers
|
||||
function blower_exit_offset(type) = blower_casing_is_square(type) ? blower_length(type) / 2 : blower_exit(type) / 2; //! Offset of exit's centre from the edge
|
||||
|
||||
fan_colour = grey(20);
|
||||
@@ -74,41 +76,54 @@ module blower_fan(type, casing_is_square) {
|
||||
module blower_square(type) { //! Draw a square blower
|
||||
width = blower_width(type);
|
||||
depth = blower_depth(type);
|
||||
wall = blower_wall(type);
|
||||
wall_left = blower_wall_left(type);
|
||||
wall_right = blower_wall_right(type);
|
||||
hole_count = len(blower_screw_holes(type));
|
||||
hole_pitch = (blower_screw_holes(type)[1].x - blower_screw_holes(type)[0].x) / 2;
|
||||
corner_radius = width / 2 - hole_pitch;
|
||||
corner_inset = (width - blower_exit(type)) / 2;
|
||||
corner_inset = (width - blower_exit(type) - wall_left - wall_right) / (hole_count == 2 ? 1 : 2);
|
||||
|
||||
module inset_corners()
|
||||
translate([width / 2, width / 2])
|
||||
for(i = hole_count == 2 ? [1, 3] : [0 : 3])
|
||||
rotate(i * 90)
|
||||
translate([-width / 2 - eps, -width/ 2 - eps])
|
||||
quadrant(corner_inset, corner_inset - corner_radius);
|
||||
|
||||
module square_inset_corners(remove_center = false)
|
||||
difference() {
|
||||
//overall outside
|
||||
square([width, width], center = false);
|
||||
rounded_square([width, width], corner_radius, center = false);
|
||||
|
||||
if (remove_center) {
|
||||
// cut out the inside, leaving the corners
|
||||
translate([corner_inset + wall, -eps])
|
||||
square([width - 2 * (wall + corner_inset), width - wall + eps], center = false);
|
||||
|
||||
translate([wall, corner_inset + wall])
|
||||
square([width - 2 * wall, width - 2 * (wall + corner_inset)], center = false);
|
||||
translate([hole_count == 2 ? wall_left : corner_inset + wall_left, -eps])
|
||||
square([blower_exit(type), width / 2], center = false);
|
||||
translate(blower_axis(type))
|
||||
circle(d = blower_bore(type) + 1);
|
||||
} else {
|
||||
// cut out the bore for the fan
|
||||
translate(blower_axis(type))
|
||||
circle(d = blower_bore(type));
|
||||
}
|
||||
// corner inset
|
||||
translate([width / 2, width / 2])
|
||||
for(i = [0 : 3])
|
||||
rotate(i * 90)
|
||||
translate([-width / 2 - eps, -width/ 2 - eps])
|
||||
quadrant(corner_inset, corner_inset - corner_radius);
|
||||
inset_corners();
|
||||
}
|
||||
|
||||
base_height = blower_base(type);
|
||||
linear_extrude(base_height)
|
||||
difference () {
|
||||
rounded_square([width, width], corner_radius, center = false);
|
||||
blower_hole_positions(type)
|
||||
circle(d = blower_screw_hole(type));
|
||||
}
|
||||
|
||||
// add the lugs which may be higher than the base
|
||||
linear_extrude(blower_lug(type))
|
||||
difference () {
|
||||
intersection() {
|
||||
rounded_square([width, width], corner_radius, center = false);
|
||||
inset_corners();
|
||||
}
|
||||
blower_hole_positions(type)
|
||||
circle(d = blower_screw_hole(type));
|
||||
}
|
||||
|
@@ -24,8 +24,9 @@
|
||||
// h h s t t
|
||||
RB5015 = ["RB5015", "Blower Runda RB5015", 51.3, 51, 15, 31.5, M4_cap_screw, 26, [27.3, 25.4], 4.5, [[4.3, 45.4], [47.3,7.4]], 20, 14, 1.5, 1.3, 1.2, 15];
|
||||
PE4020 = ["PE4020", "Blower Pengda Technology 4020", 40, 40, 20, 27.5, M3_cap_screw, 22, [21.5, 20 ], 3.2, [[37,3],[3,37],[37,37]], 29.3, 17, 1.7, 1.2, 1.3, 13];
|
||||
BL40x10 =["BL40x10","Square radial fan 4010", 40, 40,9.5, 27, M2_cap_screw, 16, [24, 20 ], 2.4, [[2,2],[38,2],[2,38],[38,38]], 30 , 9.5, 1.5, 1.5, 1.1, 1.5];
|
||||
BL30x10 =["BL30x10","Square radial fan 3010", 30, 30,10.1,25, M2_cap_screw, 16, [16, 15 ], 2.4, [[3,27],[27,3]], 21.2, 9.5, 1.1, 1.2, 2.5, 2.8, 0.9];
|
||||
BL40x10 =["BL40x10","Square radial fan 4010", 40, 40,9.5, 27, M2_cap_screw, 16, [24, 20 ], 2.4, [[2,2],[38,2],[2,38],[38,38]], 27.8, 9.5, 1.5, 1.5, 1.1, 1.5, 1.1];
|
||||
|
||||
blowers = [BL40x10, PE4020, RB5015];
|
||||
blowers = [BL30x10, BL40x10, PE4020, RB5015];
|
||||
|
||||
use <blower.scad>
|
||||
|
@@ -47,7 +47,7 @@ module square_button(type, colour = "yellow") { //! Draw square button with spec
|
||||
stem = square_button_cap_stem(type);
|
||||
|
||||
color(grey(20)) {
|
||||
rounded_rectangle([w, w, h - 0.5], r = wall, center = false);
|
||||
rounded_rectangle([w, w, h - 0.5], r = wall);
|
||||
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * pitch, y * pitch])
|
||||
|
@@ -37,7 +37,7 @@ module camera_lens(type, offset = 0, show_lens = true) //! Draw the lens stack,
|
||||
r = p[1] + offset;
|
||||
app = p[2];
|
||||
if(size.x)
|
||||
rounded_rectangle(size + [2 * offset, 2 * offset, round_to_layer(offset)], r, center = false);
|
||||
rounded_rectangle(size + [2 * offset, 2 * offset, round_to_layer(offset)], r);
|
||||
else
|
||||
if (show_lens)
|
||||
translate_z(size.y)
|
||||
@@ -72,7 +72,7 @@ module camera(type, show_lens = true) { //! Draw specified PCB camera
|
||||
pos = camera_connector_pos(type);
|
||||
color(grey(20))
|
||||
translate(pos)
|
||||
rounded_rectangle(conn, 0.5, center = false);
|
||||
rounded_rectangle(conn, 0.5);
|
||||
|
||||
flex = [5, 0.1];
|
||||
color("orange")
|
||||
|
@@ -326,7 +326,7 @@ module panel_USBA() { //! Draw a panel mount USBA connector
|
||||
dx = (length2 / 2 - r2);
|
||||
dy = (width / 2 - r1);
|
||||
translate_z(l)
|
||||
rounded_rectangle([length2, width, 1], r = r1, center = false);
|
||||
rounded_rectangle([length2, width, 1], r = r1);
|
||||
|
||||
translate([-dx, -dy, height2 - r2])
|
||||
rotate([90, 0, 0])
|
||||
|
@@ -80,7 +80,7 @@ module display(type) { //! Draw specified display
|
||||
translate_z(display_ts_thickness(type)) {
|
||||
difference() {
|
||||
color("silver")
|
||||
rounded_rectangle([w, h, t], 0.5, center = false);
|
||||
rounded_rectangle([w, h, t], 0.5);
|
||||
|
||||
color("black")
|
||||
translate([aperture[0].x, aperture[0].y, - eps])
|
||||
|
@@ -18,7 +18,11 @@
|
||||
//
|
||||
|
||||
//
|
||||
//! Used for limit switches.
|
||||
//! Used for limit switches. Currently only the button type is supported as the lever and roller types are less accurate.
|
||||
//!
|
||||
//! The switch is drawn with the button at the nominal operation point. This can be plus or minus `microswitch_op_tol(type)`.
|
||||
//!
|
||||
//! When the button is released it comes out by a maximum of `microswitch_fp_max(type)` from the nominal operating point.
|
||||
//
|
||||
include <../utils/core/core.scad>
|
||||
|
||||
@@ -32,11 +36,13 @@ function microswitch_hole_d(type) = type[6]; //! Screw hole diameter
|
||||
function microswitch_holes(type) = type[7]; //! Hole positions
|
||||
function microswitch_button_w(type) = type[8]; //! Button width
|
||||
function microswitch_button_t(type) = type[9]; //! Button thickness
|
||||
function microswitch_button_pos(type)= type[10]; //! Button position
|
||||
function microswitch_legs(type) = type[11]; //! Leg positions
|
||||
function microswitch_leg(type) = type[12]; //! Leg types
|
||||
function microswitch_body_clr(type) = type[13]; //! Body colour
|
||||
function microswitch_button_clr(type)= type[14]; //! Button colour
|
||||
function microswitch_button_pos(type)= type[10]; //! Button position at operating point
|
||||
function microswitch_op_tol(type) = type[11]; //! Operating position +/- tolerance
|
||||
function microswitch_fp_max(type) = type[12]; //! Free position maximum
|
||||
function microswitch_legs(type) = type[13]; //! Leg positions
|
||||
function microswitch_leg(type) = type[14]; //! Leg types
|
||||
function microswitch_body_clr(type) = type[15]; //! Body colour
|
||||
function microswitch_button_clr(type)= type[16]; //! Button colour
|
||||
|
||||
function microswitch_lower_extent(type) = let(leg = microswitch_leg(type)) min([for(pos = microswitch_legs(type)) pos.y - leg.y / 2]); //! How far legs extend downwards
|
||||
function microswitch_right_extent(type) = let(leg = microswitch_leg(type)) max([microswitch_length(type) / 2, for(pos = microswitch_legs(type)) pos.x + leg.x / 2]); //! How far legs extend right
|
||||
|
@@ -23,10 +23,19 @@
|
||||
small_leg = [0.9, 3.3, 0.4, 0];
|
||||
medium_leg = [0.5, 3.9, 3.2, 1.6, [0, -0.5]];
|
||||
large_leg = [11.4, 0.8, 6.3, 1.8, [1.7, 0]];
|
||||
|
||||
small_microswitch = ["small_microswitch", "DM1-00P-110-3", 5.8, 6.5, 12.8, 0, 2, [[-3.25, -1.65], [3.25, -1.65]], 2.9, 1.2, [-1.95, 3.75], [[-5.08, -4.95], [0, -4.9], [5.08, -4.9] ], small_leg, grey(20), "white" ];
|
||||
medium_microswitch = ["medium_microswitch","SS-01 or SS-5GL", 6.4, 10.2, 19.8, 1, 2.35, [[-4.8, -2.6 ], [4.7, -2.6 ]], 3.2, 2, [-2.8, 5.8 ], [[-8.05, -7.05], [0.75, -7.05], [8.05, -7.05] ], medium_leg, grey(20), "burlywood" ];
|
||||
large_microswitch = ["large_microswitch", "Saia G3 low force", 10.4, 15.9, 28.0, 2, 3.1, [[-11.1, -5.15], [11.2, 5.15]], 4, 2.75,[-9.1, 9.55], [[19.7, 2.19], [19.7, -3.45], [8.3, -10.45] ], large_leg, "ivory", "white" ];
|
||||
// t w l r h h b b b o f l l b b
|
||||
// h i e a o o u u u p p e e o u
|
||||
// i d n d l l t t t g g d t
|
||||
// c t g i e e t t t t m y t
|
||||
// k h t u o o o o a p t o
|
||||
// n h s d p n n n l x o y c n
|
||||
// e i o s p l
|
||||
// s a s w t p n e r c
|
||||
// n n o s l
|
||||
// s s r
|
||||
small_microswitch = ["small_microswitch", "DM1-00P-110-3", 5.8, 6.5, 12.8, 0, 2, [[-3.25, -1.65], [3.25, -1.65]], 2.9, 1.2, [-1.95, 3.75], 0.2, 0.55, [[-5.08, -4.95], [0, -4.9], [5.08, -4.9] ], small_leg, grey(20), "white" ];
|
||||
medium_microswitch = ["medium_microswitch","SS-01 or SS-5GL", 6.4, 10.2, 19.8, 1, 2.35, [[-4.8, -2.6 ], [4.7, -2.6 ]], 3.2, 2, [-2.8, 5.8 ], 0.5, 1.00, [[-8.05, -7.05], [0.75, -7.05], [8.05, -7.05] ], medium_leg, grey(20), "burlywood" ];
|
||||
large_microswitch = ["large_microswitch", "Saia G3 low force", 10.4, 15.9, 28.0, 2, 3.1, [[-11.1, -5.15], [11.2, 5.15]], 4, 2.75,[-9.1, 9.55], 0.3, 1.2, [[19.7, 2.19], [19.7, -3.45], [8.3, -10.45] ], large_leg, "ivory", "white" ]; //G3M1T1PUL
|
||||
|
||||
microswitches = [small_microswitch, medium_microswitch, large_microswitch];
|
||||
|
||||
|
@@ -59,7 +59,7 @@ module panel_meter_button(type) { //! Draw panel meter button
|
||||
color(pmeter_button_colour(type))
|
||||
translate(pmeter_button_pos(type))
|
||||
if(size.x)
|
||||
rounded_rectangle(pmeter_button_size(type), r, center = false);
|
||||
rounded_rectangle(pmeter_button_size(type), r);
|
||||
else
|
||||
cylinder(r = r, h = size.z);
|
||||
}
|
||||
@@ -93,8 +93,8 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
|
||||
difference() {
|
||||
if(is_list(bevel))
|
||||
hull() {
|
||||
rounded_rectangle([bezel.x - 2 * bevel.x, bezel.y - 2 * bevel.x, bezel.z], r - bevel.x, center = false);
|
||||
rounded_rectangle([bezel.x, bezel.y, bevel[1]], r, center = false);
|
||||
rounded_rectangle([bezel.x - 2 * bevel.x, bezel.y - 2 * bevel.x, bezel.z], r - bevel.x);
|
||||
rounded_rectangle([bezel.x, bezel.y, bevel[1]], r);
|
||||
}
|
||||
else
|
||||
hull() {
|
||||
@@ -111,7 +111,7 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
|
||||
cube([ap.x + ap.z, ap.y + ap.z, eps], center = true);
|
||||
|
||||
translate_z(bezel.z + eps)
|
||||
rounded_rectangle([ap.x, ap.y, bezel.z * 2], r, center = true);
|
||||
rounded_rectangle([ap.x, ap.y, bezel.z * 2], r, true);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@@ -126,7 +126,7 @@ module usb_A(h, v_flange_l, bar, cutout) {
|
||||
if(cutout)
|
||||
rotate([90, 0, 90])
|
||||
rounded_rectangle([w + 2 * v_flange_h + 2 * panel_clearance,
|
||||
h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r, center = false);
|
||||
h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r);
|
||||
else {
|
||||
color("silver") rotate([0, 90, 0]) {
|
||||
linear_extrude(l, center = true)
|
||||
|
@@ -21,6 +21,7 @@ include <d_connectors.scad>
|
||||
include <leds.scad>
|
||||
include <axials.scad>
|
||||
include <smds.scad>
|
||||
include <green_terminals.scad>
|
||||
|
||||
//
|
||||
// l w t r h l c b h
|
||||
@@ -195,6 +196,312 @@ Duex5 = ["Duex5", "Duex5 expansion board",
|
||||
]),
|
||||
[]];
|
||||
|
||||
BTT_SKR_MINI_E3_V2_0 = [
|
||||
"BTT_SKR_MINI_E3_V2_0", "BigTreeTech SKR Mini E3 v2.0",
|
||||
100.75, 70.25, 1.6, // size
|
||||
1, // corner radius
|
||||
3, // mounting hole diameter
|
||||
5, // pad around mounting hole
|
||||
grey(30), // color
|
||||
false, // true if parts should be separate BOM items
|
||||
[ // hole positions
|
||||
for (i = [ [0, 0], [62.15, 0] ])
|
||||
(i + [20.3, -2.89]),
|
||||
for (i = [ [0, -34.98], [31.80, -37.63], [95.68, -64.47] ])
|
||||
(i + [2.535, -2.89])
|
||||
],
|
||||
[ // components
|
||||
// cpu
|
||||
[ 55, 33, 0, "chip", 10, 10, 1, grey(15) ],
|
||||
// driver chips
|
||||
for (x = [10.5, 30.5, 50.5, 70.5])
|
||||
[ x, -17.5, 0, "chip", 5, 5, 1, grey(15) ],
|
||||
// mock up heat sinks over the chips
|
||||
for (x = [10.5, 30.5, 50.5, 70.5])
|
||||
[ x, -17.5, 0, "block", 9, 8.5, 2, "DeepSkyBlue" ],
|
||||
for(x = [10.5, 30.5, 50.5, 70.5], y = [-4,-2,0,2,4])
|
||||
[ x, -17.5 + y, 0, "block", 9, 0.75, 11, "DeepSkyBlue" ],
|
||||
// heat dissipation for drivers under board
|
||||
[ 43, -17.5, 0, "-block", 85, 8, 0.1, gold ],
|
||||
|
||||
// heated bed
|
||||
[ 26, 16, 0, "chip", 9.5, 8.5, 4, grey(15) ],
|
||||
[ 27, 19, 0, "-block", 13, 14, 0.1, gold ],
|
||||
// hotend
|
||||
[ 37, 14, 0, "chip", 6, 6, 2.5, grey(15) ],
|
||||
[ 40, 16, 0, "-block", 10, 8, 0.1, gold ],
|
||||
|
||||
// voltage regulator heat dissipation
|
||||
[ 12, 28.5, 0, "-block", 11, 7, 0.1, gold ],
|
||||
|
||||
// terminals
|
||||
[ 5.25, 5.3, 180, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 18.1, 5.1, -90, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 29.3, 5.1, -90, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 40.5, 5.1, -90, "gterm", gt_5x11, 2, undef, grey(20) ],
|
||||
// SD and USB
|
||||
[ -3, -(22.27 + 29.92)/2, 0, "usb_uA" ],
|
||||
[ -8, -( 2.13 + 17.17)/2, 0, "uSD", [17.17 - 2.13, 16, 2] ],
|
||||
// EXP
|
||||
[ -4.5, 17, -90, "2p54boxhdr", 5, 2 ],
|
||||
// TFT
|
||||
[ 66.1, 21.7, 0, "2p54header", 5, 1 ],
|
||||
// FAN0
|
||||
[ 50.25, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
// FAN1
|
||||
[ 49.9, 16.1, 0, "jst_xh", 2, false, grey(20) ],
|
||||
// PS-ON
|
||||
[ 58.1, 16.1, 0, "jst_xh", 2, false, grey(20) ],
|
||||
// PWR-DET
|
||||
[ 67.5, 16.0, 0, "jst_xh", 3, false, grey(20) ],
|
||||
// E0-STOP
|
||||
[ 78.2, 16.0, 0, "jst_xh", 3, false, grey(20) ],
|
||||
// Z-PROBE
|
||||
[ 87.2, 20.5, -90,"jst_xh", 5, false, grey(20) ],
|
||||
// NEO Pixel
|
||||
[ 78.2, 27.1, 0, "jst_xh", 3, false, grey(20) ],
|
||||
// end stops
|
||||
[ 58.60, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
[ 66.70, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
[ 74.90, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
// thermistors
|
||||
[ 83.00, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
[ 91.10, 3.8, 0, "jst_xh", 2, false, grey(20) ],
|
||||
// motor connections
|
||||
[ 10.15, -4.2, 0, "jst_xh", 4, false, grey(20) ],
|
||||
[ 30.35, -4.2, 0, "jst_xh", 4, false, grey(20) ],
|
||||
[ 43.90, -4.2, 0, "jst_xh", 4, false, grey(20) ],
|
||||
[ 57.25, -4.2, 0, "jst_xh", 4, false, grey(20) ],
|
||||
[ 70.75, -4.2, 0, "jst_xh", 4, false, grey(20) ],
|
||||
// motor jumpers
|
||||
[ 20.6, 44.1, 0, "2p54header", 2, 1 ],
|
||||
[ 39.6, 44.2, 0, "2p54header", 2, 1 ],
|
||||
[ 60.1, 44.1, 0, "2p54header", 2, 1 ],
|
||||
[ 80.3, 44.1, 0, "2p54header", 2, 1 ],
|
||||
// SWD
|
||||
[ 43.9, 39.2, 0, "2p54header", 1, 5 ],
|
||||
// SPI
|
||||
[ -3.1, 31.9, 0, "2p54header", 2, 3 ],
|
||||
// PWR-1
|
||||
[ -12.8, 30.3, 0, "2p54header", 3, 1 ],
|
||||
// VOUT
|
||||
[ -14.0, 34.4, 0, "2p54header", 2, 2 ],
|
||||
// VIN
|
||||
[ 17.3, 19.6, 0, "2p54header", 2, 2 ],
|
||||
],
|
||||
[] // accessories
|
||||
];
|
||||
|
||||
BTT_SKR_E3_TURBO = [
|
||||
"BTT_SKR_E3_TURBO", "BigTreeTech SKR E3 Turbo",
|
||||
102, 90.25, 1.6, // size
|
||||
1, // corner radius
|
||||
3.5, // mounting hole diameter
|
||||
5, // pad around mounting hole
|
||||
grey(30), // color
|
||||
false, // true if parts should be separate BOM items
|
||||
[ // hole positions
|
||||
for ( i=[ [0, 0], [62.15, 0.25] ])
|
||||
(i + [21.6, -13.3]),
|
||||
for( i=[ [0, -34.98 ], [31.80, -37.62 ], [95.68, -64.47] ])
|
||||
(i + [3.75, -13.25])
|
||||
],
|
||||
[ // components
|
||||
// cpu
|
||||
[ 62.8, 42.5, 0, "chip", 14, 14, 1, grey(15) ],
|
||||
// driver chips
|
||||
for (x = [8.5, 27.5, 43.2, 58.5, 74])
|
||||
[x, -20, 0, "chip", 5, 5, 1, grey(15)],
|
||||
// mock up heat sinks over the chips
|
||||
for (x = [8.5, 27.5, 43.2, 58.5, 74])
|
||||
[x, -20, 0, "chip", 9, 8.5, 2, "DeepSkyBlue" ],
|
||||
for (x = [8.5, 27.5, 43.2, 58.5, 74], y = [-4,-2,0,2,4])
|
||||
[x, -20 + y, 0, "chip", 9, 0.75, 11, "DeepSkyBlue" ],
|
||||
// heat dissipation for drivers under board
|
||||
[ 43, -21, 0, "-block", 85, 8, 0.1, gold ],
|
||||
// hotend and heated bed
|
||||
[ 25.5, 20, 0, "chip", 10, 8.5, 4, grey(15) ],
|
||||
[ 25.5, 20, 0, "-block", 11, 11, 0.1, gold ],
|
||||
[ 36.25, 16.75, 0, "chip", 6.5, 6, 2.5, grey(15) ],
|
||||
[ 36.25, 17, 0, "-block", 7.5, 7.5, 0.1, gold ],
|
||||
[ 44.25, 16.75, 0, "chip", 6.5, 6, 2.5, grey(15) ],
|
||||
[ 44.25, 17, 0, "-block", 7.5, 7.5, 0.1, gold ],
|
||||
// voltage regulator
|
||||
[ 15.1, 44.2, 0, "chip", 4, 5, 2, grey(15) ],
|
||||
[ 12.1, 44.2, 0, "-block", 10, 10, 0.1, gold ],
|
||||
|
||||
// terminals
|
||||
[ 5.25, 5.3, 180, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 16.25, 5.4, -90, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 26.25, 5.4, -90, "gterm", gt_5x17, 2, undef, grey(20) ],
|
||||
[ 36.1, 6.7, -90, "gterm", gt_5x11, 2, undef, "lightgreen" ],
|
||||
[ 45.0, 6.7, -90, "gterm", gt_5x11, 2, undef, "lightgreen" ],
|
||||
[ -3, -(32.27 + 39.92)/2, 0, "usb_uA" ],
|
||||
[ -8, -(12.13 + 27.17)/2, 0, "uSD", [17.17 - 2.13, 16, 2] ],
|
||||
[ -22.2, 51.6, 0, "button_6mm" ],
|
||||
// EXP
|
||||
[ -4.45, 27.2, -90, "2p54boxhdr", 5, 2 ],
|
||||
// AUX-2
|
||||
[ -3.4, 42.5, -90, "2p54header", 4, 2 ],
|
||||
// TFT
|
||||
[ 73.7, 21, 0, "2p54header", 5, 1 ],
|
||||
// FAN0
|
||||
[ 52.1, 15.3, 180, "jst_xh", 2, false, grey(20) ],
|
||||
// FAN1
|
||||
[ 60.1, 15.3, 180, "jst_xh", 2, false, grey(20) ],
|
||||
// PS-ON
|
||||
[ 67.9, 15.3, 180, "jst_xh", 2, false, grey(20) ],
|
||||
// E0-STOP
|
||||
[ 77.1, 15.3, 180, "jst_xh", 3, false, grey(20) ],
|
||||
// E1-STOP
|
||||
[ 87.5, 15.3, 180, "jst_xh", 3, false, grey(20) ],
|
||||
// Z-PROBE
|
||||
[ 85.05, 34.6, 180, "jst_xh", 5, false, grey(20) ],
|
||||
// NEO Pixel
|
||||
[ 77, 26.8, 180, "jst_xh", 3, false, grey(20) ],
|
||||
// PWR-DET
|
||||
[ 87.7, 26.8, 180, "jst_xh", 3, false, grey(20) ],
|
||||
// FAN2
|
||||
[ 52.1, 3.8, 0, "2p54header", 1, 2],
|
||||
// end stops and thermistors
|
||||
for (x = [58.5 : 7.9 : 98.1])
|
||||
[x, 3.7, 180, "jst_xh", 2, false, grey(20)],
|
||||
// motor connections
|
||||
for (x = [7, 27.1, 47.3, 67.5, 87.9])
|
||||
[x, -3.9, 0, "jst_xh", 4, false, grey(20)],
|
||||
[47.3, -10.4, 0, "jst_xh", 4, false, grey(20)], // second Z connector
|
||||
// motor jumpers
|
||||
for (x = [9.4, 26.4, 42.5, 58.7, 75.3])
|
||||
[x, -33.7, 0, "2p54header", 2, 1],
|
||||
// SWD
|
||||
[ 45.4, 35.7, 0, "2p54header", 5, 1 ],
|
||||
// USB power jumber
|
||||
[ -12.6, 40.3, 0, "2p54header", 3, 1 ],
|
||||
// VOUT
|
||||
[ -13.9, 44.5, 0, "2p54header", 2, 2 ],
|
||||
// VIN
|
||||
[ 18.6, 29.8, 0, "2p54header", 2, 2 ],
|
||||
],
|
||||
[] // accessories
|
||||
];
|
||||
|
||||
TMC2130 = [
|
||||
"TMC2130", "TMC2130",
|
||||
20, 14, 1.6, // size
|
||||
0, 0, 0, // corner radius, mounting hole diameter, pad around mounting hole
|
||||
grey(95), // colour
|
||||
false, // true if parts should be separate BOM items
|
||||
[], // hole positions
|
||||
[
|
||||
[ 10, 1, 0, "-2p54header", 8, 1 ],
|
||||
[ 10, 13, 0, "-2p54header", 8, 1 ],
|
||||
[ 12, 7, 0, "-chip", 6, 4, 1, grey(20) ],
|
||||
// mock up a heat sink
|
||||
[ 10, 7, 0, "block", 9, 8.5, 2, "DeepSkyBlue" ],
|
||||
for (y = [-4,-2,0,2,4]) [ 10, 7 + y, 0, "block", 9, 0.75, 11, "DeepSkyBlue" ],
|
||||
],
|
||||
[]
|
||||
];
|
||||
|
||||
BTT_SKR_V1_4_TURBO = [
|
||||
"BTT_SKR_V1_4_TURBO", "BigTreeTech SKR v1.4 Turbo",
|
||||
110, 85, 1.6, // size
|
||||
1, // corner radius
|
||||
3, // mounting hole diameter
|
||||
4, // pad around mounting hole
|
||||
grey(30), // colour
|
||||
false, // true if parts should be separate BOM items
|
||||
[ // hole positions
|
||||
[-4, 4], [-4, -4], [4, -4], [4, 4]
|
||||
],
|
||||
[ // components
|
||||
[ (29.15+31.5)/2, 8, -90, "usb_B" ],
|
||||
[ (46.9+51.55)/2, 7, -90, "uSD", [14, 14, 2] ],
|
||||
[ 105, 13, 0, "button_6mm" ],
|
||||
[ 58, 43, 0, "chip", 15, 15, 1, grey(20) ],
|
||||
// ESP-01 socket
|
||||
[ 69.8, 4, 0, "2p54socket", 4, 2 ],
|
||||
// terminals
|
||||
[ 5.3, 13.2, 180, "gterm", gt_5x17, 2, undef, grey(20)],
|
||||
[ 5.3, 25.8, 180, "gterm", gt_5x17, 2, undef, grey(20)],
|
||||
[ 5.3, 37.2, 180, "gterm", gt_5x11, 2, undef, grey(20)],
|
||||
[ 5.3, 47.2, 180, "gterm", gt_5x11, 2, undef, grey(20)],
|
||||
|
||||
[ 2.8, 56.7, -90, "jst_xh", 2, false, grey(20) ],
|
||||
[ 10.9, 56.7, 90, "jst_xh", 2, false, grey(20) ],
|
||||
[ 82, 4, 0, "jst_xh", 2, false, grey(20) ],
|
||||
[ 90, 4, 0, "jst_xh", 2, false, grey(20) ],
|
||||
[ 98, 4, 0, "jst_xh", 2, false, grey(20) ],
|
||||
|
||||
[ 87.7, 29.0, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 87.7, 39.5, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 87.7, 50.1, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 95.3, 29.0, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 95.3, 39.5, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 95.3, 50.1, -90, "jst_xh", 3, false, grey(20) ],
|
||||
|
||||
[ 85.7, 18.2, 180, "jst_xh", 3, false, grey(20) ],
|
||||
[ 94.9, 18.2, 180, "jst_xh", 2, false, grey(20) ],
|
||||
[ 77.2, 19.6, -90, "jst_xh", 3, false, grey(20) ],
|
||||
[ 69.8, 11.0, 0, "jst_xh", 5, false, grey(20) ],
|
||||
|
||||
[ 69.0, 19.2, 0, "2p54header", 4, 1 ],
|
||||
[ 57.8, 18.0, 0, "2p54header", 3, 2 ],
|
||||
[ 28.0, 19.7, 0, "2p54header", 2, 2 ],
|
||||
|
||||
[ 37.6, 28.8, 0, "2p54header", 1, 3, undef, "red" ],
|
||||
[ 77.8, 27.5, 0, "2p54header", 2, 2 ],
|
||||
[ 81.8, 26.4, 0, "2p54header", 1, 3, undef, "red" ],
|
||||
[ 43.8, 42.8, 0, "2p54header", 1, 5 ],
|
||||
|
||||
// EXP1 & EXP2
|
||||
[ -6.6, 29.4, 90, "2p54boxhdr", 5, 2 ],
|
||||
[ -6.6, 50.4, 90, "2p54boxhdr", 5, 2 ],
|
||||
|
||||
// motor axes connections
|
||||
[ 11.2, -3.75, 180, "jst_xh", 2, false, grey(20) ],
|
||||
[ 21.8, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 35.0, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 48.2, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 61.4, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 74.7, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 87.9, -3.75, 180, "jst_xh", 4, false, grey(20) ],
|
||||
[ 98.5, -3.75, 180, "jst_xh", 2, false, grey(20) ],
|
||||
|
||||
// stepper drivers
|
||||
[ 11.5, 62.5, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 11.5, 75.2, 0, "2p54socket", 8, 1 ],
|
||||
[ 2.6, 66.3, 90, "2p54socket", 2, 1, undef, undef, undef, "red" ],
|
||||
[ 11.5, 68.85, 0, "pcb", 11, TMC2130 ],
|
||||
|
||||
[ 33.1, 62.5, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 33.1, 75.2, 0, "2p54socket", 8, 1 ],
|
||||
[ 24.2, 66.3, 90, "2p54socket", 2, 1, undef, undef, undef, "red" ],
|
||||
[ 33.1, 68.85, 0, "pcb", 11, TMC2130 ],
|
||||
|
||||
[ 54.8, 62.5, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 54.8, 75.2, 0, "2p54socket", 8, 1 ],
|
||||
[ 45.9, 66.3, 90, "2p54socket", 2, 1, undef, undef, undef, "red" ],
|
||||
[ 54.8, 68.85, 0, "pcb", 11, TMC2130 ],
|
||||
|
||||
[ 76.4, 62.5, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 76.4, 75.2, 0, "2p54socket", 8, 1 ],
|
||||
[ 67.5, 66.3, 90, "2p54socket", 2, 1, undef, undef, undef, "red" ],
|
||||
[ 76.4, 68.85, 0, "pcb", 11, TMC2130 ],
|
||||
|
||||
[ 98.1, 62.5, 0, "2p54socket", 8, 1, undef, undef, undef, "red" ],
|
||||
[ 98.1, 75.2, 0, "2p54socket", 8, 1 ],
|
||||
[ 89.2, 66.3, 90, "2p54socket", 2, 1, undef, undef, undef, "red" ],
|
||||
|
||||
// closed loop pins
|
||||
[ 24.4, 57.5, 0, "2p54header", 6, 1 ],
|
||||
[ 40.6, 57.5, 0, "2p54header", 6, 1 ],
|
||||
[ 56.7, 57.5, 0, "2p54header", 6, 1 ],
|
||||
[ 72.9, 57.5, 0, "2p54header", 6, 1 ],
|
||||
[ 89.1, 57.5, 0, "2p54header", 6, 1 ],
|
||||
],
|
||||
[] // accessories
|
||||
];
|
||||
|
||||
Melzi = ["Melzi", "Melzi electronics", 203.2, 49.53, 1.6, 3.81, 3.1, 6, "green", false, [[3.81, 3.81], [-3.81, 3.81], [-3.81, -3.81], [3.81, -3.81]],
|
||||
[],
|
||||
@@ -440,7 +747,9 @@ ESP_01 = [
|
||||
[] // accessories
|
||||
];
|
||||
|
||||
pcbs = [MP1584EN, TP4056, ESP_01, MT3608, RAMPSEndstop, ExtruderPCB, PI_IO, ZC_A0591, RPI0, EnviroPlus, ArduinoUno3, ArduinoLeonardo, Keyes5p1, PSU12V1A, WD2002SJ, RPI3, RPI4, DuetE, Duex2, Duex5];
|
||||
pcbs = [MP1584EN, TP4056, ESP_01, RAMPSEndstop, MT3608, PI_IO, ExtruderPCB, ZC_A0591, RPI0, EnviroPlus, ArduinoUno3, ArduinoLeonardo, WD2002SJ, RPI3, RPI4, BTT_SKR_MINI_E3_V2_0, BTT_SKR_E3_TURBO, BTT_SKR_V1_4_TURBO, DuetE, Duex5];
|
||||
|
||||
pcbs_not_shown = [Melzi, Duex2, PSU12V1A, Keyes5p1];
|
||||
|
||||
perfboards = [PERF74x51, PERF70x50, PERF60x40, PERF70x30, PERF80x20];
|
||||
|
||||
|
@@ -53,7 +53,7 @@ function pulley_extent(type) = max(pulley_flange_dia(type), pulley_hub_dia(type)
|
||||
T_angle = 40;
|
||||
GT_r = 0.555;
|
||||
|
||||
module pulley(type) { //! Draw a pulley
|
||||
module pulley(type, colour = silver) { //! Draw a pulley
|
||||
teeth = pulley_teeth(type);
|
||||
od = pulley_od(type);
|
||||
|
||||
@@ -117,7 +117,7 @@ module pulley(type) { //! Draw a pulley
|
||||
rotate([-90, 0, i * -90])
|
||||
cylinder(r = screw_radius(pulley_screw(type)), h = 100);
|
||||
|
||||
color(silver) {
|
||||
color(colour) {
|
||||
if(screw_z && screw_z < hl)
|
||||
render()
|
||||
difference() {
|
||||
@@ -140,9 +140,9 @@ module pulley(type) { //! Draw a pulley
|
||||
}
|
||||
}
|
||||
|
||||
module pulley_assembly(type) { //! Draw a pulley with its grub screws in place
|
||||
module pulley_assembly(type, colour = silver) { //! Draw a pulley with its grub screws in place
|
||||
translate_z(pulley_offset(type)) {
|
||||
pulley(type);
|
||||
pulley(type, colour);
|
||||
|
||||
if(pulley_screws(type))
|
||||
translate_z(pulley_screw_z(type))
|
||||
|
@@ -31,13 +31,11 @@ function rail_bore(type) = type[5]; //! Counter bore diameter for screw
|
||||
function rail_hole(type) = type[6]; //! Screw hole diameter
|
||||
function rail_bore_depth(type) = type[7]; //! Counter bore depth
|
||||
function rail_screw(type) = type[8]; //! Screw type
|
||||
function rail_carriage(type) = type[9]; //! Carriage type
|
||||
function rail_end_screw(type) = type[10]; //! Screw used for ends only (Countersink used for better location)
|
||||
function rail_groove_offset(type)=type[11]; //! Offset of centre of groove from top of rail
|
||||
function rail_groove_width(type)=type[12]; //! Groove width
|
||||
function rail_end_screw(type) = type[9]; //! Screw used for ends only (Countersink used for better location)
|
||||
function rail_groove_offset(type)=type[10]; //! Offset of centre of groove from top of rail
|
||||
function rail_groove_width(type)=type[11]; //! Groove width
|
||||
|
||||
function rail_screw_height(type, screw) = rail_height(type) - rail_bore_depth(type) + screw_head_depth(screw, rail_hole(type)); //! Position screw taking into account countersink into counterbored hole
|
||||
function rail_travel(type, length) = length - carriage_length(rail_carriage(type)); //! How far the carriage can travel
|
||||
|
||||
function carriage_length(type) = type[0]; //! Overall length
|
||||
function carriage_block_length(type) = type[1]; //! Length of the metal part
|
||||
@@ -48,7 +46,9 @@ function carriage_clearance(type) = type[4]; //! Gap under the carriage
|
||||
function carriage_pitch_x(type) = type[5]; //! Screw hole x pitch
|
||||
function carriage_pitch_y(type) = type[6]; //! Screw hole y pitch
|
||||
function carriage_screw(type) = type[7]; //! Carriage screw type
|
||||
function carriage_rail(type) = type[8]; //! Rail type
|
||||
function carriage_screw_depth(type) = 2 * screw_radius(carriage_screw(type)); //! Carriage thread depth
|
||||
function carriage_travel(type, rail_length) = rail_length - carriage_length(type); //! How far the carriage can travel on a given length rail
|
||||
|
||||
function rail_holes(type, length) = //! Number of holes in a rail given its `length`
|
||||
floor((length - 2 * rail_end(type)) / rail_pitch(type)) + 1;
|
||||
@@ -73,7 +73,7 @@ module carriage_hole_positions(type) { //! Position children over screw holes
|
||||
children();
|
||||
}
|
||||
|
||||
module carriage(type, rail, end_colour = grey(20), wiper_colour = grey(20)) { //! Draw the specified carriage
|
||||
module carriage(type, end_colour = grey(20), wiper_colour = grey(20)) { //! Draw the specified carriage
|
||||
total_l = carriage_length(type);
|
||||
block_l = carriage_block_length(type);
|
||||
block_w = carriage_width(type);
|
||||
@@ -85,9 +85,9 @@ module carriage(type, rail, end_colour = grey(20), wiper_colour = grey(20)) { //
|
||||
screw_depth = carriage_screw_depth(type);
|
||||
|
||||
module cutout() {
|
||||
w = rail_width(rail) + 0.4;
|
||||
w = rail_width(carriage_rail(type)) + 0.4;
|
||||
translate([-w / 2, 0])
|
||||
square([w , rail_height(rail) + 0.2]);
|
||||
square([w , rail_height(carriage_rail(type)) + 0.2]);
|
||||
}
|
||||
|
||||
color(grey(90)) {
|
||||
@@ -179,11 +179,11 @@ module rail(type, length, colour = grey(90), use_polycircles = false) { //! Draw
|
||||
}
|
||||
}
|
||||
|
||||
module rail_assembly(type, length, pos, carriage_end_colour = grey(20), carriage_wiper_colour = grey(20)) { //! Rail and carriage assembly
|
||||
rail(type, length);
|
||||
module rail_assembly(carriage, length, pos, carriage_end_colour = grey(20), carriage_wiper_colour = grey(20)) { //! Rail and carriage assembly
|
||||
rail(carriage_rail(carriage), length);
|
||||
|
||||
translate([pos, 0])
|
||||
carriage(rail_carriage(type), type, carriage_end_colour, carriage_wiper_colour);
|
||||
carriage(carriage, carriage_end_colour, carriage_wiper_colour);
|
||||
}
|
||||
|
||||
module rail_screws(type, length, thickness, screws = 100, index_screws = undef) { //! Place screws in the rail
|
||||
|
@@ -17,30 +17,29 @@
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
// Carriages
|
||||
//
|
||||
// L L1 W H H1 C B
|
||||
MGN5_carriage = [ 16, 9.6, 12, 6, 1.5, 0, 8 , M2_cap_screw ];
|
||||
MGN7_carriage = [ 23, 14.3, 17, 8, 1.5, 8, 12, M2_cap_screw ];
|
||||
MGN9_carriage = [ 29.7, 20.8, 20, 10, 2, 10, 15, M3_cap_screw ];
|
||||
MGN12_carriage = [ 34.7, 21.7, 27, 13, 3, 15, 20, M3_cap_screw ];
|
||||
MGN12H_carriage= [ 45.4, 32.4, 27, 13, 3, 20, 20, M3_cap_screw ];
|
||||
MGN15_carriage = [ 43.3, 27.7, 32, 16, 4, 20, 25, M3_cap_screw ];
|
||||
SSR15_carriage = [ 40.3, 23.3, 34, 24, 4.5, 0, 26, M4_cap_screw ];
|
||||
//
|
||||
// Rails
|
||||
//
|
||||
// Wr Hr E P D d h go gw
|
||||
MGN5 = [ "MGN5", 5, 3.6, 5, 15, 3.6, 2.4, 0.8, M2_cs_cap_screw, M2_cs_cap_screw, 1, 1 ]; // Screw holes too small for M2 heads
|
||||
MGN7 = [ "MGN7", 7, 5, 5, 15, 4.3, 2.4, 2.6, M2_cap_screw, M2_cs_cap_screw, 1.5, 1.5 ];
|
||||
MGN9 = [ "MGN9", 9, 6, 5, 20, 6.0, 3.5, 3.5, M3_cap_screw, M3_cs_cap_screw, 1.5, 1.5 ];
|
||||
MGN12 =[ "MGN12", 12, 8, 10, 25, 6.0, 3.5, 4.5, M3_cap_screw, M3_cs_cap_screw, 2.25, 2.75];
|
||||
MGN15 =[ "MGN15", 15, 10, 10, 40, 6.0, 3.5, 5.0, M3_cap_screw, M3_cs_cap_screw, 2.5, 2.75 ];
|
||||
SSR15= [ "SSR15", 15, 12.5, 10, 60, 7.5, 4.5, 5.3, M4_cap_screw, M4_cs_cap_screw, 2.5, 2.75 ];
|
||||
//
|
||||
// Wr Hr E P D d h go gw
|
||||
MGN5 = [ "MGN5", 5, 3.6, 5, 15, 3.6, 2.4, 0.8, M2_cs_cap_screw, MGN5_carriage, M2_cs_cap_screw, 1, 1 ]; // Screw holes too small for M2 heads
|
||||
MGN7 = [ "MGN7", 7, 5, 5, 15, 4.3, 2.4, 2.6, M2_cap_screw, MGN7_carriage, M2_cs_cap_screw, 1.5, 1.5 ];
|
||||
MGN9 = [ "MGN9", 9, 6, 7.5, 20, 6.0, 3.5, 3.5, M3_cap_screw, MGN9_carriage, M3_cs_cap_screw, 1.5, 1.5 ];
|
||||
MGN12= [ "MGN12", 12, 8, 10, 25, 6.0, 3.5, 4.5, M3_cap_screw, MGN12_carriage, M3_cs_cap_screw, 2.25, 2.75 ];
|
||||
MGN12H=[ "MGN12H",12, 8, 10, 25, 6.0, 3.5, 4.5, M3_cap_screw, MGN12H_carriage,M3_cs_cap_screw, 2.25, 2.75];
|
||||
MGN15= [ "MGN15", 15, 10, 10, 40, 6.0, 3.5, 5.0, M3_cap_screw, MGN15_carriage, M3_cs_cap_screw, 2.5, 2.75 ];
|
||||
SSR15= [ "SSR15", 15, 12.5,10, 60, 7.5, 4.5, 5.3, M4_cap_screw, SSR15_carriage, M4_cs_cap_screw, 2.5, 2.75 ];
|
||||
// Carriages
|
||||
//
|
||||
// L L1 W H H1 C B
|
||||
MGN5_carriage = [ 16, 9.6, 12, 6, 1.5, 0, 8, M2_cap_screw, MGN5 ];
|
||||
MGN7C_carriage = [ 23, 14.3, 17, 8, 1.5, 8, 12, M2_cap_screw, MGN7 ];
|
||||
MGN9C_carriage = [ 29.7, 20.8, 20, 10, 2, 10, 15, M3_cap_screw, MGN9 ];
|
||||
MGN12C_carriage = [ 34.7, 21.7, 27, 13, 3, 15, 20, M3_cap_screw, MGN12 ];
|
||||
MGN12H_carriage = [ 45.4, 32.4, 27, 13, 3, 20, 20, M3_cap_screw, MGN12 ];
|
||||
MGN15C_carriage = [ 43.3, 27.7, 32, 16, 4, 20, 25, M3_cap_screw, MGN15 ];
|
||||
SSR15_carriage = [ 40.3, 23.3, 34, 24, 4.5, 0, 26, M4_cap_screw, SSR15 ];
|
||||
|
||||
rails = [MGN5, MGN7, MGN9, MGN12, MGN12H, MGN15, SSR15];
|
||||
|
||||
carriages = [MGN5_carriage, MGN7C_carriage, MGN9C_carriage, MGN12C_carriage, MGN12H_carriage, MGN15C_carriage, SSR15_carriage];
|
||||
|
||||
use <rail.scad>
|
||||
|
@@ -83,6 +83,7 @@ M5_cs_cap_screw = ["M5_cs_cap","M5 cs cap", hs_cs_cap,5,10.0, 0, 3.00,3.0
|
||||
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];
|
||||
M5_dome_screw = ["M5_dome", "M5 dome", hs_dome, 5, 9.5, 2.75, 1.56,3.0, 22, M5_washer, M5_nut, M5_tap_radius, M5_clearance_radius];
|
||||
|
||||
M2p5_pan_screw = ["M2p5_pan", "M2.5 pan", hs_pan, 2.5, 4.7, 1.7, 0, 0, 0, M2p5_washer, M2p5_nut, M2p5_tap_radius, M2p5_clearance_radius];
|
||||
M3_pan_screw = ["M3_pan", "M3 pan", hs_pan, 3, 5.4, 2.0, 0, 0, 0, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
|
||||
@@ -111,7 +112,7 @@ screw_lists = [
|
||||
[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw],
|
||||
[ 0, 0, M3_low_cap_screw],
|
||||
[ M2_cs_cap_screw, 0, M3_cs_cap_screw, M4_cs_cap_screw, M5_cs_cap_screw],
|
||||
[ M2_dome_screw, 0, M3_dome_screw, M4_dome_screw],
|
||||
[ M2_dome_screw, 0, M3_dome_screw, M4_dome_screw, M5_dome_screw],
|
||||
[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw],
|
||||
[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, M5_pan_screw, M6_pan_screw, No632_pan_screw],
|
||||
[ No2_screw, 0, No4_screw, No6_screw, No6_cs_screw],
|
||||
|
@@ -45,11 +45,14 @@ Foam20 = [ "Foam20", "Foam sponge", 20,[0.3, 0.3, 0.3, 1 ],
|
||||
AL6 = [ "AL6", "Aluminium tooling plate", 6, [0.9, 0.9, 0.9, 1 ], false];
|
||||
AL8 = [ "AL8", "Aluminium tooling plate", 8, [0.9, 0.9, 0.9, 1 ], false];
|
||||
Steel06 = [ "Steel06", "Sheet mild steel", 0.6,"silver" , false];
|
||||
CF1 = [ "CF1", "Sheet carbon fiber", 1, grey(30), false, 2, 2, grey(25)];
|
||||
CF2 = [ "CF2", "Sheet carbon fiber", 2, grey(30), false, 2, 2, grey(25)];
|
||||
CF3 = [ "CF3", "Sheet carbon fiber", 3, grey(30), false, 2, 2, grey(25)];
|
||||
Spring05 = [ "Spring05", "Bi-metal saw blade", 0.5,"#FBC300", false];
|
||||
Silicone3 = [ "Silicone3", "Sheet silicone", 3, [0.9, 0.9, 0.9, 0.95 ], false];
|
||||
CF1 = [ "CF1", "Sheet carbon fiber", 1, grey(35), false, 2, 2, grey(20)];
|
||||
CF2 = [ "CF2", "Sheet carbon fiber", 2, grey(35), false, 2, 2, grey(20)];
|
||||
CF3 = [ "CF3", "Sheet carbon fiber", 3, grey(35), false, 2, 2, grey(20)];
|
||||
|
||||
|
||||
sheets = [CF1, CF2, CF3, MDF6, MDF10, MDF12, MDF19, PMMA2, PMMA3, PMMA6, PMMA8, PMMA10, glass2, DiBond, DiBond6, Cardboard, FoilTape, Foam20, AL6, AL8, Steel06];
|
||||
sheets = [CF1, CF2, CF3, MDF6, MDF10, MDF12, MDF19, PMMA2, PMMA3, PMMA6, PMMA8, PMMA10,
|
||||
glass2, DiBond, DiBond6, Cardboard, FoilTape, AL6, AL8, Steel06, Spring05, Silicone3, Foam20];
|
||||
|
||||
use <sheet.scad>
|
||||
|
@@ -62,7 +62,7 @@ module sk_bracket(type) { //! SK shaft support bracket
|
||||
}
|
||||
for(x = [W / 2 - 2 * fillet, -W / 2 + 2 * fillet])
|
||||
translate([x, G / 2, 0])
|
||||
rounded_rectangle([4 * fillet, G, L], fillet);
|
||||
rounded_rectangle([4 * fillet, G, L], fillet, true);
|
||||
}
|
||||
|
||||
translate([0, -h, -L /2])
|
||||
|
@@ -56,10 +56,10 @@ module transformer(type) { //! Draw specified transformer
|
||||
|
||||
}
|
||||
|
||||
color("white") {
|
||||
color("white")
|
||||
translate_z(tx_lamination_height(type) / 2 + tx_bobbin_offset(type) / 2)
|
||||
rounded_rectangle([tx_bobbin_width(type), tx_depth(type), tx_bobbin_height(type)], r = tx_bobbin_radius(type));
|
||||
}
|
||||
rounded_rectangle([tx_bobbin_width(type), tx_depth(type), tx_bobbin_height(type)], tx_bobbin_radius(type), true);
|
||||
|
||||
terminal_height = tx_height(type) - tx_lamination_height(type);
|
||||
|
||||
if(terminal_height)
|
||||
|
@@ -143,8 +143,8 @@ module vero_components(type, cutouts = false, angle = undef)
|
||||
|
||||
module vero_cutouts(type, angle = undef) vero_components(type, true, angle); //! Make cutouts to clear components
|
||||
|
||||
module veroboard_assembly(type, height, thickness, flip = false) //! Draw the assembly with components and fasteners in place
|
||||
assembly(vero_assembly(type)) {
|
||||
module veroboard_assembly(type, height, thickness, flip = false, ngb = false) //! Draw the assembly with components and fasteners in place
|
||||
assembly(vero_assembly(type), ngb = ngb) {
|
||||
screw = vero_screw(type);
|
||||
nut = screw_nut(screw);
|
||||
screw_length = screw_length(screw, height + thickness + vero_thickness(type), 2, nyloc = true);
|
||||
|
@@ -62,7 +62,7 @@ module ziptie(type, r, t = 0) //! Draw specified ziptie wrapped around radius `r
|
||||
translate([lx, -r])
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
rounded_rectangle(latch, 0.5, center = false);
|
||||
rounded_rectangle(latch, 0.5);
|
||||
|
||||
translate_z((latch.z + 1) / 2)
|
||||
cube([ziptie_thickness(type), ziptie_width(type), latch.z + 1], center = true);
|
||||
|