Embed:
(wiki syntax)
Show/hide line numbers
Kalman.cpp
00001 //*************************************************************************************** 00002 //Kalman Filter implementation 00003 //*************************************************************************************** 00004 #include "Kalman.h" 00005 #include "rtos.h" 00006 #include "RFSRF05.h" 00007 #include "math.h" 00008 #include "globals.h" 00009 #include "motors.h" 00010 #include "system.h" 00011 #include "geometryfuncs.h" 00012 00013 #include <tvmet/Matrix.h> 00014 #include <tvmet/Vector.h> 00015 using namespace tvmet; 00016 00017 Kalman::Kalman(Motors &motorsin, 00018 UI &uiin, 00019 PinName Sonar_Trig, 00020 PinName Sonar_Echo0, 00021 PinName Sonar_Echo1, 00022 PinName Sonar_Echo2, 00023 PinName Sonar_Echo3, 00024 PinName Sonar_Echo4, 00025 PinName Sonar_Echo5, 00026 PinName Sonar_SDI, 00027 PinName Sonar_SDO, 00028 PinName Sonar_SCK, 00029 PinName Sonar_NCS, 00030 PinName Sonar_NIRQ, 00031 PinName IR_Tx, 00032 PinName IR_Rx) : 00033 ir(*this,IR_Tx,IR_Rx), 00034 sonararray(Sonar_Trig, 00035 Sonar_Echo0, 00036 Sonar_Echo1, 00037 Sonar_Echo2, 00038 Sonar_Echo3, 00039 Sonar_Echo4, 00040 Sonar_Echo5, 00041 Sonar_SDI, 00042 Sonar_SDO, 00043 Sonar_SCK, 00044 Sonar_NCS, 00045 Sonar_NIRQ), 00046 motors(motorsin), 00047 ui(uiin), 00048 predictthread(predictloopwrapper, this, osPriorityNormal, 512), 00049 predictticker( SIGTICKARGS(predictthread, 0x1) ), 00050 // sonarthread(sonarloopwrapper, this, osPriorityNormal, 256), 00051 // sonarticker( SIGTICKARGS(sonarthread, 0x1) ), 00052 updatethread(updateloopwrapper, this, osPriorityNormal, 512) { 00053 00054 Kalman_init = false; 00055 //Intialising some arrays to zero 00056 for (int kk = 0; kk < 3; kk ++) { 00057 SonarMeasure_Offset[kk] = 0; 00058 } 00059 //Initialising other vars 00060 00061 00062 //Initilising matrices 00063 00064 // X = x, y, theta; 00065 X = 0.5, 0, 0; 00066 00067 P = 1, 0, 0, 00068 0, 1, 0, 00069 0, 0, 0.04; 00070 00071 //measurment variance R is provided by each sensor when calling runupdate 00072 00073 //attach callback 00074 sonararray.callbackobj = (DummyCT*)this; 00075 sonararray.mcallbackfunc = (void (DummyCT::*)(int beaconnum, float distance, float variance)) &Kalman::runupdate; 00076 00077 00078 predictticker.start(20); 00079 // sonarticker.start(50); 00080 00081 } 00082 00083 00084 //Note: this init function assumes that the robot faces east, theta=0, in the +x direction 00085 void Kalman::KalmanInit() { 00086 float SonarMeasuresx1000[3]; 00087 float IRMeasuresloc[3]; 00088 int beacon_cnt = 0; 00089 // set initiating flag to false 00090 Kalman_init = false; 00091 00092 // init the offset array 00093 for (int k = 0; k < 3; k ++) { 00094 SonarMeasure_Offset[k] = 0; 00095 IRMeasures[k] = 0; 00096 } 00097 00098 LPC_UART0->FCR = LPC_UART0->FCR | 0x06; // Flush the serial FIFO buffer / OR with FCR 00099 //wating untill the IR has reved up and picked up some data 00100 wait(1); 00101 00102 //temporaraly disable IR updates 00103 ir.detachisr(); 00104 //IRturret.attach(NULL,Serial::RxIrq); 00105 00106 //lock the state throughout the computation, as we will override the state at the end 00107 statelock.lock(); 00108 00109 SonarMeasuresx1000[0] = SonarMeasures[0]*1000.0f; 00110 SonarMeasuresx1000[1] = SonarMeasures[1]*1000.0f; 00111 SonarMeasuresx1000[2] = SonarMeasures[2]*1000.0f; 00112 IRMeasuresloc[0] = IRMeasures[0]; 00113 IRMeasuresloc[1] = IRMeasures[1]; 00114 IRMeasuresloc[2] = IRMeasures[2]; 00115 //printf("0: %0.4f, 1: %0.4f, 2: %0.4f \n\r", IRMeasuresloc[0]*180/PI, IRMeasuresloc[1]*180/PI, IRMeasuresloc[2]*180/PI); 00116 00117 float d = beaconpos[2].y - beaconpos[1].y; 00118 float i = beaconpos[0].y - beaconpos[1].y; 00119 float j = beaconpos[0].x - beaconpos[1].x; 00120 float y_coor = (SonarMeasuresx1000[1]*SonarMeasuresx1000[1]- SonarMeasuresx1000[2]*SonarMeasuresx1000[2] + d*d) / (2*d); 00121 float x_coor = (SonarMeasuresx1000[1]*SonarMeasuresx1000[1] - SonarMeasuresx1000[0]*SonarMeasuresx1000[0] + i*i + j*j)/(2*j) - i*y_coor/j; 00122 00123 //Compute sonar offset 00124 float Dist_Exp[3]; 00125 for (int k = 0; k < 3; k++) { 00126 Dist_Exp[k] = sqrt((beaconpos[k].y - y_coor)*(beaconpos[k].y - y_coor)+(beaconpos[k].x - x_coor)*(beaconpos[k].x - x_coor)); 00127 SonarMeasure_Offset[k] = (SonarMeasuresx1000[k]-Dist_Exp[k])/1000.0f; 00128 } 00129 00130 //Compute IR offset 00131 ir.angleOffset = 0; 00132 for (int i = 0; i < 3; i++) { 00133 float angle_est = atan2(beaconpos[i].y - y_coor,beaconpos[i].x - x_coor); 00134 // take average offset angle from valid readings 00135 if (IRMeasuresloc[i] != 0) { 00136 beacon_cnt ++; 00137 // changed to current angle - estimated angle 00138 float angle_temp = IRMeasuresloc[i] - angle_est; 00139 angle_temp -= (floor(angle_temp/(2*PI)))*2*PI; 00140 ir.angleOffset += angle_temp; 00141 } 00142 } 00143 ir.angleOffset = ir.angleOffset/float(beacon_cnt); 00144 //printf("\n\r"); 00145 00146 //statelock already locked 00147 ir.angleInit = true; 00148 // set int flag to true 00149 Kalman_init = true; 00150 X(0) = x_coor/1000.0f; 00151 X(1) = y_coor/1000.0f; 00152 X(2) = 0; 00153 statelock.unlock(); 00154 00155 //printf("x: %0.4f, y: %0.4f, offset: %0.4f \n\r", x_coor, y_coor, angleOffset*180/PI); 00156 00157 //reattach the IR processing 00158 ir.attachisr(); 00159 //IRturret.attach(&IR::vIRValueISR,Serial::RxIrq); 00160 } 00161 00162 00163 void Kalman::predictloop() { 00164 00165 float lastleft = 0; 00166 float lastright = 0; 00167 00168 while (1) { 00169 Thread::signal_wait(0x1); 00170 OLED1 = !OLED1; 00171 00172 int leftenc = motors.getEncoder1(); 00173 int rightenc = motors.getEncoder2(); 00174 00175 float dleft = motors.encoderToDistance(leftenc-lastleft)/1000.0f; 00176 float dright = motors.encoderToDistance(rightenc-lastright)/1000.0f; 00177 00178 lastleft = leftenc; 00179 lastright = rightenc; 00180 00181 00182 //The below calculation are in body frame (where +x is forward) 00183 float dxp, dyp,d,r; 00184 float thetap = (dright - dleft)*PI / (float(robotCircumference)/1000.0f); 00185 if (abs(thetap) < 0.02) { //if the rotation through the integration step is small, approximate with a straight line to avoid numerical error 00186 d = (dright + dleft)/2.0f; 00187 dxp = d*cos(thetap/2.0f); 00188 dyp = d*sin(thetap/2.0f); 00189 00190 } else { //calculate circle arc 00191 //float r = (right + left) / (4.0f * PI * thetap); 00192 r = (dright + dleft) / (2.0f*thetap); 00193 dxp = abs(r)*sin(thetap); 00194 dyp = r - r*cos(thetap); 00195 } 00196 00197 statelock.lock(); 00198 00199 //rotating to cartesian frame and updating state 00200 X(0) += dxp * cos(X(2)) - dyp * sin(X(2)); 00201 X(1) += dxp * sin(X(2)) + dyp * cos(X(2)); 00202 X(2) = rectifyAng(X(2) + thetap); 00203 00204 //Linearising F around X 00205 Matrix<float, 3, 3> F; 00206 F = 1, 0, (dxp * -sin(X(2)) - dyp * cos(X(2))), 00207 0, 1, (dxp * cos(X(2)) - dyp * sin(X(2))), 00208 0, 0, 1; 00209 00210 //Generating forward and rotational variance 00211 float varfwd = fwdvarperunit * (dright + dleft) / 2.0f; 00212 float varang = varperang * thetap; 00213 float varxydt = xyvarpertime * PREDICTPERIOD; 00214 float varangdt = angvarpertime * PREDICTPERIOD; 00215 00216 //Rotating into cartesian frame 00217 Matrix<float, 2, 2> Qsub,Qsubrot,Qrot; 00218 Qsub = varfwd + varxydt, 0, 00219 0, varxydt; 00220 00221 Qrot = Rotmatrix(X(2)); 00222 00223 Qsubrot = Qrot * Qsub * trans(Qrot); 00224 00225 //Generate Q 00226 Matrix<float, 3, 3> Q;//(Qsubrot); 00227 Q = Qsubrot(0,0), Qsubrot(0,1), 0, 00228 Qsubrot(1,0), Qsubrot(1,1), 0, 00229 0, 0, varang + varangdt; 00230 00231 P = F * P * trans(F) + Q; 00232 00233 statelock.unlock(); 00234 //Thread::wait(PREDICTPERIOD); 00235 00236 //cout << "predict" << X << endl; 00237 //cout << P << endl; 00238 } 00239 } 00240 00241 //void Kalman::sonarloop() { 00242 // while (1) { 00243 // Thread::signal_wait(0x1); 00244 // sonararray.startRange(); 00245 // } 00246 //} 00247 00248 00249 void Kalman::runupdate(measurement_t type, float value, float variance) { 00250 //printf("beacon %d dist %f\r\n", sonarid, dist); 00251 //led2 = !led2; 00252 00253 measurmentdata* measured = (measurmentdata*)measureMQ.alloc(); 00254 if (measured) { 00255 measured->mtype = type; 00256 measured->value = value; 00257 measured->variance = variance; 00258 00259 osStatus putret = measureMQ.put(measured); 00260 if (putret) 00261 OLED4 = 1; 00262 // printf("putting in MQ error code %#x\r\n", putret); 00263 } else { 00264 OLED4 = 1; 00265 //printf("MQalloc returned NULL ptr\r\n"); 00266 } 00267 00268 } 00269 00270 void Kalman::updateloop() { 00271 measurement_t type; 00272 float value,variance,rbx,rby,expecdist,Y; 00273 float dhdx,dhdy; 00274 bool aborton2stddev = false; 00275 00276 Matrix<float, 1, 3> H; 00277 00278 float S; 00279 Matrix<float, 3, 3> I3( identity< Matrix<float, 3, 3> >() ); 00280 00281 00282 while (1) { 00283 OLED2 = !OLED2; 00284 00285 osEvent evt = measureMQ.get(); 00286 00287 if (evt.status == osEventMail) { 00288 00289 measurmentdata &measured = *(measurmentdata*)evt.value.p; 00290 type = measured.mtype; //Note, may support more measurment types than sonar in the future! 00291 value = measured.value; 00292 variance = measured.variance; 00293 00294 // don't forget to free the memory 00295 measureMQ.free(&measured); 00296 00297 if (type <= maxmeasure) { 00298 00299 if (type <= SONAR3) { 00300 00301 float dist = value / 1000.0f; //converting to m from mm 00302 int sonarid = type; 00303 aborton2stddev = false; 00304 00305 // Remove the offset if possible 00306 if (Kalman_init) 00307 dist = dist - SonarMeasure_Offset[sonarid]; 00308 00309 statelock.lock(); 00310 //update the current sonar readings 00311 SonarMeasures[sonarid] = dist; 00312 00313 rbx = X(0) - beaconpos[sonarid].x/1000.0f; 00314 rby = X(1) - beaconpos[sonarid].y/1000.0f; 00315 00316 expecdist = hypot(rbx, rby);//sqrt(rbx*rbx + rby*rby); 00317 Y = dist - expecdist; 00318 00319 dhdx = rbx / expecdist; 00320 dhdy = rby / expecdist; 00321 00322 H = dhdx, dhdy, 0; 00323 00324 } else if (type <= IR3) { 00325 00326 aborton2stddev = false; 00327 int IRidx = type-3; 00328 00329 statelock.lock(); 00330 IRMeasures[IRidx] = value; 00331 00332 rbx = X(0) - beaconpos[IRidx].x/1000.0f; 00333 rby = X(1) - beaconpos[IRidx].y/1000.0f; 00334 00335 float expecang = atan2(-rby, -rbx) - X(2); 00336 Y = rectifyAng(value - expecang); 00337 00338 float dstsq = rbx*rbx + rby*rby; 00339 H = -rby/dstsq, rbx/dstsq, -1; 00340 } 00341 00342 Matrix<float, 3, 1> PH (P * trans(H)); 00343 S = (H * PH)(0,0) + variance; 00344 00345 if (aborton2stddev && Y*Y > 4 * S) { 00346 statelock.unlock(); 00347 continue; 00348 } 00349 00350 Matrix<float, 3, 1> K (PH * (1/S)); 00351 00352 //Updating state 00353 X += col(K, 0) * Y; 00354 X(2) = rectifyAng(X(2)); 00355 00356 P = (I3 - K * H) * P; 00357 00358 statelock.unlock(); 00359 00360 } 00361 00362 } else { 00363 OLED4 = 1; 00364 //printf("ERROR: in updateloop, code %#x", evt); 00365 } 00366 00367 } 00368 00369 }
Generated on Sun Jul 17 2022 21:06:42 by 1.7.2