odometer_base.h
Go to the documentation of this file.
00001 
00002 #ifndef ODOMETER_BASE_H_
00003 #define ODOMETER_BASE_H_
00004 
00005 #include <ros/ros.h>
00006 #include <nav_msgs/Odometry.h>
00007 #include <std_srvs/Empty.h>
00008 
00009 #include <tf/transform_listener.h>
00010 #include <tf/transform_broadcaster.h>
00011 
00012 namespace viso2_ros
00013 {
00014 
00020 class OdometerBase
00021 {
00022 
00023 private:
00024 
00025   // publisher
00026   ros::Publisher odom_pub_;
00027   ros::Publisher pose_pub_;
00028 
00029   ros::ServiceServer reset_service_;
00030 
00031   // tf related
00032   std::string sensor_frame_id_;
00033   std::string odom_frame_id_;
00034   std::string base_link_frame_id_;
00035   tf::TransformListener tf_listener_;
00036   tf::TransformBroadcaster tf_broadcaster_;
00037   bool publish_tf_;
00038 
00039   // the current integrated camera pose
00040   tf::Transform integrated_pose_;
00041   // timestamp of the last update
00042   ros::Time last_update_time_;
00043   // initial tf base link to sensor link
00044   tf::StampedTransform initial_base_to_sensor_;
00045   // current tf base link to sensor link
00046   tf::StampedTransform current_base_to_sensor_;
00047 
00048   // covariances
00049   boost::array<double, 36> pose_covariance_;
00050   boost::array<double, 36> twist_covariance_;
00051 
00052 public:
00053 
00054   OdometerBase()
00055   {
00056     // Read local parameters
00057     ros::NodeHandle local_nh("~");
00058 
00059     local_nh.param("odom_frame_id", odom_frame_id_, std::string("/odom"));
00060     local_nh.param("base_link_frame_id", base_link_frame_id_, std::string("/base_link"));
00061     local_nh.param("sensor_frame_id", sensor_frame_id_, std::string("/camera"));
00062     local_nh.param("publish_tf", publish_tf_, true);
00063 
00064     ROS_INFO_STREAM("Basic Odometer Settings:" << std::endl <<
00065                     "  odom_frame_id      = " << odom_frame_id_ << std::endl <<
00066                     "  base_link_frame_id = " << base_link_frame_id_ << std::endl <<
00067                     "  publish_tf         = " << (publish_tf_?"true":"false"));
00068     
00069     // advertise
00070     odom_pub_ = local_nh.advertise<nav_msgs::Odometry>("odometry", 1);
00071     pose_pub_ = local_nh.advertise<geometry_msgs::PoseStamped>("pose", 1);
00072 
00073     reset_service_ = local_nh.advertiseService("reset_pose", &OdometerBase::resetPose, this);
00074 
00075     integrated_pose_.setIdentity();
00076 
00077     pose_covariance_.assign(0.0);
00078     twist_covariance_.assign(0.0);
00079   }
00080 
00081 protected:
00082 
00083   void setSensorFrameId(const std::string& frame_id)
00084   {
00085     sensor_frame_id_ = frame_id;
00086     integrated_pose_.setIdentity();
00087   }
00088 
00089   std::string getSensorFrameId() const
00090   {
00091     return sensor_frame_id_;
00092   }
00093 
00094   void setPoseCovariance(const boost::array<double, 36>& pose_covariance)
00095   {
00096     pose_covariance_ = pose_covariance;
00097   }
00098 
00099   void setTwistCovariance(const boost::array<double, 36>& twist_covariance)
00100   {
00101     twist_covariance_ = twist_covariance;
00102   }
00103 
00104   void updateInitialBaseToSensorTransform()
00105   {
00106     ROS_INFO("Retrieving initial transform for %s to %s.", 
00107         base_link_frame_id_.c_str(), sensor_frame_id_.c_str());
00108     ros::Duration polling_sleep_duration(0.01);
00109     ros::Duration timeout(5.0);
00110     std::string error_msg;
00111     bool success = tf_listener_.waitForTransform(
00112         base_link_frame_id_, sensor_frame_id_,
00113         ros::Time(0), timeout, polling_sleep_duration, &error_msg);
00114     if (success)
00115     {
00116       tf_listener_.lookupTransform(
00117           base_link_frame_id_,
00118           sensor_frame_id_,
00119           ros::Time(0), initial_base_to_sensor_);
00120     }
00121     else
00122     {
00123       ROS_WARN("The tf from '%s' to '%s' does not seem to be available, "
00124                "will assume it as identity!", 
00125                base_link_frame_id_.c_str(),
00126                sensor_frame_id_.c_str());
00127       ROS_DEBUG("Transform error: %s", error_msg.c_str());
00128       initial_base_to_sensor_.setIdentity();
00129     }
00130     current_base_to_sensor_ = initial_base_to_sensor_;
00131   }
00132 
00133   void updateCurrentBaseToSensorTransform(const ros::Time& timestamp)
00134   {
00135     // wait 1/20 of a second
00136     ros::Duration polling_sleep_duration(0.01);
00137     ros::Duration timeout(0.05);
00138     tf_listener_.waitForTransform(
00139         base_link_frame_id_, sensor_frame_id_,
00140         timestamp, timeout, polling_sleep_duration);
00141   
00142     std::string error_msg;
00143     if (tf_listener_.canTransform(base_link_frame_id_, sensor_frame_id_, timestamp, &error_msg))
00144     {
00145       tf_listener_.lookupTransform(
00146           base_link_frame_id_,
00147           sensor_frame_id_,
00148           timestamp, current_base_to_sensor_);
00149     }
00150     else
00151     {
00152       ROS_WARN_THROTTLE(5.0, "The tf from '%s' to '%s' does not seem to be available, "
00153                               "will use cached tf!", 
00154                               base_link_frame_id_.c_str(),
00155                               sensor_frame_id_.c_str());
00156       ROS_DEBUG("Transform error: %s", error_msg.c_str());
00157     }
00158   }
00159 
00160   void integrateAndPublish(const tf::Transform& delta_transform, const ros::Time& timestamp)
00161   {
00162     if (sensor_frame_id_.empty())
00163     {
00164       ROS_ERROR("[odometer] update called with unknown sensor frame id!");
00165       return;
00166     }
00167     if (timestamp < last_update_time_)
00168     {
00169       ROS_WARN("[odometer] saw negative time change in incoming sensor data, resetting pose.");
00170       integrated_pose_.setIdentity();
00171       tf_listener_.clear();
00172     }
00173     
00174     // integrate pose
00175     integrated_pose_ *= delta_transform;
00176 
00177     // transform integrated pose to base frame
00178     updateCurrentBaseToSensorTransform(timestamp);
00179     tf::Transform base_transform = initial_base_to_sensor_ * integrated_pose_ * current_base_to_sensor_.inverse();
00180 
00181     nav_msgs::Odometry odometry_msg;
00182     odometry_msg.header.stamp = timestamp;
00183     odometry_msg.header.frame_id = odom_frame_id_;
00184     odometry_msg.child_frame_id = base_link_frame_id_;
00185     tf::poseTFToMsg(base_transform, odometry_msg.pose.pose);
00186 
00187     // calculate twist (not possible for first run as no delta_t can be computed)
00188     tf::Transform delta_base_transform = current_base_to_sensor_ * delta_transform * current_base_to_sensor_.inverse();
00189     if (!last_update_time_.isZero())
00190     {
00191       double delta_t = (timestamp - last_update_time_).toSec();
00192       if (delta_t)
00193       {
00194         odometry_msg.twist.twist.linear.x = delta_base_transform.getOrigin().getX() / delta_t;
00195         odometry_msg.twist.twist.linear.y = delta_base_transform.getOrigin().getY() / delta_t;
00196         odometry_msg.twist.twist.linear.z = delta_base_transform.getOrigin().getZ() / delta_t;
00197         tf::Quaternion delta_rot = delta_base_transform.getRotation();
00198         tfScalar angle = delta_rot.getAngle();
00199         tf::Vector3 axis = delta_rot.getAxis();
00200         tf::Vector3 angular_twist = axis * angle / delta_t;
00201         odometry_msg.twist.twist.angular.x = angular_twist.x();
00202         odometry_msg.twist.twist.angular.y = angular_twist.y();
00203         odometry_msg.twist.twist.angular.z = angular_twist.z();
00204       }
00205     }
00206 
00207     odometry_msg.pose.covariance = pose_covariance_;
00208     odometry_msg.twist.covariance = twist_covariance_;
00209     odom_pub_.publish(odometry_msg);
00210     
00211     geometry_msgs::PoseStamped pose_msg;
00212     pose_msg.header.stamp = odometry_msg.header.stamp;
00213     pose_msg.header.frame_id = odometry_msg.header.frame_id;
00214     pose_msg.pose = odometry_msg.pose.pose;
00215 
00216     pose_pub_.publish(pose_msg);
00217 
00218     if (publish_tf_)
00219     {
00220       tf_broadcaster_.sendTransform(
00221           tf::StampedTransform(base_transform, timestamp,
00222           odom_frame_id_, base_link_frame_id_));
00223     }
00224 
00225     last_update_time_ = timestamp;
00226   }
00227 
00228 
00229   bool resetPose(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
00230   {
00231     integrated_pose_.setIdentity();
00232     updateInitialBaseToSensorTransform();
00233     return true;
00234   }
00235 
00236 };
00237 
00238 } // end of namespace
00239 
00240 #endif
00241 


viso2_ros
Author(s): Stephan Wirth
autogenerated on Tue Jan 7 2014 11:42:16