High response time - programmatically move mouse using pyautogui - python

In a python script, the response time for pyautogui.moveRel(b, a) is currently .1 sec. Is that the intended time for this function? If so, is there any way I can shorten this response time using another technique in python, or other languages? My goal response time is about 0.01 sec, which is the 60HZ rate.

The results #mertyildiran obtained are to be expected, since PyAutoGUI has a default 0.1 second pause between actions as a failsafe.
To speed things up, you can set the pause to a lower value, or even zero, like so:
pyautogui.PAUSE = 0

The code for checking the response time in microseconds(0.01 seconds = 10000 microseconds):
import pyautogui
import datetime
for x in range(0, 9):
start = datetime.datetime.now()
pyautogui.moveRel(None, 50)
end = datetime.datetime.now()
elapsed_time = end - start
print elapsed_time.microseconds
Output:
269017
112927
113071
113061
112761
112561
113115
112107
112448
That means yeah it's approximately 0.1 seconds with this library and Python. So my recommendation is go with a deeper level programming language like C++.
Stimulate mouse event with C++ in Windows: https://stackoverflow.com/a/7492837/2104879
Stimulate mouse event with C++ in Linux: https://stackoverflow.com/a/8791599/2104879

Related

What are the ways to improve my metronome written in Python?

I'm trying to write a python based metronome with librosa and sounddevice but I've came across some problems with it's accuracy. Here's the code:
from time import sleep, perf_counter
import librosa
import sounddevice as sd
bpm = 200
delay = 60/bpm
tone = librosa.tone(440, sr=22050, length=1000)
try:
while True:
sd.play(tone, 22050)
sleep(delay)
except KeyboardInterrupt:
pass
First of all, the upper limit for properly functioning metronome seems to be around 180bpm - if you set the bpm to be any higher then 200bpm then there is no sound produced. In slower tempos I can hear that metronme is not so consistent as it should be with spacing in between the clicks. I've runned the script from this topic and my results were pretty poor compared to the author of this answer(which was using "old single core 32 bit 2GHz machine" against my six-core 3.9GHz 64bit windows running):
150.0 bpm
+0.007575200
+0.006221200
-0.012907700
+0.001935400
+0.002982700
+0.006840000
-0.009625400
+0.003260200
+0.005553100
+0.000668100
-0.010895100
+0.017142500
-0.012933300
+0.001465200
+0.004203100
+0.004769100
-0.012183100
+0.002174500
+0.002301000
-0.001611100
So i wonder if my metronome problems are somehow correlated to these poor results and what I can do to fix it.
The second problem that I encounter is the way in which the metronome is switched off - I want it to be running up until the point where the user inputs a specific button, or in my case(no GUI) a specific value from the keyboard - let's say the space key. So as you can see now it works only with ctrl + c, but I have no idea how to implement interrupt with a specified key.
Running your code on a mac, the timing inconsistencies are noticeable but also the tempo was of quite a bit off from the set bpm.
This is mostly because sleep() isn't that accurate, but also because you have to account for the time that has elapsed since the last event. e.g. how much time did it take to call sd.play()
I don't know on what operating system you did run this, but most operating systems have a special timer for precise callbacks (e.g. Multimedia Timers on Windows). if you don't want a platform specific solution to improve the timing you could do a "busy wait" instead on sleep(). To do this you could sleep for have the delay, and then go into a loop where you constantly check the time elapsed.
lastTime = perf_counter()
while True:
currentTime = perf_counter()
delta = abs(lastTime - currentTime)
sleep(delay / 2.0)
while True:
currentTime = perf_counter()
if (currentTime - lastTime >= delay):
sd.play(tone, 22050)
lastTime = currentTime
break
Not a perfect solution but it'll get you closer.
You can further optimise the fraction of the delay that is spent sleeping to take load of the CPU.

How to create a python loop that allows other code to run as well

I'm an amateur coder. I'm working on a small little game for a project in biology, but I have come across an issue in my code. I have a loop that adds +1 to the variable sunlight every two seconds. However, all code below the loop is non-functional now that I have made the loop. I'm guessing it's because it's waiting for the loop to finish. Any way to have the loop always run but allow the code to run through it's sequence at the same time?
print("Game started!")
sunlight = 0
while True:
time.sleep(2)
sunlight += 1
commands = input("Type stats to see which molecules you have, type carbon to get carbon\ndioxide, and type water to get water: ")
if commands == ("stats"):
print("Sunlight: ",sunlight,"")
As you are beginner, i would not recommend to use multithreading or asyncio. Instead just start the time and when user enter "stats", elapsed time//2 will be equal to sunlight.
import time
start_time = time.time()
while True:
commands = input("Type stats to see which molecules you have, type carbon to get carbon\ndioxide, and type water to get water: ")
if commands == ("stats"):
sunlight = (time.time()-start_time)//2 # elapsed time // 2
print("Sunlight: ", sunlight, "")
Your sunlight variable basically functions as a clock; it counts half of the number of seconds since the program begins. Rather than implement your own clock using time.sleep(), it's better to just use an existing clock from the time library.
The function time.monotonic returns a number of seconds, so you can use this to get the current sunlight by saving the start time, then each time you want to know the value of sunlight, take the difference between the current time and the start time, divided by 2.
start_time = time.monotonic()
def get_sunlight():
current_time = time.monotonic()
return int(current_time - start_time) // 2
It is better to use the monotonic() function than the clock() function for this purpose, since the clock() function is deprecated as of Python 3.3:
The time.clock() function is deprecated because it is not portable: it behaves differently depending on the operating system.
It's also better than the time() function for this purpose, because changes to the system clock (such as going forwards or back due to daylight savings time) will affect the result of time():
While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.
You should look into the multithreading library. That's probably a good resource. You can fire off a thread running your sunlight incrementer that updates a global variable (not a good idea but you seem to have just 1 writer, so you can get by till you have time to pick up more advanced parallel processing concepts).
Reference: https://www.geeksforgeeks.org/multithreading-python-set-1/

How do I create a scheduled task using Python Win32com that runs every 5 seconds?

I am trying to create a scheduled task in Python using Win32com. I am able to create a daily trigger. However, I cannot find a way to create a trigger every 5 seconds or every minute for that matter. Does anybody have any pointers on how to do that?
As said in a comment, if you want to do stuff with this frequency you are better off just having your program run forever and do its own scheduling.
In a similar fashion to #Barmak Shemirani's answer, but without spawning threads:
import time
def screenshot():
# do your screenshot...
interval = 5.
target_time = time.monotonic() + interval
while True:
screenshot()
delay = target_time - time.monotonic()
if delay > 0.:
time.sleep(delay)
target_time += interval
or, if your screenshot is fast enough and you don't really care about precise timing:
while True:
screenshot()
time.sleep(interval)
If you want this to run from the system startup, you'll have to make it a service, and change the exit condition accordingly.
pywin32 is not required to create schedule or timer. Use the following:
import threading
def screenshot():
#pywin32 code here
print ("Test")
def starttimer():
threading.Timer(1.0, starttimer).start()
screenshot()
starttimer()
Use pywin32 for taking screenshot etc.

Control the speed of a loop

I'm currently reading physics in the university, and im learning python as a little hobby.
To practise both at the same time, i figured I'll write a little "physics engine" that calculates the movement of an object based on x,y and z coordinates. Im only gonna return the movement in text (at least for now!) but i want the position updates to be real-time.
To do that i need to update the position of an object, lets say a hundred times a second, and print it back to the screen. So every 10 ms the program prints the current position.
So if the execution of the calculations take 2 ms, then the loop must wait 8ms before it prints and recalculate for the next position.
Whats the best way of constructing a loop like that, and is 100 times a second a fair frequency or would you go slower, like 25 times/sec?
The basic way to wait in python is to import time and use time.sleep. Then the question is, how long to sleep? This depends on how you want to handle cases where your loop misses the desired timing. The following implementation tries to catch up to the target interval if it misses.
import time
import random
def doTimeConsumingStep(N):
"""
This represents the computational part of your simulation.
For the sake of illustration, I've set it up so that it takes a random
amount of time which is occasionally longer than the interval you want.
"""
r = random.random()
computationTime = N * (r + 0.2)
print("...computing for %f seconds..."%(computationTime,))
time.sleep(computationTime)
def timerTest(N=1):
repsCompleted = 0
beginningOfTime = time.clock()
start = time.clock()
goAgainAt = start + N
while 1:
print("Loop #%d at time %f"%(repsCompleted, time.clock() - beginningOfTime))
repsCompleted += 1
doTimeConsumingStep(N)
#If we missed our interval, iterate immediately and increment the target time
if time.clock() > goAgainAt:
print("Oops, missed an iteration")
goAgainAt += N
continue
#Otherwise, wait for next interval
timeToSleep = goAgainAt - time.clock()
goAgainAt += N
time.sleep(timeToSleep)
if __name__ == "__main__":
timerTest()
Note that you will miss your desired timing on a normal OS, so things like this are necessary. Note that even with asynchronous frameworks like tulip and twisted you can't guarantee timing on a normal operating system.
Since you cannot know in advance how long each iteration will take, you need some sort of event-driven loop. A possible solution would be using the twisted module, which is based on the reactor pattern.
from twisted.internet import task
from twisted.internet import reactor
delay = 0.1
def work():
print "called"
l = task.LoopingCall(work)
l.start(delay)
reactor.run()
However, as has been noted, don't expect a true real-time responsiveness.
A piece of warning. You may not expect a real time on a non-realtime system. The sleep family of calls guarantees at least a given delay, but may well delay you for more.
Therefore, once you returned from sleep, query current time, and make the calculations into the "future" (accounting for the calculation time).

Sleep for exact time in python

I need to wait for about 25ms in one of my functions. Sometimes this function is called when the processor is occupied with other things and other times it has the processor all to itself.
I've tried time.sleep(.25) but sometimes its actually 25ms and other times it takes much longer. Is there a way to sleep for an exact amount of time regardless of processor availability?
Because you're working with a preemptive operating system, there's no way you can guarantee that your process will be able to have control of the CPU in 25ms.
If you'd still like to try, it would be better to have a busy loop that polls until 25ms has passed. Something like this might work:
import time
target_time = time.clock() + 0.025
while time.clock() < target_time:
pass
0.25 seconds are 250 ms, not 25. Apart from this, there is no way to wait for exactly 25 ms on common operating systems – you would need some real-time operating system.
What system are you on? If you're on Windows you may want to do something like this for exact timing:
import ctypes
kernel32 = ctypes.windll.kernel32
# This sets the priority of the process to realtime--the same priority as the mouse pointer.
kernel32.SetThreadPriority(kernel32.GetCurrentThread(), 31)
# This creates a timer. This only needs to be done once.
timer = kernel32.CreateWaitableTimerA(ctypes.c_void_p(), True, ctypes.c_void_p())
# The kernel measures in 100 nanosecond intervals, so we must multiply .25 by 10000
delay = ctypes.c_longlong(.25 * 10000)
kernel32.SetWaitableTimer(timer, ctypes.byref(delay), 0, ctypes.c_void_p(), ctypes.c_void_p(), False)
kernel32.WaitForSingleObject(timer, 0xffffffff)
This code will pretty much guarentee your process will sleep .25 seconds. Watch out though- you may want to lower the priority to 2 or 3 unless it's absolutely critical that this sleeps for .25 seconds. Certainly don't change the priority too high for a user-end product.
Edit: in Windows 10 this nonsense seems unnecessary. Try it like so:
>>> from time import sleep
>>> import timeit
>>> '%.2f%% overhead' % (timeit.timeit('sleep(0.025)', number=100, globals=globals()) / 0.025 - 100)
'0.29% overhead'
.29%, or thereabout, is fairly low overhead, and usually more than accurate enough.
Previous Windows versions will by default have a sleep resolution of 55 msecs, which means your sleep call will take somewhere between 25 and 55 msecs. To get the sleep resolution down to 1 millisecond you need to set the resolution used by Windows by calling timeBeginPeriod:
import ctypes
winmm = ctypes.WinDLL('winmm')
winmm.timeBeginPeriod(1)
Another solution for accurate timings and delay is to use the perf_counter() function from module time. Especially useful in windows as time.sleep is not accurate in milliseconds. See below example where function accurate_delay creates a delay in millisecond.
import time
def accurate_delay(delay):
''' Function to provide accurate time delay in millisecond
'''
_ = time.perf_counter() + delay/1000
while time.perf_counter() < _:
pass
delay = 10
t_start = time.perf_counter()
print('Wait for {:.0f} ms. Start: {:.5f}'.format(delay, t_start))
accurate_delay(delay)
t_end = time.perf_counter()
print('End time: {:.5f}. Delay is {:.5f} ms'.
format(t_end, 1000*(t_end - t_start)))
sum = 0
ntests = 1000
for _ in range(ntests):
t_start = time.perf_counter()
accurate_delay(delay)
t_end = time.perf_counter()
print('Test completed: {:.2f}%'.format(_/ntests * 100), end='\r', flush=True)
sum = sum + 1000*(t_end - t_start) - delay
print('Average difference in time delay is {:.5f} ms.'.format(sum/ntests))
What you intend to do is a real time application. Python (and probably the OS you are using) is not intended to program this kind of applications, where time restriction is so strict.
In order for you to achieve what you are looking for you need a RTOS (Real Time Operating System) and develop your application using a suitable programming language (usually C) following RT best practises.
From the docs of the sleep method:
Suspend execution for the given number of seconds. The argument may be
a floating point number to indicate a more precise sleep time. The
actual suspension time may be less than that requested because any
caught signal will terminate the sleep() following execution of that
signal’s catching routine. Also, the suspension time may be longer
than requested by an arbitrary amount because of the scheduling of
other activity in the system.
The fact is that it depends on your underlying OS.

Categories