Управлять 2 сервоприводами с последовательным считыванием

Я хочу использовать 2-й сервопривод только тогда, когда 1-й находится в рабочем состоянии, спрашивая пользователя, хочет ли он запустить или нет. (код, выделенный жирным шрифтом, не работает)

#include <Servo.h>

    Servo myservo;
    Servo trigervo;
    int pos = 0;
    int u = 0, p = 0, t = 0;
    int incomingByte = 0; // для входящих последовательных данных

    void setup() {
      Serial.begin(9600);
      myservo.attach(9);
      trigervo.attach(10);
      pinMode(13, OUTPUT);
      myservo.write(0);
    }

    void loop() {
      if (Serial.available() > 0) {
        // считывает входящий байт:
        incomingByte = Serial.read();
        Serial.print("I received: ");
        if (incomingByte == 111 && u == 0) {
          for (pos = 0; pos <= 80; pos += 1) {
            myservo.write(pos);
            delay(5); // 
            digitalWrite(13, HIGH);
          }
          u = 1;
          p = 0;
          Serial.println(incomingByte, DEC);
          Serial.print("Want to Shoot? \n");
          Serial.print("1\n");
          ***t = Serial.read(); // отсюда 
          if (t == 107) {
            Serial.print("2\n");
            trigervo.write(60);
            trigervo.write(0);
          } // здесь, это не работает***
        } else if (incomingByte == 102 && p == 0) {

          for (pos = 100; pos >= 0; pos -= 1) {
            myservo.write(pos);
            delay(7);
            digitalWrite(13, HIGH);
          }
          u = 0;
          p = 1;
          Serial.println(incomingByte, DEC);
        }
        Serial.println(incomingByte, DEC);

      }
    }

, 👍2

Обсуждение

read() не ждет. он возвращает -1, если в буфере RX ничего нет, @Juraj

вы забыли задать вопрос ... вы также забыли описать, что происходит при запуске программы, @jsotola


1 ответ


Лучший ответ:

1

Не зная, что именно вы хотите, чтобы это делало (поскольку вы нам не сказали), я вижу в вашем коде 2 проблемы:

  1. Код вокруг строки, отмеченной "отсюда", запросит пользователя по Serial, хочет ли он снимать, но сразу после этого он будет считывать значение, не дожидаясь, пока пользователь что-то введет. Serial.read() не будет ждать поступления данных, он просто вернет -1, если в буфере ничего нет. Вы должны проверить, действительно ли что-то есть в буфере с помощью Serial.available(), и продолжить, только если на самом деле есть данные для чтения.

  2. В следующем if-операторе вы сначала записываете значение 60 в сервопривод, а непосредственно после него, без какой-либо задержки, значение 0. У сервопривода недостаточно времени, чтобы добраться до 60 - или даже начать движение, - прежде чем вы скажете ему перейти на 0. Сервоприводу нужно время для перемещений.


Помимо конкретных проблем с вашим кодом, я бы использовал для его реализации конечный автомат (FSM). Вы объявляете глобальную переменную состояния, которая представляет возможные состояния, в которых может находиться ваша машина. Если я предполагаю какой-то тип оружия / стреляющего устройства, этими состояниями могут быть ASK_USER_TO_POSITION_GUN' и 'ASK_USER_TO_SHOOT'. В каждом состоянии вы проверяете последовательный интерфейс (сначала с помощью Serial.available(), затем считываете спомощью Serial.read()`, если он возвращает что-то большее 0), и на основе этого ввода вы сначала выполняете соответствующее действие, а затем выполняете переход состояния, изменяя переменную состояния.

В качестве примера общей структуры:

int state = 0;

void loop(){
    switch(state){
        case 0:
            if(Serial.available()>0){
                int input = Serial.read();
                //принять надлежащие меры
                state = 1; //выполнить переход состояния
            }
            break;
        case 1:
            if(Serial.available()>0){
                int input = Serial.read();
                //принять надлежащие меры
                state = 0; //выполнить переход состояния
            }
            break;
    }
}

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

РЕДАКТИРОВАТЬ: Чтобы дать лучшее объяснение о конечных автоматах, я нарисовал графическое представление состояний. В основном это намного проще кодировать, когда вы впервые нарисовали такой график, чтобы визуализировать функциональность кодов. Обратите внимание, что это логика из вашего кода. Возможно, вы захотите, чтобы это работало по-другому, но это выходит за рамки и только для понимания. Также обратите внимание на другое количество состояний, чем я использовал выше, которое я меняю только потому, что мне нужно было больше состояний.

Посмотрите сначала на этот график:

Мы начинаем с состояния 0, где мы ожидаем ввода данных пользователем через serial. Если мы вводим какой-то ввод, мы принимаем решение: если значение равно 111, мы перейдем в следующее состояние (состояние 1), чтобы установить пистолет, в противном случае мы снова будем ждать дополнительных входных данных. На этапе 1 мы устанавливаем пистолет и переходим непосредственно к состоянию 2. Там мы снова ждем ввода данных пользователем. Если мы что-то получили, мы снова примем решение: при значении 107 мы осуществим переход в состояние 3 для съемки, иначе мы перейдем в состояние 0, чтобы снова запросить позиционирование, как мы делали раньше. В состоянии 3 мы снимаем и сразу снова переходим в состояние 0. Это довольно строгое деление на государства.

Поскольку в состояниях 1 и 3 мы выполняем только короткое действие, а затем переходим непосредственно в другое состояние, мы могли бы отключить эти состояния, реализуя соответствующий код при переходе из состояния 0 в состояние 2 и наоборот. Это логика из моего примера кода FSM выше (действие вместе с переходом). График будет выглядеть следующим образом:

Какую версию вы должны реализовать, зависит от других факторов. Если вас устраивает код действия для блокировки, вы можете реализовать версию 2, поскольку в ней меньше состояний. Если вы хотите написать действие в неблокирующем стиле, возможно, вам будет проще реализовать версию 1.

,

Как вы и просили, я изменил вопрос, чтобы быть точным, пожалуйста, помогите мне......, @Aditya Raj

Ответ остается прежним. Ваши прямые проблемы - это две указанные выше проблемы. Помогает ли это? Если нет: Что мешает вам реализовать это? Может быть, я смог бы написать ответ более понятным, если бы знал, что в нем непонятно., @chrisl

В случае 0 я хочу снова получить значение с помощью последовательного чтения и реализовать его, вызвав функцию, в данном случае вызывающую триггерную функцию., @Aditya Raj

Я отклонил вашу правку, потому что FSM работает не так. В штатах вы ожидаете ввода данных пользователем. Вместо того, чтобы напрямую (все еще в случае 0) пытаться прочитать больше данных, вы совершаете переход в следующее состояние, где вы ожидаете новых данных. Это делает код лучше структурированным, а также ожидание ввода пользователем не будет блокировать выполнение кода, в случае, если вы хотите сделать что-то одновременно (например, мигание светодиода или другие задачи). Я добавлю графическое представление FSM для вашего случая, чтобы оно было более понятным., @chrisl

Хорошо, теперь я получаю представление об этом, @Aditya Raj