Current Raspberry Pi FPV Scripts

This page contains the current bash scripts I have developed for streaming video from the Raspberry Pi camera to a Linux Laptop.  I will update this page as I make improvement and additions to the scripts.

These scripts assume you have generated a ssh public key on your laptop and uploaded it onto the Pi.  This will allow ssh to contact the Pi without you having to type a password every time.  I’ve outlined how to do this in one of the comments below.

Script Usage

  1. Configure the network.conf and video.conf files
  2. Boot the Raspberry Pi
  3. Connect the laptop WiFi to the Raspberry Pi’s Wifi Access Point
  4. Open a terminal on the Laptop
  5. run the ./go script on the laptop to update the configuration files on the Pi and set the time and date.
  6. The go script will leave you in a ssh session on the Pi
  7. run the ./ustream or ./utee scripts on the Pi.
  8. Open a second terminal on the laptop.
  9. run the ./tsplay or ./uts scripts on the Laptop
  10. The video will start streaming.

Laptop Scripts

1.  Network Configuration File

Filename: network.conf
Command line options: none


# TX_IP should contain the IP address of the Raspberry Pi.
export TX_IP=
export RX_IP=$(ip -o addr show wlan0 | sed -n 's/.*inet \([0-9.]*\)\/.. .*/\1/p')
export TCPPORT=5000
export UDPPORT=5001

export USER=pi


2. Video Configuration File

Filename: video.conf
Command line options: none


###### Video Settings ######
# Zero duration is continuous
export DURATION=0
export WIDTH=1280
export HEIGHT=720
export FRAMERATE=48
export BITRATE=6000000


3. Upload Configuration and start a remote shell on the Pi

Filename : go
Command line options : Frame rate in frames per second.  Must be suitable for the selected video resolution.


source network.conf

rm remote.conf

if [ "$1" != "" ] 
  sed "s/FRAMERATE=25/FRAMERATE=$1/" video.conf > remote.conf
  cp video.conf remote.conf

echo "###### Network Settings ######" >> remote.conf
echo export TCPPORT=$TCPPORT >> remote.conf
echo export UDPPORT=$UDPPORT >> remote.conf
echo export RX_IP=$RX_IP >> remote.conf
echo export NOW=\"`date +%F" "%T`\" >> remote.conf

#echo exit >> remote.conf

chmod +x remote.conf

echo Copy script to $TX_IP
scp remote.conf $USER@$TX_IP:/home/pi

echo Run Script
ssh $USER@$TX_IP ./
ssh $USER@$TX_IP


4. Capture and play a UDP stream – Does not record the stream

Filename : tsplay
Command line options : none

source ./video.conf
source ./network.conf

gst-launch-1.0 -v udpsrc port=$UDPPORT \
  caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! \
  rtph264depay ! h264parse config-interval=96 ! \
  avdec_h264 ! videoconvert ! autovideosink sync=false


5. Capture, play and record a UDP stream – saved file is muxed to a transmission stream (.ts) container

Filename : uts
Command line options : none

source ./video.conf
source ./network.conf

NOW=`date +%Y%m%d%H%M%S`

gst-launch-1.0 -v udpsrc port=$UDPPORT \
  caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! \
  rtph264depay ! h264parse config-interval=96 ! \
  tee name=t ! queue ! \
  video/x-h264, framerate=$FRAMERATE/1 ! avdec_h264 ! videoconvert ! autovideosink sync=false t. ! \
  queue ! mpegtsmux ! filesink location=$FILENAME


Raspberry Pi Scripts

6. Stream the Camera over UDP without recording locally.

Filename : ustream
Command line options : Frame rate in frames per second.  Must be suitable for the selected video resolution.


source remote.conf

if [ "$1" != "" ]
  export FRAMERATE=$1

NOW=`date +%Y%m%d%H%M%S`

/opt/vc/bin/raspivid -t $DURATION -w $WIDTH -h $HEIGHT -fps $FRAMERATE -b $BITRATE -n -pf baseline -o - | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=$RX_IP port=$UDPPORT


7. Stream the Camera over UDP and save local copies of the video (.h264) and the GPS trace (.gpx).

Filename : ustream
Command line options : none.

source ./remote.conf

NOW=`date +%Y%m%d%H%M%S`
gpxlogger -i 2 -f $NOW.gpx &

/opt/vc/bin/raspivid -t $DURATION -w $WIDTH -h $HEIGHT -fps $FRAMERATE -b $BITRATE -n -pf baseline -o - | tee $FILENAME | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=$RX_IP port=$UDPPORT


16 responses to “Current Raspberry Pi FPV Scripts

  1. Hi,
    First, thanks for sharing. in point 6, could you explain what are the commands -n -pf high for ?

    besides that, i tried 48fps and 6000000 bitrate, as you advise, what a huge difference with crap video i got in 30fps. Thanks again ! Need to try during flight now..

    • Hi,

      The -n switch is “No Preview”. Without it the Pi will send the video to the video out port. In my earliest tests, I found this added about 80ms to the latency. Whether it will attempt it if nothing is connected to the hdmi or composite ports, I don’t know, but better safe than sorry. Full details of the raspivid command line switches are available in the Raspberry Pi Camera Documentation

      The -pf high relates to the h264 “high” profile. Essentially there are three profiles: baseline, high and main. They specify what features are available to the encoder. Baseline has the maximum compatibility. High includes features that reduce the required bandwidth, but are less compatible with some older devices. There is a good discussion at

  2. i noticed that when you save video on Pi while streaming (point 7), you don’t use -pf high, is it to save cpu load ?
    Also, did you try rpicamsrc element ? seems some guys get lower latency with it. I guess it would give something like gst-launch-1.0 rpicamsrc ! ‘video/x-h264, width=1280, height=720, framerate=48/1

    • Re: Point 7. Actually I just forgot to add it in. It’s there now.
      Free time has been short of late. I haven’t followed the development of rpicamsrc. I can see some more testing coming. Thanks for the heads up.

  3. everything seems to work except when running ./go i get error

    remote.conf 100% 285 0.3KB/s 00:00
    Run Script
    pi@‘s password:
    bash: ./ No such file or directory

    and it continues from there as if there was no issue until i run the ./ts play it says it is playing but i dont see anything.

    help please!

    • You need to create a key for ssh, so that you don’t have to enter your password to login to the pi.

      On the receiving end computer run ssh-keygen in a terminal. Accept all the defaults, DON’T enter a passphrase when prompted.
      ~ $ ssh-keygen
      Generating public/private rsa key pair.
      Enter file in which to save the key (/home/pi/.ssh/id_rsa):
      Created directory '/home/pi/.ssh'.
      Enter passphrase (empty for no passphrase):
      Enter same passphrase again:
      Your identification has been saved in /home/pi/.ssh/id_rsa.
      Your public key has been saved in /home/pi/.ssh/
      The key fingerprint is:
      09:c6:4a:7e:8c:36:4b:a3:1b:30:d8:4e:0b:b6:9a:b6 pi@PiCam
      The key's randomart image is:
      +--[ RSA 2048]----+
      | |
      | . |
      | . + |
      |.. o = . . |
      |=.o O o S |
      |.*.= = |
      | .= . |
      |.o o |
      |+Eo |

      This creates a pair of files in a hidden directory .ssh

      ~ $ cd .ssh
      ~/.ssh ~ ls

      These are your public and private key pair. You need to copy the public key to the transmitting Pi. I use this script


      source ./network.conf

      scp ~/.ssh/ $USER@$TX_IP:.ssh/authorized_keys

      Make sure the .ssh directory exists on the pi before you run the script. You will need to enter the password to copy the script.

      From here on you should be able to enter ssh pi@ and get a remote shell without having to enter a password.

      To get the stream running follow this sequence.
      1. On the receiving machine run ./go This will copy the configuration files across and drop you into a remote shell on the transmitting Pi.
      2. In the remote shell start the stream ./ustream
      3. Start a new terminal on the receiving machine and run the play script ./tsplay
      4. If all goes well a window should pop up showing the video.

  4. Hi,
    thanks for all that testing… lots of good stuff here…

    i`ve been looking into it for a while now.. and my intent is to stream with gstreamer and open it on a webpage.

    looks like i`ve found something that does it and i`d like to share.

    and there`s also this site that may even further help with your latency problem. maybe you can give it a try when you have the time. i`d love to see the stats for it.

  5. nice work dude – FYI: I’m currently working on a similar solution. The difference is that I’m running a node.js server component on the Pi and I use an Android App on my mobile to control it and for video playback. Streaming is working fine so far but I’m still working on the functionality to get the telemtry data from the flight controller and to draw a HUD as an overlay on the screen.
    I’ll publish the code somewhare when I’m done and let you know.

    Did you have time to try this real time kernel in the meantime?

    • Cheers Peetie. Up to now, I’ve been concentrating on getting the latency as low as possible in what little time I have available. Today I managed to get the 5 GHz WiFi working with Pi2B, so now I can get the last couple of bench tests complete and start flight testing around other people.
      I haven’t tried the real-time kernel yet. Compiling on the Pi2 has proven a challenge.
      What sort of range can you get to a mobile phone?

    • Hi Peetie,

      Could you tell which Android app are you using for viewing?
      I tried AirPi but it seems that the image for the RPI side is not complete so I am looking for an alternative solution…

  6. Thank you for your reply – did not do any range tests yet.
    However I don’t assume that it’s much shorter than using a notebook. I’ll let you know when it tested the range…

    • Hey gary,

      Ok, no news on the range front (no testing done yet), but something else which might be interesting to you as well. I thought about the command running and about eliminating buffers. Since we pipe two commands, I thought about pipe buffering and read about it:

      For sure we need to get rid of as many buffering as possible inside the system that’s why I was looking how to disable the pipe buffering. Seems like stdbuf of GNU coreutils is doing the job.

      I’m currently running the following script on my Pi1B – which subjectively is a bit smoother with disabling the pipe buffer than having a pipe buffer in the system.

      stdbuf -i0 -o0 -e0 raspivid -n -w 640 -h 480 -b 6000000 -fps 45 -g 1 -vf -hf -t 0 -o – | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=20 pt=30 ! udpsink host=$1 port=$2

      If you still have your testenvironment set up, it would be great to see whether this squeezes out some more millisecons.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s