Проблема: Срабатывание концевого выключателя для остановки двигателя постоянного тока.

Я хочу создать проект по управлению автоматическими воротами и гаражными воротами через приложение Android и подключение через модуль Bluetooth HC-05. Каждые ворота и гаражные ворота оснащены двумя концевыми выключателями (расположенными на каждом конце хода) для остановки двигателя постоянного тока.

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

Кто-нибудь может мне помочь?

Вот мой текущий код, спасибо

// Двигатель для ворот (MotorA)
int IN1 = 2;
int IN2 = 3;
int EnableMotorA = 9;

// Мотор для гаражных ворот (MotorB)
int IN3 = 4;
int IN4 = 5;
int EnableMotorB = 10;

const int LimitSwitch1 = A1;
const int LimitSwitch2 = A2;
const int LimitSwitch3 = A3;
const int LimitSwitch4 = A4;

int state;


void setup(){
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(EnableMotorA,OUTPUT);

  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);
  pinMode(EnableMotorB,OUTPUT);

  pinMode(LimitSwitch1, INPUT);
  pinMode(LimitSwitch2, INPUT);
  pinMode(LimitSwitch3, INPUT);
  pinMode(LimitSwitch4, INPUT);

  digitalWrite(LimitSwitch1, LOW);
  digitalWrite(LimitSwitch2, LOW);
  digitalWrite(LimitSwitch3, LOW);
  digitalWrite(LimitSwitch4, LOW);

  Serial.begin(9600);
}

void loop(){
  if(Serial.available() > 0){
    state = Serial.read();
    }
    if(state == 'A') {
      OpenGate();
      if(digitalRead(LimitSwitch2) == HIGH){
      StopMotorA();
      }
    }
    else if(state == 'B') {
      CloseGate();
      if(digitalRead(LimitSwitch1) == HIGH){
      StopMotorA();
      }
    }
    else if(state == 'C') {
      OpenGarageDoor();
      if(digitalRead(LimitSwitch4) == HIGH){
      StopMotorB();
      }
    }
    else if(state == 'D') {
      CloseGarageDoor();
      if(digitalRead(LimitSwitch3) == HIGH){
      StopMotorB();
      }
    }
}

//******************** Управление двигателем А *******************
void OpenGate(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(EnableMotorA, 250);
  }
void CloseGate(){
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(EnableMotorA, 250);
}
void StopMotorA(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  analogWrite(EnableMotorA, 0);
 }
//******************** Управление двигателем B *******************
void OpenGarageDoor(){
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(EnableMotorB, 250);
}
void CloseGarageDoor(){
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(EnableMotorB, 250);
}
void StopMotorB(){
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(EnableMotorB, 0);
}
//*********************************************************

, 👍0

Обсуждение

не запускайте двигатель после замыкания переключателя. запускайте его только с помощью BT. .... нарисуйте блок-схему на бумаге, затем создайте код, который имитирует блок-схему., @jsotola

Извините, но что такое BT? Я сделал блок-схему, она выглядит так: двигатель постоянного тока вращается по часовой стрелке -> нажат ли концевой выключатель? -> если да, остановите двигатель постоянного тока. И я думал, что сделал это таким образом, @Husna Amiliansyah

BT ... bluetooth ..... вы получаете свои состояния из последовательного соединения. Это нормально, но вам также нужны внутренние состояния. Например: состояние E --- статус: все остановлено .... вход из состояния B при активации концевого выключателя (и из других), @jsotola

вам нужно как минимум 4 отдельных состояния стоп... дверь открыта, дверь закрыта, остановка двери при открытии, остановка двери при закрытии. .... выполните поиск в Интернете по запросу state machine или arduino state machine, @jsotola

состояние ссылается на символ, полученный от BT. Включен ли оператор if для концевого выключателя также в состояние остановки? хорошо, я проведу исследование по этому вопросу, спасибо, @Husna Amiliansyah


1 ответ


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

2

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не тестировал код в этом ответе, но надеюсь, что проблем не возникнет.

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

В вашем случае небольшой конечный автомат — это то, что лучше всего подходит для вашей проблемы. Лучше дайте вашим состояниям осмысленные имена, не так ли?

Итак, для начала давайте определим состояния и способы перехода через них.

У вас в основном состояние ожидания, открытые ворота, закрытые ворота, открытые ворота гаража, закрытые ворота гаража. Что вам следует делать в этих состояниях, как при въезде в состояние, так и во время нахождения в состоянии? Вот таблица для обобщения

State       | Enter         | During time
----------------------------------------------
Idle        | Stop motors   | -
OpenGate    | Start A dir 1 | -
CloseGate   | Start A dir 2 | -
OpenGarage  | Start B dir 1 | -
CloseGarage | Start B dir 2 | -

Переходы довольно просты. Выходите из режима ожидания, когда получаете (действительную) команду, выходите из других режимов, когда достигаете конечной остановки.

Реализация довольно стандартная:

// Двигатель для ворот (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;

// Мотор для гаражных ворот (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;

const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;

const byte State_Idle = 0;
const byte State_OpenGate = 1;
const byte State_CloseGate = 2;
const byte State_OpenGarage = 3;
const byte State_CloseGarage = 4;
byte currentState;

void setup(){
    pinMode(IN1,OUTPUT);
    pinMode(IN2,OUTPUT);
    pinMode(EnableMotorA,OUTPUT);

    pinMode(IN3,OUTPUT);
    pinMode(IN4,OUTPUT);
    pinMode(EnableMotorB,OUTPUT);

    pinMode(LimitSwitch1, INPUT);
    pinMode(LimitSwitch2, INPUT);
    pinMode(LimitSwitch3, INPUT);
    pinMode(LimitSwitch4, INPUT);

    Serial.begin(9600);
    currentState = 0xFF; // Принудительное изменение для перехода в состояние ожидания
}

void loop(){
    // Проверяем, нужно ли нам изменить состояние
    byte nextState = currentState;
    switch (currentState)
    {
    case State_Idle:
        { // Если мы получили действительную команду, начинаем операцию
            if(Serial.available() > 0)
            {
                switch (Serial.read())
                {
                case 'A':
                    nextState = State_OpenGate;
                    break;
                case 'B':
                    nextState = State_CloseGate;
                    break;
                case 'C':
                    nextState = State_OpenGarage;
                    break;
                case 'D':
                    nextState = State_CloseGarage;
                    break;
                default:
                    // Здесь вы можете сообщить о том, что была выполнена неверная команда
                    break;
                }
            }
        }
        break;
    case State_OpenGate:
        if(digitalRead(LimitSwitch2)) // == HIGH не обязательно
            nextState = State_Idle;
        break;
    case State_CloseGate:
        if(digitalRead(LimitSwitch1)) // == HIGH не обязательно
            nextState = State_Idle;
        break;
    case State_OpenGarage:
        if(digitalRead(LimitSwitch4)) // == HIGH не обязательно
            nextState = State_Idle;
        break;
    case State_CloseGarage:
        if(digitalRead(LimitSwitch3)) // == HIGH не обязательно
            nextState = State_Idle;
        break;
    default:
        nextState = State_Idle;
        break;
    }

    // Если произошло изменение, переключить состояние и активировать условие входа
    if (nextState != currentState)
    {
        currentState = nextState; // Перейти в новое состояние
        switch (currentState)
        { // Переход в новое состояние
        case State_Idle:
            // Остановить двигатель А
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 0);
            // Остановить двигатель B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 0);
            break;
        case State_OpenGate:
            // Запустить двигатель А
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, HIGH);
            analogWrite(EnableMotorA, 250);
            break;
        case State_CloseGate:
            // Запустить двигатель А
            digitalWrite(IN1, HIGH);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 250);
            break;
        case State_OpenGarage:
            // Запустить двигатель B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, HIGH);
            analogWrite(EnableMotorB, 250);
            break;
        case State_CloseGarage:
            // Запустить двигатель B
            digitalWrite(IN3, HIGH);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 250);
            break;
        }
    }
}

(Примечание: я изменил некоторые типы, потому что ваш бедный 8-битный uC попросил меня не усложнять его вычисления без необходимости)

Одной из модификаций вашего алгоритма является разъединение двух циклов, поскольку они кажутся разъединенными.

// Двигатель для ворот (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;

// Мотор для гаражных ворот (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;

const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;

const byte StateA_Idle = 0;
const byte StateA_Open = 1;
const byte StateA_Close = 2;
byte currentStateA;

const byte StateB_Idle = 0;
const byte StateB_Open = 1;
const byte StateB_Close = 2;
byte currentStateB;


void setup(){
    pinMode(IN1,OUTPUT);
    pinMode(IN2,OUTPUT);
    pinMode(EnableMotorA,OUTPUT);

    pinMode(IN3,OUTPUT);
    pinMode(IN4,OUTPUT);
    pinMode(EnableMotorB,OUTPUT);

    pinMode(LimitSwitch1, INPUT);
    pinMode(LimitSwitch2, INPUT);
    pinMode(LimitSwitch3, INPUT);
    pinMode(LimitSwitch4, INPUT);

    Serial.begin(9600);
    currentStateA = 0xFF; // Принудительное изменение для перехода в состояние ожидания
    currentStateB = 0xFF; // Принудительное изменение для перехода в состояние ожидания
}

void loop()
{
    byte readChar = 0;
    if(Serial.available() > 0)
        readChar = Serial.read();

    stateMachineA(readChar);
    stateMachineB(readChar);
}

void stateMachineA(byte readChar)
{
    // Проверяем, нужно ли нам изменить состояние
    byte nextState = currentStateA;
    switch (currentStateA)
    {
    case StateA_Idle:
        { // Если мы получили действительную команду, начинаем операцию
            if(readChar > 0)
            {
                switch (readChar)
                {
                case 'A':
                    nextState = StateA_Open;
                    break;
                case 'B':
                    nextState = StateA_Close;
                    break;
                default:
                    // Здесь вы можете сообщить о том, что была выполнена неверная команда
                    break;
                }
            }
        }
        break;
    case StateA_Open:
        if(digitalRead(LimitSwitch2)) // == HIGH не обязательно
            nextState = StateA_Idle;
        break;
    case StateA_Close:
        if(digitalRead(LimitSwitch1)) // == HIGH не обязательно
            nextState = StateA_Idle;
        break;
    default:
        nextState = StateA_Idle;
        break;
    }

    // Если произошло изменение, переключить состояние и активировать условие входа
    if (nextState != currentStateA)
    {
        currentStateA = nextState; // Перейти в новое состояние
        switch (currentStateA)
        { // Переход в новое состояние
        case StateA_Idle:
            // Остановить двигатель А
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 0);
            break;
        case StateA_Open:
            // Запустить двигатель А
            digitalWrite(IN1, LOW);
            digitalWrite(IN2, HIGH);
            analogWrite(EnableMotorA, 250);
            break;
        case StateA_Close:
            // Запустить двигатель А
            digitalWrite(IN1, HIGH);
            digitalWrite(IN2, LOW);
            analogWrite(EnableMotorA, 250);
            break;
        }
    }
}

void stateMachineB(byte readChar)
{
    // Проверяем, нужно ли нам изменить состояние
    byte nextState = currentStateB;
    switch (currentStateB)
    {
    case StateB_Idle:
        { // Если мы получили действительную команду, начинаем операцию
            if(readChar > 0)
            {
                switch (readChar)
                {
                case 'C':
                    nextState = StateB_Open;
                    break;
                case 'D':
                    nextState = StateB_Close;
                    break;
                default:
                    // Здесь вы можете сообщить о том, что была выполнена неверная команда
                    break;
                }
            }
        }
        break;
    case StateB_Open:
        if(digitalRead(LimitSwitch4)) // == HIGH не обязательно
            nextState = StateB_Idle;
        break;
    case StateB_Close:
        if(digitalRead(LimitSwitch3)) // == HIGH не обязательно
            nextState = StateB_Idle;
        break;
    default:
        nextState = StateB_Idle;
        break;
    }

    // Если произошло изменение, переключить состояние и активировать условие входа
    if (nextState != currentStateB)
    {
        currentStateB = nextState; // Перейти в новое состояние
        switch (currentStateB)
        { // Переход в новое состояние
        case StateB_Idle:
            // Остановить двигатель B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 0);
            break;
        case StateB_Open:
            // Запустить двигатель B
            digitalWrite(IN3, LOW);
            digitalWrite(IN4, HIGH);
            analogWrite(EnableMotorB, 250);
            break;
        case StateB_Close:
            // Запустить двигатель B
            digitalWrite(IN3, HIGH);
            digitalWrite(IN4, LOW);
            analogWrite(EnableMotorB, 250);
            break;
        }
    }
}

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

,