Kivy PyFirmata Problem

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

Hallo zusammen,

ich versuche gerade meine ersten Schritte in Kivy, Python und PyFirmata.
Was geht: mit einem Button in der GUI eine LED am Arduino anzusteuern.

Was nicht geht: mit einem Button am Arduino den zustand eines Buttons in der GUI zu ändern.

Da ich mein eigentliches Projekt bereits mit main.py und main.kv begonnen habe, habe ich zum testen das rpi-kivy-screen-master runtergeladen. Dies besteht aber nur aus der main.py in der mit build die GUI direkt aufgebaut wird. Das meiste konnte ich umschreiben, nur beim abfragen des board.digital[23].read() Zustands und damit das ändern des Zustands von Button 'input' scheitere ich total...

Hier die main.py
[Codebox=python file=main.py]
import kivy
from kivy.app import App
from kivy import platform
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.uix.image import Image
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
from time import sleep
import serial

from pyfirmata import ArduinoMega, util
from pyfirmata.util import Iterator
from pyfirmata import SERVO
from pyfirmata import INPUT
from pyfirmata import OUTPUT

if platform == 'linux':
board = ArduinoMega('/dev/tty.usbserial-A6008rIF') # please check on wich serial port talks the Arduino
if platform == 'win':
board = ArduinoMega('COM5') # please check on wich serial port talks the Arduino

#for now, use a global for blink speed (better implementation TBD):
speed = 1.0

it = Iterator(board)
it.start()

# Set up GPIO:
board.digital[22].mode = OUTPUT
board.digital[23].mode = INPUT
board.digital[23].enable_reporting()

# Make the background violet:
Builder.load_string('''
<RootWidget>
canvas.before:
Color:
rgba: 1, .3, .8, .5
Rectangle:
pos: self.pos
size: self.size
''')

# Modify the Button Class to update according to board.digital input:
class InputButton(Button):
def update(self, dt):
if board.digital[23].read() == 1:
print ("button on")
self.state = 'normal'
else:
print ("button off")
self.state = 'down'

class RootWidget(FloatLayout):
'''This is the class representing your root widget.
By default it is inherited from FloatLayout,
you can use any other layout/widget depending on your usage.
'''

# debugging code to print out all my objects when I hit the switch
level = 1
def print_tree(self,my_obj):
print str(self.level) + " "*self.level + str(my_obj)
for child in (my_obj.children):
self.level += 1
self.print_tree(child)
self.level -= 1

# This callback will be bound to the LED toggle button:
def press(self):
print ("LED on")
board.digital[22].write(1)
def release(self):
print ("LED off")
board.digital[22].write(0)

pass

class MainApp(App):
def build(self):

## Original Code ##

## Instantiate the first UI object (the GPIO input indicator):
#>>> #inputDisplay = InputButton(text="Input")

## Schedule the update of the state of the GPIO input button:
#>>> #Clock.schedule_interval(inputDisplay.update, 1.0/10.0)

## Create the rest of the UI objects (and bind them to callbacks, if necessary):
#outputControl = ToggleButton(text="LED")
#outputControl.bind(on_press=press_callback)
## Add the UI elements to the layout:
#>>> #layout.add_widget(inputDisplay)
#layout.add_widget(outputControl)

print('build running')
return RootWidget()

if __name__ == '__main__':
MainApp().run()
[/Codebox]

Und hier die main.kv
[Codebox=python file=main.kv]
<RootWidget>:
# this is the rule for your root widget, defining it's look and feel.
height: 110.0
width: 190.0
Button: # outputControl
id: output
text: 'LED'
height: 50.0
width: 50.0
size_hint_x: 0.0
size_hint_y: 0.0
x: 30.0 # 0 = left to nn = right
y: 30.0 # 0 = bottom to nn = top
on_press: root.press()
on_release: root.release()
Button: # inputDisplay
id: input
text: 'Input'
height: 50.0
width: 50.0
size_hint_x: 0.0
size_hint_y: 0.0
x: 110.0
y: 30.0
[/Codebox]

Gruß
Thilo
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

Ich denke ich habe eine Lösung gefunden, allerdings weiß ich grad absolut nicht wie ich diese in meinen Code einbinden muß...

Hier der Link: Updating widget content from a items list


Gruß
Thilo
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

Da ich bei den unzähligen Versuchen immer wieder die Meldug "'float' object has no attribute 'ids'" bekomme, habe ich in der class RootWidget(FloatLayout) noch

Code: Alles auswählen

...
class RootWidget(FloatLayout):
...
    
    def __init__(self, *args, **kwargs):
        super(RootWidget, self).__init__(*args, **kwargs)                        
        print 'rootwidget ids:',  self.ids

...
eingebaut um mir die ids im RootWidget auflisten zu lassen.

Ergebnis:

Code: Alles auswählen

rootwidget ids: {'output': <WeakProxy to <kivy.uix.button.Button object at 0x023C19D0>>, 'in_button': <WeakProxy to <kivy.uix.button.Button object at 0x029848B8>>}
Ich versteh momentan echt nicht wo und wie ich

Code: Alles auswählen

self.ids.in_button.state = 'down'
und

Code: Alles auswählen

self.ids.in_button.state = 'normal'
im main.py einbauen muß, damit sich der Status des Buttons mit der ID in_button ändert wenn sich der Wert von board.digital[23].read() ändert???

Die Befehle

Code: Alles auswählen

...
print ("button on")
... und ...
print ("button off")
...
funktionieren...

hier nochmal die beiden Programmcodes, main.py:

Code: Alles auswählen

import kivy
from kivy.app import App
from kivy import platform
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
from time import sleep
import serial

from pyfirmata import ArduinoMega, util
from pyfirmata.util import Iterator
from pyfirmata import SERVO
from pyfirmata import INPUT
from pyfirmata import OUTPUT

if platform == 'linux':
    board = ArduinoMega('/dev/tty.usbserial-A6008rIF') # please check on wich serial port talks the Arduino
if platform == 'win':
    board = ArduinoMega('COM5') # please check on wich serial port talks the Arduino

#for now, use a global for blink speed (better implementation TBD):
speed = 1.0

it = Iterator(board)
it.start()

# Set up GPIO:
board.digital[22].mode = OUTPUT
board.digital[23].mode = INPUT
board.digital[23].enable_reporting()

# Make the background violet:
Builder.load_string('''
<RootWidget>
    canvas.before:
        Color:
            rgba: 1, .3, .8, .5
        Rectangle:
            pos: self.pos
            size: self.size
''')

class RootWidget(FloatLayout):
    '''This is the class representing your root widget.
       By default it is inherited from FloatLayout,
       you can use any other layout/widget depending on your usage.
    '''
    
    # debugging code to print out all my objects when I hit the switch
    level = 1
    def print_tree(self,my_obj):
        print str(self.level) + "  "*self.level + str(my_obj)
        for child in (my_obj.children):
            self.level += 1
            self.print_tree(child)
            self.level -= 1
    
    def __init__(self, *args, **kwargs):
        super(RootWidget, self).__init__(*args, **kwargs)                        
        print 'rootwidget ids:',  self.ids
        # = rootwidget ids: {'output': <WeakProxy to <kivy.uix.button.Button object at 0x023C19D0>>,
        # 'in_button': <WeakProxy to <kivy.uix.button.Button object at 0x029848B8>>}

    # This callback will be bound to the LED toggle button:
    def press(self):
            print ("LED on")
            board.digital[22].write(1)
    def release(self):
            print ("LED off")
            board.digital[22].write(0)
            
    def in_button(self):
        if board.digital[23].read() == 1:
            print ("button on")
            #self.ids.in_button.state = 'down'
        else:
            print ("button off")
            #self.ids.in_button.state = 'normal'
                
    pass

class MainApp(App):
    def build(self):
    	
    	## Original Code ##
    	
        ## Instantiate the first UI object (the GPIO input indicator):
#>>>    #inputDisplay = InputButton(text="Input")
        
        ## Schedule the update of the state of the GPIO input button:
#>>>    #Clock.schedule_interval(inputDisplay.update, 1.0/10.0)
        
        ## Create the rest of the UI objects (and bind them to callbacks, if necessary):
        #outputControl = ToggleButton(text="LED")
        #outputControl.bind(on_press=press_callback)
        ## Add the UI elements to the layout:
#>>>    #layout.add_widget(inputDisplay)
        #layout.add_widget(outputControl)
        
        Clock.schedule_interval(RootWidget.in_button, 1.0/4.0)
        print('build running')
        return RootWidget()

if __name__ == '__main__':
    MainApp().run()
und main.kv:

Code: Alles auswählen

<RootWidget>:
    # this is the rule for your root widget, defining it's look and feel.
    height: 110.0
    width: 190.0
    #in_button: in_button
    Button: # outputControl
        id: output
        text: 'LED'
        height: 50.0
        width: 50.0
        size_hint_x: 0.0
        size_hint_y: 0.0
        x: 30.0    # 0 = left to nn = right
        y: 30.0    # 0 = bottom to nn = top
        on_press: root.press()
        on_release: root.release()
    Button: # inputDisplay
        id: in_button
        text: 'Input'
        height: 50.0
        width: 50.0
        size_hint_x: 0.0
        size_hint_y: 0.0
        x: 110.0
        y: 30.0
Gruß
Thilo
Antworten