Setting up a Camera Server


The picture shows the Raspberry Pi Zero W with the ZeroCam attached. (The ZeroCam still has its protective cover over the lens in that picture. You will need to take that off before taking pictures. I got my ZeroCam from
Pimoroni, but the PiHut appears to have an equivalent product.) The ZeroCam is a special camera for the Pi Zero. You can use the more expensive official camera, but it requires a special adaptor cable to connect it to the Zero. The ZeroCam is fine for CamChess. I housed the Zero in a "premium case" from PiHut. Despite its name, it was the cheapest case available. Here is a helpful video showing the set up of another ZeroCam project.

In my initial testing, I used a Raspberry Pi Zero W as the camera server, and sent pictures to my desktop computer over WiFi. More recently, I have configured the Zero as an Ethernet gadget and send the pictures to a Raspberry Pi 4B via a USB cable, which also powers the Zero. The set up for that is mostly the same as for WiFi, but is a little more complicated. Irrespective of the physical connection, the pictures are sent and received using the communications protocol TCP/IP. The Python code for sending and receiving the pictures remains the same. I will describe the WiFi set up first.

I installed Raspberry OS Lite on a micro-SD card using the Raspberry Pi Imager. Raspberry OS Lite does not include a desktop. If you boot Raspberry OS Lite with a monitor attached, you just get a teletype interface. That is fine when the Raspberry Pi is only being used as camera server. The Pi Zero will run the full version of Raspberry OS with a desktop, but that would slow it down. In fact, we do not need to attach a monitor to the Zero at all. We can do everything remotely. That is called running "headless".

Raspberry OS is a version of Linux, which makes the set up easier. It is a little more complicated with Windows. Here is a very helpful video explaining how to do it with Windows. The set up is essentially the same for Linux or a Mac, but it is not necessary to install PuTTY or Bonjour. After completing the basic set up, you can access the Zero remotely using SSH, and move files to the Zero using SCP. Here is an tutorial explaining how to do that. (N.B. You do not need the IP address for the Zero. You can use raspberrypi.local instead.) We need to use a few simple terminal commands. If you want to learn more, there are lots of good tutorials on the web. When you have set up SSH, use it to log into Zero, and type:

sudo apt update
sudo apt full-upgrade
sudo apt-get install python-picamera python3-picamera
sudo raspi-config

You will need to enable the camera. Select Interface Options using the cursor keys and the Return key. Select Pi Camera. Select Enable and Finish. Accept Yes to reboot now. The ZeroCam should then be fully operational.

You will need to get PiCam.py from GitHub. Click the Code button to download all the CamChess files. (You can also use the "Go to file" button to copy and paste individual files.) When you have the PiCam.py on your computer, you can use SCP to copy it to the home directory on the Zero. (You may get: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! You can fix that by following the instructions given in the warning.) When you have copied PiCam.py to the Zero's home directory, you can run it using SSH:

ssh pi@raspberrypi.local

(Type the Zero's password.)

python3 PiCam.py

The camera server will then start up. You should see Camera initialised, followed after a pause by Server listening...


You will need to install CamChess on a connected computer. I used a Raspberry Pi 4B, which was more than fast enough. You could use a slower Raspberry Pi, but a Zero is likely to be too slow. If you are using a Raspberry Pi, you will need to change the host name to something other than raspberrypi (using Menu > Preferences > Raspberry Pi Configuration and rebooting the Pi). You will then be ready to launch CamChess on that computer. When you have set up CamChess, you can do that from a terminal by typing:

python3 ~/CamChess/CamChess.py

You can shut down CamChess by closing the window. The camera server will continue to run. You can shut down the camera server by typing Cntrl+C, and shut down the Zero with:

sudo poweroff

(It is not a good idea to cut the power to the Zero without shutting it down first. That could corrupt the micro-SD card.)

I found that the ZeroCam took just over half a second to take a picture. (N.B. I had increased the exposure compensation by one stop to make the dark green squares brighter.) The time taken to send the picture over WiFi was very variable. The time taken from requesting a picture from the server to receiving it on my desktop PC could be under a second, but was often several seconds, and was over 20 seconds on one occasion. (The Raspberry Pi Zero W supports only 2.4 GHz WiFi, which can be congested where I live.) That clearly is not acceptable for this application.


I avoided this problem by setting up a Zero as an Ethernet gadget. It is then possible to both supply power and send pictures over a wired USB connection. I was already using a USB to micro-USB adaptor and a USB extension cable to power the Zero. Fortunately, they were both data cables rather than just power cables. I was able to use them to connect the micro-USB socket on the Zero (not the power socket) to a USB socket on my desktop PC. This article describes how to set up a Zero as an Ethernet gadget. You can do that, by opening up the micro-SD card in a file manager. You will need to edit two files in the boot partition. Add this as the last line of config.txt:

dtoverlay=dwc2

Open cmdline.txt, and add a space after rootwait followed by:

modules-load=dwc2,g_ether

You can disable WiFi on the Zero W, by adding this to the end of config.txt:

dtoverlay=disable-wifi

Disabling WiFi on the Zero W ensures that the TCP/IP connection is via the faster USB interface and not the slower WiFi interface. (You can achieve the same result by swapping the micro-SD card over to a plain Raspberry Pi Zero without WiFi.)

I was able to connect to the Zero from my Raspberry Pi 4B (running Raspberry OS). I unplugged the Ethernet connector from the 4B and turned WiFi off. I connected a USB socket on the 4B to the micro-USB socket on the Zero. I then powered up the 4B. The connection showed up as usb0, and I was able to connect to the Zero by typing ssh pi@raspberrypi.local in a terminal on the 4B. You may get a warning that ECDSA for 'raspberrypi.local' differs from IP address xxx. If that happens, ignore the warning and type "yes".

It took about 10 seconds to open a TCP/IP connection from the 4B. After that, the performance was dramatically better than with WiFi. The time taken to send the picture was negligible in comparison with the time to take the picture. (The 10 second delay on opening a TCP/IP connection with a Ethernet gadget did not occur when I connected from Xubuntu 20.04 on my desktop computer.) The 10 second delay was eliminated by configuring static IP addresses for both ends of the Ethernet gadget connection. I added this to the end of /etc/dhcpcd.conf on the Zero:

interface usb0
static ip_address=10.0.0.1/24

and this to the end of /etc/dhcpcd.conf on the 4B:

interface usb0
static ip_address=10.0.0.2/24

I plugged the USB adaptor cable from the Zero into the 4B and powered up the 4B. I no longer had the 10 second delay on opening a TCP/IP connection. That was true even when I connected using raspberrypi.local rather than the IP address. The Zero was, however, no longer recognised by Xubuntu.


I hit a problem using the Ethernet gadget to connect to my desktop PC running Xubuntu 20.04. When I had completed the set up (without static IP addresses) and plugged in the USB cable, Xubuntu saw the gadget, but failed to connect. I found the solution for Ubuntu here. With Xubuntu, I opened the Advanced Network Configuration application, selected the relevant connection, clicked the cog at the bottom of the window, selected IPv4 settings, and used the Method pull-down to select Link-Local Only. The connection then worked, but Xubuntu allocated different wired connection numbers (i.e. device identifiers) every time I connected. I had to set Link-Local Only for each of those wired connection numbers. (That problem did not occur with the 4B.)

It should be possible to get round that problem. The network configuration can be done automatically using the command line interface nmcli rather than the Advanced Network Configuration application. It should be possible to write a Bash script to set Link-Local Only for the wired connection, run CamChess and delete the connection afterwards. Nonetheless, I found it more convenient to use the Raspberry Pi 4B.

Comments