| | @@ -1,10 +1,10 @@ |
| 1 | | -"""Miniature through-hole SPDT slide switch, C&K OS series OS102011: a steel shell over a phenolic base, a square actuator through a |
| 2 | | -slot in the shell, three terminals in a row and a snap-in leg at each end. MS2Q stands upright (actuator up); MA1Q is the right-angle |
| 3 | | -version (actuator along -Y, parallel to the board). The origin is at terminal 2, on the board's top face (the XY plane); the terminals |
| 4 | | -and legs lie along X. Dimensions from C&K's data sheet, in the README.""" |
| 1 | +"""Through-hole slide switches: a steel shell over an insulating base, an actuator through a slot in the shell, terminals in a row and |
| 2 | +legs from the shell. C&K OS102011MS2Q stands upright (actuator up); C&K OS102011MA1Q and E-Switch EG1224 (SPDT) and EG2219 (DPDT) are |
| 3 | +right-angle (actuator along -Y, parallel to the board). The origin is at the centre of the shell's footprint, on the board's top face |
| 4 | +(the XY plane); the terminals lie along X. Dimensions from the makers' drawings, in the README.""" |
| 5 | 5 | from steve import Model |
| 6 | 6 | |
| 7 | | -kind = "MS2Q" # MS2Q: vertical (straight); MA1Q: right angle |
| 7 | +kind = "MS2Q" # MS2Q: C&K vertical; MA1Q: C&K right angle; EG1224, EG2219: E-Switch right angle |
| 8 | 8 | position = 2 # Actuator position (1 or 2) |
| 9 | 9 | |
| 10 | 10 | # Each entry: (shell length, shell width or depth, shell height, actuator out of the shell, actuator axis height (right angle only), |
| | @@ -36,69 +36,139 @@ |
| 36 | 36 | SHELL_T = 0.4 |
| 37 | 37 | BARB = (-0.4, -1.4) |
| 38 | 38 | NOTCH = 0.6 |
| 39 | +# E-Switch, each entry: (terminal rows, the rows' Y). |
| 40 | +# E-Switch drawing P040042 rev. A, "EG 1224 Non-Shorting", 4/27/98, and drawing P040170 rev. B, "EG 2219", 12/20/02 (datasheet.lcsc.com |
| 41 | +# copies), mm: body 13.8 x 6.5, 8.5 high; actuator 5.0 wide and 4.0 high, its axis 5.5 above the board, 9.0 out of the body (8.5 beyond a |
| 42 | +# 0.5 step); travel 4.0; terminals 4.0 apart, 0.5 wide and 0.4 thick, 3.5 below the board; four legs 0.8 wide and 0.5 thick, 12.0 apart |
| 43 | +# along the terminals and 6.0 across. EG1224: one row of three terminals 1.75 from the back legs' row, the body's lower edge 1.5 above |
| 44 | +# the board. EG2219: two rows 2.5 apart, between the legs' rows. |
| 45 | +EG = {"EG1224": ((1.25,),), "EG2219": ((-1.25, 1.25),)} |
| 46 | +EG_BODY = (13.8, 6.5, 8.5) |
| 47 | +EG_LOW = 1.5 |
| 48 | +EG_ACTUATOR = (5.0, 4.0) |
| 49 | +EG_AXIS = 5.5 |
| 50 | +EG_OUT = 9.0 |
| 51 | +EG_STEP = 0.5 |
| 52 | +EG_TRAVEL = 4.0 |
| 53 | +EG_PITCH = 4.0 |
| 54 | +EG_PIN = (0.5, 0.4) |
| 55 | +EG_TIP = 3.5 |
| 56 | +EG_LEG = (0.8, 0.5) |
| 57 | +EG_LEGS = (12.0, 6.0) |
| 58 | +# Proportions, for looks only: the shell's sheet thickness (the legs' 0.5), the actuator's step 4.0 x 3.0 (narrower than the knob, as |
| 59 | +# drawn), and EG2219's body lower edge, 1.5 above the board as on EG1224's drawing (EG2219's doesn't dimension it). |
| 60 | +EG_SHELL_T = 0.5 |
| 61 | +EG_STEP_SIZE = (4.0, 3.0) |
| 39 | 62 | |
| 40 | | -if kind not in KINDS: |
| 41 | | - raise ValueError(f"no type {kind!r}: {', '.join(KINDS)}") |
| 63 | +if kind not in KINDS and kind not in EG: |
| 64 | + raise ValueError(f"no type {kind!r}: {', '.join([*KINDS, *EG])}") |
| 42 | 65 | if position not in (1, 2): |
| 43 | 66 | raise ValueError("position is 1 or 2") |
| 44 | | -length, width, height, out, axis, base_low, angled = KINDS[kind] |
| 45 | | -slide = (position - 1.5) * TRAVEL # pos. 1 and 2 are a travel apart, centred on terminal 2 |
| 46 | | -L, W = length / 2, width / 2 |
| 47 | | -inner = L - SHELL_T |
| 67 | +if kind in EG: |
| 68 | + # E-Switch: right angle, the actuator a knob on a narrower step; four legs from the front and back walls. |
| 69 | + (rows,) = EG[kind] |
| 70 | + length, depth, height = EG_BODY |
| 71 | + L, D, t = length / 2, depth / 2, EG_SHELL_T |
| 72 | + slide = (position - 1.5) * EG_TRAVEL |
| 73 | + aw, ah = EG_ACTUATOR |
| 74 | + model = Model() |
| 75 | + model.box("shell_top", length, depth, t, at=(0, 0, height - t / 2), op="new", body="shell_body", name="Shell top") |
| 76 | + wall_h = height - EG_LOW |
| 77 | + for side, sy in (("back", 1), ("front", -1)): |
| 78 | + model.box(f"wall_{side}", length, t, wall_h, at=(0, sy * (D - t / 2), EG_LOW + wall_h / 2), op="join", body="shell_body", |
| 79 | + name=f"Shell wall, {side}") |
| 80 | + for side, sx in (("right", 1), ("left", -1)): |
| 81 | + model.box(f"end_{side}", t, depth, wall_h, at=(sx * (L - t / 2), 0, EG_LOW + wall_h / 2), op="join", body="shell_body", |
| 82 | + name=f"End wall, {side}") |
| 83 | + lx, ly = EG_LEGS |
| 84 | + for i, (sx, sy) in enumerate(((1, 1), (-1, 1), (-1, -1), (1, -1))): |
| 85 | + model.box(f"leg_{i + 1}", EG_LEG[0], EG_LEG[1], EG_LOW + EG_TIP + 0.01, at=(sx * lx / 2, sy * ly / 2, (EG_LOW - EG_TIP + 0.01) / 2), |
| 86 | + op="join", body="shell_body", name=f"Leg {i + 1}") |
| 87 | + model.box("slot", aw + EG_TRAVEL, t + 0.2, ah, at=(0, -D + t / 2, EG_AXIS), op="cut", body="shell_body", name="Slot") |
| 88 | + model.box("base", length - 2 * t, depth - 2 * t, height - t - EG_LOW, at=(0, 0, (EG_LOW + height - t) / 2), op="new", body="base_body", |
| 89 | + name="Base") |
| 90 | + sw, sh = EG_STEP_SIZE |
| 91 | + model.box("actuator_step", sw, t + EG_STEP, sh, at=(slide, -D + t - (t + EG_STEP) / 2, EG_AXIS), op="new", body="actuator_body", |
| 92 | + name="Actuator step") |
| 93 | + knob = EG_OUT - EG_STEP |
| 94 | + model.box("actuator", aw, knob + 0.01, ah, at=(slide, -D - EG_STEP - (knob - 0.01) / 2, EG_AXIS), op="join", body="actuator_body", |
| 95 | + name="Actuator") |
| 96 | + pins = [] |
| 97 | + for r, y in enumerate(rows): |
| 98 | + for i in range(3): |
| 99 | + n = r * 3 + i + 1 |
| 100 | + model.box(f"terminal_{n}", EG_PIN[0], EG_PIN[1], EG_LOW + EG_TIP, at=((i - 1) * EG_PITCH, y, (EG_LOW - EG_TIP) / 2), op="new", |
| 101 | + body=f"terminal_{n}_body", name=f"Terminal {n}") |
| 102 | + pins.append(f"terminal_{n}_body") |
| 103 | + # Materials, for looks and a rough mass (the drawings name none): the shell sheet steel (steel-c10), the base black phenolic |
| 104 | + # (bakelite), the actuator black POM (pom-copolymer), the terminals brass (brass), silver coloured. |
| 105 | + model.material("steel-c10", bodies=["shell_body"], color="#c9ccd0") |
| 106 | + model.material("bakelite", bodies=["base_body"], color="#2a2a2c") |
| 107 | + model.material("pom-copolymer", bodies=["actuator_body"], color="#222325") |
| 108 | + model.material("brass", bodies=pins, color="#d6d8db") |
| 109 | +else: |
| 110 | + # C&K OS102011. |
| 111 | + length, width, height, out, axis, base_low, angled = KINDS[kind] |
| 112 | + slide = (position - 1.5) * TRAVEL # pos. 1 and 2 are a travel apart, centred on terminal 2 |
| 113 | + L, W = length / 2, width / 2 |
| 114 | + inner = L - SHELL_T |
| 48 | 115 | |
| 49 | | -model = Model() |
| 50 | | -# Shell: the end walls (whose legs reach through the board), the top, and the long sides (upright) or the front face (right angle); the |
| 51 | | -# actuator's slot, the actuator plus its travel long, in the top (upright) or in the front face (right angle). |
| 52 | | -model.box("shell_top", length, width, SHELL_T, at=(0, 0, height - SHELL_T / 2), op="new", body="shell_body", name="Shell top") |
| 53 | | -for side, sx in (("right", 1), ("left", -1)): |
| 54 | | - model.box(f"end_{side}", SHELL_T, width, height, at=(sx * (L - SHELL_T / 2), 0, height / 2), op="join", body="shell_body", |
| 55 | | - name=f"End wall, {side}") |
| 56 | | - model.box(f"leg_{side}", LEG_T, LEG_W, TIP + 0.01, at=(sx * LEG_PITCH / 2, 0, -(TIP - 0.01) / 2), op="join", body="shell_body", |
| 57 | | - name=f"Leg, {side}") |
| 58 | | - model.box(f"barb_{side}", LEG_T, BARB_W, BARB[0] - BARB[1], at=(sx * LEG_PITCH / 2, 0, (BARB[0] + BARB[1]) / 2), op="join", |
| 59 | | - body="shell_body", name=f"Leg barb, {side}") |
| 60 | | -if angled: |
| 61 | | - model.box("shell_front", length, SHELL_T, height, at=(0, -W + SHELL_T / 2, height / 2), op="join", body="shell_body", name="Shell front") |
| 62 | | - model.box("slot", ACTUATOR + TRAVEL, SHELL_T + 0.2, ACTUATOR, at=(0, -W + SHELL_T / 2, axis), op="cut", body="shell_body", name="Slot") |
| 63 | | -else: |
| 64 | | - for side, sy in (("back", 1), ("front", -1)): |
| 65 | | - model.box(f"side_{side}", length, SHELL_T, height - base_low, at=(0, sy * (W - SHELL_T / 2), (height + base_low) / 2), op="join", |
| 66 | | - body="shell_body", name=f"Shell side, {side}") |
| 67 | | - model.box("slot", ACTUATOR + TRAVEL, ACTUATOR, SHELL_T + 0.2, at=(0, 0, height - SHELL_T / 2), op="cut", body="shell_body", name="Slot") |
| 68 | | -# Base: the phenolic block inside the shell, from its lower edge up to the top. |
| 69 | | -front = -W + SHELL_T |
| 70 | | -back = W if angled else W - SHELL_T # the right-angle shell has no back |
| 71 | | -model.box("base", 2 * inner, back - front, height - SHELL_T - base_low, at=(0, (front + back) / 2, (base_low + height - SHELL_T) / 2), |
| 72 | | - op="new", body="base_body", name="Base") |
| 73 | | -# Actuator: square, out of the slot by `out`, a V notch in its end. |
| 74 | | -if angled: |
| 75 | | - a_in = -W + SHELL_T |
| 76 | | - a_end = -W - out |
| 77 | | - model.box("actuator", ACTUATOR, a_in - a_end, ACTUATOR, at=(slide, (a_in + a_end) / 2, axis), op="new", body="actuator_body", |
| 78 | | - name="Actuator") |
| 79 | | - with model.sketch("notch_sketch", on="XY", name="Actuator notch") as sk: |
| 80 | | - sk.polyline("notch_outline", [(slide - NOTCH / 2, a_end - 0.01), (slide + NOTCH / 2, a_end - 0.01), (slide, a_end + NOTCH)], |
| 81 | | - closed=True) |
| 82 | | - model.extrude("notch", "notch_sketch", distance=height, op="cut", body="actuator_body", name="Actuator notch") |
| 83 | | -else: |
| 84 | | - a_low = height - SHELL_T |
| 85 | | - a_end = height + out |
| 86 | | - model.box("actuator", ACTUATOR, ACTUATOR, a_end - a_low, at=(slide, 0, (a_low + a_end) / 2), op="new", body="actuator_body", |
| 87 | | - name="Actuator") |
| 88 | | - model.plane("notch_plane", on="XZ", offset=-(ACTUATOR / 2 + 0.1), name="Actuator notch") |
| 89 | | - with model.sketch("notch_sketch", on="notch_plane", name="Actuator notch") as sk: |
| 90 | | - sk.polyline("notch_outline", [(slide - NOTCH / 2, a_end + 0.01), (slide + NOTCH / 2, a_end + 0.01), (slide, a_end - NOTCH)], |
| 91 | | - closed=True) |
| 92 | | - model.extrude("notch", "notch_sketch", distance=ACTUATOR + 0.2, op="cut", body="actuator_body", name="Actuator notch") |
| 93 | | -# Terminals 1-3: straight down from the base's lower edge to the tips. |
| 94 | | -for i in range(3): |
| 95 | | - model.box(f"terminal_{i + 1}", PIN_W, PIN_T, base_low + TIP, at=((i - 1) * PITCH, 0, (base_low - TIP) / 2), op="new", |
| 96 | | - body=f"terminal_{i + 1}_body", name=f"Terminal {i + 1}") |
| 97 | | -# Materials (page I-37, Materials): base phenolic resin (bakelite), actuator POM, black (pom-copolymer), housing plate SPCC, tin plated |
| 98 | | -# (steel-c10), terminals brass, silver plated (brass, silver coloured). |
| 99 | | -model.material("steel-c10", bodies=["shell_body"], color="#c9ccd0") |
| 100 | | -model.material("bakelite", bodies=["base_body"], color="#a5562a") |
| 101 | | -model.material("pom-copolymer", bodies=["actuator_body"], color="#222325") |
| 102 | | -model.material("brass", bodies=[f"terminal_{i + 1}_body" for i in range(3)], color="#d6d8db") |
| 116 | + model = Model() |
| 117 | + # Shell: the end walls (whose legs reach through the board), the top, and the long sides (upright) or the front face (right angle); the |
| 118 | + # actuator's slot, the actuator plus its travel long, in the top (upright) or in the front face (right angle). |
| 119 | + model.box("shell_top", length, width, SHELL_T, at=(0, 0, height - SHELL_T / 2), op="new", body="shell_body", name="Shell top") |
| 120 | + for side, sx in (("right", 1), ("left", -1)): |
| 121 | + model.box(f"end_{side}", SHELL_T, width, height, at=(sx * (L - SHELL_T / 2), 0, height / 2), op="join", body="shell_body", |
| 122 | + name=f"End wall, {side}") |
| 123 | + model.box(f"leg_{side}", LEG_T, LEG_W, TIP + 0.01, at=(sx * LEG_PITCH / 2, 0, -(TIP - 0.01) / 2), op="join", body="shell_body", |
| 124 | + name=f"Leg, {side}") |
| 125 | + model.box(f"barb_{side}", LEG_T, BARB_W, BARB[0] - BARB[1], at=(sx * LEG_PITCH / 2, 0, (BARB[0] + BARB[1]) / 2), op="join", |
| 126 | + body="shell_body", name=f"Leg barb, {side}") |
| 127 | + if angled: |
| 128 | + model.box("shell_front", length, SHELL_T, height, at=(0, -W + SHELL_T / 2, height / 2), op="join", body="shell_body", |
| 129 | + name="Shell front") |
| 130 | + model.box("slot", ACTUATOR + TRAVEL, SHELL_T + 0.2, ACTUATOR, at=(0, -W + SHELL_T / 2, axis), op="cut", body="shell_body", |
| 131 | + name="Slot") |
| 132 | + else: |
| 133 | + for side, sy in (("back", 1), ("front", -1)): |
| 134 | + model.box(f"side_{side}", length, SHELL_T, height - base_low, at=(0, sy * (W - SHELL_T / 2), (height + base_low) / 2), |
| 135 | + op="join", body="shell_body", name=f"Shell side, {side}") |
| 136 | + model.box("slot", ACTUATOR + TRAVEL, ACTUATOR, SHELL_T + 0.2, at=(0, 0, height - SHELL_T / 2), op="cut", body="shell_body", |
| 137 | + name="Slot") |
| 138 | + # Base: the phenolic block inside the shell, from its lower edge up to the top. |
| 139 | + front = -W + SHELL_T |
| 140 | + back = W if angled else W - SHELL_T # the right-angle shell has no back |
| 141 | + model.box("base", 2 * inner, back - front, height - SHELL_T - base_low, at=(0, (front + back) / 2, (base_low + height - SHELL_T) / 2), |
| 142 | + op="new", body="base_body", name="Base") |
| 143 | + # Actuator: square, out of the slot by `out`, a V notch in its end. |
| 144 | + if angled: |
| 145 | + a_in = -W + SHELL_T |
| 146 | + a_end = -W - out |
| 147 | + model.box("actuator", ACTUATOR, a_in - a_end, ACTUATOR, at=(slide, (a_in + a_end) / 2, axis), op="new", body="actuator_body", |
| 148 | + name="Actuator") |
| 149 | + with model.sketch("notch_sketch", on="XY", name="Actuator notch") as sk: |
| 150 | + sk.polyline("notch_outline", [(slide - NOTCH / 2, a_end - 0.01), (slide + NOTCH / 2, a_end - 0.01), (slide, a_end + NOTCH)], |
| 151 | + closed=True) |
| 152 | + model.extrude("notch", "notch_sketch", distance=height, op="cut", body="actuator_body", name="Actuator notch") |
| 153 | + else: |
| 154 | + a_low = height - SHELL_T |
| 155 | + a_end = height + out |
| 156 | + model.box("actuator", ACTUATOR, ACTUATOR, a_end - a_low, at=(slide, 0, (a_low + a_end) / 2), op="new", body="actuator_body", |
| 157 | + name="Actuator") |
| 158 | + model.plane("notch_plane", on="XZ", offset=-(ACTUATOR / 2 + 0.1), name="Actuator notch") |
| 159 | + with model.sketch("notch_sketch", on="notch_plane", name="Actuator notch") as sk: |
| 160 | + sk.polyline("notch_outline", [(slide - NOTCH / 2, a_end + 0.01), (slide + NOTCH / 2, a_end + 0.01), (slide, a_end - NOTCH)], |
| 161 | + closed=True) |
| 162 | + model.extrude("notch", "notch_sketch", distance=ACTUATOR + 0.2, op="cut", body="actuator_body", name="Actuator notch") |
| 163 | + # Terminals 1-3: straight down from the base's lower edge to the tips. |
| 164 | + for i in range(3): |
| 165 | + model.box(f"terminal_{i + 1}", PIN_W, PIN_T, base_low + TIP, at=((i - 1) * PITCH, 0, (base_low - TIP) / 2), op="new", |
| 166 | + body=f"terminal_{i + 1}_body", name=f"Terminal {i + 1}") |
| 167 | + # Materials (page I-37, Materials): base phenolic resin (bakelite), actuator POM, black (pom-copolymer), housing plate SPCC, tin plated |
| 168 | + # (steel-c10), terminals brass, silver plated (brass, silver coloured). |
| 169 | + model.material("steel-c10", bodies=["shell_body"], color="#c9ccd0") |
| 170 | + model.material("bakelite", bodies=["base_body"], color="#a5562a") |
| 171 | + model.material("pom-copolymer", bodies=["actuator_body"], color="#222325") |
| 172 | + model.material("brass", bodies=[f"terminal_{i + 1}_body" for i in range(3)], color="#d6d8db") |
| 103 | 173 | result = model.result() |
| 104 | 174 | |