基于icm20609姿态更新计算的四元数算法

前言

在目前的六轴姿态传感器中,网上对于icm系列的贴子相对于mpu系列要少很多,而icm20609的贴子为零。

在官网上对于MPU系列(和一款icm系列芯片)已经不做推荐了

我这里也在官网上看了下icm20609和icm20602的区别,因为这篇贴子主要是根据icm20602的讲解所改动的。

可以看出,icm20609具有超薄封装以及4K的FIFO,而icm20602更低功耗,OK,本帖不用内置的dmp,因此不回去用FIFO,所以实际上我觉得差不多。

 

问题:为什么不直接转化成欧拉角来表示而要引入四元数呢?

一方面是因为欧拉角微分方程中包含了大量的三角运算,这给实时解算带来了一定的困难。而且当俯仰角为90度时方程式会出现神奇的“GimbalLock”。

所以欧拉角方法只适用于水平姿态变化不大的情况,而不适用于全姿态飞行器的姿态确定。

四元数法只求解四个未知量的线性微分方程组,计算量小,易于操作,是比较实用的工程方法。

 

四元数是一种超复数。如把四元数的集合考虑成多维实数空间的话,四元数就代表

k i j 着一个四维空间,相对于复数为二维空间。

简而言之,四元数包含了刚体旋转的所有信息,而在四旋翼飞行器的姿态解算中,往往使用的是四元数微分方程对四元数进行更新

 

 

正文

1、首先看看icm20609的配置参数

参考代码:

https://github.com/golaced/Oldx_fly_controller/blob/master/firmware/Back_FC/applications/icm20602.c

int8_t icm20609_init_per20ms(void)
{
    int8_t icm20609_init_returnvalue = 0xff;
    u8 offset_and_data[2];
    switch (icm20609_init_State)
    {
        case icm20609_init_pre_state:
            icm20609_ReadID();
            icm20609_init_State = icm20609_init_step1_state;
            break;
        case icm20609_init_step1_state:
            if (icm20609_init_delay == 0x00)
            {
                icm20609_init_delay++;
                Icm20609acceptdata.PWR_MGMT_1_REG = 0x00;
                ICM20609_WriteReg(ICM20609_PWR_MGMT_1_REG, 0x80);
            }
            else
            {
                do {
                    ICM20609_ReadReg(ICM20609_PWR_MGMT_1_REG, &Icm20609acceptdata.PWR_MGMT_1_REG);
                }while(Icm20609acceptdata.PWR_MGMT_1_REG & 0x80);
                
                icm20609_init_delay = 0;
                icm20609_init_State = icm20609_init_step2_state;
            }
            break;

        case icm20609_init_step2_state:
            icm20609_init_delay++;
            switch (icm20609_init_delay)
            {
                case 0x01:
                    icm20609_power_on();//ICM20609_PWR_MGMT_1_REG set 0x01
                    break;
                case 0x02:
                    /*Reset digital signal path*/
                    ICM20609_WriteReg(ICM20609_SIGNAL_PATH_RESET_REG, 0x03);
                    break;
                case 0x03:
                    /*clears all the sensor registers*/
                    ICM20609_WriteReg(ICM20609_USER_CTRL_REG, 0x01);
                    break;
                case 0x04:
                    ICM20609_WriteReg(ICM20609_PWR_MGMT_2_REG,0x00);
                    break;
                case 0x05:
                    icm20609_set_odr(200);  //200 Hz  1000/200-1
                    break;
                case 0x06:    
                    ICM20609_WriteReg(ICM20609_CONFIG_REG,IAM20609_GYRO_BW_20HZ); //gtro and temp LPF
                    break;
                case 0x07:
                    icm20609_set_gyro_fsr((ICM20609_GYRO_FSR_2000 << 3));  //+-2000dps
                    break;
                case 0x08:
                    icm20609_set_accel_fsr((ICM20609_ACCEL_FSR_8G << 3));//+-8g
                    break;
                case 0x09:
                    ICM20609_WriteReg(ICM20609_ACCEL_CONFIG2_REG, ICM20609_ACCEL_BW_21HZ);/*accel LPF 20HZ*/
                    break;
                case 0x0A:
                    ICM20609_WriteReg(ICM20609_LP_MODE_CFG_REG, 0x00);/*关闭低功耗*/
                    break;
                case 0x0B:
                    ICM20609_WriteReg(ICM20609_FIFO_EN_REG, 0x00);/*关闭FIFO*/
                    icm20609_init_State = icm20609_init_finish_state;
                    break;
                default:
                    break;
            }
            break;
        case icm20609_init_finish_state:
            icm20609_init_returnvalue = 0x01;
            break;
        default:
            break;
    }

    return iam20609_init_returnvalue;
}

其实最主要的是通过ICM20609_PWR_MGMT_1_REG寄存器reset芯片,并确认是否reset了;接着就是对采样频率和陀螺仪和加速度计的量程进行设置;最后是对LPF(低通滤波)寄存器进行设置。

2、自检和校准

有需要的话可以参考这篇帖子:https://blog.csdn.net/yyw_0429/article/details/86659332

这份参考贴并没有贴出所有代码,这里就写一下原理:

自检:

  • 芯片处于no motion状态,读取加速度计和陀螺仪输出数据,计算平均值;
  • GYRO_CONFIG寄存器和ACCEL_CONFIG寄存器使能自检,此时芯片内部会自动模拟外力 施加给加速度计和陀螺仪,此时输出的加速度计和陀螺仪数据相较不使能自检状态会有所变化,计算平均值;
  • 读取自检寄存器输出数据,获得厂家出厂时固化的OTP;
  • 最后直接使用驱动程序中给出的转化表和输出值进行比较,来判断自检是否通过

 

校准:

  • 读取初始状态下加速度计输出值,计算平均值
  • 使能校准
  • 读取出厂时XA_OFFS寄存器里的校准值
  • 校准值减去平均值后写入XA_OFFS寄存器

 

这里并没有进行自检和校准,不再赘述。

 

3、数据采集

  • 这里使用软件IIC来进行采集原始数据。
  • 采样率是200HZ,程序中也是每5ms采集并更新一次姿态
  • 陀螺仪的范围选择±2000,而对应的精度是16.4 LSB/(°/s),而在四轴姿态计算中,我们通常要把角度换算成弧度。我们知道2Pi代表360度,那么1度换算成弧度就是: 2Pi/360=(2*3.1415926)/360=0.0174532=1/57.30。
  • 加速度计选择的量程是±8G,精度为4096LSB/g

 

软件iic进行读取原始数据:

int8_t icm20609_accelAndGyro_read(accel_t *accel, gyro_t *gyro, int16_t temp)
{
    u8  reg_data[14];
    ICM20609_ReadData(ICM20609_ACCEL_XOUT_H_REG, (u8 *)&reg_data, 14);
    
    accel->x = (int16_t)(reg_data[0] << 8 | reg_data[1]);
    accel->y = (int16_t)(reg_data[2] << 8 | reg_data[3]);
    accel->z = (int16_t)(reg_data[4] << 8 | reg_data[5]);
    temp     = (int16_t)(reg_data[6] << 8 | reg_data[7]);
    gyro->x  = (int16_t)(reg_data[8] << 8 | reg_data[9]);
    gyro->y  = (int16_t)(reg_data[10] << 8 | reg_data[11]);
    gyro->z  = (int16_t)(reg_data[12] << 8 | reg_data[13]);
    return 0x01;
}

 

将原始数据进行转换并传给姿态解算的函数:

//get accel and gyro from iam20609 
// 对accel一阶低通滤波(参考匿名),对gyro转成弧度每秒(2000dps)
#define new_weight           0.35f
#define old_weight           0.65f
void IMU_getValues(float * values, accel_t * accelval, gyro_t * gyroval) 
{  
    static float lastaccel[3]= {0,0,0};
    int i;
    values[0] = ((float)accelval->x) * new_weight + lastaccel[0] * old_weight;
    values[1] = ((float)accelval->y) * new_weight + lastaccel[1] * old_weight;
    values[2] = ((float)accelval->z) * new_weight + lastaccel[2] * old_weight;
    for(i=0; i<3; i++)
    {
        lastaccel[i] = values[i];
    }

    values[3] = ((float)gyroval->x) * M_PI / 180 / 16.4f;
    values[4] = ((float)gyroval->y) * M_PI / 180 / 16.4f;
    values[5] = ((float)gyroval->z) * M_PI / 180 / 16.4f;

    //
}

 

4、姿态解算

按照 原始数据->四元数->欧拉角的方式进行姿态解算并从匿名上位机中进行观察

#define delta_T      0.005f  //5ms计算一次

float I_ex, I_ey, I_ez;  // 误差积分
quaterInfo_t Q_info;  // 全局四元数
eulerianAngles_t eulerAngle; //欧拉角
float param_Kp = 50.0;   // 加速度计(磁力计)的收敛速率比例增益50 
float param_Ki = 0.20;   //陀螺仪收敛速率的积分增益 0.2
/**
  * brief IMU_AHRSupdate_noMagnetic  姿态解算融合,是Crazepony和核心算法
  * 使用的是互补滤波算法,没有使用Kalman滤波算法
  * param float gx, float gy, float gz, float ax, float ay, float az
  *
  * return None
  */
static void IMU_AHRSupdate_noMagnetic(float gx, float gy, float gz, float ax, float ay, float az)
{
    float halfT = 0.5 * delta_T;
    float vx, vy, vz;    //当前的机体坐标系上的重力单位向量
    float ex, ey, ez;    //四元数计算值与加速度计测量值的误差
    float q0 = Q_info.q0;
    float q1 = Q_info.q1;
    float q2 = Q_info.q2;
    float q3 = Q_info.q3;
    float q0q0 = q0 * q0;
    float q0q1 = q0 * q1;
    float q0q2 = q0 * q2;
    float q0q3 = q0 * q3;
    float q1q1 = q1 * q1;
    float q1q2 = q1 * q2;
    float q1q3 = q1 * q3;
    float q2q2 = q2 * q2;
    float q2q3 = q2 * q3;
    float q3q3 = q3 * q3;
    float delta_2 = 0;
  • 输入参数gx,gy,gz分别对应三个轴的角速度,单位是弧度/秒。
  • 输入参数ax,ay,az分别对应三个轴的加速度数据,由于加速度的噪声较大,在读取的时候该数据是采用低通滤波。

当电子罗盘数据有效的时候,需要融合电子罗盘的数据。这里没有使用磁力计,所以只进行加速度数据融合。

    //对加速度数据进行归一化 得到单位加速度
    float norm = invSqrt(ax*ax + ay*ay + az*az);       
    ax = ax * norm;
    ay = ay * norm;
    az = az * norm;

对加速度数据进行归一化,得到单位加速度。这里介绍一种快速计算1/sqrt(x)的函数:

float invSqrt(float x) {
	float halfx = 0.5f * x;
	float y = x;
	long i = *(long*)&y;
	i = 0x5f3759df - (i>>1);
	y = *(float*)&i;
	y = y * (1.5f - (halfx * y * y));
	return y;
}
    vx = 2*(q1q3 - q0q2);
    vy = 2*(q0q1 + q2q3);
    vz = q0q0 - q1q1 - q2q2 + q3q3;

把飞行器上次计算得到的姿态(四元数)换算成“方向余弦矩阵”中的第三列的三个元素。根据余弦矩阵和欧拉角的定义,地理坐标系的重力向量,转到机体坐标系,正好是这三个元素。所以这里的vx、vy、vz,其实就是用上一次飞行器机体姿态(四元数)换算出来的在当前的机体坐标系上的重力单位向量。

    ex = ay * vz - az * vy;
    ey = az * vx - ax * vz;
    ez = ax * vy - ay * vx;

在机体坐标系上,加速度计测出来的重力向量是ax、ay、az。由上次解算的姿态推算出的重力向量是vx、vy、vz。它们之间的误差向量,就是上次姿态和加速度计测出来的姿态之间的误差。

向量间的误差,可以用向量积(也叫外积、叉乘)来表示,ex、ey、ez就是两个重力向量的叉积。这个叉积向量仍旧是位于机体坐标系上的,而陀螺积分误差也是在机体坐标系,而且叉积的大小与陀螺积分误差成正比,正好拿来纠正陀螺。由于陀螺是对机体直接积分,所以对陀螺的纠正量会直接体现在对机体坐标系的纠正。

所以上面一段代码含义就是获得叉乘误差。

    //用叉乘误差来做PI修正陀螺零偏,
    //通过调节 param_Kp,param_Ki 两个参数,
    //可以控制加速度计修正陀螺仪积分姿态的速度。
    I_ex += delta_T * ex;   // integral error scaled by Ki
    I_ey += delta_T * ey;
    I_ez += delta_T * ez;

    gx = gx+ param_Kp*ex + param_Ki*I_ex;
    gy = gy+ param_Kp*ey + param_Ki*I_ey;
    gz = gz+ param_Kp*ez + param_Ki*I_ez;

上面一段代码,叉乘误差进行积分。用叉乘误差来做PI修正陀螺零偏,通过调节param_Kp,param_Ki 两个参数,可以控制加速度计修正陀螺仪积分姿态的速度。

到此为止,使用加速度计数据对陀螺仪数据的修正已经完成,这就是姿态解算中的深度融合。

下面就是四元数微分方程,使用修正后的陀螺仪数据对时间积分,得到飞行器的当前姿态(四元数表示)。然后进行四元数的单位化处理。

    //四元数微分方程,其中halfT为测量周期的1/2,gx gy gz为陀螺仪角速度,以下都是已知量,这里使用了一阶龙哥库塔求解四元数微分方程
    q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
    q1 = q1 + ( q0*gx + q2*gz - q3*gy)*halfT;
    q2 = q2 + ( q0*gy - q1*gz + q3*gx)*halfT;
    q3 = q3 + ( q0*gz + q1*gy - q2*gx)*halfT;

//    delta_2=(2*halfT*gx)*(2*halfT*gx)+(2*halfT*gy)*(2*halfT*gy)+(2*halfT*gz)*(2*halfT*gz);
    // 整合四元数率    四元数微分方程  四元数更新算法,二阶毕卡法
//    q0 = (1-delta_2/8)*q0 + (-q1*gx - q2*gy - q3*gz)*halfT;			
//    q1 = (1-delta_2/8)*q1 + (q0*gx + q2*gz - q3*gy)*halfT;
//    q2 = (1-delta_2/8)*q2 + (q0*gy - q1*gz + q3*gx)*halfT;
//    q3 = (1-delta_2/8)*q3 + (q0*gz + q1*gy - q2*gx)*halfT;	

    // normalise quaternion
    norm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
    Q_info.q0 = q0 * norm;
    Q_info.q1 = q1 * norm;
    Q_info.q2 = q2 * norm;
    Q_info.q3 = q3 * norm;

 

 

这里贴一下融合磁力计的四元数更新算法:

static void IMU_AHRSupdate_withMagnetic(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz)
{
    float norm;
    float halfT = 0.5 * delta_T;
    float hx, hy, hz;
    float bx, bz;
    float vx, vy, vz;
    float wx, wy, wz;
    float ex, ey, ez;
    float delta_2 = 0;
    float q0 = Q_info.q0;
    float q1 = Q_info.q1;
    float q2 = Q_info.q2;
    float q3 = Q_info.q3;
    float q0q0 = q0*q0;
    float q0q1 = q0*q1;
    float q0q2 = q0*q2;
    float q0q3 = q0*q3;
    float q1q1 = q1*q1;
    float q1q2 = q1*q2;
    float q1q3 = q1*q3;
    float q2q2 = q2*q2;
    float q2q3 = q2*q3;
    float q3q3 = q3*q3;

    norm = invSqrt(ax*ax + ay*ay + az*az);
    ax = ax * norm;
    ay = ay * norm;
    az = az * norm;

    norm = invSqrt(mx*mx + my*my + mz*mz);          
    mx = mx * norm;
    my = my * norm;
    mz = mz * norm;

    // compute reference direction of flux 通量的计算参考方向
    hx = 2*mx*(0.5f - q2q2 - q3q3) + 2*my*(q1q2 - q0q3) + 2*mz*(q1q3 + q0q2);
    hy = 2*mx*(q1q2 + q0q3) + 2*my*(0.5f - q1q1 - q3q3) + 2*mz*(q2q3 - q0q1);
    hz = 2*mx*(q1q3 - q0q2) + 2*my*(q2q3 + q0q1) + 2*mz*(0.5f - q1q1 - q2q2);         
    bx = sqrt((hx*hx) + (hy*hy));
    bz = hz;     

    // estimated direction of gravity and flux (v and w)
    vx = 2*(q1q3 - q0q2);				  	// 估计方向的重力
    vy = 2*(q0q1 + q2q3);
    vz = q0q0 - q1q1 - q2q2 + q3q3;
    wx = 2*bx*(0.5 - q2q2 - q3q3) + 2*bz*(q1q3 - q0q2);
    wy = 2*bx*(q1q2 - q0q3) + 2*bz*(q0q1 + q2q3);
    wz = 2*bx*(q0q2 + q1q3) + 2*bz*(0.5 - q1q1 - q2q2);  

    // error is sum of cross product between reference direction of fields and direction measured by sensors

    ex = (ay*vz - az*vy) + (my*wz - mz*wy);
    ey = (az*vx - ax*vz) + (mz*wx - mx*wz);
    ez = (ax*vy - ay*vx) + (mx*wy - my*wx);

    if(ex != 0.0f && ey != 0.0f && ez != 0.0f)
    {

        I_ex += delta_T * ex;	// integral error scaled by Ki
        I_ey += delta_T * ey;
        I_ez += delta_T * ez;
        //exdev=(ex[1]-ex[0]) / halfT;
        //eydev=(ey[1]-ey[0]) / halfT;
        // ezdev=(ez[1]-ez[0]) / halfT;
        // adjusted gyroscope measurements

        gx = gx+ param_Kp*ex + param_Ki*I_ex;//+ Kd*exdev;
        gy = gy+ param_Kp*ey + param_Ki*I_ey;//+ Kd*eydev;
        gz = gz+ param_Kp*ez + param_Ki*I_ez;//+ Kd*ezdev;
    }
    delta_2=(2*halfT*gx)*(2*halfT*gx)+(2*halfT*gy)*(2*halfT*gy)+(2*halfT*gz)*(2*halfT*gz);
    // 整合四元数率    四元数微分方程  四元数更新算法,二阶毕卡法
    q0 = (1-delta_2/8)*q0 + (-q1*gx - q2*gy - q3*gz)*halfT;			
    q1 = (1-delta_2/8)*q1 + (q0*gx + q2*gz - q3*gy)*halfT;
    q2 = (1-delta_2/8)*q2 + (q0*gy - q1*gz + q3*gx)*halfT;
    q3 = (1-delta_2/8)*q3 + (q0*gz + q1*gy - q2*gx)*halfT;	
    // normalise quaternion
    norm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
    Q_info.q0 = q0 * norm;
    Q_info.q1 = q1 * norm;
    Q_info.q2 = q2 * norm;
    Q_info.q3 = q3 * norm;
}

 

5、通过四元数计转换欧拉角

根据四元数方向余弦阵和欧拉角的转换关系,把四元数转换成欧拉角

void IMU_quaterToEulerianAngles()
{
    float q0 = Q_info.q0;
    float q1 = Q_info.q1;
    float q2 = Q_info.q2;
    float q3 = Q_info.q3;
    eulerAngle.pitch = asin(-2*q1*q3 + 2*q0*q2) * 180/M_PI; // pitch
    eulerAngle.roll = atan2(2*q2*q3 + 2*q0*q1, -2*q1*q1 - 2*q2*q2 + 1) * 180/M_PI; // roll
    eulerAngle.yaw = atan2(2*q1*q2 + 2*q0*q3, -2*q2*q2 - 2*q3*q3 + 1) * 180/M_PI; // yaw

/*   可以不用作姿态限度的限制
    if(eulerAngle.roll>90 || eulerAngle.roll<-90)
    {
        if(eulerAngle.pitch > 0)
        {
            eulerAngle.pitch = 180-eulerAngle.pitch;
        }
        if(eulerAngle.pitch < 0)
        {
            eulerAngle.pitch = -(180+eulerAngle.pitch);
        }
    }
    if(eulerAngle.yaw > 180)
    {
        eulerAngle.yaw -=360;
    }
    else if(eulerAngle.yaw <-180)
    {
        eulerAngle.yaw +=360;
    } 
    */
}

 

最后感谢:

http://www.crazepony.com/wiki/software-algorithm.html

  • 61
    点赞
  • 385
    收藏
    觉得还不错? 一键收藏
  • 36
    评论
### 回答1: ICM42688是一款传感器芯片,集成了能够测量加速度和陀螺仪的功能。而位姿算法是一种利用这些传感器数据来计算物体的姿态(包括旋转角度、方向和位置)的算法。 ICM42688位姿算法利用传感器测量得到的加速度和陀螺仪数据,通过复杂的运动分析和数学计算来推导出物体的姿态信息。通过计算物体受力和角速度的变化,算法可以准确地推断出物体的旋转、倾斜和平移运动。 对于ICM42688来说,它可以用于许多不同的应用领域。例如,在虚拟现实中,通过获取用户的头部姿态信息,可以实现对虚拟环境中的视角的实时调整。在运动跟踪中,可以通过获取物体的运动姿态信息来实时监测和分析人体运动的准确性和效果。此外,位姿算法还可以应用于机器人控制、虚拟导航和游戏等领域。 ICM42688位姿算法的优点在于其高精度和快速响应性。传感器能够以高频率采集数据,并且算法能够准确地处理这些数据,从而实时地计算出物体的姿态信息。这种实时性对于那些需要即时反馈和控制的应用非常重要。 总的来说,ICM42688位姿算法是一种利用传感器数据计算物体姿态信息的算法,它可以应用于虚拟现实、运动跟踪、机器人控制等多个领域,并且具有高精度和快速响应的优点。 ### 回答2: ICM42688位姿算法是一种基于ICM42688惯性测量单元(IMU)的姿态计算法。ICM42688是一种功能强大的六轴惯性测量单元,可以同时测量加速度和陀螺仪数据。 ICM42688位姿算法通过分析IMU传感器提供的加速度和陀螺仪数据来估计设备的姿态。加速度传感器测量物体的加速度,而陀螺仪测量物体的角速度。通过集成陀螺仪数据,可以得出设备相对于初始位置的旋转角度。 ICM42688位姿算法通过使用滤波技术和传感器融合算法来减少传感器测量误差,并提高姿态估计的准确性。滤波技术可以平滑不确定性,减少噪声,从而提高姿态估计的稳定性。传感器融合算法结合了加速度计和陀螺仪的数据,综合考虑二者的优势,得出更精确的姿态估计结果。 ICM42688位姿算法可以广泛应用于无人机、机器人、虚拟现实和增强现实等领域。通过实时准确地估计设备的姿态,可以为这些应用提供重要的位置和方向信息,从而实现更精确的控制和导航。 总之,ICM42688位姿算法是一种基于ICM42688 IMU的姿态计算法,通过分析加速度和陀螺仪数据来估计设备的姿态。通过滤波技术和传感器融合算法,可以提高姿态估计的准确性和稳定性。该算法在无人机、机器人和虚拟现实等领域有着广泛的应用前景。 ### 回答3: ICM42688是一款高性能、低功耗的集成式惯性测量单元(IMU)芯片。ICM42688芯片配备了先进的位姿算法,可以用于车辆导航、运动控制和虚拟现实等应用中。 ICM42688的位姿算法主要包括以下几个方面: 1. 传感器融合:ICM42688集成了三轴陀螺仪和三轴加速度计,在位姿算法中使用传感器融合技术,可以提高测量的准确性和稳定性。通过将陀螺仪和加速度计的数据进行融合,可以实现角度和位置的精确测量。 2. 运动跟踪:ICM42688可以实时跟踪物体的运动轨迹。通过计算物体在不同时间点上的位置和速度变化,可以确定物体的运动状态,从而实现运动轨迹的准确跟踪。 3. 姿态估计:ICM42688的位姿算法可以通过传感器数据估计物体的姿态,即物体在空间中的方向和位置。通过测量物体的旋转角度和位置变化,可以得到物体的姿态信息,这对于机器人控制、姿势识别等应用非常重要。 4. 姿态校准:ICM42688的位姿算法还可以进行姿态校准,以提高位姿测量的准确性。通过对陀螺仪和加速度计进行校准,可以消除传感器的误差和漂移,从而得到更精确的姿态测量结果。 总之,ICM42688的位姿算法可以实现准确的姿态估计、运动跟踪和姿态校准,为车辆导航、运动控制和虚拟现实等应用提供了重要的技术支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值