1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 | /*
* Copyright 2022-2024 Riccardo Monica
*
* This software is distributed under the 3-clause BSD license.
* You should have received a copy of the 3-clause BSD license
* along with this software. If not, see
* <https://opensource.org/license/bsd-3-clause>
*/
#include "kalman_tracking_constrained.h"
#include "ekf_pose3_tracker.h"
#define PI 3.14159265359f
template <typename T>
T SQR(const T & t) {return t * t; }
namespace Tracking
{
static ekfpt::EkfPose3Tracker::SE3 EigenToSE3(const Eigen::Affine3f & m)
{
Eigen::Matrix4d matr = m.cast<double>().matrix();
Eigen::Isometry3d transfEigen;
transfEigen = matr;
return transfEigen;
}
static Eigen::Affine3f SE3ToEigen(const ekfpt::EkfPose3Tracker::SE3 & se3)
{
Eigen::Affine3f result;
result.matrix() = se3.isometry().matrix().cast<float>();
return result;
}
bool ConstrainedKalmanTracking::SetParameter(const int parameter_id, const float value)
{
switch (parameter_id)
{
case PARAM_SIGMA_ROT:
case PARAM_SIGMA_TRANSL:
case PARAM_PSIGMA_TRANSL:
case PARAM_PSIGMA_ROT:
case PARAM_ISIGMA_TRANSL:
case PARAM_ISIGMA_ROT:
case PARAM_ROTATION_LIMIT:
case PARAM_ROTATION_DYN_LIMIT:
case PARAM_TRANSLATION_DYN_LIMIT:
case PARAM_TRANSLATION_LIMIT:
case PARAM_ROTATION_CURV_LIMIT:
return ITracking::SetParameter(parameter_id, value);
default:
return false;
}
}
ConstrainedKalmanTracking::ConstrainedKalmanTracking()
{
m_ekf_pose3_tracker.reset(new ekfpt::EkfPose3Tracker);
SetParameter(PARAM_SIGMA_ROT, 1.0f / 180.0f * PI);
SetParameter(PARAM_SIGMA_TRANSL, 0.05f);
SetParameter(PARAM_PSIGMA_ROT, 0.1f / 180.0f * PI);
SetParameter(PARAM_PSIGMA_TRANSL, 0.01f);
SetParameter(PARAM_ISIGMA_ROT, 0.01f);
SetParameter(PARAM_ISIGMA_TRANSL, 0.1f);
SetParameter(PARAM_ROTATION_LIMIT, 0.01f);
SetParameter(PARAM_ROTATION_DYN_LIMIT, 0.05f);
SetParameter(PARAM_ROTATION_CURV_LIMIT, 10.0f); // degrees / meter
SetParameter(PARAM_TRANSLATION_DYN_LIMIT, 0.05f);
SetParameter(PARAM_TRANSLATION_LIMIT, 0.0001f);
Reset();
}
void ConstrainedKalmanTracking::Reset(const Eigen::Affine3f & initial_world_to_oculus,
const Eigen::Affine3f & initial_oculus_origin_to_oculus)
{
prev_world_to_motive = initial_world_to_oculus;
prev_oculus_origin_to_oculus_mat = initial_oculus_origin_to_oculus;
pred_oculus_mat = initial_world_to_oculus;
ekfpt::EkfPose3Tracker & tracker = *m_ekf_pose3_tracker;
ekfpt::EkfPose3Tracker::SE3 stateMean = EigenToSE3(initial_world_to_oculus);
const double sigma_transl = SQR(m_params[PARAM_ISIGMA_TRANSL]);
const double sigma_rot = SQR(m_params[PARAM_ISIGMA_ROT]);
ekfpt::EkfPose3Tracker::Vector6 stdevInit;
stdevInit << sigma_transl, sigma_transl, sigma_transl, sigma_rot, sigma_rot, sigma_rot;
const ekfpt::EkfPose3Tracker::Matrix6 covarInit = stdevInit.asDiagonal();
tracker.initState(stateMean, covarInit);
position_state = STATE_INIT;
rotation_state = STATE_INIT;
}
void ConstrainedKalmanTracking::Update(const Eigen::Affine3f & world_to_motive_mat,
const Eigen::Affine3f & oculus_origin_to_oculus_mat)
{
ekfpt::EkfPose3Tracker & tracker = *m_ekf_pose3_tracker;
if (prev_world_to_motive.linear() == Eigen::Matrix3f::Zero())
{
Reset(world_to_motive_mat, oculus_origin_to_oculus_mat);
position_state = STATE_INIT;
rotation_state = STATE_INIT;
return;
}
is_motive_lost = (world_to_motive_mat.linear() == prev_world_to_motive.linear()) &&
(world_to_motive_mat.translation() == prev_world_to_motive.translation());
ekfpt::EkfPose3Tracker::Vector6 stdevOdom;
const double psigma_transl = SQR(m_params[PARAM_PSIGMA_TRANSL]);
const double psigma_rot = SQR(m_params[PARAM_PSIGMA_ROT]);
stdevOdom << psigma_transl, psigma_transl, psigma_transl, psigma_rot, psigma_rot, psigma_rot;
ekfpt::EkfPose3Tracker::Matrix6 covarOdom = stdevOdom.asDiagonal();
const Eigen::Affine3f oculus_diff = prev_oculus_origin_to_oculus_mat.inverse() * oculus_origin_to_oculus_mat;
const ekfpt::EkfPose3Tracker::SE3 diffOdom = EigenToSE3(oculus_diff);
tracker.updatePrediction(diffOdom, covarOdom);
if (!is_motive_lost)
{
pred_oculus_mat = SE3ToEigen(tracker.getMean());
const float distance = DistanceInMeters(world_to_motive_mat, pred_oculus_mat);
const float angle = DistanceInDegrees(world_to_motive_mat, pred_oculus_mat);
if (distance > 0.5f || angle > 30.0f)
{
// error too large, reinit
ekfpt::EkfPose3Tracker::SE3 stateMean = EigenToSE3(world_to_motive_mat);
const double sigma_transl = SQR(m_params[PARAM_ISIGMA_TRANSL]);
const double sigma_rot = SQR(m_params[PARAM_ISIGMA_ROT]);
ekfpt::EkfPose3Tracker::Vector6 stdevInit;
stdevInit << sigma_transl, sigma_transl, sigma_transl, sigma_rot, sigma_rot, sigma_rot;
const ekfpt::EkfPose3Tracker::Matrix6 covarInit = stdevInit.asDiagonal();
tracker.initState(stateMean, covarInit);
position_state = STATE_REPOSITION;
rotation_state = STATE_REPOSITION;
}
else
{
const double sigma_transl = SQR(m_params[PARAM_SIGMA_TRANSL]);
const double sigma_rot = SQR(m_params[PARAM_SIGMA_ROT]);
const float oculus_dist_diff = DistanceInMeters(oculus_origin_to_oculus_mat, prev_oculus_origin_to_oculus_mat);
const float oculus_angle_diff = DistanceInDegrees(oculus_origin_to_oculus_mat, prev_oculus_origin_to_oculus_mat);
const float rotation_limit = m_params[PARAM_ROTATION_LIMIT] +
m_params[PARAM_ROTATION_DYN_LIMIT] * oculus_angle_diff +
m_params[PARAM_ROTATION_CURV_LIMIT] * oculus_dist_diff;
const float translation_limit = m_params[PARAM_TRANSLATION_LIMIT] +
m_params[PARAM_TRANSLATION_DYN_LIMIT] * oculus_dist_diff;
ekfpt::EkfPose3Tracker::Vector6 stdevMeas;
stdevMeas << sigma_transl, sigma_transl, sigma_transl, sigma_rot, sigma_rot, sigma_rot;
ekfpt::EkfPose3Tracker::Matrix6 covarMeas = stdevMeas.asDiagonal();
ekfpt::EkfPose3Tracker::SE3 transfMeas = EigenToSE3(world_to_motive_mat);
tracker.updateCorrectionWithLimit(transfMeas, covarMeas, translation_limit, rotation_limit / PI * 180.0f);
position_state = STATE_SMALL_DIFF;
rotation_state = STATE_SMALL_DIFF;
}
}
else
{
position_state = STATE_SMALL_DIFF;
rotation_state = STATE_SMALL_DIFF;
}
pred_oculus_mat = SE3ToEigen(tracker.getMean());
prev_world_to_motive = world_to_motive_mat;
prev_oculus_origin_to_oculus_mat = oculus_origin_to_oculus_mat;
}
}
|