Robot 3D Printing Project

Additive manufacturing (or 3D printing) is the process of making three dimensional solid objects from a digital file. Industrial robot arms can be used as a 3-axis or a 5-axis 3D printer with RoboDK. The following video shows an overview of how to setup 3D printing with RoboDK offline: watch video.

3D printing with robots is possible in one of the following ways:

   Directly convert G-code programs (NC file) to robot programs with RoboDK, as shown with the Robot Machining project. The rate of material flow (extruder directive E) is properly calculated for each movement and it can be integrated in the generated program as a Program Event. G-code is a type of NC file supported by RoboDK and it is also a format supported by many 3D printers. Most slicer software can generate G-code given an STL file.

   Select Utilities3D Print Project to open the 3D printing settings.

Robot Machining - Image 40

Robot Machining - Image 41

Robot Machining - Image 42

By default, RoboDK translates the E directive as a program call to a program called Extruder and passing the E value as a parameter. Select Program Events to change this behavior.

Robot Machining - Image 43

The Extruder value (E) represents how much material needs to be extruded before each movement. This value can be used to drive the extruder feed from the robot taking into account the robot speed and distance between points.

Alternatively, it is possible to calculate the extruder feed using a post processor and generate appropriate code accordingly. The following section provides an example.

Post Processor for robot 3D printing

This section shows how to modify a robot post processor to calculate the extruder speed before executing a movement instruction for 3D printing. Alternatively, these operations can be made on the robot controller with the Extruder program call (default command to drive the extruder).

By customizing a robot post processor, it is possible to make the integration of an extruder for 3D printing easier before sending the program to the robot. To accomplish such task, we need to do some calculations and output customized code when the program is generated in the robot post processor.

The first step is to intercept the Extruder calls and read the new Extruder values (E values) inside the RunCode section in the post processor. The following section processes all program calls generated for a program:

def RunCode(self, code, is_function_call = False):

    if is_function_call:

        if code.startswith("Extruder("):

            # Intercept the extruder command.

            # if the program call is Extruder(123.56)

            # we extract the number as a string

            # and convert it to a number

            self.PRINT_E_NEW = float(code[9:-1])

            # Skip the program call generation

            return

        else:

            self.addline(code + "()")

    else:

        # Output program code

        self.addline(code)

The Extruder value (length/E) is saved as the PRINT_E_NEW variable in the robot post processor.

We need to trigger a function call named new_move with each new linear movement instruction. We can add this call at the beginning of the MoveL command:

def MoveL(self, pose, joints, conf_RLF=None):

    """Add a linear movement"""

    # Handle 3D printing Extruder integration

    self.new_move(pose)

   ...

We must also add the following variables in the header of the post processor to calculate the extruder increments:

 

# 3D Printing Extruder Setup Parameters:

PRINT_E_AO = 5 # Analog Output ID to command the extruder flow

PRINT_SPEED_2_SIGNAL = 0.10 # Ratio to convert the speed/flow to an analog output signal

PRINT_FLOW_MAX_SIGNAL = 24 # Maximum signal to provide to the Extruder

PRINT_ACCEL_MMSS = -1 # Acceleration, -1 assumes constant speed if we use rounding/blending

  

# Internal 3D Printing Parameters

PRINT_POSE_LAST = None # Last pose printed

PRINT_E_LAST = 0 # Last Extruder length

PRINT_E_NEW = None # New Extruder Length

PRINT_LAST_SIGNAL = None # Last extruder signal

Finally, we need to define a new procedure that will generate appropriate extruder feed commands according to the distance between movements, the robot speed and the robot acceleration. This assumes the extruder feed is driven by a specific analog output or a customized program call.

We need to add the following code before the def MoveL program definition.

 

def calculate_time(self, distance, Vmax, Amax=-1):

    """Calculate the time to move a distance with Amax acceleration and Vmax speed"""

    if Amax < 0:

        # Assume constant speed (appropriate smoothing/rounding parameter must be set)

        Ttot = distance/Vmax

    else:

        # Assume we accelerate and decelerate

        tacc = Vmax/Amax;

        Xacc = 0.5*Amax*tacc*tacc;

        if distance <= 2*Xacc:

            # Vmax is not reached

            tacc = sqrt(distance/Amax)

            Ttot = tacc*2

        else:

            # Vmax is reached

            Xvmax = distance - 2*Xacc

            Tvmax = Xvmax/Vmax

            Ttot = 2*tacc + Tvmax

    return Ttot

       

def new_move(self, new_pose):                       

    """Implement the action on the extruder for 3D printing, if applicable"""

    if self.PRINT_E_NEW isNone or new_pose is None:

        return

       

    # Skip the first move and remember the pose

    if self.PRINT_POSE_LAST isNone:

        self.PRINT_POSE_LAST = new_pose

        return         

 

    # Calculate the increase of material for the next movement

    add_material = self.PRINT_E_NEW - self.PRINT_E_LAST

    self.PRINT_E_LAST = self.PRINT_E_NEW

   

    # Calculate the robot speed and Extruder signal

    extruder_signal = 0

    if add_material > 0:

        distance_mm = norm(subs3(self.PRINT_POSE_LAST.Pos(), new_pose.Pos()))

        # Calculate movement time in seconds

        time_s = self.calculate_time(distance_mm, self.SPEED_MMS, self.PRINT_ACCEL_MMSS)

       

        # Avoid division by 0

        if time_s > 0:

            # This may look redundant but it allows you to account for accelerations and we can apply small speed adjustments

            speed_mms = distance_mm / time_s

           

            # Calculate the extruder speed in RPM*Ratio (PRINT_SPEED_2_SIGNAL)

            extruder_signal = speed_mms * self.PRINT_SPEED_2_SIGNAL

   

    # Make sure the signal is within the accepted values

    extruder_signal = max(0,min(self.PRINT_FLOW_MAX_SIGNAL, extruder_signal))

   

    # Update the extruder speed when required

    if self.PRINT_LAST_SIGNAL isNone or abs(extruder_signal - self.PRINT_LAST_SIGNAL) > 1e-6:

        self.PRINT_LAST_SIGNAL = extruder_signal

        # Use the built-in setDO function to set an analog output

        self.setDO(self.PRINT_E_AO, "%.3f"% extruder_signal)

        # Alternatively, provoke a program call and handle the integration with the robot controller

        #self.addline('ExtruderSpeed(%.3f)' % extruder_signal)

   

    # Remember the last pose

    self.PRINT_POSE_LAST = new_pose