ARDUINO Машинка на nrf24l01

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
@Arhat109, Вот я и не могу понять сам, почему приёмник видит только 0 и 2 элементы массива, хотя передаются нормально передатчиком все 4. Кусок скетча про радиоприём и передачу брал у автора здесь
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
@leeroy, значит приемник не видит. Или передатчик только "делает вид", что отправляет 4 куска массива. Присоединяюсь к предыдущему, а то мне пока этот код "не по глазам" (хрустальный шар выключен).
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
@Старик Похабыч, @Arhat109,
В общем, сделал управление движками по-своему, тривиально, но все же. Скетч автора про радиоуправление скопировал. Получается, что у меня один джостик - движение прямо-назад, второй джостик - поворот налево-направо при движении и разворот налево-направо при остановке.

ПЕРЕДАТЧИК:
C++:
#include <SPI.h>          // библиотека для работы с шиной SPI

#include "nRF24L01.h"     // библиотека радиомодуля

#include "RF24.h"         // ещё библиотека радиомодуля



RF24 radio(9, 10);





byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб

byte transmit_data[4];





void setup() {

  Serial.begin(9600); //открываем порт для связи с ПК



  radio.begin(); //активировать модуль

  radio.setAutoAck(0);         //режим подтверждения приёма, 1 вкл 0 выкл

  radio.setRetries(0, 0);    //время между попыткой достучаться, число попыток

  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал

  radio.setPayloadSize(32);     //размер пакета, в байтах



  radio.openWritingPipe(address[0]);   //мы - труба 0, открываем канал для передачи данных

  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)



  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX

  radio.setDataRate (RF24_1MBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS

  //должна быть одинакова на приёмнике и передатчике!

  //при самой низкой скорости имеем самую высокую чувствительность и дальность!



  radio.powerUp(); //начать работу

  radio.stopListening();  //не слушаем радиоэфир, мы передатчик

}
void loop() {

int x1Val, y1Val, x2Val, y2Val;
  x1Val = analogRead(A0);
  y1Val = analogRead(A1);
  x2Val = analogRead(A2);
  y2Val = analogRead(A3);
 
  transmit_data[0] = map(x1Val, 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси X

  //Serial.print(" | ");
  //Serial.print(x1Val, DEC);

  transmit_data[1] = map(y1Val, 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси Y

    //Serial.print(" | ");
  //Serial.print(y1Val, DEC);

  transmit_data[2] = map(x2Val, 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси X
  //Serial.print(" | ");
  //Serial.print(x2Val, DEC);

  transmit_data[3] = map(y2Val, 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси Y
  //Serial.print(" | ");
  //Serial.println(y2Val, DEC);
Serial.print(transmit_data[0]); Serial.print(" | "); Serial.print(transmit_data[1]); Serial.print(" | "); Serial.print(transmit_data[2]); Serial.print(" | "); Serial.print(transmit_data[3]); Serial.println(" | ");
  radio.write(&transmit_data, sizeof(transmit_data)); //отправляем получившийся массив
}
ПРИЕМНИК:
C++:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9,10); // "создать" модуль на пинах 9 и 10 Для Уно
//RF24 radio(9,53); // для Меги

byte address[][6] = {"1Node","2Node","3Node","4Node","5Node","6Node"};  //возможные номера труб
byte recieved_data[4];
void setup(){
  Serial.begin(9600); //открываем порт для связи с ПК

  pinMode(4, OUTPUT);

  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(5, OUTPUT);

  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(6, OUTPUT);


  radio.begin(); //активировать модуль
  radio.setAutoAck(0);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0,15);     //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах

  radio.openReadingPipe(1,address[0]);      //хотим слушать трубу 0
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)

  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate (RF24_1MBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //должна быть одинакова на приёмнике и передатчике!
  //при самой низкой скорости имеем самую высокую чувствительность и дальность!!

  radio.powerUp(); //начать работу
  radio.startListening();  //начинаем слушать эфир, мы приёмный модуль
}

void loop() {
    byte pipeNo;                   
    while( radio.available(&pipeNo)){    // слушаем эфир со всех труб
      radio.read( &recieved_data, sizeof(recieved_data) ); //читаем присланный массив
      digitalWrite(4, HIGH);//STBY
      //Serial.print(recieved_data[0]); Serial.print(" | "); Serial.print(recieved_data[1]); Serial.print(" | "); Serial.print(recieved_data[2]); Serial.print(" | "); Serial.println(recieved_data[3]);
//      int x1p = constrain(map(recieved_data[1], 128, 255, 0, 255), 0, 255); //обрезаем и переворачиваем значения
//      int x1b = constrain(map(recieved_data[1], 128, 0, 0, 255), 0, 255); //обрезаем и переворачиваем значения
//      int y2r = constrain(map(recieved_data[2], 122, 255, 100, 1), 0, 100); //обрезаем и переворачиваем значения
//      int y2l = constrain(map(recieved_data[2], 122, 0, 100, 1), 0, 100); //обрезаем и переворачиваем значения
//   
//      int stl = constrain(map(recieved_data[2], 123, 255, 0, 255), 0, 255); //обрезаем и переворачиваем значения
//      int str = constrain(map(recieved_data[2], 122, 0, 0, 255), 0, 255); //обрезаем и переворачиваем значения
//   
      //Serial.print(x1p); Serial.print(" | "); Serial.print(x1b); Serial.print(" | "); Serial.print(y2r); Serial.print(" | "); Serial.print(y2l); Serial.println();
//      int spr = constrain(x1p * y2r / 100, 0, 255); //скорость правого колеса
//      int spl = constrain(x1p * y2l / 100, 0, 255); //скорость левого колеса
//      int bspr = constrain(x1b * y2r / 100, 0, 255); //скорость правого колеса назад
//      int bspl = constrain(x1b * y2l / 100, 0, 255); //скорость левого колеса назад
      //Serial.print(stl); Serial.print(" | "); Serial.print(str); Serial.println();
      //Serial.print(recieved_data[2]); Serial.println();
      int FB=recieved_data[0];
      int LR=recieved_data[2];
      Serial.println(LR);
      if ((FB>=0) && (FB<=150))//движение НАЗАД
    {   if ((LR>=180) && (LR<=255)){ // и поворот направо
        digitalWrite(A1, LOW);
        digitalWrite(A0, LOW);
        
        digitalWrite(7, LOW);
        digitalWrite(8, HIGH);
        analogWrite(6, 1023);      }
        else if ((LR>=0) && (LR<=150)){ //и поворот налево
        digitalWrite(A1, LOW);
        digitalWrite(A0, HIGH);
        analogWrite(5, 1023);

        digitalWrite(7, LOW);
        digitalWrite(8, LOW);         }
        else{                            // и просто НАЗАД
          digitalWrite(A1, LOW);
        digitalWrite(A0, HIGH);
        analogWrite(5, 1023);

        digitalWrite(7, LOW);
        digitalWrite(8, HIGH);
        analogWrite(6, 1023);
            }
        }
        
     else if ((FB>=190) && (FB<=255)) //движение ВПЕРЕД
    { if ((LR>=180) && (LR<=255)){ // и поворот направо
        digitalWrite(A1, LOW);
        digitalWrite(A0, LOW);
        
        digitalWrite(7, !LOW);
        digitalWrite(8, !HIGH);
        analogWrite(6, 1023);      }
        else if ((LR>=0) && (LR<=150)){ //и поворот налево
        digitalWrite(A1, !LOW);
        digitalWrite(A0, !HIGH);
        analogWrite(5, 1023);

        digitalWrite(7, LOW);
        digitalWrite(8, LOW);         }
        else{                            // и просто Вперед
          digitalWrite(A1, !LOW);
        digitalWrite(A0, !HIGH);
        analogWrite(5, 1023);

        digitalWrite(7, !LOW);
        digitalWrite(8, !HIGH);
        analogWrite(6, 1023);
            }
    }else
    { if ((LR>=180) && (LR<=255)){ // Разворот налево
        digitalWrite(A1, HIGH);
        digitalWrite(A0, LOW);
        analogWrite(5, 1023);
        
        digitalWrite(7, LOW);
        digitalWrite(8, HIGH);
        analogWrite(6, 1023);
        }
        else if ((LR>=0) && (LR<=150)){ //Разворот направо

          
        digitalWrite(A1, LOW);
        digitalWrite(A0, HIGH);
        analogWrite(5, 1023);

        digitalWrite(7, HIGH);
        digitalWrite(8, LOW);
        analogWrite(6, 1023);
        }
        else{                            // стоп
          digitalWrite(A1, LOW);
        digitalWrite(A0, LOW);
        

        digitalWrite(7, LOW);
        digitalWrite(8, LOW);
        
            }
      }

    




      
  }
}
И проблема по-прежнему остается, показания оси Y обоих джостиков не передаются к приемнику, но отправляются передатчиком.. В будущем, конечно, хотелось бы перенести полностью управление движением на один стик, а на второй повесить управление башни, орудием.
Видео как работает сейчас: https://yadi.sk/i/1C8L9fqJyc6kkA
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
вот эта строка в передатчике
Serial.print(transmit_data[0]); Serial.print(" | "); Serial.print(transmit_data[1]); Serial.print(" | "); Serial.print(transmit_data[2]); Serial.print(" | "); Serial.print(transmit_data[3]); Serial.println(" | ");

выдает адекватные значения или уже нет ?
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Не вижу в приёмнике чтение элементов 1 и 3 принятого массива данных.
да, я забыл указать, что выводил значения принятых элементов 1 и 3 приемником в монитор порта, они при отклонении джостиков по соответствующим осям не меняются, в отличие от 0 и 2
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
Да, данные recieved_data[1] и recieved_data[3] никак не используются.

Сразу после приема данные закомментирована такая строка

//Serial.print(recieved_data[0]); Serial.print(" | "); Serial.print(recieved_data[1]); Serial.print(" | "); Serial.print(recieved_data[2]); Serial.print(" | "); Serial.println(recieved_data[3]);

Я так понимаю машинку к компу подключали и смотрели что приходит ? получается теряется где то в воздухе ? (несмотря на то, что часть данных не используется далее)
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Да, данные recieved_data[1] и recieved_data[3] никак не используются.

Сразу после приема данные закомментирована такая строка

//Serial.print(recieved_data[0]); Serial.print(" | "); Serial.print(recieved_data[1]); Serial.print(" | "); Serial.print(recieved_data[2]); Serial.print(" | "); Serial.println(recieved_data[3]);

Я так понимаю машинку к компу подключали и смотрели что приходит ? получается теряется где то в воздухе ? (несмотря на то, что часть данных не используется далее)
Именно так, вне зависимости от того, используются ли данные, приходят изменяемые значения только X (или 0 и 2 элементы массива), Y приходят как константы вне зависимости от положения джойстика.
Еще один вопрос. как выбирали канал передачи ?
Здесь ничего не скажу, я с радиоуправлением впервые сталкиваюсь и немного нуб в этом... просто скопировал часть кода про радиоуправление у автора, уже писал об этом
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
Если есть еще модули нрф ? есть есть возможность поочередно поменять передающий и принимающий модули.

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

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
@Старик Похабыч, попробовал перебрать модули (у меня их 6 штук имеется), везде тоже самое. По видео Гайвера посмотрел зашумленность каналов - конкретно этот чистый, но на всякий случай сменил на другой - и опять тоже самое...
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Если я правильно понял, то:
byte recieved_data[4]; -- это 4 байта, как место получения данных из приемника.
radio.read( &recieved_data, sizeof(recieved_data) ); -- читаем (надеюсь правильно) эти 4 байта как переданные значения джойстиков.

int FB=recieved_data[0]; -- читаем ОДИН байт из приема и превращаем его в int
int LR=recieved_data[2]; -- аналогично.

Далее по коду приемника использованы только эта пара показаний в управлении .. и? Что ви хатели от приемника? :)

То, что используете, то и получаете. значения из индексов 1 и 3 нигде не используются, как они должны влиять на управление по-вашему? Ответ: НИКАК.

У вас там закомментирована строка, и ваш ответ "они не меняются". А проверка в передатчике пишете что все нормально.

Стало быть проблема в методе read() .. он точно читает поток байтов как надо, а не преобразует их в знаковые целые "по пути"?
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
Так то так, но он пишет, что проверял строку приема полностью, в коде приемника сразу за радио.реадом под комментарием..
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
@Старик Похабыч, там надо смотреть КАК библиотека формирует пакет передачи и КАК он принимается приемником.

Нашел гитхаб библиотеки ..
/**
* Read the payload
*
* Return the last payload received
*
* The size of data read is the fixed payload size, see getPayloadSize()
*
* @note I specifically chose 'void*' as a data type to make it easier
* for beginners to use. No casting needed.
*
* @param buf Pointer to a buffer where the data should be written
* @param len Maximum number of bytes to read into the buffer
* @return True if the payload was delivered successfully false if not
*/
bool read( void* buf, uint8_t len );

это описание метода .. как видим есть некий буфер приема payload и его размер в setup() тут в .. 32 байта. А принимаем только 4 числа .. беззнаковых(!) байта. ИМХО, где-то тут порылась собака..
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Весь прием, на самом деле, ведется этим методом:
C++:
uint8_t RF24::read_payload(void* buf, uint8_t len)
{
  uint8_t status;
  uint8_t* current = reinterpret_cast<uint8_t*>(buf);

  uint8_t data_len = min(len,payload_size);
  uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len;
 
  //printf("[Reading %u bytes %u blanks]",data_len,blank_len);
 
  csn(LOW);
  status = SPI.transfer( R_RX_PAYLOAD );
  while ( data_len-- )
    *current++ = SPI.transfer(0xff);
  while ( blank_len-- )
    SPI.transfer(0xff);
  csn(HIGH);

  return status;
}
Как видим, в вашем случае, он мало того что принимает указанные вами (его параметры - прямые из метода read()! ) 4 байта, но ещё и "срет в память", затирая ещё 32-4 = 28 байт... т.е. размер буфера у вас указан в 32 байта.

Стоит воткнуть отладочную печать в цикл приема и посмотреть что он там делает в реальности.. но мне кажется, что Вам надо привести размер payloadSize к размеру вашего буфера и пакета.. в первую очередь.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
тоже сначала думал, что буфер на что то влияет. но посмотрев свой код (тот, который работает, но не тот. что нравится, на потом оставленный) увидел тот же буфер 32 байте. и пофиг на знак, там же по ссылке идет запись в память. и 1-ое что я делал проверял надежность передачи. Работает без потерь и пропусков. для получения сделал небольшую задержку, что бы гарантированно было что получать
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Да, невнимателен. Бланком заполняется только в случае динамически изменяемого размера буфера. В остальных приминает только что сказано в вызове. Просто не работал с этой библиотекой ни разу.

Нужен показ результата отладки передатчика, что он в эфир гонит все 4 числа правильно и результат отладки чтения приемником, что он там получает на самом деле. Пока непонятно, что тут может быть не так.
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Удивительно. Такое ощущение, что приемник пропускает каждый второй элемент массива. Поэкспериментировал немного и вместо отправки массива из 4 значений, отправил массив из 2 значений, тех самых, что не "ловились" приемником, они же 1 и 3, они же Y1 и Y2 где 1 и 2 - джойстики... Приемник при выводе в монитор порта ловит изменения по Y1, а Y2 опять как константу. Вот как это обьяснить? При том, опять же, что у передатчика сразу перед строкой записи в эфир я вывожу в монитор эти значения, и они изменяются нормально при отклонении стиков
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
общие мысли.. обновить IDE, удалить библиотеку NRF, всею отовсюду... скачать новую из менеджера библиотек..
В конце концов попробовать еще примеры. А вот интересно! если сделать "финт ушами"
вместо строки вот этой
radio.write(&transmit_data, sizeof(transmit_data));
написать 4 штуки

radio.write(&transmit_data[0], 1));
radio.write(&transmit_data[1], 1));
radio.write(&transmit_data[2], 1));
radio.write(&transmit_data[3], 1));

Что получит приемник ? потом можно попробовать считывать по 1 му байту, а не весь пакет. может тогда получиться найти где рыть. а то пока даже непонятно в каком из скетчей засада
 

ol82

✩✩✩✩✩✩✩
21 Сен 2019
1
0
Здравствуйте, уважаемые. У меня работает с одним стиком, и вперед-назад, и повороты. Подключаю назад второй - начинают работать раздельно. А хотелось бы со 2-го стика, как сказал leeroy, и сервой поводить. Кто в теме, как в коде пару серв прикрутить на А4-А5 в передатчике (ну и в приемнике соответственно)?
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
@ol82, насколько почитал про эти шилды - это очень непростой и капризный интсрумент, в т.ч. и аппаратно шилды сделаны через задний проход. Там надо тщательно разбираться, видел тему на радиокоте за него - очень много чего полезного народ накопал. Жаль ссыль потерял.
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
UPD.
Решил в передатчике задублировать каждый элемент передаваемого массива таким образом:
C++:
transmit_data[0] = map(analogRead(A0), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси X

  //Serial.print(" | ");
  //Serial.print(x1Val, DEC);

  transmit_data[1] = map(analogRead(A0), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси X

    //Serial.print(" | ");
  //Serial.print(y1Val, DEC);

  transmit_data[2] = map(analogRead(A1), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси Y
  //Serial.print(" | ");
  //Serial.print(x2Val, DEC);

  transmit_data[3] = map(analogRead(A1), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 1 оси Y
  //Serial.print(" | ");
  //Serial.println(y2Val, DEC);
  transmit_data[4] = map(analogRead(A2), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси X

  //Serial.print(" | ");
  //Serial.print(x1Val, DEC);

  transmit_data[5] = map(analogRead(A2), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси X

    //Serial.print(" | ");
  //Serial.print(y1Val, DEC);

  transmit_data[6] = map(analogRead(A3), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси Y
  //Serial.print(" | ");
  //Serial.print(x2Val, DEC);

  transmit_data[7] = map(analogRead(A3), 0, 1023, 0, 255); //считываем и обрезаем показания с джостика 2 оси Y
  //Serial.print(" | ");
  //Serial.println(y2Val, DEC);
Т.е. теперь отправляю массив из 8 значений, состоящего по сути их 4 повторяющихся/одинаковых.
В приемнике соответственно также получаю массив из 8 значений, и результаты вообще странные:

При изменении положения оси X стика 1 в приемнике отображаются изменения по 1 и 6 элементам массива (одинаково);
При изменении положения оси Y стика 1 в приемнике отображаются изменения по 3 и 8 элементам массива (одинаково);
При изменении положения оси X стика 2 в приемнике отображаются изменения по 5-му элементу массива;
При изменении положения оси Y стика 2 в приемнике отображаются изменения по 7-му элементу массива.

А 2-е и 4-е (received_data[1] и received_data[3]) элементы принятого массива по прежнему отображаются как константы и по сути игнорируются чтоли, т.е. как и раньше...
Тем не менее, получается, можно использовать оба джостика полноценно, но затрагивать для этого 2 лишних канала, т.е. массив из 6 значений, потому что приемник в упор не видит 2-ой и 4-й элемент... как-то так. Дальше уже буду экспериментировать, когда ко мне приедет драйвер-шилд на несколько моторов и буду уже пробовать управлять 1 стиком движениями ходовой, а вторым - поворотом башни и вертикальный ход орудия, и уже буду смотреть точно что получается.