Time.sleep() command is slower that real time, in python? - python

So, I am working on a project with the RPi, and (with python code), I want it to check something every 0.00001 seconds and note the amount of time taken until the condition is met.
I am using time.sleep(), by importing time
If I set that value to 0.001 or more, only then it works, if it's below 0.001 then time becomes either slower or faster,
eg. it takes like 3 seconds to check 1 second...
What can I do? Can you suggest any other way, except for time.sleep?
The following code just says
if GPIO 16 on the pi is high,
then, until GPIO 32 is not high, it will time the time
And the loop breaks and code ends when GPIO 32 is high
The first while loop is so the program keeps looping, which I needed it to do, you can ignore
import RPi.GPIO as hello
import time
hello.setwarnings(False)
hello.setmode(hello.BOARD)
hello.setup(16, hello.IN)
hello.setup(32, hello.IN)
t=0
while 1:
##Main Code, with the problem...
while 1:
t=0
if hello.input(16)==1:
print(t)
while hello.input(32)==0:
t=t+0.00001
time.sleep(0.00001)#Not Working
if hello.input(32)==1:
print(t)
print("Speed=",14/t,"cm/s")
break

There are limitations to all time critical functions.
I suggest overthinking the use of sleep() and using Timer Objects as stated in the Python Documentary instead.
https://docs.python.org/2.4/lib/timer-objects.html

There are at least two things here to note:
The argument to time.sleep() and the underlying system call is a lower bound. There is no guarantee that the system will not sleep for longer. (In fact we can predict that it will, if typically only by a small amount if system load is light.)
The execution of any Python code in a nanosecond timeframe is unrealistic on contemporary hardware.
>>> import timeit
>>> timeit.timeit('pass', number=10000)
8.20159912109e-05

Related

Duration calculation and control in ROS - furthermore why does this script keep running even after pressing Ctrl-C?

I have written some code to make the turtlebot turn around. The code is working. What I want to know is how fast the turtlebot is running and how I can control it. Forexample, how can I ensure that the turtlebot turns 5 degrees in one minute?
Last part of the question. After pressing Ctrl-C, the turtlebot stops but the script keeps running. Why? and how can I stop that?
this post does not really help.
went through this post .Does that mean that the while loop below runs 5 times a second regardless of the values I put in the for loops? Or does it mean ROS tries its best to make sure that the loop runs 5 times a second to the best of my machine's ability?
Thank you very much.
# 5 HZ
angle = 5
r = rospy.Rate(5);
while not rospy.is_shutdown():
# code to turn
for x in range(0,100):
rospy.loginfo("turn")
turn_cmd.angular.z = radians(angle)
new_angle = (angle + new_angle) % 360
self.cmd_vel.publish(turn_cmd)
r.sleep()
# code to pause
for x in range(0,100):
rospy.loginfo("stop")
turn_cmd.angular.z = radians(0)
self.cmd_vel.publish(turn_cmd)
r.sleep()
def shutdown(self):
# stop turtlebot
rospy.loginfo("Stop turning")
self.cmd_vel.publish(Twist())
rospy.sleep(1)
According to ROS Wiki, the rospy.Rate convenience class makes a best effort to maintain the loop running at the specified frequency by considering the execution time of the loop since the last successful r.sleep(). This means in your case: as long as the code execution time within the loop does not exceed 1/5 seconds, rospy.Rate will make sure the loop runs at 5Hz.
Regarding the script not stopping when pressing Ctrl-C:
KeyboardInterrupt will be handled differently than in normal Python scripts when using rospy.
rospy catches the KeyboardInterrupt signal to set the rospy.is_shutdown() flag to true. This flag is only checked at the end of each loop, therefore if pressing Ctrl-C during the for-loop executions, the script cannot be stopped because the flag is not checked immediately.
A manual way to signal a shutdown of the node is to use rospy.signal_shutdown(). For this, the disable_signals option needs to be set to true when initializing the ROS node (see Section 2.3 here). Note that you will additionally have to manually invoke the correct shutdown routines to ensure a proper cleanup.

Question with python, music and events, is there a more elegant way of programming this?

Goal: To create a program that will be able to turn off and on lights to music based on events that are triggered from midi notes.
Hello all, I am hoping that this isn't too broad of a question to ask. I am working on a project where I get events from a midi file and turn those events into time. I take a note from the midi file and append it to a list as the time it was placed
Example:
https://imgur.com/swZsrk9
I take all of those and place them into a list. Don't worry about how I do that as that is not my main goal to discuss. I've just substituted the list with a hard-coded one on my example code.
I now have a list of times that I want lights to either turn on or off, now I just need to set an infinite loop with a timer that starts at 0 seconds (with the start of the song) and when the timer == (the next time in the list) it will print out a line. Here is my code:
import socket
import sys
import random
import time
from pygame import mixer
from mido import MidiFile
masterList = [12.37, 14.37, 15.12, 15.62,16.36, 17.61, 18.11, 19.11, 19.61, 20.35,]
mixer.init()
song = mixer.Sound('song.wav')
startTime = time.time()
endTime = startTime + song.get_length()
print(masterList)
print('Starting song.')
song.play()
print('Playing song, timer:',startTime)
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) == masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
#print('playing...')
time.sleep(.01)
mixer.quit()
Here is a video of it runing:
https://www.youtube.com/watch?v=VW-eNoJH2Wo&feature=youtu.be
Ignore the deprecation warnings
It works but sometimes, due to the nature of programming, the time.clock() does not always == the next item in the list. I knew that this would be a problem going in as you can't rely on how long the code takes to execute. Sometimes it takes a few more milliseconds than usual to complete a while loop so then when you call the time.clock() method it != the next time in the list. Then the list does not remove it's first item and then it will never equal that first item.
I tried going by 10 milliseconds (.1) but it doesn't give me the accuracy I need.
Also, it seems clunky, sometimes the events are delayed a few milliseconds and it makes the effect not as pleasing. As you can see from my video the times of the prints aren't lined up completely where they need to be, even though they are perfectly placed on where they need to be in the midi file.
Question: Is there a more elegant way of tackling this? I seem to keep finding ways of patching it to work better and then it always goes back to the nature of programming, where the cpu always is unreliable. I've been trying to think of different ways of doing this but I can't come up with any. Your help would be much appreciated!!
Since you're deleting the notes as you play them, have you tried using >= instead of ==?
E.g.,:
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) >= masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
That way the note will play as soon as possible after the specified time, and remove it from the queue. Only way to know actual performance is to test it, but at the very least it won't skip notes.

Displaying Raspberry Pi clock on LCD display

I have a Raspberry Pi running an LCD display. I found the Python script below which displays the time on the display, but I notice there's a delay of almost a second between the Pi's time and the LCD.
I tried removing the last line of the code (sleep(1)) and that removed the delay but the LCD flickers a lot.
Can anyone please explain the function of that last line, and whether there's a way to display the time on the LCD without a delay?
Thanks.
#!/usr/bin/python
import RPi.GPIO as GPIO
from Adafruit_CharLCD import Adafruit_CharLCD
from subprocess import *
from time import sleep, strftime
from datetime import datetime
lcd = Adafruit_CharLCD()
lcd.begin(16,1)
GPIO.setup(18, 0)
GPIO.output(18, 1)
while 1:
lcd.clear()
lcd.message(datetime.now().strftime('%b %d %H:%M:%S\n'))
sleep(1)
The sleep(1) instructs the program to "sleep" for 1 second. This is actually very significant because that means that the while loop (which is always true) will then only run once every second. When you take away the sleep(1) line, that means the while loop never takes a break and continues running as fast as the computer can go infinitely. One thing you might try is just reducing the sleep(1) to some smaller value. For example, you can specify sleep(0.1)
By reducing the amount of time it sleeps, that means the clock will update more frequently. Right now with sleep(1) the clock updates once every second, which makes perfect sense. However, you might increase accuracy by having the clock update 10 times every second with sleep(0.1). Let me know if this all makes sense.
The flickering is likely caused by the fact that the program is clearing and repopulating the display so many times a second.
Edit: Documentation suggests that sending decimal values to the sleep() function is valid
Edit 2: An extra bit about how to only refresh the display if right at the turn of a second
from datetime import datetime
from time import sleep, mktime
dti = mktime(datetime.now().timetuple())
while 1:
ndti = mktime(datetime.now().timetuple())
if dti < ndti:
dti = ndti
lcd.clear()
lcd.message(datetime.now().strftime('%b %d %H:%M:%S\n'))
sleep(0.95)
else:
sleep(0.01)
In essence, here's how it works:
When starting the program, create a datetime in integer form (our var dti). By "integer form" I mean add up all the seconds from some arbitrary start date (e.g. 1970-01-01 00:00:00) and use that as a reference for time. For example, today (2016-08-18 00:00:00) might be something like 1471478400 seconds since 1970. Once we have that value, we start our loop.
At the beginning of the loop, we always create a new datetime integer (ndti) to track where we are since the last time we ran the loop. With this information handy, we hop into the if conditional. if our new datetime integer (ndti) has changed fully by one second compared to our old datetime integer (dti) then that means, obviously, one second has passed. Since that is the case, we will now set our reference datetime integer to the datetime now (dti = ndti). Then we display our message (lcd.clear() and lcd.message()). After that we will sleep the program for just under 1 whole second (sleep(0.95)). Since some computers can possibly sleep more than the exact allotted time, this gives us .05 seconds of cushion to be inaccurate. In the event that we are running through the if conditional and a second has not passed yet, we would sleep the program for a short time and continue repeating until a second has actually passed (sleep(0.01)).
If everything goes exactly as planned, then for each second our program should be refreshing the lcd screen only once, and it should also be sleeping for roughly 95% of that second, so that we aren't spinning our wheels for no reason the whole time. Another part to note is that since our else clause tells the program to sleep for 0.01 seconds, that means that, in most cases, our clock can only ever be inaccurate by a margin of 0.01 seconds, which is quite good. This is low enough to be mostly undetectable by humans. Let me know if all this makes sense.
I tested this out via command line (replacing the lcd stuff with simple print statements) and it seemed to line up exactly with another time tracking resource (http://time.is/)
Try it out and see if it works for you.
IT is best way to print date and time on lcd
firstly download or git clone rplcd library for lcd add in upper side of code
import RPLCD
textDate = strftime("%d %A %Y", gmtime())
textTime = strftime("%H:%M:%S", gmtime())
lcd_string(textDate,LCD_LINE_1)
lcd_string(textTime,LCD_LINE_2)

clicker eats a lot of processor time - python 3

I have a simple program that does the following:
1) User points a mouse somewhere,
2) then user presses Space,
3) and computer does certain amount of left-botton-mouse-clicks at that point.
The program works fine, there is only one problem - it eats 30-50% of processor time on a 4-core processor. Where is the problem?
import pyautogui
import ctypes
pyautogui.FAILSAFE = True
def get_space_state():
hllDll = ctypes.WinDLL ("User32.dll")
VK_SPACE = 0x20
return hllDll.GetKeyState(VK_SPACE)
while True:
if get_space_state() == -127 or get_space_state() == -128:
print ("yes")
pyautogui.click(clicks=40 , interval=0.01)
Thanks a lot.
Correct answer: I suspect a constant polling because of while True:. Insert sleep or pyautogui.PAUSE there (inside while loop, before if), if process sleeps for a while (even less then a second) it frees a lot of CPU cycles
Minor optimizations:
Also you're initializing entire User32.dll in every loop... twice (because of or), it seems.
And User32 is HUGE
Hints and notes:
If I remember python rules right, you just can move hllDll to a module level (above function defintion), get_space_state() will find it anyway. Or you can pass it as a parameter. And you don't need to redefine VK_SPACE every function call - though this is a micro-optimization
If all these fixes won't work, you should use debuggers, to find a true source of slowdowns
If you happen to have problems like this in the future, use something like Immunity or WinDbg to attach to process and see what's going on there

Is there a possibility to modify the reruns per second of a while-loop? (Python) [duplicate]

This question already has answers here:
How do I ensure that a Python while-loop takes a particular amount of time to run?
(3 answers)
Closed 9 years ago.
I have the following problem: I need a program that runs every minute. I have managed to do this with python's time-module and an infinite while-loop. It looks like this:
while True:
time_now = tm.gmtime(tm.time())
min_now = time_now.tm_min
if min_now - min_then == 1 or min_now - min_then == -59:
min_then = min_now
......
The loop runs about 150.000 times a second and while I don't think that the general performance is harmed worthy of mention, I wonder if there are alternatives.
Can I modify the number of reruns of a while loop? Or does the algorithm (in assembler, machine code etc.) just jump back to the beginning when finished? Can I use something like a 'wait'-command and will that help?
Thanks for listening (and answering ;) ),
best wishes,
Max
EDIT:
A sleep-command indeed solved my problems. I forget to mention that the rerun must take place every full clock-minute. A sleep for 60 seconds wouldn't be satisfying, however, I used a way that Xi Huan's link mentioned: After the execution of a loop, I use sleep(59.9-time_now.tm_sec). That reduces the CPU usage to 1%. Excellent.
And: Thank you all for your help! I'd like to upvote you, but I don't have enough reputation :D sry
bye!
An easy way would be to sleep in the loop, e.g.
import time
while True:
# do some stuff
time.sleep(60) #sleeps for a minute
EDIT:
Also be aware that you will need to 'import time' for this to work. Also, if you wish to limit the number of times it loops, this could be useful. The example below will loop once per minute and will loop 10 times in total.
import time
for x in xrange(0, 10):
#do stuff
time.sleep(60)
A common way to do this is by calling time.sleep, which is essentially the 'wait' command you ask about. If you do:
while True:
time.sleep(60)
# do stuff
The loop will end up running approximately once every minute, plus however long the do stuff takes. There are caveats mentioned in the docs that this isn't guaranteed to be an exact wait time, so you probably still want to check the time at each iteration (depending how strict the 'once per minute' is).
use a time.sleep method:
import time
while True:
#do something
time.sleep(60)

Categories

Resources