@wemap/positioning 2.7.13 → 14.0.0-0
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/README.md +51 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16582 -0
- package/dist/qr-scanner-worker.min-CdBZO1_x.js +2 -0
- package/dist/src/ILocationSource.d.ts +104 -0
- package/dist/src/ILocationSource.d.ts.map +1 -0
- package/dist/src/MapMatching.d.ts +83 -0
- package/dist/src/MapMatching.d.ts.map +1 -0
- package/dist/src/location-sources/GnssWifiLocationSource.d.ts +79 -0
- package/dist/src/location-sources/GnssWifiLocationSource.d.ts.map +1 -0
- package/dist/src/location-sources/LocationSource.d.ts +102 -0
- package/dist/src/location-sources/LocationSource.d.ts.map +1 -0
- package/dist/src/location-sources/VPSLocationSource.d.ts +107 -0
- package/dist/src/location-sources/VPSLocationSource.d.ts.map +1 -0
- package/dist/src/types.d.ts +65 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/permissions.d.ts +29 -0
- package/dist/src/utils/permissions.d.ts.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/package.json +23 -59
- package/babel.config.js +0 -11
- package/config.json +0 -4
- package/debug/absolute-attitude.html +0 -16
- package/debug/arcore-absolute.html +0 -16
- package/debug/arcore.html +0 -16
- package/debug/components/AbsoluteAttitudeComponent.jsx +0 -100
- package/debug/components/ArCoreAbsoluteComponent.jsx +0 -104
- package/debug/components/ArCoreComponent.jsx +0 -69
- package/debug/components/GnssWifiComponent.jsx +0 -56
- package/debug/components/GnssWifiPdrComponent.jsx +0 -76
- package/debug/components/ImuComponent.jsx +0 -95
- package/debug/components/InclinationComponent.jsx +0 -52
- package/debug/components/MapComponent.jsx +0 -228
- package/debug/components/NavigationConfig.js +0 -92
- package/debug/components/PdrComponent.jsx +0 -75
- package/debug/components/PoseComponent.jsx +0 -77
- package/debug/components/PositioningComponent.jsx +0 -29
- package/debug/components/PositioningInclinationComponent.jsx +0 -82
- package/debug/components/PositioningPoseComponent.jsx +0 -117
- package/debug/components/RelativeAttitudeComponent.jsx +0 -82
- package/debug/components/StartStopComponent.jsx +0 -50
- package/debug/components/Utils.js +0 -128
- package/debug/components/index.js +0 -34
- package/debug/gnss-wifi-pdr.html +0 -16
- package/debug/gnss-wifi.html +0 -16
- package/debug/imu.html +0 -16
- package/debug/inclination.html +0 -16
- package/debug/pdr.html +0 -16
- package/debug/pose.html +0 -16
- package/debug/positioning.html +0 -16
- package/debug/relative-attitude.html +0 -16
- package/dist/wemap-positioning.min.js +0 -1
- package/index.js +0 -8
- package/src/PositioningHandler.js +0 -237
- package/src/PositioningHandler.spec.js +0 -294
- package/src/PositioningOptions.js +0 -34
- package/src/errors/AskImuOnDesktopError.js +0 -9
- package/src/errors/ContainsIgnoredProviderError.js +0 -9
- package/src/errors/GeolocationApiMissingError.js +0 -9
- package/src/errors/GeolocationPermissionDeniedError.js +0 -9
- package/src/errors/GeolocationPositionUnavailableError.js +0 -9
- package/src/errors/IpResolveServerError.js +0 -9
- package/src/errors/MissingAccelerometerError.js +0 -11
- package/src/errors/MissingArCoreError.js +0 -9
- package/src/errors/MissingGyroscopeError.js +0 -11
- package/src/errors/MissingMagnetometerError.js +0 -9
- package/src/errors/MissingNativeInterfaceError.js +0 -9
- package/src/errors/MissingSensorError.js +0 -14
- package/src/errors/NoProviderFoundError.js +0 -9
- package/src/events/Availability.js +0 -30
- package/src/events/EventType.js +0 -22
- package/src/events/ProviderEvent.js +0 -35
- package/src/providers/Constants.js +0 -5
- package/src/providers/Provider.js +0 -247
- package/src/providers/ProvidersList.js +0 -44
- package/src/providers/ProvidersLogger.js +0 -75
- package/src/providers/attitude/AbsoluteAttitudeProvider.js +0 -199
- package/src/providers/attitude/EkfAttitude.js +0 -238
- package/src/providers/attitude/EkfAttitude.spec.js +0 -116
- package/src/providers/attitude/RelativeAttitudeProvider.js +0 -121
- package/src/providers/others/ImuProvider.js +0 -179
- package/src/providers/others/InclinationProvider.js +0 -99
- package/src/providers/others/MapMatchingProvider.js +0 -65
- package/src/providers/pose/ArCoreAbsoluteProvider.js +0 -235
- package/src/providers/pose/ArCoreProvider.js +0 -191
- package/src/providers/pose/GnssWifiPdrProvider.js +0 -219
- package/src/providers/pose/PoseProvider.js +0 -71
- package/src/providers/pose/pdr/PdrProvider.js +0 -364
- package/src/providers/pose/pdr/helpers/HeadingUnlocker.js +0 -41
- package/src/providers/pose/pdr/helpers/HeadingUnlocker.spec.js +0 -26
- package/src/providers/pose/pdr/helpers/Smoother.js +0 -92
- package/src/providers/pose/pdr/helpers/Smoother.spec.js +0 -426
- package/src/providers/pose/pdr/helpers/ThugDetector.js +0 -37
- package/src/providers/pose/pdr/steps/StepDetection.js +0 -7
- package/src/providers/pose/pdr/steps/StepDetectionLadetto.js +0 -67
- package/src/providers/pose/pdr/steps/StepDetectionMinMaxPeaks.js +0 -80
- package/src/providers/pose/pdr/steps/StepDetectionMinMaxPeaks2.js +0 -108
- package/src/providers/position/GnssWifiProvider.js +0 -130
- package/src/providers/position/IpProvider.js +0 -74
- package/webpack/webpack.common.js +0 -20
- package/webpack/webpack.dev.js +0 -24
- package/webpack/webpack.prod.js +0 -15
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Matrix, Matrix3, Matrix4, Quaternion, Vector, Vector3
|
|
3
|
-
} from '@wemap/maths';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const DEFAULT_RELATIVE_NOISES = {
|
|
7
|
-
acc: 0.5,
|
|
8
|
-
gyr: 0.3
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const DEFAULT_ABSOLUTE_NOISES = {
|
|
12
|
-
acc: 0.5,
|
|
13
|
-
gyr: 0.3,
|
|
14
|
-
yc: 2
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
class EkfAttitude {
|
|
18
|
-
|
|
19
|
-
constructor(accRef = [0, 0, 1], ycRef = [-1, 0, 0]) {
|
|
20
|
-
|
|
21
|
-
this.accRef = accRef;
|
|
22
|
-
this.cRef = ycRef;
|
|
23
|
-
|
|
24
|
-
this.P = Matrix.diag(Array(4).fill(0.1 ** 2));
|
|
25
|
-
|
|
26
|
-
this.quaternion = null;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.noises = {
|
|
30
|
-
relative: null,
|
|
31
|
-
absolute: null
|
|
32
|
-
};
|
|
33
|
-
this.setRelativeNoises(DEFAULT_RELATIVE_NOISES);
|
|
34
|
-
this.setAbsoluteNoises(DEFAULT_ABSOLUTE_NOISES);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
setRelativeNoises(relativeNoises) {
|
|
38
|
-
this.noises.relative = {
|
|
39
|
-
accelerometer: Matrix.diag(Array(3).fill(relativeNoises.acc ** 2)),
|
|
40
|
-
gyroscope: Matrix.diag(Array(3).fill(relativeNoises.gyr ** 2))
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
setAbsoluteNoises(absoluteNoises) {
|
|
46
|
-
this.noises.absolute = {
|
|
47
|
-
accelerometer: Matrix.diag(Array(3).fill(absoluteNoises.acc ** 2)),
|
|
48
|
-
gyroscope: Matrix.diag(Array(3).fill(absoluteNoises.gyr ** 2)),
|
|
49
|
-
yc: Matrix.diag(Array(3).fill(absoluteNoises.yc ** 2))
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
55
|
-
* Set yaw offset, this value will be used if the filter does not use magnetometer
|
|
56
|
-
* @param {Number} yaw yaw offset in radians and clockwise
|
|
57
|
-
*/
|
|
58
|
-
setOrientationYaw(yaw) {
|
|
59
|
-
this.offsetYawQuaternion = Quaternion.fromAxisAngle(this.accRef, yaw);
|
|
60
|
-
this.quaternion = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Try to initialize filter.
|
|
65
|
-
* To initialize, we need two information: current acceleration (acc) and offset on yaw angle (given by the quaternion: this.offsetYawQuaternion)
|
|
66
|
-
*/
|
|
67
|
-
tryInitialize(acc, mag) {
|
|
68
|
-
|
|
69
|
-
const accNormalized = Vector3.normalize(acc);
|
|
70
|
-
|
|
71
|
-
if (mag) {
|
|
72
|
-
const magNormalized = Vector3.normalize(mag);
|
|
73
|
-
|
|
74
|
-
const H = Vector3.normalize(Vector3.cross(magNormalized, accNormalized));
|
|
75
|
-
const M = Vector3.cross(accNormalized, H);
|
|
76
|
-
|
|
77
|
-
const R = [
|
|
78
|
-
[H[0], M[0], accNormalized[0]],
|
|
79
|
-
[H[1], M[1], accNormalized[1]],
|
|
80
|
-
[H[2], M[2], accNormalized[2]]
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
this.quaternion = Quaternion.fromMatrix3(R);
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
|
|
87
|
-
if (!this.offsetYawQuaternion) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const r = Vector3.dot(accNormalized, this.accRef) + 1;
|
|
92
|
-
const v = Vector3.cross(accNormalized, this.accRef);
|
|
93
|
-
|
|
94
|
-
let quaternionWithoutYaw = [r, v[0], v[1], v[2]];
|
|
95
|
-
quaternionWithoutYaw = Quaternion.normalize(quaternionWithoutYaw);
|
|
96
|
-
|
|
97
|
-
this.quaternion = Quaternion.multiply(this.offsetYawQuaternion, quaternionWithoutYaw);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return this.quaternion;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
update(diffTime, acc, gyr, mag) {
|
|
104
|
-
|
|
105
|
-
if (!this.quaternion) {
|
|
106
|
-
return this.tryInitialize(acc, mag);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
let q = this.quaternion;
|
|
110
|
-
|
|
111
|
-
/* ------------
|
|
112
|
-
* ESTIMATION
|
|
113
|
-
* ------------*/
|
|
114
|
-
|
|
115
|
-
const qArray = q;
|
|
116
|
-
const gyrInt = Vector3.multiplyScalar(gyr, 0.5 * diffTime);
|
|
117
|
-
const F = this.computeC([1, gyrInt[0], gyrInt[1], gyrInt[2]]);
|
|
118
|
-
const qAPriori = Matrix.multiplyVector(F, q);
|
|
119
|
-
const E1 = Matrix.diag([qArray[0], qArray[0], qArray[0]]);
|
|
120
|
-
const eSkew = Matrix3.skew([qArray[1], qArray[2], qArray[3]]);
|
|
121
|
-
|
|
122
|
-
const qPart = [-1 * qArray[1], -1 * qArray[2], -1 * qArray[3]];
|
|
123
|
-
const E = Matrix.concatRow([qPart], Matrix3.add(eSkew, E1));
|
|
124
|
-
|
|
125
|
-
const Qk = Matrix.multiplyScalar(
|
|
126
|
-
Matrix.multiply(
|
|
127
|
-
Matrix.multiply(E, this.noises[mag ? 'absolute' : 'relative'].gyroscope),
|
|
128
|
-
Matrix.transpose(E)
|
|
129
|
-
),
|
|
130
|
-
(diffTime / 2) ** 2
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
const pAPriori = Matrix4.add(
|
|
134
|
-
Matrix.multiply(
|
|
135
|
-
Matrix.multiply(F, this.P),
|
|
136
|
-
Matrix.transpose(F)
|
|
137
|
-
),
|
|
138
|
-
Qk
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
/* ------------
|
|
142
|
-
* CORRECTION
|
|
143
|
-
* ------------*/
|
|
144
|
-
|
|
145
|
-
const accNormalized = Vector3.normalize(acc);
|
|
146
|
-
let dz, K, H;
|
|
147
|
-
|
|
148
|
-
if (mag) {
|
|
149
|
-
|
|
150
|
-
const magNormalized = Vector3.normalize(mag);
|
|
151
|
-
const yc = Vector3.cross(accNormalized, magNormalized);
|
|
152
|
-
const ycNormalized = Vector3.normalize(yc);
|
|
153
|
-
|
|
154
|
-
const dzYc = Vector3.subtract(ycNormalized, Quaternion.rotate(qAPriori, this.cRef));
|
|
155
|
-
const dzAcc = Vector3.subtract(accNormalized, Quaternion.rotate(qAPriori, this.accRef));
|
|
156
|
-
dz = Vector.concat(dzYc, dzAcc);
|
|
157
|
-
|
|
158
|
-
const HYc = this.jacobianES(qAPriori, this.cRef);
|
|
159
|
-
const HAcc = this.jacobianES(qAPriori, this.accRef);
|
|
160
|
-
H = Matrix.concatRow(HYc, HAcc);
|
|
161
|
-
|
|
162
|
-
const RYc = Matrix.concatLine(this.noises.absolute.yc, Matrix3.zeros);
|
|
163
|
-
const RAcc = Matrix.concatLine(Matrix3.zeros, this.noises.absolute.accelerometer);
|
|
164
|
-
const R = Matrix.concatRow(RYc, RAcc);
|
|
165
|
-
|
|
166
|
-
K = Matrix.multiply(
|
|
167
|
-
Matrix.multiply(pAPriori, Matrix.transpose(H)),
|
|
168
|
-
Matrix.inverse(
|
|
169
|
-
Matrix.add(
|
|
170
|
-
Matrix.multiply(
|
|
171
|
-
Matrix.multiply(H, pAPriori),
|
|
172
|
-
Matrix.transpose(H)
|
|
173
|
-
),
|
|
174
|
-
R
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
);
|
|
178
|
-
} else {
|
|
179
|
-
dz = Vector3.subtract(accNormalized, Quaternion.rotate(qAPriori, this.accRef));
|
|
180
|
-
H = this.jacobianES(qAPriori, this.accRef);
|
|
181
|
-
const R = this.noises.relative.accelerometer;
|
|
182
|
-
|
|
183
|
-
K = Matrix.multiply(
|
|
184
|
-
Matrix.multiply(pAPriori, Matrix.transpose(H)),
|
|
185
|
-
Matrix3.inverse(
|
|
186
|
-
Matrix3.add(
|
|
187
|
-
Matrix.multiply(
|
|
188
|
-
Matrix.multiply(H, pAPriori),
|
|
189
|
-
Matrix.transpose(H)
|
|
190
|
-
),
|
|
191
|
-
R
|
|
192
|
-
)
|
|
193
|
-
)
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
q = Quaternion.add(
|
|
198
|
-
qAPriori,
|
|
199
|
-
Matrix.multiplyVector(K, dz)
|
|
200
|
-
);
|
|
201
|
-
const P = Matrix.multiply(
|
|
202
|
-
Matrix4.subtract(
|
|
203
|
-
Matrix4.identity,
|
|
204
|
-
Matrix.multiply(K, H)
|
|
205
|
-
),
|
|
206
|
-
pAPriori
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
q = Quaternion.normalize(q);
|
|
210
|
-
this.quaternion = q;
|
|
211
|
-
this.P = P;
|
|
212
|
-
|
|
213
|
-
return q;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
computeC(b) {
|
|
217
|
-
return [
|
|
218
|
-
[b[0], -b[1], -b[2], -b[3]],
|
|
219
|
-
[b[1], b[0], b[3], -b[2]],
|
|
220
|
-
[b[2], -b[3], b[0], b[1]],
|
|
221
|
-
[b[3], b[2], -b[1], b[0]]
|
|
222
|
-
];
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
jacobianES(q, v) {
|
|
226
|
-
|
|
227
|
-
const [qw, qx, qy, qz] = q;
|
|
228
|
-
const [vx, vy, vz] = v;
|
|
229
|
-
|
|
230
|
-
return [
|
|
231
|
-
[2 * qz * vy - 2 * qy * vz, 2 * qy * vy + 2 * qz * vz, 2 * qx * vy - 2 * qw * vz - 4 * qy * vx, 2 * qw * vy + 2 * qx * vz - 4 * qz * vx],
|
|
232
|
-
[2 * qx * vz - 2 * qz * vx, 2 * qw * vz - 4 * qx * vy + 2 * qy * vx, 2 * qx * vx + 2 * qz * vz, 2 * qy * vz - 2 * qw * vx - 4 * qz * vy],
|
|
233
|
-
[2 * qy * vx - 2 * qx * vy, 2 * qz * vx - 4 * qx * vz - 2 * qw * vy, 2 * qw * vx - 4 * qy * vz + 2 * qz * vy, 2 * qx * vx + 2 * qy * vy]
|
|
234
|
-
];
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export default EkfAttitude;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import chai from 'chai';
|
|
2
|
-
|
|
3
|
-
import { Quaternion } from '@wemap/maths';
|
|
4
|
-
|
|
5
|
-
import EkfAttitude from './EkfAttitude';
|
|
6
|
-
|
|
7
|
-
const expect = chai.expect;
|
|
8
|
-
|
|
9
|
-
const dt = [
|
|
10
|
-
0.02, 0.02, 0.02, 0.02, 0.02
|
|
11
|
-
];
|
|
12
|
-
const accData = [
|
|
13
|
-
[-0.034561157, 3.81073, 8.860977],
|
|
14
|
-
[-0.030700684, 3.814499, 8.818954],
|
|
15
|
-
[-0.018234253, 3.8023376, 8.85762],
|
|
16
|
-
[-0.020080566, 3.8205414, 8.8676605],
|
|
17
|
-
[-0.054519653, 3.8456726, 8.810287]
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
const gyrData = [
|
|
21
|
-
[0.0047454834, 0.0028076172, 0.0022888184],
|
|
22
|
-
[0.005218506, 0.0020446777, 0.0012207031],
|
|
23
|
-
[0.0044555664, 0.0023040771, 4.4250488E-4],
|
|
24
|
-
[0.0044555664, 0.0027618408, 0.0011444092],
|
|
25
|
-
[0.0040893555, 0.0020446777, 0.0025787354]
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const magData = [
|
|
29
|
-
[-7.260132, -29.21753, -30.532837],
|
|
30
|
-
[-8.378601, -29.589844, -29.684448],
|
|
31
|
-
[-8.784485, -29.97284, -29.86145],
|
|
32
|
-
[-8.784485, -30.06134, -30.036926],
|
|
33
|
-
[-8.917236, -29.666138, -28.616333]
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
const expectationsAbsolute = [
|
|
37
|
-
[0.22501367907095468, 0.048112975227173178, -0.19586497565981961, -0.95325279813673824],
|
|
38
|
-
[0.22521836492577899, 0.048187611771482071, -0.19604062637627487, -0.953164579168738],
|
|
39
|
-
[0.22546875479675244, 0.048146964451479861, -0.19603487950732199, -0.95310861733648156],
|
|
40
|
-
[0.22571872218138991, 0.04816067876157637, -0.19609909097002176, -0.95303554708035731],
|
|
41
|
-
[0.22598409746972753, 0.048415228863568645, -0.1963289784536566, -0.95291242279877153]
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const expectationsRelative = [
|
|
45
|
-
[0.979449872594084, 0.201679452107589, 0.001829118097573, 0],
|
|
46
|
-
[0.979412310855378, 0.201861876976980, 0.001818648953412, 0.000022005516141],
|
|
47
|
-
[0.979416707676713, 0.201841237873455, 0.001739180982152, 0.000051642340567],
|
|
48
|
-
[0.979405268570585, 0.201897124314688, 0.001692389320913, 0.000083114532679],
|
|
49
|
-
[0.979351148979101, 0.202158360999907, 0.001821014027950, 0.000089325563504]
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
describe('initAbsolute', () => {
|
|
53
|
-
it('Should return the good value', () => {
|
|
54
|
-
const ekf = new EkfAttitude();
|
|
55
|
-
ekf.setAbsoluteNoises({
|
|
56
|
-
acc: 0.5,
|
|
57
|
-
gyr: 0.3,
|
|
58
|
-
yc: 2
|
|
59
|
-
});
|
|
60
|
-
const result = ekf.update(dt[0], accData[0], gyrData[0], magData[0]);
|
|
61
|
-
const distance = Quaternion.distance(result, expectationsAbsolute[0]);
|
|
62
|
-
expect(distance).to.below(0.000001);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('updateAbsolute', () => {
|
|
67
|
-
it('Should return the good value', () => {
|
|
68
|
-
const ekf = new EkfAttitude();
|
|
69
|
-
ekf.setAbsoluteNoises({
|
|
70
|
-
acc: 0.5,
|
|
71
|
-
gyr: 0.3,
|
|
72
|
-
yc: 2
|
|
73
|
-
});
|
|
74
|
-
let result;
|
|
75
|
-
let distance;
|
|
76
|
-
|
|
77
|
-
for (let i = 0; i < accData.length; i++) {
|
|
78
|
-
result = ekf.update(dt[i], accData[i], gyrData[i], magData[i]);
|
|
79
|
-
distance = Quaternion.distance(result, expectationsAbsolute[i]);
|
|
80
|
-
expect(distance).to.below(0.000001);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('initRelative', () => {
|
|
86
|
-
it('Should return the good value', () => {
|
|
87
|
-
const ekf = new EkfAttitude();
|
|
88
|
-
ekf.setOrientationYaw(0);
|
|
89
|
-
ekf.setRelativeNoises({
|
|
90
|
-
acc: 0.5,
|
|
91
|
-
gyr: 0.3
|
|
92
|
-
});
|
|
93
|
-
const result = ekf.update(dt[0], accData[0], gyrData[0]);
|
|
94
|
-
const distance = Quaternion.distance(result, expectationsRelative[0]);
|
|
95
|
-
expect(distance).to.below(0.000001);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('updateRelative', () => {
|
|
100
|
-
it('Should return the good value', () => {
|
|
101
|
-
const ekf = new EkfAttitude();
|
|
102
|
-
ekf.setOrientationYaw(0);
|
|
103
|
-
ekf.setRelativeNoises({
|
|
104
|
-
acc: 0.5,
|
|
105
|
-
gyr: 0.3
|
|
106
|
-
});
|
|
107
|
-
let result;
|
|
108
|
-
let distance;
|
|
109
|
-
|
|
110
|
-
for (let i = 0; i < accData.length; i++) {
|
|
111
|
-
result = ekf.update(dt[i], accData[i], gyrData[i]);
|
|
112
|
-
distance = Quaternion.distance(result, expectationsRelative[i]);
|
|
113
|
-
expect(distance).to.below(0.000001);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import Provider from '../Provider';
|
|
2
|
-
import EventType from '../../events/EventType';
|
|
3
|
-
import EkfAttitude from './EkfAttitude';
|
|
4
|
-
import ImuProvider from '../others/ImuProvider';
|
|
5
|
-
import { Attitude } from '@wemap/geo';
|
|
6
|
-
import { deg2rad } from '@wemap/maths';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Relative attitude provider gives the device attitude in East-North-Up (ENU) frame using
|
|
11
|
-
* browser deviceorientation
|
|
12
|
-
* The provider does not work until an offset is given.
|
|
13
|
-
*/
|
|
14
|
-
class RelativeAttitudeProvider extends Provider {
|
|
15
|
-
|
|
16
|
-
lastTimestamp = 0;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @override
|
|
20
|
-
*/
|
|
21
|
-
constructor(onEvent, onError, options) {
|
|
22
|
-
super(onEvent, onError, options);
|
|
23
|
-
|
|
24
|
-
this.ekfAttitude = new EkfAttitude();
|
|
25
|
-
this.relativeOffsetQuaternion = [1, 0, 0, 0];
|
|
26
|
-
|
|
27
|
-
this.imuProvider = new ImuProvider(this.onImuEvent,
|
|
28
|
-
onError, { require: [EventType.Acceleration, EventType.AngularRate] });
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @override
|
|
34
|
-
*/
|
|
35
|
-
static get name() {
|
|
36
|
-
return 'RelativeAttitude';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @override
|
|
41
|
-
*/
|
|
42
|
-
static get displayName() {
|
|
43
|
-
return 'Relative Attitude from Ekf';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @override
|
|
48
|
-
*/
|
|
49
|
-
static get eventsType() {
|
|
50
|
-
return [EventType.RelativeAttitude];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @override
|
|
55
|
-
*/
|
|
56
|
-
static getRequiredProviders() {
|
|
57
|
-
return [ImuProvider];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @override
|
|
62
|
-
*/
|
|
63
|
-
startInternal() {
|
|
64
|
-
this.imuProvider.start();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @override
|
|
69
|
-
*/
|
|
70
|
-
stopInternal() {
|
|
71
|
-
this.imuProvider.stop();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @private
|
|
76
|
-
*/
|
|
77
|
-
onImuEvent = imuEvent => {
|
|
78
|
-
|
|
79
|
-
let timestamp, acceleration, angularRate;
|
|
80
|
-
imuEvent.forEach(event => {
|
|
81
|
-
if (event.dataType === EventType.Acceleration) {
|
|
82
|
-
acceleration = event.data;
|
|
83
|
-
timestamp = event.timestamp;
|
|
84
|
-
} else if (event.dataType === EventType.AngularRate) {
|
|
85
|
-
angularRate = event.data;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Handle timestamps and dt
|
|
90
|
-
if (this.lastTimestamp === 0) {
|
|
91
|
-
this.lastTimestamp = timestamp;
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const diffTime = timestamp - this.lastTimestamp;
|
|
95
|
-
this.lastTimestamp = timestamp;
|
|
96
|
-
|
|
97
|
-
const quaternion = this.ekfAttitude.update(diffTime, acceleration, angularRate);
|
|
98
|
-
|
|
99
|
-
if (quaternion) {
|
|
100
|
-
this.notify(this.createEvent(EventType.RelativeAttitude, new Attitude(quaternion), timestamp));
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
*
|
|
106
|
-
* Set yaw offset, this value will be used as the filter does not use magnetometer
|
|
107
|
-
* @param {Number} heading heading offset in radians and clockwise
|
|
108
|
-
*/
|
|
109
|
-
setOffset(_heading) {
|
|
110
|
-
|
|
111
|
-
// Minus before "heading" is here because ENU attitude is counter-clockwise whereas WGS84 heading is clockwise.
|
|
112
|
-
let heading = -_heading;
|
|
113
|
-
|
|
114
|
-
// Offset from window orientation
|
|
115
|
-
heading += deg2rad(window.orientation || 0);
|
|
116
|
-
|
|
117
|
-
this.ekfAttitude.setOrientationYaw(heading);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export default RelativeAttitudeProvider;
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { deg2rad } from '@wemap/maths';
|
|
2
|
-
import {
|
|
3
|
-
Browser, BrowserUtils
|
|
4
|
-
} from '@wemap/utils';
|
|
5
|
-
|
|
6
|
-
import isnumber from 'lodash.isnumber';
|
|
7
|
-
import Provider from '../Provider';
|
|
8
|
-
import EventType from '../../events/EventType';
|
|
9
|
-
import MissingAccelerometerError from '../../errors/MissingAccelerometerError';
|
|
10
|
-
import MissingGyroscopeError from '../../errors/MissingGyroscopeError';
|
|
11
|
-
import AskImuOnDesktopError from '../../errors/AskImuOnDesktopError';
|
|
12
|
-
import Availability from '../../events/Availability';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Imu (Inertial Measurement Unit) provider retrieve acceleration data
|
|
16
|
-
* and/or angular rate data from inertial sensors.
|
|
17
|
-
* opions.require has to be defined in order to work
|
|
18
|
-
*
|
|
19
|
-
* -----------------------------------
|
|
20
|
-
* Overview of compatibilities:
|
|
21
|
-
* -----------------------------------
|
|
22
|
-
*
|
|
23
|
-
* Chrome Android (v72.0.3626): YES (via devicemotion)
|
|
24
|
-
* Safari iOS (v12.0): YES (via devicemotion)
|
|
25
|
-
* Opera Android (v50.2.2426): NO {@link https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent}
|
|
26
|
-
* Firefox Android (v65.0.1): YES (via devicemotion)
|
|
27
|
-
*
|
|
28
|
-
* -----------------------------------
|
|
29
|
-
*/
|
|
30
|
-
class ImuProvider extends Provider {
|
|
31
|
-
|
|
32
|
-
requiredSensors = [];
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Constructor of ImuProvider
|
|
36
|
-
* options.require has to be filled by a list of EventType
|
|
37
|
-
* @example options = {require: [EventType.Acceleration, EventType.AngularRate]};
|
|
38
|
-
* @example options = {require: [EventType.Acceleration]};
|
|
39
|
-
*
|
|
40
|
-
* @param {Function} onEvent @see Provider#constructor
|
|
41
|
-
* @param {Function} onError @see Provider#constructor
|
|
42
|
-
* @param {Object} options @see Provider#constructor
|
|
43
|
-
*/
|
|
44
|
-
constructor(onEvent, onError, options) {
|
|
45
|
-
super(onEvent, onError, options);
|
|
46
|
-
|
|
47
|
-
if (!options.hasOwnProperty('require')) {
|
|
48
|
-
throw new Error('options.require is missing in ImuProvider constructor');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (options.require.length === 0) {
|
|
52
|
-
throw new Error('option.require is empty');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
options.require.forEach(elem => {
|
|
56
|
-
if (!ImuProvider.eventsType.includes(elem)) {
|
|
57
|
-
throw new Error(elem + ' is not recognised in options.require');
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
this.requiredSensors = options.require;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @override
|
|
66
|
-
*/
|
|
67
|
-
static get name() {
|
|
68
|
-
return 'Imu';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @override
|
|
73
|
-
*/
|
|
74
|
-
static get displayName() {
|
|
75
|
-
return 'Inertial Measurement Unit';
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @override
|
|
80
|
-
*/
|
|
81
|
-
static get eventsType() {
|
|
82
|
-
return [EventType.AngularRate, EventType.Acceleration];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @override
|
|
87
|
-
*/
|
|
88
|
-
static checkAvailability(options) {
|
|
89
|
-
return Availability.merge(
|
|
90
|
-
super.checkAvailability(options),
|
|
91
|
-
BrowserUtils.isMobile
|
|
92
|
-
? Availability.yes()
|
|
93
|
-
: Availability.no(new AskImuOnDesktopError())
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @override
|
|
99
|
-
*/
|
|
100
|
-
startInternal() {
|
|
101
|
-
window.addEventListener('devicemotion', this.parseDeviceMotionEvent, true);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* @override
|
|
106
|
-
*/
|
|
107
|
-
stopInternal() {
|
|
108
|
-
window.removeEventListener('devicemotion', this.parseDeviceMotionEvent, true);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* devicemotion callback
|
|
113
|
-
* @param {DeviceMotionEvent} e device motion event
|
|
114
|
-
* @returns {ProviderEvent[]} an array of provider events
|
|
115
|
-
* @private
|
|
116
|
-
*/
|
|
117
|
-
parseDeviceMotionEvent = e => {
|
|
118
|
-
|
|
119
|
-
const events = [];
|
|
120
|
-
|
|
121
|
-
const timestamp = e.timeStamp / 1e3;
|
|
122
|
-
|
|
123
|
-
if (this.requiredSensors.includes(EventType.Acceleration)) {
|
|
124
|
-
|
|
125
|
-
let acc;
|
|
126
|
-
if (e.accelerationIncludingGravity) {
|
|
127
|
-
const {
|
|
128
|
-
x, y, z
|
|
129
|
-
} = e.accelerationIncludingGravity;
|
|
130
|
-
|
|
131
|
-
if (isnumber(x) && isnumber(y) && isnumber(z)) {
|
|
132
|
-
acc = [x, y, z];
|
|
133
|
-
|
|
134
|
-
if (BrowserUtils.name === Browser.SAFARI) {
|
|
135
|
-
acc[0] *= -1;
|
|
136
|
-
acc[1] *= -1;
|
|
137
|
-
acc[2] *= -1;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (!acc) {
|
|
143
|
-
this.notifyError(new MissingAccelerometerError().from('devicemotion'));
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
events.push(this.createEvent(EventType.Acceleration, acc, timestamp));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (this.requiredSensors.includes(EventType.AngularRate)) {
|
|
152
|
-
|
|
153
|
-
let gyr;
|
|
154
|
-
if (e.rotationRate) {
|
|
155
|
-
const {
|
|
156
|
-
alpha, beta, gamma
|
|
157
|
-
} = e.rotationRate;
|
|
158
|
-
|
|
159
|
-
if (isnumber(alpha) && isnumber(beta) && isnumber(gamma)) {
|
|
160
|
-
gyr = [deg2rad(alpha), deg2rad(beta), deg2rad(gamma)];
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (!gyr) {
|
|
165
|
-
this.notifyError(new MissingGyroscopeError().from('devicemotion'));
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
events.push(this.createEvent(EventType.AngularRate, gyr, timestamp));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (events.length !== 0) {
|
|
173
|
-
this.notify(...events);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export default ImuProvider;
|