Go to the documentation of this file.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 #include "tf_distort.h"
00034
00035 namespace tf_distort{
00036
00037 inline void whiteGaussianNoise(double * n1, double * n2)
00038 {
00039
00040 double v1, v2, s;
00041
00042 do
00043 {
00044 v1 = 2 * static_cast<double> (rand()) / rand_max_ - 1.0;
00045 v2 = 2 * static_cast<double> (rand()) / rand_max_ - 1.0;
00046 s = v1 * v1 + v2 * v2;
00047 } while (s >= 1);
00048
00049 *n1 = sqrt(-2.0 * log(s) / s) * v1;
00050 if (n2)
00051 *n2 = sqrt(-2.0 * log(s) / s) * v2;
00052 }
00053
00054 inline double uniformNoise(const double & mag = 1)
00055 {
00056 return (static_cast<double> (rand()) / rand_max_ * 2.0 - 1.0) * mag;
00057 }
00058
00059 TfDistort::TfDistort() :
00060 nh_(""), pnh_("~"), pub_thread_runnning_(false)
00061 {
00062 srand(ros::Time::now().toNSec());
00063 info_pub_ = nh_.advertise<vicon_bridge::TfDistortInfo>("tf_distort/info", 1);
00064
00065
00066 reconf_srv_ = new ReconfServer(pnh_);
00067 reconf_srv_->setCallback(boost::bind(&TfDistort::reconfCb, this, _1, _2));
00068
00069 startPubThread();
00070 }
00071
00072 TfDistort::~TfDistort()
00073 {
00074 stopPubThread();
00075 delete reconf_srv_;
00076 }
00077
00078 void TfDistort::startPubThread()
00079 {
00080 if (!pub_thread_runnning_)
00081 {
00082 pub_thread_runnning_ = true;
00083 pub_thread_ = boost::thread(&TfDistort::pubThread, this);
00084 }
00085 }
00086
00087 void TfDistort::stopPubThread()
00088 {
00089 pub_thread_runnning_ = false;
00090 pub_thread_.join();
00091 }
00092
00093 void TfDistort::addNoise(tf::StampedTransform & tf)
00094 {
00095 const double deg2rad = M_PI / 180.0;
00096 static ros::Time last_time = ros::Time(0);
00097 static bool once = false;
00098
00099 if (!once)
00100 {
00101 once = true;
00102 last_time = tf.stamp_;
00103 return;
00104 }
00105
00106 double dt = (tf.stamp_-last_time).toSec();
00107 double noise_x = 0, noise_y = 0, noise_z = 0, noise_roll = 0, noise_pitch = 0, noise_yaw = 0;
00108
00109 if (config_.noise_type == vicon_bridge::tf_distort_NORMAL)
00110 {
00111 whiteGaussianNoise(&noise_roll, &noise_pitch);
00112 whiteGaussianNoise(&noise_yaw, &noise_x);
00113 whiteGaussianNoise(&noise_y, &noise_z);
00114
00115 noise_roll *= config_.sigma_roll_pitch * deg2rad;
00116 noise_pitch *= config_.sigma_roll_pitch * deg2rad;
00117 noise_yaw *= config_.sigma_yaw * deg2rad;
00118
00119 noise_x *= config_.sigma_xy;
00120 noise_y *= config_.sigma_xy;
00121 noise_z *= config_.sigma_z;
00122 }
00123 else if (config_.noise_type == vicon_bridge::tf_distort_UNIFORM)
00124 {
00125 noise_roll = uniformNoise(config_.sigma_roll_pitch * deg2rad);
00126 noise_pitch = uniformNoise(config_.sigma_roll_pitch * deg2rad);
00127 noise_yaw = uniformNoise(config_.sigma_yaw * deg2rad);
00128 noise_x = uniformNoise(config_.sigma_xy);
00129 noise_y = uniformNoise(config_.sigma_xy);
00130 noise_z = uniformNoise(config_.sigma_z);
00131 }
00132
00133 noise_x += random_walk_x_.update(dt) * config_.random_walk_k_xy;
00134 noise_y += random_walk_y_.update(dt) * config_.random_walk_k_xy;
00135 noise_z += random_walk_z_.update(dt) * config_.random_walk_k_z;
00136
00137 tf::Vector3 & p = tf.getOrigin();
00138 p.setX(p.x() + noise_x);
00139 p.setY(p.y() + noise_y);
00140 p.setZ(p.z() + noise_z);
00141
00142 p *= config_.position_scale;
00143
00144 tf::Quaternion q;
00145 q.setRPY(noise_roll, noise_pitch, noise_yaw);
00146 tf.setRotation(tf.getRotation() * q);
00147
00148 last_time = tf.stamp_;
00149 }
00150
00151
00152 void TfDistort::reconfCb(Config & config, uint32_t level)
00153 {
00154 if(tf_cb_.connected())
00155 tf_cb_.disconnect();
00156
00157 pub_period_.fromSec(1.0/config.tf_pub_rate);
00158 delay_.fromNSec(config.delay*1e6);
00159
00160 random_walk_x_.configure(config.random_walk_sigma_xy, config.random_walk_tau_xy);
00161 random_walk_y_.configure(config.random_walk_sigma_xy, config.random_walk_tau_xy);
00162 random_walk_z_.configure(config.random_walk_sigma_z, config.random_walk_tau_z);
00163
00164 if(config.tf_publish && !tf_cb_.connected()){
00165 tf_cb_ = tf_listener_.addTransformsChangedListener(boost::bind(&TfDistort::tfCb, this));
00166 }
00167
00168 if(config.tf_frame_out != config_.tf_frame_out){
00169 ros::NodeHandle nh;
00170 stopPubThread();
00171 pose_pub_.reset(new ros::Publisher);
00172 *pose_pub_= nh.advertise<geometry_msgs::TransformStamped>(config.tf_frame_out, 1);
00173 startPubThread();
00174 }
00175
00176 config_ = config;
00177 publishInfo(config_);
00178 }
00179
00180
00181 void TfDistort::tfCb()
00182 {
00183 tf::StampedTransform pose;
00184 static tf::StampedTransform last_pose;
00185 ros::Time tf_time(0);
00186
00187 if (tf_listener_.canTransform(config_.tf_ref_frame, config_.tf_frame_in, tf_time))
00188 {
00189 tf_listener_.lookupTransform(config_.tf_ref_frame, config_.tf_frame_in, tf_time, pose);
00190
00191
00192 if (pose.getOrigin() != last_pose.getOrigin())
00193 {
00194 last_pose = pose;
00195
00196 ros::Time time_now = pose.stamp_;
00197
00198 if ((time_now - last_pub_time_) > pub_period_)
00199 {
00200 pose.child_frame_id_ = config_.tf_frame_out;
00201 boost::mutex::scoped_lock(tf_queue_mutex_);
00202 tf_queue_.push(DelayedTransform(pose, time_now + delay_));
00203 last_pub_time_ = time_now;
00204 }
00205
00206 }
00207 }
00208 }
00209
00210 void TfDistort::pubThread()
00211 {
00212
00213 ros::Duration d(0.001);
00214 ros::Time time_now;
00215 uint32_t cnt = 0;
00216 uint32_t msg_cnt = 0;
00217 geometry_msgs::TransformStamped pose;
00218
00219 while (nh_.ok() && pub_thread_runnning_)
00220 {
00221 cnt++;
00222 d.sleep();
00223 boost::mutex::scoped_lock lock(tf_queue_mutex_);
00224
00225 if (tf_queue_.empty())
00226 continue;
00227
00228 DelayedTransform & dt = tf_queue_.front();
00229 time_now = ros::Time::now();
00230
00231 if (std::abs(time_now.toSec() - dt.time_to_publish.toSec()) < d.toSec() * 0.75
00232 || dt.time_to_publish.toSec() - time_now.toSec() < 0)
00233 {
00234 addNoise(dt.transform);
00235 tf_broadcaster.sendTransform(dt.transform);
00236 tf::transformStampedTFToMsg(dt.transform, pose);
00237
00238
00239
00240 pose_pub_->publish(pose);
00241
00242
00243 tf_queue_.pop();
00244 msg_cnt++;
00245 }
00246 if (cnt > 1.0 / d.toSec())
00247 {
00248
00249 msg_cnt = 0;
00250 cnt = 0;
00251
00252 publishInfo(config_);
00253 }
00254 }
00255 }
00256
00257 void TfDistort::publishInfo(const Config & config){
00258 vicon_bridge::TfDistortInfoPtr info(new vicon_bridge::TfDistortInfo);
00259 info->delay = config.delay;
00260 info->noise_type = config.noise_type;
00261 info->position_scale = config.position_scale;
00262 info->random_walk_k_xy = config.random_walk_k_xy;
00263 info->random_walk_k_z = config.random_walk_k_z;
00264 info->random_walk_sigma_xy = config.random_walk_sigma_xy;
00265 info->random_walk_sigma_z = config.random_walk_sigma_z;
00266 info->random_walk_tau_xy = config.random_walk_tau_xy;
00267 info->random_walk_tau_z = config.random_walk_tau_z;
00268 info->sigma_roll_pitch = config.sigma_roll_pitch;
00269 info->sigma_xy = config.sigma_xy;
00270 info->sigma_yaw = config.sigma_yaw;
00271 info->sigma_z = config.sigma_z;
00272 info->tf_frame_in = config.tf_frame_in;
00273 info->tf_frame_out = config.tf_frame_out;
00274 info->tf_pub_rate = config.tf_pub_rate;
00275 info->tf_ref_frame = config.tf_ref_frame;
00276
00277 info_pub_.publish(info);
00278 }
00279
00280 }
00281
00282 int main(int argc, char** argv)
00283 {
00284
00285 ros::init(argc, argv, "tf_distort");
00286
00287 tf_distort::TfDistort tfd;
00288
00289 ros::spin();
00290
00291 return 0;
00292 }
00293
00294