class StepperGear(TrapezoidalGear): """ This is a length of threaded rod (without thread) """ # Parameters gear_od = PositiveFloat(8, doc="Gear diameter") gear_length = PositiveFloat(2, doc="Gear length") # default appearance _render = render_props(color=(200, 200, 200)) # dark grey def make(self): r = super(StepperGear, self).make() r = r.faces(">Z").circle((self.gear_od) / 2).extrude(self.gear_length) # cut out shaft e = 0.03 # Margin of error w = e + 3.0 / 2 # distance of flat tab l = 4.0 / 2 # distance along flat tab (no error term as that is in the c term c = e + 0.5 # Curved end r = r.cut( cadquery.Workplane("XY").transformed(offset=(0, 0, -5)).lineTo( w, 0).lineTo(w, l).threePointArc( (0, l + c), (-w, l)).lineTo(-w, -l).threePointArc( (0, -l - c), (w, -l)).lineTo(w, 0).close().extrude(20)) return r # Construct mating points for two axes @property def mate_shaft(self): """This is the top of the box""" return Mate( self, CoordSystem(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 0, 1)))
class ThreadedRod(H3Part): """ This is a length of threaded rod (without thread) """ # Parameters rod_od = PositiveFloat(8, doc="Rod diameter") rod_length = PositiveFloat(200, doc="Rod length") # default appearance _render = render_props(color=(200, 200, 200)) # dark grey def make(self): # Outside face r = cadquery.Workplane("YZ").circle( (self.rod_od) / 2).extrude(self.rod_length) # r = r.faces(">X").circle((self.gear_od)/2).extrude(self.gear_length) return r # Construct mating points def mate_along(self, distance=0, xDir=(1, 0, 0), normal=(0, -1, 0), rotation=(0, 0, 0)): """Mating along rod""" return Mate( self, CoordSystem(origin=(distance, 0, 0), xDir=xDir, normal=normal).rotated(rotation), )
class sertest(cqparts.Part): length = PositiveFloat(24, doc="") diam = PositiveFloat(5, doc="diameter") def make(self): ob = cq.Workplane("XY").circle(self.diam / 2).extrude(self.length) return ob
class Shaft(cqparts.Part): " base shaft , override ME" length = PositiveFloat(24, doc="shaft length") diam = PositiveFloat(5, doc="shaft diameter") _render = render_props(color=(50, 255, 255)) def make(self): shft = cq.Workplane("XY")\ .circle(self.diam/2)\ .extrude(self.length)\ .faces(">Z")\ .chamfer(0.4) return shft def cut_out(self): cutout = cq.Workplane("XY")\ .circle(self.diam/2)\ .extrude(self.length) return cutout # TODO , mate for shafts def get_cutout(self, clearance=0): " clearance cut out for shaft " return cq.Workplane('XY', origin=(0, 0, 0)) \ .circle((self.diam / 2) + clearance) \ .extrude(self.length*2)
class ThreadedRod(cqparts.Part): """ This is a length of threaded rod (without thread) """ # Parameters rod_od = PositiveFloat(8, doc="Rod diameter") rod_length = PositiveFloat(200, doc="Rod length") # default appearance _render = render_props(color=(200, 200, 200)) # dark grey def make(self): # Outside face r = cadquery.Workplane("YZ").circle( (self.rod_od) / 2).extrude(self.rod_length) # r = r.faces(">X").circle((self.gear_od)/2).extrude(self.gear_length) return r # Construct mating points @property def mate_start(self): return Mate( self, CoordSystem(origin=(0, 0, 0), # xDir=(1, 0, 0), normal=(0, -1, 0), ))
class Drive(cqparts.Assembly): threaded = PartRef(Threaded) lift = PositiveFloat(10) length = PositiveFloat(100) def make_components(self): comps = {"drive": self.threaded(length=self.length)} return comps def make_constraints(self): constr = [ Fixed( self.components["drive"].mate_origin, CoordSystem((0, 0, 0), (0, 1, 0), (1, 0, 0)), ) ] return constr def mate_mount(self, offset=0): return Mate( self, CoordSystem(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 0, 1))) def make_alterations(self): pass
class _Stator(cqparts.Part): # Parameters width = PositiveFloat(40.0, doc="Motor Size") length = PositiveFloat(20, doc="stator length") cham = PositiveFloat(3, doc="chamfer") _render = render_props(color=(50, 50, 50)) def make(self): base = (cq.Workplane("XY").box( self.width, self.width, self.length, centered=(True, True, True)).edges("|Z").chamfer(self.cham)) return base @property def mate_top(self): " top of the stator" return Mate( self, CoordSystem(origin=(0, 0, self.length / 2), xDir=(0, 1, 0), normal=(0, 0, 1)), ) @property def mate_bottom(self): " bottom of the stator" return Mate( self, CoordSystem(origin=(0, 0, -self.length / 2), xDir=(1, 0, 0), normal=(0, 0, -1)), )
class TrainWheels(cqparts.Assembly): width = PositiveFloat(20) diameter = PositiveFloat(10) axle = PositiveFloat(2) wheel = PartRef(TrainTyre) def initialize_parameters(self): self.ww = self.wheel().width self.aw = self.width + self.ww * 2 def make_components(self): return { "axle": TrainAxle(axle=self.axle, width=self.aw), "lwheel": TrainTyre(axle=self.axle), "rwheel": TrainTyre(axle=self.axle), } def make_constraints(self): return [ Fixed(self.components["axle"].mate_origin), Coincident(self.components["lwheel"].mate_origin, self.components["axle"].mate_left), Coincident( self.components["rwheel"].mate_origin, self.components["axle"].mate_right, ), ] def apply_cutout(self, part): # Cut wheel & axle from given part axle = self.components["axle"] local_obj = part.local_obj local_obj = local_obj.cut((axle.world_coords - part.world_coords) + axle.get_cutout(clearance=0.1)) part.local_obj = local_obj
class _EndCap(cqparts.Part): # Parameters width = PositiveFloat(42.3, doc="Motor Size") length = PositiveFloat(10, doc="End length") cham = PositiveFloat(3, doc="chamfer") # _render = render_props(color=(50, 50, 50),alpha=0.4) def make(self): base = (cq.Workplane("XY").box(self.width, self.width, self.length).edges("|Z").chamfer( self.cham)) return base @property def mate_top(self): " connect to the end of the top cap" return Mate( self, CoordSystem(origin=(0, 0, -self.length / 2), xDir=(0, 1, 0), normal=(0, 0, -1)), ) @property def mate_bottom(self): " bottom of the top cap" return Mate( self, CoordSystem(origin=(0, 0, -self.length / 2), xDir=(0, 1, 0), normal=(0, 0, 1)), )
class _StepperMount(_EndCap): spacing = PositiveFloat(31, doc="hole spacing") hole_size = PositiveFloat(3, doc="hole size") boss = PositiveFloat(22, doc="boss size") boss_length = PositiveFloat(2, doc="boss_length") def make(self): obj = super(_StepperMount, self).make() obj.faces(">Z").workplane().rect(self.spacing, self.spacing, forConstruction=True).vertices().hole( self.hole_size) obj.faces(">Z").workplane().circle(self.boss / 2).extrude( self.boss_length) return obj @property def mate_top(self): " top of the mount" return Mate( self, CoordSystem(origin=(0, 0, self.length / 2), xDir=(0, 1, 0), normal=(0, 0, 1)), ) @property def mate_bottom(self): " bottom of the mount" return Mate( self, CoordSystem(origin=(0, 0, -self.length / 2), xDir=(0, 1, 0), normal=(0, 0, 1)), )
class TrainPan(cqparts.Part): length = PositiveFloat(35) width = PositiveFloat(12) height = PositiveFloat(0) wagon = PartRef() magnet = PartRef() _render = render_props(template="steel") def make(self): wp = cq.Workplane("XY") pan = wp.box(self.width, self.length, self.height, centered=(True, True, False)).chamfer(0.2) if self.wagon is not None: w = self.wagon(width=self.width, length=self.length).make() w = w.translate((0, 0, self.height)) pan = pan.union(w) return pan def mate_lift(self, lift=0): return Mate( self, CoordSystem(origin=(0, 0, -lift), xDir=(1, 0, 0), normal=(0, 0, 1))) @property def mate_top(self): return Mate( self, CoordSystem(origin=(0, 0, self.height), xDir=(1, 0, 0), normal=(0, 0, 1)), ) def mate_end(self, direction): return Mate( self, CoordSystem( origin=(0, direction * self.length / 2, self.height / 2), xDir=(1, 0, 1), normal=(0, direction, 0), ), ) # returns the mates for the wheels def wheel_points(self, inset=0, axle=0): mps = [] pos = [1, -1] for i in pos: m = Mate( self, CoordSystem( origin=(0, i * (self.length / 2 - inset), axle), xDir=(0, 0, 1), normal=(0, i, 0), ), ) mps.append(m) return mps
class Template(cqparts.Part): length = PositiveFloat(24) diam = PositiveFloat(5) _render = render_props(color=(50, 255, 255)) def make(self): shft = cq.Workplane("XY").circle(self.diam / 2).extrude(self.length) return shft def cut_out(self): cutout = cq.Workplane("XY").circle(self.diam / 2).extrude(self.length) return cutout def get_cutout(self, clearance=0): " clearance cut out for shaft " return (cq.Workplane( "XY", origin=(0, 0, 0)).circle((self.diam / 2) + clearance).extrude(self.length * 2)) def mate_tip(self, offset=0): return Mate( self, CoordSystem(origin=(0, 0, self.length), xDir=(1, 0, 0), normal=(0, 0, 1)), )
class WoodScrew(cqparts.Part): diameter = PositiveFloat(default=3, doc="bore hole diameter") thread_length = PositiveFloat(default=5, doc="distance the screw bores into part") # TODO: more parameters def make(self): TODO: code for wood screw make()
class ControlRow(cqparts.Assembly): length = PositiveFloat(100) width = PositiveFloat(100) def initialize_parameters(self): self.controls = [] def add(self, i): self.controls.append(i) def populate(self): pass @classmethod def item_name(cls, index): return "item_%03i" % index def make_components(self): self.populate() items = {} for i in range(len(self.controls)): items[self.item_name(i)] = self.controls[i] return items def make_constraints(self): for i in self.controls: print(dir(i)) print(i) return []
class XAxis(Axis): height = PositiveFloat(65) width = PositiveFloat(50) rails = PartRef(SingleRail) drive_lift = Float(30) rail_lift = Float(50) carriage = PartRef(XSlide) # drive_end = PartRef(XDrive) pos = PositiveFloat(100) drive = PartRef(ThreadedDrive)
class _PlaceHolder(cqparts.Part): length = PositiveFloat(10) width = PositiveFloat(10) height = PositiveFloat(10) _render = render_props(template="steel") def make(self): return cq.Workplane("XY").box(self.length, self.width, self.height, centered=(False, True, False))
class _Back(_EndCap): spacing = PositiveFloat(31, doc="hole spacing") hole_size = PositiveFloat(3, doc="hole size") def make(self): obj = super(_Back, self).make() obj.faces(">Z").workplane().rect(self.spacing, self.spacing, forConstruction=True).vertices().hole( self.hole_size) return obj
class _Shelf(cqparts.Part): length = PositiveFloat(None, doc="cube size") width = PositiveFloat(None, doc="cube size") shelf_t = PositiveFloat(None, doc="cube size t") cx = PositiveFloat(None, doc="leg width from hole to glass corner") r3 = Float(80, doc="shelf r3") s1 = Float(-40, doc="shelf s1") s2 = Float(-100, doc="shelf s2") s3 = Float(40, doc="shelf s3") _render = render_props(template="wood") def make(self): r3 = self.r3 s1 = self.s1 s2 = self.s2 s3 = self.s3 x2 = (self.length - 0.85 * math.sqrt(self.cx ** 2 / 2)) / 2.0 x1 = x2 - r3 y1 = (self.width - 0.85 * math.sqrt(self.cx ** 2 / 2)) / 2.0 y2 = y1 - r3 p0 = (-x1, y1, 0) p2 = (x1, y1, 0) p4 = (x2, y2, 0) p6 = (x2, -y2, 0) p8 = (x1, -y1, 0) p10 = (-x1, -y1, 0) p12 = (-x2, -y2, 0) p14 = (-x2, y2, 0) m = ( cq.Workplane("XY", origin=(0, 0, -self.shelf_t)) .moveTo(-x1, y1) .sagittaArc(p2, s1) .radiusArc(p4, s2) .sagittaArc(p6, s3) .radiusArc(p8, s2) .sagittaArc(p10, s1) .radiusArc(p12, s2) .sagittaArc(p14, s3) .radiusArc(p0, s2) .close() .extrude(self.shelf_t) .edges("|Z") .fillet(20) .faces("|Z") .edges() .fillet(4) ) return m
class Carriage(_AxisBase): pos = PositiveFloat(0) rails = PartInst(Rails) bearing = PartRef(lm8uu) driven = PartRef(Bearing) # thie driver , depends on the type lift = PositiveFloat(0) clearance = PositiveFloat(10) def initialize_parameters(self): self.length = self.bearing().length # Override me def make_block(self): return _PlaceHolder(height=self.height - self.clearance, width=self.width, length=self.length) def make_components(self): comps = {"block": self.make_block(), "driven": self.driven()} for i, j in enumerate(self.rails.rail_pos()): comps[Rails.rail_name(i)] = self.bearing() return comps def make_constraints(self): constr = [ Fixed( self.components["block"].mate_origin, CoordSystem((self.pos, 0, self.clearance), (1, 0, 0), (0, 0, 1)), ), Fixed( self.components["driven"].mate_origin, CoordSystem((self.pos, 0, self.lift), (0, 1, 0), (1, 0, 0)), ), ] for i, j in enumerate(self.rails.rail_pos()): item = self.components[Rails.rail_name(i)] p = j.local_coords.origin m = Fixed( item.mate_origin, CoordSystem((p.x + self.pos, p.y, p.z), (0, 1, 0), (1, 0, 0)), ) constr.append(m) return constr def make_alterations(self): block = self.components["block"] driven = self.components["driven"] driven.make_cutout(part=block) for i, j in enumerate(self.rails.rail_pos()): item = self.components[Rails.rail_name(i)] item.make_cutout(part=block)
class Wagon(cqparts.Part): length = PositiveFloat(25) width = PositiveFloat(10) height = PositiveFloat(6) _render = render_props(template="wood") def make(self): wp = cq.Workplane("XY") block = wp.box(self.width, self.length, self.width, centered=(True, True, False)).chamfer(0.2) return block
class TrainCouplingMagnet(cqparts.Part): width = PositiveFloat(3) diameter = PositiveFloat(8) _render = render_props(template="tin") def initialize_parameters(self): self.hub_diameter = self.diameter * 0.6 def make(self): wp = cq.Workplane("XY") hub = (wp.workplane(offset=self.width / 2).circle( self.hub_diameter / 2).extrude(self.width / 2)) hub = hub.faces(">Z").chamfer(self.hub_diameter / 9) return hub
class Mill(cqparts.Assembly): length = PositiveFloat(250) width = PositiveFloat(300) height = PositiveFloat(100) xaxis = PartRef(XAxis) yaxis = PartRef(Axis) zaxis = PartRef(Axis) padding = PositiveFloat(20) base_thickness = PositiveFloat(6) def initialize_paramters(self): pass def make_components(self): comps = { "base": Plank(thickness=self.base_thickness, length=self.length + self.padding * 4.0, width=self.width + self.padding * 3.0), "XL": self.xaxis(length=self.length), "XR": self.xaxis(length=self.length), # "YA": self.yaxis(length=self.width), } return comps def make_constraints(self): base = self.components["base"] constr = [ Fixed(base.mate_origin), Fixed( self.components["XL"].mate_origin, CoordSystem( (-self.length / 2.0, -self.width / 2.0, base.thickness), (1, 0, 0), (0, 0, 1)), ), Fixed( self.components["XR"].mate_origin, CoordSystem( (-self.length / 2.0, self.width / 2.0, base.thickness), (1, 0, 0), (0, 0, 1)), ), # Fixed( # self.components["YA"].mate_origin, # CoordSystem((0,self.length/2 , 0), (0, -1, 0), (0, 0, 1)), # ), ] return constr
class LED(cqparts.Part): length = PositiveFloat(4.0) diam = PositiveFloat(5.0) base_thickness = PositiveFloat(1.0) base_rim = PositiveFloat(1.0) _render = render_props(color=(200, 0, 0)) def make(self): LED = ( cq.Workplane("XZ") .lineTo(self.diam / 2, 0) .lineTo(self.diam / 2, self.length) .radiusArc((0, self.length + self.diam / 2), -self.diam / 2) .close() ) LED = LED.revolve(axisStart=(0, 0, 0), axisEnd=(0, 1, 0)) base = ( cq.Workplane("XY") .circle((self.base_rim + self.diam) / 2) .extrude(-self.base_thickness) ) mark = ( cq.Workplane("XY") .rect(self.diam + self.base_rim, self.base_thickness) .extrude(-self.base_thickness) ) mark = mark.translate((0, (self.base_rim + self.diam) / 2, 0)) base = base.cut(mark) LED = LED.union(base) return LED def cut_out(self): cutout = cq.Workplane("XY").circle(self.diam / 2).extrude(self.length) return cutout def get_cutout(self, clearance=0): return ( cq.Workplane("XY", origin=(0, 0, 0)) .circle((self.diam / 2) + clearance) .extrude(self.length * 2) ) def mate_base(self, offset=0): return Mate( self, CoordSystem(origin=(0, 0, self.length), xDir=(1, 0, 0), normal=(0, 0, 1)), )
class TrainTyre(cqparts.Part): width = PositiveFloat(3) diameter = PositiveFloat(10) axle = PositiveFloat(1) _render = render_props(template="yellow") def initialize_parameters(self): self.hub_diameter = self.diameter / 2 def make(self): wp = cq.Workplane("XY") wheel = (wp.circle(self.diameter / 2).extrude(self.width).fillet( self.width / 2.2)) axle = wp.circle(self.axle / 2).extrude(self.width) wheel.cut(axle) return wheel
class Train(cqparts.Assembly): cars = [] loco = PartRef(Bogie(wagon=Loco)) axle = PositiveFloat(2) @classmethod def car_name(cls, index): return "car_%03i" % index def add_car(self, car): self.cars.insert(0, car) def make_components(self): self.loco.axle = self.axle self.cars.append(self.loco) comp = {} if len(self.cars) > 0: for i, j in enumerate(self.cars): j.axle = self.axle comp[Train.car_name(i)] = j return comp def make_constraints(self): constr = [Fixed(self.components[Train.car_name(0)].mate_origin)] self.cars.reverse() for i in range(1, len(self.cars)): last_car = self.components[Train.car_name(i - 1)].mate_end(-1) this_car = self.components[Train.car_name(i)].mate_end(1) constr.append(Coincident(this_car, last_car)) return constr
class SideConstruct(cqparts.Part): # Parameters seperation = PositiveFloat(40, doc="bar seperation") # default appearance _render = render_props(color=(250, 50, 90)) def make(self): plate = cadquery.Workplane("XY").box(self.seperation+2, 2, 0.5)\ .faces(">Y").workplane() \ .pushPoints([(0, self.seperation/2), (0, -self.seperation/2)]) \ .hole(0.125) return plate # Construct mating points for two axes @property def mate_left(self): return Mate( self, CoordSystem( origin=(0, self.seperation / 2, 0), xDir=(1, 0, 0), normal=(0, -1, 0), )) @property def mate_right(self): print('Mating right') return Mate( self, CoordSystem( origin=(0, -self.seperation / 2, 0), xDir=(1, 0, 0), normal=(0, 1, 0), ))
class Stepper_Holder(cqparts.Part): """ This is a holder for astandard 28BYJ-48 stepper motor """ # default appearance _render = render_props(color=(20, 20, 150)) # Parameters body_length = PositiveFloat(61, doc="Body length") motor_od = 28.5 def rod_block(self, workplane, offset): r = workplane.transformed(offset=(offset, 0, 0)).box(15, 15, self.body_length) return r def base_plate(self, workplane): r = workplane.transformed(offset=(-BAR_SEPERATION / 2, -6.5, 0)).box(BAR_SEPERATION, 2, self.body_length) return r def mounting_block(self, workplane, offset): r = workplane.transformed(offset=(offset, 13.5, 10)).box(15, 12, 30) return r def make(self): # Outside face r = self.rod_block(cadquery.Workplane("YZ"), 0) r = r.union(self.rod_block(r.faces(">X"), -BAR_SEPERATION)) r = r.union( self.mounting_block(r.faces(">X"), -20 + BAR_SEPERATION / 2)) r = r.union(self.mounting_block(r.faces(">X"), -BAR_SEPERATION)) r = r.union(self.base_plate(r.faces(">X"))) # add holes for bars r = r.faces(">X").workplane().transformed(offset=(0, 0.625, 0)).\ rect(BAR_SEPERATION, 0, forConstruction=True).vertices().hole(8.5) # cut out to fit motor r = r.faces(">Z").workplane().transformed(offset=(-2, 0, 0)).\ hole(self.motor_od) # add some holes for mounting nut inserts to hold motor in r = r.faces("<Z").workplane().transformed(offset=(9.5, 0, 0)).\ rect(0, 36, forConstruction=True).vertices().hole(3) # add some holes for mounting or zip ties r = r.faces("<Z").workplane().transformed(offset=(-10, 0, 0)).\ rect(10, 20, forConstruction=True).vertices().hole(3) #r = r.faces(">X").workplane().lineTo(0, BAR_SEPERATION, forConstruction=True).vertices().hole(11) return r # Construct mating points for two axes @property def mate_centre(self): return Mate( self, CoordSystem( origin=(-self.body_length / 2, -BAR_SEPERATION / 2, 0), xDir=(1, 0, 0), normal=(0, 0, 1), ))
class Gallery(cqparts.Assembly): offset = PositiveFloat(60) def initialize_parameters(self): self.coll = [] def add(self, i): self.coll.append(i) @classmethod def item_name(cls, index): return "item_%03i" % index def make_components(self): items = {} for i in range(len(self.coll)): items[self.item_name(i)] = self.coll[i] return items def make_constraints(self): constraints = [] # calculate on bounding boxes for i in range(len(self.coll)): print(self.coll[i].bounding_box.wrapped) #constraints.append( # Fixed( # self.coll[i].mate_origin, # CoordSystem( # origin=(0, i * self.offset - (total / 2) + self.offset / 2, 0), # xDir=(1, 0, 0), # normal=(0, 0, 1), # ), # ) #) return constraints
class Arrange(cqparts.Assembly): offset = PositiveFloat(60) def initialize_parameters(self): self.coll = [] def add(self, i): self.coll.append(i) @classmethod def item_name(cls, index): return "item_%03i" % index def make_components(self): items = {} for i in range(len(self.coll)): items[self.item_name(i)] = self.coll[i] return items def make_constraints(self): constraints = [] length = len(self.coll) total = length * self.offset for i in range(len(self.coll)): constraints.append( Fixed( self.coll[i].mate_origin, CoordSystem( origin=(0, i * self.offset - (total / 2) + self.offset / 2, 0), xDir=(1, 0, 0), normal=(0, 0, 1), ), )) return constraints
class _AxisBase(cqparts.Assembly): length = PositiveFloat(10) width = PositiveFloat(10) height = PositiveFloat(10) def make_components(self): comps = { "block": _PlaceHolder(length=self.length, width=self.width, height=self.height) } return comps def make_constraints(self): return [Fixed(self.components["block"].mate_origin)]