Прошу помощи

CRJ
Offline
Зарегистрирован: 22.09.2017

Приветствую, уважаемые форумчане!

Сам я дилетант в этом деле, поэтому строго не судите.

Хочу сделать следующее:

Некое устройство состоящее из сервы, 2х оптопар и светодиода.

Принцип работы:

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

Для контроля срабатывания первой оптопары имеется светодиод, который гаснет по факту срабатывания. Так же серва фиксируется в положении + 10 градусов.

Проблема в следующем: после прохождения 5 импульсов серва начинает беспорядочно шевелиться и все...

#include <Servo.h>
Servo servo;
int sensePin = 12;
boolean Impuls, OldImpuls;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
}

void loop()

{

  if (digitalRead(10)) //если сенсор закрыт
    servo.write(10); //серво + 10
  else (servo.write(0));//серво 0
  if (digitalRead(10)) //если сенсор закрыт
    digitalWrite(8, LOW); // светодиод не горит
  else (digitalWrite(8, HIGH));// светодиод горит

  if (digitalRead(10)) //если сенсор замкнут
  {
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
    if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
    {
      encoder++;  //Считаем импульсы
    }
    if (encoder >= 5) //  5 импульса

      servo.write(90);// серва +90
    {
      if (digitalRead(10))//если сенсор закрыт
      
      { OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
        if (digitalRead(11))
        {
          Impuls = true;  //то запоминаем
        }
        else  //иначе
        {
          Impuls = false; // запоминаем 0
        }
        if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
        {
          encoder++;  //Считаем импульсы
        }
        if (encoder >= 4) //  4 импульса

        {
          servo.write(0);// серва 0

        }
      }
    }
  }
}

Заранее спасибо.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Вам надо раззобраться со стилем и логикой написания програмы.
Вы 3 раза проверяете if (digitalRead(10)) - 2раза if (digitalRead(11)) и выплняете какието действия, при этом не проверяете скобки Например что делае скобка в 45ст. Вы не заботитесь о АНТИДРЕБЕЗГЕ pinMode(11,)  Я не знаю как работает Ваша библиотека Servo.h но используя ваш код я попробова упорядочить то что Вы написали. Попробуйте, если работал Ваш код то должен работать и этот, хотя без антидребезга результат будет не предсказуем.
#include <Servo.h>
Servo servo;
int sensePin = 12;
boolean Impuls, OldImpuls;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
}

void loop()

{
  if (digitalRead(10))  //если сенсор закрыт
  {
    servo.write(10); //серво + 10
    digitalWrite(8, LOW); // светодиод не горит
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
  }
  else {
    (servo.write(0));//серво 0
    (digitalWrite(8, HIGH));// светодиод горит
  }

  if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
  {
    encoder++;  //Считаем импульсы
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (encoder >= 5)  //  5 импульса
    {
      servo.write(90);// серва +90
      delay(1000);
      encoder = 0;
    }
    else if (encoder >= 4) //  4 импульса
    {
      servo.write(0);// серва 0
      delay(1000);
    }
  }
}

 

 

CRJ
Offline
Зарегистрирован: 22.09.2017

Спасибо за ответ!

Все отлично работает, но не так как надо. Требуемый алгоритм работы несколько отличается от Вашего. В Вашем случае по прошествии 5 импульсов серво +90 на 1 секунду, мне же надо - серво +90 на 4 импульса, без задержек. В написании кода я полный профан, т.к. с програмированием сталкивался в школе/институте на уровне бейсика и то 20 лет назад, поэтому и нагородил огород в попытке сделать так как нужно.

Кстати вопрос: почему заданное количество импульсов несколько отличатся от реальных? Просим 5 имп. срабатывает в диапазоне от 3 до 5.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Я просто набросал чтобы чтобы Вы посмотрели как приблизительно можно составить код. А теперь давайте решать в месте.
За количество импульсов отвечает переменная  encoder - вот в 42ст. и 48ст. мы проверяе сколько натикало
(42ст. - if (encoder = 5)  //  5 импульса) если истина то (servo.write(90);// серва +90)
(48ст. - else if (encoder = 4) //  4 импульса) если истина то (servo.write(0);// серва 0)
delay(1000); я поставил чтобы было видно что условие выполнено потому что после него прогрма начинается с начала а там стоит servo.write(10); //серво + 10
без задержки серва будет просто дегаться. После всего сказаного я думаю что при encoder = (1.2.3.-10) Вы серву повернете. А вот когда ее вернуть назад или через какое время Вы не указали, поэтому и ответа нет.
Да и в проверке надо ставить не (if (encoder >= 5)) а (if (encoder = 5))
CRJ
Offline
Зарегистрирован: 22.09.2017

Спасибо за ответ. Попробую описать что нужно на реальном примере:

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

Удалось зафиксировать серво в положении +90

#include <Servo.h>
Servo servo;
int sensePin = 12;
int pos = 90;//рабочая позиция серво
int nul = 0;//нулева позиция серво
boolean Impuls, OldImpuls;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
  servo.write(nul);//нулевая позиция серво
}

void loop()

{
  if (digitalRead(10))  //если сенсор закрыт
  {
    digitalWrite(8, LOW); // светодиод не горит
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
  }
  else {
    (digitalWrite(8, HIGH));// светодиод горит
    servo.write(nul);// серва 0
  }

  if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
  {
    encoder++;  //Считаем импульсы
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (encoder == 6)  //  6 импульсов
    {
      servo.write(pos);// серва +90
      encoder = 0;
    }
  }
}

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Не хочется вам пересказывать как программировать на Си++ , использовать ООП и в результате вы все равно не будет ни в зуб ногой. Да что говорить. Вы даже скетч не отладите.

CRJ
Offline
Зарегистрирован: 22.09.2017

Прекрасный по своей развернутости ответ!

Наша с Вами разница, уважаемый qwone, в следующем: Вам есть что пересказать о программировании на С++, в моем случае даже аббревиатура "ООП", заставила меня гуглить. 

GarryC
Offline
Зарегистрирован: 08.08.2016

Судя по Вашему описанию - в диапазоне от 3 до 5 - Вам подсказали основную идею - дребезг и необходимость его подавления.

CRJ
Offline
Зарегистрирован: 22.09.2017

GarryC пишет:

Судя по Вашему описанию - в диапазоне от 3 до 5 - Вам подсказали основную идею - дребезг и необходимость его подавления.

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

Т.е. 6 импульсов - серва +90, после еще, скажем, 6 импульсов серва в ноль, цикл закончен.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

CRJ пишет:
заставила меня гуглить.
Это хорошо что вы начали гуглить. Продолжу. В наш блин век засилия компьютеров мы так или иначе "программисты". Но для программирования используются разные подходы. Их вроде шесть. У вас процедурный подход. Это когда вы все решаете созданием функций. Но это дико устаревший , хотя и простой подход.  Но есть еще и объектный подход. Создание объектов.  Привожу аналогию. К примеру у вас порвался сапог. Вы пишете процедуру "починить сапог".  У меня же "сапог" это объект. Его  надо отнести в "сапожную мастерскую" - тоже объект. И в нем "сапожник" (и он сука) тоже объект. Сложно вроде да. Но есть большой плюс. Отнеся "сапог" "сапожнику"  вы можете пойти на работу, пойти гулять, и много чего другого.  Вот это и есть большой плюс от ООП. Вы можете заставить один компьютер делать много вещей. Это же касается и ардуино, и даже в ее родной среде.

ПС: А это для того что бы я не показался вам вруном.http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-chainikov

CRJ
Offline
Зарегистрирован: 22.09.2017

Qwone, я не считаю Вас голословным, можно было с этого и начать, мол, дорогой %username%, есть такая штука как классы, объекты и прочая святотень, обратите свой ясный взор на вот эту тему %линк%, там я для всех "программистов" в примерах разъяснил как это работает.

Именно по причине его простоты я и взялся за процедурный подход. Тема эта мне интересна для гаражного DIY, посему хочется все и сразу. Конкретная задача, очевидно, не требует каких либо сложных решений, но в силу отсутствия знаний, даже эта задача, как оказалось, мне не под силу. Иначе мы с Вами и не общались бы.

Ежели все так просто - направьте в нужное русло, подскажите. Я ведь сам по крупицам (доступным и понятным мне) пытаюсь собрать информацию.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

/**/
unsigned long mill; // переменная под millis()
typedef void (*handler)() ;
//--------------------------------
class Cl_Device {
  protected:
  public:
    Cl_Device() {}
    void setup() {}
    void loop() {}
};
//------Cl_Btn----------------------
// класс кнопка
class Cl_Btn {
  protected:
    const byte pin;
    handler Do1, Do2;
    bool btn = 1, oldBtn;
    unsigned long past;
  public:
    Cl_Btn(byte pin_, handler Do1_, handler Do2_): pin(pin_), Do1(Do1_) , Do2(Do2_) {}
    void setup() {
      pinMode(pin, INPUT_PULLUP);
      oldBtn = digitalRead(pin);
    }
    void loop() {
      btn = digitalRead(pin);
      if (!oldBtn && btn) {
        oldBtn = 1;
        Do1();
      }
      if (!oldBtn && btn) {
        btn = 0;
        Do2();
      }
    }
};
//---Компоновка-----------------------------
void Do1_btn1() {}
void Do2_btn1() {}
void Do1_btn2() {}
void Do2_btn2() {}
Cl_Btn btn1(/*пин*/10,/*наж*/Do1_btn1,/*отж*/Do2_btn1);
Cl_Btn btn2(/*пин*/11,/*наж*/Do1_btn2,/*отж*/Do2_btn2);
//---main-----------------------------
int main() {
  init();
  //setup()
  btn1.setup();
  btn2.setup();
  for (;;) {
    //loop()
    mill = millis();
    btn1.loop();
    btn2.loop();
  }
  return 0;
}
/*
  Скетч использует 1012 байт (3%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 35 байт (1%) динамической памяти, оставляя 2013 байт для локальных переменных.
*/

А с вашим компонентов который управляет сервой тоже все просто.  Каждый простой объект имеет состояние (переменую состояние) Монета 2 состояния орел решка, кубик - шесть. А у вашего объекта (x+y) состояний. от 0 до x серва в одном положении а с x+1 до x+y  в другом. и так по кругу.  Перекрыли одну оптопару у вас сброс, а перекрытие другой у вас шаг состояние на 1. И все. 

CRJ
Offline
Зарегистрирован: 22.09.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

CRJ пишет:

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

Процессор один, а объектов много. Подошло время - сработал компонент, нет- просто вошел и вышел. Быстрый loop все связывает в кучу.

CRJ
Offline
Зарегистрирован: 22.09.2017

А можно более конкретно прокоментировать код:

Куда привязывть значения прерываний?

Что значит Do1, Do2?

Cl_Btn btn1(/*пин*/10,/*наж*/Do1_btn1,/*отж*/Do2_btn1); - пин, наж, отж - это комменты?

CRJ
Offline
Зарегистрирован: 22.09.2017

Куда теперь девать серву?

CRJ
Offline
Зарегистрирован: 22.09.2017

Кто такой handler Do1, Do2; и за что отвечает.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Если на открытие и закрытие идет одинаковое число импульсов то можно так.
Если разное то надо по другому, у Вас в условии одинаковое.
#include <Servo.h>
Servo servo;
int sensePin = 12;
int pos = 90;//рабочая позиция серво
int nul = 0;//нулева позиция серво
boolean Impuls, OldImpuls;
bool value;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
  servo.write(nul);//нулевая позиция серво
}

void loop()

{
  if (digitalRead(10))  //если сенсор закрыт
  {
    digitalWrite(8, LOW); // светодиод не горит
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
  }
  else {
    (digitalWrite(8, HIGH));// светодиод горит
    servo.write(nul);// серва 0
    value = 0;
  }

  if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
  {
    encoder++;  //Считаем импульсы
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (encoder == 6)  //  6 импульсов
    {
      value = !value;
      if (value)servo.write(pos); // серва +90
      else servo.write(nul);// серва 0
      encoder = 0;
    }
  }
}

 

 

CRJ
Offline
Зарегистрирован: 22.09.2017

Ой спасибо! А если разные значения?

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Как то так на 26 или другое количество тиков 

#include <Servo.h>
Servo servo;
int sensePin = 12;
int pos = 90;//рабочая позиция серво
int nul = 0;//нулева позиция серво
boolean Impuls, OldImpuls;
bool value;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
  servo.write(nul);//нулевая позиция серво
}

void loop()

{
  if (digitalRead(10))  //если сенсор закрыт
  {
    digitalWrite(8, LOW); // светодиод не горит
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
  }
  else {
    (digitalWrite(8, HIGH));// светодиод горит
    servo.write(nul);// серва 0
    value = 0;
  }

  if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
  {
    encoder++;  //Считаем импульсы
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (encoder == 6 && !value)  //  6 импульсов
    {
      value = !value;
      servo.write(pos); // серва +90
      encoder = 0;
    }
    if (encoder == 26 && value)  //  26 импульсов
    {
      value = !value;
      servo.write(nul);// серва 0
      encoder = 0;
    }
  }
}

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

CRJ пишет:

Куда теперь девать серву?

Вышли мне по почте.

CRJ
Offline
Зарегистрирован: 22.09.2017

Ворота пишет:

CRJ пишет:

Куда теперь девать серву?

Вышли мне по почте.


Что взамен предложишь, у меня серв много всяких…

CRJ
Offline
Зарегистрирован: 22.09.2017

vosara пишет:

Как то так на 26 или другое количество тиков 

#include <Servo.h>
Servo servo;
int sensePin = 12;
int pos = 90;//рабочая позиция серво
int nul = 0;//нулева позиция серво
boolean Impuls, OldImpuls;
bool value;
int sensor;
int encoder;

void setup()
{
  pinMode(10, INPUT_PULLUP); //sen
  pinMode(11, INPUT_PULLUP); //enc
  pinMode(8, OUTPUT);// светодиод
  servo.attach(12);//серва
  servo.write(nul);//нулевая позиция серво
}

void loop()

{
  if (digitalRead(10))  //если сенсор закрыт
  {
    digitalWrite(8, LOW); // светодиод не горит
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (digitalRead(11))
    {
      Impuls = true;  //то запоминаем
    }
    else  //иначе
    {
      Impuls = false; // запоминаем 0
    }
  }
  else {
    (digitalWrite(8, HIGH));// светодиод горит
    servo.write(nul);// серва 0
    value = 0;
  }

  if (Impuls && !OldImpuls)  //Если текущий импульс 1, а предыдущий 0
  {
    encoder++;  //Считаем импульсы
    OldImpuls = Impuls; // Запоминаем состояние предыдущего импульса
    if (encoder == 6 && !value)  //  6 импульсов
    {
      value = !value;
      servo.write(pos); // серва +90
      encoder = 0;
    }
    if (encoder == 26 && value)  //  26 импульсов
    {
      value = !value;
      servo.write(nul);// серва 0
      encoder = 0;
    }
  }
}

 

Спасибо, завтра попробую.

UPD: Заработало, еще раз спасибо.

fogary
Offline
Зарегистрирован: 05.03.2016

qwone пишет:

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

...

void loop() {
  btn = digitalRead(pin);
  if (!oldBtn && btn) {
    oldBtn = 1;
    Do1();
  }
  if (!oldBtn && btn) {
    btn = 0;
    Do2();
  }
}

Что-то не могу понять, когда может сработать второе условие?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Никогда, просто Квон обкурился немного когда это писал.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

CRJ пишет:
Что взамен предложишь
"Экой ты меркантильный! О душе бы подумал!"