DroneKalmanFilter.cpp
Go to the documentation of this file.
00001 
00023 #include "DroneKalmanFilter.h"
00024 #include "EstimationNode.h"
00025 
00026 // constants (variances assumed to be present)
00027 const double varSpeedObservation_xy = 2*2;
00028 const double varPoseObservation_xy = 0.2*0.2;
00029 const double varAccelerationError_xy = 8*8;
00030 
00031 const double varPoseObservation_z_PTAM = 0.3*0.3;
00032 const double varPoseObservation_z_IMU = 0.25*0.25;
00033 const double varPoseObservation_z_IMU_NO_PTAM = 0.1*0.1;
00034 const double varAccelerationError_z = 1*1;
00035 
00036 const double varPoseObservation_rp_PTAM = 3*3;
00037 const double varPoseObservation_rp_IMU = 1*1;
00038 const double varSpeedError_rp = 360*360 * 16;   // increased because prediction based on control command is damn inaccurate.
00039 
00040 const double varSpeedObservation_yaw = 50*50;
00041 const double varPoseObservation_yaw = 3*3;
00042 const double varAccelerationError_yaw = 360*360;
00043 
00044 
00045 // constants (assumed delays in ms).
00046 // default ping values: nav=25, vid=50
00047 int DroneKalmanFilter::delayRPY = 0;            // always zero
00048 int DroneKalmanFilter::delayXYZ = 40;           // base_delayXYZ, but at most delayVideo
00049 int DroneKalmanFilter::delayVideo = 75;         // base_delayVideo + delayVid - delayNav
00050 int DroneKalmanFilter::delayControl = 100;      // base_delayControl + 2*delayNav
00051 
00052 const int DroneKalmanFilter::base_delayXYZ = 40;                // t_xyz - t_rpy = base_delayXYZ
00053 const int DroneKalmanFilter::base_delayVideo = 50;              // t_cam - t_rpy = base_delayVideo + delayVid - delayNav
00054 const int DroneKalmanFilter::base_delayControl = 50;    // t_control + t_rpy - 2*delayNav
00055 
00056 // constants (some more parameters)
00057 const double max_z_speed = 2.5; // maximum height speed tolerated (in m/s, everything else is considered to be due to change in floor-height).
00058 const double scaleUpdate_min_xyDist = 0.5*0.5*0.5*0.5;
00059 const double scaleUpdate_min_zDist = 0.1*0.1;
00060 
00061 using namespace std;
00062 
00063 // transform degree-angle to satisfy min <= angle < sup
00064 double angleFromTo(double angle, double min, double sup)
00065 {
00066         while(angle < min) angle += 360;
00067         while(angle >=  sup) angle -= 360;
00068         return angle;
00069 }
00070 
00071 
00072 
00073 
00074 
00075 pthread_mutex_t DroneKalmanFilter::filter_CS = PTHREAD_MUTEX_INITIALIZER;
00076 
00077 DroneKalmanFilter::DroneKalmanFilter(EstimationNode* n)
00078 {
00079         scalePairs = new std::vector<ScaleStruct>();
00080         navdataQueue = new std::deque<ardrone_autonomy::Navdata>();
00081         velQueue = new std::deque<geometry_msgs::TwistStamped>();
00082 
00083         useScalingFixpoint = false;
00084 
00085         this->node = n;
00086 
00087         pthread_mutex_lock( &filter_CS );
00088         reset();
00089         pthread_mutex_unlock( &filter_CS );
00090 
00091 
00092 
00093 
00094 
00095         c1 = 0.58;
00096         c2 = 17.8;
00097         c3 = 10;
00098         c4 = 35;
00099         c5 = 10;
00100         c6 = 25;
00101         c7 = 1.4;
00102         c8 = 1.0;
00103 
00104 }
00105 
00106 
00107 DroneKalmanFilter::~DroneKalmanFilter(void)
00108 {
00109         // dont delete nothing here, as this is also called for shallow copy.
00110 }
00111 
00112 void DroneKalmanFilter::release()
00113 {
00114         delete scalePairs;
00115         delete navdataQueue;
00116         delete velQueue;
00117 }
00118 
00119 
00120 void DroneKalmanFilter::setPing(unsigned int navPing, unsigned int vidPing)
00121 {
00122         // add a constant of 20ms // 40ms to accound for delay due to ros.
00123         // very, very rough approximation.
00124         navPing += 20;
00125         vidPing += 40;
00126 
00127         int new_delayXYZ = base_delayXYZ;
00128         int new_delayVideo = base_delayVideo + vidPing/(int)2 - navPing/(int)2;
00129         int new_delayControl = base_delayControl + navPing;
00130 
00131         delayXYZ = std::min(500,std::max(40,std::min(new_delayVideo,new_delayXYZ)));
00132         delayVideo = std::min(500,std::max(40,new_delayVideo));
00133         delayControl = std::min(200,std::max(50,new_delayControl));
00134 
00135         std::cout << "new delasXYZ: " << delayXYZ << ", delayVideo: " << delayVideo << ", delayControl: " << delayControl << std::endl;
00136 }
00137 
00138 void DroneKalmanFilter::reset()
00139 {
00140         // init filter with pose 0 (var 0) and speed 0 (var large).
00141         x = y = z = yaw = PVFilter(0);
00142         roll = pitch = PFilter(0);
00143         lastIMU_XYZ_ID = lastIMU_RPY_ID = -1;
00144         predictedUpToDroneTime = 0;
00145         last_z_heightDiff = 0;
00146         scalePairsIn = scalePairsOut = 0;
00147 
00148         // set statistic parameters to zero
00149         numGoodIMUObservations = 0;
00150 
00151         // set last times to 0, indicating that there was no prev. package.
00152         lastIMU_XYZ_dronetime = lastIMU_RPY_dronetime = 0;
00153         lastIMU_dronetime = 0;
00154 
00155         // clear PTAM
00156         clearPTAM();
00157 
00158         // clear IMU-queus
00159         navdataQueue->clear();
00160         velQueue->clear();
00161 
00162         predictdUpToTimestamp = getMS(ros::Time::now());
00163         predictedUpToTotal = -1;
00164 
00165         baselineZ_Filter = baselineZ_IMU = -999999;
00166         baselinesYValid = false;
00167 
00168         node->publishCommand("u l EKF has been reset to zero.");
00169 }
00170 
00171 void DroneKalmanFilter::clearPTAM()
00172 {
00173         // offsets and scales are not initialized.
00174         offsets_xyz_initialized = scale_xyz_initialized = false;
00175         xy_scale = z_scale = scale_from_xy = scale_from_z = 1;
00176         roll_offset = pitch_offset = yaw_offset = x_offset = y_offset = z_offset = 0;
00177 
00178         xyz_sum_IMUxIMU = 0.1;
00179         xyz_sum_PTAMxPTAM = 0.1;
00180         xyz_sum_PTAMxIMU = 0.1;
00181         scalePairs->clear();
00182         scalePairsIn = 1;
00183         scalePairsOut = 0;
00184 
00185         rp_offset_framesContributed = 0;
00186 
00187         // set statistic parameters to zero
00188         numGoodPTAMObservations = 0;
00189 
00190         // indicates that last PTAM frame was not valid
00191         lastPosesValid = false;
00192 }
00193 
00194 
00195 // this function does the actual work, predicting one timestep ahead.
00196 void DroneKalmanFilter::predictInternal(geometry_msgs::Twist activeControlInfo, int timeSpanMicros, bool useControlGains)
00197 {
00198         if(timeSpanMicros <= 0) return;
00199 
00200         useControlGains = useControlGains && this->useControl;
00201 
00202         bool controlValid = !(activeControlInfo.linear.z > 1.01 || activeControlInfo.linear.z < -1.01 ||
00203                         activeControlInfo.linear.x > 1.01 || activeControlInfo.linear.x < -1.01 ||
00204                         activeControlInfo.linear.y > 1.01 || activeControlInfo.linear.y < -1.01 ||
00205                         activeControlInfo.angular.z > 1.01 || activeControlInfo.angular.z < -1.01);
00206 
00207 
00208         double tsMillis = timeSpanMicros / 1000.0;      // in milliseconds
00209         double tsSeconds = tsMillis / 1000.0;   // in seconds
00210 
00211 
00212         // predict roll, pitch, yaw
00213         float rollControlGain = tsSeconds*c3*(c4 * activeControlInfo.linear.y - roll.state);
00214         float pitchControlGain = tsSeconds*c3*(c4 * activeControlInfo.linear.x - pitch.state);
00215         float yawSpeedControlGain = tsSeconds*c5*(c6 * activeControlInfo.angular.z - yaw.state[1]);     // at adaption to ros, this has to be reverted for some reason....
00216 
00217         double yawRad = yaw.state[0] * 3.14159268 / 180;
00218         double rollRad = roll.state * 3.14159268 / 180;
00219         double pitchRad = pitch.state * 3.14159268 / 180;
00220 
00221         double vz_gain = tsSeconds * c7 * (c8*activeControlInfo.linear.z - z.state[1]) * fabs(cos(rollRad)*cos(pitchRad));
00222 
00223         double accelX = (cos(yawRad) * tan(rollRad) * (9.8 + vz_gain) - sin(yawRad) * tan(pitchRad) * (9.8 + vz_gain)); // X is left-right (global)
00224         double accelY = (-sin(yawRad) * tan(rollRad) * (9.8 + vz_gain) - cos(yawRad) * tan(pitchRad) * (9.8 + vz_gain)); // Y is front-back (global)
00225 
00226         double vx_gain = tsSeconds * c1 * (c2*accelX);
00227         double vy_gain = tsSeconds * c1 * (c2*accelY);
00228 
00229         lastVXGain = vx_gain;
00230         lastVYGain = vy_gain;
00231         lastPredictedRoll = roll.state;
00232         lastPredictedPitch = pitch.state;
00233 
00234         if(!useControlGains || !controlValid)
00235         {
00236                 vx_gain = vy_gain = vz_gain = 0;
00237                 rollControlGain = pitchControlGain = yawSpeedControlGain = 0;
00238         }
00239 
00240 
00241         yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00242         roll.predict(tsMillis,varSpeedError_rp, rollControlGain);
00243         pitch.predict(tsMillis,varSpeedError_rp, pitchControlGain);
00244         yaw.predict(tsMillis,varAccelerationError_yaw,TooN::makeVector(tsSeconds*yawSpeedControlGain/2,yawSpeedControlGain),1,5*5);
00245         yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00246 
00247 
00248         x.predict(tsMillis,varAccelerationError_xy,TooN::makeVector(tsSeconds*vx_gain/2,vx_gain),0.0001);
00249         y.predict(tsMillis,varAccelerationError_xy,TooN::makeVector(tsSeconds*vy_gain/2,vy_gain),0.0001);
00250         z.predict(tsMillis,TooN::makeVector(tsSeconds*tsSeconds*tsSeconds*tsSeconds, 9*tsSeconds,tsSeconds*tsSeconds*tsSeconds*3),
00251                 TooN::makeVector(tsSeconds*vz_gain/2,vz_gain));
00252 }
00253 
00254 
00255 
00256 void DroneKalmanFilter::observeIMU_XYZ (const ardrone_autonomy::Navdata* nav)
00257 {
00258 
00259         // --------------- now: update  ---------------------------
00260         // transform to global CS, using current yaw
00261         double yawRad = yaw.state[0] * 3.14159268 / 180;
00262         double vx_global = (sin(yawRad) * nav->vx + cos(yawRad) * nav->vy) / 1000.0;
00263         double vy_global = (cos(yawRad) * nav->vx - sin(yawRad) * nav->vy) / 1000.0;
00264 
00265         if(vx_global > 10)
00266                 cout << "err";
00267 
00268         // update x,y:
00269         // if PTAM isGood, assume "normal" accuracy. if not, assume very accurate speeds
00270         // to simulate "integrating up".
00271         double lastX = x.state[0];
00272         double lastY = y.state[0];
00273 
00274         x.observeSpeed(vx_global,varSpeedObservation_xy);
00275         y.observeSpeed(vy_global,varSpeedObservation_xy);
00276 
00277 
00278         if(abs(lastX-x.state[0]) > 0.2 && lastX != 0)
00279         {
00280                 // this happens if there was no navdata for a long time -> EKF variances got big -> new update leads to large jump in pos.
00281                 ROS_WARN("detected large x jump. removing. should not happen usually (only e.g. if no navdata for a long time, or agressive re-scaling)");
00282                 x.state[0] = lastX;
00283         }
00284         if(abs(lastY-y.state[0]) > 0.2 && lastY != 0)
00285         {
00286                 y.state[0] = lastY;
00287                 ROS_WARN("detected large y jump. removing. should not happen usually (only e.g. if no navdata for a long time, or agressive re-scaling)");
00288         }
00289 
00290         // transform the drone's sonar reading into a z reading (height above the ground plane)
00291         double z_obs = (nav->altd * 0.001) / sqrt(1.0 + (tan(roll.state * 3.14159268 / 180)*tan(roll.state * 3.14159268 / 180)) \
00292                                   + (tan(pitch.state * 3.14159268 / 180)*tan(pitch.state * 3.14159268 / 180)) );
00293 
00294     if (! std::isfinite(z_obs))
00295         z_obs = nav->altd * 0.001;
00296 
00297 
00298 
00299     if(baselineZ_Filter < -100000)      // only for initialization.
00300     {
00301         baselineZ_IMU = z_obs;
00302         baselineZ_Filter = z.state[0];
00303     }
00304 
00305     if(abs(z_obs - baselineZ_IMU) < 0.150)      // jumps of more than 150mm in 40ms are ignored
00306     {
00307 
00308         // Prevent drift on the ground
00309         if (nav->state <= 2 && fabs(z_obs - baselineZ_IMU) < zDriftThreshold) {
00310             baselineZ_IMU = z_obs;
00311         }
00312 
00313         if (lastPosesValid) {  // we can't use the z_obs at face value because the sonar might have bounced off something other than the ground
00314             z.observePose(baselineZ_Filter + z_obs - baselineZ_IMU,varPoseObservation_z_IMU); // This could also be solved with a large variance, but this is adequate for the ardrone's short flights
00315 
00316         } else {
00317             if (numGoodPTAMObservations == 0 || nav->state <= 2) {
00318                 z.observePose(z_obs,varPoseObservation_z_IMU_NO_PTAM); // before PTAM initialization, or has landed
00319 
00320             } else {  // PTAM is lost
00321                 z.observePose(baselineZ_Filter + z_obs - baselineZ_IMU,varPoseObservation_z_IMU_NO_PTAM);
00322 
00323             }
00324 
00325         }
00326 
00327         if(lastIMU_XYZ_dronetime > 0)
00328         {
00329             double speed = (z_obs - baselineZ_IMU) / ((getMS(nav->header.stamp) - lastIMU_XYZ_dronetime) / 1000.0);
00330             if (std::isfinite(speed))
00331                 z.observeSpeed(speed,varPoseObservation_z_IMU*10);
00332         }
00333 
00334     }
00335 
00336     baselineZ_IMU = z_obs;
00337     baselineZ_Filter = z.state[0];
00338     lastIMU_XYZ_dronetime = getMS(nav->header.stamp);
00339     last_z_packageID = nav->header.seq;
00340 
00341 }
00342 
00343 
00344 
00345 void DroneKalmanFilter::observeIMU_RPY(const ardrone_autonomy::Navdata* nav)
00346 {
00347         roll.observe(nav->rotX,varPoseObservation_rp_IMU);
00348         pitch.observe(nav->rotY,varPoseObservation_rp_IMU);
00349 
00350 
00351         if(!baselinesYValid)    // only for initialization.
00352         {
00353                 baselineY_IMU = nav->rotZ - node->initialYaw;
00354                 baselinesYValid = true;
00355                 timestampYawBaselineFrom = getMS(nav->header.stamp);
00356                 lastdYaw = 0;
00357                 return;
00358         }
00359 
00360         double observedYaw = nav->rotZ - node->initialYaw;
00361 
00362         yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00363 
00364         if(yaw.state[0] < -90) {
00365                 observedYaw = angleFromTo(observedYaw,-360,0);
00366                 baselineY_IMU = angleFromTo(baselineY_IMU,-360,0);
00367         } else if(yaw.state[0] > 90) {
00368                 observedYaw = angleFromTo(observedYaw,0,360);
00369                 baselineY_IMU = angleFromTo(baselineY_IMU,0,360);
00370         } else {
00371                 observedYaw = angleFromTo(observedYaw,-180,180);
00372                 baselineY_IMU = angleFromTo(baselineY_IMU,-180,180);
00373         }
00374 
00375         double imuYawDiff = observedYaw - baselineY_IMU;
00376     double observedYawSpeed = imuYawDiff / ((getMS(nav->header.stamp) - timestampYawBaselineFrom) / 1000.0);
00377 
00378 
00379     // Prevent drift on the ground
00380     if (nav->state <= 2 && fabs(imuYawDiff) < yawDriftThreshold) {
00381         imuYawDiff = 0;
00382         observedYawSpeed = 0;
00383     }
00384 
00385     baselineY_IMU = observedYaw;
00386     timestampYawBaselineFrom = getMS(nav->header.stamp);
00387 
00388     if (fabs(observedYawSpeed) < 720) {
00389 
00390         if(lastPosesValid)
00391         {
00392             yaw.observePose(yaw.state[0] + imuYawDiff,1*1);
00393             if (std::isfinite(observedYawSpeed))
00394                 yaw.observeSpeed(observedYawSpeed,varSpeedObservation_yaw);
00395         }
00396         else
00397         {
00398             yaw.observePose(yaw.state[0] + imuYawDiff,0.5*0.5);
00399             if (std::isfinite(observedYawSpeed))
00400                 yaw.observeSpeed(observedYawSpeed,varSpeedObservation_yaw/2);
00401 
00402         }
00403     }
00404 
00405     lastdYaw = observedYaw;
00406         yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00407 }
00408 
00409 
00410 
00411 void DroneKalmanFilter::observePTAM(TooN::Vector<6> pose)
00412 {
00413 
00414         // ----------------- observe xyz -----------------------------
00415         // sync!
00416         if(!allSyncLocked)
00417         {
00418                 sync_xyz(pose[0], pose[1], pose[2]);
00419                 sync_rpy(pose[3], pose[4], pose[5]);
00420         }
00421 
00422         last_PTAM_pose = TooN::makeVector(pose[0], pose[1], pose[2]);
00423 
00424 
00425         pose.slice<0,3>() = transformPTAMObservation(pose[0], pose[1], pose[2]);
00426 
00427         if(offsets_xyz_initialized)
00428         {
00429                 x.observePose(pose[0],varPoseObservation_xy);
00430                 y.observePose(pose[1],varPoseObservation_xy);
00431         }
00432 
00433         // observe z
00434         if(offsets_xyz_initialized)
00435         {
00436                 z.observePose(pose[2], varPoseObservation_z_PTAM);
00437         }
00438 
00439         // observe!
00440         if(rp_offset_framesContributed > 1)
00441         {
00442                 roll.observe(pose[3]+roll_offset,varPoseObservation_rp_PTAM);
00443                 pitch.observe(pose[4]+pitch_offset,varPoseObservation_rp_PTAM);
00444 
00445                 yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00446                 double observedYaw = pose[5]+yaw_offset;
00447 
00448                 if(yaw.state[0] < -90)
00449                         observedYaw = angleFromTo(observedYaw,-360,0);
00450                 else if(yaw.state[0] > 90)
00451                         observedYaw = angleFromTo(observedYaw,0,360);
00452                 else
00453                         observedYaw = angleFromTo(observedYaw,-180,180);
00454 
00455                 yaw.observePose(observedYaw,3*3);
00456                 yaw.state[0] =  angleFromTo(yaw.state[0],-180,180);
00457         }
00458 
00459         last_fused_pose = TooN::makeVector(x.state[0], y.state[0], z.state[0]);
00460         lastPosesValid = true;
00461 }
00462 
00463 
00464 void DroneKalmanFilter::sync_rpy(double roll_global, double pitch_global, double yaw_global)
00465 {
00466         if(allSyncLocked) return;
00467         // set yaw on first call
00468         if(rp_offset_framesContributed < 1)
00469                 yaw_offset = yaw.state[0] - yaw_global;
00470 
00471         // update roll and pitch offset continuously as normal average.
00472         if(rp_offset_framesContributed < 100)
00473         {
00474                 roll_offset = rp_offset_framesContributed * roll_offset + roll.state - roll_global;
00475                 pitch_offset = rp_offset_framesContributed * pitch_offset + pitch.state - pitch_global;
00476         }
00477         rp_offset_framesContributed++;
00478 
00479         roll_offset /= rp_offset_framesContributed;
00480         pitch_offset /= rp_offset_framesContributed;
00481 }
00482 
00483 void DroneKalmanFilter::sync_xyz(double x_global, double y_global, double z_global)
00484 {
00485         if(allSyncLocked) return;
00486         // ----------- offset: just take first available ---------
00487         if(!offsets_xyz_initialized)
00488         {
00489                 x_offset = x.state[0] - x_global*xy_scale;
00490                 y_offset = y.state[0] - y_global*xy_scale;
00491                 z_offset = z.state[0] - z_global*z_scale;
00492                 offsets_xyz_initialized = true;
00493         }
00494 
00495 
00496 }
00497 
00498 
00499 
00500 void DroneKalmanFilter::flushScalePairs()
00501 {
00502         std::ofstream* fle = new std::ofstream();
00503         fle->open ("scalePairs.txt");
00504         for(unsigned int i=0;i<scalePairs->size();i++)
00505                 (*fle) << (*scalePairs)[i].ptam[0] << " " <<(*scalePairs)[i].ptam[1] << " " <<(*scalePairs)[i].ptam[2] << " " <<
00506                         (*scalePairs)[i].imu[0] << " " << (*scalePairs)[i].imu[1] << " " << (*scalePairs)[i].imu[2] << std::endl;
00507         fle->flush();
00508         fle->close();
00509         delete fle;
00510 }
00511 
00512 void DroneKalmanFilter::updateScaleXYZ(TooN::Vector<3> ptamDiff, TooN::Vector<3> imuDiff, TooN::Vector<3> OrgPtamPose)
00513 {
00514         if(allSyncLocked) return;
00515 
00516         ScaleStruct s = ScaleStruct(ptamDiff, imuDiff);
00517 
00518         // dont add samples that are way to small...
00519         if(s.imuNorm < 0.05 || s.ptamNorm < 0.05) return;
00520 
00521 
00522         // update running sums
00523         (*scalePairs).push_back(s);
00524 
00525         double xyz_scale_old = xy_scale;
00526 
00527 
00528         // find median.
00529         std::sort((*scalePairs).begin(), (*scalePairs).end());
00530         double median = (*scalePairs)[((*scalePairs).size()+1)/2].alphaSingleEstimate;
00531 
00532         // hack: if we have only few samples, median is unreliable (maybe 2 out of 3 are completely wrong.
00533         // so take first scale pair in this case (i.e. the initial scale)
00534         if((*scalePairs).size() < 5)
00535                 median = initialScaleSet;
00536 
00537         // find sums and median.
00538         // do separately for xy and z and xyz-all and xyz-filtered
00539         double sumII = 0;
00540         double sumPP = 0;
00541         double sumPI = 0;
00542         double totSumII = 0;
00543         double totSumPP = 0;
00544         double totSumPI = 0;
00545 
00546         double sumIIxy = 0;
00547         double sumPPxy = 0;
00548         double sumPIxy = 0;
00549         double sumIIz = 0;
00550         double sumPPz = 0;
00551         double sumPIz = 0;
00552 
00553         int numIn = 0;
00554         int numOut = 0;
00555         for(unsigned int i=0;i<(*scalePairs).size();i++)
00556         {
00557                 if((*scalePairs).size() < 5 || ((*scalePairs)[i].alphaSingleEstimate > median * 0.2 && (*scalePairs)[i].alphaSingleEstimate < median / 0.2))
00558                 {
00559                         sumII += (*scalePairs)[i].ii;
00560                         sumPP += (*scalePairs)[i].pp;
00561                         sumPI += (*scalePairs)[i].pi;
00562 
00563                         sumIIxy += (*scalePairs)[i].imu[0]*(*scalePairs)[i].imu[0] + (*scalePairs)[i].imu[1]*(*scalePairs)[i].imu[1];
00564                         sumPPxy += (*scalePairs)[i].ptam[0]*(*scalePairs)[i].ptam[0] + (*scalePairs)[i].ptam[1]*(*scalePairs)[i].ptam[1];
00565                         sumPIxy += (*scalePairs)[i].ptam[0]*(*scalePairs)[i].imu[0] + (*scalePairs)[i].ptam[1]*(*scalePairs)[i].imu[1];
00566 
00567                         sumIIz += (*scalePairs)[i].imu[2]*(*scalePairs)[i].imu[2];
00568                         sumPPz += (*scalePairs)[i].ptam[2]*(*scalePairs)[i].ptam[2];
00569                         sumPIz += (*scalePairs)[i].ptam[2]*(*scalePairs)[i].imu[2];
00570 
00571                         numIn++;
00572                 }
00573                 else
00574                 {
00575                         totSumII += (*scalePairs)[i].ii;
00576                         totSumPP += (*scalePairs)[i].pp;
00577                         totSumPI += (*scalePairs)[i].pi;
00578                         numOut++;
00579                 }
00580         }
00581         xyz_sum_IMUxIMU = sumII;
00582         xyz_sum_PTAMxPTAM = sumPP;
00583         xyz_sum_PTAMxIMU = sumPI;
00584 
00585         double scale_Filtered = (*scalePairs)[0].computeEstimator(sumPP,sumII,sumPI,0.2,0.01);
00586         double scale_Unfiltered = (*scalePairs)[0].computeEstimator(sumPP+totSumPP,sumII+totSumII,sumPI+totSumPI,0.2,0.01);
00587         double scale_PTAMSmallVar = (*scalePairs)[0].computeEstimator(sumPP+totSumPP,sumII+totSumII,sumPI+totSumPI,0.00001,1);
00588         double scale_IMUSmallVar = (*scalePairs)[0].computeEstimator(sumPP+totSumPP,sumII+totSumII,sumPI+totSumPI,1,0.00001);
00589 
00590 
00591         double scale_Filtered_xy = (*scalePairs)[0].computeEstimator(sumPPxy,sumIIxy,sumPIxy,0.2,0.01);
00592         double scale_Filtered_z = (*scalePairs)[0].computeEstimator(sumPPz,sumIIz,sumPIz,0.2,0.01);
00593 
00594 
00595         scalePairsIn = numIn;
00596         scalePairsOut = numOut;
00597 
00598         printf("scale: in: %i; out: %i, filt: %.3f; xyz: %.1f < %.1f < %.1f; xy: %.1f < %.1f < %.1f; z: %.1f < %.1f < %.1f;\n",
00599                 numIn, numOut, scale_Filtered,
00600                 scale_PTAMSmallVar, scale_Unfiltered, scale_IMUSmallVar,
00601                 (*scalePairs)[0].computeEstimator(sumPPxy,sumIIxy,sumPIxy,0.00001,1),
00602                 scale_Filtered_xy,
00603                 (*scalePairs)[0].computeEstimator(sumPPxy,sumIIxy,sumPIxy,1,0.00001),
00604                 (*scalePairs)[0].computeEstimator(sumPPz,sumIIz,sumPIz,0.00001,1),
00605                 scale_Filtered_z,
00606                 (*scalePairs)[0].computeEstimator(sumPPz,sumIIz,sumPIz,1,0.00001)
00607                 );
00608 
00609         printf("sumPP: %.3f  sumII: %.3f  sumPI: %.3f\n",
00610         sumPP, sumII, sumPI
00611                 );
00612 
00613         if(scale_Filtered > 0.1)
00614                 z_scale = xy_scale = scale_Filtered;
00615         else
00616                 ROS_WARN("calculated scale is too small %.3f, disallowing!",scale_Filtered);
00617 
00618 
00619         scale_from_xy = scale_Filtered_xy;
00620         scale_from_z = scale_Filtered_z;
00621         // update offsets such that no position change occurs (X = x_global*xy_scale_old + offset = x_global*xy_scale_new + new_offset)
00622         if(useScalingFixpoint)
00623         {
00624                 // fix at fixpoint
00625                 x_offset += (xyz_scale_old - xy_scale)*scalingFixpoint[0];
00626                 y_offset += (xyz_scale_old - xy_scale)*scalingFixpoint[1];
00627                 z_offset += (xyz_scale_old - z_scale)*scalingFixpoint[2];
00628         }
00629         else
00630         {
00631                 // fix at current pos.
00632                 x_offset += (xyz_scale_old - xy_scale)*OrgPtamPose[0];
00633                 y_offset += (xyz_scale_old - xy_scale)*OrgPtamPose[1];
00634                 z_offset += (xyz_scale_old - z_scale)*OrgPtamPose[2];
00635         }
00636         scale_xyz_initialized = true;
00637 }
00638 
00639 float DroneKalmanFilter::getScaleAccuracy()
00640 {
00641         return 0.5 + 0.5*std::min(1.0,std::max(0.0,xyz_sum_PTAMxIMU * xy_scale/4));     // scale-corrected PTAM x IMU
00642 }
00643 
00644 
00645 void DroneKalmanFilter::predictUpTo(int timestamp, bool consume, bool useControlGains)
00646 {
00647         if(predictdUpToTimestamp == timestamp) return;
00648 
00649         //std::cout << (consume ? "per" : "tmp") << " pred @ " << this << ": " << predictdUpToTimestamp << " to " << timestamp << std::endl;
00650 
00651 
00652 
00653         // at this point:
00654         // - velQueue contains controls, timestamped with time at which they were sent.
00655         // - navQueue contains navdata, timestamped with time at which they were received.
00656         // - timestamp is the time up to which we want to predict, i.e. maybe a little bit into the feature
00657 
00658         // start at [predictdUpToTimestamp]. predict step-by-step observing at [currentTimestamp] the
00659         // - rpy timestamped with [currentTimestamp + delayRPY]
00660         // - xyz timestamped with [currentTimestamp + delayXYZ]
00661         // using
00662         // - control timestamped with [currentTimestamp - delayControl]
00663 
00664         // fast forward until first package that will be used.
00665         // for controlIterator, this is the last package with a stamp smaller/equal than what it should be.
00666         // for both others, thi is the first package with a stamp bigger than what it should be.
00667         // if consume, delete everything before permanently.
00668         std::deque<geometry_msgs::TwistStamped>::iterator controlIterator = velQueue->begin();
00669         while(controlIterator != velQueue->end() &&
00670                         controlIterator+1 != velQueue->end() &&
00671                         getMS((controlIterator+1)->header.stamp) <= predictdUpToTimestamp - delayControl)
00672                 if(consume)
00673                 {
00674                         velQueue->pop_front();
00675                         controlIterator = velQueue->begin();
00676                 }
00677                 else
00678                         controlIterator++;
00679         if(velQueue->size() == 0) useControlGains = false;
00680 
00681         // dont delete here, it will be deleted if respective rpy data is consumed.
00682         std::deque<ardrone_autonomy::Navdata>::iterator xyzIterator = navdataQueue->begin();
00683         while(xyzIterator != navdataQueue->end() &&
00684                         getMS(xyzIterator->header.stamp) <= predictdUpToTimestamp + delayXYZ)
00685                 xyzIterator++;
00686 
00687         std::deque<ardrone_autonomy::Navdata>::iterator rpyIterator = navdataQueue->begin();
00688         while(rpyIterator != navdataQueue->end() &&
00689                         getMS(rpyIterator->header.stamp) <= predictdUpToTimestamp + delayRPY)
00690                 if(consume)
00691                 {
00692                         navdataQueue->pop_front();
00693                         rpyIterator = navdataQueue->begin();
00694                 }
00695                 else
00696                         rpyIterator++;
00697 
00698         // now, each iterator points to the first elemnent in queue that is to be integrated.
00699         // start predicting,
00700         while(true)
00701         {
00702                 // predict ahead to [timestamp]
00703                 int predictTo = timestamp;
00704 
00705                 // but a maximum of 10ms per prediction step, to guarantee nonlinearities.
00706                 predictTo = min(predictTo, predictdUpToTimestamp+10);
00707 
00708                 // get three queues to the right point in time by rolling forward in them.
00709                 // for xyz this is the first point at which its obs-time is bigger than or equal to [predictdUpToTimestamp]
00710                 while(xyzIterator != navdataQueue->end() &&
00711                                 getMS(xyzIterator->header.stamp) - delayXYZ < predictdUpToTimestamp)
00712                         xyzIterator++;
00713                 while(rpyIterator != navdataQueue->end() &&
00714                                 getMS(rpyIterator->header.stamp) - delayRPY < predictdUpToTimestamp)
00715                         rpyIterator++;
00716                 // for control that is last message with stamp <= predictdUpToTimestamp - delayControl.
00717                 while(controlIterator != velQueue->end() &&
00718                                 controlIterator+1 != velQueue->end() &&
00719                                 getMS((controlIterator+1)->header.stamp) + delayControl <= predictdUpToTimestamp)
00720                         controlIterator++;
00721 
00722 
00723 
00724                 // predict not further than the point in time where the next observation needs to be added.
00725                 if(rpyIterator != navdataQueue->end() )
00726                         predictTo = min(predictTo, getMS(rpyIterator->header.stamp)-delayRPY);
00727                 if(xyzIterator != navdataQueue->end() )
00728                         predictTo = min(predictTo, getMS(xyzIterator->header.stamp)-delayXYZ);
00729 
00730                 predictInternal(useControlGains ? controlIterator->twist : geometry_msgs::Twist(),
00731                                 (predictTo - predictdUpToTimestamp)*1000,
00732                                 useControlGains &&
00733                                 getMS(controlIterator->header.stamp) + 200 > predictdUpToTimestamp - delayControl);                             // control max. 200ms old.
00734 
00735                 // if an observation needs to be added, it HAS to have a stamp equal to [predictTo],
00736                 // as we just set [predictTo] to that timestamp.
00737                 bool observedXYZ = false, observedRPY=false;
00738                 if(rpyIterator != navdataQueue->end() && getMS(rpyIterator->header.stamp)-delayRPY == predictTo)
00739                 {
00740                         if(this->useNavdata)
00741                                 observeIMU_RPY(&(*rpyIterator));
00742 
00743                         observedRPY = true;
00744                         //cout << "a";
00745                 }
00746                 if(xyzIterator != navdataQueue->end() && getMS(xyzIterator->header.stamp)-delayXYZ == predictTo)
00747                 {
00748                         if(this->useNavdata)
00749                                 observeIMU_XYZ(&(*xyzIterator));
00750 
00751                         observedXYZ = true;
00752                         //cout << "p";
00753                 }
00754 
00755 
00756                 predictdUpToTimestamp = predictTo;
00757 
00758                 if(consume)
00759                 {
00760                         if(node->logfileFilter != NULL)
00761                         {
00762                                 pthread_mutex_lock(&(node->logFilter_CS));
00763                                 (*(node->logfileFilter)) << predictdUpToTimestamp << " " << 0 << " " << 0 << " " << 0 << " " <<
00764                                         0 << " " << 0 << " " << 0 << " " <<
00765                                         controlIterator->twist.linear.y << " " << controlIterator->twist.linear.x << " " << controlIterator->twist.linear.z << " " << controlIterator->twist.angular.z << " " <<
00766                                         (observedRPY ? rpyIterator->rotX : -1) << " " << (observedRPY ? rpyIterator->rotY : -1) << " " << (observedRPY ? lastdYaw : -1) << " " <<
00767                                         (observedXYZ ? xyzIterator->vx : -1) << " " << (observedXYZ ? xyzIterator->vy : -1) << " " << (observedXYZ ? lastdZ : -1) << " " <<
00768                                         x.state[0] << " " << y.state[0] << " " << z.state[0] << " " << roll.state << " " << pitch.state << " " << yaw.state[0] << " " << x.state[1] << " " << y.state[1] << " " << z.state[1] << " " << yaw.state[1] << " " <<
00769                                         lastVXGain << " " << lastVYGain << " " << "\n";
00770                                 pthread_mutex_unlock(&(node->logFilter_CS));
00771                         }
00772                 }
00773 
00774                 if(observedRPY) rpyIterator++;
00775                 if(observedXYZ) xyzIterator++;
00776 
00777 
00778                 // if this is where we wanna get, quit.
00779                 if(predictTo == timestamp)
00780                         break;
00781         }
00782 }
00783 
00784 
00785 TooN::Vector<3> DroneKalmanFilter::transformPTAMObservation(double x,double y,double z)
00786 {
00787         return transformPTAMObservation(x,y,z,yaw.state[0]);
00788 }
00789 TooN::Vector<3> DroneKalmanFilter::transformPTAMObservation(double x,double y,double z, double yaw)
00790 {
00791         double yawRad = yaw * 3.14159268 / 180;
00792         x = x_offset + xy_scale*x - 0.2*sin(yawRad);
00793         y = y_offset + xy_scale*y - 0.2*cos(yawRad);
00794         z = z_offset + z_scale*z;
00795         return TooN::makeVector(x,y,z);
00796 }
00797 
00798 TooN::Vector<6> DroneKalmanFilter::transformPTAMObservation(TooN::Vector<6> obs)
00799 {
00800         obs.slice<0,3>() = transformPTAMObservation(obs[0], obs[1], obs[2], obs[5]);
00801 
00802         obs[3] += roll_offset;
00803         obs[4] += pitch_offset;
00804         obs[5] += yaw_offset;
00805 
00806         return obs;
00807 }
00808 TooN::Vector<6> DroneKalmanFilter::backTransformPTAMObservation(TooN::Vector<6> obs)
00809 {
00810         obs[3] -= roll_offset;
00811         obs[4] -= pitch_offset;
00812         obs[5] -= yaw_offset;
00813 
00814         double yawRad = obs[5] * 3.14159268 / 180;
00815         obs[0] = (- x_offset + obs[0] + 0.2*sin(yawRad))/xy_scale;
00816         obs[1] = (- y_offset + obs[1] + 0.2*cos(yawRad))/xy_scale;
00817         obs[2] = (- z_offset + obs[2])/z_scale;
00818 
00819         return obs;
00820 }
00821 
00822 
00823 
00824 TooN::Vector<6> DroneKalmanFilter::getCurrentPose()
00825 {
00826         return TooN::makeVector(x.state[0], y.state[0], z.state[0], roll.state, pitch.state, yaw.state[0]);
00827 }
00828 
00829 uga_tum_ardrone::filter_state DroneKalmanFilter::getCurrentPoseSpeed()
00830 {
00831         uga_tum_ardrone::filter_state s;
00832         s.x = x.state[0];
00833         s.y = y.state[0];
00834         s.z = z.state[0];
00835         s.yaw = yaw.state[0];
00836         s.dx = x.state[1];
00837         s.dy = y.state[1];
00838         s.dz = z.state[1];
00839         s.dyaw = yaw.state[1];
00840         s.roll = roll.state;
00841         s.pitch = pitch.state;
00842 
00843         if(s.roll*s.roll < 0.001) s.roll = 0;
00844         if(s.pitch*s.pitch < 0.001) s.pitch = 0;
00845         if(s.yaw*s.yaw < 0.001) s.yaw = 0;
00846         if(s.dx*s.dx < 0.001) s.dx = 0;
00847         if(s.dy*s.dy < 0.001) s.dy = 0;
00848         if(s.dz*s.dz < 0.001) s.dz = 0;
00849         if(s.x*s.x < 0.001) s.x = 0;
00850         if(s.y*s.y < 0.001) s.y = 0;
00851         if(s.z*s.z < 0.001) s.z = 0;
00852 
00853         return s;
00854 }
00855 
00856 TooN::Vector<10> DroneKalmanFilter::getCurrentPoseSpeedAsVec()
00857 {
00858         return TooN::makeVector(x.state[0], y.state[0], z.state[0], roll.state, pitch.state, yaw.state[0],
00859                 x.state[1], y.state[1], z.state[1],yaw.state[1]);
00860 }
00861 
00862 TooN::Vector<10> DroneKalmanFilter::getCurrentPoseSpeedVariances()
00863 {
00864         return TooN::makeVector(x.var(0,0), y.var(0,0), z.var(0,0), roll.var, pitch.var, yaw.var(0,0),
00865                 x.var(1,1), y.var(1,1), z.var(1,1),yaw.var(1,1));
00866 }
00867 
00868 TooN::Vector<6> DroneKalmanFilter::getCurrentPoseVariances()
00869 {
00870         return TooN::makeVector(x.var(0,0), y.var(0,0), z.var(0,0), roll.var, pitch.var, yaw.var(0,0));
00871 }
00872 TooN::Vector<6> DroneKalmanFilter::getCurrentOffsets()
00873 {
00874         TooN::Vector<6> res = TooN::makeVector(0,0,0,0,0,0);
00875         if(offsets_xyz_initialized)
00876                 res.slice<0,3>() = TooN::makeVector(x_offset, y_offset, z_offset);
00877         if(rp_offset_framesContributed > 1)
00878                 res.slice<3,3>() = TooN::makeVector(roll_offset, pitch_offset, yaw_offset);
00879         return res;
00880 }
00881 TooN::Vector<3> DroneKalmanFilter::getCurrentScales()
00882 {
00883         return TooN::makeVector(scale_xyz_initialized ? xy_scale : 1, scale_xyz_initialized ? xy_scale : 1, scale_xyz_initialized ? z_scale : 1);
00884 }
00885 TooN::Vector<3> DroneKalmanFilter::getCurrentScalesForLog()
00886 {
00887         return TooN::makeVector(scale_xyz_initialized ? scale_from_xy : 1, scale_xyz_initialized ? scale_from_z : 1, scale_xyz_initialized ? xy_scale : 1);
00888 }
00889 
00890 void DroneKalmanFilter::setCurrentScales(TooN::Vector<3> scales)
00891 {
00892         if(allSyncLocked) return;
00893         xy_scale = scales[0];
00894         z_scale = scales[0];
00895         scale_from_xy = scale_from_z = scales[0];
00896 
00897         xyz_sum_IMUxIMU = 0.2 * scales[0];
00898         xyz_sum_PTAMxPTAM = 0.2 / scales[0];
00899         xyz_sum_PTAMxIMU = 0.2;
00900 
00901         (*scalePairs).clear();
00902 
00903         (*scalePairs).push_back(ScaleStruct(
00904                  TooN::makeVector(0.2,0.2,0.2) / sqrt(scales[0]),
00905                  TooN::makeVector(0.2,0.2,0.2) * sqrt(scales[0])
00906                 ));
00907 
00908 
00909 
00910         scale_xyz_initialized = true;
00911         offsets_xyz_initialized = false;
00912 
00913         initialScaleSet = scales[0];
00914 }
00915 
00916 void DroneKalmanFilter::addPTAMObservation(TooN::Vector<6> trans, int time)
00917 {
00918         if(time > predictdUpToTimestamp)
00919                 predictUpTo(time, true,true);
00920 
00921         observePTAM(trans);
00922         numGoodPTAMObservations++;
00923 }
00924 void DroneKalmanFilter::addFakePTAMObservation(int time)
00925 {
00926         if(time > predictdUpToTimestamp)
00927                 predictUpTo(time, true,true);
00928 
00929         lastPosesValid = false;
00930 }
00931 uga_tum_ardrone::filter_state DroneKalmanFilter::getPoseAt(ros::Time t, bool useControlGains)
00932 {
00933 
00934         // make shallow copy
00935         DroneKalmanFilter scopy = DroneKalmanFilter(*this);
00936 
00937         // predict using this copy
00938         scopy.predictUpTo(getMS(t),false, useControlGains);
00939 
00940         // return value, and discard any changes made to scopy (deleting it)
00941         return scopy.getCurrentPoseSpeed();
00942 }
00943 
00944 TooN::Vector<10> DroneKalmanFilter::getPoseAtAsVec(int timestamp, bool useControlGains)
00945 {
00946         // make shallow copy
00947         DroneKalmanFilter scopy = DroneKalmanFilter(*this);
00948 
00949         // predict using this copy
00950         scopy.predictUpTo(timestamp,false, useControlGains);
00951 
00952         // return value, and discard any changes made to scopy (deleting it)
00953         return scopy.getCurrentPoseSpeedAsVec();
00954 
00955 }
00956 
00957 bool DroneKalmanFilter::handleCommand(std::string s)
00958 {
00959 
00960         return false;
00961 }


uga_tum_ardrone
Author(s):
autogenerated on Sat Jun 8 2019 20:30:11