Timer in Pygame - python

I'm completely new to Python and I'm trying to set a timer in this game I have... Everything else has been fine but this timer is a headache.
I'll only post the parts associated with the timer to make it easier.
frame_count = 0
second = 0
minute = 5
hour = 1
time = "1 5. 0"
And then in my main loop I have.
font = pygame.font.SysFont('DS-Digital', 50, False, False)
text = font.render(time,True,red)
display.blit(text, [302, 50])
frame_count += 1
if frame_count == 60:
frame_count = 0
second -= 1
elif second == 0:
second = 9
minute -= 1
elif minute == 0:
minute = 9
hour -= 1
elif second == 0 and minute == 0 and hour == 0:
second = 0
minute = 0
hour = 0
hour = time[0]
minute = time[2]
second = time[5]
clock.tick(60)
This gives me back an error for being wrong type but I've tried converting to int and vice versa... So frustrating...
I've looked at so many examples but most examples are actual minutes and seconds.
I need my right number to just countdown from 9 to 0 then minus off middle number and so forth.

If this your whole code then you didn't imported pygame. (import pygame) at the begining and you should loop it all so for example:
import pygame
while True:
...
Your code
...
Specify more your question please, I see that you should use if insted of elif because once it got to 1 1 0 it will turn to 1 0 9 and then into 0 9 9 in two frames.
elif second == 0 and minute == 0 and hour == 0:
second = 0
minute = 0
hour = 0
This doesn't make sence really it's like if you calculate
if I have a = 0 then do a = 0 if you know what I mean (it does nothing).
Edit:
There is working code, you can edit it and replace your old code with it.
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 500))
red = (255, 0, 0)
bg_color = (0, 0, 0)
frame_count = 0
time = "1 5. 0"
while True:
pygame.time.Clock().tick(60)
frame_count += 1
hour = int(time[0])
minute = int(time[2])
second = int(time[5])
if second > 0 and frame_count == 20:
frame_count = 0
second -= 1
if second == 0 and minute > 0 and frame_count == 20:
frame_count = 0
second = 9
minute -= 1
if minute == 0 and hour > 0 and frame_count == 20:
frame_count = 0
minute = 9
second = 9
hour -= 1
time = str(hour) + " " + str(minute) + ". " + str(second)
font = pygame.font.SysFont('DS-Digital', 50, False, False)
text = font.render(time, True, red)
screen.fill(bg_color)
screen.blit(text, (302, 50))
pygame.display.update()
I'm quite sure that there is easier solution or more pythonic one, but it works and that is most important.

Remove these lines:
hour = time[0]
minute = time[2]
second = time[5]
it should work without them. Then ask what you are attempting to do with them

When you assign elements from time to you hour, minute, second variables convert them to an int like this:
hour = int(time[0])
minute = int(time[2]
second = int(time[5])

Here is my solution for simple way to sleep at the end of each iteration for the leftover time for a desired update rate
from timeit import default_timer as timer
from time import sleep as sleep
class loop_timer():
""" simple game loop timer that sleeps for leftover time (if any) at end of each iteration"""
LOG_INTERVAL_SEC=10
def __init__(self, rate_hz:float):
''' :param rate_hz: the target loop rate'''
self.rate_hz=rate_hz
self.start_loop()
self.loop_counter=0
self.last_log_time=0
def start_loop(self):
""" can be called to initialize the timer"""
self.last_iteration_start_time=timer()
def sleep_leftover_time(self):
""" call at start or end of each iteration """
now=timer()
max_sleep=1./self.rate_hz
leftover_time=max_sleep-(now-self.last_iteration_start_time)
if leftover_time>0:
sleep(leftover_time)
self.start_loop()
self.loop_counter+=1
if now-self.last_log_time>self.LOG_INTERVAL_SEC:
self.last_log_time=now
if leftover_time>0:
print('loop_timer slept for {:.1f}ms leftover time for desired loop interval {:.1f}ms'.format(leftover_time*1000,max_sleep*1000))
else:
print('loop_timer cannot achieve desired rate {}Hz, time ran over by {}ms compared with allowed time {}ms'.format(self.rate_hz, -leftover_time*1000, max_sleep*1000))
Use it like this
looper=loop_timer(MODEL_UPDATE_RATE_HZ)
while not self.exit:
# do your stuff here
try:
looper.sleep_leftover_time()
except KeyboardInterrupt:
logger.info('KeyboardInterrupt, stopping')
self.exit=True
continue

Related

Resetting the count of variable in a while loop

from microbit import *
from ssd1306 import initialize, clear_oled
from ssd1306_stamp import draw_stamp
from ssd1306_img import create_stamp
from ssd1306_text import add_text
import utime as time
window = []
threshold = 550 # limit
count = 0
sample = 0
beat = False
start = False
good = create_stamp(Image.HAPPY)
bad = create_stamp(Image.SAD)
heart = create_stamp(Image.HEART)
values = []
def mean(datalist):
sum = 0
for i in datalist:
sum += i
if len(datalist) > 0:
return sum/len(datalist)
else:
return None
while True:
if button_a.was_pressed():
while True:
signal = pin1.read_analog()
window.append(signal)
avg = round(mean(window))
values.append(avg)
if len(window) == 11:
window.pop(0)
if beat is False and avg >= threshold+10:
beat = True
count += 1
display.show(Image.HEART, wait=False)
if count == 1:
t1 = time.ticks_ms()
if count == 11:
t2 = time.ticks_ms()
T = t2 - t1
bpm = round(600*1000/(T))
display.scroll(str(bpm))
initialize()
clear_oled()
add_text(0, 0, "Heart rate :")
add_text(0, 3, str(bpm) + " bpm")
if 60 <= bpm <= 100:
draw_stamp(38, 24, good, 1)
else :
draw_stamp(38, 24, bad, 1)
count = 0
sleep(2000)
if button_b.was_pressed():
break
count = 0
elif beat is True and avg <= threshold-10:
beat = False
display.clear()
sample += 1
if sample == 250:
threshold = mean(values)
values = []
sample = 0
sleep(20)
sleep(20)
This is the code connect to the microbit, and the function is about the heart rate sensor, which it will appear the average beat per minute when sensing 10 beats of the heart.
I am thinking of adding a function that if button b is pressed, the loop will pause, and press the button a to start again. I tried to add a break function in the loop, it worked when I click the button b, it pause the loop, however, the count of beat won't reset, and the time between the beat is also recorded although I break the loop.
Is there any way that I can break the loop and reset the count?
You should reset the counter before breaking. In your current code the line for the count is not executing since it breaks out before it reaches it.
if button_b.was_pressed():
count = 0
break

Ultrasonic sensor as counter

I am trying to code ultrasonic sensors to count the number of cars in a parking lot. I am relatively new to Python, so I am asking here for help.
I have three parking slots, in which each of them has an ultrasonic sensor.
How do I make it so that the sensors and their counters work together? For example, when the parking slots are empty, the counter shows three parking slots available. When two parking slots are filled, the counter shows one availability, etc.
I have done the following code, and I am wondering how I could continue to achieve my objective?
# Sensor 1
def distance_1():
time.sleep(0.5)
GPIO.output(TRIG_1, True)
time.sleep(0.00001)
GPIO.output(TRIG_1, False)
print("Reading Sensor 1")
while GPIO.input(ECHO_1) == 0:
start = time.time()
while GPIO.input(ECHO_1) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
# Sensor 2
def distance_2():
time.sleep(0.5)
GPIO.output(TRIG_2, True)
time.sleep(0.00001)
GPIO.output(TRIG_2, False)
print("Reading Sensor 2")
while GPIO.input(ECHO_2) == 0:
start = time.time()
while GPIO.input(ECHO_2) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
# Sensor 3
def distance_3():
time.sleep(0.5)
GPIO.output(TRIG_3, True)
time.sleep(0.00001)
GPIO.output(TRIG_3, False)
print("Reading Sensor 3")
while GPIO.input(ECHO_3) == 0:
start = time.time()
while GPIO.input(ECHO_3) == 1:
end = time.time()
duration = end - start
sound = 34000 / 2
distance = duration * sound
round(distance, 0)
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
while True:
distance_1()
distance_2()
distance_3()
GPIO.cleanup()
The trouble with programming is there are so many ways to achieve the same result.
Looking at your code, I would suggest taking a step back and refactoring it to use Python classes instead. You have a lot of code repetition happening, and eventually, the code will break if you need to keep adding more sensors.
For example:
class Parking:
"This is a parking class"
def __init__(self, space):
self.space = space
def empty(self):
if self.space == 0:
print('Parking space is empty')
def full(self):
if self.space == 1:
print('Parking space is full')
def distance(self):
time.sleep(0.5)
GPIO.output(TRIG, True)
. . .
# Input:
sensor1 = Parking(1)
sensor2 = Parking(1)
sensor3 = Parking(0)
# Output:
sensor1.empty()
sensor2.empty()
sensor3.empty()
# Output:
sensor1.full()
sensor2.full()
sensor3.full()
You can then update a dictionary with the output to monitor the latest sensor information. Ideally, the dictionary would be written to a central file accessible by all the sensors or raspberry pis to read.
available_spaces = {"sensor1": 0, "sensor2": 1, "sensor3": 0}
I analyzed your code and I did some refactorings.
I suggest you to use constant values initialization (the config section you see in the code below). The values I used are random.
A function can be parametrized, so you can pass arguments to functions, and avoid writing the same piece of code changing only a few values in the same place.
You should set up your microcontroller when the script starts, to tell the board how you are using the pins (as input or output).
I didn't dig into on the snippet above the lcd_display_string and why are you doing those operations. I suppose that these are required to print on screen the distance.
## configuration
# trigger
TRIG_1 = 17
TRIG_2 = 27
TRIG_3 = 22
# echo
ECHO_1 = 10
ECHO_2 = 9
ECHO_3 = 11
# timings
INITIAL_DELAY = 0.5
TRIGGERING_DELAY = 0.00001
## support functions
# initializing GPIO
def set_up():
# set trigger GPIOs as output pins
GPIO.setup(TRIG_1, GPIO.OUT)
GPIO.setup(TRIG_2, GPIO.OUT)
GPIO.setup(TRIG_3, GPIO.OUT)
# set echo GPIOs as input pins
GPIO.setup(ECHO_1, GPIO.IN)
GPIO.setup(ECHO_2, GPIO.IN)
GPIO.setup(ECHO_3, GPIO.IN)
# I didn't dig into these values and why are you doing these operations. I suppose that these are required to print on screen the distance.
def print_distance_on_lcd(distance):
total = 3
count = total
if distance <= 10:
count -= 1
elif distance > 10:
count += 1
if count < 0:
count = 0
elif count > total:
count = total
print(count)
mylcd.lcd_display_string("{}".format(count), 2)
def trigger(trigger):
time.sleep(INITIAL_DELAY)
GPIO.output(trigger, True) # set output pin on HIGH state
time.sleep(TRIGGERING_DELAY)
GPIO.output(trigger, False) # set output pin on LOW state
def distance(t, echo):
trigger(t)
# initializing the variables here, allows you to use it outside the while block below
# using variable names that explains their content
start_time = time.time()
end_time = time.time()
# this block is not wrong, but unnecessary: initializing the variable like above is enough
'''
while GPIO.input(echo) == 0:
start_time = time.time()
'''
while GPIO.input(echo) == 1:
end_time = time.time()
duration = end_time - start_time
sound = 34000 / 2
distance = duration * sound
return distance
# call initialization function (this will be executed only one time)
set_up()
# loop forever
while True:
set_up()
print("Reading Sensor 1")
distance_sensor_1 = distance(TRIG_1, ECHO_1)
print_distance_on_lcd(distance_sensor_1)
print("Reading Sensor 2")
distance_sensor_2 = distance(TRIG_2, ECHO_2)
print_distance_on_lcd(distance_sensor_2)
print("Reading Sensor 3")
distance_sensor_3 = distance(TRIG_3, ECHO_3)
print_distance_on_lcd(distance_sensor_3)
GPIO.cleanup()

trying to get an if statement to be triggered during certain times of day

im fairly new with python but im tring to get a device to turn on for one minute and off for 3 minutes repeatedly from the times of 9am to 5pm and i can't get the if statement to reference the updated time from the loop any help would be greatly appreciated!!!
import datetime
import time
n = "on" #to be replaced with GPIO output
f = "off" #to be replaced with GPIO output
nt = "tis not be the time" #used to see if working or not
tt = "tis be time" #used to see if working or not
now = datetime.datetime.now()
hour = now.hour
def count():
now = datetime.datetime.now()
hour = now.second
total = 1
if hour >= 8 and hour <= 16:
now = datetime.datetime.now()
hour = now.hour
for i in range(1,100):
total = total*2
print (tt)
print (n)
time.sleep(60)
print(f)
time.sleep(180)
now = datetime.datetime.now()
hour = now.second
print (hour)
else :
for i in range(1,100):
now = datetime.datetime.now()
hour = now.hour
print (nt)
print (hour)
time.sleep(10)
count()
You could fix it with a while loop instead, it would look like this, just put all of it inside your function
now = datetime.datetime.now()
hour = now.hour
if hour >= 8 and hour <= 16:
run = True
else:
run = False
while run:
total = total*2
print (tt)
print (n)
time.sleep(60)
print(f)
time.sleep(180)
now = datetime.datetime.now()
hour = now.second
print (hour)
if hour >= 8 and hour <= 16:
run = True
else:
run = False
while run == False:
now = datetime.datetime.now()
hour = now.hour
print (nt)
print (hour)
time.sleep(10)
if hour >= 8 and hour <= 16:
run = True
else:
run = False
Maybe using a while statement. In addition, you have hour = now.second on the second line of the function count and I think it should be hour = now.hour.
See the code with comments:
import datetime
import time
n = "on" #to be replaced with GPIO output
f = "off" #to be replaced with GPIO output
nt = "tis not be the time" #used to see if working or not
tt = "tis be time" #used to see if working or not
#Next lines are redundant, commented out.
#now = datetime.datetime.now()
#hour = now.hour
def count():
now = datetime.datetime.now()
hour = now.hour #now.second
total = 1
while hour >= 8 and hour <= 16:
now = datetime.datetime.now()
hour = now.hour
# for i in range(1,100): -> why you need this?
total = total*2
print (tt)
print (n)
time.sleep(60)
print(f)
time.sleep(180)
now = datetime.datetime.now()
hour = now.hour #now.second
print (hour)
for i in range(1,100): #I don't know why you need a loop here
now = datetime.datetime.now()
hour = now.hour
print (nt)
print (hour)
time.sleep(10)
count()
Edited for correcting another hour = now.second inside the while loop
I don't know how are you planning on running the code, but the main problem I see is that you do not have any loop for your code to run infinitely and check the time condition.
Also it's not clear for me why you need this total variable that gets doubled.
Another thing is your for loops - the condition is not clear. Why do you want to run it in this specific range?
What I would do is I would create an infinite loop and inside it make some decisions based on a clear time conditions - the conditions that are specified by you.
So if I understood your case correctly I'd rather write something like this:
# between 9am to 5pm turn on the device for 60 seconds and off for 180 seconds repeatedly
from datetime import datetime
import time
def update_device_state(state):
# TODO: implement GPIO output code
pass
def run():
device_state = 'off'
new_state = device_state
on_timer = 0
off_timer = time.time() - 180 # initial value must be over 180 seconds to trigger device on a first run
while True:
hour = datetime.now().hour
if 5 <= hour <= 17:
if device_state == 'off' and time.time() - off_timer > 180:
on_timer = time.time()
new_state = 'on'
off_timer = 0
elif device_state == 'on' and time.time() - on_timer > 60:
off_timer = time.time()
new_state = 'off'
on_timer = 0
else:
if device_state = 'on'
new_state = 'off'
on_timer = 0
off_timer = time.time()
if device_state != new_state:
update_device_state(new_state)
device_state = new_state
time.sleep(1)
run()
But the code requires some testing as I just quickly drafted it and I just briefly red it.

More efficient solution to clocks offset

I am writing a program where the user inputs two values: the number of minutes fast per hour that two clocks are. The output should be the time displayed on the clocks when the two clocks are showing the same time. The clocks are only checked once an hour (according to an accurate clock).
At the moment, I have:
clock1 = 0
clock2 = 0
inp = input(">").split(" ")
offset1 = int(inp[0])+60
offset2 = int(inp[1])+60
def add():
global clock1
global clock2
clock1 += offset1
if clock1 > 1399:
clock1 -= 1440
clock2 += offset2
if clock2 > 1399:
clock2 -= 1440
add()
while clock1 != clock2:
add()
hours = 0
while clock1 > 59:
hours += 1
clock1 -= 60
while hours > 23:
hours -= 24
hours = str(hours)
minutes = str(clock1)
if len(hours) == 1:
hours = "0" + hours
if len(minutes) == 1:
minutes = "0" + minutes
print(hours + ":" + minutes)
This works, but when the input values get big, it takes too long. How can I make this solution more efficient?

Can't make walking animations in pygame

I was trying to code a game in pygame, but then when I tried to make a walking animation it only displayed one of the sprites.
def go_left(time):
ness_current = 1
global ness
global is_walking_left
ness_list = [ness_walking,ness_standing]
current_time = pygame.time.get_ticks()
go_left.walking_steps = 1
now = 0
cooldown = 1000
flag = 0
ness = ness_list[ness_current]
print current_time - game_loop.animation_timer
if (current_time - game_loop.animation_timer) > 200:
print 'Changing'
if ness_current == 0:
print 'Changing to sprite 1'
now = pygame.time.get_ticks()
ness_current = 1
current_time = now
elif ness_current == 1:
print 'Changing to sprite 0'
if (current_time - game_loop.animation_timer) > 200:
ness_current = 0
current_time = now
else:
'Changing to sprite 0 because of sprite reset'
ness_current = 0
current_time = now
def stop_it():
global ness
ness = pygame.image.load('nessthekid.png').convert()
ness.set_colorkey(WHITE)
car_list = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
player_list = pygame.sprite.Group()
When I try to use this it only displays one of the sprites not the other for the character. I want it to swich every 1 or 2 seconds to make it look like its walking. Help is appreciated.
First, I highly suggest using a class, to avoid using global variables.
Second, as you set the current time back to now (0), you will make it so current_time - game_loop.animation_timer will always be negative. This will keep the statement from running.
For now, I suggest completely removing the "if (current_time - game_loop.animation_timer) > 200:" from your code.
Here is an example to get you started (obviously you will have to alter it to make it work for you)
class Ness:
def __init__(self):
self.all_images = [ness_walking,ness_standing]
self.current = 0
self.image = self.all_images[self.current]
def walk_left(self):
# Every 200 clicks
if pygame.time.get_ticks() % 200 == 0:
if self.current == 0:
self.current = 1
else:
self.current = 0
self.image = self.all_images[self.current]
As suggested by #Red Twoon put the stuff separated in class is a very good practice. Another thing that you should do is no rely in get_ticks directly but instead use some kind of time independent movement/animation.
You can achieve this using delta times in your game loop.
Game loop.
while(True):
delta = #Get the delta time.
handle_events();
update(delta);
draw(delta);
#Animation stuff.
time_to_animate_frame = 200;
time_since_last_update = 0;
...
time_since_last_update += delta;
if(time_since_last_update > time_to_animate_frame):
time_since_last_update - time_to_animate_frame;
#Do the animation.....

Categories

Resources