Page 1 of 2
uasyncio parralel threading seems to not work
Posted: Fri Aug 07, 2020 3:26 pm
by zaord
Hi here,
I try to use two routine I wants to be exectued in the same time continulsy, but Only the first one is running...
Where I am wrong ?
Code: Select all
async def screen(self):
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
wri = Writer(ssd, small, verbose=False)
wri.set_clip(False, False, False)
nfields = []
dy = small.height() + 6
y = 2
col = 50
width = wri.stringlen('990.99')
for txt in ('Press:', 'Y:', 'Z:'):
nfields.append(Label(wri, y, col, width, bdcolor=None)) # Draw border
y += dy
while True :
Label(wri, 2, 2, ' Press ', True)
Label(wri, 22, 2, ' Flow ', True)
Label(wri, 42, 2, ' Temp ', True)
i=0
for field in nfields:
value = (self.bmp.pressure-self.p0,self.sfm3000.Mes_flow(),self.bmp.temperature)
#print(value[i]) # print sensors values
field.value('{:5.2f}'.format(value[i]))
i=i+1
refresh(ssd)
utime.sleep_ms(200)
async def InvPress(self):
utime.sleep_ms(1000)
print('Sw2',self.SW2.value())
while True:
print(self.SW2.value())
if self.SW2.value():
if self.PressPos == 1:
self.stepper.steps(-1600,2600)
self.PressPos = not self.PressPos
else :
self.stepper.steps(+1600,2600)
self.PressPos = not self.PressPos
utime.sleep_ms(120)
async def main(self):
uasyncio.create_task(self.InvPress())
uasyncio.create_task(self.screen())
await uasyncio.sleep(10)
Re: uasyncio parralel threading seems to not work
Posted: Sat Aug 08, 2020 11:21 am
by zaord
Hi here,
It's seems that I did not put Any await so only one routine could be run and never the others.
Here I put the code updated :
Code: Select all
uasyncio.run(self.main())
async def screen(self):
await uasyncio.sleep_ms(100)
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
wri = Writer(ssd, small, verbose=False)
wri.set_clip(False, False, False)
nfields = []
dy = small.height() + 6
y = 2
col = 50
width = wri.stringlen('990.99')
for txt in ('Press:', 'Y:', 'Z:'):
nfields.append(Label(wri, y, col, width, bdcolor=None)) # Draw border
y += dy
while True :
Label(wri, 2, 2, ' Press ', True)
Label(wri, 22, 2, ' Flow ', True)
Label(wri, 42, 2, ' Temp ', True)
i=0
for field in nfields:
value = (self.bmp.pressure-self.p0,self.sfm3000.Mes_flow(),self.bmp.temperature)
#print(value[i]) # print sensors values
field.value('{:5.2f}'.format(value[i]))
i=i+1
refresh(ssd)
await uasyncio.sleep_ms(100)
async def InvPress(self):
await uasyncio.sleep_ms(1000)
print('Sw2',self.SW2.value())
while True:
print(self.SW2.value())
if self.SW2.value():
if self.PressPos == 1:
self.stepper.steps(-1600,2600)
self.PressPos = not self.PressPos
else :
self.stepper.steps(+1600,2600)
self.PressPos = not self.PressPos
await uasyncio.sleep_ms(120)
async def main(self):
uasyncio.create_task(self.InvPress())
uasyncio.create_task(self.screen())
while True:
await uasyncio.sleep(1000)
Now my question is that I use a Class Stepper for controlling a stepper motor driver and on this class that I call In the InvPress uasyncio routine, I tried to replace the commun utime.sleep() by await uasyncio.sleep_us(20), but this not seems to works sinc when the step() routine below is running, the main code is frost...
Any idea to solve this ?
Code: Select all
async def steps(self, step_count, speed = 1000):
"""Rotate stepper for given steps."""
print(self.step_time)
self.calc_pulse_per_sec(speed)
self.dir.value(0 if step_count > 0 else 1)
for i in range(abs(step_count)):
self.stp.high()
await uasyncio.sleep_us(20)
self.stp.low()
await uasyncio.sleep_us(self.step_time)
self.current_position += step_count
Re: uasyncio parralel threading seems to not work
Posted: Sat Aug 08, 2020 12:20 pm
by pythoncoder
I think your code is throwing an exception which you may be missing.
uasyncio does not have a
sleep_us function:
Code: Select all
>>> 'sleep_us' in dir(uasyncio)
False
It is easy to miss exceptions in running
uasyncio programs because by default the task stops but the others continue, typically producing print output and causing the error to scroll out of view. You need
a global exception handler during development.
Microsecond level timing is beyond
uasyncio. When a task yields control (e.g.
await asyncio.sleep_ms(1)) all other pending tasks get to run. The actual delay depends on the design of those tasks but will typically be tens of ms.
Re: uasyncio parralel threading seems to not work
Posted: Sat Aug 08, 2020 2:36 pm
by zaord
Hi,
I found maybe a mistake in your tutorial
async def main():
loop = asyncio.get_event_loop()
Isn't be uasyncio.get_ instead ?
I try and come back if I have more questions !
Re: uasyncio parralel threading seems to not work
Posted: Sat Aug 08, 2020 2:49 pm
by zaord
Okay, I get several error that I could fix with the _exception_handler, but my code is actually still frozen during my stepper function execution.
So I have some question :
1) Is it possible to call await uasyncio.sleep_ms(120) in the function stepper from the function InvPress which is called by the uasyncio main(self) if my function stepper is not difined in one of the uasyncio.create_task() from the main function ?
2) If a want refresh a oled screen each 200 ms, is it better to put a await uasyncio.sleep_ms(200) on begining, on end or to split this into 4 await uasyncio.sleep_ms(50) dispatched in the begining, middle and end of a routine ?
Re: uasyncio parralel threading seems to not work
Posted: Sun Aug 09, 2020 7:59 am
by pythoncoder
zaord wrote: ↑Sat Aug 08, 2020 2:36 pm
Hi,
I found maybe a mistake in your tutorial
async def main():
loop = asyncio.get_event_loop()
Isn't be
uasyncio.get_ instead ?
I try and come back if I have more questions !
In my tutorial I advocate importing uasyncio as follows
This facilitates writing code which is compatible with CPython. If you later decide to port your code, you can change the import to
Code: Select all
try:
import asyncio
except ImportError:
import uasyncio as asyncio
with no further changes normally needed.
Re: uasyncio parralel threading seems to not work
Posted: Sun Aug 09, 2020 8:02 am
by zaord
Hmmm Good to know
Thanks a lot Peter !
Re: uasyncio parralel threading seems to not work
Posted: Sun Aug 09, 2020 8:12 am
by pythoncoder
I'm unclear about your other queries. If a function or method is defined with
async def it is always valid for it to call
uasyncio.sleep_ms(120). I think you need to explain the exact nature of your problem.
Re OLED refresh I can think of only one circumstance where you might want to split a delay, and that is where you have a computationally intensive routine which might hog the processor and starve other coroutines of execution. In these cases you could equally have a delay of zero as that will give every other task some execution:
Code: Select all
async def refresh_oled():
while True:
foo() # Maybe takes 20ms
await asyncio.sleep(0)
bar() # Takes another 20ms
await asyncio.sleep(0)
refresh_oled() # Takes 20ms
await asyncio.sleep(200)
In the above example no other task is blocked for more than 20ms (assuming there is no other heavy duty task in progress).
Re: uasyncio parralel threading seems to not work
Posted: Sun Aug 09, 2020 9:28 pm
by zaord
My question is that the stepper routine I post above Have a sleep to vary the speed of rotation of my stepper, and this await seems to not allow the other coroutine to run since the oled refresh function is like so slow that is freeze the screen.
So I wonder if it is normal of if it's due to the fact that this function is in another class that my main function and maybe the await from this stepper class don't 'know' the other uasyncio routine of my main class where I call uasyncio.run(self.main())...
Re: uasyncio parralel threading seems to not work
Posted: Mon Aug 10, 2020 5:11 am
by pythoncoder
It's hard to comment without seeing the code but in my experience
uasyncio V3 "just works". The scheduler will schedule every task which has been started, regardless of the module or the class that they are in.
Slowdowns of the type you describe are a common problem with asynchronous programming. They can usually be overcome with careful design. What is almost certainly happening is that some tasks are hogging the CPU. Do you ever call
time.sleep()? This hogs the CPU for the duration. In my view it should never be used -
time.sleep_us() can be necessary if there is a maximum delay which can be tolerated but you need to yield to the scheduler with
asyncio.sleep_ms() ASAP. So code like the following will be a CPU hog:
Code: Select all
async def foo(self):
while True:
for _ in range 1000: # Greedily grab 50ms of CPU time
time.sleep_us(50)
# do something
await asyncio.sleep_ms(0)
Driving stepper motors without hogging CPU is difficult. You can buy stepper motor controllers which do all the fast stuff onboard. You tell the controller where to move to and the controller handles acceleration and deceleration, telling you when it has got there. That would be my approach.