Kronalias
Posts: 13
Joined: Sat Dec 22, 2012 4:39 pm

FM Radio Telemetry Hack

Wed Mar 13, 2013 3:25 pm

This is based on the work of turning the Pi into an FM transmitter here:
http://www.icrobotics.co.uk/wiki/index. ... ransmitter
that was then excellently enhanced by rgh here:
http://www.raspberrypi.org/phpBB3/viewt ... 12#p235412

If you're going to play with this then please be socially responsible, as you're likely to be:
(a) illegal as you're transmitting without licenced equipment
(b) probably exceeding the allowable power, even if you were legal
(c) transmitting harmonics
If you can get away without using one then don't use an aerial - but if you must then keep it as short as possible.
And please don't use this outside your bricks and mortar - they'll at least provide some kind of barrier to rf propagation.

Here are links to the youtube channel and video showing data transmission
http://www.youtube.com/user/Kronalias
http://www.youtube.com/watch?v=WrduqCQKVLk


You need the following bits of software:

PiFmDma - get it from github:
https://github.com/richardghirst/PiBits ... er/PiFmDma
Download the two files (Makefile and PiFmDma.c) into a directory, go there and type:
make
This'll compile it and you should have an executable called PiFmDma.

A decoder - I use minimodem. Get it from the following link to have the most up-to-date version:
http://www.whence.com/minimodem/

Now for two of mine:
markspace.pl
This generates two files called mark.wav and space.wav. You define what the baud rate and frequencies are.
Look inside the files and modify the paths for your system - my transient files are held in /mnt/ramdisk, but this is unlikely to exist on your Pi.
Then run it - this works for me:
./markspace.pl 140 2295 2125

Code: Select all

#!/usr/bin/perl

# This requires the following Perl modules:
# sudo cpanm --verbose Audio::Wav
# When run it may install an _Inline directory in the current directory (it does on my laptop, but not on the Pi)
# Just delete it when you've finished with the program

use strict;
use warnings;
use Audio::Wav;

my $markfile = '/mnt/ramdisk/mark.wav';
my $spacefile = '/mnt/ramdisk/space.wav';

if ($#ARGV != 2) {
    print "Usage: ./markspace.pl [baud] [mark_freqency [space_frequency]  e.g.\n./markspace.pl 50 2295 2125\n";
    exit;
}

my $baudrate = $ARGV[0];
my $pulselength = 1/$baudrate;

my $mark = $ARGV[1];
my $space = $ARGV[2];

my $sample_rate = 22050;
my $bits_sample = 16;

my $details = {
    'bits_sample'   => $bits_sample,
    'sample_rate'   => $sample_rate,
    'channels'      => 1,
    'no_cache'     => 1,
};

my $mark_wav = new Audio::Wav;
my $write = $mark_wav -> write( $markfile, $details );
&add_sine( $mark, $pulselength );
$write -> finish();

my $space_wav = new Audio::Wav;
$write = $space_wav -> write( $spacefile, $details );
&add_sine( $space, $pulselength );
$write -> finish();

print "Run this command on the client:\nminimodem --rx $baudrate --mark $mark --space $space --stopbits 2.5 --ascii --quiet\n";
print "and then run fm_ascii.pl on the Pi.\n";

sub add_sine {
    my $hz = shift;
    my $length = shift;
    my $pi = ( 22 / 7 ) * 2;
    my $time;
    $length *= $sample_rate;
    my $max_no =  ( 2 ** $bits_sample ) / 2 - 1;
    for my $pos ( 0 .. $length ) {
        $time = $pos / $sample_rate;
        $time *= $hz;
        my $val = sin $pi * $time;
        my $samp = $val * $max_no;
        $write -> write( $samp );
    }
}
Once you've made mark.wav and space.wav you'll need
fm_ascii.pl
This is a Perl script that takes a command line parameter of a text file and then manufactures and transmits wav files (using the mark.wav and space.wav above) of this text file.
Again, you need to look inside it and tweak paths to suit your own system.
If you want it to transmit itself, then the command would be something like:
./fm_ascii.pl fm_ascii.pl

Code: Select all

#!/usr/bin/perl

use strict;
use warnings;

my $markfile = '/mnt/ramdisk/mark.wav';
my $spacefile = '/mnt/ramdisk/space.wav';
my $outfile = '/mnt/ramdisk/ascii.wav';

if ($#ARGV != 0) {
    print "Usage: fm_ascii.pl text_file_to_transmit\n";
    exit;
}

my ($line, $cmd, $i, $j, $chr, $ord, $bin);

# We're using sox to concatenate wav files - and it can only do so many at time
# It looks as if we can only(?) concatenate about 77 characters at 13 bits per char (2 rest, 1 start, 8 data, 2 stop)
# The decoder (minimodem) seems to work ok at 140 baud, 1 start, 8 data, 2.5 stop (trying other startbits crashes it)
# On that basis, we'll dump to fm every 30 characters, thus giving oodles in hand.
my $charcount = 0;
my $maxchars = 30;

open (MYFILE, $ARGV[0]);
while (<MYFILE>) {
    chomp;
    $line = $_ . "\n";
    $cmd = '';

    # encode one line into a wav file
    for ($i=0; $i<length($line); $i++) {
        $chr = substr ($line, $i, 1);
        $ord = ord (substr ($line, $i, 1));
        $bin = sprintf("%08b",$ord);
        $cmd .= $markfile . ' ' . $markfile . ' ';	# start with a couple of bits of rest
        $cmd .= $spacefile . ' ';	# and then one start bit
        for ($j=7; $j>=0; $j--) {	# 8 data bits
            if (substr($bin, $j, 1) eq 1) {
                $cmd .= $markfile . ' ';
            } else {
                $cmd .= $spacefile . ' ';
            }
        }
        $cmd .= $markfile . ' ' . $markfile . ' ' . $markfile . ' ';	# three stop bits
        $charcount++;
        if ($charcount == $maxchars) {
            # write the line encoded as a wav
            $cmd = 'sox ' . $cmd . $outfile;
            `$cmd`;

            # and transmit it
            `sudo ./PiFmDma $outfile`;

            $charcount = 0;
            $cmd = '';
        }
    }

    # deal with any leftovers after we've sent the line in $maxchar chunks
    if ($charcount > 0) {
        $cmd = 'sox ' . $cmd . $outfile;
        `$cmd`;
        `sudo ./PiFmDma $outfile`;
    }
}
close (MYFILE); 

unlink $outfile;

exit;

Connect an FM radio headset output to your audio input on a laptop or PC. A 3.5mm to 3.5mm stereo audio cable works fine, even though the file that you're tranmitting will be in mono. The volume doesn't need to be very high (no more than about a quarter of max, but you'll have to play with this).

Then, on a linux pc, you need to start the decoder. I use minimodem with this command:
minimodem --rx 140 --mark 2295 --space 2125 --stopbits 2.5 --ascii --quiet

Off you go to the Pi and run this to transmit the file:
./fm_ascii.pl fm_ascii.pl

And the other pc should now be receiving your transmission.

sethludwig
Posts: 5
Joined: Sun Jun 23, 2013 3:55 pm

Re: FM Radio Telemetry Hack

Sun Jun 23, 2013 5:43 pm

Very interesting post, thank you for the details! I might use this in a project I'm doing, once I check the FCC regulations.

fiskius
Posts: 25
Joined: Fri Dec 07, 2012 10:12 pm

Re: FM Radio Telemetry Hack

Mon Nov 11, 2013 11:54 pm

This is pretty cool! I've it working, except a lot of what I receive comes out garbled, I know it is the correct file. I've tried adjusting the FM radio tuning and volume, but can't get it quite right. Ultimately I'd like to use this to send data, but it needs to be accurate. Any advice? It must be possible, since dialup modems used this type of technology - but I guess there was a specified procotol for error correction. I don't know perl, so hoping to convert these examples into python eventually!
Thanks
Andy

Return to “General discussion”