Close

Firmware

A project log for Icepick Delta

A highly experimental open-source 3D printer with a rock bottom bill of materials

ttnTTN 12/13/2014 at 05:120 Comments

Since the Icepick-delta is a true non linear deltabot, it requires some math to move it. It turns out this has done this before (yay!). A big thank you to mzavatsky for writing the inverse kinematics code and bigdaveakers for making it so much easier to incorporate into marlin.

Replacing the delta functions in marlin_main.cpp and adding defines to configuration.h and we have results!

#ifdef DELTA

float f = BASE_SIDE;
float e = END_EFFECTOR_SIDE;
float rf = DELTA_ARM_LENGTH;
float re = DELTA_DIAGONAL_ROD;

const float sin120 = DELTA_SIN120;
const float cos120 = DELTA_COS120;

float x0;
float y0;
float z0;

// the function is called with like so at another point for the M665 gcode command: recalc_delta_settings(delta_radius, delta_diagonal_rod);
// for initial testing, this will be ignored

int delta_calcAngleYZ(float x0, float y0, float z0, float& theta)
{
float y1 = -0.5 * 0.57735 * f; // f/2 * tan 30
y0 -= 0.5 * 0.57735 * e; // shift center to edge
// z = a + b*y <-- what is this for?
float a = (x0*x0 + y0*y0 + z0*z0 +rf*rf - re*re - y1*y1)/(2*z0);
float b = (y1-y0)/z0;

// discriminant
float d = -(a+b*y1)*(a+b*y1)+rf*(b*b*rf+rf);

if (d < 0) return -1; // non-existing point

float yj = (y1 - a*b - sqrt(d))/(b*b + 1); // choosing outer point
float zj = a + b*yj;

theta = atan(-zj/(y1 - yj))*(180/DELTA_PI) + ((yj>y1)?180.0:0.0);

return 0;
}


void calculate_delta(float cartesian[3])
{
// inverse kinematics: (x0, y0, z0) -> (theta1, theta2, theta3)
// returned status: 0=OK, -1=non-existing position

float theta1 = 0.0;
float theta2 = 0.0;
float theta3 = 0.0;

x0 = cartesian[X_AXIS];
y0 = cartesian[Y_AXIS];
z0 = cartesian[Z_AXIS] - DELTA_HOME_POS;

int status = delta_calcAngleYZ(x0, y0, z0, theta1);

if (status == 0) status = delta_calcAngleYZ(x0*cos120 + y0*sin120, y0*cos120-x0*sin120, z0, theta2); // rotate coords to +120 deg
if (status == 0) status = delta_calcAngleYZ(x0*cos120 - y0*sin120, y0*cos120+x0*sin120, z0, theta3); // rotate coords to -120 deg

delta[X_AXIS] = -theta1;
delta[Y_AXIS] = -theta2;
delta[Z_AXIS] = -theta3;

}

That's a lot of math, just for one segment of a move. The Arduino calculates X number of segments per second, as defined in configuration.h. That's all fine and well, but with this much math, the Arduino can only handle 40 segments per second :(

At 40mm/sec, it would result in 1mm long segments. Much too large! The regular linear delta firmware such as the Rostock, can manage 200 segments per second on the Arduino mega.

What to do?

At this stage, I'm thinking optimize. I found a forum post by Jamesdanielv on replacing the square root function with the one he has posted. He claims it is 3 times faster, and is accurate within 3.5%. As an experiment, I replaced all square root function in the firmware with the faster one, this resulted in a new maximum segments per second: 50. A 20% increase. Not bad. Still far too slow.

I'm not comfortable replacing all square root functions. I'm unsure that the function will work in all cases after some members commented that it will not work in all cases (buffer overflows or something?). I may do some more investigation and use it later.

Next up we have the arctan function in the code, perhaps this can be sped up? Doing some googling, it appears a lookup table may be the answer..

Worst case scenario I could always upgrade to something with an ARM proccessor, but I'm reluctant, after all, the project goal is to develop a reprap with a rock bottom bill of materials.

To be continued..

Discussions