1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-09-06 13:20:40 +02:00

Compare commits

...

8 Commits

Author SHA1 Message Date
Chris Palmer
147ff9b24f Added alpha parameter to stl_colour() 2020-04-07 17:02:10 +01:00
Chris Palmer
b4379907a2 Updated gallery 2020-04-06 16:21:58 +01:00
Chris Palmer
3be88f6517 Some more stl_colours. 2020-04-06 15:02:50 +01:00
Chris Palmer
d42f99e437 stl_colour() now used in tests and examples. 2020-04-06 10:27:17 +01:00
Chris Palmer
65455930f8 Reverted incorrect use of stl_colour(). 2020-04-05 18:51:21 +01:00
Chris Palmer
7e0c5fdb6e Renders of STLs are now the correct colour. Fixes #71 2020-04-05 16:18:24 +01:00
Chris Palmer
bc4e18d788 The assembly module now has a big parameter to force large or small views. 2020-04-04 12:06:14 +01:00
Chris Palmer
f5980b4703 Made the ground surfaces of steppers lighter. 2020-04-02 19:54:30 +01:00
53 changed files with 301 additions and 173 deletions

View File

@@ -164,7 +164,7 @@ This is achieved by having a pair of modules: -
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") { assembly("handle") {
translate_z(handle_height()) translate_z(handle_height())
color(pp1_colour) vflip() handle_stl(); stl_colour(pp1_colour) vflip() handle_stl();
handle_screw_positions() handle_screw_positions()
vflip() vflip()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -1,67 +1,119 @@
[ [
{ {
"name": "base_assembly", "name": "base_assembly",
"big": null,
"count": 1, "count": 1,
"assemblies": {}, "assemblies": {},
"vitamins": { "vitamins": {
"insert(F1BM3): Heatfit insert M3": 2 "insert(F1BM3): Heatfit insert M3": {
"count": 2
}
}, },
"printed": { "printed": {
"socket_box.stl": 1 "socket_box.stl": {
"count": 1,
"colour": "dimgrey"
}
}, },
"routed": {} "routed": {}
}, },
{ {
"name": "feet_assembly", "name": "feet_assembly",
"big": null,
"count": 1, "count": 1,
"assemblies": { "assemblies": {
"base_assembly": 1 "base_assembly": 1
}, },
"vitamins": { "vitamins": {
"washer(M3_washer): Washer M3 x 7mm x 0.5mm": 8, "washer(M3_washer): Washer M3 x 7mm x 0.5mm": {
"screw(M3_dome_screw, 10): Screw M3 dome x 10mm": 4, "count": 8
"nut(M3_nut, nyloc = true): Nut M3 x 2.4mm nyloc": 4 },
"screw(M3_dome_screw, 10): Screw M3 dome x 10mm": {
"count": 4
},
"nut(M3_nut, nyloc = true): Nut M3 x 2.4mm nyloc": {
"count": 4
}
}, },
"printed": { "printed": {
"foot.stl": 4 "foot.stl": {
"count": 4,
"colour": "darkorange"
}
}, },
"routed": {} "routed": {}
}, },
{ {
"name": "mains_in_assembly", "name": "mains_in_assembly",
"big": null,
"count": 1, "count": 1,
"assemblies": { "assemblies": {
"feet_assembly": 1 "feet_assembly": 1
}, },
"vitamins": { "vitamins": {
": Wire green & yellow 30/0.25mm strands, length 150mm - not shown": 1, ": Wire green & yellow 30/0.25mm strands, length 150mm - not shown": {
": Wire blue 30/0.25mm strands, length 150mm - not shown": 1, "count": 1
": Wire brown 30/0.25mm strands, length 150mm - not shown": 2, },
"tubing(HSHRNK32): Heatshrink sleeving ID 3.2mm x 15mm - not shown": 3, ": Wire blue 30/0.25mm strands, length 150mm - not shown": {
"iec(IEC_inlet_atx): IEC inlet for ATX": 1, "count": 1
"screw(M3_cs_cap_screw, 12): Screw M3 cs cap x 12mm": 2, },
"washer(M3_washer): Washer M3 x 7mm x 0.5mm": 2, ": Wire brown 30/0.25mm strands, length 150mm - not shown": {
"nut(M3_nut, nyloc = true): Nut M3 x 2.4mm nyloc": 2 "count": 2
},
"tubing(HSHRNK32): Heatshrink sleeving ID 3.2mm x 15mm - not shown": {
"count": 3
},
"iec(IEC_inlet_atx): IEC inlet for ATX": {
"count": 1
},
"screw(M3_cs_cap_screw, 12): Screw M3 cs cap x 12mm": {
"count": 2
},
"washer(M3_washer): Washer M3 x 7mm x 0.5mm": {
"count": 2
},
"nut(M3_nut, nyloc = true): Nut M3 x 2.4mm nyloc": {
"count": 2
}
}, },
"printed": {}, "printed": {},
"routed": {} "routed": {}
}, },
{ {
"name": "main_assembly", "name": "main_assembly",
"big": null,
"count": 1, "count": 1,
"assemblies": { "assemblies": {
"mains_in_assembly": 1 "mains_in_assembly": 1
}, },
"vitamins": { "vitamins": {
": Wire green & yellow 30/0.25mm strands, length 150mm - not shown": 1, ": Wire green & yellow 30/0.25mm strands, length 150mm - not shown": {
": Wire blue 30/0.25mm strands, length 150mm - not shown": 1, "count": 1
"tubing(HSHRNK32): Heatshrink sleeving ID 3.2mm x 15mm - not shown": 5, },
": Ferrule for 1.5mm^2 wire - not shown": 3, ": Wire blue 30/0.25mm strands, length 150mm - not shown": {
"mains_socket(Contactum): Mains socket 13A": 1, "count": 1
"screw(M3_cs_cap_screw, 20): Screw M3 cs cap x 20mm": 2, },
"jack_4mm_shielded(\"blue\", 3, \"royalblue\"): 4mm shielded jack socket blue": 2, "tubing(HSHRNK32): Heatshrink sleeving ID 3.2mm x 15mm - not shown": {
"jack_4mm_shielded(\"brown\", 3, \"sienna\"): 4mm shielded jack socket brown": 1, "count": 5
"jack_4mm_shielded(\"green\", 3): 4mm shielded jack socket green": 2 },
": Ferrule for 1.5mm^2 wire - not shown": {
"count": 3
},
"mains_socket(Contactum): Mains socket 13A": {
"count": 1
},
"screw(M3_cs_cap_screw, 20): Screw M3 cs cap x 20mm": {
"count": 2
},
"jack_4mm_shielded(\"blue\", 3, \"royalblue\"): 4mm shielded jack socket blue": {
"count": 2
},
"jack_4mm_shielded(\"brown\", 3, \"sienna\"): 4mm shielded jack socket brown": {
"count": 1
},
"jack_4mm_shielded(\"green\", 3): 4mm shielded jack socket green": {
"count": 2
}
}, },
"printed": {}, "printed": {},
"routed": {} "routed": {}

View File

@@ -173,7 +173,7 @@ module socket_box_stl() {
// //
module base_assembly() module base_assembly()
assembly("base") { assembly("base") {
color(pp1_colour) render() /*clip(ymax = 0)*/ socket_box_stl(); stl_colour(pp1_colour) render() /*clip(ymax = 0)*/ socket_box_stl();
mains_socket_hole_positions(socket) mains_socket_hole_positions(socket)
translate_z(height) translate_z(height)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 KiB

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 199 KiB

View File

@@ -84,7 +84,7 @@ Mains isolated and variable supply with metering.
<a name="TOP"></a> <a name="TOP"></a>
## SunBot ## SunBot
A solar tracker to keep solar powerbanks pointing at the sun. A solar tracker to keep a solar panel pointing at the sun.
![](SunBot.png) ![](SunBot.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 KiB

After

Width:  |  Height:  |  Size: 775 KiB

View File

@@ -33,7 +33,7 @@ assembly("box") {
y = [-1,-1,1,1][corner]; y = [-1,-1,1,1][corner];
translate([x * (box_width(type) / 2 + 25 * exploded()), y * (box_depth(type) / 2 + 25 * exploded())]) translate([x * (box_width(type) / 2 + 25 * exploded()), y * (box_depth(type) / 2 + 25 * exploded())])
rotate(corner * 90) { rotate(corner * 90) {
color(pp2_colour) render() stl_colour(pp2_colour) render()
box_corner_profile(type); box_corner_profile(type);
translate([box_hole_inset(type), box_hole_inset(type)]) translate([box_hole_inset(type), box_hole_inset(type)])
@@ -50,7 +50,7 @@ assembly("box") {
translate_z(z * (box_height(type) / 2 - box_corner_gap(type) + 50 * exploded())) translate_z(z * (box_height(type) / 2 - box_corner_gap(type) + 50 * exploded()))
rotate([z * 90 - 90, 0, 0]) rotate([z * 90 - 90, 0, 0])
if(bezels && (z > 0 ? top : base)) if(bezels && (z > 0 ? top : base))
color(pp1_colour) render() box_bezel(type, z < 0); stl_colour(pp1_colour) render() box_bezel(type, z < 0);
translate_z(z * (box_height(type) / 2 + sheet_thickness + 50 * exploded())) translate_z(z * (box_height(type) / 2 + sheet_thickness + 50 * exploded()))
box_screw_hole_positions(type) box_screw_hole_positions(type)

View File

@@ -133,12 +133,12 @@ module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
drill(corrected_radius(diameter / 2) + wall + clearance, h); drill(corrected_radius(diameter / 2) + wall + clearance, h);
module round_grommet_assembly(diameter, thickness, od = undef) { module round_grommet_assembly(diameter, thickness, od = undef) {
color(pp1_colour) stl_colour(pp1_colour)
translate_z(wall) translate_z(wall)
vflip() vflip()
round_grommet_top(diameter, thickness, od); round_grommet_top(diameter, thickness, od);
color(pp2_colour) stl_colour(pp2_colour)
translate_z(-thickness) translate_z(-thickness)
vflip() vflip()
round_grommet_bottom(diameter, od); round_grommet_bottom(diameter, od);
@@ -188,7 +188,7 @@ module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
} }
module mouse_grommet_assembly(r, thickness) module mouse_grommet_assembly(r, thickness)
color(pp1_colour) stl_colour(pp1_colour)
rotate([-90, 0, 0]) rotate([-90, 0, 0])
mouse_grommet(r, thickness); mouse_grommet(r, thickness);

View File

@@ -120,7 +120,7 @@ module corner_block_assembly(screw = def_screw, name = false) //! The printed bl
assembly(str("corner_block_M", 20 * screw_radius(screw))) { assembly(str("corner_block_M", 20 * screw_radius(screw))) {
insert = screw_insert(screw); insert = screw_insert(screw);
color(name ? pp2_colour : pp1_colour) stl_colour(name ? pp2_colour : pp1_colour)
render() corner_block(screw, name) children(); render() corner_block(screw, name) children();
corner_block_h_holes(screw) corner_block_h_holes(screw)

View File

@@ -141,7 +141,7 @@ module door_hinge_assembly(top, door_thickness = 6) { //! The moving assembly th
translate([0, pin_y - (thickness + door_thickness / 2), dir * width / 2]) { translate([0, pin_y - (thickness + door_thickness / 2), dir * width / 2]) {
rotate([90, 0, 180]) rotate([90, 0, 180])
color(pp2_colour) door_hinge(door_thickness); stl_colour(pp2_colour) door_hinge(door_thickness);
rotate([90, 0, 0]) rotate([90, 0, 0])
door_hinge_hole_positions() door_hinge_hole_positions()
@@ -165,7 +165,7 @@ module door_hinge_static_assembly(top, sheet_thickness = 3) { //! The stationary
translate([pin_x, 0, -dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw)))]) translate([pin_x, 0, -dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw)))])
rotate([90, 0, 0]) { rotate([90, 0, 0]) {
color(pp1_colour) door_hinge_stat_stl(); stl_colour(pp1_colour) door_hinge_stat_stl();
door_hinge_stat_hole_positions() { door_hinge_stat_hole_positions() {
screw_and_washer(stat_screw, stat_screw_length); screw_and_washer(stat_screw, stat_screw_length);

View File

@@ -65,7 +65,7 @@ module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specifi
translate([0, -height - washer_thickness(washer)]) translate([0, -height - washer_thickness(washer)])
rotate([-90, 0, 0]) { rotate([-90, 0, 0]) {
color(pp1_colour) render() door_latch_stl(); stl_colour(pp1_colour) render() door_latch_stl();
translate_z(nut_trap_depth) translate_z(nut_trap_depth)
vflip() vflip()

View File

@@ -109,7 +109,7 @@ module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8
assembly(str("fixing_block_M", 20 * screw_radius(screw))) { assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
translate_z(fixing_block_height(screw)) translate_z(fixing_block_height(screw))
rotate([0, 180, 0]) rotate([0, 180, 0])
color(pp1_colour) render() fixing_block(screw); stl_colour(pp1_colour) render() fixing_block(screw);
insert = screw_insert(screw); insert = screw_insert(screw);

View File

@@ -133,17 +133,17 @@ assembly(str("hinge_", type[0])) { //! Assembled hinge
vitamin(str(": Hinge pin ", w, " x ", 2 * hr, "mm")); vitamin(str(": Hinge pin ", w, " x ", 2 * hr, "mm"));
color(pp1_colour) hinge_male(type); stl_colour(pp1_colour) hinge_male(type);
translate([0, -kr, kr]) { translate([0, -kr, kr]) {
rotate([0, 90, 0]) rotate([0, 90, 0])
explode(w + 10) explode(w + 10)
color("silver") cylinder(r = hr , h = w, center = true); stl_colour("silver") cylinder(r = hr , h = w, center = true);
rotate([-angle, 0, 0]) rotate([-angle, 0, 0])
translate([0, -kr, -kr]) translate([0, -kr, -kr])
rotate(180) rotate(180)
color(pp2_colour) hinge_female(type); stl_colour(pp2_colour) hinge_female(type);
} }
} }

View File

@@ -73,7 +73,7 @@ module foot_assembly(t = 0, type = foot, flip = false) { //! Assembly with faste
screw_length = screw_longer_than(foot_thickness(type) + t + 2 * washer_thickness(washer) + nut_thickness(nut, true) - squeeze); screw_length = screw_longer_than(foot_thickness(type) + t + 2 * washer_thickness(washer) + nut_thickness(nut, true) - squeeze);
vflip() explode(15, true) { vflip() explode(15, true) {
color(pp4_colour) foot(type); stl_colour(pp4_colour) foot(type);
if(t) if(t)
explode(15, true) explode(15, true)
@@ -136,7 +136,7 @@ assembly("insert_foot") {
insert = screw_insert(screw); insert = screw_insert(screw);
vflip() vflip()
color(pp1_colour) insert_foot(type); stl_colour(pp4_colour) insert_foot(type);
translate_z(-foot_thickness(type)) translate_z(-foot_thickness(type))
insert(insert); insert(insert);

View File

@@ -83,7 +83,7 @@ module handle_stl() { //! generate the STL
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") { assembly("handle") {
translate_z(handle_height()) translate_z(handle_height())
color(pp1_colour) vflip() handle_stl(); stl_colour(pp1_colour) vflip() handle_stl();
handle_screw_positions() handle_screw_positions()
vflip() vflip()

View File

@@ -101,7 +101,7 @@ module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly
translate_z(height) translate_z(height)
pcb(pcb); pcb(pcb);
color(pp1_colour) pcb_mount(pcb, washers = false); stl_colour(pp1_colour) pcb_mount(pcb, washers = false);
washer = screw_washer(screw); washer = screw_washer(screw);
nut = screw_nut(screw); nut = screw_nut(screw);
@@ -110,7 +110,7 @@ module pcb_mount_assembly(pcb, thickness, height = 5) { //! A PCB mount assembly
pcb_mount_screw_positions(pcb) { pcb_mount_screw_positions(pcb) {
translate_z(height + t) { translate_z(height + t) {
color(pp2_colour) pcb_mount_washer_stl(); stl_colour(pp2_colour) pcb_mount_washer_stl();
translate_z(washer_thickness) translate_z(washer_thickness)
screw(screw, screw_length); screw(screw, screw_length);

View File

@@ -221,7 +221,7 @@ module pbox_base_screws(type, thickness = 0) //! Place the screws and
pbox_screw_positions(type) { pbox_screw_positions(type) {
foot = pbox_foot(type); foot = pbox_foot(type);
if(foot) if(foot)
color(pp4_colour) stl_colour(pp4_colour)
foot(foot); foot(foot);
translate_z(foot ? foot_thickness(foot) : thickness) translate_z(foot ? foot_thickness(foot) : thickness)

View File

@@ -147,7 +147,7 @@ assembly(str("PSU_shroud_", name)) {
translate_z(psu_shroud_height(type)) translate_z(psu_shroud_height(type))
vflip() vflip()
color(pp1_colour) psu_shroud(type, cable_d, name, cables); stl_colour(pp1_colour) psu_shroud(type, cable_d, name, cables);
psu_shroud_hole_positions(type) psu_shroud_hole_positions(type)
vflip() vflip()

View File

@@ -83,7 +83,7 @@ module ribbon_clamp_assembly(ways) pose([55, 180, 25]) //! Printed part with in
assembly(str("ribbon_clamp_", ways)) { assembly(str("ribbon_clamp_", ways)) {
h = ribbon_clamp_height(); h = ribbon_clamp_height();
color(pp1_colour) render() stl_colour(pp1_colour) render()
translate_z(h) vflip() ribbon_clamp(ways); translate_z(h) vflip() ribbon_clamp(ways);
ribbon_clamp_hole_positions(ways) ribbon_clamp_hole_positions(ways)

View File

@@ -62,7 +62,7 @@ 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)) {
translate_z(knob_height) translate_z(knob_height)
vflip() vflip()
color(pp1_colour) screw_knob(screw); stl_colour(pp1_colour) screw_knob(screw);
translate_z(knob_height - knob_nut_trap_depth(screw)) translate_z(knob_height - knob_nut_trap_depth(screw))
rotate(-45) rotate(-45)

View File

@@ -92,7 +92,7 @@ assembly(str("socket_box_", type[0])) {
screw = mains_socket_screw(type); screw = mains_socket_screw(type);
insert = screw_insert(screw); insert = screw_insert(screw);
color(pp1_colour) render() socket_box(type); stl_colour(pp1_colour) render() socket_box(type);
mains_socket_hole_positions(type) mains_socket_hole_positions(type)
translate_z(height) translate_z(height)

View File

@@ -111,7 +111,7 @@ assembly(str("SSR_shroud_", name)) {
translate_z(ssr_shroud_height(type)) translate_z(ssr_shroud_height(type))
vflip() vflip()
color(pp1_colour) ssr_shroud(type, cable_d, name); stl_colour(pp1_colour) ssr_shroud(type, cable_d, name);
ssr_shroud_hole_positions(type) ssr_shroud_hole_positions(type)
insert(insert); insert(insert);
@@ -135,7 +135,7 @@ module ssr_shroud_fastened_assembly(type, cable_d, thickness, name) //! Assembly
*translate_z(cable_d / 2) *translate_z(cable_d / 2)
rotate([90, 0, 0]) rotate([90, 0, 0])
color(grey20) stl_colour(grey20)
cylinder(d = cable_d, h = 20, center = true); cylinder(d = cable_d, h = 20, center = true);
} }
} }

View File

@@ -160,7 +160,7 @@ module strap_end(type = strap) { //! Generate the STL for end piece
// //
module strap_end_assembly(type = strap) module strap_end_assembly(type = strap)
assembly("strap_end") { assembly("strap_end") {
color(pp1_colour) stl_colour(pp1_colour)
strap_end(type); strap_end(type);
translate_z(strap_height(type) + strap_key(type)) translate_z(strap_height(type) + strap_key(type))
@@ -175,7 +175,7 @@ module strap_assembly(length, type = strap) { //! Assembly with screws in place
screw_length = screw_shorter_than(washer_thickness(washer) + washer_thickness(penny) + insert_length(insert) + panel_clearance + counterbore); screw_length = screw_shorter_than(washer_thickness(washer) + washer_thickness(penny) + insert_length(insert) + panel_clearance + counterbore);
color(pp4_colour) strap(length, type); stl_colour(pp4_colour) strap(length, type);
strap_screw_positions(length, type) strap_screw_positions(length, type)
translate_z(strap_height(type)) translate_z(strap_height(type))

View File

@@ -5171,11 +5171,15 @@ Simple tube or ring
--- ---
<a name="BOM"></a> <a name="BOM"></a>
## BOM ## BOM
Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing. Assembly instructions can precede the module Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing.
definition that makes the assembly. Assembly instructions can precede the module definition that makes the assembly.
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 Assembly views shown in the instructions can be large or small and this is deduced by looking at the size of the printed parts involved and if any routed
heirachical BOMs are also generated for real projects. 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```.
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.
[utils/core/bom.scad](utils/core/bom.scad) Implementation. [utils/core/bom.scad](utils/core/bom.scad) Implementation.
@@ -5194,7 +5198,7 @@ heirachical BOMs are also generated for real projects.
### Modules ### Modules
| Module | Description | | Module | Description |
|:--- |:--- | |:--- |:--- |
| ```assembly(name)``` | Name an assembly that will appear on the BOM, there needs to a module named ```<name>_assembly``` to make it | | ```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. |
| ```dxf(name)``` | Name a dxf that will appear on the BOM, there needs to a module named ```<name>_dxf``` to make it | | ```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 | | ```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 | | ```hidden()``` | Make item invisible, except on the BOM |
@@ -5205,6 +5209,7 @@ heirachical BOMs are also generated for real projects.
| ```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_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. | | ```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(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" | | ```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" |
![bom](tests/png/bom.png) ![bom](tests/png/bom.png)

View File

@@ -29,6 +29,7 @@ import openscad
from time import * from time import *
from set_config import * from set_config import *
import json import json
import re
def find_scad_file(mname): def find_scad_file(mname):
for filename in os.listdir(source_dir): for filename in os.listdir(source_dir):
@@ -45,9 +46,20 @@ def find_scad_file(mname):
return filename return filename
return None return None
class Part:
def __init__(self, args):
self.count = 1
for arg in args:
arg = arg.replace('true', 'True').replace('false', 'False').replace('undef', 'None')
exec('self.' + arg)
def data(self):
return self.__dict__
class BOM: class BOM:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.big = None
self.count = 1 self.count = 1
self.vitamins = {} self.vitamins = {}
self.printed = {} self.printed = {}
@@ -60,14 +72,20 @@ class BOM:
assemblies[ass] = self.assemblies[ass].count assemblies[ass] = self.assemblies[ass].count
return { return {
"name" : self.name, "name" : self.name,
"big" : self.big,
"count" : self.count, "count" : self.count,
"assemblies" : assemblies, "assemblies" : assemblies,
"vitamins" : self.vitamins, "vitamins" : {v : self.vitamins[v].data() for v in self.vitamins},
"printed" : self.printed, "printed" : {p : self.printed[p].data() for p in self.printed},
"routed" : self.routed "routed" : {r : self.routed[r].data() for r in self.routed}
} }
def add_part(self, s): def add_part(self, s):
args = []
match = re.match(r'^(.*?\.stl)\((.*)\)$', s) #look for name.stl(...)
if match:
s = match.group(1)
args = [match.group(2)]
if s[-4:] == ".stl": if s[-4:] == ".stl":
parts = self.printed parts = self.printed
else: else:
@@ -76,15 +94,19 @@ class BOM:
else: else:
parts = self.vitamins parts = self.vitamins
if s in parts: if s in parts:
parts[s] += 1 parts[s].count += 1
else: else:
parts[s] = 1 parts[s] = Part(args)
def add_assembly(self, ass): def add_assembly(self, ass, args = []):
if ass in self.assemblies: if ass in self.assemblies:
self.assemblies[ass].count += 1 self.assemblies[ass].count += 1
else: else:
self.assemblies[ass] = BOM(ass) bom = BOM(ass)
for arg in args:
arg = arg.replace('true', 'True').replace('false', 'False').replace('undef', 'None')
exec('bom.' + arg, locals())
self.assemblies[ass] = bom
def make_name(self, ass): def make_name(self, ass):
if self.count == 1: if self.count == 1:
@@ -119,10 +141,10 @@ class BOM:
for ass in sorted(self.assemblies): for ass in sorted(self.assemblies):
bom = self.assemblies[ass] bom = self.assemblies[ass]
if part in bom.vitamins: if part in bom.vitamins:
file.write("%2d|" % bom.vitamins[part]) file.write("%2d|" % bom.vitamins[part].count)
else: else:
file.write(" |") file.write(" |")
print("%3d" % self.vitamins[part], description, file=file) print("%3d" % self.vitamins[part].count, description, file=file)
if self.printed: if self.printed:
if self.vitamins: if self.vitamins:
@@ -133,10 +155,10 @@ class BOM:
for ass in sorted(self.assemblies): for ass in sorted(self.assemblies):
bom = self.assemblies[ass] bom = self.assemblies[ass]
if part in bom.printed: if part in bom.printed:
file.write("%2d|" % bom.printed[part]) file.write("%2d|" % bom.printed[part].count)
else: else:
file.write(" |") file.write(" |")
print("%3d" % self.printed[part], part, file=file) print("%3d" % self.printed[part].count, part, file=file)
if self.routed: if self.routed:
print(file=file) print(file=file)
@@ -146,10 +168,10 @@ class BOM:
for ass in sorted(self.assemblies): for ass in sorted(self.assemblies):
bom = self.assemblies[ass] bom = self.assemblies[ass]
if part in bom.routed: if part in bom.routed:
file.write("%2d|" % bom.routed[part]) file.write("%2d|" % bom.routed[part].count)
else: else:
file.write(" |") file.write(" |")
print("%3d" % self.routed[part], part, file=file) print("%3d" % self.routed[part].count, part, file=file)
if self.assemblies: if self.assemblies:
print(file=file) print(file=file)
@@ -161,17 +183,22 @@ def parse_bom(file = "openscad.log", name = None):
main = BOM(name) main = BOM(name)
main.ordered_assemblies = [] main.ordered_assemblies = []
stack = [] stack = []
prog = re.compile(r'^(.*)\((.*)\)$')
for line in open(file): for line in open(file):
pos = line.find('ECHO: "~') pos = line.find('ECHO: "~')
if pos > -1: if pos > -1:
s = line[pos + 8 : line.rfind('"')] s = line[pos + 8 : line.rfind('"')]
if s[-1] == '{': if s[-1] == '{':
ass = s[:-1] ass = s[:-1]
args = []
match = prog.match(ass) #look for (...)
if match:
ass = match.group(1)
args = match.group(2).split(',')
if stack: if stack:
main.assemblies[stack[-1]].add_assembly(ass) #add to nested BOM main.assemblies[stack[-1]].add_assembly(ass) #add to nested BOM
stack.append(ass) stack.append(ass)
main.add_assembly(ass) #add to flat BOM main.add_assembly(ass, args) #add to flat BOM
if ass in main.ordered_assemblies: if ass in main.ordered_assemblies:
main.ordered_assemblies.remove(ass) main.ordered_assemblies.remove(ass)
main.ordered_assemblies.insert(0, ass) main.ordered_assemblies.insert(0, ass)

View File

@@ -29,6 +29,7 @@ import openscad
from tests import do_cmd, update_image, colour_scheme, background from tests import do_cmd, update_image, colour_scheme, background
from deps import mtime from deps import mtime
from colorama import init from colorama import init
import json
def usage(): def usage():
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files."); print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
@@ -48,6 +49,20 @@ def render(target, type):
# #
parts = bom_to_parts(bom_dir, type) parts = bom_to_parts(bom_dir, type)
# #
# Read the json bom to get the colours
#
bom_file = bom_dir + "/bom.json"
with open(bom_file) as json_file:
flat_bom = json.load(json_file)
things = { 'stl' : 'printed', 'dxf' : 'routed' }[type]
colours = {}
for ass in flat_bom:
for part in ass[things]:
obj = ass[things][part]
if "colour" in obj:
colours[part] = obj["colour"]
#
# Remove unused png files # Remove unused png files
# #
for file in os.listdir(target_dir): for file in os.listdir(target_dir):
@@ -55,7 +70,9 @@ def render(target, type):
if not file[:-4] + '.' + type in parts: if not file[:-4] + '.' + type in parts:
print("Removing %s" % file) print("Removing %s" % file)
os.remove(target_dir + '/' + file) os.remove(target_dir + '/' + file)
#
# Render the parts
#
for part in parts: for part in parts:
part_file = target_dir + '/' + part part_file = target_dir + '/' + part
png_name = target_dir + '/' + part[:-4] + '.png' png_name = target_dir + '/' + part[:-4] + '.png'
@@ -64,8 +81,13 @@ def render(target, type):
# #
if mtime(part_file) > mtime(png_name): if mtime(part_file) > mtime(png_name):
png_maker_name = "png.scad" png_maker_name = "png.scad"
colour = [0, 146/255, 0]
if part in colours:
colour = colours[part]
if not '[' in colour:
colour = '"' + colour + '"'
with open(png_maker_name, "w") as f: with open(png_maker_name, "w") as f:
f.write('color([0, 146/255, 0]) import("%s");\n' % part_file) f.write('color(%s) import("%s");\n' % (colour, part_file))
cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500" 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' else "--render" render = "--preview" if type == 'stl' else "--render"
tmp_name = 'tmp.png' tmp_name = 'tmp.png'

View File

@@ -232,9 +232,10 @@ def tests(tests):
j = name.find(']]') + 2 j = name.find(']]') + 2
name = name.replace(name[i : j], '[ ... ]') name = name.replace(name[i : j], '[ ... ]')
desc = vit[1] desc = vit[1]
body += ['| %3d | %s | %s |' % (things[item], name, desc)] body += ['| %3d | %s | %s |' % (things[item]["count"], name, desc)]
else: else:
body += ['| %3d | %s |' % (things[item], name)] count = things[item] if thing == 'assemblies' else things[item]["count"]
body += ['| %3d | %s |' % (count, name)]
body += [''] body += ['']
body += ['\n<a href="#top">Top</a>'] body += ['\n<a href="#top">Top</a>']

View File

@@ -52,22 +52,23 @@ def bom_to_assemblies(bom_dir, bounds_map):
# Decide if we need big or small assembly pictures # Decide if we need big or small assembly pictures
# #
for bom in flat_bom: for bom in flat_bom:
big = False if bom["big"] == None:
for ass in bom["assemblies"]: big = False
for b in flat_bom: for ass in bom["assemblies"]:
if b["name"] == ass: for b in flat_bom:
if b["big"]: if b["name"] == ass:
if b["big"]:
big = True
break
if not big:
for stl in bom["printed"]:
bounds = bounds_map[stl]
width = bounds[1][0] - bounds[0][0]
depth = bounds[1][1] - bounds[0][1]
if max(width, depth) > 80:
big = True big = True
break break
if not big: bom["big"] = big or bom["routed"]
for stl in bom["printed"]:
bounds = bounds_map[stl]
width = bounds[1][0] - bounds[0][0]
depth = bounds[1][1] - bounds[0][1]
if max(width, depth) > 80:
big = True
break
bom["big"] = big or bom["routed"]
# #
# Remove the main assembly if it is a shell # Remove the main assembly if it is a shell
# #
@@ -247,9 +248,9 @@ def views(target, do_assemblies = None):
for t in types: for t in types:
for thing in ass[t]: for thing in ass[t]:
if thing in things[t]: if thing in things[t]:
things[t][thing] += ass[t][thing] things[t][thing] += ass[t][thing]["count"]
else: else:
things[t][thing] = ass[t][thing] things[t][thing] = ass[t][thing]["count"]
for ass in flat_bom: for ass in flat_bom:
name = titalise(ass["name"][:-9]).replace(' ','&nbsp;') name = titalise(ass["name"][:-9]).replace(' ','&nbsp;')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '') print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
@@ -264,7 +265,7 @@ def views(target, do_assemblies = None):
print(('| ' * len(flat_bom) + '| | **%s** |') % heading, file = doc_file) print(('| ' * len(flat_bom) + '| | **%s** |') % heading, file = doc_file)
for thing in sorted(things[t], key = lambda s: s.split(":")[-1]): for thing in sorted(things[t], key = lambda s: s.split(":")[-1]):
for ass in flat_bom: for ass in flat_bom:
count = ass[t][thing] if thing in ass[t] else 0 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 = '') print('| %s ' % pad(count if count else '.', 2, 1), file = doc_file, end = '')
name = ass["name"] name = ass["name"]
if name in totals: if name in totals:
@@ -300,7 +301,7 @@ def views(target, do_assemblies = None):
print("|Qty|Description|", file = doc_file) print("|Qty|Description|", file = doc_file)
print("|---:|:----------|", file = doc_file) print("|---:|:----------|", file = doc_file)
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]): for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
print("|%d|%s|" % (vitamins[v], v.split(":")[1]), file = doc_file) print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]), file = doc_file)
print("\n", file = doc_file) print("\n", file = doc_file)
printed = ass["printed"] printed = ass["printed"]
@@ -309,7 +310,7 @@ def views(target, do_assemblies = None):
keys = sorted(list(printed.keys())) keys = sorted(list(printed.keys()))
for i in range(len(keys)): for i in range(len(keys)):
p = keys[i] p = keys[i]
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p], p), file = doc_file, end = '') 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: if (i % 3) == 2 or i == len(printed) - 1:
n = (i % 3) + 1 n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file) print('\n|%s' % ('---|' * n), file = doc_file)
@@ -325,7 +326,7 @@ def views(target, do_assemblies = None):
keys = sorted(list(routed.keys())) keys = sorted(list(routed.keys()))
for i in range(len(keys)): for i in range(len(keys)):
r = keys[i] r = keys[i]
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r], r), file = doc_file, end = '') 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: if (i % 3) == 2 or i == len(routed) - 1:
n = (i % 3) + 1 n = (i % 3) + 1
print('\n|%s' % ('---|' * n), file = doc_file) print('\n|%s' % ('---|' * n), file = doc_file)

View File

@@ -67,7 +67,7 @@ module widgit_dxf() {
//! * Push the insert into the base with a soldering iron heated to 200&deg;C //! * Push the insert into the base with a soldering iron heated to 200&deg;C
module widgit_base_assembly() module widgit_base_assembly()
assembly("widgit_base") { assembly("widgit_base") {
color(pp1_colour) stl_colour(pp1_colour)
widgit_stl(); widgit_stl();
translate_z(height) translate_z(height)

View File

@@ -22,14 +22,14 @@ use <../printed/cable_grommets.scad>
module cable_grommets() { module cable_grommets() {
rotate(90) rotate(90)
color(pp1_colour) ribbon_grommet(20, 3); stl_colour(pp1_colour) ribbon_grommet(20, 3);
translate([20, 0]) translate([20, 0])
round_grommet_assembly(6, 3); round_grommet_assembly(6, 3);
translate([40, 0]) translate([40, 0])
rotate(90) rotate(90)
color(pp1_colour) mouse_grommet(5, 3); stl_colour(pp1_colour) mouse_grommet(5, 3);
} }
if($preview) if($preview)

View File

@@ -20,15 +20,15 @@ include <../utils/core/core.scad>
use <../printed/carriers.scad> use <../printed/carriers.scad>
module carriers() { module carriers() {
color(pp1_colour) ESP12F_carrier_stl(); stl_colour(pp1_colour) ESP12F_carrier_stl();
translate([0, 15]) translate([0, 15])
rotate(90) rotate(90)
color(pp1_colour) TP4056_carrier_stl(); stl_colour(pp1_colour) TP4056_carrier_stl();
translate([0, 25]) translate([0, 25])
rotate(90) rotate(90)
color(pp1_colour) MT3608_carrier_stl(); stl_colour(pp1_colour) MT3608_carrier_stl();
} }
carriers(); carriers();

View File

@@ -24,6 +24,6 @@ use <../utils/layout.scad>
module fan_guards() module fan_guards()
layout([for(f = fans) fan_width(f)], 10) layout([for(f = fans) fan_width(f)], 10)
color(pp1_colour) fan_guard(fans[$i], spokes = fan_width(fans[$i]) > 60 ? 8 : 4); stl_colour(pp1_colour) fan_guard(fans[$i], spokes = fan_width(fans[$i]) > 60 ? 8 : 4);
fan_guards(); fan_guards();

View File

@@ -27,7 +27,7 @@ module inserts() {
translate([10 * i, 0]) translate([10 * i, 0])
insert(inserts[i]); insert(inserts[i]);
color(pp1_colour) stl_colour(pp1_colour)
translate([len(inserts) * 10, 0]) { translate([len(inserts) * 10, 0]) {
insert_lug(inserts[0], 2, 1); insert_lug(inserts[0], 2, 1);

View File

@@ -29,7 +29,7 @@ module light_strips()
for(end = [-1, 1]) for(end = [-1, 1])
translate([end * (light_strip_cut_length(light, segs) / 2 - d / 2), 0]) translate([end * (light_strip_cut_length(light, segs) / 2 - d / 2), 0])
rotate([90, 0, 90]) rotate([90, 0, 90])
color(pp1_colour) render() stl_colour(pp1_colour) render()
translate_z(-d / 2) translate_z(-d / 2)
light_strip_clip(light); light_strip_clip(light);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -34,7 +34,7 @@ module polyholes() {
children(); children();
} }
color(pp1_colour) linear_extrude(3, center = true) stl_colour(pp1_colour) linear_extrude(3, center = true)
difference() { difference() {
square([100, 27]); square([100, 27]);
@@ -52,7 +52,7 @@ module polyholes() {
sizes = [1.5, 2, 3, 4]; sizes = [1.5, 2, 3, 4];
for(i = [0 : len(sizes) - 1]) for(i = [0 : len(sizes) - 1])
translate([i * 10, -10]) { translate([i * 10, -10]) {
color(pp1_colour) stl_colour(pp1_colour)
poly_tube(ir = ir, or = cir + sizes[i] * extrusion_width, h = 1); poly_tube(ir = ir, or = cir + sizes[i] * extrusion_width, h = 1);
rod(2 * ir, 3); rod(2 * ir, 3);

View File

@@ -93,7 +93,7 @@ module box1_base_stl()
module box1_assembly() module box1_assembly()
assembly("box1") { assembly("box1") {
color(pp1_colour) render() box1_case_stl(); stl_colour(pp1_colour) render() box1_case_stl();
pbox_inserts(box1); pbox_inserts(box1);
@@ -142,7 +142,7 @@ module box2_base_stl()
module box2_assembly() module box2_assembly()
assembly("box2") { assembly("box2") {
color(pp1_colour) render() box2_case_stl(); stl_colour(pp1_colour) render() box2_case_stl();
pbox_inserts(box2); pbox_inserts(box2);

View File

@@ -20,7 +20,7 @@
include <../utils/core/core.scad> include <../utils/core/core.scad>
module teardrops() { module teardrops() {
color(pp1_colour) stl_colour(pp1_colour)
rotate([90, 0, -45]) rotate([90, 0, -45])
difference() { difference() {
linear_extrude(3) { linear_extrude(3) {

View File

@@ -54,7 +54,7 @@ module wires() {
%cylinder(r = bundle_r, h = wire_l - 10, center = true); %cylinder(r = bundle_r, h = wire_l - 10, center = true);
} }
color(pp1_colour) { stl_colour(pp1_colour) {
rotate([90, 0, 90]) rotate([90, 0, 90])
linear_extrude(thickness) linear_extrude(thickness)
difference() { difference() {

View File

@@ -18,11 +18,15 @@
// //
// //
//! Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing. Assembly instructions can precede the module //! Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing.
//! definition that makes the assembly. //! Assembly instructions can precede the module definition that makes the assembly.
//! //!
//! 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 //! Assembly views shown in the instructions can be large or small and this is deduced by looking at the size of the printed parts involved and if any routed
//! heirachical BOMs are also generated for real projects. //! 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```.
//!
//! 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.
// //
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 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 exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of ```$exploded``` if it is defined, else ```0```
@@ -80,10 +84,11 @@ module pose_vflip(exploded = undef) //! Pose an STL or assembly for render
children(); children();
module assembly(name) { //! Name an assembly that will appear on the BOM, there needs to a module named ```<name>_assembly``` to make it 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.
if(bom_mode()) if(bom_mode()) {
echo(str("~", name, "_assembly{")); args = is_undef(big) ? "" : str("(big=", big, ")");
echo(str("~", name, "_assembly", args, "{"));
}
no_pose() no_pose()
if(is_undef($child_assembly)) if(is_undef($child_assembly))
let($child_assembly = true) let($child_assembly = true)
@@ -96,9 +101,17 @@ module assembly(name) { //! Name an assembly that will appear on
echo(str("~}", name, "_assembly")); echo(str("~}", name, "_assembly"));
} }
module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named ```<name>_stl``` to make it module 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.
if(bom_mode()) $stl_colour = colour;
echo(str("~", name, ".stl")); color(colour, alpha)
children();
}
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()) {
colour = is_undef($stl_colour) ? pp1_colour : $stl_colour;
echo(str("~", name, ".stl(colour='", colour, "')"));
}
} }
module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named ```<name>_dxf``` to make it module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named ```<name>_dxf``` to make it

View File

@@ -988,7 +988,7 @@ module pcb_assembly(type, height, thickness) { //! Draw PCB assembly with spaces
translate_z(height + pcb_thickness(type)) translate_z(height + pcb_thickness(type))
screw(screw, screw_length); screw(screw, screw_length);
color(pp1_colour) stl_colour(pp1_colour)
if(taper) if(taper)
pcb_spacer(screw, height, taper = 2); pcb_spacer(screw, height, taper = 2);
else else

View File

@@ -42,6 +42,7 @@ function NEMA_big_hole(type) = NEMA_boss_radius(type) + 0.2; //! Clearance ho
stepper_body_colour = "black"; stepper_body_colour = "black";
stepper_cap_colour = grey50; stepper_cap_colour = grey50;
stepper_machined_colour = grey90;
module NEMA_outline(type) //! 2D outline module NEMA_outline(type) //! 2D outline
intersection() { intersection() {
@@ -62,57 +63,63 @@ module NEMA(type, shaft_angle = 0) { //! Draw specified NEMA stepper motor
vitamin(str("NEMA(", type[0], "): Stepper motor NEMA", round(NEMA_width(type) / 2.54), " x ", length, "mm")); vitamin(str("NEMA(", type[0], "): Stepper motor NEMA", round(NEMA_width(type) / 2.54), " x ", length, "mm"));
thread_d = 3; // Is this always the case? thread_d = 3; // Is this always the case?
union() { module cap_shape(end)
color(stepper_body_colour) // black laminations difference() {
translate_z(-length / 2) intersection() {
linear_extrude(length - cap * 2, center = true) square([side, side], center = true);
intersection() {
square([side, side], center = true);
circle(body_rad); circle(NEMA_radius(type), $fn = 360);
} }
if(end > 0)
color(stepper_cap_colour) { // aluminium end caps for(x = NEMA_holes(type), y = NEMA_holes(type))
tube(or = boss_rad, ir = shaft_rad + 2, h = boss_height * 2); // raised boss translate([x, y])
circle(d = thread_d);
for(end = [-1, 1])
translate_z(-length / 2 + end * (length - cap) / 2) {
linear_extrude(cap, center = true)
difference() {
intersection() {
square([side, side], center = true);
circle(NEMA_radius(type));
}
if(end > 0)
for(x = NEMA_holes(type), y = NEMA_holes(type))
translate([x, y])
circle(d = thread_d);
}
}
} }
if(show_threads)
for(x = NEMA_holes(type), y = NEMA_holes(type))
translate([x, y, -cap / 2])
female_metric_thread(thread_d, metric_coarse_pitch(thread_d), cap, colour = stepper_cap_colour);
shaft = NEMA_shaft_length(type); color(stepper_body_colour) // black laminations
translate_z(-5) translate_z(-length / 2)
rotate(shaft_angle) linear_extrude(length - cap * 2, center = true)
if(!is_list(shaft)) intersection() {
color(stepper_cap_colour) square([side, side], center = true);
cylinder(r = shaft_rad, h = shaft + 5); // shaft
else
not_on_bom()
leadscrew(shaft_rad * 2, shaft.x + 5, shaft.y, shaft.z, center = false)
translate([0, side / 2, -length + cap / 2]) circle(body_rad);
rotate([90, 0, 0]) }
for(i = [0 : 3])
rotate(225 + i * 90) color(stepper_machined_colour) {
color(["red", "blue","green","black"][i]) tube(or = boss_rad, ir = shaft_rad + 2, h = boss_height * 2); // raised boss
translate([1, 0, 0])
cylinder(r = 1.5 / 2, h = 12, center = true); linear_extrude(eps)
cap_shape(true);
} }
color(stepper_cap_colour) // aluminium end caps
for(end = [-1, 1])
translate_z(-length / 2 + end * (length - cap) / 2)
linear_extrude(cap, center = true)
cap_shape(end);
if(show_threads)
for(x = NEMA_holes(type), y = NEMA_holes(type))
translate([x, y, -cap / 2])
female_metric_thread(thread_d, metric_coarse_pitch(thread_d), cap, colour = stepper_cap_colour);
shaft = NEMA_shaft_length(type);
translate_z(-5)
rotate(shaft_angle)
if(!is_list(shaft))
color(stepper_machined_colour)
cylinder(r = shaft_rad, h = shaft + 5); // shaft
else
not_on_bom()
leadscrew(shaft_rad * 2, shaft.x + 5, shaft.y, shaft.z, center = false)
translate([0, side / 2, -length + cap / 2])
rotate([90, 0, 0])
for(i = [0 : 3])
rotate(225 + i * 90)
color(["red", "blue","green","black"][i])
translate([1, 0, 0])
cylinder(r = 1.5 / 2, h = 12, center = true);
} }
module NEMA_screw_positions(type, n = 4) { //! Positions children at the screw holes module NEMA_screw_positions(type, n = 4) { //! Positions children at the screw holes

View File

@@ -162,7 +162,7 @@ assembly(vero_assembly(type)) {
else else
screw_and_washer(screw, screw_length); screw_and_washer(screw, screw_length);
color(pp1_colour) pcb_spacer(screw, height); stl_colour(pp1_colour) pcb_spacer(screw, height);
translate_z(-thickness) translate_z(-thickness)
vflip() vflip()

View File

@@ -122,7 +122,7 @@ module printed_washer(type, name = false) { //! Create printed washer
t = round_to_layer(washer_thickness(type)); t = round_to_layer(washer_thickness(type));
or = washer_radius(type); or = washer_radius(type);
ir = washer_id(type) / 2; ir = washer_id(type) / 2;
color(pp1_colour) stl_colour(pp1_colour)
linear_extrude(t, center = false, convexity = 2) linear_extrude(t, center = false, convexity = 2)
poly_ring(or, ir); poly_ring(or, ir);