|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
|
|
*
|
|
|
|
* QGroundControl is licensed according to the terms in the file
|
|
|
|
* COPYING.md in the root of the source code directory.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
// NO NEW CODE HERE
|
|
|
|
// UASInterface, UAS.h/cc are deprecated. All new functionality should go into Vehicle.h/cc
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <QList>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <iostream>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <qmath.h>
|
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#include "UAS.h"
|
|
|
|
#include "LinkInterface.h"
|
|
|
|
#include "QGC.h"
|
|
|
|
#include "MAVLinkProtocol.h"
|
|
|
|
#include "QGCMAVLink.h"
|
|
|
|
#include "LinkManager.h"
|
|
|
|
#ifndef NO_SERIAL_LINK
|
|
|
|
#include "SerialLink.h"
|
|
|
|
#endif
|
|
|
|
#include "FirmwarePluginManager.h"
|
|
|
|
#include "QGCLoggingCategory.h"
|
|
|
|
#include "Vehicle.h"
|
|
|
|
#include "Joystick.h"
|
|
|
|
#include "QGCApplication.h"
|
|
|
|
|
|
|
|
QGC_LOGGING_CATEGORY(UASLog, "UASLog")
|
|
|
|
|
|
|
|
// THIS CLASS IS DEPRECATED. ALL NEW FUNCTIONALITY SHOULD GO INTO Vehicle class
|
|
|
|
UAS::UAS(MAVLinkProtocol* protocol, Vehicle* vehicle, FirmwarePluginManager * firmwarePluginManager) : UASInterface(),
|
|
|
|
lipoFull(4.2f),
|
|
|
|
lipoEmpty(3.5f),
|
|
|
|
uasId(vehicle->id()),
|
|
|
|
unknownPackets(),
|
|
|
|
mavlink(protocol),
|
|
|
|
receiveDropRate(0),
|
|
|
|
sendDropRate(0),
|
|
|
|
|
|
|
|
status(-1),
|
|
|
|
|
|
|
|
startTime(QGC::groundTimeMilliseconds()),
|
|
|
|
onboardTimeOffset(0),
|
|
|
|
|
|
|
|
controlRollManual(true),
|
|
|
|
controlPitchManual(true),
|
|
|
|
controlYawManual(true),
|
|
|
|
controlThrustManual(true),
|
|
|
|
|
|
|
|
attitudeKnown(false),
|
|
|
|
attitudeStamped(false),
|
|
|
|
lastAttitude(0),
|
|
|
|
|
|
|
|
imagePackets(0), // We must initialize to 0, otherwise extended data packets maybe incorrectly thought to be images
|
|
|
|
|
|
|
|
blockHomePositionChanges(false),
|
|
|
|
receivedMode(false),
|
|
|
|
|
|
|
|
// Note variances calculated from flight case from this log: http://dash.oznet.ch/view/MRjW8NUNYQSuSZkbn8dEjY
|
|
|
|
// TODO: calibrate stand-still pixhawk variances
|
|
|
|
xacc_var(0.6457f),
|
|
|
|
yacc_var(0.7048f),
|
|
|
|
zacc_var(0.97885f),
|
|
|
|
rollspeed_var(0.8126f),
|
|
|
|
pitchspeed_var(0.6145f),
|
|
|
|
yawspeed_var(0.5852f),
|
|
|
|
xmag_var(0.2393f),
|
|
|
|
ymag_var(0.2283f),
|
|
|
|
zmag_var(0.1665f),
|
|
|
|
abs_pressure_var(0.5802f),
|
|
|
|
diff_pressure_var(0.5802f),
|
|
|
|
pressure_alt_var(0.5802f),
|
|
|
|
temperature_var(0.7145f),
|
|
|
|
/*
|
|
|
|
xacc_var(0.0f),
|
|
|
|
yacc_var(0.0f),
|
|
|
|
zacc_var(0.0f),
|
|
|
|
rollspeed_var(0.0f),
|
|
|
|
pitchspeed_var(0.0f),
|
|
|
|
yawspeed_var(0.0f),
|
|
|
|
xmag_var(0.0f),
|
|
|
|
ymag_var(0.0f),
|
|
|
|
zmag_var(0.0f),
|
|
|
|
abs_pressure_var(0.0f),
|
|
|
|
diff_pressure_var(0.0f),
|
|
|
|
pressure_alt_var(0.0f),
|
|
|
|
temperature_var(0.0f),
|
|
|
|
*/
|
|
|
|
|
|
|
|
// The protected members.
|
|
|
|
connectionLost(false),
|
|
|
|
lastVoltageWarning(0),
|
|
|
|
lastNonNullTime(0),
|
|
|
|
onboardTimeOffsetInvalidCount(0),
|
|
|
|
_vehicle(vehicle),
|
|
|
|
_firmwarePluginManager(firmwarePluginManager)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ return the id of the uas
|
|
|
|
*/
|
|
|
|
int UAS::getUASID() const
|
|
|
|
{
|
|
|
|
return uasId;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore warnings from mavlink headers for both GCC/Clang and MSVC
|
|
|
|
#ifdef __GNUC__
|
|
|
|
|
|
|
|
#if __GNUC__ > 8
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
|
|
|
#elif defined(__clang__)
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Waddress-of-packed-member"
|
|
|
|
#else
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wall"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
|
|
|
#pragma warning(push, 0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void UAS::receiveMessage(mavlink_message_t message)
|
|
|
|
{
|
|
|
|
// Only accept messages from this system (condition 1)
|
|
|
|
// and only then if a) attitudeStamped is disabled OR b) attitudeStamped is enabled
|
|
|
|
// and we already got one attitude packet
|
|
|
|
if (message.sysid == uasId && (!attitudeStamped || lastAttitude != 0 || message.msgid == MAVLINK_MSG_ID_ATTITUDE))
|
|
|
|
{
|
|
|
|
bool multiComponentSourceDetected = false;
|
|
|
|
bool wrongComponent = false;
|
|
|
|
|
|
|
|
switch (message.compid)
|
|
|
|
{
|
|
|
|
case MAV_COMP_ID_IMU_2:
|
|
|
|
// Prefer IMU 2 over IMU 1 (FIXME)
|
|
|
|
componentID[message.msgid] = MAV_COMP_ID_IMU_2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store component ID
|
|
|
|
if (!componentID.contains(message.msgid))
|
|
|
|
{
|
|
|
|
// Prefer the first component
|
|
|
|
componentID[message.msgid] = message.compid;
|
|
|
|
componentMulti[message.msgid] = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Got this message already
|
|
|
|
if (componentID[message.msgid] != message.compid)
|
|
|
|
{
|
|
|
|
componentMulti[message.msgid] = true;
|
|
|
|
wrongComponent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (componentMulti[message.msgid] == true) {
|
|
|
|
multiComponentSourceDetected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (message.msgid)
|
|
|
|
{
|
|
|
|
case MAVLINK_MSG_ID_HEARTBEAT:
|
|
|
|
{
|
|
|
|
if (multiComponentSourceDetected && wrongComponent)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mavlink_heartbeat_t state;
|
|
|
|
mavlink_msg_heartbeat_decode(&message, &state);
|
|
|
|
|
|
|
|
// Send the base_mode and system_status values to the plotter. This uses the ground time
|
|
|
|
// so the Ground Time checkbox must be ticked for these values to display
|
|
|
|
quint64 time = getUnixTime();
|
|
|
|
QString name = QString("M%1:HEARTBEAT.%2").arg(message.sysid);
|
|
|
|
emit valueChanged(uasId, name.arg("base_mode"), "bits", state.base_mode, time);
|
|
|
|
emit valueChanged(uasId, name.arg("custom_mode"), "bits", state.custom_mode, time);
|
|
|
|
emit valueChanged(uasId, name.arg("system_status"), "-", state.system_status, time);
|
|
|
|
|
|
|
|
// We got the mode
|
|
|
|
receivedMode = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAVLINK_MSG_ID_SYS_STATUS:
|
|
|
|
{
|
|
|
|
if (multiComponentSourceDetected && wrongComponent)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mavlink_sys_status_t state;
|
|
|
|
mavlink_msg_sys_status_decode(&message, &state);
|
|
|
|
|
|
|
|
// Prepare for sending data to the realtime plotter, which is every field excluding onboard_control_sensors_present.
|
|
|
|
quint64 time = getUnixTime();
|
|
|
|
QString name = QString("M%1:SYS_STATUS.%2").arg(message.sysid);
|
|
|
|
emit valueChanged(uasId, name.arg("sensors_enabled"), "bits", state.onboard_control_sensors_enabled, time);
|
|
|
|
emit valueChanged(uasId, name.arg("sensors_health"), "bits", state.onboard_control_sensors_health, time);
|
|
|
|
emit valueChanged(uasId, name.arg("errors_comm"), "-", state.errors_comm, time);
|
|
|
|
emit valueChanged(uasId, name.arg("errors_count1"), "-", state.errors_count1, time);
|
|
|
|
emit valueChanged(uasId, name.arg("errors_count2"), "-", state.errors_count2, time);
|
|
|
|
emit valueChanged(uasId, name.arg("errors_count3"), "-", state.errors_count3, time);
|
|
|
|
emit valueChanged(uasId, name.arg("errors_count4"), "-", state.errors_count4, time);
|
|
|
|
|
|
|
|
// Process CPU load.
|
|
|
|
emit valueChanged(uasId, name.arg("load"), "%", state.load/10.0f, time);
|
|
|
|
emit valueChanged(uasId, name.arg("drop_rate_comm"), "%", state.drop_rate_comm/100.0f, time);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAVLINK_MSG_ID_PARAM_VALUE:
|
|
|
|
{
|
|
|
|
mavlink_param_value_t rawValue;
|
|
|
|
mavlink_msg_param_value_decode(&message, &rawValue);
|
|
|
|
QByteArray bytes(rawValue.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
|
|
|
|
// Construct a string stopping at the first NUL (0) character, else copy the whole
|
|
|
|
// byte array (max MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN, so safe)
|
|
|
|
QString parameterName(bytes);
|
|
|
|
mavlink_param_union_t paramVal;
|
|
|
|
paramVal.param_float = rawValue.param_value;
|
|
|
|
paramVal.type = rawValue.param_type;
|
|
|
|
|
|
|
|
processParamValueMsg(message, parameterName,rawValue,paramVal);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MAVLINK_MSG_ID_ATTITUDE_TARGET:
|
|
|
|
{
|
|
|
|
mavlink_attitude_target_t out;
|
|
|
|
mavlink_msg_attitude_target_decode(&message, &out);
|
|
|
|
float roll, pitch, yaw;
|
|
|
|
mavlink_quaternion_to_euler(out.q, &roll, &pitch, &yaw);
|
|
|
|
quint64 time = getUnixTimeFromMs(out.time_boot_ms);
|
|
|
|
|
|
|
|
// For plotting emit roll sp, pitch sp and yaw sp values
|
|
|
|
emit valueChanged(uasId, "roll sp", "rad", roll, time);
|
|
|
|
emit valueChanged(uasId, "pitch sp", "rad", pitch, time);
|
|
|
|
emit valueChanged(uasId, "yaw sp", "rad", yaw, time);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE:
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
imagePacketsArrived = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
|
|
// Check if we have a valid transaction
|
|
|
|
if (imagePackets == 0)
|
|
|
|
{
|
|
|
|
// NO VALID TRANSACTION - ABORT
|
|
|
|
// Restart statemachine
|
|
|
|
imagePacketsArrived = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < imagePayload; ++i)
|
|
|
|
{
|
|
|
|
if (pos <= imageSize) {
|
|
|
|
imageRecBuffer[pos] = img.data[i];
|
|
|
|
}
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
++imagePacketsArrived;
|
|
|
|
|
|
|
|
// emit signal if all packets arrived
|
|
|
|
if (imagePacketsArrived >= imagePackets)
|
|
|
|
{
|
|
|
|
// Restart statemachine
|
|
|
|
imagePackets = 0;
|
|
|
|
imagePacketsArrived = 0;
|
|
|
|
emit imageReady(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAVLINK_MSG_ID_LOG_ENTRY:
|
|
|
|
{
|
|
|
|
mavlink_log_entry_t log;
|
|
|
|
mavlink_msg_log_entry_decode(&message, &log);
|
|
|
|
emit logEntry(this, log.time_utc, log.size, log.id, log.num_logs, log.last_log_num);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAVLINK_MSG_ID_LOG_DATA:
|
|
|
|
{
|
|
|
|
mavlink_log_data_t log;
|
|
|
|
mavlink_msg_log_data_decode(&message, &log);
|
|
|
|
emit logData(this, log.ofs, log.id, log.count, log.data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pop warnings ignoring for mavlink headers for both GCC/Clang and MSVC
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#if defined(__clang__)
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#else
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#pragma warning(pop, 0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if time is smaller than 40 years, assuming no system without Unix
|
|
|
|
* timestamp runs longer than 40 years continuously without reboot. In worst case
|
|
|
|
* this will add/subtract the communication delay between GCS and MAV, it will
|
|
|
|
* never alter the timestamp in a safety critical way.
|
|
|
|
*/
|
|
|
|
quint64 UAS::getUnixReferenceTime(quint64 time)
|
|
|
|
{
|
|
|
|
// Same as getUnixTime, but does not react to attitudeStamped mode
|
|
|
|
if (time == 0)
|
|
|
|
{
|
|
|
|
// qDebug() << "XNEW time:" <<QGC::groundTimeMilliseconds();
|
|
|
|
return QGC::groundTimeMilliseconds();
|
|
|
|
}
|
|
|
|
// Check if time is smaller than 40 years,
|
|
|
|
// assuming no system without Unix timestamp
|
|
|
|
// runs longer than 40 years continuously without
|
|
|
|
// reboot. In worst case this will add/subtract the
|
|
|
|
// communication delay between GCS and MAV,
|
|
|
|
// it will never alter the timestamp in a safety
|
|
|
|
// critical way.
|
|
|
|
//
|
|
|
|
// Calculation:
|
|
|
|
// 40 years
|
|
|
|
// 365 days
|
|
|
|
// 24 hours
|
|
|
|
// 60 minutes
|
|
|
|
// 60 seconds
|
|
|
|
// 1000 milliseconds
|
|
|
|
// 1000 microseconds
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
else if (time < 1261440000000000LLU)
|
|
|
|
#else
|
|
|
|
else if (time < 1261440000000000)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
// qDebug() << "GEN time:" << time/1000 + onboardTimeOffset;
|
|
|
|
if (onboardTimeOffset == 0)
|
|
|
|
{
|
|
|
|
onboardTimeOffset = QGC::groundTimeMilliseconds() - time/1000;
|
|
|
|
}
|
|
|
|
return time/1000 + onboardTimeOffset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Time is not zero and larger than 40 years -> has to be
|
|
|
|
// a Unix epoch timestamp. Do nothing.
|
|
|
|
return time/1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @warning If attitudeStamped is enabled, this function will not actually return
|
|
|
|
* the precise time stamp of this measurement augmented to UNIX time, but will
|
|
|
|
* MOVE the timestamp IN TIME to match the last measured attitude. There is no
|
|
|
|
* reason why one would want this, except for system setups where the onboard
|
|
|
|
* clock is not present or broken and datasets should be collected that are still
|
|
|
|
* roughly synchronized. PLEASE NOTE THAT ENABLING ATTITUDE STAMPED RUINS THE
|
|
|
|
* SCIENTIFIC NATURE OF THE CORRECT LOGGING FUNCTIONS OF QGROUNDCONTROL!
|
|
|
|
*/
|
|
|
|
quint64 UAS::getUnixTimeFromMs(quint64 time)
|
|
|
|
{
|
|
|
|
return getUnixTime(time*1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @warning If attitudeStamped is enabled, this function will not actually return
|
|
|
|
* the precise time stam of this measurement augmented to UNIX time, but will
|
|
|
|
* MOVE the timestamp IN TIME to match the last measured attitude. There is no
|
|
|
|
* reason why one would want this, except for system setups where the onboard
|
|
|
|
* clock is not present or broken and datasets should be collected that are
|
|
|
|
* still roughly synchronized. PLEASE NOTE THAT ENABLING ATTITUDE STAMPED
|
|
|
|
* RUINS THE SCIENTIFIC NATURE OF THE CORRECT LOGGING FUNCTIONS OF QGROUNDCONTROL!
|
|
|
|
*/
|
|
|
|
quint64 UAS::getUnixTime(quint64 time)
|
|
|
|
{
|
|
|
|
quint64 ret = 0;
|
|
|
|
if (attitudeStamped)
|
|
|
|
{
|
|
|
|
ret = lastAttitude;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time == 0)
|
|
|
|
{
|
|
|
|
ret = QGC::groundTimeMilliseconds();
|
|
|
|
}
|
|
|
|
// Check if time is smaller than 40 years,
|
|
|
|
// assuming no system without Unix timestamp
|
|
|
|
// runs longer than 40 years continuously without
|
|
|
|
// reboot. In worst case this will add/subtract the
|
|
|
|
// communication delay between GCS and MAV,
|
|
|
|
// it will never alter the timestamp in a safety
|
|
|
|
// critical way.
|
|
|
|
//
|
|
|
|
// Calculation:
|
|
|
|
// 40 years
|
|
|
|
// 365 days
|
|
|
|
// 24 hours
|
|
|
|
// 60 minutes
|
|
|
|
// 60 seconds
|
|
|
|
// 1000 milliseconds
|
|
|
|
// 1000 microseconds
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
else if (time < 1261440000000000LLU)
|
|
|
|
#else
|
|
|
|
else if (time < 1261440000000000)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
// qDebug() << "GEN time:" << time/1000 + onboardTimeOffset;
|
|
|
|
if (onboardTimeOffset == 0 || time < (lastNonNullTime - 100))
|
|
|
|
{
|
|
|
|
lastNonNullTime = time;
|
|
|
|
onboardTimeOffset = QGC::groundTimeMilliseconds() - time/1000;
|
|
|
|
}
|
|
|
|
if (time > lastNonNullTime) lastNonNullTime = time;
|
|
|
|
|
|
|
|
ret = time/1000 + onboardTimeOffset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Time is not zero and larger than 40 years -> has to be
|
|
|
|
// a Unix epoch timestamp. Do nothing.
|
|
|
|
ret = time/1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the status of the code and a description of the status.
|
|
|
|
* Status can be unitialized, booting up, calibrating sensors, active
|
|
|
|
* standby, cirtical, emergency, shutdown or unknown.
|
|
|
|
*/
|
|
|
|
void UAS::getStatusForCode(int statusCode, QString& uasState, QString& stateDescription)
|
|
|
|
{
|
|
|
|
switch (statusCode)
|
|
|
|
{
|
|
|
|
case MAV_STATE_UNINIT:
|
|
|
|
uasState = tr("UNINIT");
|
|
|
|
stateDescription = tr("Unitialized, booting up.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_BOOT:
|
|
|
|
uasState = tr("BOOT");
|
|
|
|
stateDescription = tr("Booting system, please wait.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_CALIBRATING:
|
|
|
|
uasState = tr("CALIBRATING");
|
|
|
|
stateDescription = tr("Calibrating sensors, please wait.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_ACTIVE:
|
|
|
|
uasState = tr("ACTIVE");
|
|
|
|
stateDescription = tr("Active, normal operation.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_STANDBY:
|
|
|
|
uasState = tr("STANDBY");
|
|
|
|
stateDescription = tr("Standby mode, ready for launch.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_CRITICAL:
|
|
|
|
uasState = tr("CRITICAL");
|
|
|
|
stateDescription = tr("FAILURE: Continuing operation.");
|
|
|
|
break;
|
|
|
|
case MAV_STATE_EMERGENCY:
|
|
|
|
uasState = tr("EMERGENCY");
|
|
|
|
stateDescription = tr("EMERGENCY: Land Immediately!");
|
|
|
|
break;
|
|
|
|
//case MAV_STATE_HILSIM:
|
|
|
|
//uasState = tr("HIL SIM");
|
|
|
|
//stateDescription = tr("HIL Simulation, Sensors read from SIM");
|
|
|
|
//break;
|
|
|
|
|
|
|
|
case MAV_STATE_POWEROFF:
|
|
|
|
uasState = tr("SHUTDOWN");
|
|
|
|
stateDescription = tr("Powering off system.");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
uasState = tr("UNKNOWN");
|
|
|
|
stateDescription = tr("Unknown system state");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QImage UAS::getImage()
|
|
|
|
{
|
|
|
|
|
|
|
|
// qDebug() << "IMAGE TYPE:" << imageType;
|
|
|
|
|
|
|
|
// RAW greyscale
|
|
|
|
if (imageType == MAVLINK_DATA_STREAM_IMG_RAW8U)
|
|
|
|
{
|
|
|
|
int imgColors = 255;
|
|
|
|
|
|
|
|
// Construct PGM header
|
|
|
|
QString header("P5\n%1 %2\n%3\n");
|
|
|
|
header = header.arg(imageWidth).arg(imageHeight).arg(imgColors);
|
|
|
|
|
|
|
|
QByteArray tmpImage(header.toStdString().c_str(), header.length());
|
|
|
|
tmpImage.append(imageRecBuffer);
|
|
|
|
|
|
|
|
//qDebug() << "IMAGE SIZE:" << tmpImage.size() << "HEADER SIZE: (15):" << header.size() << "HEADER: " << header;
|
|
|
|
|
|
|
|
if (imageRecBuffer.isNull())
|
|
|
|
{
|
|
|
|
qDebug()<< "could not convertToPGM()";
|
|
|
|
return QImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!image.loadFromData(tmpImage, "PGM"))
|
|
|
|
{
|
|
|
|
qDebug()<< __FILE__ << __LINE__ << "could not create extracted image";
|
|
|
|
return QImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// BMP with header
|
|
|
|
else if (imageType == MAVLINK_DATA_STREAM_IMG_BMP ||
|
|
|
|
imageType == MAVLINK_DATA_STREAM_IMG_JPEG ||
|
|
|
|
imageType == MAVLINK_DATA_STREAM_IMG_PGM ||
|
|
|
|
imageType == MAVLINK_DATA_STREAM_IMG_PNG)
|
|
|
|
{
|
|
|
|
if (!image.loadFromData(imageRecBuffer))
|
|
|
|
{
|
|
|
|
qDebug() << __FILE__ << __LINE__ << "Loading data from image buffer failed!";
|
|
|
|
return QImage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restart statemachine
|
|
|
|
imagePacketsArrived = 0;
|
|
|
|
imagePackets = 0;
|
|
|
|
imageRecBuffer.clear();
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UAS::requestImage()
|
|
|
|
{
|
|
|
|
if (!_vehicle) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qDebug() << "trying to get an image from the uas...";
|
|
|
|
|
|
|
|
// check if there is already an image transmission going on
|
|
|
|
if (imagePacketsArrived == 0)
|
|
|
|
{
|
|
|
|
mavlink_message_t msg;
|
|
|
|
mavlink_msg_data_transmission_handshake_pack_chan(mavlink->getSystemId(),
|
|
|
|
mavlink->getComponentId(),
|
|
|
|
_vehicle->priorityLink()->mavlinkChannel(),
|
|
|
|
&msg,
|
|
|
|
MAVLINK_DATA_STREAM_IMG_JPEG,
|
|
|
|
0, 0, 0, 0, 0, 50);
|
|
|
|
_vehicle->sendMessageOnLinkThreadSafe(_vehicle->priorityLink(), msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* MANAGEMENT */
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @return The uptime in milliseconds
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
quint64 UAS::getUptime() const
|
|
|
|
{
|
|
|
|
if(startTime == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return QGC::groundTimeMilliseconds() - startTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO update this to use the parameter manager / param data model instead
|
|
|
|
void UAS::processParamValueMsg(mavlink_message_t& msg, const QString& paramName, const mavlink_param_value_t& rawValue, mavlink_param_union_t& paramUnion)
|
|
|
|
{
|
|
|
|
int compId = msg.compid;
|
|
|
|
|
|
|
|
QVariant paramValue;
|
|
|
|
|
|
|
|
// Insert with correct type
|
|
|
|
|
|
|
|
switch (rawValue.param_type) {
|
|
|
|
case MAV_PARAM_TYPE_REAL32:
|
|
|
|
paramValue = QVariant(paramUnion.param_float);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_UINT8:
|
|
|
|
paramValue = QVariant(paramUnion.param_uint8);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_INT8:
|
|
|
|
paramValue = QVariant(paramUnion.param_int8);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_UINT16:
|
|
|
|
paramValue = QVariant(paramUnion.param_uint16);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_INT16:
|
|
|
|
paramValue = QVariant(paramUnion.param_int16);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_UINT32:
|
|
|
|
paramValue = QVariant(paramUnion.param_uint32);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAV_PARAM_TYPE_INT32:
|
|
|
|
paramValue = QVariant(paramUnion.param_int32);
|
|
|
|
break;
|
|
|
|
|
|
|
|
//-- Note: These are not handled above:
|
|
|
|
//
|
|
|
|
// MAV_PARAM_TYPE_UINT64
|
|
|
|
// MAV_PARAM_TYPE_INT64
|
|
|
|
// MAV_PARAM_TYPE_REAL64
|
|
|
|
//
|
|
|
|
// No space in message (the only storage allocation is a "float") and not present in mavlink_param_union_t
|
|
|
|
|
|
|
|
default:
|
|
|
|
qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << rawValue.param_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
qCDebug(UASLog) << "Received PARAM_VALUE" << paramName << paramValue << rawValue.param_type;
|
|
|
|
|
|
|
|
emit parameterUpdate(uasId, compId, paramName, rawValue.param_count, rawValue.param_index, rawValue.param_type, paramValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Order the robot to start receiver pairing
|
|
|
|
*/
|
|
|
|
void UAS::pairRX(int rxType, int rxSubType)
|
|
|
|
{
|
|
|
|
if (_vehicle) {
|
|
|
|
_vehicle->sendMavCommand(_vehicle->defaultComponentId(), // target component
|
|
|
|
MAV_CMD_START_RX_PAIR, // command id
|
|
|
|
true, // showError
|
|
|
|
rxType,
|
|
|
|
rxSubType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UAS::shutdownVehicle(void)
|
|
|
|
{
|
|
|
|
_vehicle = nullptr;
|
|
|
|
}
|