Resetting the count of variable in a while loop - python

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

Related

how to select a value referring to the last repeated item in a list

I have 5 columns ( NO = index of vehicle / LEADER = index of the vehicle of the front / SEC = instant in seconds / X = position of the vehicle)
Some vehicles stop ( X stay the same for a while) and I want to get the exact time it starts to move again. Then, calculate the difference between their instant and their respective 'leader' vehicle.
I made a code but it has so many bugs
OBS: Some vehicles never stop or stop,but never return to move. I want to remove them too.
Here's my code:
dados = pd.read_excel('teste-reaction_001.xlsx')
n=dados["NO"].unique()
final=np.zeros(1)
for i in n:
botao = 0
array_aux=dados[dados["NO"] == i ]["X"]
df = pd.DataFrame(array_aux)
aux=df.diff().to_numpy()
count1 = 0
aux1 = []
for j in aux:
if j == 0:
botao = 1
elif j != 0 and botao == 1:
aux1=np.where(aux==j)[0]
aux1=aux1[np.where(aux1>=count1)[0]]
break
else :
botao = 0
count1 = count1 + 1
aux2=dados["SEC"][dados[dados["NO"]==i]["SEC"].index[aux1]].values[0]
final=np.append(final,aux2)
tr=np.zeros(1)
for i in n:
aux=dados[dados["NO"] == i ]["LEADER"].unique()[0]
aux1=np.where(dados["NO"].unique()==i)[0]
aux2=np.where(dados["NO"].unique()==aux)[0]
if aux2>-1:
aux3=final[int(aux1)]-final[aux2]
else:
aux3 = "s"
tr=np.append(tr,aux3)
columns = ["N", "TR"]
tabela = np.array([dados["NO"].unique(), tr[1:]])
res = pd.DataFrame(data=tabela.T,index=np.arange(len(tabela.T)), columns=columns)

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.

Python printing before/after different lines

I have created some code long ago which helps to create a table in BBcode used in forums.
counter = 0
counter2 = 0
while True:
UserInput = input("")
if counter2 == 0:
print ("[tr]")
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
counter2 += 1
if counter % 5 == 0:
print ("[/tr]")
So if i input Image1.jpg ~ Image7.jpg on seperate lines, the output is as shown below
> [tr]
> [td][center]Label[img]Image1.jpg[/img][/center][/td]
> [td][center]Label[img]Image2.jpg[/img][/center][/td]
> [td][center]Label[img]Image3.jpg[/img][/center][/td]
> [td][center]Label[img]Image4.jpg[/img][/center][/td]
> [td][center]Label[img]Image5.jpg[/img][/center][/td]
> [/tr]
> [td][center]Label[img]Image6.jpg[/img][/center][/td]
> [td][center]Label[img]Image7.jpg[/img][/center][/td]
Currently, the code only inserts [/tr] at the end of ever 5 images.How does one make it so that [/tr] is also printed at the end of output no matter how many jpgs are entered?
How can I print [tr] at the start and join it with the line below, and then not print again until a [/tr] has been printed?
Apologies for my crap English & explanation skills.
(Current progress)
counter = 0
while True:
UserInput = input("")
if counter == 0 or counter % 5 == 0:
print("[tr]", end = "")
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
if counter % 5 == 0:
print("[/tr]")
After reading what you wrote 5 times I believe what you want is:
print("[tr]")
while True:
counter = 0
UserInput = input("")
if UserInput == "exit":
exit(0)
print("[tr]", end = "")
while (counter !=5):
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
print ("[/tr]")
print("[/tr]")
So what happens here is you print [tr] in the same line as the first print from the inside while as you wanted. the [/tr] is in a new line but you can put it in the same by adding end = "" to the second print as well.
Separate the functions. Get the list of images, then process it:
def bbcode(images):
for i in range(0,len(images),5):
print('[tr]')
for image in images[i:i+5]:
print(f'[td][center]Label[img]{image}[/img][/center][/td]')
print('[/tr]')
def get_images():
images = []
while True:
image = input('Image? ')
if not image: break
images.append(image)
return images
images = get_images()
bbcode(images)
You can do it as one long script, but it isn't as clear:
count = 0
while True:
image = input('Image? ')
if not image:
break
count = (count + 1) % 5
if count == 1:
print('[tr]')
print(f'[td][center]Label[img]{image}[/img][/center][/td]')
if count == 0:
print('[/tr]')
if count != 0:
print('[/tr]')
Below is the result with some commentary. To update for your specifications, just set the max_item_blocks variable to whatever you want.
### your main body element with {} to pass a number
element = '[td][center]Label[img]Image{}.jpg[/img][/center][/td]'
### The number of "blocks" you want to print.
max_item_blocks = 3
### Define a start value of 1
start = 1
### Our simple loop with join() function
while max_item_blocks > 0:
### End value is start + 5
end = start + 5
print('[tr]\n' + '\n'.join([element.format(i) for i in range(start, end)]) + '\n[\\tr]')
### Start takes ending value
start = end
### Ending value is now start + 5
end = start + 5
### Reduce our block counts by 1
max_item_blocks -= 1
Output for 3 blocks:
[tr]
[td][center]Label[img]Image1.jpg[/img][/center][/td]
[td][center]Label[img]Image2.jpg[/img][/center][/td]
[td][center]Label[img]Image3.jpg[/img][/center][/td]
[td][center]Label[img]Image4.jpg[/img][/center][/td]
[td][center]Label[img]Image5.jpg[/img][/center][/td]
[\tr]
[tr]
[td][center]Label[img]Image6.jpg[/img][/center][/td]
[td][center]Label[img]Image7.jpg[/img][/center][/td]
[td][center]Label[img]Image8.jpg[/img][/center][/td]
[td][center]Label[img]Image9.jpg[/img][/center][/td]
[td][center]Label[img]Image10.jpg[/img][/center][/td]
[\tr]
[tr]
[td][center]Label[img]Image11.jpg[/img][/center][/td]
[td][center]Label[img]Image12.jpg[/img][/center][/td]
[td][center]Label[img]Image13.jpg[/img][/center][/td]
[td][center]Label[img]Image14.jpg[/img][/center][/td]
[td][center]Label[img]Image15.jpg[/img][/center][/td]
[\tr]

Timer in Pygame

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

Categories

Resources