14 : QObject(parent), _vehicle(vehicle), _actuators(actuators)
16 _spinTimer.setInterval(_spinTimeoutDefaultSec);
17 _spinTimer.setSingleShot(
true);
18 connect(&_spinTimer, &QTimer::timeout,
this, &MotorAssignment::spinTimeout);
23 if (_state != State::Idle) {
24 qCWarning(MotorAssignmentLog) <<
"Already init/running";
28 _functionFacts.clear();
29 for (
int groupIdx = 0; groupIdx < _actuators->
count(); groupIdx++) {
30 auto group = qobject_cast<ActuatorOutputs::ActuatorOutput*>(_actuators->
get(groupIdx));
31 _functionFacts.append(QList<Fact*>{});
32 group->getAllChannelFunctions(_functionFacts.last());
42 std::vector<bool> selectedAssignment(numMotors);
43 std::vector<bool> otherAssignment(numMotors);
44 for (
auto& group : _functionFacts) {
45 bool selected = index == selectedActuatorIdx;
46 for (
auto& fact : group) {
47 int currentFunction = fact->rawValue().toInt();
48 if (currentFunction >= firstMotorsFunction && currentFunction < firstMotorsFunction + numMotors) {
50 selectedAssignment[currentFunction - firstMotorsFunction] =
true;
52 otherAssignment[currentFunction - firstMotorsFunction] =
true;
59 int numAssignedToSelected = 0;
60 for (
int i = 0; i < numMotors; ++i) {
61 numAssigned += selectedAssignment[i] || otherAssignment[i];
62 numAssignedToSelected += selectedAssignment[i];
65 QString selectedActuatorOutputName = qobject_cast<ActuatorOutputs::ActuatorOutput*>(_actuators->
get(selectedActuatorIdx))->label();
67 _assignMotors =
false;
69 if (numAssigned == 0 && _functionFacts[selectedActuatorIdx].size() >= numMotors) {
72R
"(<br />No motors are assigned yet.
73By saying yes, all motors will be assigned to the first %1 channels of the selected output (%2)
74 (you can also first assign all motors, then start the identification).<br />)").arg(numMotors).arg(selectedActuatorOutputName);
76 } else if (numAssigned > 0 && numAssignedToSelected == 0 && _functionFacts[selectedActuatorIdx].size() >= numMotors) {
79R
"(<br />Motors are currently assigned to a different output.
80By saying yes, all motors will be reassigned to the first %1 channels of the selected output (%2).<br />)")
81 .arg(numMotors).arg(selectedActuatorOutputName);
83 } else if (numAssigned < numMotors) {
84 _message = tr(
"Not all motors are assigned yet. Either clear all existing assignments or assign all motors to an output.");
90R
"(This will automatically spin individual motors at 15% thrust.<br /><br />
91<b>Warning: Only proceed if you removed all propellers</b>.<br />
94The procedure is as following:<br />
95- After confirming, the first motor starts to spin for 0.5 seconds.<br />
96- Then click on the motor that was spinning.<br />
97- The above steps are repeated for all motors.<br />
98- The motor output functions will automatically be reassigned by the selected order.<br />
100Do you wish to proceed?)").arg(extraMessage);
103 _selectedActuatorIdx = selectedActuatorIdx;
104 _firstMotorsFunction = firstMotorsFunction;
105 _numMotors = numMotors;
106 _selectedMotors.clear();
107 _state = State::Init;
114 if (_state != State::Init) {
115 qCWarning(MotorAssignmentLog) <<
"Invalid state";
121 for (
auto& group : _functionFacts) {
122 for (
auto& fact : group) {
123 int currentFunction = fact->rawValue().toInt();
124 if (currentFunction >= _firstMotorsFunction && currentFunction < _firstMotorsFunction + _numMotors) {
125 fact->setRawValue(0);
131 for (
auto& fact : _functionFacts[_selectedActuatorIdx]) {
132 fact->setRawValue(_firstMotorsFunction + index);
133 if (++index >= _numMotors) {
138 _state = State::Running;
140 _spinTimer.setInterval(_assignMotors ? _spinTimeoutHighSec : _spinTimeoutDefaultSec);
146 if (_state != State::Running) {
147 qCDebug(MotorAssignmentLog) <<
"Not running";
151 _selectedMotors.append(motorIndex);
152 if (_selectedMotors.size() == _numMotors) {
155 for (
auto& group : _functionFacts) {
156 for (
auto& fact : group) {
157 int currentFunction = fact->rawValue().toInt();
158 if (currentFunction >= _firstMotorsFunction && currentFunction < _firstMotorsFunction + _numMotors) {
160 fact->setRawValue(_firstMotorsFunction + _selectedMotors[currentFunction - _firstMotorsFunction]);
165 _state = State::Idle;
169 _spinTimer.setInterval(_spinTimeoutDefaultSec);
176 if (!_commandInProgress) {
178 int motorIndex = _selectedMotors.size();
179 sendMavlinkRequest(_firstMotorsFunction + motorIndex, 0.15f);
186 _state = State::Idle;
191void MotorAssignment::spinTimeout()
199 motorAssignment->ackHandler(
static_cast<MAV_RESULT
>(ack.result), failureCode);
204 _commandInProgress =
false;
211void MotorAssignment::sendMavlinkRequest(
int function,
float value)
213 qCDebug(MotorAssignmentLog) <<
"Sending actuator test function:" << function <<
"value:" << value;
221 MAV_COMP_ID_AUTOPILOT1,
222 MAV_CMD_ACTUATOR_TEST,
230 _commandInProgress =
true;
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct __mavlink_command_ack_t mavlink_command_ack_t
void selectMotor(int motorIndex)
bool initAssignment(int selectedActuatorIdx, int firstMotorsFunction, int numMotors)
Q_INVOKABLE QObject * get(int index)
int count() const override final
void sendMavCommandWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
Sends the command and calls the callback with the result.
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Callback info bundle for sendMavCommandWithHandler.
MavCmdResultHandler resultHandler
nullptr for no handler
MavCmdResultFailureCode_t
@ MavCmdResultFailureNoResponseToCommand
No response from vehicle to command.