"""Right-angle (vertical) 6 x 6 mm through-hole tactile switch, C&K PTS645V series: a 6 x 6 mm tactile switch lying on its back in a sheet-metal frame, the actuator parallel to the board. The origin is midway between terminals 1 and 2, on the board's top face (the XY plane); the actuator points along +Y, the frame's legs are 2.55 behind the terminals (-Y). Dimensions from C&K's data sheet, in the README.""" from steve import Model kind = "31" # Actuator: length from the front leads (31, 39, 58, 83) or the square actuator (J61) force = "L" # Actuation force (sets the actuator colour and the part number) # Each entry: (actuator length from the front leads, actuator shape). # C&K "PTS645 Series, 6 mm Tact Switches", 6 february 18, page B-102 (pdf.icgoo.net copy), "Switch length from front leads for V # only": 31 3,15; 39 3,85; 58 5,85; 83 8,35 (H ±0.1). Page B-98, How To Order: 61 6,15, vertical, square actuator 2.4 mm side only. LENGTHS = { "31": (3.15, "round"), "39": (3.85, "round"), "58": (5.85, "round"), "83": (8.35, "round"), "J61": (6.15, "square"), } # Page B-99, V VERTICAL: frame 7.5 wide, 6.2 from its top to the face's lower edge; terminals 1 and 2 0.7 wide, 4.5 ±0.15 apart and # 4.3 below that edge; the frame's legs 4.95 below it, 7 apart at the tips and 8.5 over their bends, 1 wide, 2.55 ±0.1 behind the # terminals; the frame's back 4.2 behind them; the leg tips 3.95 below the board, so the face's lower edge is 4.95 - 3.95 = 1.0 above it; # the actuator Ø3.5, its axis 4.05 above the board; terminal 1/2 thickness 0.3. PCB layout: terminals 1/2 in Ø1 holes 4.5 ±0.05 # apart, the legs in Ø1.3 holes 7 ±0.05 apart, 2.55 ±0.05 behind. FRAME_W = 7.5 FACE_H = 6.2 FACE_LOW = 1.0 AXIS = 4.05 ACTUATOR_D = 3.5 PIN_PITCH = 4.5 PIN_W = 0.7 PIN_T = 0.3 PIN_DOWN = 4.3 LEG_PITCH = 7.0 LEG_OVER = 8.5 LEG_W = 1.0 LEG_BACK = 2.55 LEG_TIP = 3.95 REAR = 4.2 # Page B-100, J SQUARE ACTUATOR, VERTICAL THT (the same frame and switch): the actuator 6.2 (order table: 6.15) from the front leads # and 3.85 beyond the switch's face, so the face is 6.15 - 3.85 = 2.3 in front of the terminals; a 2.4 square stem 1.8 long on a neck # 1.4 long; four Ø0.9 holes in the face, 4.3 apart. FACE_Y = 2.3 STEM = 2.4 STEM_L = 1.8 NECK_L = 1.4 FACE_HOLE_D = 0.9 FACE_HOLE_AT = 4.3 # Page B-99, S STRAIGHT (the switch itself standing upright): body 6 square, 3.45 from the terminal side to the face. BODY = 6.0 BODY_DEPTH = 3.45 # Page B-102, ACTUATION FORCE: L 130 grams black, M 160 grams blue, H 200 grams gray, K 260 grams red. COLORS = {"L": ("130 grams", "#222325"), "M": ("160 grams", "#2f62b8"), "H": ("200 grams", "#8c8f93"), "K": ("260 grams", "#c8202a")} # Proportions, for looks only (the drawings don't dimension them): the frame's sheet thickness, the gap between the switch and the frame's # side walls, the switch's metal face thickness, the side walls' outline (sloped back edge, slanted lower front edge) and window, where the # legs bend, and the square actuator's neck (Ø1.6, as page B-101's square actuator). SHEET_T = 0.2 COVER_T = 0.3 NECK_D = 1.6 WALL_TOP_BACK = 3.2 WALL_BACK_LOW = 3.0 WALL_FOOT = 0.7 WINDOW = (-1.0, 2.0, 2.0, 3.9) LEG_BENDS = (-0.6, -1.6, -2.0, -3.0) if kind not in LENGTHS: raise ValueError(f"no actuator {kind!r}: {', '.join(LENGTHS)}") if force not in COLORS: raise ValueError(f"no actuation force {force!r}: {', '.join(COLORS)}") length, shape = LENGTHS[kind] color = COLORS[force][1] top = FACE_LOW + FACE_H body_top = FACE_LOW + BODY back = FACE_Y - BODY_DEPTH w = FRAME_W / 2 model = Model() # The switch: housing, metal face with the actuator opening and four holes, actuator along +Y. model.box("housing", BODY, BODY_DEPTH - COVER_T, BODY, at=(0, (back + FACE_Y - COVER_T) / 2, FACE_LOW + BODY / 2), op="new", body="housing_body", name="Housing") model.box("face", BODY, COVER_T, BODY, at=(0, FACE_Y - COVER_T / 2, FACE_LOW + BODY / 2), op="new", body="face_body", name="Face") model.cylinder("face_opening", ACTUATOR_D / 2 + 0.1, COVER_T + 0.2, at=(0, FACE_Y - COVER_T - 0.1, AXIS), direction=(0, 1, 0), op="cut", body="face_body", name="Actuator opening") for i, (sx, sz) in enumerate(((1, 1), (-1, 1), (-1, -1), (1, -1))): model.cylinder(f"face_hole_{i + 1}", FACE_HOLE_D / 2, COVER_T + 0.2, at=(sx * FACE_HOLE_AT / 2, FACE_Y - COVER_T - 0.1, AXIS + sz * FACE_HOLE_AT / 2), direction=(0, 1, 0), op="cut", body="face_body", name="Face hole") base = FACE_Y - COVER_T if shape == "round": model.cylinder("actuator", ACTUATOR_D / 2, length - base, at=(0, base, AXIS), direction=(0, 1, 0), op="new", body="actuator_body", name="Actuator") else: neck_at = length - STEM_L - NECK_L model.cylinder("actuator", ACTUATOR_D / 2, neck_at - base, at=(0, base, AXIS), direction=(0, 1, 0), op="new", body="actuator_body", name="Actuator") model.cylinder("neck", NECK_D / 2, NECK_L + 0.02, at=(0, neck_at - 0.01, AXIS), direction=(0, 1, 0), op="join", body="actuator_body", name="Neck") model.box("stem", STEM, STEM_L, STEM, at=(0, length - STEM_L / 2, AXIS), op="join", body="actuator_body", name="Stem") # The frame: a top plate over the switch, two side walls (sloped back, a window onto the housing) and a bent leg from each wall. model.box("frame_top", FRAME_W, FACE_Y + WALL_TOP_BACK, SHEET_T, at=(0, (FACE_Y - WALL_TOP_BACK) / 2, top - SHEET_T / 2), op="new", body="frame_body", name="Frame top") wall = [(-REAR, 0), (WALL_FOOT, 0), (FACE_Y, FACE_LOW), (FACE_Y, top), (-WALL_TOP_BACK, top), (-REAR, WALL_BACK_LOW)] for side, x0 in (("right", w - SHEET_T), ("left", -w)): model.plane(f"wall_{side}_plane", on="YZ", offset=x0, name=f"Frame wall, {side}") with model.sketch(f"wall_{side}_sketch", on=f"wall_{side}_plane", name=f"Frame wall, {side}") as sk: sk.polyline(f"wall_{side}_outline", wall, closed=True) model.extrude(f"wall_{side}", f"wall_{side}_sketch", distance=SHEET_T, op="join", body="frame_body", name=f"Frame wall, {side}") y0, y1, z0, z1 = WINDOW model.box("window", FRAME_W + 1, y1 - y0, z1 - z0, at=(0, (y0 + y1) / 2, (z0 + z1) / 2), op="cut", body="frame_body", name="Side windows") def outline(points, t): """A closed outline around a polyline of straight segments, t thick (mitred corners).""" import math def offset(sign): out = [] for i, (x, y) in enumerate(points): normals = [] segments = ([(points[i - 1], points[i])] if i else []) + ([(points[i], points[i + 1])] if i + 1 < len(points) else []) for a, b in segments: dx, dy = b[0] - a[0], b[1] - a[1] n = math.hypot(dx, dy) normals.append((-dy / n, dx / n)) if len(normals) == 1: nx, ny = normals[0] k = 1.0 else: nx, ny = normals[0][0] + normals[1][0], normals[0][1] + normals[1][1] n = math.hypot(nx, ny) nx, ny = nx / n, ny / n k = 1 / (nx * normals[0][0] + ny * normals[0][1]) out.append((x + sign * nx * k * t / 2, y + sign * ny * k * t / 2)) return out return offset(1) + offset(-1)[::-1] # Legs: from inside the wall's foot straight down, out to the 8.5 overall width, in to the 7 pitch and down to the tip; drawn in the XZ # plane (the XZ plane's normal is -Y, so a sketch on it extrudes towards -Y) and LEG_W wide along Y, centred LEG_BACK behind the terminals. x_wall = w - SHEET_T / 2 x_out = LEG_OVER / 2 - SHEET_T / 2 x_tip = LEG_PITCH / 2 b1, b2, b3, b4 = LEG_BENDS leg = [(x_wall, 0.3), (x_wall, b1), (x_out, b2), (x_out, b3), (x_tip, b4), (x_tip, -LEG_TIP)] for side, sx in (("right", 1), ("left", -1)): model.plane(f"leg_{side}_plane", on="XZ", offset=LEG_BACK - LEG_W / 2, name=f"Frame leg, {side}") with model.sketch(f"leg_{side}_sketch", on=f"leg_{side}_plane", name=f"Frame leg, {side}") as sk: sk.polyline(f"leg_{side}_outline", outline([(sx * x, z) for x, z in leg], SHEET_T), closed=True) model.extrude(f"leg_{side}", f"leg_{side}_sketch", distance=LEG_W, op="join", body="frame_body", name=f"Frame leg, {side}") # Terminals 1 and 2: straight down from the housing's underside, 0.7 x 0.3, 4.3 below the face's lower edge. for i, sx in enumerate((-1, 1)): model.box(f"terminal_{i + 1}", PIN_W, PIN_T, PIN_DOWN, at=(sx * PIN_PITCH / 2, 0, FACE_LOW - PIN_DOWN / 2), op="new", body=f"terminal_{i + 1}_body", name=f"Terminal {i + 1}") # Materials, for looks and a rough mass (the data sheet names only the silver plating): the housing black polyamide (pa6), the face and the # frame sheet steel (steel-c10), the actuator polyamide in its colour, the terminals copper alloy, silver coloured (copper). model.material("pa6", bodies=["housing_body"], color="#26272a") model.material("steel-c10", bodies=["face_body", "frame_body"], color="#c9ccd0") model.material("pa6", bodies=["actuator_body"], color=color) model.material("copper", bodies=["terminal_1_body", "terminal_2_body"], color="#d6d8db") result = model.result()