Jump to content
Ultimaker Community of 3D Printing Experts
bcsteeve

Possible to make dynamic gcode in cura?

Recommended Posts

Cura knows the size of the object being sliced (it says it down in the bottom).  Let's say I want to send a G29 command to the printer suffixed by the size of the print job.  For example, I'm printing a 50x50 object I see no reason to wait 5 minutes while it autolevels across a 300 x 300 bed.

 

I see other applications as well and I wondered if there was a way for me to instead of say "send G29 at print start", say "send G29 X{x of project] Y{y of project]"  or even better (if I want to get complex) something like this psuedo code:  "send G29 P{int(print size / 25)"  {the idea being to scan a smaller grid number for a smaller grid size).

 

I hope I'm making sense.


Basically:  can variables be used to dynamically generate gcode based on data generated by Cura (primarily object size)?

Share this post


Link to post
Share on other sites

It's not currently possible, or at least not easily.

 

We expose all settings through the bracket syntax in the start and end g-code, but nothing other than those settings except the current date and time. Those are the only thing you can use when typing start/end g-code in the interface with the Machine Settings menu. See here for the source code that handles the bracket syntax: https://github.com/Ultimaker/Cura/blob/6a053a9f46c56a94cfaf611cb55376b4d0ad09d1/plugins/CuraEngineBackend/StartSliceJob.py#L270-L285

 

When you're writing a definition file (.def.json) a few more things will be possible if you specify the "value" property instead of "default_value". The "value" property can be any arbitrary Python expression, so you could make calculations like "G29 P" + str(int(machine_width / 25)) or something, and all the setting names have already been filled in as variables. There are other (hidden) functions available then as well, for instance extruderValues(setting_name) which gets a list of all values for a setting for each extruder. But there is nothing there either that can get the size of the print.

 

Warning: I'm getting gradually more technical here...

 

There is a vulnerability of sorts that allows you to devise a setting value that escapes the sandboxed environment in which the setting expressions are evaluated, and you can obtain data from the internals of Cura this way, including the dimensions and positions of the models. I won't disclose it here. But doing this will have problems with updating the setting value if the build volume changes, so it's not going to work reliably.

 

Also for the purpose of bed levelling you'd probably want to know the size of the final print rather than the size of the input models. The actual print can be quite different due to brims, rafts and horizontal expansion (of model and/or support). Most of these can be predicted beforehand (you know the desired brim width and such). Some of them can't though, for instance if you have conical support enabled. In those cases it is really impossible to get the dimensions of the print before slicing has completed.

 

I'll shoot in a feature request ticket to add the size of the input models as a key replacement for the bracket syntax. No promises, of course. Our backlog is long.

https://github.com/Ultimaker/Cura/blob/6a053a9f46c56a94cfaf611cb55376b4d0ad09d1/plugins/CuraEngineBackend/StartSliceJob.py#L275
Edited by ghostkeeper
Saying that I'll make a feature request.

Share this post


Link to post
Share on other sites

@ghostkeeper 
I'm very much interested in this. 

How would you use the 'value' property in place of the 'default_value' ?
(in a printer definition file) 
 

This does not work (cura crashes on startup)

"machine_start_gcode": { "value": "G29 P" + str(int(machine_width/25)) },

and this does not work either (not that surprisingly)

"machine_start_gcode": { "default_value": "G29 P" + str(int(machine_width/25)) },

 

The question is... what would work? 


Thanks!

Share this post


Link to post
Share on other sites

"default_value always" needs to be a literal (ie: a numeric value for a setting that expects a number, and a string ONLY when the setting expects a string vaue).

"value" should always be a string that can be interpreted by python. The string can contain a number, or a calculation, or another string, and any pythonically valid combination thereof.

 

By that logic, only "value" can hold any sort of manipulation and/or calculation.

 

This should work:

"machine_start_gcode": { "value": "'G29 P' + str(int(machine_width/25))" },

'G29 P' is a string in the python expression. The whole expression is enclosed as a string.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Awesome stuff @ahoeben. That works, and I understand. Python strings all the way!

However, something still eludes me. The following examples do not work even though in a regular python shell I see no issues. 

 

1. If statement

"'cool' if material_bed_temperature > 0  else 'very cool'"

- I actually use a similar construct in a cfg quality profile with no issues. I'm not sure why it would not work here. ¯\_(ツ)_/¯

2. moar math

"'M190 S' + str(floor(45*material_bed_temperature/material_bed_temperature))"

- This should evaluate to 0 if the material_bed_temperature is 0 and to 45 if it is anything else. Yet, it's stuck at 45 no matter what. 

Thanks for helping me dive into this. 

Share this post


Link to post
Share on other sites
1 hour ago, carvedblock said:

1. If statement


"'cool' if material_bed_temperature > 0  else 'very cool'"

- I actually use a similar construct in a cfg quality profile with no issues. I'm not sure why it would not work here. ¯\_(ツ)_/¯

Yeah, that looks like it should work, actually. I am confuzzled!

 

1 hour ago, carvedblock said:

2. moar math


"'M190 S' + str(floor(45*material_bed_temperature/material_bed_temperature))"

- This should evaluate to 0 if the material_bed_temperature is 0 and to 45 if it is anything else. Yet, it's stuck at 45 no matter what.

I would expect a ZeroDivisonError here if the bed temperature is 0, because then you'll evaluate 45 * 0 / 0 = 0 / 0. I think the error is happening underwater and it is just displaying the old value then. Try this:

"' M190 S' + ('45' if material_bed_temperature else '0')"

 

Edited by ghostkeeper
Simplified expression.

Share this post


Link to post
Share on other sites

Puzzling times. 

The dividing with a zero was a bit of a wishful hack, when I was not able to make the IF statement work... 


Yet. No errors (with any of the mentioned constructs - including the dividing by zero) The only thing log tells me when I switch the temperature is

2018-07-12 07:32:52,134 - DEBUG - [MainThread] cura.Machines.MachineErrorChecker._rescheduleCheck [129]: New error check scheduled.
2018-07-12 07:32:52,584 - INFO - [MainThread] cura.Machines.MachineErrorChecker._setResult [181]: Error check finished, result = False, time = 0.5s

---

After embarrassingly many tests, I found something! Many of the constructs (I did not test all) work if used with 

material_bed_temperature_layer_0, but not when used with material_bed_temperature !

 

You probably have an idea what's going on here? I don't see anything. 

 

Maybe it has to do with some default calculations, but I tried various options and I see no interaction. Here's a limited case that does not work: I have a cfg quality file with these lines 

 

this works fine
---------------
material_bed_temperature = default_material_bed_temperature
material_bed_temperature_layer_0 = =material_bed_temperature + material_bed_temperature / 13

this alwas evaluates to +5, never to 0 (I tried many variations on this theme, this is just one of them)
--------------------------------------
material_bed_temperature = default_material_bed_temperature
material_bed_temperature_layer_0 = =0 if material_bed_temperature = 0 else material_bed_temperature + 5

It seems almost like Cura has issues with seeing material_bed_temperature as zero?
(Because calculations with material_bed_temperature work fine, just the if evaluation seems to be failing with no error). 

(Well, most. It seems that more complex calculations fail, but that could be an error of syntax.) 

 

SO

👍Both of the IF statements work (mine and ghostkeepers simplified one)

👍Everything seems to work with that (other than the dividing with zero, which was another issue that made the testing pattern harder to see). 

👎no clue why material_bed_temperature does not work all around

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

Welcome to the Ultimaker Community of 3D printing experts. Visit the following links to read more about our Terms of Use or our Privacy Policy. Thank you!