import math import cadquery as cq from ocp_vscode import * import localselectors class SFU1204: def __init__(self, base, l): self.w = cq.Workplane().copyWorkplane(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 = cq.Workplane().copyWorkplane(self.w).moveTo(0, 0) for v in profile[1:]: w = w.lineTo(v[1], v[0]) w = w.close() return w.revolve() def nut(self, x): w = cq.Workplane().copyWorkplane( 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) .copyWorkplane(w) .transformed(offset=(0, 0, 10)) .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 def nutHoles(self, solid, x): w = ( cq.Workplane() .copyWorkplane(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, 0), rotate=(-90, 180, 0)) w2 = w.transformed(offset=(0, h - H1 / 2, 0)) w3 = w.transformed(offset=(0, E / 2, 0)) bearing = ( w.rect(B1, B1) .extrude(L1 + L) .copyWorkplane(w2) .rect(B, H1) .extrude(L) .copyWorkplane(w2.transformed(offset=(0, 0, L))) .tag("mounting face") .copyWorkplane(w.transformed(rotate=(180, 0, 0))) .hole(d1) .copyWorkplane(w3.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, -E / 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 + 7 / 2 - L / 2, 0), rotate=(-90, 0, 0) ) b = ( w.rect(B1, B1) .extrude(L) .copyWorkplane(w.transformed(offset=(0, 0, L), rotate=(0, 0, 180))) .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, -E / 2) .rect(P, E, forConstruction=True) .vertices() .hole(d2) .copyWorkplane(w) .circle(30 / 2) .extrude(L / 2 - 7 / 2, combine="s") .workplaneFromTagged("floating_far_end") .transformed(rotate=(180, 0, 0)) .circle(30 / 2) .extrude(L / 2 - 7 / 2, combine="s") ) 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 - 20, 0), rotate=(90, 0, 0)) solid = ( solid.copyWorkplane(w) .center(0, -E / 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 = [] 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, 90, 0), (-self.l / 2, 0, 0)) w = w.placeSketch(HGR20.rail_sketch().assemble()) w = w.extrude(self.l) 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 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 ( cq.Workplane() .copyWorkplane(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))