This project demostrates building a high performance robot tele-op system using LiveKit that enables < 200ms latency video and controls. Everything needed to build the rover in this project was available off the shelf, costing no more than $200. The repo includes the source code that runs on the rover for streaming realtime video and receiving control messages via LiveKit. It also includes a Flutter app for remote teleop user for controlling the rover with a standard gamepad.
The rover is built with all off-the-shelf components costing less than $200 USD. This does not include the gamepad used by controller app.
- Raspberry Pi 4B 8GB - $75
- Raspberry Pi Camera V2 - $12
- Waveshare Rover - $99
- 3x 18650 batteries - ~$14
- Assorted mounting hardware & jumper cables
Total cost = $200
You will need a API key for LiveKit cloud or host your own LiveKit server to run this demo. Get a free account at https://cloud.livekit.io.
- Install batteries into rover.
- Install the Raspberry Pi onto the mounting bracket.
- Install the camera module onto the mounting bracket.
- Install the camera/compute bracket onto the rover.
- Connect 5V, ground, Uart TX/TX to the rover ESP32.
Before setting up the rover teleop software, you need to prepare your Raspberry Pi.
-
Install Raspberry Pi OS 64-bit (Bookworm):
- Download the Raspberry Pi Imager from raspberrypi.com/software.
- Use the imager to install Raspberry Pi OS 64-bit (Bookworm) on your SD card.
- Complete the initial setup process (create user, set timezone, connect to WiFi).
- This repo assumes you are configuring the Pi to use the default user
pi.
-
Enable required interfaces: Power up the Pi connected to a monitor, keyboard, and mouse to continue the setup. It should boot directly into a GUI desktop environment.
sudo raspi-config- Navigate to "Interface Options"
- Enable SSH
- Enable Serial port - but do not enable login shell on serial port.
- Enable I2C
- Enable SPI
- Reboot when prompted or run
sudo reboot
-
Disable booting into GUI interface
sudo systemctl set-default multi-user.target -
Set up the Raspberry Pi Camera v2:
- Connect the camera module to the Raspberry Pi's camera port
- Add the following to
/boot/firmware/config.txt:
sudo nano /boot/firmware/config.txt- Comment out the line that says:
camera_auto_detect=1- Add the following line:
dtoverlay=imx219,rotation=0- Save and reboot
-
Verify the camera is working:
rpicam-hello- You should see the detected camera image displayed
At this point, you should be able to ssh into the pi and do everything remotely.
Install other dependencies that the rover apps require:
-
Install uv (modern Python package manager):
curl -LsSf https://astral.sh/uv/install.sh | sh -
Install other dependencies
sudo apt install -y git -
Install Gstreamer
sudo apt install -y gstreamer1.0-libcamera gstreamer1.0-tools \ gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-alsa -
Install the LiveKit CLI
curl -sSL https://get.livekit.io/cli | bash
-
Clone this repository to your Raspberry Pi:
cd ~ git clone https://github.com/livekit-examples/rover-teleop.git cd rover-teleop -
Copy
env.exampleto.envand fill with your actual credentials:cp /home/pi/rover-teleop/env.example /home/pi/rover-teleop/rover/.env nano /home/pi/rover-teleop/rover/.envAdd your actual values for:
LIVEKIT_URL=<your LiveKit server URL> LIVEKIT_API_KEY=<your API Key> LIVEKIT_API_SECRET=<your API Secret> LIVEKIT_CONTROLLER_TOKEN=<Token for the teleop controller app> ROOM_NAME=<your room name> ROVER_PORT=/dev/serial0 -
Run the installation script to create systemd services:
sudo ./install-services.shThis script will:
- Install the systemd service files
- Enable the services to start at boot
Start services:
sudo systemctl start rover-cam-gstreamer.service
sudo systemctl start rover-cam-publish.service
sudo systemctl start rover-control.service
Check service status:
sudo systemctl status rover-cam-gstreamer.service
sudo systemctl status rover-cam-publish.service
sudo systemctl status rover-control.service
Stop services:
sudo systemctl stop rover-cam-gstreamer.service
sudo systemctl stop rover-cam-publish.service
sudo systemctl stop rover-control.service
View logs:
sudo journalctl -u rover-cam-gstreamer.service
sudo journalctl -u rover-cam-publish.service
sudo journalctl -u rover-control.service
This Flutter application connects to a LiveKit server to control and view a rover's camera feed.
- Create a copy of your
.envfile in thecontrollerdirectory:
cp /home/pi/rover-teleop/rover/.env /home/pi/rover-teleop/controller/.env
- Change to the controller directory:
cd controller
- Install dependencies:
flutter pub get- Run the application:
flutter run -d macosWhen the app is running, you will see the video from your rover.
The app will automatically connect to the LiveKit server using the credentials from the .env file.
- The main screen displays the rover camera feed when connected
- Tap the
Start/Stopbutton on the top left to enable/disable tele-op. - Tap the
Mute/Unmutebutton on the top right to enable/disable streaming audio from local microphone. This is not used for anything currently. - The left thumbstick Y axis controls the throttle on the rover, pushing forward on the stick will cause the rover to drive forward, pulling back will reverse.
- The right thumbstick X axis controls steering proportionally.
- Flutter 3.7.2 or higher
- A valid LiveKit server and token
- A connected gamepad. It can usb or Bluetooth. XBox or Playstation controllers work great.
- This app has only been tested on MacOS, but it should work on iOS, Android, Windows without any issues.
The roundtrip glass-to-glass latency can be measured by pointing the rover at a clock on the same screen displaying the rover video stream. Rover and controller were both connected to LiveKit Cloud. By taking a screenshot, we can calculate the latency is approximately 190ms.
- To further reduce latency, we can add WIFI 6/7 capable radio to rover (-10ms) and move controller laptop to ethernet (-20-30ms).


