Собираем GPS-радар на базе STM32F3DISCOVERY и u-blox Neo-6M
Конечно, ты можешь купить GPS-приемник в Китае за несколько долларов. А можешь и не покупать — все равно он есть у тебя в телефоне, в навигаторе в машине… Но если ты хочешь быть настоящим хакером-инженером и разобраться в технологии GPS на низком уровне, то добро пожаловать в эту статью. Разберемся так, что мало не покажется!
История разработки глобальной системы позиционирования (Global Positioning System, GPS) уходит корнями в 50-е годы прошлого века, а первый спутник был запущен в 1974 году. Первоначально система использовалась лишь военными, но после трагедии с самолетом авиакомпании Korean Airlines, который был сбит над территорией СССР, гражданские службы также получили возможность работы с GPS. В 1993-м окончательно было решено предоставить GPS для использования гражданскими службами на безвозмездной основе, а после отключения намеренного округления положения точность возросла со ста метров до двадцати. В наши дни точность продолжает увеличиваться, а стоимость приемников — снижаться. Поэтому сделать GPS-логгер, ну или навигатор, может любой, кто родился с паяльником вместо…ладно-ладно, это шутка была. Одно другого не исключает :).
Матчасть
Итак, что же должно делать наше устройство?
- Получить информацию о текущем положении от GPS-приемника.
- Разобрать ее.
- Показать на экране текущее положение приемника, а также видимые спутники.
Для этого придется узнать, что таится за терминами GPS, NMEA-0183 и алгоритм Брезенхема.
Конечно, детально разбираться в нюансах работы GPS не требуется, поскольку всю работу по вычислению координат, скорости, курса и других параметров за нас возьмет на себя GPS-приемник. Но базу знать надо.
В первую очередь надо понять, что GPS-приемник ничего и никогда не передает спутникам (если ты мне не веришь, то просто обрати внимание, что приемники могут быть размером с флешку, в то время как антенны спутниковых телефонов порой больше самого телефона). Задача спутниковой навигации заключается в определении приемником своих координат, если известны точные координаты передатчиков. Если мы знаем расстояние до спутников, то с помощью элементарных геометрических построений можно с некоторой точностью рассчитать свои координаты.
Для нахождения расстояния между приемником и передатчиком необходимо сначала синхронизировать их часы, а затем посчитать искомое расстояние, зная скорость распространения радиоволны, а также задержку между временем передачи и временем приема.
Как я уже писал выше, приемнику необходимо знать точные положения передатчиков. Подобная информация предоставляется передатчиком и называется «альманах». Естественно, эта информация устаревает, поэтому в зависимости от «свежести» альманаха можно выделить три типа задержки между включением приемника и определения его первых точных координат: «холодный старт», «теплый старт» и «горячий старт».
Существуют способы, которые позволяют уменьшить время старта: AGPS (получение альманаха альтернативными способами — через интернет или Почтой России), DGPS (исключение искажения сигнала атмосферой) и другие. Но я их рассматривать не буду, поскольку для выполнения поставленной задачи этого не нужно.
Теперь разберемся с тем, в каком же виде рассчитанные координаты появляются на выходе устройства. Для этого существует специальный стандарт.
NMEA-0183
NMEA — National Marine Electronics Association, а NMEA-0183 (согласно Википедии) — текстовый протокол связи морского (как правило, навигационного) оборудования (или оборудования, используемого в поездах) между собой. Вот строки, приходящие от моего приемника.
Сначала определим похожие части каждой строки. Легко видеть, что все они начинаются одинаково и более-менее одинаково заканчиваются. $GP — информация идет от приемника GPS (ты ведь понимаешь, что на корабле куча других датчиков: если бы у нас был аварийный маяк, то строка начиналась бы с $EP , а если эхолот, то с $SD , ну и так далее). Каждая строка обязательно заканчивается контрольной XOR-суммой всех байтов в строке начиная от $ и заканчивая * — это как раз те два символа в конце строки. И не забываем про символы <CR> и <LF> после контрольной суммы. Разберем каждую из строк подробнее.
- GPRMC — GPS Recommended Minimum Navigation Information sentence C — рекомендуемый минимум навигационной информации, строка типа С.
- hhmmss.ss — время по всемирному координированному времени UTC, когда была произведена фиксация положения.
- A — флаг достоверности информации. Если V , то информации верить нельзя.
- aaaa.aaaaa — величина широты. Первые две цифры — градусы, вторые две — целое значение количества угловых минут, после точки — дробная часть количества угловых минут (переменной длины).
- N — северная широта. Если S , то южная.
- bbbb.bbbbb — величина долготы. Первые две цифры — градусы, вторые две — целое значение количества угловых минут, после точки — дробная часть количества угловых минут (переменной длины).
- E — восточная долгота. Если W , то западная.
- c.c — горизонтальная скорость в узлах (умножить на 1,852 для получения скорости в километрах в час), целая и дробная части имеют переменную длину.
- d.d — направление скорости (путевой угол, курс) в градусах, целая и дробная части имеют переменную длину.
- DDMMYY — текущая дата.
- z1 — отсутствующая у нас величина направления магнитного склонения.
- z2 — также отсутствующее у нас направление магнитного склонения.
- e — индикатор режима.
- ff — контрольная сумма.
- $GPVTG — GPS Track Made Good and Ground Speed — строка с информацией о курсе и скорости.
- a.a — курс в градусах.
- T — True, флаг достоверности информации.
- b.b — направление магнитного склонения (у нас его нет).
- M — Magnetic, да, действительно магнитное.
- c.c — горизонтальная скорость в узлах (умножить на 1,852 для получения скорости в километрах в час).
- N — kNots, узлы.
- d.d — горизонтальная скорость в километрах в час (и умножать ничего не надо).
- K — километры в час.
- ee — контрольная сумма.
- $GPGGA — Global Positioning System Fix Data — строка с информацией о текущем местоположении.
- hhmmss.ss — время по всемирному координированному времени UTC, когда была произведена фиксация положения.
- a.a — величина широты.
- N — северная широта. Если S , то южная.
- b.b — величина долготы.
- E — восточная долгота. Если W , то западная.
- c — флаг качества сигнала GPS.
- d — количество используемых спутников.
- e.e — фактор снижения точности (DOP, Dilution of precision).
- f.f — высота расположения приемника над уровнем моря.
- M — высота дается в метрах.
- g.g — различие между геоидом (истинной формой нашей планеты) и эллипсоидом по WGS84 (трехмерная система координат для позиционирования).
- M — различие дается в метрах.
- h.h — номер станции, передающей поправки DGPS.
- i — контрольная сумма.
- $GPGSA — GPS DOP and Active satellites — строка с информацией о спутниках, использованных для определения местоположения и о факторах снижения точности.
- A — автоматический режим выбора работы в 2D или 3D, M — ручной режим, когда жестко выбран, например, 2D.
- x — режим работы приемника: 0 — координаты не определены, 1 — режим 2D, 2 — режим 3D.
- y1..y12 — номера спутников, используемых для определения местоположения приемника.
- z1..z2 — PDOP, HDOP, VDOP (факторы снижения точности по положению, в горизонтальной плоскости и в вертикальной плоскости соответственно).
- i — контрольная сумма.
- GPGSV — GPS Satellites in View — строка содержит в себе информацию о номере, азимуте, высоте над горизонтом и соотношением сигнал/шум спутника. В строке максимально может быть четыре спутника.
- a — общее количество строк GPGSV .
- b — номер текущей строки.
- c1..c4 — номер спутника.
- d1..d4 — высота над горизонтом в градусах (0..90) .
- e1..e4 — азимут спутника в градусах (0..359) .
- f1..f4 — соотношение сигнал/шум в дБ (0..99) .
$GPGLL,5541.23512,N,03749.12634,E,174214.00,A,A*6D — на этой строке нет смысла останавливаться подробно, поскольку она содержит в себе координаты и время, а это мы уже имеем в строках GPRMC и GPGGA .
Разумеется, производителям GPS-приемников не запрещается добавлять собственные строки. У моего приемника можно при запуске увидеть такие:
Алгоритм Брезенхема
Этот алгоритм является одним из самых старых алгоритмов компьютерной графики — он был разработан Джеком Брезенхемом (IBM) аж в 1962 году. С его помощью происходит растеризация графического примитива, другими словами, этот алгоритм определяет координаты пикселей, которые необходимо зажечь на экране, чтобы полученный рисунок примитива совпадал с оригиналом.
Представим, что мы рисуем линию, идущую из точки (0; 0) в (100, 32) , как ты помнишь, у нашего экрана разрешение 128 x 64 точки. Несложно посчитать, что угол между этой прямой и осью Х составляет менее 45 градусов. Работа алгоритма заключается в последовательном переборе всех координат по оси Х в диапазоне от 0 до 100 и расчете соответствующей координаты Y. Логично, что в большинстве случаев значение координаты Y будет дробным, а это значит, что надо каким-то образом выбрать целочисленное значение координаты. Это делается путем выбора ближайшего пикселя. Для других углов наклона прямой, а также для окружностей, эллипсов и прочего алгоритм имеет аналогичный вид (подробнее о нем можно почитать в Википедии).
Алгоритм Брезенхема использует только операции сложения и вычитания целых чисел: обычно использование арифметики дробных чисел замедляет работу контроллера. Обычно, но не в нашем случае, поскольку внутри контроллера STM32F303VC находится ядро ARM Cortex-M4 с FPU. FPU (Floating Point Unit) — устройство, ускоряющее работу с дробными числами (математический сопроцессор), поэтому нас ничто не ограничивает и мы можем использовать алгоритм DDA-линии. Интересную демонстрацию ускорения работы МК при рисовании фракталов можно посмотреть на YouTube.
Железо
Что же мы используем в проекте?
- Отладочную плату STM32F3-Discovery;
- модуль UART GPS NEO-6M от WaveShare на базе приемника u-blox NEO-6M;
- ЖК-матрицу МТ-12864А.
Про ЖК-экран я рассказывал в сентябрьском номере (№ 188), кратко лишь скажу, что сделан он на базе контроллеров KS0108, а схема подключения к STM32F3-Discovery не изменилась: разъем для подключения экрана содержит в себе 20 пинов, описание представлено в списке по следующей маске: <номер> — <название из даташита> — <описание из даташита> — <куда подключается>.
- 1 — Ucc — питание — к 5V на Discovery.
- 2 — GND — земля — к GND на Discovery.
- 3 — Uo — вход питания ЖК-панели для управления контрастностью — к подстроечному резистору.
- 4..11 — DB0..DB7 — шина данных — к PD0..PD7 на Discovery.
- 12, 13 — E1, E2 — выбор контроллера — к PD8,PD9 на Discovery.
- 14 — RES — сброс — к PD10 на Discovery.
- 15 — R/W — выбор: чтение/запись — к PD11 на Discovery.
- 16 — A0 — выбор: команда/данные — к PD12 на Discovery.
- 17 — E — стробирование данных — к PD13 на Discovery.
- 18 — Uee — выход DC-DC преобразователя — к подстроечному резистору.
NEO-6M
Данный приемник производится швейцарской компанией u-blox, основанной в 1997 году. Линейка модулей Neo-6 представлена разновидностями G, Q, M, P, V и T, каждый из которых обладает своими характерными возможностями: например, Neo-6P имеет возможность очень точного (с ошибкой <1 м) определения положения за счет метода Precise Point Positioning (PPP).
Приемник Neo-6M обладает следующими свойствами:
- время холодного или теплого старта — 27 с;
- время горячего старта — 21 с;
- максимальная частота выдачи информации — 1 Гц;
- диапазон частот импульсов на пин PPS — 0,25 Гц — 1 кГц;
- максимальная точность определения положения — 2,5 м;
- максимальная точность определения скорости — 0,1 м/с;
- максимальная точность определения курса — 0,5 градуса.
Neo-6M умеет использовать SBAS (Satellite Based Augmentation System) — спутниковые системы дифференциальной коррекции, что увеличивает точность определения положения до 2 м, а также AGPS (Assisted GPS) для снижения времени холодного старта. Получение данных AGPS происходит с сайта u-blox с помощью сервисов AssistNow Online и AssistNow Offline (долгосрочный альманах). Модуль обладает поддержкой протоколов NMEA, UBX и RTCM. UBX — проприетарный протокол от u-blox, а RTCM — протокол для передачи модулю данных о дифференциальной коррекции DGPS. Также для связи доступны интерфейсы UART, I2C, SPI и USB.
Для работы с приемниками существует оригинальная утилита u-center, имеющая на момент написания статьи версию 8.11 (рис. 1).
Рис. 1. Общий вид u-center
Хакер #190. Что скрывает Tor?Видно, что Neo-6M обладает огромным потенциалом, но детально описать все его возможности не хватит места, поэтому ограничимся предлагаемыми из коробки: только UART на скорости 9600, только NMEA, частота импульсов — 1 Гц.
В плане подключения все предельно просто: линии VCC, GND, RX и TX на приемнике подключаем к +3.3V, GND, PA9 и PA10 на Discovery соответственно.
Программа
Она должна отображать текущее положение приемника, скорость, направление движения, факторы снижения точности, время, дату, а еще показывать в полярной системе координат используемые спутники. Вот примерно так, как это делает u-center на рис. 2.
Рис. 2. Ожидание того, что будет показано на экранчике 128 х 64
Как только строка line от Neo-6M принимается контроллером, происходит ее разбитие на токены (массив charTokens ) — на подстроки, которые в исходной строке разделены запятыми.
Казалось бы, вполне логично использовать функцию strtok , но я этого не делаю. Причину покажу на примере. Пусть имеется строка a,b. c . Результат разбития ее на токены с помощью strtok будет таким: 'a', 'b', 'c' . Для разбора NMEA это недопустимо, поскольку в этом протоколе значения токенов зависят от положения в строке. Результат работы описанного выше метода включает в себя пустые токены — 'a', 'b', '0', '0' 'c' .
Для удобного хранения информации о положении приемника, о точности определения положения, а также о параметрах спутников были написаны три структуры данных.
Положение и скорость приемника, а также дата и время:
Структура точности определения координат:
Структура о номере спутника, его положении и качестве сигнала:
Если информация о спутнике не полная, например есть информация о высоте и азимуте, но нет о соотношении сигнал/шум, то в поле isFull записывается нулевое значение. Такие спутники при выводе на «радар» будут игнорироваться.
Заполнение структуры на основе массива токенов происходит очень просто: после разбора строки GPGSA в массиве charTokens значения факторов снижения точности *DOP находятся в элементах за номерами 15, 16 и 17.
Теперь можно разобранную информацию смело выводить на экран (рис. 3).
Рис. 3. А вот и реальность!
Теперь ты знаешь, что в GPS тоже нет ничего сложного (если не лезть в дебри), а если тебе хочется понять суть спутниковой навигации, то добро пожаловать на курс от Стэнфорда GPS: An Introduction to Satellite Navigation, with an interactive Worldwide Laboratory using Smartphones или от Университета Миннесоты From GPS and Google Maps to Spatial Computing на Coursera.
А в качестве домашнего задания я поставлю перед тобой три задачи: 1. Добавить возможность записи трека. 2. Заменить монохромный экран на цветной. 3. Вместе с WizFi220 (из номера 188) снабдить устройство возможностью получения A-GPS. Если возникли какие-нибудь вопросы, пиши мне на email, который можно найти в начале статьи. Удачи!