nRF24L01+ : побеждаем модуль.

Тема в разделе "Проводная и беспроводная связь", создана пользователем ИгорьК, 19 июн 2014.

  1. ИгорьК

    ИгорьК Гуру

    Эта тема для ардуинщиков - тех лохов сталеваров и трактористов, которые повелись на лозунг "Ардуино - это просто" и без образования и подготовки начали покупать эти смешные чичачки.
    Тему писал полный лох.
    Но сделал все, чтобы с нулевым уровнем подготовки заставить эту гадину работать и она работает до сих пор.
     
    Последнее редактирование: 14 июн 2018
  2. Переключаюсь между режимами для того что бы получить ответ об успешно выполненной команде с полезными данными. Загрузить их изначально в ACK не могу, потому что от типа команды данные могут меняться.

    Если имеется ввиду пауза между неудачными попытками, то выставлено 15 повторений через 15 мс.

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

    Передача в одну сторону без смены режима работает отлично.

    Буду пробовать через irq.
    Но сегодня закажу esp8622.
     
  3. parovoZZ

    parovoZZ Гуру

    Пробуй через прерывание. С flush_rx и flush_tx аккуратнее - если в fifo нет данных, их применять бессмысленно; а если есть - то потрешь бесследно. Я вообще этими командами не пользуюсь.
     
  4. parovoZZ

    parovoZZ Гуру

    Зачем так категорично?
     
  5. Victor_tesla

    Victor_tesla Нуб

    Добрый день.
    За ранее извиняюсь так как мой вопрос немного расходится с темой данного форума, но учитывая что, практически всю информацию о настройке модуля nRF24L01 почерпнул с этих страниц убежден в компетентности находящихся здесь людей и в том что мне смогут подсказать что делать.

    В общем появилась идея улучшить инвалидное кресло для близкого человека, а точнее установить на него электрический привод. В качестве привода использую мотор колеса от гироскутера которые были переделаны в ступицы для колес для инвалидного кресла. Колесами управляет два драйвера безколекторных двигателей на 350W. В качестве мозгов решил выбрать Arduino так как это удобно и позволяет легко повторить мою конструкцию ели кто то захочет заняться подобным проектом. Для отладки скетча собрал небольшого робота на двух колесах, колесами управляет драйвер L298n.

    В общем на Arduino выполнен модуль управления инвалидным креслом и пульт который передает данные с джойстика и кнопок, устройства связываются через nRF24L01. Связь устанавливается и оба скетча работают как часы но есть одно но.

    Проблема заключается в том что, когда на пульте нажата кнопка или джойстик отклонен в какую либо сторону и на пульте к примеру пропадает питание и пульт вырубается, на управляющем устройстве остается сигнал который не уходит пока пульт снова не включится. Простым языком если вы управляли роботом и заставляли его двигаться вперед, и если в этот момент пропадает питание на пульте робот продолжает неуправляемое движение вперед но как только снова включается пульт робот останавливается и снова слушается пульта. Как именно это можно исправить?
    Опыт работы с Arduino и программированием около двух месяцев.

    Передатчик

    Код (C++):
    /* Скетч джойстика*/

    #include <SPI.h>      // Библиотека для работы с шиной SPI
    #include <nRF24L01.h> // Библиотека радиомодуля
    #include <RF24.h>     // Подключаем библиотеку RF24-master!
    #define CE_PIN   9    // Подключаем пин D9 Ардуино UNO к выходу CE модуля NRF24L01
    #define CSN_PIN 10    // Подключаем пин D10 Ардуино UNO к выходу CSN модуля NRF24L01
    #define xAxis   14    // А1 ось X джойстика
    #define yAxis   15    // А0 ось Y джойстика
    const uint64_t pipe = 0xE8E8F0F0E1LL; //номер канала, должен быть одинаковый у передатчика и приёмника!
    RF24 radio(CE_PIN, CSN_PIN);
    int joystick[6];      // Массив, хранящий передаваемые данные

    // Обозначаем кнопки
    int buttonUp    = 2; // Кнопка А
    int buttonRight = 3; // Кнопка В
    int buttonDown  = 4; // Кнопка С
    int buttonLeft  = 5; // Кнопка D

    void setup() {
      // Обозначаем пины кнопок
      pinMode(buttonUp,INPUT_PULLUP);
      pinMode(buttonRight,INPUT_PULLUP);
      pinMode(buttonDown,INPUT_PULLUP);
      pinMode(buttonLeft,INPUT_PULLUP);

      // Обозначаем логический уровень на пинах
      digitalWrite(buttonUp,LOW);
      digitalWrite(buttonRight,LOW);
      digitalWrite(buttonDown,LOW);
      digitalWrite(buttonLeft,LOW);

      // Настройка радиоканала
      radio.begin();                     // Активировать модуль
      radio.setAutoAck(1);               // Режим подтверждения приёма, 1 вкл 0 выкл
      radio.setRetries(0, 15);           // (время между попыткой достучаться, число попыток)
      radio.enableAckPayload();          // Разрешить отсылку данных в ответ на входящий сигнал
      radio.setPayloadSize(32);          // Размер пакета, в байтах
      radio.openWritingPipe(pipe);       // Открываем канал для передачи данных
      radio.setChannel(9);               // Выбираем канал (в котором нет шумов!)
      radio.setPALevel (RF24_PA_HIGH);   // Уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
      radio.setDataRate (RF24_250KBPS);  // Скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
                                         // Должна быть одинакова на приёмнике и передатчике!
                                         // Дри самой низкой скорости имеем самую высокую чувствительность и дальность!
      radio.powerUp();                   // Начать работу
      radio.stopListening();             // Не слушаем радиоэфир, мы передатчик
    }

    void loop() {
      joystick[0] = analogRead(xAxis);   // Считываем значение оси Х джойстика и записываем в массив joystick.
      joystick[1] = analogRead(yAxis);   // Считываем значение оси Y джойстика и записываем в массив joystick.
      joystick[2] = digitalRead(buttonUp);    // Считываем значение кнопки А джойстика и записываем в массив joystick.
      joystick[3] = digitalRead(buttonRight); // Считываем значение кнопки В джойстика и записываем в массив joystick.
      joystick[4] = digitalRead(buttonDown);  // Считываем значение кнопки С джойстика и записываем в массив joystick.
      joystick[5] = digitalRead(buttonLeft);  // Считываем значение кнопки D джойстика и записываем в массив joystick.

      radio.write( joystick, sizeof(joystick) );
    }
    Приемник

    Код (C++):
    /* Скетч приемника*/

    #include <SPI.h>      // Библиотека для работы с шиной SPI
    #include <nRF24L01.h> // Библиотека радиомодуля
    #include <RF24.h>     // Подключаем библиотеку RF24-master!
    #define CE_PIN   2    // Подключаем пин D2 Ардуино UNO к выходу CE модуля NRF24L01
    #define CSN_PIN  9    // Подключаем пин D9 Ардуино UNO к выходу CSN модуля NRF24L01
    #define OUT_1   18    // Выход №1 A4
    #define OUT_2   19    // Выход №2 A5
    #define OUT_3    7    // Выход №3 D7
    #define OUT_4    8    // Выход №4 D8
    #define ENA      5    // ШИМ правого колеса
    #define ENB      6    // ШИМ левого колеса
    #define IN_1    14    // Вперед правое колесо
    #define IN_2    15    // Назад правое колесо
    #define IN_3    16    // Вперед левое колесо
    #define IN_4    17    // Назад левое колесо
    const uint64_t pipe = 0xE8E8F0F0E1LL; //номер канала, должен быть одинаковый у передатчика и приёмника!
    RF24 radio(CE_PIN, CSN_PIN);
    int joystick[6]; // Массив, хранящий передаваемые данные
    // Обозначаем переменные
    int speedRight = 0;
    int speedLeft = 0;
    int  xAxis, yAxis;
    // Обозначаем кнопки
    int buttonUp;
    int buttonRight;
    int buttonDown;
    int buttonLeft;

    void setup() {
      // Настройка радиоканала
      radio.begin();                   // Активировать модуль
      radio.setAutoAck(1);             // Режим подтверждения приёма, 1 вкл 0 выкл
      radio.setRetries(0, 15);         // (время между попыткой достучаться, число попыток)
      radio.enableAckPayload();        // Разрешить отсылку данных в ответ на входящий сигнал
      radio.setChannel(9);             // Выбираем канал (в котором нет шумов!)Должен быть одинаковым на приёмнике и передатчике!
      radio.setDataRate(RF24_250KBPS); // Установка минимальной скорости;
      radio.setPALevel(RF24_PA_HIGH);  // Установка высокую мощности;
      radio.openReadingPipe(1,pipe);   // Открываем канал для передачи данных
      radio.startListening();          // Слушаем радиоэфир, мы приёмник
      // Обозначаем выходные пины
      pinMode(OUT_1, OUTPUT);
      pinMode(OUT_2, OUTPUT);
      pinMode(OUT_3, OUTPUT);
      pinMode(OUT_4, OUTPUT);
      // Обозначаем пины выхода ШИМ левого и правого колеса
      pinMode(ENA, OUTPUT);
      pinMode(ENB, OUTPUT);
      // Обозначаем пины выхода движения вперед и назад левого и правого колеса
      pinMode(IN_1, OUTPUT);
      pinMode(IN_2, OUTPUT);
      pinMode(IN_3, OUTPUT);
      pinMode(IN_4, OUTPUT);
    }

    void loop() {
      bailout:
    if ( radio.available() )
      {
        bool done = false;
        while (!done)
          {
      done = radio.read( joystick, sizeof(joystick) );
       
          // Получаем данные джойстика из массива данных
          xAxis = joystick[0];
          yAxis = joystick[1];    
          // Получаем данные кнопок из массива данных
          int buttonUp    = joystick[2];
          int buttonRight = joystick[3];
          int buttonDown  = joystick[4];
          int buttonLeft  = joystick[5];  
          // Описание работы кнопок
          if (buttonUp == HIGH){digitalWrite(OUT_1, LOW);}
            else {digitalWrite(OUT_1, HIGH);}
          if (buttonRight == HIGH){digitalWrite(OUT_2, LOW);}
            else {digitalWrite(OUT_2, HIGH);}
          if (buttonDown == HIGH){digitalWrite(OUT_3, LOW);}
            else {digitalWrite(OUT_3, HIGH);}
          if (buttonLeft == HIGH){digitalWrite(OUT_4, LOW);}
            else {digitalWrite(OUT_4, HIGH);}
           
        // Движение по оси Y вперед
        if (yAxis < 470) {
        // Правое колесо
        digitalWrite(IN_1, LOW);
        digitalWrite(IN_2, HIGH);
        // Левое колесо
        digitalWrite(IN_3, LOW);
        digitalWrite(IN_4, HIGH);  
        // Переводим значение полученое с джойстика
        speedRight  = map(yAxis, 470, 0, 0, 255);
        speedLeft   = map(yAxis, 470, 0, 0, 255);
       }
     
        // Движение по оси Y назат
        else if (yAxis > 550) {
        // Правое колесо
        digitalWrite(IN_1, HIGH);
        digitalWrite(IN_2, LOW);
        // Левое колесо
        digitalWrite(IN_3, HIGH);
        digitalWrite(IN_4, LOW);  
        // Переводим значение полученое с джойстика
        speedRight  = map(yAxis, 550, 1023, 0, 255);
        speedLeft   = map(yAxis, 550, 1023, 0, 255);
      }  
        else {
        speedRight  = 0;
        speedLeft   = 0;
      }
     
    // Движение по оси X влево и вправо
      if (xAxis < 470) {
        // Переводим значение полученое с джойстика
        int xMapped = map(xAxis, 470, 0, 0, 255);
        // Движение налево
        speedLeft = speedLeft - xMapped;
        speedRight = speedRight + xMapped;
        // Ограничиваем значение от 0 до 255
        if (speedLeft < 0) {
          speedLeft = 0;
        }
        if (speedRight > 255) {
          speedRight = 255;
        }
      }
        if (xAxis > 550) {
        // Переводим значение полученое с джойстика
        int xMapped = map(xAxis, 550, 1023, 0, 255);
        // Движение направа
        speedLeft = speedLeft + xMapped;
        speedRight = speedRight - xMapped;
        // Ограничиваем значение от 0 до 255
        if (speedLeft > 255) {
          speedLeft = 255;
        }
        if (speedRight < 0) {
          speedRight = 0;
        }
      }
        // ШИМ, скорость левого и правого колеса
        analogWrite(ENA, speedRight);
        analogWrite(ENB, speedLeft);
        goto bailout;
          }
       }
    }
     
  6. b707

    b707 Гуру

    В приемнике добавить условие - если новых сигналов с передатчика нет более 1сек - выключать все моторы и останавливаться.
     
    Sanek.M, Victor_tesla и parovoZZ нравится это.
  7. У меня это реализовано так, код приемника под спойлером, в самом конце строчку не пропустите, она важна для изменения логической переменной
    Код (C++):
    #include <SPI.h>
    #include "nRF24L01.h"
    #include "RF24.h"
    #include <Servo.h>

    RF24 radio(7, 8); //

    int recieved_data[7]; // массив принятых данных

    byte servo_pered = 10; // сервопривод включения переднего привода
    byte servo_zad = 9;
    byte servo_rul = 6;
    int rul = 45;



    unsigned long currentTime = 0;

    byte uroven_akb = 0;   //  переменная заряда батареи

    byte gaz_lewel = 0;

    byte svet = 5;
    byte servo_pwr = A0;

    byte motion_A = 2;
    byte motion_B = 4;
    byte motion_pwm = 3;
    byte speed_coef = 0;
    boolean revers_flag = true;
    boolean stop_flag = true;
    boolean radio_on = true;

    Servo myservo_pered;
    Servo myservo_zad;
    Servo myservo_rul;

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

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

    //   TCCR0B = TCCR0B & 0b11111000 | 0x01;  // увеличивает частоту шим
    //   TCCR2B = TCCR2B & 0b11111000 | 0x01;
    //   TCCR1B = TCCR1B & 0b11111000 | 0x03;

      pinMode(svet, OUTPUT);
      pinMode(servo_pwr, OUTPUT);
      digitalWrite(servo_pwr, LOW);

      myservo_pered.attach(servo_pered);
      myservo_zad.attach(servo_zad);
      myservo_rul.attach(servo_rul);

      delay(1000);

      myservo_pered.write(78);
      myservo_zad.write(78);
      myservo_rul.write(45);

      delay(1000);

    digitalWrite(servo_pwr, HIGH);

    pinMode(motion_A, OUTPUT);
    pinMode(motion_B, OUTPUT);
    pinMode(motion_pwm, OUTPUT);


      radio.begin(); //активировать модуль
      radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
      radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
      radio.enableAckPayload();   // отключить если не работает //разрешить отсылку данных в ответ на входящий сигнал
      radio.writeAckPayload(1, &uroven_akb, 1 );
      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_250KBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS

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

    void loop() {
    byte pipeNo;       // отключить если не работает
    byte uroven_akb = 123;   //  переменная заряда батареи
    // radio.writeAckPayload(1, &uroven_akb, sizeof(uroven_akb) ); // Грузим сообщение для автоотправки;

      if ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
        currentTime = millis();
        radio_on = true;
      radio.read( &recieved_data, sizeof(recieved_data) );     // чиатем входящий сигнал
        radio.writeAckPayload(1, &uroven_akb, 1 ); // Грузим сообщение для автоотправки;  
    //    radio_on = true;
    //    currentTime = millis();
      }

     
    /////////////////////////////////////////////////////////////////////////////////////////////////////

      if (radio_on == false)
      {
       if ( (millis() - currentTime) > 500)
                {
                  if (recieved_data[1] > 0) {
                  -- recieved_data[1];
                  delay(10);
                  }
                }
      }


       if  (recieved_data[6] >= 7){  // проверяем контрольную сумму
     
        digitalWrite(svet, recieved_data[3]);  // включение фар

            rul = recieved_data[0];   // управление рулем
            myservo_rul.write(rul);

    //////////////////////////////////// торможение двигателем
    if (recieved_data[1] == 0 && stop_flag == true){
          digitalWrite(motion_A, LOW);
          digitalWrite(motion_B, LOW);
    }
    //////////////////////////////////// управление направлением движения
    else {
      stop_flag = false;
        if (recieved_data[2] == 0 && recieved_data[1] >= 5 && revers_flag == true && recieved_data[6] >= 7){
          digitalWrite(motion_A, HIGH);
          digitalWrite(motion_B, LOW);
          revers_flag = false;
          stop_flag = true;
        }
                if (recieved_data[2] == 1 && recieved_data[1] >= 5 && revers_flag == false && recieved_data[6] >= 7) {
                    digitalWrite(motion_A, LOW);
                    digitalWrite(motion_B, HIGH);
                    revers_flag = true;
                    stop_flag = true;
    //                speed_coef = 4;
                  }
    }
    //////////////////////////////////// управление раздаточной коробкой
    if (recieved_data[1] == 0){
        if (recieved_data[4] == 0){
          myservo_pered.write(78); /// on
          myservo_zad.write(78);  /// on
        }
        if (recieved_data[4] == 1){
          myservo_pered.write(78);  /// on
          myservo_zad.write(100);   /// off
        }
        if (recieved_data[4] == 2){
          myservo_pered.write(58);  /// off
          myservo_zad.write(78);   /// on
        }
        if (recieved_data[4] == 3){
          myservo_pered.write(58);   /// off
          myservo_zad.write(100);     /// off
        }
    }
     
    //////////////////////////////////////////// управление коэффициентом скорости
    if (recieved_data[5] == 0){
      speed_coef = 3;
    }
    if (recieved_data[5] == 1){
      speed_coef = 2;
    }
    if (recieved_data[5] == 2){
      speed_coef = 1;
    }

          gaz_lewel = recieved_data[1]/speed_coef;  // управление газом

         analogWrite(motion_pwm, gaz_lewel);


    //   analogWrite(motion_pwm, recieved_data[1]/speed_coef);
    //    Serial.print("0 - ");
        Serial.println(uroven_akb);
    //    Serial.println(speed_coef);
    //    Serial.print("1 - ");
    //    Serial.println(recieved_data[1]);
    ////    Serial.print("2 - ");
    //    Serial.println(recieved_data[2]);
    ////    Serial.print("3 - ");
    //    Serial.println(recieved_data[3]);
    ////    Serial.print("4 - ");
    //    Serial.println(recieved_data[4]);
    ////    Serial.print("5 - ");
    //    Serial.println(recieved_data[5]);
    ////    Serial.print("6 - ");
    //    Serial.println(recieved_data[6]);

    //    delay(60);

      }
     

    //  Serial.println(recieved_data[6]);
    //  Serial.println(recieved_data[0]);
    //  Serial.println(recieved_data[1]);
    //  delay(2000);
    //  digitalWrite(motion_pwm, LOW);

    // analogWrite(motion_pwm, 0);
    radio_on = false;
    }

     
     
  8. Oleg_7

    Oleg_7 Гик

    В чем будет разница между процессор = ATmega168. и 328 на практике?
     
  9. Oleg_7

    Oleg_7 Гик

    в плане энергосбережения.....?
     
  10. ostrov

    ostrov Гуру

    Меньше памяти же.
     
  11. parovoZZ

    parovoZZ Гуру

    в этом плане ни в чем. Это один и тот же проц.
     
  12. Подскажите , а какой емкостью можно поставить конденсатор для
    NRF24L01+PA+LNA ?
     
  13. parovoZZ

    parovoZZ Гуру

    В даташите на микросхему все описано.
     
  14. Oleg_7

    Oleg_7 Гик

  15. MickNich

    MickNich Нуб

    Ну купи пару, заодно и нам расскажещь )))
     
  16. parovoZZ

    parovoZZ Гуру

     
  17. Oleg_7

    Oleg_7 Гик

  18. Oleg_7

    Oleg_7 Гик

    Хотя nRF24LXX без "+", это настараживает....
     
  19. b707

    b707 Гуру

    наличие отдельного МК - это, конечно. классно, но уверены ли вы. что сможете писать для него программы? Если что - я просто чтобы предупредить - этот МК с ардуинами не совсместим. для него надо качать отдельный софт, покупать программатор и ... немного учиться :)
     
  20. parovoZZ

    parovoZZ Гуру

    Там 8051 стоит со всеми вытекающими.
    SDK есть на сайте производителя.
    Программатор USBasp или родной за 30 бачей.
    Тиня + классика по деньгам даже дешевле.
    Не для слабонервных, короче.

    И я ещё подозреваю, что у писькоглазых влёгкую можно купить OTP версию.
     
    Последнее редактирование: 8 авг 2018