// // Anybeam OpenSCAD Library // // This library provides an anybeam() module that can be used to create beams // with a variaty of hole, axle and slot patterns using a simple declaritive syntax. // // // Beam String // // A beam is speficied with a sequence of characters, each representing a hole // type in the beam. // // O Pin hole // X Axle hole // ( Half hole with a slot on the right. // ) Half hole with the slot on the left. // - (dash) A full width slot, use with ( and ) to create long slots with half hole ends like "(--)" (4 span slot) or "()" (2 span slot) // | (line) Pin hole at the edge (rotated 90 degree in respect to normal pin hole). Beam will be rotated 90 degree if at least one its end is "|", and none of its ends are "O". // # (hash) Axle hole at the edge. // . (period) Skip this hole. // // Use the above characters to represent the hole layout on the beam: // // XOOOOX - Size 6 beam with axle holes at the ends. // OOXOO - Size 5 beam with an axle hole in the middle. // (---)OOO - Size 8 beam with a size 5 slot and three holes at the end. // // Between each beam is a connection vector that defines how the beams connect. // // [ PREVIOUS_BEAM_HOLE, CURRENT_BEAM_HOLE, ANGLE ] // // * Holes are numbered from 1 to N (the length of the beam) from left to right. // * Angles are in degrees. // // Here is a standard 4x2 90 degree lift arm: // // [ "XOOO", [ 4, 1, 90 ], "OO" ] // // The connection hole specifier may includ a fractional part. // // // Fractional Hole Spacing // // Here is a 4x2 beam with the size 2 beam in the midde of the size 4 beam. // The space prevents a hole from appearing at the start of the beam where // the two overlap. // // Connecting hole 2.5 of the size 4 beam to hole 1 of the size 2 beam at 90 degrees. // // [ "OOOO", [ 2.5, 1, 90 ], ".O" ] // // // Examples: // Constants. AB_HOLE_SPACING = 8.0; AB_HOLE_INSIDE_DIAMETER = 5.4; AB_STUD_DIAMETER = 4.8; AB_HOLE_RING_DIAMETER = 6.28; AB_HOLE_RING_DEPTH = 0.9; AB_BEAM_WIDTH = 7.8; // originally 7.6, restore if you want slightly thinner beams like standard ones AB_AXLE_GAP = 1.95; AB_AXLE_LENGTH = 5.1; AB_BEAM_HEIGHT = 7.8; AB_THIN_BEAM_HEIGHT = AB_BEAM_HEIGHT/3; // From roipoussiere's string functions - https://www.thingiverse.com/thing:202724 function ab_fill(car, nb_occ, out="") = (nb_occ == 0) ? out : str(ab_fill(car, nb_occ-1, out), car); //anybeam( [ "XOOO", [ 4, 1, 53.13 ], "OOO()", [ 5, 1, -53.13 ], "(-)X" ], 1 ); //anybeam( [ "X##X", [ 4, 1, 90 ], "X|OO|X", [ 6, 1, 90 ], "X##X", [ 4, 1, 90 ], "X|OO|X" ], 1); // Standard small frame //anybeam( [ "O|||O", [ 5, 1, 90 ], "O|O|O|O", [ 7, 1, 90 ], "O|||O", [ 5, 1, 90 ], "O|O|O|O" ], 1); // Standard big frame //anybeam( [ "O|||O", [ 5, 3, 90 ], "||O|O|O|O||", [ 9, 1, 90 ], "O|||O", [ 5, 3, 90 ], "||O|O|O|O||" ], 1); //anybeam( [ "|O|O|", [ 5, 1, 90 ], "_|O|O|O|_", [ 9, 1, 90 ], "|O|O|", [ 5, 1, 90 ], "_|O|O|O|_" ], 1); //anybeam_tee(stem="|O|", top="_O|"); module anybeam( beams = [], height = 1 ) { translate([0, 0, height/2]) { difference() { ab_beams( beams, height * AB_BEAM_HEIGHT ); ab_holes( beams, height * AB_BEAM_HEIGHT ); } } } module anybeam_straight( holes = 10, height = 1 ) { if( len(holes )) { anybeam( [ holes ], height); } else { anybeam( [ ab_fill("O", holes ) ], height); } } module anybeam_tee( stem = "OOO", top = "OOO", height = 1 ) { anybeam( [ stem, [ 2, 1, 90 ], top ], height ); } module anybeam_143( left = "XOOO", right = "OOOOOX", height = 1 ) { anybeam( [ left, [ len(left), 1, 53.13 ], right ], height ); } module anybeam_90(left = "XOOO", right = "OO", height = 1) { anybeam( [ left, [ len(left), 1, 90 ], right ], height ); } module anybeam_135x2(left = "XOOOOOO", middle = " () ", right = "OOX", height = 1) { anybeam( [ left, [ len(left), 1, 45 ], middle, [ len(middle), 1, 45], right ], height ); } // // Test beam that uses all features. // module anybeam_test(left = "XOOOOOO", middle = "O(-) ", right = 3, height = 1) { anybeam( [ left, [ len(left), 3, 45 ], middle, [ len(middle), 1, 45], right ], height ); } // // Support Modules // // // Layout beam holes. // module ab_holes( beams = [], height = AB_BEAM_HEIGHT, b = 0 ) { beam = beams[b]; connection = beams[b-1]; next_beam = beams[b+2]; if( connection ) { if( next_beam ) { translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] ) rotate([0, 0, connection[2]]) translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] ) ab_beam_holes( beam, height ) ab_holes( beams, height, b+2 ); } else { translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] ) rotate([0, 0, connection[2]]) translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] ) ab_beam_holes( beam, height ); } } else { if( next_beam ) { ab_beam_holes( beam, height ) ab_holes( beams, height, b+2 ); } else { ab_beam_holes( beam, height ); } } } // // Layout solid beams. // module ab_beams( beams = [], height = AB_BEAM_HEIGHT, b = 0 ) { beam = beams[b]; connection = beams[b-1]; next_beam = beams[b+2]; if( connection ) { if( next_beam ) { translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] ) rotate([0, 0, connection[2]]) translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] ) ab_solid_beam( beam, height ) ab_beams( beams, height, b+2 ); } else { translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] ) rotate([0, 0, connection[2]]) translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] ) ab_solid_beam( beam, height ); } } else { if( next_beam ) { ab_solid_beam( beam, height ) ab_beams( beams, height, b+2 ); } else { ab_solid_beam( beam, height ); } } } // // A single solid beam. // module ab_solid_beam( beam = "OOOO", beam_height = AB_BEAM_HEIGHT ) { holes = len(beam) ? len(beam)-1 : beam-1; beam_length = holes*AB_HOLE_SPACING; rot = (beam[0] == "|" && beam[len(beam)-1] != "O" || beam[0] != "O" && beam[len(beam)-1] == "|" ? 90 : 0); union() { rotate([ rot, 0, 0 ]) translate( [beam_length/2,0,0] ) { cube( [ beam_length, AB_BEAM_WIDTH, beam_height ], center=true ); translate( [-beam_length/2, 0, 0] ) cylinder( r = AB_BEAM_WIDTH/2, beam_height, center=true, $fn=100 ); translate( [beam_length/2, 0, 0] ) cylinder( r = AB_BEAM_WIDTH/2, beam_height, center=true, $fn=100 ); } if( $children ) child(0); } } module ab_beam_holes( beam = "OOOO", beam_height = AB_BEAM_HEIGHT ) { holes = len(beam)-1; beam_length = holes*AB_HOLE_SPACING; layout = beam; for (hole = [0:1:holes]) { translate( [hole*AB_HOLE_SPACING,0,0] ) { if( layout == "" ) { ab_hole_pin( beam_height ); } else { if( layout[hole] == "O" ) { ab_hole_pin( beam_height ); } if( layout[hole] == "|" ) { rotate([-90, 0, 0]) ab_hole_pin( beam_height ); } if( layout[hole] == "(" ) { ab_hole_left_slot( beam_height ); } if( layout[hole] == ")" ) { ab_hole_right_slot( beam_height ); } if( layout[hole] == "-" ) { ab_hole_slot( beam_height ); } if( layout[hole] == "X" ) { ab_hole_axle( beam_height, first = (hole==0), last = (hole==holes) ); } if( layout[hole] == "#" ) { rotate([-90, 0, 0]) ab_hole_axle( beam_height, first = (hole==0), last = (hole==holes) ); } // Any other letter is a space. } } } if( $children ) child(0); } module ab_hole_pin( beam_height = AB_BEAM_HEIGHT ) { cylinder(beam_height+2, AB_HOLE_INSIDE_DIAMETER/2, AB_HOLE_INSIDE_DIAMETER/2, center = true, $fn=100); translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5]) cylinder(AB_HOLE_RING_DEPTH+1, AB_HOLE_RING_DIAMETER/2, AB_HOLE_RING_DIAMETER/2, center = true, $fn=100); translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)]) cylinder(AB_HOLE_RING_DEPTH+1, AB_HOLE_RING_DIAMETER/2, AB_HOLE_RING_DIAMETER/2, center = true, $fn=100); } module ab_hole_left_slot( beam_height = AB_BEAM_HEIGHT ) { ab_hole_pin(beam_height); translate([AB_HOLE_SPACING/4, 0, 0]) { cube([AB_HOLE_SPACING/2+.05,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true); translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5]) cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true); translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)]) cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true); } } module ab_hole_right_slot( beam_height = AB_BEAM_HEIGHT ) { ab_hole_pin(beam_height); translate([-AB_HOLE_SPACING/4, 0, 0]) { cube([AB_HOLE_SPACING/2+.05,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true); translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5]) cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true); translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)]) cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true); } } module ab_hole_slot( beam_height = AB_BEAM_HEIGHT ) { cube([AB_HOLE_SPACING,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true); translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5]) cube([AB_HOLE_SPACING, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true); translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)]) cube([AB_HOLE_SPACING, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true); } module ab_hole_axle( beam_height = AB_BEAM_HEIGHT , first = false, last = false) { if( first == true ) { cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true); translate([+.5,0,0]) cube([AB_AXLE_LENGTH+1,AB_AXLE_GAP,beam_height+2], center = true); } if( last == true ) { cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true); translate([-.5,0,0]) cube([AB_AXLE_LENGTH+1,AB_AXLE_GAP,beam_height+2], center = true); } if( first == false && last == false ) { cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true); cube([AB_AXLE_LENGTH,AB_AXLE_GAP,beam_height+2], center = true); } }