About a year ago, I decided to get into 3d printing. I had a specific project in mind (which of course I still haven’t done) for building a fairly large interior structure for a pelican case, and so at the advice of a friend I decided to pick up a Creality CR-10v3 for its large build volume. Fast forward many months of building custom firmware, cursing furiously at slicer settings and hand-tuning the printer to get acceptable precision and I finally started making practical prints. But … printing is kinda slow. A single part can routinely take 3-4h to bake. Printing multiple parts at a time is possible, but printing time is mostly a factor of tool-head movement time. More movement for multiple parts means more time than printing the parts serially, and more time means more risk of bed ahesion or something else failing. So better to make printing multiple objects sequentially efficient, or even to print in parallel. Enter print farming, and my second CR-10v3.

Printing in parallel across multiple machines allows for total wall clock time-to-print to be reduced, and reduces the blast radius of part failures to a single part. But it requires a different approach to managing 3d printers than off the shelf solutions provide.

While printer vendors are beginning to roll out “cloud connected” printers managed through their own proprietary management platforms (sigh), printers started as just AVR microcontrollers reading streamed G-CODE instructions over serial connections. OctoPrint is a piece of software which implements exactly that streaming of G-CODE from a “real” computer (often a Raspberry Pi via OctoPi or some other toy computer). Unfortunately for me however, OctoPrint is designed to control exactly one physical printer.

Internally, OctoPrint’s model consists of model files which can be sliced into G-CODE, G-CODE files which can be “selected” for printing, and the “selected” file which can be “printing” (streaming G-CODE to the physical printer) actively. OctoPrint is mostly concerned with managing and parsing the serial connection protocol between itself and the physical printer, and doesn’t make much of any effort to present a job queue or any other high-level constructs.

For a single printer setup, it’s quite convenient to run an OctoPrint instance because many slicers (such as PrusaSlicer) have native support for “Send to OctoPrint” when slicing a model. This means that when you’re iterating on a model you essentially have a “slice and go” button. No need to generate a G-CODE script file and copy it around. Just load up a model, slice it, click print and the slicer tool will HTTP POST the sliced script to a configured OctoPrint API for you, and start the print running.

But, OctoPrint being a single-printer piece of software that doesn’t work when you have multiple machines in the loop. It also doesn’t work when you want to run off multiple copies of a given file, because OctoPrint can’t represent that request for say six copies. It only knows that there’s a file selected for printing. Once that print is done, something needs to request a new print – usually you. This usually means logging into the web UI for OctoPrint and clicking print again once you’ve turned the machine over between tasks. For two copies, that may be OK. But if you want to print many copies, it rapidly gets onerous. And forget trying to manually push files and print jobs out to multiple OctoPrint instances.

Surely there is a better way!

In theory OctoFarm should provide that better way, but among other defects it doesn’t actually have a scheduler.

So I built Tentacles.

Tentacles is a solution for fronting multiple OctoPrint instances with a job queue, and presenting them as if it was one OctoPrint … with multiple tentacles. In this screenshot, we can see that OctoPrint is currently configured to drive two printers, both CR-10s and that there’s a job currently scheduled to P1.

While the UI could use some love, the job queue UI shows that the job is currently running, and allows for duplication of the job, or cancellation.

We can also see that each of the printers is configured with a number of details – nozzle size, machine limits, machine type and loaded filament type. These details serve as scheduling constraints, allowing Tentacles to ensure that it doesn’t accidentally upload a PLA print to a machine loaded with ABS which needs much higher working temperatures. It also allows scheduling of jobs to printers which are the “right size”. Were I to add a smaller printer such as a Prusa Mini to the fleet, physical size constraints would prevent jobs which need a large working bed from running on the small printer. Users don’t need to specify the requirements of their jobs – it can be extracted either through simulating the G-CODE or by parsing the metadata PrusaSlicer helpfully includes.

Okay, so Tentacles can receive jobs, enqueue them and map them out … how do we determine when a printer is ready to receive work? OctoPrint provides some state bits reflecting whether a job is currently running or cancelling, but that doesn’t handle machine turnover. When a print finishes, or when there’s no print in progress, we need a way to decide whether the print bed is clear and the printer ready to do work. Enter the bedready plugin. By the standards of CV it’s super primitive and just does image-to-image comparisons, but if you use a printer’s webcam to take a reference image of an empty bed in a default “reset” position, that can be enough. As long as OctoPrint runs a script which returns the print bed to the “reset” position when a job finishes or the printer resets, you can then compare the webcam pictures to detect say finished prints that still haven’t been removed from the print bed. Or stray tools. Or support material that didn’t get cleaned up, any of which indicates that the printer is not ready to accept jobs.

Just for fun, Tentacles is also a fully multi-tenant solution! While it doesn’t feature job priorities, quotas or chargeback (yet), it does have a user signup, verification and approval flow. Once approved, users can directly request jobs on Tentacles as if it were a simple OctoPrint instance! To date, two friends have successfully printed jobs through Tentacles without ever coming over to my shop.

I could say more, but this is probably the most interesting stuff. The code is available, licensed under the anticapitalist.software license. No support or releases are provided – if you want to try and use it you’re gonna have to bazel build it yourself.

This is, after all, hobby software for my hobby print farm. But it is awful handy for running off fleets of benchies.