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 }