"Лифт" (подъемник) на 2 этажа

axenov048
Offline
Зарегистрирован: 06.07.2018

Здравствуйте. Исходные материалы: ардуино, двойной релейный модуль, 2 концевика и кнопка( вообще 3 кнопки вызова - внизу, наверху и в лифте - каждая из которых может отправить лифт в любом направлении взависимости от положения лифта). 

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

int flagStart; //команда Старт - была нажата кнопка вызова
int flagDirection; //Направление движения - читаем какой концевик нажат
int flagMotion; //Включаем реле

void setup(){
    Serial.begin(9600);
	pinMode(1,INPUT); //кнопка вызова
	pinMode(2,INPUT); //концевик внизу
	pinMode(3,INPUT); //концевик вверху
	pinMode(4,OUTPUT); //мотор вверх
	pinMode(5,OUTPUT); //мотор вниз
}

void loop(){
	
	if (digitalRead(1)==HIGH) {
		flagStart=true; //кнопка вызова была нажата
		Direction();  //проверяем положение лифта по концевикам для старта
		flagMotion=true; //запуск лифта
	}
		if (flagMotion==true) {
			digitalWrite(flagDirection,HIGH); //посылаем сигнал на реле в зависимости от состояние концевика(вверх/вниз)
			flagStart==false; //отпускаем команду вызова
		}
		Direction();//проверяем положение лифта во время движения, для остановки по концевику
}
	

void Direction(){ //проверяем какой концевик нажат
       //проверка для старта (т.е. нажат концевик внизу и нажата кнопка вызова, включаем реле вверх)
	if ((digitalRead(2)==HIGH) && (flagStart==true)) flagDirection=4;
	if ((digitalRead(3)==HIGH) && (flagStart==true)) flagDirection=5;
	
	//проверка состояние концевиков во время движение и остановка движения если сработал концевик
	if ((digitalRead(2)==HIGH) && (flagMotion==true)) flagMotion=false;
	if ((digitalRead(3)==HIGH) && (flagMotion==true)) flagMotion=false;

}

 

kalapanga
Offline
Зарегистрирован: 23.10.2016

Для начала, это как бы не весь код. А где собственно включение и выключение моторов (светодиодов) в зависимости от всех этих кнопок и флагов?

sadman41
Offline
Зарегистрирован: 19.10.2016

Так за этим и на форум пришел... чтобы моторы начали включаться.

axenov048
Offline
Зарегистрирован: 06.07.2018

Включение - если digitalRead(1) ==HIGH (кликнули кнопку вызова)- то проверяем какой концевик нажат (допустим digitalRead(2) == HIGH -лифт внизу) и определяем переменную flagDirection = 4 или 5 (верх или вниз, в данном случае 4(вверх)) для digitalWrite(flagDirection,HIGH) - мотор начал движение 

Выключение - если переменная flagMotion включена(лифт движется), а она включается после клика по кнопке вызова - то проверяем положение лифта по концевикам в функции Direction - если flagMotion =True и нажат концевик Вверх(лифт доехал до верха), то объявляем переменную flagMotion =false и тогда в void loop условие  if flagMotion не выполняется - соответсвенно digitalWrite(flagDirection,HIGH) не выполняется.

я пишу и читаю это так)

kalapanga
Offline
Зарегистрирован: 23.10.2016

Сорри, да, запуск-то есть. А остановка мотора где?

axenov048
Offline
Зарегистрирован: 06.07.2018

поправьте пожалуйста если я ошибаюсь - я думал, что если условие не выполняется (т.е. flagMotion не равен True), то и сигнал на digitalWrite(flagDirection,HIGH) отправлятся не будет

kalapanga
Offline
Зарегистрирован: 23.10.2016

От этого HIGH на выводе не пропадёт. Надо LOW записать. Возможно в Direction(), где концевики проверяете и сбрасываете флаг flagMotion=false.

axenov048
Offline
Зарегистрирован: 06.07.2018

пробовал в void loop дописывать 

if (flagMotion==falsedigitalWrite(flagDirection,LOW);
 
не работает
 
может подключение не правильное?

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Вы в логике запутались. Вынесите проверки в функции с говорящими именами. Сразу станет намного легче разбираться.

axenov048
Offline
Зарегистрирован: 06.07.2018

запутаться запутался, прошу помогите распутаться. первый раз пишу

kalapanga
Offline
Зарегистрирован: 23.10.2016

axenov048 пишет:

запутаться запутался, прошу помогите распутаться. первый раз пишу

Ну я имел ввиду так:

if ((digitalRead(2)==HIGH) && (flagMotion==true)) {flagMotion=false; digitalWrite(4, LOW);}
if ((digitalRead(3)==HIGH) && (flagMotion==true)) {flagMotion=false; digitalWrite(5, LOW);}

Если едем и сработал концевик, то остановить соответствующий двигатель и сбросить флаг. Но не факт, что этого достаточно. (4 и 5 сами проверьте кто там верх, кто низ)

Ещё возможно стоит добавить:

 if (digitalRead(1)==HIGH) and !flagMotion {

пока едем - нечего кнопки давить.

axenov048
Offline
Зарегистрирован: 06.07.2018

попробовал, не работает. я все думаю, что проблемы с подключением

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Блин, фига се глюк! написал обстоятельный ответ, а он пропал :( Только маленький кусочек остался

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

axenov048 пишет:

запутаться запутался, прошу помогите распутаться. первый раз пишу

Я думал, что я Вам уже помог фразой

ЕвгенийП пишет:

Вынесите проверки в функции с говорящими именами. Сразу станет намного легче разбираться.

Но, Вы, похоже, её не поняли.

Хорошо, давайте подробнее. Вот смотрите, что у Вас написано, например

axenov048 пишет:

       //проверка для старта (т.е. нажат концевик внизу и нажата кнопка вызова, включаем реле вверх)
	if ((digitalRead(2)==HIGH) && (flagStart==true)) flagDirection=4;
	if ((digitalRead(3)==HIGH) && (flagStart==true)) flagDirection=5;

начнём с того, что комментарий неправильный - последняя строка - она про верхний концевик, а в комментарии о нём ничего не сказано.

Сделайте несколько простых вещей (привыкните их делать всегда) и Вам сразу станет намного легче писать программы и искать в них ошибки.

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

2. Все проверки и действия выделите в отдельные функции с говорящими названиями. Например

enum PINS : uint8_t {
	pin_UpperLimit = 3,
	pin_LowerLimit = 2,
	pin_CallButton = 1, // см. замечание №1 в конце поста
	pin_relayUp = 4,
	pin_RelayDown = 5
};

//
//	Возвращает истину, если нижний концевик активирован
//
inline bool isLowerLimitSwitchActive(void) {
	return digitalRead(pin_LowerLimit);
}

//
//	Возвращает истину, если верхний концевик активирован
//
inline bool isUpperLimitSwitchActive(void) {
	return digitalRead(pin_UpperLimit);
}

//
//	Возвращает истину, если кнопка вызова активирована
//
inline bool isCallButtonActive(void) {
	return digitalRead(pin_CallButton);
}

//
//	Начать движение вверх
//
inline void goUp(void) {
	digitalWrite(pin_RelayDown, LOW); // от греха подальше
	digitalWrite(pin_RelayUp, HIGH); 
}

//
//	Начать движение вниз
//
inline void goUp(void) {
	digitalWrite(pin_RelayUp, LOW); // от греха подальше
	digitalWrite(pin_RelayDown, HIGH); 
}

//
//	Остановиться
//
inline void stop(void) {
	digitalWrite(pin_RelayUp, LOW);
	digitalWrite(pin_RelayDown, LOW);
}

Теперь, Вы никогда не пишете "if (digitalRead ...", но всегда пишете "if (isUpperLimitSwitchActive() ..."

Точно также, Вы никогда не пишете "digitalWrite(...", а пишете "goUp()"

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

2. Вы завели ТРИ флага и запутались в них. Это немудрено. Три флага дают 8 состояний и в них чёрт ногу сломит. Уйдите от использования флагов и работайте через состояния системы. Их меньше и они понятнее. Обязательно дайте им имена (ни в коем случае не числа!!!). Например,

enum ElevatroStates : uint8_t {
	ES_STAYING_1ST_FLOOR,
	ES_STAYING_2ND_FLOOR,
	ES_MOVING_UP,
	ES_MOVING_DOWN
};

И везде используйте состояния, тогда флаги не нужны вовсе. А с так названными состояниями, им и комментарии не нужны - они сами себя комментируют.

Вот теперь попробуйте переписать программу с учётом всего, что я написал, и почувствуйте разницу.

Два замечания напоследок:

1) уйдите от пина 1. Используйте другой. Привыкайте использовать пины 0 и 1 только по прямому назначению. Потом поймёте почему и когда можно, а когда нельзя, пока же - только для UART и ни для каких кнопок

2) у Вас что, одна кнопка вызова?

---------------------------

А если хотите научится писать такие программы грамотно, то у Вас просто изначально неверный подход. Это классическая автоматная задача и делать её надо автоматом. Вот посмотрите пример со светофором на стр. 8+ вот в этой книге. С лифтом всё точно также. Оцените как элегантно и просто получается с таблицей состояний и переходов - проще некуда. Вот так это и надо делать.

axenov048
Offline
Зарегистрирован: 06.07.2018

Большое Вам спасибо за потраченное время на ответ. Сижу изучаю, уже понимаю насколько примитивно и запутано я все написал. Постараюсь изучить больше, так как сейчас не все понятно. сейчас буду читать про inline void ,почемуто ругается на строках inline void goUp(void)

Кнопок вызова 3. на 1 этаже, на втором и в кабине (в кабине хочу подключить беспроводную кнопку). Думаю они все должны быть паралельны. Чтобы нажав на любую из кнопокк можно было вызвать или отправить "лифт"

 

Еще раз большое спасибо!

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Если не понимаете на что ругаетмся - показывайте. И код и копипасту ругани.

axenov048
Offline
Зарегистрирован: 06.07.2018

Да посидел 20 минут подумал и не разобрался. как я понял дальше следует в void loop() записать условия

if (isCallButtonActive==true && isLowerLimitSwitchActive==true) goUp();

if (isCallButtonActive==true && isUpperLimitSwitchActive==true) goDown();

но как указать, что пора остановиться?

а ругается In function 'void goUp()': 42:13: error: redefinition of 'void goUp()' 34:13: error: 'void goUp()' previously defined here

Jeka_M
Jeka_M аватар
Онлайн
Зарегистрирован: 06.07.2014

Там две функции с одинаковым именем - goUp(), это ошибка. Переименуй вторую функцию, например goDown()

b707
Онлайн
Зарегистрирован: 26.05.2017

axenov048 пишет:

Кнопок вызова 3. на 1 этаже, на втором и в кабине (в кабине хочу подключить беспроводную кнопку). Думаю они все должны быть паралельны.

Если все кнопки будут "параллельны" - как лифт узнает, вызываете лм вы его с первого этажа или со второго? Думаю, все три кнопки должны быть независимы.

axenov048
Offline
Зарегистрирован: 06.07.2018

переименовывал. и поправлял регистр. думаю это глюк какой то был на сайте эмулятора. с 4ой попытки получилось

понимать должен по состоянию концевиков. он либо вверху, либо внизу.

 

axenov048
Offline
Зарегистрирован: 06.07.2018

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