GazeStabilization.cc
Go to the documentation of this file.
1
3
4#include <cstdio>
5#include <iostream>
6
8//#include "mbs_sensor.h"
9#include "pinv.hh"
10
11#include <Eigen/Dense>
12
14
16{
17
18 this->options = options;
19
20 if (options->model == 0) // armar 4 WO torso
21 {
22 n_LB_joints = 6;
23 n_UB_joints = 7;
24 n_virt_joints = 3;
25 }
26 else if (options->model == 1) // armar 4 W torso
27 {
28 n_LB_joints = 8;
29 n_UB_joints = 7;
30 n_virt_joints = 3;
31 }
32 else if (options->model == 2) // armar 3
33 {
34 n_LB_joints = 10;
35 n_UB_joints = 5;
36 n_virt_joints = 3;
37 }
38
39 input = new GazeStabInput(n_LB_joints, n_UB_joints);
40 output = new GazeStabOutput(n_UB_joints);
41
42
43 mbs_data_virt_q.reserve(get_n_all_joints() + 1);
44 mbs_data_virt_qd.reserve(get_n_all_joints() + 1);
45 mbs_data_virt_qdd.reserve(get_n_all_joints() + 1);
46
47 optFlow_pred.resize(2);
48 gyroscopeRotation_pred.resize(3);
49}
50
51
53{
54 delete input;
55 delete output;
56 delete options;
57}
58
59
61{
62
63 printf("hello from GazeSatb init\n");
64
65 // create corresponding sensors
66 allocate_sensor(&sens_virt, get_n_all_joints());
67 init_sensor(&sens_virt, get_n_all_joints());
68
70 init_sensor(&sens_eye, get_n_real_joints());
71
72 allocate_sensor(&sens_head_imu, get_n_real_joints() - 2);
73 init_sensor(&sens_head_imu, get_n_real_joints() - 2);
74
75 qd_gaze_des = Eigen::VectorXd::Zero(get_n_gaze_joints());
76 q_UB_des = Eigen::VectorXd::Zero(n_UB_joints);
77
78 if ((options->model == 0) || (options->model == 1)) // armar4
79 {
80 q_UB_des(2) = M_PI; // = initial configuration
81
82 q_virt[0] = -1.9415;
83 q_virt[1] = 0.0;
84 q_virt[2] = 0.0;
85 }
86 else // armar 3
87 {
88 q_virt[0] = 1.18;
89 q_virt[1] = M_PI;
90 q_virt[2] = -M_PI / 2.;
91 }
92
93 //input->pos_target[0] = input->qd_LB[1] + 1; // 1m in front of the robot
94
95 // TODO use newton raphson to find the initial q_virt
96
97 vel_xFP = Eigen::VectorXd::Zero(6);
98 pos_xFP = Eigen::Vector3d::Zero();
99 desired_vel_xFP = Eigen::VectorXd::Zero(6);
100
101 Jac_IK.resize(6, get_n_gaze_joints());
102 Jac_FK.resize(6, get_n_all_joints());
103 inv_Jac.resize(get_n_gaze_joints(), 6);
104 null_space.resize(get_n_gaze_joints(), get_n_gaze_joints());
105
106 last_t_ctrl = 0.;
107
108}
109
111{
112
113 /************
114 * Get input
115 * *********/
116 double tsim = input->tsim;
117
118 /************
119 * Forward kinematics (FK)
120 * *********/
121
122 // copy lower body joints pos
123 for (int i = 1; i <= n_LB_joints; i++)
124 {
125 mbs_data_virt_q[i] = input->q_LB[i - 1];
126 mbs_data_virt_qd[i] = input->qd_LB[i - 1];
127 }
128
129 // copy head joints pos
130 for (int i = n_LB_joints + 1; i <= get_n_real_joints(); i++)
131 {
132 mbs_data_virt_q[i] = input->q_UB[i - (n_LB_joints + 1)];
133 mbs_data_virt_qd[i] = input->qd_UB[i - (n_LB_joints + 1)];
134 }
135
136 // copy virt joints pos
137 for (int i = get_n_real_joints() + 1; i <= get_n_all_joints(); i++)
138 {
139 mbs_data_virt_q[i] = q_virt[i - (get_n_real_joints() + 1)];
140 mbs_data_virt_qd[i] = qd_gaze_des(i - (n_LB_joints + 1));
141 }
142
143 if (options->model == 0) // Armar4 WO torso
144 {
145 mbs_sensor_ArmarIV_GazeStab_virt(&sens_virt, &mbs_data_virt_q[0], &mbs_data_virt_qd[0], &mbs_data_virt_qdd[0], 1);
146 }
147 else if (options->model == 1) // Armar4 W torso
148 {
149 mbs_sensor_ArmarIV_W_Torso_virt(&sens_virt, &mbs_data_virt_q[0], &mbs_data_virt_qd[0], &mbs_data_virt_qdd[0], 1);
150 }
151 else if (options->model == 2) // Armar3
152 {
153 mbs_sensor_ArmarIII_simplified_virt(&sens_virt, &mbs_data_virt_q[0], &mbs_data_virt_qd[0], 3); // virtual fixation point
154 }
155
156 predict_optFlow_xy();
157 predict_optFlow_index();
158 predict_IMU();
159
160 for (int row = 0; row < 6; row++)
161 for (int col = 0; col < get_n_all_joints(); col++)
162 {
163 Jac_FK(row, col) = sens_virt.J[row + 1][col + 1];
164 }
165
166 vel_xFP = Jac_FK.block(0, 0, 6, n_LB_joints) * input->qd_LB_des;
167
168 for (int i = 0; i < 3; i++)
169 {
170 pos_xFP(i) = sens_virt.P[i + 1];
171 }
172
173 for (int row = 0; row < 3; row++)
174 for (int col = 0; col < 3; col++)
175 {
176 R_xFP[row][col] = sens_virt.R[row + 1][col + 1];
177 }
178
179 pos_err = input->pos_target - pos_xFP;
180
181 // if (pos_err.norm() > 0.1)
182 // {
183 // ARMARX_IMPORTANT_S << "fixation point error large = " << pos_err(0) << " " << pos_err(1) << " " << pos_err(2) << " m";
184 // pos_err = 0.1 * pos_err / pos_err.norm();
185 // }
186
187 double K1 = 0.;//5.;//100;
188 double K2 = 0.;//2.;//40;
189 double K3 = 0.;//5.;//100; // null space
190 Eigen::VectorXd drift_corr(6);
191 drift_corr << K1* pos_err, 0, K2* get_or_err(), 0;
192
193 desired_vel_xFP = -1 * vel_xFP + drift_corr;
194
195 /************
196 * Inverse kinematics (IK)
197 * *********/
198
199 Jac_IK = Jac_FK.block(0, n_LB_joints, 6, get_n_gaze_joints());
200
201 if (options->weighted_inverse)
202 {
203 Eigen::VectorXd w(get_n_gaze_joints()); // weights
204
205 for (int i = 0; i < get_n_gaze_joints(); i++)
206 {
207 w(i) = 1.;
208 }
209
210 w(get_n_gaze_joints() - 3) = options->lambda * 19.13 / fabs(q_virt[0]); // zoom
211 w(get_n_gaze_joints() - 2) = options->lambda * 1.2054;
212 w(get_n_gaze_joints() - 1) = options->lambda * 2.1431;
213
214 //w(get_n_gaze_joints() - 4) = 8.; // minimize eye motion
215
216 inv_Jac = weightedPseudoInverse(Jac_IK, w);
217 }
218 else if (options->pseudo_inverse)
219 {
220 inv_Jac = pseudoInverse(Jac_IK);
221 }
222
223 // null space projection
224 null_space = Eigen::MatrixXd::Identity(get_n_gaze_joints(), get_n_gaze_joints()) - inv_Jac * Jac_IK;
225
226 Eigen::Map<Eigen::VectorXd> tmp(&input->q_UB[0], n_UB_joints);
227 Eigen::VectorXd null_space_err(get_n_gaze_joints());
228 null_space_err << K3*(q_UB_des - tmp), 0., 0., 0.; // 0 correction for virt joints
229
230 qd_gaze_des = inv_Jac * desired_vel_xFP + null_space * null_space_err;
231
232 //std::cout << "hello : " << Jac_IK*inv_Jac << std::endl;
233 //std::cout << "hello : " << Jac_FK.block(0,0,6,6)*qd_LB_des + Jac_IK*qd_gaze_des << std::endl;
234
235 /************
236 * Update q_virt
237 * *********/
238
239 double dt = tsim - last_t_ctrl;
240 if (dt > 0.1)
241 {
242 ARMARX_IMPORTANT_S << "gaze stab control perido too large = " << dt << " s";
243 dt = 0.;
244 }
245
246 for (int i = 0; i < n_virt_joints; i++)
247 {
248 q_virt[i] += dt * qd_gaze_des(i + n_UB_joints);
249 }
250
251 last_t_ctrl = tsim;
252
253 /************
254 * Write output
255 * *********/
256
257 for (int i = 0; i < n_UB_joints; i++)
258 {
259 output->qd_UB_des[i] = qd_gaze_des(i);
260 }
261
262 //ARMARX_LOG_S << pos_err;
263 //ARMARX_IMPORTANT_S << "hello" << input->qd_LB_des[7];
264 // for (int i = 0; i < 10; i++)
265 // {
266 // ARMARX_IMPORTANT_S << "input lower body velocity " << i << " " << input->qd_LB_des[i];
267 // }
268
269 // for (int i = 0; i < 5; i++)
270 // {
271 // ARMARX_IMPORTANT_S << "output upper body velocity " << i << " " << output->qd_UB_des[i];
272 // }
273}
274
276{
277
278 printf("hello from GazeSatb finish \n");
279
280 // free sensors
281 free_sensor(&sens_virt);
282 free_sensor(&sens_eye);
283 free_sensor(&sens_head_imu);
284
285}
286
287
288// predicotr part
289void GazeStabilization::predict_IMU()
290{
291 mbs_sensor_ArmarIII_simplified_virt(&sens_head_imu, &mbs_data_virt_q[0], &mbs_data_virt_qd[0], 1); //head IMU kin
292
293 gyroscopeRotation_pred[0] = -1 * (sens_head_imu.R[1][1] * sens_head_imu.OM[1] + sens_head_imu.R[2][1] * sens_head_imu.OM[2] + sens_head_imu.R[3][1] * sens_head_imu.OM[3]);
294 gyroscopeRotation_pred[2] = sens_head_imu.R[1][2] * sens_head_imu.OM[1] + sens_head_imu.R[2][2] * sens_head_imu.OM[2] + sens_head_imu.R[3][2] * sens_head_imu.OM[3];
295 gyroscopeRotation_pred[1] = sens_head_imu.R[1][3] * sens_head_imu.OM[1] + sens_head_imu.R[2][3] * sens_head_imu.OM[2] + sens_head_imu.R[3][3] * sens_head_imu.OM[3];
296}
297
298void GazeStabilization::predict_optFlow_xy()
299{
300 // TODO (use head orientation to select x and y optical flow axis)
301
302 //optFlow_pred[0] = atan2(sens_virt.V[2], q_virt[0]);
303 optFlow_pred[1] = -1 * atan2(sens_virt.V[3], q_virt[0]);
304}
305
306void GazeStabilization::predict_optFlow_index()
307{
308 double v_zoom; // zoom velocity [m/s]
309 double v_hor; // horizontal velocity [m/s]
310 double v_ver; // vertical velocity [m/s]
311 double v_tilt; // tilt rotational velocity [rad/s]
312 double v_yaw; // yaw rotational velocity [rad/s]
313 double v_roll; // roll rotational velocity [rad/s]
314
315 const double f = 529.9 * (59.7 / 640.); // focal length converted in deg (from camera calibration file)
316
317 mbs_sensor_ArmarIII_simplified_virt(&sens_eye, &mbs_data_virt_q[0], &mbs_data_virt_qd[0], 2); //eye kin
318
319 v_zoom = get_qdvirt(0);
320 v_tilt = get_qdvirt(1);
321 v_yaw = sens_eye.R[1][3] * sens_virt.OM[1] + sens_eye.R[2][3] * sens_virt.OM[2] + sens_eye.R[3][3] * sens_virt.OM[3]; //get_qdvirt(2);
322
323 v_hor = sens_eye.R[1][2] * sens_eye.V[1] + sens_eye.R[2][2] * sens_eye.V[2] + sens_eye.R[3][2] * sens_eye.V[3]; // vy in eye frame
324 v_ver = sens_eye.R[1][3] * sens_eye.V[1] + sens_eye.R[2][3] * sens_eye.V[2] + sens_eye.R[3][3] * sens_eye.V[3]; // vz in eye frame;
325 v_roll = sens_eye.R[1][1] * sens_eye.OM[1] + sens_eye.R[2][1] * sens_eye.OM[2] + sens_eye.R[3][1] * sens_eye.OM[3];
326
327 //double integral with X in [-15:15] deg and Y in [-11:11] deg for:
328 // computed with www.wolframalpha.com
329 double surf = 30.*22.;
330
331 // 1) zoom : sqrt(X^2 + Y^2)/ surf
332 double int_zoom = 6612.53 / surf;
333
334 // 2) tilt : sqrt((X*Y)^2 + Y^4) / (f * surf)
335 double int_tilt = 40359.9 / (f * surf);
336
337 // 3) yaw : sqrt((X*Y)^2 + X^4) / (f * surf)
338 double int_yaw = 58943.5 / (f * surf);
339
340 // 4) v_hor : constant f
341 double int_hor = f ;
342
343 // 5) v_ver : constant f
344 double int_ver = f;
345
346 // 6) roll : sqrt(X^2 + Y^2) / surf
347 double int_roll = 6612.53 / surf;
348
349
350 // mean distance of the optical flow [deg]
351 mean_optFl_pred = 0.;
352 mean_optFl_pred += int_zoom * fabs(v_zoom / q_virt[0]);
353 mean_optFl_pred += int_tilt * fabs(v_tilt);
354 mean_optFl_pred += int_yaw * fabs(v_yaw);
355 mean_optFl_pred += int_hor * fabs(v_hor / q_virt[0]);
356 mean_optFl_pred += int_ver * fabs(v_ver / q_virt[0]);
357 mean_optFl_pred += int_roll * fabs(v_roll);
358
359 double f_rad = f * M_PI / 180.0; // = 0.85
360 optFlow_pred[0] = (f_rad / q_virt[0]) * v_hor + f_rad * v_yaw;
361 optFlow_pred[0] = optFlow_pred[0] / 3.;
362
363}
364
365
#define M_PI
Definition MathTools.h:17
constexpr T dt
GazeStabOutput * output
GazeStabilization(GazeStabOptions *options)
double get_qdvirt(int i)
GazeStabInput * input
GazeStabOptions * options
#define ARMARX_IMPORTANT_S
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:210
void free_sensor(MbsSensor *psens)
Free the memory of MbsSensor structure.
Definition mbs_sensor.c:49
void allocate_sensor(MbsSensor *psens, int njoint)
Allocate the Jacobian matrix of the MbsSensor according to the number of joints in the multibody syst...
Definition mbs_sensor.c:14
void init_sensor(MbsSensor *psens, int njoint)
Initialize all fields of MbsSensor structure to 0.
Definition mbs_sensor.c:25
void mbs_sensor_ArmarIII_simplified_virt(MbsSensor *sens, double *q_dof, double *qd_dof, int isens)
void mbs_sensor_ArmarIV_GazeStab_virt(MbsSensor *sens, double *q, double *qd, double *qdd, int isens)
void mbs_sensor_ArmarIV_W_Torso_virt(MbsSensor *sens, double *q, double *qd, double *qdd, int isens)
Eigen::MatrixXd pseudoInverse(const Eigen::MatrixXd &a, double epsilon=std::numeric_limits< double >::epsilon())
Definition pinv.hh:6
Eigen::MatrixXd weightedPseudoInverse(const Eigen::MatrixXd &a, const Eigen::VectorXd w)
Definition pinv.hh:13
double OM[4]
Angular velocity vector of the sensor expressed in the inertial frame: .
Definition mbs_sensor2.h:28
double R[4][4]
Rotation matrix from the inertial frame to the sensor frame: .
Definition mbs_sensor2.h:24