2 * Copyright (C) 2016-2017 The LibrePilot Project
3 * Contact: http://www.librepilot.org
5 * This file is part of LibrePilot GCS.
7 * LibrePilot GCS is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * LibrePilot GCS is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>.
21 // ***************************
22 // Common javascript uav utils
23 // ***************************
28 .import UAVTalk.VtolPathFollowerSettings 1.0 as VtolPathFollowerSettings
31 .import UAVTalk.HomeLocation 1.0 as HomeLocation
32 .import UAVTalk.TakeOffLocation 1.0 as TakeOffLocation
35 .import UAVTalk.AuxMagSettings 1.0 as AuxMagSettings
36 .import UAVTalk.FlightBatterySettings 1.0 as FlightBatterySettings
39 .import UAVTalk.RevoSettings 1.0 as RevoSettings
42 .import UAVTalk.HwSettings 1.0 as HwSettings
43 .import UAVTalk.SystemSettings 1.0 as SystemSettings
48 .import UAVTalk.FlightStatus 1.0 as FlightStatus
49 .import UAVTalk.ManualControlCommand 1.0 as ManualControlCommand
50 .import UAVTalk.StabilizationDesired 1.0 as StabilizationDesired
51 .import UAVTalk.VelocityDesired 1.0 as VelocityDesired
54 .import UAVTalk.PathDesired 1.0 as PathDesired
55 .import UAVTalk.WaypointActive 1.0 as WaypointActive
58 .import UAVTalk.FlightBatteryState 1.0 as FlightBatteryState
59 .import UAVTalk.GPSPositionSensor 1.0 as GPSPositionSensor
60 .import UAVTalk.GPSSatellites 1.0 as GPSSatellites
63 .import UAVTalk.AttitudeState 1.0 as AttitudeState
64 .import UAVTalk.MagState 1.0 as MagState
65 .import UAVTalk.NedAccel 1.0 as NedAccel
66 .import UAVTalk.PositionState 1.0 as PositionState
67 .import UAVTalk.VelocityState 1.0 as VelocityState
70 .import UAVTalk.OPLinkStatus 1.0 as OPLinkStatus
71 .import UAVTalk.ReceiverStatus 1.0 as ReceiverStatus
72 .import UAVTalk.SystemAlarms 1.0 as SystemAlarms
74 Qt.include("common.js")
85 return Qt.vector3d(attitudeState.roll, attitudeState.pitch, attitudeState.yaw);
88 function attitudeRoll() {
89 return attitudeState.roll;
92 function attitudePitch() {
93 return attitudeState.pitch;
96 function attitudeYaw() {
97 return attitudeState.yaw;
100 function currentVelocity() {
101 return Math.sqrt(Math.pow(velocityState.north, 2) + Math.pow(velocityState.east, 2));
104 function positionStateDown() {
105 return positionState.down;
108 function velocityStateDown() {
109 return velocityState.down;
112 function nedAccelDown() {
113 return nedAccel.down;
116 function position() {
117 switch(gpsPositionSensor.status) {
118 case GPSPositionSensor.Status.Fix2D:
119 case GPSPositionSensor.Status.Fix3D:
120 case GPSPositionSensor.Status.Fix3DDGNSS:
121 return gpsPosition();
122 case GPSPositionSensor.Status.NoFix:
123 case GPSPositionSensor.Status.NoGPS:
125 return (homeLocation.set == HomeLocation.Set.True) ? homePosition() : defaultPosition();
129 function gpsPosition() {
131 gpsPositionSensor.longitude / 10000000.0,
132 gpsPositionSensor.latitude / 10000000.0,
133 gpsPositionSensor.altitude);
136 function homePosition() {
138 homeLocation.longitude / 10000000.0,
139 homeLocation.latitude / 10000000.0,
140 homeLocation.altitude);
143 function defaultPosition() {
144 return Qt.vector3d(pfdContext.longitude, pfdContext.latitude, pfdContext.altitude);
152 // Hack: detect Coptercontrol with mem free
153 return (freeMemoryBytes() < 3096);
156 function frameType() {
157 var frameTypeText = ["FixedWing", "FixedWingElevon", "FixedWingVtail", "VTOL", "HeliCP", "QuadX", "QuadP",
158 "Hexa+", "Octo+", "Custom", "HexaX", "HexaH", "OctoV", "OctoCoaxP", "OctoCoaxX", "OctoX", "HexaCoax",
159 "Tricopter", "GroundCar", "GroundDiff", "GroundMoto", "GroundBoat", "GroundDiffBoat"];
161 if (frameTypeText.length != SystemSettings.SystemSettingsConstants.AirframeTypeCount) {
162 console.log("uav.js: frameType() do not match systemSettings.airframeType uavo");
165 return frameTypeText[systemSettings.airframeType]
168 function isVtolOrMultirotor() {
169 return ((systemSettings.airframeType > SystemSettings.AirframeType.FixedWingVtail) &&
170 (systemSettings.airframeType < SystemSettings.AirframeType.GroundVehicleCar));
173 function isFixedWing() {
174 return (systemSettings.airframeType <= SystemSettings.AirframeType.FixedWingVtail);
177 function isGroundVehicle() {
178 return (systemSettings.airframeType >= SystemSettings.AirframeType.GroundVehicleCar);
181 function freeMemoryBytes() {
182 return systemStats.heapRemaining;
185 function freeMemoryKBytes() {
186 return (systemStats.heapRemaining / 1024).toFixed(2);
189 function freeMemory() {
190 return (freeMemoryBytes() > 1024) ? freeMemoryKBytes() + "Kb" : freeMemoryBytes() + "bytes";
194 return systemStats.cpuLoad;
198 return systemStats.cpuTemp;
201 function flightTimeValue() {
202 return Math.round(systemStats.flightTime / 1000)
209 function isAttitudeValid() {
210 return (systemAlarms.alarmAttitude == SystemAlarms.Alarm.OK);
213 function isAttitudeNotInitialised() {
214 return (systemAlarms.alarmAttitude == SystemAlarms.Alarm.Uninitialised);
217 function isGpsValid() {
218 return (systemAlarms.alarmGPS == SystemAlarms.Alarm.OK);
221 function isGpsNotInitialised() {
222 return (systemAlarms.alarmGPS == SystemAlarms.Alarm.Uninitialised);
225 function isGpsStatusFix3D() {
226 return ((gpsPositionSensor.status == GPSPositionSensor.Status.Fix3D) || (gpsPositionSensor.status == GPSPositionSensor.Status.Fix3DDGNSS));
229 function isOplmConnected() {
230 return (opLinkStatus.linkState == OPLinkStatus.LinkState.Connected);
233 function oplmRSSI() {
234 return (opLinkStatus.rssi > -13) ? -13 : opLinkStatus.rssi;
237 function oplmDeviceID() {
238 return opLinkStatus.deviceID;
241 function magSourceName() {
242 var auxMagTypeText = ["GPSv9", "Flexi", "I2C", "DJI"];
243 var magStateSourceText = ["Invalid", "OnBoard", "ExtMag"];
245 if ((auxMagTypeText.length != AuxMagSettings.AuxMagSettingsConstants.TypeCount) ||
246 (magStateSourceText.length != MagState.MagStateConstants.SourceCount)) {
247 console.log("uav.js: magSourceName() do not match magState.source or auxMagSettings.type uavo");
250 return [magState.source == MagState.Source.Aux ? auxMagTypeText[auxMagSettings.type] + " " : ""] + magStateSourceText[magState.source];
253 function gpsSensorType() {
254 var gpsSensorTypeText = ["Unknown", "NMEA", "UBX", "UBX7", "UBX8", "DJI"];
256 if (gpsSensorTypeText.length != GPSPositionSensor.GPSPositionSensorConstants.SensorTypeCount) {
257 console.log("uav.js: gpsSensorType() do not match gpsPositionSensor.sensorType uavo");
260 return gpsSensorTypeText[gpsPositionSensor.sensorType];
263 function gpsNumSat() {
264 return gpsPositionSensor.satellites;
267 function gpsSatsInView() {
268 return gpsSatellites.satsInView;
271 function gpsHdopInfo() {
272 return gpsPositionSensor.hdop.toFixed(2) + "/" + gpsPositionSensor.vdop.toFixed(2) + "/" + gpsPositionSensor.pdop.toFixed(2);
275 function gpsAltitude() {
276 return gpsPositionSensor.altitude.toFixed(2);
279 function gpsStatus() {
280 var gpsStatusText = ["NO GPS", "NO FIX", "2D", "3D", "3D"];
282 if (gpsStatusText.length != GPSPositionSensor.GPSPositionSensorConstants.StatusCount) {
283 console.log("uav.js: gpsStatus() do not match gpsPositionSensor.status uavo");
286 return gpsStatusText[gpsPositionSensor.status];
289 function fusionAlgorithm() {
290 var fusionAlgorithmText = ["None", "Basic (No Nav)", "CompMag", "Comp+Mag+GPS", "EKFIndoor", "GPSNav (INS)", "GPSNav (INS+CF)", "Testing (INS Indoor+CF)"];
292 if (fusionAlgorithmText.length != RevoSettings.RevoSettingsConstants.FusionAlgorithmCount) {
293 console.log("uav.js: fusionAlgorithm() do not match revoSettings.fusionAlgorithm uavo");
296 return fusionAlgorithmText[revoSettings.fusionAlgorithm];
299 function receiverQuality() {
300 return (receiverStatus.quality > 0) ? receiverStatus.quality + "%" : "?? %";
303 function oplmLinkState() {
304 var oplmLinkStateText = ["Disabled", "Enabled", "Binding", "Bound", "Disconnected", "Connecting", "Connected"];
306 if (oplmLinkStateText.length != OPLinkStatus.OPLinkStatusConstants.LinkStateCount) {
307 console.log("uav.js: oplmLinkState() do not match opLinkStatus.linkState uavo");
310 return oplmLinkStateText[opLinkStatus.linkState];
317 function batteryModuleEnabled() {
318 return (hwSettings.optionalModulesBattery == HwSettings.OptionalModules.Enabled);
321 function batteryNbCells() {
322 return flightBatterySettings.nbCells;
325 function batteryVoltage() {
326 return flightBatteryState.voltage.toFixed(2);
329 function batteryCurrent() {
330 return flightBatteryState.current.toFixed(2);
333 function batteryConsumedEnergy() {
334 return flightBatteryState.consumedEnergy.toFixed(0);
337 function estimatedFlightTimeValue() {
338 return Math.round(flightBatteryState.estimatedFlightTime);
341 function batteryAlarmColor() {
342 // Uninitialised, Ok, Warning, Critical, Error
343 return ["#2c2929", "green", "orange", "red", "red"][systemAlarms.alarmBattery];
346 function estimatedTimeAlarmColor() {
347 return ((estimatedFlightTimeValue() <= 120) && (estimatedFlightTimeValue() > 60)) ? "orange" :
348 (estimatedFlightTimeValue() <= 60) ? "red" : batteryAlarmColor();
352 * Pathplan and Waypoints
355 function isPathPlanEnabled() {
356 return (flightStatus.flightMode == FlightStatus.FlightMode.PathPlanner);
359 function isPathPlanValid() {
360 return (systemAlarms.alarmPathPlan == SystemAlarms.Alarm.OK);
363 function isPathDesiredActive() {
364 return ((pathDesired.endEast != 0.0) || (pathDesired.endNorth != 0.0) || (pathDesired.endingVelocity != 0.0))
367 function isTakeOffLocationValid() {
368 return (takeOffLocation.status == TakeOffLocation.Status.Valid);
371 function pathModeDesired() {
372 var pathModeDesiredText = ["GOTO ENDPOINT","FOLLOW VECTOR","CIRCLE RIGHT","CIRCLE LEFT","FIXED ATTITUDE",
373 "SET ACCESSORY","DISARM ALARM","LAND","BRAKE","VELOCITY","AUTO TAKEOFF"];
375 if (pathModeDesiredText.length != PathDesired.PathDesiredConstants.ModeCount) {
376 console.log("uav.js: pathModeDesired() do not match pathDesired.mode uavo");
379 return pathModeDesiredText[pathDesired.mode];
382 function velocityDesiredDown() {
383 return velocityDesired.down;
386 function pathDesiredEndDown() {
387 return pathDesired.endDown;
390 function pathDesiredEndingVelocity() {
391 return pathDesired.endingVelocity;
394 function currentWaypointActive() {
395 return (waypointActive.index + 1);
398 function waypointCount() {
399 return pathPlan.waypointCount;
402 function homeHeading() {
403 return 180 / 3.1415 * Math.atan2(takeOffLocation.east - positionState.east, takeOffLocation.north - positionState.north);
406 function waypointHeading() {
407 return 180 / 3.1415 * Math.atan2(pathDesired.endEast - positionState.east, pathDesired.endNorth - positionState.north);
410 function homeDistance() {
411 return Math.sqrt(Math.pow((takeOffLocation.east - positionState.east), 2) +
412 Math.pow((takeOffLocation.north - positionState.north), 2));
415 function waypointDistance() {
416 return Math.sqrt(Math.pow((pathDesired.endEast - positionState.east), 2) +
417 Math.pow((pathDesired.endNorth - positionState.north), 2));
421 * FlightModes, Stabilization, Thrust modes
424 function isFlightModeManual() {
425 return (flightStatus.flightMode == FlightStatus.FlightMode.Manual);
428 function isFlightModeAssisted() {
429 return (flightStatus.flightMode > FlightStatus.FlightMode.Stabilized6);
432 function isVtolPathFollowerSettingsThrustAuto() {
433 return (vtolPathFollowerSettings.thrustControl == VtolPathFollowerSettings.ThrustControl.Auto);
436 function flightModeName() {
437 var flightModeNameText = ["MANUAL", "STAB 1", "STAB 2", "STAB 3", "STAB 4", "STAB 5", "STAB 6",
438 "POS HOLD", "COURSELOCK", "VEL ROAM", "HOME LEASH", "ABS POS", "RTB",
439 "LAND", "PATHPLAN", "POI", "AUTOCRUISE", "AUTOTAKEOFF", "AUTOTUNE"];
441 if (flightModeNameText.length != FlightStatus.FlightStatusConstants.FlightModeCount) {
442 console.log("uav.js: flightModeName() do not match flightStatus.flightMode uavo");
445 return flightModeNameText[flightStatus.flightMode];
448 function flightModeColor() {
449 var flightModeColorText = ["gray", "green", "green", "green", "green", "green", "green",
450 "cyan", "cyan", "cyan", "cyan", "cyan", "cyan",
451 "cyan", "cyan", "cyan", "cyan", "cyan", "cyan"];
453 if (flightModeColorText.length != FlightStatus.FlightStatusConstants.FlightModeCount) {
454 console.log("uav.js: flightModeColor() do not match flightStatus.flightMode uavo");
457 return flightModeColorText[flightStatus.flightMode];
460 function thrustMode() {
461 return !isFlightModeAssisted() ? stabilizationDesired.stabilizationModeThrust :
462 (isFlightModeAssisted() && isVtolOrMultirotor() && isVtolPathFollowerSettingsThrustAuto()) ?
463 StabilizationDesired.StabilizationDesiredConstants.StabilizationModeCount : (isFlightModeAssisted() && isFixedWing()) ?
464 StabilizationDesired.StabilizationDesiredConstants.StabilizationModeCount : 0;
467 function thrustModeName() {
468 // Lower case modes are never displayed/used for Thrust
469 var thrustModeNameText = ["MANUAL", "rate", "ratetrainer", "attitude", "axislock", "weakleveling", "virtualbar", "acro+ ", "rattitude",
470 "ALT HOLD", "ALT VARIO", "CRUISECTRL", "systemident"];
472 // Last "Auto" Thrust mode is added to current UAVO enum list for display.
473 thrustModeNameText.push("AUTO");
475 if (thrustModeNameText.length != StabilizationDesired.StabilizationDesiredConstants.StabilizationModeCount + 1) {
476 console.log("uav.js: thrustModeName() do not match stabilizationDesired.StabilizationMode uavo");
479 return thrustModeNameText[thrustMode()];
482 function thrustModeColor() {
483 var thrustModeColorText = ["green", "grey", "grey", "grey", "grey", "grey", "grey", "grey", "grey",
484 "green", "green", "green", "grey"];
486 // Add the cyan color for AUTO
487 thrustModeColorText.push("cyan");
489 if (thrustModeColorText.length != StabilizationDesired.StabilizationDesiredConstants.StabilizationModeCount + 1) {
490 console.log("uav.js: thrustModeColor() do not match stabilizationDesired.StabilizationMode uavo");
493 return thrustModeColorText[thrustMode()];
496 function armStatusName() {
497 var armStatusNameText = ["DISARMED","ARMING","ARMED"];
499 if (armStatusNameText.length != FlightStatus.FlightStatusConstants.ArmedCount) {
500 console.log("uav.js: armStatusName() do not match flightStatus.armed uavo");
503 return armStatusNameText[flightStatus.armed];
506 function armStatusColor() {
507 var armStatusColorText = ["gray", "orange", "green"];
509 if (armStatusColorText.length != FlightStatus.FlightStatusConstants.ArmedCount) {
510 console.log("uav.js: armStatusColor() do not match flightStatus.armed uavo");
513 return armStatusColorText[flightStatus.armed];
520 function autopilotStatusColor() {
521 return statusColor(systemAlarms.alarmGuidance)
524 function rcInputStatusColor() {
525 return statusColor(systemAlarms.alarmManualControl)
528 function statusColor(module) {
529 return ["gray", "green", "red", "red", "red"][module];
532 function masterCautionWarning() {
533 return ((systemAlarms.alarmBootFault > SystemAlarms.Alarm.OK) ||
534 (systemAlarms.alarmOutOfMemory > SystemAlarms.Alarm.OK) ||
535 (systemAlarms.alarmStackOverflow > SystemAlarms.Alarm.OK) ||
536 (systemAlarms.alarmCPUOverload > SystemAlarms.Alarm.OK) ||
537 (systemAlarms.alarmEventSystem > SystemAlarms.Alarm.OK))