Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Case Study: Driver Terminal for 
Forage Harvester 
Burkhard Stubert 
Solopreneur & Chief Engineer 
Embedded Use (DBA) 
www...
About Me 
• Interesting Projects 
– In-flight entertainment system for 
US company 
– In-vehicle infotainment system for 
...
Forage Harvester: Krone BigX 480/580 
11/5/2014 © Burkhard Stubert, 2014 3
Project Schedule 
• 06/2012: Project start 
• 08/2012: First prototype in corn 
harvest 
– Qt 4.8 on Windows XP and Intel ...
System Architecture 
GUI in QML 
150 screens 
50 QML components 
Business Logic in Qt/C++ 
30 ECU functions 
CAN message h...
Modes: Field, Road, Maintenance 
11/5/2014 © Burkhard Stubert, 2014 6
Modes: Day and Night 
11/5/2014 © Burkhard Stubert, 2014 7
Internationalization 
Metric vs. Imperial Units Multiple Languages 
11/5/2014 © Burkhard Stubert, 2014 8
More Features 
• User input with both 
touch and rotary/push 
knob 
• Crop area management 
• Access to machine 
parameter...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViews Well 
• An Efficient Page Stack 
• Themes for Day and Night M...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViews Well 
• An Efficient Page Stack 
• Themes for Day and Night M...
Dividing Application into Threads 
GUI Thread 
asynchronous 
signal-slot connections 
ECU Thread File Thread 
Average of 2...
Setting up the Threads 
int main(int argc, char *argv[]) { 
QGuiApplication app(argc, argv); 
QThread fileThread; 
FileMan...
Inter-Thread Calls with Signals & Slots 
// Set up inter-thread connections in HomeModel, 
// which is in GUI thread 
conn...
Caveats 
• Arguments of queued connections must be builtins or have 
copy constructor 
– Examples: int, QString, const QLi...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViewsWell 
• An Efficient Page Stack 
• Themes for Day and Night Mo...
Over-Generalized QML Delegates 
• AllInOneDelegate instantiates 10 cells 
– For unused cells: visible: false 
• AllInOneCe...
Over-Generalized QML Delegates (2) 
• Solution: 
– Write a delegate for each type of ListView 
– Write a component for eac...
Bad Vibrations 
• Problem: 
– Due to harvester’s vibrations and resistive touch, 
tapping always interpreted as flicking 
...
Nested C++ List Models 
• Roles of SeasonView 
– pName: QString 
– pValue: EnumListModel* 
• Roles of SingleChoiceDialog 
...
Passing EnumListModel* to QML 
// Delegate of SeasonView 
Row { 
DisplayCell { 
text: pName 
} 
EditCell { 
SingleChoiceDi...
Passing EnumListModel* to QML (2) 
// In SeasonModel.h 
class SeasonModel : public QAbstractListModel { 
struct RowData { ...
Passing EnumListModel* to QML (3) 
// In SeasonModel.cpp 
QVariant SeasonModel::data(const QModelIndex &index, int role) c...
Wrapping Enum in ListModel 
class EnumListModel : public QAbstractListModel { 
Q_OBJECT 
Q_PROPERTY(int eIndex READ getEIn...
Wrapping Enum in ListModel (2) 
// In ParameterEnums.h 
class ParameterEnums : public QObject { 
Q_OBJECT 
Q_ENUMS(Attachm...
Wrapping Enum in ListModel (3) 
// In SeasonModel.cpp 
Emits dataChanged(QModelIndex, QModelIndex) 
of QAbstractListModel ...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViews Well 
• An Efficient Page Stack 
• Themes for Day and Night M...
Page Stack: Bad Implementation 
• Problem: 
– Every QML item with 
“visible: true” is rendered 
– 4 full screens of 1024x7...
Page Stack: Good Implementation 
• Solution: 
– All pages except top page have 
“visible: false” 
– If transition animated...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViews Well 
• An Efficient Page Stack 
• Themes for Day and Night M...
Day and Night Mode 
• Theme 
– GUI Structure unchanged 
– Look changes: text and 
background colours, images 
• Change bet...
Changing Theme in C++ 
// In ThemeManager.cpp 
// Exposed to QML as singleton 
void ThemeManager::setTheme(const QString &...
Theme Selection in QML 
// In Main.qml 
property alias g_theme: themeLoader.item 
Loader { 
id: themeLoader 
source: Qt.re...
Theme Files 
DayTheme.qml 
Item { 
property color textColor: “black” 
property color lineColor1: “#333333” 
property color...
Organisation in File System 
/path/to/my/app/qml 
+night/ 
images/ 
bg_CentralArea.png 
bg_TableRow1.png 
AccelerationRamp...
Agenda 
• Multi-Threaded Architecture 
• Know Your ListViews Well 
• An Efficient Page Stack 
• Themes for Day and Night M...
Multiple Languages 
• Change between languages 
at runtime 
• Two solutions: 
– [S1] qsTr bound to 
languageChanged proper...
[S1] QML Client Code 
// In a QML file 
Text { 
text: qsTr(“Areas”) + g_tr.languageChanged 
// … 
} 
When property g_tr.la...
[S1] Changing Language in C++ 
// In TranslationMgr.h 
// Exposed to QML as singleton g_tr 
class TranslationMgr : public ...
[S1] Changing Language in C++ 
// In TranslationMgr.cpp 
void TranslationMgr::setLanguage(const QString &lang) { 
if (m_la...
[S2] QML Client Code 
// In a QML file 
Text { 
text: g_tr.s_areas 
// … 
} 
Simpler than 
qsTr(“Areas”) + g_tr.languageCh...
[S2] Changing Language in C++ 
// In TranslationMgr.cpp 
// Exposed to QML as singleton TranslationMgr 
void TranslationMg...
[S2] Translation Selection in QML 
// In Main.qml 
property alias g_tr: trLoader.item 
Loader { 
id: trLoader 
source: Qt....
[S2] Translation Files with qsTr 
Translations.qml (en_US) 
Item { 
property string s_arm_rest: 
qsTr(“Arm rest”) 
propert...
[S2] Translation Files without qsTr 
Translations.qml (en_US) 
Item { 
property string s_arm_rest: “Arm rest” 
property st...
Terminal Krone Big X 480/580 
11/5/2014 © Burkhard Stubert, 2014 46
Upcoming SlideShare
Loading in …5
×

3

Share

Download to read offline

Developing Driver Terminal for Forage Harvester with QML and Qt

Download to read offline

The driver terminal of Krone’s BiG X 480/580 forage harvester uses dials, info fields, quick-access buttons and status buttons to show about 30+ pieces of information on its home screen. The driver can change some of the information directly on the home screen. The terminal receives up to 250 signals per second from the “machine” over 4 CAN buses. Some of the signals are received up to 100 times per second. Nevertheless, the needles of the dials and the digital numbers must change smoothly.

Moreover, the driver can fine-tune 1000+ parameters of 30 control units. He can perform on-board diagnostics and calibrate parts of the machine. He can dynamically change between languages, measurement units, and day and night mode. The terminal can “count” the harvested area, diesel consumption or the usage hours of the cutting drum or front attachment.

Burkhard was the lead developer for building the driver terminal of Krone’s BiG X 480/580 forage harvester. He worked together with two developers from Krone and an independent UI designer. It took the team 21 months from the first UI design to the product release. A first prototype was ready for a maize harvest after less than three months. The GUI parts of the driver terminal were developed with QML and the non-GUI parts with Qt/C++.

Burkhard will share his first-hand experience from this project and will explain how the team solved some typical challenges of such a project.

(1) The team used a multi-threaded architecture to cope with the load of up to 1000 messages per second from the machine. The communication between the threads is done exclusively with Qt’s signals and slots. Special considerations are needed for singletons.

2) The team faced some QML performance problems. For example, the standard implementation of a screen stack from QtQuick components would require the graphics power of a 4K TV. Or, over-generalised QML delegates, which make unused parts invisible, can render the scrolling of a ListView unusable.

(3) Selecting the right touchscreen display, which is used on a 500 horse-power harvester with “good vibrations” under bright daylight and at night, is quite tricky.

(4) The project started with Qt 4.8 on an Intel-Atom system with Windows XP and without OpenGL acceleration. It then moved to an ARM Cortex-A8 CPU with OpenGL acceleration. It was finally released with Qt 5.1.

(5) The ultimate challenge was to develop the driver terminal with three developers and one UI designer in less than two years. A first prototype had to be available for the maize harvest after three months. Problems found during the 6-weeks window of a harvest season had to be fixed basically over night.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Developing Driver Terminal for Forage Harvester with QML and Qt

  1. 1. Case Study: Driver Terminal for Forage Harvester Burkhard Stubert Solopreneur & Chief Engineer Embedded Use (DBA) www.embeddeduse.com
  2. 2. About Me • Interesting Projects – In-flight entertainment system for US company – In-vehicle infotainment system for German tier-1 supplier – Driver terminal for Krone harvester – Internet radio for CSR – VoIP handset for xG • 15+ years developing embedded and desktop systems – Especially with Qt and C++ – Architecture, development, test, coaching, project lead • Previous companies: – Nokia, Cambridge Consultants, Infineon, Siemens Burkhard Stubert Solopreneur & Chief Engineer Embedded Use (DBA) Mail: burkhard.stubert@embeddeduse.com Web: www.embeddeduse.com Mobile: +49 176 721 433 16 11/5/2014 © Burkhard Stubert, 2014 2
  3. 3. Forage Harvester: Krone BigX 480/580 11/5/2014 © Burkhard Stubert, 2014 3
  4. 4. Project Schedule • 06/2012: Project start • 08/2012: First prototype in corn harvest – Qt 4.8 on Windows XP and Intel Atom • 02/2013: Usability test with drivers – Qt 5.1 on Linux and ARM Cortex-A8 • 05/2013: Alpha in grass harvest • 08/2013: Beta in corn harvest • 11/2013: Shown at Agritechnica • 04/2014: Product release Old New All done with 3 SW developers and 1 UI designer! 11/5/2014 © Burkhard Stubert, 2014 4
  5. 5. System Architecture GUI in QML 150 screens 50 QML components Business Logic in Qt/C++ 30 ECU functions CAN message handling Linux 250 classes Incl. 20 list models Terminal CCPilot XS Freescale i.Mx53 OpenGL ES2 RAM: 1GB, Flash: 4GB Display: 10”, 1024x768 Resistive touch 4x CAN, USB, A/V, Eth 11/5/2014 © Burkhard Stubert, 2014 5
  6. 6. Modes: Field, Road, Maintenance 11/5/2014 © Burkhard Stubert, 2014 6
  7. 7. Modes: Day and Night 11/5/2014 © Burkhard Stubert, 2014 7
  8. 8. Internationalization Metric vs. Imperial Units Multiple Languages 11/5/2014 © Burkhard Stubert, 2014 8
  9. 9. More Features • User input with both touch and rotary/push knob • Crop area management • Access to machine parameters for fine tuning • On-Board Diagnosis 11/5/2014 © Burkhard Stubert, 2014 9
  10. 10. Agenda • Multi-Threaded Architecture • Know Your ListViews Well • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 10
  11. 11. Agenda • Multi-Threaded Architecture • Know Your ListViews Well • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 11
  12. 12. Dividing Application into Threads GUI Thread asynchronous signal-slot connections ECU Thread File Thread Average of 250 File I/O very slow CAN messages per second CAN I/O ECUs SD Card 11/5/2014 © Burkhard Stubert, 2014 12
  13. 13. Setting up the Threads int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QThread fileThread; FileManager::instance()->moveToThread(&fileThread); QThread ecuThread; EcuManager::instance()->moveToThread(&ecuThread); fileThread.start(); ecuThread.start(); QQuickView view; view.setSource(“main.qml”); view.show(); return app.exec(); } FileManager and EcuManger are single entry point into fileThread and ecuThread All singletons used in several threads must be created before threads started! Starts event loop of QThread object. Needed for queued signal-slot connections 11/5/2014 © Burkhard Stubert, 2014 13
  14. 14. Inter-Thread Calls with Signals & Slots // Set up inter-thread connections in HomeModel, // which is in GUI thread connect(EcuManager::instance()->getDieselEngine(), SIGNAL(engineSpeed(float)), this, SLOT(setEngineSpeed(float))); Sender and receiver in different threads. Hence: Qt::QueuedConnection Triggering the queued connection: DieselEngine engineSpeed(float) setEngineSpeed(float) HomeModel Meta object appends slot to event loop of GUI thread When event loop of GUI thread executed next time, slot is called Best of all: No thread synchronisation needed! 11/5/2014 © Burkhard Stubert, 2014 14
  15. 15. Caveats • Arguments of queued connections must be builtins or have copy constructor – Examples: int, QString, const QList<float>& • Don’t pass pointers over queued connections • Don’t call into other thread directly • Create singletons used in 2+ threads before threads started – Before C++11: No guarantee that synchronisation of singleton creation works on multi-core/processor machines • See “C++ and the Perils of Double-Checked Locking” by Scott Meyers and Andrei Alexandrescu, 2004, Dr. Dobbs Journal – Since C++11: Double-checked locking fixed • See “Double-Checked Locking is Fixed in C++11” by Jeff Preshing, 2013 • But: instance() with synchronisation performs considerably worse than without 11/5/2014 © Burkhard Stubert, 2014 15
  16. 16. Agenda • Multi-Threaded Architecture • Know Your ListViewsWell • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 16
  17. 17. Over-Generalized QML Delegates • AllInOneDelegate instantiates 10 cells – For unused cells: visible: false • AllInOneCell instantiates 5 types of cells – For unused types (4 out of 5): visible: false • Problem: – For each visible row, ListView creates 50 objects – While scrolling, rows are deleted and created when becoming invisible and visible • Result: Scrolling becomes erratic for 30+ rows 11/5/2014 © Burkhard Stubert, 2014 17
  18. 18. Over-Generalized QML Delegates (2) • Solution: – Write a delegate for each type of ListView – Write a component for each type of cell – For each visible row, ListView creates 1 object for each cell • For the examples: 3 instead of 50 objects created 11/5/2014 © Burkhard Stubert, 2014 18
  19. 19. Bad Vibrations • Problem: – Due to harvester’s vibrations and resistive touch, tapping always interpreted as flicking • Solution: – Read-only cells used for flicking – Editable cells used for tapping (selection) 11/5/2014 © Burkhard Stubert, 2014 19
  20. 20. Nested C++ List Models • Roles of SeasonView – pName: QString – pValue: EnumListModel* • Roles of SingleChoiceDialog – eName: QString – eValue: int 11/5/2014 © Burkhard Stubert, 2014 20
  21. 21. Passing EnumListModel* to QML // Delegate of SeasonView Row { DisplayCell { text: pName } EditCell { SingleChoiceDialog is ListView with pValue as its model text: pValue.eName onClicked: g_guiMgr.pushPage( “SingleChoiceDialog”, { “model”: pValue } ); } } 11/5/2014 © Burkhard Stubert, 2014 21
  22. 22. Passing EnumListModel* to QML (2) // In SeasonModel.h class SeasonModel : public QAbstractListModel { struct RowData { QString pName; EnumListModel *pValue; }; QList<RowData *> m_data; public slots: void receiveParameters(const QList<ParamData> &params); // More … }; Slot (in GUI thread) triggered by signal from ECU thread ParamData is copyable object providing the data of a row in SeasonView 11/5/2014 © Burkhard Stubert, 2014 22
  23. 23. Passing EnumListModel* to QML (3) // In SeasonModel.cpp QVariant SeasonModel::data(const QModelIndex &index, int role) const { // Some checks ... QVariant v; switch (role) { case ROLE_PNAME: return m_data[index.row()]->pName; case ROLE_PVALUE: v.setValue(static_cast<QObject*>(m_data[index.row()]->pValue)); return v; default: return v; } } Must be QObject*, because only pointer type registered with QVariant. Custom pointer types cannot be registered with QVariant. 11/5/2014 © Burkhard Stubert, 2014 23
  24. 24. Wrapping Enum in ListModel class EnumListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int eIndex READ getEIndex WRITE setEIndex NOTIFY eIndexChanged) Q_PROPERTY(int eName READ getEName NOTIFY eIndexChanged) Q_PROPERTY(int eValue READ getEValue NOTIFY eIndexChanged) signals: void eIndexChanged(); public: EnumListModel(QMap<int, QPair<QString, int> >&(*func)(), QObject *parent = 0) // More … Index of the currently selected item in the ListView eName and eValue depend fully on eIndex. Hence, no setter and same notification signal as eIndex Function with mapping from index to pair of enum string and value Getters, setters for properties. roleNames(), data(), rowCount() for QAbstractListModel 11/5/2014 © Burkhard Stubert, 2014 24
  25. 25. Wrapping Enum in ListModel (2) // In ParameterEnums.h class ParameterEnums : public QObject { Q_OBJECT Q_ENUMS(AttachmentProfile) public: enum AttachmentProfile { AP_NONE = 0, AP_GRASS, AP_MAIZE_2 //… }; static QMap<int, QPair<QString, int> > &getApEnum() { static QMap<int, QPair<QString, int> > m; if (m.isEmpty()) { m.insert(0, qMakePair(QString(“Without front attachment”), AP_NONE)); m.insert(1, qMakePair(QString(“Grass”), AP_GRASS)); m.insert(2, qMakePair(QString(“Maize 2-part”), AP_MAIZE_2)); // … } return m; } 11/5/2014 © Burkhard Stubert, 2014 25
  26. 26. Wrapping Enum in ListModel (3) // In SeasonModel.cpp Emits dataChanged(QModelIndex, QModelIndex) of QAbstractListModel for row given as argument // In constructor m_mapper = new QSignalMapper(this); connect(m_mapper, SIGNAL(mapped(int)), this, SLOT(emitDataChanged(int))); // In slot receiving data from ECU thread void SeasonModel::receiveParameters(const QList<ParamData> &params) { for (int i = 0; i < params.count(); ++i) { RowData *rd = new RowData; if (params[i].pValueType == ParamData::VT_ENUM) { rd->pName = params[i].pName; rd->pValue = new EnumListModel(params[i].enumFunc, this); connect(rd, SIGNAL(eIndexChanged()), m_mapper, SLOT(map())); m_mapper->setMapping(rd, i); } // other value types For example: ParameterEnums::getApEnum() 11/5/2014 © Burkhard Stubert, 2014 26
  27. 27. Agenda • Multi-Threaded Architecture • Know Your ListViews Well • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 27
  28. 28. Page Stack: Bad Implementation • Problem: – Every QML item with “visible: true” is rendered – 4 full screens of 1024x768 pixels rendered! • GUI hardly responsive! • Occurred in PageStack of Qt 4.8 FrontAttachment visible: true CropFlow visible: true MainMenu visible: true Home visible: true Page Stack Top 11/5/2014 © Burkhard Stubert, 2014 28
  29. 29. Page Stack: Good Implementation • Solution: – All pages except top page have “visible: false” – If transition animated, set “visible: false” when animation finished • Correct in StackView since Qt 5.1 – But: Too much Javascript! • Note: Two full screens during animation may be too much for some GPUs FrontAttachment visible: true CropFlow visible: false MainMenu visible: false Home visible: false Page Stack Top 11/5/2014 © Burkhard Stubert, 2014 29
  30. 30. Agenda • Multi-Threaded Architecture • Know Your ListViews Well • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 30
  31. 31. Day and Night Mode • Theme – GUI Structure unchanged – Look changes: text and background colours, images • Change between day and night theme at runtime • Solution: QQmlFileSelector 11/5/2014 © Burkhard Stubert, 2014 31
  32. 32. Changing Theme in C++ // In ThemeManager.cpp // Exposed to QML as singleton void ThemeManager::setTheme(const QString &theme) { if (m_theme == theme) return; m_theme = theme; QStringList xsel; if (m_theme == “night”) { xsel << m_theme; } Triggered in QML by ThemeManager.theme = “night” Searches for …/+night/Theme.qml Day theme is default with empty selector list Searches for …/Theme.qml QQmlFileSelector::get(m_qmlEngine)->setExtraSelectors(xsel); emit themeChanged(); } Extra selectors searched before locale Notify QML about and platform selectors theme change 11/5/2014 © Burkhard Stubert, 2014 32
  33. 33. Theme Selection in QML // In Main.qml property alias g_theme: themeLoader.item Loader { id: themeLoader source: Qt.resolvedUrl(“Theme.qml”) } Connections { target: ThemeManager onThemeChanged: { themeLoader.source = Qt.resolvedUrl(“Theme.qml”) } } Name of theme file same for day and night mode Singleton managing themes Loads file variant for new theme Binding for every theme variable changes 11/5/2014 © Burkhard Stubert, 2014 33
  34. 34. Theme Files DayTheme.qml Item { property color textColor: “black” property color lineColor1: “#333333” property color backgroundColor1: “#E6E6E6” property url bg_centralArea: “images/bg_CentralArea.png” property url bg_tableRow1: “images/bg_TableRow1.png” property url ic_accelerationRamp1: “images/AccelerationRamp1.png” // Many more … } NightTheme.qml Item { property color textColor: “white” property color lineColor1: “#000000” property color backgroundColor1: “#595959” property url bg_centralArea: “images/bg_CentralArea.png” property url bg_tableRow1: “images/bg_TableRow1.png” property url ic_accelerationRamp1: “images/AccelerationRamp1.png” // Many more … } Property names used in QML code instead of actual values source: g_theme.bg_centralArea 11/5/2014 © Burkhard Stubert, 2014 34
  35. 35. Organisation in File System /path/to/my/app/qml +night/ images/ bg_CentralArea.png bg_TableRow1.png AccelerationRamp1.png Theme.qml images/ bg_CentralArea.png bg_TableRow1.png AccelerationRamp1.png Theme.qml Files for night theme in variant directory Files for day/default theme in plain directory 11/5/2014 © Burkhard Stubert, 2014 35
  36. 36. Agenda • Multi-Threaded Architecture • Know Your ListViews Well • An Efficient Page Stack • Themes for Day and Night Mode • Internationalisation 11/5/2014 © Burkhard Stubert, 2014 36
  37. 37. Multiple Languages • Change between languages at runtime • Two solutions: – [S1] qsTr bound to languageChanged property – [S2] “Theme” for each language 11/5/2014 © Burkhard Stubert, 2014 37
  38. 38. [S1] QML Client Code // In a QML file Text { text: qsTr(“Areas”) + g_tr.languageChanged // … } When property g_tr.languageChanged changes, property text must be re-evaluated and qsTr(“Areas”) re-executed Translation of “Areas” assigned to property text 11/5/2014 © Burkhard Stubert, 2014 38
  39. 39. [S1] Changing Language in C++ // In TranslationMgr.h // Exposed to QML as singleton g_tr class TranslationMgr : public QObject { Q_OBJECT Q_PROPERTY(QString languageChanged READ getLanguageChanged NOTIFY languageChanged) QString getLanguageChanged() const { return “”; } signals: void languageChanged(); Must return empty string to keep translated string unchanged 11/5/2014 © Burkhard Stubert, 2014 39
  40. 40. [S1] Changing Language in C++ // In TranslationMgr.cpp void TranslationMgr::setLanguage(const QString &lang) { if (m_lang == lang) return; // Install proper QTranslator for language // … QLocale::setDefault(lang); emit languageChanged(); } Triggered in QML by g_tr.language = “de_DE” Load qm file for lang (e.g., “de_DE”) Set default locale to lang (e.g., “de_DE”) Notify QML about language change 11/5/2014 © Burkhard Stubert, 2014 40
  41. 41. [S2] QML Client Code // In a QML file Text { text: g_tr.s_areas // … } Simpler than qsTr(“Areas”) + g_tr.languageChanged 11/5/2014 © Burkhard Stubert, 2014 41
  42. 42. [S2] Changing Language in C++ // In TranslationMgr.cpp // Exposed to QML as singleton TranslationMgr void TranslationMgr::setLanguage(const QString &lang) { if (m_lang == lang) return; // Install proper QTranslator for language // … QLocale::setDefault(lang); emit languageChanged(); } Triggered in QML by TranslationMgr.language = “de_DE” Load qm file for lang (e.g., “de_DE”) File selector supports locales Searches for …/+de_DE/Translations.qml Use proper default (e.g., en_US) Notify QML about theme change 11/5/2014 © Burkhard Stubert, 2014 42
  43. 43. [S2] Translation Selection in QML // In Main.qml property alias g_tr: trLoader.item Loader { id: trLoader source: Qt.resolvedUrl(“Translations.qml”) } Connections { target: TranslationMgr onLanguageChanged: { trLoader.source = Qt.resolvedUrl(“Translations.qml”) } } Name of translation file same for all languages Singleton managing translations Loads file variant for new language Binding for every translated string changes 11/5/2014 © Burkhard Stubert, 2014 43
  44. 44. [S2] Translation Files with qsTr Translations.qml (en_US) Item { property string s_arm_rest: qsTr(“Arm rest”) property string s_settings: qsTr(“Settings”) property string s_areas: qsTr(“Areas”) Translations.qml (de_DE) Item { property string s_arm_rest: qsTr(“Arm rest”) property string s_settings: qsTr(“Settings”) property string s_areas: qsTr(“Areas”) Property names used in QML code instead of qsTr(“string”) text: g_tr.s_areas qsTr() does the actual translation 11/5/2014 © Burkhard Stubert, 2014 44
  45. 45. [S2] Translation Files without qsTr Translations.qml (en_US) Item { property string s_arm_rest: “Arm rest” property string s_settings: “Settings” property string s_areas: “Areas” Translations.qml (de_DE) Item { property string s_arm_rest: “Armlehne” property string s_settings: “Einstellungen” property string s_areas: “Flächen” Translations written directly into QML “translation” files 11/5/2014 © Burkhard Stubert, 2014 45
  46. 46. Terminal Krone Big X 480/580 11/5/2014 © Burkhard Stubert, 2014 46
  • eddsuanthai

    Feb. 6, 2019
  • TobiasWellnitz

    Feb. 8, 2015
  • wiliwe

    Dec. 17, 2014

The driver terminal of Krone’s BiG X 480/580 forage harvester uses dials, info fields, quick-access buttons and status buttons to show about 30+ pieces of information on its home screen. The driver can change some of the information directly on the home screen. The terminal receives up to 250 signals per second from the “machine” over 4 CAN buses. Some of the signals are received up to 100 times per second. Nevertheless, the needles of the dials and the digital numbers must change smoothly. Moreover, the driver can fine-tune 1000+ parameters of 30 control units. He can perform on-board diagnostics and calibrate parts of the machine. He can dynamically change between languages, measurement units, and day and night mode. The terminal can “count” the harvested area, diesel consumption or the usage hours of the cutting drum or front attachment. Burkhard was the lead developer for building the driver terminal of Krone’s BiG X 480/580 forage harvester. He worked together with two developers from Krone and an independent UI designer. It took the team 21 months from the first UI design to the product release. A first prototype was ready for a maize harvest after less than three months. The GUI parts of the driver terminal were developed with QML and the non-GUI parts with Qt/C++. Burkhard will share his first-hand experience from this project and will explain how the team solved some typical challenges of such a project. (1) The team used a multi-threaded architecture to cope with the load of up to 1000 messages per second from the machine. The communication between the threads is done exclusively with Qt’s signals and slots. Special considerations are needed for singletons. 2) The team faced some QML performance problems. For example, the standard implementation of a screen stack from QtQuick components would require the graphics power of a 4K TV. Or, over-generalised QML delegates, which make unused parts invisible, can render the scrolling of a ListView unusable. (3) Selecting the right touchscreen display, which is used on a 500 horse-power harvester with “good vibrations” under bright daylight and at night, is quite tricky. (4) The project started with Qt 4.8 on an Intel-Atom system with Windows XP and without OpenGL acceleration. It then moved to an ARM Cortex-A8 CPU with OpenGL acceleration. It was finally released with Qt 5.1. (5) The ultimate challenge was to develop the driver terminal with three developers and one UI designer in less than two years. A first prototype had to be available for the maize harvest after three months. Problems found during the 6-weeks window of a harvest season had to be fixed basically over night.

Views

Total views

3,347

On Slideshare

0

From embeds

0

Number of embeds

906

Actions

Downloads

58

Shares

0

Comments

0

Likes

3

×