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,true);
00096 m_particlecloudPub = m_nh.advertise<geometry_msgs::PoseArray>("particlecloud",1,true);
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 private_nh.param("transform_tolerance", transform_tolerance_, 0.1);
00110 m_particleCloud.header.stamp = ros::Time::now();
00111 m_particleCloud.header.frame_id = global_frame_id_;
00112 m_particleCloud.poses.resize(1);
00113 ros::NodeHandle nh;
00114
00115 m_offsetTf = tf::Transform(tf::createQuaternionFromRPY(0, 0, -delta_yaw_ ), tf::Point(-delta_x_, -delta_y_, 0.0));
00116
00117 stuff_sub_ = nh.subscribe("base_pose_ground_truth", 100, &FakeOdomNode::stuffFilter, this);
00118 filter_sub_ = new message_filters::Subscriber<nav_msgs::Odometry>(nh, "", 100);
00119 filter_ = new tf::MessageFilter<nav_msgs::Odometry>(*filter_sub_, *m_tfListener, base_frame_id_, 100);
00120 filter_->registerCallback(boost::bind(&FakeOdomNode::update, this, _1));
00121
00122
00123 m_initPoseSub = new message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>(nh, "initialpose", 1);
00124 m_initPoseFilter = new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(*m_initPoseSub, *m_tfListener, global_frame_id_, 1);
00125 m_initPoseFilter->registerCallback(boost::bind(&FakeOdomNode::initPoseReceived, this, _1));
00126 }
00127
00128 ~FakeOdomNode(void)
00129 {
00130 if (m_tfServer)
00131 delete m_tfServer;
00132 }
00133
00134
00135 private:
00136 ros::NodeHandle m_nh;
00137 ros::Publisher m_posePub;
00138 ros::Publisher m_particlecloudPub;
00139 message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>* m_initPoseSub;
00140 tf::TransformBroadcaster *m_tfServer;
00141 tf::TransformListener *m_tfListener;
00142 tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>* m_initPoseFilter;
00143 tf::MessageFilter<nav_msgs::Odometry>* filter_;
00144 ros::Subscriber stuff_sub_;
00145 message_filters::Subscriber<nav_msgs::Odometry>* filter_sub_;
00146
00147 double delta_x_, delta_y_, delta_yaw_;
00148 bool m_base_pos_received;
00149 double transform_tolerance_;
00150
00151 nav_msgs::Odometry m_basePosMsg;
00152 geometry_msgs::PoseArray m_particleCloud;
00153 geometry_msgs::PoseWithCovarianceStamped m_currentPos;
00154 tf::Transform m_offsetTf;
00155
00156
00157 std::string odom_frame_id_;
00158 std::string base_frame_id_;
00159 std::string global_frame_id_;
00160
00161 public:
00162 void stuffFilter(const nav_msgs::OdometryConstPtr& odom_msg){
00163
00164
00165
00166 boost::shared_ptr<nav_msgs::Odometry> stuff_msg(new nav_msgs::Odometry);
00167 *stuff_msg = *odom_msg;
00168 stuff_msg->header.frame_id = odom_frame_id_;
00169 filter_->add(stuff_msg);
00170 }
00171
00172 void update(const nav_msgs::OdometryConstPtr& message){
00173 tf::Pose txi;
00174 tf::poseMsgToTF(message->pose.pose, txi);
00175 txi = m_offsetTf * txi;
00176
00177 tf::Stamped<tf::Pose> odom_to_map;
00178 try
00179 {
00180 m_tfListener->transformPose(odom_frame_id_, tf::Stamped<tf::Pose>(txi.inverse(), message->header.stamp, base_frame_id_), odom_to_map);
00181 }
00182 catch(tf::TransformException &e)
00183 {
00184 ROS_ERROR("Failed to transform to %s from %s: %s\n", odom_frame_id_.c_str(), base_frame_id_.c_str(), e.what());
00185 return;
00186 }
00187
00188 m_tfServer->sendTransform(tf::StampedTransform(odom_to_map.inverse(),
00189 message->header.stamp + ros::Duration(transform_tolerance_),
00190 global_frame_id_, message->header.frame_id));
00191
00192 tf::Pose current;
00193 tf::poseMsgToTF(message->pose.pose, current);
00194
00195
00196 current = m_offsetTf * current;
00197
00198 geometry_msgs::Pose current_msg;
00199 tf::poseTFToMsg(current, current_msg);
00200
00201
00202 m_currentPos.header = message->header;
00203 m_currentPos.header.frame_id = global_frame_id_;
00204 m_currentPos.pose.pose = current_msg;
00205 m_posePub.publish(m_currentPos);
00206
00207
00208 m_particleCloud.header = m_currentPos.header;
00209 m_particleCloud.poses[0] = m_currentPos.pose.pose;
00210 m_particlecloudPub.publish(m_particleCloud);
00211 }
00212
00213 void initPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg){
00214 tf::Pose pose;
00215 tf::poseMsgToTF(msg->pose.pose, pose);
00216
00217 if (msg->header.frame_id != global_frame_id_){
00218 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());
00219 }
00220
00221
00222 tf::StampedTransform baseInMap;
00223 try{
00224 m_tfListener->lookupTransform(base_frame_id_, global_frame_id_, msg->header.stamp, baseInMap);
00225 } catch(tf::TransformException){
00226 ROS_WARN("Failed to lookup transform!");
00227 return;
00228 }
00229
00230 tf::Transform delta = pose * baseInMap;
00231 m_offsetTf = delta * m_offsetTf;
00232
00233 }
00234 };
00235
00236 int main(int argc, char** argv)
00237 {
00238 ros::init(argc, argv, "fake_localization");
00239
00240 FakeOdomNode odom;
00241
00242 ros::spin();
00243
00244 return 0;
00245 }