Python- run a while loop in background of script - python

So I have this script for controlling an LCD plate where I want the backlight to change every time you press a button, but also want to do other things as well. Currently this doesn't work and it doesn't display the messages I want it to.
This is the change backlight bit of code:
while True:
for b in btn:
if lcd.buttonPressed(b):
lcd.backlight(col[randint(0,5)])
And then I want to go on and run a bit of code that prints a string to the lcd and stuff, in this way:
lcd.message("This is a string")
but the script doesn't ever print the string, it just stays on the backlight change-y bit.
Basically I'm creating an index of letters that you can move through using the LCD buttons, and want the backlight to change each time you press a button.

The standard way is to have a single loop containing both. In the loop you first handles any input or state changes. Then at the end of your loop you update display. This is a fairly common paradigm in game programming see pygame for tons of examples. You would then only break once your program is terminating. One thing worth pointing out is that you would not want to block on checking for key press (or any input), otherwise you would hold up your display waiting for input.
sudo code would be something like:
while True:
for event in key_presses():
handle_event(event) # stuff that happens as a result of input
update_state() # stuff that happens regardless of input
update_display() # everything that changes the display (backlight, text, anything)

Related

Can I put input in Mindstorms 51515 while programming in python?

When I was programming in Mindstorms Robot Inventor, and decided to put an input in my code, I bumped into this NameErrorThis is the Error
Is it Even possible to put an input in Mindstorms??
The Python available isn’t the complete Python standard library. The terminal view in the code editor doesn’t provide for a way to put in input either, so unfortunately no.
What you can do instead is use the buttons on the hub as a type of input. This wouldn’t be free-form text, but if you’re using input() as a user-controlled wait before progressing, you can do that.
_ = hub.right_button.was_pressed() # clear out any button press
while not hub.right_button.was_pressed():
# do something
# do something after the button was pressed
You can string multiple of the above in a row if you want to do multiple actions separated by waiting for you to let it continue, or even take different actions based on which button was pressed.
Finally, you could do a very slow text input using the buttons and the display screen to scroll through the alphabet, confirm the letter, and finish the input.

Python keyboard input while blocking keyboard for the rest of the system

Premise:
I am trying to have python accept keyboard input and have it lock the keyboard to only python input such as that I can hit a key and "transfer" the keyboard from the entire system to only my python script and have it listen to any keys hit so there's no input terminal or any sort of GUI for input
Question:
Is there any way of locking keyboard input to only python for a short time? Is there a better way of doing this?
More Informations:
I want to have the script "draw", on the screen, when a combination of keys is pressed, for example having ctrl be a square, I can use keyboard.wait() to register the hotkey or a combination of them and then just drawSquare() using pyautogui or pywin32 or any other means but this would mean that the size of the square, the movement of the mouse would be hardcoded
This I am trying to avoid, I had in mind waiting for a hotkey with keyboard.wait() then just listening for, say, size of square, or coordinates, whatever, and this does work but the problem is keyboard also "types" in whatever program I am as well as python (using keyboard.record()) so say I wanted ctrl to begin listening for size and then enter 123 123 for width and height 123 123 would also be entered into whatever program I am in (as it would with natural typing since keyboards are meant to do that)

Moving on to another stimulus whenever a key is pressed

I'm setting up an experiment on psychopy in which a stimulus is displayed on the screen for a set period of time (say 0.5s), after which a blank screen is presented with a fixation. I'm using event.waitKeys() in order to get Keyboard input.
I have written the following code.
for i in range (1, 21):
answer = cf.Stimulus() #This is a function for generating the stimulus
img = visual.ImageStim(
win=win,
image="temp.jpg",
units="pix"
)
img.draw() #This is the first screen
fixation.draw()
win.flip()
core.wait(0.5)
fixation.draw() #This is the second screen
win.flip()
keysarray = event.waitKeys()
os.remove('temp.jpg')
The problem which I'm running into here is that, if the keyboard input has been received before the wait time of 0.5 ends in the first screen, events.waitKeys() doesn't register this key entry and still waits on the second screen for the keyboard input. The program only moves forward if a key entry is received for the second screen.
Instead, I want the program to go to the next stimulus whenever a keyboard input is presented between the start of screen 1 to the end of screen 2. That is, if the keyboard input is received in screen 1 itself (before the end of 0.5s), I want the input to be registered and the program to move on to the next stimulus (either by moving to screen 2 for a very short duration of time, or by skipping screen 2 all together). I can't seem to figure out how this can be achieved.
The short answer here is that event.waitKeys() defaults to clearing the event queue, so that only new keypresses are detected. You can get the behaviour you want by overriding that:
keysarray = event.waitKeys(clearEvents=False)
But I think that keys pressed prior to calling the function would not have useful reaction times recorded (although keyboard handling has changed a lot in version 3.1).
Having said that, there are a bunch of other issues with this code that could be improved to fit a more optimal PsychoPy style. I'd suggest posting it at the user forum at https://discourse.psychopy.org. That forum is better suited to back-and-forth discussions than the single question/answer format here at SO.

How to only log valid key presses in simple Psychopy experiment

I'm new to Python and I'm programming a simple psychology experiment. In a nutshell, I'm presenting participants with a series of randomized images and having them to press one key if they detect a face in a given image.
One of my problems is that the program crashes when participant presses the key too fast - that is, I've noticed that the program logs responses even if the participant is pressing a key when there is no image present. Each image will only be present on the screen for 10 seconds. Participant usually takes ~0.5 second on average to make a response.
Is there a key for me to program the experiment so that that Psychopy will only log key presses ONCE, AFTER image is presented on screen? I've pasted my code below.
Thanks so much.
StimList=['Face1.png','Face2.png',]
StimList.extend(['Noise1.png','Noise2.png'])
# randomize lists:
numpy.random.shuffle(StimList)
outstr=""
for TrialNo in range(len(StimList)):
# load our image:
img=visual.ImageStim(
win=win,
image=StimList[TrialNo],
)
# draw the fixation cross and wait for trial start:
win.flip()
time.sleep(1) # wait 1 second on fixation cross
# start a trial: loop until a key has been pressed (or trial times out)
FaceDetected=0 # same as false
Responded=0 #revise
timer=core.Clock()
timer.reset()
while (not Responded) and (timer.getTime()<TimeOut): #remove not responded
img.draw()# outside loop
win.flip() #outside loop
keys=event.getKeys(keyList=['y','Y', 'n','N'], modifiers=False, timeStamped=timer)
if keys:
if (keys[0][0]=='y') | (keys[0][0]=='Y'):
FaceDetected=True
Responded=True
RT=keys[0][1]
elif (keys[0][0]=='n') | (keys[0][0]=='N'):
FaceDetected=False
Responded=True
RT=keys[0][1]
outstr=outstr+str(TrialNo)+", "+ StimList[TrialNo] +", "+str(FaceDetected)+", "+str(RT)+"\n"
print(outstr)
# first open the file:
outfile=open('tmpdata.csv', 'w')
outfile.write(outstr)
outfile.close()
win.close()
There are a bunch of Python issues with the code above, which I suspect are due to negative transfer from another programming language. For example, in Python you should use or in logical comparisons, not |, which in Python is the operator for bitwise 'OR', a different beast. Also, you might want to try out the more Pythonic for TrialNo, stimulus in enumerate(StimList): in place of for TrialNo in range(len(StimList)):, and avoid standard Python functions like time.sleep() when you could have more precise control using PsychoPy's timing classes or screen refresh counting.
But in PsychoPy API-specific terms relevant to your main question, you need to call event.clearEvents() prior to first drawing your stimulus (e.g. when you reset the trial timer). That will clear the keyboard buffer of any previously-pressed keys.
In further PsychoPy-specific hints, avoid creating objects repeatedly. e.g. the timer only needs to be created once, at the start of the script. Then you just reset it once per trial. At the moment, the reset is actually redundant, as the timer is zeroed when it is created. Timers are simple and multiple creation doesn't really impact performance, but stimuli are more complicated and you should definitely avoid creating them over and over again. e.g. here just create your image stimulus once. Then on each trial, just update its image property. That itself takes time to do, as the file needs to be read from disk. So ideally you would be doing that during the fixation stimulus period, or between trials as it is currently.
Your code really shows a few issues rather than just the one you raised in the question. hence, you might find the forum at https://discourse.psychopy.org more useful than the single question and answer format here at SO.

How do I use a button on a Raspberry Pi to toggle states in a while loop?

I'm trying to figure out a way to use a button on a Raspberry Pi to toggle between two different conditions in a while loop. Ideally, by merely pressing the button, I could switch back and forth.
I know this is wrong, but I'm not sure where to go from here.
Roughly, my code looks like this:
from gpiozero import Button
btn=Button(17) #The GPIO pin is 17
def addSurf():
i = i + 1
i = 0
btn.when_pressed = addSurf
while True:
if i % 2 == 0:
#do some stuff
else:
#do some other stuff
Since I started i at 0 before the while loop, I figured that by adding integers when the button was pressed, and checking to see if the modulo was zero or not, I could navigate back and forth between the two states.
However, I don't know how to incorporate the .when_pressed function into the loop so that it's always going to respond to move the program into one state or the other.
Forgive me if I'm a bit of a newbie here, but I tried looking into the documentation for raspberry-gpio-python for information about event detection and multithreading, but I didn't understand it.
It turns out that the problem with the button.when_pressed function is that it can't take any argument, so there's no way to have it act as a variable.
Though it may not be the proper way to do it, I ended up running two different while loops in their own threads and having the button.when_pressed function toggle the sign of an integer in a global variable, as as a kind of switch for the other thread.

Categories

Resources