2 ******************************************************************************
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup HITLPlugin HITL Plugin
10 * @brief The Hardware In The Loop plugin
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "simulator.h"
30 #include "hitlnoisegeneration.h"
32 #include <extensionsystem/pluginmanager.h>
33 #include <coreplugin/icore.h>
34 #include <coreplugin/threadmanager.h>
35 #include <uavtalk/telemetrymanager.h>
37 volatile bool Simulator::isStarted
= false;
39 const float Simulator::GEE
= 9.81;
40 const float Simulator::FT2M
= 0.3048;
41 const float Simulator::KT2MPS
= 0.514444444;
42 const float Simulator::INHG2KPA
= 3.386;
43 const float Simulator::FPS2CMPS
= 30.48;
44 const float Simulator::DEG2RAD
= (M_PI
/ 180.0);
45 const float Simulator::RAD2DEG
= (180.0 / M_PI
);
48 Simulator::Simulator(const SimulatorSettings
& params
) :
56 autopilotConnectionStatus(false),
57 simConnectionStatus(false),
63 moveToThread(Core::ICore::instance()->threadManager()->getRealTimeThread());
64 connect(this, SIGNAL(myStart()), this, SLOT(onStart()), Qt::QueuedConnection
);
67 QTime currentTime
= QTime::currentTime();
68 gpsPosTime
= currentTime
;
69 groundTruthTime
= currentTime
;
70 gcsRcvrTime
= currentTime
;
71 attRawTime
= currentTime
;
72 baroAltTime
= currentTime
;
73 battTime
= currentTime
;
74 airspeedStateTime
= currentTime
;
76 // Define standard atmospheric constants
77 airParameters
.univGasConstant
= 8.31447; // [J/(mol·K)]
78 airParameters
.dryAirConstant
= 287.058; // [J/(kg*K)]
79 airParameters
.groundDensity
= 1.225; // [kg/m^3]
80 airParameters
.groundTemp
= 15 + 273.15; // [K]
81 airParameters
.tempLapseRate
= 0.0065; // [deg/m]
82 airParameters
.M
= 0.0289644; // [kg/mol]
83 airParameters
.relativeHumidity
= 20; // [%]
84 airParameters
.seaLevelPress
= 101.325; // [kPa]
87 Simulator::~Simulator()
108 // NOTE: Does not currently work, may need to send control+c to through the terminal
109 if (simProcess
!= NULL
) {
110 // connect(simProcess,SIGNAL(finished(int, QProcess::ExitStatus)),this,SLOT(onFinished(int, QProcess::ExitStatus)));
112 simProcess
->disconnect();
113 if (simProcess
->state() == QProcess::Running
) {
116 // if(simProcess->waitForFinished())
117 // emit deleteSimProcess();
123 void Simulator::onDeleteSimulator(void)
126 Simulator::setStarted(false);
128 Simulator::Instances().removeOne(simulatorId
);
134 void Simulator::onStart()
136 QMutexLocker
locker(&lock
);
138 QThread
*mainThread
= QThread::currentThread();
140 qDebug() << "Simulator Thread: " << mainThread
;
142 // Get required UAVObjects
143 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
144 UAVObjectManager
*objManager
= pm
->getObject
<UAVObjectManager
>();
145 actDesired
= ActuatorDesired::GetInstance(objManager
);
146 actCommand
= ActuatorCommand::GetInstance(objManager
);
147 manCtrlCommand
= ManualControlCommand::GetInstance(objManager
);
148 gcsReceiver
= GCSReceiver::GetInstance(objManager
);
149 flightStatus
= FlightStatus::GetInstance(objManager
);
150 posHome
= HomeLocation::GetInstance(objManager
);
151 velState
= VelocityState::GetInstance(objManager
);
152 posState
= PositionState::GetInstance(objManager
);
153 baroAlt
= BaroSensor::GetInstance(objManager
);
154 flightBatt
= FlightBatteryState::GetInstance(objManager
);
155 airspeedState
= AirspeedState::GetInstance(objManager
);
156 attState
= AttitudeState::GetInstance(objManager
);
157 attSettings
= AttitudeSettings::GetInstance(objManager
);
158 accelState
= AccelState::GetInstance(objManager
);
159 gyroState
= GyroState::GetInstance(objManager
);
160 gpsPos
= GPSPositionSensor::GetInstance(objManager
);
161 gpsVel
= GPSVelocitySensor::GetInstance(objManager
);
162 telStats
= GCSTelemetryStats::GetInstance(objManager
);
163 groundTruth
= GroundTruth::GetInstance(objManager
);
165 // Listen to autopilot connection events
166 TelemetryManager
*telMngr
= pm
->getObject
<TelemetryManager
>();
167 connect(telMngr
, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
168 connect(telMngr
, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect()));
169 // connect(telStats, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(telStatsUpdated(UAVObject*)));
171 // If already connect setup autopilot
172 GCSTelemetryStats::DataFields stats
= telStats
->getData();
173 if (stats
.Status
== GCSTelemetryStats::STATUS_CONNECTED
) {
174 onAutopilotConnect();
177 inSocket
= new QUdpSocket();
178 outSocket
= new QUdpSocket();
179 setupUdpPorts(settings
.hostAddress
, settings
.inPort
, settings
.outPort
);
181 emit
processOutput("\nLocal interface: " + settings
.hostAddress
+ "\n" + \
182 "Remote interface: " + settings
.remoteAddress
+ "\n" + \
183 "inputPort: " + QString::number(settings
.inPort
) + "\n" + \
184 "outputPort: " + QString::number(settings
.outPort
) + "\n");
186 qDebug() << ("\nLocal interface: " + settings
.hostAddress
+ "\n" + \
187 "Remote interface: " + settings
.remoteAddress
+ "\n" + \
188 "inputPort: " + QString::number(settings
.inPort
) + "\n" + \
189 "outputPort: " + QString::number(settings
.outPort
) + "\n");
191 // if(!inSocket->waitForConnected(5000))
192 // emit processOutput(QString("Can't connect to %1 on %2 port!").arg(settings.hostAddress).arg(settings.inPort));
193 // outSocket->connectToHost(settings.hostAddress,settings.outPort); // FG
194 // if(!outSocket->waitForConnected(5000))
195 // emit processOutput(QString("Can't connect to %1 on %2 port!").arg(settings.hostAddress).arg(settings.outPort));
198 connect(inSocket
, SIGNAL(readyRead()), this, SLOT(receiveUpdate()), Qt::DirectConnection
);
200 // Setup transmit timer
201 txTimer
= new QTimer();
202 connect(txTimer
, SIGNAL(timeout()), this, SLOT(transmitUpdate()), Qt::DirectConnection
);
203 txTimer
->setInterval(updatePeriod
);
205 // Setup simulator connection timer
206 simTimer
= new QTimer();
207 connect(simTimer
, SIGNAL(timeout()), this, SLOT(onSimulatorConnectionTimeout()), Qt::DirectConnection
);
208 simTimer
->setInterval(simTimeout
);
218 void Simulator::receiveUpdate()
220 // Update connection timer and status
221 simTimer
->setInterval(simTimeout
);
224 if (!simConnectionStatus
) {
225 simConnectionStatus
= true;
226 emit
simulatorConnected();
230 while (inSocket
->hasPendingDatagrams()) {
233 datagram
.resize(inSocket
->pendingDatagramSize());
236 inSocket
->readDatagram(datagram
.data(), datagram
.size(),
237 &sender
, &senderPort
);
238 // QString datastr(datagram);
239 // Process incomming data
240 processUpdate(datagram
);
244 void Simulator::setupObjects()
246 if (settings
.gcsReceiverEnabled
) {
247 setupInputObject(actCommand
, settings
.minOutputPeriod
); // Input to the simulator
248 setupOutputObject(gcsReceiver
, settings
.minOutputPeriod
);
249 } else if (settings
.manualControlEnabled
) {
250 setupInputObject(actDesired
, settings
.minOutputPeriod
); // Input to the simulator
253 setupOutputObject(posHome
, 10000); // Hardcoded? Bleh.
255 if (settings
.gpsPositionEnabled
) {
256 setupOutputObject(gpsPos
, settings
.gpsPosRate
);
257 setupOutputObject(gpsVel
, settings
.gpsPosRate
);
260 if (settings
.groundTruthEnabled
) {
261 setupOutputObject(posState
, settings
.groundTruthRate
);
262 setupOutputObject(velState
, settings
.groundTruthRate
);
265 if (settings
.attRawEnabled
) {
266 setupOutputObject(accelState
, settings
.attRawRate
);
267 setupOutputObject(gyroState
, settings
.attRawRate
);
270 if (settings
.attStateEnabled
&& settings
.attActHW
) {
271 setupOutputObject(accelState
, settings
.attRawRate
);
272 setupOutputObject(gyroState
, settings
.attRawRate
);
275 if (settings
.attStateEnabled
&& !settings
.attActHW
) {
276 setupOutputObject(attState
, 20); // Hardcoded? Bleh.
278 setupWatchedObject(attState
, 100); // Hardcoded? Bleh.
280 if (settings
.airspeedStateEnabled
) {
281 setupOutputObject(airspeedState
, settings
.airspeedStateRate
);
284 if (settings
.baroSensorEnabled
) {
285 setupOutputObject(baroAlt
, settings
.baroAltRate
);
286 setupOutputObject(flightBatt
, settings
.baroAltRate
);
291 void Simulator::setupInputObject(UAVObject
*obj
, quint32 updatePeriod
)
293 UAVObject::Metadata mdata
;
295 mdata
= obj
->getDefaultMetadata();
297 UAVObject::SetGcsAccess(mdata
, UAVObject::ACCESS_READONLY
);
298 UAVObject::SetGcsTelemetryAcked(mdata
, false);
299 UAVObject::SetGcsTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_MANUAL
);
300 mdata
.gcsTelemetryUpdatePeriod
= 0;
302 UAVObject::SetFlightAccess(mdata
, UAVObject::ACCESS_READWRITE
);
303 UAVObject::SetFlightTelemetryAcked(mdata
, false);
305 UAVObject::SetFlightTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_PERIODIC
);
306 mdata
.flightTelemetryUpdatePeriod
= updatePeriod
;
308 obj
->setMetadata(mdata
);
312 void Simulator::setupWatchedObject(UAVObject
*obj
, quint32 updatePeriod
)
314 UAVObject::Metadata mdata
;
316 mdata
= obj
->getDefaultMetadata();
318 UAVObject::SetGcsAccess(mdata
, UAVObject::ACCESS_READONLY
);
319 UAVObject::SetGcsTelemetryAcked(mdata
, false);
320 UAVObject::SetGcsTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_MANUAL
);
321 mdata
.gcsTelemetryUpdatePeriod
= 0;
323 UAVObject::SetFlightAccess(mdata
, UAVObject::ACCESS_READWRITE
);
324 UAVObject::SetFlightTelemetryAcked(mdata
, false);
325 UAVObject::SetFlightTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_PERIODIC
);
326 mdata
.flightTelemetryUpdatePeriod
= updatePeriod
;
328 obj
->setMetadata(mdata
);
332 void Simulator::setupOutputObject(UAVObject
*obj
, quint32 updatePeriod
)
334 UAVObject::Metadata mdata
;
336 mdata
= obj
->getDefaultMetadata();
338 UAVObject::SetGcsAccess(mdata
, UAVObject::ACCESS_READWRITE
);
339 UAVObject::SetGcsTelemetryAcked(mdata
, false);
340 UAVObject::SetGcsTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_PERIODIC
);
341 mdata
.gcsTelemetryUpdatePeriod
= updatePeriod
;
343 UAVObject::SetFlightAccess(mdata
, UAVObject::ACCESS_READONLY
);
344 UAVObject::SetFlightTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_MANUAL
);
346 obj
->setMetadata(mdata
);
349 void Simulator::onAutopilotConnect()
351 autopilotConnectionStatus
= true;
353 emit
autopilotConnected();
356 void Simulator::onAutopilotDisconnect()
358 autopilotConnectionStatus
= false;
359 emit
autopilotDisconnected();
362 void Simulator::onSimulatorConnectionTimeout()
364 if (simConnectionStatus
) {
365 simConnectionStatus
= false;
366 emit
simulatorDisconnected();
371 void Simulator::telStatsUpdated(UAVObject
*obj
)
375 GCSTelemetryStats::DataFields stats
= telStats
->getData();
376 if (!autopilotConnectionStatus
&& stats
.Status
== GCSTelemetryStats::STATUS_CONNECTED
) {
377 onAutopilotConnect();
378 } else if (autopilotConnectionStatus
&& stats
.Status
!= GCSTelemetryStats::STATUS_CONNECTED
) {
379 onAutopilotDisconnect();
384 void Simulator::resetInitialHomePosition()
390 void Simulator::updateUAVOs(Output2Hardware out
)
392 QTime currentTime
= QTime::currentTime();
395 HitlNoiseGeneration noiseSource
;
397 if (settings
.addNoise
) {
398 noise
= noiseSource
.generateNoise();
400 memset(&noise
, 0, sizeof(Noise
));
403 /*******************************/
404 HomeLocation::DataFields homeData
= posHome
->getData();
406 // Upon startup, we reset the HomeLocation object to
407 // the plane's location:
408 memset(&homeData
, 0, sizeof(HomeLocation::DataFields
));
409 // Update homelocation
410 homeData
.Latitude
= out
.latitude
; // Already in *10^7 integer format
411 homeData
.Longitude
= out
.longitude
; // Already in *10^7 integer format
412 homeData
.Altitude
= out
.agl
;
417 posHome
->setData(homeData
);
420 // Compute initial distance
428 /*******************************/
429 // Copy everything to the ground truth object. GroundTruth is Noise-free.
430 GroundTruth::DataFields groundTruthData
;
431 groundTruthData
= groundTruth
->getData();
433 groundTruthData
.AccelerationXYZ
[0] = out
.accX
;
434 groundTruthData
.AccelerationXYZ
[1] = out
.accY
;
435 groundTruthData
.AccelerationXYZ
[2] = out
.accZ
;
437 groundTruthData
.AngularRates
[0] = out
.rollRate
;
438 groundTruthData
.AngularRates
[1] = out
.pitchRate
;
439 groundTruthData
.AngularRates
[2] = out
.yawRate
;
441 groundTruthData
.CalibratedAirspeed
= out
.calibratedAirspeed
;
442 groundTruthData
.TrueAirspeed
= out
.trueAirspeed
;
443 groundTruthData
.AngleOfAttack
= out
.angleOfAttack
;
444 groundTruthData
.AngleOfSlip
= out
.angleOfSlip
;
446 groundTruthData
.PositionNED
[0] = out
.dstN
- initN
;
447 groundTruthData
.PositionNED
[1] = out
.dstE
- initD
;
448 groundTruthData
.PositionNED
[2] = out
.dstD
- initD
;
450 groundTruthData
.VelocityNED
[0] = out
.velNorth
;
451 groundTruthData
.VelocityNED
[1] = out
.velEast
;
452 groundTruthData
.VelocityNED
[2] = out
.velDown
;
454 groundTruthData
.RPY
[0] = out
.roll
;
455 groundTruthData
.RPY
[0] = out
.pitch
;
456 groundTruthData
.RPY
[0] = out
.heading
;
459 groundTruth
->setData(groundTruthData
);
461 /*******************************/
462 // Update attState object
463 AttitudeState::DataFields attStateData
;
464 attStateData
= attState
->getData();
466 if (settings
.attActHW
) {
468 /*****************************************/
469 } else if (settings
.attActSim
) {
470 // take all data from simulator
471 attStateData
.Roll
= out
.roll
+ noise
.attStateData
.Roll
; // roll;
472 attStateData
.Pitch
= out
.pitch
+ noise
.attStateData
.Pitch
; // pitch
473 attStateData
.Yaw
= out
.heading
+ noise
.attStateData
.Yaw
; // Yaw
476 rpy
[0] = attStateData
.Roll
;
477 rpy
[1] = attStateData
.Pitch
;
478 rpy
[2] = attStateData
.Yaw
;
479 Utils::CoordinateConversions().RPY2Quaternion(rpy
, quat
);
480 attStateData
.q1
= quat
[0];
481 attStateData
.q2
= quat
[1];
482 attStateData
.q3
= quat
[2];
483 attStateData
.q4
= quat
[3];
486 attState
->setData(attStateData
);
487 /*****************************************/
488 } else if (settings
.attActCalc
) {
489 // calculate RPY with code from Attitude module
490 static float q
[4] = { 1, 0, 0, 0 };
491 static float gyro_correct_int2
= 0;
495 AttitudeSettings::DataFields attSettData
= attSettings
->getData();
496 float accelKp
= attSettData
.AccelKp
* 0.1666666666666667;
497 // float accelKi = attSettData.AccelKp * 0.1666666666666667;
498 float yawBiasRate
= attSettData
.YawBiasRate
;
500 // calibrate sensors on arming
501 if (flightStatus
->getData().Armed
== FlightStatus::ARMED_ARMING
) {
506 float gyro
[3] = { out
.rollRate
, out
.pitchRate
, out
.yawRate
};
507 float attRawAcc
[3] = { out
.accX
, out
.accY
, out
.accZ
};
509 // code from Attitude module begin ///////////////////////////////
510 float *accels
= attRawAcc
;
514 // Rotate gravity to body frame and cross with accels
515 grot
[0] = -(2 * (q
[1] * q
[3] - q
[0] * q
[2]));
516 grot
[1] = -(2 * (q
[2] * q
[3] + q
[0] * q
[1]));
517 grot
[2] = -(q
[0] * q
[0] - q
[1] * q
[1] - q
[2] * q
[2] + q
[3] * q
[3]);
521 accel_err
[0] = accels
[1] * grot
[2] - grot
[1] * accels
[2];
522 accel_err
[1] = grot
[0] * accels
[2] - accels
[0] * grot
[2];
523 accel_err
[2] = accels
[0] * grot
[1] - grot
[0] * accels
[1];
526 // Account for accel magnitude
527 float accel_mag
= sqrt(accels
[0] * accels
[0] + accels
[1] * accels
[1] + accels
[2] * accels
[2]);
528 accel_err
[0] /= accel_mag
;
529 accel_err
[1] /= accel_mag
;
530 accel_err
[2] /= accel_mag
;
532 // Accumulate integral of error. Scale here so that units are (deg/s) but Ki has units of s
533 gyro_correct_int2
+= -gyro
[2] * yawBiasRate
;
535 // Correct rates based on error, integral component dealt with in updateSensors
536 gyro
[0] += accel_err
[0] * accelKp
/ dT
;
537 gyro
[1] += accel_err
[1] * accelKp
/ dT
;
538 gyro
[2] += accel_err
[2] * accelKp
/ dT
+ gyro_correct_int2
;
540 // Work out time derivative from INSAlgo writeup
541 // Also accounts for the fact that gyros are in deg/s
543 qdot
[0] = (-q
[1] * gyro
[0] - q
[2] * gyro
[1] - q
[3] * gyro
[2]) * dT
* M_PI
/ 180 / 2;
544 qdot
[1] = (+q
[0] * gyro
[0] - q
[3] * gyro
[1] + q
[2] * gyro
[2]) * dT
* M_PI
/ 180 / 2;
545 qdot
[2] = (+q
[3] * gyro
[0] + q
[0] * gyro
[1] - q
[1] * gyro
[2]) * dT
* M_PI
/ 180 / 2;
546 qdot
[3] = (-q
[2] * gyro
[0] + q
[1] * gyro
[1] + q
[0] * gyro
[2]) * dT
* M_PI
/ 180 / 2;
562 float qmag
= sqrt((q
[0] * q
[0]) + (q
[1] * q
[1]) + (q
[2] * q
[2]) + (q
[3] * q
[3]));
568 // If quaternion has become inappropriately short or is nan reinit.
569 // THIS SHOULD NEVER ACTUALLY HAPPEN
570 if ((fabs(qmag
) < 1e-3) || (qmag
!= qmag
)) {
580 float q0s
, q1s
, q2s
, q3s
;
586 float R13
, R11
, R12
, R23
, R33
;
587 R13
= 2 * (q
[1] * q
[3] - q
[0] * q
[2]);
588 R11
= q0s
+ q1s
- q2s
- q3s
;
589 R12
= 2 * (q
[1] * q
[2] + q
[0] * q
[3]);
590 R23
= 2 * (q
[2] * q
[3] + q
[0] * q
[1]);
591 R33
= q0s
- q1s
- q2s
+ q3s
;
593 rpy2
[1] = RAD2DEG
* asinf(-R13
); // pitch always between -pi/2 to pi/2
594 rpy2
[2] = RAD2DEG
* atan2f(R12
, R11
);
595 rpy2
[0] = RAD2DEG
* atan2f(R23
, R33
);
598 attStateData
.Roll
= rpy2
[0];
599 attStateData
.Pitch
= rpy2
[1];
600 attStateData
.Yaw
= rpy2
[2];
601 attStateData
.q1
= q
[0];
602 attStateData
.q2
= q
[1];
603 attStateData
.q3
= q
[2];
604 attStateData
.q4
= q
[3];
607 attState
->setData(attStateData
);
608 /*****************************************/
611 /*******************************/
612 if (settings
.gcsReceiverEnabled
) {
613 if (gcsRcvrTime
.msecsTo(currentTime
) >= settings
.minOutputPeriod
) {
614 GCSReceiver::DataFields gcsRcvrData
;
615 memset(&gcsRcvrData
, 0, sizeof(GCSReceiver::DataFields
));
617 for (quint16 i
= 0; i
< GCSReceiver::CHANNEL_NUMELEM
; i
++) {
618 gcsRcvrData
.Channel
[i
] = 1500 + (out
.rc_channel
[i
] * 500); // Elements in rc_channel are between -1 and 1
621 gcsReceiver
->setData(gcsRcvrData
);
623 gcsRcvrTime
= gcsRcvrTime
.addMSecs(settings
.minOutputPeriod
);
628 /*******************************/
629 if (settings
.gpsPositionEnabled
) {
630 if (gpsPosTime
.msecsTo(currentTime
) >= settings
.gpsPosRate
) {
631 qDebug() << " GPS time:" << gpsPosTime
<< ", currentTime: " << currentTime
<< ", difference: " << gpsPosTime
.msecsTo(currentTime
);
632 // Update GPS Position objects
633 GPSPositionSensor::DataFields gpsPosData
;
634 memset(&gpsPosData
, 0, sizeof(GPSPositionSensor::DataFields
));
635 gpsPosData
.Altitude
= out
.altitude
+ noise
.gpsPosData
.Altitude
;
636 gpsPosData
.Heading
= out
.heading
+ noise
.gpsPosData
.Heading
;
637 gpsPosData
.Groundspeed
= out
.groundspeed
+ noise
.gpsPosData
.Groundspeed
;
638 gpsPosData
.Latitude
= out
.latitude
+ noise
.gpsPosData
.Latitude
; // Already in *10^7 integer format
639 gpsPosData
.Longitude
= out
.longitude
+ noise
.gpsPosData
.Longitude
; // Already in *10^7 integer format
640 gpsPosData
.GeoidSeparation
= 0.0;
641 gpsPosData
.PDOP
= 3.0;
642 gpsPosData
.VDOP
= gpsPosData
.PDOP
* 1.5;
643 gpsPosData
.Satellites
= 10;
644 gpsPosData
.Status
= GPSPositionSensor::STATUS_FIX3D
;
646 gpsPos
->setData(gpsPosData
);
648 // Update GPS Velocity.{North,East,Down}
649 GPSVelocitySensor::DataFields gpsVelData
;
650 memset(&gpsVelData
, 0, sizeof(GPSVelocitySensor::DataFields
));
651 gpsVelData
.North
= out
.velNorth
+ noise
.gpsVelData
.North
;
652 gpsVelData
.East
= out
.velEast
+ noise
.gpsVelData
.East
;
653 gpsVelData
.Down
= out
.velDown
+ noise
.gpsVelData
.Down
;
655 gpsVel
->setData(gpsVelData
);
657 gpsPosTime
= gpsPosTime
.addMSecs(settings
.gpsPosRate
);
661 /*******************************/
662 // Update VelocityState.{North,East,Down}
663 if (settings
.groundTruthEnabled
) {
664 if (groundTruthTime
.msecsTo(currentTime
) >= settings
.groundTruthRate
) {
665 VelocityState::DataFields velocityStateData
;
666 memset(&velocityStateData
, 0, sizeof(VelocityState::DataFields
));
667 velocityStateData
.North
= out
.velNorth
+ noise
.velocityStateData
.North
;
668 velocityStateData
.East
= out
.velEast
+ noise
.velocityStateData
.East
;
669 velocityStateData
.Down
= out
.velDown
+ noise
.velocityStateData
.Down
;
670 velState
->setData(velocityStateData
);
672 // Update PositionState.{Nort,East,Down}
673 PositionState::DataFields positionStateData
;
674 memset(&positionStateData
, 0, sizeof(PositionState::DataFields
));
675 positionStateData
.North
= (out
.dstN
- initN
) + noise
.positionStateData
.North
;
676 positionStateData
.East
= (out
.dstE
- initE
) + noise
.positionStateData
.East
;
677 positionStateData
.Down
= (out
.dstD
/*-initD*/) + noise
.positionStateData
.Down
;
678 posState
->setData(positionStateData
);
680 groundTruthTime
= groundTruthTime
.addMSecs(settings
.groundTruthRate
);
684 ///*******************************/
685 // if (settings.sonarAltitude) {
686 // static QTime sonarAltTime = currentTime;
687 // if (sonarAltTime.msecsTo(currentTime) >= settings.sonarAltRate) {
688 // SonarAltitude::DataFields sonarAltData;
689 // sonarAltData = sonarAlt->getData();
691 // float sAlt = settings.sonarMaxAlt;
692 //// 0.35 rad ~= 20 degree
693 // if ((agl < (sAlt * 2.0)) && (roll < 0.35) && (pitch < 0.35)) {
694 // float x = agl * qTan(roll);
695 // float y = agl * qTan(pitch);
696 // float h = qSqrt(x*x + y*y + agl*agl);
697 // sAlt = qMin(h, sAlt);
700 // sonarAltData.Altitude = sAlt;
701 // sonarAlt->setData(sonarAltData);
702 // sonarAltTime = currentTime;
706 /*******************************/
707 // Update BaroSensor object
708 if (settings
.baroSensorEnabled
) {
709 if (baroAltTime
.msecsTo(currentTime
) >= settings
.baroAltRate
) {
710 BaroSensor::DataFields baroAltData
;
711 memset(&baroAltData
, 0, sizeof(BaroSensor::DataFields
));
712 baroAltData
.Altitude
= out
.altitude
+ noise
.baroAltData
.Altitude
;
713 baroAltData
.Temperature
= out
.temperature
+ noise
.baroAltData
.Temperature
;
714 baroAltData
.Pressure
= out
.pressure
+ noise
.baroAltData
.Pressure
;
715 baroAlt
->setData(baroAltData
);
717 baroAltTime
= baroAltTime
.addMSecs(settings
.baroAltRate
);
721 /*******************************/
722 // Update FlightBatteryState object
723 if (settings
.baroSensorEnabled
) {
724 if (battTime
.msecsTo(currentTime
) >= settings
.baroAltRate
) {
725 FlightBatteryState::DataFields batteryData
;
726 memset(&batteryData
, 0, sizeof(FlightBatteryState::DataFields
));
727 batteryData
.Voltage
= out
.voltage
;
728 batteryData
.Current
= out
.current
;
729 batteryData
.ConsumedEnergy
= out
.consumption
;
730 flightBatt
->setData(batteryData
);
732 battTime
= battTime
.addMSecs(settings
.baroAltRate
);
736 /*******************************/
737 // Update AirspeedState object
738 if (settings
.airspeedStateEnabled
) {
739 if (airspeedStateTime
.msecsTo(currentTime
) >= settings
.airspeedStateRate
) {
740 AirspeedState::DataFields airspeedStateData
;
741 memset(&airspeedStateData
, 0, sizeof(AirspeedState::DataFields
));
742 airspeedStateData
.CalibratedAirspeed
= out
.calibratedAirspeed
+ noise
.airspeedState
.CalibratedAirspeed
;
743 airspeedStateData
.TrueAirspeed
= out
.trueAirspeed
+ noise
.airspeedState
.TrueAirspeed
;
744 // airspeedStateData.alpha=out.angleOfAttack; // to be implemented
745 // airspeedStateData.beta=out.angleOfSlip;
746 airspeedState
->setData(airspeedStateData
);
748 airspeedStateTime
= airspeedStateTime
.addMSecs(settings
.airspeedStateRate
);
752 /*******************************/
753 // Update raw attitude sensors
754 if (settings
.attRawEnabled
) {
755 if (attRawTime
.msecsTo(currentTime
) >= settings
.attRawRate
) {
756 // Update gyroscope sensor data
757 GyroState::DataFields gyroStateData
;
758 memset(&gyroStateData
, 0, sizeof(GyroState::DataFields
));
759 gyroStateData
.x
= out
.rollRate
+ noise
.gyroStateData
.x
;
760 gyroStateData
.y
= out
.pitchRate
+ noise
.gyroStateData
.y
;
761 gyroStateData
.z
= out
.yawRate
+ noise
.gyroStateData
.z
;
762 gyroState
->setData(gyroStateData
);
764 // Update accelerometer sensor data
765 AccelState::DataFields accelStateData
;
766 memset(&accelStateData
, 0, sizeof(AccelState::DataFields
));
767 accelStateData
.x
= out
.accX
+ noise
.accelStateData
.x
;
768 accelStateData
.y
= out
.accY
+ noise
.accelStateData
.y
;
769 accelStateData
.z
= out
.accZ
+ noise
.accelStateData
.z
;
770 accelState
->setData(accelStateData
);
772 attRawTime
= attRawTime
.addMSecs(settings
.attRawRate
);
778 * calculate air density from altitude. http://en.wikipedia.org/wiki/Density_of_air
780 float Simulator::airDensityFromAltitude(float alt
, AirParameters air
, float gravity
)
782 float p
= airPressureFromAltitude(alt
, air
, gravity
);
783 float rho
= p
* air
.M
/ (air
.univGasConstant
* (air
.groundTemp
- air
.tempLapseRate
* alt
));
789 * @brief Simulator::airPressureFromAltitude Get air pressure from altitude and atmospheric conditions.
790 * @param alt altitude
791 * @param air atmospheric conditions
795 float Simulator::airPressureFromAltitude(float alt
, AirParameters air
, float gravity
)
797 return air
.seaLevelPress
* pow(1 - air
.tempLapseRate
* alt
/ air
.groundTemp
, gravity
* air
.M
/ (air
.univGasConstant
* air
.tempLapseRate
));
801 * @brief Simulator::cas2tas calculate TAS from CAS and altitude. http://en.wikipedia.org/wiki/Airspeed
802 * @param CAS Calibrated airspeed
803 * @param alt altitude
804 * @param air atmospheric conditions
806 * @return True airspeed
808 float Simulator::cas2tas(float CAS
, float alt
, AirParameters air
, float gravity
)
810 float rho
= airDensityFromAltitude(alt
, air
, gravity
);
812 return CAS
* sqrt(air
.groundDensity
/ rho
);
816 * @brief Simulator::tas2cas calculate CAS from TAS and altitude. http://en.wikipedia.org/wiki/Airspeed
817 * @param TAS True airspeed
818 * @param alt altitude
819 * @param air atmospheric conditions
821 * @return Calibrated airspeed
823 float Simulator::tas2cas(float TAS
, float alt
, AirParameters air
, float gravity
)
825 float rho
= airDensityFromAltitude(alt
, air
, gravity
);
827 return TAS
/ sqrt(air
.groundDensity
/ rho
);
831 * @brief Simulator::getAirParameters get air parameters
832 * @return airParameters
834 AirParameters
Simulator::getAirParameters()
836 return airParameters
;
840 * @brief Simulator::setAirParameters set air parameters
841 * @param airParameters
843 void Simulator::setAirParameters(AirParameters airParameters
)
845 this->airParameters
= airParameters
;