Пульт управления RC лодкой с двухканальной связью NRF24L01- Chat GPT

Пробовал с мегабит, ничего не изменилось. Не вышло также передать напряжение пусть даже на ручных командах прием\передачи. В итоге решил сделать отдельный канал связи для вольтметра - просто добавится пара nRF24L01, будет торчать 2 антенну у лодки и 2 антенны в пульте. Потребление немного вырастет, ну да ладно, это не критично. При простой передаче в одну стороноу чего угодно, все работает сразу, но как только любым способом пытаешься слать назад по тому же каналу, не работает. Не думаю что проблема в поддельных модулях, у меня они примерно по 400 р каждый. В таком исполнении как меня дороже не нашел на али, видимо есть с ПО свои тонкости.

модули какие-то я ещё могу найти, но нанок нету, можно было попробовать, не может код не работать

Код передатчика, но АСК должен работать и на скорости 250, по крайней мере в примерах эта скорость выставлена

//Transmitter -https://forum.arduino.cc/t/simple-nrf24l01-2-4ghz-transceiver-demo/405123/3

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
const uint64_t pipeOut = 0xABCDABCD71LL;         // NOTE: The address in the Transmitter and Receiver code must be the same "0xABCDABCD71LL"
RF24 radio(9, 10);                               // select CE,CSN pin

int ackData[2] = { -1, -1}; // to hold the two values coming from the slave
bool newData = false;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second

struct Signal {
  byte throttle;
  byte pitch;
  byte roll;
  byte yaw;
  byte aux1;
  byte aux2;
};
Signal data;

void ResetData()
{
  data.throttle = 0;
  data.pitch = 127;
  data.roll = 127;
  data.yaw = 127;
  data.aux1 = 0;
  data.aux2 = 0;

}
void setup()
{
  // Configure the NRF24 module
  radio.begin();
  radio.enableAckPayload();
  radio.setRetries(5, 5);             // delay, count
  radio.openWritingPipe(pipeOut);
  radio.setChannel(100);
  radio.setAutoAck(true);
  radio.setDataRate(RF24_1MBPS);      // The lowest data rate value for more stable communication
  radio.setPALevel(RF24_PA_MAX);      // Output power is set for maximum range
  // radio.stopListening();              // Start the radio comunication for Transmitter
  ResetData();
}


// Joystick center and its borders
int Border_Map(int val, int lower, int middle, int upper, bool reverse)
{
  val = constrain(val, lower, upper);
  if ( val < middle )
    val = map(val, lower, middle, 0, 128);
  else
    val = map(val, middle, upper, 128, 255);
  return ( reverse ? 255 - val : val );
}


void loop()
{
  data.roll = Border_Map( analogRead(A3), 0, 512, 1023, true );        // CH1   Note: "true" or "false" for signal direction
  data.pitch = Border_Map( analogRead(A0), 0, 512, 1023, true );       // CH2
  data.throttle = Border_Map( analogRead(A2), 0, 340, 570, true );     // CH3   Note: For Single side ESC |
  // data.throttle = Border_Map( analogRead(A2),0, 512, 1023, true );  // CH3   Note: For Bidirectional ESC |
  data.yaw = Border_Map( analogRead(A1), 0, 512, 1023, false );        // CH4
  data.aux1 = digitalRead(0);                                          // CH5
  data.aux2 = digitalRead(3);                                          // CH6
  if (millis() - prevMillis >= txIntervalMillis) {
    bool rslt;
    rslt = radio.write(&data, sizeof(Signal));
    if (rslt) {
      if ( radio.isAckPayloadAvailable() ) {
        radio.read(&ackData, sizeof(ackData));
        newData = true;
      }
    }
    prevMillis = millis();
  }
  if(newData){
   Serial.println("Напряжение батареи считано!");
   Serial.print("Датчик 1 = ");
   Serial.println(ackData[0]);
   Serial.print("Датчик 2 = ");
   Serial.println(ackData[1]);   
   newData = false;
  }
}

Да. Это я ошибся, почему то уверен был что в даташите так было.
@RCboat , скетч без вольтей сейчас точно работает?
Если опыты на столе, то уменьшай мощность.
С модулей бы состояние регистра статуса смотреть на каждом шаге не помешало.

Я промудохался с заказчиком и потратил кучу времени что бы выяснить что его китайские модули не равны моим китайским модулям. Пришлось переписать весь софт под то что работало у него. Ужос. Мужик заплатил, но был не доволен.(

ну так тема о том, что 99% модулей NRF24L01 подделка давно муссируется, нормальный модуль стоит в районе 500 руб. но никак не 100 )))

Там выше по ссылке есть два скетча, приёмник и передатчик, просто скопируй их и выдай сюда результат, работает или нет, на оригинальных - работает

На моих модулях сервы не реагируют на джойстик с этими скетчами. Видимо нужно заказать ведро NRF24L01 с али, чтобы было что выбрать…

У меня модули точно такие ,стоили в районе 400р за штуку https://www.ebyte.com/en/product-view-news.aspx?id=450

без ACK ты жеж говорил, что работает

Вощем так:

  1. Пробуем связь с НРФ по SPI
  2. Пробуем в режиме noACK передавать в эфир
  3. Пробуем приёмником поймать сигнал
  4. А теперь передаём в режиме АСК
  5. И только теперь уже можно под себя что-то добавлять-убавлять.
    В этом деле сложно и долго искать причину если нет связи. Косяк может быть где угодно, для этого и надо смотреть регистр статуса после каждого действия с модулем.
    Возможен косяк в монтаже или нет подтверждения или переполнен буфер или просто не рабочая.

а вот и проект на ELRS модулях презентовали:

А в чём смысл ExpressLRS ? Пульт и приёмник такие же как и у любой другой фирмы. Или приёмник программируется тоже?

Вот это девочка удивлённая :smiley:

если не врут то на модулях на 430 на одно ваттных дальность чуть ли не 130 километров (врут конечно), надо смотреть как высоко стоит тропа, ночью она выше 3 километров поднимается, а вот утром опускается до 1800 где-то, а то и ниже, то есть если мы летим на высоте до тропы связь будет,выше, сильное экранирование, к примеру сидит у меня приятель на Эльбрусе и пока он в базовом лагере связь нормальная, как только полез на скалы Ленца - неустойчивая, 430 мегагерц, антенна направленная 3 элемента, 5 ватт, расстояние порядка 75-85 километров

Модули конечно шикарные, дело в протоколе, есть конфигуратор, там можно много что улучшить.

Подкупает готовый пульт. А так я больше к Лоре склоняюсь. Ибо там можно сделать всё что угодно.

и библиотеки есть, вот под ESP/STM32

То есть приёмник как всякие Лоры и НРФ можно и в хвост и в гриву посредством МК?

так он так и делается, в основном на модулях в качестве управляющего контроллера ST8 разные используются, поэтому сторонние прошивки не на всех модулях идут, так как контроллеры там бывают разные

Хм. На досуге поизучаю эту занятную вещь. Даташит покурю.

Там по приёму бюджет в минус 146дб, есть желание в сканер и этот модуль применить

так как ардуино нано у меня нет попробуем тестовый скетч сделать на том, что есть:

Приёмник:

// SimpleRxAckPayload- the slave or the receiver (RP2040) 06.02.2024

#include <Adafruit_GFX.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// ILI9341
#include <Adafruit_ILI9341.h> // Hardware-specific library for ILI9341 240x320
#include <Adafruit_ST7789.h>  // Hardware-specific library for ST7789

// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000       ///<   0,   0,   0
#define ST77XX_NAVY 0x000F        ///<   0,   0, 123
#define ST77XX_DARKGREEN 0x03E0   ///<   0, 125,   0
#define ST77XX_DARKCYAN 0x03EF    ///<   0, 125, 123
#define ST77XX_MAROON 0x7800      ///< 123,   0,   0
#define ST77XX_PURPLE 0x780F      ///< 123,   0, 123
#define ST77XX_OLIVE 0x7BE0       ///< 123, 125,   0
#define ST77XX_LIGHTGREY 0xC618   ///< 198, 195, 198
#define ST77XX_DARKGREY 0x7BEF    ///< 123, 125, 123
#define ST77XX_BLUE 0x001F        ///<   0,   0, 255
#define ST77XX_GREEN 0x07E0       ///<   0, 255,   0
#define ST77XX_CYAN 0x07FF        ///<   0, 255, 255
#define ST77XX_RED 0xF800         ///< 255,   0,   0
#define ST77XX_MAGENTA 0xF81F     ///< 255,   0, 255
#define ST77XX_YELLOW 0xFFE0      ///< 255, 255,   0
#define ST77XX_WHITE 0xFFFF       ///< 255, 255, 255
#define ST77XX_ORANGE 0xFD20      ///< 255, 165,   0
#define ST77XX_GREENYELLOW 0xAFE5 ///< 173, 255,  41
#define ST77XX_PINK 0xFC18        ///< 255, 130, 198

#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
      defined(ARDUINO_GENERIC_RP2040) ||defined(ARDUINO_RASPBERRY_PI_PICO_W) )

// замаркировать если используем наоборот
#define SPI01             // Дисплей на SPIO1, NRF24L01 на SPI0 (выбор между SPI0 и SPI1)
#if defined(SPI01)        // для RP2040 SPI1
#define TFT_CS        13  // GP13 - CS              (hard - 13)
#define TFT_RST       10  // GP14 - RESET           (10)  
#define TFT_DC        11  // GP15 - A0              (11)  
#define TFT_MISO      12  // GP12 - MISO (MISO, RX) (hard - 12)
#define TFT_MOSI      15  // GP11 - SDA  (MOSI, TX) (hard - 15)
#define TFT_SCLK      14  // GP10 - SCK             (hard - 14)
#else                     // для RP2040 SPI0
#define TFT_CS        17  //5   // GP5 - CS               (hard - 17)
#define TFT_RST       20  //6   // GP6 - RESET
#define TFT_DC        21  //7   // GP7 - A0
#define TFT_MISO      16  //4   // GP4 - MISO (MISO, RX)  (hard - 16)
#define TFT_MOSI      19  //3   // GP3 - SDA  (MOSI, TX)  (hard - 19)
#define TFT_SCLK      18  //2   // GP2 - SCK              (hard - 18)
#endif



// SPI definitions and macros то NRF24L01
#if defined(SPI01)
#define CE_pin    21 //7
#define RST_pin   20 // не используется
#define CS_pin    17 //5
#define MOSI_pin  19 //3
#define MISO_pin  16 //4
#define SCK_pin   18 //2
#else
#define CE_pin    11 //15
#define RST_pin   10 // не используется
#define CS_pin    13
#define MOSI_pin  15 //11
#define MISO_pin  12
#define SCK_pin   14 //10
#endif
#include "api/HardwareSPI.h"
#endif

//hard SPI01 для RP2040
Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI1, TFT_DC, TFT_CS, TFT_RST); //via hard SPI1 old LIB


const byte thisSlaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};

RF24 radio(CE_pin, CS_pin);

char dataReceived[10]; // this must match dataToSend in the TX
int ackData[2] = {109, -4000}; // the two values to be sent to the master
bool newData = false;

//==============

void setup() {

  Serial.begin(115200);
  delay(5000);

  Serial.println("SimpleRxAckPayload Starting");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.openReadingPipe(1, thisSlaveAddress);

  radio.enableAckPayload();

  radio.startListening();

  radio.writeAckPayload(1, &ackData, sizeof(ackData)); // pre-load data
}

//==========

void loop() {
  getData();
  showData();
}

//============

void getData() {
  if ( radio.available() ) {
    radio.read( &dataReceived, sizeof(dataReceived) );
    updateReplyData();
    newData = true;
  }
}

//================

void showData() {
  if (newData == true) {
    Serial.print("Data received ");
    Serial.println(dataReceived);
    Serial.print(" ackPayload sent ");
    Serial.print(ackData[0]);
    Serial.print(", ");
    Serial.println(ackData[1]);
    newData = false;
  }
}

//================

void updateReplyData() {
  ackData[0] -= 1;
  ackData[1] -= 1;
  if (ackData[0] < 100) {
    ackData[0] = 109;
  }
  if (ackData[1] < -4009) {
    ackData[1] = -4000;
  }
  radio.writeAckPayload(1, &ackData, sizeof(ackData)); // load the payload for the next time
}