Lab 3: Multiple Inputs

The questions below are due on Sunday July 15, 2018; 11:59:00 AM.


You are not logged in.

If you are a current student, please Log In for full access to this page.

Music for this Lab

1) State Machines and Clicks

We're now going to build a simple LED ON/OFF controller. It will work using the following:

  • If the LED is off and you push the button (connected to Pin 5), the LED will turn on. Upon release of the button nothing happens.
  • If the LED is on and you push and then subsequently release the button, the LED will turn off. Upon release of the button nothing happens

The net result is a Push-On-Push-Off type of light controller like some light switches you might encounter! The functionality is shown in the video below. Watch the video closely.

This is harder to create than you might think since the code needs to work not off of just what the button is, but rather what the button is doing over time. To get you started, below is an "attempt" at doing what we want, but it doesn't work. Load this code and compare/contrast what it is doing to what the system actually needs to do based on the specification above. (Specifically we want only one action)

import RPi.GPIO as GPIO  #import library to use input/output pins
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
led_pin = 4
GPIO.setup(led_pin,GPIO.OUT)
input_pin = 5
GPIO.setup(input_pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def input_check(input):
    if input==1:
        GPIO.output(led_pin,1)
        print("Pushed")
    else:
        GPIO.output(led_pin,0)
        print("Unpushed")

while True:
    input_check(GPIO.input(input_pin))
    time.sleep(0.05)

In order to implement the Push-On-Push-Off functionality we want, we're going to need to add another conceptual tool to our toolbox. An important idea that can really help with handling problems is the idea of a state machine. To understand what a state machine is, we first need to understand what a state machine isn't...and that is a stateless machine. (note when we say "machine" we mean any sort of object (piece of code, robot, actual machine, etc...)

If you were to have a machine that always takes in a numerical input and immediately prints out three times that number regardless of what has happened in the past, we'd call this a "stateless" system. Basically the way it responds is based solely on its inputs and nothing else. For example...here's a stateless function in Python:

def slm(x):
    return 3*x

No matter how many times you call the function slm it will always do exactly the same operation. It lives in the moment with no concern for the past. If you were to do three simultaneous calls on slm of: slm(2), slm(2), slm(2), each time you'd get back 6.

Another stateless function is our function from earlier:

def input_check(input):
    if input==1:
        print("Pushed")
while True:
    input_check(GPIO.input(input_pin))
    time.sleep(0.05)

This function will print Pushed for as long as we are pushing it. How could we change this so that it only prints Pushed when the switch is first pushed? And then prints Released when the switch is first released (but not continuously afterwards)?

If you think about it, just reading the switch's currently value doesn't contain enough information for the code to decide when it is first pushed and first released. It needs something more, and that something more could be described as memory, history, or the more technical term: a system state. One way to model and design complex systems which act in ways more complex is as what's known as a state machine. It is important to realize that the term state machine refers to an abstract idea, namely systems which act based on current inputs and past inputs, and those past inputs are usually stored in some form (either individually or through some combination) in system states. The way these previous inputs influence the system's response manifests itself in the form of a "state" as in state of mind...as in New York State of Mind by Nas.

In order to accomplish such a functionality, state machines need to be able to remember...they need to have memory and ready access to what their states are and this memory generally takes the form of variables. As a result, when a state machine analyzes its inputs it can also use previous information to make an informed decision.

The following is a state machine that would accomplish what we described above, only printing stuff when the switch is first pushed or first released.

import RPi.GPIO as GPIO  #import library to use input/output pins
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
led_pin = 4
GPIO.setup(led_pin,GPIO.OUT)
input_pin = 5
GPIO.setup(input_pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

pushed = False #global variable to store what the state of the button is!

def input_check2(input)
    global pushed #tell function to refer to "global" pushed
    if input==1:
        if pushed==False: #means we see a push after not seeing one!
            pushed = True #change state so we remember it is now pushed
            print("Pushed")
    else: #(the button is not pushed)
        if pushed==True: # the button is not pushed but previously it was!
            pushed = False #change state so we remember it is now unpushed!
            print("Unpushed")

while True:
    input_check2(GPIO.input(input_pin))
    time.sleep(0.05)

Another state machine example is a human eating food. We put food in our mouth and eat, and then put food in our mouth and eat...but eventually our "state" changes and even if we were to put food into our mouth we might not want to eat any more or might throw up. Intelligence/Life can in some sense be characterized by the presence of state machines. A rock will always do the same thing when you yell at it...but a dog or a human will eventually tire of your anger and walk away or yell back or something.

1.1) Flow Diagrams

A good way to start thinking about (and ultimately designing) state machines is by sketching out how we want to respond inputs and putting it down in a flow diagram. An example one is shown below and is a graphical representation of how the input_check2 function operates from above. Different states of the system are in the blue boxes and different decision points are in the diamond shapes. One decision is made per time we run the function and in our code above, we are calling our function twenty times per second. See if you can map the decisions and states and how they are implemented in vivo in the code below.

A Flow Diagram of our Button State Machine

1.2) Finish the LED

So now let's return to our LED task. As a reminder, we wanted a system that does the following:

  • If the LED is off and you push and then subsequently release the button (connected to Pin 5), the LED will turn on.
  • If the LED is on and you push and then subsequently release the button, the LED will turn off

Use the state machine above (with printing) as the basis for a piece of code which will do this on-off functionality. Merge that code in with your Python file and get the functionality working! Save it for your deliverable video for lab!

2) Music Player

Your final goal for this lab is to make a music player. The system should allow a user to start playing a song as well as pause and unpause the playing of a song and cycle through a selection of at least three songs. The code should be able to run forever if desired.

  • If the system is playing a song (unpaused), it will pause the song upon pushing and releasing Button 1
  • If the system is paused, it will unpause (play from where it left off), upon pushing and releasing Button 1
  • Upon pushing and releasing Button 2, the system will skip to the next song in its queue (list of songs). If you are at the end of your songs, you need to restart in your list.

The code you need for this lab is going to take in all that you've learned so far. Whenever you start coding out a solution to a problem, often times the beginning is the worst since the problem can seem just so massive that you don't know where to start. What I usually do is try and sketch out an idea of my control flow...what paths will my code take as it runs...What ends up happening might not 100% match what you initially sketched out but at least this helps you get started. Here's the flow diagram I quickly sketched out when I was coming up with this lab.

The documentation for the pygame music player is found HERE, but you should be able to achieve all required functionality by studying the example use code below. An example of the necessary functionalities is included below. Move this file onto your computer and add two additional songs (From the internet...make them mp3's) below!

import pygame
import time

song1 = "/home/pi/Music/seeyouagain.mp3"
song2 = "" #you should add a song here
song3 = "" #you should add another song here

#Initialize the Mixer:
pygame.mixer.init()

#Load a Song:
pygame.mixer.music.load(song1)

#Start Playing the Song (always need to do after loading a song):
pygame.mixer.music.play()

#Wait for Ten Seconds:
time.sleep(10)

#Pause song:
pygame.mixer.music.pause()

#Pause for three seconds:
time.sleep(3)

#Unpause song (continue playing from where it left off)
#Note if you instead did music.play() here, the song would restart from beginning!
pygame.mixer.music.unpause()

#Load next song and start playing it (assumes song2 is defined):
pygame.mixer.music.load(song2)
pygame.mixer.music.play()

#Stop song being played 
#Different from pause() in that you lose position in song when you do this:
pygame.mixer.music.stop()

Some tips to keep in mind:

  • In order to start planning how to design this, first choose a few songs you like from a legal or quasi-legal download site (download MP3s), and place them on your Pi in the Music folder.
  • Break the assignment down into several parts:

    • First you need to get reliable readings for when the buttons have been pushed. Consider using the earlier button function from the previous section! In fact consider having two of those functions running in your loop so that you can get updated information on which button has been pressed recently.
    • After you can reliably get info on the two buttons use that information to determine how to drive the music player.
  • The pygame.mixer.music.pause() and pygame.mixer.music.unpause() are great ways to get the pause/unpause functionality we want in our system. However these methods will only work on a song that has already played. This means that if you change songs, you'll need to first call pygame.mixer.music.load() on the song name, followed by pygame.mixer.music.play() in order to have things working.

Build up a working system using state machines and code we've provided. Sketch out your design using a flow diagram. Ask for help! When it is all working, be sure to demo it in your Lab 2 video below. And then when all is good, zip up all files from this lab and upload them below!

A video of one student's functioning system is shown below for reference and to clear up any confusion about what is requred here:

3) Final Deliverable (Lab 3)

When you're all done, create a short video and upload to Youtube/Google Drive, showing the following behaviors:

  • Your ON-OFF LED controller from above
  • Your music player showing all functionalities! Including the ability to cycle repeatedly through your list of songs
  • Anything else you want to show.
Problem Status:
A Python Error Occurred:

Error on line 2 of Python tag (line 247 of source):
    kerberos = cs_user_info['username']

KeyError: 'username'

Enter the url for the video

Place all of your code into a folder and zip it up before uploading here:

 No file selected

Enter any comments you may want me to know about. For example, you can list non-obvious things you got working, things you're proud of, outstanding issues, etc.. Please hit submit on this question even if you don't have any comments.