█ 【无人机学习之QGroundControl】android端 源码
█ 系列文章目录
提示:这里是收集了无人机的相关文章
-
【无人机学习】无人机基础知识
-
【无人机学习】Mission Planner(pc端)和QGroundControl(android端)
-
【无人机学习之DroidPlanner】FlightActivity的启动过程
-
【无人机学习之DroidPlanner】msg_heartbeat心跳处理(含MAVLink协议)
-
【无人机学习之DroidPlanner】msg_sys_status系统状态
-
【无人机学习之QGroundControl】android端App初解1
-
【无人机学习之QGroundControl】android端App初解2-APMPowerComponent(含QML的介绍)
-
【无人机学习之QGroundControl】android端App初解3-ParameterEditorController
█ 文章目录
█ 读前说明
- 本文通过学习别人写demo,学习一些课件,参考一些博客,学习相关知识,如有涉及侵权请告知
- 本文可能只简单罗列了一些相关的代码实现过程,复制了一些大神的高论,如内容有误请自行辨别
- 涉及到的逻辑以及说明可能只做了简单的介绍,主要当做笔记,了解过程而已,如有不同看法,欢迎下方评论
-
本文源码:
https://github.com/mavlink/qgroundcontrol
-
本文UI:
https://github.com/mavlink/qgroundcontrol/blob/master/src/ui
- QGC中UI设计的主要模式是用QML编写的UI页面,多次与用C ++编写的定制“控制器”进行通信。类似MVC的设计模式。
提示:QGroundControl是使用QT & c++ 编写的
█ 界面分析
1.参数界面
2.相关文件
3.ParameterEditor.qml
此文件在
qgroundcontrol-master\src\QmlControls\ParameterEditor.qml
//---------------------------------------------
//-- Header 头部搜索栏
Row {
id: header
anchors.left: parent.left
anchors.right: parent.right
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Search:")
}
QGCTextField {//
id: searchText
text: controller.searchText
onDisplayTextChanged: controller.searchText = displayText
anchors.verticalCenter: parent.verticalCenter
}
QGCButton {
text: qsTr("Clear")// 清除按钮
onClicked: {
if(ScreenTools.isMobile) {
Qt.inputMethod.hide();
}
clearTimer.start()// 定时器自动清除
}
anchors.verticalCenter: parent.verticalCenter
}
QGCCheckBox {
text: qsTr("Show modified only")
anchors.verticalCenter: parent.verticalCenter
checked: controller.showModifiedOnly
onClicked: controller.showModifiedOnly = checked
visible: QGroundControl.multiVehicleManager.activeVehicle.px4Firmware
}
} // Row - Header
QGCButton {
anchors.top: header.top
anchors.bottom: header.bottom
anchors.right: parent.right
text: qsTr("Tools")
visible: !_searchFilter // _searchFilter=true: showing results of search
onClicked: toolsMenu.popup()
}
// Group buttons 左边菜单 折叠列表
QGCFlickable {
id : groupScroll
width: ScreenTools.defaultFontPixelWidth * 25
anchors.top: header.bottom
anchors.bottom: parent.bottom
clip: true
pixelAligned: true
contentHeight: groupedViewCategoryColumn.height
flickableDirection: Flickable.VerticalFlick
visible: !_searchFilter
ColumnLayout {
id: groupedViewCategoryColumn
anchors.left: parent.left
anchors.right: parent.right
spacing: Math.ceil(ScreenTools.defaultFontPixelHeight * 0.25)
Repeater {// Repeater重复器 可以用于显示一个数组的数据,一级目录
model: controller.categories
Column {
Layout.fillWidth: true
spacing: Math.ceil(ScreenTools.defaultFontPixelHeight * 0.25)
SectionHeader {
id: categoryHeader
anchors.left: parent.left
anchors.right: parent.right
text: object.name
checked: object == controller.currentCategory// 一级目录,判断是否折叠
exclusiveGroup: sectionGroup
onCheckedChanged: {// 修改一级目录
if (checked) {
controller.currentCategory = object
}
}
}
Repeater {// Repeater重复器 可以用于显示一个数组的数据,二级目录
model: categoryHeader.checked ? object.groups : 0
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 25
text: object.name
height: _rowHeight
checked: object == controller.currentGroup // 判断当前选中的菜单
autoExclusive: true
onClicked: {
if (!checked) _rowWidth = 10
checked = true
controller.currentGroup = object
}
}
}
}
}
}
}
// Parameter list 右侧的参数列表(二级目录对应的参数列表)
QGCListView {
id: editorListView
anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.left: _searchFilter ? parent.left : groupScroll.right// 有搜索时,全屏,遮盖groupScroll(QGCFlickable的id)
anchors.right: parent.right
anchors.top: header.bottom
anchors.bottom: parent.bottom
orientation: ListView.Vertical// 垂直列表
model: controller.parameters// 数据源
cacheBuffer: height > 0 ? height * 2 : 0
clip: true
delegate: Rectangle {
height: _rowHeight
width: _rowWidth
color: Qt.rgba(0,0,0,0)
Row {
id: factRow
spacing: Math.ceil(ScreenTools.defaultFontPixelWidth * 0.5)
anchors.verticalCenter: parent.verticalCenter
property Fact modelFact: object
QGCLabel {// 参数名
id: nameLabel
width: ScreenTools.defaultFontPixelWidth * 20
text: factRow.modelFact.name
clip: true
}
QGCLabel {// 参数值
id: valueLabel
width: ScreenTools.defaultFontPixelWidth * 20
color: factRow.modelFact.defaultValueAvailable ? (factRow.modelFact.valueEqualsDefault ? qgcPal.text : qgcPal.warningText) : qgcPal.text
text: factRow.modelFact.enumStrings.length === 0 ? factRow.modelFact.valueString + " " + factRow.modelFact.units : factRow.modelFact.enumStringValue
clip: true
}
QGCLabel {// 参数描述
text: factRow.modelFact.shortDescription
}
Component.onCompleted: {
if(_rowWidth < factRow.width + ScreenTools.defaultFontPixelWidth) {
_rowWidth = factRow.width + ScreenTools.defaultFontPixelWidth
}
}
}
MouseArea {// 点击事件
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
_editorDialogFact = factRow.modelFact
// 弹出参数编辑器对话框,对应对话框id是editorDialogComponent
mainWindow.showComponentDialog(editorDialogComponent, qsTr("Parameter Editor"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Save)
}
}
}
}
4.参数编辑器Dialog
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
_editorDialogFact = factRow.modelFact
// editorDialogComponent是对话框的id
mainWindow.showComponentDialog(editorDialogComponent, qsTr("Parameter Editor"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Save)
}
}
Component {
id: editorDialogComponent
ParameterEditorDialog {// 参数编辑器Dialog
fact: _editorDialogFact
showRCToParam: _showRCToParam
}
}
- ParameterEditorDialog.qml
QGCViewDialog {
id: root
focus: true
property Fact fact
ParameterEditorController { id: controller; }
// Save 保存按钮
function accept() {// 下一步需要查看的信息:参数编辑器Dialog
if (bitmaskColumn.visible && !manualEntry.checked) {
fact.value = bitmaskValue();
fact.valueChanged(fact.value)
valueChanged()
hideDialog();
} else if (factCombo.visible && !manualEntry.checked) {
fact.enumIndex = factCombo.currentIndex
valueChanged()
hideDialog()
} else {
var errorString = fact.validate(valueField.text, forceSave.checked)
if (errorString === "") {
fact.value = valueField.text
fact.valueChanged(fact.value)
valueChanged()
hideDialog()
} else {
validationError.text = errorString
if (_allowForceSave) {
forceSave.visible = true
}
}
}
}
// Cancel 取消按钮
function reject() {
fact.valueChanged(fact.value)
hideDialog();
}
QGCFlickable {
id: flickable
anchors.fill: parent
contentHeight: _column.y + _column.height
flickableDirection: Flickable.VerticalFlick
Column {
id: _column
spacing: globals.defaultTextHeight
anchors.left: parent.left
anchors.right: parent.right
QGCLabel {
id: validationError
width: parent.width
wrapMode: Text.WordWrap
color: qgcPal.warningText
}
RowLayout {
spacing: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
anchors.right: parent.right
QGCTextField {
id: valueField
text: validate ? validateValue : fact.valueString
visible: fact.enumStrings.length === 0 || validate || manualEntry.checked
unitsLabel: fact.units
showUnits: fact.units != ""
Layout.fillWidth: true
focus: setFocus
inputMethodHints: (fact.typeIsString || ScreenTools.isiOS) ?
Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it
Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard
}
QGCButton {
visible: _allowDefaultReset
text: qsTr("Reset to default")
onClicked: {
fact.value = fact.defaultValue
fact.valueChanged(fact.value)
hideDialog()
}
}
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
visible: !longDescriptionLabel.visible
text: fact.shortDescription
}
QGCLabel {
id: longDescriptionLabel
width: parent.width
wrapMode: Text.WordWrap
visible: fact.longDescription != ""
text: fact.longDescription
}
QGCLabel {
text: qsTr("Parameter name: ") + fact.name
visible: fact.componentId > 0 // > 0 means it's a parameter fact
}
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: qsTr("Warning: Modifying values while vehicle is in flight can lead to vehicle instability and possible vehicle loss. ") +
qsTr("Make sure you know what you are doing and double-check your values before Save!")
visible: fact.componentId != -1
}
} // Column
}
} // QGCViewDialog
5.下拉框spinner(对应QT – QGCMenu )
QGCButton {
anchors.top: header.top
anchors.bottom: header.bottom
anchors.right: parent.right
text: qsTr("Tools")
visible: !_searchFilter
onClicked: toolsMenu.popup()// toolsMenu是下拉框spinner的id
}
QGCMenu {
id: toolsMenu
QGCMenuItem {// 下一步需要查看的信息:刷新参数
text: qsTr("Refresh")
onTriggered: controller.refresh()
}
QGCMenuItem {
text: qsTr("Reset all to firmware's defaults")
onTriggered: mainWindow.showComponentDialog(resetToDefaultConfirmComponent, qsTr("Reset All"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Reset)
}
QGCMenuItem {
text: qsTr("Reset to vehicle's configuration defaults")
visible: !_activeVehicle.apmFirmware
onTriggered: mainWindow.showComponentDialog(resetToVehicleConfigurationConfirmComponent, qsTr("Reset All"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Reset)
}
QGCMenuSeparator { }
QGCMenuItem {
text: qsTr("Load from file...")
onTriggered: {
fileDialog.title = qsTr("Load Parameters")
fileDialog.selectExisting = true
fileDialog.openForLoad()
}
}
QGCMenuItem {
text: qsTr("Save to file...")
onTriggered: {
fileDialog.title = qsTr("Save Parameters")
fileDialog.selectExisting = false
fileDialog.openForSave()
}
}
QGCMenuSeparator { visible: _showRCToParam }
QGCMenuItem {
text: qsTr("Clear all RC to Param")
onTriggered: _activeVehicle.clearAllParamMapRC()
visible: _showRCToParam
}
QGCMenuSeparator { }
QGCMenuItem {
text: qsTr("Reboot Vehicle")
onTriggered: mainWindow.showComponentDialog(rebootVehicleConfirmComponent, qsTr("Reboot Vehicle"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Ok)
}
}
█ 通信说明(ParameterManager.cc)
1.过程
1. 刚进入,通过MAV_COMP_ID_AUTOPILOT1来读取左侧的折叠列表:系统飞行控制器组件的所有参数;
2.当修改参数后,则通过MAV_COMP_ID_ALL来更新所有的参数:接收系统的所有组件;
序号 | 字段 | 说明 |
---|---|---|
#20 | PARAM_REQUEST_READ | 请求一个参数。接收者使用PARAM_VALUE广播指定的参数值。 |
#21 | PARAM_REQUEST_LIST | 请求所有参数。接收者使用PARAM_VALUE广播所有参数值。 |
#22 | PARAM_VALUE | 参数的当前值,响应于获取一个或多个参数(PARAM_REQUEST_READ,PARAM_REQUEST_LIST)的请求而广播,或者在参数被设置(PARAM_SET)或更改时进行广播。 |
#23 | PARAM_SET | 发送命令以将指定参数设置为值。设置值后(无论成功与否),接收者应使用PARAM_VALUE广播当前值。 |
2.发送参数
void ParameterManager::_sendParamSetToVehicle(int componentId, const QString& paramName, FactMetaData::ValueType_t valueType, const QVariant& value)
{
WeakLinkInterfacePtr weakLink = _vehicle->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
mavlink_param_set_t p;// 参数设置消息(mavlink_param_set_t)
mavlink_param_union_t union_value;// 所有的参数都以浮点型的mavlink_param_union_t值发送
SharedLinkInterfacePtr sharedLink = weakLink.lock();
memset(&p, 0, sizeof(p));
// MAV_PARAM_TYPE_UINT8/MAV_PARAM_TYPE_INT8/MAV_PARAM_TYPE_UINT16
// MAV_PARAM_TYPE_INT16/MAV_PARAM_TYPE_UINT32
// MAV_PARAM_TYPE_UINT64/MAV_PARAM_TYPE_INT64/MAV_PARAM_TYPE_REAL32/MAV_PARAM_TYPE_REAL64
p.param_type = factTypeToMavType(valueType);
switch (valueType) {
case FactMetaData::valueTypeUint8:
union_value.param_uint8 = (uint8_t)value.toUInt();
break;
case FactMetaData::valueTypeInt8:
union_value.param_int8 = (int8_t)value.toInt();
break;
case FactMetaData::valueTypeUint16:
union_value.param_uint16 = (uint16_t)value.toUInt();
break;
case FactMetaData::valueTypeInt16:
union_value.param_int16 = (int16_t)value.toInt();
break;
case FactMetaData::valueTypeUint32:
union_value.param_uint32 = (uint32_t)value.toUInt();
break;
case FactMetaData::valueTypeFloat:
union_value.param_float = value.toFloat();
break;
default:
qCritical() << "Unsupported fact falue type" << valueType;
// fall through
case FactMetaData::valueTypeInt32:
union_value.param_int32 = (int32_t)value.toInt();
break;
}
p.param_value = union_value.param_float;
p.target_system = (uint8_t)_vehicle->id();
p.target_component = (uint8_t)componentId;
strncpy(p.param_id, paramName.toStdString().c_str(), sizeof(p.param_id));
mavlink_message_t msg;
mavlink_msg_param_set_encode_chan(_mavlink->getSystemId(),
_mavlink->getComponentId(),
sharedLink->mavlinkChannel(),
&msg,
&p);
_vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
}
3.读取参数
QString ParameterManager::readParametersFromStream(QTextStream& stream)
{
QString missingErrors;
QString typeErrors;
while (!stream.atEnd()) {
QString line = stream.readLine();
if (!line.startsWith("#")) {
QStringList wpParams = line.split("\t");
int lineMavId = wpParams.at(0).toInt();
if (wpParams.size() == 5) {
if (_vehicle->id() != lineMavId) {
return QString("The parameters in the stream have been saved from System Id %1, but the current vehicle has the System Id %2.").arg(lineMavId).arg(_vehicle->id());
}
int componentId = wpParams.at(1).toInt();
QString paramName = wpParams.at(2);
QString valStr = wpParams.at(3);
uint mavType = wpParams.at(4).toUInt();
if (!parameterExists(componentId, paramName)) {
QString error;
error += QStringLiteral("%1:%2 ").arg(componentId).arg(paramName);
missingErrors += error;
qCDebug(ParameterManagerLog) << QStringLiteral("Skipped due to missing: %1").arg(error);
continue;
}
Fact* fact = getParameter(componentId, paramName);
if (fact->type() != mavTypeToFactType((MAV_PARAM_TYPE)mavType)) {
QString error;
error = QStringLiteral("%1:%2 ").arg(componentId).arg(paramName);
typeErrors += error;
qCDebug(ParameterManagerLog) << QStringLiteral("Skipped due to type mismatch: %1").arg(error);
continue;
}
qCDebug(ParameterManagerLog) << "Updating parameter" << componentId << paramName << valStr;
fact->setRawValue(valStr);
}
}
}
QString errors;
if (!missingErrors.isEmpty()) {
errors = tr("Parameters not loaded since they are not currently on the vehicle: %1\n").arg(missingErrors);
}
if (!typeErrors.isEmpty()) {
errors += tr("Parameters not loaded due to type mismatch: %1").arg(typeErrors);
}
return errors;
}
█ 事件分析
1.搜索文本框
QGCTextField变化 |
---|
controller.searchText变化 ,即cc中_searchText变化 |
回调cc中 searchTextChanged (QString searchText),即_searchTextChanged(void) |
- ParameterEditor.qml
ParameterEditorController {
id: controller
}
QGCTextField {
id: searchText// QGCTextField的id
text: controller.searchText// cc文件的成员
onDisplayTextChanged: controller.searchText = displayText
anchors.verticalCenter: parent.verticalCenter
}
- ParameterEditorController.h
class ParameterEditorController : public FactPanelController
{
Q_OBJECT
public:
ParameterEditorController(void);
~ParameterEditorController();
// 成员_searchText 和 qml的controller.searchText绑定,变化时,回调 searchTextChanged
Q_PROPERTY(QString searchText MEMBER _searchText NOTIFY searchTextChanged)
// 表明searchParameters可以被qml调用
Q_INVOKABLE QStringList searchParameters(const QString& searchText, bool searchInName=true, bool searchInDescriptions=true);
signals:// 信号
void searchTextChanged (QString searchText);
private slots:// 槽
void _searchTextChanged (void);
private:
QString _searchText;// 成员_searchText
QmlObjectListModel _searchParameters;
};
- ParameterEditorController.cc
ParameterEditorController::ParameterEditorController(void)
: _parameterMgr(_vehicle->parameterManager())
{
_buildLists();
// 一个信号可以连接一个槽,在发射这个信号的时候,会以不确定的顺序一个接一个的调用这些槽。
connect(this, &ParameterEditorController::searchTextChanged, this, &ParameterEditorController::_searchTextChanged);
}
QStringList ParameterEditorController::searchParameters(const QString& searchText, bool searchInName, bool searchInDescriptions)
{
QStringList list;
for(const QString ¶mName: _parameterMgr->parameterNames(_vehicle->defaultComponentId())) {
if (searchText.isEmpty()) {
list += paramName;
} else {
Fact* fact = _parameterMgr->getParameter(_vehicle->defaultComponentId(), paramName);
if (searchInName && fact->name().contains(searchText, Qt::CaseInsensitive)) {
list += paramName;
} else if (searchInDescriptions && (fact->shortDescription().contains(searchText, Qt::CaseInsensitive) || fact->longDescription().contains(searchText, Qt::CaseInsensitive))) {
list += paramName;
}
}
}
list.sort();
return list;
}
void ParameterEditorController::_searchTextChanged(void)
{
QObjectList newParameterList;
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QStringList rgSearchStrings = _searchText.split(' ', QString::SkipEmptyParts);
#else
QStringList rgSearchStrings = _searchText.split(' ', Qt::SkipEmptyParts);
#endif
if (rgSearchStrings.isEmpty() && !_showModifiedOnly) {// 空字符串,显示全部
ParameterEditorCategory* category = _categories.count() ? _categories.value<ParameterEditorCategory*>(0) : nullptr;
setCurrentCategory(category);
_searchParameters.clear();
} else {
_searchParameters.beginReset();
_searchParameters.clear();
// ParameterManager _parameterMgr 获取全部参数树 名称
for (const QString ¶Name: _parameterMgr->parameterNames(_vehicle->defaultComponentId())) {
// 获取具体的参数对象
Fact* fact = _parameterMgr->getParameter(_vehicle->defaultComponentId(), paraName);
bool matched = _shouldShow(fact);
// All of the search items must match in order for the parameter to be added to the list
if (matched) {
for (const auto& searchItem : rgSearchStrings) {
if (!fact->name().contains(searchItem, Qt::CaseInsensitive) &&
!fact->shortDescription().contains(searchItem, Qt::CaseInsensitive) &&
!fact->longDescription().contains(searchItem, Qt::CaseInsensitive)) {
matched = false;
}
}
}
if (matched) {// 参数匹配,就加入搜索的参数
_searchParameters.append(fact);
}
}
_searchParameters.endReset();
if (_parameters != &_searchParameters) {
_parameters = &_searchParameters;
emit parametersChanged();
_currentCategory = nullptr;
_currentGroup = nullptr;
}
}
}
bool ParameterEditorController::_shouldShow(Fact* fact)
{
bool show = _showModifiedOnly ? (fact->defaultValueAvailable() ? (fact->valueEqualsDefault() ? false : true) : false) : true;
return show;
}
- ParameterManager.cc
QMap<int /* comp id */, QMap<QString /* parameter name */, Fact*>> _mapCompId2FactMap;
// 根据参数名获取参数对象
Fact* ParameterManager::getParameter(int componentId, const QString& paramName)
{
componentId = _actualComponentId(componentId);
QString mappedParamName = _remapParamNameToVersion(paramName);
if (!_mapCompId2FactMap.contains(componentId) || !_mapCompId2FactMap[componentId].contains(mappedParamName)) {
qgcApp()->reportMissingParameter(componentId, mappedParamName);
return &_defaultFact;
}
return _mapCompId2FactMap[componentId][mappedParamName];
}
// 根据组件id获取所有的参数名数组
QStringList ParameterManager::parameterNames(int componentId)
{
QStringList names;
for(const QString ¶mName: _mapCompId2FactMap[_actualComponentId(componentId)].keys()) {
names << paramName;
}
return names;
}
2.修改参数(参数编辑对话框)
- ParameterEditor.qml
Component {
id: editorDialogComponent
ParameterEditorDialog {// 下一步需要查看的信息:参数编辑器Dialog
fact: _editorDialogFact
showRCToParam: _showRCToParam
}
}
- ParameterEditorDialog.qml
QGCViewDialog {
id: root
focus: true
property Fact fact
ParameterEditorController { id: controller; }
// Save 保存按钮
function accept() {// 下一步需要查看的信息:参数编辑器Dialog
if (bitmaskColumn.visible && !manualEntry.checked) {
fact.value = bitmaskValue();
fact.valueChanged(fact.value)
valueChanged()
hideDialog();
} else if (factCombo.visible && !manualEntry.checked) {
fact.enumIndex = factCombo.currentIndex
valueChanged()
hideDialog()
} else {// 在这边进行修改参数
var errorString = fact.validate(valueField.text, forceSave.checked)
if (errorString === "") {// 判断是否合法
fact.value = valueField.text
// This signal is only meant for use by the QT property system.
// It should not be connected to by client code.
fact.valueChanged(fact.value)// 库函数
valueChanged()
hideDialog()
} else {// 非法参数,直接提示
validationError.text = errorString
if (_allowForceSave) {
forceSave.visible = true
}
}
}
}
// Cancel 取消按钮
function reject() {
fact.valueChanged(fact.value)
hideDialog();
}
} // QGCViewDialog
- QGCViewDialogContainer.qml
// This is the main dialog panel
Item {
id: _dialogPanel
anchors.fill: parent
Rectangle {
id: _header
width: parent.width
height: _acceptButton.visible ? _acceptButton.height : _rejectButton.height
color: qgcPal.windowShade
QGCLabel {
x: _defaultTextWidth
text: dialogTitle
height: parent.height
verticalAlignment: Text.AlignVCenter
}
QGCButton {// 取消按钮
id: _rejectButton
anchors.right: _acceptButton.visible ? _acceptButton.left : parent.right
anchors.bottom: parent.bottom
onClicked: _dialogComponentLoader.item.reject()
}
QGCButton {// 保存按钮
id: _acceptButton
anchors.right: parent.right
anchors.bottom: parent.bottom
primary: true
onClicked: _dialogComponentLoader.item.accept()
}
}
}
2.刷新参数(Tools -> Refresh)
mavlink_msg_param_request_list_pack_chan(SysId,CmpId,mavlinkChannel(),&msg,vehicleid, MAV_COMP_ID_ALL); |
---|
_vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg); |
- ParameterEditor.qml
property var _controller: controller
ParameterEditorController {
id: controller
}
QGCMenuItem {
text: qsTr("Refresh")
onTriggered: controller.refresh()// 下一步需要查看的信息:刷新参数
}
- ParameterEditorController.h
class ParameterEditorController : public FactPanelController
{
Q_OBJECT
public:
ParameterEditorController(void);
~ParameterEditorController();
。。。。。。
Q_INVOKABLE void saveToFile (const QString& filename);
Q_INVOKABLE bool buildDiffFromFile (const QString& filename);
Q_INVOKABLE void clearDiff (void);
Q_INVOKABLE void sendDiff (void);
Q_INVOKABLE void refresh (void);// 下一步需要查看的信息:刷新参数
。。。。。。
private:
ParameterManager* _parameterMgr = nullptr;
QString _searchText;
ParameterEditorCategory* _currentCategory = nullptr;
ParameterEditorGroup* _currentGroup = nullptr;
。。。。。。
};
- ParameterManager.cc
void ParameterEditorController::refresh(void)
{
_parameterMgr->refreshAllParameters();// 下一步需要查看的信息:刷新参数
}
- ParameterManager.h
class ParameterManager : public QObject
{
Q_OBJECT
friend class ParameterEditorController;
public:
Vehicle* _vehicle;
MAVLinkProtocol* _mavlink;
// Re-request the full set of parameters from the autopilot
// 刷新全部参数树:MAV_COMP_ID_ALL = 0
void refreshAllParameters(uint8_t componentID = MAV_COMP_ID_ALL);// 下一步需要查看的信息
};
- ParameterEditorController.cc
void ParameterManager::refreshAllParameters(uint8_t componentId)
{
。。。。。。
// Reset index wait lists
for (int cid: _paramCountMap.keys()) {
// Add/Update all indices to the wait list, parameter index is 0-based
if(componentId != MAV_COMP_ID_ALL && componentId != cid)
continue;
for (int waitingIndex = 0; waitingIndex < _paramCountMap[cid]; waitingIndex++) {
// This will add a new waiting index if needed and set the retry count for that index to 0
_waitingReadParamIndexMap[cid][waitingIndex] = 0;
}
}
MAVLinkProtocol* mavlink = qgcApp()->toolbox()->mavlinkProtocol();// 从工具栏获取相关配置信息
mavlink_message_t msg;// 找不到对应的文件,可能是库函数
SharedLinkInterfacePtr sharedLink = weakLink.lock();
// 找不到对应的详情方法,可能是库函数,将消息打包
// MAVLinkProtocol将字节转换为MAVLink消息
mavlink_msg_param_request_list_pack_chan(mavlink->getSystemId(),// 飞控id
mavlink->getComponentId(),// 组件id
sharedLink->mavlinkChannel(),
&msg,
_vehicle->id(),
componentId);// MAV_COMP_ID_ALL
_vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);// 下一步需要查看的信息:发送消息
}
- Vehicle.h
class Vehicle : public FactGroup
{
Q_OBJECT
public:
Vehicle(LinkInterface* link,
int vehicleId,
int defaultComponentId,
MAV_AUTOPILOT firmwareType,
MAV_TYPE vehicleType,
FirmwarePluginManager* firmwarePluginManager,
JoystickManager* joystickManager);
/// Sends a message to the specified link
/// @return true: message sent, false: Link no longer connected
bool sendMessageOnLinkThreadSafe(LinkInterface* link, mavlink_message_t message);// 下一步需要查看的信息:发送消息
- Vehicle.cc
bool Vehicle::sendMessageOnLinkThreadSafe(LinkInterface* link, mavlink_message_t message)
{
if (!link->isConnected()) {
return false;
}
// Give the plugin a chance to adjust
_firmwarePlugin->adjustOutgoingMavlinkMessageThreadSafe(this, link, &message);
// Write message into buffer, prepending start sign
uint8_t buffer[MAVLINK_MAX_PACKET_LEN];// 打包为Buff
int len = mavlink_msg_to_send_buffer(buffer, &message);
link->writeBytesThreadSafe((const char*)buffer, len);// 下一步需要查看的信息:发送消息
_messagesSent++;
emit messagesSentChanged();
return true;
}
- LinkInterface.h
/**
* @brief The link interface defines the interface for all links used to communicate
* with the ground station application.
**/
class LinkInterface : public QThread
{
Q_OBJECT
friend class LinkManager;
public:
virtual ~LinkInterface();
Q_INVOKABLE virtual void disconnect (void) = 0;
virtual bool isConnected (void) const = 0;
bool decodedFirstMavlinkPacket (void) const { return _decodedFirstMavlinkPacket; }
bool setDecodedFirstMavlinkPacket(bool decodedFirstMavlinkPacket) { return _decodedFirstMavlinkPacket = decodedFirstMavlinkPacket; }
void writeBytesThreadSafe (const char *bytes, int length);// 下一步需要查看的信息:发送消息
}
- LinkInterface.cc
void LinkInterface::writeBytesThreadSafe(const char *bytes, int length)
{
QByteArray byteArray(bytes, length);
_writeBytesMutex.lock();
_writeBytes(byteArray);
_writeBytesMutex.unlock();
}
█ 相关资料
提示:这里是参考的相关文章
-
2018-03-08 QGC 连接功能 底层执行逻辑_/* */-CSDN博客
-
2019-01-15 QT Qml 的qmlRegisterUncreatableType()函数_小马哔哔-CSDN博客
-
2018-03-04 QGroundControl 开发人员指南_/* */-CSDN博客_qgroundcontrol
-
2019-05-11 Qt学习笔记:多语言文件.qm的生成和使用_chase_hung的博客-CSDN博客
:生成ts文件,修改ts文件,生成qm文件,加载qm语言包 -
2016-12-17 QT开发(五十三)———QML基本元素-生命不息,奋斗不止-51CTO博客
-
2019-02-15 qml和cpp 交互_Owen li的博客-CSDN博客
█ 免责声明
博主分享的所有文章内容,部分参考网上教程,引用大神高论,部分亲身实践,记下笔录,内容可能存在诸多不实之处,还望海涵,本内容仅供学习研究使用,切勿用于商业用途,若您是部分内容的作者,不喜欢此内容被分享出来,可联系博主说明相关情况通知删除,感谢您的理解与支持! |
---|
提示:转载请注明出处:
https://blog.csdn.net/ljb568838953/article/details/112904481
版权声明:本文为ljb568838953原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。