Without delay(), how hard is it?

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
unory
Posts: 2
Joined: Sun Apr 02, 2017 8:53 am

Without delay(), how hard is it?

Post by unory » Sun Apr 02, 2017 9:05 am

Hi uPy Forum

Just got my pyboard v1.0 2 days ago and fall in love with it.
Here is what i want to do:
Auto move the servo from -90 to 90 repeatedly
The button input from 'X17' which is the on board button when pressed will turn the LED(1) on which is red.

However i could not get it to work the way i want. Can anyone give me some guide? Thanks

And here is my code:

import pyb
sw = pyb.Pin('X17', pyb.Pin.IN, pyb.Pin.PULL_UP)
le = pyb.LED(1)
servo1 = pyb.Servo(1)
while True:
servo1.angle(-90)
pyb.delay(500)
servo1.angle(90)
pyb.delay(500)
if sw.value == 0:
le.on()
else:
le.off()

The button is not working during the pyb.delay periods. I know the problem but doesnt know how to get around this.
Thanks first guys.

User avatar
deshipu
Posts: 1348
Joined: Thu May 28, 2015 5:54 pm

Re: Without delay(), how hard is it?

Post by deshipu » Sun Apr 02, 2017 10:21 am

The standard trick to do this is called "blink without a delay" and involves running the loop without any delays, but only doing things inside it if the time elapsed since the last time is greater than some value. For example:

Code: Select all

last_button = last_servo = utime.ticks_ms()
servo_angle = 90
led_state = False
while True:
    now = utime.ticks_ms()
    if utime.ticks_diff(now, last_servo) > 500:
        servo1.angle(servo_angle)
        servo_angle = -servo_angle
        last_servo = now
    if utime.ticks_diff(now, last_button) > 200 and not sw.value():
        led_state = not led_state
        le.value(led_state)
        last_button = now
Last edited by deshipu on Sun Apr 02, 2017 10:25 am, edited 2 times in total.

User avatar
deshipu
Posts: 1348
Joined: Thu May 28, 2015 5:54 pm

Re: Without delay(), how hard is it?

Post by deshipu » Sun Apr 02, 2017 10:23 am

There are also other ways, such as interrupts, asyncio or even threads, but I think this is an important trick to have up your sleeve.

unory
Posts: 2
Joined: Sun Apr 02, 2017 8:53 am

Re: Without delay(), how hard is it?

Post by unory » Sun Apr 02, 2017 10:42 am

Thanks for the info and the code. I trying the code atm but its said ticks_ms is not define
I try to look up the library from this link but i cant find any library for utime https://pypi.python.org/pypi?%3Aaction= ... icropython

Did i miss step somewhere?

User avatar
deshipu
Posts: 1348
Joined: Thu May 28, 2015 5:54 pm

Re: Without delay(), how hard is it?

Post by deshipu » Sun Apr 02, 2017 3:15 pm

utime is built-in, you just have to import it

User avatar
lepi
Posts: 3
Joined: Sat May 04, 2019 10:47 am
Location: Warsaw, Poland

Re: Without delay(), how hard is it?

Post by lepi » Mon May 27, 2019 8:26 am

>> "blink without a delay" (...) For example:

Deshipu, thank you for this implementation, sth exactly like this should be in utime module docs.

Perhaps instead of this:
# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
do_a_little_of_something()

Cheers!

User avatar
pythoncoder
Posts: 3695
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Without delay(), how hard is it?

Post by pythoncoder » Tue May 28, 2019 10:25 am

This approach is fine for very simple programs but the event loop soon gets convoluted as the number of events to be handled increases. You can write more modular and object oriented code using asyncio. Consider this code which flashes the four Pyboard LED's asynchronously for ten seconds:

Code: Select all

import pyb
import uasyncio as asyncio

async def killer(duration):
    await asyncio.sleep(duration)

async def toggle(objLED, time_ms):
    while True:
        await asyncio.sleep_ms(time_ms)
        objLED.toggle()

loop = asyncio.get_event_loop()
leds = [pyb.LED(x) for x in range(1,5)]  # Initialise all four on board LED's
for x, led in enumerate(leds):  # Create a coroutine for each LED
    t = int((0.2 + x/2) * 1000)
    loop.create_task(toggle(leds[x], t))
loop.run_until_complete(killer(10))  # Run for 10s
If you had, say, 16 LED's all you'd need to change is a single number. With a hand crafted event loop, the loop code would increase substantially. For anyone unfamiliar with asyncio async repo includes a tutorial.
Peter Hinch

User avatar
lepi
Posts: 3
Joined: Sat May 04, 2019 10:47 am
Location: Warsaw, Poland

Re: Without delay(), how hard is it?

Post by lepi » Thu May 30, 2019 10:55 am

Thank you Peter!

I'll sit down to understand this in the evening : )
I'll look into uasyncio tutorial as well.

Cheers! : )

Post Reply