diff --git a/gantry.py b/gantry.py new file mode 100644 index 0000000..5253b0c --- /dev/null +++ b/gantry.py @@ -0,0 +1,222 @@ +import cadquery as cq +from ocp_vscode import * +from utils import * + +import localselectors + +tube_w = inch(2.0) +tube_h = inch(1.5) +tube_wall = inch(0.075) # 1.519 #inch(0.062) +column_spacing = 500 +column_h = 400 +plate_z = 2.54 +plate_z2 = 10 + +x_rail_spacing = 240 +x_carriage_spacing = 120 + +class Gantry: + def __init__(self, w): + self.left = tubing( + column_h, + tube_w, + tube_h, + tube_wall, + w.transformed(offset=(-0.5*column_spacing, 0, 0))) + self.right = tubing( + column_h, + tube_w, + tube_h, + tube_wall, + w.transformed(offset=(0.5*column_spacing, 0, 0))) + upper_center = column_h - 0.5*tube_w + self.upper = tubing( + column_spacing - tube_w, + tube_h, + tube_w, + tube_wall, + w.transformed(offset=(-0.5*column_spacing+0.5*tube_w, 0, upper_center), rotate=(90, 90, 0))) + lower_center = upper_center - x_rail_spacing + self.lower = tubing( + column_spacing - tube_w, + tube_h, + tube_w, + tube_wall, + w.transformed( + offset=( + -0.5*column_spacing+0.5*tube_w, + 0, + lower_center), rotate=(90, 90, 0))) + self.upper_rail = HGR20( + w.transformed( + offset=(0, 0.5*tube_h + plate_z, upper_center), + rotate=(-90, 0, 0) + ), column_spacing + tube_w) + self.lower_rail = HGR20( + w.transformed( + offset=(0, 0.5*tube_h + plate_z, lower_center), + rotate=(-90, 0, 0) + ), column_spacing + tube_w) + self.upper_front_plate = ( + w.transformed(offset=(0, tube_h/2, upper_center), rotate=(-90, 0, 0)) + .rect(column_spacing + tube_w, tube_w) + .extrude(plate_z) + ) + self.lower_front_plate = ( + w.transformed(offset=(0, tube_h/2, lower_center), rotate=(-90, 0, 0)) + .rect(column_spacing + tube_w, tube_w) + .extrude(plate_z) + ) + self.upper_back_plate = ( + w.transformed(offset=(0, -tube_h/2, upper_center), rotate=(90, 0, 0)) + .rect(column_spacing + tube_w, tube_w) + .extrude(plate_z) + ) + self.lower_back_plate = ( + w.transformed(offset=(0, -tube_h/2, lower_center), rotate=(90, 0, 0)) + .rect(column_spacing + tube_w, tube_w) + .extrude(plate_z) + ) + + self.upper_front_plate = self.upper_rail.holes(self.upper_front_plate) + self.upper_back_plate = self.upper_rail.holes(self.upper_back_plate) + + self.lower_front_plate = self.lower_rail.holes(self.lower_front_plate) + self.lower_back_plate = self.lower_rail.holes(self.lower_back_plate) + + def assembly(self): + return (cq.Assembly(name="gantry") + .add(self.left, name="left column") + .add(self.right, name="right column") + .add(self.upper, name="upper platform") + .add(self.lower, name="lower platform") + .add(self.upper_rail.rail(), name="upper rail") + .add(self.lower_rail.rail(), name="lower rail") + .add(self.upper_front_plate, name="upper front plate") + .add(self.lower_front_plate, name="lower front plate") + .add(self.upper_back_plate, name="upper back plate") + .add(self.lower_back_plate, name="lower back plate") + ) + #assembly.test = 7 + +z_rail_spacing = 120 +z_carriage_spacing = 100 +z_rail_len = 450 +carriage_w = 250 +carriage_h = 300 +bolster_w = 30 +bolster_z = 25 +class Carriage: + def __init__(self, gantry, x=0, z=0): + self.bul = gantry.upper_rail.carriage(x) + self.bur = gantry.upper_rail.carriage(x+x_carriage_spacing) + self.bll = gantry.lower_rail.carriage(x) + self.blr = gantry.lower_rail.carriage(x+x_carriage_spacing) + back = cq.Workplane("XZ").copyWorkplane(self.bul.workplaneFromTagged("mountingholes")) + # why doesn't this track the carriage without me adding x to it? + self.plate = (back.center(-x-HGR20.L-x_carriage_spacing/2, -x_rail_spacing/2) + #.rect(HGR20.L+x_carriage_spacing, HGR20.W+x_rail_spacing) + .rect(carriage_w, carriage_h) + .extrude(plate_z2) + .faces(">z") # localselectors plugin + .workplane() + .tag("carriage_plate") + ) + self.plate = gantry.upper_rail.carriageHoles(self.plate, x) + self.plate = gantry.upper_rail.carriageHoles(self.plate, x+x_carriage_spacing) + self.plate = gantry.lower_rail.carriageHoles(self.plate, x) + self.plate = gantry.lower_rail.carriageHoles(self.plate, x+x_carriage_spacing) + + # creating the workplane the rails of the spindle carrier + # mount to, because HGR works from that plane forward + self.carrier_plane = (cq.Workplane() + .copyWorkplane(self.plate.workplaneFromTagged("carriage_plate")) + .transformed(offset=(0, 0, HGR20.H), rotate=(180, 0, 0)) + ) + + self.left_rail = HGR20( + self.carrier_plane. + transformed(offset=(z_rail_spacing/2, z, 0), rotate=(0, 0, 90)), + z_rail_len) + self.right_rail = HGR20( + self.carrier_plane. + transformed(offset=(-z_rail_spacing/2, z, 0), rotate=(0, 0, 90)), + z_rail_len) + + u_zcarriage_pos = z_rail_len/2 - HGR20.L/2 -z - z_carriage_spacing/2 + l_zcarriage_pos = u_zcarriage_pos + z_carriage_spacing + self.ful = self.left_rail.carriage(u_zcarriage_pos) + self.fll = self.left_rail.carriage(l_zcarriage_pos) + self.fur = self.right_rail.carriage(u_zcarriage_pos) + self.flr = self.right_rail.carriage(l_zcarriage_pos) + + self.plate = self.left_rail.carriageHoles(self.plate, u_zcarriage_pos) + self.plate = self.left_rail.carriageHoles(self.plate, l_zcarriage_pos) + self.plate = self.right_rail.carriageHoles(self.plate, u_zcarriage_pos) + self.plate = self.right_rail.carriageHoles(self.plate, l_zcarriage_pos) + + self.lbolster = (cq.Workplane() + .copyWorkplane(self.plate.workplaneFromTagged("carriage_plate")) + .transformed(offset=(-(carriage_w - bolster_w)/2, 0, 0)) + .rect(bolster_w, carriage_h) + .extrude(bolster_z) + ) + self.rbolster = (cq.Workplane() + .copyWorkplane(self.plate.workplaneFromTagged("carriage_plate")) + .transformed(offset=((carriage_w - bolster_w)/2, 0, 0)) + .rect(bolster_w, carriage_h) + .extrude(bolster_z) + ) + # TODO add bolster mounting holes + + self.wp_carrier = (cq.Workplane() + .copyWorkplane(self.plate.workplaneFromTagged("carriage_plate")) + .transformed(offset=(0, -z, HGR20.H), rotate=(0, 0, 0)) + ) + + def assembly(self): + return (cq.Assembly(name="x carriage") + .add(self.bul, name="back ul carriage") + .add(self.bur, name="back ur carriage") + .add(self.bll, name="back ll carriage") + .add(self.blr, name="back lr carriage") + .add(self.plate, name="carrier plate") + .add(self.left_rail.rail(), name="left rail") + .add(self.right_rail.rail(), name="right rail") + .add(self.ful, name="front ul carriage") + .add(self.fur, name="front ur carriage") + .add(self.fll, name="front ll carriage") + .add(self.flr, name="front lr carriage") + .add(self.lbolster, name="left bolster") + .add(self.lbolster, name="right bolster") + ) + +class Carrier: + def __init__(self, carriage): + self.plane = carriage.wp_carrier + self.plate = (cq.Workplane() + .copyWorkplane(self.plane) + .rect(200, z_rail_len) + .extrude(10)) + self.plate = carriage.left_rail.holes(self.plate) + self.plate = carriage.right_rail.holes(self.plate) + + def assembly(self): + return (cq.Assembly(name="z carrier") + .add(self.plate, name="z plate")) +g = Gantry(cq.Workplane()) +c = Carriage(g, 150, 0) +ca = Carrier(c) + +# TODO add ball screws and associated assembly + +full_assmbly = (cq.Assembly() + .add(g.assembly(), name="gantry") + .add(c.assembly(), name="carriage") + .add(ca.assembly(), name="carrier") +) + +show_object(full_assmbly) +#show_object(ca.assembly()) +#show_object(c.assembly()) +#show_object(g.assembly()) \ No newline at end of file diff --git a/localselectors.py b/localselectors.py new file mode 100644 index 0000000..e7afee6 --- /dev/null +++ b/localselectors.py @@ -0,0 +1,140 @@ +import cadquery as cq + +from cadquery.occ_impl.geom import Vector +from cadquery.occ_impl.shape_protocols import ( + geom_LUT_EDGE, + geom_LUT_FACE, +) + +from pyparsing import ( + pyparsing_common, + Literal, + Word, + nums, + Optional, + Combine, + oneOf, + Group, + infixNotation, + opAssoc, +) + +def _makeGrammar(): + """ + Define the simple string selector grammar using PyParsing + """ + + # float definition + point = Literal(".") + plusmin = Literal("+") | Literal("-") + number = Word(nums) + integer = Combine(Optional(plusmin) + number) + floatn = Combine(integer + Optional(point + Optional(number))) + + # vector definition + lbracket = Literal("(") + rbracket = Literal(")") + comma = Literal(",") + vector = Combine( + lbracket + floatn("x") + comma + floatn("y") + comma + floatn("z") + rbracket, + adjacent=False, + ) + + # direction definition + simple_dir = oneOf(["X", "Y", "Z", "XY", "XZ", "YZ"] + ["x", "y", "z", "xy", "xz", "yz"]) + direction = simple_dir("simple_dir") | vector("vector_dir") + + # CQ type definition + cqtype = oneOf( + set(geom_LUT_EDGE.values()) | set(geom_LUT_FACE.values()), caseless=True, + ) + cqtype = cqtype.setParseAction(pyparsing_common.upcaseTokens) + + # type operator + type_op = Literal("%") + + # direction operator + direction_op = oneOf([">", "<"]) + + # center Nth operator + center_nth_op = oneOf([">>", "<<"]) + + # index definition + ix_number = Group(Optional("-") + Word(nums)) + lsqbracket = Literal("[").suppress() + rsqbracket = Literal("]").suppress() + + index = lsqbracket + ix_number("index") + rsqbracket + + # other operators + other_op = oneOf(["|", "#", "+", "-"]) + + # named view + named_view = oneOf(["front", "back", "left", "right", "top", "bottom"]) + + return ( + direction("only_dir") + | (type_op("type_op") + cqtype("cq_type")) + | (direction_op("dir_op") + direction("dir") + Optional(index)) + | (center_nth_op("center_nth_op") + direction("dir") + Optional(index)) + | (other_op("other_op") + direction("dir")) + | named_view("named_view") + ) + + +old_getVector = cq.selectors._SimpleStringSyntaxSelector._getVector + +def _getVector(self, pr): + if "simple_dir" in pr and pr.simple_dir in cq.selectors._SimpleStringSyntaxSelector.local_axes: + return cq.selectors._SimpleStringSyntaxSelector.local_axes[pr.simple_dir] + else: + return old_getVector(self, pr) + +class LocalCoordinates: + def __init__(self, plane): + self.plane = plane + self.old_axes = None + + def __enter__(self): + self.old_axes, cq.selectors._SimpleStringSyntaxSelector.local_axes = (cq.selectors._SimpleStringSyntaxSelector.local_axes, + { + 'x': self.plane.xDir, + 'y': self.plane.yDir, + 'z': self.plane.zDir, + 'xy': self.plane.xDir + self.plane.yDir, + 'yz': self.plane.yDir + self.plane.zDir, + 'xz': self.plane.xDir + self.plane.zDir, + }) + + def __exit__(self, _exc_type, _exc_value, _traceback): + cq.selectors._SimpleStringSyntaxSelector.local_axes = self.old_axes + + +def _filter(self, objs, selector): + selectorObj: Selector + if selector: + if isinstance(selector, str): + with LocalCoordinates(self.plane): + selectorObj = cq.selectors.StringSyntaxSelector(selector) + else: + selectorObj = selector + toReturn = selectorObj.filter(objs) + else: + toReturn = objs + + return toReturn + +cq.selectors._SimpleStringSyntaxSelector.local_axes = { + "x": Vector(1, 0, 0), + "y": Vector(0, 1, 0), + "z": Vector(0, 0, 1), + "xy": Vector(1, 1, 0), + "yz": Vector(0, 1, 1), + "xz": Vector(1, 0, 1), +} +cq.selectors._SimpleStringSyntaxSelector._getVector = _getVector + +cq.selectors._grammar = _makeGrammar() # make a grammar instance +cq.selectors._expression_grammar = cq.selectors._makeExpressionGrammar(cq.selectors._grammar) + +cq.Workplane._filter = _filter diff --git a/utils.py b/utils.py index 2f2a94d..763fcce 100644 --- a/utils.py +++ b/utils.py @@ -1,78 +1,453 @@ +import math + import cadquery as cq +from ocp_vscode import * -# pixel coordinates based on a picture in the Hiwin's -# linear rail guidebook +import localselectors -hgr_profile = [ - (0, 0), - (37, 0), - (37 + 6, 6), - (96 - 6, 6), - (96, 0), - (186-17, 0), - (186, 17), - (186, 76), - (129, 133), - (129, 59 + 133), - (129 + 20, 59 + 133 + 20), - (31, 129 + 20 + 31, 133 + 20 + 31), - (186 - 6, 316 - 42 - 25 - 6), - (186, 316 - 42 - 25), - (186, 316 - 42), - (186 - 6, 316 - 42 + 6 - 1), - (31, 186 - 6 - 31, 316 - 6 - 1), - (143 + 6, 316 - 6), - (143, 316), - (0, 316) - ] +class SFU1204: + def __init__(self, base, l): + self.w = base.workplane() + self.len = l + + def ballscrew(self): + profile = [ + (0, 0), + (0, 8/2), + (15, 8/2), + (15, 10/2), + (15+16, 10/2), + (15+39, 10/2), + (15+39, 12/2), + (self.len - 10, 12/2), + (self.len - 10, 8/2), + (self.len, 8/2), + (self.len, 0), + ] + w = self.w.moveTo(0, 0) + for v in profile[1:]: + w = w.lineTo(v[1], v[0]) + w = w.close() + return w.revolve() -scale = (10/186*17/316)**0.5 + def nut(self, x): + w = self.w.transformed(offset=(0, x, 0), rotate=(90, 0, 0)) + n = (w.sketch() + .circle(40/2) + .circle(12/2, mode='s') + .rect(42, 30, mode='i') + .finalize() + .extrude(10) + .faces(">z") + .workplane() + .tag("nut_face") + .sketch() + .circle(22/2) + .circle(12/2, mode='s') + .finalize() + .extrude(25)) + hole_r = 32/2 + hole_pts = [ + (hole_r*math.cos(angle*math.pi/180), + hole_r*math.sin(angle*math.pi/180)) for angle in + [-45, 0, 45, 180-45, 180, 180+45]] + n = (n.workplaneFromTagged("nut_face") + .pushPoints(hole_pts) + .hole(4.8) + ) + return n -scaled_profile = [tuple((scale * v for v in vals)) for vals in hgr_profile] + def nutHoles(self, solid, x): + w = self.w.transformed(offset=(0, x, 0), rotate=(90, 0, 0)) + hole_r = 32/2 + hole_pts = [ + (hole_r*math.cos(angle*math.pi/180), + hole_r*math.sin(angle*math.pi/180)) for angle in + [-45, 0, 45, 180-45, 180, 180+45]] + solid = (solid.copyWorkplane(w) + .pushPoints(hole_pts) + .hole(4.8)) + return solid + def fixedBearing(self): + d1 = 12 + L = 25 + L1 = 5 + L2 = 29 + L3 = 5 + C1 = 13 + C2 = 6 + B = 60 + H = 43 + b = 30 + h = 25 + B1 = 34 + H1 = 32.5 + E = 18 + P = 46 + d2 = 5.5 + X = 6.6 + Y = 10.8 + Z = 1.5 + w = self.w.transformed(offset=(0, 39+15-L, 0), rotate=(-90, 0, 0)) + w2 = w.transformed(offset=(0, (H-H1)/2, 0)) + + bearing = (w + .rect(B1, B1) + .extrude(L1+L) + .copyWorkplane(w2) + .rect(B, H1) + .extrude(L) + .copyWorkplane(w.transformed(rotate=(180, 0, 0))) + .hole(d1) + .copyWorkplane(w2.transformed(rotate=(180, 0, 0))) + .rect(P, E, forConstruction=True) + .vertices() + .hole(d2) + ) + # TODO the holes on the top surface + + return bearing + + def fixedBearingHoles(self, solid): + d1 = 12 + L = 25 + L1 = 5 + L2 = 29 + L3 = 5 + C1 = 13 + C2 = 6 + B = 60 + H = 43 + b = 30 + h = 25 + B1 = 34 + H1 = 32.5 + E = 18 + P = 46 + d2 = 5.5 + X = 6.6 + Y = 10.8 + Z = 1.5 + + w = self.w.transformed(offset=(0, 39+15-L, -(H-H1)/2), rotate=(-90, 0, 0)) + return (solid + .copyWorkplane(w) + .rect(P, E, forConstruction=True) + .vertices() + .hole(d2) + ) + + def floatingBearing(self): + d1 = 10 + L = 20 + B = 60 + H = 43 + b = 30 + h = 25 + B1 = 34 + H1 = 32.5 + E = 18 + P = 46 + d2 = 5.5 + X = 6.6 + Y = 10.8 + Z = 1.5 + + w = self.w.transformed(offset=(0, self.len-10, 0), rotate=(-90, 0, 0)) + b = (w + .rect(B1, B1) + .extrude(L) + .faces(">z") + .workplane() + .tag("floating_far_end") + .copyWorkplane(w) + .center(0, (H-H1)/2) + .rect(B, H1) + .extrude(L) + .workplaneFromTagged("floating_far_end") + .hole(d1) + .workplaneFromTagged("floating_far_end") + .center(0, -(H-H1)/2) + .rect(P, E, forConstruction=True) + .vertices() + .hole(d2) + ) + return b + + def floatingBearingHoles(self, solid): + d1 = 10 + L = 20 + B = 60 + H = 43 + b = 30 + h = 25 + B1 = 34 + H1 = 32.5 + E = 18 + P = 46 + d2 = 5.5 + X = 6.6 + Y = 10.8 + Z = 1.5 + + w = self.w.transformed(offset=(0, self.len-10+L, 0), rotate=(90, 0, 0)) + solid = (solid + .copyWorkplane(w) + .center(0, -(H-H1)/2) + .rect(P, E, forConstruction=True) + .vertices() + .hole(d2) + ) + return solid + +# it's oriented along the y axis of the given base plane class HGR20: def __init__(self, base, l): self.base = base.workplane() self.l = l def holes(self, w): - pts = [(0, x-self.l/2) for x in range(20, self.l, 60)] - print("points", pts) + pts = [] + x = 20 + while x < self.l + 1e-6: + pts.append((x - self.l/2, 0)) + x += 60 w = (w.copyWorkplane(self.base) .transformed(offset=(0,0,17)) .pushPoints(pts) .hole(5)) return w + def rail_sketch(s = None): + # pixel coordinates based on a picture in the Hiwin's + # linear rail guidebook + + hgr_profile = [ + (0, 0), + (37, 0), + (37 + 6, 6), + (96 - 6, 6), + (96, 0), + (186-17, 0), + (186, 17), + (186, 76), + (129, 133), + (129, 59 + 133), + (129 + 20, 59 + 133 + 20), + #(31, 129 + 20 + 31, 133 + 20 + 31), + (186 - 6, 316 - 42 - 25 - 6), + (186, 316 - 42 - 25), + (186, 316 - 42), + (186 - 6, 316 - 42 + 6 - 1), + (31, 186 - 6 - 31, 316 - 6 - 1), + (143 + 6, 316 - 6), + (143, 316), + (0, 316) + ] + scale = (10/186*17/316)**0.5 + scaled_profile = [tuple((scale * v for v in vals)) for vals in hgr_profile] + if s is None: + s = cq.Sketch() + s = s.segment((0, 0), scaled_profile[1]) + # TODO do arcs correctly + for v in scaled_profile[2:]: + if len(v) == 2: + s = s.segment(v) + else: + s = s.segment(v[1:]) + for v in scaled_profile[-2:0:-1]: + if len(v) == 2: + s = s.segment((-v[0], v[1])) + else: + s = s.segment((-v[1], v[2])) + s = s.segment((0, 0)) + return s + def rail(self): # workplane or face to use, length of rail # TODO rotate w xy = cq.Workplane().copyWorkplane(self.base) - w = xy.transformed((90, 0, 0), (0, self.l/2, 0)) - for v in scaled_profile[1:]: - if len(v) == 2: - w = w.lineTo(*v) - else: - w = w.lineTo(*v[1:3]) # TODO draw an arc instead - w = w.mirrorY() + w = xy.transformed((90, 90, 0), (-self.l/2, 0, 0)) + w = w.placeSketch(HGR20.rail_sketch().assemble()) w = w.extrude(self.l) - pts = [(0, x-self.l/2) for x in range(20, self.l, 60)] - print("points", pts) + + x = 20 + pts = [] + while x < self.l: + pts.append((x-self.l/2, 0)) + x += 60 + #print("points", pts) w = (w.copyWorkplane(xy) .transformed(offset=(0,0,17)) .pushPoints(pts) .hole(5)) # TODO replace with counterbore and get proper diameter return w -plate = (cq.Workplane("XY") - .rect(200, 200) - .extrude(10) - .faces(">Z") - .workplane() - .tag("railmount") - .end() - ) -hgr20 = HGR20(plate.workplaneFromTagged("railmount"), 300) -plate2 = hgr20.holes(plate) -hgrtest = hgr20.rail() -show_object(plate2) -show_object(hgrtest) \ No newline at end of file + W = 44 + H = 30 + H1 = 4.6 + L = 77.5 + L1 = 50.1 # for HGH20CA, TODO deal with variations + B = 32 + C = 36 + l = 5 # M5x6 + T = 6 + + def carriage(self, x): # HGH20CA + W = 44 + H = 30 + H1 = 4.6 + L = 77.5 + L1 = 50.1 # for HGH20CA, TODO deal with variations + B = 32 + C = 36 + l = 5 # M5x6 + T = 6 + xy = cq.Workplane().copyWorkplane(self.base) + w = xy.transformed((90, 90, 0), (-self.l/2 + x, 0, 0)).tag("endplane") + # TODO + + + s = (cq.Sketch() + .segment((W/2, H1), (W/2, H)) + .segment((-W/2, H)) + .segment((-W/2, H1)) + .segment((W/2, H1)) + .assemble() + ) + s = s.face(HGR20.rail_sketch().assemble(), mode="s") + s2 = (cq.Sketch() + .segment((W/2, H1), (W/2, H-3)) + .segment((-W/2, H-3)) + .segment((-W/2, H1)) + .segment((W/2, H1)) + .assemble() + ) + s2 = s2.face(HGR20.rail_sketch().assemble(), mode="s") + + pts = [] + def savePointsF(l, p): + l.append(p) + return p + #origin = w.workplane().plane.toWorldCoords(cq.Vector(0, 0, 0)) + #norm = w.workplane().plane.toWorldCoords(cq.Vector(0, 1, 0)) + #norm = norm - origin + #print(norm) + # FINALLY GOT THIS WORKING + w = (w.transformed((0, 0, 0), (0, 0, L/2-L1/2)) + .placeSketch(s).extrude(L1) + .workplaneFromTagged("endplane") + .placeSketch(s2) + .extrude(L) + #.faces(cq.DirectionMinMaxSelector(norm, True)) + .faces(">y") + .workplane() + .transformed((0, 0, 0), (L/2 + x, 0, 0)) + .rect(C, B) + .tag("mountingholes") + .vertices() # carriage mounting holes are here! + #.extrude(20) + .hole(l, T) + ) + return w + + def carriageHoles(self, w, x): + W = 44 + H = 30 + H1 = 4.6 + L = 77.5 + L1 = 50.1 # for HGH20CA, TODO deal with variations + B = 32 + C = 36 + l = 5 # M5x6 + T = 6 + xy = cq.Workplane().copyWorkplane(self.base).transformed(offset=(0, 0, H)) + holes = (xy.transformed((0, 0, 0), (-self.l/2+L/2 + x, 0, 0)) + .rect(C, B) + .vertices() + .cylinder(1000, l/2) + ) + w = (w.cut(holes)) + return w + +class Plate: + # TODO add standard thicknesses here + pass + + +def inch(x): + return 25.4*x + +def tubing(l, x, y, w, workplane): + return (workplane + .placeSketch(cq.Sketch() + .rect(x, y) + .rect(x - 2*w, y-2*w, mode='s')) + .extrude(l)) + + +if __name__ == "__main__": + plate = (cq.Workplane("XY") + .rect(200, 200) + .extrude(10) + .faces(">Z") + .workplane() + .tag("railmount") + .end() + ) + + hgr20 = HGR20(plate.workplaneFromTagged("railmount"), 300) + plate2 = hgr20.holes(plate) + hgrtest = hgr20.rail() + carriage = hgr20.carriage(0) + plate3 = (cq.Workplane("XY") + .copyWorkplane(carriage.workplaneFromTagged("mountingholes")) + .rect(200, 200) + .extrude(5) + ) + plate3 = hgr20.carriageHoles(plate3, 0) + tube1 = tubing(500, inch(2), inch(1), inch(0.062), cq.Workplane("XZ")) + + ball_screw = SFU1204(cq.Workplane(), 500) + + #show_object(plate2) + #show_object(hgrtest) + #show_object(carriage) + #show_object(plate3) + #show_object(tube1) + + show_object(ball_screw.ballscrew()) + show_object(ball_screw.nut(200)) + nut_holder = (cq.Workplane("XZ") + .transformed(offset=(0, 0, -200-50)) + .rect(40, 30) + .extrude(50) + .faces(">z") + .hole(12.4) + ) + nut_holder = ball_screw.nutHoles(nut_holder, 200) + fixed = ball_screw.fixedBearing() + show_object(nut_holder) + show_object(fixed) + bearing_holder = (cq.Workplane("XZ") + .transformed(offset=(0, 0, 0)) + .rect(60, 80) + .extrude(20) + .faces(">z") + .hole(12.4) + ) + bearing_holder = ball_screw.fixedBearingHoles(bearing_holder) + show_object(bearing_holder) + bearing2 = ball_screw.floatingBearing() + show_object(bearing2) + bearing_holder2 = (cq.Workplane("XZ") + .transformed(offset=(0, 0, -540)) + .rect(60, 80) + .extrude(20) + .faces(">z") + .hole(12.4) + ) + bearing_holder2 = ball_screw.floatingBearingHoles(bearing_holder2) + show_object(bearing_holder2) + + #show_object(cq.Workplane().placeSketch(HGR20.rail_sketch().assemble()).extrude(10)) \ No newline at end of file