Как сгладить срабатывание кода?

Ferrit
Offline
Зарегистрирован: 26.02.2022
Я сделал управление ходьбой в играх реальными шагами с помощью датчиков на ногах. Закрепил датчики ускорения на каждую ногу на голени.
Датчики имеют 3 оси. Датчики подключены параллельно к одним и тем же пинам. Оси X расположены по ходу движения вперед- назад.
Оси Y обращены вниз, а Z влево- вправо.
Код работает, но ходьба получается рывками, с микропаузами, в момент постановки одной ноги и начала движения другой.
Подскажите, как убрать эти паузы, чтобы персонаж в игре шел так же, как и при постоянно нажатой клавише
#include <SoftwareSerial.h>. 
#include <Keyboard.h>
int x = 0; //ось x датчика расположена по направлению движения вперед
int y = 0; //ось y датчика расположена по направлению вниз
int z = 0; // ось z  датчика расположена по направлению движения вбок
unsigned long millisstep = 0;

void setup() {
  pinMode(chek, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() { 
//чтение показаний ускорений со всех осей датчика ускорения
  if (millis() - millisstep > 100) {
    x = analogRead(A0);
    z = analogRead(A2);
  }
  y = analogRead(A1); 
 

  // нажатие кнопки W при движении вперед. 
  if (x < 330 && y > 410) { //ускорение на оси x свидетельствует о начале движения вперед
    Keyboard.press('w');  //ускорение на оси y обращенной вниз говорит о наличии центробежной
    millisstep = millis();  //силы, значит нога движется
  }
  else if (y < 410) {
    Keyboard.release('w');
  }

  // нажатие кнопки S при движении назад
  if (x >340 && y > 410) {
    Keyboard.press('s');
    millisstep = millis();
  }
  else if (y < 410) {
    Keyboard.release('s');
  }

  //нажатие кнопки A при движении влево
  if (z > 340 && y >410) {
    Keyboard.press('a');
    millisstep = millis();
  }
  else if (y < 410) {
    Keyboard.release('a');
  }

  //нажатие D при движ вправо
  if (z < 330 && y > 410) {
    Keyboard.press('d');
    millisstep = millis();
  }
  else if (y < 410) {
    Keyboard.release('d');
  }

}

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

И где в этом коде "ходьба"?

Ferrit
Offline
Зарегистрирован: 26.02.2022

Ходьба в играх работает на кнопки WSDA. Датчики на ногах, в зависимости от напраления реальной ходьбы в игре нажимается клавиша, соответствующая направлению.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Напишите алгоритм того, что Вы хотите сделать по-русски.

Ferrit
Offline
Зарегистрирован: 26.02.2022

Я уже не знаю как еще можно объяснить.

Вы знаете что такое датчики ускорения? Вот они на ногах. Если по оси Х ускорение меньше 330, значит нога по этой оси начала движение вперед. Но так как сила на датчике возникает только в самом начале движения, то этого мало, мне нужно считывать все движение ноги, чтобы кнопка движения в игре нажималась все время шага. Для этого еще в условии ставлю ось У. Она направлена вниз. Так как голень ноги движется по дуге, то по оси У во время всего движения ноги возникает сила центробежного ускорения > 410. Когда срабатывают эти два условия, можно понять, что происходит шаг вперед. Значит в игре надо нажать кнопку вперед W.

Со всеми другими направлениями аналогично.

Проблема в том, что во время шага возникают моменты, когда обе ноги на мгновение стоят на земле, на это мгновение кнопка W отпускается и в игре получается нажал- отпустил, вместо нажал. Анимация ходьбы персонажа в игре становится дерганная, она не успевает проиграться, как кнопка уже отпускается.

Если включить не игру, а текстовый документ, то wwwwwww будет нажиматься постоянно без рывков, потому что там есть инерция, этого мгновения текстовый редактор не замечает. А игры быстро реагируют на нажатие и отпускание и с ними такое не проходит

 

 

rkit
Offline
Зарегистрирован: 23.11.2016

Ferrit пишет:

Вы знаете что такое датчики ускорения?

Нет, не знаю.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Замерь время когда кнопка отпускается и не отпускай кнопку на это время + ещё чуть-чуть когда обе ноги на земле. Получится искусственная инерция.

Ferrit
Offline
Зарегистрирован: 26.02.2022

Просто использовать delay ? Не получается, время это каждый раз будет немного отличаться, а значит будет пропущен момент начала шага, мгновение, когда нога только начинает движение и возникает сила на оси Х, по которой понимается направление вперед. Дальше движение ноги равноускоренное и силы почти никакой нет на датчике

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ferrit, скажите, что происходит в Вашей игре при нажатии/отпускании клавиши? Один шаг или несколько шагов, пока не отпустишь клавишу?

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

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

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

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

Ferrit
Offline
Зарегистрирован: 26.02.2022

В играх нет как такового шага, там просто перемещение персонажа и проигрывание анимации ходьбы.

Речь идет не о моей игре, а обо всех играх шутерах.

Там нет такого, что на нажал- отпустил будет сделан шаг, если быстро нажать и отпустить, то в игре персонаж просто немного дернется вперед на треть шага, если смотреть по расстоянию.

На счет непрерывного сигнала. Каждый шаг заканчивается остановкой передней ноги, и обгоном задней ноги переднюю. В этот момент, во время резкой остановки передней ноги, на ее датчике возникает ускорение при торможении в обратную сторону на оси Х, а на У тоже ускорение вниз при ударе о землю.

И код воспринимает этот момент как начало движения назад. Потому что движение назад включается именно по такому алгоритму. Поэтому на мгновение команда "движение вперед" прерывается на движение назад и возникает микро пауза. Как можно сделать непрерывный сигнал движения вперед, если проверку на движение назад мне нужно так же делать каждый шаг.

 

 

vrd
Offline
Зарегистрирован: 20.01.2022

Вам нужно сделать саморегулирующийся таймер.

Ввести 3 переменные

булеан dvijenie

2 инт на вперёд и на вбок

Убрать иф в 20-й строке.

vrd
Offline
Зарегистрирован: 20.01.2022
#include <SoftwareSerial.h>. 
#include <Keyboard.h>
int x = 0; //ось x датчика расположена по направлению движения вперед
int y = 0; //ось y датчика расположена по направлению вниз
int z = 0; // ось z  датчика расположена по направлению движения вбок
unsigned long millisstep = 0;
boolean dvijenie = false;
int vpered = 0;
int vbok = 0;
void setup() {
  pinMode(chek, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() { 
//чтение показаний ускорений со всех осей датчика ускорения

   x = analogRead(A0);
   z = analogRead(A2);
   y = analogRead(A1); 
 

Дальше надо делать таймер. Внутри ифа. По каждой оси.

Ferrit
Offline
Зарегистрирован: 26.02.2022

millis() . Этот таймер отсчитывает время с начала каждого цикла. А как сделать, чтобы таймер начинал считать с момента срабатывания датчика?

Как это преобразовать в код с использованием millis() или может какого- то другого таймера?

======================================================

Если х < 330 и у > 410 на время больше, чем 100 мс, то движение вперед 

======================================================

Когда нога ставится на землю, на ней возникает обратное ускорение торможения на Х и ускорение от удара на У. В это мгновение код "думает, что это движение назад" От движения назад это отличает только то, что на оси У ускорение очень короткое от удара, а при движении назад на У ускорение от центробежной силы длится в течение всего движения ноги.

Эти микро паузы, думаю, возникают как раз по этой причине, что код "не отличает" просто постановку ноги и начало шага назад.

Ferrit
Offline
Зарегистрирован: 26.02.2022

У меня были переменные вначале на каждую сторону. И все работало так же. Я просто их удалил, раз они ни на что не влияли.

Я почти уверен, что нужно исправить вот это, но не знаю как выразить это в коде.

Если знаете, напишите, пожалуйста, вот эту строчку

Если х < 330 и у > 410 на время больше, чем 100 мс, то движение вперед

vrd
Offline
Зарегистрирован: 20.01.2022
// нажатие кнопки W при движении вперед.
if (x < 330 && y > 410) { //ускорение на оси x свидетельствует о начале движения вперед
  if (dvijenie == false) {
    dvijenie = true;
    millisstep = millis();
  }
  vpered = millis() - millisstep;
  Keyboard.press('w');  //ускорение на оси y обращенной вниз говорит о наличии центробежной
}

else if (y < 410) {
  dvijenie == false;
  if (millis() - millisstep >= vpered) {
    vpered = 0;
    Keyboard.release('w');
  }
}

Попробуйте так.

vrd
Offline
Зарегистрирован: 20.01.2022

В 12-м сообщении убрать <code class="plain"> и </code>

Keyboard.press('*');

Вставлять в каждом цикле после объявления "true". Тогда будет блок остальных движений до остановки.

Ferrit
Offline
Зарегистрирован: 26.02.2022

А можно код написать, я не понял вообще здесь)

Код из предыдущего сообщения я сейчас пробую, пока непонятное движение рывками

vrd
Offline
Зарегистрирован: 20.01.2022
#include <SoftwareSerial.h>.
#include <Keyboard.h>
int x = 0; //ось x датчика расположена по направлению движения вперед
int y = 0; //ось y датчика расположена по направлению вниз
int z = 0; // ось z  датчика расположена по направлению движения вбок
unsigned long millisstep = 0;
boolean dvijenie = false;
int vpered = 0;
int vbok = 0;
void setup() {
  pinMode(chek, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  //чтение показаний ускорений со всех осей датчика ускорения

  x = analogRead(A0);
  z = analogRead(A2);
  y = analogRead(A1);

  // нажатие кнопки W при движении вперед.
  if (x < 330 && y > 410) { //ускорение на оси x свидетельствует о начале движения вперед
    if (dvijenie == false) {
      dvijenie = true;
      Keyboard.press('w');
      millisstep = millis();
    }
    vpered = millis() - millisstep;
  }

  else if (y < 410) {
    if (dvijenie == true) {
      millisstep = millis();
    }
    dvijenie = false;
    if (millis() - millisstep >= vpered) {
      vpered = 0;
      Keyboard.release('w');
    }
  }

Совместил. Рывки убрал.