Hi,
I am running ecl/EKF with my own IMU and optical flow measurements. Let’s say the camera and IMU are mounted as follows
In this way, when the IMU moves forward/backward/right/left, we will have the following pixel changes
- IMU moves forward, dx=0, dy>0
- IMU moves backward, dx=0, dy<0
- IMU moves right, dx<0, dy=0
- IMU moves left, dx>0, dy=0
This can be illustrated by
Then by using the intrinsic camera parameters (obtained by camera calibration), we can convert the pixel flow into radius flow:
flow_x_radius = dx/fx
flow_y_radius = dy/fy
where fx,fy are the focal length in pixel unit.
My question is how to fit (flow_x_radius, flow_y_radius) into flowSample data structure defined in ecl/EKF common.h?
struct flowSample {
uint64_t fn{ 0 };
uint64_t time_us{0}; ///< timestamp of the integration period leading edge (uSec)
Vector2f flow_xy_rad; ///< measured delta angle of the image about the X and Y body axes (rad), RH rotation is positive
Vector3f gyro_xyz; ///< measured delta angle of the inertial frame about the body axes obtained from rate gyro measurements (rad), RH rotation is positive
float dt; ///< amount of integration time (sec)
uint8_t quality; ///< quality indicator between 0 and 255
};
“Measured delta angle of the image about the X and Y body axes (rad), RH rotation is positive” how to interpret this sentence?
My intuitive guess is
flow_xy_rad(0) = + flow_y_radius
flow_xy_rad(1) = - flow_x_radius
but it seems does not work.
Furthermore, when dig deeper, I found the following lines of key code
in control.cpp:
L0: _flow_compensated_XY_rad = _flow_sample_delayed.flow_xy_rad - _flow_sample_delayed.gyro_xyz.xy();
in optflow_fusion.cpp:
//my comments: from prediction side
L1: const Vector3f vel_rel_earth = _state.vel + _R_to_earth * vel_rel_imu_body;
L2: const Vector3f vel_body = earth_to_body * vel_rel_earth;
//my comments: from measurement side
const Vector2f opt_flow_rate = _flow_compensated_XY_rad / _flow_sample_delayed.dt +
Vector2f(_flow_gyro_bias);
L3: _flow_vel_body(0) = -opt_flow_rate(1) * range;
L4: _flow_vel_body(1) = opt_flow_rate(0) * range;
L5: _flow_vel_ne = Vector2f(_R_to_earth * Vector3f(_flow_vel_body(0), _flow_vel_body(1), 0.f));
//innovation
L6: _flow_innov(0) = vel_body(1) / range - opt_flow_rate(0); // flow around the X axis
L7: _flow_innov(1) = -vel_body(0) / range - opt_flow_rate(1); // flow around the Y axis
L3-L7 even bothered me more for the three reasons:
a) why it switches index between 0 and 1?
b) in KF, innovation is defined by
\tilt{y}k = z_k - H_k \hat{x}{k|k-1} // observation - predictedMeasurement
why at here it uses predictedMeasurement - observation?
c) In process-and-observation-model.pdf, it says
LOS_X = -V_Y/R, LOS_Y=V_X/R,
but the code dose not match it. Also by checking matlab code, I found that both c++ and matlab use the same way, then I assume there is a typo in the document.
Thanks for your help!