Last active
March 28, 2023 14:09
-
-
Save dlech/fa48f9b2a3a661c79c2c5880684b63ae to your computer and use it in GitHub Desktop.
Example of LEGO SPIKE Prime scratch program translated to MicroPython using generator functions as coroutines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spike.control.wait_for_seconds doesn't allow decimal points | |
# so we replace it with the standard MicroPython sleep function instead | |
from utime import sleep as wait_for_seconds | |
from utime import ticks_diff, ticks_ms | |
# See https://docs.micropython.org/en/latest/library/utime.html for more info on the utime module | |
from spike import (PrimeHub, LightMatrix, Button, StatusLight, ForceSensor, MotionSensor, | |
Speaker, ColorSensor, App, DistanceSensor, Motor, MotorPair) | |
from spike.control import wait_until | |
# spike.control.Timer doesn't allow decimal points | |
class Timer(): | |
"""Replacement Timer class that allows decimal points so we can measure times of less than one second.""" | |
def __init__(self): | |
self.start_ticks = 0 | |
def now(self): | |
"""Returns the time in seconds since the timer was last reset.""" | |
return ticks_diff(ticks_ms(), self.start_ticks) / 1000 | |
def reset(self): | |
"""Resets the timer.""" | |
self.start_ticks = ticks_ms() | |
hub = PrimeHub() | |
background_beep_timer = Timer() # For use in background_beep() | |
background_image_timer = Timer() # For use in background_image_delay() | |
def background_beep(note, seconds): | |
"""Coroutine version of hub.speaker.beep(). | |
Parameters | |
---------- | |
note (int): The MIDI note number to play. | |
seconds (float): The duration of the beep in seconds. | |
""" | |
# this timer is used to measure how long it has been since we started | |
# the beep | |
background_beep_timer.reset() | |
# hub.speaker.beep() would block the rest of the program, so we have | |
# to use hub.speaker.start_beep() instead | |
hub.speaker.start_beep(note) | |
# then we use a timer to keep checking to see how long it has been since | |
# we started the beep | |
while background_beep_timer.now() < seconds: | |
# if it has not been long enought yet, then we "yield" to let the | |
# rest of the program run for a while then we will come back here | |
# later and check again | |
yield | |
# After it has been long enough, we have to stop the beep | |
hub.speaker.stop() | |
def play_melody(): | |
"""Plays a melody in the background.""" | |
while True: | |
# since background_beep() uses "yield" instead of "return", we have to | |
# say "yield from" here to keep calling background_beep() until it is done | |
yield from background_beep(72, 0.2) | |
yield from background_beep(74, 0.2) | |
yield from background_beep(76, 0.2) | |
yield from background_beep(77, 0.2) | |
yield from background_beep(79, 0.2) | |
yield from background_beep(81, 0.2) | |
yield from background_beep(83, 0.2) | |
yield from background_beep(84, 0.2) | |
def background_image_delay(seconds): | |
"""Delays for ``seconds``.""" | |
background_image_timer.reset() | |
while background_image_timer.now() < seconds: | |
yield | |
def animate_image(): | |
"""Shows different images in the background.""" | |
while True: | |
hub.light_matrix.show_image('HAPPY') | |
yield from background_image_delay(0.5) | |
hub.light_matrix.show_image('SAD') | |
yield from background_image_delay(0.5) | |
# Since the play_melody() and animate_image() functions use "yield" instead of | |
# "return", the functions don't actually run here when we *call* them. Instead, | |
# they create *generator* objects that will be used to run the funcitons one | |
# "yield" at a time. | |
melody_generator = play_melody() | |
animation_generator = animate_image() | |
# Task runner | |
while True: | |
# perform the "next" step in the play_melody() function by running it | |
# to the next "yield" statement | |
next(melody_generator) | |
# perform the "next" step in the animate_image() function | |
next(animation_generator) | |
# wait a *short* time before trying the next step | |
wait_for_seconds(0.01) |
still can't understand how it works😥
hello I'm a first lego league competitor and I wanted to know if this is the only way to perform actions simultaneously in micropython with the spike prime, wouldn't it have a similar function to the scratch broadcast block? Another thing I can apply your method to make my robot walk and turn a separate motor? (If any of these possibilities are really working, could you explain me how to do it? thanks for your attention ;) )
Is there also alternative for EV3? Thanks
For EV3, have a look at pybricks/support#666 and pybricks/support#99.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original scratch program:
Source: https://community.legoeducation.com/discuss/viewtopic/66/110