惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
J
Java Code Geeks
Blog — PlanetScale
Blog — PlanetScale
大猫的无限游戏
大猫的无限游戏
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
腾讯CDC
博客园_首页
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
D
DataBreaches.Net
Microsoft Security Blog
Microsoft Security Blog
有赞技术团队
有赞技术团队
博客园 - 叶小钗

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Building a Custom Autonomous Drone Stack - Part 1: The Bl...
Harsh Pandhe · 2026-06-23 · via DEV Community

Why We Ditched MAVROS for Raw PyMAVLink and systemd

If you're building an autonomous UAV, MAVROS is the undisputed industry standard for bridging a companion computer (like a Raspberry Pi or Jetson Nano) to your flight controller (like a Pixhawk). It wraps the MAVLink serial protocol into the ROS ecosystem. For most projects, it's the perfect tool.

But what if you're building a micro-UAV for a strictly GPS-denied environment?

What if your Raspberry Pi needs every ounce of CPU and RAM to run heavy, tightly-coupled LiDAR SLAM algorithms like FAST-LIO?

During the development of our autonomous drone stack, we hit a massive computational bottleneck. We simply couldn't afford to burn precious CPU cycles and deal with middleware overhead just to log telemetry.

We needed a zero-latency "Black Box" flight recorder. It needed to capture Optical Flow drift, Barometer altitude, CPU load, and frame vibrations at a strict 10 Hz frequency so we could mathematically verify stability before autonomous flight.

Our solution?

We bypassed ROS and MAVROS entirely for the telemetry layer and went straight to the metal using raw pymavlink over a blazing 921600 baud serial connection.


The PyMAVLink Interceptor

Instead of wrestling with ROS nodes, topic publishers, and XML configurations, we wrote a lightweight procedural Python script. It opens a direct UART connection to the Pixhawk, intercepts the binary MAVLink stream, and logs only the data we care about directly into a CSV file.

One important detail: flight controllers won't continuously spam data unless you explicitly ask them to.

1. Connect to the Pixhawk 6C

import time
import csv
from pymavlink import mavutil

PORT = "/dev/ttyAMA0"
BAUD = 921600

print(f"Connecting to Pixhawk on {PORT} at {BAUD} baud...")
master = mavutil.mavlink_connection(PORT, baud=BAUD)

We use a 921600 baud rate to avoid bottlenecking the telemetry stream.

2. Wait for the First Heartbeat

master.wait_heartbeat()
print(f"Connected! Target System: {master.target_system}")

This guarantees the Pixhawk is fully booted and speaking MAVLink before we continue.

3. Request All Data Streams at 10 Hz

master.mav.request_data_stream_send(
    master.target_system,
    master.target_component,
    mavutil.mavlink.MAV_DATA_STREAM_ALL,
    10,
    1
)

MAV_DATA_STREAM_ALL tells ArduPilot to actively send telemetry rather than waiting for individual requests.


The Async Logging Loop

By sending request_data_stream_send(), we tell the Pixhawk to start continuously flooding the serial port with MAVLink packets.

Different messages arrive at different frequencies:

  • Attitude → 50 Hz
  • Battery Status → 1 Hz
  • Optical Flow → varies

Writing directly to CSV every time a packet arrives would create inconsistent rows.

Instead, we maintain a state dictionary, continuously update it, and snapshot it every 0.1 seconds.

Simplified Logging Loop

state = {
    "Alt": 0.0,
    "Flow_X": 0.0,
    "Flow_Y": 0.0,
    "Quality": 0
}

last_write = time.time()

while True:
    msg = master.recv_match(blocking=True, timeout=0.1)

    if not msg:
        continue

    msg_type = msg.get_type()

    if msg_type == "VFR_HUD":
        state["Alt"] = msg.alt

    elif msg_type == "OPTICAL_FLOW":
        state["Flow_X"] = msg.flow_comp_m_x
        state["Flow_Y"] = msg.flow_comp_m_y
        state["Quality"] = msg.quality

    if time.time() - last_write >= 0.1:
        write_to_csv(state)
        last_write = time.time()

This keeps all asynchronous packets synchronized into a single telemetry snapshot.


The systemd Autopilot

A flight recorder is useless if:

  • You forget to start it before takeoff.
  • You need to SSH into the drone after every battery swap.
  • The script crashes mid-flight.

To make the logger production-ready, we wrapped it inside a Linux systemd service.

Unlike cron or rc.local, systemd automatically:

  • Starts the logger when the Raspberry Pi boots.
  • Restarts it if it crashes.
  • Runs silently in the background.

Create /etc/systemd/system/drone_blackbox.service

[Unit]
Description=Autonomous Drone Black Box Flight Recorder
After=multi-user.target network.target

[Service]
User=pi
WorkingDirectory=/home/pi/drone_project
ExecStart=/usr/bin/python3 /home/pi/drone_project/drone_blackbox.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable the Service

sudo systemctl daemon-reload
sudo systemctl enable drone_blackbox.service
sudo systemctl start drone_blackbox.service

Your Raspberry Pi is now a professional-grade auto-starting telemetry recorder.


🚨 The Serial Port "Gotcha"

Suppose your logger is already running in the background and you launch another Python script for autonomous takeoff.

Linux will throw:

serial.serialutil.SerialException:
device reports readiness to read but returned no data
(device disconnected or multiple access on port)

A hardware serial port can only be owned by one process at a time.

Option 1

Stop the logger temporarily:

sudo systemctl stop drone_blackbox.service

Option 2

Use a MAVLink router like MAVProxy to split one physical serial connection into multiple virtual UDP ports.


Final Thoughts

By ditching ROS and MAVROS for telemetry logging, we achieved:

  • Lower CPU overhead
  • Near-zero latency
  • Deterministic 10 Hz logging
  • Automatic startup with systemd
  • Improved reliability during indoor autonomous flights

Sometimes the best architecture isn't adding another layer of abstraction.

Sometimes it's removing one.


Up Next

Logging data is easy.

Making the drone fly itself is hard.

In Part 2 of this series, we'll explore:

  • Autonomous takeoff without GPS
  • ArduPilot's EKF3 safety engine
  • State polling and pre-arm checks
  • Safe operation in GPS-denied environments
  • The realities of indoor autonomous flight

Stay tuned.