This repository presents a vision-based precision landing pipeline for a quadrotor UAV using a static AprilTag in simulation. The system integrates PX4 SITL, Gazebo, and ROS 2 to perform autonomous takeoff, search, detection, alignment, and landing.
A Constant-Position Kalman Filter (KF) is implemented and evaluated purely as an analysis baseline. Through quantitative metrics and delay analysis, we conclude that raw AprilTag pose estimates outperform KF-filtered poses for a static tag. Consequently, the KF is intentionally NOT used for control in the current system.
The KF work serves as a foundational baseline for future extension to a moving target, where a Constant-Velocity Kalman Filter will be required.
The following video shows the full autonomous mission: takeoff → spiral search → AprilTag detection → alignment → precision landing.
apriltag_precision_landing.webm
- End-to-end PX4–ROS 2 precision landing stack for a static AprilTag
- Spiral trajectory-based visual search strategy
- TF-consistent multi-frame pose estimation pipeline
- Quantitative evaluation of raw vs Kalman-filtered AprilTag poses
- Delay analysis demonstrating KF-induced lag
- Clear justification for rejecting KF in static-tag control
- Design groundwork for future moving-tag landing
In Scope:
- Static AprilTag detection and pose estimation
- Quantitative comparison of raw vs filtered pose quality
- Complete simulation pipeline with PX4 SITL
- Performance metrics and delay analysis
Out of Scope:
- Moving target tracking
- Real-world sensor noise modeling
- Closed-loop visual servoing (current control is open-loop)
- State estimation fusion beyond basic Kalman filtering
Assumptions:
- AprilTag is static and rigidly attached to the ground
- Camera intrinsics are perfectly known (simulation)
- Lighting conditions are ideal
- No wind or external disturbances
flowchart TD
%% ================= Simulation =================
A[PX4 SITL + Gazebo World<br/>Input: World SDF, Vehicle Model<br/>Output: Camera Images, Vehicle State]
%% ================= Perception =================
B[Monocular Camera<br/>Output: image_raw, camera_info]
C[Image Rectification<br/>Input: image_raw<br/>Output: image_rect]
D[AprilTag Detector<br/>Input: image_rect<br/>Output: Tag Pose in Camera Frame]
%% ================= TF =================
E[TF Tree<br/>Inputs:<br/>- Static TF: base_link → camera<br/>- Dynamic TF: map → base_link<br/>- Detection TF: camera → tag<br/>Output: Consistent Frame Transforms]
%% ================= Pose Estimation =================
F[AprilTag Pose in Map Frame<br/>Input: TF lookup<br/>Output: tag_pose_map raw]
%% ================= Kalman Filter =================
G[Constant-Position Kalman Filter<br/>Input: tag_pose_map raw<br/>Output: tag_pose_map_kf<br/>Note: Analysis baseline only]
%% ================= Control =================
H[Vision Guidance Controller<br/>Input: Raw tag_pose_map<br/>Output: Position Setpoints]
I[PX4 Offboard Interface<br/>Input: Position Setpoints<br/>Output: Vehicle Actuation]
%% ================= Logging =================
J[TF State Logger<br/>Inputs:<br/>- Drone State<br/>- Raw Tag Pose<br/>- KF Tag Pose<br/>Output: CSV Logs]
K[Offline Analysis<br/>Inputs: CSV Logs<br/>Outputs:<br/>- Stability Metrics<br/>- Delay Analysis<br/>- Trajectory Plots]
%% ================= Connections =================
A --> B
B --> C
C --> D
D --> E
E --> F
F -->|Raw Pose| H
H --> I
I --> A
F -->|Raw Pose| J
G -->|Filtered Pose| J
F --> G
J --> K
- Ubuntu 22.04
- ROS 2 Humble
- PX4-Autopilot
- Gazebo (Ignition) Garden
- Python 3.8+
This project uses custom Gazebo models and a custom world, which must be manually installed into the PX4 Gazebo directory.
Copy the following folders from this repository:
models/worlds/
into you PX4 installation at:
# Copy models
cp -r models/* ~/PX4-Autopilot/Tools/simulation/gz/models/
# Copy worlds
cp -r worlds/* ~/PX4-Autopilot/Tools/simulation/gz/worlds/Important: PX4 will not detect the AprilTag model or custom world unleass these files are placed in the Gazebo search path shown above
# Clone the repository
cd ~/px4_ros2_ws/src
git clone https://github.com/09priyamgupta/px4_vision_landing_staticTag.git
# Build the workspace
cd ~/px4_ros2_ws
colcon build --symlink-install
# Source the workspace
source install/setup.bashThe project is organized to clearly separate perception, control, analysis, and simulation assets.
px4_vision_landing_staticTag
├── analysis
│ └── plot_tf_logs.py
├── apriltag_land.rviz
├── config
│ ├── apriltag.yaml
│ └── frames.yaml
├── images
│ ├── kf_delay_analysis_x.png
│ ├── kf_delay_analysis_y.png
│ ├── kf_Delay_analysis_z.png
│ ├── landing_performance.png
│ ├── raw_vs_kf_poses.png
│ ├── rviz_analysis.png
│ ├── terminal_metrics_log.png
│ ├── tf_tree.png
│ └── trajectory_comparison.png
├── launch
│ ├── apriltag_pipeline.launch.py
│ └── landing.launch.py
├── models
│ ├── apriltag_1000mm
│ └── x500_mono_cam_down
├── px4_logs
│ └── px4_state_raw_tag_kf_filtered.csv
├── px4_vision_landing_staticTag
│ ├── apriltag_relative_pose.py
│ ├── offboard_experiment_manager.py
│ ├── tag_pose_kf.py
│ ├── tag_rviz_markers.py
│ ├── tf_state_logger.py
│ ├── vision_guidance_controller.py
│ └── utils
├── videos
│ └── apriltag_precision_landing_vision.webm
├── worlds
│ └── px4_vision_landing_staticTag.sdf
├── README.md
├── LICENSE
└── setup.py
| Frame | Description | Publisher |
|---|---|---|
map |
Global ENU world frame | PX4 |
base_link |
Drone body frame | PX4 |
camera_link |
Downward-facing monocular camera | Static TF |
tag36h11:0 |
AprilTag frame | apriltag_ros |
- PX4 publishes
map → base_link(vehicle state) - Static TF defines
base_link → camera_link(mounting offset) - apriltag_ros publishes
camera_link → tag36h11:0(detection) - TF chaining enables
map → tag36h11:0andtag36h11:0 → base_link
Coordinate Convention: All positions are expressed in ENU (East-North-Up) coordinates for consistency with ROS standards.
| State | Description | Transition Condition |
|---|---|---|
TAKEOFF |
Ascend to target altitude | Altitude reached |
SEARCH |
Execute spiral trajectory | Tag detected |
VISION_ACTIVE |
Hand over to vision guidance | Within alignment threshold |
ALIGN |
Lateral alignment over tag | XY error < threshold |
DESCEND |
Controlled vertical descent | Altitude above ground |
LAND |
PX4 land command | Touchdown detected |
- Expands search radius gradually (3m → 10m)
- Maintains continuous camera coverage
- Simple and deterministic
- Maximizes search area coverage
- Maintains smooth motion for stable detection
- Avoids aggressive maneuvers that cause tag loss
- Assumes stationary target
- Inefficient for moving platforms
- Target-relative adaptive search
- Velocity-aware prediction
- Multi-scale search patterns
where
and the process noise is modeled as
where
and the measurement noise is modeled as
Critical Design Decision: The Kalman Filter is NOT used for control in this project.
It is implemented only to answer the question:
Does filtering improve AprilTag pose quality for a static target?
Answer: No. Data shows raw poses outperform KF for static targets due to:
- Phase lag introduction (see delay analysis)
- No significant noise reduction in simulation
- Inconsistent performance across axes
Terminal 1 – Micro XRCE DDS Agent
cd ~/PX4-Autopilot
MicroXRCEAgent udp4 -p 8888
Terminal 2 – PX4 SITL
cd ~/PX4-Autopilot
export PX4_GZ_WORLD=px4_vision_landing_staticTag
make px4_sitl gz_x500_mono_cam_down
Terminal 3 – QGroundControl
qgroundcontrol
Terminal 4 – ROS–Gazebo Bridge
cd ~/px4_ros2_ws
ros2 launch px4_gz_bridge start_bridges.launch.py
Terminal 5 – RViz (for visualization)
rviz2
Terminal 6 – Main Landing System
cd ~/px4_ros2_ws
ros2 launch px4_vision_landing_staticTag landing.launch.py
Rate:10HzFormat:CSV with timestampFields:Drone state, raw tag pose, KF pose, visibility flag
cd ~/px4_ros2_ws/src/px4_vision_landing_staticTag
python3 analysis/plot_tf_logs.py
- Landing Error: Final XY Euclidean distance (m)
- Tracking RMSE: Root Mean Square Error per axis (m)
- Tag Stability: Standard deviation of tag position
- KF Delay: Phase lag via cross-correlation (s)
- Detection Rate: Percentage of frames with tag visible
- Drone follows commanded spiral trajectory
- AprilTag remains static in map frame
- Confirms TF correctness and frame consistency
Observation
- Raw poses track the true tag position closely
- KF output is smoother but visibly lags
Key Insight For a static tag, smoothing adds latency without benefit.
- KF improves Y and Z stability
- KF worsens X error
- Overall benefit is inconsistent
This inconsistency makes KF unsuitable for control.
- Final landing error ≈ 4.7 cm
- Achieved using raw poses only
- Confirms KF is unnecessary for static landing
Interpretation
- KF introduces measurable phase lag
- Delay magnitude depends on motion excitation
- For static signals, cross-correlation becomes unreliable
Conclusion Even small KF delays are unacceptable for precision landing.
| Decision | Justification | Impact |
|---|---|---|
| Use raw poses for control | KF adds lag without accuracy gain | Better responsiveness |
| Spiral search trajectory | Maximizes coverage while maintaining smooth motion | Higher detection rate |
| Static tag assumption | Simplifies initial implementation | Baseline for moving target |
| Open-loop control | Focus on perception evaluation | Clear separation of concerns |
- Static Target Only: Cannot track moving AprilTags
- Simulation Constraints: Ideal lighting, perfect camera calibration
- No Disturbances: No wind, magnetic interference, or sensor biases
- Limited Trajectory Set: Only spiral search implemented
- Altitude-dependent Detection: Tag loss during takeoff/landing phases
- KF Title Discrepancy: Inconsistent delay values between plot and title
- Constant-Velocity Kalman Filter for moving target prediction
- Moving AprilTag platform simulation
- Adaptive search strategies based on detection confidence
- Multi-tag detection for robustness
- Closed-loop visual servoing for landing
- Sensor fusion with IMU and GPS for pose refinement
- Real-world validation with hardware platform
- Obstacle avoidance integration
- Multi-UAV cooperative landing
- Dynamic target interception
- All-weather capability with complementary sensors
- Standardized benchmarking suite
| Issue | Solution |
|---|---|
| Gazebo world not found | Verify models/worlds copied to PX4 directory |
| No AprilTag detection | Check camera FOV, tag size parameter |
| TF lookup failures | Verify all frames in TF tree (ros2 run tf2_tools view_frames) |
| PX4 connection lost | Restart MicroXRCEAgent and PX4 SITL |
| RViz markers missing | Check topic names in RViz config |
If this work contributes to your research, please consider citing:
@software{px4_vision_landing_2026,
title = {Vision-Based Precision Landing on Static AprilTag using PX4 + ROS 2},
author = {Priyam GUpta},
year = {2026},
url = {https://github.com/09priyamgupta/px4_vision_landing_staticTag.git},
note = {Simulation framework for UAV precision landing}
}
Priyam Gupta
This project is licensed under the MIT License. See LICENSE for details.







