Using Github Actions to generate STL files from Python code

August 01, 2024

The previous post Creating 3D objects on Blender using Python showed how to do 3D modeling by using just Python and Blender. But everytime I wanted to print it, I needed to open the project using blender, run the code and and click in some options to export the STL file. But is there a way to automate this STL export?

Changing the code

Blender has specific methods for exporting objects. This can be found at the following documentation: https://docs.blender.org/api/current/bpy.ops.export_mesh.html.

It is need to run only one command that is described bellow. Since this code will be part of the script and it is not expected to export the STL while developing, an environment variable is checked before exporting, and will be defined only in CI runtime.

if os.getenv("RUNNING_IN_CI") == "true":
    if not os.path.exists("/tmp/exported_stl"):
        os.makedirs("/tmp/exported_stl")

    bpy.ops.object.select_all(action='SELECT')

    bpy.ops.export_mesh.stl(
        filepath="./exported/object.stl",
        use_selection=True
    )

Here is the final code from the previous post:

import bpy
import math
import os

bpy.ops.object.select_all(action='DESELECT')

for obj in bpy.data.objects:
    obj.select_set(True)
    bpy.ops.object.delete(use_global=False, confirm=False)

def set_scale(obj, x, y, z):
    bpy.context.view_layer.objects.active = obj
    obj.scale[0] = x
    obj.scale[1] = y
    obj.scale[2] = z


total_height = 10
slice_height = 0.1
slices_count = int(total_height / slice_height)
rotation_per_slice = math.radians(45) / slices_count
square_width = 5
rotation_layers = 4
rotation_offset = math.radians(90) / rotation_layers

for item_x in range(rotation_layers):
    for item_n in range(slices_count):
        height_offset = slice_height/2 + item_n * slice_height
        bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, location=(0, 0, height_offset))
        obj_reference = bpy.context.object
        
        distorted_width = square_width * 0.7 + (square_width * math.sin(math.pi * item_n / slices_count)) * 0.3

        set_scale(obj_reference, distorted_width, distorted_width, slice_height)
        obj_reference.rotation_euler[2] = rotation_per_slice * item_n + rotation_offset * item_x


if os.getenv("RUNNING_IN_CI") == "true":
    if not os.path.exists("/tmp/exported_stl"):
        os.makedirs("/tmp/exported_stl")

    bpy.ops.object.select_all(action='SELECT')

    bpy.ops.export_mesh.stl(
        filepath="/tmp/exported_stl/object.stl",
        use_selection=True
    )

Creating CI Pipeline

The example below uses Github Actions to run the pipeline since the Python code is stored on Github:

.github/workflows/export_stl.yml

name: Export STL
on:
  workflow_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    steps:
      - uses: actions/checkout@v4
      - name: Install needed packages
        run: |
          pip install bpy
      - name: Build
        run: python main.py
        env:
          RUNNING_IN_CI: "true"
      - name: Archive Exported File
        uses: actions/upload-artifact@v4
        with:
          name: stl-from-build-result
          path: /tmp/exported_stl

Some key aspects:

The tag on: workflow_dispatch: means that the execution is only triggered manually by entering the action's page and clicking in "Run Workflow":

ci-pipeline-01


The step named Archive Exported File makes use of a pre-defined action, that is responsible for uploading the contents of a folder from the runner machine to a bucket, and then linking it to the Action's run result:

ci-pipeline-01

By clicking stl-from-build-result, a zip file with the object.stl (defined in the python code) will be downloaded and can be used, for example, to send it to a 3D printer slicer.

Further: Exporting .gcode

With the above steps it is already possible to improve the 3D printing process by having a centralized process for generating the STL files. But to be in fact easy, generating the .gcode file, which contains the steps for a 3D printer is the final destination. More can be found at: https://manpages.ubuntu.com/manpages/trusty/man1/CuraEngine.1.html.

πŸ¦† πŸ–€ πŸ’»