Тормозит радио пульт или автор скетча ?

popUP
Offline
Зарегистрирован: 09.10.2014

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

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

кнопка не всегда срабатывает, иногда ее состояние вообще не передается.

Серва - пока не закончит движение по одной команде - на другие не реагирует. На пульте серва уже пару раз туда-обратно сгоняла, а на машинке  через раз. 

Однозначно где-то лоханулся в коде, что, в прочем, закономерно. Подскажите, что поправить. Желательно, доходчиво, как для чайника. И еще вопрос: Я Правильно понимаю, что у меня прерывание по кнопке на пульте - до одного места, так как данные все равно пакетом общим передаются ?

И еще один вопрос: В моем случае прерывание на пульте до одного места, так как данные передаются общим пакетом?

Скетч Пульта

/* Пульт радиоуправляемой машинки
 
 - Arduino NANO
  Подключены устройства
вывода
 - LCD 128x64   i2c
 - серво
ввода
 - Джойстик 2 шт
 - Кнопка

 */

/* Подключаем передатчик и библиотеку RadioHead - не пашет совместно с Adafruit_SSD1306. как и VirtualWire
 Добавим Серво без библиотек, уберем дисплей

 */



//подключаем библиотеки ////////////////////////////

#include <Wire.h> 
#include <SPI.h>  //Библиотека (Serial Peripheral Interface), или последовательный периферийный интерфейс

//#include <Servo.h> 
int servoPin_1 = 6;
float pos_1 ;
float pos_2 ;
int myAngle;                 // будет хранить угол поворота
int pulseWidth;              // длительность импульса

//#include <Adafruit_GFX.h>  //Библиотека экрана
//#include <Adafruit_SSD1306.h>  //Библиотека экрана

#include <RH_ASK.h>
#include <SPI.h>
RH_ASK driver  (2000, 12);;

////Определение Экрана
//#define OLED_RESET 4
//Adafruit_SSD1306 display(OLED_RESET);
//#define NUMFLAKES 10
//#define XPOS 0
//#define YPOS 1
//#define DELTAY 2
//#if (SSD1306_LCDHEIGHT != 64)
//#error("Height incorrect, please fix Adafruit_SSD1306.h!");
//#endif

// Пины и переменные
#define Joy_1_Pin_X    A0   // Джойстик 1 Ось Х
#define Joy_1_Pin_Y    A1   // Джойстик 1 Ось Y
#define Joy_1_Pin_Sw   7   // Джойстик 1 SW
#define Joy_2_Pin_X    A2   // Джойстик 2 Ось Х
#define Joy_2_Pin_Y    A3   // Джойстик 2 Ось Y
#define Joy_2_Pin_Sw   8   // Джойстик 2 SW
#define Sw_1_Pin       10   // Кнопка 1

int Joy_1_Val_X ;
int Joy_1_Val_Y ;
int Joy_1_Val_Sw ;
int Joy_2_Val_X ;
int Joy_2_Val_Y ;
int Joy_2_Val_Sw ;
int Sw_1_Val ;

/// Определяем передатчик
struct SEND_DATA_STRUCTURE{
  int Joy_1_Val_X ;
  int Joy_1_Val_Y ;
  int Joy_1_Val_Sw ;
  int Joy_2_Val_X ;
  int Joy_2_Val_Y ;
  int Joy_2_Val_Sw ;
  int Sw_1_Val ;
  
};

SEND_DATA_STRUCTURE mydata;
byte tx_buf[sizeof(mydata)] = {};


////******убираем к чертям DELAY****Спасибо г-н Клапауций 322 http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-...
long previousMillis = 0;        // храним время последнего действия чтением датчиков
long interval = 200;           // интервал между чтением датчиков 

void setup() {
  Serial.begin(9600); 
  Serial.println("test start!");
  // только для отладки
  if (!driver.init())
    Serial.println("init failed");

//  myservo_1.attach(servoPin_1);  // attaches the servo on pin 6
  pinMode(servoPin_1, OUTPUT);          // конфигурируем пин сервы, как выход

  pinMode (Joy_1_Pin_Sw, INPUT);
  pinMode (Joy_2_Pin_Sw, INPUT);
  digitalWrite(Joy_1_Pin_Sw, HIGH); // включаем встроенный подтягивающий резистор
  digitalWrite(Joy_2_Pin_Sw, HIGH); // включаем встроенный подтягивающий резистор

  pinMode (Sw_1_Pin, INPUT);
  digitalWrite(Sw_1_Pin, HIGH); // включаем встроенный подтягивающий резистор

  //  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3С (for the 128x64)
  //  display.display();
  //  delay(200);
  //  display.clearDisplay();
  //  display.setTextSize(1);
  //  display.setTextColor(WHITE);
  //  display.clearDisplay();


} /* --(end setup )-- */

void loop() {
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
//    READ_DATA();
    previousMillis = currentMillis; // сохраняем время последнего переключения
  }

  //  LCD_PRINT ();
 
 READ_DATA();
 
  myAngle = map (Joy_1_Val_X, 0, 1021 , 0, 180);
  servoPulse(servoPin_1, myAngle); 

  mydata.Joy_1_Val_X    = Joy_1_Val_X;
  mydata.Joy_1_Val_Y    = Joy_1_Val_Y;
  mydata.Joy_1_Val_Sw   = Joy_1_Val_Sw;
  mydata.Joy_2_Val_X    = Joy_2_Val_X;
  mydata.Joy_2_Val_Y    = Joy_2_Val_Y;
  mydata.Joy_2_Val_Sw   = Joy_2_Val_Sw;
  mydata.Sw_1_Val       = Sw_1_Val;

  memcpy(tx_buf, &mydata, sizeof(mydata) );
  byte size_mydata = sizeof(mydata);
  driver.send((uint8_t *)tx_buf, size_mydata);
  driver.waitPacketSent();

  Serial.print ("Joy_1_Val_X : ");
  Serial.print (Joy_1_Val_X);
  Serial.print (" Joy_1_Val_Y : ");
  Serial.print (Joy_1_Val_Y);
  Serial.print (" Joy_1_Val_Sw : ");
  Serial.print (Joy_1_Val_Sw);
  
  Serial.print (" Joy_2_Val_X : ");
  Serial.print (Joy_2_Val_X);
  Serial.print (" Joy_2_Val_Y : ");
  Serial.print (Joy_2_Val_Y);
   Serial.print (" Joy_2_Val_Sw : ");
  Serial.print (Joy_2_Val_Sw);
   Serial.print (" Sw_1_Val : ");
  Serial.print (Sw_1_Val);
  
 Serial.print ("\n");  
//  Serial.print ("myAngle :");
//  Serial.print (myAngle);
//  Serial.print ("pulseWidth :");
//  Serial.print (pulseWidth);

  Serial.print ("\n");

  //  delay (200);
} /* --(end main loop )-- */

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----( Declare User-written Functions )-----*/
void servoPulse(int servoPin_1, int myAngle) 
{
  pulseWidth = (myAngle * 10) + 400;  // конвертируем угол в микросекунды
  digitalWrite(servoPin_1, HIGH);       // устанавливаем серве высокий уровень
  delayMicroseconds(pulseWidth);      // ждём
  digitalWrite(servoPin_1, LOW);        // устанавливаем низкий уровень
  delay(20);                          // 
}

void READ_DATA ()
{
  Joy_1_Val_X = analogRead(Joy_1_Pin_X);      //// Джойстик 1 Ось Х
//  delay(10); //recomanen posar-ho
  Joy_1_Val_Y = analogRead(Joy_1_Pin_Y);      //// Джойстик 1 Ось Х
//  delay(10); //recomanen posar-ho
  Joy_1_Val_Sw = digitalRead (Joy_1_Pin_Sw);  //Джойстик 1 SW

  Joy_2_Val_X = analogRead(Joy_2_Pin_X);      //// Джойстик 2 Ось Х
//  delay(10); //recomanen posar-ho
  Joy_2_Val_Y = analogRead(Joy_2_Pin_Y);      //// Джойстик 2 Ось Х
//  delay(10); //recomanen posar-ho
  Joy_2_Val_Sw = digitalRead (Joy_2_Pin_Sw);  //Джойстик 2 SW

  Sw_1_Val = digitalRead (Sw_1_Pin);      //Кнопка 1

}




//void LCD_PRINT ()
//{
//  display.setCursor(0,0);
//  display.print("Joy_1_X: ");
//  display.print(Joy_1_Val_X);
//  display.setCursor(0,15);
//  display.print("Joy_1_Y: ");
//  display.print(Joy_1_Val_Y);
//  display.setCursor(80,15);
//  display.print("SW_1: ");
//  display.print(Joy_1_Val_Sw);
//
//  display.setCursor(0,30);
//  display.print("Joy_2_X: ");
//  display.print(Joy_2_Val_X);
//  display.setCursor(0,45);
//  display.print("Joy_2_Y: ");
//  display.print(Joy_2_Val_Y);
//  display.setCursor(80,45);
//  display.print("SW_2: ");
//  display.print(Joy_2_Val_Sw);
//
//  display.setCursor(0,55);
//  display.print("Swich_1: ");
//  display.print(Sw_1_Val);
//
//  display.display();
//  display.clearDisplay();
//}






 

Скетч машинки

/* ИСТОРИЯ ДОБАВЛЕНИЙ, ИЗМЕНЕНИЙ И НОВЫХ МОДУЛЕЙ
  01
  Подключаем радио приемник 433 и библиотеку RadioHead с прерыванием 2
  -RF 433 Mhz
  02
  Управляем моторами

  Ещу будут
  / - PIR     движения
  / - Photo   фоторезистор + 10 kOm
  - Ir препятствий 4 шт
  / - КТ 973 (2 шт) , резистор 2.2kOm, диод на обратный ток, на линии 12В
  / - КТ 972 (2 шт) резистор 10kOm,на линии 12В

*/

/* ОПИСАНИЕ ПОДКЛЮЧЕННЫХ УСТРОЙСТВ И МОДУЛЕЙ
  Подключены устройства
  - Arduino MEGA 2560
  - L298N motor driver
  - LCD 16x2      i2c
  - 4 x Geared motor
  - Servo

  // - RTC DS1307    i2c

  Подключены датчики и сенсоры
  - Ultrasonic
  - Джойстик 2 шт

  Ну и еще
  - Спикер с конденсатором на 10 mf

  Силовая часть
  - 4х1500mA  Li-ion - 8,4В
  - 3х1800mA  Li-ion - 12,2В
  - 2 шт Mini Red LED Panel Voltage Meter 3-Digital Adjustment Voltmeter - для двух батарей
  - Стабилизаторы напряжения на 9, 5 и 3,3в
  - несколько линеек светодиодов на 12В - Фары, днище, задний свет
  - Двухцветные светодиоды 3В на колеса
*/

//В начале было слово:

/*  --- подключаем библиотеки --- */

#include <Motor.h>              //Motor.h - Library for powering robot motors.
#include <LiquidCrystal_I2C.h>  //A library for I2C LCD displays
#include <Wire.h>
#include "Ultrasonic.h"

#include <RH_ASK.h>
#include <SPI.h>

/*  --- Назначаем PIN подключения девайсов ---  */
// ВХОДЫ

#define Sonic_1_Pin1    22   // 22->trig, 23->echo
#define Sonic_1_Pin2    23
int Rec_Pin = 11;
int Servo_1_Pin = 31;

/// Приемник радио 433 Mhz
RH_ASK driver (2000, Rec_Pin);   /// Which will initialise the driver at 2000 bps


//#define Receiver_Pin    12    // Радио Приемник
//#define PirPin        A3    // Датчик движения
//#define Ir_1_Pin      A8   // IR препятствие 1
//#define Ir_2_Pin      A8   // IR препятствие 2
//#define Ir_3_Pin      A8   // IR препятствие 3
//#define Ir_4_Pin      A8   // IR препятствие 4

// ВЫХОДЫ

#define SpkPin          8     // Спикер
//#define LazerPin      0      // определение управления лазером и подсветкой  CONTROL_PIN  8
//#define LedFrontPin   0      // Фара
//#define LedBackPin    0      // Задний свет
//#define LedBottomPin  0      // Свет на днище
//#define LedWheelPin   0      // Свет на колесах

#define Led_1_Pin        49     // Кнопка 1 - светодиод

/*   --- Объявляем что можем ---    */
Ultrasonic ultrasonic(Sonic_1_Pin1, Sonic_1_Pin2);
Motor motor;
LiquidCrystal_I2C lcd(0x27, 20, 2);  // адрес LCD

/// Приемник радио 433 Mhz
//RH_ASK driver (2000, Rec_Pin);   /// Which will initialise the driver at 2000 bps

struct SEND_DATA_STRUCTURE {       // структура данных должна быть в точности одинакова для передатчика и для приемника!
  int Joy_1_Val_X ;
  int Joy_1_Val_Y ;
  int Joy_1_Val_Sw ;
  int Joy_2_Val_X ;
  int Joy_2_Val_Y ;
  int Joy_2_Val_Sw ;
  int Sw_1_Val ;
};

SEND_DATA_STRUCTURE mydata;
byte tx_buf[sizeof(mydata)] = {
};

/*   --- И переменные ---   */

//Для  и Ultrasonic
const int STEP = 5;    //
const int SIZE = 37;   // Size of distance array =(180/STEP) +1
int dist[SIZE];

////Для Servo
int myAngle;                 // будет хранить угол поворота
int pulseWidth;              // длительность импульса

//для Motor
int rDelay;
int s = 16;              // rotation time ms/degree  (16 on carpet and 8 on wooden floor)
//int s = 32;            // rotation time ms/degree  (16 on carpet and 8 on wooden floor)

// для джойстиков
int Joy_1_Val_X = 0;//valor X
int Joy_1_Val_Y = 0;//valor Y
int Joy_1_Val_Sw = 0;//valor X
int Joy_2_Val_X = 0;//valor X
int Joy_2_Val_Y = 0;//valor Y
int Joy_2_Val_Sw = 0;//valor X
int Sw_1_Val = 0;


////******убираем DELAY************
long previousMillis = 0;        // храним время последнего действия чтением датчиков
long interval = 10;           // интервал между чтением датчиков

/////***************************************************************************************

void setup() {
  Wire.begin();
  motor.stop(motor.Motor_LR);

  Serial.begin(9600);
 if (!driver.init())
    Serial.println("init failed");

  pinMode(SpkPin, OUTPUT);
  pinMode (Led_1_Pin , OUTPUT);
  pinMode(Servo_1_Pin, OUTPUT);
  //  pinMode(LazerPin, OUTPUT);

  /*  --- Запускаем приветствие на LCD ---  */
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  P R I V E T ");
  lcd.setCursor(0, 1);
  lcd.print("  M A S T E R ");
  delay (1000);

  /*  --- выводим на LCD постоянный текст ---  */
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("X1:");
  lcd.setCursor(0, 1);
  lcd.print("Y1:");
  lcd.setCursor(8, 0);
  lcd.print("X2:");
  lcd.setCursor(8, 1);
  lcd.print("Y2:");

} /* --(end setup )-- */

/////***************************************************************************************

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis; // сохраняем время последнего переключения

// пока тут ничего нет
  
    }

  ///////Получение данных с пульта
  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);
  if (driver.recv(buf, &buflen)) // Non-blocking
  {
    memcpy(&mydata, buf, sizeof(mydata));
  }
  
  READ_DATA();                    ///* Преобразование данных, полученных с пульта*/
  
  digitalWrite(Led_1_Pin, Sw_1_Val);

    if (Joy_1_Val_X > 510 || Joy_1_Val_X < 490) {         //убираем колебания джойстика
    SERVO_1(Servo_1_Pin, myAngle);
   }
   else {Joy_1_Val_X = 500;}
      
   SERVO_1(Servo_1_Pin, myAngle);
  
  LCD_PRINT ();
  SerMon_PRINT();

  //  GoGO();

  
} /* --(end main loop )-- */

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----( Declare User-written Functions )-----*/

void READ_DATA ()                       ///* Преобразование данных, полученных с пульта*/
{
  Joy_1_Val_X    = mydata.Joy_1_Val_X  ;
  Joy_1_Val_Y    = mydata.Joy_1_Val_Y;
  Joy_1_Val_Sw   = mydata.Joy_1_Val_Sw;
  Joy_2_Val_X    = mydata.Joy_2_Val_X;
  Joy_2_Val_Y    = mydata.Joy_2_Val_Y;
  Joy_2_Val_Sw   = mydata.Joy_2_Val_Sw;
  Sw_1_Val       = mydata.Sw_1_Val;
}

void SERVO_1 (int Servo_1_Pin, int myAngle)
{
  myAngle = map (Joy_1_Val_X, 0, 1021 , 0, 180);
  pulseWidth = (myAngle * 10) + 400;     // конвертируем угол в микросекунды
  digitalWrite(Servo_1_Pin, HIGH);       // устанавливаем серве высокий уровень
  delayMicroseconds(pulseWidth);         // ждём
  digitalWrite(Servo_1_Pin, LOW);        // устанавливаем низкий уровень
  delay(10);                          //
}

void LCD_PRINT ()       ////* вывод значений на LCD  */
{
  lcd.setCursor(3, 0);
  lcd.print(Joy_1_Val_X);
  lcd.print ("  ");
  lcd.setCursor(3, 1);
  lcd.print(Joy_1_Val_Y);
  lcd.print ("  ");
  lcd.setCursor(11, 0);
  lcd.print(Joy_2_Val_X);
  lcd.print ("  ");
  lcd.setCursor(11, 1);
  lcd.print(Joy_2_Val_Y);
  lcd.print ("  ");
}

void SerMon_PRINT()         ////*вывод значений на Serial_Monitor*/
{
  Serial.print ("Joy_1_Val_X : ");
  Serial.print (Joy_1_Val_X);
  Serial.print (" Joy_1_Val_Y : ");
  Serial.print (Joy_1_Val_Y);
  Serial.print (" Joy_1_Val_Sw : ");
  Serial.print (Joy_1_Val_Sw);

  Serial.print (" Joy_2_Val_X : ");
  Serial.print (Joy_2_Val_X);
  Serial.print (" Joy_2_Val_Y : ");
  Serial.print (Joy_2_Val_Y);
  Serial.print (" Joy_2_Val_Sw : ");
  Serial.print (Joy_2_Val_Sw);
  Serial.print (" Sw_1_Val : ");
  Serial.print (Sw_1_Val);
  Serial.print ("\n");
}



 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы теряете часть сообщений. Посмотрите на строки 189-192. Вы проверяеете, что "что-то" пришло. И всё. А кто Вам сказал, что пришла структура целиком а не кусочек от неё?

Если пришла целиком, то Вам повезло, а если нет, то Вы хватаете этот кусочек, работаете с ним, как с целым (т.е. хвост структуры используете "с прошлого раза"), потом, когда приходит оставшая часть структуры, Вы её снова держите за целую и т.д.

Вам нужно не просто проверять, что "что-то пришло", а заодно ещё и то, что длин пришедших данных равна sizeof(SEND_DATA_STRUCTURE). Если длина меньше, то не дергаться сразу исполнять, а подождать до следующего прохода, когда структруа придёт целиком и только тогда уже что-то исполнять.

popUP
Offline
Зарегистрирован: 09.10.2014

Спасибо.

popUP
Offline
Зарегистрирован: 09.10.2014

ЕвгенийП,

посмотрите, пожалуйста, правильно ли я понял Вашу подсказку. В программировании я нуб, а примеров с такой проверкой не нашел... поэтому в силу своего понимания. Компиллятор не ругается, но может там вообще бред?

  ///////Получение данных с пульта

  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);

 do
 {
  if (driver.recv(buf, &buflen) ) // Non-blocking
  {
   memcpy(&mydata, buf, sizeof(mydata));
  }
  } while (sizeof(buf) == sizeof(SEND_DATA_STRUCTURE));

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

popUP пишет:

может там вообще бред?

  ///////Получение данных с пульта

  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);

 do
 {
  if (driver.recv(buf, &buflen) ) // Non-blocking
  {
   memcpy(&mydata, buf, sizeof(mydata));
  }
  } while (sizeof(buf) == sizeof(SEND_DATA_STRUCTURE));

К сожалению, он самый.

Чтобы Вам можно было помочь, дайте мне сслку на ту самую библиотеку RH_ASK.h, которую Вы используете. А то уж сколько раз было - трахаешься, трахаешься, а после уймы убитого времени, выясняется. что у человека можифицирована быблиотека (не сто го сайта брал, что я). Давайте точно Вашу библиотеку - посмотрим.

popUP
Offline
Зарегистрирован: 09.10.2014
 
Спасибо, ЕвгенийП !
Ссылка на библиотеку:
 
Мне неудобно нагружать Вас такой ерундой. Тем более, что модули, которые есть у меня - как-то ...хреново передают-принимают, особенно, когда включаются двигатели. Я однозначно буду менять устройство и принцип связи между пультом и машинкой.
Мне будет интересно и очень полезно понять про передачу пакетов по радио и пригодится и для других проектов, где я планирую применить именно эти устройства и эту библиотеку.
Но, если разбирательство этого вопроса заходит так глубоко, что Вам придется смотреть саму библиотеку,мне бы не хотелосьтратить Ваше время на данный случай, так как сейчас это просто эксперимент и не будет иметь продолжения в текущем проекте.
У меня будет еще ОЧЕНЬ много вопросов с установленными устройствами, и я заренее прошу прощения за потраченное на их разбирательство время и силы :).
На сейчас программа для пульта не менялась, а для машинки выглядит так:
/* ИСТОРИЯ ДОБАВЛЕНИЙ, ИЗМЕНЕНИЙ И НОВЫХ МОДУЛЕЙ
  01
  Подключаем радио приемник 433 и библиотеку RadioHead с прерыванием 2
  -RF 433 Mhz
  02
  Управляем моторами

  Ещу будут
  / - PIR     движения
  / - Photo   фоторезистор + 10 kOm
  - Ir препятствий 4 шт
  / - КТ 973 (2 шт) , резистор 2.2kOm, диод на обратный ток, на линии 12В
  / - КТ 972 (2 шт) резистор 10kOm,на линии 12В

*/

/* ОПИСАНИЕ ПОДКЛЮЧЕННЫХ УСТРОЙСТВ И МОДУЛЕЙ
  Подключены устройства
  - Arduino MEGA 2560
  - L298N motor driver
  - LCD 16x2      i2c
  - 4 x Geared motor
  - Servo

  // - RTC DS1307    i2c

  Подключены датчики и сенсоры
  - Ultrasonic
  - Джойстик 2 шт

  Ну и еще
  - Спикер с конденсатором на 10 mf

  Силовая часть
  - 4х1500mA  Li-ion - 8,4В
  - 3х1800mA  Li-ion - 12,2В
  - 2 шт Mini Red LED Panel Voltage Meter 3-Digital Adjustment Voltmeter - для двух батарей
  - Стабилизаторы напряжения на 9, 5 и 3,3в
  - несколько линеек светодиодов на 12В - Фары, днище, задний свет
  - Двухцветные светодиоды 3В на колеса
*/

//В начале было слово:

/*  --- подключаем библиотеки --- */

#include <Motor.h>              //Motor.h - Library for powering robot motors.
#include <LiquidCrystal_I2C.h>  //A library for I2C LCD displays
#include <Wire.h>
#include "Ultrasonic.h"

#include <RH_ASK.h>
#include <SPI.h>

/*  --- Назначаем PIN подключения девайсов ---  */
// ВХОДЫ

#define Sonic_1_Pin1    22   // 22->trig, 23->echo
#define Sonic_1_Pin2    23
int Rec_Pin = 11;
int Servo_1_Pin = 31;

/// Приемник радио 433 Mhz
RH_ASK driver (2000, Rec_Pin);   /// Which will initialise the driver at 2000 bps


//#define Receiver_Pin    12    // Радио Приемник
//#define PirPin        A3    // Датчик движения
//#define Ir_1_Pin      A8   // IR препятствие 1
//#define Ir_2_Pin      A8   // IR препятствие 2
//#define Ir_3_Pin      A8   // IR препятствие 3
//#define Ir_4_Pin      A8   // IR препятствие 4

// ВЫХОДЫ

#define SpkPin          8     // Спикер
//#define LazerPin      0      // определение управления лазером и подсветкой  CONTROL_PIN  8
//#define LedFrontPin   0      // Фара
//#define LedBackPin    0      // Задний свет
//#define LedBottomPin  0      // Свет на днище
//#define LedWheelPin   0      // Свет на колесах

#define Led_1_Pin        49     // Кнопка 1 - светодиод

/*   --- Объявляем что можем ---    */
Ultrasonic ultrasonic(Sonic_1_Pin1, Sonic_1_Pin2);
Motor motor;
LiquidCrystal_I2C lcd(0x27, 20, 2);  // адрес LCD

/// Приемник радио 433 Mhz
//RH_ASK driver (2000, Rec_Pin);   /// Which will initialise the driver at 2000 bps

struct SEND_DATA_STRUCTURE {       // структура данных должна быть в точности одинакова для передатчика и для приемника!
  int Joy_1_Val_X ;
  int Joy_1_Val_Y ;
  int Joy_1_Val_Sw ;
  int Joy_2_Val_X ;
  int Joy_2_Val_Y ;
  int Joy_2_Val_Sw ;
  int Sw_1_Val ;
};

SEND_DATA_STRUCTURE mydata;
byte tx_buf[sizeof(mydata)] = {
};

/*   --- И переменные ---   */

//Для  и Ultrasonic
const int STEP = 5;    //
const int SIZE = 37;   // Size of distance array =(180/STEP) +1
int dist[SIZE];

////Для Servo
int myAngle;                 // будет хранить угол поворота
int pulseWidth;              // длительность импульса

//для Motor
int rDelay;
int s = 16;              // rotation time ms/degree  (16 on carpet and 8 on wooden floor)
//int s = 32;            // rotation time ms/degree  (16 on carpet and 8 on wooden floor)
int LMS = 0;
int RMS = 0;
int AMS = 0;
int AMS1 = 0;

int MooveDir = 0;
int RMS1;
int LMS1;

// для джойстиков
int Joy_1_Val_X = 0;//valor X
int Joy_1_Val_Y = 0;//valor Y
int Joy_1_Val_Sw = 0;//valor X
int Joy_2_Val_X = 0;//valor X
int Joy_2_Val_Y = 0;//valor Y
int Joy_2_Val_Sw = 0;//valor X
int Sw_1_Val = 0;


////******убираем DELAY************
long previousMillis = 0;        // храним время последнего действия чтением датчиков
long interval = 2000;           // интервал между чтением датчиков

/////***************************************************************************************

void setup() {
  Wire.begin();
  motor.off(motor.Motor_LR);

  Serial.begin(9600);
  if (!driver.init())
    Serial.println("init failed");

  pinMode(SpkPin, OUTPUT);
  pinMode (Led_1_Pin , OUTPUT);
  pinMode(Servo_1_Pin, OUTPUT);
  //  pinMode(LazerPin, OUTPUT);

  /*  --- Запускаем приветствие на LCD ---  */
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  P R I V E T ");
  lcd.setCursor(0, 1);
  lcd.print("  M A S T E R ");
  delay (1000);

  /*  --- выводим на LCD постоянный текст ---  */
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("X2:");
  lcd.setCursor(0, 1);
  lcd.print("Y2:");
  //  lcd.setCursor(7, 0);
  //  lcd.print("D:");
  //  lcd.setCursor(8, 1);
  //  lcd.print("Y2:");

} /* --(end setup )-- */

/////***************************************************************************************

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval)
  {
    //Joy_1_Val_X = 500;
    // SERVO_1(Servo_1_Pin, myAngle);
    // пока тут ничего нет
    previousMillis = currentMillis; // сохраняем время последнего переключения
  }

  ///////Получение данных с пульта

  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);

  do
  {
    if (driver.recv(buf, &buflen) ) // Non-blocking
    {
      memcpy(&mydata, buf, sizeof(mydata));
    }
  } while (sizeof(buf) == sizeof(SEND_DATA_STRUCTURE));



  READ_DATA();                    ///* Преобразование данных, полученных с пульта*/

  /// ---- Свет  ----
  digitalWrite(Led_1_Pin, Sw_1_Val);

  /// ---  Серво   ---------///
  if (Joy_1_Val_X > 510 || Joy_1_Val_X < 490)      //убираем колебания джойстика
  {
    SERVO_1(Servo_1_Pin, myAngle);
  }
  else {
    Joy_1_Val_X = 500;
  }

  SERVO_1(Servo_1_Pin, myAngle);

  ////------ Motor ------
  if (Joy_2_Val_X == 0 &  Joy_2_Val_Y == 0)
  {
    motor.off(motor.Motor_LR);
  }
  else {
    GoGo ();
  }

  /// ----  Print -----------
  LCD_PRINT ();
  SerMon_PRINT();

} /* --(end main loop )-- */

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----( Declare User-written Functions )-----*/

void READ_DATA ()                       ///* Преобразование данных, полученных с пульта*/
{
  Joy_1_Val_X    = mydata.Joy_1_Val_X  ;
  Joy_1_Val_Y    = mydata.Joy_1_Val_Y;
  Joy_1_Val_Sw   = mydata.Joy_1_Val_Sw;
  Joy_2_Val_X    = mydata.Joy_2_Val_X;
  Joy_2_Val_Y    = mydata.Joy_2_Val_Y;
  Joy_2_Val_Sw   = mydata.Joy_2_Val_Sw;
  Sw_1_Val       = mydata.Sw_1_Val;
}

void GoGo()
{
  if (Joy_2_Val_X > 450 & Joy_2_Val_X <550 & Joy_2_Val_Y > 450 & Joy_2_Val_Y < 550 )
  {
    MooveDir = 0;
  }
  
    if (Joy_2_Val_X < 450 & Joy_2_Val_Y > 450 & Joy_2_Val_Y < 550  )
    {
      MooveDir = 1;
    }
    else {
      if (Joy_2_Val_X < 450 )
      {
        MooveDir = 5;
      }
    }

  if (Joy_2_Val_X > 550 & Joy_2_Val_Y > 450 & Joy_2_Val_Y < 550  )
    {
      MooveDir = 2;
    }
    else {
      if (Joy_2_Val_X > 550 )
      {
        MooveDir = 6;
      }
    }
    
  if (Joy_2_Val_X > 450 & Joy_2_Val_X < 550 & Joy_2_Val_Y < 450 )
  {
    MooveDir = 3;
  }

  if (Joy_2_Val_X > 450 & Joy_2_Val_X <550 & Joy_2_Val_Y > 550 )
  {
    MooveDir = 4;
  }
  
  switch (MooveDir)
  {
    case 0:
      motor.off(motor.Motor_LR);
      break;
    case 1:                         ///////////------------------/НЕ готово
      AMS = (1023 - Joy_2_Val_X) ;
      AMS1 = AMS;
      AMS = map (AMS, 550, 1023, 50, 100);
      motor.onFwd(motor.Motor_LR, AMS);
      break;
    case 2:                         ///////////------------------/НЕ готово
      AMS = (Joy_2_Val_X) ;
      AMS1 = AMS;
      AMS = map (AMS, 550, 1023, 50, 100);
      motor.onRev(motor.Motor_LR, AMS);
      break;

    case 3:
      motor.turnRight(100);
      break;
    case 4:
      motor.turnLeft (100);
      break;
    case 5:                         ///////////------------------/НЕ готово
      RMS = (1023 - Joy_2_Val_X) + (Joy_2_Val_Y - 525);
      RMS1 = RMS;
      RMS = map (RMS, 550, 1550, 20, 100);
      LMS = (1023 - Joy_2_Val_X) - (Joy_2_Val_Y - 525);
      LMS1 = LMS;
      LMS = map (LMS, 550, 1550, 20, 100);
      motor.onFwd(motor.Motor_L, LMS);
      motor.onFwd(motor.Motor_R, RMS);
      break;
    case 6:                         ///////////------------------/НЕ готово
      RMS = (Joy_2_Val_X) - (Joy_2_Val_Y - 525);
      RMS1 = RMS;
      RMS = map (RMS, 550, 1550, 20, 100);
      LMS = (Joy_2_Val_X) + (Joy_2_Val_Y - 525);
      LMS1 = LMS;
      LMS = map (LMS, 550, 1550, 20, 100);
      motor.onRev(motor.Motor_L, LMS);
      motor.onRev(motor.Motor_R, RMS);
      break;

    default:
      break;
  }
}


void SERVO_1 (int Servo_1_Pin, int myAngle)
{
  myAngle = map (Joy_1_Val_X, 0, 1021 , 0, 180);
  pulseWidth = (myAngle * 10) + 400;     // конвертируем угол в микросекунды
  digitalWrite(Servo_1_Pin, HIGH);       // устанавливаем серве высокий уровень
  delayMicroseconds(pulseWidth);         // ждём
  digitalWrite(Servo_1_Pin, LOW);        // устанавливаем низкий уровень
  delay(10);                          //
}

void LCD_PRINT ()       ////* вывод значений на LCD  */
{
  lcd.setCursor(3, 0);
  lcd.print(Joy_2_Val_X);
  lcd.print ("  ");
  lcd.setCursor(3, 1);
  lcd.print(Joy_2_Val_Y);
  lcd.print ("  ");

  //  lcd.setCursor(9, 0);
  //  lcd.print(MooveDir);

  lcd.setCursor(8, 0);
  lcd.print ("R: ");
  lcd.print(RMS);
  lcd.print ("  ");
  lcd.setCursor(8, 1);
  lcd.print ("L: ");
  lcd.print(LMS);
  lcd.print ("  ");
}

void SerMon_PRINT()         ////*вывод значений на Serial_Monitor*/
{
  //  Serial.print ("Joy_1_Val_X : ");
  //  Serial.print (Joy_1_Val_X);
  //  Serial.print (" Joy_1_Val_Y : ");
  //  Serial.print (Joy_1_Val_Y);
  //  Serial.print (" Joy_1_Val_Sw : ");
  //  Serial.print (Joy_1_Val_Sw);

  Serial.print (" Joy_2_Val_X : ");
  Serial.print (Joy_2_Val_X);
  Serial.print ("  ");

  Serial.print (" Joy_2_Val_Y : ");
  Serial.print (Joy_2_Val_Y);
  Serial.print ("  ");

  Serial.print (" MooveDir : ");
  Serial.print (MooveDir);

  Serial.print (" AMS_1 ");
  Serial.print (AMS1);
  Serial.print (" AMS ");
  Serial.print (AMS);

Serial.print (" RMS_1 ");
  Serial.print (RMS1);
  Serial.print (" RMS ");
  Serial.print (RMS);


  Serial.print (" LMS_1 ");
  Serial.print (LMS1);
  Serial.print (" LMS ");
  Serial.print (LMS);


  //  Serial.print (" Joy_2_Val_Sw : ");
  //  Serial.print (Joy_2_Val_Sw);
  //  Serial.print (" Sw_1_Val : ");
  //  Serial.print (Sw_1_Val);


  Serial.print ("\n");
}



Для пульта :

/* Пульт радиоуправляемой машинки
  - Arduino NANO
  Подключены устройства
  ввода
  - Джойстик 2 шт
  - Кнопка

*/

/* Убрал все лишнее
*/

//подключаем библиотеки ////////////////////////////

#include <Wire.h>
#include <SPI.h>  //Библиотека (Serial Peripheral Interface), или последовательный периферийный интерфейс
#include <RH_ASK.h>
#include <SPI.h>

RH_ASK driver  (2000, 12);

// Пины и переменные
#define Joy_1_Pin_X    A0   // Джойстик 1 Ось Х
#define Joy_1_Pin_Y    A1   // Джойстик 1 Ось Y
#define Joy_1_Pin_Sw   7   // Джойстик 1 SW
#define Joy_2_Pin_X    A2   // Джойстик 2 Ось Х
#define Joy_2_Pin_Y    A3   // Джойстик 2 Ось Y
#define Joy_2_Pin_Sw   8   // Джойстик 2 SW
#define Sw_1_Pin       10   // Кнопка 1

int Joy_1_Val_X ;
int Joy_1_Val_Y ;
int Joy_1_Val_Sw ;
int Joy_2_Val_X ;
int Joy_2_Val_Y ;
int Joy_2_Val_Sw ;
int Sw_1_Val ;

/// Определяем передатчик
struct SEND_DATA_STRUCTURE {
  int Joy_1_Val_X ;
  int Joy_1_Val_Y ;
  int Joy_1_Val_Sw ;
  int Joy_2_Val_X ;
  int Joy_2_Val_Y ;
  int Joy_2_Val_Sw ;
  int Sw_1_Val ;
};

SEND_DATA_STRUCTURE mydata;
byte tx_buf[sizeof(mydata)] = {};

////******убираем к чертям DELAY****
long previousMillis = 0;        // храним время последнего действия чтением датчиков
long interval = 200;           // интервал между чтением датчиков

void setup() {
  Serial.begin(9600);

  // только для отладки
    if (!driver.init())
      Serial.println("init failed");

  pinMode (Joy_1_Pin_Sw, INPUT);
  pinMode (Joy_2_Pin_Sw, INPUT);
  digitalWrite(Joy_1_Pin_Sw, HIGH); // включаем встроенный подтягивающий резистор
  digitalWrite(Joy_2_Pin_Sw, HIGH); // включаем встроенный подтягивающий резистор
  pinMode (Sw_1_Pin, INPUT);
  digitalWrite(Sw_1_Pin, HIGH); // включаем встроенный подтягивающий резистор

} /* --(end setup )-- */

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
/////тут пока ничего нет
    previousMillis = currentMillis; // сохраняем время последнего переключения
  }

  READ_DATA();

  mydata.Joy_1_Val_X    = Joy_1_Val_X;
  mydata.Joy_1_Val_Y    = Joy_1_Val_Y;
  mydata.Joy_1_Val_Sw   = Joy_1_Val_Sw;
  mydata.Joy_2_Val_X    = Joy_2_Val_X;
  mydata.Joy_2_Val_Y    = Joy_2_Val_Y;
  mydata.Joy_2_Val_Sw   = Joy_2_Val_Sw;
  mydata.Sw_1_Val       = Sw_1_Val;

  memcpy(tx_buf, &mydata, sizeof(mydata) );
  byte size_mydata = sizeof(mydata);
  driver.send((uint8_t *)tx_buf, size_mydata);
  driver.waitPacketSent();

//  Serial.print ("Joy_1_Val_X : ");
//  Serial.print (Joy_1_Val_X);
//  Serial.print (" Joy_1_Val_Y : ");
//  Serial.print (Joy_1_Val_Y);
//  Serial.print (" Joy_1_Val_Sw : ");
//  Serial.print (Joy_1_Val_Sw);
//
//  Serial.print (" Joy_2_Val_X : ");
//  Serial.print (Joy_2_Val_X);
//  Serial.print (" Joy_2_Val_Y : ");
//  Serial.print (Joy_2_Val_Y);
//  Serial.print (" Joy_2_Val_Sw : ");
//  Serial.print (Joy_2_Val_Sw);
//  Serial.print (" Sw_1_Val : ");
//  Serial.print (Sw_1_Val);
//
//  Serial.print ("\n");

} /* --(end main loop )-- */

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----( Declare User-written Functions )-----*/

void READ_DATA ()
{
  Joy_1_Val_X = analogRead(Joy_1_Pin_X);      //// Джойстик 1 Ось Х
//  delay(10); //recomanen posar-ho
  Joy_1_Val_Y = analogRead(Joy_1_Pin_Y);      //// Джойстик 1 Ось Х
 // delay(10); //recomanen posar-ho
  Joy_1_Val_Sw = digitalRead (Joy_1_Pin_Sw);  //Джойстик 1 SW

  Joy_2_Val_X = analogRead(Joy_2_Pin_X);      //// Джойстик 2 Ось Х
 // delay(10); //recomanen posar-ho
  Joy_2_Val_Y = analogRead(Joy_2_Pin_Y);      //// Джойстик 2 Ось Х
 // delay(10); //recomanen posar-ho
  Joy_2_Val_Sw = digitalRead (Joy_2_Pin_Sw);  //Джойстик 2 SW

  Sw_1_Val = digitalRead (Sw_1_Pin);      //Кнопка 1
}

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

popUP пишет:

хреново передают-принимают, особенно, когда включаются двигатели.
 

Знаете, попробуйте посмотреть что происходит с питанием в момент включения двигателей. Мы с внуком сидели с осциллографом несколько дней, вставляли фильтры питания, не помогало. Тогда просто разделили питание: моторы от одной батареи, а контроллер, приёмник и остальная логика - от другой. Как рукой сняло. Там стоит скромный, один из самых дешёвых приёмников и отлично работает - никаких нареканий.

popUP пишет:

Мне будет интересно и очень полезно понять про передачу пакетов по радио и пригодится и для других проектов

Это правильно, потому, что нет никакой разницы, принимать сообщение от приёмника или "от телевизора" - надо просто уметь его принимать.

Давайте в Ваш код машинки, вместо строк 195-206 вставим такую строку.
 
const boolean newDataArrived = receiveData();

После этого Вы можете использовать переменную newDataArrived. Т.е. пишете if (newDataArrived ) и делаете что нужно делать, если новые данные поступили. Это понятно?

Осталось написать функцию receiveData. 

Её специфика в том, что возможны разные варианты:

1. Сообщение пришло не полностью
2. Сообщение пришло полностью
3. Пришло сразу два (или полтора) сообщения (это если Вы уж очень быстро джойстиком крутите).
4. ...

Она в любом случае должна работать корректно. Вот давайте её и напишем.

#define	STRUCT_LEN sizeof(SEND_DATA_STRUCTURE)
bool receiveData(void) {
	// В dataHolder будут храниться и накапливаться полученные данные
	// Длина буфера dataHolder должна быть достаточной, чтобы вместить
	// все данные полученные между обработками. Думаю, никак не меньше,
	// чем STRUCT_LEN * 2.
	static byte dataHolder[STRUCT_LEN * 3];

	// Эта переменная содержит текущее количество байтов хранящихся
	// в dataHolder и ещё не обработанных
	static uint8_t bytesRead = 0;

	// Длина данных, которые мы готовы получить.
	// Равна остатку свободного места в dataHolder
	// После вызова driver.recv - здесь будет длина реально полученных данных.
	uint8_t buflen = sizeof(dataHolder) - bytesRead;

	// Вызываем driver.recv и, если что-то получено, увеличиваем bytesRead
	// Таким образом bytesRead у нас всегда содержит количество необработанных
	// байтов, хранящихся в dataHolder
	if (driver.recv(dataHolder + bytesRead, &buflen)) bytesRead += buflen;

	// Начинаем обработку
	// Заметьте, мы делаем это всегда, независимо от того, получили мы что-то или нет
	// потому, что мы могли в прошлый раз получить сразу два пакета. В этом случае,
	// один уже обработан, а второй ждёт обработки

	// Если в dataHolder полный пакет ещё не накопился, возвращаем false
	// и ничего не делаем (ждём прихода новых данных)
	if (bytesRead < STRUCT_LEN) return false;

	// Если же уже накопилось, копируем полную структруру
	// в mydata, а остаток данных оставляем в dataHolder для
	// обработки в следующий раз.
	// 1. Копируем
	memcpy(& mydata, dataHolder, STRUCT_LEN);
	// 2. Теперь у нас в dataHolder осталось на STRUCT_LEN байтов меньше. чем было
	bytesRead -= STRUCT_LEN;
	// 3. Если остались необработанные данные, переносим их в начало dataHolder
	if (bytesRead) memcpy(dataHolder, dataHolder + STRUCT_LEN, bytesRead);

	// возвращаем true - признак того, что мы скопировали данные в mydata
	return true;
}

Ну, вот как-то так.

Здесь есть одна неэффективность. В строке 40 мы копируем данные с места на место ("возим" по памяти). Это не самая лучшая операция. Но, здесь она не настолько долгая, т.к. структура небольшая. А сделать "по уму" - через кольцевой буффер, будет стоить с десяток-полтора строк очень аккуратного (опасного ошибками) кода. До тех пор, пока быстродействие не является МЕГАкритичным, лучше не выпендриваться и оставить как здесь.