@@ -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 , "\n d must be a positive number." );
1538+ assert(is_finite(h) && h> 0 , "\n h must be a positive number." );
1539+ assert(is_finite(pin_h) && pin_h> 0 , "\n pin_h must be a positive number." );
1540+ assert(is_integer(pins) && pins>= 1 , "\n pins must be a positive integer." );
1541+ assert(is_finite(pin_ang) && pin_ang> 0 && pin_ang< 360 /pins, "\n pin_ang must be positive and less than 360/pins." );
1542+ assert(is_finite(taper_ang) && taper_ang>= 0 && taper_ang< 90 , "\n taper_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 , "\n d must be a positive number." );
1619+ assert(is_finite(h) && h> 0 , "\n h must be a positive number." );
1620+ assert(is_finite(pin_h) && pin_h> 0 , "\n pin_h must be a positive number." );
1621+ assert(is_integer(pins) && pins>= 1 , "\n pins must be a positive integer." );
1622+ assert(is_finite(pin_ang) && pin_ang> 0 && pin_ang< 360 /pins, "\n pin_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
0 commit comments