Rotary 3D Printing
Using an Open 5X Voron V0 and Meta Gcode to print spirals and more!
Rotary 3d printing
Adding one or more rotary axes to a traditional 3d printer opens up a wide range of opportunities for part design that are not available in traditional 2.5D printing. One of those is printing on a cylindrical or cylinder like object. This is a different way of thinking about constructing objects, for example here is a “propeller” like structure printed on a twisted 6 faced base:
The Open5X project has dramatically reduced the cost of MultiAxis printing, providing a modification path for machines like the Prusa Mk3, the E3D and Jubilee Toolchangers and the Voron V0. More recent work at Loughborough University has further reduced the barrier to entry with a simple 4 axis modification to low cost machines.
As further experiment in multi axis printing, we have been printing on printed cylinders, using toolpaths generated using RepRapFirmware Meta G-code. Meta G-code, designed and implemented by Duet3D is a simple but powerful extension of G-code that allows for programming constructs such as variables, loops and conditional statements. These small but powerful gcode programs can define quite complex behaviour for the machine, or in this case the toolpath for an object, without a slicer or other toolpath generator.
Here is a spiral printed on a printed cylinder using just a few lines of gcode:
The gcode for the printed cylinder is:
var mandrelR=5;
var mH=50;
var lH=0.5
var mStartZ=var.lH
var mRots={var.mH/var.lH}
G1 Y-60 F7000
G1 B0 F2000
G1 Z{var.mStartZ+5} X{var.mandrelR} Y-55 F5000
G1 X{var.mandrelR} Y0 Z1 F5000
G1 Z{var.mStartZ}
G92 C0
G1 C{var.mRots*360} Z{var.mH} E{var.mRots*12} F9
G92 C0
G1 Y-57 F7000
If you don’t want to use the variables to generalise printing cylinders, you could just send:
G1 C36000 Z50 E1200 F9
What is happening is a spiral is being printed from the start Z height, which is set to the “layer height” of 0.5, up to Z 50, with 100 rotations, to print a 50mm high cylinder with the diameter of the X offset, in this case 5mm. This diameter is actually 5mm + the extusion width which in this case is ~0.8mm. The gcode for the spiral printed on the cylinder is:
var pitch=3;
var startX=12
var rots=12
var endX=var.startX+var.pitch*var.rots
var startZ=5.8
var zStep=0.4
var zPasses=50
var eRot=11
var fr=8
G1 Y-60 F7000
G1 B90 F2000
G1 Z{var.startZ+5} X{var.startX} Y-55 F5000
G1 X{var.startX} Y0 F7000
while iterations<var.zPasses
set var.startX={var.startX+0.2}
set var.endX={var.endX+0.2}
var currentZ=var.startZ+var.zStep*iterations
var scale=(1+(var.currentZ-var.startZ)/(var.startZ))
G1 Z{var.currentZ} F5000
G92 C0 E0
var dir = (mod(iterations,2)=0)?-1:1
var currentEndX=((var.dir>0)?var.startX:var.endX)
G1 C{-360*var.rots*var.dir} X{var.currentEndX} E{var.scale*var.eRot*var.rots} F{var.fr/var.scale}
;echo "C move: "^{-360*var.rots*var.dir}^" xmove: "^var.currentEndX ^" rots: "^var.rots
G92 C0 E0
G1 Y-55 F5000
Note the ”eRotCurrent” variable scales the amount of extrusion per layer so that the extrusion/mm is constant as the diameter of the spiral increases. Also in every iteration the spiral is shifted slightly forward to get a slight conical shape.
Adding some conditional statements to the gcode allows us to lean the spiral path forward to start with, then backward while its printing. Getting a “Z” shaped cross section to the spiral. The “while” block from the above gcode is expanded to:
while iterations<var.zPasses
if iterations/var.zPasses < 0.5
set var.startX={var.startX+0.3}
set var.endX={var.endX+0.3}
elif iterations/var.zPasses < 0.6
set var.startX={var.startX+0.05}
et var.endX={var.endX+0.05}
else
set var.startX={var.startX-0.3}
set var.endX={var.endX-0.3}
var currentZ=var.startZ+var.zStep*iterations
var eRotCurrent=(1+(var.currentZ-var.startZ)/(var.startZ))*var.eRot
G1 X{var.startX} Y0 F5000
G1 Z{var.currentZ} F5000
G92 C0 E0
G1 C{-360*var.rots} X{var.endX} E{var.eRotCurrent*var.rots} F7
In the meta gcode examples thus far there has been a move back to the start on each “layer” however there is no reason to do this, it is easy to add a check that switches the direction of the X movement and rotation at each end of the spiral:
var dir=(mod(iterations,2)=0)?1:-1
var currentX=(mod(iterations,2)=0)?var.endX:var.startX
G1 C{-360*var.rots*var.dir} X{var.currentX} E{var.eRotCurrent*var.rots} F7
So now the move switches direction of rotation, and changes the X move destination, based on if the iterations of the while loop are even or odd. The “ternary operator: a?b:c” used is a quick shortcut for an “if ‘a’ is true do ‘b’, if its false do ‘c’”
If we just reverse the direction of X movement and not the direction of rotation then we can get two overlapping spirals, one right handed, one left handed. In that case it is better to only increment the Z every second move to get good layer adhesion.
Of course we are not limited to printing spirals. If we only print part way round the cylinder before reversing the direction of rotation, while moving up and down in X we get a wavy pattern line this:
The spiral is from +45 to -45 degrees in C, so there is space to print a number of them around the cylinder. For this example there are three sets of spirals spaced 120 degrees apart.
The loop for this is three nested while blocks:
var waveAngle=45
var pitch=6
var steps=5
while iterations <3
G1 C-120 F4000
G92 C0
G1 C{var.waveAngle} X{var.startX} Y0 F7000
G1 E2 F300 ;unretract
while iterations<var.zPasses
var currentZ=var.startZ+var.zStep*iterations
var scale=(1+(var.currentZ-var.startZ)/(var.startZ))
G1 Z{var.currentZ} F5000
var dir = (mod(iterations,2)=0)?-1:1 ;evens go forward, odds go backwards
G91
while iterations<var.steps
var stepDir = ((mod(iterations,2)=0)?1:-1)
G1 C{-var.waveAngle*var.dir*var.stepDir} X{-var.pitch*var.dir} E{var.scale*var.eRot} F{var.fr/var.scale}
G90
;echo "C move: "^{-360*var.rots*var.dir}^" xmove: "^var.currentEndX ^" rots: "^var.rots
G9 E-2 F300
G1 Y-55 F5000
In all these examples, the B axis has been held constant, if we start to rotate the B axis then the tool path can get very complex. Here is a very simple example of a ball being printed by rotating B while moving X and spinning C:
At this point we have probably reached whats easy to do in meta gcode for now. It is possible to adapt these examples to use G2/G3 arcs rather than straight lines, but to go further a more powerful tool pathing software, like FullControlGcode is needed.
We hope this example helps you see some of the possibilities of multi axis 3d printing. The Open5X project has already got 5 printer options to choose from, and the simple mod from Loughborough University is very accessible to build. We look forward to seeing your builds and experiments on our forum.