Skip to content

Commit c848559

Browse files
author
Enrique Fernandez
committed
Compute twist on odom publish event
1 parent 0195d74 commit c848559

File tree

3 files changed

+95
-61
lines changed

3 files changed

+95
-61
lines changed

diff_drive_controller/include/diff_drive_controller/odometry.h

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ namespace diff_drive_controller
134134
bool updateOpenLoop(const double linear, const double angular,
135135
const ros::Time &time);
136136

137+
/**
138+
* \brief Update the odometry twist with the (internal) incremental pose,
139+
* since the last update/call to this method; this resets the (internal)
140+
* incremental pose
141+
* \param[in] time Current time, used to compute the time step/increment,
142+
* which is used to divide the (internal) incremental pose
143+
* by dt and obtain the twist
144+
* \return true if twist is actually updated; it won't be updated if the
145+
* time step/increment is very small, to avoid division by zero
146+
*/
147+
bool updateTwist(const ros::Time& time);
148+
137149
/**
138150
* \brief Heading getter
139151
* \return Heading [rad]
@@ -276,17 +288,12 @@ namespace diff_drive_controller
276288
const double v_l, const double v_r, const ros::Time& time);
277289

278290
/**
279-
* \brief Update the odometry twist with the previous and current odometry
280-
* pose
281-
* \param[in] p0 Previous odometry pose
282-
* \param[in] p1 Current odometry pose
283-
* \param[in] v_l Left wheel velocity [rad/s]
284-
* \param[in] v_r Right wheel velocity [rad/s]
285-
* \param[in] time Current time
286-
* \return true if the odometry twist is actually updated
291+
* \brief Updates the (internal) incremental odometry with latest left and
292+
* right wheel position increments
293+
* \param[in] dp_l Left wheel position increment [rad]
294+
* \param[in] dp_r Right wheel position increment [rad]
287295
*/
288-
bool updateTwist(const SE2& p0, const SE2& p1,
289-
const double v_l, const double v_r, const ros::Time& time);
296+
void updateIncrementalPose(const double dp_l, const double dp_r);
290297

291298
/**
292299
* \brief Update the measurement covariance
@@ -303,19 +310,31 @@ namespace diff_drive_controller
303310
/// Current timestamp:
304311
ros::Time timestamp_;
305312

313+
/// Timestamp for last twist computed, ie. since when the (internal)
314+
/// incremental pose has been computed:
315+
ros::Time timestamp_twist_;
316+
306317
/// Current pose:
307318
double x_; // [m]
308319
double y_; // [m]
309320
double heading_; // [rad]
310321

322+
/// Current incremental pose:
323+
double d_x_; // [m]
324+
double d_y_; // [m]
325+
double d_yaw_; // [rad]
326+
311327
/// Current velocity:
312-
double v_x_; // [m/s]
313-
double v_y_; // [m/s]
314-
double v_yaw_; // [rad/s]
328+
double v_x_; // [m/s]
329+
double v_y_; // [m/s]
330+
double v_yaw_; // [rad/s]
315331

316332
/// Pose covariance:
317333
PoseCovariance pose_covariance_;
318334

335+
/// Incremental Pose covariance:
336+
PoseCovariance incremental_pose_covariance_;
337+
319338
/// Twist (and minimum twist) covariance:
320339
TwistCovariance twist_covariance_;
321340
TwistCovariance minimum_twist_covariance_;

diff_drive_controller/src/diff_drive_controller.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,10 +612,19 @@ namespace diff_drive_controller
612612
}
613613

614614
// Publish odometry message:
615+
bool twist_updated_ = false;
616+
615617
const ros::Duration half_period(0.5 * control_period);
616618
if (last_odom_publish_time_ + publish_period_ < time + half_period &&
617619
odom_pub_->trylock())
618620
{
621+
// Update twist:
622+
// Note that the twist must be computed at the same frequency that it gets
623+
// published, because otherwise the code that uses it cannot apply the
624+
// same period it was used to compute it.
625+
odometry_.updateTwist(time);
626+
twist_updated_ = true;
627+
619628
last_odom_publish_time_ = time;
620629

621630
// Populate odom message and publish:
@@ -642,6 +651,12 @@ namespace diff_drive_controller
642651
last_odom_tf_publish_time_ + publish_period_ < time + half_period &&
643652
tf_odom_pub_->trylock())
644653
{
654+
// Note that the tf odometry doesn't need the twist, only the pose.
655+
// In the current implementation the pose is computed on its own, ie. w/o
656+
// using the (internal) incremental pose. Therefore, it's always up to
657+
// date with every control cycle and can be published at any rate because
658+
// it doesn't depend on any period.
659+
645660
last_odom_tf_publish_time_ = time;
646661

647662
// Populate tf odometry frame message and publish:

diff_drive_controller/src/odometry.cpp

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,16 @@ namespace diff_drive_controller
5858

5959
Odometry::Odometry(size_t velocity_rolling_window_size)
6060
: timestamp_(0.0)
61+
, timestamp_twist_(0.0)
6162
, x_(0.0)
6263
, y_(0.0)
6364
, heading_(0.0)
6465
, v_x_(0.0)
6566
, v_y_(0.0)
6667
, v_yaw_(0.0)
68+
, d_x_(0.0)
69+
, d_y_(0.0)
70+
, d_yaw_(0.0)
6771
, wheel_separation_(0.0)
6872
, left_wheel_radius_(0.0)
6973
, right_wheel_radius_(0.0)
@@ -86,19 +90,19 @@ namespace diff_drive_controller
8690
minimum_twist_covariance_.setIdentity();
8791
minimum_twist_covariance_ *= DEFAULT_MINIMUM_TWIST_COVARIANCE;
8892

89-
// There's no need to initialize the twist covariance because it's updated
90-
// from scratch on each cycle, but it's safer to initialize it anyway:
9193
twist_covariance_ = minimum_twist_covariance_;
9294

9395
pose_covariance_.setIdentity();
9496
pose_covariance_ *= DEFAULT_POSE_COVARIANCE;
97+
98+
incremental_pose_covariance_.setZero();
9599
}
96100

97101
void Odometry::init(const ros::Time& time)
98102
{
99103
// Reset accumulators and timestamp:
100104
resetAccumulators();
101-
timestamp_ = time;
105+
timestamp_ = timestamp_twist_ = time;
102106
}
103107

104108
bool Odometry::updateCloseLoop(
@@ -138,6 +142,7 @@ namespace diff_drive_controller
138142

139143
/// Compute time step:
140144
const double dt = (time - timestamp_).toSec();
145+
timestamp_ = time;
141146

142147
/// Update pose and twist:
143148
return update(v_l * dt, v_r * dt, v_l, v_r, time);
@@ -166,72 +171,67 @@ namespace diff_drive_controller
166171
/// Safe new state:
167172
const SE2 p1(SE2::Scalar(heading_), SE2::Point(x_, y_));
168173

169-
/// Update twist:
170-
return updateTwist(p0, p1, v_l, v_r, time);
174+
/// Update incremental pose:
175+
// @todo in principle there's no need to use v_l, v_r at all!
176+
//updateIncrementalPose(v_l * dt, v_r * dt);
177+
updateIncrementalPose(dp_l, dp_r);
178+
179+
return true;
171180
}
172181

173-
bool Odometry::updateTwist(const SE2& p0, const SE2& p1,
174-
double v_l, double v_r, const ros::Time& time)
182+
void Odometry::updateIncrementalPose(
183+
const double dp_l, const double dp_r)
175184
{
176-
/// We cannot estimate the speed with very small time intervals:
177-
const double dt = (time - timestamp_).toSec();
178-
if (dt < 0.0001)
179-
return false;
185+
/// Integrate incremental odometry pose:
186+
IntegrateFunction::PoseJacobian J_pose;
187+
IntegrateFunction::MeasJacobian J_meas;
188+
(*integrate_fun_)(d_x_, d_y_, d_yaw_, dp_l, dp_r, J_pose, J_meas);
180189

181-
timestamp_ = time;
190+
/// Update Measurement Covariance with the wheel joint position increments:
191+
updateMeasCovariance(dp_l, dp_r);
182192

183-
/// Compute relative transformation:
184-
const SE2 p = p0.inverse() * p1;
193+
/// Update incremental pose covariance:
194+
incremental_pose_covariance_ =
195+
J_pose * incremental_pose_covariance_ * J_pose.transpose() +
196+
J_meas * meas_covariance_ * J_meas.transpose();
197+
}
185198

186-
/// Retrieve rotation and translation:
187-
/// Note that we don't use the log from SE(2) because we didn't use exp
188-
/// to create p0 and p1.
189-
/// So instead of:
190-
///
191-
/// const SE2::Tangent v = p.log();
192-
///
193-
/// we use the following:
194-
const SE2::ConstTranslationReference t = p.translation();
199+
bool Odometry::updateTwist(const ros::Time& time)
200+
{
201+
/// We cannot estimate the speed with very small time intervals:
202+
const double dt = (time - timestamp_twist_).toSec();
203+
if (dt < 0.0001)
204+
{
205+
return false;
206+
}
195207

196-
v_x_ = t[0];
197-
v_y_ = t[1];
198-
v_yaw_ = p.so2().log();
208+
timestamp_twist_ = time;
199209

200210
/// Estimate speeds using a rolling mean to filter them out:
201-
v_x_acc_(v_x_/dt);
202-
v_y_acc_(v_y_/dt);
203-
v_yaw_acc_(v_yaw_/dt);
211+
const double f = 1.0 / dt;
212+
213+
v_x_acc_(d_x_ * f);
214+
v_y_acc_(d_y_ * f);
215+
v_yaw_acc_(d_yaw_ * f);
204216

205217
v_x_ = bacc::rolling_mean(v_x_acc_);
206218
v_y_ = bacc::rolling_mean(v_y_acc_);
207219
v_yaw_ = bacc::rolling_mean(v_yaw_acc_);
208220

209-
/// Integrate odometry twist:
210-
/// Note that this is done this way because it isn't trivial to compute the
211-
/// Jacobians for the relative transformation between p0 and p1
212-
const double dp_l = v_l * dt;
213-
const double dp_r = v_r * dt;
214-
215-
IntegrateFunction::PoseJacobian J_dummy;
216-
IntegrateFunction::MeasJacobian J_meas;
217-
double x = 0.0, y = 0.0, yaw = 0.0;
218-
(*integrate_fun_)(x, y, yaw, dp_l, dp_r, J_dummy, J_meas);
219-
220-
/// Include the Jacobian of dividing by dt, which is equivalent to divide
221-
/// all the elements of the other Jacobian by dt:
222-
J_meas /= dt;
223-
224-
/// Update Measurement Covariance with the wheel joint velocites:
225-
updateMeasCovariance(dp_l, dp_r);
226-
227221
/// Update twist covariance:
228-
twist_covariance_ = J_meas * meas_covariance_ * J_meas.transpose();
222+
IntegrateFunction::PoseJacobian J_twist =
223+
IntegrateFunction::PoseJacobian::Identity() * f;
224+
twist_covariance_ = J_twist * incremental_pose_covariance_ * J_twist.transpose();
229225

230226
/// Add minimum (diagonal) covariance to avoid ill-conditioned covariance
231227
/// matrices, i.e. with a very large condition number, which would make
232228
/// inverse or Cholesky decomposition fail on many algorithms:
233229
twist_covariance_ += minimum_twist_covariance_;
234230

231+
/// Reset incremental pose and its covariance:
232+
d_x_ = d_y_ = d_yaw_ = 0.0;
233+
incremental_pose_covariance_.setZero();
234+
235235
return true;
236236
}
237237

0 commit comments

Comments
 (0)