PTAMWrapper.cpp
Go to the documentation of this file.
00001 
00024 #include "PTAMWrapper.h"
00025 #include <cvd/gl_helpers.h>
00026 #include <gvars3/instances.h>
00027 #include "PTAM/ATANCamera.h"
00028 #include "PTAM/MapMaker.h"
00029 #include "PTAM/Tracker.h"
00030 #include "PTAM/Map.h"
00031 #include "PTAM/MapPoint.h"
00032 #include "../HelperFunctions.h"
00033 #include "Predictor.h"
00034 #include "DroneKalmanFilter.h"
00035 #include <cv_bridge/cv_bridge.h>
00036 #include <sensor_msgs/image_encodings.h>
00037 #include "GLWindow2.h"
00038 #include "EstimationNode.h"
00039 #include <iostream>
00040 #include <fstream>
00041 #include <string>
00042 
00043 pthread_mutex_t PTAMWrapper::navInfoQueueCS = PTHREAD_MUTEX_INITIALIZER;
00044 pthread_mutex_t PTAMWrapper::shallowMapCS = PTHREAD_MUTEX_INITIALIZER;
00045 
00046 pthread_mutex_t PTAMWrapper::logScalePairs_CS = PTHREAD_MUTEX_INITIALIZER;
00047 
00048 PTAMWrapper::PTAMWrapper(DroneKalmanFilter* f, EstimationNode* nde)
00049 {
00050         filter = f;
00051         node = nde;
00052 
00053         mpMap = 0;
00054         mpMapMaker = 0;
00055         mpTracker = 0;
00056         predConvert = 0;
00057         predIMUOnlyForScale = 0;
00058         mpCamera = 0;
00059         newImageAvailable = false;
00060 
00061         mapPointsTransformed = std::vector<tvec3>();
00062         keyFramesTransformed = std::vector<tse3>();
00063 
00064 
00065         predConvert = new Predictor();
00066         predIMUOnlyForScale = new Predictor();
00067         imuOnlyPred = new Predictor();
00068 
00069         drawUI = UI_PRES;
00070         frameWidth = frameHeight = 0;
00071 
00072         minKFDist = 0;
00073         minKFWiggleDist = 0;
00074         minKFTimeDist = 0;
00075 
00076         maxKF = 60;
00077 
00078         logfileScalePairs = 0;
00079 }
00080 
00081 void PTAMWrapper::ResetInternal()
00082 {
00083         mimFrameBW.resize(CVD::ImageRef(frameWidth, frameHeight));
00084         mimFrameBW_workingCopy.resize(CVD::ImageRef(frameWidth, frameHeight));
00085 
00086 
00087         if(mpMapMaker != 0) delete mpMapMaker;
00088         if(mpMap != 0) delete mpMap;
00089         if(mpTracker != 0) delete mpTracker;
00090         if(mpCamera != 0) delete mpCamera;
00091 
00092 
00093         // read camera calibration (yes, its done here)
00094         std::string file = node->calibFile;
00095         while(node->arDroneVersion == 0)
00096         {
00097                 std::cout << "Waiting for first navdata to determine drone version!" << std::endl;
00098                 usleep(250000);
00099         }
00100         if(file.size()==0)
00101         {
00102                 if(node->arDroneVersion == 1)
00103                         file = node->packagePath + "/camcalib/ardrone1_default.txt";
00104                 else if(node->arDroneVersion == 2)
00105                         file = node->packagePath + "/camcalib/ardrone2_default.txt";
00106         }
00107 
00108         std::ifstream fleH (file.c_str());
00109         TooN::Vector<5> camPar;
00110         fleH >> camPar[0] >> camPar[1] >> camPar[2] >> camPar[3] >> camPar[4];
00111         fleH.close();
00112         std::cout<< "Set Camera Paramerer to: " << camPar[0] << " " << camPar[1] << " " << camPar[2] << " " << camPar[3] << " " << camPar[4] << std::endl;
00113 
00114 
00115 
00116         mpMap = new Map;
00117         mpCamera = new ATANCamera(camPar);
00118         mpMapMaker = new MapMaker(*mpMap, *mpCamera);
00119         mpTracker = new Tracker(CVD::ImageRef(frameWidth, frameHeight), *mpCamera, *mpMap, *mpMapMaker);
00120 
00121     setPTAMPars(minKFTimeDist, minKFWiggleDist, minKFDist, min_tol, max_tol);
00122 
00123         predConvert->setPosRPY(0,0,0,0,0,0);
00124         predIMUOnlyForScale->setPosRPY(0,0,0,0,0,0);
00125 
00126         resetPTAMRequested = false;
00127         forceKF = false;
00128         isGoodCount = 0;
00129         lastAnimSentClock = 0;
00130         lockNextFrame = false;
00131         PTAMInitializedClock = 0;
00132         lastPTAMMessage = "";
00133 
00134         flushMapKeypoints = false;
00135 
00136         node->publishCommand("u l PTAM has been reset.");
00137 }
00138 
00139 void PTAMWrapper::setPTAMPars(double minKFTimeDist, double minKFWiggleDist, double minKFDist,
00140                               double min_tol, double max_tol)
00141 {
00142         if(mpMapMaker != 0)
00143                 mpMapMaker->minKFDist = minKFDist;
00144         if(mpMapMaker != 0)
00145                 mpMapMaker->minKFWiggleDist = minKFWiggleDist;
00146         if(mpTracker != 0)
00147                 mpTracker->minKFTimeDist = minKFTimeDist;
00148 
00149     if(mpMapMaker != 0)
00150         mpMapMaker->min_tol = min_tol;
00151     if(mpMapMaker != 0)
00152         mpMapMaker->max_tol = max_tol;
00153 
00154         this->minKFDist = minKFDist;
00155         this->minKFWiggleDist = minKFWiggleDist;
00156         this->minKFTimeDist = minKFTimeDist;
00157     this->min_tol = min_tol;
00158     this->max_tol = max_tol;
00159 }
00160 
00161 PTAMWrapper::~PTAMWrapper(void)
00162 {
00163         if(mpCamera != 0) delete mpCamera;
00164         if(mpMap != 0) delete mpMap;
00165         if(mpMapMaker != 0) delete mpMapMaker;
00166         if(mpTracker != 0) delete mpTracker;
00167         if(predConvert != 0) delete predConvert;
00168         if(predIMUOnlyForScale != 0) delete predIMUOnlyForScale;
00169         if(imuOnlyPred != 0) delete imuOnlyPred;
00170 
00171 }
00172 
00173 
00174 void PTAMWrapper::startSystem()
00175 {
00176         keepRunning = true;
00177         changeSizeNextRender = false;
00178         start();
00179 }
00180 
00181 void PTAMWrapper::stopSystem()
00182 {
00183         keepRunning = false;
00184         new_frame_signal.notify_all();
00185         join();
00186 }
00187 
00188 
00189 void PTAMWrapper::run()
00190 {
00191         std::cout << "Waiting for Video" << std::endl;
00192 
00193         // wait for firsst image
00194         while(!newImageAvailable)
00195                 usleep(100000); // sleep 100ms
00196         newImageAvailable = false;
00197         while(!newImageAvailable)
00198                 usleep(100000); // sleep 100ms
00199 
00200         // read image height and width
00201         frameWidth = mimFrameBW.size().x;
00202         frameHeight = mimFrameBW.size().y;
00203 
00204         ResetInternal();
00205 
00206 
00207         snprintf(charBuf,200,"Video resolution: %d x %d",frameWidth,frameHeight);
00208         ROS_INFO("%s", charBuf);
00209         node->publishCommand(std::string("u l ")+charBuf);
00210 
00211         // create window
00212     myGLWindow = new GLWindow2(CVD::ImageRef(frameWidth,frameHeight), "PTAM Drone Camera Feed", this);
00213         myGLWindow->set_title("PTAM Drone Camera Feed");
00214 
00215         changeSizeNextRender = true;
00216         if(frameWidth < 640)
00217                 desiredWindowSize = CVD::ImageRef(frameWidth*2,frameHeight*2);
00218         else
00219                 desiredWindowSize = CVD::ImageRef(frameWidth,frameHeight);
00220 
00221 
00222         boost::unique_lock<boost::mutex> lock(new_frame_signal_mutex);
00223 
00224         while(keepRunning)
00225         {
00226                 if(newImageAvailable)
00227                 {
00228                         newImageAvailable = false;
00229 
00230                         // copy to working copy
00231                         mimFrameBW_workingCopy.copy_from(mimFrameBW);
00232                         mimFrameTime_workingCopy = mimFrameTime;
00233                         mimFrameSEQ_workingCopy = mimFrameSEQ;
00234                         mimFrameTimeRos_workingCopy = mimFrameTimeRos;
00235 
00236                         // release lock and do the work-intensive stuff.....
00237                         lock.unlock();
00238 
00239                         HandleFrame();
00240 
00241 
00242                         if(changeSizeNextRender)
00243                         {
00244                                 myGLWindow->set_size(desiredWindowSize);
00245                                 changeSizeNextRender = false;
00246                         }
00247 
00248                         // get lock again
00249                         lock.lock();
00250                 }
00251                 else
00252                         new_frame_signal.wait(lock);
00253         }
00254 
00255         lock.unlock();
00256         delete myGLWindow;
00257 }
00258 
00259 // called every time a new frame is available.
00260 // needs to be able to
00261 // - (finally) roll forward filter
00262 // - query it's state
00263 // - add a PTAM observation to filter.
00264 void PTAMWrapper::HandleFrame()
00265 {
00266         //printf("tracking Frame at ms=%d (from %d)\n",getMS(ros::Time::now()),mimFrameTime-filter->delayVideo);
00267 
00268 
00269         // prep data
00270         msg = "";
00271         ros::Time startedFunc = ros::Time::now();
00272 
00273         // reset?
00274         if(resetPTAMRequested)
00275                 ResetInternal();
00276 
00277 
00278         // make filter thread-safe.
00279         // --------------------------- ROLL FORWARD TIL FRAME. This is ONLY done here. ---------------------------
00280         pthread_mutex_lock( &filter->filter_CS );
00281         //filter->predictUpTo(mimFrameTime,true, true);
00282         TooN::Vector<10> filterPosePrePTAM = filter->getPoseAtAsVec(mimFrameTime_workingCopy-filter->delayVideo,true);
00283         pthread_mutex_unlock( &filter->filter_CS );
00284 
00285         // ------------------------ do PTAM -------------------------
00286         myGLWindow->SetupViewport();
00287         myGLWindow->SetupVideoOrtho();
00288         myGLWindow->SetupVideoRasterPosAndZoom();
00289 
00290 
00291 
00292         // 1. transform with filter
00293         TooN::Vector<6> PTAMPoseGuess = filter->backTransformPTAMObservation(filterPosePrePTAM.slice<0,6>());
00294         // 2. convert to se3
00295         predConvert->setPosRPY(PTAMPoseGuess[0], PTAMPoseGuess[1], PTAMPoseGuess[2], PTAMPoseGuess[3], PTAMPoseGuess[4], PTAMPoseGuess[5]);
00296         // 3. multiply with rotation matrix
00297         TooN::SE3<> PTAMPoseGuessSE3 = predConvert->droneToFrontNT * predConvert->globaltoDrone;
00298 
00299 
00300         // set
00301         mpTracker->setPredictedCamFromW(PTAMPoseGuessSE3);
00302         //mpTracker->setLastFrameLost((isGoodCount < -10), (videoFrameID%2 != 0));
00303         mpTracker->setLastFrameLost((isGoodCount < -20), (mimFrameSEQ_workingCopy%3 == 0));
00304 
00305         // track
00306         ros::Time startedPTAM = ros::Time::now();
00307         mpTracker->TrackFrame(mimFrameBW_workingCopy, true);
00308         TooN::SE3<> PTAMResultSE3 = mpTracker->GetCurrentPose();
00309         lastPTAMMessage = msg = mpTracker->GetMessageForUser();
00310         ros::Duration timePTAM= ros::Time::now() - startedPTAM;
00311 
00312         TooN::Vector<6> PTAMResultSE3TwistOrg = PTAMResultSE3.ln();
00313 
00314         node->publishTf(mpTracker->GetCurrentPose(),mimFrameTimeRos_workingCopy, mimFrameSEQ_workingCopy,"cam_front");
00315 
00316 
00317         // 1. multiply from left by frontToDroneNT.
00318         // 2. convert to xyz,rpy
00319         predConvert->setPosSE3_globalToDrone(predConvert->frontToDroneNT * PTAMResultSE3);
00320         TooN::Vector<6> PTAMResult = TooN::makeVector(predConvert->x, predConvert->y, predConvert->z, predConvert->roll, predConvert->pitch, predConvert->yaw);
00321 
00322         // 3. transform with filter
00323         TooN::Vector<6> PTAMResultTransformed = filter->transformPTAMObservation(PTAMResult);
00324 
00325 
00326 
00327 
00328         // init failed?
00329         if(mpTracker->lastStepResult == mpTracker->I_FAILED)
00330         {
00331                 ROS_INFO("initializing PTAM failed, resetting!");
00332                 resetPTAMRequested = true;
00333         }
00334         if(mpTracker->lastStepResult == mpTracker->I_SECOND)
00335         {
00336                 PTAMInitializedClock = getMS();
00337                 filter->setCurrentScales(TooN::makeVector(mpMapMaker->initialScaleFactor*1.2,mpMapMaker->initialScaleFactor*1.2,mpMapMaker->initialScaleFactor*1.2));
00338                 mpMapMaker->currentScaleFactor = filter->getCurrentScales()[0];
00339                 ROS_INFO("PTAM initialized!");
00340                 ROS_INFO("initial scale: %f\n",mpMapMaker->initialScaleFactor*1.2);
00341                 node->publishCommand("u l PTAM initialized (took second KF)");
00342                 framesIncludedForScaleXYZ = -1;
00343                 lockNextFrame = true;
00344                 imuOnlyPred->resetPos();
00345         }
00346         if(mpTracker->lastStepResult == mpTracker->I_FIRST)
00347         {
00348                 node->publishCommand("u l PTAM initialization started (took first KF)");
00349         }
00350 
00351 
00352 
00353 
00354 
00355 
00356         // --------------------------- assess result ------------------------------
00357         bool isGood = true;
00358         bool isVeryGood = true;
00359         // calculate absolute differences.
00360         TooN::Vector<6> diffs = PTAMResultTransformed - filterPosePrePTAM.slice<0,6>();
00361         for(int i=0;1<1;i++) diffs[i] = abs(diffs[i]);
00362 
00363 
00364         if(filter->getNumGoodPTAMObservations() < 10 && mpMap->IsGood())
00365         {
00366                 isGood = true;
00367                 isVeryGood = false;
00368         }
00369         else if(mpTracker->lastStepResult == mpTracker->I_FIRST ||
00370                 mpTracker->lastStepResult == mpTracker->I_SECOND ||
00371                 mpTracker->lastStepResult == mpTracker->I_FAILED ||
00372                 mpTracker->lastStepResult == mpTracker->T_LOST ||
00373                 mpTracker->lastStepResult == mpTracker->NOT_TRACKING ||
00374                 mpTracker->lastStepResult == mpTracker->INITIALIZING)
00375                 isGood = isVeryGood = false;
00376         else
00377         {
00378                 // some chewy heuristic when to add and when not to.
00379                 bool dodgy = mpTracker->lastStepResult == mpTracker->T_DODGY ||
00380                         mpTracker->lastStepResult == mpTracker->T_RECOVERED_DODGY;
00381 
00382                 // if yaw difference too big: something certainly is wrong.
00383                 // maximum difference is 5 + 2*(number of seconds since PTAM observation).
00384                 double maxYawDiff = 10.0 + (getMS()-lastGoodYawClock)*0.002;
00385                 if(maxYawDiff > 20) maxYawDiff = 1000;
00386                 if(false && diffs[5] > maxYawDiff)
00387                         isGood = false;
00388 
00389                 if(diffs[5] < 10)
00390                         lastGoodYawClock = getMS();
00391 
00392                 if(diffs[5] > 4.0)
00393                         isVeryGood = false;
00394 
00395                 // if rp difference too big: something certainly is wrong.
00396                 if(diffs[3] > 20 || diffs[4] > 20)
00397                         isGood = false;
00398 
00399                 if(diffs[3] > 3 || diffs[4] > 3 || dodgy)
00400                         isVeryGood = false;
00401         }
00402 
00403         if(isGood)
00404         {
00405                 if(isGoodCount < 0) isGoodCount = 0;
00406                 isGoodCount++;
00407         }
00408         else
00409         {
00410                 if(isGoodCount > 0) isGoodCount = 0;
00411                 isGoodCount--;
00412 
00413                 if(mpTracker->lastStepResult == mpTracker->T_RECOVERED_DODGY)
00414                         isGoodCount = std::max(isGoodCount,-2);
00415                 if(mpTracker->lastStepResult == mpTracker->T_RECOVERED_GOOD)
00416                         isGoodCount = std::max(isGoodCount,-5);
00417 
00418         }
00419 
00420         TooN::Vector<10> filterPosePostPTAM;
00421         // --------------------------- scale estimation & update filter (REDONE) -----------------------------
00422         // interval length is always between 1s and 2s, to enshure approx. same variances.
00423         // if interval contained height inconsistency, z-distances are simply both set to zero, which does not generate a bias.
00424         // otherwise distances are scaled such that height is weighted more.
00425         // if isGood>=3 && framesIncludedForScale < 0                   ===> START INTERVAL
00426         // if 18 <= framesIncludedForScale <= 36 AND isGood>=3  ===> ADD INTERVAL, START INTERVAL
00427         // if framesIncludedForScale > 36                                               ===> set framesIncludedForScale=-1
00428 
00429         // include!
00430 
00431         // TODO: make shure filter is handled properly with permanent roll-forwards.
00432         pthread_mutex_lock( &filter->filter_CS );
00433         if(filter->usePTAM && isGoodCount >= 3)
00434         {
00435                 filter->addPTAMObservation(PTAMResult,mimFrameTime_workingCopy-filter->delayVideo);
00436         }
00437         else
00438                 filter->addFakePTAMObservation(mimFrameTime_workingCopy-filter->delayVideo);
00439 
00440         filterPosePostPTAM = filter->getCurrentPoseSpeedAsVec();
00441         pthread_mutex_unlock( &filter->filter_CS );
00442 
00443 
00444         // if interval is started: add one step.
00445         int includedTime = mimFrameTime_workingCopy - ptamPositionForScaleTakenTimestamp;
00446         if(framesIncludedForScaleXYZ >= 0) framesIncludedForScaleXYZ++;
00447 
00448         // if interval is overdue: reset & dont add
00449         if(includedTime > 3000)
00450         {
00451                 framesIncludedForScaleXYZ = -1;
00452         }
00453 
00454         if(isGoodCount >= 3)
00455         {
00456                 // filter stuff
00457                 lastScaleEKFtimestamp = mimFrameTime_workingCopy;
00458 
00459                 if(includedTime >= 2000 && framesIncludedForScaleXYZ > 1)       // ADD! (if too many, was resetted before...)
00460                 {
00461                         TooN::Vector<3> diffPTAM = PTAMResult.slice<0,3>() - PTAMPositionForScale;
00462                         bool zCorrupted, allCorrupted;
00463                         float pressureStart = 0, pressureEnd = 0;
00464                         TooN::Vector<3> diffIMU = evalNavQue(ptamPositionForScaleTakenTimestamp - filter->delayVideo + filter->delayXYZ,mimFrameTime_workingCopy - filter->delayVideo + filter->delayXYZ,&zCorrupted, &allCorrupted, &pressureStart, &pressureEnd);
00465 
00466                         pthread_mutex_lock(&logScalePairs_CS);
00467                         if(logfileScalePairs != 0)
00468                                 (*logfileScalePairs) <<
00469                                                 pressureStart << " " <<
00470                                                 pressureEnd << " " <<
00471                                                 diffIMU[2] << " " <<
00472                                                 diffPTAM[2] << std::endl;
00473                         pthread_mutex_unlock(&logScalePairs_CS);
00474 
00475 
00476                         if(!allCorrupted)
00477                         {
00478                                 // filtering: z more weight, but only if not corrupted.
00479                                 double xyFactor = 0.05;
00480                                 double zFactor = zCorrupted ? 0 : 3;
00481 
00482                                 diffPTAM.slice<0,2>() *= xyFactor; diffPTAM[2] *= zFactor;
00483                                 diffIMU.slice<0,2>() *= xyFactor; diffIMU[2] *= zFactor;
00484 
00485                                 filter->updateScaleXYZ(diffPTAM, diffIMU, PTAMResult.slice<0,3>());
00486                                 mpMapMaker->currentScaleFactor = filter->getCurrentScales()[0];
00487                         }
00488                         framesIncludedForScaleXYZ = -1; // causing reset afterwards
00489                 }
00490 
00491                 if(framesIncludedForScaleXYZ == -1)     // RESET!
00492                 {
00493                         framesIncludedForScaleXYZ = 0;
00494                         PTAMPositionForScale = PTAMResult.slice<0,3>();
00495                         //predIMUOnlyForScale->resetPos();      // also resetting z corrupted flag etc. (NOT REquired as reset is done in eval)
00496                         ptamPositionForScaleTakenTimestamp = mimFrameTime_workingCopy;
00497                 }
00498         }
00499 
00500 
00501         if(lockNextFrame && isGood)
00502         {
00503                 filter->scalingFixpoint = PTAMResult.slice<0,3>();
00504                 lockNextFrame = false;
00505                 //filter->useScalingFixpoint = true;
00506 
00507                 snprintf(charBuf,500,"locking scale fixpoint to %.3f %.3f %.3f",PTAMResultTransformed[0], PTAMResultTransformed[1], PTAMResultTransformed[2]);
00508                 ROS_INFO("%s", charBuf);
00509                 node->publishCommand(std::string("u l ")+charBuf);
00510         }
00511 
00512 
00513         // ----------------------------- Take KF? -----------------------------------
00514         if(!mapLocked && isVeryGood && (forceKF || (int)(mpMap->vpKeyFrames.size()) < maxKF || maxKF <= 1))
00515         {
00516                 mpTracker->TakeKF(forceKF);
00517                 forceKF = false;
00518         }
00519 
00520         // ---------------- save PTAM status for KI --------------------------------
00521         if(mpTracker->lastStepResult == mpTracker->NOT_TRACKING)
00522                 PTAMStatus = PTAM_IDLE;
00523         else if(mpTracker->lastStepResult == mpTracker->I_FIRST ||
00524                 mpTracker->lastStepResult == mpTracker->I_SECOND ||
00525                 mpTracker->lastStepResult == mpTracker->T_TOOK_KF)
00526                 PTAMStatus = PTAM_TOOKKF;
00527         else if(mpTracker->lastStepResult == mpTracker->INITIALIZING)
00528                 PTAMStatus = PTAM_INITIALIZING;
00529         else if(isVeryGood)
00530                 PTAMStatus = PTAM_BEST;
00531         else if(isGood)
00532                 PTAMStatus = PTAM_GOOD;
00533         else if(mpTracker->lastStepResult == mpTracker->T_DODGY ||
00534                 mpTracker->lastStepResult == mpTracker->T_GOOD)
00535                 PTAMStatus = PTAM_FALSEPOSITIVE;
00536         else
00537                 PTAMStatus = PTAM_LOST;
00538 
00539 
00540         // ----------------------------- update shallow map --------------------------
00541         if(!mapLocked && rand()%5==0)
00542         {
00543                 pthread_mutex_lock(&shallowMapCS);
00544                 mapPointsTransformed.clear();
00545                 keyFramesTransformed.clear();
00546                 for(unsigned int i=0;i<mpMap->vpKeyFrames.size();i++)
00547                 {
00548                         predConvert->setPosSE3_globalToDrone(predConvert->frontToDroneNT * mpMap->vpKeyFrames[i]->se3CfromW);
00549                         TooN::Vector<6> CamPos = TooN::makeVector(predConvert->x, predConvert->y, predConvert->z, predConvert->roll, predConvert->pitch, predConvert->yaw);
00550                         CamPos = filter->transformPTAMObservation(CamPos);
00551                         predConvert->setPosRPY(CamPos[0], CamPos[1], CamPos[2], CamPos[3], CamPos[4], CamPos[5]);
00552                         keyFramesTransformed.push_back(predConvert->droneToGlobal);
00553                 }
00554                 TooN::Vector<3> PTAMScales = filter->getCurrentScales();
00555                 TooN::Vector<3> PTAMOffsets = filter->getCurrentOffsets().slice<0,3>();
00556                 for(unsigned int i=0;i<mpMap->vpPoints.size();i++)
00557                 {
00558                         TooN::Vector<3> pos = (mpMap->vpPoints)[i]->v3WorldPos;
00559                         pos[0] *= PTAMScales[0];
00560                         pos[1] *= PTAMScales[1];
00561                         pos[2] *= PTAMScales[2];
00562                         pos += PTAMOffsets;
00563                         mapPointsTransformed.push_back(pos);
00564                 }
00565 
00566                 // flush map keypoints
00567                 if(flushMapKeypoints)
00568                 {
00569                         std::ofstream* fle = new std::ofstream();
00570                         fle->open("pointcloud.txt");
00571 
00572                         for(unsigned int i=0;i<mapPointsTransformed.size();i++)
00573                         {
00574                                 (*fle) << mapPointsTransformed[i][0] << " "
00575                                            << mapPointsTransformed[i][1] << " "
00576                                            << mapPointsTransformed[i][2] << std::endl;
00577                         }
00578 
00579                         fle->flush();
00580                         fle->close();
00581 
00582                         printf("FLUSHED %lu KEYPOINTS to file pointcloud.txt\n\n",mapPointsTransformed.size());
00583 
00584                         flushMapKeypoints = false;
00585                 }
00586 
00587 
00588                 pthread_mutex_unlock(&shallowMapCS);
00589 
00590         }
00591 
00592 
00593 
00594         // ---------------------- output and render! ---------------------------
00595         ros::Duration timeALL = ros::Time::now() - startedFunc;
00596         if(isVeryGood) snprintf(charBuf,1000,"\nQuality: best            ");
00597         else if(isGood) snprintf(charBuf,1000,"\nQuality: good           ");
00598         else snprintf(charBuf,1000,"\nQuality: lost                       ");
00599 
00600         snprintf(charBuf+20,800, "scale: %.3f (acc: %.3f)                            ",filter->getCurrentScales()[0],(double)filter->getScaleAccuracy());
00601         snprintf(charBuf+50,800, "PTAM time: %i ms                            ",(int)(1000*timeALL.toSec()));
00602         snprintf(charBuf+68,800, "(%i ms total)  ",(int)(1000*timeALL.toSec()));
00603         if(mapLocked) snprintf(charBuf+83,800, "m.l. ");
00604         else snprintf(charBuf+83,800, "     ");
00605         if(filter->allSyncLocked) snprintf(charBuf+88,800, "s.l. ");
00606         else snprintf(charBuf+88,800, "     ");
00607 
00608 
00609         msg += charBuf;
00610 
00611         if(mpMap->IsGood())
00612         {
00613                 if(drawUI == UI_DEBUG)
00614                 {
00615                         snprintf(charBuf,1000,"\nPTAM Diffs:              ");
00616                         snprintf(charBuf+13,800, "x: %.3f                          ",diffs[0]);
00617                         snprintf(charBuf+23,800, "y: %.3f                          ",diffs[1]);
00618                         snprintf(charBuf+33,800, "z: %.3f                          ",diffs[2]);
00619                         snprintf(charBuf+43,800, "r: %.2f                          ",diffs[3]);
00620                         snprintf(charBuf+53,800, "p: %.2f                          ",diffs[4]);
00621                         snprintf(charBuf+63,800, "y: %.2f",diffs[5]);
00622                         msg += charBuf;
00623 
00624 
00625                         snprintf(charBuf,1000,"\nPTAM Pose:              ");
00626                         snprintf(charBuf+13,800, "x: %.3f                          ",PTAMResultTransformed[0]);
00627                         snprintf(charBuf+23,800, "y: %.3f                          ",PTAMResultTransformed[1]);
00628                         snprintf(charBuf+33,800, "z: %.3f                          ",PTAMResultTransformed[2]);
00629                         snprintf(charBuf+43,800, "r: %.2f                          ",PTAMResultTransformed[3]);
00630                         snprintf(charBuf+53,800, "p: %.2f                          ",PTAMResultTransformed[4]);
00631                         snprintf(charBuf+63,800, "y: %.2f",PTAMResultTransformed[5]);
00632                         msg += charBuf;
00633 
00634 
00635                         snprintf(charBuf,1000,"\nPTAM WiggleDist:              ");
00636                         snprintf(charBuf+18,800, "%.3f                          ",mpMapMaker->lastWiggleDist);
00637                         snprintf(charBuf+24,800, "MetricDist: %.3f",mpMapMaker->lastMetricDist);
00638                         msg += charBuf;
00639                 }
00640         }
00641 
00642         if(drawUI != UI_NONE)
00643         {
00644                 // render grid
00645                 predConvert->setPosRPY(filterPosePostPTAM[0], filterPosePostPTAM[1], filterPosePostPTAM[2], filterPosePostPTAM[3], filterPosePostPTAM[4], filterPosePostPTAM[5]);
00646 
00647                 //renderGrid(predConvert->droneToFrontNT * predConvert->globaltoDrone);
00648                 //renderGrid(PTAMResultSE3);
00649 
00650 
00651                 // draw HUD
00652                 //if(mod->getControlSystem()->isControlling())
00653                 {
00654                         myGLWindow->SetupViewport();
00655                         myGLWindow->SetupVideoOrtho();
00656                         myGLWindow->SetupVideoRasterPosAndZoom();
00657 
00658                         //glDisable(GL_LINE_SMOOTH);
00659                         glLineWidth(2);
00660                         glBegin(GL_LINES);
00661                         glColor3f(0,0,1);
00662 
00663                         glVertex2f(0,frameHeight/2);
00664                         glVertex2f(frameWidth,frameHeight/2);
00665 
00666                         glVertex2f(frameWidth/2,0);
00667                         glVertex2f(frameWidth/2,frameHeight);
00668 
00669                         // 1m lines
00670                         glVertex2f(0.25*frameWidth,0.48*frameHeight);
00671                         glVertex2f(0.25*frameWidth,0.52*frameHeight);
00672                         glVertex2f(0.75*frameWidth,0.48*frameHeight);
00673                         glVertex2f(0.75*frameWidth,0.52*frameHeight);
00674                         glVertex2f(0.48*frameWidth,0.25*frameHeight);
00675                         glVertex2f(0.52*frameWidth,0.25*frameHeight);
00676                         glVertex2f(0.48*frameWidth,0.75*frameHeight);
00677                         glVertex2f(0.52*frameWidth,0.75*frameHeight);
00678 
00679                         glEnd();
00680                 }
00681 
00682 
00683                 myGLWindow->DrawCaption(msg);
00684         }
00685 
00686         lastPTAMResultRaw = PTAMResultSE3;
00687         // ------------------------ LOG --------------------------------------
00688         // log!
00689         if(node->logfilePTAM != NULL)
00690         {
00691                 TooN::Vector<3> scales = filter->getCurrentScalesForLog();
00692                 TooN::Vector<3> sums = TooN::makeVector(0,0,0);
00693                 TooN::Vector<6> offsets = filter->getCurrentOffsets();
00694                 pthread_mutex_lock(&(node->logPTAM_CS));
00695                 // log:
00696                 // - filterPosePrePTAM estimated for videoFrameTimestamp-delayVideo.
00697                 // - PTAMResulttransformed estimated for videoFrameTimestamp-delayVideo. (using imu only for last step)
00698                 // - predictedPoseSpeed estimated for lastNfoTimestamp+filter->delayControl     (actually predicting)
00699                 // - predictedPoseSpeedATLASTNFO estimated for lastNfoTimestamp (using imu only)
00700                 if(node->logfilePTAM != NULL)
00701                         (*(node->logfilePTAM)) << (isGood ? (isVeryGood ? 2 : 1) : 0) << " " <<
00702                                 (mimFrameTime_workingCopy-filter->delayVideo) << " " << filterPosePrePTAM[0] << " " << filterPosePrePTAM[1] << " " << filterPosePrePTAM[2] << " " << filterPosePrePTAM[3] << " " << filterPosePrePTAM[4] << " " << filterPosePrePTAM[5] << " " << filterPosePrePTAM[6] << " " << filterPosePrePTAM[7] << " " << filterPosePrePTAM[8] << " " << filterPosePrePTAM[9] << " " <<
00703                                 filterPosePostPTAM[0] << " " << filterPosePostPTAM[1] << " " << filterPosePostPTAM[2] << " " << filterPosePostPTAM[3] << " " << filterPosePostPTAM[4] << " " << filterPosePostPTAM[5] << " " << filterPosePostPTAM[6] << " " << filterPosePostPTAM[7] << " " << filterPosePostPTAM[8] << " " << filterPosePostPTAM[9] << " " <<
00704                                 PTAMResultTransformed[0] << " " << PTAMResultTransformed[1] << " " << PTAMResultTransformed[2] << " " << PTAMResultTransformed[3] << " " << PTAMResultTransformed[4] << " " << PTAMResultTransformed[5] << " " <<
00705                                 scales[0] << " " << scales[1] << " " << scales[2] << " " <<
00706                                 offsets[0] << " " << offsets[1] << " " << offsets[2] << " " << offsets[3] << " " << offsets[4] << " " << offsets[5] << " " <<
00707                                 sums[0] << " " << sums[1] << " " << sums[2] << " " <<
00708                                 PTAMResult[0] << " " << PTAMResult[1] << " " << PTAMResult[2] << " " << PTAMResult[3] << " " << PTAMResult[4] << " " << PTAMResult[5] << " " <<
00709                                 PTAMResultSE3TwistOrg[0] << " " << PTAMResultSE3TwistOrg[1] << " " << PTAMResultSE3TwistOrg[2] << " " << PTAMResultSE3TwistOrg[3] << " " << PTAMResultSE3TwistOrg[4] << " " << PTAMResultSE3TwistOrg[5] << " " <<
00710                                 videoFramePing << " " << mimFrameTimeRos_workingCopy << " " << mimFrameSEQ_workingCopy << std::endl;
00711 
00712                 pthread_mutex_unlock(&(node->logPTAM_CS));
00713         }
00714 
00715         myGLWindow->swap_buffers();
00716         myGLWindow->HandlePendingEvents();
00717 
00718 }
00719 
00720 
00721 // Draw the reference grid to give the user an idea of wether tracking is OK or not.
00722 void PTAMWrapper::renderGrid(TooN::SE3<> camFromWorld)
00723 {
00724         myGLWindow->SetupViewport();
00725         myGLWindow->SetupVideoOrtho();
00726         myGLWindow->SetupVideoRasterPosAndZoom();
00727 
00728         camFromWorld.get_translation() *= 1;
00729 
00730         // The colour of the ref grid shows if the coarse stage of tracking was used
00731         // (it's turned off when the camera is sitting still to reduce jitter.)
00732         glColor4f(0,0,0,0.6);
00733 
00734         // The grid is projected manually, i.e. GL receives projected 2D coords to draw.
00735         int nHalfCells = 5;
00736         int nTot = nHalfCells * 2 + 1;
00737         CVD::Image<Vector<2> >  imVertices(CVD::ImageRef(nTot,nTot));
00738         for(int i=0; i<nTot; i++)
00739                 for(int j=0; j<nTot; j++)
00740                 {
00741                         Vector<3> v3;
00742                         v3[0] = (i - nHalfCells) * 1;
00743                         v3[1] = (j - nHalfCells) * 1;
00744                         v3[2] = 0.0;
00745                         Vector<3> v3Cam = camFromWorld * v3;
00746                         //v3Cam[2] *= 100;
00747                         if(v3Cam[2] < 0.001)
00748                                 v3Cam = TooN::makeVector(100000*v3Cam[0],100000*v3Cam[1],0.0001);
00749 
00750                         imVertices[i][j] = mpCamera->Project(TooN::project(v3Cam))*0.5;
00751                 }
00752 
00753         glEnable(GL_LINE_SMOOTH);
00754         glEnable(GL_BLEND);
00755         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00756         glLineWidth(2);
00757         for(int i=0; i<nTot; i++)
00758         {
00759                 glBegin(GL_LINE_STRIP);
00760                 for(int j=0; j<nTot; j++)
00761                 CVD::glVertex(imVertices[i][j]);
00762                 glEnd();
00763 
00764                 glBegin(GL_LINE_STRIP);
00765                 for(int j=0; j<nTot; j++)
00766                 CVD::glVertex(imVertices[j][i]);
00767                 glEnd();
00768         };
00769 
00770   glLineWidth(1);
00771   glColor3f(1,0,0);
00772 
00773 
00774 
00775 }
00776 
00777 TooN::Vector<3> PTAMWrapper::evalNavQue(unsigned int from, unsigned int to, bool* zCorrupted, bool* allCorrupted, float* out_start_pressure, float* out_end_pressure)
00778 {
00779         predIMUOnlyForScale->resetPos();
00780 
00781         int firstAdded = 0, lastAdded = 0;
00782         pthread_mutex_lock(&navInfoQueueCS);
00783         int skipped=0;
00784         int used = 0;
00785         double firstZ = 0;
00786 
00787         float sum_first=0, num_first=0, sum_last=0, num_last=0;
00788         int pressureAverageRange = 100;
00789 
00790 
00791         for(std::deque<ardrone_autonomy::Navdata>::iterator cur = navInfoQueue.begin();
00792                         cur != navInfoQueue.end();
00793                         )
00794         {
00795                 int curStampMs = getMS(cur->header.stamp);
00796 
00797                 if(curStampMs < (int)from-pressureAverageRange)
00798                         cur = navInfoQueue.erase(cur);
00799                 else
00800                 {
00801                         if(curStampMs >= (int)from-pressureAverageRange && curStampMs <= (int)from+pressureAverageRange)
00802                         {
00803                                 sum_first += cur->pressure;
00804                                 num_first++;
00805                         }
00806 
00807                         if(curStampMs >= (int)to-pressureAverageRange && curStampMs <= (int)to+pressureAverageRange)
00808                         {
00809                                 sum_last += cur->pressure;
00810                                 num_last++;
00811                         }
00812                         cur++;
00813                 }
00814         }
00815 
00816         for(std::deque<ardrone_autonomy::Navdata>::iterator cur = navInfoQueue.begin();
00817                         cur != navInfoQueue.end();
00818                         cur++
00819                         )
00820         {
00821                 int frontStamp = getMS(cur->header.stamp);
00822                 if(frontStamp < (int)from)              // packages before: delete
00823                 {
00824                         //navInfoQueue.pop_front();
00825                         skipped++;
00826                 }
00827                 else if(frontStamp >= (int)from && frontStamp <= (int)to)
00828                 {
00829                         if(firstAdded == 0)
00830                         {
00831                                 firstAdded = frontStamp;
00832                                 firstZ = (cur->altd * 0.001) / sqrt(1.0 + (tan(cur->rotX * 3.14159268 / 180)*tan(cur->rotX * 3.14159268 / 180)) \
00833                                   + (tan(cur->rotY * 3.14159268 / 180)*tan(cur->rotY * 3.14159268 / 180)) );
00834 
00835                 if (! std::isfinite(firstZ))
00836                     firstZ = cur->altd * 0.001;
00837 
00838                                 predIMUOnlyForScale->z = firstZ;        // avoid height check initially!
00839                         }
00840                         lastAdded = frontStamp;
00841                         // add
00842                         predIMUOnlyForScale->predictOneStep(&(*cur));
00843                         // pop
00844                         //navInfoQueue.pop_front();
00845                         used++;
00846                 }
00847                 else
00848                         break;
00849 
00850         }
00851         //printf("QueEval: before: %i; skipped: %i, used: %i, left: %i\n", totSize, skipped, used, navInfoQueue.size());
00852         predIMUOnlyForScale->z -= firstZ;       // make height to height-diff
00853 
00854         *zCorrupted = predIMUOnlyForScale->zCorrupted;
00855         *allCorrupted = abs(firstAdded - (int)from) + abs(lastAdded - (int)to) > 80;
00856         pthread_mutex_unlock(&navInfoQueueCS);
00857 
00858         if(*allCorrupted)
00859                 printf("scalePackage corrupted (imu data gap for %ims)\n",abs(firstAdded - (int)from) + abs(lastAdded - (int)to));
00860         else if(*zCorrupted)
00861                 printf("scalePackage z corrupted (jump in meters: %.3f)!\n",predIMUOnlyForScale->zCorruptedJump);
00862 
00863         printf("from: %u to: %u; first: %d last: %d firstZ %f => z alt diff: %f\n",
00864                         from,
00865                         to,
00866                         firstAdded,
00867                         lastAdded,
00868                         firstZ,
00869                         predIMUOnlyForScale->z
00870         );
00871 
00872 
00873         *out_end_pressure = sum_last/num_last;
00874         *out_start_pressure = sum_first/num_first;
00875 
00876         return TooN::makeVector(predIMUOnlyForScale->x,predIMUOnlyForScale->y,predIMUOnlyForScale->z);
00877 }
00878 
00879 void PTAMWrapper::newNavdata(ardrone_autonomy::Navdata* nav)
00880 {
00881         lastNavinfoReceived = *nav;
00882 
00883         if(getMS(lastNavinfoReceived.header.stamp) > 2000000)
00884         {
00885                 printf("PTAMSystem: ignoring navdata package with timestamp %f\n", lastNavinfoReceived.tm);
00886                 return;
00887         }
00888         if(lastNavinfoReceived.header.seq > 2000000 || lastNavinfoReceived.header.seq < 0)
00889         {
00890                 printf("PTAMSystem: ignoring navdata package with ID %i\n", lastNavinfoReceived.header.seq);
00891                 return;
00892         }
00893 
00894         // correct yaw with filter-yaw (!):
00895         lastNavinfoReceived.rotZ = filter->getCurrentPose()[5];
00896 
00897         pthread_mutex_lock( &navInfoQueueCS );
00898         navInfoQueue.push_back(lastNavinfoReceived);
00899 
00900         if(navInfoQueue.size() > 1000)  // respective 5s
00901         {
00902                 navInfoQueue.pop_front();
00903                 if(!navQueueOverflown)
00904                         printf("NavQue Overflow detected!\n");
00905                 navQueueOverflown = true;
00906         }
00907         pthread_mutex_unlock( &navInfoQueueCS );
00908 
00909         //filter->setPing(nav->pingNav, nav->pingVid);
00910 
00911         imuOnlyPred->yaw = filter->getCurrentPose()[5];
00912         imuOnlyPred->predictOneStep(&lastNavinfoReceived);
00913 }
00914 
00915 void PTAMWrapper::newImage(sensor_msgs::ImageConstPtr img)
00916 {
00917 
00918         // convert to CVImage
00919         cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(img, sensor_msgs::image_encodings::MONO8);
00920 
00921 
00922         boost::unique_lock<boost::mutex> lock(new_frame_signal_mutex);
00923 
00924         // copy to internal image, convert to bw, set flag.
00925         if(ros::Time::now() - img->header.stamp > ros::Duration(30.0))
00926                 mimFrameTimeRos = (ros::Time::now()-ros::Duration(0.001));
00927         else
00928                 mimFrameTimeRos = (img->header.stamp);
00929 
00930         mimFrameTime = getMS(mimFrameTimeRos);
00931 
00932         //mimFrameTime = getMS(img->header.stamp);
00933         mimFrameSEQ = img->header.seq;
00934 
00935         // copy to mimFrame.
00936         // TODO: make this threadsafe (save pointer only and copy in HandleFrame)
00937         if((int)(mimFrameBW.size().x) != img->width || (int)(mimFrameBW.size().y) != img->height)
00938                 mimFrameBW.resize(CVD::ImageRef(img->width, img->height));
00939 
00940         memcpy(mimFrameBW.data(),cv_ptr->image.data,img->width * img->height);
00941         newImageAvailable = true;
00942 
00943         lock.unlock();
00944         new_frame_signal.notify_all();
00945 }
00946 
00947 
00948 
00949 void PTAMWrapper::on_key_down(int key)
00950 {
00951         if(key == 114) // r
00952         {
00953                 node->publishCommand("p reset");
00954         }
00955         if(key == 117) // u
00956         {
00957                 node->publishCommand("p toggleUI");
00958         }
00959         if(key == 32) // Space
00960         {
00961                 node->publishCommand("p space");
00962         }
00963         if(key == 107) // k
00964         {
00965                 node->publishCommand("p keyframe");
00966         }
00967         if(key == 108) // l
00968         {
00969                 node->publishCommand("toggleLog");
00970         }
00971         if(key == 115) // s
00972         {
00973                 pthread_mutex_lock(&logScalePairs_CS);
00974                 if(logfileScalePairs == 0)
00975                 {
00976                         logfileScalePairs = new std::ofstream();
00977                         logfileScalePairs->open ("logScalePairs.txt");
00978                         printf("\nSTART logging scale pairs\n\n");
00979                 }
00980                 else
00981                 {
00982                         logfileScalePairs->flush();
00983                         logfileScalePairs->close();
00984                         delete logfileScalePairs;
00985                         logfileScalePairs = NULL;
00986                         printf("\nEND logging scale pairs\n\n");
00987                 }
00988                 pthread_mutex_unlock(&logScalePairs_CS);
00989         }
00990 
00991         if(key == 109) // m
00992         {
00993                 node->publishCommand("p toggleLockMap");
00994         }
00995 
00996         if(key == 110) // n
00997         {
00998 
00999                 node->publishCommand("p toggleLockSync");
01000         }
01001 
01002         if(key == 116) // t
01003         {
01004 
01005                 flushMapKeypoints = true;
01006         }
01007 
01008 }
01009 
01010 
01011 // reached by typing "df p COMMAND" into console
01012 bool PTAMWrapper::handleCommand(std::string s)
01013 {
01014         if(s.length() == 5 && s.substr(0,5) == "space")
01015         {
01016             if (mpTracker == 0) {
01017             ROS_INFO("Haven't received the first video frame yet, can't start the tracker");
01018             return true;
01019             }
01020                 mpTracker->pressSpacebar();
01021         }
01022 
01023         // ptam reset: resets only PTAM, keeps filter state.
01024         if(s.length() == 5 && s.substr(0,5) == "reset")
01025         {
01026                 //filter->clearPTAM();
01027                 Reset();
01028 
01029         }
01030 
01031         if(s.length() == 8 && s.substr(0,8) == "keyframe")
01032         {
01033                 forceKF = true;
01034         }
01035 
01036         if(s.length() == 8 && s.substr(0,8) == "toggleUI")
01037         {
01038                 if(drawUI == UI_NONE) drawUI = UI_DEBUG;
01039                 else if(drawUI == UI_DEBUG) drawUI = UI_PRES;
01040                 else if(drawUI == UI_PRES) drawUI = UI_NONE;
01041                 else drawUI = UI_PRES;
01042         }
01043 
01044         if(s.length() == 11 && s.substr(0,11) == "lockScaleFP")
01045         {
01046                 lockNextFrame = true;
01047         }
01048 
01049         if(s.length() == 13 && s.substr(0,13) == "toggleLockMap")
01050         {
01051                 mapLocked = !mapLocked;
01052 
01053 
01054                 if(mapLocked)
01055                 {
01056                         node->publishCommand("u l PTAM map locked.");
01057                         printf("\n\nMAP LOCKED!\n\n\n");
01058                 }
01059                 else
01060                 {
01061                         printf("\n\nMAP UNLOCKED!\n\n\n");
01062                         node->publishCommand("u l PTAM map UNlocked.");
01063                 }
01064         }
01065 
01066         if(s.length() == 14 && s.substr(0,14) == "toggleLockSync")
01067         {
01068                 filter->allSyncLocked = !filter->allSyncLocked;
01069 
01070 
01071                 if(filter->allSyncLocked)
01072                 {
01073                         printf("\n\nSYNC LOCKED!\n\n\n");
01074                         node->publishCommand("u l PTAM sync locked.");
01075                 }
01076                 else
01077                 {
01078                         printf("\n\nSYNC UNLOCKED!\n\n\n");
01079                         node->publishCommand("u l PTAM sync UNlocked.");
01080                 }
01081         }
01082 
01083         return true;
01084 }
01085 
01086 void PTAMWrapper::on_mouse_down(CVD::ImageRef where, int state, int button)
01087 {
01088         double x = 4*(where.x/(double)this->myGLWindow->size().x - 0.5);
01089         double y = -4*(where.y/(double)this->myGLWindow->size().y - 0.5);
01090         char bf[100];
01091 
01092 
01093         node->publishCommand("c clearCommands");
01094         node->publishCommand("c lockScaleFP");
01095 
01096         if(button == 1)
01097                 snprintf(bf,100,"c moveByRel %.3f %.3f 0 0",x,y);
01098         else
01099                 snprintf(bf,100,"c moveByRel 0 0 %.3f %.3f",y,x*45);
01100 
01101         node->publishCommand(bf);
01102 }


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