bigger rudders

bigger rudders

/* Machine */
MACHINE_TOLERANCE = 0; //For the JAS laser at Maker Space
/* MACHINE_TOLERANCE = 0.1; //For most other lasers */

/* Material */
MATERIAL_THICKNESS = 3;
HALF_MATERIAL_THICKNESS = MATERIAL_THICKNESS / 2;

/* General */
CORNER = 1;
HALF_CORNER = CORNER / 2;
SPACER_TAB_WIDTH_FACTOR = 0.35;

/* Base plate */
BASE_DIMENSIONS = [180, 240];
BASE_FRONT_CORNER_RADIUS = BASE_DIMENSIONS[0] / 2;
BASE_REAR_CORNER_RADIUS = 30;

/* Lift fan duct mount */
LIFT_FAN_DUCT_DIMENSIONS = [71, 28]; // [diameter, length]
LIFT_FAN_DUCT_MOUNT_PADDING = 30;
LIFT_FAN_DUCT_POSITION = [0, (BASE_DIMENSIONS[1] / 2) - LIFT_FAN_DUCT_DIMENSIONS[0]];
LIFT_FAN_DUCT_MOUNT_SPACING = 18;
LIFT_FAN_DUCT_MOUNT_SEP_WIDTH = 14;

/* Thrust fan duct mount */
THRUST_FAN_DUCT_DIMENSIONS = [74.5, 48]; // [diameter, length]
THRUST_FAN_DUCT_HEIGHT = 60;
THRUST_FAN_DUCT_MOUNT_PADDING = 30;
THRUST_FAN_DUCT_MOUNT_POSITION = [0, -40];
THRUST_FAN_DUCT_MOUNT_SPACING = THRUST_FAN_DUCT_DIMENSIONS[1] - 8;
THRUST_FAN_DUCT_MOUNT_WIDTH = BASE_DIMENSIONS[0] * 0.8;
THRUST_FAN_DUCT_MOUNT_SEP_WIDTH = 14;
THRUST_FAN_DUCT_MOUNT_TAB_POSITIONS = [-THRUST_FAN_DUCT_MOUNT_WIDTH * 0.4, 0, THRUST_FAN_DUCT_MOUNT_WIDTH * 0.4];
THRUST_FAN_DUCT_MOUNT_TAB_WIDTH = 10;
THRUST_FAN_DUCT_MOUNT_BRACE_DIM = [25, THRUST_FAN_DUCT_HEIGHT * 0.95];
THRUST_FAN_DUCT_MOUNT_BRACE_SPACING = THRUST_FAN_DUCT_MOUNT_WIDTH * 0.7;
THRUST_FAN_DUCT_MOUNT_BRACE_TOP_TAB_WIDTH = 10;
THRUST_FAN_DUCT_MOUNT_BRACE_TOP_TAB_POS = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[1] * 0.8;
THRUST_FAN_DUCT_MOUNT_BRACE_BOTTOM_TAB_WIDTH = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[0] * 0.75;
THRUST_FAN_DUCT_MOUNT_BRACE_BOTTOM_TAB_POS = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[0] * 0.5;

/* Rudder */
RUDDER_DIMENSIONS = [40, THRUST_FAN_DUCT_DIMENSIONS[0] * 0.9];
RUDDER_CORNER_RADIUS = 2;
RUDDER_PIVOT_LENGTH = 10;
RUDDER_SPACING = THRUST_FAN_DUCT_DIMENSIONS[0] * 0.6;
RUDDER_ARM_HOLE_POSITION = [-4, -RUDDER_DIMENSIONS[1] * 0.45];
RUDDER_ARM_HOLE_DIAM = 2;

/* Rudder mount */
RUDDER_MOUNT_DIMENSIONS = [THRUST_FAN_DUCT_DIMENSIONS[0] * 0.8, 10];
RUDDER_MOUNT_CORNER_RADIUS = 5;
RUDDER_MOUNT_OFFSET = (RUDDER_DIMENSIONS[1] / 2) + MATERIAL_THICKNESS;
RUDDER_MOUNT_TAB_WIDTH = 5;
RUDDER_MOUNT_TAB_OFFSET = (RUDDER_MOUNT_DIMENSIONS[0] - RUDDER_MOUNT_TAB_WIDTH) / 2;
RUDDER_MOUNT_TAB_LENGTH = MATERIAL_THICKNESS + 6;

/* Skirt clamp */
SKIRT_CLAMP_PADDING = 10;
SKIRT_CLAMP_HOLE_DIAM = 3;

/* Lower skirt mount */
LOWER_SKIRT_MOUNT_SCALE = 0.6;

/* Machine */
MACHINE_TOLERANCE = 0; //For the JAS laser at Maker Space
/* MACHINE_TOLERANCE = 0.1; //For most other lasers */

/* Material */
MATERIAL_THICKNESS = 3;
HALF_MATERIAL_THICKNESS = MATERIAL_THICKNESS / 2;

/* General */
CORNER = 1;
HALF_CORNER = CORNER / 2;
SPACER_TAB_WIDTH_FACTOR = 0.35;

/* Base plate */
BASE_DIMENSIONS = [180, 240];
BASE_FRONT_CORNER_RADIUS = BASE_DIMENSIONS[0] / 2;
BASE_REAR_CORNER_RADIUS = 30;

/* Lift fan duct mount */
LIFT_FAN_DUCT_DIMENSIONS = [71, 28]; // [diameter, length]
LIFT_FAN_DUCT_MOUNT_PADDING = 30;
LIFT_FAN_DUCT_POSITION = [0, (BASE_DIMENSIONS[1] / 2) - LIFT_FAN_DUCT_DIMENSIONS[0]];
LIFT_FAN_DUCT_MOUNT_SPACING = 18;
LIFT_FAN_DUCT_MOUNT_SEP_WIDTH = 14;

/* Thrust fan duct mount */
THRUST_FAN_DUCT_DIMENSIONS = [74.5, 48]; // [diameter, length]
THRUST_FAN_DUCT_HEIGHT = 60;
THRUST_FAN_DUCT_MOUNT_PADDING = 30;
THRUST_FAN_DUCT_MOUNT_POSITION = [0, -40];
THRUST_FAN_DUCT_MOUNT_SPACING = THRUST_FAN_DUCT_DIMENSIONS[1] - 8;
THRUST_FAN_DUCT_MOUNT_WIDTH = BASE_DIMENSIONS[0] * 0.8;
THRUST_FAN_DUCT_MOUNT_SEP_WIDTH = 14;
THRUST_FAN_DUCT_MOUNT_TAB_POSITIONS = [-THRUST_FAN_DUCT_MOUNT_WIDTH * 0.4, 0, THRUST_FAN_DUCT_MOUNT_WIDTH * 0.4];
THRUST_FAN_DUCT_MOUNT_TAB_WIDTH = 10;
THRUST_FAN_DUCT_MOUNT_BRACE_DIM = [25, THRUST_FAN_DUCT_HEIGHT * 0.95];
THRUST_FAN_DUCT_MOUNT_BRACE_SPACING = THRUST_FAN_DUCT_MOUNT_WIDTH * 0.7;
THRUST_FAN_DUCT_MOUNT_BRACE_TOP_TAB_WIDTH = 10;
THRUST_FAN_DUCT_MOUNT_BRACE_TOP_TAB_POS = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[1] * 0.8;
THRUST_FAN_DUCT_MOUNT_BRACE_BOTTOM_TAB_WIDTH = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[0] * 0.75;
THRUST_FAN_DUCT_MOUNT_BRACE_BOTTOM_TAB_POS = THRUST_FAN_DUCT_MOUNT_BRACE_DIM[0] * 0.5;

/* Rudder */
RUDDER_DIMENSIONS = [30, THRUST_FAN_DUCT_DIMENSIONS[0] * 0.9];
RUDDER_CORNER_RADIUS = 2;
RUDDER_PIVOT_LENGTH = 10;
RUDDER_SPACING = THRUST_FAN_DUCT_DIMENSIONS[0] * 0.475;
RUDDER_ARM_HOLE_POSITION = [RUDDER_DIMENSIONS[0] * 0.2, -RUDDER_DIMENSIONS[1] * 0.45];
RUDDER_ARM_HOLE_DIAM = 2;

/* Rudder mount */
RUDDER_MOUNT_DIMENSIONS = [THRUST_FAN_DUCT_DIMENSIONS[0] * 0.8, 10];
RUDDER_MOUNT_CORNER_RADIUS = 5;
RUDDER_MOUNT_OFFSET = (RUDDER_DIMENSIONS[1] / 2) + MATERIAL_THICKNESS;
RUDDER_MOUNT_TAB_WIDTH = 5;
RUDDER_MOUNT_TAB_OFFSET = (RUDDER_MOUNT_DIMENSIONS[0] - RUDDER_MOUNT_TAB_WIDTH) / 2;
RUDDER_MOUNT_TAB_LENGTH = MATERIAL_THICKNESS + 6;

/* Skirt clamp */
SKIRT_CLAMP_PADDING = 10;
SKIRT_CLAMP_HOLE_DIAM = 3;

/* Lower skirt mount */
LOWER_SKIRT_MOUNT_SCALE = 0.6;


gantry/lower/connector: fix front screw position

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

module gantry_lower_connector()
{
    thick = gantry_connector_thickness;
    width = extrusion_size+thick;
    depth = extrusion_size*2;
    height = main_lower_dist_z+extrusion_size;
    translate([thick,0,0])
    difference()
    {
        material(Mat_Plastic)
        union()
        {
            // top/bottom
            for(z=[-1,1])
            translate([0,0,z*height/2])
            rcubea([width,extrusion_size*2,thick], align=[-1,0,z], extra_size=[0,thick,0], extra_align=[0,-1,0]);

            // side
            rcubea([thick,depth,height+thick], align=[-1,0,0], extra_size=[0,thick,0], extra_align=[0,-1,0]);

            // front
            translate([0,-depth/2,0])
            rcubea([width,thick,height+thick], align=[-1,-1,0]);

        }

        // side nuts
        for(z=[-1,1])
        translate([0,extrusion_size/2,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_nut, head="button", h=thick+.1, with_nut=false, orient=[-1,0,0], align=[-1,0,0]);

        // side end nuts
        for(z=[-1,1])
        translate([0,-extrusion_size/2,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_end_nut, head="button", h=thick+.1, with_nut=false, orient=[-1,0,0], align=[-1,0,0]);

        // front nuts
        for(z=[-1,1])
        translate([-width/2-thick/2,-extrusion_size-thick,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_nut, head="button", h=thick+.1, with_nut=false, orient=Y, align=Y);
    }
}

module part_gantry_lower_connector()
{
    /*rotate([0,90,0])*/
    rotate([90,0,0])
    gantry_lower_connector();
}

/*gantry_lower_connector();*/

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

module gantry_lower_connector()
{
    thick = gantry_connector_thickness;
    width = extrusion_size+thick;
    depth = extrusion_size*2;
    height = main_lower_dist_z+extrusion_size;
    translate([thick,0,0])
    difference()
    {
        material(Mat_Plastic)
        union()
        {
            // top/bottom
            for(z=[-1,1])
            translate([0,0,z*height/2])
            rcubea([width,extrusion_size*2,thick], align=[-1,0,z], extra_size=[0,thick,0], extra_align=[0,-1,0]);

            // side
            rcubea([thick,depth,height+thick], align=[-1,0,0], extra_size=[0,thick,0], extra_align=[0,-1,0]);

            // front
            translate([0,-depth/2,0])
            rcubea([width,thick,height+thick], align=[-1,-1,0]);

        }

        // side nuts
        for(z=[-1,1])
        translate([0,extrusion_size/2,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_nut, head="button", h=thick+.1, with_nut=false, orient=[-1,0,0], align=[-1,0,0]);

        // side end nuts
        for(z=[-1,1])
        translate([0,-extrusion_size/2,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_end_nut, head="button", h=thick+.1, with_nut=false, orient=[-1,0,0], align=[-1,0,0]);

        // front nuts
        for(z=[-1,1])
        translate([-width/2-thick,-extrusion_size-thick,z*main_lower_dist_z/2])
        screw_cut(nut=extrusion_nut, head="button", h=thick+.1, with_nut=false, orient=Y, align=Y);
    }
}

module part_gantry_lower_connector()
{
    /*rotate([0,90,0])*/
    rotate([90,0,0])
    gantry_lower_connector();
}

/*gantry_lower_connector();*/


Add some pieces to attach to the lines

Add some pieces to attach to the lines

width = 97; // External width (except clipping mechanism)
height = 146; // External height (except clipping mechanism)
corner_radius = 14; // Round corner at the bottom corners
top_width = 114; // Clipping mechanism width
top_height = 20; // Clipping mechanism height
thickness = 5; // Thickness
clip_height = 14;

//Main pocket
difference()
{
	union(){
		cube(size = [width,height,thickness], center = true);
		difference(){
			translate([-width/2, 0,0]) cylinder(r=20, h=thickness, center = true);
			translate([-width/2-5, 0,0]) cylinder(r=2.5, h=thickness, center = true);
			translate([-width/2-1.5, -10,0]) cube(size =[3,26,thickness], center = true);
		}
		difference(){
			translate([width/2, 0,0]) cylinder(r=20, h=thickness, center = true);
			translate([width/2+5, 0,0]) cylinder(r=2.5, h=thickness, center = true);
			translate([width/2+1.5, -10,0]) cube(size =[3,26,thickness], center = true);
}
	}
	cube(size = [width-20,height-24,thickness], center = true);
}

// Existing top clip
//translate([0, height/2 + top_height/2, 0]) cube(size = [top_width,top_height,thickness], center = true);

clip_width = width +20;
// Top clip support
difference(){
	translate([0, height/2 - clip_height/2, 0]) cube(size = [clip_width, clip_height, thickness], center = true);
	translate([-clip_width/2+7, height/2- clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([+clip_width/2-7, height/2- clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
}

// Top clip
difference()
{
	translate([-clip_height/2-1, 0 , 0]) cube(size = [clip_height, clip_width, thickness], center = true);
	translate([-clip_height/2-1, clip_width/2-7, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([-clip_height/2-1, -clip_width/2+7, 0]) cylinder(r=2.5, h=thickness, center = true);
}

// Bottom clip support
difference(){
	translate([0, -height/2+clip_height/2, 0]) cube(size = [clip_width, clip_height, thickness], center = true);
	translate([-clip_width/2+7, -height/2+ clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([+clip_width/2-7, -height/2+ clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
}
// Bottom clip
difference(){
 translate([clip_height/2+1, 0, 0]) cube(size = [clip_height, clip_width, thickness], center = true);
	translate([clip_height/2+1, clip_width/2-7, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([clip_height/2+1, -clip_width/2+7, 0]) cylinder(r=2.5, h=thickness, center = true);
}

module tender()
{
difference(){
	cube(size=[20, 40, thickness], center=true);
	translate([2, 0, 0]) cylinder(r=2.5, h=thickness, center = true);
		translate([0-4, 1, 0]) rotate([0,0, -20]) cube(size=[15, 3, thickness], center=true);
		translate([0+2, 12, 0]) cylinder(r=2.5, h=thickness, center = true);
		translate([0-4, 12+1, 0]) rotate([0,0, -20]) cube(size=[15, 3, thickness], center=true);
		translate([0+2, -12, 0]) cylinder(r=2.5, h=thickness, center = true);
		translate([0-4, -12-1, 0]) rotate([0,0, 20]) cube(size=[15, 3, thickness], center=true);
		translate([0-5, -6, 0]) cylinder(r=2.5, h=thickness, center = true);

	}
}
translate([clip_width/4-2,clip_width/4,0]) tender();
translate([clip_width/4-2,-clip_width/4,0]) tender();
translate([-clip_width/4+2,-clip_width/4,0]) tender();
translate([-clip_width/4+2,clip_width/4,0]) tender();

width = 97; // External width (except clipping mechanism)
height = 146; // External height (except clipping mechanism)
corner_radius = 14; // Round corner at the bottom corners
top_width = 114; // Clipping mechanism width
top_height = 20; // Clipping mechanism height
thickness = 5; // Thickness
clip_height = 14;

//Main pocket
difference()
{
	union(){
		cube(size = [width,height,thickness], center = true);
		difference(){
			translate([-width/2, 0,0]) cylinder(r=20, h=thickness, center = true);
			translate([-width/2-5, 0,0]) cylinder(r=2.5, h=thickness, center = true);
			translate([-width/2-1.5, -10,0]) cube(size =[3,26,thickness], center = true);
		}
		difference(){
			translate([width/2, 0,0]) cylinder(r=20, h=thickness, center = true);
			translate([width/2+5, 0,0]) cylinder(r=2.5, h=thickness, center = true);
			translate([width/2+1.5, -10,0]) cube(size =[3,26,thickness], center = true);
}
	}
	cube(size = [width-20,height-24,thickness], center = true);
}

// Existing top clip
//translate([0, height/2 + top_height/2, 0]) cube(size = [top_width,top_height,thickness], center = true);

clip_width = width +20;
// Top clip support
difference(){
	translate([0, height/2 - clip_height/2, 0]) cube(size = [clip_width, clip_height, thickness], center = true);
	translate([-clip_width/2+7, height/2- clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([+clip_width/2-7, height/2- clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
}

// Top clip
difference()
{
	translate([-clip_height, 0 , 0]) cube(size = [clip_height, clip_width, thickness], center = true);
	translate([-clip_height, clip_width/2-7, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([-clip_height, -clip_width/2+7, 0]) cylinder(r=2.5, h=thickness, center = true);
}

// Bottom clip support
difference(){
	translate([0, -height/2+clip_height/2, 0]) cube(size = [clip_width, clip_height, thickness], center = true);
	translate([-clip_width/2+7, -height/2+ clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([+clip_width/2-7, -height/2+ clip_height/2, 0]) cylinder(r=2.5, h=thickness, center = true);
}
// Bottom clip
difference(){
 translate([clip_height, 0, 0]) cube(size = [clip_height, clip_width, thickness], center = true);
	translate([clip_height, clip_width/2-7, 0]) cylinder(r=2.5, h=thickness, center = true);
	translate([clip_height, -clip_width/2+7, 0]) cylinder(r=2.5, h=thickness, center = true);
}


y/motor-mount: use material system

y/motor-mount: use material system

use <thing_libutils/shapes.scad>
use <thing_libutils/attach.scad>
use <thing_libutils/transforms.scad>
include <thing_libutils/materials.scad>

include <y-motor-mount.h>

module yaxis_motor_mount_bearing_clamp(align=N)
{
    bearing_d = bearing_625[1];
    bearing_h = bearing_625[2];
    width=ymotor_w+ymotor_mount_thickness;
    depth=ymotor_w+ymotor_mount_thickness*2;
    height=yaxis_motor_mount_bearing_clamp_offset_z;

    /*size_align(size=[width,depth,height], align=align);*/
    difference()
    {
        cubea([width, depth, height], align=[0,0,-1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        translate([0,0,.1])
            cylindera(h=bearing_h*2, d=bearing_d*rod_fit_tolerance, orient=Z, align=[0,0,-1]);

        // cutout for belt path
        cylindera(d=bearing_d, h=height*2, orient=Z, align=[0,0,-1]);
        translate([depth/2, 0, -bearing_h])
            cubea([depth, ymotor_round_d, height-bearing_h+1], align=[0,0,-1]);

        // cut out motor mount holes etc
        screw_dist = lookup(NemaDistanceBetweenMountingHoles, yaxis_motor);
        for(x=[-1,1])
        for(y=[-1,1])
        translate([x*screw_dist/2, y*screw_dist/2, 1])
        cylindera(h=height, d=3*mm, orient=Z, align=[0,0,-1]);
    }

    // debug bearing
    %cylindera(h=bearing_h, d=bearing_d*rod_fit_tolerance, align=[0,0,-1], orient=Z);
}

module motor_mount_top(width, depth, height, belt_cutout=true, belt_cutout_orient=X, align=N)
{
    size_align(size=[width, depth, height], align=align);
    difference()
    {
        cubea([width, depth, height], align=Z);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        // cutout for belt path
        cylindera(d=ymotor_round_d, h=height*2, orient=Z, align=N);
        translate([0, 0,-1])
            cubea([depth/2, ymotor_round_d, height*2], align=[1,0,1]);

        // cut out motor mount holes etc
        translate([0,0,-1])
            linear_extrude(height+2)
            stepper_motor_mount(17, slide_distance=0, mochup=false);
    }
}

module yaxis_motor_mount(show_motor=false)
{
    difference()
    {
        // top plate
        material(Mat_Plastic)
        union()
        {
            translate([0,0,yaxis_motor_offset_z])
            {
                // top plate
                translate([ymotor_mount_thickness,0,extrusion_size/2])
                {
                    /*translate([ymotor_w/2,0,ymotor_mount_thickness_h+yaxis_motor_mount_bearing_clamp_offset_z+1])*/
                        /*yaxis_motor_mount_bearing_clamp(align=[0,0,-1]);*/

                    translate([ymotor_w/2,0,0])
                        motor_mount_top(width=ymotor_w+ymotor_mount_thickness,
                        depth=ymotor_w+ymotor_mount_thickness*2,
                        height=ymotor_mount_thickness_h,
                        belt_cutout=true,
                        belt_cutout_orient=X);
                }

                translate([0,0,extrusion_size/2])
                {
                    difference()
                    {
                        // reinforcement plate between motor and extrusion
                        cubea([ymotor_mount_thickness, ymotor_w+ymotor_mount_thickness*2, ymotor_h], align=[1,0,-1], extrasize=[0,0,ymotor_mount_thickness_h], extrasize_align=Z);

                        // cutout for motor cables
                        translate([0,0,-20*mm])
                            cubea([ymotor_mount_thickness*3, 20*mm, ymotor_h], align=[0,0,-1]);
                    }
                }

                // side triangles
                for(i=[-1,1])
                {
                    translate([ymotor_mount_thickness, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        triangle(
                                ymotor_w+ymotor_mount_thickness/2,
                                main_lower_dist_z+extrusion_size+yaxis_motor_offset_z,
                                depth=ymotor_mount_thickness,
                                align=[1,0,-1],
                                orient=X
                                );

                    translate([0, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        cubea([ymotor_mount_thickness, ymotor_mount_thickness, ymotor_mount_h], align=[1,0,-1]);
                }
            }

            // top mount plate
            difference()
            {
                cubea([ymotor_mount_thickness, ymotor_mount_width, extrusion_size], align=X);

                for(i=[-1,1])
                    translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                        cylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia, orient=X);
            }

            // bottom mount plate
            translate([0,0,-main_lower_dist_z])
            {
                difference()
                {
                    cubea([ymotor_mount_thickness, ymotor_w, extrusion_size], align=X);

                    for(i=[0])
                        translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                            cylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia,align=N, orient=X);
                }
            }

        }

    }

    if(show_motor)
    {
        attach(yaxis_motor_mount_conn_motor,[N,N])
        {
            motor(yaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);

            translate([0,0,8*mm])
                %pulley(pulley_2GT_20T);
        }
    }
}

module part_y_motor_mount()
{
    attach(yaxis_motor_mount_conn_motor,[N,X])
    {
        yaxis_motor_mount(show_motor=false);
    }
}

/*yaxis_motor_mount(show_motor=true);*/

use <thing_libutils/shapes.scad>
use <thing_libutils/attach.scad>
use <thing_libutils/transforms.scad>

include <y-motor-mount.h>

module yaxis_motor_mount_bearing_clamp(align=N)
{
    bearing_d = bearing_625[1];
    bearing_h = bearing_625[2];
    width=ymotor_w+ymotor_mount_thickness;
    depth=ymotor_w+ymotor_mount_thickness*2;
    height=yaxis_motor_mount_bearing_clamp_offset_z;

    /*size_align(size=[width,depth,height], align=align);*/
    difference()
    {
        cubea([width, depth, height], align=[0,0,-1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        translate([0,0,.1])
            cylindera(h=bearing_h*2, d=bearing_d*rod_fit_tolerance, orient=Z, align=[0,0,-1]);

        // cutout for belt path
        cylindera(d=bearing_d, h=height*2, orient=Z, align=[0,0,-1]);
        translate([depth/2, 0, -bearing_h])
            cubea([depth, ymotor_round_d, height-bearing_h+1], align=[0,0,-1]);

        // cut out motor mount holes etc
        screw_dist = lookup(NemaDistanceBetweenMountingHoles, yaxis_motor);
        for(x=[-1,1])
        for(y=[-1,1])
        translate([x*screw_dist/2, y*screw_dist/2, 1])
        cylindera(h=height, d=3*mm, orient=Z, align=[0,0,-1]);
    }

    // debug bearing
    %cylindera(h=bearing_h, d=bearing_d*rod_fit_tolerance, align=[0,0,-1], orient=Z);
}

module motor_mount_top(width, depth, height, belt_cutout=true, belt_cutout_orient=X, align=N)
{
    size_align(size=[width, depth, height], align=align);
    difference()
    {
        cubea([width, depth, height], align=Z);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        // cutout for belt path
        cylindera(d=ymotor_round_d, h=height*2, orient=Z, align=N);
        translate([0, 0,-1])
            cubea([depth/2, ymotor_round_d, height*2], align=[1,0,1]);

        // cut out motor mount holes etc
        translate([0,0,-1])
            linear_extrude(height+2)
            stepper_motor_mount(17, slide_distance=0, mochup=false);
    }
}

module yaxis_motor_mount(show_motor=false)
{
    difference()
    {
        // top plate
        union()
        {
            translate([0,0,yaxis_motor_offset_z])
            {
                // top plate
                translate([ymotor_mount_thickness,0,extrusion_size/2])
                {
                    /*translate([ymotor_w/2,0,ymotor_mount_thickness_h+yaxis_motor_mount_bearing_clamp_offset_z+1])*/
                        /*yaxis_motor_mount_bearing_clamp(align=[0,0,-1]);*/

                    translate([ymotor_w/2,0,0])
                        motor_mount_top(width=ymotor_w+ymotor_mount_thickness,
                        depth=ymotor_w+ymotor_mount_thickness*2,
                        height=ymotor_mount_thickness_h,
                        belt_cutout=true,
                        belt_cutout_orient=X);
                }

                translate([0,0,extrusion_size/2])
                {
                    difference()
                    {
                        // reinforcement plate between motor and extrusion
                        cubea([ymotor_mount_thickness, ymotor_w+ymotor_mount_thickness*2, ymotor_h], align=[1,0,-1], extrasize=[0,0,ymotor_mount_thickness_h], extrasize_align=Z);

                        // cutout for motor cables
                        translate([0,0,-20*mm])
                            cubea([ymotor_mount_thickness*3, 20*mm, ymotor_h], align=[0,0,-1]);
                    }
                }

                // side triangles
                for(i=[-1,1])
                {
                    translate([ymotor_mount_thickness, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        triangle(
                                ymotor_w+ymotor_mount_thickness/2,
                                main_lower_dist_z+extrusion_size+yaxis_motor_offset_z,
                                depth=ymotor_mount_thickness,
                                align=[1,0,-1],
                                orient=X
                                );

                    translate([0, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        cubea([ymotor_mount_thickness, ymotor_mount_thickness, ymotor_mount_h], align=[1,0,-1]);
                }
            }

            // top mount plate
            difference()
            {
                cubea([ymotor_mount_thickness, ymotor_mount_width, extrusion_size], align=X);

                for(i=[-1,1])
                    translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                        cylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia, orient=X);
            }

            // bottom mount plate
            translate([0,0,-main_lower_dist_z])
            {
                difference()
                {
                    cubea([ymotor_mount_thickness, ymotor_w, extrusion_size], align=X);

                    for(i=[0])
                        translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                            cylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia,align=N, orient=X);
                }
            }

        }

    }

    if(show_motor)
    {
        attach(yaxis_motor_mount_conn_motor,[N,N])
        {
            motor(yaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);

            translate([0,0,8*mm])
                %pulley(pulley_2GT_20T);
        }
    }
}

module part_y_motor_mount()
{
    attach(yaxis_motor_mount_conn_motor,[N,X])
    {
        yaxis_motor_mount(show_motor=false);
    }
}

/*yaxis_motor_mount(show_motor=true);*/


New shape for screw_hole_cap() module.

New shape for screw_hole_cap() module.

//See:
// http://edutechwiki.unige.ch/en/OpenScad_beginners_tutorial
// https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/

// Global variables.
overcut = 0.1;  // Overcut for solid difference(), to assure complete holes.
overlap = 0.1;  // Intersection for solid union() to avoid the manifold problem.

include <misc_parts.scad>;
include <boards.scad>;
include <rounded_cube.scad>;

// Box internal size.
x_size  = 115.0;
y_size  = 144.0;
z_size  =  29.0;
thick   =   2.2;
chamfer =  13.0;

// Mounting screw holes.
screw_hole1_y = 24;
screw_hole2_y = y_size - 26;
screw_diam    = 3.6;

// Position and size of push button hole.
button_x = x_size;
button_y = 64;
button_z = 16.0;
button_d = 6.2;

// Position and size of power socket hole.
psocket_x = x_size / 2;
psocket_z = 7;
psocket_d = 8.2;

// Position and size for temperature sensor grommet.
tsensor_x  = -thick - 1;
tsensor_y  = 78;
tsensor_z  = 13;
tsensor_h  = thick + 9;
tsensor_d1 = 9.0;
tsensor_d2 = 5.25;

// Positon and size for boiler cable grommet (cable is 5.5 x 3.5 mm).
bcable_x  = 19;
bcable_y  = -thick - 1;
bcable_z  = 9.5;
bcable_h  = thick + 9;
bcable_t  = 1.7; // Grommet thickness
bcable_d1 = 5.4; // Rectangular hole X
bcable_d2 = 3.4; // Rectangular hole Y
bcable_r  = 1.5; // Chamfer radius

//-------------------------------------------------------------------------
// Housing for a rubber foot.
//-------------------------------------------------------------------------
module rubber_foot(d1, d2, h) {
    $fn = 48;
    difference() {
        cylinder(r=(d1 / 2), h=h);
        translate([0, 0, -overcut]) cylinder(r=(d2 / 2), h=(h + overcut * 2));
    }
}

//-------------------------------------------------------------------------
// Housings for rubber feet (grows towards negative z axis).
//-------------------------------------------------------------------------
module box_feet(x, y, margin) {
    d1 = 11.0;
    d2 =  8.2;
    h  =  0.8;
    translate([margin,     margin,     -h]) rubber_foot(d1, d2, h + overlap);
    translate([x - margin, margin,     -h]) rubber_foot(d1, d2, h + overlap);
    translate([x - margin, y - margin, -h]) rubber_foot(d1, d2, h + overlap);
    translate([margin,     y - margin, -h]) rubber_foot(d1, d2, h + overlap);
}

//-------------------------------------------------------------------------
// Flange for screw hole.
//-------------------------------------------------------------------------
module screw_flange(r, t) {
    $fn = 60;
    r1 = r * 1.1;
    difference() {
        intersection() {
            cylinder(r=r1, h=t);
            union() {
                translate([r, r, 0]) cylinder(r=r, h=t);
                translate([r, 0, 0]) cube([r, r, t]);
                translate([0, r, 0]) cube([r, r, t]);}}
        translate([r1 / 2, r1 / 2, -overcut]) cylinder(r=1, h=(t + overcut * 2), $fn=24);
    }
}

//-------------------------------------------------------------------------
// Add a flange to the rounded_box() module.
//-------------------------------------------------------------------------
module rounded_box_flange(x, y, z, r) {
    w = 1.5;
    difference() {
        rounded_cube(x_size, y_size, z, r);
        translate([w, w, -overcut])
            rounded_cube(x_size - w * 2, y_size - w * 2, z + overcut * 2, r);
    }
    translate([0, 0, 0]) rotate(a=0 ,  v=[0, 0, 1]) screw_flange(r, z);
    translate([x, 0, 0]) rotate(a=90,  v=[0, 0, 1]) screw_flange(r, z);
    translate([x, y, 0]) rotate(a=180, v=[0, 0, 1]) screw_flange(r, z);
    translate([0, y, 0]) rotate(a=270, v=[0, 0, 1]) screw_flange(r, z);
}

//-------------------------------------------------------------------------
// Round cable grommet.
//-------------------------------------------------------------------------
module cable_grommet(h, d1, d2) {
    $fn = 32;
    cut_width = 3;
    difference() {
        union() {
            cylinder(r=(d1 / 2), h=h);
            translate([0, 0, h - 2.4]) cylinder(r=((d1 + 1.0) / 2), h=2.4);
        }
        translate([0, 0, -overcut]) cylinder(r=(d2 / 2), h=(h + 2 * overcut));
        translate([(d2 / 4), -(d1 / 2), h - (cut_width + 2.5)])
            cube([(d1 / 2), d1, cut_width]);
    }
}

//-------------------------------------------------------------------------
// Rectangular (with chamfer) cable grommet.
// h = height, x, y = hole inner size, r = chamfer radius, t = thickness
//-------------------------------------------------------------------------
module cable_grommet_rect(h, x, y, r, t) {
    cut_width = 3;
    difference() {
        union() {
            translate([-x / 2, -y / 2, 0]) rounded_cube_border(x, y, h, r, t);
            translate([-x / 2, -y / 2, h - 2.4]) rounded_cube_border(x, y, 2.4, r, t + 0.5);
        }
        translate([-(x / 2) - t - overcut, 0, h - (cut_width + 2.5)])
            cube([x + (t + overcut) * 2, y / 2 + t + overcut, cut_width]);
    }
}

//-------------------------------------------------------------------------
// Drill a screw hole with cuts for horizontal and vertical wall mount.
// Screw body diameter is d, head diameter will be d * 2.
//-------------------------------------------------------------------------
module screw_hole(d, depth) {
    $fn = 32;
    hole_depth = depth + overcut * 2;
    hole_bottom = -(depth + overcut);
    cut_length = d * 2;
    union() {
        translate([0, 0, hole_bottom])          cylinder(r=d, h=hole_depth);
        translate([-(d / 2), 0, hole_bottom])   cube([d, cut_length, hole_depth]);
        translate([0, -(d / 2), hole_bottom])   cube([cut_length, d, hole_depth]);
        translate([0, cut_length, hole_bottom]) cylinder(r=(d / 2), h=hole_depth);
        translate([cut_length, 0, hole_bottom]) cylinder(r=(d / 2), h=hole_depth);
    }
}

//-------------------------------------------------------------------------
// Build a cap to place over a screw hole.
// Screw body diameter = d
// Screw head diameter = d * 2
// Screw head height   = d * 0.6
//-------------------------------------------------------------------------
module screw_hole_cap(d, thick) {
    $fn = 36;
    r2 = 1.4142;
    pin_radius = thick * 1.3;
    pin_heigh = (d * 0.6) + (overlap * 2);
    pin_base = -overlap;
    offset = (((pin_radius * r2) - pin_radius) / r2) + ((pin_radius * 2) / r2) + (d / r2);
    size1 = (offset + overlap) * 2;
    size2 = size1 + d * 2;
    translate([-(size1 / 2), -(size1 / 2), 0]) {
        union() {
            translate([0, 0, d * 0.6]) rounded_cube(size1, size2, thick, pin_radius);
            translate([0, 0, d * 0.6]) rounded_cube(size2, size1, thick, pin_radius);
            translate([pin_radius, pin_radius, pin_base])                 cylinder(r=pin_radius, h=pin_heigh);
            translate([size2 - pin_radius, pin_radius, pin_base])         cylinder(r=pin_radius, h=pin_heigh);
            translate([size2 - pin_radius, size1 - pin_radius, pin_base]) cylinder(r=pin_radius, h=pin_heigh);
            translate([size1 - pin_radius, size2 - pin_radius, pin_base]) cylinder(r=pin_radius, h=pin_heigh);
            translate([pin_radius, size2 - pin_radius, pin_base])         cylinder(r=pin_radius, h=pin_heigh);
        }
    }
}

//-------------------------------------------------------------------------
// Make a box with the requested internal size and rounded corners.
// The origin is the lower-left internal corner.
//-------------------------------------------------------------------------
module rounded_box(x_size, y_size, z_size, chamfer, thick) {
    cover_thick = 2;
    union() {
        translate([-overlap, -overlap, -thick])
            rounded_cube(x_size + overlap * 2, y_size + overlap * 2, thick, chamfer + overlap);
        translate([0, 0, -thick])
            rounded_cube_border(x_size, y_size, z_size + thick, chamfer, thick);
        translate([-overlap, -overlap, z_size - cover_thick - thick])
            rounded_box_flange(x_size + overlap * 2, y_size + overlap * 2, thick, chamfer + overlap);
        translate([0, 0, -thick])
            box_feet(x_size, y_size, 10);
        // Draw the box cover, for dimension testing.
        //translate([0, 0, z_size - cover_thick])
        //    %rounded_cube(x_size, y_size, cover_thick, chamfer);
    }
}

//-------------------------------------------------------------------------
// Make a box with rounded corners, drill all the required holes.
//-------------------------------------------------------------------------
module rounded_box_holes(x_size, y_size, z_size, chamfer, thick) {

    holes_diam = 3.5;

    // Boiler cable grommet.
    translate([bcable_x, bcable_y, bcable_z])
        rotate(a=180, v=[0, 1, 0])
            rotate(a=270, v=[1, 0, 0])
                cable_grommet_rect(bcable_h, bcable_d1, bcable_d2, bcable_r, bcable_t);

    // Temperature sensor cable grommet.
    translate([tsensor_x, tsensor_y, tsensor_z])
        rotate(a=90, v=[1, 0, 0])
            rotate(a=90, v=[0, 1, 0])
                cable_grommet(tsensor_h, tsensor_d1, tsensor_d2);

    difference() {
        rounded_box(x_size, y_size, z_size, chamfer, thick);

        // Bottom venting holes.
        translate([x_size / 2, 0, z_size / 2])
            rotate(a=90, v=[1, 0, 0]) vent_holes(12, 3, holes_diam, thick);

        // Top venting holes.
        translate([x_size / 2, y_size + thick, z_size / 2])
            rotate(a=90, v=[1, 0, 0]) vent_holes(11, 3, holes_diam, thick);

        // Backplane venting holes.
        translate([83, 88, -thick]) vent_holes(8, 6, holes_diam, thick);
        translate([25, 38, -thick]) vent_holes(5, 4, holes_diam, thick);

        // Mounting screw holes.
        translate([x_size / 2, screw_hole1_y, 0]) rotate(a=90, v=[0, 0, 1]) screw_hole(screw_diam, thick);
        translate([x_size / 2, screw_hole2_y, 0]) rotate(a=90, v=[0, 0, 1]) screw_hole(screw_diam, thick);

        // Temperature sensor hole.
        translate([-(thick + overcut), tsensor_y, tsensor_z])
            rotate(a=90, v=[0, 1, 0]) cylinder(r=(tsensor_d2 / 2), h=(thick + overcut * 2), $fn=24);

        // Bush-button hole.
        translate([button_x - overcut, button_y, button_z])
            rotate(a=90, v=[0, 1, 0]) cylinder(r=(button_d / 2), h=(thick + overcut * 2), $fn=24);

        // Power socket hole.
        translate([psocket_x, overcut, psocket_z])
            rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2), h=(thick + overcut * 2), $fn=24);

        // Boiler cable hole.
        translate([bcable_x, bcable_y - overcut, bcable_z])
            rotate(a=270, v=[1, 0, 0]) rounded_cube_centered(bcable_d1, bcable_d2, bcable_h + overcut * 2, bcable_r);

    }

    // Reinforce for power socket hole.
    difference() {
        translate([psocket_x, 0, psocket_z]) rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2) + 2.5, h=thick);
        translate([psocket_x, overcut, psocket_z])
            rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2), h=(thick + overcut * 2), $fn=24);
    }

    // Reinforce for boiler cable hole.
    difference() {
        translate([bcable_x, 0, bcable_z])
            rotate(a=90, v=[1, 0, 0]) rounded_cube_centered(bcable_d1 + 5.5, bcable_d2 + 5.5, thick, 3);
        translate([bcable_x, overcut, bcable_z])
            rotate(a=90, v=[1, 0, 0]) rounded_cube_centered(bcable_d1, bcable_d2, (thick + overcut * 2), bcable_r);
    }

    // Mounting screws holes.
    translate([x_size / 2, screw_hole1_y, 0]) rotate(a=90, v=[0, 0, 1]) #screw_hole_cap(screw_diam, 1.7);
    translate([x_size / 2, screw_hole2_y, 0]) rotate(a=90, v=[0, 0, 1]) #screw_hole_cap(screw_diam, 1.7);
}

//-------------------------------------------------------------------------
// Drill a grid of rows x columns vent holes. Each hole has the
// specified diameter and depth, the grid is centered into the origin.
//-------------------------------------------------------------------------
module vent_holes(x, y, diameter, depth) {
    $fn = 6; // 18 = rounded holes, 6 = hexagonal
    step = diameter * 2;
    radius = diameter / 1.8;  // Divide by 2.0 if rounded holes, 1.8 if hexagonal.
    offset_x = (step * (x - 1)) / 2;
    offset_y = (step * (y - 1)) / 2;
    for (i = [1:x]) {
        for (j = [1:y]) {
            translate([(i - 1) * step - offset_x, (j -1) * step - offset_y, -overcut])
              cylinder(r=radius, h=(depth + overcut * 2));
        }
    }
    for (i = [1:x-1]) {
        for (j = [1:y-1]) {
            translate([(i - 1) * step - offset_x + step / 2, (j -1) * step - offset_y + step / 2, -overcut])
                cylinder(r=radius, h=(depth + overcut * 2));
        }
    }
}

//-------------------------------------------------------------------------
// Screw stub: d1 is the outer diameter, d2 is the screw diameter.
// The stub height must be grather than the depth of the hole.
//-------------------------------------------------------------------------
module stub(d1, height, d2, hole_depth) {
    $fn = 36;
    // The hole for a self-tapping screw is narrower than the screw.
    hole_diameter = d2 * 0.75;
    difference() {
        translate([0, 0, -overlap]) {
            union() {
                cylinder(r=(d1 / 2), h=(height + overlap));
                cylinder(r1=(d1 * 0.7), r2=(d1 / 2), h=(4 + overlap));
            }
        }
        translate([0, 0, height - hole_depth])
            cylinder(r=(hole_diameter / 2), h=(hole_depth + overcut));
    }
}

//-------------------------------------------------------------------------
// Screw stubs for relay board (SainSmart like manufacturer).
//-------------------------------------------------------------------------
module stubs_2relays_sainsmart(height) {
    diameter = 7;
    screw_diameter = 2.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([2.75, 2.75, 0]) {
        translate([ 0,      0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([33.5,    0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([0,    45.5, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([33.5, 45.5, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for relay board (Keyes manufacturer).
//-------------------------------------------------------------------------
module stubs_2relays_keyes(height) {
    diameter = 7;
    screw_diameter = 3.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([3.5, 9, 0]) {
        translate([ 0,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([38,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([0,  40, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([38, 40, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for PCD8544 LCD (Nokia 5110/3310), blue PCB model.
//-------------------------------------------------------------------------
module stubs_pcd8544_blue(height) {
    diameter = 6.5;
    screw_diameter = 2.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([4.25, 2.25, 0]) {
        translate([ 0,    0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([34.5,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([0,    41, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([34.5, 41, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for PCD8544 LCD (Nokia 5110/3310), red PCB model.
//-------------------------------------------------------------------------
module stubs_pcd8544_red(height) {
    diameter = 6.0;
    screw_diameter = 2.0;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([1.75, 2.0, 0]) {
        translate([ 0,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([40,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([ 0, 39, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([40, 39, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for Raspberry Pi Model B v.2.
//-------------------------------------------------------------------------
module stubs_raspberrypi_model_b_v2(height) {
    screw_diameter = 2.5;
    hole_depth = 6;
    translate([38, 25.5, 0]) {
        translate([    0,    0, 0]) stub(6.5, height, screw_diameter, hole_depth);
        translate([-25.5, 54.5, 0]) stub(6.5, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Main procedure.
//-------------------------------------------------------------------------
translate([-(x_size / 2), -(y_size/2), 0]) {
    rounded_box_holes(x_size, y_size, z_size, chamfer, thick);
    translate([ 5, 12,  0.0]) stubs_2relays_sainsmart(5.0);
    translate([ 8, 90,  0.0]) stubs_pcd8544_red(20.5); // Non diminuire Y sennò tocca il coprivite!
    translate([55, 37,  0.0]) stubs_raspberrypi_model_b_v2(5.0);
    //translate([55, 37 , 5.0]) board_raspberrypi_model_b_v2();
    //translate([ 8, 90, 20.5]) board_pcd8544_red();
    //translate([ 5, 12,  5.0]) board_2relays_sainsmart();
    //translate([button_x, button_y, button_z]) rotate(a=90, v=[0, 1, 0]) push_button();
    //translate([psocket_x, -thick, psocket_z]) rotate(a=90, v=[1, 0, 0]) coax_power_jack();
}

include <RigacciOrg.scad>;
translate([-x_size / 2 - thick + overlap, -29, 13])
    rotate(a=270, v=[0,0,1]) rotate(a=90, v=[1,0,0]) {
        //#cube([55, 12.54, 0.5], center=true);
        RigacciOrg(0.5);
    }

include <ccbysa.scad>;
translate([-x_size / 2 - thick + overlap, 34, 13])
    rotate(a=270, v=[0,0,1]) rotate(a=90, v=[1,0,0]) {
        //#cube([35.60, 12.54, 0.5], center=true);
        ccbysa(0.5);
    }

//See:
// http://edutechwiki.unige.ch/en/OpenScad_beginners_tutorial
// https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/

// Global variables.
overcut = 0.1;  // Overcut for solid difference(), to assure complete holes.
overlap = 0.1;  // Intersection for solid union() to avoid the manifold problem.

include <misc_parts.scad>;
include <boards.scad>;
include <rounded_cube.scad>;

// Box internal size.
x_size  = 115.0;
y_size  = 144.0;
z_size  =  29.0;
thick   =   2.2;
chamfer =  13.0;

// Mounting screw holes.
screw_hole1_y = 24;
screw_hole2_y = y_size - 26;
screw_diam    = 3.6;

// Position and size of push button hole.
button_x = x_size;
button_y = 64;
button_z = 16.0;
button_d = 6.2;

// Position and size of power socket hole.
psocket_x = x_size / 2;
psocket_z = 7;
psocket_d = 8.2;

// Position and size for temperature sensor grommet.
tsensor_x  = -thick - 1;
tsensor_y  = 78;
tsensor_z  = 13;
tsensor_h  = thick + 9;
tsensor_d1 = 9.0;
tsensor_d2 = 5.25;

// Positon and size for boiler cable grommet (cable is 5.5 x 3.5 mm).
bcable_x  = 19;
bcable_y  = -thick - 1;
bcable_z  = 9.5;
bcable_h  = thick + 9;
bcable_t  = 1.7; // Grommet thickness
bcable_d1 = 5.4; // Rectangular hole X
bcable_d2 = 3.4; // Rectangular hole Y
bcable_r  = 1.5; // Chamfer radius

//-------------------------------------------------------------------------
// Housing for a rubber foot.
//-------------------------------------------------------------------------
module rubber_foot(d1, d2, h) {
    $fn = 48;
    difference() {
        cylinder(r=(d1 / 2), h=h);
        translate([0, 0, -overcut]) cylinder(r=(d2 / 2), h=(h + overcut * 2));
    }
}

//-------------------------------------------------------------------------
// Housings for rubber feet (grows towards negative z axis).
//-------------------------------------------------------------------------
module box_feet(x, y, margin) {
    d1 = 11.0;
    d2 =  8.2;
    h  =  0.8;
    translate([margin,     margin,     -h]) rubber_foot(d1, d2, h + overlap);
    translate([x - margin, margin,     -h]) rubber_foot(d1, d2, h + overlap);
    translate([x - margin, y - margin, -h]) rubber_foot(d1, d2, h + overlap);
    translate([margin,     y - margin, -h]) rubber_foot(d1, d2, h + overlap);
}

//-------------------------------------------------------------------------
// Flange for screw hole.
//-------------------------------------------------------------------------
module screw_flange(r, t) {
    $fn = 60;
    r1 = r * 1.1;
    difference() {
        intersection() {
            cylinder(r=r1, h=t);
            union() {
                translate([r, r, 0]) cylinder(r=r, h=t);
                translate([r, 0, 0]) cube([r, r, t]);
                translate([0, r, 0]) cube([r, r, t]);}}
        translate([r1 / 2, r1 / 2, -overcut]) cylinder(r=1, h=(t + overcut * 2), $fn=24);
    }
}

//-------------------------------------------------------------------------
// Add a flange to the rounded_box() module.
//-------------------------------------------------------------------------
module rounded_box_flange(x, y, z, r) {
    w = 1.5;
    difference() {
        rounded_cube(x_size, y_size, z, r);
        translate([w, w, -overcut])
            rounded_cube(x_size - w * 2, y_size - w * 2, z + overcut * 2, r);
    }
    translate([0, 0, 0]) rotate(a=0 ,  v=[0, 0, 1]) screw_flange(r, z);
    translate([x, 0, 0]) rotate(a=90,  v=[0, 0, 1]) screw_flange(r, z);
    translate([x, y, 0]) rotate(a=180, v=[0, 0, 1]) screw_flange(r, z);
    translate([0, y, 0]) rotate(a=270, v=[0, 0, 1]) screw_flange(r, z);
}

//-------------------------------------------------------------------------
// Round cable grommet.
//-------------------------------------------------------------------------
module cable_grommet(h, d1, d2) {
    $fn = 32;
    cut_width = 3;
    difference() {
        union() {
            cylinder(r=(d1 / 2), h=h);
            translate([0, 0, h - 2.4]) cylinder(r=((d1 + 1.0) / 2), h=2.4);
        }
        translate([0, 0, -overcut]) cylinder(r=(d2 / 2), h=(h + 2 * overcut));
        translate([(d2 / 4), -(d1 / 2), h - (cut_width + 2.5)])
            cube([(d1 / 2), d1, cut_width]);
    }
}

//-------------------------------------------------------------------------
// Rectangular cable grommet with chamfer.
// h = height, x, y = hole inner size, r = chamfer radius, t = thickness
//-------------------------------------------------------------------------
module cable_grommet_rect(h, x, y, r, t) {
    cut_width = 3;
    difference() {
        union() {
            translate([-x / 2, -y / 2, 0]) rounded_cube_border(x, y, h, r, t);
            translate([-x / 2, -y / 2, h - 2.4]) rounded_cube_border(x, y, 2.4, r, t + 0.5);
        }
        translate([-(x / 2) - t - overcut, 0, h - (cut_width + 2.5)])
            cube([x + (t + overcut) * 2, y / 2 + t + overcut, cut_width]);
    }
}

//-------------------------------------------------------------------------
// Drill a screw hole with cuts for horizontal and vertical wall mount.
// Screw body diameter is d, head diameter will be d * 2.
//-------------------------------------------------------------------------
module screw_hole(d, depth) {
    $fn = 32;
    hole_depth = depth + overcut * 2;
    hole_bottom = -(depth + overcut);
    cut_length = d * 2;
    union() {
        translate([0, 0, hole_bottom])                  cylinder(r=d, h=hole_depth);
        translate([-(d / 2), 0, hole_bottom])           cube([d, cut_length, hole_depth]);
        translate([-cut_length, -(d / 2), hole_bottom]) cube([cut_length, d, hole_depth]);
        translate([0, cut_length, hole_bottom])         cylinder(r=(d / 2), h=hole_depth);
        translate([-cut_length, 0, hole_bottom])        cylinder(r=(d / 2), h=hole_depth);
    }
}

//-------------------------------------------------------------------------
// Build a cap to place over a screw hole.
// Screw body diameter = d
// Screw head diameter = d * 2
// Screw head height   = d * 0.6
//-------------------------------------------------------------------------
module screw_hole_cap(d, thick) {
    $fn = 36;
    pin_radius = thick * 1;
    pin_heigh = (d * 0.6) + (overlap * 2);
    pin_base = -overlap;
    size = (d * 4) + (pin_radius * 2);
    translate([-size + d + (pin_radius * 2), -d - (pin_radius * 2), 0]) {
        union() {
            translate([0, 0, d * 0.6]) {
                rounded_cube(size, size, thick, thick);
            }
            translate([pin_radius, pin_radius, pin_base])               cylinder(r=pin_radius, h=pin_heigh);
            translate([size - pin_radius, pin_radius, pin_base])        cylinder(r=pin_radius, h=pin_heigh);
            translate([size - pin_radius, size - pin_radius, pin_base]) cylinder(r=pin_radius, h=pin_heigh);
            translate([pin_radius, size - pin_radius, pin_base])        cylinder(r=pin_radius, h=pin_heigh);
        }
    }
}

//-------------------------------------------------------------------------
// Make a box with the requested internal size and rounded corners.
// The origin is the lower-left internal corner.
//-------------------------------------------------------------------------
module rounded_box(x_size, y_size, z_size, chamfer, thick) {
    cover_thick = 2;
    union() {
        translate([-overlap, -overlap, -thick])
            rounded_cube(x_size + overlap * 2, y_size + overlap * 2, thick, chamfer + overlap);
        translate([0, 0, -thick])
            rounded_cube_border(x_size, y_size, z_size + thick, chamfer, thick);
        translate([-overlap, -overlap, z_size - cover_thick - thick])
            rounded_box_flange(x_size + overlap * 2, y_size + overlap * 2, thick, chamfer + overlap);
        translate([0, 0, -thick])
            box_feet(x_size, y_size, 10);
        // Draw the box cover, for dimension testing.
        //translate([0, 0, z_size - cover_thick])
        //    %rounded_cube(x_size, y_size, cover_thick, chamfer);
    }
}

//-------------------------------------------------------------------------
// Make a box with rounded corners and required holes.
//-------------------------------------------------------------------------
module rounded_box_holes(x_size, y_size, z_size, chamfer, thick) {

    holes_diam = 3.5;

    // Boiler cable grommet.
    translate([bcable_x, bcable_y, bcable_z])
        rotate(a=180, v=[0, 1, 0])
            rotate(a=270, v=[1, 0, 0])
                cable_grommet_rect(bcable_h, bcable_d1, bcable_d2, bcable_r, bcable_t);

    // Temperature sensor cable grommet.
    translate([tsensor_x, tsensor_y, tsensor_z])
        rotate(a=90, v=[1, 0, 0])
            rotate(a=90, v=[0, 1, 0])
                cable_grommet(tsensor_h, tsensor_d1, tsensor_d2);

    difference() {
        rounded_box(x_size, y_size, z_size, chamfer, thick);

        // Bottom venting holes.
        translate([x_size / 2, 0, z_size / 2])
            rotate(a=90, v=[1, 0, 0]) vent_holes(12, 3, holes_diam, thick);

        // Top venting holes.
        translate([x_size / 2, y_size + thick, z_size / 2])
            rotate(a=90, v=[1, 0, 0]) vent_holes(11, 3, holes_diam, thick);

        // Backplane venting holes.
        translate([83, 88, -thick]) vent_holes(8, 6, holes_diam, thick);
        translate([25, 38, -thick]) vent_holes(5, 4, holes_diam, thick);

        // Mounting screw holes.
        translate([x_size / 2, screw_hole1_y, 0]) screw_hole(screw_diam, thick);
        translate([x_size / 2, screw_hole2_y, 0]) screw_hole(screw_diam, thick);

        // Temperature sensor hole.
        translate([-(thick + overcut), tsensor_y, tsensor_z])
            rotate(a=90, v=[0, 1, 0]) cylinder(r=(tsensor_d2 / 2), h=(thick + overcut * 2), $fn=24);

        // Bush-button hole.
        translate([button_x - overcut, button_y, button_z])
            rotate(a=90, v=[0, 1, 0]) cylinder(r=(button_d / 2), h=(thick + overcut * 2), $fn=24);

        // Power socket hole.
        translate([psocket_x, overcut, psocket_z])
            rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2), h=(thick + overcut * 2), $fn=24);

        // Boiler cable hole.
        translate([bcable_x, bcable_y - overcut, bcable_z])
            rotate(a=270, v=[1, 0, 0]) rounded_cube_centered(bcable_d1, bcable_d2, bcable_h + overcut * 2, bcable_r);

    }

    // Reinforce for power socket hole.
    difference() {
        translate([psocket_x, 0, psocket_z]) rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2) + 2.5, h=thick);
        translate([psocket_x, overcut, psocket_z])
            rotate(a=90, v=[1, 0, 0]) cylinder(r=(psocket_d / 2), h=(thick + overcut * 2), $fn=24);
    }

    // Reinforce for boiler cable hole.
    difference() {
        translate([bcable_x, 0, bcable_z])
            rotate(a=90, v=[1, 0, 0]) rounded_cube_centered(bcable_d1 + 5.5, bcable_d2 + 5.5, thick, 3);
        translate([bcable_x, overcut, bcable_z])
            rotate(a=90, v=[1, 0, 0]) rounded_cube_centered(bcable_d1, bcable_d2, (thick + overcut * 2), bcable_r);
    }

    // Add mounting screws holes.
    translate([x_size / 2, screw_hole1_y, 0]) screw_hole_cap(screw_diam, 1.7);
    translate([x_size / 2, screw_hole2_y, 0]) screw_hole_cap(screw_diam, 1.7);
}

//-------------------------------------------------------------------------
// Screw stub: d1 is the outer diameter, d2 is the screw diameter.
// The stub height must be grather than the depth of the hole.
//-------------------------------------------------------------------------
module stub(d1, height, d2, hole_depth) {
    $fn = 36;
    // The hole for a self-tapping screw is narrower than the screw.
    hole_diameter = d2 * 0.75;
    difference() {
        translate([0, 0, -overlap]) {
            union() {
                cylinder(r=(d1 / 2), h=(height + overlap));
                cylinder(r1=(d1 * 0.7), r2=(d1 / 2), h=(4 + overlap));
            }
        }
        translate([0, 0, height - hole_depth])
            cylinder(r=(hole_diameter / 2), h=(hole_depth + overcut));
    }
}

//-------------------------------------------------------------------------
// Drill a grid of rows x columns vent holes. Each hole has the
// specified diameter and depth, the grid is centered into the origin.
//-------------------------------------------------------------------------
module vent_holes(x, y, diameter, depth) {
    $fn = 6; // 18 = rounded holes, 6 = hexagonal
    step = diameter * 2;
    radius = diameter / 1.8;  // Divide by 2.0 if rounded holes, 1.8 if hexagonal.
    offset_x = (step * (x - 1)) / 2;
    offset_y = (step * (y - 1)) / 2;
    for (i = [1:x]) {
        for (j = [1:y]) {
            translate([(i - 1) * step - offset_x, (j -1) * step - offset_y, -overcut])
              cylinder(r=radius, h=(depth + overcut * 2));
        }
    }
    for (i = [1:x-1]) {
        for (j = [1:y-1]) {
            translate([(i - 1) * step - offset_x + step / 2, (j -1) * step - offset_y + step / 2, -overcut])
                cylinder(r=radius, h=(depth + overcut * 2));
        }
    }
}

//-------------------------------------------------------------------------
// Screw stubs for relay board (SainSmart like manufacturer).
//-------------------------------------------------------------------------
module stubs_2relays_sainsmart(height) {
    diameter = 7;
    screw_diameter = 2.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([2.75, 2.75, 0]) {
        translate([ 0,      0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([33.5,    0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([0,    45.5, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([33.5, 45.5, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for relay board (Keyes manufacturer).
//-------------------------------------------------------------------------
module stubs_2relays_keyes(height) {
    diameter = 7;
    screw_diameter = 3.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([3.5, 9, 0]) {
        translate([ 0,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([38,  0, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([0,  40, 0]) stub(diameter, height, screw_diameter, hole_depth);
        translate([38, 40, 0]) stub(diameter, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for PCD8544 LCD (Nokia 5110/3310), blue PCB model.
//-------------------------------------------------------------------------
module stubs_pcd8544_blue(h) {
    diameter = 6.5;
    screw_diameter = 2.5;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([4.25, 2.25, 0]) {
        translate([ 0,    0, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([34.5,  0, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([0,    41, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([34.5, 41, 0]) stub(diameter, h, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for PCD8544 LCD (Nokia 5110/3310), red PCB model.
//-------------------------------------------------------------------------
module stubs_pcd8544_red(h) {
    diameter = 6.0;
    screw_diameter = 2.0;
    hole_depth = 6;
    // Offset of first (lower left) hole from edge.
    translate([1.75, 2.0, 0]) {
        translate([ 0,  0, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([40,  0, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([ 0, 39, 0]) stub(diameter, h, screw_diameter, hole_depth);
        translate([40, 39, 0]) stub(diameter, h, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Screw stubs for Raspberry Pi Model B v.2.
//-------------------------------------------------------------------------
module stubs_raspberrypi_model_b_v2(height) {
    screw_diameter = 2.5;
    hole_depth = 6;
    translate([38, 25.5, 0]) {
        translate([    0,    0, 0]) stub(6.5, height, screw_diameter, hole_depth);
        translate([-25.5, 54.5, 0]) stub(6.5, height, screw_diameter, hole_depth);
    }
}

//-------------------------------------------------------------------------
// Main procedure.
//-------------------------------------------------------------------------
translate([-(x_size / 2), -(y_size/2), 0]) {
    rounded_box_holes(x_size, y_size, z_size, chamfer, thick);
    translate([ 5, 12,  0.0]) stubs_2relays_sainsmart(5.0);
    translate([ 8, 90,  0.0]) stubs_pcd8544_red(20.5); // Non diminuire Y sennò tocca il coprivite!
    translate([55, 37,  0.0]) stubs_raspberrypi_model_b_v2(5.0);
    //translate([55, 37 , 5.0]) board_raspberrypi_model_b_v2();
    //translate([ 8, 90, 20.5]) board_pcd8544_red();
    //translate([ 5, 12,  5.0]) board_2relays_sainsmart();
    //translate([button_x, button_y, button_z]) rotate(a=90, v=[0, 1, 0]) push_button();
    //translate([psocket_x, -thick, psocket_z]) rotate(a=90, v=[1, 0, 0]) coax_power_jack();
}

include <RigacciOrg.scad>;
translate([-x_size / 2 - thick + overlap, -29, 13])
    rotate(a=270, v=[0,0,1]) rotate(a=90, v=[1,0,0]) {
        //#cube([55, 12.54, 0.5], center=true);
        RigacciOrg(0.5);
    }

include <ccbysa.scad>;
translate([-x_size / 2 - thick + overlap, 34, 13])
    rotate(a=270, v=[0,0,1]) rotate(a=90, v=[1,0,0]) {
        //#cube([35.60, 12.54, 0.5], center=true);
        ccbysa(0.5);
    }


pulley: use material module

pulley: use material module

include <units.scad>
include <materials.scad>
use <shapes.scad>

// h, full_h, inner_d, outer_d, walls, bore
pulley_2GT_20T_idler = [8.65*mm, U, 12*mm, 18*mm, 1*mm, 5*mm];
pulley_2GT_20T       = [8.65*mm, 16*mm, 12*mm, 16*mm, 1.15*mm, 5*mm];

function pulley_height(pulley) = pulley[1]==U?pulley[0]:pulley[1];

module pulley(pulley=pulley_2GT_20T, flip=false, align=N, orient = Z)
{
    is_idler = pulley[1] == U;
    pulley_full(
            is_idler=is_idler,
            h=pulley[0],
            full_h=is_idler?U:pulley[1],
            inner_d=pulley[2],
            outer_d=pulley[3],
            walls=pulley[4],
            bore=pulley[5],
            flip=flip,
            align=align,
            orient=orient
            );
}

module pulley_full(h, inner_d, outer_d, bore, walls, is_idler=false, full_h, flip=false, align=N, orient = Z)
{
    material(Mat_Aluminium)
    size_align(size=[outer_d, outer_d, full_h==U?h:full_h], align=align, orient=orient)
    {
        //for flipping
        mirror([0,0,flip?-1:0])
        //center
        translate([0,0,full_h==U?-h/2:-full_h/2])
        difference()
        {
            union()
            {
                cylindera(d = outer_d, h = walls, align=Z, orient=Z);

                translate(N)
                cylindera(d = inner_d, h = h, align=Z, orient=Z);

                translate([0,0,h-walls])
                cylindera(d = outer_d, h = walls, align=Z, orient=Z);

                translate([0,0,h])
                if(!is_idler)
                {
                    cylindera(d = outer_d, h = full_h-h, align=Z, orient=Z);
                }
            }
            translate([0,0,-.1])
            cylindera(d = bore, h = full_h+.2, align=Z, orient=Z);
        }
    }
}

if(false)
{
    /*pulley(pulley_2GT_20T_idler, align=Z, orient=Z);*/
    pulley(pulley_2GT_20T, align=Z, orient=-Z, flip=false);
    /*pulley(pulley_2GT_20T, align=-Z, orient=Z, flip=false);*/
}

include <units.scad>
use <shapes.scad>

// h, full_h, inner_d, outer_d, walls, bore
pulley_2GT_20T_idler = [8.65*mm, U, 12*mm, 18*mm, 1*mm, 5*mm];
pulley_2GT_20T       = [8.65*mm, 16*mm, 12*mm, 16*mm, 1.15*mm, 5*mm];

function pulley_height(pulley) = pulley[1]==U?pulley[0]:pulley[1];

module pulley(pulley=pulley_2GT_20T, flip=false, align=N, orient = Z)
{
    is_idler = pulley[1] == U;
    pulley_full(
            is_idler=is_idler,
            h=pulley[0],
            full_h=is_idler?U:pulley[1],
            inner_d=pulley[2],
            outer_d=pulley[3],
            walls=pulley[4],
            bore=pulley[5],
            flip=flip,
            align=align,
            orient=orient
            );
}

module pulley_full(h, inner_d, outer_d, bore, walls, is_idler=false, full_h, flip=false, align=N, orient = Z)
{
    size_align(size=[outer_d, outer_d, full_h==U?h:full_h], align=align, orient=orient)
    {
        //for flipping
        mirror([0,0,flip?-1:0])
        //center
        translate([0,0,full_h==U?-h/2:-full_h/2])
        difference()
        {
            union()
            {
                cylindera(d = outer_d, h = walls, align=Z, orient=Z);

                translate(N)
                cylindera(d = inner_d, h = h, align=Z, orient=Z);

                translate([0,0,h-walls])
                cylindera(d = outer_d, h = walls, align=Z, orient=Z);

                translate([0,0,h])
                if(!is_idler)
                {
                    cylindera(d = outer_d, h = full_h-h, align=Z, orient=Z);
                }
            }
            translate([0,0,-.1])
            cylindera(d = bore, h = full_h+.2, align=Z, orient=Z);
        }
    }
}

if(false)
{
    /*pulley(pulley_2GT_20T_idler, align=Z, orient=Z);*/
    pulley(pulley_2GT_20T, align=Z, orient=-Z, flip=false);
    /*pulley(pulley_2GT_20T, align=-Z, orient=Z, flip=false);*/
}


The beginning of support for iPhone 6 plus...

// Description: Tapster Base Plate - plus sized for iPhone and Note 4
// Project home: http://tapsterbot.com

beam_width    = 8;
hole_diameter = 5.2;
hole_radius   = hole_diameter / 2;

module beam(number_of_holes) {
    beam_length = number_of_holes * 8;
    for (x=[beam_width/2 : beam_width*1 : beam_length]) {
        translate([x-4,beam_width/2-4,-2])
        cylinder(r=hole_radius, h=12, $fn=30);
    }
}

module joint(){
    translate([-20.5,-85-13,-4])
    cube([5,9.1,12]);

    translate([15.5,-85-13,-4])
    cube([5,9.1,12]);

    translate([0,-beam_width*11.5,-10])
    cylinder(r=hole_radius, h=25, $fn=30);
}

// Uncomment 'projection' to create 2D (DXF-able) version
projection(cut=true, center=true) {
difference(){
    cylinder(r=beam_width*14, h=4, $fn=6);
    //cylinder(r=beam_width*11+2, h=4, $fn=30);

    joint();

    rotate(120)
    joint();

    rotate(240)
    joint();

    box();
}
}

module box(){
    translate([-beam_width*5,-beam_width*10+4,-2])
    beam(11);

    translate([-beam_width*5,beam_width*11+4,-2])
    beam(11);

    rotate(90)
    translate([-beam_width*9+4,beam_width*6,-2])
    beam(20);

    rotate(90)
    translate([-beam_width*9+4,-beam_width*6,-2])
    beam(20);
}

error: pathspec 'hardware/tapster-2-plus/scad/base.scad' did not match any file(s) known to git