Радиоуправление на ардуино

ESKILS

✩✩✩✩✩✩✩
23 Июн 2023
3
0
Оформи код соответствующим тэгом
Написал скетч радиоуправление на ардуино и NRF24 управление двумя моторами по танковой схеме одним джойстиком
При включении реагирует только на: джойстик вперёд машинка едет вперёд назад неработает поворачивает на право, а на лево не поворачивает.
Помогите пожалуйста!!!!

Скетч пульта
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <GyverMotor.h>
GMotor motorL(DRIVER2WIRE,2,3);
GMotor motorR(DRIVER2WIRE,4,5);
int Y = A1;
int X= A0 ;
int swit=8;
RF24 radio(9, 10);
byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"};


byte transmit_data[3];
byte latest_data[3];
boolean flag;
void setup() {
pinMode(8,INPUT_PULLUP);
motorR.setMode(AUTO);
motorL.setMode(AUTO);


Serial.begin(9600);

radio.begin();
radio.setAutoAck(1);
radio.setRetries(0, 15);
radio.enableAckPayload();
radio.setPayloadSize(32);
radio.openWritingPipe(address[0]); radio.setChannel(102);
radio.setPALevel (RF24_PA_MAX);

radio.setDataRate (RF24_250KBPS);
radio.powerUp();
radio.stopListening();
}
void loop() {
X= 255-analogRead(0)/2;
Y = 255-analogRead(1)/2;


transmit_data[0] = X;
transmit_data[1] =Y;

transmit_data[2] = digitalRead (8);




for (int i = 0; i < 3; i++) {
if (transmit_data != latest_data) {
flag = 1;
latest_data = transmit_data;
}
}
if (flag == 1) { radio.powerUp();
radio.write(&transmit_data, sizeof(transmit_data));
flag = 0;
radio.powerDown();
}
}





Скетч приёмника
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
RF24 radio(9, 10);
#include <GyverMotor.h>
GMotor motorL(DRIVER2WIRE,2,3);
GMotor motorR(DRIVER2WIRE,4, 5);
int led=8;
byte recieved_data[6];



byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"};
void setup() {
pinMode(8,OUTPUT);
motorR.setMode(AUTO);
motorL.setMode(AUTO);
Serial.begin(9600);
radio.begin();
radio.setAutoAck(1);
radio.setRetries(0, 15);
radio.enableAckPayload(); radio.setPayloadSize(32);
radio.openReadingPipe(1, address[0]);
radio.setChannel(0x60);
radio.setPALevel (RF24_PA_MAX); radio.setDataRate (RF24_250KBPS);
radio.powerUp();
radio.startListening();
}
void loop() {
byte pipeNo;
while ( radio.available(&pipeNo))
{

radio.read(&recieved_data, sizeof(recieved_data));
int R =recieved_data[0];
int L = recieved_data[1];
int pipR=R+L;
int pipL=L-R;
motorR.setSpeed(pipR);
motorL.setSpeed (pipL);

digitalWrite(8, recieved_data[2]);



}
}
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
612
146
C++:
X= 255-analogRead(0)/2;
Y = 255-analogRead(1)/2;
Допустим, при значениях analogRead от 0 до 512 всё понятно. А если значение будет больше 512, например, 600? 255-600/2=-45. Правильно? А теперь ответьте на простой вопрос: что будет на ШИМ выходе при значении -45? Тут нужно сначала проверятьположение джойстика, и если оно отрицательное, то передавать ещё команду на смену направления. Потом, так же в приемнике, если изменилось направление, то давать команду, как в описании к библиотеке
C++:
// направление вращения 
// NORM - обычное
// REVERSE - обратное
void setDirection(dir direction);
. И не плохо было бы добавить мертвую зону джойстика, иначе поймать нейтральное положение будет ооочень сложно, при малейшем движении джойстика, да и просто от наводок на А0 и А1, у моторов будет дискотека.
 
  • Лойс +1
Реакции: ESKILS и PiratFox

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
Тут нужно сначала проверять положение джойстика, и если оно отрицательное, то передавать ещё команду на смену направления.
Необязательно. Эту обработку можно делать уже в приёмнике, таким образом не будут передаваться избыточные данные по радиоканалу. Но это не принципиально. Другой вопрос, почему ТС об этом никак не позаботился.
 
Изменено:

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
98
Виновника темы нет,не беда)
при значениях analogRead от 0 до 512 всё понятно. А если значение будет больше 512, например, 600?
Не будет. Диапазон АЦП 0-1023.Там же ж деление на 2. Т.о получаем 255-(0...255)= 255...0. Не забываем что сначала идёт деление,потом вычитание.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
98
@PiratFox,тссс! Надеюсь моего позора никто не видел...😜 Уже простые числа вычитать и делить разучился. Завтра пойду в школу,обещаю))))
Дабы избегать в будущем проблем,для себя решил принять стандарт : любые параметры телеметрии в эфире имеют значения 0-1023. Все ручки передатчика и все исп.устройства приёмника калибрую под эти значения.
 
Изменено:
  • Ахах! +1
  • Лойс +1
Реакции: poty и PiratFox

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
любые параметры телеметрии в эфире имеют значения 0-1023
Ну так это только при 10-битном АЦП(210 - 1). Соответственно, при 8 битах 28 - 1 = 255, и т. п., контроллеры-то разные бывают. :) Нужно обращать на это внимание, шоб не лохануться.;)
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
98
@PiratFox,я пока только на 8 битках. А даже если значения 0...255,всё равно привожу к 0...1024. У-унификация) Мне важно чтоб любой пульт имел совместимость с любым приёмником.
И вообще постарался максимально унифицировать блочную архитектуру,дабы легко было изготовить под любой обвес кнопок,энкодеров,стиков,моторов и сервомашинок.
Касаемо темы.
Не нравятся мне эти "ардуиновские" методы кодинга,где всё мухи с котлетами вместе идут подряд.
Что это за бесполезный цикл?
C++:
for (int i = 0; i < 3; i++) {
if (transmit_data != latest_data) {
flag = 1;
latest_data = transmit_data;
}
И зачем передатчик постоянно делает вкл/выкл?
C++:
if (flag == 1) { radio.powerUp();
radio.write(&transmit_data, sizeof(transmit_data));
flag = 0;
radio.powerDown();
}
Он долго просыпается из режима powerDown. 2мс почти.
htmlimage.png
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
@te238s, ну, первый кусок кода определяет, изменились данные, или нет. Соответственно выставляется флаг. Зачем тут цикл - мне тоже непонятно.:unsure: Флаг используется во втором куске для того, чтобы лишний раз не включать передатчик и не гонять ненужную информацию по радиоканалу. Цель этого алгоритма, как и функции radio.powerDown(); - минимизировать потребление энергии. Чтобы батарейки реже менять. :) А 2 ms на пробуждение - это совсем немного. ;)
 
Изменено:

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
98
@PiratFox,если только ради экономии. Но хз на сколько экономная.Не поленился в даташит глянуть.
PowerDown 0.9мкА
StandBy-1 22мкА
StandBy-2 320мкА
Из powerdown 1.5мс потребляет 285мкА
Таким образом,если переводить в СтендБай-1,имеем 22 мкА.
Ну вместо 3 лет будет 2 года 11 месяцев и 29 дней) Но это уже так,придирки. Не судите строго.
22мкА это 15ма/ч ёмкости за месяц.
А сам МК не спит. Сколько он потребляет?) По сравнению с нрф24 он ТЭН))
Эти ж режимы сна для действительно экономных вещей,чтоб от "таблетки" годами работать.
 
Изменено:

skunss

✩✩✩✩✩✩✩
1 Авг 2023
5
0
Уважаемые коллеги! Я так понимаю вопрос еще не решен? У меня аналогичная проблема. Суть в том же - не правильно задаются значения с джойстиков. Помогите пожалуйста! https://community.alexgyver.ru/thre...dzhojstika-dlja-bota-s-makanum-kolesami.8747/

Я нашел скетч где управление идет с одного PS2 джоя. Но может более знающие люди подскажут, моих знаий тут не хватает
Пример с сайта https://www.instructables.com/Arduino-Robot-With-PS2-Controller-PlayStation-2-Jo/:
void loop(){
 
if(error == 1) //skip loop if no controller found
  return;

else { //DualShock Controller

    ps2x.read_gamepad(false, vibrate); // disable vibration of the controller  
   
    int nJoyX = ps2x.Analog(PSS_LX); // read x-joystick
    int nJoyY = ps2x.Analog(PSS_LY); // read y-joystick
   

    nJoyX = map(nJoyX, 0, 255, -1023, 1023);
    nJoyY = map(nJoyY, 0, 255, 1023, -1023);

    // OUTPUTS
    int nMotMixL; // Motor (left) mixed output
    int nMotMixR; // Motor (right) mixed output

    // CONFIG
    // - fPivYLimt  : The threshold at which the pivot action starts
    //                This threshold is measured in units on the Y-axis
    //                away from the X-axis (Y=0). A greater value will assign
    //                more of the joystick's range to pivot actions.
    //                Allowable range: (0..+127)
    float fPivYLimit = 1023.0;
       
    // TEMP VARIABLES
    float   nMotPremixL;    // Motor (left) premixed output
    float   nMotPremixR;    // Motor (right) premixed output
    int     nPivSpeed;      // Pivot Speed
    float   fPivScale;      // Balance scale between drive and pivot

    // Calculate Drive Turn output due to Joystick X input
    if (nJoyY >= 0) {
      // Forward
      nMotPremixL = (nJoyX>=0)? 1023.0 : (1023.0 + nJoyX);
      nMotPremixR = (nJoyX>=0)? (1023.0 - nJoyX) : 1023.0;
    } else {
      // Reverse
      nMotPremixL = (nJoyX>=0)? (1023.0 - nJoyX) : 1023.0;
      nMotPremixR = (nJoyX>=0)? 1023.0 : (1023.0 + nJoyX);
    }

    // Scale Drive output due to Joystick Y input (throttle)
    nMotPremixL = nMotPremixL * nJoyY/1023.0;
    nMotPremixR = nMotPremixR * nJoyY/1023.0;

    // Now calculate pivot amount
    // - Strength of pivot (nPivSpeed) based on Joystick X input
    // - Blending of pivot vs drive (fPivScale) based on Joystick Y input
    nPivSpeed = nJoyX;
    fPivScale = (abs(nJoyY)>fPivYLimit)? 0.0 : (1.0 - abs(nJoyY)/fPivYLimit);

    // Calculate final mix of Drive and Pivot
    nMotMixL = (1.0-fPivScale)[I]nMotPremixL + fPivScale[/I]( nPivSpeed);
    nMotMixR = (1.0-fPivScale)[I]nMotPremixR + fPivScale[/I](-nPivSpeed);
   
    motor_left_speed = nMotMixL;
    motor_right_speed = nMotMixR;

    if (motor_right_speed > 50) {
      digitalWrite(MOTORB_1,HIGH);
      digitalWrite(MOTORB_2,LOW);
    }
    else if (motor_right_speed < -50) {
      digitalWrite(MOTORB_1,LOW);
      digitalWrite(MOTORB_2, HIGH);
     
    }
    else {
      digitalWrite(MOTORB_1, LOW);
      digitalWrite(MOTORB_2, LOW);
    }

    if (motor_left_speed > 50) {
      digitalWrite(MOTORA_1, LOW);
      digitalWrite(MOTORA_2, HIGH);
    }
    else if (motor_left_speed < -50) {
      digitalWrite(MOTORA_1,HIGH);
      digitalWrite(MOTORA_2,LOW);
    }
    else {
      digitalWrite(MOTORA_1, LOW);
      digitalWrite(MOTORA_2, LOW);
    }
    analogWrite(ENA, abs(motor_left_speed));
    analogWrite(ENB, abs(motor_right_speed));
    if (abs(motor_left_speed > 50) || abs(motor_left_speed > 50)) {
      Serial.println("Moving!");
    }
 
   delay(50);
}  
}
 
Изменено: