00001
00002
00003
00004
00005
00006
00007
00008 #include "Tools/Math/MVTools.h"
00009 #include "ConstantSpeedModel.h"
00010 #include "Tools/Debugging/Debugging.h"
00011
00012
00013 double KalmanConstantSpeedModel::defaultA[16] =
00014 {
00015 1.0, 0.0, 0.0, 0.0,
00016 0.0, 1.0, 0.0, 0.0,
00017 0.0, 0.0, 1.0, 0.0,
00018 0.0, 0.0, 0.0, 1.0
00019 };
00020
00021 double KalmanConstantSpeedModel::defaultP[16] =
00022 {
00023 1.0, 0.0, 0.0, 0.0,
00024 0.0, 1.0, 0.0, 0.0,
00025 0.0, 0.0, 1.0, 0.0,
00026 0.0, 0.0, 0.0, 1.0
00027 };
00028
00029
00030
00031 double KalmanConstantSpeedModel::defaultQ[16] =
00032 {
00033 0.004, 0.000, 0.004, 0.000,
00034 0.000, 0.004, 0.000, 0.004,
00035 0.004, 0.000, 0.004, 0.000,
00036 0.000, 0.004, 0.000, 0.004
00037 };
00038
00039
00040 double KalmanConstantSpeedModel::defaultR[16] =
00041 {
00042 0.01*0.01, 0.00*0.00, 0.00*0.00, 0.00*0.00,
00043 0.00*0.00, 0.01*0.01, 0.00*0.00, 0.00*0.00,
00044 0.00*0.00, 0.00*0.00, 0.03*0.03, 0.00*0.00,
00045 0.00*0.00, 0.00*0.00, 0.00*0.00, 0.03*0.03
00046 };
00047
00048 KalmanConstantSpeedModel::KalmanConstantSpeedModel() : KalmanProcessModelBase(),
00049 panningVelocityThreshold(pi/3)
00050 {
00051 A = defaultA;
00052 globQ = defaultQ;
00053 globR = defaultR;
00054
00055
00056 double x[2] =
00057 {
00058 0.0,
00059 1.5
00060 };
00061 double fx[2] =
00062 {
00063 0.01*0.01,
00064 0.1*0.1
00065 };
00066 double Vx[2] =
00067 {
00068 0.0,
00069 2.5
00070 };
00071 double Vfx[2] =
00072 {
00073 0.0001,
00074 0.1
00075 };
00076 calculateVarianceAdaptionPolynom(x, fx, varianceAdaptionPosition);
00077 calculateVarianceAdaptionPolynom(Vx, Vfx, varianceAdaptionSpeed);
00078
00079 reset();
00080 }
00081
00082 KalmanConstantSpeedModel::~KalmanConstantSpeedModel()
00083 {
00084 }
00085
00086 void KalmanConstantSpeedModel::calculateVarianceAdaptionPolynom(
00087 double x[2], double fx[2], double result[2])
00088 {
00089 double dMatrixValues[4] =
00090 {
00091 x[0]*x[0], 1,
00092 x[1]*x[1], 1
00093 };
00094 Matrix_nxn<double, 2> A(dMatrixValues);
00095 Vector_n<double, 2> b(fx);
00096
00097 Vector_n<double, 2> sol = A.solve(b);
00098 result[0] = sol[0];
00099 result[1] = sol[1];
00100 }
00101
00102 void KalmanConstantSpeedModel::reset()
00103 {
00104 initState = NotInited;
00105 P = defaultP;
00106 lastLiklihood = 0.0;
00107 lastTime = 0.0;
00108 double zeros[4] = {0.0, 0.0, 0.0, 0.0};
00109 x_act = zeros;
00110 }
00111
00112 KalmanUpdateResult
00113 KalmanConstantSpeedModel::update(double time, double x, double y, const RobotPose& pose, double panningVelocity)
00114 {
00115 KalmanUpdateResult res;
00116
00117
00118 if (initState == NotInited)
00119 {
00120
00121 x_act[0] = z[0] = x;
00122 x_act[1] = z[1] = y;
00123
00124 initState = PositionInited;
00125 lastTime = time;
00126
00127 res.liklihood = 0.0;
00128 return res;
00129 }
00130
00131
00132 double dt = time - lastTime;
00133 if (MVTools::isNearZero(dt))
00134 {
00135
00136 res.state.x = x_act[0];
00137 res.state.y = x_act[1];
00138 res.state.vx = x_act[2];
00139 res.state.vy = x_act[3];
00140 res.liklihood = lastLiklihood;
00141 return res;
00142 }
00143
00144 if (initState == PositionInited)
00145 {
00146
00147 x_act[2] = z[2] = (x - x_act[0]) / dt;
00148 x_act[3] = z[3] = (y - x_act[1]) / dt;
00149 x_act[0] = z[0] = x;
00150 x_act[1] = z[1] = y;
00151
00152 initState = Ready;
00153 lastTime = time;
00154
00155 res.liklihood = 0.0;
00156 return res;
00157 }
00158
00159
00160 try
00161 {
00162
00163 double dt2 = dt*dt;
00164 double dt3 = dt2*dt;
00165 double dt4 = dt2*dt2;
00166 Q = globQ;
00167 Q[0][0] *= dt4;
00168 Q[0][2] *= dt3;
00169 Q[1][1] *= dt4;
00170 Q[1][3] *= dt3;
00171 Q[2][0] *= dt3;
00172 Q[2][2] *= dt2;
00173 Q[3][1] *= dt3;
00174 Q[3][3] *= dt2;
00175
00176
00177 try
00178 {
00179 A[0][2] = dt;
00180 A[1][3] = dt;
00181 x_minus = A*x_act;
00182 P_minus = A*P*transpose(A) + Q;
00183
00184
00185 z[2] = (x - z[0])/dt;
00186 z[3] = (y - z[1])/dt;
00187 z[0] = x;
00188 z[1] = y;
00189 }
00190 catch (MVException m)
00191 {
00192
00193 OutputException("time-update", m);
00194 reset();
00195 res.liklihood = 0.0;
00196 return res;
00197 }
00198
00199
00200 double radiussquare = x*x + y*y;
00201 double angle = atan2(y,x);
00202 double ca = cos(angle);
00203 double sa = sin(angle);
00204
00205 double posA, posB, spdA, spdB;
00206
00207 double abAspectRatio = (panningVelocity < panningVelocityThreshold) ? 0.15 : 0.15*panningVelocity/(panningVelocityThreshold);
00208 double bPanningFactor = (panningVelocity < panningVelocityThreshold) ? 1.0 : 1.0*panningVelocity/(panningVelocityThreshold);
00209 posB = varianceAdaptionPosition[0]*radiussquare +
00210 varianceAdaptionPosition[1];
00211 posB *= bPanningFactor;
00212 posA = posB*abAspectRatio;
00213
00214 spdB = varianceAdaptionSpeed[0]*radiussquare +
00215 varianceAdaptionSpeed[1];
00216 spdB *= bPanningFactor;
00217 spdA = spdB*abAspectRatio;
00218
00219 Matrix2x2<double> Lambda(Vector2<double>(posB, 0), Vector2<double>(0, posA));
00220 Matrix2x2<double> M(Vector2<double>(ca, sa), Vector2<double>(-sa, ca));
00221 Matrix2x2<double> Rxy = M*Lambda*M.transpose();
00222 Lambda[0][0] = spdB;
00223 Lambda[1][1] = spdA;
00224 Matrix2x2<double> RVxy = M*Lambda*M.transpose();
00225
00226 Lambda[0][0] = sqrt(posB);
00227 Lambda[1][1] = sqrt(posA);
00228 Matrix2x2<double> draw = M*Lambda;
00229
00230 Vector2<double> ellipseA(1000.0*draw[0][0], 1000.0*draw[0][1]);
00231 Vector2<double> ellipseB(1000.0*draw[1][0], 1000.0*draw[1][1]);
00232 Vector2<double> ballMeasuredPos(x*1000.0, y*1000.0);
00233 ellipseA += ballMeasuredPos;
00234 ellipseB += ballMeasuredPos;
00235 ellipseA = Geometry::relative2FieldCoord(pose, ellipseA.x,
00236 ellipseA.y);
00237 ellipseB = Geometry::relative2FieldCoord(pose, ellipseB.x,
00238 ellipseB.y);
00239 ballMeasuredPos = Geometry::relative2FieldCoord(pose, ballMeasuredPos.x,
00240 ballMeasuredPos.y);
00241 LINE(ballLocatorField, ballMeasuredPos.x, ballMeasuredPos.y,
00242 ellipseA.x, ellipseA.y,
00243 3, 0, Drawings::pink);
00244 LINE(ballLocatorField, ballMeasuredPos.x, ballMeasuredPos.y,
00245 ellipseB.x, ellipseB.y,
00246 3, 0, Drawings::pink);
00247
00248 R = globR;
00249 R[0][0] = Rxy[0][0];
00250 R[0][1] = Rxy[1][0];
00251 R[1][0] = Rxy[0][1];
00252 R[1][1] = Rxy[1][1];
00253
00254 R[2][2] = RVxy[0][0];
00255 R[2][3] = RVxy[1][0];
00256 R[3][2] = RVxy[0][1];
00257 R[3][3] = RVxy[1][1];
00258
00259
00260 C = P_minus + R;
00261 double determinant;
00262 try
00263 {
00264 C_inv = invert(C);
00265 determinant = det(C);
00266 if (determinant < 0.0)
00267 throw MVException(MVException::DetNegative);
00268 if (MVTools::isNearZero(determinant))
00269 throw MVException(MVException::DetCloseToZero);
00270 }
00271 catch (MVException m)
00272 {
00273
00274 OutputException("invert_c", m);
00275 reset();
00276 res.liklihood = 0.0;
00277 return res;
00278 }
00279
00280 double exponent = -0.5*(z - x_minus)*(C_inv*(z - x_minus));
00281 MVException m;
00282 if (exponent > MVTools::getMaxExpDouble())
00283 {
00284
00285
00286 exponent = MVTools::getMaxExpDouble();
00287 }
00288 double denominator = 4*pi*pi*sqrt(determinant);
00289 res.liklihood = exp(exponent)/(denominator);
00290
00291
00292 try
00293 {
00294 K = P_minus * C_inv;
00295 x_act = x_minus + K*(z - x_minus);
00296 P = (P.eye() - K)*P_minus;
00297 }
00298 catch (MVException m)
00299 {
00300
00301 OutputException("measurement-update", m);
00302 reset();
00303 res.liklihood = 0.0;
00304 return res;
00305 }
00306
00307
00308 lastLiklihood = res.liklihood;
00309 res.state.x = x_act[0];
00310 res.state.y = x_act[1];
00311 res.state.vx = x_act[2];
00312 res.state.vy = x_act[3];
00313 lastTime = time;
00314 }
00315 catch (...)
00316 {
00317
00318 OUTPUT(idText, text,
00319 "UnknownException in KalmanConstantSpeedModel::update()");
00320 reset();
00321 res.liklihood = 0.0;
00322 return res;
00323 }
00324
00325 return res;
00326 }
00327
00328 KalmanPredictResult KalmanConstantSpeedModel::predict(double time)
00329 {
00330 KalmanPredictResult res;
00331
00332
00333 if (initState != Ready)
00334 return res;
00335
00336
00337
00338 double dt = time - lastTime;
00339
00340
00341 A[0][2] = dt;
00342 A[1][3] = dt;
00343
00344
00345 try
00346 {
00347 x_predict = A*x_act;
00348 }
00349 catch (MVException m)
00350 {
00351
00352 OutputException("prediction", m);
00353 reset();
00354 res.liklihood = 0.0;
00355 return res;
00356 }
00357 res.state.x = x_predict[0];
00358 res.state.y = x_predict[1];
00359 res.state.vx = x_predict[2];
00360 res.state.vy = x_predict[3];
00361 res.liklihood = lastLiklihood;
00362
00363 return res;
00364 }
00365
00366 void KalmanConstantSpeedModel::adapt(const OdometryData& lastOdometry,
00367 const OdometryData& actualOdometry)
00368 {
00369
00370 Vector2<double> tempBallPosition =
00371 (lastOdometry + Pose2D(x_act[0]*1000.0, x_act[1]*1000.0) -
00372 actualOdometry).translation;
00373 x_act[0] = tempBallPosition.x / 1000.0;
00374 x_act[1] = tempBallPosition.y / 1000.0;
00375
00376 tempBallPosition =
00377 (lastOdometry + Pose2D(z[0]*1000.0, z[1]*1000.0) -
00378 actualOdometry).translation;
00379 z[0] = tempBallPosition.x / 1000.0;
00380 z[1] = tempBallPosition.y / 1000.0;
00381
00382 double vx, vy;
00383 double speed_rot = lastOdometry.getAngle() - actualOdometry.getAngle();
00384 vx = x_act[2];
00385 vy = x_act[3];
00386 x_act[2] = vx*cos(speed_rot) - vy*sin(speed_rot);
00387 x_act[3] = vx*sin(speed_rot) + vy*cos(speed_rot);
00388
00389 vx = z[2];
00390 vy = z[3];
00391 z[2] = vx*cos(speed_rot) - vy*sin(speed_rot);
00392 z[3] = vx*sin(speed_rot) + vy*cos(speed_rot);
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460