include include include include frame_size = 20; frame_expansion = 0.2; // expansion on each side wall_thickness = 2; corner_size = 40; // length of mating surface between corner and frame // The length along each edge that the corner bracket takes. I.e., if // you construct a frame of four corner brackets and 4 tubes of length // $L-$corner_size, the distance between opposite tubes' centerlines // will be $L. corner_offset = frame_size / 2 + wall_thickness; rail_diam = 8; ysled_extralen = frame_size; // on each end // Both of these are distance from frame centerline belt_height1 = frame_size / 2 + wall_thickness + belt_width / 2 + 2; belt_height2 = belt_height1 + belt_width + 2; // calculated ysled_rail_spacing = (sled_ysize); motor_shaft_xoffset = 15; motor_mount_length_adjustment = 5; motor_mount_length = nema17_face + wall_thickness + motor_mount_length_adjustment; // distance between centerline of rail and centerline of frame Y tube. yrail_offset = motor_shaft_xoffset + pulley_sbend_offset; // Generates bar of length $l, centered on origin extending in +Z module tslot(l) { bom_item(printable = false, label = str("tslot(", l, "mm)")); colorize(stock_color) { translate([ -frame_size / 2, -frame_size / 2, 0 ]) cube([ frame_size, frame_size, l ]); } } // A corner, with tubes extending in +x and +y. module corner_base(extension = wall_thickness) { odim = frame_size / 2 + wall_thickness; ldim = frame_size / 2 + corner_size + (extension - wall_thickness); actual_corner_offset = frame_size / 2 + extension; cap_points = [ [ -odim, -odim ], [ -odim, ldim ], [ odim, ldim ], [odim, odim], [ ldim, odim ], [ ldim, -odim ] ]; difference() { translate([ 0, 0, -odim ]) linear_extrude(odim * 2) polygon(points = cap_points); // two bars... translate([ -frame_size / 2 - frame_expansion, actual_corner_offset, -frame_size / 2 - frame_expansion ]) cube([ frame_size + frame_expansion*2, ldim, frame_size + frame_expansion*2 ]); translate([ actual_corner_offset, -frame_size / 2 - frame_expansion, -frame_size / 2 - frame_expansion ]) cube([ ldim, frame_size + frame_expansion * 2, frame_size + frame_expansion*2 ]); // Screw holes for (pos = [10, 30], mirror_normal = [[0,1,0], [1,-1,0]]) { mirror(mirror_normal) translate([pos + actual_corner_offset, 0, -odim]) union() { cylinder(d = 8, h=2, center=true); cylinder(d = 5 * screw_hole_expansion, h = odim); } } // Adjustable feet cylinder(d=m6_insert_d, h=odim * 2 + 1, center=true); } } rail_holder_width = (yrail_offset - frame_size / 2 - wall_thickness) * 2; module rail_holder(in_x) { odim = frame_size / 2 + wall_thickness; box_size = (yrail_offset - odim) * 2; assert(box_size == rail_holder_width); ldim = frame_size / 2 + box_size; tube_offset = (corner_size) / 2 + wall_thickness; tube_rotation = in_x ? 90 : 0; translated_rail_offset = yrail_offset - frame_size / 2 - wall_thickness; translate([ odim, odim, -odim ]) { difference() { cube([ !in_x ? box_size - wall_thickness : 10, !in_x ? 10 : box_size - wall_thickness, wall_thickness * 2 + frame_size ]); translate( [ translated_rail_offset, translated_rail_offset, frame_size / 2 + wall_thickness ]) rotate([ tube_rotation - 90, tube_rotation, 0 ]) translate([ 0, 0, -corner_size ]) cylinder(d = rail_diam, corner_size * 4); } } } // centered on the rail. module ysled_slider(associated_parts = $preview, is_left=true) { spread = sled_ysize; bom_item(label = str("ysled_slider(", spread, ")")); sled_len = spread + frame_size; sled_height = frame_size; idler_spacing = spread / 6 + pulley_radius(idler_nteeth); local_idler_xoffset = pulley_sbend_offset - yrail_offset + motor_shaft_xoffset; echo("LIX:", local_idler_xoffset) colorize("green") translate([ 0, -sled_len / 2, 0 ]) rotate([ -90, 0, 0 ]) { difference() { union() { translate([ -frame_size / 2, -frame_size / 2, 0 ]) cube([ frame_size + 5, frame_size, sled_len ]); translate([ pulley_sbend_offset - yrail_offset + motor_shaft_xoffset - pulley_clearance_rad - 4, -frame_size / 2, 0 ]) cube([ frame_size + 5, frame_size, sled_len ]); } for (y = [idler_spacing, -idler_spacing]) { rotate([90, 0, 0]) translate([local_idler_xoffset, sled_len/2 + y, 0]) cylinder(d=3, h = frame_size); } cylinder(d = rail_diam * 1.5, h = sled_len); translate([ 0, 0, -1 ]) cylinder(d = bushing_od, h = bushing_len + 1); translate([ 0, 0, sled_len - bushing_len ]) cylinder(d = bushing_od, h = bushing_len + 1); for (zpos = [ frame_size / 2, sled_len - frame_size / 2 ]) { translate([ sled_height / 2, 0, zpos ]) rotate([ 0, 90, 0 ]) { cylinder(h = sled_height + 1, d = rail_diam); } } } } // TODO: add posts for the idlers // color("#f00") translate( [ local_idler_xoffset, 0, frame_size/2 - 1 ]) { translate([ 0, idler_spacing, 0 ]) { idler_post(belt_height = belt_height1 - frame_size/2 + 1, toothed = is_left); } translate([ 0, -idler_spacing, 0 ]) { rotate([ 0, 0, -90 ]) { idler_post(belt_height = belt_height2 - frame_size/2 + 1, toothed = !is_left); } } } if ($preview) { translate([ 0, -sled_len / 2, 0 ]) rotate([ -90, 0, 0 ]) bushing(); translate([ 0, sled_len / 2, 0 ]) rotate([ 90, 0, 0 ]) bushing(); } } module nema17_housing() { hwidth = corner_size + frame_size + wall_thickness; hheight = nema17_face + wall_thickness * 2; hdepth = frame_size + wall_thickness * 2; vertical_extension = frame_size + belt_height2; screw_dxy = 31 / 2; slot_vector = [0, - motor_mount_length_adjustment, 0]; translate([ 0, -nema17_face / 2 - frame_size / 2 - wall_thickness, 0 ]) { slotify(slot_vector) { translate([ 0, 0, -belt_height2/2 - wall_thickness ]) cube([ nema17_face + 2, nema17_face + 2, hdepth + belt_height2 ], center = true); cylinder(d = 23, frame_size); } for (x = [-1, 1], y = [-1,1]) { slotify(slot_vector) translate([ x * screw_dxy, y * screw_dxy, frame_size / 2 + wall_thickness + 0.5 ]) rotate([ 180, 0, 0 ]) { cylinder(d = 5 * screw_hole_expansion, h = wall_thickness + 1); } } } } // belt height is the center of the belt. // Roration is in Z axis, from +x/+y module idler_post(belt_height, toothed = true) { gap = 0.5; post_radius = pulley_clearance_rad + 4; top_shelf_thickness = 4; total_height = idler_zmargin.y + belt_height + top_shelf_thickness + gap; slot_radius = pulley_clearance_rad; slot_height = idler_zmargin.x + idler_zmargin.y + gap * 2; difference() { union() { // outer shell cylinder(h = total_height, r = post_radius); translate([ 0, -post_radius, 0 ]) cube([ post_radius, post_radius, total_height ]); translate([ -post_radius, 0, 0 ]) cube([ post_radius, post_radius, total_height ]); } translate([ 0, 0, belt_height - idler_zmargin.x - gap ]) { cylinder(r = slot_radius, slot_height); translate([ -slot_radius, 0, 0 ]) cube([ post_radius * 2, post_radius * 2, slot_height ]); translate([ 0, -slot_radius, 0 ]) cube([ post_radius * 2, post_radius * 2, slot_height ]); } cylinder(d = 3, h = total_height + 1); translate([ 0, 0, total_height - 2 ]) cylinder(r = 3, h = 3); } if($preview) { idler(height = belt_height, toothed=toothed); } } module flcorner() { bom_item(); motor_height = belt_height2 - belt_height1; union() { rotate([ 0, 0, 0 ]) { corner_base(); rail_holder(false); } difference() { translate([ -frame_size/2 - wall_thickness, -frame_size/2 - wall_thickness - motor_mount_length, -frame_size/2 - wall_thickness ]) cube([ frame_size + wall_thickness + corner_size, motor_mount_length + wall_thickness, frame_size + wall_thickness * 2 + motor_height ]); translate([ motor_shaft_xoffset, 0, motor_height ]) nema17_housing(); } // translate([motor_shaft_xoffset, 0, 0 ]) nema17_housing(); } if ($preview) translate([ motor_shaft_xoffset, -nema17_face / 2 - frame_size / 2 - wall_thickness, frame_size / 2 ]) { translate([0,0,motor_height]) nema17(); translate([ 0, 0, -frame_size / 2 + belt_height2 ]) rotate([180,0,0]) { active_pulley(); } } } module frcorner() { bom_item(); union() { rotate([ 0, 0, 90 ]) { corner_base(); rail_holder(true); } difference() { translate([ -frame_size/2 - corner_size, -frame_size/2 - wall_thickness - motor_mount_length, -frame_size/2 - wall_thickness ]) cube([ frame_size + wall_thickness + corner_size, motor_mount_length, frame_size + wall_thickness * 2 ]); translate([ -motor_shaft_xoffset, 0, 0 ]) nema17_housing(); } } if ($preview) translate([ -motor_shaft_xoffset, -nema17_face / 2 - frame_size / 2 - wall_thickness, frame_size / 2 ]) { nema17(); translate([ 0, 0, belt_height1 - frame_size / 2 ]) { rotate([ 180, 0, 0 ]) active_pulley(); } } } module blcorner() { bom_item(); difference() { rotate([0, 0, 270]) { corner_base(extension = rail_holder_width); rail_holder(true); } for (pos = [ [motor_shaft_xoffset + pulley_sbend_offset, 0, 0], [0, motor_shaft_xoffset + pulley_sbend_offset, 0], ]) { translate(pos) cylinder(d = 3, h = belt_height2, $fn=screw_num_sides); } } translate([motor_shaft_xoffset + pulley_sbend_offset, 0, frame_size/2]) rotate([0,0,-90]) idler_post(belt_height = belt_height1 - frame_size/2, toothed=true); translate([0, -(motor_shaft_xoffset + pulley_sbend_offset), frame_size/2]) rotate([0,0,-90]) idler_post(belt_height = belt_height2 - frame_size/2, toothed=true); } module brcorner() { bom_item(); union() rotate([ 0, 0, 180 ]) { corner_base(extension = rail_holder_width); rail_holder(false); } translate([-(motor_shaft_xoffset + pulley_sbend_offset), 0, frame_size/2]) rotate([0,0,180]) idler_post(belt_height = belt_height2 - frame_size/2, toothed=true); translate([0, -(motor_shaft_xoffset + pulley_sbend_offset), frame_size/2]) rotate([0,0,180]) idler_post(belt_height = belt_height1 - frame_size/2, toothed=true); } module xsled_slider() { slider_len = bushing_len + 10; screw_tab_len = 20; screw_tab_thickness = 10; union() // translate([screw_tab_len, 0, 0]) difference() { union() { rotate([ 0, 90, 0 ]) { cylinder(d = frame_size, h = slider_len); } translate([ 0, -frame_size / 2, 0 ]) cube([ slider_len, frame_size, frame_size / 2 ]); *translate([ -screw_tab_len, -frame_size / 2, frame_size / 2 ]) cube( [ screw_tab_len * 2 + slider_len, frame_size, screw_tab_thickness ]); } rotate([ 0, 90, 0 ]) { cylinder(d = bushing_od, h = bushing_len); cylinder(d = rail_diam * 1.1, slider_len * 2); } } if ($preview) rotate([ 0, 90, 0 ]) bushing(); } module sled_cornera() { bom_item(); corner_base(); translate([ -frame_size / 2 - wall_thickness, 0, -frame_size ]) xsled_slider(); } module sled_cornerb() { bom_item(); corner_base(); rotate([ 0, 0, 90 ]) translate([ -frame_size / 2 - wall_thickness, 0, -frame_size ]) xsled_slider(); } module xsled_frame() { translate([ -sled_xsize / 2 + corner_offset, -ysled_rail_spacing / 2, 0 ]) rotate([ 0, 90, 0 ]) tslot(sled_xsize - corner_offset * 2); translate([ -sled_xsize / 2 + corner_offset, ysled_rail_spacing / 2, 0 ]) rotate([ 0, 90, 0 ]) tslot(sled_xsize - corner_offset * 2); translate([ -sled_xsize / 2, -ysled_rail_spacing / 2 + corner_offset, 0 ]) rotate([ -90, 0, 0 ]) tslot(sled_ysize - corner_offset * 2); translate([ sled_xsize / 2, -ysled_rail_spacing / 2 + corner_offset, 0 ]) rotate([ -90, 0, 0 ]) tslot(sled_ysize - corner_offset * 2); translate([ -sled_xsize / 2, -sled_ysize / 2, 0 ]) sled_cornera(); translate([ sled_xsize / 2, sled_ysize / 2, 0 ]) rotate([ 0, 0, 180 ]) sled_cornera(); translate([ sled_xsize / 2, -sled_ysize / 2, 0 ]) rotate([ 0, 0, 90 ]) sled_cornerb(); translate([ -sled_xsize / 2, sled_ysize / 2, 0 ]) rotate([ 0, 0, 270 ]) sled_cornerb(); // simulate a piece of film if (false) { color("#0008") cube([ 5 * inch, 4 * inch, 1 ], center = true); } } gt2_clip_meshing_dist = belt_pitch * 6; gt2_clip_peg_diam = 8; // min 6 gt2_clip_ease_in_diam = 6; gt2_clip_narrowing_dist = 12; // distance from center of loop peg to meshing point gt2_clip_gap_diam = gt2_clip_peg_diam + belt_thickness * 2 + 1; gt2_clip_thickness = (gt2_clip_peg_diam + gt2_clip_gap_diam)/2; gt2_clip_length = gt2_clip_narrowing_dist + gt2_clip_meshing_dist + gt2_clip_peg_diam / 2 + gt2_clip_gap_diam - belt_thickness; module gt2_clip_cutout(teeth_inside) { belt_expansion = 0.5; dual_width = belt_thickness * 2 - tooth_height + belt_expansion; loop_peg_diam = gt2_clip_peg_diam; // min 6mm gap_diam = gt2_clip_gap_diam; narrowing_ease_diam = 6; narrowing_dist = gt2_clip_narrowing_dist; meshing_dist = gt2_clip_meshing_dist; ease_out_rad = gap_diam - belt_thickness ; out_off = teeth_inside ? 0 : dual_width - belt_thickness - belt_expansion; translate([ -(narrowing_dist + meshing_dist + (ease_out_rad - out_off - belt_thickness)) -(teeth_inside ? tooth_height - belt_pld : belt_backing) , loop_peg_diam / 2, -1]) union() { difference() { hull() { circle(d = gap_diam); polygon([ [0, 0], [0, gap_diam / 2], [narrowing_dist, gap_diam / 2], [narrowing_dist, gap_diam / 2 - dual_width] ]); } circle(d = loop_peg_diam); translate([narrowing_dist, gap_diam / 2 - dual_width - narrowing_ease_diam / 2]) circle(d = narrowing_ease_diam); } translate([narrowing_dist, gap_diam / 2]) polygon([ [0, 0], [meshing_dist - 1, 0], [meshing_dist, - out_off], [meshing_dist, - belt_thickness - out_off - belt_expansion], [meshing_dist - 1, - dual_width], [0, - dual_width] ]); translate([narrowing_dist + meshing_dist, gap_diam / 2 - ease_out_rad]) { intersection() { translate([0, -2]) square(ease_out_rad + 2); difference() { circle(ease_out_rad - out_off); circle(ease_out_rad - out_off - belt_thickness - belt_expansion); } } } } } module gt2_clip(teeth_inside) { out_off = teeth_inside ? 0 : belt_thickness - tooth_height; actual_thickness = gt2_clip_thickness + wall_thickness; translate([0,-actual_thickness, -belt_width/2 - 2]) difference() { translate([-gt2_clip_length - belt_thickness + out_off/2, 0]) { cube([gt2_clip_length + belt_thickness * 2, actual_thickness, belt_width + 4]); mirror([0,0,1]) translate([0, actual_thickness]) linear_extrude(height=actual_thickness * 1.5, scale=[1,0]) translate([0, -actual_thickness]) square([ gt2_clip_length + belt_thickness * 2, actual_thickness ]); } translate([0,0,0]) linear_extrude(belt_width + 6) gt2_clip_cutout(teeth_inside); } } module xsled2() { bom_item(); tab_len = bushing_len * 2; tab_thickness = bushing_od + wall_thickness * 2; glass_thickness = 5; // TODO: Update when an actual size is available inner_ysize = sled_ysize - tab_thickness; film_height = belt_height2 + belt_width / 2; ledge_width = 15; inside_ledge_width = 8; outside_ledge_width = ledge_width - inside_ledge_width; film_thickness = 0.25; finger_notch_diam = 25; finger_notch_smdepth = 2; glass_holder_points = [ [0, - tab_thickness / 2], [0, film_height + glass_thickness], [wall_thickness, film_height + glass_thickness], [wall_thickness, film_height], [outside_ledge_width, film_height], [outside_ledge_width, film_height - glass_thickness], [ledge_width, film_height - glass_thickness], [wall_thickness * 2, - tab_thickness / 2] ]; echo("Ledge width: ", ledge_width - outside_ledge_width); // rail attachment points render() { for (xsign = [1, - 1], ysign = [1, - 1]) { translate([sled_xsize / 2 * xsign, sled_ysize / 2 * ysign, 0]) rotate([0, - 90 * xsign, 0]) { difference() { union() { cylinder(d = tab_thickness, h = tab_len); translate( [- tab_thickness / 2, ysign > 0 ? - tab_thickness / 2 : 0, 0]) cube([tab_thickness, tab_thickness / 2 + 1, tab_len]); } translate([0, 0, - 0.5]) { cylinder(d = bushing_od, h = bushing_len + 0.5); cylinder(d = rail_diam * 1.1, h = tab_len + 1); } } } } // glass holding frame difference() { union() { translate([- sled_xsize / 2, - inner_ysize / 2, 0]) rotate([0, 90, 0]) rotate([0, 0, 90]) linear_extrude(sled_xsize) polygon(glass_holder_points); translate([sled_xsize / 2, inner_ysize / 2, 0]) rotate([0, 90, 180]) rotate([0, 0, 90]) linear_extrude(sled_xsize) polygon(glass_holder_points); translate([sled_xsize / 2, - inner_ysize / 2, 0]) rotate([0, 90, 90]) rotate([0, 0, 90]) linear_extrude(inner_ysize) polygon(glass_holder_points); translate([- sled_xsize / 2, inner_ysize / 2, 0]) rotate([0, 90, - 90]) rotate([0, 0, 90]) linear_extrude(inner_ysize) polygon(glass_holder_points); } // grub screw points for glass levelling for (x = [- 1, 1], y = [- 1, 1]) { translate([x * (sled_xsize / 2 - outside_ledge_width - inside_ledge_width / 2), y * (inner_ysize / 2 - outside_ledge_width - inside_ledge_width / 2), film_height]) rotate([180, 0, 0]) { cylinder(d = 4, h = 50); cylinder(d = 5, h = 4 + glass_thickness); } } // finger notch translate([ - 10, - inner_ysize / 2, film_height - glass_thickness + 0.5 - finger_notch_smdepth + finger_notch_diam / 2 ]) rotate([90, 0, 0]) cylinder(d = finger_notch_diam, h = ledge_width * 3, center = true); } // belt attachment points idler_spacing = sled_ysize / 6; for (params = [ [true, [- sled_xsize / 2, idler_spacing, belt_height1]], [false, [- sled_xsize / 2, - idler_spacing, belt_height2]], [true, [sled_xsize / 2, idler_spacing, belt_height2]], [false, [sled_xsize / 2, - idler_spacing, belt_height1]] ]) { should_mirror = params[1][0] > 0 ? params[0] : !params[0]; translate(params[1]) rotate([0, 0, params[1][0] > 0 ? 90 : - 90]) { if (should_mirror) { mirror([1, 0, 0]) gt2_clip(params[0]); } else { gt2_clip(params[0]); } } } } if ($preview) { for (xsign = [1, - 1], ysign = [1, - 1]) { translate([sled_xsize / 2 * xsign, sled_ysize / 2 * ysign, 0]) rotate([0, - 90 * xsign, 0]) { bushing(); } } } color("#fff3") if ($preview) { // draw glass sheets bom_item(label = str("glass (", glass_thickness, ", ", sled_xsize - outside_ledge_width * 2, ", ", inner_ysize - outside_ledge_width * 2, ")"), printable=false); bom_item(label = str("glass (", glass_thickness, ", ", sled_xsize - wall_thickness * 2, ", ", inner_ysize - wall_thickness * 2, ")"), printable=false); translate( [0, 0, film_height - glass_thickness / 2 + 0.5]) cube( [ sled_xsize - outside_ledge_width * 2, inner_ysize - outside_ledge_width * 2, glass_thickness ], center = true); *translate( [0, 0, film_height + film_thickness * 2 + glass_thickness / 2 + 0.5]) cube( [ sled_xsize - wall_thickness * 2, inner_ysize - wall_thickness * 2, glass_thickness ], center = true); } if ($preview) { color("#0003") translate([0, 0, film_height + 0.5]) { cube([5 * inch, 4 * inch, film_thickness], center = true); } } } // render() // xsled2();