$search
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 }