Raspberry Pi - Python - joystick - python

I am using Raspberry Pi.
while True:
if joystick.get_button(0) == 1:
print ("stop")
else
print ("start")
The purpose of this code is :
I want to interrupt some action while I press a button.
while running the code, it ignores me when I press the button and keep giving me "start". However, if I change the code to :
if joystick.get_button(0) == 0:
the program gives me "stop" at once. (0 is the default value of get_button(0), 1 means I press the button)

The cycle itself seems ok, so I would think that the problem is how your get_button() method acts. Be sure that it is returning the right value and that infinite loop and status checking are not running in the same thread.
Anyway, I would suggest you to use the Observer Pattern.
Basically, it allows you to create a reaction over your joystick button without using infinite loops.
The following code should fit your needs. Joystick class call methods from Player class every time the button is pressed, so every time Joystick change its state.
//OBSERVABLE OBJECT
class Joystick(object):
def __init__(self):
self._button = 0
self._observers = []
def get_button(self):
return self._button
def set_button(self, value):
for callback in self._observers:
callback(self._button)
def bind_to(self, callback):
self._observers.append(callback)
//OBSERVER OBJECT
class Player(object):
def __init__(self, controller):
self._state = 0; //1 - stop, 0 - play
self.controller.bind_to(self.change_state)
def change_state(self, new_state):
self_state = new_state
if(new_state == 0)
print 'play'
else
print 'stop'
This solution will print 'play' and 'stop' once, on every state change.
Then in your code you will create an observable instance:
joystick = new Joystick()
and pass it to an observer:
player = new Player(joystick)
in this way, when you launch your setter function:
joystick.set_button(0)
joystick will automatically change the status in player instance.

Related

setText changes every QTextEdit even if specified to focus on one

I'm trying to put text into a QTextEdit in PyQT5, but every time I set the text for one text field it copies the same value into the other text fields on the same page. Even though I specified that it has to only change the contents of the QTextEdit field of which I have given the ID. Is this normal behavior, or is there a workaround? Any advice would be appreciated.
class NodeUIDScanner(QObject):
rfidTag = pyqtSignal(str)
scanEnabled = bool
def init(self):
self.scanEnabled = False
def run(self):
self.scanEnabled = True
dev = rfid_scanner.init('COM7') #change depending on usb port
while self.scanEnabled:
rfid = rfid_scanner.read(dev)
if rfid is None:
continue
if 'rfid' not in rfid:
continue
rfid = rfid['rfid']
self.scanEnabled = False
self.rfidTag.emit(rfid)
def stop(self):
self.scanEnabled = False
class Main:
def __init__(self):
self.main_win = QMainWindow()
self.ui = RFIDScannerDesign.Ui_MainWindow()
self.ui.setupUi(self.main_win)
#default page on load is the create page
self.ui.stackedWidget.setCurrentWidget(self.ui.pageCreate)
#nav buttons
self.ui.buttonCreate.clicked.connect(self.showCreate)
self.ui.buttonRead.clicked.connect(self.showRead)
self.ui.buttonUpdate.clicked.connect(self.showUpdate)
self.ui.buttonDelete.clicked.connect(self.showDelete)
self.ui.read_editButton.clicked.connect(self.showEdit)
#scan buttons
self.ui.create_buttonScan.clicked.connect(self.scanNodeUidCreate)
self.ui.read_buttonScan.clicked.connect(self.scanNodeUidRead)
self.ui.update_buttonScanOld.clicked.connect(self.scanNodeUidOld)
self.ui.update_buttonScanNew.clicked.connect(self.scanNodeUidNew)
self.ui.delete_buttonScan.clicked.connect(self.scanNodeUidDelete)
#submit button gives alert asking if you're sure you have the right input
self.ui.create_buttonSubmit.clicked.connect(self.alertCreate)
self.ui.edit_buttonSubmit.clicked.connect(self.alertEdit)
self.ui.update_buttonSubmit.clicked.connect(self.alertUpdate)
self.ui.delete_buttonSubmit.clicked.connect(self.alertDelete)
#yes or no buttons with alert. Yes sends info to db. No keeps you on the page
self.ui.create_buttonSubmitYes.clicked.connect(self.submitCreate)
self.ui.create_buttonSubmitNo.clicked.connect(self.hideCreateAlert)
self.ui.edit_buttonSubmitYes.clicked.connect(self.submitEdit)
self.ui.edit_buttonSubmitNo.clicked.connect(self.hideEditAlert)
self.ui.update_buttonSubmitYes.clicked.connect(self.submitUpdate)
self.ui.update_buttonSubmitNo.clicked.connect(self.hideUpdateAlert)
self.ui.delete_buttonSubmitYes.clicked.connect(self.submitDelete)
self.ui.delete_buttonSubmitNo.clicked.connect(self.hideDeleteAlert)
#define QThread here so it can be used
self.main_win.thread = QThread()
self.worker = NodeUIDScanner()
self.worker.moveToThread(self.main_win.thread)
self.main_win.thread.started.connect(self.worker.run)
def show(self):
self.main_win.show()
#Functions for nav buttons to show the right page
def showCreate(self):
self.ui.stackedWidget.setCurrentWidget(self.ui.pageCreate)
self.ui.create_buttonSubmit.show()
self.ui.create_alert.hide()
self.ui.create_buttonSubmitYes.hide()
self.ui.create_buttonSubmitNo.hide()
def showRead(self):
self.ui.stackedWidget.setCurrentWidget(self.ui.pageRead)
self.ui.read_editButton.show()
def showUpdate(self):
self.ui.stackedWidget.setCurrentWidget(self.ui.pageUpdate)
self.ui.update_buttonSubmit.show()
self.ui.update_alert.hide()
self.ui.update_buttonSubmitYes.hide()
self.ui.update_buttonSubmitNo.hide()
def showDelete(self):
self.ui.stackedWidget.setCurrentWidget(self.ui.pageDelete)
self.ui.delete_buttonSubmit.show()
self.ui.delete_alert.hide()
self.ui.delete_buttonSubmitYes.hide()
self.ui.delete_buttonSubmitNo.hide()
def showEdit(self):
self.ui.stackedWidget.setCurrentWidget(self.ui.pageEdit)
self.ui.edit_buttonSubmit.show()
self.ui.edit_alert.hide()
self.ui.edit_buttonSubmitYes.hide()
self.ui.edit_buttonSubmitNo.hide()
#Threads for scanning nodeUIDs asynchronously
def readRFID(self, rfid):
try:
response_rfid = database.query(IndexName='rfid-index',
KeyConditionExpression=Key('rfid').eq(rfid))
if response_rfid['Count'] > 0:
print('RFID already in database', rfid)
print('Node uid:', int(response_rfid['Items'][0]['node_uid']))
return int(response_rfid['Items'][0]['node_uid'])
except Exception as e:
print(e)
def scanNodeUidCreate(self):
if self.ui.create_buttonScan.clicked:
self.worker.stop()
self.worker.rfidTag.connect(self.displayNodeCreate)
self.main_win.thread.start()
def scanNodeUidRead(self):
if self.ui.read_buttonScan.clicked:
self.worker.stop()
self.worker.rfidTag.connect(self.displayNodeRead)
self.main_win.thread.start()
def scanNodeUidOld(self):
if self.ui.update_buttonScanOld.clicked:
self.worker.stop()
self.worker.rfidTag.connect(self.displayNodeOld)
self.main_win.thread.start()
def scanNodeUidNew(self):
if self.ui.update_buttonScanNew.clicked:
self.worker.stop()
self.worker.rfidTag.connect(self.displayNodeNew)
self.main_win.thread.start()
def scanNodeUidDelete(self):
if self.ui.delete_buttonScan.clicked:
self.worker.stop()
self.worker.rfidTag.connect(self.displayNodeDelete)
self.main_win.thread.start()
#Slot for passing signal from worker thread to keep it asynchronous
def displayNodeCreate(self, node):
if self.ui.stackedWidget.currentWidget() == self.ui.pageCreate:
self.ui.create_nodeUid.setText(str(self.readRFID(node)))
self.ui.create_buttonScan.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
def displayNodeRead(self, node):
if self.ui.stackedWidget.currentWidget() == self.ui.pageRead:
self.ui.read_nodeUid.setText(str(self.readRFID(node)))
self.ui.edit_nodeUid.setText(str(self.readRFID(node)))
self.ui.read_buttonScan.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
def displayNodeOld(self, node):
if self.ui.stackedWidget.currentWidget() == self.ui.pageUpdate:
self.ui.update_nodeUidOld.setText(str(self.readRFID(node)))
self.ui.update_buttonScanOld.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
def displayNodeNew(self, node):
if self.ui.stackedWidget.currentWidget() == self.ui.pageUpdate:
self.ui.update_nodeUidNew.setText(str(self.readRFID(node)))
self.ui.update_buttonScanNew.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
def displayNodeDelete(self, node):
if self.ui.stackedWidget.currentWidget() == self.ui.pageDelete:
self.ui.delete_nodeUid.setText(str(self.readRFID(node)))
self.ui.delete_buttonScan.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
#Submit button, when pressed gives alerts
def alertCreate(self):
self.ui.create_buttonSubmit.hide()
self.ui.create_alert.show()
self.ui.create_buttonSubmitYes.show()
self.ui.create_buttonSubmitNo.show()
def alertEdit(self):
self.ui.edit_buttonSubmit.hide()
self.ui.edit_alert.show()
self.ui.edit_buttonSubmitYes.show()
self.ui.edit_buttonSubmitNo.show()
def alertUpdate(self):
self.ui.update_buttonSubmit.hide()
self.ui.update_alert.show()
self.ui.update_buttonSubmitYes.show()
self.ui.update_buttonSubmitNo.show()
def alertDelete(self):
self.ui.delete_buttonSubmit.hide()
self.ui.delete_alert.show()
self.ui.delete_buttonSubmitYes.show()
self.ui.delete_buttonSubmitNo.show()
#TODO add db connection
def submitCreate(self):
self.showCreate()
self.ui.create_alertSucces.show()
self.fade(self.ui.create_alertSucces)
def submitEdit(self):
self.showRead()
self.ui.read_alertSucces.show()
self.fade(self.ui.read_alertSucces)
def submitUpdate(self):
self.showUpdate()
self.ui.update_alertSucces.show()
self.fade(self.ui.update_alertSucces)
def submitDelete(self):
self.showDelete()
self.ui.delete_alertSucces.show()
self.fade(self.ui.delete_alertSucces)
def hideCreateAlert(self):
self.ui.create_buttonSubmit.show()
self.ui.create_alert.hide()
self.ui.create_buttonSubmitYes.hide()
self.ui.create_buttonSubmitNo.hide()
def hideEditAlert(self):
self.ui.edit_buttonSubmit.show()
self.ui.edit_alert.hide()
self.ui.edit_buttonSubmitYes.hide()
self.ui.edit_buttonSubmitNo.hide()
def hideUpdateAlert(self):
self.ui.update_buttonSubmit.show()
self.ui.update_alert.hide()
self.ui.update_buttonSubmitYes.hide()
self.ui.update_buttonSubmitNo.hide()
def hideDeleteAlert(self):
self.ui.delete_buttonSubmit.show()
self.ui.delete_alert.hide()
self.ui.delete_buttonSubmitYes.hide()
self.ui.delete_buttonSubmitNo.hide()
#fade effect for animations on labels and alerts
def fade(self, widget):
self.effect = QGraphicsOpacityEffect()
widget.setGraphicsEffect(self.effect)
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(3000)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_win = Main()
main_win.show()
sys.exit(app.exec_())
The problem is that every time a "buttonScan" is clicked, you connect it to a slot. Signals can be connected to an indefinite number of functions, and it is also possible to connect a signal to the same function more than once.
Stopping the worker won't change anything, as the object still exists, and when the signal will be emitted every (previously) connected function will be called as well.
Since all functions do practically the same thing, a better choice is to connect the signal to a single function, and set the target widgets when switching between pages.
Note that there are other problems in your code, most importantly:
clicked is a signal, using if someObject.someSignal: is pointless as it will always be considered valid, and since the function is already connected to that signal there would be no point in checking it anyway;
calling wait() of an external thread in the main thread is wrong, since it is blocking; I won't address the issue here as it's off topic to the question;
Unfortunately, your code is quite convoluted, so I'm only providing modifications for a single page, then you have to implement the rest on your own.
class Main:
def __init__(self):
# ...
self.ui.create_buttonScan.clicked.connect(self.startScan)
# ...
self.worker.rfidTag.connect(self.rfidReceived)
def showCreate(self):
if self.ui.stackedWidget.currentWidget == self.ui.pageCreate:
return
# ...
self.worker.stop() # just to be sure...
self.targetField = self.ui.create_nodeUid
self.targetCheck = self.ui.create_buttonScan
def startScan(self):
self.worker.stop()
self.main_win.thread.start()
def rfidReceived(self, node):
self.targetField.setText(str(self.readRFID(node))
self.targetCheck.setChecked(False)
self.worker.stop()
self.main_win.thread.quit()
self.main_win.thread.wait()
Note that more than half of your code is boilerplate just like the functions that update the text edits: they always do the same thing, just for different targets. This makes your code unnecessarily long and convoluted, so, prone to errors and annoying editing whenever you need to change its behavior. Since it seems clear that almost all your pages have the same interface (except for the read page) it's pointless to have functions that do the same thing repeated 5 times, especially considering that you're using very similar names that might be easily confused; each function is repeated for its 5 "targets" (the page and its buttons), that makes 30 functions, while you could just have 4 or 5. A better modularization and usage of classes will certainly be a smarter choice, will cut down your code by at least half the size, and will make debugging and maintenance much easier.

Urwid horizontal menu - return to previous state or restart loop

I'm building an app based on the Horizontal Menu example from Urwid.
I have an item that I want to show some information. I have an "OK" button underneath, and I want it to either pop the menu back to the previous state, or maybe restart the entire screen/loop.
In the example, they use ExitMainLoop(), but I don't want to exit - I just want to restart it.
So, I've changed the callback to a different function - but all my attempts either do nothing or crash my program.
Here's the relevant bits:
Starting the menu:
if __name__ == "__main__":
top = HorizontalBoxes()
top.open_box(menu_top([]).menu)
urwid.MainLoop(urwid.Filler(top, 'middle', 40), palette).run()
Relevant menu class/functions. My problem is - what goes in the does_nothing function?
class Choice(urwid.WidgetWrap):
def __init__(self, caption, pid):
super(Choice, self).__init__(
MenuButton(caption, partial(self.item_chosen,pid)))
self.caption = caption
def item_chosen(self, pid, button):
if self.caption == (u"System status"):
showSystemStatus()
def showSystemStatus():
response = urwid.Text( "... some text ")
done = MenuButton(u'OK', does_nothing)
response_box = urwid.Filler(urwid.Pile([response,done]))
top.open_box(urwid.AttrMap(response_box, 'options'))
def does_nothing(key):
????????????????????
return
I found a solution!
I had to add a new method to the HorizontalBoxes class. Specifically, the close_box method:
class HorizontalBoxes(urwid.Columns):
def __init__(self):
super(HorizontalBoxes, self).__init__([], dividechars=1)
def open_box(self, box):
if self.contents:
del self.contents[self.focus_position + 1:]
self.contents.append((urwid.AttrMap(box, 'options', focus_map),
self.options('given', 40)))
self.focus_position = len(self.contents) - 1
def close_box(self):
if self.contents:
del self.contents[self.focus_position :]
self.focus_position = len(self.contents) - 1
And then, it was a simple matter of calling the close_box method from my does_nothing function from before:
def does_nothing(key):
top.close_box()
return

PyUserInput - stopping PyMouseEvent

I am trying to build a program whose first part is saving user clicks for calibration purposes.
I am using PyUserInput for this (on Python 3.4.3) and following their tutorial on GitHub. Currently, this is my code:
from pymouse import PyMouseEvent
positions = []
class Click(PyMouseEvent):
def __init__(self):
PyMouseEvent.__init__(self)
def click(self, x, y, button, press):
if button == 1:
if press:
print('Click! X=%d - Y=%d' % (x, y))
positions.append((x, y))
print(positions)
if len(positions) >= 4:
self.stop()
C = Click()
C.run()
print('Calibrated')
The problem I'm running into is that, even after the PyMouseEvent stops (when position reaches 4 values), I cannot run anything after it (i.e. 'Calibrated' does not print).
How can I continue to run scripts after calling stop() on PyMouseEvent?
I appreciate any help.
This is more of a workaround than a "legal" solution. The idea is to replace stop() method calls with raising exception and wrapping run() method call inside try: except: statements. I recommend making your own exception by subclassing Exception for better understanding of the code.
Here:
from pymouse import PyMouseEvent
positions = []
class ListenInterrupt(Exception):
pass
class Click(PyMouseEvent):
def __init__(self):
PyMouseEvent.__init__(self)
return
def click(self, x, y, button, press):
if button == 1:
if press:
print('Click! X=%d - Y=%d' % (x, y))
positions.append((x, y))
print(positions)
if len(positions) >= 4:
raise ListenInterrupt("Calibrated.")
return
C = Click()
try:
C.run()
except ListenInterrupt as e:
print(e.args[0])
This should stop event listener. If you wish to recalibrate using this approach, simply reruning same instance of listener won't work. The solution is deleting current instance of class Click and instantiating new one each time.
del C
C = Click()

Extract value from a list in another function in Python

I am programming a robot and I want to use an Xbox Controller using pygame. So far this is what I got (original code credits to Daniel J. Gonzalez):
"""
Gamepad Module
Daniel J. Gonzalez
dgonz#mit.edu
Based off code from: http://robots.dacloughb.com/project-1/logitech-game-pad/
"""
import pygame
"""
Returns a vector of the following form:
[LThumbstickX, LThumbstickY, Unknown Coupled Axis???,
RThumbstickX, RThumbstickY,
Button 1/X, Button 2/A, Button 3/B, Button 4/Y,
Left Bumper, Right Bumper, Left Trigger, Right Triller,
Select, Start, Left Thumb Press, Right Thumb Press]
Note:
No D-Pad.
Triggers are switches, not variable.
Your controller may be different
"""
def get():
out = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
it = 0 #iterator
pygame.event.pump()
#Read input from the two joysticks
for i in range(0, j.get_numaxes()):
out[it] = j.get_axis(i)
it+=1
#Read input from buttons
for i in range(0, j.get_numbuttons()):
out[it] = j.get_button(i)
it+=1
first = out[1]
second = out[2]
third = out[3]
fourth = out[4]
return first, second, third, fourth
def test():
while True:
first, second, third, fourth = get()
pygame.init()
j = pygame.joystick.Joystick(0)
j.init()
print 'Initialized Joystick : %s' % j.get_name()
test()
Do you see the list called "out"? Each element in it is a button on the Xbox Controller. I want to extract those elements and put them on variables, one variable to each element/button so I can control my robot.
How could I do it?
I've tried to use global variables but then everything turned down to a mess.
Please note that I am a beginner in Python.
If you want to have out in your program then just return it from your function get:
def get():
# rest of the code ...
return out
Also change your function test:
def test():
while True:
out = get()
LThumbstickX = out[0]
LThumbstickY = out[1]
# and so on
Then run your program as before. What the function test does is constantly (while True) read the keypad. You could for example do:
def test():
while True:
out = get()
LThumbstickX = out[0]
if LThumbstickX != 0:
print 'Left button has been pressed'
# and so on
You can just return the list and use python's unpacking feature:
def get():
out = [1,2,3,4]
return out
first, second, third, fourth = get()

Pyside program locks up in response to a checkbox click

I am having a very strange problem. Whenever the QCheckBox is checked it calls drawall as expected. However when drawall is finished it completely hangs. I have tried directly calling drawall (Version 2) when clicked but with no luck the result is the same.
scene = QGraphicsScene(0, 0, 500, 500)
class SurrogateBeat(QGraphicsItem):
def __init__(self,beat,top):
super(SurrogateBeat, self).__init__()
print "Init"
class Test(QWidget):
def __init__(self):
self.drawAll = QCheckBox("Draw all frames on screen",self)
self.drawAll.stateChanged.connect(self.onDrawAllClicked)
def onDrawAllClicked(self): #Version 1
QTimer.singleShot(0, self.drawall)
def onDrawAllClicked(self): #Version 2 (neither work)
self.drawall()
def drawall(self):
if self.drawAll.checkState() == Qt.CheckState.Checked:
self.surrogates=[]
for b in range(0,len(self.item.beats)):
print "Loop"
surrogate = SurrogateBeat(b, self.item)
scene.addItem(surrogate)
self.surrogates.append(surrogate)
scene.update()
print "Update"
Loop prints out 16 times, the init for SurrogateBeat prints out so it is being called, but after "Update" prints out, the program is hung.
QGraphicsItem is an abstract base class.
As a minimum, your SurrogateBeat subclass will need to reimplement the boundingRect and paint functions.

Categories

Resources