Хранение значений широты и долготы в виде символов с заданной точностью

Я получаю данные широты и долготы от GPS и хочу сохранить эти числа в середине последовательности символов.

Например, широта = -23,123456

длинный = 135.123456

Мне нужно что-то вроде "Ваши координаты -23.123456,135.123456" в виде массива символов.

Я пробовал:

float latitude = -23.123456;
float longitude = 135.123456;

String one = "Your coordinates are ";
String two = ","    
String message = one + latitude + two + longitude;

// Преобразование строки в массив символов
int str_len = message.length() + 1;
char textmessage[str_len];
message.toCharArray(textmessage,str_len);

Serial.println(textmessage);

но результат: Ваши координаты -023.12,0135.12

Как это исправить?

Заранее спасибо!

, 👍0

Обсуждение

Действительно ли ваш GPS дает вам «поплавок»? Большая часть выводимого текста на последовательный порт; если вам не нужно выполнять числовые операции со значениями, возможно, вам следует просто обрабатывать их как текст на всем протяжении. Обратите внимание, что если вы используете float, их точность ограничена, что вполне может быть причиной того, что вы видите с вашими поддельными тестовыми данными., @Chris Stratton

Вы уверены в своем результате? Пробую ваш код и получаю "Ваши координаты -23.123456,135.123456". На всякий случай, если вы не заметили, вы пропустили один ;, @dhimaspw

Относительно ограниченной точности формата float32: для чисел в диапазоне \[128, 256) (например, ваша долгота) [единица измерения на последнем месте](https://en.wikipedia.org/wiki/Unit_in_the_last_place) около 1,53e-5, что соответствует разрешению 1,7 м на поверхности Земли. Присвоение долготы «поплавку» может привести к ошибке округления до половины ulp или около 85 см., @Edgar Bonet

Почему бы просто не использовать функцию члена String c_str() для доступа к массиву символов? message.c_str() https://www.arduino.cc/en/Reference/CStr, @Mikael Patel


1 ответ


1

Если форматирование последовательного вывода вызывает беспокойство, стоит загрузить и использовать Streaming.h предоставленная библиотека, которая добавляет некоторый «синтаксический сахар» в Arduino C. То есть во время компиляции она преобразует C++-подобные операторы последовательного потока << в Serial.print без увеличения размера кода. Если у вас не установлен Streaming.h, вы можете получить Streaming5.zip с сайта arduiniana.org.

В настоящее время Streaming.h не поддерживает setw() и setfill(), которые в обычном C++ устанавливают ширину поля и заполняющий символ.

Однако он поддерживает четыре спецификатора преобразования базы: _HEX, _DEC, _OCT и _BIN; функция _FLOAT с указанным количеством знаков после запятой; и endl.

Таким образом, чтобы напечатать «Ваши координаты -23.123456, 135.123456», нужно написать:

Serial << "Your coordinates are " << _FLOAT(latitude,6) << ", " << _FLOAT(longitude,6) << endl;

Обратите внимание, что в отличие от класса String использование Streaming.h не влечет за собой какого-либо динамического управления памятью — все, что он делает, происходит во время компиляции — и не увеличивает размер кода — он переводит потоковые операции в обычные вызовы .print() и .println(). Это должно привести к несколько меньшему, более быстрому и более надежному коду за счет исключения String. Использование динамической памяти во встроенных системах с небольшим объемом памяти может быть проблематичным, и это позволяет избежать этих проблем.


Редактировать 1a: Как отмечает Крис Страттон, числа с плавающей запятой Arduino не поддерживают 9-значную точность. Я думаю, что арифметика с плавающей запятой в Arduino предназначена для соответствия IEEE 754, который устанавливает стандарты для использования на современных компьютерах, поддерживать арифметику с плавающей запятой.

В формате binary32, используемом для реализации стандарта IEEE 754 single-point точность двоичного числа с плавающей запятой, точность мантиссы составляет 24 бита. Это соответствует примерно 7,22 десятичных разряда (т. е. 24*log₁₀(2)), поэтому для простых вычислений реалистична точность до 7 знаков, более того — нет.


[Часть] Редактировать 1b: В более широком смысле, возможно, нет необходимости создавать и сохранять форматированную строку, подобную этой. Это бесполезно для вычислений — для этого лучше подходят значения с плавающей запятой. Для связи это не требуется — можно выполнить другую потоковую запись.


Изменить 2 [заменяет большую часть 1b]: Streaming.h не создает никаких строк, а просто доставляет текст своего символа <<-arguments -посимвольно в поток. Однако класс PString в arduiniana может создавать строки из входных потоков, как в следующем примере кода.

#include <Streaming.h>
#include <PString.h>

char buffer[28];
PString pstr(buffer, sizeof(buffer));

void setup() {
  Serial.begin(115200);
  pstr.begin();     // Очистить буфер
}

void loop() {
  int first=50, second=100;
  pstr.begin();     // Очистить буфер
  pstr << 'X' << first << 'Y' << second << 'T';
  pstr += " hihi ";
  pstr << millis() << endl;
  Serial << pstr;
  delay(1000);
}

Вот как выглядит часть его вывода в Serial:

X50Y100T hihi 263198
X50Y100T hihi 264199
X50Y100T hihi 265199
X50Y100T hihi 266201
X50Y100T hihi 267201
X50Y100T hihi 268201

В примере кода сначала инициализируется строковый буфер, затем создается часть символьной строки с помощью оператора потоковой передачи <<, затем часть с помощью конкатенации, затем еще немного с помощью <<, затем напечатайте строку. Обратите внимание, что задействованные здесь строки находятся в фиксированных буферах, а не в динамически выделенных буферах, как это использует класс String.

,

Возможно, вы можете сделать лучше, чем код в вопросе, но вы * не * получите желаемую точность от «поплавка» Arduino Uno на базе ATmega., @Chris Stratton

Спасибо! Однако мне нужно сохранить эту напечатанную последовательность как массив символов, который будет использоваться позже в коде. Можно ли это сделать из напечатанного Serial <<... ?, @Anwar

@ChrisStratton, отражено в Edit 1a, @James Waldby - jwpat7

@ Анвар, см. Редактировать 1b, @James Waldby - jwpat7

Несмотря на то, что потоковая библиотека — это приятная синтаксическая конфета, вам не нужно указывать количество цифр для печати. Вы также можете использовать Serial.print(широта, 6);., @Edgar Bonet

@ ЭдгарБонет, правда. Но если кто-то выполняет большое количество операций форматирования (т. е. случай «Когда форматирование последовательного вывода вызывает беспокойство»), Streaming.h помогает сделать код компактным и более четким, чем длинная серия распечаток. (Мое первоначальное прочтение вопроса, возможно, неправильное, предполагало проблемы с форматированием, а не проблемы с получением строки.), @James Waldby - jwpat7

Спасибо за участие, ребята. Однако я ищу решение, которое не считывает строку из последовательного окна (как предложено в Edit 1b), так как в конечном итоге я буду использовать этот модуль без подключения к компьютеру., @Anwar

@Анвар, редактирование 2 объясняет, как построить строку, используя класс PString. В любом случае, 1a и 1b были о том, как отправлять данные через Serial, без предложения «прочитать строку из окна Serial»., @James Waldby - jwpat7