Raspberry Pi OS
Introduction
Edit this on GitHub
Raspberry Pi OS is a free operating system based on Debian, optimised for the Raspberry Pi hardware, and is the recommended operating system for normal use on a Raspberry Pi. The OS comes with over 35,000 packages: pre-compiled software bundled in a nice format for easy installation on your Raspberry Pi.
Raspberry Pi OS is under active development, with an emphasis on improving the stability and performance of as many Debian packages as possible on Raspberry Pi.
Updating and Upgrading Raspberry Pi OS
Edit this on GitHub
It’s important to keep your Raspberry Pi up to date. The first and probably the most important reason is security. A device running Raspberry Pi OS contains millions of lines of code that you rely on. Over time, these millions of lines of code will expose well-known vulnerabilities, which are documented in publicly available databases meaning that they are easy to exploit. The only way to mitigate these exploits as a user of Raspberry Pi OS is to keep your software up to date, as the upstream repositories track CVEs closely and try to mitigate them quickly.
The second reason, related to the first, is that the software you are running on your device most certainly contains bugs. Some bugs are CVEs, but bugs could also be affecting the desired functionality without being related to security. By keeping your software up to date, you are lowering the chances of hitting these bugs.
Using APT
The easiest way to manage installing, upgrading, and removing software is using APT (Advanced Packaging Tool) from Debian. To update software in Raspberry Pi OS, you can use the apt
tool from a Terminal window.
Keeping your Operating System up to Date
APT keeps a list of software sources on your Raspberry Pi in a file at /etc/apt/sources.list
. Before installing software, you should update your package list with apt update
. Go ahead and open a Terminal window and type:
sudo apt update
Next, upgrade all your installed packages to their latest versions with the following command:
sudo apt full-upgrade
Note that full-upgrade
is used in preference to a simple upgrade
, as it also picks up any dependency changes that may have been made.
Generally speaking, doing this regularly will keep your installation up to date for the particular major Raspberry Pi OS release you are using (e.g. Bookworm). It will not update from one major release to another, for example, Buster to Bullseye or Bullseye to Bookworm.
However, there are occasional changes made in the Raspberry Pi OS image that require manual intervention, for example a newly introduced package. These are not installed with an upgrade, as this command only updates the packages you already have installed.
Note
|
The kernel and firmware are installed as a Debian package, and so will also get updates when using the procedure above. These packages are updated infrequently and after extensive testing. |
If moving an existing SD card to a new Raspberry Pi model (for example the Raspberry Pi Zero 2 W), you may also need to update the kernel and the firmware first using the instructions above.
Running Out of Space
When running sudo apt full-upgrade
, it will show how much data will be downloaded and how much space it will take up on the SD card. It’s worth checking with df -h
that you have enough free disk space, as unfortunately apt
will not do this for you. Also be aware that downloaded package files (.deb
files) are kept in /var/cache/apt/archives
. You can remove these in order to free up space with sudo apt clean
(sudo apt-get clean
in older releases of apt).
Upgrading from Previous Operating System Versions
Warning
|
Upgrading an existing image is sometimes possible, but is not guaranteed to work in every circumstance and we do not recommend it. If you do wish to try upgrading your operating system version, we strongly suggest making a backup first. We accept no responsibility for the loss of any data during a failed update. |
The latest version of Raspberry Pi OS is based on Debian Bookworm. The previous version was based on Debian Bullseye.
Searching for Software
You can search the archives for a package with a given keyword with apt-cache search
:
apt-cache search locomotive
sl - Correct you if you type `sl' by mistake
You can view more information about a package before installing it with apt-cache show
:
apt-cache show sl
Package: sl
Version: 3.03-17
Architecture: armhf
Maintainer: Hiroyuki Yamamoto <[email protected]>
Installed-Size: 114
Depends: libc6 (>= 2.4), libncurses5 (>= 5.5-5~), libtinfo5
Homepage: http://www.tkl.iis.u-tokyo.ac.jp/~toyoda/index_e.html
Priority: optional
Section: games
Filename: pool/main/s/sl/sl_3.03-17_armhf.deb
Size: 26246
SHA256: 42dea9d7c618af8fe9f3c810b3d551102832bf217a5bcdba310f119f62117dfb
SHA1: b08039acccecd721fc3e6faf264fe59e56118e74
MD5sum: 450b21cc998dc9026313f72b4bd9807b
Description: Correct you if you type `sl' by mistake
Sl is a program that can display animations aimed to correct you
if you type 'sl' by mistake.
SL stands for Steam Locomotive.
Installing a Package with APT
sudo apt install tree
Typing this command should inform the user how much disk space the package will take up and asks for confirmation of the package installation. Entering Y
(or just pressing Enter
, as yes is the default action) will allow the installation to occur. This can be bypassed by adding the -y
flag to the command:
sudo apt install tree -y
Installing this package makes tree
available for the user.
Uninstalling a Package with APT
You can uninstall a package with apt remove
:
sudo apt remove tree
The user is prompted to confirm the removal. Again, the -y
flag will auto-confirm.
You can also choose to completely remove the package and its associated configuration files with apt purge
:
sudo apt purge tree
Using rpi-update
rpi-update
is a command line application that will update your Raspberry Pi OS kernel and VideoCore firmware to the latest pre-release versions.
Warning
|
Pre-release versions of software are not guaranteed to work. You should not use rpi-update on any system unless recommended to do so by a Raspberry Pi engineer. It may leave your system unreliable or even completely broken. It should not be used as part of any regular update process.
|
The rpi-update
script was originally written by Hexxeh, but is now supported by Raspberry Pi engineers. The script source is in the rpi-update repository.
What it does
rpi-update
will download the latest pre-release version of the linux kernel, its matching modules, device tree files, along with the latest versions of the VideoCore firmware. It will then install these files to relevant locations on the SD card, overwriting any previous versions.
All the source data used by rpi-update
comes from the rpi-firmware repository. This repository simply contains a subset of the data from the official firmware repository, as not all the data from that repo is required.
Running rpi-update
If you are sure that you need to use rpi-update
, it is advisable to take a backup of your current system first as running rpi-update
could result in a non-booting system.
rpi-update
needs to be run as root. Once the update is complete you will need to reboot.
sudo rpi-update sudo reboot
It has a number of options documented in the rpi-update repository.
How to get back to safety
If you have done an rpi-update
and things are not working as you wish, if your Raspberry Pi is still bootable you can return to the stable release using:
sudo apt-get update sudo apt install --reinstall raspi-firmware
Note
|
If your device still runs Raspberry Pi OS Bullseye, use the following command to reinstall raspberrypi-kernel instead: sudo apt install --reinstall libraspberrypi0 libraspberrypi-{bin,dev,doc} raspberrypi-{kernel,bootloader} .
|
You will need to reboot your Raspberry Pi for these changes to take effect.
Playing Audio and Video
Edit this on GitHub
The simplest way of playing audio and video on Raspberry Pi is to use the pre-installed VLC application. This is hardware accelerated, and can play back many popular audio and video file formats. More extensive information can be found at https://www.videolan.org/
The VLC application
To play an audio or video file in the Raspberry Pi OS desktop environment, you can simply double-click on the file in the file-manager, and VLC will automatically launch and play the file. Alternatively, you can launch "VLC Media Player" from the "Sound & Video" menu, and then select "Media" → "Open File…" and navigate to the file you want to play. By default the audio is sent over the HDMI link; if you instead want to output the audio over the Headphone jack, right-click on the speaker-icon in the top-right corner of the screen, and select "AV Jack".
For more fine-grained control, you can also launch VLC from the command-line. For the examples below, we used a short clip from Big Buck Bunny.
wget --trust-server-names http://rptl.io/big-buck-bunny vlc big-buck-bunny-1080p.mp4
To prevent the VLC GUI staying open after your file has finished playing, you can add the --play-and-exit
flag:
vlc --play-and-exit big-buck-bunny-1080p.mp4
You can also add the --fullscreen
flag to force a video to use the full screen - and this can also lead to smoother playback in some circumstances.
vlc --play-and-exit --fullscreen big-buck-bunny-1080p.mp4
If you use cvlc
instead of vlc
with any of these commands, then the VLC GUI won’t be shown:
cvlc --play-and-exit big-buck-bunny-1080p.mp4
If you have a raw H264 stream, for example as captured from the Raspberry Pi Camera Module, you will get much smoother playback in VLC by encapsulating the stream inside a container-format. This can be done using ffmpeg
, for example this command converts video.h264
to a containerised video.mp4
at 30 fps:
ffmpeg -r 30 -i video.h264 -c:v copy video.mp4
Playing Audio and Video on Raspberry Pi OS Lite
Firstly, install the necessary VLC components:
sudo apt install --no-install-recommends vlc-bin vlc-plugin-base
And then download and play an example audio file:
wget --trust-server-names http://rptl.io/startup-music cvlc --play-and-exit computer-startup-music.mp3
To force the audio output to a particular device, you need to use:
cvlc --play-and-exit -A alsa --alsa-audio-device <alsa-device> computer-startup-music.mp3
replacing <alsa-device>
with one of the following options:
ALSA device | Description |
---|---|
sysdefault:CARD=Headphones |
The headphone jack |
sysdefault:CARD=vc4hdmi |
The HDMI output on a Raspberry Pi Zero, or Raspberry Pi Model 1, 2 or 3 |
sysdefault:CARD=vc4hdmi0 |
The HDMI0 output on a Raspberry Pi 4 or 400 |
sysdefault:CARD=vc4hdmi1 |
The HDMI1 output on a Raspberry Pi 4 or 400 |
Use the following command to get a list of all ALSA devices on your Raspberry Pi:
aplay -L | grep sysdefault
To force the video output to a particular device, you need to use:
cvlc --play-and-exit --drm-vout-display <drm-device> big-buck-bunny-1080p.mp4
replacing <drm-device>
with one of the following options:
DRM device | Description |
---|---|
HDMI-A-1 |
The HDMI output on a Raspberry Pi Zero, or Raspberry Pi Model 1, 2 or 3; or the HDMI0 output on a Raspberry Pi 4 or 400 |
HDMI-A-2 |
The HDMI1 output on a Raspberry Pi 4 or 400 |
DSI-1 |
The Raspberry Pi Touch Display |
Use the following command to get a list of all DRM devices on your Raspberry Pi:
kmsprint | grep Connector
You can combine these options, so to direct the video output to the touchscreen, and the audio output to the headphone jack, you’d use
cvlc --play-and-exit --fullscreen --drm-vout-display DSI-1 -A alsa --alsa-audio-device sysdefault:CARD=Headphones your_video.mp4
Using a USB webcam
Edit this on GitHub
Rather than using the Raspberry Pi camera module, you can use a standard USB webcam to take pictures and video on your Raspberry Pi.
Note
|
The quality and configurability of the camera module is highly superior to a standard USB webcam. |
First, install the fswebcam
package:
sudo apt install fswebcam
Next, add your username to the video
group, otherwise you will see 'permission denied' errors:
sudo usermod -a -G video <username>
To check that the user has been added to the group correctly, use the groups
command.
Basic Usage
Enter the command fswebcam
followed by a filename and a picture will be taken using the webcam, and saved to the filename specified:
fswebcam image.jpg
This command will show the following information:
--- Opening /dev/video0... Trying source module v4l2... /dev/video0 opened. No input was specified, using the first. Adjusting resolution from 384x288 to 352x288. --- Capturing frame... Corrupt JPEG data: 2 extraneous bytes before marker 0xd4 Captured frame in 0.00 seconds. --- Processing captured image... Writing JPEG image to 'image.jpg'.

Note
|
The small default resolution used, and the presence of a banner showing the timestamp. |
The webcam used in this example has a resolution of 1280 x 720
so to specify the resolution I want the image to be taken at, use the -r
flag:
fswebcam -r 1280x720 image2.jpg
This command will show the following information:
--- Opening /dev/video0... Trying source module v4l2... /dev/video0 opened. No input was specified, using the first. --- Capturing frame... Corrupt JPEG data: 1 extraneous bytes before marker 0xd5 Captured frame in 0.00 seconds. --- Processing captured image... Writing JPEG image to 'image2.jpg'.

Picture now taken at the full resolution of the webcam, with the banner present.
Removing the Banner
Now add the --no-banner
flag:
fswebcam -r 1280x720 --no-banner image3.jpg
which shows the following information:
--- Opening /dev/video0... Trying source module v4l2... /dev/video0 opened. No input was specified, using the first. --- Capturing frame... Corrupt JPEG data: 2 extraneous bytes before marker 0xd6 Captured frame in 0.00 seconds. --- Processing captured image... Disabling banner. Writing JPEG image to 'image3.jpg'.

Now the picture is taken at full resolution with no banner.
Automating Image Capture
You can write a Bash script which takes a picture with the webcam. The script below saves the images in the /home/pi/webcam
directory, so create the webcam
subdirectory first with:
mkdir webcam
To create a script, open up your editor of choice and write the following example code:
#!/bin/bash
DATE=$(date +"%Y-%m-%d_%H%M")
fswebcam -r 1280x720 --no-banner /home/pi/webcam/$DATE.jpg
This script will take a picture and name the file with a timestamp. Say we saved it as webcam.sh
, we would first make the file executable:
chmod +x webcam.sh
Then run with:
./webcam.sh
Which would run the commands in the file and give the usual output:
--- Opening /dev/video0... Trying source module v4l2... /dev/video0 opened. No input was specified, using the first. --- Capturing frame... Corrupt JPEG data: 2 extraneous bytes before marker 0xd6 Captured frame in 0.00 seconds. --- Processing captured image... Disabling banner. Writing JPEG image to '/home/pi/webcam/2013-06-07_2338.jpg'.
Time-Lapse Captures
You can use cron
to schedule taking a picture at a given interval, such as every minute to capture a time-lapse.
First open the cron table for editing:
crontab -e
This will either ask which editor you would like to use, or open in your default editor. Once you have the file open in an editor, add the following line to schedule taking a picture every minute (referring to the Bash script from above):
* * * * * /home/pi/webcam.sh 2>&1
Save and exit and you should see the message:
crontab: installing new crontab
Ensure your script does not save each picture taken with the same filename. This will overwrite the picture each time.
Useful Utilities
Edit this on GitHub
There are several useful command line utilities pre-installed in Raspberry Pi OS.
kmsprint
The kmsprint
tool can be used to list the display-modes supported by the monitors attached to the Raspberry Pi. Use kmsprint
to see details of the monitors connected to the Raspberry Pi, and kmsprint -m
to see a list of all the display-modes supported by each monitor. You can find source code for the kmsprint
utility on Github.
vcgencmd
The vcgencmd
tool is used to output information from the VideoCore GPU on the Raspberry Pi. You can find source code for the vcgencmd
utility on Github.
To get a list of all commands which vcgencmd
supports, use vcgencmd commands
. Some useful commands and their required parameters are listed below.
vcos
The vcos
command has two useful sub-commands:
-
version
displays the build date and version of the firmware on the VideoCore -
log status
displays the error log status of the various VideoCore firmware areas
get_throttled
Returns the throttled state of the system. This is a bit-pattern - a bit being set indicates the following meanings:
Bit | Hex value | Meaning |
---|---|---|
0 |
0x1 |
Under-voltage detected |
1 |
0x2 |
Arm frequency capped |
2 |
0x4 |
Currently throttled |
3 |
0x8 |
Soft temperature limit active |
16 |
0x10000 |
Under-voltage has occurred |
17 |
0x20000 |
Arm frequency capping has occurred |
18 |
0x40000 |
Throttling has occurred |
19 |
0x80000 |
Soft temperature limit has occurred |
measure_temp
Returns the temperature of the SoC as measured by its internal temperature sensor;
on Raspberry Pi 4, measure_temp pmic
returns the temperature of the PMIC.
measure_clock [clock]
This returns the current frequency of the specified clock. The options are:
clock | Description |
---|---|
arm |
ARM core(s) |
core |
GPU core |
h264 |
H.264 block |
isp |
Image Sensor Pipeline |
v3d |
3D block |
uart |
UART |
pwm |
PWM block (analogue audio output) |
emmc |
SD card interface |
pixel |
Pixel valves |
vec |
Analogue video encoder |
hdmi |
HDMI |
dpi |
Display Parallel Interface |
e.g. vcgencmd measure_clock arm
measure_volts [block]
Displays the current voltages used by the specific block.
block | Description |
---|---|
core |
VC4 core voltage |
sdram_c |
SDRAM Core Voltage |
sdram_i |
SDRAM I/O voltage |
sdram_p |
SDRAM Phy Voltage |
otp_dump
Displays the content of the OTP (one-time programmable) memory inside the SoC. These are 32-bit values, indexed from 8 to 64. See the OTP bits page for more details.
get_config [configuration item|int|str]
Display value of the configuration setting specified: alternatively, specify either int
(integer) or str
(string) to see all configuration items of the given type. For example:
vcgencmd get_config total_mem
returns the total memory on the device in megabytes.
get_mem type
Reports on the amount of memory addressable by the ARM and the GPU. To show the amount of ARM-addressable memory use vcgencmd get_mem arm
; to show the amount of GPU-addressable memory use vcgencmd get_mem gpu
. Note that on devices with more than 1GB of memory the arm
parameter will always return 1GB minus the gpu
memory value, since the GPU firmware is only aware of the first 1GB of memory. To get an accurate report of the total memory on the device, see the total_mem
configuration item - see get_config
section above.
codec_enabled [type]
Reports whether the specified CODEC type is enabled. Possible options for type are AGIF, FLAC, H263, H264, MJPA, MJPB, MJPG, MPG2, MPG4, MVC0, PCM, THRA, VORB, VP6, VP8, WMV9, WVC1. Those highlighted currently require a paid for licence (see the this config.txt section for more info), except on the Raspberry Pi 4 and 400, where these hardware codecs are disabled in preference to software decoding, which requires no licence. Note that because the H.265 HW block on the Raspberry Pi 4 and 400 is not part of the VideoCore GPU, its status is not accessed via this command.
Accessibility options
Edit this on GitHub
Visual aids
Visually-impaired users of Raspberry Pi OS can find helpful tools in the Recommend Software menu.
We offer the Orca screen reader to better navigate your way through the Raspberry Pi operating system, along with a screen magnifier to increase the readability of UI and screen elements.
Orca screen reader
You can install Orca screen reader from the Recommended Software section of the main Raspberry Pi menu. Alternatively you can press Ctrl + Alt + Space to automatically install Orca.
When booting Raspberry Pi OS for the first time after installing a new image, an automatic spoken reminder will play after 30 seconds. This reminder will provide instructions on how to install Orca.
Python on Raspberry Pi
Edit this on GitHub
Python 3 is installed by default on Raspberry Pi OS and is used for many important functions. Interfering with the system Python installation can cause problems for your operating system, so it’s important that if you install third-party Python libraries, you use the correct package-management tools.
There are two routes to installing libraries into the default python
distribution. You can use apt
and install pre-configured system packages, or you can use pip
to install packages which are not distributed as part of Raspberry Pi OS.
Important
|
From Bookworm onwards, packages installed via pip must be installed into a Python Virtual Environment using venv . This has been introduced by the Python community, not Raspberry Pi; see PEP 668 for more details.
|
Installing Python packages using apt
Important
|
Installing packages using apt is the preferred method for installing Python libraries on Raspberry Pi OS.
|
Packages installed via apt
are tested, are usually pre-compiled so they install faster, and are designed for Raspberry Pi OS. They won’t break your system. Installing via this route also means that all required dependencies are also installed, and a log of installation is maintained by the OS so installation can be easily rolled back (uninstalled) if needed.
For instance, to install the Python 3 library to support the Raspberry Pi Build HAT you would:
$ sudo apt install python3-build-hat
…to install the pre-built library.
Using apt
makes installing larger packages, like numpy
(which has many native dependencies including a Fortran compiler), much simpler than installing individual packages using Python’s own package-management system.
If you want to install a Python library called "foobar" you can use apt search foobar
to find the exact package name. In most cases, you’ll find that the required package is going to be called python-foobar
or python3-foobar
.
About Python virtual environments
In previous versions of the operating system, it was possible to install libraries directly, system-wide, using the package installer for Python, commonly known as pip
. You’ll find the following sort of command in many tutorials online.
$ pip install buildhat
In newer versions of Raspberry Pi OS, and other operating systems, this is disallowed. If you try and install a Python package system-wide you’ll receive an error similar to this:
$ pip install buildhat
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
For more information visit http://rptl.io/venv
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
This error is generated because you’re trying to install a third-party package into the system Python. A long-standing practical problem for Python users has been conflicts between OS package managers like apt
and Python-specific package management tools like pip
. These conflicts include both Python-level API incompatibilities and conflicts over file ownership.
Therefore from Bookworm onwards, packages installed via pip
must be installed into a Python virtual environment using venv
. A virtual environment is a container where you can safely install third-party modules so they won’t interfere with, or break, your system Python.
Using pip with virtual environments
To use a virtual environment you will need to create a container to store the environment. There are several ways you can do this depending on how you want to work with Python.
Using a separate environment for each project
One way you can proceed is to create a new virtual environment for each Python project you make. Here, you’ll create a directory to hold your own code along with a virtual environment directory:
$ mkdir my_project
$ cd my_project
$ python -m venv env
If you now look inside the my_project
directory you’ll see a directory called env
.
$ ls -la
total 12
drwxr-xr-x 3 pi pi 4096 Oct 3 14:34 .
drwx------ 20 pi pi 4096 Oct 3 14:34 ..
drwxr-xr-x 5 pi pi 4096 Oct 3 14:34 env
$
Note
|
If you want to inherit the currently installed packages from the system Python, you should create your virtual environment using python -m venv --system-site-packages env .
|
Inside this directory is a full Python distribution. To activate your virtual environment and make that version of Python the one you’re currently using, you should type:
$ source env/bin/activate
(env) $
You’ll see that your prompt is now prepended with (env)
to indicate that you’re no longer using the system Python. Instead, you’re using the version of Python contained inside your virtual environment. Any changes you make here won’t cause problems for your system Python; nor will any new modules you install into your environment.
(env) $ which python
/home/pi/my_project/env/bin/python
If you install a third-party package, it’ll install into the Python distribution in your virtual environment:
(env) $ pip install buildhat
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting buildhat
Downloading https://www.piwheels.org/simple/buildhat/buildhat-0.5.12-py3-none-any.whl (57 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.8/57.8 kB 2.8 MB/s eta 0:00:00
Collecting gpiozero
Downloading https://www.piwheels.org/simple/gpiozero/gpiozero-2.0-py3-none-any.whl (150 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 150.5/150.5 kB 6.9 MB/s eta 0:00:00
Collecting pyserial
Downloading https://www.piwheels.org/simple/pyserial/pyserial-3.5-py2.py3-none-any.whl (90 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 90.6/90.6 kB 7.5 MB/s eta 0:00:00
Collecting colorzero
Downloading https://www.piwheels.org/simple/colorzero/colorzero-2.0-py2.py3-none-any.whl (26 kB)
Requirement already satisfied: setuptools in ./env/lib/python3.11/site-packages (from colorzero->gpiozero->buildhat) (66.1.1)
Installing collected packages: pyserial, colorzero, gpiozero, buildhat
Successfully installed buildhat-0.5.12 colorzero-2.0 gpiozero-2.0 pyserial-3.5
(env) $
Now, if you pip list
, you’ll see that your current version of Python includes your new modules.
(env) $ pip list
Package Version
---------- -------
buildhat 0.5.12
colorzero 2.0
gpiozero 2.0
pip 23.0.1
pyserial 3.5
setuptools 66.1.1
After writing your code, you can run it from the command line inside the virtual environment as you’d expect, by invoking Python as usual.
(env) $ ls -la
total 12
drwxr-xr-x 3 pi pi 4096 Oct 3 14:34 .
drwx------ 20 pi pi 4096 Oct 3 14:34 ..
drwxr-xr-x 5 pi pi 4096 Oct 3 14:34 env
-rw-r--r-- 1 pi pi 0 Oct 3 14:45 my_code.py
(env) $ python my_code.py
Hello World!
(env) $
You can leave your virtual environment and return to using the system Python by typing:
(env) $ deactivate
$
…and demonstrate to yourself you’ve done so by checking the installed packages using pip list
.
Using a separate environment for each user
An alternative method to creating a virtual environment for each of your Python projects is to create a single virtual environment for your user account, and then activate that environment before running any of your Python code. This approach may be preferred if you commonly install the same set of modules for each project, and don’t want to have to bother creating individual Python environments for each project, essentially just duplicating your environment.
$ python -m venv ~/.env
$ source ~/.env/bin/activate
(.env) $
You can again check you’re in a separate environment by using pip list
,
(.env) $ pip list
Package Version
---------- -------
pip 23.0.1
setuptools 66.1.1
and leave it using deactivate
.
(.env) $ deactivate
$
Using the Thonny editor
Thonny is our recommended editor when you’re working with Python on the Raspberry Pi. By default Thonny uses the system Python. However, you can switch to using a Python virtual environment by clicking on the interpreter menu located at the bottom right of the Thonny window. Clicking on this will offer you a menu to select a configured interpreter or to Configure interpreter…
.

Selecting this will open a popup allowing you to create a new virtual environment.
GPIO and the 40-pin Header
Edit this on GitHub
A powerful feature of the Raspberry Pi is the row of GPIO (general-purpose input/output) pins along the top edge of the board. A 40-pin GPIO header is found on all current Raspberry Pi boards (unpopulated on Raspberry Pi Zero, Raspberry Pi Zero W and Raspberry Pi Zero 2 W). Prior to the Raspberry Pi 1 Model B+ (2014), boards comprised a shorter 26-pin header. The GPIO header on all boards (including the Raspberry Pi 400) have a 0.1" (2.54mm) pin pitch.

Any of the GPIO pins can be designated (in software) as an input or output pin and used for a wide range of purposes.

Note
|
The numbering of the GPIO pins is not in numerical order; GPIO pins 0 and 1 are present on the board (physical pins 27 and 28) but are reserved for advanced use (see below). |
Voltages
Two 5V pins and two 3.3V pins are present on the board, as well as a number of ground pins (0V), which are unconfigurable. The remaining pins are all general purpose 3.3V pins, meaning outputs are set to 3.3V and inputs are 3.3V-tolerant.
Inputs
A GPIO pin designated as an input pin can be read as high (3.3V) or low (0V). This is made easier with the use of internal pull-up or pull-down resistors. Pins GPIO2 and GPIO3 have fixed pull-up resistors, but for other pins this can be configured in software.
More
As well as simple input and output devices, the GPIO pins can be used with a variety of alternative functions, some are available on all pins, others on specific pins.
-
PWM (pulse-width modulation)
-
Software PWM available on all pins
-
Hardware PWM available on GPIO12, GPIO13, GPIO18, GPIO19
-
-
SPI
-
SPI0: MOSI (GPIO10); MISO (GPIO9); SCLK (GPIO11); CE0 (GPIO8), CE1 (GPIO7)
-
SPI1: MOSI (GPIO20); MISO (GPIO19); SCLK (GPIO21); CE0 (GPIO18); CE1 (GPIO17); CE2 (GPIO16)
-
-
I2C
-
Data: (GPIO2); Clock (GPIO3)
-
EEPROM Data: (GPIO0); EEPROM Clock (GPIO1)
-
-
Serial
-
TX (GPIO14); RX (GPIO15)
-
GPIO pinout
A handy reference can be accessed on the Raspberry Pi by opening a terminal window and running the command pinout
. This tool is provided by the GPIO Zero Python library, which is installed by default in Raspberry Pi OS.

For more details on the advanced capabilities of the GPIO pins see gadgetoid’s interactive pinout diagram.
Warning
|
While connecting up simple components to the GPIO pins is perfectly safe, it’s important to be careful how you wire things up. LEDs should have resistors to limit the current passing through them. Do not use 5V for 3.3V components. Do not connect motors directly to the GPIO pins, instead use an H-bridge circuit or a motor controller board. |
Permissions
In order to use the GPIO ports your user must be a member of the gpio
group. The pi
user is a member by default, other users need to be added manually.
sudo usermod -a -G gpio <username>
GPIO in Python
Using the GPIO Zero library makes it easy to get started with controlling GPIO devices with Python. The library is comprehensively documented at gpiozero.readthedocs.io.
LED
To control an LED connected to GPIO17, you can use this code:
from gpiozero import LED
from time import sleep
led = LED(17)
while True:
led.on()
sleep(1)
led.off()
sleep(1)
Run this in an IDE like Thonny, and the LED will blink on and off repeatedly.
LED methods include on()
, off()
, toggle()
, and blink()
.
Button
To read the state of a button connected to GPIO2, you can use this code:
from gpiozero import Button
from time import sleep
button = Button(2)
while True:
if button.is_pressed:
print("Pressed")
else:
print("Released")
sleep(1)
Button functionality includes the properties is_pressed
and is_held
; callbacks when_pressed
, when_released
, and when_held
; and methods wait_for_press()
and wait_for_release
.
Button + LED
To connect the LED and button together, you can use this code:
from gpiozero import LED, Button
led = LED(17)
button = Button(2)
while True:
if button.is_pressed:
led.on()
else:
led.off()
Alternatively:
from gpiozero import LED, Button
led = LED(17)
button = Button(2)
while True:
button.wait_for_press()
led.on()
button.wait_for_release()
led.off()
or:
from gpiozero import LED, Button
led = LED(17)
button = Button(2)
button.when_pressed = led.on
button.when_released = led.off
Going further
You can find more information on how to program electronics connected to your Raspberry Pi with the GPIO Zero Python library in the Raspberry Pi Press book Simple Electronics with GPIO Zero. Written by Phil King, it is part of the MagPi Essentials series published by Raspberry Pi Press. The book gets you started with the GPIO Zero library, and walks you through how to use it by building a series of projects.
You can download this book as a PDF file for free, it has been released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY NC-SA) licence.