[User]
I need a customizable mounting plate generator, something like what I've seen before but a bit more flexible. I want to be able to define multiple mounting holes with individual x, y coordinates, and for each of those, specify whether it's a simple hole or if it should have a recessed nut on either the top or the bottom.

The plate should have standoffs for each hole. The standoffs should be cylindrical pads. I'd also like bars connecting the pads, but not all of them; instead, I'd like to be able to specify how many of the *closest* pads get connected to each pad by a bar. I need to control the diameter of the pads and bars independently.

For the holes, I need to set the bolt hole diameter as well as the nut hole diameter. I need to control the standoff height, the nut thickness (for recessing), and the overall plate thickness.

I've seen some versions where the input is comma-separated strings. That's fine, but I need three strings for the input: one for the X coordinates of the holes, another for the Y coordinates, and the last to indicate the nut side (0 for bottom, 1 for top, 2 for no nut). For example, it should handle something like:

`x_values="0,0,95,0,6.3,81.3,82.5";`

`y_values="0,95,0,48.4,0,0,48.4";`

`nut_side="1,1,1,0,0,0,0";`

I don't really care what libraries are used as long as it generates a usable .stl output.

[Assistant]
CustomMount.scad:
```
// 2018/05/06 v1.0 Laurie Gellatly
// 2018/06/09 v1.1 Only draw the closest 'bars'bolt_hole_diameter
// 2018/06/10 v1.2 Add stand_offs and recess nuts
// 2020/08/14 v1.3 Fix range for bars to draw between
// Customiseable mount plate
//

// (3.4 for M3 bolts) slightly larger than bolt diameter?
bolt_hole_diameter  = 3.4; // [1.1:0.1:5]
// for chosen bolt (use 6.2 for M3)?
hex_nut_hole_diameter   = 6.2; // [3:0.1:10]
// above plate?
stand_off = 2;       // [0:0.1:10]
stand_off_diameter = 9;         // [5:0.1:12]
// by bars?
nearest_holes_connected = 1;           // [1:5]
// Hole position and nut side enter "x,y,nut_side;" nutside is 0 for underneath, 1 for on top, 2 for none
holes_X_Y_nutside="0,0,1;0,100,1;80,0,1;5,58.4,0;35.5,25.4,0;87.5,58.4,0;35.5,53.3,0";

/* [Hidden] */
nut_thickness = 2.4;
hole_depth = 1 + nut_thickness; // The extra 1 makes the nut recessed
plate_thickness = hole_depth + 1.8;
abit=0.01;

function substr(s, st, en, p="") =
    (st >= en || st >= len(s)) ? p : substr(s, st+1, en, str(p, s[st]));

// Thanks to Jesse for atof and atoi
// Jesse Campbell
// www.jbcse.com
// OpenSCAD ascii string to number conversion function atof
// scientific notation support added by Alexander Pruss (thingiverse user arpruss)
// atoi are from http://www.thingiverse.com/roipoussiere

function atoi(str, base=10, i=0, nb=0) =
	i == len(str) ? (str[0] == "-" ? -nb : nb) :
	i == 0 && str[0] == "-" ? atoi(str, base, 1) :
	atoi(str, base, i + 1,
		nb + search(str[i], "0123456789ABCDEF")[0] * pow(base, len(str) - i - 1));

function atof(str) = len(str) == 0 ? 0 : let( expon1 = search("e", str), expon = len(expon1) ? expon1 : search("E", str)) len(expon) ? atof(substr(str,pos=0,len=expon[0])) * pow(10, atoi(substr(str,pos=expon[0]+1))) : let( multiplyBy = (str[0] == "-") ? -1 : 1, str = (str[0] == "-" || str[0] == "+") ? substr(str, 1, len(str)-1) : str, decimal = search(".", str), beforeDecimal = decimal == [] ? str : substr(str, 0, decimal[0]), afterDecimal = decimal == [] ? "0" : substr(str, decimal[0]+1) ) (multiplyBy * (atoi(beforeDecimal) + atoi(afterDecimal)/pow(10,len(afterDecimal))));
// End Jesse Campbell

function split(h, s, p=[]) =
    let(x = search(h, s))
    x == []
        ? concat(p, s)
        : let(i=x[0], l=substr(s, 0, i), r=substr(s, i+1, len(s)))
                split(h, r, concat(p, l));

// input : list of pairs of numbers
// output : sorted list (by second number) of paired number
function quicksort(arr) = !(len(arr)>0) ? [] : let(
    pivot   = arr[floor(len(arr)/2)],
    lesser  = [ for (y = arr) if (y[1]  < pivot[1]) y ],
    equal   = [ for (y = arr) if (y[1] == pivot[1]) y ],
    greater = [ for (y = arr) if (y[1]  > pivot[1]) y ]
) concat(
    quicksort(lesser), equal, quicksort(greater)
);

function distarray(p, holes) = [for (c=[p+1:1:len(holes)-1]) [c,distance(holes[p],holes[c])]];

function distance(pos1,pos2)= // Find the distance between pos1 and pos2
    pow(pow(pos1[0] - pos2[0], 2) + pow(pos1[1] - pos2[1], 2), 0.5); // ((x1-x2)^2 + (y1-y2)^2)^.5)

function angle(pos1,pos2) = // Find the angle from pos1 to pos2
    atan((pos2[1] - pos1[1]) / (pos2[0] - pos1[0])) + ((pos2[0] < pos1[0]) ? 180 : 0); // atan((y2-y1)/ (x2-x1))
//    atan((pos2[1] - pos1[1]) / pow(pos2[0] - pos1[0])); // atan((y2-y1)/ (x2-x1))

module pad(pos){    // draw a pad at pos
    translate([pos[0],pos[1],0]) cylinder(d=stand_off_diameter, h=stand_off+plate_thickness);
}

module bar(pos1,pos2){  // Draw a bar between pos1 and pos2
    translate([pos1[0],pos1[1],0])rotate([0,0,angle(pos1,pos2)]) translate([0,-stand_off_diameter*0.5,0]) cube([distance(pos1,pos2), stand_off_diameter, plate_thickness]);
}

function red(s,vec,i=-9,p="") =
    let(x = i==-9? len(vec)-1 : i)
    x == 0
        ? substr(s, 0, vec[x])
        : str(red(s,vec,x-1),substr(s, vec[x-1]+1, vec[x]));

function blank_idx(holes_txt) = concat(search(" ",holes_txt,0)[0],len(holes_txt));

function cell_values(holes_txt) = red(holes_txt,blank_idx(holes_txt));

// x, y, bolt dia, nut dia, nut height
function parse_holes(holes_txt) = [for (c=split(";",cell_values(holes_txt))) [for(n=split(",",c)) atof(n)
]];

//echo(holes_X_Y_nutside);
holes=parse_holes(holes_X_Y_nutside);
//echo(holes);

difference(){
    union(){
        for(p=[0:1:len(holes)-1])
            pad(holes[p]);      // Draw a pad around each hole
        for(p=[0:1:len(holes)-1]){ // From a hole to every remaining hole
            dist = distarray(p,holes);   // Fnd the distances to them
            //echo(dist);
            mindist = quicksort(dist); // sort them by distance
            //echo(mindist);
            for(b=[0:1:nearest_holes_connected<len(mindist)-1?nearest_holes_connected:len(mindist)-1])   // Draw bars to the closest 'holes'
                bar(holes[p],holes[mindist[b][0]]);
        }
    }
    for(p=[0:1:len(holes)-1]){
        translate([holes[p][0],holes[p][1],-abit]) cylinder(d=bolt_hole_diameter,h=stand_off+plate_thickness+2*abit);    // Bolt hole
        if(holes[p][2] != 2) translate([holes[p][0],holes[p][1],(holes[p][2] == 1)? stand_off+plate_thickness - hole_depth: -abit]) cylinder(d=hex_nut_hole_diameter,h=hole_depth+abit,$fn=6);    // Nut hole
    }
}

```
CustomMount.scad:
```
// 2018/05/06 v1.0 Laurie Gellatly
// 2018/06/09 v1.1 Only draw the closest 'bars'bolt_hole_diameter
// 2018/06/10 v1.2 Add stand_offs and recess nuts
// Customiseable mount plate
//

// (3.4 for M3 bolts) slightly larger than bolt diameter?
bolt_hole_diameter  = 3.4; // [1.1:0.1:5]
// for chosen bolt (use 6.2 for M3)?
hex_nut_hole_diameter   = 6.2; // [3:0.1:10]
// above plate?
stand_off = 2;       // [0:0.1:10]
stand_off_diameter = 10;         // [5:0.1:12]
// by bars?
nearest_holes_connected = 1;           // [1:5]
// of all the holes (',' between and no spaces)?
x_values="0,0,95,0,6.3,81.3,82.5";
// of all the holes (in the same order as X)?
y_values="0,95,0,48.4,0,0,48.4";
// is 0 for underneath, 1 for on top, 2 for none (in same order as X) ?
nut_side="1,1,1,0,0,0,0";

/* [Hidden] */
nut_thickness = 2.4;
hole_depth = 1 + nut_thickness; // The extra 1 makes the nut recessed
plate_thickness = hole_depth + 1.8;
abit=0.01;

function substr(s, st, en, p="") =
    (st >= en || st >= len(s)) ? p : substr(s, st+1, en, str(p, s[st]));

// Thanks to Jesse for atof and atoi
// Jesse Campbell
// www.jbcse.com
// OpenSCAD ascii string to number conversion function atof
// scientific notation support added by Alexander Pruss (thingiverse user arpruss)
// atoi are from http://www.thingiverse.com/roipoussiere

function atoi(str, base=10, i=0, nb=0) =
	i == len(str) ? (str[0] == "-" ? -nb : nb) :
	i == 0 && str[0] == "-" ? atoi(str, base, 1) :
	atoi(str, base, i + 1,
		nb + search(str[i], "0123456789ABCDEF")[0] * pow(base, len(str) - i - 1));

function atof(str) = len(str) == 0 ? 0 : let( expon1 = search("e", str), expon = len(expon1) ? expon1 : search("E", str)) len(expon) ? atof(substr(str,pos=0,len=expon[0])) * pow(10, atoi(substr(str,pos=expon[0]+1))) : let( multiplyBy = (str[0] == "-") ? -1 : 1, str = (str[0] == "-" || str[0] == "+") ? substr(str, 1, len(str)-1) : str, decimal = search(".", str), beforeDecimal = decimal == [] ? str : substr(str, 0, decimal[0]), afterDecimal = decimal == [] ? "0" : substr(str, decimal[0]+1) ) (multiplyBy * (atoi(beforeDecimal) + atoi(afterDecimal)/pow(10,len(afterDecimal))));
// End Jesse Campbell

function split(h, s, p=[]) =
    let(x = search(h, s))
    x == []
        ? concat(p, s)
        : let(i=x[0], l=substr(s, 0, i), r=substr(s, i+1, len(s)))
                split(h, r, concat(p, l));

// input : list of pairs of numbers
// output : sorted list (by second number) of paired number
function quicksort(arr) = !(len(arr)>0) ? [] : let(
    pivot   = arr[floor(len(arr)/2)],
    lesser  = [ for (y = arr) if (y[1]  < pivot[1]) y ],
    equal   = [ for (y = arr) if (y[1] == pivot[1]) y ],
    greater = [ for (y = arr) if (y[1]  > pivot[1]) y ]
) concat(
    quicksort(lesser), equal, quicksort(greater)
);

function distarray(p, holes) = [for (c=[p+1:1:len(holes)-1]) [c,distance(holes[p],holes[c])]];

function distance(pos1,pos2)= // Find the distance between pos1 and pos2
    pow(pow(pos1[0] - pos2[0], 2) + pow(pos1[1] - pos2[1], 2), 0.5); // ((x1-x2)^2 + (y1-y2)^2)^.5)

function angle(pos1,pos2) = // Find the angle from pos1 to pos2
    atan((pos2[1] - pos1[1]) / (pos2[0] - pos1[0])) + ((pos2[0] < pos1[0]) ? 180 : 0); // atan((y2-y1)/ (x2-x1))
//    atan((pos2[1] - pos1[1]) / pow(pos2[0] - pos1[0])); // atan((y2-y1)/ (x2-x1))

module pad(pos){    // draw a pad at pos
    translate([pos[0],pos[1],0]) cylinder(d=stand_off_diameter, h=stand_off+plate_thickness);
}

module bar(pos1,pos2){  // Draw a bar between pos1 and pos2
    translate([pos1[0],pos1[1],0])rotate([0,0,angle(pos1,pos2)]) translate([0,-stand_off_diameter*0.5,0]) cube([distance(pos1,pos2), stand_off_diameter, plate_thickness]);
}
xv=split(",",x_values);
yv=split(",",y_values);
nv=split(",",nut_side);
if((len(xv) == len(yv)) && (len(xv) == len(nv))){
holes=[for (ind=[0:len(xv)-1]) [atof(xv[ind]),atof(yv[ind]),atoi(nv[ind])]];
   echo(holes);
difference(){
    union(){
        for(p=[0:1:len(holes)-1])
            pad(holes[p]);      // Draw a pad around each hole
        for(p=[0:1:len(holes)-1]){ // From a hole to every remaining hole
            dist = distarray(p,holes);   // Fnd the distances to them
            //echo(dist);
            mindist = quicksort(dist); // sort them by distance
            //echo(mindist);
            for(b=[0:1:nearest_holes_connected])   // Draw bars to the closest 'holes'
                bar(holes[p],holes[mindist[b][0]]);
        }
    }
    for(p=[0:1:len(holes)-1]){
        translate([holes[p][0],holes[p][1],-abit]) cylinder(d=bolt_hole_diameter,h=stand_off+plate_thickness+2*abit);    // Bolt hole
        if(holes[p][2] != 2) translate([holes[p][0],holes[p][1],(holes[p][2] == 1)? stand_off+plate_thickness - hole_depth: -abit]) cylinder(d=hex_nut_hole_diameter,h=hole_depth+abit,$fn=6);    // Nut hole
    }
}
}else echo("Error:Input X, Y and nut_side values are not the same length!");
```


[User]
I'm looking to create a dual planetary gear system in OpenSCAD, similar to the one I've described in the previous SCAD file, but I'd like it to be fully parametric and also have a few improvements. I'd like to move away from having fixed sizes and instead define things mostly by ratios and diameters. I want the code to be modular, so we can reuse individual parts, and I'd like to separate the main assembly from the individual gear definitions.

Here's what I'm thinking. I want the following parameters to control the system:

*   **`module_size`:** This will be the basic size unit, sort of like a "module" in gear terminology. Everything else should scale based on this.
*   **`drive_gear_diameter`:** The diameter of the central drive gear.
*   **`inner_planet_ratio`**: The ratio between the drive gear teeth and the inner planet teeth, so that the `inner_planet_diameter` can be calculated based on this ratio, and also the `inner_ring_diameter`
*   **`outer_planet_ratio`:** Similarly, the ratio between the inner ring diameter and the outer planet teeth so that we can calculate `outer_planet_diameter` and the `outer_ring_diameter`
*   **`planet_count_inner`:** Number of inner planet gears.
*    **`planet_count_outer`:** Number of outer planet gears.
*   **`gear_thickness`:** The overall thickness of the gears.
*   **`shaft_diameter`:** Diameter of the shafts for the gears.
*   **`clearance`:**  A global clearance value that will be used between gears.
*  **`backlash_planet_drive`:** backlash value to apply to the planet and drive gears.
*  **`backlash_ring_inner`:** backlash value to apply to inner ring gear
*  **`backlash_ring_outer`:** backlash value to apply to outer ring gear
*  **`teeth_twist`**: a way to rotate the teeth of the gear for visual appeal or artistic effect.
*  **`ring_thickness`:** Thickness of inner ring and outer ring.

I'd like the output to be several separate `.scad` files for modularity:

1.  **`gear_definitions.scad`**: Should define all the gears using the `MCAD/involute_gears.scad` library, based on the parameters and should include a `planetgear` and `drivegear` module, both of which should include the backlash, clearance, and teeth_twist features described above. Also include the ring gears, as separate `innerring` and `outerring` modules. This file should also be aware of the shaft diameter when making gears.
2.  **`dual_planetary.scad`**: This file should define the assembly, and position the drive gear, inner and outer planet gears, and inner and outer ring gears according to the parameters provided, using modules to instantiate the individual gear definitions. This file should also create the inner ring and outer ring and include the shafts.
3.  **`test_assembly.scad`**: should instantiate the `dual_planetary.scad` module, and create a simple test assembly, using the provided parameters to ensure everything fits together as intended. This should also include some simple test geometry to check clearances.
4.  **`utils.scad`**: Should contain reusable functions or modules, such as a `planets` module, that can be used to position planet gears in a circle, similar to the existing module I created in my original code.

I'm particularly interested in a robust design, so the `gear_definitions.scad` file should handle negative backlash and clearance to make sure gears do not mesh incorrectly. The `dual_planetary.scad` file should check to ensure all ratios and numbers are compatible and should echo some diagnostics if there are any issues with the selected numbers. I'm hoping to use this as a starting point for a larger project. And I'd like the modules to be as clean and understandable as possible. Please comment the code so I can understand how everything is being calculated.

[Assistant]
DualPlanetarySystem.scad:
```
// OpenSCAD Dual Planetary System
// (c) 2018, tmackay
//
// Licensed under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license, http://creativecommons.org/licenses/by-sa/4.0.
include <MCAD/involute_gears.scad>

// Overall height
gear_h = 10;
// Circular pitch: Length of the arc from one tooth to the next
cp = 360;
// Number of teeth in central drive gear
drive_t = 7;
// Number of teeth in inner planet gears
planet_t = 7;
// Number of teeth in outer planet gears
planet_t2 = 6;
// Extra teeth in ring, determines thickness of inner ring
ring_t = 5;
// Scale the planet gears for clearance if printed too close
gear_scale = 1;
// Shaft diameter
shaft_d = 3;
// Number of planet gears in inner circle
inner_planets = 4;
// Number of planet gears in outer circle
outer_planets = 8;
// Clearance
clearance = 0.2;
// Backlash applied to planet and drive gears for rotational clearance
backlash = 0.2;
// Backlash applied to ring gear for rotational clearance
backlash_r = 1;
// Backlash applied to negative ring gears for rotational clearance
backlash_n = 1;

// Curve resolution settings, minimum angle
$fa = 5;
// Curve resolution settings, minimum size
$fs = 1;

ring_t1 = drive_t+2*planet_t;
ring_t2 = ring_t1 + ring_t;
case_t = ring_t2 + 2*planet_t2;

// Tolerances for geometry connections.
AT=0.02;
ST=AT*2;
TT=AT/2;

module planetgear(t1=13,teethtwist=1,b=0,s=1,cl=clearance,bl=backlash)
{
	g1twist = 360 * teethtwist / t1;
	union()
	{
		translate([0,0,(gear_h/2) - TT])
			gear(twist = -g1twist,
				number_of_teeth=t1,
				circular_pitch=cp*s,
				gear_thickness = (gear_h/2)+AT,
				rim_thickness = (gear_h/2)+AT,
				rim_width = 0,
				hub_thickness = (gear_h/2)+AT,
				hub_width = 0,
				bore_diameter=b,
                clearance=cl,
                backlash=bl);
		translate([0,0,(gear_h/2) + TT]) rotate([180,0,0])
			gear(twist = g1twist,
				number_of_teeth=t1,
				circular_pitch=cp*s,
				gear_thickness = (gear_h/2)+AT,
				rim_thickness = (gear_h/2)+AT,
				hub_thickness = (gear_h/2)+AT,
				bore_diameter=b,
                clearance=cl,
                backlash=bl);
	}
}

module planets()
{
    for(i = [0:n-1])
    rotate([0,0,round(i*t/n)*360/t])
        translate([offset,0,0]) rotate([0,0,round(i*t/n)*360/t*t2/t1])
            children();
}

module drivegear(t1=13,teethtwist=1)
{
    difference()
    {
        planetgear(t1,teethtwist);
        translate([-1,-3,-AT])
            cube([2,6,gear_h+ST]);
    }
}

module gearring(t1=13,t2=51,teethtwist=1)
{
    difference() {
        rotate([0,0,180/ring_t2*(1-planet_t2%2)])
            planetgear(t1=t2,teethtwist=-teethtwist,b=0,bl=backlash_r);
        planetgear(t1=t1,b=0,TT=AT,AT=ST, bl=-backlash_n, cl=0, s=1+360*clearance/t1/cp);
	}
}

module gearcase(t1=13,teethtwist=1)
{
    difference() {
        union()
        {
            cylinder(r=t1*cp/360+gear_h/2, h=gear_h);
            //shaft supports
            planets(t1=planet_t, t2=ring_t2, offset=t1*cp/360+gear_h/2,n=outer_planets,t=case_t+ring_t2)
                cylinder(d=3*shaft_d, h=gear_h);
        }
  		union()
		{
            planetgear(t1=t1,b=0,TT=AT,AT=ST,bl=-backlash_n,cl=0,s=1+360*clearance/t1/cp);
            //shaftholes
            planets(t1=planet_t, t2=ring_t2, offset=t1*cp/360+gear_h/2,n=outer_planets,t=case_t+ring_t2)
                translate([0,0,-TT])
                    cylinder(d=shaft_d, h=gear_h+ST);
		}
	}
}

// center gear
rotate([0,0,180/drive_t*(1-planet_t%2)])
    drivegear(t1 = drive_t, teethtwist=-1);

// inner planets
planets(t1=planet_t, t2=drive_t,offset=(drive_t+planet_t)*cp/360,n=inner_planets,t=ring_t1+drive_t)
    planetgear(t1 = planet_t, b=shaft_d, s=gear_scale);

// inner ring
gearring(t1=ring_t1, t2=ring_t2);

// outer planets
planets(t1=planet_t2, t2=ring_t2, offset=(ring_t2+planet_t2)*cp/360,n=outer_planets,t=case_t+ring_t2)
    planetgear(t1 = planet_t2, b=shaft_d, s=gear_scale);

// outer ring
gearcase(t1=case_t);

if ((drive_t+ring_t1)%inner_planets)
{
    echo(str("For even spacing, inner_planets must divide ", drive_t+ring_t1));
}
if ((ring_t2+case_t)%outer_planets)
{
    echo(str("For even spacing, outer_planets must divide ", ring_t2+case_t));
}

```


[User]
Hey! I need a parametric design for a rectangular fishbowl lid. I have a basic design in mind, and I'd like it to be customizable.

Essentially, it's a rectangular lid that sits on top of the fishbowl. The lid should have a lip that goes down around the outside of the bowl to keep it from sliding off. And also, the lid will have a grid of holes in it.

Here are the basic parameters:
*   `bowlSizeX`: The inside width of the bowl.
*   `bowlSizeY`: The inside length of the bowl.
*   `wallThickness`: The thickness of the lid walls and lip.
*   `lidHeight`: The height of the top part of the lid.
*   `holeSpacing`: The spacing between the centers of the holes in the grid.
*   `holeRadius`: The radius of the holes.

The lid should be a simple hollow box with a lip. The holes should be arranged in a grid across the top, evenly spaced.

I'm thinking of using OpenSCAD for this. Is that okay? Also, I don't need anything super complicated, but I'd like it to be clean and easy to use. Could you make sure it's parametric so I can easily change the dimensions?

[Assistant]
square_fishbowl_lid.scad:
```

wallThickness = 1.6;
bowlSizeX = 166;
bowlSizeY = 166;
lidHeight=10;

difference() {
    cube([bowlSizeX+2*wallThickness, bowlSizeY+2*wallThickness, lidHeight+wallThickness]);
    translate([wallThickness, wallThickness, wallThickness]) {
        cube([bowlSizeX, bowlSizeY, lidHeight+1]);
        for (i=[10:10:bowlSizeX-10]) {
            for (j=[10:10:bowlSizeY-10]) {
                translate([i+(bowlSizeX%10)/2,j+(bowlSizeY%10)/2,-wallThickness-1]) {
                    cylinder(r=5/2, h=wallThickness+2, $fn=6);
                }
            }
        }
    }
}

```


[User]
I need a set of OpenSCAD files to generate a variety of pipe connectors for a DIY project. I'm planning on using PVC pipe, probably with a 20mm inner diameter, but I'd like to make the files parametric so I can adjust the pipe size and other dimensions as needed. I'm familiar with some basic OpenSCAD, but not enough to generate complex shapes reliably.

The specific connectors I'm looking for are:

1.  **End Stop:** A simple cap for the end of a pipe. It should have a recess that the pipe fits into.
2.  **Elbow:** A 90-degree elbow joint, again with recesses for the pipes to fit into.
3.  **Straight Connector:** Just a straight piece with two recesses, for connecting two pipes in line.
4.  **3-Way Corner:** A corner connector with three ports, all at 90-degree angles to each other.
5.  **3-Way Tee:** A "T" shaped connector with three ports in the same plane.
6.  **4-Way Edge:** A four way connector with the ports on two different perpendicular planes, like an L shape with an additional port in each direction.
7.  **4-Way Flat:** A four way connector with all ports in the same plane.
8. **5-Way:** A connector with 5 ports, with the ports on 3 perpendicular planes.
9. **6-Way:** A connector with 6 ports, the ports are placed in a 3D cross shape.

I would like the following parameters to be customizable in all modules:

*   `inner_diameter`: The inner diameter of the pipe.
*   `wall_thickness`: The thickness of the pipe wall.
*   `length`: The length from the center of the fitting to the end of a port.
*    `recess_thickness`: The amount of space between the outer diameter of the pipe and the inner wall of the fitting.
*   `recess_depth`: How far the pipe goes into the fitting.

I'd like the design to include a small fillet radius at the base of each connector arm for better aesthetics and printability. The fillet radius should be derived from the `wall_thickness` variable.

Please generate a set of OpenSCAD files to accomplish this. I do not need files for specific libraries, but please specify which libraries you are using so I am sure to use those.

[Assistant]
5_Way.scad:
```
////////////////////////////////////////////////////////
// Created by Paul Tibble - 11/5/18                   //
// https://www.thingiverse.com/Paul_Tibble/about      //
// Please consider tipping, if you find this useful.  //
////////////////////////////////////////////////////////

//use the outer diameter of pipe
inner_diameter = 20;
//
wall_thickness = 3;
//from center of fitting to end of port
length = 30;
//use the wall thickness of the pipe
recess_thickness = 2;
//how far the pipe enters into the fitting
recess_depth = 15;

//do not change these
$fn = 100*1;
inner_radius = inner_diameter/2;
outer_diameter = inner_diameter + (wall_thickness*2);
outer_radius = outer_diameter/2;
fillet_radius = wall_thickness/2;

module create_center_bore() {
    sphere(inner_radius+0.001);
}

module create_center(){
    sphere(outer_radius+0.001);
}
module create_center_recess_bore() {
    sphere((inner_radius-recess_thickness)+0.001);
}

module create_center_recess(){
    sphere(inner_radius+0.001);
}

module create_x_recess(){
    rotate([0,90,0])translate([0,0,(length-recess_depth)/2])cylinder(length-recess_depth,inner_radius+0.001,inner_radius+0.001,true);
}
module create_x_recess_bore(){
    rotate([0,90,0])translate([0,0,length/2])cylinder(length,(inner_radius-recess_thickness),(inner_radius-recess_thickness),true);
}
module create_x_bore(){
    rotate([0,90,0])translate([0,0,length])cylinder(length*2,inner_radius,inner_radius,true);
}
module create_x_outer(){
    rotate([0,90,0]){
        rotate_extrude(angle=360,convexity=10){
            square([outer_radius,length-fillet_radius]);
            translate([outer_radius-fillet_radius,length-fillet_radius,0])circle(fillet_radius);
            translate([0,length-fillet_radius,0])square([outer_radius-fillet_radius,fillet_radius]);
        }
    }
}

module create_mx_recess(){
    rotate([0,0,180])create_x_recess();
}
module create_mx_recess_bore(){
    rotate([0,0,180])create_x_recess_bore();
}
module create_mx_bore(){
    rotate([0,0,180])create_x_bore();
}
module create_mx_outer(){
    rotate([0,0,180])create_x_outer();
}

module create_y_recess(){
    rotate([0,0,90])create_x_recess();
}
module create_y_recess_bore(){
    rotate([0,0,90])create_x_recess_bore();
}
module create_y_bore(){
    rotate([0,0,90])create_x_bore();
}
module create_y_outer(){
    rotate([0,0,90])create_x_outer();
}

module create_my_recess(){
    rotate([0,0,-90])create_x_recess();
}
module create_my_recess_bore(){
    rotate([0,0,-90])create_x_recess_bore();
}
module create_my_bore(){
    rotate([0,0,-90])create_x_bore();
}
module create_my_outer(){
    rotate([0,0,-90])create_x_outer();
}

module create_z_recess(){
    rotate([0,-90,0])create_x_recess();
}
module create_z_recess_bore(){
    rotate([0,-90,0])create_x_recess_bore();
}
module create_z_bore(){
    rotate([0,-90,0])create_x_bore();
}
module create_z_outer(){
    rotate([0,-90,0])create_x_outer();
}

module create_mz_recess(){
    rotate([0,90,0])create_x_recess();
}
module create_mz_recess_bore(){
    rotate([0,90,0])create_x_recess_bore();
}
module create_mz_bore(){
    rotate([0,90,0])create_x_bore();
}
module create_mz_outer(){
    rotate([0,90,0])create_x_outer();
}
//difference(){
union(){
    difference(){
        union(){
            create_center();
            create_x_outer();
            create_mx_outer();
            create_y_outer();
            create_my_outer();
            create_z_outer();
            //create_mz_outer();
        }
        create_center_bore();
        create_x_bore();
        create_mx_bore();
        create_y_bore();
        create_my_bore();
        create_z_bore();
        //create_mz_bore();
    }

    difference(){
        union(){
            create_center_recess();
            create_x_recess();
            create_mx_recess();
            create_y_recess();
            create_my_recess();
            create_z_recess();
            //create_mz_recess();
        }
        create_center_recess_bore();
        create_x_recess_bore();
        create_mx_recess_bore();
        create_y_recess_bore();
        create_my_recess_bore();
        create_z_recess_bore();
        //create_mz_recess_bore();
    }
}
//translate([0,0,-100])cube([200,200,200],true);
//}
```


[User]
I'm looking to design a modular desk organizer, specifically a pencil holder with some extra features. I'd like it to be parametric so I can easily change dimensions and features later.

Here's what I have in mind:

**Core Components:**

*   **Cubilete (Pot/Cup):** This is the basic unit - a square-based, cylindrical container. I need to be able to control the:
    *   Inner width/depth (`d`)
    *   Wall thickness (`t`)
    *   Height (`h`)
    *   Corner rounding radius (`r`), which should have a limit to prevent it from exceeding the pot's size
*   **Stackable Design:** The pots should be stackable. I want two stacking system options:
    *   **Trim:** A simple, slightly smaller rim that fits inside the base of the pot above it.  This should include a small tolerance (`tol`) to make stacking easier.
    *   **Magnets:** Holes for small cylindrical magnets, which should have settable diameter (`md`) and height (`mh`). There should also be a tolerance for these.

*   **Divided Pot:** I want the ability to create a single object that is a series of stacked pots, either with the trim or magnets option specified. This is based on the number of divisions (`nd`). Each "division" should be a `cubilete` of height `h/nd`.

*   **Lid:** A lid for the pot. It should also have options for either the trim stack system or magnets.

*   **MicroSD Card Insert:**  A small insert that can be placed inside a pot and used to hold several microSD cards. It should have labeled slots for each card ("A","B","1","2",etc).

**Customization:**

*   I need to easily switch between the trim and magnet stacking systems, potentially via a string parameter `ss`, which should have "Trim" and "Magnets" as available options.
*   The number of divisions for the split pots should be controlled by an integer parameter `nd`.
*   I'd like to control whether or not the various parts (pots, lids, microSD insert) are exported through `exportar_cubiletes`, `exportar_tapa`, and `exportar_microsd` boolean parameters.

**General:**

*   I need the `$fn` to be adjustable for smooth curves, with a default of 100.
*   I'll need a library of functions, so include a `jmutils.scad` with any helper functions. Please just specify that the library is used; don't write the code for it.
*   Make sure that the design is parameterized, meaning everything should be defined with variables that can be changed at the top of the file.

Could you create the necessary OpenSCAD files for this? I'm thinking probably just one main file, or maybe a couple if it makes sense, in addition to the specified library.

[Assistant]
cubilete_modular_v3_accesorios.scad:
```
/* Modular pencil holder by Jose Manuel Rute, 2018-06-07. Thingiverse: vimamsa  */

// Añadir tolerancias encaje piezas !!! <<<<-------------------------

/* [Pot] */
// inner width
    d=40;
// wall thickness
    t=5;
// height
    h=70;
// corner rounding radius: 0 (squared)  <= r < d/2 (rounded)
    r=15;
/* [Splitting] */
// number of divisions
    nd=2;
// Stacking system
    ss="Trim"; //["Trim", "Magnets"]
// Magnet diameter
    md=3;
// Magnet height
    mh=1;
// tolerance (clearance)
    tol=0.5;
/* [Export] */
    exportar_cubiletes="Yes"; //[Yes,No]
    exportar_tapa="Yes"; //[Yes,No]
    exportar_microsd="Yes"; //[Yes,No]
/* [Other] */
// $fn
    $fn=100;

use <jmutils.scad>

// valores calculados
a= d+2*t; // ancho exterior
rv=(r<d/2 ? r:d/2-0.01); // radio validado

if (exportar_cubiletes=="Yes") {cubilete_div (nd=nd);}
if (exportar_tapa=="Yes") {translate([0,-a-2,0]) tapa();}
//if (exportar_microsd=="Yes") {translate([a+6,-a,0]) microsd_insert();}
if (exportar_microsd=="Yes") {translate([a+2+t,t,2*t]) microsd_insert();}

// -------------------------------------------------------------------
module cubilete(x=d, y=d, h=h, r=rv)
{
    translate([r+t,r+t,0]) union()
    {
        linear_extrude(height=t) // base
        {
            offset(r=r+t) square([x-2*r,y-2*r], center=false);
        }

        linear_extrude(height=h) // tubo
        {
            difference()
            {
                offset(r=r+t) square([x-2*r,y-2*r], center=false);
                offset(r=r) square([x-2*r,y-2*r], center=false);
            }
        }
    }
}

module tubo (x=d, y=d, h=h, r=rv)
{
    translate([r+t,r+t,0]) linear_extrude(height=h)
        {
            difference()
            {
                offset(r=r+t) square([x-2*r,y-2*r], center=false);
                offset(r=r) square([x-2*r,y-2*r], center=false);
            }
        }
}

module cubilete_apilable(x=d, y=d, h=h, r=rv)
{
    difference()
    {
    translate([r+t,r+t,0]) union()
    {
        linear_extrude(height=2*t) // base
        {
            offset(r=r+t) square([x-2*r,y-2*r], center=false);
        }

        linear_extrude(height=h) // tubo
        {
            difference()
            {
                offset(r=r+t) square([x-2*r,y-2*r], center=false);
                offset(r=r) square([x-2*r-tol,y-2*r-tol], center=false);
            }
        }
    }
    tubo(x,y,t,rv);
}
}

module cubilete_ap_imanes (x=d, y=d, h=h, r=rv)
{
    difference()
    {
    translate([r+t,r+t,0]) union()
    {
        linear_extrude(height=t) // base
        {
            offset(r=r+t) square([x-2*r,y-2*r], center=false);
        }

        linear_extrude(height=h) // tubo
        {
            difference()
            {
                offset(r=r+t) square([x-2*r,y-2*r], center=false);
                offset(r=r) square([x-2*r,y-2*r], center=false);
            }
        }
    }
    translate([a/2, a-t/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a/2, t/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([t/2, a/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a-t/2, a/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a/2, a-t/2,0]) cylinder(d=md, h=mh+tol);
    translate([a/2, t/2,0]) cylinder(d=md, h=mh+tol);
    translate([t/2, a/2,0]) cylinder(d=md, h=mh+tol);
    translate([a-t/2, a/2,0]) cylinder(d=md, h=mh+tol);
}
}

module cub_ap_im_base (x=d, y=d, h=h, r=rv)
{
    difference()
    {
    translate([r+t,r+t,0]) union()
    {
        linear_extrude(height=t) // base
        {
            offset(r=r+t) square([x-2*r,y-2*r], center=false);
        }

        linear_extrude(height=h) // tubo
        {
            difference()
            {
                offset(r=r+t) square([x-2*r,y-2*r], center=false);
                offset(r=r) square([x-2*r,y-2*r], center=false);
            }
        }
    }
    translate([a/2, a-t/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a/2, t/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([t/2, a/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a-t/2, a/2,h-mh-tol]) cylinder(d=md, h=mh+tol);
}
}

module cubilete_div (nd=nd)
{
    hd=h/nd; echo(hd);
    for (i=[0:nd-1])
    {
        translate([i*(a+2),0,0])
        if (i==0)
        {
            if (ss=="Trim")
            {
                cubilete(d, d, hd, rv);
            }
            else
            {
                cub_ap_im_base (d, d, hd, rv);
            }

        }
        else
        {
            if (ss=="Trim")
                {cubilete_apilable(d,d,hd,rv);}
            else
                {cubilete_ap_imanes (d, d, hd, rv);}
        }
    }
}

module tapa_sin_iman(x=d, y=d, h=h, r=rv)
{
    translate([r+t,r+t,0]) union()
    {
        linear_extrude(height=t) offset(r=r+t) square([x-2*r,y-2*r], center=false);
        translate([0,0,t]) linear_extrude(height=t) offset(r=r) square([x-2*r-tol,y-2*r-tol], center=false);
    }
}

module tapa_imanes (x=d, y=d, h=h, r=rv)
{
    difference() {
    translate([r+t,r+t,0])
    linear_extrude(height=t) offset(r=r+t) square([x-2*r,y-2*r], center=false);
    translate([a/2, a-t/2,t-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a/2, t/2,t-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([t/2, a/2,t-mh-tol]) cylinder(d=md, h=mh+tol);
    translate([a-t/2, a/2,t-mh-tol]) cylinder(d=md, h=mh+tol);
}
}

module tapa()
{
    if (ss=="Trim")
    {tapa_sin_iman();}
    else
    {tapa_imanes();}
}

module microsd_insert()
{
    num=["1", "2", "3", "4", "5", "6", "7"];
    union()
    {
    difference(){
    translate([r,r,0]) linear_extrude(height=14) offset(r=r) square(d-2*r, center=false);
    translate([a/2-t,a/2-t,4]) ranuras_microsd();
    }
    translate([9,32,14]) linear_extrude(height=1) text("A", size=5);
    translate([26,32,14]) linear_extrude(height=1) text("B", size=5);
    for (i=[0:6])
    {
        translate([19,29-3.7*i,14]) linear_extrude(height=1) text(num[i], size=3);
    }
    }
}

module ranuras_microsd(nx=2, ny=7)
{
translate([-15,-12,0]) for (x=[0:nx-1])
    {
        for (y=[0:ny-1])
        {
            translate([x*(12+6),y*3.5]) cube([12.5,1,10]);
        }
    }
}

module colocar_cubiletes()
{
    if (num_cubiletes=="all")
    {
        for (x=[0:nx-1])
        {
            for (y=[0:ny-1])
            {
                color(espar(x) ? (espar(y) ? "Gray":"Orange") : (espar(y) ? "Orange":"Gray")) {translate([x*a+(x+1)*(en_bandeja=="inside" ? tol:2*tol),y*a+(y+1)*(en_bandeja=="inside" ? tol:2*tol),(en_bandeja=="inside" ? t:0)]) cubilete();}
            }
        }
    }
    else
    {
        color("Orange") {translate([tol,tol,(en_bandeja=="inside" ? t:0)]) cubilete();}
    }
}

function espar(x)= x/2-floor(x/2)==0 ? true:false;

```


[User]
I'd like to have a parametric OpenSCAD design for a 4-way flat pipe connector, similar to the one I've seen on Thingiverse. I'm thinking it should be customizable for different pipe sizes and thicknesses, as well as the depth the pipe goes into the connector.

Specifically, I need to be able to define:

*   `inner_diameter`: The inner diameter of the pipe the connector is for.
*   `wall_thickness`: The wall thickness of the pipe.
*   `length`:  The distance from the center of the connector to the end of one of the ports.
*   `recess_thickness`: The thickness of the material removed to create a recess for the pipe to enter.
*   `recess_depth`: How far the pipe should enter into the fitting's recess.

The connector should have four ports, all arranged in a flat plane, and I'd like it to have a central spherical portion. The pipe ports should have recesses that are slightly larger than the pipe to allow for easy insertion and a good fit, and the outer shape of the ports should have rounded edges where they meet the main body of the connector.

I don't need any nuts, bolts, or other fasteners integrated, just a solid, printable connector with the customizable features described. It would also be great if it could work with the BOSL2 library so I can use some of its functions for more advanced customization later on.

[Assistant]
4_Way_Flat.scad:
```
////////////////////////////////////////////////////////
// Created by Paul Tibble - 11/5/18                   //
// https://www.thingiverse.com/Paul_Tibble/about      //
// Please consider tipping, if you find this useful.  //
////////////////////////////////////////////////////////

//use the outer diameter of pipe
inner_diameter = 20;
//
wall_thickness = 3;
//from center of fitting to end of port
length = 30;
//use the wall thickness of the pipe
recess_thickness = 2;
//how far the pipe enters into the fitting
recess_depth = 15;

//do not change these
$fn = 100*1;
inner_radius = inner_diameter/2;
outer_diameter = inner_diameter + (wall_thickness*2);
outer_radius = outer_diameter/2;
fillet_radius = wall_thickness/2;

module create_center_bore() {
    sphere(inner_radius+0.001);
}

module create_center(){
    sphere(outer_radius+0.001);
}
module create_center_recess_bore() {
    sphere((inner_radius-recess_thickness)+0.001);
}

module create_center_recess(){
    sphere(inner_radius+0.001);
}

module create_x_recess(){
    rotate([0,90,0])translate([0,0,(length-recess_depth)/2])cylinder(length-recess_depth,inner_radius+0.001,inner_radius+0.001,true);
}
module create_x_recess_bore(){
    rotate([0,90,0])translate([0,0,length/2])cylinder(length,(inner_radius-recess_thickness),(inner_radius-recess_thickness),true);
}
module create_x_bore(){
    rotate([0,90,0])translate([0,0,length])cylinder(length*2,inner_radius,inner_radius,true);
}
module create_x_outer(){
    rotate([0,90,0]){
        rotate_extrude(angle=360,convexity=10){
            square([outer_radius,length-fillet_radius]);
            translate([outer_radius-fillet_radius,length-fillet_radius,0])circle(fillet_radius);
            translate([0,length-fillet_radius,0])square([outer_radius-fillet_radius,fillet_radius]);
        }
    }
}

module create_mx_recess(){
    rotate([0,0,180])create_x_recess();
}
module create_mx_recess_bore(){
    rotate([0,0,180])create_x_recess_bore();
}
module create_mx_bore(){
    rotate([0,0,180])create_x_bore();
}
module create_mx_outer(){
    rotate([0,0,180])create_x_outer();
}

module create_y_recess(){
    rotate([0,0,90])create_x_recess();
}
module create_y_recess_bore(){
    rotate([0,0,90])create_x_recess_bore();
}
module create_y_bore(){
    rotate([0,0,90])create_x_bore();
}
module create_y_outer(){
    rotate([0,0,90])create_x_outer();
}

module create_my_recess(){
    rotate([0,0,-90])create_x_recess();
}
module create_my_recess_bore(){
    rotate([0,0,-90])create_x_recess_bore();
}
module create_my_bore(){
    rotate([0,0,-90])create_x_bore();
}
module create_my_outer(){
    rotate([0,0,-90])create_x_outer();
}

module create_z_recess(){
    rotate([0,-90,0])create_x_recess();
}
module create_z_recess_bore(){
    rotate([0,-90,0])create_x_recess_bore();
}
module create_z_bore(){
    rotate([0,-90,0])create_x_bore();
}
module create_z_outer(){
    rotate([0,-90,0])create_x_outer();
}

module create_mz_recess(){
    rotate([0,90,0])create_x_recess();
}
module create_mz_recess_bore(){
    rotate([0,90,0])create_x_recess_bore();
}
module create_mz_bore(){
    rotate([0,90,0])create_x_bore();
}
module create_mz_outer(){
    rotate([0,90,0])create_x_outer();
}
//difference(){
union(){
    difference(){
        union(){
            create_center();
            create_x_outer();
            create_mx_outer();
            create_y_outer();
            create_my_outer();
            //create_z_outer();
            //create_mz_outer();
        }
        create_center_bore();
        create_x_bore();
        create_mx_bore();
        create_y_bore();
        create_my_bore();
        //create_z_bore();
        //create_mz_bore();
    }

    difference(){
        union(){
            create_center_recess();
            create_x_recess();
            create_mx_recess();
            create_y_recess();
            create_my_recess();
            //create_z_recess();
            //create_mz_recess();
        }
        create_center_recess_bore();
        create_x_recess_bore();
        create_mx_recess_bore();
        create_y_recess_bore();
        create_my_recess_bore();
        //create_z_recess_bore();
        //create_mz_recess_bore();
    }
}
//translate([0,0,-100])cube([200,200,200],true);
//}
```


[User]
I'm looking to design a series of pipe connectors for use with standard PVC pipe, and I want them to be parametric so I can easily adjust them for different pipe sizes. I'd like to start with a "4-Way Edge" connector, similar to the one in the included SCAD file, but I'd like it to be more robust and flexible in its design.

Specifically, I'd like the following features:

*   **Parametric Pipe Dimensions:** The design should be driven by parameters for the pipe's inner diameter, wall thickness, and a recess thickness that controls how snug the pipe fits into the connector. It's important that the recess be a separate feature so that I can use the same design for a frictional fit connector or one designed for a glued connection.
*   **Parametric Port Length:** I need to be able to control the length of the port from the center of the fitting to the end of each pipe insertion point.
*   **Recess Depth:** There should also be a parameter for how deep the pipe goes into the connector.
*   **Filleted Edges:** All of the outer edges should have a fillet to improve strength and appearance. The fillet radius should be a function of the pipe wall thickness.
*   **Precise Bores:** The internal bores for the pipes should be very slightly larger than the inner diameter of the pipes (e.g. 0.001mm) to allow for a tight fit.
*   **Center Bore:** The very center of the connector should have a bore matching the internal diameter of the pipes for each port.
*   **OpenSCAD Libraries:** I'd like this to use the `BOSL2` library to improve some of the more complex geometries.

Could you please generate the necessary parametric OpenSCAD file(s) to create this connector, using the parameters and features listed above, and ensuring it utilizes the BOSL2 library? I would also like the file(s) to have good comments for readability.

[Assistant]
4_Way_Edge.scad:
```
////////////////////////////////////////////////////////
// Created by Paul Tibble - 11/5/18                   //
// https://www.thingiverse.com/Paul_Tibble/about      //
// Please consider tipping, if you find this useful.  //
////////////////////////////////////////////////////////

//use the outer diameter of pipe
inner_diameter = 20;
//
wall_thickness = 3;
//from center of fitting to end of port
length = 30;
//use the wall thickness of the pipe
recess_thickness = 2;
//how far the pipe enters into the fitting
recess_depth = 15;

//do not change these
$fn = 100*1;
inner_radius = inner_diameter/2;
outer_diameter = inner_diameter + (wall_thickness*2);
outer_radius = outer_diameter/2;
fillet_radius = wall_thickness/2;

module create_center_bore() {
    sphere(inner_radius+0.001);
}

module create_center(){
    sphere(outer_radius+0.001);
}
module create_center_recess_bore() {
    sphere((inner_radius-recess_thickness)+0.001);
}

module create_center_recess(){
    sphere(inner_radius+0.001);
}

module create_x_recess(){
    rotate([0,90,0])translate([0,0,(length-recess_depth)/2])cylinder(length-recess_depth,inner_radius+0.001,inner_radius+0.001,true);
}
module create_x_recess_bore(){
    rotate([0,90,0])translate([0,0,length/2])cylinder(length,(inner_radius-recess_thickness),(inner_radius-recess_thickness),true);
}
module create_x_bore(){
    rotate([0,90,0])translate([0,0,length])cylinder(length*2,inner_radius,inner_radius,true);
}
module create_x_outer(){
    rotate([0,90,0]){
        rotate_extrude(angle=360,convexity=10){
            square([outer_radius,length-fillet_radius]);
            translate([outer_radius-fillet_radius,length-fillet_radius,0])circle(fillet_radius);
            translate([0,length-fillet_radius,0])square([outer_radius-fillet_radius,fillet_radius]);
        }
    }
}

module create_mx_recess(){
    rotate([0,0,180])create_x_recess();
}
module create_mx_recess_bore(){
    rotate([0,0,180])create_x_recess_bore();
}
module create_mx_bore(){
    rotate([0,0,180])create_x_bore();
}
module create_mx_outer(){
    rotate([0,0,180])create_x_outer();
}

module create_y_recess(){
    rotate([0,0,90])create_x_recess();
}
module create_y_recess_bore(){
    rotate([0,0,90])create_x_recess_bore();
}
module create_y_bore(){
    rotate([0,0,90])create_x_bore();
}
module create_y_outer(){
    rotate([0,0,90])create_x_outer();
}

module create_my_recess(){
    rotate([0,0,-90])create_x_recess();
}
module create_my_recess_bore(){
    rotate([0,0,-90])create_x_recess_bore();
}
module create_my_bore(){
    rotate([0,0,-90])create_x_bore();
}
module create_my_outer(){
    rotate([0,0,-90])create_x_outer();
}

module create_z_recess(){
    rotate([0,-90,0])create_x_recess();
}
module create_z_recess_bore(){
    rotate([0,-90,0])create_x_recess_bore();
}
module create_z_bore(){
    rotate([0,-90,0])create_x_bore();
}
module create_z_outer(){
    rotate([0,-90,0])create_x_outer();
}

module create_mz_recess(){
    rotate([0,90,0])create_x_recess();
}
module create_mz_recess_bore(){
    rotate([0,90,0])create_x_recess_bore();
}
module create_mz_bore(){
    rotate([0,90,0])create_x_bore();
}
module create_mz_outer(){
    rotate([0,90,0])create_x_outer();
}
//difference(){
union(){
    difference(){
        union(){
            create_center();
            create_x_outer();
            create_mx_outer();
            create_y_outer();
            //create_my_outer();
            create_z_outer();
            //create_mz_outer();
        }
        create_center_bore();
        create_x_bore();
        create_mx_bore();
        create_y_bore();
        //create_my_bore();
        create_z_bore();
        //create_mz_bore();
    }

    difference(){
        union(){
            create_center_recess();
            create_x_recess();
            create_mx_recess();
            create_y_recess();
            //create_my_recess();
            create_z_recess();
            //create_mz_recess();
        }
        create_center_recess_bore();
        create_x_recess_bore();
        create_mx_recess_bore();
        create_y_recess_bore();
        //create_my_recess_bore();
        create_z_recess_bore();
        //create_mz_recess_bore();
    }
}
//translate([0,0,-100])cube([200,200,200],true);
//}
```


[User]
Okay, I need an OpenSCAD design for a customizable electrical box, specifically for standard American 120VAC outlets. It should consist of two parts: a base and a cover.

Here are the parameters that need to be adjustable:

*   **Width:** The width of the box, with a default of 69.33mm, and should be able to range from 51mm to 85mm.
*   **Height:** The height of the box, with a default of 41mm, and should be adjustable between 37mm and 70mm.
*   **Thickness:** The thickness of the box walls and cover, with a default of 2mm, should be configurable between 1mm and 4mm.
*   **Clearance Gap:**  A small gap between the box and cover, set to 0.5mm by default.
*   **Screw Hole Diameter:** The diameter of the screw holes at each end of both the base and the cover. The default is 3mm, but should be adjustable from 3mm to 6mm.
*   **Wire Hole Radius:** The radius of the hole for the incoming power wires, set to 10mm by default, and adjustable from 8mm to 12mm.
*   **Screw Position:** The distance of the screw holes from the edge of the box.  This will be the same on the box and the cover, with a default value of 3mm. This should be adjustable, so the user can change the distance of the holes from the side edge.

The design should also have:

*   **Fixed Length:** The length of the box is fixed at 104mm.
*   **Corner Holes:**  Four screw holes in the base for mounting to a wall. The radius of these holes is fixed at 2.5mm.
*   **Mounting Screw Hole Depth:** The depth of the screw holes at each end for securing the cover is 10mm.
*   **Cover Mounting Features:** The cover should have tabs that fit over the posts on the box sides.

I'd also like to be able to choose in the OpenSCAD code which part to render (either the base, the cover, or both parts together). Please use the variable `part` with options like `all_parts__`, `bottom_part__`, and `top_part__` to switch between rendering options. If `part` is not specified, it defaults to `all_parts__`.

The cover should match the base dimensions, taking the thickness and gap into account. The outlet socket holes should have the same dimensions used by Wally in their Thingiverse model (https://www.thingiverse.com/thing:47956) - but I don't need those to be customizable, just included in the design.

I think this should cover everything. I'm not using any specific libraries yet, but I'd appreciate if you could keep it organized and easy to understand.

[Assistant]
ElectricalBox.scad:
```
/*
*  Created by: Anhtien Nguyen
*  Date:  June 11, 2018
*  Description:  an electrical box with the dimension
*/

// Choose, which part you want to see!
part = "all_parts__";  //[all_parts__:All Parts,bottom_part__:Bottom,top_part__:Top]

// Length is fixed at 104mm,  width default 69.33mm
width=69.33; //[51:85]
// Height default 41mm
height=41;  // [37:70]

// Adjust for clearance, thickness
gap = 0.5;
thickness = 2; // [1:4]
// screw diameter (mm) for the holes at 2 ends
hole_diag = 3; // [3:6]
// radius of hole to run the AC wires (mm)
wires_hole_radius = 10; // [8:12]

// Program Section //
if(part == "bottom_part__") {
    box();
} else if(part == "top_part__") {
    cover();
} else if(part == "all_parts__") {
    all_parts();
} else {
    all_parts();
}

module all_parts() {
// call the function for the bottom part
//
translate([0,0,(height+gap+thickness)/2]) box();
//
// call the function for the top part
//
translate([width+gap+(thickness*2)+10,0,thickness/2]) cover();
//    translate([0,0,(height+gap+thickness)+1]) cover();  // this displacement puts the cover on top
}
// Fixed data
length = 104;
hole_depth=10; // how far down those 2 holes go
screw_rad = 2.5; // radius of 4 holes on the plate
rad = 7; // radius of the half columns at the 2 ends
rad=hole_diag*2+1;

module cover(width = width, length = length, height = 41,  screw_pos = 3) {
    difference() {
        // define plate
         cube([width, length, thickness],center=true);

        rotate([0,0,90])
        translate([-length/2+11,0,0])
        union() {
            translate([height + 19.3915,0,0])
            {
            difference() {
                cylinder(r=17.4625, h=15, center = true);
                translate([-24.2875,-15,-2]) cube([10,37,15], center = false);
                translate([14.2875,-15,-2]) cube([10,37,15], center = false);
                }
            }
            translate([height - 19.3915,0,0]){
                difference(){
                cylinder(r=17.4625, h=15, center = true);
                translate([-24.2875,-15,-2]) cube([10,37,15], center = false);
                translate([14.2875,-15,-2]) cube([10,37,15], center = false);
                }
            }
            translate([height,0,-1]) cylinder(r=2, h=10,$fn=12);
            translate([height,0,3.5]) cylinder(r1=2, r2=3.3, h=3);

        } // union

        // define holes at 2 ends
        translate([0,-length/2+1+screw_pos,-thickness]) cylinder(r=hole_diag/2,h=thickness*2,$fn=60);
        translate([0, length/2-1-screw_pos,-thickness]) cylinder(r=hole_diag/2,h=thickness*2,$fn=60);
    }
}

/*
 * Function box()
 * Draw the box
 */
module box(width = width+gap, length = length+gap , height = height +gap, screw_pos = 3) {
    ow_width = width + thickness;
    ow_length= length + thickness;
    ow_height= height  + thickness;

    // fixed values
   eye_diag = 33.6 + gap;
    eye_rad = eye_diag/2;
   eye_width = 28 + gap;

    difference() {
        // define the box without the top
        difference() {
            // outside wall
            intersection() {
                cube([ow_width, ow_length, ow_height],center=true);
            }
            // inside wall
             translate([0,0,thickness]) intersection() {
               cube([width, length, height],center=true);
             }
        }

        // four corner holes
        for (a = [0:90:359])
        {
            rotate([0, 0, a]) translate([20, 20, -ow_height/2])
            cylinder(r=screw_rad+.25, h=10, center=true, $fn=12);
        } // for (a =

        // hot wires hole
        rotate([0,-90,0]) translate([-(wires_hole_radius/2+1),-(ow_width/2-5),-length/2]) cylinder(r=wires_hole_radius,h=50,$fn=60,center=true);

    } //difference box without top

    // screw hole left
    translate([0, -length/2+1,-ow_height/2])
    difference(){
        cylinder(ow_height-(thickness+2), rad,rad,$fn=60);
        translate([-rad,-rad*2-1,-1])cube([rad*2,rad*2,ow_height+2-thickness]);
        translate([0,screw_pos,ow_height-hole_depth+1]) cylinder(r=hole_diag/2,h=hole_depth,$fn=60);
    }
    // screw hole the other left :-)
        rotate([0,0,180])  translate([0, -length/2+1,-ow_height/2])
    difference(){
        cylinder(ow_height-(thickness+2), rad,rad,$fn=60);
        translate([-rad,-rad*2-1,-1])cube([rad*2,rad*2,ow_height+2-thickness]);
        translate([0,screw_pos,ow_height-hole_depth+1]) cylinder(r=hole_diag/2,h=hole_depth,$fn=60);
    }

    // support front
    rotate([0,0,90]) translate([0, -(ow_width/2-thickness),-ow_height/2])
    difference(){
        cylinder(ow_height-(thickness+2), rad,rad,$fn=60);
        translate([-rad,-rad*2-1,-1])cube([rad*2,rad*2,ow_height+2-thickness]);
    }

    // support back
    rotate([0,0,-90]) translate([0, -ow_width/2+thickness,-ow_height/2])
    difference(){
        cylinder(ow_height-(thickness+2), rad,rad,$fn=60);
        translate([-rad,-rad*2-1,-1])cube([rad*2,rad*2,ow_height+2-thickness]);
    }
}
```


[User]
I'm looking to design a dual planetary gear system for a clockwork mechanism, and I need some help generating the OpenSCAD files. I've got the basic specs for the gears, but I need everything to be parametric so I can tweak it later. Here's what I'm envisioning:

The core of the mechanism is a central drive gear that meshes with a set of inner planet gears. These inner planets, in turn, mesh with an inner ring gear. Then, on the outside, that inner ring gear acts as the "sun" for a second set of planet gears, which then mesh with an outer ring/case.

Here are the key parameters I'd like to control:

*   **Overall height (gear_h):** The total thickness of all the gears. I'm thinking 10mm to start.
*   **Circular pitch (cp):** This determines the size of the teeth, let's say 360 for now.
*   **Drive gear teeth (drive_t):** Number of teeth on the central gear, starting at 7.
*   **Inner planet gear teeth (planet_t):** The number of teeth on the first set of planet gears, also 7 for now.
*   **Outer planet gear teeth (planet_t2):** Number of teeth on the second set of planet gears; 6 to begin with.
*   **Inner ring thickness (ring_t):** The thickness of the inner ring gear, determined by how many extra teeth it has compared to the inner planet gears; start with 5.
*   **Shaft diameter (shaft_d):** The diameter of the shafts running through the planet gears; 3mm.
*   **Slot width (slot_w):** Width of a slot on the central drive gear for a drive arm; 2mm.
*   **Slot length (slot_l):** Length of that slot; 8mm.
*   **Number of inner planet gears (inner_planets):** Number of planets in the first planetary set, 4 to begin.
*   **Number of outer planet gears (outer_planets):** Number of planets in the second set; let's go with 8.
*   **Number of teeth to twist across (nTwist):** Controls the helix angle of the herringbone gears; set to 1 for now.
*   **Gear clearance (tol):** Space between gears, say 0.15mm.
*   **Pressure angle (P):** Angle of the gear teeth, 45 degrees is a good start.
*   **Curve resolution ($fa and $fs):** Minimum angle and minimum size for curve resolution; 5 and 1 respectively is fine.

The design needs to include:

*   **A central drive gear with a slot:** The main gear in the middle, needs a slot for a drive arm.
*   **Inner planet gears:** These gears mesh with the central gear and the inner ring. These should have a bore hole for shafts.
*   **An inner ring gear:** That meshes with both the inner planet gears, and also acts as the sun for the outer planet gears.
*   **Outer planet gears:** Gears that mesh with the inner ring gear and the outer ring/case. They also need bore holes.
*   **An outer ring/case:** Acts as the outer boundary and holds everything together.
*   **Herringbone gears:** All gears should be herringbone style.
*   **Shaft holes in the case:** The outer ring needs to have holes to support the shafts for the outer planet gears.
*   **Parametric design:** The number of gears, size, etc., need to be controlled by the parameters above.
*   **Tolerances:** I need some tolerances built in to account for 3D printing. Add `AT` for connection tolerances, `ST` for a shaft tolerance, and `TT` for gear teeth. I'd say: `AT = 0.02`, `ST = AT * 2`, and `TT = AT / 2`.

I'd like the code to be well-organized and easy to understand. I'd also appreciate comments, where appropriate. The code should be designed so that the inner and outer planet gears are evenly spaced, which means the number of inner planet gears must divide `drive_t + ring_t1`, where `ring_t1 = drive_t + 2*planet_t` and the number of outer planet gears must divide `ring_t2 + case_t`, where `ring_t2 = ring_t1 + ring_t` and `case_t = ring_t2 + 2*planet_t2`. If these divisibility requirements are not met, an echo statement should print the error message, but the rest of the code should still run.

I'm hoping you can provide me with a single .scad file for this design. Also, the design will use the included gear module from terrym's parametric gear set on thingiverse, so you can incorporate that directly. Please use the functions `involute_intersect_angle` and `involute`, but you don't need to include those functions. It's very important that the gears are herringbone and reversible.

Let me know if you need any other information!

[Assistant]
DualPlanetarySystemHerringbone.scad:
```
// OpenSCAD Dual Planetary System
// (c) 2018, tmackay
//
// Licensed under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license, http://creativecommons.org/licenses/by-sa/4.0.
//include <MCAD/involute_gears.scad>

// Overall height
gear_h = 10;
// Circular pitch: Length of the arc from one tooth to the next
cp = 360;
// Number of teeth in central drive gear
drive_t = 7;
// Number of teeth in inner planet gears
planet_t = 7;
// Number of teeth in outer planet gears
planet_t2 = 6;
// Extra teeth in ring, determines thickness of inner ring
ring_t = 5;
// Shaft diameter
shaft_d = 3;
// Slot width
slot_w = 2;
// Slot length
slot_l = 8;
// Number of planet gears in inner circle
inner_planets = 4;
// Number of planet gears in outer circle
outer_planets = 8;
// number of teeth to twist across
nTwist=1;
// Gear clearance
tol=0.15;
// pressure angle
P=45;//[30:60]
// Curve resolution settings, minimum angle
$fa = 5;
// Curve resolution settings, minimum size
$fs = 1;

ring_t1 = drive_t+2*planet_t;
ring_t2 = ring_t1 + ring_t;
case_t = ring_t2 + 2*planet_t2;

// Tolerances for geometry connections.
AT=0.02;
ST=AT*2;
TT=AT/2;

helix_angle=atan(PI*nTwist*cp/90/gear_h);

// center gear
rotate([0,0,180/drive_t*(1-planet_t%2)])
    drivegear(t1=drive_t);

// inner planets
planets(t1=planet_t, t2=drive_t,offset=(drive_t+planet_t)*cp/360,n=inner_planets,t=ring_t1+drive_t)
    planetgear(t1 = planet_t, bore=shaft_d);

// inner ring
gearring(t1=ring_t1, t2=ring_t2);

// outer planets
planets(t1=planet_t2, t2=ring_t2, offset=(ring_t2+planet_t2)*cp/360,n=outer_planets,t=case_t+ring_t2)
    planetgear(t1 = planet_t2, bore=shaft_d);

// outer ring
gearcase(t1=case_t);

if ((drive_t+ring_t1)%inner_planets)
{
    echo(str("For even spacing, inner_planets must divide ", drive_t+ring_t1));
}
if ((ring_t2+case_t)%outer_planets)
{
    echo(str("For even spacing, outer_planets must divide ", ring_t2+case_t));
}

// Drive gear with slot
module drivegear(t1=13,reverse=false)
{
    difference()
    {
        planetgear(t1,!reverse);
        translate([-slot_w/2,-slot_l/2,-gear_h/2-TT])
            cube([slot_w,slot_l,gear_h+AT]);
        translate([-slot_l/2,-slot_w/2,-gear_h/2-TT])
            cube([slot_l,slot_w,gear_h+AT]);
    }
}

// reversible herringbone gear with bore hole
module planetgear(t1=13,reverse=false,bore=0)
{
    difference()
    {
        if (reverse) {
            mirror([0,1,0])
                herringbone(t1,PI*cp/180,P,1,tol,helix_angle,gear_h);
        } else {
            herringbone(t1,PI*cp/180,P,1,tol,helix_angle,gear_h);
        }
        translate([0,0,-gear_h/2-TT])
            cylinder(d=bore, h=gear_h+AT);
    }
}

// Space out planet gears approximately equally
module planets()
{
    for(i = [0:n-1])
    rotate([0,0,round(i*t/n)*360/t])
        translate([offset,0,0]) rotate([0,0,round(i*t/n)*360/t*t2/t1])
            children();
}

module gearring(t1=13,t2=51,reverse=false)
{
    difference() {
        rotate([0,0,180/ring_t2*(1-planet_t2%2)])
            planetgear(t1=t2,reverse=!reverse,b=0);
        planetgear(t1=t1,b=0,gear_h=gear_h+TT,tol=-tol);

	}
}

module gearcase(t1=13,teethtwist=1)
{
    difference() {
        translate([0,0,-gear_h/2])union()
        {
            cylinder(r=t1*cp/360+gear_h/2,h=gear_h);
            //shaft supports
            planets(t1=planet_t,t2=ring_t2,offset=t1*cp/360+gear_h/2,n=outer_planets,t=case_t+ring_t2)
                cylinder(d=3*shaft_d,h=gear_h);
        }
  		union()
		{
            planetgear(t1=t1,gear_h=gear_h+TT,tol=-tol);
            //shaftholes
            planets(t1=planet_t,t2=ring_t2,offset=t1*cp/360+gear_h/2,n=outer_planets,t=case_t+ring_t2)
                translate([0,0,-gear_h/2-TT])
                    cylinder(d=shaft_d,h=gear_h+AT);
		}
	}
}

// Herringbone gear code, taken from:
// Planetary gear bearing (customizable)
// https://www.thingiverse.com/thing:138222
// Captive Planetary Gear Set: parametric. by terrym is licensed under the Creative Commons - Attribution - Share Alike license.
module herringbone(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5){
union(){
    translate([0,0,-TT])
	gear(number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance,
		helix_angle,
		gear_thickness/2+TT);
	mirror([0,0,1]) translate([0,0,-TT])
		gear(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness/2+TT);
}}

module gear (
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5,
	flat=false){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
twist=tan(helix_angle)*gear_thickness/pitch_radius*180/PI;

flat_extrude(h=gear_thickness,twist=twist,flat=flat)
	gear2D (
		number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance);
}

module flat_extrude(h,twist,flat){
	if(flat==false)
		linear_extrude(height=h,twist=twist,slices=twist/6)children(0);
	else
		children(0);
}

module gear2D (
	number_of_teeth,
	circular_pitch,
	pressure_angle,
	depth_ratio,
	clearance){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
base_radius = pitch_radius*cos(pressure_angle);
depth=circular_pitch/(2*tan(pressure_angle));
outer_radius = clearance<0 ? pitch_radius+depth/2-clearance : pitch_radius+depth/2;
root_radius1 = pitch_radius-depth/2-clearance/2;
root_radius = (clearance<0 && root_radius1<base_radius) ? base_radius : root_radius1;
backlash_angle = clearance/(pitch_radius*cos(pressure_angle)) * 180 / PI;
half_thick_angle = 90/number_of_teeth - backlash_angle/2;
pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
min_radius = max (base_radius,root_radius);

intersection(){
	rotate(90/number_of_teeth)
		circle($fn=number_of_teeth*3,r=pitch_radius+depth_ratio*circular_pitch/2-clearance/2);
	union(){
		rotate(90/number_of_teeth)
			circle($fn=number_of_teeth*2,r=max(root_radius,pitch_radius-depth_ratio*circular_pitch/2-clearance/2));
		for (i = [1:number_of_teeth])rotate(i*360/number_of_teeth){
			halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
			mirror([0,1])halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
		}
	}
}}

module halftooth (
	pitch_angle,
	base_radius,
	min_radius,
	outer_radius,
	half_thick_angle){
index=[0,1,2,3,4,5];
start_angle = max(involute_intersect_angle (base_radius, min_radius)-5,0);
stop_angle = involute_intersect_angle (base_radius, outer_radius);
angle=index*(stop_angle-start_angle)/index[len(index)-1];
p=[[0,0], // The more of these the smoother the involute shape of the teeth.
	involute(base_radius,angle[0]+start_angle),
	involute(base_radius,angle[1]+start_angle),
	involute(base_radius,angle[2]+start_angle),
	involute(base_radius,angle[3]+start_angle),
	involute(base_radius,angle[4]+start_angle),
	involute(base_radius,angle[5]+start_angle)];

difference(){
	rotate(-pitch_angle-half_thick_angle)polygon(points=p);
	square(2*outer_radius);
}}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / PI;

// Calculate the involute position for a given base radius and involute angle.

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*PI/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*PI/180*cos (involute_angle))
];

```


[User]
Hi, I'm looking to create a customizable hexagonal storage system similar to the "Hive" design, but with much tighter-fitting connectors. I'd like to be able to adjust the size of the main hexagons, the depth of the main hexagon and back walls, the thickness of the hexagon walls, the connector sizes, and the tolerance of the connectors. I'd also like to be able to choose between a solid or openwork back wall, or no back wall at all.

Ideally, I'd like the design to be parametric in OpenSCAD, so that I can easily tweak the dimensions and connector fit. It would be great if the design could also use the same connector sizes even if the main hexagon sizes are different - though I understand this won't create a perfect honeycomb pattern with varying hexagon sizes. It also must use the basic hexagonal module and allow for customization of its height and depth.

Here are the parameters I'm thinking of:

*   **Main Hexagon:**
    *   `HEXAGON_HEIGHT`:  The distance between parallel edges of the main hexagon.
    *   `HEXAGON_DEPTH`: The depth of the main hexagon (distance from the front to the back of the main container area).
    *   `HEXAGON_WALL_THICKNESS`:  The thickness of the main hexagon walls.

*   **Back Wall:**
    *   `BACK_WALL_TYPE`: A setting to select whether to have a back wall, and if so, whether it's solid or openwork. Options should be something like `0:None`, `1:Solid`, `2:Openwork`.
    *   `BACK_WALL_DEPTH`: The depth of the back wall.

*   **Connectors:**
    *   `CONNECTOR_HEIGHT`:  The distance between parallel edges of the connector hexagon.
    *    `CONNECTOR_DISTANCE`: Distance between the central and side connectors
    *   `CONNECTOR_OFFSET`: The fraction of the connector that should be embedded within the main hexagon body.  Should be between 0 and 1, but default it to something like 0.8.
    *   `CONNECTOR_TOLERANCE`: A tolerance value that reduces the size of the positive connectors to ensure they fit snugly into the negative ones.

Could you please generate the necessary OpenSCAD files for this design? I do not have any libraries in particular that are needed.

[Assistant]
hive-like.scad:
```
/* [MAIN HEXAGON] */

// What is the desired distance between two parallel edges of the main hex, so that the drawer would fit ?
HEXAGON_HEIGHT = 65.4;

// What is depth of the main hex, so that the drawer would fit? (distance from the front edge to the beginning of the back wall)
HEXAGON_DEPTH = 3;

// What is the desired thickness of the main hex, so that it is sturdy enough?
HEXAGON_WALL_THICKNESS = 4.82;

/* [BACK WALL] */

// What is the type of the back wall?
BACK_WALL_TYPE = 2; // [0:None,1:Solid,2:Openwork]

// What is the depth of the back wall? (it will be added to the total depth)
BACK_WALL_DEPTH = 1; // [0:10]

/* [CONNECTORS] */

// What is the desired distance of two parallel edges of the connector hex?
CONNECTOR_HEIGHT = 3.85;

// What is the desired distance between the central and side connectors
CONNECTOR_DISTANCE = 5.5;

// What fraction of the connector should be "hidden" within the main hex body.
CONNECTOR_OFFSET  = 0.8; // [0.6:0.1:0.9]

// Tolerance reduces the positive connector size, so it is more likely it fits.
CONNECTOR_TOLERANCE = 0.19;    // [0.0:0.01:4.0]

/* [HIDDEN] */
/*
    Print the part !
    With the defaults, it is most likely compatibile with the Hive system
*/
hive_hexagon(
    HEXAGON_HEIGHT, HEXAGON_DEPTH, HEXAGON_WALL_THICKNESS,
    BACK_WALL_TYPE, BACK_WALL_DEPTH,
    CONNECTOR_HEIGHT, CONNECTOR_DISTANCE, CONNECTOR_OFFSET, CONNECTOR_TOLERANCE
);

/*
    Generates the hive_hex.
*/
module hive_hexagon(
    hexagon_height, hexagon_depth, hexagon_wall_thickness,
    back_wall_type, back_wall_depth,
    connector_height, connector_distance, connector_offset, connector_tolerance){
    base_total_height = total_height(hexagon_height, hexagon_wall_thickness);
    base_total_depth = hexagon_depth + back_wall_depth;

    echo(str("Total base height:", base_total_height));
    echo(str("Total base depth:", base_total_depth));

    union(){
        back_wall(hexagon_height, back_wall_type, back_wall_depth);

        translate([0,0,base_total_depth/2])
        difference(){
            hexagon_with_connectors(base_total_height, connector_height, connector_distance, connector_offset, connector_tolerance, base_total_depth);
            hexagon(hexagon_height, base_total_depth*2);
        };
    }
}

/*
    Generates hexagon of the given size (distance between its parallel edges)
    This version works with my brain a bit better than hexagon in shapes.scad from https://github.com/openscad/MCAD
*/
module hexagon(size, depth) {
  angle_step = 60;
  // Iterate 3 times
  for (n = [0:1:2]){
      rotate([0,0, n*angle_step])
      cube([edge_length(size), size, depth], true);
  }
}

/*
    Generates the hive_hex's back wall.

    Back wall of the container - optional
    type:
    0 - none
    1 - solid
    2 - openwork (ajour)
*/
module back_wall(hexagon_height, type, depth){
    if (type==0) {
        // no wall
    }

    if (type==1) {
        // solid wall
        translate([0,0,depth/2])
        hexagon(hexagon_height, depth);
    }

    if (type==2) {
        // ajour
        color("red");
        edge_thickness = 4;
        hollow_hexagon_height = (hexagon_height + edge_thickness) / 2;

        translate([0,0,depth/2])
        intersection(){
            union(){

                hollow_hexagon(hollow_hexagon_height, edge_thickness, depth);
                for (r = [-150, -90, -30, 30, 90, 150]){
                    rotate([0,0,r])
                    translate([hollow_hexagon_height - edge_thickness/2, 0, 0])
                    rotate([0,0,-r])
                    hollow_hexagon(hollow_hexagon_height, 4, depth);
                }
            };
            hexagon(hexagon_height+depth/2, depth*2);
        }
    }
}

module connectors_set(cube_width, cube_height, cube_depth, connector_size, connector_distance, position, offset_ratio, tolerance){
    /*
    This module draws a set of connectors (a row of connectors)
    */
    //x_translation = 0.22*cube_width;
    x_translation = connector_distance + vertex_to_vertex_distance(connector_size);
    echo(x_translation);
    y_translation = position*(cube_height/2 + connector_size/2 - connector_size*offset_ratio);

    for (n = [-1, 0, 1]) {
        translate([x_translation*n,y_translation,0])
        hexagon(connector_size-tolerance, cube_depth*1.0);
    }
}

module cube_with_connectors(dimmensions, connector_size, connector_distance, connector_offset, connector_tolerance) {
    hex_side_width = dimmensions[0];
    hex_height = dimmensions[1];
    hive_depth = dimmensions[2];

    negative_position = -1;
    positive_position = 1;

    echo (str("Connector tolerance: ",connector_tolerance, "resulted in connector sizes", "\nNEGATIVE: ", connector_size, "\nPOSITIVE:", connector_size-connector_tolerance,"\n"));

    union(){
        difference(){
            cube(dimmensions, true);
            connectors_set(
                hex_side_width, hex_height, hive_depth*2,
                connector_size, connector_distance,
                negative_position, connector_offset, 0);
        }
        connectors_set(
            hex_side_width, hex_height, hive_depth,
            connector_size, connector_distance,
            positive_position, 1 - connector_offset, connector_tolerance);
    }
}

/*
    Modified version of the hexagon.
*/
module hexagon_with_connectors(size, connector_size, connector_distance, connector_offset, connector_tolerance, height) {
  angle_step = 60*2;   // Every second box

  // Iterate 3 times
  for (n = [0:1:2]){
      rotate([0,0, n*angle_step])
      cube_with_connectors([edge_length(size), size, height], connector_size, connector_distance, connector_offset, connector_tolerance);
  }
}

/*
    Calculates total height (edge to edge) based on inner height and wall thickness
*/
function total_height(inner_height, wall_thickness) = inner_height + wall_thickness*2;

/*
    Calculates the vertex to vertex distance
*/
function vertex_to_vertex_distance(edge_to_edge_distance) = edge_to_edge_distance*1.1547;

/*
    Calculates the hexagon edge length
*/
function edge_length(size) = size*0.5774;

module hollow_hexagon(height, wall_thickness, depth){
    difference(){
        hexagon(height, depth);
        hexagon(height-wall_thickness, depth*2);
    }
}

```


[User]
I'm looking to create a series of parametric pipe connectors for a DIY project, and I'd like them to be easily customizable for different pipe sizes. I've seen some existing designs that are close, but I need something fully parametric from the ground up. I'd like to start with a 3-way corner connector, similar to the one in the provided code but without hard-coded values.

The key parameters I need to be able to adjust are:

*   `inner_diameter`: The inner diameter of the pipe that will fit into the connector.
*   `wall_thickness`: The wall thickness of the connector itself.
*   `length`: The length of each arm of the connector from the center of the fitting to the end of the port.
*   `recess_thickness`: The thickness of the recess where the pipe inserts into the connector.
*   `recess_depth`: How far the pipe inserts into the fitting.

The connector should have a spherical center section with three cylindrical arms extending out at 90-degree angles to each other (along the x, y, and z axes). The ends of each arm should have a recess that allows the pipe to fit snugly inside.  I’d like to use the OpenSCAD `rotate_extrude` function as is used in the example for the outer and a straightforward `cylinder` for the inner/recessed regions as shown, but I want it done parametrically and without the negative values (mx, my, and mz) as this should be able to be accomplished with positive rotations. It should be a single file. I'm not picky about the fillet radius - I'm happy with it being half of the wall thickness. I'm also fine with the `$fn` being 100 as in the example. Please use standard OpenSCAD functions and don't include any library files (e.g. MCAD, BOSL, etc.).

[Assistant]
3_Way_Corner.scad:
```
////////////////////////////////////////////////////////
// Created by Paul Tibble - 11/5/18                   //
// https://www.thingiverse.com/Paul_Tibble/about      //
// Please consider tipping, if you find this useful.  //
////////////////////////////////////////////////////////

//use the outer diameter of pipe
inner_diameter = 20;
//
wall_thickness = 3;
//from center of fitting to end of port
length = 30;
//use the wall thickness of the pipe
recess_thickness = 2;
//how far the pipe enters into the fitting
recess_depth = 15;

//do not change these
$fn = 100*1;
inner_radius = inner_diameter/2;
outer_diameter = inner_diameter + (wall_thickness*2);
outer_radius = outer_diameter/2;
fillet_radius = wall_thickness/2;

module create_center_bore() {
    sphere(inner_radius+0.001);
}

module create_center(){
    sphere(outer_radius+0.001);
}
module create_center_recess_bore() {
    sphere((inner_radius-recess_thickness)+0.001);
}

module create_center_recess(){
    sphere(inner_radius+0.001);
}

module create_x_recess(){
    rotate([0,90,0])translate([0,0,(length-recess_depth)/2])cylinder(length-recess_depth,inner_radius+0.001,inner_radius+0.001,true);
}
module create_x_recess_bore(){
    rotate([0,90,0])translate([0,0,length/2])cylinder(length,(inner_radius-recess_thickness),(inner_radius-recess_thickness),true);
}
module create_x_bore(){
    rotate([0,90,0])translate([0,0,length])cylinder(length*2,inner_radius,inner_radius,true);
}
module create_x_outer(){
    rotate([0,90,0]){
        rotate_extrude(angle=360,convexity=10){
            square([outer_radius,length-fillet_radius]);
            translate([outer_radius-fillet_radius,length-fillet_radius,0])circle(fillet_radius);
            translate([0,length-fillet_radius,0])square([outer_radius-fillet_radius,fillet_radius]);
        }
    }
}

module create_mx_recess(){
    rotate([0,0,180])create_x_recess();
}
module create_mx_recess_bore(){
    rotate([0,0,180])create_x_recess_bore();
}
module create_mx_bore(){
    rotate([0,0,180])create_x_bore();
}
module create_mx_outer(){
    rotate([0,0,180])create_x_outer();
}

module create_y_recess(){
    rotate([0,0,90])create_x_recess();
}
module create_y_recess_bore(){
    rotate([0,0,90])create_x_recess_bore();
}
module create_y_bore(){
    rotate([0,0,90])create_x_bore();
}
module create_y_outer(){
    rotate([0,0,90])create_x_outer();
}

module create_my_recess(){
    rotate([0,0,-90])create_x_recess();
}
module create_my_recess_bore(){
    rotate([0,0,-90])create_x_recess_bore();
}
module create_my_bore(){
    rotate([0,0,-90])create_x_bore();
}
module create_my_outer(){
    rotate([0,0,-90])create_x_outer();
}

module create_z_recess(){
    rotate([0,-90,0])create_x_recess();
}
module create_z_recess_bore(){
    rotate([0,-90,0])create_x_recess_bore();
}
module create_z_bore(){
    rotate([0,-90,0])create_x_bore();
}
module create_z_outer(){
    rotate([0,-90,0])create_x_outer();
}

module create_mz_recess(){
    rotate([0,90,0])create_x_recess();
}
module create_mz_recess_bore(){
    rotate([0,90,0])create_x_recess_bore();
}
module create_mz_bore(){
    rotate([0,90,0])create_x_bore();
}
module create_mz_outer(){
    rotate([0,90,0])create_x_outer();
}
//difference(){
union(){
    difference(){
        union(){
            create_center();
            create_x_outer();
            //create_mx_outer();
            create_y_outer();
            //create_my_outer();
            create_z_outer();
            //create_mz_outer();
        }
        create_center_bore();
        create_x_bore();
        //create_mx_bore();
        create_y_bore();
        //create_my_bore();
        create_z_bore();
        //create_mz_bore();
    }

    difference(){
        union(){
            create_center_recess();
            create_x_recess();
            //create_mx_recess();
            create_y_recess();
            //create_my_recess();
            create_z_recess();
            //create_mz_recess();
        }
        create_center_recess_bore();
        create_x_recess_bore();
        //create_mx_recess_bore();
        create_y_recess_bore();
        //create_my_recess_bore();
        create_z_recess_bore();
        //create_mz_recess_bore();
    }
}
//translate([0,0,-100])cube([200,200,200],true);
//}
```


[User]
Hey, I'm looking to get a parametric RC car arm generator created in OpenSCAD. I've been messing around with a design, but I'd like to have something a bit more robust and adaptable.

I've got a pretty good idea of the parameters that I want to control. So basically I need a module that takes parameters to create an RC car arm, which is kind of like a wishbone arm or A-arm. I need it to have mounting points at the frame and at the knuckle.

Here's the gist of the parameters:

*   **Inner_Hole_Diam:** The diameter of the pin at the frame connection. Should be adjustable from 2mm to 8mm in 0.5mm increments.
*   **Frame_Width:** The width of the frame mounting point, or the distance between the two frame connection holes. Adjustable from 10mm to 60mm in 1mm increments.
*   **Max_Frame_Width:** The maximum width of the frame mounting, just a slightly wider value than the Frame_Width. Should be between 20mm and 100mm, 1mm increment.
*   **Arm_Length:**  The length of the arm from frame connection to the knuckle connection.  Adjustable from 20mm to 150mm, 1mm increments.
*   **Outer_Hole_Diam:** The pin diameter at the knuckle connection.  Same as the inner hole: 2mm to 8mm, 0.5mm increment.
*   **Knuckle_Width:** Width of the knuckle mounting, the distance between the two knuckle connection holes. 6mm to 40mm, 1mm increments.
*   **Max_Knuckle_Width:**  The maximum width around the knuckle.  8mm to 80mm, 1mm increments.
*  **Knuckle_Offset**: The Y distance between the frame and the knuckle connection points. Can be positive or negative. Adjust from -30mm to 80mm in 0.5mm increments.
*   **Knuckle_Depth:**  Clearance from knuckle hole to the edge of the arm.  2mm to 25mm in 0.5mm increments.
*   **Middle_Hole_Number:** Number of shock mounting holes between the frame and knuckle. 0 to 8, integer only.
*   **Middle_Hole_X:** Distance from the frame mounting point to the *average* of the middle shock mounting points. 10mm to 120mm, 1mm increment.
*   **Middle_Hole_Offset:**  The Y distance from the frame hole to the flat of the shock mount area. -20mm to 50mm, 1mm increments.
*   **Middle_Hole_Diam:** Diameter of the shock mount holes. 1.5mm to 8mm, 0.2mm increments.
*   **Channel_Diam:** Diameter of an optional channel for an axle or similar. 0 disables it, up to 20mm, 0.5mm increment.
*   **Rib_Thickness:**  Thickness of the ribs. 1.0mm to 8.0mm, 0.1mm increment.
*   **Side**: Choose "Left," "Right," or "Both" to create a left side, right side, or both sides. String type.

Also, a few additional parameters I'm using for the math:

*   **Around_Holes:**  Clearance around holes. Maybe this should just be a fixed value? I'm using 2.5
*   **Frame_Depth:** The clearance from the frame hole to the edge of the arm. I'm using 5
*   **Hole_Spacing:** The distance between the center of shock mount holes. I'm using 3.5
*   **Mount_Width:** The width of the gap for shock mounting points. I'm using 9
*   **Tolerance:** An offset to all of the hole diameters. I'm using 0.2

The design I have now uses a combination of linear extrudes and rotated cylinders and cubes to build the shape. It also has some trig calculations in there for the ribs. I'm not married to this design, and I'm open to other approaches if it makes sense.

The main goal is to have a functional arm design that is easy to modify for different RC cars. I'm hoping you can help me with this. I'm not using any external libraries, so everything should be in a single or at most two files. Thanks!

[Assistant]
Car_arm_Generator.scad:
```
// RC car arm
// Eric Lindholm

// There are a lot of parameters for this file.
// All sizes are in mm.

// The diameter of the pin at the frame point. This controls the thickness of the part.
Inner_Hole_Diam=3;    // [2:0.5:8]
// The frame width is the distance between the two hole mounts for the inner joint.
Frame_Width=30;       // [10:1:60]
// Maximum width of the frame. This can only be obtained with an existing part - making one at random use a value between 15 and 30 higher than the frame width.
Max_Frame_Width=45;   // [20:1:100]
// The arm length is the distance between the frame point and the knuckle.
Arm_Length=93;        // [20:1:150]
// The diameter of the pin at the knuckle point. This controls the slope of the part.
Outer_Hole_Diam=3;    // [2:0.5:8]
// The knuckle width is the distance between the two hole mounts on the knuckle.
Knuckle_Width=15;     // [6:1:40]
// The distance around the knuckle width. This also affects the width around the frame mount.
Max_Knuckle_Width=28; // [8:1:80]
//  The Y distance between the frame mounting point and knuckle mounting point.
Knuckle_Offset=7.5;   // [-30:0.5:80]
// Clearance between the knuckle hole and the edge of the arm. If not necessary, about 2-3x knuckle hole diameter is good.
Knuckle_Depth=12;     // [2:0.5:25]
// Number of holes between the frame and knuckle. This is where the shocks mount.
Middle_Hole_Number=5; // [0:1:8]
// This is the distance from the frame point to the MIDDLE shock mount. (Technically, the average of the hole points.)
Middle_Hole_X=43;     // [10:1:120]
// This is the distance from the front of the frame mount to the flat of the shock mount areas.
Middle_Hole_Offset=-2;     // [-20:1:50]
// This is the diameter of each shock mount hole.
Middle_Hole_Diam=2.4;   // [1.5:0.2:8]
// This creates a round channel for an axle, where the outer radius just touches the bottom of the part near the knuckle. Recommend less than or equal to knuckle width. 0 = disable
Channel_Diam=14;       // [0:0.5:20]
// Thicker ribs = stronger part, right?
Rib_Thickness=4.5;       // [1.0:0.1:8.0]
// This basically mirrors the part. Or, you could have both sides in the same file.
Side="Both";         // ["Left","Right","Both"]

// Preview[view:south east, tilt: top diagonal]

/* [hidden] */

// Make the thing
if(Side=="Right")
	arm();
if(Side=="Left")
	mirror([1,0,0])
		arm();
if(Side=="Both") {
	translate([ht,0,0])
		arm();
	translate([-ht,0,0])
		mirror([1,0,0])
			arm();
}

// Other parameters
$fn=36;             // I don't like the default.
Around_Holes=2.5;
Frame_Depth=5;      // Clearance between the frame hole and the edge of the arm.
Hole_Spacing=3.5;     // Distance between center holes.
Mount_Width=9;     // The width of the gap for the shock mount holes (also depth of holes)
Tolerance=0.2;     // expands all hole diameters by this much

// Math
ht=Around_Holes*Inner_Hole_Diam;
knucklecenterline=(Frame_Width-Knuckle_Width)/2-Knuckle_Offset;  // I'm not sure if it's easier to measure this or the knuckle offset.
extra=(Max_Knuckle_Width-Knuckle_Width)/2;
maxwidth=Max_Frame_Width;
endht=0.95*Around_Holes*Outer_Hole_Diam;
polygonend=Arm_Length-Knuckle_Depth-endht/2;
Middle_Hole_Y=Frame_Width/2-Middle_Hole_Offset;
// All the ribs math (lots of trig)
//langle=atan(0.5*(ht-endht-0.1)/(polygonend-ht));
//langlelen=(polygonend-ht)/cos(langle)+0.5;
sangleR=atan(0.5*(Max_Knuckle_Width-maxwidth+knucklecenterline*2)/(polygonend-endht));
sanglelenR=(polygonend-ht)/cos(sangleR)+endht/2;
sangleL=atan(0.5*(Max_Knuckle_Width-maxwidth-knucklecenterline*2)/(polygonend-endht));
sanglelenL=(polygonend-ht)/cos(sangleR)+endht/2;
crangleR=-atan((Max_Knuckle_Width/2+maxwidth/2-Rib_Thickness-knucklecenterline)/(polygonend-ht));
cranglelenR=(polygonend-ht)/cos(crangleR)+Rib_Thickness/4;
crangleL=atan((Max_Knuckle_Width/2+maxwidth/2
-Rib_Thickness+knucklecenterline)/(polygonend-ht));
cranglelenL=(polygonend-ht)/cos(crangleL)+Rib_Thickness/4;
// Shock mount math
mountxlen=Hole_Spacing*Middle_Hole_Number;
holedepth=Mount_Width*1.5;
aroundhole=(Around_Holes*Middle_Hole_Diam>endht)?endht:Around_Holes*Middle_Hole_Diam;
m=-0.5*(maxwidth-Max_Knuckle_Width+knucklecenterline)/(polygonend-ht);
insidehole=(Middle_Hole_Y+Mount_Width-m*Middle_Hole_X)<=(Max_Knuckle_Width/2+knucklecenterline-m*polygonend); // not a mistake
// axle slot math
changley=atan((Channel_Diam)/Arm_Length);
changlez=atan(knucklecenterline/polygonend);
chlen=Arm_Length*1.5;

//Debug
//echo(knucklecenterline);
//echo(sangle);
//echo(m);
//echo(Middle_Hole_Y-m*Middle_Hole_X);
//echo(Max_Knuckle_Width-m*polygonend);
//echo(aroundhole);
//echo(insidehole);

// Main module
module arm() {
difference() {
	// Positive entities
	union() {
		// Frame mount point
		translate([0,0,ht/2])
			rotate(90,[1,0,0])
				cylinder(r=ht/2,h=maxwidth,center=true);
		translate([ht/2,0,ht/2])
			cube([ht,maxwidth,ht],center=true);
		// Main: create lower portion, then side ribs, then cross-ribs
		// Flat base
		//translate([ht,0,0])
			//rotate(-langle,[0,1,0])
				linear_extrude(height=Rib_Thickness,convexity=10,twist=0)
					polygon(points=[[ht,maxwidth/2],[ht,-maxwidth/2],[polygonend,knucklecenterline-Max_Knuckle_Width/2],[polygonend,knucklecenterline+Max_Knuckle_Width/2]]);
		// Side ribs
		translate([ht,maxwidth/2,0])
			rotate(sangleR,[0,0,1])
				rotate(90,[1,0,0])
					linear_extrude(height=Rib_Thickness,convexity=10,twist=0)
						polygon(points=[[0,0],[sanglelenR,0],[sanglelenR,endht],[0,ht]]);
		translate([ht,-maxwidth/2,0])
			rotate(-sangleL,[0,0,1])
				rotate(-90,[1,0,0])
					linear_extrude(height=Rib_Thickness,convexity=10,twist=0)
						polygon(points=[[0,0],[sanglelenL,0],[sanglelenL,-endht],[0,-ht]]);
		// Cross ribs
		translate([ht,maxwidth/2,0])
			rotate(crangleR,[0,0,1])
				rotate(90,[1,0,0])
					linear_extrude(height=Rib_Thickness,convexity=10,twist=0)
						polygon(points=[[0,0],[0,ht],[cranglelenR,endht],[cranglelenR,0]]);
		translate([ht,-maxwidth/2,0])
			rotate(crangleL,[0,0,1])
				rotate(-90,[1,0,0])
					linear_extrude(height=Rib_Thickness,convexity=10,twist=0)
						polygon(points=[[0,0],[0,-ht],[cranglelenL,-endht],[cranglelenL,0]]);

		// Knuckle Mount point
		translate([polygonend+Knuckle_Depth/2+endht/4,knucklecenterline,endht/2])
			cube([Knuckle_Depth+endht/2,Max_Knuckle_Width,endht],center=true);
		translate([Arm_Length,knucklecenterline,endht/2])
			rotate(90,[1,0,0])
				cylinder(r=endht/2,h=Max_Knuckle_Width,center=true);

		// Shock mounting points
		if(insidehole)
			translate([0,0,(endht+ht)/4])
				InsideMountHolePos();
		else
			translate([0,0,(endht+ht)/4])
				OutsideMountHolePos();
	}
	// Negative entities
	union() {
		// Frame hole and cut-out
		translate([0,0,ht/2])
			rotate(90,[1,0,0])
				cylinder(r=Inner_Hole_Diam/2+Tolerance,h=maxwidth+1,center=true);
		translate([0,0,ht/2])
			cube([2*Frame_Depth,Frame_Width+Tolerance,ht+4], center=true);
		// Knuckle hole and cut-out
		translate([Arm_Length,knucklecenterline,endht/2])
			rotate(90,[1,0,0])
				cylinder(r=Outer_Hole_Diam/2+Tolerance,h=maxwidth+2    ,center=true);
		translate([Arm_Length,knucklecenterline,endht/2])
			cube([Knuckle_Depth*2,Knuckle_Width+Tolerance,endht+2],center=true);
		// Axle channel cut-out
		translate([0,0,Channel_Diam*1.5])
			rotate(changlez,[0,0,1])
				rotate(90+changley,[0,1,0])
		 			cylinder(r=Channel_Diam/2,h=chlen);

		// Shock mounting points
		if(insidehole)
			translate([0,0,(endht+ht)/4])
				InsideMountHoleNeg();
		else
			translate([0,0,(endht+ht)/4])
				OutsideMountHoleNeg();
	}
}
}

// Creates shock mountings inside rib area
module InsideMountHolePos() {
translate([Middle_Hole_X,Middle_Hole_Y,0])
    // An inverse slot
	union() {
		cube([mountxlen,holedepth*1.5,aroundhole],center=true);
		translate([-mountxlen/2,0,0])
			rotate(90,[1,0,0])
				cylinder(r=aroundhole/2,h=holedepth*1.5,center=true);
		translate([mountxlen/2,0,0])
			rotate(90,[1,0,0])
				cylinder(r=aroundhole/2,h=holedepth*1.5,center=true);
	}
}

// negative section for the inside holes
module InsideMountHoleNeg() {
translate([Middle_Hole_X,Middle_Hole_Y,0])
    // Slot for mount positions, then all the mounting holes
	union() {
		cube([mountxlen,Mount_Width+Tolerance,ht*2],center=true);
		translate([-mountxlen/2,0,0])
			rotate(90,[1,0,0])
				cylinder(r=ht,h=Mount_Width+Tolerance,center=true);
		translate([mountxlen/2,0,0])
			rotate(90,[1,0,0])
				cylinder(r=ht,h=Mount_Width+Tolerance,center=true);
		if(Middle_Hole_Number>1)
			for(m=[1:1:Middle_Hole_Number])
				translate([-mountxlen/2+(m-1)*mountxlen/(Middle_Hole_Number-1),-Mount_Width,0])
					rotate(-90,[1,0,0])
						cylinder(r=Middle_Hole_Diam/2+Tolerance,h=holedepth+maxwidth/2,center=false);
		if(Middle_Hole_Number==1)
			translate([0,-Mount_Width,0])
				rotate(-90,[1,0,0])
					cylinder(r=Middle_Hole_Diam/2+Tolerance,h=holedepth+maxwidth/2,center=false);
	}
}

// Creates shock mountings outside rib area
module OutsideMountHolePos() {
translate([Middle_Hole_X,Middle_Hole_Y,0])
    // An inverse slot
	union() {
		translate([0,-holedepth/2,0])
			cube([mountxlen,holedepth,aroundhole],center=true);
		translate([-mountxlen/2,-holedepth/2,0])
			rotate(90,[1,0,0])
				cylinder(r=aroundhole/2,h=holedepth,center=true);
		translate([mountxlen/2,-holedepth/2,0])
			rotate(90,[1,0,0])
				cylinder(r=aroundhole/2,h=holedepth,center=true);
	}
}

// Negative section for the outer holes
module OutsideMountHoleNeg() {
translate([Middle_Hole_X,Middle_Hole_Y,0])
    // A slot for mount points, then all the holes
	union()  {
		if(Middle_Hole_Number>1)
			for(m=[1:1:Middle_Hole_Number])
				translate([-mountxlen/2+(m-1)*mountxlen/(Middle_Hole_Number-1),0,0])
					rotate(90,[1,0,0])
						cylinder(r=Middle_Hole_Diam/2+Tolerance,holedepth*7/4,center=true);
		if(Middle_Hole_Number==1)
			rotate(90,[1,0,0])
				cylinder(r=Middle_Hole_Diam/2,holedepth*7/4,center=true);
        // slot
		translate([0,holedepth/2,0])
			cube([mountxlen,holedepth,ht*2],center=true);
		translate([-mountxlen/2,holedepth/2,0])
			rotate(90,[1,0,0])
				cylinder(r=ht,h=holedepth,center=true);
		translate([mountxlen/2,holedepth/2,0])
			rotate(90,[1,0,0])
				cylinder(r=ht,h=holedepth,center=true);
	}
}
```


[User]
Okay, I'd like to create a parametric OpenSCAD design for a cap, or maybe a shallow cup depending on how you configure it. It should have a cylindrical body with an inner and outer wall, allowing you to plug it onto the end of a rod. It'll also have an optional base.

Here are the parameters I want to control:

*   **`diameter`**: The diameter of the rod that the cap will fit onto (default 8mm). This will determine the inner diameter of the cap.
*   **`gap`**: The clearance between the rod and the inner wall of the cap (default 0.5mm). This will make sure the fit isn't too tight.
*   **`thickness`**: The thickness of the wall between the inner and outer wall of the cap (default 2mm).
*  **`height`**: The overall height of the cylindrical part of the cap (default 15mm).
*   **`base_diameter`**: The diameter of the optional base (default 16mm). Set to zero to omit the base.
*   **`base_height`**: The height of the optional base (default 5mm).

The cap should be constructed as a difference between two cylinders; the outer cylinder and inner cylinder. The inner cylinder should be shifted up by the wall thickness, so that the base of both cylinders match. This should create a cylindrical "wall".

If the `base_diameter` is greater than zero, I'd like a base cylinder to be added to the bottom. The base should be shifted down by either the thickness or the base height, whichever is smaller, so it doesn't stick out too far into the part.

I'd like to keep the number of facets on the cylinders reasonably high for a nice smooth look, so could you please use a `$fn` of 64 for all cylinders?

Could you create this for me, please?

[Assistant]
rod_ends-v1.scad:
```
/*
*  Name: rod_ends.scad
*  Description: caps to be plugged to the end of rods
*  Author: Anhtien Nguyen
*  Date: June 12, 2018
*/

// diameter of the rod
diameter=8;
rad =diameter/2;
// clearance between rod & inner wall
gap=0.5;
// wall thickness between inner & outter wall
thickness=2;
// rod end height
height=15;
// enter zero here if base not needed
base_diameter=16;
base_radius=base_diameter/2;
//  base height
base_height=5;

cap();

module cap(rad = rad+gap,thick=thickness,height=height, base_height=base_height, base_radius=base_radius) {

    shiftdown = thick > base_height?  base_height :thick;
    difference() {
        // outter circle
    cylinder(r=rad+thick,h=height,$fn=64);
        // inner circle
    translate([0,0,thick]) cylinder(r=rad,h=height,$fn=64);
    }

    // add the base
    if (base_height >0 && base_radius>0)
    {
        translate([0,0,-shiftdown]) cylinder(r=base_radius, h=base_height,$fn=64);
    }

}

```