Синхронизация часов по NTP с точностью до микросекунд

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Доброго времени суток!

Узнал сегодня, что протокол NTP может предоставлять время с точностью почти до 1 мкс. В Сети нашел множество примеров получения данных (с помощью Ethernet модуля) с точностью до секунд, но не точнее. 

Может ли кто-нибудь подсказать, как изменить программный код, чтобы повысить точность до тысячных секунды с помощью NTP или каких-либо других средств(мало-ли, может есть средства проще)?

axill
Offline
Зарегистрирован: 05.09.2011

Если вы планируете синхронизировать DS1307 то точность выше полусекунды лишена смысла

Daemon2017
Offline
Зарегистрирован: 08.10.2013

axill пишет:

Если вы планируете синхронизировать DS1307 то точность выше полусекунды лишена смысла

Да мне даже не принципиально, чтобы синхронизировались часы реального времени. Достаточно, чтобы я разово, т.е. по команде, мог запросить и распарсить время с точностью до 10-100мс. 

Понимаю, что нужно несколько дополнить код, а вот чем именно дополнить - ума не приложу...

axill
Offline
Зарегистрирован: 05.09.2011

я не об этом. ну получите вы время с точностью до 10мск, что дальше? как вы созраните ход времени с той же точностью?

Daemon2017
Offline
Зарегистрирован: 08.10.2013

axill пишет:

я не об этом. ну получите вы время с точностью до 10мск, что дальше? как вы созраните ход времени с той же точностью?

Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с micros(): запросил - получил. 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с 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

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

Так я тоже не об этом :) Мне не нужен ход времени, мне нужна возможность узнавать точнейшее время в тот момент, когда я этого хочу. По аналогии с 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

Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)

axill
Offline
Зарегистрирован: 05.09.2011

и в чем тогда проблема? Берете готовый пример из библиотеки Ethernet с сайта arduino.cc, в коде убираете округление до секунд и получаете то что нужно. Если вам нужно одинаковое время на двух ардуинках но при этом не так критично чтобы оно было такое как на ntp то этого достаточно

Daemon2017
Offline
Зарегистрирован: 08.10.2013

axill пишет:

и в чем тогда проблема? Берете готовый пример из библиотеки Ethernet с сайта arduino.cc, в коде убираете округление до секунд и получаете то что нужно. Если вам нужно одинаковое время на двух ардуинках но при этом не так критично чтобы оно было такое как на ntp то этого достаточно

Спасибо! Взял с сайта пример кода:

/*

 Udp NTP Client
 
 Get the time from a Network Time Protocol (NTP) time server
 Demonstrates use of UDP sendPacket and ReceivePacket 
 For more on NTP time servers and the messages needed to communicate with them, 
 see http://en.wikipedia.org/wiki/Network_Time_Protocol
 
 Warning: NTP Servers are subject to temporary failure or IP address change.
 Plese check 

    http://tf.nist.gov/tf-cgi/servers.cgi

 if the time server used in the example didn't work.

 created 4 Sep 2010 
 by Michael Margolis
 modified 9 Apr 2012
 by Tom Igoe
 
 This code is in the public domain.

 */

#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() 
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  Udp.begin(localPort);
}

void loop()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server

    // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);               

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;  
    // print Unix time:
    Serial.println(epoch);                               


    // print the hour, minute and second:
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
    Serial.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch %60); // print the second
  }
  // wait ten seconds before asking for the time again
  delay(10000); 
}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

Но, как я понял, в данном коде мы получаем количество секунд, прошедших с 1 января 1900 года. NTP же позволяет получать даже микросекунды - вот в этом и состоит вопрос: как дополнить код, чтобы он запрашивал с сервера(само-собой, я найду такой, который бы предлагал микросекундную точность) именно микросекунды. 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)

Синхронизируйте одну ардуину по другой: достаточно одного синхросигнала. :)

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

Ничего страшного: мне важно синхронизировать две ардуинки, подключенные к одному роутеру, т.е. время доставки у них будет примерно одинаковым и синхронность будет получена :)

Синхронизируйте одну ардуину по другой: достаточно одного синхросигнала. :)

А не могли бы Вы подсказать, как это делается?) 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

А не могли бы Вы подсказать, как это делается?) 

Одна ардуина шлет другой некий сигнал... Например, millis(). На принимающей стороне Вы его ловите и используете для синхронизации.

Мне кажется, что проще озвучить конечную цель, чем пытаться негодными методами решить проблему. Ведь если до Вас ее никто не решал - то с большой долей вероятности, Вы идете не тем путем...

leshak
Offline
Зарегистрирован: 29.09.2011

Никогда не работал с 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. Но как сказали выше, особого смысла в этом не видно. Это доли секунды того момента когда СЕРВЕР формировал вам ответ. Отправка ответа, передача, прием, парсинг... тоже занимает время.

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

А не могли бы Вы подсказать, как это делается?) 

Одна ардуина шлет другой некий сигнал... Например, millis(). На принимающей стороне Вы его ловите и используете для синхронизации.

Мне кажется, что проще озвучить конечную цель, чем пытаться негодными методами решить проблему. Ведь если до Вас ее никто не решал - то с большой долей вероятности, Вы идете не тем путем...

Без проблем, конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами, а вот как ее осуществить - я не знаю. Но думаю, что синхронизация по NTP каждый цикл и дальнейший счет времени с помощью micos() может принести положительный результат.

Т.е. Вы предлагаете замерить на одной дуине её внутреннее время micros(), отправить на вторую дуину и в момент приема ею данных от первой дуины засечь и её micros(), после чего использовать разницу в часах двух дуин для определения их расхождения?

Daemon2017
Offline
Зарегистрирован: 08.10.2013

leshak пишет:

Никогда не работал с 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. Но как сказали выше, особого смысла в этом не видно. Это доли секунды того момента когда СЕРВЕР формировал вам ответ. Отправка ответа, передача, прием, парсинг... тоже занимает время.

Спасибо! Стоит попытаться, выглядит логично. Мне не нужно знать точное время, мне нужно, чтобы две дуины получили одинаковое время :) И пусть оно будет неправильным, но одинаковым - меня это устроит.

leshak
Offline
Зарегистрирован: 29.09.2011

Daemon2017 пишет:

 И пусть оно будет неправильным, но одинаковым - меня это устроит.

Не будет оно одинаковымым. С чего ему быть? Оно же неправильное. Причем - у каждой свое "неправильное".

Ну представте что два человека, спрашивают у третьего "который час?". Причем спрашивают с помощью курьера, а не напрямую. Причем нет даже гарантии что курьер бегает c одинаковой скоростью. Смогут они выставить свои часы "одинаково"?  Ну с какой-то точностью - да. Грубо. А вот "ну совсем точно" .... это врядли.

Что-бы "синхронизироваться" им потребуется как-то "связатся между собой". Что-бы один другому сказал, время. Тот потом в ответ сказал свое. Увидеть "расхождение". Поправить его. Возможно повторить эту операцию несколько раз... статистически "убрать разницу".

И повторять это время от времени. Так как  у каждого часы идут со своей погрешностью). Если только обе дуины не тактируются от одного источника.

leshak
Offline
Зарегистрирован: 29.09.2011

И кстати, если оно у вам важдно только "одинаковость", то зачем вам вообще внешний NTP?  Раз обе дуины подключены к сети, почему одна другую спросить не может "который час на твоей millis()?"?

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами,

Не нужна. :) Просто на второй дуине надо ловить два сигнала: первый - с источника, второй - отраженный: зная расстояние между дуинами - вычисляем расстояние до отраженной цели. Как видите: никакой синхронизации не требуется.

Daemon2017
Offline
Зарегистрирован: 08.10.2013

leshak пишет:

И кстати, если оно у вам важдно только "одинаковость", то зачем вам вообще внешний NTP?  Раз обе дуины подключены к сети, почему одна другую спросить не может "который час на твоей millis()?"?

На тему того, что у обоих время будет неправильное Вы правы, жаль.

Сейчас попробую поступить следующим образом:

1)Мастер подает сигнал слейву.

2)Слейв отсылает свое значение micros() на момент отправки.

3)Мастер записывает свое значение micros() и находит разницу между своим и чужим значением.

4)Мастер объявляет, что в момент времени n он начнет передачу УЗ сигнала. Слейву отсылает значение n+расхождение в часах.

5)В момент n+расхождение слейв начинает прием УЗ-сигнала.

Как сделаю - отпишусь. Правдоподобно выглядит?

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

конечная цель такова: одна ардуинка выпускает из УЗ-дальномера звуковую волну(приёмник у неё отпаян), а вторая ардуинка должна эту волну поймать и сообщить расстояние до первой(излучатель у нее отпаян). Для решения этой задачи необходима синхронизация времени между дуинами,

Не нужна. :) Просто на второй дуине надо ловить два сигнала: первый - с источника, второй - отраженный: зная расстояние между дуинами - вычисляем расстояние до отраженной цели. Как видите: никакой синхронизации не требуется.

А можно поподробнее? Что такое отраженный сигнал?)

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

А можно поподробнее? Что такое отраженный сигнал?)

Ну, Вы же сами пишете "вторая ардуинка должна эту волну поймать". Или Вам между двумя ардуинами расстояние требуется измерить?

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

А можно поподробнее? Что такое отраженный сигнал?)

Ну, Вы же сами пишете "вторая ардуинка должна эту волну поймать". Или Вам между двумя ардуинами расстояние требуется измерить?

Да, я имел ввиду именно замерить расстояние. Понимаю, что несколько извращенно, но таковы условия :)

step962
Offline
Зарегистрирован: 23.05.2011

Вы когда нибудь видели, как спортивный судья работает с секундомером? Услышав выстрел стартового пистолета, он запускает свой секундомер и следит за бегунами на дорожке, чтобы в момент пересечения финишной черты остановить свой агрегат. И ему глубоко фиолетово, какое время показывают часы вышеупомянутого муд...жика с пистолетом. И есть ли у него вообще какие-либо часы.

У вас ситуация аналогичная, поэтому 

0. соедините свои дуинки проводочком (сигнальным). Землю, естественно, тоже пробросьте.

1. В момент генерации УЗ-импульса первая дуинка дергает сигнальный провод. Вторая дуинка запоминает момент этого дергания (t1, он же - момент испускания УЗ-импульса).

2. Первая дуинка больше ничего не делает. Вторая - слушает.....

3. Услышав УЗ-сигнал, испущенный первой дуинкой, вторая запоминает и этот момент (t2, момент прихода УЗ-импульса).

4. Ну а дальше - t2-t1 -> время прохождения УЗ-импульса от источника к приемнику. Умножаем его на скорость распространения звука в воздухе и получаем искомое расстояние.

Резюме: Поскольку скорость распространения электричества в меди существенно больше скорости звука, можно считать, то электросигнал распространяется мгновенно. Синхронизации часов не требуется. Часы нужны только на одной из Ардуин - на той, которая будет заниматься основной работой (вычислениями). От другой Ардуины требуется лишь дернуть сигнальный провод.

Daemon2017
Offline
Зарегистрирован: 08.10.2013

step962 пишет:

Вы когда нибудь видели, как спортивный судья работает с секундомером? Услышав выстрел стартового пистолета, он запускает свой секундомер и следит за бегунами на дорожке, чтобы в момент пересечения финишной черты остановить свой агрегат. И ему глубоко фиолетово, какое время показывают часы вышеупомянутого муд...жика с пистолетом. И есть ли у него вообще какие-либо часы.

У вас ситуация аналогичная, поэтому 

0. соедините свои дуинки проводочком (сигнальным). Землю, естественно, тоже пробросьте.

1. В момент генерации УЗ-импульса первая дуинка дергает сигнальный провод. Вторая дуинка запоминает момент этого дергания (t1, он же - момент испускания УЗ-импульса).

2. Первая дуинка больше ничего не делает. Вторая - слушает.....

3. Услышав УЗ-сигнал, испущенный первой дуинкой, вторая запоминает и этот момент (t2, момент прихода УЗ-импульса).

4. Ну а дальше - t2-t1 -> время прохождения УЗ-импульса от источника к приемнику. Умножаем его на скорость распространения звука в воздухе и получаем искомое расстояние.

Резюме: Поскольку скорость распространения электричества в меди существенно больше скорости звука, можно считать, то электросигнал распространяется мгновенно. Синхронизации часов не требуется. Часы нужны только на одной из Ардуин - на той, которая будет заниматься основной работой (вычислениями). От другой Ардуины требуется лишь дернуть сигнальный провод.

Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.

Код ардуинки-слейва прост до безобразия, даже не знаю, что может быть не так.

void loop() 
{              
    if(digitalRead(7) == HIGH)
    {  
      digitalWrite(sputnic_T_2, HIGH);   
      delayMicroseconds(10);
      digitalWrite(sputnic_T_2, LOW);       
      tim2=pulseIn(sputnic_E_2, HIGH);
          
      data.tim2 = tim2;
       
      ET.sendData(I2C_SLAVE_ADDRESS2); 
      
      delay(200);  
    }   
}

 

step962
Offline
Зарегистрирован: 23.05.2011

Не баловался с УЗ-дальномером, но, насколько я знаю функцию 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 появится искомый импульс, по длительности которого и судить о расстоянии между двумя датчиками. При этом следует экранировать (фетром обернуть) УЗ-передатчик второго датчика, чтобы его сигнал не вносил сумятицу в систему.

Daemon2017
Offline
Зарегистрирован: 08.10.2013

step962 пишет:

Не баловался с УЗ-дальномером, но, насколько я знаю функцию 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 появится искомый импульс, по длительности которого и судить о расстоянии между двумя датчиками. При этом следует экранировать (фетром обернуть) УЗ-передатчик второго датчика, чтобы его сигнал не вносил сумятицу в систему.

У меня оно так и работает, только "глазок" передатчика замотан изолентой)

Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Daemon2017 пишет:

Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.

Импульсы идут достаточно редко? Не может откуда-то приходить отраженный сигнал и портить картинку? Тогда я бы просто ввел поправочный коэффициент и посмотрел - не сильно ли он меняется от расстояния...

Daemon2017
Offline
Зарегистрирован: 08.10.2013

Andrey_Y_Ostanovsky пишет:

Daemon2017 пишет:

Вообще не понимаю, почему в случае с двумя ардуинами расстояние определяется совсем не верно.

Импульсы идут достаточно редко? Не может откуда-то приходить отраженный сигнал и портить картинку? Тогда я бы просто ввел поправочный коэффициент и посмотрел - не сильно ли он меняется от расстояния...

Проблему только что решил!

В чем была загвоздка: когда мы используем применик и передатчик на одном устройстве - он засекает путь от своего излучателя к стене, а потом от стены к себе. Во время расчетов мы делим длинну импульса пополам(т.к. нас интересует расстояние от себя к стене, а не от себя к стене + от стены к себе). Я использвал эту формулу. И в этом была ошибка.

Когда мы одновременно стартуем излучение звука на одной дуине и прием на другой - принимающая дуина засекает сразу необходимое расстояние, которое не нужно делить пополам. Я просто убрал деление на 2 из формулы и все стало отлично.

Формула стала такой: distance_sm=time_us/29;

А была такой: distance_sm=time_us/29/2;

Спасибо всем, кто помогал :)

P.S. ошибку обнаружил, когда сидел на диване и листал мануалы, а в боковом окне было открыто окно монитора порта. И так вышло, что излучатель одной дуины и приемник другой были направлены на потолок. А в мониторе порта светилось число 434. И тут я вспомнил, что высота от дивана до потолка у меня 217 см (т.е. 434/2). Ну тут то меня и осенило - убрал деление пополам и всё заработало :)

step962
Offline
Зарегистрирован: 23.05.2011

Так вы, получается, вводили в заблуждение, когда писали:

Daemon2017 пишет:

Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.

Ведь 50/2=25 и никак не 15?

Кстати, поэтому и передатчик можно не заклеивать - отраженный сигнал придет зна-а-а-ачительно позже, чем прямой от "правильной" ардуины.

Хотя.... на заставленном всякими предметами сцене эхо от какой-нибудь ножки стула может прийти и пораньше.

 

Daemon2017
Offline
Зарегистрирован: 08.10.2013

step962 пишет:

Так вы, получается, вводили в заблуждение, когда писали:

Daemon2017 пишет:

Попробовал сделать так, как Вы посоветовали. Значения поменялись, но... они всё еще даже не близки к действительным. На расстоянии 50 см пишет, что расстояние 15.

Ведь 50/2=25 и никак не 15?

Кстати, поэтому и передатчик можно не заклеивать - отраженный сигнал придет зна-а-а-ачительно позже, чем прямой от "правильной" ардуины.

Хотя.... на заставленном всякими предметами сцене эхо от какой-нибудь ножки стула может прийти и пораньше.

 

Почему он тогда показывал 15 - для приема использовался бракованый дальномер(у него исправный передатчик и сломаный приемник, который показывает слишком маленькие значения). Как только я переставил бракованный дальномер в передающую позицию, а исправный в принимающую - стало выдавать слишком большой результат. Не стал акцентировать внимание,т.к. всё равно неправитльный результат)

Теперь вот ясно, почему такой большой.

Это верно, но лучше заклемит от греха подальше - он может прийти и в следующую итерацию, если задержка между ними слищшком маленькая.