Преобразование трехосевого магнитометра в Градусы
Я не знаю, является ли здесь лучшим местом для публикации этого вопроса. У меня есть датчик 9-DOF (MPU 9150), и я хочу использовать его магнитометр для определения угла поворота от 0 до 359. Однако его библиотека возвращает три значения: x, y и z.
Я не знаю, как преобразовать это в одно значение. Есть ли какой-нибудь способ сделать это?
@Guilherme, 👍12
Обсуждение4 ответа
Лучший ответ:
Ответ, данный Дэйвом Икс, а именно
az=90-atan(y/x)*180/pi
находится на правильном пути. Однако он не может работать как есть по двум причинам:
Формула плохо работает всякий раз,когда x = 0,
Он дает один и тот же азимут для x = y = 1 и для x = y = -1. Другими словами, он не может провести различие между северо-востоком и юго-западом.
Формула может быть исправлена путем замены atan(y/x)
функцией, которая
возвращает:
- atan(y/x), если x > 0
- π/2, если x = 0 и y > 0
- −π/2, если x = 0 и y < 0
- atan(y/x) + π, если x < 0 и y ≥ 0
- atan(y/x) − π, если x < 0 и y < 0
Это была бы, по существу, двух аргументная, “квадрантно-ориентированная” версия арктангенса, дающая результаты в (-π, π] вместо (−π/2, π/2).
К счастью, такая функция уже существует. Это очень стандартная
функция библиотеки C и называется atan2()
. Таким образом, правильная
формула такова:
az = 90 - atan2(y, x) * 180 / M_PI;
Теперь, поскольку atan(y/x) = π/2 − atan(x/y), приведенную выше формулу можно упростить до
az = atan2(x, y) * 180 / M_PI;
Эта формула дает направление вектора (x, y), отсчитываемого по часовой стрелке от оси y. Вполне вероятно, что ОП хочет вместо этого узнать курс какого-то транспортного средства. Правильная формула зависит от того, как магнитометр установлен относительно автомобиля. Если предположить , что ось x магнитометра направлена вперед, а ось y -влево, то:
- транспортное средство движется на север (магнитный курс 0°), когда горизонтальная составляющая магнитного поля находится вдоль +x
- транспортное средство движется на восток (магнитный курс 90°), когда горизонтальная составляющая магнитного поля находится вдоль +y
Отсюда следует, что курс транспортного средства
heading = atan2(y, x) * 180 / M_PI;
Очевидно, что магнитное склонение должно быть добавлено, если вас интересует истинный (а не магнитный) курс.
Edit: Все это предполагает, что плоскость XY горизонтальна. Если это не так (из-за тангажа и крена автомобиля), обратитесь к ответу Tails86, чтобы узнать, как справиться с этим.
Это элементарная математическая задача.
az=90-atan(y/x)*180/pi
"atan()" является арктангенсом и преобразует из переменных координат угол в радианах, *180/pi преобразует из радианов в градусы, а 90 - преобразует из градусов математические углы (градусы CCW от оси x) в азимут (градусы CW от севера).
Калибровка датчика-более сложная проблема.
Сначала вам нужна калибровка (либо с помощью метода калибровки устройства, либо вращая его по полному кругу, чтобы определить полную напряженность поля).
Затем вы можете использовать показания X, Y и Z для вычисления местоположения "севера" относительно того, куда вы указываете (имея в виду, что "север" меняется на 30 градусов в зависимости от того, где вы находитесь на земле (так называемое склонение - см. http://www.magnetic-declination.com/), и что это также не горизонтально к земле (смутно называемое "наклоном" - см. https://physics.stackexchange.com/questions/283761/if-you-hold-a-compass-needle-vertical-does-it-point-down-or-up-differently-on-wh/283782 )
Если вы представите показания X, Y и Z как означающие "где на воображаемом круге находится направление магнетизма - где эти 3 круга находятся в 3 разных плоскостях, вы можете вычислить логическое положение вектора, указывающего на магнитный север в 3 измерениях.
Плохая новость - нет простого способа сделать то, что вы хотите точно, и определенно не тот, который будет работать без тригонометрической математики на всех 3 чтениях (вы не можете просто использовать X и/или Y в одиночку).
Хорошая новость - вам, вероятно, на самом деле не нужно знать фактический "заголовок" - большинству приложений просто нужно некоторое локальное относительное направление по сравнению с тем, что вы уже знаете.
Остерегайтесь, что сильные магниты (например, во всех современных двигателях) серьезно мешают показаниям с большого расстояния (даже 10 или более футов) - возьмите приложение из своего телефонного магазина, которое показывает показания магнитометра вашего телефона, и помашите магнитом, чтобы легко это увидеть!
Я хотел бы подробнее рассказать о том, к чему клонит Anon, и привести некоторую математику, поскольку я только что прошел через этот процесс для аналогичного 9-осевого устройства.
Во-первых, полезно знать, что означает вектор магнитного поля. Мне нравится этот источник, потому что он дает изображение, показывающее, куда указывают магнитные векторы при движении вверх и вниз по земле. Она указывает вниз в северном полушарии и вверх в южном. В остальном текст не имеет отношения к делу, поскольку он более или менее просто объясняет, как вы можете аппроксимировать положение laitudinal из этих данных - угол горизонтальной составляющей-это все, что нам нужно знать, чтобы получить заголовок.
Проблема с ответом Эдгара заключается в том, что он предполагает, что ваша опорная плоскость плоская относительно земли. Как только вы добавите какой-либо шаг или бросок, этот ответ будет неправильным. Чтобы исправить это, вам нужно спроецировать вектор магнитного поля на горизонтальную плоскость. К счастью, этот датчик также предоставляет вам акселерометр, который позволяет определить, какой путь вниз из-за силы тяжести, если вы не двигаетесь слишком быстро.
Я проецировал вектор магнитного поля на вектор ускорения, а затем вычитал его из вектора магнитного поля, чтобы получить вектор горизонтальной компоненты. Тогда я мог бы получить вектор угла на плоскости X/Y точно так же, как описано другими.
// Облегченное определение 3D-вектора, поэтому я не завишу от внешних библиотек
class Vector3D
{
public:
Vector3D() : mArr{} {}
Vector3D(double x, double y, double z)
{
mArr[0] = x;
mArr[1] = y;
mArr[2] = z;
}
double dot(const Vector3D& rhs) const
{
double out = 0;
for (int i = 0; i < NUM_DIMENSIONS; ++i)
{
out = out + mArr[i] * rhs.mArr[i];
}
return out;
}
Vector3D operator* (double x) const
{
Vector3D out;
for (int i = 0; i < NUM_DIMENSIONS; ++i)
{
out.mArr[i] = mArr[i] * x;
}
return out;
}
Vector3D operator- (const Vector3D& x) const
{
Vector3D out;
for (int i = 0; i < NUM_DIMENSIONS; ++i)
{
out.mArr[i] = mArr[i] - x.mArr[i];
}
return out;
}
double getX() const {return mArr[0];}
double getY() const {return mArr[1];}
double getZ() const {return mArr[2];}
private:
static const int NUM_DIMENSIONS = 3;
double mArr[NUM_DIMENSIONS];
};
Vector3D operator* (double x, const Vector3D& y)
{
return (y * x);
}
// mag: магнитный вектор
// accel: вектор ускорения (под действием силы тяжести)
double computeYaw(double mag_x, double mag_y, double mag_z, double accel_x, double accel_y, double accel_z)
{
const Vector3D vector_mag(mag_x, mag_y, mag_z);
const Vector3D vector_down(accel_x, accel_y, accel_z);
const Vector3D vector_north = vector_mag - ((vector_mag.dot(vector_down) / vector_down.dot(vector_down)) * vector_down);
return atan2(vector_north.getX(), vector_north.getY()) * 180 / M_PI;
}
EDIT: я изменил код, чтобы здесь были определены необходимые элементы вектора, чтобы не было путаницы.
tf2/LinearMath/Vector3.h: Такого файла или каталога нет. Есть ссылка на библиотеку?, @VE7JRO
Очень хорошая мысль! Обратите внимание, что: 1. Если платформа движется, мы можем получить лучшую оценку вертикали, объединив данные акселерометра с данными гироскопа. 2. Для повышения точности atan2()
следует подавать компонентами намагниченности в горизонтальной плоскости, а не в плоскости XY платформы., @Edgar Bonet
Эдгар - Это действительно большая проблема с этой реализацией. Любые небольшие движения исказят результат. Я обнаружил, что усреднения результата по 20 образцам было достаточно, чтобы сгладить его для моих собственных нужд, поскольку я имею дело с медленно движущимся устройством., @Tails86
Есть ли какая-нибудь библиотека с открытым исходным кодом, которая реализует всю математику статьи, связанной во втором редактировании?, @Guilherme
- В чем разница между акселерометром, гироскопом и датчиком магнитометра?
- Проблема с кодом для мультиплексора SDA/SCL TC9548A и датчиков HMC58 83L.
- MPU-9250 IMU на SPI, внешнем датчике или магнитометре с использованием мастера I2C
- Как прочитать необработанные данные с модуля GY-85?
- Компас с компенсацией наклона Adafruit_LSM303
- Почему неправильно указывает направление компаса, используя показания магнитометра?
- Как отфильтровать или исключить показания магнитного поля Земли вокруг 3D-магнитного датчика?
- Компас MPU-9250 всегда возвращается к нулю
Он дает вам вектор, который проходит вдоль локального магнитного поля - в идеале он указывает на магнитный север. Отображение вращения между измерением и магнитным севером должно дать вам ваш курс., @BrettAM
Чтение таблицы данных может быть очень поучительным. Вы пробовали это сделать?, @Majenko
@Majenko Да, но ничего действительно полезного., @Guilherme
Итак, возможно ли вычислить курс (с компенсацией наклона) только с помощью магнитометра (без гирометра или акселерометра)?, @Max