main: fix range/position of T0/T1

main: fix range/position of T0/T1

include <config.scad>

include <thing_libutils/system.scad>
include <thing_libutils/units.scad>
include <thing_libutils/materials.scad>

use <thing_libutils/screws.scad>
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/transforms.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/linear-extrusion.scad>;
use <thing_libutils/timing-belts.scad>;

use <x-end.scad>
include <x-end.h>

use <x-carriage.scad>
include <x-carriage.h>

use <y-carriage.scad>
include <y-carriage.h>

use <y-motor-mount.scad>
include <y-motor-mount.h>

use <y-carriage-bearing-mount.scad>
include <y-carriage-bearing-mount.h>

use <y-carriage-belt-clamp.scad>
include <y-carriage-belt-clamp.h>

use <y-idler.scad>
include <y-idler.h>

use <z-motor-mount.scad>
include <z-motor-mount.h>

use <gantry-upper-connector.scad>
use <gantry-lower-connector.scad>

use <rod-clamps.scad>
include <rod-clamps.h>

use <printbed.scad>
include <printbed.h>

/*use <psu.scad>*/
/*include <psu.h>*/

/*use <lcd2004.scad>*/
/*use <power-panel-iec320.scad>*/

// x carriage
axis_range_x_ = main_width/2 - extrusion_size - x_carriage_w/2 + 20;
axis_range_x = [-1,1] *  axis_range_x_;
axis_printrange_x = [-1, 1] * (printbed_size[0]/2+extruder_b_hotend_mount_offset.x);
axis_x_pos_relative=[1,0];
axis_x_parked = [false, true];

axis_range_y=[0*mm,200*mm];
axis_pos_y = -axis_range_y[0]/2-30*mm;
axis_range_z=[-extruder_offset.z-extruder_offset_b.z-extruder_b_hotend_mount_offset.z+hotend_height+yaxis_carriage_offset.z+yaxis_carriage_bearing_mount_conn_bearing[0].z+yaxis_carriage_printbed_offset.z+printbed_size.z,353*mm];
axis_pos_z = axis_range_z[0];

echo(str("Axis range X: " , axis_range_x[0], " ", axis_range_x[1]," mm"));
echo(str("Axis range Y: " , axis_range_y[0], " ", axis_range_y[1]," mm"));
echo(str("Axis range Z: " , axis_range_z[0], " ", axis_range_z[1]," mm"));

echo(str("Build area Z: " , axis_range_z[1]-axis_range_z[0] , " mm"));

home_offset_x0 = axis_range_x[0] - axis_printrange_x[0] + v_x(extruder_b_filapath_offset)[0];
echo(str("Home offset X0: " , home_offset_x0));
echo(str("Tool offset X: " , axis_range_x_+x_carriage_w/2));

module x_axis()
{
    // x axis
    tz(axis_pos_z)
    {
        zrod_offset = zmotor_mount_rod_offset_x;
        for(z=xaxis_beltpath_z_offsets)
        tz(z)
        ty(xaxis_zaxis_distance_y)
        tx(-sign(z)*(-main_width/2-zrod_offset+xaxis_end_motor_offset[0]))
        rotate(90*X)
        belt_path(
            len=main_width+xaxis_end_motor_offset[0],
            belt_width=xaxis_belt_width,
            belt=xaxis_belt,
            pulley_d=xaxis_pulley_inner_d,
            orient=X, align=-sign(z)*X);

        for(x=[0:len(axis_range_x)-1])
        {
            /*#cubea(size=[x_carriage_w,10,100]);*/

            pos = axis_x_parked[x] ? axis_range_x[x] : (axis_printrange_x[x]+axis_x_pos_relative[x]*printbed_size[0]);
            echo("x carriage", x, pos);

            tx(pos)
            mirror([x==0?0:1,0,0])
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],N])
            {
                x_carriage_withmounts($show_vit=true, beltpath_sign=x==0?-1:1, with_sensormount=x==0);

                x_carriage_extruder($show_vit=true);
            }
        }

        // x smooth rods
        for(z=[-1,1])
        translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
        material(Mat_Chrome)
        cylindera(h=xaxis_rod_l,d=xaxis_rod_d+.1, orient=X);

        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_motor=true, show_nut=true);

            xaxis_end_bucket();
        }
    }
}

module y_axis()
{
    // y axis
    attach([[yaxis_belt_path_offset_x,main_depth/2+extrusion_size,yaxis_motor_offset_z], Y], yaxis_motor_mount_conn)
    yaxis_motor_mount();

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        yaxis_idler();

        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        yaxis_idler_pulleyblock(show_pulley=true);
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    translate([0,main_depth/2+extrusion_size+yaxis_motor_offset_x,0])
    rotate(90*Y)
    belt_path(
        len=main_depth+yaxis_motor_offset_x-yaxis_idler_pulley_offset_y+extrusion_size,
        belt_width=yaxis_belt_width,
        pulley_d=yaxis_pulley_inner_d,
        belt=yaxis_belt,
        align=-Y, orient=Y);

    translate([0,-axis_pos_y,get(LinearBearingInnerDiameter, yaxis_bearing)/2])
    attach(yaxis_carriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    yaxis_belt_holder();

    t(yaxis_carriage_offset)
    {
        // y smooth rod clamps to frame
        for(x=[-1,1])
        for(y=[-1,1])
        attach([[x*(yaxis_rod_distance/2),y*(main_depth/2+extrusion_size/2),0],Z],mount_rod_clamp_conn_rod)
        mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=extrusion_thread, orient=Y);

        for(x=[-1,1])
        translate([x*(yaxis_rod_distance/2), 0, 0])
        {
            // y smooth rods
            material(Mat_Chrome)
            cylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=Y);

            // y bearing mounts
            for(y=[-1,1])
            attach([[0,y*(yaxis_bearing_distance_y/2)-axis_pos_y,0],-Z], yaxis_carriage_bearing_mount_conn_bearing)
            {
                yaxis_carriage_bearing_mount();
            }
        }

        attach(yaxis_carriage_bearing_mount_conn_bearing, [Y*axis_pos_y,Z])
        {
            yaxis_carriage();

            t(yaxis_carriage_printbed_offset)
            printbed(align=Z);
        }
    }

}

module z_axis()
{
    // z axis
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        mirror([x==-1?1:0,0,0])
        translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
        mount_rod_clamp_half(
            rod_d=zaxis_rod_d,
            screw_dist=zmotor_mount_clamp_dist,
            thick=5,
            base_thick=5,
            width=zmotor_mount_thickness_h,
            thread=zmotor_mount_clamp_thread);

        tx(x*(main_width/2))
        {
            tz(zaxis_motor_offset_z)
            mirror([x==-1?1:0,0,0])
            {
                zaxis_motor_mount();

                tx(zmotor_mount_rod_offset_x)
                tz(zmotor_mount_thickness_h/2)
                mount_rod_clamp_half(
                    rod_d=zaxis_rod_d,
                    screw_dist=zmotor_mount_clamp_dist,
                    thick=5,
                    base_thick=5,
                    width=zmotor_mount_thickness_h,
                    thread=zmotor_mount_clamp_thread);
            }

            // z smooth rods
            tx(x*(zmotor_mount_rod_offset_x))
            tz(zaxis_motor_offset_z-80*mm)
            material(Mat_Chrome)
            cylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=Z);
        }
    }

}

module gantry_upper()
{
    for(y=[-1,1])
    translate([0,y*(main_upper_dist_y/2),0])
    {
        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        linear_extrusion(h=main_height, align=[-x,0,1], orient=Z);

        translate([0, 0, main_height])
        linear_extrusion(h=main_upper_width, align=Z, orient=X);
    }

    // upper gantry connectors
    for(x=[-1,1])
    tx(x*(main_upper_width/2))
    tz(main_height)
    {
        linear_extrusion(h=main_upper_dist_y, align=-x*X+Z, orient=Y);
        mirror([x==1?0:-1,0,0])
        gantry_upper_connector();
    }

}

module gantry_lower()
{
    for(z=[-1,1])
    translate([0,0,z*-main_lower_dist_z/2])
    {
        for(y=[-1,1])
        translate([0, y*(main_depth/2), 0])
        linear_extrusion(h=main_width, align=[0,y,-1], orient=X);

        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        linear_extrusion(h=main_depth, align=-x*X-Z, orient=Y);
    }

    // lower gantry connectors
    for(x=[-1,1])
    for(y=[-1,1])
    translate([x*(main_width/2),y*(main_depth/2),-extrusion_size/2])
    mirror([x==1?0:-1,0,0])
    mirror([0,y==1?1:0,0])
    gantry_lower_connector();

}

module enclosure()
{
    // inner
    w=56*cm;
    h=56*cm;
    d=58*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2+wallthick])
    {
        // left/right walls
        for(x=[-1,1])
        translate([x*w/2,0,0])
        cubea([wallthick,d,h], align=[x, 0, 0]);

        // back plate
        translate([0,d/2,0])
        cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(z=[-1,1])
        translate([0,0,z*h/2])
        cubea([w+wallthick*2,d,wallthick], align=[0,0, z]);
    }
}

module main()
{
    render();
    translate([0,0,-main_lower_dist_z/2])
    gantry_lower();

    render();
    translate(-zaxis_rod_offset)
    gantry_upper();

    render();
    x_axis();

    render();
    y_axis();

    render();
    z_axis();

    render();
    translate([-75*mm,0,0])
    translate([0,main_depth/2,0])
    translate([0,extrusion_size,0])
    translate([0,0,-main_lower_dist_z/2-extrusion_size/2])
    power_panel_iec320(orient=[0,-1,0], align=Y);

    if(!$preview_mode)
    {
        render();
        translate([0,-main_depth/2,0])
        translate([0,-extrusion_size/2,0])
        translate([0,0,-main_lower_dist_z/2])
        mount_lcd2004(show_gantry=true);

        for(x=[-1,1])
        translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
        translate([-x*psu_a_w/2, -psu_a_d/2, psu_a_h/2])
        {
            render();
            psu_a();

            render();
            mirror([x==-1?1:0,0,0])
            translate([0, -psu_a_screw_dist_y/2, 0])
            psu_a_extrusion_bracket_side();

            render();
            translate([0, psu_a_screw_dist_y/2, 0])
            psu_a_extrusion_bracket_back();
        }

        render();
        translate([0,-main_depth/2,-main_lower_dist_z-extrusion_size])
        translate([-100,100,0])
        rotate([0,0,270])
        import("stl/RAMPS1_4.STL");
    }
}

feet_height = 8*mm;
translate([0, 0, main_lower_dist_z+extrusion_size*2+feet_height])
main();

/*psu();*/

/*%enclosure();*/

include <config.scad>

include <thing_libutils/system.scad>
include <thing_libutils/units.scad>
include <thing_libutils/materials.scad>

use <thing_libutils/screws.scad>
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/transforms.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/linear-extrusion.scad>;
use <thing_libutils/timing-belts.scad>;

use <x-end.scad>
include <x-end.h>

use <x-carriage.scad>
include <x-carriage.h>

use <y-carriage.scad>
include <y-carriage.h>

use <y-motor-mount.scad>
include <y-motor-mount.h>

use <y-carriage-bearing-mount.scad>
include <y-carriage-bearing-mount.h>

use <y-carriage-belt-clamp.scad>
include <y-carriage-belt-clamp.h>

use <y-idler.scad>
include <y-idler.h>

use <z-motor-mount.scad>
include <z-motor-mount.h>

use <gantry-upper-connector.scad>
use <gantry-lower-connector.scad>

use <rod-clamps.scad>
include <rod-clamps.h>

use <printbed.scad>
include <printbed.h>

/*use <psu.scad>*/
/*include <psu.h>*/

/*use <lcd2004.scad>*/
/*use <power-panel-iec320.scad>*/

// x carriage
axis_range_x_ = main_width/2 - extrusion_size - zaxis_rod_d/2 - xaxis_end_width_right(true) - x_carriage_w/2;
axis_range_x = [-1,1] *  axis_range_x_;
axis_printrange_x = [-1, 1] * (printbed_size[0]/2-extruder_b_hotend_mount_offset.x);
axis_x_parked = [false, false];

axis_range_y=[0*mm,200*mm];
axis_pos_y = -axis_range_y[0]/2-30*mm;
axis_range_z=[-extruder_offset.z-extruder_offset_b.z-extruder_b_hotend_mount_offset.z+hotend_height+yaxis_carriage_offset.z+yaxis_carriage_bearing_mount_conn_bearing[0].z+yaxis_carriage_printbed_offset.z+printbed_size.z,353*mm];
axis_pos_z = axis_range_z[0];

echo(str("Axis range X: " , axis_range_x[0], " ", axis_range_x[1]," mm"));
echo(str("Axis range Y: " , axis_range_y[0], " ", axis_range_y[1]," mm"));
echo(str("Axis range Z: " , axis_range_z[0], " ", axis_range_z[1]," mm"));

echo(str("Build area Z: " , axis_range_z[1]-axis_range_z[0] , " mm"));

home_offset_x0 = axis_range_x[0] - axis_printrange_x[0] + v_x(extruder_b_filapath_offset)[0];
echo(str("Home offset X0: " , home_offset_x0));
echo(str("Tool offset X: " , axis_range_x_+x_carriage_w/2));

module x_axis()
{
    // x axis
    tz(axis_pos_z)
    {
        zrod_offset = zmotor_mount_rod_offset_x;
        for(z=xaxis_beltpath_z_offsets)
        tz(z)
        ty(xaxis_zaxis_distance_y)
        tx(-sign(z)*(-main_width/2-zrod_offset+xaxis_end_motor_offset[0]))
        rotate(90*X)
        belt_path(
            len=main_width+xaxis_end_motor_offset[0],
            belt_width=xaxis_belt_width,
            belt=xaxis_belt,
            pulley_d=xaxis_pulley_inner_d,
            orient=X, align=-sign(z)*X);

        for(x=[0:len(axis_range_x)-1])
        {
            /*#cubea(size=[x_carriage_w,10,100]);*/

            pos = axis_x_parked[x] ? axis_range_x[x] : axis_printrange_x[x];

            tx(pos)
            mirror([x==0?0:1,0,0])
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],N])
            {
                x_carriage_withmounts($show_vit=true, beltpath_sign=x==0?-1:1, with_sensormount=x==0);

                x_carriage_extruder($show_vit=true);
            }
        }

        // x smooth rods
        for(z=[-1,1])
        translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
        material(Mat_Chrome)
        cylindera(h=xaxis_rod_l,d=xaxis_rod_d+.1, orient=X);

        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_motor=true, show_nut=true);

            xaxis_end_bucket();
        }
    }
}

module y_axis()
{
    // y axis
    attach([[yaxis_belt_path_offset_x,main_depth/2+extrusion_size,yaxis_motor_offset_z], Y], yaxis_motor_mount_conn)
    yaxis_motor_mount();

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        yaxis_idler();

        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        yaxis_idler_pulleyblock(show_pulley=true);
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    translate([0,main_depth/2+extrusion_size+yaxis_motor_offset_x,0])
    rotate(90*Y)
    belt_path(
        len=main_depth+yaxis_motor_offset_x-yaxis_idler_pulley_offset_y+extrusion_size,
        belt_width=yaxis_belt_width,
        pulley_d=yaxis_pulley_inner_d,
        belt=yaxis_belt,
        align=-Y, orient=Y);

    translate([0,-axis_pos_y,get(LinearBearingInnerDiameter, yaxis_bearing)/2])
    attach(yaxis_carriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    yaxis_belt_holder();

    t(yaxis_carriage_offset)
    {
        // y smooth rod clamps to frame
        for(x=[-1,1])
        for(y=[-1,1])
        attach([[x*(yaxis_rod_distance/2),y*(main_depth/2+extrusion_size/2),0],Z],mount_rod_clamp_conn_rod)
        mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=extrusion_thread, orient=Y);

        for(x=[-1,1])
        translate([x*(yaxis_rod_distance/2), 0, 0])
        {
            // y smooth rods
            material(Mat_Chrome)
            cylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=Y);

            // y bearing mounts
            for(y=[-1,1])
            attach([[0,y*(yaxis_bearing_distance_y/2)-axis_pos_y,0],-Z], yaxis_carriage_bearing_mount_conn_bearing)
            {
                yaxis_carriage_bearing_mount();
            }
        }

        attach(yaxis_carriage_bearing_mount_conn_bearing, [Y*axis_pos_y,Z])
        {
            yaxis_carriage();

            t(yaxis_carriage_printbed_offset)
            printbed(align=Z);
        }
    }

}

module z_axis()
{
    // z axis
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        mirror([x==-1?1:0,0,0])
        translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
        mount_rod_clamp_half(
            rod_d=zaxis_rod_d,
            screw_dist=zmotor_mount_clamp_dist,
            thick=5,
            base_thick=5,
            width=zmotor_mount_thickness_h,
            thread=zmotor_mount_clamp_thread);

        tx(x*(main_width/2))
        {
            tz(zaxis_motor_offset_z)
            mirror([x==-1?1:0,0,0])
            {
                zaxis_motor_mount();

                tx(zmotor_mount_rod_offset_x)
                tz(zmotor_mount_thickness_h/2)
                mount_rod_clamp_half(
                    rod_d=zaxis_rod_d,
                    screw_dist=zmotor_mount_clamp_dist,
                    thick=5,
                    base_thick=5,
                    width=zmotor_mount_thickness_h,
                    thread=zmotor_mount_clamp_thread);
            }

            // z smooth rods
            tx(x*(zmotor_mount_rod_offset_x))
            tz(zaxis_motor_offset_z-80*mm)
            material(Mat_Chrome)
            cylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=Z);
        }
    }

}

module gantry_upper()
{
    for(y=[-1,1])
    translate([0,y*(main_upper_dist_y/2),0])
    {
        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        linear_extrusion(h=main_height, align=[-x,0,1], orient=Z);

        translate([0, 0, main_height])
        linear_extrusion(h=main_upper_width, align=Z, orient=X);
    }

    // upper gantry connectors
    for(x=[-1,1])
    tx(x*(main_upper_width/2))
    tz(main_height)
    {
        linear_extrusion(h=main_upper_dist_y, align=-x*X+Z, orient=Y);
        mirror([x==1?0:-1,0,0])
        gantry_upper_connector();
    }

}

module gantry_lower()
{
    for(z=[-1,1])
    translate([0,0,z*-main_lower_dist_z/2])
    {
        for(y=[-1,1])
        translate([0, y*(main_depth/2), 0])
        linear_extrusion(h=main_width, align=[0,y,-1], orient=X);

        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        linear_extrusion(h=main_depth, align=-x*X-Z, orient=Y);
    }

    // lower gantry connectors
    for(x=[-1,1])
    for(y=[-1,1])
    translate([x*(main_width/2),y*(main_depth/2),-extrusion_size/2])
    mirror([x==1?0:-1,0,0])
    mirror([0,y==1?1:0,0])
    gantry_lower_connector();

}

module enclosure()
{
    // inner
    w=56*cm;
    h=56*cm;
    d=58*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2+wallthick])
    {
        // left/right walls
        for(x=[-1,1])
        translate([x*w/2,0,0])
        cubea([wallthick,d,h], align=[x, 0, 0]);

        // back plate
        translate([0,d/2,0])
        cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(z=[-1,1])
        translate([0,0,z*h/2])
        cubea([w+wallthick*2,d,wallthick], align=[0,0, z]);
    }
}

module main()
{
    render();
    translate([0,0,-main_lower_dist_z/2])
    gantry_lower();

    render();
    translate(-zaxis_rod_offset)
    gantry_upper();

    render();
    x_axis();

    render();
    y_axis();

    render();
    z_axis();

    render();
    translate([-75*mm,0,0])
    translate([0,main_depth/2,0])
    translate([0,extrusion_size,0])
    translate([0,0,-main_lower_dist_z/2-extrusion_size/2])
    power_panel_iec320(orient=[0,-1,0], align=Y);

    if(!$preview_mode)
    {
        render();
        translate([0,-main_depth/2,0])
        translate([0,-extrusion_size/2,0])
        translate([0,0,-main_lower_dist_z/2])
        mount_lcd2004(show_gantry=true);

        for(x=[-1,1])
        translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
        translate([-x*psu_a_w/2, -psu_a_d/2, psu_a_h/2])
        {
            render();
            psu_a();

            render();
            mirror([x==-1?1:0,0,0])
            translate([0, -psu_a_screw_dist_y/2, 0])
            psu_a_extrusion_bracket_side();

            render();
            translate([0, psu_a_screw_dist_y/2, 0])
            psu_a_extrusion_bracket_back();
        }

        render();
        translate([0,-main_depth/2,-main_lower_dist_z-extrusion_size])
        translate([-100,100,0])
        rotate([0,0,270])
        import("stl/RAMPS1_4.STL");
    }
}

feet_height = 8*mm;
translate([0, 0, main_lower_dist_z+extrusion_size*2+feet_height])
main();

/*psu();*/

/*%enclosure();*/


removed dead code + put holes in place of rods - these will be replaced by metal M8 screws, instead

r_mount=(28.8+2*2.1)/2;
h=20;
eps=0.01;

module mount_rod_space()
{
  translate([0, 0, -eps])
    cylinder(r=r_mount, h=h+2*eps, $fn=180);
}

module body_core()
{
  // main rod with mounts
  rotate([0, 0, 180-30])
  {
    difference()
    {
      // main block
      hull()
        for(dx=[0, 90])
          translate([dx, 0, 0])
            cylinder(r=30/2, h=h);
      // support rods
      for(dx=[0, 29.5, 60.5])
        translate([90-dx, 0, -eps])
          cylinder(r=8.5/2, h=30, $fn=50);
    }
  }
  // rod_slot
  difference()
  {
    // main block
    union()
    {
      cylinder(r=30/2, h=h);
      translate([-35, -50, 0])
        cube([50, 50, h]);
      // stubbing hole, between two elements
      translate([-35, 0, 0])
        cube([20, 10, h]);
    }
    // screw hole
    translate([-35-eps, -42, h/2])
      rotate([0, 90, 0])
        cylinder(r=3.5/2, h=50+2*eps, $fn=50);
    // place for bottom block
    translate([-20/2-r_mount, -20-40, -eps])
      cube([r_mount*2, 40, h+2*eps]);
  }
}

module buggy_troley_closure()
{
  dy=30;
  difference()
  {
    cube([r_mount*2, dy, h]);
    translate([r_mount, dy, 0])
      mount_rod_space();
    translate([-eps-10, 8, h/2])
      rotate([0, 90, 0])
        cylinder(r=3.5/2, h=55+2*eps, $fn=50);
  }
}

module buggy_troley_mount()
{
  difference()
  {
    body_core();
    translate([-20/2, -20, 0])
      mount_rod_space();
  }
}

for(pos=[[0,0,0], [180,1,35]])
  translate([pos[2], 0, 0])
    rotate([0, pos[0], 0])
      mirror([0, 0, pos[1]])
      {
        buggy_troley_mount();
        %translate([-20/2-r_mount, -50, 0])
          buggy_troley_closure();

        translate([-75, -30, 0])
          buggy_troley_closure();
      }

r_mount=(28.8+2*2.1)/2;
h=20;
eps=0.01;

module mount_rod_space()
{
  translate([0, 0, -eps])
    cylinder(r=r_mount, h=h+2*eps, $fn=180);
}

module rod_protection()
{
  $fn=50;
  h=15;
  difference()
  {
    cylinder(r=10.5/2, h=h);
    translate([0,0,-eps])
      cylinder(r=8.5/2, h=h+2*eps);
  }
}

module body_core()
{
  // main rod with mounts
  rotate([0, 0, 180-30])
  {
    // main block
    hull()
      for(dx=[0, 90])
        translate([dx, 0, 0])
          cylinder(r=30/2, h=h);
    // support rods
    for(dx=[0, 29.5, 60.5])
      translate([90-dx, 0, h])
        cylinder(r=10.5/2, h=30, $fn=50);
  }
  // rod_slot
  difference()
  {
    // main block
    union()
    {
      cylinder(r=30/2, h=h);
      translate([-35, -50, 0])
        cube([50, 50, h]);
      // stubbing hole, between two elements
      translate([-35, 0, 0])
        cube([20, 10, h]);
    }
    // screw hole
    translate([-35-eps, -42, h/2])
      rotate([0, 90, 0])
        cylinder(r=3.5/2, h=50+2*eps, $fn=50);
    // place for bottom block
    translate([-20/2-r_mount, -20-40, -eps])
      cube([r_mount*2, 40, h+2*eps]);
  }
}

module buggy_troley_closure()
{
  dy=30;
  difference()
  {
    cube([r_mount*2, dy, h]);
    translate([r_mount, dy, 0])
      mount_rod_space();
    translate([-eps-10, 8, h/2])
      rotate([0, 90, 0])
        cylinder(r=3.5/2, h=55+2*eps, $fn=50);
  }
}

module buggy_troley_mount()
{
  difference()
  {
    body_core();
    translate([-20/2, -20, 0])
      mount_rod_space();
  }
}

for(pos=[[0,0,0], [180,1,35]])
  translate([pos[2], 0, 0])
    rotate([0, pos[0], 0])
      mirror([0, 0, pos[1]])
      {
        buggy_troley_mount();
        %translate([-20/2-r_mount, -50, 0])
          buggy_troley_closure();

        translate([-75, -30, 0])
          buggy_troley_closure();
      }

%rod_protection();


element count is now a parameter

element count is now a parameter

eps=0.01;
wall=4;
h=wall+8+5;
$fn=60;
N=4;

module support_()
{
  translate(-wall/2*[0, 1, 0])
  {
    dist=8+wall+(8+2)/2;
    cube([dist, wall, wall]);
    translate([dist-wall, 0, 0])
      cube([wall, wall, wall+8]);
  }
}

module screw_space_()
{
  cylinder(r=(3.5+0.4)/2, h=h+eps);
  translate(-eps*[0,0,1])
    cylinder(r1=(8+0.5)/2, r2=(3.5+0.5)/2, h=4.5+eps);
}

module element()
{
  difference()
  {
    union()
    {
      cylinder(r=(8+2)/2, h=h);
      support_();
    }
    screw_space_();
  }
}

for(i=[1:N])
  translate([0, i*12, 0])
    element();

eps=0.01;
wall=4;
h=wall+8+5;
$fn=60;

module support_()
{
  translate(-wall/2*[0, 1, 0])
  {
    dist=8+wall+(8+2)/2;
    cube([dist, wall, wall]);
    translate([dist-wall, 0, 0])
      cube([wall, wall, wall+8]);
  }
}

module screw_space_()
{
  cylinder(r=(3.5+0.4)/2, h=h+eps);
  translate(-eps*[0,0,1])
    cylinder(r1=(8+0.5)/2, r2=(3.5+0.5)/2, h=4.5+eps);
}

module element()
{
  difference()
  {
    union()
    {
      cylinder(r=(8+2)/2, h=h);
      support_();
    }
    screw_space_();
  }
}

for(i=[0:2])
  translate([0, i*12, 0])
    element();


added explicit function for the participating blocks

$fn=30;

corrners = [ [-1,-1,0], [-1,+1,0], [+1,-1,0], [+1,+1,0] ];

// wall-mounted part
module wall(tr, size)
{
  translate(tr)
    hull()
      difference()
      {
        for(t = corrners)
        {
          off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
            translate(off)
              sphere(size[2]);
        };
        translate([0,0,-size[2]]) cube(2*size, center=true);
      }
}

// water drops catching plane
module plane(tr, size)
{
  rotate([90,0,0])
    translate(tr)
      hull()
        for(t = corrners)
        {
          off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
            translate(off)
              sphere(size[2]);
        };
}

// element for holding a single brush
module holder(tr, size)
{
  translate(tr)
  {
    cube([size[0], 7, size[2]]);
    translate([1.5, 7, size[2]-3])
      rotate([-90,0,0])
      {
        cylinder(r=(8-1.5)/2, h=7+2);
        cylinder(r=(3-1)/2, h=14+2);
      }
  }
}

module brush_holder()
{
  wall([0,0,0], [36,50,2]);
  plane([0,16.5,50/2-2], [36-2*2,29,2]);
  holder([20/2-1,-1,2], [3,25,18]);
  holder([-20/2-1,-1,2], [3,25,18]);
}

brush_holder();

$fn=30;

corrners = [ [-1,-1,0], [-1,+1,0], [+1,-1,0], [+1,+1,0] ];

// wall-mounted part
module wall(tr, size)
{
  translate(tr)
    hull()
      difference()
      {
        for(t = corrners)
        {
          off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
            translate(off)
              sphere(size[2]);
        };
        translate([0,0,-size[2]]) cube(2*size, center=true);
      }
}

// water drops catching plane
module plane(tr, size)
{
  rotate([90,0,0])
    translate(tr)
      hull()
        for(t = corrners)
        {
          off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
            translate(off)
              sphere(size[2]);
        };
}

// element for holding a single brush
module holder(tr, size)
{
  translate(tr)
  {
    cube([size[0], 7, size[2]]);
    translate([1.5, 7, size[2]-3])
      rotate([-90,0,0])
      {
        cylinder(r=(8-1.5)/2, h=7+2);
        cylinder(r=(3-1)/2, h=14+2);
      }
  }
}

wall([0,0,0], [36,50,2]);
plane([0,16.5,50/2-2], [36-2*2,29,2]);
holder([20/2-1,-1,2], [3,25,18]);
holder([-20/2-1,-1,2], [3,25,18]);


More regular layout of sandbox models

More regular layout of sandbox models

/*

	Playground for developing the vitamins/ArduinoPro.scad library

*/

include <../config/config.scad>

// include the ArduinoPro.scad library
include <../vitamins/ArduinoPro.scad>

// Set custom board properties
// ArduinoPro_PCB_Width  =  1.0 * 25.4;
// ArduinoPro_PCB_Length =  1.5 * 25.4;
// ArduinoPro_PCB_Colour = "green";

module ArduinoPro_Layout_Sandbox()
{
    // show pins in layout
    showpins = ArduinoPro_Pins_Normal;

    // how far apart to layout boards
    margin_x = ArduinoPro_PCB_Inset * 2;

    // amount origin is offset in board
    origin_o = ArduinoPro_PCB_Inset;

    // layout offsets to use in translate
    layout_o = origin_o + margin_x;
    layout_x = ArduinoPro_PCB_Width  - origin_o + margin_x;
    layout_y = ArduinoPro_PCB_Length - origin_o + margin_x;

    // Create an Arduino Pro Mini with header pins
    translate([-layout_x, layout_o, 0])
        ArduinoPro(ArduinoPro_Mini, showpins, showpins);

    // Create an Arduino Pro Micro with header pins
    translate([layout_o, layout_o, 0])
        ArduinoPro(ArduinoPro_Micro, showpins);

    // Create an Arduino Pro (common features only, pin mounting reversed)
    translate([-layout_x, -layout_y, 0])
        ArduinoPro(ArduinoPro_No_Port, showpins * ArduinoPro_Pins_Opposite);

    // Create an Arduino Pro Mini without any header pins
    translate([layout_o, -layout_y, 0])
        ArduinoPro(ArduinoPro_Mini);
}

ArduinoPro_Layout_Sandbox();

/*

	Playground for developing the vitamins/ArduinoPro.scad library

*/

include <../config/config.scad>

// include the ArduinoPro.scad library
include <../vitamins/ArduinoPro.scad>

// Set custom board properties
// ArduinoPro_PCB_Width  =  0.7 * 25.4;
// ArduinoPro_PCB_Length =  1.3 * 25.4;
// ArduinoPro_PCB_Colour = [26/255, 90/255, 160/255];

// Create an Arduino Pro Mini with header pins
translate([-ArduinoPro_PCB_Width, 0, 0])
    ArduinoPro(ArduinoPro_Mini, ArduinoPro_Pins_Normal, ArduinoPro_Pins_Normal);

// Create an Arduino Pro Micro with header pins
translate([ArduinoPro_PCB_Width, 0, 0])
    ArduinoPro(ArduinoPro_Micro, ArduinoPro_Pins_Normal);

// Create an Arduino Pro Mini without any header pins
translate([ArduinoPro_PCB_Width, -ArduinoPro_PCB_Length *1.5, 0])
    ArduinoPro(ArduinoPro_Mini);

// Create an Arduino Pro (no programming header, pin mounting reversed)
translate([-ArduinoPro_PCB_Width, -ArduinoPro_PCB_Length *1.5, 0])
    ArduinoPro(ArduinoPro_No_Port, ArduinoPro_Pins_Opposite);


Increase spacing between wheel and support

pot_radius=5.90/2;
meplat = 1.5;
width=12.5;
length = 13.2;
screw_radius = 8.6/2;
pot_length = 12.8;
screw_length = 6.9;
thickness = 3;
axis_radius = 5.5;
spacing = 1.5;

wheel_radius = width/2+thickness+0.5;

module pot(mep){
translate([0,0,-1.5-1]) cube(size=[width, length, 5], center=true);
translate([0,0, -1])cylinder(r= screw_radius, h=screw_length+1);
difference(){
		translate([0,0,screw_length-1]) cylinder(r=pot_radius, h=pot_length+2);
		translate([2*pot_radius-mep,0,50+screw_length]) cube([2*pot_radius	, 100,100], center=true);
}
}

//rotate([0,-90,0])
difference(){
union(){
translate([0,0,-1.5+1]) cube(size=[width+thickness, length+thickness, 5], center=true);
cylinder(r= screw_radius+thickness, h=screw_length);
difference(){
		translate([0,0,screw_length-thickness]) cylinder(r=wheel_radius+spacing+thickness, h=pot_length+thickness);
		translate([50,0,screw_length+(pot_length-thickness)/2]) cube([100, 100,pot_length-thickness], center=true);

		translate([0,0,screw_length]) cylinder(r=wheel_radius+spacing, h=pot_length-thickness);
}
}
pot(0);
	translate([wheel_radius+axis_radius-0.1,0,0]) cylinder(r=axis_radius, h=100, center=true);
}

//Wheel

translate([30,0,0])
difference(){
	translate([0,0, screw_length+1]) cylinder(r=wheel_radius, h=pot_length-5);
pot(meplat);
	}

pot_radius=5.90/2;
meplat = 1.5;
width=12.5;
length = 13.2;
screw_radius = 8.6/2;
pot_length = 12.8;
screw_length = 6.9;
thickness = 3;
axis_radius = 5.5;

wheel_radius = width/2+thickness+0.5;

module pot(mep){
translate([0,0,-1.5-1]) cube(size=[width, length, 5], center=true);
translate([0,0, -1])cylinder(r= screw_radius, h=screw_length+1);
difference(){
		translate([0,0,screw_length-1]) cylinder(r=pot_radius, h=pot_length+2);
		translate([2*pot_radius-mep,0,50+screw_length]) cube([2*pot_radius	, 100,100], center=true);
}
}
//pot(meplat);
difference(){
union(){
translate([0,0,-1.5+1]) cube(size=[width+thickness, length+thickness, 5], center=true);
cylinder(r= screw_radius+thickness, h=screw_length);
difference(){
		translate([0,0,screw_length-thickness]) cylinder(r=wheel_radius+thickness, h=pot_length+thickness);
		translate([50,0,screw_length+(pot_length-thickness)/2]) cube([100, 100,pot_length-thickness], center=true);

		translate([0,0,screw_length]) cylinder(r=wheel_radius+0.5, h=pot_length-thickness);
}
}
pot(0);
	translate([wheel_radius+axis_radius-0.1,0,0]) cylinder(r=axis_radius, h=100, center=true);
}

translate([30,0,0])
difference(){
	translate([0,0, screw_length+1]) cylinder(r=wheel_radius, h=pot_length-5);
pot(meplat);
	}


xaxis/ends: re-enable leadscew support to top

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

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

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

// overlap of the X and Z rods
xaxis_end_xz_rod_overlap = 4*mm;

// how much "stop" for the x rods
xaxis_end_rod_stop = 10*mm;

xaxis_endstop_size = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset = [-1.8*mm, 0*mm, 0*mm];

module xaxis_end_body(with_motor, beltpath_index=0, nut_top=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, 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()
        {
            difference()
            {
                cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1], round_radius=2);
                translate([0,-zaxis_nut[0]/2-1*mm,0])
                cubea([zaxis_nut[4]*2,zaxis_nut[4]+.2,zaxis_nut[4]+.2], align=[0,-1,1]);
            }

            // 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
    xaxis_rod_d_support = xaxis_rod_d+5*mm;
    for(z=[-1,1])
    translate([-xaxis_end_xz_rod_overlap,0,z*(xaxis_rod_distance/2)])
    cylindera(h=wx_+xaxis_end_xz_rod_overlap, d=xaxis_rod_d_support, orient=[1,0,0], align=[1,0,0], round_radius=2);

    translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
    {
        rcubea(xaxis_endstop_size, align=[-1,0,-1]);
    }

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0], round_radius=2);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-1,0,0]);
        }
    }
}

module xaxis_end(with_motor=false, stop_x_rods=false, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = 1;

        hull()
        {
            xaxis_end_body(with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        //endstop mount screw cuts
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        translate(xaxis_endstop_screw_offset)
        for(y=[-1,1])
        translate([-5*mm,y*9.5*mm/2,-2*mm])
        nut_trap_cut(nut=MHexNutM3, screw_l=6*mm, screw_l_extra=0*mm, trap_axis=[-1,0,0], orient=[0,0,1], align=[0,0,-1]);

        xaxis_end_beltpath(height=xaxis_beltpath_height_body);

        // 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(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        with_zips=true,
                        show_zips=false
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

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

        // x smooth rods
        x_rod_stop = stop_x_rods ? xaxis_end_rod_stop : 0;
        for(z=[-1,1])
        translate([-xaxis_end_xz_rod_overlap-.1+x_rod_stop,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_+xaxis_end_xz_rod_overlap-x_rod_stop+.2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

        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);

                // 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]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                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+4*mm), z*screw_dist/2])
                {
                    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*13.5*mm, 0, -zaxis_nut[3]])
                    screw_cut(thread=ThreadM3, h=16*mm, with_nut=false, orient=[0,0,1], align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_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]);
                motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
            }
        }
    }

    //endstop
    %if($show_vit)
    {
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        {
            difference()
            {
                rcubea(xaxis_endstop_size, align=[-1,0,1]);

                translate(xaxis_endstop_screw_offset)
                for(y=[-1,1])
                translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size[2]])
                screw_cut(nut=MHexNutM3, h=10*mm, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
    }

    %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=xaxis_beltpath_width, length = 1000)
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=[1,0,0], roll=-180*min(0,z), truncate=.5);
}

module xaxis_end_idlerholder(part, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    width = 20*mm;

    if(part==undef)
    {
        difference()
        {
            xaxis_end_idlerholder(part="pos", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
            xaxis_end_idlerholder(part="neg", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
        }
    }
    else if(part=="pos")
    {
        hull()
        {
            // support for x smooth rods
            for(z=[-1,1])
            translate([0,0,z*(xaxis_rod_distance/2)])
            cylindera(h=width, d=xaxis_rod_d+4*mm, orient=[1,0,0], align=[1,0,0], round_radius=2);

            // extra support for pulley
            translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
            translate([width/2,0,0])
            cylindera(h=8*mm+pulley_height(xaxis_idler_pulley), d=xaxis_idler_pulley[3], orient=[0,1,0], round_radius=2);
        }
    }
    else if(part=="neg")
    {
        for(z=[-1,1])
        {
            translate([0,0,z*(xaxis_rod_distance/2)])
            {
                // x smooth rods
                translate([width/2+.1,0,0])
                cylindera(h=width/2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

                screw_cut(nut=MHexNutM4, h=16*mm, with_nut=false, orient=[1,0,0], align=[1,0,0]);

                translate([6*mm,0,0])
                nut_trap_cut(nut=MHexNutM4, screw_l=16*mm, trap_axis=[0,-1,0], orient=[1,0,0], $show_vit=false);
            }
        }

        translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([width/2,0,0])
                pulley(xaxis_idler_pulley, orient=[0,1,0]);

            translate([width/2,0,0])
                cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

            xaxis_end_beltpath(height=xaxis_beltpath_height_holders);
        }
    }
    else if(part=="vit")
    {
        %translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        translate([width/2,0,0])
        pulley(xaxis_idler_pulley, orient=[0,1,0]);
    }
}

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]);
    }
}

include <thing_libutils/misc.scad>;
if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-z*3*mm, xaxis_zaxis_distance_y, z])
            belt_path(5*mm+main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[0,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([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);

                translate([x*95, xaxis_zaxis_distance_y, 0])
                mirror([0,0,max(0,x)])
                mirror([max(0,x),0,0])
                xaxis_end_idlerholder();
            }
        }
    }

}

if(false)
{
    zrod_offset = zmotor_mount_rod_offset_x;
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    translate([0,0,xaxis_end_wz/2])
    translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
    belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);

    translate([0, xaxis_zaxis_distance_y, 0])
    {
        for(x=[-1,1])
        translate([x*55,0,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);

        for(x=[-1,1])
        translate([0,0,xaxis_end_wz/2])
        translate([x*45,25,0])
        translate([x*105,0,0])
        mirror([max(0,x),0,0])
        rotate([0,-90,0])
        xaxis_end_idlerholder(beltpath_index=max(0,x));
    }
}

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

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

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

// overlap of the X and Z rods
xaxis_end_xz_rod_overlap = 4*mm;

// how much "stop" for the x rods
xaxis_end_rod_stop = 10*mm;

xaxis_endstop_size = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset = [-1.8*mm, 0*mm, 0*mm];

module xaxis_end_body(with_motor, beltpath_index=0, nut_top=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, 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()
        {
            difference()
            {
                cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1], round_radius=2);
                translate([0,-zaxis_nut[0]/2-1*mm,0])
                cubea([zaxis_nut[4]*2,zaxis_nut[4]+.2,zaxis_nut[4]+.2], align=[0,-1,1]);
            }

            // 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]);*/
        }
    }

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

    translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
    {
        rcubea(xaxis_endstop_size, align=[-1,0,-1]);
    }

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0], round_radius=2);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-1,0,0]);
        }
    }
}

module xaxis_end(with_motor=false, stop_x_rods=false, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = 1;

        hull()
        {
            xaxis_end_body(with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        //endstop mount screw cuts
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        translate(xaxis_endstop_screw_offset)
        for(y=[-1,1])
        translate([-5*mm,y*9.5*mm/2,-2*mm])
        nut_trap_cut(nut=MHexNutM3, screw_l=6*mm, screw_l_extra=0*mm, trap_axis=[-1,0,0], orient=[0,0,1], align=[0,0,-1]);

        xaxis_end_beltpath(height=xaxis_beltpath_height_body);

        // 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(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        with_zips=true,
                        show_zips=false
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

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

        // x smooth rods
        x_rod_stop = stop_x_rods ? xaxis_end_rod_stop : 0;
        for(z=[-1,1])
        translate([-xaxis_end_xz_rod_overlap-.1+x_rod_stop,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_+xaxis_end_xz_rod_overlap-x_rod_stop+.2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

        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);

                // 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]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                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+4*mm), z*screw_dist/2])
                {
                    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*13.5*mm, 0, -zaxis_nut[3]])
                    screw_cut(thread=ThreadM3, h=16*mm, with_nut=false, orient=[0,0,1], align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_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]);
                motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
            }
        }
    }

    //endstop
    %if($show_vit)
    {
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        {
            difference()
            {
                rcubea(xaxis_endstop_size, align=[-1,0,1]);

                translate(xaxis_endstop_screw_offset)
                for(y=[-1,1])
                translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size[2]])
                screw_cut(nut=MHexNutM3, h=10*mm, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
    }

    %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=xaxis_beltpath_width, length = 1000)
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=[1,0,0], roll=-180*min(0,z), truncate=.5);
}

module xaxis_end_idlerholder(part, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    width = 20*mm;

    if(part==undef)
    {
        difference()
        {
            xaxis_end_idlerholder(part="pos", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
            xaxis_end_idlerholder(part="neg", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
        }
    }
    else if(part=="pos")
    {
        hull()
        {
            // support for x smooth rods
            for(z=[-1,1])
            translate([0,0,z*(xaxis_rod_distance/2)])
            cylindera(h=width, d=xaxis_rod_d+4*mm, orient=[1,0,0], align=[1,0,0], round_radius=2);

            // extra support for pulley
            translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
            translate([width/2,0,0])
            cylindera(h=8*mm+pulley_height(xaxis_idler_pulley), d=xaxis_idler_pulley[3], orient=[0,1,0], round_radius=2);
        }
    }
    else if(part=="neg")
    {
        for(z=[-1,1])
        {
            translate([0,0,z*(xaxis_rod_distance/2)])
            {
                // x smooth rods
                translate([width/2+.1,0,0])
                cylindera(h=width/2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

                screw_cut(nut=MHexNutM4, h=16*mm, with_nut=false, orient=[1,0,0], align=[1,0,0]);

                translate([6*mm,0,0])
                nut_trap_cut(nut=MHexNutM4, screw_l=16*mm, trap_axis=[0,-1,0], orient=[1,0,0], $show_vit=false);
            }
        }

        translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([width/2,0,0])
                pulley(xaxis_idler_pulley, orient=[0,1,0]);

            translate([width/2,0,0])
                cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

            xaxis_end_beltpath(height=xaxis_beltpath_height_holders);
        }
    }
    else if(part=="vit")
    {
        %translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        translate([width/2,0,0])
        pulley(xaxis_idler_pulley, orient=[0,1,0]);
    }
}

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]);
    }
}

include <thing_libutils/misc.scad>;
if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-z*3*mm, xaxis_zaxis_distance_y, z])
            belt_path(5*mm+main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[0,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([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);

                translate([x*95, xaxis_zaxis_distance_y, 0])
                mirror([0,0,max(0,x)])
                mirror([max(0,x),0,0])
                xaxis_end_idlerholder();
            }
        }
    }

}

if(false)
{
    zrod_offset = zmotor_mount_rod_offset_x;
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    translate([0,0,xaxis_end_wz/2])
    translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
    belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);

    translate([0, xaxis_zaxis_distance_y, 0])
    {
        for(x=[-1,1])
        translate([x*55,0,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);

        for(x=[-1,1])
        translate([0,0,xaxis_end_wz/2])
        translate([x*45,25,0])
        translate([x*105,0,0])
        mirror([max(0,x),0,0])
        rotate([0,-90,0])
        xaxis_end_idlerholder(beltpath_index=max(0,x));
    }
}


draft for support structure in steel version

// config e
Ay=3.318;
AC=17.5;
Bx=53.83;

loY=-40;  // location of lower brace beams
loX= 20;

$fn=8;

for (a=[-1,1]) {
  %translate([0,0, 80*a]) legProxy();
  %translate([0,0,100*a]) legProxy();
  translate([0,0,90*a]) mainBar();
  translate([Bx*a,0,0]) cylinder(r=2.5,h=300,$fn=16,center=true); // main axle
  translate([-20*a,-40,0]) cube([2.5,2.5,300],center=true); // lower rails

  hull() for (b=[-1,1]) translate([ Bx*b, 0 ,70*a]) sphere(1); // arm guard bar
  hull() for (b=[-1,1]) translate([loX*b,loY,70*a]) sphere(1); // outer foot bar
  for (b=[-1,1]) {
    hull() { // outer diagonal
      translate([ Bx*b, 0 ,70*a]) sphere(1);
      translate([loX*b,loY,70*a]) sphere(1);
    }
    hull() { // inner support on outside trapaoid
      translate([  5*b, 0 ,70*a]) sphere(1);
      translate([loX*b,loY,70*a]) sphere(1);
    }
  }

  hull() { // center front trap
    translate([loX,loY, 2*a]) sphere(1);
    translate([ Bx, 0 ,25*a]) sphere(1);
  }
  hull() { // outer front diag
    translate([loX,loY,68*a]) sphere(1);
    translate([ Bx, 0 ,40*a]) sphere(1);
  }
  hull() { // inner back trap
    translate([-loX,loY,25*a]) sphere(1);
    translate([ -Bx, 0 , 5*a]) sphere(1);
  }
  hull() { // outer back
    translate([-loX,loY,35*a]) sphere(1);
    translate([ -Bx, 0 ,65*a]) sphere(1);
  }

  for (b=[-1,1]) { // outside diagonal brace
    hull() {
      translate([loX*b,loY,140*a]) sphere(1);
      translate([ Bx*b, 0 ,110*a]) sphere(1);
    }
    hull() {
      translate([ Bx*b, 0 ,140*a]) sphere(1);
      translate([loX*b,loY,110*a]) sphere(1);
    }
    hull() {
      translate([loX*b,loY,110*a]) sphere(1);
      translate([ Bx*b, 0 ,110*a]) sphere(1);
    }
  }
  hull() for(b=[-1,1]) translate([loX*b,loY,140*a]) sphere(1);
  hull() for(b=[-1,1]) translate([ Bx*b, 0 ,110*a]) sphere(1);

  hull() { // center foot low diag
    translate([ loX,loY, 5*a]) sphere(1);
    translate([-loX,loY,30*a]) sphere(1);
  }
  hull() {
    translate([-loX,loY,40*a]) sphere(1);
    translate([ loX,loY,70*a]) sphere(1);
  }
  for (b=[-1,1]) hull() {  // outer low X
    translate([-loX*b,loY,130*a]) sphere(1);
    translate([ loX*b,loY, 70*a]) sphere(1);
  }

}

module mainBar() {
  cube([110,5,5],center=true);
  translate([0,Ay,0]) {
    cylinder(r=1.5,h=4,$fn=16,center=true);
    #cylinder(r=AC,h=2,$fn=36,center=true);
    //cylinder(r=AC+2,h=.4,$fn=36,center=true);
  }

}
module legProxy() {

  legProxy1();
  mirror([1,0,0]) legProxy1();

}

// measurements from drawing, center pixel 600,300, 4 pixels/cm
module legProxy1() {

  hull() {
    translate([0,3.32,0]) cylinder(r=17.5+2,h=1,$fn=36,center=true);
    translate([-250/4, 290/4,0]) node();
    translate([-200/4, 290/4,0]) node();
    translate([-360/4, 120/4,0]) node();
    translate([-500/4,-110/4,0]) node();
    translate([-430/4,-230/4,0]) node();
  }
  hull() {
    translate([-400/4,-220/4  ,0]) node();
    translate([-340/4,-370/4+2,0]) node();
    translate([ -90/4,-370/4+2,0]) node();
    translate([-140/4,-120/4  ,0]) node();
  }
}

module node() cylinder(r=2,h=1,$fn=9,center=true);

error: pathspec 'Drawings/steel/walkerChassis.scad' did not match any file(s) known to git


16x2 LED matrix bracket

16x2 LED matrix bracket

/** \file
 * Bracket to hold a 16x2 LED panel in an Octoscroller configuration.
 */

module bracket()
{
	render() difference()
	{
		cube([16,5,10]);

		translate([13,10,5])
		rotate([90,0,0])
		cylinder(r=2, h=20, $fs=1);
	}
}

rotate([0,0,+45/2]) bracket();
rotate([0,0,-45/2-180]) translate([0,-5,0]) bracket();

%translate([0,0,-1]) cube([200,200,2], center=true);

error: pathspec 'matrix-bracket.scad' did not match any file(s) known to git


parameterize the minkowskiSphereRadius value

use <../../../basics/rounded-edges/doughnuts/doughnuts.scad>;

module halfCirclePhoneStand(minkowskiSphereRadius = 0.5)
{

    halfCirclePhoneStand_stand_base(minkowskiSphereRadius = minkowskiSphereRadius);
}

// sub-modules and functions follow

module halfCirclePhoneStand_stand_base(minkowskiSphereRadius)
{
    color("green")
    translate([0, 0, minkowskiSphereRadius])
    roundDoughnut(height = 19.125,
                innerRadius = 4.9,
                outerRadius = 5.59,
                minkowskiSphereRadius = minkowskiSphereRadius);
}

use <../../../basics/rounded-edges/doughnuts/doughnuts.scad>;

module halfCirclePhoneStand()
{

    halfCirclePhoneStand_stand_base();
}

// sub-modules and functions follow

module halfCirclePhoneStand_stand_base()
{
    minkowskiSphereRadius = 0.5;

    color("green")
    translate([0, 0, minkowskiSphereRadius])
    roundDoughnut(height = 19.125,
                innerRadius = 4.9,
                outerRadius = 5.59,
                minkowskiSphereRadius = minkowskiSphereRadius);
}


Further work on box/enclosure design.

Further work on box/enclosure design.

thickness = 0.25;

width = 20;
length = 20;
height = 10;

// width and height of tank base plate
base_width = width/4;
base_height = 1;

// height of side supports
//side_support_height = height/2; // full side walls
side_support_height = 2;

// amount faces extend past each other at corners
overhang = 1;

// for minor corrections
epsilon = 0.01;

vert_faces();
side_supports();
tank_base();

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
			vert_face(x=length);
		}
		side_support_base(clearance=0.1, height_scale=0.5);
		side_support_top(clearance=0.1, height_scale=0.5);
	}
}

module vert_face(x) {
	translate([x-thickness/2,0,0])
		cube([thickness,width,height]);
}

module tank_base(clearance=0) {
	translate([thickness,0,base_height])
	difference() {
		cube([base_width, length, thickness + clearance]);
		tank_base_cutouts(clearance);
		translate([0,length-overhang-thickness/2,0])
			tank_base_cutouts(clearance);
	}
}

module tank_base_cutouts(clearance=0) {
	cube([base_width/8, overhang+thickness/2, thickness+clearance]);
	translate([3*base_width/8,0,0])
		cube([base_width/4, overhang+thickness/2, thickness+clearance]);
	translate([7*base_width/8,0,0])
		cube([base_width/8+epsilon, overhang+thickness/2, thickness+clearance]);
}

module side_supports() {
	difference() {
		union() {
			side_support_base();
			side_support_top();
		}
		vert_faces();
		tank_base(clearance=0.1);
	}
}

module side_support_top(clearance=0, height_scale=1) {
	translate([0,0,height])
	side_support_base(clearance=clearance, height_scale=-height_scale);
}

module side_support_base(clearance=0, height_scale=1) {
	scale([1,1,height_scale])
		union() {
			side_support(y=overhang, clearance=clearance);
			side_support(y=width-overhang, clearance=clearance);
		}
}

module side_support(y, clearance) {
	translate([-overhang,y-thickness/2-clearance/2,0])
		cube([length+overhang*2, thickness+clearance, side_support_height+clearance]);
}

thickness = 0.5;

width = 20;
length = 20;
height = 10;

vert_faces();
side_supports();

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
			vert_face(x=length);
		}
		scale([1,1,0.5]) {
			side_support_base(clearance=0.1);
		}
	}
}

module vert_face(x) {
	translate([x-thickness/2,0,0])
		cube([thickness,width,height]);
}

module side_supports() {
	difference() {
		side_support_base();
		vert_faces();
	}
}

module side_support_base(clearance=0) {
	union() {
		side_support(y=2, clearance=clearance);
		side_support(y=width-2, clearance=clearance);
	}
}

module side_support(y, clearance) {
	overhang = 1;
	height = 2;
	translate([-overhang,y-thickness/2-clearance/2,0])
		cube([length+overhang*2, thickness+clearance, height+clearance]);
}


Note that the belt clamp has been tested working.

// This printed part is one possible way to anchor Shapeoko belts.
// See http://www.shapeoko.com/wiki/index.php/Belt_Anchors for other ideas.
// Motivated by http://www.thingiverse.com/thing:33881 not being strong enough
// when I initially printed it.

// Upright: printed, tested lightly
// Top: printed, tested

gThick = 8;
gRibHeight = 6;
gTopRoundoverRadius = 4;
gSideRoundoverRadius = 4;
gMainWidth = 16;
gMainHeight = 66;

gTopWidth = 30;
gRibWidth = 3.4;
gRibLength = 50;
gHoleSpacing = 20;
gBeltWide = 14; // 1/4" belt + slop
gBeltPitch = 2.032; // MXL in mm
gBeltThick = 1.5;
e = 0.02;

// screw_clearance_diameter, socket_head_clearance_diameter, nut outside diameter
// TODO untested numbers, these should move to a common include.
M3 = [3.8, 6.4, 6.5];
M5 = [5.5, 9.4, 9.4];
M8 = [8, 13, 13];

module InsetHole(x) {
  d = x[0];
  socket_head = x[1];
  union() {
    translate([0,0,-50]) cylinder(r=d/2, h=100);
    cylinder(r=socket_head/2, h=10);
  }
}

module NutHole(x) {
  d = x[0];
  nut_size = x[2];
  union() {
    translate([0,0,1]) cylinder(r=d/2, h=50);
    cylinder(r=nut_size/2, $fn=6, h=6);
  }
}

module Rib(t=4) {
  translate([-t/2,0,-0.1])
    rotate([90,0,90])
      linear_extrude(height=t)
        polygon(points=[[0,0],[gRibLength,0],[0,gRibHeight]],paths=[[0,1,2]]);
}

module Roundover(r) {
  translate([0.1,0.1,-50])
    difference() {
      cube([r,r,100]);
      translate([0,0,-1]) cylinder(r=r,h=102,$fn=20);
    }
}

module Upright() {
  difference() {
    union() {
      // body, for now (until beziers work)
      translate([0,-gMainHeight/2-4.9,(gThick+gRibHeight)/2]) cube([gTopWidth,10,gThick+gRibHeight], center=true);
      translate([0,0,gThick/2]) cube([gMainWidth,gMainHeight,gThick], center=true);
      // ribs
      translate([(gMainWidth-gRibWidth)/2,-gMainHeight/2,gThick]) Rib(t=gRibWidth);
      translate([-(gMainWidth-gRibWidth)/2,-gMainHeight/2,gThick]) Rib(t=gRibWidth);
    }
    // Chamfer top edges
    // TODO make these translation numbers constants as well, and fix Roundover's
    // origin.
    translate([gTopWidth/2-gTopRoundoverRadius,0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,0])
        Roundover(r=gTopRoundoverRadius);
    translate([-(gTopWidth/2-gTopRoundoverRadius),0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,180])
        Roundover(r=gTopRoundoverRadius);
    // Chamfer edges near bottom mounting hole
    translate([gMainWidth/2-gSideRoundoverRadius,gMainHeight/2-4,0])
      Roundover(r=gSideRoundoverRadius);
    translate([-(gMainWidth/2-gSideRoundoverRadius),gMainHeight/2-4,0])
      rotate([0,0,90])
        Roundover(r=gSideRoundoverRadius);
    // M5 mounting holes
    translate([0,gMainHeight/2-30,gThick-2]) InsetHole(M5);
    translate([0,gMainHeight/2-10,gThick-2]) InsetHole(M5);
    // M3 nut traps (20mm spacing, for compat with old part)
    translate([-gHoleSpacing/2,-gMainHeight/2+4,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    translate([gHoleSpacing/2,-gMainHeight/2+4,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
  }
}

module Belt() {
  translate([0,0,gBeltThick/2]) cube([gBeltWide,30,gBeltThick], center=true);
  for(i = [0:30/gBeltPitch]) {
    translate([0,i * gBeltPitch,-gBeltThick/2+e]) cube([gBeltWide,gBeltPitch / 2,gBeltThick], center=true);
  }
}

module Top() {
  rotate([-90,0,0]) difference() {
    translate([0,-6/2,(gThick+gRibHeight)/2]) cube([gTopWidth,6,gThick+gRibHeight], center=true);
    // holes
    translate([-gHoleSpacing/2,20,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    translate([gHoleSpacing/2,20,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    // chamfer
    translate([gTopWidth/2-gTopRoundoverRadius,0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,0])
        Roundover(r=gTopRoundoverRadius);
    translate([-(gTopWidth/2-gTopRoundoverRadius),0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,180])
        Roundover(r=gTopRoundoverRadius);
    // TODO remove magic number
    translate([0,-8+(1.6*gBeltThick),0]) rotate([90,0,0]) Belt();
  }
}

union() {
  Upright();
  translate([0,-gMainHeight/2-12,0]) rotate([0,0,180]) Top();
}

// This printed part is one possible way to anchor Shapeoko belts.
// See http://www.shapeoko.com/wiki/index.php/Belt_Anchors for other ideas.
// Motivated by http://www.thingiverse.com/thing:33881 not being strong enough
// when I initially printed it.

// Upright: printed, but not stress tested, looks sturdy
// Top: completely untested

gThick = 8;
gRibHeight = 6;
gTopRoundoverRadius = 4;
gSideRoundoverRadius = 4;
gMainWidth = 16;
gMainHeight = 66;

gTopWidth = 30;
gRibWidth = 3.4;
gRibLength = 50;
gHoleSpacing = 20;
gBeltWide = 14; // 1/4" belt + slop
gBeltPitch = 2.032; // MXL in mm
gBeltThick = 1.5;
e = 0.02;

// screw_clearance_diameter, socket_head_clearance_diameter, nut outside diameter
// TODO untested numbers, these should move to a common include.
M3 = [3.8, 6.4, 6.5];
M5 = [5.5, 9.4, 9.4];
M8 = [8, 13, 13];

module InsetHole(x) {
  d = x[0];
  socket_head = x[1];
  union() {
    translate([0,0,-50]) cylinder(r=d/2, h=100);
    cylinder(r=socket_head/2, h=10);
  }
}

module NutHole(x) {
  d = x[0];
  nut_size = x[2];
  union() {
    translate([0,0,1]) cylinder(r=d/2, h=50);
    cylinder(r=nut_size/2, $fn=6, h=6);
  }
}

module Rib(t=4) {
  translate([-t/2,0,-0.1])
    rotate([90,0,90])
      linear_extrude(height=t)
        polygon(points=[[0,0],[gRibLength,0],[0,gRibHeight]],paths=[[0,1,2]]);
}

module Roundover(r) {
  translate([0.1,0.1,-50])
    difference() {
      cube([r,r,100]);
      translate([0,0,-1]) cylinder(r=r,h=102,$fn=20);
    }
}

module Upright() {
  difference() {
    union() {
      // body, for now (until beziers work)
      translate([0,-gMainHeight/2-4.9,(gThick+gRibHeight)/2]) cube([gTopWidth,10,gThick+gRibHeight], center=true);
      translate([0,0,gThick/2]) cube([gMainWidth,gMainHeight,gThick], center=true);
      // ribs
      translate([(gMainWidth-gRibWidth)/2,-gMainHeight/2,gThick]) Rib(t=gRibWidth);
      translate([-(gMainWidth-gRibWidth)/2,-gMainHeight/2,gThick]) Rib(t=gRibWidth);
    }
    // Chamfer top edges
    // TODO make these translation numbers constants as well, and fix Roundover's
    // origin.
    translate([gTopWidth/2-gTopRoundoverRadius,0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,0])
        Roundover(r=gTopRoundoverRadius);
    translate([-(gTopWidth/2-gTopRoundoverRadius),0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,180])
        Roundover(r=gTopRoundoverRadius);
    // Chamfer edges near bottom mounting hole
    translate([gMainWidth/2-gSideRoundoverRadius,gMainHeight/2-4,0])
      Roundover(r=gSideRoundoverRadius);
    translate([-(gMainWidth/2-gSideRoundoverRadius),gMainHeight/2-4,0])
      rotate([0,0,90])
        Roundover(r=gSideRoundoverRadius);
    // M5 mounting holes
    translate([0,gMainHeight/2-30,gThick-2]) InsetHole(M5);
    translate([0,gMainHeight/2-10,gThick-2]) InsetHole(M5);
    // M3 nut traps (20mm spacing, for compat with old part)
    translate([-gHoleSpacing/2,-gMainHeight/2+4,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    translate([gHoleSpacing/2,-gMainHeight/2+4,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
  }
}

module Belt() {
  translate([0,0,gBeltThick/2]) cube([gBeltWide,30,gBeltThick], center=true);
  for(i = [0:30/gBeltPitch]) {
    translate([0,i * gBeltPitch,-gBeltThick/2+e]) cube([gBeltWide,gBeltPitch / 2,gBeltThick], center=true);
  }
}

module Top() {
  rotate([-90,0,0]) difference() {
    translate([0,-6/2,(gThick+gRibHeight)/2]) cube([gTopWidth,6,gThick+gRibHeight], center=true);
    // holes
    translate([-gHoleSpacing/2,20,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    translate([gHoleSpacing/2,20,(gThick+gRibHeight)/2]) rotate([90,-90,0]) NutHole(M3);
    // chamfer
    translate([gTopWidth/2-gTopRoundoverRadius,0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,0])
        Roundover(r=gTopRoundoverRadius);
    translate([-(gTopWidth/2-gTopRoundoverRadius),0,gThick+gRibHeight-gTopRoundoverRadius])
      rotate([90,0,180])
        Roundover(r=gTopRoundoverRadius);
    // TODO remove magic number
    translate([0,-8+(1.6*gBeltThick),0]) rotate([90,0,0]) Belt();
  }
}

union() {
  Upright();
  translate([0,-gMainHeight/2-12,0]) rotate([0,0,180]) Top();
}
//union() {
//  for(i=[1:4]) {
//    translate([0,-15*i,0]) Top();
//  }
//}


Change some variable names/comments

Change some variable names/comments

/*
  Vitamin: ArduinoPro
  Model of an Arduino Pro Mini/Micro

  Derived from: https://github.com/sparkfun/Pro_Micro/
           and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

  Authors:
    Jamie Osborne (@jmeosbn)

  Local Frame:
    Point of origin is the centre of the bottom left pin (9)

  Parameters:
    type: can be "mini", or "micro";
          otherwise returns a blank board with header pin holes

  Returns:
    Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro PCB Variables
ArduinoPro_PCB_Pitch  = 2.54;                       // spacing of the holes
ArduinoPro_PCB_Inset  = ArduinoPro_PCB_Pitch/2;     // inset from board edge
ArduinoPro_PCB_Width  =  0.7 * 25.4;                // width of the PCB     (along x)
ArduinoPro_PCB_Length =  1.3 * 25.4;                // length of the PCB    (along y)
ArduinoPro_PCB_Height = .063 * 25.4;                // thickness of the PCB (along z)
ArduinoPro_PCB_Colour = [26/255, 90/255, 160/255];  // colour of solder mask

// Show board clearance area for components
ArduinoPro_PCB_Clearance = 3;
ArduinoPro_PCB_Clearance_Show  = true;

// FIXME: export to external vitamin?
module Micro_USB_Clearance() {
  // Rough dimensions for micro usb header
  height  = 2.7;
  area    = [7.7, 5.2];
  colour  = [220/255, 220/255, 220/255];
  move_x  = ArduinoPro_PCB_Width/2 - ArduinoPro_PCB_Inset;
  move_y  = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch;
  move_z  = ArduinoPro_PCB_Height;

  color(colour)
    translate([move_x, move_y, move_z])
    linear_extrude(height=height)
    square(size = area, center = true);
}

module ArduinoPro_PCB() {
  // Bare PCB, origin through location for bottom left hole
  translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0])
    square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

// TODO: Add throughhole/padding
// TODO: Option to show header pins?
// FIXME: export to external vitamin?
module ArduinoPro_Header_Hole(d = 1.25) {
  // Standard PCB hole
  circle(d = d);
}

module ArduinoPro_Headers() {
  // distance between the two header rows
  rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;
  // length for holes, leaving room for end header and insets
  rowlength = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch - ArduinoPro_PCB_Inset*2;

  // Add headers to either side (along y)
  for (x = [0, rowpitch], y = [0 : ArduinoPro_PCB_Pitch : rowlength]) {
    translate([x, y, 0]) ArduinoPro_Header_Hole();
  }

}

module ArduinoPro_Serial_Header() {
  // y position for header
  header_y = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset*2;
  // width for holes, leaving room for insets
  rowwidth = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;

  // Add serial header along top of board (along x)
  for (x = [ArduinoPro_PCB_Inset : ArduinoPro_PCB_Pitch : rowwidth]) {
    translate([x, header_y, 0]) ArduinoPro_Header_Hole();
  }
}

module ArduinoPro(type = "mini") {
  union() {
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
      // Common Features for Pro Mini/Micro
      ArduinoPro_PCB();
      ArduinoPro_Headers();

      // Features for Pro Mini
      if (type == "mini") {
        // Pro Mini Serial Header
        ArduinoPro_Serial_Header();
      }
    }

    // Features for Pro Micro
    if (type == "micro") {
      // Pro Micro USB port
      Micro_USB_Clearance();
    }

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show)
      color(ArduinoPro_PCB_Colour, 0.1)
      translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, ArduinoPro_PCB_Height])
      linear_extrude(height=ArduinoPro_PCB_Clearance)
      square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
  }
}

// Example Usage
*ArduinoPro("mini");
*ArduinoPro("micro");

/*
  Vitamin: ArduinoPro
  Model of an Arduino Pro Mini/Micro

  Derived from: https://github.com/sparkfun/Pro_Micro/
           and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

  Authors:
    Jamie Osborne (@jmeosbn)

  Local Frame:
    Point of origin is the centre of the bottom left pin (9)

  Parameters:
    type: can be "mini", or "micro";
          otherwise returns a blank board with header pin holes

  Returns:
    Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro PCB Variables
ArduinoPro_Hole_Space = 2.54;                    // spacing of the holes
ArduinoPro_Hole_Inset = ArduinoPro_Hole_Space/2; // Inset from board edge
ArduinoPro_PCB_Height = .063 * 25.4;             // thickness of the PCB
ArduinoPro_PCB_Length =  1.3 * 25.4;             // length of the PCB
ArduinoPro_PCB_Width  =  0.7 * 25.4;             // width of the PCB
ArduinoPro_PCB_Colour = [26/255, 90/255, 160/255];

// Show board clearance area for components
ArduinoPro_PCB_Clearance = 3;
ArduinoPro_PCB_Clearance_Show  = true;

// FIXME: export to external vitamin?
module Micro_USB_Clearance() {
  // Rough dimensions for micro usb header
  height  = 2.7;
  area    = [7.7, 5.2];
  colour  = [220/255, 220/255, 220/255];
  move_x  = ArduinoPro_PCB_Width/2 - ArduinoPro_Hole_Inset;
  move_y  = ArduinoPro_PCB_Length - ArduinoPro_Hole_Space;
  move_z  = ArduinoPro_PCB_Height;

  color(colour)
    translate([move_x, move_y, move_z])
    linear_extrude(height=height)
    square(size = area, center = true);
}

module ArduinoPro_PCB() {
  // Bare PCB, origin at location for bottom left hole
  translate([-ArduinoPro_Hole_Inset, -ArduinoPro_Hole_Inset, 0])
    square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

// TODO: Add throughhole/padding
// TODO: Option to show header pins?
// FIXME: export to external vitamin?
module ArduinoPro_Header_Hole(d = 1.25) {
  // Standard PCB hole
  circle(d = d);
}

module ArduinoPro_Headers() {
  // distance between the two header rows
  rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_Hole_Inset*2;
  // length for holes, leaving room for end header and insets
  rowlength = ArduinoPro_PCB_Length - ArduinoPro_Hole_Space - ArduinoPro_Hole_Inset*2;

  // Add headers to either side (along y)
  for (x = [0, rowpitch], y = [0 : ArduinoPro_Hole_Space : rowlength]) {
    translate([x, y, 0]) ArduinoPro_Header_Hole();
  }

}

module ArduinoPro_Serial_Header() {
  // y position for header
  header_y = ArduinoPro_PCB_Length - ArduinoPro_Hole_Inset*2;
  // width for holes, leaving room for insets
  rowwidth = ArduinoPro_PCB_Width - ArduinoPro_Hole_Inset*2;

  // Add serial header along top of board (along x)
  for (x = [ArduinoPro_Hole_Inset : ArduinoPro_Hole_Space : rowwidth]) {
    translate([x, header_y, 0]) ArduinoPro_Header_Hole();
  }
}

module ArduinoPro(type = "mini") {
  union() {
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
      // Common Features for Pro Mini/Micro
      ArduinoPro_PCB();
      ArduinoPro_Headers();

      // Features for Pro Mini
      if (type == "mini") {
        // Pro Mini Serial Header
        ArduinoPro_Serial_Header();
      }
    }

    // Features for Pro Micro
    if (type == "micro") {
      // Pro Micro USB port
      Micro_USB_Clearance();
    }

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show)
      color(ArduinoPro_PCB_Colour, 0.1)
      translate([-ArduinoPro_Hole_Inset, -ArduinoPro_Hole_Inset, ArduinoPro_PCB_Height])
      linear_extrude(height=ArduinoPro_PCB_Clearance)
      square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
  }
}

// Example Usage
*ArduinoPro("mini");
*ArduinoPro("micro");


Fix place of conges()

Fix place of conges()

$fn=100;
longueur = 150.5;
largeur = 110.5;
hauteur = 42;
rayon = 20;
base_ep = 1.5;
murs_ep = 1.5;

longueur_e = longueur+murs_ep*2;
largeur_e = largeur+murs_ep*2;
rayon_e = rayon + murs_ep;

longueur_c = longueur / 2 - rayon;
largeur_c = largeur / 2 - rayon;

conge = murs_ep * 2;

module quart_tore() {
	rotate_extrude(angle = 90, convexity=10) translate([rayon, 0, 0])
	    difference() {
		translate([-conge/2, conge/2, 0]) square([conge, conge], center=true);
		translate([-conge, conge, 0]) circle(r=conge, $fn=500);
	    };
}

module quart_rond(l) {
	difference() {
		translate([-conge/2, -conge/2, 0]) cube([conge, conge, l], center=true);
		translate([-conge, -conge, 0]) cylinder(r=conge, h=l, center=true, $fn=500);
	}
}

module quart_tube() {
	intersection() {
		difference() {
			cylinder(r = rayon_e, h = hauteur, center=true, $fn = 500);
			cylinder(r = rayon - 0.001, h = hauteur, center=true, $fn = 500);
		};
		translate([rayon_e/2, rayon_e/2, 0]) cube([rayon_e, rayon_e, hauteur], center=true);
	};
}

module base () {
	union() {
		difference() {
			cube([longueur_e, largeur_e, base_ep], center = true);
			translate([longueur/2, largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([-longueur/2, largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([-longueur/2, -largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([longueur/2, -largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
		} ;
		translate([longueur_c, largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([-longueur_c, largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([-longueur_c, -largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([longueur_c, -largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);

	};
}

module murs() {
	translate([0,0,base_ep/2 + hauteur/2]) union() {
		translate([(longueur+murs_ep)/2, 0, 0]) cube([murs_ep + 0.0001, largeur-rayon*2, hauteur], center = true);
		translate([-(longueur+murs_ep)/2, 0, 0]) cube([murs_ep + 0.0001, largeur-rayon*2, hauteur], center = true);
		translate([0, (largeur+murs_ep)/2, 0]) cube([longueur-rayon*2, murs_ep + 0.0001, hauteur], center = true);
		translate([0, -(largeur+murs_ep)/2, 0]) cube([longueur-rayon*2, murs_ep + 0.0001, hauteur], center = true);
		translate([longueur_c, largeur_c, 0]) quart_tube();
		translate([-longueur_c, largeur_c, 0]) rotate([0,0,90]) quart_tube();
		translate([-longueur_c, -largeur_c, 0]) rotate([0,0,180]) quart_tube();
		translate([longueur_c, -largeur_c, 0]) rotate([0,0,-90]) quart_tube();
	};
}

module conges() {
	translate([0,0,base_ep/2]) union() {
		translate([longueur/2, 0, 0]) rotate([90,90,0]) quart_rond(largeur-rayon*2);
		translate([-longueur/2, 0, 0]) rotate([-90,90,0]) quart_rond(largeur-rayon*2);
		translate([0, largeur/2, 0]) rotate([0,90,0]) quart_rond(longueur-rayon*2);
		translate([0, -largeur/2, 0]) rotate([90,90,-90]) quart_rond(longueur-rayon*2);
		translate([longueur_c, largeur_c, 0]) quart_tore();
		translate([-longueur_c, largeur_c, 0]) rotate([0,0,90]) quart_tore();
		translate([-longueur_c, -largeur_c, 0]) rotate([0,0,180]) quart_tore();
		translate([longueur_c, -largeur_c, 0]) rotate([0,0,-90]) quart_tore();
	};
}

module all() {
	union() {
		base();
		murs();
		conges();

	};
}

all();

// difference() {
// 	all ();
// 	cube([longueur+10, largeur+10, (hauteur-5) * 2], center=true);
// }
// projection(cut=true) translate([0,0, -(base_ep+conge+0.1)]) all();
// projection(cut=true) rotate([90, 0, 0]) all();

$fn=100;
longueur = 150.5;
largeur = 110.5;
hauteur = 42;
rayon = 20;
base_ep = 1.5;
murs_ep = 1.5;

longueur_e = longueur+murs_ep*2;
largeur_e = largeur+murs_ep*2;
rayon_e = rayon + murs_ep;

longueur_c = longueur / 2 - rayon;
largeur_c = largeur / 2 - rayon;

conge = murs_ep * 2;

module quart_tore() {
	rotate_extrude(angle = 90, convexity=10) translate([rayon, 0, 0])
	    difference() {
		translate([-conge/2, conge/2, 0]) square([conge, conge], center=true);
		translate([-conge, conge, 0]) circle(r=conge, $fn=500);
	    };
}

module quart_rond(l) {
	difference() {
		translate([-conge/2, -conge/2, 0]) cube([conge, conge, l], center=true);
		translate([-conge, -conge, 0]) cylinder(r=conge, h=l, center=true, $fn=500);
	}
}

module quart_tube() {
	intersection() {
		difference() {
			cylinder(r = rayon_e, h = hauteur, center=true, $fn = 500);
			cylinder(r = rayon - 0.001, h = hauteur, center=true, $fn = 500);
		};
		translate([rayon_e/2, rayon_e/2, 0]) cube([rayon_e, rayon_e, hauteur], center=true);
	};
}

module base () {
	union() {
		difference() {
			cube([longueur_e, largeur_e, base_ep], center = true);
			translate([longueur/2, largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([-longueur/2, largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([-longueur/2, -largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
			translate([longueur/2, -largeur/2, 0]) cube([rayon*2, rayon*2, base_ep], center = true);
		} ;
		translate([longueur_c, largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([-longueur_c, largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([-longueur_c, -largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);
		translate([longueur_c, -largeur_c, 0]) cylinder(r = (rayon+murs_ep), h = base_ep, center = true, $fn = 500);

	};
}

module murs() {
	translate([0,0,base_ep/2 + hauteur/2]) union() {
		translate([(longueur+murs_ep)/2, 0, 0]) cube([murs_ep + 0.0001, largeur-rayon*2, hauteur], center = true);
		translate([-(longueur+murs_ep)/2, 0, 0]) cube([murs_ep + 0.0001, largeur-rayon*2, hauteur], center = true);
		translate([0, (largeur+murs_ep)/2, 0]) cube([longueur-rayon*2, murs_ep + 0.0001, hauteur], center = true);
		translate([0, -(largeur+murs_ep)/2, 0]) cube([longueur-rayon*2, murs_ep + 0.0001, hauteur], center = true);
		translate([longueur_c, largeur_c, 0]) quart_tube();
		translate([-longueur_c, largeur_c, 0]) rotate([0,0,90]) quart_tube();
		translate([-longueur_c, -largeur_c, 0]) rotate([0,0,180]) quart_tube();
		translate([longueur_c, -largeur_c, 0]) rotate([0,0,-90]) quart_tube();
	};
}

module conges() {
	translate([0,0,base_ep]) union() {
		translate([longueur/2, 0, 0]) rotate([90,90,0]) quart_rond(largeur-rayon*2);
		translate([-longueur/2, 0, 0]) rotate([-90,90,0]) quart_rond(largeur-rayon*2);
		translate([0, largeur/2, 0]) rotate([0,90,0]) quart_rond(longueur-rayon*2);
		translate([0, -largeur/2, 0]) rotate([90,90,-90]) quart_rond(longueur-rayon*2);
		translate([longueur_c, largeur_c, 0]) quart_tore();
		translate([-longueur_c, largeur_c, 0]) rotate([0,0,90]) quart_tore();
		translate([-longueur_c, -largeur_c, 0]) rotate([0,0,180]) quart_tore();
		translate([longueur_c, -largeur_c, 0]) rotate([0,0,-90]) quart_tore();
	};
}

module all() {
	union() {
		base();
		murs();
		conges();

	};
}

all();

// difference() {
// 	all ();
// 	cube([longueur+10, largeur+10, (hauteur-5) * 2], center=true);
// }
// projection(cut=true) translate([0,0, -(base_ep+conge+0.1)]) all();


added test sample

added test sample

$fn = 100;
eps = 0.01;

module tester()
{
  module rise_for(h)
  {
    translate([0, 0, 11-h+eps])
      children();
  }
  module up()
  {
    translate([0, 9, 0])
      children();
  }
  module right()
  {
    translate([9, 0, 0])
      children();
  }
  module pair(d, h)
  {
    right()
    {
      rise_for(h)
      {
        cylinder(d=d, h=h);
        up()
          cylinder(d=d, h=h+10);
      }
      children();
    }
  }

  difference()
  {
    cube([37, 20, 11]);
    translate([-3, 5, 0])
    {
      pair(d=6.4, h=10.5)      // M5x9.5
        pair(d=6.4, h=6.8)     // M5x5.8
          pair(d=4.0, h=6.7)   // M3x5.7
            pair(d=4.0, h=4.0) // M3x3.0
        ;
    }
  }
}

tester();