Официальный сайт компании Arduino по адресу arduino.cc
Тормозит радио пульт или автор скетча ?
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Пт, 23/09/2016 - 23:55
Доброго времени суток!
Помогите понять, почему так не сразу реагирует робот на команды с пульта.
кнопка не всегда срабатывает, иногда ее состояние вообще не передается.
Серва - пока не закончит движение по одной команде - на другие не реагирует. На пульте серва уже пару раз туда-обратно сгоняла, а на машинке через раз.
Однозначно где-то лоханулся в коде, что, в прочем, закономерно. Подскажите, что поправить. Желательно, доходчиво, как для чайника. И еще вопрос: Я Правильно понимаю, что у меня прерывание по кнопке на пульте - до одного места, так как данные все равно пакетом общим передаются ?
И еще один вопрос: В моем случае прерывание на пульте до одного места, так как данные передаются общим пакетом?
Скетч Пульта
/* Пульт радиоуправляемой машинки - 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"); }
Вы теряете часть сообщений. Посмотрите на строки 189-192. Вы проверяеете, что "что-то" пришло. И всё. А кто Вам сказал, что пришла структура целиком а не кусочек от неё?
Если пришла целиком, то Вам повезло, а если нет, то Вы хватаете этот кусочек, работаете с ним, как с целым (т.е. хвост структуры используете "с прошлого раза"), потом, когда приходит оставшая часть структуры, Вы её снова держите за целую и т.д.
Вам нужно не просто проверять, что "что-то пришло", а заодно ещё и то, что длин пришедших данных равна sizeof(SEND_DATA_STRUCTURE). Если длина меньше, то не дергаться сразу исполнять, а подождать до следующего прохода, когда структруа придёт целиком и только тогда уже что-то исполнять.
Спасибо.
ЕвгенийП,
посмотрите, пожалуйста, правильно ли я понял Вашу подсказку. В программировании я нуб, а примеров с такой проверкой не нашел... поэтому в силу своего понимания. Компиллятор не ругается, но может там вообще бред?
может там вообще бред?
К сожалению, он самый.
Чтобы Вам можно было помочь, дайте мне сслку на ту самую библиотеку RH_ASK.h, которую Вы используете. А то уж сколько раз было - трахаешься, трахаешься, а после уймы убитого времени, выясняется. что у человека можифицирована быблиотека (не сто го сайта брал, что я). Давайте точно Вашу библиотеку - посмотрим.
Для пульта :
Знаете, попробуйте посмотреть что происходит с питанием в момент включения двигателей. Мы с внуком сидели с осциллографом несколько дней, вставляли фильтры питания, не помогало. Тогда просто разделили питание: моторы от одной батареи, а контроллер, приёмник и остальная логика - от другой. Как рукой сняло. Там стоит скромный, один из самых дешёвых приёмников и отлично работает - никаких нареканий.
Это правильно, потому, что нет никакой разницы, принимать сообщение от приёмника или "от телевизора" - надо просто уметь его принимать.
После этого Вы можете использовать переменную newDataArrived. Т.е. пишете if (newDataArrived ) и делаете что нужно делать, если новые данные поступили. Это понятно?
Осталось написать функцию receiveData.
Её специфика в том, что возможны разные варианты:
1. Сообщение пришло не полностью
2. Сообщение пришло полностью
3. Пришло сразу два (или полтора) сообщения (это если Вы уж очень быстро джойстиком крутите).
4. ...
Она в любом случае должна работать корректно. Вот давайте её и напишем.
Ну, вот как-то так.
Здесь есть одна неэффективность. В строке 40 мы копируем данные с места на место ("возим" по памяти). Это не самая лучшая операция. Но, здесь она не настолько долгая, т.к. структура небольшая. А сделать "по уму" - через кольцевой буффер, будет стоить с десяток-полтора строк очень аккуратного (опасного ошибками) кода. До тех пор, пока быстродействие не является МЕГАкритичным, лучше не выпендриваться и оставить как здесь.