Tuesday 28 July 2015

Raspberry Pi AstroPi LED matrix animations


When we were investigating the AstroPi board,  I wrote a simple Pygame app for creating images for the LED matrix. Quite a few of the children started using this to produce singles frames to be amalgamated into an animation.  Assembling the animation in this way was good coding practice but some of their complicated compositions were several hundred frames long and manually putting them together was fairly tedious to say the least.

So I decided to enhance my code to add the functionality to create and save animations directly through the app.  This has involved adding some more buttons: 


But essentially it works in the same way as the original, just with the added ability to step back and forward through frames.

After some initial testing, the children suggested (demanded?) some extra features that I hadn't included (e.g. the ability to delete a frame and change the speed of playback).


 I also added a warning message if you try to quit without saving. Pygame's lack of a standard library of GUI tools (e.g. file browse etc) does add some limitations, so the file save/import is always via a file of the same name. Other than that though, it works pretty well.


Here are some examples of animations created using the app.

Space launch:


Tetris:


Union Flag to Raspberry Pi Logo


The code and full instructions is available on GitHub here.

Monday 20 July 2015

Writing our Astro Pi sweaty astronaut code

Since we heard that we'd won the Primary School AstroPi competition, my Codeclubbers have been working on turning the idea - trying to detect the presence of an astronaut by the increase in humidity that they cause - into a working program.

Design 

I was really pleased that of all the ideas that we submitted, this was the one that was chosen because I reckoned it would  be the easiest to split down into individual functions.  It seemed too complicated and time consuming to get every member of the club to write their own version in full, so by allocating individual elements to different children, I was able to try to match difficulty to ability.

To start off with, we generated a flow diagram of the various stages of the program, largely based on the pseudo-code that was submitted as part of our original paper entry to the competition. Pleasingly we found that this was fairly complete and most of the things we added were neat enhancements rather than modifications to the overall logic. Then we tried to identify which of these blocks would constitute a function in the code. 


This was a good opportunity to talk about writing functions, passing input arguments and returning output. The children had encountered these concepts in some of the other projects we'd worked on with the Pis, but  it was clear that not everyone grasped the ideas straight away. In particular, writing code that would would work on input values supplied by another function  was a common cause of confusion:

'Where will |the values come from?'
"They'll be the output from  Harry's code"
"But he hasn't written his code yet..."
"That's OK, just pretend he has and that it provides you with a list of values"
<Pause>
"But where will I get them from?"

Showing how to use fictitious test values when developing helped, but it wasn't until we started putting individual functions together that things started to click.

Teamwork

This approach  is, of course, good experience and representative of 'proper' coding jobs.  It was really good to see them working as a team, particularly when they got together in pairs (without any prompting from me) to solve problems that had an element of commonality. Taking the concept all the way from a design on paper to working code was a great project for a half-term and I could see that some of the children were really engaged with the process, thinking through the various steps and making suggestions as to ways things could be done.


There was a lot of focus on what messages the code would display, Partly I think this was because the children really like programming funky images and scrolling text for the LED matrix, but also because they felt that it was important that program communicated what it was doing. This helped them understand what was going on but also reflects (I think) a sensible and user-centric focus to UI design. Consequently our final code is full of display messages for the LEDs and also logs plenty of data to file too.

We even had a simulated (using an Astro Pi, naturally) Tim Peake to help with our test scenarios.


Testing

The children all excel at coming up with 'What if...?" questions. A lot of these were really great observations (e.g. "what if the humidity doesn't go back down again straight away?") and led to our code being more robust and also incorporating an element of self-tuning.

Throughout the whole thing I have been consistently impressed with the calm and confident way with which the children have approached the task. When we came to testing the first  full working version I was quite nervous but they seemed unsurprised that it pretty much worked first time. It was funny how, at very stages, one or other of the children would ask:

"Is our code really going to be running on the International Space Station?"

as though they thought it was some sort of trick or 'pretend' prize.

Weirdly, none of these positive benefits from working on a team project like this  had occurred to me before we started - I rather blundered into them. But now I'm thinking about how to accommodate something like this in future (including at CoderDojo) rather than stick with the standard single-person project that tends to be the default for this kind of thing.

Testing

I wanted them to think about the environment in which the code would be running - the ISS is obviously very different to the school Computing suite. So we had an idea to build a replica AstroPi flight case from Lego. Apart from being a bit of fun, this did highlight a couple of operational issues, for example the various messages displayed on the LED matrix were not all set at the same rotational angle. Obviously it is easier to spin through 180 degrees in zero-gravity, but it seems sensible to standardise the orientation.



It was also obvious that the flight buttons would be much easier to press in order for the astronauts to confirm their presence. Our original design just had the joystick used for this, but we all agreed that using the buttons would be a good enhancement.

So: Flight Case Mk2, incorporating working buttons connected to the GPIO pins just like the real one.  One of the useful outcomes of having children who have had (pretty much) nothing but Lego for birthday presents for the last 5 years is that we have a wide range of pieces. Combined with the superbly proportioned Pimoroni CakeBoard, and we've been able to add the flight button functionality into our prototype.




Not quite as elegant as the original - its need to be deeper to accommodate the breadboard and buttons. We've also had to make some adjustments to our code and as the end of term was fast approaching, we just adapted the existing functions rather than re-writing that entire 'wait for user input' chunk.

End of term

With only a small amount of after school tinkering (mainly to include the flight buttons)  by my sons, we managed to get the whole program finished by the end of term. The final session of the 2014-15 academic year was spent on some final testing and designing some animations to display when the program starts or when there is nothing else interesting happening (e.g. between measurements).

Of course our code isn't the most elegant or optimal software ever written. Despite my urging, some of the variables are not the most sensibly named (I haven't changed them: this is their code, not mine). But it works and manages to perform the intended task in a concise and efficient way. I think a lot of this is due to the excellent API for the AstroPi HAT, but the children's creativity and user-focused design methodology has also be a big contributory factor.

I'm incredibly proud of what the children have achieved and the positive attitude they've adopted to the whole competition. The best moments for me - apart from the phone call when we found out we'd won - were those light-bulb moments when I saw one of the children work out something they'd been trying to solve for a while.  Or when we'd be discussing the code and they'd tell me that was a better way to achieve something than the one I'd just suggested.

And there were quite a few of those...





Thursday 2 July 2015

Simon Says with Pimoroni ExplorerHat

The ExplorerHat was one of those impulse purchases from Pimoroni that I added to my basket when shopping for something else that I actually needed.  It has sat in my to-do box for a few weeks but recently I've found the time to have a play (I've been a bit busy coordinating my CodeClub's AstroPi project).

The ExplorerHat is a great test-bed for prototyping - having four buttons and LEDs all readily available means it's easy to knock together a test circuit without fiddling around  to wire up these simple and versatile components.

As a first project I thought I'd put together a Simon Says game.



The big LEDs flash in a sequence that gets longer and faster every time you successfully duplicate it by pressing the corresponding buttons on the ExplorerHat. If you get a sequence correct, all the lights flash in celebration!



Here's the wiring diagram:


And here's the (slightly rough and ready) code:

import explorerhat as eh
import time, random

target_seq = []
global user_seq 
user_seq = []
user_seq = []
leds_list = [1,2,3,4]


def wait_for_press(c,e):

if c > 4:
led = c - 5
else:
led = c - 1
if e == 'press':
eh.light[led].on()
else:
eh.light[led].off()
user_seq.append(led + 1)

print 'Starting. Copy the sequence.'
level = 0
GameOn = True
gap = 0.8
while GameOn:

user_seq = []

level+=1
count = 1
print 'Starting Level ' + str(level)
for i in  range(count):
led = random.choice(leds_list)
target_seq.append(led)

for seq_n in target_seq:
eh.output[seq_n-1].on()
time.sleep(gap)
eh.output[seq_n-1].off()
time.sleep(gap)

eh.touch.pressed(wait_for_press)
eh.touch.released(wait_for_press)
countdown = 20
waiting = True
while waiting:
if (len(user_seq) == len(target_seq)) or (countdown == 0):
if user_seq == target_seq:
waiting = False
#print user_seq, target_seq
time.sleep(0.5)
print 'Correct'
for x in range(0,4):
eh.output[x].on()
eh.light[x].on()
time.sleep(0.5)
for x in range(0,4):
eh.output[x].off()
eh.light[x].off()
gap = gap* 0.8
else:
waiting = False
GameOn = False
print 'Fail'
print 'You reached level:' + str(level) 

eh.pause()
time.sleep(1)
countdown-=1

time.sleep(2)