In previous posts I built a prototype ‘TandemB’ which can be thought of as a 2D Delta printer in terms of its x and y-axis movement. This prototype could be moved about under its own power but that had no compatible firmware to drive it. In this post I cover the firmware modifications required to make the Tandem move using normal g-code commands. You can find a copy of this modified firmware here.

## Modifying Marlin

**Note**: *If you are considering doing any major modifications to firmware beyond just editing the config files I highly recommend exploring options other than the standard arduino code editor. I have been using the free community edition Visual Studio 2013 to view, modify and upload the firmware and it is a big improvement. Visual studio actively monitors the #define statements and then greys out any code that is not defined. ie: definitions that have been commented out. This makes skimming through the code much quicker as around 80% of what’s there is not in use for any one setup and so is greyed out. The tabs are also much easier to view, search and organise and I find the the compiling errors are simpler to find and diagnose. If you would like to use VS then you will also need VisualMicro for arduino support.*

Marlin firmware was modified to work with my Tandem setup due to its compartmentalised nature and the fact that Craig Bossard had already started to make the very changes I needed. Craig would like to use scavenged flatbed scanner parts to build a 3D printer in the same manner as the Tandem and so had already been modifying Marlin to this end before I even started working on the Tandem idea. So thanks Craig for sending me a copy of you modified Marlin as it gave me a great starting point!

Craig’s idea was that rather than re-writing a lot of code it would be far simpler to modify the existing Delta reverse kinematics. The required changes all take place in marlin.main.cpp.

The original Delta kinematic equations from marlin.main are shown below:

void recalc_delta_settings(float radius, float diagonal_rod)

{

delta_tower1_x= -SIN_60*radius; // front left tower

delta_tower1_y= -COS_60*radius;

delta_tower2_x= SIN_60*radius; // front right tower

delta_tower2_y= -COS_60*radius;

delta_tower3_x= 0.0; // back middle tower

delta_tower3_y= radius;

delta_diagonal_rod_2= sq(diagonal_rod);

}

void calculate_delta(float cartesian[3])

{

delta[X_AXIS] = sqrt(delta_diagonal_rod_2

– sq(delta_tower1_x-cartesian[X_AXIS])

– sq(delta_tower1_y-cartesian[Y_AXIS])

) + cartesian[Z_AXIS];

delta[Y_AXIS] = sqrt(delta_diagonal_rod_2

– sq(delta_tower2_x-cartesian[X_AXIS])

– sq(delta_tower2_y-cartesian[Y_AXIS])

) + cartesian[Z_AXIS];

delta[Z_AXIS] = sqrt(delta_diagonal_rod_2

– sq(delta_tower3_x-cartesian[X_AXIS])

– sq(delta_tower3_y-cartesian[Y_AXIS])

) + cartesian[Z_AXIS];

This code works off the delta tower definitions which is also located in marlin.main.cpp and is shown below:

#ifdef DELTA

float delta[3] = { 0, 0, 0 };

#define SIN_60 0.8660254037844386

#define COS_60 0.5

// these are the default values, can be overriden with M665

float delta_radius = DELTA_RADIUS;

float delta_tower1_x = -SIN_60 * delta_radius; // front left tower

float delta_tower1_y = -COS_60 * delta_radius;

float delta_tower2_x = SIN_60 * delta_radius; // front right tower

float delta_tower2_y = -COS_60 * delta_radius;

float delta_tower3_x = 0; // back middle tower

float delta_tower3_y = delta_radius;

float delta_diagonal_rod = DELTA_DIAGONAL_ROD;

float delta_diagonal_rod_2 = sq(delta_diagonal_rod);

float delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;

#endif

Using the code above as a basis I constructed an excel spreadsheet that modeled the delta kinematics (copy here) so as to allow me to make changes to the equations and see the results in real time. *Note that excel does not allow you to plot an xyz three dimensional scatter plot and so if you want to visualise the results you will need to use a third party program such as Origin Pro.*

By removing one tower completely, and then redefining the z-axis to behave as the y-axis the changes were complete. A spreadsheet that models the tandem kinematics and plots the required carriage position can be found here.

The new kinematic equations in marlin for the tandem setup are shown below:

void recalc_delta_settings(float radius, float diagonal_rod)

{

delta_tower1_x = -radius; // front left tower

delta_tower2_x = radius; // front right tower

delta_diagonal_rod_2 = sq(diagonal_rod);

}

void calculate_delta(float cartesian[2])

{

delta[X_AXIS] = (sqrt(delta_diagonal_rod_2 – sq(delta_tower1_x – cartesian[X_AXIS])) + cartesian[Y_AXIS]);

delta[Y_AXIS] = sqrt(delta_diagonal_rod_2 – sq(delta_tower2_x – cartesian[X_AXIS])) + cartesian[Y_AXIS];

delta[Z_AXIS] = cartesian[Z_AXIS];

and the new tower definitions:

#ifdef DELTA

float delta[3] = { 0, 0, 0 };

#define SIN_60 0.8660254037844386

#define COS_60 0.5

// these are the default values, can be overriden with M665

float delta_radius = DELTA_RADIUS;

float delta_tower1_x = -delta_radius; // front left tower

float delta_tower2_x = delta_radius; // front right tower

float delta_diagonal_rod = DELTA_DIAGONAL_ROD;

float delta_diagonal_rod_2 = sq(delta_diagonal_rod);

float delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;

#endif

For now I have left the homing code unchanged as it seems to be working fine. The only other changes were to configuration.h. Here the normal delta definitions are as follows:

// Center-to-center distance of the holes in the diagonal push rods.

#define DELTA_DIAGONAL_ROD 175.0 // mm

// Horizontal offset from middle of printer to smooth rod center. Adjust this to calibrate x-axis distance for tandem setup.

#define DELTA_SMOOTH_ROD_OFFSET 118.0 // mm

// Horizontal offset of the universal joints on the end effector.

#define DELTA_EFFECTOR_OFFSET 0.0 // mm

// Horizontal offset of the universal joints on the carriages.

#define DELTA_CARRIAGE_OFFSET 0.0 // mm

As there is no effector or carriage offset both of these values were set to zero. The DELTA_DIAGONAL_ROD distance was set to the length of the arms (175.0mm) and the DELTA_SMOOTH_ROD_OFFSET was originally set to half half the distance separating the smooth rods, just as you would in a normal delta. The result of these setting is shown below where an upscaled 40mm cube print is being dry run with a pen acting as a pen plotter.

Its clear that the cube outline is neither symmetrical or square.

In a norma Delta configuration each carriage has two parallel arms connecting it to the end effector in such a way that the resulting parallelogram prevents the tool head from moving in any direction other than parallel to the print surface. For the TandemB setup only two arms in total are used and therefore no such parallelogram exists. It is because of this, and the fact the tool head is not directly positioned where the centre pivot is located, that we are seeing this curvature. The solution turned out to be as simple as adjusting the DELTA_SMOOTH_ROD_OFFSET from 118.0 down to 89.5 which was determined by trial and error but is something that should also be derivable mathematically. After this adjustment I can now trace cubes that are almost square.

Hopefully some fine tuning of the carriage homing positions and the tool head location is all thats now needed to make it perfect.

In the video below you can again see an upscaled ’40mm’ cube that has been stretched so as to fill the available build area and had the first layers removed so that the infill is now being drawn first.

Its far from perfect, but its a good start.

As expected, there is quite a lot of play in the z-axis (vertical) direction during rapid direction changes. This is not a problem when using a pen, as the pen acts to support itself as it pushes against the surface its drawing on. However, it will be a massive problem for a 3d printer and so needs to be addressed. I have a few ideas of how to solve this problem without reverting to the potentially much slower ‘TandemC’ design shown here and these ideas may even remove the need for any smooth rods in the whole design. More to come soon.