Обмен данными между двумя дуинками с помощью EasyTransfer

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

Хочу сделать так, чтобы две ардуинки одновременно замеряли дистанцию до преграды с помощью УЗ-дальномера. 

Как я это вижу: 

Дуина-master(Mega2560) замеряет расстояние до преграды и отправляет единицу(которая лежит в переменной sygnal) на Дуину-slave(Uno) и та замеряет расстояние, после чего ответ посылает первой, а та выводит его через Serial на компьютер. 

Код дуины-мастера:

#include <EasyTransfer.h>

EasyTransfer ET, ET2; 

struct SEND_DATA_STRUCTURE
{
  int sygnal;
};

struct RECEIVE_DATA_STRUCTURE
{
  float tim2;
};

SEND_DATA_STRUCTURE data2;
RECEIVE_DATA_STRUCTURE data;

#define sputnic_T_1 3
#define sputnic_E_1 2

float tim1, tim2;

void setup() 
{
  Serial.begin(9600);
  Serial1.begin(9600);
  
  ET2.begin(details(data2), &Serial1);
  ET.begin(details(data), &Serial1);
  
  pinMode(sputnic_T_1, OUTPUT); 
  pinMode(sputnic_E_1, INPUT); 
}

void loop() 
{      
  digitalWrite(sputnic_T_1, HIGH);
  delayMicroseconds(1);
  digitalWrite(sputnic_T_1, LOW);
  tim1=pulseIn(sputnic_E_1, HIGH);  
  
  delay(250);  
  
  data2.sygnal=1;
  
  ET2.sendData(); 
       
  if(ET.receiveData())
  {   
  tim2 = data.tim2;
    
  Serial.println(" ");  
  Serial.print("tim1: ");
  Serial.print(tim1, 6);
  Serial.println(" "); 
  
  Serial.print("tim2: ");
  Serial.print(tim2, 6);
  Serial.println(" ");  

  delay(250);  
  }
}

Код дуины-слейва:

#include <EasyTransfer.h>

EasyTransfer ET, ET2; 

struct RECEIVE_DATA_STRUCTURE
{
  int sygnal;
};

struct SEND_DATA_STRUCTURE
{
  float tim2;
};

RECEIVE_DATA_STRUCTURE data2;
SEND_DATA_STRUCTURE data;

#define sputnic_T_2 5
#define sputnic_E_2 4

float tim2;

void setup() 
{
  Serial.begin(9600);
  
  ET2.begin(details(data2), &Serial);
  ET.begin(details(data), &Serial);

  pinMode(sputnic_T_2, OUTPUT); 
  pinMode(sputnic_E_2, INPUT); 
}

void loop() 
{        
  if(ET2.receiveData())
  {  
  digitalWrite(sputnic_T_2, HIGH);   
  delayMicroseconds(1);
  digitalWrite(sputnic_T_2, LOW);
  
  tim2=pulseIn(sputnic_E_2, HIGH);  
 
  data.tim2 = tim2;
    
  ET.sendData(); 

  delay(250);  
  }
}


Что работает:

если убрать проверку прихода информации(т.е. if(ET2.receiveData())) на обоих дуинках и просто разместить там ET2.receiveData(); то вторая дуинка успешно присылает данные на первую, а та выводит их на экран. Беда в том, что данные с них поступают с жутким рассинхроном. Если же вернуть проверку наличия входящего сигнала через if, то на компьютер мне вообще ничего не приходит. Из этого делаю вывод, что либо я делаю что-то не так, либо банально не уходит/не доходит сигнал. Второе вряд ли - занимаюсь проверкой своего кода, но так ничего подозрительного и не нашел.

Буду очень благодарен за помощь!

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

столкнулся на днях с такой же проблемой при обмене mini с DUE. Так вот, грабли оказались вот в чем. 

struct RECEIVE_DATA_STRUCTURE{unsigned long RXCommandC; unsigned long RXDataC; unsigned long RXExtrasC; unsigned int ToNode; };

вроде одна и та же строка. НО как оказалось на платке "мини",  эта строка занимает в памяти 4+4+4+2 = 16 байт. эта же строка в DUE занимает 4+4+4+4 = 16 байт. почему я так и не понял. долно не думал, ибо лень :) сделал на обоих так 

struct RECEIVE_DATA_STRUCTURE{unsigned long RXCommandC; unsigned long RXDataC; unsigned long RXExtrasC; unsigned long ToNode; };

и на обоих получается 4+4+4+4 = 16 байт. а зачем это всё? а затем, что библиотека EasyTransfer сверяет длинну полученного пакета и длину объявленого struct. В самом файле EasyTransfer.cpp эта проверка выглядит так.

rx_len = _stream->read();
		//make sure the binary structs on both Arduinos are the same size.
        if(rx_len != size){
          rx_len = 0;
          return false;

можно конечно убрать эту проверку, но мне показалось это не правильным.

 

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

Хм, я слышал, что int имеет разное значение в 16 и 32 битных системах, но не думал, что это касается ардуино)

Т.е. Вы предлагаете привести объем всех переменных к более крупному, либо отключить проверку?

Спасибо, сейчас попробую. Не исключаю, что так оно и будет, ведь с float'ной переменной передача/прием работает. Кстати, как Вы поняли, что int на этих платах занимает разное число байт?

Garry
Garry аватар
Offline
Зарегистрирован: 07.04.2012

Daemon2017 пишет:

Кстати, как Вы поняли, что int на этих платах занимает разное число байт?

http://arduino.cc/en/Reference/Int#.UwdibuOqmfA

Особо не вдавался в ваш код в первом посте, но что сразу бросатеся в глаза - Serial1.begin(9600); Что мешает поставит скорость передачи больше?

Garry
Garry аватар
Offline
Зарегистрирован: 07.04.2012

Сигнал синхронизации можно передать через любой свободный pin, а не гонять по сериал int. Получится так: мастер сделал измерение, выставил синхросигнал на пине, слэйв по прерыванию словил синхросигнал, сделал измерение и предал измерение мастеру. Логику с синхросигналом проработать только.

А зачем такая система - двух измерений на разных устройствах, интересно?

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

Огромное спасибо, pmaster!

Дело действительно было в int'е. Поменял на float и заработало. Но почему-то значение расстояния(tim2), которое я получаю с Uno, равно значению sygnal, которое я на неё же подаю с Mega. Ума не приложу, чем это вызвано.

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

Garry, я рассматривал такой вариант, но он мне казался костылем и я рассчитывал обойтись без него. Более высокую скорость пока не пытался ставить :)

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

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

Я сам не понимал, пока не стал разбирать всё библиотеку, выводя все данные в терминал. тут то и заметил, что длинна пакетов разная. Поменял тип переменной и заработало. а зачем передавать float ? unsigned long не устраивает?

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

Здорово, что Вы проделали эту работу!

Устраивает, просто остальные переменные в этом же типе данных храню и решил опробовать не отходя от традиции. Код теперь выглядит так:

Uno(Slave) -

#include <EasyTransfer.h>

EasyTransfer ET, ET2; 

struct RECEIVE_DATA_STRUCTURE
{
  float signal;
};

struct SEND_DATA_STRUCTURE
{
  float tim2;
};

RECEIVE_DATA_STRUCTURE data2;
SEND_DATA_STRUCTURE data;

#define sputnic_T_2 5
#define sputnic_E_2 4

float tim2;

void setup() 
{
  Serial.begin(115200);
  
  ET2.begin(details(data2), &Serial);
  ET.begin(details(data), &Serial);

  pinMode(sputnic_T_2, OUTPUT); 
  pinMode(sputnic_E_2, INPUT); 
}

void loop() 
{        
  if(ET2.receiveData())
  {  
    digitalWrite(sputnic_T_2, HIGH);   
    delayMicroseconds(10);
    digitalWrite(sputnic_T_2, LOW);
    
    tim2=pulseIn(sputnic_E_2, HIGH);  
   
    delay(250); 
   
    data.tim2 = tim2;
      
    ET.sendData();     
  }
}

Mega(Master) -

#include <EasyTransfer.h>

EasyTransfer ET, ET2; 

struct SEND_DATA_STRUCTURE
{
  float signal;
};

struct RECEIVE_DATA_STRUCTURE
{
  float tim2;
};

SEND_DATA_STRUCTURE data2;
RECEIVE_DATA_STRUCTURE data;

#define sputnic_T_1 3
#define sputnic_E_1 2

float tim1, tim2;

void setup() 
{
  Serial.begin(9600);
  Serial1.begin(115200);
  
  ET2.begin(details(data2), &Serial1);
  ET.begin(details(data), &Serial1);
  
  pinMode(sputnic_T_1, OUTPUT); 
  pinMode(sputnic_E_1, INPUT); 
}

void loop() 
{      
  digitalWrite(sputnic_T_1, HIGH);
  delayMicroseconds(10);
  digitalWrite(sputnic_T_1, LOW);

  tim1=pulseIn(sputnic_E_1, HIGH);  
  
  delay(250);  

  data2.signal = 5;
   
  ET2.sendData(); 
        
  if(ET.receiveData())
  {    
  tim2 = data.tim2;
    
  Serial.println(" ");  
  Serial.print("tim1: ");
  Serial.print(tim1, 0);
  Serial.println(" "); 
  
  Serial.print("tim2: ");
  Serial.print(tim2, 0);
  Serial.println(" ");  

  delay(250);  
  }
}

Ума не приложу, почему пятерка, которую я отсылаю на Uno возвращается мне на Mega вместо значения tim2. 

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

Нашел свой косяк: забыл подключить общую линию заземления. Как только добавил - заработало как надо :)