Мозг помогает человеку достаточно хорошо ориентироваться в окружающем пространстве. К сожалению, у роботов человеческого мозга нет, поэтому им нужно каким-либо другим образом "чувствовать" свое направление движения чтобы они могли автономно передвигаться по новой для них местности. Для преодоления этой проблемы роботы используют множество разнообразных датчиков, однако чаще всего для этой цели используется магнитометр, который может информировать робота в каком направлении он передвигается (или развернут лицом). Это помогает роботу не только чувствовать направление движения, но и давать ему команды для поворота на заранее определенный угол или в определенном направлении.
В этой статье мы рассмотрим как работает магнитометр и как его подключить к плате Arduino. На основе магнитометра и платы Arduino мы спроектируем цифровой компас, на котором горящий светодиод будет указывать направление на север. Схему компаса мы распаяли на печатной плате, изготовленной в компании PCBGOGO.
Необходимые компоненты
- Плата Arduino Pro mini (купить на AliExpress).
- Магнитометр (Magnetometer sensor) HMC5883L (купить на AliExpress).
- Светодиоды – 8 шт. (купить на AliExpress).
- Резисторы 470 Ом – 8 шт. (купить на AliExpress).
- Разъем типа Barrel Jack.
- Изготовленная печатная плата.
- FTDI программатор.
- Компьютер/ноутбук.
Что такое магнитометр и как он работает
Надеемся, что слово магнитометр не ассоциируется у вас с мутантом по имени "Магнето" из популярной киноэпопеи "Люди Х" – но он там был реально крут, не правда ли? ))
На самом деле магнитометр представляет собой устройство, которое может ощущать ("чувствовать") магнитные полюса Земли и указывать направление к ним. Все мы знаем что Земля представляет собой огромный сферический магнит с северным и южным полюсами. Естественно, этот огромный магнит создает магнитное поле. Магнитометр улавливает (ощущает) это магнитное поле и на основании направления этого магнитного поля он может определять направление (в котором мы смотрим или развернуты лицом).
Как работает датчик (магнитометр) HMC5883L
Датчик (магнитометр) HMC5883L содержит в своем составе микросхему HMC5883L от компании Honeywell. Эта микросхема содержит внутри себя 3 магниторезистивных материала, которые упорядочены (ориентированы) по осям x, y и z. Количество тока, протекающего через эти материалы, чувствительно к магнитному полю Земли. То есть, измеряя изменения в токе, протекающем через эти материалы, мы можем обнаруживать изменения в магнитном поле Земли. В дальнейшем эти изменения можно передать любому микроконтроллеру (например, плате Arduino) по протоколу I2C.
Поскольку показания данного датчика основаны на величине магнитного поля, то на них в значительной степени будут влиять расположенные рядом металлические предметы. Поэтому иногда данные датчики используются в детекторах металла. Но если вы будете использовать магнитометр в составе компаса следите чтобы рядом с ним не было крупных металлических предметов, иначе показания компаса будут неправильными – надеюсь, все помнят фильм про пятнадцатилетнего капитана и как его обманули с показаниями компаса.
Разница между HMC5883L и QMC5883L
Некоторые поставщики радиодеталей продают датчики QMC5883L (они изготавливаются той же самой компанией Honeywell) вместо HMC5883L поскольку QMC5883L стоят дешевле. Печальная новость здесь состоит в том, что работа этих двух датчиков немного отличается и один и тот же программный код не будет работать с обоими этими датчиками. Поэтому и адрес в протоколе I2C у них будет различный. Код программы, приведенный в нашей статье, будет работать только с QMC5883L – он более дешевый и его проще достать.
Чтобы узнать какая модель датчика у вас, HMC5883L или QMC5883L, посмотрите поближе что на нем написано. Если на нем написано что то вроде L883, то это HMC58836L, а если написано что то вроде DA5883, то это QMC5883L. Внешний вид обоих этих модулей показан на следующем рисунке.
Работа схемы
Схема цифрового компаса на основе платы Arduino и магнитометра HMC5883L представлена на следующем рисунке.
Как видите, схема достаточно проста. Нам просто необходимо подключить датчик HMC5883L к плате Arduino и соединить 8 светодиодов с контактами платы Arduino Pro mini.
Магнитометр HMC5883L имеет 5 контактов. Его контакт DRDY (Data Ready) мы не будем использовать поскольку в нашем проекте датчик будет работать в непрерывном режиме. Контакты Vcc и ground (земля) датчика используются для питания модуля от платы Arduino. Контакты SCL и SDA используются для связи по протоколу I2C и подключены к контактам A4 и A5 (которые также являются контактами для связи по протоколу I2C) платы Arduino Pro mini. Поскольку контакты датчика имеют внутренние подтягивающие резисторы, то нет необходимости добавлять в схему внешние подтягивающие резисторы.
Для индикации направления в проекте мы используем 8 светодиодов, подключенных к контактам платы Arduino с помощью ограничивающих ток резисторов сопротивлением 470 Ом. Схема запитывается от батарейки 9V через переходник типа barrel Jack – на фотографиях хорошо видно что он из себя представляет. Эти 9V попадают на контакт Vin платы Arduino, затем с помощью встроенного регулятора платы Arduino это напряжение понижается до 5V, которое и используется для питания нашей схемы.
Изготовление печатной платы для цифрового компаса
Основная идея проекта состоит в том, чтобы расположить 8 светодиодов по периметру круга на плате. Каждый из этих светодиодов будет обозначать свое направление. Соответственно, будет 8 направлений – Север, Северо-Восток, Восток, Юго-Восток, Юг, Юго-Запад, Запад и Северо-Запад. На перфорированной плате красиво расположить эти светодиоды достаточно затруднительно, поэтому мы использовали печатную плату. Файлы разработанной для этого проекта печатной платы можно скачать по следующей ссылке - Gerber файл для проекта цифрового компаса.
Когда дизайн печатной платы готов можно приступать к ее изготовлению. Для этого необходимо выполнить следующую последовательность шагов.
Шаг 1. Перейдите по адресу https://www.pcbgogo.com/?code=t, зарегистрируйтесь там если это ваше первое посещение. Затем на вкладке PCB Prototype введите размеры вашей печатной платы, число ее слоев и какое количество печатных плат вам необходимо. Мы использовали размер печатной платы 80mm×80mm.
Шаг 2. Нажмите на кнопку Quote Now (рассчитать цену сейчас). После этого вас перебросит на страницу, где вам будет необходимо ввести дополнительные параметры печатной платы: материал, цвет и т.д. Обычно значения, выставленные на этой странице по умолчанию, работают превосходно. Единственное, на что вам обязательно необходимо обратить внимание – это на цену и на время изготовления. Для наших плат стоимость составила $5 и время изготовления 2-3 дня. Также вы можете выбрать удобный для себя вид доставки.
Шаг 3. Загрузите в сервис свои Gerber файлы и оплатите заказ. После загрузки сервис PCBGOGO проверяет ваши Gerber файлы на корректность.
Разумеется, мы не настаиваем, чтобы вы заказывали печатную плату именно в PCBGOGO, вы можете заказать ее у любого производителя печатных плат, с которым вы привыкли работать.
Сборка печатной платы
Нам платы пришли в отличном состоянии, их внешний вид вы можете посмотреть на следующих рисунках.
Нам понадобилось около 10 минут чтобы припаять к плате необходимые компоненты, после этого мы получили следующий вид нашей платы:
Объяснение программы для Arduino
Основная цель работы программы – считать данные с магнитометра QMC5883L и преобразовать их в градусы (от 0 до 360). А когда мы будем знать градусы мы легко сможем определить светодиод, который нужно зажечь чтобы указать нужное направление. Мы в нашем проекте будем указывать направление на север – вы можете изменить это по своему желанию, внеся изменения в код программы. То есть горящий светодиод у нас будет указывать направление на север.
Полный код программы приведен в конце статьи, здесь же мы рассмотрим его основные фрагменты.
Мы используем микросхему магнитометра QMC5883L, для взаимодействия с ней нам необходимо знать I2C адрес ее регистров, который можно найти в даташите. Но к счастью, как говорится "все уже сделано за нас" и на Github можно скачать готовую библиотеку для работы с QMC5883L. По этой ссылке вы скачаете ZIP файл, который затем можно добавить в вашу Arduino IDE открыв там пункт меню Sketch -> Include Library -> Add .ZIP library.
После добавления библиотеки мы можем приступать к написанию программы. Первым делом нам в программе необходимо подключить используемые библиотеки – библиотека wire используется для осуществления связи по протоколу I2C, а MechaQMC5883 – для работы с магнитометром (ее мы только что добавили в Arduino IDE).
1 2 |
#include <Wire.h> //Wire Librarey for I2C communication #include <MechaQMC5883.h> //QMC5883 Librarey is added since mine is QMC583 and not HMC5883 |
Далее мы создадим объект для работы с магнитометром – мы использовали для него имя qmc.
1 |
MechaQMC5883 qmc; //Create an object name for the snsor, I have named it as qmc |
Далее мы объявим глобальные переменные. Для управления 8 светодиодами мы будем использовать массив ledPins, переменная led_count будет обозначать общее количество используемых нами светодиодов – поскольку нумерация элементов массива начинается с 0, то значение этой переменной равно 0.
1 2 |
int ledPins[] = {2,3,4,5,6,7,8,9}; //массив выходных контактов к которым подключены светодиоды char led_count = 7; //общее число светодиодов |
Внутри функции void setup мы инициализируем связь по протоколу I2C, последовательную связь и магнитометр (датчик). Затем мы зададим режим работы на вывод данных для всех контактов, к которым подключены светодиоды. Поскольку мы используем массив, то нам будет достаточно просто обращаться ко всем этим контактам с помощью цикла.
1 2 3 4 5 6 7 8 9 |
void setup() { Wire.begin(); //инициализация связи по протоколу I2C Serial.begin(9600); //инициализация последовательной связи qmc.init(); //инициализация датчика QMC5883 for (int thisPin=0; thisPin <= led_count; thisPin++){ //навигация по всем контакам в массиве pinMode(ledPins[thisPin],OUTPUT); //задаем им режим работы на вывод данных } } |
В основном цикле loop, который является бесконечным по сути, мы считываем значения x, y и z с датчика и рассчитываем угол в градусах, на который повернут датчик. Для считывания значений x, y и z мы используем следующие строчки кода:
1 2 |
int x,y,z; qmc.read(&x,&y,&z); //считываем значения X,Y и Z с датчика |
В следующем фрагменте кода мы рассчитываем нужное нам направление в градусах. Поскольку нам не нужно вращать компас по оси z мы это значение можем не учитывать. Приведенную в программе формулу для расчета направления в градусах можно использовать только если наш компас ориентирован строго параллельно земле. После расчета направления (heading) по приведенной формуле его значение будет в диапазоне от -180 до 180, которое мы должны преобразовать в диапазон от 0 до 360, привычный для обычного компаса.
1 2 3 4 5 |
int heading=atan2(x, y)/0.0174532925; //рассчитываем направление в градусах используя значения X и Y //преобразуем результат в диапазон от 0 до 360 if(heading < 0) heading+=360; heading = 360-heading; |
Заключительный шаг – это зажечь светодиод, который указывает на север. Для этого мы будем использовать несколько условий с помощью оператора if чтобы проверить в каком диапазоне находится рассчитанное в градусах направление и в зависимости от этого уже зажечь нужный светодиод.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// в зависимости от значения рассчитанного направления печатаем результат (для отладки) и зажигаем соответствующий светодиод if (heading > 338 || heading < 22) { Serial.println("NORTH"); digitalWrite(ledPins[0],HIGH); } if (heading > 22 && heading < 68) { Serial.println("NORTH-EAST"); digitalWrite(ledPins[7],HIGH); } if (heading > 68 && heading < 113) { Serial.println("EAST"); digitalWrite(ledPins[6],HIGH); } if (heading > 113 && heading < 158) { Serial.println("SOUTH-EAST"); digitalWrite(ledPins[5],HIGH); } if (heading > 158 && heading < 203) { Serial.println("SOUTH"); digitalWrite(ledPins[4],HIGH); } if (heading > 203 && heading < 248) { Serial.println("SOTUH-WEST"); digitalWrite(ledPins[3],HIGH); } if (heading > 248 && heading < 293) { Serial.println("WEST"); digitalWrite(ledPins[2],HIGH); } if (heading > 293 && heading < 338) { Serial.println("NORTH-WEST"); digitalWrite(ledPins[1],HIGH); } |
Логика работы представленного фрагмента кода определяется следующей таблицей.
Направление | Градусы, соответствующие направлению | Диапазон градусов для нашего компаса |
Север | 0° / 360° | >338° или < 22° |
Северо-Восток | 45° | 22°-68° |
Восток | 90° | 68°-113° |
Юго-Восток | 135° | 113°-158° |
Юг | 180° | 158°-203° |
Юго-Запад | 225° | 203°-248° |
Запад | 170° | 248°-293° |
Северо-Запад | 315° | 293°-338° |
В заключительной части программы мы должны определить как часто должны обновляться результаты. Мы использовали задержку в 500 миллисекунд, но вы можете изменить ее по своему желанию.
1 2 3 4 5 |
delay(500); // обновляем позицию светодиода каждые полсекунды //выключаем все светодиоды for (int thisPin=0; thisPin <= led_count; thisPin++){ digitalWrite(ledPins[thisPin],LOW); } |
Тестирование работы компаса
Поскольку мы используем плату Arduino pro mini нам будет необходим какой-нибудь внешний программатор чтобы загрузить в нее программу. Мы использовали в качестве программатора плату FTDI. После загрузки программы в плату Arduino вы увидите что в нашей собранной схеме загорится один из светодиодов – он будет указывать на север.
После этого вы можете изменять ориентацию платы и наблюдать как меняются горящие светодиоды. Более подробно все эти процессы вы можете посмотреть на видео, приведенном в конце статьи. Вы также можете наблюдать как компас будет показывать неправильное направление на север если рядом с ним находится тяжелый металлический предмет или если вы будете вращать плату вдоль оси Z. Эти трудности в работе компаса можно преодолеть, но это уже материал для другой статьи.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/* * Program for Arduino Digital Compass using QMC5883 * Project by: Aswinth Raj * Dated: 1-11-2018 * Website: http://www.circuitdigest.com/ * Lib. from https://github.com/keepworking/Mecha_QMC5883L * WARNING: This code works only for QMC5883 Sensor which is commonly being sold as HMC5883 read article to find the actual name of the sensor you have. */ #include <Wire.h> //библиотека для работы по протоколу I2C #include <MechaQMC5883.h> //библиотека QMC5883 для работы с датчиком QMC583, но не с HMC5883 MechaQMC5883 qmc; //создаем объект для работы с датчиком (магнитометром), даем ему имя qmc int ledPins[] = {2,3,4,5,6,7,8,9}; // массив выходных контактов, к которым подключены светодиоды char led_count = 7; //общее число используемых контактов для светодиодов void setup() { Wire.begin(); //старт связи по протоколу I2C Serial.begin(9600); //старт последовательной связи со скоростью 9600 qmc.init(); //инициализация датчика QMC5883 for (int thisPin=0; thisPin <= led_count; thisPin++){ //навигация по всем контактам в массиве pinMode(ledPins[thisPin],OUTPUT); //задаем им режим работы на вывод данных } } void loop() { //бесконечный цикл int x,y,z; qmc.read(&x,&y,&z); //считываем значения X, Y и Z с датчика int heading=atan2(x, y)/0.0174532925; // рассчитываем направление в градусах используя значения X и Y //преобразуем результат в диапазон от 0 до 360 if(heading < 0) heading+=360; heading = 360-heading; Serial.println(heading); //передаем значение направления в последовательный порт связи для целей отладки //в зависимости от значения рассчитанного направления печатаем результат (для отладки) и зажигаем соответствующий светодиод if (heading > 338 || heading < 22) { Serial.println("NORTH"); digitalWrite(ledPins[0],HIGH); } if (heading > 22 && heading < 68) { Serial.println("NORTH-EAST"); digitalWrite(ledPins[7],HIGH); } if (heading > 68 && heading < 113) { Serial.println("EAST"); digitalWrite(ledPins[6],HIGH); } if (heading > 113 && heading < 158) { Serial.println("SOUTH-EAST"); digitalWrite(ledPins[5],HIGH); } if (heading > 158 && heading < 203) { Serial.println("SOUTH"); digitalWrite(ledPins[4],HIGH); } if (heading > 203 && heading < 248) { Serial.println("SOTUH-WEST"); digitalWrite(ledPins[3],HIGH); } if (heading > 248 && heading < 293) { Serial.println("WEST"); digitalWrite(ledPins[2],HIGH); } if (heading > 293 && heading < 338) { Serial.println("NORTH-WEST"); digitalWrite(ledPins[1],HIGH); } delay(500); // обновление данных каждые полсекунды //выключаем все светодиоды for (int thisPin=0; thisPin <= led_count; thisPin++){ digitalWrite(ledPins[thisPin],LOW); } } |
Не понял, для чего ссылка на Необходимые компоненты: Магнитометр (Magnetometer sensor) HMC5883L (купить на AliExpress), если в проекте используется QMC5883L, но при этом представлена Работа схемы
цифрового компаса на основе платы Arduino и магнитометра HMC5883L? Да и к чему описание Как работает датчик HMC5883L, если Разница между HMC5883L и QMC5883L не раскрыта , кроме стоимости.
Илья, просто раньше по моей ссылке "купить на AliExpress" продавались и HMC5883L, и QMC5883L. Сейчас же, судя по всему, в этом магазине остались только HMC5883L. За всеми этими ссылками у меня нет возможности постоянно следить, я же не принуждаю никаким образом покупать именно по моей ссылке - по ней вы можете посмотреть ориентировочную цену товара (не гарантирую что она самая низкая потому что конъюнктура цен постоянно меняется), а затем сами на AliExpress выбрать себе наиболее выгодный вариант для покупки на текущий момент.
Разница между HMC5883L и QMC5883L полностью не раскрыта, но статья же не претендует на абсолютную полноту. Подключение их аналогичное, но код программы необходимо будет немного изменить
быстрее, точнее, надёжнее.. а старый ещё от температуры зависит
для тебя разницы нет, у них только i2c адрес разный
Хорошо, спасибо за пояснение
Ищу контакты программиста для реализации несложной задачки. Москва.
Удачи, Константин. Но аудитория моего сайта пока еще, к сожалению, достаточно мала чтобы объявления такого рода были успешными. В дальнейшем, если аудитория сайта увеличится, конечно же создам форум где можно будет размещать объявления подобного вида. Ну а пока что попрошу не спамить подобными объявлениями в комментариях
Еще актуально?
Вряд ли. Его предложению уже больше полугода