0

阿木币

2

精华

76 小时

在线时间

老司机

Rank: 2

发表于 2020-8-4 18:30:35 6067 浏览 6 回复

[导航算法] EKF2_AID_MASK中的rotate external vision是什么意思?

本帖最后由 wilsonleong 于 2021-6-4 20:03 编辑

原问题:
EKF2_AID_MASK中的rotate external vision是什么意思?是PX4会自动校准相机和机体坐标系之间的旋转矩阵么?


2021.6.4更新:
过了很久,再来思考这个问题。
wiki明确表明这两个mask flag是互斥的,而且必须开启其中一个:Either bit 4 (EV_YAW) or bit 6 (EV_ROTATE) should be set to true, but not both together.先看MASK_ROTATE_EV的描述:set to true if the EV observations are in a non NED reference frame and need to be rotated before being used

基于此:
1.如果只开MASK_ROTATE_EV,关闭MASK_USE_EVYAW,那么EKF2中YAW的来源只能是Magnetometer或者GPS,他们都是NED坐标系的,而外部SLAM或者MoCap的数据是FRD的,所以FRD系的数据是要旋转到NED的。
2.如果只开MASK_USE_EVYAW,关闭MASK_ROTATE_EV,意思就是使用外部SLAM或者MoCap的FRD坐标系来确定YAW,不用Magnetometer或者GPS的NED了,所以也不需要旋转FRD的数据了。

总结一下,想用外部视觉,又想保持NED坐标系,那只能放弃外部视觉的YAW,转而使用Magnetometer或者GPS来估计YAW,这时候开启MASK_ROTATE_EV。反之,不需要保持着NED的YAW指向的话,那直接用外部视觉的YAW就好,这时候开MASK_USE_EVYAW。
简单说:
1. Heading w.r.t. North  -->  MASK_ROTATE_EV
2. Heading w.r.t. external vision frame  -->  MASK_USE_EVYAW

欢迎指正!
AmovlabQYP已获得悬赏 10 阿木币

最佳答案

首先看一下EKF2_AID_MASK的定义,rotate external vision的定义为set to true if the EV observations are in a non NED reference frame and need to be rotated before being used。 /** * Integer bitmask contr ...

扫一扫浏览分享
回复

使用道具 举报

188

阿木币

3

精华

71 小时

在线时间

技术大V

Rank: 4

发表于 2020-8-5 09:48:14
AmovlabQYP 发表于 2020-8-5 09:46
首先看一下EKF2_AID_MASK的定义,rotate external vision的定义为set to true if the EV observations are  ...

粘贴代码不是很熟练,编辑的很丑,凑活看吧,建议去搜一下源码就知道了,没人用过的东西基本都只能相信源码和相信真实的测试结果。
回复 点赞 1

使用道具 举报

144

阿木币

0

精华

143 小时

在线时间

技术大V

Rank: 4

发表于 2020-8-5 08:28:54
不懂帮顶!阿木币好多,土豪!好想回答啊,就是问题太难了。。。   
回复 点赞

使用道具 举报

139

阿木币

0

精华

287 小时

在线时间

管理员

Rank: 9Rank: 9Rank: 9

发表于 2020-8-5 09:38:21
视觉传感器提供航向信息的意思,一般视觉SLAM和激光SLAM 算法也可以替代磁罗盘提供航向信息
我不为己,谁人为我,但我只为己,那我又是谁?
回复 点赞

使用道具 举报

188

阿木币

3

精华

71 小时

在线时间

技术大V

Rank: 4

发表于 2020-8-5 09:46:09
本帖最后由 AmovlabQYP 于 2020-8-5 09:47 编辑

首先看一下EKF2_AID_MASK的定义,rotate external vision的定义为set to true if the EV observations are in a non NED reference frame and need to be rotated before being used。
/**
* Integer bitmask controlling data fusion and aiding methods.
*
* Set bits in the following positions to enable:
* 0 : Set to true to use GPS data if available
* 1 : Set to true to use optical flow data if available
* 2 : Set to true to inhibit IMU delta velocity bias estimation
* 3 : Set to true to enable vision position fusion
* 4 : Set to true to enable vision yaw fusion. Cannot be used if bit position 7 is true.
* 5 : Set to true to enable multi-rotor drag specific force fusion
* 6 : set to true if the EV observations are in a non NED reference frame and need to be rotated before being used
* 7 : Set to true to enable GPS yaw fusion. Cannot be used if bit position 4 is true.
*
* @group EKF2
* @min 0
* @max 511
* @bit 0 use GPS
* @bit 1 use optical flow
* @bit 2 inhibit IMU bias estimation
* @bit 3 vision position fusion
* @bit 4 vision yaw fusion
* @bit 5 multi-rotor drag fusion
* @bit 6 rotate external vision
* @bit 7 GPS yaw fusion
* @bit 8 vision velocity fusion
* @reboot_required true
*/
PARAM_DEFINE_INT32(EKF2_AID_MASK, 1);
找一下相关源码,可以看到官方的注释也是说需要计算这个转换矩阵,重点就在于看看calcExtVisRotMat();这个函数到底做了什么事情。
                // if the ev data is not in a NED reference frame, then the transformation between EV and EKF navigation frames
                // needs to be calculated and the observations rotated into the EKF frame of reference
                if ((_params.fusion_mode & MASK_ROTATE_EV) && ((_params.fusion_mode & MASK_USE_EVPOS) || (_params.fusion_mode & MASK_USE_EVVEL)) && !_control_status.flags.ev_yaw) {
                        // rotate EV measurements into the EKF Navigation frame
                        calcExtVisRotMat();
                }



来看看这个函数到底干了什么,加粗那句是重点

// update the estimated misalignment between the EV navigation frame and the EKF navigation frame
// and calculate a rotation matrix which rotates EV measurements into the EKF's navigation frame
void Ekf::calcExtVisRotMat()
{
        // Calculate the quaternion delta that rotates from the EV to the EKF reference frame at the EKF fusion time horizon.
        Quatf q_error = _state.quat_nominal * _ev_sample_delayed.quat.inversed();
        q_error.normalize();

        // convert to a delta angle and apply a spike and low pass filter
        Vector3f rot_vec = q_error.to_axis_angle();

        float rot_vec_norm = rot_vec.norm();

        if (rot_vec_norm > 1e-6f) {

                // apply an input limiter to protect from spikes
                Vector3f _input_delta_vec = rot_vec - _ev_rot_vec_filt;
                float input_delta_len = _input_delta_vec.norm();

                if (input_delta_len > 0.1f) {
                        rot_vec = _ev_rot_vec_filt + _input_delta_vec * (0.1f / input_delta_len);
                }

                // Apply a first order IIR low pass filter
                const float omega_lpf_us = 0.2e-6f; // cutoff frequency in rad/uSec
                float alpha = math::constrain(omega_lpf_us * (float)(_time_last_imu - _ev_rot_last_time_us), 0.0f, 1.0f);
                _ev_rot_last_time_us = _time_last_imu;
                _ev_rot_vec_filt = _ev_rot_vec_filt * (1.0f - alpha) + rot_vec * alpha;

        }

        // convert filtered vector to a quaternion and then to a rotation matrix
        q_error.from_axis_angle(_ev_rot_vec_filt);
        _ev_rot_mat = quat_to_invrotmat(q_error); // rotation from EV reference to EKF reference

}


所以应该是,PX4会自动校准相机和机体坐标系之间的旋转矩阵。

但是,一般这个标志位我们不会用这个参数,所以不确定是否真的有用。
一般会把相机和无人机都水平放置,保证在一个平面内,然后选择@bit 3 vision position fusion和@bit 4 vision yaw fusion,即设置为24.这样我们就遵循相机的yaw角即可,就不是真正意义的NED坐标系了。


回复 点赞

使用道具 举报

0

阿木币

2

精华

76 小时

在线时间

老司机

Rank: 2

 楼主| 发表于 2020-8-12 11:24:26
if ((_params.fusion_mode & MASK_ROTATE_EV) && ((_params.fusion_mode & MASK_USE_EVPOS) || (_params.fusion_mode & MASK_USE_EVVEL)) && !_control_status.flags.ev_yaw) {
    // rotate EV measurements into the EKF Navigation frame
    calcExtVisRotMat();
}
// update the rotation matrix which rotates EV measurements into the EKF's navigation frame
void Ekf::calcExtVisRotMat()
{
    // Calculate the quaternion delta that rotates from the EV to the EKF reference frame at the EKF fusion time horizon.
    const Quatf q_error((_state.quat_nominal * _ev_sample_delayed.quat.inversed()).normalized());
    _R_ev_to_ekf = Dcmf(q_error);
}
回复 点赞

使用道具 举报

0

阿木币

2

精华

76 小时

在线时间

老司机

Rank: 2

 楼主| 发表于 2020-8-12 11:34:07

本帖最后由 wilsonleong 于 2020-8-13 10:30 编辑

如果 MASK_ROTATE_EV 和 MASK_USE_EVYAW 同时启用,EKF2只会算校准一次外部视觉的旋转矩阵,后面就不再校准了。具体是,程序是否进行外部视觉旋转矩阵校准是检查 _control_status.flags.ev_yaw 而不是 MASK_USE_EVYAW,所以刚开始 _control_status.flags.ev_yaw 为 false,程序进行了一次校准。到后面 MASK_USE_EVYAW 把 _control_status.flags.ev_yaw 设置为 true,就不再进行校准了。

EKF\control.cpp (1.10)

void Ekf::controlExternalVisionFusion()
{
    // Check for new external vision data
    if (_ev_data_ready) {

        // if the ev data is not in a NED reference frame, then the transformation between EV and EKF navigation frames
        // needs to be calculated and the observations rotated into the EKF frame of reference
        if ((_params.fusion_mode & MASK_ROTATE_EV) && ((_params.fusion_mode & MASK_USE_EVPOS) || (_params.fusion_mode & MASK_USE_EVVEL)) && !_control_status.flags.ev_yaw) {
            // rotate EV measurements into the EKF Navigation frame
            calcExtVisRotMat();
        }

        // external vision aiding selection logic
        if (_control_status.flags.tilt_align && _control_status.flags.yaw_align) {

                /* ...... */

                if ((_params.fusion_mode & MASK_ROTATE_EV) && !(_params.fusion_mode & MASK_USE_EVYAW)
                    && !_ev_rot_mat_initialised)  {
                    // Reset transformation between EV and EKF navigation frames when starting fusion
                    resetExtVisRotMat();
                    _ev_rot_mat_initialised = true;
                    ECL_INFO_TIMESTAMPED("EKF external vision aligned");
                }
            }
        }

        // external vision yaw aiding selection logic
        if (!_control_status.flags.gps && (_params.fusion_mode & MASK_USE_EVYAW) && !_control_status.flags.ev_yaw && _control_status.flags.tilt_align) {
            // don't start using EV data unless daa is arriving frequently
            if (_time_last_imu - _time_last_ext_vision < 2 * EV_MAX_INTERVAL) {

                /* ...... */

                // turn on fusion of external vision yaw measurements and disable all magnetometer fusion
                _control_status.flags.ev_yaw = true;
                _control_status.flags.mag_hdg = false;
                _control_status.flags.mag_dec = false;

                /* ...... */
            }
        }

        /* ...... */

        // determine if we should use the yaw observation
        if (_control_status.flags.ev_yaw) {
            fuseHeading();

        }

    } else if ((_control_status.flags.ev_pos || _control_status.flags.ev_vel)
           && (_time_last_imu >= _time_last_ext_vision)
           && ((_time_last_imu - _time_last_ext_vision) > (uint64_t)_params.reset_timeout_max)) {

        // Turn off EV fusion mode if no data has been received
        _control_status.flags.ev_pos = false;
        _control_status.flags.ev_vel = false;
        _control_status.flags.ev_yaw = false;
        ECL_INFO_TIMESTAMPED("EKF External Vision Data Stopped");

    }
}

EKF\control.cpp (1.11)

void Ekf::controlExternalVisionFusion()
{
    // Check for new external vision data
    if (_ev_data_ready) {

        // if the ev data is not in a NED reference frame, then the transformation between EV and EKF navigation frames
        // needs to be calculated and the observations rotated into the EKF frame of reference
        if ((_params.fusion_mode & MASK_ROTATE_EV) && ((_params.fusion_mode & MASK_USE_EVPOS) || (_params.fusion_mode & MASK_USE_EVVEL)) && !_control_status.flags.ev_yaw) {
            // rotate EV measurements into the EKF Navigation frame
            calcExtVisRotMat();
        }

        /* ...... */

        // external vision yaw aiding selection logic
        if (!_control_status.flags.gps && (_params.fusion_mode & MASK_USE_EVYAW) && !_control_status.flags.ev_yaw && _control_status.flags.tilt_align) {
            // don't start using EV data unless data is arriving frequently
            if (isRecent(_time_last_ext_vision, 2 * EV_MAX_INTERVAL)) {
                // reset the yaw angle to the value from the vision quaternion
                const Eulerf euler_obs(_ev_sample_delayed.quat);
                const float yaw = euler_obs(2);
                const float yaw_variance = fmaxf(_ev_sample_delayed.angVar, sq(1.0e-2f));

                resetQuatStateYaw(yaw, yaw_variance, true);

                // flag the yaw as aligned
                _control_status.flags.yaw_align = true;

                // turn on fusion of external vision yaw measurements and disable all magnetometer fusion
                _control_status.flags.ev_yaw = true;
                _control_status.flags.mag_dec = false;

                stopMagHdgFusion();
                stopMag3DFusion();

                ECL_INFO_TIMESTAMPED("starting vision yaw fusion");
            }
        }

        /* ...... */

        // determine if we should use the yaw observation
        if (_control_status.flags.ev_yaw) {
            fuseHeading();
        }

    } else if ((_control_status.flags.ev_pos || _control_status.flags.ev_vel)
           && isTimedOut(_time_last_ext_vision, (uint64_t)_params.reset_timeout_max)) {

        // Turn off EV fusion mode if no data has been received
        stopEvFusion();
        ECL_INFO_TIMESTAMPED("vision data stopped");

    }
}
回复 点赞

使用道具 举报

返回列表
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表