Проблема: Срабатывание концевого выключателя для остановки двигателя постоянного тока.
Я хочу создать проект по управлению автоматическими воротами и гаражными воротами через приложение 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);
}
//*********************************************************
1 ответ
Лучший ответ:
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не тестировал код в этом ответе, но надеюсь, что проблем не возникнет.
В вашем коде есть серьезная проблема: что происходит, когда одни ворота движутся, а вы запускаете другое движение? (ответ: что-то плохое). Эту проблему проектирования можно решить, используя стандартный способ проектирования такого рода конечных автоматов.
В вашем случае небольшой конечный автомат — это то, что лучше всего подходит для вашей проблемы. Лучше дайте вашим состояниям осмысленные имена, не так ли?
Итак, для начала давайте определим состояния и способы перехода через них.
У вас в основном состояние ожидания, открытые ворота, закрытые ворота, открытые ворота гаража, закрытые ворота гаража. Что вам следует делать в этих состояниях, как при въезде в состояние, так и во время нахождения в состоянии? Вот таблица для обобщения
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;
}
}
}
В этой второй реализации есть два параллельных конечных автомата (совместно использующих только последовательный вход). Это позволит вам управлять обоими воротами одновременно (например, когда ворота закрываются, вы можете открыть гараж)
- Управление двигателем Arduino Uno с помощью 2 реле, 2 концевых выключателей и Bluetooth. Вперед Назад Стоп
- Заменить механический переключатель электрическим переключателем или реле.
- Arduino сбрасывается или зависает во время работы, только когда подключены двигатели постоянного тока
- Можно ли объединить модуль Bluetooth h HC-05 и уменьшенную плату Arduino ATtiny45/85 для управления двигателем, светодиодами или другими компонентами?
- Как управлять коммутатором (proteus) с помощью Bluetooth-карты (HC-05) и arduino?
- Энкодер соединен с валом двигателя. Энкодер выдает более высокие значения, чем ожидалось.
- Можно ли измерить скорость акселерометром? Насколько точно?
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
не запускайте двигатель после замыкания переключателя. запускайте его только с помощью BT. .... нарисуйте блок-схему на бумаге, затем создайте код, который имитирует блок-схему., @jsotola
Извините, но что такое BT? Я сделал блок-схему, она выглядит так: двигатель постоянного тока вращается по часовой стрелке -> нажат ли концевой выключатель? -> если да, остановите двигатель постоянного тока. И я думал, что сделал это таким образом, @Husna Amiliansyah
BT ... bluetooth ..... вы получаете свои состояния из последовательного соединения. Это нормально, но вам также нужны внутренние состояния. Например:
состояние E --- статус: все остановлено .... вход из состояния B при активации концевого выключателя (и из других)
, @jsotolaвам нужно как минимум 4 отдельных состояния
стоп
... дверь открыта, дверь закрыта, остановка двери при открытии, остановка двери при закрытии. .... выполните поиск в Интернете по запросуstate machine
илиarduino state machine
, @jsotolaсостояние ссылается на символ, полученный от BT. Включен ли оператор if для концевого выключателя также в состояние остановки? хорошо, я проведу исследование по этому вопросу, спасибо, @Husna Amiliansyah