Laser & CNC Mill/Router support

Hello Guys,
Octoprint is quickly becoming the best way to drive many types, including cnc lasers and mills that use the common 3d printer controllers.

I would like to start contributing by coding up a few changes to make those uses less clunky, they are mostly small but quite useful.

A few examples is hiding the temperatue tab and extruder controls for machines other than 3d printers, another common issue is jogging with G1 as on some lasers that turns the laser on, G0 would be preferable.

I know I could bend over backwards and make those as plugins hiding HTML elements of hard coded names and making a gcode filter to intercept G1 jog, but after looking around these changes would be much simply made in OctoPrint and I assume could open it for a lot more uses and users.

So the main point of my changes would be to add two more attributes to the Profile, one for machine type (Printer, Laser, CNC) and another one for Firmware/GCode flavor: (Marlin, Repetier, Smoothie, GRBL, Other).

With those we could add simple checks around OctoPi and plugins to better behave depending on machine type and Gcode flavor.

What do you think?

Here are some of the changes I already made while toying with these ideas:



Any feedback is welcome on these as well as the nicest way to hide the Temperature tab for machines with no heaters. Best I found was Settings.Appearance.Disabled.Tabs, but that seems to need a restart.

Cheers,
Fabio.

2 Likes

Absolutely. I think you've got the right idea.

I've seen attempts at terraforming the OctoPrint interface with a complete overhaul which ended up so ugly that nobody could work on it. Getting some toggles into OctoPrint itself would be preferred in this case, I'd suggest. But then again, I'm not the one doing PRs so foosel would be the person who should weigh in here.

I'll review these today and try to give some feedback.

  • You might want to also consider plotters (here, here, here)
  • I'm considering creating a printer design which will extrude food-grade inks on top of a latte
  • I'm considering creating a printer design which will extrude either just flux or flux + powdered solder so that circuit boards can be prep'd for reflow soldering
  • You could use something like this to pick/place electronic components (SMD)
  • In theory, you might be able to use OctoPrint as a 3D scanner

Yes, absolutely, the plotters you linked have yet another special cases that could be gated on the Profile.MachineType, that way reducing the risk of such changes to the other machine types.
Once these are in the profile we can slowly start addressing each of these scenarios.
@foosel What do you think?

1 Like

Extending things to other types of machines than just printers has been something I've been wanting to do for a long while. Putting something like a machine type into the printer profiles would be a logical first step to achieve that.

What really rubs me the wrong way though is calling them "printer profiles" in that case though :sweat_smile: Machine profile would be more fitting. Would mean quite a number of wrappers though to keep things backwards compatible on the APIs, but IMHO that would be worth it. Could be something down the road though.

Taking this further we'd also need a way to make the list of possible machine types extendable and thus the evaluation of what to support more flexible, so that we don't do something like "show temperature tab if machine is a printer" but rather "show temperature tab if machine supports temperature control". I see you've already gone this direction with your control tab adjustment. Reason for extendability and flexibility here: There are people out there using OctoPrint for things like lathes, pick-n-place-machines, drawbots, ...

Taking a look at your proposed changes up there, fine by me with some minor changes which I've annotated to the commits. Considering that at least those three actually qualify as improvements rather than a full blown new feature I'd even be tempted to say we'll put those unto the maintenance branch to have them live with 1.3.11.

Regarding the question on how to hide the temperature tab, that should only need a change to the data bindings of the whole tab really to hide it. We might have to backport some tab selection magic from the devel branch to still select the first visible tab in such cases on page reload, but other than that it should be fairly straight forward.

It would be awesome if the /api/printerprofile response allowed this to be queried in a consistent way.

I don't have one of those cool Prusa MMU2s or a Palette+ but maybe this could also be identified (if it's not already).

Thanks for looking Foosel!

I have the itches too, once I started thinking of the machine type concept I started seeing all this stuff in the UI that would need to be renamed to better reflect that, but scoping to a small change now will make it easier to slowly make OctoPrint machine type agnostic, hopefully with some community help.

Good point on making the machine types extensible via plugin, I can incorporate that on my changes.
Do you think we should make it an AddMachineType method on the printerProfilesViewModel? Or should we add it server side somehow? new mixin hook?

I see your point on the machine types having overlaps where temp control, extruders, or tools not being exclusive to one type or another, and we don't want that mapping from type to ability to be hard coded. My changes reflect that conflict as I proposed the machine type laser but then commuted the control UI based on extruders being present(which I think is a better signal). That also becomes relevant when choosing the command for jog, home, probe, level, etc. Maybe it could be extra configurations on the machine profile. But I felt that going that direction would not only clutter the profile settings ui but also the profile code...

Should we plan to have an unbounded dictionary for machine specific config and let the plugins manage it? Something like profile.particulars["hasHotEnd"] = true; profile.particulars["jogCommand"] = "G0"; profile.particulars["firmware"] = "Smoothieware";

I looked for some data binding I could do for the Temperature tab but the template temperature.jinja2 contains only the tab contents, not the tab itself and that threw me off. I see now in index.jinja2 where the tab is generated that I can inject something using templates.tab.entries[]["data_bind"] is that what you meant? Where can I elegantly set that?

Thanks,
Fabio.

Just a short word to say that this is a genius idea, and that there is a ton of potential here. I currently manually edit Octoprint's source code on my customer's machines to do so many things that would just be easy out of the box if this were implemented.

Apologies for the delayed reply.

Should definitely be server side. A hook (not a mixin) should probably suffice.

Not sure about particulars, more leaning towards something like properties. But in general, yes. We might want to make it hierarchical though...

properties:
  commands:
    jog: G0
    extrude: G1
    read_temperature: M105
    set_temperature_hotend: M104
  firmware: Smoothieware
  parts:
    hotend: true
    bed: false

Modelling that might go through some iterations though.

It's hidden in src/server/views.py, where all the core components come together. On the devel branch there's an example on how to set data-bindings there (since we need them there for the granular permissions):

Syntax is the same as for TemplatePlugins (same underlying mechanism).

1 Like

Hello Foosel,
Thanks for the pointers, I got the databindings somewhat working, on devel they work fine but on maintenance it takes a little more javascript magic to hide the tab link, please take a look:

If that's ok with you I will start PRs for hideTempTab, HideExtrusionContols. For the G0 jog would you like to wait for the profile changes? Should that go to devel or maintenance? devel seems to be way ahead, what is the general cadence that devel ships?

As for "properties" I was trying to keep it as an schema free dictionary so we would be able to extend via plugin, wouldn't that be preferable?

I'll start working on extensible machine types now.

Cheers,
Fabio

It might make sense to simply backport the generalized tab selection magic from devel to maintenance for this instead of going for something temperature tab specific. I believe it was these lines:

Hm... tricky questions :wink:

Regarding the devel release cycle, since there are quite invasive changes on devel (new permission system, Py3 compatibility, and I'm also targeting the new comm layer for that and am focusing a ton of this again now for that reason) that usually takes quite a long time, like, two years+. 1.3.0 was released in December of 2016 and I have to make a 1.4.0 release this year since starting 2020 Python 2 hits end-of-life, so OctoPrint stable needs to be Python 3 compatible before. But I can't tell you if it will be summer or fall, too much to do still.

To get the G0 into maintenance I'd go at it with your original approach and leave the full blown profile refactoring to a later date/devel.

It can still be a schema free dictionary even with a hierarchy. I just want to avoid something like encoding hierarchy into key names when it can live in the data structure (jogCommand, heatCommand, extrudeCommand vs commands.jog, commands.heat, commands.extrude). I'm not saying we should nail down the first level keys, they can still be freeform depending on what makes sense, but the more generalized things that the platform needs to read in order to configure itself properly should have some hierarchy so that I don't go insane maintaining it long term :wink:

This post was flagged by the community and is temporarily hidden.

This post was flagged by the community and is temporarily hidden.

1 Like

It might be worth mentioning the printer profile(s) that you setup to test this.

I added it to the PRs, but in a nutshell you have to disable the heated bed option and set extruder count to 0.

For reference here are the PRs:


I'll update this code to use the new profile properties once we get that coded up.

Re-posting half of my earlier post as it was flagged as not useful though had some relevant unanswered questions.

By original you mean switch to G0 cold turkey or you mean gate on the new MachineType and leave properties for later?

Thanks again for the time you're spending guiding me here.
Cheers,
Fabio.

Any update on this? Would like to be able to at least use Octolapse with it as well as remotely shut down the CNC at the very least.

1 Like

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? :slight_smile: