Для некоторых датчиков ускорения требуется дополнительная калибровка нуля после монтажа на плату. Когда я увидел несколько исходников с калибровкой датчиков ускорения, где составляющая G учитывалась просто путём вычитания из оси Z величины = 9,8 м/с2 — появилась идея написать данную заметку.




Структура публикации


  • Проблема
  • Постановка задачи и способ решения
  • Как правильно получить точки?
  • Как вычислить центр шара?
  • Как ускорить поиск центра шара?
  • Как ещё ускорить поиск центра шара?
  • Об ошибках при замерах
  • Итог


Проблема


В чём проблема — МЕМС-датчики после монтажа в плату претерпевают незначительные деформации, которые влияют на:
  • положение нуля;
  • масштабирование измеряемых величин;
  • перпендикулярность осей к друг-другу.

И если масштабирование и перпендикулярность нарушаются не так заметно, то положение нуля сбивается ощутимо. Например, если перевести типичную величину смещения нуля для акселерометра датчика MPU9250 в м/с2, то это получается в районе 0,2 м/с2. Т. е. датчик неподвижен, но при этом показывает ускорение, а через 5 секунд мы получаем скорость в 1 м/с. С одной стороны, все данные датчиков всегда пропускают через какой-либо фильтр (например такой). Но с другой стороны зачем фильтру постоянно компенсировать это смещение? Ведь датчик будет показывать движение там, где его нет. Это снижает точность результата. А всего то нужно один раз найти величину смещения и потом во время работы датчика вычитать эту величину из его показаний.

Простейшее решение для поиска величины смещения нуля, которое сразу приходит в голову — это создать условия, при которых датчик точно должен показывать ноль. Значение, регистрируемое на датчике — это и есть величина смещения нуля! Так? Но нет — на акселерометр постоянно действует сила тяжести. Чтобы её избежать, понадобится невесомость (подбрасывание не подойдёт). На компас действует магнитное поле Земли, а на гироскоп её вращение. Так что, если у вас нет персонального звездолёта, то придётся что-то придумать.

Второе решение, которое сразу приходит в голову — это поставить датчик (а точнее его оси) в такое положение, при котором мы точно будем знать, что должен показывать датчик. Разница между тем, что датчик показывает и тем, что он должен показывать — и будет смещение нуля! Так? Например, мы знаем, что если акселерометр поставить в уровень с горизонтом, то по идее, вектор ускорения свободного падения будет направлен точно вдоль оси Z датчика. Величину вектора ускорения мы знаем.

Однако есть проблема. Заключается она в том, что мы не можем точно установить оси датчика в уровень с горизонтом. Дело в том, что поверхность на которую мы будем опираться не параллельна печатной плате. Та в свою очередь не параллельна площадке на которой расположен датчик. Сам датчик не ровно стоит на своей площадке и оси внутри датчика не параллельны корпусу датчика. Погрешность в установки оси относительно горизонта на 1 градус, даёт проекцию, сопоставимую по размерам с величиной самого смещения нуля, которое мы хотим найти. В случае магнитометра, мы вдобавок не знаем, куда направлен вектор магнитного поля. В теории — на север. Но на практике, само магнитное поле Земли неоднородно по напряжённости и направлению. Плюс ближайшие металлические предметы вносят свои коррективы.


Постановка задачи и способ решения


Задача звучит так: нужно определить вектор смещения нуля, используя показания датчика, который всегда будет регистрировать вектор смещения + постоянный вектор внешнего воздействия (ускорение свободного падения, вращение Земли, магнитное поле Земли), величину и направление которого мы не знаем (в случае с акселерометром величину мы знаем, но опять же масштаб датчика может быть не равен 1).

Способ решения. В данной статье предлагается определять вектор смещения следующим образом. Мы берём и крутим датчик по всякому и регистрируем показания датчика. После N измерений, величины взятые с датчика и расположенные на графике будут представлять собой шар, радиус которого — это величина внешнего воздействия, а центр — это как раз искомая величина смещения нуля.

Как правильно получить точки?


Для облегчения самой процедуры измерения, можно написать простенькую программу. Она должна фиксировать показание датчиков, когда прибор неподвижен. Нам останется только поворачивать прибор в нужные положения. Для того, чтобы определить неподвижное состояние, подходит и не калиброванный акселерометр — просто берём разницу между текущим значением и предыдущим. И если больше уровня шума, то значит фиксируем движение. У меня порог получается в районе 0,07G. Если держите руками, будет получаться больше этого значения. Я использовал для фиксации положения малярный скотч. Если всё-равно не получается — проверьте, нет ли рядом холодильника, вентилятора или чего-то подобного.
Как это может быть в коде
// здесь у вас глобальные по модулю переменные
static TSumSensorsData 	g_sens_data[2];
static int32_t   	g_sens_data_sum_cnt[2];
static uint8_t		g_sens_data_num;

// здесь какое-то прерывание, при получении данных с датчиков
IS_INTERRUPT void on_dma_raw_ready_calibrate_step1()
{
	SensorRawBuffer *raw = sensor_get_raw_buffer();
	g_sens_data[g_sens_data_num].acc_x += swap_i16(raw->accell_x_unswap);
	g_sens_data[g_sens_data_num].acc_y += swap_i16(raw->accell_y_unswap);
	g_sens_data[g_sens_data_num].acc_z += swap_i16(raw->accell_z_unswap);
	g_sens_data[g_sens_data_num].gyro_x += swap_i16(raw->gyro_x_unswap);
	g_sens_data[g_sens_data_num].gyro_y += swap_i16(raw->gyro_y_unswap);
	g_sens_data[g_sens_data_num].gyro_z += swap_i16(raw->gyro_z_unswap);
	g_sens_data[g_sens_data_num].mag_x += raw->mag_x_raw * g_mag_calibrate.kx;
	g_sens_data[g_sens_data_num].mag_y += raw->mag_y_raw * g_mag_calibrate.ky;
	g_sens_data[g_sens_data_num].mag_z += raw->mag_z_raw * g_mag_calibrate.kz;
	g_sens_data_sum_cnt[g_sens_data_num]++;
}

//это вызывается из main
void sensors_calibrate_program(FlashROM *flash_ptr)
{
	double calibrate_result_error[3];
	TVector16 calibrate_result[3];
	int32_t radius[ACCEL_NO_MOTION_DETECT_COUNT];
	uint8_t raw_is_deleted[ACCEL_NO_MOTION_DETECT_COUNT];
	TVector16 raw[3][ACCEL_NO_MOTION_DETECT_COUNT];
	
        . . .

	// определяю неподвижность
	g_sens_data_sum_cnt[0] = 0;
	g_sens_data_num = 0;
	int16_t prev_avg_x = 0;
	int16_t prev_avg_y = 0;
	int16_t prev_avg_z = 0;
	int8_t low_motion_cnt = 0;

	while(low_motion_cnt < ACCEL_NO_MOTION_DETECT_COUNT)
	{
		if (g_sens_data_sum_cnt[g_sens_data_num] >= ACCEL_NO_MOTION_DETECT_SAMPLES)
		{
			uint8_t new_data_num = (g_sens_data_num + 1) & 1;
			g_sens_data[new_data_num].acc_x = 0;
			g_sens_data[new_data_num].acc_y = 0;
			g_sens_data[new_data_num].acc_z = 0;
			g_sens_data[new_data_num].gyro_x = 0;
			g_sens_data[new_data_num].gyro_y = 0;
			g_sens_data[new_data_num].gyro_z = 0;
			g_sens_data[new_data_num].mag_x = 0;
			g_sens_data[new_data_num].mag_y = 0;
			g_sens_data[new_data_num].mag_z = 0;
			g_sens_data_sum_cnt[new_data_num] = 0;

			uint8_t old_data_num = g_sens_data_num;
			g_sens_data_num = new_data_num; // вот эта операция не может быть выполнена во время работы прерывания
			// (так по-простому можно разделить два потока, не имея операционки)

			// здесь всё очень просто - нахожу среднюю
			int16_t avg_x = g_sens_data[old_data_num].acc_x / g_sens_data_sum_cnt[old_data_num];
			int16_t avg_y = g_sens_data[old_data_num].acc_y / g_sens_data_sum_cnt[old_data_num];
			int16_t avg_z = g_sens_data[old_data_num].acc_z / g_sens_data_sum_cnt[old_data_num];

			// собственно получаю разницу с предыдущим значением
			int16_t dx = avg_x - prev_avg_x;
			int16_t dy = avg_y - prev_avg_y;
			int16_t dz = avg_z - prev_avg_z;
			prev_avg_x = avg_x;
			prev_avg_y = avg_y;
			prev_avg_z = avg_z;

			// если акселерометр регистрировал низкую активность
			if ((abs_i16(dx) <= ACCEL_NO_MOTION_DETECT_AVG_VALUE)&&(abs_i16(dy) <= ACCEL_NO_MOTION_DETECT_AVG_VALUE)&&(abs_i16(dz) <= ACCEL_NO_MOTION_DETECT_AVG_VALUE))
			{
				// тогда мы регистрируем точку
				raw[RAW_ACC][low_motion_cnt].x = avg_x;
				raw[RAW_ACC][low_motion_cnt].y = avg_y;
				raw[RAW_ACC][low_motion_cnt].z = avg_z;
				raw[RAW_GYRO][low_motion_cnt].x = g_sens_data[old_data_num].gyro_x / g_sens_data_sum_cnt[old_data_num];
				raw[RAW_GYRO][low_motion_cnt].y = g_sens_data[old_data_num].gyro_y / g_sens_data_sum_cnt[old_data_num];
				raw[RAW_GYRO][low_motion_cnt].z = g_sens_data[old_data_num].gyro_z / g_sens_data_sum_cnt[old_data_num];
				raw[RAW_MAG][low_motion_cnt].x = g_sens_data[old_data_num].mag_x / g_sens_data_sum_cnt[old_data_num];
				raw[RAW_MAG][low_motion_cnt].y = g_sens_data[old_data_num].mag_y / g_sens_data_sum_cnt[old_data_num];
				raw[RAW_MAG][low_motion_cnt].z = g_sens_data[old_data_num].mag_z / g_sens_data_sum_cnt[old_data_num];

				low_motion_cnt++;

				// даём звуковой сигнал
				beep();

				// и даём фору себе 2 секунды отклеить скотч, пока датчик в руках - программа регистрирует движение
				// прилепили - получили точку
				// поэтому всё получится быстро и весело
				delay_ms(2000);
			}
		}
	}
. . .
}


Чтобы получить шар на графике, нужно крутить устройство с датчиком по определённой схеме. Для этих целей хорошо подойдёт глобус, так как имеет разметку. Можно подумать, что лепить нужно по всему глобусу. Но это не так.
Пример неправильного результата


Нужно датчик лепить не по всей поверхности глобуса, а на один меридиан. Допустим берём семь точек на меридиане (первая и последняя на северном и южном полюсе). В каждой точке меридиана прикладываем ваше устройство к глобусу и ещё крутим устройство вокруг своей оси с определённым шагом, например 30-35 градусов. Получается если вокруг своей оси поворачивать 12 раз, то в 7 точках всего получается 84 замера.



Прелесть метода в том, что всё можно сделать “на коленке”. Точность позиционирования особой роли не играет, просто нужно крутить по схеме, чтобы вектор внешнего воздействия на графике нарисовал шар. Правильный выглядит примерно так — см. рис (отметкой обозначен центр).



Как вычислить центр шара?


Это интересная задача и у неё несколько вариантов решения. Может показаться, что для поиска центра достаточно взять среднее арифметическое по координатам полученных точек. Однако это не так — точки могут быть расположены на шаре неравномерно (см. рис).



Уравнение шара выглядит так: (X — A)2 + (Y — B)2 + (Z — C)2 = R2, где X, Y, Z — координаты точки, лежащей на шаре. A, B, C — это координаты центра на осях x, y и z соответственно. R — радиус шара. Можно построить систему уравнений и каким-то методом постараться попроще решить эту систему. А можно просто перебором найти центр (это типа метод последовательных приближений). Смысл метода прост: величина ошибки (X — A)2 + (Y — B)2 + (Z — C)2 — R2 должна стремиться к нулю. А значит сумма этих величин для всех точек сферы также должна стремиться к нулю. Зная это, мы можем подобрать такие значения A, B и C, для которых величина ошибки для всех точек будет минимальной. Зона перебора ограничивается габаритами шара (условный куб). То есть мы последовательно должны поставить центр шара во все точки куба и посчитать ошибку. Там где минимальная ошибка — там и центр.



В качестве R нужно брать теоретическую величину вектора внешнего воздействия — для акселерометра, это ускорение свободного падения, для компаса — это средняя величина магнитного поля Земли, для гироскопа — скорость вращения Земли. Разумеется в формуле должны быть величины одной размерности (условные единицы датчика или м/с2, градус/с и т. д.). Удобней пересчитывать в условные единицы соответствующего датчика.
Как посчитать некую величину в условные единицы датчика?
Условные единицы датчика = Величина * Разрешение датика / (Максимальный предел измерения — Минимальный предел измерения)
Например: Сколько условных единиц должен показать 16-битный датчик ускорения с пределом измерения ±2g при воздействии на датчик только ускорения свободного падения?:
9,8 м/с2 * 65536 / (2g + 2g) = 9,8 м/с2 * 65536 / (2 * 9,8 м/с2 + 2 * 9,8 м/с2) = 16384 у. е. датчика.

Кстати, если точно знать радиус шара, то можно вычислить центр только по его «дольке». То есть по точкам, которые расположены только на кусочке поверхности шара. Но это не наш случай.

Как ускорить поиск центра шара?


Нужно искать центр не во всём кубе (габариты шара), а по линии, начало у которой произвольное, каждая следующая точка ближе к действительному центру и окончание — в центре. Предположим, что мы начинаем с точки (0; 0; 0)… Мы всегда движемся с постоянным шагом. Поэтому если представить набор кубиков 3х3х3, где каждая грань равна величине шага и также представить, что текущее положение — это средний кубик, то у нас есть 9 + 8 + 9 вариантов, куда поставить следующую точку. Мы просто должны находясь в каждой точке, посчитать в какой из соседних 26 точках ошибка будет меньше. Если окажется, что ошибка меньше в текущей точке, а не в одной из соседних, то значит она стоит в центре и перебор окончен.


Как это может быть в коде
Public Function get_err(A As Double, B As Double, C As Double, R As Double) As Double
Dim x, y, z As Double
Dim sigma As Double
Dim row_n As Long
get_err = 0
For row_n = 1 To 15
    x = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 1).Value
    y = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 2).Value
    z = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 3).Value
    get_err = get_err + abs( (A - x) ^ 2 + (B - y) ^ 2 + (C - z) ^ 2 - R ^ 2 )
Next
End Function

. . .
A = 0
B = 0
C = 0

Do While True
   min_sigma = 0
    For ai = -1 To 1
        For bi = -1 To 1
            For ci = -1 To 1
                sigma = get_err(A + ai, B + bi, C + ci, 16384)
                If sigma < min_sigma Or min_sigma = 0 Then
                    ai_min = ai
                    bi_min = bi
                    ci_min = ci
                    min_sigma = sigma
                End If
            Next
        Next
    Next
    
    If ai_min = 0 And bi_min = 0 And ci_min = 0 Then
        Exit Do
    End If
    
    A = A + ai_min
    B = B + bi_min
    C = C + ci_min
Loop
. . .



Как ещё ускорить поиск центра шара?


Нужно искать с переменным шагом. Сначала ищем центр крупным шагом. Нашли центр, уменьшаем шаг и от него начинаем искать дальше. И так далее, пока не получите результат необходимой точности.
Как это может быть в коде
Public Function get_err(A As Double, B As Double, C As Double, R As Double) As Double
Dim x, y, z As Double
Dim sigma As Double
Dim row_n As Long
get_err = 0
For row_n = 1 To 15
    x = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 1).Value
    y = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 2).Value
    z = Application.ActiveWorkbook.ActiveSheet.Cells(row_n, 3).Value
    get_err = get_err + abs( (A - x) ^ 2 + (B - y) ^ 2 + (C - z) ^ 2 - R ^ 2 )
Next
End Function
. . .
A = 0
B = 0
C = 0
step = 1000
Do While True
   min_sigma = 0
    For ai = -1 To 1
        For bi = -1 To 1
            For ci = -1 To 1
                sigma = get_err(A + ai * step, B + bi * step, C + ci * step, 16384)
                If sigma < min_sigma Or min_sigma = 0 Then
                    ai_min = ai
                    bi_min = bi
                    ci_min = ci
                    min_sigma = sigma
                End If
            Next
        Next
    Next
    If ai_min = 0 And bi_min = 0 And ci_min = 0 Then        
        step = step / 10
        If step < 0.01 Then
            Exit Do
        End If
    Else
    A = A + ai_min * step
    B = B + bi_min * step
    C = C + ci_min * step
    End If
Loop
. . .



Об ошибках при замерах


Во время замеров могут быть ситуации, когда по каким-то причинам результат замера может оказаться сильно дальше от поверхности шара. Или это может быть множество точек. Или вообще в результате замеров может получиться не шар, а “яйцо” или “дирижабль”. В этом случае, разумеется, нужно повторить все замеры, выявив возможные причины ошибок. Например, для магнитометра это может быть болт или гвоздь в столе и прямо над ним вы проводите замеры. И чем ниже по мередиану опускать датчик, тем сильнее металл будет влиять на результат. Поэтому нужно определить порог допустимой величины ошибки. Чтобы не переделывать замеры из-за нескольких явно ошибочных точек, можно применить фильтр. Принцип действия фильтра очень простой — вычислив первый раз центр, отсортируйте точки по уровню ошибки в каждой из них. Часть точек с наибольшей ошибкой можно просто выбросить (например 10%). Затем нужно повторить поиск центра.


Итог


У метода довольно хорошая точность. Метод позволяет обходиться простыми подручными средствами (мяч, банка и т. п.). Достаточно быстро работает. Простой код. Во многих датчиках есть специальные регистры, куда можно записать найденное значение, и датчик будет сам на лету его вычитать. Такие регистры обычно имеют префикс «TRIM», как в MPU9260, или «OFFSET», как в LSM303. А вот всем известный LIS302DL таких регистров не имеет.

Не забывайте ставить плюсик, если понравилось. Пишите в комментариях свои способы калибровки датчиков.

Комментарии (22)


  1. goodwind
    17.09.2015 13:57
    +2

    Классно!
    Данный метод используется для калибровки в Ardupilot. Всегда было интересно как это делается


  1. vasimv
    17.09.2015 15:41

    Магнетометр-то откалибруете, а вот акселерометр так калибровать смысла никакого нет. Как раз потому что он стоит немного неровно. Его калибруют просто поставив коптер на ровную горизонтальную поверхность (желательно с уровнем) — от него требуется держать коптер горизонтально, чтобы дрифта постоянного не было.


    1. 1div0
      17.09.2015 16:13
      +1

      Боюсь Вы не уловили суть. Пожалуйста, обратите особое внимание на текст статьи, начиная со слов «Например, мы знаем, что если акселерометр поставить в уровень с горизонтом...»


      1. vasimv
        17.09.2015 16:21
        +3

        А нафига? Вы хотите сделать уровень электронный, что-ли? Акселерометр нужно калибровать по горизонтальности коптера, а не самого акселерометра или его платы. Это коптер должен быть горизонтален (а не акселерометр), иначе просто будет лететь в сторону наклона.


        1. 1div0
          17.09.2015 18:33

          Хорошо. Представьте, что коптер неподвижно лежит ровно по уровню на земле, а его датчик показывает ускорение, направленное на юго-восток, величиной = 3g.

          Вопрос: что вы, как разработчик коптера, планируете делать с показаниями датчика?


          1. vasimv
            17.09.2015 19:33

            У всех контроллеров на этот случай есть ручная калибровка, они просто запомнят, что нужно -3 вычитать (ставим на ровную поверхность, кликаем на калибровку, контроллер запоминает положение «ноля»). У продвинутых — есть еще и ручные перевороты коптера по определенным осям при калибровке, просто чтобы понять, что контроллер не вверх ногами закреплен.


            1. 1div0
              17.09.2015 21:45

              Представьте, что Вы — это датчик. Вас тянет вправо с силой 10g. Вопрос: где земля?


              1. vasimv
                17.09.2015 21:48

                10g акселерометр не выдаст в спокойном положении.


                1. 1div0
                  17.09.2015 22:00

                  Это чтобы проиллюстрировать суть проблемы. Представьте, что с датчиком всё в порядке. Но он показывает вот так. Как система должна определить — где земля?


                  1. vasimv
                    17.09.2015 22:35
                    +1

                    Во-первых, не покажет. Во-вторых, контроллеру не нужно знать где земля, ему нужно знать что отклонение коптера от горизонтального положения.


                    1. 1div0
                      17.09.2015 23:32

                      Спасибо за Ваше замечание.


                  1. mbrdancer
                    20.09.2015 13:59

                    Да какая разница где земля? Контроллер должен зафиксировать значения в положении, в котором точно известно, что он должен показывать (=g=), — и дальше корректировать свои показания по этим значениям. Ему не надо знать, почему. Ему надо показать в таком же положении ровно такое же =g=. Если его показания линейны, то при отклонении на 0.5g по оси он получит значения, смещенные от «калибровочных» на 0.5g по этой оси. Что, собственно, и нужно.


                    1. 1div0
                      20.09.2015 17:12

                      «Ему надо показать в таком же положении ровно такое же =g=»
                      Господа, статья вообще не об этом. Видимо имеет место различные значения, придаваемые слову «калибровка».

                      Здесь рассматривается задача, с которой не сталкиваются пользователи. Разработчики её решают до того, как изделие к ним попадёт — смещение нуля датчика.


                      1. mbrdancer
                        05.10.2015 16:53

                        Как представитель той самой когорты «разработчиков» смею уверить, что смещение нуля датчика — данные совершенно несущественные (за исключением откровенно лажовых случаев, когда масштаб бедствия намекает на какие-то конкретные ошибки в сборке). Значение для ориентации устройства в пространстве имеет только отклонение от «нормы» по трем осям. Норма должна фиксироваться в собранном виде, ибо никакая сборка в настоящее время не даст точную установку датчика и отсутствие его деформаций.
                        Вопросов должно быть только два: линейность и изотропность показаний в зависимости от смещений, и «нормальное» положение.


                        1. 1div0
                          06.10.2015 23:22

                          Ниже в комментариях некто HomoLuden правильно пишет: "… статья… про компенсацию чисто инструментальной погрешности изготовления и установки датчика на плату контроллера."
                          И это верно.
                          На смещение нуля действительно можно не обращать внимание (если Вас не смущает сдвиг нуля на пару дм/с2), и, как я и пишу в статье, его может скомпенсировать фильтр. Так же как и дрейф нуля.
                          Если Вы под «нормой» понимаете определение некоего опорного направления (например g) — согласитесь, что это другая задача.


        1. 1div0
          18.09.2015 08:47

          Пользователь получает коптер либо с уже откалиброванным датчиком, либо эта процедура вообще не производится и смещение нуля компенсирует фильтр. Вы описываете процедуру определения положения в пространстве по вектору силы тяжести. Это вообще о другом.


  1. wormball
    18.09.2015 01:31

    Центр шара можно найти в одно действие. А именно, он будет лежать на пересечении плоскостей, перпендикулярных отрезкам между точками сферы и проходящих через их центры. Ну или на пересечении перпендикуляров к треугольникам, проведённых через центры их описанных окружностей. Хотя, конечно, всё равно он будет с ошибкой, и надо будет уточнять.

    > Не забывайте ставить плюсик

    Попрошайничать нехорошо.


    1. 1div0
      18.09.2015 10:01

      В таком варианте уже на этапе построения отрезков будет двойной цикл. Кроме того гораздо больше расчётов.


      Про плюсик — это требование. ;-)


  1. mbrdancer
    20.09.2015 14:17

    Вместо жесткой фиксации 10%-ного трешхолда на выбросы я бы использовал кластеризацию. Например, даже с евклидовой метрикой расстояний. При корректной организации измерений нибольший кластер должен оказаться искомым.
    Вопрос использования алгоритма K-means при этом осложняется необходимостью задания K — количества кластеров. Но это вполне можно обойти многократным прогоном с возрастающими K. В определенный момент искомый кластер начнет дробиться на более мелкие — это можно отследить.


    1. 1div0
      20.09.2015 17:41

      Это может быть эффективней. Только нужно подумать, что брать за расстояние? И в какой момент нам понять, что замеры прошли неудачно? К примеру если отфильтрована четверть точек — это ещё хорошо или уже нет? А если половина? А если оставшиеся точки сгруппированы только в одной половине сферы?


  1. HomoLuden
    02.10.2015 11:28

    Например, если перевести типичную величину смещения нуля для акселерометра датчика MPU9250 в м/с2, то это получается в районе 0,2 м/с2. Т. е. датчик неподвижен, но при этом показывает ускорение, а через 5 секунд мы получаем скорость в 1 м/с. С одной стороны, все данные датчиков всегда пропускают через какой-либо фильтр (например такой). Но с другой стороны зачем фильтру постоянно компенсировать это смещение? Ведь датчик будет показывать движение там, где его нет. Это снижает точность результата. А всего то нужно один раз найти величину смещения и потом во время работы датчика вычитать эту величину из его показаний.


    Спешу расстроить, но дрейф MEMS датчиков (гироскопов особенно, но и акселерометры страдают в значительной степени) величина случайная. Она меняется во время работы и между запусками. Калибровать нужно непосредственно перед запуском, т.к. играет роль величина питающего напряжения, температура и другие факторы текущих условий эксплуатации.

    Я понял про что статья. Она про компенсацию чисто инструментальной погрешности изготовления и установки датчика на плату контроллера. Но эта задача, во-первых, теряет актуальность в изложенном виде в виду сложности проведения такой калибровки в поле (если принять факт, что дрейф меняется). А во-вторых, на практике важнее знать, что нужно вычесть из показаний датчика, чтобы при абсолютно горизонтальном положении коптера (всего БПЛА, а не платы с контроллером) акселерометр выдавал {0;0;g}.


    1. 1div0
      03.10.2015 22:29

      Статья действительно про компенсацию чисто инструментальной погрешности изготовления и установки датчика на плату. Предполагается, что компенсация выявляется на этапе изготовления один раз, но метод настолько прост, что можно это сделать и в поле. Для потребителей это действительно не актуально.
      Про дрейф нуля гироскопа — это отдельная история. Установка горизонта — тоже отдельная история, не имеющая отношения к данной статье.