// Máy điểm danh RFID V5 — phát triển từ V4, theo bộ ảnh V5 (01/02/03-*-v5.png). // Giữ: ESP32 XH-S3E-AI, RC522. Mới: mạch sạc IP5306 Type-C, pin LiPo 104050 2500 mAh, // loa 40 mm 4 Ω 3 W, 3 LED 3 mm, công tắc KCD11. Mọi thứ bắt vít. // Đơn vị mm. Gốc: góc dưới-trái-sau. X sang phải, Y lên (nhìn từ trước), Z từ đáy ra mặt trước. // // Xuất file in: // openscad -D 'part="base"' -o v5-day-hop.stl enclosure.scad // openscad -D 'part="lid"' -o v5-nap-hop.stl enclosure.scad // openscad -D 'part="clips"' -o v5-bo-kep.stl enclosure.scad // Kiểm va chạm: openscad -D 'part="check"' -D 'pair=N' ... (xem check_fit.sh) part = "assembled"; // base, lid, clips, assembled, open, check pair = 0; // ---------- Vỏ ---------- W = 140; H = 110; D = 36; WALL = 2.5; FLOOR = 2.5; LID_T = 3; R = 8; BH = D - LID_T; // mặt trong nắp ở Z = 33 CORNER = 7; BOSS_D = 9; INSERT_D = 4.3; INSERT_DEPTH = 11; // đai ốc cấy đồng M3 dài 4, OD 5; lỗ sâu 11 cho đuôi vít M3x10 M3_CLEAR = 3.4; M3_CSK = 6.6; M2_PILOT = 1.7; M2_CLEAR = 2.4; CLIP_T = 2.5; LIP_IN = 0.3; LIP_W = 1.6; LIP_H = 3; $fn = 40; // ---------- Linh kiện (đo lại khi có hàng thật rồi sửa ở đây) ---------- // ESP32: nằm ngang 39 x 26, mặt module hướng lên nắp, USB-C quay trái (trong vỏ), // header cái 8 chân dọc mép dưới, chĩa xuống. Cắm hàng rào đực cong 90° rồi hàn dây (dupont thẳng không vừa). ESP_X = 12; ESP_Y = 9.5; ESP_L = 39; ESP_W = 26; ESP_Z = 15; ESP_PCB = 1.6; ESP_MOD_H = 3.2; FOAM = 2; // Mạch sạc IP5306 Type-C: 16 x 25 (có bản 20 x 25 — đổi CHG_W), USB-C ở cạnh ngắn quay xuống cạnh dưới vỏ. CHG_W = 16; CHG_L = 25; CHG_X = 63 - CHG_W/2; CHG_Y = 3; CHG_Z = FLOOR + 2; CHG_PCB = 1.6; USB_X = CHG_X + CHG_W/2; USB_Z = CHG_Z + CHG_PCB + 1.6; USB_CUT_W = 12.5; USB_CUT_H = 7; // Pin 104050: 50 x 40 x 10 (khay 51 x 41 x 10,5) BAT_X = 77.5; BAT_Y = 2.5; BAT_IN_W = 51; BAT_IN_L = 40.5; BAT_T = 10.5; // pin sát góc dưới phải, không nằm dưới loa/công tắc // Loa 40 mm 4 Ω 3 W cao ~20, gắn sau nắp SPK_X = 108; SPK_Y = 76; SPK_D = 40; SPK_DEPTH = 20; SPK_FLANGE = 2.5; SPK_SCREW_R = 24; // vành loa 1,5 + gioăng xốp 1 SPK_EARS = [45, 225]; // RC522 60 x 40 dán sát mặt trong nắp RC_X = 14; RC_Y = 52; RC_W = 60; RC_L = 40; RC_PCB = 1.6; RC_ANT_X = RC_X + 40; RC_ANT_Y = RC_Y + 20; // 3 LED 3 mm, POWER / READ / STATUS LED_XS = [22, 33, 44]; LED_Y = 99; LED_HOLE = 3.1; LED_FLANGE = 1; // Công tắc KCD11 dựng đứng ở thành phải: lỗ 9 (Y) x 13,5 (Z) SW_Y = 48.5; SW_Z = 21; SW_CUT_W = 9; SW_CUT_H = 13.5; // khe trống giữa pin (Y ≤ 43) và vòng kẹp loa (Y ≥ 53) corners = [[CORNER, CORNER], [W-CORNER, CORNER], [CORNER, H-CORNER], [W-CORNER, H-CORNER]]; module rbox(w, h, z, r) { linear_extrude(z) offset(r) offset(-r) square([w, h]); } module rrect2d(w, h, r) { offset(r) offset(-r) square([w, h]); } module post(x, y, z0, z1) { translate([x, y, z0]) difference() { cylinder(h = z1 - z0, d = 6); translate([0, 0, max(0.8, z1 - z0 - 8)]) cylinder(h = 9, d = M2_PILOT); } } // ================= ĐÁY ================= ESP_STRAP_X = 37; ESP_POSTS = [[ESP_STRAP_X, ESP_Y - 3.5], [ESP_STRAP_X, ESP_Y + ESP_W + 3.5]]; ESP_POST_TOP = ESP_Z + ESP_PCB + ESP_MOD_H - 0.3; CHG_STRAP_Y = CHG_Y + 7; CHG_POSTS = [[CHG_X - 4, CHG_STRAP_Y], [CHG_X + CHG_W + 4, CHG_STRAP_Y]]; CHG_POST_TOP = CHG_Z + CHG_PCB + 4; // thanh đè lên cuộn cảm qua lớp xốp 1 mm BAT_POSTS = [[BAT_X - 3.5, BAT_Y + BAT_IN_L/2], [BAT_X + BAT_IN_W + 3.5, BAT_Y + BAT_IN_L/2]]; // 2 tai kẹp ở hai đầu pin BAT_POST_TOP = FLOOR + BAT_T + 1.5; module base() { difference() { union() { difference() { rbox(W, H, BH, R); translate([WALL, WALL, FLOOR]) rbox(W - 2*WALL, H - 2*WALL, BH, R - WALL); } for (c = corners) translate([c[0], c[1], 0]) cylinder(h = BH, d = BOSS_D); // ESP32: bệ giữa (dán xốp), cữ chặn đầu phải, 2 trụ thanh kẹp translate([ESP_X + 9, ESP_Y + 16, 0]) cube([22, 8, ESP_Z - FOAM]); // đỡ nửa trên board, chừa chỗ dupont cong 90° phía dưới header translate([ESP_X + ESP_L + 0.5, ESP_Y + 19, 0]) cube([2, 6, ESP_Z + ESP_PCB]); for (p = ESP_POSTS) post(p[0], p[1], 0, ESP_POST_TOP); // Mạch sạc: 2 ray đỡ dọc mép, vách hai bên, 1 trụ tai kẹp phía trên for (x = [CHG_X - 1.5, CHG_X + CHG_W - 1]) translate([x, CHG_Y + 8, 0]) cube([2.5, CHG_L - 8, CHG_Z]); for (x = [CHG_X - 1.7, CHG_X + CHG_W + 0.5]) translate([x, CHG_Y + 8, 0]) cube([1.2, CHG_L - 8, CHG_Z + CHG_PCB]); for (p = CHG_POSTS) post(p[0], p[1], 0, CHG_POST_TOP); // Khay pin cao 6, hở đầu trái cho dây translate([0, 0, FLOOR]) difference() { translate([BAT_X - 1.5, BAT_Y - 1.5, 0]) cube([BAT_IN_W + 3, BAT_IN_L + 3, 6]); translate([BAT_X, BAT_Y, -1]) cube([BAT_IN_W, BAT_IN_L, 8]); translate([BAT_X - 2, BAT_Y + 6, -1]) cube([3, 14, 8]); } for (p = BAT_POSTS) post(p[0], p[1], 0, BAT_POST_TOP); } for (c = corners) translate([c[0], c[1], BH - INSERT_DEPTH]) cylinder(h = INSERT_DEPTH + 1, d = INSERT_D); // USB-C của mạch sạc, cạnh dưới translate([USB_X, WALL/2, USB_Z]) rotate([90, 0, 0]) linear_extrude(WALL + 2, center = true) translate([-USB_CUT_W/2, -USB_CUT_H/2]) rrect2d(USB_CUT_W, USB_CUT_H, 2); // Công tắc, thành phải translate([W - WALL - 1, SW_Y - SW_CUT_W/2, SW_Z - SW_CUT_H/2]) cube([WALL + 2, SW_CUT_W, SW_CUT_H]); } } // ================= NẮP (tọa độ in: mặt ngoài ở z = 0) ================= RC_TABS = [[RC_X - 4, RC_Y + 3], [RC_X - 4, RC_Y + RC_L - 3], [RC_X + RC_W + 4, RC_Y + 3], [RC_X + RC_W + 4, RC_Y + RC_L - 3]]; SPK_POSTS = [for (a = SPK_EARS) [SPK_X + SPK_SCREW_R*cos(a), SPK_Y + SPK_SCREW_R*sin(a)]]; LED_POSTS = [[LED_XS[0] - 5.5, LED_Y], [LED_XS[2] + 5.5, LED_Y]]; module tap_icon2d() { rotate(-45) translate([-7, -5]) difference() { rrect2d(14, 10, 1.8); translate([1.2, 1.2]) rrect2d(11.6, 7.6, 1); } } module waves2d() { for (r = [11, 15, 19]) intersection() { difference() { circle(r = r); circle(r = r - 1.3); } polygon([[0, 0], [30*cos(-38), 30*sin(-38)], [30, 0], [30*cos(38), 30*sin(38)]]); } } module lid() { difference() { union() { rbox(W, H, LID_T, R); translate([0, 0, LID_T]) difference() { // gờ định vị translate([WALL + LIP_IN, WALL + LIP_IN, 0]) rbox(W - 2*(WALL + LIP_IN), H - 2*(WALL + LIP_IN), LIP_H, R - WALL - LIP_IN); translate([WALL + LIP_IN + LIP_W, WALL + LIP_IN + LIP_W, -1]) rbox(W - 2*(WALL + LIP_IN + LIP_W), H - 2*(WALL + LIP_IN + LIP_W), LIP_H + 2, R - WALL - LIP_IN - LIP_W); for (c = corners) translate([c[0], c[1], -1]) cylinder(h = LIP_H + 2, r = BOSS_D/2 + 0.6); translate([W - WALL - 3, SW_Y - 9, -1]) cube([4, 18, LIP_H + 2]); // chừa thân công tắc } translate([0, 0, LID_T]) difference() { // khung RC522 translate([RC_X - 1.9, RC_Y - 1.9, 0]) cube([RC_W + 3.8, RC_L + 3.8, 2.5]); translate([RC_X - 0.4, RC_Y - 0.4, -1]) cube([RC_W + 0.8, RC_L + 0.8, 4]); for (t = RC_TABS) translate([t[0] - 6, t[1] - 4.5, -1]) cube([12, 9, 4]); } for (t = RC_TABS) translate([t[0], t[1], LID_T]) cylinder(h = RC_PCB, d = 6); translate([SPK_X, SPK_Y, LID_T]) difference() { cylinder(h = 2, d = SPK_D + 4.3); translate([0, 0, -1]) cylinder(h = 4, d = SPK_D + 0.8); } for (p = SPK_POSTS) translate([p[0], p[1], LID_T]) cylinder(h = SPK_FLANGE, d = 6); for (p = LED_POSTS) translate([p[0], p[1], LID_T]) cylinder(h = LED_FLANGE, d = 6); } for (c = corners) translate([c[0], c[1], 0]) { translate([0, 0, -1]) cylinder(h = LID_T + 5, d = M3_CLEAR); translate([0, 0, -0.01]) cylinder(h = (M3_CSK - M3_CLEAR)/2, d1 = M3_CSK, d2 = M3_CLEAR); } for (p = concat(RC_TABS, SPK_POSTS, LED_POSTS)) translate([p[0], p[1], 0.8]) cylinder(h = 10, d = M2_PILOT); translate([RC_X, RC_Y, LID_T - 1.2]) cube([10, RC_L, 2]); // chừa mối hàn header RC522 for (x = LED_XS) translate([x, LED_Y, -1]) cylinder(h = LID_T + 2, d = LED_HOLE); // lưới loa khe ngang kiểu V4 intersection() { translate([SPK_X, SPK_Y, -1]) cylinder(h = LID_T + 2, d = 32); for (k = [-6:6]) translate([SPK_X - 20, SPK_Y + k*2.6 - 0.75, -1]) cube([40, 1.5, LID_T + 2]); } // khắc chìm 0,6 mm translate([0, 0, -0.01]) linear_extrude(0.6) { translate([RC_ANT_X, RC_ANT_Y + 3]) { tap_icon2d(); waves2d(); mirror([1, 0]) waves2d(); } translate([RC_ANT_X, RC_Y + 2]) text("CHẠM THẺ", size = 5, font = "Liberation Sans:style=Bold", halign = "center"); translate([44, 18]) text("ĐIỂM DANH", size = 9, font = "Liberation Sans:style=Bold", halign = "center", valign = "center"); for (i = [0:2]) translate([LED_XS[i], LED_Y - 5.5]) text(["POWER", "READ", "STATUS"][i], size = 2, font = "Liberation Sans:style=Bold", halign = "center"); } } } // ================= KẸP IN RỜI ================= module bar(len, w, holes) { difference() { translate([-len/2, -w/2, 0]) linear_extrude(CLIP_T) rrect2d(len, w, w/2 - 0.01); for (h = holes) translate([h, 0, -1]) cylinder(h = CLIP_T + 2, d = M2_CLEAR); } } module tab_clip() { difference() { translate([-3.5, -3.5, 0]) linear_extrude(CLIP_T) rrect2d(11, 7, 1.5); translate([0, 0, -1]) cylinder(h = CLIP_T + 2, d = M2_CLEAR); } } module esp_strap() { bar(ESP_W + 13, 6, [-(ESP_W/2 + 3.5), ESP_W/2 + 3.5]); } module chg_strap() { bar(CHG_W + 14, 7, [-(CHG_W/2 + 4), CHG_W/2 + 4]); } module bat_tabs() { for (i = [0:1]) translate([BAT_POSTS[i][0], BAT_POSTS[i][1], BAT_POST_TOP]) rotate(i == 0 ? 0 : 180) tab_clip(); } module spk_ring() { difference() { union() { cylinder(h = CLIP_T, d = SPK_D + 6); rotate(SPK_EARS[0]) translate([-SPK_SCREW_R - 4, -4, 0]) linear_extrude(CLIP_T) rrect2d(2*SPK_SCREW_R + 8, 8, 3.9); } translate([0, 0, -1]) cylinder(h = CLIP_T + 2, d = SPK_D - 3); for (a = SPK_EARS) rotate(a) translate([SPK_SCREW_R, 0, -1]) cylinder(h = CLIP_T + 2, d = M2_CLEAR); } } module led_bar() { // ép vành LED vào mặt trong nắp; lỗ 3,4 cho chân LED lọt qua difference() { sp = LED_XS[1] - LED_XS[0]; translate([-(sp + 9), -3.5, 0]) linear_extrude(CLIP_T) rrect2d(2*sp + 18, 7, 3.4); for (x = [-sp, 0, sp]) translate([x, 0, -1]) cylinder(h = CLIP_T + 2, d = 3.4); for (x = [-(sp + 5.5), sp + 5.5]) translate([x, 0, -1]) cylinder(h = CLIP_T + 2, d = M2_CLEAR); } } module clips() { for (i = [0:3]) translate([8 + i*14, 8, 0]) tab_clip(); translate([72, 22, 0]) chg_strap(); translate([28, 22, 0]) esp_strap(); for (i = [0:1]) translate([50 + i*14, 36, 0]) tab_clip(); translate([30, 50, 0]) led_bar(); translate([38, 80, 0]) spk_ring(); } // ================= LẮP RÁP + KIỂM VA CHẠM ================= module lid_assembled() { translate([0, 0, D]) mirror([0, 0, 1]) lid(); } module clips_assembled() { for (t = RC_TABS) translate([t[0], t[1], BH - RC_PCB - CLIP_T]) rotate(t[0] < RC_X ? 0 : 180) tab_clip(); translate([USB_X, CHG_STRAP_Y, CHG_POST_TOP]) chg_strap(); translate([ESP_STRAP_X, ESP_Y + ESP_W/2, ESP_POST_TOP]) rotate(90) esp_strap(); bat_tabs(); translate([SPK_X, SPK_Y, BH - SPK_FLANGE - CLIP_T]) spk_ring(); translate([(LED_XS[0] + LED_XS[2])/2, LED_Y, BH - LED_FLANGE - CLIP_T]) led_bar(); } // Khối bao linh kiện thật (co 0,05 để chỗ tiếp xúc không tính là va chạm) module c_esp() { translate([ESP_X, ESP_Y, ESP_Z]) cube([ESP_L, ESP_W, ESP_PCB]); translate([ESP_X + 12, ESP_Y + 3.5, ESP_Z + ESP_PCB]) cube([26.5, 19, ESP_MOD_H - 0.35]); // module + anten (thanh kẹp ép 0,3 qua xốp) translate([ESP_X - 0.6, ESP_Y + 8.5, ESP_Z + ESP_PCB]) cube([7.4, 9, 3.3]); // USB-C translate([ESP_X + 5, ESP_Y + 19.5, ESP_Z + ESP_PCB]) cube([6, 6, 9]); // JST + giắc translate([ESP_X + 8, ESP_Y + 0.5, ESP_Z - 8.5]) cube([21, 2.6, 8.5]); // header cái translate([ESP_X + 8, ESP_Y + 0.5, ESP_Z - 8.5 - 4]) cube([21, 14, 4]); // hàng rào đực cong 90° + dây hàn } module c_chg() { translate([CHG_X, CHG_Y, CHG_Z]) cube([CHG_W, CHG_L, CHG_PCB]); translate([USB_X - 4.5, CHG_Y - 0.6, CHG_Z + CHG_PCB]) cube([9, 7.4, 3.3]); translate([CHG_X + 1, CHG_Y + 8, CHG_Z + CHG_PCB]) cube([CHG_W - 2, CHG_L - 9.5, 3.5]); // cuộn cảm, chip } module c_bat() { translate([BAT_X + 0.5, BAT_Y + 0.5, FLOOR]) cube([50, 40, 10]); } module c_spk() { translate([SPK_X, SPK_Y, BH - SPK_DEPTH]) { cylinder(h = 10, r = 11); // nam châm translate([0, 0, 10]) cylinder(h = 8.5, r1 = 12, r2 = 18); // rổ loa translate([0, 0, 18.5]) cylinder(h = 1.5, r = 20); // vành trước } } module c_rc() { translate([RC_X, RC_Y, BH - RC_PCB]) cube([RC_W, RC_L, RC_PCB]); translate([RC_X + 4, RC_Y + 4, BH - RC_PCB - 4]) cube([RC_W - 8, RC_L - 8, 4]); // linh kiện (mép 4 mm trống ở góc kẹp) translate([RC_X + 1.5, RC_Y + 6.5, BH - RC_PCB - 2.5 - 14]) cube([3, 21, 16.5]); // header + dupont } module c_sw() { translate([W - WALL - 13, SW_Y - 4.5, SW_Z - 6.5]) cube([13, 9, 13]); translate([W - WALL - 18, SW_Y - 3.5, SW_Z - 2.5]) cube([5, 7, 5]); // chân hàn } module c_leds() { for (x = LED_XS) translate([x, LED_Y, BH - 5.3 - 4]) cylinder(h = 9.3, d = 3); } module shrink() { minkowski() { children(); cube(0.001, center = true); } } module printed() { base(); lid_assembled(); clips_assembled(); } module comp(i) { if (i == 0) c_esp(); if (i == 1) c_chg(); if (i == 2) c_bat(); if (i == 3) c_spk(); if (i == 4) c_rc(); if (i == 5) c_sw(); if (i == 6) c_leds(); } // pair 0..6: linh kiện i vs phần in. pair 100 + i*10 + j: linh kiện i vs j. module check() { if (pair < 100) intersection() { resize_in() comp(pair); printed(); } else intersection() { resize_in() comp(floor((pair - 100)/10)); resize_in() comp((pair - 100) % 10); } } module resize_in() { children(); } if (part == "base") base(); if (part == "lid") lid(); if (part == "clips") clips(); if (part == "check") check(); if (part == "open") { color("#2b2f33") base(); color("orange") clips_assembled(); color("purple") c_esp(); color("navy") c_chg(); color("silver") c_bat(); color("red") c_sw(); } if (part == "assembled") { color("#2b2f33") base(); color("#eef0f2") lid_assembled(); color("orange") clips_assembled(); color("purple") c_esp(); color("navy") c_chg(); color("silver") c_bat(); color("dimgray") c_spk(); color("royalblue") c_rc(); color("red") c_sw(); color("lime") c_leds(); } // ---- Hình để làm ảnh minh họa đúng tỉ lệ ---- module lid_parts_assembled() { c_rc(); c_spk(); c_leds(); } if (part == "xray") { // nhìn từ trước, bỏ nắp, linh kiện gắn nắp vẫn giữ đúng vị trí color("#26292d") base(); color("#f28c28") clips_assembled(); color("#6a1b9a") c_esp(); color("#111418") c_chg(); color("#c9ccd1") c_bat(); color("#111111") c_sw(); color("#1f4fbf") c_rc(); color("#202022") c_spk(); for (i = [0:2]) color(["#2e9d3a", "#f2c200", "#d32f2f"][i]) translate([LED_XS[i], LED_Y, BH - 9.3]) cylinder(h = 9.3, d = 3); for (c = corners) color("#c9a227") translate([c[0], c[1], BH - 4]) cylinder(h = 4, d = 5); } if (part == "closed") { color("#26292d") base(); color("#f4f5f7") lid_assembled(); color("#111111") c_sw(); } // Tách lớp: đáy / lớp linh kiện đáy / lớp linh kiện nắp / nắp. ids = true: tô mỗi nhóm một màu thuần để dò vị trí. module exploded(ids = false) { k = function(c, id) ids ? id : c; color(k("#26292d", "#000080")) base(); translate([0, 0, 60]) { color(k("#6a1b9a", "#ff00ff")) c_esp(); color(k("#111418", "#00ffff")) c_chg(); color(k("#c9ccd1", "#ffff00")) c_bat(); color(k("#111111", "#ff8000")) c_sw(); color(k("#f28c28", "#808000")) { translate([ESP_STRAP_X, ESP_Y + ESP_W/2, ESP_POST_TOP]) rotate(90) esp_strap(); translate([USB_X, CHG_STRAP_Y, CHG_POST_TOP]) chg_strap(); bat_tabs(); } } translate([0, 0, 125]) { color(k("#1f4fbf", "#0000ff")) c_rc(); color(k("#202022", "#ff0000")) c_spk(); for (i = [0:2]) color(k(["#2e9d3a", "#f2c200", "#d32f2f"][i], "#00ff00")) translate([LED_XS[i], LED_Y, BH - 9.3]) cylinder(h = 9.3, d = 3); color(k("#f28c28", "#808000")) { for (t = RC_TABS) translate([t[0], t[1], BH - RC_PCB - CLIP_T]) rotate(t[0] < RC_X ? 0 : 180) tab_clip(); translate([SPK_X, SPK_Y, BH - SPK_FLANGE - CLIP_T]) spk_ring(); translate([(LED_XS[0] + LED_XS[2])/2, LED_Y, BH - LED_FLANGE - CLIP_T]) led_bar(); } } translate([0, 0, 190]) color(k("#f4f5f7", "#008000")) lid_assembled(); } if (part == "exploded") exploded(); if (part == "exploded_ids") exploded(true); layer = 0; // dùng với part="exploded_layer": 1 nắp, 2 linh kiện sau nắp, 3 linh kiện đáy, 4 đáy module exploded_layer(n) { if (n == 4) color("#26292d") base(); if (n == 3) translate([0, 0, 60]) { color("#6a1b9a") c_esp(); color("#111418") c_chg(); color("#c9ccd1") c_bat(); color("#111111") c_sw(); color("#f28c28") { translate([ESP_STRAP_X, ESP_Y + ESP_W/2, ESP_POST_TOP]) rotate(90) esp_strap(); translate([USB_X, CHG_STRAP_Y, CHG_POST_TOP]) chg_strap(); bat_tabs(); } } if (n == 2) translate([0, 0, 125]) { color("#1f4fbf") c_rc(); color("#202022") c_spk(); for (i = [0:2]) color(["#2e9d3a", "#f2c200", "#d32f2f"][i]) translate([LED_XS[i], LED_Y, BH - 9.3]) cylinder(h = 9.3, d = 3); color("#f28c28") { for (t = RC_TABS) translate([t[0], t[1], BH - RC_PCB - CLIP_T]) rotate(t[0] < RC_X ? 0 : 180) tab_clip(); translate([SPK_X, SPK_Y, BH - SPK_FLANGE - CLIP_T]) spk_ring(); translate([(LED_XS[0] + LED_XS[2])/2, LED_Y, BH - LED_FLANGE - CLIP_T]) led_bar(); } } if (n == 1) translate([0, 0, 190]) color("#f4f5f7") lid_assembled(); } if (part == "exploded_layer") exploded_layer(layer); module lid_clips_only() { for (t = RC_TABS) translate([t[0], t[1], BH - RC_PCB - CLIP_T]) rotate(t[0] < RC_X ? 0 : 180) tab_clip(); translate([SPK_X, SPK_Y, BH - SPK_FLANGE - CLIP_T]) spk_ring(); translate([(LED_XS[0] + LED_XS[2])/2, LED_Y, BH - LED_FLANGE - CLIP_T]) led_bar(); } module base_clips_except_bat() { translate([USB_X, CHG_STRAP_Y, CHG_POST_TOP]) chg_strap(); translate([ESP_STRAP_X, ESP_Y + ESP_W/2, ESP_POST_TOP]) rotate(90) esp_strap(); }