00001
00023 #include "EstimationNode.h"
00024 #include "ros/ros.h"
00025 #include "ros/package.h"
00026 #include "geometry_msgs/Twist.h"
00027 #include "sensor_msgs/Image.h"
00028 #include "tf/tfMessage.h"
00029 #include "tf/transform_listener.h"
00030 #include "tf/transform_broadcaster.h"
00031 #include "std_msgs/Empty.h"
00032 #include "std_srvs/Empty.h"
00033 #include "../HelperFunctions.h"
00034 #include "DroneKalmanFilter.h"
00035 #include <ardrone_autonomy/Navdata.h>
00036 #include "deque"
00037 #include "uga_tum_ardrone/filter_state.h"
00038 #include "PTAMWrapper.h"
00039 #include "std_msgs/String.h"
00040 #include "std_msgs/Empty.h"
00041 #include "std_srvs/Empty.h"
00042 #include "MapView.h"
00043 #include <sys/stat.h>
00044 #include <string>
00045
00046 using namespace std;
00047
00048 pthread_mutex_t EstimationNode::logIMU_CS = PTHREAD_MUTEX_INITIALIZER;
00049 pthread_mutex_t EstimationNode::logPTAM_CS = PTHREAD_MUTEX_INITIALIZER;
00050 pthread_mutex_t EstimationNode::logFilter_CS = PTHREAD_MUTEX_INITIALIZER;
00051 pthread_mutex_t EstimationNode::logPTAMRaw_CS = PTHREAD_MUTEX_INITIALIZER;
00052
00053 EstimationNode::EstimationNode()
00054 {
00055 navdata_channel = nh_.resolveName("ardrone/navdata");
00056 control_channel = nh_.resolveName("cmd_vel");
00057 output_channel = nh_.resolveName("ardrone/predictedPose");
00058 video_channel = nh_.resolveName("ardrone/image_raw");
00059 command_channel = nh_.resolveName("uga_tum_ardrone/com");
00060 packagePath = ros::package::getPath("uga_tum_ardrone");
00061
00062 std::string val;
00063 float valFloat = 0;
00064
00065 predTime = ros::Duration(25*0.001);
00066
00067 ros::param::get("~publishFreq", val);
00068 if(val.size()>0)
00069 sscanf(val.c_str(), "%f", &valFloat);
00070 else
00071 valFloat = 30;
00072 publishFreq = valFloat;
00073 cout << "set publishFreq to " << valFloat << "Hz"<< endl;
00074
00075
00076
00077 ros::param::get("~calibFile", calibFile);
00078 if(calibFile.size()>0)
00079 cout << "set calibFile to " << calibFile << endl;
00080 else
00081 cout << "set calibFile to DEFAULT" << endl;
00082
00083
00084 navdata_sub = nh_.subscribe(navdata_channel, 10, &EstimationNode::navdataCb, this);
00085 vel_sub = nh_.subscribe(control_channel,10, &EstimationNode::velCb, this);
00086 vid_sub = nh_.subscribe(video_channel,10, &EstimationNode::vidCb, this);
00087
00088 dronepose_pub = nh_.advertise<uga_tum_ardrone::filter_state>(output_channel,1);
00089
00090 uga_tum_ardrone_pub = nh_.advertise<std_msgs::String>(command_channel,50);
00091 uga_tum_ardrone_sub = nh_.subscribe(command_channel,50, &EstimationNode::comCb, this);
00092
00093
00094
00095
00096 logfileIMU = logfilePTAM = logfileFilter = logfilePTAMRaw = 0;
00097 currentLogID = 0;
00098 lastDroneTS = 0;
00099 lastRosTS = 0;
00100 droneRosTSOffset = 0;
00101 lastNavStamp = ros::Time(0);
00102 filter = new DroneKalmanFilter(this);
00103 ptamWrapper = new PTAMWrapper(filter, this);
00104 mapView = new MapView(filter, ptamWrapper, this);
00105 arDroneVersion = 0;
00106
00107
00108 initialYaw = 0;
00109
00110 }
00111
00112 EstimationNode::~EstimationNode()
00113 {
00114 filter->release();
00115 delete mapView;
00116 delete ptamWrapper;
00117 delete filter;
00118
00119
00120
00121 }
00122 void EstimationNode::navdataCb(const ardrone_autonomy::NavdataConstPtr navdataPtr)
00123 {
00124 lastNavdataReceived = *navdataPtr;
00125 if(ros::Time::now() - lastNavdataReceived.header.stamp > ros::Duration(30.0))
00126 lastNavdataReceived.header.stamp = ros::Time::now();
00127
00128 if(arDroneVersion == 0)
00129 {
00130 arDroneVersion = (navdataPtr->pressure == 0) ? 1 : 2;
00131 std::cout <<"Found ARDrone Version " << arDroneVersion << std::endl;
00132 }
00133
00134
00135
00136
00137
00138
00139 long rosTS = getMS(lastNavdataReceived.header.stamp);
00140 long droneTS = navdataPtr->tm / 1000;
00141
00142 if(lastDroneTS == 0) lastDroneTS = droneTS;
00143
00144 if((droneTS+1000000) < lastDroneTS)
00145 {
00146 droneRosTSOffset = rosTS - droneTS;
00147 ROS_WARN("Drone Navdata timestamp overflow! (should happen epprox every 30min, while drone switched on)");
00148 }
00149 else
00150 droneRosTSOffset = 0.9 * droneRosTSOffset + 0.1*(rosTS - droneTS);
00151
00152 long rosTSNew =droneTS + droneRosTSOffset;
00153 long TSDiff = std::min(100l,std::max(-100l,rosTSNew-rosTS));
00154 lastNavdataReceived.header.stamp += ros::Duration(TSDiff/1000.0);
00155 lastRosTS = rosTS;
00156 lastDroneTS = droneTS;
00157
00158
00159
00160 lastNavdataReceived.rotZ *= -1;
00161 lastNavdataReceived.rotY *= -1;
00162 lastNavdataReceived.vy *= -1;
00163 lastNavdataReceived.vz *= -1;
00164 lastNavdataReceived.ay *= -1;
00165 lastNavdataReceived.az *= -1;
00166
00167
00168
00169
00170 pthread_mutex_lock( &filter->filter_CS );
00171 filter->navdataQueue->push_back(lastNavdataReceived);
00172 pthread_mutex_unlock( &filter->filter_CS );
00173
00174
00175
00176 ptamWrapper->newNavdata(&lastNavdataReceived);
00177
00178
00179
00180 if(lastNavStamp != ros::Time(0) && (lastNavdataReceived.header.stamp - lastNavStamp > ros::Duration(0.1)))
00181 std::cout << (lastNavdataReceived.header.stamp - lastNavStamp).toSec() << "s between two consecutive navinfos. This system requires Navinfo at 200Hz. If this error persists, set drone to debug mode and change publish freq in ardrone_autonomy" << std::endl;
00182 lastNavStamp = lastNavdataReceived.header.stamp;
00183
00184
00185 if(logfileIMU != NULL)
00186 {
00187 int pingNav = 0, pingVid = 0;
00188 pthread_mutex_lock(&logIMU_CS);
00189 if(logfileIMU != NULL)
00190 (*logfileIMU) << getMS(lastNavdataReceived.header.stamp) << " " << lastNavdataReceived.tm << " " <<
00191 lastNavdataReceived.vx << " " << lastNavdataReceived.vy << " " << lastNavdataReceived.altd << " " << lastNavdataReceived.rotX/1000.0 << " " << lastNavdataReceived.rotY/1000.0 << " " << lastNavdataReceived.rotZ/1000.0 << " " <<
00192 lastNavdataReceived.pressure << " " << 0 << " " << 0 << " " << 0 << " " <<
00193 pingNav << " " << pingVid << "\n";
00194 pthread_mutex_unlock(&logIMU_CS);
00195 }
00196
00197 }
00198
00199 void EstimationNode::velCb(const geometry_msgs::TwistConstPtr velPtr)
00200 {
00201 geometry_msgs::TwistStamped ts;
00202 ts.header.stamp = ros::Time::now();
00203 ts.twist = *velPtr;
00204
00205
00206
00207 ts.twist.linear.y *= -1;
00208 ts.twist.linear.x *= -1;
00209 ts.twist.angular.z *= -1;
00210
00211 pthread_mutex_lock( &filter->filter_CS );
00212 filter->velQueue->push_back(ts);
00213 pthread_mutex_unlock( &filter->filter_CS );
00214 }
00215
00216 void EstimationNode::vidCb(const sensor_msgs::ImageConstPtr img)
00217 {
00218
00219 ptamWrapper->newImage(img);
00220 }
00221
00222 void EstimationNode::comCb(const std_msgs::StringConstPtr str)
00223 {
00224 if(str->data.length() > 2 && str->data.substr(0,2) == "p ")
00225 {
00226 ptamWrapper->handleCommand(str->data.substr(2,str->data.length()-2));
00227 }
00228
00229 if(str->data.length() > 2 && str->data.substr(0,2) == "f ")
00230 {
00231 mapView->handleCommand(str->data.substr(2,str->data.length()-2));
00232 }
00233
00234 if(str->data.length() > 2 && str->data.substr(0,2) == "m ")
00235 {
00236 mapView->handleCommand(str->data.substr(2,str->data.length()-2));
00237 }
00238
00239 if(str->data.length() == 9 && str->data.substr(0,9) == "toggleLog")
00240 {
00241 this->toogleLogging();
00242 }
00243
00244
00245
00246
00247 if(str->data.length() > 2 && str->data.substr(0,2) == "c ")
00248 {
00249
00250 float parameter;
00251
00252 if(sscanf(str->data.c_str(),"c setInitialYaw %f",¶meter) == 1)
00253 {
00254 initialYaw = parameter;
00255 }
00256 }
00257
00258
00259 int a, b;
00260 if(sscanf(str->data.c_str(),"pings %d %d",&a, &b) == 2)
00261 {
00262 filter->setPing((unsigned int)a, (unsigned int)b);
00263 predTime = ros::Duration((0.001*filter->delayControl));
00264 }
00265 }
00266
00267
00268 void EstimationNode::Loop()
00269 {
00270 ros::Rate pub_rate(publishFreq);
00271
00272 ros::Time lastInfoSent = ros::Time::now();
00273
00274 while (nh_.ok())
00275 {
00276
00277 ros::spinOnce();
00278
00279
00280
00281
00282 pthread_mutex_lock( &filter->filter_CS );
00283 uga_tum_ardrone::filter_state s = filter->getPoseAt(ros::Time().now() + predTime);
00284 pthread_mutex_unlock( &filter->filter_CS );
00285
00286
00287 s.header.stamp = ros::Time().now();
00288 s.scale = filter->getCurrentScales()[0];
00289 s.scaleAccuracy = filter->getScaleAccuracy();
00290 s.ptamState = ptamWrapper->PTAMStatus;
00291 s.droneState = lastNavdataReceived.state;
00292 s.batteryPercent = lastNavdataReceived.batteryPercent;
00293
00294
00295 dronepose_pub.publish(s);
00296
00297
00298
00299
00300
00301 if((getMS(ros::Time().now()) - filter->predictdUpToTimestamp) > 500)
00302 filter->addFakePTAMObservation(getMS(ros::Time().now()) - 300);
00303
00304
00305
00306 if((ros::Time::now() - lastInfoSent) > ros::Duration(0.4))
00307 {
00308 reSendInfo();
00309 lastInfoSent = ros::Time::now();
00310 }
00311
00312
00313 pub_rate.sleep();
00314 }
00315 }
00316 void EstimationNode::dynConfCb(uga_tum_ardrone::StateestimationParamsConfig &config, uint32_t level)
00317 {
00318 if(!filter->allSyncLocked && config.PTAMSyncLock)
00319 ROS_WARN("Ptam Sync has been disabled. This fixes scale etc.");
00320
00321 if(!ptamWrapper->mapLocked && config.PTAMMapLock)
00322 ROS_WARN("Ptam Map has been locked.");
00323
00324
00325 filter->useControl =config.UseControlGains;
00326 filter->usePTAM =config.UsePTAM;
00327 filter->useNavdata =config.UseNavdata;
00328
00329 filter->useScalingFixpoint = config.RescaleFixOrigin;
00330
00331 ptamWrapper->maxKF = config.PTAMMaxKF;
00332 ptamWrapper->mapLocked = config.PTAMMapLock;
00333 filter->allSyncLocked = config.PTAMSyncLock;
00334
00335 ptamWrapper->setPTAMPars(config.PTAMMinKFTimeDiff, config.PTAMMinKFWiggleDist, config.PTAMMinKFDist,
00336 config.MinTolerance, config.MaxTolerance);
00337
00338 filter->c1 = config.c1;
00339 filter->c2 = config.c2;
00340 filter->c3 = config.c3;
00341 filter->c4 = config.c4;
00342 filter->c5 = config.c5;
00343 filter->c6 = config.c6;
00344 filter->c7 = config.c7;
00345 filter->c8 = config.c8;
00346
00347 filter->zDriftThreshold = config.zDriftThreshold;
00348 filter->yawDriftThreshold = config.yawDriftThreshold;
00349
00350 }
00351
00352 pthread_mutex_t EstimationNode::uga_tum_ardrone_CS = PTHREAD_MUTEX_INITIALIZER;
00353 void EstimationNode::publishCommand(std::string c)
00354 {
00355 std_msgs::String s;
00356 s.data = c.c_str();
00357 pthread_mutex_lock(&uga_tum_ardrone_CS);
00358 uga_tum_ardrone_pub.publish(s);
00359 pthread_mutex_unlock(&uga_tum_ardrone_CS);
00360 }
00361
00362 void EstimationNode::publishTf(TooN::SE3<> trans, ros::Time stamp, int seq, std::string system)
00363 {
00364 trans = trans.inverse();
00365
00366 tf::Matrix3x3 m;
00367 m[0][0] = trans.get_rotation().get_matrix()(0,0);
00368 m[0][1] = trans.get_rotation().get_matrix()(0,1);
00369 m[0][2] = trans.get_rotation().get_matrix()(0,2);
00370 m[1][0] = trans.get_rotation().get_matrix()(1,0);
00371 m[1][1] = trans.get_rotation().get_matrix()(1,1);
00372 m[1][2] = trans.get_rotation().get_matrix()(1,2);
00373 m[2][0] = trans.get_rotation().get_matrix()(2,0);
00374 m[2][1] = trans.get_rotation().get_matrix()(2,1);
00375 m[2][2] = trans.get_rotation().get_matrix()(2,2);
00376
00377 tf::Vector3 v;
00378 v[0] = trans.get_translation()[0];
00379 v[1] = trans.get_translation()[1];
00380 v[2] = trans.get_translation()[2];
00381
00382
00383 tf::Transform tr = tf::Transform(m,v);
00384 tf::StampedTransform t = tf::StampedTransform(tr,stamp,"map",system);
00385 tf_broadcaster.sendTransform(t);
00386
00387
00388
00389 if(logfilePTAMRaw != NULL)
00390 {
00391 pthread_mutex_lock(&(logPTAMRaw_CS));
00392
00393
00394
00395
00396
00397 if(logfilePTAMRaw != NULL)
00398 (*(logfilePTAMRaw)) << seq << " " << stamp << " " << tr.getOrigin().x() << " " << tr.getOrigin().y() << " " << tr.getOrigin().z() << " " <<
00399 tr.getRotation().x() << " " << tr.getRotation().y() << " " << tr.getRotation().z() << " " << tr.getRotation().w() << std::endl;
00400
00401 pthread_mutex_unlock(&(logPTAMRaw_CS));
00402 }
00403
00404 }
00405
00406 void EstimationNode::toogleLogging()
00407 {
00408
00409 struct stat st;
00410 if(stat((packagePath+std::string("/logs")).c_str(),&st) != 0)
00411 mkdir((packagePath+std::string("/logs")).c_str(),S_IXGRP | S_IXOTH | S_IXUSR | S_IRWXU | S_IRWXG | S_IROTH);
00412
00413 char buf[200];
00414 bool quitLogging = false;
00415 if(logfileIMU == 0)
00416 {
00417 currentLogID = ((long)time(0))*100+(getMS()%100);
00418 startedLogClock = getMS();
00419 ROS_INFO("\n\nENABLED LOGGING to %s/logs/%ld\n\n\n",packagePath.c_str(),currentLogID);
00420 sprintf(buf,"%s/logs/%ld",packagePath.c_str(),currentLogID);
00421 mkdir(buf, S_IXGRP | S_IXOTH | S_IXUSR | S_IRWXU | S_IRWXG | S_IROTH);
00422
00423
00424 sprintf(buf,"u l ENABLED LOGGING to %s/logs/%ld",packagePath.c_str(),currentLogID);
00425 publishCommand(buf);
00426 }
00427 else
00428 quitLogging = true;
00429
00430
00431
00432
00433 pthread_mutex_lock(&logIMU_CS);
00434 if(logfileIMU == 0)
00435 {
00436 logfileIMU = new std::ofstream();
00437 sprintf(buf,"%s/logs/%ld/logIMU.txt",packagePath.c_str(),currentLogID);
00438 logfileIMU->open (buf);
00439 }
00440 else
00441 {
00442 logfileIMU->flush();
00443 logfileIMU->close();
00444 delete logfileIMU;
00445 logfileIMU = NULL;
00446 }
00447 pthread_mutex_unlock(&logIMU_CS);
00448
00449
00450
00451 pthread_mutex_lock(&logPTAM_CS);
00452 if(logfilePTAM == 0)
00453 {
00454 logfilePTAM = new std::ofstream();
00455 sprintf(buf,"%s/logs/%ld/logPTAM.txt",packagePath.c_str(),currentLogID);
00456 logfilePTAM->open (buf);
00457 }
00458 else
00459 {
00460 logfilePTAM->flush();
00461 logfilePTAM->close();
00462 delete logfilePTAM;
00463 logfilePTAM = NULL;
00464 }
00465 pthread_mutex_unlock(&logPTAM_CS);
00466
00467
00468
00469
00470 pthread_mutex_lock(&logFilter_CS);
00471 if(logfileFilter == 0)
00472 {
00473 logfileFilter = new std::ofstream();
00474 sprintf(buf,"%s/logs/%ld/logFilter.txt",packagePath.c_str(),currentLogID);
00475 logfileFilter->open (buf);
00476 }
00477 else
00478 {
00479 logfileFilter->flush();
00480 logfileFilter->close();
00481 delete logfileFilter;
00482 logfileFilter = NULL;
00483 }
00484 pthread_mutex_unlock(&logFilter_CS);
00485
00486
00487
00488 pthread_mutex_lock(&logPTAMRaw_CS);
00489 if(logfilePTAMRaw == 0)
00490 {
00491 logfilePTAMRaw = new std::ofstream();
00492 sprintf(buf,"%s/logs/%ld/logPTAMRaw.txt",packagePath.c_str(),currentLogID);
00493 logfilePTAMRaw->open (buf);
00494 }
00495 else
00496 {
00497 logfilePTAMRaw->flush();
00498 logfilePTAMRaw->close();
00499 delete logfilePTAMRaw;
00500 logfilePTAMRaw = NULL;
00501 }
00502 pthread_mutex_unlock(&logPTAMRaw_CS);
00503
00504
00505 if(quitLogging)
00506 {
00507 printf("\n\nDISABLED LOGGING (logged %ld sec)\n\n\n",(getMS()-startedLogClock+500)/1000);
00508 char buf2[200];
00509 sprintf(buf,"%s/logs/%ld",packagePath.c_str(),currentLogID);
00510 sprintf(buf2,"%s/logs/%ld-%lds",packagePath.c_str(),currentLogID,(getMS()-startedLogClock+500)/1000);
00511 rename(buf,buf2);
00512 }
00513
00514 }
00515
00516 void EstimationNode::reSendInfo()
00517 {
00518
00519
00520 std::string ptamStatus;
00521 switch(ptamWrapper->PTAMStatus)
00522 {
00523 case PTAMWrapper::PTAM_IDLE:
00524 ptamStatus = "Idle";
00525 break;
00526 case PTAMWrapper::PTAM_INITIALIZING:
00527 ptamStatus = "Initializing";
00528 break;
00529 case PTAMWrapper::PTAM_LOST:
00530 ptamStatus = "Lost";
00531 break;
00532 case PTAMWrapper::PTAM_FALSEPOSITIVE:
00533 ptamStatus = "FalsePositive";
00534 break;
00535 case PTAMWrapper::PTAM_GOOD:
00536 ptamStatus = "Good";
00537 break;
00538 case PTAMWrapper::PTAM_TOOKKF:
00539 case PTAMWrapper::PTAM_BEST:
00540 ptamStatus = "Best";
00541 break;
00542 }
00543
00544
00545
00546
00547 std::string ptamMsg = ptamWrapper->lastPTAMMessage;
00548 int kf, kp, kps[4], kpf[4];
00549 size_t pos = ptamMsg.find("Found: ");
00550 int found = 0;
00551 if(pos != std::string::npos)
00552 found = sscanf(ptamMsg.substr(pos).c_str(),"Found: %d/%d %d/%d %d/%d %d/%d Map: %dP, %dKF",
00553 &kpf[0],&kps[0],&kpf[1],&kps[1],&kpf[2],&kps[2],&kpf[3],&kps[3],&kp,&kf);
00554 char bufp[200];
00555 if(found == 10)
00556 snprintf(bufp,200,"Map: KF: %d, KP: %d (%d of %d found)",
00557 kf, kp,kpf[0]+kpf[1]+kpf[2]+kpf[3], kps[0]+kps[1]+kps[2]+kps[3]);
00558 else
00559 snprintf(bufp,200,"Map: -");
00560
00561 std::string status = "";
00562 switch( lastNavdataReceived.state)
00563 {
00564 case 0: status = "Unknown";break;
00565 case 1: status = "Init"; break;
00566 case 2: status = "Landed";break;
00567 case 3: status = "Flying"; break;
00568 case 4: status = "Hovering";break;
00569 case 5: status = "Test"; break;
00570 case 6: status = "Taking off";break;
00571 case 7: status = "Goto Fix Point"; break;
00572 case 8: status = "Landing";break;
00573 case 9: status = "Looping"; break;
00574 }
00575
00576
00577
00578
00579
00580
00581
00582 char buf[1000];
00583 snprintf(buf,1000,"u s PTAM: %s\n%s\nScale: %.3f (%d in, %d out), acc: %.2f\nScaleFixpoint: %s\nDrone Status: %s (%d Battery)",
00584 ptamStatus.c_str(),
00585 bufp,
00586 filter->getCurrentScales()[0],filter->scalePairsIn,filter->scalePairsOut,filter->getScaleAccuracy(),
00587 filter->useScalingFixpoint ? "FIX" : "DRONE",
00588 status.c_str(), (int)lastNavdataReceived.batteryPercent);
00589
00590 publishCommand(buf);
00591 }