Install both a Raspberry PI Camera and a USB Camera on Octopi 0.17 and 0.18
/Last updated February 27, 2021
I use Octoprint to manage my Prusa MK3 3D printer. To keep an eye on my prints, I have two cameras hooked up to the Raspberry PI on which I have Octoprint installed. The main camera is a Raspberry PI camera that hooks up directly the PI via a ribbon cable, and the second camera is a Logitech C510 webcam that I plug into one of the PI’s USB ports.
When I upgraded Octopi — a Raspberry PI Linux distribution that comes with Octoprint pre-installed — the USB camera stopped working and I couldn’t figure out how to get it working again. Octopi 0.17 is significantly different from previous versions, so I couldn’t rely on the tutorials I had used before.
I searched on YouTube, my favorite DIY resource, and found Chris Riley’s Chris’ Basement channel. He has a series of videos on how to set up an Octoprint multi-instance on one PI on Octopi 0.17. His instructions are great and I wouldn’t have found a solution without his videos, but they are geared toward hooking up USB cameras — not both a Raspberry PI camera and a USB camera.
Prerequisites
In this post I don’t explain how to install Octopi 0.17/0.18, nor how to attach and get working a PI Cam. You’ll need to get that done first before moving on.
You’ll also need to know a little about getting around a Linux command line and using the nano text editor.
Once you have the PI and PI Cam up and running, follow the instructions below to get a second (USB) camera working with your Raspberry PI.
Word of Caution:
You might be tempted to connect 2, 3 or 4 USB webcams to your Raspberry PI. Don’t do it. That path leads to madness. The cameras won’t mount as expected — I suspect because of limitations of Raspberry PIs in general, but I don’t know for sure. You’ll drive yourself crazy. Be content with running the RPI Camera Module and one USB camera.
1: Get information about your USB webcam
Log into your Raspberry PI via ssh. If you followed the standard Octopi setup, ssh’ing into your PI should be as simple as this:
> ssh pi@octopi.local
Make sure your USB webcam is unplugged from Raspberry PI. Type the following command in the terminal:
> tail -f /var/log/messages
Now plug the USB camera back in, and look at the new text that appeared in the logs you’re tailing. You should see bunch of lines that include the text “New USB device found”, or similar. Here’s an example of my log:
May 25 17:43:00 octopi kernel: [ 2.411980] usb 1-1.3: new high-speed USB device number 5 using dwc_otg
May 25 17:43:00 octopi kernel: [ 2.753813] usb 1-1.3: New USB device found, idVendor=046d, idProduct=081b, bcdDevice= 0.12
May 25 17:43:00 octopi kernel: [ 2.759809] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=2May 25 17:43:00 octopi kernel: [ 2.763045] usb 1-1.3: SerialNumber: 61196260
You'll need the values for idVendor, idProduct, and SerialNumber in the next step.
2: Create (or edit if existing) USB rules file
Use the nano text editor to edit (or create) a usb rules file:
> sudo nano /etc/udev/rules.d/99-usb.rules
Add the following line to the file:
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="081b", ATTRS{serial}=="61196260", SYMLINK+="PrusaWebCam"
These are the values I found in my log for my camera (a Logitech C510 HD webcam) — you’ll need to use your values for idVendor, idProduct and serial. For SYMLINK, use whatever name you want to give your camera. You’ll use the name in upcoming steps.
3: Confirm USB camera is properly set up:
Before moving on to step 4, it’s a good idea to confirm that the camera you configured in the previous udev USB rules step is working properly. If it isn’t, then none of the steps that follow will work.
First, let’s reboot the Raspberry PI to make it read the settings in 99-usb.rules
and connect your camera.
> sudo reboot
Once your PI is back up, ssh into it again and type the following command to list all the devices under the /dev
directory:
> ls -la /dev
If 99-usb.rules
was read correctly at startup, you should find the symlink you created under /dev
. Here’s what I see on my PI (I removed lots of entries to keep this short):
drwxr-xr-x 2 root root 60 Feb 11 19:20 net
crw-rw-rw- 1 root root 1, 3 Feb 11 19:20 null
crw------- 1 root root 108, 0 Feb 11 19:20 ppp
lrwxrwxrwx 1 root root 6 Feb 11 19:20 PrusaWebCam -> video0
crw-rw-rw- 1 root tty 5, 2 Feb 11 19:26 ptmx
drwxr-xr-x 2 root root 0 Feb 14 2019 pts
brw-rw---- 1 root disk 1, 0 Feb 11 19:20 ram0
The ->
character next to PrusaWebCam indicates that linux set up a symbolic link to the video0 device called PrusaWebCam.
If you see a symbolic link for your camera:
Congratulations! You are the golden child! Move on to step 4.
If you DON’T see a symbolic link for your camera:
Darn it! Something is wrong in 99-usb.rules
. Here are some things you can try:
Troubleshooting 1:
Before you start messing around with text editors, try the following: REBOOT AGAIN. This shouldn’t be a serious step, but it’s worked some than once for me.
Troubleshooting 2:
One of the main culprits of issues with udev rules is that some cameras don’t have valid serial numbers.
For example, I bought a cheap USB endoscope on Amazon to test and connected it to my spare Raspberry PI with Octopi 0.18 installed. I tailed the messages log while I plugged the endoscope in and here’s a partial list of the output:
Feb 11 20:04:22 octopi2 kernel: [ 2619.572078] usb 1-1.1.3: new high-speed USB device number 7 using dwc_otg
Feb 11 20:04:23 octopi2 kernel: [ 2619.783159] usb 1-1.1.3: New USB device found, idVendor=1908, idProduct=2311, bcdDevice= 1.00
Feb 11 20:04:23 octopi2 kernel: [ 2619.783177] usb 1-1.1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
SerialNumber=0
was suspicious to me, but I tried using it anyway in a second entry in my 99-usb.rules file, with SYMLINK+="EndoCam"
. After a reboot, I didn’t find an EndoCam symbolic link under the /dev
directory. I rebooted several more times, still no luck.
The fix was easy. I added the EndoCam entry without a serial number attribute. Here’s what my 99-usb.rules
file looks like now with both cameras configured:
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="081b", ATTRS{serial}=="3A108F50", SYMLINK+="PrusaWebCam"
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="1908", ATTRS{idProduct}=="2311", SYMLINK+="EndoCam"
After rebooting, I now saw two video symbolic links under /dev
.
lrwxrwxrwx 1 root root 6 Feb 11 20:04 EndoCam -> video5
lrwxrwxrwx 1 root root 6 Feb 11 19:20 PrusaWebCam -> video0
Troubleshooting 3:
Recheck your 99-usb.rules
file. Make sure the syntax is correct, that the serial number and vendor ID are correct, and that you don’t have any strange characters like “smart quotes” or anything else that isn’t a standard ASCII character.
4: Prepare octopi.txt file for new webcam:
Under /boot
there is an octopi.txt
file which is a configuration file for the webcamd
service (more on that service later). If you have your Raspberry PI camera running, then octopi.txt
is set up to configure your PI cam. We’ll copy that file and use it to configure our webcam.
> cd /boot
> sudo cp octopi.txt octopi2.txt
> sudo nano octopi2.txt
Edit octopi2.txt:
Change the text
camera="raspi"
(or it might becamera="auto"
) tocamera="usb".
The line might be commented out, indicated by a “#” (pound, or hash symbol) at the beginning of the line. Make sure to remove the # at the beginning of the line, otherwise changing the line to read
camera="usb"
will have no effect.
NOTE: Some people have reported not seeing a “camera” entry at all in their octopi.txt file. If that’s the case, you’ll need to add one yourself.
Remove the
#
from in front of the line that starts withcamera_usb_options
to uncomment it. Currently, it should look something likecamera_usb_options="-r 640x480 -f 10"
Change that line to point to your USB camera. You’ll do that by adding a
-d
flag with the name you gave your USB camera. Here’s what my camera usb options looks like:
camera_usb_options="-d /dev/PrusaWebCam -r 1280x720 -f 10"
NOTE: Be conservative with your resolution and framerate settings. A Logitech C920 can support 1920x1080 at 30 frames per second. However, your Raspberry PI can’t keep up with the camera, especially if it’s running a PI Cam module and Octoprint. So, I recommend setting USB cameras as 1280x720 and 10 fps.
If your camera supports higher resolution you can experiment with changing the -r
setting (resolution) from 640x480
to a different resolution, like I did in my example above. The -f
flag is for framerate.
Further down in
octopi2.txt
you’ll need to comment out the line that starts withcamera_raspi_options
by adding a#
in front of it.Finally, remove the
#
from in front of the line that starts withcamera_http_options
to uncomment it (should be at the very end of the file) and change it to readcamera_http_options="-p 8081"
That sets the port for your webcam to 8081.
You’re done with this file and can save and close it.
Now let’s edit octopi.txt (the config file for your Raspicam):
> sudo nano octopi.txt
To avoid the original octopi.txt
from starting up the wrong camera, let’s edit it as well and make sure camera
is set to raspi
and not auto
.
Find the
camera
line and make sure it readscamera="raspi"
instead ofauto
NOTE: As mentioned above, your octopi.txt file might not have a “camera” entry. If that’s the case for you, add one and set it to
camera="raspi"
Set the port of the PI camera to 8080 by uncommenting the last line of the file, which should be
camera_http_options
by deleting the#
in front of the line.Make the line read
camera_http_options="-p 8080"
Save and close the file
5: Prepare webcamd service files:
First we’ll duplicate the existing webcamd file.
> cd /root/bin
> sudo cp webcamd webcamd2
Now let’s edit webcamd.
> sudo nano webcamd
Toward the top of the file, make sure the line that starts with
cfg_files+=
points tooctopi.txt
. It should read:cfg_files+=/boot/octopi.txt
Further down in the file, look for two lines that read:
# add video device into options
options="$options -d /dev/$device"
Add a
#
in front of theoptions
line to comment it out.#options="$options -d /dev/$device"
That line only works when you have a single camera connected, otherwise it causes problems.
We’ll make almost the same edits to webcamd2.
> sudo nano webcamd2
Toward the top of the file, make sure the line that starts with
cfg_files+=
points tooctopi2.txt
(our second octopi configuration file). It should read:cfg_files+=/boot/octopi2.txt
Comment out the same
options
line as you did in webcamd.#options="$options -d /dev/$device"
6: Set up service for webcamd2:
Now that we have our webcamd2 file ready, we need to create a service start file. We’ll copy an existing service file and edit it.
> cd /etc/systemd/system/
> sudo cp webcamd.service webcamd2.service
> sudo nano webcamd2.service
Change the
ExecStart
line to readExecStart=/root/bin/webcamd2
Save and close the file.
Now let’s inform Linux about the webcamd2 service so it will get started at boot time:
> sudo systemctl enable webcamd2
7: Set up camera proxy:
The final step for running a second webcam on Octopi, is to set up a proxy. The proxy links the internal webcamd2 camera service to an http port, allowing you (and Octoprint) to view the camera’s mpeg stream from a browser.
> cd /etc/haproxy
> sudo nano haproxy.cfg
Under the
frontend public
heading add the following line:use_backend webcam2 if { path_beg /webcam2/ }
There will already be an entry for
webcam
. Copy the entirebackend webcam
section and paste it below the first entry. We’ll make a couple of changes to have it point to the second webcam. It should look like this:
backend webcam2
reqrep ^([^\ :]*)\ /webcam2/(.*) \1\ /\2
server webcam1 127.0.0.1:8081
errorfile 503 /etc/haproxy/errors/503-no-webcam.http
Notice a few things:
regrep line changed to read
webcam2
server
line port changed to 8081, the port we assigned the second camera in an earlier step.HOWEVER, the server name should remain
webcam1
. That’s not a typo above. Tricksy Linux.
Here’s what the two backend
entries look like in my haproxy.cfg
file.
backend webcam
reqrep ^([^\ :]*)\ /webcam/(.*) \1\ /\2
server webcam1 127.0.0.1:8080
errorfile 503 /etc/haproxy/errors/503-no-webcam.http
backend webcam2
reqrep ^([^\ :]*)\ /webcam2/(.*) \1\ /\2
server webcam1 127.0.0.1:8081
errorfile 503 /etc/haproxy/errors/503-no-webcam.http
Now you can reboot and you should see output from your second camera by pointing a browser to port 8081 on your Octopi box. Example: I have Bonjour setup and called my Raspberry PI box “octopi”, so the URL for the second camera within my home network is: http://octopi.local:8081/?action=stream
If you don’t see your USB camera at port 8081, move on to step 8 for troubleshooting tips.
8: Troubleshooting Services
The most common issue after not seeing your camera listed under /dev is problems with the service that launches mjpg streamer for the USB camera.
If you don’t see your USB webcam show up at port 8081, do you see it under /dev, then the service that starts up mjpg streamer is having a problem. To confirm this, run the following systemctl command:
> systemctl status webcamd2.service
If the service started up correctly, you’ll see something like this:
● webcamd2.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd2.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2021-02-27 15:16:51 PST; 9min ago
Process: 340 ExecStart=/root/bin/webcamd2 (code=exited, status=0/SUCCESS)
Main PID: 486 (mjpg_streamer)
Tasks: 4 (limit: 1939)
CGroup: /system.slice/webcamd2.service
└─486 ./mjpg_streamer -o output_http.so -w ./www-octopi -p 8081 -i input_uvc.so -d /dev/LogiCam -r 640x480 -f 5
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: Format............: JPEG
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: TV-Norm...........: DEFAULT
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: www-folder-path......: ./www-octopi/
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: HTTP TCP port........: 8081
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: HTTP Listen Address..: (null)
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: username:password....: disabled
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: commands.............: enabled
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: starting input plugin input_uvc.so
Feb 27 15:16:50 octopi2 mjpg_streamer[486]: MJPG-streamer [486]: starting output plugin: output_http.so (ID: 00)
Feb 27 15:16:51 octopi2 systemd[1]: Started the OctoPi webcam daemon with the user specified config.
However, if the service failed to start up correctly, you’ll see something like this:
● webcamd2.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd2.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Sat 2021-02-27 15:28:51 PST; 1min 35s ago
Process: 350 ExecStart=/root/bin/webcamd2 (code=exited, status=0/SUCCESS)
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: starting application
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: MJPG Streamer Version: git rev: 5554f42c352ecfa7edaec6fc51e507afce605a34
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: Using V4L2 device.: /dev/video3
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: Desired Resolution: 640 x 480
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: Frames Per Second.: 5
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: Format............: JPEG
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: TV-Norm...........: DEFAULT
Feb 27 15:28:50 octopi2 mjpg_streamer[484]: MJPG-streamer [484]: init_VideoIn failed
Notice the last line. It reads init_VideoIn failed
. AND THIS IS WITH THE SAME CAMERA WITH THE SAME SETTINGS.
Troubleshooting Tip 1:
Reduce the resolution and frame rate of both your PI Camera and your USB webcam.
Your Raspberry PI is amazing, but it still must obey the laws of physics, and you just might be asking it to do too much. Remember, your PI is running Linux, Octoprint and two video streaming services.
Here are the settings for my PI Cam and Logitech C510 in octopi.txt and octopi2.txt, respectively:
// octopi.txt -- raspi cam settings
camera_raspi_options="-x 1280 -y 720 -fps 10"
// octopi2.txt -- USB cam settings
camera_usb_options="-d /dev/PrusaWebCam -r 1280x720 -f 10"
Both cameras support resolutions of 1920x1080 and frame rates of 30fps, but setting the cameras to their max values caused the cameras not to start up. Sometimes I’d get one, or the other, but never both at the same time.
NOTE: Don’t set your frame rate to less than 5. While testing, I set my USB camera to -f 1
and discovered in the logs that the value was being pushed up (or “coerced” in video4linux speak) to 5. Seems like Linux doesn’t like frame rates that low.
Troubleshooting Tip 2:
Switch the camera to another USB port.
This shouldn’t matter, but apparently it can make a difference. Follow this procedure:
Boot your PI, confirm that the service didn’t load properly.
Move the USB camera to another port while the PI is still on.
Reboot your PI.
Check the service status.
Troubleshooting Tip 3:
Change the service’s restart delay.
By editing webcamd2.service you can change the delay before the service controller tries to restart a failing service.
sudo nano /etc/systemd/system/webcamd2.service
Change the RestartSec setting to 3, instead of 1, which is the default.
RestartSec=3
UPDATE February 27, 2021:
Added new services troubleshooting section, and updated the camera configuration section with comments about limiting resolution and frame rates.
UPDATE February 11, 2021:
Added a new troubleshooting section with information about confirming the camera set up and configuring cameras without serial numbers.
UPDATE February 7, 2021:
TL;DR:
Because of issues with HTML and Unicode, the code fragments in the instructions below had curly quotes (“) instead of straight quotes ("). Anyone that copied text off this page was unknowingly pasting in curly quotes that caused the Linux configuration files to not work. I’ve gone through and updated all the code sections and confirmed that everything works in Octopi 0.18.
The full story (for those who are curious):
A couple of weeks ago this post started getting a flurry of comments and questions, seemingly related to the instructions below not working when users updated to Octopi 0.18. The most common complaint was that only one camera (typically the PI cam) would work, while the USB camera didn’t connect.
To investigate why Octopi 0.18 didn’t work as expected, I took a spare Raspberry PI and installed a fresh copy of Octopi 0.18. Octoprint 1.5.2 worked correctly, as did a spare Raspberry PI camera module I have.
I followed my own instructions to connect a spare USB camera — I apparently have a lot of spare parts — and it didn’t work. The webcamd2 service I had created tried over and over to connect to the USB camera but failed. For a couple of hours I went down various rabbit holes, reading through comments, trying various approaches and learning more about the vagaries of Linux configuration. At one point, I even compared configuration files from Octopi 0.17 and 0.18, looking for a bug.
After ruling out issues with all the other configuration files I had created or edited, I was left with just one: the 99-usb.rules file. That’s how you tell the USB system about your USB camera and set up a symlink/alias to the camera. The alias/symlink is supposed to show up under /dev
with whatever name you gave in your rules file. I had called my USB camera TestCam, but there was no entry under /dev
.
I checked my working Octopi 0.17 build and sure enough, I saw a symlinked entry under the /dev directory. When I compared the two 99-usb.rules files from my Octopi 0.17 and 0.18 installations, I saw what was going on. The Octopi 0.18 rules files had curly quotes (“) instead of standard straight quotes ("). Curly quotes — also known as “smart” quotes — are fancy quotes used in word processors and webpages, but they don’t belong in text-only Linux configuration files. Putting curly quotes in configuration files is like putting diesel in a gasoline engine. It don’t work.
The only text I had copied and pasted from this blog entry had been for the usb rules file. And, when I checked, I saw that the usb rules text in the post had curly quotes in it. Once I edited 99-usb.rules
, replaced the stupid smart quotes with regular ASCII straight quotes and rebooted, the USB camera showed up under /dev
, webcam2 service was able to find it and start up, and the camera worked correctly. I then went through all the code sections in this blog post and ensured that none contained curly quotes.