Microbit Beacons
Radio on the microbit is one of it's best features for interactivity between learners. Here I'll show a couple of examples of using the radio to create static beacons (and may be hidden) to broadcast information that can be picked up by someone moving around the space with a suitably coded receiver.
Hot and Cold
As well as simple receiving text messages over the radio, the microbit also supports a full mode which returns not just the message text but also the signal strength and a timestamp. We can use the signal strength to get a measure of how close or far away we are from a beacon. Signal strength is measured in decibels but comes to us as a score from 0 (strongest) down to -255 (weakest).
Beacon
We'll start off with a simple beacon, broadcasting some text every half a second.
from microbit import *
import radio
radio.on()
while True:
radio.send('ping')
sleep(500)
Receiver
Our receiver shouldn't care what the message is, just how strong the signal is. We convert the 0-255 scale into a percentage signal strength.
from microbit import *
import radio
radio.on()
while True:
display.show("?")
message = radio.receive_full()
if message:
signal_strength = message[1]
percent_strength = ((signal_strength + 255)* 100) / 255
display.scroll(str(percent_strength))
sleep(200)
Place the beacon somewhere out of the way (or have someone else place it) then walk around and try to find it based purely on signal strength. You can use the radio config option to change the radio power to suit the size of the space you are working in.
Simple Treasure Hunt
Now that we can send and receive messages from a single beacon, we can program several of them with unique ids, hide them around the local environment and use them as the basis for a simple treasure hunt. Each beacon can be given a text name or a number which it broadcasts. The treasure hunter has a receiver listening for any radio signal and completes the "hunt" by checking off each of the beacons that they find.
Beacon
Here's a simple beacon with a hard-coded id. Each beacon will need a different id flashed onto it.
from microbit import *
import radio
beacon_id = 1
# Lowest power transmit
radio.config(power=0)
radio.on()
while True:
radio.send(str(beacon_id))
display.show(str(beacon_id))
sleep(1000)
Alternatively, a slightly fancier beacon can be programmed with a dynamic id using the a and b buttons like this:
from microbit import *
import radio
beacon_count = 5
beacon_id = 1
# Lowest power transmit
radio.config(power=0) # power is 0 -> 7
radio.on()
while True:
# decrease beacon_id
if button_a.was_pressed():
beacon_id = max(beacon_id - 1, 1)
# increase beacon_id
elif button_b.was_pressed():
beacon_id = min(clue + 1, beacon_id)
# broadcast the current beacon_id
else:
radio.send(str(beacon_id))
display.show(str(beacon_id))
sleep(500)
Each beacon is flashed with the same code and it's up to the person doing the hiding to program each one with a unique number before hiding them.
Full Treasure Hunt
Finally, instead of a simple id, we can embed clues to a treasure hunt trail in the beacons so that each beacon can be configured to broadcast one clue. By sending the beacon's id out with the clue, we can even program the receiver to accept the clues in sequence so that the hunter has to visit the beacons in the correct order to make sense of the clues.
Beacon
from microbit import *
import radio
all_clues = [
"Walk Fifteen paces east",
"Ten paces north",
"Walk forwards",
"Look under the seat",
"Hooray, you win!"
]
clue_count = len(all_clues)
clue = 1
radio.config(power=4) # power is 0 -> 7
radio.on()
while True:
# decrease clue number
if button_a.was_pressed():
clue = max(clue - 1, 1)
# increase clue number
elif button_b.was_pressed():
clue = min(clue + 1, clue_count)
# broadcast the current clue
else:
clue_text = str(clue) + ":" + all_clues[clue - 1]
radio.send(clue_text)
display.show(str(clue))
sleep(500)
Receiver
from microbit import *
import radio
# starting clue
clue = "hint: Walk around to find the first clue"
display.scroll(clue)
next_clue = 1
radio.on()
while True:
display.show("?")
# are we near any clue beacons?
message = radio.receive()
if message:
# picked up a clue !
number, text = message.split(":")
# is it the one we want?
if int(number) == next_clue:
clue = "clue " + str(number) + ":" + text
next_clue += 1
display.scroll(clue)
sleep(250)
There are lots of variations you can explore once the system is up and running:
- Change the receiver to remind you about the last clue
- Draw a starting image
- Draw an image to show when the beacon is broadcasting.
- Change the code to make a Pokemon Go collecting game. Instead of clues, beacons can broadcast an image of a Pokemon and the hunter has to collect them all.
Adjust the power from each beacon to make it more challenging. If you are playing with more than one group in an area, consider changing the radio channel for each group so the clues belonging to each group don't interfere with each other.