MotionModel.cpp
Go to the documentation of this file.
1 // SVN $HeadURL$
2 // SVN $Id$
3 
4 /*
5  * 6D localization for humanoid robots
6  *
7  * Copyright 2009-2012 Armin Hornung, University of Freiburg
8  * http://www.ros.org/wiki/humanoid_localization
9  *
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, version 3.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 using namespace tf;
27 using namespace std;
28 
29 namespace humanoid_localization{
30 
31 MotionModel::MotionModel(ros::NodeHandle* nh, EngineT* rngEngine, tf::TransformListener* tf,
32  const std::string& odomFrameId, const std::string& baseFrameId)
33 : m_tfListener(tf),
34  m_rngNormal(*rngEngine, NormalDistributionT(0.0, 1.0)),
35  m_rngUniform(*rngEngine, UniformDistributionT(0.0, 1.0)),
36  m_odomFrameId(odomFrameId), m_baseFrameId(baseFrameId),
37  m_firstOdometryReceived(false)
38 
39 {
40 
41  // motion model noise parameters:
42  m_odomNoise2D = Eigen::Matrix3d::Zero();
43  // noise affecting x direction (sq. / variance)
44  nh->param("motion_noise/xx", m_odomNoise2D(0,0), 0.01);
45  nh->param("motion_noise/xy", m_odomNoise2D(0,1), 0.01);
46  nh->param("motion_noise/xt", m_odomNoise2D(0,2), 0.0001);
47  // noise affecting y direction (sq. / variance)
48  nh->param("motion_noise/yx", m_odomNoise2D(1,0), 0.01);
49  nh->param("motion_noise/yy", m_odomNoise2D(1,1), 0.01);
50  nh->param("motion_noise/yt", m_odomNoise2D(1,2), 0.0001);
51  // noise affecting orientation (sq. / variance)
52  nh->param("motion_noise/tx", m_odomNoise2D(2,0), 0.5);
53  nh->param("motion_noise/ty", m_odomNoise2D(2,1), 0.5);
54  nh->param("motion_noise/tt", m_odomNoise2D(2,2), 0.01);
55 
56  // std. devs for z, roll & pitch (depend on amount of transl.)
57  nh->param("motion_noise/z", m_odomNoiseZ, 0.01);
58  nh->param("motion_noise/roll", m_odomNoiseRoll, 0.05);
59  nh->param("motion_noise/pitch", m_odomNoisePitch, 0.1);
60 
61  // old parameters, warn that renamed:
62  if (nh->hasParam("motion_noise/x"))
63  ROS_WARN("Parameter motion_noise/x is no longer used, use variances motion_noise/[xx|xy|xt] instead");
64 
65  if (nh->hasParam("motion_noise/y"))
66  ROS_WARN("Parameter motion_noise/y is no longer used, use variances motion_noise/[yx|yy|yt] instead");
67 
68  if (nh->hasParam("motion_noise/yaw"))
69  ROS_WARN("Parameter motion_noise/yaw is no longer used, use variances motion_noise/[tx|ty|tt] instead");
70 
71  // odometry calibration (systematic drift correction)
72  m_odomCalibration2D = Eigen::Matrix3d::Identity();
73  nh->param("motion_calib/xx", m_odomCalibration2D(0,0), 1.0);
74  nh->param("motion_calib/xy", m_odomCalibration2D(0,1), 0.0);
75  nh->param("motion_calib/xt", m_odomCalibration2D(0,2), 0.0);
76  nh->param("motion_calib/yx", m_odomCalibration2D(1,0), 0.0);
77  nh->param("motion_calib/yy", m_odomCalibration2D(1,1), 1.0);
78  nh->param("motion_calib/yt", m_odomCalibration2D(1,2), 0.0);
79  nh->param("motion_calib/tx", m_odomCalibration2D(2,0), 0.0);
80  nh->param("motion_calib/ty", m_odomCalibration2D(2,1), 0.0);
81  nh->param("motion_calib/tt", m_odomCalibration2D(2,2), 1.0);
82 
83 
84  reset();
85 
86 }
87 
89 
90 }
91 
92 
94  // vectors (x,y,theta) in 2D for squared motion and variance
95  Eigen::Vector3d motion2D_sq, motion_variance;
96  double yaw = tf::getYaw(odomTransform.getRotation());
97  motion2D_sq(0) = odomTransform.getOrigin().x() * odomTransform.getOrigin().x();
98  motion2D_sq(1) = odomTransform.getOrigin().y() * odomTransform.getOrigin().y();
99  motion2D_sq(2) = yaw * yaw;
100 
101  motion_variance = m_odomNoise2D * motion2D_sq;
102 
103  // use std.normal dev as basis:
104  // X is normally distributed (mean 0, dev 1)
105  // => Y = aX + b is also normally distributed with mean b and deviation a
106 
107  // absolute amount of translation, used to scale noise in z, roll & pitch
108  // (about 1-2cm for each update step)
109  const double d = odomTransform.getOrigin().length();
111  m_rngNormal() * d * m_odomNoiseRoll, // roll
112  m_rngNormal() * d * m_odomNoisePitch, // pitch
113  m_rngNormal() * sqrt(motion_variance(2))),// yaw
114  tf::Vector3(
115  m_rngNormal() * sqrt(motion_variance(0)), // x
116  m_rngNormal() * sqrt(motion_variance(1)), // y
117  m_rngNormal() * d * m_odomNoiseZ)); // z
118 }
119 
121  m_firstOdometryReceived = false;
122 }
123 
124 void MotionModel::applyOdomTransform(tf::Pose& particlePose, const tf::Transform& odomTransform){
125  particlePose *= calibrateOdometry(odomTransform) * odomTransformNoise(odomTransform);
126 }
127 
128 void MotionModel::applyOdomTransform(Particles& particles, const tf::Transform& odomTransform){
129  const tf::Transform calibratedOdomTransform = calibrateOdometry(odomTransform);
130 
131  for (unsigned i=0; i < particles.size(); ++i){
132  particles[i].pose *= calibratedOdomTransform * odomTransformNoise(odomTransform);
133  }
134 }
135 
136 bool MotionModel::applyOdomTransformTemporal(Particles& particles,const ros::Time& t, double dt){
137  ros::WallTime startTime = ros::WallTime::now();
138 
139  // first see if default time is available
140  tf::Transform odomTransform;
141  if (!lookupOdomTransform(t, odomTransform))
142  return false;
143 
144  tf::Transform timeSampledTransform;
145  ros::Duration maxDuration;
146  if (dt > 0.0){
147  ros::Time maxTime;
148  std::string errorString;
150  maxDuration = maxTime - t;
151  }
152 
153  for (unsigned i=0; i < particles.size(); ++i){
154  if (dt > 0.0){
155  ros::Duration duration(m_rngUniform()*dt -dt/2.0);
156  // TODO: time t is time of first measurement in scan!
157  if (duration > maxDuration)
158  duration = maxDuration;
159 
160  if (lookupOdomTransform(t + duration, timeSampledTransform))
161  applyOdomTransform(particles[i].pose, timeSampledTransform);
162  else{
163  ROS_WARN("Could not lookup temporal odomTransform");
164  applyOdomTransform(particles[i].pose, odomTransform);
165  }
166  } else{
167  applyOdomTransform(particles[i].pose, odomTransform);
168  }
169  }
170 
171  double dwalltime = (ros::WallTime::now() - startTime).toSec();
172  ROS_INFO_STREAM("OdomTransformTemporal took " << dwalltime << "s ");
173 
174 
175  return true;
176 }
177 
179  Eigen::Vector3d odomPose2D;
180  double roll, pitch;
181  odomPose2D(0) = odomTransform.getOrigin().getX();
182  odomPose2D(1) = odomTransform.getOrigin().getY();
183  odomPose2D(2) = tf::getYaw(odomTransform.getRotation());
184  odomTransform.getBasis().getRPY(roll, pitch, odomPose2D(2));
185 
186  odomPose2D = m_odomCalibration2D * odomPose2D;
187 
188  return tf::Transform(tf::createQuaternionFromRPY(roll, pitch, odomPose2D(2)),
189  tf::Vector3(odomPose2D(0), odomPose2D(1), odomTransform.getOrigin().getZ()));
190 
191 
192 }
193 
194 bool MotionModel::lookupOdomTransform(const ros::Time& t, tf::Transform& odomTransform) const{
195  tf::Stamped<tf::Pose> odomPose;
196 
197  if (t <= m_lastOdomPose.stamp_){
198  ROS_WARN("Looking up OdomTransform that is %f ms older than the last odomPose!",
199  (m_lastOdomPose.stamp_ - t).toSec()/1000.0);
200  }
201 
202  if (!lookupOdomPose(t, odomPose))
203  return false;
204 
205  odomTransform = computeOdomTransform(odomPose);
206  return true;
207 }
208 
211  return m_lastOdomPose.inverse() * currentPose;
212  } else{
214  }
215 
216 }
217 
220  if (odomPose.stamp_ <= m_lastOdomPose.stamp_){
221  ROS_WARN("Trying to store an OdomPose that is older or equal than the current in the MotionModel, ignoring!");
222  } else {
223  m_lastOdomPose = odomPose;
224  }
225 
226 }
227 
228 
230 {
232  tf::Vector3(0,0,0)), t, m_baseFrameId);
233 
234  try
235  {
236  m_tfListener->transformPose(m_odomFrameId, ident, odomPose);
237  }
238  catch(tf::TransformException& e)
239  {
240  ROS_WARN("Failed to compute odom pose, skipping scan (%s)", e.what());
241  return false;
242  }
243 
244  return true;
245 }
246 
247 
248 bool MotionModel::lookupLocalTransform(const std::string& targetFrame, const ros::Time& t,
249  tf::StampedTransform& localTransform) const
250 {
251  try
252  {
253  m_tfListener->lookupTransform(targetFrame, m_baseFrameId, t, localTransform);
254  }
255  catch(tf::TransformException& e)
256  {
257  ROS_WARN("Failed to lookup local transform (%s)", e.what());
258  return false;
259  }
260 
261  return true;
262 }
263 
266  lastOdomPose = m_lastOdomPose;
267  return true;
268  } else{
269  return false;
270  }
271 
272 }
273 
274 }
275 
d
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
void storeOdomPose(const tf::Stamped< tf::Pose > &odomPose)
store odomPose as m_lastOdomPose to compute future odom transforms
tf::Transform odomTransformNoise(const tf::Transform &odomTransform)
Definition: MotionModel.cpp:93
double m_odomNoisePitch
std.dev param of noise in pitch (depending on distance traveled)
Definition: MotionModel.h:101
boost::uniform_real UniformDistributionT
bool lookupLocalTransform(const std::string &targetFrame, const ros::Time &t, tf::StampedTransform &localTransform) const
lookup the local target frame in the base frame (local transform)
boost::mt19937 EngineT
Boost RNG engine:
tf::TransformListener * m_tfListener
Definition: MotionModel.h:87
Eigen::Matrix3d m_odomCalibration2D
systematic calibration parameters for odometry drift
Definition: MotionModel.h:95
TFSIMD_FORCE_INLINE Matrix3x3 & getBasis()
double m_odomNoiseZ
std.dev param of noise in Z (depending on distance traveled)
Definition: MotionModel.h:97
static double getYaw(const Quaternion &bt_q)
int getLatestCommonTime(const std::string &source_frame, const std::string &target_frame, ros::Time &time, std::string *error_string) const
bool getLastOdomPose(tf::Stamped< tf::Pose > &lastOdomPose) const
bool lookupOdomPose(const ros::Time &t, tf::Stamped< tf::Pose > &odomPose) const
look up the odom pose at a certain time through tf
TFSIMD_FORCE_INLINE const tfScalar & getY() const
TFSIMD_FORCE_INLINE const tfScalar & getZ() const
#define ROS_WARN(...)
static tf::Quaternion createIdentityQuaternion()
Eigen::Matrix3d m_odomNoise2D
variance parameters for calibrated odometry noise
Definition: MotionModel.h:93
TFSIMD_FORCE_INLINE const tfScalar & x() const
boost::normal_distribution NormalDistributionT
Boost RNG distribution:
tf::Transform computeOdomTransform(const tf::Transform currentPose) const
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TFSIMD_FORCE_INLINE const tfScalar & y() const
tf::Transform calibrateOdometry(const tf::Transform &odomTransform) const
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
ros::Time stamp_
#define ROS_INFO_STREAM(args)
static WallTime now()
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
Quaternion getRotation() const
bool lookupOdomTransform(const ros::Time &t, tf::Transform &odomTransform) const
looks up the odometry pose at time t and then calls computeOdomTransform()
bool applyOdomTransformTemporal(Particles &particles, const ros::Time &t, double dt)
TFSIMD_FORCE_INLINE const tfScalar & getX() const
bool hasParam(const std::string &key) const
std::vector< Particle > Particles
double m_odomNoiseRoll
std.dev param of noise in roll (depending on distance traveled)
Definition: MotionModel.h:99
void applyOdomTransform(Particles &particles, const tf::Transform &odomTransform)
apply odomTransform to all particles (with random noise and calibration)
tf::Stamped< tf::Pose > m_lastOdomPose
Definition: MotionModel.h:109
TFSIMD_FORCE_INLINE tfScalar length() const


humanoid_localization
Author(s): Armin Hornung, Stefan Osswald, Daniel Maier
autogenerated on Mon Jun 10 2019 13:38:31