diff --git a/nhf/touhou/yasaka_kanako/onbashira.py b/nhf/touhou/yasaka_kanako/onbashira.py index 92a7fea..60773a9 100644 --- a/nhf/touhou/yasaka_kanako/onbashira.py +++ b/nhf/touhou/yasaka_kanako/onbashira.py @@ -347,7 +347,10 @@ class Onbashira(Model): motor_coupler_conn_dx: float = 30.0 motor_coupler_wall_thickness: float = 5.0 motor_coupler_inner_gap: float = 1.0 - turning_bar_parent_hole_diam: float = 8.0 + + turning_bar_tilt: float = 12.0 + turning_bar_hole_dy: float = 20.0 + turning_bar_parent_hole_diam_extra: float = 1.0 turning_bar_child_hole_diam: float = 4.0 turning_bar_width: float = 15.0 turning_bar_height: float = 30.0 @@ -441,6 +444,14 @@ class Onbashira(Model): """ return self.chamber_side_width / 2 / math.tan(math.radians(self.angle_side / 2)) + def interior_length(self, section_length: float) -> float: + """ + Given the outside length of a section, calculate the length between the + mount holes on the angle joints on the two ends of it. + """ + z2 = self.angle_joint_gap - self.angle_joint_flange_thickness + return section_length + z2 + @target(name="sanding-block") def sanding_block(self) -> Cq.Workplane: # Dihedral angle / 2 @@ -1262,14 +1273,8 @@ class Onbashira(Model): ### Electronics ### @property - def turning_bar_hole_dy(self) -> float: - """ - Distance between centre of mounting holes in the turning bar and top of - the side panels. - """ - panel_to_mount = self.angle_joint_flange_thickness / 2 - self.angle_joint_gap / 2 - return panel_to_mount + self.turning_bar_width / 2 - + def turning_bar_parent_hole_diam(self) -> float: + return BOLT_COMMON.diam_thread + self.turning_bar_parent_hole_diam_extra @target(name="turning-bar") def turning_bar(self) -> Cq.Workplane: """ @@ -1279,6 +1284,39 @@ class Onbashira(Model): _, dx = self.angle_joint_bind_pos.to2d_pos() t = 8 w = self.turning_bar_width + h = self.turning_bar_height + flange = Cq.Solid.makeBox( + length=w, + width=t, + height=w/2, + ).moved(-w/2, 0, 0) + Cq.Solid.makeCylinder( + radius=w/2, + height=t, + pnt=(0, 0, 0), + dir=(0, 1, 0), + ) - Cq.Solid.makeCylinder( + radius=self.turning_bar_parent_hole_diam/2, + height=w*2, + pnt=(0, -w, 0), + dir=(0, 1, 0), + ) + flange = flange.moved(0, -t, -w/2-h) + + leg = ( + Cq.Workplane('YZ') + .sketch() + .polygon([ + (0, -h), + (-t, -h), + (-t-self.turning_bar_tilt, 0), + (-self.turning_bar_tilt, 0), + ]) + .finalize() + .extrude(w) + .translate((-w/2, 0, 0)) + .union(flange) + .val() + ) result = ( Cq.Workplane() .box( @@ -1287,51 +1325,47 @@ class Onbashira(Model): height=t, centered=(True, True, False) ) - ) - h = self.turning_bar_height - flange = Cq.Solid.makeBox( - length=w, - width=t, - height=w/2 + h, - ).moved(-w/2, -t, -w/2-h) + Cq.Solid.makeCylinder( - radius=w/2, - height=t, - pnt=(0, -t, -w/2-h), - dir=(0, 1, 0), + .translate((0, -w/2-self.turning_bar_tilt, -t)) ) holeC = Cq.Solid.makeCylinder( radius=self.turning_bar_child_hole_diam/2, height=w, ) - holeP = Cq.Solid.makeCylinder( - radius=self.turning_bar_parent_hole_diam/2, - height=w*2, - pnt=(0, -w, -w/2-h), - dir=(0, 1, 0), - ) dxe = self.electronics_mount_dx result = ( result - + flange.moved(dx, w/2, 0) - + flange.moved(-dx, w/2, 0) - - holeC.moved(dxe, 0, 0) - - holeC.moved(-dxe, 0, 0) - - holeP.moved(dx, 0, 0) - - holeP.moved(-dx, 0, 0) + + leg.moved(dx, 0, 0) + + leg.moved(-dx, 0, 0) + - holeC.moved(dxe, -self.turning_bar_hole_dy, -w) + - holeC.moved(-dxe, -self.turning_bar_hole_dy, -w) ) - result.tagAbsolute("holeBO1", (dx, w/2, -w/2-h), direction="+Y") - result.tagAbsolute("holeBO2", (-dx, w/2, -w/2-h), direction="+Y") - result.tagAbsolute("holeMO1", (dxe, 0, t)) - result.tagAbsolute("holeMO2", (-dxe, 0, t)) + result.tagAbsolute("holeBO1", (dx, 0, -w/2-h), direction="+Y") + result.tagAbsolute("holeBO2", (-dx, 0, -w/2-h), direction="+Y") + result.tagAbsolute("holeMO1", (dxe, -self.turning_bar_hole_dy, 0)) + result.tagAbsolute("holeMO2", (-dxe, -self.turning_bar_hole_dy, 0)) return result + def profile_electronics_panel(self) -> Cq.Sketch: + """ + Generic electronics panel + """ + hole_dx = self.electronics_mount_dx + # Distance between the holes + y = self.interior_length(self.side_length3) - self.turning_bar_hole_dy * 2 + l = y + 15 + w = self.side_width * self.electronics_panel_width_ratio + return ( + Cq.Sketch() + .rect(l, w) + .rect(y, hole_dx * 2, mode="c", tag="corner") + .vertices(tag="corner") + .circle(self.turning_bar_child_hole_diam/2, mode="s") + .reset() + ) + @target(name="electronics-panel1", kind=TargetKind.DXF) def profile_electronics_panel1(self) -> Cq.Sketch: - hole_dy = self.turning_bar_hole_dy - hole_dx = self.electronics_mount_dx - l = self.side_length3 - hole_dy * 2 + 12 - y = self.side_length3 - hole_dy * 2 - w = self.side_width * self.electronics_panel_width_ratio + # Distance between the holes controller_holes = [ self.controller_loc * Cq.Location.from2d(*h).flip_y() for h in self.controller.holes @@ -1342,12 +1376,7 @@ class Onbashira(Model): for loc in self.battery_box_locs ] profile = ( - Cq.Sketch() - .rect(l, w) - .rect(y, hole_dx * 2, mode="c", tag="corner") - .vertices(tag="corner") - .circle(self.turning_bar_child_hole_diam/2, mode="s") - .reset() + self.profile_electronics_panel() .push([ h.to2d_pos() for h in controller_holes ] + [ @@ -1358,21 +1387,20 @@ class Onbashira(Model): return profile def electronics_panel1(self) -> Cq.Workplane: - hole_dy = self.turning_bar_hole_dy hole_dx = self.electronics_mount_dx - l = self.side_length3 + y = self.interior_length(self.side_length3) - self.turning_bar_hole_dy * 2 + l = y + 15 t = self.side_thickness result = ( Cq.Workplane() .placeSketch(self.profile_electronics_panel1()) .extrude(t) ) - x = l/2 - hole_dy for side, z, d in [("T", t, "+Z"), ("B", 0, "-Z")]: - result.tagAbsolute(f"holeLP{side}", (-x, hole_dx, z), direction=d) - result.tagAbsolute(f"holeLS{side}", (-x, -hole_dx, z), direction=d) - result.tagAbsolute(f"holeRP{side}", (x, -hole_dx, z), direction=d) - result.tagAbsolute(f"holeRS{side}", (x, hole_dx, z), direction=d) + result.tagAbsolute(f"holeLP{side}", (-y/2, hole_dx, z), direction=d) + result.tagAbsolute(f"holeLS{side}", (-y/2, -hole_dx, z), direction=d) + result.tagAbsolute(f"holeRP{side}", (y/2, -hole_dx, z), direction=d) + result.tagAbsolute(f"holeRS{side}", (y/2, hole_dx, z), direction=d) for (i, h) in enumerate(self.controller.holes): loc = self.controller_loc * Cq.Location.from2d(*h).flip_y() hx, hy = loc.to2d_pos() @@ -1455,6 +1483,84 @@ class Onbashira(Model): ) return a.solve() + @target(name="electronics-panel2", kind=TargetKind.DXF) + def profile_electronics_panel2(self) -> Cq.Sketch: + n = 15 + h_hole = 10 + y = self.interior_length(self.side_length3) - self.turning_bar_hole_dy * 2 + w_hole = self.side_width * self.electronics_panel_width_ratio * 0.75 + profile = ( + self.profile_electronics_panel() + .rarray(y / n, 0, n, 1) + .slot(w_hole, h_hole, mode="s", angle=90) + ) + return profile + + def electronics_panel2(self) -> Cq.Workplane: + hole_dx = self.electronics_mount_dx + y = self.interior_length(self.side_length3) - self.turning_bar_hole_dy * 2 + l = y + 15 + t = self.side_thickness + result = ( + Cq.Workplane() + .placeSketch(self.profile_electronics_panel2()) + .extrude(t) + ) + for side, z, d in [("T", t, "+Z"), ("B", 0, "-Z")]: + result.tagAbsolute(f"holeLP{side}", (-y/2, hole_dx, z), direction=d) + result.tagAbsolute(f"holeLS{side}", (-y/2, -hole_dx, z), direction=d) + result.tagAbsolute(f"holeRP{side}", (y/2, -hole_dx, z), direction=d) + result.tagAbsolute(f"holeRS{side}", (y/2, hole_dx, z), direction=d) + return result + + @assembly() + def assembly_electronics2(self) -> Cq.Assembly: + name_barL = "barL" + name_barR = "barR" + name_panel = "panel" + a = ( + Cq.Assembly() + .addS( + self.turning_bar(), + name=name_barL, + material=self.material_brace, + role=Role.STRUCTURE, + ) + .addS( + self.turning_bar(), + name=name_barR, + material=self.material_brace, + role=Role.STRUCTURE, + ) + .addS( + self.electronics_panel2(), + name=name_panel, + material=self.material_auxiliary, + role=Role.STRUCTURE, + ) + .constrain( + f"{name_panel}?holeLPB", + f"{name_barL}?holeMO1", + "Plane" + ) + .constrain( + f"{name_panel}?holeLSB", + f"{name_barL}?holeMO2", + "Plane" + ) + .constrain( + f"{name_panel}?holeRPB", + f"{name_barR}?holeMO1", + "Plane" + ) + .constrain( + f"{name_panel}?holeRSB", + f"{name_barR}?holeMO2", + "Plane" + ) + ) + return a.solve() + ### Side Panels @target(name="front-bracket") @@ -1853,7 +1959,7 @@ class Onbashira(Model): h = self.angle_joint_flange_thickness # drill hole cyl = Cq.Solid.makeCylinder( - radius=self.rotor_bind_bolt_diam/2, + radius=BOLT_COMMON.diam_thread/2, height=h, pnt=(ri * math.cos(th), ri * math.sin(th), -h/2), ) @@ -2257,7 +2363,6 @@ class Onbashira(Model): result.tagAbsolute(f"holeRSM{i}", locrot * Cq.Location(dr0, -x, -py), direction="-X") # Generate the flange geometry - flange = self.angle_joint_flange() result = result + self.angle_joint_flange() th = math.pi / self.n_side ri = self.angle_joint_bind_radius @@ -2495,6 +2600,8 @@ class Onbashira(Model): if has_part(parts, "electronics1"): a = a.add(self.assembly_electronics1(), name="electronics1") a = a.constrain("electronics1/controller", "Fixed") + if has_part(parts, "electronics2"): + a = a.add(self.assembly_electronics2(), name="electronics2") if has_part(parts, ["electronics1", "ring3"]): a = a.constrain( f"electronics1/barL?holeBO2", @@ -2506,6 +2613,17 @@ class Onbashira(Model): f"ring3/side2?holeStatorL", "Plane", ) + if has_part(parts, ["electronics2", "ring3"]): + a = a.constrain( + f"electronics2/barL?holeBO2", + f"ring3/side3?holeStatorL", + "Plane", + ) + a = a.constrain( + f"electronics2/barL?holeBO1", + f"ring3/side4?holeStatorL", + "Plane", + ) if has_part(parts, ["motor", "ring2"]): for i in range(self.n_side // 2):