filter_base.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, 2015, 2016, Charles River Analytics, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following
13  * disclaimer in the documentation and/or other materials provided
14  * with the distribution.
15  * 3. Neither the name of the copyright holder nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
35 
36 #include <iomanip>
37 #include <iostream>
38 #include <limits>
39 #include <sstream>
40 #include <vector>
41 
42 namespace RobotLocalization
43 {
45  accelerationGains_(TWIST_SIZE, 0.0),
46  accelerationLimits_(TWIST_SIZE, 0.0),
47  decelerationGains_(TWIST_SIZE, 0.0),
48  decelerationLimits_(TWIST_SIZE, 0.0),
49  controlAcceleration_(TWIST_SIZE),
50  controlTimeout_(0.0),
51  controlUpdateVector_(TWIST_SIZE, 0),
52  dynamicProcessNoiseCovariance_(STATE_SIZE, STATE_SIZE),
53  latestControlTime_(0.0),
54  state_(STATE_SIZE),
55  predictedState_(STATE_SIZE),
56  transferFunction_(STATE_SIZE, STATE_SIZE),
57  transferFunctionJacobian_(STATE_SIZE, STATE_SIZE),
58  estimateErrorCovariance_(STATE_SIZE, STATE_SIZE),
59  covarianceEpsilon_(STATE_SIZE, STATE_SIZE),
60  processNoiseCovariance_(STATE_SIZE, STATE_SIZE),
61  identity_(STATE_SIZE, STATE_SIZE),
62  debug_(false),
63  debugStream_(NULL),
64  useControl_(false),
65  useDynamicProcessNoiseCovariance_(false)
66  {
67  reset();
68  }
69 
71  {
72  }
73 
75  {
76  initialized_ = false;
77 
78  // Clear the state and predicted state
79  state_.setZero();
80  predictedState_.setZero();
81  controlAcceleration_.setZero();
82 
83  // Prepare the invariant parts of the transfer
84  // function
85  transferFunction_.setIdentity();
86 
87  // Clear the Jacobian
88  transferFunctionJacobian_.setZero();
89 
90  // Set the estimate error covariance. We want our measurements
91  // to be accepted rapidly when the filter starts, so we should
92  // initialize the state's covariance with large values.
93  estimateErrorCovariance_.setIdentity();
95 
96  // We need the identity for the update equations
97  identity_.setIdentity();
98 
99  // Set the epsilon matrix to be a matrix with small values on the diagonal
100  // It is used to maintain the positive-definite property of the covariance
101  covarianceEpsilon_.setIdentity();
102  covarianceEpsilon_ *= 0.001;
103 
104  // Assume 30Hz from sensor data (configurable)
105  sensorTimeout_ = 0.033333333;
106 
107  // Initialize our measurement time
109 
110  // These can be overridden via the launch parameters,
111  // but we need default values.
112  processNoiseCovariance_.setZero();
128 
130  }
131 
132  void FilterBase::computeDynamicProcessNoiseCovariance(const Eigen::VectorXd &state, const double delta)
133  {
134  // A more principled approach would be to get the current velocity from the state, make a diagonal matrix from it,
135  // and then rotate it to be in the world frame (i.e., the same frame as the pose data). We could then use this
136  // rotated velocity matrix to scale the process noise covariance for the pose variables as
137  // rotatedVelocityMatrix * poseCovariance * rotatedVelocityMatrix'
138  // However, this presents trouble for robots that may incur rotational error as a result of linear motion (and
139  // vice-versa). Instead, we create a diagonal matrix whose diagonal values are the vector norm of the state's
140  // velocity. We use that to scale the process noise covariance.
141  Eigen::MatrixXd velocityMatrix(TWIST_SIZE, TWIST_SIZE);
142  velocityMatrix.setIdentity();
143  velocityMatrix.diagonal() *= state.segment(POSITION_V_OFFSET, TWIST_SIZE).norm();
144 
146  velocityMatrix *
147  processNoiseCovariance_.block<TWIST_SIZE, TWIST_SIZE>(POSITION_OFFSET, POSITION_OFFSET) *
148  velocityMatrix.transpose();
149  }
150 
151  const Eigen::VectorXd& FilterBase::getControl()
152  {
153  return latestControl_;
154  }
155 
157  {
158  return latestControlTime_;
159  }
160 
162  {
163  return debug_;
164  }
165 
166  const Eigen::MatrixXd& FilterBase::getEstimateErrorCovariance()
167  {
169  }
170 
172  {
173  return initialized_;
174  }
175 
177  {
178  return lastMeasurementTime_;
179  }
180 
181  const Eigen::VectorXd& FilterBase::getPredictedState()
182  {
183  return predictedState_;
184  }
185 
186  const Eigen::MatrixXd& FilterBase::getProcessNoiseCovariance()
187  {
189  }
190 
192  {
193  return sensorTimeout_;
194  }
195 
196  const Eigen::VectorXd& FilterBase::getState()
197  {
198  return state_;
199  }
200 
202  {
203  FB_DEBUG("------ FilterBase::processMeasurement (" << measurement.topicName_ << ") ------\n");
204 
205  double delta = 0.0;
206 
207  // If we've had a previous reading, then go through the predict/update
208  // cycle. Otherwise, set our state and covariance to whatever we get
209  // from this measurement.
210  if (initialized_)
211  {
212  // Determine how much time has passed since our last measurement
213  delta = measurement.time_ - lastMeasurementTime_;
214 
215  FB_DEBUG("Filter is already initialized. Carrying out predict/correct loop...\n"
216  "Measurement time is " << std::setprecision(20) << measurement.time_ <<
217  ", last measurement time is " << lastMeasurementTime_ << ", delta is " << delta << "\n");
218 
219  // Only want to carry out a prediction if it's
220  // forward in time. Otherwise, just correct.
221  if (delta > 0)
222  {
223  validateDelta(delta);
224  predict(measurement.time_, delta);
225 
226  // Return this to the user
228  }
229 
230  correct(measurement);
231  }
232  else
233  {
234  FB_DEBUG("First measurement. Initializing filter.\n");
235 
236  // Initialize the filter, but only with the values we're using
237  size_t measurementLength = measurement.updateVector_.size();
238  for (size_t i = 0; i < measurementLength; ++i)
239  {
240  state_[i] = (measurement.updateVector_[i] ? measurement.measurement_[i] : state_[i]);
241  }
242 
243  // Same for covariance
244  for (size_t i = 0; i < measurementLength; ++i)
245  {
246  for (size_t j = 0; j < measurementLength; ++j)
247  {
248  estimateErrorCovariance_(i, j) = (measurement.updateVector_[i] && measurement.updateVector_[j] ?
249  measurement.covariance_(i, j) :
251  }
252  }
253 
254  initialized_ = true;
255  }
256 
257  if (delta >= 0.0)
258  {
259  lastMeasurementTime_ = measurement.time_;
260  }
261 
262  FB_DEBUG("------ /FilterBase::processMeasurement (" << measurement.topicName_ << ") ------\n");
263  }
264 
265  void FilterBase::setControl(const Eigen::VectorXd &control, const double controlTime)
266  {
267  latestControl_ = control;
268  latestControlTime_ = controlTime;
269  }
270 
271  void FilterBase::setControlParams(const std::vector<int> &updateVector, const double controlTimeout,
272  const std::vector<double> &accelerationLimits, const std::vector<double> &accelerationGains,
273  const std::vector<double> &decelerationLimits, const std::vector<double> &decelerationGains)
274  {
275  useControl_ = true;
276  controlUpdateVector_ = updateVector;
277  controlTimeout_ = controlTimeout;
278  accelerationLimits_ = accelerationLimits;
279  accelerationGains_ = accelerationGains;
280  decelerationLimits_ = decelerationLimits;
281  decelerationGains_ = decelerationGains;
282  }
283 
284  void FilterBase::setDebug(const bool debug, std::ostream *outStream)
285  {
286  if (debug)
287  {
288  if (outStream != NULL)
289  {
290  debugStream_ = outStream;
291  debug_ = true;
292  }
293  else
294  {
295  debug_ = false;
296  }
297  }
298  else
299  {
300  debug_ = false;
301  }
302  }
303 
304  void FilterBase::setUseDynamicProcessNoiseCovariance(const bool useDynamicProcessNoiseCovariance)
305  {
306  useDynamicProcessNoiseCovariance_ = useDynamicProcessNoiseCovariance;
307  }
308 
309  void FilterBase::setEstimateErrorCovariance(const Eigen::MatrixXd &estimateErrorCovariance)
310  {
311  estimateErrorCovariance_ = estimateErrorCovariance;
312  }
313 
314  void FilterBase::setLastMeasurementTime(const double lastMeasurementTime)
315  {
316  lastMeasurementTime_ = lastMeasurementTime;
317  }
318 
319  void FilterBase::setProcessNoiseCovariance(const Eigen::MatrixXd &processNoiseCovariance)
320  {
321  processNoiseCovariance_ = processNoiseCovariance;
323  }
324 
325  void FilterBase::setSensorTimeout(const double sensorTimeout)
326  {
327  sensorTimeout_ = sensorTimeout;
328  }
329 
330  void FilterBase::setState(const Eigen::VectorXd &state)
331  {
332  state_ = state;
333  }
334 
335  void FilterBase::validateDelta(double &delta)
336  {
337  // This handles issues with ROS time when use_sim_time is on and we're playing from bags.
338  if (delta > 100000.0)
339  {
340  FB_DEBUG("Delta was very large. Suspect playing from bag file. Setting to 0.01\n");
341 
342  delta = 0.01;
343  }
344  }
345 
346 
347  void FilterBase::prepareControl(const double referenceTime, const double predictionDelta)
348  {
349  controlAcceleration_.setZero();
350 
351  if (useControl_)
352  {
353  bool timedOut = ::fabs(referenceTime - latestControlTime_) >= controlTimeout_;
354 
355  if (timedOut)
356  {
357  FB_DEBUG("Control timed out. Reference time was " << referenceTime << ", latest control time was " <<
358  latestControlTime_ << ", control timeout was " << controlTimeout_ << "\n");
359  }
360 
361  for (size_t controlInd = 0; controlInd < TWIST_SIZE; ++controlInd)
362  {
363  if (controlUpdateVector_[controlInd])
364  {
366  (timedOut ? 0.0 : latestControl_(controlInd)), accelerationLimits_[controlInd],
367  accelerationGains_[controlInd], decelerationLimits_[controlInd], decelerationGains_[controlInd]);
368  }
369  }
370  }
371  }
372 
374  {
378  }
379 
380  bool FilterBase::checkMahalanobisThreshold(const Eigen::VectorXd &innovation,
381  const Eigen::MatrixXd &invCovariance,
382  const double nsigmas)
383  {
384  double sqMahalanobis = innovation.dot(invCovariance * innovation);
385  double threshold = nsigmas * nsigmas;
386 
387  if (sqMahalanobis >= threshold)
388  {
389  FB_DEBUG("Innovation mahalanobis distance test failed. Squared Mahalanobis is: " << sqMahalanobis << "\n" <<
390  "Threshold is: " << threshold << "\n" <<
391  "Innovation is: " << innovation << "\n" <<
392  "Innovation covariance is:\n" << invCovariance << "\n");
393 
394  return false;
395  }
396 
397  return true;
398  }
399 } // namespace RobotLocalization
void setProcessNoiseCovariance(const Eigen::MatrixXd &processNoiseCovariance)
Sets the process noise covariance for the filter.
std::vector< double > decelerationGains_
Gains applied to deceleration derived from control term.
Definition: filter_base.h:412
Eigen::MatrixXd transferFunctionJacobian_
The Kalman filter transfer function Jacobian.
Definition: filter_base.h:519
const int STATE_SIZE
Global constants that define our state vector size and offsets to groups of values within that state...
Definition: filter_common.h:75
double controlTimeout_
Timeout value, in seconds, after which a control is considered stale.
Definition: filter_base.h:428
const int TWIST_SIZE
Definition: filter_common.h:85
std::vector< int > controlUpdateVector_
Which control variables are being used (e.g., not every vehicle is controllable in Y or Z) ...
Definition: filter_base.h:424
const Eigen::VectorXd & getState()
Gets the filter state.
Eigen::MatrixXd estimateErrorCovariance_
This matrix stores the total error in our position estimate (the state_ variable).
Definition: filter_base.h:447
FilterBase()
Constructor for the FilterBase class.
Definition: filter_base.cpp:44
Structure used for storing and comparing measurements (for priority queues)
Definition: filter_base.h:61
Eigen::VectorXd predictedState_
Holds the last predicted state of the filter.
Definition: filter_base.h:470
Eigen::MatrixXd transferFunction_
The Kalman filter transfer function.
Definition: filter_base.h:509
void setEstimateErrorCovariance(const Eigen::MatrixXd &estimateErrorCovariance)
Manually sets the filter&#39;s estimate error covariance.
Eigen::MatrixXd covarianceEpsilon_
Covariance matrices can be incredibly unstable. We can add a small value to it at each iteration to h...
Definition: filter_base.h:434
void setControlParams(const std::vector< int > &updateVector, const double controlTimeout, const std::vector< double > &accelerationLimits, const std::vector< double > &accelerationGains, const std::vector< double > &decelerationLimits, const std::vector< double > &decelerationGains)
Sets the control update vector and acceleration limits.
void setLastMeasurementTime(const double lastMeasurementTime)
Sets the filter&#39;s last measurement time.
bool getDebug()
Gets the value of the debug_ variable.
const int POSITION_V_OFFSET
Definition: filter_common.h:78
#define FB_DEBUG(msg)
double getControlTime()
Returns the time at which the control term was issued.
Eigen::VectorXd latestControl_
Latest control term.
Definition: filter_base.h:420
Eigen::MatrixXd identity_
We need the identity for a few operations. Better to store it.
Definition: filter_base.h:451
double getLastMeasurementTime()
Gets the most recent measurement time.
double computeControlAcceleration(const double state, const double control, const double accelerationLimit, const double accelerationGain, const double decelerationLimit, const double decelerationGain)
Method for settings bounds on acceleration values derived from controls.
Definition: filter_base.h:346
double latestControlTime_
The time of reception of the most recent control term.
Definition: filter_base.h:466
void prepareControl(const double referenceTime, const double predictionDelta)
Converts the control term to an acceleration to be applied in the prediction step.
virtual ~FilterBase()
Destructor for the FilterBase class.
Definition: filter_base.cpp:70
const int POSITION_OFFSET
Definition: filter_common.h:76
const Eigen::VectorXd & getPredictedState()
Gets the filter&#39;s predicted state, i.e., the state estimate before correct() is called.
virtual void processMeasurement(const Measurement &measurement)
Does some final preprocessing, carries out the predict/update cycle.
void reset()
Resets filter to its unintialized state.
Definition: filter_base.cpp:74
bool debug_
Whether or not the filter is in debug mode.
Definition: filter_base.h:533
Eigen::MatrixXd dynamicProcessNoiseCovariance_
Gets updated when useDynamicProcessNoise_ is true.
Definition: filter_base.h:442
void setDebug(const bool debug, std::ostream *outStream=NULL)
Sets the filter into debug mode.
virtual void wrapStateAngles()
Keeps the state Euler angles in the range [-pi, pi].
double sensorTimeout_
The updates to the filter - both predict and correct - are driven by measurements. If we get a gap in measurements for some reason, we want the filter to continue estimating. When this gap occurs, as specified by this timeout, we will continue to call predict() at the filter&#39;s frequency.
Definition: filter_base.h:489
void setUseDynamicProcessNoiseCovariance(const bool dynamicProcessNoiseCovariance)
Enables dynamic process noise covariance calculation.
bool getInitializedStatus()
Gets the filter&#39;s initialized status.
virtual bool checkMahalanobisThreshold(const Eigen::VectorXd &innovation, const Eigen::MatrixXd &invCovariance, const double nsigmas)
Tests if innovation is within N-sigmas of covariance. Returns true if passed the test.
double clampRotation(double rotation)
Utility method keeping RPY angles in the range [-pi, pi].
virtual void predict(const double referenceTime, const double delta)=0
Carries out the predict step in the predict/update cycle. Projects the state and error matrices forwa...
void setControl(const Eigen::VectorXd &control, const double controlTime)
Sets the most recent control term.
bool useDynamicProcessNoiseCovariance_
If true, uses the robot&#39;s vehicle state and the static process noise covariance matrix to generate a ...
Definition: filter_base.h:528
const Eigen::VectorXd & getControl()
Returns the control vector currently being used.
Eigen::VectorXd measurement_
Definition: filter_base.h:69
void validateDelta(double &delta)
Ensures a given time delta is valid (helps with bag file playback issues)
virtual void correct(const Measurement &measurement)=0
Carries out the correct step in the predict/update cycle. This method must be implemented by subclass...
double getSensorTimeout()
Gets the sensor timeout value (in seconds)
std::vector< double > accelerationGains_
Gains applied to acceleration derived from control term.
Definition: filter_base.h:400
void computeDynamicProcessNoiseCovariance(const Eigen::VectorXd &state, const double delta)
Computes a dynamic process noise covariance matrix using the parameterized state. ...
double lastMeasurementTime_
Tracks the time the filter was last updated using a measurement.
Definition: filter_base.h:462
const Eigen::MatrixXd & getEstimateErrorCovariance()
Gets the estimate error covariance.
void setState(const Eigen::VectorXd &state)
Manually sets the filter&#39;s state.
void setSensorTimeout(const double sensorTimeout)
Sets the sensor timeout.
const Eigen::MatrixXd & getProcessNoiseCovariance()
Gets the filter&#39;s process noise covariance.
bool initialized_
Whether or not we&#39;ve received any measurements.
Definition: filter_base.h:455
Eigen::VectorXd controlAcceleration_
Variable that gets updated every time we process a measurement and we have a valid control...
Definition: filter_base.h:408
Eigen::VectorXd state_
This is the robot&#39;s state vector, which is what we are trying to filter. The values in this vector ar...
Definition: filter_base.h:494
std::vector< double > accelerationLimits_
Caps the acceleration we apply from control input.
Definition: filter_base.h:404
Eigen::MatrixXd processNoiseCovariance_
As we move through the world, we follow a predict/update cycle. If one were to imagine a scenario whe...
Definition: filter_base.h:482
std::vector< double > decelerationLimits_
Caps the deceleration we apply from control input.
Definition: filter_base.h:416
std::vector< int > updateVector_
Definition: filter_base.h:75
std::ostream * debugStream_
Used for outputting debug messages.
Definition: filter_base.h:438
bool useControl_
Whether or not we apply the control term.
Definition: filter_base.h:523


robot_localization
Author(s): Tom Moore
autogenerated on Wed Feb 3 2021 03:34:02