12 changed files with 4 additions and 2659 deletions
@ -1,149 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <QThread> |
|
||||||
#include <QProcess> |
|
||||||
#include "inttypes.h" |
|
||||||
|
|
||||||
class QGCHilLink : public QThread |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
public: |
|
||||||
|
|
||||||
virtual bool isConnected() = 0; |
|
||||||
virtual qint64 bytesAvailable() = 0; |
|
||||||
virtual int getPort() const = 0; |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The human readable port name |
|
||||||
*/ |
|
||||||
virtual QString getName() = 0; |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get remote host and port |
|
||||||
* @return string in format <host>:<port> |
|
||||||
*/ |
|
||||||
virtual QString getRemoteHost() = 0; |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the application name and version |
|
||||||
* @return A string containing a unique application name and compatibility version |
|
||||||
*/ |
|
||||||
virtual QString getVersion() = 0; |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get index of currently selected airframe |
|
||||||
* @return -1 if default is selected, index else |
|
||||||
*/ |
|
||||||
virtual int getAirFrameIndex() = 0; |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if sensor level HIL is enabled |
|
||||||
* @return true if sensor HIL is enabled |
|
||||||
*/ |
|
||||||
virtual bool sensorHilEnabled() = 0; |
|
||||||
|
|
||||||
public slots: |
|
||||||
virtual void setPort(int port) = 0; |
|
||||||
/** @brief Add a new host to broadcast messages to */ |
|
||||||
virtual void setRemoteHost(const QString& host) = 0; |
|
||||||
/** @brief Send new control states to the simulation */ |
|
||||||
virtual void updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode) = 0; |
|
||||||
virtual void processError(QProcess::ProcessError err) = 0; |
|
||||||
/** @brief Set the simulator version as text string */ |
|
||||||
virtual void setVersion(const QString& version) = 0; |
|
||||||
/** @brief Enable sensor-level HIL (instead of state-level HIL) */ |
|
||||||
virtual void enableSensorHIL(bool enable) = 0; |
|
||||||
|
|
||||||
virtual void selectAirframe(const QString& airframe) = 0; |
|
||||||
|
|
||||||
virtual void readBytes() = 0; |
|
||||||
/**
|
|
||||||
* @brief Write a number of bytes to the interface. |
|
||||||
* |
|
||||||
* @param data Pointer to the data byte array |
|
||||||
* @param size The size of the bytes array |
|
||||||
**/ |
|
||||||
void writeBytesSafe(const char* data, int length) |
|
||||||
{ |
|
||||||
emit _invokeWriteBytes(QByteArray(data, length)); |
|
||||||
} |
|
||||||
|
|
||||||
virtual bool connectSimulation() = 0; |
|
||||||
virtual bool disconnectSimulation() = 0; |
|
||||||
|
|
||||||
private slots: |
|
||||||
virtual void _writeBytes(const QByteArray) = 0; |
|
||||||
|
|
||||||
protected: |
|
||||||
virtual void setName(QString name) = 0; |
|
||||||
|
|
||||||
QGCHilLink() : |
|
||||||
QThread() |
|
||||||
{ |
|
||||||
connect(this, &QGCHilLink::_invokeWriteBytes, this, &QGCHilLink::_writeBytes); |
|
||||||
} |
|
||||||
|
|
||||||
signals: |
|
||||||
/**
|
|
||||||
* @brief This signal is emitted instantly when the link is connected |
|
||||||
**/ |
|
||||||
void simulationConnected(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This signal is emitted instantly when the link is disconnected |
|
||||||
**/ |
|
||||||
void simulationDisconnected(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Thread safe signal to disconnect simulator from other threads |
|
||||||
**/ |
|
||||||
void disconnectSim(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This signal is emitted instantly when the link status changes |
|
||||||
**/ |
|
||||||
void simulationConnected(bool connected); |
|
||||||
|
|
||||||
/** @brief State update from simulation */ |
|
||||||
void hilStateChanged(quint64 time_us, float roll, float pitch, float yaw, float rollspeed, |
|
||||||
float pitchspeed, float yawspeed, double lat, double lon, double alt, |
|
||||||
float vx, float vy, float vz, float ind_airspeed, float true_airspeed, float xacc, float yacc, float zacc); |
|
||||||
|
|
||||||
void hilGroundTruthChanged(quint64 time_us, float roll, float pitch, float yaw, float rollspeed, |
|
||||||
float pitchspeed, float yawspeed, double lat, double lon, double alt, |
|
||||||
float vx, float vy, float vz, float ind_airspeed, float true_airspeed, float xacc, float yacc, float zacc); |
|
||||||
|
|
||||||
void sensorHilGpsChanged(quint64 time_us, double lat, double lon, double alt, int fix_type, float eph, float epv, float vel, float vn, float ve, float vd, float cog, int satellites); |
|
||||||
|
|
||||||
void sensorHilRawImuChanged(quint64 time_us, float xacc, float yacc, float zacc, |
|
||||||
float xgyro, float ygyro, float zgyro, |
|
||||||
float xmag, float ymag, float zmag, |
|
||||||
float abs_pressure, float diff_pressure, |
|
||||||
float pressure_alt, float temperature, |
|
||||||
quint32 fields_updated); |
|
||||||
|
|
||||||
void sensorHilOpticalFlowChanged(quint64 time_us, qint16 flow_x, qint16 flow_y, float flow_comp_m_x, |
|
||||||
float flow_comp_m_y, quint8 quality, float ground_distance); |
|
||||||
|
|
||||||
/** @brief Remote host and port changed */ |
|
||||||
void remoteChanged(const QString& hostPort); |
|
||||||
|
|
||||||
/** @brief Status text message from link */ |
|
||||||
void statusMessage(const QString& message); |
|
||||||
|
|
||||||
/** @brief Airframe changed */ |
|
||||||
void airframeChanged(const QString& airframe); |
|
||||||
|
|
||||||
/** @brief Selected sim version changed */ |
|
||||||
void versionChanged(const QString& version); |
|
||||||
|
|
||||||
/** @brief Selected sim version changed */ |
|
||||||
void versionChanged(const int version); |
|
||||||
|
|
||||||
/** @brief Sensor leve HIL state changed */ |
|
||||||
void sensorHilChanged(bool enabled); |
|
||||||
|
|
||||||
/** @brief Helper signal to force execution on the correct thread */ |
|
||||||
void _invokeWriteBytes(QByteArray); |
|
||||||
}; |
|
||||||
|
|
@ -1,399 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (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. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file |
|
||||||
* @brief Definition of UDP connection (server) for unmanned vehicles |
|
||||||
* @author Lorenz Meier <lorenz@px4.io> |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <QTimer> |
|
||||||
#include <QList> |
|
||||||
#include <QDebug> |
|
||||||
#include <QMutexLocker> |
|
||||||
#include <QHostInfo> |
|
||||||
|
|
||||||
#include <iostream> |
|
||||||
|
|
||||||
#include "UAS.h" |
|
||||||
#include "QGCJSBSimLink.h" |
|
||||||
#include "QGC.h" |
|
||||||
//-- TODO: #include "QGCMessageBox.h"
|
|
||||||
|
|
||||||
QGCJSBSimLink::QGCJSBSimLink(Vehicle* vehicle, QString startupArguments, QString remoteHost, QHostAddress host, quint16 port) |
|
||||||
: _vehicle(vehicle) |
|
||||||
, socket(nullptr) |
|
||||||
, process(nullptr) |
|
||||||
, startupArguments(startupArguments) |
|
||||||
{ |
|
||||||
// We're doing it wrong - because the Qt folks got the API wrong:
|
|
||||||
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
|
|
||||||
moveToThread(this); |
|
||||||
|
|
||||||
this->host = host; |
|
||||||
this->port = port + _vehicle->id(); |
|
||||||
this->connectState = false; |
|
||||||
this->currentPort = 49000 + _vehicle->id(); |
|
||||||
this->name = tr("JSBSim Link (port:%1)").arg(port); |
|
||||||
setRemoteHost(remoteHost); |
|
||||||
} |
|
||||||
|
|
||||||
QGCJSBSimLink::~QGCJSBSimLink() |
|
||||||
{ //do not disconnect unless it is connected.
|
|
||||||
//disconnectSimulation will delete the memory that was allocated for process, terraSync and socket
|
|
||||||
if(connectState){ |
|
||||||
disconnectSimulation(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Runs the thread |
|
||||||
* |
|
||||||
**/ |
|
||||||
void QGCJSBSimLink::run() |
|
||||||
{ |
|
||||||
qDebug() << "STARTING FLIGHTGEAR LINK"; |
|
||||||
|
|
||||||
if (!_vehicle) return; |
|
||||||
socket = new QUdpSocket(this); |
|
||||||
socket->moveToThread(this); |
|
||||||
connectState = socket->bind(host, port, QAbstractSocket::ReuseAddressHint); |
|
||||||
|
|
||||||
QObject::connect(socket, &QUdpSocket::readyRead, this, &QGCJSBSimLink::readBytes); |
|
||||||
|
|
||||||
process = new QProcess(this); |
|
||||||
|
|
||||||
connect(_vehicle->uas(), &UAS::hilControlsChanged, this, &QGCJSBSimLink::updateControls); |
|
||||||
connect(this, &QGCJSBSimLink::hilStateChanged, _vehicle->uas(), &UAS::sendHilState); |
|
||||||
|
|
||||||
_vehicle->uas()->startHil(); |
|
||||||
|
|
||||||
//connect(&refreshTimer, SIGNAL(timeout()), this, SLOT(sendUAVUpdate()));
|
|
||||||
// Catch process error
|
|
||||||
connect(process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), |
|
||||||
this, &QGCJSBSimLink::processError); |
|
||||||
|
|
||||||
// Start Flightgear
|
|
||||||
QStringList arguments; |
|
||||||
QString processJSB; |
|
||||||
QString rootJSB; |
|
||||||
|
|
||||||
#ifdef Q_OS_MACX |
|
||||||
processJSB = "/usr/local/bin/JSBSim"; |
|
||||||
rootJSB = "/Applications/FlightGear.app/Contents/Resources/data"; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32 |
|
||||||
processJSB = "C:\\Program Files (x86)\\FlightGear\\bin\\Win32\\fgfs"; |
|
||||||
rootJSB = "C:\\Program Files (x86)\\FlightGear\\data"; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX |
|
||||||
processJSB = "/usr/games/fgfs"; |
|
||||||
rootJSB = "/usr/share/games/flightgear"; |
|
||||||
#endif |
|
||||||
|
|
||||||
// Sanity checks
|
|
||||||
bool sane = true; |
|
||||||
QFileInfo executable(processJSB); |
|
||||||
if (!executable.isExecutable()) |
|
||||||
{ |
|
||||||
//-- TODO: QGCMessageBox::critical("JSBSim", tr("JSBSim failed to start. JSBSim was not found at %1").arg(processJSB));
|
|
||||||
sane = false; |
|
||||||
} |
|
||||||
|
|
||||||
QFileInfo root(rootJSB); |
|
||||||
if (!root.isDir()) |
|
||||||
{ |
|
||||||
//-- TODO: QGCMessageBox::critical("JSBSim", tr("JSBSim failed to start. JSBSim data directory was not found at %1").arg(rootJSB));
|
|
||||||
sane = false; |
|
||||||
} |
|
||||||
|
|
||||||
if (!sane) return; |
|
||||||
|
|
||||||
/*Prepare JSBSim Arguments */ |
|
||||||
|
|
||||||
if (_vehicle->vehicleType() == MAV_TYPE_QUADROTOR) |
|
||||||
{ |
|
||||||
arguments << QString("--realtime --suspend --nice --simulation-rate=1000 --logdirectivefile=%s/flightgear.xml --script=%s/%s").arg(rootJSB, rootJSB, script); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
arguments << QString("JSBSim --realtime --suspend --nice --simulation-rate=1000 --logdirectivefile=%s/flightgear.xml --script=%s/%s").arg(rootJSB, rootJSB, script); |
|
||||||
} |
|
||||||
|
|
||||||
process->start(processJSB, arguments); |
|
||||||
|
|
||||||
emit simulationConnected(connectState); |
|
||||||
if (connectState) { |
|
||||||
emit simulationConnected(); |
|
||||||
connectionStartTime = QGC::groundTimeUsecs()/1000; |
|
||||||
} |
|
||||||
qDebug() << "STARTING SIM"; |
|
||||||
|
|
||||||
exec(); |
|
||||||
} |
|
||||||
|
|
||||||
void QGCJSBSimLink::setPort(int port) |
|
||||||
{ |
|
||||||
this->port = port; |
|
||||||
disconnectSimulation(); |
|
||||||
connectSimulation(); |
|
||||||
} |
|
||||||
|
|
||||||
void QGCJSBSimLink::processError(QProcess::ProcessError err) |
|
||||||
{ |
|
||||||
QString msg; |
|
||||||
|
|
||||||
switch(err) { |
|
||||||
case QProcess::FailedToStart: |
|
||||||
msg = tr("JSBSim Failed to start. Please check if the path and command is correct"); |
|
||||||
break; |
|
||||||
|
|
||||||
case QProcess::Crashed: |
|
||||||
msg = tr("JSBSim crashed. This is a JSBSim-related problem, check for JSBSim upgrade."); |
|
||||||
break; |
|
||||||
|
|
||||||
case QProcess::Timedout: |
|
||||||
msg = tr("JSBSim start timed out. Please check if the path and command is correct"); |
|
||||||
break; |
|
||||||
|
|
||||||
case QProcess::ReadError: |
|
||||||
case QProcess::WriteError: |
|
||||||
msg = tr("Could not communicate with JSBSim. Please check if the path and command are correct"); |
|
||||||
break; |
|
||||||
|
|
||||||
case QProcess::UnknownError: |
|
||||||
default: |
|
||||||
msg = tr("JSBSim error occurred. Please check if the path and command is correct."); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
//-- TODO: QGCMessageBox::critical("JSBSim HIL", msg);
|
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @param host Hostname in standard formatting, e.g. localhost:14551 or 192.168.1.1:14551 |
|
||||||
*/ |
|
||||||
void QGCJSBSimLink::setRemoteHost(const QString& host) |
|
||||||
{ |
|
||||||
if (host.contains(":")) |
|
||||||
{ |
|
||||||
//qDebug() << "HOST: " << host.split(":").first();
|
|
||||||
QHostInfo info = QHostInfo::fromName(host.split(":").first()); |
|
||||||
if (info.error() == QHostInfo::NoError) |
|
||||||
{ |
|
||||||
// Add host
|
|
||||||
QList<QHostAddress> hostAddresses = info.addresses(); |
|
||||||
QHostAddress address; |
|
||||||
for (int i = 0; i < hostAddresses.size(); i++) |
|
||||||
{ |
|
||||||
// Exclude loopback IPv4 and all IPv6 addresses
|
|
||||||
if (!hostAddresses.at(i).toString().contains(":")) |
|
||||||
{ |
|
||||||
address = hostAddresses.at(i); |
|
||||||
} |
|
||||||
} |
|
||||||
currentHost = address; |
|
||||||
//qDebug() << "Address:" << address.toString();
|
|
||||||
// Set port according to user input
|
|
||||||
currentPort = host.split(":").last().toInt(); |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
QHostInfo info = QHostInfo::fromName(host); |
|
||||||
if (info.error() == QHostInfo::NoError) |
|
||||||
{ |
|
||||||
// Add host
|
|
||||||
currentHost = info.addresses().first(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
void QGCJSBSimLink::updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode) |
|
||||||
{ |
|
||||||
// magnetos,aileron,elevator,rudder,throttle\n
|
|
||||||
|
|
||||||
//float magnetos = 3.0f;
|
|
||||||
Q_UNUSED(time); |
|
||||||
Q_UNUSED(systemMode); |
|
||||||
Q_UNUSED(navMode); |
|
||||||
|
|
||||||
if(!qIsNaN(rollAilerons) && !qIsNaN(pitchElevator) && !qIsNaN(yawRudder) && !qIsNaN(throttle)) |
|
||||||
{ |
|
||||||
QString state("%1\t%2\t%3\t%4\t%5\n"); |
|
||||||
state = state.arg(rollAilerons).arg(pitchElevator).arg(yawRudder).arg(true).arg(throttle); |
|
||||||
emit _invokeWriteBytes(state.toLatin1()); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
qDebug() << "HIL: Got NaN values from the hardware: isnan output: roll: " << qIsNaN(rollAilerons) << ", pitch: " << qIsNaN(pitchElevator) << ", yaw: " << qIsNaN(yawRudder) << ", throttle: " << qIsNaN(throttle); |
|
||||||
} |
|
||||||
//qDebug() << "Updated controls" << state;
|
|
||||||
} |
|
||||||
|
|
||||||
void QGCJSBSimLink::_writeBytes(const QByteArray data) |
|
||||||
{ |
|
||||||
//#define QGCJSBSimLink_DEBUG
|
|
||||||
#ifdef QGCJSBSimLink_DEBUG |
|
||||||
QString bytes; |
|
||||||
QString ascii; |
|
||||||
for (int i=0, size = data.size(); i<size; i++) |
|
||||||
{ |
|
||||||
unsigned char v = data[i]; |
|
||||||
bytes.append(QString().sprintf("%02x ", v)); |
|
||||||
if (data[i] > 31 && data[i] < 127) |
|
||||||
{ |
|
||||||
ascii.append(data[i]); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
ascii.append(219); |
|
||||||
} |
|
||||||
} |
|
||||||
qDebug() << "Sent" << size << "bytes to" << currentHost.toString() << ":" << currentPort << "data:"; |
|
||||||
qDebug() << bytes; |
|
||||||
qDebug() << "ASCII:" << ascii; |
|
||||||
#endif |
|
||||||
if (connectState && socket) socket->writeDatagram(data, currentHost, currentPort); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Read a number of bytes from the interface. |
|
||||||
* |
|
||||||
* @param data Pointer to the data byte array to write the bytes to |
|
||||||
* @param maxLength The maximum number of bytes to write |
|
||||||
**/ |
|
||||||
void QGCJSBSimLink::readBytes() |
|
||||||
{ |
|
||||||
const qint64 maxLength = 65536; |
|
||||||
char data[maxLength]; |
|
||||||
QHostAddress sender; |
|
||||||
quint16 senderPort; |
|
||||||
|
|
||||||
unsigned int s = socket->pendingDatagramSize(); |
|
||||||
if (s > maxLength) std::cerr << __FILE__ << __LINE__ << " UDP datagram overflow, allowed to read less bytes than datagram size" << std::endl; |
|
||||||
socket->readDatagram(data, maxLength, &sender, &senderPort); |
|
||||||
|
|
||||||
/*
|
|
||||||
// Print string
|
|
||||||
QByteArray b(data, s); |
|
||||||
QString state(b); |
|
||||||
|
|
||||||
// Parse string
|
|
||||||
float roll, pitch, yaw, rollspeed, pitchspeed, yawspeed; |
|
||||||
double lat, lon, alt; |
|
||||||
double vx, vy, vz, xacc, yacc, zacc; |
|
||||||
|
|
||||||
// Send updated state
|
|
||||||
emit hilStateChanged(QGC::groundTimeUsecs(), roll, pitch, yaw, rollspeed, |
|
||||||
pitchspeed, yawspeed, lat, lon, alt, vx, vy, vz, xacc, yacc, zacc); |
|
||||||
*/ |
|
||||||
|
|
||||||
// Echo data for debugging purposes
|
|
||||||
std::cerr << __FILE__ << __LINE__ << "Received datagram:" << std::endl; |
|
||||||
for (unsigned int i=0; i<s; i++) |
|
||||||
{ |
|
||||||
unsigned int v=data[i]; |
|
||||||
fprintf(stderr,"%02x ", v); |
|
||||||
} |
|
||||||
std::cerr << std::endl; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of bytes to read. |
|
||||||
* |
|
||||||
* @return The number of bytes to read |
|
||||||
**/ |
|
||||||
qint64 QGCJSBSimLink::bytesAvailable() |
|
||||||
{ |
|
||||||
return socket->pendingDatagramSize(); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnect the connection. |
|
||||||
* |
|
||||||
* @return True if connection has been disconnected, false if connection couldn't be disconnected. |
|
||||||
**/ |
|
||||||
bool QGCJSBSimLink::disconnectSimulation() |
|
||||||
{ |
|
||||||
disconnect(_vehicle->uas(), &UAS::hilControlsChanged, this, &QGCJSBSimLink::updateControls); |
|
||||||
disconnect(this, &QGCJSBSimLink::hilStateChanged, _vehicle->uas(), &UAS::sendHilState); |
|
||||||
disconnect(process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), |
|
||||||
this, &QGCJSBSimLink::processError); |
|
||||||
|
|
||||||
if (process) |
|
||||||
{ |
|
||||||
process->close(); |
|
||||||
delete process; |
|
||||||
process = nullptr; |
|
||||||
} |
|
||||||
if (socket) |
|
||||||
{ |
|
||||||
socket->close(); |
|
||||||
delete socket; |
|
||||||
socket = nullptr; |
|
||||||
} |
|
||||||
|
|
||||||
connectState = false; |
|
||||||
|
|
||||||
emit simulationDisconnected(); |
|
||||||
emit simulationConnected(false); |
|
||||||
return !connectState; |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Connect the connection. |
|
||||||
* |
|
||||||
* @return True if connection has been established, false if connection couldn't be established. |
|
||||||
**/ |
|
||||||
bool QGCJSBSimLink::connectSimulation() |
|
||||||
{ |
|
||||||
start(HighPriority); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the startup arguments used to start flightgear |
|
||||||
* |
|
||||||
**/ |
|
||||||
void QGCJSBSimLink::setStartupArguments(QString startupArguments) |
|
||||||
{ |
|
||||||
this->startupArguments = startupArguments; |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if connection is active. |
|
||||||
* |
|
||||||
* @return True if link is connected, false otherwise. |
|
||||||
**/ |
|
||||||
bool QGCJSBSimLink::isConnected() |
|
||||||
{ |
|
||||||
return connectState; |
|
||||||
} |
|
||||||
|
|
||||||
QString QGCJSBSimLink::getName() |
|
||||||
{ |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
QString QGCJSBSimLink::getRemoteHost() |
|
||||||
{ |
|
||||||
return QString("%1:%2").arg(currentHost.toString(), currentPort); |
|
||||||
} |
|
||||||
|
|
||||||
void QGCJSBSimLink::setName(QString name) |
|
||||||
{ |
|
||||||
this->name = name; |
|
||||||
} |
|
@ -1,149 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (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. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file |
|
||||||
* @brief UDP connection (server) for unmanned vehicles |
|
||||||
* @author Lorenz Meier <mavteam@student.ethz.ch> |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <QString> |
|
||||||
#include <QList> |
|
||||||
#include <QMap> |
|
||||||
#include <QMutex> |
|
||||||
#include <QUdpSocket> |
|
||||||
#include <QTimer> |
|
||||||
#include <QProcess> |
|
||||||
#include <LinkInterface.h> |
|
||||||
#include "QGCConfig.h" |
|
||||||
#include "QGCHilLink.h" |
|
||||||
#include "Vehicle.h" |
|
||||||
|
|
||||||
class QGCJSBSimLink : public QGCHilLink |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
//Q_INTERFACES(QGCJSBSimLinkInterface:LinkInterface)
|
|
||||||
|
|
||||||
public: |
|
||||||
QGCJSBSimLink(Vehicle* vehicle, QString startupArguments, QString remoteHost=QString("127.0.0.1:49000"), QHostAddress host = QHostAddress::Any, quint16 port = 49005); |
|
||||||
~QGCJSBSimLink(); |
|
||||||
|
|
||||||
bool isConnected(); |
|
||||||
qint64 bytesAvailable(); |
|
||||||
int getPort() const { |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The human readable port name |
|
||||||
*/ |
|
||||||
QString getName(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get remote host and port |
|
||||||
* @return string in format <host>:<port> |
|
||||||
*/ |
|
||||||
QString getRemoteHost(); |
|
||||||
|
|
||||||
QString getVersion() |
|
||||||
{ |
|
||||||
return QString("FlightGear %1").arg(flightGearVersion); |
|
||||||
} |
|
||||||
|
|
||||||
int getAirFrameIndex() |
|
||||||
{ |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
void run(); |
|
||||||
|
|
||||||
bool sensorHilEnabled() { |
|
||||||
return _sensorHilEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public slots: |
|
||||||
// void setAddress(QString address);
|
|
||||||
void setPort(int port); |
|
||||||
/** @brief Add a new host to broadcast messages to */ |
|
||||||
void setRemoteHost(const QString& host); |
|
||||||
/** @brief Send new control states to the simulation */ |
|
||||||
void updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode); |
|
||||||
// /** @brief Remove a host from broadcasting messages to */
|
|
||||||
// void removeHost(const QString& host);
|
|
||||||
// void readPendingDatagrams();
|
|
||||||
void processError(QProcess::ProcessError err); |
|
||||||
/** @brief Set the simulator version as text string */ |
|
||||||
void setVersion(const QString& version) |
|
||||||
{ |
|
||||||
Q_UNUSED(version); |
|
||||||
} |
|
||||||
|
|
||||||
void selectAirframe(const QString& airframe) |
|
||||||
{ |
|
||||||
script = airframe; |
|
||||||
} |
|
||||||
|
|
||||||
void enableSensorHIL(bool enable) { |
|
||||||
if (enable != _sensorHilEnabled) { |
|
||||||
_sensorHilEnabled = enable; |
|
||||||
emit sensorHilChanged(enable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void readBytes(); |
|
||||||
|
|
||||||
private slots: |
|
||||||
/**
|
|
||||||
* @brief Write a number of bytes to the interface. |
|
||||||
* |
|
||||||
* @param data Pointer to the data byte array |
|
||||||
* @param size The size of the bytes array |
|
||||||
**/ |
|
||||||
void _writeBytes(const QByteArray data); |
|
||||||
|
|
||||||
public slots: |
|
||||||
bool connectSimulation(); |
|
||||||
bool disconnectSimulation(); |
|
||||||
|
|
||||||
void setStartupArguments(QString startupArguments); |
|
||||||
|
|
||||||
private: |
|
||||||
Vehicle* _vehicle; |
|
||||||
QString name; |
|
||||||
QHostAddress host; |
|
||||||
QHostAddress currentHost; |
|
||||||
quint16 currentPort; |
|
||||||
quint16 port; |
|
||||||
int id; |
|
||||||
QUdpSocket* socket; |
|
||||||
bool connectState; |
|
||||||
|
|
||||||
quint64 bitsSentTotal; |
|
||||||
quint64 bitsSentCurrent; |
|
||||||
quint64 bitsSentMax; |
|
||||||
quint64 bitsReceivedTotal; |
|
||||||
quint64 bitsReceivedCurrent; |
|
||||||
quint64 bitsReceivedMax; |
|
||||||
quint64 connectionStartTime; |
|
||||||
QMutex statisticsMutex; |
|
||||||
QMutex dataMutex; |
|
||||||
QTimer refreshTimer; |
|
||||||
QProcess* process; |
|
||||||
unsigned int flightGearVersion; |
|
||||||
QString startupArguments; |
|
||||||
QString script; |
|
||||||
bool _sensorHilEnabled; |
|
||||||
|
|
||||||
void setName(QString name); |
|
||||||
}; |
|
||||||
|
|
@ -1,237 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (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. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file QGCXPlaneLink.h |
|
||||||
* @brief X-Plane simulation link |
|
||||||
* @author Lorenz Meier <mavteam@student.ethz.ch> |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <QString> |
|
||||||
#include <QList> |
|
||||||
#include <QMap> |
|
||||||
#include <QMutex> |
|
||||||
#include <QUdpSocket> |
|
||||||
#include <QTimer> |
|
||||||
#include <QProcess> |
|
||||||
#include <LinkInterface.h> |
|
||||||
#include "QGCConfig.h" |
|
||||||
#include "QGCHilLink.h" |
|
||||||
#include "Vehicle.h" |
|
||||||
|
|
||||||
class QGCXPlaneLink : public QGCHilLink |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
//Q_INTERFACES(QGCXPlaneLinkInterface:LinkInterface)
|
|
||||||
|
|
||||||
public: |
|
||||||
QGCXPlaneLink(Vehicle* vehicle, QString remoteHost=QString("127.0.0.1:49000"), QHostAddress localHost = QHostAddress::Any, quint16 localPort = 49005); |
|
||||||
~QGCXPlaneLink(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Load X-Plane HIL settings |
|
||||||
*/ |
|
||||||
void loadSettings(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Store X-Plane HIL settings |
|
||||||
*/ |
|
||||||
void storeSettings(); |
|
||||||
|
|
||||||
bool isConnected(); |
|
||||||
qint64 bytesAvailable(); |
|
||||||
int getPort() const { |
|
||||||
return localPort; |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The human readable port name |
|
||||||
*/ |
|
||||||
QString getName(); |
|
||||||
|
|
||||||
void run(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get remote host and port |
|
||||||
* @return string in format <host>:<port> |
|
||||||
*/ |
|
||||||
QString getRemoteHost(); |
|
||||||
|
|
||||||
enum AIRFRAME |
|
||||||
{ |
|
||||||
AIRFRAME_UNKNOWN = 0, |
|
||||||
AIRFRAME_QUAD_DJI_F450_PWM, |
|
||||||
AIRFRAME_QUAD_X_MK_10INCH_I2C, |
|
||||||
AIRFRAME_QUAD_X_ARDRONE, |
|
||||||
AIRFRAME_FIXED_WING_BIXLER_II, |
|
||||||
AIRFRAME_FIXED_WING_BIXLER_II_AILERONS |
|
||||||
}; |
|
||||||
|
|
||||||
QString getVersion() |
|
||||||
{ |
|
||||||
return QString("X-Plane %1").arg(xPlaneVersion); |
|
||||||
} |
|
||||||
|
|
||||||
int getAirFrameIndex() |
|
||||||
{ |
|
||||||
return (int)airframeID; |
|
||||||
} |
|
||||||
|
|
||||||
bool sensorHilEnabled() { |
|
||||||
return _sensorHilEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
bool useHilActuatorControls() { |
|
||||||
return _useHilActuatorControls; |
|
||||||
} |
|
||||||
|
|
||||||
signals: |
|
||||||
/** @brief Sensor leve HIL state changed */ |
|
||||||
void useHilActuatorControlsChanged(bool enabled); |
|
||||||
|
|
||||||
public slots: |
|
||||||
// void setAddress(QString address);
|
|
||||||
void setPort(int port); |
|
||||||
/** @brief Add a new host to broadcast messages to */ |
|
||||||
void setRemoteHost(const QString& host); |
|
||||||
/** @brief Send new control states to the simulation */ |
|
||||||
void updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode); |
|
||||||
/** @brief Send new control commands to the simulation */ |
|
||||||
void updateActuatorControls(quint64 time, quint64 flags, |
|
||||||
float ctl_0, |
|
||||||
float ctl_1, |
|
||||||
float ctl_2, |
|
||||||
float ctl_3, |
|
||||||
float ctl_4, |
|
||||||
float ctl_5, |
|
||||||
float ctl_6, |
|
||||||
float ctl_7, |
|
||||||
float ctl_8, |
|
||||||
float ctl_9, |
|
||||||
float ctl_10, |
|
||||||
float ctl_11, |
|
||||||
float ctl_12, |
|
||||||
float ctl_13, |
|
||||||
float ctl_14, |
|
||||||
float ctl_15, |
|
||||||
quint8 mode); |
|
||||||
/** @brief Set the simulator version as text string */ |
|
||||||
void setVersion(const QString& version); |
|
||||||
/** @brief Set the simulator version as integer */ |
|
||||||
void setVersion(unsigned int version); |
|
||||||
|
|
||||||
void enableSensorHIL(bool enable) { |
|
||||||
if (enable != _sensorHilEnabled) { |
|
||||||
_sensorHilEnabled = enable; |
|
||||||
emit sensorHilChanged(enable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void enableHilActuatorControls(bool enable); |
|
||||||
|
|
||||||
void processError(QProcess::ProcessError err); |
|
||||||
|
|
||||||
void readBytes(); |
|
||||||
|
|
||||||
private slots: |
|
||||||
/**
|
|
||||||
* @brief Write a number of bytes to the interface. |
|
||||||
* |
|
||||||
* @param data Pointer to the data byte array |
|
||||||
* @param size The size of the bytes array |
|
||||||
**/ |
|
||||||
void _writeBytes(const QByteArray data); |
|
||||||
|
|
||||||
public slots: |
|
||||||
bool connectSimulation(); |
|
||||||
bool disconnectSimulation(); |
|
||||||
/**
|
|
||||||
* @brief Select airplane model |
|
||||||
* @param plane the name of the airplane |
|
||||||
*/ |
|
||||||
void selectAirframe(const QString& airframe); |
|
||||||
/**
|
|
||||||
* @brief Set the airplane position and attitude |
|
||||||
* @param lat |
|
||||||
* @param lon |
|
||||||
* @param alt |
|
||||||
* @param roll |
|
||||||
* @param pitch |
|
||||||
* @param yaw |
|
||||||
*/ |
|
||||||
void setPositionAttitude(double lat, double lon, double alt, double roll, double pitch, double yaw); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set a random position |
|
||||||
*/ |
|
||||||
void setRandomPosition(); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set a random attitude |
|
||||||
*/ |
|
||||||
void setRandomAttitude(); |
|
||||||
|
|
||||||
protected: |
|
||||||
Vehicle* _vehicle; |
|
||||||
QString name; |
|
||||||
QHostAddress localHost; |
|
||||||
quint16 localPort; |
|
||||||
QHostAddress remoteHost; |
|
||||||
quint16 remotePort; |
|
||||||
int id; |
|
||||||
QUdpSocket* socket; |
|
||||||
bool connectState; |
|
||||||
|
|
||||||
quint64 bitsSentTotal; |
|
||||||
quint64 bitsSentCurrent; |
|
||||||
quint64 bitsSentMax; |
|
||||||
quint64 bitsReceivedTotal; |
|
||||||
quint64 bitsReceivedCurrent; |
|
||||||
quint64 bitsReceivedMax; |
|
||||||
quint64 connectionStartTime; |
|
||||||
QMutex statisticsMutex; |
|
||||||
QMutex dataMutex; |
|
||||||
QTimer refreshTimer; |
|
||||||
QProcess* process; |
|
||||||
QProcess* terraSync; |
|
||||||
|
|
||||||
bool gpsReceived; |
|
||||||
bool attitudeReceived; |
|
||||||
|
|
||||||
float roll, pitch, yaw, rollspeed, pitchspeed, yawspeed; |
|
||||||
double lat, lon, alt, alt_agl; |
|
||||||
float vx, vy, vz, xacc, yacc, zacc; |
|
||||||
float ind_airspeed; |
|
||||||
float true_airspeed; |
|
||||||
float groundspeed; |
|
||||||
float xmag, ymag, zmag, abs_pressure, diff_pressure, pressure_alt, temperature; |
|
||||||
float barometerOffsetkPa; |
|
||||||
|
|
||||||
float man_roll, man_pitch, man_yaw; |
|
||||||
QString airframeName; |
|
||||||
enum AIRFRAME airframeID; |
|
||||||
bool xPlaneConnected; |
|
||||||
unsigned int xPlaneVersion; |
|
||||||
quint64 simUpdateLast; |
|
||||||
quint64 simUpdateFirst; |
|
||||||
quint64 simUpdateLastText; |
|
||||||
quint64 simUpdateLastGroundTruth; |
|
||||||
float simUpdateHz; |
|
||||||
bool _sensorHilEnabled; |
|
||||||
bool _useHilActuatorControls; |
|
||||||
bool _should_exit; |
|
||||||
|
|
||||||
void setName(QString name); |
|
||||||
void sendDataRef(QString ref, float value); |
|
||||||
}; |
|
||||||
|
|
Loading…
Reference in new issue