Pygame PiTFT touch events - main loop sits waiting until touches are detected - raspberry-pi

I am using a raspberry pi and PiTFT to measure sensors and display the results.
Using the tips from https://stackoverflow.com/a/54986161 all is working fine but one problem:
the main loop sits waiting until the lcd is touched.
I removed all non trivial parts from the program just to test the main loop.
This piece of code is printing the state after touch and release.
As long as the lcd is being touched the main loop keeps printing, releasing the lcd stops the loop. How can I rewrite the loop so it's keeps running even when there is no keypress?
#!/usr/bin/python3
import subprocess, pygame, evdev, select
pygame.init()
surfaceSize = (320, 240)
##
# Everything that follows is for handling the touchscreen touch events via evdev
##
# Used to map touch event from the screen hardware to the pygame surface pixels.
# (Those values have been found empirically, but I'm working on a simple interactive calibration tool
tftOrig = (3750, 180)
tftEnd = (150, 3750)
tftDelta = (tftEnd [0] - tftOrig [0], tftEnd [1] - tftOrig [1])
tftAbsDelta = (abs(tftEnd [0] - tftOrig [0]), abs(tftEnd [1] - tftOrig [1]))
# We use evdev to read events from our touchscreen
# (The device must exist and be properly installed for this to work)
touch = evdev.InputDevice('/dev/input/touchscreen')
# We make sure the events from the touchscreen will be handled only by this program
# (so the mouse pointer won't move on X when we touch the TFT screen)
touch.grab()
# Prints some info on how evdev sees our input device
print(touch)
# Even more info for curious people
#print(touch.capabilities())
# Here we convert the evdev "hardware" touch coordinates into pygame surface pixel coordinates
def getPixelsFromCoordinates(coords):
# TODO check divide by 0!
if tftDelta [0] < 0:
x = float(tftAbsDelta [0] - coords [0] + tftEnd [0]) / float(tftAbsDelta [0]) * float(surfaceSize [0])
else:
x = float(coords [0] - tftOrig [0]) / float(tftAbsDelta [0]) * float(surfaceSize [0])
if tftDelta [1] < 0:
y = float(tftAbsDelta [1] - coords [1] + tftEnd [1]) / float(tftAbsDelta [1]) * float(surfaceSize [1])
else:
y = float(coords [1] - tftOrig [1]) / float(tftAbsDelta [1]) * float(surfaceSize [1])
return (int(x), int(y))
# Was useful to see what pieces I would need from the evdev events
def printEvent(event):
print(evdev.categorize(event))
print("Value: {0}".format(event.value))
print("Type: {0}".format(event.type))
print("Code: {0}".format(event.code))
while True:
r,w,x = select.select([touch], [], [])
for event in touch.read():
if event.type == evdev.ecodes.EV_ABS:
if event.code == 1:
X = event.value
elif event.code == 0:
Y = event.value
elif event.type == evdev.ecodes.EV_KEY:
if event.code == 330 and event.value == 1:
printEvent(event)
p = getPixelsFromCoordinates((X, Y))
if 12 <= p[0] <= 72 and 210 <= p[1] <= 230:
num = 0
if 92 <= p[0] <= 154 and 210 <= p[1] <= 230:
num = 1
if 173 <= p[0] <= 234 and 210 <= p[1] <= 230:
num = 2
if 255 <= p[0] <= 317 and 210 <= p[1] <= 230:
num = 3
if 290 <= p[0] <= 320 and 0 <= p[1] <= 30:
pygame.quit()
quit()
print(num)
pygame.quit()
quit()

Solved!
With the comments from #sloth and #Kingsley I rewrote the code to:
r,w,x = select.select([touch], [], [], 0)
if ( touch in r ):
for event in touch.read():
if event.type == evdev.ecodes.EV_ABS:
if event.code == 1:
X = event.value
elif event.code == 0:
Y = event.value
elif event.type == evdev.ecodes.EV_KEY:
if event.code == 330 and event.value == 1:
printEvent(event)
Now the loop runs even if there is no input, and input is working ok also.

Related

dht11 sensor only retuning unexpected number of pulse often

I am trying to make a simple water pump controller using a dth11 to make the pump turn on more frequently when the temperature is higher. i have it working but every 4th or 5th time i call measure on the dht11 sensor i get an error saying "InvalidPulseCount: Expected 82 but got 0 pulses" or "InvalidPulseCount: Got more than 82 pulses". I have added try block that is stopping the program from crashing but would really like to figure out why it is happening. I also had to edit the dht.py lib to have 82 instead of 84 as the default expected pulses because that was what was commonly returned.
here is my main.py file
from machine import Pin
from time import sleep_ms
import dht
import I2C_LCD_driver
sensor = dht.DHT11(Pin(28))
lcd = I2C_LCD_driver.lcd()
pump = Pin(7, machine.Pin.OUT)
counter = 0
pumpTime = 30
normalTime = 60
hotTime = 30
lowTemp = 19
# sensor variables only updated every 3 loops
lastMesure = 1
temp = 0
humid = 0
first = True
while True:
# sensor.messure can only be called ever 3 seconds
# start at 1 and set to zero in the first loop for our first messurement
lastMesure += -1
if lastMesure <= 0:
try:
sensor.measure()
lastMesure = 3
temp = round((sensor.temperature), 0)
humid = sensor.humidity
except:
print("something went wrong")
print("Counter: {:.0f} pumpping:{:0.f}".format(counter, pump.value()))
print("Temp: {:.0f}℃ HUMIDITY: {:.0F}% ".format(temp, humid))
# if the pump is running
if pump.value() == 1:
if counter >= pumpTime: # if it has been the set pump run time
pump.value(0) # turn off pump
counter = 0 # reset counter
else:
counter += 1
else:
# check current temp
# if warmer then {lowTemp} check for {hotTime} else check for {normalTime}
if (temp > lowTemp and counter >= hotTime) or counter >= normalTime:
pump.value(1) # turn on pump
counter = 0 # reset counter
else:
counter += 1
# print current data to the screen
lcd.lcd_clear()
lcd.lcd_display_string("T: {:.0f}C H:{:.0f}%".format(temp, humid), 1)
if pump.value() == 1:
status = f'Pumping {pumpTime - counter}s'
lcd.lcd_display_string(status, 2);
else:
lcd.lcd_display_string("Pump off ", 2)
sleep_ms(1000)
here is a picture of my breadboard set up. I have run it both with and without a 1k pull up resistor on the data pin

Program not running with error unsupported operand type(s) for +: 'function' and 'int'

Im creating a program for NIM for my Python Intro class, and am having a problem with trying to get the program to finish.
I am at a loss...
def main():
import random
#User random to generate integer between 10 and 100 for random pile size of marbles.
ballCount = random.randint(10, 100)
print("The size of the pile is: ",ballCount)
#Generate a random integer between 0 and 1, this will tell if the human or computer takes first turn.
def playerTurn(ballCount):
playerTurn = random.randint(0, 1)
if playerTurn == 0:
print("Its the computers turn...")
else:
print("Its your turn...")
#Generate a random integer between 0 and 1, to determine if the computer is smart or dumb.
computerMode = random.randint(0, 1)
def computerDumbMode(ballCount):
computerMode = random.randint(0, 1)
if computerMode == 0:
print("This computer is very dumb, no need to stress")
def computerSmartMode(ballCount):
computerMode = random.randint(0, 1)
if computerMode == 1:
print("This computer is very intelligent, beware")
#In dumb mode the computer generates random values (between 1 and n/2),
#you will use a random integer n for ballCount, when it is the computers turn.
while ballCount != 1: #This will compile untill you are left with only one marble.
if playerTurn == 0: #This will initiate computers turn.
if computerMode == 1: #This will initiate Smart Mode.
temp = random.randint(1, ballCount/2) #Pick a random number between 1, and n/2.
else: # Pick your own number of Marbles for your ballCount (n).
if ballCount - 3 > 0 and ballCount - 3 < ballCount/2:
temp = ballCount - 3
elif ballCount - 7 > 0 and ballCount - 7 < ballCount/2:
temp = ballCount - 7
elif ballCount - 15 > 0 and ballCount - 15 < ballCount/2:
temp = ballCount - 15
elif ballCount - 31 > 0 and ballCount - 31 < ballCount / 2:
temp = ballCount - 31
else:
temp = ballCount - 63
print("The computer has chosen: %d marbles." % temp) #Print the number of marbles the computer has chosen.
ballCount -= temp #Then subtract the number of marbles chosen by the computer.
else:
ballCountToPick = int(input("It is now your turn, Please pick the number of marbles in the range 1 - %d: " % int(ballCount/2))) #Reads the number of marbles to be picked by user.
while ballCountToPick < 1 or ballCountToPick > ballCount/2: #If computer reads this invalidly, it will try repeatedly.
ballCountToPick = int(input("The number you chose, is incorrect. Try again, and pick marbles in the range 1 - %d: " % int(ballCount/2)))
ballCount -= ballCountToPick #Subtract the marbles that were chosen by user.
playerTurn = (playerTurn + 1) % 2 #Changes the turn of player.
print("Now the pile is of size %d." % ballCount)
if playerTurn == 0: #Show the outcome.
print("You came, you saw, and you won... CONGRATULATIONS!!!")
else:
print("Once again... You lost and the computer wins!!!")
main()
Trying to get the program/game to run and print end result if the computer or person wins!
Your "playerTurn" variable is a function in the following line:
playerTurn = (playerTurn + 1) % 2 #Changes the turn of player.
Have a separate "playerTurn" function and "player_turn" variable will resolve your problem.

How I read mouse data In a non blocking way

I'm implementing a fail safe handover procedure in ROS and I'm using python scripts to do so.
I'm using the optical sensor from a mouse to keep under control the acceleration of the object so I can detect when is falling. Everything seems to works fine but now I want to give give a limit to the monitoring procedure (let's say 1000 times) before declaring the handover succeded. The problem is that the function read that I use for the mouse get stucked, if no movement are detected the next iteration is not performed. How can I read from the device without encountering this issue?
Here is the code I'm using to read from the mouse:
def getMouseEvent():
buf = file.read(3)
x, y = struct.unpack( "bb", buf[1:] ) # <--- X and Y deltas.
return [x , y]
Here the loop I want to implement
release_grasp()
rospy.loginfo( "Force detected -- Release mode active")
# If the object is falling regrasp it.
detected= False
trials = 0
while (not(detected) and trials < 1000):
trials = trials + 1
rospy.loginfo ("Acc monitored for the" + str(trials) + "th time"
if fall_test():
cilindrical_grasp()
rospy.loginfo("Fall detected -- Object regrasped")
detected = True
rate.sleep()
The output I get blocks to a given iteration until the mouse does not detect some kind of movement.
UPDATE: Here is the full code
#!/usr/bin/env python2
import rospy
import numpy
import struct
from reflex_sf_msgs.msg import SFPose
from matteo.msg import force
from matteo.msg import acc
# Defining force treshold in each direction ( to be completed and tuned )
rospy.init_node('DetectionFail')
xt = 0.5
yt = xt
zt = 0.3
# For the future try to handle the initialization.
fx = None
fy = None
fz = None
ax = None
ay = None
rate = rospy.Rate(100) # <--- Rate Hz
#-----------------------------MOUSE-----------------------------------#
# Open the mouse device. To be sure if it is "mouse2" type in the terminal: cat /proc/bus/input/devices, look for the device whose name is "Logitech optical USB mouse" and get the name of the handler. If you need root permissions type: sudo chmod 777 /dev/input/(handler)
file = open ("/dev/input/mouse3" , "rb")
#Defining the function to read mouse deltas.
def getMouseEvent():
buf = file.read(3);
x,y = struct.unpack( "bb", buf[1:] ); # <--- X and Y deltas.
return [x , y]
#Defining the function to estimate the acceleraton.
def acc_comp():
vx_old = 0
vy_old = 0
vx_new = getMouseEvent()[0]
vy_new = getMouseEvent()[1]
x_acc = (vx_old - vx_new)*100
y_acc = (vy_old - vy_new)*100
vx_old = vx_new
vy_old = vy_new
return [x_acc , y_acc]
#---------------------------------------------------------------------#
#Defining function fall test
def fall_test():
if ( acc_comp()[1] >= 3000 or acc_comp()[1] <= -3000 ):
return True
else:
return False
#---------------------------------------------------------------------#
# Initialize hand publisher.
hand_pub = rospy.Publisher('/reflex_sf/command', SFPose, queue_size=1)
rospy.sleep(0.5)
#---------------------------------------------------------------------#
# Defining sferical grasp.
def cilindrical_grasp():
hand_pub.publish ( 2.5 , 2.5 , 2.5, 0)
#---------------------------------------------------------------------#
# Define release position.
def release_grasp():
hand_pub.publish ( 2, 2 , 2 , 0)
#---------------------------------------------------------------------#
# Define test for the force measure
def force_treshold ( fx, fy , fz):
if ( fx > xt and fy > yt or fz > zt):
return True
else:
return False
#---------------------------------------------------------------------#
# Callback function to save the datas obtained by the force sensor
def callback_force(msg):
global fx
global fy
global fz
fx = msg.fx
fy = msg.fy
fz = msg.fz
# Main loop.
def main():
#Apply the sferical grasp.
rospy.loginfo("Applying grasp")
cilindrical_grasp()
while not(rospy.is_shutdown()):
rospy.Subscriber("/Forces", force, callback_force )
if force_treshold ( fx , fy , fz ):
release_grasp()
rospy.loginfo( "Force detected -- Release mode active")
# If the object is falling regrasp it.
detected= False
trials = 0
while (not(detected) and trials < 1000):
trials = trials +1
if fall_test():
cilindrical_grasp()
rospy.loginfo("Fall detected -- Object regrasped")
detected = True
rate.sleep()
if rospy.is_shutdown() :
break
Yesterday I came out with this code:
#!/usr/bin/env python
import struct
import rospy
from matteo.msg import acc
import struct
import os
import time
i = 0
# Mouse read with a non blocking structure, the problem is that does not provide the same output as
# mouse_clean.py, probably there is a problem with the unpacking or the reading.
while i < 1000:
i += 1
try:
file = os.open("/dev/input/mouse0", os.O_RDONLY | os.O_NONBLOCK)
time.sleep(0.1)
buf = os.read(file , 3)
x,y = struct.unpack( "bb", buf[1:] ) # <--- X and Y deltas.
print ( "X:" +str ( x ) + "---" +"Y:" +str ( y ) )
except OSError as err:
if err.errno == 11:
print ( "No motion detected")
continue
os.close(file)
It works fine, if there is no motion the message is printed out but, in case of motion the output I get is quite different from the "vanilla" mode.

Improve speed on joining multiple images

What I'm trying to do is take numerous(up to 48) 1024x768 images that are color coded images(weather maps, the precip overlay) and add up the precip to fall over the course of time. When I run into non-precip I want to take a box 5x5 around the pixel in question and average the value and use that value as the value of the pixel in question.
I can do this but it takes a long time to accomplish it. I have heard numpy could improve the speed but I still haven't been able to wrap my mind around how it going to improve the speed given the sequence of events that have to take place. It seems like I would still have to do it pixel by pixel. I've included an idea of the code I'm using to accomplish this SLOWLY.
I have this actually as two separate program, one to download the images and the other does the image processing(working up toward merging the two programs in the near future, just trying to get all the bugs worked out before the merger.) Hence some of the download coding may look a little strange. I figure I could probably write the file straight to a variable but I haven't been doing it that way so I stuck with a bit longer approach.
Is there anyway of increasing the speed? I don't see anyway of avoiding pixel by pixel due to the color coding scheme in place(look at the color bar in the lower left it shows the full color scheme...I only included part of it for demo purposes in the coding below.) Some of the coding may be a bit rough since I chopped from the two programs and put the important parts in here...it shows what I'm currently doing and gives the full idea of how I'm going about doing it.
Also, if you happen to see this three to four or more days after it was posted you would need to change the date in the download link to the current date. The files are only kept on the server for 3-4 days before they are removed.
from PIL import Image
import time
import urllib
import os
pathstr = '/'
url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/20140216/00/gfs_namer_006_1000_500_thick.gif'
urllib.urlretrieve(url,str(pathstr + '20140216006.gif'))
url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/20140216/00/gfs_namer_012_1000_500_thick.gif'
urllib.urlretrieve(url,str(pathstr + '20140216012.gif'))
url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/20140216/00/gfs_namer_018_1000_500_thick.gif'
urllib.urlretrieve(url,str(pathstr + '20140216018.gif'))
url = 'http://mag.ncep.noaa.gov/GemPakTier/MagGemPakImages/gfs/20140216/00/gfs_namer_024_1000_500_thick.gif'
urllib.urlretrieve(url,str(pathstr + '20140216024.gif'))
class Convert():
def __init__(self):
self.colorscale2 = [(255,255,255),(127,255,0),(0,205,0),(145,44,238),(16,78,139),
(30,144,255),(0,178,238),(0,238,238),(137,104,205),(0,139,0),
(139,0,139),(139,0,0),(205,0,0),(238,64,0),(255,127,0),(205,133,0),
(255,215,0),(238,238,0),(255,255,0),(139,71,38),(255,0,0),(0,0,255),(0,0,0)]
self.x = 0
self.y = 0
self.grid = 0
self.moist = 0
self.scan = 0
self.turn = 0
self.precip = {}
start = time.time()
for i in range(6, 30, 6):
if i < 10:
filename = '/2014021600' + str(i) + '.gif'
else:
filename = '/201402160' + str(i) + '.gif'
self.im1 = Image.open(filename).convert('RGB')
self.image = self.im1.getdata()
self.size = width, height = self.im1.size
self.coordinates = self.x,self.y = width, height
self.getprecip()
self.turn = 1
print (time.time()-start)
def getprecip(self):
for self.x in range(81, 950):
for self.y in range(29, 749):
if self.turn == 0:
self.moist = 0
else:
self.moist = self.precip[self.x,self.y]
self.coordinates = self.x,self.y
self.scan = 0
self.imagescan()
if self.turn == 0:
self.precip[self.x,self.y] = self.moist
else:
self.precip[self.x,self.y] += self.moist
def imagescan(self):
if self.image[(self.y * 1024) + self.x] == self.colorscale2[0]:
self.moist =0
self.grid -=1
elif self.image[(self.y * 1024) + self.x] == self.colorscale2[1]:
self.moist =.01
elif self.image[(self.y * 1024) + self.x] == self.colorscale2[2]:
self.moist =.1
elif self.image[(self.y * 1024) + self.x] == self.colorscale2[3]:
self.moist =.25
elif self.image[(self.y * 1024) + self.x] == self.colorscale2[4]:
self.moist =.5
#on and on through self.colorscale2[18]
if self.scan == 1:
self.grid += 1
if self.scan == 0:
x = self.x
y = self.y
self.deliso540()
self.x = x
self.y = y
def deliso540(self):
self.grid = 1
self.scan = 1
for p in range(self.x-2,self.x+2):
for q in range(self.y-2,self.y+2):
self.x = p
self.y = q
self.imagescan()
self.moist = self.moist / self.grid

Extract numbers from specific image

I am involved in a project that I think you can help me. I have multiple images that you can see here Images to recognize. The goal here is to extract the numbers between the dashed lines. What is the best approach to do that? The idea that I have from the beginning is to find the coordinates of the dash lines and do the crop function, then is just run OCR software. But is not easy to find those coordinates, can you help me? Or if you have a better approach tell me.
Best regards,
Pedro Pimenta
You may start by looking at more obvious (bigger) objects in your images. The dashed lines are way too small in some images. Searching for the "euros milhoes" logo and the barcode will be easier and it will help you have an idea of the scale and rotation involved.
To find these objects without using match template you can binarize your image (watch out for the background texture) and use the Hu moments on the contours/blobs.
Don't expect a good OCR accuracy on images where the numbers are smaller than 8-10 pixels.
You can use python-tesseract https://code.google.com/p/python-tesseract/ ,it works with your image.What you need to do is to split the result string.I use your https://www.dropbox.com/sh/kcybs1i04w3ao97/u33YGH_Kv6#f:euro9.jpg to test.And source code is below.UPDATE
# -*- coding: utf-8 -*-
from PIL import Image
from PIL import ImageEnhance
import tesseract
im = Image.open('test.jpg')
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(4)
im = im.convert('1')
w, h = im.size
im = im.resize((w * (416 / h), 416))
pix = im.load()
LINE_CR = 0.01
WHITE_HEIGHT_CR = int(h * (20 / 416.0))
status = 0
white_line = []
for i in xrange(h):
line = []
for j in xrange(w):
line.append(pix[(j, i)])
p = line.count(0) / float(w)
if not p > LINE_CR:
white_line.append(i)
wp = None
for i in range(10, len(white_line) - WHITE_HEIGHT_CR):
k = white_line[i]
if white_line[i + WHITE_HEIGHT_CR] == k + WHITE_HEIGHT_CR:
wp = k
break
result = []
flag = 0
while 1:
if wp < 0:
result.append(wp)
break
line = []
for i in xrange(w):
line.append(pix[(i, wp)])
p = line.count(0) / float(w)
if flag == 0 and p > LINE_CR:
l = []
for xx in xrange(20):
l.append(pix[(xx, wp)])
if l.count(0) > 5:
break
l = []
for xx in xrange(416-1, 416-100-1, -1):
l.append(pix[(xx, wp)])
if l.count(0) > 17:
break
result.append(wp)
wp -= 1
flag = 1
continue
if flag == 1 and p < LINE_CR:
result.append(wp)
wp -= 1
flag = 0
continue
wp -= 1
result.reverse()
for i in range(1, len(result)):
if result[i] - result[i - 1] < 15:
result[i - 1] = -1
result = filter(lambda x: x >= 0, result)
im = im.crop((0, result[0], w, result[-1]))
im.save('test_converted.jpg')
api = tesseract.TessBaseAPI()
api.Init(".","eng",tesseract.OEM_DEFAULT)
api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyz")
api.SetPageSegMode(tesseract.PSM_AUTO)
mImgFile = "test_converted.jpg"
mBuffer=open(mImgFile,"rb").read()
result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api)
print "result(ProcessPagesBuffer)=",result
Depends python 2.7 python-tesseract-win32 python-opencv numpy PIL,and be sure to follow python-tesseract's remember to .