Skip to content

Commit c715759

Browse files
committed
feat: adiciona bayonet_mount() e bayonet_socket() para juntas twist-lock (#1323)
Implementa dois novos modulos em joiners.scad para juntas bayoneta: - bayonet_mount(d, h, pin_h, pins, pin_ang, taper_ang, clearance, wall): Cria pinos radiais em superficie cilindrica para encaixe twist-lock. Suporta taper para travamento por friccao, numero variavel de pinos, e tolerancias configuraveis. Compativel com attachable(). - bayonet_socket(d, h, pin_h, pins, pin_ang, clearance, wall): Cria slots em L correspondentes para receber os pinos do mount. Entrada vertical + canal horizontal de travamento. Clearance automatico para ajuste de impressao 3D. Ambos seguem o padrao BOSL2: attachable(), validacao de parametros, documentacao completa com Synopsis/SynTags/Topics/Examples. Testes adicionados em test_joiners.scadtest cobrindo variantes de pinos, taper, clearance e dimensoes.
1 parent b9c5dd7 commit c715759

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

joiners.scad

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,4 +1486,180 @@ module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer, rounding,
14861486
}
14871487
}
14881488

1489+
// Section: Bayonet Mounts
1490+
1491+
1492+
// Module: bayonet_mount()
1493+
// Synopsis: Creates a twist-lock bayonet mount with configurable pins.
1494+
// SynTags: Geom
1495+
// Topics: Joiners, Parts, 3D Printing
1496+
// See Also: snap_pin(), dovetail(), rabbit_clip()
1497+
// Usage:
1498+
// bayonet_mount(d, h, pin_h, [pins=], [pin_ang=], [taper_ang=], [clearance=], [wall=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
1499+
// Description:
1500+
// Creates a bayonet (twist-lock) mount — a set of pins/flanges on a
1501+
// cylindrical surface that lock into corresponding slots when twisted.
1502+
// Use with {{bayonet_socket()}} to create the mating part.
1503+
// .
1504+
// The mount produces radial pins on the outside of a cylinder. The pins
1505+
// have an optional taper angle for friction-fit locking. Designed to be
1506+
// printable without supports in the default orientation (pins pointing outward).
1507+
// Arguments:
1508+
// d = Outer diameter of the cylinder.
1509+
// h = Height of the cylindrical body.
1510+
// pin_h = Height (radial thickness) of each pin.
1511+
// ---
1512+
// pins = Number of pins evenly spaced around the cylinder. Default: 3
1513+
// pin_ang = Angular width of each pin in degrees. Default: 30
1514+
// taper_ang = Taper angle for friction locking, in degrees. Default: 0
1515+
// clearance = Gap for mating tolerance. Default: 0.2
1516+
// wall = Wall thickness of the cylinder. Default: 2
1517+
// anchor = Translate so anchor point is at origin. Default: `CENTER`
1518+
// spin = Rotate this many degrees around the Z axis. Default: `0`
1519+
// orient = Vector to rotate top toward. Default: `UP`
1520+
// Example: Basic 3-pin mount
1521+
// bayonet_mount(d=30, h=8, pin_h=2);
1522+
// Example: 4-pin with taper
1523+
// bayonet_mount(d=30, h=8, pin_h=2, pins=4, taper_ang=5);
1524+
// Example: Large pin angle
1525+
// bayonet_mount(d=40, h=10, pin_h=3, pin_ang=45, pins=2);
1526+
module bayonet_mount(
1527+
d, h, pin_h,
1528+
pins=3,
1529+
pin_ang=30,
1530+
taper_ang=0,
1531+
clearance=0.2,
1532+
wall=2,
1533+
anchor=CENTER,
1534+
spin=0,
1535+
orient=UP
1536+
) {
1537+
assert(is_finite(d) && d>0, "\nd must be a positive number.");
1538+
assert(is_finite(h) && h>0, "\nh must be a positive number.");
1539+
assert(is_finite(pin_h) && pin_h>0, "\npin_h must be a positive number.");
1540+
assert(is_integer(pins) && pins>=1, "\npins must be a positive integer.");
1541+
assert(is_finite(pin_ang) && pin_ang>0 && pin_ang<360/pins, "\npin_ang must be positive and less than 360/pins.");
1542+
assert(is_finite(taper_ang) && taper_ang>=0 && taper_ang<90, "\ntaper_ang must be between 0 and 90.");
1543+
r = d/2;
1544+
pin_step = 360 / pins;
1545+
attachable(anchor, spin, orient, d=d+2*pin_h, l=h) {
1546+
union() {
1547+
// Cylindrical body
1548+
tube(od=d, wall=wall, h=h);
1549+
// Pins
1550+
for (i = [0:1:pins-1]) {
1551+
zrot(i * pin_step)
1552+
difference() {
1553+
// Pin body: arc segment
1554+
intersection() {
1555+
tube(od=d+2*pin_h, id=d-0.01, h=h);
1556+
pie_slice(
1557+
d=d+2*pin_h+1,
1558+
h=h,
1559+
ang=pin_ang,
1560+
spin=-pin_ang/2
1561+
);
1562+
}
1563+
// Taper cut
1564+
if (taper_ang > 0) {
1565+
zrot(pin_ang/2)
1566+
fwd(d/2)
1567+
xrot(90-taper_ang)
1568+
cube([d+2*pin_h+2, h*2, h*2], center=true);
1569+
}
1570+
}
1571+
}
1572+
}
1573+
children();
1574+
}
1575+
}
1576+
1577+
1578+
// Module: bayonet_socket()
1579+
// Synopsis: Creates a socket (receiver) for a {{bayonet_mount()}}.
1580+
// SynTags: Geom
1581+
// Topics: Joiners, Parts, 3D Printing
1582+
// See Also: bayonet_mount(), snap_pin(), dovetail()
1583+
// Usage:
1584+
// bayonet_socket(d, h, pin_h, [pins=], [pin_ang=], [clearance=], [wall=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
1585+
// Description:
1586+
// Creates the socket (receiver) for a bayonet twist-lock mount.
1587+
// This is a cylinder with L-shaped slots that accept the pins from
1588+
// {{bayonet_mount()}} — insert vertically, then twist to lock.
1589+
// .
1590+
// The slot consists of a vertical entry channel and a horizontal
1591+
// locking channel. Clearance is added automatically for fit.
1592+
// Arguments:
1593+
// d = Inner diameter of the socket (matches mount outer diameter).
1594+
// h = Height of the socket body.
1595+
// pin_h = Depth of the slots (matches mount pin_h).
1596+
// ---
1597+
// pins = Number of slots matching the mount pins. Default: 3
1598+
// pin_ang = Angular width of each slot. Default: 30
1599+
// clearance = Extra clearance for mating tolerance. Default: 0.2
1600+
// wall = Wall thickness of the socket cylinder. Default: 2
1601+
// anchor = Translate so anchor point is at origin. Default: `CENTER`
1602+
// spin = Rotate this many degrees around the Z axis. Default: `0`
1603+
// orient = Vector to rotate top toward. Default: `UP`
1604+
// Example: Socket matching default mount
1605+
// bayonet_socket(d=30, h=12, pin_h=2);
1606+
// Example: 4-slot socket
1607+
// bayonet_socket(d=30, h=12, pin_h=2, pins=4);
1608+
module bayonet_socket(
1609+
d, h, pin_h,
1610+
pins=3,
1611+
pin_ang=30,
1612+
clearance=0.2,
1613+
wall=2,
1614+
anchor=CENTER,
1615+
spin=0,
1616+
orient=UP
1617+
) {
1618+
assert(is_finite(d) && d>0, "\nd must be a positive number.");
1619+
assert(is_finite(h) && h>0, "\nh must be a positive number.");
1620+
assert(is_finite(pin_h) && pin_h>0, "\npin_h must be a positive number.");
1621+
assert(is_integer(pins) && pins>=1, "\npins must be a positive integer.");
1622+
assert(is_finite(pin_ang) && pin_ang>0 && pin_ang<360/pins, "\npin_ang must be positive and less than 360/pins.");
1623+
r = d/2;
1624+
cl = clearance;
1625+
pin_step = 360 / pins;
1626+
slot_h = h/3; // Vertical entry is top third
1627+
lock_h = pin_h + 2*cl;
1628+
attachable(anchor, spin, orient, d=d+2*wall, l=h) {
1629+
difference() {
1630+
// Outer cylinder
1631+
tube(od=d+2*wall, id=d, h=h);
1632+
// L-shaped slots for each pin
1633+
for (i = [0:1:pins-1]) {
1634+
zrot(i * pin_step) {
1635+
// Vertical entry slot (top)
1636+
up(h/2 - slot_h/2)
1637+
intersection() {
1638+
tube(od=d+2*pin_h+2*cl+0.01, id=d-0.01, h=slot_h+0.01);
1639+
pie_slice(
1640+
d=d+2*pin_h+2*cl+1,
1641+
h=slot_h+0.01,
1642+
ang=pin_ang+2*cl,
1643+
spin=-(pin_ang+2*cl)/2
1644+
);
1645+
}
1646+
// Horizontal locking channel (bottom of entry)
1647+
up(h/2 - slot_h - lock_h/2 + 0.01)
1648+
intersection() {
1649+
tube(od=d+2*pin_h+2*cl+0.01, id=d-0.01, h=lock_h);
1650+
pie_slice(
1651+
d=d+2*pin_h+2*cl+1,
1652+
h=lock_h,
1653+
ang=pin_ang*2+2*cl,
1654+
spin=-(pin_ang+2*cl)/2
1655+
);
1656+
}
1657+
}
1658+
}
1659+
}
1660+
children();
1661+
}
1662+
}
1663+
1664+
14891665
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

tests/test_joiners.scadtest

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,39 @@ module test_rabbit_clip() {
117117
}
118118
test_rabbit_clip();
119119
'''
120+
121+
[[test]]
122+
name = "test_bayonet_mount"
123+
script = '''
124+
include <../std.scad>
125+
include <../joiners.scad>
126+
127+
module test_bayonet_mount() {
128+
$fn = 8;
129+
// Basico: 3 pinos padrao
130+
bayonet_mount(d=30, h=8, pin_h=2);
131+
// 4 pinos com taper
132+
bayonet_mount(d=30, h=8, pin_h=2, pins=4, taper_ang=5);
133+
// 2 pinos com angulo largo
134+
bayonet_mount(d=40, h=10, pin_h=3, pin_ang=45, pins=2);
135+
}
136+
test_bayonet_mount();
137+
'''
138+
139+
[[test]]
140+
name = "test_bayonet_socket"
141+
script = '''
142+
include <../std.scad>
143+
include <../joiners.scad>
144+
145+
module test_bayonet_socket() {
146+
$fn = 8;
147+
// Socket padrao
148+
bayonet_socket(d=30, h=12, pin_h=2);
149+
// 4 slots
150+
bayonet_socket(d=30, h=12, pin_h=2, pins=4);
151+
// Clearance customizado
152+
bayonet_socket(d=40, h=15, pin_h=3, clearance=0.3, wall=3);
153+
}
154+
test_bayonet_socket();
155+
'''

0 commit comments

Comments
 (0)