Hello!
I am developing on the Mr Beam Plugin for our commercial Laser Cutter.
Obviously compatibility of OctoPrint for generalised machine types has therefore been on our minds.
Our way of getting around it
The way we currently have it set up is a semi-total rewrite of the MachineComm class and a subclass for Printer (called Laser). A complete re-write allows us to set completely new GCode commands, new machine states etc...
Ideally it would be best to have some extra abstraction layers for MachineCom so it doesn't include hard-coded Gcode values or 3D printer behaviour / states.
Upgrade cycle
As we are upgrading to OctoPrint v1.4 , some of the states changed etc...
If in your plugin you have to modify that would recommend - if you can - to rely on the octoprint.util.comm.MachineCom class as much as possible. Will make your life easier. Not necessarily inherit from it, but reference as much of your logic to the one that is already written in octoprint itself.
Personal thoughts on general purpose CNC machines accepting GCode
When looking at the OctoPrint codebase, I am pretty confident that a Machine class can be created. A Printer would be a Machine, composed of Parts such as a PrintHead, HeatBed, Gantry etc...
Each Part has a unique ID. What would be nice is that you can refer to each part of a Machine using my_machine['my_part_1'] or preferably my_machine.my_part_1 (using set_attribute)
Each part implements a behaviour (function) for the Machine (do_homing, move_to, heat, start_laser ... ). Each action/behaviour is related to a default Part (or groups of Parts ?), but you could perform a homing with my_machine.non_default_gantry using either
my_machine.non_default_gantry.home()
my_machine.home(part='non_default_gantry')
my_machine.home(part=my_machine.non_default_gantry)
A default MachineInterface can create these functions for the machine as
Whether the MachineInterface and Machine classes are metaclasses, normal classes or even class decorators is completely up in the air right now. It will probably come down to an orchestra of those different types.
How it ties in with the standard.Printer
The Machine, MachineInterface and Part can have their own folder in src/octoprint/machine/ and the Printer / PrinterInterface would inherit from those and still keep their current place and form to maximise backwards compatibility.
Default Parts
Each Part could have some attached settings to describe some behaviour. If all the required Parts are implemented, one could describe a whole machine with some settings, in the same vein as described in foosel's previous comment
properties:
firmware: Smoothieware
parts:
gantry:
type: gantry
axis: 3 # or [x, y, z]
range_x: [0, 200]
range_y: [0, 300]
max_speed: 2000
jog: G0
extrude: G1
heatbed:
type: heatbed
read_temperature: M20
hotend1:
type: hotend
default: true
set_temperature: M104
hotend2:
type: hotend
set_temperature: M105
If the Machine has enough Parts to slice / print a file, you shouldn't need to create your own MyOtherMachine class in a plugin. That will probably be necessary if you intend to use multiple redundant parts (yeah I'm thinking of the crazies who are using 2 hotends on the same gantry at a time haha)
As you might see I've started to write a tiny bit of code to see if it ain't ridiculous.
@foosel I hope this is good food for thoughts? What do you think? 