Link bumper thickness to dw

Link bumper thickness to dw

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

	    color(Level2PlasticColor) {
            if (UseSTL) {
                import(str(STLPath, "Bumper.stl"));
            } else {
				BumperModel();
            }
        }
	}
}

Bumper_Pin_Width = 3;
Bumper_Pin_Length = 18;

module BumperModel()
{
	thickness = dw;
	height = 15;
	offset = 5;				// distance from base to inside of bumper
	wrapAngle = 170;		// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	outr = BaseDiameter/2 + offset + thickness; // outr is the outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate(a=wrapAngle/2, v=[0,0,1])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate(a=-wrapAngle/2, v=[0,0,1])
			square([outr, outr * 2]);
	}

	// Springy bits
	for(i=[0,1])
		mirror([i, 0, 0])
		translate([30, outr - 24, 0])
		rotate([0,0,90])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175, center=true);

	// Flanges to hit microwitch
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate(a=microSwitchAngle, v=[0, 0, 1]) {
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([8, offset + 1 + eta, 5]);
	}

	// Microswitch plates
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate([0, 0, microSwitchAngle])
	translate([-10, BaseDiameter/2 - 23, 0])
		MicroSwitchPlate();

}

module MicroSwitchPlate()
{
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Pin section
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0,0,dw])
		mirror([0,0,1])
			pinhole(fixed=true);
	}
}

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

	    color(Level2PlasticColor) {
            if (UseSTL) {
                import(str(STLPath, "Bumper.stl"));
            } else {
				BumperModel();
            }
        }
	}
}

Bumper_Pin_Width = 3;
Bumper_Pin_Length = 18;

module BumperModel()
{
	thickness = 2;
	height = 15;
	offset = 5;				// distance from base to inside of bumper
	wrapAngle = 170;		// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	outr = BaseDiameter/2 + offset + thickness; // outr is the outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate(a=wrapAngle/2, v=[0,0,1])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate(a=-wrapAngle/2, v=[0,0,1])
			square([outr, outr * 2]);
	}

	// Springy bits
	for(i=[0,1])
		mirror([i, 0, 0])
		translate([30, outr - 24, 0])
		rotate([0,0,90])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175, center=true);

	// Flanges to hit microwitch
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate(a=microSwitchAngle, v=[0, 0, 1]) {
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([8, offset + 1 + eta, 5]);
	}

	// Microswitch plates
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate([0, 0, microSwitchAngle])
	translate([-10, BaseDiameter/2 - 23, 0])
		MicroSwitchPlate();

}

module MicroSwitchPlate()
{
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Pin section
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0,0,dw])
		mirror([0,0,1])
			pinhole(fixed=true);
	}
}


Add groud station 3D

Add groud station 3D

//rotate([90,0,0]) union(){
//	rotate_extrude(convexity = 10)
//	translate([6, 0, 0])
//	circle(r = 1);
//}
rotate([90,0,0]) union(){
	linear_extrude(height = 2, center = false, convexity = 10, twist = 360, $fn = 100)
	translate([6, 0, 0])
	scale([1,1,1]) circle(r=1);
}
rotate([90,0,0])
minkowski(){
rotate([0,0,90]) translate([6,0,0]) sphere(r=1);
rotate([0,0,70]) translate([6,0,0]) sphere(r=1);
}

winch();
translate([480, 0,0]) rotate([0, 0, 180]) winch();
translate([480/2,0,-40/2-20/2]) cube(size=[480+100, 300,20], center=true);
module pulley(){
	difference(){
	cylinder(r=6, h =10, center= true);
	cylinder(r=5, h =11, center= true);

	}
	difference(){
	cylinder(r=15, h =10, center= true);
	cylinder(r=7.5, h =11, center= true);

	}
}

module winch(){
	rotate([90, 0,0]) union(){
		translate([0,0, 50])
		union(){
			pulley();
			pulley_support();
		}
		translate([0,0, -50])
		union(){
			pulley();
			pulley_support();
		}
		translate([0,0,0])  cylinder(r=5, h=150, center=true);

	}
}

module pulley_support(){
difference(){
translate([25, 0,0]) cube(size=[100, 40,10], center=true);
cylinder(r=16, h =11, center= true);
translate([-15,0,0]) cube(size=[25,12,11], center=true);
}
}

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


adapted block

adapted block

extrusiuon heigth 13, and pipe module added

$fn=50;
module side_flat() {
    difference() {
        square([37,34]);
        for(i=[3.5,37-3.5])translate([i,3.5])circle(r=3/2);
        translate([37-3.5,11.5])circle(r=8/2);
        translate([0,7])square([7,50]);
        translate([18,25.5])circle(r=7);
        translate([5,25.5])square([37,34]);
        translate([17,18.5])square([37,34]);
    }
}
module side_ext() {
    difference() {
        translate([0,16])rotate(a=[90,0,0])difference() {
            linear_extrude(height=13)side_flat();
            for(i=[3.5,37-3.5])translate([i,3.5,2])cylinder(r=5.4/2,h=16);
        }
        translate([21.5,11])pipe();
    }
}
module pipe() {

    cylinder(r=3,$fn=9,h=2);
    translate([0,0,2])cylinder(r=3,$fn=6,h=6);
    translate([0,0,8])cylinder(r2=1,r1=1.75,h=4);
    translate([0,0,11])cylinder(r=1,h=8);
}
side_ext();

$fn=50;
module side_flat() {
    difference() {
        square([37,34]);
        for(i=[3.5,37-3.5])translate([i,3.5])circle(r=3/2);
        translate([37-3.5,11.5])circle(r=8/2);
        translate([0,7])square([7,50]);
        translate([18,25.5])circle(r=7);
        translate([5,25.5])square([37,34]);
        translate([17,18.5])square([37,34]);
    }
}
module side_ext() {
    difference() {
        translate([0,16])rotate(a=[90,0,0])difference() {
            linear_extrude(height=16)side_flat();
            for(i=[3.5,37-3.5])translate([i,3.5,2])cylinder(r=5.4/2,h=16);
        }
        translate([21.5,11])cylinder(r=2,h=30);
    }
}

side_ext();


Line up batteries inside battery pack (slightly cheating)

// Battery packs
// battery_pack_linear - all batteries in a row
// battery_pack_double - 2 rows of batteries (can't cope with odd numbers!)

// Point of origin is the centre of the end of the end battery.

include <../config/colors.scad>

eta = 0.01;

// AAs - http://en.wikipedia.org/wiki/AA_battery

//                    Battery len, Battery dia, Pack width, Pack depth, Pack height, Linear?, Batteries, Name
BatteryPack_AA_4_SQ = [ 50.5,       14.5,        31.4,       27.5,       57.4,        0,      , 4,       "AA" ];

// Default:
BatteryPack_AA = BatteryPack_AA_4_SQ;

// Constants for access:
BatteryPack_Const_BLen = 0;
BatteryPack_Const_BDia = 1;
BatteryPack_Const_PWidth = 2;
BatteryPack_Const_PDepth = 3;
BatteryPack_Const_PHeight = 4;
BatteryPack_Const_Linear = 5;
BatteryPack_Const_Count = 6;
BatteryPack_Const_Name = 7;

// Connectors:
function BatteryPack_Con_Centre(BP) = [
  [
    BP[BatteryPack_Const_PWidth]/2 + BP[BatteryPack_Const_BDia]/2,
    BP[BatteryPack_Const_PDepth]/2 + BP[BatteryPack_Const_BDia]/2,
    BP[BatteryPack_Const_PHeight]/2,
  ],
  [ 0,0,0 ],
  0, 0, 0
];

// We have the total battery length, assume the positive terminal is 1/20th of the length
module battery(BP) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];

  button_h = (1/20)*Battery_len;
  top_h = (1/3)*Battery_len;
  bottom_h = Battery_len-(top_h+button_h);

  color("black")
  linear_extrude(height=bottom_h)
    circle(r=Battery_dia/2);

  color("red")
  translate([0, 0, bottom_h])
    linear_extrude(height=top_h)
      circle(r=Battery_dia/2);

  color(MetalColor)
  translate([0, 0, bottom_h+top_h])
    linear_extrude(height=button_h)
      circle(r=Battery_dia/4);

}

module battery_pack_linear(BP, battery_sep, battery_count) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];

  for(i=[0:battery_count-1]) {
    translate([i*(Battery_dia+battery_sep), 0, 0])
      if(i % 2 == 1) {
        translate([0,0,Battery_len/2])
          rotate([180, 0, 0])
            translate([0,0,-Battery_len/2])
              battery(BP);
      } else {
        battery(BP);
      }
  }
}

module battery_pack_double(BP, battery_sep, battery_count) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];
  BatteryPack_height = BP[BatteryPack_Const_PHeight];

  translate([0,0,(BatteryPack_height-Battery_len)/2])
  for(i=[0:(battery_count/2)-1]) {
    translate([i*(Battery_dia+battery_sep), 0, 0])
      battery(BP);
    translate([i*(Battery_dia+battery_sep), Battery_dia+battery_sep, 0])
      translate([0,0,Battery_len/2])
        rotate([180, 0, 0])
          translate([0,0,-Battery_len/2])
            battery(BP);
  }
}

// NB, This completely ignores battery count/linear setting! 2x2 is what you get!
module BatteryPack(BP) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];
  BatteryPack_height = BP[BatteryPack_Const_PHeight];
  BatteryPack_width = BP[BatteryPack_Const_PWidth];
  BatteryPack_depth = BP[BatteryPack_Const_PDepth];

  // Actually measured, it overhangs by 2mm, 1 because this is actually
  // a radius -- how far is the center-line of the battery offset from the edge
  // of the case (in the y direction).
  battery_depth_offset = Battery_dia/2 - 1;

  render()
  translate([-Battery_dia/2, -Battery_dia/2,0])
  difference() {
   linear_extrude(height=BatteryPack_height)
     hull() {
      // Main body
      translate([Battery_dia/2, Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([BatteryPack_width-Battery_dia/2, Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([Battery_dia/2, BatteryPack_depth-Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([BatteryPack_width-Battery_dia/2, BatteryPack_depth-Battery_dia/2, 0])
        circle(r=Battery_dia/2);
   }

   // Subtract battery shapes
   translate([Battery_dia/2-eta, battery_depth_offset-eta, (BatteryPack_height-Battery_len)/2])
     cylinder(h=Battery_len, r=Battery_dia/2);

   translate([BatteryPack_width-Battery_dia/2+eta, battery_depth_offset-eta, (BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);

   translate([Battery_dia/2-eta, BatteryPack_depth-battery_depth_offset+eta, (BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);
   translate([BatteryPack_width-Battery_dia/2+eta,BatteryPack_depth-battery_depth_offset+eta,(BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);

   translate([BatteryPack_width/4,-BatteryPack_depth+6,(BatteryPack_height-Battery_len)/2])
     cube([BatteryPack_width/2, BatteryPack_depth, Battery_len]);
   translate([BatteryPack_width/4,BatteryPack_depth-6,(BatteryPack_height-Battery_len)/2])
     cube([BatteryPack_width/2, BatteryPack_depth, Battery_len]);

 }
}

*battery_pack_linear(BatteryPack_AA, 2,4);
*battery_pack_double(BatteryPack_AA, 2, 4);
*battery(BatteryPack_AA);
BatteryPack(BatteryPack_AA);

// Battery packs
// battery_pack_linear - all batteries in a row
// battery_pack_double - 2 rows of batteries (can't cope with odd numbers!)

// Point of origin is the centre of the end of the end battery.

include <../config/colors.scad>

eta = 0.01;

// AAs - http://en.wikipedia.org/wiki/AA_battery

//                    Battery len, Battery dia, Pack width, Pack depth, Pack height, Linear?, Batteries, Name
BatteryPack_AA_4_SQ = [ 50.5,       14.5,        31.4,       27.5,       57.4,        0,      , 4,       "AA" ];

// Default:
BatteryPack_AA = BatteryPack_AA_4_SQ;

// Constants for access:
BatteryPack_Const_BLen = 0;
BatteryPack_Const_BDia = 1;
BatteryPack_Const_PWidth = 2;
BatteryPack_Const_PDepth = 3;
BatteryPack_Const_PHeight = 4;
BatteryPack_Const_Linear = 5;
BatteryPack_Const_Count = 6;
BatteryPack_Const_Name = 7;

// Connectors:
function BatteryPack_Con_Centre(BP) = [
  [
    BP[BatteryPack_Const_PWidth]/2 + BP[BatteryPack_Const_BDia]/2,
    BP[BatteryPack_Const_PDepth]/2 + BP[BatteryPack_Const_BDia]/2,
    BP[BatteryPack_Const_PHeight]/2,
  ],
  [ 0,0,0 ],
  0, 0, 0
];

// We have the total battery length, assume the positive terminal is 1/20th of the length
module battery(BP) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];

  button_h = (1/20)*Battery_len;
  top_h = (1/3)*Battery_len;
  bottom_h = Battery_len-(top_h+button_h);

  color("black")
  linear_extrude(height=bottom_h)
    circle(r=Battery_dia/2);

  color("red")
  translate([0, 0, bottom_h])
    linear_extrude(height=top_h)
      circle(r=Battery_dia/2);

  color(MetalColor)
  translate([0, 0, bottom_h+top_h])
    linear_extrude(height=button_h)
      circle(r=Battery_dia/4);

}

module battery_pack_linear(BP, battery_sep, battery_count) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];

  for(i=[0:battery_count-1]) {
    translate([i*(Battery_dia+battery_sep), 0, 0])
      if(i % 2 == 1) {
        translate([0,0,Battery_len/2])
          rotate([180, 0, 0])
            translate([0,0,-Battery_len/2])
              battery(BP);
      } else {
        battery(BP);
      }
  }
}

module battery_pack_double(BP, battery_sep, battery_count) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];

  for(i=[0:(battery_count/2)-1]) {
    translate([i*(Battery_dia+battery_sep), 0, 0])
      battery(BP);
    translate([i*(Battery_dia+battery_sep), Battery_dia+battery_sep, 0])
      translate([0,0,Battery_len/2])
        rotate([180, 0, 0])
          translate([0,0,-Battery_len/2])
            battery(BP);
  }
}

// NB, This completely ignores battery count/linear setting! 2x2 is what you get!
module BatteryPack(BP) {

  Battery_len = BP[BatteryPack_Const_BLen];
  Battery_dia = BP[BatteryPack_Const_BDia];
  BatteryPack_height = BP[BatteryPack_Const_PHeight];
  BatteryPack_width = BP[BatteryPack_Const_PWidth];
  BatteryPack_depth = BP[BatteryPack_Const_PDepth];

  // Actually measured, it overhangs by 2mm, 1 because this is actually
  // a radius -- how far is the center-line of the battery offset from the edge
  // of the case (in the y direction).
  battery_depth_offset = Battery_dia/2 - 1;

  render()
  translate([-Battery_dia/2, -Battery_dia/2,0])
  difference() {
   linear_extrude(height=BatteryPack_height)
     hull() {
      // Main body
      translate([Battery_dia/2, Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([BatteryPack_width-Battery_dia/2, Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([Battery_dia/2, BatteryPack_depth-Battery_dia/2, 0])
        circle(r=Battery_dia/2);
      translate([BatteryPack_width-Battery_dia/2, BatteryPack_depth-Battery_dia/2, 0])
        circle(r=Battery_dia/2);
   }

   // Subtract battery shapes
   translate([Battery_dia/2-eta, battery_depth_offset-eta, (BatteryPack_height-Battery_len)/2])
     cylinder(h=Battery_len, r=Battery_dia/2);

   translate([BatteryPack_width-Battery_dia/2+eta, battery_depth_offset-eta, (BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);

   translate([Battery_dia/2-eta, BatteryPack_depth-battery_depth_offset+eta, (BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);
   translate([BatteryPack_width-Battery_dia/2+eta,BatteryPack_depth-battery_depth_offset+eta,(BatteryPack_height-Battery_len)/2])
    cylinder(h=Battery_len, r=Battery_dia/2);

   translate([BatteryPack_width/4,-BatteryPack_depth+6,(BatteryPack_height-Battery_len)/2])
     cube([BatteryPack_width/2, BatteryPack_depth, Battery_len]);
   translate([BatteryPack_width/4,BatteryPack_depth-6,(BatteryPack_height-Battery_len)/2])
     cube([BatteryPack_width/2, BatteryPack_depth, Battery_len]);

 }
}

*battery_pack_linear(BatteryPack_AA, 2,4);
*battery_pack_double(BatteryPack_AA, 2, 4);
*battery(BatteryPack_AA);
BatteryPack(BatteryPack_AA);


more details on hinges, plans for bushing at axle

// try to draw Jansen linkage leg assembly as it might appear in steel

// these are for configuration "E" as referenced in other drawings
AC=17.5;
Ay =  3.318; Bx = 53.833;
BD = 48.020; BE = 46.977; BH = 40.359;
CD = 59.635; CH = 71.441; DE = 66.437;
EF = 47.467; FG = 75.792;
FH = 40.843; GH = 55.790;

DEleft = (DE*DE + BD*BD - BE*BE)/(2*DE);
FGleft = (FG*FG + FH*FH - GH*GH)/(2*FG);
DEperp = sqrt(BD*BD - DEleft*DEleft);
FGperp = sqrt(FH*FH - FGleft*FGleft);

echo(str("DEleft=",DEleft,"   DEperp=",DEperp));
echo(str("FGleft=",FGleft,"   FGperp=",FGperp));

//r38 = (3/8)*2.54/2;  // radius of 3/8" bolt

a=360*$t;
legAssembly(a,0);
mirror([1,0,0]) legAssembly(180-a,1.4);

//  -------------------------- crank-arm circle reference
%color([1,.5,.3,.4]) translate([0,Ay,-2]) difference() {
  cylinder(r=AC,h=1,$fn=48,center=true);
  cylinder(r=2,h=2,center=true);
}
color([0.3,.3,1,.7]) // axles
for(x=[-1,1]) translate([x*Bx,0,0]) difference() {
   cylinder(r=2.54/2,h=20,$fn=24,center=true);
   cylinder(r=2.54/2-.4,h=22,$fn=19,center=true);
}

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

// -----------------------------------------------------------------

// plot a link shadow, a different way, to check kinematic correctness
module checkLink(xa,ya,xb,yb,ab) {
  *translate([(xa+xb)/2,(ya+yb)/2,-9])
    rotate([0,0,atan2(yb-ya,xb-xa)]) cube([ab,1,1],center=true);
}

function triK1(ax,ay,ca,bx,by,cb) = (cb*cb - ca*ca + ax*ax -bx*bx +ay*ay -by*by)/(2*(ax-bx));

// ===================================================================

module legAssembly(ang=0,linkOffset=0) {

// solve kinematics for given crank angle
xC = AC*cos(ang);
yC = AC*sin(ang)+Ay;
echo("C",xC,yC);

k1=(yC*yC - Bx*Bx + BD*BD - CD*CD + xC*xC)/(2*yC);
k2=(xC+Bx)/yC;
c=k1*k1-BD*BD+Bx*Bx;
b=2*(Bx-k1*k2);
a=k2*k2+1;
sgnD=(yC<0)?1:-1;
xD=(-b+sgnD*sqrt(b*b-4*a*c))/(2*a);
yD=sqrt(BD*BD - pow(xD+Bx,2));
echo("D",xD,yD,"CD err",sqrt(pow(xC-xD,2)+pow(yC-yD,2))-CD);

hipRot = atan2(yD,Bx+xD)-atan2(DEperp,DEleft);
echo("hipRot",hipRot);
xE = cos(hipRot) * (DEleft-DE) - sin(hipRot) * DEperp - Bx;
yE = sin(hipRot) * (DEleft-DE) + cos(hipRot) * DEperp;
/*
ke1=(yD*yD + xD*xD + DE*DE + BE*BE)/(2*yD);
ke2=(xD+Bx)/yD;
ae=2+ke2*ke2;
be=2*(Bx-ke1*ke2);
ce=ke1*ke1 - BE*BE +Bx*Bx;
echo("E abc:",ae,be,ce);
xE=(-be+sqrt(be*be-4*ae*ce))/(2*ae);
yE=sqrt(BE*BE - pow(xE+Bx,2));
*/
echo("E",xE,yE);

k1h=(xC*xC + yC*yC + BH*BH - CH*CH - Bx*Bx)/(2*yC);
k2h=-(xC+Bx)/yC;
ah=k2h*k2h+1;
bh=2*(k1h*k2h + Bx);
ch=k1h*k1h + Bx*Bx - BH*BH;
sgnH=(yC>0)?1:-1;
xH=(-bh+sgnH*sqrt(bh*bh-4*ah*ch))/(2*ah);
yH=-sqrt(BH*BH - pow(xH+Bx,2));
bhRot=atan2(yH,xH+Bx);
echo("H",xH,yH,"rot",bhRot,"CH err",sqrt(pow(xH-xC,2)+pow(yH-yC,2))-CH);

/*
k1f=(FH*FH - EF*EF - yE*yE - yH*yH + xE*xE - xH*xH) / (2*(yE-yH));
k2f=(xH-xE)/(yE-yH);
af=k2f*k2f+1;
bf=2*(k1f*k2f - xH - k2f*yH);
cf=xH*xH + yH*yH - 2*k1f*yH + k1f*k1f - FH*FH;
xF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
yF=k1f+k2f*xF;
*/
k2f = (yE-yH)/(xE-xH);
k1f = triK1(xE,yE,EF,xH,yH,FH);
af=k2f*k2f+1;
bf=2*(k2f*xE - k1f*k2f -yE);
cf=k1f*k1f - 2*k1f*xE + xE*xE + yE*yE - EF*EF;
yF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
xF=k1f-k2f*yF;
echo("F",xF,yF,"EF err",sqrt(pow(xF-xE,2)+pow(yF-yE,2))-EF);
echo("FH err",sqrt(pow(xF-xH,2)+pow(yF-yH,2))-FH);

// draw the hip so that the main "plane", the ED centerline plane, is at z=0
translate([-Bx,0,0]) rotate([0,0,hipRot])
    translate([DEleft-DE,DEperp,0]) hip();
//translate([-Bx,0,2.5]) rotate([0,0,12.5]) translate([-DEleft,DEperp,0]) hip();
//translate([ Bx,0,0]) rotate([0,0,-20]) translate([DE-DEleft,DEperp,0]) mirror([1,0,0])
//  hip();
checkLink(-Bx,0,xD,yD,BD);
checkLink(-Bx,0,xE,yE,BE);
checkLink(xD,yD,xE,yE,DE);

translate([-Bx,0,0]) rotate([0,0,bhRot])
   BHlinks();
checkLink(-Bx,0,xH,yH,BH);

//------------------------------------------------------- CrankLinks
translate([xC,yC,linkOffset-.6]) rotate([0,0,atan2(yD-yC,xD-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CD);
checkLink(xC,yC,xD,yD,CD);

translate([xC,yC,linkOffset+2.2]) rotate([0,0,atan2(yH-yC,xH-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CH);
checkLink(xC,yC,xH,yH,CH);

translate([xF,yF,0]) rotate([0,0,atan2(yE-yF,xE-xF)]) EFlink();
checkLink(xE,yE,xF,yF,EF);

footRot = atan2(yH-yF,xH-xF)-atan2(FGperp,FGleft);
translate([xF,yF,0]) rotate([0,0,footRot])
   foot();
checkLink(xF,yF,xH,yH,FH);

} // end module legAssembly()

// include includes whole text.
// use just imports modules
use <util.scad>

// -----------------------------------------------------------------

module foot() {
  hull() {  // FG
    translate([4,0,.2]) cube([4,2.5,2.5],center=true);
    translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.6,$fn=24,center=true);
  }

  // knee braces/fork
  for (z=[-1.3,7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for knee
      //translate([-5,2,1.5*z])scale([3,5,1])cylinder(r=1,h=.4,$fn=64,center=true);
      // wider knee shouldn't need brace
      translate([0,0,z]) cylinder(r=2.5,h=.4,$fn=24,center=true);
      translate([9,0,z])cylinder(r=1,h=.4,center=true);
    }
    cylinder(r=.4,h=22,$fn=17,center=true);
  }

  // hinge holders at H
  %color([0,0,.6,.4])
  translate([FGleft,FGperp,-1]) difference() {
    cylinder(r=2.54/2,h=7,$fn=36);

    cylinder(r=1.9/2,h=22,center=true,$fn=24);
    translate([0,0,3.9])cube([3,3,2.8],center=true);
  }
  translate([FGleft,FGperp,-.87]) {
    rotate([180,0,0]) F698();
    translate([0,0,5.3]) rotate([180,0,0]) F698();
    translate([0,0,2.24]) F698();
    translate([0,0,6.74]) F698();
  }

  // vertical brace extension at knee
  translate([3.5,0,4.1]) cube([2.6,2.6,5.3],center=true);
  hull() {  // gusset
    translate([ 5.5,-1,1]) cylinder(r=.2,h=5.8,$fn=8);
    translate([18, 1,0]) cylinder(r=.3,h=1  ,$fn=8);
  }

  // FH segment bracing
  for (z=[-.3,5.1]) hull() {
    translate([   3    ,   1    ,z]) sphere(.8);
    translate([FGleft-1,FGperp-1,z]) sphere(.8);
  }
  hull() {  // dig brace.  Could be gusset?
      translate([3,1,5.7]) sphere(.8);
      translate([12,11,-.3]) sphere(.8);
  }
  translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  hull() {
      translate([FGleft-7.2,FGperp-8,5.3]) sphere(.8);
      translate([14,13.5,-.3]) sphere(.8);
  }

  // GH braces
  hull() {
      translate([FG-8,0,-.3]) sphere(.8);
      translate([FGleft+1,FGperp-1,-.3]) sphere(.8);
  }
  hull() {
      translate([FG-10,0,0]) sphere(.8);
      translate([FGleft+1,FGperp-1,5.2]) sphere(.8);
  }

  hull() {    // perp brace
      translate([FGleft,FGperp-1,5.2]) sphere(.8);
      translate([FGleft,0,0]) sphere(.8);
  }
  hull() {    // perp brace
      translate([FGleft,FGperp-1,-.3]) sphere(.8);
      translate([FGleft,0,-.3]) sphere(.8);
  }

  // extra truss braces
  hull() {
      translate([46,15,3]) sphere(.8);
      translate([35, 0,0]) sphere(.8);
  }
  translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
  translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
}

$fn=12;
module hip() {
  translate([DE/2,0,-.2]) cube([DE-5,2.5,2.5],center=true); // top tube
  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     cylinder(r=2.54*1.5/2,h=7.2,$fn=36); // axle
     cylinder(r=2.54*1.5/2-.3,h=22,$fn=18,center=true);
  }

  // top tube fork plates
  translate([DE,0,0]) mirror([1,0,0]) eFork();
                                      eFork();

  hull() {  // diag tubes
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([8,0,0]) sphere(.8);
  }
  hull() {
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([DE-8,0,0]) sphere(.8);
  }

  // extra bracing
  translate([DE/2,-20,0]) rotate([0,90,0]) cylinder(r=.8,h=20,center=true);
  translate([DE-DEleft,-DEperp,5]) rotate([-110,0,0]) cylinder(r=.8,h=14.4);
}

module eFork() for(z=[-1,1]) difference() {
  hull() {
    translate([0,0,1.4*z]) cylinder(r=2,h=.3,$fn=24,center=true);
    translate([6,0,1.4*z]) cube([1,2,.3],center=true);
  }
  cylinder(r=.4,h=11,$fn=17,center=true);
}

module crankLink(dx=CD) {
  %color([0,0,.6,.4]) difference() {
    cylinder(r=2.54/2,h=1,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .36]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.36]) rotate([180,0,0]) F698();

  //translate([dx/2-1,0,0]) cube([dx-3,1.3,1.3],center=true);
  %color([0,.8,0,.6])
  translate([dx/2-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3,$fn=11,center=true);

  translate([dx,0,0]) SA8();
}

module EFlink() {
  translate([EF,0,0]) SA8();
  translate([EF/2-.4,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3,$fn=13,center=true);

    // ------ tube and knee bearings
    %color([0,0,.6,.4])
    translate([0,0,-.84]) difference() {
       cylinder(r=2.54/2,h=2.54*3-.25,$fn=36);
       cylinder(r=2.54/2-.3,h=22,$fn=36,center=true);
    }
    translate([0,0,6.41]) F698();
    translate([0,0,-.7]) rotate([180,0,0]) F698();

    hull() {  // gusset
      translate([1.3,0,2*2.54/2]) cylinder(r=.2,h=2.54*3,$fn=12,center=true);
      translate([9,0,   0    ]) cylinder(r=.2,h=1,$fn=12);
    }

  //translate([EF,0,0]) cylinder(r=r38,h=5,center=true);
    //                //cylinder(r=r38,h=55,center=true);
  //cylinder(r=1.2,h=22,$fn=36,center=true);
}

// this link drawn with B axle at origin, always.
module BHlinks() {
  difference() {  // main axle rings
    translate([0,0,2.4]) cylinder(r=2.54*1.5/2,h=13.5,$fn=36,center=true);
    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=2.54*1.5/2-.3,h=22,$fn=19,center=true);
  }

  // brace near axle
  translate([3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);
  // fork brace
  translate([BH-7,0,2.43]) cube([2.5,2.5,7.6],center=true);

  for(z=[-2.4,7.2]) {
     hull() {
       translate([BH-6,0,z]) sphere(.8);
       translate([   0,0,z]) sphere(.8);
     }
  }

  hull() {
    translate([   4,.7,-1.6]) sphere(.8);
    translate([BH-9,.7, 6.2]) sphere(.8);
  }
  hull() {
    translate([   4,-.7, 6.2]) sphere(.8);
    translate([BH-9,-.7,-1.6]) sphere(.8);
  }

  // H forks
  for(z=[-1.7,6.2]) translate([BH,0,z]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}
module BHlinks1() {
  translate([0,0, 6.8])                 BHlink();
  translate([0,0,-2  ]) mirror([0,0,1]) BHlink();
}
module BHlink() {
  cylinder(r=1.4,h=6,$fn=24);

  //%translate([BH/2-1,0,1.3]) cube([BH-2,2.5,2.5],center=true);
  for (q=[-1,1]) hull() {
    translate([  0 ,1.5*q,1]) sphere(0.8);
    translate([BH-3,1  *q,1]) sphere(0.8);
  }
  hull() {
    translate([  0 ,0,5]) sphere(0.8);
    translate([BH-3,0,1]) sphere(0.8);
  }

  translate([BH,0,-.3]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }
}

// try to draw Jansen linkage leg assembly as it might appear in steel

// these are for configuration "E" as referenced in other drawings
AC=17.5;
Ay =  3.318; Bx = 53.833;
BD = 48.020; BE = 46.977; BH = 40.359;
CD = 59.635; CH = 71.441; DE = 66.437;
EF = 47.467; FG = 75.792;
FH = 40.843; GH = 55.790;

DEleft = (DE*DE + BD*BD - BE*BE)/(2*DE);
FGleft = (FG*FG + FH*FH - GH*GH)/(2*FG);
DEperp = sqrt(BD*BD - DEleft*DEleft);
FGperp = sqrt(FH*FH - FGleft*FGleft);

echo(str("DEleft=",DEleft,"   DEperp=",DEperp));
echo(str("FGleft=",FGleft,"   FGperp=",FGperp));

//r38 = (3/8)*2.54/2;  // radius of 3/8" bolt

a=360*$t;
legAssembly(a,0);
mirror([1,0,0]) legAssembly(180-a,1.4);
//legAssembly(100);

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

// -----------------------------------------------------------------

// plot a link shadow, a different way, to check kinematic correctness
module checkLink(xa,ya,xb,yb,ab) {
  *translate([(xa+xb)/2,(ya+yb)/2,-9])
    rotate([0,0,atan2(yb-ya,xb-xa)]) cube([ab,1,1],center=true);
}

function triK1(ax,ay,ca,bx,by,cb) = (cb*cb - ca*ca + ax*ax -bx*bx +ay*ay -by*by)/(2*(ax-bx));

// ===================================================================

module legAssembly(ang=0,linkOffset=0) {

// solve kinematics for given crank angle
xC = AC*cos(ang);
yC = AC*sin(ang)+Ay;
echo("C",xC,yC);

k1=(yC*yC - Bx*Bx + BD*BD - CD*CD + xC*xC)/(2*yC);
k2=(xC+Bx)/yC;
c=k1*k1-BD*BD+Bx*Bx;
b=2*(Bx-k1*k2);
a=k2*k2+1;
sgnD=(yC<0)?1:-1;
xD=(-b+sgnD*sqrt(b*b-4*a*c))/(2*a);
yD=sqrt(BD*BD - pow(xD+Bx,2));
echo("D",xD,yD,"CD err",sqrt(pow(xC-xD,2)+pow(yC-yD,2))-CD);

hipRot = atan2(yD,Bx+xD)-atan2(DEperp,DEleft);
echo("hipRot",hipRot);
xE = cos(hipRot) * (DEleft-DE) - sin(hipRot) * DEperp - Bx;
yE = sin(hipRot) * (DEleft-DE) + cos(hipRot) * DEperp;
/*
ke1=(yD*yD + xD*xD + DE*DE + BE*BE)/(2*yD);
ke2=(xD+Bx)/yD;
ae=2+ke2*ke2;
be=2*(Bx-ke1*ke2);
ce=ke1*ke1 - BE*BE +Bx*Bx;
echo("E abc:",ae,be,ce);
xE=(-be+sqrt(be*be-4*ae*ce))/(2*ae);
yE=sqrt(BE*BE - pow(xE+Bx,2));
*/
echo("E",xE,yE);

k1h=(xC*xC + yC*yC + BH*BH - CH*CH - Bx*Bx)/(2*yC);
k2h=-(xC+Bx)/yC;
ah=k2h*k2h+1;
bh=2*(k1h*k2h + Bx);
ch=k1h*k1h + Bx*Bx - BH*BH;
sgnH=(yC>0)?1:-1;
xH=(-bh+sgnH*sqrt(bh*bh-4*ah*ch))/(2*ah);
yH=-sqrt(BH*BH - pow(xH+Bx,2));
bhRot=atan2(yH,xH+Bx);
echo("H",xH,yH,"rot",bhRot,"CH err",sqrt(pow(xH-xC,2)+pow(yH-yC,2))-CH);

/*
k1f=(FH*FH - EF*EF - yE*yE - yH*yH + xE*xE - xH*xH) / (2*(yE-yH));
k2f=(xH-xE)/(yE-yH);
af=k2f*k2f+1;
bf=2*(k1f*k2f - xH - k2f*yH);
cf=xH*xH + yH*yH - 2*k1f*yH + k1f*k1f - FH*FH;
xF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
yF=k1f+k2f*xF;
*/
k2f = (yE-yH)/(xE-xH);
k1f = triK1(xE,yE,EF,xH,yH,FH);
af=k2f*k2f+1;
bf=2*(k2f*xE - k1f*k2f -yE);
cf=k1f*k1f - 2*k1f*xE + xE*xE + yE*yE - EF*EF;
yF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
xF=k1f-k2f*yF;
echo("F",xF,yF,"EF err",sqrt(pow(xF-xE,2)+pow(yF-yE,2))-EF);
echo("FH err",sqrt(pow(xF-xH,2)+pow(yF-yH,2))-FH);

//  -------------------------- crank-arm circle reference
%color([1,.5,.3,.2]) translate([0,Ay,-2]) difference() {
  cylinder(r=AC,h=1,$fn=48,center=true);
  cylinder(r=2,h=2,center=true);
}

// draw the hip so that the main "plane", the ED centerline plane, is at z=0
translate([-Bx,0,0]) rotate([0,0,hipRot])
    translate([DEleft-DE,DEperp,0]) hip();
//translate([-Bx,0,2.5]) rotate([0,0,12.5]) translate([-DEleft,DEperp,0]) hip();
//translate([ Bx,0,0]) rotate([0,0,-20]) translate([DE-DEleft,DEperp,0]) mirror([1,0,0])
//  hip();
checkLink(-Bx,0,xD,yD,BD);
checkLink(-Bx,0,xE,yE,BE);
checkLink(xD,yD,xE,yE,DE);

translate([-Bx,0,0]) rotate([0,0,bhRot])
   BHlinks();
checkLink(-Bx,0,xH,yH,BH);

//------------------------------------------------------- CrankLinks
translate([xC,yC,linkOffset-.6]) rotate([0,0,atan2(yD-yC,xD-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CD);
checkLink(xC,yC,xD,yD,CD);

translate([xC,yC,linkOffset+2.2]) rotate([0,0,atan2(yH-yC,xH-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CH);
checkLink(xC,yC,xH,yH,CH);

translate([xF,yF,0]) rotate([0,0,atan2(yE-yF,xE-xF)]) EFlink();
checkLink(xE,yE,xF,yF,EF);

footRot = atan2(yH-yF,xH-xF)-atan2(FGperp,FGleft);
translate([xF,yF,0]) rotate([0,0,footRot])
   foot();
checkLink(xF,yF,xH,yH,FH);

} // end module legAssembly()

// include includes whole text.
// use just imports modules
use <util.scad>

// -----------------------------------------------------------------

module foot() {
  hull() {  // FG
    translate([4,0,.2]) cube([4,2.5,2.5],center=true);
    translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.6,$fn=24,center=true);
  }

  // knee braces/fork
  for (z=[-1.3,7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for knee
      //translate([-5,2,1.5*z])scale([3,5,1])cylinder(r=1,h=.4,$fn=64,center=true);
      // wider knee shouldn't need brace
      translate([0,0,z]) cylinder(r=2.5,h=.4,$fn=24,center=true);
      translate([9,0,z])cylinder(r=1,h=.4,center=true);
    }
    cylinder(r=.4,h=22,$fn=17,center=true);
  }

  // hinge holders at H
  translate([FGleft,FGperp,-1]) difference() {
    cylinder(r=2.54/2,h=7,$fn=36);

    cylinder(r=1.9/2,h=22,center=true,$fn=24);
    translate([0,0,3.9])cube([3,3,2.8],center=true);
  }

  // vertical brace extension at knee
  translate([3.5,0,4.1]) cube([2.6,2.6,5.3],center=true);
  hull() {  // gusset
    translate([ 5.5,-1,1]) cylinder(r=.2,h=5.8,$fn=8);
    translate([18, 1,0]) cylinder(r=.3,h=1  ,$fn=8);
  }

  // FH segment bracing
  for (z=[-.3,5.3]) hull() {
    translate([   3    ,   1    ,z]) sphere(.8);
    translate([FGleft-1,FGperp-1,z]) sphere(.8);
  }
  hull() {  // dig brace.  Could be gusset?
      translate([3,1,5.7]) sphere(.8);
      translate([12,11,-.3]) sphere(.8);
  }
  translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  hull() {
      translate([FGleft-7.2,FGperp-8,5.3]) sphere(.8);
      translate([14,13.5,-.3]) sphere(.8);
  }

  // GH braces
  hull() {
      translate([FG-8,0,-.3]) sphere(.8);
      translate([FGleft+1,FGperp-1,-.3]) sphere(.8);
  }
  hull() {
      translate([FG-10,0,0]) sphere(.8);
      translate([FGleft+1,FGperp-1,5.8]) sphere(.8);
  }

  hull() {    // perp brace
      translate([FGleft,FGperp-1,5.7]) sphere(.8);
      translate([FGleft,0,0]) sphere(.8);
  }
  hull() {    // perp brace
      translate([FGleft,FGperp-1,-.3]) sphere(.8);
      translate([FGleft,0,-.3]) sphere(.8);
  }

  // extra truss braces
  hull() {
      translate([46,15,3]) sphere(.8);
      translate([35, 0,0]) sphere(.8);
  }
  translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
  translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
}

$fn=12;
module hip() {
  translate([DE/2,0,-.2]) cube([DE-5,2.5,2.5],center=true); // top tube
  translate([DE-DEleft,-DEperp,-1.2]) cylinder(r=1.4,h=7.2,$fn=36); // axle

  // top tube fork plates
  translate([DE,0,0]) mirror([1,0,0]) eFork();
                                      eFork();

  hull() {  // diag tubes
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([8,0,0]) sphere(.8);
  }
  hull() {
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([DE-8,0,0]) sphere(.8);
  }

  // extra bracing
  translate([DE/2,-20,0]) rotate([0,90,0]) cylinder(r=.8,h=20,center=true);
  translate([DE-DEleft,-DEperp,4]) rotate([-105,0,0]) cylinder(r=.8,h=14);
}

module eFork() for(z=[-1,1]) difference() {
  hull() {
    translate([0,0,1.4*z]) cylinder(r=2,h=.3,$fn=24,center=true);
    translate([6,0,1.4*z]) cube([1,2,.3],center=true);
  }
  cylinder(r=.4,h=11,$fn=17,center=true);
}

module crankLink(dx=CD) {
  %color([0,0,.6,.4]) difference() {
    cylinder(r=2.54/2,h=1,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .36]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.36]) rotate([180,0,0]) F698();

  //translate([dx/2-1,0,0]) cube([dx-3,1.3,1.3],center=true);
  %color([0,.8,0,.6])
  translate([dx/2-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3,$fn=11,center=true);

  translate([dx,0,0]) SA8();
}

module EFlink() {
  translate([EF,0,0]) SA8();
  translate([EF/2-.4,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3,$fn=13,center=true);

    // ------ tube and knee bearings
    %color([0,0,.6,.4])
    translate([0,0,2*2.54/2]) difference() {
       cylinder(r=2.54/2,h=2.54*3,$fn=36,center=true);
       cylinder(r=2.54/2-.3,h=9,$fn=36,center=true);
    }
    translate([0,0,6.22]) F698();
    translate([0,0,-1.14]) rotate([180,0,0]) F698();

    hull() {  // gusset
      translate([1.3,0,2*2.54/2]) cylinder(r=.2,h=2.54*3,$fn=12,center=true);
      translate([9,0,   0    ]) cylinder(r=.2,h=1,$fn=12);
    }

  //translate([EF,0,0]) cylinder(r=r38,h=5,center=true);
    //                //cylinder(r=r38,h=55,center=true);
  //cylinder(r=1.2,h=22,$fn=36,center=true);
}

// this link drawn with B axle at origin, always.
module BHlinks() {
  difference() {
    translate([0,0,2.4]) cylinder(r=1.4,h=13.5,$fn=36,center=true);
    translate([0,0,2.4]) cube([4,4,7.9],center=true);
  }

  for(z=[-2.4,7.2]) {
     hull() {
       translate([BH-3,0,z]) sphere(.8);
       translate([   0,0,z]) sphere(.8);
     }
  }

  hull() {
    translate([   4,0.5,-2.4]) sphere(.8);
    translate([BH-5,1, 6  ]) sphere(.8);
  }
  hull() {
    translate([   4,-.5, 7]) sphere(.8);
    translate([BH-5, -1, -2  ]) sphere(.8);
  }

  for(z=[-1.7,6.2]) translate([BH,0,z]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }

}
module BHlinks1() {
  translate([0,0, 6.8])                 BHlink();
  translate([0,0,-2  ]) mirror([0,0,1]) BHlink();
}
module BHlink() {
  cylinder(r=1.4,h=6,$fn=24);

  //%translate([BH/2-1,0,1.3]) cube([BH-2,2.5,2.5],center=true);
  for (q=[-1,1]) hull() {
    translate([  0 ,1.5*q,1]) sphere(0.8);
    translate([BH-3,1  *q,1]) sphere(0.8);
  }
  hull() {
    translate([  0 ,0,5]) sphere(0.8);
    translate([BH-3,0,1]) sphere(0.8);
  }

  translate([BH,0,-.3]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }
}


New iterations

New iterations

tube_diameter = 28;
margin = 1 ;
thickness	    =1;
width = 15;
beam_size = 10;
beam_thickness = 5;

clip_width=10;
difference(){
union(){
union(){
rotate([90,0,0]) cylinder(r=tube_diameter/2+thickness+margin, h = width, center=true);
translate([0, 0, beam_thickness]) cube(size=[beam_size+2*thickness, width, tube_diameter+2*thickness], center = true);
}

translate([0, width/2-(width-clip_width)/4, 0]) hull(){
rotate([90,0,0]) cylinder(r=tube_diameter/2+thickness+margin+1, h = (width-clip_width)/2, center=true);
translate([0, 0, beam_thickness+1]) cube(size=[beam_size+2*thickness, (width-clip_width)/2, tube_diameter+2*thickness], center = true);
}
translate([0, -width/2+(width-clip_width)/4, 0]) hull(){
rotate([90,0,0]) cylinder(r=tube_diameter/2+thickness+margin+1, h = (width-clip_width)/2, center=true);
translate([0, 0, beam_thickness+1]) cube(size=[beam_size+2*thickness, (width-clip_width)/2, tube_diameter+2*thickness], center = true);
}
}
translate([0, 0, tube_diameter/2+thickness*2+beam_thickness/2+1]) cube(size=[beam_size, 2*width, beam_thickness+2], center = true);
rotate([90,0,0]) cylinder(r=tube_diameter/2+margin, h = 2*width, center=true);
translate([0, 0, -tube_diameter*5/8]) cube(size=[2*tube_diameter, 2*width, tube_diameter*2], center=true);

}

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


Correct rear panel

Correct rear panel

use <Suwako/DXFImport.scad>

display_dxf = "../Kanako/Displays/eBay_7inch_TFT.dxf";
rx_dxf = "../Kanako/Modules/RC832_5.8ghz_video_RX.dxf";

module DisplayCutout()
{
  projection()
    DXFImport(display_dxf, subtraction_layers=["TFT_Cutout"]);
}

module DisplayMountingHoles()
{
  projection()
    DXFImport(display_dxf, subtraction_layers=["TFT_MountingHoles"]);
}

module RX()
{
  projection()
    DXFImport(rx_dxf, subtraction_layers=["RX_Cutouts"]);
}

module RX_MountingHoles()
{
  hole_diam = 3.5;

  translate([-40,  20]) circle(d=hole_diam);
  translate([-40, -20]) circle(d=hole_diam);
  translate([ 40,  20]) circle(d=hole_diam);
  translate([ 40, -20]) circle(d=hole_diam);
  translate([ 15, -50]) circle(d=hole_diam);
  translate([-15, -50]) circle(d=hole_diam);
}

use <Suwako/DXFImport.scad>

display_dxf = "../Kanako/Displays/eBay_7inch_TFT.dxf";
rx_dxf = "../Kanako/Modules/RC832_5.8ghz_video_RX.dxf";

module DisplayCutout()
{
  projection()
    DXFImport(display_dxf, subtraction_layers=["TFT_Cutout"]);
}

module DisplayMountingHoles()
{
  projection()
    DXFImport(display_dxf, subtraction_layers=["TFT_MountingHoles"]);
}

module RX()
{
  projection()
    DXFImport(rx_dxf, subtraction_layers=["RX_Cutouts", "RX_Case"]);
}

module RX_MountingHoles()
{
  hole_diam = 3.5;

  translate([-40,  20]) circle(d=hole_diam);
  translate([-40, -20]) circle(d=hole_diam);
  translate([ 40,  20]) circle(d=hole_diam);
  translate([ 40, -20]) circle(d=hole_diam);
  translate([ 15, -50]) circle(d=hole_diam);
  translate([-15, -50]) circle(d=hole_diam);
}


ring created

ring created

2d and 3d

//2D
module ring(r=5,d=1) {
	difference() {
		circle(r=r);
		circle(r=r-d);
	}
}
//3D
module ring(r=5,d=1,h=2) {
	difference() {
		cylinder(r=r,h=h);
		cylinder(r=r-d,h=h);
	}
}

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


Tidy up and simplify some positioning

Tidy up and simplify some positioning

/* Pins required -

pintack(side=true, h=7.8+2+2.5, bh=2);

*/

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

		color(Level2PlasticColor) {
			if (UseSTL) {
				import(str(STLPath, "Bumper.stl"));
			} else {
				BumperModel();
			}
		}
	}
}

module BumperModel()
{
	// Parameters
	thickness = dw;				// bumper thickness
	height = 15;				// bumper height
	offset = 5;					// distance from base to inside of bumper
	wrapAngle = 170;			// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	bumpstopWidth = 8;			// width of little block that sticks out to hit the microswitch
	bumpstopHeight = 5;			// height of little block that sticks out to hit the microswitch

	// Calculated parameters
	outr = BaseDiameter/2 + offset + thickness;		// outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate([0, 0, wrapAngle/2])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate([0, 0, -wrapAngle/2])
			square([outr, outr * 2]);
	}

	// Connectors
	for(i=[0, 1])
	mirror([i, 0, 0])
	rotate([0, 0, microSwitchAngle]) {

		// Springy bits
		translate([15, BaseDiameter/2 - 11, 0])
		rotate([0, 0, -130])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175);

		// Bumpstops to hit microwitch arm
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([bumpstopWidth, offset + 1 , bumpstopHeight]);

		// Microswitch plates
		translate([-10, BaseDiameter/2 - 23, 0])
			MicroSwitchPlate();
	}
}

module MicroSwitchPlate()
{
	// Parameters - todo: pickup from microswitch model?
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Rear support lozenge with pin hole
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		// Actual hole
		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0, 0, dw])
		mirror([0, 0, 1])
			pinhole(fixed=true);
	}
}

/* Pins required -

pintack(side=true, h=7.8+2+2.5, bh=2);

*/

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

	    color(Level2PlasticColor) {
            if (UseSTL) {
                import(str(STLPath, "Bumper.stl"));
            } else {
				BumperModel();
            }
        }
	}
}

module BumperModel()
{
	// Parameters
	thickness = dw;				// bumper thickness
	height = 15;				// bumper height
	offset = 5;					// distance from base to inside of bumper
	wrapAngle = 170;			// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	// Calculated parameters
	outr = BaseDiameter/2 + offset + thickness;		// outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate([0, 0, wrapAngle/2])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate([0, 0, -wrapAngle/2])
			square([outr, outr * 2]);
	}

	// Springy bits
	for(i=[0, 1])
		mirror([i, 0, 0])
		translate([30, outr - 24, 0])
		rotate([0, 0, 90])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175, center=true);

	// Flanges to hit microwitch
	for(i=[0, 1])
		mirror([i, 0, 0])
		rotate([0, 0, microSwitchAngle])
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([8, offset + 1 + eta, 5]);

	// Microswitch plates
	for(i=[0, 1])
		mirror([i, 0, 0])
		rotate([0, 0, microSwitchAngle])
		translate([-10, BaseDiameter/2 - 23, 0])
			MicroSwitchPlate();
}

module MicroSwitchPlate()
{
	// Parameters - todo: pickup from microswitch model?
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Rear support lozenge with pin hole
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		// Actual hole
		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0, 0, dw])
		mirror([0, 0, 1])
			pinhole(fixed=true);
	}
}


Added Malcolm's motor.scad file to the repo

motor_shaft_r=5;
motor_shaft_h=8;
motor_flange_h = 1;
motor_flange_r = 9.20;
Motor_body_r = 28.00;
Motor_body_h = 19.30;

	///rotate object around to Y access
	rotate([90,0,0]){
	// shaft
		color("grey")
	cylinder(r=motor_shaft_r, h=motor_shaft_h, center=true);
		//flange
		translate([0,0,motor_shaft_h/2])
			color("yellow")
			cylinder(r=motor_flange_r, h=motor_flange_h, center=true);
			// Main Body
				translate([0,-15,14])///don't understand this
					color("silver")
			cylinder(r=Motor_body_r, h=Motor_body_h, center=true);
				//Flanges
					translate([35,-15,4.5]){///don't understand this

					cylinder(r=7, h=1);
							translate([-14,-7,0]){
								cube([14.5,14,1]);
							}
					color("white")
					cylinder(r=4, h=1);

					}
					translate([-35,-15,4.5]){///don't understand this

					cylinder(r=7, h=1);
						translate([0,-7,0]){
								cube([14.5,14,1]);
							}

								color("white")
					cylinder(r=4, h=1);

							}
				  //bottom
				color("blue")
				 translate([0-7,-46,4])
					  cube([14.5,5.5,Motor_body_h]);

}

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


fixed external padding

fixed external padding

count=2;

module tusk(h, l)
{
  translate([l,0,0])
    rotate([0,0,90])
      polyhedron(
        points=[
                 [0,   0,  0],  // 0
                 [h,   0,  0],  // 1
                 [h/2, 0,  h],  // 2
                 [0,   l,  0],  // 3
                 [h,   l,  0],  // 4
                 [h/2, l,  h]   // 5
               ],
        faces=[
                [0,2,1],
                [0,1,4],
                [4,3,0],
                [1,2,5],
                [5,4,1],
                [0,5,2],
                [3,5,0],
                [3,4,5]
              ]
      );
}

module side()
{
  w =20; // width
  tc=8;  // Tusks Count
  th=5;  // Tusk Height
  ph=3;  // Platform Height
  l =tc*1.5*th-0.5*th; // length
  // tusks:
  for(dy = [0:tc-1])
    translate([0, dy*1.5*th, ph])
      tusk(h=th, l=w);
  // base and mount
  phi=4; // diameter for screw
  pad=3; // padding around each hole
  ext=phi+pad; // external element size
  difference()
  {
    union()
    {
      translate([-ext,0,0])
        cube([w+2*ext, l, ph]);
    }
    // screw mounts
    for(dx = [-phi/2, w+phi/2])
      for(dy = [0, (tc-2)*th*1.5-th*1.5])
        translate([dx, dy+1.5*th-th/4, -ph])
          hull()
            for(offy = [0, th*1.5])
              translate([0,offy,0])
                cylinder(h=ph*3, r=phi/2, $fs=1);
  }
}

for(i = [0:count-1])
  translate([i*35,0,0])
    side();

%translate([20, 4, 15])
%  rotate([0,180,0])
%    side();

count=2;

module tusk(h, l)
{
  translate([l,0,0])
    rotate([0,0,90])
      polyhedron(
        points=[
                 [0,   0,  0],  // 0
                 [h,   0,  0],  // 1
                 [h/2, 0,  h],  // 2
                 [0,   l,  0],  // 3
                 [h,   l,  0],  // 4
                 [h/2, l,  h]   // 5
               ],
        faces=[
                [0,2,1],
                [0,1,4],
                [4,3,0],
                [1,2,5],
                [5,4,1],
                [0,5,2],
                [3,5,0],
                [3,4,5]
              ]
      );
}

module side()
{
  w =20; // width
  tc=8;  // Tusks Count
  th=5;  // Tusk Height
  ph=3;  // Platform Height
  l =tc*1.5*th-0.5*th; // length
  // tusks:
  for(dy = [0:tc-1])
    translate([0, dy*1.5*th, ph])
      tusk(h=th, l=w);
  // base and mount
  phi=4; // diameter for screw
  pad=3; // padding around each hole
  ext=phi/2+pad; // external element size
  difference()
  {
    union()
    {
      translate([-ext,0,0])
        cube([w+2*ext, l, ph]);
    }
    // screw mounts
    for(dx = [-phi/2, w+phi/2])
      for(dy = [0, (tc-2)*th*1.5-th*1.5])
        translate([dx, dy+1.5*th-th/4, -ph])
          hull()
            for(offy = [0, th*1.5])
              translate([0,offy,0])
                cylinder(h=ph*3, r=phi/2, $fs=1);
  }
}

for(i = [0:count-1])
  translate([i*35,0,0])
    side();

%translate([20, 4, 15])
%  rotate([0,180,0])
%    side();


TrooperDoorLockBushing.scad: attempt to compensate for thin wall thickness problem

// Door lock bushing for unlock rod on a 1993 Isuzu Trooper.

// http://www.vehicross.info/modules.php?name=Content&file=viewarticle&id=22
// The manufacturer name for the part is "Holder; Rod, Door".
// The part number for right door is 8-97037-508-0.
// The part number for left door is 8-97037-509-0.

// The original version had notches at the end of the cylinder to
// allow it to flex in to put in the hole, and flex out to insert
// the rod.  But the cylinder wall thickness is so thin that it
// would break when flexing.

// number of faces on each cylinder
$fn=36;

difference() {
    union() {
        // base
        cylinder(h=2, r=5);
        translate([5, 0, 1]) {
            cube([8, 10, 2], center=true);
        }
        translate([8, 0, 0]) {
            cylinder(h=2, r=5);
        }

        // cylinder
        cylinder(h=16, r=3.7);
    }

    // through hole
    cylinder(h=20, r=2.75);

    // notches in base for ziptie
    translate([7, 5, 1]) {
        cube([4, 4, 4], center=true);
    }
    translate([7, -5, 1]) {
        cube([4, 4, 4], center=true);
    }
}

// Door lock bushing for unlock rod on a 1993 Isuzu Trooper.

// need to verify dimensions!

// http://www.vehicross.info/modules.php?name=Content&file=viewarticle&id=22
// The manufacturer name for the part is "Holder; Rod, Door".
// The part number for right door is 8-97037-508-0.
// The part number for left door is 8-97037-509-0.

// number of faces on each cylinder
$fn=36;

difference() {
    union() {
        // base
        cylinder(h=2, r=5);
        translate([5, 0, 1]) {
            cube([10, 10, 2], center=true);
        }
        translate([10, 0, 0]) {
            cylinder(h=2, r=5);
        }

        // cylinder
        cylinder(h=17, r=3.7);

        // swell
        translate([0, 0, 14.1]) {
            sphere(r=4.0);
        }
    }

    // through hole
    cylinder(h=10.5, r=2.75);
    translate([0, 0, 10]) {
        cylinder(h=4, r=2.5);
    }
    translate([0, 0, 13]) {
        cylinder(h=4, r=2.75);
    }

    // hole through base for ziptie
    translate([10, 0, 0]) {
        cylinder(h=3, r=2.7);
    }

    // E/W notch
    translate([-5, -0.4, 11]) {
        cube([10, 0.8, 7]);
    }

    // N/S notch
    translate([-0.4, -5, 11]) {
        cube([0.8, 10, 7]);
    }

    // chop top
    translate([0, 0, 16]) {
        cylinder(h=10, r=10);
    }
}


added cart to big screw

added cart to big screw

include <materials.scad>

cart_position = 300;

module big_screw() {
  len = 650;
  r1 = 5;
  r2 = 6;

  r3 = 14;
  r4 = 24;
  h1 = 15;
  h2 = 5;

  w = 40;

  cw = 200;

  color(Stainless) {
    rotate([-90,0,0]) {
      cylinder(len, r1, r1);
      translate([0, 0, 10])
        cylinder(len - 25, r2, r2);
      translate([0, 0, cart_position - h1 - h2]) {
        difference() {
          union() {
            cylinder(h1, r3, r3);
            translate([0, 0, h1])
              cylinder(h2, r4, r4);
          }
          translate([w/2,-cw/2,0])
            cube([cw,cw,cw]);
          translate([-w/2-cw,-cw/2,0])
            cube([cw,cw,cw]);
        }
      }
    }
  }
}

include <materials.scad>

module big_screw() {
  len = 650;
  r1 = 5;
  r2 = 6;
  color(Stainless)
    rotate([-90,0,0]) {
      cylinder(len, r1, r1);
      translate([0, 0, 10])
        cylinder(len - 25, r2, r2);
    }
}


Started on a StealthShell

Started on a StealthShell

…didn’t get very far

include <../config/config.scad>
UseSTL=false;
UseVitaminSTL=true;
DebugConnectors=true;
DebugCoordinateFrames=true;

StealthShell_STL();

module StealthShell_STL() {
	printedPart("printedparts/StealthShell.scad", "Stealth Shell", "StealthShell_STL()") {
	    view(t=[-2, 6, 14], r=[63, 0, 26], d=726);

        color([Level2PlasticColor[0], Level2PlasticColor[1], Level2PlasticColor[2], 1])
             if (UseSTL) {
                import(str(STLPath, "StealthShell.stl"));
            } else {
				StealthShell_Model();
            }
    }
}

module StealthShell_Model() {

	sw = 2 * perim;

	or = BaseDiameter/2 + Shell_NotchTol + dw;

	sr = or - sw + eta;

	supportAngle = 50;
	bridgeDist = 5;

	numRibs1 = round(circumference(sr * cos(supportAngle)) / bridgeDist);
	numRibs = 4 * (floor(numRibs1 / 4) + 1);

	ribThickness = 0.7;

	$fn=64;

	// shell with hole for LED
	//render()
		difference() {
			union() {
				// curved shell with centre hole for pen
				*rotate_extrude()
					difference() {
						// outer shell
						donutSector(
							or=or,
							ir=BaseDiameter/2 + Shell_NotchTol,
							a=90
						);

						polygon(
							[
								[0, ShellOpeningHeight + 1000],
								[ShellOpeningDiameter/2 + 1000, ShellOpeningHeight + 1000],
								[ShellOpeningDiameter/2 - dw - 1, ShellOpeningHeight - dw - 1],
								[0, ShellOpeningHeight - dw - 1]
							]);

					}

				// twist lock
				Shell_TwistLock();
			}
		}
}

/*

    Shell API Functions

    To help build loads of funky shells...  with twist-lock fitting

*/

Shell_NotchOuterWidth   = 20;
Shell_NotchSlope        = 2;
Shell_NotchInnerWidth   = Shell_NotchOuterWidth - 2* Shell_NotchSlope;
Shell_NotchDepth        = 5;
Shell_NotchTol          = 1;
Shell_NotchStop         = dw;
Shell_NotchRotation = 2 * atan2(Shell_NotchOuterWidth/2 - Shell_NotchStop/2, BaseDiameter/2);

// 2D shape to be removed from the base to support shell twist-lock
module Shell_TwistLockCutouts() {
    a = Shell_NotchOuterWidth + 2*Shell_NotchTol;
    b = Shell_NotchInnerWidth + 2*Shell_NotchTol;
    h = Shell_NotchDepth + Shell_NotchTol;
    aOffset = Shell_NotchSlope;

    for (i=[0,1])
        rotate([0,0, i*180 + Shell_NotchRotation/2])
        translate([BaseDiameter/2 - h/2 + eta, 0, 0])
        rotate([0,0, 90])
        trapezoid(b, a, h, aOffset, center=true);
}

// 3D twist-lock ring to mate a shell to the base
module Shell_TwistLock() {
    a = Shell_NotchOuterWidth;
    b = Shell_NotchInnerWidth;
    h = Shell_NotchDepth;
    aOffset = Shell_NotchSlope;

    union() {
        // Locking tabs
        for (i=[0,1])
            translate([0,0,-dw])
            difference() {
                // create the basic tab shape
                linear_extrude(dw)
                    hull() {
                        // Locking tab
                        rotate([0,0, i*180 - Shell_NotchRotation/2])
                            translate([BaseDiameter/2 - h/2 + eta, 0, 0])
                            rotate([0,0, 90])
                            trapezoid(b, a, h, aOffset, center=true);

                        // linking piece to connect locking tab to outer ring
                        translate([0,0,0])
                            rotate([0,0, i*180 - Shell_NotchRotation])
                            donutSector(or=BaseDiameter/2 + Shell_NotchTol + dw,
                                ir=BaseDiameter/2,
                                a=Shell_NotchRotation
                            );
                    }

                // now chop out a slight slope to allow for a tight friction fit
                rotate([0,0, i*180 - Shell_NotchRotation/2])
                    translate([BaseDiameter/2 - h - 3, 0, dw * 0.8])
                    rotate([5,0,0])
                    translate([0,-a/2-1,0])
                    cube([10, a + 2,10]);
            }

        // notch stops
        for (i=[0,1])
            rotate([0,0, i*180 - Shell_NotchRotation/2 + 0.3])
            translate([BaseDiameter/2 - h/2 + 1+eta, a/2 - Shell_NotchStop/2 - 0.5/2, -dw])
            rotate([0,0, 90])
            linear_extrude(dw*2)
            trapezoid(Shell_NotchStop-aOffset+0.7, Shell_NotchStop+1.3, h+2, 0, center=true);

        // outer ring
        translate([0,0,-dw])
            rotate_extrude()
            translate([BaseDiameter/2 + Shell_NotchTol, 0])
            union() {
                square([dw, 3*dw]);

                translate([eta, 3*dw - Shell_NotchTol, 0])
                    mirror([1,1,0])
                    rightTriangle(dw, dw, center = true);

                translate([-dw+eta, 3*dw - Shell_NotchTol - eta,0])
                    square([dw, Shell_NotchTol+eta]);
            }

    }
}

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


body:bottom shoulder

body:bottom shoulder

include <constants.scad>;
HEIGHT_BODY = 44.5;
DIAMETER_BODY = 10.4;
BORDER_RADIUS_BODY = 0.2;
HEIGHT_NIPPLE = 0.8;

HEIGHT_TOP = 2 * BORDER_RADIUS_BODY;

function top_position_z () = -(HEIGHT_NIPPLE + BORDER_RADIUS_BODY);
function main_position_z() = -(HEIGHT_BODY - BORDER_RADIUS_BODY);

module top_surface()
{
    position = [0,0,top_position_z()];

    diameter_base = DIAMETER_BODY - HEIGHT_TOP;

    translate(position)
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = diameter_base,
        $fn = FINE);
}

module top_shoulder()
{
    position_ring = [0,0,top_position_z()];

    position_circle_x = radius(DIAMETER_BODY)-BORDER_RADIUS_BODY;
    position_circle = [position_circle_x, 0, 0];

    translate(position_ring)
        rotate_extrude(convexity = CONVEXITY, $fn = FINE)
            translate(position_circle)
                circle(r = BORDER_RADIUS_BODY, $fn = FINE);
}

module main_cylinder()
{
    heigh_main = HEIGHT_BODY - (HEIGHT_NIPPLE + HEIGHT_TOP);

    position = [0,0,main_position_z()];

    translate(position)
        cylinder(
            h = heigh_main,
            d = DIAMETER_BODY,
            $fn = FINE);
}

module bottom_shoulder()
{
    position_ring = [0,0,main_position_z()];

    position_circle_x = radius(DIAMETER_BODY)-BORDER_RADIUS_BODY;
    posision_circle = [position_circle_x, 0, 0];

    translate(position_ring)
        rotate_extrude(convexity = CONVEXITY, $fn = FINE)
            translate(posision_circle)
                circle(r = BORDER_RADIUS_BODY, $fn = FINE);
}
module body()
{
    top_surface();
    top_shoulder();
    main_cylinder();
    bottom_shoulder();

//Bottom face of body
translate([0,0,-(HEIGHT_BODY)])
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = (DIAMETER_BODY - (2 * BORDER_RADIUS_BODY)),
        $fn = FINE);
}

body();

include <constants.scad>;
HEIGHT_BODY = 44.5;
DIAMETER_BODY = 10.4;
BORDER_RADIUS_BODY = 0.2;
HEIGHT_NIPPLE = 0.8;

HEIGHT_TOP = 2 * BORDER_RADIUS_BODY;

function top_position_z () = -(HEIGHT_NIPPLE + BORDER_RADIUS_BODY);
function main_position_z() = -(HEIGHT_BODY - BORDER_RADIUS_BODY);

module top_surface()
{
    position = [0,0,top_position_z()];

    diameter_base = DIAMETER_BODY - HEIGHT_TOP;

    translate(position)
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = diameter_base,
        $fn = FINE);
}

module top_shoulder()
{
    position_ring = [0,0,top_position_z()];

    position_circle_x = radius(DIAMETER_BODY)-BORDER_RADIUS_BODY;
    position_circle = [position_circle_x, 0, 0];

    translate(position_ring)
        rotate_extrude(convexity = CONVEXITY, $fn = FINE)
            translate(position_circle)
                circle(r = BORDER_RADIUS_BODY, $fn = FINE);
}

module main_cylinder()
{
    heigh_main = HEIGHT_BODY - (HEIGHT_NIPPLE + HEIGHT_TOP);

    position = [0,0,main_position_z()];

    translate(position)
        cylinder(
            h = heigh_main,
            d = DIAMETER_BODY,
            $fn = FINE);
}

module body()
{
    top_surface();
    top_shoulder();
    main_cylinder();

//Body bottom shoulder
translate([0,0,main_position_z()])
    rotate_extrude(convexity = CONVEXITY, $fn = FINE)
    translate([(DIAMETER_BODY/2)-BORDER_RADIUS_BODY, 0, 0])
        circle(r = BORDER_RADIUS_BODY, $fn = FINE);

//Bottom face of body
translate([0,0,-(HEIGHT_BODY)])
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = (DIAMETER_BODY - (2 * BORDER_RADIUS_BODY)),
        $fn = FINE);
}

body();


Show body by default

Show body by default

$fn=100;

button_radius = 49;
hole_radius = 14.5;
table_padding = 40;
extra_padding = 2;
bottom_padding = 30;

wall_thickness = 3;

mount_height = table_padding + extra_padding + button_radius + hole_radius + bottom_padding;
mount_depth = 50;
mount_width = (hole_radius * 2) + (bottom_padding * 2);

font = "monaco.dxf";

// Body
union() {
    difference() {
        bottom();
        name();
    }

    difference() {
        sides();
        cover_screws();
        mount_screws();
    }
}

// Cover
// difference() {
//     translate([0, 0, mount_depth-wall_thickness])
//     cover();
//     cover_screws();
//     project();
// }

module screw_mount() {
    difference() {
        cube([10, wall_thickness, 10]);

        rotate([90, 0, 0])
        translate([5, 5, -wall_thickness-1])
        cylinder(r=2, h=wall_thickness+2);
    }
}

module bottom() {
    difference() {
    hull() {
        // lower left
        translate([wall_thickness*2, wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // lower right
        translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // upper right
        translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);

        // upper left
        translate([0, mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);
    }

    union() {
        translate([mount_width/2, wall_thickness+7.5, -1])
        cylinder(r=3, h=wall_thickness+2);

        translate([mount_width/2-4.5, wall_thickness+7.5-2.5, wall_thickness-.8])
        cube(size=[9, 5, 1]);
    }
    }
}

module sides() {
    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);

            // upper left
            translate([0, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);
        }

        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);
        }
    }

    intersection() {
        translate([wall_thickness, wall_thickness, 0])
        cube([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), mount_depth]);

        union() {
            translate([wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);
        }
    }
}

module cover() {
    hole_center = mount_height - table_padding - button_radius;

    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);
        }

        translate([mount_width/2, hole_center, -1])
        cylinder(r=hole_radius, h=wall_thickness*2);
    }

    // Fake button
    // translate([mount_width/2, hole_center, 5])
    // cylinder(r=button_radius, h=20);
}

module cover_screws() {
    translate([wall_thickness+3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([wall_thickness+3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);
}

module mount_screws() {
    spacing = 15;

    translate([spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);
}

// Text
module letter(l, h=100, i=0) {
    union() {
        linear_extrude(height=h) import(font, layer=l[i]);
        translate([dxf_dim(file=font, name="advx", layer=l[i]), dxf_dim(file=font, name="advy", layer=l[i]), 0])
        child();
    }
}

module word(wrd, h=100, i=0) {
    if (i < len(wrd)) {
        letter(wrd, h, i) word(wrd, h, i+1);
    } else {
        child();
    }
}

module name() {
    translate([18.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Scott", 1000);

    translate([46.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Barron", 1000);

    translate([34.5, mount_height - 35, wall_thickness-1.5])
    scale(0.002)
    word("2014", 1000);
}

module project() {
    translate([22, mount_height-20, mount_depth-1.5])
    scale(0.002)
     word("Pingduino", 1000);
}

$fn=100;

button_radius = 49;
hole_radius = 14.5;
table_padding = 40;
extra_padding = 2;
bottom_padding = 30;

wall_thickness = 3;

mount_height = table_padding + extra_padding + button_radius + hole_radius + bottom_padding;
mount_depth = 50;
mount_width = (hole_radius * 2) + (bottom_padding * 2);

font = "monaco.dxf";

// Body
// union() {
//     difference() {
//         bottom();
//         name();
//     }

//     difference() {
//         sides();
//         cover_screws();
//         mount_screws();
//     }
// }

// Cover
difference() {
    translate([0, 0, mount_depth-wall_thickness])
    cover();
    cover_screws();
    project();
}

module screw_mount() {
    difference() {
        cube([10, wall_thickness, 10]);

        rotate([90, 0, 0])
        translate([5, 5, -wall_thickness-1])
        cylinder(r=2, h=wall_thickness+2);
    }
}

module bottom() {
    difference() {
    hull() {
        // lower left
        translate([wall_thickness*2, wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // lower right
        translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // upper right
        translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);

        // upper left
        translate([0, mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);
    }

    union() {
        translate([mount_width/2, wall_thickness+7.5, -1])
        cylinder(r=3, h=wall_thickness+2);

        translate([mount_width/2-4.5, wall_thickness+7.5-2.5, wall_thickness-.8])
        cube(size=[9, 5, 1]);
    }
    }
}

module sides() {
    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);

            // upper left
            translate([0, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);
        }

        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);
        }
    }

    intersection() {
        translate([wall_thickness, wall_thickness, 0])
        cube([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), mount_depth]);

        union() {
            translate([wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);
        }
    }
}

module cover() {
    hole_center = mount_height - table_padding - button_radius;

    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);
        }

        translate([mount_width/2, hole_center, -1])
        cylinder(r=hole_radius, h=wall_thickness*2);
    }

    // Fake button
    // translate([mount_width/2, hole_center, 5])
    // cylinder(r=button_radius, h=20);
}

module cover_screws() {
    translate([wall_thickness+3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([wall_thickness+3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);
}

module mount_screws() {
    spacing = 15;

    translate([spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);
}

// Text
module letter(l, h=100, i=0) {
    union() {
        linear_extrude(height=h) import(font, layer=l[i]);
        translate([dxf_dim(file=font, name="advx", layer=l[i]), dxf_dim(file=font, name="advy", layer=l[i]), 0])
        child();
    }
}

module word(wrd, h=100, i=0) {
    if (i < len(wrd)) {
        letter(wrd, h, i) word(wrd, h, i+1);
    } else {
        child();
    }
}

module name() {
    translate([18.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Scott", 1000);

    translate([46.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Barron", 1000);

    translate([34.5, mount_height - 35, wall_thickness-1.5])
    scale(0.002)
    word("2014", 1000);
}

module project() {
    translate([22, mount_height-20, mount_depth-1.5])
    scale(0.002)
     word("Pingduino", 1000);
}


shorter holder for Lis :)

shorter holder for Lis :)

include <Write.scad>

/*
 * configuration
 */
names = ["LIS"];
brushes_count = len(names);
//$fn=200;

/*
 * modules
 */

module lower_tub()
{
  translate([0, (20+4)/2, 0])
    difference()
    {
      cylinder(h=10+3, r=(20+3)/2);
      translate([0,0,3])
        cylinder(h=10+3, r2=20/2, r1=16/2);
    }
}

module upper_ring()
{
  translate([0, (24+5)/2, 0])
    difference()
    {
      cylinder(h=10, r=(24+5)/2);
      cylinder(h=10, r=(24+0)/2);
    }
}

module back_wall()
{
  // lower part
  translate([-40/2, 0, 0])
    cube([40, 3, 20]);
  // upper part
  translate([-40/2, 0, 100-10-25])
    cube([40, 3, 20]);
  // connector
  translate([-10/2, 0, 0])
    cube([10, 3, 100-25]);
}

module brush_holder()
{
  lower_tub();
  translate([0,0,100-5-25])
    upper_ring();
  back_wall();
  // lower mounting
  difference()
  {
    translate([-15/2, 3, 0])
      cube([15, 4, 10+3]);
    translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
      hull()
        lower_tub();
  }
  // upper mounting
  translate([0, 0, 100-5-25])
  {
    difference()
    {
      translate([-25/2, 3, 0])
        cube([25, 10, 10]);
      translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
        hull()
          upper_ring();
    }
  }
}

/*
 * main program
 */

rotate([90, 0, 0])
{
  for(i = [0:brushes_count-1])
  {
    translate([i*30,4,45])
      rotate([-90, -90, 0])
        scale([2,1,1])
          write(names[i], t=2, h=8, center=true);
    translate(i * [30, 0, 0])
      brush_holder();
  }
}

include <Write.scad>

/*
 * configuration
 */
names = ["JOHN", "JANE", "BILLY"];
brushes_count = len(names);
//$fn=200;

/*
 * modules
 */

module lower_tub()
{
  translate([0, (20+4)/2, 0])
    difference()
    {
      cylinder(h=10+3, r=(20+3)/2);
      translate([0,0,3])
        cylinder(h=10+3, r2=20/2, r1=16/2);
    }
}

module upper_ring()
{
  translate([0, (24+5)/2, 0])
    difference()
    {
      cylinder(h=10, r=(24+5)/2);
      cylinder(h=10, r=(24+0)/2);
    }
}

module back_wall()
{
  // lower part
  translate([-40/2, 0, 0])
    cube([40, 3, 20]);
  // upper part
  translate([-40/2, 0, 100-10])
    cube([40, 3, 20]);
  // connector
  translate([-10/2, 0, 0])
    cube([10, 3, 100]);
}

module brush_holder()
{
  lower_tub();
  translate([0,0,100-5])
    upper_ring();
  back_wall();
  // lower mounting
  difference()
  {
    translate([-15/2, 3, 0])
      cube([15, 4, 10+3]);
    translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
      hull()
        lower_tub();
  }
  // upper mounting
  translate([0, 0, 100-5])
  {
    difference()
    {
      translate([-25/2, 3, 0])
        cube([25, 10, 10]);
      translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
        hull()
          upper_ring();
    }
  }
}

/*
 * main program
 */

rotate([90, 0, 0])
{
  for(i = [0:brushes_count-1])
  {
    translate([i*30,4,55])
      rotate([-90, 90, 0])
        scale([2,1,1])
          write(names[i], t=2, h=8, center=true);
    translate(i * [30, 0, 0])
      brush_holder();
  }
}


bearings: Add orient param

bearings: Add orient param