· Lecture 15: Machine Design/Mechanical Design

Lecture 15: May 1 - Hurray, 2013
Assignment:

Lecture Notes:

What We did:

The progress and result of Our combined efforts is documented in this page: here.

What I did:

I was assigned to investigate prior work and the math behind the polar bots

Math & Prior Work

The kind of plotter we are making a version of is called many things like "Polargraph", "vertical plotter", "drawbot", "wall plotter" etc. They are more or less all orperating on the same principle namely a couple of stepper motors extending or retracting a known amount of wire - which in turn makes the pen, attached to a hanging "gondola" move in an xy space defined by two polar coordinate systems rather than the normal cartesian coordinate system used in "normal" plotters. Contrary to an cartesian plotter, the polargraph is easily scalable just by altering the distance between the two steppers and the length of string available.
The math behind is a little more complicated because of the need to convert the cartesian coordinates of a "drawing" to the polar coordinated used by the "drawing robot".

There is a nice list on Makerblok with links to a lot of other Polargraphs/Drawbots here

Geometrically the math is simple enough - based on Phytagoras because the two point where the wire/string pivots and the place of the gondola describes simple triangles.
Marginally Clever (who calls their drawbot "Makelangelo") has a nice description (and a better drawing) of the math behind a polargraph here.


The length of string dispensed by the steppers depend on the amount of steps per revolution as well as the circumference of the bobbins which carry the strings. In our version the steppers are offset from the bobbins - but with a 1:1 gear ratio so that doesn't have to be delt with in the math.

We use the Fab Inventory steppers (PF35T-48L4) from Nippon Pulse. The datasheet for these can be found at jameco.com. They are only 48 steps per revolution (i.e. 7.5 degrees per step) but the electronics and code we use allow for microstepping so the resolution can be increased "in software" to give the necessary precision.
In our prototype the bobbins have a diameter of 15,75mm and they are spaced 45 centimeters apart - but this distance is further reduced with tacs so the "distance between steppers" are 360 milimeters.
Remembering the relation of the circumference to the radius (C=2*PI*r) gives us an alteration in string length of just above 1 mm per full step.
When winding string onto or off the bobbins - the circumference is altered. But since we use a very thin and strong fishing line (aka "Fireline"; a non-monofilament line) with a thickness of only 0,13mm with almost 2 kg break strength, almost no stretch and almost no "shape memory" - this alteration is considered negligible with respect to the needed precision.

As we are puny humans standing on the shoulders of giants we cobbled code together from Marginally Clevers drawbot (linked to above) and "Keerbot's" c-code: here

Since we need only to draw fixed "hardcoded" graphics (a small bell icon) in known positions on the drawing surface, our solution is even simpler.

The Keerbot's c-code version looks like this:

#include “stdio.h”
#include “math.h”
#define UPR ‘q’ // here ro define the key.
#define UPL 3
#define DOWNR 5
#define DOWNL 7
#define UP_CURSOR 9
#define DOWN_CURSOR 4
#define swap(a,b) t=a;a=b;b=t;

int main(int argc,char* argv[])
{
if(argc != 5 || strcmp(argv[1],”read_lines”))
{
printf(“error in command !! \n should be:<br>
 %s read_lines points_file serial_out_file distanse_between_nails\n”,argv[0]);
return -1;
}
FILE* f = fopen(argv[2],”r”);
FILE* fout = fopen(argv[3],”w”);
double nail_dis = atoi(argv[4]);
int last_rl = 0,last_rr = 0;
while(!feof(f))
{
int x1,y1,x2,y2,t;
int num = fscanf(f,”%d %d %d %d\n”,&x1,&y1,&x2,&y2);
if(num != 4)
{
printf(“error in line cordinates format !! should be lines of 1 y1 x2 y2\n”);
return -1;
}
int r_start = sqrt(x1*x1 + y1*y1);
int r_end = sqrt(x2*x2 + y2*y2);
if(r_start > r_end)
{
swap(r_start,r_end);
swap(x1,x2);
swap(y1,y2);
}
fprintf(fout,”%d”,UP_CURSOR);
double l_x = x1,l_y = y1;
for(int r = r_start;r < r_end; ++r)
{
double dx = x2 – x1;
double dy = y2 – y1;
double dr = sqrt(dx*dx + dy*dy);
double D = x1*y2 – x2*y1;

double cross_x1 = (D*dy + dx*sqrt(r*r*dr*dr – D*D))/(dr*dr);
double cross_y1 = y1 + dy*(cross_x1 – x1)/dx;

double cross_x2 = (D*dy – dx*sqrt(r*r*dr*dr – D*D))/(dr*dr);
double cross_y2 = y1 + dy*(cross_x2 – x1)/dx;

if((cross_x1 – l_x)*(cross_x1 – l_x) + (cross_y1 – l_y)*(cross_y1 – l_y) <
(cross_x2 – l_x)*(cross_x2 – l_x) + (cross_y2 – l_y)*(cross_y2 – l_y))
l_x = cross_x1,l_y = cross_y1;
else
l_x = cross_x2,l_y = cross_y2;

int rl = (int)sqrt(l_x*l_x + l_y*l_y);
int rr = (int)sqrt((l_x – nail_dis)*(l_x – nail_dis) + l_y*l_y);
for(;last_rl < rl;++last_rl)
fprintf(fout,”%d”,UPL);
for(;last_rl > rl;–last_rl)
fprintf(fout,”%d”,DOWNL);

for(;last_rr < rr;++last_rr)
fprintf(fout,”%d”,UPR);
for(;last_rr > rr;–last_rr)
fprintf(fout,”%d”,DOWNR);
if(r == r_start)
fprintf(fout,”%d”,DOWN_CURSOR);
}
}
return 0;
}

We had some problems compiling this, but eventually Maurice "De Programmer" came up with this:

	#include 
#include
#include /* atoi */

#define UPR 1 // here ro define the key. // motor 1
#define UPL 3 // motor 2
#define DOWNR 5 //motor 1
#define DOWNL 7 // motor2
#define UP_CURSOR 9 // servo
#define DOWN_CURSOR 4 // servo
#define swap(a,b) t=a;a=b;b=t;

float arrx[2] = {30.0f,1.0f};
float arry[2] = {1.0,30.0f};
double nail_dis = 30.00;
int last_rl = 0;
int last_rr = 0;
double t;
int r;
int j;
double cartesianStep = 0.1;
double machineStep=0.5; // length of minimum change in rope with one step of machine
// double nail_dis = 360.00;
// int last_rl = 0;
// int last_rr = 0;

int main(){

int i=0;
int r_start = sqrt(arrx[i]*arrx[i] + arry[i]*arry[i]); // distance of hypothenusa
printf("r_start: %d \n",r_start);
int r_end = sqrt(arrx[i+1]*arrx[i+1] + arry[i+1]*arry[i+1]); // distance of new hypothenusa
printf("r_end: %d \n",r_end);

double x1 = arrx[i];
printf("x1 %0.2f \n",x1);
double x2 = arrx[i+1];
printf("x2 %0.2f \n",x2);
double y1 = arry[i];
printf("y1 %0.2f \n",y1);
double y2 = arry[i+1];
printf("y2 %0.2f \n",y2);

// double changeInx = x2 - x1; // change in x
// printf("changeXLeft: %0.2f\n", changeInx);
// double changeIny = y2 - y1; //change in y
// printf("changeY: %0.2f\n", changeIny);
// double changeInxRight = (nail_dis-x2) - (nail_dis-x1); // change in x
//printf("changeXRight: %0.2f\n", changeInxRight);

// double relativeSpeed = fabs(changeInx)/fabs(changeIny);

double oldleftwirelength = sqrt(x1*x1+y1*y1);
double oldrightwirelength = sqrt((nail_dis-x1)*(nail_dis-x1)+y1*y1);

int totalCartesianSteps = fabs(x2-x1)/cartesianStep;
printf("totalCartesianSteps: %d",totalCartesianSteps);

for (j =0;j <=totalCartesianSteps;j++){

double changeInx = x2 - x1; // change in x
// printf("changeXLeft: %0.2f\n", changeInx);
double changeIny = y2 - y1; //change in y
//printf("changeY: %0.2f\n", changeIny);
double changeInxRight = (nail_dis-x2) - (nail_dis-x1); // change in x
// printf("changeXRight: %0.2f\n", changeInxRight);

double relativeSpeed = fabs(changeInx)/fabs(changeIny);

// move cartesian x and y with cartesianstep

if (changeInx>0) { x1 = x1 + cartesianStep;
// printf("x1-: ,%0.2f\n",x1);
}
else {x1 = x1 - cartesianStep;
// printf("x1+: ,%0.2f\n",x1);
}
// if cartesian x is negative then negative step else positive step
// move y in ratio to x

// if cartesian y is negative then negative steo else positive step
if (changeIny>0) {y1 = y1 + (cartesianStep/relativeSpeed);
// printf("y1-: ,%0.2f\n",y1);
}
else {y1 = y1 - (cartesianStep/relativeSpeed);
// printf("y1+: ,%0.2f\n",y1);
}
double newleftwirelength = sqrt(x1*x1+y1*y1);
double newrightwirelength = sqrt((nail_dis-x1)*(nail_dis-x1)+y1*y1);
if(newleftwirelength>oldleftwirelength){
if(fabs(newleftwirelength-oldleftwirelength) > machineStep){
printf(" ReleaseLeft\n");
oldleftwirelength = newleftwirelength;
}
}
if(newleftwirelength machineStep){
printf(" PullLeft\n");
oldleftwirelength = newleftwirelength;
}
}
if(newrightwirelength>oldrightwirelength){
if(fabs(newrightwirelength-oldrightwirelength) > machineStep){
printf(" ReleaseRight\n");
oldrightwirelength = newrightwirelength;
}
}
if(newrightwirelength machineStep){
printf(" PullRight\n");
oldrightwirelength = newrightwirelength;
}
}
// printf("oldleftwirelength: %0.2f:\n", oldleftwirelength);
// printf("newleftwirelength: %0.2f:\n", newleftwirelength);
// printf("oldrightwirelength: %0.2f:\n", oldrightwirelength);
// printf("newrightwirelength: %0.2f:\n", newrightwirelength);
// calculate move in leftrope
// move in leftrope is bigger than machinestep, make machine step
}
}

The Keerbot has the steppers on the gondola itself and does
not take into account the circumference of bobbins which our
solution has to. So our stringlength is modified by the ratio
of circumference to steps.


For reference the more involved Arduino-code for the Makelangelo (Marginally Clever) looks like: this.

Machine Building

Sadly I ended up ill and never get to participate in the actual building of the drawing robot. In order to make up for that I decided to build a Fabscan 100 line-laser scanner. I redrew the designfiles hosted on Github here:

The files where redrawn for 4 mm hdf (high density fiberboard) because the 5 mm mdf used in the original proved difficult to source locally.
The 4 mm designfiles are her:

Back and Middle

Bottom

Front

Laser- and Turntable-holder

Sides

These images show the assembly line and the finished 3D scanner. The hdf where cut on an Epilog Helix 40 Watt with settings of |DPI:600|Power:100%|Speed:10%|Freq:500|


The assembly line - almost Toyota LEAN environment
(the visually agile will see that I had to slaughter my Eggbot from last Easter to get the steppers)

The electronics and electromechanics are comprised of an Arduino Uno, a custom made shield (which is just a breakout board to a Polulu stepper driver), a power supply, a Polulu #1200 stepper motor and a Logitech C270 "HD" webcamera pulled apart.


The hardware of the Fabscan 100


The parts list call for Polulu #1200 steppers - they have a smooth axle - but the chassis demands a flattened axle - so I had to dremel one myself


The completed line laser scanner. It is plenty solid and stable in 4 mm MDF

The shield is documented here:
http://sebastian.setz.name/arduino/my-projekts/fabscanmod/

The shield was milled on a Roland MDX-20 using Fab Modules
This proved to be a bit difficult to get right. I had to use a 0.01" mill bit because the traces are so close - the shield is for the Arduino Uno. No matter what I did, a few of the traces would be messed up when generating the milling paths. In the end I hand annotated the layout png image in GIMP. This helped eventhough the traces now look a bit "artistic".

The settings used where:
Traces: 0.01" Bit, Error=0.1 px, 2D Z=-0.11, Speed=1.8 mm/s, Jog=1.0 mm
Holes and Cut: 1/32" bit, 2D Z= -1.5 mm, Error=0.1 px, Speed=4 mm/s

The bits are so fragile that I had to turn down the trawel speed otherwise they would break (yes I broke a bit - just a bit).


The milled shield for Arduino Uno

Soldering the simple shield was trivial this late in a Fab Academy year - it only has a few small components. The majority is headers and the Polulu stepper driver.

Getting the Roland to work was almost an assignment on its own. When I came home to Copenhagen Fablab some had already tried to get it to work with a PCI-E hardware serial port from Star Tech - who also does the USB to serial converter cable. The original cable from Roland had been "archived" because a lot of milling jobs had been ruined by what seemed to be communication errors. Sadly the PCI based card did not work any better. So I tried to find out why. I then found a pinout from Roland on their support forum and I used that to manufacture a cable from and old modem cable. This had no effect on communication problems. Then I bought the USB to serial cable which a lot of fablabs have had success with. When that came there where still problems with sending jobs to the Modela. I then found this page:
http://progmatter.com/drupal/?q=node/2
And then made another serial cable to connect the Star Tech converter cable with the Modela. I am happy to say that this works.

A couple of pictures from the long journey below.


The place for the correct pinout for connecting Star Tech USB to serial converter cable.


A job worth doing is a job worth doing well.


Finally! A micro milling machine that works.

At the moment we don't have a Mac in the Lab so its on a "loaner". We'll set it up on a Mac Mini. Next version, I will use better optics for laser line generating. The cheap one I used just has a plastic Fresnel lens. I will try to get hold of a proper optic "capped roof prism"/Powell lens - like the one seen here:
http://laserlineoptics.com/powell_primer.html