Hi guys,
I wanted to inform you that I'm working on a simple menu system for klipper.
I already have working mockup and now I'm trying to fit it into Klippers system.
The menu structure is fully configurable via config file.
Menu is working on different screens, 2x16, 4x20 and on graphics displays.
It's a text based menu system. You just have to specify correct cols and rows.
It has 3 basic menu elements:
All submenus have first item as "go back". System inserts it automatically.
You can define klipper system predefined variables in args attribute.
In menu item name you can use variables list defined in args as standard print format options.
For navigation only 3 buttons is needed: UP, DOWN, SELECT
When menu item (only input item) is in edit mode then system shows asterisk and UP & DOWN will change value accordingly. Currently only float value type is supported.
Pressing SELECT again will exit from edit mode and will execute GCODE (value is given as print format first element).
I tried to make flexible way for adding dynamic data into name and gcode.
There is attribute parameter: endstop.xmax:b["OPEN", "TRIG"]
In Klipper there's collection of status info from all modules.
First part endstop.xmax of attribute value is value key of that collection.
Second part :b["OPEN", "TRIG"] of attribute value is additional way
for mapping value to list or dict.
: is delimiter
b is boolean typecast for value. Other casting types are: f - float, i - int, b - bool, s - str
["OPEN", "TRIG"] is literal presentation of python list. List and Dict are allowed.
Python will use safe method to turn it into real dataset.
You don't have to use mapping options all the time. In most cases it's not needed and
just parameter with simple value key parameter: fan.speed will do.
When preparing name or gcode then you're able to use pyhton advanced string formatting
possibilities.
Value is avalilable as {0} and mapped option as {1}.
If there's error condition in conversion or just wrong data type
then raw name or gcode string is used instead of formatted one.
Changeable input is using value and can only be float type.
But in name and gcode you can use mapped one if needed.
Menu manager config
[menu]
root: main1 # mandatory
rows: 4 # mandatory
cols: 20 # mandatory
Group menu item config
[menu main1]
type: group # mandatory
name: Main menu # mandatory
enter_gcode: # optional
leave_gcode: # optional
items: menu1, menu2, menu3 # mandatory
Menu item with action
[menu menu1]
type: command # mandatory
name: Fan speed: {0:d} # mandatory
parameter: fan.speed # optional
[menu menu2]
type: command # mandatory
name: Pause octoprint # mandatory
gcode: @//pause # optional
[menu menu3]
type: command # mandatory
name: Kill me # mandatory
gcode: M112 # optional
[menu menu1]
type: command # mandatory
name: xmax endstop: {1:4s} # mandatory
parameter: endstop.xmax:b["OPEN", "TRIG"] # optional
Menu item with input
[menu enable_fan]
type: input # mandatory
name: Enable Fan: {0:d} # mandatory
parameter: fan.speed # mandatory
input_min: 0 # optional
input_max: 255 # optional
input_step: 1 # mandatory
gcode: M106 {0} # optional
Some screenshots from mockup demo



NB! This is still a Work in Progress. Concept, code, and other stuff might change!
Menu system is already working as Klipper module.
Integration with display and buttons are still missing.
Menu debugging is currently only possible with custom gcodes and terminal output.
Code itself needs more work and debugging.
@KevinOConnor, I'm having a problem with buttons.py module.
I tried to checkout it and make but when I start klipper service it gives me an error:
self.mcu.send(self.ack_cmd.encode(new_count), cq=self.cmd_queue)
AttributeError: MCU instance has no attribute 'send'
Do you have any example code how to use this buttons module correctly?
On Mon, Jun 18, 2018 at 03:29:01PM -0700, Janar Sööt wrote:
Menu system is already working as Klipper module.
Integration with display and buttons are still missing.
Thanks - it looks very interesting.
On Mon, Jun 18, 2018 at 10:39:08PM -0700, Janar Sööt wrote:
@KevinOConnor, I have problems with buttons.py module.
I tried to checkout it and run but it gives me an error:self.mcu.send(self.ack_cmd.encode(new_count), cq=self.cmd_queue) AttributeError: MCU instance has no attribute 'send'Do you have any example code how to use this buttons module correctly?
There was an error in one of the past merges of that branch. It
should be fixed now.
I tested it with the following in my config:
[buttons]
pins: ^!ar31, ^!ar33, ^!ar35, ^!ar41
With that, when I move the encoder clockwise, I get messages like the
following in the log:
buttons=ar31
buttons=ar31,ar33
buttons=ar33
buttons=
with counter-clockwise I get:
buttons=ar33
buttons=ar31,ar33
buttons=ar31
buttons=
On pressing the encoder down I get:
buttons=ar35
buttons=
One challenge you will have with this demo code is that the
handle_buttons_state() callback in buttons.py is invoked from a
background thread. Some work will be needed to notify the main thread
(which runs the display.py code).
-Kevin
@KevinOConnor Hi, could you check my modifications for buttons module.
https://github.com/mcmatrix/klipper/tree/work-buttons-20180620
I havent tested it yet, hopefully tomorrow i can do testings.
The idea is simple but not 100% sure that it will work.
From other module you register your named button and pin in buttons module.
Pin of course has to be in buttons monitoring list.
btns = config.get_printer().lookup_object('buttons')
btns.register_button('enc_a','ar31')
btns.register_button('enc_b','ar33')
btns.register_button('enc_c','ar35')
and in display update you can check registred buttons last press state
btns.check_button('enc_c')
What you think?
I suspect you may run into race conditions with that code (self.last_pressed isn't thread safe).
-Kevin
I suspect you may run into race conditions with that code (self.last_pressed isn't thread safe).
Considering with thread safety will make things more complex.
Queues are thread safe in Python.
I have few ideas:
I made short mockup with Queue.
import Queue
class error(Exception):
pass
button_list = {}
button_list['enc_a'] = ('ar31', Queue.Queue(1))
button_list['enc_b'] = ('ar33', Queue.Queue(1))
button_list['enc_c'] = ('ar34', Queue.Queue(1))
pin_list = []
pin_list.append(('ar31', 1, 0))
pin_list.append(('ar33', 1, 0))
pin_list.append(('ar34', 1, 0))
# will be called from background thread
def handle_buttons_state(b):
out_pins = []
out_btns = []
pressed_buttons = []
pressed_pins = [pin for i, (pin, pull_up, invert) in enumerate(pin_list) if ((b>>i) & 1) ^ invert]
print 'pins bits from mcu: %d' % b
for name, (pin, q) in button_list.items():
if pin in pressed_pins:
pressed_buttons.append(name)
try:
q.put(name, False)
except:
pass
out_pins.append(','.join(pressed_pins))
out_btns.append(','.join(pressed_buttons))
print "buttons_pins=%s" % ' '.join(out_pins)
print "buttons_btns=%s" % ' '.join(out_btns)
# will be called from main thread
def check_button(name):
press = None
if name not in button_list:
raise error("Button '%s' is not registered" % (name,))
try:
press = button_list[name][1].get(False)
button_list[name][1].task_done()
except:
pass
return press
#---------------
for b in range(1,4):
handle_buttons_state(b)
#---------------
print 'check press: %s' % check_button('enc_a')
print 'check press: %s' % check_button('enc_a')
@KevinOConnor What you think, will this approach be thread safe?
buttons module - test version is ready for my testing
menu module - test version is ready for my testing
display module - both buttons and menu modules are integrated, needs my testing
Everything is still WIP!
It's in WIP statuses.
I'm having hard time with encoder stability.
I first did encoder decoding in display module but the update rate was too low.
So I moved encoder part to buttons module, inside pin state handler.
But still it's hard to get nice and stable encoder readout having that encoder functionality in buttons.py
Can it be done in python level or it has to be done in mcu level?
I have 3 different dev branch:
Mostly these python files were modified by me.
My config is:
# Panel buttons
[buttons]
pins = ^!ar31, ^!ar33, ^!ar35, ^!ar41
# "RepRapDiscount 2004 Smart Controller" type displays
[display]
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
encoder_a_pin: ar31
encoder_b_pin: ar33
click_button_pin: ar35
# Menu manager
[menu]
root: main1
rows: 4
cols: 20
[menu main1]
type: group
name: Main menu
#enter_gcode:
#leave_gcode:
items: menu1, menu2, menu3
[menu menu1]
type: command
name: Resume octoprint
gcode: @//resume
[menu menu2]
type: command
name: Pause octoprint
gcode: @//pause
[menu menu3]
type: group
name: Group 1
#enter_gcode:
#leave_gcode:
items: menu4, menu5
[menu menu4]
type: command
name: Kill
gcode: M112
[menu menu5]
type: input
name: Move Z: {0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 Z{0:.2f}
This is needed to run klipper with menu.
from what I see here, the menu system always starts with a main menu, right?
Could you allow to have a pure display page and use a button to go to the menu?
Unfortunately, the menu configuration (especially according to dynamic parameters) seems to be based on menu lines, so it doesn't allow to have multiple parameters per line.
I think this could be solved by using sections describing single parameters which could be inserted in the display via their names.
On a display page the encoder could jump from field to field. Pressing the encoder would activate editing the parameter via rotating the encoder, pressing again would leave editing.
One of the fields could be a menu button, pressing the encoder on it would enter the menu system.
There could be multiple display pages, switched by pressing on a button field (which could be the same as the menu button).
Additionally display pages could be linked and scrolling through the parameters could automatically switch to the next or previous page.
Example config:
[menu page]
type: switch
parameter: menu.page
items: top,2nd
[menu X]
type: parameter
parameter: toolhead.xpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 X{0:.2f}
...
[menu top]
type: page
page:
{page:s} X{X:.2f} Y{Y.2f} Z{Z.2f}
Bed{temp_bed:d} Hot{temp_hotend:d} ...
[menu 2nd]
type: page
...
Example usage:
>top X:0 Y:0 Z:2.5
Bed:80° Hot:185° ...
[press]
>2nd ...
[press]
>top X:0 Y:0 Z:2.5
Bed:80° Hot:185° ...
[right]
:top X>0 Y:0 Z:2.5
Bed:80° Hot:185° ...
[press]
:top X=0 Y:0 Z:2.5
Bed:80° Hot:185° ...
[right]
:top X=1 Y:1 Z:2.5
Bed:80° Hot:185° ...
[press]
:top X>1 Y:0 Z:2.5
Bed:80° Hot:185° ...
One of the pages could be the current type of menu.
But I think, the menu could eventually replaced by using pages:
This would also allow to place several menu buttons on one line.
The selected field in the example is indicated by using a single character (mainly because I wanted to use simple text above).
Instead, the selection could be indicated by inverting the field. However there needs to be another indicator for editing mode (underline?).
The field could also be surrounded on both sides by spaces or [...] or >...< to indicate the three modes, but this would need another character for each field.
Eventually the type of indicator could be chosen by a setting.
from what I see here, the menu system always starts with a main menu, right?
Yes, it's like general marlin or repetier menu.
Thank you for sharing interesting menu concept.
This horizontal layout for menuitems is nice and compact.
Right now first priority is to get my menu working and get rid of WIP status.
After that I'm ready to investigate what can be implemented from your idea.
https://github.com/mcmatrix/klipper/tree/dev-release-20180622
dev-release contains all 3 merged work branches.
It's still beta firmware so use it ONLY FOR TESTING and not in production!
Documentation is still missing.
Encoder is still problematic
I tried to reduce encoder jitter with running average and new decoding algorithm but i'm not happy yet (anyway better than nothing). Dont try to rotate encoder very fast, it wont keep up.
Maybe someone has idea how to improve encoder decoding!
Could be that we need to help python from mcu. In microcontroller level it should be able to detect encoder state changes very precisely?
Example config:
# Panel buttons
[buttons]
pins = ^!ar31, ^!ar33, ^!ar35, ^!ar41
# "RepRapDiscount 2004 Smart Controller" type displays
[display]
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
lcd_type: st7920
cs_pin: ar16
sclk_pin: ar23
sid_pin: ar17
#lcd_type: hd44780
#rs_pin: ar16
#e_pin: ar17
#d4_pin: ar23
#d5_pin: ar25
#d6_pin: ar27
#d7_pin: ar29
#encoder_a_pin: ar31
#encoder_b_pin: ar33
encoder_a_pin: ar33
encoder_b_pin: ar31
click_button_pin: ar35
encoder_resolution: 1
# Menu manager
[menu]
root: main1
rows: 4
#cols: 20
cols: 16
[menu main1]
type: group
name: Main menu
#enter_gcode:
#leave_gcode:
items: menu1, menu2, test1, menu3
[menu menu1]
type: command
name: Resume octoprint
#gcode: @//resume
[menu menu2]
type: command
name: Pause octoprint
#gcode: @//pause
[menu test1]
type: command
name: Printing: {1:>3s}
parameter: toolhead.is_printing:b['NO','YES']
[menu menu3]
type: group
name: Group 1
#enter_gcode:
#leave_gcode:
items: menu4, menu5, menu6
[menu menu4]
type: command
name: Kill
gcode: M112
[menu menu5]
type: input
name: Move Z: {0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 Z{0:.2f}
[menu menu6]
type: input
name: Choose: {1:s}
parameter: 0:i('----', 'cola','pepsi','fanta','sprite')
input_min: 0
input_max: 4
input_step: 1
gcode: M117 My favorite: {1}
On Fri, Jun 22, 2018 at 02:38:29PM -0700, Janar Sööt wrote:
https://github.com/mcmatrix/klipper/tree/dev-release-20180622
dev-release contains all 3 merged work branches.It's still beta firmware so use it ONLY FOR TESTING and not in production!
Documentation is still missing.Encoder is still problematic
Interesting. When I last tested this, I didn't see any indication of
lost messages from the mcu even when I was spinning the rotary encoder
very fast. I'll try to take a look at it - but it will likely take me
a few days.
Thanks,
-Kevin
Did few changes in encoder handler, for me it looks more stable now, even without moving average (commented it out, probably not needed).
Still fast spinning encoder states are not decoded correctly.
dev-release-20180622 should be up to date.
First of all, this is awesome! This feature was definitely missing in klipper. Thanks for working hard on it.
Maybe someone has idea how to improve encoder decoding!
Could be that we need to help python from mcu. In microcontroller level it should be able to detect encoder state changes very precisely?
I think that handling this at the mcu level would improve precision. Because of the latency of the serial connection, more than one trigger event can happen between two serial frames, so they aren't caught by the host software.
You can maybe append something like 3 characters at the end of the serial string for the different encoder infos:
nul : no encoder event
clk : encoder was rotated clockwise
ccw : encoder was rotated couter-clockwise
btn : encoder button was pressed
Another suggestion: Is putting the menus architecture in a separate, JSON-like file feasible?
Here are the advantages I see to this:
I tried to install this WIP release to test the menus but I keep getting the following error when starting klippy:
Config error
Traceback (most recent call last):
File "/home/pi/klipper/klippy/klippy.py", line 234, in _connect self._read_config()
File "/home/pi/klipper/klippy/klippy.py", line 225, in _read_config option, section))
Error: Option 'encoder_a_pin' is not valid in section 'display'
Can a working example cfg file be posted to help in getting this to work?
Latest dev-release should work and part of working config is posted above. Please update to the latest.
Did you checkout dev-release fully? It looks like extras/display.py is not changed.
I'll try a "from scratch" install of this dev-release (which in fact I did not do properly) and get back with some feedback.
Install original klipper first.
Set it up correctly, make sure that everything works and then check out my dev-release for testing.
This way by using git checkout you can easily switch between different branches.
This should help with my dev-release checkout.
git remote add mcmatrix https://github.com/mcmatrix/klipper
git fetch mcmatrix
git checkout mcmatrix/dev-release-20180622
make clean
make
sudo service klipper stop
make flash FLASH_DEVICE=/dev/ttyACM0
sudo service klipper start
Thanks for the heads-up.
In the meantime I've a question concerning the pins required for the menus.
In the [buttons] section we see 4 pins being declared:
pins = ^!ar31, ^!ar33, ^!ar35, ^!ar41
but then only 3 are in fact used for the encoder:
encoder_a_pin: ar33
encoder_b_pin: ar31
click_button_pin: ar35
could you please explain this (apparent) inconsistence? Why is pin ar41 also declared?
In my current setup (Due + RADDS + MK4duo FW) I've got this as the pins being used for the encoder:
#define BTN_EN1 50
#define BTN_EN2 52
#define BTN_ENC 48
Thanks in advance.
In my case ar41 should be kill button but it’s not used right now. You can leave it out.
In [buttons] section you have to list all pins (with config: pullups, inverted) you want to monitor.
In [display] you just specify pins name (without config) you want to use for encoder.
Thanks again for the clear explanation.
I'm in the middle of a print… will try this after it finishes and get back to you.
Those who have more navigation buttons can use these attributes too:
# enter, select, encoder click
click_button_pin:
# up navigation, same as encoder up
up_button_pin:
# down navigaton, same as encoder down
down_button_pin:
# navigation back, return from active submenu, same as selecting “..” in menu.
back_button_pin:
# needed for encoder
encoder_a_pin:
encoder_b_pin:
NB! all these attributes can be used together.
I've reinstalled Klipper and your branch and was able to start things up with your test configuration.
On the other hand, as soon as I click the encoder button Klipper crashes and I have this in the log:
buttons: pins=ar48 ; buttons=click_button
buttons: pins= ; buttons=
Unhandled exception during run
Traceback (most recent call last):
File "/home/pi/klipper/klippy/klippy.py", line 274, in run
self.reactor.run()
File "/home/pi/klipper/klippy/reactor.py", line 124, in run
g_next.switch()
File "/home/pi/klipper/klippy/reactor.py", line 151, in _dispatch_loop
timeout = self._check_timers(eventtime)
File "/home/pi/klipper/klippy/reactor.py", line 65, in _check_timers
t.waketime = t.callback(eventtime)
File "/home/pi/klipper/klippy/extras/display.py", line 535, in screen_update_event
self.menu.begin(eventtime)
File "/home/pi/klipper/klippy/extras/menu.py", line 187, in begin
self.update_info(eventtime)
File "/home/pi/klipper/klippy/extras/menu.py", line 221, in update_info
info = obj.get_heater().get_status(eventtime)
AttributeError: Heater instance has no attribute 'get_heater'
Any idea if this could come from my configuration or is it a real bug?
Sorry, it seems like a bug. I'll fix it after I get home.
@micheleamerica That bug should be fixed in dev-release-20180622.
Great news. Thanks.
Just updated and the issue is fixed.
Thank you very much.
BTW, you guys are doing a great job with Klipper… it is, until now, the best FW I ever installed in my 3d printers.
@KevinOConnor I did some experiments with encoder decoding on mcu level.
Please check mcu-encoder-test-20180625 test branch for this feature.
Currently it's a more like hack, this bit twiddling makes my head hurt.
Probably there's a nicer way of doing it.
It takes encoder a & b separate from button pins.
# Panel buttons
[buttons]
pins = ^!ar35, ^!ar41
encoder_pins = ^!ar33, ^!ar31
It decodes encoder input and makes encoder a&b pins behave like fake buttons.
Decoder is nice state machine algorithm, look very reliable.
So encoder CW and CCW output is either pin A or pin B pressed.
In display you can use these:
[display]
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
encoder_up_pin: ar33
encoder_down_pin: ar31
click_button_pin: ar35
I had to reduce QUERY_TIME to .002
Right now fast spinning encoder looks okey.
Will this faster query time affect printing performance?
On Mon, Jun 25, 2018 at 08:49:54PM +0000, Janar Sööt wrote:
@KevinOConnor I did some experiments with encoder decoding on mcu level.
Please checkmcu-encoder-test-20180625test branch for this feature.
Currently it's a more like hack, this bit twiddling makes my head hurt.
Probably there's a nicer way of doing it.
[...]
I had to reduceQUERY_TIMEto.002
Right now fast spinning encoder looks okey.
Will this faster query time affect printing performance?
Okay, thanks. I got some time to retest this on the rotary encoder
that came with my ST7920 display. I also now see the issue of
spinning too fast causing lost events. (I'm not sure if the rotary
encoder on my hd44780 display didn't have the issue, or if I just
didn't test rotating that fast.) However, the only change that I
think is necessary is to tune QUERY_TIME - I don't think moving the
encoder logic to the mcu code is necessary.
I ran some benchmarks, and I don't see a significant difference in
overhead between .005 and .002 so I think the faster time is okay.
I also cleaned up the buttons.c code a little (no more oid hacks).
I've pushed the updated button code to the work-lcd-20180115.
I'm going to see if I can get the python code to forward events to the
main thread so that the buttons code doesn't need to worry about
threads.
-Kevin
FYI - I made some updates to the low-level button handling code. The demo code now forwards events to the main thread, and I updated the demo code to be able to run g-code on a button press.
The new code is on the work-lcd-20180115 branch. I tested it with the following config snippet:
[buttons encoder]
rotary_encoder_pins: ^!ar33, ^!ar31
clockwise_gcode:
ECHO MSG=right
counterclockwise_gcode:
ECHO MSG=left
[buttons encoder_press]
pin: ^!ar35
gcode:
ECHO MSG=press
Thank you.
It's a nice upgrade.
Now we can have for example kill button:
[buttons killme]
pin: ^!ar41
gcode:
M112
I'll make changes in my work to integrate new buttons into menu system.
Not sure what direction you are going to take but add a custom gcode like MENU MSG=up/down/select/back may be a way to use the new button code. Then all we have to do is add the menu to the display if the menu exits. Haven't test but the idea is like https://github.com/KevinOConnor/klipper/compare/work-lcd-20180115...wizhippo:menu not sure is the menu cmd needs to call a method to update the display or just rely on it refreshing.
EDIT: note I have made it so if the default group is selected the original display code will show. This allows to go back to that screen.
It’s the simplest way but it depends how klipper is handling gcodes. For example if you are running M190 or M109. In marlin no other normal gcodes are executed until these are reached temp.
I havent used klipper for real printing yet but probably it’s doing the same.
When waiting gcode is running then you cannot use menu.
How klipper will handle gcode burst when you spin encoder fast?
At the moment I like more direct integration but lets see.
I’ll test this gcode way of navigating menu.
I'd recommend doing the programming on the python level. Specifically, with the latest buttons code one can do the following in any module:
buttons = printer.try_load_module(config, "buttons")
buttons.register_button([config.get('my_pin')], self.my_callback)
to register a button and arrange for my_callback() to be invoked on each button press and release.
I fear going through g-code would add complexity and weird corner cases with command scheduling.
-Kevin
@KevinOConnor Thank you.
dev-release-20180622 is updated and encoder is running very well
Now I can continue with menu testing.
For brave testers this should help you with my dev-release checkout.
It's still beta firmware so use it ONLY FOR TESTING and not in production!
git remote add mcmatrix https://github.com/mcmatrix/klipper
```
git fetch mcmatrix
sudo service klipper stop
git checkout mcmatrix/dev-release-20180622
make clean
make
sudo service klipper stop
make flash FLASH_DEVICE=/dev/ttyACM0
sudo service klipper start
Part of my test printer config:
```ini
[buttons killme]
pin: ^!ar41
gcode:
M112
# "RepRapDiscount 2004 Smart Controller" type displays
[display]
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
#lcd_type: st7920
#cs_pin: ar16
#sclk_pin: ar23
#sid_pin: ar17
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
encoder_pins: ^!ar33,^!ar31
click_pin: ^!ar35
# Menu manager
[menu]
root: main1
rows: 4
#cols: 20
cols: 16
[menu main1]
type: group
name: Main menu
#enter_gcode:
#leave_gcode:
items: menu1, menu2, test1, menu3
[menu menu1]
type: command
name: Resume octoprint
#gcode: @//resume
[menu menu2]
type: command
name: Pause octoprint
#gcode: @//pause
[menu test1]
type: command
name: Printing: {1:>3s}
parameter: toolhead.is_printing:b['NO','YES']
[menu menu3]
type: group
name: Group 1
#enter_gcode:
#leave_gcode:
items: menu4, menu5, menu6
[menu menu4]
type: command
name: Kill
gcode: M112
[menu menu5]
type: input
name: Move Z: {0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 Z{0:.2f}
[menu menu6]
type: input
name: Choose: {1:s}
parameter: 0:i('----', 'cola','pepsi','fanta','sprite')
input_min: 0
input_max: 4
input_step: 1
gcode: M117 My favorite: {1}
@KevinOConnor Could you make small change in buttons.py.
Replace pin_params = ppins.lookup_pin('digital_in', pin)
with pin_params = ppins.lookup_pin('digital_in', pin.strip())
On Wed, Jun 27, 2018 at 06:56:27AM +0000, Janar Sööt wrote:
@KevinOConnor Thank you.
dev-release-20180622 is updated and encoder is running very well
Now I can continue with menu testing.For brave testers this should help you with my dev-release checkout.
It's still beta firmware so use it ONLY FOR TESTING and not in production!
Great! I have some high level thoughts (dont't take them too
seriously as I haven't had a chance to really look at your code in
detail).
[buttons killme]
pin: ^!ar41
gcode:
M112
[...]
[menu menu4]
type: command
name: Kill
gcode: M112
I fear this wont work well because it would end up waiting for the
current command to finish before executing the M112. I think a kill
button (or menu item) would need to have some python code to make it
work correctly.
I noticed in the code that you're using
"self.gcode.run_script(script)". FYI, that isn't currently safe as it
could lead to the g-code processor being reentrant. The
self.gcode.process_batch() call is currently needed - as is used in
buttons.py and virtual_sdcard.py. However, I think it's probably
better to fix the gcode class instead of fixing this in the menu code
[...]
[menu main1]
type: group
name: Main menuenter_gcode:
leave_gcode:
items: menu1, menu2, test1, menu3
One thing that I think would be useful is if the code defined a bunch
of common menus by default. Then the config could override, extend,
or replace the defaults if desired. That way casual users can get a
basic menu without a lot of work. That said, no need to focus on that
now.
On Wed, Jun 27, 2018 at 12:02:59AM -0700, Janar Sööt wrote:
@KevinOConnor Could you make small change in buttons.py.
Replacepin_params = ppins.lookup_pin('digital_in', pin)
withpin_params = ppins.lookup_pin('digital_in', pin.strip())
Sure. In fact, ppins.lookup_pin() should be doing the strip itself.
I'll take a look at it.
Finally, you may have noticed that I moved the display.py code to its
own sub-directory in extras/. I hope this doesn't conflict too badly
with the work you've been doing. I wanted to get the code separated
so that it would be easier to merge future changes. Along those
lines, I wonder if menu.py could be moved to
klippy/extras/display/menu.py, have it instantiated by display.py, and
have it use config.get_prefix_sections('menu ') to find all the menu
blocks in the config (instead of using load_config() ).
-Kevin
I fear this wont work well because it would end up waiting for the
current command to finish before executing the M112. I think a kill
button (or menu item) would need to have some python code to make it
work correctly.
Is it possible to make it high priority gcode command?
So when gcode parser sees it then it will act immediately and it doesnt matter what else is going on.
It's also better for octoprint and repetier-server.
They have "emergency stop" button and it's calling M112 gcode.
The self.gcode.process_batch() call is currently needed - as is used in
buttons.py and virtual_sdcard.py. However, I think it's probably
better to fix the gcode class instead of fixing this in the menu code
I'll try to take a look at that.
OK I'll check how it's done in buttons and virtual_sdcard and do the same.
One thing that I think would be useful is if the code defined a bunch
of common menus by default. Then the config could override, extend,
or replace the defaults if desired. That way casual users can get a
basic menu without a lot of work. That said, no need to focus on that
now.
Actually it's a good idea to have standard common menu.
But what should be in that standard default menu for klipper?
This is probably topic for the next discussion-issue.
I hope this doesn't conflict too badly
with the work you've been doing.
No problem, i can handle it.
I wonder if menu.py could be moved to
klippy/extras/display/menu.py, have it instantiated by display.py, and
have it use config.get_prefix_sections('menu ') to find all the menu
blocks in the config (instead of using load_config() ).
OK did i understand it correctly. You're suggesting to get rid of [menu] section
[menu]
root: main1
rows: 4
cols: 20
move these attributes under [display] section and have it to initiate menu manager and load all the menu items?
I think it's doable.
Btw how should I initiate menu class itself (like buttons module)?
self.menu = self.printer.try_load_module(config, "menu")
When I'm looking into current display.py then it seems that I should just import menu
and initiate it as normal class?
On Thu, Jun 28, 2018 at 12:02:51AM -0700, Janar Sööt wrote:
I fear this wont work well because it would end up waiting for the
current command to finish before executing the M112. I think a kill
button (or menu item) would need to have some python code to make it
work correctly.Is it possible to make it high priority gcode command?
So when gcode parser sees it then it will act immediately and it doesnt matter what else is going on.
It's also better for octoprint and repetier-server.
They have "emergency stop" button and it's calling M112 gcode.
Klipper does do that when reading input, but it does not have that
logic in runscript() or process_batch() though. It's complex to scan
commands out of order, so I don't think it makes sense to add that
complexity to runscript(). Easier (and safer) to have code that
directly invokes the shutdown logic ( printer.invoke_shutdown() ).
OK did i understand it correctly. You're suggesting to get rid of
[menu]section[menu] root: main1 rows: 4 cols: 20move these attributes under
[display]section and have it to initiate menu manager and load all the menu items?
I think it's doable.
Btw how should I initiate menu class itself (like buttons module)?
self.menu = self.printer.try_load_module(config, "menu")
I was thinking something more like:
import menu
...
self.menu = menu.Menu(config)
BTW, the display should know the rows and columns (hd44780 is 20x4,
all others are 16x4), so unless I'm missing something it shouldn't be
necessary for the user to specify that in the config.
-Kevin
BTW, the display should know the rows and columns (hd44780 is 20x4,
all others are 16x4), so unless I'm missing something it shouldn't be
necessary for the user to specify that in the config.
Yes and no. The ready made RepRapDiscount Smart Controller (hd44780) has 20x4
and RepRapDiscount Full Graphic Smart Controller (builtin character generator) has 16x4.
But hd44780 can also have 16x4, 16x2, 8x2 etc variations.
Any other full graphic lcd using custom fonts can be different than 16x4.
We can make cols,rows to use default values by LCD_chips.
So that in common cases user doesn't have to specify these.
But lets leave option to specify different rows and cols if needed.
There're lot of DIY doers.
My dev-release-20180622 is updated to the latest.
Menu is now under display modules.
Encoder decoding is inside buttons.py RotaryEncoder class
Display is using that class from buttons.
Added kill_pin for emergency stop.
Menu run_scripts is using self.gcode.process_batch()
In config there's no more [menu] section, only menuitems remain.
Display config with menu looks like
# "RepRapDiscount 2004 Smart Controller" type displays
[display]
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
#lcd_type: st7920
#cs_pin: ar16
#sclk_pin: ar23
#sid_pin: ar17
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
root: main1
encoder_pins: ^!ar33,^!ar31
click_pin: ^!ar35
kill_pin: ^!ar41
Is it possible to use RepRapDiscount controller buzzer for having beeper?
It doesnt have to be that fancy like in marlin. Just to do short beeps is enought.
@mcmatrix - not sure code wise, but it is just a pin, so I don't think implementing it should be too difficult. I had some issues with some bleed back on the pin, so it's possible to set the pin high and low without much issue via set_pin
@AxMod3DPrint - I'll try that. It depends is it active or passive buzzer. With active buzzer it's easy just pin on/off. If it's passive then it's more complex you have to generate frequency for it.
It's just active on the Reprap Full Graphic and Reprap Smart, so it really is just an on/off
@hg42 New menuitem type row is available.
By using this you can make compact menu layouts having multiple items in one row.
It accepts command and input type items and it show items in one row.
It uses blinking as selecting indicator (underline is not possible on text screen).
Example menu config
# "RepRapDiscount 2004 Smart Controller" type displays
[display]
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
#lcd_type: st7920
#cs_pin: ar16
#sclk_pin: ar23
#sid_pin: ar17
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
root: main1
encoder_pins: ^!ar33,^!ar31
click_pin: ^!ar35
kill_pin: ^!ar41
[menu main1]
type: group
name: Main menu
#enter_gcode:
#leave_gcode:
items: menu1, menu2, test1, menu20, menu3
[menu menu1]
type: command
name: Resume octoprint
#gcode: @//resume
[menu menu2]
type: command
name: Pause octoprint
#gcode: @//pause
[menu test1]
type: command
name: Printing: {1:>3s}
parameter: toolhead.is_printing:b['NO','YES']
[menu menu3]
type: group
name: Group 1
#enter_gcode:
#leave_gcode:
items: menu4, menu5, menu6
[menu menu4]
type: command
name: Kill
gcode: M112
[menu menu5]
type: input
name: Move Z: {0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 Z{0:.2f}
[menu menu6]
type: input
name: Choose: {1:s}
parameter: 0:i('----', 'cola','pepsi','fanta','sprite')
input_min: 0
input_max: 4
input_step: 1
gcode: M117 My favorite: {1}
[menu menu20]
type: row
items: menu21,menu22,menu23
[menu menu21]
type: input
name: X:{0:.2f}
parameter: toolhead.xpos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 X{0:.2f}
[menu menu22]
type: input
name: Y:{0:.2f}
parameter: toolhead.ypos
input_min: 0
input_max: 300
input_step: 0.01
gcode: G1 Y{0:.2f}
[menu menu23]
type: input
name: Z:{0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.1
gcode: G1 Z{0:.2f}
It will show as one row:
>X:0.00Y:0.00Z:0.00
You can select them as normal menuitems.
It can be still buggy!
This is available for testing in dev-release-20180622
I propose initial structure for default menu
- Pause Octoprint
- Resume Octoprint
- Abort Octoprint
- SD Card print
- Start/resume
- Pause
- list of files
- Control
- Home Z
- Home X/Y
- Move 10mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Move 1mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Move 0.1mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Fan: ON/OFF
- Motors off
- Temperature
- Hotend: 23°
- Hotbed: 24°
- Preheat PLA
- Preheat all
- Preheat hotend
- Preheat hotbed
- Preheat ABS
- Preheat all
- Preheat hotend
- Preheat hotbed
- Cooldown
- Cooldown all
- Cooldown hotend
- Cooldown hotbed
- Filament
- Preheat hotend
- Unload Filament
- Load Filament
- Feed Filament
- Prepare
- Delta calibrate
- Bed Tilt
- Z Tilt
This will be the menu structure in example-menu.cfg
It's not meant to be final.
You can always customize that structure to meet your needs.
Looks pretty comprehensive to me.
Once thing that's crossed my mind, but would probably a whole lot of work,
would be pulling the file list from the Virtual SD folder and being able to
start and stop print via that. That would probably bring even more
accessibility to klipper by having those that do not like to run teathered
via octoprint or whatever front end. Just means you could CURL or SCP the
file directly to the virtual SD folder on the host and walk over to the
printer and start the print.
On 30 June 2018 at 13:34, Janar Sööt notifications@github.com wrote:
I propose initial structure for default menu
- Pause printing
- Resume printing
- Control
- Home Z
- Home X/Y
- Move 10mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Move 1mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Move 0.1mm
Move X: 000.0
Move Y: 000.0
Move Z: 000.0
Move E: 000.0
- Fan: ON/OFF
- Motors off
- Temperature
- Hotend: 23°
- Hotbed: 24°
- Preheat PLA
- Preheat all
- Preheat hotend
- Preheat hotbed
- Preheat ABS
- Preheat all
- Preheat hotend
- Preheat hotbed
- Cooldown
- Cooldown all
- Cooldown hotend
- Cooldown hotbed
- Filament
- Preheat hotend
- Unload Filament
- Load Filament
- Feed Filament
- Prepare
- Delta calibrate
- Bed Tilt
- Z Tilt
This will be the menu structure in example-menu.cfg
It's not meant to be final.
You can always customize that structure to meet your needs.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/KevinOConnor/klipper/issues/404#issuecomment-401538425,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AQULnn8EtabxIdJRcyUdWx5wCnKqA2Gqks5uB3A8gaJpZM4Uq-yU
.
@AxMod3DPrint You're right, it's probably lot of work to integrate with menu but I'll check that virtual sd stuff.
EDITED: Looks quite doable! It's a simple list of files. Folders are not supported atm.
Btw RepRapDiscount has active buzzer so this will work.
[output_pin buzzer]
pin: ar37
[gcode_macro BEEP]
gcode:
SET_PIN PIN=buzzer VALUE=1
G4 P200
SET_PIN PIN=buzzer VALUE=0
This G4 P200 - i added 200ms pause but it's ok without it too
Now BEEP gcode can be easily inserted into print start & end scripts.
@mcmatrix
Just tested your branch, got to say: Awesome work, thank you very much, I really appreciate the effort you put into implementing the menu.
May I ask:
On Thu, Jun 28, 2018 at 12:14:29PM -0700, Janar Sööt wrote:
My
dev-release-20180622updated to the latest.
Menu is now under display modules.
Encoder decoding is inside buttons.py RotaryEncoder class
Display is using that class.
Thanks. I've gone ahead and merged the low-level button code into the
master branch. This also includes some changes: pin.strip() is done
on pin lookup, I've added buttons.register_rotary_encoder() and
buttons.register_button_push() helper methods, and the
gcode.run_script() can now be run from button callbacks.
If you're ready for submitting your changes, that would be great.
-Kevin
@KevinOConnor Thats great.
I need to make slight changes in display according to new buttons methods.
My button.py with changes in RotaryEncoder class can be submitted.
I'll rebase it to the latest and then submit PR for buttons.
With menu I need more time for testing. Recently added 2 new menuitem types.
@AxMod3DPrint Added new menuitem type sdcard
It requires that virtual_sdcard is active. If not then then this item is not enabled in menu.
[menu menu99]
type: sdcard
name: SD Card print
items: sdcard01, sdcard02
[menu sdcard01]
type: command
name: Start/resume
gcode: M24
[menu sdcard02]
type: command
name: Pause
gcode: M25
All menuitems in items attribute are added before files (but you can also remove items).
It shows file in menu as command type menuitem and
when selecting it will execute M23 /filename
Folders are not working at the moment because virtual_sdcard is not supporting folders.
But folders can be easily implemented into menu by using group menuitem.
@Zwaubel
Is there an easy way to dynamically hide and show menus/menu items depending on the printer state? (e.g. show menu "homing" when not printing and hide it when printing)
There is an option. All menuitems have enable: attribute. By default it's True.
You can use the same list of variables as for parameter attribute.
It will convert any value to boolean. You have also option for negation.
NB! It will not hide/show menu when you are in menu.
It's only checking it when you open menu from overview screen.
For example:
Item is only available when printing
[menu cmd01]
type: command
enable: toolhead.is_printing
name: Home
gcode: G28
Item is only available when not printing
[menu cmd01]
type: command
enable: !toolhead.is_printing
name: Home
gcode: G28
Sorry I dont have documented all that stuff yet.
Is there an option to invert the rotary encoder direction depending on the menu it is in?
EDITED: Just general encoder direction change by reversing pins order.
encoder_pins: ^!ar33,^!ar31 to encoder_pins: ^!ar31,^!ar33
Not menuitem based atm, but I think it can be implemented.
You ask possibility to change encoder direction for input type menuitem?
Is there an option to set time out after which the menu automatically disappears?
Theres no timeout for menu at the moment.
@mcmatrix
You ask possibility to change encoder direction for input type menuitem?
yeah, that is exactly what I'm looking for.
I just tested your new sdcardtype menu and it seems that this type does not like to have sub menus of type commandwhich use the enable:attribute.
For instance if I do the following
[menu menu99]
type: sdcard
name: SD Card print
items: sdcard01, sdcard02
[menu sdcard01]
type: command
name: Start/resume
gcode: M24
enable: !toolhead.is_printing
[menu sdcard02]
type: command
name: Pause
gcode: M25
enable: toolhead.is_printing
klipper will crash as soon as I try to enter the menu.
Further questions regarding inputtype menus:
Is there a list / file anywhere which contains all parameters that can be manipulated?
Lets say I want to change the hotend temp, how would I do that?
[menu tempHotend]
type: input
name: Set Temperature: {0:.2f}
parameter: extruder.temp
input_min: 0
input_max: 250.0
input_step: 1.0
gcode: M104 S{0:.2f}
--> This does not work, most probably because the parameter I used, is nonexistent (I just guessed it).
Same (not working) example for the fan control:
[menu fanValue]
type: input
name: Fan Value {0:.3f}
parameter: fan.value
input_min: 0
input_max: 1.0
input_step: 0.05
gcode: SET_PIN PIN=fan VALUE={0:.2f}
Hello mcmatrix,
great work i can say that from now and i try to create basic menu tree on my klipper setup.Here are the config.I ll use this like 2 days sometimes need firmware restart but no issues.Maybe you want to use or another user may be decide to use. Last section is still waiting for future use :D
[display]
lcd_type: st7920
cs_pin: ar16
sclk_pin: ar23
sid_pin: ar17
root: main1
encoder_pins: ^!ar31,^!ar33
click_pin: ^!ar35
kill_pin: ^!ar41
[menu main1]
type: group
name: Main menu
items: menu0, menu00, menu1, menu2, menu3
[menu menu0]
type: row
enable: !toolhead.is_printing
items: menu25,menu26,menu27
[menu menu00]
type: command
name: Kill
gcode: M112
[menu menu1]
type: group
enable: !toolhead.is_printing
name: Temperature
items: menu11, menu12, menu13, menu14, menu15
[menu menu11]
type: command
name: Preheat Pla
gcode: M140 S60;M104 S230
[menu menu12]
type: command
name: Preheat Abs
gcode: M140 S110;M104 S245
[menu menu13]
type: command
name: CoolDown
gcode: M104 S0;M140 S0
[menu menu14]
type: command
name: Fan On
gcode: M106 S255
[menu menu15]
type: command
name: Fan Off
gcode: M106 S0
[menu menu2]
type: group
enable: !toolhead.is_printing
name: Movement
items: menu21, menu22, menu23,menu24, menu25, menu26, menu27
[menu menu21]
type: command
name: Home X
gcode: G28 X
[menu menu22]
type: command
name: Home Y
gcode: G28 Y
[menu menu23]
type: command
name: Home Z
gcode: G28 Z
[menu menu24]
type: command
name: Disable Steppers
gcode: M84; M18
[menu menu25]
type: input
name: X:{0:.2f}
parameter: toolhead.xpos
input_min: 0
input_max: 190
input_step: 5.0
gcode: G1 X{0:.2f}
[menu menu26]
type: input
name: Y:{0:.2f}
parameter: toolhead.ypos
input_min: 0
input_max: 190
input_step: 5.0
gcode: G1 Y{0:.2f}
[menu menu27]
type: input
name: Z:{0:.2f}
parameter: toolhead.zpos
input_min: 0
input_max: 180
input_step: 1.0
gcode: G1 Z{0:.2f}
[menu menu3]
type: group
name: Status
items: menu31, menu32, menu33
[menu menu31]
type: command
name: Printing: {1:>3s}
parameter: toolhead.is_printing:b['NO','YES']
[menu menu32]
type: command
name: Pause Print
gcode: @//pause
[menu menu33]
type: command
name: Resume Print
gcode: @//resume
@Zwaubel Could you attach klipper log and your printer config after it crashes.
For me it's not crashing when using same menus.
I'll add new gcode for menu, so that it will dump list of all parameters available.
@ygtc Nice menu you have.
@mcmatrix
It's not crashing but simply not working the way I want it to:
I want to be able to set the printers temperature using a inputtype menu but don't know what I do have to use as a parameter. Same applies to the fan control: I want to set the speed/pwm duty cycle but don't know the correct parameter to use.
=============
Just had a few crashes while using the menu:
Oh and the sdcard type menu does not like submenus which have a specific enableattribute set.
Doing something like this:
[menu octoPrintVirtualSDCard]
type: sdcard
name: Browse Files
items: octoStartPrint, octoPausePrint
[menu octoStartPrint]
type: command
name: Start Printing
gcode: M24
enable: !toolhead.is_printing
[menu octoPausePrint]
type: command
name: Pause Printing
gcode: M25
enable: toolhead.is_printing
would lead to klipper not even starting.
I attached my config and log files for all three crashes in the zip file below.
logs_and_config.zip
@Zwaubel Thank you for feedback.
From logs i see clearly that menu is crashing in klippy_crashed_while_idling.log and klippy_crashed_while_heating.log
I'll investigate why it's doing it and will fix it.
Here klippy_while_printing_crashed.log i don't see why it's restarting, no visible exceptions.
The menu itself is not printing anything.
@KevinOConnor In this case could it be problem in virtual_sdcard functionality.
dev-release-20180622 is updated.
Fixed one bug, hopefully didn't produce more.
NB! sdcard type is change to vsdcard
Added gcodes for menu control.
MENU DO=dump ; will dump all parameters (open menu, otherwise parameters are not populated)
MENU DO=exit ; exit from menu
MENU DO=up
MENU DO=down
MENU DO=select
MENU DO=back
Just now added reverse option for input.
Default value it's false, accepts values 0 or 1, or just leave it out
It will reverse the input inc & dec
[menu moveX_1mm]
type: input
name: Move X: {0:.2f}
parameter: toolhead.xpos
reverse: 1
input_min: 0
input_max: 150
input_step: 1.0
gcode: G1 X{0:.2f}
enable: !toolhead.is_printing
Brave testers, please attach klippers log & config in case of error report.
Just now added reverse option for input.
Default value it's false, accepts values 0 or 1, or just leave it out
Nice! works perfectly!
One question remaining regarding the input type menu:
Is there a list / file anywhere which contains all parameter option that can be manipulated?
I'm talking about these values: toolhead.is_printing, toolhead.zpos,...
Lets say I want to change the hotend temp, how would I do that?
[menu tempHotend]
type: input
name: Set Temperature: {0:.2f}
parameter: extruder.temp
input_min: 0
input_max: 250.0
input_step: 1.0
gcode: M104 S{0:.2f}
--> This does not work, most probably because the parameter I used, is nonexistent (I just guessed it).
Same (not working) example for the fan control:
[menu fanValue]
type: input
name: Fan Value {0:.3f}
parameter: fan.value
input_min: 0
input_max: 1.0
input_step: 0.05
gcode: SET_PIN PIN=fan VALUE={0:.2f}
@Zwaubel
MENU DO=dump
Will dump available parameters into terminal and also to log.
The output will depend on what modules are enabled in config.
You should open menu, otherwise parameter list is not populated
MENU DO=dump
Will dump available parameters into terminal and also to log.
The output will depend on what modules are enabled in config.
You should open menu, otherwise parameter list is not populated
Oh, my bad.. I wasn't paying enough attention to your prior posts.
@mcmatrix
One thing that came in my mind:
Wouldn't it be a good addition to have the menu name (of the menu you are currently in) showing up in the first row of the lcd.
I'm talking about something like this:
=============================
| Temperature |
=============================
| <- |
| > Preheat PLA |
| > Set Temp. Hotend |
| > Set Temp Bed |
| > Cool down |
=============================
For full graphic lcds there should be plenty of space if you lower the font size to implement something like that.
@Zwaubel
Currently max available row count is 4 (even for graphical lcd, it's using builtin text mode).
Just updated new version where title is next to back
@mcmatrix
Oh okay. No chance to draw your own shapes or anything?
Your solution works for me!
Last update for today.
I tried to add output_pin and servo values to parameters (could be buggy, sorry).
There's no nice way of doing it, so i'm just peeking what output_pins and servos are available
in config and then just reading their last_values.
This way you are able to get feedback back to menuitem.
@mcmatrix
New menuitem type row is available.
sorry for not answering yet...
I appreciate your effort and the configuration looks good.
However I don't use an LCD, yet. I only made suggestions looking forward to future uses.
One thing I noticed:
Is there a possibility to configure a space between two entries on one line? It seems to be difficult to add a space before or after the string value (hmm, or can we use "..." ?).
One thing I noticed:
Is there a possibility to configure a space between two entries on one line? It seems to be difficult to add a space before or after the string value (hmm, or can we use "..." ?).
I think the easiest way is to support optional beginning and ending quotes (or apostrophes) for name values.
@mcmatrix
The menu seems to pretty stable right now, no klipper crashes while heating up or printing. 👍
How do I use the parameter: fan properly, if I want to set the value via a input type menu?
Something like
[menu fanValue]
type: input
name: Fan Speed: {0:.2f}
parameter: fan.speed
input_min: 0.0
input_max: 1.0
input_step: 0.01
gcode: SET_PIN PIN=fan VALUE={0:.2f}
reverse: True
enable: !toolhead.is_printing
does not work.
Same question regarding the parameter: output_pin:
This
[menu caseLightValue]
type: input
name: Case Light: {0:.2f}
parameter: caseLightPin.value
input_min: 0
input_max: 1.0
input_step: 0.05
gcode: SET_PIN PIN=caseLightPin VALUE={0:.2f}
enable: True
does not work.
Some changes, hopefully without bugs.
Now you can enclose name into quotes in config.
name: "X:{0:.2f} "
Menu has it's own timers for blinking and timeout.
Config attributes have been changed!
# new timeout option in seconds, if 0 or no parameter then there's no menu timeout
menu_timeout: 10
# root is now menu_root
menu_root: main
Parameter attribute is even more flexible now.
You can use mapping options like (look 1st post) this parameter: endstop.xmax:b["OPEN", "TRIG"]
or you can use it as a scaling option (it accepts ints and floats).
parameter: fan.speed:i255
It means that format option 1 is now (value * scale) converted to int
format option 0 is still normal value.
It can be used in cases where parameter value is in range 0....1
and value in gcode and name should be in other range like 0..255.
[menu fanValue]
type: input
name: Fan Speed {1:3d}
parameter: fan.speed:i255
input_min: 0
input_max: 1
input_step: 0.00392
gcode: M106 S{1:d}
enable: !toolhead.is_printing
@Zwaubel
Same question regarding the parameter: output_pin:
This[menu caseLightValue]
type: input
name: Case Light: {0:.2f}
parameter: caseLightPin.value
input_min: 0
input_max: 1.0
input_step: 0.05
gcode: SET_PIN PIN=caseLightPin VALUE={0:.2f}
enable: True
does not work.
Parameter name is wrong for that pin. It's output_pin.caseLightPin
Try something like this.
[menu caseLightValue]
type: input
name: Case Light: {1:3d}
parameter: output_pin.caseLightPin:i255
input_min: 0
input_max: 1.0
input_step: 0.00392
gcode: SET_PIN PIN=caseLightPin VALUE={0:.3f}
enable: True
@mcmatrix
Parameter name is wrong for that pin. It's output_pin.caseLightPin
Try something like this.[menu caseLightValue] type: input name: Case Light: {1:3d} parameter: output_pin.caseLightPin:i255 input_min: 0 input_max: 1.0 input_step: 0.00392 gcode: SET_PIN PIN=caseLightPin VALUE={0:.3f} enable: True
Works like a charm, thank you very much!
Hopefully no more features ;)
Please test. Lets try to find as many bugs as possible!
In case of menu crash please include klippers log & config.
I'll start preparing example menus, prepare preliminary description of all features
and then it's more or less ready for PR.
@mcmatrix
Hopefully no more features ;)
Please test. Lets try to find as many bugs as possible!
In case of menu crash please include klippers log & config.
I'm on it!
How can I help testing, What branch should I checkout?
I have simplified parameter transformations.
Now parameter attribute should contain only parameter name or static float | int value
I added additional attribute transform
Example:
# Interpolation example
[menu fanValue]
type: input
name: Fan Speed {1:3d}
parameter: fan.speed
transform: (0,1,0,255)
input_min: 0
input_max: 1
input_step: 0.00392
gcode: M106 S{1:d}
# Scaler example
[menu caseLightValue]
type: input
name: Case Light: {1:3d}
parameter: output_pin.caseLightPin
transform: 255
input_min: 0
input_max: 1.0
input_step: 0.00392
gcode: SET_PIN PIN=caseLightPin VALUE={0:.3f}
# custom choice example
[menu menu6]
type: input
name: Choose: {1:s}
parameter: 0
transform:['----', 'cola','pepsi','fanta','sprite']
input_min: 0
input_max: 4
input_step: 1
gcode: M117 My favorite: {1}
For transform attribute you have following options.
There's no more type cast letter.
(#,#) - parameter → boolean choice, output depends from tuple element type
(#,#,#,#) - parameter interpolate `(from_min, from_max, to_min, to_max)`, output type is same as `to_max` type
"ABC" - parameter → integer choice, output type is string
[#,#,#,...] parameter → integer choice, output type depends from list element type
255 - parameter scaler, output type depends from scale factor type
{1:"open",2:"close",3:"unknown",...} parameter → [integer | float | string] (depends from first key type) choice, output depends from element value type
Usage of these values remain same.
{0} is parameter raw value
{1} is transformed parameter value (not available if attribute is not used)
name: Test value {0} transformed {1}
All python print formatting options will work.
dev-release is updated
@mvturnho Please check this comment https://github.com/KevinOConnor/klipper/issues/404#issuecomment-399739544
I tested with my Tronxy board (Melzi type) with a Tronxy graphical LCD (ST7920).
I basically used @Zwaubel's config, with some minor changes:
menu_*, entry_*, etc.)"..." to include spacestransform attributeEverything works well for me (though my test environment cannot print, so I couldn't test this part).
Some remarks/questions/wishes (I am not up to date with the display and menu branches, comments etc. so I appologize if I am asking something already discussed, I searched but didn't find something):
config:
[display]
lcd_type: st7920
cs_pin: tronxy:PA1
sclk_pin: tronxy:PC0
sid_pin: tronxy:PA3
encoder_pins: ^!tronxy:PD2,^!tronxy:PD3
click_pin: ^!tronxy:PA5
#kill_pin: ^!tronxy:...
menu_root: root
[menu root]
type: group
name: Main menu
#enter_gcode:
#leave_gcode:
items: xyz, kill, menu_temp, menu_move, status
[menu xyz]
type: row
enable: !toolhead.is_printing
items: move_X,move_Y,move_Z
[menu kill]
type: command
name: Kill
gcode: M112
[menu menu_temp]
type: group
enable: !toolhead.is_printing
name: Temperature
items: preheat_PLA, preheat_ABS, cool_down, fan_on, fan_off
[menu preheat_PLA]
type: command
name: Preheat Pla
gcode: M140 S60;M104 S230
[menu preheat_ABS]
type: command
name: Preheat Abs
gcode: M140 S110;M104 S245
[menu cool_down]
type: command
name: CoolDown
gcode: M104 S0;M140 S0
[menu fan_on]
type: command
name: Fan On
gcode: M106 S255
[menu fan_off]
type: command
name: Fan Off
gcode: M106 S0
[menu menu_move]
type: group
enable: !toolhead.is_printing
name: Movement
items: home_X, home_Y, home_Z,disable, move_X, move_Y, move_Z
[menu home_X]
type: command
name: Home X
gcode: G28 X
[menu home_Y]
type: command
name: Home Y
gcode: G28 Y
[menu home_Z]
type: command
name: Home Z
gcode: G28 Z
[menu disable]
type: command
name: Disable Steppers
gcode: M84; M18
[menu move_X]
type: input
name: "X:{0:.0f} "
parameter: toolhead.xpos
input_min: -159
input_max: 155
input_step: 5.0
gcode: G1 X{0:.0f}
[menu move_Y]
type: input
name: "Y:{0:.0f} "
parameter: toolhead.ypos
input_min: -155
input_max: 155
input_step: 5.0
gcode: G1 Y{0:.0f}
[menu move_Z]
type: input
name: "Z:{0:.1f} "
parameter: toolhead.zpos
input_min: 0
input_max: 300
input_step: 0.1
gcode: G1 Z{0:.1f}
[menu status]
type: group
name: Status
#enter_gcode:
#leave_gcode:
items: printing, pause, resume
[menu printing]
type: command
name: Printing: {1:>3s}
parameter: toolhead.is_printing
transform: ('NO','YES')
[menu pause]
type: command
name: Pause Print
gcode: @//pause
[menu resume]
type: command
name: Resume Print
gcode: @//resume
#[menu choose]
#type: input
#name: Choose: {1:s}
#parameter: 0:i('----', 'cola','pepsi','fanta','sprite')
#input_min: 0
#input_max: 4
#input_step: 1
#gcode: M117 My favorite: {1}
ok, I integrated my display into a working printer.
I see the menu entries update online, nice!
Entering the root menu once to display as all-in-one page once is ok for now.
I also tried some things to build an all-in-one main page (for now the root menu, which I enter once).
Most things already work, but two things:
(0,100,0,255), because the fan.speed is in the range 0-1.0[menu e__fan]
type: input
name: "F{0:.1f} "
parameter: fan.speed
input_min: 0.0
input_max: 1.0
input_step: 0.1
transform: 255
gcode: M106 S{1:.0f}
[menu e__bed]
type: input
name: "B{0:.0f}={1:.0f} "
parameter: heater_bed.target, heater_bed.temperature
input_min: 0
input_max: 135
input_step: 5
gcode: M140 S{0:.0f}
this works:
[menu r__temp]
type: row
#enable: !toolhead.is_printing
items: e__bed, e__bed_now, e__hotend, e__hotend_now
[menu e__bed]
type: input
name: "B{0:.0f}"
parameter: heater_bed.target
input_min: 0
input_max: 135
input_step: 5
gcode: M140 S{0:.0f}
[menu e__bed_now]
type: command
name: ":{0:.0f} "
parameter: heater_bed.temperature
[menu e__hotend]
type: input
name: "T{0:.0f}"
parameter: extruder0.target
input_min: 0
input_max: 230
input_step: 5
gcode: M104 S{0:.0f}
[menu e__hotend_now]
type: command
name: ":{0:.0f} "
parameter: extruder0.temperature
It would be nice if the *_now entries could be skipped when selecting a field.
Is there a type for a pure display?
I think, in addition to transform we would need something like reverse_transform to scale the current parameter value.
Eventually something like:
parameter --[rtransform]--> input --[transform]--> parameter2
where parameter2 could be the same as parameter.
I think, transforming at the place where the value is used or retrieved seems to be more flexible than a single transform.
E.g. I could display the same value with two scales:
{0:.0f(0,1,0,100)}%={0:.0f(0,1,0,255)}
In general the model could have
May be something like this could be used:
parameter: heater_bed.target, heater_bed.temperature
could result in the first parameter in {0} and the second in {1}. I think, this would work, if the scaling is done at the place of use.
The first would always be the target of the input, the second (and even more) could be added for displaying current data.
The target parameter could have a transformation attached (like it was before).
E.g. a parameter like fan.is_enabled could be displayed additionally to fan.speed or additional to heater_bed.temperature we could display something like case.temperature.
just some ideas...
I think, the title on the root menu could be ommitted (eventually as an option).
There are cases where no submenu is used.
@hg42
It would be nice if the *_now entries could be skipped when selecting a field.
Is there a type for a pure display?
Yep, it would be nice feature. I propose that command without gcode should be considered as static or display item for row
I'm testing this change atm.
Multiple parameters will make everything too complex, i already have in testing following:
Multiple transformations.
Like this
[menu control_fanspeed]
type: input
enable: fan.is_enabled
name: Fan speed:{1:3d}%
parameter: fan.speed
transform:
(0,1,0,100)
(0,1,0,255)
input_min: 0
input_max: 1
input_step: 0.01
gcode: M106 S{2:d}
The background value is still the same fan.speed having float range 0→1
You will define 2 transformations:
{1} interpolate raw value to new range 0→100
{2} interpolate raw value to new range 0→255
In background you still change float value but with step : 1/100 = 0.01
To have percentage from value in float range 0→1, python has format option for this {0:4.0%}
Fixed size percentage without decimals.
example2 of multi transforms. Btw you can have more that 2 transformation :)
[menu control_fanonoff]
type: input
enable: fan.is_enabled
name: Fan {1:3s}
parameter: fan.speed
transform:
('OFF','ON')
(0,255)
input_min: 0
input_max: 1
input_step: 1
gcode: M106 S{2:d}
These changes are in my local test not released yet!
fine, there are several ways to solve this and multiple tranformations seems to be equivalent and it is consistent, which I think is important.
"command" without gcode makes sense, too.
I always found that lcd screens need too much input operations to be useful.
But now I can define a single shortcut screen that contains most of the most important operations and I really start using it.
That's awesome...
Another suggestion:
"command" with a python script for unusual operations.
I'm thinking about getting rid of row menuitem as external separate config element.
It's easier to use it like this (it remains internally).
items: menu1, menu21;menu22;menu23, menu3, menu4
where items delimited by comma are separate menu items and those delimited by semicolon belong into one row.
Edited: or 'pipe' character items: menu1, menu21|menu22|menu23, menu3, menu4
usually semicolons divide more...
You could use a dash to symbolize the direction.
or simply write it without whitespace
items: menu1, menu21 menu22 menu23, menu3, menu4
or write it with string as separator (special case: only whitespace):
items: menu1, menu21 " " menu22 "" menu23 ": " menu24, menu3, menu4
I have made many changed and added new features.
My aim is to make menu as flexible as possible.
So that it can even be used as working display.
I'm almost finish with these, still few thing need to complete.
I hope to update to dev tomorrow, 09.07!
I'll let you all know,
So excited to add this to my printer. Thank you for the hard work
Hi, I tested the dev branch today and found a problem. When I start a home command from the menu's and while homing I update the printer light with the menu and rotating the encoder all goes well. The lights are only updated after homeing finishes, but that is just how ikt works.
Then when I start my bed leveling using the menu with gcode command; Z_TILT_ADJUST and then enter the menu to adjust the light the printer crashes. It seems the encoder activity crashes the printer when probe-ing
I attached my log it should include miy config as well.
Hi guys,
It's taking longer than excpected. I had to redesign couple of times.
But now it's more or less working.
It still needs work but here are 2 teaser images :)


It's flexible and can be used as normal menu or/and statusscreen replacement.
It has built in sequencer and multipage option
also inline editing of values is possible if needed.
Let you know when it's available for testing.
sounds awesome...
just take the time it needs...no hurry...
I will be happy to test this, when I'm back from vacations (in about two weeks)
FYI, the more features that are added the harder reviewing will be, and that might make merging into the master branch harder. I'm all for replacement of the status display with something more flexible, but I suspect it would be preferable to do that in separate commits from basic menu support.
Cheers,
-Kevin
EDIT: To be clear, I appreciate your work on this and look forward to seeing it fully merged. Thanks!
btw. would the concept allow more than one display (eventually with different menu structure)?
Just a thought (because I have another spare display laying around). Not sure how this could work and what could be the benefits.
May be as a remote display or as extension for the first one with different parameters.
Klipper opens up so much possibilities never thought of before. We can use old spare hardware (or cheap new ones) for new purposes.
I don't think of it being implemented right now, but this might be the best time to make the definitions open enough for such possibilities.
I guess, we would only need a named menu root (that could use the same pages or define it's own, which is easily managed by their names).
So, I think the current definition would already be extensible to that.
@KevinOConnor
That let's me refresh my request to allow every section to be named like [<class_name> <instance_name>].
Eventually with a shortcut [<class_name>] meaning
either [<class_name> <class_name>]
or some standard name like [<class_name> default] or [<class_name> main] or [<class_name> __main__] or similar.
@KevinOConnor I guess it's a simplification and a unification, so it should improve patch management. Though it may still be possible to split this into two separate steps.
First step adding support for menu modules, second adding this flexible module.
First step adding support for menu modules
actually, I meant splitting the display code into hardware display (which could be further divided into hardware specific modules) and status display and allowing to register alternate status display(s).
However, looking at display.py it seems like half of it would be replaced by the new code.
The different screen_update_xxx functions would probably be handled by different defaults for the "menu"?
FYI, the more features that are added the harder reviewing will be, and that might make merging into the master branch harder. I'm all for replacement of the status display with something more flexible, but I suspect it would be preferable to do that in separate commits from basic menu support.
It's fine, I understand your concern.
I'm only changing display module as much as is needed for menu subsystem support.
The magic is all happening inside menu module.
The original status display and everything else remains.
It's up to user who can choose what he/she wants to use.
Hi guys,
Moving slowly, enjoing my last vacation week and summer heatwave in Estonia.
Let you know when the new development release will be available.
New development release is ready for testing.
I made new branch dev-release-20180720 for it!
NB! Please be aware that config has changed, please look example-menu.cfg
For new testers please use following steps to get menu:
Install original klipper first.
Set it up correctly, make sure that everything works and then check out my dev-release for testing.
This way by using git checkout you can easily switch between different branches.
This should help with my dev-release checkout.
git remote add mcmatrix https://github.com/mcmatrix/klipper
git fetch mcmatrix
git checkout mcmatrix/dev-release-20180720
make clean
make
sudo service klipper stop
make flash FLASH_DEVICE=/dev/ttyACM0
sudo service klipper start
md5-a2d8546d76e5307a6e8c63e306675367
# timeout in seconds, leave it out if not needed
menu_timeout: 60
# to use menu you have to specify root menu entry
# for stock statusscreen and menu use `main`
# for custom statusscreen use `infoscreen`
menu_root: main
# this option allows to run menu immediately at startup.
# use it for custom statusscreen
menu_autorun: yes
I have built example menu tree and made few sample statusscreens.
You can change everything and build your own menu structure and status screens.
All statusscreen cards made for 20x4. Users having 16x4 displays have to modify these cards to fit.
I tried to show config options in example-menu.cfg
I need to start doing boring stuff too, documenting menu configuration options.
This is still missing.
Hi being a novice would it be possible for you to go into detail on how to install your menu system.
I have klipper installed (did that about 8 weeks ago so not the latest version) and the original klipper menu is working (just a static screen with little info, nothing else).
I use Putty SSH to connect to Raspberry Pi3
git remote add mcmatrix https://github.com/mcmatrix/klipper
fatal: Not a git repository (or any of the parent directories): .git
git fetch mcmatrix
fatal: Not a git repository (or any of the parent directories): .git
Do not know where to go from here.
regards - bruce
@bruce356 You have to be inside klipper directory.
cd ~/klipper/
Thanks that worked, do I just have to copy the contents of your example-menu.cfg into my printer.cfg file (which by the way is the generic-rumba.cfg), I have done that but my GLCD shows no change the menu is still the original static display.
I used sudo service klipper stop and sudo service klipper start
regards
@bruce356 Could you attach you klipper config to comment.
Then I can see what have you done.
@mcmatrix please find attached my printer.cfg file
regards
printer.zip
@bruce356 To use menu you have to enable it in display section
First you have to find out what pins to use for buttons and encoder.
In example-extras.cfg
# Support for a display attached to the micro-controller.
#[display]
#lcd_type:
# The type of LCD chip in use. This may be "hd44780" (which is
# used in "RepRapDiscount 2004 Smart Controller" type displays),
# "st7920" (which is used in "RepRapDiscount 12864 Full Graphic
# Smart Controller" type displays) or "uc1701" (which is used in
# "MKS Mini 12864 type" displays). This parameter must be provided.
#rs_pin:
#e_pin:
#d4_pin:
#d5_pin:
#d6_pin:
#d7_pin:
# The pins connected to an hd44780 type lcd. These parameters must
# be provided when using an hd44780 display.
#cs_pin:
#sclk_pin:
#sid_pin:
# The pins connected to an st7920 type lcd. These parameters must be
# provided when using an st7920 display.
#cs_pin:
#a0_pin
# The pins connected to an uc1701 type lcd. These parameters must be
# provided when using an uc1701 display.
#menu_root:
# Entry point for menu, root menuitem name. This parameter must be
# provided when using menu.
#menu_timeout:
# Timeout for menu. Being inactive this amount of seconds will trigger
# menu exit or return to root menu when having autorun enabled [optional]
#menu_autorun:
# Enable this to run menu immediately at startup. It's mostly used to replace
# stock info screens with custom ones. It accepts boolean values,
# default is False. [optional]
#rows:
# Only needed when using display with custom row count [Optional].
#cols:
# Only needed when using display with custom column count [Optional].
#encoder_pins:
# The pins connected to encoder. 2 pins must be provided when
# using encoder. This parameter must be provided when using menu.
#click_pin:
# The pin connected to 'enter' button or encoder 'click'. This parameter
# must be provided when using menu.
#back_pin:
# The pin connected to 'back' button [Optional].
#up_pin:
# The pin connected to 'up' button. This parameter must be provided
# when using menu without encoder.
#down_pin:
# The pin connected to 'down' button. This parameter must be provided
# when using menu without encoder.
#kill_pin:
# The pin connected to 'kill' button. This button will call
# emergency stop.
This is my test config for display section
[display]
lcd_type: hd44780
rs_pin: ar16
e_pin: ar17
d4_pin: ar23
d5_pin: ar25
d6_pin: ar27
d7_pin: ar29
#menu_root: infoscreen
menu_root: main
#menu_autorun: yes
#menu_timeout: 60
encoder_pins: ^!ar31, ^!ar33
click_pin: ^!ar35
kill_pin: ^!ar41
Added initial draft description of menu element attributes to example-menu.cfg
@mcmatrix nice work of yours!
I noticed two minor issues regarding the case light control in your example menu:
config atteched:
printer.zip
Should be fine now.
Please check example-config there was a mistake in caselight gcode.
I had to remove realtime menuitems enable/disable update.
When executing gcode klipper goes for a couple of seconds to the printing state
and it was causing menuitems hide/show and cursor jump.
Now items enable/disable status is only updated when entering to menu or submenu.
Great! Works fine now, thank you!
@mcmatrix thanks very much for your efforts to help me.
I am complete novice and have been trying to get # "RepRapDiscount 128x64 Full Graphic Smart Controller" working for many hours but this pins thing is so confusing (China Rumba board). Why is "^!" placed before the pin number.
I will wait for someone with more knowledge to get this type of GLCD working.
regards - bruce
@bruce356 The "^!" syntax is described in the example.cfg configuration file:
Pin names may be preceded by an '!' to indicate that a reverse polarity should be used (eg, trigger on low instead of high).
Input pins may be preceded by a '^' to indicate that a hardware pull-up resistor should be enabled for the pin.
You may have to look at the datasheet for your screen in order to determine the pinout of your LCD.
If I understood well, you have this LCD screen. The reprap wiki page gives you the following schematics, and you can find the config for your LCD and board in the Marlin firmware example.
If you don't know how the pins have to be trigerred (high or low), you can just experiment with the config... as long as the wiring is fine, there is no risk for the hardware :)
@Taz8du29, Thanks for the information, you inspired me to try again.
This is my final result
RepRapDiscount 128x64 Full Graphic Smart Controller
[display]
lcd_type: st7920
cs_pin: ar19
sclk_pin: ar18
sid_pin: ar42
menu_timeout: 60
menu_root: main
menu_autorun: yes
encoder_pins: ^ar11, ^ar12
click_pin: ^ar43
kill_pin: ^!ar46
The kill_pin just seems to lock up the system (I expected a reset as in Marlin) but its not required very often so does not matter.
@mcmatrix this is a fantastic result thank you very much.
regards - bruce
@KevinOConnor What you think? Should we wait for more testings (It's a summertime and people are away from computers) or I'll make PR with 2 commits (for display modifications and menu stuff) and lets merge it with master.
On Wed, Jul 25, 2018 at 12:01:31AM -0700, Janar Sööt wrote:
@KevinOConnor What you think? Should we wait for more testings (It's a summertime and people are away from computers) or I'll make PR with 2 commits (for display modifications and menu stuff) and lets merge it with master.
I'd like to see this merged. Once it's in the main branch, I suspect
we will see more testers.
Also, once it's submitted as a github pull-request, it will make it
easier for me to review.
Thanks,
-Kevin
@mcmatrix , hi just a thought, seeing how you are a good knowledgeable programmer (only if you have the spare time) had you given any thoughts to mesh bed levelling for Klipper using a probe like the BLTouch. This would make Klipper far more attractive for larger printer bed users.
regards - bruce
@bruce356 Thank you. There are more talented programmers than me :)
I'm having delta with glass bed so mesh leveling is quite useless for me.
If my bed is somehow transformed then my delta calibration will be off anyway.
Don't worry, if the Klippers community will grow then all needed features will come sooner or later ;)
@mcmatrix , hi would it be possible to add "Babystepping" to the Z axis to fine tune the first layer offset from the bed (maybe in 0.005 increments). I understand that KevinOConnor has added M206 to SET_GCODE_OFFSET for fine adjustment. When starting a print it is much easier quicker to make that final fine adjustment from the GLCD.
Another minor point, under the OctoPrint heading (using your menu) there are no sub options, not sure why.
Regards - bruce

Another minor point, under the OctoPrint heading (using your menu) there are no sub options, not sure why.
If you examine Octoprint menu items more closely
### menu octoprint ###
[menu octoprint]
type: list
name: OctoPrint
items:
octoprint_pause
octoprint_resume
octoprint_abort
[menu octoprint_pause]
type: command
enable: toolhead.is_printing
name: Pause printing
gcode: ECHO MSG=@pause
[menu octoprint_resume]
type: command
enable: toolhead.is_printing
name: Resume printing
gcode: ECHO MSG=@resume
[menu octoprint_abort]
type: command
enable: toolhead.is_printing
name: Abort printing
gcode: ECHO MSG=@abort
then there's an attribute enable: toolhead.is_printing
it means that menu item is only enabled (visible) when this condition is true.
If you want these items visible all the time then just remove enabled attribute
or put it enable: true
hi would it be possible to add "Babystepping" to the Z axis to fine tune the first layer offset from the bed (maybe in 0.005 increments). I understand that KevinOConnor has added M206 to SET_GCODE_OFFSET for fine adjustment. When starting a print it is much easier quicker to make that final fine adjustment from the GLCD.
SET_GCODE_OFFSET [X=<pos>|X_ADJUST=<adjust>] [Y=<pos>|Y_ADJUST=<adjust>] [Z=<pos>|Z_ADJUST=<adjust>]: Set a positional offset to apply to future G-Code commands. This is commonly used to virtually change the Z bed offset or to set nozzle XY offsets when switching extruders. For example, if "SET_GCODE_OFFSET Z=0.2" is sent, then future G-Code moves will have 0.2mm added to their Z height. If the X_ADJUST style parameters are used, then the adjustment will be added to any existing offset (eg, "SET_GCODE_OFFSET Z=-0.2" followed by "SET_GCODE_OFFSET Z_ADJUST=0.3" would result in a total Z offset of 0.1).
I think it's possible. But I leave it for you to figure it out.
Please look existing items in example-menu.cfg
You should be able to put this together quite easily. Hint, it should be input type, input parameter should be number (0), in gcode you should use Z_ADJUST. So whatever amount you will execute it will be added to existing offset. You cannot read back existing offset in menu item, so each time you start this "babystepping" menu input starts from 0.
@mcmatrix, I appreciate what you are trying to do but I have no clue to programming in Python or anything else. It is easy to look at what other people have done and copy plus make minor changes.
I have used your Test Menu section to attempt to add a BabyStepping section as follows:-
[menu test]
type: input
enable: true
name: "BabySt Z:{0:05.3f}"
parameter: toolhead.zpos
input_min: -0.2
input_max: 0.25
input_step: 0.005
gcode: G1 Z{0:.3f}
I have no idea if this is what you had in mind but it is just about all I can do to copy your example and make minor changes.
Thanks and regards - bruce
I would try something like these
[menu babystep_adj]
type: input
name: "BabySt adj Z:{0:05.3f}"
parameter: 0
input_min: -0.25
input_max: 0.25
input_step: 0.005
gcode: SET_GCODE_OFFSET Z_ADJUST={0:.3f}
[menu babystep_abs]
type: input
name: "BabySt abs Z:{0:05.3f}"
parameter: 0
input_min: -0.25
input_max: 0.25
input_step: 0.005
gcode: SET_GCODE_OFFSET Z={0:.3f}
babystep_abs is for setting absolute offset value and babystep_adj will adjust existing offset by amount.
At the moment there's no way of reading these offset current values in menu input so you have to use 0 as an initial value.
In the terminal, you can check existing offsets when using GET_POSITION gcode and look gcode homing: section.
@mcmatrix , thanks very nicely done and nothing like I imagined.
I have finally uploaded all to my Dual X Carriage printer.
What I find strange is that none of the movement settings through the GLCD take effect until dial button is pressed. Is it not possible for movement to take place while rotating the dial as with other firmware.
The Babystepping does work but with a considerable time delay (I guess it depends on where it was placed in the Que) and also no effect until after button press.
Regards - bruce
What I find strange is that none of the movement settings through the GLCD take effect until dial button is pressed. Is it not possible for movement to take place while rotating the dial as with other firmware.
This is how input item is currently working. Click on edit item will enter into edit mode allowing value change and another click will exit from this mode and formatted gcode will be executed.
Could be that in the future this will be modified to allow realtime change.
@mcmatrix , Just going through and doing some testing of the Menu Move system, X Y & Z seem to be working as expected but "E" is making strange movements on my printer, movements seem to be very fast (that may be by design, can this be changed), nothing above 50mm of movement seems to work for me and the movement distance is not consistent, sometimes moving the set distance other times just a small amount and other times no movement at all. Is the movement on "E" set to G91 Relative Positioning or G90 Absolute Positioning (can this be changed from one to the other).
I am very pleased with this addition to Klipper, without the GLCD Menu option I would not have gone from Marlin to Klipper as I prefer to control my printer this way.
Thanks & regards - bruce
PS it seems that "E" is set to G90 Absolute Positioning but does not show its actual position as for XYZ this is confusing, would it not be better to have "E" set to G91 Relative Positioning?
@bruce356 For the 50mm distance, it's normal. If you didn't change the configuration, Klipper defaults the maximum allowed extruder move to 50mm.
Ses the example.cfg file documentation for more details
@Taz8du29 , thanks I missed that option, so many things to configure.
@mcmatrix , I understand now how extruder move functions (as you have set it up) but as it is, it would be nice to display its actual position from the starting point (starting point being +000.0).
If moved to say +100mm (& once moved the display returns to +000.0) and it may need reversing by say 10mm that then means setting the display to +90mm (& again once moved the display returns to +000.0).
My logical assumption was that if wanting to reverse by 10mm the display would need to be set at -010.0 but this causes the extruder to reverse by 110mm not the 10mm expected.
That is why I feel the display should show actual position (if its possible on the extruder) otherwise one has to remember ones last position selection, other wise unpredictable movement will occur.
The other option would be to set the extruder (if its possible) for that short period of use to G91 Relative Positioning.
Regards -bruce
@bruce356 Thanks for your feedback.
I'll check once more how extruder movements are working.
I love the work you've done, very nice and great effort.
My only feedback, which has most likely come too late now, is a change to the naming convention you've used for the sections in printer.cfg and how the root items are initially set - all in the name of making it more user friendly and easier to navigate.
Due to the current naming convention, if a very descriptive group or list item name is not used, and/or the sections are not entered in a flowing order, it makes it all but impossible to quickly discern what section belongs to what.
On quick inspection, everything basically looks like it belongs to a single menu item called "menu" as each section lists the word "menu" first and then only the group or list item name.
Adding to the problem above, if there are any instances it would make sense to use the same group or list item name (eg. up, down, on, off, etc), you cannot actually do that with the current naming convention as you'd end up with a duplicate section name, so you need to append an index of some sort so there is no conflict (eg. up1, down1, up2, down2, on1, off1, on2, off2, etc).
Current menu structure of a pretty standard menu for a 3D printer:
# Menu manager
[menu]
root: main1
rows: 4
cols: 16
[menu main1]
type: group
name: Main menu
items: info, control, octoprint, babysteps
[menu info]
type: list
name: Information
items: version, status
[menu version]
type: command
...
[menu status]
type: command
...
[menu control]
type: group
name: Printer Control
items: fan, temperature, movement,
[menu fan]
type: list
name: Fan Control
items:
on
off
...
[menu on]
type: command
...
[menu off]
type: command
...
[menu temperature]
type: group
name: Temperature
items: bed, nozzle
[menu bed]
type: list
name: Adjust Bed Temperature
items:
down
up
off2
...
[menu down]
type: command
...
[menu up]
type: command
...
[menu off2]
type: command
...
[menu nozzle]
type: list
name: Adjust Nozzle Temperature
items:
down2
up2
off3
...
[menu down2]
type: command
...
[menu up2]
type: command
...
[menu off3]
type: command
...
[menu movement]
type: group
name: Move Axis
items: X, Y, Z
...
[menu X]
type: list
name: Move X Axis
items:
left
right
[menu left]
type: command
...
[menu right]
type: command
...
[menu Y]
type: list
name: Move Y Axis
items:
back
forward
[menu back]
type: command
...
[menu forward]
type: command
...
[menu Z]
type: list
name: Move Z Axis
items:
down4
up4
[menu down4]
type: command
...
[menu up4]
type: command
...
[menu octoprint]
type: list
name: OctoPrint
items:
pause
resume
abort
[menu pause]
type: command
...
[menu resume]
type: command
...
[menu abort]
type: command
...
[menu babysteps]
type: list
name: BabySteps
items:
adj
abs
[menu adj]
type: input
...
[menu abs]
type: input
...
My suggestion, as can be seen below, is to use a parent/child approach for the naming convention of the sections, which makes it far quicker and easier to identify what parent group/list section each child item section belongs to.
By naming the sections the way I have below, it gets around the problems where list items use the same name (eg. up, down, on, off, etc) as the section name includes the parent group/list name, meaning you don't have to append an index - and that makes it very easy to work through and know exactly what belongs to what.
The same menu structure as above, except this time with the cvhanges I suggest:
# Menu manager
[menu]
rows: 4
cols: 16
type: group
name: Main Menu
items: info, control, octoprint, babysteps
#Root "parent" menu items above are listed on LCD when menu is activated
[menu info]
type: list
name: Information
items: version, status
[menu info version]
type: command
...
[menu info status]
type: command
...
[menu control]
type: group
name: Printer Control
items: fan, temperature, movement,
[menu control fan]
type: list
name: Fan Control
items:
on
off
...
[menu control fan on]
type: command
...
[menu control fan off]
type: command
...
[menu control temperature]
type: group
name: Temperature
items:
bed
nozzle
[menu control temperature bed]
type: list
name: Adjust Bed Temperature
items:
down
up
off
...
[menu control temperature bed down]
type: command
...
[menu control temperature bed up]
type: command
...
[menu control temperature bed off]
type: command
...
[menu control temperature nozzle]
type: list
name: Adjust Nozzle Temperature
items:
down
up
off
...
[menu control temperature nozzle down]
type: command
...
[menu control temperature nozzle up]
type: command
...
[menu control temperature nozzle off]
type: command
...
[menu control movement]
type: group
name: Move Axis
items: X, Y, Z
...
[menu control movement X]
type: list
name: Move X Axis
items:
left
right
[menu control movement X left]
type: command
...
[menu control movement X right]
type: command
...
[menu control movement Y]
type: list
name: Move Y Axis
items:
back
forward
[menu control movement Y back]
type: command
...
[menu control movement Y forward]
type: command
...
[menu control movement Z]
type: list
name: Move Z Axis
items:
down
up
[menu control movement Z down]
type: command
...
[menu control movement Z up]
type: command
...
[menu octoprint]
type: list
name: OctoPrint
items:
pause
resume
abort
[menu octoprint pause]
type: command
...
[menu octoprint resume]
type: command
...
[menu octoprint abort]
type: command
...
[menu babysteps]
type: list
name: BabySteps
items:
adj
abs
[menu babysteps adj]
type: input
...
[menu babysteps abs]
type: input
...
@unnefer1 You have an interesting concept by using namespaces or relative naming.
I added a small change in menu code so that you can use a mixed namings :)
### menu main ###
[menu main]
type: list
name: Main Menu
items:
octoprint
### menu octoprint ###
[menu octoprint]
type: list
name: OctoPrint
items:
.pause
.resume
octoprint_abort
octoprint abort2
[menu octoprint pause]
type: command
enable: toolhead.is_printing
name: Pause printing
gcode: ECHO MSG=@pause
[menu octoprint resume]
type: command
enable: toolhead.is_printing
name: Resume printing
gcode: ECHO MSG=@resume
[menu octoprint_abort]
type: command
enable: toolhead.is_printing
name: Abort printing
gcode: ECHO MSG=@abort
[menu octoprint abort2]
type: command
enable: toolhead.is_printing
name: Abort printing2
gcode: ECHO MSG=@abort
When in attribute items the item name starts with . then the system will add container namespace as a prefix to it otherwise absolute naming is used.
It's still in my local repo. It'll be available when I push PR update.
Stay tuned!
That is really awesome Janar, I didn't expect any change would be made this far along. Top stuff.
I'm working through a few prints at the moment, so won't have the chance to pull the code until the weekend, but once I have a moment, I'll give it a go using attirbute items and spacing in the sections names.
Cheers.
PR https://github.com/KevinOConnor/klipper/pull/500 is updated with the latest work.
This feature is now in the master branch.