00001 /** 00002 * @file Modules/SelfLocator/SpecialPerceptSelfLocator.cpp 00003 * 00004 * This file contains a class for self-localization based on 00005 * special percepts, e.g. checkerboard percepts. 00006 * 00007 * @author <a href="mailto:dueffert@informatik.hu-berlin.de">Uwe Düffert</a> 00008 */ 00009 00010 #include "SpecialPerceptSelfLocator.h" 00011 #include "Tools/FieldDimensions.h" 00012 #include "Platform/SystemCall.h" 00013 #include <math.h> 00014 00015 00016 SpecialPerceptSelfLocator::SpecialPerceptSelfLocator(const SelfLocatorInterfaces& interfaces) 00017 : SelfLocator(interfaces),lastRobotPose(0,0,0),psdCrashCount(0), 00018 /* 00019 //6x6-Kalman: 00020 H(1,0,0,0,0,0, 0,1,0,0,0,0, 0,0,1,0,0,0), 00021 A(1,0,0,1,0,0, 0,1,0,0,1,0, 0,0,1,0,0,1, 0,0,0,1,0,0, 0,0,0,0,1,0, 0,0,0,0,0,1), 00022 P(1000,10,10,10,10,10, 10,1000,10,10,10,10, 10,10,1000,10,10,10, 00023 10,10,10,1000,10,10, 10,10,10,10,1000,10, 10,10,10,10,10,1000), 00024 R(10, 0.03, 0.03, 0.03, 20, 0.03, 0.03, 0.03, 5), 00025 K(1,0,0, 0,1,0, 0,0,1, 0,0,0, 0,0,0, 0,0,0) 00026 */ 00027 /* 00028 //2x2-Kalman: 00029 H(1,0), 00030 A(Vector2<double>(1,1),Vector2<double>(0,1)), 00031 P(Vector2<double>(100,1),Vector2<double>(1,100)), 00032 R(10), 00033 K(1,0) 00034 */ 00035 robotPosX (0.15, 0.25, 0.0, 0, -3600, 0, 100), 00036 robotPosY (0.15, 0.25, 0.0, 0, -yPosLeftFlags, yPosLeftFlags, 100), 00037 robotPosR(0.15, 0.25, 0.0, 0, -pi, pi, 1), 00038 lastFrame(0) 00039 { 00040 /* 00041 //quadratische Kurve: 00042 perceptPoseBuffer.init(); 00043 perceptTimeBuffer.init(); 00044 */ 00045 } 00046 00047 void SpecialPerceptSelfLocator::execute() 00048 { 00049 selfLocatorSamples.link(NULL, 0,0); 00050 Pose2D odometry = odometryData - lastOdometry; 00051 lastOdometry = odometryData; 00052 robotPose.setFrameNumber(specialPercept.frameNumber); 00053 static PIDsmoothedValue rspeed(0.1, 0.15, 0.0, 0, -3, 3, 100); 00054 00055 if (specialPercept.type==SpecialPercept::checkerboard) 00056 { 00057 psdCrashCount=0; 00058 /* 00059 //6x6-Kalman: 00060 Vector3<double> z(specialPercept.checkerPose.translation.x,specialPercept.checkerPose.translation.y,specialPercept.checkerPose.rotation); 00061 static Matrix_6x1 x = K * z; 00062 00063 //@todo: framediff * wiederholen ???: 00064 //@todo: Kalman dokumentieren, wie passt man bei Kalman R ordentlich an 00065 Matrix_6x1 xpre = A*x; 00066 Matrix_6x6 Ppre = A*P*A.transpose(); 00067 00068 K = Ppre * H.transpose() * (H * Ppre * H.transpose() * R).inverse(); 00069 x = xpre + K * (z - (H * xpre)); 00070 P = (Matrix_6x6() - (K * H)) * Ppre; 00071 */ 00072 00073 /* 00074 //2x2-Kalman nahezu: 00075 double z=specialPercept.checkerPose.translation.x; 00076 static Vector2<double> x = K * z; 00077 00078 //@todo: framediff * wiederholen ???: 00079 //@todo: Kalman dokumentieren, wie passt man bei Kalman R ordentlich an 00080 Math:: 00081 Vector2<double> xpre = (A*x); 00082 Matrix2x2<double> Ppre = A*P*A.transpose(); 00083 00084 K = Ppre * H.transpose() / (H * Ppre * H.transpose() * R); 00085 x = xpre + K * (z - (H * xpre)); 00086 P = (Matrix2x2<double>(Vector2<double>(1-K.x*H.x,-K.y*H.x),Vector2<double>(1-K.x*H.y,-K.y*H.y))) * Ppre; 00087 */ 00088 00089 /* 00090 //quadratische Kurve: 00091 unsigned long time=specialPercept.frame; //SystemCall::getCurrentSystemTime(); 00092 perceptTimeBuffer.add(time); 00093 perceptPoseBuffer.add(specialPercept.checkerPose); 00094 long tdiff=perceptTimeBuffer[0]-perceptTimeBuffer[perceptTimeBuffer.getNumberOfEntries()-1]; 00095 00096 if ((perceptTimeBuffer.getNumberOfEntries()>4)&&(tdiff<1000)) 00097 { 00098 //some helping variables: 00099 double St0=0,St1=0,St2=0,St3=0,St4=0,Sx1=0,St1x1=0,St2x1=0,Sy1=0,St1y1=0,St2y1=0,Sr1=0,St1r1=0,St2r1=0; 00100 for (int i=0;i<perceptTimeBuffer.getNumberOfEntries();i++) 00101 { 00102 double t=perceptTimeBuffer[0]-perceptTimeBuffer[i]; 00103 double x=perceptPoseBuffer[i].translation.x; 00104 double y=perceptPoseBuffer[i].translation.y; 00105 //rotation only works because robot is always facing forwards -> no -pi/pi jump 00106 double r=perceptPoseBuffer[i].rotation; 00107 St0 ++; 00108 St1 += t; 00109 St2 += t*t; 00110 St3 += t*t*t; 00111 St4 += t*t*t*t; 00112 00113 Sx1 += x; 00114 St1x1 += t*x; 00115 St2x1 += t*t*x; 00116 00117 Sy1 += y; 00118 St1y1 += t*y; 00119 St2y1 += t*t*y; 00120 00121 Sr1 += r; 00122 St1r1 += t*r; 00123 St2r1 += t*t*r; 00124 } 00125 00126 //approximate the t coordinates with quadratic equation f_x(t)=m_x*t^2+n_x*t+o_x, minimize square error, result (Mathematica): 00127 double divisor = (St0*St3*St3 + St1*St1*St4 - St2*(2*St1*St3 + St0*St4 - St2*St2)); 00128 //double m_x = (St0*(St1x1*St3 - St2*St2x1) + St2*St2*Sx1 - St1*(St1x1*St2 + St3*Sx1 - St1*St2x1)) / divisor; 00129 //double n_x = (St2*(St1x1*St2 - St1*St2x1 - St3*Sx1) + St0*(St2x1*St3 - St1x1*St4) + St1*St4*Sx1) / divisor; 00130 double o_x = (St1*(St1x1*St4 - St2x1*St3) + St3*St3*Sx1 - St2*(St1x1*St3 + St4*Sx1 - St2*St2x1)) / divisor; 00131 //approximate the y coordinates with quadratic equation f_y(t)=m_y*t^2+n_y*t+o_y, minimize square error, result (Mathematica): 00132 //double m_y = (St0*(St1y1*St3 - St2*St2y1) + St2*St2*Sy1 - St1*(St1y1*St2 + St3*Sy1 - St1*St2y1)) / divisor; 00133 //double n_y = (St2*(St1y1*St2 - St1*St2y1 - St3*Sy1) + St0*(St2y1*St3 - St1y1*St4) + St1*St4*Sy1) / divisor; 00134 double o_y = (St1*(St1y1*St4 - St2y1*St3) + St3*St3*Sy1 - St2*(St1y1*St3 + St4*Sy1 - St2*St2y1)) / divisor; 00135 //approximate the rotation with quadratic equation f_r(t)=m_r*t^2+n_r*t+o_r, minimize square error, result (Mathematica): 00136 //double m_r = (St0*(St1r1*St3 - St2*St2r1) + St2*St2*Sr1 - St1*(St1r1*St2 + St3*Sr1 - St1*St2r1)) / divisor; 00137 //double n_r = (St2*(St1r1*St2 - St1*St2r1 - St3*Sr1) + St0*(St2r1*St3 - St1r1*St4) + St1*St4*Sr1) / divisor; 00138 double o_r = (St1*(St1r1*St4 - St2r1*St3) + St3*St3*Sr1 - St2*(St1r1*St3 + St4*Sr1 - St2*St2r1)) / divisor; 00139 00140 //2do: Ausreisserfilter? 00141 00142 //double t=time; 00143 //robotPose.translation.x = m_x*m_x*t+n_x*t+o_x; 00144 //robotPose.translation.y = m_y*m_y*t+n_y*t+o_y; 00145 //robotPose.rotation = m_r*m_r*t+n_r*t+o_r; 00146 robotPose.translation.x = o_x; 00147 robotPose.translation.y = o_y; 00148 robotPose.rotation = o_r; 00149 double validity = 1/ 00150 ( 00151 1+ 00152 fabs(specialPercept.checkerPose.translation.x-robotPose.translation.x)/15+ 00153 fabs(specialPercept.checkerPose.translation.y-robotPose.translation.y)/50+ 00154 fabs(specialPercept.checkerPose.rotation-robotPose.rotation)/0.2 00155 ); 00156 robotPose.setValidity(validity); 00157 } 00158 */ 00159 00160 //filter away single outliers 00161 lastWasOutlier = ((!lastWasOutlier)&& 00162 ((fabs(specialPercept.checkerPose.translation.x-robotPosX.getVal())>300)|| 00163 (fabs(specialPercept.checkerPose.translation.y-robotPosY.getVal())>300)|| 00164 (fabs(specialPercept.checkerPose.rotation-robotPosR.getVal())>0.4))); 00165 00166 //PIDsmoothed: 00167 if (lastWasOutlier) 00168 { 00169 Pose2D pose = lastRobotPose + odometry; 00170 robotPose.translation=pose.translation; 00171 robotPose.rotation=pose.rotation; 00172 //dont modify validity here, we only misdetected for one single frame 00173 } 00174 else 00175 { 00176 if (specialPercept.frameNumber-lastFrame>=125) 00177 { 00178 robotPosX.resetTo(specialPercept.checkerPose.translation.x); 00179 robotPosY.resetTo(specialPercept.checkerPose.translation.y); 00180 robotPosR.resetTo(specialPercept.checkerPose.rotation); 00181 //2do: 25/30 according to robot type: 00182 rspeed.resetTo(30*odometry.rotation); 00183 } 00184 else 00185 { 00186 robotPosX.approximateVal(specialPercept.checkerPose.translation.x); 00187 robotPosY.approximateVal(specialPercept.checkerPose.translation.y); 00188 robotPosR.approximateVal(specialPercept.checkerPose.rotation); 00189 } 00190 robotPose.translation.x=robotPosX.getVal(); 00191 robotPose.translation.y=robotPosY.getVal(); 00192 robotPose.rotation=robotPosR.getVal(); 00193 robotPose.setValidity(0.9); 00194 lastFrame=specialPercept.frameNumber; 00195 } 00196 } 00197 else 00198 { 00199 lastWasOutlier=false; 00200 if (psdPercept.numOfPercepts>0) 00201 { 00202 for (int i=0;i<psdPercept.numOfPercepts;i++) 00203 { 00204 if ((psdPercept[i].isValid)&& 00205 (!psdPercept[i].tooFarAway)&& 00206 (psdPercept[i].frameNumber>lastFrame)&& 00207 ((psdPercept[i].x)*(psdPercept[i].x)+(psdPercept[i].y)*(psdPercept[i].y)<=450*450)&& 00208 (psdPercept[i].z>130)) 00209 { 00210 psdCrashCount++; 00211 //we can only crash into the wall if we are near to it. otherwise it is a measurement error due to stamping or noise 00212 if ((psdCrashCount>3)&&((robotPose.translation.x>-660)||(psdPercept[i].frameNumber-lastFrame>125))) 00213 { 00214 robotPose.translation.x=-400; 00215 robotPose.translation.y=0; 00216 robotPose.setValidity(0.05); 00217 //OUTPUT(idText,text, "psd < 450"); 00218 return; 00219 } 00220 } 00221 } 00222 //OUTPUT(idText,text, "no checkerboard, psd: x=" << psdPercept[0].x << ", z=" << psdPercept[0].z); 00223 } 00224 //we use this approximation while measuring turning: 00225 robotPose = lastRobotPose + odometry; 00226 robotPose.setValidity(0.4); 00227 } 00228 00229 //2do: 25/30 according to robot type: 00230 rspeed.approximateVal(30*(robotPose.rotation-lastRobotPose.rotation)); 00231 robotPose.speedbyDistanceToGoal = rspeed.getVal(); 00232 00233 lastRobotPose.translation=robotPose.translation; 00234 lastRobotPose.rotation=robotPose.rotation; 00235 } 00236 00237 /* 00238 * Change log : 00239 * 00240 * $Log: SpecialPerceptSelfLocator.cpp,v $ 00241 * Revision 1.2 2004/06/09 08:20:46 dueffert 00242 * some fine tuning 00243 * 00244 * Revision 1.1.1.1 2004/05/22 17:20:49 cvsadm 00245 * created new repository GT2004_WM 00246 * 00247 * Revision 1.15 2004/05/11 16:32:37 dueffert 00248 * psd crash detection improved 00249 * 00250 * Revision 1.14 2004/05/03 18:52:27 dueffert 00251 * comments corrected 00252 * 00253 * Revision 1.13 2004/03/29 15:31:13 dueffert 00254 * misdetection of near checkerboard corrected 00255 * 00256 * Revision 1.12 2004/03/26 09:22:22 dueffert 00257 * crash detection improved 00258 * 00259 * Revision 1.11 2004/03/19 09:20:48 dueffert 00260 * allow higher distance to checkerboard for 400mm/s-measurement 00261 * 00262 * Revision 1.10 2004/03/15 12:34:05 dueffert 00263 * cool filter for single outliers implemented 00264 * 00265 * Revision 1.9 2004/03/08 02:11:48 roefer 00266 * Interfaces should be const 00267 * 00268 * Revision 1.8 2004/02/29 13:42:30 dueffert 00269 * beautified 00270 * 00271 * Revision 1.7 2004/02/23 16:45:02 dueffert 00272 * ERS7 adaptions of evolution 00273 * 00274 * Revision 1.6 2004/01/20 16:20:03 dueffert 00275 * frameNumber handling corrected 00276 * 00277 * Revision 1.5 2004/01/16 15:47:51 dueffert 00278 * some improvements 00279 * 00280 * Revision 1.4 2003/11/14 19:02:26 goehring 00281 * frameNumber added 00282 * 00283 * Revision 1.3 2003/11/13 16:47:38 goehring 00284 * frameNumber added 00285 * 00286 * Revision 1.2 2003/11/10 13:34:07 dueffert 00287 * checkerboard localization improved 00288 * 00289 * Revision 1.3 2003/08/09 14:53:10 dueffert 00290 * files and docu beautified 00291 * 00292 * Revision 1.2 2003/07/30 14:47:46 dueffert 00293 * SpecialPerceptSelfLocator for Checkboard added 00294 * 00295 * Revision 1.1.1.1 2003/07/02 09:40:24 cvsadm 00296 * created new repository for the competitions in Padova from the 00297 * tamara CVS (Tuesday 2:00 pm) 00298 * 00299 * removed unused solutions 00300 * 00301 * Revision 1.2 2003/05/21 13:36:20 brunn 00302 * set selfLocatorSamples to NULL as these locators do not have any samples 00303 * 00304 * Revision 1.1 2003/01/22 14:59:49 dueffert 00305 * checkerboard stuff added 00306 * 00307 * 00308 */