Printable version of the as yet unnamed one-handed typing device which has been submitted to Shapeways

function pythag(a, b) = sqrt(a*a + b*b);
function angle(a, b) = atan(a/b);

visualizeInternalComponents = false;

// this is the accuracy value for Shapeways' "Strong & Flexible Plastics" option
error = 0.15;

error2 = error * 2;

// note: AFAIK, "clearance" is a minimum gap in printed parts.  Here, however, it is used
// as a lesser/safer accuracy for gaps between the printed part and foreign objects such as
// circuit boards, which may not have been cut or measured with the same degree of precision.
clearance = 0.5;

pinHoleRes = 10;
/*
cornerRoundingRes = 50;
connectorPinRes = 50;
ledHoleRes = 50;
//*/
//*
cornerRoundingRes = 10;
connectorPinRes = 10;
ledHoleRes = 10;
//*/
containmentWallThick = 1;

nanoLength = 43.2;
nanoWidth = 18.0;
nanoHeightWithoutUsb = 5.4;
nanoHeightToUsbBase = 3.3;
nanoUsbWidth = 7.6;
nanoUsbHeight = 3.9;
nanoLeftMargin = 5;

chargerHeaderLength = 5.1;
chargerHeaderWidth = 2.6;

powerSwitchLength = 11.6;
powerSwitchWidth = 4.0;
powerSwitchDepth = 7.5;
powerSwitchOffset = 12;

ledDomeRadius = 2.5;
ledRimRadius = 2.95;
ledRimThick = 1.0;

lidThick = 1.5;
floorThick = 1.5;

caseWidth = 70;
caseLength = 130;
thickestComponent = 7.9;
caseHeight = lidThick + floorThick + thickestComponent + 1;

wallThick = caseHeight/2;

echo("caseHeight: ", caseHeight);

pushButtonWellWidth = 7;
pushButtonHeight = 5.0;
pushButtonLegLength = 3.4;
pushButtonPressDepth = 0.25;
pushButtonWellDepth = 4.0;
pushButtonBaseThick = 1.5;

fingerHeightOffset = 5;
fingerWellDepth = 10;
fingerRad = 15;
thumbWellDepth = wallThick;
thumbWellRadius = 30;
buttonThick = 8;
buttonWidth = pushButtonWellWidth;
fingerButtonLength = 25;
thumbButtonLength = 30;
buttonStabilizerWellWidth = 3;
buttonClearance = 0.3;  // horizontal clearance between button and walls
buttonLip = 2.5;
buttonSlack = 0.5;  // minimum vertical clearance between button and floor/retainers
buttonRetainerThick = 1.0;
buttonStabilizerRodHeight = pushButtonHeight - (pushButtonPressDepth + buttonSlack + error2);
totalFingerWellDepth = fingerWellDepth + buttonThick/2 + pushButtonPressDepth + pushButtonWellDepth;
totalThumbWellDepth = thumbWellDepth + buttonThick/2 + pushButtonPressDepth + pushButtonWellDepth;

pinHoleRadius = 0.8;

thumbBevelLength = 48;
thumbBevelWidth = 31;
thumbBevelBuffer = 2;

thumbBevelAngle = angle(thumbBevelLength-wallThick,thumbBevelWidth-wallThick);
thumbBevelStretch = pythag(thumbBevelLength-wallThick, thumbBevelWidth-wallThick);

thumbKeyOffset = 27;

cavityWidth = caseWidth - wallThick - totalFingerWellDepth - pushButtonBaseThick;
cavityLength = caseLength - (2 * wallThick);

module button(length) {
    difference() {
        union() {
                    // rounded cap
                    translate([buttonClearance,buttonWidth/2,buttonWidth/2]) {
                        rotate([0,90,0]) { cylinder(h=length-2*buttonClearance,r=buttonWidth/2-buttonClearance, $fn=cornerRoundingRes); }
                    }

                    // button body
                    translate([buttonClearance,buttonClearance,buttonWidth/2]) {
                        cube([length-2*buttonClearance,buttonWidth-2*buttonClearance,buttonThick-buttonWidth/2]);
                    }

                    // stabilizer rods
                    translate([buttonClearance,buttonClearance,buttonThick]) {
                        cube([buttonStabilizerWellWidth-2*buttonClearance, buttonWidth-2*buttonClearance, buttonStabilizerRodHeight]);
		            }
                    translate([length-buttonStabilizerWellWidth+buttonClearance,buttonClearance,buttonThick]) {
                        cube([buttonStabilizerWellWidth-2*buttonClearance, buttonWidth-2*buttonClearance, buttonStabilizerRodHeight]);
		            }
                    // retainer rods
                    translate([buttonClearance,buttonClearance,buttonThick+pushButtonHeight-pushButtonWellDepth+buttonRetainerThick+buttonSlack+error2]) {
                        cube([buttonStabilizerWellWidth+buttonLip-2*buttonClearance,buttonWidth-2*buttonClearance, 1]);
                    }
                    translate([length-buttonStabilizerWellWidth-buttonLip+buttonClearance,buttonClearance,buttonThick+pushButtonHeight-pushButtonWellDepth+buttonRetainerThick+buttonSlack+error2]) {
                        cube([buttonStabilizerWellWidth+buttonLip-2*buttonClearance,buttonWidth-2*buttonClearance, 1]);
                    }
        }

	// hollow out the button to save plastic/money
        translate([0,buttonWidth/2,buttonWidth/2]) {
            rotate([0,90,0]) { cylinder(h=length+1,r=buttonWidth/3); }
        }
    }
}

// button well with origin at the center of the base of the switch
// legs of the switch run along the x axis
module pushButtonWell(length, depth) {
    translate([-pushButtonWellWidth/2, -pushButtonWellWidth/2, 0]) {

		// square well for body of switch
        cube([pushButtonWellWidth,pushButtonWellWidth, depth]);

		// channels for legs/wires of switch
        translate([0,0,-pushButtonLegLength]) {
                translate([0,0,0]) {
                    cube([1.5,1.5,depth+pushButtonLegLength]);
                }
                translate([pushButtonWellWidth-1.5,0, 0]) {
                    cube([1.5,1.5,depth+pushButtonLegLength]);
                }
                translate([0,pushButtonWellWidth-1.5, 0]) {
                    cube([1.5,1.5,depth+pushButtonLegLength]);
                }
                translate([pushButtonWellWidth-1.5,pushButtonWellWidth-1.5, 0]) {
                    cube([1.5,1.5,depth+pushButtonLegLength]);
                }
        }
    }

    // rectangular well for button body, and stabilizer wells
    translate([-length/2,-buttonWidth/2,pushButtonWellDepth]) {
        cube([length,buttonWidth,buttonThick+10]);

        translate([0,0,-pushButtonWellDepth]) {
            cube([buttonStabilizerWellWidth, buttonWidth, pushButtonWellDepth]);

            cube([buttonStabilizerWellWidth+buttonLip, buttonWidth, pushButtonWellDepth-buttonRetainerThick]);
		}

        translate([length-buttonStabilizerWellWidth,0,-pushButtonWellDepth]) {
            cube([buttonStabilizerWellWidth, buttonWidth, pushButtonWellDepth]);

            translate([-buttonLip,0,0]) {
                cube([buttonStabilizerWellWidth+buttonLip, buttonWidth, pushButtonWellDepth-buttonRetainerThick]);
            }
		}
    }
}

module fingerWell(depth, radius) {
    translate([radius - depth,0,0]) {
        cylinder(h=caseHeight,r=radius, $fn=cornerRoundingRes);
    }

    translate([radius - depth, 0, wallThick]) {
        cylinder(h=wallThick+.001, r1=radius-wallThick/2, r2=radius+wallThick/2, $fn=cornerRoundingRes);
    }

    translate([radius - depth,0,0]) {
        cylinder(h=wallThick+.001, r2=radius-wallThick/2, r1=radius+wallThick/2, $fn=cornerRoundingRes);
    }
}

module pinHole() {
    cylinder(h=caseHeight+2,r=pinHoleRadius, $fn=pinHoleRes);
}

module pinHoles() {
    translate([0,0,-1]) {

        for (i = [0:4]) {
            translate([wallThick+cavityWidth+3,caseLength-fingerHeightOffset-fingerRad*i*2,0]) { pinHole(); }
            //translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,0]) { pinHole(); }

        }

        for (i = [1:4]) {
            translate([wallThick*2/3,wallThick*2/3 + i*(caseLength-thumbBevelLength - wallThick*2/3)/4,0]) {
                pinHole();
            }
        }
        translate([12,caseLength-thumbBevelLength+2,0]) {
            pinHole();
        }
        translate([thumbBevelWidth, caseLength-wallThick*2/3,0]) {
            pinHole();
        }
        translate([thumbBevelWidth, caseLength-15, 0]) {
            pinHole();
        }
        translate([wallThick*2/3,10,0]) {
            pinHole();
        }
        translate([10,wallThick*2/3,0]) {
            pinHole();
        }
        translate([wallThick+cavityWidth-nanoLeftMargin-nanoWidth/2-8,wallThick*2/3,0]) {
            pinHole();
        }
        translate([wallThick+cavityWidth-nanoLeftMargin-nanoWidth/2+8,wallThick*2/3,0]) {
            pinHole();
        }
    }
}

module caseConvexHull() {
		// box with thumb bevel
        difference() {
            translate([wallThick, wallThick,0]) {
                cube([caseWidth-caseHeight,caseLength-caseHeight,caseHeight]);
            }
            translate([thumbBevelWidth,caseLength-wallThick,-1]) {
                rotate([0,0,thumbBevelAngle]) {
                    rotate([0,-90,0]) {
                        cube([caseHeight+1, 100, thumbBevelStretch]);
                    }
                }
            }
        }

        translate([wallThick,wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([-90,0,0]) {
                cylinder(h=caseLength-thumbBevelLength-wallThick, r=wallThick, $fn=cornerRoundingRes);
            }
            rotate([0,90,0]) {
                cylinder(h=caseWidth-caseHeight, r=wallThick, $fn=cornerRoundingRes);
            }
        }
        translate([caseWidth-wallThick,wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([-90,0,0]) {
                cylinder(h=caseLength-caseHeight, r=wallThick, $fn=cornerRoundingRes);
            }
        }
        translate([caseWidth-wallThick,caseLength-wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
        }

		// thumb bevel
		translate([wallThick,caseLength-thumbBevelLength,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
        }
        translate([thumbBevelWidth,caseLength-wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([0,90,0]) {
                cylinder(h=caseWidth-thumbBevelWidth-wallThick, r=wallThick, $fn=cornerRoundingRes);
            }
            rotate([0,0,180+thumbBevelAngle]) {
                rotate([0,90,0]) {
                    cylinder(h=thumbBevelStretch, r=wallThick, $fn=cornerRoundingRes);
                }
            }
        }
}

module basicCase() {
  difference() {
    caseConvexHull();

    // inner compartment
    translate([wallThick,wallThick,lidThick]) {
        cube([cavityWidth,caseLength-thumbBevelLength-wallThick,caseHeight-floorThick-lidThick]);
    }
    translate([thumbBevelWidth+thumbBevelBuffer,wallThick,lidThick]) {
        cube([cavityWidth-thumbBevelWidth+wallThick-thumbBevelBuffer,cavityLength,caseHeight-floorThick-lidThick]);
    }

    pinHoles();

    // finger button wells
    for (i = [0:3]) {
        translate([
            caseWidth,
            caseLength - fingerHeightOffset - fingerRad * (1 + 2 * i),
        0]) {

            fingerWell(fingerWellDepth, fingerRad);

            // well and channels for push button switch and wires
            translate([-totalFingerWellDepth,0,caseHeight/2]) {
                rotate([0,90,0]) { rotate([0,0,90]) {
                    pushButtonWell(fingerButtonLength, pushButtonWellDepth+fingerRad);
                }}
            }
        }
    }

    // thumb button well
    translate([thumbBevelWidth,caseLength-wallThick,caseHeight]) {
        rotate([0,0,180+thumbBevelAngle]) {
            rotate([0,90,0]) {
                translate([0,0,thumbKeyOffset]) {
                    rotate([0,90,0]) { rotate([0,0,-90]) {
                        //cube([50,100,200]);

                        translate([wallThick,0,0]) {
                            fingerWell(thumbWellDepth, thumbWellRadius);
                        }
                    }}

                    rotate([0,90,-90]) {
                        translate([0,wallThick,wallThick-totalThumbWellDepth]) {
                            pushButtonWell(thumbButtonLength, pushButtonWellDepth+100);

                            rotate([180,0,0]) {
                                translate([-27,-wallThick+lidThick,pushButtonBaseThick]) {
                                    cube([42,caseHeight-floorThick-lidThick,15]);
                                    cube([22,caseHeight-floorThick-lidThick,20]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // hole for status LED
    translate([cavityWidth+wallThick-ledRimRadius-3,caseLength+1,wallThick]) {
    	    rotate(a=[90,0,0]) {
            cylinder(h=wallThick+2,r=ledDomeRadius+error, $fn=ledHoleRes);

            // note: the rim depression uses a larger error/clearance, since it doesn't need
            // to fit tightly and can't be filed down
            translate([0,0,-1+wallThick+ledRimThick]) {
                cylinder(h=10,r=ledRimRadius+clearance, $fn=20);
            }
        }
    }

    // hole for battery charger headers
	translate([wallThick+cavityWidth-chargerHeaderWidth-error2,0,caseHeight-floorThick-chargerHeaderLength-error2]) {
        cube([chargerHeaderWidth+error2,wallThick+1,chargerHeaderLength+error2]);
    }

    // hole for SPDT Mini Power Switch
    translate([powerSwitchOffset,0,wallThick-powerSwitchWidth/2-error]) {
        cube([powerSwitchLength+error2,wallThick+1,powerSwitchWidth+error2]);
    }

    // hole for USB port
    translate([wallThick+cavityWidth-nanoLeftMargin-nanoWidth/2-nanoUsbWidth/2-clearance,0,caseHeight-floorThick-nanoHeightToUsbBase-nanoUsbHeight-clearance]) {
        cube([nanoUsbWidth+2*clearance,wallThick+1,nanoUsbHeight+clearance]);
    }
  }
}

// body
difference() {
    union() {
        basicCase();
        translate([wallThick, wallThick, 0]) {
            cylinder(h=caseHeight-floorThick+0.001, r=3);
        }
    }
    cube([caseWidth, caseLength, (caseHeight-buttonWidth)/2+0.0001]);

    for (i = [0:4]) {
        translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,0]) {
            cylinder(h=caseHeight*2/3, r=1.5+error2, $fn=connectorPinRes);
        }
    }
    translate([thumbBevelWidth-3, caseLength-wallThick-6, 0]) {
        cylinder(h=caseHeight*2/3, r=1.5+error2, $fn=connectorPinRes);
    }
    translate([wallThick+2, caseLength-thumbBevelLength+3, 0]) {
        cylinder(h=caseHeight*2/3, r=1.5+error2, $fn=connectorPinRes);
    }
    translate([wallThick, wallThick, 0]) {
        cylinder(h=caseHeight*2/3, r=1.5+error2, $fn=connectorPinRes);
    }

    // screwdriver/leverage slots
    translate([wallThick,wallThick/2,(caseHeight-buttonWidth)/2]) {
        rotate([150,0,0]) { cube([5,10,10]); }
    }
    translate([wallThick+cavityWidth+3,wallThick/2,(caseHeight-buttonWidth)/2]) {
        rotate([150,0,0]) { cube([5,10,10]); }
    }
    translate([wallThick+cavityWidth+3,caseLength-wallThick/2,(caseHeight-buttonWidth)/2]) {
        rotate([-60,0,0]) { cube([5,10,10]); }
    }
}

// lid
translate([caseWidth + 10, 0, 0]) {
    difference() {
        basicCase();
        translate([0,0,(caseHeight-buttonWidth)/2]) {
            cube([caseWidth, caseLength, caseHeight]);
        }
    }

    for (i = [0:4]) {
        translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,lidThick]) {
            cylinder(h=caseHeight/3, r=1.5, $fn=connectorPinRes);
        }
    }
    translate([thumbBevelWidth-3, caseLength-wallThick-6, lidThick]) {
        cylinder(h=caseHeight/3, r=1.5, $fn=connectorPinRes);
    }
    translate([wallThick+2, caseLength-thumbBevelLength+3, lidThick]) {
        cylinder(h=caseHeight/3, r=1.5, $fn=connectorPinRes);
    }
    translate([wallThick, wallThick, lidThick]) {
        cylinder(h=caseHeight/3, r=1.5, $fn=connectorPinRes);
    }
}

// buttons
// Note: the buttons are oriented so as to make the longest surfaces the smoothest
translate([-10,0,10]) {
    for (i = [0:3]) {
        translate([0,i*(fingerButtonLength+2),0]) { rotate([90,180,-90]) {
            button(fingerButtonLength);
        }}
    }
}
translate([5,caseLength-35,10]) {
    rotate([90,180,-90]) {
        button(thumbButtonLength);
    }
}

// electronic components
translate([wallThick,wallThick,0]) {
    // container for power switch
    translate([powerSwitchOffset-wallThick,0,wallThick-powerSwitchWidth/2-error]) {
        translate([-containmentWallThick,0,0]) {
            cube([containmentWallThick,powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick+powerSwitchWidth/2+error]);
        }
        translate([powerSwitchLength+error2,0,0]) {
            cube([containmentWallThick,powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick+powerSwitchWidth/2+error]);
        }
        translate([-containmentWallThick,0,powerSwitchWidth+2*error]) {
            cube([powerSwitchLength+2*(containmentWallThick+error),powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick-powerSwitchWidth/2-error]);
        }
        translate([-containmentWallThick,powerSwitchDepth-wallThick+error,powerSwitchWidth+2*error-1]) {
            cube([powerSwitchLength+2*(containmentWallThick+error),containmentWallThick,1]);
        }
    }

    // container for Arduino Nano v3.0
    translate([cavityWidth-nanoLeftMargin-nanoWidth,0,0]) {
        translate([0,0,caseHeight-floorThick-nanoHeightToUsbBase-error]) {
            translate([-containmentWallThick-clearance,0,0]) {
                cube([containmentWallThick,nanoLength+clearance+containmentWallThick,nanoHeightToUsbBase+error]);
            }
            translate([nanoWidth+clearance,0,0]) {
                cube([containmentWallThick,nanoLength+clearance+containmentWallThick,nanoHeightToUsbBase+error]);
            }
            translate([-containmentWallThick-clearance,nanoLength+clearance,0]) {
                cube([nanoWidth+2*(clearance+containmentWallThick),containmentWallThick,nanoHeightToUsbBase+error]);
            }
        }
    }

    if (visualizeInternalComponents) {
        // Arduino Nano v3.0
        translate([cavityWidth-nanoLeftMargin-nanoWidth,0,-10]) {
            cube([nanoWidth,nanoLength,nanoHeightWithoutUsb]);
        }

        // Surface Transducer - Small
        translate([thumbBevelWidth-wallThick+4,caseLength-2*wallThick-21.4-4,-10]) {
           cube([13.8,21.4,7.9]);
        }
        // Bluetooth Modem - BlueSMiRF Silver -- 42.0 x 16.0 x 3.9
        translate([0,31,-10]) { cube([16,42,3.9]); }
        // Polymer Lithium Ion Battery - 110mAh
        translate([-40,0,-10]) { cube([12,28,5.7]); }
        // Polymer Lithium Ion Battery - 400mAh
	    translate([18,47,-10]) { cube([25,35,5]); }
        // Triple Axis Accelerometer & Gyro Breakout - MPU-6050
        translate([0,3,-10]) { cube([15.5, 25.7, 2.5]); }
    }
}

function pythag(a, b) = sqrt(a*a + b*b);
function angle(a, b) = atan(a/b);

visualizeInternalComponents = false;

// this is the accuracy value for Shapeways' "Strong & Flexible Plastics" option
error = 0.15;

error2 = error * 2;

// note: AFAIK, "clearance" is a minimum gap in printed parts.  Here, however, it is used
// as a lesser/safer accuracy for gaps between the printed part and foreign objects such as
// circuit boards, which may not have been cut or measured with the same degree of precision.
clearance = 0.5;

//cornerRoundingRes = 50;
cornerRoundingRes = 10;
pinHoleRes = 10;
//connectorPinRes = 50;
connectorPinRes = 10;
//ledHoleRes = 50;
ledHoleRes = 10;

containmentWallThick = 1;

nanoLength = 43.2;
nanoWidth = 18.0;
nanoHeightWithoutUsb = 5.4;
nanoHeightToUsbBase = 3.3;
nanoUsbWidth = 7.6;
nanoUsbHeight = 3.9;
nanoLeftMargin = 5;

chargerHeaderLength = 5.10;
chargerHeaderWidth = 2.56;

powerSwitchLength = 11.6;
powerSwitchWidth = 4.0;
powerSwitchDepth = 7.5;
powerSwitchOffset = 12;

ledDomeRadius = 2.5;
ledRimRadius = 2.9;

caseWidth = 70;
caseLength = 130;
caseHeight = 12;

wallThick = caseHeight/2;
lidThick = 1.5;
floorThick = 1.5;

pushButtonWellWidth = 7;
pushButtonHeight = 5.0;
pushButtonLegLength = 4;
pushButtonPressDepth = 0.3;
pushButtonWellDepth = 4;
pushButtonBaseThick = 1.5;

fingerHeightOffset = 5;
fingerWellDepth = 10;
fingerRad = 15;
thumbWellDepth = wallThick;
thumbWellRadius = 30;
buttonThick = 8;
buttonWidth = pushButtonWellWidth;
buttonLength = 25;
buttonStabilizerWellWidth = 3;
buttonClearance = 0.3;  // horizontal clearance between button and walls
buttonLip = 2.5;
buttonSlack = 0.5;  // minimum vertical clearance between button and floor/retainers
buttonRetainerThick = 1.0;
buttonStabilizerRodHeight = pushButtonHeight - (pushButtonPressDepth + buttonSlack + error);
totalFingerWellDepth = fingerWellDepth + buttonThick/2 + pushButtonPressDepth + pushButtonWellDepth;
totalThumbWellDepth = thumbWellDepth + buttonThick/2 + pushButtonPressDepth + pushButtonWellDepth;

pinHoleRadius = 0.8;

thumbBevelLength = 48;
thumbBevelWidth = 31;
thumbBevelBuffer = 2;

thumbBevelAngle = angle(thumbBevelLength-wallThick,thumbBevelWidth-wallThick);
thumbBevelStretch = pythag(thumbBevelLength-wallThick, thumbBevelWidth-wallThick);

thumbKeyOffset = 23;

cavityWidth = caseWidth - wallThick - totalFingerWellDepth - pushButtonBaseThick;
cavityLength = caseLength - (2 * wallThick);

module button() {
    difference() {
        union() {
                    // rounded cap
                    translate([buttonClearance,buttonWidth/2,buttonWidth/2]) {
                        rotate([0,90,0]) { cylinder(h=buttonLength-2*buttonClearance,r=buttonWidth/2-buttonClearance, $fn=cornerRoundingRes); }
                    }

                    // button body
                    translate([buttonClearance,buttonClearance,buttonWidth/2]) {
                        cube([buttonLength-2*buttonClearance,buttonWidth-2*buttonClearance,buttonThick-buttonWidth/2]);
                    }

                    // stabilizer rods
                    translate([buttonClearance,buttonClearance,buttonThick]) {
                        cube([buttonStabilizerWellWidth-2*buttonClearance, buttonWidth-2*buttonClearance, buttonStabilizerRodHeight]);
		            }
                    translate([buttonLength-buttonStabilizerWellWidth+buttonClearance,buttonClearance,buttonThick]) {
                        cube([buttonStabilizerWellWidth-2*buttonClearance, buttonWidth-2*buttonClearance, buttonStabilizerRodHeight]);
		            }
                    // retainer rods
                    translate([buttonClearance,buttonClearance,buttonThick+pushButtonHeight-pushButtonWellDepth+buttonRetainerThick+buttonSlack+error]) {
                        cube([buttonStabilizerWellWidth+buttonLip-2*buttonClearance,buttonWidth-2*buttonClearance, 1]);
                    }
                    translate([buttonLength-buttonStabilizerWellWidth-buttonLip+buttonClearance,buttonClearance,buttonThick+pushButtonHeight-pushButtonWellDepth+buttonRetainerThick+buttonSlack+error]) {
                        cube([buttonStabilizerWellWidth+buttonLip-2*buttonClearance,buttonWidth-2*buttonClearance, 1]);
                    }
        }

	// hollow out the button to save plastic/money
        translate([0,buttonWidth/2,buttonWidth/2]) {
            rotate([0,90,0]) { cylinder(h=buttonLength+1,r=buttonWidth/3); }
        }
    }
}

// button well with origin at the center of the base of the switch
// legs of the switch run along the x axis
module pushButtonWell(depth) {
    translate([-pushButtonWellWidth/2, -pushButtonWellWidth/2, 0]) {

		// square well for body of switch
        cube([pushButtonWellWidth,pushButtonWellWidth, depth]);

		// channels for legs/wires of switch
        translate([0,0,-pushButtonLegLength]) {
                translate([0,0,0]) {
                    cube([2,2,depth+pushButtonLegLength]);
                }
                translate([pushButtonWellWidth-2,0, 0]) {
                    cube([2,2,depth+pushButtonLegLength]);
                }
                translate([0,pushButtonWellWidth-2, 0]) {
                    cube([2,2,depth+pushButtonLegLength]);
                }
                translate([pushButtonWellWidth-2,pushButtonWellWidth-2, 0]) {
                    cube([2,2,depth+pushButtonLegLength]);
                }
        }
    }

    // rectangular well for button body, and stabilizer wells
    translate([-buttonLength/2,-buttonWidth/2,pushButtonWellDepth]) {
        cube([buttonLength,buttonWidth,buttonThick+pushButtonPressDepth+10]);
//        cube([buttonLength,buttonWidth,pushButtonWellDepth+buttonThick-buttonWidth/2+error]);

        translate([0,0,-pushButtonWellDepth]) {
            cube([buttonStabilizerWellWidth, buttonWidth, pushButtonWellDepth]);

            cube([buttonStabilizerWellWidth+buttonLip, buttonWidth, pushButtonWellDepth-buttonRetainerThick]);
		}

        translate([buttonLength-buttonStabilizerWellWidth,0,-pushButtonWellDepth]) {
            cube([buttonStabilizerWellWidth, buttonWidth, pushButtonWellDepth]);

            translate([-buttonLip,0,0]) {
                cube([buttonStabilizerWellWidth+buttonLip, buttonWidth, pushButtonWellDepth-buttonRetainerThick]);
            }
		}
    }
}

module fingerWell(depth, radius) {
    translate([radius - depth,0,0]) {
        cylinder(h=caseHeight,r=radius, $fn=cornerRoundingRes);
    }

    translate([radius - depth, 0, wallThick]) {
        cylinder(h=wallThick+.001, r1=radius-wallThick/2, r2=radius+wallThick/2, $fn=cornerRoundingRes);
    }

    translate([radius - depth,0,0]) {
        cylinder(h=wallThick+.001, r2=radius-wallThick/2, r1=radius+wallThick/2, $fn=cornerRoundingRes);
    }
}

module pinHole() {
    cylinder(h=caseHeight+2,r=pinHoleRadius, $fn=pinHoleRes);
}

module pinHoles() {
    translate([0,0,-1]) {

        for (i = [0:4]) {
            translate([wallThick+cavityWidth+3,caseLength-fingerHeightOffset-fingerRad*i*2,0]) { pinHole(); }
            //translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,0]) { pinHole(); }

        }

        for (i = [1:5]) {
            translate([wallThick*2/3,wallThick*2/3 + i*(caseLength-thumbBevelLength - wallThick*2/3)/5,0]) {
                pinHole();
            }
        }
        translate([15,caseLength-thumbBevelLength+3,0]) {
            pinHole();
        }

        translate([thumbBevelWidth, caseLength-wallThick*2/3,0]) {
            pinHole();
        }
        translate([thumbBevelWidth, caseLength-15, 0]) {
            pinHole();
        }
    }
}

module caseConvexHull() {
		// box with thumb bevel
        difference() {
            translate([wallThick, wallThick,0]) {
                cube([caseWidth-caseHeight,caseLength-caseHeight,caseHeight]);
            }
            translate([thumbBevelWidth,caseLength-wallThick,-1]) {
                rotate([0,0,thumbBevelAngle]) {
                    rotate([0,-90,0]) {
                        cube([caseHeight+1, 100, thumbBevelStretch]);
                    }
                }
            }
        }

        translate([wallThick,wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([-90,0,0]) {
                cylinder(h=caseLength-thumbBevelLength-wallThick, r=wallThick, $fn=cornerRoundingRes);
            }
            rotate([0,90,0]) {
                cylinder(h=caseWidth-caseHeight, r=wallThick, $fn=cornerRoundingRes);
            }
        }
        translate([caseWidth-wallThick,wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([-90,0,0]) {
                cylinder(h=caseLength-caseHeight, r=wallThick, $fn=cornerRoundingRes);
            }
        }
        translate([caseWidth-wallThick,caseLength-wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
        }

		// thumb bevel
		translate([wallThick,caseLength-thumbBevelLength,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
        }
        translate([thumbBevelWidth,caseLength-wallThick,wallThick]) {
            sphere(wallThick, $fn=cornerRoundingRes);
            rotate([0,90,0]) {
                cylinder(h=caseWidth-thumbBevelWidth-wallThick, r=wallThick, $fn=cornerRoundingRes);
            }
            rotate([0,0,180+thumbBevelAngle]) {
                rotate([0,90,0]) {
                    cylinder(h=thumbBevelStretch, r=wallThick, $fn=cornerRoundingRes);
                }
            }
        }
}

module basicCase() {
  difference() {
    caseConvexHull();

    // inner compartment
    translate([wallThick,wallThick,lidThick]) {
        cube([cavityWidth,caseLength-thumbBevelLength-wallThick,caseHeight-floorThick-lidThick]);
    }
    translate([thumbBevelWidth+thumbBevelBuffer,wallThick,lidThick]) {
        cube([cavityWidth-thumbBevelWidth+wallThick-thumbBevelBuffer,cavityLength,caseHeight-floorThick-lidThick]);
    }

    pinHoles();

    // finger button wells
    for (i = [0:3]) {
        translate([
            caseWidth,
            caseLength - fingerHeightOffset - fingerRad * (1 + 2 * i),
        0]) {

            fingerWell(fingerWellDepth, fingerRad);

            // well and channels for push button switch and wires
            translate([-totalFingerWellDepth,0,caseHeight/2]) {
                rotate([0,90,0]) { rotate([0,0,90]) {
                    pushButtonWell(pushButtonWellDepth+fingerRad);
                }}
            }
        }
    }

    // thumb button well
    translate([thumbBevelWidth,caseLength-wallThick,caseHeight]) {
        rotate([0,0,180+thumbBevelAngle]) {
            rotate([0,90,0]) {
                translate([0,0,thumbKeyOffset]) {
                    rotate([0,90,0]) { rotate([0,0,-90]) {
                        //cube([50,100,200]);

                        translate([wallThick,0,0]) {
                            fingerWell(thumbWellDepth, thumbWellRadius);
                        }
                    }}

                    rotate([0,90,-90]) {
                        translate([0,wallThick,wallThick-totalThumbWellDepth]) {
                            pushButtonWell(pushButtonWellDepth+100);

                            rotate([180,0,0]) {
                                translate([-27,-wallThick+lidThick,pushButtonBaseThick]) {
                                    cube([39,caseHeight-floorThick-lidThick,15]);
                                    cube([22,caseHeight-floorThick-lidThick,20]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // hole for status LED
    translate([cavityWidth+wallThick-ledRimRadius-3,caseLength+1,wallThick]) {
    	    rotate(a=[90,0,0]) {
            cylinder(h=wallThick+2,r=ledDomeRadius+error, $fn=ledHoleRes);

            // note: the rim depression uses a larger error/clearance, since it doesn't need
            // to fit tightly and can't be filed down
            translate([0,0,wallThick]) {
                cylinder(h=10+1,r=ledRimRadius+clearance, $fn=20);
            }
        }
    }

    // hole for battery charger headers
	translate([wallThick+cavityWidth-chargerHeaderWidth-2*error,0,caseHeight-floorThick-chargerHeaderLength-2*error]) {
        cube([chargerHeaderWidth+2*error,wallThick,chargerHeaderLength+2*error]);
    }

    // hole for SPDT Mini Power Switch
    translate([powerSwitchOffset,0,wallThick-powerSwitchWidth/2-error]) {
        cube([powerSwitchLength+2*error,wallThick,powerSwitchWidth+2*error]);
    }

    // hole for USB port
    translate([wallThick+cavityWidth-nanoLeftMargin-nanoWidth/2-nanoUsbWidth/2-clearance,0,caseHeight-floorThick-nanoHeightToUsbBase-nanoUsbHeight-clearance]) {
        cube([nanoUsbWidth+2*clearance,wallThick,nanoUsbHeight+clearance]);
    }
  }
}

// body
difference() {
    union() {
        basicCase();
        translate([wallThick, wallThick, 0]) {
            cylinder(h=caseHeight-floorThick+0.001, r=3);
        }
    }
    cube([caseWidth, caseLength, (caseHeight-buttonWidth)/2+0.0001]);

    for (i = [0:4]) {
        translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,0]) {
            cylinder(h=caseHeight/2+error2, r=1.5+error2, $fn=connectorPinRes);
        }
    }
    translate([thumbBevelWidth-3, caseLength-wallThick-6, 0]) {
        cylinder(h=caseHeight/2+error2, r=1.5+error2, $fn=connectorPinRes);
    }
    translate([wallThick+7, caseLength-thumbBevelLength+7, 0]) {
        cylinder(h=caseHeight/2+error2, r=1.5+error2, $fn=connectorPinRes);
    }
    translate([wallThick, wallThick, 0]) {
        cylinder(h=caseHeight/2+error2, r=1.5+error2, $fn=connectorPinRes);
    }
}

// lid
translate([caseWidth + 10, 0, 0]) {
    difference() {
        basicCase();
        translate([0,0,(caseHeight-buttonWidth)/2]) {
            cube([caseWidth, caseLength, caseHeight]);
        }
    }

    for (i = [0:4]) {
        translate([wallThick+cavityWidth+10,caseLength-fingerHeightOffset-fingerRad*i*2,0]) {
            cylinder(h=caseHeight/2, r=1.5, $fn=connectorPinRes);
        }
    }
    translate([thumbBevelWidth-3, caseLength-wallThick-6, 0]) {
        cylinder(h=caseHeight/2, r=1.5, $fn=connectorPinRes);
    }
    translate([wallThick+7, caseLength-thumbBevelLength+7, 0]) {
        cylinder(h=caseHeight/2, r=1.5, $fn=connectorPinRes);
    }
    translate([wallThick, wallThick, 0]) {
        cylinder(h=caseHeight/2, r=1.5, $fn=connectorPinRes);
    }
}

// buttons
// Note: the buttons are oriented so as to make the longest surfaces the smoothest
translate([-5,0,10]) {
    for (i = [0:4]) {
        translate([0,i*(buttonLength+2),0]) { rotate([90,180,-90]) {
            //cube([10,20,40]);

            button();
        }}
    }
}

// electronic components
translate([wallThick,wallThick,0]) {
    // power switch
    translate([powerSwitchOffset-wallThick,0,wallThick-powerSwitchWidth/2-error]) {
        translate([-containmentWallThick,0,0]) {
            cube([containmentWallThick,powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick+powerSwitchWidth/2+error]);
        }
        translate([powerSwitchLength+2*error,0,0]) {
            cube([containmentWallThick,powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick+powerSwitchWidth/2+error]);
        }
        translate([-containmentWallThick,0,powerSwitchWidth+2*error]) {
            cube([powerSwitchLength+2*(containmentWallThick+error),powerSwitchDepth-wallThick+error+containmentWallThick,caseHeight-floorThick-wallThick-powerSwitchWidth/2-error]);
        }
        translate([-containmentWallThick,powerSwitchDepth-wallThick+error,powerSwitchWidth+2*error-1]) {
            cube([powerSwitchLength+2*(containmentWallThick+error),containmentWallThick,1]);
        }
    }

    // container for Arduino Nano v3.0
    translate([cavityWidth-nanoLeftMargin-nanoWidth,0,0]) {
        translate([0,0,caseHeight-floorThick-nanoHeightToUsbBase-error]) {
            translate([-containmentWallThick-clearance,0,0]) {
                cube([containmentWallThick,nanoLength+clearance+containmentWallThick,nanoHeightToUsbBase+error]);
            }
            translate([nanoWidth+clearance,0,0]) {
                cube([containmentWallThick,nanoLength+clearance+containmentWallThick,nanoHeightToUsbBase+error]);
            }
            translate([-containmentWallThick-clearance,nanoLength+clearance,0]) {
                cube([nanoWidth+2*(clearance+containmentWallThick),containmentWallThick,nanoHeightToUsbBase+error]);
            }
        }
    }

    if (visualizeInternalComponents) {
        // Arduino Nano v3.0
        translate([cavityWidth-nanoLeftMargin-nanoWidth,0,-10]) {
            cube([nanoWidth,nanoLength,nanoHeightWithoutUsb]);
        }

        // Surface Transducer - Small
        translate([thumbBevelWidth-wallThick+4,caseLength-2*wallThick-21.4-4,-10]) {
           cube([13.8,21.4,7.9]);
        }
        // Bluetooth Modem - BlueSMiRF Silver -- 42.0 x 16.0 x 3.9
        translate([0,31,-10]) { cube([16,42,3.9]); }
        // Polymer Lithium Ion Battery - 110mAh
        translate([-40,0,-10]) { cube([12,28,5.7]); }
        // Polymer Lithium Ion Battery - 400mAh
	    translate([18,47,-10]) { cube([25,35,5]); }
        // Triple Axis Accelerometer & Gyro Breakout - MPU-6050
        translate([0,3,-10]) { cube([15.5, 25.7, 2.5]); }
    }
}


added slot gantry extrusion

added slot gantry extrusion

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


walls maked slimmer + fixed distances

walls maked slimmer + fixed distances


rod-clamps: use material system

rod-clamps: use material system

include <rod-clamps.h>

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

module mount_rod_clamp_half(part, rod_d=10, screw_dist=undef, width=4, thick=undef, base_thick=undef, thread=ThreadM4, align, orient, align_obj = "rod")
{
    thick_=thick==undef?rod_d:thick;
    outer_d= rod_d+thick_*2;
    thread_dia=lookup(ThreadSize, thread);
    screw_dist_=screw_dist==undef?outer_d+thread_dia+thick_:screw_dist;
    base_thick_=base_thick==undef?thick_*1.2:base_thick;
    clamp_tolerance = 0.5*mm;

    pos_offset = align_obj == "mount" ? N : N;

    if(part==undef)
    {
        difference()
        {
            mount_rod_clamp_half(part="pos", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
            mount_rod_clamp_half(part="neg", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
        if($show_vit)
        {
            %mount_rod_clamp_half(part="vit", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
    }
    else if(part=="pos")
    {
        s=[outer_d, base_thick_, width];
        material(Mat_Plastic)
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            /*hull()*/
            {
                // cylinder around rod
                rcylindera(d=outer_d, h=width, orient=Z, align=N);

                // base
                rcubea([base_thick_, screw_dist_+thread_dia*2.5, width], align=X);
            }
        }
    }
    else if(part=="neg")
    {
        s=[outer_d, base_thick_, width];
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            // cut bottom of cylinder
            cubea([outer_d/2+.1, screw_dist_+thread_dia*2.5+.1, width+1], align=[-1,0,0]);

            // cut clamp screw holes
            for(i=[-1,1])
            translate([0, i*screw_dist_/2, 0])
            {
                screw_cut(thread=thread, orient=-X);
            }

            // cut rod
            translate(-clamp_tolerance*X)
            cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
        }
    }
    else if(part=="vit")
    {
        s=[outer_d, base_thick_, width];
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            translate(-clamp_tolerance*X)
            cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
        }
    }
}

module mount_rod_clamp_full(part, rod_d=10, screw_dist=undef, width=4, thick=undef, base_thick=undef, thread=ThreadM4, align, orient, align_obj = "rod")
{
    thick_=thick==undef?rod_d:thick;
    outer_d= rod_d+thick_*2;
    thread_dia=lookup(ThreadSize, thread);
    screw_dist_=screw_dist==undef?outer_d+thread_dia*2+thick_:screw_dist;
    base_thick_=base_thick==undef?thick_*1.2:base_thick;
    clamp_tolerance = 0.5*mm;

    pos_offset = align_obj == "mount" ? N : [-rod_d/2,0,0];

    s=[base_thick_, screw_dist_+thread_dia*2.5, width];
    if(part==undef)
    {
        difference()
        {
            mount_rod_clamp_full(part="pos", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
            mount_rod_clamp_full(part="neg", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
        if($show_vit)
        {
            %mount_rod_clamp_full(part="vit", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
    }
    else if(part=="pos")
    {
        material(Mat_Plastic)
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            /*hull()*/
            {
                // cylinder around rod
                translate([rod_d/2,0,0])
                rcylindera(d=outer_d, h=width, orient=Z, align=N);

                // base
                /*translate([-rod_d/2,0,0])*/
                rcubea([base_thick_, screw_dist_+thread_dia*2.5, width], align=X);
            }
        }
    }
    else if(part=="neg")
    {
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            // cut bottom of cylinder
            /*translate(-rod_d/2*X)*/
            cubea([outer_d/2, screw_dist_+thread_dia*2.5+.1, width+1], align=[-1,0,0]);

            // cut clamp screw holes
            for(i=[-1,1])
            translate([0, i*screw_dist_/2, 0])
            {
                screw_cut(thread=thread, orient=-X);
            }

            // cut rod
            translate([rod_d/2,0,0])
            translate(-clamp_tolerance*X)
            hull()
            {
                stack(axis=-X, dist=100)
                {
                    cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
                    cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
                }
            }
        }
    }
    else if(part=="vit")
    {
        %size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        translate([rod_d/2,0,0])
        translate(-clamp_tolerance*X)
        cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
    }
}

if(false)
{
    /*$show_vit=false;*/
    /*$preview_mode=false;*/
    stack(axis=Z, dist=50)
    {
        mount_rod_clamp_half(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="mount");
        mount_rod_clamp_full(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="mount");

        mount_rod_clamp_half(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="rod");
        mount_rod_clamp_full(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="rod");
    }
}

include <rod-clamps.h>

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

module mount_rod_clamp_half(part, rod_d=10, screw_dist=undef, width=4, thick=undef, base_thick=undef, thread=ThreadM4, align, orient, align_obj = "rod")
{
    thick_=thick==undef?rod_d:thick;
    outer_d= rod_d+thick_*2;
    thread_dia=lookup(ThreadSize, thread);
    screw_dist_=screw_dist==undef?outer_d+thread_dia+thick_:screw_dist;
    base_thick_=base_thick==undef?thick_*1.2:base_thick;
    clamp_tolerance = 0.5*mm;

    pos_offset = align_obj == "mount" ? N : N;

    if(part==undef)
    {
        difference()
        {
            mount_rod_clamp_half(part="pos", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
            mount_rod_clamp_half(part="neg", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
        if($show_vit)
        {
            %mount_rod_clamp_half(part="vit", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
    }
    else if(part=="pos")
    {
        s=[outer_d, base_thick_, width];
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            /*hull()*/
            {
                // cylinder around rod
                rcylindera(d=outer_d, h=width, orient=Z, align=N);

                // base
                rcubea([base_thick_, screw_dist_+thread_dia*2.5, width], align=X);
            }
        }
    }
    else if(part=="neg")
    {
        s=[outer_d, base_thick_, width];
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            // cut bottom of cylinder
            cubea([outer_d/2+.1, screw_dist_+thread_dia*2.5+.1, width+1], align=[-1,0,0]);

            // cut clamp screw holes
            for(i=[-1,1])
            translate([0, i*screw_dist_/2, 0])
            {
                screw_cut(thread=thread, orient=-X);
            }

            // cut rod
            translate(-clamp_tolerance*X)
            cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
        }
    }
    else if(part=="vit")
    {
        s=[outer_d, base_thick_, width];
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            translate(-clamp_tolerance*X)
            cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
        }
    }
}

module mount_rod_clamp_full(part, rod_d=10, screw_dist=undef, width=4, thick=undef, base_thick=undef, thread=ThreadM4, align, orient, align_obj = "rod")
{
    thick_=thick==undef?rod_d:thick;
    outer_d= rod_d+thick_*2;
    thread_dia=lookup(ThreadSize, thread);
    screw_dist_=screw_dist==undef?outer_d+thread_dia*2+thick_:screw_dist;
    base_thick_=base_thick==undef?thick_*1.2:base_thick;
    clamp_tolerance = 0.5*mm;

    pos_offset = align_obj == "mount" ? N : [-rod_d/2,0,0];

    s=[base_thick_, screw_dist_+thread_dia*2.5, width];
    if(part==undef)
    {
        difference()
        {
            mount_rod_clamp_full(part="pos", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
            mount_rod_clamp_full(part="neg", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
        if($show_vit)
        {
            %mount_rod_clamp_full(part="vit", rod_d=rod_d, screw_dist=screw_dist, width=width, thick=thick, base_thick=base_thick, thread=thread, align=align, orient=orient, align_obj=align_obj);
        }
    }
    else if(part=="pos")
    {
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            /*hull()*/
            {
                // cylinder around rod
                translate([rod_d/2,0,0])
                rcylindera(d=outer_d, h=width, orient=Z, align=N);

                // base
                /*translate([-rod_d/2,0,0])*/
                rcubea([base_thick_, screw_dist_+thread_dia*2.5, width], align=X);
            }
        }
    }
    else if(part=="neg")
    {
        size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        {
            // cut bottom of cylinder
            /*translate(-rod_d/2*X)*/
            cubea([outer_d/2, screw_dist_+thread_dia*2.5+.1, width+1], align=[-1,0,0]);

            // cut clamp screw holes
            for(i=[-1,1])
            translate([0, i*screw_dist_/2, 0])
            {
                screw_cut(thread=thread, orient=-X);
            }

            // cut rod
            translate([rod_d/2,0,0])
            translate(-clamp_tolerance*X)
            hull()
            {
                stack(axis=-X, dist=100)
                {
                    cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
                    cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
                }
            }
        }
    }
    else if(part=="vit")
    {
        %size_align(size=s, align=align, orient=orient, orient_ref=Z)
        translate(pos_offset)
        translate([rod_d/2,0,0])
        translate(-clamp_tolerance*X)
        cylindera(d=rod_d*rod_fit_tolerance, h=width*2, orient=Z);
    }
}

if(false)
{
    /*$show_vit=false;*/
    /*$preview_mode=false;*/
    stack(axis=Z, dist=50)
    {
        mount_rod_clamp_half(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="mount");
        mount_rod_clamp_full(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="mount");

        mount_rod_clamp_half(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="rod");
        mount_rod_clamp_full(rod_d=yaxis_rod_d,  width=extrusion_size, thick=4, thread=ThreadM5, align_obj="rod");
    }
}


support size decreased

support size decreased

ball_radius=610/2;  // [mm]

module theBall()
{
  translate([0, 0, ball_radius+2])
    sphere(r=ball_radius, $fn=100);
}

difference()
{
  cylinder(r=ball_radius/5, h=20, $fn=100);
  #theBall();
}

ball_radius=610/2;  // [mm]

module theBall()
{
  translate([0, 0, ball_radius+2])
    sphere(r=ball_radius, $fn=100);
}

difference()
{
  cylinder(r=ball_radius/3, h=20, $fn=100);
  #theBall();
}


Just adding some basic code: Variables and other grunt lines

// https://www.github.com/agupta231

// User set variables
init_side_len = 50.8;

echo(version());

module pattern() {

}


main: add param for y carrriage pos

main: add param for y carrriage pos

include <thing_libutils/metric-thread.scad>;
include <thing_libutils/metric-hexnut.scad>;
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

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

include <config.scad>
include <misc.scad>
include <extruder-direct.scad>
include <x-carriage.scad>
include <y-axis.scad>
include <z-axis.scad>
include <psu.scad>
include <rod-clamps.scad>

use <scad-utils/trajectory.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>

axis_pos_x = 0*mm;
axis_pos_y = 0*mm;
axis_range_z=[85,380];
axis_pos_z = axis_range_z[1]*mm/2;

module main()
{
    color(extrusion_color)
    gantry_lower();

    color(extrusion_color)
    translate([0,0,-main_lower_dist_z])
    gantry_lower();

    color(extrusion_color)
    for(i=[-1,1])
    translate([0,i*(main_upper_dist_y/2),0])
    gantry_upper();

    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            translate([0, xaxis_zaxis_distance_y, 0])
                belt_path(500, 6, xaxis_pulley_d, orient=[1,0,0]);
        }

        translate([axis_pos_x,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage(show_bearings=true);
            }

            if(!preview_mode)
            {
                attach([[12, -30, -30], [1,0,0]], extruder_conn_xcarriage)
                {
                    extruder();
                }
            }
        }

        // x smooth rods
        for(i=[-1,1])
            translate([0,xaxis_zaxis_distance_y,i*(xaxis_rod_distance/2)])
                fncylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);
    }

    // y axis
    attach([[0,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    translate([0,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x, 6, yaxis_pulley_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    hull()
    {
        translate([0,0,yaxis_bearing[0]/2])
        {
            attach(ycarriage_bearing_mount_conn_bearing, [[0,0,0],[0,0,1]])
            {
                cubea([10,20,10], align=[0,0,-1]);
            }
            translate([0,0,yaxis_belt_path_offset_z])
            {
                cubea([10,20,10], align=[0,0,-1]);
            }
        }

    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(i=[-1,1])
        for(j=[-1,1])
        {
            attach([[i*(yaxis_rod_distance/2),j*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        for(i=[-1,1])
        translate([i*(yaxis_rod_distance/2), 0, 0])
        {
            fncylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(j=[-1,1])
            {
                attach([[0,j*(yaxis_bearing_distance_y/2)-axis_pos_y,0],[0,0,-1]], ycarriage_bearing_mount_conn_bearing)
                {
                    ycarriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(ycarriage_bearing_mount_conn_bearing, [[0,axis_pos_y,0],[0,0,1]])
        {
            /*translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1])/2, 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,0]);
                }
                translate([x*(ycarriage_size[0]/2-16*mm), y*(ycarriage_size[1]/2-16*mm), 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,0]);
                }
            }

            cubea([ycarriage_size[0]-16*mm*2,ycarriage_size[1]-16*mm*2, ycarriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(ycarriage_size, align=[0,0,1]);
        }
    }

    // z axis
    for(i=[-1,1])
    {
        translate([i*(main_width/2),0,main_height])
        {
            mirror([i==-1?1:0,0,0])
            {
                upper_gantry_zrod_connector();

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

        translate([i*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([i==-1?1:0,0,0])
                {
                    zaxis_motor_mount(show_motor=true);

                    translate([zmotor_mount_rod_offset_x, 0, 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
            translate([i*(lookup(NemaSideSize,zaxis_motor)/2), 0, 0])
            translate([i*(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
            {
                // z rods
                translate([0,0,zaxis_motor_offset_z-50])
                    fncylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(j=[-1,1])
                    translate([0,0,axis_pos_z-j*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }

            translate([i*zmotor_mount_rod_offset_x, 0, axis_pos_z])
                #fncylindera(h=100, d=zaxis_nut[1], align=[0,0,0]);

            translate([i*zaxis_leadscrew_offset_x, 0, axis_pos_z-xaxis_rod_distance/2-10])
            {
                difference()
                {
                    #fncylindera(h=10, d=zaxis_nut[1], align=[0,0,0]);
                    union()
                    {
                        fncylindera(h=10+1, d=zaxis_nut[0], center= false);
                        translate([0, 13.5, -1]) fncylindera(h=5, r=1.6);
                        translate([0, -13.5, -1]) fncylindera(h=5, r=1.6);
                    }
                }
            }
        }
    }

    for(x=[-1,1])
    translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
    {
        translate([-x*psu_w/2, -psu_d/2, psu_h/2])
        {
            psu();

            mirror([x==-1?1:0,0,0])
            translate([0, -psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_side();

            translate([0, psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_back();
        }
    }
}

module upper_gantry_zrod_connector()
{
    upper_width_extra = main_upper_width-main_width;
    difference()
    {
        union()
        {
            hull()
            {
                // attach to z rod
                translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
                translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
                {
                    cubea([gantry_connector_thickness, zmotor_mount_clamp_width, extrusion_size+gantry_connector_thickness], align=[-1,0,1]);
                }

                // connect upper gantry
                translate([upper_width_extra/2, 0, 0])
                    translate([0,0,extrusion_size/2])
                    cubea([gantry_connector_thickness,main_upper_dist_y+extrusion_size,extrusion_size], align=[1,0,0], extrasize=[0,0,gantry_connector_thickness], extrasize_align=[0,0,1]);
            }

            translate([upper_width_extra/2, 0, 0])
                translate([0,0,extrusion_size])
                cubea([extrusion_size*1.5,main_upper_dist_y+extrusion_size,gantry_connector_thickness], align=[-1,0,1]);

        }

        // cut out z rod mounting clamp nut traps and screw holes
        translate([0,0,extrusion_size/2])
        translate([upper_width_extra/2, 0, 0])
        for(i=[-1,1])
        {
            translate([-1, i*zmotor_mount_clamp_dist/2, 0])
            {
                fncylindera(fn=6, d=zmotor_mount_clamp_nut_dia, h=zmotor_mount_clamp_nut_thick, orient=[1,0,0], align=[1,0,0]);

                fncylindera(d=zmotor_mount_clamp_thread_dia, h=100, orient=[1,0,0], align=[1,0,0]);
            }
        }

        // cutout for z rod
        translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
        translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,extrusion_size])
        fncylindera(d=zaxis_rod_d*1.01, h=extrusion_size*3, align=[0,0,0], orient=[0,0,1]);
    }
}

module gantry_upper()
{
    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea(size=[extrusion_size, extrusion_size, main_height], align=[-i,0,1]);
        }
        else
        {
            linear_extrusion(h=main_height, align=[-i,0,1], orient=[0,0,1]);
        }
    }

    translate([0, 0, main_height])
    {
        if(preview_mode)
        {
            cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
        }
        else
        {
            linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
        }
    }
}

module gantry_lower()
{
    for(i=[-1,1])
    translate([0,  i*(main_depth/2), 0])
    {
        if(preview_mode)
        {
            cubea([main_width, extrusion_size, extrusion_size], align=[0,i,-1]);
        }
        else
        {
            linear_extrusion(h=main_width, align=[0,i,-1], orient=[1,0,0]);
        }
    }

    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea([extrusion_size, main_depth, extrusion_size], align=[-i,0,-1]);
        }
        else
        {
            linear_extrusion(h=main_depth, align=[-i,0,-1], orient=[0,1,0]);
        }
    }
}

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

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

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

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

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/

include <thing_libutils/metric-thread.scad>;
include <thing_libutils/metric-hexnut.scad>;
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

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

include <config.scad>
include <misc.scad>
include <extruder-direct.scad>
include <x-carriage.scad>
include <y-axis.scad>
include <z-axis.scad>
include <psu.scad>
include <rod-clamps.scad>

use <scad-utils/trajectory.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>

axis_pos_x = 0*mm;
axis_range_z=[85,380];
axis_pos_z = axis_range_z[1]*mm/2;

module main()
{
    color(extrusion_color)
    gantry_lower();

    color(extrusion_color)
    translate([0,0,-main_lower_dist_z])
    gantry_lower();

    color(extrusion_color)
    for(i=[-1,1])
    translate([0,i*(main_upper_dist_y/2),0])
    gantry_upper();

    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            translate([0, xaxis_zaxis_distance_y, 0])
                belt_path(500, 6, xaxis_pulley_d, orient=[1,0,0]);
        }

        translate([axis_pos_x,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage(show_bearings=true);
            }

            if(!preview_mode)
            {
                attach([[12, -30, -30], [1,0,0]], extruder_conn_xcarriage)
                {
                    extruder();
                }
            }
        }

        // x smooth rods
        for(i=[-1,1])
            translate([0,xaxis_zaxis_distance_y,i*(xaxis_rod_distance/2)])
                fncylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);
    }

    // y axis
    attach([[0,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    translate([0,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x, 6, yaxis_pulley_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    hull()
    {
        translate([0,0,yaxis_bearing[0]/2])
        {
            attach(ycarriage_bearing_mount_conn_bearing, [[0,0,0],[0,0,1]])
            {
                cubea([10,20,10], align=[0,0,-1]);
            }
            translate([0,0,yaxis_belt_path_offset_z])
            {
                cubea([10,20,10], align=[0,0,-1]);
            }
        }

    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(i=[-1,1])
        for(j=[-1,1])
        {
            attach([[i*(yaxis_rod_distance/2),j*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        for(i=[-1,1])
        translate([i*(yaxis_rod_distance/2), 0, 0])
        {
            fncylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(j=[-1,1])
            {
                attach([[0,j*(yaxis_bearing_distance_y/2),0],[0,0,-1]], ycarriage_bearing_mount_conn_bearing)
                {
                    ycarriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(ycarriage_bearing_mount_conn_bearing, [[0,0,0],[0,0,1]])
        {
            /*translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1])/2, 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,0]);
                }
                translate([x*(ycarriage_size[0]/2-16*mm), y*(ycarriage_size[1]/2-16*mm), 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,0]);
                }
            }

            cubea([ycarriage_size[0]-16*mm*2,ycarriage_size[1]-16*mm*2, ycarriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(ycarriage_size, align=[0,0,1]);
        }
    }

    // z axis
    for(i=[-1,1])
    {
        translate([i*(main_width/2),0,main_height])
        {
            mirror([i==-1?1:0,0,0])
            {
                upper_gantry_zrod_connector();

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

        translate([i*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([i==-1?1:0,0,0])
                {
                    zaxis_motor_mount(show_motor=true);

                    translate([zmotor_mount_rod_offset_x, 0, 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
            translate([i*(lookup(NemaSideSize,zaxis_motor)/2), 0, 0])
            translate([i*(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
            {
                // z rods
                translate([0,0,zaxis_motor_offset_z-50])
                    fncylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(j=[-1,1])
                    translate([0,0,axis_pos_z-j*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }

            translate([i*zmotor_mount_rod_offset_x, 0, axis_pos_z])
                #fncylindera(h=100, d=zaxis_nut[1], align=[0,0,0]);

            translate([i*zaxis_leadscrew_offset_x, 0, axis_pos_z-xaxis_rod_distance/2-10])
            {
                difference()
                {
                    #fncylindera(h=10, d=zaxis_nut[1], align=[0,0,0]);
                    union()
                    {
                        fncylindera(h=10+1, d=zaxis_nut[0], center= false);
                        translate([0, 13.5, -1]) fncylindera(h=5, r=1.6);
                        translate([0, -13.5, -1]) fncylindera(h=5, r=1.6);
                    }
                }
            }
        }
    }

    for(x=[-1,1])
    translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
    {
        translate([-x*psu_w/2, -psu_d/2, psu_h/2])
        {
            psu();

            mirror([x==-1?1:0,0,0])
            translate([0, -psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_side();

            translate([0, psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_back();
        }
    }
}

module upper_gantry_zrod_connector()
{
    upper_width_extra = main_upper_width-main_width;
    difference()
    {
        union()
        {
            hull()
            {
                // attach to z rod
                translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
                translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
                {
                    cubea([gantry_connector_thickness, zmotor_mount_clamp_width, extrusion_size+gantry_connector_thickness], align=[-1,0,1]);
                }

                // connect upper gantry
                translate([upper_width_extra/2, 0, 0])
                    translate([0,0,extrusion_size/2])
                    cubea([gantry_connector_thickness,main_upper_dist_y+extrusion_size,extrusion_size], align=[1,0,0], extrasize=[0,0,gantry_connector_thickness], extrasize_align=[0,0,1]);
            }

            translate([upper_width_extra/2, 0, 0])
                translate([0,0,extrusion_size])
                cubea([extrusion_size*1.5,main_upper_dist_y+extrusion_size,gantry_connector_thickness], align=[-1,0,1]);

        }

        // cut out z rod mounting clamp nut traps and screw holes
        translate([0,0,extrusion_size/2])
        translate([upper_width_extra/2, 0, 0])
        for(i=[-1,1])
        {
            translate([-1, i*zmotor_mount_clamp_dist/2, 0])
            {
                fncylindera(fn=6, d=zmotor_mount_clamp_nut_dia, h=zmotor_mount_clamp_nut_thick, orient=[1,0,0], align=[1,0,0]);

                fncylindera(d=zmotor_mount_clamp_thread_dia, h=100, orient=[1,0,0], align=[1,0,0]);
            }
        }

        // cutout for z rod
        translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
        translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,extrusion_size])
        fncylindera(d=zaxis_rod_d*1.01, h=extrusion_size*3, align=[0,0,0], orient=[0,0,1]);
    }
}

module gantry_upper()
{
    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea(size=[extrusion_size, extrusion_size, main_height], align=[-i,0,1]);
        }
        else
        {
            linear_extrusion(h=main_height, align=[-i,0,1], orient=[0,0,1]);
        }
    }

    translate([0, 0, main_height])
    {
        if(preview_mode)
        {
            cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
        }
        else
        {
            linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
        }
    }
}

module gantry_lower()
{
    for(i=[-1,1])
    translate([0,  i*(main_depth/2), 0])
    {
        if(preview_mode)
        {
            cubea([main_width, extrusion_size, extrusion_size], align=[0,i,-1]);
        }
        else
        {
            linear_extrusion(h=main_width, align=[0,i,-1], orient=[1,0,0]);
        }
    }

    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea([extrusion_size, main_depth, extrusion_size], align=[-i,0,-1]);
        }
        else
        {
            linear_extrusion(h=main_depth, align=[-i,0,-1], orient=[0,1,0]);
        }
    }
}

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

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

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

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

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/


Added rounded cap

Added rounded cap

INCHES = 25.4;

NUMBER = 5;
DIAMETER = 60;
HEIGHT = 120;
TWIST = 0.5;
DISTANCE = 0.7;
SCALE = 5/8;

HOLLOW = false;
INSIDE_COLOR = 1;

module baseshape(size) {
 circle(size/2);
* rotate([0,0,45]) square(size, center=true);
* rotate([0,0,45]) pentagon(size/2);
}

COLORS = ["White", "Red", "Green", "Blue", "Yellow", "Black", "Pink"];
NUM_COLORS = 8;
ITEM = -1;
use <MCAD/regular_shapes.scad>

module base(neg = false) {
  if (neg) {
    difference() {
      translate([DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
      translate([-DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
    }
  }
  else {
    translate([-DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
  }
}

module baseitem(n) {
  rotate([0,0,n*360/NUMBER]) translate([DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
}

module newbase(n) {
  difference() {
    baseitem(n);
    for (i=[0:NUMBER-1]) {
      if (i!=n) baseitem(i);
    }
  }
}

module smoother() {
  hull() {
    sphere(r=10);
    translate([0,0,54.5]) sphere(r=4);
  }
}

module extrudepart() {
    linear_extrude(height=HEIGHT, twist=TWIST*360, scale=[SCALE, SCALE], convexity=3) child();
}

module basepart(item) {
    extrudepart() baseitem(item);
    translate([0,0,HEIGHT]) rotate([0,0,TWIST*360])
     scale(SCALE) rotate([0,0,item*360/NUMBER])
      translate([DIAMETER/2*DISTANCE,0])
       sphere(DIAMETER/2);
}

module part(item) {
    color(COLORS[item%NUM_COLORS]) {
        render() difference() {
            basepart(item);
            for (i=[0:NUMBER-1]) if (i!=item) basepart(i);
        }
        if (!HOLLOW && INSIDE_COLOR == item) inside();
    }
}

module inside() {
    extrudepart() for (i=[1:NUMBER-1], j=[0:i-1]) {
        intersection() {baseitem(i); baseitem(j);}
    }
}

module horn(item) {
  if (item == -1) {
      for (x=[0:NUMBER-1]) part(x);
      if (!HOLLOW) color(COLORS[INSIDE_COLOR]) inside();
  }
  else {
      part(item);
  }
}

horn(ITEM);

INCHES = 25.4;

NUMBER = 2;
DIAMETER = 60;
HEIGHT = 120;
TWIST = 0.5;
DISTANCE = 0.4;
HOLLOW = false;
SCALE = 6/8;

module baseshape(size) {
 circle(size/2);
* rotate([0,0,45]) square(size, center=true);
* rotate([0,0,45]) pentagon(size/2);
}

COLORS = ["White", "Red", "Green", "Blue", "Yellow", "Black", "Pink"];
NUM_COLORS = 8;
ITEM = -1;
use <MCAD/regular_shapes.scad>

module base(neg = false) {
  if (neg) {
    difference() {
      translate([DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
      translate([-DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
    }
  }
  else {
    translate([-DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
  }
}

module baseitem(n) {
  rotate([0,0,n*360/NUMBER]) translate([DIAMETER/2*DISTANCE,0]) baseshape(DIAMETER);
}

module newbase(n) {
  difference() {
    baseitem(n);
    for (i=[0:NUMBER-1]) {
      if (i!=n) baseitem(i);
    }
  }
}

module smoother() {
  hull() {
    sphere(r=10);
    translate([0,0,54.5]) sphere(r=4);
  }
}

module extrudepart() {
    linear_extrude(height=HEIGHT, twist=TWIST*360, scale=[SCALE, SCALE], convexity=3) child();
}

module part(item) {
    color(COLORS[(item+1)%NUM_COLORS]) extrudepart() newbase(item);
}

module inside() {
    color(COLORS[0]) extrudepart() for (i=[1:NUMBER-1], j=[0:i-1]) {
        intersection() {baseitem(i); baseitem(j);}
    }
}

module horn(item) {
  if (item == -1) {
      for (x=[0:NUMBER-1]) part(x);
  }
  else {
      part(item);
  }
}

horn(ITEM);
if (!HOLLOW) inside();