YouTube player

In this project the Raspberry Pi with the PiCam is used as a wireless camera which can transmit images over long distances, usually hundreds of meters! Images are transmitted by amateur radio (ham radio) using slow scan television (SSTV) on the 2 meter band (144.5MHz).

Thanks to Oliver Mattos and Oskar Weigl the Pi can generate the high-frequency FM signal itself — no additional electronics are needed for low-power transmissions. For a little bit more power, a one or two transistor amplifier would be suitable. Furthermore a low pass filter is recommended to filter out higher harmonics of the signal.

This project also contains a Python script which detects movement. Using this script, the Raspberry Pi can be used as a wireless security cam at distances far outside the range of normal WiFi networks. Be aware that you need a ham-radio license to use this application!

Here’s how I made it work. Follow the steps below; the project code can be found on my blog or on my GitHub page.

Credits to KI4MCW (SSTV), Oliver Mattos and Oskar Weigl (PiFm).

pisstv_camera_small

What will the next generation of Make: look like? We’re inviting you to shape the future by investing in Make:. By becoming an investor, you help decide what’s next. The future of Make: is in your hands. Learn More.

Project Steps

Connect the hardware

The only hardware used for this project is a Raspberry Pi, a Pi NoIR camera, a PiFace Control & Display board, and a piece of wire which serves as antenna.

For portable use, stick a 5V USB battery pack to the Raspberry Pi case with a piece of duct tape.

Capturing the image

The first thing to do is capturing the image we want to transmit. This can easily be done with the raspistill command-line utility:

raspistill -t 1 --width 320 --height 256 -e png -o /tmp/image.png

For SSTV we need a small image of 320×256 pixels. It is saved into the /tmp directory as a PNG image file.

Converting the image to a SSTV sound file

Next we need to convert the image to a sound file which can be transmitted over the air. There are several SSTV implementations available for the Raspberry Pi.

The first one tested is PiSSTV, a Python implementation. It works but it’s very slow — it takes several minutes to convert a single image. (For details see my blog.)

Next I found a plain C implementation by ham KI4MCW (Robert Marshall). Unfortunately there were some errors in the preamble tones, but those were easy to fix. I also made it a little more flexible so you can set the audio sample rate from the command line.

Source of my implementation can be found on GitHub. To compile the source code:

pi@rpicamera ~/sstv $ sudo apt-get install libgd2-xpm-dev

pi@rpicamera ~/sstv $ sudo apt-get install libmagic-dev

pi@rpicamera ~/sstv $ gcc -lgd -lmagic -o pisstv pisstv.c

To run the program:

pi@rpicamera ~/pisstv $ ./pisstv /tmp/image.png 22050

Constants check:

rate = 22050

BITS = 16

VOLPCT = 20

scale = 6553

us/samp = 45.351474

2p/rate = 0.000285

Checking filetype for file [/tmp/image.png]

File is a PNG image.

Input file is [/tmp/image.png].

Output file is [/tmp/image.png.wav].

Writing audio data to file.

Got a total of [2589556] samples.

Done writing to audio file.

Created soundfile in 4 seconds.

As you can see, the SSTV sound file is created in just 4 seconds. So far so good. Next step: how to transmit the audio over the air.

Transmitting the sound file with PiFm

You can add a radio transmitter, like a portable radio transceiver, but it’s much more fun to let the Pi itself generate the high-frequency signal. This is possible thanks to PiFm software by Oliver Mattos and Oskar Weigl (see our Raspberry Pirate Radio project here).

You can find their code here. It has evolved considerably: The first version was very simple, but used all CPU cycles, and the signal was hampered by glitches when other processes were active. The last version uses DMA and works pretty well, without eating up all CPU cycles. Nevertheless the code is much more complex now.

Oliver and Oskar did a very good job, but out of the box the PiFm software is not suitable for ham radio and SSTV. There are 2 main problems. Firstly the bandwidth is too high, and secondly the timing, which is very important for SSTV, was a little bit off.

Reducing the bandwidth

Reducing the bandwidth appeared to be very simple. As every ham knows, for frequency modulation the bandwidth can be set with the modulation index, which is equal to the volume of the audio signal which modulates the HF carrier. In the source code it is just one value; it can be found in the consume function of the Outputter/ class.

Here's the original code:

void consume(float* data, int num) {

for (int i=0; i<num;i++){

float value = data[i]*8; // modulation index (AKA volume!)

I made a command-line parameter of this value. The new code looks like this:

void consume(float* data, int num) {

for (int i=0; i<num;i++){

float value = data[i]*modulation_index; // modulation index (AKA volume!) (original 8)

Unfortunately this doesn't work very well, very strong sidebands persists, so this needs some focus in future versions of the software.

The first figure shows a spectral plot of the full bandwidth FM signal.

The second spectrum is the reduced bandwidth. Tuning on the peak in the middle shows a nice clean signal, but we need to get rid of the sidebands.

The last image is the reduced bandwidth signal of the first version of PiFm, nice bandwidth, but the signal is hampered by clicks due to cpu activity in other processes.

Fixing the timing

When the sample rate of audio transmitted by PiFm is slightly larger or smaller, a listener hardly notices any difference. For SSTV this is not the case, SSTV timing is very precise.

A slightly off sample rate results in slanted images, as can be seen in the first image.

The second image is the same sound file properly sampled.

Fixing the timing appeared to be straight forward, just by adapting the timing constant in the source code.

//clocksPerSample = 22500.0 / rate * 1373.5; // for timing, determined by experiment

clocksPerSample = 22050.0 / rate * timing_correction; // for timing, determined by experiment

As you can see I replaced the timing constant (1373.5) in the code with the variable timing_correction which can be set from the command line. I expect a different value for each individual Raspberry Pi. In my case the value is 1414.0. I’m just curious which is the proper value for you — please comment on your value in the comments below! For all other adaptations to the code, see the source file at GitHub.

Adding call-sign

When you start transmitting SSTV signals using your ham radio license, you’re required to transmit your call-sign in every transmission, so we need to add this information to the image.

This can easily be done either from the command line using imagick, or from python using the Python Image Library (PIL). Both are used in this project.

Catching movement

Now we’re able to grab an image and send it properly over the air using PiFm. Next we need to focus on triggering the image capture when something interesting happens in front of the camera. I have implemented this in Python, using PIL. The code is quite straightforward, it just compares the pixels of the previous image with the current image. When the difference is too large, the current image is transmitted.

Here’s a code snippet:

# loop forever while (True):

# grab comparison image

imgnew, bufnew = captureImage()

# Count changed pixel

changedPixels = 0

for x in xrange(0, 320):

for y in xrange(0, 256):

# Just check red channel as it's dominant for PiCam NoIR

pixdiff = abs(buf[x,y][0] - bufnew[x,y][0])

if pixdiff > threshold:

changedPixels += 1

# Transmit an image if pixels changed

if changedPixels > sensitivity:

# Swap comparison buffers

img = imgnew

buf = bufnew

transmitImage(img.copy())

Again, the full code can be found on the GitHub page. Please share your builds and mods in the comments below!