Skip to main content Skip to navigation

Python for coding a Raspberry Pi Pico microcontroller

A microcontroller is a small programmable computer into which we can plug sensors and outputs. It can control screens, motors, lights, etc. Inputs include buttons, keypads, IR sensors, temperature sensors. All of these components are cheap and easily available. Microcontrollers can run off a battery or a USB power source. Arduino has been the most popular example. The Raspberry Pi Pico is an even smaller alternative. The latest version includes wifi and bluetooth, meaning we can easily load data from the web, send data, or interconnect multiple devices. Microcontrollers are popular with robotics builders and museum designers. The Museum in a Box system uses Arduino. We can build sophisticated activities like the Story Museum story throne using them.

In this simple example we run a quiz using multiple choice questions loaded from a file. We could load them from a web page, or even using generative AI.

The actual program starts running with the code right at the end of the file.

questions = list()

score = 0

loadQuestionsFromCSV()

writeToLCD("Press any key to start", True)

#ASK THE FIRST QUESTION

askRandomQuestion()
Pi with keypad and screen

Setting things up

The first part of the program does the work of importing essential library files. There is one that allows us to take inputs from the keypad, one that allows us to output to the screen, another that is used to add pauses to the program (time), and one that allows us to generate a random number (random) so that questions can be chosen randomly. These last two can be used in any other type of Python program. We then have some code that sets up the keypad. I copied this from an example.

Unhelpfully, the screen doesn't auto-wrap. So I wrote a function that is used throughout to print messages on the screen. This includes an algorithm that checks if the message is more than 16 characters long, splits the message into two, and displays the second part on the second line of the display.

We then move on to the multiple choice questions code.

Loading the questions

We can have an unspecified number of multiple choice questions (they are loaded from a .csv file). They all have the same structure, with the complication that there are variable numbers of optional answers (usually 3, but doesn't have to be). So I defined a class of questions. This is a custom data structure, that can also have its own algorithms. To create the class we pass it three arguments: question (a string with the question in), answers (a string with the sequence of possible answers), and correct (an integer identifying which of the options is correct). As we are loading the data from a comma-separated text file, we can't use commas to separate the optional answers - that would confuse the loading code. So we use the | symbol. When we make a new question object, we have to break down the answers string into the sequence of answers, and make a List object of the answers. So the Class definition includes code that does that. It also gets the number of questions in the questions List, so we know when to stop asking them.

 self.answersList = answers.split("|")

self.answersCount = len(self.answersList) #this gets the number of questions in the list

We then need some code to load the csv file (test.csv), create a Question object for each row, and add them to a List of questions. I could have done this using the Pandas library, but in this case just used some neat code supplied by my assistant Alex.

def loadCSV(path):

csvdata = []

delim = ',' #the data is comma separated

with open(path,'r') as file:

for line in file:

csvdata.append(line.rstrip('\n').rstrip('\r').split(delim))

return csvdata
And this creates the List of Question objects:
def loadQuestionsFromCSV():

global questions

global questionCount #this is so we now how many questions there are to ask

global startingCount

questionCount = 0

data = loadCSV("./test.csv") #that's the file

for row in data:

question = mcq(row[1], row[2], row[0]) #creating a question object from the data

questions.append(question) #adding the new question to the lost of questions

questionCount = questionCount + 1

startingCount = questionCount

Asking the questions, checking the answers

And finally, we have a complicated function that randomly selects a question from the list. Here are some key lines of code selected (the whole thing is more complicated).
 #GET A RANDOM INDEX NUMBER WITHIN THE BOUNDS OF THE QUESTION SET

if questionCount > 0:

index = random.randint(0, questionCount - 1)

else:

index = 0

#GET THE QUESTION AT THAT INDEX

selectedQuestion = questions[index]
Displays it to the screen, followed by the options
writeToLCD(selectedQuestion.getQuestion(), True)
Gets the chosen answer from the keypad, checks it, reports if it is wrong or right, and counts the players score.

if selectedQuestion.isCorrect(matrix_keys[row][col]):

writeToLCD("Correct", True)

score = score + 1

else:

writeToLCD("Wrong", True)
This keeps looping until there are no questions left, and then the final score is reported.
if questionCount > 0:

askRandomQuestion()

else:

writeToLCD("Done. You scored " + str(score) + " out of " + str(startingCount) + "\n\n\n", True)
The code deals with one complication caused by the size of the screen, making things more complicated. We can't display the question and the options at the same time, so we have to page through them. The player has to press any key to move to the next lines of text before they get the chance to answer. We could use a bigger screen!

Let us know you agree to cookies