私はSLAMのドメインを初めて使いました。最近私はMobile Robot Programming Toolkitを見つけました。拡張カルマンフィルタを学びたいと思います。しかし、イライラして、私はサンプルbayesianTracking/test.cppが私にとっては少し複雑だと思います。MRPT(モバイルロボットプログラミングツールキット)カルマンフィルタ
この例では、一定の速度及び高度を想定し、航空機の位置を追跡し、そしてaircraft.Thatへ傾斜距離の測定は、我々を意味する:だから、私は、以下の単純な問題を解決するためにそれを適応させます
X = [X、 VX、 Y]
:水平距離、。水平速度、および高度 - 3つの状態変数を必要とします測定機能は:
H(X)= SQRT(X^2 + y^2)
この問題の我々は観察ヤコビアンを有する:
J_H = [X/SQRT(2^X^2 + y)は、 0、 Y/SQRT(2^X^2 + Y)]
あり私のコードに構文エラーがありませんが、結果が収束しません。多分私はいくつかの間違いを犯しましたか?誰かが私がどこに問題があるかを知る手伝いができますか?
#include <mrpt/bayes/CKalmanFilterCapable.h>
#include <mrpt/random.h>
#include <mrpt/system/os.h>
#include <mrpt/system/threads.h>
#include <iostream>
using namespace mrpt;
using namespace mrpt::bayes;
using namespace mrpt::math;
using namespace mrpt::utils;
using namespace mrpt::random;
using namespace std;
#define DELTA_TIME 0.05f // Time Step between Filter Steps
#define VEHICLE_INITIAL_X 10.0f
#define VEHICLE_INITIAL_Y 2000.0f
#define VEHICLE_INITIAL_V 200.0f
#define TRANSITION_MODEL_STD 1.0f
#define RANGE_SENSOR_NOISE_STD 5.0f
// Implementation of the system models as a EKF
class CRange: public CKalmanFilterCapable<3, 1, 0, 0>
{
public:
CRange();
virtual ~CRange();
void Process(double DeltaTime, double observationRange);
void getState(KFVector &xkk, KFMatrix &pkk)
{
xkk = m_xkk; //The system state vector.
pkk = m_pkk; //The system full covariance matrix
}
protected:
float m_obsRange;
float m_deltaTime; // Time Step between Filter Steps
// return the action vector u
void OnGetAction(KFArray_ACT &out_u) const;
// Implements the transition model
void OnTransitionModel(const KFArray_ACT &in_u,KFArray_VEH &inout_x,bool &out_skipPrediction) const;
// Implements the transition Jacobian
void OnTransitionJacobian(KFMatrix_VxV &out_F) const;
// Implements the transition noise covariance
void OnTransitionNoise(KFMatrix_VxV &out_Q) const;
// Return the observation NOISE covariance matrix, that is, the model of the Gaussian additive noise of the sensor.
void OnGetObservationNoise(KFMatrix_OxO &out_R) const;
/** This is called between the KF prediction step and the update step
* This method will be called just once for each complete KF iteration.
* \note It is assumed that the observations are independent, i.e. there are NO cross-covariances between them.
*/
void OnGetObservationsAndDataAssociation(
vector_KFArray_OBS &out_z,
mrpt::vector_int &out_data_association,
const vector_KFArray_OBS &in_all_predictions,
const KFMatrix &in_S,
const vector_size_t &in_lm_indices_in_S,
const KFMatrix_OxO &in_R
);
// Implements the observation prediction
void OnObservationModel(const vector_size_t &idx_landmarks_to_predict,vector_KFArray_OBS &out_predictions) const;
// Implements the observation Jacobians
void OnObservationJacobians(const size_t &idx_landmark_to_predict,KFMatrix_OxV &Hx,KFMatrix_OxF &Hy) const;
};
CRange::CRange()
{
KF_options.method = kfEKFNaive;
// State: (x,vx,y)
m_xkk.resize(3);
m_xkk[0]= VEHICLE_INITIAL_X;
m_xkk[1]= VEHICLE_INITIAL_V;
m_xkk[2]= VEHICLE_INITIAL_Y;
// Initial cov: Large uncertainty
m_pkk.setSize(3,3);
m_pkk.unit();
m_pkk = 50 * m_pkk;
}
CRange::~CRange()
{
}
void CRange::Process(double DeltaTime, double observationRange)
{
m_deltaTime = (float)DeltaTime;
m_obsRange = (float)observationRange;
runOneKalmanIteration(); // executes one complete step: prediction + update
}
// Must return the action vector u.
// param out_u: The action vector which will be passed to OnTransitionModel
void CRange::OnGetAction(KFArray_ACT &out_u) const
{
}
/** Implements the transition model(Project the state ahead)
param in_u : The vector returned by OnGetAction.
param inout_x: prediction value
param out_skip: Set this to true if for some reason you want to skip the prediction step. Default:false
*/
void CRange::OnTransitionModel(const KFArray_ACT &in_u, KFArray_VEH &inout_x, bool &out_skipPrediction) const
{
// The constant-velocities model is implemented simply as:
inout_x[0] += (inout_x[0] + m_deltaTime * inout_x[1]);
inout_x[1] = inout_x[1];
inout_x[2] = inout_x[2];
}
/** Implements the transition Jacobian
param out_F Must return the Jacobian.
The returned matrix must be N*N with N being the size of the whole state vector.
*/
void CRange::OnTransitionJacobian(KFMatrix_VxV &F) const
{
F.unit();
F(0,1) = m_deltaTime;
}
/** Implements the transition noise covariance
param out_Q Must return the covariance matrix.
The returned matrix must be of the same size than the jacobian from OnTransitionJacobian
*/
void CRange::OnTransitionNoise(KFMatrix_VxV &Q) const
{
Q.unit();
Q *= square(TRANSITION_MODEL_STD);
}
/** Return the observation NOISE covariance matrix, that is, the model of the Gaussian additive noise of the sensor.
param out_R : The noise covariance matrix. It might be non diagonal, but it'll usually be.
*/
void CRange::OnGetObservationNoise(KFMatrix_OxO &R) const
{
R.unit();
R *= square(RANGE_SENSOR_NOISE_STD);
}
// This is called between the KF prediction step and the update step
void CRange::OnGetObservationsAndDataAssociation(
vector_KFArray_OBS &out_z,
mrpt::vector_int &out_data_association,
const vector_KFArray_OBS &in_all_predictions,
const KFMatrix &in_S,
const vector_size_t &in_lm_indices_in_S,
const KFMatrix_OxO &in_R)
{
//out_z: N vectors, N being the number of "observations"
out_z.resize(1);
out_z[0][0] = m_obsRange;
}
/** Implements the observation prediction
param idx_landmark_to_predict: The indices of the landmarks in the map whose predictions are expected as output. For non SLAM-like problems, this input value is undefined and the application should just generate one observation for the given problem.
param out_predictions: The predicted observations.
*/
void CRange::OnObservationModel(const vector_size_t &idx_landmarks_to_predict,vector_KFArray_OBS &out_predictions) const
{
// idx_landmarks_to_predict is ignored in NON-SLAM problems
out_predictions.resize(1);
out_predictions[0][0] = sqrt(square(m_xkk[0]) + square(m_xkk[2]));
}
// Implements the observation Jacobians
void CRange::OnObservationJacobians(const size_t &idx_landmark_to_predict,KFMatrix_OxV &Hx,KFMatrix_OxF &Hy) const
{
Hx.zeros();
Hx(0,0) = m_xkk[0]/sqrt(square(m_xkk[0])+square(m_xkk[2]));
Hx(0,2) = m_xkk[2]/sqrt(square(m_xkk[0])+square(m_xkk[2]));
}
int main()
{
// Create class instance
CRange EKF;
EKF.KF_options.method = kfEKFNaive; //select the KF algorithm
// Initiate simulation
float x=0, y=1000, v=100; // true values
float t=0;
while (!mrpt::system::os::kbhit())
{
// Simulate noisy observation:
x += v * DELTA_TIME;
float realRange = sqrt(square(x)+square(y));
// double mrpt::random::CRandomGenerator::drawGaussian1D_normalized(double * likelihood = NULL)
// Generate a normalized (mean=0, std=1) normally distributed sample
float obsRange = max(0.0, realRange + RANGE_SENSOR_NOISE_STD * randomGenerator.drawGaussian1D_normalized());
printf("Real/Simulated range: %.03f/%.03f \n", realRange, obsRange);
// Process with EKF
EKF.Process(DELTA_TIME, obsRange);
// Show EKF state:
CRange::KFVector EKF_xkk;
CRange::KFMatrix EKF_pkk;
EKF.getState(EKF_xkk, EKF_pkk);
printf("Real state: x:%.03f v=%.03f y=%.03f \n",x,v,y);
cout << "EKF estimation:" <<endl<< EKF_xkk << endl;
cout <<"-------------------------------------------"<<endl;
// Delay(An OS-independent method for sending the current thread to "sleep" for a given period of time)
mrpt::system::sleep((int)(DELTA_TIME*1000));
t += DELTA_TIME;
}
return 0;
}
ありがとうございました!私はそのような間違いをすることを期待していませんでした。 – chen