def make_reservation(self): vss = self.get_ventscrews_a() sr = CQ().box(self.reserve_xy, self.reserve_xy, self.reserve_h, centered=(True, True, False)) sr = sr.translate( (0, 0, -self.pcb_thickness - self.pcb_spacer_h - self.cu_base_t)) wires = CQ().box(self.wire_slot_depth, 2.54 * 20, 2.54 * 2, centered=(False, True, False)).translate( (-self.reserve_xy / 2, 0, self.wire_slot_z + self.pcb_thickness / 2)) wiresA = wires.translate((0, self.wire_slot_offset, 0)) wiresB = wires.translate((0, -self.wire_slot_offset, 0)) sr = sr.cut(wiresA).cut(wiresB).add(vss) # these next two lines are very expensive (and optional)! sr = sr.add(self.get_pcb()) #sr = CQ().union(sr) return sr
def mkwalls( aso: cadquery.Assembly, height: float, cshift, extents, hps, zbase: float, ): """the chamber walls""" name = "walls" color = cadquery.Color("GRAY55") thickness = 12 inner = (extents[0] - 2 * thickness, extents[1] - 2 * thickness) inner_shift = cshift outer_fillet = 2 inner_fillet = 6 chamfer = 0.75 nut = HexNut(size="M5-0.8", fastener_type="iso4033") # HNN-M5-A2 flat_to_flat = math.sin(60 * math.pi / 180) * nut.nut_diameter + 0.25 gas_fitting_hole_diameter = 20.6375 # 13/16" gas_fitting_recess = 6.35 gas_fitting_flat_to_flat = 22.22 + 0.28 gas_fitting_diameter = 25.66 + 0.34 back_holes_shift = 45 back_holes_spacing = 27 front_holes_spacing = 75 fitting_step_xy = ( 3, 15) # dims of the little step for the vac fitting alignment fitting_step_center = (-fitting_step_xy[0] / 2 + inner[0] / 2 + cshift[0], extents[1] / 2 - fitting_step_xy[1] / 2 - thickness) wp = CQ().workplane(offset=zbase).sketch() wp = wp.push([cshift ]).rect(extents[0], extents[1], mode="a").reset().vertices().fillet(outer_fillet) wp = wp.push([inner_shift]).rect(inner[0], inner[1], mode="s").reset() dummy_xy = (fitting_step_xy[0], inner[1]) dummy_center = (fitting_step_center[0], 0) wp = wp.push([dummy_center]).rect( *dummy_xy, mode="a") # add on a dummy bit that we'll mostly subtract away wp = wp.finalize().extrude(height).edges("|Z").fillet(inner_fillet) sub_xy = (40, inner[1] - fitting_step_xy[1]) sub_center = (-sub_xy[0] / 2 + inner[0] / 2 + cshift[0], -fitting_step_xy[1] / 2) wp2 = CQ().workplane(offset=zbase).sketch().push([sub_center ]).rect(*sub_xy, mode="a") wp2 = wp2.finalize().extrude(height).edges("|Z").fillet(inner_fillet) wp = wp.cut(wp2) # wp = CQ().workplane(offset=zbase).sketch() # wp = wp.push([cshift]).rect(extents[0], extents[1], mode="a").reset().vertices().fillet(outer_fillet) # wp = wp.push([inner_shift]).rect(inner[0], inner[1], mode="s") # .reset().vertices().fillet(inner_fillet) # wp = wp.finalize().extrude(height) wp: cadquery.Workplane # shouldn't have to do this (needed for type hints) wall_hardware = cq.Assembly(None, name="wall_hardware") # corner holes (with nuts and nut pockets) wp = wp.faces(">Z").workplane( **u.copo, offset=-nut.nut_thickness).pushPoints(hps).clearanceHole( fastener=nut, fit="Close", counterSunk=False, baseAssembly=wall_hardware) wp = wp.faces(">Z").workplane(**u.copo).sketch().push(hps[0:4:3]).rect( flat_to_flat, nut.nut_diameter, angle=45).reset().push( hps[1:3]).rect(flat_to_flat, nut.nut_diameter, angle=-45).reset().vertices().fillet( nut.nut_diameter / 4).finalize().cutBlind(-nut.nut_thickness) # chamfers wp = wp.faces(">Z").edges(">>X").chamfer(chamfer) # gas holes with recesses wp = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift, 0).rarray(back_holes_spacing, 1, 2, 1).hole(diameter=gas_fitting_hole_diameter, depth=thickness) # wp = wp.faces("<X").workplane(**u.cobb).center(back_holes_shift, 0).sketch().rarray(back_holes_spacing, 1, 2, 1).rect(gas_fitting_diameter, gas_fitting_flat_to_flat).reset().vertices().fillet(gas_fitting_diameter / 4).finalize().cutBlind(-gas_fitting_recess) wp = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift, 0).sketch().rect( 2 * gas_fitting_diameter / 2 + back_holes_spacing, gas_fitting_flat_to_flat).reset().vertices().fillet( gas_fitting_diameter / 4).finalize().cutBlind( -gas_fitting_recess) # unify the back holes wp = wp.faces(">X").workplane(**u.cobb).rarray( front_holes_spacing, 1, 2, 1).hole(diameter=gas_fitting_hole_diameter, depth=thickness) wp = wp.faces(">X").workplane(**u.cobb).sketch().rarray( front_holes_spacing, 1, 2, 1).rect(gas_fitting_diameter, gas_fitting_flat_to_flat).reset().vertices().fillet( gas_fitting_diameter / 4).finalize().cutBlind(-gas_fitting_recess) # that's part number polymax 230X2N70 o_ring_thickness = 2 o_ring_inner_diameter = 230 ooffset = 17 # two times the o-ring path's center offset from the outer edge of the walls # cut the lid o-ring groove wp = wp.faces(">Z").workplane(**u.cobb).mk_groove( ring_cs=o_ring_thickness, follow_pending_wires=False, ring_id=o_ring_inner_diameter, gland_x=extents[0] - ooffset, gland_y=extents[1] - ooffset, hardware=wall_hardware) # cut the base o-ring groove wp = wp.faces("<Z").workplane(**u.cobb).mk_groove( ring_cs=o_ring_thickness, follow_pending_wires=False, ring_id=o_ring_inner_diameter, gland_x=extents[0] - ooffset, gland_y=extents[1] - ooffset, hardware=wall_hardware) # get pipe fitting geometry a_pipe_fitting = u.import_step( wrk_dir.joinpath( "components", "5483T93_Miniature Nickel-Plated Brass Pipe Fitting.step")) a_pipe_fitting = a_pipe_fitting.translate( (0, 0, -6.35 - gas_fitting_recess)) pipe_fitting_asy = cadquery.Assembly(a_pipe_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=30), name="one_pipe_fitting") # move the pipe fittings to their wall holes wppf = wp.faces(">X").workplane(**u.cobb).center( front_holes_spacing / 2, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="front_right_gas_fitting") wppf = wppf.center(-front_holes_spacing, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="front_left_gas_fitting") wppf = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift + back_holes_spacing / 2, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="rear_left_gas_fitting") wppf = wppf.center(-back_holes_spacing, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="rear_right_gas_fitting") # get bonded washer geometry, part 229-6277 bonded_washer = u.import_step( wrk_dir.joinpath("components", "hutchinson_ljf_207242.stp")) bonded_washer = bonded_washer.rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=90).translate( (0, 0, 1.25)) bonded_washer_asy = cadquery.Assembly(bonded_washer, name="one_bonded_washer") # move bonded washers to their wall holes washer_thickness = 2.5 wpbw = wp.faces(">X").workplane(**u.cobb, offset=-thickness - washer_thickness).center( -front_holes_spacing / 2, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="front_right_bonded_washer") wpbw = wpbw.center(front_holes_spacing, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="front_left_bonded_washer") wpbw = wp.faces("<X[-5]").workplane(**u.cobb).center( -back_holes_shift - back_holes_spacing / 2, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="rear_right_bonded_washer") wpbw = wpbw.center(back_holes_spacing, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="rear_left_bonded_washer") aso.add(wall_hardware.toCompound(), name="wall_hardware", color=cadquery.Color(hardware_color)) # passthrough details pcb_scr_head_d_safe = 6 n_header_pins = 50 header_length = n_header_pins / 2 * 2.54 + 7.62 # n*0.1 + 0.3 inches support_block_width = 7 pt_pcb_width = 2 * (support_block_width / 2 + pcb_scr_head_d_safe / 2) + header_length pt_pcb_outer_depth = 8.89 + 0.381 # 0.35 + 0.15 inches pt_pcb_inner_depth = 8.89 + 0.381 # 0.35 + 0.15 inches pt_center_offset = 28.65 # so that the internal passthrough connector aligns with the one in the chamber # make the electrical passthrough pt_asy = cadquery.Assembly( ) # this will hold the passthrough part that gets created # pcb_asy = cadquery.Assembly() # this will hold the pcb part that gets created pcb_asy = None # dont generate the base PCB (will probably later import the detailed board model) hw_asy = cadquery.Assembly( ) # this will hold the pcb part that gets created ptt = 5.5 # passthrough thickness, reduce a bit from default (which was half wall thickness) to prevent some thin walls close to an o-ring gland wp = wp.faces("<X").workplane(**u.cobb).center( -pt_center_offset, 0).make_oringer(board_width=pt_pcb_width, board_inner_depth=pt_pcb_inner_depth, board_outer_depth=pt_pcb_outer_depth, wall_depth=thickness, part_thickness=ptt, pt_asy=pt_asy, pcb_asy=pcb_asy, hw_asy=hw_asy) # insert passthrough into assembly for asyo in pt_asy.traverse(): part = asyo[1] if isinstance(part.obj, cadquery.occ_impl.shapes.Solid): aso.add(part.obj, name=asyo[0], color=color) if pcb_asy is not None: # insert pcb into assembly for asyo in pcb_asy.traverse(): # insert only one solid object part = asyo[1] if isinstance(part.obj, cadquery.occ_impl.shapes.Solid): aso.add(part.obj, name=asyo[0], color=cadquery.Color("DARKGREEN")) # insert hardware into assembly aso.add(hw_asy.toCompound(), name="passthrough hardware") # add in little detailed PCB a_little_pcb = u.import_step( wrk_dir.joinpath("components", "pt_pcb.step")).translate( (0, 0, -pcb_thickness / 2)) # shift pcb to be z-centered little_pcb = cadquery.Assembly(a_little_pcb.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=90).rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=90), name="small detailed pcb") asys["squirrel"].add(little_pcb, loc=wp.plane.location, name="little pcb") # for the vac chuck fittings rotation_angle = -155 # degrees vac_fitting_wall_offset = extents[ 1] / 2 - thickness - inner_fillet - 4 # mounting location offset from center wp = wp.faces(">X").workplane(**u.cobb).center( vac_fitting_wall_offset, 0).tapHole(vac_fitting_screw, depth=thickness + fitting_step_xy[0]) vac_chuck_fitting = cadquery.Assembly(a_vac_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=rotation_angle), name="outer_wall_vac_fitting") aso.add(vac_chuck_fitting, loc=wp.plane.location, name="vac chuck fitting (wall outer)") nwp = wp.faces(">X").workplane(**u.cobb, invert=True, offset=thickness + fitting_step_xy[0]).center( vac_fitting_wall_offset, 0) vac_chuck_fitting = cadquery.Assembly(a_vac_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=-rotation_angle), name="inner_wall_vac_fitting") aso.add(vac_chuck_fitting, loc=nwp.plane.location, name="vac chuck fitting (wall inner)") aso.add(wp, name=name, color=color) # add the walls bulk
def _makeNegative(center): """ Generates the pocket shape we'll be cutting out """ # the connector pocket's dimensions pocket_w = connector_width + con_clearance * 2 pocket_l = con_len + con_clearance * 2 pocket_d = connector_height + con_clearance # find the source thing's thickness at the cut point swiss = CQ(self.plane).add(self.findSolid()) cheese = CQ(self.plane).add(self.findSolid()).pushPoints( [center]).circle(0.5).cutThruAll() core = swiss.cut(cheese) this_thikness = u.find_length(core, along="normal", bb_method=False) min_thickness = pocket_d + min_gp_connector_pocket_spacing + gp_depth # check that it's thick enough here if this_thikness < min_thickness: raise (ValueError( f"The part is too thin (thickness = {this_thikness}) at {center} to cut the PCB pocket" )) # make a box to subtract from start_box = CQ("XY").box(100, 100, this_thikness, centered=(True, True, False)) # make a simple pocket that we'll use for the chamfer operation result = start_box.faces("<Z").rect(pocket_w, pocket_l).cutBlind(pocket_d) # chamfer the connector edge result = result.faces("<Z").edges("not(<X or >X or <Y or >Y)").chamfer( chamfer_length) # now make the undercut pocket CQ.undercutRelief2D = u.undercutRelief2D result = result.faces("<Z").workplane().undercutRelief2D( pocket_l, pocket_w, diameter=r * 2, angle=90, kind=kind).cutBlind(pocket_d) # cut out the glue pocket slot_width = c.pcb_thickness + 2 * gp_buffer slot_len = pcb_len + slot_width result = result.faces(">Z").workplane().slot2D( slot_len, slot_width, angle=90).cutBlind(-gp_depth) # cut out the pcb passthrough slot slot_width = c.pcb_thickness + 2 * pcb_clearance slot_len = pcb_len + slot_width result = result.faces(">Z").workplane().slot2D(slot_len, slot_width, angle=90).cutThruAll() # invert the geometry and rotate the negative negative = start_box.cut(result) negative = negative.rotate((0, 0, 0), (0, 0, 1), angle) to_cut = negative.findSolid().locate(center) to_cut = to_cut.mirror("XY") return to_cut