Close

Principle of operation

A project log for RigTig's Big 3D Printer

A DIY 3D printer (big volume, inexpensive, lightweight and portable).

rigtigRigTig 09/11/2016 at 11:580 Comments

Three motors provides three degrees of freedom (3DOF), so we hang the effector from 3 pieces of string. We know the length of each string, so how do we know where the effector is, in 3D cartesian space (i.e. x, y and z coordinates)? And if we are given the desired effector position in x, y and z coordinates, then how long should each piece of string be?

Essentially, the length of string from each motor to the effector is the radius of a sphere. The general solution for the intersection of the surfaces of three spheres results in two positions in cartesian space. We know which one to use simply because gravity has a predictable direction of pull. If you want to look at the mathematics in more detail, refer to the Wikipedia article on Trilateration (https://en.wikipedia.org/wiki/Trilateration).

Version 1.0 of the software uses a mathematical simplification of assuming all the motors (i.e. the top of the strings) are all in a plane parallel to the print surface. Effectively, this means the installation of each string motor needs to be at the same height from the floor as the other string motors.

We do have to choose a point to be the origin (x=0, y=0 and z=0) for the object being printed and we need to be consistent with the 3D printing convention that z increases up from the build surface. It seems best to have the origin for the object in the centre of the triangular base, so there is the need for a remapping from the mathematical reference axes to the object axes. Making the two sets of axes to be parallel means a simple arithmetic adjustment to map between the object space and the mathematical space.

We are using stepper motors, which lead to a software design choice to measure the length of each string in steps. The scale in the GCODE for the x, y and z coordinates is assumed to be in centimetres. So the code for converting between the lengths of the three strings and the z, y and z coordinates (in version 1.0) is as follows (for Arduino):

//------------------------------------------------------------------------------
// Forward Kinematics - turns lengths of string (in steps) into XYZ object coordinates
static void FK(long l1, long l2, long l3, float &x, float &y, float &z) {
#ifdef VERBOSE
Serial.println(F("FK"));
Serial.print(m1d); Serial.println(l1);
Serial.print(m2d); Serial.println(l2);
Serial.print(m3d); Serial.println(l3);
#endif
float a = l1 * um_per_step * 0.0001; // step * um/step * 0.0001 cm/um
float b = l2 * um_per_step * 0.0001;
float c = l3 * um_per_step * 0.0001; // step * um/step * 0.0001 cm/um



#ifdef VERBOSE
Serial.print(a); Serial.print(":");
Serial.print(b); Serial.print(":");
Serial.println(c);
#endif

x = (a*a - b*b + x2*x2)/(2*x2);
y = (a*a - c*c + x3*x3 - 2*x*x3 + y3*y3)/(2*y3);
z = sqrt(a*a - x*x - y*y);
x -= objx;
y -= objy;
z = objz -z;

// in object space
#ifdef VERBOSE
Serial.print(F("["));
Serial.print(x); Serial.print(",");
Serial.print(y); Serial.print(",");
Serial.print(z); Serial.println("]");
#endif

}

//------------------------------------------------------------------------------
// Inverse Kinematics - turns XYZ object coordinates into thread lengths l1,l2 & l3 in steps
static void IK(float x, float y, float z, long &l1, long &l2, long &l3) {
#ifdef VERBOSE
Serial.print(F("IK ["));
Serial.print(x); Serial.print(",");
Serial.print(y); Serial.print(",");
Serial.print(z); Serial.println("]");
#endif
// translate object coordinates into machine coordinates
float mx = x + objx;
float my = y + objy;
float mz = objz - z;

// find string lengths in steps, i.e. cm * 10000 um/cm / um/step
float mzmz = mz*mz;
l1 = floor( sqrt(mx*mx + my*my + mzmz) * 10000.0 / um_per_step );
l2 = floor( sqrt((mx-x2)*(mx-x2) + my*my + mzmz) * 10000.0 / um_per_step );
l3 = floor( sqrt((mx-x3)*(mx-x3) + (my-y3)*(my-y3) + mzmz) * 10000.0 / um_per_step );
#ifdef VERBOSE
Serial.print(m1d); Serial.println(l1);
Serial.print(m2d); Serial.println(l2);
Serial.print(m3d); Serial.println(l3);
#endif
}

Discussions