Saranga is a low-power ultrasound-based perception stack for palm-sized aerial robots, enabling obstacle avoidance in visually degraded conditions (darkness, fog, dust) where cameras and lidars fail. It combines physical noise reduction with a lightweight deep learning denoising network to localize obstacles using a dual/tri-sonar array. The network is deployable on the Google Coral Mini onboard computer (or any Linux based development computer).
Clone this repository, then download the data files from Dryad and extract them into the cloned directory:
git clone https://github.com/pearwpi/Saranga
cd SarangaThe code is also archived on Zenodo: https://doi.org/10.5281/zenodo.18952903
Dryad — https://datadryad.org/dataset/doi:10.5061/dryad.f1vhhmh9z
| # | File | Description |
|---|---|---|
| 1 | dataset.zip |
Training and testing datasets |
| 2 | trained_model.zip |
Trained model checkpoints |
This repository
| # | Folder | Description |
|---|---|---|
| 1 | dataset_generator/ |
Synthetic data generation pipeline |
| 2 | train/ |
Training code for Saranga |
| 3 | tpu_optimization/ |
Post-training quantization and Edge TPU compilation |
| 4 | visualize/ |
Lightweight script to visualize Saranga inference on the representative dataset |
| 5 | ros2_src/ |
ROS2 Humble source — drivers for the ICU30201 ultrasonic sensor, perception, and local planner pipeline |
| 6 | benchmark/ |
Benchmarking compute time of Saranga against classical techniques |
For dataset generation, training and benchmarking:
conda create -n saranga python=3.11 -y
conda activate saranga
pip install tensorflow[and-cuda] keras wandb opencv-python \
numpy matplotlib scikit-image scipy Pillow tqdm ipdb keras-cv
wandb loginBoth the quantization script (
tpu_optimization/) and the ROS2 pipeline (ros2_src/) require a ROS2 Humble environment (Ubuntu 22.04 recommended) — see the ROS2 Pipeline section below for setup. Instructions may also work on Ubuntu 24.04 with ROS2 Jazzy.
The generated dataset is already provided in
dataset.zipon Dryad. You only need to run this if you want to regenerate or customize the dataset.
cd dataset_generator/- Open
generate4_wave.py— this is the entry point - Set
genOption = "test"(or"train") - Set the output folder
OUTPUT_DIR
python3 generate4_wave.pyThe trained model checkpoints are already provided in
trained_model.zipon Dryad. You only need to run this if you want to retrain the network.
cd train/
DS_PATH=../dataset OUT_PATH=/tmp/saranga_train/ N_FILTERS=8 IMG_WIDTH=512 LOSS_FUNCTION=mse LR=2e-4 python train.pyYou only need to run this if you want to recompile the TFLite models for the Edge TPU. The compiled outputs are already included in this repository under
visualize/mse_f8_a0428f_us_f8_w512/.
cd tpu_optimization/After sourcing the ROS2 environment,
- Install
edgetpu_compiler: https://coral.ai/docs/edgetpu/compiler#download - Open
tfLiteConverter.pyand set:-
TRAIN_FOLDERto point to the extractedtrained_model.zipfolder (e.g.TRAIN_FOLDER = "../trained_model/") -
Checkpoint to convert (default is
ckpt-60, the checkpoint used in the paper):RESTORE_CHECKPOINT = os.path.join(TRAIN_PATH, "checkpoint/ckpt-60")
-
- Output will go to
OUT_DIRas defined intfLiteConverter.py
Post-training quantization requires a representative dataset, which is provided in the
./representative_dataset/folder. The script is already configured to use it. Generated tflite outputs are in./mse_f8_a0428f_us_f8_w512.
To quickly visualize Saranga inference on the representative dataset, run visualize.py from the visualize/ folder. It is already configured to load the tflite model and representative dataset from the current folder:
conda create -n saranga_viz python=3.11 -y
conda activate saranga_viz
pip install tflite-runtime "numpy<2" matplotlib
cd visualize/
python3 visualize.pyChange FRAME_INDEX in visualize.py to visualize a different frame.
This step requires a ROS2 Humble setup: https://docs.ros.org/en/humble/Installation.html
We compiled ROS2 Humble from the official source and ported a minimal version onto the Google Coral Mini. The codebase is Linux-compliant and should work with any other desktop or embedded Linux distributions (Ubuntu, Debian, etc.).
The ros2_src/ folder is the src directory of a ROS2 workspace. To build it:
mkdir -p ~/ros2_ws/src
cp -r ros2_src/* ~/ros2_ws/src/
cd ~/ros2_ws
source /opt/ros/humble/setup.bash
colcon build
source install/setup.bashSee ros2_src/run_all.sh and ros2_src/run_cron.sh for the commands to launch our ROS2 nodes. Run the Python files from their respective folders.
| Node | Description |
|---|---|
teensy_pubsub |
ROS2 driver for the ultrasonic sensor. Reads over serial and publishes ICU30201 sensor data as icu_interfaces/msg/Icupkt. Teensy firmware is in ros2_src/teensy_pubsub/Arduino/icu30201_to_coral/ |
stacking_node.py |
Combines data from multiple ICU30201 sensors for the last N time steps into a single time-synced packet |
edge_detection.py |
Runs inference using Saranga on the Edge TPU |
proc.py |
Runs perception and planning algorithms |
icuAndMavLink.py |
Sends velocity commands to the ArduPilot autopilot over MAVLink |
batdeck.py |
Classical baseline algorithm used for comparison against Saranga |
These benchmarks run on the Google Coral Mini compute board. Setup instructions for the board are available at https://gweb-coral-full.uc.r.appspot.com/.
cd benchmark/This folder contains scripts for benchmarking the compute time of Saranga against classical obstacle detection techniques on the same input size (32 × 512).
| Script | Method |
|---|---|
saranga.py |
Saranga (UNet on Edge TPU) |
classical_blur_sobel.py |
Gaussian blur + Sobel |
tv1_sobel.py |
Total variation denoising + Sobel |
tv1_golay_sobel.py |
Total variation + Savitzky-Golay + Sobel |
tdlms_sobel.py |
Two Dimensional LMS filter + Sobel |
saranga.py requires the compiled Edge TPU model at ./mse_f8_a0428f_us_f8_w512/model_int8_edgetpu.tflite.
@article{
doi:10.1126/scirobotics.adz9609,
author = {Manoj Velmurugan and Phillip Brush and Colin Balfour and Richard J. Przybyla and Nitin J. Sanket },
title = {Milliwatt ultrasound for navigation in visually degraded environments on palm-sized aerial robots},
journal = {Science Robotics},
volume = {11},
number = {112},
pages = {eadz9609},
year = {2026},
doi = {10.1126/scirobotics.adz9609},
URL = {https://www.science.org/doi/abs/10.1126/scirobotics.adz9609},
eprint = {https://www.science.org/doi/pdf/10.1126/scirobotics.adz9609}
}
@misc{velmurugan2026saranga,
author = {Velmurugan, Manoj and Brush, Phillip and Balfour, Colin and Przybyla, Richard and Sanket, Nitin},
title = {Code and data from: milliWatt ultrasound for navigation in visually degraded environments on palm-sized aerial robots},
year = {2026},
publisher = {Dryad},
doi = {10.5061/dryad.f1vhhmh9z},
url = {https://doi.org/10.5061/dryad.f1vhhmh9z}
}- CRC16 checksum implementation uses CRC++ by Daniel Bahr (BSD license).