Building an AI drone software stack requires orchestrating low-level flight control with high-level perception and spatial navigation. The core architecture relies on ROS 2 as the middleware connecting your edge compute hardware (e.g., NVIDIA Jetson Orin) to a flight controller running PX4 Autopilot or ArduPilot.
Core System Architecture
[Sensors: RGB-D / LiDAR / IMU]
│
▼
[ROS 2 Node: OpenCV / TensorRT] ──► (Inference & Tracking)
│
▼
[ROS 2 Node: Nav2 / VIO / SLAM] ──► (Pose & Path Planning)
│
▼ (Micro XRCE-DDS / MAVROS)
[PX4 / ArduPilot Flight Controller]
│
▼
[Motors & Actuators]
Software Layer Breakdown
1. Perception & Computer Vision Pipeline
- Hardware Acceleration: Convert PyTorch or ONNX models to NVIDIA TensorRT engines to achieve sub-10ms inference times on onboard GPUs.
- Video Streaming & Decoding: Use GStreamer or NVIDIA Isaac ROS (Argus) to handle zero-copy CSI camera input directly into GPU memory (CUDA).
- Node Responsibilities:
- Detection/Segmentation: YOLOv8/v10 running on TensorRT publishing bounding boxes as ROS 2
vision_msgs/msg/Detection2DArray. - Target Tracking: DeepSORT or ByteTrack nodes to track moving targets across frames.
- Detection/Segmentation: YOLOv8/v10 running on TensorRT publishing bounding boxes as ROS 2
2. State Estimation & GPS-Denied Navigation
- Visual-Inertial Odometry (VIO): Use package suites like Isaac ROS Visual SLAM or OpenVINS to fuse camera feeds and IMU telemetry into a stable relative position vector.
- Obstacle Mapping: Publish point clouds or depth maps into OctoMap or NVBlox to build real-time 3D occupancy grids.
- Trajectory Generation: Feed maps into ROS 2 Nav2 or specialized UAV trajectory generators (e.g., Fast-Planner / Ego-Planner) to generate collision-free setpoints.
3. Flight Controller Bridge & Offboard Control
- Communication Protocol: Use Micro XRCE-DDS (standard for PX4 and ROS 2) or MAVROS (for ArduPilot/Mavlink) over UART/Ethernet.
- Control Loop: The vision/navigation nodes output high-frequency trajectory setpoints (
geometry_msgs/msg/PoseStampedorTrajectorySetpoint). - PX4 Offboard Failsafe: The ROS 2 node must continuously stream target setpoints at $>2\text{ Hz}$ before requesting
OFFBOARDmode to prevent PX4’s failsafe mechanism from rejecting mode changes.
Minimal ROS 2 Offboard Command Node (Python)
Python
import rclpy
from rclpy.node import Node
from px4_msgs.msg import OffboardControlMode, TrajectorySetpoint, VehicleCommand
class AIAutonomousDrone(Node):
def __init__(self):
super().__init__('ai_drone_offboard_node')
# Publishers to PX4 via Micro XRCE-DDS
self.offboard_control_mode_pub = self.create_publisher(
OffboardControlMode, '/fmu/in/offboard_control_mode', 10)
self.trajectory_setpoint_pub = self.create_publisher(
TrajectorySetpoint, '/fmu/in/trajectory_setpoint', 10)
self.vehicle_command_pub = self.create_publisher(
VehicleCommand, '/fmu/in/vehicle_command', 10)
# 20Hz Loop for streaming setpoints to PX4
self.timer = self.create_timer(0.05, self.cmd_loop)
self.offboard_counter = 0
def cmd_loop(self):
# 1. Publish Heartbeat required by PX4 for Offboard Mode
offboard_msg = OffboardControlMode()
offboard_msg.position = True
offboard_msg.timestamp = int(self.get_clock().now().nanoseconds / 1000)
self.offboard_control_mode_pub.publish(offboard_msg)
# 2. Set Target Position (x, y, z in NED frame)
setpoint = TrajectorySetpoint()
setpoint.position = [0.0, 0.0, -2.0] # Hover at 2m altitude
setpoint.timestamp = int(self.get_clock().now().nanoseconds / 1000)
self.trajectory_setpoint_pub.publish(setpoint)
# 3. Request Offboard mode after establishing setpoint stream
if self.offboard_counter == 10:
self.send_vehicle_command(VehicleCommand.VEHICLE_CMD_DO_SET_MODE, 1.0, 6.0)
self.arm()
if self.offboard_counter < 11:
self.offboard_counter += 1
def arm(self):
self.send_vehicle_command(VehicleCommand.VEHICLE_CMD_COMPONENT_ARM_DISARM, 1.0)
def send_vehicle_command(self, command, param1=0.0, param2=0.0):
cmd = VehicleCommand()
cmd.command = command
cmd.param1 = param1
cmd.param2 = param2
cmd.target_system = 1
cmd.target_component = 1
cmd.from_external = True
cmd.timestamp = int(self.get_clock().now().nanoseconds / 1000)
self.vehicle_command_pub.publish(cmd)
def main(args=None):
rclpy.init(args=args)
node = AIAutonomousDrone()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
Development & Simulation Tools
- SITL (Software-In-The-Loop): Run PX4 or ArduPilot inside Gazebo Harmonic or Isaac Sim. This lets you test ROS 2 nodes and computer vision models without risk of crashing hardware.
- HITL (Hardware-In-The-Loop): Connect your actual onboard computer (e.g., Jetson Orin) and flight controller (e.g., Pixhawk 6C) via serial/Ethernet to simulate physical hardware interaction before outdoor testing.