I am using a raspberry pi, a pi face and a python script to monitor several home sensors. I want to add the sensing wire from the smoke detectors to that list but I need a bit of help with the if statement.
I'm unsure how to tell the if statement to check how long the input has detected the signal. Under 4 seconds disregard (low battery chirp), over 4 seconds (smoke detected) alert me..
Basically I need help writing the if statement below.
if piface.digital_read(0)==0 >= 4 seconds:
# do x
else:
# do y
Do I need a loop and can it be as easy as what I have above? (Coded correctly of course!)
Something like this (untested pseudo-code):
counter = 0
while True: #your main loop
smoke = digital_read() #assume 0 = no alarm, 1 = alarm
if smoke:
counter += 1
else:
counter = 0
if counter >= 4: #there was smoke for the last 4 seconds
call_the_fire_brigade()
time.sleep(1) #wait one second
I guess you probably need some loop.
Well I think a good solution to this would be spawn a separate thread for each detector and then use a blocking for the number with a loop.. like
count = 0
while count < 4:
if piface.digital_read(0) == 0:
count += 1
else: count = 0
sleep(4000)
# ... rest of code ...
Related
I am learning python, and am trying to make (how original) a disease model, where green balls bounce around and if a red ball touches them, they get infected with the red color.
I am trying to make it so every x seconds, each infected red ball has a probability to die and turn black, but I can't figure out how to do that. I have tried to use pygame's clocks but couldn't figure it out.
here's the die function
def die(particle_list):
for i in particle_list:
if (i.colour == red) and random.choice([1,1,1,1,1,1,1,1,1,1,1,1,1,1,0])==0:
i.colour = black
If the task of checking the red balls for killing them is suppose to happen without bothering the rest of the process, then I'd suggest that you use a separate thread to check it and perform operation.
Check out the threading module in standard library for examples.
Simplest example would be:
import threading, time
def checkballs_and_turn_black(balls_data):
while True:
time.sleep(10) # sleep for 10 secs
for ball in balls_data:
if check_probability(ball):
ball.set_black()
t = threading.Thread(target=checkballs_and_turn_black, args=(actual_balls_data,))
t.start()
Use the time.sleep method. It will block program execution for the given number of seconds.
I would also like to point out that is better to use random numbers for probablilities like this. In you example your particle has a 1 in 15 chance to die, so you would want to generate a random number from 0 to 1, and i the number is bellow 0.066666667 (1 / 15) the particle will die.
This example will do what you want:
import random
def die(particle_list, death_rate):
for particle in particle_list:
if random.random() <= death_rate:
particle.color = black
I have now solved the issue. I didn't yet firgure out how multithreading works, but I will look into tutorials for that as that seems easier than what I came up with. I did this:
d = 0
def day_counter():
global day_count, timelist
time = int(pg.time.get_ticks()/1000)
if time not in timelist:
timelist.append(time)
d = True
if timelist[-1]%(seconds_in_a_day) == 0 and d:
day_count += 1
d = False
e = True
so that the constant e becomes True every in-game day (which ticks every (seconds_in_a_day) seconds) Then, I used the constant e to regulate how often the other time based functions happen, like this:
def die(particle_list):
global sick_count,dead_count,e
for i in particle_list:
if i.colour == red and e:
if r.random() < death_rate:
i.colour = black
sick_count -= 1
dead_count += 1
e = False
Answer added on behalf of OP.
I am newbie in Python. And I am wondering how to exit out of an unbounded loop after n failures. Using counter seems for me unpythonic.
This is my code:
while(True):
#get trigger state
trigState = scope.ask("TRIG:STATE?")
#check if Acq complete
if( trigState.endswith('SAVE') ):
print 'Acquisition complete. Writing into file ...\n'
#save screen
#rewrite in file
#check if trigger is still waiting
elif( trigState.endswith('READY') ):
print 'Please wait ...\n'
#if trigger neither in SAVE nor in READY mode
else:
#THIS IS FAILURE!!!
print 'Failure: k tries remaining'
#wait for several seconds before next iteration
time.sleep(2)
Note that loop must be unbounded - it may iterate arbitrarily many times until number of tries exceeded.
Is there an elegant (or at least pythonic) method to meet the requirements?
To be "pythonic" you'll want to write code that conforms to the Zen of Python and a relevant rules here are:
Explicit is better than implicit.
Readability counts.
You should be explicit about the number of failures you allow, or the number of failures remaining. In the former case:
for number_of_failures in range(MAX_FAILURE):
...
expresses that intent, but is clunky because each time through the loop you are not necessarily failing, so you'd have to be be contorted in counting successes, which would impact readability. You can go with:
number_of_failures = 0
while number_of_failures < MAX_FAILURES:
...
if this_is_a_failure_case:
number_of_failures += 1
...
This is perfectly fine, as it says "if I haven't failed the maximum number of times, keep going. This is a little better than:
number_of_failures = 0
while True:
...
if this_is_a_failure_case:
number_of_failures += 1
...
if number_of_failures == MAX_FAILURES: #you could use >= but this isn't necessary
break
which hides the exit case. There are times when it is perfectly fine to exit the loop in the middle, but in your case, aborting after N failures is so crucial to what you want to do, that the condition should be in the while-loop condition.
You can also rephrase in terms of number of failures remaining:
failures_remaining = MAX_FAILURES
while failures_remaining > 0:
...
if this_is_a_failure_case:
failures_remaining -= 1
...
If you like functional programming, you can get rid of the loop and use tail recursion:
def do_the_thing():
def try_it(failures_remaining = MAX_FAILURES):
...
failed = ....
...
try_it(failures_remaining-1 if failed else failures_remaining)
try_it()
but IMHO that isn't really an improvement. In Python, we like to be direct and meaningful. Counters may sound clunky, but if you phrase things well (after all you are counting failures, right?) you are safely in the realm of Pythonic code.
Using an if statement to number your attempts seems simple enough for your purposes. It's simple, and (to my eyes anyway) easily readable, which suits your Pythonic criterion.
Within your while loop you you can do:
failure_no = 0
max_fails = n #you can substitute an integer for this variable
while:
#...other code
else:
failure_no += 1
if failure_no == max_fails:
break
print 'Failure: '+str(max_fails - failure_no)+' tries remaining'
This will only iterate the number of attempts if a else/failure condition is met, if you wanted to count the total number of run throughs, not just failures, you could put the failure_no +=1 right after your while rather than within the else block.
NB You could easily put a notification inside your escape:
eg
if failure_no == max_fails:
print 'Maximum number of failures reached'
break
E.g. you can use an if statement and raise an error after n tries.
You only need a limit and a counter.
while(True):
#get trigger state
limit = 5
counter = 0
trigState = scope.ask("TRIG:STATE?")
#check if Acq complete
if( trigState.endswith('SAVE') ):
print 'Acquisition complete. Writing into file ...\n'
#save screen
#rewrite in file
#check if trigger is still waiting
elif( trigState.endswith('READY') ):
print 'Please wait ...\n'
#if trigger neither in SAVE nor in READY mode
else:
#THIS IS FAILURE!!!
counter +=1
print 'Failure: ', limit - counter ,' tries remaining'
if k => limit: raise RuntimeError('too many attempts')
#wait for several seconds before next iteration
time.sleep(2)
...
I'm trying to create a simulation where there are two printers and I find the average wait time for each. I'm using a class for the printer and task in my program. Basically, I'm adding the wait time to each of each simulation to a list and calculating the average time. My issue is that I'm getting a division by 0 error so nothing is being appended. When I try it with 1 printer (Which is the same thing essentially) I have no issues. Here is the code I have for the second printer. I'm using a queue for this.
if printers == 2:
for currentSecond in range(numSeconds):
if newPrintTask():
task = Task(currentSecond,minSize,maxSize)
printQueue.enqueue(task)
if (not labPrinter1.busy()) and (not labPrinter2.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter1.startNext(nexttask)
elif (not labPrinter1.busy()) and (labPrinter2.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter1.startNext(nexttask)
elif (not labPrinter2.busy()) and (labPrinter1.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter2.startNext(nexttask)
labPrinter1.tick()
labPrinter2.tick()
averageWait = sum(waitingtimes)/len(waitingtimes)
outfile.write("Average Wait %6.2f secs %3d tasks remaining." \
%(averageWait,printQueue.size()))
Any assistance would be great!
Edit: I should mention that this happens no matter the values. I could have a page range of 99-100 and a PPM of 1 yet I still get divided by 0.
I think your problem stems from an empty waitingtimes on the first iteration or so. If there is no print job in the queue, and there has never been a waiting time inserted, you are going to reach the bottom of the loop with waitingtimes==[] (empty), and then do:
sum(waitingtimes) / len(waitingtimes)
Which will be
sum([]) / len([])
Which is
0 / 0
The easiest way to deal with this would just be to check for it, or catch it:
if not waitingtimes:
averageWait = 0
else:
averageWait = sum(waitingtimes)/len(waitingtimes)
Or:
try:
averageWait = sum(waitingtimes)/len(waitingtimes)
except ZeroDivisionError:
averageWait = 0
I'm building a game in python, and I want to create an event listener that checks for when the main character's hp is smaller or equal to 0, and then executes a game over function. In other languages (vb.net) i have achieved this by creating a new thread that continuously loops an if statement until the condition is met, then runs the game over code, then closes itself. How do you create/start/close threads in python? Also, is there a better way of doing this that is sitting right in front of me?
from threading import Thread
def my_function():
while True:
if player.lives < 5:
do_stuff()
Thread(my_function).start()
However most of the times the games are developed following a frame-loop rule, with the following structure:
def my_game():
should_continue = False
while should_continue:
should_continue = update_logic()
update_graphics()
What you define in update_logic and update_graphics is up to you and the graphic library you're using (since you're using text, your function would just print text in your console), but some examples of the logic would be like this:
def update_logic():
if player.lives < 5:
return False
# these are just examples, perhaps not valid in your game
player.xdirection = 0
player.ydirection = 0
player.speed = 0
player.hitting = False
if player.damage_received_timer > 0:
player.damage_received_timer -= 1
if right_key_pressed:
player.xdirection = 1
if left_key_pressed:
player.xdirection = -1
if up_key_pressed:
player.ydirection = -1
if down_key_pressed:
player.ydirection = +1
if player.ydirection or player.xdirection:
player.speed = 20
if space_key_pressed:
player.hitting = True
# bla bla bla more logic
return True
This does not make use of threads and using threads is most of the times a bad practice if multiple events occur. However in your text games, perhaps not so much elements are involved, so it's unlikely a race condition would occur. Be careful, however. I always prefer these loops instead of threads.
I have created a simple score system for my pygame. but it's pausing the game. I know it's because of time.sleep but I don't how to sort it out.
The score system is to +100 every 5 seconds while start is true, code:
while start == True:
time.sleep(5)
score = score + 100
Full code with indentation: http://pastebin.com/QLd3YTdJ
code at line : 156-158
Thank you
Instead of using sleep, which stalls the game until time has elapsed, you want to count up an internal timer with the number of seconds which have passed. When you hit 5 seconds, increment the score and then reset the timer.
Something like this:
scoreIncrementTimer = 0
lastFrameTicks = pygame.time.get_ticks()
while start == True:
thisFrameTicks = pygame.time.get_ticks()
ticksSinceLastFrame = thisFrameTicks - lastFrameTicks
lastFrameTicks = thisFrameTicks
scoreIncrementTimer = scoreIncrementTimer + ticksSinceLastFrame
if scoreIncrementTimer > 5000:
score = score + 100
scoreIncrementTimer = 0
This could easily be improved (what if your frame rate is so low there's more than 5 seconds between frames?) but is the general idea. This is commonly called a "delta time" game timer implementation.
If i understand you correctly you dont want the while True: score += 100 loop to block your entire program?
You should solve it by moving the score adding to a seperate function
and use the intervalfunction of APScheduler http://packages.python.org/APScheduler/intervalschedule.html
from apscheduler.scheduler import Scheduler
# Start the scheduler
sched = Scheduler()
sched.start()
# Schedule job_function to be called every 5 seconds
#sched.interval_schedule(seconds=5)
def incr_score():
score += 100
This will result in APScheduler creating a thread for you running the function every 5 seconds.
you might need to do some changes to the function to make it work but it should get you started at least :).