x-ends: tweak height and bearing positions

include <MCAD/motors.scad>
include <MCAD/stepper.scad>

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/screws.scad>
use <thing_libutils/timing-belts.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_pulley_offset = 41*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+zaxis_bearing[1]/2+1*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+xaxis_rod_d+5*mm;

xaxis_endstop_size_switch = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset_switch = [-2.45*mm, 0*mm, 0*mm];

xaxis_endstop_size_SN04 = [34.15*mm, 18.15*mm, 17.8*mm];
xaxis_endstop_screw_offset_SN04 = [-27.5*mm, 0*mm, 0*mm];
xaxis_endstop_offset_SN04 = [-3*mm, 0*mm, 0*mm];

function xaxis_end_width(with_motor) = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : zaxis_bearing[1]/2+zaxis_nut[1];

module xaxis_end_body(part, with_motor, beltpath_index=0, nut_top=false, with_xrod_adjustment=false)
{
    nut_h = zaxis_nut[4];
    bearing_sizey = zaxis_bearing[1] + 5*mm;

    xaxis_end_xrod_offset_z = xaxis_rod_l/2 - (main_width/2 + zmotor_mount_rod_offset_x);
    xaxis_rod_d_support = xaxis_rod_d+5*mm;
    xaxis_rod_l_support = xaxis_end_xrod_offset_z + 8*mm + (with_xrod_adjustment?8*mm:0);

    if(part==undef)
    {
        difference()
        {
            xaxis_end_body(part="pos", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
            xaxis_end_body(part="neg", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
        }
        %xaxis_end_body(part="vit", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
    }
    else if(part=="pos")
    {
        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);
            for(x=[-1,1])
            for(z=[-1,1])
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                translate([x*screw_dist/2, 0, z*screw_dist/2])
                cylindera(d=lookup(ThreadSize,xaxis_motor_thread)+4*mm, h=motor_mount_wall_thick, orient=[0,1,0], align=[0,-1,0], rounding_radius=2);
            }
        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            // main nut support
            cylindera(h=zaxis_nut[4], d=zaxis_nut[0]+5*mm, align=[0,0,1], round_radius=2);

            // nut screw holes support
            for(x=[-1,1])
            translate([x*zaxis_nut[5], 0, 0])
            cylindera(h=zaxis_nut[4], d=lookup(ThreadSize, zaxis_nut[6])+5*mm, align=[0,0,1], round_radius=2);

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1], round_radius=2);*/
        }

        // x axis rod holders
        for(z=[-1,1])
        translate([0,0,z*(xaxis_rod_distance/2)])
        cylindera(h=xaxis_rod_l_support, d=xaxis_rod_d_support, orient=[1,0,0], align=[-1,0,0], round_radius=2);

        /*if(xaxis_endstop_type == "SWITCH")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            {
                rcubea(xaxis_endstop_size_switch, align=[-1,0,-1]);
            }
        }
        /*else if(xaxis_endstop_type == "SN04")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            {
                translate(xaxis_endstop_offset_SN04)
                rcubea(xaxis_endstop_size_SN04, align=[-1,0,-1]);
            }
        }

        // support around z axis bearings
        translate([0, -xaxis_zaxis_distance_y, 0])
        cylindera(h=xaxis_end_wz,d=bearing_sizey, orient=[0,0,1], align=[0,0,0], round_radius=2);

        // belt idler screw cut support
        for(z=[-1,1])
        for(y=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0,y*-xaxis_beltpath_width/2,0])
            cylindera(orient=YAXIS, d=15*mm, h=7*mm, align=-y*YAXIS);
        }
    }
    else if(part=="neg")
    {
        // cut support around z axis bearings
        translate([0, -xaxis_zaxis_distance_y, 0])
        translate([0,0,.1])
        cubea([bearing_sizey+.1, bearing_sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[0,-1,0]);

        // x smooth rods
        for(z=[-1,1])
        translate([0,0*mm,z*(xaxis_rod_distance/2)])
        {
            xoff = - xaxis_end_xrod_offset_z -(with_xrod_adjustment?6:0)*mm;
            translate([xoff,0,0])
            cylindera(h=abs(xoff)+xaxis_end_width(with_motor)+1,d=xaxis_rod_d+.5*mm, orient=[1,0,0], align=[1,0,0]);

            if(with_xrod_adjustment)
            {
                translate([-xaxis_rod_l_support+5*mm,0,0])
                nut_trap_cut(nut=NutHexM4, trap_axis=YAXIS, orient=-XAXIS, align=XAXIS);

                translate([-xaxis_rod_l_support-7*mm,0,0])
                cylindera(d=10, h=10, orient=XAXIS);
            }
        }
    }
    else if(part=="vit")
    {
    }
}

module xaxis_end(part, with_motor=false, stop_x_rods=true, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false, with_xrod_adjustment=false)
{
    nut_h = zaxis_nut[4];
    extrasize = with_motor?0*mm:0*mm;
    extrasize_align = 1;

    if(part==undef)
    {
        difference()
        {
            xaxis_end(part="pos", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
            xaxis_end(part="neg", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
        }
        %xaxis_end(part="vit", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
    }
    else if(part=="pos")
    {
        hull()
        {
            xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
        }
    }
    else if(part=="neg")
    {
        xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

        // belt idler screw cut
        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0, -xaxis_beltpath_width/2 - 7*mm, 0])
            {
                screw_cut(nut=NutHexM5, h=xaxis_beltpath_width+13*mm, with_nut=true, orient=[0,1,0], align=[0,1,0]);
            }
        }

        //endstop mount screw cuts
        /*if(xaxis_endstop_type == "SWITCH")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            translate(xaxis_endstop_screw_offset_switch)
            for(y=[-1,1])
            translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size_switch[2]])
            {
                screw_cut(nut=NutHexM2_5, h=10*mm, embed_head=false, with_head=true, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
        /*else if(xaxis_endstop_type == "SN04")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            translate(xaxis_endstop_screw_offset_SN04)
            for(y=[-1,1])
            translate([-0*mm,y*10.5*mm/2,xaxis_endstop_size_SN04[2]])
            {
                translate(xaxis_endstop_offset_SN04)
                screw_cut(nut=NutHexM3, h=20*mm, embed_head=false, with_head=true, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);
            }
        }

        xaxis_end_beltpath(height=xaxis_beltpath_height_body, width=xaxis_beltpath_width);

        // z smooth bearing mounts
        for(z=[-1,1])
        {
            translate([0,0,z*(xaxis_end_wz/2-2*mm)])
            translate([0, -xaxis_zaxis_distance_y, 0])
            {
                bearing_mount_holes(
                        bearing_type=zaxis_bearing,
                        ziptie_type=ziptie_type,
                        ziptie_bearing_distance=ziptie_bearing_distance,
                        orient=ZAXIS,
                        align=[0,0,-z],
                        with_zips=true
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

                    /*translate([-5*cm,0,0])*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/
                /*}*/
            }
        }

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])
                teardrop(d=round_d,h=motor_mount_wall_thick, tear_orient=[0,0,1], orient=[0,1,0], align=[0,-1,0], roll=90, truncate=0.9);

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                cylindera(d=bearing_MR105[1], h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                for(x=[-1,1])
                for(z=[-1,1])
                translate([0,-xaxis_end_motor_offset[1],0])
                translate([x*screw_dist/2, -(xaxis_beltpath_width/2+3*mm), z*screw_dist/2])
                {
                    if(!(x==1 && z == (beltpath_index==0?1:-1)))
                    screw_cut(xaxis_motor_nut, h=25, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=lookup(NemaFrontAxleLength,zaxis_motor), d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                    translate([i*zaxis_nut[5], 0, -zaxis_nut[3]])
                    screw_cut(thread=zaxis_nut[6], h=20*mm, with_nut=false, orient=ZAXIS, align=ZAXIS);
                }
            }
        }
    }
    else if(part=="vit")
    {
        xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

        if(with_motor)
        {
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                // 1mm due to motor offset
                translate([0,-1*mm,0])
                {
                    // 1mm between pulley and motor
                    translate([0,-1*mm,0])
                    pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);

                    if(show_motor)
                    {
                        motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
                    }
                }
            }
        }

        //endstop
        if($show_vit)
        {
            /*if(xaxis_endstop_type == "SWITCH")*/
            {
                translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
                {
                    difference()
                    {
                        rcubea(xaxis_endstop_size_switch, align=[-1,0,1]);

                        translate(xaxis_endstop_screw_offset_switch)
                        for(y=[-1,1])
                        translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size_switch[2]])
                        screw(nut=NutHexM2_5, h=6*mm, orient=[0,0,-1], align=[0,0,-1]);
                    }
                }
            }
            /*else if(xaxis_endstop_type == "SN04")*/
            {
                translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
                {
                    translate(xaxis_endstop_offset_SN04)
                    translate([-36,-9,0])
                    rotate(ZAXIS*-90)
                    import("stl/SN04-N_Inductive_Proximity_Sensor_3528_0.stl");
                }
            }
        }

        // belt idler pulley screw
        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0, -xaxis_beltpath_width/2 - 7*mm, 0])
            {
                screw(nut=NutHexM5, h=25*mm, with_nut=true, orient=[0,1,0], align=[0,1,0]);
            }
        }

        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            pulley(xaxis_idler_pulley, orient=[0,1,0]);
        }

        if(show_nut)
        {
            mirror([0,0,nut_top?1:0])
            translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
            xaxis_end_znut();
        }

        if(show_rods)
        {
            for(z=[-1,1])
                translate([0,0,z*xaxis_rod_distance/2])
                translate([0, -xaxis_zaxis_distance_y, 0])
                cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
        }

        if(show_bearings)
        {
            for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            bearing(zaxis_bearing);
        }
    }
}

module xaxis_end_beltpath(height, width, length = 1000, align=[0,0,0], orient=[1,0,0])
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=orient, align=align, roll=-180*min(0,z), truncate=1);
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }

        translate([0,0,-.1])
        cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!$preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(x=[-1,1])
            {
                z=xaxis_beltpath_z_offsets[x<0?0:x];
                xo = x>0?xaxis_end_pulley_offset:xaxis_end_motor_offset[0];
                xw = x<0?xaxis_end_pulley_offset:xaxis_end_motor_offset[0];
                translate([-main_width/2-xo/2, xaxis_zaxis_distance_y, z])
                rotate([90,0,0])
                color("black")
                belt_path(main_width+xw, 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);
            }
        }

        /*translate([axis_pos_x,0,0])*/
        /*{*/
            // x carriage
            /*attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])*/
            /*{*/
                /*x_carriage_full();*/
            /*}*/
        /*}*/

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
        translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
        cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        translate([x*(zmotor_mount_rod_offset_x),0,0])
        cylindera(h=zaxis_rod_l,d=zaxis_rod_d, orient=ZAXIS, align=[0,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            {
                translate([0, xaxis_zaxis_distance_y, 0])
                translate([x*zmotor_mount_rod_offset_x, 0, 0])
                mirror([max(0,x),0,0])
                {
                    xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);
                }
            }
        }
    }

}

if(false)
{
    for(x=[-1,1])
    translate([x*55,x*55,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    {
        xaxis_end(with_motor=true, beltpath_index=max(0,x), show_motor=false, show_nut=false, show_bearings=false, with_xrod_adjustment=true);
    }
}

module part_x_end_right()
{
    x=1;
    translate([0,0,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    xaxis_end(with_motor=true, beltpath_index=max(0,x), with_xrod_adjustment=true);
}

module part_x_end_left()
{
    x=-1;
    translate([0,0,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    xaxis_end(with_motor=true, beltpath_index=max(0,x), with_xrod_adjustment=true);
}

include <MCAD/motors.scad>
include <MCAD/stepper.scad>

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/screws.scad>
use <thing_libutils/timing-belts.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_pulley_offset = 41*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+zaxis_bearing[1]/2+1*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+zaxis_bearing[2]+2*mm;

xaxis_endstop_size_switch = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset_switch = [-2.45*mm, 0*mm, 0*mm];

xaxis_endstop_size_SN04 = [34.15*mm, 18.15*mm, 17.8*mm];
xaxis_endstop_screw_offset_SN04 = [-27.5*mm, 0*mm, 0*mm];
xaxis_endstop_offset_SN04 = [-3*mm, 0*mm, 0*mm];

function xaxis_end_width(with_motor) = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : zaxis_bearing[1]/2+zaxis_nut[1];

module xaxis_end_body(part, with_motor, beltpath_index=0, nut_top=false, with_xrod_adjustment=false)
{
    nut_h = zaxis_nut[4];
    bearing_sizey = zaxis_bearing[1] + 5*mm;

    xaxis_end_xrod_offset_z = xaxis_rod_l/2 - (main_width/2 + zmotor_mount_rod_offset_x);
    xaxis_rod_d_support = xaxis_rod_d+5*mm;
    xaxis_rod_l_support = xaxis_end_xrod_offset_z + 8*mm + (with_xrod_adjustment?8*mm:0);

    if(part==undef)
    {
        difference()
        {
            xaxis_end_body(part="pos", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
            xaxis_end_body(part="neg", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
        }
        %xaxis_end_body(part="vit", with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
    }
    else if(part=="pos")
    {
        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);
            for(x=[-1,1])
            for(z=[-1,1])
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                translate([x*screw_dist/2, 0, z*screw_dist/2])
                cylindera(d=lookup(ThreadSize,xaxis_motor_thread)+4*mm, h=motor_mount_wall_thick, orient=[0,1,0], align=[0,-1,0], rounding_radius=2);
            }
        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            // main nut support
            cylindera(h=zaxis_nut[4], d=zaxis_nut[0]+5*mm, align=[0,0,1], round_radius=2);

            // nut screw holes support
            for(x=[-1,1])
            translate([x*zaxis_nut[5], 0, 0])
            cylindera(h=zaxis_nut[4], d=lookup(ThreadSize, zaxis_nut[6])+5*mm, align=[0,0,1], round_radius=2);

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1], round_radius=2);*/
        }

        // x axis rod holders
        for(z=[-1,1])
        translate([0,0,z*(xaxis_rod_distance/2)])
        cylindera(h=xaxis_rod_l_support, d=xaxis_rod_d_support, orient=[1,0,0], align=[-1,0,0], round_radius=2);

        /*if(xaxis_endstop_type == "SWITCH")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            {
                rcubea(xaxis_endstop_size_switch, align=[-1,0,-1]);
            }
        }
        /*else if(xaxis_endstop_type == "SN04")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            {
                translate(xaxis_endstop_offset_SN04)
                rcubea(xaxis_endstop_size_SN04, align=[-1,0,-1]);
            }
        }

        // support around z axis bearings
        translate([0, -xaxis_zaxis_distance_y, 0])
        cylindera(h=xaxis_end_wz,d=bearing_sizey, orient=[0,0,1], align=[0,0,0], round_radius=2);

        // belt idler screw cut support
        for(z=[-1,1])
        for(y=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0,y*-xaxis_beltpath_width/2,0])
            cylindera(orient=YAXIS, d=15*mm, h=7*mm, align=-y*YAXIS);
        }
    }
    else if(part=="neg")
    {
        // cut support around z axis bearings
        translate([0, -xaxis_zaxis_distance_y, 0])
        translate([0,0,.1])
        cubea([bearing_sizey+.1, bearing_sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[0,-1,0]);

        // x smooth rods
        for(z=[-1,1])
        translate([0,0*mm,z*(xaxis_rod_distance/2)])
        {
            xoff = - xaxis_end_xrod_offset_z -(with_xrod_adjustment?6:0)*mm;
            translate([xoff,0,0])
            cylindera(h=abs(xoff)+xaxis_end_width(with_motor)+1,d=xaxis_rod_d+.5*mm, orient=[1,0,0], align=[1,0,0]);

            if(with_xrod_adjustment)
            {
                translate([-xaxis_rod_l_support+5*mm,0,0])
                nut_trap_cut(nut=NutHexM4, trap_axis=YAXIS, orient=-XAXIS, align=XAXIS);

                translate([-xaxis_rod_l_support-7*mm,0,0])
                cylindera(d=10, h=10, orient=XAXIS);
            }
        }
    }
    else if(part=="vit")
    {
    }
}

module xaxis_end(part, with_motor=false, stop_x_rods=true, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false, with_xrod_adjustment=false)
{
    nut_h = zaxis_nut[4];
    extrasize = with_motor?0*mm:0*mm;
    extrasize_align = 1;

    if(part==undef)
    {
        difference()
        {
            xaxis_end(part="pos", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
            xaxis_end(part="neg", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
        }
        %xaxis_end(part="vit", with_motor=with_motor, stop_x_rods=stop_x_rods, beltpath_index=beltpath_index, show_motor=show_motor, nut_top=nut_top, show_nut=show_nut, show_rods=show_rods, show_bearings=show_bearings, with_xrod_adjustment=with_xrod_adjustment);
    }
    else if(part=="pos")
    {
        hull()
        {
            xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);
        }
    }
    else if(part=="neg")
    {
        xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

        // belt idler screw cut
        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0, -xaxis_beltpath_width/2 - 7*mm, 0])
            {
                screw_cut(nut=NutHexM5, h=xaxis_beltpath_width+13*mm, with_nut=true, orient=[0,1,0], align=[0,1,0]);
            }
        }

        //endstop mount screw cuts
        /*if(xaxis_endstop_type == "SWITCH")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            translate(xaxis_endstop_screw_offset_switch)
            for(y=[-1,1])
            translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size_switch[2]])
            {
                screw_cut(nut=NutHexM2_5, h=10*mm, embed_head=false, with_head=true, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
        /*else if(xaxis_endstop_type == "SN04")*/
        {
            translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
            translate(xaxis_endstop_screw_offset_SN04)
            for(y=[-1,1])
            translate([-0*mm,y*10.5*mm/2,xaxis_endstop_size_SN04[2]])
            {
                translate(xaxis_endstop_offset_SN04)
                screw_cut(nut=NutHexM3, h=20*mm, embed_head=false, with_head=true, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);
            }
        }

        xaxis_end_beltpath(height=xaxis_beltpath_height_body, width=xaxis_beltpath_width);

        // z smooth bearing mounts
        for(z=[-1,1])
        {
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            {
                bearing_mount_holes(
                        bearing_type=zaxis_bearing,
                        ziptie_type=ziptie_type,
                        ziptie_bearing_distance=ziptie_bearing_distance,
                        orient=[0,0,1],
                        with_zips=true
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

                    /*translate([-5*cm,0,0])*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/
                /*}*/
            }
        }

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])
                teardrop(d=round_d,h=motor_mount_wall_thick, tear_orient=[0,0,1], orient=[0,1,0], align=[0,-1,0], roll=90, truncate=0.9);

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                cylindera(d=bearing_MR105[1], h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                for(x=[-1,1])
                for(z=[-1,1])
                translate([0,-xaxis_end_motor_offset[1],0])
                translate([x*screw_dist/2, -(xaxis_beltpath_width/2+3*mm), z*screw_dist/2])
                {
                    if(!(x==1 && z == (beltpath_index==0?1:-1)))
                    screw_cut(xaxis_motor_nut, h=25, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=lookup(NemaFrontAxleLength,zaxis_motor), d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                    translate([i*zaxis_nut[5], 0, -zaxis_nut[3]])
                    screw_cut(thread=zaxis_nut[6], h=20*mm, with_nut=false, orient=ZAXIS, align=ZAXIS);
                }
            }
        }
    }
    else if(part=="vit")
    {
        xaxis_end_body(part=part, with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top, with_xrod_adjustment=with_xrod_adjustment);

        if(with_motor)
        {
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                // 1mm due to motor offset
                translate([0,-1*mm,0])
                {
                    // 1mm between pulley and motor
                    translate([0,-1*mm,0])
                    pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);

                    if(show_motor)
                    {
                        motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
                    }
                }
            }
        }

        //endstop
        if($show_vit)
        {
            /*if(xaxis_endstop_type == "SWITCH")*/
            {
                translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
                {
                    difference()
                    {
                        rcubea(xaxis_endstop_size_switch, align=[-1,0,1]);

                        translate(xaxis_endstop_screw_offset_switch)
                        for(y=[-1,1])
                        translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size_switch[2]])
                        screw(nut=NutHexM2_5, h=6*mm, orient=[0,0,-1], align=[0,0,-1]);
                    }
                }
            }
            /*else if(xaxis_endstop_type == "SN04")*/
            {
                translate([xaxis_end_width(with_motor),0,(xaxis_rod_distance/2)+xaxis_rod_d])
                {
                    translate(xaxis_endstop_offset_SN04)
                    translate([-36,-9,0])
                    rotate(ZAXIS*-90)
                    import("stl/SN04-N_Inductive_Proximity_Sensor_3528_0.stl");
                }
            }
        }

        // belt idler pulley screw
        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([0, -xaxis_beltpath_width/2 - 7*mm, 0])
            {
                screw(nut=NutHexM5, h=25*mm, with_nut=true, orient=[0,1,0], align=[0,1,0]);
            }
        }

        for(z=[-1,1])
        translate([xaxis_end_pulley_offset,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            pulley(xaxis_idler_pulley, orient=[0,1,0]);
        }

        if(show_nut)
        {
            mirror([0,0,nut_top?1:0])
            translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
            xaxis_end_znut();
        }

        if(show_rods)
        {
            for(z=[-1,1])
                translate([0,0,z*xaxis_rod_distance/2])
                translate([0, -xaxis_zaxis_distance_y, 0])
                cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
        }

        if(show_bearings)
        {
            for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            bearing(zaxis_bearing);
        }
    }
}

module xaxis_end_beltpath(height, width, length = 1000, align=[0,0,0], orient=[1,0,0])
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=orient, align=align, roll=-180*min(0,z), truncate=1);
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }

        translate([0,0,-.1])
        cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!$preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(x=[-1,1])
            {
                z=xaxis_beltpath_z_offsets[x<0?0:x];
                xo = x>0?xaxis_end_pulley_offset:xaxis_end_motor_offset[0];
                xw = x<0?xaxis_end_pulley_offset:xaxis_end_motor_offset[0];
                translate([-main_width/2-xo/2, xaxis_zaxis_distance_y, z])
                rotate([90,0,0])
                color("black")
                belt_path(main_width+xw, 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);
            }
        }

        /*translate([axis_pos_x,0,0])*/
        /*{*/
            // x carriage
            /*attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])*/
            /*{*/
                /*x_carriage_full();*/
            /*}*/
        /*}*/

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
        translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
        cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        translate([x*(zmotor_mount_rod_offset_x),0,0])
        cylindera(h=zaxis_rod_l,d=zaxis_rod_d, orient=ZAXIS, align=[0,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            {
                translate([0, xaxis_zaxis_distance_y, 0])
                translate([x*zmotor_mount_rod_offset_x, 0, 0])
                mirror([max(0,x),0,0])
                {
                    xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);
                }
            }
        }
    }

}

if(false)
{
    for(x=[-1,1])
    translate([x*55,x*55,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    {
        xaxis_end(with_motor=true, beltpath_index=max(0,x), show_motor=false, show_nut=false, show_bearings=false, with_xrod_adjustment=true);
    }
}

module part_x_end_right()
{
    x=1;
    translate([0,0,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    xaxis_end(with_motor=true, beltpath_index=max(0,x), with_xrod_adjustment=true);
}

module part_x_end_left()
{
    x=-1;
    translate([0,0,xaxis_end_wz/2])
    mirror([max(0,x),0,0])
    xaxis_end(with_motor=true, beltpath_index=max(0,x), with_xrod_adjustment=true);
}


see through lid/base on elbow, marker indent in forearm, extended forearm cutout

use <StepMotor_28BYJ-48.scad>;
use <Hub_28BYJ-48.scad>;
include <Bearing_6807-2RS.scad>;

// global rendering parameters
//$fn = 64; // production
//$fn = 48; // development
$fn = 24; // LQ
echo($fn);

// library examples
// translate([100, 100, 10]) { StepMotor28BYJ(); }
// stepperHub(10, 7, 6, 3.1, 1.5, 2.75);
//translate([0, 0, 8]) bearing6807_2RS();
// bearingInnerStep(bearing6807_2RS_d - iFitAdjust, 2, 2);
//shoulderBase(2, 55, 9.1, 3.1);

// interference fit adjustment for 3D printer
iFitAdjust = .4;

// shoulder base parameters
shoulderBaseHeight = 3;
shoulderBaseDiameter = 55;
shaftBossDiameter = 10;
mountScrewDiameter = 3.1;
bearingStep = 2; // size in mm of bearing interface step
// joint parameters
hubHeight = 10;
hubRadius = 7;
shaftHeight = 6;
shaftRadius = 3.1;
setScrewRadius = 1.5;
setScrewHeight = 2.75;
spokeWidth = 3;
spokes = 6;
screwTabs = 4;
screwTabHeight = 4;
armLength = 100;
// misc
baseDeckExtension = 60;
boundingBox = 8;
boundingBoxHalf = boundingBox / 2;
// 8 is distance from shaft center to screw center on x axis
// 35 is screw center to screw center on y axis
shaftCenterToMountHoldCenterXAxis = 8;
mountHoleCenterToMountHoleCenter = 35;
leadScrewDiameter = 8;
// forearm
forearmLength = 75;

/* Pieces in this model
** Shoulder:
*** Base plate
*** Top plate
*** Lower arm
*** Upper arm
** Forearm:
*** ?
** Hand:
*** ?
*/

// SHOULDER
// shoulder base
module shoulderBasePlate() { // make me
color([.7, .7, 1])
    shoulderBase(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter);
}
shoulderBasePlate();
// shoulder lower stepper
rotate([0, 180, 0])
    translate([-8, 0, 10])
        StepMotor28BYJ();
// lower shoulder bearing
translate([0, 0, shoulderBaseHeight + bearingStep])
    %bearing6807_2RS();
// shoulder top
color([.6, .6, .9])
    translate([0, 0, 2 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep)])
    rotate([180, 0, 0])
        shoulderBase(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter);
// upper shoulder bearing
translate([0, 0, shoulderBaseHeight + (3 * bearing6807_2RS_B) + (7 * bearingStep)])
    %bearing6807_2RS();
// shoulder upper stepper
rotate([0, 0, 180])
    translate([-8, 0, 10 + 2 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep)])
        StepMotor28BYJ();
// shoulder spacers
module shoulderSpacerSet() { // make me
color([.7, .6, .2])
shoulderSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
color([.7, .6, .2])
translate([baseDeckExtension / 3, 0, 0])
shoulderSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
}
shoulderSpacerSet();
// end shoulder

// lower arm including the shoulder - arm joint
//render()
module armSection() { // make me
color([1, .7, .7])
    translate([0, 0, shoulderBaseHeight + bearing6807_2RS_B])
        armLower(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength);
}
armSection();
// upper arm
//render()
color([.9, .7, .7])
    translate([0, 0, shoulderBaseHeight + ( 2*bearing6807_2RS_B) + (12 * bearingStep) - (.5 * bearingStep)])
        rotate([180, 0, 0])
            armLower(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength);
// elbow joint pieces
// lower bearing
translate([-armLength, 0, shoulderBaseHeight + bearing6807_2RS_B + bearingStep])
    %bearing6807_2RS();
// arm upper stepper
translate([-armLength + 8, 0, shoulderBaseHeight + ( 3*bearing6807_2RS_B) + (16 * bearingStep) - (.5 * bearingStep)])
    rotate([0, 0, 180])
        StepMotor28BYJ();
// arm lower stepper
rotate([0, 180, 0])
    translate([armLength - 8, 0, bearingStep * 2])
        StepMotor28BYJ();
// arm spacers
module armSpacerSet() { // make me
color([.6, .6, .3])
    armSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
}
armSpacerSet();
// end arm

// forearm pieces
// lower
module forearmSection() { // make me
color([.1, .7, .1])
translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (4 *bearingStep)])
//translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (14 *bearingStep)])
    forearmLower(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight + (bearing6807_2RS_B / 2) + (bearingStep/2), hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox);
}
forearmSection();
// upper
render()
color([.2, .8, .2])
translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (4 *bearingStep)])
    rotate([180, 0, 0])
        forearmLower(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight + (bearing6807_2RS_B / 2) + (bearingStep/2), hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox);
// forearm upper bearing
translate([-armLength, 0, shoulderBaseHeight + (2 * bearing6807_2RS_B) + (7 * bearingStep)])
    %bearing6807_2RS();
// forearm spacers
// none at this time

//bearingInnerStep(bearing6807_2RS_d - iFitAdjust, 2, 2);
module bearingInnerStep(bearingID, stepHeight, stepWidth) {
    difference() {
        union() {
            // this fits inside of the bearing
            cylinder(h = stepHeight * 2, d = bearingID);
            // this rests on the bearing inner lip
            cylinder(h = stepHeight, d = bearingID + stepWidth);
        }
        // remove center
        cylinder(h = stepHeight * 2, d = bearingID - (stepWidth * 2));
    }
}

//translate([0, 0, 12]) bearingOuterStep(bearing6807_2RS_D + iFitAdjust, 2, 2);
module bearingOuterStep(bearingOD, stepHeight, stepWidth) {
    //render(convexivity = 3)
    difference() {
        cylinder(h = stepHeight * 2, d = bearingOD + stepWidth);
        cylinder(h = stepHeight * 2, d = bearingOD - stepWidth);
        cylinder(h = stepHeight, d = bearingOD);
    }
}

module shoulderSpacers(bearingOD, screwSpacerHeight) {
    union() {
        // screw holes for joining to arm
        rotate([0, 0, -30])
        radial_array_partial(vec = [0, 0, 1], n = 6, 2)
            translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 1.0])
        difference() {
            union () {
                cylinder(h = screwSpacerHeight, r = setScrewRadius * 2);

                }
            cylinder(h = screwTabHeight, r = setScrewRadius);
        }
    }
}

module armSpacers(bearingOD, screwSpacerHeight) {
    union() {
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = 4)
            translate([bearingOD / 2 + (setScrewRadius * 2), 0, shoulderBaseHeight + bearing6807_2RS_B + 2 * bearingStep])
        difference() {
            union () {
                cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius * 2);

                }
            cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius);
        }
        // TODO: put in spacers along arm, make sure holes exist in arm
        translate([- armLength, 0, 0])
        rotate([0, 0, -30])
        radial_array_partial(vec = [0, 0, 1], n = 6, 2)
            translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight + bearing6807_2RS_B + 2 * bearingStep])
        difference() {
            union () {
                cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius * 2);

                }
            cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius);
        }
    }
}

// armJointSpacer(bearing6807_2RS_D - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, shaftBossDiameter, mountScrewDiameter);
module armJointSpacer(bearingID, bearingOD, bearingStep, shaftBossDiameter, mountScrewDiameter) {
    union() {
        difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
            cylinder(h = bearingStep * 2, d = bearingID);
        }
        translate([0, 0, bearingStep * 2])
                bearingInnerStep(bearingID, bearingStep, bearingStep);
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * bearingStep) - screwTabHeight])
                    difference() {
                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }
                        cylinder(h = screwTabHeight, r = setScrewRadius);
                    }
    }
}

//shoulderBase(2, 55, 9.1, 3.1);
// WARNING: has some hard-coded non-parametric values in here!
module shoulderBase(bearingID, bearingOD, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter) {
    mountHoleDepth = shoulderBaseHeight;

    //render(convexivity = 3)
    difference() {
        union () {
            cylinder(h = shoulderBaseHeight, d = shoulderBaseDiameter);
            translate([0, 0, shoulderBaseHeight])
                bearingInnerStep(bearing6807_2RS_d - iFitAdjust, bearingStep, bearingStep);
            // 40 is the length of deck extension from the baseplate in x
            translate([0, -shoulderBaseDiameter / 2, 0])
                cube([baseDeckExtension, shoulderBaseDiameter, shoulderBaseHeight], center = false);
        }
        // motor shaft hole
        cylinder(h = shoulderBaseHeight + (bearingStep * 2), d = shaftBossDiameter);
        // mounting holes

        translate([shaftCenterToMountHoldCenterXAxis, mountHoleCenterToMountHoleCenter/2, 0])
            cylinder(h = mountHoleDepth, d = mountScrewDiameter);
        translate([shaftCenterToMountHoldCenterXAxis, -mountHoleCenterToMountHoleCenter/2, 0])
            cylinder(h = mountHoleDepth, d = mountScrewDiameter);
        // lead screw hole
        translate([baseDeckExtension - (leadScrewDiameter * 1.5), 0, 0])
            cylinder(h = shoulderBaseHeight, d = leadScrewDiameter + (leadScrewDiameter / 2));
        // upper to lower spacer screw holes
        rotate([0, 0, -30])
            radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 0])
                    cylinder(h = screwTabHeight, r = setScrewRadius);
           translate([baseDeckExtension / 3, 0, 0])
            rotate([0, 0, -30])
            radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 0])
                    cylinder(h = screwTabHeight, r = setScrewRadius);
    }
    // NOTE: need to add LM8UU mounts
}

module armLower(bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength) {
    armWidth = bearingOD / 2;
    //render(convexivity = 3)
    difference() {
    union() {
        armInnerJoint(bearingOD, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight);
        translate([-armLength, 0, 0])
            armOuterJointBase(bearingOD, bearingStep, setScrewRadius, screwTabs, screwTabHeight);
        difference() {
            translate([-armLength, -armWidth / 2, 0])
                cube([armLength, armWidth, bearingStep * 2], center=false);
            cylinder(h = bearingStep * 2, d = bearingOD);
            translate([-armLength, 0, 0])
                cylinder(h = bearingStep * 2, d = bearingOD);
            translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                cube([armLength - bearingOD - (boundingBox + boundingBoxHalf), armWidth - boundingBox, bearingStep * 2], center = false);
        }
        difference() {
            intersection() {

                translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([armLength - bearingOD - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
                for (i = [ bearingOD / 2 - boundingBoxHalf: armWidth : armLength]) {
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, 45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, -45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                }
            }

        }
               difference() {
               hull() {
                   translate([- armLength, 0, bearingStep])
                    linear_extrude(height = 2 * bearingStep, center = true, twist = 0)
                        polygon(points=[[0, -bearingOD/2 - setScrewRadius/2], [bearingOD / 2 + (setScrewRadius * 8), -armWidth / 2], [bearingOD / 2 + (setScrewRadius * 8), armWidth / 2], [0, bearingOD/2 + setScrewRadius/2]]);
                translate([- armLength, 0, 0])
                    rotate([0, 0, -30])
                    radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                        translate([bearingOD / 2 + (setScrewRadius * 8), 0, 0])
                            cylinder(h = 2 * bearingStep, r = setScrewRadius * 2);

                    }
                translate([- armLength, 0, 0])
                    rotate([0, 0, -30])
                    radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                        translate([bearingOD / 2 + (setScrewRadius * 8), 0, 0])
                        cylinder(h = 2 * bearingStep, r = setScrewRadius);

                 translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([armLength - bearingOD - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
             translate([-armLength, 0, 0])
                cylinder(h = bearingStep * 2, d = bearingOD);

        }
   }
           // screw holes for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])
                       cylinder(h = screwTabHeight, r = setScrewRadius);

   }
}

module armOuterJointBase(bearingOD, bearingStep, setScrewRadius, screwTabs, screwTabHeight) {
    mountHoleDepth = bearingStep * 2;

    //render()
    union() {
        difference() {
            union() {
                translate([0, 0, -(bearingStep * 2)])
                    difference() { // base w/ cutout for seeing into the joint

                        cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
                    intersection() { // cutout
                        difference() {
                            cylinder(h = bearingStep * 2, d = .85 * bearingOD);
                            cylinder(h = bearingStep * 2, d = .35 * bearingOD);
                        }
                        translate([-bearingOD, -bearingOD/2, 0])
                            cube([bearingOD, bearingOD, bearingStep * 2], center = false);
                    }
                }
                translate([0, 0, bearingStep * 2])
                    rotate([0, 180, 0])
                        bearingOuterStep(bearingOD, bearingStep, bearingStep);
                // spokes
                rotate([0, 0, 150])
                radial_array_partial(vec=[0, 0, 1], n = 6, 2)
                translate([hubRadius - (bearingStep / 2), -(spokeWidth / 2), -(bearingStep * 2)])
                    cube([(bearingOD / 2) - hubRadius, spokeWidth, bearingStep], center = false);
            }
            // motor shaft hole
            translate([0, 0, -(bearingStep * 2)])
                cylinder(h = shoulderBaseHeight + (bearingStep * 2), d = shaftBossDiameter);
            // mounting holes
            translate([0, 0, -(bearingStep * 2)]) {
                translate([shaftCenterToMountHoldCenterXAxis, mountHoleCenterToMountHoleCenter/2, 0])
                cylinder(h = mountHoleDepth, d = mountScrewDiameter);
                translate([shaftCenterToMountHoldCenterXAxis, -mountHoleCenterToMountHoleCenter/2, 0])
                cylinder(h = mountHoleDepth, d = mountScrewDiameter);
            }
        }

    }
}

//armInnerJoint(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight);
module armInnerJoint(bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight) {
    //translate([0, 0, hubHeight - (2 * stepHeight)])
    difference() {
        union() {
         difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + (setScrewRadius * 6));
            cylinder(h = bearingStep * 2, d = bearingOD);
//            translate([0, -bearingOD, 0])
//                cube([bearingOD, bearingOD * 2, bearingStep * 2]);
        }
        bearingOuterStep(bearingOD, stepHeight, stepWidth);
        // hub
        translate([0, 0, -(hubHeight - (2 * stepHeight))])
            stepperHub(hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight);
        // spokes
        radial_array(vec=[0, 0, 1], n = spokes)
                translate([hubRadius - (stepWidth / 2), -(spokeWidth / 2), stepHeight])
                    cube([(bearingOD / 2) - hubRadius, spokeWidth, stepHeight], center = false);
        // screw tabs for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])

                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }

                    }
        // screw holes for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])
                       cylinder(h = screwTabHeight, r = setScrewRadius);
    }
}

module forearmLower(bearingID, bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox) {
    armWidth = bearingOD / 2;

    rotate([180, 0, 0]) union() {
        boundingBoxHalf = boundingBox / 2;
        difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
            cylinder(h = bearingStep * 2, d = bearingID - (2 * bearingStep));
        }
        translate([0, 0, bearingStep * 2])
            bearingInnerStep(bearingID, bearingStep, bearingStep);
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * bearingStep) - screwTabHeight])
                    difference() {
                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }
                        cylinder(h = screwTabHeight, r = setScrewRadius);
                    }
        // hub
        translate([0, 0, hubHeight]) rotate([180, 0, 0])
            stepperHub(hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight);
        // spokes
        radial_array(vec=[0, 0, 1], n = spokes)
                translate([hubRadius - (stepWidth / 2), -(spokeWidth / 2), 0])
                    cube([(bearingOD / 2) - hubRadius, spokeWidth, 2 *stepHeight], center = false);
        // forearm extension
        difference() {
            translate([-forearmLength, -armWidth / 2, 0])
                cube([forearmLength, armWidth, bearingStep * 2], center=false);
            cylinder(h = bearingStep * 2, d = bearingOD);
 /* original */
sharpieDiameter = 13;
            translate([-forearmLength, 0, 0])
                 cylinder(h = bearingStep * 2, d = sharpieDiameter);
                 // 4 on next line comes from dividing the bearingOD on the above line
            #translate([-forearmLength + sharpieDiameter, -(armWidth / 2) + boundingBoxHalf, 0])
                cube([forearmLength - (bearingOD/2) - (boundingBox + boundingBoxHalf), armWidth - boundingBox, bearingStep * 2], center = false);
/**/
        }

            intersection() {

                translate([-forearmLength + boundingBox, -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([forearmLength - (bearingOD / 2) - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
                for (i = [ bearingOD / 2 - boundingBoxHalf: armWidth : forearmLength]) {
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, 45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, -45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                }
            }

    }
}

module copy_mirror(vec=[0,1,0]) {
    children();
    mirror(vec)
        children();
}

module radial_array(vec = [0,0,1], n = 4) {
    for ( i = [0 : n - 1] )
    {
        rotate( i * 360 / n, vec)
            children();
    }
}

module radial_array_partial(vec = [0,0,1], n = 4, j = 2) {
    for ( i = [0 : n - 1] )
    {
        if (i < j)
            rotate( i * 360 / n, vec)
                children();
    }
}

use <StepMotor_28BYJ-48.scad>;
use <Hub_28BYJ-48.scad>;
include <Bearing_6807-2RS.scad>;

// global rendering parameters
quality = "development";
if (quality == "production") {
	$fn = 48;
} else {
	$fn = 24;
}

// library examples
// translate([100, 100, 10]) { StepMotor28BYJ(); }
// stepperHub(10, 7, 6, 3.1, 1.5, 2.75);
//translate([0, 0, 8]) bearing6807_2RS();
// bearingInnerStep(bearing6807_2RS_d - iFitAdjust, 2, 2);
//shoulderBase(2, 55, 9.1, 3.1);

// interference fit adjustment for 3D printer
iFitAdjust = .4;

// shoulder base parameters
shoulderBaseHeight = 3;
shoulderBaseDiameter = 55;
shaftBossDiameter = 10;
mountScrewDiameter = 3.1;
bearingStep = 2; // size in mm of bearing interface step
// joint parameters
hubHeight = 10;
hubRadius = 7;
shaftHeight = 6;
shaftRadius = 3.1;
setScrewRadius = 1.5;
setScrewHeight = 2.75;
spokeWidth = 3;
spokes = 6;
screwTabs = 4;
screwTabHeight = 4;
armLength = 100;
// misc
baseDeckExtension = 60;
boundingBox = 8;
boundingBoxHalf = boundingBox / 2;
// 8 is distance from shaft center to screw center on x axis
// 35 is screw center to screw center on y axis
shaftCenterToMountHoldCenterXAxis = 8;
mountHoleCenterToMountHoleCenter = 35;
leadScrewDiameter = 8;
// forearm
forearmLength = 75;

/* Pieces in this model
** Shoulder:
*** Base plate
*** Top plate
*** Lower arm
*** Upper arm
** Forearm:
*** ?
** Hand:
*** ?
*/

// SHOULDER
// shoulder base
module shoulderBasePlate() { // make me
color([.7, .7, 1])
    shoulderBase(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter);
}
shoulderBasePlate();
// shoulder lower stepper
rotate([0, 180, 0])
    translate([-8, 0, 10])
        StepMotor28BYJ();
// lower shoulder bearing
translate([0, 0, shoulderBaseHeight + bearingStep])
    %bearing6807_2RS();
// shoulder top
color([.6, .6, .9])
    translate([0, 0, 2 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep)])
    rotate([180, 0, 0])
        shoulderBase(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter);
// upper shoulder bearing
translate([0, 0, shoulderBaseHeight + (3 * bearing6807_2RS_B) + (7 * bearingStep)])
    %bearing6807_2RS();
// shoulder upper stepper
rotate([0, 0, 180])
    translate([-8, 0, 10 + 2 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep)])
        StepMotor28BYJ();
// shoulder spacers
module shoulderSpacerSet() { // make me
color([.7, .6, .2])
shoulderSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
color([.7, .6, .2])
translate([baseDeckExtension / 3, 0, 0])
shoulderSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
}
shoulderSpacerSet();
// end shoulder

// lower arm including the shoulder - arm joint
//render()
module armSection() { // make me
color([1, .7, .7])
    translate([0, 0, shoulderBaseHeight + bearing6807_2RS_B])
        armLower(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength);
}
armSection();
// upper arm
//render()
color([.9, .7, .7])
    translate([0, 0, shoulderBaseHeight + ( 2*bearing6807_2RS_B) + (12 * bearingStep) - (.5 * bearingStep)])
        rotate([180, 0, 0])
            armLower(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength);
// elbow joint pieces
// lower bearing
translate([-armLength, 0, shoulderBaseHeight + bearing6807_2RS_B + bearingStep])
    %bearing6807_2RS();
// arm upper stepper
translate([-armLength + 8, 0, shoulderBaseHeight + ( 3*bearing6807_2RS_B) + (16 * bearingStep) - (.5 * bearingStep)])
    rotate([0, 0, 180])
        StepMotor28BYJ();
// arm lower stepper
rotate([0, 180, 0])
    translate([armLength - 8, 0, bearingStep * 2])
        StepMotor28BYJ();
// arm spacers
module armSpacerSet() { // make me
color([.6, .6, .3])
    armSpacers(bearing6807_2RS_D + iFitAdjust, 0 * shoulderBaseHeight + (4 * bearing6807_2RS_B) + (8 * bearingStep));
}
armSpacerSet();
// end arm

// forearm pieces
// lower
module forearmSection() { // make me
color([.1, .7, .1])
translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (4 *bearingStep)])
//translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (14 *bearingStep)])
    forearmLower(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight + (bearing6807_2RS_B / 2) + (bearingStep/2), hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox);
}
forearmSection();
// upper
color([.2, .8, .2])
translate([-armLength, 0, shoulderBaseHeight + (bearing6807_2RS_B * 2) + (4 *bearingStep)])
    rotate([180, 0, 0])
        forearmLower(bearing6807_2RS_d - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight + (bearing6807_2RS_B / 2) + (bearingStep/2), hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox);
// forearm upper bearing
translate([-armLength, 0, shoulderBaseHeight + (2 * bearing6807_2RS_B) + (7 * bearingStep)])
    %bearing6807_2RS();
// forearm spacers
// none at this time

//bearingInnerStep(bearing6807_2RS_d - iFitAdjust, 2, 2);
module bearingInnerStep(bearingID, stepHeight, stepWidth) {
    difference() {
        union() {
            // this fits inside of the bearing
            cylinder(h = stepHeight * 2, d = bearingID);
            // this rests on the bearing inner lip
            cylinder(h = stepHeight, d = bearingID + stepWidth);
        }
        // remove center
        cylinder(h = stepHeight * 2, d = bearingID - (stepWidth * 2));
    }
}

//translate([0, 0, 12]) bearingOuterStep(bearing6807_2RS_D + iFitAdjust, 2, 2);
module bearingOuterStep(bearingOD, stepHeight, stepWidth) {
    //render(convexivity = 3)
    difference() {
        cylinder(h = stepHeight * 2, d = bearingOD + stepWidth);
        cylinder(h = stepHeight * 2, d = bearingOD - stepWidth);
        cylinder(h = stepHeight, d = bearingOD);
    }
}

module shoulderSpacers(bearingOD, screwSpacerHeight) {
    union() {
        // screw holes for joining to arm
        rotate([0, 0, -30])
        radial_array_partial(vec = [0, 0, 1], n = 6, 2)
            translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 1.0])
        difference() {
            union () {
                cylinder(h = screwSpacerHeight, r = setScrewRadius * 2);

                }
            cylinder(h = screwTabHeight, r = setScrewRadius);
        }
    }
}

module armSpacers(bearingOD, screwSpacerHeight) {
    union() {
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = 4)
            translate([bearingOD / 2 + (setScrewRadius * 2), 0, shoulderBaseHeight + bearing6807_2RS_B + 2 * bearingStep])
        difference() {
            union () {
                cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius * 2);

                }
            cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius);
        }
        // TODO: put in spacers along arm, make sure holes exist in arm
        translate([- armLength, 0, 0])
        rotate([0, 0, -30])
        radial_array_partial(vec = [0, 0, 1], n = 6, 2)
            translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight + bearing6807_2RS_B + 2 * bearingStep])
        difference() {
            union () {
                cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius * 2);

                }
            cylinder(h = bearing6807_2RS_B * 2 + 4 * bearingStep, r = setScrewRadius);
        }
    }
}

// armJointSpacer(bearing6807_2RS_D - iFitAdjust, bearing6807_2RS_D + iFitAdjust, bearingStep, shaftBossDiameter, mountScrewDiameter);
module armJointSpacer(bearingID, bearingOD, bearingStep, shaftBossDiameter, mountScrewDiameter) {
    union() {
        difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
            cylinder(h = bearingStep * 2, d = bearingID);
        }
        translate([0, 0, bearingStep * 2])
                bearingInnerStep(bearingID, bearingStep, bearingStep);
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * bearingStep) - screwTabHeight])
                    difference() {
                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }
                        cylinder(h = screwTabHeight, r = setScrewRadius);
                    }
    }
}

//shoulderBase(2, 55, 9.1, 3.1);
// WARNING: has some hard-coded non-parametric values in here!
module shoulderBase(bearingID, bearingOD, shoulderBaseHeight, shoulderBaseDiameter, shaftBossDiameter, mountScrewDiameter) {
    mountHoleDepth = shoulderBaseHeight;

    //render(convexivity = 3)
    difference() {
        union () {
            cylinder(h = shoulderBaseHeight, d = shoulderBaseDiameter);
            translate([0, 0, shoulderBaseHeight])
                bearingInnerStep(bearing6807_2RS_d - iFitAdjust, bearingStep, bearingStep);
            // 40 is the length of deck extension from the baseplate in x
            translate([0, -shoulderBaseDiameter / 2, 0])
                cube([baseDeckExtension, shoulderBaseDiameter, shoulderBaseHeight], center = false);
        }
        // motor shaft hole
        cylinder(h = shoulderBaseHeight + (bearingStep * 2), d = shaftBossDiameter);
        // mounting holes

        translate([shaftCenterToMountHoldCenterXAxis, mountHoleCenterToMountHoleCenter/2, 0])
            cylinder(h = mountHoleDepth, d = mountScrewDiameter);
        translate([shaftCenterToMountHoldCenterXAxis, -mountHoleCenterToMountHoleCenter/2, 0])
            cylinder(h = mountHoleDepth, d = mountScrewDiameter);
        // lead screw hole
        translate([baseDeckExtension - (leadScrewDiameter * 1.5), 0, 0])
            cylinder(h = shoulderBaseHeight, d = leadScrewDiameter + (leadScrewDiameter / 2));
        // upper to lower spacer screw holes
        rotate([0, 0, -30])
            radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 0])
                    cylinder(h = screwTabHeight, r = setScrewRadius);
           translate([baseDeckExtension / 3, 0, 0])
            rotate([0, 0, -30])
            radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                translate([bearingOD / 2 + (setScrewRadius * 8), 0, shoulderBaseHeight * 0])
                    cylinder(h = screwTabHeight, r = setScrewRadius);
    }
    // NOTE: need to add LM8UU mounts
}

module armLower(bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight, armLength) {
    armWidth = bearingOD / 2;
    //render(convexivity = 3)
    difference() {
    union() {
        armInnerJoint(bearingOD, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight);
        translate([-armLength, 0, 0])
            armOuterJointBase(bearingOD, bearingStep, setScrewRadius, screwTabs, screwTabHeight);
        difference() {
            translate([-armLength, -armWidth / 2, 0])
                cube([armLength, armWidth, bearingStep * 2], center=false);
            cylinder(h = bearingStep * 2, d = bearingOD);
            translate([-armLength, 0, 0])
                cylinder(h = bearingStep * 2, d = bearingOD);
            translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                cube([armLength - bearingOD - (boundingBox + boundingBoxHalf), armWidth - boundingBox, bearingStep * 2], center = false);
        }
        difference() {
            intersection() {

                translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([armLength - bearingOD - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
                for (i = [ bearingOD / 2 - boundingBoxHalf: armWidth : armLength]) {
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, 45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, -45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                }
            }

        }
               difference() {
               hull() {
                   translate([- armLength, 0, bearingStep])
                    linear_extrude(height = 2 * bearingStep, center = true, twist = 0)
                        polygon(points=[[0, -bearingOD/2 - setScrewRadius/2], [bearingOD / 2 + (setScrewRadius * 8), -armWidth / 2], [bearingOD / 2 + (setScrewRadius * 8), armWidth / 2], [0, bearingOD/2 + setScrewRadius/2]]);
                translate([- armLength, 0, 0])
                    rotate([0, 0, -30])
                    radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                        translate([bearingOD / 2 + (setScrewRadius * 8), 0, 0])
                            cylinder(h = 2 * bearingStep, r = setScrewRadius * 2);

                    }
                translate([- armLength, 0, 0])
                    rotate([0, 0, -30])
                    radial_array_partial(vec = [0, 0, 1], n = 6, 2)
                        translate([bearingOD / 2 + (setScrewRadius * 8), 0, 0])
                        cylinder(h = 2 * bearingStep, r = setScrewRadius);

                 translate([-armLength + (bearingOD / 2) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([armLength - bearingOD - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
             translate([-armLength, 0, 0])
                cylinder(h = bearingStep * 2, d = bearingOD);

        }
   }
           // screw holes for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])
                       cylinder(h = screwTabHeight, r = setScrewRadius);

   }
}

module armOuterJointBase(bearingOD, bearingStep, setScrewRadius, screwTabs, screwTabHeight) {
    mountHoleDepth = bearingStep * 2;

    union() {
        difference() {
            union() {
                translate([0, 0, -(bearingStep * 2)])
                    cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
                translate([0, 0, bearingStep * 2])
                    rotate([0, 180, 0])
                        bearingOuterStep(bearingOD, bearingStep, bearingStep);
            }
            // motor shaft hole
            translate([0, 0, -(bearingStep * 2)])
                cylinder(h = shoulderBaseHeight + (bearingStep * 2), d = shaftBossDiameter);
            // mounting holes
            translate([0, 0, -(bearingStep * 2)]) {
                translate([shaftCenterToMountHoldCenterXAxis, mountHoleCenterToMountHoleCenter/2, 0])
                cylinder(h = mountHoleDepth, d = mountScrewDiameter);
                translate([shaftCenterToMountHoldCenterXAxis, -mountHoleCenterToMountHoleCenter/2, 0])
                cylinder(h = mountHoleDepth, d = mountScrewDiameter);
            }
        }

    }
}

//armInnerJoint(bearing6807_2RS_D + iFitAdjust, bearingStep, bearingStep, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight);
module armInnerJoint(bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, screwTabs, screwTabHeight) {
    //translate([0, 0, hubHeight - (2 * stepHeight)])
    difference() {
        union() {
         difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + (setScrewRadius * 6));
            cylinder(h = bearingStep * 2, d = bearingOD);
//            translate([0, -bearingOD, 0])
//                cube([bearingOD, bearingOD * 2, bearingStep * 2]);
        }
        bearingOuterStep(bearingOD, stepHeight, stepWidth);
        // hub
        translate([0, 0, -(hubHeight - (2 * stepHeight))])
            stepperHub(hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight);
        // spokes
        radial_array(vec=[0, 0, 1], n = spokes)
                translate([hubRadius - (stepWidth / 2), -(spokeWidth / 2), stepHeight])
                    cube([(bearingOD / 2) - hubRadius, spokeWidth, stepHeight], center = false);
        // screw tabs for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])

                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }

                    }
        // screw holes for joining to upper
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * stepHeight) - screwTabHeight])
                       cylinder(h = screwTabHeight, r = setScrewRadius);
    }
}

module forearmLower(bearingID, bearingOD, stepHeight, stepWidth, hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight, spokeWidth, spokes, forearmLength, boundingBox) {
    armWidth = bearingOD / 2;

    rotate([180, 0, 0]) union() {
        boundingBoxHalf = boundingBox / 2;
        difference() {
            cylinder(h = bearingStep * 2, d = bearingOD + bearingStep);
            cylinder(h = bearingStep * 2, d = bearingID - (2 * bearingStep));
        }
        translate([0, 0, bearingStep * 2])
            bearingInnerStep(bearingID, bearingStep, bearingStep);
        // screw holes for joining to arm
        radial_array(vec = [0, 0, 1], n = screwTabs)
                translate([bearingOD / 2 + (setScrewRadius * 2), 0, (2 * bearingStep) - screwTabHeight])
                    difference() {
                        union () {
                            cylinder(h = screwTabHeight, r = setScrewRadius * 2);
                            translate([-2 * setScrewRadius, - 2 * setScrewRadius, 0])
                                cube([setScrewRadius * 2, 4 * setScrewRadius, screwTabHeight], center = false);
                        }
                        cylinder(h = screwTabHeight, r = setScrewRadius);
                    }
        // hub
        translate([0, 0, hubHeight]) rotate([180, 0, 0])
            stepperHub(hubHeight, hubRadius, shaftHeight, shaftRadius, setScrewRadius, setScrewHeight);
        // spokes
        radial_array(vec=[0, 0, 1], n = spokes)
                translate([hubRadius - (stepWidth / 2), -(spokeWidth / 2), 0])
                    cube([(bearingOD / 2) - hubRadius, spokeWidth, 2 *stepHeight], center = false);
        // forearm extension
             difference() {
            translate([-forearmLength, -armWidth / 2, 0])
                cube([forearmLength, armWidth, bearingStep * 2], center=false);
            cylinder(h = bearingStep * 2, d = bearingOD);
            translate([-forearmLength, 0, 0])
                cylinder(h = bearingStep * 2, d = bearingOD / 2);
                 // 4 on next line comes from dividing the bearingOD on the above line
            translate([-forearmLength + (bearingOD / 4) + (boundingBox / 2), -(armWidth / 2) + boundingBoxHalf, 0])
                cube([forearmLength - (bearingOD/2) - (boundingBox + boundingBoxHalf), armWidth - boundingBox, bearingStep * 2], center = false);
        }

            intersection() {

                translate([-forearmLength + boundingBox * 2, -(armWidth / 2) + boundingBoxHalf, 0])
                    cube([forearmLength - (bearingOD / 2) - boundingBox, armWidth - boundingBox, bearingStep * 2], center = false);
                for (i = [ bearingOD / 2 - boundingBoxHalf: armWidth : forearmLength]) {
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, 45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                    translate([ -i, 0, bearingStep])
                        rotate([0, 0, -45])
                            cube([spokeWidth, armWidth + boundingBoxHalf, bearingStep * 2], center = true);
                }
            }

    }
}

module copy_mirror(vec=[0,1,0]) {
    children();
    mirror(vec)
        children();
}

module radial_array(vec = [0,0,1], n = 4) {
    for ( i = [0 : n - 1] )
    {
        rotate( i * 360 / n, vec)
            children();
    }
}

module radial_array_partial(vec = [0,0,1], n = 4, j = 2) {
    for ( i = [0 : n - 1] )
    {
        if (i < j)
            rotate( i * 360 / n, vec)
                children();
    }
}


y/idler: fix print direction

y/idler: fix print direction

include <y-idler.h>

include <thing_libutils/materials.scad>
use <thing_libutils/screws.scad>

module yaxis_idler(part)
{
    tighten_screw_dia_outer = yaxis_idler_mount_tightscrew_dia*4;
    mount_screw_dist = (yidler_w/2+yaxis_idler_mount_thread_dia*3)*1.3;

    if(part==U)
    {
        difference()
        {
            yaxis_idler(part="pos");
            yaxis_idler(part="neg");
        }
        yaxis_idler(part="vit");
    }
    else if(part=="pos")
    material(Mat_Plastic)
    {
        // front plate
        tx(-extrusion_size/2)
        rcubea(
            size=[yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size],
            align=-X,
            extra_size=Z*yaxis_idler_mount_thickness,
            extra_align=Z
            );

        // top mount plate
        tx(-yaxis_idler_mount_thickness)
        tz(extrusion_size/2)
        rcubea(
            size=[extrusion_size, yidler_mount_width, yaxis_idler_mount_thickness],
            align=Z,
            extra_size=[yaxis_idler_mount_thickness,0,0],
            extra_align=X
            );

        intersection()
        {
            tz(extrusion_size/2)
            cubea([100, yidler_mount_width, 100], align=Z);

            hull()
            {
                for(y=[-1,1])
                ty(y*yaxis_idler_tightscrew_dist)
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                {
                    translate([yaxis_idler_mount_thickness/2,0,yaxis_belt_path_offset_z])
                    rcylindera(
                        h=extrusion_size+yaxis_idler_mount_thickness,
                        d=tighten_screw_dia_outer,
                        align=N,
                        orient=X
                        );
                    rcubea(
                        size=[extrusion_size, mount_screw_dist-yaxis_idler_mount_tightscrew_dia*3, yaxis_idler_mount_thickness],
                        align=Z,
                        extra_size=[yaxis_idler_mount_thickness,0,0],
                        extra_align=X
                        );
                }

                // adjustment screw
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                t(yaxis_idler_mount_adjustscrew_offset)
                rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*2, orient=X, align=X);

                // adjustment screw
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                t([yaxis_idler_mount_thickness/2,0,yaxis_belt_path_offset_z])
                t(yaxis_idler_mount_adjustscrew_offset)
                rcylindera(
                    h=extrusion_size+yaxis_idler_mount_thickness,
                    d=yaxis_idler_mount_adjustscrew_hexnut_dia*sqrt(2),
                    align=N,
                    orient=X
                    );
                /*rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*2, orient=X, align=X);*/
            }

        }

    }
    else if(part=="neg")
    {
        // top/vertical mount screws (to extrusion)
        tz(extrusion_size/2+yaxis_idler_mount_thickness)
        for(y=[-1,1])
        ty(y*mount_screw_dist/2)
        screw_cut(nut=extrusion_nut, head="button", h=yaxis_idler_mount_thickness+5*mm, with_nut=false, orient=-Z, align=-Z);

        // mount screws for pulley block
        for(y=[-1,1])
        tx(-extrusion_size/2-yaxis_idler_mount_thickness)
        ty(y*yaxis_idler_tightscrew_dist)
        tz(extrusion_size/2+yaxis_belt_path_offset_z)
        screw_cut(yaxis_idler_mount_tightscrew_hexnut, head_embed=false, h=extrusion_size+yaxis_idler_mount_thickness+10*mm, with_nut=false, orient=X, align=X);

        // pulley block adjustment screw
        tx(-extrusion_size/2)
        tx(-yaxis_idler_mount_thickness)
        tz(extrusion_size/2+yaxis_belt_path_offset_z)
        t(yaxis_idler_mount_adjustscrew_offset)
        screw_cut(yaxis_idler_mount_adjustscrew_hexnut, head="button", h=extrusion_size+yaxis_idler_mount_thickness+10*mm, head_embed=false, with_nut=false, orient=X, align=X);

        // front/horizontal mount screws (to extrusion)
        tx(-extrusion_size/2)
        tx(-yaxis_idler_mount_thickness)
        for(y=[-1,1])
        ty(y*(yaxis_idler_mount_thread_dia*2.5))
        screw_cut(nut=extrusion_nut, head="button", h=yaxis_idler_mount_thickness+5*mm, with_nut=false, orient=X, align=X);
    }
}

module yaxis_idler_pulleyblock(part, show_pulley=false)
{
    h = yaxis_idler_pulley_h + 3*mm*2;
    d=yaxis_idler_mount_tightscrew_hexnut_dia*2;

    if(part==U)
    {
        difference()
        {
            yaxis_idler_pulleyblock(part="pos");
            yaxis_idler_pulleyblock(part="neg");
        }
        %yaxis_idler_pulleyblock(part="vit");
    }
    else if(part=="pos")
    material(Mat_Plastic)
    {
        hull()
        {
            // idler
            tz(h/2)
            rcylindera(d=yaxis_idler_pulley_thread_dia+15*mm, h=h, orient=-Z, align=-Z);

            // tension screws
            tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
            for(y=[-1,1])
            ty(y*yaxis_idler_tightscrew_dist)
            rcubea([d,d,yaxis_idler_pulley_tight_len], orient=X, align=X);

            // adjustment screw
            tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
            t(yaxis_idler_mount_adjustscrew_offset)
            rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*sqrt(2), orient=X, align=X);
        }
    }
    else if(part=="neg")
    {
        // pulley cutout
        tx(-3*mm)
        cubea(
            size=[yaxis_idler_pulley_outer_d, yaxis_idler_pulley_outer_d*3, yaxis_idler_pulley_h+0.5],
            align=N,
            extra_size=[20*mm,0,0], extra_align=X
            );

        // pulley screw
        tz(h/2)
        screw_cut(yaxis_idler_pulley_nut, head="button", h=h+5*mm, orient=-Z, align=-Z);

        // tension screws
        for(y=[-1,1])
        tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
        ty(y*yaxis_idler_tightscrew_dist)
        screw_cut(yaxis_idler_mount_tightscrew_hexnut, head_embed=false, nut_offset=2*mm, h=yaxis_idler_pulley_tight_len, orient=X, align=X);

        // adjustment screw
        tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
        tx(yaxis_idler_pulley_tight_len/2)
        t(yaxis_idler_mount_adjustscrew_offset)
        nut_trap_cut(nut=yaxis_idler_mount_adjustscrew_hexnut, head="button", cut_screw=true, screw_l=7*mm, trap_axis=-Z, orient=-X);
    }
    else if(part=="vit")
    {
        pulley(pulley_2GT_20T_idler);
    }

}

module part_y_idler()
{
    attach([N, -Z], yaxis_idler_conn)
    {
        yaxis_idler();
    }
}

module part_y_idler_pulleyblock()
{
    attach([N, Z], yaxis_idler_pulleyblock_conn_print)
    {
        yaxis_idler_pulleyblock(show_pulley=false);
    }
}

/*yaxis_idler();*/
/*yaxis_idler_pulleyblock();*/

/*attach([N,-X], yaxis_idler_conn)*/
/*{*/
    /*yaxis_idler();*/
    /*attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)*/
    /*{*/
        /*yaxis_idler_pulleyblock(show_pulley=true);*/
    /*}*/
/*}*/

include <y-idler.h>

include <thing_libutils/materials.scad>
use <thing_libutils/screws.scad>

module yaxis_idler(part)
{
    tighten_screw_dia_outer = yaxis_idler_mount_tightscrew_dia*4;
    mount_screw_dist = (yidler_w/2+yaxis_idler_mount_thread_dia*3)*1.3;

    if(part==U)
    {
        difference()
        {
            yaxis_idler(part="pos");
            yaxis_idler(part="neg");
        }
        yaxis_idler(part="vit");
    }
    else if(part=="pos")
    material(Mat_Plastic)
    {
        // front plate
        tx(-extrusion_size/2)
        rcubea(
            size=[yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size],
            align=-X,
            extra_size=Z*yaxis_idler_mount_thickness,
            extra_align=Z
            );

        // top mount plate
        tx(-yaxis_idler_mount_thickness)
        tz(extrusion_size/2)
        rcubea(
            size=[extrusion_size, yidler_mount_width, yaxis_idler_mount_thickness],
            align=Z,
            extra_size=[yaxis_idler_mount_thickness,0,0],
            extra_align=X
            );

        intersection()
        {
            tz(extrusion_size/2)
            cubea([100, yidler_mount_width, 100], align=Z);

            hull()
            {
                for(y=[-1,1])
                ty(y*yaxis_idler_tightscrew_dist)
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                {
                    translate([yaxis_idler_mount_thickness/2,0,yaxis_belt_path_offset_z])
                    rcylindera(
                        h=extrusion_size+yaxis_idler_mount_thickness,
                        d=tighten_screw_dia_outer,
                        align=N,
                        orient=X
                        );
                    rcubea(
                        size=[extrusion_size, mount_screw_dist-yaxis_idler_mount_tightscrew_dia*3, yaxis_idler_mount_thickness],
                        align=Z,
                        extra_size=[yaxis_idler_mount_thickness,0,0],
                        extra_align=X
                        );
                }

                // adjustment screw
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                t(yaxis_idler_mount_adjustscrew_offset)
                rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*2, orient=X, align=X);

                // adjustment screw
                tx(-yaxis_idler_mount_thickness)
                tz(extrusion_size/2)
                t([yaxis_idler_mount_thickness/2,0,yaxis_belt_path_offset_z])
                t(yaxis_idler_mount_adjustscrew_offset)
                rcylindera(
                    h=extrusion_size+yaxis_idler_mount_thickness,
                    d=yaxis_idler_mount_adjustscrew_hexnut_dia*sqrt(2),
                    align=N,
                    orient=X
                    );
                /*rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*2, orient=X, align=X);*/
            }

        }

    }
    else if(part=="neg")
    {
        // top/vertical mount screws (to extrusion)
        tz(extrusion_size/2+yaxis_idler_mount_thickness)
        for(y=[-1,1])
        ty(y*mount_screw_dist/2)
        screw_cut(nut=extrusion_nut, head="button", h=yaxis_idler_mount_thickness+5*mm, with_nut=false, orient=-Z, align=-Z);

        // mount screws for pulley block
        for(y=[-1,1])
        tx(-extrusion_size/2-yaxis_idler_mount_thickness)
        ty(y*yaxis_idler_tightscrew_dist)
        tz(extrusion_size/2+yaxis_belt_path_offset_z)
        screw_cut(yaxis_idler_mount_tightscrew_hexnut, head_embed=false, h=extrusion_size+yaxis_idler_mount_thickness+10*mm, with_nut=false, orient=X, align=X);

        // pulley block adjustment screw
        tx(-extrusion_size/2)
        tx(-yaxis_idler_mount_thickness)
        tz(extrusion_size/2+yaxis_belt_path_offset_z)
        t(yaxis_idler_mount_adjustscrew_offset)
        screw_cut(yaxis_idler_mount_adjustscrew_hexnut, head="button", h=extrusion_size+yaxis_idler_mount_thickness+10*mm, head_embed=false, with_nut=false, orient=X, align=X);

        // front/horizontal mount screws (to extrusion)
        tx(-extrusion_size/2)
        tx(-yaxis_idler_mount_thickness)
        for(y=[-1,1])
        ty(y*(yaxis_idler_mount_thread_dia*2.5))
        screw_cut(nut=extrusion_nut, head="button", h=yaxis_idler_mount_thickness+5*mm, with_nut=false, orient=X, align=X);
    }
}

module yaxis_idler_pulleyblock(part, show_pulley=false)
{
    h = yaxis_idler_pulley_h + 3*mm*2;
    d=yaxis_idler_mount_tightscrew_hexnut_dia*2;

    if(part==U)
    {
        difference()
        {
            yaxis_idler_pulleyblock(part="pos");
            yaxis_idler_pulleyblock(part="neg");
        }
        %yaxis_idler_pulleyblock(part="vit");
    }
    else if(part=="pos")
    material(Mat_Plastic)
    {
        hull()
        {
            // idler
            tz(h/2)
            rcylindera(d=yaxis_idler_pulley_thread_dia+15*mm, h=h, orient=-Z, align=-Z);

            // tension screws
            tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
            for(y=[-1,1])
            ty(y*yaxis_idler_tightscrew_dist)
            rcubea([d,d,yaxis_idler_pulley_tight_len], orient=X, align=X);

            // adjustment screw
            tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
            t(yaxis_idler_mount_adjustscrew_offset)
            rcylindera(d=yaxis_idler_mount_adjustscrew_hexnut_dia*sqrt(2), orient=X, align=X);
        }
    }
    else if(part=="neg")
    {
        // pulley cutout
        tx(-3*mm)
        cubea(
            size=[yaxis_idler_pulley_outer_d, yaxis_idler_pulley_outer_d*3, yaxis_idler_pulley_h+0.5],
            align=N,
            extra_size=[20*mm,0,0], extra_align=X
            );

        // pulley screw
        tz(h/2)
        screw_cut(yaxis_idler_pulley_nut, head="button", h=h+5*mm, orient=-Z, align=-Z);

        // tension screws
        for(y=[-1,1])
        tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
        ty(y*yaxis_idler_tightscrew_dist)
        screw_cut(yaxis_idler_mount_tightscrew_hexnut, head_embed=false, nut_offset=2*mm, h=yaxis_idler_pulley_tight_len, orient=X, align=X);

        // adjustment screw
        tx(-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len)
        tx(yaxis_idler_pulley_tight_len/2)
        t(yaxis_idler_mount_adjustscrew_offset)
        nut_trap_cut(nut=yaxis_idler_mount_adjustscrew_hexnut, head="button", cut_screw=true, screw_l=7*mm, trap_axis=-Z, orient=-X);
    }
    else if(part=="vit")
    {
        pulley(pulley_2GT_20T_idler);
    }

}

module part_y_idler()
{
    attach([N, -Z], yaxis_idler_conn)
    {
        yaxis_idler();
    }
}

module part_y_idler_pulleyblock()
{
    attach([N, -X], yaxis_idler_pulleyblock_conn_print)
    {
        yaxis_idler_pulleyblock(show_pulley=false);
    }
}

/*yaxis_idler();*/
/*yaxis_idler_pulleyblock();*/

/*attach([N,-X], yaxis_idler_conn)*/
/*{*/
    /*yaxis_idler();*/
    /*attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)*/
    /*{*/
        /*yaxis_idler_pulleyblock(show_pulley=true);*/
    /*}*/
/*}*/