这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【i646593001】QuadCopter DIY进程帖

共76条 4/8 |‹ 2 3 4 5 6 7 ›| 跳转至
菜鸟
2014-06-21 12:14:00     打赏
31楼
赞一个

菜鸟
2014-06-21 12:14:03     打赏
32楼
赞一个

助工
2014-06-21 13:44:34     打赏
33楼
一个就够了,

院士
2014-06-21 14:08:21     打赏
34楼
赞一个

助工
2014-06-21 16:36:07     打赏
35楼

传感器数据融合

MPU6050有了驱动之后就可以考虑数据融合了。简单来说,陀螺仪精度高,但时间长了会有漂移,加速度动态精度差,但没有长期漂移。综合利用陀螺仪和加速度计的特点,优势互补获得准确的姿态角度,方法就是用卡尔曼滤波做数据融合。

Snake0301使用的是MPU6050内置的DMP,直接输出姿态数据,使用方法网上有例程,可见这里:

https://gist.github.com/jannson/11280208

但是很多人说用DMP后Z轴会有漂移,Snake0301也有反映,且DMP的输出速率不是很高,最快200Hz,所以准备舍弃这种方法,还是中规中矩的用滤波吧。


高工
2014-06-22 13:35:02     打赏
36楼
条理清晰,加油。

助工
2014-06-23 00:13:18     打赏
37楼
今天手贱,想把link的几个母头用502粘到一起,结果胶水多了,把插口都塞满了,暂时用不了了,找机会重新做插头了。

助工
2014-06-24 18:14:17     打赏
38楼
昨晚上花了两个小时才把st-link的插口重新做好,第一次做完了后发现母头比以前的大一点点,如果以前的是2.54的话,第一次做的可能就是2.6的了,总之大了那么一点,只好重新剪掉重新做了。真是郁闷,发现做这个挺麻烦的,不知道工厂里是怎么大批量做的。

助工
2014-06-24 18:55:35     打赏
39楼

今天看了"让四轴飞"网友的工程,发现程序还真是简洁,基本上一个模块一个.c文件即可实现,总共才那么六七个模块,重新移植修改起来就很方便了。反观crazyfliie的工程,代码量多了好几倍,又加入了操作系统FreeRTOS,真担心MCU的处理能力,不过看他们的视频,还是很有信心的。

附链接地址:

http://v.youku.com/v_show/id_XNTEwODM4MzEy/v.swf.html




助工
2014-06-25 00:16:43     打赏
40楼


上面分析了Crazyflie的acc采样数值的滤波,接着分析其他函数吧。上代码

void imu6Read(Axis3f* gyroOut, Axis3f* accOut)
{
  mpu6050GetMotion6(&accelMpu.x, &accelMpu.y, &accelMpu.z, &gyroMpu.x, &gyroMpu.y, &gyroMpu.z);

  imuAddBiasValue(&gyroBias, &gyroMpu);
  if (!accelBias.isBiasValueFound)
    imuAddBiasValue(&accelBias, &accelMpu);
  if (!gyroBias.isBiasValueFound)
    imuFindBiasValue(&gyroBias);

#ifdef IMU_TAKE_ACCEL_BIAS
  if (gyroBias.isBiasValueFound &&
      !accelBias.isBiasValueFound)
  {
    Axis3i32 mean;

    imuCalculateBiasMean(&accelBias, &mean);
    accelBias.bias.x = mean.x;
    accelBias.bias.y = mean.y;
    accelBias.bias.z = mean.z - IMU_1G_RAW;
    accelBias.isBiasValueFound = TRUE;
//    uartPrintf("Accel bias: %i, %i, %i\n",
//                accelBias.bias.x, accelBias.bias.y, accelBias.bias.z);
  }
#endif

  imuAccIIRLPFilter(&accelMpu, &accelLPF, &accelStoredFilterValues,
                    (int32_t)imuAccLpfAttFactor);

  imuAccAlignToGravity(&accelLPF, &accelLPFAligned);

  // Re-map outputs
  gyroOut->x = (gyroMpu.x - gyroBias.bias.x) * IMU_DEG_PER_LSB_CFG;
  gyroOut->y = (gyroMpu.y - gyroBias.bias.y) * IMU_DEG_PER_LSB_CFG;
  gyroOut->z = (gyroMpu.z - gyroBias.bias.z) * IMU_DEG_PER_LSB_CFG;
  accOut->x = (accelLPFAligned.x - accelBias.bias.x) * IMU_G_PER_LSB_CFG;
  accOut->y = (accelLPFAligned.y - accelBias.bias.y) * IMU_G_PER_LSB_CFG;
  accOut->z = (accelLPFAligned.z - accelBias.bias.z) * IMU_G_PER_LSB_CFG;
//  uartSendData(sizeof(Axis3f), (uint8_t*)gyroOut);
//  uartSendData(sizeof(Axis3f), (uint8_t*)accOut);
}


其中数据类型的定义如下


typedef struct
{
  int16_t x;
  int16_t y;
  int16_t z;
} Axis3i16;

typedef struct
{
  int32_t x;
  int32_t y;
  int32_t z;
} Axis3i32;

typedef struct
{
  float x;
  float y;
  float z;
} Axis3f;

typedef struct
{
  Axis3i16   bias;
  bool       isBiasValueFound;
  bool       isBufferFilled;
  Axis3i16*  bufHead;
  Axis3i16   buffer[IMU_NBR_OF_BIAS_SAMPLES];
} BiasObj;

BiasObj    gyroBias;
BiasObj    accelBias;
int32_t    varianceSampleTime;
Axis3i16   gyroMpu;
Axis3i16   accelMpu;
Axis3i16   accelLPF;
Axis3i16   accelLPFAligned;
Axis3i16   mag;
Axis3i32   accelStoredFilterValues;
uint8_t    imuAccLpfAttFactor;


1、第一个函数


  mpu6050GetMotion6(&accelMpu.x, &accelMpu.y, &accelMpu.z, &gyroMpu.x, &gyroMpu.y, &gyroMpu.z);

从MPU6050读取6个数值,不表。

2、imuAddBiasValue(&gyroBias, &gyroMpu);

函数原型:


/**
 * Adds a new value to the variance buffer and if it is full
 * replaces the oldest one. Thus a circular buffer.
 */
static void imuAddBiasValue(BiasObj* bias, Axis3i16* dVal)
{
  bias->bufHead->x = dVal->x;
  bias->bufHead->y = dVal->y;
  bias->bufHead->z = dVal->z;
  bias->bufHead++;

  if (bias->bufHead >= &bias->buffer[IMU_NBR_OF_BIAS_SAMPLES])
  {
    bias->bufHead = bias->buffer;
    bias->isBufferFilled = TRUE;
  }
}


其中IMU_NBR_OF_BIAS_SAMPLES = 128,此函数易读,即向一个bias结构体的长128数组中填充数据,并更新下一个待填充数据的地址。第一次填充完128个数据后,isBufferFilled成员即更改为TRUE。



3、imuFindBiasValue(&gyroBias);


函数原型:

/**
 * Checks if the variances is below the predefined thresholds.
 * The bias value should have been added before calling this.
 * @param bias  The bias object
 */
static bool imuFindBiasValue(BiasObj* bias)
{
  bool foundBias = FALSE;

  if (bias->isBufferFilled)
  {
    Axis3i32 variance;
    Axis3i32 mean;

    imuCalculateVarianceAndMean(bias, &variance, &mean);

    //uartSendData(sizeof(variance), (uint8_t*)&variance);
    //uartSendData(sizeof(mean), (uint8_t*)&mean);
    //uartPrintf("%i, %i, %i", variance.x, variance.y, variance.z);
    //uartPrintf("%i, %i, %i\n", mean.x, mean.y, mean.z);

    if (variance.x < GYRO_VARIANCE_THRESHOLD_X &&
        variance.y < GYRO_VARIANCE_THRESHOLD_Y &&
        variance.z < GYRO_VARIANCE_THRESHOLD_Z &&
        (varianceSampleTime + GYRO_MIN_BIAS_TIMEOUT_MS < xTaskGetTickCount()))
    {
      varianceSampleTime = xTaskGetTickCount();
      bias->bias.x = mean.x;
      bias->bias.y = mean.y;
      bias->bias.z = mean.z;
      foundBias = TRUE;
      bias->isBiasValueFound = TRUE;
    }
  }

  return foundBias;
}


该函数在BiasObj结构体的128长的数组没填充完时不处理即返回False


在填充完128个值后做如下处理:

imuCalculateVarianceAndMean(bias, &variance, &mean);

函数原型:

/**
 * Calculates the variance and mean for the bias buffer.
 */
static void imuCalculateVarianceAndMean(BiasObj* bias, Axis3i32* varOut, Axis3i32* meanOut)
{
  uint32_t i;
  int32_t sum[GYRO_NBR_OF_AXES] = {0};
  int64_t sumSq[GYRO_NBR_OF_AXES] = {0};

  for (i = 0; i < IMU_NBR_OF_BIAS_SAMPLES; i++)
  {
    sum[0] += bias->buffer[i].x;
    sum[1] += bias->buffer[i].y;
    sum[2] += bias->buffer[i].z;
    sumSq[0] += bias->buffer[i].x * bias->buffer[i].x;
    sumSq[1] += bias->buffer[i].y * bias->buffer[i].y;
    sumSq[2] += bias->buffer[i].z * bias->buffer[i].z;
  }

  varOut->x = (sumSq[0] - ((int64_t)sum[0] * sum[0]) / IMU_NBR_OF_BIAS_SAMPLES);
  varOut->y = (sumSq[1] - ((int64_t)sum[1] * sum[1]) / IMU_NBR_OF_BIAS_SAMPLES);
  varOut->z = (sumSq[2] - ((int64_t)sum[2] * sum[2]) / IMU_NBR_OF_BIAS_SAMPLES);

  meanOut->x = sum[0] / IMU_NBR_OF_BIAS_SAMPLES;
  meanOut->y = sum[1] / IMU_NBR_OF_BIAS_SAMPLES;
  meanOut->z = sum[2] / IMU_NBR_OF_BIAS_SAMPLES;

  isInit = TRUE;
}


其中GYRO_NBR_OF_AXES = 3,IMU_NBR_OF_BIAS_SAMPLES = 128。


可以看出varOut的每一项(x,y,z)为该项的方差


meanOut为128个数的均值。

若计算出的3个方差小于设定值,且当前时间距上次采样时间小于1ms,则更新3个偏移值,并更新BiasObj的isBiasValueFound成员。

4、imuCalculateBiasMean(&accelBias, &mean);

该函数Calculates the mean for the bias buffer.

5、  imuAccIIRLPFilter(&accelMpu, &accelLPF, &accelStoredFilterValues,
                    (int32_t)imuAccLpfAttFactor);

该函数上楼已经分析了,pass。

6、imuAccAlignToGravity(&accelLPF, &accelLPFAligned);


该函数的函数原型为:


// Pre-calculated values for accelerometer alignment
float cosPitch;
float sinPitch;
float cosRoll;
float sinRoll;

	

/**
 * Compensate for a miss-aligned accelerometer. It uses the trim
 * data gathered from the UI and written in the config-block to
 * rotate the accelerometer to be aligned with gravity.
 */
static void imuAccAlignToGravity(Axis3i16* in, Axis3i16* out)
{
  Axis3i16 rx;
  Axis3i16 ry;

  // Rotate around x-axis
  rx.x = in->x;
  rx.y = in->y * cosRoll - in->z * sinRoll;
  rx.z = in->y * sinRoll + in->z * cosRoll;

  // Rotate around y-axis
  ry.x = rx.x * cosPitch - rx.z * sinPitch;
  ry.y = rx.y;
  ry.z = -rx.x * sinPitch + rx.z * cosPitch;

  out->x = ry.x;
  out->y = ry.y;
  out->z = ry.z;
}


看函数注释,函数对滤波后的加速度值做X轴和Y轴方向上进行补偿。


7、最终结果

  // Re-map outputs
  gyroOut->x = (gyroMpu.x - gyroBias.bias.x) * IMU_DEG_PER_LSB_CFG;
  gyroOut->y = (gyroMpu.y - gyroBias.bias.y) * IMU_DEG_PER_LSB_CFG;
  gyroOut->z = (gyroMpu.z - gyroBias.bias.z) * IMU_DEG_PER_LSB_CFG;
  accOut->x = (accelLPFAligned.x - accelBias.bias.x) * IMU_G_PER_LSB_CFG;
  accOut->y = (accelLPFAligned.y - accelBias.bias.y) * IMU_G_PER_LSB_CFG;
  accOut->z = (accelLPFAligned.z - accelBias.bias.z) * IMU_G_PER_LSB_CFG;

对陀螺仪的数据去偏差后赋值给gyroOut单位为度/s,对补偿后的加速度值赋值给accOut,单位为G。


综合上面几个步骤,该函数imu6Read的功能为对从mpu6050读取到的数值进行融合处理。从中可以看出,Crazyflie对数据的处理还是比较周到的,包括加速度的iir滤波,对加速度和角速度偏移的求取,加速度和角速度的修正,角速度对加速度的反馈等,而匿名四轴的程序暂时只看到对加速度进行了滑动窗口形式的滤波。






共76条 4/8 |‹ 2 3 4 5 6 7 ›| 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]