8#include <QtCore/QString>
9#include <QtCore/QJsonArray>
10#include <QtCore/QJsonObject>
19 : QObject(parent), _actuatorTest(vehicle), _mixer(vehicle->parameterManager()),
20 _motorAssignment(
nullptr, vehicle, _actuatorOutputs), _vehicle(vehicle)
24 qRegisterMetaType<Actuators*>(
"Actuators*");
33 QPointF clickPosition{ x, y };
35 qCDebug(ActuatorsLog) <<
"Image clicked: position:" << clickPosition <<
"displaySize:" << displaySize <<
"motor index:" << motorIndex;
37 if (_motorAssignment.
active()) {
38 QList<ActuatorGeometry>& actuators = provider->
actuators();
40 for (
auto& actuator : actuators) {
42 actuator.renderOptions.highlight =
false;
46 updateGeometryImage();
57 if (index >= _actuatorOutputs->
count() || index < 0) {
60 _selectedActuatorOutput = index;
65 if (_actuatorOutputs->
count() == 0) {
71void Actuators::updateGeometryImage()
75 QList<ActuatorGeometry>& actuators = provider->
actuators();
76 QList<ActuatorGeometry> previousActuators = actuators;
80 for (
int mixerGroupIdx = 0; mixerGroupIdx < _mixer.
groups()->count(); ++mixerGroupIdx) {
82 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
86 actuators.append(geometry);
87 qCDebug(ActuatorsLog) <<
"Airframe actuator:" << geometry.
index <<
"pos:" << geometry.position;
93 if (previousActuators.size() == actuators.size()) {
94 for (
int i = 0; i < actuators.size(); ++i) {
95 if (previousActuators[i].type == actuators[i].type && previousActuators[i].index == actuators[i].index) {
96 actuators[i].renderOptions = previousActuators[i].renderOptions;
101 _imageRefreshFlag = !_imageRefreshFlag;
104 _motorAssignmentEnabled = provider->
numMotors() > 0;
117 if (metadata.isNull()) {
118 _initError = QStringLiteral(
"Could not load metadata file: %1").arg(json_file);
120 qCWarning(ActuatorsLog) << _initError;
124 _jsonMetadata = metadata;
134 qWarning() <<
"Incorrect calling order, parameters not yet ready";
137 if (!parseJson(_jsonMetadata)) {
143 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
144 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
146 qCDebug(ActuatorsLog) <<
"Removing actuator group w/o function parameters at" << groupIdx;
147 _actuatorOutputs->
removeAt(groupIdx);
159 qCDebug(ActuatorsLog) <<
"Param update";
164 QList<int> allFunctions;
165 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
166 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
168 QList<Fact*> groupFunctions;
170 for (
const auto& groupFunction : groupFunctions) {
171 int function = groupFunction->rawValue().toInt();
173 allFunctions.append(function);
177 const auto iter = _mixer.
functions().find(function);
178 if (iter != _mixer.
functions().end() && iter->note !=
"") {
179 if (iter->noteCondition.evaluate()) {
180 qCDebug(ActuatorsLog) <<
"Showing Note:" << iter->note;
187 for (
int subbroupIdx = 0; subbroupIdx < group->
subgroups()->count(); subbroupIdx++) {
189 for (
int channelIdx = 0; channelIdx < subgroup->
channelConfigs()->count(); channelIdx++) {
196 std::sort(allFunctions.begin(), allFunctions.end());
199 QList<ActuatorTesting::Actuator*> actuators;
200 QSet<int> uniqueConfiguredFunctions;
202 for (
int function : allFunctions) {
203 if (uniqueConfiguredFunctions.find(function) != uniqueConfiguredFunctions.end()) {
206 uniqueConfiguredFunctions.insert(function);
210 bool excludeFromActuatorTesting =
false;
211 const auto iter = _mixer.
functions().find(function);
213 excludeFromActuatorTesting = iter->excludeFromActuatorTesting;
217 if (!excludeFromActuatorTesting) {
219 for (
const auto& actuatorTypeName : actuatorTypes.keys()) {
230 if (!found && actuatorTypes.find(
"DEFAULT") != actuatorTypes.end()) {
241 QSet<int> requiredFunctions = _mixer.
getFunctions(
true);
242 _hasUnsetRequiredFunctions =
false;
243 for (
int requiredFunction : requiredFunctions) {
244 if (uniqueConfiguredFunctions.find(requiredFunction) == uniqueConfiguredFunctions.end()) {
245 _hasUnsetRequiredFunctions =
true;
250 updateFunctionMetadata();
252 updateActuatorActions();
254 updateGeometryImage();
257void Actuators::updateFunctionMetadata()
262 QSet<int> usedMixerFunctions = _mixer.
getFunctions(
false);
264 QMap<int, QString> usedMixerLabels;
265 for (
int usedMixerFunction : usedMixerFunctions) {
269 if (_usedMixerLabels == usedMixerLabels) {
273 _usedMixerLabels = usedMixerLabels;
276 QSet<int> removedMixerFunctions;
277 for(Mixer::ActuatorTypes::const_iterator iter = _mixer.
actuatorTypes().constBegin();
279 if (iter.key() ==
"DEFAULT")
282 for (
int i = iter.value().functionMin; i <= iter.value().functionMax; ++i) {
283 if (!usedMixerFunctions.contains(i)) {
284 removedMixerFunctions.insert(i);
290 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
291 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
295 if (!enumStrings.empty()) {
296 QVariantList enumValues = fact->enumValues();
299 for (int usedMixerFunction : usedMixerFunctions) {
300 QString label = usedMixerLabels[usedMixerFunction];
301 int index = enumValues.indexOf(usedMixerFunction);
304 bool inserted = false;
305 for (index = 0; index < enumValues.count() && !inserted; ++index) {
306 if (enumValues[index].toInt() > usedMixerFunction) {
307 enumValues.insert(index, usedMixerFunction);
308 enumStrings.insert(index, label);
313 enumValues.append(usedMixerFunction);
314 enumStrings.append(label);
317 enumStrings[index] = label;
322 for (
int removedMixerFunction : removedMixerFunctions) {
323 int index = enumValues.indexOf(removedMixerFunction);
325 enumValues.removeAt(index);
326 enumStrings.removeAt(index);
336void Actuators::updateActuatorActions()
339 QSet<int> addedFunctions;
340 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
341 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
344 int outputFunctionVal = fact->
rawValue().toInt();
345 if (outputFunctionVal != 0 && !addedFunctions.contains(outputFunctionVal)) {
346 auto outputFunctionIter = _mixer.functions().find(outputFunctionVal);
347 if (outputFunctionIter != _mixer.functions().end()) {
348 const Mixer::Mixers::OutputFunction& outputFunction = outputFunctionIter.value();
349 for (const auto& action : subgroup->actions()) {
350 if (!action.condition.evaluate()) {
353 if (!action.actuatorTypes.empty() && action.actuatorTypes.find(outputFunction.actuatorType) == action.actuatorTypes.end()) {
358 auto actuatorAction = new ActuatorActions::Action(this, action, outputFunction.label, outputFunctionVal, _vehicle);
359 ActuatorActions::ActionGroup* actionGroup = nullptr;
361 for (int actionGroupIdx = 0; actionGroupIdx < _actuatorActions->count(); actionGroupIdx++) {
362 ActuatorActions::ActionGroup* curActionGroup =
363 qobject_cast<ActuatorActions::ActionGroup*>(_actuatorActions->get(actionGroupIdx));
364 if (curActionGroup->type() == action.type) {
365 actionGroup = curActionGroup;
371 QString groupLabel = action.typeToLabel();
372 actionGroup = new ActuatorActions::ActionGroup(this, groupLabel, action.type);
373 _actuatorActions->append(actionGroup);
375 actionGroup->addAction(actuatorAction);
376 addedFunctions.insert(outputFunctionVal);
383 emit actuatorActionsChanged();
386bool Actuators::parseJson(
const QJsonDocument &json)
390 QJsonObject obj = json.object();
391 QJsonValue outputsJson = obj.value(
"outputs_v1");
392 QJsonValue functionsJson = obj.value(
"functions_v1");
393 QJsonValue mixerJson = obj.value(
"mixer_v1");
394 if (outputsJson.isNull() || functionsJson.isNull() || mixerJson.isNull()) {
396 if (outputsJson.isNull()) missing <<
"outputs_v1";
397 if (functionsJson.isNull()) missing <<
"functions_v1";
398 if (mixerJson.isNull()) missing <<
"mixer_v1";
399 if (_initError.isEmpty()) {
400 _initError = QStringLiteral(
"Missing required JSON sections: %1").arg(missing.join(
", "));
402 qCWarning(ActuatorsLog) << _initError;
407 auto makeConditionFromValue = [
this](
const QJsonValue& val,
const char* key) {
411 QJsonArray outputs = outputsJson.toArray();
412 for (
const auto &&outputJson : outputs) {
413 QJsonValue output = outputJson.toObject();
414 QString label = output[
"label"].toString();
416 qCDebug(ActuatorsLog) <<
"Actuator group:" << label;
418 Condition groupVisibilityCondition = makeConditionFromValue(output,
"show-subgroups-if");
419 subscribeFact(groupVisibilityCondition.
fact());
422 _actuatorOutputs->
append(currentActuatorOutput);
424 auto parseParam = [¤tActuatorOutput,
this](
const QJsonValue ¶meter) {
426 param.
parse(parameter);
427 QString functionStr = parameter[
"function"].toString(
"");
428 qCDebug(ActuatorsLog) <<
"param:" << param.name <<
"label:" << param.label <<
"function:" << functionStr;
430 if (functionStr ==
"enable") {
431 function = ConfigParameter::Function::Enable;
432 }
else if (functionStr ==
"primary") {
433 function = ConfigParameter::Function::Primary;
434 }
else if (functionStr !=
"") {
435 qCWarning(ActuatorsLog) <<
"Unknown function " << functionStr <<
"for param" << param.name;
440 QJsonArray parameters = output[
"parameters"].toArray();
441 for (
const auto&& parameterJson : parameters) {
442 currentActuatorOutput->
addConfigParam(parseParam(parameterJson.toObject()));
445 QJsonArray subgroups = output[
"subgroups"].toArray();
446 for (
const auto&& subgroupJson : subgroups) {
447 QJsonValue subgroup = subgroupJson.toObject();
448 QString subgroupLabel = subgroup[
"label"].toString();
450 currentActuatorOutput->
addSubgroup(actuatorSubgroup);
452 QJsonValue supportedActions = subgroup[
"supported-actions"];
453 if (!supportedActions.isNull()) {
454 QJsonObject supportedActionsObj = supportedActions.toObject();
455 for (
const auto& actionName : supportedActionsObj.keys()) {
456 QJsonObject actionObj = supportedActionsObj.value(actionName).toObject();
458 bool knownAction =
true;
459 if (actionName ==
"beep") {
461 }
else if (actionName ==
"3d-mode-on") {
463 }
else if (actionName ==
"3d-mode-off") {
465 }
else if (actionName ==
"set-spin-direction1") {
467 }
else if (actionName ==
"set-spin-direction2") {
471 qCWarning(ActuatorsLog) <<
"Unknown 'supported-actions':" << actionName;
474 QJsonArray actuatorTypesArr = actionObj[
"actuator-types"].toArray();
475 for (
const auto&& type : actuatorTypesArr) {
476 action.actuatorTypes.insert(type.toString());
478 action.condition = makeConditionFromValue(actionObj,
"supported-if");
479 subscribeFact(action.condition.fact());
485 QJsonArray subgroupParameters = subgroup[
"parameters"].toArray();
486 for (
const auto&& parameterJson : subgroupParameters) {
487 actuatorSubgroup->
addConfigParam(parseParam(parameterJson.toObject()));
490 QJsonArray channelParameters = subgroup[
"per-channel-parameters"].toArray();
491 for (
const auto&& channelParametersJson : channelParameters) {
492 QJsonValue channelParameter = channelParametersJson.toObject();
494 param.
parse(channelParameter);
497 QString functionStr = channelParameter[
"function"].toString(
"");
498 if (functionStr ==
"function") {
499 function = ChannelConfig::Function::OutputFunction;
500 }
else if (functionStr ==
"disarmed") {
501 function = ChannelConfig::Function::Disarmed;
502 }
else if (functionStr ==
"min") {
503 function = ChannelConfig::Function::Minimum;
504 }
else if (functionStr ==
"max") {
505 function = ChannelConfig::Function::Maximum;
506 }
else if (functionStr ==
"failsafe") {
507 function = ChannelConfig::Function::Failsafe;
508 }
else if (functionStr !=
"") {
509 qCWarning(ActuatorsLog) <<
"Unknown 'function':" << functionStr;
512 Condition visibilityCondition = makeConditionFromValue(channelParameter,
"show-if");
513 subscribeFact(visibilityCondition.
fact());
515 qCDebug(ActuatorsLog) <<
"per-channel-param:" << param.
label <<
"param:" << param.
name;
519 QJsonArray channels = subgroup[
"channels"].toArray();
520 for (
const auto&& channelJson : channels) {
521 QJsonValue channel = channelJson.toObject();
522 QString channelLabel = channel[
"label"].toString();
523 int paramIndex = channel[
"param-index"].toInt();
524 qCDebug(ActuatorsLog) <<
"channel label:" << channelLabel <<
"param-index" << paramIndex;
532 _showUi = makeConditionFromValue(QJsonValue(obj),
"show-ui-if");
535 QMap<int, Mixer::Mixers::OutputFunction> outputFunctions;
536 QJsonObject functions = functionsJson.toObject();
537 for (
const auto& functionKey : functions.keys()) {
539 int key = functionKey.toInt(&ok);
541 QJsonObject functionObj = functions.value(functionKey).toObject();
542 QString label = functionObj[
"label"].toString();
544 QJsonObject noteObj = functionObj[
"note"].toObject();
545 QString note = noteObj[
"text"].toString();
546 QString condition = noteObj[
"condition"].toString();
547 QString noteCondition = functionObj[
"label"].toString();
548 bool exclude = functionObj[
"exclude-from-actuator-testing"].toBool(
false);
550 subscribeFact(conditionObj.fact());
555 qCDebug(ActuatorsLog) <<
"functions:" << outputFunctions;
559 QJsonObject actuatorTypesJson = mixerJson.toObject().value(
"actuator-types").toObject();
560 for (
const auto& actuatorTypeName : actuatorTypesJson.keys()) {
561 QJsonValue actuatorTypeVal = actuatorTypesJson.value(actuatorTypeName).toObject();
563 actuatorType.
functionMin = actuatorTypeVal[
"function-min"].toInt();
564 actuatorType.functionMax = actuatorTypeVal[
"function-max"].toInt();
565 actuatorType.labelIndexOffset = actuatorTypeVal[
"label-index-offset"].toInt(0);
566 QJsonValue values = actuatorTypeVal[
"values"].toObject();
567 actuatorType.values.min = values[
"min"].toDouble();
568 actuatorType.values.max = values[
"max"].toDouble();
569 actuatorType.values.defaultVal = values[
"default"].toDouble();
570 if (values[
"default-is-nan"].toBool()) {
571 actuatorType.values.defaultVal = NAN;
573 actuatorType.values.reversible = values[
"reversible"].toBool();
575 QJsonArray perItemParametersJson = actuatorTypeVal[
"per-item-parameters"].toArray();
576 for (
const auto&& perItemParameterJson : perItemParametersJson) {
577 QJsonValue perItemParameter = perItemParameterJson.toObject();
579 param.
parse(perItemParameter);
580 actuatorType.perItemParams.append(param);
582 actuatorTypes[actuatorTypeName] = actuatorType;
586 auto actuatorTypeIter = actuatorTypes.constBegin();
587 while (actuatorTypeIter != actuatorTypes.constEnd()) {
588 if (actuatorTypeIter.key() !=
"DEFAULT") {
589 for (
int function = actuatorTypeIter.value().functionMin; function <= actuatorTypeIter.value().functionMax; ++function) {
590 auto functionIter = outputFunctions.find(function);
591 if (functionIter != outputFunctions.end()) {
592 functionIter->actuatorType = actuatorTypeIter.key();
600 QJsonValue mixerConfigJson = mixerJson.toObject().value(
"config");
601 QJsonArray mixerConfigJsonArr = mixerConfigJson.toArray();
602 for (
const auto&& mixerConfigJsonValue : mixerConfigJsonArr) {
603 QJsonValue mixerConfig = mixerConfigJsonValue.toObject();
605 option.
option = mixerConfig[
"option"].toString();
606 option.type = mixerConfig[
"type"].toString();
607 option.title = mixerConfig[
"title"].toString();
608 option.helpUrl = mixerConfig[
"help-url"].toString();
609 QJsonArray actuatorsJson = mixerConfig[
"actuators"].toArray();
610 for (
const auto&& actuatorJson : actuatorsJson) {
611 QJsonValue actuatorJsonVal = actuatorJson.toObject();
613 actuator.
groupLabel = actuatorJsonVal[
"group-label"].toString();
614 if (actuatorJsonVal[
"count"].isString()) {
615 actuator.count = actuatorJsonVal[
"count"].toString();
617 actuator.fixedCount = actuatorJsonVal[
"count"].toInt();
619 actuator.actuatorType = actuatorJsonVal[
"actuator-type"].toString();
620 actuator.required = actuatorJsonVal[
"required"].toBool(
false);
621 QJsonArray parametersJson = actuatorJsonVal[
"parameters"].toArray();
622 for (
const auto&& parameterJson : parametersJson) {
623 QJsonValue parameter = parameterJson.toObject();
625 mixerParameter.
parse(parameter);
626 actuator.parameters.append(mixerParameter);
629 QJsonArray perItemParametersJson = actuatorJsonVal[
"per-item-parameters"].toArray();
630 for (
const auto&& parameterJson : perItemParametersJson) {
631 QJsonValue parameter = parameterJson.toObject();
634 mixerParameter.identifier = parameter[
"identifier"].toString();
635 QString function = parameter[
"function"].toString();
636 if (function ==
"posx") {
638 }
else if (function ==
"posy") {
640 }
else if (function ==
"posz") {
642 }
else if (function ==
"spin-dir") {
644 }
else if (function ==
"axisx") {
646 }
else if (function ==
"axisy") {
648 }
else if (function ==
"axisz") {
650 }
else if (function ==
"type") {
652 }
else if (function !=
"") {
653 qCWarning(ActuatorsLog) <<
"Unknown param function:" << function;
656 bool invalid =
false;
657 if (mixerParameter.param.name ==
"") {
658 QJsonArray valuesJson = parameter[
"value"].toArray();
659 for (
const auto&& valueJson : valuesJson) {
660 mixerParameter.values.append(valueJson.toDouble());
663 if (actuator.fixedCount != mixerParameter.values.size() && mixerParameter.values.size() != 1) {
665 qCWarning(ActuatorsLog) <<
"Invalid mixer param config:" << actuator.fixedCount <<
"," << mixerParameter.values.size();
669 actuator.perItemParameters.append(mixerParameter);
673 if (actuatorJsonVal[
"item-label-prefix"].isString()) {
674 actuator.itemLabelPrefix.append(actuatorJsonVal[
"item-label-prefix"].toString());
676 QJsonArray itemLabelPrefixJson = actuatorJsonVal[
"item-label-prefix"].toArray();
677 for (
const auto&& itemLabelPrefix : itemLabelPrefixJson) {
678 actuator.itemLabelPrefix.append(itemLabelPrefix.toString());
680 if (actuator.fixedCount != actuator.itemLabelPrefix.size() && actuator.itemLabelPrefix.size() > 1) {
681 qCWarning(ActuatorsLog) <<
"Invalid mixer config (item-label-prefix):" << actuator.fixedCount <<
","
682 << actuator.itemLabelPrefix.size();
686 option.actuators.append(actuator);
688 mixerOptions.append(option);
691 QList<Mixer::Rule> rules;
692 QJsonValue mixerRulesJson = mixerJson.toObject().value(
"rules");
693 QJsonArray mixerRulesJsonArr = mixerRulesJson.toArray();
694 for (
const auto&& mixerRuleJson : mixerRulesJsonArr) {
695 QJsonValue mixerRule = mixerRuleJson.toObject();
699 QJsonArray identifiersJson = mixerRule[
"apply-identifiers"].toArray();
700 for (
const auto&& identifierJson : identifiersJson) {
701 rule.applyIdentifiers.append(identifierJson.toString());
704 QJsonObject itemsJson = mixerRule[
"items"].toObject();
705 for (
const auto& itemKey : itemsJson.keys()) {
707 int key = itemKey.toInt(&ok);
709 QJsonArray itemsArr = itemsJson.value(itemKey).toArray();
710 QList<Mixer::Rule::RuleItem> items{};
711 for (
const auto&& itemJson : itemsArr) {
712 QJsonObject itemObj = itemJson.toObject();
715 if (itemObj.contains(
"min")) {
717 item.min = itemObj[
"min"].toDouble();
719 if (itemObj.contains(
"max")) {
721 item.max = itemObj[
"max"].toDouble();
723 if (itemObj.contains(
"default")) {
724 item.hasDefault =
true;
725 item.defaultVal = itemObj[
"default"].toDouble();
727 item.hidden = itemObj[
"hidden"].toBool(
false);
728 item.disabled = itemObj[
"disabled"].toBool(
false);
731 if (items.size() == rule.applyIdentifiers.size()) {
732 rule.items[key] = items;
734 qCWarning(ActuatorsLog) <<
"Rules: unexpected num items in " << itemsArr <<
"expected:" << rule.applyIdentifiers.size();
741 _mixer.
reset(actuatorTypes, mixerOptions, outputFunctions, rules);
746Fact* Actuators::getFact(
const QString& paramName)
749 qCDebug(ActuatorsLog) <<
"Mixer: Param does not exist:" << paramName;
757void Actuators::subscribeFact(
Fact* fact)
759 if (fact && !_subscribedFacts.contains(fact)) {
761 _subscribedFacts.insert(fact);
779 qWarning() <<
"Actuator type 'motor' not found";
781 ret = _motorAssignment.
initAssignment(_selectedActuatorOutput, iter->functionMin, numMotors);
786void Actuators::highlightActuators(
bool highlight)
789 QList<ActuatorGeometry>& actuators = provider->
actuators();
790 for (
auto& actuator : actuators) {
792 actuator.renderOptions.highlight = highlight;
795 updateGeometryImage();
800 highlightActuators(
true);
801 _motorAssignment.
start();
805 _motorAssignment.
abort();
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void addConfigParam(ConfigParameter *param)
void addChannel(ActuatorOutputChannel *channel)
QmlObjectListModel * channelConfigs()
void addChannelConfig(ChannelConfig *channelConfig)
void addAction(const ActuatorActions::Config &action)
QmlObjectListModel * subgroups()
ConfigParameter * enableParam() const
void forEachOutputFunction(std::function< void(ActuatorOutputSubgroup *, ChannelConfigInstance *, Fact *)> callback) const
void getAllChannelFunctions(QList< Fact * > &allFunctions) const
void addConfigParam(ConfigParameter *param)
void addNote(const QString ¬e)
bool hasExistingOutputFunctionParams() const
void addSubgroup(ActuatorOutputSubgroup *subgroup)
Function
Describes the meaning of the parameter.
void updateFunctions(const QList< Actuator * > &actuators)
void actuatorOutputsChanged()
Q_INVOKABLE bool initMotorAssignment()
void hasUnsetRequiredFunctionsChanged()
Q_INVOKABLE void abortMotorAssignment()
bool isMultirotor() const
void imageRefreshFlagChanged()
void motorAssignmentMessageChanged()
Q_INVOKABLE void selectActuatorOutput(int index)
Q_INVOKABLE void startMotorAssignment()
Q_INVOKABLE void imageClicked(QSizeF displaySize, float x, float y)
void motorAssignmentActiveChanged()
ActuatorOutputs::ActuatorOutput * selectedActuatorOutput() const
void motorAssignmentEnabledChanged()
void load(const QString &json_file, const QJsonDocument &metadata)
void selectedActuatorOutputChanged()
A Fact is used to hold a single value within the system.
void setEnumInfo(const QStringList &strings, const QVariantList &values)
Generally this is done during parsing. But if you know what you are doing, you can.
void rawValueChanged(const QVariant &value)
QStringList enumStrings() const
QVariant rawValue() const
Value after translation.
static VehicleGeometryImageProvider * instance()
QList< ActuatorGeometry > & actuators()
int getHighlightedMotorIndexAtPos(const QSizeF &displaySize, const QPointF &position)
bool getGeometry(const ActuatorTypes &actuatorTypes, const MixerOption::ActuatorGroup &group, ActuatorGeometry &geometry) const
const MixerOption::ActuatorGroup & group() const
QmlObjectListModel * channels()
const ActuatorTypes & actuatorTypes() const
QString configuredType() const
QmlObjectListModel * groups()
const QMap< int, OutputFunction > & functions() const
void reset(const ActuatorTypes &actuatorTypes, const MixerOptions &mixerOptions, const QMap< int, OutputFunction > &functions, const Rules &rules)
QString getSpecificLabelForFunction(int function) const
void geometryParamChanged()
QSet< int > getFunctions(bool requiredOnly) const
void selectMotor(int motorIndex)
bool initAssignment(int selectedActuatorIdx, int firstMotorsFunction, int numMotors)
bool parameterExists(int componentId, const QString ¶mName) const
Fact * getParameter(int componentId, const QString ¶mName)
bool parametersReady() const
static constexpr int defaultComponentId
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
Q_INVOKABLE QObject * get(int index)
QObject * removeAt(int index)
int count() const override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
ParameterManager * parameterManager()
@ SpinDirection
CCW = true or 1.
QList< MixerOption > MixerOptions
QMap< QString, ActuatorType > ActuatorTypes
key is the group name, where 'DEFAULT' is the default group
@ set3DModeOn
motors: enable 3D mode (reversible)
@ setSpinDirection2
motors: set spin direction 2
@ set3DModeOff
motors: disable 3D mode (reversible)
@ setSpinDirection1
motors: set spin direction 1
static Type typeFromStr(const QString &type)
void parse(const QJsonValue &jsonValue)
QString name
vehicle parameter name, this may have an index in the form '${i}'