[User]
I need a parametric OpenSCAD design for a button. I'd like to be able to configure several things:

First, the overall height of the button and the height of the inner, recessed portion should be adjustable. I'll call these `TotalHeight` and `InnerHeight`, respectively.

Second, I need to set the outer diameter and the diameter of the recessed inner part. Let's call these `OuterSize` and `InnerSize`.

I also want to be able to specify how many holes the button has. This number should be able to be set to 0, 1, 2, 3, 4, 5, or 6. Let's call this `NHoles`.

Then, I need to set the size of the holes using the parameter `HoleSize`.

And finally the distance of these holes from the center of the button should be configurable via `HoleDistance`. I need the distance to be at least half the hole size and also less than half of the `InnerSize` .

Lastly I want to add a rounding option to the outer edges. It should be set to `-1` for automatic rounding, `0` for no rounding, and any positive number as the rounding radius `Rounding`. Automatic rounding should be set to 1/5 of the `TotalHeight`.

I would like all of these parameters to be easily configurable at the beginning of the file.

Could you please generate the OpenSCAD code for this design? I don't have any existing code to provide. I'd prefer it doesn't use any external libraries; just the standard OpenSCAD functionality.

[Assistant]
ConfigurableButton.scad:
```
/////////////////Parameters
/* [Sizes] */
// total height
TotalHeight =3;
// inner height
InnerHeight = 2;
// outer size
OuterSize = 20;
// inner size
InnerSize = 16;
// How many holes?
NHoles=4; // [0:6]
// hole size
HoleSize = 2; //
// hole distance from center (to be more than HoleSize/2 and less than InnerSize/2)
HoleDistance = 3;
// rounding: -1 = automatic, 0 = no, >0 = radius of rounding
Rounding = -1;
/* [Hidden] */

knopf(TotalHeight,InnerHeight,OuterSize/2,InnerSize/2,NHoles,HoleDistance,HoleSize/2);

module knopf(h1,h2,r1,r2,nh,rh,ih,rr= -1) {
	irr = (rr<0) ? h1/5 : rr;
	difference() {
		rcyl(r1,h1,irr);
		translate([0,0,h2])
			cylinder(r=r2,h=(h1-h2+0.01),$fn=120);
		if (nh > 1) {
			for (i=[0:360/nh:360-0.01]) {
				translate([cos(i)*rh,sin(i)*rh,0])
					cylinder(r=ih,h=h1*2,center=true,$fn=60);
			}
		} else
			if (nh > 0)
				cylinder(r=ih,h=h1*2,center=true,$fn=60);
	}
}

module rcyl(cr,hh,rr,ce=false,fn=120) {
	if (rr > 0) {
		translate([0,0,rr])
			minkowski() {
				cylinder(r=cr-rr,h=hh-2*rr,center=ce,$fn=fn);
				sphere(rr,$fn=24);
			}
	} else {
		cylinder(r=cr,h=hh,center=ce,$fn=fn);
	}
}

```


[User]
Hey, I'm looking to create a parametric box generator for laser cutting, using finger joints. I'd like to be able to define the box's outer dimensions (width, depth, and height) as well as the material thickness. Also, I need to be able to toggle a lid on or off and define the finger joint widths, including separate widths for the lid.  It would also be cool if I could add a hole in the center of the lid with a customizable diameter and number of facets. Finally, I'd need separate controls for separation between parts and a transparency level of the 3D model, and a toggle to choose between 2D and 3D rendering (for DXF/STL output).

Here's a rundown of the parameters I need to be able to control:

*   **Box Dimensions:**
    *   `bX` (width)
    *   `bY` (depth)
    *   `bZ` (height)
*   **Material:**
    *   `thick` (thickness)
*   **Lid:**
    *   `addLid` (toggle on/off)
    *   `holeDia` (diameter of hole, 0 for no hole)
    *   `holeFacets` (number of facets for the hole)
*   **Finger Joints:**
    *   `fingerW` (width of finger joints on the main box)
    *   `fingerLidW` (width of finger joints on the lid)
*   **Layout:**
    *   `separation` (spacing between cut pieces in 2D)
    *   `alpha` (transparency of 3D model)
    *   `2D` (toggle between 2D/3D output)

The script should output correctly sized parts with finger joints, taking into account material thickness, for either 2D laser cutting layout (in a single plane) or a 3D model. Also, I'd prefer if the code didn't use kerf compensation (I can handle that separately). Let me know if you need any more info!

[Assistant]
finger_joint-3.3.scad:
```
/*
Create an outline for a laser cut box with finger joints
Released under the Creative Commons Attribution License
Some Rights Reserved: aaron . ciuffo 2 gmail.com

Version 3.0 12 November 2014
  * rewrite from scratch
  * removed kerf all together

Version 3.1 13 November 2014
  * reworked layout2D to handled a greater variety of part sizes

Version 3.2 13 November 2014
  * verified that removing kerf handling was a good idea
  * fixed small issue with layout2D
  * cookies?

Version 3.3 15 November 2014
  * fixed a few typos - Thanks Mixomycetes for pointing those out

*/

/*[Box Outside Dimensions]*/
//Box Width - X
bX=75;
//Box Depth - Y
bY=120;
//Box Height - Z
bZ=55;
//Material Thickness
thick=3;

/*[Box Features]*/
//Include a lid?
addLid=1; //[1:Lid, 0:No Lid]
//Finger Hole Diameter - 0==no hole
holeDia=20; //[0:50]
holeFacets=36;//[3:36]

/*[Finger Width]*/
//Finger width (NB! width must be < 1/3 shortest side)
fingerW=5;//[3:20]
//Lid finger width
fingerLidW=15;//[3:20]
//Laser kerf
kerf=0.1;

/*[Layout]*/
//separation of finished pieces
separation=1;
//transparency of 3D model
alpha=50; //[1:100]
2D=0; //[1:2D for DXF, 0:3D for STL]

/*[Hidden]*/
//transparency alpha
alp=1-alpha/100;

//cuts that fall complete inside the edge
module insideCuts(length, fWidth, cutD, uDiv) {
  //Calculate the number of fingers and cuts
  numFinger=floor(uDiv/2);
  numCuts=ceil(uDiv/2);

  //draw out rectangles for slots
  for (i=[0:numCuts-1]) {
    translate([i*(fWidth*2), 0, 0])
      square([fWidth, cutD]);
  }
}

//cuts that fall at the end of an edge requirng an extra long cut
module outsideCuts(length, fWidth, cutD, uDiv) {
  numFinger=ceil(uDiv/2);
  numCuts=floor(uDiv/2);
  //calculate the length of the extra long cut
  endCut=(length-uDiv*fWidth)/2;
  //amount of padding to add to the itterative placement of cuts
  // this is the extra long cut at the beginning and end of the edge
  padding=endCut+fWidth;

  square([endCut, cutD]);

  for (i=[0:numCuts]) {
    if (i < numCuts) {
      translate([i*(fWidth*2)+padding, 0, 0])
        square([fWidth, cutD]);
    } else {
      translate([i*(fWidth*2)+padding, 0, 0])
        square([endCut, cutD]);
    }
  }

}

//Face A (X and Z dimensions)
//Front and back face
module faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {
  difference() {
    square([bX, bZ], center=true);

    //X+/- edge (X axis in OpenSCAD)
    //if true, make cuts for the lid, otherwise leave a blank edge
    if (addLid) {
      translate([-uDivLX*fingerLidW/2, bZ/2-thick, 0])
        insideCuts(len=bX, fWidth=fingerLidW, cutD=thick, uDiv=uDivLX);
    }
    translate([-uDivX*fingerW/2, -bZ/2, 0])
      insideCuts(length=bX, fWidth=fingerW, cutD=thick, uDiv=uDivX);

    //Z+/- edge (Y axis in OpenSCAD)
    translate([bX/2-thick, uDivZ*fingerW/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);
    translate([-bX/2, uDivZ*fingerW/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);

  }
}

//Face B (X and Y dimensions)
//Lid and base
module faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=0) {

  //if this is the "lid" use fingerLidW dimensions instead of fingerW
  //create the local version of these variables

  uDivXloc= makeLid==1 ? uDivLX : uDivX;
  uDivYloc= makeLid==1 ? uDivLY : uDivY;
  fingerWloc= makeLid==1 ? fingerLidW : fingerW;
  lidHoleLoc= makeLid==1 ? holeDia/2 : 0;

  difference() {
    square([bX, bY], center=true);

    //X+/- edge
    translate([-bX/2, bY/2-thick, 0])
      outsideCuts(length=bX, fWidth=fingerWloc, cutD=thick, uDiv=uDivXloc);
    translate([-bX/2, -bY/2, 0])
      outsideCuts(length=bX, fWidth=fingerWloc, cutD=thick, uDiv=uDivXloc);

    //Y+/- edge
    translate([bX/2-thick, uDivYloc*fingerWloc/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bY, fWidth=fingerWloc, cutD=thick, uDiv=uDivYloc);
    translate([-bX/2, uDivYloc*fingerWloc/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bY, fWidth=fingerWloc, cutD=thick, uDiv=uDivYloc);

    //lid hole with holeFacets sides
    circle(r=lidHoleLoc, $fn=holeFacets);
  }

}

//Face C (Z and Y dimensions)
//left and right sides
module faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {

  difference() {
    square([bY, bZ], center=true);

    //Y+/- edge (X axis in OpenSCAD)
    //make cuts for the lid or leave a straight edge
    if(addLid) {
      translate([-bY/2, bZ/2-thick, 0])
        outsideCuts(length=bY, fWidth=fingerLidW, cutD=thick, uDiv=uDivLY);
    }
    translate([-bY/2, -bZ/2, 0])
      outsideCuts(length=bY, fWidth=fingerW, cutD=thick, uDiv=uDivY);

    //Z+/- edge (Y axis in OpenSCAD)
    translate([bY/2-thick, bZ/2, 0]) rotate([0, 0, -90])
      outsideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);
    translate([-bY/2, bZ/2, 0]) rotate([0, 0, -90])
      outsideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);

  }
}

module layout2D(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {
  yDisplace= bY>bZ ? bY : bZ+separation;

  translate([])
    color("red") faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  translate([bX+separation+bY+separation, 0, 0])
    color("darkred") faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY);

  translate([bX/2+bY/2+separation, 0, 0])
    color("blue") faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  //bottom row
  translate([bX/2+bY/2+separation, -yDisplace, 0])
    color("darkblue") faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY);

  if (addLid) {
    //bottomo row
    translate([0, -bZ/2-yDisplace/2-separation, 0])
      color("lime") faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=1);
  }
  translate([bX+separation+bY+separation, -bZ/2-yDisplace/2-separation, 0])
    color("green") faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=0);
}

module layout3D(uDivX, uDivY, uDivZ, uDivLX, uDivLY, alp=0.5) {
  //amount to shift for cut depth
  D=thick/2;

  //bottom of box (B-)
  color("green", alpha=alp)
    translate([0, 0, 0])
    linear_extrude(height=thick, center=true) faceB(uDivX, uDivY, uDivZ, uDivLX,
      uDivLY, makeLid=0);

  if (addLid) {
    color("lime", alpha=alp)
      translate([0, 0, bZ-thick])
      linear_extrude(height=thick, center=true) faceB(uDivX, uDivY, uDivZ, uDivLX,
        uDivLY, makeLid=1);
  }

  color("red", alpha=alp)
    translate([0, bY/2-D, bZ/2-D]) rotate([90, 0, 0])
    linear_extrude(height=thick, center=true) faceA(uDivX, uDivY, uDivZ, uDivLX,
      uDivLY);

  color("darkred", alpha=alp)
    translate([0, -bY/2+D, bZ/2-D]) rotate([90, 0, 0])
    linear_extrude(height=thick, center=true) faceA(uDivX, uDivY, uDivZ, uDivLX,
      uDivLY);

  color("blue", alpha=alp)
    translate([bX/2-D, 0, bZ/2-D]) rotate([90, 0, 90])
    linear_extrude(height=thick, center=true) faceC(uDivX, uDivY, uDivZ, uDivLX,
      uDivLY);
  color("darkblue", alpha=alp)
    translate([-bX/2+D, 0, bZ/2-D]) rotate([90, 0, 90])
    linear_extrude(height=thick, center=true) faceC(uDivX, uDivY, uDivZ, uDivLX,
      uDivLY);

}

module main() {
  //Calculate the maximum number of fingers and cuts possible
  maxDivX=floor(bX/fingerW);
  maxDivY=floor(bY/fingerW);
  maxDivZ=floor(bZ/fingerW);

  //Calculate the max number of fingers and cuts for the lid
  maxDivLX=floor(bX/fingerLidW);
  maxDivLY=floor(bY/fingerLidW);

  //the usable divisions value must be odd for this layout
  uDivX= (maxDivX%2)==0 ? maxDivX-3 : maxDivX-2;
  uDivY= (maxDivY%2)==0 ? maxDivY-3 : maxDivY-2;
  uDivZ= (maxDivZ%2)==0 ? maxDivZ-3 : maxDivZ-2;
  uDivLX= (maxDivLX%2)==0 ? maxDivLX-3 : maxDivLX-2;
  uDivLY= (maxDivLY%2)==0 ? maxDivLY-3 : maxDivLY-2;

  if(2D) {
    layout2D(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  } else {
    layout3D(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  }
}

main();

```


[User]
Hi, I'm looking to create a parametric OpenSCAD design for a Soma cube puzzle, similar to the one I have, but with some modifications and full parameterization. I've included a .scad file I wrote to describe it - hopefully, that's helpful.

The core design should consist of 7 pieces that fit together to form a 3x3x3 cube. The individual pieces are made up of unit cubes. The units will have grooves cut into them so that they fit together. I’d like to have all parameters defined at the beginning of the files, so it's easy to tweak them.

Here are the specific things to consider:

1.  **Unit Cube Size:** I need a parameter for the base unit cube size, for example `cube_size`.
2.  **Gap Between Cubes:** Another parameter should specify the gap between the cubes. This should be applied between _all_ faces, even those which form interior faces. I'd like this to be `cube_gap`.
3.  **Groove Depth:** The depth of the rectangular grooves should be controlled via a parameter as well. Let's call this `groove_depth`.
4.  **Overall part arrangement:** Each of the seven pieces in the Soma cube should be a separate module or function, and they should be rendered as separate parts, rather than being assembled into the final cube. I'd like a parameter for the spacing between these parts, called `part_spacing`.
5.  **Groove type:** The existing model uses simple rectangular grooves, but I would like to experiment with different groove types. Please provide options for rectangular, trapezoidal, and dovetail grooves. The shape of the grooves should be parameterized and selected by a parameter, e.g. `groove_type`, which can take the values `"rectangular"`, `"trapezoidal"`, or `"dovetail"`. Also I need additional parameters specific to the groove type such as trapezoid slant angle, and dovetail slant angle.

6. **Modularity:** The individual parts and the unit cube function should be in separate files, which are easy to include into any project. Ideally, I'd have a core file, and then separate ones for the base cubes and each of the individual parts.

7.  **No library dependencies:** Please do not use any libraries for this design. I would like to avoid them for simplicity.

Essentially, I want a fully parametric Soma cube, with the option to select the style of the joining grooves, and to be able to adjust dimensions of all the elements easily.  Can you generate the necessary OpenSCAD files for me? Let me know if you have any questions.

[Assistant]
soma.scad:
```
/* soma puzzle */

// base component cubes size
size=15;

// size of gap lines between cubes
gap= 0.4;

// depth of gaps
gd = 1.5;

// space between main parts for printing
sp = 3;

module part0() { /* base cube */
	translate([gap / 2, gap / 2, gap / 2])
		cube(size - gap);
}

module part05() { /* cube with a connector on one side */
	part0();
	translate([-gap * 0.5005, gap / 2 + gd, gap / 2 + gd])
		cube([gap * 1.001, size - gap - 2 * gd, size - gap - 2 * gd]);
}

module part1() { /* basic 3 cube part as base for all parts */
	part0();
	translate([size, 0, 0])
		part05();
	translate([size, size, 0])
		rotate([0, 0, 90])
			part05();
}

	/* part r */
	part1();

	/* part y */
	translate([2 * size + sp, 2 * size + sp, 0])
	rotate([0, 0, -90])
	{
		part1();
		rotate([0, 0, -90])
			part05();
	}

	/* part Z */
	translate([3 * size + 2 * sp, size, 0])
	rotate([0, 0, -90])
	{
		part1();
		translate([size, 0, 0])
			rotate([0, 0, -90])
				part05();
	}

	/* part left */
	translate([2 * size + sp, -(3 * size +2 * sp), 0])
	rotate([0, 0, 90])
	{
		part1();
		rotate([0, -90, 0])
			translate([size, 0, -2 * size])
				part05();
	}

	/* part right */
	translate([0, -sp, 0])
	rotate([0, 0, -90])
	{
		part1();
		rotate([0, -90, 0])
			translate([size, size, -size])
				part05();
	}

	/* part Y */
	translate([2 * size + 2 * sp, -(size + sp), 0])
	rotate([0, 0, -90])
	{
		part1();
		rotate([0, -90, 0])
			translate([size, 0, -size])
				part05();
	}

	/* part L */
	translate([5 * size + 3 * sp, -(3 * size + 2 * sp), 0])
	rotate([0, 0, 90])
	{
		part1();
		translate([2 * size, 0, 0])
			part05();
	}

/* eof */

```


[User]
Hey, I'm looking to design a parametric mount for an E3D hotend on a Makibox 3D printer. I've got some measurements and design constraints I need to incorporate, and I'd like to use OpenSCAD to make it easily customizable.

Here's what I need:

**General Structure:**

*   The mount needs to be split into two halves (top and bottom) for easier assembly. I'd like to be able to control the thickness of the split.
*   The mount will have channels/slots for the Makibox's rods.
*   It will need screw holes for mounting to the printer frame.
*   It'll also need a cutout to securely hold the E3D hotend.
*   I'd like the mount to have some rounded bevels for a nicer look, and a place to optionally add a small piece of text to personalize it.

**Key Parameters (these will need to be user-configurable):**

*   **Rod Channels:**
    *   `rod_width`: The width of the rod channels.
    *   `rod_height`: The height of the rod channels.
    *   `rod_spacing`: The distance between the two rod channels.
*   **E3D Hotend:**
    *   `E3D_neck_width`: The width of the E3D hotend's neck (the part that fits into the mount).
    *   `E3D_neck_height`: The height of the E3D hotend's neck.
    *   `E3D_body_width`: The width of the main body of the E3D hotend.
*   **Mount Material:**
    *   `edge_material`: The amount of material extending beyond the rods horizontally.
    *   `top_material`:  The amount of material above the upper rods.
    *    `bottom_material`: The amount of material below the lower rods.
*   **Mount Dimensions (Calculated):**
    * `mount_width` Total width of mount
    * `mount_in_width` Width of central cross section.
    * `mount_height` Total height of mount.
*    `split_size`: The thickness of the split between the top and bottom halves.
*   **Screw Holes:**
    *   `screw_diameter`: The diameter of the screw holes.
     * `space_between_screwholes_and_rods` The distance between screw holes and rod channel.
*   **Build Plate:**
    *  `build_plate_selector` Integer value to switch between multiple build plate shapes.
    * `build_plate_manual_x`: X size for a rectangular build plate.
    * `build_plate_manual_y`: Y size for a rectangular build plate.

**Libraries:**

I'll also need to use the following libraries for the text and build plate generation

* `Write.scad` for the text
* `build_plate.scad` for the build plate (this might be custom)

**Output:**

I'd like a single STL file to be generated. I understand that Cura can be used to split this into two parts.

Can you generate the necessary OpenSCAD code based on these specs?

[Assistant]
E3D_mount_for_Makibox_fixed.scad:
```
// Mount for E3D on Makibox

e=0.0001*1; //epsilon to offset holes and ensure "Simple"
e2=2*e; // 2*episilon to add to width

//CUSTOMIZER VARIABLES

/* [Rods] */

//Channel width (mm)
rod_width = 4.2; // [3.9, 3.95, 4.0, 4.05, 4.1, 4.15, 4.2, 4.25, 4.3, 4.25, 4.4]

//Channel height (mm)
rod_height = 4.0; // [3.9, 3.95, 4.0, 4.05, 4.1, 4.15, 4.2]

//Intra-channel spacing (mm)
rod_spacing = 19.8; // [19.7, 19.75, 19.8, 19.85, 19.9, 19.95, 20.0, 20.05, 20.1, 20.15, 20.2]

//Curved or square slots
//tbc

/* [Hot-end] */

//Neck width  (mm) including tolerance
E3D_neck_width = 12.2;

//Neck height  (mm) including tolerance. Start with 5.4 for v5 and 5.8 for v6
E3D_neck_height = 5.4;

//Width of rest of lower section (mm) including tolerance
E3D_body_width = 16.2;

/* [Mount] */

//Material outside the rods (mm)
edge_material = 6;
//Material above upper rods  (mm)
top_material = 2.8;
//Material below lower rods  (mm)  Start with 3.6 for v5 and 2.2 for v6
bottom_material = 3.6;

mount_width = rod_spacing + rod_width*2 + edge_material*2;
mount_in_width= rod_spacing + rod_width*2;
mount_height= bottom_material + rod_height*2 + top_material;

//total height should be 14.4 for v5, 13.0 for v6
echo("Mount height is:",mount_height);
echo("Should be 14.4 for v5");
echo("Should be 13.0 for v6");

//Screw hole size  (mm)
screw_diameter = 3; // [1,2,3]
space_between_screwholes_and_rods = 1.5*1;

//Split into top and bottom halves to enable assembly
split_size = 0.4;

//Build Plate Type
build_plate_selector = 3*1; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//Build plate x dimension
build_plate_manual_x = 108*1; //[100:400]

//Build plate y dimension
build_plate_manual_y = 148*1; //[100:400]

//preview[view:east, tilt:top]

//CUSTOMIZER VARIABLES END

include <write/Write.scad>
include <utils/build_plate.scad>
use <Write.scad>

//
//
//

build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

difference(){

// adds material below
union(){
// main blocks make a +
 translate([edge_material,0,0])cube(size = [mount_in_width,mount_width,mount_height]);
 translate([0,edge_material,0])cube(size = [mount_width,mount_in_width,mount_height]);

//bevels x 4 round out the +
for(i = [ [edge_material,edge_material,0],
           [edge_material,edge_material+mount_in_width,0],
           [edge_material+mount_in_width,edge_material,0],
           [edge_material+mount_in_width,edge_material+mount_in_width,0] ])
    translate(i)cylinder(r=edge_material,h=mount_height,$fn=40);

}

// removes material below
union(){

//a split between the two parts
 translate([-e,-e,bottom_material+rod_height-split_size/2-e])cube(size = [mount_width+e2,mount_width+e2,split_size+e2]);

// slots for the rods
for(i = [[0-e,edge_material-e,bottom_material-e],
           [0-e,edge_material+rod_width+rod_spacing,bottom_material-e] ])
    translate(i)cube(size = [mount_width+e2,rod_width+e2,rod_height+e2]);

//rounded alternative
//rotate([0,90,0])translate([-2,2,0])cylinder(r=2,h=40,$fn=20);
//cube(size=[40,4,2]);

for(i = [[edge_material-e,0-e,bottom_material+rod_height-e],
           [edge_material+rod_width+rod_spacing-e,0-e,bottom_material+rod_height-e] ])
    translate(i)cube(size = [rod_width+e2,mount_width+e2,rod_height+e2]);
//rotate([-90,0,0])translate([2,-2,0])cylinder(r=2,h=40,$fn=20);
//cube(size=[4,40,2]);

// screwholes x4
for(i = [ [edge_material-space_between_screwholes_and_rods,edge_material-space_between_screwholes_and_rods,0-e],
           [mount_width-edge_material+space_between_screwholes_and_rods,edge_material-space_between_screwholes_and_rods,0-e],
           [edge_material-space_between_screwholes_and_rods,mount_width-edge_material+space_between_screwholes_and_rods,0-e],
           [mount_width-edge_material+space_between_screwholes_and_rods,mount_width-edge_material+space_between_screwholes_and_rods,0-e] ])
    translate(i)cylinder(r=screw_diameter/2,h=mount_height+2*e,$fn=20);

// space for the hot-end
 translate([mount_width/2, mount_width/2,0-e])cylinder(r=E3D_body_width/2,h=mount_height-E3D_neck_height+e2,$fn=20);

 translate([mount_width/2, mount_width/4,bottom_material+rod_height+(top_material+rod_height-E3D_neck_height)/2])cube([E3D_body_width+e2,mount_width/2+e2,top_material+rod_height-E3D_neck_height+e2],center=true);

 translate([mount_width/2, mount_width/2,mount_height-E3D_neck_height-e])cylinder(r=E3D_neck_width/2,h=E3D_neck_height+e2,$fn=20);
 translate([mount_width/2, mount_width/4,mount_height-E3D_neck_height/2])cube([E3D_neck_width,mount_width/2+e2,E3D_neck_height+e2],center=true);

 translate([ mount_width*1/4,mount_width/2,(bottom_material+rod_width)/2])cube([mount_width/2,E3D_body_width,bottom_material+rod_width+split_size+e2],center=true);

// cosmetic rounding of body
for(i = [ [-mount_width,mount_width/2,0-e],
			[mount_width/2,-mount_width,0-e],
			[2*mount_width,mount_width/2,0-e],
			[mount_width/2,2*mount_width,0-e] ])
    translate(i)cylinder(r=1.05*mount_width,h=mount_height+e2,$fn=160);

// MyMaki signature
translate([mount_width-9, mount_width/2,mount_height])rotate([0,0,90])write("MyMaki",h=7,t=3, font="write/BlackRose.dxf",center=true);

} // end differences

}

```


[User]
Hey, I'm looking to create a parametric ball pocket, kinda like a shot glass but with a specific shape for a ball hinge. I have some dimensions and a specific construction method in mind, but I'm not sure how to write it in OpenSCAD.

Here are the details:

*   **Base Shape:** The pocket should start with a cylindrical base. The inner diameter at the base (where the ball will sit) should be adjustable and is represented as `d`. The inner radius will therefore be `r = d/2`.
*   **Wall Thickness:**  The thickness of the wall should be adjustable, let's call that `t`.
*   **Height Extension:** The overall height of the pocket will be driven by a multiplier, `f`, of the base radius (`r`).  The height difference is `dh = r * f`.
*   **Opening Angle:** The top opening of the pocket should flare out at an angle, `alpha`, relative to vertical. The radius increase at the top due to the flare will be `dr = dh * sin(alpha)`.
*   **Construction:**  I'm looking to create the shape by using a hull of spheres. The base would be a sphere of radius r+t which is translated upward so the bottom of the sphere is at r+t-(r+t)*(1-1/sqrt(2)), and then at height r+t+dh, there would be a sphere of radius r+dr+t, which results in the desired outer shape. Similarly, a sphere at radius r is translated up so the bottom is at r+t and then another at height r+t+dh has radius r+dr. The inner shape is created as a hull of these two spheres. The outer shape should be the result of subtracting this hull of spheres from the hull of the outer two spheres.
*   **Cut Feature:** I'd like an optional cut feature. A `cut` parameter should have options to cut or not cut. If it's set to 'yes', then the model should be cut in half by a cube that spans the full depth of the model.
*   **Resolution:** I’d like to control the resolution via `$fa` (maximum angle per segment) and `$fs` (minimal segment length).
*   **Parameters:** The parameters to control should be: `d` (base diameter), `t` (wall thickness), `f` (height multiplier), `alpha` (opening angle), and `cut` (yes/no).

I'm thinking something like what I have here, but I'd appreciate a more polished and robust solution:

```
// title: parametric ballpocket
// license: public domain

/* [parameters] */

// inner base radius diameter
d = 16.5;
r = d/2;

// wall thickness
t = 1.6;

//additional hight in units of base radius
f = 1;
dh = r*f;

// opening angle
alpha = 20;
dr = dh * sin(alpha);

cut = "no"; // [no,yes]

/* [resolution] */

// maximal angle per segment (3 good & slow)
$fa = 12;
// minimal segment length (0.15 good slow)
$fs = 0.6;

eps = 0.05*1;

intersection()
{
difference()
{
  // outer cylinder
  //translate([0,0,0])
  //cylinder(r1=r+t,r2=r+t+dr,h=r+t+dh,center=false);

  hull()
  {
    translate([0,0,r+t-(r+t)*(1-1/sqrt(2))])
    sphere(r+t);
    translate([0,0,r+t+dh])
    sphere(r+dr+t);
  }

  hull()
  {
    translate([0,0,r+t])
    sphere(r);
    translate([0,0,r+t+dh])
    sphere(r+dr);
  }
  //translate([0,0,r+t])
  //cylinder(r1=r,r2=r+dr,h=r+t+dh+eps,center=false);

  if(cut == "yes")
  {  translate([0,0,-1]) cube([100,100,100]); }
}
  translate([0,0,(r+t+dh)/2])
  cube([100,100,r+t+dh],center=true);

}
```

I don't need any external libraries. Can you create the OpenSCAD file based on this? Thanks!

[Assistant]
ballpocket.scad:
```

// title: parametric ballpocket
// license: public domain

/* [parameters] */

// inner base radius diameter
d = 16.5;
r = d/2;

// wall thickness
t = 1.6;

//additional hight in units of base radius
f = 1;
dh = r*f;

// opening angle
alpha = 20;
dr = dh * sin(alpha);

cut = "no"; // [no,yes]

/* [resolution] */

// maximal angle per segment (3 good & slow)
$fa = 12;
// minimal segment length (0.15 good slow)
$fs = 0.6;

eps = 0.05*1;

intersection()
{
difference()
{
  // outer cylinder
  //translate([0,0,0])
  //cylinder(r1=r+t,r2=r+t+dr,h=r+t+dh,center=false);

  hull()
  {
    translate([0,0,r+t-(r+t)*(1-1/sqrt(2))])
    sphere(r+t);
    translate([0,0,r+t+dh])
    sphere(r+dr+t);
  }

  hull()
  {
    translate([0,0,r+t])
    sphere(r);
    translate([0,0,r+t+dh])
    sphere(r+dr);
  }
  //translate([0,0,r+t])
  //cylinder(r1=r,r2=r+dr,h=r+t+dh+eps,center=false);

  if(cut == "yes")
  {  translate([0,0,-1]) cube([100,100,100]); }
}
  translate([0,0,(r+t+dh)/2])
  cube([100,100,r+t+dh],center=true);

}
```


[User]
Hey, I'm looking to generate some speaker enclosures for 3D printing. I've got some experience with OpenSCAD, but I'd like some help designing a parametric script.

Essentially, I want to be able to customize a box, specifying its internal volume, wall thickness, and aspect ratio. I’d like to be able to toggle between manually setting the box volume or having it automatically calculated based on the Thiele/Small parameters of my driver (Qts, Fs, and Vas). It also needs to include cutouts for the speaker and terminals, with options for screw holes around those cutouts. I'd like a bass port to be an optional feature, with control over its dimensions and location (front or back).

For the speaker cutouts, I need to define the main speaker hole diameter, the diameter of the screw holes, the screw hole spacing, and the number of screw holes. For the terminals, I'd like options for simple dual or single wire holes, or a cutout for a terminal block, including the same screw hole parameters as the speaker cutout.

The bass port should be configurable, with the ability to set the internal diameter, length, wall thickness, and x and y offsets of the port.

I also need the script to display specs of the enclosure, including the F3 frequency, Qtc, volume, internal dimensions, and external dimensions. It'd be great if that was also a toggleable feature so that it wouldn’t interfere with the actual 3D model.

I'll need to use the `write/Write.scad` library for the text display. Also, I think I need to use some math functions in OpenSCAD - so I will be using the standard library that's included by default. I'd like all the dimensions to be in millimeters.

Could you help me put together some OpenSCAD code for this? Thanks!

[Assistant]
speakergen.scad:
```
//http://www.bcae1.com/spboxad2.htm
//http://www.mh-audio.nl/ReflexBoxCalculator.asp
//http://tara.mmto.org/speakers/theory/Closed-Box-Loudspeaker-Systems-Part-I-Analysis.pdf

//Test case
//http://www.madisound.com/store/manuals/aurasound/ns3-193-4a.pdf
//These are nice inexpensive drivers - very good bass - but drop off a little on the high end (benefit from turning up the treble)
//1.7 liter box
//tuned to 70hz / 66hz f3

//This script is intended to help design small single driver speakers (using full range drivers).

//Advantages of single-driver designs:
//No cross-over network / no cancellation between drivers
//Inexpensive full-range drivers are available that produce surprisingly good bass and high-end response

//Advantages of 3d printing your speaker box
//No issues with adhesives
//Box can be printed with bass port

//https://www.parts-express.com/

//design notes
//test case for very small (0.5 liter) enclosure produced reasonable results with 7mm wall thickness / 2 shells and 10% infill at 300 micron.  Cabinet walls definitely resonated - but sound quality didn't seem to suffer noticeably.  Higher infill is probably good idea for all but smallest cabinets.

//Stuff I've read on speaker design:
//avoid two or more identical dimensions - as this can lend to reflections.  Some people say "golden ratio" of .62 : 1 : 1.62 is optimal
//stuffing box with poly-fil (fabric store) can effectively increase box volume by around 20%
//If using a bass port - it's diameter should be at least 1/3rd of your driver's diamter (I've violated this a bit without apparent issue)

//calculators to help determine box / port size and performance
//http://www.mh-audio.nl/ReflexBoxCalculator.asp
//http://www.mh-audio.nl/ClosedBoxCalculator.asp

use<write/Write.scad>;

// preview[view:south, tilt:top diagonal]

/* [General] */
//Display box specs (disable before export)
showSpecs = "yes"; //[yes,no]
//Box size in -liters- (closed box calc overrides)
manualBoxVolume = 1.68;
//thickness of box walls in mm (independant of volume)
boxThickness = 7;
boxHeightRatio = 1.1;
boxWidthRatio = .9;
boxDepthRatio = 1.7;

/* [Speaker Hole] */
//make a few mm larger than actually needed to assure fit
speakerHoleDiameter = 80;
//diagonally opposing holes this distance apart (mm)
speakerScrewHoleSpacing = 94;
numberOfSpeakerScrewHoles = 4;
//3.25mm seems good for #6 wood screw (screw in slowly / don't overtighten to avoid cracking) - chase with drill bit if needed
speakerScrewHoleDiameter = 3.25;

/* [Closed Box Calc] */
//Automatically calculate box size for desired Q (needs driver parameters)
enableClosedBoxCalc = "no"; //[yes,no]
//Qtc for box - (must be larger than Driver Qts)
boxQ = 0.9;
//Qts for driver
driverQts = 0.68;
//Resonance frequency for driver
driverFS = 73;
//Vas in liters (*28.3 to convert from cubic feet)
driverVas = 1.132;

/* [Bass Port] */
//Manual config only (Closed box calc must be off!)
makePort = "no"; //[yes,no]
portLocation = "back"; //[front,back]
//Use a tool like www.mh-audio.nl/ReflexBoxCalculator.asp to calculate (mm)
portInternalDiameter = 20;
//Use a tool like www.mh-audio.nl/ReflexBoxCalculator.asp to calculate (mm)
portLength = 100;
portWallThickness = 5;
portXOffset = 0;
//May need to manually added supports for values besides 0
portYOffset = 0;

/* [Terminal] */
terminalType = "dual wire holes"; //[dual wire holes, single wire hole, terminal cutout, none]
//about 2.2mm for 22 gauge solid core wire (use silicone seal / chase with drill bit if needed)
wireDiameter = 2.2;
//make a bit larger than needed to assure fit (mm)
terminalHoleDiameter = 40;
//diagonally opposing holes this distance apart (mm)
terminalScrewHoleSpacing = 50;
numberOfTerminalScrewHoles = 4;
//3.25 seems good for #6 wood screw (screw in slowly / don't overtighten to avoid cracking) - chase with drill bit if needed
terminalScrewHoleDiameter = 3.25;

/* [Hidden] */

alpha = pow((boxQ / driverQts), 2) - 1;
desiredBoxVolume = (enableClosedBoxCalc == "yes") ? driverVas / alpha : manualBoxVolume;
fc = sqrt(alpha+1)*driverFS;

a1 = (1/boxQ/boxQ)-2;
f3 = fc*sqrt(a1/2+sqrt(a1*a1/4+1));

boxRatioFactor = (pow(boxHeightRatio * boxWidthRatio * boxDepthRatio, 1/3));
boxIntHeight = (pow(desiredBoxVolume * 1000000, 1/3)) * (boxHeightRatio / boxRatioFactor);
boxIntWidth =  (pow(desiredBoxVolume * 1000000, 1/3)) * (boxWidthRatio / boxRatioFactor);
boxIntDepth = (pow(desiredBoxVolume * 1000000, 1/3)) * (boxDepthRatio / boxRatioFactor);

f3String = str("F3:",round(f3),"hz");
qString = str("Qtc:",round(boxQ * 100) / 100);
volString = str("Vol:", round((boxIntWidth * boxIntHeight * boxIntDepth) / 10000) / 100, "L");
intDimString = str("Int dim:", round(boxIntWidth), "x", round(boxIntHeight), "x", round(boxIntDepth),"mm");
extDimString = str("Ext dim:", round(boxIntWidth + boxThickness * 2), "x",
	  round(boxIntHeight + boxThickness * 2), "x", round(boxIntDepth + boxThickness * 2),"mm");

makeBox();
if (showSpecs == "yes") renderSpecs();

module makeBox()
{
	difference()
	{
		boxExterior();
		boxInterior();

		circleCutOut(90, speakerHoleDiameter);
		screwCutOuts(90, speakerScrewHoleSpacing, numberOfSpeakerScrewHoles, speakerScrewHoleDiameter);

		makeTerminal();

		if (makePort == "yes" && enableClosedBoxCalc != "yes") {
			if (portLocation == "back") portHole();
			if (portLocation == "front") rotate ([0,0,180]) portHole();
		}
	}

	if (makePort == "yes" && enableClosedBoxCalc != "yes") {
		if (portLocation == "back") port();
		if (portLocation == "front") rotate ([0,0,180]) port();
	}
}

module renderSpecs() {
	rotate([90,0,0]) {
	if (enableClosedBoxCalc == "yes") {
	translate ([(boxIntWidth + boxThickness) / 1.25,50,boxIntDepth / 2]) write(f3String ,h=14,t=1);
	translate ([(boxIntWidth + boxThickness) / 1.25,25,boxIntDepth / 2]) write(qString ,h=14,t=1);
	translate ([(boxIntWidth + boxThickness) / 1.25,0,boxIntDepth / 2])  write(volString ,h=14,t=1);}

	translate ([(boxIntWidth + boxThickness) / 1.25,-25,boxIntDepth / 2]) write(intDimString ,h=14,t=1);
	translate ([(boxIntWidth + boxThickness) / 1.25,-50,boxIntDepth / 2]) write(extDimString ,h=14,t=1);}
}

module boxExterior()
{
		cube([boxIntWidth + boxThickness * 2,
		boxIntDepth + boxThickness * 2,
		boxIntHeight + boxThickness * 2], center = true);
}

module boxInterior()
{
	cube([boxIntWidth,
		boxIntDepth,
		boxIntHeight], center = true);
}

module circleCutOut(rotation, holeDiameter)
{
	rotate ([rotation,0,0]) translate([0, 0, (boxIntDepth  / 2) - 1])
	{
		cylinder(r = holeDiameter / 2, h = boxThickness * 2);
	}
}

module screwCutOuts(rotation, distance, numberOfHoles, holeDiameter)
{
	rotate ([rotation,0,0]) translate([0, 0, (boxIntDepth  / 2) - 1])
	{
		for (i = [0 : 360 / numberOfHoles : 360])
		{
			rotate([0,0,i + 45])
				translate([0, distance / 2, 0])
					cylinder(r = holeDiameter / 2, h = boxThickness * 2);
		}
	}
}

module makeTerminal()
{
	if (terminalType == "single wire hole") {
		rotate ([270,0,0]) translate([0, 0, (boxIntDepth  / 2) - 1])
			cylinder(r = wireDiameter / 2, h = boxThickness * 2);
	}

	if (terminalType == "dual wire holes") {
		rotate ([270,0,0]) translate([0, 0, (boxIntDepth  / 2) - 1]) {
			translate ([wireDiameter * -2,0,0])
				cylinder(r = wireDiameter / 2, h = boxThickness * 2);
			translate ([wireDiameter * 2,0,0])
				cylinder(r = wireDiameter / 2, h = boxThickness * 2);
		}
	}

	if (terminalType == "terminal cutout") {
		circleCutOut(270, terminalHoleDiameter);
		screwCutOuts(270, terminalScrewHoleSpacing, numberOfTerminalScrewHoles, terminalScrewHoleDiameter);
	}

}

module port()
{
	difference()
	{
		rotate([90,0,0])
		translate([(boxIntWidth / -2) - portInternalDiameter / -2,
			(boxIntHeight / -2) - portInternalDiameter / -2 ,
			(boxIntDepth / -2) - boxThickness])
		translate([portXOffset,portYOffset,0])
		cylinder(r = (portInternalDiameter + portWallThickness) / 2,
			 h = portLength);
		portHole();
	}

}

module portHole()
{
	rotate([90,0,0])
		translate([(boxIntWidth / -2) - portInternalDiameter / -2,
			(boxIntHeight / -2) - portInternalDiameter / -2 ,
			(boxIntDepth / -2) - boxThickness])
	translate([portXOffset,portYOffset,-0.5])
	cylinder(r = (portInternalDiameter) / 2,
		 h = portLength + 1);
}

```


[User]
I'd like to design a cloud-shaped key hanger with multiple hooks. The cloud shape should be created from several overlapping cylinders and a central cuboid, all scaled to make it more cloud-like. The base cloud should have two small holes going through it for mounting. The hooks should be minkowski sums, with a small cylinder at the joining point and a rectangular prism at the end. I need to be able to control the height of the cloud, the number of hooks, the spacing of the hooks, and the length of the hooks independently.

Could you please generate the OpenSCAD file for this? It would also be great if you could make the number of hooks a variable, and their position can be offset along the Y axis. Also the overall X position of the hooks should be scaled with their number. The hooks should be made up of a cube and a cylinder joined by a minkowski sum. The cloud should have mounting holes near the top. I'd also like to be able to change the size of the rectangular prism of the hook.

[Assistant]
icloud.scad:
```
/*[Variables]*/
height_cloud = 5; // [1:20]

quantity_hook =5; // [1:5]

//offset hook in axis Y
position_hook_offset_y = 4; //

//distance hooks between self
distance_hook = 15; // [5:18]

//length hooks
cube_z = 15; // [9:30]

/*[hidden]*/
size = [0.2 * quantity_hook, 0.2 * quantity_hook, 1];
circle1 = 77.981/2;
circle2 = 57.986/2;
circle3 = 104.974/2;
circle4 = 73.982/2;
cube5_x = 123.917/2;
cube5_y =  42.798/2;
position_hook_y = -position_hook_offset_y * quantity_hook;

cube_xy = 5;

x1 = distance_hook * quantity_hook;

hook1 = [[0,-5,0]];
hook2 = [[-x1,position_hook_y,0], [x1, position_hook_y, 0]];
hook3 = [[-x1,position_hook_y,0], [0, position_hook_y, 0], [x1, position_hook_y, 0]];
hook4 = [[-x1,position_hook_y,0], [-x1/3, position_hook_y, 0], [x1/3, position_hook_y, 0], [x1, position_hook_y, 0]];
hook5 = [[-x1,position_hook_y,0], [-x1/2, position_hook_y, 0], [0, position_hook_y, 0], [x1/2, position_hook_y, 0], [x1, position_hook_y, 0]];

hook = quantity_hook == 1 ? hook1 : quantity_hook == 2 ? hook2 : quantity_hook == 3 ? hook3 : quantity_hook == 4 ? hook4 : quantity_hook == 5 ? hook5 : hook1;
hole1 = [[0, 10, 0]];
hole2 = [[-x1/1.5, 10, height_cloud/2], [x1/1.5, 10, height_cloud/2]];
holes = quantity_hook < 3 ? hole1 : hole2;
difference(){
	scale(v=size){
		union(){
			translate ([-61.001, -11.417, 0]) {
				cylinder(h = height_cloud, r = circle1, center = true, $fn = 100);
			}
			translate ([-46.769, 22.975, 0]) {
				cylinder(h = height_cloud, r = circle2, center = true, $fn = 100);
			}
			translate ([14.831, 25.274, 0]) {
				cylinder(h = height_cloud, r = circle3, center = true, $fn = 100);
			}
			translate ([63.084, -13.512, 0]) {
				cylinder(h = height_cloud, r = circle4, center = true, $fn = 100);
			}
			translate ([-0.162, -29, 0]) {
				cube(size = [123.917, 42.798, height_cloud], center = true);
			}
		}
	}
	for (a = holes){
		union(){
			translate(a){
				 cylinder(h=height_cloud + 20, r=2, $fn=50, center=true);
			}
			translate(a){
				 cylinder(h=height_cloud/2, r1=2, r2 = 6, $fn=50, center=true);
			}
		}
	}
}
$fn = 20;
for(x = hook){
	translate(x){
		minkowski(){
			union(){
				translate ([0,0, (cube_z/2)+(height_cloud/2)]){
					cube(size = [cube_xy, cube_xy, cube_z], center = true);
				}
				difference(){
					translate ([0, 5, (((height_cloud/2)+cube_z)-3.75)]){
						cube(size = [cube_xy, cube_xy, 7.5], center = true);
					}
					translate([0, 6, (((height_cloud/2)+cube_z)-5.75)]){
						rotate([30, 0, 0]){
							#cube(size = [cube_xy+2, 10, 5], center=true);
						}
					}
				}
			}
			rotate([0, 90, 0]){
				cylinder(r = 2, h = 2);
			}
		}
	}
}

```


[User]
I need an OpenSCAD design for a wedge-shaped shim to stabilize a wobbly toilet. The shim should have adjustable length, width, and the angle of the wedge. I want to be able to tweak these to get a perfect fit under the toilet base.

Specifically, the shim should start at a height of zero and slope upwards along its length. The length, width, and angle of the slope need to be parameters I can easily adjust. I guess I can also specify a single height value, which would then only need to be multiplied by some small number in the actual model since I only need it for the final height, not the initial.

Please generate an OpenSCAD file that uses the hull function to create the solid wedge shape. This also needs to be parametric, and I'd like to include a comment on each variable for ease of understanding.

[Assistant]
Shim.scad:
```
Length = 30; // [1:50]

Width = 10; // [1:50]

// ignore this variable!
Height = 0.1 * 1;

// Steepness?
Angle = 15; // [1:20]

module shim() {
hull() {
	translate([0, 0, 0])
	rotate([0, -Angle, 0])
	cube([Length, Width, Height]);
	cube([Length, Width, Height]);
	}
}

shim();
```


[User] I need a parametric design for a washer and optional spacer, similar to the one I've been using, but I'd like to use the BOSL2 library for some extra functionality, and maybe some more refined control over the parameters. I'd like to be able to control the inner diameter, washer thickness, washer outer diameter, spacer thickness, and spacer diameter. The spacer should sit concentrically on top of the washer, and it should be a separate part that can easily be removed (i.e. I don't want it unioned with the washer by default). It's important that the washer thickness be independent of the spacer thickness. When I set the spacer thickness to zero, I should just get a washer, with no spacer portion. The inner and spacer diameters should both always be larger than 0. It would also be nice if I could easily export either the washer, the spacer, or both. I'm also not totally confident with how `translate()` works - is there a more intuitive method for stacking the washer and spacer (maybe using BOSL2's `up()` or `stack()` operations)? Finally, I'd appreciate if the design could incorporate some BOSL2 features like `linear_extrude` for the washer and `rotate_extrude` for the spacer, but only if that can be done without sacrificing flexibility.

[Assistant]
Washer_and_Spacer.scad:
```
$fs = 0.1*1;
$fa=1*1;

// Add extra room to use easily (about 0.5mm)
inner_diameter = 4; // [0.5:30.1]

washer_thickness = 2; // [0.1:30.1]

// Outer Diameter of Washer, should be greater than inner diameter
washer_diameter = 18; // [0.1:30.1]

// Set to Zero for No Spacer
spacer_thickness = 2; // [0.1:30.1]

// Set this less than washer diameter, but greater than inner diameter
spacer_diameter = 8; // [0.1:30.1]

module washer() {
difference() {
	cylinder(washer_thickness, d=washer_diameter, center=true);
	cylinder(washer_thickness+1, d=inner_diameter, center=true);
	}
}

module washer_spacer() {
difference() {
	cylinder(spacer_thickness, d=spacer_diameter, center=true);
	cylinder(spacer_thickness+1, d=inner_diameter, center=true);
	}
}

module washer_and_spacer() {
translate([0, 0, washer_thickness+(washer_thickness/2)]) washer_spacer();
translate([0, 0, washer_thickness/2]) washer();
}

washer_and_spacer();
```


[User]
Hey, I'm looking to create a customizable peristaltic pump for 3D printing. I've seen some designs out there, but they're not quite what I need. I'd like a design that's based on a planetary gear system, similar to a planetary gear bearing, with the planet gears acting as rollers to compress the tubing.

Here's what I'm imagining and the parameters I'd like to control:

**Overall Structure:**

*   The pump should have an outer ring, a sun gear, and a set of planet gears.
*   The planet gears should be positioned to squeeze a flexible tube against the outer ring.
*   Everything needs to print as one piece, with the planet gears already assembled and captive. I'm aiming for no rotary wear surfaces, except the tubing itself of course.
*   The design should be customizable, so I can easily change the size and tubing dimensions.
*   I want the sun gear to be able to be driven with a standard nut driver bit, like a 6.7mm hex.
*   I would prefer a herringbone gear design to maximize the contact surface, but a simple spur gear design would be acceptable if necessary.

**Customizable Parameters (in mm unless otherwise specified):**

*   `tol`: Clearance between non-connected parts (default 0.15). This should adjust how tightly the parts fit together.
*  `allowed_overhang`: Allowed overhang for overhang removal, should be a number between 0 and 0.999 (0 = none, 0.5 = 45 degrees, 1 = infinite). Default should be 0.75.
*   `tubing_od`: Outer diameter of the tubing (e.g., 4.7625).
*   `tubing_wall_thickness`: Wall thickness of the tubing (e.g., 0.79375).
*   `tubing_squish_ratio`: Proportion of the tubing thickness to compress (0 = no squish, 1.0 = full squish, default should be 0.5)
*   `D`: Approximate outer diameter of the ring (e.g., 51.7).
*   `T`: Thickness/height of the pump (e.g., 15).
*   `number_of_planets`: Number of planet gears (e.g., 3).
*   `number_of_teeth_on_planets`: Number of teeth on each planet gear (e.g., 7).
*   `approximate_number_of_teeth_on_sun`: Approximate number of teeth on the sun gear (e.g., 9). The number of teeth on the sun gear should be adjusted to work with the other parameters, so the gears work smoothly.
*   `P`: Pressure angle for the gears (e.g. 45, in degrees).
*   `nTwist`: Number of teeth to twist across for herringbone gears (e.g. 1). This value should also be used to angle the extruded overhang cut for planets.
*   `w`: Width of the hexagonal hole in the sun gear (e.g., 6.7).
*   `DR`: Maximum depth ratio of the gear teeth (e.g. 0.5).

**Additional Considerations:**

*   I need the design to work with a 3/16 inch (4.7625mm) OD latex surgical tubing by default, but it needs to be customizable for other tubing sizes.
*   I'd like the OpenSCAD code to handle the math for gear ratios and tooth counts automatically to avoid any manual calculations.
*   The code should be well-commented so I can easily understand what's going on.
*   The code needs to take overhang into account, and be designed to be printable without supports. Overhangs should be removed by applying a chamfer during the extrusion as needed.
* I need a cutaway for tubing to exit the pump. I think two holes would be ideal, one for entering and one for exiting.

Could you generate an OpenSCAD file or set of files for this design? I think it would be easiest if you included all of the modules within a single file to make it easier to share. I don't need any included libraries, but please let me know which libraries you used to make sure I have them on hand, if any. Thanks!

[Assistant]
peristaltic.scad:
```
// Planetary peristaltic pump (customizable)
// by Drmn4ea (drmn4ea at google's mail)
//
// Released under the Creative Commons - Attribution - Share Alike license (http://creativecommons.org/licenses/by-sa/3.0/)
//
// Adapted from Emmett Lalish's Planetary Gear Bearing at http://www.thingiverse.com/thing:53451

// --------  Printer-related settings ------------

// Clearance to generate between non-connected parts. If the gears print 'stuck together' or are difficult to separate, try increasing this value. If there is excessive play between them, try lowering it. (default: 0.15mm)
tol=0.15;

// Allowed overhang for overhang removal; between 0 and 0.999 (0 = none, 0.5 = 45 degrees, 1 = infinite)
allowed_overhang = 0.75;

// --------  Details of the tubing used in the pump, in mm ------------

// Outer diameter of your tubing in mm
tubing_od = 4.7625;

// Wall thickness of your tubing
tubing_wall_thickness = 0.79375;
// Amount the tubing should be compressed by the rollers, as a proportion of total thickness (0 = no squish, 1.0 = complete squish)
tubing_squish_ratio = 0.5;

// --------  Part geometry settings ------------

// Approximate outer diameter of ring in mm
D=51.7;

// Thickness i.e. height in mm
T=15;

// Number of planet gears
number_of_planets=3;

// Number of teeth on planet gears
number_of_teeth_on_planets=7;

// Number of teeth on sun gear (approximate)
approximate_number_of_teeth_on_sun=9;

// pressure angle
P=45;//[30:60]

// number of teeth to twist across
nTwist=1;

// width of hexagonal hole
w=6.7;

DR=0.5*1;// maximum depth ratio of teeth

// ----------------End of customizable values -----------------

m=round(number_of_planets);
np=round(number_of_teeth_on_planets);
ns1=approximate_number_of_teeth_on_sun;
k1=round(2/m*(ns1+np));
k= k1*m%2!=0 ? k1+1 : k1;
ns=k*m/2-np;
echo(ns);
nr=ns+2*np;
pitchD=0.9*D/(1+min(PI/(2*nr*tan(P)),PI*DR/nr));
pitch=pitchD*PI/nr;
echo(pitch);
helix_angle=atan(2*nTwist*pitch/T);
echo(helix_angle);

phi=$t*360/m;

// compute some parameters related to the tubing
tubing_squished_width = tubing_od * (PI/2);
tubing_depth_clearance = 2*(tubing_wall_thickness*(1-tubing_squish_ratio));

// temporary variables for computing the outer radius of the outer ring gear teeth
// used to make the clearance for the peristaltic squeezer feature on the planets
outerring_pitch_radius = nr*pitch/(2*PI);
outerring_depth=pitch/(2*tan(P));
outerring_outer_radius = tol<0 ? outerring_pitch_radius+outerring_depth/2-tol : outerring_pitch_radius+outerring_depth/2;

// temporary variables for computing the outer radius of the planet gear teeth
// used to make the peristaltic squeezer feature on the planets
planet_pitch_radius = np*pitch/(2*PI);
planet_depth=pitch/(2*tan(P));
planet_outer_radius = tol<0 ? planet_pitch_radius+planet_depth/2-tol : planet_pitch_radius+planet_depth/2;

// temporary variables for computing the inside & outside radius of the sun gear teeth
// used to make clearance for planet squeezers
sun_pitch_radius = ns*pitch/(2*PI);
sun_base_radius = sun_pitch_radius*cos(P);
echo(sun_base_radius);
sun_depth=pitch/(2*tan(P));
sun_outer_radius = tol<0 ? sun_pitch_radius+sun_depth/2-tol : sun_pitch_radius+sun_depth/2;
sun_root_radius1 = sun_pitch_radius-sun_depth/2-tol/2;
sun_root_radius = (tol<0 && sun_root_radius1<sun_base_radius) ? sun_base_radius : sun_root_radius1;
sun_min_radius = max (sun_base_radius,sun_root_radius);

// debug raw gear shape for generating overhang removal
//translate([0,0,5])
//{
//	//halftooth (pitch_angle=5,base_radius=1, min_radius=0.1,	outer_radius=5,	half_thick_angle=3);
//	gear2D(number_of_teeth=number_of_teeth_on_planets, circular_pitch=pitch, pressure_angle=P, depth_ratio=DR, clearance=tol);
//}

translate([0,0,T/2])
{
	// outer ring
	difference()
	{
		// HACK: Add tubing depth clearance value to the total OD, otherwise the outer part may be too thin. FIXME: This is a quick n dirty way and makes the actual OD not match what the user entered...
		cylinder(r=D/2 + tubing_depth_clearance,h=T,center=true,$fn=100);
		exitholes(outerring_outer_radius-tubing_od/4,tubing_od, len=100);
		union()
		{
			// HACK: On my printer, it seems to need extra clearance for the outside gear, trying double...
			herringbone(nr,pitch,P,DR,-2*tol,helix_angle,T+0.2);
			cylinder(r=outerring_outer_radius+tubing_depth_clearance,h=tubing_squished_width,center=true,$fn=100);
			// overhang removal for top teeth of outer ring: create a frustum starting at the top surface of the "roller" cylinder
			// (which will actually be cut out of the outer ring) and shrinking inward at the allowed overhang angle until it reaches the
			// gear root diameter.
			translate([0, 0, tubing_squished_width/2])
			{
				cylinder(r1=outerring_outer_radius+tubing_depth_clearance, r2=outerring_depth,h=abs(outerring_outer_radius+tubing_depth_clearance - outerring_depth)/tan(allowed_overhang*90),center=false,$fn=100);
			}
		}
	}

	// sun gear
	rotate([0,0,(np+1)*180/ns+phi*(ns+np)*2/ns])

	difference()
	{

		// the gear with band cut out of the middle
		difference()
		{
			mirror([0,1,0])
				herringbone(ns,pitch,P,DR,tol,helix_angle,T);
				// center hole
				cylinder(r=w/sqrt(3),h=T+1,center=true,$fn=6);
				// gap for planet squeezer surface
				difference()
				{
					cylinder(r=sun_outer_radius,h=tubing_squished_width,center=true,$fn=100);
					cylinder(r=sun_min_radius-tol,h=tubing_squished_width,center=true,$fn=100);
				}
		}

		// on the top part, cut an angle on the underside of the gear teeth to keep the overhang to a feasible amount
		translate([0, 0, tubing_squished_width/2])
		{
			difference()
			{
				// in height, numeric constant sets the amount of allowed overhang after trim.
				//h=abs((sun_min_radius-tol)-sun_outer_radius)*(1-allowed_overhang)
				// h=tan(allowed_overhang*90)
				cylinder(r=sun_outer_radius,h=abs((sun_min_radius-tol)-sun_outer_radius)/tan(allowed_overhang*90),center=false,$fn=100);
				cylinder(r1=sun_min_radius-tol, r2=sun_outer_radius,h=abs((sun_min_radius-tol)-sun_outer_radius)/tan(allowed_overhang*90),center=false,$fn=100);
			}
		}

	}

	// planet gears

	for(i=[1:m])
	{

		rotate([0,0,i*360/m+phi])
		{

			translate([pitchD/2*(ns+np)/nr,0,0])
			{
				rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi])
				{
					union()
					{
						herringbone(np,pitch,P,DR,tol,helix_angle,T);
						// Add a roller cylinder in the center of the planet gears.
						// But also constrain overhangs to a sane level, so this is kind of a mess...
						intersection()
						{
							// the cylinder itself
							cylinder(r=planet_outer_radius,h=tubing_squished_width-tol,center=true,$fn=100);

							// Now deal with overhang on the underside of the planets' roller cylinders.
							// create the outline of a gear where the herringbone meets the cylinder;
							// make its angle match the twist at this point.
							// Then difference this flat gear from a slightly larger cylinder, extrude it with an
							// outward-growing angle, and cut the result from the cylinder.
							planet_overhangfix(np, pitch, P, DR, tol, helix_angle, T, tubing_squished_width, allowed_overhang);

						}

					}

				}
			}
		}
	}

}

module planet_overhangfix(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5,
	tubing_squished_width,
	allowed_overhang)
{

	height_from_bottom =  (gear_thickness/2) - (tubing_squished_width/2);
	pitch_radius = number_of_teeth*circular_pitch/(2*PI);
	twist=tan(helix_angle)*height_from_bottom/pitch_radius*180/PI; // the total rotation angle at that point - should match that of the gear itself

	translate([0,0, -tubing_squished_width/2]) // relative to center height, where this is used
	{
		// FIXME: This calculation is most likely wrong...
		//rotate([0, 0, helix_angle * ((tubing_squished_width-(2*tol))/2)])
		rotate([0, 0, twist])
		{
			// want to extrude to a height proportional to the distance between the root of the gear teeth
			// and the outer edge of the cylinder
			linear_extrude(height=tubing_squished_width-clearance,twist=0,slices=6, scale=1+(1/(1-allowed_overhang)))
			{
				gear2D(number_of_teeth=number_of_teeth, circular_pitch=circular_pitch, pressure_angle=pressure_angle, depth_ratio=depth_ratio, clearance=clearance);
			}
		}
	}
}

module exitholes(distance_apart, hole_diameter)
{
	translate([distance_apart, len/2, 0])
	{
		rotate([90, 0, 0])
		{
			cylinder(r=hole_diameter/2,h=len,center=true,$fn=100);
		}
	}

	mirror([1,0,0])
	{
		translate([distance_apart, len/2, 0])
		{
			rotate([90, 0, 0])
			{
				cylinder(r=hole_diameter/2,h=len,center=true,$fn=100);
			}
		}
	}
}

module rack(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	helix_angle=0,
	clearance=0,
	gear_thickness=5,
	flat=false){
addendum=circular_pitch/(4*tan(pressure_angle));

flat_extrude(h=gear_thickness,flat=flat)translate([0,-clearance*cos(pressure_angle)/2])
	union(){
		translate([0,-0.5-addendum])square([number_of_teeth*circular_pitch,1],center=true);
		for(i=[1:number_of_teeth])
			translate([circular_pitch*(i-number_of_teeth/2-0.5),0])
			polygon(points=[[-circular_pitch/2,-addendum],[circular_pitch/2,-addendum],[0,addendum]]);
	}
}

//module monogram(h=1)
//linear_extrude(height=h,center=true)
//translate(-[3,2.5])union(){
//	difference(){
//		square([4,5]);
//		translate([1,1])square([2,3]);
//	}
//	square([6,1]);
//	translate([0,2])square([2,1]);
//}

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,10])
	gear(number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance,
		helix_angle,
		gear_thickness/2);
	mirror([0,0,1])
		gear(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness/2);
}}

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, scale=1)child(0);
	else
		child(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],
	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]
I need a fire extinguisher wall mount, designed to be 3D printed. I have an existing OpenSCAD design, but I'd prefer a completely new, parametric version. I need it to handle different sized extinguishers. I'll want to be able to adjust the wall thickness of the bracket, the screw hole diameter, and the angle of the arms holding the extinguisher. I'm thinking of two main parts: a base that is mostly a cylinder with a flat backplate for mounting, and two arms that hold the extinguisher from the top. I want the base to be able to be printed without supports if possible.

For the base, I want a cylinder that the extinguisher rests in, and a flat backplate that extends outwards to allow for mounting to the wall. The back plate should have two screw holes for mounting. I want to be able to specify the cylinder diameter of the inner cylinder where the extinguisher will rest. The back plate should have mounting screw holes that can also be specified in size. The whole thing should be printable with the flat back plate down on the print bed, and with the support cylinder extending from that.

For the arms, I want to start with a similar main cylinder shape as the base, but have two arms cut from it that extend outwards at an angle to grab the extinguisher from the top. The angle between the arms should be adjustable. The arms themselves should be solid and flat, and join into the main cylindrical portion. I want these arms to be able to attach to the back plate.

I would like all dimensions to be parametric, and all parts to be designed so that they can be 3D printed without supports.

The parameters I will want to adjust are:

*   `extinguisher_diameter`: The diameter of the extinguisher in mm.
*   `bracket_width`: The wall thickness of the bracket in mm. This should affect all the parts where appropriate.
*   `screw_hole_diameter`: The diameter of the screw holes in mm.
*   `arm_angle`: The angle between the arms in degrees.

I'd also like the screw holes to be countersunk.

Can you generate the OpenSCAD files for this, maybe one file per part? Also, are there any common libraries that would be useful for OpenSCAD designs like this?

[Assistant]
ExtinguisherMount.scad:
```
/* [ Basics ] */
// Which one would you like to see?
part = "Base"; // [Base:The bottom of the bracket,Arms:The arms to hold the extinguisher]

//The Diameter of your extinguisher (mm)
extinguisher_diameter = 80;
/* [ Extras ] */
// The width of the walls of the bracket (mm). Most parts scale with this value.
bracket_width = 4;
// The diameter of the screw hole (mm). The countersinking scales with this.
screw_hole_diameter = 3;
// The size of the gap in the arms (degrees).
arm_angle = 120; // [90:180]

/* [Hidden] */
// All done. Customizer doesn't need to see all this

$fn=50;
ext_r = extinguisher_diameter/2;
screw_r = screw_hole_diameter/2;
back_width = ext_r*1.5;
arm_angle = 120;

angle = (arm_angle - 90 )/2;
back_height = 8*bracket_width+screw_hole_diameter;

cube_size = 10; // [1:100]
cylinder_size = 10; // [1:100]

print_part();

module print_part() {
	if (part == "Base") {
		base();
		back_plate();
	}
	else {
		back_plate();
		arms();
	}
}

module base(){
difference(){
cylinder(r = ext_r+bracket_width, h = 4*bracket_width);
translate([-0,0,bracket_width])cylinder(r = ext_r, h = 4*bracket_width);
translate([0,0,-bracket_width/2])cylinder(r = ext_r-3*bracket_width, h = 2*bracket_width);
}
}
//translate([0,ext_r-bracket_width,4*bracket_width])cube(back_height-4*bracket_width);

module arms(){
difference(){
cylinder(r = ext_r+bracket_width, h = 4*bracket_width);
translate([0,0,-bracket_width])cylinder(r = ext_r, h = 8*bracket_width);
rotate([0,0,angle])rotate([0,0,45+180])translate([0,0,-.01])cube(back_width);
rotate([0,0,-angle])rotate([0,0,45+180])translate([0,0,-.01])cube(back_width);
}
rotate([0,0,arm_angle/2])
translate([0,-(ext_r+bracket_width),0])cylinder(r = bracket_width, h = 4*bracket_width);
rotate([0,0,-arm_angle/2])
translate([0,-(ext_r+bracket_width),0])cylinder(r = bracket_width, h = 4*bracket_width);

}

module back_plate(){
difference(){
translate([-back_width/2,bracket_width,0])cube([back_width, ext_r,back_height]);
translate([0,0,-.01])cylinder(r = ext_r, h = back_width*2);
translate([back_width/2-2*bracket_width-screw_r,0,0])screw_hole();
translate([-(back_width/2-2*bracket_width-screw_r),0,0])screw_hole();
}
}

module screw_hole(){
translate([0,ext_r,6*bracket_width+screw_r])rotate([-90,0,0])
union(){
cylinder(r = screw_r, h = extinguisher_diameter);
translate([0,0,-screw_r+.01])cylinder(r2 = screw_r, r1 = screw_r*3, h = screw_r);
translate([0,0,-screw_r-ext_r+.02])cylinder(r = screw_r*3, h = ext_r);
}
}

```


[User]
Okay, I need an OpenSCAD design for a microscope adapter, something that will let me take pictures through the microscope with my phone. I've got some basic dimensions I want to be able to tweak.

The adapter needs to have a cylindrical part that fits over the microscope eyepiece and a rectangular part that holds my phone.

For the cylindrical part, I need to be able to set the eyepiece diameter, the distance the cylinder extends past the phone mounting plate (distance_away), and the lens diameter which will be a hole all the way through the cylinder. Additionally, the length of the cylinder past the mounting plate needs to be a user-set parameter (tube_length) which should be added to the distance_away parameter to obtain the total cylinder length.

The phone mount part should have a rectangular opening that's offset from the center of the cylinder. I need to be able to set the x and y coordinates for the center of my camera lens relative to the cylinder center (cam_x and cam_y). The rectangular opening should be large enough so that my phone's camera lens can see through the adapter. I also need to control the thickness of the wall of the rectangular phone holder (wall_thickness) and the wall_height of the phone holder (wall_height), and the height of the phone mounting plate itself. The phone mounting plate should be 2.5 units thick by default.

I'd like the design to be parametric so I can adjust these dimensions easily.

Here's a summary of the parameters I need:

*   `eyepiece_diameter`: Diameter of the microscope eyepiece.
*   `distance_away`: Distance the cylinder extends past the phone mounting plate.
*   `lens_diameter`: Diameter of the hole through the cylinder to allow the lens to see through the adapter.
*   `cam_x`: X coordinate of the camera lens center relative to the cylinder center.
*   `cam_y`: Y coordinate of the camera lens center relative to the cylinder center.
*   `wall_height`: Height of the wall of the phone holder.
*   `wall_thickness`: Thickness of the wall of the phone holder.
*   `tube_length`: Length of the cylindrical tube extending past the phone mount.

I'm hoping to get a single .scad file that I can just open and change the values of the parameters in. I don't think I need anything from any external libraries.

[Assistant]
Microscope_Adapter.scad:
```
eyepiece_diameter = 30;
distance_away = 2.5;
lens_diameter = 20;
cam_x = 9.28;
cam_y = 7.35;
wall_height = 10;
wall_thickness = 3;
tube_length= 30;

outer_diameter = eyepiece_diameter+5;
plate_w = cam_y + outer_diameter/2 + wall_thickness;
plate_h = cam_x + outer_diameter/2 + wall_thickness;

rotate([0,180,0]){
difference(){
	union(){
		translate([cam_y - plate_w + wall_thickness, cam_x - plate_h + wall_thickness, 0]){
			cube([plate_w, plate_h, 2.5]);
		}
		cylinder(tube_length + distance_away, outer_diameter/2, outer_diameter/2);
	}
	translate([0,0,distance_away]){
		cylinder(tube_length + distance_away, eyepiece_diameter/2, eyepiece_diameter/2);
	}
	translate([0,0,-1]){
		cylinder(tube_length + distance_away, lens_diameter/2, lens_diameter/2);
	}
}
translate([-outer_diameter/2,cam_x,-wall_height]){
	cube([plate_w, wall_thickness, wall_height]);
}
translate([cam_y,-outer_diameter/2,-wall_height]){
	cube([wall_thickness, plate_h, wall_height]);
}
}
```


[User]
Hi there, I'm looking for some help designing a parametric toilet paper holder using OpenSCAD. I've got a basic idea of the design, and I'm hoping you can generate the necessary SCAD files for me.

Essentially, the holder will be made of two main pieces: a larger tube and a smaller tube that fits inside the larger one with a spring in between. The two tubes will interlock with a simple key and slot design. Both tubes will have endcaps. I want to be able to adjust the dimensions to fit different sized springs and toilet paper rolls.

Here's a more detailed breakdown of what I'm after:

*   **Large Tube:** This is the main body of the holder. It should be a hollow cylinder with parameters for diameter, length, and wall thickness. It will have an endcap attached to one end.
*   **Small Tube:** This tube will slide into the large tube and also be a hollow cylinder with parameters for diameter, length and wall thickness.  It will also have an endcap.
*   **Interlocking Mechanism:** I envision a simple key-and-slot type mechanism, with a key on the small tube and a slot on the large tube. It needs to compress a spring. The key will just be a rectangular prism extruding out from the small tube and the slot will be a rectangular cutout on the large tube.
*   **Endcaps:** These will be small, simple cylinders that attach to the end of the tubes.  They should have parameters for base thickness, base diameter, cap diameter and cap height.
*   **Spring:** While the spring isn't part of the design itself, the design should allow a certain percentage of compression of the spring.  I expect this to need parameters for spring length.  I want to define compression as a percentage (e.g. 90%)
*   **Overall Length:** There needs to be a parameter for overall length, which affects the lengths of both tubes.  I want the small tube to slide into the large tube and allow the interlocking mechanism to align correctly.

I’d like all the dimensions to be parametric, so I can easily adjust the holder to fit any roll and spring. I'm hoping you can create a set of SCAD files that allow me to easily modify these parameters. I am not expecting you to add any libraries for springs or other complex functionality. I just need the basic geometry and parametric control. I am looking for the files to be set up so that I can just load the files and adjust variables to get the result I want.

I believe that should be all the detail you need to generate a good file. Please let me know if anything is unclear or you need further information.

[Assistant]
toil_paper_holder_v2.scad:
```
lg_dia = 25; 	// large cylinder diameter
lg_len = 80; 	// large cylinder length
lg_d = 1.8;		// large cylinder thickness

cap_dia = 15.5;
cap_len = 7;
cap_d = 1.2;

total_len = 160; // total length

sp_len = 68;	// spring length

/*
 * This generates the height of the interlocking piece.
 * It is designed to achieve 90% compression of the spring
 */
lock_h = (lg_len - ((sp_len) * .9))/2;

sm_dia = 21.5;	// small cylinder diameter
sm_len = total_len - lg_len + lock_h;	// small cylinder length
sm_d = 1.5;		// small cylinder thickness

key_sz = 3; // Thickness of the interlocking piece

/*
 * Hollow tube
 */
module tube(len,dia,thick) {
	difference() {
		cylinder(len,d=dia,dia/2);
		translate([0,0,-5]) {
			cylinder(len+10,d=(dia-thick),(dia-thick)/2);
		};
	};
};

/*
 * Endcap where tube attaches to holder
 */
module endcap(base_thick=2, base_dia, dia, height) {
	cylinder(base_thick, d=base_dia, base_dia/2);
	tube(cap_len+base_thick,cap_dia,cap_d);
}

/*
 * Simple interlocking piece
 */
module tube_lock(height,outer_dia,inner_dia,key_size) {
	difference() {
		tube(height,outer_dia,(outer_dia-inner_dia)*.8);
		translate([-key_size/2,-(outer_dia+10)/2,-5]) {
			cube([key_size,outer_dia+10,height+10]);
		};
	}
}

/*
 * Simple key
 */
module tube_key(height,outer_dia,inner_dia,key_size) {
	/* set to 90% thickness of difference between outer and inner tube */
	tube(height,inner_dia,outer_dia-inner_dia);
	translate([-(key_size*.8)/2,-(outer_dia-.2)/2,0]) {
		cube([key_size*.8,outer_dia-.2,height]);
	}
}

module big_tube() {
	union() {
		tube(lg_len, lg_dia, lg_d);
		tube_lock(lock_h,lg_dia-lg_d,sm_dia,key_sz);
		translate([0,0,lg_len-2]) {
			endcap(2, lg_dia, cap_dia, cap_len);
		}
	}
}

module small_tube() {
	union() {
		tube_key(lock_h,lg_dia-lg_d,sm_dia,key_sz);
		translate([0,0,lock_h]) {
			tube(sm_len, sm_dia, sm_d);
			translate([0,0,sm_len-2]) {
				endcap(2, sm_dia, cap_dia, cap_len);
			}
		}
	}
}

translate([0,-(lg_dia/2+sm_dia/2+25)/2,0]) {
	big_tube();
	translate([0,50,0]) {
		small_tube();
	}
}
```


[User]
I'm looking to generate some cable holders that I can customize with OpenSCAD. I have a general idea of what I want, but I need it to be flexible and user-friendly, so I'm hoping you can help me create a parametric design.

Essentially, I need a holder that mounts to a wall or surface using a nail or screw, and it needs to hold a round cable. The design should be a half-circle for the cable to rest in, with a hole behind it for the nail or screw.

Here's a breakdown of the parameters I'd like to be able to control:

*   **`Width`**: The overall width of the holder - how far it extends from the mounting surface.
*   **`NailDiameter`**: The diameter of the nail or screw that will be used to mount it.
*   **`CableDiameter`**: The diameter of the cable that the holder will accommodate.
*   **`Thickness`**: The thickness of the plastic material around the cable and mounting hole.
*  **`CutLengthBottom`**:  A length that controls a cut out below the cable holder.
*  **`CutLengthSide`**: A length that controls a cut out on the side of the cable holder.
*   **`Resolution`**: A setting to control how finely the curves are rendered. I'd like this to allow for values like "Draft", "Medium", "Fine", and "Very Fine," which would correspond to different `$fn` values.
*   **`Geometry`**: Another way to control detail, specifically related to the nail hole.
*   **`NailHeadDiameter`**: The diameter of the head of the nail or screw being used.
*   **`CountersinkDepth`**: The depth of the countersink for the nail or screw head.
*   **`Countersink`**:  This should be a selection between "Normal" (a regular countersink), "No Countersink", and "Angle" (for an angled countersink).
*   **`Manifoldfix`**: A small hidden parameter that controls the tolerance between objects - set it to something like 0.1.

I think that covers everything! I'd like to keep this reasonably simple to generate so it doesn't use a bunch of external libraries. I'd prefer that you use the built-in functions from OpenSCAD rather than any external libraries if possible.

[Assistant]
CustomizableCableHolder2.scad:
```
// ************* Credits part *************

// "Customizable Cable Holder"

// Programmed by Fryns - September 2014

// Optimized for Customizer

// ************* Declaration part *************

/* [Dimensions] */
// Width of hanger in mm
Width=4;
NailDiameter=1.6; // Nail or Screw Diameter
CableDiameter=6.0;
Thickness=1;

/* [Advanced] */
CutLengthBottom=0.1; // from -Thickness to CableDiameter
CutLengthSide=1; // from 0 to CableDiameter
Resolution=100; //[20:Draft,50:Medium,100:Fine, 200:very fine]
Geometry=8; //[8:Obey rule of 45,100:Fine, 200:very fine]

/* [Countersink] */
NailHeadDiameter=2.5;
CountersinkDepth=1.2;
Countersink="Normal"; // [Normal,No Countersink,Angle]

/* [Hidden] */
Manifoldfix=0.1;

// ************* Executable part *************
translate([0,0,Width/2])
rotate(a=[90,0,0])
difference(){
	BaseVolume();
	CutVolume();
	if (Countersink=="Angle") CountersinkAngle();
	if (Countersink=="Normal") Countersink();
}

// ************* Module part *************

module BaseVolume(){
//Base ensuring plane top
   translate([(NailDiameter/2+CableDiameter/2+Thickness)/2,0,0])
		cube(size = [NailDiameter/2+CableDiameter/2+Thickness,Width,CableDiameter+2*Thickness], center = true);

//Base head for Nail
	rotate(a=[0,0,360/(Geometry*2)])
		cylinder(h = CableDiameter+2*Thickness, r = Width/2/cos(360/(Geometry*2)),$fn=Geometry, center = true);

//Base for cable
   translate([NailDiameter/2+CableDiameter/2+Thickness,0,0])
		rotate(a=[90,0,0])
			cylinder(h = Width, r = (CableDiameter+2*Thickness)/2,$fn=Resolution, center = true);
}

module CutVolume(){
// cut-cylinder for Nail
	rotate(a=[0,0,360/(8*2)])
		cylinder(h = CableDiameter+2*Thickness+Manifoldfix, r = NailDiameter/2/cos(360/(Geometry*2)),$fn=Geometry, center = true);

// cut-cylinder for cable
   translate([NailDiameter/2+CableDiameter/2+Thickness,0,0])
		rotate(a=[90,0,0])
		cylinder(h = Width+2*Manifoldfix, r = (CableDiameter)/2,$fn=Resolution, center = true);

// cut-cube Bottom
   translate([(Width+CableDiameter+2*Thickness)/2-Width/2-Manifoldfix,0,CutLengthBottom+Thickness-(CableDiameter+2*Thickness)])
		cube(size = [Width+CableDiameter+2*Thickness,Width+Manifoldfix,CableDiameter+2*Thickness], center = true);

// cut-cube Side
   translate([NailDiameter/2+(CableDiameter-CutLengthSide)/2+Thickness,0,-(CableDiameter+2*Thickness)/2])
		cube(size = [CableDiameter-CutLengthSide,Width+Manifoldfix,CableDiameter+2*Thickness], center = true);
}

module Countersink(){	// Normal countersink for nail head
   translate([0,0,(CableDiameter+2*Thickness)/2-CountersinkDepth+Manifoldfix])
		rotate(a=[0,0,360/(Geometry*2)])
			cylinder(h = CountersinkDepth, r = NailHeadDiameter/2/cos(360/(Geometry*2)),$fn=Geometry, center = false);
}

module CountersinkAngle(){ // Angle countersink for screw head
   translate([0,0,(CableDiameter+2*Thickness)/2-(NailHeadDiameter/2-NailDiameter/2)+Manifoldfix])
		cylinder(h = NailHeadDiameter/2-NailDiameter/2, r1 = NailDiameter/2,r2 = NailHeadDiameter/2,$fn=Resolution, center = false);
}
```


[User]
I need an OpenSCAD design for a spool roller bracket that press-fits into the existing Printrbot Simple XL spool roller frame. This bracket will have two sets of rollers: one for wider spools, around 90mm, and one for narrower spools, around 58mm. I'm envisioning something similar to the attached `spoolbracket.scad` but I'd like the new design to be fully parametric.

Here's the basic functionality and measurements I need:

*   **Press-fit:** The bracket should press-fit into a socket with dimensions `socket_x` (width) and `socket_y` (depth).
*   **Bearing Mounts:** The bracket will use standard roller bearings. I need to specify the `bearing_outer_diameter`, `bearing_inner_diameter`, and `bearing_screw_diameter`.  I also need to define the lip size, `bearing_lip` that keeps the bearing in place.
*   **Bracket Thickness:** I need to be able to control the minimum thickness of the frame using the parameter `bracket_width`.
*   **Spool Widths:** There should be two sets of bearing mounts. One set for a smaller spool with width `inner_spool`, and one for a larger spool with width `outer_spool`.
*   **Corner Reinforcements:** The design should include some kind of corner bracing or reinforcement around the bearing mounts. Something like the `Brace` module in the provided code is okay.
*   **Axle Holes:** There should be mounting holes for axles at the center of each set of bearing mounts.

I'd like all of this to be parametric, so I can easily adjust the values above. Please use the `linear_extrude` and `polygon` features for the overall shape, similar to what's done in the existing `spoolbracket.scad`. It's probably easiest if you work off of the existing shapes in that file, but I'd also like to see if you can generate something more robust by including a more complex bracing structure.

Finally, I'd prefer if the design is laid out in a way that's easy to modify and understand. I'm fine with you using helper modules if that makes things cleaner but I do not want you to use any external libraries.

[Assistant]
spoolbracket.scad:
```
// Outer diameter of roller bearings. (mm)
bearing_outer_diameter = 22;

// Inner diameter of roller bearings. Determines diameter of bearing mounting pegs. (mm)
bearing_inner_diameter = 7.75;

// Diameter of pilot holes for bearing mounting screws. (mm)
bearing_screw_diameter = 2.5;

// Minimum size of bearing flange formed by bracket body. Keeps spool on bracket. (mm)
bearing_lip = 2;

// Minimum thickness of bracket frame. (mm)
bracket_width = 6;

// Width of socket into which the bracket is press fit. (mm)
socket_x = 76;

// Depth of socket into which the bracket is press fit. (mm)
socket_y = 25;

// Width of inner spool (should be less than socket width). (mm)
inner_spool = 59;

// Width of outer spool (should be greater than socket width). (mm)
outer_spool = 90;

bearing_zone = bearing_outer_diameter + (2 * bearing_lip);
lower_stack = max(socket_y, bearing_zone);

// Curved corner reinforcements
module Brace() {
	scale([bearing_outer_diameter/2, bearing_outer_diameter/2, bearing_outer_diameter/2])
	rotate([0, 0, 180])
	translate([-1, -1, -1])
	difference() {
		polyhedron(
			points=[
				[1, 1, 0],
				[1, 1, 1],
				[1, 0, 1],
				[0, 1, 1]
			],
			triangles=[
				[0, 1, 2],
				[3, 0, 2],
				[3, 1, 0],
				[1, 3, 2]
			]
		);
		sphere(r = sqrt(2), $fn = 60, center=true);
	}
}

module Braces() {
	// inner spool braces
	translate([-inner_spool/2, bracket_width, bearing_zone/2]) Brace();
	translate([-inner_spool/2, bracket_width, -bearing_zone/2]) mirror([0, 0, 1]) Brace();
	translate([inner_spool/2, bracket_width, bearing_zone/2]) mirror([0, 0, 1]) rotate([0, 180, 0]) Brace();
	translate([inner_spool/2, bracket_width, -bearing_zone/2]) rotate([0, 180, 0]) Brace();

	// outer spool braces
	translate([-outer_spool/2, lower_stack + bracket_width, bearing_zone/2]) Brace();
	translate([-outer_spool/2, lower_stack + bracket_width, -bearing_zone/2]) mirror([0, 0, 1]) Brace();
	translate([outer_spool/2, lower_stack + bracket_width, bearing_zone/2]) mirror([0, 0, 1]) rotate([0, 180, 0]) Brace();
	translate([outer_spool/2, lower_stack + bracket_width, -bearing_zone/2]) rotate([0, 180, 0]) Brace();
}

module Axle() {
	rotate([0, 90, 0]) cylinder(d=bearing_screw_diameter, h= outer_spool + (2 * bracket_width) + 1, center=true, $fn=30);
}

module BevelButton(diameter = 8, flat = 2, height = 3) {
	assign(inset = (diameter - flat)/2, radius = diameter/2)
	// this intersection operation seems to leave a micro gap
	intersection() {
		rotate([90, 0, 0])
		linear_extrude(height=diameter, center=true)
		polygon(points=[
			[-radius, 0	],
			[inset - radius, height],
			[radius - inset, height],
			[radius, 0]
		]);
		cylinder(h=height, r=radius, $fn=30);
	}
}

module BracketStock() {
	difference() {
		union() {
			linear_extrude(height=bearing_zone, center=true) BracketPattern();

			// bearing holders
			translate([-inner_spool/2, lower_stack + bracket_width - bearing_zone/2, 0]) rotate([90, 90, 90]) BevelButton(bearing_inner_diameter, bearing_screw_diameter);
			translate([inner_spool/2, lower_stack + bracket_width - bearing_zone/2, 0]) rotate([-90, 90, 90]) BevelButton(bearing_inner_diameter, bearing_screw_diameter);
			translate([-outer_spool/2, lower_stack + bracket_width + bearing_zone/2, 0]) rotate([90, 90, 90]) BevelButton(bearing_inner_diameter, bearing_screw_diameter);
			translate([outer_spool/2, lower_stack + bracket_width + bearing_zone/2, 0]) rotate([-90, 90, 90]) BevelButton(bearing_inner_diameter, bearing_screw_diameter);
		}

		// inner spool axle hole
		translate([0, lower_stack + bracket_width - bearing_zone/2, 0]) Axle();

		// outer spool axle hole
		translate([0, lower_stack + bracket_width + bearing_zone/2, 0]) Axle();
	}
}

module BracketPattern() {
	pts = [
		[0, socket_x/2],
		[socket_y, socket_x/2],
		[socket_y, outer_spool/2 + bracket_width],
		[lower_stack + bracket_width + bearing_zone, outer_spool/2 + bracket_width],
		[lower_stack + bracket_width + bearing_zone, outer_spool/2],
		[lower_stack + bracket_width, outer_spool/2],
		[lower_stack + bracket_width, inner_spool/2],
		[bracket_width, inner_spool/2],
		[bracket_width, 0],
		[0, 0]
	];
	rotate([0, 0, 90]) union() {
		polygon(points=pts);
		mirror([0, 1, 0]) polygon(points=pts);
	}
}

rotate([0, 0, 180])
translate([0, 0, bearing_zone/2])
union() {
	BracketStock();
	Braces();
}
```


[User]
Okay, I need an OpenSCAD script that generates a fan grill with concentric rings, sort of like a negative space version of a fan guard. The idea is that I can use this to subtract it from the surface of a case to create a built-in fan grill, rather than having to add a separate grill.

Here are the parameters I need control over:

*   **Outer Diameter:** The overall diameter of the fan grill (e.g. 38mm).
*   **Inner Diameter:** The diameter of the central hole in the fan grill (e.g. 5mm).
*   **Number of Rings:** How many concentric rings the grill should have (e.g., 3 rings).
*   **Height:** The thickness or height of the rings (e.g., 10mm).
*   **Resolution:** The number of sides on each ring (e.g. 45 for a relatively smooth cylinder).
*   **Connector Width:** The width of the solid connectors that hold the rings together (e.g. 2mm).
*   **Orthogonal Connectors:** A boolean option to add two solid orthogonal connectors (perpendicular) (yes/no).
*   **Diagonal Connectors:** A boolean option to add two solid diagonal connectors (yes/no).

The script should generate the rings as a series of nested cylinders, with the diameters adjusted to create the concentric ring effect. The inner diameter should create the central opening.

Also, I need the script to use a difference operation to create the negative space, so that the generated solid can be used to subtract from other objects.

I'd also like it to be fairly straightforward to modify each variable without digging too deep into the code. I don't need any libraries this time, but the code should be well-commented, just in case I need to modify it later.

Can you generate that?

[Assistant]
NJC_Fan_Grid_Concentric_Holes_Generator.scad:
```
/* [FAN FEATURES] */

// How large is the fan rotor ? (mm)
OuterDiameter=38;
// How large is the inner part of the fan rotator ? (mm)
InnerDiameter=5;

/* [RINGS] */

// How many concentric rings should be generated ?
NumberOfRings = 3; // [1:20]
// The height of the extruded rings (mm)
Height = 10;
// The number of faces on each ring perimeter
Resoultion=45; // [3:100]

/* [CONNECTORS] */

// With of the solid connectors that keeps the rings attached to the surface (mm)
ConnectorsWidth=2;
// Generate a pair of solid orthogonal connectors ?
AddOrtogonalConnectors="YES"; // [YES,NO]
// Generate a pair of solid diagonal connectors ?
AddDiagonalConnectors="YES"; // [YES,NO]

// VARIABLES INITIALIZATION
echo("OuterDiameter=",OuterDiameter);
echo("InnerDiameter=",InnerDiameter);
echo("NumberOfRings=",NumberOfRings);
echo("Height=",Height);
echo("Resoultion=",Resoultion);

OuterRadius = OuterDiameter/2;
echo("OuterRadius=",OuterRadius);
InnerRadius = InnerDiameter/2;
echo("InnerRadius=",InnerRadius);

DeltaRadius = OuterRadius-InnerRadius;
echo("DeltaRadius=",DeltaRadius);
RingRadiusStep =DeltaRadius/(NumberOfRings*2-1);
echo("RingRadiusStep=",RingRadiusStep);

difference()
{
for (i=[0:2:(NumberOfRings*2-1)]){
echo(i," - Outer radius=",OuterRadius-(RingRadiusStep*(i)));
echo(i," - Inner radius=",OuterRadius-(RingRadiusStep*(i+1)));
 difference()
 {
  cylinder(h=Height,r=OuterRadius-(RingRadiusStep*(i)), center = true, $fn=Resoultion);
  cylinder(h=Height*2,r=OuterRadius-(RingRadiusStep*(i+1)), center = true, $fn=Resoultion);
 }
}

if(AddOrtogonalConnectors=="YES")
{
cube(size = [OuterDiameter*1.1,ConnectorsWidth,Height*2], center = true);
cube(size = [ConnectorsWidth,OuterDiameter*1.1,Height*2], center = true);
}

if(AddDiagonalConnectors=="YES")
{
rotate([0,0,45])
{
cube(size = [OuterDiameter*1.1,ConnectorsWidth,Height*2], center = true);
cube(size = [ConnectorsWidth,OuterDiameter*1.1,Height*2], center = true);
}
}

}

```


[User]
Hey, I'm looking to design a magnetic pickup tool for geocaching. I need to be able to customize it for different magnet sizes, and it should have holes for a wire to attach.

The basic idea is a cylinder with a recessed area for the magnet, and a channel for a wire to pass through. It's pretty similar to a design I saw online, I guess, but it needs to be fully parametric so I can adjust it for my specific magnets.

Here are the parameters I think are important:

*   `tool_diameter`: The overall diameter of the cylindrical tool body.
*   `tool_height`: The overall height of the tool body.
*   `magnet_diameter`: The diameter of the magnet to be embedded.
*   `magnet_height`: The height of the magnet to be embedded.
*   `wire_diameter`: The diameter of the wire used to attach the tool.
*   `distance_between_holes`: The distance between the two holes where the wire passes through.

The tool body will be a solid cylinder, and then I need to cut out the magnet recess and the wire channel using `difference()` in OpenSCAD. The magnet should be inset at the bottom of the tool. The wire holes should go through the sides of the tool, and there should be a channel connecting them near the magnet recess.

I would like the holes and cutouts for the wire to account for the wire radius, and for the cylinder for the magnet to be slightly larger so the magnet has space to be put in. I'm thinking I want the wire channel to be rectangular where it exits the circle and joins the holes.

Could you create the OpenSCAD files for this? It should be a single file.

[Assistant]
magnetic_pickup_tool.scad:
```
tool_diameter = 24.6;         // [0.0:60.0]
tool_height = 7;              // [0.0:30.0]
magnet_diameter = 20.6;       // [0.0:60.0]
magnet_height = 2;            // [0.0:30.0]
wire_diameter = 3;            // [0.0:10.0]
distance_between_holes = 10;	// [0.0:60.0]

magnet_radius = magnet_diameter / 2;
tool_radius = tool_diameter / 2;
wire_radius = wire_diameter / 2;

difference()
{

  cylinder(h = tool_height, r = tool_radius, $fn=72);

  // magnet
  translate([0,0,tool_height-magnet_height])
  {
    cylinder(h = magnet_height + 0.01, r = magnet_radius, $fn=72);
  }

  // hole for left wire
  translate([distance_between_holes / 2, 0, -0.5])
  {
    cylinder(h = tool_height + 0.01, r = wire_radius, $fn=36);
  }

  // hole for right wire
  translate([- distance_between_holes / 2, 0, -0.5])
  {
    cylinder(h = tool_height + 0.1, r = wire_radius, $fn=36);
  }

  // space connecting left and right hole
  translate([-distance_between_holes/2, 0, tool_height-magnet_height-wire_radius])
  {
    translate([0, -wire_radius, 0])
    {
      cube(size = [distance_between_holes, wire_radius*2 , wire_radius+0.01]);
    }

    rotate([0,90,0])
    {
      cylinder(h = distance_between_holes, r = wire_radius, $fn=36);
    }
  }
}

```


[User]
I need an OpenSCAD design for a simple cable holder that clamps onto the edge of a table. I'd like it to be parametric, so I can easily adjust the cable diameter, table thickness, holder width, and holder thickness.

Here are the specific parameters I need to control:

*   `diameter`: The diameter of the cable the holder will accommodate.
*   `height_table`: The thickness of the table that the holder will clamp onto.
*   `width`: The overall width of the holder.
*  `thickness`: The thickness of the material used for the holder.

I'd also like a toggleable option to add a small locking feature to help keep the cable in place. When enabled (`lock = "yes"`), this locking feature should consist of two small spheres that partially intrude into the cable channel.

I don't have any specific aesthetic requirements; a simple and functional design is fine.  I'm expecting that the holder will have a C-shaped profile that fits around the edge of the table. I don't need any other features, just the basic clamp and cable channel and optional cable lock.

Could you generate the OpenSCAD file or files for this? I'm not using any specific libraries at the moment, but if you require them, please let me know.

[Assistant]
cable_holder.scad:
```

/*[Parameters]*/

//diameter cable (default: 7)
diameter = 7; //[2:30]

//height table (default: 22.5)
height_table = 22.5;

//width holder (default: 10)
width = 10;

//Thickness holder (default: 2.5)
thickness = 2.5; //[2.5:5]

//Use Lock for cable? (default: No)
lock = "no"; //[no: No, yes: Yes]

/*[hidden]*/
module output(){
	if (lock == "yes"){
		lock();
	}
}

module lock(){
	translate([-(width/2)-(diameter)-(thickness/2),0,0]){
		translate([(diameter/14),(diameter/1.9),0]){
			sphere(r = diameter/12, $fn=32, center=true);
		}
		translate([(diameter/14),-(diameter/1.9),0]){
			sphere(r = diameter/12, $fn=32, center=true);
		}
	}
}

rotate ([0,-90,0])
part1();
module part1(){
	difference(){
		translate([0 ,0,0]){
		cube([width+(thickness),  diameter + (thickness*2) ,height_table+(thickness*2)], center = true);
	}
		translate([thickness,0,0]){
			cube([width+(thickness), diameter + (thickness*4), height_table], center = true);
		}
	}
	difference(){
		union(){
			difference(){
				translate([(-width/2)-(diameter/2)- (thickness/2),0,0]){
					cube	([diameter+thickness, diameter + (thickness*2) , height_table + (thickness*2)], center = true);
				}
				translate([(-width/2)-(diameter/2)-(thickness/2),0,0]){
					union(){
						#cylinder(h = height_table+(thickness*4), r = diameter/2, $fn=100, center=true);
						translate([-(diameter/2)-1,0, 0]){
							cube([diameter+2, diameter, height_table+(thickness*4)], center = true);
						}
					}
				}
			}

			//lock
			output();
		}

	}
}

```


[User]
Hey, I'm looking to get some custom drawer dividers designed for my small parts drawers. I've got a few specific requirements and would love some help creating an OpenSCAD file to generate them.

Basically, I want to be able to define the overall shape of the divider with different widths at the top and bottom, along with a specified height and thickness. The bottom of the divider should have rounded corners, and the top should also have rounded corners, but potentially with a different radius than the bottom. I need to be able to specify all of these parameters.

Additionally, I'd like to be able to generate multiple dividers in a single print. So I'll need to define a grid of these dividers by specifying the number of rows and columns, and the separation between them.

I want to ensure it's fully parametric, so I can easily adjust any of these values in the future. I guess the main parameters would be the bottom width, the top width, the height, the thickness, bottom corner radius, top corner radius, the grid separation, number of grid rows, and number of grid columns.

Could you create an OpenSCAD file or files that would let me do that? I don't think I need any special libraries, just some basic OpenSCAD commands. Thanks!

[Assistant]
drawer_dividers.scad:
```
bottom_width = 50;
top_width = 51;
height = 32;
thickness = 1.5;
bottom_radius = 1; // [0.01:10]
top_radius = 0.01; // [0.01:10]

grid_separation = 3;
grid_rows = 1;
grid_columns = 10;

/* [Hidden] */
$fn = 50;

module divider() {
	rotate(90, [1,0,0]) hull() {
		translate([bottom_width/2-bottom_radius,height-bottom_radius,0]) cylinder(r=bottom_radius, h=thickness);
		translate([-bottom_width/2+bottom_radius,height-bottom_radius,0]) cylinder(r=bottom_radius, h=thickness);
		translate([top_width/2-top_radius,top_radius,0]) cylinder(r=top_radius, h=thickness);
		translate([-top_width/2+top_radius,top_radius,0]) cylinder(r=top_radius, h=thickness);
	}
}

for(a = [1:grid_rows])
	for(b = [1:grid_columns])
		translate([a*(grid_separation + max(bottom_width, top_width)), b*(grid_separation + thickness), 0])
			divider();

```