Официальный сайт компании Arduino по адресу arduino.cc
Синхронизация часов по NTP с точностью до микросекунд
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Пт, 07/03/2014 - 18:59
Доброго времени суток!
Узнал сегодня, что протокол NTP может предоставлять время с точностью почти до 1 мкс. В Сети нашел множество примеров получения данных (с помощью Ethernet модуля) с точностью до секунд, но не точнее.
Может ли кто-нибудь подсказать, как изменить программный код, чтобы повысить точность до тысячных секунды с помощью NTP или каких-либо других средств(мало-ли, может есть средства проще)?
Если вы планируете синхронизировать DS1307 то точность выше полусекунды лишена смысла
Если вы планируете синхронизировать DS1307 то точность выше полусекунды лишена смысла
Да мне даже не принципиально, чтобы синхронизировались часы реального времени. Достаточно, чтобы я разово, т.е. по команде, мог запросить и распарсить время с точностью до 10-100мс.
Понимаю, что нужно несколько дополнить код, а вот чем именно дополнить - ума не приложу...
я не об этом. ну получите вы время с точностью до 10мск, что дальше? как вы созраните ход времени с той же точностью?
я не об этом. ну получите вы время с точностью до 10мск, что дальше? как вы созраните ход времени с той же точностью?
Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с micros(): запросил - получил.
Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с micros(): запросил - получил.
Оно смысла не имеет - у Вас, скорее всего, jitter при одноразовом запросе получится больше точности.
Кроме того, сервер Вам может и отдаст с такой точностью, но пока сигнал идет до приемника - время все равно сместится. Нормальные ntp сервера долго опрашивают свои источники и на основании статистики делают выбор наиболее подходящего...
$ ntpq -nc peers 127.0.0.1
remote refid st t when poll reach delay offset jitter
==============================================================================
77.232.189.253 .INIT. 16 u - 512 0 0.000 0.000 0.000
+89.169.173.117 89.109.251.24 2 u 476 512 377 11.837 1.446 0.343
*83.143.51.50 .PPS. 1 u 127 512 377 38.122 2.873 3.636
+89.175.22.33 89.175.22.41 2 u 373 512 377 12.623 3.073 0.122
Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с micros(): запросил - получил.
Оно смысла не имеет - у Вас, скорее всего, jitter при одноразовом запросе получится больше точности.
Кроме того, сервер Вам может и отдаст с такой точностью, но пока сигнал идет до приемника - время все равно сместится. Нормальные ntp сервера долго опрашивают свои источники и на основании статистики делают выбор наиболее подходящего...
$ ntpq -nc peers 127.0.0.1
remote refid st t when poll reach delay offset jitter
==============================================================================
77.232.189.253 .INIT. 16 u - 512 0 0.000 0.000 0.000
+89.169.173.117 89.109.251.24 2 u 476 512 377 11.837 1.446 0.343
*83.143.51.50 .PPS. 1 u 127 512 377 38.122 2.873 3.636
+89.175.22.33 89.175.22.41 2 u 373 512 377 12.623 3.073 0.122
Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)
и в чем тогда проблема? Берете готовый пример из библиотеки Ethernet с сайта arduino.cc, в коде убираете округление до секунд и получаете то что нужно. Если вам нужно одинаковое время на двух ардуинках но при этом не так критично чтобы оно было такое как на ntp то этого достаточно
и в чем тогда проблема? Берете готовый пример из библиотеки Ethernet с сайта arduino.cc, в коде убираете округление до секунд и получаете то что нужно. Если вам нужно одинаковое время на двух ардуинках но при этом не так критично чтобы оно было такое как на ntp то этого достаточно
Спасибо! Взял с сайта пример кода:
Но, как я понял, в данном коде мы получаем количество секунд, прошедших с 1 января 1900 года. NTP же позволяет получать даже микросекунды - вот в этом и состоит вопрос: как дополнить код, чтобы он запрашивал с сервера(само-собой, я найду такой, который бы предлагал микросекундную точность) именно микросекунды.
Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)
Синхронизируйте одну ардуину по другой: достаточно одного синхросигнала. :)
Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)
Синхронизируйте одну ардуину по другой: достаточно одного синхросигнала. :)
А не могли бы Вы подсказать, как это делается?)
А не могли бы Вы подсказать, как это делается?)
Одна ардуина шлет другой некий сигнал... Например, millis(). На принимающей стороне Вы его ловите и используете для синхронизации.
Мне кажется, что проще озвучить конечную цель, чем пытаться негодными методами решить проблему. Ведь если до Вас ее никто не решал - то с большой долей вероятности, Вы идете не тем путем...
Никогда не работал с NTP. Посмотрел в wiki (просто исходя из предположения, что если хочу парсить какой-то протокол, то хоть бегло глянуть его описание. есть ли в нем вообще нужные данные):
http://ru.wikipedia.org/wiki/NTP
Читаю:"время представляется в системе NTP 64-битным числом (8 байт), состоящим из 32-битного счётчика секунд и 32-битного счётчика долей секунды"
Смотрю коментарий в коде (строки 77, 78): "the timestamp starts at byte 40 of the received packet and is four bytes"
Вижу как в строках 80-84 вычитывают первые четыре байта (первый 32-битныйх счетчик). Байты 40,41,42,43. А доли секунд, как пишет вики находится во втором. По идее "они идут за ним".
Что бы я делал? Попытался абсолютно аналогично, строкам 80-84, вычитать байты 44,45,46,47
P.S. Но как сказали выше, особого смысла в этом не видно. Это доли секунды того момента когда СЕРВЕР формировал вам ответ. Отправка ответа, передача, прием, парсинг... тоже занимает время.
А не могли бы Вы подсказать, как это делается?)
Одна ардуина шлет другой некий сигнал... Например, millis(). На принимающей стороне Вы его ловите и используете для синхронизации.
Мне кажется, что проще озвучить конечную цель, чем пытаться негодными методами решить проблему. Ведь если до Вас ее никто не решал - то с большой долей вероятности, Вы идете не тем путем...
Без проблем, конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами, а вот как ее осуществить - я не знаю. Но думаю, что синхронизация по NTP каждый цикл и дальнейший счет времени с помощью micos() может принести положительный результат.
Т.е. Вы предлагаете замерить на одной дуине её внутреннее время micros(), отправить на вторую дуину и в момент приема ею данных от первой дуины засечь и её micros(), после чего использовать разницу в часах двух дуин для определения их расхождения?
Никогда не работал с NTP. Посмотрел в wiki (просто исходя из предположения, что если хочу парсить какой-то протокол, то хоть бегло глянуть его описание. есть ли в нем вообще нужные данные):
http://ru.wikipedia.org/wiki/NTP
Читаю:"время представляется в системе NTP 64-битным числом (8 байт), состоящим из 32-битного счётчика секунд и 32-битного счётчика долей секунды"
Смотрю коментарий в коде (строки 77, 78): "the timestamp starts at byte 40 of the received packet and is four bytes"
Вижу как в строках 80-84 вычитывают первые четыре байта (первый 32-битныйх счетчик). Байты 40,41,42,43. А доли секунд, как пишет вики находится во втором. По идее "они идут за ним".
Что бы я делал? Попытался абсолютно аналогично, строкам 80-84, вычитать байты 44,45,46,47
P.S. Но как сказали выше, особого смысла в этом не видно. Это доли секунды того момента когда СЕРВЕР формировал вам ответ. Отправка ответа, передача, прием, парсинг... тоже занимает время.
Спасибо! Стоит попытаться, выглядит логично. Мне не нужно знать точное время, мне нужно, чтобы две дуины получили одинаковое время :) И пусть оно будет неправильным, но одинаковым - меня это устроит.
И пусть оно будет неправильным, но одинаковым - меня это устроит.
Не будет оно одинаковымым. С чего ему быть? Оно же неправильное. Причем - у каждой свое "неправильное".
Ну представте что два человека, спрашивают у третьего "который час?". Причем спрашивают с помощью курьера, а не напрямую. Причем нет даже гарантии что курьер бегает c одинаковой скоростью. Смогут они выставить свои часы "одинаково"? Ну с какой-то точностью - да. Грубо. А вот "ну совсем точно" .... это врядли.
Что-бы "синхронизироваться" им потребуется как-то "связатся между собой". Что-бы один другому сказал, время. Тот потом в ответ сказал свое. Увидеть "расхождение". Поправить его. Возможно повторить эту операцию несколько раз... статистически "убрать разницу".
И повторять это время от времени. Так как у каждого часы идут со своей погрешностью). Если только обе дуины не тактируются от одного источника.
И кстати, если оно у вам важдно только "одинаковость", то зачем вам вообще внешний NTP? Раз обе дуины подключены к сети, почему одна другую спросить не может "который час на твоей millis()?"?
конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами,
Не нужна. :) Просто на второй дуине надо ловить два сигнала: первый - с источника, второй - отраженный: зная расстояние между дуинами - вычисляем расстояние до отраженной цели. Как видите: никакой синхронизации не требуется.
И кстати, если оно у вам важдно только "одинаковость", то зачем вам вообще внешний NTP? Раз обе дуины подключены к сети, почему одна другую спросить не может "который час на твоей millis()?"?
На тему того, что у обоих время будет неправильное Вы правы, жаль.
Сейчас попробую поступить следующим образом:
1)Мастер подает сигнал слейву.
2)Слейв отсылает свое значение micros() на момент отправки.
3)Мастер записывает свое значение micros() и находит разницу между своим и чужим значением.
4)Мастер объявляет, что в момент времени n он начнет передачу УЗ сигнала. Слейву отсылает значение n+расхождение в часах.
5)В момент n+расхождение слейв начинает прием УЗ-сигнала.
Как сделаю - отпишусь. Правдоподобно выглядит?
конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами,
Не нужна. :) Просто на второй дуине надо ловить два сигнала: первый - с источника, второй - отраженный: зная расстояние между дуинами - вычисляем расстояние до отраженной цели. Как видите: никакой синхронизации не требуется.
А можно поподробнее? Что такое отраженный сигнал?)
А можно поподробнее? Что такое отраженный сигнал?)
Ну, Вы же сами пишете "вторая ардуинка должна эту волну поймать". Или Вам между двумя ардуинами расстояние требуется измерить?
А можно поподробнее? Что такое отраженный сигнал?)
Ну, Вы же сами пишете "вторая ардуинка должна эту волну поймать". Или Вам между двумя ардуинами расстояние требуется измерить?
Да, я имел ввиду именно замерить расстояние. Понимаю, что несколько извращенно, но таковы условия :)
Вы когда нибудь видели, как спортивный судья работает с секундомером? Услышав выстрел стартового пистолета, он запускает свой секундомер и следит за бегунами на дорожке, чтобы в момент пересечения финишной черты остановить свой агрегат. И ему глубоко фиолетово, какое время показывают часы вышеупомянутого муд...жика с пистолетом. И есть ли у него вообще какие-либо часы.
У вас ситуация аналогичная, поэтому
0. соедините свои дуинки проводочком (сигнальным). Землю, естественно, тоже пробросьте.
1. В момент генерации УЗ-импульса первая дуинка дергает сигнальный провод. Вторая дуинка запоминает момент этого дергания (t1, он же - момент испускания УЗ-импульса).
2. Первая дуинка больше ничего не делает. Вторая - слушает.....
3. Услышав УЗ-сигнал, испущенный первой дуинкой, вторая запоминает и этот момент (t2, момент прихода УЗ-импульса).
4. Ну а дальше - t2-t1 -> время прохождения УЗ-импульса от источника к приемнику. Умножаем его на скорость распространения звука в воздухе и получаем искомое расстояние.
Резюме: Поскольку скорость распространения электричества в меди существенно больше скорости звука, можно считать, то электросигнал распространяется мгновенно. Синхронизации часов не требуется. Часы нужны только на одной из Ардуин - на той, которая будет заниматься основной работой (вычислениями). От другой Ардуины требуется лишь дернуть сигнальный провод.
Вы когда нибудь видели, как спортивный судья работает с секундомером? Услышав выстрел стартового пистолета, он запускает свой секундомер и следит за бегунами на дорожке, чтобы в момент пересечения финишной черты остановить свой агрегат. И ему глубоко фиолетово, какое время показывают часы вышеупомянутого муд...жика с пистолетом. И есть ли у него вообще какие-либо часы.
У вас ситуация аналогичная, поэтому
0. соедините свои дуинки проводочком (сигнальным). Землю, естественно, тоже пробросьте.
1. В момент генерации УЗ-импульса первая дуинка дергает сигнальный провод. Вторая дуинка запоминает момент этого дергания (t1, он же - момент испускания УЗ-импульса).
2. Первая дуинка больше ничего не делает. Вторая - слушает.....
3. Услышав УЗ-сигнал, испущенный первой дуинкой, вторая запоминает и этот момент (t2, момент прихода УЗ-импульса).
4. Ну а дальше - t2-t1 -> время прохождения УЗ-импульса от источника к приемнику. Умножаем его на скорость распространения звука в воздухе и получаем искомое расстояние.
Резюме: Поскольку скорость распространения электричества в меди существенно больше скорости звука, можно считать, то электросигнал распространяется мгновенно. Синхронизации часов не требуется. Часы нужны только на одной из Ардуин - на той, которая будет заниматься основной работой (вычислениями). От другой Ардуины требуется лишь дернуть сигнальный провод.
Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.
Код ардуинки-слейва прост до безобразия, даже не знаю, что может быть не так.
Не баловался с УЗ-дальномером, но, насколько я знаю функцию PulseIn, в строке 08 у вас происходит измерение длины отраженного импульса (испускавшегося в течение 10 микросекунд). Эта величина имеет мало общего с расстоянием а, скорее, говорит нечто о характеристиках поверхности отразившей УЗ-импульс: можно предположить, что при отражении от толстой (и гладкой) металлической плиты значение tim2 будет ближе к 10, а при отражении от мягкой и неровной (портьера или мебельная обивка) - составит и 15, и 20 мкс...
Измерять необходимо диапазон времени между моментом начала испускания УЗ-импульса и моментом начала регистрации эха (либо между моментом окончания испускаемого импульса и моментом перехода сигнала с HIGH на LOW, а может быть даже два этих периода, чтобы потом на их основании производить усреднение).
То есть:
перед строкой 05 запоминаем момент начала испускания УЗ-импульса: t1=micros();
строку 08 меняем на строки while(digitalRead(sputnic_E_2)==LOW); t2=micros(); (т.е. ждем, когда начнет приходить эхо)
Здесь необходимо помнить, что бывают ситуации, когда эхо не приходит (слишком большое расстояние до преграды), поэтому не лишне будет ограничить время ожидания в цикле while каким-либо разумным диапазоном - иначе скетч зависнет.
По разнице t2-t1 рассчитываем (оцениваем?) расстояние.
UPD: взглянул на описание УЗ-датчика на Robocraft'е. Исходя из него, длина импульса таки соответствует расстоянию. НО только в том случае, если с датчиком работать как с черным ящиком - дернул за ногу T, получил значение расстояния с ноги E. Тогда, похоже, на второй Arduino тоже необходимо обеспечить полный цикл опроса УЗ-датчика - дернуть его ногу T2 одновременно c T1 и ждать, когда на ноге E2 появится искомый импульс, по длительности которого и судить о расстоянии между двумя датчиками. При этом следует экранировать (фетром обернуть) УЗ-передатчик второго датчика, чтобы его сигнал не вносил сумятицу в систему.
Не баловался с УЗ-дальномером, но, насколько я знаю функцию PulseIn, в строке 08 у вас происходит измерение длины отраженного импульса (испускавшегося в течение 10 микросекунд). Эта величина имеет мало общего с расстоянием а, скорее, говорит нечто о характеристиках поверхности отразившей УЗ-импульс: можно предположить, что при отражении от толстой (и гладкой) металлической плиты значение tim2 будет ближе к 10, а при отражении от мягкой и неровной (портьера или мебельная обивка) - составит и 15, и 20 мкс...
Измерять необходимо диапазон времени между моментом начала испускания УЗ-импульса и моментом начала регистрации эха (либо между моментом окончания испускаемого импульса и моментом перехода сигнала с HIGH на LOW, а может быть даже два этих периода, чтобы потом на их основании производить усреднение).
То есть:
перед строкой 05 запоминаем момент начала испускания УЗ-импульса: t1=micros();
строку 08 меняем на строки while(digitalRead(sputnic_E_2)==LOW); t2=micros(); (т.е. ждем, когда начнет приходить эхо)
Здесь необходимо помнить, что бывают ситуации, когда эхо не приходит (слишком большое расстояние до преграды), поэтому не лишне будет ограничить время ожидания в цикле while каким-либо разумным диапазоном - иначе скетч зависнет.
По разнице t2-t1 рассчитываем (оцениваем?) расстояние.
UPD: взглянул на описание УЗ-датчика на Robocraft'е. Исходя из него, длина импульса таки соответствует расстоянию. НО только в том случае, если с датчиком работать как с черным ящиком - дернул за ногу T, получил значение расстояния с ноги E. Тогда, похоже, на второй Arduino тоже необходимо обеспечить полный цикл опроса УЗ-датчика - дернуть его ногу T2 одновременно c T1 и ждать, когда на ноге E2 появится искомый импульс, по длительности которого и судить о расстоянии между двумя датчиками. При этом следует экранировать (фетром обернуть) УЗ-передатчик второго датчика, чтобы его сигнал не вносил сумятицу в систему.
У меня оно так и работает, только "глазок" передатчика замотан изолентой)
Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.
Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.
Импульсы идут достаточно редко? Не может откуда-то приходить отраженный сигнал и портить картинку? Тогда я бы просто ввел поправочный коэффициент и посмотрел - не сильно ли он меняется от расстояния...
Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.
Импульсы идут достаточно редко? Не может откуда-то приходить отраженный сигнал и портить картинку? Тогда я бы просто ввел поправочный коэффициент и посмотрел - не сильно ли он меняется от расстояния...
Проблему только что решил!
В чем была загвоздка: когда мы используем применик и передатчик на одном устройстве - он засекает путь от своего излучателя к стене, а потом от стены к себе. Во время расчетов мы делим длинну импульса пополам(т.к. нас интересует расстояние от себя к стене, а не от себя к стене + от стены к себе). Я использвал эту формулу. И в этом была ошибка.
Когда мы одновременно стартуем излучение звука на одной дуине и прием на другой - принимающая дуина засекает сразу необходимое расстояние, которое не нужно делить пополам. Я просто убрал деление на 2 из формулы и все стало отлично.
Формула стала такой: distance_sm=time_us/29;
А была такой: distance_sm=time_us/29/2;
Спасибо всем, кто помогал :)
P.S. ошибку обнаружил, когда сидел на диване и листал мануалы, а в боковом окне было открыто окно монитора порта. И так вышло, что излучатель одной дуины и приемник другой были направлены на потолок. А в мониторе порта светилось число 434. И тут я вспомнил, что высота от дивана до потолка у меня 217 см (т.е. 434/2). Ну тут то меня и осенило - убрал деление пополам и всё заработало :)
Так вы, получается, вводили в заблуждение, когда писали:
Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.
Ведь 50/2=25 и никак не 15?
Кстати, поэтому и передатчик можно не заклеивать - отраженный сигнал придет зна-а-а-ачительно позже, чем прямой от "правильной" ардуины.
Хотя.... на заставленном всякими предметами сцене эхо от какой-нибудь ножки стула может прийти и пораньше.
Так вы, получается, вводили в заблуждение, когда писали:
Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.
Ведь 50/2=25 и никак не 15?
Кстати, поэтому и передатчик можно не заклеивать - отраженный сигнал придет зна-а-а-ачительно позже, чем прямой от "правильной" ардуины.
Хотя.... на заставленном всякими предметами сцене эхо от какой-нибудь ножки стула может прийти и пораньше.
Почему он тогда показывал 15 - для приема использовался бракованый дальномер(у него исправный передатчик и сломаный приемник, который показывает слишком маленькие значения). Как только я переставил бракованный дальномер в передающую позицию, а исправный в принимающую - стало выдавать слишком большой результат. Не стал акцентировать внимание,т.к. всё равно неправитльный результат)
Теперь вот ясно, почему такой большой.
Это верно, но лучше заклемит от греха подальше - он может прийти и в следующую итерацию, если задержка между ними слищшком маленькая.