1
0
mirror of https://github.com/nophead/Mendel90.git synced 2025-01-16 20:38:15 +01:00

first commit

This commit is contained in:
Chris Palmer 2012-03-12 01:13:07 +00:00
commit d22174869f
68 changed files with 90115 additions and 0 deletions

19
README.txt Normal file
View File

@ -0,0 +1,19 @@
Limitations
-----------
Currently only supports mendel and sturdy machine varients, the huxley version needs more work.
Only builds on Windows, using the version of openscad.exe included and the openscad_cl.exe wrapper.
Use
---
To make all the files for a machine run
make_machine.py machine_name
To make just the bom, sheets or stls run bom.py, sheets.py or stls.py
machine_name can be mendel or sturdy. To make your own variant copy scad\conf\mendel.scad or scad\conf\sturdy to yourname_config.scad.
To view the whole machine model open scad\main.scad. It will take about 8 miniutes to render but after that you can pan and zoom it
at reasonable speed and changes takes less time to render.
To view a sub assembly open the inididual scad files. Set the exploded flag in config.scad to make exploded views.

10
_canute.bat Normal file
View File

@ -0,0 +1,10 @@
@ECHO OFF
TITLE Canute
CALL %TOOLSDRV%\BAT\SYSENV w:
SET GNU=1
IF ERRORLEVEL 1 GOTO :ERR
IF NOT ERRORLEVEL 1 GOTO :DONE
:ERR
PAUSE
:DONE

138
bom.py Normal file
View File

@ -0,0 +1,138 @@
import os
import subprocess
import sys
import shutil
class BOM():
def __init__(self):
self.count = 1
self.vitamins = {}
self.printed = {}
self.assemblies = {}
def add_part(self, s):
if s[-4:] == ".stl":
parts = self.printed
else:
parts = self.vitamins
if s in parts:
parts[s] += 1
else:
parts[s] = 1
def add_assembly(self, ass):
if ass in self.assemblies:
self.assemblies[ass].count += 1
else:
self.assemblies[ass] = BOM()
def make_name(self, ass):
if self.count == 1:
return ass
return ass.replace("assembly", "assemblies")
def print_bom(self, breakdown, file = None):
if breakdown:
longest = 0
for ass in self.assemblies:
name = ass.replace("_assembly","")
longest = max(longest, len(name))
for i in range(longest):
print >> file, " " * 14,
for ass in sorted(self.assemblies):
name = ass.replace("_assembly","").replace("_"," ")
if longest - i > len(name):
print >> file, " ",
else:
print >> file, " %s" % name[i - (longest - len(name))],
print >> file
print >> file, "Vitamins:"
for part in sorted(self.vitamins):
if ': ' in part:
part_no, description = part.split(': ')
else:
part_no, description = "", part
print >> file, "%3d %-10s" % (self.vitamins[part], part_no),
if breakdown:
for ass in sorted(self.assemblies):
bom = self.assemblies[ass]
if part in bom.vitamins:
print >> file, "%2d" % bom.vitamins[part],
else:
print >> file, " ",
print >> file, description
print >> file
print >> file, "Printed:"
for part in sorted(self.printed):
print >> file, "%3d" % self.printed[part],
if breakdown:
print >> file, " " * 10,
for ass in sorted(self.assemblies):
bom = self.assemblies[ass]
if part in bom.printed:
print >> file, "%2d" % bom.printed[part],
else:
print >> file, " ",
print >> file, part
print >> file
if self.assemblies:
print >> file, "Sub-assemblies:"
for ass in sorted(self.assemblies):
print >> file, "%3d %s" % (self.assemblies[ass].count, self.assemblies[ass].make_name(ass))
def boms(machine):
bom_dir = machine + "/bom"
if os.path.isdir(bom_dir):
shutil.rmtree(bom_dir)
os.makedirs(bom_dir)
f = open("scad/conf/machine.scad","wt")
f. write("include <%s_config.scad>\n" % machine);
f.close()
subprocess.call(["openscad_cl", "-o", "dummy.stl", "scad/bom.scad"])
print "Generating bom ...",
main = BOM()
stack = []
for line in open("openscad.log"):
if line[:7] == 'ECHO: "':
s = line[7:-2]
if s[-1] == '/':
ass = s[:-1]
if stack:
main.assemblies[stack[-1]].add_assembly(ass) #add to nested BOM
stack.append(ass)
main.add_assembly(ass) #add to flat BOM
else:
if s[0] == '/':
if s[1:] != stack[-1]:
raise Exception, "Mismatched assembly " + s[1:] + str(stack)
stack.pop()
else:
main.add_part(s)
main.assemblies[stack[-1]].add_part(s)
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
for ass in sorted(main.assemblies):
f = open(bom_dir + "/" + ass + ".txt", "wt");
bom = main.assemblies[ass]
print >> f, bom.make_name(ass) + ":"
bom.print_bom(False, f)
f.close()
print " done"
if __name__ == '__main__':
if len(sys.argv) > 1:
boms(sys.argv[1])
else:
print "usage: bom [mendel|sturdy|your_machine]"
sys.exit(1)

11
credits.txt Normal file
View File

@ -0,0 +1,11 @@
Fan model based on http://www.thingiverse.com/thing:8063 by MiseryBot, CC license.
Sangunino model http://www.thingiverse.com/thing:18606 by ax_the_b, CC license.
Spring taken from openscad example 20
x-end.scad and wade.scad uses some elements of the Prusa ones by Josef Prusa, GPL license.
z_couplings orginally based on http://www.thingiverse.com/thing:7153 by Griffin_Nicoll, GPL license.
Bearing holders originally based on http://www.thingiverse.com/thing:7755 by Jolijar, CC license.

132
dxf.py Normal file
View File

@ -0,0 +1,132 @@
from math import *
from svg import *
def parse_dxf(fn):
f = open(fn)
# skip to entities section
s = f.next()
while s.strip() != 'ENTITIES':
s = f.next()
in_line = False
in_circle = False
pt_list = []
cir_list = []
for line in f:
line = line.strip()
# In ENTITIES section, iteration can cease when ENDSEC is reached
if line == 'ENDSEC':
break
elif in_line:
keys = dict.fromkeys(['8','10','20','30','11','21','31'], 0.0)
while line != '0':
if line in keys:
keys[line] = float(f.next().strip())
line = f.next().strip()
pt_list.append( ((keys['10'], keys['20']), (keys['11'], keys['21'])) )
in_line = False
elif in_circle:
keys = dict.fromkeys(['8','10','20','30','40'], 0.0)
while line != '0':
if line in keys:
keys[line] = float(f.next().strip())
line = f.next().strip()
cir_list.append([[keys['10'], keys['20'], keys['30']], keys['40']])
in_circle = False
else:
if line == 'LINE':
in_line = True
elif line == 'CIRCLE' or line == 'ARC':
in_circle = True
f.close()
return pt_list, cir_list
def is_circle(path):
points = len(path)
if points < 9:
return None
for i in range(points) :
p1 = path[0]
p2 = path[int(points /3 )]
p3 = path[int(points * 2 / 3)]
if p1[0] != p2[0] and p2[0] != p3[0]:
ma = (p2[1] - p1[1]) / (p2[0] - p1[0])
mb = (p3[1] - p2[1]) / (p3[0] - p2[0])
if ma == mb:
return None
x = (ma * mb *(p1[1] - p3[1]) + mb * (p1[0] + p2[0]) - ma * (p2[0] + p3[0])) / (2 * (mb - ma))
if ma == 0:
y = -(x - (p2[0] + p3[0]) / 2) / mb + (p2[1] + p3[1]) / 2
else:
y = -(x - (p1[0] + p2[0]) / 2) / ma + (p1[1] + p2[1]) / 2
r = sqrt((p1[0] - x) * (p1[0] - x) + (p1[1] - y) * (p1[1] - y))
for p in path:
if abs(sqrt((p[0] - x) * (p[0] - x) + (p[1] - y) * (p[1] - y)) - r) > 0.1:
#print "error too big", abs(sqrt((p[0] - x) * (p[0] - x) + (p[1] - y) * (p[1] - y)) - r), points, 2 * r
#print p, path
return None
return [x,y, 2 * r, points]
path = path[1:] + path[:1] #rotate and try again
return None
def dxf_to_svg(fn):
ptList, cirList = parse_dxf(fn)
loops = []
for pt1, pt2 in ptList:
found = False
for i in range(len(loops)):
loop = loops[i]
p0 = loop[0]
p1 = loop[-1]
if pt1 == p0:
loops[i] = [pt2] + loop; found = True
elif pt2 == p0:
loops[i] = [pt1] + loop; found = True
elif pt1 == p1:
loops[i] = loop + [pt2]; found = True
elif pt2 == p1:
loops[i] = loop + [pt2]; found = True
if not found:
loops.append([pt1, pt2])
xmax = ymax = 0
xmin = ymin = 99999999
for loop in loops:
if len(loop) < 4 or loop[0] != loop[-1]:
raise Exception, "loop not closed " + str(loop)
for point in loop:
if point[0] > xmax: xmax = point[0]
if point[0] < xmin: xmin = point[0]
if point[1] > ymax: ymax = point[1]
if point[1] < ymin: ymin = point[1]
def p(x, y): return (x - xmin, ymax - y)
print xmin, ymin, xmax, ymax
scene = Scene(fn[:-4], ceil(ymax - ymin + 10), ceil(xmax - xmin + 10))
for loop in loops:
circle = is_circle(loop)
if circle:
x ,y, d, n = circle
scene.add(Circle(p(x, y), d / 2, (255,0,0)))
scene.add(Line( p(x + d, y), p(x - d, y) ))
scene.add(Line( p(x, y + d), p(x, y - d) ))
scene.add(Text( p(x + d / 2, y + d / 2), str(round(d,1)) ))
#scene.add(Text( p(x + d, y - d - 3), "[%0.1f, %0.1f]" % (x, y), 12 ))
else:
last = loop[-1]
for point in loop:
scene.add(Line(p(last[0],last[1]),p(point[0],point[1])))
last = point
scene.write_svg()
if __name__ == '__main__':
import sys
dxf_to_svg(sys.argv[1])

37130
imported_stls/39t17p.stl Normal file

File diff suppressed because it is too large Load Diff

BIN
imported_stls/pulley.stl Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

41988
imported_stls/wades_gear.stl Normal file

File diff suppressed because it is too large Load Diff

17
make_machine.py Normal file
View File

@ -0,0 +1,17 @@
import sys
from bom import boms
from sheets import sheets
from stls import stls
def make_machine(machine):
boms(machine)
sheets(machine)
stls(machine)
if __name__ == '__main__':
if len(sys.argv) > 1:
make_machine(sys.argv[1])
else:
print "usage: make_machine [mendel|sturdy|your_machine]"
sys.exit(1)

BIN
openscad.exe Normal file

Binary file not shown.

BIN
openscad_cl.exe Normal file

Binary file not shown.

221
scad/bar-clamp.scad Normal file
View File

@ -0,0 +1,221 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Rail supports
//
include <conf/config.scad>
include <positions.scad>
nut_trap_meat = 4; // how much plastic above the nut trap
wall = 3;
tab_height = 5;
function bar_clamp_inner_rad(d) = d / 2;
function bar_clamp_outer_rad(d) = bar_clamp_inner_rad(d) + bar_clamp_band;
function bar_clamp_stem(d) = bar_clamp_inner_rad(d) + bar_clamp_outer_rad(d) + bar_clamp_tab - 2;
function bar_clamp_length(d) = bar_clamp_tab + bar_clamp_stem(d) + bar_clamp_tab;
function bar_rail_offset(d) = bar_clamp_tab + d / 2 + bar_clamp_band;
function bar_clamp_switch_y_offset() = 12;
function y_switch_x(w) = -w / 2 - bar_clamp_switch_y_offset();
function y_switch_y(d) = bar_clamp_inner_rad(d) + microswitch_thickness() / 2 + 2;
function y_switch_z(h) = h + microswitch_button_x_offset();
function bar_clamp_switch_x_offset() = y_switch_y(Y_bar_dia);
function bar_clamp_switch_z_offset() = microswitch_button_x_offset();
module bar_clamp_holes(d)
for(y = [bar_rail_offset(d) - bar_clamp_length(d) + 0.5 * bar_clamp_tab,
bar_rail_offset(d) - 0.5 * bar_clamp_tab])
translate([0, y, 0])
child();
module bar_clamp(d, h, w, switch = false, yaxis = false) {
gap = 1.5;
inner_rad = bar_clamp_inner_rad(d);
outer_rad = bar_clamp_outer_rad(d);
stem = bar_clamp_stem(d);
length = bar_clamp_length(d);
rail_offset = bar_rail_offset(d);
cavity_l = stem - 2 * wall;
cavity_h = h - nut_trap_meat - nut_trap_depth;
cavity_w = w - 2 * wall;
sbracket_length = -y_switch_x(w) + 4;
sbracket_thickness = 7;
sbracket_height = microswitch_length();
color([0,1,0]) {
translate([0, rail_offset, 0]) {
union() {
difference() {
translate([0,-length/2,0]) rotate([90,0,90]) linear_extrude(height = w, center = true, convexity = 6) {
difference() {
union() {
translate([0, tab_height / 2, 0])
square([length, tab_height], center = true); // base
translate([0, h / 2, 0])
square([stem, h], center = true); // stem
translate([(stem/2 - outer_rad), h, 0])
circle(r = outer_rad, center = true); // band
translate([-stem/2 ,h,0])
square([stem - outer_rad, outer_rad]); // band tab
}
translate([(stem/2 - outer_rad), h, 0])
poly_circle(r = inner_rad, center = true); // bore
translate([-rail_offset, h, 0])
square([stem, gap]); // gap
}
}
//
// plastic saving cavity
//
translate([0, -cavity_l / 2 - bar_clamp_tab - wall, cavity_h / 2 - eta])
cube([cavity_w, cavity_l, cavity_h], center = true);
//
// nut trap
//
translate([0,-length + 1.5 * bar_clamp_tab,0])
rotate([0,0,90])
nut_trap(screw_clearance_radius, nut_radius, h - nut_trap_meat, horizontal = true);
//
// mounting holes
//
translate([0, -rail_offset, 0])
bar_clamp_holes(d)
rotate([0,0,90])
tearslot( h = 100, r = screw_clearance_radius(frame_screw), center = true, w = 2); // mounting screw
if(switch && !yaxis)
translate([-w / 2 - axis_endstop_clearance,
outer_rad + microswitch_thickness() / 2 - rail_offset,
h - outer_rad + microswitch_first_hole_x_offset()])
rotate([0, 90, 90])
microswitch_holes();
*translate([0,-50,-1]) cube([100,100,100]); // cross section for debug
}
if(switch && yaxis) { // switch bracket
difference() {
union() {
translate([w / 2 -sbracket_length,
y_switch_y(d) + microswitch_thickness() / 2 - rail_offset,
y_switch_z(h) - microswitch_button_x_offset() - microswitch_length() / 2])
cube([sbracket_length, sbracket_thickness, sbracket_height]);
translate([w / 2 - eta - sbracket_thickness,
y_switch_y(d) - microswitch_thickness() / 2 - rail_offset +0.5,
y_switch_z(h) - microswitch_button_x_offset() - microswitch_length() / 2])
cube([sbracket_thickness,
y_switch_y(d) - outer_rad + microswitch_thickness() / 2 + 1,
h - (y_switch_z(h) - microswitch_button_x_offset() - microswitch_length() / 2)]);
}
translate([y_switch_x(w), y_switch_y(d) - rail_offset, y_switch_z(h)])
mirror([0,1,0]) rotate([0, 90, 90])
microswitch_holes();
translate([0, - 0.5 * bar_clamp_tab - 0.5,0]) // screwdriver access
rotate([0,0,90])
teardrop(h = 100, r = 3, center = true, truncate = false);
}
}
}
}
}
}
module bar_clamp_assembly(d, h, w, name, switch = false, yaxis = true) {
inner_rad = bar_clamp_inner_rad(d);
outer_rad = bar_clamp_outer_rad(d);
length = bar_clamp_length(d);
rail_offset = bar_rail_offset(d);
//assembly(name);
stl(str(name, switch ? "_switch" : ""));
color([0,1,0]) render() bar_clamp(d, h, w, switch, yaxis);
//
// screw and washer for clamp
//
translate([0, rail_offset - length + 1.5 * bar_clamp_tab, h + inner_rad + bar_clamp_band])
screw_and_washer(cap_screw, screw_longer_than(outer_rad + nut_trap_meat + washer_thickness(washer) + nut_thickness(nut, true)));
//
// Captive nut
//
translate([0, rail_offset - length + 1.5 * bar_clamp_tab, h - nut_trap_meat])
rotate([180, 0, 90])
nut(nut, true);
//
// mounting screws and washers
//
for(y = [rail_offset - length + 0.5 * bar_clamp_tab, rail_offset - 0.5 * bar_clamp_tab])
translate([0, y, tab_height])
if(yaxis)
base_screw();
else
frame_screw(tab_height);
//
// limit switch
//
if(switch)
if(yaxis)
translate([y_switch_x(w), y_switch_y(d), y_switch_z(h)])
mirror([0,1,0]) rotate([0, 90, 90]) {
microswitch();
microswitch_hole_positions()
screw_and_washer(No2_screw, 13);
}
else
translate([-w / 2 - axis_endstop_clearance,
outer_rad + microswitch_thickness() / 2,
h - outer_rad + microswitch_first_hole_x_offset()])
rotate([0, 90, 90]) {
microswitch();
microswitch_hole_positions()
screw_and_washer(No2_screw, 13);
}
//end(name);
}
module y_bar_clamp_assembly(d, h, w, switch = false) {
bar_clamp_assembly(d, h, w, "y_bar_clamp", switch, yaxis = true);
}
module z_bar_clamp_assembly(d, h, w, switch = false) {
bar_clamp_assembly(d, h, w, "z_bar_clamp", switch, yaxis = false);
}
//bar_clamp(Z_bar_dia, gantry_setback, bar_clamp_depth, true);
module y_bar_clamp_stl() translate([0,0,bar_clamp_depth/2]) rotate([0,90,0]) bar_clamp(Y_bar_dia, Y_bar_height, bar_clamp_depth, false, true);
module y_bar_clamp_switch_stl() translate([0,0,bar_clamp_depth/2]) rotate([0,90,0]) bar_clamp(Y_bar_dia, Y_bar_height, bar_clamp_depth, true, true);
module z_bar_clamp_stl() translate([0,0,bar_clamp_depth/2]) rotate([0,90,0]) bar_clamp(Z_bar_dia, gantry_setback, bar_clamp_depth, false, false);
module z_bar_clamp_switch_stl() translate([0,0,bar_clamp_depth/2]) rotate([0,90,0]) bar_clamp(Z_bar_dia, gantry_setback, bar_clamp_depth, true, false);
if(0) {
z_bar_clamp_switch_stl();
translate([gantry_setback + 15, 0, 0]) z_bar_clamp_stl() ;
translate([10, 40, 0]) y_bar_clamp_switch_stl();
translate([gantry_setback + 25, 40, 0]) y_bar_clamp_stl();
translate([gantry_setback + 15, 80, 0]) y_bar_clamp_stl();
translate([0, 80, 0]) y_bar_clamp_stl();
}
else {
z_bar_clamp_assembly(Z_bar_dia, gantry_setback, bar_clamp_depth, true);
//bar_clamp(Z_bar_dia, gantry_setback, bar_clamp_depth, true, false);
//translate([30, 0, 0]) y_bar_clamp_assembly(Y_bar_dia, Y_bar_height, bar_clamp_depth, true);
//translate([30, 0, 0]) bar_clamp(Y_bar_dia, Y_bar_height, bar_clamp_depth, true, true);
}

60
scad/bearing-holder.scad Normal file
View File

@ -0,0 +1,60 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Fastens the bearings to the Y-carriage
//
// Based on a design by Jeffrey Olijar (Jolijar)
//
include <conf/config.scad>
wall = 2.5; // wall thickness
end_wall = 2.8;
clearance = 0.2; // end clearance
relief = 0.5; // clearance in the middle to stop the bearing rocking
ziptie_clearance = 1;
ziptie = small_ziptie;
zipslot_width = ziptie_width(ziptie) + ziptie_clearance;
zipslot_tickness = ziptie_thickness(ziptie) + ziptie_clearance;
function bearing_holder_length(bearing) = bearing[0] + 2 * (end_wall + clearance);
function bearing_holder_width(bearing) = bearing[1] + wall * 2;
function bearing_ziptie_radius(bearing) = bearing[1] / 2 + wall + eta;
module bearing_holder(bearing, bar_height, populate = false) {
bearing_length = bearing[0];
bearing_dia = bearing[1];
below = 5 * bearing_dia / 15;
height = bar_height + bearing_dia/2 - below;
offset = below + height / 2 - bearing_dia / 2;
fence = 2.5;
width = bearing_holder_width(bearing);
length = bearing_holder_length(bearing);
fence_offset = bearing_dia / 2 - fence + (fence + 1) /2;
union(){
difference() {
translate([0, 0, -offset]) // Basic shape
cube(size = [width, length, height], center = true);
rotate([90,0,0]) {
cylinder(h = length + 1, r = bearing_dia / 2, center=true); // Bearing Cutout
cylinder(h = length / 2, r = bearing_dia / 2 + relief, center=true);// releave the center so does not rock
tube(h = zipslot_width, ir = bearing_dia / 2 + wall,
or = bearing_dia / 2 + wall + zipslot_tickness, fn=64); // ziptie slot
}
}
translate([0, (length - end_wall)/ 2, -fence_offset]) cube(size = [width,end_wall,fence + 1], center = true); // Blocks at the end to keep the bearing from sliding out
translate([0, -(length - end_wall)/ 2, -fence_offset]) cube(size = [width,end_wall,fence + 1], center = true);
}
if(populate)
rotate([0,0,90])
linear_bearing(bearing);
}
bearing_holder(LM8UU, 20);

52
scad/bed.scad Normal file
View File

@ -0,0 +1,52 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Bed with glass and support pillars
//
include <conf/config.scad>
module bed_assembly() {
assembly("bed_assembly");
for(x = [-bed_holes / 2, bed_holes /2]) {
translate([x, bed_holes / 2, 0])
washer(M3_washer);
for(y = [-bed_holes / 2, bed_holes /2])
translate([x, y, washer_thickness(M3_washer)]) {
hex_pillar(bed_pillars);
translate([0,0, pillar_height(bed_pillars) + pcb_thickness]) {
//star_washer(M3_washer);
//translate([0,0, washer_thickness(M3_washer)])
screw(M3_cap_screw, 10);
}
}
}
translate([0, 0, washer_thickness(M3_washer)]) {
vitamin(str("BED", bed_width, bed_depth,": PCB bed ", bed_width, " x ", bed_depth));
translate([0,0, pillar_height(bed_pillars) + pcb_thickness / 2])
color([0.7,0,0]) cube([bed_width, bed_depth, pcb_thickness], center = true);
translate([0,0, pillar_height(bed_pillars) + pcb_thickness + sheet_thickness(glass) / 2 + eta * 3])
sheet(glass, bed_width, bed_depth - 12);
for(x = [-1, 1])
for(y = [-1,1])
translate([bed_width / 2 * x,
((bed_depth - bulldog_length(small_bulldog)) / 2 - washer_diameter(M3_washer)) * y,
pillar_height(bed_pillars) + (pcb_thickness + sheet_thickness(glass))/ 2])
rotate([0, 0, 90 + x * 90])
bulldog(small_bulldog, pcb_thickness + sheet_thickness(glass));
}
end("bed_assembly");
}
bed_assembly();

12
scad/bom.scad Normal file
View File

@ -0,0 +1,12 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// A dummy object to make a BOM
//
use <main.scad>
machine_assembly();

95
scad/cable_clip.scad Normal file
View File

@ -0,0 +1,95 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Cable clips to order
//
include <conf/config.scad>
wall = 2;
thickness = 5;
function cable_clip_width(screw) = wall + 2 * screw_clearance_radius(screw) + wall;
function cable_clip_height(cable) = max(cable_height(cable) + wall, thickness);
function cable_clip_extent(screw, cable) = screw_clearance_radius(screw) + wall + cable_width(cable) + wall;
function cable_clip_offset(screw, cable) = screw_clearance_radius(screw) + wall + cable_width(cable) / 2;
module single_cable_clip(cable, screw, h = 0) {
screw_dia = 2 * screw_clearance_radius(screw);
height = cable_clip_width(screw);
depth = h ? h : cable_height(cable) + wall;
width = wall + cable_width(cable) + wall + screw_dia + wall;
hole_x = wall + cable_width(cable) + wall + screw_dia / 2;
rad = min(wall + cable_wire_size(cable) / 2, depth / 2);
translate([-hole_x, 0, 0]) difference() {
linear_extrude(height = height)
hull() {
square([width, 1]);
translate([width - 1, 0])
square([1, depth]);
translate([rad, depth - rad])
circle(r = rad);
}
translate([wall + cable_width(cable) / 2, 0, 0])
rounded_rectangle([cable_width(cable), cable_height(cable) * 2], cable_wire_size(cable) / 2, center = true);
translate([hole_x, depth / 2, height / 2])
rotate([90,0,0])
teardrop_plus(h = depth + 1, r = screw_dia / 2, center = true);
}
}
module double_cable_clip(cable1, cable2, screw_dia) {
h = max(cable_clip_height(cable1), cable_clip_height(cable2));
union() {
single_cable_clip(cable1, screw_dia, h);
mirror([1,0,0]) single_cable_clip(cable2, screw_dia, h);
}
}
module cable_clip(screw, cable1, cable2 = 0) {
if(cable2) {
stl(str("cable_clip_", cable1[2], cable2[2]));
double_cable_clip(cable1, cable2, screw);
}
else {
stl(str("cable_clip_",2 * screw_radius(screw), cable1[2]));
single_cable_clip(cable1, screw);
}
}
module cable_clip_assembly(screw, screw_length, cable1, cable2 = 0) {
color([1,0,0]) render() translate([0, cable_clip_width(screw) / 2, 0]) rotate([90, 0, 0])
cable_clip(screw, cable1, cable2);
translate([0, 0, max(cable_clip_height(cable1), cable_clip_height(cable2))])
screw_and_washer(screw, screw_length);
}
module cable_clip_AB_stl() cable_clip(base_clip_screw, endstop_wires, motor_wires);
module cable_clip_AD_stl() cable_clip(frame_clip_screw, endstop_wires, fan_motor_wires);
module cable_clip_CA_stl() cable_clip(base_clip_screw, thermistor_wires, bed_wires);
spacing = cable_clip_height(motor_wires) + 1;
if(1)
cable_clip_assembly(base_clip_screw, base_screw_length, endstop_wires, motor_wires);
else {
translate([0, -cable_clip_height(bed_wires) - 1, 0])
cable_clip(base_clip_screw, thermistor_wires, bed_wires);
for(i=[0:1])
translate([0, spacing * i, 0])
cable_clip(base_clip_screw, endstop_wires, motor_wires);
for(i=[2:3])
translate([0, spacing * i, 0])
cable_clip(frame_clip_screw, endstop_wires, fan_motor_wires);
}

34
scad/cal.scad Normal file
View File

@ -0,0 +1,34 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// A test object for calibration
//
include <conf/config.scad>
module cal() {
difference() {
union() {
cube([10,40,5]);
cube([40,10,6]);
cube([20,20,10]);
translate([10, 10])
cylinder(r = 10, h = 15);
}
translate([10,10,15])
nut_trap(Z_screw_dia / 2, Z_nut_radius, Z_nut_depth);
translate([5,30,5])
rotate([0,0,90])
nut_trap(M3_clearance_radius, M3_nut_radius, M3_nut_trap_depth);
translate([30,5,6])
nut_trap(M4_clearance_radius, M4_nut_radius, M4_nut_trap_depth);
}
}
cal();

148
scad/conf/config.scad Normal file
View File

@ -0,0 +1,148 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Configuration file
//
bom = 2; // 0 no bom, 1 assemblies and stls, 2 vitamins as well
exploded = false; // true for exploded view
eta = 0.01; // small fudge factor to stop CSG barfing on coincident faces.
$fa = 5;
$fs = 0.5;
//
// Hole sizes
//
No2_pilot_radius = 1.7 / 2; // self tapper into ABS
No4_pilot_radius = 2.0 / 2; // wood screw into soft wood
No6_pilot_radius = 2.0 / 2; // wood screw into soft wood
No2_clearance_radius = 2.5 / 2;
No4_clearance_radius = 3.5 / 2;
No6_clearance_radius = 4.0 / 2;
M2p5_tap_radius = 2.05 / 2;
M2p5_clearance_radius= 2.8 / 2; // M2.5
M3_tap_radius = 2.5 / 2;
M3_clearance_radius = 3.3 / 2;
M3_nut_radius = 6.5 / 2;
M3_nut_trap_depth = 3;
M4_tap_radius = 3.3 / 2;
M4_clearance_radius = 2.2;
M4_nut_radius = 8.2 / 2;
M4_nut_trap_depth = 4.5;
M6_tap_radius = 5 / 2;
M6_clearance_radius = 6.4 / 2;
M6_nut_radius = 11.6 / 2;
M6_nut_depth = 5;
M8_tap_radius = 6.75 / 2;
M8_clearance_radius = 8.4 / 2;
M8_nut_radius = 15.4 / 2;
M8_nut_depth = 6.5;
layer_height = 0.4;
filament_width = layer_height * 1.5;
min_wall = 2 * filament_width + eta;
pcb_thickness = 1.6;
include <utils.scad>
include <vitamins.scad>
endstop_wires = [2, 1.4, "A"]; // 7 strands of 0.2
motor_wires = [4, 1.4, "B"];
bed_wires = [2, 2.8, "C"]; // 13A mains cable
fan_motor_wires = [6, 1.4, "D"]; // fan and motor wires along top of gantry
thermistor_wires = endstop_wires;
endstop_wires_hole_radius = wire_hole_radius(endstop_wires);
motor_wires_hole_radius = wire_hole_radius(motor_wires);
fan_motor_wires_hole_radius = wire_hole_radius(fan_motor_wires);
bed_wires_hole_radius = wire_hole_radius(bed_wires);
thermistor_wires_hole_radius = wire_hole_radius(thermistor_wires);
include <machine.scad> // this file is generated from the command line parameter to include one of the machine configs
screw_clearance_radius = screw_clearance_radius(cap_screw);
nut = screw_nut(cap_screw);
nut_radius = nut_radius(nut);
nut_trap_depth = nut_trap_depth(nut);
washer = screw_washer(cap_screw);
bearing_clamp_tab = washer_diameter(washer) + 2; // how much the lugs stick out and their width
bearing_clamp_tab_height = 4; // thickness of the lugs
hole_edge_clearance = 5; // how close a hole can be to the edge of a sheet
base_clearance = 2; // how close we get to the edge of the base
axis_endstop_clearance = 2; // how close we get to the end of an axis
X_carriage_clearance = 2; // how close the X carriage is to the XZ plane
// how close the Y carriage is to the window in the XZ plane
Y_carriage_clearance = 2 + bulldog_handle_length(small_bulldog) - (Y_carriage_width - bed_width) / 2;
Z_clearance = 10; // How close the top of the object gets to the gantry
belt_clearance = 0.2; // clearance of belt clamp slots
pulley_inner_radius = (14.4 / 2) - belt_thickness(T5x6); // measured from outer diameter
X_bar_dia = X_bearings[2]; // rod sizes to match the bearings
Y_bar_dia = Y_bearings[2];
Z_bar_dia = Z_bearings[2];
Y_idler_bearing = BB624;
X_idler_bearing = BB624;
extruder_ways = 4 + 4 + 2 + 1 + 1; // motor + heater(x2) + thermistor + probe + fan = 12
x_end_ways = extruder_ways + 4 + 2 + 2; // motor plus limit switch and two guards = 20
bed_ways = 20 + 2; // ten each way for the current plus a thermistor
function z_bar_offset() = round(NEMA_width(Z_motor)) / 2;
base_screw = sheet_is_soft(base) ? frame_soft_screw : frame_thick_screw;
base_screw_length = screw_shorter_than(sheet_thickness(base) + 5 + 2 * washer_thickness(screw_washer(base_screw)));
base_clip_screw = base_screw;
base_clip_screw_length = base_screw_length;
frame_screw = sheet_is_soft(frame) ? frame_soft_screw : frame_nuts ? frame_thin_screw : frame_thick_screw;
frame_clip_screw = frame_screw;
frame_screw_length = frame_nuts ? screw_longer_than(sheet_thickness(frame) + 5 + 2 * washer_thickness(screw_washer(frame_screw)) +
nut_thickness(screw_nut(frame_screw), true))
: screw_shorter_than(sheet_thickness(frame) + 5 + 2 * washer_thickness(screw_washer(frame_screw)));
frame_clip_screw_length = frame_screw_length;
echo("base screw length", base_screw_length);
echo("frame screw length",frame_screw_length);
module frame_screw(thickness) {
screw_and_washer(frame_screw, frame_screw_length, !frame_nuts);
if(frame_nuts)
translate([0, 0, -sheet_thickness(frame) - thickness])
rotate([180, 0, 0])
nut_and_washer(screw_nut(frame_screw), true);
}
module frame_screw_hole() {
cylinder(r = frame_nuts ? screw_clearance_radius(frame_screw) :
screw_pilot_hole(frame_screw), h = 100, center = true);
}
module base_screw() {
screw_and_washer(base_screw, base_screw_length, true);
}
module base_screw_hole() {
cylinder(r = screw_pilot_hole(base_screw), h = 100, center = true);
}
bar_clamp_depth = 4 + washer_diameter(screw_washer(base_screw)); // how thick the bar clamps are
bar_clamp_tab = 3 + washer_diameter(screw_washer(base_screw)); // how much the lugs stick out
bar_clamp_band = 3; // the thickness of the strap that clamps the bar.

View File

@ -0,0 +1,73 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Configuration file
//
echo("Huxley:");
Z_bearings = LM6UU;
Y_bearings = LM6UU;
X_bearings = LM6UU;
X_motor = NEMA14;
Y_motor = NEMA14;
Z_motor = NEMA14;
X_travel = 140;
Y_travel = 140;
Z_travel = 110;
bed_depth = 150;
bed_width = 150;
bed_pillars = M3x20_pillar;
bed_thickness = 1.6 + sheet_thickness(glass); // PCB heater plus glass sheet
bed_holes = 146;
base = PMMA10; // Sheet material used for the base. Needs to be thick enough to screw into.
base_corners = 50;
frame = PMMA6;
frame_corners = 25;
frame_nuts = false;
case_fan = fan80x38;
single_piece_frame = true;
stays_from_window = false;
Y_carriage = PMMA6;
extruder_width = 30; // actually 28 but offset
nozzle_x_offset = 16; // offset from centre of the extruder
nozzle_length = 50; // from base of extruder to nozzle tip
X_belt = T5x6;
Y_belt = T5x6;
motor_shaft = 5;
Z_screw_dia = 6; // Studding for Z axis
Y_carriage_depth = bed_depth + 10;
Y_carriage_width = bed_width + 10;
Z_nut_radius = M6_nut_radius;
Z_nut_depth = M6_nut_depth;
Z_nut = M6_nut;
//
// Default screw use where size doesn't matter
//
cap_screw = M3_cap_screw;
hex_screw = M3_hex_screw;
//
// Screw for the frame and base
//
frame_soft_screw = No4_screw; // Used when sheet material is soft, e.g. wood
frame_thin_screw = M3_cap_screw; // Used with nuts when sheets are thin
frame_thick_screw = M3_pan_screw; // Used with tapped holes when sheets are thick and hard, e.g. plastic or metal
//
// Feature sizes
//
default_wall = 3;
thick_wall = 3;

View File

@ -0,0 +1,76 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Configuration file
//
echo("Mendel:");
Z_bearings = LM8UU;
Y_bearings = LM8UU;
X_bearings = LM8UU;
X_motor = NEMA17;
Y_motor = NEMA17;
Z_motor = NEMA17;
X_travel = 200;
Y_travel = 200;
Z_travel = 140;
bed_depth = 214;
bed_width = 214;
bed_pillars = M3x20_pillar;
bed_thickness = 1.6 + sheet_thickness(glass); // PCB heater plus glass sheet
bed_holes = 209;
base = PMMA10; // Sheet material used for the base. Needs to be thick enough to screw into.
base_corners = 50;
frame = PMMA6;
frame_corners = 25;
frame_nuts = false;
case_fan = fan80x38;
psu = KY240W;
single_piece_frame = true;
stays_from_window = false;
Y_carriage = PMMA6;
extruder_width = 30; // actually 28 but offset
nozzle_x_offset = 16; // offset from centre of the extruder
nozzle_length = 50; // from base of extruder to nozzle tip
X_belt = T5x6;
Y_belt = T5x6;
motor_shaft = 5;
Z_screw_dia = 8; // Studding for Z axis
Y_carriage_depth = bed_depth + 10;
Y_carriage_width = bed_width + 10;
Z_nut_radius = M8_nut_radius;
Z_nut_depth = M8_nut_depth;
Z_nut = M8_nut;
//
// Default screw use where size doesn't matter
//
cap_screw = M3_cap_screw;
hex_screw = M3_hex_screw;
//
// Screw for the frame and base
//
frame_soft_screw = No6_screw; // Used when sheet material is soft, e.g. wood
frame_thin_screw = M4_cap_screw; // Used with nuts when sheets are thin
frame_thick_screw = M4_pan_screw; // Used with tapped holes when sheets are thick and hard, e.g. plastic or metal
//
// Feature sizes
//
default_wall = 3;
thick_wall = 4;

48
scad/conf/positions.scad Normal file
View File

@ -0,0 +1,48 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Work out the positions and size of things
//
use <y-motor-bracket.scad>
use <x-carriage.scad>
use <x-end.scad>
Y_carriage_height = y_motor_bracket_height() + X_carriage_clearance + sheet_thickness(Y_carriage) / 2;
bed_height = Y_carriage_height + sheet_thickness(Y_carriage) / 2 + pillar_height(bed_pillars) + washer_thickness(M3_washer) + bed_thickness;
Z0 = floor(bed_height + nozzle_length - x_carriage_offset());
height = Z0 + Z_travel + x_end_height() + bar_clamp_depth + axis_endstop_clearance + base_clearance;
gantry_thickness = height - max(bed_height + Z_travel + Z_clearance, Y_carriage_depth + 1);
gantry_setback = X_carriage_clearance + x_carriage_width() / 2;
Z_bar_spacing = X_travel + x_carriage_length() + 2 * (axis_endstop_clearance + Z_bearings[1] / 2);
base_width = base_clearance - x_idler_overhang() + Z_bar_spacing -x_motor_overhang() + base_clearance;
base_depth = Y_travel + Y_carriage_depth + 2 * base_clearance + 2 * axis_endstop_clearance;
window_width = Y_carriage_width + Y_carriage_clearance * 2;
stay_depth = stays_from_window ? window_width / 2 : base_depth / 2 - (gantry_setback + sheet_thickness(frame));
stay_height = single_piece_frame && !stays_from_window ? height : height - gantry_thickness - 1;
idler_end = -base_width / 2 + base_clearance - x_idler_overhang();
motor_end = base_width / 2 - base_clearance + x_motor_overhang();
X_origin = (idler_end + motor_end) / 2 + nozzle_x_offset;
left_w = (base_width - window_width)/2 + X_origin;
right_w = (base_width - window_width)/2 - X_origin;
Y_belt_height = y_motor_height() + pulley_inner_radius + belt_thickness(Y_belt);
Y_bar_height = Y_belt_height;
Y_belt_clamp_height = Y_carriage_height - Y_belt_height - sheet_thickness(Y_carriage) / 2;
Y_bearing_holder_height = Y_carriage_height - Y_bar_height - sheet_thickness(Y_carriage) / 2;

View File

@ -0,0 +1,76 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Configuration file
//
echo("Sturdy:");
Z_bearings = LM10UU;
Y_bearings = LM10UU;
X_bearings = LM10UU;
X_motor = NEMA17;
Y_motor = NEMA17;
Z_motor = NEMA17;
X_travel = 214;
Y_travel = 218;
Z_travel = 150;
bed_depth = 214;
bed_width = 214;
bed_pillars = M3x20_pillar;
bed_thickness = 1.6 + sheet_thickness(glass); // PCB heater plus glass sheet
bed_holes = 209;
base = MDF12;
base_corners = 0;
frame = MDF12;
frame_corners = 0;
frame_nuts = false;
case_fan = fan80x38;
psu = KY240W;
single_piece_frame = true;
stays_from_window = false;
Y_carriage = DiBond;
extruder_width = 30; // actually 28 but offset
nozzle_x_offset = 16; // offset from centre of the extruder
nozzle_length = 50; // from base of extruder to nozzle tip
X_belt = T5x6;
Y_belt = T5x6;
motor_shaft = 5;
Z_screw_dia = 8; // Studding for Z axis
Y_carriage_depth = bed_depth + 10;
Y_carriage_width = bed_width + 10;
Z_nut_radius = M8_nut_radius;
Z_nut_depth = M8_nut_depth;
Z_nut = M8_nut;
//
// Default screw use where size doesn't matter
//
cap_screw = M4_cap_screw;
hex_screw = M4_hex_screw;
//
// Screw for the frame and base
//
frame_soft_screw = No6_screw; // Used when sheet material is soft, e.g. wood
frame_thin_screw = M4_cap_screw; // Used with nuts when sheets are thin
frame_thick_screw = M4_pan_screw; // Used with tapped holes when sheets are thick and hard, e.g. plastic or metal
//
// Feature sizes
//
default_wall = 4;
thick_wall = 4;

119
scad/conf/utils.scad Normal file
View File

@ -0,0 +1,119 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Utilities
//
include <../utils/bom.scad>
include <../utils/polyholes.scad>
include <../utils/teardrops.scad>
include <../utils/cables.scad>
module slot(h, r, l, center = true)
linear_extrude(height = h, convexity = 6, center = center)
hull() {
translate([l/2,0,0])
circle(r = r, center = true);
translate([-l/2,0,0])
circle(r = r, center = true);
}
module nut_trap(screw_r, nut_r, depth, horizontal = false) {
union() {
if(horizontal) {
teardrop_plus(r = screw_r, h = 200, center = true);
cylinder(r = nut_r + layer_height / 4, h = depth * 2, center = true, $fn = 6);
}
else {
poly_cylinder(r = screw_r, h = 200, center = true);
cylinder(r = nut_r, h = depth * 2, center = true, $fn = 6);
}
}
}
module fillet(r, h) {
translate([r / 2, r / 2, 0])
difference() {
cube([r + eta, r + eta, h], center = true);
translate([r/2, r/2, 0])
cylinder(r = r, h = h + 1, center = true);
}
}
module right_triangle(width, height, h, center = true) {
linear_extrude(height = h, center = center)
polygon(points = [[0,0], [width, 0], [0, height]]);
}
module rounded_square(w, h, r)
{
union() {
square([w - 2 * r, h], center = true);
square([w, h - 2 * r], center = true);
for(x = [-w/2 + r, w/2 - r])
for(y = [-h/2 + r, h/2 - r])
translate([x, y])
circle(r = r);
}
}
module rounded_rectangle(size, r, center = true)
{
w = size[0];
h = size[1];
linear_extrude(height = size[2], center = center)
rounded_square(size[0], size[1], r);
}
//
// Cylinder with rounded ends
//
module rounded_cylinder(r, h, r2)
{
rotate_extrude()
union() {
square([r - r2, h]);
square([r, h - r2]);
translate([r - r2, h - r2])
circle(r = r2);
}
}
module sector(r, a, h, , center = true) {
linear_extrude(height = h, center = center)
intersection() {
circle(r = r, center = true);
polygon(points = [
[0, 0],
[2 * r * cos(a / 2), 2 * r * sin(a / 2)],
[2 * r * cos(a / 2), -2 * r * sin(a / 2)],
]);
}
}
module tube(or, ir, h, center = true) {
difference() {
cylinder(r = or, h = h, center = center);
cylinder(r = ir, h = h + 1, center = center);
}
}
//
// Exploded view helper
//
module explode(v, offset = [0,0,0]) {
if(exploded) {
translate(v)
child();
render() hull() {
sphere(0.2);
translate(v + offset)
sphere(0.2);
}
}
else
child();
}

48
scad/conf/vitamins.scad Normal file
View File

@ -0,0 +1,48 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Off the shelf parts
//
include <../vitamins/washers.scad>
include <../vitamins/nuts.scad>
include <../vitamins/screws.scad>
include <../vitamins/microswitch.scad>
include <../vitamins/stepper-motors.scad>
include <../vitamins/ball-bearings.scad>
include <../vitamins/linear-bearings.scad>
include <../vitamins/pillars.scad>
include <../vitamins/belts.scad>
include <../vitamins/sheet.scad>
include <../vitamins/springs.scad>
include <../vitamins/d-connectors.scad>
include <../vitamins/ziptie.scad>
include <../vitamins/bulldog.scad>
include <../vitamins/cable_strip.scad>
include <../vitamins/fans.scad>
include <../vitamins/electronics.scad>
module rod(d , l) {
vitamin(str("RD", d, round(l), ": Smooth rod ", d, " x ", round(l)));
color([0.8,0.8,0.8])
cylinder(r = d / 2, h = l, center = true);
}
module studding(d , l) {
vitamin(str("ST", d, round(l),": Threaded rod ", d, " x ", round(l)));
color([0.5,0.5,0.5])
cylinder(r = d / 2, h = l, center = true);
}
module tubing(od, id, length) {
vitamin(str("TB", od, id, length,": Tubing OD ",od, " ID ", id," x ",length));
color([0.8, 0.8, 0.8, 0.75]) render() difference() {
cylinder(r = od / 2, h = length, center = true);
cylinder(r = id / 2, h = length + 1, center = true);
}
}

337
scad/d-motor_bracket.scad Normal file
View File

@ -0,0 +1,337 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Bracket to mount 9 way D type to back of motor
//
include <conf/config.scad>
use <ribbon_clamp.scad>
connector = DCONN9;
thickness = 2.4;
lid_thickness = 2.4;
wall = 2;
front_thickness = wall + No2_pilot_radius + washer_diameter(M2p5_washer) / 2 + 1;
echo(front_thickness);
slot_width = 21;
inner_slot_width = 15.6;
slot_height = 11;
face_height = 13;
flange_clearance = 0.2;
flange_width = d_flange_length(connector) + 2 * flange_clearance;
flange_height = d_flange_width(connector) + flange_clearance;
flange_thickness = d_flange_thickness(connector) + flange_clearance;
overlap = 5; // how much it overlaps the side of the motor
length = overlap + thickness + 20;
height = slot_height / 2 + face_height / 2 + thickness;
d_width = flange_width + 2 * wall; //slot_width + 4 * (wall + No2_pilot_radius);
nut_slot = nut_thickness(M3_nut) + 0.3;
lug_depth = nut_slot + 3 * wall;
lug_width = 2 * nut_flat_radius(M3_nut) + wall;
lug_height = thickness + slot_height / 2 + M3_nut_radius;
screw_x = length - wall - No2_pilot_radius;
screw_y = (d_width + slot_width) / 4;
pitch = d_width + 2 * nut_flat_radius(M3_nut);
nut_x = length + flange_thickness + wall -lug_depth + wall;
//function d_motor_bracket_offset(motor) = NEMA_holes(motor)[1] + screw_head_radius(M3_cap_screw) - inner_slot_width / 2;
function d_motor_bracket_offset(motor) = NEMA_holes(motor)[0] + (2.5 / cos(30)) / 2 + d_width / 2 + lug_width;
//function d_motor_bracket_offset(motor) = (NEMA_width(motor) + 2 * thickness - d_width) / 2;
//
// Lid to retain connector and nuts
//
module d_motor_bracket_lid_stl(motor = NEMA17, nuts = true) {
if(nuts)
stl("d_motor_bracket_lid");
else
stl("d_shell_lid");
lid_width = front_thickness + flange_thickness + wall;
nut_cover_width = d_width + 2 * lug_width;
nut_cover_height = height + lid_thickness - lug_height - flange_clearance;
nut_cover_depth = lug_depth;
difference() {
union() {
translate([length - front_thickness + lid_width / 2, 0, 0])
rounded_rectangle([lid_width, d_width, lid_thickness], 2, center = false);
if(nuts)
translate([length - front_thickness + lid_width - nut_cover_depth / 2, 0, 0])
rounded_rectangle([nut_cover_depth, nut_cover_width, nut_cover_height], 2, center = false);
}
if(nuts)
translate([length - nut_cover_depth, -d_width / 2 - flange_clearance, lid_thickness - eta])
cube([nut_cover_depth * 2, d_width + 2 * flange_clearance, 10]);
for(side = [-1, 1])
translate([screw_x, side * screw_y, 0])
rotate([0, 0, -side * 360 / 20])
poly_cylinder(r = No2_clearance_radius, h = 100, center = true);
}
}
module d_shell_lid_stl() d_motor_bracket_lid_stl(motor = NEMA17, nuts = false);
//
// Attaches to the motor
//
module d_motor_bracket_stl(motor = NEMA17) {
stl("d_motor_bracket");
m_width = NEMA_width(motor) + 2 * thickness;
offset = d_motor_bracket_offset(motor) + (m_width - d_width) / 2;
mouth = pitch + 2 * M3_clearance_radius + layer_height / 2;
difference() {
union() {
linear_extrude(height = thickness, convexity = 5) // base
polygon(points = [ [0, 0],
[overlap, 0],
[overlap, offset],
[length - eta, offset],
[length - eta, offset + d_width],
[overlap, offset + d_width],
[overlap, m_width],
[0, m_width],
]);
translate([overlap , 0, eta]) // motor wall
cube([thickness, d_width + offset, height]);
for(y = [0, m_width - thickness]) // buttresses
translate([overlap + eta, y, thickness - eta])
rotate([90, 0, 180])
right_triangle(width = overlap, height = height - thickness, h = thickness, center = false);
difference() {
union() {
// connector wall
translate([length - front_thickness, offset, eta])
cube([front_thickness + flange_thickness + wall, d_width, height]);
// nut lugs
translate([length + flange_thickness + wall - lug_depth / 2, offset + d_width / 2, eta])
rounded_rectangle([lug_depth, d_width + 2 * lug_width, lug_height], r = 2, center = false);
// d side walls
for(y = [0, d_width - thickness])
translate([overlap, y + offset, eta])
cube([length - overlap, thickness, height]);
}
translate([length, offset + (d_width - flange_width) / 2, thickness + slot_height / 2 - flange_height / 2])
cube([flange_thickness, flange_width, 20]); // slot for flange
translate([10, d_width / 2 - slot_width / 2 + offset, thickness + eta * 2]) //slot for connector body
cube([30, slot_width, 20]);
for(side = [-1, 1]) {
translate([nut_x + nut_slot / 2, d_width / 2 - side * pitch / 2 + offset, thickness + slot_height / 2]) //connector screws
rotate([90, 0, 90]) {
rotate([0,0,30])
nut_trap(1, M3_nut_radius, nut_slot / 2, true);
translate([0, 5, 0])
cube([nut_flat_radius(M3_nut) * 2, 10, nut_slot], center = true);
teardrop_plus(r = M3_clearance_radius, h = 100, center = true);
}
translate([screw_x, d_width / 2 - side * screw_y + offset, height + lid_thickness]) // lid screws holes
rotate([0,0,180])
poly_cylinder(r = No2_pilot_radius, h = 12 * 2, center = true);
}
}
}
for(y = NEMA_holes(motor)) // motor screws
for(z = NEMA_holes(motor))
translate([overlap - 1, m_width / 2 + y, NEMA_width(motor) / 2 + thickness + z])
rotate([90,0,90])
teardrop_plus(r = M3_clearance_radius, h = thickness + 2, center = false);
}
}
//
// Attaches connector to ribbon cable and plastic strip
//
cable_guide_width = 20;
cable_guide_thickness = 4;
cable_screw = M3_cap_screw;
shell_front = front_thickness;
shell_length = shell_front + 12 + ribbon_clamp_width(cable_screw);
shell_screw_x = shell_length - wall - No2_pilot_radius;
function d_motor_connector_offset(motor) = [
NEMA_width(motor) / 2 + thickness - cable_guide_thickness,
-NEMA_length(motor) + overlap - length - d_mate_distance(connector) - shell_length + ribbon_clamp_width(cable_screw),
d_motor_bracket_offset(motor)
];
module d_shell_stl() {
stl("d_shell");
mouth = pitch + 2 * screw_clearance_radius(cable_screw) + layer_height / 2;
rad = ribbon_clamp_width(cable_screw) / 2;
clamp_pitch = ribbon_clamp_pitch(extruder_ways, cable_screw);
front = shell_front + flange_thickness + wall;
union() {
difference() {
union() {
translate([shell_length - shell_front, 0, 0]) // connector wall
cube([front, d_width, height]);
// screw lugs
translate([shell_length + flange_thickness + wall - front / 2, d_width / 2, eta])
rounded_rectangle([front, d_width + 2 * lug_width,
thickness + slot_height / 2 + washer_diameter(M3_washer) / 2 + 1], r = 2, center = false);
linear_extrude(height = cable_guide_thickness, convexity = 5)
hull() {
for(side = [-1,1])
translate([rad, d_width / 2 + side * clamp_pitch / 2])
circle(r = rad, center = true);
translate([shell_length - shell_front, 0])
square([1, d_width]);
}
}
translate([shell_length,(d_width - flange_width) / 2, thickness + slot_height / 2 - flange_height / 2])
cube([flange_thickness, flange_width, 20]); // slot for flange
translate([rad * 2, d_width / 2 - slot_width / 2 , thickness - eta]) //slot for connector body
cube([30, slot_width, 20]);
for(side = [-1, 1]) {
translate([nut_x + nut_slot / 2, d_width / 2 - side * pitch / 2, thickness + slot_height / 2]) //connector screws
rotate([90, 0, 90])
teardrop_plus(r = M3_clearance_radius, h = 100, center = true);
translate([shell_screw_x, d_width / 2 - side * screw_y, height + lid_thickness]) // lid screws holes
rotate([0,0,180])
poly_cylinder(r = No2_pilot_radius, h = 12 * 2, center = true);
}
//
// clamp screw holes
//
translate([rad, d_width / 2, cable_guide_thickness / 2])
rotate([0, 0, 90])
ribbon_clamp_holes(extruder_ways, cable_screw)
poly_cylinder(r = screw_clearance_radius(cable_screw), h = 100, center = true);
}
}
}
module d_shell_assembly(motor) {
translate([-NEMA_width(motor) / 2 + slot_height / 2, d_motor_bracket_offset(motor), -NEMA_length(motor) + overlap]) {
translate([0, 0, -length - d_mate_distance(connector)])
rotate([0, 0, 90])
explode([0, -25, 0])
d_socket(connector);
}
translate([-NEMA_width(NEMA17) / 2 - thickness,
d_width / 2 + d_motor_bracket_offset(motor),
-NEMA_length(NEMA17) - length - shell_length - d_mate_distance(connector) + overlap])
rotate([0, -90, 180]) {
color([0,1,0]) render() d_shell_stl();
translate([0, d_width / 2, height + lid_thickness])
translate([length, 0, 0])
explode([0, 0, 40])
translate([-length, 0, 0])
color([1,0,0]) render() rotate([180, 0, 0]) d_shell_lid_stl(motor);
for(side = [-1, 1]) {
translate([shell_length - shell_front, d_width / 2 - side * pitch / 2, thickness + slot_height / 2]) //connector screws
rotate([90, 0, -90])
screw_and_washer(M3_cap_screw, 20);
translate([shell_screw_x, d_width / 2 - side * screw_y, height + lid_thickness])
//explode([0, 0, 40])
screw_and_washer(No2_screw, 13);
}
translate([ribbon_clamp_width(M3_cap_screw) / 2, d_width / 2, cable_guide_thickness])
rotate([0, 0, 90])
ribbon_clamp_assembly(extruder_ways, cable_screw, 16, cable_guide_thickness, false, true);
}
}
module d_motor_bracket_assembly(motor) {
rotate([0, 90, 0])
translate([NEMA_length(NEMA17) - overlap, -NEMA_width(NEMA17) / 2 - thickness, -NEMA_width(NEMA17) / 2 - thickness]) {
color([0,1,0]) render() d_motor_bracket_stl(NEMA17);
translate([0, NEMA_width(NEMA17) / 2 + d_motor_bracket_offset(NEMA17) + thickness, height + lid_thickness])
translate([length, 0, 0])
explode([0, 0, 40])
translate([-length, 0, 0])
color([1,0,0]) render() rotate([180, 0, 0]) d_motor_bracket_lid_stl(motor);
}
translate([-NEMA_width(motor) / 2 + slot_height / 2, d_motor_bracket_offset(motor), -NEMA_length(motor) + overlap]) {
translate([0, 0, -length])
rotate([180, 0, -90])
explode([0, -25, 0])
d_plug(connector);
for(side = [-1, 1]) {
translate([0, pitch / 2 * side, -nut_x])
rotate([180, 0, 0])
explode([10,0,0])
nut(M3_nut);
translate([height - slot_height / 2 - thickness + lid_thickness, side * screw_y, - screw_x])
rotate([0, 90, 0])
explode([0, 0, 40])
screw_and_washer(No2_screw, 13);
}
}
for(y = NEMA_holes(motor)) // motor screws
for(x = NEMA_holes(motor))
if(x < 0)
translate([x, y, -NEMA_length(motor) - thickness])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, 45);
}
if(1) {
NEMA(NEMA17);
d_motor_bracket_assembly(NEMA17);
translate([0, 0, exploded ? - 20 : 0])
d_shell_assembly(NEMA17);
}
else {
d_motor_bracket_stl(NEMA17);
translate([11, 35, 0])
d_motor_bracket_lid_stl(NEMA17);
translate([22, 35, 0])
d_shell_lid_stl(NEMA17);
translate([-32, 6, 0])
d_shell_stl(NEMA17);
translate([25, 4, ribbon_clamp_thickness()])
ribbon_clamp(extruder_ways, cable_screw);
}

51
scad/fan-guard.scad Normal file
View File

@ -0,0 +1,51 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
//
//
include <conf/config.scad>
thickness = 2;
wall = 2 * filament_width + eta;
finger_width = 7;
spokes = 4;
function fan_guard_thickness() = thickness;
module fan_guard(type) {
stl("fan_guard");
hole_pitch = fan_hole_pitch(type);
screw = fan_screw(type);
corner_radius = washer_diameter(screw_washer(screw)) / 2 + 1;
width = max(2 * (hole_pitch + corner_radius), fan_bore(type) + 2 * wall);
hole = fan_bore(type) / 2;
rings = ceil(hole / (wall + finger_width)) - 1;
inner_ring = hole - rings * (wall + finger_width);
union() {
difference() {
rounded_rectangle([width, width, thickness], r = width / 2 - hole_pitch, center = false);
fan_holes(type, true);
}
for(i = [1 : rings])
difference() {
cylinder(r = hole - i * (wall + finger_width) + wall / 2, h = thickness);
cylinder(r = hole - i * (wall + finger_width) - wall / 2, h = 2 * thickness + 1, center = true);
}
for(i = [0 : spokes - 1])
rotate([0, 0, i * 360 / spokes + 180 / spokes - 90])
translate([inner_ring, -wall / 2, 0])
cube([hole - inner_ring + eta, wall, thickness]);
}
}
module fan_guard_stl() fan_guard(case_fan);
fan_guard(fan80x38);
//fan_guard(fan60x25);

103
scad/fixing-block.scad Normal file
View File

@ -0,0 +1,103 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Brackets to fasten the frame together
//
include <conf/config.scad>
slot = 2;
thickness = 5;
thin_wall = filament_width * 2 + eta;
wall = 3;
counter_bore_rad = washer_diameter(screw_washer(base_screw)) / 2 + 0.2;
width = 2 * wall + 2 * thin_wall + 6 * counter_bore_rad;
shear = min(counter_bore_rad - screw_clearance_radius(frame_screw), 2.5);
hole_pitch = 2 * (2 * counter_bore_rad + thin_wall);
depth = 2 * (thickness + counter_bore_rad) + slot - 2 * shear;
height = depth;
hole_offset = depth / 2;
corner_rad = 3;
counter_bore_depth = depth - thickness;
function fixing_block_width() = width;
function fixing_block_height() = height;
module fixing_block_v_hole(h)
translate([0, hole_offset, h])
child();
module fixing_block_h_holes(h)
for(end = [-1, 1])
translate([end * hole_pitch / 2, h, hole_offset])
rotate([90, 0, 180])
child();
module fixing_block_stl() {
stl("fixing_block");
difference() {
translate([-(width - 2 * corner_rad) / 2, 0, 0])
minkowski() {
cube([width - 2 * corner_rad, depth- corner_rad, height -corner_rad]);
intersection() {
sphere(r = corner_rad);
translate([0, 5, 5])
cube([10, 10, 10], center = true);
}
}
translate([-width / 2 - 1, thickness, height + eta]) // diagonal slice of the front
rotate([-45, 0, 0])
cube([width + 2, depth * 2, height]);
fixing_block_v_hole(height - counter_bore_depth)
rotate([0,0,90])
union() {
slot(h = 100, r = screw_clearance_radius(frame_screw), l = slot, center = true);
multmatrix(m = [ [1, 0, shear / counter_bore_depth, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1] ])
slot(h = 100, r = counter_bore_rad, l = slot, center = false);
}
fixing_block_h_holes(depth - counter_bore_depth)
rotate([0,0,0])
union() {
vertical_tearslot(h = 100, r = screw_clearance_radius(frame_screw), l = slot, center = true);
multmatrix(m = [ [1, 0, 0, 0],
[0, 1, shear / counter_bore_depth, 0],
[0, 0, 1, 0],
[0, 0, 0, 1] ])
vertical_tearslot(h = 100, r = counter_bore_rad, l = slot, center = false);
}
}
}
module fixing_block_assembly(front = false) {
color([0,1,0]) render() fixing_block_stl();
fixing_block_v_hole(height - counter_bore_depth)
if(front)
frame_screw(thickness);
else
base_screw();
fixing_block_h_holes(depth - counter_bore_depth)
frame_screw(thickness);
}
if(0) {
fixing_block_stl();
}
else
fixing_block_assembly();

738
scad/main.scad Normal file
View File

@ -0,0 +1,738 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// main assembly
//
include <conf/config.scad>
use <bed.scad>
use <z-screw_pointer.scad>
use <bar-clamp.scad>
use <pulley.scad>
use <y-bearing-mount.scad>
use <y-idler-bracket.scad>
use <y-belt-anchor.scad>
use <z-coupling.scad>
use <z-motor-bracket.scad>
use <z-limit-switch-bracket.scad>
use <fixing-block.scad>
use <ribbon_clamp.scad>
use <fan-guard.scad>
use <wade.scad>
use <cable_clip.scad>
use <pcb_spacer.scad>
include <positions.scad>
X = 0 * X_travel / 2; //sin(360 * $t) * bed_width / 2;
Y = 0 * Y_travel / 2; //cos(360 * $t) * bed_depth / 2;
Z = 0 * Z_travel;
//
// X axis
//
X_bar_length = motor_end - idler_end + 2 * x_end_bar_length();
module x_axis_assembly(show_extruder) {
X_belt_gap = x_carriage_belt_gap() - 10;
assembly("x_axis_assembly");
for(side = [-1,1])
translate([(idler_end + motor_end) / 2 + eta, side * x_bar_spacing() / 2, Z + Z0])
rotate([0,90,0])
rod(X_bar_dia, X_bar_length);
translate([-X + X_origin, 0, Z + Z0 + x_carriage_offset()])
rotate([180, 0, 180])
x_carriage_assembly(show_extruder);
translate([0, -gantry_setback - belt_width(X_belt) / 2, Z + Z0])
rotate([90, 0, 0]) render()
union() {
difference() {
twisted_belt(X_belt, idler_end + x_idler_offset(), 0, ball_bearing_diameter(X_idler_bearing) / 2,
motor_end - x_motor_offset(), 0, pulley_inner_radius, X_belt_gap - x_belt_loop_length());
translate([-X + X_origin - nozzle_x_offset + (x_carriage_belt_gap() - X_belt_gap + 5) / 2,
pulley_inner_radius + belt_thickness(X_belt)/2, 0])
cube([X_belt_gap + 5, belt_thickness(X_belt) * 3, belt_width(X_belt) * 2], center = true);
}
}
elliptical_cable_strip(ribbon_clamp_slot(extruder_ways) - 1,
[motor_end, 0, Z + Z0] + x_end_extruder_ribbon_clamp_offset(),
[-X + X_origin, 0, Z + Z0 + x_carriage_offset()] + extruder_connector_offset(),
[-X_travel / 2 + X_origin, 0, Z + Z0 + x_carriage_offset()] + extruder_connector_offset());
end("x_axis_assembly");
}
//
// Z axis
//
Z_motor_length = NEMA_length(Z_motor);
Z_bar_length = height - Z_motor_length - base_clearance;
module z_end(motor_end) {
Z_screw_length = Z0 + Z_travel + anti_backlash_height() + axis_endstop_clearance
- (Z_motor_length + NEMA_shaft_length(Z_motor) + 2);
if(!motor_end)
translate([-z_bar_offset(), gantry_setback, Z0 - x_end_thickness() / 2])
z_limit_switch_assembly();
translate([-z_bar_offset(), 0, Z_motor_length]) {
z_motor_assembly(gantry_setback, motor_end);
translate([0, 0, NEMA_shaft_length(Z_motor) + 2 + Z_screw_length / 2]) {
studding(d = Z_screw_dia, l = Z_screw_length);
translate([0, 0, -Z_screw_length / 2 + z_coupling_length() / 2 - 1])
render() z_screw_pointer_stl();
}
translate([z_bar_offset(), 0, Z_bar_length / 2])
rod(Z_bar_dia, Z_bar_length);
translate([z_bar_offset(), gantry_setback, Z_bar_length - bar_clamp_depth / 2]) {
rotate([90,motor_end ? 90 : - 90, 0])
z_bar_clamp_assembly(Z_bar_dia, gantry_setback, bar_clamp_depth, !motor_end);
}
}
translate([0, 0, Z + Z0])
x_end_assembly(motor_end, true);
}
module z_axis_assembly() {
assembly("z_axis_assembly");
translate([motor_end, 0, 0])
mirror([1,0,0])
z_end(true);
translate([idler_end, 0, 0])
z_end(false);
end("z_axis_assembly");
}
//
// Y axis
//
Y_bar_length = Y_travel + Y_carriage_depth + 2 * axis_endstop_clearance;
Y_bar_length2 = Y_travel + bearing_mount_length(Y_bearings) + 2 * bar_clamp_depth + axis_endstop_clearance + bar_clamp_switch_y_offset();
Y_bar_spacing = Y_carriage_width - bearing_mount_width(Y_bearings);
Y_bearing_inset = bearing_mount_length(Y_bearings) / 2 + bar_clamp_depth;
Y_belt_motor_offset = 13 + belt_width(Y_belt) / 2;
//Y_belt_line = min(X_origin,
// X_origin + Y_bar_spacing / 2
// - max(bar_rail_offset(Y_bar_dia), bearing_mount_width(Y_bearings) /2)
// - NEMA_length(Y_motor) - Y_belt_motor_offset - X_carriage_clearance);
Y_belt_line = X_origin - ribbon_clamp_slot(bed_ways) / 2 - y_belt_anchor_width() / 2 - 5;
Y_motor_end = -base_depth / 2 + y_motor_bracket_width() / 2 + base_clearance;
Y_idler_end = base_depth / 2 - y_idler_offset() - base_clearance;
Y_belt_anchor_m = Y_motor_end + NEMA_width(Y_motor) / 2 + Y_travel / 2;
Y_belt_anchor_i = Y_idler_end - y_idler_clearance() - Y_travel / 2;
Y_belt_end = 20;
Y_belt_gap = Y_belt_anchor_i - Y_belt_anchor_m - 2 * Y_belt_end;
//
// supported bar
//
module rail(length, height, endstop) {
translate([0, 0, height])
rotate([90,0,0])
rod(Y_bar_dia, length);
for(end = [-1, 1])
translate([0, end * (length / 2 - bar_clamp_depth / 2), 0])
rotate([0, 0, 90])
y_bar_clamp_assembly(Y_bar_dia, height, bar_clamp_depth, endstop && end == 1);
}
module y_rails() {
offset = bar_clamp_switch_y_offset() - axis_endstop_clearance;
translate([-Y_bar_spacing / 2, 0, 0])
rail(Y_bar_length, Y_bar_height);
rotate([0,0,180])
translate([-Y_bar_spacing / 2, offset / 2, 0])
rail(Y_bar_length2, Y_bar_height, true);
}
module rail_holes(length) {
for(end = [-1, 1])
translate([0, end * (length / 2 - bar_clamp_depth / 2), 0])
rotate([0, 0, 90])
bar_clamp_holes(Y_bar_dia)
base_screw_hole();
}
module y_rail_holes() {
offset = bar_clamp_switch_y_offset() - axis_endstop_clearance;
translate([-Y_bar_spacing / 2, 0, 0])
rail_holes(Y_bar_length);
rotate([0,0,180])
translate([-Y_bar_spacing / 2, offset / 2, 0])
rail_holes(Y_bar_length2);
}
cable_clamp_y = Y_carriage_depth / 2 - ribbon_clamp_width(cap_screw);
module y_carriage() {
difference() {
sheet(Y_carriage, Y_carriage_width, Y_carriage_depth, [3,3,3,3]);
translate([0, cable_clamp_y, 0])
rotate([180, 0, 0])
ribbon_clamp_holes(bed_ways, cap_screw)
cylinder(r = screw_clearance_radius(cap_screw), h = 100, center = true);
translate([Y_bar_spacing / 2, 0, 0])
rotate([0,180,0])
bearing_mount_holes();
for(end = [-1, 1])
translate([-Y_bar_spacing / 2, end * (Y_carriage_depth / 2 - Y_bearing_inset), 0])
rotate([0,180,0])
bearing_mount_holes();
for(end = [[Y_belt_anchor_m, 0], [Y_belt_anchor_i, 180]])
translate([Y_belt_line - X_origin, end[0], 0])
rotate([0, 180, end[1]])
y_belt_anchor_holes();
for(x = [-bed_holes / 2, bed_holes / 2])
for(y = [-bed_holes / 2, bed_holes / 2])
translate([x, y, 0])
cylinder(r = 2.5/2, h = 100, center = true);
}
}
module y_axis_assembly(show_bed) {
carriage_bottom = Y_carriage_height - sheet_thickness(Y_carriage) / 2;
carriage_top = Y_carriage_height + sheet_thickness(Y_carriage) / 2;
translate([X_origin, 0, 0]) {
assembly("y_axis_assembly");
y_rails();
translate([Y_belt_line - X_origin, Y_motor_end, y_motor_height()]) rotate([90,0,-90]) {
render() difference() {
twisted_belt(Y_belt,
Y_motor_end - Y_idler_end,
pulley_inner_radius - ball_bearing_diameter(Y_idler_bearing) / 2,
ball_bearing_diameter(Y_idler_bearing) / 2,
0, 0, pulley_inner_radius, Y_belt_gap);
translate([-(Y_belt_anchor_i + Y_belt_anchor_m) / 2 + Y_motor_end - Y, pulley_inner_radius + belt_thickness(Y_belt)/2, 0])
cube([Y_belt_gap, belt_thickness(Y_belt) * 2, belt_width(Y_belt) * 2], center = true);
}
translate([0, 0, -Y_belt_motor_offset])
y_motor_assembly();
}
translate([Y_belt_line - X_origin, Y_idler_end, 0])
y_idler_assembly();
end("y_axis_assembly");
//
// Y carriage
//
translate([0, Y, 0]) {
assembly("y_carriage_assembly");
translate([Y_bar_spacing / 2, 0, Y_bar_height])
rotate([0,180,0])
y_bearing_assembly(Y_bearing_holder_height, true);
for(end = [-1, 1])
translate([-Y_bar_spacing / 2, end * (Y_carriage_depth / 2 - Y_bearing_inset), Y_bar_height])
rotate([0,180,0])
y_bearing_assembly(Y_bearing_holder_height);
for(end = [[Y_belt_anchor_m, 0, false], [Y_belt_anchor_i, 180, true]])
translate([Y_belt_line - X_origin, end[0], carriage_bottom])
rotate([0, 180, end[1]])
y_belt_anchor_assembly(Y_belt_clamp_height, end[2]);
translate([0, cable_clamp_y, carriage_top])
rotate([180, 0, 0])
color([1,0,0]) render() ribbon_clamp(bed_ways, cap_screw);
translate([0, cable_clamp_y, carriage_bottom])
rotate([180, 0, 0])
ribbon_clamp_assembly(bed_ways, cap_screw, 25, sheet_thickness(Y_carriage) + ribbon_clamp_thickness(), false, true);
if(show_bed)
translate([0, 0, Y_carriage_height + sheet_thickness(Y_carriage) / 2])
bed_assembly();
translate([0, 0, Y_carriage_height + eta * 2])
if(show_bed)
y_carriage();
else
%y_carriage();
end("y_carriage_assembly");
}
}
}
module y_axis_screw_holes() {
translate([X_origin, 0, 0]) {
y_rail_holes();
translate([Y_belt_line - X_origin, Y_idler_end, 0])
y_idler_screw_hole()
base_screw_hole();
translate([Y_belt_line - X_origin, Y_motor_end, y_motor_height()])
rotate([90,0,-90])
translate([0, 0, -Y_belt_motor_offset])
y_motor_bracket_holes()
base_screw_hole();
}
}
//
// List of cable clips
//
left_stay_x = max(-base_width / 2 + left_w / 2,
idler_end - z_bar_offset() + z_motor_bracket_hole_offset() + washer_diameter(M4_washer) / 2 + 1) + sheet_thickness(frame) / 2;
right_stay_x = max(base_width / 2 - right_w / 2,
motor_end + z_bar_offset() + z_motor_bracket_hole_offset() + washer_diameter(M4_washer) / 2 + 1) + sheet_thickness(frame) / 2 ;
z_gantry_wire_height = height - base_clearance - fixing_block_width() -fixing_block_height() -
base_clearance - cable_clip_extent(base_clip_screw, endstop_wires);
cable_clips = [ // cable1, cable2 , position, vertical, rotation
// near to the Y limit switch
[endstop_wires, motor_wires,
[base_width / 2 - right_w - cable_clip_extent(base_clip_screw, motor_wires), -Y_bar_length2 / 2 + 20, 0], false, 0],
// at the foot of the gantry
[endstop_wires, motor_wires,
[base_width / 2 - right_w - cable_clip_extent(base_clip_screw, motor_wires), gantry_setback + 20, 0], false, 0],
// bed wires
[bed_wires, thermistor_wires,
[20, base_depth / 2 -2 * base_clearance - fixing_block_width() - cable_clip_extent(base_clip_screw, bed_wires), 0], false, -90],
// Z axis left
[endstop_wires, fan_motor_wires,
[left_stay_x + 15, gantry_setback + sheet_thickness(frame), z_gantry_wire_height], true, 90],
// Z axis right
[endstop_wires, fan_motor_wires,
[right_stay_x - 15, gantry_setback + sheet_thickness(frame), z_gantry_wire_height], true, 90],
];
module place_cable_clips(holes = false) {
for(clip = cable_clips) {
translate(clip[2])
rotate([clip[3] ? -90 : 0, 0, 0]) rotate([0, 0, clip[4]])
if(holes)
cylinder(r = clip[3] ? (frame_nuts ? screw_clearance_radius(frame_clip_screw) : screw_pilot_hole(frame_clip_screw)) :
screw_pilot_hole(base_clip_screw), h = 100, center = true);
else
if(clip[3])
cable_clip_assembly(frame_clip_screw, frame_clip_screw_length, clip[0], clip[1]);
else
cable_clip_assembly(base_clip_screw, base_clip_screw_length, clip[0], clip[1]);
}
}
//
// Frame
//
module fixing_blocks(upper = false) {
w = fixing_block_width();
h = fixing_block_height();
t = sheet_thickness(frame);
if(upper) { // all screws into frame
translate([left_stay_x + t / 2, gantry_setback + t, stay_height - base_clearance - h - w / 2]) // top
rotate([0,-90,-90])
child();
translate([right_stay_x - t / 2, gantry_setback + t, stay_height - base_clearance - h - w / 2]) // top
rotate([0,90, 90])
child();
translate([left_stay_x + t / 2, gantry_setback + t, base_clearance + h + w / 2]) // front
rotate([0,-90,-90])
child();
translate([right_stay_x - t / 2, gantry_setback + t, base_clearance + h + w / 2]) // front
rotate([0,90, 90])
child();
}
else { // one screw in the base
for(x = [-base_width/2 + base_clearance + w /2,
base_width/2 - base_clearance - w /2,
-base_width/2 - base_clearance - w /2 + left_w,
base_width/2 + base_clearance + w /2 - right_w])
translate([x, gantry_setback + t, 0])
child();
translate([left_stay_x + t / 2, gantry_setback + t + stay_depth - base_clearance - w / 2, 0]) // back
rotate([0, 0,-90])
child();
translate([right_stay_x - t / 2, gantry_setback + t + stay_depth - base_clearance - w / 2, 0]) // back
rotate([0,0, 90])
child();
}
}
module fixing_block_holes() {
fixing_blocks()
group() {
fixing_block_v_hole(0)
base_screw_hole();
fixing_block_h_holes(0)
frame_screw_hole();
}
fixing_blocks(true)
group() {
fixing_block_v_hole(0)
frame_screw_hole();
fixing_block_h_holes(0)
frame_screw_hole();
}
}
module frame_base() {
difference() {
translate([0,0, -sheet_thickness(base) / 2])
sheet(base, base_width, base_depth, [base_corners, base_corners, base_corners, base_corners]); // base
fixing_block_holes();
y_axis_screw_holes();
translate([motor_end + z_bar_offset(), 0, 0]) // in case motor has second shaft
cylinder(r = 4, h = 100, center = true);
translate([idler_end - z_bar_offset(), 0, 0])
cylinder(r = 4, h = 100, center = true);
translate([X_origin, cable_clamp_y,0])
ribbon_clamp_holes(bed_ways, base_screw)
base_screw_hole();
place_cable_clips(true);
}
}
module frame_gantry() {
difference() {
translate([0, gantry_setback + sheet_thickness(frame) / 2, height / 2])
rotate([90,0,0])
if(single_piece_frame)
difference() {
sheet(frame, base_width, height, [frame_corners, frame_corners, 0, 0]); // vertical plane
translate([X_origin, -gantry_thickness, 0])
rounded_rectangle([window_width, height, sheet_thickness(frame) + 1], r = 5, center = true);
}
else {
translate([-base_width / 2 + left_w / 2, 0, 0])
sheet(frame, left_w, height, [frame_corners, 0, 0, 0]); // left side
translate([ base_width / 2 - right_w / 2, 0, 0])
sheet(frame, right_w, height, [0, frame_corners, 0, 0]); // right side
translate([0, height / 2 - gantry_thickness / 2, -sheet_thickness(frame)])
sheet(frame, base_width, gantry_thickness, [frame_corners, frame_corners, 0, 0]); // top
}
fixing_block_holes();
//
// Z bar clamps
//
for(end = [idler_end, motor_end])
translate([end, gantry_setback, height - base_clearance - bar_clamp_depth / 2])
rotate([0, 90, 90])
bar_clamp_holes(Z_bar_dia)
frame_screw_hole();
//
// Z motor bracket holes
//
for(side = [idler_end - z_bar_offset(), motor_end + z_bar_offset()])
translate([side, 0, Z_motor_length])
z_motor_bracket_holes(gantry_setback)
frame_screw_hole();
//
// Z limit switch holes
//
translate([idler_end -z_bar_offset(), gantry_setback, Z0 - x_end_thickness() / 2])
z_limit_screw_positions()
frame_screw_hole();
//
// X ribbon clamp
//
translate([motor_end - x_motor_offset(), gantry_setback, height - base_clearance - ribbon_clamp_width(frame_screw)])
ribbon_clamp_holes(x_end_ways, frame_screw)
rotate([90, 0, 0])
frame_screw_hole();
//
// Wiring holes
//
translate([idler_end - bar_rail_offset(Z_bar_dia) + 0.5 * bar_clamp_tab,
gantry_setback, height - base_clearance - bar_clamp_depth - endstop_wires_hole_radius - base_clearance])
rotate([90, 0, 0])
wire_hole(endstop_wires_hole_radius); // Z top endstop
translate([-base_width / 2 + base_clearance + fixing_block_width() + base_clearance + motor_wires_hole_radius,
gantry_setback, motor_wires_hole_radius + hole_edge_clearance])
rotate([90, 0, 0])
wire_hole(motor_wires_hole_radius); // Z lhs motor
translate([max(motor_end + bar_rail_offset(Z_bar_dia),
base_width / 2 - right_w + fixing_block_width() + 2 * base_clearance + motor_wires_hole_radius),
gantry_setback, motor_wires_hole_radius + hole_edge_clearance])
rotate([90, 0, 0])
wire_hole(motor_wires_hole_radius); // Z rhs motor
translate([idler_end - bar_rail_offset(Z_bar_dia),
gantry_setback, Z_motor_length + z_motor_bracket_height() + endstop_wires_hole_radius])
rotate([90, 0, 0])
wire_hole(endstop_wires_hole_radius); // bottom limit switch
place_cable_clips(true);
}
}
fan_y = gantry_setback + sheet_thickness(frame) + fixing_block_height() + fan_width(case_fan) / 2 + base_clearance;
fan_z = Y_carriage_height + fan_width(case_fan) / 2;
sanguinololu_z = 10;
sanguinololu_y = base_depth / 2 - 50 - sanguinololu_width(); // inset by 50 to leave room for USB plug
psu_z = height - psu_length(psu) / 2 - base_clearance;
psu_y = gantry_setback + sheet_thickness(frame) + fixing_block_height() + psu_width(psu) / 2;
module frame_stay(left, bodge = 0) {
x = left ? left_stay_x : right_stay_x;
difference() {
translate([x, gantry_setback + sheet_thickness(frame) + stay_depth / 2, stay_height / 2])
rotate([90,0,90])
sheet(frame, stay_depth, stay_height, [0, frame_corners, 0, 0]);
fixing_block_holes();
if(left)
translate([x + (sheet_thickness(frame) + fan_depth(case_fan)) / 2, fan_y, fan_z])
rotate([0,90,0])
scale([1 + bodge, 1 + bodge, 1]) fan_holes(case_fan); // scale prevents OpenCSG z buffer artifacts
else {
//
// Electronics mounting holes
//
translate([x, sanguinololu_y, sanguinololu_z])
rotate([90, 0, 90])
sanguinololu_screw_positions()
cylinder(r = M3_tap_radius, h = 100, center = true);
translate([x, psu_y, psu_z])
rotate([0, -90, 180])
psu_screw_positions(psu)
cylinder(r = M3_clearance_radius, h = 100, center = true);
//
// Wiring holes
//
translate([x, gantry_setback + sheet_thickness(frame) + fixing_block_height() + motor_wires_hole_radius,
hole_edge_clearance + motor_wires_hole_radius]) {
rotate([0, 90, 0])
wire_hole(motor_wires_hole_radius); // Z rhs motor at bottom
translate([0, motor_wires_hole_radius + hole_edge_clearance + motor_wires_hole_radius, 0]) {
rotate([0, 90, 0])
wire_hole(motor_wires_hole_radius); // Y motor wires at bottom
translate([0, motor_wires_hole_radius + hole_edge_clearance + endstop_wires_hole_radius,
endstop_wires_hole_radius - motor_wires_hole_radius])
rotate([0, 90, 0])
wire_hole(endstop_wires_hole_radius); // Y endstop wires at bottom
}
}
translate([x, gantry_setback + sheet_thickness(frame) + stay_depth - 2 * base_clearance - fixing_block_width() - bed_wires_hole_radius,
hole_edge_clearance + bed_wires_hole_radius]) {
rotate([0, 90, 0])
wire_hole(bed_wires_hole_radius); // Bed wires at bottom
translate([0, -bed_wires_hole_radius - hole_edge_clearance - thermistor_wires_hole_radius,
thermistor_wires_hole_radius - bed_wires_hole_radius])
rotate([0, 90, 0])
wire_hole(thermistor_wires_hole_radius); // Bed thermistor wires
}
}
translate([x, gantry_setback + sheet_thickness(frame) + endstop_wires_hole_radius + hole_edge_clearance, z_gantry_wire_height]) {
translate([0, 0, cable_clip_offset(frame_clip_screw, endstop_wires)])
rotate([0, 90, 0])
wire_hole(endstop_wires_hole_radius); // Z endstop wires
translate([0, fan_motor_wires_hole_radius - endstop_wires_hole_radius,
-cable_clip_offset(frame_clip_screw, fan_motor_wires)])
rotate([0, 90, 0])
wire_hole(fan_motor_wires_hole_radius); // Z motor wires
}
}
}
module bed_fan_assembly() {
assembly("bed_fan_assembly");
translate([left_stay_x, fan_y, fan_z])
rotate([0, -90, 0]) {
translate([0, 0, -(sheet_thickness(frame) + fan_depth(case_fan)) / 2])
fan_assembly(case_fan, sheet_thickness(frame) + fan_guard_thickness());
translate([0, 0, sheet_thickness(frame) / 2])
color([0,1,0]) render() fan_guard(case_fan);
}
end("bed_fan_assembly");
}
module electronics_assembly() {
thickness = sheet_thickness(frame) + washer_thickness(M3_washer) * 2;
psu_screw = screw_longer_than(thickness + 2);
if(psu_screw > thickness + 5)
echo("psu_screw too long");
assembly("electronics_assembly");
translate([right_stay_x + sheet_thickness(frame) / 2, sanguinololu_y, sanguinololu_z])
rotate([90, 0, 90]) {
sanguinololu_screw_positions()
pcb_spacer_assembly();
translate([0, 0, pcb_spacer_height()])
sanguinololu();
}
translate([right_stay_x + sheet_thickness(frame) / 2, psu_y, psu_z])
rotate([0, -90, 180]) {
psu_screw_positions(psu) group() {
translate([0, 0, -sheet_thickness(frame)])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, psu_screw, true);
}
psu(psu);
}
end("electronics_assembly");
}
module frame_assembly(show_gantry = true) {
assembly("frame_assembly");
ribbon_clamp_z = height - base_clearance - ribbon_clamp_width(frame_screw);
translate([motor_end - x_motor_offset(), gantry_setback, ribbon_clamp_z])
rotate([90, 0, 0]) {
if(frame_nuts)
ribbon_clamp_assembly(x_end_ways, frame_screw, frame_screw_length, sheet_thickness(frame), false, true);
else
ribbon_clamp_assembly(x_end_ways, frame_screw, frame_screw_length);
translate([0, ribbon_clamp_width(frame_screw) / 2, 0])
rotate([90, 0, 90])
cable_strip(ribbon_clamp_slot(x_end_ways) - 1, gantry_setback - x_end_ribbon_clamp_y(),
(Z_travel + (ribbon_clamp_z - (Z_travel + Z0 + x_end_ribbon_clamp_z()))) * 2,
Z + Z0 + x_end_ribbon_clamp_z() - ribbon_clamp_z, 50);
}
translate([X_origin, cable_clamp_y,0]) {
ribbon_clamp_assembly(bed_ways, base_screw, base_screw_length);
translate([0, ribbon_clamp_width(base_screw), 0])
rotate([90, 0, 90])
cable_strip(ribbon_clamp_slot(bed_ways) - 1, Y_carriage_height - sheet_thickness(Y_carriage) / 2, Y_travel, Y);
}
place_cable_clips();
frame_base();
if(show_gantry) {
fixing_blocks()
fixing_block_assembly();
fixing_blocks(true)
fixing_block_assembly(true);
frame_stay(true, eta);
frame_stay(false);
frame_gantry();
}
end("frame_assembly");
}
module machine_assembly() {
assembly("machine_assembly");
show_bed = true;
translate([0,0, sheet_thickness(base)]) {
bed_fan_assembly();
electronics_assembly();
x_axis_assembly(true);
z_axis_assembly();
y_axis_assembly(show_bed);
//
// Draw the possibly transparent bits last
//
frame_assembly(true);
}
end("machine_assembly");
}
machine_assembly();
//frame_assembly();
module frame_base_dxf() projection(cut = true) translate([0,0, sheet_thickness(base) / 2]) frame_base();
module frame_left_dxf() projection(cut = true) translate([0, -gantry_setback - sheet_thickness(frame), left_stay_x]) rotate([0, 90, 0]) frame_stay(true);
module frame_right_dxf() projection(cut = true) translate([0, -gantry_setback - sheet_thickness(frame), right_stay_x]) rotate([0, 90, 0]) frame_stay(false);;
module frame_gantry_and_y_carriage_dxf() projection(cut = true) {
translate([0,0, gantry_setback + sheet_thickness(frame) / 2]) rotate([-90, 0, 0]) frame_gantry();
translate([X_origin, height - gantry_thickness - Y_carriage_depth / 2 -1, 0]) y_carriage();
}
module frame_gantry_dxf() projection(cut = true)
translate([0,0, gantry_setback + sheet_thickness(frame) / 2]) rotate([-90, 0, 0]) frame_gantry();
module y_carriage_dxf() projection(cut = true) y_carriage();
echo("Width: ", base_width, " Depth: ", base_depth, " Height: ", height + sheet_thickness(base));
echo(left_w, window_width, right_w);
echo("X bar: ", X_bar_length, " Y Bar 1: ", Y_bar_length, " Y Bar 2: ", Y_bar_length2, " Z Bar: ", Z_bar_length);

41
scad/pcb_spacer.scad Normal file
View File

@ -0,0 +1,41 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
include <conf/config.scad>
pcb_screw_length = frame_nuts ?
screw_longer_than(2 * washer_thickness(M3_washer) + pcb_thickness + sheet_thickness(frame) + nut_thickness(M3_nut, true)) : 16;
function pcb_spacer_height() = frame_nuts ? 3 : max(3, 16 - 2 * washer_thickness(M3_washer) - pcb_thickness - sheet_thickness(frame));
module pcb_spacer_stl(screw = M3_cap_screw, h = pcb_spacer_height()) {
stl("pcb_spacer");
r = screw_clearance_radius(screw);
difference() {
cylinder(r = corrected_diameter(r * 2) / 2 + 2, h = h, center = false);
translate([0, 0, -0.5])
poly_cylinder(r = r, h = h + 1, center = false);
}
}
module pcb_spacer_assembly() {
color([0,1,0]) render() pcb_spacer_stl();
translate([0,0, pcb_spacer_height() + pcb_thickness])
screw_and_washer(M3_cap_screw, pcb_screw_length, !frame_nuts);
if(frame_nuts)
translate([0, 0, -sheet_thickness(frame)])
rotate([180, 0, 0])
nut_and_washer(screw_nut(M3_cap_screw), true);
}
if(0)
pcb_spacer_stl();
else
pcb_spacer_assembly();

48
scad/positions.scad Normal file
View File

@ -0,0 +1,48 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Work out the positions and size of things
//
use <y-motor-bracket.scad>
use <x-carriage.scad>
use <x-end.scad>
Y_carriage_height = y_motor_bracket_height() + X_carriage_clearance + sheet_thickness(Y_carriage) / 2;
bed_height = Y_carriage_height + sheet_thickness(Y_carriage) / 2 + pillar_height(bed_pillars) + washer_thickness(M3_washer) + bed_thickness;
Z0 = floor(bed_height + nozzle_length - x_carriage_offset());
height = Z0 + Z_travel + x_end_height() + bar_clamp_depth + axis_endstop_clearance + base_clearance;
gantry_thickness = height - max(bed_height + Z_travel + Z_clearance, Y_carriage_depth + 1);
gantry_setback = X_carriage_clearance + x_carriage_width() / 2;
Z_bar_spacing = X_travel + x_carriage_length() + 2 * (axis_endstop_clearance + Z_bearings[1] / 2);
base_width = base_clearance - x_idler_overhang() + Z_bar_spacing -x_motor_overhang() + base_clearance;
base_depth = Y_travel + Y_carriage_depth + 2 * base_clearance + 2 * axis_endstop_clearance;
window_width = ceil(Y_carriage_width + Y_carriage_clearance * 2);
stay_depth = stays_from_window ? window_width / 2 : base_depth / 2 - (gantry_setback + sheet_thickness(frame));
stay_height = single_piece_frame && !stays_from_window ? height : height - gantry_thickness - 1;
idler_end = -base_width / 2 + base_clearance - x_idler_overhang();
motor_end = base_width / 2 - base_clearance + x_motor_overhang();
X_origin = (idler_end + motor_end) / 2 + nozzle_x_offset;
left_w = ceil((base_width - window_width)/2 + X_origin);
right_w = ceil((base_width - window_width)/2 - X_origin);
Y_belt_height = y_motor_height() + pulley_inner_radius + belt_thickness(Y_belt);
Y_bar_height = Y_belt_height;
Y_belt_clamp_height = Y_carriage_height - Y_belt_height - sheet_thickness(Y_carriage) / 2;
Y_bearing_holder_height = Y_carriage_height - Y_bar_height - sheet_thickness(Y_carriage) / 2;

31
scad/pulley.scad Normal file
View File

@ -0,0 +1,31 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
include <conf/config.scad>
module pulley_stl() {
stl("pulley");
color([1,0,0])
translate([-10, -10, 0])
import("../imported_stls/pulley.stl");
}
module pulley_assembly() {
color([1,0,0]) render() pulley_stl();
rotate([90, 0, 0]) {
translate([0, 4, -5/2 - 6])
screw(M3_grub_screw, 6);
translate([0, 4, -6])
rotate([0,0,30])
nut(M3_nut);
}
}
if(1)
pulley_assembly();
else
pulley_stl();

91
scad/ribbon_clamp.scad Normal file
View File

@ -0,0 +1,91 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Clamps for ribbon cable plus cable_strip
//
include <conf/config.scad>
thickness = 5;
slot_depth = 1.3;
min_gap = 1.5;
function ribbon_clamp_slot(ways) = ways * 0.05 * 25.4 + 2;
function ribbon_clamp_pitch(ways, screw_type) = ribbon_clamp_slot(ways) + 2 * (screw_clearance_radius(screw_type) + min_gap);
function ribbon_clamp_width(screw_type) = washer_diameter(screw_washer(screw_type)) + 2;
function ribbon_clamp_length(ways, screw_type) = ribbon_clamp_pitch(ways, screw_type) + ribbon_clamp_width(screw_type);
function ribbon_clamp_thickness() = thickness;
module ribbon_clamp_holes(ways, screw_type) {
pitch = ribbon_clamp_pitch(ways, screw_type);
for(end = [-1, 1])
translate([end * pitch / 2, 0, 0])
child();
}
module ribbon_clamp(ways, screw_type) {
hole_rad = screw_clearance_radius(screw_type);
stl(str("ribbon_clamp_",ways,"_", 20 * hole_rad));
rad = ribbon_clamp_width(screw_type) / 2;
slot = ribbon_clamp_slot(ways);
pitch = ribbon_clamp_pitch(ways, screw_type);
translate([0,0, -thickness / 2]) difference() {
//
// body
//
slot(r = rad, l = pitch, h = thickness, center = true);
//
// screw holes
//
ribbon_clamp_holes(ways, screw_type)
poly_cylinder(r = hole_rad, h = thickness + 1, center = true);
//
// Slot
//
translate([0, 0,thickness - slot_depth])
cube([slot, 2 * rad + 1,thickness], center = true);
}
}
module ribbon_clamp_assembly(ways, screw_type, screw_length, panel_thickness = 0, vertical = false, washer = false) {
color([1,0,0])
render() rotate([180, 0, 0])
ribbon_clamp(ways, screw_type);
translate([0,0, thickness])
ribbon_clamp_holes(ways, screw_type)
screw_and_washer(screw_type, screw_length);
if(panel_thickness != 0)
translate([0,0, - panel_thickness])
ribbon_clamp_holes(ways, screw_type)
rotate([180, 0, vertical ? 90 : 0])
if(washer)
nut_and_washer(screw_nut(screw_type), true);
else
nut(screw_nut(screw_type), true);
}
module ribbon_clamp_12_33_stl() translate([0,0,thickness]) ribbon_clamp(12, M3_cap_screw);
module ribbon_clamp_20_33_stl() translate([0,0,thickness]) ribbon_clamp(20, M3_cap_screw);
module ribbon_clamp_20_40_stl() translate([0,0,thickness]) ribbon_clamp(20, No6_screw);
module ribbon_clamp_20_44_stl() translate([0,0,thickness]) ribbon_clamp(20, M4_cap_screw);
module ribbon_clamp_22_33_stl() translate([0,0,thickness]) ribbon_clamp(22, M3_cap_screw);
module ribbon_clamp_22_40_stl() translate([0,0,thickness]) ribbon_clamp(22, No6_screw);
module ribbon_clamp_22_44_stl() translate([0,0,thickness]) ribbon_clamp(22, M4_cap_screw);
if(1)
ribbon_clamp_assembly(20, M4_cap_screw, 20, 4);
else {
translate([0,-12,0]) ribbon_clamp(bed_ways, cap_screw);
translate([0,0,0]) ribbon_clamp(bed_ways, cap_screw);
translate([0,12,0]) ribbon_clamp(bed_ways, base_screw);
translate([0,25,0]) ribbon_clamp(x_end_ways, frame_screw);
translate([0,37,0]) ribbon_clamp(x_end_ways, M3_cap_screw);
translate([0,48,0]) ribbon_clamp(extruder_ways, M3_cap_screw);
translate([0,59,0]) ribbon_clamp(extruder_ways, M3_cap_screw);
}

28
scad/utils/bom.scad Normal file
View File

@ -0,0 +1,28 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// BOM generation
//
module assembly(name) { // start an assembly
if(bom > 0)
echo(str(name, "/"));
}
module end(name) { // end an assembly
if(bom > 0)
echo(str("/",name));
}
module stl(name) { // name an stl
if(bom > 0)
echo(str(name,".stl"));
}
module vitamin(name) { // name a vitamin
if(bom > 1)
echo(name);
}

26
scad/utils/cables.scad Normal file
View File

@ -0,0 +1,26 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Cable sizes
//
function cable_wires(cable) = cable[0];
function cable_wire_size(cable) = cable[1];
// numbers from http://mathworld.wolfram.com/CirclePacking.html
function cable_radius(cable) = ceil([0, 1, 2, 2.15, 2.41, 2.7, 3, 3][cable_wires(cable)] * cable_wire_size(cable)) / 2; // radius of a bundle
function wire_hole_radius(cable) = cable_radius(cable) + 0.5;
module wire_hole(r) {
cylinder(r = r, h = 100, center = true);
}
// arrangement of bundle in flat cable clip
function cable_bundle(cable) = [[0,0], [1,1], [2,1], [2, 0.5 + sin(60)], [2,2], [3, 0.5 + sin(60)], [3,2]][cable_wires(cable)];
function cable_width(cable) = cable_bundle(cable)[0] * cable_wire_size(cable); // width in flat clip
function cable_height(cable) = cable_bundle(cable)[1] * cable_wire_size(cable); // height in flat clip

30
scad/utils/polyholes.scad Normal file
View File

@ -0,0 +1,30 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// See http://hydraraptor.blogspot.com/2011/02/polyholes.html
//
function sides(r) = max(round(4 *r),3);
function corrected_radius(r,n) = 0.1 + r / cos(180 / n);
function corrected_diameter(d) = 0.2 + d / cos(180 / sides(d / 2));
module poly_circle(r, center = false) {
n = sides(r);
circle(r = corrected_radius(r,n), $fn = n, center = center);
}
module poly_cylinder(r, h, center = false) {
n = sides(r);
cylinder(h = h, r = corrected_radius(r,n), $fn = n, center = center);
}
module poly_d_cylinder(r, center = false) {
n = sides(r);
r = corrected_radius(r,n);
cylinder(h = h, r = r, $fn = n, center = center);
translate([0, -r, 0])
cube([r, 2 * r, h]);
}

46
scad/utils/teardrops.scad Normal file
View File

@ -0,0 +1,46 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// For making horizontal holes that don't need support material
// Small holes can get away without it but they print better with truncated teardrops
//
module teardrop_2D(r, truncate = true) {
difference() {
union() {
circle(r = r, center = true);
translate([0,r / sqrt(2),0])
rotate([0,0,45])
square([r, r], center = true);
}
if(truncate)
translate([0, r * 2, 0])
square([2 * r, 2 * r], center = true);
}
}
module teardrop(h, r, center, truncate = true)
linear_extrude(height = h, convexity = 2, center = center)
teardrop_2D(r, truncate);
module teardrop_plus(h, r, center, truncate = true)
teardrop(h, r + layer_height / 4, center, truncate);
module tearslot(h, r, w, center)
linear_extrude(height = h, convexity = 6, center = center)
hull() {
translate([-w/2,0,0]) teardrop_2D(r, true);
translate([ w/2,0,0]) teardrop_2D(r, true);
}
module vertical_tearslot(h, r, l, center = true)
linear_extrude(height = h, convexity = 6, center = center)
hull() {
translate([0, l / 2]) teardrop_2D(r, true);
translate([0, -l / 2, 0])
circle(r = r, center = true);
}

View File

@ -0,0 +1,29 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Ball bearings
//
BB624 = [4, 13, 5, "624"]; // 624 ball bearing for idlers
BB608 = [8, 22, 7, "608"]; // 608 bearings for wades
function ball_bearing_diameter(type) = type[1];
function ball_bearing_width(type) = type[2];
module ball_bearing(type) {
vitamin(str("BB",type[3],": Ball bearing ",type[3]," ",type[0], " x ", type[1], " x ", type[2]));
rim = type[1] / 10;
color([0.7,0.7,0.7]) render() difference() {
cylinder(r = type[1] / 2, h = type[2], center = true);
cylinder(r = type[0] / 2, h = type[2] + 1, center = true);
for(z = [-type[2] / 2, type[2] / 2])
translate([0,0,z]) difference() {
cylinder(r = (type[1] - rim) / 2, h = 2, center = true);
cylinder(r = (type[0] + rim) / 2, 2, center = true);
}
}
}

68
scad/vitamins/belts.scad Normal file
View File

@ -0,0 +1,68 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Belt model
//
T5x6 = [5, 6, 2.25];
T5x10 = [5, 10, 2.25];
function belt_pitch(type) = type[0];
function belt_width(type) = type[1];
function belt_thickness(type) = type[2];
module belt(type, x1, y1, r1, x2, y2, r2, gap = 0) {
width = belt_width(type);
thickness = belt_thickness(type);
pi = 3.14159265;
dx = x2 - x1;
dy = y2 - y1;
length = pi * (r1 + r2) + 2 * sqrt(dx * dx + dy * dy) - gap;
vitamin(str("BT", belt_pitch(type),width, round(length), ": Belt T", belt_pitch(type)," x ", width, " x ", round(length)));
linear_extrude(height = width, center = true, convexity = 6) {
difference() {
hull() { // outside of belt
translate([x1,y1])
circle(r = r1 + thickness, center = true);
translate([x2,y2])
circle(r = r2 + thickness, center = true);
}
hull() { // inside of belt
translate([x1,y1])
circle(r = r1, center = true);
translate([x2,y2])
circle(r = r2, center = true);
}
}
}
}
module twisted_belt(type, x1, y1, r1, x2, y2, r2, gap = 0) {
dx = x2 - x1;
dy = y2 - y1;
angle = atan2(dy, dx) - atan2((r2 - r1), dx);
union() {
difference() {
belt(type, x1, y1, r1, x2, y2, r2, gap);
translate([x1, y1 - r1 - belt_thickness(type) / 2, 0])
rotate([0,0, angle])
translate([dx / 2, 0, 0])
cube([dx, belt_thickness(type) + 1 , belt_width(type) + 1], center = true);
}
translate([x1, y1 - r1 - belt_thickness(type) / 2, 0])
rotate([0,90, angle])
linear_extrude(height = dx, twist = 180)
square([belt_width(type), belt_thickness(type)], center = true);
}
}
//twisted_belt(T5x6, 10, 11-4.87, 4.87, 200, 20, 11);
//twisted_belt(T5x6, -374, -1.55, 6.5, 0, 0, 4.95);

View File

@ -0,0 +1,71 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Crude representation of a bulldog clip
//
small_bulldog = [19, 12, 8, 0.25, 2.67, 1, 16];
function bulldog_length(type) = type[0];
function bulldog_depth(type) = type[1];
function bulldog_height(type) = type[2];
function bulldog_thickness(type) = type[3];
function bulldog_tube(type) = type[4] / 2;
function bulldog_radius(type) = type[5];
function bulldog_handle_length(type) = type[6];
module bulldog_shape(depth, height, radius, open) {
hull() {
translate([-depth / 2 + radius, height / 2 - radius]) circle(radius);
translate([-depth / 2 + radius, -height / 2 + radius]) circle(radius);
translate([ depth / 2, 0]) square([0.1, open], center = true);
}
}
module shell(length, width, height, wall) {
difference() {
linear_extrude(height = height, center = true, convexity = 5)
child();
linear_extrude(height = height + 1, center = true, convexity = 5)
difference() {
square([length - 2 * wall, width - 2 * wall], center = true);
minkowski() {
difference() {
square([length + 1, width + 1], center = true);
translate([10,0])
square([length + 1, 2 * wall + eta], center = true);
child();
}
circle(r = wall, center = true);
}
}
}
}
module bulldog(type, open = 4) {
tube = bulldog_tube(type);
thickness = bulldog_thickness(type);
depth = bulldog_depth(type);
gap = open + thickness * 2;
vitamin(str("BD00", bulldog_length(type), ": ", bulldog_length(type), "mm bulldog clip"));
render() translate([depth / 2 - thickness - eta, 0, 0])
union() {
difference() {
rotate([90, 0, 0])
shell(depth, bulldog_height(type), bulldog_length(type), thickness)
bulldog_shape(depth, bulldog_height(type), bulldog_radius(type), gap);
translate([depth - tube - eta, 0, 0])
cube([depth, bulldog_length(type) + 1, 100], center = true);
}
for(side = [-1,1])
translate([bulldog_depth(type) / 2 - tube, 0, side * (gap / 2 + tube)])
rotate([90,0,0])
tube(or = tube, ir = tube - thickness, h = bulldog_length(type));
}
}

View File

@ -0,0 +1,96 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// A strip of polypropylene used with ribbon cable to make a cable flexible in one direction only.
//
module cable_strip(width, depth, travel, x, extra = 15) {
thickness = 0.5;
radius = depth / 2;
top = travel / 4 + extra + x / 2;
bottom = travel / 4 + extra - x /2;
length = max(top, bottom);
total = ceil(top + bottom + PI * depth);
w = ceil(width);
vitamin(str("PP", thickness * 10, w, total,": Polypropylene strip ", total, "mm x ", w, "mm x ", thickness, "mm"));
color([1,0,1]) render() linear_extrude(height = w, center = true, convexity = 4)
difference() {
union() {
translate([-bottom, radius])
circle(r = radius, center = true);
translate([-bottom, 0])
square([length, depth]);
}
union() {
translate([-bottom, radius])
circle(r = radius - thickness, center = true);
translate([-bottom, thickness])
square([length + 1, depth - thickness * 2]);
}
translate([0, -thickness / 2])
square([travel, thickness * 2]);
translate([x, depth - thickness - thickness / 2])
square([travel, thickness * 2]);
}
}
//cable_strip(20, 50, 200, -100);
module ellipse(xr, yr, center = true)
{
scale([1, yr / xr])
circle(r = xr, center = center);
}
module elliptical_cable_strip(width, p1, p2, pmax, extra = 15) {
thickness = 0.5;
w = ceil(width);
max_delta = pmax - p1;
delta = p2 - p1;
A = abs(max_delta[0] / 2);
B = 50;
length = ceil(PI * pow((pow(A,1.5) + pow(B,1.5))/2, 1/1.5));
total = length + 2 * extra;
vitamin(str("PP", thickness * 10, w, total,": Polypropylene strip ", total, "mm x ", w, "mm x ", thickness, "mm"));
a = abs(delta[0] / 2);
b = pow(2 * pow(length / PI, 1.5) - pow(a, 1.5), 1/1.5);
translate(p1 - [a, 0, 0])
multmatrix(m = [ [1, 0, 0, 0],
[delta[1] / delta[0], 1, 0, delta[1] / 2],
[delta[2] / delta[0], 0, 1, delta[2] / 2],
[0, 0, 0, 1] ])
color([1,0,1]) render() linear_extrude(height = w, center = true, convexity = 4)
difference() {
union() {
square([(a + thickness) * 2, extra * 2], center = true);
translate([0, -extra])
ellipse((a + thickness), b + thickness);
}
translate([0, (b + 1) / 2])
square([a * 2 + 1, b + 1], center = true);
square([a * 2, extra * 2], center = true);
translate([0, -extra])
ellipse(a, b);
}
}

View File

@ -0,0 +1,136 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// D-connectors
//
DCONN9 = [30.81, [18, 16.92], 24.99, [9.26, 8.36], 12.55, 10.72, 6.693, 1.12, 9];
function d_flange_length(type) = type[0];
function d_flange_width(type) = type[4];
function d_flange_thickness(type) = type[7];
function d_mate_distance(type) = 8.5;
module d_pillar(type) {
vitamin("DP0000: D-type connect pillar");
rad = 5.37 / 2;
height = 4.5;
screw = 2.5;
screw_length = 8;
color([0.9,0.9,0.9]) render() translate([0,0, d_flange_thickness(type)]) difference() {
union() {
cylinder(r = rad, h = height, $fn = 6);
translate([0,0, - screw_length + eta])
cylinder(r = screw / 2, h = screw_length);
}
translate([0,0,1])
cylinder(r = screw / 2, h = height);
}
}
module d_plug(type, socket = false) {
hole_r = 3.05 / 2;
dwall = 0.5;
flange_length = d_flange_length(type);
d_length = socket ? type[1][1] : type[1][0];
hole_pitch = type[2];
d_width = socket ? type[3][1] : type[3][0];
flange_width = d_flange_width(type);
d_height = type[6];
back_height = type[5] - d_height;
pins = type[8];
if(socket)
vitamin(str("DTYPES", pins, ": ", pins," way D socket"));
else
vitamin(str("DTYPEP", pins, ": ", pins," way D plug"));
module D(length, width, rad) {
d = width / 2 - rad;
offset = d * sin(10);
hull() {
translate([-length / 2 + rad - offset, width / 2 - rad])
circle(r = rad, center = true);
translate([-length / 2 + rad + offset, -width / 2 + rad])
circle(r = rad, center = true);
translate([length / 2 - rad + offset, width / 2 - rad])
circle(r = rad, center = true);
translate([length / 2 - rad - offset, -width / 2 + rad])
circle(r = rad, center = true);
}
}
//
// Shell
//
color([0.8, 0.8, 0.8]) render() difference() {
union() {
rounded_rectangle([flange_length, flange_width, d_flange_thickness(type)], 2, center = false);
linear_extrude(height = d_height, convexity = 5)
difference() {
D(d_length, d_width, 2.5);
D(d_length - 2 * dwall, d_width - 2 * dwall, 2.5 - dwall);
}
rotate([0,180,0])
linear_extrude(height = back_height, convexity = 5)
D(type[1][0] + 2 * dwall, type[3][0] + 2 * dwall, 2.5 + dwall);
}
for(end = [-1, 1])
translate([end * hole_pitch / 2, 0, 0])
cylinder(r = hole_r, h = 10, center = true);
}
//
// Insulator
//
color([0.2,0.2,0.2]) render() {
translate([0,0, d_flange_thickness(type) + eta])
rotate([0, 180, 0])
linear_extrude(height = back_height + 1 + d_flange_thickness(type), convexity = 5)
D(d_length - dwall, d_width - dwall, 2.5 - dwall/2);
if(socket)
linear_extrude(height = d_height - eta, convexity = 5)
difference() {
D(d_length - dwall, d_width - dwall, 2.5 - dwall/2);
for(i = [1 : pins])
translate([(i - (pins + 1) / 2) * 2.77 / 2, (i % 2 - 0.5) * 2.84, 0])
circle(r = 0.7);
}
}
//
// Pins
//
render() for(i = [1 : pins])
translate([(i - (pins + 1) / 2) * 2.77 / 2, (i % 2 - 0.5) * 2.84, 0]) {
union() {
if(!socket)
translate([0,0, - 0.5])
cylinder(r = 0.5, h = d_height);
rotate([180, 0, 0])
difference() {
cylinder(r = 1, h = 8);
cylinder(r = 0.45, h = 9);
translate([0, (i % 2 - 0.5) * -4, 8])
rotate([45, 0, 0])
cube(3, center = true);
}
}
}
}
module d_socket(connector) d_plug(connector, true);
//d_plug(DCONN9);
//d_pillar();

View File

@ -0,0 +1,51 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Model by Václav 'ax' Hula
//
function sanguinololu_width() = 2 * 25.4;
function sanguinololu_length() = 4 * 25.4;
module sanguinololu() {
vitamin("SANGUINOL: Electronics e.g. Sanguinolou");
import("../imported_stls/sanguinololu.stl");
}
module sanguinololu_screw_positions() {
inset = 1.5 * 2.54;
for(x = [inset, sanguinololu_width() - inset])
for(y = [inset, sanguinololu_length() - inset])
translate([x, y, 0])
child();
}
KY240W = ["KY240W12L", 199, 110, 50, [[ 199 / 2 - 12, 110 / 2 - 93],
[ 199 / 2 - 12, 110 / 2 - 9 ],
[ 199 / 2 - 138, 110 / 2 - 93],
[ 199 / 2 - 138, 110 / 2 - 9 ]]];
function psu_name(type) = type[0];
function psu_length(type) = type[1];
function psu_width(type) = type[2];
function psu_height(type) = type[3];
function psu_hole_list(type) = type[4];
module psu(type) {
vitamin(str(psu_name(type),": PSU e.g. ", psu_name(type)));
color([0.8, 0.8, 0.8])
translate([0,0, psu_height(type) / 2])
cube([psu_length(type), psu_width(type), psu_height(type)], center = true);
}
module psu_screw_positions(type) {
for(point = psu_hole_list(type))
translate(point)
child();
}

101
scad/vitamins/fans.scad Normal file
View File

@ -0,0 +1,101 @@
//
// Mendel90
//
// nop.head@gmail.com
// hydraraptor.blogspot.com
// based on http://www.thingiverse.com/thing:8063 by MiseryBot, CC license
fan80x38 = [80, 38, 75, 35.75, M4_cap_screw, 40, 4.3, 84];
fan60x25 = [60, 25, 57, 25, M3_cap_screw, 31.5, 3.6, 64];
function fan_width(type) = type[0];
function fan_depth(type) = type[1];
function fan_bore(type) = type[2];
function fan_hole_pitch(type) = type[3];
function fan_hub(type) = type[5];
function fan_thickness(type) = type[6];
function fan_outer_diameter(type) = type[7];
function fan_screw(type) = type[4];
module fan(type) {
width = fan_width(type);
depth = fan_depth(type);
thickness = fan_thickness(type);
hole_pitch = fan_hole_pitch(type);
corner_radius = width / 2 - hole_pitch;
screw = fan_screw(type);
vitamin(str("FAN", fan_width(type), fan_depth(type), ": Fan ", fan_width(type), " x ", fan_depth(type)));
difference() {
linear_extrude(height = depth, center = true, convexity = 4)
difference() {
//overall outside
rounded_square(width, width, corner_radius);
//main inside bore, less hub
difference() {
circle(r = fan_bore(type) / 2, center = true);
circle(r = fan_hub(type) / 2, center = true);
}
//Mounting holes
for(x = [-hole_pitch, hole_pitch])
for(y = [-hole_pitch, hole_pitch])
translate([x, y])
circle(r = screw_clearance_radius(screw), center = true);
}
//Remove outside ring
difference() {
cylinder(r = sqrt(2) * width / 2, h = depth - 2 * thickness, center = true);
cylinder(r = fan_outer_diameter(type) / 2, h = depth - 2 * thickness + 0.2, center = true);
}
}
//Seven Blades
linear_extrude(height = depth - 1, center = true, convexity = 4, twist = -30, slices = depth / 2)
for(i= [0 : 6])
rotate((360 * i) / 7)
translate([0, -1.5 / 2])
square([fan_bore(type) / 2 - 0.75, 1.5]);
}
module fan_holes(type, poly = false) {
//Mounting holes
hole_pitch = fan_hole_pitch(type);
screw = fan_screw(type);
for(x = [-hole_pitch, hole_pitch])
for(y = [-hole_pitch, hole_pitch])
translate([x, y, 0])
if(poly)
poly_cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
else
cylinder(r = screw_clearance_radius(screw), h = 100, center = true);
cylinder(r = fan_bore(type) / 2, h = 100, center = true);
}
module fan_assembly(type, thickness) {
color([0.2, 0.2, 0.2])
render()
fan(type);
hole_pitch = fan_hole_pitch(type);
screw = fan_screw(type);
washer = screw_washer(screw);
nut = screw_nut(screw);
for(x = [-hole_pitch, hole_pitch])
for(y = [-hole_pitch, hole_pitch]) {
translate([x, y, thickness + fan_depth(type) / 2])
screw_and_washer(screw, screw_longer_than(thickness + fan_thickness(type) +
washer_thickness(washer) + nut_thickness(nut, true)));
translate([x, y, fan_depth(type) / 2 - fan_thickness(type)])
rotate([180, 0, 0])
nut(screw_nut(screw), true);
}
}
//fan(fan80x38);
//fan(fan60x25);

View File

@ -0,0 +1,21 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Linear bearings
//
LM10UU = [29, 19, 10];
LM8UU = [24, 15, 8];
LM6UU = [19, 12, 6];
LM4UU = [12, 8, 4];
module linear_bearing(type) {
vitamin(str("LM",type[2],"UU: ","LM",type[2],"UU linear bearing"));
color([0.7,0.7,0.7]) rotate([0,90,0]) difference() {
cylinder(r = type[1] / 2, h = type[0], center = true);
cylinder(r = type[2] / 2, h = type[0] + 1, center = true);
}
}

View File

@ -0,0 +1,69 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Microswitch used for endstops
//
function microswitch_thickness() = 6.4;
function microswitch_length() = 19.8;
function microswitch_first_hole_x_offset() = -2;
function microswitch_button_x_offset() = -(5.1 - microswitch_first_hole_x_offset()) + microswitch_length() / 2;
function microswitch_hole_y_offset() = -8.4;
module microswitch_hole_positions()
{
for(x = [microswitch_first_hole_x_offset(), 7.5])
translate([x, microswitch_hole_y_offset(), microswitch_thickness() / 2])
child();
}
module microswitch_holes(r = No2_pilot_radius, h = 7.5)
{
translate([0, 0, -microswitch_thickness() - h / 2])
microswitch_hole_positions()
teardrop_plus(r = r, h = h + 1, center = true);
}
module microswitch_contact_space() {
depth = 15;
translate([-microswitch_first_hole_x_offset() + 0.75, -depth / 2 - 3, 0])
cube([microswitch_length() - 2, depth, microswitch_thickness() - 2], center = true);
}
module microswitch() {
vitamin("SMMICRO: Microswitch");
translate([-(5.1 + 9.5 - 7.5), -(8.4 + 2.5), -3.2 + (exploded ? 5 : 0)]) { // put operating point of button at the origin
color([0,0,0]) render() difference() { // main body
cube([19.8, 10.2, 6.4]);
translate([10, 9.5, -1])
cube([19.8, 10.2, 8]); // lower half of top
translate([5.1, 2.5, -1])
cylinder(r = 2.35 / 2, h = 8); // mounting holes
translate([5.1 + 9.5, 2.5, -1])
cylinder(r = 2.35 / 2, h = 8);
}
color([1,0.7,0]) render() // orange button
translate([5.1 + 9.5 - 7.5,8.4 + 2.5 - 0.5,1.6])
linear_extrude(height = 3.2)
hull() {
circle(r = 1);
translate([0,-4])
circle(r = 1);
}
color([1,1,0]) render() // yellow contacts
for(x = [1.6, 1.6 + 8.8, 1.6 + 8.8 + 7.3])
translate([x, 2.5 - 6.4, 1.6])
difference() {
cube([0.5, 7, 3.2]);
translate([0, 1.6, 1.6])
rotate([0,90,0])
cylinder(r = 0.8, h = 5, center = true);
}
}
}

93
scad/vitamins/nuts.scad Normal file
View File

@ -0,0 +1,93 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Washers
//
M3_nut = [3, 6.4, 2.4, 4, M3_washer, M3_nut_trap_depth];
M4_nut = [4, 8.1, 3.2, 5, M4_washer, M4_nut_trap_depth];
M6_nut = [6, 11.5, 5, 8, M6_washer, M6_nut_depth];
M8_nut = [8, 15, 6.5, 8, M8_washer, M8_nut_depth];
function nut_radius(type) = type[1] / 2;
function nut_flat_radius(type) = nut_radius(type) * cos(30);
function nut_thickness(type, nyloc = false) = nyloc ? type[3] : type[2];
function nut_washer(type) = type[4];
function nut_trap_depth(type) = type[5];
module nut(type, nyloc = false) {
hole_rad = type[0] / 2;
outer_rad = nut_radius(type);
thickness = nut_thickness(type);
nyloc_thickness = type[3];
if(nyloc)
vitamin(str("NYLOCM", type[0], ": Nyloc nut M", type[0]));
else
vitamin(str("NUTM", type[0], ": Nut M", type[0]));
if(exploded && nyloc)
cylinder(r = 0.2, h = 10);
color([0.7, 0.7, 0.7]) render() translate([0, 0, (exploded && nyloc) ? 10 : 0]) difference() {
union() {
cylinder(r = outer_rad, h = thickness, $fn = 6);
if(nyloc)
translate([0,0, eta])
rounded_cylinder(r = outer_rad * cos(30) , h = nyloc_thickness, r2 = (nyloc_thickness - thickness) / 2);
}
translate([0,0,-1])
cylinder(r = hole_rad, h = nyloc_thickness + 2);
}
}
module nut_and_washer(type, nyloc) {
washer = nut_washer(type);
translate([0, 0, exploded ? 7 : 0])
washer(washer);
translate([0,0, washer_thickness(washer)])
nut(type, nyloc);
}
M4_wingnut = [4, 10, 3.75, 8, M4_washer, 0, 22, 10, 6, 3];
module wingnut(type) {
hole_rad = type[0] / 2;
bottom_rad = nut_radius(type);
top_rad = type[3] / 2;
thickness = nut_thickness(type);
wing_span = type[6];
wing_height = type[7];
wing_width = type[8];
wing_thickness = type[9];
top_angle = asin((wing_thickness / 2) / top_rad);
bottom_angle = asin((wing_thickness / 2) / bottom_rad);
vitamin(str("WING0", type[0], ": Wingnut M",type[0]));
if(exploded)
cylinder(r = 0.2, h = 10);
color([0.7,0.7,0.7]) render() translate([0, 0, exploded ? 10 : 0]) difference() {
union() {
cylinder(r1 = bottom_rad, r2 = top_rad, h = thickness);
for(rot = [0, 180])
rotate([90, 0, rot]) linear_extrude(height = wing_thickness, center = true)
hull() {
translate([wing_span / 2 - wing_width / 2, wing_height - wing_width / 2])
circle(r = wing_width / 2, center = true);
polygon([
[bottom_rad * cos(top_angle) - eta, 0],
[wing_span / 2 - wing_width / 2, wing_height - wing_width / 2],
[top_rad * cos(top_angle) - eta, thickness],
[bottom_rad * cos(top_angle) - eta, 0],
]);
}
}
translate([0,0,-1])
cylinder(r = hole_rad, h = thickness + 2);
}
}

View File

@ -0,0 +1,40 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Nylon pillars
//
M3x13_pillar = [3, 13, 6.5, 6];
M3x20_pillar = [3, 20, 5.5, 7];
function pillar_height(type) = type[1];
module pillar(type) {
height = pillar_height(type);
vitamin(str("pillar M", type[0], "x", height));
color([0.9,0.9,0.9]) render() difference() {
cylinder(h = height, r = type[2] / 2);
translate([0,0, height])
cylinder(h = type[3] * 2, r = type[0] / 2, center = true);
}
color([1,1,0]) render() cylinder(h = type[3] * 2, r = type[0] / 2, center = true);
}
module hex_pillar(type) {
height = pillar_height(type);
vitamin(str("HP0", type[0], height, " : Hex pillar M", type[0], " x ", height));
color([0.9,0.9,0.9]) render() difference() {
union() {
cylinder(h = height, r = type[2] / 2, $fn = 6);
cylinder(h = type[3] * 2, r = type[0] / 2, center = true);
}
translate([0,0, height])
cylinder(h = type[3] * 2, r = type[0] / 2, center = true);
}
}

147
scad/vitamins/screws.scad Normal file
View File

@ -0,0 +1,147 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Screws
//
hs_cap = 0;
hs_pan = 1;
hs_cs = 2; // counter sunk
hs_hex = 3;
hs_grub= 4; // pulley set screw
M2p5_pan_screw = ["PS025", "M2.5 pan screw", hs_pan, 2.5, 4.7, 1.7, M2p5_washer, false, M2p5_tap_radius, M2p5_clearance_radius];
M2p5_cap_screw = ["CS025", "M2.5 cap screw", hs_cap, 2.5, 4.7, 2.0, M2p5_washer, false, M2p5_tap_radius, M2p5_clearance_radius];
M3_cap_screw = ["CS030", "M3 cap screw", hs_cap, 3, 5.5, 2.5, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M3_pan_screw = ["PS030", "M3 pan screw", hs_pan, 3, 5.4, 2.0, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M3_hex_screw = ["HX030", "M3 hex screw", hs_hex, 3, 6.4, 2.125, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M3_grub_screw = ["GB030", "M3 grub screw", hs_grub, 3, 1.6, 2.5, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius];
M4_cap_screw = ["CS040", "M4 cap screw", hs_cap, 4, 7.0, 3.0, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
M4_hex_screw = ["HX040", "M4 hex screw", hs_hex, 4, 8.1, 2.925, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
M4_pan_screw = ["PS040", "M4 pan screw", hs_pan, 4, 7.8, 3.3, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius];
M8_hex_screw = ["HX080", "M8 hex screw", hs_hex, 8, 15, 5.65, M8_washer, M8_nut, M8_tap_radius, M8_clearance_radius];
No2_screw = ["PSW02", "No2 pan wood screw", hs_pan, 2.2, 4.2, 1.7, M2p5_washer, false, No2_pilot_radius, No2_clearance_radius];
No4_screw = ["PSW04", "No4 pan wood screw", hs_pan, 3.0, 5.5, 2.0, M3p5_washer, false, No4_pilot_radius, No4_clearance_radius];
No6_screw = ["PSW06", "No6 pan wood screw", hs_pan, 3.5, 6.7, 2.2, M4_washer, false, No6_pilot_radius, No6_clearance_radius];
No6_cs_screw = ["PSW06", "No6 cs wood screw", hs_cs, 3.5, 7.0, 0, M4_washer, false, No6_pilot_radius, No6_clearance_radius];
function screw_washer(type) = type[6];
function screw_nut(type) = type[7];
function screw_pilot_hole(type) = type[8];
function screw_clearance_radius(type) = type[9];
function screw_radius(type) = type[3] / 2;
function screw_head_radius(type) = type[4] / 2;
function screw_longer_than(x) = x <= 10 ? 10 :
x <= 12 ? 12 :
x <= 16 ? 16 :
ceil(x / 5) * 5;
function screw_shorter_than(x) = x > 20 ? floor(x / 5) * 5 :
x > 16 ? 16 :
x > 12 ? 12 :
10;
function screw_head_height(type) = type[2] == hs_cap ? type[4] :
type[2] == hs_cs ? type[4] / 2 : type[5];
module screw(type, length) {
vitamin(str(type[0], length,": ",type[1], " x ", length));
head_type = type[2];
rad = screw_radius(type) - eta;
head_rad = screw_head_radius(type);
if(exploded)
cylinder(r = 0.2, h = 16);
translate([0, 0, exploded ? length + 10 : 0]) {
if(head_type == hs_cap) {
assign(head_height = rad * 2,
socket_rad = type[5] / cos(30) / 2,
socket_depth = 2 * rad / 3)
color([0.2,0.2,0.2]) render() difference() {
union() {
cylinder(r = head_rad, h = head_height);
translate([0,0, - length + eta])
cylinder(r = rad, h = length);
}
translate([0,0, head_height])
cylinder(r = socket_rad, h = socket_depth * 2, $fn = 6, center = true);
}
}
if(head_type == hs_grub) {
assign(socket_rad = type[4] / 2,
socket_depth = type[5])
color([0.2,0.2,0.2]) render() difference() {
cylinder(r = rad, h = length);
cylinder(r = socket_rad, h = socket_depth * 2, $fn = 6, center = true);
}
}
if(head_type == hs_hex) {
assign(head_height =type[5])
color([0.8,0.8,0.8]) render() union() {
cylinder(r = head_rad, h = head_height, $fn = 6);
translate([0,0, - length + eta])
cylinder(r = rad, h = length);
}
}
if(head_type == hs_pan) {
assign(head_height = type[5],
socket_rad = 0.6 * head_rad,
socket_depth = 0.5 * type[5])
color([0.8,0.8,0.4]) render() difference() {
union() {
rounded_cylinder(r = head_rad, h = head_height, r2 = head_height / 2);
translate([0,0, - length + eta])
cylinder(r = rad, h = length);
}
translate([0,0,head_height]) {
cube([2 * socket_rad, 1, 2 * socket_depth], center = true);
cube([1, 2 * socket_rad, 2 * socket_depth], center = true);
}
}
}
if(head_type == hs_cs) {
assign(head_height = head_rad,
socket_rad = 0.6 * head_rad,
socket_depth = 0.3 * head_rad,
socket_width = 1)
color([0.8,0.8,0.4]) render() difference() {
union() {
translate([0,0, -head_height])
cylinder(h = head_height, r1 = 0, r2 = head_rad);
translate([0,0, - length - eta])
cylinder(r = rad, h = length);
}
translate([0,0,0]) {
cube([2 * socket_rad, socket_width, 2 * socket_depth], center = true);
cube([socket_width, 2 * socket_rad, 2 * socket_depth], center = true);
}
}
}
}
}
module screw_and_washer(type, length, spring = false) {
washer = screw_washer(type);
translate([0, 0, exploded ? 6 : 0])
washer(washer);
translate([0,0, washer_thickness(washer)]) {
if(spring) {
translate([0, 0, exploded ? 8 : 0])
star_washer(washer);
translate([0,0, washer_thickness(washer)])
screw(type, length);
}
else
screw(type, length);
}
}

57
scad/vitamins/sheet.scad Normal file
View File

@ -0,0 +1,57 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Flat sheets
//
MDF6 = [ "MD", "MDF sheet", 6, [0.4, 0.4, 0.2, 1 ], true];
MDF10 = [ "MD", "MDF sheet", 10, [0.4, 0.4, 0.2, 1 ], true];
MDF12 = [ "MD", "MDF sheet", 12, [0.4, 0.4, 0.2, 1 ], true];
PMMA6 = [ "AC", "Acrylic sheet", 6, [1, 1, 1, 0.5 ], false];
PMMA8 = [ "AC", "Acrylic sheet", 8, [1, 1, 1, 0.2 ], false];
PMMA10 = [ "AC", "Acrylic sheet",10, [1, 1, 1, 0.2 ], false];
glass = [ "GL", "Glass sheet", 2, [1, 1, 1, 0.25 ], false];
DiBond = [ "DB", "Dibond sheet", 3, [0.5, 0.5, 0.5, 1 ], false];
function sheet_thickness(type) = type[2];
function sheet_is_soft(type) = type[4];
module corner(r) {
if(r > 0)
translate([r, - r])
circle(r, center = true);
else
if(r < 0)
translate([-r, r])
rotate([0,0,45])
square(-r * sqrt(2), -r * sqrt(2), center = true);
else
translate([0.5, -0.5])
square(1, center = true);
}
module sheet(type, w, d, corners = [0, 0, 0, 0]) {
t = sheet_thickness(type);
vitamin(str(type[0], t, round(w), round(d),": ",type[1]," ", round(w), " x ", round(d), " x ", t));
color(type[3])
linear_extrude(height = t, center = true)
hull() {
translate([-w/2, d/2])
corner(corners[0]);
translate([ w/2, d/2])
rotate([0, 0, -90])
corner(corners[1]);
translate([ w/2, -d/2])
rotate([0, 0, -180])
corner(corners[2]);
translate([-w/2, -d/2])
rotate([0, 0, -270])
corner(corners[3]);
}
}

View File

@ -0,0 +1,61 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Springs
//
extruder_spring = [7, 1, 10, 5];
hob_spring = [12, 0.75, 10, 6];
// taken from openscad example 20
module coil(r1 = 100, r2 = 10, h = 100, twists)
{
hr = h / (twists * 2);
stepsize = 1/16;
module segment(i1, i2) {
alpha1 = i1 * 360*r2/hr;
alpha2 = i2 * 360*r2/hr;
len1 = sin(acos(i1*2-1))*r2;
len2 = sin(acos(i2*2-1))*r2;
if (len1 < 0.01)
polygon([
[ cos(alpha1)*r1, sin(alpha1)*r1 ],
[ cos(alpha2)*(r1-len2), sin(alpha2)*(r1-len2) ],
[ cos(alpha2)*(r1+len2), sin(alpha2)*(r1+len2) ]
]);
if (len2 < 0.01)
polygon([
[ cos(alpha1)*(r1+len1), sin(alpha1)*(r1+len1) ],
[ cos(alpha1)*(r1-len1), sin(alpha1)*(r1-len1) ],
[ cos(alpha2)*r1, sin(alpha2)*r1 ],
]);
if (len1 >= 0.01 && len2 >= 0.01)
polygon([
[ cos(alpha1)*(r1+len1), sin(alpha1)*(r1+len1) ],
[ cos(alpha1)*(r1-len1), sin(alpha1)*(r1-len1) ],
[ cos(alpha2)*(r1-len2), sin(alpha2)*(r1-len2) ],
[ cos(alpha2)*(r1+len2), sin(alpha2)*(r1+len2) ]
]);
}
linear_extrude(height = h, twist = 180*h/hr,
$fn = (hr/r2)/stepsize, convexity = 5) {
for (i = [ stepsize : stepsize : 1+stepsize/2 ])
segment(i-stepsize, min(i, 1));
}
}
module comp_spring(spring, l = 0) {
l = (l == 0) ? spring[2] : l;
vitamin(str("SPR", spring[0], spring[1] * 100, spring[2], ": Spring ", spring[0], " x ", spring[1], " x ", spring[2] ));
color([0.2, 0.2, 0.2]) render() coil(r1 = (spring[0] - spring[1])/ 2, r2 = spring[1] / 2, h = l, twists = spring[3]);
}
//comp_spring(extruder_spring);

View File

@ -0,0 +1,72 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// NEMA stepper motor model
//
// corner body boss boss shaft
// side, length, radius, radius, radius, depth, shaft, length, holes
NEMA17 = [42.3, 47.5, 53.6/2, 25, 11, 2, 5, 24, 31 ];
NEMA17S = [42.3, 34, 53.6/2, 25, 11, 2, 5, 24, 31 ];
NEMA14 = [35.2, 36, 46.4/2, 21, 11, 2, 5, 21, 26 ];
function NEMA_width(motor) = motor[0];
function NEMA_length(motor) = motor[1];
function NEMA_radius(motor) = motor[2];
function NEMA_holes(motor) = [-motor[8]/2, motor[8]/2];
function NEMA_big_hole(motor) = motor[4] + 0.2;
function NEMA_shaft_length(motor) = motor[7];
module NEMA(motor) {
side = NEMA_width(motor);
length = NEMA_length(motor);
body_rad = motor[3];
boss_rad = motor[4];
boss_height = motor[5];
shaft_rad = motor[6] / 2;
cap = 8;
vitamin(str("NEMA", round(motor[0] / 2.54), length * 10, ": NEMA", round(motor[0] / 2.54), " x ", length, " stepper motor"));
union() {
color([0,0,0]) render() // black laminations
translate([0,0, -length / 2])
intersection() {
cube([side, side, length - cap * 2],center = true);
cylinder(r = body_rad, h = 2 * length, center = true);
}
color([0.5,0.5,0.5]) render() { // aluminium end caps
difference() {
union() {
intersection() {
union() {
translate([0,0, -cap / 2])
cube([side,side,cap], center = true);
translate([0,0, -length + cap / 2])
cube([side,side,cap], center = true);
}
cylinder(r = NEMA_radius(motor), h = 3 * length, center = true);
}
difference() {
cylinder(r = boss_rad, h = boss_height * 2, center = true); // raised boss
cylinder(r = shaft_rad + 2, h = boss_height * 2 + 1, center = true);
}
cylinder(r = shaft_rad, h = NEMA_shaft_length(motor) * 2, center = true); // shaft
}
for(x = NEMA_holes(motor))
for(y = NEMA_holes(motor))
translate([x, y, 0])
cylinder(r = 3/2, h = 9, center = true);
}
}
}
}
module NEMA_screws(motor, n = 4) {
for(a = [0: 90 : 90 * (n - 1)])
rotate([0, 0, a])
translate([motor[8]/2, motor[8]/2, 0])
screw_and_washer(M3_pan_screw, 8, true);
}

View File

@ -0,0 +1,49 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Washers
//
M2p5_washer= [2.5, 5, 0.5, false];
M3_washer = [3, 7, 0.5, false];
M3p5_washer = [3.5, 8, 0.5, false];
M4_washer = [4, 9, 0.9, false];
M5_penny_washer = [5, 20, 1.4, false];
M6_washer = [6, 12, 1.5, false];
M8_washer = [8, 16, 1.5, false];
M3_rubber_washer= [3, 10, 1.5, true];
function washer_diameter(type) = type[1];
function washer_thickness(type) = type[2];
function washer_soft(type) = type[3];
module washer(type) {
if(washer_soft(type))
vitamin(str("WR", type[0] * 10, type[1], type[2] * 10, ": Rubber washer M",type[0], " x ", type[1], " x ", type[2]));
else
vitamin(str("WA", type[0] * 10, type[1], type[2] * 10, ": Washer M",type[0], " x ", type[1], " x ", type[2]));
color(washer_soft(type) ? [0.2,0.2,0.2] : [0.8,0.8,0.8]) render() difference() {
cylinder(r = washer_diameter(type) / 2, h = washer_thickness(type));
cylinder(r = type[0] / 2, h = 2 * washer_thickness(type) + 1, center = true);
}
}
module star_washer(type) {
hole = type[0] / 2;
rad = washer_diameter(type) / 2;
inner = (hole + rad) / 2;
spoke = rad - hole;
vitamin(str("WS", type[0] * 10, type[1], type[2] * 10, ": Star washer M",type[0], " x ", type[1], " x ", type[2]));
color([0.8,0.8,0.4]) render() difference() {
cylinder(r = rad, h = washer_thickness(type));
cylinder(r = hole, h = 2 * washer_thickness(type) + 1, center = true);
for(a = [0:30:360])
rotate([0, 0, a])
translate([inner + spoke / 2, 0, 0.5])
cube([spoke, 2 * 3.142 * inner / 36, washer_thickness(type) + 1], center = true);
}
}

36
scad/vitamins/ziptie.scad Normal file
View File

@ -0,0 +1,36 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Zipties
//
small_ziptie = [2.3, 1, [4.7, 4.25, 3], [1,1,1], 20];
function ziptie_width(type) = type[0];
function ziptie_thickness(type) = type[1];
module ziptie(type, r)
{
latch = type[2];
length = ceil(2 * PI * r + type[4] + latch[2] + 1);
vitamin(str("ZT00", length, ": Ziptie ",length));
angle = asin((latch[0] / 2) / r) - asin(ziptie_thickness(type) / latch[0]);
color(type[3]) render() union() {
tube(ir = r, or = r + ziptie_thickness(type), h = ziptie_width(type));
translate([0, -r, - latch[1] / 2])
rotate([90, 0, angle]) {
union() {
cube(latch);
translate([latch[0] / 2, latch[1] / 2, (latch[2] + 1) / 2])
cube([ziptie_thickness(type), ziptie_width(type), latch[2] + 1], center = true);
}
}
}
}
//ziptie(small_ziptie, 10);

355
scad/wade.scad Normal file
View File

@ -0,0 +1,355 @@
//
// Mendel90
//
// Originally based on Josef Prusa's version but much hacked
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
include <conf/config.scad>
use <d-motor_bracket.scad>
Stoffle15_10mm = [10, 13, 5, false];
Stoffle15_16mm = [16.5, 10, 6, false];
Mendel90_12mm = [12, 10, 6 + 3/2 - 1, false];
function insulator_diameter(type) = type[0];
function insulator_depth(type) = type[1];
function insulator_screw_pitch(type) = type[2];
function insulator_clamped(type) = type[3];
hot_end = Mendel90_12mm;
clamp_width = 2 * (insulator_screw_pitch(hot_end) + screw_clearance_radius(M3_cap_screw) + min_wall);
module b608(h=7){
difference(){
union(){
translate([0,0,3.5])
cylinder(r=11.01,h=h,center=true);
*translate([0,0,3.5])
cylinder(r=6,h=7,center=true);
}
//translate([0,0,3.5]) cylinder(r=4,h=8,center=true);
}
}
screw_depth = 5;
motor_y = 31.5;
motor_min = 26 + 5;
motor_max = 36;
motor_x = (motor_min + motor_max) / 2;
motor_leeway = motor_max - motor_min;
thickness = 5;
base_thickness = 6;
filament_x = 75;
filament_z = 15;
width = 28;
mount_pitch = 25;
pscrew_x = 60;
pscrew_y = [17.5, 45.5];
pscrew_z = [8.5, 21.5];
driven_x = 70;
driven_y = 31.5;
function extruder_connector_offset() = [-filament_x + motor_x, filament_z - thickness, motor_y] + d_motor_connector_offset(NEMA17);
module wades_block_stl() {
stl("wades_block");
insulator = insulator_diameter(hot_end);
screw_pitch = insulator_screw_pitch(hot_end);
insulator_depth = insulator_depth(hot_end);
difference(){
union(){
cube([81, 52, thickness]); // motor plate
cube([filament_x + 25 - 3.5, base_thickness, 28]); // base
translate([filament_x + 25 - 3.5, base_thickness / 2, filament_z])
for(a = [-90, 90])
rotate([a, 0, 0])
teardrop(r = 10.6, h = base_thickness, truncate = false, center = true);
translate([57, 0, 0])
cube([26, 52, width]); // bearing housing
translate([80,1,0]) // fillet
cube([11,11, width]);
}
translate([91,base_thickness,-1])
rotate([0,0,45])
cube([9,9,30]); // chamfer on fillet
translate([-11,-1,30]) rotate([0,60,0]) cube([30, base_thickness + 2, 60]); // base chamfers
translate([80, -1, width + eta]) cube([40, base_thickness + 2, 10]);
translate([filament_x, 20, filament_z])
rotate([90,0,0])
teardrop(h = 70, r=4/2, center=true); // filament
// mounting holes
for(side = [-1, 1])
translate([filament_x + mount_pitch * side, base_thickness, filament_z])
rotate([90,0,0])
nut_trap(M4_clearance_radius, M4_nut_radius, 3, true);
for(y = pscrew_y)
for(z = pscrew_z) {
translate([70, y, z]) rotate([90,0,90])teardrop(h=40,r=4.5/2, center=true); // pressure screws
translate([pscrew_x - 5, y, z]) rotate([90,0,90])cylinder(h=10,r=M4_nut_radius, $fn=6, center=true); // nut traps
}
//
// holes for motor
//
translate([motor_x, motor_y, -1]) {
slot(r = NEMA_big_hole(NEMA17), l = motor_leeway, h = 10, center = false); // motor hub slot
for(x = NEMA_holes(NEMA17)) // motor screw slots
for(y = NEMA_holes(NEMA17))
translate([x,y,0])
slot(r = M3_clearance_radius, l = motor_leeway, h = 10, center = false);
}
//
// remove fourth motor slot
//
translate([motor_x - 40 + motor_leeway / 2, motor_y - NEMA_big_hole(NEMA17), -1])
cube([40,32,7]);
translate([motor_x - 40 + motor_leeway / 2 + 6, motor_y, -1])
cube([40,32,7]);
translate([-5,-1,-1]) cube([16,60,30]); // truncates tail
translate([driven_x, driven_y, 7.5]) poly_cylinder(r = M8_clearance_radius + 0.25,h=30); // hole for hobbed bolt
translate([driven_x, driven_y, 21.01]) b608(); // top bearing socket
translate([83, driven_y, 11.5]) b608(8); // clearance for idler
translate([driven_x, driven_y, -0.01]) b608(); // bottom bearing socket
//
// Hole for hot end
//
translate([filament_x, -15 + insulator_depth, filament_z])
rotate([90,0,0]) {
teardrop(h = 30, r = insulator / 2, center=true); // insulator
translate([0,0, -14.5])
teardrop(h = 1 , r = insulator / 2 + 1, center=true); // relief to avoid radius so end is flat
}
if(insulator_clamped(hot_end))
translate([filament_x - clamp_width / 2, -eta, filament_z])
cube([clamp_width, insulator_depth, 100]);
for(side = [-1, 1])
translate([filament_x + screw_pitch * side, screw_depth, -1])
cylinder(h = 30, r = (3.3 / 2), $fn = 9); // retaining screws
}
}
module wades_gear_spacer_stl() {
stl("wades_gear_spacer");
washer = M8_washer;
h = 5 * washer_thickness(washer);
difference() {
cylinder(r = washer_diameter(washer) / 2, h = h, center = false);
translate([0,0, -0.5])
poly_cylinder(r = M8_clearance_radius, h = h + 1, center = false);
}
}
bfbext=false;
*difference() {
wadeblock(bfbext);
*translate([-1,-1, filament_z])
cube([200,100,100]);
}
function extruder_connector_height() = motor_y - d_motor_bracket_offset(NEMA17);
module wades_big_gear_stl() {
stl("wades_big_gear");
color([0,1,0]) import("../imported_stls/39t17p.stl");
}
module wades_small_gear_stl() {
stl("wades_small_gear");
color([1,0,0])
translate([-10, -10, 0])
import("../imported_stls/wades_gear.stl");
}
module small_gear_assembly() {
wades_small_gear_stl();
rotate([90, 0, -24]) {
translate([0, 4, -5/2 - 6])
screw(M3_grub_screw, 6);
translate([0, 4, -6])
rotate([0,0,30])
nut(M3_nut);
}
}
idler_height = 12;
module wades_idler_block_stl() {
stl("wades_idler_block");
long_side = 37;
short_side = 25;
corners_diameter = 3;
608_dia = 12;
608_height = 9;
mounting_dia = 4.5;
difference(){
// Main block
rounded_rectangle([long_side, short_side, idler_height], corners_diameter, center = false);
// bearing cutout
translate([0, 0, idler_height - 2]){
rotate([90,0,0])
cylinder(h = 608_height, r=608_dia, center=true);
rotate(a=[90,0,0])
cylinder(h = short_side-2, r=8.6/2, center=true);
}
//mounting holes
for(x = pscrew_y)
for(y = pscrew_z)
translate([x - motor_y, y - filament_z, 0])
poly_cylinder(h = idler_height * 2.1, r = mounting_dia / 2, center=true);
}
}
module wade_idler_assembly() {
color([0,1,0]) render() wades_idler_block_stl();
translate([0, 0, idler_height - 2])
rotate([90, 0, 0]) {
rod(d = 8, l = 22);
ball_bearing(BB608);
}
}
module wades_assembly() {
assembly("wades_assembly");
render() wades_block_stl();
// idler screws, washers and springs
for(i = [0,1])
translate([pscrew_x, pscrew_y[i], pscrew_z[i]])
rotate([-90,0,90]) {
screw(M4_hex_screw, 50);
translate([0,0, -38]) {
translate([0,0, -6]) {
comp_spring(extruder_spring, 6);
translate([0,0, -washer_thickness(M4_washer)]) {
washer(M4_washer);
translate([0,0, -nut_thickness(M4_nut)])
nut(M4_nut);
}
}
}
}
// mounting screws
for(side = [-1, 1])
translate([filament_x + mount_pitch * side, base_thickness - 3, filament_z])
rotate([-90,0,0])
screw(M4_hex_screw, 20);
//idler
translate([98, motor_y, filament_z])
rotate([90, 0, -90])
wade_idler_assembly();
// motor and gear
translate([motor_x, motor_y, thickness + eta])
rotate([0,180,0]) {
NEMA(NEMA17);
translate([0,0, 3.5])
small_gear_assembly();
translate([0, 0, thickness])
rotate([0, 0, 90])
NEMA_screws(NEMA17, 3);
assembly("D_connector_assembly");
d_motor_bracket_assembly(NEMA17);
d_shell_assembly(NEMA17);
end("D_connector_assembly");
}
// hobbed bolt and gear
translate([driven_x, motor_y, 0]) {
translate([0, 0, width - BB608[2] / 2])
ball_bearing(BB608);
translate([0, 0, BB608[2] / 2])
ball_bearing(BB608);
rotate([180, 0, 0])
color([1,0,0]) render() wades_gear_spacer_stl();
translate([0, 0, -7.5])
rotate([180, 0, 0])
wades_big_gear_stl();
translate([0,0, -14])
rotate([180, 0, 0])
screw(M8_hex_screw, 60);
translate([0,0, width])
washer(M8_washer);
translate([0,0, width + washer_thickness(M8_washer)]) {
comp_spring(hob_spring, 8);
translate([0, 0, 8])
nut(M8_nut);
}
}
translate([75, 5 - nozzle_length / 4, 15])
rotate([-90, 0, 0]) {
color([0.6, 0.5, 0.2]) cylinder(h = nozzle_length / 2 + 10, r = insulator_diameter(hot_end) / 2, center = true);
translate([0, 0, -nozzle_length /2 - 5])
color([1, 1, 0]) cylinder(h = nozzle_length / 2, r = 3, center = true);
}
for(side = [-1, 1])
translate([filament_x + insulator_screw_pitch(hot_end) * side, screw_depth, width])
screw(M3_cap_screw, 30);
end("wades_assembly");
}
if(1)
rotate([90, 0, 0])
wades_assembly();
else {
wades_block_stl();
*wades_idler_block_stl();
*wades_gear_spacer_stl();
}

458
scad/x-carriage.scad Normal file
View File

@ -0,0 +1,458 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// X carriage, carries the extruder
//
include <conf/config.scad>
use <bearing-holder.scad>
use <wade.scad>
hole = 36;
width = hole + 2 * bearing_holder_width(X_bearings);
length = 97;
top_thickness = 3;
rim_thickness = 8;
nut_trap_thickness = 8;
corner_radius = 5;
wall = 2.8;
base_offset = nozzle_x_offset; // offset of base from centre
bar_offset = ceil(max(X_bearings[2] / 2 + rim_thickness + 1, // offset of carriage origin from bar centres
nut_radius(M3_nut) * 2 + belt_thickness(X_belt) + pulley_inner_radius + 6 * layer_height));
echo(bar_offset);
mounting_holes = [90, 270];
function x_carriage_offset() = bar_offset;
function x_bar_spacing() = hole + bearing_holder_width(X_bearings);
function x_carriage_width() = width;
function x_carriage_length() = length;
function x_carriage_thickness() = rim_thickness;
bar_y = x_bar_spacing() / 2;
bar_x = (length - bearing_holder_length(X_bearings)) / 2;
tooth_height = belt_thickness(X_belt) / 2;
tooth_width = belt_pitch(X_belt) / 2;
lug_width = 2.5 * belt_pitch(X_belt);
lug_depth = X_carriage_clearance + belt_width(X_belt) + belt_clearance + M3_clearance_radius + lug_width / 2;
lug_screw = -(X_carriage_clearance + belt_width(X_belt) + belt_clearance + M3_clearance_radius);
slot_y = -X_carriage_clearance - (belt_width(X_belt) + belt_clearance) / 2;
function x_carriage_belt_gap() = length - 2 * lug_width;
clamp_thickness = 3;
dowel = 5;
dowel_height = 2;
module belt_lug(motor_end) {
height = motor_end ? x_carriage_offset() - pulley_inner_radius:
x_carriage_offset() - ball_bearing_diameter(X_idler_bearing) / 2;
height2 = motor_end ? height + clamp_thickness : height;
width = lug_width;
depth = lug_depth;
extra = 0.5; // extra belt clearance
union() {
difference() {
union() {
translate([width / 2, -depth + width / 2])
cylinder(r = width / 2, h = height2 + (motor_end ? M3_nut_trap_depth : 0));
translate([0, -(depth - width / 2)])
cube([width, depth - width / 2, height2]);
}
translate([width / 2, slot_y, height - belt_thickness(X_belt) / 2 + 2 * eta]) // slot for belt
cube([width + 1, belt_width(X_belt) + belt_clearance, belt_thickness(X_belt)], center = true);
translate([width / 2, lug_screw, height2 + M3_nut_trap_depth + eta])
nut_trap(M3_clearance_radius, M3_nut_radius, M3_nut_trap_depth);
// slot to join screw hole
translate([width / 2, -(X_carriage_clearance + belt_width(X_belt) + belt_clearance),
height - belt_thickness(X_belt) / 2 + extra /2])
cube([M3_clearance_radius * 2, M3_clearance_radius * 2, belt_thickness(X_belt) + extra], center = true);
if(motor_end) {
translate([width, slot_y, (height - belt_thickness(X_belt)) / 2]) // tensioning screw
rotate([90, 0, 90])
nut_trap(M3_clearance_radius, M3_nut_radius, M3_nut_trap_depth, true);
translate([width / 2, slot_y, height - (belt_thickness(X_belt) - extra) / 2 - eta]) // clearance slot for belt
cube([width + 1, belt_width(X_belt) + extra, belt_thickness(X_belt) + extra], center = true);
}
}
//
// fillets
//
*translate([width, 0, height / 2])
rotate([0, 0, -90])
fillet(r = X_carriage_clearance, h = height);
if(motor_end)
//
// support membrane
//
translate([width / 2, lug_screw, height + extra + layer_height / 2 - eta])
cylinder(r = M3_clearance_radius + 1, h = layer_height, center = true);
else
for(i = [-1:1]) // teeth to grip belt
translate([width / 2 + i * belt_pitch(X_belt), slot_y, height- belt_thickness(X_belt) + tooth_height / 2 - eta ])
cube([tooth_width, belt_width(X_belt) + belt_clearance + eta, tooth_height], center = true);
}
}
module belt_loop() {
d = x_carriage_offset() - pulley_inner_radius - belt_thickness(X_belt);
height = d + 2 * belt_thickness(X_belt);
length = lug_width + 12.5;
translate([d / 2, 0, 0])
linear_extrude(height = belt_width(X_belt), convexity = 5, center = true)
difference() {
union() {
circle(r = height / 2, center = true);
translate([0, -height / 2])
square([length, height]);
}
union() {
circle(r = d / 2, center = true);
translate([0, -d / 2])
square([length, d]);
}
translate([length - 12.5, -height])
square([100, height]);
}
}
function x_belt_loop_length() = PI * (x_carriage_offset() - pulley_inner_radius - belt_thickness(X_belt) / 2) / 2 + lug_width + 15;
module x_belt_clamp_stl()
{
height = clamp_thickness;
width = lug_width;
depth = lug_depth;
stl("x_belt_clamp");
union() {
difference() {
union() {
translate([width / 2, -depth + width / 2])
cylinder(r = width / 2, h = height + M3_nut_trap_depth);
translate([0, -(depth - width / 2)])
cube([width, depth - width / 2, height]);
}
translate([width / 2, lug_screw, height + M3_nut_trap_depth])
nut_trap(M3_clearance_radius, M3_nut_radius, M3_nut_trap_depth);
}
}
}
module x_belt_grip_stl()
{
height = clamp_thickness + belt_thickness(X_belt);
width = lug_width;
depth = lug_depth;
stl("x_belt_grip");
union() {
difference() {
linear_extrude(height = height, convexity = 5)
hull() {
translate([width / 2, -depth + width / 2])
circle(r = width / 2);
translate([0, -(depth - width / 2 - dowel)])
square([width, depth - width / 2]);
}
translate([width / 2, lug_screw, -1])
poly_cylinder(r = M3_clearance_radius, h = height + 2); // clamp screw hole
translate([width / 2, -(X_carriage_clearance + belt_width(X_belt) + belt_clearance), height]) // slot to join screw hole
cube([M3_clearance_radius * 2, M3_clearance_radius * 2, 2 * belt_thickness(X_belt)], center = true);
translate([width / 2, slot_y, height - belt_thickness(X_belt) / 2 + 2 * eta]) // slot for belt
cube([width + 1, belt_width(X_belt) + belt_clearance, belt_thickness(X_belt)], center = true);
}
translate([width / 2, dowel / 2, eta])
cylinder(r = dowel / 2 - 0.1, h = height + dowel_height);
for(i = [-1:1]) // teeth
translate([width / 2 + i * belt_pitch(X_belt), slot_y, height - belt_thickness(X_belt) + tooth_height / 2 - eta ])
cube([tooth_width, belt_width(X_belt) + belt_clearance + eta, tooth_height], center = true);
}
}
belt_tensioner_rim = X_carriage_clearance;
belt_tensioner_height = belt_tensioner_rim + belt_width(X_belt) + belt_clearance + belt_tensioner_rim;
module x_belt_tensioner_stl()
{
stl("x_belt_tensioner");
flat = 1;
d = x_carriage_offset() - pulley_inner_radius - belt_thickness(X_belt);
module d(r, w) {
difference() {
union() {
circle(r, center = true);
translate([0, -r])
square([w + 1, 2 * r]);
}
translate([w, - 50])
square([100, 100]);
}
}
difference() {
translate([d / 2, 0, 0]) union() {
linear_extrude(height = belt_tensioner_height)
d(d / 2, flat);
linear_extrude(height = belt_tensioner_rim)
d(d / 2 + 2, flat);
}
translate([wall, 0, belt_tensioner_height / 2])
rotate([90, 0, 90])
teardrop(r = M3_clearance_radius, h = 100);
}
}
bearing_gap = 5;
bearing_slit = 1;
hole_width = hole - wall - bearing_slit;
hole_offset = (hole - hole_width) / 2;
module base_shape() {
difference() {
hull() {
translate([-length / 2, -width / 2])
square();
translate([ length / 2 - 1, -width / 2])
square();
translate([bearing_holder_length(X_bearings) / 2 + bearing_gap, width / 2 - corner_radius])
circle(r = corner_radius, center = true);
translate([-bearing_holder_length(X_bearings) / 2 - bearing_gap, width / 2 - corner_radius])
circle(r = corner_radius, center = true);
translate([-length / 2 + corner_radius, extruder_width / 2 ])
circle(r = corner_radius, center = true);
translate([ length / 2 - corner_radius , extruder_width / 2])
circle(r = corner_radius, center = true);
}
translate([0, width / 2 - (bearing_holder_width(X_bearings) + bearing_slit) / 2 + eta])
square([bearing_holder_length(X_bearings) + 2 * bearing_gap,
bearing_holder_width(X_bearings) + bearing_slit ], center = true);
}
}
module inner_base_shape() {
difference() {
square([length - 2 * wall, width - 2 * wall], center = true);
minkowski() {
difference() {
square([length + 1, width + 1], center = true);
translate([10,0])
square([length + 1, 2 * wall + eta], center = true);
base_shape();
}
circle(r = wall, center = true);
}
}
}
module x_carriage_stl(){
stl("x_carriage");
translate([base_offset, 0, top_thickness])
difference(){
union(){
translate([0, 0, rim_thickness / 2 - top_thickness]) {
difference() {
union() {
// base plate
difference() {
linear_extrude(height = rim_thickness, center = true, convexity = 5)
base_shape();
translate([0, 0, top_thickness])
linear_extrude(height = rim_thickness, center = true, convexity = 5)
difference() {
inner_base_shape();
translate([-base_offset, -hole_offset])
rounded_square(hole + 2 * wall, hole_width + 2 * wall, corner_radius + wall);
}
}
// ribs
for(end = [-1,1])
linear_extrude(height = rim_thickness, center = true, convexity = 5)
hull() {
translate([0, bar_y - bearing_holder_width(X_bearings) / 2 - bearing_slit- wall])
circle(r = wall, center = true);
translate([end * bar_x, -bar_y + bearing_holder_width(X_bearings) / 2])
circle(r = wall, center = true);
}
}
//Holes for bearing holders
translate([0, bar_y, rim_thickness - top_thickness - eta])
cube([bearing_holder_length(X_bearings) - 2 * eta, bearing_holder_width(X_bearings) - 2 * eta, rim_thickness * 2], center = true);
translate([- bar_x, -bar_y, rim_thickness - top_thickness - eta])
cube([bearing_holder_length(X_bearings) - 2 * eta, bearing_holder_width(X_bearings) - 2 * eta, rim_thickness * 2], center = true);
translate([+ bar_x, -bar_y, rim_thickness - top_thickness - eta])
cube([bearing_holder_length(X_bearings) - 2 * eta, bearing_holder_width(X_bearings) - 2 * eta, rim_thickness * 2], center = true);
}
}
//
// Floating bearing springs
//
for(side = [-1, 1])
translate([0, bar_y + side * (bearing_holder_width(X_bearings) - min_wall - eta) / 2, rim_thickness / 2 - top_thickness])
cube([bearing_holder_length(X_bearings) + 2 * bearing_gap + 1, min_wall, rim_thickness], center = true);
// raised section for nut traps
for(a = mounting_holes)
translate([25 * sin(a) - base_offset, 25 * cos(a), (nut_trap_thickness - top_thickness) / 2])
cylinder(r = 7, h = nut_trap_thickness - top_thickness, center = true);
// belt lugs
translate([-length / 2, -width / 2 + eta, -top_thickness])
belt_lug(true);
translate([ length / 2, -width / 2 + eta, -top_thickness])
mirror([1,0,0])
belt_lug(false);
//Bearing holders
translate([0, bar_y, bar_offset - top_thickness]) rotate([0,0,90]) bearing_holder(X_bearings, bar_offset - eta);
translate([- bar_x, -bar_y, bar_offset - top_thickness]) rotate([0,0,90]) bearing_holder(X_bearings, bar_offset - eta);
translate([+ bar_x, -bar_y, bar_offset - top_thickness]) rotate([0,0,90]) bearing_holder(X_bearings, bar_offset - eta);
}
translate([-base_offset, 0, 0]) {
// hole to clear the hot end
translate([0, - hole_offset])
rounded_rectangle([hole, hole_width, 2 * rim_thickness], corner_radius);
// holes for connecting extruder
for(a = mounting_holes)
translate([25 * sin(a), 25 * cos(a), nut_trap_thickness - top_thickness]) {
*cylinder(h = nut_trap_thickness, r = 7);
rotate([0,0,-a])
//nut_trap(M4_clearance_radius, M4_nut_radius, M4_nut_trap_depth);
poly_cylinder(r = M4_clearance_radius, h = 50, center = true);
}
}
//
// Belt grip dowel hole
//
translate([-length / 2 + lug_width / 2, -width / 2 + dowel / 2, -top_thickness])
cylinder(r = dowel / 2 + 0.1, h = dowel_height * 2, center = true);
}
}
module x_carriage_assembly(show_extruder = false) {
assembly("x_carriage_assembly");
color([1,0,0]) render() x_carriage_stl();
if(show_extruder)
translate([75, 15, eta])
rotate([-90,0,180])
wades_assembly(false, true);
for(end = [-1, 1])
translate([25 * end, 0, nut_trap_thickness])
rotate([0,0, 45])
wingnut(M4_wingnut);
translate([base_offset, bar_y, bar_offset]) {
linear_bearing(X_bearings);
rotate([0,-90,0])
ziptie(small_ziptie, bearing_ziptie_radius(X_bearings));
}
for(end = [-1,1])
translate([base_offset + bar_x * end, -bar_y, bar_offset]) {
linear_bearing(X_bearings);
rotate([90,-90,90])
ziptie(small_ziptie, bearing_ziptie_radius(X_bearings));
}
//
// Idler end belt clamp
//
translate([length / 2 + base_offset, -width / 2, x_carriage_offset() - ball_bearing_diameter(X_idler_bearing) / 2]) {
mirror([1,0,0])
color([0,1,0]) render() x_belt_clamp_stl();
translate([-lug_width / 2, lug_screw, clamp_thickness])
nut(M3_nut, true);
}
translate([length / 2 + base_offset - lug_width / 2, -width / 2 + lug_screw, 0])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, 20);
//
// Motor end belt clamp
//
translate([-length / 2 + base_offset, -width / 2, x_carriage_offset() - pulley_inner_radius])
translate([lug_width / 2, lug_screw, clamp_thickness])
nut(M3_nut, true);
translate([-length / 2 + base_offset, -width / 2, -(clamp_thickness + belt_thickness(X_belt))]) {
color([0,1,0]) render() x_belt_grip_stl();
translate([lug_width / 2, lug_screw, 0])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, 25);
}
translate([-length / 2 + base_offset - 7, -width / 2 + slot_y, (x_carriage_offset() - pulley_inner_radius - belt_thickness(X_belt)) /2]) {
rotate([0, -90, 0])
screw(M3_cap_screw, 25); // tensioning screw
translate([25 + wall, belt_tensioner_height / 2, 0])
rotate([90, 180, 0])
color([0,1,0]) render() x_belt_tensioner_stl();
translate([25 + wall, 0, 0])
rotate([90, 180, 0])
belt_loop();
}
translate([-length / 2 + base_offset + lug_width - M3_nut_trap_depth, -width / 2 + slot_y, (x_carriage_offset() - pulley_inner_radius - belt_thickness(X_belt)) /2])
rotate([90, 0, 90])
nut(M3_nut, false); // tensioning nut
end("x_carriage_assembly");
}
if(0) {
x_belt_clamp_stl();
translate([-(lug_width + 2),0,0]) x_belt_grip_stl();
x_carriage_stl();
translate([6, 8, 0]) rotate([0, 0, -90]) x_belt_tensioner_stl();
}
else
x_carriage_assembly(true);
//belt_lug(false);

551
scad/x-end.scad Normal file
View File

@ -0,0 +1,551 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Ends of the X axis
//
include <conf/config.scad>
use <x-carriage.scad>
use <pulley.scad>
use <ribbon_clamp.scad>
use <wade.scad>
bwall = 2.3;
bearing_dia = Z_bearings[1] + 0.2;
bearing_width = bearing_dia + 2 * bwall;
bearing_depth = bearing_width / 2 + 1;
bearing_length = Z_bearings[0];
bearing_height = min(65, 2.8 * bearing_length);
shelf_thickness = 2;
shelf_clearance = 0.5;
shelves = [ shelf_thickness / 2,
shelf_thickness + bearing_length + shelf_clearance + shelf_thickness / 2,
bearing_height - shelf_thickness / 2,
bearing_height - (shelf_thickness + bearing_length + shelf_clearance + shelf_thickness / 2) ];
actuator_width = 4;
actuator_depth = 3;
actuator_height = 10;
module z_linear_bearings(motor_end) {
rod_dia = Z_bearings[2];
opening = 2 * bearing_dia / 15.4;
shelf_depth = bearing_depth - (rod_dia / 2 + 1);
union() {
difference(){
union(){
//main vertical block
translate([-bearing_depth / 2, 0, bearing_height / 2])
cube([bearing_depth, bearing_width, bearing_height], center = true);
cylinder(h = bearing_height, r = bearing_width / 2);
if(!motor_end)
*translate([-bearing_depth + eta, 0, bearing_height - eta])
rotate([-90, 0, 0])
right_triangle(width = -actuator_depth, height = actuator_height, h = actuator_width, center = true);
}
//hole for bearings
translate([0, 0, -1])
cylinder(h = bearing_height + 2, r = bearing_dia / 2);
//entry cut out
translate([10 * sqrt(2) - opening, 0, bearing_height / 2])
rotate([0, 0, 45])
cube([20, 20, bearing_height + 1], center = true);
}
//
// shelves
//
for(y = shelves)
translate([-bearing_depth + shelf_depth / 2 + eta, 0, y])
cube([shelf_depth, bearing_width, shelf_thickness], center = true);
}
}
//z_linear_bearings();
wall = thick_wall; // 4mm on Mendel and Sturdy, 3mm on Huxley
width = x_bar_spacing();
back = -ceil(z_bar_offset() + Z_nut_radius + wall);
front = -(Z_bar_dia / 2 + 1);
length = front - back;
thickness = X_bar_dia + 2 * wall;
clamp_wall = default_wall; // 4mm on Sturdy, 3mm on Mendel and Huxley
nut_flat_radius = nut_radius * cos(30);
clamp_width = 2 * (nut_radius + clamp_wall);
clamp_height = washer_diameter(washer) / 2 + nut_flat_radius + clamp_wall;
clamp_depth = wall + nut_trap_depth;
clamp_thickness = 5;
slit = 1;
bar_y = x_bar_spacing() / 2;
belt_edge = -x_carriage_width() / 2 - X_carriage_clearance;
idler_front = belt_edge - belt_width(X_belt) / 2 + ball_bearing_width(BB624) / 2 + washer_thickness(M4_washer) + washer_thickness(M5_penny_washer);
idler_screw_length = 40;
idler_depth = idler_screw_length - ball_bearing_width(BB624) - 2 * (washer_thickness(M4_washer) + washer_thickness(M5_penny_washer)) - 1;
idler_back = idler_front + idler_depth;
idler_width = ceil(2 * (M4_nut_radius + wall));
mbracket_thickness = 4;
motor_angle = 45;
motor_w = ceil(min(max(sin(motor_angle) + cos(motor_angle)) * NEMA_width(X_motor), NEMA_radius(X_motor) * 2) + 1);
mbracket_width = motor_w + 2 * mbracket_thickness;
mbracket_height = thickness / 2 + NEMA_radius(X_motor) + mbracket_thickness;
mbracket_front = belt_edge + 14;
mbracket_depth = NEMA_length(X_motor) + 2 * mbracket_thickness + 1;
mbracket_centre = mbracket_front + mbracket_depth / 2 - mbracket_thickness;
switch_op_x = Z_bearings[1] / 2 + 2; // switch operates 2mm before carriage hits the bearing
switch_op_z = x_carriage_offset() - x_carriage_thickness() / 2; // hit the edge of the carriage
sbracket_top = switch_op_z + 12;
sbracket_height = sbracket_top + thickness / 2;
sbracket_depth = switch_op_x - 3 - front;
sbracket_thickness = bar_y - (X_bar_dia / 2) * sin(45) - bearing_width / 2 - 1.5 - microswitch_thickness();
sbracket_y = -bearing_width / 2 - 1 - sbracket_thickness / 2;
function x_motor_offset() = back - mbracket_thickness - motor_w / 2;
function x_motor_overhang() = back - mbracket_width;
function x_idler_offset() = back - idler_width / 2;
function x_idler_overhang() = x_idler_offset() - washer_diameter(M5_penny_washer) / 2;
function x_end_bar_length() = -back;
function x_end_height() = bearing_height - thickness / 2;
function x_end_thickness() = thickness;
ribbon_screw = M3_cap_screw;
ribbon_nut = screw_nut(ribbon_screw);
ribbon_nut_trap_depth = nut_trap_depth(ribbon_nut);
ribbon_pillar_depth = 12;
ribbon_pillar_thickness = wall + ribbon_nut_trap_depth;
ribbon_clamp_x = back - ribbon_pillar_depth;
ribbon_clamp_y = mbracket_front + washer_diameter(screw_washer(ribbon_screw)) / 2 + 2;
//ribbon_clamp_z = x_carriage_offset() + extruder_connector_height();
ribbon_clamp_z = mbracket_height + ribbon_clamp_length(extruder_ways, ribbon_screw) / 2 - thickness / 2 + 0.5;
ribbon_pillar_width = nut_radius(ribbon_nut) * 2 + 2 * wall + 0.5;
ribbon_pillar_top = ribbon_clamp_z + ribbon_clamp_length(extruder_ways, ribbon_screw) / 2;
function anti_backlash_height() = 24 + thickness / 2;
anti_backlash_radius = Z_nut_radius + 0.2;
anti_backlash_wall = 3;
function x_end_ribbon_clamp_y() = mbracket_front + mbracket_depth - mbracket_thickness;
function x_end_ribbon_clamp_z() = mbracket_height - thickness / 2 - mbracket_thickness - nut_radius(ribbon_nut);
function x_end_extruder_ribbon_clamp_offset() = [-ribbon_clamp_x, ribbon_clamp_y + ribbon_clamp_width(ribbon_screw) / 2, ribbon_clamp_z];
module x_end_bracket(motor_end, assembly = false){
if(motor_end)
stl("x_motor_bracket");
else
stl("x_idler_bracket");
union(){
translate([0, 0, - thickness / 2])
z_linear_bearings(motor_end);
difference(){
union(){
// base
translate([front - length / 2, 0, 0])
cube([length, width, thickness], center = true);
//
// Anti-backlash nut holder
//
translate([-z_bar_offset(), 0, thickness / 2 - eta])
cylinder(r = anti_backlash_radius + anti_backlash_wall, h = anti_backlash_height() - thickness / 2, $fn = 6);
//
// Webs from bearing holder
//
for(side = [-1, 1])
if(motor_end)
translate([back - eta, (bearing_width - wall - eta) / 2 * side, thickness / 2 - eta])
rotate([90, 0, 0])
linear_extrude(height = wall, center = true)
polygon(points = [
[0, 0],
[-back - bearing_depth + 2 * eta, 0],
[-back - bearing_depth + 2 * eta, bearing_height - thickness],
[0, mbracket_height - thickness]
],
sides = [0, 1, 2, 3]
);
else
translate([-bearing_depth + eta, (bearing_width - wall - eta) / 2 * side, thickness / 2 - eta])
rotate([90, 0, 0])
right_triangle(width = back + bearing_depth, height = bearing_height - thickness, h = wall);
for(side = [-1, 1]) {
//
// Bar holders
//
union() {
translate([front - length / 2, bar_y * side, 0]) {
rotate([90, 0, 90])
teardrop(r = thickness / 2, h = length, center = true);
rotate([-90, 0, 90])
teardrop(r = thickness / 2, h = length, center = true);
rotate([90, 0, 90 * side])
linear_extrude(height = length - 4 * eta, center = true)
hull() {
translate([slit / 2 + eta, thickness / 2 - 1])
square([clamp_thickness - 2 * eta, 0.5]);
circle(r = thickness / 2 - eta);
}
}
}
//
// Bar clamps
//
difference() {
group() {
translate([front - length / 2, side * (bar_y - clamp_depth / 2 - slit / 2), thickness / 2 + clamp_height / 2 -eta])
cube([clamp_width, clamp_depth, clamp_height], center = true);
translate([front - length / 2, side * (bar_y + clamp_thickness / 2 + slit / 2) -eta, thickness / 2])
rotate([90, 0, 0])
linear_extrude(height = clamp_thickness, center = true)
polygon(points = [
[-length / 2 + eta, 0],
[-length / 2 + eta, -thickness / 2],
[ length / 2 - eta, -thickness / 2],
[ length / 2 - eta, 0],
[ clamp_width / 2, clamp_height],
[-clamp_width / 2, clamp_height],
]);
}
//
// Bar clamp nut traps
//
translate([front - length / 2, side * (bar_y - clamp_depth - slit / 2), thickness / 2 + washer_diameter(washer) / 2])
rotate([90,0,0])
nut_trap(screw_clearance_radius, nut_radius, nut_trap_depth, true);
}
}
}
//
// Cut out for bearing holder
//
cube([bearing_depth * 2 -eta, bearing_width - eta, thickness + 10], center = true);
//
// Hole for z leadscrew
//
translate([-z_bar_offset(), 0, -thickness / 2])
nut_trap((Z_screw_dia + 1) / 2, Z_nut_radius, Z_nut_depth);
translate([-z_bar_offset(), 0, thickness / 2 + eta])
cylinder(r = anti_backlash_radius, h = bearing_height, $fn = 6);
for(side = [-1, 1]) {
//
// Holes for x_bars
//
translate([front - length / 2, bar_y * side, 0]) {
translate([0, 0, thickness / 2])
cube([length + 1, slit, thickness + 1], center = true);
rotate([90, 0, 90])
teardrop_plus(r = X_bar_dia / 2, h = length + 1, center = true, truncate = false);
}
}
//
// cut out for bottom microswitch contact
//
if(motor_end)
translate([switch_op_x,
sbracket_y - sbracket_thickness / 2 - microswitch_thickness() / 2,
switch_op_z])
rotate([0, -90, -90])
microswitch_contact_space();
}
//
// support membrane
//
translate([-z_bar_offset(), 0, Z_nut_depth + layer_height / 2 - thickness / 2 + eta])
cylinder(r = (Z_screw_dia + 2) /2, h = layer_height, center = true);
if(motor_end) {
difference() {
//
// Bracket
//
union() {
translate([back - mbracket_width / 2 + eta, mbracket_centre, mbracket_height / 2 - thickness / 2]) {
difference() {
cube([mbracket_width, mbracket_depth, mbracket_height], center = true); // outside
translate([0, 0, -mbracket_thickness])
cube([mbracket_width - 2 * mbracket_thickness, // inside
mbracket_depth - 2 * mbracket_thickness, mbracket_height], center = true);
translate([0, 0, (mbracket_height - mbracket_thickness) / 2 + layer_height])
cube([mbracket_width - 30, mbracket_depth - 30, assembly ? 10: mbracket_thickness], center = true); // open top
}
//
// Fillet to anchor the end wall to the bed while being printed
//
translate([-mbracket_width / 2 + mbracket_thickness - eta, 0, -mbracket_height / 2])
rotate([90, 0, 0])
right_triangle(width = 4, height = 4, h = mbracket_depth - eta, center = true);
}
//
// ribbon clamp pillar
//
translate([ribbon_clamp_x,
ribbon_clamp_y,
mbracket_height + (ribbon_pillar_top - mbracket_height - thickness / 2) / 2 - eta])
{
translate([ribbon_pillar_thickness / 2, 0, 0])
cube([ribbon_pillar_thickness,
ribbon_pillar_width,
ribbon_pillar_top - mbracket_height + thickness / 2], center = true);
for(side = [-1, 1])
translate([ribbon_pillar_thickness - eta, side * (ribbon_pillar_width - wall) / 2,
-(ribbon_pillar_top - mbracket_height + thickness / 2) / 2 - eta])
rotate([90,0,0])
right_triangle(width = ribbon_pillar_depth - ribbon_pillar_thickness,
height = ribbon_pillar_top - mbracket_height + thickness / 2,
h = wall);
}
//
// Ribbon clamp nut traps
//
translate([x_motor_offset(), mbracket_front + mbracket_depth - 2 * mbracket_thickness + eta, x_end_ribbon_clamp_z()])
rotate([90, 180, 0])
ribbon_clamp_holes(x_end_ways, ribbon_screw)
difference() {
teardrop(r = nut_radius(ribbon_nut) + 2, h = ribbon_nut_trap_depth, truncate = false);
translate([0, (nut_radius(ribbon_nut) + 2) * sqrt(2), ribbon_nut_trap_depth + eta])
rotate([0, 90, 180])
right_triangle(width = ribbon_nut_trap_depth, height = ribbon_nut_trap_depth, h = 20);
}
}
//
// Slits to leave clamp free
//
for(side = [-1,1]) // both sides in case motor longer than bracket
translate([back - slit / 2 + eta * 2, side * (-bar_y - thickness / 2 + slit / 2), 0])
difference() {
cube([slit, thickness, thickness + 2], center = true);
translate([-1, 0, thickness / 2 + 1])
rotate([0, 45, 0])
cube([2, thickness + 1, 2], center = true);
}
//
// Holes
//
translate([x_motor_offset(), mbracket_front, 0]) {
//
// big hole for motor boss
//
translate([0, 0, -50/2])
rotate([90,0,0])
vertical_tearslot(r = NEMA_big_hole(X_motor), h = 2 * mbracket_thickness + 1, l = 50, center = true);
//
// small hole for second shaft
//
translate([0, mbracket_depth - mbracket_thickness, -50/2])
rotate([90,0,0])
vertical_tearslot(r = 4, h = 2 * mbracket_thickness + 1, l = 50, center = true);
//
// Mounting holes
//
for(x = NEMA_holes(X_motor)) // motor screw holes
for(z = NEMA_holes(X_motor))
rotate([0, motor_angle, 0])
translate([x,0,z])
rotate([90, -motor_angle, 0]) {
teardrop_plus(r = M3_clearance_radius, h = 2 * mbracket_thickness + 1, center = true);
translate([0, 0, mbracket_thickness])
teardrop_plus(r = (washer_diameter(M3_washer) + 1) / 2, h = 2 * (mbracket_thickness - 3.999), center = true);
}
}
//
// ribbon clamp holes
//
translate([x_motor_offset(),
mbracket_front + mbracket_depth - 2 * mbracket_thickness - ribbon_nut_trap_depth,
mbracket_height - thickness / 2 - mbracket_thickness - nut_radius(ribbon_nut)])
rotate([90, 0, 0])
ribbon_clamp_holes(x_end_ways, ribbon_screw)
difference() {
nut_trap(screw_clearance_radius(ribbon_screw), nut_radius(ribbon_nut), ribbon_nut_trap_depth, true);
translate([0,0, 10])
cylinder(r = 10, h =100);
}
translate([ribbon_clamp_x + ribbon_pillar_thickness, ribbon_clamp_y, ribbon_clamp_z])
rotate([-90,90,90])
ribbon_clamp_holes(extruder_ways, ribbon_screw)
rotate([0, 0, 90])
nut_trap(screw_clearance_radius(ribbon_screw), nut_radius(ribbon_nut), ribbon_nut_trap_depth, true);
//
// Hole for switch wires
//
translate([back, -bearing_width / 2 - 3, thickness / 2 + 10])
rotate([90, 0, 90])
teardrop(r = 3, h = 2 * mbracket_thickness + 1, center = true);
}
//
// limit switch bracket
//
difference() {
translate([front - eta, sbracket_y, - thickness / 2])
rotate([90, 0, 0])
linear_extrude(height = sbracket_thickness, center = true)
polygon([
[0, 0],
[sbracket_depth, sbracket_height - microswitch_length() + 2],
[sbracket_depth, sbracket_height],
[sbracket_depth - 10, sbracket_height],
//[-length / 2 + clamp_width / 2 - eta, thickness + clamp_height],
[-length / 2 + clamp_width / 2 - eta, thickness - eta]
]);
translate([switch_op_x, sbracket_y + sbracket_thickness / 2 + microswitch_thickness() / 2, switch_op_z])
rotate([0, -90, -90])
microswitch_holes(h = sbracket_thickness);
}
}
else {
//
// idler end
//
difference() {
union() {
translate([back - idler_width / 2 + eta - slit / 2, idler_back - idler_depth / 2, 0])
rounded_rectangle([idler_width - slit, idler_depth, thickness], r = 2, center = true);
translate([back - 5, idler_back - (idler_back + bar_y - slit / 2) / 2, 0])
cube([10, idler_back + bar_y - slit / 2, thickness], center = true);
translate([back, idler_back, 0])
rotate([0, 0, 90])
fillet(h = thickness, r = idler_width / 2);
}
translate([back - idler_width / 2, -bar_y, 0])
rotate([90, 0, 90])
teardrop(r = X_bar_dia / 2 + 0.5, h = idler_width + 1, center = true);
translate([x_idler_offset(), idler_back, 0])
rotate([90, 0, 0])
nut_trap(M4_clearance_radius, M4_nut_radius, M4_nut_trap_depth);
}
}
}
}
module x_end_assembly(motor_end) {
if(motor_end)
assembly("x_motor_assembly");
else
assembly("x_idler_assembly");
//
// RP bit
//
color([0,1,0]) render() x_end_bracket(motor_end, true);
//
// bearings
//
for(i = [0,2])
translate([0, 0, (shelves[i] + shelves[i+1])/2 - thickness / 2])
rotate([0,90,0])
linear_bearing(Z_bearings);
//
// lead nut
//
translate([-z_bar_offset(), 0 , -thickness / 2 + Z_nut_depth])
rotate([180, 0, 0])
nut(Z_nut);
//
// bearing clamp fasteners
//
for(side = [-1, 1]) {
translate([front - length / 2, side * (bar_y + clamp_thickness + slit / 2), thickness / 2 + washer_diameter(washer) / 2])
rotate([-90 * side,0,0])
screw_and_washer(hex_screw, 16);
translate([front - length / 2, side * (bar_y - clamp_depth - slit / 2 + nut_trap_depth), thickness / 2 + washer_diameter(washer) / 2])
rotate([90 * side,0,0])
nut(nut, true);
}
if(motor_end) {
translate([x_motor_offset(), mbracket_front + eta, 0]) {
rotate([90, motor_angle, 0]) {
NEMA(X_motor);
translate([0,0, mbracket_thickness])
NEMA_screws(X_motor, 3);
translate([0, 0, 4])
pulley_assembly();
}
}
translate([switch_op_x, sbracket_y - sbracket_thickness / 2 - microswitch_thickness() / 2, switch_op_z])
rotate([0, -90, -90]) {
microswitch();
microswitch_hole_positions()
translate([0,0, -(microswitch_thickness())])
rotate([180,0,0])
screw_and_washer(No2_screw, 13);
}
//
// ribbon clamps
//
translate([x_motor_offset(), x_end_ribbon_clamp_y(), x_end_ribbon_clamp_z()])
rotate([-90, 0, 0])
ribbon_clamp_assembly(x_end_ways, M3_hex_screw, 16, mbracket_thickness);
translate([ribbon_clamp_x, ribbon_clamp_y, ribbon_clamp_z])
rotate([-90, 90, 90])
ribbon_clamp_assembly(extruder_ways, ribbon_screw, 16, wall, true);
}
else {
translate([x_idler_offset(), belt_edge - belt_width(X_belt) / 2, 0]) {
rotate([90,0,0 ])
ball_bearing(BB624);
for(i = [-1, 1]) {
translate([0, (ball_bearing_width(X_idler_bearing) / 2) * i, 0])
rotate([-i * 90, 0, 0])
washer(M4_washer);
translate([0, (ball_bearing_width(X_idler_bearing) / 2 + washer_thickness(M4_washer)) * i, 0])
rotate([-i * 90, 0, 0])
washer(M5_penny_washer);
}
translate([0,-ball_bearing_width(X_idler_bearing) / 2 - washer_thickness(M4_washer) - washer_thickness(M5_penny_washer),0])
rotate([90,0,0])
screw(M4_cap_screw, idler_screw_length);
}
translate([x_idler_offset(), idler_back - M4_nut_trap_depth, 0])
rotate([-90, 0, 0])
nut(M4_nut, true);
}
if(motor_end)
end("x_motor_assembly");
else
end("x_idler_assembly");
}
module x_motor_bracket_stl() translate([0, 0, thickness / 2]) mirror ([1,0,0]) x_end_bracket(true);
module x_idler_bracket_stl() translate([0, 0, thickness / 2]) x_end_bracket(false);
//x_end_bracket(false);
//x_end_assembly(false);
//mirror ([1,0,0]) x_end_bracket(true);
mirror ([1,0,0]) x_end_assembly(true);

103
scad/y-bearing-mount.scad Normal file
View File

@ -0,0 +1,103 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// For the y carriage
//
include <conf/config.scad>
include <positions.scad>
use <bearing-holder.scad>
use <bar-clamp.scad>
slot = 2;
tab_length = bearing_clamp_tab + slot;
function bearing_mount_width(bearing) = bearing_holder_width(bearing) + 2 * tab_length;
function bearing_mount_length(bearing) = bearing_holder_length(bearing);
module tab() {
linear_extrude(height = bearing_clamp_tab_height, center = false, convexity = 6)
difference() {
union() {
translate([(bearing_clamp_tab / 2 + slot) / 2, 0])
square([bearing_clamp_tab / 2 + slot, bearing_clamp_tab], center = true);
translate([bearing_clamp_tab / 2 + slot ,0])
circle(r = bearing_clamp_tab/ 2, center = true);
}
translate([bearing_clamp_tab / 2, 0])
circle(r = screw_clearance_radius, center = true);
translate([bearing_clamp_tab / 2 + slot, 0, 0])
circle(r = screw_clearance_radius, center = true);
translate([bearing_clamp_tab / 2 + slot / 2, 0])
square([slot, screw_clearance_radius * 2], center = true);
}
}
module bearing_mount(bearing, height, endstop) {
endstop_w = bar_clamp_switch_x_offset() + microswitch_thickness() / 2 - bearing_holder_width(bearing) / 2;
endstop_d = 3;
endstop_h = height - bar_clamp_switch_z_offset() + microswitch_thickness() / 4;
stl(str("y_bearing_mount", endstop ? "_switch" : ""));
color([1,0,0]) union() {
bearing_holder(bearing, height);
for(end = [-1, 1])
translate([end * (bearing_holder_width(bearing) / 2 - eta), -end * (bearing_holder_length(bearing) - bearing_clamp_tab)/2, -height])
rotate([0,0,90 - end * 90])
tab();
if(endstop)
translate([-(bearing_holder_width(bearing) / 2 + endstop_w / 2),
-(bearing_holder_length(bearing) / 2 - endstop_d / 2),
endstop_h / 2 - height])
cube([endstop_w, endstop_d, endstop_h], center = true);
}
}
module bearing_mount_holes(height)
for(end = [-1, 1])
translate([end * (bearing_holder_width(Y_bearings) / 2 + tab_length / 2),
-end * (bearing_holder_length(Y_bearings) - bearing_clamp_tab) / 2, 0])
cylinder(r = screw_clearance_radius, h = 100, center = true);;
module y_bearing_assembly(height, endstop = false)
{
//assembly("y_bearing_assembly");
color([1,0,0]) render() bearing_mount(Y_bearings, height, endstop);
rotate([0,0,90]) {
linear_bearing(Y_bearings);
rotate([0,90,0])
ziptie(small_ziptie, bearing_ziptie_radius(Y_bearings));
}
//
// Fasterners
//
for(end = [-1, 1])
translate([end * (bearing_holder_width(Y_bearings) / 2 + tab_length / 2),
-end * (bearing_holder_length(Y_bearings) - bearing_clamp_tab) / 2, -height + bearing_clamp_tab_height]) {
nut_and_washer(nut, true);
translate([0,0, -bearing_clamp_tab_height - sheet_thickness(Y_carriage)])
rotate([180, 0, 0])
screw_and_washer(cap_screw, 16);
}
//end("y_bearing_assembly");
}
module y_bearing_mount_stl() translate([0,0, Y_bearing_holder_height]) bearing_mount(Y_bearings, Y_bearing_holder_height, false);
module y_bearing_mount_switch_stl() translate([0,0, Y_bearing_holder_height]) bearing_mount(Y_bearings, Y_bearing_holder_height, true);
if(1)
y_bearing_assembly(Y_bearing_holder_height, false);
else {
y_bearing_mount_stl();
translate([ bearing_mount_width(Y_bearings) - tab_length + 2, 0, 0]) y_bearing_mount_stl();
translate([-(bearing_mount_width(Y_bearings) - tab_length + 2), 0, 0]) y_bearing_mount_switch_stl();
};

147
scad/y-belt-anchor.scad Normal file
View File

@ -0,0 +1,147 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Anchors the belt to the bottom of the y carriage
//
include <conf/config.scad>
include <positions.scad>
wall = 2;
clearance = 2;
thickness = M3_nut_trap_depth + wall;
rad = 3;
clamp_thickness = 3;
width = belt_width(Y_belt) + 3 + washer_diameter(M3_washer) + clearance;
inner_width = (M3_nut_radius + wall) * 2;
depth = washer_diameter(M3_washer) + clearance;
length = depth + 2 * (2 * M3_nut_radius * cos(30) + wall);
tooth_height = belt_thickness(Y_belt) / 2;
tooth_width = belt_pitch(Y_belt) / 2;
function y_belt_anchor_width() = width;
module y_belt_anchor_holes() {
for(side = [-1, 1])
translate([0, side * (depth / 2 + M3_nut_radius * cos(30) + eta) + depth / 2, 0])
cylinder(r = M3_clearance_radius, h = 100, center = true);
}
module y_belt_anchor(height, toothed) {
h = height + belt_thickness(Y_belt) - belt_clearance;
recess = length - depth;
stl(str("y_belt_anchor", toothed ? "_toothed" : ""));
color([0,1,0]) union() {
difference() {
union() {
translate([0, depth / 2, h / 2]) // tall bit
rounded_rectangle([width, depth, h], r = rad);
translate([0, depth / 2, thickness / 2])
rounded_rectangle([inner_width, length, thickness], r = rad); // wide bit
for(side = [-1, 1]) // webs
for(end = [-1, 1])
translate([side * (M3_nut_radius + wall / 2), eta + (end + 1) * (depth / 2 - 2 * eta), thickness - eta])
rotate([90,0,90 * end])
right_triangle(width = (length - depth) / 2 - rad, height = h - thickness, h = wall);
}
translate([0, depth / 2, height + (h - height) / 2 + 2 * eta]) // slot for belt
cube([belt_width(Y_belt) + belt_clearance, depth + 1, h - height], center = true);
for(side = [-1, 1]) { // clamp screw nut traps
translate([side * (belt_width(Y_belt) / 2 + M3_clearance_radius), depth / 2, 0 ])
rotate([0,0,90/7 * (side + 1)])
nut_trap(M3_clearance_radius, M3_nut_radius, height - clamp_thickness);
translate([0, side * (depth / 2 + M3_nut_radius * cos(30) + eta) + depth / 2, thickness]) // mounting screw nut traps
nut_trap(M3_clearance_radius, M3_nut_radius, M3_nut_trap_depth);
}
translate([0, depth / 2, height + (h - height) / 2 + 2 * eta]) // slot to join screw holes
cube([belt_width(Y_belt) + M3_clearance_radius * 2, corrected_diameter(M3_clearance_radius * 2), h - height], center = true);
}
for(side = [-1, 1]) // blind the nut traps
translate([side * (belt_width(Y_belt) / 2 + M3_clearance_radius), depth / 2, height - clamp_thickness])
cylinder(r = M3_clearance_radius + 0.5, h = layer_height + eta);
if(toothed)
translate([0,depth / 2, height - eta + tooth_height / 2])
cube([belt_width(Y_belt), tooth_width, tooth_height], center = true);
}
}
module y_belt_clip(toothed) {
stl(str("y_belt_clip", toothed ? "_toothed" : ""));
color([1, 0, 0]) union() {
translate([0, 0, clamp_thickness / 2]) difference() {
rounded_rectangle([width, depth, clamp_thickness], r = rad);
for(side = [-1, 1]) // screw holes
translate([side * (belt_width(Y_belt) / 2 + M3_clearance_radius), 0, 0 ])
poly_cylinder(r = M3_clearance_radius, h = clamp_thickness + 1, center = true);
}
if(toothed)
translate([0,0, clamp_thickness - eta + tooth_height / 2])
cube([belt_width(Y_belt), tooth_width, tooth_height], center = true);
}
}
module y_belt_anchor_assembly(height, toothed) {
//assembly("y_belt_anchor_assembly");
color([0, 1, 0]) render() y_belt_anchor(height, toothed);
translate([0, depth / 2, height + belt_thickness(Y_belt) + clamp_thickness]) {
rotate([180, 0, 0])
color([1, 0, 0]) render() y_belt_clip(!toothed);
//
// Clamp screws
//
for(side = [-1, 1])
translate([side * (belt_width(Y_belt) / 2 + M3_clearance_radius), 0, 0]) {
screw_and_washer(M3_cap_screw, 16);
translate([0, 0, -2 * clamp_thickness - belt_thickness(Y_belt)])
rotate([180, 0, 0])
nut(M3_nut, true);
}
}
for(side = [-1, 1])
translate([0, side * (depth / 2 + M3_nut_radius * cos(30) + eta) + depth / 2, 0]) {
translate([0, 0, thickness - M3_nut_trap_depth])
nut(M3_nut, true);
translate([0, 0, - sheet_thickness(Y_carriage)])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, 16);
}
//end("y_belt_anchor_assembly");
}
module y_belt_anchor_stl() y_belt_anchor(Y_belt_clamp_height, false);
module y_belt_anchor_toothed_stl() y_belt_anchor(Y_belt_clamp_height, true);
module y_belt_clip_stl() y_belt_clip(false);
module y_belt_clip_toothed_stl() y_belt_clip(true);
if(1)
y_belt_anchor_assembly(Y_belt_clamp_height, true);
else {
translate([0, 0, 0]) y_belt_anchor_toothed_stl();
translate([0, 25, 0]) y_belt_anchor_stl();
translate([15, 5, 0]) rotate([0,0,90])y_belt_clip_toothed_stl();
translate([15,30, 0]) rotate([0,0,90]) y_belt_clip_stl();
}

115
scad/y-idler-bracket.scad Normal file
View File

@ -0,0 +1,115 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Holds the idler pulley
//
include <conf/config.scad>
use <y-motor-bracket.scad>
slot = 10;
axel_height = y_motor_height() + pulley_inner_radius - ball_bearing_diameter(Y_idler_bearing) / 2;
base_thickness = 5;
wall = default_wall;
clearance = 1;
dia = washer_diameter(M5_penny_washer) + 2 * clearance;
tab_length = washer_diameter(screw_washer(base_screw)) + 2 * clearance + slot;
length = dia + wall + tab_length;
function y_idler_clearance() = dia / 2 + slot;
function y_idler_offset() = dia / 2 + wall + tab_length;
width = (wall + washer_thickness(M5_penny_washer) + washer_thickness(M4_washer) + ball_bearing_width(Y_idler_bearing)) * 2;
back_width = washer_diameter(screw_washer(base_screw)) + 2 * clearance + 2 * wall;
height = axel_height + dia / 2;
module y_idler_bracket_stl() {
stl("y_idler_bracket");
color([0,1,0]) intersection() {
difference() {
rotate([90, 0, 90])
linear_extrude(height = width, center = true) //side profile
hull() {
translate([0, axel_height])
circle(dia / 2);
translate([-dia / 2 , 0])
square([length, base_thickness]); // base
square([dia / 2 + wall, height]); // upright
}
translate([0, - dia / 2, height + base_thickness]) // cavity for bearing
rotate([0, 90, 0])
rounded_rectangle(size = [height * 2, dia * 2, width - 2 * wall], r = dia / 2);
translate([0, dia / 2 + wall + tab_length / 2 + eta, height / 2 + base_thickness + eta]) // cavity for screw slot
cube([back_width - 2 * wall, tab_length, height], center = true);
translate([0, dia / 2 + wall + slot / 2 + washer_diameter(screw_washer(base_screw)) / 2 + clearance , 0]) // screw slot
rotate([0,0,90])
slot(r = screw_clearance_radius(base_screw), l = slot, h = 2 * base_thickness + 1, center = true);
translate([0, 0, axel_height]) // hole for axel
rotate([90, 0, 90])
teardrop_plus(r = M4_clearance_radius, h = width + 1, center = true);
}
union() { // plan profile
translate([0, (length - tab_length) / 2 - dia / 2, -1])
rounded_rectangle([width - eta, length - tab_length - eta, height + 2], r = 2, center = false);
translate([0, length - (tab_length + 5) / 2 - dia / 2 - eta, -1])
rounded_rectangle([back_width, tab_length + 5, height + 2], r = 2, center = false);
}
}
}
module y_idler_screw_hole()
translate([0, dia / 2 + wall + tab_length / 2 - slot / 2,0])
child();
module y_idler_assembly() {
assembly("y_idler_assembly");
color([0,1,0]) render() y_idler_bracket_stl();
translate([0, 0, axel_height]) rotate([0, -90, 0]) {
for(side = [-1, 1]) {
translate([0, 0, (ball_bearing_width(Y_idler_bearing) / 2) * side])
ball_bearing(BB624);
translate([0, 0, ball_bearing_width(Y_idler_bearing) * side])
rotate([0, side * 90 - 90, 0])
washer(M4_washer);
translate([0, 0, (ball_bearing_width(Y_idler_bearing) + washer_thickness(M4_washer)) * side])
rotate([0, side * 90 - 90, 0])
washer(M5_penny_washer);
}
translate([0, 0, width / 2])
screw_and_washer(M4_cap_screw, 40); // could be 30mm but would be the only one, 40 is used on the idler
translate([0, 0, -width / 2])
rotate([180, 0, 0])
nut_and_washer(M4_nut, true);
}
y_idler_screw_hole()
translate([0, 0, base_thickness])
base_screw();
end("y_idler_assembly");
}
if(1)
y_idler_assembly();
else
y_idler_bracket_stl();

105
scad/y-motor-bracket.scad Normal file
View File

@ -0,0 +1,105 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Fastens the Y motor to the base
//
include <conf/config.scad>
use <pulley.scad>
thickness = 4;
tab = 2 + washer_diameter(screw_washer(base_screw));
foot = 5;
holes = tab / 2 + 1;
function y_motor_bracket_height() = round(NEMA_width(Y_motor)) + 2;
function y_motor_height() = y_motor_bracket_height() / 2;
function y_motor_bracket_width() = y_motor_bracket_height() + 2 * (tab + thickness);
function y_motor_bracket_top_width() = y_motor_bracket_width() - 2 * tab;
depth = y_motor_bracket_height() + thickness - foot;
module y_motor_bracket() {
height = y_motor_bracket_height();
width = y_motor_bracket_width();
stl("y_motor_bracket");
color([0,1,0]) {
difference() {
translate([0, 0, thickness - depth / 2]) // main body
cube([width, height, depth], center = true);
cylinder(r = NEMA_big_hole(Y_motor), h = thickness * 2 + 1, center = true); // hole for stepper locating boss
translate([0, 0, - depth / 2])
cube([depth, height + 1, depth], center = true); // space for motor
translate([-width / 2, foot, 0])
cube([tab * 2, height, depth * 2], center = true); // cut outs for lugs
translate([width / 2, foot, 0])
cube([tab * 2, height, depth * 2], center = true);
translate([0, - height / 2 + foot, - depth + thickness]) // sloping sides
rotate([45,0,0])
translate([0,0, - depth / 2])
cube([width, 3 * height, depth], center = true);
for(x = NEMA_holes(Y_motor)) // motor screw holes
for(y = NEMA_holes(Y_motor))
translate([x,y,0])
poly_cylinder(r = M3_clearance_radius, h = 2 * thickness + 1, center = true);
//
// mounting screw holes
//
for(side = [-1, 1])
for(z = [thickness - depth + holes, thickness - holes])
translate([side * (width / 2 - tab / 2), - height / 2, z])
rotate([-90, 0, 0]) teardrop_plus(r = screw_clearance_radius(base_screw), h = foot * 2 + 1, center = true);
}
}
}
module y_motor_bracket_holes()
for(side = [-1, 1])
for(z = [thickness - depth + holes, thickness - holes])
translate([side * (y_motor_bracket_width() / 2 - tab / 2), -y_motor_bracket_height() / 2 + foot, z])
rotate([-90, 0, 0])
child();
module y_motor_assembly() {
assembly("y_motor_assembly");
color([0,1,0]) render() y_motor_bracket();
//
// Mounting screws and washers
//
y_motor_bracket_holes()
base_screw();
//
// Motor and screws
//
NEMA(Y_motor);
translate([0,0, thickness])
NEMA_screws(Y_motor);
//
// Pulley
//
translate([0, 0, 4])
pulley_assembly();
end("y_motor_assembly");
}
module y_motor_bracket_stl() translate([0, 0, thickness]) rotate([0,180,0]) y_motor_bracket();
if(1)
y_motor_assembly();
else
y_motor_bracket_stl();

114
scad/z-coupling.scad Normal file
View File

@ -0,0 +1,114 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Couples the leadscrews to the motor
//
include <conf/config.scad>
studding_dia = Z_screw_dia;
shaft_dia = 7; // includes tubing
holeR = M3_clearance_radius;
nutR = M3_nut_radius;
nutH = M3_nut_trap_depth;
corner_cut = 26;
wall = 2;
holeX = 7.5;
holeY2 = studding_dia / 2 + M3_clearance_radius;
holeY1 = shaft_dia / 2 + M3_clearance_radius;
nut_flat_radius = M3_nut_radius * cos(30);
width = 2 * (max(holeY2, holeY1) + nut_flat_radius + wall);
length = 30;
function z_coupling_length() = length;
depth = 8;
centre_line = depth / 2 + 0.5;
rad = M3_nut_radius + wall;
module z_coupling_stl(){
stl("z_coupling");
color([1,0,0]) translate([0, 0, depth / 2]) union() {
difference(){
linear_extrude(height = depth, center = true)
hull() {
polygon([
[ length / 2, shaft_dia / 2 + 1],
[ length / 2, -shaft_dia / 2 - 1],
[-length / 2, -studding_dia / 2 - 1],
[-length / 2, studding_dia / 2 + 1]
]);
translate([holeX, holeY1])
circle(r = rad, center = true);
translate([holeX, -holeY1])
circle(r = rad, center = true);
translate([-holeX, holeY2])
circle(r = rad, center = true);
translate([-holeX, -holeY2])
circle(r = rad, center = true);
}
//nut holes
translate([ holeX, holeY1, nutH/2 - 4.01]) rotate([0,0, 30]) cylinder(h = nutH, r=nutR, $fn=6, center=true);
translate([-holeX, holeY2, nutH/2 - 4.01]) rotate([0,0,-30]) cylinder(h = nutH, r=nutR, $fn=6, center=true);
//shaft groves
translate([ -17, 0, centre_line]) rotate([0,90,0]) cylinder(h = 16, r=studding_dia / 2);
translate([ 1, 0, centre_line]) rotate([0,90,0]) cylinder(h = 16, r=shaft_dia / 2);
//screw holes
for(y = [-1, 1]) {
translate([ holeX, y * holeY1, -10]) rotate([0,0, y * 360/28]) poly_cylinder(h = 20, r=holeR);
translate([-holeX, y * holeY2, -10]) rotate([0,0, y * 360/28]) poly_cylinder(h = 20, r=holeR);
}
//slots to prevent screw holes beading into the shaft holes
translate([holeX, 0, centre_line])
cube([2 * holeR, 2 * holeY1, shaft_dia], center = true);
translate([-holeX, 0, centre_line])
cube([2 * holeR, 2 * holeY2, studding_dia], center = true);
}
// bridge
translate([ holeX, holeY1, nutH-3.9]) cylinder(h = 0.4, r=nutR+0.1, $fn=6, center=true);
translate([-holeX, holeY2, nutH-3.9]) cylinder(h = 0.4, r=nutR+0.1, $fn=6, center=true);
}
}
module z_coupler_assembly() {
//assembly("z_coupler_assembly");
for(side = [-1, 1])
explode([10 * side, 0, 0])
translate([centre_line * side, 0, 0])
rotate([0, 90, 90 * side + 90]) {
color([1,0,0]) render() translate([0, 0, -depth/2]) z_coupling_stl();
for(pos = [[holeX, -holeY1], [-holeX, -holeY2]])
translate([pos[0], pos[1], -depth/2])
rotate([180, 0, 0])
screw_and_washer(M3_cap_screw, 20);
for(pos = [[holeX, holeY1], [-holeX, holeY2]])
translate([pos[0], pos[1], -depth/2 + nutH])
rotate([180, 0, 0])
nut(M3_nut, true);
}
translate([0,0, -9])
tubing(shaft_dia, 5, 16);
//end("z_coupler_assembly");
}
if(0)
z_coupling_stl();
else
z_coupler_assembly();

View File

@ -0,0 +1,167 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Adjustable bottom limit switch
//
include <conf/config.scad>
include <positions.scad>
wall = 2;
thickness = 5;
adjustment = 20;
down_adjustment = 10;
hinge_length = 2;
hinge_post = 4;
switch_boss = 7;
washers = 2;
switch_y = max(14 - microswitch_thickness() / 2, gantry_setback - x_bar_spacing() / 2);
switch_mount_height = switch_y - microswitch_thickness() / 2;
hinge_height = thickness + washer_diameter(M3_washer) + 2;
centre = max(washer_diameter(M3_washer), 2 * (nut_radius(M3_nut) + wall));
screw_spacing = adjustment + centre + washer_diameter(screw_washer(frame_screw)) + 2;
hinge_thickness = 2 * filament_width + eta;
leg_width = 1 + washer_diameter(screw_washer(frame_screw));
leg_length = adjustment + screw_spacing + leg_width + hinge_post;
lever_width = 4;
lever_length = leg_length / 2 + centre / 2 + hinge_post / 2;
bottom_z = microswitch_hole_y_offset() - switch_boss / 2;
slot_x = -x_end_bar_length() + z_bar_offset() -lever_width - hinge_length - leg_width / 2 -base_clearance;
screw_x = slot_x + leg_width / 2 + hinge_length + lever_width;
screw_y = hinge_height - washer_diameter(M3_washer) / 2 - 2;
screw_z = bottom_z + leg_length / 2 + hinge_post / 2;
center_thickness = leg_width - washer_thickness(M3_washer) - nut_thickness(M3_nut, true);
module z_limit_screw_positions() {
for(z = [0, screw_spacing])
translate([slot_x, -thickness, bottom_z + hinge_post + leg_width / 2 + adjustment - down_adjustment + z])
rotate([90, 0, 0])
child();
}
module z_limit_switch_bracket_stl() {
stl("z_limit_switch_bracket");
difference() {
union() {
//
// Boss for switch screws
//
translate([0, 0, -microswitch_thickness() / 2])
hull() {
microswitch_hole_positions()
cylinder(h = switch_mount_height, r = switch_boss / 2);
translate([slot_x + leg_width / 2 + hinge_length, microswitch_hole_y_offset() - switch_boss / 2, microswitch_thickness() / 2])
cube([1, switch_boss, switch_mount_height]);
}
//
// Screw slot
//
linear_extrude(height = thickness, convexity = 5) {
difference() {
hull() {
translate([slot_x, bottom_z + leg_length - leg_width / 2])
circle(r = leg_width / 2, center = true);
translate([slot_x - leg_width / 2, bottom_z])
square([leg_width, hinge_post]);
}
hull()
for(z = [bottom_z + screw_spacing, bottom_z + screw_spacing + adjustment])
translate([slot_x, z + hinge_post + leg_width / 2])
circle(r = screw_radius(frame_screw), center = true);
hull()
for(z = [bottom_z, bottom_z + adjustment])
translate([slot_x, z + hinge_post + leg_width / 2])
circle(r = screw_radius(frame_screw), center = true);
}
}
//
// Hinge
//
translate([slot_x, bottom_z + hinge_post / 2, hinge_height / 2])
cube([leg_width, hinge_post, hinge_height], center = true);
translate([slot_x + hinge_length / 2, bottom_z + hinge_thickness / 2, hinge_height / 2])
cube([leg_width + hinge_length + eta, hinge_thickness, hinge_height], center = true);
//
// Lever
//
translate([slot_x + leg_width / 2 + hinge_length, bottom_z, 0])
cube([lever_width, lever_length, hinge_height]);
//
// Adjuster screw bracket
//
translate([slot_x + leg_width / 2 -center_thickness / 2, screw_z, hinge_height / 2])
cube([center_thickness, centre, hinge_height], center = true);
}
translate([slot_x - leg_width / 2 - eta, screw_z, screw_y])
rotate([0, 90, 0])
cylinder(r = screw_y - 3, h = leg_width - center_thickness);
translate([screw_x, screw_z, screw_y])
rotate([90, 0, 90])
nut_trap(M3_clearance_radius, M3_nut_radius, screw_head_height(M3_hex_screw), true);
microswitch_hole_positions()
poly_cylinder(h = 100, r = No2_pilot_radius, center = true);
}
}
module z_limit_switch_assembly() {
assembly("z_limit_switch_assembly");
pos = 0;
screw_length = 16;
washer_thickness = hinge_length / washers;
translate([0, 0, pos]) {
rotate([90, 0, 0])
color([0, 1, 0]) render()
z_limit_switch_bracket_stl();
translate([screw_x - screw_head_height(M3_hex_screw), -screw_y, screw_z])
rotate([0, 90, 0])
screw(M3_hex_screw, 16);
for(i = [0 : washers - 1])
translate([slot_x + leg_width / 2 + i * washer_thickness, -screw_y, screw_z])
explode([i * 1, 0, 15], [washer_thickness / 2, 0, - washer_diameter(M3_rubber_washer) / 2])
rotate([0, 90, 0])
scale([1, 1, washer_thickness / washer_thickness(M3_rubber_washer)]) // squash it
washer(M3_rubber_washer);
translate([slot_x + leg_width / 2 - center_thickness, -screw_y, screw_z])
rotate([0, -90, 0])
nut_and_washer(M3_nut, true);
translate([0, -switch_y, 0])
rotate([90, 0, 0]) {
microswitch();
microswitch_hole_positions()
screw_and_washer(No2_screw, 13);
}
}
z_limit_screw_positions()
frame_screw(thickness);
end("z_limit_switch_assembly");
}
if(1)
z_limit_switch_assembly();
else
z_limit_switch_bracket_stl();

182
scad/z-motor-bracket.scad Normal file
View File

@ -0,0 +1,182 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Fastens the Z motor to the gantry
//
include <conf/config.scad>
include <positions.scad>
use <z-coupling.scad>
corner_rad = 5;
length = ceil(NEMA_width(Z_motor));
thickness = 4;
back_thickness = 5;
back_height = 24;
big_hole = NEMA_big_hole(Z_motor);
clamp_height = washer_diameter(washer) + 3;
clamp_thickness = bar_clamp_band;
clamp_screw_clearance = 2;
clamp_length = Z_bar_dia / 2 + bar_clamp_tab - 2;
gap = 1.5;
clamp_width = Z_bar_dia + 2 * clamp_thickness;
slot_inset = max((washer_diameter(screw_washer(frame_screw)) + 2),
length / 2 - NEMA_holes(Z_motor)[1] + washer_diameter(M3_washer) / 2 + 1) / 2;
clamp_x = z_bar_offset() + clamp_length - bar_clamp_tab / 2;
function z_motor_bracket_height() = back_height;
module z_motor_bracket(y_offset, rhs) {
width = y_offset + length / 2;
cutout = y_offset - length / 2 - back_thickness;
stl(rhs? "z_motor_bracket_rhs" : "z_motor_bracket_lhs");
color([0,1,0]) {
difference() {
union() {
//
// main body
//
translate([0, width / 2 - length / 2, back_height / 2])
difference() {
cube([length, width, back_height], center = true);
translate([0, -back_thickness, thickness])
cube([length + 1, width, back_height], center = true);
}
//
// Bracing webs
//
for(x = [length / 2 - 2 * slot_inset - thickness / 2, -(length / 2 - 2 * slot_inset - thickness / 2)])
translate([x, y_offset - back_thickness + eta, eta])
rotate([90, 0, -90])
right_triangle(width = y_offset - big_hole, height = back_height, h = thickness);
//
// bar clamp
//
translate([z_bar_offset() + clamp_length / 2 - eta, 0, clamp_height / 2 + eta])
cube([clamp_length, clamp_width, clamp_height], center = true);
translate([z_bar_offset(), 0, clamp_height / 2 + eta])
cylinder(h = clamp_height, r = Z_bar_dia/2 + clamp_thickness, center = true);
}
//
// front corners rounded
//
translate([-length / 2, - length / 2, thickness / 2])
fillet(r = corner_rad, h = thickness + 1);
translate([ length / 2, - length / 2, thickness / 2])
rotate([0,0, 90])
fillet(r = corner_rad, h = thickness + 1);
//
// Cut out between webs
//
translate([0, length / 2 + cutout / 2, thickness / 2])
rounded_rectangle([length - 4 * slot_inset - 2 * thickness, cutout, thickness + 1], r = corner_rad / 2, center = true);
//
// motor holes
//
poly_cylinder(r = big_hole, h = thickness * 2 + 1, center = true); // hole for stepper locating boss
for(x = NEMA_holes(Z_motor)) // motor screw holes
for(y = NEMA_holes(Z_motor))
translate([x,y,0])
poly_cylinder(r = M3_clearance_radius, h = 2 * thickness + 1, center = true);
//
// bar clamp
//
translate([z_bar_offset() + clamp_length / 2, 0, 0]) // clamp slot
cube([clamp_length, gap, clamp_height * 2 + 1], center = true);
translate([clamp_x, Z_bar_dia / 2 + clamp_thickness, clamp_height / 2])
rotate([90, 0, 0])
nut_trap(screw_clearance_radius, nut_radius, nut_trap_depth, horizontal = true); // clamp screw
translate([z_bar_offset(), 0, 0])
poly_cylinder(r = Z_bar_dia / 2, h = clamp_height * 2 + 1, center = true); // hole for z rod
//
// screw slots in the back
//
for(side = [-1, 1])
translate([side * (length / 2 - slot_inset), width - length / 2 - back_thickness / 2, back_height / 2 + thickness / 2])
rotate([90, 0, 0])
vertical_tearslot(h = back_thickness + 1, l = back_height - thickness - 2 * slot_inset,
r = screw_clearance_radius(frame_screw), center = true);
//
// rounded corners on the back
//
translate([-length / 2, width - length / 2 - back_thickness / 2, back_height])
rotate([-90, 0, 0])
fillet(r = corner_rad, h = back_thickness + 1);
translate([length / 2, width - length / 2 - back_thickness / 2, back_height])
rotate([-90, 90, 0])
fillet(r = corner_rad, h = back_thickness + 1);
}
}
}
function z_motor_bracket_hole_offset() = length / 2 - slot_inset;
module z_motor_bracket_holes(gantry_setback)
for(side = [-1, 1])
translate([side * z_motor_bracket_hole_offset(), gantry_setback - back_thickness, back_height / 2 + thickness / 2])
rotate([90, 0, 0])
child();
module z_motor_assembly(gantry_setback, rhs, standalone = false) {
assembly("z_motor_assembly");
color([0,1,0]) render() z_motor_bracket(gantry_setback, rhs);
//
// Clamp screw and washer
//
translate([clamp_x, -clamp_width / 2, clamp_height / 2])
rotate([90, 0, 0])
screw_and_washer(cap_screw, screw_longer_than(clamp_width + washer_thickness(screw_washer(cap_screw))));
//
// Clamp nyloc
//
translate([clamp_x, clamp_width / 2 - nut_trap_depth, clamp_height / 2])
rotate([-90, 0, 0])
nut(nut, true);
//
// Mounting screws
//
if(!standalone)
z_motor_bracket_holes(gantry_setback)
frame_screw(back_thickness);
//
// Motor and screws
//
NEMA(Z_motor);
translate([0,0, thickness])
NEMA_screws(Z_motor);
//
// The coupling assembly
//
explode([0, 0, 30])
translate([0, 0, NEMA_shaft_length(Z_motor) + 1])
rotate([0,0,45])
z_coupler_assembly();
end("z_motor_assembly");
}
module z_motor_bracket_lhs_stl() z_motor_bracket(gantry_setback, false);
module z_motor_bracket_rhs_stl()mirror([1,0,0]) z_motor_bracket(gantry_setback, true);
if(0) {
translate([length + 2, 0, 0]) z_motor_bracket_lhs_stl();
z_motor_bracket_rhs_stl();
}
else
z_motor_assembly(gantry_setback, false);

39
scad/z-screw_pointer.scad Normal file
View File

@ -0,0 +1,39 @@
//
// Mendel90
//
// GNU GPL v2
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// Pointers on the Z screws
//
include <conf/config.scad>
function z_screw_pointer_height() = 5;
module z_screw_pointer_stl() {
wall = 2.4;
height = z_screw_pointer_height();
inner_rad = (((Z_screw_dia == 6) ? M6_tap_radius : M8_tap_radius) + Z_bar_dia / 2) / 2; // half depth thread
outer_rad = inner_rad + wall;
pointer = z_bar_offset() - Z_bar_dia / 2 - 1;
stl("z_screw_pointer");
difference() {
union() {
linear_extrude(height = wall)
hull() {
circle(r = outer_rad, center = true);
translate([pointer - filament_width, 0, 0])
square(filament_width * 2, center = true);
}
translate([0,0, eta])
cylinder(r = outer_rad, h = height);
}
poly_cylinder(r = inner_rad, h = 2 * height + 1, center = true);
}
}
z_screw_pointer_stl();

60
sheets.py Normal file
View File

@ -0,0 +1,60 @@
import os
import subprocess
import shutil
import sys
from dxf import *
source_dir = "scad"
def sheets(machine):
#
# Make the target directory
#
target_dir = machine + "/sheets"
if os.path.isdir(target_dir):
shutil.rmtree(target_dir)
os.makedirs(target_dir)
#
# Set the target machine
#
f = open("scad/conf/machine.scad","wt")
f. write("include <%s_config.scad>\n" % machine);
f.close()
#
# Find all the scad files
#
for filename in os.listdir(source_dir):
if filename[-5:] == ".scad":
#
# find any modules ending in _dxf
#
for line in open(source_dir + "/" + filename, "r").readlines():
words = line.split()
if(len(words) and words[0] == "module"):
module = words[1].split('(')[0]
if module[-4:] == "_dxf":
#
# make a file to use the module
#
dxf_maker_name = target_dir + "/" + module + ".scad"
f = open(dxf_maker_name, "w")
f.write("use <%s/%s>\n" % (source_dir, filename))
f.write("%s();\n" % module);
f.close()
#
# Run openscad on the created file
#
dxf_name = target_dir + "/" + module[:-4] + ".dxf"
subprocess.call(["openscad_cl", "-o", dxf_name, dxf_maker_name])
dxf_to_svg(dxf_name)
if __name__ == '__main__':
if len(sys.argv) > 1:
sheets(sys.argv[1])
else:
print "usage: sheets [mendel|sturdy|your_machine]"
sys.exit(1)

75
stls.py Normal file
View File

@ -0,0 +1,75 @@
import os
import subprocess
import shutil
import sys
source_dir = "scad"
def stls(machine):
#
# Make the target directory
#
target_dir = machine + "/stls"
if os.path.isdir(target_dir):
shutil.rmtree(target_dir)
os.makedirs(target_dir)
#
# Set the target machine
#
f = open("scad/conf/machine.scad","wt")
f. write("include <%s_config.scad>\n" % machine);
f.close()
#
# Make a list of all the stls in the BOM
#
targets = []
for line in open(machine + "/bom/bom.txt", "rt").readlines():
words = line.split()
if words:
last_word = words[-1]
if len(last_word) > 4 and last_word[-4:] == ".stl":
targets.append(last_word.replace(".stl", "_stl"))
#
# Find all the scad files
#
for filename in os.listdir(source_dir):
if filename[-5:] == ".scad":
#
# find any modules ending in _stl
#
for line in open(source_dir + "/" + filename, "r").readlines():
words = line.split()
if(len(words) and words[0] == "module"):
module = words[1].split('(')[0]
if module in targets:
#
# make a file to use the module
#
stl_maker_name = source_dir + "/stl.scad"
f = open(stl_maker_name, "w")
f.write("use <%s/%s>\n" % (source_dir, filename))
f.write("%s();\n" % module);
f.close()
#
# Run openscad on the created file
#
stl_name = target_dir + "/" + module[:-4] + ".stl"
subprocess.call(["openscad_cl", "-o", stl_name, stl_maker_name])
targets.remove(module)
#
# List the ones we didn't find
#
for module in targets:
print "Could not find", module
if __name__ == '__main__':
if len(sys.argv) > 1:
stls(sys.argv[1])
else:
print "usage: stls [mendel|sturdy|your_machine]"
sys.exit(1)

112
svg.py Normal file
View File

@ -0,0 +1,112 @@
## {{{ http://code.activestate.com/recipes/325823/ (r1)
#!/usr/bin/env python
"""\
SVG.py - Construct/display SVG scenes.
The following code is a lightweight wrapper around SVG files. The metaphor
is to construct a scene, add objects to it, and then write it to a file
to display it.
"""
import os
class Scene:
def __init__(self,name="svg",height=400,width=400):
self.name = name
self.items = []
self.height = height
self.width = width
return
def add(self,item): self.items.append(item)
def strarray(self):
var = ["<?xml version=\"1.0\"?>\n",
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="%dmm" width="%dmm" >\n' % (self.height,self.width),
' <g style="fill-opacity:1.0; stroke:black; stroke-width:1;">\n'
]
for item in self.items: var += item.strarray()
var += [" </g>\n</svg>\n"]
return var
def write_svg(self,filename=None):
if filename:
self.svgname = filename
else:
self.svgname = self.name + ".svg"
file = open(self.svgname,'w')
file.writelines(self.strarray())
file.close()
return
def display(self):
os.system("%s" % (self.svgname))
return
class Line:
def __init__(self,start,end):
self.start = start #xy tuple
self.end = end #xy tuple
return
def strarray(self):
return [' <line x1="%fmm" y1="%fmm" x2="%fmm" y2="%fmm" />\n' % (self.start[0],self.start[1],self.end[0],self.end[1])]
class Circle:
def __init__(self,center,radius,color):
self.center = center #xy tuple
self.radius = radius
self.color = color #rgb tuple in range(0,256)
return
def strarray(self):
return [' <circle cx="%fmm" cy="%fmm" r="%fmm" fill="none"/>\n' % (self.center[0],self.center[1],self.radius)]
class Rectangle:
def __init__(self,origin,height,width,color):
self.origin = origin
self.height = height
self.width = width
self.color = color
return
def strarray(self):
return [' <rect x="%dmm" y="%dmm" height="%dmm"\n' % (self.origin[0],self.origin[1],self.height),
' width="%dmm" style="fill:%s;" />\n' % (self.width,colorstr(self.color))]
class Text:
def __init__(self,origin,text,size=24):
self.origin = origin
self.text = text
self.size = size
return
def strarray(self):
return [' <text x="%dmm" y="%dmm" font-size="%d">\n' % (self.origin[0],self.origin[1],self.size),
' %s\n' % self.text,
' </text>\n']
def colorstr(rgb): return "#%x%x%x" % (rgb[0]/16,rgb[1]/16,rgb[2]/16)
def test():
scene = Scene('test')
scene.add(Rectangle((50,50),100,100,(0,255,255)))
scene.add(Line((100,100),(150,100)))
scene.add(Line((100,100),( 50,100)))
scene.add(Line((100,100),(100,150)))
scene.add(Line((100,100),(100, 50)))
scene.add(Circle((100,100),15,(0,0,255)))
scene.add(Circle((100,150),15,(0,255,0)))
scene.add(Circle((150,100),15,(255,0,0)))
scene.add(Circle(( 50,100),15,(255,255,0)))
scene.add(Circle((100, 50),15,(255,0,255)))
scene.add(Text((25,25),"Testing SVG"))
scene.write_svg()
scene.display()
return
if __name__ == '__main__': test()
## end of http://code.activestate.com/recipes/325823/ }}}