Направление по компасу не изменяется линейно

Я использую магнитометрический компас HMC-5983 на своем Arduino Uno, чтобы определить направление строящегося автомобиля. Но показания моего компаса не меняются линейно. Например, когда я поворачиваю компас на 90 градусов, изменение показаний не соответствует 90 градусам. Я попытался сопоставить необработанные выходные данные компаса с фактическим направлением, но когда я это делаю, направления между точками, которые я нанес на карту, недостаточно точны, что приводит к тому, что моя машина ведет себя ненормально. Я также искал в Google, но не нашел ничего полезного, хотя было упоминание об использовании алгоритма для решения этой проблемы. Пожалуйста, помогите мне решить эту проблему.

    #include <Wire.h> //Библиотека I2C Arduino
#define Magnetometer_mX0 0x03  
#define Magnetometer_mX1 0x04  
#define Magnetometer_mZ0 0x05  
#define Magnetometer_mZ1 0x06  
#define Magnetometer_mY0 0x07  
#define Magnetometer_mY1 0x08  
int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;
float heading, headingDegrees, headingFiltered, declination;
float Xm,Ym,Zm;
#define Magnetometer 0x1E // 7-битный адрес I2C HMC5883
void setup(){
  // Инициализация последовательной связи и связи I2C
  Serial.begin(9600);
  Wire.begin();
  delay(100);

  Wire.beginTransmission(Magnetometer); 
  Wire.write(0x02); // Регистр выбора режима
  Wire.write(0x00); // Непрерывный режим измерения
  Wire.endTransmission();
}
void loop(){

//---- ось X
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mX1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
    if(Wire.available()<=1)   
  {
    mX0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mX0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mX1 = Wire.read();
  }
  //---- ось Y
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mY1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mY0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mY1 = Wire.read();
  }

  //---- ось Z
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mZ1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ0 = Wire.read();
  }
  Wire.beginTransmission(Magnetometer); // передать на устройство
  Wire.write(Magnetometer_mZ0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer,1); 
  if(Wire.available()<=1)   
  {
    mZ1 = Wire.read();
  }

  //---- ось X
  mX1=mX1<<8;
  mX_out =mX0+mX1; // Необработанные данные
  // Из таблицы данных: 0,92 мГ/разр.
  Xm = mX_out*0.00092; // Единица Гаусса
  //* Магнитное поле Земли колеблется от 0,25 до 0,65 Гаусса, так что это значения, которые нам нужно получить приблизительно.
  //---- ось Y
  mY1=mY1<<8;
  mY_out =mY0+mY1;
  Ym = mY_out*0.00092;
  //---- ось Z
  mZ1=mZ1<<8;
  mZ_out =mZ0+mZ1;
  Zm = mZ_out*0.00092;
  // ===============================
  //Вычисление заголовка
  heading = filtered_angle(Zm, Xm);// арктангенс z/x

  // Коррекция курса с углом склонения в зависимости от вашего местоположения
  // Вы можете найти свой угол склонения по адресу: http://www.ngdc.noaa.gov/geomag-web/
  // В моем местоположении 4,2 градуса => 0,073 рад
  declination = 0.03717551307 ;
  heading += declination;

  // Исправление при перепутывании знаков
  if(heading <0) heading += 2*PI;
  // Исправление за счет добавления угла склонения
  if(heading > 2*PI)heading -= 2*PI;
  headingDegrees = heading * 180/PI; // Заголовок в градусах
  // Сглаживание выходного угла / Фильтр нижних частот
  headingFiltered = headingDegrees;
  //Отправка значения заголовка через последовательный порт в Processing IDE

  if(headingFiltered >= 0 && headingFiltered <= 89){
                c_head=map(headingFiltered,0,90,270,359);
        }   
    if(headingFiltered > 89 && headingFiltered <= 204){
                c_head=map(headingFiltered,90,204,0,90);
        }     
    if(headingFiltered > 204 && headingFiltered <= 290){
                c_head=map(headingFiltered,205,290,91,180);
        }         
      if(headingFiltered > 290){
               c_head=map(headingFiltered,291,359,181,269);
        }   




// Serial.print("Градусы - ");
 Serial.println(headingDegrees);
delay(500);
}

float filtered_angle(float p, float q) {
         const float filter_constant = 0.15;
         static float q_f, p_f; // отфильтрованные компоненты
         q_f += filter_constant * (q - q_f);
         p_f += filter_constant * (p - p_f);
         return atan2(p, q); 
        }

, 👍0

Обсуждение

Можете ли вы дать нам таблицу с градусами, которые вы вращали, и градусами, которые вы измеряли ими?, @chrisl

Вы применяете нелинейное (кусочно-линейное, с map()) преобразование в своем коде. Зачем ты это делаешь? Почему вы ожидаете, что ваше нелинейное преобразование даст линейный результат?, @Edgar Bonet


1 ответ


Лучший ответ:

0

Если вы не можете найти и устранить системную ошибку, например наличие рядом источников железа, магнитных или электромагнитных полей, вызывающих наблюдаемые вами ошибки, вам придется сделать то, что навигаторы делали веками: качать компас.

Движение компаса включает в себя перемещение транспортного средства (т. е. вашего робота-автомобиля) куда-нибудь подальше от внешних источников ошибок (электропроводка здания, железо/стальные массы и т. д.) и выполнение ряда измерений, направляя транспортное средство в нескольких направлениях. известен средствами, независимыми от его собственного компаса. Например, с лодкой вы выбираете известное место посреди гавани и проводите линию от этого известного положения до каждого ориентира (для автомобиля вы можете использовать большое игровое поле). Это дает вам истинный азимут (азимут относительно северного полюса) от выбранного положения до ориентира. Составьте список этих ориентиров и их истинных направлений в столбцах 1 и 2. 2 листа бумаги, по часовой стрелке, начиная с истинного севера.

Преобразуйте истинные азимуты в магнитные азимуты (относительно направления от того места, где вы сейчас находитесь, к северному магнитному полюсу Земли). На навигационных картах будет показана разница (в градусах) между истинными азимутами и магнитными азимутами для местоположения (мест). покрывается этой диаграммой; разница называется «вариацией» (иногда ее называют склонением). Если магнитное склонение в вашем местоположении западное (соответствует 15 градусам западной долготы истинного севера, f/ex), добавьте это значение к только что перечисленным пеленгам. Третий столбец чисел представляет собой магнитный азимут каждого из этих ориентиров и значение, которое должен показывать безошибочный компас.

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

Столбцы 3 и amp; 4 теперь являются таблицей коррекции компаса. Когда компас считывает число в столбце 4 (азимут по компасу), фактическим (скорректированным) магнитным курсом является соответствующее число в столбце 3 (магнитный курс).

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

  1. Найдите пару азимутов в столбце 4, направления по компасу, которые заключают в скобки показания, которые вы только что получили.
  2. Найдите процент разницы показаний брекетинга компаса.
  3. Примените тот же процент к разнице между соседними магнитными азимутами в столбце 3, чтобы найти фактический магнитный азимут.

Я довольно быстро упустил процесс интерполяции, так как вопрос был о корректировке компаса. Интерполяция или другие способы внесения поправок — это отдельная тема, но функция Arduino map() будет здесь очень кстати. Кроме того, чем больше значений поправок (ориентиров) вы используете для составления таблицы и чем более равномерно они распределены по компасу, тем точнее будут ваши поправки.

,

Спасибо. Это сработало довольно хорошо. Для этого я использовал оператор управления регистром switch и функцию map()., @AfiJaabb