QuadBots · NSF REU · University of Idaho

I worked on a UAV that carries a ground robot for search and rescue

I’m Pratosh Tiwari, a student at RIT. This is QuadBots, the UAV + UGV search and rescue project I came up with and spent a 10 week NSF REU living in. I directed the team a bit on what we built and in what order. CAD was not me. This page is just the project: what we built, what broke, and what actually flew.

Summer 2026 · teammates Soyoung Moon (Georgia Tech), Nicholas Ruiz (UCF), Nicholas Woodburn (Boise State)

Team QuadBots standing with their research poster
Team QuadBots at the end of the REU, plus the poster. I’m the one in the RIT jacket.

The idea

The original idea was mine. I wanted a drone that could carry a ground robot, drop it near the interesting part of a disaster site, then keep looking from the air while the tank actually deals with the 2D mess on the ground. Drones are great until the battery says no. Ground robots can hang around longer, but they eat time just getting over rubble and fences. Pairing them felt obvious after we read enough papers and talked ourselves into “this could actually help firefighters / SAR / anyone who shouldn’t walk into a bad building first.”

The NSF REU was hosted at the University of Idaho and was supposed to be about UAS. I spent a couple of days convincing people this was the project: UAV/UGV for disaster relief, with a path toward something you could actually field, not just a lab demo. I directed the team a bit after that, on what to build next and who should sit on which problem. We called the team QuadBots even after we switched to a hexacopter. The name stuck. Sorry.

The picture in my head was pretty simple: fly in, park, pop the ramp, let the UGV drive off. Reverse it when you’re done.

CAD view of the ground robot driving onto the UAV mount
Stage 1: drive in
CAD view of the UGV settled on the UAV plate with the ramp down
Stage 2: settle on the plate
CAD view of the ramp closed with the UGV stowed under the hexacopter
Stage 3: close the ramp

I’m putting those CAD frames here because they’re how we explained the idea. I did not do the CAD. Mechanical folks on the team owned that.

We started smaller than the CAD, because none of us had built a serious drone before. F450 frame, FlySky FS i6X, Pixhawk 2.4.8 B Cube, ArduPilot Mission Planner. Assembly was fine. The motors did not spin. We checked the ESCs, the battery, and the radio. The problem was the ESC signal wires. They were plugged into the Pixhawk upside down. After that, the quad could spin motors.

Red F450-style quadcopter on a table with a Raspberry Pi beside it
The learning quad. Yes, that Pi on the table was part of the same chaos.
Close-up of a Pixhawk 2.4.8 B-Cube with servo wires in the main out ports
Pixhawk close-up. The “upside down connector” era of my life.

Next milestone: pick up a small ground robot. The mechanical folks 3D-printed a PLA mount with a lock. After a couple of ugly versions, the quad could carry the little guy. Then we hung 915 MHz radios on it so Mission Planner wasn’t glued to a USB cable.

3D-printed UGV mount next to a small wheeled robot wearing the mount
The first UGV mount. Not pretty. It worked enough to teach us the quad did not have the thrust we wanted.

That was the whole point of the learning airframe. The quad could not lift the tank we actually wanted. So we pivoted to a carbon fiber hexacopter, still on a Pixhawk 2.4.8, still Mission Planner. Ground side was a Yahboom G1 tank on a Raspberry Pi. Treads, so grass and dry dirt weren’t an automatic no.

Carbon fiber hexacopter from above with Pixhawk, GPS, and wiring on the frame
Hexacopter from above.
Blue tracked ground robot on a desk with cables and a phone
Yahboom G1, mid-wiring, looking like every student robot ever.

Computer vision (AI)

This was one of the tabs I actually owned. If the vehicles were going to be useful, they had to see people / buildings / cars / trees without me babysitting every frame. Companion computers: NVIDIA Jetson Orin Nano on the air side, Raspberry Pi 4B on the tank. YOLO on both, because we needed something that ran live, not a research model that thought about it for three seconds.

Pi setup: 64 GB card, Raspberry Pi OS, started headless, later I gave up and used a monitor like a normal person. Camera was an ArduCam 8MP on a 15-to-22 pin cable. The Pi pretended the camera didn’t exist until I turned off camera_auto_detect and added dtoverlay=imx219 in /boot/firmware/config.txt. That one line ate more of my week than I want to admit.

Raspberry Pi 4B connected to an ArduCam 8MP camera with a ribbon cable
Pi 4B + ArduCam 8MP. The ribbon cable is doing the most.

I trained our own YOLOv8. We scraped about 5000 images from Kaggle / Roboflow / GitHub, four classes, 80 to 20 split. I wanted to use the ONNX file on the Pi. The Pi is not a training machine (about 0.1 TOPS and 4 GB), so a usable model was the goal. It overfit. The dataset was too small and too clean. After more reading, we used the pretrained YOLOv8 with the 80 COCO classes. For what we had, it was better. Camera feed on the Pi sat around 12 FPS.

Grid of YOLO test images with bounding boxes on buildings, trees, and vehicles
YOLOv8 testing collage. Boxes everywhere. Some of them even correct.

Jetson was the grown-up computer. JetPack / Jetson Linux on another 64 GB card, headed the whole time. Same ArduCam family, 15-to-15 CSI cable, CSI-Camera repo for bring-up. 24 FPS, which felt luxurious after the Pi. Because the Orin Nano is in a totally different weight class (~67 TOPS), I put YOLOv26s on it for better recognition and wrote the glue scripts around it. Before a run we’d SSH in (when 4G actually worked) and start the vision process. Not fancy. Repeatable enough.

NVIDIA Jetson Orin Nano on a bench with a CSI camera on a ribbon cable
Jetson Orin Nano and camera on the bench.

The instinct was the same the whole summer: don’t wait on a slow round-trip if a person is already in the frame.

Embedded programming

The two boards I actually lived on were a Raspberry Pi 4B (tank / UGV) and an NVIDIA Jetson Orin Nano (air / UAV). A lot of my hours were not “AI” in the LinkedIn sense. They were: flash this card, fight this overlay, SSH in, talk to a modem in minicom, shove UDP out of the Jetson, remember which USB port the Pixhawk lied about.

Raspberry Pi

On the Pi I flashed a 64 GB SanDisk with Raspberry Pi OS using Pi Imager, started headless, then gave up and used a monitor. I hung the ArduCam 8MP off a 15-to-22 pin cable, killed camera_auto_detect, and added dtoverlay=imx219 in /boot/firmware/config.txt so the camera even showed up. I also booted the same Pi through Yahboom’s firmware and Ubuntu just to see what the tank would run. That’s the machine YOLO sat on at ~12 FPS, and the one I SSH’d into before a run.

NVIDIA Jetson

On the Jetson I flashed another 64 GB card with Jetson Linux via JetPack and kept a screen on it the whole summer. Same ArduCam family, 15-to-15 CSI cable, CSI-Camera repo for bring-up, ~24 FPS. That’s where YOLOv26s ran, and where I started the UDP process the dashboard listened to. If I was “on the drone computer,” I was on the Orin Nano.

ArduPilot and LTE

On the flight controller side we loaded ArduPilot through Mission Planner, mapped ESCs, and learned that one backwards connector looks exactly like a dead power system. The 4G dongles (Waveshare SIM7600G-H) were their own embedded side quest. No IMEI on the module, so we couldn’t register the SIM the normal way. We borrowed an IMEI from a spare phone that had extra SIM slots, which is the kind of sentence that should not appear in a professional paper and is exactly what we did. Then I plugged a dongle into a laptop and used minicom to see if the modem even existed. It did, until it didn’t. More on that in comms.

Tracked robot with a Waveshare SIM7600G-H 4G dongle attached
Tank with the SIM7600G-H hanging off it. This is also what “embedded” looked like on our desks.

Controls (flight controls)

Flight controls was another tab that was actually mine, in the “make the airframe do modes a human can trust” way, not in the “I derived a new controller” way. Primary stick was the FlySky FS-i6X. 2.4 GHz, AFHDS 2A, hopping across a pile of channels. First four were throttle, yaw, pitch, roll. Five was loiter (GPS hold). Six was return-to-home. Radio itself was the least dramatic part of the summer, which I will take.

FlySky FS-i6X transmitter and receiver
The radio kit. Channels 5 and 6 were loiter and RTH once we stopped treating the switches like mystery meat.

Autonomous missions were supposed to live in Mission Planner over 915 MHz telemetry so we weren’t waving a transmitter at a hex the whole time. In the lab we could track odometry, upload a path, pull logs, stop babysitting USB. Outside, the same radios ghosted us. We also couldn’t get the PID tune we wanted in the field, and Mission Planner got spicy about stabilization until we recalibrated GPS and compass. After that, hover / loiter / RTH actually happened, under a real remote PIC, in an FAA legal field, because our office was a no fly zone for a long time.

On the side I worked on GPS denied nav a bit. I am still working on it.

Communication

This was the biggest tab I worked on for comms. Three layers.

Radio control

LOS stick on 2.4 GHz, as above. That was the “don’t lose the airplane” path. Fine.

Telemetry

3DR 500 mW kit on 915 MHz. Lower frequency, less data, more distance — textbook. USB on the laptop, TELEM on the Pixhawk. In the lab it was great. On the field day it would not handshake, even though we’d done it a lot. I still don’t have a clean postmortem. That’s the honest version.

Pair of 915 MHz FPV radio telemetry modules with antennas
Telemetry kit. Beloved indoors. Mysterious outdoors.

4G LTE + a VPN I now have opinions about

For AI-assisted stuff we needed a real network, not a phone hotspot that dies when you walk 30 feet. Two SIM7600G-H dongles, two SIMs, Jetson + Pi + a home-base laptop on Tailscale because the free tier was enough to try. Then latency went to something like 2500 ms. We wanted ~50. Tailscale couldn’t get P2P, parked us on a Seattle DERP relay, and the office walls / peak traffic probably didn’t help.

Diagram of UAV, laptop, and UGV linked over 915 MHz and 4G LTE VPN
How we wanted the non-RC links to look. Reality added a Seattle relay and then a brick wall.

The day before field testing, both 4G modules just died. Best guess: the carrier noticed the SIMs were not in the phone we used to register them. If I did this again I would buy actual IoT SIMs on day one and stop being clever. I now have a tiny, expensive intuition for why you want more than one comms path.

Dashboard

We wanted one place to see camera, odometry, battery, and “is there a person who looks like they need help.” Half of that already lived in Mission Planner. The other half lived in a terminal. So I vibe-coded a dashboard in Cursor: live feed, telemetry, and a path that only asked a model to look closer if YOLO saw a person above 0.8 confidence for two frames in a row. During alpha we wired OpenAI in for that second look. The feed in the screenshot is redacted / swapped, which is why the neighborhood doesn’t match Idaho.

QuadBots ground control dashboard with human alerts, live feed, and telemetry
UAV dashboard. UDP in, localhost out, me SSH’d into the Jetson like it’s a ritual.

Bring-up: SSH to the Orin, start a process that sprays UDP (no handshake, no retries — we wanted speed, not politeness), then boot the dashboard. Same idea on the tank. If you’ve used a vehicle UI that has to stay boringly reliable while payloads yell, you already know why I cared about this tab.

Field testing

FAA + a no fly office meant we sat on this thing for way too long. When we finally got an approved area and a remote PIC, the hex flew. Hover, loiter, and return to home all happened. That part felt unreal in a good way. With the ground robot on it the hex was unstable at times.

People working on the hexacopter with the ground robot mounted, outdoors on asphalt
Hex with the tank underneath, asphalt, too many hands, actual sun. Field testing.

What broke: telemetry link, PID tune, a compass/GPS fit we fixed by calibrating like we should have the first time. The tank still rolled around fine on its own. In the air, carrying it, the hex was not always settled.

I don’t want to oversell it. We did not finish the sci-fi docking loop. We did not get the 4G story to the field. We did get a carbon hex in the air with a tank underneath, vision running on boards I set up, a dashboard I could stare at, and a very specific list of what bites you when the vehicle leaves the carpet.

Final look

Hexacopter with the tracked ground robot docked on the ramp, sitting on carpet
Hex with the tank on the ramp.

That’s the project. A summer of making unmanned stuff honest.