Arduino Nano+2 Сервы+Мотор+NRF_PA_LNA - никак что то...
- Войдите на сайт для отправки комментариев
Сб, 17/09/2022 - 02:35
Всем доброго друзья!
Делаю тут одну штуку...Самолёт в общем из потолочки :-)
И никак не могу побороть эту застарелую беду (насколько я понял, порыскав по сети). А именно:
Мне нужно чтобы работали 2 сервы, двигатель и радиомодуль NRF_PA_LNA. Всё настроил, всё работает (и передатчик тоже). Но! По отдельности :-))
Или сервы - или мотор. Хоть ты тресни. Да, почитал про особенности библиотеки Servo.h. И про таймеры: https://arduino.ru/Tutorial/Arduino_Interrupts_part2
Однако, всё равно не могу пока побороть....Любому совету буду рад. На 11-12 пине у меня висит NRF (т.к. там у нас MOSI-MISO). Остаются для экспериментов остальные пины...
Скетч приёмной части пока такой:
// 4 Channel Receiver
// PWM output on pins D2, D3, D4, D5
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
#define PIN_CE 7 // Номер пина Arduino, к которому подключен вывод CE радиомодуля
#define PIN_CSN 8 // Номер пина Arduino, к которому подключен вывод CSN радиомодуля
RF24 radio(PIN_CE, PIN_CSN); // Создаём объект radio с указанием выводов CE и CSN
//------Настройки двигателя------
int DirPin = 10;
int SpeedPin = 3;
//-------------------------------
int ch_width_1 = 0;
int ch_width_2 = 0;
int ch_width_3 = 0;
int ch_width_4 = 0;
//Servo ch1;
//Servo ch2;
Servo ch3;
Servo ch4;
struct Signal {
byte throttle;
byte pitch;
byte roll;
byte yaw;
};
Signal data;
const uint64_t pipeIn = 0xE9E8F0F0E1LL;
void ResetData()
{
// Определение начальных значений
// Среднее положение потенциометров (254/2=127)
data.throttle = 0; // Motor Stop
data.pitch = 127; // Center
data.roll = 127; // Center
data.yaw = 127; // Center
}
void setup()
{
// Serial.begin (9600);
//-----Настраиваем двигатель-----------
pinMode(DirPin, OUTPUT);
pinMode(SpeedPin, OUTPUT);
digitalWrite(DirPin, LOW);
analogWrite(SpeedPin, 0);
//-------------------------------------
//Set the pins for each PWM signal
// ch1.attach(2);
// ch2.attach(3);
ch3.attach(6);
ch4.attach(5);
radio.begin(); // Инициализация модуля NRF24L01
radio.setChannel(5); // Обмен данными будет вестись на пятом канале (2,405 ГГц)
radio.setDataRate (RF24_1MBPS); // Скорость обмена данными 1 Мбит/сек
radio.setPALevel(RF24_PA_HIGH); // Выбираем высокую мощность передатчика (-6dBm)
radio.openReadingPipe (1, pipeIn); // Открываем трубу ID передатчика
radio.startListening(); // Начинаем прослушивать открываемую трубу
}
void(* resetFunc) (void) = 0; // объявляем функцию reset
unsigned long lastRecvTime = 0;
void recvData()
{
while ( radio.available() )
{
radio.read(&data, sizeof(Signal));
lastRecvTime = millis(); // receive the data
analogWrite(SpeedPin, data.throttle);
}
}
void loop()
{
recvData();
unsigned long now = millis();
if ( now - lastRecvTime > 1000 )
{
ResetData(); // Сигнал потерян..Сброс данных
resetFunc(); //вызываем reset
}
// ch_width_1 = map(data.throttle, 0, 255, 0, 255); // pin D2 (PWM signal)
ch_width_2 = map(data.pitch, 0, 255, 1000, 2000); // pin D3 (PWM signal)
ch_width_3 = map(data.roll, 0, 255, 1000, 2000); // pin D4 (PWM signal)
ch_width_4 = map(data.yaw, 0, 255, 1000, 2000); // pin D5 (PWM signal)
//
//// Write the PWM signal
//ch1.writeMicroseconds(ch_width_1);
// ch2.writeMicroseconds(ch_width_2);
ch3.writeMicroseconds(ch_width_3);
ch4.writeMicroseconds(ch_width_4);
}
Какую застарелую беду? У каждого она своя - у кого нога не ходит, у кого в голове туман.
да ладно, как там в песенке...если в голове опилки не беда...да...да...да...
Короче, всё, как всегда:-) Токсичные старики (да я и сам не молод). Про это даже мем есть: " спросишь на зарубежном форуме - получишь ответ. Спросишь на нашем - тебе объяснят, что ты мудак" :-)))
P.S. прежде чем спрашивать - я вычитал теорию, и перепробовал массу вариантов. В том числе разделять: вешать даижок на один таймер, сервы- на другой. Ни хрена не работат..
Короче все как всегда - телепаты требуются. В отпуске они все, приходите через полгода.
у тебя там всё неправильно, как это можно комментировать, данные зачем нулишь?
вот так всегда, задаст вопрос и исчезнет...
Если ты о ResetData() - то это насколько я понимаю, при потере связи - для отключения двигателя и переключения руля и эакрылков - в среднее положение.
Буду рад, если скажешь что неправильно.
P.S. Самолёт управляется пультом - на котором 2 аналоговых джойстика. По отдельности (или сервы или движок - всё работает. Вместе - уже нет. уже чего только не пробовал...).
Система соединений примерно такая, как на картинке (только у меня проще -я взял эту за основу, но у меня только 2 сервы- для простоты управления. Плюс - у меня перед двигателем стоит драйвер L9110, а не как тут.
В коде выше 3 серва не везде вырублена -но это не суть. И отключаешь её и не отключаешь - сути не меняет. Пробовал...
попробуй убрать разрешение мотора с 10 пина на любой другой (кроме 9), может там косяк, так как он к первому таймеру (это servo.h) привязан
Хорошо, попробую завтра и отпишусь. Спасибо!
В общем, пока бесполезно...
Попробовал такое:
5,3 – двигатель; 9,10 – две сервы
5,6-двигатель; 3-одна серва
9,10 – две сервы; 5,6-двигатель
Сервы дергаются вместе с двигателем...Или какой то косяк в коде, - хотя пока что в упор не вижу. С питанием системы -всё отлично - 2 элемента 18650 последовательно. Или просто что то другое...Читал в сети, что многие сталкиваются с такой проблемой. И кто то даже рекомендовал искать асинхронную библиотеку для серв - вместо Servo.h.
Пока не знаю, что ещё сказать. Всю голову сломал над этим вопросом...По отдельности (если отключить сервы или движок ) - всё отлично. Вместе - ну никак...
Не надо искать библиотеки. Надо зарядить таймеры 1 и 2 на выдачу необходимых сигналов. Они аппаратно, без участия программы, будут держать сервы в нужных положениях. Первый канал третьего таймера можно пустить на управление мотором. Программе останется только обмен данными и редкая запись в регистры таймеров значений угла серв и скорости мотора. Таймеры зарядить на 20 мс цикл, а в регистры сравнения писать данные. Соответственно будут задействованы ноги D10 D9 - выход первого таймера и D3 - выход второго канала второго таймера. Первый канал второго таймера конфликтует по выходу со SPI, поэтому управление мотором через прерывание первого канала второго таймера можно отправить на любую ногу.
Первый канал третьего таймера можно пустить на управление мотором.
Их всего 3. Имена конечно нулевой, первый и второй, но если считать как звучит - всего три - то так и хочется говорить. Прости такую оплошность. В голове почему-то упорно гуляет первый, второй, третий.
Откуда у наны третий таймер?
В современном варианте (PB) - 4.
Первый канал третьего таймера можно пустить на управление мотором.
это истинно китайская нано, там есть )))
В общем, пока бесполезно...
Попробовал такое:
5,3 – двигатель; 9,10 – две сервы
5,6-двигатель; 3-одна серва
9,10 – две сервы; 5,6-двигатель
Сервы дергаются вместе с двигателем...Или какой то косяк в коде, - хотя пока что в упор не вижу. С питанием системы -всё отлично - 2 элемента 18650 последовательно. Или просто что то другое...Читал в сети, что многие сталкиваются с такой проблемой. И кто то даже рекомендовал искать асинхронную библиотеку для серв - вместо Servo.h.
Пока не знаю, что ещё сказать. Всю голову сломал над этим вопросом...По отдельности (если отключить сервы или движок ) - всё отлично. Вместе - ну никак...
поменяй движок на нормальный с регулем и забудь
У меня есть конечно дурацкий способ (вернее, нормальный) -но используя решение, которое в своё время у меня заработало на ESP32. В своё время я решил такую проблему. Там суть была в том, что вместо библиотеки Servo.h - я пользовал решение, позаимствованное от буржуинов. Сейчас выложу.
Вот это решение у меня заработало на esp. Там было 2 двигателя и серва (машинка детская с клешнёй спереди). И движки с ШИМом так же конфликтовали с сервой. Библиотека была та же (Servo.h) Это - вкратце решение (как запустить серву без библиотеки вообще):
#include "esp32-hal-ledc.h" // переменные для свойств широтно-импульсной модуляции (ШИМ) сервы: #define low 1638 #define high 7864 #define timer 16 void setup() { //Настраиваем ШИМ: 1 канал, 50 Гц, 16-бит ledcSetup(1, 50, timer); //1 канал ШИМ подключили к 18 пину ledcAttachPin(18, 1); } void loop() { //повернули серву в одну сторону на 180 градусов for (int i=high ; i >=low ; i=i-100) { ledcWrite(1, i); } delay (1000); //повернули серву в другую сторону на 180 градусов for (int i=low ; i < high ; i=i+100) { ledcWrite(1, i); } }ПЫ-СЫ: Дурацкость решения заключается в том, что я выкидываю на.. нану :-). Ставлю вместо неё esp32. В итоге - все счастливы, танцуют и смеются :-)
Ну это я пока так. На скорую руку. Надо попробовать предложенное выше с таймерами. Если вытяну...
вообще-то NRF24 занимает 5 пинов, 4 из них ты поменять не можешь, это 10,11,12,13 волен только пин CS определять самостоятельно
CS - это какой пин?
обычно используют CE -D9, CSN -D10, MO -D11, MI - D12, SCK-D13 servo.h на первом таймере и конфликтует с SPI так что проблемы неизбежны, а он еще шимит напрямую, можно попробовать на 0 таймер на D5 D6 и, это пожалуй единственный вариант, не?
Так можно CS поменять или нет? В посте два утверждения, противоречащих друг другу.
по идее можно, но для начала по фэншую, как прописаны, а потом уж экспериментировать, не?
Я тут вот с SPI RP2040 экспериментирую, не хочешь подключиться?
Уф, победил полностью. Но не нану :-) Сделал "мозги" на самолёт - на базе esp32. Работает отлично.
Уф, победил полностью. Но не нану :-) Сделал "мозги" на самолёт - на базе esp32. Работает отлично.
чего бы ей на таком монстре не работать, ESP тут явно лишний, я бы взял Rasberry Pi Pico, 175 рублей всех делов
Скидывай скетчи приёмника и передатчика, откомпилирую, посмотрим...пины разведу сам )))
Начало универсального скетча аппаратуры радиоуправления на ESP32 или RP2040 будет выглядеть так:
#include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Servo.h> // распиновка для SPI0 и SPI1 #if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \ defined(ARDUINO_GENERIC_RP2040) ) // замаркировать если используем наоборот #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 #elif ( defined(ESP32)) #define WIFI // Используем модуль вайфая #include "WiFi.h" // *** *** *** Для ESP32 подключаем SPI так: #define HSPI // Дисплей на HSPI, NRF24L01 на VSPI #if defined(HSPI) // для ESP32 HSPI #define TFT_CS 15 // GP13 - CS #define TFT_RST 16 // GP14 - RESET #define TFT_DC 17 // GP15 - A0 #define TFT_MISO 12 // GP12 - MISO (MISO, RX) #define TFT_MOSI 13 // GP11 - SDA (MOSI, TX) #define TFT_SCLK 14 // GP10 - SCK #else // для ESP32 VSPI #define TFT_CS 5 // GP5 - CS #define TFT_RST 20 // GP20 - RESET #define TFT_DC 21 // GP21 - A0 #define TFT_MISO 19 // GP19 - MISO (MISO, RX) #define TFT_MOSI 23 // GP23 - SDA (MOSI, TX) #define TFT_SCLK 18 // GP18 - SCK #endif // SPI definitions and macros то NRF24L01 #if defined(HSPI) // NRF24L01 на VSPI если монитор на HSPI и наоборот ;-) #define CE_pin 21 #define CS_pin 5 #define MOSI_pin 23 #define MISO_pin 19 #define SCK_pin 18 #else // HSPI #define CE_pin 17 #define CS_pin 15 #define MOSI_pin 13 #define MISO_pin 12 #define SCK_pin 14 #endif #else #error This code is intended to run on the RP2040 or ESP32 modules! #endif //#define PIN_CE 7 // Номер пина Arduino, к которому подключен вывод CE радиомодуля //#define PIN_CSN 8 // Номер пина Arduino, к которому подключен вывод CSN радиомодуля RF24 radio(CE_pin, CS_pin); // Создаём объект radio с указанием выводов CE и CSNНу ок.. Выложу коды ;-)
Вкратце система:
-пульт управления - на Arduino Nano (переставить на esp32 элементарно - просто CE перекинуть на 4 пин, а CSN-на 5-й. В общем, всё как у приёмника);
- мозги самолёта - esp32
Почему такой разнобой: потому что хотел изначально всё собрать на Arduino Nano - но нет времени с ней возиться. Поэтому: пульт заработал - ну и нормально. Самолёт заработал? Да и хрен бы с ним...:-)
В коде много мусора из закомментированных участков. Но некоторые нужны - ибо пояснения. Код протестирован и отлично работает.
Выявилась проблема только в том (но это уже не с кодом), что двигатель потребляет дюже много ампер (гораздо больше того, что может дать драйвер). В пике, пишут что аж до 20А и более может быть. Так как питаю от парочки 18650 высокотоковых (на 35А макс) - без разницы. Но - когда в первый раз запустил и "выжал газ" - натурально пошёл дым и выгорел драйвер двигателя. Сейчас буду ставить мосфет с логическим уровнем (чтобы мог открыться полностью от вольтажа пинов esp32). Так как это винт самолёта - реверс вращения мне не нужен, достаточно только вращения в одну сторону.
P.S. в настройках ШИМа забыл обновить комменты- ну да неважно. Кому надо - разберётесь;-)
В мозгах самолёта - какие либо библиотеки для управления сервами - не используются. Применяется решение, которое я выложил выше.
Пульт (Arduino Nano):
// 4 Channel Transmitter #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #define PIN_CE 7 // Номер пина Arduino, к которому подключен вывод CE радиомодуля #define PIN_CSN 8 // Номер пина Arduino, к которому подключен вывод CSN радиомодуля RF24 radio(PIN_CE, PIN_CSN); // Создаём объект radio с указанием выводов CE и CSN const uint64_t pipeOut = 0xE9E8F0F0E1LL; //IMPORTANT: The same as in the receiver 0xE9E8F0F0E1LL int temp = 0; struct Signal { byte throttle; byte pitch; byte roll; byte yaw; }; Signal data; void ResetData() { data.throttle = 127; // Motor Stop (254/2=127) data.pitch = 127; // Center data.roll = 127; // Center data.yaw = 127; // Center } void setup() { radio.begin(); // Инициализация модуля NRF24L01 radio.setChannel(5); // Обмен данными будет вестись на пятом канале (2,405 ГГц) radio.setDataRate (RF24_1MBPS); // Скорость обмена данными 1 Мбит/сек radio.setPALevel(RF24_PA_HIGH); // Выбираем высокую мощность передатчика (-6dBm) radio.openWritingPipe(pipeOut); // Открываем трубу с уникальным ID } // Joystick center and its borders int mapJoystickValues(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() { if (analogRead(A0)>0) { data.throttle = map(analogRead(A0), 509, 1023, 0, 253); } else { data.throttle = 0; } data.roll = mapJoystickValues( analogRead(A1), 12, 524, 1020, true ); // "true" or "false" for servo direction data.pitch = mapJoystickValues( analogRead(A2), 12, 524, 1020, true ); // "true" or "false" for servo direction data.yaw = mapJoystickValues( analogRead(A3), 12, 524, 1020, true ); // "true" or "false" for servo direction radio.write(&data, sizeof(Signal)); }Мозги самолёта(esp32):