Project Info
Inspiration
In wilderness search and rescue, time is the enemy. Ground teams cover terrain slowly, aerial spotters get fatigued, and a person under canopy can be almost invisible from above. Even when drones are available, teams still need to answer the hard operational question: where should we look next? We wanted to build something more useful than another object detector. A detector can say "maybe person in this frame." Search teams need a system that combines that evidence with terrain, search coverage, missed detections, and uncertainty. SARchlight is our attempt to build that missing decision layer: a drone-side search brain that keeps updating the probability of where the person is and uses that map to drive the next move.
What it does
SARchlight gives SAR teams a live search brain: Builds a probability map from last-known position, terrain, land cover, and accessibility. Sends drones toward the highest-priority search sectors. Converts image detections into ground locations with a georeferencer. Updates the map from both detections and non-detections. Coordinates multiple drones so they do not search the same area. Declares a subject located only after persistent, concentrated evidence. Shows the mission state in a live React dashboard. After locating the subject, computes a terrain-aware route and simulates a drone guiding them back to operators. The core loop is: prior map -> search path -> drone observation -> Bayesian update -> next search target -> located event
How we built it
Search brain The backend uses a Python and NumPy probability grid. The brain owns a single-writer MapState and applies Bayesian updates as observations arrive. Terrain-aware prior The prior is shaped by the last-known position, elevation, land cover, and accessibility. The real-terrain showcase uses Marin County terrain with DEM hillshade and land-cover-derived visibility. Georeferencing The georeferencer translates detector boxes from image space into ground cells. This lets the search map understand where a detection happened and which ground cells were actually searched. Detection adapter The detector is swappable. The deterministic demo can run on simulated detections, while the integration path supports YOLO-style detector outputs through an adapter. Multi-drone planner The planner overlays coarse sectors on the fine belief grid, ranks sectors by probability and remaining coverage, and assigns drones to disjoint sectors. Dashboard A FastAPI server projects the brain state into a React, TypeScript, Vite, and Tailwind dashboard with probability heat, drone positions, detections, search path, confidence, locate status, and guide-home routing. Voice Layer The voice layer uses Deepgram for both the subject broadcast (text-to-speech) and a Twilio-backed operator phone agent (Deepgram Voice Agent) deployed on Fly.io, which reads the live search state over a dedicated endpoint and answers operator questions through function calls. Reliability For reliability, we instrumented the entire stack with Sentry — the FastAPI brain, the React dashboard, and the remotely deployed phone agent — so failures that would otherwise be invisible (a background search-thread crash, a degraded voice line, or an error mid-phone-call) surface immediately; it's fully env-gated, so it adds observability without adding any risk to the core loop.
Challenges we ran into
Making non-detections useful Search is not only about what the drone sees. Empty ground matters too. We had to model clean passes as evidence without letting repeated misses unfairly erase a subject hidden by canopy. Correlated misses under canopy In real terrain, repeated looks from the same sensor can fail in the same way. We added capped cumulative clearance per sensor so one drone repeatedly missing the same obscured cell does not drive that cell to zero probability. Avoiding premature locate alerts A single false positive should not trigger a rescue declaration. RescueLoop waits for persistent evidence and probability concentration before declaring the subject located. Real terrain was harder than synthetic terrain The real Marin terrain prior made the find more realistic and less forgiving. We redesigned the scenario around a plausible subject cell, canopy visibility, thermal corroboration, and a generalized flight path. Keeping the system integrated The detector, georeferencer, brain, server, dashboard, and voice layer all use different data shapes. We kept clear contracts and adapters so the pieces could connect without rewriting each other.
Accomplishments we're proud of
Built a working closed-loop SAR search system. Ran the brain on real terrain data. Located the planted subject at 0-cell error in the real-terrain showcase. Built multi-drone sector assignment with no overlapping search sectors. Built a live React dashboard for operator situational awareness. Added guide-home routing after the subject is found. Kept the demo honest about what is simulated, what is real, and what still needs field validation. -Deployed a live operator phone agent that answers questions from real-time search state. ##
What we learned
The most important signal in search is not always a detection. Sometimes it is a well-modeled miss. We learned that the strongest AI system here is not a single model. It is the loop connecting perception, geography, probability, planning, and communication. A weaker detector inside a strong search loop can be more useful than a stronger detector with no operational reasoning around it.
What's next
for Next, we want to turn Untitled from a software demo into a field-ready rescue assistant. We would connect it to live drone telemetry, real GPS/camera data, and thermal footage so detections can update the map in real time. We also want to improve the probability model with real SAR behavior data, terrain difficulty, trails, and last-known-position patterns. Long term, Untitled could coordinate multiple drones, support multilingual voice broadcasts to missing people, and use phone-signal or beacon data as another clue. Our goal is simple: help rescue teams search faster, avoid duplicated effort, and make better decisions when every minute matters.
SARchlight
An AI rescue-intelligence layer that turns drone footage, terrain, and uncertainty into a live map of where to search next.
UC Berkeley AI Hackathon 2026 · wide-area Search & Rescue support.
SARchlight is the brain behind a search-and-rescue drone — not the drone itself. It builds a live probability map of where a missing person likely is from last-known position, terrain, and land cover; directs drones to the highest-probability sectors; turns image detections into ground locations; updates the map from both detections and clean non-detections; coordinates multiple drones so they never re-cover the same ground; and declares a subject located only after persistent evidence. Once found, a drone guides the subject home and the system speaks to them.
Scope. SARchlight is the decision layer, demonstrated in simulation — there is no real drone or live flight here. The demos run on simulated detections and a scripted, simulated flight over real terrain data, with a stationary subject. A real YOLO detector path exists but has not been run on real footage, and no detector has been fine-tuned, so detection accuracy on real aerial imagery is untested. The "zero-cell locate on real terrain" result below is produced by the brain, GeoReferencer, and planner driven by the simulator, not by real perception. Real drone telemetry, footage, thermal sensing, and a moving-target model are future work (see What's next).
The closed loop
prior map ─▶ directs search path ─▶ detector on footage ─▶ detections + coverage update map
▲ │
└──────────────── updated map redirects + flags high-probability areas ┘
│
confident, persistent detection ─▶ subject broadcast + operator alert ─▶ guide home
In the multi-drone planner demo, the flight path is not hand-drawn — it emerges from the map: a detection (or a clean sweep) changes the belief, and the changed belief changes where the simulated drones go next. (The geo+brain feasibility demo uses a fixed scripted path.)
What's inside
- Probability map (the core). A NumPy belief grid with Bayesian updates. Single-writer design
so map state can't be corrupted by concurrent readers. See
docs/interfaces.mdfor the contracts and the Bayesian /locatedmath. - Terrain-aware prior. Real DEM (elevation) + ESA WorldCover (land cover) shape where the
subject is likely to be. See
docs/prior_model.md. - Non-detection handling. A clean sweep lowers probability where we've actually looked — but canopy means "didn't see" ≠ "not there", so probability is down-weighted, never erased.
locatedtrigger. Confidence-as-likelihood-ratio (clipped) + persistence, so a single false-positive aerial frame can't trip an alert. Locates at zero-cell error on real Marin terrain rasters in the demo, driven by simulated detections.- Multi-drone planner. Probability-of-area ranking with disjoint sector assignment and a boustrophedon sweep — no overlapping coverage.
- GeoReferencer. Projects pixel detection boxes to ground cells; geography lives in exactly one swappable place, so the detector stays geography-blind.
- Swappable detector. A simulator and a real YOLO path behind one adapter, so the loop runs immediately while the detector is an independent upgrade.
- Guide-home. After locating, a drone leads the mobile subject home along a terrain-aware route.
- Voice layer. A synthesized subject broadcast (Deepgram TTS) speaks to the found person, and a Twilio-backed operator phone agent (Deepgram Voice Agent, deployed on Fly.io) lets ground operators call in and ask the live system questions — coverage, the current highest-probability area, and whether the subject has been found.
- Live dashboard. A React/TypeScript/Tailwind app showing the probability heat map over real terrain, drone positions, detections, routing, the live video feed, and the call transcript.
- Observability. The whole stack is instrumented with Sentry — the FastAPI brain, the React dashboard, and the remotely deployed phone agent — so failures that would otherwise be invisible (a background search-thread crash, a degraded voice line, an error mid-phone-call) surface immediately. Fully env-gated: with no DSN it is a complete no-op.
Repository layout
src/ the brain: GridSpec + contracts (common/), GeoReferencer (geo/),
prior + Bayesian update + located trigger + planner + terrain (search/),
and runnable demos (demo/)
integration/ the transport seam: FastAPI server, the steppable loop, detector backends,
broadcast + Deepgram TTS, map rendering, Sentry init (observability.py)
dashboard_app/ the live React/Vite dashboard
voice/ the Twilio + Deepgram operator phone agent (deploys to Fly.io)
detector/ the real YOLO detector adapter
tests/ unit + integration + soak tests (pytest)
docs/ technical reference: interfaces, prior_model, core_loop, data, tech_stack
data/ terrain rasters (gitignored — see Setup)
Setup
# 1. Python backend (the brain + integration server)
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
# 2. Secrets — copy the template and fill in what you need
cp .env.example .env # DEEPGRAM_API_KEY, ANTHROPIC_API_KEY; SENTRY_DSN is optional
# 3. Terrain rasters are large and gitignored. Verify they are present + intact:
.venv/bin/python check_setup.py # see docs/data.md for how to fetch them
Run
# Tests (unit + integration + soak)
.venv/bin/python -m pytest
# Brain demo on synthetic terrain (locates) -> demo_output/
.venv/bin/python -m src.demo.run
# Multi-drone sector search (closed loop)
.venv/bin/python -m src.demo.search_demo --drones 3
# Closed loop CLI: detector -> geo -> brain (simulator backend)
.venv/bin/python -m integration.loop
# ...or the real YOLO backend:
.venv/bin/python -m integration.loop --video <footage> --weights <weights>
# Live dashboard: start the server, then the React app
.venv/bin/uvicorn integration.server:app # http://localhost:8000 (serves /state, /map_base.png, /ops, ...)
cd dashboard_app && npm install && npm run dev # http://localhost:5173
# Operator phone agent (local dev; needs DEEPGRAM_API_KEY)
cd voice && python main.py # deploys to Fly.io via voice/ — see voice/README.md
Tech stack
Python · NumPy · rasterio · FastAPI · YOLO · React · TypeScript · Vite · Tailwind · Claude (Anthropic) · Deepgram · Twilio · Fly.io · Sentry
What's next
Live drone telemetry, GPS/camera and thermal footage for real-time updates; richer
probability models from real SAR behavior and trail data; and multilingual voice broadcasts.
Known limitations and deferred work are noted alongside the relevant docs in docs/.
Analysis
View
Metric
- 62
- 6
- 4
- 2
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- FastAPIIn code
- HTMLIn code
- JavaScriptIn code
- PythonIn code
- ReactIn code
- Tailwind CSSIn code
- TypeScriptIn code
8 of 8 appear in the indexed code.
AI coding agents
- Claude CodeCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
893 KB
Source files
144
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
Mudit-Arora/SAR-system
178 files · 23.2 MB · @ eafc890
Structure
Interface
13 files · 7%Screens, components and styles rendered to the user.
Application logic
75 files · 42%Domain rules, services and shared utilities.
+10 moreData & schema
1 file · 1%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python80%
- Markdown13%
- TypeScript5%
- Shell0%
- JavaScript0%
- CSS0%
- Other (2)0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
dashboard_app/package.json
npm · 13- @sentry/react
- lucide-react
- react
- react-dom
- recharts
- +8 more
requirements.txt
pypi · 11- fastapi
- httpx
- matplotlib
- numpy
- opencv-python
- pytest
- pytest-cov
- rasterio
- sentry-sdk
- ultralytics
- uvicorn
voice/requirements.txt
pypi · 7- deepgram-sdk
- python-dotenv
- python-multipart
- sentry-sdk
- starlette
- twilio
- uvicorn[standard]
detector/requirements.txt
pypi · 5- numpy
- opencv-python
- PyYAML
- tqdm
- ultralytics
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.