@wemap/providers 5.6.1 → 5.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wemap-providers.es.js +498 -361
- package/dist/wemap-providers.es.js.map +1 -1
- package/package.json +2 -2
- package/src/Providers.js +1 -0
- package/src/ProvidersInterface.js +6 -2
- package/src/events/EventType.js +1 -0
- package/src/providers/attitude/absolute/AbsoluteAttitude.js +58 -8
- package/src/providers/imu/MagnetometerCalibrationDetector.js +67 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { deg2rad, Vector3, Matrix, Quaternion, Matrix3, Matrix4, Vector, Rotations, std, diffAngleLines, diffAngle, rad2deg } from '@wemap/maths';
|
|
2
2
|
import { BrowserUtils, Browser, PromiseUtils, TimeUtils } from '@wemap/utils';
|
|
3
3
|
import Logger from '@wemap/logger';
|
|
4
|
-
import { Attitude, RelativePosition,
|
|
4
|
+
import { Attitude, RelativePosition, Constants as Constants$1, MapMatching, UserPosition, GraphEdge, AbsoluteHeading, GeoRelativePosition as GeoRelativePosition$1, Network } from '@wemap/geo';
|
|
5
5
|
import geomagnetism from '@wemap/geomagnetism';
|
|
6
6
|
import { Itinerary } from '@wemap/osm';
|
|
7
7
|
|
|
@@ -14,6 +14,7 @@ var EventType = {
|
|
|
14
14
|
MagneticField: 'MAGNETIC_FIELD',
|
|
15
15
|
AngularRate: 'ANGULAR_RATE',
|
|
16
16
|
Acceleration: 'ACCELERATION',
|
|
17
|
+
MagnetometerNeedCalibration: 'MAGNETOMETER_NEED_CALIBRATION',
|
|
17
18
|
|
|
18
19
|
RelativeAttitude: 'RELATIVE_ATTITUDE',
|
|
19
20
|
AbsoluteAttitude: 'ABSOLUTE_ATTITUDE',
|
|
@@ -876,6 +877,12 @@ class HighRotationsDetector extends Provider {
|
|
|
876
877
|
|
|
877
878
|
var HighRotationsDetector$1 = new HighRotationsDetector();
|
|
878
879
|
|
|
880
|
+
class MissingMagnetometerError extends MissingSensorError {
|
|
881
|
+
constructor(message) {
|
|
882
|
+
super(message);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
879
886
|
const DEFAULT_RELATIVE_NOISES = {
|
|
880
887
|
acc: 0.5,
|
|
881
888
|
gyr: 0.3
|
|
@@ -1196,86 +1203,6 @@ class RelativeAttitudeFromEkf extends Provider {
|
|
|
1196
1203
|
|
|
1197
1204
|
var RelativeAttitudeFromEkf$1 = new RelativeAttitudeFromEkf();
|
|
1198
1205
|
|
|
1199
|
-
class RelativeAttitudeFromInertial extends Provider {
|
|
1200
|
-
|
|
1201
|
-
/**
|
|
1202
|
-
* default relative attitude drift in rad.second-1
|
|
1203
|
-
*/
|
|
1204
|
-
DEFAULT_DRIFT = deg2rad(5) / 60;
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
/**
|
|
1208
|
-
* @override
|
|
1209
|
-
*/
|
|
1210
|
-
static get pname() {
|
|
1211
|
-
return 'RelativeAttitudeFromInertial';
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
/**
|
|
1215
|
-
* @override
|
|
1216
|
-
*/
|
|
1217
|
-
static get eventsType() {
|
|
1218
|
-
return [EventType.RelativeAttitude];
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
/**
|
|
1222
|
-
* @override
|
|
1223
|
-
*/
|
|
1224
|
-
get _availability() {
|
|
1225
|
-
return PromiseUtils.any([
|
|
1226
|
-
RelativeAttitudeFromEkf$1.availability,
|
|
1227
|
-
RelativeAttitudeFromBrowser$1.availability,
|
|
1228
|
-
HighRotationsDetector$1.availability
|
|
1229
|
-
]);
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
/**
|
|
1233
|
-
* @override
|
|
1234
|
-
*/
|
|
1235
|
-
start() {
|
|
1236
|
-
|
|
1237
|
-
RelativeAttitudeFromEkf$1.availability
|
|
1238
|
-
.then(() => (this.provider = RelativeAttitudeFromEkf$1))
|
|
1239
|
-
.catch(() => (this.provider = RelativeAttitudeFromBrowser$1))
|
|
1240
|
-
.finally(() => {
|
|
1241
|
-
this.listenerId = this.provider.addEventListener(
|
|
1242
|
-
events => this._parseEvent(events[0]),
|
|
1243
|
-
error => this.notifyError(error)
|
|
1244
|
-
);
|
|
1245
|
-
this._highRotationsDetector = HighRotationsDetector$1.addEventListener(
|
|
1246
|
-
() => {},
|
|
1247
|
-
error => this.notifyError(error)
|
|
1248
|
-
);
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
/**
|
|
1253
|
-
* @param {ProviderEvent<Attitude>} event
|
|
1254
|
-
*/
|
|
1255
|
-
_parseEvent(event) {
|
|
1256
|
-
const relativeAttitudeEvent = event.clone();
|
|
1257
|
-
if (HighRotationsDetector$1.isInProgress()) {
|
|
1258
|
-
let accuracy = relativeAttitudeEvent.data.accuracy + (this.DEFAULT_DRIFT * 100);
|
|
1259
|
-
accuracy = Math.min(accuracy, Math.PI);
|
|
1260
|
-
relativeAttitudeEvent.data.accuracy = accuracy;
|
|
1261
|
-
}
|
|
1262
|
-
this.notify(relativeAttitudeEvent);
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
/**
|
|
1266
|
-
* @override
|
|
1267
|
-
*/
|
|
1268
|
-
stop() {
|
|
1269
|
-
if (this.provider) {
|
|
1270
|
-
this.provider.removeEventListener(this.listenerId);
|
|
1271
|
-
this.provider = null;
|
|
1272
|
-
}
|
|
1273
|
-
HighRotationsDetector$1.removeEventListener(this._highRotationsDetector);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
var RelativeAttitudeFromInertial$1 = new RelativeAttitudeFromInertial();
|
|
1278
|
-
|
|
1279
1206
|
/**
|
|
1280
1207
|
* Relative attitude provider gives the device attitude in a custom frame (x-right, y-front, z-up) using
|
|
1281
1208
|
* browser deviceorientation
|
|
@@ -1363,6 +1290,86 @@ class RelativeAttitudeFromBrowser extends Provider {
|
|
|
1363
1290
|
|
|
1364
1291
|
var RelativeAttitudeFromBrowser$1 = new RelativeAttitudeFromBrowser();
|
|
1365
1292
|
|
|
1293
|
+
class RelativeAttitudeFromInertial extends Provider {
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* default relative attitude drift in rad.second-1
|
|
1297
|
+
*/
|
|
1298
|
+
DEFAULT_DRIFT = deg2rad(5) / 60;
|
|
1299
|
+
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* @override
|
|
1303
|
+
*/
|
|
1304
|
+
static get pname() {
|
|
1305
|
+
return 'RelativeAttitudeFromInertial';
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* @override
|
|
1310
|
+
*/
|
|
1311
|
+
static get eventsType() {
|
|
1312
|
+
return [EventType.RelativeAttitude];
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* @override
|
|
1317
|
+
*/
|
|
1318
|
+
get _availability() {
|
|
1319
|
+
return PromiseUtils.any([
|
|
1320
|
+
RelativeAttitudeFromEkf$1.availability,
|
|
1321
|
+
RelativeAttitudeFromBrowser$1.availability,
|
|
1322
|
+
HighRotationsDetector$1.availability
|
|
1323
|
+
]);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* @override
|
|
1328
|
+
*/
|
|
1329
|
+
start() {
|
|
1330
|
+
|
|
1331
|
+
RelativeAttitudeFromEkf$1.availability
|
|
1332
|
+
.then(() => (this.provider = RelativeAttitudeFromEkf$1))
|
|
1333
|
+
.catch(() => (this.provider = RelativeAttitudeFromBrowser$1))
|
|
1334
|
+
.finally(() => {
|
|
1335
|
+
this.listenerId = this.provider.addEventListener(
|
|
1336
|
+
events => this._parseEvent(events[0]),
|
|
1337
|
+
error => this.notifyError(error)
|
|
1338
|
+
);
|
|
1339
|
+
this._highRotationsDetector = HighRotationsDetector$1.addEventListener(
|
|
1340
|
+
() => {},
|
|
1341
|
+
error => this.notifyError(error)
|
|
1342
|
+
);
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* @param {ProviderEvent<Attitude>} event
|
|
1348
|
+
*/
|
|
1349
|
+
_parseEvent(event) {
|
|
1350
|
+
const relativeAttitudeEvent = event.clone();
|
|
1351
|
+
if (HighRotationsDetector$1.isInProgress()) {
|
|
1352
|
+
let accuracy = relativeAttitudeEvent.data.accuracy + (this.DEFAULT_DRIFT * 100);
|
|
1353
|
+
accuracy = Math.min(accuracy, Math.PI);
|
|
1354
|
+
relativeAttitudeEvent.data.accuracy = accuracy;
|
|
1355
|
+
}
|
|
1356
|
+
this.notify(relativeAttitudeEvent);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* @override
|
|
1361
|
+
*/
|
|
1362
|
+
stop() {
|
|
1363
|
+
if (this.provider) {
|
|
1364
|
+
this.provider.removeEventListener(this.listenerId);
|
|
1365
|
+
this.provider = null;
|
|
1366
|
+
}
|
|
1367
|
+
HighRotationsDetector$1.removeEventListener(this._highRotationsDetector);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
var RelativeAttitudeFromInertial$1 = new RelativeAttitudeFromInertial();
|
|
1372
|
+
|
|
1366
1373
|
class MissingArCoreError extends Error {
|
|
1367
1374
|
|
|
1368
1375
|
static DEFAULT_MESSAGE = 'ARCore is missing';
|
|
@@ -1658,327 +1665,70 @@ class RelativeAttitude extends Provider {
|
|
|
1658
1665
|
|
|
1659
1666
|
var RelativeAttitude$1 = new RelativeAttitude();
|
|
1660
1667
|
|
|
1661
|
-
class
|
|
1662
|
-
constructor(message) {
|
|
1663
|
-
super(message);
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
/**
|
|
1668
|
-
* Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
|
|
1669
|
-
*/
|
|
1670
|
-
class AbsoluteAttitude extends Provider {
|
|
1671
|
-
|
|
1672
|
-
/** @type {boolean} */
|
|
1673
|
-
_attitudeFromBrowserErrored = false;
|
|
1674
|
-
|
|
1675
|
-
/** @type {boolean} */
|
|
1676
|
-
_attitudeFromRelativeErrored = false;
|
|
1677
|
-
|
|
1678
|
-
/*
|
|
1679
|
-
* RELATIVE
|
|
1680
|
-
*/
|
|
1681
|
-
|
|
1682
|
-
/** @type {Attitude} */
|
|
1683
|
-
_relativeAttitude = null;
|
|
1684
|
-
|
|
1685
|
-
/** @type {number} in radians/s */
|
|
1686
|
-
_relativeAccuracy = 0;
|
|
1687
|
-
|
|
1688
|
-
/** @type {ProviderEvent<Attitude|AbsoluteHeading>} */
|
|
1689
|
-
_lastForcedHeadingEvent;
|
|
1668
|
+
class TurnDetector extends Provider {
|
|
1690
1669
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1670
|
+
// in seconds
|
|
1671
|
+
static SLIDING_WINDOW_TIME = 0.3;
|
|
1693
1672
|
|
|
1673
|
+
static STD_THRESHOLD = 0.075;
|
|
1694
1674
|
|
|
1695
|
-
|
|
1696
|
-
|
|
1675
|
+
/** @type {number} in seconds */
|
|
1676
|
+
static CONSIDER_TURN_UNTIL = 1;
|
|
1697
1677
|
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
}
|
|
1678
|
+
/** @type {number[]} */
|
|
1679
|
+
slidingWindow = [];
|
|
1701
1680
|
|
|
1702
1681
|
/**
|
|
1703
1682
|
* @override
|
|
1704
1683
|
*/
|
|
1705
1684
|
static get pname() {
|
|
1706
|
-
return '
|
|
1685
|
+
return 'TurnDetector';
|
|
1707
1686
|
}
|
|
1708
1687
|
|
|
1709
1688
|
/**
|
|
1710
1689
|
* @override
|
|
1711
1690
|
*/
|
|
1712
1691
|
static get eventsType() {
|
|
1713
|
-
return [EventType.
|
|
1692
|
+
return [EventType.Turn];
|
|
1714
1693
|
}
|
|
1715
1694
|
|
|
1716
1695
|
/**
|
|
1717
1696
|
* @override
|
|
1718
1697
|
*/
|
|
1719
1698
|
get _availability() {
|
|
1720
|
-
return
|
|
1721
|
-
AbsoluteAttitudeFromBrowser$1.availability,
|
|
1722
|
-
RelativeAttitude$1.availability
|
|
1723
|
-
]);
|
|
1699
|
+
return RelativeAttitude$1.availability;
|
|
1724
1700
|
}
|
|
1725
1701
|
|
|
1726
1702
|
/**
|
|
1727
1703
|
* @override
|
|
1728
1704
|
*/
|
|
1729
1705
|
start() {
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
error => {
|
|
1734
|
-
this._attitudeFromBrowserErrored = true;
|
|
1735
|
-
this.onError(error);
|
|
1736
|
-
}
|
|
1737
|
-
);
|
|
1738
|
-
|
|
1739
|
-
this.relativeAttitudeProviderId = RelativeAttitude$1.addEventListener(
|
|
1740
|
-
events => this._onRelativeAttitudeEvent(events[0]),
|
|
1741
|
-
error => {
|
|
1742
|
-
this._attitudeFromRelativeErrored = true;
|
|
1743
|
-
this.onError(error);
|
|
1744
|
-
}
|
|
1706
|
+
this.providerId = RelativeAttitude$1.addEventListener(
|
|
1707
|
+
events => this._parseRelativeAttitude(events[0]),
|
|
1708
|
+
error => this.notifyError(error)
|
|
1745
1709
|
);
|
|
1746
|
-
|
|
1747
1710
|
}
|
|
1748
1711
|
|
|
1749
1712
|
/**
|
|
1750
1713
|
* @override
|
|
1751
1714
|
*/
|
|
1752
1715
|
stop() {
|
|
1753
|
-
|
|
1754
|
-
RelativeAttitude$1.removeEventListener(this.relativeAttitudeProviderId);
|
|
1716
|
+
RelativeAttitude$1.removeEventListener(this.providerId);
|
|
1755
1717
|
}
|
|
1756
1718
|
|
|
1757
|
-
|
|
1758
|
-
if (this.
|
|
1759
|
-
|
|
1719
|
+
isTurning() {
|
|
1720
|
+
if (!this.lastEvent || !RelativeAttitude$1.lastEvent) {
|
|
1721
|
+
return false;
|
|
1760
1722
|
}
|
|
1761
|
-
}
|
|
1762
1723
|
|
|
1724
|
+
const diffTime = RelativeAttitude$1.lastEvent.data.time - this.lastEvent.data.timestamp;
|
|
1725
|
+
return diffTime < TurnDetector.CONSIDER_TURN_UNTIL;
|
|
1726
|
+
}
|
|
1763
1727
|
|
|
1764
1728
|
/**
|
|
1765
|
-
* @
|
|
1729
|
+
* @private
|
|
1766
1730
|
*/
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
if (this.lastEvent && absoluteHeadingEvent.data.accuracy > this.lastEvent.data.accuracy) {
|
|
1770
|
-
return;
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
/**
|
|
1775
|
-
* @param {Attitude} relativeAttitude
|
|
1776
|
-
*/
|
|
1777
|
-
const calcForceHeading = (relativeAttitude) => {
|
|
1778
|
-
const currentRelativeHeading = relativeAttitude.heading;
|
|
1779
|
-
|
|
1780
|
-
this._relAbsQuat = Quaternion.fromAxisAngle(
|
|
1781
|
-
[0, 0, 1],
|
|
1782
|
-
currentRelativeHeading - absoluteHeadingEvent.data.heading
|
|
1783
|
-
);
|
|
1784
|
-
|
|
1785
|
-
this._relativeAccuracy = 0;
|
|
1786
|
-
this._lastForcedHeadingEvent = absoluteHeadingEvent;
|
|
1787
|
-
};
|
|
1788
|
-
|
|
1789
|
-
// If relativeAttitude does not exist yet, wait the next
|
|
1790
|
-
if (this._relativeAttitude) {
|
|
1791
|
-
calcForceHeading(this._relativeAttitude);
|
|
1792
|
-
return;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
// If this._relativeAttitude does not exist, wait the first value
|
|
1796
|
-
// /!\ This works only if the relative attitude event is provided rapidly.
|
|
1797
|
-
const providerId = RelativeAttitude$1.addEventListener(
|
|
1798
|
-
events => {
|
|
1799
|
-
calcForceHeading(events[0].data);
|
|
1800
|
-
RelativeAttitude$1.removeEventListener(providerId);
|
|
1801
|
-
}
|
|
1802
|
-
);
|
|
1803
|
-
|
|
1804
|
-
};
|
|
1805
|
-
|
|
1806
|
-
/**
|
|
1807
|
-
* @param {ProviderEvent<Attitude>} event
|
|
1808
|
-
*/
|
|
1809
|
-
_onRelativeAttitudeEvent(event) {
|
|
1810
|
-
|
|
1811
|
-
const { quaternion, accuracy, time } = event.data;
|
|
1812
|
-
|
|
1813
|
-
// Calculate relative accuracy
|
|
1814
|
-
if (this._relativeAttitude) {
|
|
1815
|
-
this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
// Keep the relative attitude event for the calculation of relAbsQuat
|
|
1819
|
-
// /!\ Keep this even if forced heading is not set /!\
|
|
1820
|
-
this._relativeAttitude = event.data;
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
if (!this._lastForcedHeadingEvent) {
|
|
1824
|
-
return;
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
const accuracyWithRelative = Math.min(
|
|
1828
|
-
this._lastForcedHeadingEvent.data.accuracy + this._relativeAccuracy,
|
|
1829
|
-
Math.PI
|
|
1830
|
-
);
|
|
1831
|
-
|
|
1832
|
-
let newAccuracy = accuracyWithRelative;
|
|
1833
|
-
let relAbsQuat = this._relAbsQuat;
|
|
1834
|
-
|
|
1835
|
-
if (this._eventFromBrowser) {
|
|
1836
|
-
|
|
1837
|
-
const {
|
|
1838
|
-
accuracy: accuracyWithAbsolute,
|
|
1839
|
-
heading: headingFromAbsolute
|
|
1840
|
-
} = this._eventFromBrowser.data;
|
|
1841
|
-
|
|
1842
|
-
if (accuracyWithAbsolute < accuracyWithRelative) {
|
|
1843
|
-
newAccuracy = accuracyWithAbsolute;
|
|
1844
|
-
relAbsQuat = Quaternion.fromAxisAngle([0, 0, 1], event.data.heading - headingFromAbsolute);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
const absoluteQuat = Quaternion.multiply(relAbsQuat, quaternion);
|
|
1849
|
-
const attitude = new Attitude(absoluteQuat, time, newAccuracy);
|
|
1850
|
-
|
|
1851
|
-
this.notify(this.createEvent(
|
|
1852
|
-
EventType.AbsoluteAttitude,
|
|
1853
|
-
attitude,
|
|
1854
|
-
[event, this._lastForcedHeadingEvent]
|
|
1855
|
-
));
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
/**
|
|
1860
|
-
* @param {ProviderEvent<Attitude>} event
|
|
1861
|
-
*/
|
|
1862
|
-
_onAttitudeFromBrowser(event) {
|
|
1863
|
-
this._eventFromBrowser = event;
|
|
1864
|
-
|
|
1865
|
-
if (!this._lastForcedHeadingEvent) {
|
|
1866
|
-
this._forceHeadingForRelative(event);
|
|
1867
|
-
return;
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
// Absolute attitude from browser is not used anymore due to magnetometer inaccuracy on pitch and roll
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
/**
|
|
1874
|
-
* @override
|
|
1875
|
-
* @param {AbsoluteHeading|Attitude|ProviderEvent} data
|
|
1876
|
-
*/
|
|
1877
|
-
feed(data) {
|
|
1878
|
-
|
|
1879
|
-
if (data instanceof AbsoluteHeading) {
|
|
1880
|
-
|
|
1881
|
-
if (data.time === null) {
|
|
1882
|
-
throw Error('the time of the absolute heading is not defined');
|
|
1883
|
-
}
|
|
1884
|
-
if (data.accuracy === null) {
|
|
1885
|
-
throw Error('the accuracy of the absolute heading is not defined');
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
|
|
1889
|
-
|
|
1890
|
-
} else if (data instanceof Attitude) {
|
|
1891
|
-
|
|
1892
|
-
if (data.time === null) {
|
|
1893
|
-
throw Error('the time of the attitude is not defined');
|
|
1894
|
-
}
|
|
1895
|
-
if (data.accuracy === null) {
|
|
1896
|
-
throw Error('the accuracy of the attitude is not defined');
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
|
|
1900
|
-
|
|
1901
|
-
} else if (data instanceof ProviderEvent) {
|
|
1902
|
-
|
|
1903
|
-
if (data.dataType !== EventType.AbsoluteHeading
|
|
1904
|
-
|| !(data.data instanceof AbsoluteHeading)) {
|
|
1905
|
-
throw Error('the provider event is not an AbsoluteHeading');
|
|
1906
|
-
}
|
|
1907
|
-
|
|
1908
|
-
this._forceHeadingForRelative(data);
|
|
1909
|
-
|
|
1910
|
-
} else {
|
|
1911
|
-
throw new Error('data is nor an AbsoluteHeading or an Attitude object');
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
var AbsoluteAttitude$1 = new AbsoluteAttitude();
|
|
1917
|
-
|
|
1918
|
-
class TurnDetector extends Provider {
|
|
1919
|
-
|
|
1920
|
-
// in seconds
|
|
1921
|
-
static SLIDING_WINDOW_TIME = 0.3;
|
|
1922
|
-
|
|
1923
|
-
static STD_THRESHOLD = 0.075;
|
|
1924
|
-
|
|
1925
|
-
/** @type {number} in seconds */
|
|
1926
|
-
static CONSIDER_TURN_UNTIL = 1;
|
|
1927
|
-
|
|
1928
|
-
/** @type {number[]} */
|
|
1929
|
-
slidingWindow = [];
|
|
1930
|
-
|
|
1931
|
-
/**
|
|
1932
|
-
* @override
|
|
1933
|
-
*/
|
|
1934
|
-
static get pname() {
|
|
1935
|
-
return 'TurnDetector';
|
|
1936
|
-
}
|
|
1937
|
-
|
|
1938
|
-
/**
|
|
1939
|
-
* @override
|
|
1940
|
-
*/
|
|
1941
|
-
static get eventsType() {
|
|
1942
|
-
return [EventType.Turn];
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
/**
|
|
1946
|
-
* @override
|
|
1947
|
-
*/
|
|
1948
|
-
get _availability() {
|
|
1949
|
-
return RelativeAttitude$1.availability;
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
/**
|
|
1953
|
-
* @override
|
|
1954
|
-
*/
|
|
1955
|
-
start() {
|
|
1956
|
-
this.providerId = RelativeAttitude$1.addEventListener(
|
|
1957
|
-
events => this._parseRelativeAttitude(events[0]),
|
|
1958
|
-
error => this.notifyError(error)
|
|
1959
|
-
);
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
/**
|
|
1963
|
-
* @override
|
|
1964
|
-
*/
|
|
1965
|
-
stop() {
|
|
1966
|
-
RelativeAttitude$1.removeEventListener(this.providerId);
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
|
-
isTurning() {
|
|
1970
|
-
if (!this.lastEvent || !RelativeAttitude$1.lastEvent) {
|
|
1971
|
-
return false;
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
const diffTime = RelativeAttitude$1.lastEvent.data.time - this.lastEvent.data.timestamp;
|
|
1975
|
-
return diffTime < TurnDetector.CONSIDER_TURN_UNTIL;
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
/**
|
|
1979
|
-
* @private
|
|
1980
|
-
*/
|
|
1981
|
-
_parseRelativeAttitude = relativeAttitudeEvent => {
|
|
1731
|
+
_parseRelativeAttitude = relativeAttitudeEvent => {
|
|
1982
1732
|
|
|
1983
1733
|
const { heading, time: timestamp } = relativeAttitudeEvent.data;
|
|
1984
1734
|
|
|
@@ -3884,6 +3634,392 @@ class Inclination extends Provider {
|
|
|
3884
3634
|
|
|
3885
3635
|
var Inclination$1 = new Inclination();
|
|
3886
3636
|
|
|
3637
|
+
/* eslint-disable max-statements */
|
|
3638
|
+
|
|
3639
|
+
/**
|
|
3640
|
+
* Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
|
|
3641
|
+
*/
|
|
3642
|
+
class AbsoluteAttitude extends Provider {
|
|
3643
|
+
|
|
3644
|
+
/** @type {number} */
|
|
3645
|
+
static REL_ABS_DIVERGENCE_ANGLE_THRESHOLD = deg2rad(25);
|
|
3646
|
+
|
|
3647
|
+
/** @type {number} in seconds */
|
|
3648
|
+
static REL_ABS_DIVERGENCE_TIME_THRESHOLD = 2.5;
|
|
3649
|
+
|
|
3650
|
+
/** @type {number} */
|
|
3651
|
+
static REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD = deg2rad(15);
|
|
3652
|
+
|
|
3653
|
+
/** @type {boolean} */
|
|
3654
|
+
_attitudeFromBrowserErrored = false;
|
|
3655
|
+
|
|
3656
|
+
/** @type {boolean} */
|
|
3657
|
+
_attitudeFromRelativeErrored = false;
|
|
3658
|
+
|
|
3659
|
+
/*
|
|
3660
|
+
* RELATIVE
|
|
3661
|
+
*/
|
|
3662
|
+
|
|
3663
|
+
/** @type {Attitude} */
|
|
3664
|
+
_relativeAttitude = null;
|
|
3665
|
+
|
|
3666
|
+
/** @type {number} in radians/s */
|
|
3667
|
+
_relativeAccuracy = 0;
|
|
3668
|
+
|
|
3669
|
+
/** @type {ProviderEvent<Attitude|AbsoluteHeading>} */
|
|
3670
|
+
_lastForcedHeadingEvent;
|
|
3671
|
+
|
|
3672
|
+
/** @type {number[]} quaternion offset from relative to absolute */
|
|
3673
|
+
_relAbsQuat;
|
|
3674
|
+
|
|
3675
|
+
/** @type {boolean} */
|
|
3676
|
+
_wasHighRotationInProgress = false;
|
|
3677
|
+
|
|
3678
|
+
/** @type {?number} */
|
|
3679
|
+
_timeFirstDivergence = null;
|
|
3680
|
+
|
|
3681
|
+
|
|
3682
|
+
constructor() {
|
|
3683
|
+
super();
|
|
3684
|
+
|
|
3685
|
+
this._attitudeFromBrowserErrored = false;
|
|
3686
|
+
this._attitudeFromRelativeErrored = false;
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
/**
|
|
3690
|
+
* @override
|
|
3691
|
+
*/
|
|
3692
|
+
static get pname() {
|
|
3693
|
+
return 'AbsoluteAttitude';
|
|
3694
|
+
}
|
|
3695
|
+
|
|
3696
|
+
/**
|
|
3697
|
+
* @override
|
|
3698
|
+
*/
|
|
3699
|
+
static get eventsType() {
|
|
3700
|
+
return [EventType.AbsoluteAttitude];
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
/**
|
|
3704
|
+
* @override
|
|
3705
|
+
*/
|
|
3706
|
+
get _availability() {
|
|
3707
|
+
return PromiseUtils.any([
|
|
3708
|
+
AbsoluteAttitudeFromBrowser$1.availability,
|
|
3709
|
+
RelativeAttitude$1.availability
|
|
3710
|
+
]);
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
/**
|
|
3714
|
+
* @override
|
|
3715
|
+
*/
|
|
3716
|
+
start() {
|
|
3717
|
+
|
|
3718
|
+
this.fromBrowserProviderId = AbsoluteAttitudeFromBrowser$1.addEventListener(
|
|
3719
|
+
events => this._onAttitudeFromBrowser(events[0]),
|
|
3720
|
+
error => {
|
|
3721
|
+
this._attitudeFromBrowserErrored = true;
|
|
3722
|
+
this.onError(error);
|
|
3723
|
+
}
|
|
3724
|
+
);
|
|
3725
|
+
|
|
3726
|
+
this.relativeAttitudeProviderId = RelativeAttitude$1.addEventListener(
|
|
3727
|
+
events => this._onRelativeAttitudeEvent(events[0]),
|
|
3728
|
+
error => {
|
|
3729
|
+
this._attitudeFromRelativeErrored = true;
|
|
3730
|
+
this.onError(error);
|
|
3731
|
+
}
|
|
3732
|
+
);
|
|
3733
|
+
|
|
3734
|
+
this.inclinationProviderId = Inclination$1.addEventListener();
|
|
3735
|
+
|
|
3736
|
+
this.highRotationDetectorId = HighRotationsDetector$1.addEventListener();
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
/**
|
|
3740
|
+
* @override
|
|
3741
|
+
*/
|
|
3742
|
+
stop() {
|
|
3743
|
+
AbsoluteAttitudeFromBrowser$1.removeEventListener(this.fromBrowserProviderId);
|
|
3744
|
+
RelativeAttitude$1.removeEventListener(this.relativeAttitudeProviderId);
|
|
3745
|
+
Inclination$1.removeEventListener(this.inclinationProviderId);
|
|
3746
|
+
HighRotationsDetector$1.removeEventListener(this.highRotationDetectorId);
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
onError(error) {
|
|
3750
|
+
if (this._attitudeFromBrowserErrored && this._attitudeFromRelativeErrored) {
|
|
3751
|
+
this.notifyError(error);
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
|
|
3755
|
+
|
|
3756
|
+
/**
|
|
3757
|
+
* @param {ProviderEvent<Attitude|AbsoluteHeading>} absoluteHeadingEvent
|
|
3758
|
+
*/
|
|
3759
|
+
_forceHeadingForRelative = (absoluteHeadingEvent) => {
|
|
3760
|
+
|
|
3761
|
+
if (this.lastEvent && absoluteHeadingEvent.data.accuracy > this.lastEvent.data.accuracy) {
|
|
3762
|
+
return;
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
|
|
3766
|
+
/**
|
|
3767
|
+
* @param {Attitude} relativeAttitude
|
|
3768
|
+
*/
|
|
3769
|
+
const calcForceHeading = (relativeAttitude) => {
|
|
3770
|
+
const currentRelativeHeading = relativeAttitude.heading;
|
|
3771
|
+
|
|
3772
|
+
this._relAbsQuat = Quaternion.fromAxisAngle(
|
|
3773
|
+
[0, 0, 1],
|
|
3774
|
+
currentRelativeHeading - absoluteHeadingEvent.data.heading
|
|
3775
|
+
);
|
|
3776
|
+
|
|
3777
|
+
this._relativeAccuracy = 0;
|
|
3778
|
+
this._lastForcedHeadingEvent = absoluteHeadingEvent;
|
|
3779
|
+
};
|
|
3780
|
+
|
|
3781
|
+
// If relativeAttitude does not exist yet, wait the next
|
|
3782
|
+
if (this._relativeAttitude) {
|
|
3783
|
+
calcForceHeading(this._relativeAttitude);
|
|
3784
|
+
return;
|
|
3785
|
+
}
|
|
3786
|
+
|
|
3787
|
+
// If this._relativeAttitude does not exist, wait the first value
|
|
3788
|
+
// /!\ This works only if the relative attitude event is provided rapidly.
|
|
3789
|
+
const providerId = RelativeAttitude$1.addEventListener(
|
|
3790
|
+
events => {
|
|
3791
|
+
calcForceHeading(events[0].data);
|
|
3792
|
+
RelativeAttitude$1.removeEventListener(providerId);
|
|
3793
|
+
}
|
|
3794
|
+
);
|
|
3795
|
+
|
|
3796
|
+
};
|
|
3797
|
+
|
|
3798
|
+
/**
|
|
3799
|
+
* @param {ProviderEvent<Attitude>} event
|
|
3800
|
+
*/
|
|
3801
|
+
_onRelativeAttitudeEvent(event) {
|
|
3802
|
+
|
|
3803
|
+
const { quaternion, accuracy, time } = event.data;
|
|
3804
|
+
|
|
3805
|
+
// Calculate relative accuracy
|
|
3806
|
+
if (this._relativeAttitude) {
|
|
3807
|
+
this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// Keep the relative attitude event for the calculation of relAbsQuat
|
|
3811
|
+
// /!\ Keep this even if forced heading is not set /!\
|
|
3812
|
+
this._relativeAttitude = event.data;
|
|
3813
|
+
|
|
3814
|
+
|
|
3815
|
+
if (!this._lastForcedHeadingEvent) {
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
|
|
3819
|
+
const accuracyWithRelative = Math.min(
|
|
3820
|
+
this._lastForcedHeadingEvent.data.accuracy + this._relativeAccuracy,
|
|
3821
|
+
Math.PI
|
|
3822
|
+
);
|
|
3823
|
+
|
|
3824
|
+
const highRotationInProgress = HighRotationsDetector$1.isInProgress();
|
|
3825
|
+
|
|
3826
|
+
let magnetometerNeedCalibrationEvent = null;
|
|
3827
|
+
let divergenceDetected = false;
|
|
3828
|
+
|
|
3829
|
+
if (this._eventFromBrowser) {
|
|
3830
|
+
|
|
3831
|
+
const {
|
|
3832
|
+
accuracy: accuracyWithAbsolute,
|
|
3833
|
+
heading: headingFromAbsolute
|
|
3834
|
+
} = this._eventFromBrowser.data;
|
|
3835
|
+
|
|
3836
|
+
if (this._wasHighRotationInProgress && !highRotationInProgress) {
|
|
3837
|
+
// Update heading for relative if it the end of high rotations
|
|
3838
|
+
// (probably due to a magnetometer calibratiton)
|
|
3839
|
+
this._forceHeadingForRelative(this._eventFromBrowser);
|
|
3840
|
+
|
|
3841
|
+
} else if (accuracyWithAbsolute < accuracyWithRelative) {
|
|
3842
|
+
// Update heading for relative if:
|
|
3843
|
+
// (1) accuracy from absolute is better than relative
|
|
3844
|
+
// (2) heading divergence is greater than REL_ABS_DIVERGENCE_THRESHOLD
|
|
3845
|
+
const relativeQuaternion = Quaternion.multiply(this._relAbsQuat, quaternion);
|
|
3846
|
+
const relativeAttitude = new Attitude(relativeQuaternion);
|
|
3847
|
+
const angle = Math.abs(diffAngle(relativeAttitude.heading, headingFromAbsolute));
|
|
3848
|
+
const inclination = Inclination$1.lastEvent.data;
|
|
3849
|
+
|
|
3850
|
+
|
|
3851
|
+
if (angle > AbsoluteAttitude.REL_ABS_DIVERGENCE_ANGLE_THRESHOLD
|
|
3852
|
+
&& Math.abs(inclination - Math.PI / 4) > AbsoluteAttitude.REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD
|
|
3853
|
+
) {
|
|
3854
|
+
divergenceDetected = true;
|
|
3855
|
+
|
|
3856
|
+
// Be sure before forcing heading
|
|
3857
|
+
if (this._timeFirstDivergence !== null
|
|
3858
|
+
&& time - this._timeFirstDivergence > AbsoluteAttitude.REL_ABS_DIVERGENCE_TIME_THRESHOLD) {
|
|
3859
|
+
|
|
3860
|
+
this._forceHeadingForRelative(this._eventFromBrowser);
|
|
3861
|
+
magnetometerNeedCalibrationEvent = this.createEvent(
|
|
3862
|
+
EventType.MagnetometerNeedCalibration,
|
|
3863
|
+
{
|
|
3864
|
+
angle
|
|
3865
|
+
}, [event, this._lastForcedHeadingEvent]
|
|
3866
|
+
);
|
|
3867
|
+
this._timeFirstDivergence = null;
|
|
3868
|
+
} else if (this._timeFirstDivergence === null) {
|
|
3869
|
+
this._timeFirstDivergence = time;
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
if (!divergenceDetected) {
|
|
3878
|
+
this._timeFirstDivergence = null;
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
this._wasHighRotationInProgress = highRotationInProgress;
|
|
3882
|
+
|
|
3883
|
+
const absoluteQuat = Quaternion.multiply(this._relAbsQuat, quaternion);
|
|
3884
|
+
const attitude = new Attitude(absoluteQuat, time, accuracyWithRelative);
|
|
3885
|
+
|
|
3886
|
+
const eventsToNotify = [
|
|
3887
|
+
this.createEvent(
|
|
3888
|
+
EventType.AbsoluteAttitude,
|
|
3889
|
+
attitude,
|
|
3890
|
+
[event, this._lastForcedHeadingEvent]
|
|
3891
|
+
)
|
|
3892
|
+
];
|
|
3893
|
+
if (magnetometerNeedCalibrationEvent) {
|
|
3894
|
+
eventsToNotify.push(magnetometerNeedCalibrationEvent);
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3897
|
+
this.notify(...eventsToNotify);
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
|
|
3901
|
+
/**
|
|
3902
|
+
* @param {ProviderEvent<Attitude>} event
|
|
3903
|
+
*/
|
|
3904
|
+
_onAttitudeFromBrowser(event) {
|
|
3905
|
+
this._eventFromBrowser = event;
|
|
3906
|
+
|
|
3907
|
+
if (!this._lastForcedHeadingEvent) {
|
|
3908
|
+
this._forceHeadingForRelative(event);
|
|
3909
|
+
return;
|
|
3910
|
+
}
|
|
3911
|
+
|
|
3912
|
+
// Absolute attitude from browser is not used anymore due to magnetometer inaccuracy on pitch and roll
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
/**
|
|
3916
|
+
* @override
|
|
3917
|
+
* @param {AbsoluteHeading|Attitude|ProviderEvent} data
|
|
3918
|
+
*/
|
|
3919
|
+
feed(data) {
|
|
3920
|
+
|
|
3921
|
+
if (data instanceof AbsoluteHeading) {
|
|
3922
|
+
|
|
3923
|
+
if (data.time === null) {
|
|
3924
|
+
throw Error('the time of the absolute heading is not defined');
|
|
3925
|
+
}
|
|
3926
|
+
if (data.accuracy === null) {
|
|
3927
|
+
throw Error('the accuracy of the absolute heading is not defined');
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
|
|
3931
|
+
|
|
3932
|
+
} else if (data instanceof Attitude) {
|
|
3933
|
+
|
|
3934
|
+
if (data.time === null) {
|
|
3935
|
+
throw Error('the time of the attitude is not defined');
|
|
3936
|
+
}
|
|
3937
|
+
if (data.accuracy === null) {
|
|
3938
|
+
throw Error('the accuracy of the attitude is not defined');
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
|
|
3942
|
+
|
|
3943
|
+
} else if (data instanceof ProviderEvent) {
|
|
3944
|
+
|
|
3945
|
+
if (data.dataType !== EventType.AbsoluteHeading
|
|
3946
|
+
|| !(data.data instanceof AbsoluteHeading)) {
|
|
3947
|
+
throw Error('the provider event is not an AbsoluteHeading');
|
|
3948
|
+
}
|
|
3949
|
+
|
|
3950
|
+
this._forceHeadingForRelative(data);
|
|
3951
|
+
|
|
3952
|
+
} else {
|
|
3953
|
+
throw new Error('data is nor an AbsoluteHeading or an Attitude object');
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
var AbsoluteAttitude$1 = new AbsoluteAttitude();
|
|
3959
|
+
|
|
3960
|
+
class MagnetometerCalibrationDetector extends Provider {
|
|
3961
|
+
|
|
3962
|
+
/**
|
|
3963
|
+
* @override
|
|
3964
|
+
*/
|
|
3965
|
+
static get pname() {
|
|
3966
|
+
return 'MagnetometerCalibrationDetector';
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
|
|
3970
|
+
/**
|
|
3971
|
+
* @override
|
|
3972
|
+
*/
|
|
3973
|
+
static get eventsType() {
|
|
3974
|
+
return [EventType.MagnetometerNeedCalibration];
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
/**
|
|
3978
|
+
* @override
|
|
3979
|
+
*/
|
|
3980
|
+
get _availability() {
|
|
3981
|
+
return AbsoluteAttitude$1.availability;
|
|
3982
|
+
}
|
|
3983
|
+
|
|
3984
|
+
/**
|
|
3985
|
+
* @override
|
|
3986
|
+
*/
|
|
3987
|
+
start() {
|
|
3988
|
+
this.providerId = AbsoluteAttitude$1.addEventListener(
|
|
3989
|
+
events => this._parseAbsoluteAttitudeEvents(events),
|
|
3990
|
+
error => this.notifyError(error),
|
|
3991
|
+
false
|
|
3992
|
+
);
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
/**
|
|
3996
|
+
* @override
|
|
3997
|
+
*/
|
|
3998
|
+
stop() {
|
|
3999
|
+
AbsoluteAttitude$1.removeEventListener(this.providerId);
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
/**
|
|
4003
|
+
* @private
|
|
4004
|
+
* @param {ProviderEvent[]} absoluteAttitudeEvents
|
|
4005
|
+
*/
|
|
4006
|
+
_parseAbsoluteAttitudeEvents = absoluteAttitudeEvents => {
|
|
4007
|
+
|
|
4008
|
+
if (absoluteAttitudeEvents.length < 2) {
|
|
4009
|
+
return;
|
|
4010
|
+
}
|
|
4011
|
+
|
|
4012
|
+
const magnetometerNeedCalibrationEvent = absoluteAttitudeEvents[1];
|
|
4013
|
+
if (magnetometerNeedCalibrationEvent.dataType !== EventType.MagnetometerNeedCalibration) {
|
|
4014
|
+
return;
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
this.notify(magnetometerNeedCalibrationEvent);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
var MagnetometerCalibrationDetector$1 = new MagnetometerCalibrationDetector();
|
|
4022
|
+
|
|
3887
4023
|
class IpResolveServerError extends Error {
|
|
3888
4024
|
|
|
3889
4025
|
static DEFAULT_MESSAGE = 'IP Resolver failed';
|
|
@@ -4111,6 +4247,7 @@ var Providers = /*#__PURE__*/Object.freeze({
|
|
|
4111
4247
|
Accelerometer: Accelerometer$1,
|
|
4112
4248
|
Gyroscope: Gyroscope$1,
|
|
4113
4249
|
HighRotationsDetector: HighRotationsDetector$1,
|
|
4250
|
+
MagnetometerCalibrationDetector: MagnetometerCalibrationDetector$1,
|
|
4114
4251
|
RelativeAttitudeFromBrowser: RelativeAttitudeFromBrowser$1,
|
|
4115
4252
|
RelativeAttitudeFromEkf: RelativeAttitudeFromEkf$1,
|
|
4116
4253
|
RelativeAttitudeFromInertial: RelativeAttitudeFromInertial$1,
|