pose_estimation.cpp
Go to the documentation of this file.
00001 
00010 #include "ucl_drone/pose_estimation.h"
00011 
00012 #include <math.h> /* isfinite*/
00013 
00014 // Constructor
00015 PoseEstimator::PoseEstimator()
00016 {
00017   // Parameters
00018 
00019   ros::param::get("~use_visual_pose",
00020                   this->use_visual_pose);  // if false, only onboard readings are used
00021 
00022   std::string drone_prefix;
00023   ros::param::get("~drone_prefix", drone_prefix);  // relative path to the ardrone_autonomy node
00024 
00025   // Subsribers
00026 
00027   navdata_channel =
00028       nh.resolveName(drone_prefix + "ardrone/navdata");  // raw information from Parrot SDK
00029   navdata_sub = nh.subscribe(navdata_channel, 10, &PoseEstimator::navdataCb, this);
00030 
00031   odometry_channel =
00032       nh.resolveName(drone_prefix + "ardrone/odometry");  // information from Parrot SDK converted
00033                                                           // to SI Units by ardrone_autonomy
00034                                                           // + buggy velocities integration
00035   odometry_sub = nh.subscribe(odometry_channel, 10, &PoseEstimator::odometryCb, this);
00036 
00037   pose_visual_channel = nh.resolveName("pose_visual");  // pose estimation from the mapping node
00038   pose_visual_sub = nh.subscribe(pose_visual_channel, 1, &PoseEstimator::poseVisualCb, this);
00039 
00040   reset_channel = nh.resolveName("reset_pose");  // signal to reset the pose to (0,0,h)
00041   reset_sub = nh.subscribe(reset_channel, 10, &PoseEstimator::resetCb, this);
00042 
00043   // Publishers
00044 
00045   if (this->use_visual_pose)
00046   {
00047     pose_channel = nh.resolveName("pose_estimation");
00048     end_reset_pose_channel = nh.resolveName("end_reset_pose");
00049   }
00050   else
00051   {
00052     pose_channel = nh.resolveName("blind_pose_estimation");
00053     end_reset_pose_channel = nh.resolveName("blind_end_reset_pose");
00054   }
00055 
00056   pose_pub = nh.advertise< ucl_drone::Pose3D >(pose_channel, 1);
00057 
00058   end_reset_pose_pub = nh.advertise< std_msgs::Empty >(end_reset_pose_channel, 1);
00059 
00060   odometry_publishing = false;
00061   visual_pose_available = false;
00062   pending_reset = false;
00063 }
00064 
00065 // Destructor
00066 PoseEstimator::~PoseEstimator()
00067 {
00068 }
00069 
00070 void PoseEstimator::resetCb(const std_msgs::Empty msg)
00071 {
00072   pending_reset = true;  // togle reset state when reset signal is emmitted
00073 }
00074 
00075 // this function call the drone to re-caibrate sensors ! do not call this when the drone is flying !
00076 // the drone needs to lie flat on ground
00077 void PoseEstimator::doFlatTrim()
00078 {
00079   ros::ServiceClient client = nh.serviceClient< std_srvs::Empty >("motherboard1/ardrone/flattrim");
00080   std_srvs::Empty srv;
00081   client.call(srv);
00082 }
00083 
00084 // method to reset the pose to origin (behalve the altitude, the altimeter is used)
00085 void PoseEstimator::doReset()
00086 {
00087   odometry_x = 0;
00088   odometry_y = 0;
00089   odometry_rotX = 0;
00090   odometry_rotY = 0;
00091   odometry_rotZ = 0;
00092   odom_time = lastOdometryReceived.header.stamp;
00093 
00094   lastposeVisualReceived = ucl_drone::Pose3D();
00095   visual_pose_available = false;
00096 
00097   rot_Z_offset = lastNavdataReceived.rotZ / 180.0 * PI;
00098 }
00099 
00100 void PoseEstimator::navdataCb(const ardrone_autonomy::Navdata::ConstPtr navdataPtr)
00101 {
00102   if (pending_reset)
00103     return;
00104   lastNavdataReceived = *navdataPtr;
00105 }
00106 
00107 void PoseEstimator::poseVisualCb(const ucl_drone::Pose3D::ConstPtr poseVisualPtr)
00108 {
00109   if (pending_reset)
00110     return;
00111 
00112   // throw away values older than 1 sec
00113   if (poseVisualPtr->header.stamp < ros::Time::now() - ros::Duration(1.0 / 2.0))
00114   {
00115     ROS_DEBUG("VISUAL POSE disregarded in pose_estimation");
00116     return;
00117   }
00118 
00119   lastposeVisualReceived = *poseVisualPtr;
00120   visual_pose_available = true;
00121 }
00122 
00123 void PoseEstimator::odometryCb(const nav_msgs::Odometry::ConstPtr odometryPtr)
00124 {
00125   // to see what exactly is put in Odometry: see in ardrone_autonomy:
00126   // ardrone_driver.cpp line 698 to 713
00127 
00128   // avoid to publish NAN values
00129   if (std::isfinite(odometryPtr->twist.twist.linear.x) &&
00130       std::isfinite(odometryPtr->twist.twist.linear.y))
00131   {
00132     odometry_publishing = true;
00133     lastOdometryReceived = *odometryPtr;
00134     previous_rotX = lastRotX;
00135     previous_rotY = lastRotY;
00136     previous_rotZ = lastRotZ;
00137     lastRotX = lastNavdataReceived.rotX / 180.0 * PI;
00138     lastRotY = lastNavdataReceived.rotY / 180.0 * PI;
00139     lastRotZ = lastNavdataReceived.rotZ / 180.0 * PI;
00140   }
00141   else
00142   {
00143     ROS_DEBUG("Is ardrone_autonomy odometry a stupid Nan ?");
00144   }
00145 }
00146 
00147 void PoseEstimator::publish_end_reset_pose()
00148 {
00149   std_msgs::Empty msg;
00150   end_reset_pose_pub.publish(msg);
00151   pending_reset = false;
00152 }
00153 
00154 void PoseEstimator::publish_pose()
00155 {
00156   ucl_drone::Pose3D pose_msg;
00157   bool fusion_is_ok = false;
00158   if (this->use_visual_pose)
00159   {
00160     fusion_is_ok = queuePoseFusion(pose_msg);
00161   }
00162   else
00163   {
00164     fusion_is_ok = poseFusion(pose_msg);
00165   }
00166 
00167   // publish
00168   if (fusion_is_ok)  // && pose_pub.getNumSubscribers() > 0)
00169   {
00170     pose_pub.publish(pose_msg);
00171   }
00172 }
00173 
00174 bool PoseEstimator::poseCopy(ucl_drone::Pose3D& pose_msg)
00175 {
00176   // Stupid recopying of ardrone_autonomy odometry based on the integration of
00177   // velocity estimation based on Parrot's optical flow (bottom camera).
00178   // Some small differences:
00179   //    - the header timestamp gives the current time
00180   //    - the angles are given in Euler form (not quaternions): can be deduced
00181   //      from quaternions (can introduce NaN's) or by directly recopying Navdata
00182   pose_msg.header.stamp = ros::Time().now();  // lastOdometryReceived.header.stamp;
00183   pose_msg.header.frame_id = lastOdometryReceived.header.frame_id;
00184   pose_msg.x = lastOdometryReceived.pose.pose.position.x;
00185   pose_msg.y = lastOdometryReceived.pose.pose.position.y;
00186   pose_msg.z = lastOdometryReceived.pose.pose.position.z;
00187 
00188   pose_msg.rotX = lastNavdataReceived.rotX / 180.0 * PI;
00189   pose_msg.rotY = lastNavdataReceived.rotY / 180.0 * PI;
00190   pose_msg.rotZ = lastNavdataReceived.rotZ / 180.0 * PI;
00191   pose_msg.xvel = lastOdometryReceived.twist.twist.linear.x;
00192   pose_msg.yvel = lastOdometryReceived.twist.twist.linear.y;
00193   pose_msg.zvel = lastOdometryReceived.twist.twist.linear.z;
00194   pose_msg.rotXvel = lastOdometryReceived.twist.twist.angular.x;
00195   pose_msg.rotYvel = lastOdometryReceived.twist.twist.angular.y;
00196   pose_msg.rotZvel = lastOdometryReceived.twist.twist.angular.z;
00197 }
00198 
00199 bool PoseEstimator::poseFusion(ucl_drone::Pose3D& pose_msg)
00200 {
00201   // with our own odometry integrated from optical flow
00202   // reset taken into account
00203   // but visual pose not used
00204   ros::Time previous_odom_time = odom_time;
00205   odom_time = lastOdometryReceived.header.stamp;
00206   double delta_t = (odom_time - previous_odom_time).toSec();
00207 
00208   if (delta_t == 0)  // it seems no new odometry was published
00209   {
00210     ROS_DEBUG("Is ardrone_autonomy always responding ?");
00211     return false;
00212   }
00213   if (!std::isfinite(delta_t))
00214   {
00215     ROS_DEBUG("Something strange hapenned! delta_t is not finite!");
00216     return false;
00217   }
00218 
00219   pose_msg.rotX = lastRotX;  // no fusion
00220   pose_msg.rotY = lastRotY;  // no fusion
00221 
00222   odometry_rotZ += lastRotZ - previous_rotZ;
00223 
00224   if (odometry_rotZ > M_PI)
00225     odometry_rotZ -= 2 * M_PI;
00226   if (odometry_rotZ < -M_PI)
00227     odometry_rotZ += 2 * M_PI;
00228 
00229   pose_msg.rotZ = odometry_rotZ;
00230 
00231   // Formulas recopied from ardrone_autonomy, to compute pose from integration
00232   // of the velocities based on Parrot's optical flow (bottom camera).
00233   double xvel =
00234       (float)((cos(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.x) -   // - 0.0048) -
00235                sin(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.y)) *  // - 0.0158)) *
00236               delta_t);
00237   odometry_x += xvel;
00238 
00239   double yvel =
00240       (float)((sin(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.x) +   // - 0.0048) +
00241                cos(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.y)) *  // - 0.0158)) *
00242               delta_t);
00243   odometry_y += yvel;
00244 
00245   pose_msg.x = odometry_x;
00246   pose_msg.y = odometry_y;
00247   pose_msg.z = lastOdometryReceived.pose.pose.position.z;  // no fusion
00248   // but altitude is not received when drone is not flying !
00249   if (lastOdometryReceived.pose.pose.position.z == 0)
00250     pose_msg.z = lastposeVisualReceived.z;  // for experiments
00251 
00252   pose_msg.header.stamp = odom_time;
00253 
00254   pose_msg.xvel = lastOdometryReceived.twist.twist.linear.x;
00255   pose_msg.yvel = lastOdometryReceived.twist.twist.linear.y;
00256   pose_msg.zvel =
00257       lastOdometryReceived.twist.twist.linear.z;  // not received when drone is not flying !
00258   pose_msg.rotXvel =
00259       lastOdometryReceived.twist.twist.angular.x;  // not received when drone is not flying !
00260   pose_msg.rotYvel =
00261       lastOdometryReceived.twist.twist.angular.y;  // not received when drone is not flying !
00262   pose_msg.rotZvel =
00263       lastOdometryReceived.twist.twist.angular.z;  // not received when drone is not flying !
00264 
00265   return true;
00266 }
00267 
00268 bool PoseEstimator::queuePoseFusion(ucl_drone::Pose3D& pose_msg)
00269 {
00270   // Simple fusion technique explained in our report
00271   // our own odometry integrated from optical flow
00272   ros::Time previous_odom_time = odom_time;
00273   odom_time = lastOdometryReceived.header.stamp;
00274   double delta_t = (odom_time - previous_odom_time).toSec();
00275 
00276   if (delta_t == 0)  // it seems no new odometry was published
00277   {
00278     ROS_DEBUG("Is ardrone_autonomy always responding ?");
00279     return false;
00280   }
00281   if (!std::isfinite(delta_t))
00282   {
00283     ROS_DEBUG("Something strange hapenned! delta_t is not finite!");
00284     return false;
00285   }
00286 
00287   if (visual_pose_available)
00288   {
00289     ROS_DEBUG("VISUAL POSE received in pose_estimation");
00290     odometry_x = 0;
00291     odometry_y = 0;
00292     odometry_rotZ = lastposeVisualReceived.rotZ;
00293 
00294     this->processQueue(this->queue_dx, this->odometry_x);
00295     this->processQueue(this->queue_dy, this->odometry_y);
00296     this->processQueue(this->queue_drotZ, this->odometry_rotZ);
00297 
00298     visual_pose_available = false;
00299   }
00300 
00301   pose_msg.rotX = lastRotX;
00302   pose_msg.rotY = lastRotY;
00303 
00305   odometry_rotZ += lastRotZ - previous_rotZ;
00306 
00308   this->pushQueue(this->queue_drotZ, lastRotZ - previous_rotZ);
00309   pose_msg.rotZ = odometry_rotZ;
00310 
00311   // ////////////////////////////////////////////////////////////////////
00312   // pose_msg.rotZ = lastRotZ - rot_Z_offset;  // rot_Z_offset determined by
00313 
00314   // initial calibration
00315   // (see PoseEstimator::reset)
00316 
00317   if (pose_msg.rotZ > M_PI)
00318     pose_msg.rotZ -= 2 * M_PI;
00319   if (pose_msg.rotZ < -M_PI)
00320     pose_msg.rotZ += 2 * M_PI;
00321 
00322   // Formulas recopied from ardrone_autonomy, to compute pose from integration
00323   // of the velocities
00324   double dx =
00325       (float)((cos(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.x) -   // - 0.0048) -
00326                sin(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.y)) *  // - 0.0158)) *
00327               delta_t);
00328   odometry_x += dx;
00329 
00330   this->pushQueue(this->queue_dx, dx);
00331 
00332   double dy =
00333       (float)((sin(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.x) +   // - 0.0048) +
00334                cos(pose_msg.rotZ) * (lastOdometryReceived.twist.twist.linear.y)) *  // - 0.0158)) *
00335               delta_t);
00336   odometry_y += dy;
00337 
00338   this->pushQueue(this->queue_dy, dy);
00339 
00340   pose_msg.x = lastposeVisualReceived.x + odometry_x;
00341   pose_msg.y = lastposeVisualReceived.y + odometry_y;
00342   pose_msg.z = lastOdometryReceived.pose.pose.position.z;  // not received when drone not
00343   //   flying !!!
00344   if (lastOdometryReceived.pose.pose.position.z == 0)
00345     pose_msg.z = lastposeVisualReceived.z;
00346 
00347   pose_msg.header.stamp = odom_time;
00348 
00349   pose_msg.xvel = lastOdometryReceived.twist.twist.linear.x;
00350   pose_msg.yvel = lastOdometryReceived.twist.twist.linear.y;
00351   pose_msg.zvel =
00352       lastOdometryReceived.twist.twist.linear.z;  // not received when drone not flying !!!
00353   pose_msg.rotXvel =
00354       lastOdometryReceived.twist.twist.angular.x;  // not received when drone not flying !!!
00355   pose_msg.rotYvel =
00356       lastOdometryReceived.twist.twist.angular.y;  // not received when drone not flying !!!
00357   pose_msg.rotZvel =
00358       lastOdometryReceived.twist.twist.angular.z;  // not received when drone not flying !!!
00359 
00360   return true;
00361 }
00362 
00363 void PoseEstimator::pushQueue(std::queue< std::vector< double > >& myqueue, double item)
00364 {
00365   std::vector< double > v(2);
00366   v[0] = lastOdometryReceived.header.stamp.toSec();
00367   v[1] = item;
00368   myqueue.push(v);
00369   if (myqueue.size() > 200)
00370   {
00371     myqueue.pop();
00372   }
00373 }
00374 
00375 void PoseEstimator::processQueue(std::queue< std::vector< double > >& myqueue, double& result)
00376 {
00377   bool test = true;
00378   while (test && !myqueue.empty())
00379   {
00380     std::vector< double > popped = myqueue.front();
00381     myqueue.pop();
00382     test = popped[0] < lastposeVisualReceived.header.stamp.toSec();
00383   }
00384 
00385   while (!myqueue.empty())
00386   {
00387     std::vector< double > popped = myqueue.front();
00388     myqueue.pop();
00389     result += popped[1];
00390   }
00391 }
00392 
00393 int main(int argc, char** argv)
00394 {
00395   // if (ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug))
00396   // {
00397   //   ros::console::notifyLoggerLevelsChanged();
00398   // }
00399   ROS_INFO_STREAM("pose_estimation started!");
00400 
00401   ros::init(argc, argv, "pose_estimation");
00402   PoseEstimator myPose;
00403   ros::Rate r(20);
00404 
00405   ROS_DEBUG("pose estimation initialized");
00406   while (!myPose.odometry_publishing && ros::ok())
00407   {
00408     ros::spinOnce();
00409     r.sleep();
00410   }
00411 
00412   ROS_DEBUG("ardrone_driver publishing: ending hibernate");
00413   myPose.doFlatTrim();
00414   myPose.doReset();
00415   ROS_DEBUG("reset done");
00416 
00417   while (ros::ok())
00418   {
00419     TIC(pose);
00420     myPose.publish_pose();
00421     TOC(pose, "pose");
00422 
00423     if (myPose.pending_reset)
00424     {
00425       ros::Time t = ros::Time::now() + ros::Duration(3);
00426       while (ros::Time::now() < t)
00427       {
00428         ros::spinOnce();
00429         myPose.doReset();
00430       }
00431       myPose.publish_end_reset_pose();
00432     }
00433 
00434     ros::spinOnce();
00435     r.sleep();
00436   }
00437   return 0;
00438 }


ucl_drone
Author(s): dronesinma
autogenerated on Sat Jun 8 2019 20:51:53