Embedded Linux HMI Development: Custom Interface Design with Yocto and Qt
Introduction
The dominance of Windows CE and proprietary solutions in industrial HMI systems has been rapidly shifting towards Embedded Linux in recent years. Our HMI Industrial Display Solutions are at the center of this paradigm shift: customized Linux distribution with Yocto Project and modern interface development with Qt/QML.
In this article, we examine how to build an embedded Linux HMI from scratch, Qt integration on the Yocto infrastructure we explained in our blog, and real-world applications.
Why Embedded Linux + Qt?
Limitations of Traditional HMI Solutions
1. Windows CE / Windows Embedded
- License costs ($100+ per device)
- Security updates ended (Windows CE EOL in 2018)
- High hardware requirements (minimum 512MB RAM)
2. Proprietary Solutions (Siemens WinCC, Rockwell FactoryTalk)
- Vendor lock-in
- Limited customization options
- High software costs
3. Arduino/MCU-based Simple Displays
- Low graphics performance
- Limited networking (weak TCP/IP stack)
- Insufficient for complex applications
Advantages of Embedded Linux + Qt
✅ Open Source & Free: No license costs
✅ Full Control: Customize every layer of OS
✅ Powerful Graphics: Hardware-accelerated UI with Qt Quick (QML)
✅ Networking: Native TCP/IP, MQTT, Modbus support
✅ OTA Updates: Secure software updates with A/B partition
✅ Long Lifespan: Linux kernel and Qt, 10+ years support guarantee
Yocto Project: Custom Linux Image
What is Yocto?
Yocto Project is a build system for creating customized Linux distributions for embedded devices. Difference from standard Ubuntu/Debian:
- Minimal footprint: Only needed packages included (~50MB rootfs)
- Cross-compilation: Compile for ARM processors on development PC (x86)
- Reproducible builds: Every build produces same result
Yocto Layer Structure for HMI
meta-hmi-amazeng/
├── recipes-core/
│ └── images/
│ └── hmi-image.bb # Main image recipe
├── recipes-graphics/
│ └── qt5/
│ └── qtbase_%.bbappend # Qt customizations
├── recipes-connectivity/
│ └── modbus/
│ └── libmodbus_git.bb # Modbus library
├── recipes-kernel/
│ └── linux/
│ └── linux-%.bbappend # Touchscreen drivers
└── recipes-app/
└── hmi-app/
└── hmi-app_git.bb # HMI application
Example HMI Image Recipe
# hmi-image.bb
DESCRIPTION = "Amazeng HMI Linux Image"
LICENSE = "MIT"
IMAGE_FEATURES += " \
splash \
ssh-server-dropbear \
hwcodecs \
"
IMAGE_INSTALL = " \
packagegroup-core-boot \
qtbase \
qtdeclarative \
qtquickcontrols2 \
qtgraphicaleffects \
qtsvg \
qtwebsockets \
libmodbus \
hmi-app \
ca-certificates \
tzdata \
"
inherit core-image
Modern HMI Interface with Qt/QML
Qt Quick (QML) vs Qt Widgets
| Feature | Qt Widgets (C++) | Qt Quick (QML) |
|---|---|---|
| Performance | CPU-based | GPU-accelerated |
| Development Speed | Slow (compile) | Fast (interpreted) |
| Animation | Complex | Very easy |
| Touchscreen | Mouse events | Native touch |
| Designer Support | Qt Designer | Qt Design Studio |
Qt Quick (QML) should definitely be preferred for HMI applications.
Simple HMI Application: Loadcell Reader
HMI reading weight from GDT Digital Transmitter via Modbus TCP:
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
ApplicationWindow {
visible: true
width: 1024
height: 600
title: "GDT Loadcell Monitor"
// Background gradient
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#2C3E50" }
GradientStop { position: 1.0; color: "#34495E" }
}
}
ColumnLayout {
anchors.centerIn: parent
spacing: 30
// Title
Text {
text: "Tank 1 - Net Weight"
font.pixelSize: 36
font.bold: true
color: "#ECF0F1"
Layout.alignment: Qt.AlignHCenter
}
// Weight display
Rectangle {
width: 600
height: 200
color: "#1ABC9C"
radius: 20
Text {
anchors.centerIn: parent
text: modbusBackend.weight.toFixed(2) + " kg"
font.pixelSize: 72
font.bold: true
color: "white"
}
}
// Control buttons
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 20
Button {
text: "TARE"
font.pixelSize: 24
implicitWidth: 150
implicitHeight: 80
onClicked: modbusBackend.tare()
}
Button {
text: "ZERO"
font.pixelSize: 24
implicitWidth: 150
implicitHeight: 80
onClicked: modbusBackend.zero()
}
}
}
}
Real World Application: Multi-Tank Monitoring
Scenario
3 milk tanks, each with GDT Digital Transmitter + 4 loadcells. Monitoring all tanks with a central 10.1" HMI.
Architecture
┌──────────────┐ Modbus TCP ┌──────────────┐
│ Tank 1 GDT │◄─────────────────►│ │
│ 192.168.1.101│ │ │
└──────────────┘ │ HMI Panel │
│ (10.1 inch) │
┌──────────────┐ Modbus TCP │ Qt/QML │
│ Tank 2 GDT │◄─────────────────►│ │
│ 192.168.1.102│ │ │
└──────────────┘ └──────────────┘
Cloud Integration: HMI + AWS IoT
HMI panel can also work as an IoT gateway. In our Cloud & IoT Data Collection solution, HMI:
- Collects data from ZMA and GDT devices via Modbus RTU/TCP
- Sends to AWS IoT Core via MQTT
- Displays both on local interface and Grafana dashboard
Qt MQTT Client Example:
#include <QtMqtt/QMqttClient>
QMqttClient *mqttClient = new QMqttClient(this);
mqttClient->setHostname("xxxxx.iot.eu-west-1.amazonaws.com");
mqttClient->setPort(8883);
mqttClient->connectToHost();
// Publish data read from GDT
QByteArray payload = QString("{\"tank_id\":1,\"weight\":%1}").arg(weight).toUtf8();
mqttClient->publish("amazeng/tank/data", payload);
Conclusion
The Embedded Linux + Qt combination is the most flexible and powerful solution for modern industrial HMIs. Our HMI Industrial Display Solutions are built on this technology stack and:
✅ 70% more economical than proprietary solutions
✅ Full customization freedom
✅ 10+ years long-term support guarantee
✅ Ready for Cloud and IoT integration
Related Resources
- Embedded Linux with Yocto
- Why We Use Zephyr RTOS (alternative RTOS approach)
- HMI Industrial Display Solutions
- Cloud & IoT Data Collection