From a347a65985584dd05807f4be62b0ab5194f65042 Mon Sep 17 00:00:00 2001 From: LM Date: Tue, 14 Feb 2012 17:13:37 +0100 Subject: [PATCH] Formatting, fixing audio alarms --- .gitignore | 1 - audio/alert.wav | Bin 88334 -> 0 bytes files/audio/alert.wav | Bin 0 -> 88334 bytes qgroundcontrol.pri | 15 +- src/GAudioOutput.cc | 51 +- src/comm/MAVLinkSimulationLink.cc | 84 +-- src/uas/UAS.cc | 1130 ++++++++++++++++++------------------- src/uas/UAS.h | 3 +- src/ui/HSIDisplay.cc | 51 +- src/ui/HSIDisplay.h | 1 + 10 files changed, 685 insertions(+), 651 deletions(-) delete mode 100644 audio/alert.wav create mode 100644 files/audio/alert.wav diff --git a/.gitignore b/.gitignore index 9f3c6c9..9d9d566 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ debug release qgroundcontrol mavlinkgen-build-desktop -*.wav qgroundcontrol.xcodeproj/** doc/html doc/doxy.log diff --git a/audio/alert.wav b/audio/alert.wav deleted file mode 100644 index 6c9856863f887966971929a2554aee345bd96a15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88334 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"Hello world", 0, NULL); pVoice->Release(); pVoice = NULL; @@ -146,7 +151,8 @@ GAudioOutput::GAudioOutput(QObject* parent) : QObject(parent), void GAudioOutput::mute(bool mute) { - if (mute != muted) { + if (mute != muted) + { this->muted = mute; QSettings settings; settings.setValue(QGC_GAUDIOOUTPUT_KEY+"muted", this->muted); @@ -162,11 +168,13 @@ bool GAudioOutput::isMuted() bool GAudioOutput::say(QString text, int severity) { - if (!muted) { + if (!muted) + { // TODO Add severity filter Q_UNUSED(severity); bool res = false; - if (!emergency) { + if (!emergency) + { // Speech synthesis is only supported with MSVC compiler #ifdef _MSC_VER2 @@ -202,7 +210,9 @@ bool GAudioOutput::say(QString text, int severity) #endif } return res; - } else { + } + else + { return false; } } @@ -212,22 +222,26 @@ bool GAudioOutput::say(QString text, int severity) */ bool GAudioOutput::alert(QString text) { - if (!emergency || !muted) { + if (!emergency || !muted) + { // Play alert sound beep(); // Say alert message say(text, 2); return true; - } else { + } + else + { return false; } } void GAudioOutput::notifyPositive() { - if (!muted) { + if (!muted) + { // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/audio/double_notify.wav")); + QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/double_notify.wav")); //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); //m_media->play(); } @@ -235,9 +249,10 @@ void GAudioOutput::notifyPositive() void GAudioOutput::notifyNegative() { - if (!muted) { + if (!muted) + { // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/audio/flat_notify.wav")); + QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/flat_notify.wav")); //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); //m_media->play(); } @@ -252,7 +267,8 @@ void GAudioOutput::notifyNegative() */ bool GAudioOutput::startEmergency() { - if (!emergency) { + if (!emergency) + { emergency = true; // Beep immediately and then start timer if (!muted) beep(); @@ -279,9 +295,10 @@ bool GAudioOutput::stopEmergency() void GAudioOutput::beep() { - if (!muted) { + if (!muted) + { // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/audio/alert.wav")); + QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/alert.wav")); qDebug() << "FILE:" << f.fileName(); //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); //m_media->play(); diff --git a/src/comm/MAVLinkSimulationLink.cc b/src/comm/MAVLinkSimulationLink.cc index 27056fb..d5546cf 100644 --- a/src/comm/MAVLinkSimulationLink.cc +++ b/src/comm/MAVLinkSimulationLink.cc @@ -678,8 +678,7 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) int bufferlength = 0; // Output all bytes as hex digits - int i; - for (i=0; iid, data[i], &msg, &comm)) { @@ -687,16 +686,19 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) qDebug() << "SIMULATION LINK RECEIVED MESSAGE!"; emit messageReceived(msg); - switch (msg.msgid) { + switch (msg.msgid) + { // SET THE SYSTEM MODE - case MAVLINK_MSG_ID_SET_MODE: { + case MAVLINK_MSG_ID_SET_MODE: + { mavlink_set_mode_t mode; mavlink_msg_set_mode_decode(&msg, &mode); // Set mode indepent of mode.target system.base_mode = mode.base_mode; } break; - case MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT: { + case MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT: + { mavlink_set_local_position_setpoint_t set; mavlink_msg_set_local_position_setpoint_decode(&msg, &set); spX = set.x; @@ -714,7 +716,8 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) } break; // EXECUTE OPERATOR ACTIONS - case MAVLINK_MSG_ID_COMMAND_LONG: { + case MAVLINK_MSG_ID_COMMAND_LONG: + { mavlink_command_long_t action; mavlink_msg_command_long_decode(&msg, &action); @@ -756,44 +759,48 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) } break; #endif - case MAVLINK_MSG_ID_PARAM_REQUEST_LIST: { + case MAVLINK_MSG_ID_PARAM_REQUEST_LIST: + { qDebug() << "GCS REQUESTED PARAM LIST FROM SIMULATION"; mavlink_param_request_list_t read; mavlink_msg_param_request_list_decode(&msg, &read); -// if (read.target_system == systemId) -// { - // Output all params - // Iterate through all components, through all parameters and emit them - QMap::iterator i; - // Iterate through all components / subsystems - int j = 0; - for (i = onboardParams.begin(); i != onboardParams.end(); ++i) { - if (j != 5) { - // Pack message and get size of encoded byte string - mavlink_msg_param_value_pack(read.target_system, componentId, &msg, i.key().toStdString().c_str(), i.value(), MAVLINK_TYPE_FLOAT, onboardParams.size(), j); - // Allocate buffer with packet data - bufferlength = mavlink_msg_to_send_buffer(buffer, &msg); - //add data into datastream - memcpy(stream+streampointer,buffer, bufferlength); - streampointer+=bufferlength; + if (read.target_system == systemId) + { + // Output all params + // Iterate through all components, through all parameters and emit them + QMap::iterator i; + // Iterate through all components / subsystems + int j = 0; + for (i = onboardParams.begin(); i != onboardParams.end(); ++i) { + if (j != 5) { + // Pack message and get size of encoded byte string + mavlink_msg_param_value_pack(read.target_system, componentId, &msg, i.key().toStdString().c_str(), i.value(), MAVLINK_TYPE_FLOAT, onboardParams.size(), j); + // Allocate buffer with packet data + bufferlength = mavlink_msg_to_send_buffer(buffer, &msg); + //add data into datastream + memcpy(stream+streampointer,buffer, bufferlength); + streampointer+=bufferlength; + } + j++; } - j++; - } - qDebug() << "SIMULATION SENT PARAMETERS TO GCS"; -// } + qDebug() << "SIMULATION SENT PARAMETERS TO GCS"; + } } - break; - case MAVLINK_MSG_ID_PARAM_SET: { + break; + case MAVLINK_MSG_ID_PARAM_SET: + { // Drop on even milliseconds - if (QGC::groundTimeMilliseconds() % 2 == 0) { + if (QGC::groundTimeMilliseconds() % 2 == 0) + { qDebug() << "SIMULATION RECEIVED COMMAND TO SET PARAMETER"; mavlink_param_set_t set; mavlink_msg_param_set_decode(&msg, &set); // if (set.target_system == systemId) // { QString key = QString((char*)set.param_id); - if (onboardParams.contains(key)) { + if (onboardParams.contains(key)) + { onboardParams.remove(key); onboardParams.insert(key, set.param_value); @@ -809,13 +816,15 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) } } break; - case MAVLINK_MSG_ID_PARAM_REQUEST_READ: { + case MAVLINK_MSG_ID_PARAM_REQUEST_READ: + { qDebug() << "SIMULATION RECEIVED COMMAND TO SEND PARAMETER"; mavlink_param_request_read_t read; mavlink_msg_param_request_read_decode(&msg, &read); QByteArray bytes((char*)read.param_id, MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN); QString key = QString(bytes); - if (onboardParams.contains(key)) { + if (onboardParams.contains(key)) + { float paramValue = onboardParams.value(key); // Pack message and get size of encoded byte string @@ -826,7 +835,9 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) memcpy(stream+streampointer,buffer, bufferlength); streampointer+=bufferlength; //qDebug() << "Sending PARAM" << key; - } else if (read.param_index < onboardParams.size()) { + } + else if (read.param_index < onboardParams.size()) + { key = onboardParams.keys().at(read.param_index); float paramValue = onboardParams.value(key); @@ -842,8 +853,6 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) } break; } - - } unsigned char v=data[i]; fprintf(stderr,"%02x ", v); @@ -851,7 +860,8 @@ void MAVLinkSimulationLink::writeBytes(const char* data, qint64 size) fprintf(stderr,"\n"); readyBufferMutex.lock(); - for (int i = 0; i < streampointer; i++) { + for (int i = 0; i < streampointer; i++) + { readyBuffer.enqueue(*(stream + i)); } readyBufferMutex.unlock(); diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc index 25749d9..48c38a1 100644 --- a/src/uas/UAS.cc +++ b/src/uas/UAS.cc @@ -75,12 +75,12 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), pitch(0.0), yaw(0.0), statusTimeout(new QTimer(this)), -#if defined(QGC_PROTOBUF_ENABLED) && defined(QGC_USE_PIXHAWK_MESSAGES) + #if defined(QGC_PROTOBUF_ENABLED) && defined(QGC_USE_PIXHAWK_MESSAGES) receivedPointCloudTimestamp(0.0), receivedRGBDImageTimestamp(0.0), receivedObstacleListTimestamp(0.0), receivedPathTimestamp(0.0), -#endif + #endif paramsOnceRequested(false), airframe(QGC_AIRFRAME_EASYSTAR), attitudeKnown(false), @@ -202,25 +202,25 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) switch (message.compid) { case MAV_COMP_ID_ALL: - { - componentName = "ANONYMOUS"; - break; - } + { + componentName = "ANONYMOUS"; + break; + } case MAV_COMP_ID_IMU: - { - componentName = "IMU #1"; - break; - } + { + componentName = "IMU #1"; + break; + } case MAV_COMP_ID_CAMERA: - { - componentName = "CAMERA"; - break; - } + { + componentName = "CAMERA"; + break; + } case MAV_COMP_ID_MISSIONPLANNER: - { - componentName = "MISSIONPLANNER"; - break; - } + { + componentName = "MISSIONPLANNER"; + break; + } } components.insert(message.compid, componentName); @@ -274,6 +274,10 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) { case MAVLINK_MSG_ID_HEARTBEAT: { + if (multiComponentSourceDetected && wrongComponent) + { + break; + } lastHeartbeat = QGC::groundTimeUsecs(); emit heartbeat(this); mavlink_heartbeat_t state; @@ -381,338 +385,338 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) GAudioOutput::instance()->say(audiostring.toLower()); } -// if (state.system_status == MAV_STATE_POWEROFF) -// { -// emit systemRemoved(this); -// emit systemRemoved(); -// } -} + // if (state.system_status == MAV_STATE_POWEROFF) + // { + // emit systemRemoved(this); + // emit systemRemoved(); + // } + } break; -// case MAVLINK_MSG_ID_NAMED_VALUE_FLOAT: -// case MAVLINK_MSG_ID_NAMED_VALUE_INT: -// // Receive named value message -// receiveMessageNamedValue(message); -// break; + // case MAVLINK_MSG_ID_NAMED_VALUE_FLOAT: + // case MAVLINK_MSG_ID_NAMED_VALUE_INT: + // // Receive named value message + // receiveMessageNamedValue(message); + // break; case MAVLINK_MSG_ID_SYS_STATUS: { - if (multiComponentSourceDetected && message.compid != MAV_COMP_ID_IMU_2) - { - break; - } - mavlink_sys_status_t state; - mavlink_msg_sys_status_decode(&message, &state); - - emit loadChanged(this,state.load/10.0f); + if (multiComponentSourceDetected && wrongComponent) + { + break; + } + mavlink_sys_status_t state; + mavlink_msg_sys_status_decode(&message, &state); - currentVoltage = state.voltage_battery/1000.0f; - lpVoltage = filterVoltage(currentVoltage); + emit loadChanged(this,state.load/10.0f); - if (startVoltage == 0) startVoltage = currentVoltage; - timeRemaining = calculateTimeRemaining(); - if (!batteryRemainingEstimateEnabled && chargeLevel != -1) - { - chargeLevel = state.battery_remaining; - } - //qDebug() << "Voltage: " << currentVoltage << " Chargelevel: " << getChargeLevel() << " Time remaining " << timeRemaining; - emit batteryChanged(this, lpVoltage, getChargeLevel(), timeRemaining); - emit voltageChanged(message.sysid, state.voltage_battery/1000); + currentVoltage = state.voltage_battery/1000.0f; + lpVoltage = filterVoltage(currentVoltage); - // LOW BATTERY ALARM - if (lpVoltage < warnVoltage) - { - startLowBattAlarm(); - } - else - { - stopLowBattAlarm(); - } + if (startVoltage == 0) startVoltage = currentVoltage; + timeRemaining = calculateTimeRemaining(); + if (!batteryRemainingEstimateEnabled && chargeLevel != -1) + { + chargeLevel = state.battery_remaining; + } + //qDebug() << "Voltage: " << currentVoltage << " Chargelevel: " << getChargeLevel() << " Time remaining " << timeRemaining; + emit batteryChanged(this, lpVoltage, getChargeLevel(), timeRemaining); + emit voltageChanged(message.sysid, state.voltage_battery/1000); - // COMMUNICATIONS DROP RATE - // FIXME - emit dropRateChanged(this->getUASID(), state.drop_rate_comm/10000.0f); + // LOW BATTERY ALARM + if (lpVoltage < warnVoltage) + { + startLowBattAlarm(); } - break; - case MAVLINK_MSG_ID_ATTITUDE: + else { - if (wrongComponent) break; - - mavlink_attitude_t attitude; - mavlink_msg_attitude_decode(&message, &attitude); - quint64 time = getUnixReferenceTime(attitude.time_boot_ms); - lastAttitude = time; - roll = QGC::limitAngleToPMPIf(attitude.roll); - pitch = QGC::limitAngleToPMPIf(attitude.pitch); - yaw = QGC::limitAngleToPMPIf(attitude.yaw); - -// // Emit in angles - -// // Convert yaw angle to compass value -// // in 0 - 360 deg range -// float compass = (yaw/M_PI)*180.0+360.0f; -// if (compass > -10000 && compass < 10000) -// { -// while (compass > 360.0f) { -// compass -= 360.0f; -// } -// } -// else -// { -// // Set to 0, since it is an invalid value -// compass = 0.0f; -// } - - attitudeKnown = true; - emit attitudeChanged(this, roll, pitch, yaw, time); - emit attitudeChanged(this, message.compid, roll, pitch, yaw, time); - emit attitudeSpeedChanged(uasId, attitude.rollspeed, attitude.pitchspeed, attitude.yawspeed, time); + stopLowBattAlarm(); } + + // COMMUNICATIONS DROP RATE + // FIXME + emit dropRateChanged(this->getUASID(), state.drop_rate_comm/10000.0f); + } + break; + case MAVLINK_MSG_ID_ATTITUDE: + { + if (wrongComponent) break; + + mavlink_attitude_t attitude; + mavlink_msg_attitude_decode(&message, &attitude); + quint64 time = getUnixReferenceTime(attitude.time_boot_ms); + lastAttitude = time; + roll = QGC::limitAngleToPMPIf(attitude.roll); + pitch = QGC::limitAngleToPMPIf(attitude.pitch); + yaw = QGC::limitAngleToPMPIf(attitude.yaw); + + // // Emit in angles + + // // Convert yaw angle to compass value + // // in 0 - 360 deg range + // float compass = (yaw/M_PI)*180.0+360.0f; + // if (compass > -10000 && compass < 10000) + // { + // while (compass > 360.0f) { + // compass -= 360.0f; + // } + // } + // else + // { + // // Set to 0, since it is an invalid value + // compass = 0.0f; + // } + + attitudeKnown = true; + emit attitudeChanged(this, roll, pitch, yaw, time); + emit attitudeChanged(this, message.compid, roll, pitch, yaw, time); + emit attitudeSpeedChanged(uasId, attitude.rollspeed, attitude.pitchspeed, attitude.yawspeed, time); + } break; case MAVLINK_MSG_ID_HIL_CONTROLS: - { - mavlink_hil_controls_t hil; - mavlink_msg_hil_controls_decode(&message, &hil); - emit hilControlsChanged(hil.time_usec, hil.roll_ailerons, hil.pitch_elevator, hil.yaw_rudder, hil.throttle, hil.mode, hil.nav_mode); - } + { + mavlink_hil_controls_t hil; + mavlink_msg_hil_controls_decode(&message, &hil); + emit hilControlsChanged(hil.time_usec, hil.roll_ailerons, hil.pitch_elevator, hil.yaw_rudder, hil.throttle, hil.mode, hil.nav_mode); + } break; case MAVLINK_MSG_ID_VFR_HUD: - { - mavlink_vfr_hud_t hud; - mavlink_msg_vfr_hud_decode(&message, &hud); - quint64 time = getUnixTime(); - // Display updated values - emit thrustChanged(this, hud.throttle/100.0); - - if (!attitudeKnown) - { - yaw = QGC::limitAngleToPMPId((((double)hud.heading-180.0)/360.0)*M_PI); - emit attitudeChanged(this, roll, pitch, yaw, time); - } + { + mavlink_vfr_hud_t hud; + mavlink_msg_vfr_hud_decode(&message, &hud); + quint64 time = getUnixTime(); + // Display updated values + emit thrustChanged(this, hud.throttle/100.0); - emit altitudeChanged(uasId, hud.alt); - emit speedChanged(this, hud.airspeed, 0.0f, hud.climb, time); + if (!attitudeKnown) + { + yaw = QGC::limitAngleToPMPId((((double)hud.heading-180.0)/360.0)*M_PI); + emit attitudeChanged(this, roll, pitch, yaw, time); } + + emit altitudeChanged(uasId, hud.alt); + emit speedChanged(this, hud.airspeed, 0.0f, hud.climb, time); + } break; case MAVLINK_MSG_ID_LOCAL_POSITION_NED: //std::cerr << std::endl; //std::cerr << "Decoded attitude message:" << " roll: " << std::dec << mavlink_msg_attitude_get_roll(message.payload) << " pitch: " << mavlink_msg_attitude_get_pitch(message.payload) << " yaw: " << mavlink_msg_attitude_get_yaw(message.payload) << std::endl; - { - mavlink_local_position_ned_t pos; - mavlink_msg_local_position_ned_decode(&message, &pos); - quint64 time = getUnixTime(pos.time_boot_ms); + { + mavlink_local_position_ned_t pos; + mavlink_msg_local_position_ned_decode(&message, &pos); + quint64 time = getUnixTime(pos.time_boot_ms); - // Emit position always with component ID - emit localPositionChanged(this, message.compid, pos.x, pos.y, pos.z, time); + // Emit position always with component ID + emit localPositionChanged(this, message.compid, pos.x, pos.y, pos.z, time); - if (!wrongComponent) - { + if (!wrongComponent) + { - localX = pos.x; - localY = pos.y; - localZ = pos.z; + localX = pos.x; + localY = pos.y; + localZ = pos.z; - // Emit + // Emit - emit localPositionChanged(this, pos.x, pos.y, pos.z, time); - emit speedChanged(this, pos.vx, pos.vy, pos.vz, time); + emit localPositionChanged(this, pos.x, pos.y, pos.z, time); + emit speedChanged(this, pos.vx, pos.vy, pos.vz, time); - // Set internal state - if (!positionLock) { - // If position was not locked before, notify positive - GAudioOutput::instance()->notifyPositive(); - } - positionLock = true; - isLocalPositionKnown = true; + // Set internal state + if (!positionLock) { + // If position was not locked before, notify positive + GAudioOutput::instance()->notifyPositive(); } + positionLock = true; + isLocalPositionKnown = true; } + } break; case MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE: - { - mavlink_global_vision_position_estimate_t pos; - mavlink_msg_global_vision_position_estimate_decode(&message, &pos); - quint64 time = getUnixTime(pos.usec); - emit localPositionChanged(this, message.compid, pos.x, pos.y, pos.z, time); - emit attitudeChanged(this, message.compid, pos.roll, pos.pitch, pos.yaw, time); - } + { + mavlink_global_vision_position_estimate_t pos; + mavlink_msg_global_vision_position_estimate_decode(&message, &pos); + quint64 time = getUnixTime(pos.usec); + emit localPositionChanged(this, message.compid, pos.x, pos.y, pos.z, time); + emit attitudeChanged(this, message.compid, pos.roll, pos.pitch, pos.yaw, time); + } break; case MAVLINK_MSG_ID_GLOBAL_POSITION_INT: //std::cerr << std::endl; //std::cerr << "Decoded attitude message:" << " roll: " << std::dec << mavlink_msg_attitude_get_roll(message.payload) << " pitch: " << mavlink_msg_attitude_get_pitch(message.payload) << " yaw: " << mavlink_msg_attitude_get_yaw(message.payload) << std::endl; + { + mavlink_global_position_int_t pos; + mavlink_msg_global_position_int_decode(&message, &pos); + quint64 time = getUnixTime(); + latitude = pos.lat/(double)1E7; + longitude = pos.lon/(double)1E7; + altitude = pos.alt/1000.0; + speedX = pos.vx/100.0; + speedY = pos.vy/100.0; + speedZ = pos.vz/100.0; + emit globalPositionChanged(this, latitude, longitude, altitude, time); + emit speedChanged(this, speedX, speedY, speedZ, time); + // Set internal state + if (!positionLock) + { + // If position was not locked before, notify positive + GAudioOutput::instance()->notifyPositive(); + } + positionLock = true; + isGlobalPositionKnown = true; + //TODO fix this hack for forwarding of global position for patch antenna tracking + forwardMessage(message); + } + break; + case MAVLINK_MSG_ID_GPS_RAW_INT: + { + mavlink_gps_raw_int_t pos; + mavlink_msg_gps_raw_int_decode(&message, &pos); + + // SANITY CHECK + // only accept values in a realistic range + // quint64 time = getUnixTime(pos.time_usec); + quint64 time = getUnixTime(pos.time_usec); + + if (pos.fix_type > 2) { - mavlink_global_position_int_t pos; - mavlink_msg_global_position_int_decode(&message, &pos); - quint64 time = getUnixTime(); + emit globalPositionChanged(this, pos.lat/(double)1E7, pos.lon/(double)1E7, pos.alt/1000.0, time); latitude = pos.lat/(double)1E7; longitude = pos.lon/(double)1E7; altitude = pos.alt/1000.0; - speedX = pos.vx/100.0; - speedY = pos.vy/100.0; - speedZ = pos.vz/100.0; - emit globalPositionChanged(this, latitude, longitude, altitude, time); - emit speedChanged(this, speedX, speedY, speedZ, time); - // Set internal state - if (!positionLock) - { - // If position was not locked before, notify positive - GAudioOutput::instance()->notifyPositive(); - } positionLock = true; isGlobalPositionKnown = true; - //TODO fix this hack for forwarding of global position for patch antenna tracking - forwardMessage(message); - } - break; - case MAVLINK_MSG_ID_GPS_RAW_INT: - { - mavlink_gps_raw_int_t pos; - mavlink_msg_gps_raw_int_decode(&message, &pos); - // SANITY CHECK - // only accept values in a realistic range - // quint64 time = getUnixTime(pos.time_usec); - quint64 time = getUnixTime(pos.time_usec); - - if (pos.fix_type > 2) + // Check for NaN + int alt = pos.alt; + if (!isnan(alt) && !isinf(alt)) { - emit globalPositionChanged(this, pos.lat/(double)1E7, pos.lon/(double)1E7, pos.alt/1000.0, time); - latitude = pos.lat/(double)1E7; - longitude = pos.lon/(double)1E7; - altitude = pos.alt/1000.0; - positionLock = true; - isGlobalPositionKnown = true; - - // Check for NaN - int alt = pos.alt; - if (!isnan(alt) && !isinf(alt)) - { - alt = 0; - //emit textMessageReceived(uasId, message.compid, 255, "GCS ERROR: RECEIVED NaN or Inf FOR ALTITUDE"); - } - // FIXME REMOVE LATER emit valueChanged(uasId, "altitude", "m", pos.alt/(double)1E3, time); - // Smaller than threshold and not NaN + alt = 0; + //emit textMessageReceived(uasId, message.compid, 255, "GCS ERROR: RECEIVED NaN or Inf FOR ALTITUDE"); + } + // FIXME REMOVE LATER emit valueChanged(uasId, "altitude", "m", pos.alt/(double)1E3, time); + // Smaller than threshold and not NaN - float vel = pos.vel/100.0f; + float vel = pos.vel/100.0f; - if (vel < 1000000 && !isnan(vel) && !isinf(vel)) - { - // FIXME REMOVE LATER emit valueChanged(uasId, "speed", "m/s", vel, time); - //qDebug() << "GOT GPS RAW"; - // emit speedChanged(this, (double)pos.v, 0.0, 0.0, time); - } - else - { - emit textMessageReceived(uasId, message.compid, 255, QString("GCS ERROR: RECEIVED INVALID SPEED OF %1 m/s").arg(vel)); - } + if (vel < 1000000 && !isnan(vel) && !isinf(vel)) + { + // FIXME REMOVE LATER emit valueChanged(uasId, "speed", "m/s", vel, time); + //qDebug() << "GOT GPS RAW"; + // emit speedChanged(this, (double)pos.v, 0.0, 0.0, time); + } + else + { + emit textMessageReceived(uasId, message.compid, 255, QString("GCS ERROR: RECEIVED INVALID SPEED OF %1 m/s").arg(vel)); } } + } break; case MAVLINK_MSG_ID_GPS_STATUS: + { + mavlink_gps_status_t pos; + mavlink_msg_gps_status_decode(&message, &pos); + for(int i = 0; i < (int)pos.satellites_visible; i++) { - mavlink_gps_status_t pos; - mavlink_msg_gps_status_decode(&message, &pos); - for(int i = 0; i < (int)pos.satellites_visible; i++) - { - emit gpsSatelliteStatusChanged(uasId, (unsigned char)pos.satellite_prn[i], (unsigned char)pos.satellite_elevation[i], (unsigned char)pos.satellite_azimuth[i], (unsigned char)pos.satellite_snr[i], static_cast(pos.satellite_used[i])); - } + emit gpsSatelliteStatusChanged(uasId, (unsigned char)pos.satellite_prn[i], (unsigned char)pos.satellite_elevation[i], (unsigned char)pos.satellite_azimuth[i], (unsigned char)pos.satellite_snr[i], static_cast(pos.satellite_used[i])); } + } break; case MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN: - { - mavlink_gps_global_origin_t pos; - mavlink_msg_gps_global_origin_decode(&message, &pos); - emit homePositionChanged(uasId, pos.latitude, pos.longitude, pos.altitude); - } + { + mavlink_gps_global_origin_t pos; + mavlink_msg_gps_global_origin_decode(&message, &pos); + emit homePositionChanged(uasId, pos.latitude, pos.longitude, pos.altitude); + } break; case MAVLINK_MSG_ID_RC_CHANNELS_RAW: - { - mavlink_rc_channels_raw_t channels; - mavlink_msg_rc_channels_raw_decode(&message, &channels); - emit remoteControlRSSIChanged(channels.rssi/255.0f); - emit remoteControlChannelRawChanged(0, channels.chan1_raw); - emit remoteControlChannelRawChanged(1, channels.chan2_raw); - emit remoteControlChannelRawChanged(2, channels.chan3_raw); - emit remoteControlChannelRawChanged(3, channels.chan4_raw); - emit remoteControlChannelRawChanged(4, channels.chan5_raw); - emit remoteControlChannelRawChanged(5, channels.chan6_raw); - emit remoteControlChannelRawChanged(6, channels.chan7_raw); - emit remoteControlChannelRawChanged(7, channels.chan8_raw); - } + { + mavlink_rc_channels_raw_t channels; + mavlink_msg_rc_channels_raw_decode(&message, &channels); + emit remoteControlRSSIChanged(channels.rssi/255.0f); + emit remoteControlChannelRawChanged(0, channels.chan1_raw); + emit remoteControlChannelRawChanged(1, channels.chan2_raw); + emit remoteControlChannelRawChanged(2, channels.chan3_raw); + emit remoteControlChannelRawChanged(3, channels.chan4_raw); + emit remoteControlChannelRawChanged(4, channels.chan5_raw); + emit remoteControlChannelRawChanged(5, channels.chan6_raw); + emit remoteControlChannelRawChanged(6, channels.chan7_raw); + emit remoteControlChannelRawChanged(7, channels.chan8_raw); + } break; case MAVLINK_MSG_ID_RC_CHANNELS_SCALED: - { - mavlink_rc_channels_scaled_t channels; - mavlink_msg_rc_channels_scaled_decode(&message, &channels); - emit remoteControlRSSIChanged(channels.rssi/255.0f); - emit remoteControlChannelScaledChanged(0, channels.chan1_scaled/10000.0f); - emit remoteControlChannelScaledChanged(1, channels.chan2_scaled/10000.0f); - emit remoteControlChannelScaledChanged(2, channels.chan3_scaled/10000.0f); - emit remoteControlChannelScaledChanged(3, channels.chan4_scaled/10000.0f); - emit remoteControlChannelScaledChanged(4, channels.chan5_scaled/10000.0f); - emit remoteControlChannelScaledChanged(5, channels.chan6_scaled/10000.0f); - emit remoteControlChannelScaledChanged(6, channels.chan7_scaled/10000.0f); - emit remoteControlChannelScaledChanged(7, channels.chan8_scaled/10000.0f); - } + { + mavlink_rc_channels_scaled_t channels; + mavlink_msg_rc_channels_scaled_decode(&message, &channels); + emit remoteControlRSSIChanged(channels.rssi/255.0f); + emit remoteControlChannelScaledChanged(0, channels.chan1_scaled/10000.0f); + emit remoteControlChannelScaledChanged(1, channels.chan2_scaled/10000.0f); + emit remoteControlChannelScaledChanged(2, channels.chan3_scaled/10000.0f); + emit remoteControlChannelScaledChanged(3, channels.chan4_scaled/10000.0f); + emit remoteControlChannelScaledChanged(4, channels.chan5_scaled/10000.0f); + emit remoteControlChannelScaledChanged(5, channels.chan6_scaled/10000.0f); + emit remoteControlChannelScaledChanged(6, channels.chan7_scaled/10000.0f); + emit remoteControlChannelScaledChanged(7, channels.chan8_scaled/10000.0f); + } break; case MAVLINK_MSG_ID_PARAM_VALUE: + { + mavlink_param_value_t value; + mavlink_msg_param_value_decode(&message, &value); + QByteArray bytes(value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN); + QString parameterName = QString(bytes); + int component = message.compid; + mavlink_param_union_t val; + val.param_float = value.param_value; + val.type = value.param_type; + + // Insert component if necessary + if (!parameters.contains(component)) { - mavlink_param_value_t value; - mavlink_msg_param_value_decode(&message, &value); - QByteArray bytes(value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN); - QString parameterName = QString(bytes); - int component = message.compid; - mavlink_param_union_t val; - val.param_float = value.param_value; - val.type = value.param_type; - - // Insert component if necessary - if (!parameters.contains(component)) - { - parameters.insert(component, new QMap()); - } + parameters.insert(component, new QMap()); + } - // Insert parameter into registry - if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName); + // Insert parameter into registry + if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName); - // Insert with correct type - switch (value.param_type) - { - case MAVLINK_TYPE_FLOAT: - { - // Variant - QVariant param(val.param_float); - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAVLINK_TYPE_UINT32_T: - { - // Variant - QVariant param(val.param_uint32); - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAVLINK_TYPE_INT32_T: - { - // Variant - QVariant param(val.param_int32); - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - qDebug() << "RECEIVED PARAM:" << param; - } - break; - default: - qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << value.param_type; - } + // Insert with correct type + switch (value.param_type) + { + case MAVLINK_TYPE_FLOAT: + { + // Variant + QVariant param(val.param_float); + parameters.value(component)->insert(parameterName, param); + // Emit change + emit parameterChanged(uasId, message.compid, parameterName, param); + emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); + qDebug() << "RECEIVED PARAM:" << param; } + break; + case MAVLINK_TYPE_UINT32_T: + { + // Variant + QVariant param(val.param_uint32); + parameters.value(component)->insert(parameterName, param); + // Emit change + emit parameterChanged(uasId, message.compid, parameterName, param); + emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); + qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAVLINK_TYPE_INT32_T: + { + // Variant + QVariant param(val.param_int32); + parameters.value(component)->insert(parameterName, param); + // Emit change + emit parameterChanged(uasId, message.compid, parameterName, param); + emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); + qDebug() << "RECEIVED PARAM:" << param; + } + break; + default: + qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << value.param_type; + } + } break; case MAVLINK_MSG_ID_COMMAND_ACK: mavlink_command_ack_t ack; @@ -727,268 +731,268 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) } break; case MAVLINK_MSG_ID_ROLL_PITCH_YAW_THRUST_SETPOINT: - { - mavlink_roll_pitch_yaw_thrust_setpoint_t out; - mavlink_msg_roll_pitch_yaw_thrust_setpoint_decode(&message, &out); - quint64 time = getUnixTimeFromMs(out.time_boot_ms); - emit attitudeThrustSetPointChanged(this, out.roll, out.pitch, out.yaw, out.thrust, time); - } + { + mavlink_roll_pitch_yaw_thrust_setpoint_t out; + mavlink_msg_roll_pitch_yaw_thrust_setpoint_decode(&message, &out); + quint64 time = getUnixTimeFromMs(out.time_boot_ms); + emit attitudeThrustSetPointChanged(this, out.roll, out.pitch, out.yaw, out.thrust, time); + } break; case MAVLINK_MSG_ID_MISSION_COUNT: + { + mavlink_mission_count_t wpc; + mavlink_msg_mission_count_decode(&message, &wpc); + if (wpc.target_system == mavlink->getSystemId()) { - mavlink_mission_count_t wpc; - mavlink_msg_mission_count_decode(&message, &wpc); - if (wpc.target_system == mavlink->getSystemId()) - { - waypointManager.handleWaypointCount(message.sysid, message.compid, wpc.count); - } - else - { - qDebug() << "Got waypoint message, but was not for me"; - } + waypointManager.handleWaypointCount(message.sysid, message.compid, wpc.count); } + else + { + qDebug() << "Got waypoint message, but was not for me"; + } + } break; case MAVLINK_MSG_ID_MISSION_ITEM: + { + mavlink_mission_item_t wp; + mavlink_msg_mission_item_decode(&message, &wp); + //qDebug() << "got waypoint (" << wp.seq << ") from ID " << message.sysid << " x=" << wp.x << " y=" << wp.y << " z=" << wp.z; + if(wp.target_system == mavlink->getSystemId()) { - mavlink_mission_item_t wp; - mavlink_msg_mission_item_decode(&message, &wp); - //qDebug() << "got waypoint (" << wp.seq << ") from ID " << message.sysid << " x=" << wp.x << " y=" << wp.y << " z=" << wp.z; - if(wp.target_system == mavlink->getSystemId()) - { - waypointManager.handleWaypoint(message.sysid, message.compid, &wp); - } - else - { - qDebug() << "Got waypoint message, but was not for me"; - } + waypointManager.handleWaypoint(message.sysid, message.compid, &wp); + } + else + { + qDebug() << "Got waypoint message, but was not for me"; } + } break; case MAVLINK_MSG_ID_MISSION_ACK: + { + mavlink_mission_ack_t wpa; + mavlink_msg_mission_ack_decode(&message, &wpa); + if(wpa.target_system == mavlink->getSystemId() && wpa.target_component == mavlink->getComponentId()) { - mavlink_mission_ack_t wpa; - mavlink_msg_mission_ack_decode(&message, &wpa); - if(wpa.target_system == mavlink->getSystemId() && wpa.target_component == mavlink->getComponentId()) - { - waypointManager.handleWaypointAck(message.sysid, message.compid, &wpa); - } + waypointManager.handleWaypointAck(message.sysid, message.compid, &wpa); } + } break; case MAVLINK_MSG_ID_MISSION_REQUEST: + { + mavlink_mission_request_t wpr; + mavlink_msg_mission_request_decode(&message, &wpr); + if(wpr.target_system == mavlink->getSystemId()) { - mavlink_mission_request_t wpr; - mavlink_msg_mission_request_decode(&message, &wpr); - if(wpr.target_system == mavlink->getSystemId()) - { - waypointManager.handleWaypointRequest(message.sysid, message.compid, &wpr); - } - else - { - qDebug() << "Got waypoint message, but was not for me"; - } + waypointManager.handleWaypointRequest(message.sysid, message.compid, &wpr); + } + else + { + qDebug() << "Got waypoint message, but was not for me"; } + } break; case MAVLINK_MSG_ID_MISSION_ITEM_REACHED: - { - mavlink_mission_item_reached_t wpr; - mavlink_msg_mission_item_reached_decode(&message, &wpr); - waypointManager.handleWaypointReached(message.sysid, message.compid, &wpr); - QString text = QString("System %1 reached waypoint %2").arg(getUASName()).arg(wpr.seq); - GAudioOutput::instance()->say(text); - emit textMessageReceived(message.sysid, message.compid, 0, text); - } + { + mavlink_mission_item_reached_t wpr; + mavlink_msg_mission_item_reached_decode(&message, &wpr); + waypointManager.handleWaypointReached(message.sysid, message.compid, &wpr); + QString text = QString("System %1 reached waypoint %2").arg(getUASName()).arg(wpr.seq); + GAudioOutput::instance()->say(text); + emit textMessageReceived(message.sysid, message.compid, 0, text); + } break; case MAVLINK_MSG_ID_MISSION_CURRENT: - { - mavlink_mission_current_t wpc; - mavlink_msg_mission_current_decode(&message, &wpc); - waypointManager.handleWaypointCurrent(message.sysid, message.compid, &wpc); - } + { + mavlink_mission_current_t wpc; + mavlink_msg_mission_current_decode(&message, &wpc); + waypointManager.handleWaypointCurrent(message.sysid, message.compid, &wpc); + } break; case MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT: - { - mavlink_local_position_setpoint_t p; - mavlink_msg_local_position_setpoint_decode(&message, &p); - emit positionSetPointsChanged(uasId, p.x, p.y, p.z, p.yaw, QGC::groundTimeUsecs()); - } + { + mavlink_local_position_setpoint_t p; + mavlink_msg_local_position_setpoint_decode(&message, &p); + emit positionSetPointsChanged(uasId, p.x, p.y, p.z, p.yaw, QGC::groundTimeUsecs()); + } break; case MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT: - { - mavlink_set_local_position_setpoint_t p; - mavlink_msg_set_local_position_setpoint_decode(&message, &p); - emit userPositionSetPointsChanged(uasId, p.x, p.y, p.z, p.yaw); - } + { + mavlink_set_local_position_setpoint_t p; + mavlink_msg_set_local_position_setpoint_decode(&message, &p); + emit userPositionSetPointsChanged(uasId, p.x, p.y, p.z, p.yaw); + } break; case MAVLINK_MSG_ID_STATUSTEXT: - { - QByteArray b; - b.resize(MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN); - mavlink_msg_statustext_get_text(&message, b.data()); - //b.append('\0'); - QString text = QString(b); - int severity = mavlink_msg_statustext_get_severity(&message); - //qDebug() << "RECEIVED STATUS:" << text;false - //emit statusTextReceived(severity, text); - emit textMessageReceived(uasId, message.compid, severity, text); - } + { + QByteArray b; + b.resize(MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN); + mavlink_msg_statustext_get_text(&message, b.data()); + //b.append('\0'); + QString text = QString(b); + int severity = mavlink_msg_statustext_get_severity(&message); + //qDebug() << "RECEIVED STATUS:" << text;false + //emit statusTextReceived(severity, text); + emit textMessageReceived(uasId, message.compid, severity, text); + } break; #ifdef MAVLINK_ENABLED_PIXHAWK case MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE: - { - qDebug() << "RECIEVED ACK TO GET IMAGE"; - mavlink_data_transmission_handshake_t p; - mavlink_msg_data_transmission_handshake_decode(&message, &p); - imageSize = p.size; - imagePackets = p.packets; - imagePayload = p.payload; - imageQuality = p.jpg_quality; - imageType = p.type; - imageWidth = p.width; - imageHeight = p.height; - imageStart = QGC::groundTimeMilliseconds(); - } + { + qDebug() << "RECIEVED ACK TO GET IMAGE"; + mavlink_data_transmission_handshake_t p; + mavlink_msg_data_transmission_handshake_decode(&message, &p); + imageSize = p.size; + imagePackets = p.packets; + imagePayload = p.payload; + imageQuality = p.jpg_quality; + imageType = p.type; + imageWidth = p.width; + imageHeight = p.height; + imageStart = QGC::groundTimeMilliseconds(); + } break; case MAVLINK_MSG_ID_ENCAPSULATED_DATA: - { - mavlink_encapsulated_data_t img; - mavlink_msg_encapsulated_data_decode(&message, &img); - int seq = img.seqnr; - int pos = seq * imagePayload; + { + mavlink_encapsulated_data_t img; + mavlink_msg_encapsulated_data_decode(&message, &img); + int seq = img.seqnr; + int pos = seq * imagePayload; - // Check if we have a valid transaction - if (imagePackets == 0) - { - // NO VALID TRANSACTION - ABORT - // Restart statemachine - imagePacketsArrived = 0; - } + // Check if we have a valid transaction + if (imagePackets == 0) + { + // NO VALID TRANSACTION - ABORT + // Restart statemachine + imagePacketsArrived = 0; + } - for (int i = 0; i < imagePayload; ++i) - { - if (pos <= imageSize) { - imageRecBuffer[pos] = img.data[i]; - } - ++pos; + for (int i = 0; i < imagePayload; ++i) + { + if (pos <= imageSize) { + imageRecBuffer[pos] = img.data[i]; } + ++pos; + } - ++imagePacketsArrived; + ++imagePacketsArrived; - // emit signal if all packets arrived - if ((imagePacketsArrived >= imagePackets)) - { - // Restart statemachine - imagePacketsArrived = 0; - emit imageReady(this); - qDebug() << "imageReady emitted. all packets arrived"; - } + // emit signal if all packets arrived + if ((imagePacketsArrived >= imagePackets)) + { + // Restart statemachine + imagePacketsArrived = 0; + emit imageReady(this); + qDebug() << "imageReady emitted. all packets arrived"; } + } break; #endif -// case MAVLINK_MSG_ID_OBJECT_DETECTION_EVENT: -// { -// mavlink_object_detection_event_t event; -// mavlink_msg_object_detection_event_decode(&message, &event); -// QString str(event.name); -// emit objectDetected(event.time, event.object_id, event.type, str, event.quality, event.bearing, event.distance); -// } -// break; - // WILL BE ENABLED ONCE MESSAGE IS IN COMMON MESSAGE SET -// case MAVLINK_MSG_ID_MEMORY_VECT: -// { -// mavlink_memory_vect_t vect; -// mavlink_msg_memory_vect_decode(&message, &vect); -// QString str("mem_%1"); -// quint64 time = getUnixTime(0); -// int16_t *mem0 = (int16_t *)&vect.value[0]; -// uint16_t *mem1 = (uint16_t *)&vect.value[0]; -// int32_t *mem2 = (int32_t *)&vect.value[0]; -// // uint32_t *mem3 = (uint32_t *)&vect.value[0]; causes overload problem -// float *mem4 = (float *)&vect.value[0]; -// if ( vect.ver == 0) vect.type = 0, vect.ver = 1; else ; -// if ( vect.ver == 1) -// { -// switch (vect.type) { -// default: -// case 0: -// for (int i = 0; i < 16; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "i16", mem0[i], time); -// break; -// case 1: -// for (int i = 0; i < 16; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "ui16", mem1[i], time); -// break; -// case 2: -// for (int i = 0; i < 16; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "Q15", (float)mem0[i]/32767.0, time); -// break; -// case 3: -// for (int i = 0; i < 16; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "1Q14", (float)mem0[i]/16383.0, time); -// break; -// case 4: -// for (int i = 0; i < 8; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time); -// break; -// case 5: -// for (int i = 0; i < 8; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time); -// break; -// case 6: -// for (int i = 0; i < 8; i++) -// // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "float", mem4[i], time); -// break; -// } -// } -// } -// break; + // case MAVLINK_MSG_ID_OBJECT_DETECTION_EVENT: + // { + // mavlink_object_detection_event_t event; + // mavlink_msg_object_detection_event_decode(&message, &event); + // QString str(event.name); + // emit objectDetected(event.time, event.object_id, event.type, str, event.quality, event.bearing, event.distance); + // } + // break; + // WILL BE ENABLED ONCE MESSAGE IS IN COMMON MESSAGE SET + // case MAVLINK_MSG_ID_MEMORY_VECT: + // { + // mavlink_memory_vect_t vect; + // mavlink_msg_memory_vect_decode(&message, &vect); + // QString str("mem_%1"); + // quint64 time = getUnixTime(0); + // int16_t *mem0 = (int16_t *)&vect.value[0]; + // uint16_t *mem1 = (uint16_t *)&vect.value[0]; + // int32_t *mem2 = (int32_t *)&vect.value[0]; + // // uint32_t *mem3 = (uint32_t *)&vect.value[0]; causes overload problem + // float *mem4 = (float *)&vect.value[0]; + // if ( vect.ver == 0) vect.type = 0, vect.ver = 1; else ; + // if ( vect.ver == 1) + // { + // switch (vect.type) { + // default: + // case 0: + // for (int i = 0; i < 16; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "i16", mem0[i], time); + // break; + // case 1: + // for (int i = 0; i < 16; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "ui16", mem1[i], time); + // break; + // case 2: + // for (int i = 0; i < 16; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "Q15", (float)mem0[i]/32767.0, time); + // break; + // case 3: + // for (int i = 0; i < 16; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*2)), "1Q14", (float)mem0[i]/16383.0, time); + // break; + // case 4: + // for (int i = 0; i < 8; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time); + // break; + // case 5: + // for (int i = 0; i < 8; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "i32", mem2[i], time); + // break; + // case 6: + // for (int i = 0; i < 8; i++) + // // FIXME REMOVE LATER emit valueChanged(uasId, str.arg(vect.address+(i*4)), "float", mem4[i], time); + // break; + // } + // } + // } + // break; #ifdef MAVLINK_ENABLED_UALBERTA case MAVLINK_MSG_ID_NAV_FILTER_BIAS: - { - mavlink_nav_filter_bias_t bias; - mavlink_msg_nav_filter_bias_decode(&message, &bias); - quint64 time = getUnixTime(); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[0]", "raw", bias.accel_0, time); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[1]", "raw", bias.accel_1, time); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[2]", "raw", bias.accel_2, time); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[0]", "raw", bias.gyro_0, time); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[1]", "raw", bias.gyro_1, time); - // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[2]", "raw", bias.gyro_2, time); - } + { + mavlink_nav_filter_bias_t bias; + mavlink_msg_nav_filter_bias_decode(&message, &bias); + quint64 time = getUnixTime(); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[0]", "raw", bias.accel_0, time); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[1]", "raw", bias.accel_1, time); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_f[2]", "raw", bias.accel_2, time); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[0]", "raw", bias.gyro_0, time); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[1]", "raw", bias.gyro_1, time); + // FIXME REMOVE LATER emit valueChanged(uasId, "b_w[2]", "raw", bias.gyro_2, time); + } break; case MAVLINK_MSG_ID_RADIO_CALIBRATION: - { - mavlink_radio_calibration_t radioMsg; - mavlink_msg_radio_calibration_decode(&message, &radioMsg); - QVector aileron; - QVector elevator; - QVector rudder; - QVector gyro; - QVector pitch; - QVector throttle; - - for (int i=0; i radioData = new RadioCalibrationData(aileron, elevator, rudder, gyro, pitch, throttle); - emit radioCalibrationReceived(radioData); - delete radioData; - } + { + mavlink_radio_calibration_t radioMsg; + mavlink_msg_radio_calibration_decode(&message, &radioMsg); + QVector aileron; + QVector elevator; + QVector rudder; + QVector gyro; + QVector pitch; + QVector throttle; + + for (int i=0; i radioData = new RadioCalibrationData(aileron, elevator, rudder, gyro, pitch, throttle); + emit radioCalibrationReceived(radioData); + delete radioData; + } break; #endif @@ -1006,17 +1010,17 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) case MAVLINK_MSG_ID_NAMED_VALUE_INT: break; default: + { + if (!unknownPackets.contains(message.msgid)) { - if (!unknownPackets.contains(message.msgid)) - { - unknownPackets.append(message.msgid); - QString errString = tr("UNABLE TO DECODE MESSAGE NUMBER %1").arg(message.msgid); - GAudioOutput::instance()->say(errString+tr(", please check console for details.")); - emit textMessageReceived(uasId, message.compid, 255, errString); - std::cout << "Unable to decode message from system " << std::dec << static_cast(message.sysid) << " with message id:" << static_cast(message.msgid) << std::endl; - //qDebug() << std::cerr << "Unable to decode message from system " << std::dec << static_cast(message.acid) << " with message id:" << static_cast(message.msgid) << std::endl; - } + unknownPackets.append(message.msgid); + QString errString = tr("UNABLE TO DECODE MESSAGE NUMBER %1").arg(message.msgid); + GAudioOutput::instance()->say(errString+tr(", please check console for details.")); + emit textMessageReceived(uasId, message.compid, 255, errString); + std::cout << "Unable to decode message from system " << std::dec << static_cast(message.sysid) << " with message id:" << static_cast(message.msgid) << std::endl; + //qDebug() << std::cerr << "Unable to decode message from system " << std::dec << static_cast(message.acid) << " with message id:" << static_cast(message.msgid) << std::endl; } + } break; } } @@ -1127,10 +1131,6 @@ void UAS::setHomePosition(double lat, double lon, double alt) mavlink_msg_command_long_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), 0, MAV_CMD_DO_SET_HOME, 1, 0, 0, 0, 0, lat, lon, alt); // Send message twice to increase chance that it reaches its goal sendMessage(msg); - // Wait 15 ms - QGC::SLEEP::usleep(15000); - // Send again - sendMessage(msg); // Send new home position to UAS mavlink_set_gps_global_origin_t home; @@ -1164,10 +1164,6 @@ void UAS::setLocalOriginAtCurrentGPSPosition() mavlink_msg_command_long_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), 0, MAV_CMD_DO_SET_HOME, 1, 1, 0, 0, 0, 0, 0, 0); // Send message twice to increase chance that it reaches its goal sendMessage(msg); - // Wait 15 ms - QGC::SLEEP::usleep(15000); - // Send again - sendMessage(msg); } } @@ -1272,9 +1268,9 @@ quint64 UAS::getUnixReferenceTime(quint64 time) #ifndef _MSC_VER else if (time < 1261440000000000LLU) #else - else if (time < 1261440000000000) + else if (time < 1261440000000000) #endif - { + { // qDebug() << "GEN time:" << time/1000 + onboardTimeOffset; if (onboardTimeOffset == 0) { @@ -1341,9 +1337,9 @@ quint64 UAS::getUnixTime(quint64 time) #ifndef _MSC_VER else if (time < 1261440000000000LLU) #else - else if (time < 1261440000000000) + else if (time < 1261440000000000) #endif - { + { // qDebug() << "GEN time:" << time/1000 + onboardTimeOffset; if (onboardTimeOffset == 0) { @@ -1457,14 +1453,14 @@ QString UAS::getNavModeText(int mode) { if (autopilot == MAV_AUTOPILOT_PIXHAWK) { - switch (mode) - { - case 0: - return QString("PREFLIGHT"); - break; - default: - return QString("UNKNOWN"); - } + switch (mode) + { + case 0: + return QString("PREFLIGHT"); + break; + default: + return QString("UNKNOWN"); + } } else if (autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA) { @@ -1568,9 +1564,9 @@ QImage UAS::getImage() imageType == MAVLINK_DATA_STREAM_IMG_PGM || imageType == MAVLINK_DATA_STREAM_IMG_PNG) { - if (!image.loadFromData(imageRecBuffer)) + if (!image.loadFromData(imageRecBuffer)) { - qDebug() << "Loading data from image buffer failed!"; + qDebug() << "Loading data from image buffer failed!"; } } // Restart statemachine @@ -1578,7 +1574,7 @@ QImage UAS::getImage() //imageRecBuffer.clear(); return image; #else - return QImage(); + return QImage(); #endif } @@ -1614,7 +1610,7 @@ quint64 UAS::getUptime() const } else { - return MG::TIME::getGroundTimeNow() - startTime; + return QGC::groundTimeMilliseconds() - startTime; } } @@ -1626,7 +1622,7 @@ int UAS::getCommunicationStatus() const void UAS::requestParameters() { mavlink_message_t msg; - mavlink_msg_param_request_list_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), 25); + mavlink_msg_param_request_list_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), MAV_COMP_ID_ALL); sendMessage(msg); } @@ -2088,7 +2084,7 @@ void UAS::setManualControlCommands(double roll, double pitch, double yaw, double sendMessage(message); qDebug() << __FILE__ << __LINE__ << ": SENT MANUAL CONTROL MESSAGE: roll" << manualRollAngle << " pitch: " << manualPitchAngle << " yaw: " << manualYawAngle << " thrust: " << manualThrust; - emit attitudeThrustSetPointChanged(this, roll, pitch, yaw, thrust, MG::TIME::getGroundTimeNow()); + emit attitudeThrustSetPointChanged(this, roll, pitch, yaw, thrust, QGC::groundTimeMilliseconds()); } else { @@ -2168,30 +2164,30 @@ bool UAS::emergencyKILL() { halt(); // FIXME MAVLINKV10PORTINGNEEDED -// bool result = false; -// QMessageBox msgBox; -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setText("EMERGENCY: KILL ALL MOTORS ON UAS"); -// msgBox.setInformativeText("Do you want to cut power on all systems?"); -// msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); -// msgBox.setDefaultButton(QMessageBox::Cancel); -// int ret = msgBox.exec(); - -// // Close the message box shortly after the click to prevent accidental clicks -// QTimer::singleShot(5000, &msgBox, SLOT(reject())); - - -// if (ret == QMessageBox::Yes) -// { -// mavlink_message_t msg; -// // TODO Replace MG System ID with static function call and allow to change ID in GUI -// mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU, (int)MAV_ACTION_EMCY_KILL); -// // Send message twice to increase chance of reception -// sendMessage(msg); -// sendMessage(msg); -// result = true; -// } -// return result; + // bool result = false; + // QMessageBox msgBox; + // msgBox.setIcon(QMessageBox::Critical); + // msgBox.setText("EMERGENCY: KILL ALL MOTORS ON UAS"); + // msgBox.setInformativeText("Do you want to cut power on all systems?"); + // msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + // msgBox.setDefaultButton(QMessageBox::Cancel); + // int ret = msgBox.exec(); + + // // Close the message box shortly after the click to prevent accidental clicks + // QTimer::singleShot(5000, &msgBox, SLOT(reject())); + + + // if (ret == QMessageBox::Yes) + // { + // mavlink_message_t msg; + // // TODO Replace MG System ID with static function call and allow to change ID in GUI + // mavlink_msg_action_pack(MG::SYSTEM::ID, MG::SYSTEM::COMPID, &msg, this->getUASID(), MAV_COMP_ID_IMU, (int)MAV_ACTION_EMCY_KILL); + // // Send message twice to increase chance of reception + // sendMessage(msg); + // sendMessage(msg); + // result = true; + // } + // return result; return false; } @@ -2227,8 +2223,8 @@ void UAS::enableHil(bool enable) * @param zacc Z acceleration (mg) */ void UAS::sendHilState(uint64_t time_us, float roll, float pitch, float yaw, float rollspeed, - float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, - int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) + float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, + int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) { mavlink_message_t msg; mavlink_msg_hil_state_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, time_us, roll, pitch, yaw, rollspeed, pitchspeed, yawspeed, lat, lon, alt, vx, vy, vz, xacc, yacc, zacc); @@ -2322,19 +2318,19 @@ QString UAS::getShortModeTextFor(int id) } if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_GUIDED) { - mode += "GUIDED"; + mode += "|GUID"; } if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_STABILIZE) { - mode += "STABILIZED"; + mode += "|STAB"; } if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_TEST) { - mode += "TEST"; + mode += "|TEST"; } if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_MANUAL) { - mode += "MANUAL"; + mode += "|MAN"; } if (modeid == 0) @@ -2345,11 +2341,11 @@ QString UAS::getShortModeTextFor(int id) // ARMED STATE DECODING if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_SAFETY) { - mode.prepend("A|"); + mode.prepend("A/"); } else { - mode.prepend("D|"); + mode.prepend("D/"); } // HARDWARE IN THE LOOP DECODING @@ -2480,7 +2476,7 @@ QString UAS::getBatterySpecs() int UAS::calculateTimeRemaining() { - quint64 dt = MG::TIME::getGroundTimeNow() - startTime; + quint64 dt = QGC::groundTimeMilliseconds() - startTime; double seconds = dt / 1000.0f; double voltDifference = startVoltage - currentVoltage; if (voltDifference <= 0) voltDifference = 0.00000000001f; diff --git a/src/uas/UAS.h b/src/uas/UAS.h index e70bc52..d6284d0 100644 --- a/src/uas/UAS.h +++ b/src/uas/UAS.h @@ -218,7 +218,8 @@ protected: //COMMENTS FOR TEST UNIT bool batteryRemainingEstimateEnabled; ///< If the estimate is enabled, QGC will try to estimate the remaining battery life float chargeLevel; ///< Charge level of battery, in percent int timeRemaining; ///< Remaining time calculated based on previous and current - uint8_t mode; ///< The current mode of the MAV + uint8_t mode; ///< The current mode of the MAV + uint32_t custom_mode; ///< The current mode of the MAV int status; ///< The current status of the MAV uint32_t navMode; ///< The current navigation mode of the MAV quint64 onboardTimeOffset; diff --git a/src/ui/HSIDisplay.cc b/src/ui/HSIDisplay.cc index 9edb219..6cf3772 100644 --- a/src/ui/HSIDisplay.cc +++ b/src/ui/HSIDisplay.cc @@ -104,6 +104,7 @@ HSIDisplay::HSIDisplay(QWidget *parent) : leftDragStarted(false), mouseHasMoved(false), actionPending(false), + directSending(false), userSetPointSet(false), userXYSetPointSet(false) { @@ -637,37 +638,53 @@ void HSIDisplay::keyPressEvent(QKeyEvent* event) statusClearTimer.start(); sendBodySetPointCoordinates(); } - else if ((event->key() == Qt::Key_Up)) + else if ((event->key() == Qt::Key_W)) { - setBodySetpointCoordinateXY(0.5, 0); + setBodySetpointCoordinateXY(1.0, 0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_Down)) + else if ((event->key() == Qt::Key_S)) { - setBodySetpointCoordinateXY(-0.5, 0); + setBodySetpointCoordinateXY(-1.0, 0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_Left)) + else if ((event->key() == Qt::Key_A)) { - setBodySetpointCoordinateXY(0, -0.5); + setBodySetpointCoordinateXY(0, -1.0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_Right)) + else if ((event->key() == Qt::Key_D)) { - setBodySetpointCoordinateXY(0, 0.5); + setBodySetpointCoordinateXY(0, 1.0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_Plus)) + else if ((event->key() == Qt::Key_Up)) { - setBodySetpointCoordinateZ(-0.2); + setBodySetpointCoordinateXY(0, 0); + setBodySetpointCoordinateZ(-0.5+uas->getLocalZ()); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_Minus)) + else if ((event->key() == Qt::Key_Down)) { - setBodySetpointCoordinateZ(+0.2); + setBodySetpointCoordinateZ(+0.5+uas->getLocalZ()); + setBodySetpointCoordinateXY(0, 0); + setBodySetpointCoordinateYaw(uas->getYaw()); } - else if ((event->key() == Qt::Key_L)) + else if ((event->key() == Qt::Key_Left)) { - setBodySetpointCoordinateYaw(-0.1); + setBodySetpointCoordinateXY(0, 0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(-0.2+uas->getYaw()); } - else if ((event->key() == Qt::Key_R)) + else if ((event->key() == Qt::Key_Right)) { - setBodySetpointCoordinateYaw(0.1); + setBodySetpointCoordinateXY(0, 0); + setBodySetpointCoordinateZ(uas->getLocalZ()); + setBodySetpointCoordinateYaw(0.2+uas->getYaw()); } HDDisplay::keyPressEvent(event); } @@ -811,7 +828,7 @@ void HSIDisplay::sendBodySetPointCoordinates() double dx = uiXSetCoordinate - uas->getLocalX(); double dy = uiYSetCoordinate - uas->getLocalY(); double dz = uiZSetCoordinate - uas->getLocalZ(); - bool valid = (sqrt(dx*dx + dy*dy + dz*dz) < 1.0);//UASManager::instance()->isInLocalNEDSafetyLimits(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate); + bool valid = (sqrt(dx*dx + dy*dy + dz*dz) < 3.0);//UASManager::instance()->isInLocalNEDSafetyLimits(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate); if (valid) { uas->setLocalPositionSetpoint(uiXSetCoordinate, uiYSetCoordinate, uiZSetCoordinate, uiYawSet); diff --git a/src/ui/HSIDisplay.h b/src/ui/HSIDisplay.h index fd815e7..6397baa 100644 --- a/src/ui/HSIDisplay.h +++ b/src/ui/HSIDisplay.h @@ -175,6 +175,7 @@ protected: QTimer statusClearTimer; QString statusMessage; bool actionPending; + bool directSending; /** * @brief Private data container class to be used within the HSI widget