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
00026 ros::Publisher odom_pub_;
00027 ros::Publisher pose_pub_;
00028
00029 ros::ServiceServer reset_service_;
00030
00031
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
00040 tf::Transform integrated_pose_;
00041
00042 ros::Time last_update_time_;
00043
00044 tf::StampedTransform initial_base_to_sensor_;
00045
00046 tf::StampedTransform current_base_to_sensor_;
00047
00048
00049 boost::array<double, 36> pose_covariance_;
00050 boost::array<double, 36> twist_covariance_;
00051
00052 public:
00053
00054 OdometerBase()
00055 {
00056
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
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
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
00175 integrated_pose_ *= delta_transform;
00176
00177
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
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 }
00239
00240 #endif
00241