Python Programming Tutorial: Getting Started with the Raspberry Pi – SparkFun Learn

Favorited

Favorite

27

Install the OS

You have a few options when it comes to interacting with the Raspberry Pi. The first and most common is to use it like you would a full desktop computer (just smaller). This involves connecting a keyboard, mouse, and monitor. With this setup, you are likely best served by installing Raspbian with Desktop, which gives you a full graphical user interface (GUI) to work with. This is the best option if you want an experience similar to working with other operating systems (OS), such as Windows, macOS, or other popular Linux flavors, like Ubuntu.

Raspberry Pi full desktop setup with monitor, keyboard, and mouse

Option 1: Use the Raspberry Pi like a full computer with keyboard, mouse, and monitor

The other option is to create a headless setup, which means you can skip the monitor, keyboard, and mouse. While this is the cheaper way to go, it means you’ll need to be open to performing all your actions in the command line interface. For this, you will want either Raspbian with Desktop or Raspbian Lite operating systems.

Raspberry Pi connected to laptop over Serial

Option 2: Configure the Raspberry Pi for “headless” operation where you interact with it from another computer

This guide will show you how to write and run Python programs that will work in both configurations.

Option 1: Full Desktop Setup

The Raspberry Pi 3 Starter Kit Hookup Guide offers a great walkthrough to setting up your Raspberry Pi with NOOBS (Raspberry Pi’s easy-to-use graphical OS installer).

From here on out, all instructions that are unique to the full desktop setup will be highlighted in blue.

Raspberry Pi 3 Starter Kit Hookup Guide

April 11, 2016

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Favorited

Favorite

13

Option 2: Headless Pi

If you want to skip the keyboard, mouse, and monitor, you can install Raspbian Lite. This will allow you to get a terminal into your Pi using SSH or Serial on another computer. The Headless Raspberry Pi Setup walks you through setting up your Raspberry Pi without a graphical interface.

Instructions in this tutorial that are unique to the headless setup will be highlighted in yellow.

Headless Raspberry Pi Setup

April 23, 2018

Configure a Raspberry Pi without a keyboard, mouse, or monitor.

Favorited

Favorite

17

If you have the Raspberry Pi Starter Kit, you can attach the Pi Wedge to the Pi over the provided ribbon cable, and connect the FTDI Breakout board to the Pi Wedge. From here, connect a USB cable between your computer and the FTDI Breakout board. This will allow you to open a Serial terminal to your Raspberry Pi, as covered in the Serial Terminal section of the Headless Pi tutorial.

Fully assembled Raspberry Pi Starter kit with FTDI serial-to-USB breakout

Configure Your Pi

Regardless of whether you are using the full desktop or a headless setup, you will need to perform some basic configuration steps on your new Raspberry Pi installation. These steps can be easily performs from a terminal (a text input/output environment).

Full Desktop: You should be automatically logged into the X windows manager (otherwise known as the desktop). To open a terminal, simply click on the Terminal icon on the top left of the desktop. You should be immediately presented with a command prompt in a terminal window.

Raspbian desktop

Headless: With a headless setup, everything you do will be through a terminal. When you connect to your Pi through Serial or SSH, you will be presented with a login prompt on the terminal. Enter the default credentials:

  • Username: pi
  • Password: raspberry

You will be presented with a command prompt.

Serial terminal showing command prompt for Raspberry Pi

Run the Config Tool

From your command prompt, enter the command:

language:bash
sudo raspi-config

If asked to enter a password, type out the default password: raspberry.

You will be given several options on how to configure your Raspberry Pi.

Raspberry Pi raspi-config tool

  • Use the arrow keys to select 1 Change User Password and follow the on-screen prompts to change your default password.

Warning: It is strongly recommended that you change your password. If you connect your Pi to a network and leave the password as ‘raspberry’, anyone with access to that network will be able to easily get into your Pi.

  • Next, select 2 Network Options
  • In the following screen, select N2 Wi-fi, and follow the prompts to connect your Pi to a local WiFi network (assuming you have one available).

Raspberry Pi network options

Select 4 Localisation Options to bring up the keyboard and time zone options.

Raspberry Pi raspi-config screen

  • Select I1 Change Local
  • Scroll down to highlight en_GB.UTF-8 UTF-8, and press the spacebar to deselect it (the asterisk ‘*’ will disappear)
  • Scroll to find your language/country and press space to select it (an asterisk ‘*’ will appear next to your selection)
  • If you live in Great Britain, you can just leave en_GB.UTF-8 UTF-8 selected
  • If you live in the United States, you will probably want to select en_US.UTF-8 UTF-8.

Raspberry Pi raspi-config screen

  • Press enter to save the changes
  • On the next screen, highlight your chosen localization option (e.g. en_US.UTF-8 if you’re in the United States) and press enter.

Raspberry Pi raspi-config screen

  • Go back into the 4 Localisations Options, and select I2 Change Timezone
  • Follow the prompts to select your timezone.
  • Back in 4 Localisations Options, select I3 Change Keyboard Layout
  • Choose your preferred layout (the default Generic 105-key (Intl) PC seems to work well in most situations)
  • On the next screen, select the layout for your language/country
  • If you live in Great Britain, you can leave English (UK) selected. Otherwise, select Other, press enter, and follow the prompts to select your language/country. If you live in the United States, select English (US), and on the next screen, scroll up to highlight English (US). Press enter.

Raspberry Pi raspi-config screen

  • Leave The default for the keyboard layout selected, and press enter
  • Once again, leave the default No compose key selected, and press enter
  • Leave No selected when asked about using Control+Alt+Backspace, and press enter
  • After a few moments, you will be dropped back into the main Configuration Tool menu.

Select 5 Interfacing Options.

Raspberry Pi raspi-config screen

  • Feel free to enable the Camera interface and SSH if you think you’ll need them
  • Select SPI, select yes on the following screen, press enter
  • Repeat for I2C
  • Repeat for Serial

Back in the main screen, select 7 Advanced Options.

Raspberry Pi raspi-config screen

  • Select A1 Expand Filesystem, and press enter
  • Go back into 7 Advanced Options, select A4 Audio, highlight 1 Force 3.5mm (‘headphone’) jack, and press enter
  • Use the right arrow key to select Finish, and press enter. If asked to reboot, select Yes and press enter. Wait while your Raspberry Pi restarts.

If you are using a Serial or SSH terminal, log back in using the username pi and the password you created earlier.

Use Python 3

By default, Raspbian (Stretch version April 2018 and earlier) uses Python 2. However, versions 2 and 3 come installed by default. We just have to make 1 minor change so that the Pi uses Python 3 whenever we type python into a terminal.

In a terminal window, enter the following command:

language:bash
python --version

You should see which version is being used by default. For example, you might see Python 2.7.13. If you see that your OS is using Python 2 by default, you’ll need to change it to use the Python 3 installation. We want to this so that Python 3 is used every time we log in.

Enter the command:

language:bash
nano ~/.bashrc

.bashrc is a file that resides in the user’s home directory (the user pi in this case). The file acts as a shell script that is run each time that specific user opens a terminal (or logs in over SSH, Serial, etc.). It can help to customize the user environment, and you will likely see a number of other commands already in there.

Scroll down to the bottom, and add the following command to the file:

language:bash
alias python='/usr/bin/python3'

Modifying .bashrc to use Python 3 by default

Exit out of nano by pressing ctrl+x, press the y key when prompted if you want to save the file, and press the enter key.

Instead of logging out and logging back in again to run the new command, you can simply run the contents of the .bashrc script by entering:

language:bash
source ~/.bashrc

Now, check the version of Python again:

language:bash
python --version

You should see some version of Python 3 being used.

Checking Python version on the Raspberry Pi

Install pip

Full Desktop: If you are using the full desktop version of Raspbian, you should have pip already installed.

Headless: If you are using Raspbian Lite, the Python package manager, pip, does not come pre-installed. As a result, you will need to install it with the commands:

language:bash
sudo apt-get update
sudo apt-get install python3-pip

Press y when prompted.

Note that to use pip for Python 3, you will need to use the command pip3. However, we can modify the .bashrc file to use pip instead of pip3, as the rest of the tutorial will show examples using pip:

language:bash
nano ~/.bashrc

Scroll down to the bottom, and add the following command to the file:

language:bash
alias pip=pip3

Modify .bashrc to use the pip command

Exit out of nano with ctrl+x, press y and enter. Run the .bashrc script with:

language:bash
source ~/.bashrc

You should now be able to install Python packages using the pip command.

Hello, World!

One of the coolest features of Python is that it is an interpreted language (OK, in reality, Python scripts are first compiled to some bytecode, and that bytecode is interpreted). This means that we don’t need to run a separate compile step (i.e. translate our program into machine code) in order to run our program. In fact, we can even run the interpreter in what’s known as interactive mode. This will allow us to test out commands one line at a time!

To start, we’ll tell Python to print the phrase, “Hello, World!” to the terminal. We’ll do this first from the interpreter and then we’ll create a file and run it as a program. This will show you two of the main ways to interact with Python.

If you are curious about where the phrase “Hello, World!” comes from, this Wikipedia article gives a brief yet fascinating history.

Getting Started with the Interpreter

From a terminal, enter the following commend to start the Python interpreter:

language:bash
python

You should be presented with a different command prompt, consisting of 3 greater-than signs >>>.

Type the following command:

language:bash
print("Hello, World!")

Once you press enter, you should see the phrase Hello, World! repeated back to you.

Running Python on a Raspberry Pi from a serial terminal

And that’s it! You just ran your first Python program!

Exit out of the interpreter by entering:

language:bash
exit()

Running a Python Program from a File

You can individually enter and run commands one line at a time in the Python interpreter, which is incredibly useful for trying out different commands (or using it as a calculator!). Often, you will want to save your commands together in one or more files so that you can run them all at once.

The simplest way to do this is to create a file from the terminal, although you are welcome to use the Raspbian graphical editor, Leafpad, as well (found under Accessories > Text Editor when you click on the Raspberry Pi icon in the top left).

Still in a terminal, enter the command:

language:bash
nano hello.py

This creates a file named hello.py in your home directory (/home/pi) and starts editing it with the nano program.

In this file, enter the following on the first line:

language:bash
print("Hello, World!")

Writing a Python program on a Raspberry Pi

Save and exit (ctrl+x followed by y and then enter). Back in the Linux command prompt, enter the command:

language:bash
python hello.py

This should run the code found in the file hello.py. In our case, you should see the iconic phrase Hello, World! printed out in the console.

Running a Python program on a Raspberry Pi

Note: In case you were wondering, I am clearing my terminal between screenshots with the clear command.

To summarize what we just did, you can use the python command on its own to begin an interactive interpreter session that allows you to type commands in real time. If you specify a file, such as python <FILE>.py, the Python interpreter will run the commands found in the file without giving you an interactive session.

Note that the filename suffix .py is not required for the interpreter to run the code found inside. However, it can be very helpful to keep your files organized so that when you see a file ending in .py, you will know that it contains Python code. The .py suffix is also necessary when making modules, which we’ll cover later.

Development Environments

The simplest way to create Python programs is to write your code in a text editor (e.g. nano, vim, emacs, Midnight Commander, Leafpad, etc.), save it, and then run it from the terminal with the command python <FILE>.py. You are welcome to continue working through this guide using a text editor and command line.

Some users prefer to use an integrated development environment (IDE) when developing code. IDEs offer a number of benefits including syntax highlighting, code completion, one-click running, debugging hints, etc. However, most IDEs require a graphical interface to use, which means you will need to be on the full desktop version of Raspbian.

Note: Out of the box, Raspbian comes with three Python IDEs: IDLE, Geany, and Thonny. I show a brief introduction to each below, and you are welcome to use them or any other text editor or IDE you so choose.

IDLE

IDLE is the default Python editor that has been available on Raspbian for many generations. The good news is that it has a built-in interpreter, which allows you to run commands one at a time to test code. The bad news is that it doesn’t show line numbers, and it only works with Python (but you’re only here for Python anyway, right?).

Open IDLE by selecting the Raspberry Pi logo in the top-left, and click Programming > Python 3 (IDLE). You should be presented with the Python interactive interpreter.

IDLE Python command prompt

To write a program, go to File > New File. Enter in your code.

Writing a Python program in IDLE

Click File > Save As… to save your code to a Python file (don’t forget the .py suffix!). Click Run > Run Module to run your program.

Running a Python program in IDLE

Geany

Geany is a great, beginner-friendly IDE that works with many different languages. However, it does not start up with a Python interactive interpreter. You can open Geany up by click on the Raspberry Pi logo in the top-left, and selecting Programming > Geany. Write your code in the file editor pane.

Writing a Python program in Geany

Save your code, making sure the filename ends with .py.

By default, Geany will attempt to open a new window to show the output of your code, which may or may not work on the Raspberry Pi. We can change it to run in the Terminal pane. Click Edit > Preferences. Select the Terminal tab and click to enable Execute programs in the VTE. Press enter to save and close the Preferences window.

Execute programs in the terminal in Geany

Click Build > Execute (or click the paper airplane icon) to run your code. You should see the output of your program appear in the Terminal pane of Geany.

Running a program in Geany

Thonny

Finally, Thonny is another great, easy-to-use IDE that comes pre-loaded on Raspbian. It focuses on Python and has an interactive environment when you load the program. Start Thonny by clicking on the Raspberry Pi icon followed by Programming > Thonny Python IDE.

Thonny IDE on the Raspberry Pi

Write your program in the top pane, click File > Save as… to save it, and click Run > Run current script to execute the program. Output will appear in the bottom interpreter pane.

Running a Python program on Thonny

Opinion: If you are just starting your journey in programming, we recommend Thonny for a graphical IDE and using nano if you are using a headless Raspberry Pi setup.

Experiment 1: Digital Input and Output

In the embedded world, the first thing many developers like to do is blink an LED. In a sense, it is the “Hello, World!” of embedded electronics. It proves that we can run code and control some hardware (with immediate, and often amusing, results). In this section, we’ll start by blinking an LED, and we’ll take it a step further by also responding to a push button.

Recommended Reading

  • Python (RPi.GPIO) API – Overview of the RPi.GPIO module, which we’ll be using throughout this tutorial to control hardware
  • What is Electricity? – Covers the basics of how electricity works
  • What is a Circuit? – Talks about how electricity moves through a circuit
  • Polarity – Shows why we need to put the LED in the circuit a certain way
  • How to Use a Breadboard – Breadboards are great for prototyping, and we use them in this tutorial

Raspberry Pi Pinout

One of the things that makes the Raspberry Pi better for learning electronics than most other computers is its ability to control the voltage on several of its easily accessible pins. If you hold your Pi facing up in portrait mode (as shown in the photo below), on the right side, you will see a header with 40 pins. This header contains outputs for 3.3V, 5V, Ground, and lots of General Purpose Input/Output (GPIO) pins!

Raspberry Pi GPIO Header

Note that pin 1 is on the top left of the header, as shown in the photo. With pin 1 in this position, we can see what each of the pins is used for:

Raspberry Pi 3 GPIO pinout

Hardware Connections

You can connect the Raspberry Pi to the LED and button directly, or you can go through the SparkFun Pi Wedge to make the connections easier on a breadboard. The important thing is to note that we are using the GPIO numbers in our code (listed as Gx on the Pi Wedge, where x is the GPIO number). These GPIO numbers are shown in the yellow boxes in the GPIO Pinout diagram above.

  • Connect GPIO12 (pin 32) to the 330Ω resistor, and the resistor to the LED
  • Connect GPIO4 (pin 7) to the button
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram

Having trouble seeing the diagrams? Click on them to see the full-size version!

If you have a Pi Wedge, it can make connecting to external hardware on a breadboard easier. If you don’t, you can still connect directly to the Raspberry Pi with jumper wires.

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect LED and button

Connecting directly to the Raspberry Pi:

Raspberry Pi Fritzing diagram to connect LED and button

Note: It matters how you plug in your LED! Current can only flow in one direction through an LED, so pay careful attention to the leads. The long lead on the LED should be connected on the same row as the 330Ω resistor.

LED polarity diagram

Note: Buttons can be a little weird, if it’s the first time you’ve used them. The pins across from each other are always connected, whereas the pins on the same side are only connected when you push the button.

How a push button is configured on the inside Note: If you are using the

If you are using the full-size breadboard , the power rails are divided in the middle. This means that to get power to the whole power row, you will need to connect the two halves. See the picture below to see how to use jumper wires to connect the halves of the power rows.

Connect power rows on a full-size breadboard

Code Part 1: Blinking an LED

Depending on your version of Raspbian, you may or may not have to install the RPi.GPIO package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

language:bash
pip install rpi.gpio

In a new file, enter the following code:

language:python
import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Suppress warnings
GPIO.setwarnings(False)

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Blink forever
while True:
    GPIO.output(led_pin, GPIO.HIGH) # Turn LED on
    time.sleep(1)                   # Delay for 1 second
    GPIO.output(led_pin, GPIO.LOW)  # Turn LED off
    time.sleep(1)                   # Delay for 1 second

Save the file (I named my file blink.py). Run the code from the terminal by entering:

language:bash
python blink.py

You should see your LED begin to blink on and off every second:

LED connected to Raspberry Pi blinking

Once you’ve gotten bored of watching the LED, end the program by pressing ctrl + c.

Troubleshooting: If you see the message “ModuleNotFoundError: No module named ‘rpi'” you will need to install the RPi.GPIO package by entering pip install RPi.GPIO in a terminal.

Code to Note:

To control hardware from the Raspberry Pi, we rely on the RPi.GPIO module. This module (likely known as a “library” in other languages) is specifically designed to help us toggle pins and talk to other pieces of hardware. Lucky for us, it comes pre-packaged with Raspbian!

In the first two lines, you see that we imported modules, but we added a few things onto those imports. First up, we used the keyword as:

language:python
import RPi.GPIO as GPIO

RPi.GPIO is the name of the module. By saying as GPIO, we change how we want to refer to that module in the rest of the program. This allows us to type

language:python
GPIO.output(led_pin, GPIO.HIGH)

instead of the much longer

language:python
RPi.GPIO.output(led_pin, RPi.GPIO.HIGH)

While it’s generally not a good idea to disable warnings while coding, we added the following line:

language:python
GPIO.setwarnings(False)

Without it, you’ll get a warning from the interpreter when you try to run the blink program again:

language:python
blink.py:14: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(led_pin, GPIO.OUT)

This is because we did not shut down the GPIO 12 pin nicely when we exited the program. To do this, we would want to add a GPIO.cleanup() line at the end of our program. However, because we wrote our program to run forever, we have to interrupt the program to stop it (and a call to cleanup() would never occur). For the time being, it’s enough to just ignore the warnings.

Challenge: Change the program to make the LED blink like a heartbeat: 2 quick flashes in succession and then a longer delay.

import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Suppress warnings
GPIO.setwarnings(False)

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Blink forever
while True:
    GPIO.output(led_pin, GPIO.HIGH)
    time.sleep(0.2)
    GPIO.output(led_pin, GPIO.LOW)
    time.sleep(0.2)
    GPIO.output(led_pin, GPIO.HIGH)
    time.sleep(0.2)
    GPIO.output(led_pin, GPIO.LOW)
    time.sleep(1)

Code Part 2: Fading an LED with PWM

We’ve seen how to turn an LED on and off, but how do we control its brightness levels? An LED’s brightness is determined by controlling the amount of current flowing through it, but that requires a lot more hardware components. A simple trick we can do is to flash the LED faster than the eye can see!

By controlling the amount of time the LED is on versus off, we can change its perceived brightness. This is known as pulse width modulation (PWM). We have two separate PWM channels for our use: PWM0 and PWM1. We can output a PWM signal on PWM0, which will show up on GPIO12 and GPIO18. Additionally, PWM1 controls the signal for GPIO13 and GPIO19.

Copy the following code into a file (e.g. pwm.py):

language:python
import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pwm object with 50 Hz and 0% duty cycle
pwm = GPIO.PWM(led_pin, 50)
pwm.start(0)

# Set PWM duty cycle to 50%, wait, then to 90%
pwm.ChangeDutyCycle(50)
time.sleep(2)
pwm.ChangeDutyCycle(90)
time.sleep(2)

# Stop, cleanup, and exit
pwm.stop()
GPIO.cleanup()

Run it (e.g. python pwm.py), and you should see the LED start dim, wait 2 seconds, grow brighter, wait another 2 seconds, and then turn off before exiting the program.

Dim LED connected to Raspberry Pi

Code to Note:

In the first part, we use the .output() function of the GPIO module to toggle the LED. Here, we create PWM object and store it in the variable pwm. We do this with the line:

language:python
pwm = GPIO.PWM(led_pin, 50)

From there, we can control the PWM by calling methods within that object. For example, we change the brightness by calling:

language:python
pwm.ChangeDutyCycle(t)

where t is some number between 0-100 (0 being off and 100 being always on). Putting in the number 50 would mean that the LED is on half the time and off the other half the time (it’s just toggling so fast that you can’t see it!).

Also, we left out the GPIO.setwarnings() call, since we can actually call GPIO.cleanup() at the end of our program! If you try to run the PWM code twice, you should not see any warnings.

Challenge: Make the LED slowly fade from off to fully bright over the course of about 2 seconds. Once it has reached maximum brightness, the LED should turn off and repeat the fading process again. Have the LED fade on over and over again forever.

import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pwm object with 50 Hz and 0% duty cycle
pwm = GPIO.PWM(led_pin, 50)
pwm.start(0)

# Have the LED slowly fade up, turn off, and repeat
while True:
    for brightness in range(0, 101):
        pwm.ChangeDutyCycle(brightness)
        time.sleep(0.02)

Code Part 3: Button Input

Let’s add some user input! Save the following to a file (such as button.py).

language:python
import time
import RPi.GPIO as GPIO

# Pins definitions
btn_pin = 4
led_pin = 12

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)
GPIO.setup(led_pin, GPIO.OUT)

# If button is pushed, light up LED
try:
    while True:
        if GPIO.input(btn_pin):
            GPIO.output(led_pin, GPIO.LOW)
        else:
            GPIO.output(led_pin, GPIO.HIGH)

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Run it the code (python button.py). Now, when you press the button, the LED should turn on.

Pushing button to turn on LED connected to Raspberry Pi

Code to Note:

The first odd thing you might notice is the try: and finally: statements. These are part of the error and exception handling abilities in Python (you can read more about them in the Exceptions chapter in Byte of Python).

If we press ctrl + x while the program is inside the while True: loop, an exception will be thrown. We don’t care to do anything with that exception (hence why you don’t see an except block, like you might have read about in “exception handling”). Regardless of whatever the exception is, we do want to call our GPIO.cleaup() function. That way, we can close down the GPIO and not have to worry about any more errors!

The other odd thing you might see is that if GPIO.input(btn_pin) is True (which means the pin is logic high, or 3.3V), we turn the LED off. Wait, what?

In our circuit, our button has a pull-up resistor connecting one of the pins to a constant 3.3V. This means that in its default state (not pressed), the pin connected to the button is 3.3V. When we press the button, the pin is connected to ground (through the button’s internal contacts), and the pin becomes logic low (0V).

As a result, when the button is not pressed, we get logic high (GPIO.input() returns True), and when the button is pressed, we get logic low (GPIO.input() returns False).

Challenge: Write a program so that whenever you press the button, a variable is incremented by one and is printed to the screen. This should work as a simple button counter. Start at 0, and each time you press the button, it counts up on the screen.

Incrementing a counter whenever a button is pressed

import time
import RPi.GPIO as GPIO

# Pins definitions
btn_pin = 4

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)

# Our counter
counter = 0

# Remember the current and previous button states
current_state = True
prev_state = True

# If button is pushed, light up LED
try:
    while True:
        current_state = GPIO.input(btn_pin)
        if (current_state == False) and (prev_state == True):
            counter = counter + 1
            print(counter)
        prev_state = current_state

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Experiment 2: Play Sounds

Downloading audio clips and playing them on a Raspberry Pi is quite simple. We will use the command line to download a .wav file, adjust the audio, and test playing the file. Then, we’ll write a Python script to play that file whenever we press a button!

Recommended Reading

  • amixer – We will be using the amixer Linux tool to adjust the volume on our Raspberry Pi
  • Pygame – Pygame is a framework that is used for making simple games in Python. Raspbian comes pre-loaded with Pygame, which means we can use it to play sounds.

Hardware Connections

Good news, everyone! We will be using the same circuit from the previous experiment.

  • Connect GPIO12 (pin 32) to the 330Ω resistor, and the resistor to the LED
  • Connect GPIO4 (pin 7) to the button
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect LED and button

Connecting directly to the Raspberry Pi:

Raspberry Pi Fritzing diagram to connect LED and button

You will also need to plug an external speaker (or a set of headphones) into the Pi’s headphone jack. If you are using the Hamburger Mini Speaker, make sure it is charged and turned on.

Speaker plugged into Raspberry Pi

Configure Audio

Before we write code, we need to configure the audio from the command line. Open a terminal (if you are using Raspbian with a desktop).

Note: Make sure you have selected the 3.5mm (‘headphone’) jack as your output audio device from the sudo rasp-config advanced options. Refer to the

Make sure you have selected theas your output audio device from theadvanced options. Refer to the Configure Your Pi section to see how to do this.

From a terminal, enter the following commands:

language:bash
amixer set PCM unmute
amixer set PCM 100%

Verify that your audio is on and up by entering the command:

language:bash
amixer

At the end of the printout, you should see Mono: Playback 400 [100%] [4.00dB] [on].

Configure audio output on Raspberry Pi

Download a free sound clip (we’ll go with some applause, because we’re awesome):

language:bash
wget http://www.pacdv.com/sounds/people_sound_effects/applause-1.wav

Test playing this sound with:

language:bash
aplay applause-1.wav

You should hear some nice cheering and clapping out of your speaker (or headphones).

Code: Push Button, Get Sound

Depending on your version of Raspbian, you may or may not have to install the pygame package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

language:bash
sudo apt-get update
sudo apt-get install python3-pygame

In a new file, enter the following code:

language:python
import time
import RPi.GPIO as GPIO
from pygame import mixer

# Pins definitions
btn_pin = 4

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)

# Initialize pygame mixer
mixer.init()

# Remember the current and previous button states
current_state = True
prev_state = True

# Load the sounds
sound = mixer.Sound('applause-1.wav')

# If button is pushed, light up LED
try:
    while True:
        current_state = GPIO.input(btn_pin)
        if (current_state == False) and (prev_state == True):
            sound.play()
        prev_state = current_state

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Save the file (e.g. applause.py), and start the program with python applause.py. Push the button, and you should hear some congratulatory sounds!

Pushing button to play sound

Troubleshooting: If you see the message “ModuleNotFoundError: No module named ‘pygame'” you will need to install the pygame package by entering pip install pygame in a terminal.

Code to Note:

To play sounds, we are using the pygame package. A package in Python is a collection of modules grouped together. Lucky for us, pygame comes pre-installed with Python on Raspbian. To use it, we just need to use from pygame in our code, and we can specify which module we want to use by saying import after it. For example, we might say:

language:python
from pygame import mixer

This says that we want to import the mixer module from the pygame package. Later in our code, we can use the mixer module to create a Sound object with:

language:python
sound = mixer.Sound('applause-1.wav`)

Our downloaded file, applause-1.wav is used to create a Sound object, which we store in the sound variable. We can call the .play() method in our Sound object to start playing the .wav file.

language:python
sound.play()

Challenge: You might have noticed that if you press the button again while the sound is playing, an new sound will start that overlaps the first clip. Let’s fix this! Change the code so that when you press the button while the sound is playing, the sound stops. When you press it again, the sound clip starts over again. Also, because we can, have the LED light up while the sound is playing. Hint: it might help to look at the pygame.mixer methods for determining if sound is being played (or “mixed”) and how to stop a sound.

import time
import RPi.GPIO as GPIO
from pygame import mixer

# Pins definitions
btn_pin = 4
led_pin = 12

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pygame mixer
mixer.init()

# Remember the current and previous button states
current_state = True
prev_state = True

# Load the sounds
sound = mixer.Sound('applause-1.wav')

# If button is pushed, light up LED
try:
    while True:

        # If button is pressed, turn on LED and play sound
        current_state = GPIO.input(btn_pin)
        if (current_state == False) and (prev_state == True):
            if mixer.get_busy():
                sound.stop()
            else:
                GPIO.output(led_pin, GPIO.HIGH)
                sound.play()

        # Only turn off LED if sound has stopped playing
        if mixer.get_busy() == False:
            GPIO.output(led_pin, GPIO.LOW)

        # Save state of switch to use in next iteration of the loop
        prev_state = current_state

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Experiment 3: SPI and Analog Input

Many sensors out there use an analog voltage to convey their measurement data. For example, photocells change their resistance depending on how much light is falling on the sensor. By using a voltage divider in our circuit, we can effectively measure the amount of ambient light by measuring a voltage.

The bad news is that our Raspberry Pi does not come with any way to measure an analog voltage. To do that, we’ll need to rely on a separate piece of circuitry: an analog-to-digital converter (ADC). Specifically, we’ll be using the Microchip MCP3002, which is a niftly little chip that can measure up to 2 analog voltages on separate channels and report their values over the Serial Peripheral Interface (SPI) interface.

We’ll use the built-in spidev module in Python to send commands and read replies on the SPI bus.

Recommended Reading

  • Analog vs. Digital – What is the difference, and why do we need to care about them for this example?
  • Voltage Dividers – Explains how to set up, use, and calculate the values in a voltage divider
  • Serial Peripheral Interface (SPI) – Read this if you would like to learn how SPI works on a low level
  • Binary – We’ll be working directly in binary in this section

Hardware Connections

Refer to the Raspberry Pi Pinout section in the previous example if you would like to see what pins and GPIO labels belong to each of these connections.

  • Connect MOSI (GPIO10, pin 19) to Din on the MCP3002
  • Connect MISO (GPIO9, pin 21) to Dout on the MCP3002
  • Connect SCLK (GPIO11, pin 23) to CLK on the MCP3002
  • Connect CE0 (GPIO8, pin 24) to CS/SHDN on the MCP3002
  • Connect the photocell voltage divider to CH0 on the MCP3002
  • Connect the potentiometer’s middle pin to CH1 on the MCP3002
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect an MCP3002

Connecting directly to the Raspberry Pi:

Raspberry Pi with MCP3002 Fritzing diagram

Note: Pay close attention to how the MCP3002 is oriented. You should see a notch in the top surface of the chip. With the notch oriented up, pin 1 is down and to the left of the notch.

MCP3002 DIP pinout

Pinout from the MCP3002 datasheet

Code: Reading Analog Voltage

Depending on your version of Raspbian, you may or may not have to install the spidev package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

language:bash
pip install spidev

In a new file, enter the following code:

language:python
import time
import spidev

spi_ch = 0

# Enable SPI
spi = spidev.SpiDev(0, spi_ch)
spi.max_speed_hz = 1200000

def read_adc(adc_ch, vref = 3.3):

    # Make sure ADC channel is 0 or 1
    if adc_ch != 0:
        adc_ch = 1

    # Construct SPI message
    #  First bit (Start): Logic high (1)
    #  Second bit (SGL/DIFF): 1 to select single mode
    #  Third bit (ODD/SIGN): Select channel (0 or 1)
    #  Fourth bit (MSFB): 0 for LSB first
    #  Next 12 bits: 0 (don't care)
    msg = 0b11
    msg = ((msg << 1) + adc_ch) << 5
    msg = [msg, 0b00000000]
    reply = spi.xfer2(msg)

    # Construct single integer out of the reply (2 bytes)
    adc = 0
    for n in reply:
        adc = (adc << 8) + n

    # Last bit (0) is not part of ADC value, shift to remove it
    adc = adc >> 1

    # Calculate voltage form ADC value
    voltage = (vref * adc) / 1024

    return voltage

# Report the channel 0 and channel 1 voltages to the terminal
try:
    while True:
        adc_0 = read_adc(0)
        adc_1 = read_adc(1)
        print("Ch 0:", round(adc_0, 2), "V Ch 1:", round(adc_1, 2), "V")
        time.sleep(0.2)

finally:
    spi.close()
    GPIO.cleanup()

Save the file (e.g. adc.py), and run it with Python:

language:bash
python adc.py

You should be able to cover the photocell and see the Ch 0 voltage change. Adjust the knob on the potentiometer to see the Ch 1 voltage change.

Reading analog voltages with Python on a Raspberry Pi

Code to Note:

We are using SPI channel 0 on the Raspberry Pi when we initialize the SpiDev object:

language:python
spi_ch = 0
spi = spidev.SpiDev(0, spi_ch)

Channel 0 corresponds to using CE0 (chip enable 0) on the Pi’s pins. If you wanted to use another device on the SPI bus, you would need to connect it to CE1 and use SpiDev channel 1 as well.

We construct our SPI message by manipulating individual bits. We start with binary 11 (which is the decimal number 3) by using the prefix ‘0b’:

language:python
msg = 0b11

If you look at section 5 in the MCP3002 datasheet, you will see that we need to send a 1 to start transmission, followed by another 1 to denote that we want “single ended mode.” After that, we select our channel with a 0 (for channel 0) or a 1 (for channel 1). Then, we send a 0 to show that we want data returned to us with the least significant bit (LSB) sent first.

language:python
msg = ((msg << 1) + adc_ch) << 5

Finally, we send another twelve 0s. What we send here really doesn’t matter, as we just need to send clock pulses to the MCP3002 so that it sends data back to us over the Dout (MISO) line. This data (4 setup bits followed by twelve 0s) is stored in a list.

language:python
msg = [msg, 0b00000000]

We store the data returned to us in the reply variable, and it comes to us as a list of 2 bytes (stored as 2 integers). Note that we send out data and read the reply at the same time when using SPI:

language:python
reply = spi.xfer2(msg)

From there, we construct a single integer out of the two bytes (8 bits) by shifting the first over to the left by 8 bits and then adding the second byte to it. The last bit we read in is extraneous (not part of the ADC’s return value) so we shift the answer to the right by one bit.

language:python
adc = 0
for n in reply:
    adc = (adc << 8) + n

adc = adc >> 1

The ADC value is given as a percentage of the maximum voltage (whatever the voltage is on the Vdd/Vref pin). That percentage is calculated by dividing the reply value by 1024. We get 1024 because we know that the MCP3002 is a 10-bit ADC, which means the maximum value of 10 bits (0b1111111111) is 1023. Many ADCs have some error, so we round up to 1024 to make the math easier (here’s a discussion on max ADC values, if you’re curious).

Once we get the percentage of Vref with val / 1024, we multiply that percentage by our Vref, which we know is 3.3V in the case of our Raspberry Pi.

language:python
voltage = (vref * adc) / 1024

And that’s how we get our analog voltage reading! If all this is confusing, you can simple copy the Enable SPI portion and read_adc() function into your own code. Then, just call read_adc(0) to get the voltage at CH0 on the MCP3002.

One last interesting bit of code is the idea of default parameters. If you take a look at the read_adc() definition:

language:python
def read_adc(adc_ch, vref = 3.3):

You’ll see that there are actually two parameters: adc_ch and vref. When you call this function, you are required to give it a channel number (0 or 1). However, you can optionally send it an argument with the Vref value. On most cases with the Raspberry Pi, the voltage will be 3.3V. If you use another voltage (e.g. 5V), then you can change the math so that the ADC gives you a more accurate reading.

You have the option of calling this function with another Vref (e.g. 5) using either read_adc(0, 5) or by explicitly naming the vref parameter read_adc(0, vref=5). However, because we know that we’ve connected 3.3V to the MCP3002, we can simply call read_adc(0) and know that the function will rely on its default parameter of vref=3.3 when doing its calculations.

Challenge: Add an LED to your circuitry. Write a program to act as a variable nightlight. That is, the LED should turn on whenever the photocell sees dark (little ambient light) and should turn off whenever the photocell sees light (lots of ambient light). Have the potentiometer control the brightness of the LED when it is on. Hint: you might want to take some measurements to determine the threshold of light vs. dark. What is the voltage when you cover the photocell with your hand?

Raspberry Pi nightlight created in Python

import time
import spidev
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Light/dark threshold (Volts)
light_threshold = 2.2

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED as output
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pwm object with 50 Hz and 0% duty cycle
pwm = GPIO.PWM(led_pin, 50)
pwm.start(0)

# SPI channel (use CE0)
spi_ch = 0

# Enable SPI
spi = spidev.SpiDev(0, spi_ch)
spi.max_speed_hz = 1200000

def read_adc(adc_ch, vref = 3.3):

    # Make sure ADC channel is 0 or 1
    if adc_ch != 0:
        adc_ch = 1

    # Construct SPI message
    #  First bit (Start): Logic high (1)
    #  Second bit (SGL/DIFF): 1 to select single mode
    #  Third bit (ODD/SIGN): Select channel (0 or 1)
    #  Fourth bit (MSFB): 0 for LSB first
    #  Next 12 bits: 0 (don't care)
    msg = 0b11
    msg = ((msg << 1) + adc_ch) << 5
    msg = [msg, 0b00000000]
    reply = spi.xfer2(msg)

    # Construct single integer out of the reply (2 bytes)
    adc = 0
    for n in reply:
        adc = (adc << 8) + n

    # Last bit (0) is not part of ADC value, shift to remove it
    adc = adc >> 1

    # Calculate voltage form ADC value
    voltage = (vref * adc) / 1024

    return voltage

# Read ADC values and determine if LED should be on or off
try:
    while True:

        # Read ADC values
        light_val = read_adc(0)
        knob_val = read_adc(1)

        # Calculate brightness for when LED is on
        # Max brightness is 100% duty cycle
        brightness = (knob_val / 3.3) * 100

        # Turn LED off if ambient light is above threshold
        # Turn LED on if ambient light is equal to or below threshold
        if light_val > light_threshold:
            pwm.ChangeDutyCycle(0)
        else:
            pwm.ChangeDutyCycle(brightness)
        time.sleep(0.1)

finally:
    pwm.stop()
    spi.close()
    GPIO.cleanup()

Connect an LED and resistor to GPIO12 (pin 32), like in the previous experiment.