Traditional vs Curved-Layer Fused Filament Fabrication (CLFFF) using Real3DFFF
fff_vs_clfff_15fps.mp4
- Generate curved tool paths for FFF-Printers including normal vectors for 5-axis printing
- Generate Preform geometries
- Extract geometries for support only generation
- Import/Export of G-Code, STL, STEP, IGES
The developed algorithm uses a Preform Geometry that represents an extruded shadow of the actual part to be printed. That Preform is sliced with a regular slicing software that creates annotations about current layer and z-height inside the generated G-Code for the Preform. That G-Code is then adjusted on a per-layer basis to match the final geometry of the to be printed part.
The adjustment of a G-Code movement inside a layer includes the re-calculation of the z-coordinate based on the upper and lower surface coordinates in that specific area of the to be printed part. This requires a segmentation/splitting of G-Code segments into smaller segments to properly approximate the final geometry. In addition, the extrusion amount per segment and travel moves are recalculated to compensate for the change due to the z-adjustment of the layer.
Since the total number of layers in the sliced Preform is identical to the number in the final output, the layer height in the final G-Code is variable (adaptive) based on the z-cross section of the to be printed geometry.
During all following steps we use a coordinate system where the Z-axis points into the build direction while the XY-plane represents the build plate of the printer.
In this work, a preform refers to an auxiliary body. A preform is created from the original geometry. The preform results from an orthogonal projection of the original geometry into the XY plane. The projection, which is a like a shadow of the component, is extruded in the Z-direction. The amount of extrusion should be chosen to correspond to the largest amount of the cross-section in the Z-direction of the original geometry. Together with the chosen layer thickness during slicing, the amount of extrusion determines the number of layers in the final part.
An important property of the preform is that it has a constant cross-section in Z and all information about overhangs and undercuts of the original part is lost.
Preform geometries can be created in many ways. If the CAD data for the part to be printed is available, the preform can be created directly by projecting the outer edges in CAD. Other methods exist for tessellated geometries (STL). The application "Autodesk Netfabb", for example, provides such a function. The bottom side of the to be printed geometry is extruded in the positive Z-direction. A Boolean “common” intersection with a box will result in the desired preform geometry. The XY-dimension of the box must be at least equal to the XY-dimension of the part. The height of the box in Z determines the height of the preform. The box must be positioned above the highest point of the bottom surface of the part.
The algorithm ZGetter is used to obtain the Z-coordinates of the surface of a component at an arbitrary point (X, Y). Usually, two values are returned for a requested position. One for the bottom and one for the top of the component. In the following also called Zlower and Zupper. If the part contains undercuts or faulty geometry (e.g. in STL files), more than two intersection points may result. In this case, the two points with the lowest and the highest amount of Z are returned.
The algorithm determines the intersection points by intersecting a straight line passing through the point (X, Y) and parallel to the Z-axis with the geometry to be printed. OCCT provides corresponding implementations for the generation of straight lines and the determination of intersection points with a 3D geometry.
In addition to the Z coordinates, the normal vector on the top and bottom of the geometry can be determined at the sampled point (X, Y). For this purpose, the partial surface of the component on which, for example, the point (X, Y, Zlower) is located is determined. The normal vector of the surface at this point can then be calculated. Here, too, OCCT provides implementations for the determination of the surface and the normal vector at the point (X, Y). As a result, two additional normal vectors are obtained at the points (X, Y, Zlower) and (X, Y, Zupper). The vectors are normalised and it is ensured that they have the same orientation. By definition, this is in the negative Z direction.
The algorithm for generating curved paths is described below. The first step is to create a preform from the original geometry. As already described, this can be done directly in CAD and on the basis of the component geometry to be printed. Both the preform and the component geometry to be printed should have the same coordinate system and be congruent in the XY plane. This pre-positioning ensures correct execution of the subsequent steps.
For the preform geometry, the G-code must now be generated using a slicer. Care must be taken that the slicer does not realign the preform geometry on the print bed. In principle, any slicer is suitable as long as it is able to output the layer index and the Z-coordinate of the layer at the beginning of each layer. A defined notation must be adhered to so that subsequent steps can extract this information. The Real3DFFF application supports the notation formats of the slicers "Slic3r", "Slic3r PE", “SuperSlicer” and IdeaMaker. For the former three, the notation can be freely adapted via script.
In the next step, the geometry to be printed is triangulated i.e., its surface is approximated with triangles. This step is not necessary for parts in the STL or similar formats, as their surface already consists of triangles. The CAD formats STEP and IGES can be converted to STL via the OCCT API. The maximum allowed deviation of the resulting geometry from the component geometry is defined by the parameters "linear deflection" and "angular deflection".
All triangular surfaces with a surface normal parallel to the Z-axis are now removed from the resulting triangular grid. The same applies to surfaces whose normal has a Z-component of zero. In these areas the curvature of the component surface is constant or irrelevant. As a result we receive all surfaces of the approximated component geometry where the component has a curvature. All edges of these surfaces are projected into the XY-plane. In the following, these edges are called the "adjustment layer".
Now the G-code of the preform can be adapted to the final geometry. In the next step, the G-code of the preform is loaded. The individual layers are identified with their layer index and the corresponding Z-coordinate. The slicer has stored this information in the G-code via the defined notation. The following step only considers the G-code segments in which an extrusion actually takes place. Travel movements are ignored for now. Each G-Code layer is projected into the XY-plane.
Now all extrusions of a G-Code layer are intersected with the edges of the adjustment layer that were previously projected into the XY-plane. This step is conducted for each layer of the Preform G-code. The resulting intersections give the points in the Preform G-code where a G-Code move (extrusion segment) must be split and the Z-coordinates adjusted to fit the final geometry. Each start and end point of a movement from the preform G-code must also be adjusted in the Z-direction. This ensures that the final G-code exactly fills the parts volume that is defined by triangulation. OCCT helps to calculate the intersection points between the G-code layer and the adjustment layer.
The segmentation of Preform G-code layers can result in very short extrusion segments. The minimum allowed segment length can be defined by a parameter in the Real3DFFF application. Segments that do not meet the criterion are deleted and the resulting gap is filled by adjusting the start point of the following segment. This step is performed in the 2D and in the XY-plane.
[7-1]
In this step, the segmented Preform G-code and the respective extrusion rate of each segment is adjusted. Each end point of a segment is now moved using the ZGetter class. It is not necessary to move the start points, as only the end point of a movement is specified in the G-code format.
The new Z-coordinate of each segment end point at (X, Y) is calculated according to [7-1] from the number of layers in the preform G-code, the layer height, the current layer index and the Z-coordinates of the component surface at point (X, Y) returned by the ZGetter implementation. The number of layers in the preform is constant, as only preform geometries with constant cross-section in the Z-direction are considered.
Since the cross-section of the part can change but the number of layers remains constant through the cross-section, the extrusion rate must be scaled according to the increasing/decreasing local layer thickness (adaptive layer thickness).
[7-2]
Where
[7-3]
Here
As already described, ZGetter also provides the normal vector at the top and bottom (
[7-4]
The interpolated normal vector
In addition to the X, Y, Z and E coordinates of an extrusion instruction, the parameters N, O and R are added to the instruction. The three coordinates of the normal vector are stored as additional parameters. The parameter N stores the X-component, O the Y-component and R the Z-value of the normal. The previously defined printer coordinate system is used.
The following are part of the adaptive CLFFF algorithm to ensure printability and quality of the final G-Code.
In addition to the extrusions, the travel movements must also be adjusted. Otherwise, there will be collisions between the print head and the printed geometry. Depending on the length of the travel movement, the movement is replaced by three individual movements. Raising the nozzle by a defined value, moving the print head in the XY plane to the target point and lowering it to the desired Z coordinate. To optimise the printing time, the process distinguishes between three types. Long, short and direct travel movements. The criterion in each case is the length of the travel movement in 2D. It can be set via parameters in Real3DFFF.
With long travel movements, the print head is raised by a defined value above the highest point of the already printed part.
With short travel movements, the printhead is raised by a defined value before it moves in the XY-plane to the target coordinate and is lowered again. With such movements, it is assumed that the travel distance is too short for a collision to occur.
In the case of direct travel movements, the printhead is not raised, but travels directly in a straight line to the target point.
The method described so far for segmenting the preform G-code uses the triangulation of the part surface. In areas with linear cross-section changes of the part, there are only very few edges available from the tessellation. As a result, an extrusion is not split up very often and only a few G-code segments are created in such an area. This is problematic since the extrusion rate on a G-Code segment can only be constant. Due to the linear increase of the final parts cross section, a constant change in layer height of the final G-Code is required. The required increase in layer height and thereby also in extrusion rate can only be achieved by splitting the G-Code segment into multiple segments to approximate that linear increase.
The developed algorithm therefore subdivides a G-Code segment of the preform into
[7-5]
Where
Depending on the geometry to be printed, support structures are necessary to support overhangs (~>45°). Since components with undercuts have been excluded for this process, only support structures that lie directly on the build platform need to be considered. To generate the support structures, the underside of the component geometry (surfaces with angles to the Z-axis <90°) is identified. These are extracted and passed to a conventional slicer. The slicer generates the G-code for the support structures below the extracted surface. No G-code is generated for the surface itself when using supported slicers, as the surface does not represent a closed volume. Depending on the slicer, additional settings may have to be made so that such non-manifold geometries (extracted surfaces of the component underside) are not automatically repaired or ignored. Also, in this step it is important that the slicer does not reposition the part on the build plate, so that later the support structure is directly under the part to be printed. The G-code for the support structure printed first. Then the CLFFF G-code can be executed.
Real3DFFF requires a big set of dependencies, some of them being a bit dated. To make things easier, a complete python environment is provided in addition to the code to get you started in no time.
- Download the package from the GitHub release section.
- Extract the files.
- Run
main.py
using the provided python interpreter in the root folder of the extracted files.
- Create a Preform for the to-be-printed geometry (an extruded shadow of the part)
- Slice the Preform geometry with a supported slicer (Slic3r or variants, IdeaMaker) adding the necessary annootations (see below)
- Run the below script within the provided Python environment.
Annotations necessary for Slic3r based slicers like PrusaSlicer, SuperSlicer etc.:
Add a custom gcode at layer change:
; layer_num=[layer_num]
; layer_z=[layer_z]
import os
from data_io.loaders import load_step
from gcode.gcode_visualizer.virtual_reprap import VirtualRepRap
from gcode.real_3d.generate_curved_layer import generate_curved_layer_christl
from globals import ANGULAR_DEFLECTION
if __name__ == "__main__":
"""
Generate curved layer Fused Filament Fabrication paths using the algorithm according to Christl
"""
# Path to file representing the final shape
path_geo = "test_geometry/wave_rounded/wave_round.stp"
# path to preform G-Code
path_gcode = "test_geometry/wave_rounded/wave_round_preform_IdeaMaker.gcode"
# Path to output file that will be created with the final curved layer gcode inside
path_out_file = "test_geometry/wave_rounded/wave_round_curved.gcode"
# supply preform geometry if you want to use the local layer index -> This feature does not work yet use None
path_preform = None
if os.path.exists(path_out_file):
os.remove(path_out_file)
part_shape = load_step(path_geo)
preform_shape = load_step(path_preform)
vreprap = VirtualRepRap()
preform_gcode = vreprap.readin_gcode(path_gcode, 0.2, 0.4)
curved_layer_gcode = generate_curved_layer_christl(part_shape, preform_gcode, path_out_file,
preform_shape=preform_shape,
max_lin_deflection=0.5,
ang_deflection=ANGULAR_DEFLECTION,
min_segment_length=0.2,
max_extrusion_err=0.5,
lifted_travel_dist=2,
low_trav_clearance=0.5,
high_trav_clearance=1,
max_len_direct_trav=2,
compute_normals=False
)
Extrusion rate and computed normal vector.
Author: Wolfgang Christl - Extract of my 2019 Master-Thesis
All code licensed under GNU LESSER GENERAL PUBLIC LICENSE V3