back to square tubes on BH

back to square tubes on BH

// 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.3);

//  -------------------------- 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
%color([0,0,1,.2]) translate([0,0,-8])
   cube([114,1.75*2.54,1.75*2.54],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);

// 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]) 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() {
useF698=0;
thin=1;
withBrace=0;  // use wobble braces at knee as fork

  // FG (shin)
    if (withBrace) {
      hull() {  // FG (shin)
        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); // foot
      }
    } else {
      // knee end fork cut out of square tube
      difference() {
        hull() {
          cube([4,2.54,2.54],center=true);
          translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.54,$fn=24,center=true); // foot
        }

        #cylinder(r=.4,h=4,$fn=17,center=true);
        translate([-.5,.2,0]) cube([4,2.54,2.1],center=true);
      }
    }

  // knee braces/fork
  *%color([0,1,1,.2])
  for (z=[-1.3,thin?1.6:7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for thin knee
      translate([-5,2,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=thin?4:17,$fn=17,center=true);
  }

  // hinge holders at H
  if (useF698) {
    // F698 tubes for H-hinge fork
    %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.6])cube([3,3,2.8],center=true);
    }
    translate([FGleft,FGperp,-.87]) {
      rotate([180,0,0]) F698();
      translate([0,0,5.0]) rotate([180,0,0]) F698();
      translate([0,0,1.95]) F698();
      translate([0,0,6.75]) F698();
    }
  } else {
    // use SA8 Heim rod-ends for H fork
    // use some washers/spacers to get heim a few mm inside fork, to allow
    // room for connecting rod to clear fork
    for (z=[-.7+.3,5.6-.3]) translate([FGleft,FGperp,z])
      rotate([0,0,142]) SI8onBolt(); //SA8();
  }

  if (thin==0) {
    // vertical brace extension at knee
    translate([3.5,0,4.1]) cube([2.5,2.5,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
  if (thin) {
    for (z=[-.3]) hull() {
      translate([   3    ,   1    ,]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }
    hull() {
      translate([FGleft+4.5,FGperp-4,6]) barEnd1();
      translate([7,4.4,0]) barEnd1();
    }

  } else {
    for (z=[-.3,5.1]) hull() {
      translate([   3    ,   1    ,z]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }

    hull() {  // dig brace.  Could be gusset?
       translate([3,1,5.7]) barEnd1();
       translate([useF698?12:13+2,11,-.3]) barEnd1();
    }

    hull() {
      translate([FGleft-(useF698?7.2:5-4),FGperp-8,5.3]) barEnd1();
      translate([useF698?14:15.5+2.6,13.5,-.3]) barEnd1();
    }
  }

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

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

  // extra truss braces
  hull() {
      translate([46,15,3]) barEnd1();
      translate([35, 0,0]) barEnd1();
  }

  // out-of-plane perp braces
  if (useF698) {
    translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  } else {
    ////translate([FGleft+1,FGperp-2,.3]) cylinder(r=.6,h=5);
    ////translate([FGleft-1,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    //translate([FGleft+4,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    translate([FGleft+4.5,FGperp-3.5,2.4]) rotate([0,0,142])
      cube([.75*2.54,.75*2.54,8],center=true);
  }
}

$fn=12;
module hip() {
squareTop=1;  // 1==let top tube be square, no additional fork pieces

  if (squareTop) {
    // crank link width with flange bearings is a little over 1"
    // so go with 1.25" square top tube
    *difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,1.25*2.54,1.25*2.54],center=true);

      translate([-1,-.3,0]) cube([5,3.2,2.8],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,3.2,2.8],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

    // Even though , technically, the crank link hits the
    // edge with a 1" top tube, I think there is enough slop
    // with the heim joint to use a 1" top tube anyway.
    // also... if needed, we can shift the top tube
    // up or down 1/8" depending in which side we are, and make it work.
    // have slightly uneven spacers at F, and we are fine
    difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,2.54,2.54],center=true);

      translate([-1,-.3,0]) cube([5,2.6,2.2],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,2.6,2.2],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

  } else {
    translate([DE/2,0,-.2]) rotate([0,90,0])      // top tube
      cylinder(r=.9,h=DE-4,$fn=17,center=true);
  }

  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     union() {
       cylinder(r=2.54*1.75/2,h=7.2,$fn=36);                // axle

       hull() {  // diag tubes
         translate([-1.6,1.4,1.2]) barEnd1();
         translate([DEleft-DE+2,DEperp,1.2]) barEnd1();
       }
       hull() {
         translate([0,0,1.2]) barEnd1();
         translate([DE-DEleft-1,DEperp,1.2]) barEnd1();
       }

       // extra brace
       translate([0,0,6.2]) rotate([-105,0,0]) cylinder(r=.8,h=20);
     }

     // bore out for 6805 bearing
     cylinder(r=3.7/2+.1,h=22,$fn=18,center=true);
  }

  if (squareTop==0) {
  // use cut-out square tube (or channel) for forks, instead of all welded.
  // easier to drill and maintain aligned holes
  // 14ga roughly 2mm thick
  translate([DE,0,0]) rotate([0,0,180]) channelFork();
  channelFork();
  }

  // extra bracing
  translate([DE/2,-15,0]) rotate([0,90,0]) cylinder(r=.8,h=35,center=true);
}

// cut-out square tube (or channel) for forks
//     easier to drill and maintain aligned holes
module channelFork(od=2.54*1.24,gu=.2,len=3,hd=.82,co=.5)
translate([co,0,0]) difference() {
  cube([od     ,len  ,od     ],center=true);
  cube([od-2*gu,len+1,od-2*gu],center=true);

  // open one side of square tube to make a channel
  translate([-od/2,0,0]) cube([2.1*gu,len+1,od-2*gu-.05],center=true);

  // put hole at x=0,y=0 in part space.
  #translate([-co,0,0]) cylinder(r=hd/2,h=od+1,$fn=17,center=true);
}

/*
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=.9,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .31]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.31]) 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-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3-3,$fn=11,center=true);

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

module EFlink() {
thin=1;

  translate([EF,0,0]) SI8onBolt(); //SA8();

  if (thin) {
    rotate([0,0,180]) SI8onBolt();

    // main tube
    translate([EF/2,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-9,$fn=13,center=true);

  } else {

    // main tube
    translate([EF/2-.4-1.5,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3-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() {

  // main bars for BH link.
  // may want to fabricate these first, then add the extra
  // bracing, in place, on a working (but wobbly?) leg
  translate([0,0,7.8]) rotate([180,0,0]) BHbar();
  translate([0,0,-3]) BHbar();

  // brace near axle
  translate([3.3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);

  BHcrosses();
}

module BHbar() {
  difference() {
    union() {
      cylinder(r=2.54*1.75/2,h=2.8,$fn=42,center=true);
      translate([BH/2+1,0,.14]) difference() {
        cube([BH+2,2.54,2.54],center=true);  // sq. tube
        cube([BH+3,2.2,2.2],center=true);

        // carve out for H bolt
        translate([BH/2,0,-1.4]) rotate([0,-30,0])
           cube([6,3,3],center=true);
      }

      // weld extra plate for strength at H node
      translate([BH,0,2.54/2+.3]) cube([3,3,.4],center=true);
    }

    cylinder(r=3.7/2+.1,h=3,$fn=19,center=true);
    #translate([BH,0,0]) cylinder(r=.4,h=7,$fn=13);
  }
}

// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses() {
h1=BH-4;  // node closest to H
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([b1, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([b1,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
}

module barEnd1() sphere(.8,$fn=12);

// 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.3);

//  -------------------------- 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
%color([0,0,1,.2]) translate([0,0,-8])
   cube([114,1.75*2.54,1.75*2.54],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);

// 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]) 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() {
useF698=0;
thin=1;
withBrace=0;  // use wobble braces at knee as fork

  // FG (shin)
    if (withBrace) {
      hull() {  // FG (shin)
        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); // foot
      }
    } else {
      // knee end fork cut out of square tube
      difference() {
        hull() {
          cube([4,2.54,2.54],center=true);
          translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.54,$fn=24,center=true); // foot
        }

        #cylinder(r=.4,h=4,$fn=17,center=true);
        translate([-.5,.2,0]) cube([4,2.54,2.1],center=true);
      }
    }

  // knee braces/fork
  *%color([0,1,1,.2])
  for (z=[-1.3,thin?1.6:7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for thin knee
      translate([-5,2,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=thin?4:17,$fn=17,center=true);
  }

  // hinge holders at H
  if (useF698) {
    // F698 tubes for H-hinge fork
    %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.6])cube([3,3,2.8],center=true);
    }
    translate([FGleft,FGperp,-.87]) {
      rotate([180,0,0]) F698();
      translate([0,0,5.0]) rotate([180,0,0]) F698();
      translate([0,0,1.95]) F698();
      translate([0,0,6.75]) F698();
    }
  } else {
    // use SA8 Heim rod-ends for H fork
    // use some washers/spacers to get heim a few mm inside fork, to allow
    // room for connecting rod to clear fork
    for (z=[-.7+.3,5.6-.3]) translate([FGleft,FGperp,z])
      rotate([0,0,142]) SI8onBolt(); //SA8();
  }

  if (thin==0) {
    // vertical brace extension at knee
    translate([3.5,0,4.1]) cube([2.5,2.5,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
  if (thin) {
    for (z=[-.3]) hull() {
      translate([   3    ,   1    ,]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }
    hull() {
      translate([FGleft+4.5,FGperp-4,6]) barEnd1();
      translate([7,4.4,0]) barEnd1();
    }

  } else {
    for (z=[-.3,5.1]) hull() {
      translate([   3    ,   1    ,z]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }

    hull() {  // dig brace.  Could be gusset?
       translate([3,1,5.7]) barEnd1();
       translate([useF698?12:13+2,11,-.3]) barEnd1();
    }

    hull() {
      translate([FGleft-(useF698?7.2:5-4),FGperp-8,5.3]) barEnd1();
      translate([useF698?14:15.5+2.6,13.5,-.3]) barEnd1();
    }
  }

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

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

  // extra truss braces
  hull() {
      translate([46,15,3]) barEnd1();
      translate([35, 0,0]) barEnd1();
  }

  // out-of-plane perp braces
  if (useF698) {
    translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  } else {
    ////translate([FGleft+1,FGperp-2,.3]) cylinder(r=.6,h=5);
    ////translate([FGleft-1,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    //translate([FGleft+4,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    translate([FGleft+4.5,FGperp-3.5,2.4]) rotate([0,0,142])
      cube([.75*2.54,.75*2.54,8],center=true);
  }
}

$fn=12;
module hip() {
squareTop=1;  // 1==let top tube be square, no additional fork pieces

  if (squareTop) {
    // crank link width with flange bearings is a little over 1"
    // so go with 1.25" square top tube
    *difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,1.25*2.54,1.25*2.54],center=true);

      translate([-1,-.3,0]) cube([5,3.2,2.8],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,3.2,2.8],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

    // Even though , technically, the crank link hits the
    // edge with a 1" top tube, I think there is enough slop
    // with the heim joint to use a 1" top tube anyway.
    // also... if needed, we can shift the top tube
    // up or down 1/8" depending in which side we are, and make it work.
    // have slightly uneven spacers at F, and we are fine
    difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,2.54,2.54],center=true);

      translate([-1,-.3,0]) cube([5,2.6,2.2],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,2.6,2.2],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

  } else {
    translate([DE/2,0,-.2]) rotate([0,90,0])      // top tube
      cylinder(r=.9,h=DE-4,$fn=17,center=true);
  }

  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     union() {
       cylinder(r=2.54*1.75/2,h=7.2,$fn=36);                // axle

       hull() {  // diag tubes
         translate([-1.6,1.4,1.2]) barEnd1();
         translate([DEleft-DE+2,DEperp,1.2]) barEnd1();
       }
       hull() {
         translate([0,0,1.2]) barEnd1();
         translate([DE-DEleft-1,DEperp,1.2]) barEnd1();
       }

       // extra brace
       translate([0,0,6.2]) rotate([-105,0,0]) cylinder(r=.8,h=20);
     }

     // bore out for 6805 bearing
     cylinder(r=3.7/2+.1,h=22,$fn=18,center=true);
  }

  if (squareTop==0) {
  // use cut-out square tube (or channel) for forks, instead of all welded.
  // easier to drill and maintain aligned holes
  // 14ga roughly 2mm thick
  translate([DE,0,0]) rotate([0,0,180]) channelFork();
  channelFork();
  }

  // extra bracing
  translate([DE/2,-15,0]) rotate([0,90,0]) cylinder(r=.8,h=35,center=true);
}

// cut-out square tube (or channel) for forks
//     easier to drill and maintain aligned holes
module channelFork(od=2.54*1.24,gu=.2,len=3,hd=.82,co=.5)
translate([co,0,0]) difference() {
  cube([od     ,len  ,od     ],center=true);
  cube([od-2*gu,len+1,od-2*gu],center=true);

  // open one side of square tube to make a channel
  translate([-od/2,0,0]) cube([2.1*gu,len+1,od-2*gu-.05],center=true);

  // put hole at x=0,y=0 in part space.
  #translate([-co,0,0]) cylinder(r=hd/2,h=od+1,$fn=17,center=true);
}

/*
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=.9,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .31]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.31]) 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-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3-3,$fn=11,center=true);

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

module EFlink() {
thin=1;

  translate([EF,0,0]) SI8onBolt(); //SA8();

  if (thin) {
    rotate([0,0,180]) SI8onBolt();

    // main tube
    translate([EF/2,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-9,$fn=13,center=true);

  } else {

    // main tube
    translate([EF/2-.4-1.5,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3-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
    union() {
      // main axle tube
      translate([0,0,2.4]) cylinder(r=2.54*1.75/2,h=13.5,$fn=36,center=true);

      for(z=[-2.4,7.2]) {  // main side rails
        hull() {
          translate([BH-6,0,z]) barEnd1();
          translate([   0,0,z]) barEnd1();
        }
      }

    }

    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=3.7/2+.1,h=22,$fn=19,center=true);
  }

  // brace near axle
  translate([3.3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);

/* get rid of fork brace.  Comes close to hitting CH cranklink.
   let cross members hold forks apart
  //    fork brace
  translate([BH-7,0,2.43]) cube([2.5,2.5,7.6],center=true);

  hull() {
    translate([   4,.7,-1.6]) barEnd1();
    translate([BH-9,.7, 6.2]) barEnd1();
  }
  hull() {
    translate([   4,-.7, 6.2]) barEnd1();
    translate([BH-9,-.7,-1.6]) barEnd1();
  }
*/

  BHcrosses();

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

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}

// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses() {
h1=BH-4;  // node closest to H
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([b1, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([b1,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
}

/*
// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses2() {
h1=BH-4;  // node closest to H
h2=h1-19;
b2=h2-4;
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([h2, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([h2,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
  hull() {
    translate([b1,-spread,lo]) barEnd1();
    translate([b2,-spread,hi]) barEnd1();
  }
  hull() {
    translate([b2,spread,lo]) barEnd1();
    translate([b1,spread,hi]) barEnd1();
  }
}
*/

module barEnd1() sphere(.8,$fn=12);


reduce fuzz for spread around holes.  current printer does not spread that much

// $URL: svn+ssh://mrwhat@ssh.boim.com/home/mrwhat/svn/Walker/trunk/Jansen.scad $
// $Id: Jansen.scad 427 2014-08-23 20:42:39Z mrwhat $

// Define PART to one of the following values to generate model for desired part.
//       HipA, HipB, FootA, FootB, CH, CD, EF, BH, AC, pulley, mainBar, drivePulley
// For a 2-leg (half-trotter) :  print (2) CH, CD ; (4) EF, BH ; (1) of the others
// For a production robot, glue a rectangular support/spacer between BH pairs for stiffness
//
// Combined parts with pads, optimized for RepRap :
// Hip, Feet, crankLinks, EFs, BHs    : main, pulley, drivePulley as above (brace)
PART="HipA";
hingeStyle = "spacer"; //6standoff";  // spacer or standoff
echo(str("PART=",PART));

HoleFuzz = 0.1;  // extra radius (mm) to add to holes to account for printer slop
dHoleFuzz = 0.2;  // extra radius (mm) to add to d-shaft holes.  Sometimes not the same as HoleFuzz since it is harder to clean D-shaft holes

// measured diameter of '3/16"' spacer was 4.74 to 4.76, not 4.7625 as expected.
// Current design:  3/16" axles at B
//                  3/16" long 1/4"  OD standoffs at D, E, F
//                  1/2"  long 3/16" OD standoffs at H, A, C
Bdiam = 4.7625;  // larger brass tube rdiameter, measured on 3/16" tube
Adiam = 4.76;
Hdiam = Adiam;
//Ddiam = 6.35;  // 1/4" OD standoffs
Ddiam = Adiam;  // 3/16" OD standoffs/spacers
diam4 = 2.76;  // diameter of #4-40 screw, OD of thread

// on spacer tests:
//    Brad +.125 mm was snug, but not quite free rotating
//         +.05     turned, but not freely
//         -.025    still turned,  was very close
//    Arad +.125    turned free (good for main, crankLinks)
//         +.05     was press-to-fit (good for crankArm)
//    rad4 + 0.2    allowed a screw to go through snugly but freely
//         +.125    only threaded through
//  1/4"OD + 0.2    was a snug fit, no turn.  almost press-to-fit
//         + 0.275  snug, free turn... good for hinges on standoff

Brad = Bdiam/2 + HoleFuzz/2;    // 4.76mm diam brass tube -- critical fit
Arad = Adiam/2 + HoleFuzz/2.3;  // 3.18mm diam brass tube -- critical fit
rad4 = diam4/2 + HoleFuzz;  // good for screw pass-through
Hrad = Hdiam/2 + HoleFuzz*1.35;  // standoff holes for freely-moving hinges
Drad = Ddiam/2 + HoleFuzz;
AradFree = Adiam/2 + .25;  // loose fit on spindle

BradTight = Brad-0.05;
BradFree  = Brad+0.05;

Frad = 7;  // radius of beefed-up "knee"

LinkRad=3;
BarHeight=3;
//NodeHeight=5.8;  // gives a little room for 6.35 mm (.25 inch) standoffs
layer1bias=0.4;  // shift up for 1 layer of brim/raft

// 9/16" spacer height 14.37mm, not 14.287 as expected
// 3/16" spacer height  4.79mm, not 4.7625 as expected (*3=14.37)
// 1/4" Al standoffs were pretty close, and 3x was 19.02mm high, not 19.05 as expected, pretty close
//TrueNodeHeight = (hingeStyle == "spacer") ? 4.79-.2 : 6.35;
TrueNodeHeight = 4.79-.2;
NodeHeight = TrueNodeHeight - 0.3;  // a little room for hinges
//NodeHeight3 = 25.4*((hingeStyle == "spacer") ? 9/16 : 3/4) - 0.3;
// moving to slightly thinner 1/2" standoffs at H
NodeHeight3 = 25.4/2 - 0.3;

// Forks should be 1 node thick for standoffs...  short screws go into variable length standoff.
// they should be 2 nodes thick for spacers, extra long so that ALL hinges are 5 nodes wide.
//ForkHeight = (hingeStyle == "spacer") ? 2*NodeHeight : NodeHeight;
ForkHeight = NodeHeight;

// definitions of linkage lengths: AC;Ay;Bx;BH;EF;CD;CH;BD;BE;DE;FG;FH;GH
// derived quantities: DEleft;FGleft;DEperp;FGperp
include <JansenDefs.scad>;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//       define some standard part dimensions for re-use in groups, etc.
acH0 = NodeHeight;
acH1 = acH0+2;
acOR = Arad+3;
acIR = rad4;
pulleyR = 17;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

module nodeCyl(nodeHeight,nodeRad)
{ cylinder(h=nodeHeight,r1=nodeRad+.3,r2=nodeRad-.3,$fn=64); }  // set to 20+ for production quality

module drillHole(holeRad) { translate([0,0,-.03])
   cylinder(h=22,r=holeRad,$fn=80); } // set to 80 for production run

module footpad(r) { // pad to help a part stick to plate for 3D printer
   color("Cyan") cylinder(h=layer1bias,r1=r,r2=r-.3,$fn=11); }

// place a point, usually inside a linkage bar, to use in a hull
// with a part connected to a linkage bar
module barAnchor(dx) {
   translate([dx,0,0]) cylinder(h=BarHeight,r1=.8,r2=.6,$fn=6);
}

use <pulley.scad>;

include <JansenMain.scad>
include <JansenFoot.scad>

module monoBracedLinkage(len) {
lro = Drad+1.8;  // outisde link radius
difference() { union() { //------------------------ EF
    difference() { hull() {  // main bar
      translate([ 0 ,0,0])   nodeCyl(BarHeight,Frad);
      translate([len,0,0])   nodeCyl(BarHeight,lro*.5);
      }
      hull() { translate([0,0,-1.5]) { nodeCyl(BarHeight,Frad-1.5);
               translate([len,0 ,0])   nodeCyl(BarHeight,1); }}
    }

    // non-braced (BED side) reinforcement
    translate(  [len,0,0]) { nodeCyl(BarHeight,lro);
       hull() { translate([0,0,BarHeight-1])
          cylinder(h=ForkHeight-BarHeight+1,r1=lro-.8,r2=rad4+1.2,$fn=64);
          cylinder(h=NodeHeight-1,r1=lro+.1,r2=rad4+1.2,$fn=16);
          //barAnchor(-1.5*lro);
          translate([-2*lro,0,2]) sphere(r=.4,$fn=12);
       }
    }
    hull() { translate([1.3*Frad,0,1.5]) scale([1,1,1]) sphere(r=1,$fn=16);
        translate([0,0,BarHeight-1])
          cylinder(h=ForkHeight-BarHeight+1,r1=Frad-.6,r2=rad4+1.6,$fn=64); }
    cylinder(h=BarHeight-1,r1=rad4+2.2,r2=rad4+3.3,$fn=32);

    hull() { // out-of-plane ridge/brace
        translate([ 0 ,0,2.2]) scale([1,1,2]) sphere(r=1,$fn=16);
        translate([len,0,2.2]) scale([1,1,2]) sphere(r=1,$fn=16); }
    }
    drillHole(rad4);
    translate([len,0,0]) drillHole(rad4);
}}

//------------------------------------------------------------ crankLink
// linkage with thin, wide connection for crank side, full node height on other
module crankLink(len,dFlat,rHole) {
// changing crank spindle to a 3/16 spacer instead of the 1/8" brass tube
radA = AradFree;  // free spinning on 3/16 OD standoff
echo(str("rHole=",rHole));
difference() { union() {
   hull() { cylinder(h=NodeHeight/2,r1=radA+3,r2=radA+2.8,$fn=48);
      translate([dFlat+4,0,0]) cylinder(h=NodeHeight/2,r1=1.2,r2=1,$fn=6); }
   translate([len,0,0]) { hull() {
      cylinder(h=NodeHeight,r1=rHole+2.2,r2=rHole+2,$fn=48);
         translate([-rHole-4,0,0]) cylinder(h=BarHeight,r1=1.2,r2=1,$fn=6); }}
   hull() {                  cylinder(h=NodeHeight/2,r1=LinkRad+.4,r2=LinkRad,$fn=6);
      translate([len/2,0,0]) cylinder(h=NodeHeight/2,r1=LinkRad+.4,r2=LinkRad,$fn=6); }
   hull() { translate([dFlat-2,0,0]) cylinder(h=BarHeight,r1=LinkRad+.4,r2=LinkRad-.2,$fn=6);
            translate([len-2  ,0,0]) cylinder(h=BarHeight,r1=LinkRad+.4,r2=LinkRad-.2,$fn=6); }
   hull() {
      translate([dFlat+2  ,0,BarHeight-1]) scale([1,1,1.5]) sphere(r=1,$fn=12);
      translate([len-rHole,0,BarHeight-1]) scale([1,1,1.5]) sphere(r=1,$fn=12);
      translate([len*0.65 ,0,BarHeight+.5]){scale([0.6,0.6,1.7]) sphere(r=1,$fn=12);
         translate([0,0,-2]) scale([2,2,1]) sphere(r=1,$fn=12);}
      translate([dFlat+15 ,0,BarHeight+.5]){scale([0.6,0.6,1.7]) sphere(r=1,$fn=12);
         translate([0,0,-2]) scale([2,2,1]) sphere(r=1,$fn=12);}
      }
   }
   drillHole(radA);  // a little extra to move freely
   translate([len,0,0]) drillHole(rHole);
}}

module linkage1(len,h0,r0,d0,h1,r1,d1) { difference() { union() {
   hull() { barAnchor(1.5*r0);
      cylinder(h=h0,r1=r0+.2,r2=r0-0.2,$fn=48); }
   translate([len,0,0]) { hull() { barAnchor(-1.5*r1);
      cylinder(h=h1,r1=r1,r2=0.4*r1+0.6*d1,$fn=48); }}
   hull() {                cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6);
      translate([len,0,0]) cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6); }
   hull() {                   cylinder(h=h0-0.5,r1=2,r2=.6,$fn=6);
      translate([len-d1,0,0]) cylinder(h=h1-0.5,r1=2,r2=.6,$fn=6); }
   }
   drillHole(d0);
   translate([len,0,0]) drillHole(d1);
}}

module linkage(len,h0,r0,d0,h1,r1,d1) { difference() { union() {
echo(str("linkage:",len,",",h0,",",r0,",",d0,",",h1,",",r1,",",d1));
   hull() { barAnchor(2.5*r0);
      cylinder(h=h0,r1=r0+.1,r2=r0-0.2,$fn=48); }
   translate([len,0,0]) { hull() { barAnchor(-2.5*r1);
      cylinder(h=h1,r1=r1+.1,r2=r1-.2,$fn=48); }}
   hull() {                cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6);
      translate([len,0,0]) cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6); }
   hull() {                   cylinder(h=h0-0.5,r1=2,r2=.6,$fn=6);
      translate([len-d1,0,0]) cylinder(h=h1-0.5,r1=2,r2=.6,$fn=6); }
   }
   drillHole(d0);
   translate([len,0,0]) drillHole(d1);
}}

// beefier version of a simple linkage, with same ends on both sides
module brace(len,h0,r0) {
r1=r0+1.7;
difference() { union() {
   difference() { hull() { cylinder(h=3,r1=r1+.1,r2=r1-.1,$fn=48);
      translate([len,0,0]) cylinder(h=3,r1=r1+.1,r2=r1-.1,$fn=48); }
      translate([1.5,0,-1.5]) hull() { cylinder(h=3,r1=r1-1.6,r2=r1-1.4,$fn=6);
             translate([len-1.5,0,0])  cylinder(h=3,r1=r1-1.6,r2=r1-1.4,$fn=6); }}

   translate([len,0,0])
   hull() { cylinder(h=h0,r1=r1+.2,r2=r1-.1,$fn=48);
      translate([-r1-4,0,2]) sphere(r=1,$fn=12); }
   hull() { cylinder(h=h0,r1=r1+.2,r2=r1-.1,$fn=48);
      translate([ r1+4,0,2]) sphere(r=1,$fn=12); }

   translate([0,0,h0/2]) hull() { scale([1,1,h0/2]) sphere(r=1,$fn=12);
            translate([len,0,0])  scale([1,1,h0/2]) sphere(r=1,$fn=12); }

   }
   drillHole(r0);
   translate([len,0,0]) drillHole(r0);
}}

module crankArm(len,h0,r0,d0,h1,r1,d1) { difference() {
  linkage(len,h0,r0,d0,h1,r1,d1);

  //// add little hole for "cotter-wire" on crank arm
  //translate([0,0,h0/2]) rotate(a=[90,0,0])
  //   cylinder(h=3*r0,r=.8,$fn=80,center=true);

  // for change to using standoffs as axle, counter sink axle screw
  translate([0,0,h0-1.5]) cylinder(h=2+.2,r1=rad4,r2=3.3,$fn=24);

  // try another countersink for spindle screw.
  translate([len,0,-1]) cylinder(h=2.2,r1=3.3,r2=rad4,$fn=24);
}}

include <JansenBED.scad>;

//============================================ Parts with brim/pads underneath

module BED_pad(left,base,perp) { union() { color("Cyan") hull() {
  translate([-left,0,0]) footpad(11);
  translate([base-left,0,0]) footpad(11);
  translate([0,perp,0]) footpad(13);}
  translate([0,0,.2]) imBED(left,base,perp);
}}
module bracedFoot_pad(left,base,perp) { union() { color("Cyan") hull() {
  translate([-left,0,0]) footpad(17);
  translate([0,perp,0]) footpad(11);
  translate([base-left,0,0]) footpad(13); }
  translate([0,0,.2]) bracedFoot(left,base,perp);
}}
module crankLink_pad(len,dFlat,rHole) { union() { color("Cyan") hull() {
   footpad(13);
   translate([len,0,0]) footpad(13); }
   translate([0,0,.2]) crankLink(len,dFlat,rHole);
}}
module monoBracedLinkage_pad(len) { union() { color("Cyan") hull() {
   footpad(15);
   translate([len,0,0]) footpad(13); }
   translate([0,0,.2]) monoBracedLinkage(len);
}}
module linkage_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) linkage(len,h0,r0,d0,h1,r1,d1);
}}
module brace_pad(len,h0,r0) { union() { color("Cyan") hull() { translate([len,0,0])
   footpad(r0+7);
   footpad(r0+7); }
   translate([0,0,.2]) brace(len,h0,r0);
}}
module linkage1_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) linkage1(len,h0,r0,d0,h1,r1,d1);
}}
module crankArm_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) crankArm(len,h0,r0,d0,h1,r1,d1);
}}
module mainBar_pad(x,y) { union() { color("Cyan") hull() {
  translate([-x,0,0]) footpad(12);
  translate([ x,0,0]) footpad(12);
  }
  translate([0,0,.2]) mainBar(x,y);
}}

//---------------------
module BED(dLeft,dBase,dPerp) { union() { rotate([0,0,50]) {
   translate([dBase*0.2,-3*Drad,0]) rotate([0,0,180]) mirror([1,0,0])
   BED_pad(dLeft,dBase,dPerp);
   BED_pad(dLeft,dBase,dPerp);
}}}
module feet(dLeft,dBase,dPerp) { union() {
   translate([dBase*0.15,-0.5*dPerp,0]) rotate([0,0,190]) mirror([1,0,0])
   bracedFoot_pad(dLeft,dBase,dPerp);
   bracedFoot_pad(dLeft,dBase,dPerp);
}}
module crankLinks() {
spc=6;
union() {
   translate([0,spc*3.2,0])
     crankLink_pad(CH,15,Hrad);
     crankLink_pad(CH,15,Hrad);
   rotate([0,0,180]) {
     translate([-CD-1.5*spc, spc*1.6,0]) crankLink_pad(CD,15,Drad);
     translate([-CD-1.5*spc,-spc*1.6,0]) crankLink_pad(CD,15,Drad); }

   // tight holes to glue to axle, not spin
   translate([5*spc,-3.2*spc,0])
     crankArm_pad(AC,acH0,acOR,acIR,acH1,acOR,acIR);
}}
module EFs(len) {
spc=6;
union() {
  translate([len-spc, 1.9*spc,0]) rotate([0,0,180]) monoBracedLinkage_pad(len);
  translate([len-spc,-1.9*spc,0]) rotate([0,0,180]) monoBracedLinkage_pad(len);
  translate([0,-3.8*spc,0]) monoBracedLinkage_pad(len);
  monoBracedLinkage_pad(len);
}}
module BHs(len,h0,r0,d0,h1,r1,d1) {
spc = 2*Brad;
union() {
  translate([spc*1.1, 1.6*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
  translate([spc*1.1,-1.6*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
  translate([ 0     ,-3.2*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
                                  linkage1_pad(len,h0,r0,d0,h1,r1,d1);
}}

//=====================================================
use <spacers.scad>;

if      (PART=="BED"  ) {                   BED(DEleft,DE,DEperp); }
//else if (PART=="BEDa" ) {                 imBED(DEleft,DE,DEperp); }
//else if (PART=="BEDb" ) { mirror([1,0,0]) imBED(DEleft,DE,DEperp); }
else if (PART=="HipA" ) {                 BED1(DEleft,DE,DEperp); }
else if (PART=="HipB" ) { mirror([1,0,0]) BED1(DEleft,DE,DEperp); }
else if (PART=="jHipA" ) { imBEDj(DEleft,DE,DEperp); }
else if (PART=="jHipB" ) { mirror([1,0,0]) imBEDj(DEleft,DE,DEperp); }
else if (PART=="Feet" )                         feet(FGleft,FG,FGperp);
else if (PART=="FootA")
//difference() {
                  bracedFoot(FGleft,FG,FGperp);
  //  translate([0,0,18]) cube([200,200,20],center=true); }
else if (PART=="FootB") { mirror([1,0,0]) bracedFoot(FGleft,FG,FGperp); }
else if (PART=="crankLinks") crankLinks();
else if (PART=="CH"   ) crankLink(CH,15,Hrad); // build 2
else if (PART=="CD"   ) crankLink(CD,15,Drad); // build 2
else if (PART=="EF"   ) monoBracedLinkage(EF); // build 4
else if (PART=="EFs"  ) EFs(EF);
else if (PART=="BHs"  ) BHs(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4);
else if (PART=="BH"   ) linkage1(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4); // build 4, glue them together with a rectangle if desired
else if (PART=="AC"   ) crankArm(AC,acH0,acOR,acIR,acH1,acOR,acIR);
else if (PART=="halfPulley") { union() { color("Cyan") footpad(pulleyR+7);
       translate([0,0,.2]) halfPulley(pulleyR,2.5,AradTight,-1); }}
else if (PART=="halfDrivePulley") { union() { color("Cyan") footpad(15);
       translate([0,0,.1]) halfPulley(8,2.5,1.5+.3,1+.3); }}
else if (PART=="pulley_pad") { union() { footpad(23); translate([0,0,.2])
                            pulley(18,5,rad4,0); }}
else if (PART=="pulley") {  pulley(18,5,rad4,0); }
else if (PART=="drivePulley_pad") { union() { footpad(15); translate([0,0,.2])
                                pulley(10,4,1.5+dHoleFuzz,1+dHoleFuzz); }}
else if (PART=="drivePulley") { pulley(10,4,1.5+dHoleFuzz,1+dHoleFuzz); }
else if (PART=="mainBar") {  mainBar(Bx,Ay); }
else if (PART=="main") { mainBar_pad(Bx,Ay); }
else if (PART=="braceBar") {  brace(2*Bx,8,Brad); }
else if (PART=="brace") { brace_pad(2*Bx,8,Brad); }
else if (PART=="spacers") { union(){ spacers(NodeHeight/2,Bhole+3,Brad);
   translate([0,-7.5*LinkRad*1.414+1,0]) spacers(NodeHeight/2,LinkRad,rad4); }}
//else if (PART=="demo") { //show all unique parts
else {
   mainBar(Bx,Ay);
   #translate([0,Ay,20]) pulley(18,5,rad4,0);
   translate([0,-50,0])  pulley(10,4,1.5+.3,1+.3);
   translate([ 50, 30,0]) BED1(DEleft,DE,DEperp);//imBED(DEleft,DE,DEperp);
   translate([-26, 44,0]) rotate([0,0,180]) bracedFoot(FGleft,FG,FGperp);
   translate([-12,-16,0]) crankLink(CD,15,Drad);
   translate([-36,-28,0]) crankLink(CH,15,Hrad);
   translate([-73,-15,0]) monoBracedLinkage(EF);
   translate([-60, 15,0]) crankArm(AC,acH0,acOR,acIR,acH1,acOR,acIR);

   translate([ 25, 15,0]) linkage1(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4);
   translate([40,-42,0]) rotate([0,0,50]) brace(2*Bx,8,Brad);
}

// $URL: svn+ssh://mrwhat@ssh.boim.com/home/mrwhat/svn/Walker/trunk/Jansen.scad $
// $Id: Jansen.scad 427 2014-08-23 20:42:39Z mrwhat $

// Define PART to one of the following values to generate model for desired part.
//       HipA, HipB, FootA, FootB, CH, CD, EF, BH, AC, pulley, mainBar, drivePulley
// For a 2-leg (half-trotter) :  print (2) CH, CD ; (4) EF, BH ; (1) of the others
// For a production robot, glue a rectangular support/spacer between BH pairs for stiffness
//
// Combined parts with pads, optimized for RepRap :
// Hip, Feet, crankLinks, EFs, BHs    : main, pulley, drivePulley as above (brace)
PART="FootA";
hingeStyle = "spacer"; //6standoff";  // spacer or standoff
echo(str("PART=",PART));

HoleFuzz = 0.2;  // extra radius (mm) to add to holes to account for printer slop

// measured diameter of '3/16"' spacer was 4.74 to 4.76, not 4.7625 as expected.
// Current design:  3/16" axles at B
//                  3/16" long 1/4"  OD standoffs at D, E, F
//                  1/2"  long 3/16" OD standoffs at H, A, C
Bdiam = 4.7625;  // larger brass tube rdiameter, measured on 3/16" tube
Adiam = 4.76;
Hdiam = Adiam;
//Ddiam = 6.35;  // 1/4" OD standoffs
Ddiam = Adiam;  // 3/16" OD standoffs/spacers
diam4 = 2.76;  // diameter of #4-40 screw, OD of thread

// on spacer tests:
//    Brad +.125 mm was snug, but not quite free rotating
//         +.05     turned, but not freely
//         -.025    still turned,  was very close
//    Arad +.125    turned free (good for main, crankLinks)
//         +.05     was press-to-fit (good for crankArm)
//    rad4 + 0.2    allowed a screw to go through snugly but freely
//         +.125    only threaded through
//  1/4"OD + 0.2    was a snug fit, no turn.  almost press-to-fit
//         + 0.275  snug, free turn... good for hinges on standoff

Brad = Bdiam/2 + HoleFuzz/2;    // 4.76mm diam brass tube -- critical fit
Arad = Adiam/2 + HoleFuzz/2.3;  // 3.18mm diam brass tube -- critical fit
rad4 = diam4/2 + HoleFuzz;  // good for screw pass-through
Hrad = Hdiam/2 + HoleFuzz*1.35;  // standoff holes for freely-moving hinges
Drad = Ddiam/2 + HoleFuzz;
AradFree = Adiam/2 + .25;  // loose fit on spindle

BradTight = Brad-0.05;
BradFree  = Brad+0.05;

Frad = 7;  // radius of beefed-up "knee"

LinkRad=3;
BarHeight=3;
//NodeHeight=5.8;  // gives a little room for 6.35 mm (.25 inch) standoffs
layer1bias=0.4;  // shift up for 1 layer of brim/raft

// 9/16" spacer height 14.37mm, not 14.287 as expected
// 3/16" spacer height  4.79mm, not 4.7625 as expected (*3=14.37)
// 1/4" Al standoffs were pretty close, and 3x was 19.02mm high, not 19.05 as expected, pretty close
//TrueNodeHeight = (hingeStyle == "spacer") ? 4.79-.2 : 6.35;
TrueNodeHeight = 4.79-.2;
NodeHeight = TrueNodeHeight - 0.3;  // a little room for hinges
//NodeHeight3 = 25.4*((hingeStyle == "spacer") ? 9/16 : 3/4) - 0.3;
// moving to slightly thinner 1/2" standoffs at H
NodeHeight3 = 25.4/2 - 0.3;

// Forks should be 1 node thick for standoffs...  short screws go into variable length standoff.
// they should be 2 nodes thick for spacers, extra long so that ALL hinges are 5 nodes wide.
//ForkHeight = (hingeStyle == "spacer") ? 2*NodeHeight : NodeHeight;
ForkHeight = NodeHeight;

// definitions of linkage lengths: AC;Ay;Bx;BH;EF;CD;CH;BD;BE;DE;FG;FH;GH
// derived quantities: DEleft;FGleft;DEperp;FGperp
include <JansenDefs.scad>;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//       define some standard part dimensions for re-use in groups, etc.
acH0 = NodeHeight;
acH1 = acH0+2;
acOR = Arad+3;
acIR = rad4;
pulleyR = 17;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

module nodeCyl(nodeHeight,nodeRad)
{ cylinder(h=nodeHeight,r1=nodeRad+.3,r2=nodeRad-.3,$fn=64); }  // set to 20+ for production quality

module drillHole(holeRad) { translate([0,0,-.03])
   cylinder(h=22,r=holeRad,$fn=80); } // set to 80 for production run

module footpad(r) { // pad to help a part stick to plate for 3D printer
   color("Cyan") cylinder(h=layer1bias,r1=r,r2=r-.3,$fn=11); }

// place a point, usually inside a linkage bar, to use in a hull
// with a part connected to a linkage bar
module barAnchor(dx) {
   translate([dx,0,0]) cylinder(h=BarHeight,r1=.8,r2=.6,$fn=6);
}

use <pulley.scad>;

include <JansenMain.scad>
include <JansenFoot.scad>

module monoBracedLinkage(len) {
lro = Drad+1.8;  // outisde link radius
difference() { union() { //------------------------ EF
    difference() { hull() {  // main bar
      translate([ 0 ,0,0])   nodeCyl(BarHeight,Frad);
      translate([len,0,0])   nodeCyl(BarHeight,lro*.5);
      }
      hull() { translate([0,0,-1.5]) { nodeCyl(BarHeight,Frad-1.5);
               translate([len,0 ,0])   nodeCyl(BarHeight,1); }}
    }

    // non-braced (BED side) reinforcement
    translate(  [len,0,0]) { nodeCyl(BarHeight,lro);
       hull() { translate([0,0,BarHeight-1])
          cylinder(h=ForkHeight-BarHeight+1,r1=lro-.8,r2=rad4+1.2,$fn=64);
          cylinder(h=NodeHeight-1,r1=lro+.1,r2=rad4+1.2,$fn=16);
          //barAnchor(-1.5*lro);
          translate([-2*lro,0,2]) sphere(r=.4,$fn=12);
       }
    }
    hull() { translate([1.3*Frad,0,1.5]) scale([1,1,1]) sphere(r=1,$fn=16);
        translate([0,0,BarHeight-1])
          cylinder(h=ForkHeight-BarHeight+1,r1=Frad-.6,r2=rad4+1.6,$fn=64); }
    cylinder(h=BarHeight-1,r1=rad4+2.2,r2=rad4+3.3,$fn=32);

    hull() { // out-of-plane ridge/brace
        translate([ 0 ,0,2.2]) scale([1,1,2]) sphere(r=1,$fn=16);
        translate([len,0,2.2]) scale([1,1,2]) sphere(r=1,$fn=16); }
    }
    drillHole(rad4);
    translate([len,0,0]) drillHole(rad4);
}}

//------------------------------------------------------------ crankLink
// linkage with thin, wide connection for crank side, full node height on other
module crankLink(len,dFlat,rHole) {
// changing crank spindle to a 3/16 spacer instead of the 1/8" brass tube
radA = AradFree;  // free spinning on 3/16 OD standoff
echo(str("rHole=",rHole));
difference() { union() {
   hull() { cylinder(h=NodeHeight/2,r1=radA+3,r2=radA+2.8,$fn=48);
      translate([dFlat+4,0,0]) cylinder(h=NodeHeight/2,r1=1.2,r2=1,$fn=6); }
   translate([len,0,0]) { hull() {
      cylinder(h=NodeHeight,r1=rHole+2.2,r2=rHole+2,$fn=48);
         translate([-rHole-4,0,0]) cylinder(h=BarHeight,r1=1.2,r2=1,$fn=6); }}
   hull() {                  cylinder(h=NodeHeight/2,r1=LinkRad+.4,r2=LinkRad,$fn=6);
      translate([len/2,0,0]) cylinder(h=NodeHeight/2,r1=LinkRad+.4,r2=LinkRad,$fn=6); }
   hull() { translate([dFlat-2,0,0]) cylinder(h=BarHeight,r1=LinkRad+.4,r2=LinkRad-.2,$fn=6);
            translate([len-2  ,0,0]) cylinder(h=BarHeight,r1=LinkRad+.4,r2=LinkRad-.2,$fn=6); }
   hull() {
      translate([dFlat+2  ,0,BarHeight-1]) scale([1,1,1.5]) sphere(r=1,$fn=12);
      translate([len-rHole,0,BarHeight-1]) scale([1,1,1.5]) sphere(r=1,$fn=12);
      translate([len*0.65 ,0,BarHeight+.5]){scale([0.6,0.6,1.7]) sphere(r=1,$fn=12);
         translate([0,0,-2]) scale([2,2,1]) sphere(r=1,$fn=12);}
      translate([dFlat+15 ,0,BarHeight+.5]){scale([0.6,0.6,1.7]) sphere(r=1,$fn=12);
         translate([0,0,-2]) scale([2,2,1]) sphere(r=1,$fn=12);}
      }
   }
   drillHole(radA);  // a little extra to move freely
   translate([len,0,0]) drillHole(rHole);
}}

module linkage1(len,h0,r0,d0,h1,r1,d1) { difference() { union() {
   hull() { barAnchor(1.5*r0);
      cylinder(h=h0,r1=r0+.2,r2=r0-0.2,$fn=48); }
   translate([len,0,0]) { hull() { barAnchor(-1.5*r1);
      cylinder(h=h1,r1=r1,r2=0.4*r1+0.6*d1,$fn=48); }}
   hull() {                cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6);
      translate([len,0,0]) cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6); }
   hull() {                   cylinder(h=h0-0.5,r1=2,r2=.6,$fn=6);
      translate([len-d1,0,0]) cylinder(h=h1-0.5,r1=2,r2=.6,$fn=6); }
   }
   drillHole(d0);
   translate([len,0,0]) drillHole(d1);
}}

module linkage(len,h0,r0,d0,h1,r1,d1) { difference() { union() {
echo(str("linkage:",len,",",h0,",",r0,",",d0,",",h1,",",r1,",",d1));
   hull() { barAnchor(2.5*r0);
      cylinder(h=h0,r1=r0+.1,r2=r0-0.2,$fn=48); }
   translate([len,0,0]) { hull() { barAnchor(-2.5*r1);
      cylinder(h=h1,r1=r1+.1,r2=r1-.2,$fn=48); }}
   hull() {                cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6);
      translate([len,0,0]) cylinder(h=BarHeight,r1=LinkRad+.2,r2=LinkRad-.2,$fn=6); }
   hull() {                   cylinder(h=h0-0.5,r1=2,r2=.6,$fn=6);
      translate([len-d1,0,0]) cylinder(h=h1-0.5,r1=2,r2=.6,$fn=6); }
   }
   drillHole(d0);
   translate([len,0,0]) drillHole(d1);
}}

// beefier version of a simple linkage, with same ends on both sides
module brace(len,h0,r0) {
r1=r0+1.7;
difference() { union() {
   difference() { hull() { cylinder(h=3,r1=r1+.1,r2=r1-.1,$fn=48);
      translate([len,0,0]) cylinder(h=3,r1=r1+.1,r2=r1-.1,$fn=48); }
      translate([1.5,0,-1.5]) hull() { cylinder(h=3,r1=r1-1.6,r2=r1-1.4,$fn=6);
             translate([len-1.5,0,0])  cylinder(h=3,r1=r1-1.6,r2=r1-1.4,$fn=6); }}

   translate([len,0,0])
   hull() { cylinder(h=h0,r1=r1+.2,r2=r1-.1,$fn=48);
      translate([-r1-4,0,2]) sphere(r=1,$fn=12); }
   hull() { cylinder(h=h0,r1=r1+.2,r2=r1-.1,$fn=48);
      translate([ r1+4,0,2]) sphere(r=1,$fn=12); }

   translate([0,0,h0/2]) hull() { scale([1,1,h0/2]) sphere(r=1,$fn=12);
            translate([len,0,0])  scale([1,1,h0/2]) sphere(r=1,$fn=12); }

   }
   drillHole(r0);
   translate([len,0,0]) drillHole(r0);
}}

module crankArm(len,h0,r0,d0,h1,r1,d1) { difference() {
  linkage(len,h0,r0,d0,h1,r1,d1);

  //// add little hole for "cotter-wire" on crank arm
  //translate([0,0,h0/2]) rotate(a=[90,0,0])
  //   cylinder(h=3*r0,r=.8,$fn=80,center=true);

  // for change to using standoffs as axle, counter sink axle screw
  translate([0,0,h0-1.5]) cylinder(h=2+.2,r1=rad4,r2=3.3,$fn=24);

  // try another countersink for spindle screw.
  translate([len,0,-1]) cylinder(h=2.2,r1=3.3,r2=rad4,$fn=24);
}}

include <JansenBED.scad>;

//============================================ Parts with brim/pads underneath

module BED_pad(left,base,perp) { union() { color("Cyan") hull() {
  translate([-left,0,0]) footpad(11);
  translate([base-left,0,0]) footpad(11);
  translate([0,perp,0]) footpad(13);}
  translate([0,0,.2]) imBED(left,base,perp);
}}
module bracedFoot_pad(left,base,perp) { union() { color("Cyan") hull() {
  translate([-left,0,0]) footpad(17);
  translate([0,perp,0]) footpad(11);
  translate([base-left,0,0]) footpad(13); }
  translate([0,0,.2]) bracedFoot(left,base,perp);
}}
module crankLink_pad(len,dFlat,rHole) { union() { color("Cyan") hull() {
   footpad(13);
   translate([len,0,0]) footpad(13); }
   translate([0,0,.2]) crankLink(len,dFlat,rHole);
}}
module monoBracedLinkage_pad(len) { union() { color("Cyan") hull() {
   footpad(15);
   translate([len,0,0]) footpad(13); }
   translate([0,0,.2]) monoBracedLinkage(len);
}}
module linkage_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) linkage(len,h0,r0,d0,h1,r1,d1);
}}
module brace_pad(len,h0,r0) { union() { color("Cyan") hull() { translate([len,0,0])
   footpad(r0+7);
   footpad(r0+7); }
   translate([0,0,.2]) brace(len,h0,r0);
}}
module linkage1_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) linkage1(len,h0,r0,d0,h1,r1,d1);
}}
module crankArm_pad(len,h0,r0,d0,h1,r1,d1) { union() { color("Cyan") hull() {
   footpad(11);
   translate([len,0,0]) footpad(11); }
   translate([0,0,.2]) crankArm(len,h0,r0,d0,h1,r1,d1);
}}
module mainBar_pad(x,y) { union() { color("Cyan") hull() {
  translate([-x,0,0]) footpad(12);
  translate([ x,0,0]) footpad(12);
  }
  translate([0,0,.2]) mainBar(x,y);
}}

//---------------------
module BED(dLeft,dBase,dPerp) { union() { rotate([0,0,50]) {
   translate([dBase*0.2,-3*Drad,0]) rotate([0,0,180]) mirror([1,0,0])
   BED_pad(dLeft,dBase,dPerp);
   BED_pad(dLeft,dBase,dPerp);
}}}
module feet(dLeft,dBase,dPerp) { union() {
   translate([dBase*0.15,-0.5*dPerp,0]) rotate([0,0,190]) mirror([1,0,0])
   bracedFoot_pad(dLeft,dBase,dPerp);
   bracedFoot_pad(dLeft,dBase,dPerp);
}}
module crankLinks() {
spc=6;
union() {
   translate([0,spc*3.2,0])
     crankLink_pad(CH,15,Hrad);
     crankLink_pad(CH,15,Hrad);
   rotate([0,0,180]) {
     translate([-CD-1.5*spc, spc*1.6,0]) crankLink_pad(CD,15,Drad);
     translate([-CD-1.5*spc,-spc*1.6,0]) crankLink_pad(CD,15,Drad); }

   // tight holes to glue to axle, not spin
   translate([5*spc,-3.2*spc,0])
     crankArm_pad(AC,acH0,acOR,acIR,acH1,acOR,acIR);
}}
module EFs(len) {
spc=6;
union() {
  translate([len-spc, 1.9*spc,0]) rotate([0,0,180]) monoBracedLinkage_pad(len);
  translate([len-spc,-1.9*spc,0]) rotate([0,0,180]) monoBracedLinkage_pad(len);
  translate([0,-3.8*spc,0]) monoBracedLinkage_pad(len);
  monoBracedLinkage_pad(len);
}}
module BHs(len,h0,r0,d0,h1,r1,d1) {
spc = 2*Brad;
union() {
  translate([spc*1.1, 1.6*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
  translate([spc*1.1,-1.6*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
  translate([ 0     ,-3.2*spc,0]) linkage1_pad(len,h0,r0,d0,h1,r1,d1);
                                  linkage1_pad(len,h0,r0,d0,h1,r1,d1);
}}

//=====================================================
use <spacers.scad>;

if      (PART=="BED"  ) {                   BED(DEleft,DE,DEperp); }
//else if (PART=="BEDa" ) {                 imBED(DEleft,DE,DEperp); }
//else if (PART=="BEDb" ) { mirror([1,0,0]) imBED(DEleft,DE,DEperp); }
else if (PART=="HipA" ) {                 BED1(DEleft,DE,DEperp); }
else if (PART=="HipB" ) { mirror([1,0,0]) BED1(DEleft,DE,DEperp); }
else if (PART=="jHipA" ) { imBEDj(DEleft,DE,DEperp); }
else if (PART=="jHipB" ) { mirror([1,0,0]) imBEDj(DEleft,DE,DEperp); }
else if (PART=="Feet" )                         feet(FGleft,FG,FGperp);
else if (PART=="FootA")
//difference() {
                  bracedFoot(FGleft,FG,FGperp);
  //  translate([0,0,18]) cube([200,200,20],center=true); }
else if (PART=="FootB") { mirror([1,0,0]) bracedFoot(FGleft,FG,FGperp); }
else if (PART=="crankLinks") crankLinks();
else if (PART=="CH"   ) crankLink(CH,15,Hrad); // build 2
else if (PART=="CD"   ) crankLink(CD,15,Drad); // build 2
else if (PART=="EF"   ) monoBracedLinkage(EF); // build 4
else if (PART=="EFs"  ) EFs(EF);
else if (PART=="BHs"  ) BHs(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4);
else if (PART=="BH"   ) linkage1(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4); // build 4, glue them together with a rectangle if desired
else if (PART=="AC"   ) crankArm(AC,acH0,acOR,acIR,acH1,acOR,acIR);
else if (PART=="halfPulley") { union() { color("Cyan") footpad(pulleyR+7);
       translate([0,0,.2]) halfPulley(pulleyR,2.5,AradTight,-1); }}
else if (PART=="halfDrivePulley") { union() { color("Cyan") footpad(15);
       translate([0,0,.1]) halfPulley(8,2.5,1.5+.3,1+.3); }}
else if (PART=="pulley_pad") { union() { footpad(23); translate([0,0,.2])
                            pulley(18,5,rad4,0); }}
else if (PART=="pulley") {  pulley(18,5,rad4,0); }
else if (PART=="drivePulley_pad") { union() { footpad(15); translate([0,0,.2])
                                pulley(10,4,1.5+.3,1+.3); }}
else if (PART=="drivePulley") { pulley(10,4,1.5+.3,1+.3); }
else if (PART=="mainBar") {  mainBar(Bx,Ay); }
else if (PART=="main") { mainBar_pad(Bx,Ay); }
else if (PART=="braceBar") {  brace(2*Bx,8,Brad); }
else if (PART=="brace") { brace_pad(2*Bx,8,Brad); }
else if (PART=="spacers") { union(){ spacers(NodeHeight/2,Bhole+3,Brad);
   translate([0,-7.5*LinkRad*1.414+1,0]) spacers(NodeHeight/2,LinkRad,rad4); }}
//else if (PART=="demo") { //show all unique parts
else {
   mainBar(Bx,Ay);
   #translate([0,Ay,20]) pulley(18,5,rad4,0);
   translate([0,-50,0])  pulley(10,4,1.5+.3,1+.3);
   translate([ 50, 30,0]) BED1(DEleft,DE,DEperp);//imBED(DEleft,DE,DEperp);
   translate([-26, 44,0]) rotate([0,0,180]) bracedFoot(FGleft,FG,FGperp);
   translate([-12,-16,0]) crankLink(CD,15,Drad);
   translate([-36,-28,0]) crankLink(CH,15,Hrad);
   translate([-73,-15,0]) monoBracedLinkage(EF);
   translate([-60, 15,0]) crankArm(AC,acH0,acOR,acIR,acH1,acOR,acIR);

   translate([ 25, 15,0]) linkage1(BH,2.5*NodeHeight,Brad+1.8,BradFree,ForkHeight,Hrad+2,rad4);
   translate([40,-42,0]) rotate([0,0,50]) brace(2*Bx,8,Brad);
}


axis/carriage+extruder: wip

axis/carriage+extruder: wip

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
use <thing_libutils/bearing.scad>
use <thing_libutils/metric-screw.scad>

include <config.scad>

xaxis_carriage_bearing_distance = 8;
xaxis_carriage_padding = 2;
xaxis_carriage_mount_distance = 23;
xaxis_carriage_mount_offset_z = 0;
xaxis_carriage_teeth_height=xaxis_belt_width*1.5;
xaxis_carriage_mount_screws = ThreadM4;

xaxis_carriage_conn = [[0, -xaxis_bearing[1]/2 - xaxis_carriage_bearing_offset_y,0], [0,0,0]];

xaxis_carriage_beltfasten_w = 20;
module x_carriage_base()
{
    bottom_width = xaxis_bearing[2] + 2*xaxis_carriage_padding;
    top_width = xaxis_bearing[2]*2 + xaxis_carriage_bearing_distance + 2*xaxis_carriage_padding;
    thickness = xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_y;

    hull()
    {
        // top bearings
        translate([0,0,xaxis_rod_distance/2])
            cuberounda([top_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

        /*cuberounda([top_width,thickness,xaxis_rod_distance/2], align=[0,1,0]);*/

        // bottom bearing
        translate([0,0,-xaxis_rod_distance/2])
            cuberounda([bottom_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

    }
    translate([0,xaxis_bearing[1]/2+xaxis_carriage_bearing_offset_y+xaxis_carriage_beltpath_offset+.1,0])
    {
        translate([0,-xaxis_beltpath_width/2,0])
        for(x=[-1,1])
        translate([x*(xaxis_carriage_beltfasten_w/2+5),-xaxis_beltpath_width/2,xaxis_pulley_inner_d/2])
        cuberounda([xaxis_carriage_beltfasten_w,xaxis_beltpath_width,xaxis_beltpath_height/3], align=[0,0,-1]);
    }
}

module x_carriage_holes()
{
    for(i=[-1,1])
    translate([
            i*(xaxis_bearing[2]/2+xaxis_carriage_bearing_distance/2),
            xaxis_bearing[1]/2+xaxis_carriage_bearing_offset_y,
            xaxis_rod_distance/2
    ])
    {
        bearing_mount_holes(xaxis_bearing, orient=[1,0,0]);
        cubea([xaxis_bearing[2]*2,xaxis_bearing[1]/2+10,xaxis_bearing[1]+1*mm], align=[0,1,0]);
    }

    translate([
            0,
            xaxis_bearing[1]/2+xaxis_carriage_bearing_offset_y,
            -xaxis_rod_distance/2])
    {
        bearing_mount_holes(xaxis_bearing, orient=[1,0,0]);
        cubea([xaxis_bearing[2]*2,xaxis_bearing[1]/2+10,xaxis_bearing[1]+1*mm], align=[0,1,0]);
    }

    // Extruder mounting holes
    /*translate([0,0,xaxis_carriage_mount_offset_z])*/
    /*for(j=[-1,1])*/
    /*for(i=[-1,1])*/
    /*{*/
        /*translate([i*xaxis_carriage_mount_distance/2,0,j*xaxis_carriage_mount_distance/2])*/
        /*{*/
            /*screw_dia = lookup(ThreadSize, xaxis_carriage_mount_screws);*/
            /*cylindera(d=screw_dia, h=100, orient=[0,1,0]);*/
        /*}*/
    /*}*/

    translate([0,xaxis_carriage_beltpath_offset+.1,0])
    {
        // Cut clearing space for the belt
        /*translate([0,-xaxis_beltpath_width/2,-xaxis_beltpath_height/2])*/
            /*#cuberounda([500,xaxis_beltpath_width+1,5], align=[0,1,0], extrasize=[0,0,4], extrasize_align=[0,0,1]);*/

        translate([0,-xaxis_beltpath_width/2,0])
        {
            difference()
            {
                cuberounda([500,xaxis_beltpath_width*2,xaxis_beltpath_height], align=[0,1,0]);
                for(x=[-1,1])
                translate([x*(xaxis_carriage_beltfasten_w/2+5),-xaxis_beltpath_width/2,xaxis_pulley_inner_d/2])
                    cuberounda([xaxis_carriage_beltfasten_w,xaxis_beltpath_width*2,xaxis_beltpath_height/3], align=[0,1,-1]);
            }
        }

        /*belt_thickness=1.5;*/
        /*for(i=[-1,1])*/
            /*translate([i*30,0,0])*/
                /*cuberounda([15,xaxis_beltpath_width,15-belt_thickness], align=[0,0,0]);*/

        // Cut in the middle for belt
        /*cuberounda([7,xaxis_beltpath_width,xaxis_beltpath_height], align=[0,0,0]);*/

        /*translate([0,-xaxis_beltpath_width/2,xaxis_pulley_inner_d/2])*/
        /*{*/
            /*// Belt slit*/
            /*cuberounda([500,xaxis_beltpath_width,belt_thickness], align=[0,1,0]);*/

            /*[>// Teeth cuts<]*/
            /*[>teeth = 50;<]*/
            /*[>teeth_height = 2;<]*/
            /*[>translate([-belt_tooth_distance/2*teeth-.5,0,0])<]*/
            /*[>for(i=[0:teeth])<]*/
            /*[>{<]*/
                /*[>translate([i*belt_tooth_distance,0,0])<]*/
                    /*[>cubea([belt_tooth_distance*belt_tooth_ratio,xaxis_carriage_teeth_height,teeth_height], align=[0,0,-1]);<]*/
            /*[>}<]*/
        /*}*/
    }
}

extruder_gear_small_d_inner = 5.75*mm;
extruder_gear_big_d_inner = 29.35*mm;
extruder_gear_big_d_outer = 30.85*mm;
extruder_gear_big_h = [3.85*mm, 5*mm];

module extruder_gear_small()
{
    difference()
    {
        union()
        {
            hull()
            {
                cylindera(d=extruder_gear_small_d_inner, h=7*mm, orient=[0,1,0], align=[0,1,0]);
                cylindera(d=10*mm, h= 3*mm, orient=[0,1,0], align=[0,1,0]);
            }
            cylindera(d=extruder_gear_small_d_inner, h=13*mm, orient=[0,1,0], align=[0,1,0]);
        }
        cylindera(d=5*mm, h=13*mm+.1, orient=[0,1,0], align=[0,1,0]);
    }
}

module extruder_gear_big(align=[0,0,0], orient=[0,0,1])
{
    total_h = extruder_gear_big_h[0]+extruder_gear_big_h[1];
    size_align([extruder_gear_big_d_inner, extruder_gear_big_d_inner, total_h], align=align, orient=orient)
    translate([0,0,-extruder_gear_big_h[0] + total_h/2])
    difference()
    {
        union()
        {
            cylindera(d=extruder_gear_big_d_inner, h=extruder_gear_big_h[0], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=12*mm, h=extruder_gear_big_h[1], orient=[0,0,1], align=[0,0,-1]);
        }
        translate([0,0,-.5])
        cylindera(d=5*mm, h=total_h+.2, orient=[0,0,1], align=[0,0,0]);
    }
}

extruder_motor = dict_replace_multiple(Nema17,
        [
        [NemaLengthMedium, 11.75*mm],
        [NemaFrontAxleLength, 5*mm],
        ]);

extruder_shaft_d = 5*mm;
// dist between gear and motor
extruder_gear_motor_dist = .5*mm;

module motor_mount_cut(motor=Nema17, h=10*mm)
{
    screw_dist = lookup(NemaDistanceBetweenMountingHoles, motor);

    // round dia
    translate([0, .1, 0])
    cylindera(d=1.1*lookup(NemaRoundExtrusionDiameter, motor), h=h, orient=[0,1,0], align=[0,1,0]);

    // motor axle
    translate([0, .1, 0])
    cylindera(d=1.2*lookup(NemaAxleDiameter, motor), h=lookup(NemaFrontAxleLength, motor)+2*mm, orient=[0,1,0], align=[0,1,0]);

    // bearing for offloading force on motor shaft
    /*translate([0, -1*mm-xaxis_pulley[1]-.1, 0])*/
    scale(1.03)
    bearing(bearing_MR105, override_h=h, orient=[0,1,0], align=[0,-1,0]);

    motor_thread=ThreadM3;
    motor_nut=MHexNutM3;
    for(x=[-1,1])
    for(z=[-1,1])
    translate([x*screw_dist/2, -h, z*screw_dist/2])
    {
        if(x!=-1 || z!=-1)
        screw_cut(motor_nut, h=h, with_nut=false, orient=[0,1,0], align=[0,1,0]);
    }
}

function sinh(x) = (1 - pow(e, -2 * x)) / (2 * pow(e, -x));
function cosh(x) = (1 + pow(e, -2 * x)) / (2 * pow(e, -x));
function tanh(x) = sinh(x) / cosh(x);
function cot(x) = 1 / tan(x);

// 13t metal gear and 60t metal gear
extruder_gears_distance=extruder_gear_big_d_inner/2+extruder_gear_small_d_inner/2;

extruder_motor_angle = -80;
extruder_motor_offset_x = cos(extruder_motor_angle) * extruder_gears_distance;
extruder_motor_offset_z = sin(extruder_motor_angle) * extruder_gears_distance;
extruder_motor_holedist = lookup(NemaDistanceBetweenMountingHoles, extruder_motor);

extruder_gear_big_offset=[-extruder_motor_offset_x,0,extruder_motor_offset_z];

extruder_a_h = 14*mm;
module extruder_a(show_vitamins=false)
{
    difference()
    {
        hull()
        /*union()*/
        {
            side = 15*mm;
            cuberounda([extruder_motor_holedist+side/2,extruder_a_h,extruder_motor_holedist+side/2], align=[0,1,0]);
            /*hull()*/
            /*{*/
                /*for(x=[-1,1])*/
                /*for(z=[-1,1])*/
                /*translate([(extruder_motor_holedist/2)*x,0,(extruder_motor_holedist/2)*z])*/
                /*rotate([0,x*45,0])*/
                /*cuberounda([side/2,extruder_a_h,side/2], align=[0,1,0]);*/
            /*}*/
            translate(extruder_gear_big_offset)
            cylindera(d=extruder_gear_big_d_outer+3*mm, h=extruder_a_h, orient=[0,1,0], align=[0,-1,0]);
        }

        translate([0,extruder_a_h,0])
        {
            translate(extruder_gear_big_offset)
            {
                /*scale([1.3,2.0,1.3])*/
                /*#extruder_gear_big(orient=[0,-1,0], align=[0,-1,0]);*/

                // big gear cutout
                translate([0,-bearing_MR105[2]+.1,0])
                cylindera(d=extruder_gear_big_d_outer+1*mm, h=extruder_a_h+.2, orient=[0,1,0], align=[0,1,0]);

                translate([0,.1,0])
                cylindera(d=extruder_shaft_d+.5*mm, h=extruder_a_h+.2, orient=[0,1,0], align=[0,1,0]);

                translate([0,.1,0])
                scale(1.03)
                bearing(bearing_MR105, override_h=6*mm, orient=[0,1,0], align=[0,-1,0]);
            }

            motor_mount_cut(extruder_motor, h=extruder_a_h+1);
        }

    }

    if(show_vitamins)
    translate([0,extruder_a_h,0])
    {
        translate([0,-extruder_gear_motor_dist,0])
        {
            extruder_gear_small();

            // big gear
            translate(extruder_gear_big_offset)
            {
                translate([0,1,0])
                translate([0,-bearing_MR105[2]+.1,0])
                extruder_gear_big(orient=[0,-1,0], align=[0,-1,0]);

                translate([0,1,0])
                bearing(bearing_MR105, orient=[0,1,0], align=[0,-1,0]);

                translate([0,bearing_MR105[2],0])
                {
                    cylindera(h=60*mm, d=extruder_shaft_d, orient=[0,1,0], align=[0,1,0]);
                }
            }
        }
        motor(extruder_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
    }
}

// from E3D V6 heatsink drawing
// http://wiki.e3d-online.com/wiki/File:DRAWING-V6-175-SINK.png
// each entry == dia + h
hotmount_d_h=[[16*mm,3.7*mm],[12*mm,6*mm],[16*mm,3*mm]];
hotmount_outer_size_xy=max(vec_i(hotmount_d_h,0))+5*mm;
hotmount_outer_size_h=max(vec_i(hotmount_d_h,1))+5*mm;
hotmount_offset_h=-2*mm;
// which side does hotend slide in (x-axis, i.e. -1 is left, 1 is right)
hotmount_clamp_side=1;
hotmount_tolerance=1.05*mm;

// hotmount clamp screws distance from center
hotmount_clamp_thread = ThreadM3;
hotmount_clamp_nut = MHexNutM3;

hotmount_clamp_screw_dia = lookup(ThreadSize, hotmount_clamp_thread);
hotmount_clamp_screws_dist = hotmount_d_h[1][1] + 1.5*hotmount_clamp_screw_dia;
hotmount_clamp_pad = 0;
hotmount_clamp_thickness = 5*mm;
hotmount_clamp_y = 2*(hotmount_clamp_screws_dist + hotmount_clamp_screw_dia + hotmount_clamp_pad);
hotmount_clamp_height = hotmount_d_h[1][1];

module hotmount_cutout(extend_cut=false)
{
    // cutout of j-head/e3d heatsink mount
    heights=vec_i(hotmount_d_h,1);
    for(e=v_itrlen(hotmount_d_h))
    {
        hs=v_sum(heights,e-1);
        translate([0,0,-hs])
        {
            d=hotmount_d_h[e][0]*hotmount_tolerance;
            h=hotmount_d_h[e][1]*hotmount_tolerance;
            cylindera(d=d,h=h,align=[0,0,-1]);
            if(extend_cut)
            {
                cubea([extruder_b_w/2+1,d,h],align=[hotmount_clamp_side,0,-1]);
            }
        }
    }
}

module hotmount_clamp()
{
    difference()
    {
        union()
        {
            translate([extruder_b_w/2 * hotmount_clamp_side, 0, 0]);
            {
                cubea([hotmount_clamp_thickness, hotmount_clamp_y, hotmount_clamp_height], align=[-hotmount_clamp_side,0,0]);
            }

            difference()
            {
                translate([extruder_b_w/2 * hotmount_clamp_side, 0, 0]);
                {
                    cubea([extruder_b_w/2, hotmount_d_h[1][0], hotmount_clamp_height], align=[-hotmount_clamp_side,0,0]);
                }

                translate([(-extruder_b_w/2 * hotmount_clamp_side) + (-0.5*hotmount_clamp_side), 0, hotmount_d_h[0][1]+hotmount_d_h[1][1]/2])
                {
                    hotmount_cutout(extend_cut = false);
                }
            }

        }

        // clamp mount screw holes
        for(i=[-1,1])
        {
            translate([.1, i*hotmount_clamp_screws_dist, 0])
                rotate([0,90,0])
                cylindera(r=screw_m3[0], h=hotmount_clamp_thickness+.2, align=[0,0,-hotmount_clamp_side], extra_h=2);
        }
    }
}

extruder_guilder_bearing = bearing_625;
extruder_b_bearing = bearing_MR105;
module extruder_b(show_vitamins=false)
{
    translate(extruder_filapath_offset-[hobbed_gear_d_inner/2,0,0])
    {
        difference()
        {
            hull()
            {
                // gear support
                translate([0,-hobbed_gear_h/2,0])
                {
                    cylindera(d=hobbed_gear_d_outer+5*mm, h=abs(extruder_filapath_offset[1])+hobbed_gear_h/2, align=[0,-1,0], orient=[0,1,0]);

                    // bearing support
                    translate([0,-extruder_b_bearing[2]-5*mm,0])
                        cylindera(d=extruder_b_bearing[1]+5*mm, h=abs(extruder_filapath_offset[1]), align=[0,-1,0], orient=[0,1,0]);

                }
                // hotmount support
                translate([hobbed_gear_d_inner/2,0,-hobbed_gear_d_outer/2 + hotmount_offset_h])
                cubea([extruder_b_w, hotmount_outer_size_xy, hotmount_outer_size_h], align=[0,0,-1]);

                // clamp mount screw holes
                translate([hobbed_gear_d_inner/2,0,-hobbed_gear_d_outer/2 + hotmount_offset_h])
                for(i=[-1,1])
                {
                    translate([0, i*hotmount_clamp_screws_dist, -hotmount_d_h[0][1]-hotmount_d_h[1][1]/2])
                        rotate([0,90,0])
                        cylindera(r=screw_m3[0]+3*mm, h=extruder_b_w+1);
                }
            }
            translate([hobbed_gear_d_inner/2,0,-hobbed_gear_d_outer/2 + hotmount_offset_h])
            for(i=[-1,1])
            {
                translate([0, i*hotmount_clamp_screws_dist, -hotmount_d_h[0][1]-hotmount_d_h[1][1]/2])
                    rotate([0,90,0])
                    cylindera(r=screw_m3[0], h=extruder_b_w+10);
            }

            // filament path
            translate([hobbed_gear_d_outer/2,0,0])
            cylindera(h=1000, d=4*mm, orient=[0,0,1], align=[0,0,0]);

            cylindera(h=hobbed_gear_h, d=hobbed_gear_d_outer+1*mm, orient=[0,1,0], align=[0,0,0]);

            translate([0,-hobbed_gear_h/2-extruder_b_bearing[2]-.5*mm,0])
                scale([1.03,1,1.03])
                bearing(extruder_b_bearing, override_h=6*mm, orient=[0,1,0], align=[0,1,0]);

            translate([hobbed_gear_d_inner/2+extruder_guilder_bearing[1]/2,0,0])
                scale([1.03,1,1.03])
                {
                    cubea([extruder_guilder_bearing[1]+1*mm,extruder_guilder_bearing[2]+1*mm,extruder_guilder_bearing[1]*2], align=[0,0,1]);
                    cylindera(d=extruder_guilder_bearing[1]+1*mm, h=extruder_guilder_bearing[2]+1*mm, orient=[0,1,0], align=[0,0,0]);
                }

            translate([hobbed_gear_d_inner/2,0,-hobbed_gear_d_outer/2 - 2*mm])
            {
                hotmount_cutout(extend_cut=true);

                // clamp mount screw holes
                for(i=[-1,1])
                {
                    translate([0, i*hotmount_clamp_screws_dist, -hotmount_d_h[0][1]-hotmount_d_h[1][1]/2])
                        rotate([0,90,0])
                        cylindera(r=screw_m3[0], h=extruder_b_w+1);
                }

                translate([extruder_b_w/2 * (hotmount_clamp_side), 0, -hotmount_d_h[0][1]-hotmount_d_h[1][1]/2])
                {
                    cubea([hotmount_clamp_thickness+0.2, hotmount_clamp_y+0.2, hotmount_clamp_height+0.2], align=[-hotmount_clamp_side,0,0], extrasize=[1,0,0], extrasize_align=[hotmount_clamp_side,0,0]);
                }
            }
        }

        if(show_vitamins)
        {
            translate([hobbed_gear_d_inner/2,0,-hobbed_gear_d_outer/2 + hotmount_offset_h])
            translate([extruder_b_w/2,0,0])
            translate([0,0,-hobbed_gear_d_outer/2])
            hotmount_clamp();

            translate([0,-hobbed_gear_h/2-extruder_b_bearing[2]-.5*mm,0])
            {
                cylindera(h=extruder_a_h+extruder_offset_a[1]-extruder_filapath_offset[1], d=extruder_shaft_d, orient=[0,1,0], align=[0,-1,0]);

                bearing(extruder_b_bearing, orient=[0,1,0], align=[0,1,0]);
            }

            // hobbed gear
            cylindera(h=hobbed_gear_h, d=hobbed_gear_d_inner, orient=[0,1,0], align=[0,0,0]);
            for(y=[-1,1])
            translate([0,y*hobbed_gear_h/2,0])
            {
                cylindera(h=hobbed_gear_h/3, d=hobbed_gear_d_outer, orient=[0,1,0], align=[0,y,0]);
            }
        }
    }
}

hobbed_gear_d_outer = 12.65;
hobbed_gear_d_inner = 11.5;
hobbed_gear_h = 11;
extruder_offset = [0,0,10*mm];
extruder_offset_a = -extruder_gear_big_offset+[
    0,
    xaxis_bearing[1] + xaxis_carriage_bearing_offset_y + 1*mm,
    0];
extruder_filapath_offset = [hobbed_gear_d_inner/2, -15*mm, 0];

extruder_b_w = hobbed_gear_d_outer+10*mm;

// Final part
module x_carriage(show_bearings=true)
{
    difference()
    {
        /*hull()*/
        union()
        {
            x_carriage_base();
            translate(extruder_offset)
            translate(extruder_offset_a)
            {
                for(x=[-1,1])
                for(z=[-1,1])
                translate([x*extruder_motor_holedist/2,0,z*extruder_motor_holedist/2])
                cylindera(d=10*mm, h=extruder_offset_a[1], orient=[0,1,0], align=[0,1,0]);
            }
        }
        translate(extruder_offset)
        translate(extruder_offset_a)
        {
            for(x=[-1,1])
            for(z=[-1,1])
            translate([x*extruder_motor_holedist/2,0,z*extruder_motor_holedist/2])
            translate([0,.1,0])
            cylindera(d=3*mm, h=extruder_offset_a[1]+.2, orient=[0,1,0], align=[0,1,0]);
        }
        x_carriage_holes();
    }

    /*if(false)*/
    translate(extruder_offset)
    {
        extruder_b(show_vitamins=true);

        translate(extruder_offset_a)
        {
            %extruder_a(show_vitamins=true);
        }
    }

    //filament path
    %translate(extruder_filapath_offset)
        cylindera(h=1000, d=1.75*mm, orient=[0,0,1], align=[0,0,0]);

    hotend_conn =[[0,0,30],[0,0,1]];
    translate(extruder_offset)
    translate(extruder_filapath_offset)
    attach(extruder_conn_hotend, hotend_conn)
        rotate([90,0,270])
        import("stl/E3D_V6_1.75mm_Universal_HotEnd_Mockup.stl");

    if(show_bearings)
    {
        for(x=[-1,1])
        translate([
                x*(xaxis_carriage_bearing_distance+xaxis_bearing[2])/2,
                xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_y,
                xaxis_rod_distance/2
        ])
        bearing(xaxis_bearing, orient=[1,0,0]);

        translate([
                0,
                xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_y,
                -xaxis_rod_distance/2
        ])
        bearing(xaxis_bearing, orient=[1,0,0]);

        /*translate([0,xaxis_carriage_beltpath_offset,0])*/
        /*for(i=[-1,1])*/
        /*translate([i*100,0,0])*/
        /*pulley(xaxis_idler_pulley, orient=[0,1,0]);*/
    }
}

/*if(false)*/
{
/*extruder_a(show_vitamins=true);*/
    x_carriage();
}

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
use <thing_libutils/bearing.scad>

include <config.scad>

xaxis_carriage_bearing_distance = 8;
xaxis_carriage_padding = 2;
xaxis_carriage_mount_distance = 23;
xaxis_carriage_mount_offset_z = 0;
xaxis_carriage_teeth_height=xaxis_belt_width*1.5;
xaxis_carriage_mount_screws = ThreadM4;

xaxis_carriage_conn = [[0, -xaxis_bearing[1]/2 - xaxis_carriage_bearing_offset_z,0], [0,0,0]];

module x_carriage_base()
{
    bottom_width = xaxis_bearing[2] + 2*xaxis_carriage_padding;
    top_width = xaxis_bearing[2]*2 + xaxis_carriage_bearing_distance + 2*xaxis_carriage_padding;
    thickness = xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z;

    difference()
    {
        union()
        {
            hull()
            {
                // top bearings
                translate([0,0,xaxis_rod_distance/2])
                    cuberounda([top_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

                /*#cubea([top_width,xaxis_carriage_bearing_offset_z,xaxis_rod_distance/2], align=[0,1,0]);*/

                // bottom bearing
                translate([0,0,-xaxis_rod_distance/2])
                    cuberounda([bottom_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

            }

            translate([0,xaxis_carriage_beltpath_offset,0])
            {
                difference()
                {
                    translate([0,0,xaxis_pulley_inner_d/2])
                        cuberounda([50, xaxis_carriage_teeth_height, 10], align=[0,0,-1]);
                }
            }
        }

        translate([0,xaxis_carriage_beltpath_offset+.1,0])
        {
            // Cut clearing space for the belt
            translate([0,0,-xaxis_pulley_inner_d/2])
                cubea([500,xaxis_carriage_teeth_height,5], align=[0,0,0], extrasize=[0,0,4], extrasize_align=[0,0,1]);

            belt_thickness=1.5;
            for(i=[-1,1])
                translate([i*30,0,0])
                    cubea([15,xaxis_carriage_teeth_height,15-belt_thickness], align=[0,0,0]);

            // Cut in the middle for belt
            cubea([7,xaxis_carriage_teeth_height+.1,15], align=[0,0,0]);

            translate([0,0,xaxis_pulley_inner_d/2])
            {
                // Belt slit
                cubea([500,xaxis_carriage_teeth_height,belt_thickness], align=[0,0,0]);

                // Teeth cuts
                teeth = 50;
                teeth_height = 2;
                translate([-belt_tooth_distance/2*teeth-.5,0,0])
                for(i=[0:teeth])
                {
                    translate([i*belt_tooth_distance,0,0])
                        cubea([belt_tooth_distance*belt_tooth_ratio,xaxis_carriage_teeth_height,teeth_height], align=[0,0,-1]);
                }
            }

        }

    }
}

module x_carriage_holes()
{
    for(i=[-1,1])
    translate([i*(xaxis_bearing[2]/2+xaxis_carriage_bearing_distance/2),0,0])
    translate([0, xaxis_bearing[1]/2+xaxis_carriage_bearing_offset_z, xaxis_rod_distance/2])
    bearing_mount_holes(xaxis_bearing, orient=[1,0,0]);

    translate([0, xaxis_bearing[1]/2+xaxis_carriage_bearing_offset_z, -xaxis_rod_distance/2])
    bearing_mount_holes(xaxis_bearing, orient=[1,0,0]);

    // Extruder mounting holes
    translate([0,0,xaxis_carriage_mount_offset_z])
    for(j=[-1,1])
    for(i=[-1,1])
    {
        translate([i*xaxis_carriage_mount_distance/2,0,j*xaxis_carriage_mount_distance/2])
        {
            screw_dia = lookup(ThreadSize, xaxis_carriage_mount_screws);
            cylindera(d=screw_dia, h=100, orient=[0,1,0]);
        }
    }
}

// Final part
module x_carriage(show_bearings=true)
{
    difference()
    {
        x_carriage_base();
        x_carriage_holes();
    }

    if(show_bearings)
    {
        for(j=[-1,1])
        translate([0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z,0])
        translate([j*(xaxis_carriage_bearing_distance+xaxis_bearing[2])/2,0,0])
        translate([0, 0, xaxis_rod_distance/2])
                bearing(xaxis_bearing, orient=[1,0,0]);

        translate([0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z,0])
        translate([0, 0, -xaxis_rod_distance/2])
            bearing(xaxis_bearing, orient=[1,0,0]);

        translate([0,xaxis_carriage_beltpath_offset,0])
        for(i=[-1,1])
        translate([i*50,0,0])
        pulley(xaxis_idler_pulley, orient=[0,1,0]);
    }
}

if(false)
{
    x_carriage();
}


belt-fastener: minor cleanup in preview

belt-fastener: minor cleanup in preview

include <belt_fastener.h>
use <thing_libutils/screws.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/timing-belts.scad>

module belt_fastener(part, belt=TimingBelt_GT2_2, belt_width=6*mm, belt_dist=pulley_2GT_20T[2], width=55*mm, with_tensioner=true, align=N, orient=X)
{
    belt_t2 = belt_t2_thickness(belt) + .2*mm;
    tension_screw_nut = NutHexM3;
    tension_screw_thread = ThreadM3;
    tension_screw_dia = lookup(ThreadSize, tension_screw_thread);
    angle_screw_thread = ThreadM4;
    angle_screw_dia = 3.25*mm;
    height = belt_dist + belt_t2 + angle_screw_dia + 3*mm;
    slide_width=20*mm;
    depth = belt_width + 10*mm;

    s= [width, depth, height];
    size_align(size=s, orient=orient, align=align, orient_ref=-X)
    {
        if(part==undef)
        {
            difference()
            {
                belt_fastener("pos", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
                belt_fastener("neg", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
            }
            %belt_fastener("vit", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
        }
        else if(part=="pos")
        {
            hull()
            {
                translate(-belt_dist/2*Z)
                {
                    // support for belt path
                    rcubea([width, belt_width, belt_t2*2 + angle_screw_dia]);

                    translate(-belt_width*Y)
                    translate(-angle_screw_dia/2*Y)
                    rcubea([width, angle_screw_dia+2*mm, belt_t2*2 + angle_screw_dia]);
                }
            }
        }
        else if(part=="neg")
        {
            translate(-belt_dist/2*Z)
            if(with_tensioner)
            {
                translate([0,0,belt_t2/4])
                cubea(size=[1000, belt_width+.1, belt_t2], extra_size=1000*Y, extra_align=Y);

                /*translate([0,0,angle_screw_dia/2])*/
                {
                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*11*mm*X)
                        cylindera(d=angle_screw_dia+belt_t2, h=belt_width+.1, extra_h=1000, extra_align=Y, orient=Y);
                    }

                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*slide_width/2*X)
                        translate(-belt_width*Y)
                        translate(-angle_screw_dia*Y)
                        translate(-.1*Y)
                        cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=Y, align=Y);
                    }

                    translate(-belt_width*Y)
                    {
                        // cut for angle screw
                        translate(-1*mm*Y)
                        translate(-12*mm*X)
                        {
                            cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=X, align=X);
                            nut_trap_cut(nut=tension_screw_nut, screw_l=6*mm, cut_screw=true, orient=-X, trap_axis=Y);
                        }
                    }
                }

            }
            else
            {
                cubea([1000, belt_width+3*mm, belt_t2*1.8], extra_size=[0,1000,1*mm], extra_align=Y+Z);
            }

            translate(belt_dist/2*Z)
            cubea([1000, belt_width+3*mm, belt_t2*2], extra_size=1000*Y, extra_align=Y);
        }
        else if(part=="vit")
        {
            if(with_tensioner)
            {
                /*translate(-belt_dist/2*Z)*/
                /*translate(-belt_width*Y)*/
                /*translate(screw_offset_x*X)*/
                /*screw(nut=tension_screw_nut, h=25*mm, with_head=true, with_nut=false, head_embed=true, with_nut=false, orient=X, align=X);*/

                // 90 angle metal screw
                /*translate(screw_offset_x*X)*/
                translate(-belt_dist/2*Z)
                translate(-belt_width*Y)
                translate(-angle_screw_dia/2*Y)
                {
                    cylindera(d=angle_screw_dia+.2*mm, h=20*mm, orient=X, align=X);
                    cylindera(d=angle_screw_dia+.2*mm, h=11*mm, orient=Y, align=Y+X);
                }
            }
        }
    }
}

if(false)
{
    for(z=xaxis_beltpath_z_offsets)
    {
        tz(z)
        {
            ty(xaxis_carriage_beltpath_offset_y)
            tx(-main_width/2)
            rx(90)
            belt_path(main_width, xaxis_belt_width, xaxis_pulley_inner_d, orient=X, align=X);

            /*proj_extrude_axis(axis=-Y)*/
            ty(xaxis_carriage_beltpath_offset_y)
            mirror([0,0,sign(z)>1?1:0])
            mirror([sign(z)<1?1:0,0,0])
            belt_fastener();
        }
    }
}

include <belt_fastener.h>
use <thing_libutils/screws.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/timing-belts.scad>

module belt_fastener(part, belt=TimingBelt_GT2_2, belt_width=6*mm, belt_dist=pulley_2GT_20T[2], width=55*mm, with_tensioner=true, align=N, orient=X)
{
    belt_t2 = belt_t2_thickness(belt) + .2*mm;
    tension_screw_nut = NutHexM3;
    tension_screw_thread = ThreadM3;
    tension_screw_dia = lookup(ThreadSize, tension_screw_thread);
    angle_screw_thread = ThreadM4;
    angle_screw_dia = 3.25*mm;
    height = belt_dist + belt_t2 + angle_screw_dia + 3*mm;
    slide_width=20*mm;
    depth = belt_width + 10*mm;

    s= [width, depth, height];
    size_align(size=s, orient=orient, align=align, orient_ref=-X)
    {
        if(part==undef)
        {
            difference()
            {
                belt_fastener("pos", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
                belt_fastener("neg", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
            }
            %belt_fastener("vit", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
        }
        else if(part=="pos")
        {
            hull()
            {
                translate(-belt_dist/2*Z)
                {
                    // support for belt path
                    rcubea([width, belt_width, belt_t2*2 + angle_screw_dia]);

                    translate(-belt_width*Y)
                    translate(-angle_screw_dia/2*Y)
                    rcubea([width, angle_screw_dia+2*mm, belt_t2*2 + angle_screw_dia]);
                }
            }
        }
        else if(part=="neg")
        {
            translate(-belt_dist/2*Z)
            if(with_tensioner)
            {
                translate([0,0,belt_t2/4])
                cubea(size=[1000, belt_width+.1, belt_t2], extra_size=1000*Y, extra_align=Y);

                /*translate([0,0,angle_screw_dia/2])*/
                {
                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*11*mm*X)
                        cylindera(d=angle_screw_dia+belt_t2, h=belt_width+.1, extra_h=1000, extra_align=Y, orient=Y);
                    }

                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*slide_width/2*X)
                        translate(-belt_width*Y)
                        translate(-angle_screw_dia*Y)
                        translate(-.1*Y)
                        cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=Y, align=Y);
                    }

                    translate(-belt_width*Y)
                    {
                        // cut for angle screw
                        translate(-1*mm*Y)
                        translate(-12*mm*X)
                        {
                            cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=X, align=X);
                            nut_trap_cut(nut=tension_screw_nut, screw_l=6*mm, cut_screw=true, orient=-X, trap_axis=Y);
                        }
                    }
                }

            }
            else
            {
                cubea([1000, belt_width+3*mm, belt_t2*1.8], extra_size=[0,1000,1*mm], extra_align=Y+Z);
            }

            translate(belt_dist/2*Z)
            cubea([1000, belt_width+3*mm, belt_t2*2], extra_size=1000*Y, extra_align=Y);
        }
        else if(part=="vit")
        {
            if(with_tensioner)
            {
                /*translate(-belt_dist/2*Z)*/
                /*translate(-belt_width*Y)*/
                /*translate(screw_offset_x*X)*/
                /*screw(nut=tension_screw_nut, h=25*mm, with_head=true, with_nut=false, head_embed=true, with_nut=false, orient=X, align=X);*/

                // 90 angle metal screw
                /*translate(screw_offset_x*X)*/
                translate(-belt_dist/2*Z)
                translate(-belt_width*Y)
                translate(-angle_screw_dia/2*Y)
                {
                    cylindera(d=angle_screw_dia+.2*mm, h=20*mm, orient=X, align=X);
                    cylindera(d=angle_screw_dia+.2*mm, h=11*mm, orient=Y, align=Y+X);
                }
            }
        }
    }
}

if(false)
{
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    {
        translate([0, 0, z])
        {
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            translate([-main_width/2, 0, 0])
            rotate([90,0,0])
            belt_path(main_width, xaxis_belt_width, xaxis_pulley_inner_d, orient=X, align=X);

            proj_extrude_axis(axis=-Y)
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            mirror([0,0,sign(z)>1?1:0])
            /*mirror(X)*/
            belt_fastener();
        }
    }
}