ARDUINO Arduino SEGA game pad nrf24l01 для RC моделей.

Геннадий П

★★★★★★✩
14 Апр 2021
1,847
595
44
необходимость контроля целостности передачи,
NRF вроде как поддерживает аппаратно контроль целостности передаваемых данных, только не знаю поддерживается ли это ардуиновской библиотекой.
 
  • Красота! +2
Реакции: Stamp

Stamp

★✩✩✩✩✩✩
12 Янв 2021
62
34
@bort707, Байт это не структура. Это просто байт. Структурой его делает мозг программиста.
Здесь задача слишком проста, что бы заморачиваться о протоколах и прочей фигне. Если сильно хочется, можно CRC добавить.
Просто структура даёт более внятный доступ к данным.
А так решений 100500, нужно выбрать приемлемое для себя.
Просто заставлять человека делать так, как делают Ардуинщики, в лоб, это неправильно.
Нужно смотреть классику программирования и следовать ей, если не изобрёл более лучшего.
@Геннадий П, Это поддерживается на уровне железа, хочет этого библиотека или нет.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
375
94
Пока доделываю свою радиосвязь. Но я решил что лучше делать сразу универсальную базу,поэтому организовал многопоточную работу. Первый поток периодически отправляет пакеты с массивом. Второй занимается обработкой органов управления. По крайней мере мне так проще систему масштабировать потом под любое управление чем-либо. Не знаю,может усложнил сильно,зато всё прозрачно.
Приёмная часть на меге128(ну просто была в наличии). Там параллельная работа по и2с,спай и уарту тоже независимо работают для связи с другими модулями в перспективе.
Массив единый на приёмнике и передатчике. Там информация идёт в обе стороны.
По поводу периодичности отправки. Я так думаю,будет проще оценивать и просчитывать качество связи. Это важно. Одно дело детская машинка,и другое лодка,затупившая на середине озера;)
 
Изменено:

Геннадий П

★★★★★★✩
14 Апр 2021
1,847
595
44
@te238s, 20мсек - за глаза. У человека средняя реакция на визуальный раздражитель - 150-300мсек, а если еще с распознаванием типа раздражителя - и того больше. Я не понимаю людей, которые гонятся за около-нулевой задержки ввода.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,199
1,285
Москва
По моему опыту передача небольших пактов информации (6 байт ) с интервалом менее 15мс приводит к пропусками пакетов на нрф. С интервалом в 20 мс передается стабильно на любых скоростях.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
375
94
@Старик Похабыч,с чем может быть связано? С модулями ли? Может где-то в другом месте затык?
Все ли тайминги соблюдали по даташиту?
 

bort707

★★★★★★✩
21 Сен 2020
2,911
865
20мс это 50 Гц. Кто различит отдельные мерцания лампы накаливания?)))
мерцания лампы накаливания вы не видите не потому, что не можете уловить 50 Гц, а в основном потому, что нить лампы за 20мс просто не успевает погаснуть.
Это хорошо доказывает видео - мерцания светодиодов на видео есть, а мерцания лампочек - нет
 

ТехнарьКто

★★★★★✩✩
13 Янв 2020
273
435
@te238s, 20мсек - за глаза. У человека средняя реакция на визуальный раздражитель - 150-300мсек, а если еще с распознаванием типа раздражителя - и того больше. Я не понимаю людей, которые гонятся за около-нулевой задержки ввода.
150 мсек это 0,15 секунды. Если я Вас правильно понял. Это чуть менее 7 Герц. Человек различает картинку со сменой кадров вплоть до 300 герц. Но задержек в 20 мкс вполне достаточно для управления в рассматриваемом случае. А вот почему так, сильно долго объяснять и мало кому будет интересно.

PS За около нулевой задержкой гонятся военные. И там оно не надо, а критично. А в самодельном пульте оно мало критично и соответственно совсем не нужно.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
375
94
А в самодельном пульте оно мало критично и соответственно совсем не нужно.
Именно. Коряво выражаясь,пальцы так не могут быстро на кнопки нажимать:D прибавить ещё энерцию механизмов.
Пример с глазами,конечно,не совсем удачен.

Пишут что максимум у nrf24l01 около 6500 пакетов в секунду.
В принципе так и выходит. Около 150мкс без подтверждения приёма на скорости 2 Мбит/с и spi на 10МГц(что нереально на авр). Да и то,в теории. Никто не знает какие там микросхемы,Китай или Китай :D В даташите есть подробнейшие и муторные расчёты всех таймингов. Другое дело что нам для "бытовухи" это излишне.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,199
1,285
Москва
Около 150мкс без подтверждения приёма на скорости 2 Мбит/с
Да, я тоже печатаю 1534 знака в минуту, но такая хня выхордит! (с)
Я отслеживал пакеты именно с подтверждением, по нему и смотрел задержки. Вот скорость передачи не помню, но скорее всего пробовал на разных.
 

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
Тут жеж получается что нажатие одной кнопки блокирует другие,ниже расположеные в коде.
Ну да, так и получается, пока одна зажата вторую не нажмёшь:)
Но это первый скетч, я не уверен был, что он вообще заработает.
Я за скоростью не гонюсь проста ардуинка тоже должна обработать сам джойстик сеги а уже патом передавать сигнал и всё такое.
 

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
Вот что у меня получилось,
но есть нюансы.
C++:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
RF24 radio(9, 10);
#define UP_OR_Z 2
#define DOWN_OR_Y 3
#define LEFT_OR_X 4
#define RIGHT_OR_MODE 5
#define B_OR_A 6
#define SEL 7
#define C_OR_START 8
bool sega_up = false;
bool sega_down = false;
bool sega_left = false;
bool sega_right = false;
bool sega_start = false;
bool sega_mode = false;
bool sega_a = false;
bool sega_b = false;
bool sega_c = false;
bool sega_x = false;
bool sega_y = false;
bool sega_z = false;
byte up, down, left, right, start, mode, a, b, c, x, y, z;
byte batton_transmit[12];
void segaRead() {
  digitalWrite(SEL, HIGH);
  sega_up = (digitalRead(UP_OR_Z) == LOW);
  sega_left = (digitalRead(LEFT_OR_X) == LOW);
  sega_right = (digitalRead(RIGHT_OR_MODE) == LOW);
  sega_down = (digitalRead(DOWN_OR_Y) == LOW);
  sega_c = (digitalRead(C_OR_START) == LOW);
  sega_b = (digitalRead(B_OR_A) == LOW);
  digitalWrite(SEL, LOW);
  sega_a = (digitalRead(B_OR_A) == LOW);
  sega_start = (digitalRead(C_OR_START) == LOW);
  digitalWrite(SEL, HIGH);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
  sega_x = (digitalRead(LEFT_OR_X) == LOW);
  sega_y = (digitalRead(DOWN_OR_Y) == LOW);
  sega_z = (digitalRead(UP_OR_Z) == LOW);
  sega_mode = (digitalRead(RIGHT_OR_MODE) == LOW);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
}
void batton_byte () {
  up = sega_up;
  left = sega_left;
  right = sega_right;
  down = sega_down;
  start = sega_start;
  mode = sega_mode;
  a = sega_a;
  b = sega_b;
  c = sega_c;
  x = sega_x;
  y = sega_y;
  z = sega_z;
}
void setup() {
  radio.begin();
  radio.setChannel(0x70);
  radio.setPALevel (RF24_PA_MAX);
  radio.setDataRate (RF24_1MBPS);
  radio.openWritingPipe(0x0123456789LL);
  radio.powerUp();
  radio.stopListening();
  pinMode(SEL, OUTPUT);
  pinMode(UP_OR_Z, INPUT);
  pinMode(DOWN_OR_Y, INPUT);
  pinMode(LEFT_OR_X, INPUT);
  pinMode(RIGHT_OR_MODE, INPUT);
  pinMode(B_OR_A, INPUT);
  pinMode(C_OR_START, INPUT);
}
void loop() {
  segaRead();
  batton_byte();
  {
    batton_transmit[0] = up;
    batton_transmit[1] = left;
    batton_transmit[2] = right;
    batton_transmit[3] = down;
    batton_transmit[4] = start;
    batton_transmit[5] = mode;
    batton_transmit[6] = a;
    batton_transmit[7] = b;
    batton_transmit[8] = c;
    batton_transmit[9] = x;
    batton_transmit[10] = y;
    batton_transmit[11] = z;
    radio.write(&batton_transmit, sizeof(batton_transmit));
    delay(20);
  }
}
 
Изменено:

Геннадий П

★★★★★★✩
14 Апр 2021
1,847
595
44
radio.setPALevel (RF24_PA_MAX);
Ну зачем? Зачем долбить максимальной мощностью для устройства которое по сути находится на паре метров дистанции? Минимальной мощности для домашних устройств - за глаза, да и потребление гораздо меньше будет.
 

Stamp

★✩✩✩✩✩✩
12 Янв 2021
62
34
@te238s, Что то здесь есть.
Я уже писал прошивку поиска, но, похоже, потерял.
 

Вложения

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
Ну зачем? Зачем долбить максимальной мощностью для устройства которое по сути находится на паре метров дистанции? Минимальной мощности для домашних устройств - за глаза, да и потребление гораздо меньше будет.
Ну я не совсем для домашнего устройства делаю. Машинка RC и на улице может эксплуатироваться.
Так да можно и уменьшить. Я в самом начале специально по максимуму сделал, что бы на дальность работы и на ошибки проверить.
Получилось приёмник (маленький со встроенной антенной) дома на втором этаже хрущёвки, а я от дома метров на 30м - 35м отдалился пока сигнал совсем не пропал.
Ну это как говорится, нюансы можно к нормальному виду всё привести, главное с основным разобраться.;)
 

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
О,уже более унивесальный алгоритм. А что за нюансы?
Пользуясь случаем,хочу замутить ещё алгоритм автоматического поиска наилучшего канала.
Попробовал ещё дописать режим энергоэкономии, как у Гайвера в "заметках ардуинщика".
Стали ошибки вылизать, ложные срабатывания кнопок.
Скеч в приёмной части нужно переписать, что бы полноценно протестировать геймпад на срабатывание кнопок.
 

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
C++:
void segaRead() {
  digitalWrite(SEL, HIGH);
  sega_up = (digitalRead(UP_OR_Z) == LOW);
  sega_left = (digitalRead(LEFT_OR_X) == LOW);
  sega_right = (digitalRead(RIGHT_OR_MODE) == LOW);
  sega_down = (digitalRead(DOWN_OR_Y) == LOW);
  sega_c = (digitalRead(C_OR_START) == LOW);
  sega_b = (digitalRead(B_OR_A) == LOW);
  digitalWrite(SEL, LOW);
  sega_a = (digitalRead(B_OR_A) == LOW);
  sega_start = (digitalRead(C_OR_START) == LOW);
  digitalWrite(SEL, HIGH);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
  sega_x = (digitalRead(LEFT_OR_X) == LOW);
  sega_y = (digitalRead(DOWN_OR_Y) == LOW);
  sega_z = (digitalRead(UP_OR_Z) == LOW);
  sega_mode = (digitalRead(RIGHT_OR_MODE) == LOW);
  digitalWrite(SEL, LOW);
  digitalWrite(SEL, HIGH);
}
Ещё в этом куске SEL должен шарашить с определённой периодичностью LOW/HIGH.
Вроди там с задержкой опрос кнопок должен происходить в 15 - 20мсек, я этим пренебрёг.
Может из за этого проблемы выплывают, а может и нет:cool:.
Ещё я геймпад собрал всё утрамбовал во внутрь, а как к нему подключаться для прошивки не подумал.
Кароче нужно допилить геймпад , что бы из обычного юзерского превратиля в Developer Kit SEGA gamepad:LOL:.
 

Nick

✩✩✩✩✩✩✩
1 Авг 2018
35
5
Тестовый скетч для проверки геймпада.
Выводит данные геймпада в монитор порта приёмника.
Arduino SEGA game pad nrf24l01.
C++:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
RF24 radio(9, 10);
uint8_t pipe;
bool up, down, left, right, start, mode, a, b, c, x, y, z;
byte batton_transmit[12];
int total_battons;
void batton_bool () {
  up = batton_transmit[0];
  left = batton_transmit[1];
  right = batton_transmit[2];
  down = batton_transmit[3];
  start = batton_transmit[4];
  mode = batton_transmit[5];
  a = batton_transmit[6];
  b = batton_transmit[7];
  c = batton_transmit[8];
  x = batton_transmit[9];
  y = batton_transmit[10];
  z = batton_transmit[11];
}
void setup() {
  Serial.begin(57600);
  radio.begin();
  radio.setChannel(0x70);
  radio.setDataRate(RF24_1MBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.openReadingPipe(1, 0x0123456789LL);
  radio.startListening();
}
void loop() {
  batton_bool ();
  if (radio.available(&pipe)) {
    radio.read(&batton_transmit, sizeof(batton_transmit));
  }
  Serial.println ("TEST battons");
  Serial.println ("SEGA game PAD");
  Serial.println ("NRF 24L01 2.4Ghz");
  for (int i; i < 12; i++) {
    batton_transmit[i];
    Serial.print(batton_transmit[i]);
  }
  Serial.println (" ");
  if (up == 1) {
    Serial.println ("UP");
  } else if (left == 1)
  { Serial.println("LEFT");
  } else if (right == 1)
  { Serial.println("RIGHT");
  } else if (down == 1)
  { Serial.println("DOWN");
  } else if (start == 1)
  { Serial.println("START");
  } else if (mode == 1)
  { Serial.println("MODE");
  } else if (a == 1)
  { Serial.println("A");
  } else if (b == 1)
  { Serial.println("B");
  } else if (c == 1)
  { Serial.println("C");
  } else if (x == 1)
  { Serial.println("X");
  } else if (y == 1)
  { Serial.println("Y");
  } else if (z == 1)
    Serial.println("Z");
  delay(150);
  Serial.println("Total buttons game pad");
  total_battons = up + down + left + right + start + mode + a + b + c + x + y + z;
  Serial.println(total_battons);
}
 
Изменено: