def heat_set_insert(diameter, depth, excess_diameter, excess_depth, taper_angle_degrees = 8, negative_depth=0, negative_diameter=None): """ taper angle is going to specify the deflection off of zero s.t. the diameter is slightly less as you move closer to the bottom. The taper angle specifies the slope of the line off of the radial axis. The excess parameters are for a smaller hole that collects the melted material, so that it's not the same size as the portion that bonds to the insert. negative_depth creates material of exactly diameter but the hole, to create a path to move the insert during assembly and provide screwdriver access. If negative_diameter is specified, that's used instead of the insert hole diameter. """ top_radius = diameter / 2.0 if taper_angle_degrees == 0: bottom_radius = diameter / 2.0 else: bottom_radius = diameter/2.0 - tan(taper_angle_degrees * pi / 180) * depth / 2.0 negative_hole = None if negative_depth != 0: if negative_diameter is None: negative_radius = diameter / 2.0 else: negative_radius = negative_diameter / 2.0 negative_hole = so.translate((0,0,-negative_depth - 0.01))(so.cylinder(r=negative_radius, h=negative_depth + 0.01)) insert_hole = so.translate((0,0,-0.01))(so.cylinder(r1=top_radius, r2=bottom_radius, h=depth + 0.01)) excess_hole = so.translate((0,0,depth - 0.01))(so.cylinder(r=excess_diameter / 2.0, h=excess_depth + 0.01)) total = insert_hole + excess_hole if negative_hole is not None: total += negative_hole return total
def basic_geometry(): # SolidPython code can look a lot like OpenSCAD code. It also has # some syntactic sugar built in that can make it look more pythonic. # Here are two identical pieces of geometry, one left and one right. # left_piece uses standard OpenSCAD grammar (note the commas between # block elements; OpenSCAD doesn't require this) left_piece = union()(translate((-15, 0, 0))(cube([10, 5, 3], center=True)), translate( (-10, 0, 0))(difference()(cylinder(r=5, h=15, center=True), cylinder(r=4, h=16, center=True)))) # Right piece uses a more Pythonic grammar. + (plus) is equivalent to union(), # - (minus) is equivalent to difference() and * (star) is equivalent to intersection # solid.utils also defines up(), down(), left(), right(), forward(), and back() # for common transforms. right_piece = right(15)(cube([10, 5, 3], center=True)) cyl = cylinder(r=5, h=15, center=True) - cylinder(r=4, h=16, center=True) right_piece += right(10)(cyl) return union()(left_piece, right_piece)
def pulley_arms(height=40, through_screw='m4', arm_width=15, arm_thickness=7.5, pully_width=10, base_width=30, base_thickness=10, spin_clearance=0.5): arm_base = so.translate((0,-arm_width/2.0,0))(so.cube((arm_thickness, arm_width, 1))) arm = so.hull()(so.translate((0,0,height-arm_width/2.0))(so.rotate((0,90,0))(so.cylinder(r=arm_width/2.0, h=arm_thickness))) + arm_base) def arms_xf_left(obj): return so.translate(((pully_width + spin_clearance)/2.0,0,0))(obj) def arms_xf_right(obj): return so.translate((-(pully_width + spin_clearance)/2.0,0,0))(so.rotate((0,0,180))(obj)) arms = arms_xf_left(arm) + arms_xf_right(arm) plate_orig = so.translate((-base_width/2.0,-base_width/2.0,-base_thickness))(so.cube((base_width, base_width, base_thickness))) plate = so.hull()(plate_orig, so.translate((0,0,base_thickness/2.0))(arms_xf_left(arm_base))) plate += so.hull()(plate_orig, so.translate((0,0,base_thickness/2.0))(arms_xf_right(arm_base))) # add mount holes spacing = arm_thickness*2.0+pully_width bolt_hole = so.rotate((0,90,0))(so.translate((0,0,-spacing))(so.cylinder(r=screw_clearance[through_screw]/2.0, h=spacing*2.0))) nut_recess = so.translate((-spacing/2.0,0,0))(so.rotate((0,90,0))(hex(screw_nut[through_screw]['width'], screw_nut[through_screw]['depth']))) bolt_hole += nut_recess head_recess = so.translate((spacing/2.0,0,0))(so.rotate((0,-90,0))(so.cylinder(r=screw_head_sink[through_screw]['diameter']/2.0, h=screw_head_sink[through_screw]['h']))) bolt_hole += head_recess arms -= so.translate((0,0,height-arm_width/2.0))(bolt_hole) # add base mount hole head_recess = so.translate((0,0,-5))(so.cylinder(r=screw_head_sink[through_screw]['diameter']/2.0, h=screw_head_sink[through_screw]['h']*base_thickness)) bolt_hole = so.translate((0,0,-base_thickness))(so.cylinder(r=screw_clearance[through_screw]/2.0, h=base_thickness*2.0)) bolt_hole += head_recess return arms + plate - bolt_hole
def multipart_hole(): # It's good to be able to keep holes empty, but often we want to put # things (bolts, etc.) in them. The way to do this is to declare the # object containing the hole a "part". Then, the hole will remain # empty no matter what you add to the 'part'. But if you put an object # that is NOT part of the 'part' into the hole, it will still appear. # On the left (not_part), here's what happens if we try to put an object # into an explicit hole: the object gets erased by the hole. # On the right (is_part), we mark the cube-with-hole as a "part", # and then insert the same 'bolt' cylinder into it. The entire # bolt rematins. b = cube(10, center=True) c = cylinder(r=2, h=12, center=True) # A cube with an explicit hole not_part = b - hole()(c) # Mark this cube-with-hole as a separate part from the cylinder is_part = part()(not_part.copy()) # This fits in the holes bolt = cylinder(r=1.5, h=14, center=True) + up(8)(cylinder( r=2.5, h=2.5, center=True)) # The section of the bolt inside not_part disappears. The section # of the bolt inside is_part is still there. return not_part + bolt + right(45)(is_part + bolt)
def lasershim(height): """lasershim This is a shim which can be used to pad. The base of the shim is in the XY plane at quadrant 1. One corner is at the origin. The width is parallel to the x-axis. The shim can be used if the laserbase is not correctly alligned. The laser was provided by Odic Force, productid OFL510-1. param: height: defines height shim [mm] """ # PARAMETER xdisp = 48.5 # [mm], x-displacement screw ydisp = 16 # [mm], y-displacement screws r_shaft = 2 + 0.5 # [mm], shaft radius screws length = 75 # [mm], x-direction length laser width = 30 # [mm], y-direction width laser screw_offst = 7 # [mm], screw offset +x-edge # MAXIMAL MATERIAL BASE base = cube([length, width, height]) # screw holes screws = cylinder(h=height, r=r_shaft) + right(xdisp)(cylinder(h=height, r=r_shaft)) spiegel = forward(ydisp / 2)(mirror([0, 1, 0])(back(ydisp / 2)(screws))) screws += spiegel # create holes base -= translate([length - xdisp - screw_offst, (width - ydisp) / 2, 0])(screws) return base
def screw(r_head, h_head, r_shaft, length, thick=THICK_WALL): """screw create a hole so a screw can be screwd into the box the center of the screw is aligned with the center of the coordinate system the screw is oriented as flipped T, i.e. it is standing on its head. screws are generated with an enclosing of THICK_WALL mm the interior is ensured via the hole function it is assumed that r_head > r_shaft The height of the head is h_head, an additional r_head-r_r_shaft is added to ensure printablity. :param r_head: radius of the head of the screw [mm] :param h_head: height of the head of the screw [mm] :param r_shaft: radius of the shaft of the screw [mm] :param length: desired length of the screw [mm] """ h_shaft = length - h_head - (r_head - r_shaft) head = cylinder(h=h_head, r=r_head, segments=30) # 45 degrees cone for printability cone = up(h_head)(cylinder(h=r_head - r_shaft, r1=r_head, r2=r_shaft, segments=30)) shaft = up(h_head + (r_head - r_shaft))(cylinder(h=h_shaft, r=r_shaft, segments=30)) inner = head + cone + shaft screw = cylinder(h=length, r=r_head + thick) - hole()(inner) return screw
def slot(r_head, h_head, r_shaft, width, height): """slot openscad styled vertically oriented printable slot origin formed by the center of left circle :param r_head: the radius of the top of the screw, [mm] :param h_head: the height of the top of the screw, [mm] :param r_shaft: the radius of the shaft of the screw, [mm] :param width: the width of the slot, [mm] :param height: the height of the slot, [mm] """ h_shaft = height - h_head - (r_head - r_shaft) head = cylinder(h=h_head, r=r_head, segments=30) # 45 degrees cone for printability cone = up(h_head)(cylinder(h=r_head - r_shaft, r1=r_head, r2=r_shaft, segments=30)) shaft = up(h_head + (r_head - r_shaft))(cylinder(h=h_shaft, r=r_shaft, segments=30)) cyl = head + cone + shaft inner = hull()(cyl, right(width)(cyl)) cyl = cylinder(h=height, r=r_head + THICK_WALL) outer = hull()(cyl, right(width)(cyl)) slot = outer - hole()(inner) return slot
def m3_nut(): hx = cylinder(r=nut_rad, h=nut_height) hx.add_param('$fn', 6) # make the nut hexagonal n = difference()( hx, translate((0, 0, -EPSILON))( cylinder(r=m3_rad, h=nut_height + 2 * EPSILON) ) ) return n
def board_cylinder(): group = cube() # FIXME: look into empties/children for x in [-m.rpi_hole_x_dist / 2, m.rpi_hole_x_dist / 2]: for y in [-m.rpi_hole_y_dist / 2, m.rpi_hole_y_dist / 2]: c = cylinder(r=m.rpi_cylinder / 2, h=5) c2 = up(m.rpi_board_height)( cylinder(r=m.rpi_hole / 2 - m.diameter_margin, h=m.rpi_board_height) ) c = c + c2 group += forward(y)(left(x)(c)) return group
def pipe_intersection_no_hole(): pipe_od = 12 pipe_id = 10 seg_length = 30 outer = cylinder(r=pipe_od, h=seg_length, center=True) inner = cylinder(r=pipe_id, h=seg_length + 2, center=True) pipe_a = outer - inner pipe_b = rotate(a=90, v=FORWARD_VEC)(pipe_a) # pipe_a and pipe_b are both hollow, but because # their central voids aren't explicitly holes, # the union of both pipes has unwanted internal walls return pipe_a + pipe_b
def top_bracket(through_screw='m4', chamfer=1, clearance=0.25, bottom_thickness=10, height=30): body = bracket(bottom_thickness=bottom_thickness, chamfer=chamfer, height=height, clearance=clearance, through_offsets=[20]) d = screw_nut[through_screw]['depth'] + 2.5 nut_recess = so.translate((0,0,bottom_thickness-d))(hex(screw_nut[through_screw]['width'], d+10)) bolt_hole = so.cylinder(r=screw_clearance[through_screw]/2.0, h=bottom_thickness) return body - nut_recess - bolt_hole
def stopper(screw='m4'): body = so.cube((40,20,10), center=True) nut_recess = hex(screw_nut[screw]['width'], screw_nut[screw]['depth']) bolt_hole = so.translate((0,0,-10))(so.cylinder(r=screw_clearance[screw]/2.0, h=20)) nut_slide = so.translate((0,-screw_nut[screw]['width']/2.0))(so.cube((20, screw_nut[screw]['width'], screw_nut[screw]['depth']))) nut_attachment = so.rotate((0,-90,-90))(so.translate((0,0,-screw_nut[screw]['depth']/2.0))(nut_slide + nut_recess) + bolt_hole) return body - so.rotate((0,0,180))(so.translate((0,-13,-10))(expand_for_fit(0.3)(rail_section(20)))) - so.translate((0,-5,0))(nut_attachment)
def doohickey(): hole_cyl = translate( (0, 0, -EPSILON))(cylinder(r=m3_rad, h=doohickey_h + 2 * EPSILON)) d = difference()(cube([30, 10, doohickey_h], center=True), translate((-10, 0, 0))(hole_cyl), hole_cyl, translate((10, 0, 0))(hole_cyl)) return d
def top_part(): maze_path = os.path.join(os.path.dirname(__file__), 'maze7.png') depth_map = build_depth_map(maze_path) d = difference() u = union() u.add(bumpMapCylinder(depth_map, innerR, hn, 0, 255)) u.add(cylinder(r=innerR + wall + gap, h=gripH)) d.add(u) d.add(intersection().add( bumpMapCylinder(depth_map, innerR, hn + 2, wall, 0).set_modifier("")).add( translate((0, 0, baseH)).add( cylinder(r=innerR + 2 * wall, h=h * 1.1).set_modifier("")))) return d
def split_lock(diameter, thickness=3, depth=40, lip=10, chamfer=1, gap=2, screw='m4', shape='circle'): lip_part = so.translate((diameter/2.0,-thickness/2.0,0))(so.cube((lip,thickness,depth))) if shape == 'circle': hole = so.cylinder(r=diameter/2.0, h=depth*2) brace = so.cylinder(r=diameter/2.0+thickness, h=depth) elif shape == 'square': hole = so.rotate((0,0,45))(so.translate((-diameter/2.0,-diameter/2.0,0))(so.cube((diameter,diameter,depth*2)))) brace = so.rotate((0,0,45))(so.translate((-diameter/2.0-thickness,-diameter/2.0-thickness,0))(so.cube((2*thickness+diameter,2*thickness+diameter,depth)))) holder = so.translate((0,depth/2.0,0))(chamfer_hull(x=True,y=True)(so.rotate((90,0,0))(brace + lip_part)) - so.hole()(so.translate((0,depth/2.0,0))(so.rotate((90,0,0))(hole)))) split = so.translate((0, -depth/2.0-chamfer, -gap/2.0))(so.cube((thickness + diameter + lip,depth+chamfer*2,gap))) split_nut_recess = so.translate((0,0,chamfer))(hex(screw_nut[screw]['width'], screw_nut[screw]['depth'])) split_nut_slide = so.translate((0,-screw_nut[screw]['width']/2, chamfer))(so.cube((thickness + diameter, screw_nut[screw]['width'], screw_nut[screw]['depth']))) split_bolt_hole = so.translate((0,0,-thickness*2-chamfer))(so.cylinder(r=screw_clearance[screw]/2.0, h=100)) split_head_recess = so.translate((0,0,-diameter-thickness*2.5))(so.cylinder(r=screw_head_sink[screw]['diameter']/2.0, h=diameter+thickness)) split_tensioner = so.translate(((diameter+lip)/2.0,0,thickness/2.0+chamfer))(split_nut_recess + split_bolt_hole + split_nut_slide + split_head_recess) return holder - split - so.hole()(split_tensioner)
def carriage_plate(dims=(49, 42, 10), chamfer=1, screw_thickness=8, arm_screw='m4', arm_mount_dist=20): (x,y,z) = dims plate = so.translate((0,0,chamfer+z/2.0))(chamfer_hull(x=True,y=True,z=True)(so.cube(dims, center=True))) head_recess = so.translate((0,0,3))(so.cylinder(r=screw_head_sink['m3']['diameter']/2.0, h=screw_head_sink['m3']['h']*z)) bolt_hole = so.translate((0,0,-z))(so.cylinder(r=screw_clearance['m3']/2.0, h=z*3.0)) for m in [1,-1]: for t in [True, False]: x,y = (m,0) if t: x,y=y,x plate -= so.translate((y*41.0/2,x*34.5/2,0))(bolt_hole + head_recess) head_recess = so.cylinder(r=screw_head_sink[arm_screw]['diameter']/2.0, h=screw_head_sink[arm_screw]['h']+1) bolt_hole = so.cylinder(r=screw_clearance[arm_screw]/2.0, h=z+2*chamfer) mount_hole = head_recess + bolt_hole return plate - so.translate((arm_mount_dist/2.0,0,0))(mount_hole) - so.translate((-arm_mount_dist/2.0,0,0))(mount_hole)
def boxmount(): base = cube([30, 50, 2]) circ = cylinder(h=10, r=1.6, segments=30) circs = right(5)(circ) + right(25)(circ) base -= forward(5)(circs) base -= forward(25)(circs) base -= forward(45)(circs) base = rotate([90, 0, 90])(base) return base
def m3_12(): bolt_height = 12 m = union()( head(), translate((0, 0, -bolt_height))( cylinder(r=m3_rad, h=bolt_height) ) ) return m
def hex(width, h, fillet_radius = 0.1): """ width is the distance between opposing flat sides """ r = width/2.0/cos(pi/6.0) # magic so that we have the width b/w flat faces instead of corners pole = so.translate((r - fillet_radius, 0, 0))(so.cylinder(r=fillet_radius, h=h)) body = pole for i in range(1,6): body += so.rotate((0,0,60 * i))(pole) return so.hull()(body)
def assembly(): pts = [(0, -1, 0), (1, 0, 0), (0, 1, 0), (-1, 0, 0), (-1, -1, 0)] a = thread(pts, inner_rad=10, pitch=6, length=2, segments_per_rot=31, neck_in_degrees=30, neck_out_degrees=30) return a + cylinder(10 + EPSILON, 2)
def pipe_intersection_hole(): pipe_od = 12 pipe_id = 10 seg_length = 30 outer = cylinder(r=pipe_od, h=seg_length, center=True) inner = cylinder(r=pipe_id, h=seg_length + 2, center=True) # By declaring that the internal void of pipe_a should # explicitly remain empty, the combination of both pipes # is empty all the way through. # Any OpenSCAD / SolidPython object can be declared a hole(), # and after that will always be empty pipe_a = outer + hole()(inner) # Note that "pipe_a = outer - hole()(inner)" would work identically; # inner will always be subtracted now that it's a hole pipe_b = rotate(a=90, v=FORWARD_VEC)(pipe_a) return pipe_a + pipe_b
def sidewall_clamp(): # my wood is 19.5mm wide and 38.6mm tall body = chamfer_hull(z=True, y=True)(so.cube((20, thickness, height))) body += chamfer_hull(z=True, y=True, x=[1])(so.translate((19,0,0))(so.cube((1, thickness, height))) + so.translate((50,-thickness*0.25,0))(so.cube((10, thickness*1.5, 45)))) wood_cavity = so.translate((20,0,5))(so.cube((100,19.5,38.6))) body -= wood_cavity insert = so.rotate((0,90,0))(m3_heatset_insert_hole) for i in range(1,4): body -= so.translate((0,thickness/2.0,height/4.0*i))(insert) body -= so.translate((depth,thickness/2.0,height/4.0*i))(so.rotate((0,0,180))(insert)) nut_recess = so.translate((54,-5,15))(so.rotate((90,30,0))(hex(screw_nut['m3']['width'], screw_nut['m3']['depth']))) screw_recess = so.translate((54,22.4+5,15))(so.rotate((90,0,0))(so.cylinder(screw_head_sink['m3']['diameter']/2.0, screw_nut['m3']['depth']))) screw_hole = so.translate((54,22.4+10,15))(so.rotate((90,0,0))(so.cylinder(screw_clearance['m3']/2.0, 100))) screw_capture = nut_recess + screw_recess + screw_hole def add_screw(x,y): nonlocal body body -= so.translate((-x,0,y))(screw_capture) add_screw(0,0) add_screw(0,17) add_screw(17/2.0,17/2.0) return body
def double_side_rail(h, bottom_thickness=10, holes=None): section = so.translate((0,5,0))(rail_section(h)) stack = section + so.rotate((0,0,180))(section) + so.translate((-8,-5,0))(so.cube((16,10,h))) if holes is not None: bolt_hole = so.rotate((0,90,0))(so.translate((0,0,-40))(so.cylinder(r=screw_clearance[holes]/2.0, h=80))) def mkhole(offset): nonlocal stack stack -= so.translate((0,0,offset))(bolt_hole) mkhole(20-bottom_thickness) mkhole(40-bottom_thickness) mkhole(h-10) return stack
def test_hole_transform_propagation(self): # earlier versions of holes had problems where a hole # that was used a couple places wouldn't propagate correctly. # Confirm that's still happening as it's supposed to h = hole()(rotate(a=90, v=[0, 1, 0])(cylinder(2, 20, center=True))) h_vert = rotate(a=-90, v=[0, 1, 0])(h) a = cube(10, center=True) + h + h_vert expected = '\n\ndifference(){\n\tunion() {\n\t\tcube(center = true, size = 10);\n\t\trotate(a = -90, v = [0, 1, 0]) {\n\t\t}\n\t}\n\t/* Holes Below*/\n\tunion(){\n\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\tcylinder(center = true, h = 20, r = 2);\n\t\t}\n\t\trotate(a = -90, v = [0, 1, 0]){\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(center = true, h = 20, r = 2);\n\t\t\t}\n\t\t}\n\t} /* End Holes */ \n}' actual = scad_render(a) self.assertEqual(expected, actual)
def bottom_part(): top = difference() u = union() u2 = union() top.add(u) d = difference() d.add(cylinder(r=innerR + wall + gap, h=toph)) d.add(translate((0, 0, baseH)).add(cylinder(r=innerR + gap, h=toph))) u.add(d) top.add(u2) for i in range(0, 3): a = i * 2 * pi / 3 r = innerR + gap + wall / 2 u.add( translate(((r - 0.3) * cos(a), (r - 0.3) * sin(a), toph - 6)).add(sphere(r=2.4))) u2.add( translate(((r + wall - 0.3) * cos(a), (r + wall - 0.3) * sin(a), toph - 6)).add(sphere(r=2.4))) return top
def slot(radius, height, width): """slot openscad styled vertically oriented printable slot origin formed by the center of the left circle :param radius: the radius of the top of the screw :param height: the height of the slot :param width: the width of the slot, i.e. distance between radii """ cyl = cylinder(h=height, r=radius) outer = hull()(cyl, right(width)(cyl)) return outer
def assembly(): section = screw_thread.default_thread_section(tooth_height=10, tooth_depth=5) s = screw_thread.thread(outline_pts=section, inner_rad=inner_rad, pitch=screw_height, length=screw_height, segments_per_rot=SEGMENTS, neck_in_degrees=90, neck_out_degrees=90) c = cylinder(r=inner_rad, h=screw_height) return s + c
def basewall(passive=False): body = chamfer_hull(z=True, y=True, x=[-1])(so.cube((thickness, width, height))) m3_hole = so.translate((thickness + 1.0 ,0,0))(so.rotate((0,-90,0))(so.cylinder(r=screw_clearance['m3']/2.0, h=m3_support_depth) + so.translate((0,0,m3_support_depth))(so.cylinder(r=screw_head_sink['m3']['diameter']/2.0, h=thickness+2.0-m3_support_depth)))) for i in range(1,4): body -= so.translate((0,thickness/2.0,height/4.0*i))(m3_hole) body -= so.translate((0,width-thickness/2.0,height/4.0*i))(m3_hole) shaft_hole = so.cylinder(r=39.0/2+0.05, h=10) + so.cylinder(r=15.2/2+0.3, h=thickness+2) for i in [0,90,180,270]: shaft_hole += so.rotate((0,0,i))(so.translate((19.5,0,0))(so.cylinder(r=2, h=thickness+2))) shaft_hole = so.rotate((0,-90,0))(shaft_hole) servo_offset = 75 servo_vertical_offset = 8 servo_shaft_offset = 9.7 gear_spacing = 50 gear_angle = 0.75 for offset in [servo_offset - gear_spacing * cos(gear_angle), 110, 155, 200]: body -= so.translate((thickness + 1, offset, servo_vertical_offset + servo_shaft_offset + gear_spacing * sin(gear_angle)))(shaft_hole) if not passive: body -= so.translate((-1, servo_offset, servo_vertical_offset))(servo_mount()) if passive: body = so.mirror((1,0,0))(body) return body
def iron_holder(thickness=20, depth=40, length=45, iron_diameter=20.5, chamfer=1, iron_holder_thickness=5,arm_screw='m4', arm_mount_dist=20, gap=5, split_screw='m4', cup_diameter=30, cup_thickness=5): arm = chamfer_hull(x=True,y=True,z=[1])(so.translate((-thickness/2.0, -depth/2.0, 0))(so.cube((thickness,depth,length + cup_diameter)))) counterweight_cup = so.translate((0,depth/2.0,length-cup_thickness))(chamfer_hull(x=True,y=True)(so.rotate((90,0,0))(so.cylinder(r=cup_diameter/2.0+cup_thickness, h=depth))) - so.hole()(so.translate((0,depth/2.0-cup_thickness,0))(so.rotate((90,0,0))(so.cylinder(r=cup_diameter/2.0, h=depth))))) holder = so.translate((0,0,cup_diameter+length))(so.rotate((0,-90,0))(split_lock(iron_diameter, thickness=iron_holder_thickness, depth=depth, lip=10, chamfer=chamfer, gap=gap, screw=split_screw))) rope_tie = so.translate((0,depth/2.0+chamfer,length/2.0-iron_holder_thickness))(so.rotate((-90,90,0))(arch())) nut_recess = hex(screw_nut[arm_screw]['width'], screw_nut[arm_screw]['depth']) bolt_hole = so.cylinder(r=screw_clearance[arm_screw]/2.0, h=10) nut_slide = so.translate((0,-screw_nut[arm_screw]['width']/2.0))(so.cube((thickness, screw_nut[arm_screw]['width'], screw_nut[arm_screw]['depth']))) nut_attachment = so.translate((0,0,5))(nut_slide + nut_recess) + bolt_hole plate_install_holes = so.translate((0,0,-0.1))(carraige_plate_install_holes(diameter=4.95)) return counterweight_cup + arm + holder - so.translate((0,arm_mount_dist/2.0,0))(nut_attachment) - so.translate((0,-arm_mount_dist/2.0,0))(nut_attachment) + rope_tie - plate_install_holes
def ueyeholder(): """ueyeholder creates a holder for an ueye camera A holder for an uEye camera to view upward. The uEye camera cannot look upward due its connector on the back. This design solves this problem via a cubical enclosure. """ #### UEYE cubical dimension margin = 0.3 size_x = 34 # mm size_y = 32 # mm size_z = 34.6 # mm ### UEYE screw screw_d = 3 # mm screw_z = 30.4 # sep z-direction screw_z -= screw_d screw_ytop = 19.8 # mm screw_ytop -= screw_d screw_ybottom = 21.8 screw_ybottom -= screw_d screw_zoff = 1.3 + screw_d / 2 connector_z = 18 # mm connector_x = 16.2 # mm #### # box # camera is pushed in from bottom holder = cube([ size_x + 2 * THCKW + margin, size_y + 2 * THCKW + margin, size_z + THCKW + connector_z + margin ]) holder -= translate([THCKW, THCKW, THCKW])(cube([ size_x + margin, size_y + margin, size_z + THCKW + connector_z + margin ])) # 4 screw holes socket = cylinder(h=size_x + 2 * THCKW, r=screw_d / 2, segments=SGM) socket = rotate([0, 90, 0])(socket) sockets = socket + forward(screw_ybottom)(socket) temp = (screw_ytop - screw_ybottom) * 0.5 sockets += up(screw_z)(back(temp)(socket) + forward(screw_ytop - temp)(socket)) # substraction prep sockets holder -= translate([ 0, (size_y - screw_ybottom) * 0.5 + THCKW + 0.5 * margin, screw_zoff + THCKW + connector_z + 0.5 * margin ])(sockets) # space connector holder -= translate([THCKW + 0.5 * (size_x - connector_x), 0, THCKW])(cube( [connector_x, THCKW, size_z + THCKW + connector_z])) return holder