кнопок контроллера PS3

Я работаю над креплением для слайдера камеры со степпером X (для перемещения вдоль ползунка), степпером Y (панорамирование влево вправо) и степпером Z (наклон вверх вниз). Все это управляется контроллером PS3 (библиотека PS3BT).

Я реализовал функцию, в которой все три степпера перемещаются из одной сохраненной позиции в другую, а затем обратно... это повторяется бесконечно. Он отлично работает, за исключением того, что я не могу его остановить - я думаю, это скорее проблема программирования. Вот этот код

// Экземпляр MultiStepper - где-то вверху
MultiStepper StepperControl;

void loop(){
    if(PS3.getButtonClick(START)){ // НАЧАТЬ, чтобы начать движение между двумя POS.
        Serial.print("\n Starting Movement between POS1 and POS2");    
        while(!PS3.getButtonClick(CROSS)){        
          StepperControl.moveTo(POS1); // переходим к POS1
          StepperControl.runSpeedToPosition();
          delay(200);
          StepperControl.moveTo(POS2); // переходим к POS2
          StepperControl.runSpeedToPosition();
          delay(200);
        }
      }
}

Моя проблема в том, что нажатие X (крест) на клавиатуре не выходит из цикла. Я чувствую, что происходит то, что цикл работает слишком быстро, и все команды moveTo() накладываются друг на друга. Таким образом, даже если я нажму X, слишком много команд moveTo() уже выполнено, и он просто продолжает выполнять эти «поставленные в очередь» команды.

Я также пытался поместить оператор if в цикл while, который прерывает цикл при нажатии кнопки CROSS, но безуспешно.

// Это не весь код, а только те его части, которые я считаю важными.

, 👍0

Обсуждение

вам нужно правильно определить проблему, прежде чем вы сможете прийти к решению ..... описание вашей проблемы не имеет ничего общего с библиотекой AccelStepper - moveTo() ..... удалите весь код шагового двигателя из вашего скетча ( или начните новый скетч) .... сохраните код PS3 и используйте serial.print() для отладки вашего кода ..... определите, какой код вам нужен, чтобы правильно определить, какие кнопки нажаты, @jsotola


1 ответ


1

while(!PS3.getButtonClick(CROSS)) проверяется только один раз за цикл, поэтому ваша система завершит перемещение в POS1, подождет 200 мс, завершит перемещение в POS2 и снова подождет. 200 мс, прежде чем он сможет проверить контроллер на предмет нажатия другой кнопки.

runSpeedToPosition() является "блокирующим", что означает, что НИЧЕГО больше не может произойти, пока он выполняет свою задачу.

Вместо этого вы, вероятно, захотите избежать блокировки функций и настроить конечный автомат. и используйте функцию run() в AccelStepper, которую следует вызывать как можно чаще, и она будет перемещать степпер на один шаг ближе к целевой позиции, если он еще не в целевой позиции.

Следующее переписывание не тестировалось, но общая структура должна показать вам, как вы можете изменить способ написания программы. Вы должны представить себе, что функция loop() выполняется и завершается миллион раз в секунду, и каждый раз вы проверяете состояние (то есть, на каком этапе система в данный момент включена) и действуйте соответственно. При необходимости измените состояние на новое.

В примере есть 5 состояний, соответствующих всем возможным комбинациям того, что может делать ваша программа:

  • ОСТАНОВЛЕНО: исходное состояние, степпер не имеет цели
  • RUNTO1: степпер движется к POS1, но еще не достиг его
  • WAIT1: степпер достиг POS1 и теперь ожидает указанную задержку перед переходом в следующее состояние. В этом состоянии используется процесс, показанный в BlinkWithoutDelay стандартном скетче Arduino для задержки без блокировки.
  • RUNTO2: степпер движется к POS2, но еще не достиг его
  • WAIT2: степпер достиг POS2 и теперь ожидает следующего состояния

Вы также можете увидеть ситуации, когда состояние изменяется:

  • При нажатии СТАРТ установите новую целевую позицию и введите RUNTO1 состояние

  • При нажатии кнопки CROSS останавливаются все действия шагового двигателя и выполняется переход в состояние STOPPED

  • Когда в RUNTO1 или RUNTO2 и DistanceToGo() равно нулю, перейдите в соответствующее состояние WAITn

  • Когда вы находитесь в состоянии WAITn и истекло указанное время, перейдите в соответствующее следующее состояние RUNTOn.

Пример:

#define POS1 80
#define POS2 0

const uint16_t DELAY = 200;
enum stepperstates {STOPPED, RUNTO1, WAIT1, RUNTO2, WAIT2};

[...]

void loop() {
  static uint16_t last_millis;
  static stepperstates xStepState;
  if (PS3.getButtonClick(START)){
    xStepState = RUNTO1;
    StepperControl.moveTo(POS1); // переходим к POS1
    Serial.print("\n Starting Movement between POS1 and POS2");
  }
  if (PS3.getButtonClick(CROSS)) {
    xStepState = STOPPED;
  }

  StepperControl.run();

  switch (xStepState) {
    case STOPPED:
      StepperControl.stop();
      break;
    case RUNTO1:
      if (StepperControl.distanceToGo()==0) {
        xStepState = WAIT1;
        last_millis = millis();
      }
      break;
    case WAIT1:
      if (millis() - last_millis >= DELAY) {
        xStepState = RUNTO2;
        StepperControl.moveTo(POS2);
      }
      break;
    case RUNTO2:
      if (StepperControl.distanceToGo()==0) {
        xStepState = WAIT2;
        last_millis = millis();
      }
      break;
    case WAIT2:
      if (millis() - last_millis >= DELAY) {
        xStepState = RUNTO1;
        StepperControl.moveTo(POS1);
      }
      break;
  }
}
,

Ах. Это имеет гораздо больше смысла. Таким образом, в основном с моим исходным кодом у пользователя почти не было возможности даже нажать X, потому что delay() блокировала, как и moveToPosition(). И теперь с этим кодом - run() не блокируется, и каждый раз, когда происходит run(), мы проверяем, был ли нажат X, и если да, то переходим в состояние STOP., @AlfroJang80