9-point bed levelling reprap firmware

In the dc42 fork of the reprap firmware, there is a 5 point bed levelling routine for traditional cartesian printers. However, my bed is relatively big and warped in weird ways. I needed more points to level the bed properly. I made the following changes to version 1.13 of David Crocker’s firmware to allow 9-point bed levelling, where the 9 points are arranged like this:

^
|   [P2]   [P3]   [P4]
|
Y  [P1]   [P8]   [P5]
|
|   [P0]   [P7]   [P6]
—————X————->

 

The coordinates need to be stated in the bed.g file in the order shown above (P0 -P8). The bed.g file will then have to contain the following lines, where xxx=x coordinate and yyy=y coordinate.

G30 P0 Xxxx Yyyy Z-99999

G30 P1 Xxxx Yyyy Z-99999

G30 P2 Xxxx Yyyy Z-99999

[…]

G30 P8 Xxxx Yyyy Z-99999 S9

A compiled version of firmware version 1.13beta1 with 9-point bed levelling can be found here (RepRapFirmware/Release/…:

RepRapFirmware-with-9-point-bed-levelling

In the move class (move.h) I changed the number of permitted corner points:

float baryXBedProbePoints[5];						// The X coordinates of the triangle corner points
float baryYBedProbePoints[5];						// The Y coordinates of the triangle corner points
float baryZBedProbePoints[5];						// The Z coordinates of the triangle corner points

to

float baryXBedProbePoints[9];						// The X coordinates of the triangle corner points
float baryYBedProbePoints[9];						// The Y coordinates of the triangle corner points
float baryZBedProbePoints[9];						// The Z coordinates of the triangle corner points

and added

private:
float Triangle9Z(float x, float y) const;					// Interpolate onto a triangular grid using 9 point calibration

In move.cpp I changed the BedTransform and InverseBedTransform functions. – I just added the case 9:, so that an S9 after the last G30 command in the bed.g file will use 9 points.

void Move::BedTransform(float xyzPoint[AXES]) const
{
	switch(numBedCompensationPoints)
	{
	case 0:
		break;

	case 3:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] + aX*xyzPoint[X_AXIS] + aY*xyzPoint[Y_AXIS] + aC;
		break;

	case 4:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] + SecondDegreeTransformZ(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;

	case 5:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] + TriangleZ(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;
	case 9:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] + Triangle9Z(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;
	default:
		reprap.GetPlatform()->Message(GENERIC_MESSAGE, "BedTransform: wrong number of sample points.");
	}
}

// Invert the bed transform BEFORE the axis transform
void Move::InverseBedTransform(float xyzPoint[AXES]) const
{
	switch(numBedCompensationPoints)
	{
	case 0:
		break;

	case 3:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] - (aX*xyzPoint[X_AXIS] + aY*xyzPoint[Y_AXIS] + aC);
		break;

	case 4:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] - SecondDegreeTransformZ(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;

	case 5:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] - TriangleZ(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;
	case 9:
		xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] - Triangle9Z(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
		break;
	default:
		reprap.GetPlatform()->Message(GENERIC_MESSAGE, "InverseBedTransform: wrong number of sample points.");
	}
}

and added the 9 point triangle interpolation.

float Move::Triangle9Z(float x, float y) const
{
	for (size_t i = 0; i < 8; i++)
	{
		size_t j = (i + 1) % 8;
		float l1, l2, l3;
		BarycentricCoordinates(i, j, 8, x, y, l1, l2, l3);
		if (l1 > TRIANGLE_ZERO && l2 > TRIANGLE_ZERO && l3 > TRIANGLE_ZERO)
		{
			return l1 * baryZBedProbePoints + l2 * baryZBedProbePoints[j] + l3 * baryZBedProbePoints[8];
		}
	}
	reprap.GetPlatform()->Message(GENERIC_MESSAGE, "Triangle interpolation: point outside all triangles!\n");
	return 0.0;
}

Lastly I added the Probe Bed Equation:

void Move::SetProbedBedEquation(size_t numPoints, StringRef& reply)
{
	switch(numPoints)
	{
	case 3:
		/*
		 * Transform to a plane
		 */

		{
			float x10 = xBedProbePoints[1] - xBedProbePoints[0];
			float y10 = yBedProbePoints[1] - yBedProbePoints[0];
			float z10 = zBedProbePoints[1] - zBedProbePoints[0];
			float x20 = xBedProbePoints[2] - xBedProbePoints[0];
			float y20 = yBedProbePoints[2] - yBedProbePoints[0];
			float z20 = zBedProbePoints[2] - zBedProbePoints[0];
			float a = y10 * z20 - z10 * y20;
			float b = z10 * x20 - x10 * z20;
			float c = x10 * y20 - y10 * x20;
			float d = -(xBedProbePoints[1] * a + yBedProbePoints[1] * b + zBedProbePoints[1] * c);
			aX = -a / c;
			aY = -b / c;
			aC = -d / c;
		}
		break;

	case 4:
		/*
		 * Transform to a ruled-surface quadratic.  The corner points for interpolation are indexed:
		 *
		 *   ^  [1]      [2]
		 *   |
		 *   Y
		 *   |
		 *   |  [0]      [3]
		 *      -----X---->
		 *
		 *   These are the scaling factors to apply to x and y coordinates to get them into the
		 *   unit interval [0, 1].
		 */
		xRectangle = 1.0 / (xBedProbePoints[3] - xBedProbePoints[0]);
		yRectangle = 1.0 / (yBedProbePoints[1] - yBedProbePoints[0]);
		break;

	case 5:
		for (size_t i = 0; i < 4; i++)
		{
			float x10 = xBedProbePoints[i] - xBedProbePoints[4];
			float y10 = yBedProbePoints[i] - yBedProbePoints[4];
			float z10 = zBedProbePoints[i] - zBedProbePoints[4];
			baryXBedProbePoints[i] = xBedProbePoints[4] + 2.0 * x10;
			baryYBedProbePoints[i] = yBedProbePoints[4] + 2.0 * y10;
			baryZBedProbePoints[i] = zBedProbePoints[4] + 2.0 * z10;
		}
		baryXBedProbePoints[4] = xBedProbePoints[4];
		baryYBedProbePoints[4] = yBedProbePoints[4];
		baryZBedProbePoints[4] = zBedProbePoints[4];
		break;

	case 9:
		for (size_t i = 0; i < 8; i++) { float x10 = xBedProbePoints[i] - xBedProbePoints[8]; float y10 = yBedProbePoints[i] - yBedProbePoints[8]; float z10 = zBedProbePoints[i] - zBedProbePoints[8]; baryXBedProbePoints[i] = xBedProbePoints[8] + 2.0 * x10; baryYBedProbePoints[i] = yBedProbePoints[8] + 2.0 * y10; baryZBedProbePoints[i] = zBedProbePoints[8] + 2.0 * z10; } baryXBedProbePoints[8] = xBedProbePoints[8]; baryYBedProbePoints[8] = yBedProbePoints[8]; baryZBedProbePoints[8] = zBedProbePoints[8]; break; default: reprap.GetPlatform()->MessageF(GENERIC_MESSAGE, "Bed calibration error: %d points provided but only 3, 4, 5 and 9 supported\n", numPoints);
		return;
	}

The bed.g file contains the following points P0-P8:

^
| [2] [3] [4]
|
Y[1] [8] [5]
|
| [0] [7] [6]
———–X———>

9 point calculation is initiated by G30 P8 Xxxx Yyyy Z-99999 S9
where xxx and yyy are the respective coordinates of P8.

Posted in 3D Printing.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.