1 /* 2 * Copyright (C) 2016 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.ar.slam; 17 18 import com.irurueta.algebra.Matrix; 19 import com.irurueta.geometry.Point3D; 20 import com.irurueta.geometry.Quaternion; 21 import com.irurueta.statistics.MultivariateNormalDist; 22 23 import java.io.Serializable; 24 25 /** 26 * Base class to estimate position, velocity, acceleration and orientation of 27 * a device using sensor data such as accelerometers and gyroscopes. 28 * Implementations of this class are designed taking into account sensors 29 * available on Android devices. 30 * 31 * @param <D> calibrator type associated to implementations of SLAM calibration 32 * data. 33 */ 34 @SuppressWarnings("DuplicatedCode") 35 public abstract class BaseSlamEstimator<D extends BaseCalibrationData> implements Serializable { 36 37 /** 38 * Number of components in 3D. 39 */ 40 protected static final int N_COMPONENTS_3D = 3; 41 42 /** 43 * Conversion of nanoseconds to milliseconds. 44 */ 45 protected static final double NANOS_TO_SECONDS = 1e-9; 46 47 /** 48 * Indicates whether sample accumulation must be enabled or not. 49 */ 50 protected static final boolean DEFAULT_ENABLE_SAMPLE_ACCUMULATION = true; 51 52 /** 53 * Current position of the device along x-axis expressed in meters (m). 54 */ 55 protected double statePositionX; 56 57 /** 58 * Current position of the device along y-axis expressed in meters (m). 59 */ 60 protected double statePositionY; 61 62 /** 63 * Current position of the device along z-axis expressed in meters (m). 64 */ 65 protected double statePositionZ; 66 67 /** 68 * Current linear velocity of the device along x-axis expressed in meters 69 * per second (m/s). 70 */ 71 protected double stateVelocityX; 72 73 /** 74 * Current linear velocity of the device along y-axis expressed in meters 75 * per second (m/s). 76 */ 77 protected double stateVelocityY; 78 79 /** 80 * Current linear velocity of the device along z-axis expressed in meters 81 * per second (m/s). 82 */ 83 protected double stateVelocityZ; 84 85 /** 86 * Current linear acceleration of the device along x-axis expressed in 87 * meters per squared second (m/s^2). 88 */ 89 protected double stateAccelerationX; 90 91 /** 92 * Current linear acceleration of the device along y-axis expressed in 93 * meters per squared second (m/s^2). 94 */ 95 protected double stateAccelerationY; 96 97 /** 98 * Current linear acceleration of the device along z-axis expressed in 99 * meters per squared second (m/s^2). 100 */ 101 protected double stateAccelerationZ; 102 103 /** 104 * A value of quaternion containing current device orientation. 105 */ 106 protected double stateQuaternionA; 107 108 /** 109 * B value of quaternion containing current device orientation. 110 */ 111 protected double stateQuaternionB; 112 113 /** 114 * C value of quaternion containing current device orientation. 115 */ 116 protected double stateQuaternionC; 117 118 /** 119 * D value of quaternion containing current device orientation. 120 */ 121 protected double stateQuaternionD; 122 123 /** 124 * Angular speed of rotation of the device along x-axis expressed in radians 125 * per second (rad/s). 126 */ 127 protected double stateAngularSpeedX; 128 129 /** 130 * Angular speed of rotation of the device along y-axis expressed in radians 131 * per second (rad/s). 132 */ 133 protected double stateAngularSpeedY; 134 135 /** 136 * Angular speed of rotation of the device along z-axis expressed in radians 137 * per second (rad/s). 138 */ 139 protected double stateAngularSpeedZ; 140 141 /** 142 * Indicates whether an error occurred during the estimation. 143 * If an error occurs the estimator should be restarted since state values 144 * might become unreliable. 145 */ 146 protected boolean error; 147 148 /** 149 * Indicates whether accumulation of samples is enabled or not. 150 */ 151 protected boolean accumulationEnabled = DEFAULT_ENABLE_SAMPLE_ACCUMULATION; 152 153 /** 154 * Timestamp expressed in nanoseconds since the epoch time of the last 155 * accelerometer sample. 156 */ 157 protected long accelerometerTimestampNanos = -1; 158 159 /** 160 * Timestamp expressed in nanoseconds since the epoch time of the last 161 * gyroscope sample. 162 */ 163 protected long gyroscopeTimestampNanos = -1; 164 165 /** 166 * Number of accelerometer samples accumulated since last full sample. 167 */ 168 protected int accumulatedAccelerometerSamples = 0; 169 170 /** 171 * Number of gyroscope samples accumulated since last full sample. 172 */ 173 protected int accumulatedGyroscopeSamples = 0; 174 175 /** 176 * Average of acceleration along x-axis accumulated since last full sample. 177 * Expressed in meters per squared second (m/s^2). 178 */ 179 protected double accumulatedAccelerationSampleX; 180 181 /** 182 * Average of acceleration along y-axis accumulated since last full sample. 183 * Expressed in meters per squared second (m/s^2). 184 */ 185 protected double accumulatedAccelerationSampleY; 186 187 /** 188 * Average of acceleration along z-axis accumulated since last full sample. 189 * Expressed in meters per squared second (m/s^2). 190 */ 191 protected double accumulatedAccelerationSampleZ; 192 193 /** 194 * Average of angular speed along x-axis accumulated since last full sample. 195 * Expressed in radians per second (rad/s). 196 */ 197 protected double accumulatedAngularSpeedSampleX; 198 199 /** 200 * Average of angular speed along y-axis accumulated since last full sample. 201 * Expressed in radians per second (rad/s). 202 */ 203 protected double accumulatedAngularSpeedSampleY; 204 205 /** 206 * Average of angular speed along z-axis accumulated since last full sample. 207 * Expressed in radians per second (red/s). 208 */ 209 protected double accumulatedAngularSpeedSampleZ; 210 211 /** 212 * Listener in charge of handling events raised by instances of this class. 213 */ 214 protected transient BaseSlamEstimatorListener<D> listener; 215 216 /** 217 * Calibration data. When provided, its mean and covariance are used 218 * to correct control samples and adjust process covariance matrix during 219 * Kalman filtering in prediction stage. 220 */ 221 protected D calibrationData; 222 223 /** 224 * Multivariate distribution to be reused during propagation of calibrated 225 * covariance. 226 */ 227 protected transient MultivariateNormalDist normalDist; 228 229 /** 230 * Constructor. 231 */ 232 protected BaseSlamEstimator() { 233 reset(); 234 } 235 236 /** 237 * Resets position and timestamp to zero while keeping other state parameters. 238 */ 239 public final void resetPosition() { 240 reset(0.0, 0.0, 0.0, stateVelocityX, stateVelocityY, 241 stateVelocityZ, stateAccelerationX, stateAccelerationY, stateAccelerationZ, 242 stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD, 243 stateAngularSpeedX, stateAngularSpeedY, stateAngularSpeedZ); 244 } 245 246 /** 247 * Resets linear velocity and timestamp to zero while keeping other state parameters. 248 */ 249 public final void resetVelocity() { 250 reset(statePositionX, statePositionY, statePositionZ, 0.0, 0.0, 251 0.0, stateAccelerationX, stateAccelerationY, stateAccelerationZ, 252 stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD, 253 stateAngularSpeedX, stateAngularSpeedY, stateAngularSpeedZ); 254 } 255 256 /** 257 * Resets position, linear velocity and timestamp to zero while keeping other state parameters. 258 */ 259 public final void resetPositionAndVelocity() { 260 reset(0.0, 0.0, 0.0, 0.0, 0.0, 261 0.0, stateAccelerationX, stateAccelerationY, stateAccelerationZ, 262 stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD, 263 stateAngularSpeedX, stateAngularSpeedY, stateAngularSpeedZ); 264 } 265 266 /** 267 * Resets acceleration and timestamp to zero while keeping other state parameters. 268 */ 269 public final void resetAcceleration() { 270 reset(statePositionX, statePositionY, statePositionZ, 271 stateVelocityX, stateVelocityY, stateVelocityZ, 0.0, 272 0.0, 0.0, stateQuaternionA, stateQuaternionB, 273 stateQuaternionC, stateQuaternionD, stateAngularSpeedX, stateAngularSpeedY, 274 stateAngularSpeedZ); 275 } 276 277 /** 278 * Resets orientation and timestamp to zero while keeping other state parameters. 279 */ 280 public final void resetOrientation() { 281 reset(statePositionX, statePositionY, statePositionZ, 282 stateVelocityX, stateVelocityY, stateVelocityZ, 283 stateAccelerationX, stateAccelerationY, stateAccelerationZ, 284 1.0, 0.0, 0.0, 0.0, 285 stateAngularSpeedX, stateAngularSpeedY, stateAngularSpeedZ); 286 } 287 288 /** 289 * Resets angular speed and timestamp to zero while keeping other state parameters. 290 */ 291 public final void resetAngularSpeed() { 292 reset(statePositionX, statePositionY, statePositionZ, 293 stateVelocityX, stateVelocityY, stateVelocityZ, 294 stateAccelerationX, stateAccelerationY, stateAccelerationZ, 295 stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD, 296 0.0, 0.0, 0.0); 297 } 298 299 /** 300 * Resets position, linear velocity, linear acceleration, orientation and 301 * angular speed of the device to zero. 302 */ 303 public final void reset() { 304 // NOTE: initial orientation is expressed as quaternion 305 // (1.0, 0.0, 0.0, 0.0) which is equivalent to no rotation. 306 reset(0.0, 0.0, 0.0, 0.0, 0.0, 307 0.0, 0.0, 0.0, 0.0, 308 1.0, 0.0, 0.0, 0.0, 309 0.0, 0.0, 0.0); 310 } 311 312 /** 313 * Obtains current x-position of the device expressed in meters (m). 314 * 315 * @return x-position of the device expressed in meters (m). 316 */ 317 public double getStatePositionX() { 318 return statePositionX; 319 } 320 321 /** 322 * Obtains current y-position of the device expressed in meters (m). 323 * 324 * @return y-position of the device expressed in meters (m). 325 */ 326 public double getStatePositionY() { 327 return statePositionY; 328 } 329 330 /** 331 * Obtains current z-position of the device expressed in meters (m). 332 * 333 * @return z-position of the device expressed in meters (m). 334 */ 335 public double getStatePositionZ() { 336 return statePositionZ; 337 } 338 339 /** 340 * Gets x,y,z coordinates of the device position expressed in meters (m). 341 * 342 * @return position of the device. 343 */ 344 public double[] getStatePosition() { 345 return new double[]{statePositionX, statePositionY, statePositionZ}; 346 } 347 348 /** 349 * Gets x,y,z coordinates of the device position expressed in meters (m) and 350 * stores the result into provided array. 351 * 352 * @param result array where position coordinates will be stored. 353 * @throws IllegalArgumentException if the array does not have length 3. 354 */ 355 public void getStatePosition(final double[] result) { 356 if (result.length != N_COMPONENTS_3D) { 357 // result must have length 3 358 throw new IllegalArgumentException(); 359 } 360 result[0] = statePositionX; 361 result[1] = statePositionY; 362 result[2] = statePositionZ; 363 } 364 365 /** 366 * Gets current linear velocity of the device along x-axis expressed in 367 * meters per second (m/s). 368 * 369 * @return current velocity along x-axis expressed in meters per second 370 * (m/s). 371 */ 372 public double getStateVelocityX() { 373 return stateVelocityX; 374 } 375 376 /** 377 * Gets current linear velocity of the device along y-axis expressed in 378 * meters per second (m/s). 379 * 380 * @return current velocity along y-axis expressed in meters per second 381 * (m/s). 382 */ 383 public double getStateVelocityY() { 384 return stateVelocityY; 385 } 386 387 /** 388 * Gets current linear velocity of the device along z-axis expressed in 389 * meters per second (m/s). 390 * 391 * @return current velocity along z-axis expressed in meters per second 392 * (m/s). 393 */ 394 public double getStateVelocityZ() { 395 return stateVelocityZ; 396 } 397 398 /** 399 * Gets x,y,z coordinates of current linear velocity of the device expressed 400 * in meters per second (m/s). 401 * 402 * @return current linear velocity of the device. 403 */ 404 public double[] getStateVelocity() { 405 return new double[]{stateVelocityX, stateVelocityY, stateVelocityZ}; 406 } 407 408 /** 409 * Gets x,y,z coordinates of current linear velocity of the device expressed 410 * in meters per second (m/s). 411 * 412 * @param result array where linear velocity of the device will be stored. 413 * @throws IllegalArgumentException if result array does not have length 3. 414 */ 415 public void getStateVelocity(final double[] result) { 416 if (result.length != N_COMPONENTS_3D) { 417 // result must have length 3 418 throw new IllegalArgumentException(); 419 } 420 result[0] = stateVelocityX; 421 result[1] = stateVelocityY; 422 result[2] = stateVelocityZ; 423 } 424 425 /** 426 * Gets current linear acceleration of the device along x-axis expressed in 427 * meters per squared second (m/s^2). 428 * 429 * @return linear acceleration of the device along x-axis. 430 */ 431 public double getStateAccelerationX() { 432 return stateAccelerationX; 433 } 434 435 /** 436 * Gets current linear acceleration of the device along y-axis expressed in 437 * meters per squared second (m/s^2). 438 * 439 * @return linear acceleration of the device along y-axis. 440 */ 441 public double getStateAccelerationY() { 442 return stateAccelerationY; 443 } 444 445 /** 446 * Gets current linear acceleration of the device along z-axis expressed in 447 * meters per squared second (m/s^2). 448 * 449 * @return linear acceleration of the device along z-axis. 450 */ 451 public double getStateAccelerationZ() { 452 return stateAccelerationZ; 453 } 454 455 /** 456 * Gets current x,y,z linear acceleration coordinates of the device 457 * expressed in meters per squared second (m/s^2). 458 * 459 * @return current linear acceleration of the device. 460 */ 461 public double[] getStateAcceleration() { 462 return new double[]{stateAccelerationX, stateAccelerationY, stateAccelerationZ}; 463 } 464 465 /** 466 * Gets current x,y,z linear acceleration coordinates of the device 467 * expressed in meters per squared second (m/s^2). 468 * 469 * @param result array where resulting linear acceleration coordinates will 470 * be stored. 471 * @throws IllegalArgumentException if array does not have length 3. 472 */ 473 public void getStateAcceleration(final double[] result) { 474 if (result.length != N_COMPONENTS_3D) { 475 // result must have length 3 476 throw new IllegalArgumentException(); 477 } 478 result[0] = stateAccelerationX; 479 result[1] = stateAccelerationY; 480 result[2] = stateAccelerationZ; 481 } 482 483 /** 484 * Gets A value of quaternion containing current device orientation. 485 * 486 * @return A value of quaternion containing current device orientation. 487 */ 488 public double getStateQuaternionA() { 489 return stateQuaternionA; 490 } 491 492 /** 493 * Gets B value of quaternion containing current device orientation. 494 * 495 * @return B value of quaternion containing current device orientation. 496 */ 497 public double getStateQuaternionB() { 498 return stateQuaternionB; 499 } 500 501 /** 502 * Gets C value of quaternion containing current device orientation. 503 * 504 * @return C value of quaternion containing current device orientation. 505 */ 506 public double getStateQuaternionC() { 507 return stateQuaternionC; 508 } 509 510 /** 511 * Gets D value of quaternion containing current device orientation. 512 * 513 * @return D value of quaternion containing current device orientation. 514 */ 515 public double getStateQuaternionD() { 516 return stateQuaternionD; 517 } 518 519 /** 520 * Gets A, B, C, D values of quaternion containing current device 521 * orientation. 522 * 523 * @return A, B, C, D values of quaternion containing current device 524 * orientation. 525 */ 526 public double[] getStateQuaternionArray() { 527 return new double[]{stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD}; 528 } 529 530 /** 531 * Gets A, B, C, D values of quaternion containing current device 532 * orientation. 533 * 534 * @param result array where A, B, C, D values of quaternion will be stored. 535 * Must have length 4. 536 * @throws IllegalArgumentException if provided array does not have length 537 * 4. 538 */ 539 public void getStateQuaternionArray(final double[] result) { 540 if (result.length != Quaternion.N_PARAMS) { 541 throw new IllegalArgumentException("result must have length 4"); 542 } 543 result[0] = stateQuaternionA; 544 result[1] = stateQuaternionB; 545 result[2] = stateQuaternionC; 546 result[3] = stateQuaternionD; 547 } 548 549 /** 550 * Gets quaternion containing current device orientation. 551 * 552 * @return quaternion containing current device orientation. 553 */ 554 public Quaternion getStateQuaternion() { 555 return new Quaternion(stateQuaternionA, stateQuaternionB, stateQuaternionC, stateQuaternionD); 556 } 557 558 /** 559 * Gets quaternion containing current device orientation. 560 * 561 * @param result instance where quaternion data will be stored. 562 */ 563 public void getStateQuaternion(final Quaternion result) { 564 result.setA(stateQuaternionA); 565 result.setB(stateQuaternionB); 566 result.setC(stateQuaternionC); 567 result.setD(stateQuaternionD); 568 } 569 570 /** 571 * Gets angular speed along x-axis expressed in radians per second (rad/s). 572 * 573 * @return angular speed along x-axis. 574 */ 575 public double getStateAngularSpeedX() { 576 return stateAngularSpeedX; 577 } 578 579 /** 580 * Gets angular speed along y-axis expressed in radians per second (rad/s). 581 * 582 * @return angular speed along y-axis. 583 */ 584 public double getStateAngularSpeedY() { 585 return stateAngularSpeedY; 586 } 587 588 /** 589 * Gets angular speed along z-axis expressed in radians per second (rad/s). 590 * 591 * @return angular speed along z-axis. 592 */ 593 public double getStateAngularSpeedZ() { 594 return stateAngularSpeedZ; 595 } 596 597 /** 598 * Gets angular speed of the device along x,y,z axes expressed in radians 599 * per second (rad/s). 600 * 601 * @return device's angular speed. 602 */ 603 public double[] getStateAngularSpeed() { 604 return new double[]{stateAngularSpeedX, stateAngularSpeedY, stateAngularSpeedZ}; 605 } 606 607 /** 608 * Gets angular speed of the device along x,y,z axes expressed in radians 609 * per second (rad/s) and stores the result into provided array. 610 * 611 * @param result array where angular speed will be stored. Must have length 612 * 3. 613 * @throws IllegalArgumentException if provided array does not have length 614 * 3. 615 */ 616 public void getStateAngularSpeed(final double[] result) { 617 if (result.length != N_COMPONENTS_3D) { 618 // result must have length 3 619 throw new IllegalArgumentException(); 620 } 621 result[0] = stateAngularSpeedX; 622 result[1] = stateAngularSpeedY; 623 result[2] = stateAngularSpeedZ; 624 } 625 626 /** 627 * Gets covariance matrix of state variables (position, velocity, acceleration, orientation and 628 * angular speed). 629 * Actual meaning of elements in returned matrix will depend on actual implementation of the estimator. 630 * 631 * @return covariance matrix of state variables. 632 */ 633 public abstract Matrix getStateCovariance(); 634 635 /** 636 * Indicates whether an error occurred during the estimation. 637 * If an error occurs the estimator should be restarted since state values 638 * might become unreliable. 639 * 640 * @return true if an error occurred since last start time, false otherwise. 641 */ 642 public boolean hasError() { 643 return error; 644 } 645 646 /** 647 * Indicates whether accumulation of samples is enabled or not. 648 * 649 * @return true if accumulation of samples is enabled, false otherwise. 650 */ 651 public boolean isAccumulationEnabled() { 652 return accumulationEnabled; 653 } 654 655 /** 656 * Specifies whether accumulation of samples is enabled or not. 657 * 658 * @param accumulationEnabled true if accumulation of samples is enabled, 659 * false otherwise. 660 */ 661 public void setAccumulationEnabled(final boolean accumulationEnabled) { 662 this.accumulationEnabled = accumulationEnabled; 663 } 664 665 /** 666 * Gets timestamp expressed in nanoseconds since the epoch time of the last 667 * accelerometer sample, or -1 if no sample has been set yet. 668 * 669 * @return timestamp expressed in nanoseconds since the epoch time of the 670 * last accelerometer sample, or -1. 671 */ 672 public long getAccelerometerTimestampNanos() { 673 return accelerometerTimestampNanos; 674 } 675 676 /** 677 * Gets timestamp expressed in nanoseconds since the epoch time of the last 678 * gyroscope sample, or -1 if no sample has been set yet. 679 * 680 * @return timestamp expressed in nanoseconds since the epoch time of the 681 * last gyroscope sample, or -1. 682 */ 683 public long getGyroscopeTimestampNanos() { 684 return gyroscopeTimestampNanos; 685 } 686 687 /** 688 * Gets number of accelerometer samples accumulated since last full sample. 689 * 690 * @return number of accelerometer samples accumulated since last full 691 * sample. 692 */ 693 public int getAccumulatedAccelerometerSamples() { 694 return accumulatedAccelerometerSamples; 695 } 696 697 /** 698 * Gets number of gyroscope samples accumulated since last full sample. 699 * 700 * @return number of gyroscope samples accumulated since last full sample. 701 */ 702 public int getAccumulatedGyroscopeSamples() { 703 return accumulatedGyroscopeSamples; 704 } 705 706 /** 707 * Indicates whether the accelerometer sample has been received since the 708 * last full sample (accelerometer + gyroscope). 709 * 710 * @return true if accelerometer sample has been received, false otherwise. 711 */ 712 public boolean isAccelerometerSampleReceived() { 713 return accumulatedAccelerometerSamples > 0; 714 } 715 716 /** 717 * Indicates whether the gyroscope sample has been received since the last 718 * full sample (accelerometer + gyroscope). 719 * 720 * @return true if gyroscope sample has been received, false otherwise. 721 */ 722 public boolean isGyroscopeSampleReceived() { 723 return accumulatedGyroscopeSamples > 0; 724 } 725 726 /** 727 * Indicates whether a full sample (accelerometer + gyroscope) has been 728 * received or not. 729 * 730 * @return true if full sample has been received, false otherwise. 731 */ 732 public boolean isFullSampleAvailable() { 733 return isAccelerometerSampleReceived() && isGyroscopeSampleReceived(); 734 } 735 736 /** 737 * Gets average acceleration along x-axis accumulated since last full 738 * sample. Expressed in meters per squared second (m/s^2). 739 * 740 * @return average acceleration along x-axis accumulated since last full 741 * sample. 742 */ 743 public double getAccumulatedAccelerationSampleX() { 744 return accumulatedAccelerationSampleX; 745 } 746 747 /** 748 * Gets average acceleration along y-axis accumulated since last full 749 * sample. Expressed in meters per squared second (m/s^2). 750 * 751 * @return average acceleration along y-axis accumulated since last full 752 * sample. 753 */ 754 public double getAccumulatedAccelerationSampleY() { 755 return accumulatedAccelerationSampleY; 756 } 757 758 /** 759 * Gets average acceleration along z-axis accumulated since last full 760 * sample. Expressed in meters per squared second (m/s^2). 761 * 762 * @return average acceleration along z-axis accumulated since last full 763 * sample. 764 */ 765 public double getAccumulatedAccelerationSampleZ() { 766 return accumulatedAccelerationSampleZ; 767 } 768 769 /** 770 * Gets average acceleration along x,y,z axes accumulated since last full 771 * sample. Expressed in meters per squared second (m/s^2). 772 * 773 * @return average acceleration along x,y,z axes expressed in meters per 774 * squared second (m/s^2). 775 */ 776 public double[] getAccumulatedAccelerationSample() { 777 return new double[]{ 778 accumulatedAccelerationSampleX, 779 accumulatedAccelerationSampleY, 780 accumulatedAccelerationSampleZ 781 }; 782 } 783 784 /** 785 * Gets average acceleration along x,y,z axes accumulated since last full 786 * sample. Expressed in meters per squared second (m/s^2). 787 * 788 * @param result array where average acceleration along x,y,z axes will be 789 * stored. 790 * @throws IllegalArgumentException if provided array does not have length 791 * 3. 792 */ 793 public void getAccumulatedAccelerationSample(final double[] result) { 794 if (result.length != N_COMPONENTS_3D) { 795 throw new IllegalArgumentException("result must have length 3"); 796 } 797 result[0] = accumulatedAccelerationSampleX; 798 result[1] = accumulatedAccelerationSampleY; 799 result[2] = accumulatedAccelerationSampleZ; 800 } 801 802 /** 803 * Gets average angular speed along x-axis accumulated since last full 804 * sample. Expressed in radians per second (rad/s). 805 * 806 * @return average angular speed along x-axis expressed in radians per 807 * second (rad/s). 808 */ 809 public double getAccumulatedAngularSpeedSampleX() { 810 return accumulatedAngularSpeedSampleX; 811 } 812 813 /** 814 * Gets average angular speed along y-axis accumulated since last full 815 * sample. Expressed in radians per second (rad/s). 816 * 817 * @return average angular speed along y-axis expressed in radians per 818 * second (rad/s). 819 */ 820 public double getAccumulatedAngularSpeedSampleY() { 821 return accumulatedAngularSpeedSampleY; 822 } 823 824 /** 825 * Gets average angular speed along z-axis accumulated since last full 826 * sample. Expressed in radians per second (rad/s). 827 * 828 * @return average angular speed along z-axis expressed in radians per 829 * second. 830 */ 831 public double getAccumulatedAngularSpeedSampleZ() { 832 return accumulatedAngularSpeedSampleZ; 833 } 834 835 /** 836 * Gets average angular speed along x,y,z axes accumulated since last full 837 * sample. Expressed in radians per second (rad/s). 838 * 839 * @return average angular speed along x,y,z axes expressed in radians per 840 * second. 841 */ 842 public double[] getAccumulatedAngularSpeedSample() { 843 return new double[]{ 844 accumulatedAngularSpeedSampleX, 845 accumulatedAngularSpeedSampleY, 846 accumulatedAngularSpeedSampleZ 847 }; 848 } 849 850 /** 851 * Gets average angular speed along x,y,z axes accumulated since last full 852 * sample. Expressed in radians per second (rad/s). 853 * 854 * @param result array where average angular speed along x,y,z axes will be 855 * stored. 856 * @throws IllegalArgumentException if provided array does not have length 857 * 3. 858 */ 859 public void getAccumulatedAngularSpeedSample(final double[] result) { 860 if (result.length != N_COMPONENTS_3D) { 861 throw new IllegalArgumentException("result must have length 3"); 862 } 863 result[0] = accumulatedAngularSpeedSampleX; 864 result[1] = accumulatedAngularSpeedSampleY; 865 result[2] = accumulatedAngularSpeedSampleZ; 866 } 867 868 /** 869 * Provides a new accelerometer sample. 870 * If accumulation is enabled, samples are averaged until a full sample is 871 * received. 872 * When a full sample (accelerometer + gyroscope) is received, internal 873 * state gets also updated. 874 * 875 * @param timestamp timestamp of accelerometer sample since epoch time and 876 * expressed in nanoseconds. 877 * @param accelerationX linear acceleration along x-axis expressed in meters 878 * per squared second (m/s^2). 879 * @param accelerationY linear acceleration along y-axis expressed in meters 880 * per squared second (m/s^2). 881 * @param accelerationZ linear acceleration along z-axis expressed in meters 882 * per squared second (m/s^2). 883 */ 884 public void updateAccelerometerSample( 885 final long timestamp, final float accelerationX, final float accelerationY, final float accelerationZ) { 886 if (!isFullSampleAvailable()) { 887 accelerometerTimestampNanos = timestamp; 888 if (isAccumulationEnabled() && isAccelerometerSampleReceived()) { 889 // accumulation enabled 890 final var nextSamples = accumulatedAccelerometerSamples + 1; 891 accumulatedAccelerationSampleX = (accumulatedAccelerationSampleX * accumulatedAccelerometerSamples 892 + accelerationX) / nextSamples; 893 accumulatedAccelerationSampleY = (accumulatedAccelerationSampleY * accumulatedAccelerometerSamples 894 + accelerationY) / nextSamples; 895 accumulatedAccelerationSampleZ = (accumulatedAccelerationSampleZ * accumulatedAccelerometerSamples 896 + accelerationZ) / nextSamples; 897 accumulatedAccelerometerSamples = nextSamples; 898 } else { 899 // accumulation disabled 900 accumulatedAccelerationSampleX = accelerationX; 901 accumulatedAccelerationSampleY = accelerationY; 902 accumulatedAccelerationSampleZ = accelerationZ; 903 accumulatedAccelerometerSamples++; 904 } 905 notifyFullSampleAndResetSampleReceive(); 906 } 907 } 908 909 /** 910 * Provides a new accelerometer sample. 911 * If accumulation is enabled, samples are averaged until a full sample is 912 * received. 913 * When a full sample (accelerometer + gyroscope) is received, internal 914 * state gets also updated. 915 * 916 * @param timestamp timestamp of accelerometer sample since epoch time and 917 * expressed in nanoseconds. 918 * @param data array containing x,y,z components of linear acceleration 919 * expressed in meters per squared second (m/s^2). 920 * @throws IllegalArgumentException if provided array does not have length 921 * 3. 922 */ 923 public void updateAccelerometerSample(final long timestamp, final float[] data) { 924 if (data.length != N_COMPONENTS_3D) { 925 throw new IllegalArgumentException("acceleration must have length 3"); 926 } 927 updateAccelerometerSample(timestamp, data[0], data[1], data[2]); 928 } 929 930 /** 931 * Provides a new gyroscope sample. 932 * If accumulation is enabled, samples are averaged until a full sample is 933 * received. 934 * When a full sample (accelerometer + gyroscope) is received, internal 935 * state gets also updated. 936 * 937 * @param timestamp timestamp of gyroscope sample since epoch time and 938 * expressed in nanoseconds. 939 * @param angularSpeedX angular speed of rotation along x-axis expressed in 940 * radians per second (rad/s). 941 * @param angularSpeedY angular speed of rotation along y-axis expressed in 942 * radians per second (rad/s). 943 * @param angularSpeedZ angular speed of rotation along z-axis expressed in 944 * radians per second (rad/s). 945 */ 946 public void updateGyroscopeSample( 947 final long timestamp, final float angularSpeedX, final float angularSpeedY, final float angularSpeedZ) { 948 if (!isFullSampleAvailable()) { 949 gyroscopeTimestampNanos = timestamp; 950 if (isAccumulationEnabled() && isGyroscopeSampleReceived()) { 951 // accumulation enabled 952 final var nextSamples = accumulatedGyroscopeSamples + 1; 953 accumulatedAngularSpeedSampleX = (accumulatedAngularSpeedSampleX * accumulatedGyroscopeSamples 954 + angularSpeedX) / nextSamples; 955 accumulatedAngularSpeedSampleY = (accumulatedAngularSpeedSampleY * accumulatedGyroscopeSamples 956 + angularSpeedY) / nextSamples; 957 accumulatedAngularSpeedSampleZ = (accumulatedAngularSpeedSampleZ * accumulatedGyroscopeSamples 958 + angularSpeedZ) / nextSamples; 959 accumulatedGyroscopeSamples = nextSamples; 960 } else { 961 // accumulation disabled 962 accumulatedAngularSpeedSampleX = angularSpeedX; 963 accumulatedAngularSpeedSampleY = angularSpeedY; 964 accumulatedAngularSpeedSampleZ = angularSpeedZ; 965 accumulatedGyroscopeSamples++; 966 } 967 notifyFullSampleAndResetSampleReceive(); 968 } 969 } 970 971 /** 972 * Provides a new gyroscope sample. 973 * If accumulation is enabled, samples are averaged until a full sample is 974 * received. 975 * When a full sample (accelerometer + gyroscope) is received, internal 976 * state gets also updated. 977 * 978 * @param timestamp timestamp of gyroscope sample since epoch time and 979 * expressed in nanoseconds. 980 * @param data angular speed of rotation along x,y,z axes expressed in 981 * radians per second (rad/s). 982 * @throws IllegalArgumentException if provided array does not have length 983 * 3. 984 */ 985 public void updateGyroscopeSample(final long timestamp, final float[] data) { 986 if (data.length != N_COMPONENTS_3D) { 987 throw new IllegalArgumentException("angular speed must have length 3"); 988 } 989 updateGyroscopeSample(timestamp, data[0], data[1], data[2]); 990 } 991 992 /** 993 * Gets most recent timestamp of received partial samples (accelerometer or 994 * gyroscope). 995 * 996 * @return most recent timestamp of received partial sample. 997 */ 998 public long getMostRecentTimestampNanos() { 999 return Math.max(accelerometerTimestampNanos, gyroscopeTimestampNanos); 1000 } 1001 1002 /** 1003 * Corrects system state with provided position measure having an accuracy 1004 * determined by provided covariance matrix. 1005 * 1006 * @param positionX new position along x-axis expressed in meters (m). 1007 * @param positionY new position along y-axis expressed in meters (m). 1008 * @param positionZ new position along z-axis expressed in meters (m). 1009 * @param positionCovariance new position covariance matrix determining 1010 * new position accuracy or null if last available covariance does not need 1011 * to be updated. 1012 * @throws IllegalArgumentException if provided covariance matrix is not 1013 * 3x3. 1014 */ 1015 public void correctWithPositionMeasure( 1016 final double positionX, final double positionY, final double positionZ, final Matrix positionCovariance) { 1017 setPositionCovarianceMatrix(positionCovariance); 1018 correctWithPositionMeasure(positionX, positionY, positionZ); 1019 } 1020 1021 /** 1022 * Corrects system state with provided position measure having an accuracy 1023 * determined by provided covariance matrix. 1024 * 1025 * @param position x,y,z coordinates of position expressed in meters (m). 1026 * Must have length 3. 1027 * @param positionCovariance new position covariance matrix determining new 1028 * position accuracy or null if last available covariance does not need to 1029 * be updated. 1030 * @throws IllegalArgumentException if provided covariance matrix is not 1031 * 3x3 or if provided position array does not have length 3. 1032 */ 1033 public void correctWithPositionMeasure(final double[] position, final Matrix positionCovariance) { 1034 if (position.length != N_COMPONENTS_3D) { 1035 throw new IllegalArgumentException("position must have length 3"); 1036 } 1037 correctWithPositionMeasure(position[0], position[1], position[2], positionCovariance); 1038 } 1039 1040 /** 1041 * Corrects system state with provided position measure having an accuracy 1042 * determined by provided covariance matrix. 1043 * 1044 * @param position position expressed in meters (m). 1045 * @param positionCovariance new position covariance matrix determining new 1046 * position accuracy or null if last available covariance does not need to 1047 * be updated. 1048 * @throws IllegalArgumentException if provided covariance matrix is not 1049 * 3x3. 1050 */ 1051 public void correctWithPositionMeasure(final Point3D position, final Matrix positionCovariance) { 1052 correctWithPositionMeasure(position.getInhomX(), position.getInhomY(), position.getInhomZ(), 1053 positionCovariance); 1054 } 1055 1056 /** 1057 * Updates covariance matrix of position measures. 1058 * If null is provided, covariance matrix is not updated. 1059 * 1060 * @param positionCovariance new position covariance determining position 1061 * accuracy or null if last available covariance does not need to be 1062 * updated. 1063 * @throws IllegalArgumentException if provided covariance matrix is not 1064 * 3x3. 1065 */ 1066 public abstract void setPositionCovarianceMatrix(final Matrix positionCovariance); 1067 1068 /** 1069 * Gets current covariance matrix of position measures determining current 1070 * accuracy of provided position measures. 1071 * 1072 * @return covariance matrix of position measures. 1073 */ 1074 public abstract Matrix getPositionCovarianceMatrix(); 1075 1076 /** 1077 * Corrects system state with provided position measure using current 1078 * position accuracy. 1079 * 1080 * @param positionX new position along x-axis expressed in meters (m). 1081 * @param positionY new position along y-axis expressed in meters (m). 1082 * @param positionZ new position along z-axis expressed in meters (m). 1083 */ 1084 public abstract void correctWithPositionMeasure( 1085 final double positionX, final double positionY, final double positionZ); 1086 1087 /** 1088 * Corrects system state with provided position measure using current 1089 * position accuracy. 1090 * 1091 * @param position x,y,z coordinates of position expressed in meters (m). 1092 * Must have length 3. 1093 * @throws IllegalArgumentException if provided array does not have length 1094 * 3. 1095 */ 1096 public void correctWithPositionMeasure(final double[] position) { 1097 correctWithPositionMeasure(position, null); 1098 } 1099 1100 /** 1101 * Corrects system state with provided position measure using current 1102 * position accuracy. 1103 * 1104 * @param position position expressed in meters (m). 1105 */ 1106 public void correctWithPositionMeasure(final Point3D position) { 1107 correctWithPositionMeasure(position, null); 1108 } 1109 1110 /** 1111 * Gets listener in charge of handling events raised by instances of this 1112 * class. 1113 * 1114 * @return listener in charge of handling events raised by instances of this 1115 * class. 1116 */ 1117 public BaseSlamEstimatorListener<D> getListener() { 1118 return listener; 1119 } 1120 1121 /** 1122 * Sets listener in charge of handling events raised by instances of this 1123 * class. 1124 * 1125 * @param listener listener in charge of handling events raised by instances 1126 * of this class. 1127 */ 1128 public void setListener(final BaseSlamEstimatorListener<D> listener) { 1129 this.listener = listener; 1130 } 1131 1132 /** 1133 * Gets calibration data. When provided, its mean and covariance are used 1134 * to correct control samples and adjust process covariance matrix during 1135 * Kalman filtering in prediction stage. 1136 * 1137 * @return calibration data. 1138 */ 1139 public D getCalibrationData() { 1140 return calibrationData; 1141 } 1142 1143 /** 1144 * Sets calibration data. When provided, its mean and covariance are used 1145 * to correct control samples and adjust process covariance matrix during 1146 * Kalman filtering in prediction stage. 1147 * 1148 * @param calibrationData calibration data. 1149 */ 1150 public void setCalibrationData(final D calibrationData) { 1151 this.calibrationData = calibrationData; 1152 } 1153 1154 /** 1155 * Resets position, linear velocity, linear acceleration, orientation and 1156 * angular speed to provided values. 1157 * 1158 * @param statePositionX position along x-axis expressed in meters (m). 1159 * @param statePositionY position along y-axis expressed in meters (m). 1160 * @param statePositionZ position along z-axis expressed in meters (m). 1161 * @param stateVelocityX linear velocity along x-axis expressed in meters 1162 * per second (m/s). 1163 * @param stateVelocityY linear velocity along y-axis expressed in meters 1164 * per second (m/s). 1165 * @param stateVelocityZ linear velocity along z-axis expressed in meters 1166 * per second (m/s). 1167 * @param stateAccelerationX linear acceleration along x-axis expressed in 1168 * meters per squared second (m/s^2). 1169 * @param stateAccelerationY linear acceleration along y-axis expressed in 1170 * meters per squared second (m/s^2). 1171 * @param stateAccelerationZ linear acceleration along z-axis expressed in 1172 * meters per squared second (m/s^2). 1173 * @param stateQuaternionA A value of orientation quaternion. 1174 * @param stateQuaternionB B value of orientation quaternion. 1175 * @param stateQuaternionC C value of orientation quaternion. 1176 * @param stateQuaternionD D value of orientation quaternion. 1177 * @param stateAngularSpeedX angular speed along x-axis expressed in radians 1178 * per second (rad/s). 1179 * @param stateAngularSpeedY angular speed along y-axis expressed in radians 1180 * per second (rad/s). 1181 * @param stateAngularSpeedZ angular speed along z-axis expressed in radians 1182 * per second (rad/s). 1183 */ 1184 protected void reset( 1185 final double statePositionX, final double statePositionY, final double statePositionZ, 1186 final double stateVelocityX, final double stateVelocityY, final double stateVelocityZ, 1187 final double stateAccelerationX, final double stateAccelerationY, final double stateAccelerationZ, 1188 final double stateQuaternionA, final double stateQuaternionB, 1189 final double stateQuaternionC, final double stateQuaternionD, 1190 final double stateAngularSpeedX, final double stateAngularSpeedY, final double stateAngularSpeedZ) { 1191 this.statePositionX = statePositionX; 1192 this.statePositionY = statePositionY; 1193 this.statePositionZ = statePositionZ; 1194 this.stateVelocityX = stateVelocityX; 1195 this.stateVelocityY = stateVelocityY; 1196 this.stateVelocityZ = stateVelocityZ; 1197 this.stateAccelerationX = stateAccelerationX; 1198 this.stateAccelerationY = stateAccelerationY; 1199 this.stateAccelerationZ = stateAccelerationZ; 1200 this.stateQuaternionA = stateQuaternionA; 1201 this.stateQuaternionB = stateQuaternionB; 1202 this.stateQuaternionC = stateQuaternionC; 1203 this.stateQuaternionD = stateQuaternionD; 1204 this.stateAngularSpeedX = stateAngularSpeedX; 1205 this.stateAngularSpeedY = stateAngularSpeedY; 1206 this.stateAngularSpeedZ = stateAngularSpeedZ; 1207 accelerometerTimestampNanos = gyroscopeTimestampNanos = -1; 1208 } 1209 1210 /** 1211 * Notifies that a full sample has been received and resets flags indicating 1212 * whether partial samples have been received. 1213 */ 1214 protected void notifyFullSampleAndResetSampleReceive() { 1215 if (isFullSampleAvailable()) { 1216 processFullSample(); 1217 accumulatedAccelerometerSamples = accumulatedGyroscopeSamples = 0; 1218 } 1219 } 1220 1221 /** 1222 * Method to be implemented in subclasses to process a full sample. 1223 */ 1224 protected abstract void processFullSample(); 1225 1226 /** 1227 * Listener for implementations of this class. 1228 * 1229 * @param <D> calibrator type associated to implementations of SLAM calibration 1230 * data. 1231 */ 1232 public interface BaseSlamEstimatorListener<D extends BaseCalibrationData> { 1233 /** 1234 * Called when a full sample (accelerometer + gyroscope, etc.) has been 1235 * received and is about to be processed to update internal state. 1236 * 1237 * @param estimator SLAM estimator. 1238 */ 1239 void onFullSampleReceived(final BaseSlamEstimator<D> estimator); 1240 1241 /** 1242 * Called when a full sample (accelerometer + gyroscope, etc.) has been 1243 * received and has already been processed, and hence internal state has 1244 * also been updated. 1245 * 1246 * @param estimator SLAM estimator. 1247 */ 1248 void onFullSampleProcessed(final BaseSlamEstimator<D> estimator); 1249 1250 /** 1251 * Called when internal state is about to be corrected by using an 1252 * external measure. 1253 * 1254 * @param estimator SLAM estimator. 1255 */ 1256 void onCorrectWithPositionMeasure(final BaseSlamEstimator<D> estimator); 1257 1258 /** 1259 * Called after internal state has been corrected using an external 1260 * measure. 1261 * 1262 * @param estimator SLAM estimator. 1263 */ 1264 void onCorrectedWithPositionMeasure(final BaseSlamEstimator<D> estimator); 1265 } 1266 }