6#include <QtCore/QString>
8#include <QtCore/QJsonArray>
9#include <QtCore/QJsonObject>
16 : QObject(parent), _actuatorTest(vehicle), _mixer(vehicle->parameterManager()),
17 _motorAssignment(nullptr, vehicle, _actuatorOutputs), _vehicle(vehicle)
21 qRegisterMetaType<Actuators*>(
"Actuators*");
27void Actuators::imageClicked(QSizeF displaySize,
float x,
float y)
30 QPointF clickPosition{ x, y };
32 qCDebug(ActuatorsConfigLog) <<
"Image clicked: position:" << clickPosition <<
"displaySize:" << displaySize <<
"motor index:" << motorIndex;
34 if (_motorAssignment.
active()) {
35 QList<ActuatorGeometry>& actuators = provider->
actuators();
37 for (
auto& actuator : actuators) {
39 actuator.renderOptions.highlight =
false;
43 updateGeometryImage();
54 if (index >= _actuatorOutputs->
count() || index < 0) {
57 _selectedActuatorOutput = index;
62 if (_actuatorOutputs->
count() == 0) {
68void Actuators::updateGeometryImage()
72 QList<ActuatorGeometry>& actuators = provider->
actuators();
73 QList<ActuatorGeometry> previousActuators = actuators;
77 for (
int mixerGroupIdx = 0; mixerGroupIdx < _mixer.groups()->count(); ++mixerGroupIdx) {
79 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
83 actuators.append(geometry);
84 qCDebug(ActuatorsConfigLog) <<
"Airframe actuator:" << geometry.
index <<
"pos:" << geometry.position;
90 if (previousActuators.size() == actuators.size()) {
91 for (
int i = 0; i < actuators.size(); ++i) {
92 if (previousActuators[i].type == actuators[i].type && previousActuators[i].index == actuators[i].index) {
93 actuators[i].renderOptions = previousActuators[i].renderOptions;
98 _imageRefreshFlag = !_imageRefreshFlag;
101 _motorAssignmentEnabled = provider->
numMotors() > 0;
114 QFile file(json_file);
115 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
116 _initError = QStringLiteral(
"Could not open metadata file: %1").arg(file.fileName());
118 qCWarning(ActuatorsConfigLog) << _initError;
122 const QByteArray json_data = file.readAll();
125 QJsonParseError parseError;
126 _jsonMetadata = QJsonDocument::fromJson(json_data, &parseError);
127 if (_jsonMetadata.isNull()) {
128 _initError = QStringLiteral(
"Invalid JSON in metadata file %1: %2").arg(file.fileName(), parseError.errorString());
130 qCWarning(ActuatorsConfigLog) << _initError;
142 qWarning() <<
"Incorrect calling order, parameters not yet ready";
145 if (!parseJson(_jsonMetadata)) {
151 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
152 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
154 qCDebug(ActuatorsConfigLog) <<
"Removing actuator group w/o function parameters at" << groupIdx;
155 _actuatorOutputs->
removeAt(groupIdx);
167 qCDebug(ActuatorsConfigLog) <<
"Param update";
172 QList<int> allFunctions;
173 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
174 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
176 QList<Fact*> groupFunctions;
178 for (
const auto& groupFunction : groupFunctions) {
179 int function = groupFunction->rawValue().toInt();
181 allFunctions.append(function);
185 const auto iter = _mixer.
functions().find(function);
186 if (iter != _mixer.
functions().end() && iter->note !=
"") {
187 if (iter->noteCondition.evaluate()) {
188 qCDebug(ActuatorsConfigLog) <<
"Showing Note:" << iter->note;
195 for (
int subbroupIdx = 0; subbroupIdx < group->
subgroups()->count(); subbroupIdx++) {
197 for (
int channelIdx = 0; channelIdx < subgroup->
channelConfigs()->count(); channelIdx++) {
204 std::sort(allFunctions.begin(), allFunctions.end());
207 QList<ActuatorTesting::Actuator*> actuators;
208 QSet<int> uniqueConfiguredFunctions;
210 for (
int function : allFunctions) {
211 if (uniqueConfiguredFunctions.find(function) != uniqueConfiguredFunctions.end()) {
214 uniqueConfiguredFunctions.insert(function);
218 bool excludeFromActuatorTesting =
false;
219 const auto iter = _mixer.
functions().find(function);
221 excludeFromActuatorTesting = iter->excludeFromActuatorTesting;
225 if (!excludeFromActuatorTesting) {
227 for (
const auto& actuatorTypeName : actuatorTypes.keys()) {
238 if (!found && actuatorTypes.find(
"DEFAULT") != actuatorTypes.end()) {
249 QSet<int> requiredFunctions = _mixer.
getFunctions(
true);
250 _hasUnsetRequiredFunctions =
false;
251 for (
int requiredFunction : requiredFunctions) {
252 if (uniqueConfiguredFunctions.find(requiredFunction) == uniqueConfiguredFunctions.end()) {
253 _hasUnsetRequiredFunctions =
true;
258 updateFunctionMetadata();
260 updateActuatorActions();
262 updateGeometryImage();
265void Actuators::updateFunctionMetadata()
270 QSet<int> usedMixerFunctions = _mixer.
getFunctions(
false);
272 QMap<int, QString> usedMixerLabels;
273 for (
int usedMixerFunction : usedMixerFunctions) {
277 if (_usedMixerLabels == usedMixerLabels) {
281 _usedMixerLabels = usedMixerLabels;
284 QSet<int> removedMixerFunctions;
285 for(Mixer::ActuatorTypes::const_iterator iter = _mixer.
actuatorTypes().constBegin();
287 if (iter.key() ==
"DEFAULT")
290 for (
int i = iter.value().functionMin; i <= iter.value().functionMax; ++i) {
291 if (!usedMixerFunctions.contains(i)) {
292 removedMixerFunctions.insert(i);
298 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
299 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
302 QStringList enumStrings = fact->enumStrings();
303 if (!enumStrings.empty()) {
304 QVariantList enumValues = fact->enumValues();
307 for (int usedMixerFunction : usedMixerFunctions) {
308 QString label = usedMixerLabels[usedMixerFunction];
309 int index = enumValues.indexOf(usedMixerFunction);
312 bool inserted = false;
313 for (index = 0; index < enumValues.count() && !inserted; ++index) {
314 if (enumValues[index].toInt() > usedMixerFunction) {
315 enumValues.insert(index, usedMixerFunction);
316 enumStrings.insert(index, label);
321 enumValues.append(usedMixerFunction);
322 enumStrings.append(label);
325 enumStrings[index] = label;
330 for (
int removedMixerFunction : removedMixerFunctions) {
331 int index = enumValues.indexOf(removedMixerFunction);
333 enumValues.removeAt(index);
334 enumStrings.removeAt(index);
338 fact->setEnumInfo(enumStrings, enumValues);
344void Actuators::updateActuatorActions()
347 QSet<int> addedFunctions;
348 for (
int groupIdx = 0; groupIdx < _actuatorOutputs->
count(); groupIdx++) {
349 ActuatorOutput* group = qobject_cast<ActuatorOutput*>(_actuatorOutputs->
get(groupIdx));
352 int outputFunctionVal = fact->rawValue().toInt();
353 if (outputFunctionVal != 0 && !addedFunctions.contains(outputFunctionVal)) {
354 auto outputFunctionIter = _mixer.functions().find(outputFunctionVal);
355 if (outputFunctionIter != _mixer.functions().end()) {
356 const Mixer::Mixers::OutputFunction& outputFunction = outputFunctionIter.value();
357 for (const auto& action : subgroup->actions()) {
358 if (!action.condition.evaluate()) {
361 if (!action.actuatorTypes.empty() && action.actuatorTypes.find(outputFunction.actuatorType) == action.actuatorTypes.end()) {
366 auto actuatorAction = new ActuatorActions::Action(this, action, outputFunction.label, outputFunctionVal, _vehicle);
367 ActuatorActions::ActionGroup* actionGroup = nullptr;
369 for (int actionGroupIdx = 0; actionGroupIdx < _actuatorActions->count(); actionGroupIdx++) {
370 ActuatorActions::ActionGroup* curActionGroup =
371 qobject_cast<ActuatorActions::ActionGroup*>(_actuatorActions->get(actionGroupIdx));
372 if (curActionGroup->type() == action.type) {
373 actionGroup = curActionGroup;
379 QString groupLabel = action.typeToLabel();
380 actionGroup = new ActuatorActions::ActionGroup(this, groupLabel, action.type);
381 _actuatorActions->append(actionGroup);
383 actionGroup->addAction(actuatorAction);
384 addedFunctions.insert(outputFunctionVal);
391 emit actuatorActionsChanged();
394bool Actuators::parseJson(
const QJsonDocument &json)
398 QJsonObject obj = json.object();
399 QJsonValue outputsJson = obj.value(
"outputs_v1");
400 QJsonValue functionsJson = obj.value(
"functions_v1");
401 QJsonValue mixerJson = obj.value(
"mixer_v1");
402 if (outputsJson.isNull() || functionsJson.isNull() || mixerJson.isNull()) {
404 if (outputsJson.isNull()) missing <<
"outputs_v1";
405 if (functionsJson.isNull()) missing <<
"functions_v1";
406 if (mixerJson.isNull()) missing <<
"mixer_v1";
407 if (_initError.isEmpty()) {
408 _initError = QStringLiteral(
"Missing required JSON sections: %1").arg(missing.join(
", "));
410 qCWarning(ActuatorsConfigLog) << _initError;
415 auto makeConditionFromValue = [
this](
const QJsonValue& val,
const char* key) {
419 QJsonArray outputs = outputsJson.toArray();
420 for (
const auto &&outputJson : outputs) {
421 QJsonValue output = outputJson.toObject();
422 QString label = output[
"label"].toString();
424 qCDebug(ActuatorsConfigLog) <<
"Actuator group:" << label;
426 Condition groupVisibilityCondition = makeConditionFromValue(output,
"show-subgroups-if");
427 subscribeFact(groupVisibilityCondition.
fact());
430 _actuatorOutputs->
append(currentActuatorOutput);
432 auto parseParam = [¤tActuatorOutput,
this](
const QJsonValue ¶meter) {
434 param.
parse(parameter);
435 QString functionStr = parameter[
"function"].toString(
"");
436 qCDebug(ActuatorsConfigLog) <<
"param:" << param.name <<
"label:" << param.label <<
"function:" << functionStr;
438 if (functionStr ==
"enable") {
439 function = ConfigParameter::Function::Enable;
440 }
else if (functionStr ==
"primary") {
441 function = ConfigParameter::Function::Primary;
442 }
else if (functionStr !=
"") {
443 qCWarning(ActuatorsConfigLog) <<
"Unknown function " << functionStr <<
"for param" << param.name;
445 return new ConfigParameter(currentActuatorOutput, getFact(param.name), param.label, function);
448 QJsonArray parameters = output[
"parameters"].toArray();
449 for (
const auto&& parameterJson : parameters) {
450 currentActuatorOutput->
addConfigParam(parseParam(parameterJson.toObject()));
453 QJsonArray subgroups = output[
"subgroups"].toArray();
454 for (
const auto&& subgroupJson : subgroups) {
455 QJsonValue subgroup = subgroupJson.toObject();
456 QString subgroupLabel = subgroup[
"label"].toString();
458 currentActuatorOutput->
addSubgroup(actuatorSubgroup);
460 QJsonValue supportedActions = subgroup[
"supported-actions"];
461 if (!supportedActions.isNull()) {
462 QJsonObject supportedActionsObj = supportedActions.toObject();
463 for (
const auto& actionName : supportedActionsObj.keys()) {
464 QJsonObject actionObj = supportedActionsObj.value(actionName).toObject();
466 bool knownAction =
true;
467 if (actionName ==
"beep") {
469 }
else if (actionName ==
"3d-mode-on") {
471 }
else if (actionName ==
"3d-mode-off") {
473 }
else if (actionName ==
"set-spin-direction1") {
475 }
else if (actionName ==
"set-spin-direction2") {
479 qCWarning(ActuatorsConfigLog) <<
"Unknown 'supported-actions':" << actionName;
482 QJsonArray actuatorTypesArr = actionObj[
"actuator-types"].toArray();
483 for (
const auto&& type : actuatorTypesArr) {
484 action.actuatorTypes.insert(type.toString());
486 action.condition = makeConditionFromValue(actionObj,
"supported-if");
487 subscribeFact(action.condition.fact());
493 QJsonArray subgroupParameters = subgroup[
"parameters"].toArray();
494 for (
const auto&& parameterJson : subgroupParameters) {
495 actuatorSubgroup->
addConfigParam(parseParam(parameterJson.toObject()));
498 QJsonArray channelParameters = subgroup[
"per-channel-parameters"].toArray();
499 for (
const auto&& channelParametersJson : channelParameters) {
500 QJsonValue channelParameter = channelParametersJson.toObject();
502 param.
parse(channelParameter);
505 QString functionStr = channelParameter[
"function"].toString(
"");
506 if (functionStr ==
"function") {
507 function = ChannelConfig::Function::OutputFunction;
508 }
else if (functionStr ==
"disarmed") {
509 function = ChannelConfig::Function::Disarmed;
510 }
else if (functionStr ==
"min") {
511 function = ChannelConfig::Function::Minimum;
512 }
else if (functionStr ==
"max") {
513 function = ChannelConfig::Function::Maximum;
514 }
else if (functionStr ==
"failsafe") {
515 function = ChannelConfig::Function::Failsafe;
516 }
else if (functionStr !=
"") {
517 qCWarning(ActuatorsConfigLog) <<
"Unknown 'function':" << functionStr;
520 Condition visibilityCondition = makeConditionFromValue(channelParameter,
"show-if");
521 subscribeFact(visibilityCondition.
fact());
523 qCDebug(ActuatorsConfigLog) <<
"per-channel-param:" << param.
label <<
"param:" << param.
name;
527 QJsonArray channels = subgroup[
"channels"].toArray();
528 for (
const auto&& channelJson : channels) {
529 QJsonValue channel = channelJson.toObject();
530 QString channelLabel = channel[
"label"].toString();
531 int paramIndex = channel[
"param-index"].toInt();
532 qCDebug(ActuatorsConfigLog) <<
"channel label:" << channelLabel <<
"param-index" << paramIndex;
540 _showUi = makeConditionFromValue(QJsonValue(obj),
"show-ui-if");
543 QMap<int, Mixer::Mixers::OutputFunction> outputFunctions;
544 QJsonObject functions = functionsJson.toObject();
545 for (
const auto& functionKey : functions.keys()) {
547 int key = functionKey.toInt(&ok);
549 QJsonObject functionObj = functions.value(functionKey).toObject();
550 QString label = functionObj[
"label"].toString();
552 QJsonObject noteObj = functionObj[
"note"].toObject();
553 QString note = noteObj[
"text"].toString();
554 QString condition = noteObj[
"condition"].toString();
555 QString noteCondition = functionObj[
"label"].toString();
556 bool exclude = functionObj[
"exclude-from-actuator-testing"].toBool(
false);
558 subscribeFact(conditionObj.fact());
563 qCDebug(ActuatorsConfigLog) <<
"functions:" << outputFunctions;
567 QJsonObject actuatorTypesJson = mixerJson.toObject().value(
"actuator-types").toObject();
568 for (
const auto& actuatorTypeName : actuatorTypesJson.keys()) {
569 QJsonValue actuatorTypeVal = actuatorTypesJson.value(actuatorTypeName).toObject();
571 actuatorType.
functionMin = actuatorTypeVal[
"function-min"].toInt();
572 actuatorType.functionMax = actuatorTypeVal[
"function-max"].toInt();
573 actuatorType.labelIndexOffset = actuatorTypeVal[
"label-index-offset"].toInt(0);
574 QJsonValue values = actuatorTypeVal[
"values"].toObject();
575 actuatorType.values.min = values[
"min"].toDouble();
576 actuatorType.values.max = values[
"max"].toDouble();
577 actuatorType.values.defaultVal = values[
"default"].toDouble();
578 if (values[
"default-is-nan"].toBool()) {
579 actuatorType.values.defaultVal = NAN;
581 actuatorType.values.reversible = values[
"reversible"].toBool();
583 QJsonArray perItemParametersJson = actuatorTypeVal[
"per-item-parameters"].toArray();
584 for (
const auto&& perItemParameterJson : perItemParametersJson) {
585 QJsonValue perItemParameter = perItemParameterJson.toObject();
587 param.
parse(perItemParameter);
588 actuatorType.perItemParams.append(param);
590 actuatorTypes[actuatorTypeName] = actuatorType;
594 auto actuatorTypeIter = actuatorTypes.constBegin();
595 while (actuatorTypeIter != actuatorTypes.constEnd()) {
596 if (actuatorTypeIter.key() !=
"DEFAULT") {
597 for (
int function = actuatorTypeIter.value().functionMin; function <= actuatorTypeIter.value().functionMax; ++function) {
598 auto functionIter = outputFunctions.find(function);
599 if (functionIter != outputFunctions.end()) {
600 functionIter->actuatorType = actuatorTypeIter.key();
608 QJsonValue mixerConfigJson = mixerJson.toObject().value(
"config");
609 QJsonArray mixerConfigJsonArr = mixerConfigJson.toArray();
610 for (
const auto&& mixerConfigJsonValue : mixerConfigJsonArr) {
611 QJsonValue mixerConfig = mixerConfigJsonValue.toObject();
613 option.
option = mixerConfig[
"option"].toString();
614 option.type = mixerConfig[
"type"].toString();
615 option.title = mixerConfig[
"title"].toString();
616 option.helpUrl = mixerConfig[
"help-url"].toString();
617 QJsonArray actuatorsJson = mixerConfig[
"actuators"].toArray();
618 for (
const auto&& actuatorJson : actuatorsJson) {
619 QJsonValue actuatorJsonVal = actuatorJson.toObject();
621 actuator.
groupLabel = actuatorJsonVal[
"group-label"].toString();
622 if (actuatorJsonVal[
"count"].isString()) {
623 actuator.count = actuatorJsonVal[
"count"].toString();
625 actuator.fixedCount = actuatorJsonVal[
"count"].toInt();
627 actuator.actuatorType = actuatorJsonVal[
"actuator-type"].toString();
628 actuator.required = actuatorJsonVal[
"required"].toBool(
false);
629 QJsonArray parametersJson = actuatorJsonVal[
"parameters"].toArray();
630 for (
const auto&& parameterJson : parametersJson) {
631 QJsonValue parameter = parameterJson.toObject();
633 mixerParameter.
parse(parameter);
634 actuator.parameters.append(mixerParameter);
637 QJsonArray perItemParametersJson = actuatorJsonVal[
"per-item-parameters"].toArray();
638 for (
const auto&& parameterJson : perItemParametersJson) {
639 QJsonValue parameter = parameterJson.toObject();
642 mixerParameter.identifier = parameter[
"identifier"].toString();
643 QString function = parameter[
"function"].toString();
644 if (function ==
"posx") {
646 }
else if (function ==
"posy") {
648 }
else if (function ==
"posz") {
650 }
else if (function ==
"spin-dir") {
652 }
else if (function ==
"axisx") {
654 }
else if (function ==
"axisy") {
656 }
else if (function ==
"axisz") {
658 }
else if (function ==
"type") {
660 }
else if (function !=
"") {
661 qCWarning(ActuatorsConfigLog) <<
"Unknown param function:" << function;
664 bool invalid =
false;
665 if (mixerParameter.param.name ==
"") {
666 QJsonArray valuesJson = parameter[
"value"].toArray();
667 for (
const auto&& valueJson : valuesJson) {
668 mixerParameter.values.append(valueJson.toDouble());
671 if (actuator.fixedCount != mixerParameter.values.size() && mixerParameter.values.size() != 1) {
673 qCWarning(ActuatorsConfigLog) <<
"Invalid mixer param config:" << actuator.fixedCount <<
"," << mixerParameter.values.size();
677 actuator.perItemParameters.append(mixerParameter);
681 if (actuatorJsonVal[
"item-label-prefix"].isString()) {
682 actuator.itemLabelPrefix.append(actuatorJsonVal[
"item-label-prefix"].toString());
684 QJsonArray itemLabelPrefixJson = actuatorJsonVal[
"item-label-prefix"].toArray();
685 for (
const auto&& itemLabelPrefix : itemLabelPrefixJson) {
686 actuator.itemLabelPrefix.append(itemLabelPrefix.toString());
688 if (actuator.fixedCount != actuator.itemLabelPrefix.size() && actuator.itemLabelPrefix.size() > 1) {
689 qCWarning(ActuatorsConfigLog) <<
"Invalid mixer config (item-label-prefix):" << actuator.fixedCount <<
","
690 << actuator.itemLabelPrefix.size();
694 option.actuators.append(actuator);
696 mixerOptions.append(option);
699 QList<Mixer::Rule> rules;
700 QJsonValue mixerRulesJson = mixerJson.toObject().value(
"rules");
701 QJsonArray mixerRulesJsonArr = mixerRulesJson.toArray();
702 for (
const auto&& mixerRuleJson : mixerRulesJsonArr) {
703 QJsonValue mixerRule = mixerRuleJson.toObject();
707 QJsonArray identifiersJson = mixerRule[
"apply-identifiers"].toArray();
708 for (
const auto&& identifierJson : identifiersJson) {
709 rule.applyIdentifiers.append(identifierJson.toString());
712 QJsonObject itemsJson = mixerRule[
"items"].toObject();
713 for (
const auto& itemKey : itemsJson.keys()) {
715 int key = itemKey.toInt(&ok);
717 QJsonArray itemsArr = itemsJson.value(itemKey).toArray();
718 QList<Mixer::Rule::RuleItem> items{};
719 for (
const auto&& itemJson : itemsArr) {
720 QJsonObject itemObj = itemJson.toObject();
723 if (itemObj.contains(
"min")) {
725 item.min = itemObj[
"min"].toDouble();
727 if (itemObj.contains(
"max")) {
729 item.max = itemObj[
"max"].toDouble();
731 if (itemObj.contains(
"default")) {
732 item.hasDefault =
true;
733 item.defaultVal = itemObj[
"default"].toDouble();
735 item.hidden = itemObj[
"hidden"].toBool(
false);
736 item.disabled = itemObj[
"disabled"].toBool(
false);
739 if (items.size() == rule.applyIdentifiers.size()) {
740 rule.items[key] = items;
742 qCWarning(ActuatorsConfigLog) <<
"Rules: unexpected num items in " << itemsArr <<
"expected:" << rule.applyIdentifiers.size();
749 _mixer.
reset(actuatorTypes, mixerOptions, outputFunctions, rules);
754Fact* Actuators::getFact(
const QString& paramName)
757 qCDebug(ActuatorsConfigLog) <<
"Mixer: Param does not exist:" << paramName;
765void Actuators::subscribeFact(
Fact* fact)
767 if (fact && !_subscribedFacts.contains(fact)) {
769 _subscribedFacts.insert(fact);
787 qWarning() <<
"Actuator type 'motor' not found";
789 ret = _motorAssignment.
initAssignment(_selectedActuatorOutput, iter->functionMin, numMotors);
794void Actuators::highlightActuators(
bool highlight)
797 QList<ActuatorGeometry>& actuators = provider->
actuators();
798 for (
auto& actuator : actuators) {
800 actuator.renderOptions.highlight = highlight;
803 updateGeometryImage();
808 highlightActuators(
true);
809 _motorAssignment.
start();
813 _motorAssignment.
abort();
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()
bool initMotorAssignment()
void hasUnsetRequiredFunctionsChanged()
void abortMotorAssignment()
bool isMultirotor() const
void imageRefreshFlagChanged()
QmlObjectListModel *actuatorOutputs READ actuatorOutputs NOTIFY actuatorOutputsChanged(QmlObjectListModel *actuatorActions READ actuatorActions NOTIFY actuatorActionsChanged) 1(bool isMultirotor READ isMultirotor CONSTANT) 1(bool imageRefreshFlag READ imageRefreshFlag NOTIFY imageRefreshFlagChanged) 1(bool hasUnsetRequiredFunctions READ hasUnsetRequiredFunctions NOTIFY hasUnsetRequiredFunctionsChanged) 1(bool motorAssignmentActive READ motorAssignmentActive NOTIFY motorAssignmentActiveChanged) 1(bool motorAssignmentEnabled READ motorAssignmentEnabled NOTIFY motorAssignmentEnabledChanged) 1(QString motorAssignmentMessage READ motorAssignmentMessage NOTIFY motorAssignmentMessageChanged) 1(ActuatorTesting voi selectActuatorOutput)(int index)
void motorAssignmentMessageChanged()
void startMotorAssignment()
void motorAssignmentActiveChanged()
ActuatorOutputs::ActuatorOutput * selectedActuatorOutput() const
void motorAssignmentEnabledChanged()
void load(const QString &json_file)
void selectedActuatorOutputChanged()
Actuators(QObject *parent, Vehicle *vehicle)
A Fact is used to hold a single value within the system.
void rawValueChanged(const QVariant &value)
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
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.
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}'