-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Basic menu support (beta) #404
Comments
Interim reportMenu system is already working as Klipper module. |
@KevinOConnor, I'm having a problem with buttons.py module.
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. I havent tested it yet, hopefully tomorrow i can do testings. The idea is simple but not 100% sure that it will work. 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 |
I suspect you may run into race conditions with that code (self.last_pressed isn't thread safe). -Kevin |
Considering with thread safety will make things more complex.
|
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? |
Interim reportbuttons module - test version is ready for my testing Everything is still WIP! |
It's Alive!It's in WIP statuses. I'm having hard time with encoder stability. But still it's hard to get nice and stable encoder readout having that encoder functionality in buttons.py 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? 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. Example config:
Example usage:
One of the pages could be the current type of menu.
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). |
Yes, it's like general marlin or repetier menu. Thank you for sharing interesting menu concept. |
dev-release code is ready for testinghttps://github.com/mcmatrix/klipper/tree/dev-release-20180622 It's still beta firmware so use it ONLY FOR TESTING and not in production! Encoder is still problematic Maybe someone has idea how to improve encoder decoding! 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). |
First of all, this is awesome! This feature was definitely missing in klipper. Thanks for working hard on it.
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:
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: 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. |
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. This should help with my dev-release checkout.
|
Thanks for the heads-up. In the [buttons] section we see 4 pins being declared: but then only 3 are in fact used for the encoder: 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: Thanks in advance. |
In my case ar41 should be kill button but it’s not used right now. You can leave it out. |
Thanks again for the clear explanation. |
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.
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. |
@KevinOConnor I did some experiments with encoder decoding on mcu level. It takes encoder a & b separate from button pins.
It decodes encoder input and makes encoder a&b pins behave like fake buttons. So encoder CW and CCW output is either pin A or pin B pressed. In display you can use these:
I had to reduce |
@mcmatrix please find attached my printer.cfg file |
@bruce356 To use menu you have to enable it in In
This is my test config for display section
|
Added initial draft description of menu element attributes to |
@mcmatrix nice work of yours! I noticed two minor issues regarding the case light control in your example menu:
config atteched: |
Should be fine now. I had to remove realtime menuitems enable/disable update. 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. |
@bruce356 The "^!" syntax is described in the example.cfg configuration file:
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. 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. |
@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. |
@bruce356 Thank you. There are more talented programmers than me :) |
@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. |
If you examine Octoprint menu items more closely
then there's an attribute
I think it's possible. But I leave it for you to figure it out. |
@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:- test menu[menu test] 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
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. |
@mcmatrix , thanks very nicely done and nothing like I imagined. 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. |
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. |
@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 |
@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. |
@bruce356 Thanks for your feedback. |
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:
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:
|
@unnefer1 You have an interesting concept by using namespaces or relative naming.
When in attribute |
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 #500 is updated with the latest work. |
This feature is now in the master branch. |
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:
SELECT will enter into submenu
SELECT will execute GCODE (if specified)
SELECT will go into edit mode
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
Group menu item config
Menu item with action
Menu item with input
Some screenshots from mockup demo
NB! This is still a Work in Progress. Concept, code, and other stuff might change!
The text was updated successfully, but these errors were encountered: