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 private:
00023
00024 ros::Publisher odom_pub_;
00025 ros::Publisher pose_pub_;
00026
00027 ros::ServiceServer reset_service_;
00028
00029
00030 std::string sensor_frame_id_;
00031 std::string odom_frame_id_;
00032 std::string base_link_frame_id_;
00033 tf::TransformListener tf_listener_;
00034 tf::TransformBroadcaster tf_broadcaster_;
00035 bool publish_tf_;
00036
00037
00038 tf::Transform integrated_pose_;
00039
00040 ros::Time last_update_time_;
00041
00042
00043 boost::array<double, 36> pose_covariance_;
00044 boost::array<double, 36> twist_covariance_;
00045
00046 public:
00047 OdometerBase()
00048 {
00049
00050 ros::NodeHandle local_nh("~");
00051
00052 local_nh.param("odom_frame_id", odom_frame_id_, std::string("/odom"));
00053 local_nh.param("base_link_frame_id", base_link_frame_id_, std::string("/multisense/head"));
00054 local_nh.param("sensor_frame_id", sensor_frame_id_, std::string("/multisense/left_camera_optical_frame"));
00055 local_nh.param("publish_tf", publish_tf_, true);
00056
00057 ROS_INFO_STREAM("Basic Odometer Settings:" << std::endl <<
00058 " odom_frame_id = " << odom_frame_id_ << std::endl <<
00059 " base_link_frame_id = " << base_link_frame_id_ << std::endl <<
00060 " publish_tf = " << (publish_tf_?"true":"false"));
00061
00062
00063 odom_pub_ = local_nh.advertise<nav_msgs::Odometry>("odometry", 1);
00064 pose_pub_ = local_nh.advertise<geometry_msgs::PoseStamped>("pose", 1);
00065
00066 reset_service_ = local_nh.advertiseService("reset_pose", &OdometerBase::resetPose, this);
00067
00068 integrated_pose_.setIdentity();
00069
00070 pose_covariance_.assign(0.0);
00071 twist_covariance_.assign(0.0);
00072 }
00073
00074 protected:
00075
00076 void setSensorFrameId(const std::string& frame_id)
00077 {
00078 sensor_frame_id_ = frame_id;
00079 }
00080
00081 std::string getSensorFrameId() const
00082 {
00083 return sensor_frame_id_;
00084 }
00085
00086 void setPoseCovariance(const boost::array<double, 36>& pose_covariance)
00087 {
00088 pose_covariance_ = pose_covariance;
00089 }
00090
00091 void setTwistCovariance(const boost::array<double, 36>& twist_covariance)
00092 {
00093 twist_covariance_ = twist_covariance;
00094 }
00095
00096 void integrateAndPublish(const tf::Transform& delta_transform, const ros::Time& timestamp)
00097 {
00098 if (sensor_frame_id_.empty())
00099 {
00100 ROS_ERROR("[odometer] update called with unknown sensor frame id!");
00101 return;
00102 }
00103 if (timestamp < last_update_time_)
00104 {
00105 ROS_WARN("[odometer] saw negative time change in incoming sensor data, resetting pose.");
00106 integrated_pose_.setIdentity();
00107 tf_listener_.clear();
00108 }
00109 integrated_pose_ *= delta_transform;
00110
00111
00112 tf::StampedTransform base_to_sensor;
00113 std::string error_msg;
00114 if (tf_listener_.canTransform(base_link_frame_id_, sensor_frame_id_, timestamp, &error_msg))
00115 {
00116 tf_listener_.lookupTransform(
00117 base_link_frame_id_,
00118 sensor_frame_id_,
00119 timestamp, base_to_sensor);
00120 }
00121 else
00122 {
00123 ROS_WARN_THROTTLE(10.0, "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 base_to_sensor.setIdentity();
00129 }
00130
00131 tf::Transform base_transform = base_to_sensor * integrated_pose_ * base_to_sensor.inverse();
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 nav_msgs::Odometry odometry_msg;
00143 odometry_msg.header.stamp = timestamp;
00144 odometry_msg.header.frame_id = odom_frame_id_;
00145 odometry_msg.child_frame_id = base_link_frame_id_;
00146 tf::poseTFToMsg(base_transform, odometry_msg.pose.pose);
00147
00148
00149 tf::Transform delta_base_transform = base_to_sensor * delta_transform * base_to_sensor.inverse();
00150 if (!last_update_time_.isZero())
00151 {
00152 double delta_t = (timestamp - last_update_time_).toSec();
00153 if (delta_t)
00154 {
00155 odometry_msg.twist.twist.linear.x = delta_base_transform.getOrigin().getX() / delta_t;
00156 odometry_msg.twist.twist.linear.y = delta_base_transform.getOrigin().getY() / delta_t;
00157 odometry_msg.twist.twist.linear.z = delta_base_transform.getOrigin().getZ() / delta_t;
00158 tf::Quaternion delta_rot = delta_base_transform.getRotation();
00159 tfScalar angle = delta_rot.getAngle();
00160 tf::Vector3 axis = delta_rot.getAxis();
00161 tf::Vector3 angular_twist = axis * angle / delta_t;
00162 odometry_msg.twist.twist.angular.x = angular_twist.x();
00163 odometry_msg.twist.twist.angular.y = angular_twist.y();
00164 odometry_msg.twist.twist.angular.z = angular_twist.z();
00165 }
00166 }
00167
00168
00169 odometry_msg.pose.covariance = pose_covariance_;
00170 odometry_msg.twist.covariance = twist_covariance_;
00171 odom_pub_.publish(odometry_msg);
00172
00173 geometry_msgs::PoseStamped pose_msg;
00174 pose_msg.header.stamp = odometry_msg.header.stamp;
00175 pose_msg.header.frame_id = odometry_msg.header.frame_id;
00176 pose_msg.pose = odometry_msg.pose.pose;
00177
00178 pose_pub_.publish(pose_msg);
00179
00180 if (publish_tf_)
00181 {
00182 tf_broadcaster_.sendTransform(
00183 tf::StampedTransform(base_transform, timestamp,
00184 odom_frame_id_, base_link_frame_id_));
00185 }
00186
00187 last_update_time_ = timestamp;
00188 }
00189
00190
00191 bool resetPose(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
00192 {
00193 integrated_pose_.setIdentity();
00194 return true;
00195 }
00196
00197 };
00198
00199 }
00200
00201 #endif
00202