diff --git a/readme.md b/readme.md index 89b2410..9f76dad 100644 --- a/readme.md +++ b/readme.md @@ -2680,7 +2680,9 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o | 1 | `potentiometer(BTT_encoder)` | BTT_encoder | | 1 | `box_header(2p54header, 4, 2)` | Box header 4 x 2 | | 1 | `box_header(2p54header, 4, 2, right_angle = true)` | Box header 4 x 2 right angle | +| 1 | `rd_disc(10mm_disc, "1nF Y2")` | Ceramic capacitor, 10mm_disc 1nF Y2 | | 1 | `rd_disc(6p4mm_disc, "100n")` | Ceramic capacitor, 6p4mm_disc 100n | +| 1 | `rd_cm_choke(ATX_CM_CHOKE ,"3.5mH")` | Common mode choke 3.5mH | | 1 | `rd_xtal(ACT1100, "40MHz")` | Crystal ACT1100 40MHz | | 1 | `rd_xtal(ACT1700, "80MHz")` | Crystal ACT1700 80MHz | | 1 | `rd_xtal(C_002RX, "60KHz")` | Crystal C_002RX 60KHz | @@ -2716,6 +2718,7 @@ PCBs and perfboard with optional components. The shape can be a rectangle with o | 1 | `pin_socket(2p54header, 4, 1)` | Pin socket 4 x 1 | | 1 | `pin_socket(2p54header, 6, 1)` | Pin socket 6 x 1 | | 2 | `pin_socket(2p54header, 8, 1)` | Pin socket 8 x 1 | +| 1 | `rd_coil(IND16x10 ,"4.7uH")` | Radial inductor 16x10 4.7uH | | 1 | `rd_transistor(TO92, "78L05")` | Regulator TO92 78L05 | | 1 | `rd_module(HF33F, "012-HSL-3F")` | Relay HF33F / 012-HSL-3F | | 1 | `ax_res(res1_2, 10, tol = 10)` | Resistor 10 Ohms 10% 0.5W | @@ -3429,6 +3432,15 @@ Radial components for PCBs. | `rd_boxc_size(type)` | Overall size and corner radius | | `rd_boxc_skirt(type)` | Skirt slot, thickness, height | | `rd_boxc_z(type)` | Height of inner base above PCB. | +| `rd_cm_choke_core(type)` | Core OD, ID, width, corner radius | +| `rd_cm_choke_csep(type)` | Central separator thickness in slot, total thickness, height | +| `rd_cm_choke_seam(type)` | Overlapping semicircular seams to join the two halves of the core width and thickness | +| `rd_cm_choke_slot(type)` | Slot to hold central separator width, height, thickness | +| `rd_cm_choke_wire(type)` | Wire positions, length and diameter | +| `rd_coil_colour(type)` | Core colour | +| `rd_coil_size(type)` | OD, ID, height, coil height | +| `rd_coil_turns(type)` | Number of turns | +| `rd_coil_wire(type)` | Wire pitch, diameter and length | | `rd_disc_colours(type)` | Colours of body and text | | `rd_disc_kind(type)` | Capacitor, etc | | `rd_disc_lead_d(type)` | Lead diameter and sleeve diameter | @@ -3459,6 +3471,8 @@ Radial components for PCBs. | Module | Description | |:--- |:--- | | `rd_box_cap(type, kind, value)` | Draw radial boxed film capacitor | +| `rd_cm_choke(type, value)` | Draw specified common mode choke. | +| `rd_coil(type, value, pitch = undef)` | Draw the specified vertical coil | | `rd_disc(type, value, pitch = undef, z = 0, tail = 3)` | Draw a radial disc component | | `rd_electrolytic(type, value, pitch = undef, z = 0, tail = 3)` | Draw a radial electrolytic capcacitor | | `rd_module(type, value)` | Draw a PCB mounted potted module, e.g. PSU or relay | @@ -3470,7 +3484,9 @@ Radial components for PCBs. ### Vitamins | Qty | Module call | BOM entry | | ---:|:--- |:---| +| 1 | `rd_disc(10mm_disc, "1nF Y2")` | Ceramic capacitor, 10mm_disc 1nF Y2 | | 1 | `rd_disc(6p4mm_disc, "10nF")` | Ceramic capacitor, 6p4mm_disc 10nF | +| 1 | `rd_cm_choke(ATX_CM_CHOKE ,"3.5mH")` | Common mode choke 3.5mH | | 1 | `rd_xtal(ACT1100, "ACT1100")` | Crystal ACT1100 ACT1100 | | 1 | `rd_xtal(ACT1700, "ACT1700")` | Crystal ACT1700 ACT1700 | | 1 | `rd_xtal(C_002RX, "C_002RX")` | Crystal C_002RX C_002RX | @@ -3480,6 +3496,7 @@ Radial components for PCBs. | 1 | `rd_module(LDE10_20B, "12V 900ma")` | PSU LDE10_20B / 12V 900ma | | 1 | `rd_module(VCE03, "12V 250ma")` | PSU VCE03 / 12V 250ma | | 2 | `pcb(PERF70x50)` | Perfboard 70 x 50mm | +| 1 | `rd_coil(IND16x10 ,"4.7uH")` | Radial inductor 16x10 4.7uH | | 1 | `rd_module(HF33F, "012-HSL3F")` | Relay HF33F / 012-HSL3F | | 1 | `rd_transistor(E_LINE, "ZTX853")` | Transistor E_LINE ZTX853 | | 1 | `rd_transistor(TO92, "BC337")` | Transistor TO92 BC337 | @@ -7580,6 +7597,7 @@ Each vertex, apart from the first and the last, has an associated radius and the | `segmented_path(path, min_segment)` | Add points to a path to enforce a minimum segment length | | `skin_faces(points, npoints, facets, loop, offset = 0)` | Create the mesh for the swept volume without end caps | | `spiral_paths(path, n, r, twists, start_angle)` | Create a new paths which spiral around the given path. Use for making twisted cables | +| `spiral_wrap(path, profile, pitch, turns)` | Create a path that spirals around the specified profile with the given pitch. | | `sweep(path, profile, loop = false, twist = 0)` | Generate the point list and face list of the swept volume | ### Modules diff --git a/tests/PCB.scad b/tests/PCB.scad index 1c06335..4de0e4d 100644 --- a/tests/PCB.scad +++ b/tests/PCB.scad @@ -134,6 +134,7 @@ test_pcb = ["test_pcb", "Test PCB", [ 25, 190, 0, "rd_electrolytic", ECAP8x11, "220uF35V"], [ 25, 180, 90, "rd_disc", ERZV07D471, "471"], [ 25, 170, 90, "rd_disc", 6p4mm_disc, "100n"], + [ 30, 170, 90, "rd_disc", 10mm_disc, "1nF Y2"], [ 90, 135, -90, "rd_module", HF33F, "012-HSL-3F"], [ 35, 3, 0, "link", 0, 5], // Vertical wire @@ -189,7 +190,7 @@ test_pcb = ["test_pcb", "Test PCB", [ 52, 200, 0, "pcb", 11, TMC2130 ], [ 76, 210, 0, "pdip", 24, "27C32", true, inch(0.6) ], [ 80, 180, 0, "pdip", 8, "NE555" ], - [ 71, 180, 0, "smd_inductor", IND2525, "4R7"], + [ 71, 180, 0, "smd_inductor", IND2525, "4R7"], [ 87, 166, -90, "smd_soic", SOIC18, "PIC18F88"], [ 78, 166, -90, "smd_soic", SOIC14, "74HC00"], @@ -197,14 +198,16 @@ test_pcb = ["test_pcb", "Test PCB", [ 64, 166, -90, "smd_soic", SOIC8, "M34063"], [ 70, 150, 0, "chip", 10, 5, 1, grey(20)], - [90, 140, -90, "relay", HF33F, "012-HSL-3F"], + [ 90, 140, -90, "relay", HF33F, "012-HSL-3F"], [ 52, 206, 0, "2p54socket", 8, 1 ], [ 52, 194, 0, "2p54socket", 8, 1, false, 0, false, "red" ], - [ 50, 220, 0, "standoff", 5, 4.5, 12.5, 2.54], - [ 50, 240, 0, "potentiometer"], + [ 55, 220, 0, "standoff", 5, 4.5, 12.5, 2.54], + [ 60, 240, 0, "potentiometer"], [ 75, 240, 0, "potentiometer", KY_040_encoder, 8], + [ 40, 235, -90, "rd_cm_choke", ATX_CM_CHOKE, "3.5mH"], + [ 40, 217, 0, "rd_coil", IND16x10, "4.7uH"], [ 30, 85, -90, "7seg", WT5011BSR, 2], [ 30, 55, -90, "D_plug", DCONN9], ], diff --git a/tests/png/pcb.png b/tests/png/pcb.png index 10e441c..af7a33b 100644 Binary files a/tests/png/pcb.png and b/tests/png/pcb.png differ diff --git a/tests/png/radials.png b/tests/png/radials.png index bd422ea..c3d178b 100644 Binary files a/tests/png/radials.png and b/tests/png/radials.png differ diff --git a/tests/radials.scad b/tests/radials.scad index 1cabc7c..222d2e2 100644 --- a/tests/radials.scad +++ b/tests/radials.scad @@ -21,7 +21,9 @@ include <../vitamins/pcbs.scad> module radials() { pcb = PERF70x50; + $solder = pcb_solder(pcb); pcb(pcb); + translate([0, pcb_width(pcb) + inch(0.2)]) { pcb(pcb); @@ -36,9 +38,17 @@ module radials() { for(i = [0 : len(rd_box_caps) - 1]) pcb_grid(pcb, 20, i * 4) rd_box_cap(rd_box_caps[i], "X2 rated film capacitor", ["0.1uF 250V", "0.47uF 250V"][i]); + + + for(i = [0 : len(rd_cm_chokes) - 1]) + pcb_grid(pcb, 10.5, 2) + rd_cm_choke(rd_cm_chokes[i], "3.5mH"); + + pcb_grid(pcb, 4, 2.5) + rotate(90) + rd_coil(rd_coils[0], "4.7uH"); } - $solder = pcb_solder(pcb); for(i = [0 : len(rd_xtals) - 1]) pcb_grid(pcb, [0.5, 1, 1.5, 9, 1][i], [4, 6, 10.5, 10.5, 16][i]) @@ -51,7 +61,6 @@ module radials() { rotate(-90) rd_module(rd_modules[1], "12V 250ma"); - for(i = [0 : len(rd_discs) - 1]) pcb_grid(pcb, 1 + 2.5 * i, 1) { disc = rd_discs[i]; @@ -60,7 +69,7 @@ module radials() { dy = round(pitch.y / inch(0.1)) * inch(0.1); rotate(90 - atan2(dy, dx)) - rd_disc(disc, pitch = norm([dy, dx]), z = 0.5, value = ["10nF", "470V",][i]); + rd_disc(disc, pitch = norm([dy, dx]), z = 0.5, value = ["10nF", "470V", "1nF Y2"][i]); } for(i = [0 : len(rd_transistors) - 1]) diff --git a/utils/sweep.scad b/utils/sweep.scad index d978425..aec3e8f 100644 --- a/utils/sweep.scad +++ b/utils/sweep.scad @@ -263,3 +263,29 @@ module show_path(path, r = 0.1) //! Show a path using a chain of hulls for debug translate(path[i]) color("red") sphere($fn = 16, r * 4); } + +function move_along(j, z, path_S) = + j >= len(path_S) - 1 || z <= path_S[j] ? j : move_along(j + 1, z, path_S); + +function spiral_wrap(path, profile, pitch, turns) = //! Create a path that spirals around the specified profile with the given pitch. + let( + transforms = sweep_transforms(path, loop = false, twist = 0), + plen = len(profile), + S = path_length(profile), + profile = [ + for(i = 0, s = 0; i < plen; s = s + norm(profile[(i + 1) % plen] - profile[i]), i = i + 1) + let(p = profile[i]) [p.x, p.y, p.z + pitch * s / S, 1] + ], + path_len = len(path), + path_S = [for(i = 0, s = 0; i < path_len; s = s + norm(path[(i + 1) % path_len] - path[i]), i = i + 1) s], + n = turns * plen, + + ) [ + for(i = 0, j = 0, k = 0, zstep = 0; + i < n; + i = i + 1, + k = i % plen, + zstep = floor(i / plen) * pitch, + j = move_along(j, zstep + profile[k].z, path_S)) + if(!i || k) (profile[k] + [0, 0, zstep - path_S[j], 0]) * transforms[j] + ]; diff --git a/vitamins/pcb.scad b/vitamins/pcb.scad index 5abf61a..e54cac0 100644 --- a/vitamins/pcb.scad +++ b/vitamins/pcb.scad @@ -1170,6 +1170,8 @@ module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb compon if(show(comp, "rd_transistor")) rd_transistor(type = comp[4], value = comp[5], lead_positions = param(6, undef), z = param(7, 5), kind = param(8,"Transistor")); // type, value, lead positions, z, kind if(show(comp, "rd_box_cap")) rd_box_cap(type = comp[4], kind = comp[5], value = comp[6]); + if(show(comp, "rd_cm_choke")) rd_cm_choke(type = comp[4], value = comp[5]); + if(show(comp, "rd_coil")) rd_coil(type = comp[4], value = comp[5], pitch = param(6, undef)); if(show(comp, "link")) wire_link(l = comp[4], h = param(5, 1), d = param(6, 0.8), tail = param(7, 3), sleeve = param(8, false)); if(show(comp, "D_plug")) translate_z(d_pcb_offset(comp[4])) d_plug(comp[4], pcb = true); if(show(comp, "molex_hdr")) molex_254(comp[4], param(5, 0), param(6, undef)); diff --git a/vitamins/radial.scad b/vitamins/radial.scad index c9248e5..7211d9b 100644 --- a/vitamins/radial.scad +++ b/vitamins/radial.scad @@ -451,3 +451,179 @@ module rd_box_cap(type, kind, value) { //! Draw radial boxed film capacitor resize([size.x * 0.9, size.z / 6]) text(value, halign = "left", valign = "top"); } + +function rd_cm_choke_core(type) = type[1]; //! Core OD, ID, width, corner radius +function rd_cm_choke_seam(type) = type[2]; //! Overlapping semicircular seams to join the two halves of the core width and thickness +function rd_cm_choke_slot(type) = type[3]; //! Slot to hold central separator width, height, thickness +function rd_cm_choke_csep(type) = type[4]; //! Central separator thickness in slot, total thickness, height +function rd_cm_choke_wire(type) = type[5]; //! Wire positions, length and diameter + +module rd_cm_choke(type, value) { //! Draw specified common mode choke. + vitamin(str("rd_cm_choke(", type[0], " ,\"", value, "\"): Common mode choke ", value)); + core = rd_cm_choke_core(type); + seam = rd_cm_choke_seam(type); + slot = rd_cm_choke_slot(type); + csep = rd_cm_choke_csep(type); + wire = rd_cm_choke_wire(type); + or = core.x / 2; + ir = core.y / 2; + core_w = core.z; + core_r = core[3]; + z = seam.y + or; + wire_r = wire[3] / 2; + w = or - ir; + $fs = fs; $fa = fa; + + color(grey(90)) + translate_z(z) { + rotate([90, 0, 0]) { + rotate_extrude() + translate([(ir + or) / 2, 0]) + rounded_square([w, core_w], core_r, center = true); + + for(h = [true, false]) + hflip(h) + rotate(-90) + rotate_extrude(angle = 180) + translate([or, 0]) + square([seam.y, seam.x]); + } + r = sqrt(sqr(or * cos(180 / r2sides(or))) - sqr(slot.z + csep.x / 2)); + for(x = [-1, 1], z = [-1, 1]) + translate([x * (csep.x / 2 + slot.z / 2), 0, z * (r - slot.y / 2)]) + rotate([0, 90, 0]) + rounded_rectangle([slot.y, slot.x, slot.z], core_r, center = true); + + rotate([0, 90, 0]) { + rounded_rectangle([2 * ir, slot.x, csep.x], core_r, center = true); + + rounded_rectangle([csep.z, slot.x, csep.y], core_r, center = true); + } + } + + color(silver) + for(x = [-1, 1], y = [-1, 1]) + translate([x * wire.x / 2, y * wire.y / 2]) { + solder(wire_r); + + vflip() + cylinder(r = wire_r, h = wire.z, $fn = fn); + } + + color(copper) { + wire_d = 2 * wire_r; + r = ir - wire_r; + cr = core_r + wire_r; + points = [ + [-core_w / 2 + core_r, 0, 0], + [ core_w / 2 + wire_r, 0, 0], cr, + [ core_w / 2 + wire_r, w + wire_r, 0], cr, + [ 0, w + wire_d + seam.y * 2, 0], 7, + [-core_w / 2 - wire_r, w + wire_r, 0], cr, + [-core_w / 2 - wire_r, 0, 0], cr - eps, + [-core_w / 2 + core_r, 0, 0], + ]; + profile = segmented_path(rounded_path(points, $fn = fn), fs); + min_gap_angle = 2 * asin((slot.z + csep.x / 2 + wire_r) / r); + turns = floor((r * PI * (180 - min_gap_angle) / 180) / wire_d); + turn_angle = wire_d / (r * PI) * 180; + //turns = floor(((or + wire_r) * PI * (180 - min_gap_angle) / 180) / wire_d / 2); + //turn_angle = 2 * asin(wire_d / (or + wire_r)); + gap_angle = 180 - turns * turn_angle; + path = arc_points(r, a = [90, 180 + gap_angle / 2, 180], al = 180 - gap_angle, $fn = turns * len(profile)); + spiral = spiral_wrap(path, profile, path_length(path) / turns, turns); + tail = bezier_join([[wire.x / 2, wire.y / 2, -z - eps], [wire.x / 2, wire.y / 2, -z]], spiral, 1.5); + tilt = turn_angle * (or + wire_r) / 120; + + outer_points = [ + [ core_w / 2 - core_r - wire_d, -wire_d, 0], + [-core_w / 2 - wire_r - wire_d, -wire_d, 0], cr + wire_d, + [-core_w / 2 - wire_r, w + wire_r, tilt / 2], cr, + [ 0, w + wire_d + seam.y * 2, -tilt / 4], 7, // No idea why -tilt / 2.5 and not zero. + [ core_w / 2 + wire_r, w + wire_r, -tilt / 1.5], cr, + [ core_w / 2 + wire_r + wire_d, -wire_d, 0], cr + wire_d, + [ core_w / 2 - core_r - wire_d, -wire_d, 0], + ]; + + outer_profile = segmented_path(rounded_path(outer_points, $fn = fn), fs); + outer_path = arc_points(r, a = [90, 180 + gap_angle / 2 + turn_angle / 2, 180], al = 180 - gap_angle, $fn = (turns - 1) * len(outer_profile)); + outer_spiral = concat(spiral_wrap(outer_path, outer_profile, path_length(outer_path) / turns, turns), [spiral[len(spiral) - 1]]); + outer_tail = bezier_join([[wire.x / 2, -wire.y / 2, -z - eps], [wire.x / 2, -wire.y / 2, -z]], outer_spiral, 3); + + wire_points = circle_points(wire_r, $fn = fn); + translate_z(z) + for(side = [-1, 1]) mirror([side < 0 ? 1 : 0, 0]){ + color(copper)sweep(tail, wire_points); + + sweep(outer_tail, wire_points); + } + } +} + +function rd_coil_size(type) = type[1]; //! OD, ID, height, coil height +function rd_coil_wire(type) = type[2]; //! Wire pitch, diameter and length +function rd_coil_colour(type) = type[3]; //! Core colour +function rd_coil_turns(type) = type[4]; //! Number of turns + +module rd_coil(type, value, pitch = undef) { //! Draw the specified vertical coil + size = rd_coil_size(type); + wire = rd_coil_wire(type); + pitch = is_undef(pitch) ? wire.x : pitch; + wire_d = wire.y; + wire_r = wire_d / 2; + vitamin(str("rd_coil(", type[0], " ,\"", value, "\"): Radial inductor ", size.z, "x", size.x, " ", value)); + $fs = fs; $fa = fa; + end = (size.z - size[3]) / 2; + function sigmoid(x) = 1 / (1 + exp(-x)); + z = end + size[3] / 2; + h = size[3] - wire_d; + + color(rd_coil_colour(type)) { + cylinder(d = size.y, h = size.z); + + for(z = [0, size.z - end]) + translate_z(z) + cylinder(d = size.x, h = end); + } + turns = rd_coil_turns(type); + + color(silver) + for(side = [-1, 1]) + translate([side * pitch / 2, 0]) { + vflip() + cylinder(d = wire_d, h = wire.z, $fn = fn); + + solder(wire.y / 2); + } + + color(copper) { + r = size.y / 2 + wire_r; + sides = r2sides4n(r); + leadin = sides / 4; + total = sides * turns; + shortcut = 3; + spiral = [ + for(i = [shortcut: total - shortcut]) + let(a = 360 * i / sides, + j = i <= leadin ? leadin - i : i >= total - leadin ? i - (total - leadin) : 0, + R = r + j * wire_r / leadin + ) + [R * cos(a), R * sin(a), (size[3] - wire.y) * i / total + end + wire_r] + ]; + half_spiral = [ + for(i = [sides / 2 - shortcut : -1 : shortcut * 2]) + let(a = 360 * i / sides, R = r + wire_d) + [R * cos(a), R * -sin(a), h * sigmoid((i - sides / 4) / 2) + end + wire_r] + + ]; + path = bezier_join([[-pitch / 2, 0, -eps], [-pitch / 2, 0, 0]], bezier_join(bezier_join(half_spiral, spiral, 1), [[pitch / 2, 0, 0], [pitch / 2, 0, -eps]], 3), 3); + sweep(path, circle_points(wire_r, $fn = fn)); + } + + color("white") + translate_z(size.z) + linear_extrude(eps) + resize([size.x * 0.9, 0], auto = true) + text(value, halign = "center", valign = "center"); + +} diff --git a/vitamins/radials.scad b/vitamins/radials.scad index 70c70ad..44106c2 100644 --- a/vitamins/radials.scad +++ b/vitamins/radials.scad @@ -38,10 +38,11 @@ LDE10_20B = ["LDE10_20B","PSU", [53.8, 28.8, 19.0], 0.5, grey(20), [1.0, 0, rd_modules = [HF33F, VCE03, LDE10_20B]; // Disks -ERZV07D471 = ["ERZV07D471", "Varistor", [6.5, 5.0, 8.0], [4.75, 3.1], [0.6, 1.4], [grey(20), grey(80)]]; -6p4mm_disc = ["6p4mm_disc","Ceramic capacitor", [6.5, 2.1, 7.8], [5.0, 0.9], [0.6, 0.8], ["#C5702D", grey(20)]]; +ERZV07D471 = ["ERZV07D471", "Varistor", [6.5, 5.0, 8.0], [4.75, 3.1], [0.6, 1.4], [grey(20), grey(80)]]; +6p4mm_disc = ["6p4mm_disc", "Ceramic capacitor", [6.5, 2.1, 7.8], [5.0, 0.9], [0.6, 0.8], ["#C5702D", grey(20)]]; +10mm_disc = ["10mm_disc", "Ceramic capacitor", [10, 4.25, 12], [7.72, 0], [0.64, 2.0], ["#BA9C16", grey(20)]]; -rd_discs = [6p4mm_disc, ERZV07D471]; +rd_discs = [6p4mm_disc, ERZV07D471, 10mm_disc]; // Transistors TO92 = ["TO92", [5.0, 3.9, 4.5], [grey(20), grey(80)], [0.48, 0.48], [[-1,0], [0,0], [1,0]] ]; @@ -60,4 +61,12 @@ BOXC18x10x16 = ["BOXC18x10x16", [18, 10, 16, 0.25], 1.7, [12, 0.8, 0.4], [15, 0. rd_box_caps = [BOXC18x5x11, BOXC18x10x16]; +ATX_CM_CHOKE = ["ATX_CM_CHOKE", [17.4, 11.4, 9, 0.5], [2, 0.8], [11, 4.7, 0.8], [1, 2.4, 6.8], [inch(0.3), inch(0.4), 3, 0.65]]; + +rd_cm_chokes = [ATX_CM_CHOKE]; + +IND16x10 = ["IND16x10", [10, 6.7, 16, 10], [inch(0.5), 0.9, 3], grey(20), 10]; + +rd_coils = [IND16x10]; + use