fake_localization.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  * 
00004  *  Copyright (c) 2008, Willow Garage, Inc.
00005  *  All rights reserved.
00006  * 
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  * 
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  * 
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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       // subscription to "2D Pose Estimate" from RViz:
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     //parameter for what odom to use
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       //we have to do this to force the message filter to wait for transforms
00162       //from odom_frame_id_ to base_frame_id_ to be available at time odom_msg.header.stamp
00163       //really, the base_pose_ground_truth should come in with no frame_id b/c it doesn't make sense
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       //also apply the offset to the pose
00192       current = m_offsetTf * current;
00193 
00194       geometry_msgs::Pose current_msg;
00195       tf::poseTFToMsg(current, current_msg);
00196 
00197       // Publish localized pose
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       // The particle cloud is the current position. Quite convenient.
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       // set offset so that current pose is set to "initialpose"    
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 }


fake_localization
Author(s): Ioan A. Sucan
autogenerated on Sat Dec 28 2013 17:14:38