00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00073 #include <ros/ros.h>
00074 #include <ros/time.h>
00075 
00076 #include <nav_msgs/Odometry.h>
00077 #include <geometry_msgs/PoseArray.h>
00078 #include <geometry_msgs/PoseWithCovarianceStamped.h>
00079 
00080 #include <angles/angles.h>
00081 
00082 #include "ros/console.h"
00083 
00084 #include "tf/transform_broadcaster.h"
00085 #include "tf/transform_listener.h"
00086 #include "tf/message_filter.h"
00087 #include "message_filters/subscriber.h"
00088 
00089 
00090 class FakeOdomNode
00091 {
00092   public:
00093     FakeOdomNode(void)
00094     {
00095       m_posePub = m_nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("amcl_pose",1);
00096       m_particlecloudPub = m_nh.advertise<geometry_msgs::PoseArray>("particlecloud",1);
00097       m_tfServer = new tf::TransformBroadcaster();      
00098       m_tfListener = new tf::TransformListener();
00099 
00100       m_base_pos_received = false;
00101 
00102       ros::NodeHandle private_nh("~");
00103       private_nh.param("odom_frame_id", odom_frame_id_, std::string("odom"));
00104       private_nh.param("base_frame_id", base_frame_id_, std::string("base_link")); 
00105       private_nh.param("global_frame_id", global_frame_id_, std::string("/map"));
00106       private_nh.param("delta_x", delta_x_, 0.0);
00107       private_nh.param("delta_y", delta_y_, 0.0);
00108       private_nh.param("delta_yaw", delta_yaw_, 0.0);      
00109       m_particleCloud.header.stamp = ros::Time::now();
00110       m_particleCloud.header.frame_id = global_frame_id_;
00111       m_particleCloud.poses.resize(1);
00112       ros::NodeHandle nh;
00113 
00114       m_offsetTf = tf::Transform(tf::createQuaternionFromRPY(0, 0, -delta_yaw_ ), tf::Point(-delta_x_, -delta_y_, 0.0));
00115 
00116       stuff_sub_ = nh.subscribe("base_pose_ground_truth", 100, &FakeOdomNode::stuffFilter, this);
00117       filter_sub_ = new message_filters::Subscriber<nav_msgs::Odometry>(nh, "", 100);
00118       filter_ = new tf::MessageFilter<nav_msgs::Odometry>(*filter_sub_, *m_tfListener, base_frame_id_, 100);
00119       filter_->registerCallback(boost::bind(&FakeOdomNode::update, this, _1));
00120 
00121       
00122       m_initPoseSub = new message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>(nh, "initialpose", 1);
00123       m_initPoseFilter = new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(*m_initPoseSub, *m_tfListener, global_frame_id_, 1);
00124       m_initPoseFilter->registerCallback(boost::bind(&FakeOdomNode::initPoseReceived, this, _1));
00125     }
00126 
00127     ~FakeOdomNode(void)
00128     {
00129       if (m_tfServer)
00130         delete m_tfServer; 
00131     }
00132 
00133 
00134   private:
00135     ros::NodeHandle m_nh;
00136     ros::Publisher m_posePub;
00137     ros::Publisher m_particlecloudPub;
00138     message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>* m_initPoseSub;
00139     tf::TransformBroadcaster       *m_tfServer;
00140     tf::TransformListener          *m_tfListener;
00141     tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>* m_initPoseFilter;
00142     tf::MessageFilter<nav_msgs::Odometry>* filter_;
00143     ros::Subscriber stuff_sub_; 
00144     message_filters::Subscriber<nav_msgs::Odometry>* filter_sub_;
00145 
00146     double                         delta_x_, delta_y_, delta_yaw_;
00147     bool                           m_base_pos_received;
00148 
00149     nav_msgs::Odometry  m_basePosMsg;
00150     geometry_msgs::PoseArray      m_particleCloud;
00151     geometry_msgs::PoseWithCovarianceStamped      m_currentPos;
00152     tf::Transform m_offsetTf;
00153 
00154     
00155     std::string odom_frame_id_;
00156     std::string base_frame_id_;
00157     std::string global_frame_id_;
00158 
00159   public:
00160     void stuffFilter(const nav_msgs::OdometryConstPtr& odom_msg){
00161       
00162       
00163       
00164       boost::shared_ptr<nav_msgs::Odometry> stuff_msg(new nav_msgs::Odometry);
00165       *stuff_msg = *odom_msg;
00166       stuff_msg->header.frame_id = odom_frame_id_;
00167       filter_->add(stuff_msg);
00168     }
00169 
00170     void update(const nav_msgs::OdometryConstPtr& message){
00171       tf::Pose txi;
00172       tf::poseMsgToTF(message->pose.pose, txi);
00173       txi = m_offsetTf * txi;
00174 
00175       tf::Stamped<tf::Pose> odom_to_map;
00176       try
00177       {
00178         m_tfListener->transformPose(odom_frame_id_, tf::Stamped<tf::Pose>(txi.inverse(), message->header.stamp, base_frame_id_), odom_to_map);
00179       }
00180       catch(tf::TransformException &e)
00181       {
00182         ROS_ERROR("Failed to transform to %s from %s: %s\n", odom_frame_id_.c_str(), base_frame_id_.c_str(), e.what());
00183         return;
00184       }
00185 
00186       m_tfServer->sendTransform(tf::StampedTransform(odom_to_map.inverse(), message->header.stamp, global_frame_id_, message->header.frame_id));
00187 
00188       tf::Pose current;
00189       tf::poseMsgToTF(message->pose.pose, current);
00190 
00191       
00192       current = m_offsetTf * current;
00193 
00194       geometry_msgs::Pose current_msg;
00195       tf::poseTFToMsg(current, current_msg);
00196 
00197       
00198       m_currentPos.header = message->header;
00199       m_currentPos.header.frame_id = global_frame_id_;
00200       m_currentPos.pose.pose = current_msg;
00201       m_posePub.publish(m_currentPos);
00202 
00203       
00204       m_particleCloud.header = m_currentPos.header;
00205       m_particleCloud.poses[0] = m_currentPos.pose.pose;
00206       m_particlecloudPub.publish(m_particleCloud);
00207     }
00208 
00209     void initPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg){
00210       tf::Pose pose;
00211       tf::poseMsgToTF(msg->pose.pose, pose);
00212 
00213       if (msg->header.frame_id != global_frame_id_){
00214         ROS_WARN("Frame ID of \"initialpose\" (%s) is different from the global frame %s", msg->header.frame_id.c_str(), global_frame_id_.c_str());
00215       }
00216 
00217       
00218       tf::StampedTransform baseInMap;
00219       try{
00220         m_tfListener->lookupTransform(base_frame_id_, global_frame_id_, msg->header.stamp, baseInMap);
00221       } catch(tf::TransformException){
00222         ROS_WARN("Failed to lookup transform!");
00223         return;
00224       }
00225 
00226       tf::Transform delta = pose * baseInMap;
00227       m_offsetTf = delta * m_offsetTf;
00228 
00229     }
00230 };
00231 
00232 int main(int argc, char** argv)
00233 {
00234   ros::init(argc, argv, "fake_localization");
00235 
00236   FakeOdomNode odom;
00237 
00238   ros::spin();
00239 
00240   return 0;
00241 }