Key Takeaways
- QGroundControl’s default 2D map can be upgraded to a Cesium 3D globe by embedding a QML
WebEngineView. - Drone position comes from GPS longitude, latitude and altitude, while roll, pitch and yaw are streamed over MAVLink.
- Qt forwards telemetry to JavaScript through
QWebChannel, and Cesium updates the GLB model’sModelMatrix. - Common blockers are WebGL shared-context conflicts, Cesium ion network errors and GLB axis/origin mismatches.
- As of 2026, the same pattern extends to multi-drone display and GPS/attitude track replay.
Building a QGroundControl 3D digital twin means replacing the flat 2D map with a real WebGL globe: you embed Cesium inside QGroundControl’s Qt/QML stack, load a GLB drone model, and drive its position and attitude from live MAVLink telemetry. This guide walks through the full architecture, the initialization code, the Qt-to-JavaScript bridge, and the three problems that most developers hit, based on a 2026 integration project.
1. Project Background
QGroundControl traditionally relies on a 2D map to show where a UAV is. As drones, robotics and digital-twin technology have advanced, that 2D view is no longer enough for complex scenarios. This project introduces a Cesium 3D globe into QGroundControl to deliver four capabilities:
- Displaying the drone on a 3D globe
- Loading a GLB drone model
- Real-time longitude/latitude positioning
- Roll, pitch and yaw attitude synchronization
- Data exchange between Qt and JavaScript
The original animated GIF cannot be uploaded, so a screenshot is used instead:
2. Overall Architecture
The system data flow moves from the flight controller, through QGroundControl’s C++ layer, across the Qt WebChannel, into JavaScript, and finally into Cesium.

3. Why Choose Cesium
Cesium is a WebGL-based 3D globe engine. Compared with a traditional 2D map it offers a true three-dimensional earth, supports real elevation models, and accepts GLB / 3D Tiles assets.

4. Embedding Cesium in Qt
QGroundControl uses a Qt/QML architecture, so it is generally not practical to embed Cesium directly with a C++ QWebEngineView. The cleaner route is to use the QML WebEngineView, the same QML surface you extend when you follow a QGroundControl secondary development guide for custom panels and maps. Core code:


5. Cesium Initialization
Inside index.html, create the viewer and disable the widgets you do not need:
const viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false,
homeButton: false,
animation: false,
fullscreenButton: false,
sceneModePicker: false,
timeline: false,
navigationHelpButton: false,
baseLayerPicker: false,
selectionIndicator: false,
infoBox: false,
shouldAnimate: true,
imageryProvider: Cesium.createWorldImagery(),
terrainProvider: Cesium.createWorldTerrain()
});
Turning off unused components such as the timeline, animation, search box and home button reduces performance overhead.

6. Loading a Drone 3D Model
For the drone model, glTF or GLB is recommended. Example:
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height
),
model: {
uri: "drone.glb"
}
});
The result is an aircraft whose position follows GPS and altitude in real time, with a full 3D model on screen.

7. MAVLink Attitude Synchronization
The flight controller outputs attitude as roll, pitch and yaw through the ATTITUDE message. If you also need an onboard companion computer, the tooling described in our pymavlink for ArduPilot on a Raspberry Pi walkthrough feeds the very same MAVLink stream. The data flow is:
Flight controller attitude
|
| MAVLink
|
QGroundControl C++
|
| Qt WebChannel
|
JavaScript
|
| Cesium ModelMatrix
8. Qt and JavaScript Communication
On the Qt side, register the object that will be exposed to JavaScript:
QWebChannel channel;
channel.registerObject("drone", object);
In JavaScript, connect to the channel and bind the object:
new QWebChannel(qt.webChannelTransport, function(channel) {
drone = channel.objects.drone;
// render
});
The implementation sends GPS, altitude and attitude from C++ in real time, and JavaScript updates the 3D model accordingly.
9. Problems Encountered During Development
9.1 WebGL GPU Context Conflict
The error returned is Failed to create shared context. The cause is that the Qt Quick OpenGL environment can conflict with Chromium’s WebGL. The direction for a fix is to adjust the Qt graphics backend, avoid forcing OpenGL, and use an appropriate Qt WebEngine configuration.

9.2 Cesium Map Load Failure
The reported error is ERR_NETWORK_ACCESS_DENIED, because Cesium ion or an online map requires network access. Solutions include local tiles, MBTiles and a self-hosted map service.
9.3 3D Model Orientation Problems
Models may come from different tools, for example Creo, Rhino or KeyShot, then exported to GLB and loaded into Cesium. Because coordinate systems differ between programs, you may need to adjust the XYZ axes, the model origin and the heading direction.
10. Future Extension Directions
The approach can be extended in several ways. Multi-drone display lets you show several aircraft, for example Drone1, Drone2 and Drone3, simultaneously. Track replay records GPS, altitude and attitude so historical flight paths can be played back. Before adding more airframes, it helps to have a stable development setup, as covered in our ArduPilot environment setup guide, and to understand the flight controller hardware feeding the telemetry.
Summary
By embedding Cesium into QGroundControl through Qt WebEngine, a conventional ground station can be upgraded from a 2D map into a 3D digital-twin platform. The technology stack is Qt + QGroundControl + MAVLink + Cesium + a GLB model, giving UAV, robotics and autonomous-driving systems a far more intuitive three-dimensional situational display.
Have questions about this article? Feel free to contact us at [email protected] — we’re happy to help!
Frequently Asked Questions
What is a QGroundControl 3D digital twin?
A QGroundControl 3D digital twin is a live three-dimensional replica of a drone inside the ground station. Instead of a flat 2D map, the aircraft is rendered as a GLB model on a Cesium globe, with position and attitude updated from MAVLink telemetry in real time.
Why use Cesium instead of the built-in QGroundControl map?
Cesium is a WebGL globe engine that supports real elevation models and GLB or 3D Tiles assets. That makes it far better suited to complex scenes than the default flat map, especially when you need spatial context, terrain and a true 3D attitude view.
How does Qt send data to Cesium in JavaScript?
Qt exposes a C++ object through QWebChannel, and JavaScript binds it with channel.objects.drone. The C++ side pushes GPS, altitude and attitude, and JavaScript applies those values to the Cesium model’s ModelMatrix each frame.
How do I fix “Failed to create shared context” in Qt?
That WebGL error usually means the Qt Quick OpenGL environment is conflicting with Chromium. Fix it by adjusting the Qt graphics backend, avoiding a forced OpenGL path, and applying an appropriate Qt WebEngine configuration rather than leaving defaults in place.
Why does Cesium show ERR_NETWORK_ACCESS_DENIED?
Cesium ion and online imagery need network access, so an offline or firewalled machine returns that error. The practical fix is to serve local tiles, use MBTiles, or host your own map service so the globe can load without external requests.
About Aomway
Aomway supplies FPV and UAV hardware, including video transmitters, antennas and link equipment used across drone platforms. Our team follows ground-station software and MAVLink integration closely, and we are happy to discuss hardware choices for telemetry, video links and digital-twin setups.

