Raspberry Pi Jupyter Headless Setup with GPIO Examples

This article covers setting up a headless Raspberry Pi as a Jupyter Notebook server. It also provides examples of how to use the GPIO to read a button and control an LED from within a Jupyter Notebook. This is sometimes referred to as physical computing.

If you’d like to know how I setup the headless image before I added Jupyter, I’ve provided some links at the end of this article. The image I’ve setup has ssh enabled so I can remotely log into it.

Step 1. Remote login to the Raspberry Pi

Remote into the Raspberry Pi:

  • Open up a terminal / command line window on your computer
  • Perform an ssh login to access your Raspberry Pi
  • For example (substitute mypi with your Pi’s hostname):
    ssh pi@mypi.local
    

Step 2. Enable interfacing options

From within the Pi:

  • Launch sudo raspi-config
  • Under Interfacing options enable the following:
    • Camera
    • I2C

You will be prompted to reboot.

Step 3. Switch mirrors (optional)

For the steps that follow I had trouble finding packages when I ran apt-get. In my case I needed to switch my system to another mirror of the resources.

You can try the same or just skip to the next step and see if it works (if not, come back to this step).

To switch mirrors I did the following:

  • Find a mirror near you:
  • Edit the sources.list file:
    sudo nano /etc/apt/sources.list
    
  • Comment out the current top line
  • Insert this line at the top (sub with a reliable mirror near you):
    deb http://mirror.umd.edu/raspbian/raspbian buster main contrib non-free rpi
    
  • Verify the mirror is now being used:
    sudo apt-get update
    

    Note that it is now connecting to the mirror:

    Get:1 http://mirror.umd.edu/raspbian/raspbian buster InRelease [15.0 kB]
    

Step 4. Install python libraries

To install the python libraries needed to run Jupyter, run the following commands:

sudo apt install python3-pip python3-pil
sudo pip3 install --upgrade numpy
sudo apt-get install python-rpi.gpio python3-rpi.gpio
sudo apt-get install python-picamera python3-picamera
sudo pip3 install jupyter 
jupyter nbextension enable --py widgetsnbextension

Step 5. Setup a password

To secure Jupyter, setup a password:

jupyter notebook password

If you lose your connection, close the terminal window and try another one.

Step 6. Run Jupyter

On your Pi, do the following:

jupyter notebook --no-browser

On your laptop, do the following:

  • Run this in a terminal window (adjust for your hostname):
    ssh -N -f -L localhost:8888:localhost:8888 pi@mypi.local
    
  • Open up a browser (I’m using Chrome)
  • Browse to: http://localhost:8888
  • Enter the Jupyter password

You should now be looking at the tree (folder) view.

Step 7. Create a test notebook

In Jupyter, do the following:

  • On the right side of the browser view, click the New dropdown
  • Under Notebook: select Python 3
  • In the header click Untitled and rename the notebook to Hello
  • In the new cell enter the following Python code:
    print("Hello World!")
    
  • In the toolbar, click Run

The output should be printed under the cell.

At this point you have Jupyter working and you can start creating new notebooks.

But if you would like to test the hardware interaction, proceed on to the next few steps.

Test 8. Test GPIO with a button

To test interaction with hardware using this example, you will need a button (preferably a momentary contact button).

  • You may want to shutdown the Pi for this to avoid accidentally shorting it
  • Wire a momentary contact button between Pin 6 (GND) and Pin 16 (GPIO23)
    • Once done, remote back into the pi, restart Jupyter and reconnect over ssh
  • Create a new notebook called push_button
  • Add the code below to a new cell
  • Run the code and then push the physical (momentary contact) button
    • the program should print some messages then exit
  • To stop the program without pressing the physical button:
    • click the button in the tool bar that looks like a stop button
    • or from the menu select Kernel / Interrupt (which does the same thing)
#!/usr/bin/python3

import RPi.GPIO as GPIO
from time import sleep

# Button: GND (Pin 6), GPIO23 (Pin 16)

buttonPin = 16

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

# pull up using internal resistor
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) 

print("Press the physical button or:")
print("Select: Kernel / Interrupt or Jupyter tool bar button to stop")

pushed = False

try:

  while True:
    sleep(0.1)  # Give the CPU a break
    if GPIO.input(buttonPin) == GPIO.LOW:
      if not pushed:
          pushed = True
          print("LOW")
          break
    else:
      pushed = False

except KeyboardInterrupt:  
    print("\nInterupt detected")
    
print("Button pressed? " + str(pushed) )
print("Click inside code block to run again")

Test 9. Test GPIO with an LED

To test interaction with hardware using this example, you will need an LED and a 100 ohm resistor, jumper wire and a breadboard.

  • You may want to shutdown the Pi for this to avoid accidentally shorting it
  • Wire in series an LED with a 100 ohm resistor between Pin 6 (GND) and Pin 8
    • The cathode (shorter lead) of the LED should connect to ground (GND)
    • The anode (longer lead) should connect to a 100 ohm resister that connects to Pin 8
    • Once done, remote back into the pi, restart Jupyter and reconnect over ssh
  • Create a new notebook called led_flash
  • Add the code below to a new cell
  • Run the code and the led should start flashing
  • To stop the program, click the button in the tool bar that looks like a stop button
    • or from the menu select Kernel / Interrupt (which does the same thing)
#!/usr/bin/python3 

import RPi.GPIO as GPIO
from time import sleep

# Led: 
# Cathode (-) to GND (RPi Pin 6),
# Anode (+) (longer lead) to 100 ohm resistor
# Other end of resitor to (RPi Pin 8)

ledPin = 8
delay = 0.5

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW) 

print("Select: Kernel / Interrupt or tool bar button to stop")

try:

  while True:
    GPIO.output(ledPin, GPIO.HIGH) # Turn on
    sleep(delay)               
    GPIO.output(ledPin, GPIO.LOW)  # Turn off
    sleep(delay)                  

except KeyboardInterrupt: 
  print("Interrupt detected")    

print("Turning off LED")
GPIO.output(ledPin, GPIO.LOW)  # Turn off
print("Click inside code block to run again")

Troubleshooting

If the ssh command says the port is in use, try this (tested on a Mac):

lsof -ti:8888 | xargs kill

Conclusion

In this article you learned how to:

  • Install Jupyter on a headless Raspberry Pi
  • Create a notebook in Jupyter
  • Create Jupyter notebooks that interact with the hardware

References

  • Physical Computing (Wikipedia) [1]
  • JetBot Create SD Card Image from Scratch [2]
  • Raspbian Mirrors - [3]
  • ipywidgets - [4]



About the Author

Mitch Allen works for a robotics company in New England.