micro:bits and raspberry pis
whoami
Luke Spademan
0) Student
1) GCSEs
3) gave a lightening talk last year
2) @lukespademan: [twitter, github, etc]
Project
Project
Connect 4 Game
Micro:bits have 5x5 led matrix
Connect 3 Game
micro:bits
micro:bits
2 micro:bits play connect 3
They use the radio module to communicte
import radio
radio.config(channel=10)
radio.on()
data = radio.receive()
print(data)
radio.send("Hello World")
and raspberry pis
and raspberry pis
It then sends the data over serial to a raspberry pi
Another micro:bit listens in on the game play
The raspberry pi then displays that data using a sense hat with RGB LED matrix
print("Hello World")
and tensor flow
and tensor flow
I was going to have AI play you at connect 3
But reaslised with the hardware I was using it wasn't going to work
The lessons learnt part of the title, is the lesson that neural networks and raspberry pis are difficult to get talking
Especially because I wanted to do the training on the RPi
microbits = 3 # for game play and sending data to RPi
raspberrypis = 1 # for displaying game
tensorflow = 0 # sorry
Plan
Plan
- 2 micro:bits play connect 3
- Your turn and you update the display, you also send the data using the radio
- Opponent to see board
- 3rd micro:bit to see board
- 3rd micro:bit sends data over serial
- raspberry pi displays that data on an RGB LED matrix
Let's do this
Step 1
moving the counter along the top
Step 1.0
from microbit import *
board = "00000:" \
"00000:" \
"00000:" \
"00000:" \
"00000"
x = 0
while True:
if button_a.is_pressed():
x += 1
if x == 5:
x = 0
board = board[:4] + "0" + board[5:]
else:
board = board[:x-1] + "0" + board[x:]
board = board[:x] + "9" + board[x+1:]
print(board)
display.show(Image(board))
Step 1.1
from microbit import *
board = "00000:" \
"00000:" \
"00000:" \
"00000:" \
"00000:"
x = 0
while True:
if button_a.is_pressed():
x += 1
if x == 5:
x = 0
board = board[:4] + "0" + board[5:]
else:
board = board[:x-1] + "0" + board[x:]
board = board[:x] + "9" + board[x+1:]
display.show(Image(board))
sleep(250) # allows recognition on one press
Step 1.2
from microbit import *
def set_board_pixel(x, y, board, colour):
pos = get_pos(x, y)
board = board[:pos] + str(colour) + board[pos+1:]
return board
def get_pos(x, y):
pos = (6*y) + x
return pos
board = "00000:" \
"00000:" \
"00000:" \
"00000:" \
"00000:"
x = 0
while True:
if button_a.is_pressed():
x += 1
if x == 5:
x = 0
board = set_board_pixel(4, 0, board, "0")
else:
board = set_board_pixel(x-1, 0, board, "0")
board = set_board_pixel(x, 0, board, "9")
print(board)
display.show(Image(board))
sleep(250)
Step 2
send data to the other micro:bit
Step 2
# player1.py
from microbit import *
import radio
radio.on()
radio.config(channel=27)
def show_board(board):
display.show(Image(board))
radio.send(board)
# more functions and setup
while True:
if button_a.is_pressed():
x += 1
if x == 5:
x = 0
board = set_board_pixel(4, 0, board, "0")
else:
board = set_board_pixel(x-1, 0, board, "0")
board = set_board_pixel(x, 0, board, "9")
print(board)
show_board(board)
sleep(250)
# player2.py
from microbit import *
import radio
radio.on()
radio.config(channel=27)
board = "00000:" \
"00000:" \
"00000:" \
"00000:" \
"00000"
while True:
data = radio.recive()
if data:
board = data
display.show(Image(board))
Step 3
dropping the counter
Step 3
# player1.py
# imports, radio setup, functions
def get_board_pixel(x, y, board):
pos = get_pos(x, y)
value = board[pos]
return value
Step 3
# player1.py
# imports, radio setup, functions
def get_board_pixel(x, y, board):
# code
def fall(x, y, board, colour):
set_board_pixel(x, y, board, colour)
show_board(board)
falling = True # while counter has not hit bottom or other counter
while falling:
if y >= 4 or get_board_pixel(x, y+1, board) != "0":
falling = False
else:
y += 1
board = set_board_pixel(x, y, board, colour) # moves counter down by one
board = set_board_pixel(x, y-1, board, 0) # removes counter from above
show_board(board)
sleep(500) # waits for 0.5 seconds so animation can be seen
return board
while True:
if button_a.is_pressed():
# moving counter code...
elif button_b.is_pressed():
board = fall(x, y, board, my_colour)
Step 4
taking it in turns to have a go
Step 4
# player1.py
# imports
# functions, setup
my_turn = True
my_colour = "9"
while True:
if my_turn:
if button_a.is_pressed():
# moving counter code...
elif button_b.is_pressed():
board = fall(x, y, board, my_colour)
my_turn = False
radio.send("YT")
else:
data = radio.receive()
if data:
if data == "YT":
my_turn = True
else:
board = data
display.show(Image(data))
# player2.py
# imports
# functions, setup
my_turn = False
my_colour = "4"
while True:
if my_turn:
if button_a.is_pressed():
# moving counter code...
elif button_b.is_pressed():
board = fall(x, y, board, my_colour)
my_turn = False
radio.send("YT")
else:
data = radio.receive()
if data:
if data == "YT":
my_turn = True
else:
board = data
display.show(Image(data))
my_turn = True
my_colour = "9"
my_turn = False
my_colour = "4"
Step 5
stop players placing counters on the top row
Step 5
# imports
# setup
# functons
# more setup
while True:
if my_turn:
if button_a.is_pressed():
x += 1
while get_board_pixel(x, 1, board) != "0":
x += 1 # move along.
if x > 5: # when your at the end go to the start
x = 0
row = ["0", "0", "0", "0", "0"]
row[x] = my_colour
for c, pixel_colour in enumerate(row): # counter acts as x co-ord
board = set_board_pixel(c, 0, board, pixel_colour)
# more code...
c = 0
for item in list:
print(c, item)
c += 1
for c, item in enumerate(list):
print(c, item)
Step 6
sending data to the raspberry pi
Step 6.0
# viewer.py
from microbit import *
import radio
radio.config(channel=86)
radio.on()
while True:
data = radio.receive()
if data:
if data != "YT":
display.show(Image(data))
print(data)
# display.py
import serial
from sense_hat import SenseHat
sense = SenseHat() # setup sense hat (RGB LED matrix)
# copied and adapted from
# projects.raspberrypi.org/en/projects/microbit-game-controller
PORT = "/dev/ttyACM0"
BAUD = 115200
s = serial.Serial(PORT)
s.baudrate = BAUD
s.parity = serial.PARITY_NONE
s.databits = serial.EIGHTBITS
s.stopbits = serial.STOPBITS_ONE
# copy ends
sense.show_letter("~") # lets me know that it has started
player1 = (0, 0, 255) # colours to be displayed for
player2 = (255, 0, 0) # each player
blank = (0, 0, 0) # for empty spaces
edge = (100, 100, 100) # and the edge of the board
# ^ because RPi Sense Hat LED matrix is > 5x5 on micro:bit
Step 6.1
# viewer.py
from microbit import *
import radio
radio.config(channel=86)
radio.on()
while True:
data = radio.receive()
if data:
if data != "YT":
display.show(Image(data))
print(data)
# display.py
# imports, setup
while True:
data = s.readline().decode("UTF-8").rstrip()
data_s = data.split(":")
formatted = [] # will store data to send to LED matrix
for i in range(8*2): # top two rows
formatted.append(edge)
for row in data_s:
formatted.append(edge) # first col is an edge
for c in row:
if c == "4":
formatted.append(player2)
if c == "9":
formatted.append(player1)
if c == "0":
formated.append(blank)
formatted.append(edge) # two thick edge on right side
formatted.append(edge)
for i in range(8):
formatted.append(edge)
sense.set_pixels(formated)
https://trinket.io/sense-hat
Step 7
win detection
Step 7.0
def detect_win(board):
"""detects is a player has won connect 3"""
rows = board.split(":")
rows = [
["00000"],
["00000"],
["00000"],
["00000"],
["00000"]
]
Formatting the board
Step 7.1
def detect_win(board):
# setup
"""detects win on x axis"""
for row in rows:
for i in range(3):
colour = row[i]
if colour != "0":
if row[i] == row[i+1] == row[i+2]:
return colour
rows = [
["00000"],
["00000"],
["00000"],
["00000"],
["00999"]
]
Detecting in in a row
Step 7.2
def detect_win(board):
# setup and x axis detection
""""detects win on y axis"""
for col in range(3):
for row in range(5):
colour = rows[col][row]
if colour != "0":
if rows[col][row] == rows[col+1][row] == rows[col+2][row]:
return colour
rows = [
["00000"],
["00000"],
["00009"],
["00009"],
["00009"]
]
Detecting a win in a column
Step 7.3
def detect_win(board):
# setup x axis and y axis detection
""""detects win on y = -x + c"""
for col in range(3):
for row in range(3):
colour = rows[col][row]
if colour != "0":
if rows[col][row] == rows[col+1][row+1] == rows[col+2][row+2]:
return colour
rows = [
["00000"],
["00000"],
["00900"],
["00090"],
["00009"]
]
Detecting a win in a y=-x+c diagonal
Step 7.4
def detect_win(board):
# setup, x axis, y axis and y=-x+c detection
""""detects win on y = x + c"""
for col in range(4, 1, -1):
for row in range(3):
colour = rows[col][row]
if colour != "0":
if rows[col][row] == rows[col-1][row+1] == rows[col-2][row+2]:
return colour
rows = [
["00000"],
["00000"],
["00009"],
["00090"],
["00900"]
]
Detecting a win in y=x+c diagonal
Step 7.5
def detect_win(board):
"""detects is a player has won connect 3"""
# [:-1] is needed as board ends with :
# causing an emtpy list at the end or rows
rows = board.split(":")[:-1]
"""detects win on x axis"""
# code
""""detects win on y axis"""
# code
"""detects win on y=-x+c"""
# code
"""detects win on y=x+c"""
# code
return None
Overview
Step 7.6
# player1.py & player2.py
# imports
# functions, setup
def detect_win(board):
# code
# setup
while True:
if my_turn:
# code
elif button_b.is_pressed():
board = fall(x, y, board, my_colour)
my_turn = False
winner = detect_win(board)
if winner == my_colour:
congradulate()
else:
radio.send("YT")
else:
data = radio.receive()
if data:
if data == "YT":
my_turn = True
elif data == "IW":
defeat()
# code...
Implementing win_detection
Step 7.7
# player1.py
# imports
import music
# functions, setup
def detect_win(board):
# code
def congradulate():
radio.send("IW")
display.show(Image.HAPPY)
music.play(music.BA_DING)
def defeat():
display.show(Image.SAD)
music.play(music.DADADADUM)
Congradulating the winner
Step 8
ending game after win/loss
Step 8
# player1.py & player2.py
# imports
# functions, setup
def detect_win(board):
# code
# setup
while True:
if my_turn:
# code
elif button_b.is_pressed():
board = fall(x, y, board, my_colour)
my_turn = False
winner = detect_win(board)
if winner == my_colour:
congradulate()
break
else:
radio.send("YT")
else:
data = radio.receive()
if data:
if data == "YT":
my_turn = True
elif data == "IW":
defeat()
break
# code...
That's it
so far
What have I learnt?
What have I learnt?
- Don't be confined by the specifications of a device, or what other people tell you a device can be/do.
- If I have an issue, search the web, and see if anyone else has solved your issue before / can help you.
- Python programmers are the nicest out there.
Thank you for listening
- project code is available at github.com/lukespademan/connect3
- @lukespademan
- github
- conference slack
- here until Sunday afternoon
micro:bits and raspberry pis
By Luke
micro:bits and raspberry pis
- 2,048