Many of us have had to become familiar with Zoom, Teams, Skype, and countless other video calling applications in recent years. Our ability to communicate and work together has been transformed by them, and at times it has been the only way for us to see our loved ones. Despite this, webcams are generally low in quality and low in resolution. It’s likely that a typical middle-of-the-road laptop will include a webcam at only 720p resolution and specifications that are at best mediocre.
Raspberry Pi now offers a suite of Camera Module 3 variants with 12-megapixel sensors and autofocus functionality, together with a choice of standard and wide lenses which are available with or without an infrared filter. These cameras are available alongside our two High Quality Cameras with 12.3 megapixel sensor and back-illuminated sensor architecture, adjustable back focus, your choice of C/CS mount or M12 mount, and built-in tripod mount.
We’ve teamed up with the folks over at ideasonboard.com to bring you some great new software, and in this tutorial, we’ll demonstrate how to use it with your choice of camera and a Raspberry Pi Zero 2 W using USB OTG (On-The-Go) technology. The result is a plug-and-play USB webcam that can rival any expensive off-the-shelf web camera. Our Raspberry Pi will be programmed with bespoke UVC (USB Video Class) software — simply plug it in to any Mac or Windows computer and it will automatically show up as a camera you can use in any video application you choose.
If you’re using a Raspberry Pi Zero 2 W or a Raspberry Pi 4, no additional power supply is necessary – a single cable can pass both power and data, provided you make sure the USB cable you choose is one that’s capable of passing data and is not just a power cable. It’s often not possible to tell whether a cable is suitable just by looking at it — while your Raspberry Pi might power on, it will not function for this project if your USB cable is just a power cable. For use with Raspberry Pi Zero 2 W we recommend the official Raspberry Pi USB to micro USB cable, which you can use together with our micro USB to USB-C adapter if you’re using a Raspberry Pi 4 for this project.
Another computer connected to your network. We’ll refer to this as “your usual computer”, to distinguish it from the Raspberry Pi computer that you are setting up as a webcam. We’re going to be accessing and controlling our Raspberry Pi via Wi-Fi from this computer, so there is no need for an additional keyboard, mouse, and display to be attached to your Raspberry Pi: this is called a headless setup.
We’re going to use Raspberry Pi Imager to install Raspberry Pi OS Lite onto your microSD card. Raspberry Pi Imager is available for free for Windows, macOS, Ubuntu for x86, and Raspberry Pi OS. Download it to your usual computer here.
Connect your microSD card to your usual computer, using an SD card adapter if you need one. We recommend a minimum storage size of 16GB. Open Raspberry Pi Imager, click CHOOSE OS, and select Raspberry Pi OS Lite (32-bit), which is the smaller-sized Raspberry Pi OS without a desktop environment or any additional applications — we won’t need them for this project. It can be found under Raspberry Pi OS (other):
CHOOSE STORAGE: Select your microSD card.
Press Ctrl-Shift-X to bring up the Raspberry Pi Imager advanced menu, or click the advanced menu cogwheel button in the bottom right corner:
Set a hostname of your choice; we’re using the hostname webcam for this tutorial. Check the Enable SSH (Secure Shell) box and set a username and password. You’ll need these details to access your Raspberry Pi later, so be sure to make a secure note of them. Configure your wireless LAN by checking the box, and replace XXXXXX with your own SSID (network name) and password.
Click SAVE to close the advanced menu, and finally select WRITE to start the process of writing the operating system to the SD card, which will take a few minutes to complete.
Insert your microSD card into your Raspberry Pi and connect it to power. Your Raspberry Pi will now boot for the first time and will connect to your Wi-Fi network automatically, as we have already given it all the credentials it needs.
SSH, or Secure Shell, is a network communication protocol that enables two computers to communicate. Open a terminal session on your usual computer and run the following to access your Raspberry Pi computer via SSH:
$ ssh pi@webcam.local
The fist time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:
$ ssh pi@webcam.local
The authenticity of host 'webcam.local (2a00:1098:3142:15:c6f9:55b7:4138:6fbf)' can't be established.
ED25519 key fingerprint is SHA256:StcWZgSqbeKq9gaenaOkcA2PWwXmEJ8nsSLK5UuWPJw.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'webcam.local' (ED25519) to the list of known hosts.
pi@webcam.local's password:
Linux webcam 5.15.61-v7+ #1579 SMP Fri Aug 26 11:10:59 BST 2022 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Sep 22 02:02:36 2022
It’s best practice to run an update task for a fresh installation of Raspberry Pi OS, and it’s something that you should do regularly. You want to ensure the device is running with the very latest versions of all programs and security. Run the following two commands, typing y
and hitting Enter when prompted to continue:
$ sudo apt update
$ sudo apt full-upgrade
Reboot your device to allow any changes to take effect:
$ sudo reboot
Now that your Raspberry Pi is fully updated and ready to go, log back in before moving on.
The fist step is to instruct your Raspberry Pi and camera to act as a OTG (On-The-Go) USB device when attached to another computer. We’ll do this by adding to the /boot/config.txt file, using the following command:
$ echo "dtoverlay=dwc2,dr_mode=otg" | sudo tee -a /boot/config.txt
Our next step is to install a few prerequisite programs:
$ sudo apt install git meson libcamera-dev libjpeg-dev
Meson is an open source build system that we’ll use to put together the camera software later, and the two lib programs relate to the open source camera stack system that Raspberry Pi uses for our new cameras. Confirm the installation by typing y to install the programs.
We’re now ready to download the UVC gadget software which is based on the standard video streaming functionality for USB:
$ git clone https://gitlab.freedesktop.org/camera/uvc-gadget.git
Navigate to the downloaded folder:
$ cd uvc-gadget
We now need to make, build, and install the software with the following commands:
$ make uvc-gadget
$ cd build
$ sudo meson install
$ sudo ldconfig
The last command, ldconfig
, is typically run after installing new libraries or updating existing ones, to ensure that the system is aware of the new libraries and can properly link to them.
The next step is to create a script that will run each time your Raspberry Pi is powered on in order to set everything up:
$ cd
$ sudo nano rpi-uvc-gadget.sh
We’re using nano here as our text editor to create a bash script called rpi-uvc-gadget.sh in the Raspberry Pi home directory. Copy and paste the following into your file:
#!/bin/bash
# Variables we need to make things easier later on.
CONFIGFS="/sys/kernel/config"
GADGET="$CONFIGFS/usb_gadget"
VID="0x0525"
PID="0xa4a2"
SERIAL="0123456789"
MANUF=$(hostname)
PRODUCT="UVC Gadget"
BOARD=$(strings /proc/device-tree/model)
UDC=`ls /sys/class/udc` # will identify the 'first' UDC
# Later on, this function is used to tell the usb subsystem that we want
# to support a particular format, framesize and frameintervals
create_frame() {
# Example usage:
# create_frame <function name> <width> <height> <format> <name> <intervals>
FUNCTION=$1
WIDTH=$2
HEIGHT=$3
FORMAT=$4
NAME=$5
wdir=functions/$FUNCTION/streaming/$FORMAT/$NAME/${HEIGHT}p
mkdir -p $wdir
echo $WIDTH > $wdir/wWidth
echo $HEIGHT > $wdir/wHeight
echo $(( $WIDTH * $HEIGHT * 2 )) > $wdir/dwMaxVideoFrameBufferSize
cat <<EOF > $wdir/dwFrameInterval
$6
EOF
}
# This function sets up the UVC gadget function in configfs and binds us
# to the UVC gadget driver.
create_uvc() {
CONFIG=$1
FUNCTION=$2
echo " Creating UVC gadget functionality : $FUNCTION"
mkdir functions/$FUNCTION
create_frame $FUNCTION 640 480 uncompressed u "333333
416667
500000
666666
1000000
1333333
2000000
"
create_frame $FUNCTION 1280 720 uncompressed u "1000000
1333333
2000000
"
create_frame $FUNCTION 1920 1080 uncompressed u "2000000"
create_frame $FUNCTION 640 480 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"
create_frame $FUNCTION 1280 720 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"
create_frame $FUNCTION 1920 1080 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"
mkdir functions/$FUNCTION/streaming/header/h
cd functions/$FUNCTION/streaming/header/h
ln -s ../../uncompressed/u
ln -s ../../mjpeg/m
cd ../../class/fs
ln -s ../../header/h
cd ../../class/hs
ln -s ../../header/h
cd ../../class/ss
ln -s ../../header/h
cd ../../../control
mkdir header/h
ln -s header/h class/fs
ln -s header/h class/ss
cd ../../../
# This configures the USB endpoint to allow 3x 1024 byte packets per
# microframe, which gives us the maximum speed for USB 2.0. Other
# valid values are 1024 and 2048, but these will result in a lower
# supportable framerate.
echo 2048 > functions/$FUNCTION/streaming_maxpacket
ln -s functions/$FUNCTION configs/c.1
}
# This loads the module responsible for allowing USB Gadgets to be
# configured through configfs, without which we can't connect to the
# UVC gadget kernel driver
echo "Loading composite module"
modprobe libcomposite
# This section configures the gadget through configfs. We need to
# create a bunch of files and directories that describe the USB
# device we want to pretend to be.
if [ ! -d $GADGET/g1 ]; then
echo "Detecting platform:"
echo " board : $BOARD"
echo " udc : $UDC"
echo "Creating the USB gadget"
echo "Creating gadget directory g1"
mkdir -p $GADGET/g1
cd $GADGET/g1
if [ $? -ne 0 ]; then
echo "Error creating usb gadget in configfs"
exit 1;
else
echo "OK"
fi
echo "Setting Vendor and Product ID's"
echo $VID > idVendor
echo $PID > idProduct
echo "OK"
echo "Setting English strings"
mkdir -p strings/0x409
echo $SERIAL > strings/0x409/serialnumber
echo $MANUF > strings/0x409/manufacturer
echo $PRODUCT > strings/0x409/product
echo "OK"
echo "Creating Config"
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "Creating functions..."
create_uvc configs/c.1 uvc.0
echo "OK"
echo "Binding USB Device Controller"
echo $UDC > UDC
echo "OK"
fi
# Run uvc-gadget. The -c flag sets libcamera as a source, arg 0 selects
# the first available camera on the system. All cameras will be listed,
# you can re-run with -c n to select camera n or -c ID to select via
# the camera ID.
uvc-gadget -c 0 uvc.0
Make the script executable with the following command:
$ sudo chmod 777 rpi-uvc-gadget.sh
The easiest way to execute this script every time the device is powered on is to add to the /etc/rc.local file. The contents of this file are run at the end of every boot process, so it is ideal for our purpose. Edit the file using the following command:
$ sudo nano /etc/rc.local
Add the command to execute our script above the exit 0
line and then hit Ctrl+X, Y, and Enter to save. The file should now look like this:
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
sudo /home/pi/rpi-uvc-gadget.sh
exit 0
Finally, shut down your Raspberry Pi:
$ sudo shutdown -h now
Now you have set up your software, connect your camera to your Raspberry Pi with the ribbon cable (see here for how to do this), and put them into your case, if you’re using one. For this tutorial we have provided free STL files for you to 3D print or laser cut a simple Raspberry Pi Zero 2 W case to use with a standard cold shoe laptop mount. Assembling the case is just a matter of fastening together the camera, Raspberry Pi, and 3D-printed case using M2.5 and M2 hex nylon standoffs, nuts and bolts, as this image shows:
The 3D-printed case is a push-fit for any standard cold shoe mount. We used one of these laptop mounts:
With your Raspberry Pi now all set to turn itself into a USB webcam anytime you plug it in to a computer, all that remains is to use it. There is just one small thing to remember: when using a Raspberry Pi Zero 2 W, you must connect it to your usual computer using the Pi Zero’s micro USB data port, not its micro USB power port. Your Pi Zero will receive its power and send the video feed through the data port to your usual computer simply by plugging it in. You do not need to use the Pi’s micro USB power port.
If you’re using a Raspberry Pi 3 or 3B+ for this project, then you’ll need to supply power in the usual way via its micro USB power port, and you’ll need to use a separate USB cable to connect one of the Pi’s four USB A data ports to your usual computer.
Finally, if you’re using Raspberry Pi 4, simply connecting a suitable USB-C cable to your usual computer from your Raspberry Pi’s USB-C port will work, because this port can handle both power and data. You won’t need any additional cables.
An alternative to using a Raspberry Pi Camera Module 3 and mounting it as described above is to use a Raspberry Pi High Quality Camera. These are 12.3 megapixels in resolution and come with your choice of C/CS mount or M12 mount. They have a super simple mounting method that’s compatible with any standard tripod, as shown in the photo below, which illustrates the M12 mount.
Here at Raspberry Pi, we have celebrated the launch of this software by updating an amazing project by Max Braun that uses the casing from the iconic Apple iSight. We’ve replaced the 25-year-old technology inside with a Raspberry Pi Zero 2 W and Camera Module 3.
We’ve made a few tweaks to Max’s original project in order to get it working with Raspberry Pi Camera Module 3. Check out our blog here to read all about it, and find all the necessary 3D print files available for free here.