Наливатор - автоматизированная машина, которая будет разливать алкоголь по стопкам.

Viblis
Offline
Зарегистрирован: 04.11.2016

А я решил уйти от этой схемы- минусы эксплуатации в том, что дозировка определяеться с помощью команды Delay(), т.е. временем работы помпы. Соответственно  при первом наливе еще система (трубка) должна заполниться жидкостью, а длина трубки у всех разная и зависит от многих факторов (расположение бутылки относительно наливатора, высота самой бутылки, метод крепления трубки к бутылке (глубина погружения)) Кроме этого после использования трубка остается заполнена, нужно или все доливать, или аккуратно вытаскивать и запускать систему уже без бутылки, что бы не проливалось. После применения наливатора по назначению сеё действо напрягает -))). Поигрался несколько раз перед гостями и отложил на полку. Сейчас делаю новую схему с запорным клапаном от авто и расходомером, заказал вот такой на алли, жду когда придет:https://ru.aliexpress.com/item/32871530987.html?spm=a2g0s.9042311.0.0.274233edQN1uy5

 

Araris
Araris аватар
Offline
Зарегистрирован: 09.11.2012

Пожалуй, это уже на подфорум "Проекты" тянет, перенёс.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Оптодатчик у меня самодельный АЛ157 и КТФ109А

Есть предложение: добавить  в схему DF Player mini (https://ru.aliexpress.com/item/32665891488.html?spm=a2g0o.cart.0.0.3cc13c00acZQHK),  для аудио воспроизведения "Тостов от Михалыча" после розива:

1    Ну, начали! (сразу после промывки)
2    Ну, за встречу!
3    Ну, за красоту!
4    Ну, за дружбу!
5    Ну, за братство!
6    Ну, за справедливость!
7    Ну, за рыбалку!
8    Ну, за искусство!
9    Ну, за разум!
10    Ну, за истинных женщин! А их, уверяю вас, и у нас да и во всём мире, очень много! Ну, за женщин!
11    Ну, за понимание!
12    Ну, за солидное мужское молчание!
13    Ну, за единение!
14    Ну, за истинных женщин! А их, уверяю вас, и у нас да и во всём мире, очень много!
15    Ну, за женщин!
16    Ну, за победу!
17    Ну, чтоб голова не трещала!
18    Ну,чтоб не морщило
19    Ну, чтоб в сторону не вильнуло!
20    Ну,вы блин даете
21    Ну, за Родину!

Нарезка файлов имеется.

Так же емть кусочки кода.

den-a2rh
Offline
Зарегистрирован: 07.01.2018

Хорошая идея

den-a2rh
Offline
Зарегистрирован: 07.01.2018

а скетч и схема подключения есть?

atom23rus
Offline
Зарегистрирован: 06.08.2019

ты есть в вк?!ну или на почту можешь брякнуть. Есть вопросы по твоему скетчу.можешь помочь?!моя почта darmi_talibanov@mail.ru 

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

den-a2rh пишет:
а скетч и схема подключения есть?

В 34 сообщении, по скетчу понятно что куда подключать.

atom23rus
Offline
Зарегистрирован: 06.08.2019

я новичек в этом деле. у меня вопрос какому пину подключать серву и что используется в качестве распознавания рюмок(ик датчик)? может Вы мне подскажите?

den-a2rh
Offline
Зарегистрирован: 07.01.2018

Я имел ввиду скетч и схема подключения с плеером

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

den-a2rh, это пока проект. Подключается к Rx и Tx  или к свободным цифровым пинам используя  SoftwareSerial. Ну примерно так хотел реализовать.

#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
Serial.begin (9600);
char *str[] = {"---------", "Ye? yfxfkb!", "pf dcnhtxe!", "pf rhfcjne!", "pf lhe;,e!", "pf ,hfncndj!", "pf cghfdtlkbdjcnm!", 
//					07				08				09				10					11				12
			   "pf hs,fkre!", "pf bcreccndj!", "pf hfpev!", "pf bcnbyys[ ;tyoby!", "pf gjybvfybt!", "pf cjkblyjt ve;crjt vjkxfybt!", 
//					13		   		14				15			16					17							18
			   "pf tlbytybt!", "pf bcnbyys!", "pf ;tyoby!", "pf gj,tle!", "xnj, ujkjdf yt nhtofkf!", "xnj, vjhobkj vtymit!", 
//							19						20
			   "xnj, d cnjhjye yt dbkmyekj!", "pf Hjlbye!"};

void nocheck()//Случайный выбор тоста и его проигрывание
{
	unsigned int index = (unsigned int)(random(2, 21));
	myOLED.print(str[index], CENTER, 50);
	mp3_play(index);
	delay(100);
	mp3_stop();
	myOLED.update();
}

 

stpavel
Offline
Зарегистрирован: 09.10.2018

Viblis пишет:

А я решил уйти от этой схемы- минусы эксплуатации в том, что дозировка определяеться с помощью команды Delay(), т.е. временем работы помпы. Соответственно  при первом наливе еще система (трубка) должна заполниться жидкостью, а длина трубки у всех разная и зависит от многих факторов (расположение бутылки относительно наливатора, высота самой бутылки, метод крепления трубки к бутылке (глубина погружения)) Кроме этого после использования трубка остается заполнена, нужно или все доливать, или аккуратно вытаскивать и запускать систему уже без бутылки, что бы не проливалось. После применения наливатора по назначению сеё действо напрягает -))). Поигрался несколько раз перед гостями и отложил на полку. Сейчас делаю новую схему с запорным клапаном от авто и расходомером, заказал вот такой на алли, жду когда придет:https://ru.aliexpress.com/item/32871530987.html?spm=a2g0s.9042311.0.0.274233edQN1uy5

 

А я прихожу к мнению что однозначно нужно использовать перистальтический насос. Если еще и с шаговиком ,то точность будет как в аптеке. Плюс забирать жидкость нужно не из бутылки, а сверху в наливаторе должен быть какой то сосуд. Наполнил,  и из него уже разлив по рюмкам. Это минимизирует длину всех шлангов в системе. Да и шланг в бутылку с дозатором не засунешь.

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

 

 

 

Viblis
Offline
Зарегистрирован: 04.11.2016

stpavel пишет:
А я прихожу к мнению что однозначно нужно использовать перистальтический насос

Кстати да, хорошая идея, и стоит недорого, к примеру, 3*5

https://ru.aliexpress.com/item/32770860268.html?scm=1007.23534.124000.0&pvid=ab234279-ff76-40aa-bd9d-b23e98ded993&rmsg=do_not_replacement&af=TO&cn=aliexpress&cv=banner&dp=19TZ1Q2mXOZvNFh&tp2=TO&afref=&aff_platform=link-c-tool&cpt=1565119506737&sk=cD4TW1tW&aff_trace_key=1a8381bff4b94720bdb52756f0d75557-1565119506737-00047-cD4TW1tW&terminal_id=a084fd7ec79949e9a7b1cbe993a5be61

Нужно только правильно по производительности подобрать

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

atom23rus пишет:

я новичек в этом деле. у меня вопрос какому пину подключать серву и что используется в качестве распознавания рюмок(ик датчик)? может Вы мне подскажите?

Серва подключается к 9 пину (const int PIN_SERVO = 9;)

Энкодер к 2, 3 и 4

const int pin_A = 2;       // Подключение вывода A (CLK) энкодера
const int pin_B = 3;       // Подключение вывода B (DT) энкодера
const int pin_SW = 4;       // Подключение вывода кнопки (SW) энкодера

Датчики к аналоговым входам (Оптопары подключены, A0,A1,A2,A3,A6)

Схема датчика в моем сообщении  см. выше. Можно использовать ИК светодиод и ИК фототранзистор, я использовал что имелось в наличии. при выборе светодиода и фототранзистора смотри чтобы работали на одной волне.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Вот еще одно решение с краником:

Использовал кабель канал 16х16.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

stpavel, у Вас , как я понимаю, парковка 0, рюмки 35,70,105,140,175 градусов?

206 for (int pos = servo.read();  pos >= 0; pos -= 1) {

193 for (int pos = servo.read(); pos <= rumka * 35; pos += 1)

У меня парковка 6 (над 1й рюмкой), рюмки 8,50,92,134,176 градусов, как поменять формулу вычисления?

 

atom23rus
Offline
Зарегистрирован: 06.08.2019

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

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

stpavel, у Вас , как я понимаю, парковка 0, рюмки 35,70,105,140,175 градусов?

206 for (int pos = servo.read();  pos >= 0; pos -= 1) {

193 for (int pos = servo.read(); pos <= rumka * 35; pos += 1)

У меня парковка 6 (над 1й рюмкой), рюмки 8,50,92,134,176 градусов, как поменять формулу вычисления?

 

Да, верно.

Переделаю в ближайшие пару дней , выложу.

 

atom23rus
Offline
Зарегистрирован: 06.08.2019

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

1 206 for (int pos = servo.read();  pos >= 8; pos -= 0) {
2  
3 193 for (int pos = servo.read(); pos <= rumka * 42; pos += 1)

 

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

atom23rus, ошибся. Сейчас объясню.

for (int pos = servo.read();  pos >= 0; pos -= 1) - это парковка, считывается позиция сервы; если позиция больше считываемой (она может быть 35,70,105,140,175 как у автора или 8,50,92,134,176 как у меня, то вычитается 1 градус и - servo.write(pos); передается на серву которая перемещается на 1 градус за 10милиСекунд -  delay(10); - и так по циклу пока не дойдет до нуля.

for (int pos = servo.read(); pos <= rumka * 35; pos += 1) Серва, дешовая как у меня, имеет угол поворота 0...175 градусов с невеликой точностью, формула: pos <= rumka * 35; вычисляет позицию рюмки поз1=1*35=35г, поз2- 75г, ....поз5=5*35=175г, позиция в зависимости от номера неналитой рюмки вычисляется и по градусу перемещается в указанное положение. Если 42*5=210градусов, это пркатит если серва 0...360 градусов.

Мне тоже кое что непонятно:

31	const byte  max_DrinkCount = 5; //Максимальное кол-во рюмок - 5
	
191	void ServoNaliv(int rumka) {
  servo.attach(PIN_SERVO);
  for (int pos = servo.read(); pos <= rumka * 35; pos += 1) { // вращаем ротор от 0 до 180 градусов
    // с шагом в 1 градус
    servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos'
    delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию
  }
  servo.detach();


201	}

337		for (int y = 0; y < max_DrinkCount; y++) {
            if (analogRead(Optics[y]) > 1000 ) {
              strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом
              strip.show();
              ServoNaliv(y); // Перемещяемся к рюмке
              pump_timer(Drink); // Налив.
              strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито.
              strip.show();
              drink_count++;
            }
		}

Получается y=rumka?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Viblis пишет:

stpavel пишет:
А я прихожу к мнению что однозначно нужно использовать перистальтический насос

Кстати да, хорошая идея, и стоит недорого, к примеру, 3*5

https://ru.aliexpress.com/item/32770860268.html?scm=1007.23534.124000.0&pvid=ab234279-ff76-40aa-bd9d-b23e98ded993&rmsg=do_not_replacement&af=TO&cn=aliexpress&cv=banner&dp=19TZ1Q2mXOZvNFh&tp2=TO&afref=&aff_platform=link-c-tool&cpt=1565119506737&sk=cD4TW1tW&aff_trace_key=1a8381bff4b94720bdb52756f0d75557-1565119506737-00047-cD4TW1tW&terminal_id=a084fd7ec79949e9a7b1cbe993a5be61

Нужно только правильно по производительности подобрать

Отличный моторчик. Для справки - 50 грамм наливает примерно за 30 секунд. - из отзывов на али.

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

Viblis пишет:

stpavel пишет:
А я прихожу к мнению что однозначно нужно использовать перистальтический насос

Кстати да, хорошая идея, и стоит недорого, к примеру, 3*5

https://ru.aliexpress.com/item/32770860268.html?scm=1007.23534.124000.0&pvid=ab234279-ff76-40aa-bd9d-b23e98ded993&rmsg=do_not_replacement&af=TO&cn=aliexpress&cv=banner&dp=19TZ1Q2mXOZvNFh&tp2=TO&afref=&aff_platform=link-c-tool&cpt=1565119506737&sk=cD4TW1tW&aff_trace_key=1a8381bff4b94720bdb52756f0d75557-1565119506737-00047-cD4TW1tW&terminal_id=a084fd7ec79949e9a7b1cbe993a5be61

Нужно только правильно по производительности подобрать

Отличный моторчик. Для справки - 50 грамм наливает примерно за 30 секунд. - из отзывов на али.

 

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

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

 

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

Мне тоже кое что непонятно:

31	const byte  max_DrinkCount = 5; //Максимальное кол-во рюмок - 5
	
191	void ServoNaliv(int rumka) {
  servo.attach(PIN_SERVO);
  for (int pos = servo.read(); pos <= rumka * 35; pos += 1) { // вращаем ротор от 0 до 180 градусов
    // с шагом в 1 градус
    servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos'
    delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию
  }
  servo.detach();


201	}

337		for (int y = 0; y < max_DrinkCount; y++) {
            if (analogRead(Optics[y]) > 1000 ) {
              strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом
              strip.show();
              ServoNaliv(y); // Перемещяемся к рюмке
              pump_timer(Drink); // Налив.
              strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито.
              strip.show();
              drink_count++;
            }
		}

Получается y=rumka?

Да , совершенно верно.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

"а то слюной захлебнешся ," - сам хотел озвучить.

Viblis
Offline
Зарегистрирован: 04.11.2016

Forthomo пишет:

"а то слюной захлебнешся ," - сам хотел озвучить.

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

stpavel
Offline
Зарегистрирован: 09.10.2018

Исправленная версия. 

Появилась переменная 

//Позиция каждой рюмки 
const byte Rumka_pos[] = {0,40,75,105,140};

Сюда забиваем свои значения угла серво для каждой рюмки. 

Краткое описание, три пункта меню, Авто, Ручной и Промывка . Управление одним энкодером. 

Вращаяем влево/вправо - перемещаемся по меню. Нажатие на энкодер вход в меню. Долгое нажатие энкодера - выход в главное меню. 

Для  включения промывки нужно нажать на энкодер на пункте Промывка  и держать три секунды. После этого насос включиться и будет оставаться включенным до момента отпускания кнопки энкодера. Я посчитал что так удобно, случайно не включишь, защита от "дурака".

Меню авто - тут все понятно. наличие рюмок по оптическим датчикам. 

Меню ручной - Вращаем вправо энкодер - увеличиваем милилитры в рюмку по кругу, вращая в левую сторону меняем количество рюмок. 

#include <OLED_I2C.h>
#include <Servo.h>
#include "Adafruit_NeoPixel.h"

OLED  myOLED(SDA, SCL, 8); //Подключение экрана А4, А5
extern uint8_t MegaNumbers[];
extern uint8_t RusFont[];
extern uint8_t SmallFont[];
unsigned long currentTime;
unsigned long loopTime;
unsigned long ledTime;
// Переменные для энкодера -----------
const int pin_A = 2;       // Подключение вывода A (CLK) энкодера
const int pin_B = 3;       // Подключение вывода B (DT) энкодера
const int pin_SW = 4;       // Подключение вывода кнопки (SW) энкодера
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev = 0;
unsigned char encoder_sw_prew = 1;
//Массив , обозначаем подключенные оптопары по выводам . Оптопары подключены, A0,A1,A2,A3,A6
const byte  Optics[] = {0, 1, 2, 3, 6};
//Серво
const int PIN_SERVO = 9;
Servo servo;
//Позиция каждой рюмки 
const byte Rumka_pos[] = {0,40,75,105,140};
//-------------------------
byte  Menu = 0;
byte MenuFlag = 0; // Здесь храниться уровень меню. 0 находимся в  Главном меню. 1 Вошли в меню Авто, 2 вошли в  Ручное управление
byte  Drink = 25; // По умолчанию в рюмку наливаем  20 мл.
const byte  max_Drink = 50; // Максимум в рюмку - 50 мл.
byte  DrinkCount = 1; //По умолчанию, для ручного режима - 1 рюмка
const byte  max_DrinkCount = 5; //Максимальное кол-во рюмок - 5
// Насосик
const byte PIN_PUMP = 12;
// Светодиоды
const int PIN_LED = 5;// Сюда подключаются светодиоды
const int LED_COUNT = max_DrinkCount;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN_LED, NEO_GRB + NEO_KHZ800);
//-------



void pump_enable() {
  digitalWrite(PIN_PUMP, 1);
}

void pump_disable() {
  digitalWrite(PIN_PUMP, 0);
}

void pump_timer(byte Drink) {
  digitalWrite(PIN_PUMP, 1);
  delay(map(Drink, 2, 50, 300, 4000));
  digitalWrite(PIN_PUMP, 0);
}

void oled_menu(int Menu) {
  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print(F("Y F K B D F N J H"), CENTER, 0);
  myOLED.print(F("F D N J"), CENTER, 15);
  myOLED.print(F("H E X Y J Q "), CENTER, 30);
  myOLED.print(F("G H J V S D R F"), CENTER, 45);
  myOLED.setFont(SmallFont);
  myOLED.print(F(">"), LEFT, (Menu * 15) + 15);
  myOLED.print(F("<"), RIGHT, (Menu * 15) + 15);
  myOLED.update();

}
//  выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение
void DrinkInfo(byte pos) {
  if (Drink < 15) {
    myOLED.print(F("YB J XTV"), CENTER, pos);
  } else if (Drink < 28) {
    myOLED.print(F("GJ XENM - XENM"), CENTER, pos);
  } else if (Drink < 38) {
    myOLED.print(F("D CFVSQ HFP"), CENTER, pos);
  } else if (Drink < 48) {
    myOLED.print(F("GJ GJKYJQ"), CENTER, pos);
  } else {
    myOLED.print(F("LJ RHFTD"), CENTER, pos);
  }

}

void Tost() {
  randomSeed(currentTime);
  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print(F("DSGMTV"), CENTER, 20); //Выпьем
  // Рандом - 1
  switch (random(11)) {
    case 0:
      myOLED.print(F("PF LHEPTQ!"), CENTER, 40); //За друзей
      break;
    case 1:
      myOLED.print(F("PF VBKS{ LFV!"), CENTER, 40); //За милых дам
      break;
    case 2:
      myOLED.print(F("PF PLJHJDMT!"), CENTER, 40); //За здоровье
      break;
    case 3:
      myOLED.print(F("PF ELFXE!"), CENTER, 40); //За удачу
      break;
    case 4:
      myOLED.print(F("PF VBH DJ DCTV VBHT!"), CENTER, 40); //За мир во всем мире
      break;
    case 5:
      myOLED.print(F("PF NT{ RNJ D VJHT!"), CENTER, 40); //За тех кто в море
      break;
    case 6:
      myOLED.print(F("PF K><JDM !"), CENTER, 40); //За любовь !
      break;
    case 7:
      myOLED.print(F("PF RHFCJNE !"), CENTER, 40); //За красоту !
      break;
    case 8:
      myOLED.print(F("PF DTPTYBT !"), CENTER, 40); //За везение !
      break;
    case 9:
      myOLED.print(F("PF HJLBYE !"), CENTER, 40); //За родину !
      break;
    case 10:
      myOLED.print(F("PF YFC C DFVB"), CENTER, 38); //За нас с вами
      myOLED.print(F("B {HTY C YBVB !"), CENTER, 55); //И хрен с ними
      break;

  }
  myOLED.update();

}

// Меню Авто режим
void oled_auto(int Drink) {

  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print(F("F D N J"), CENTER, 0);
  myOLED.print(F("VK   "), RIGHT, 27);
  DrinkInfo(57);
  //  myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57);
  myOLED.setFont(MegaNumbers);
  myOLED.print(String(Drink), CENTER, 13);
  myOLED.update();
}

// Меню Ручной режим
void oled_manual(int DrinkCount, int Drink) {

  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print(F("H E X Y J Q"), CENTER, 0);
  DrinkInfo(57);
  // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57);
  myOLED.print(F("H>V"), 24, 27);
  myOLED.print(F("VK "), RIGHT, 27);
  myOLED.setFont(MegaNumbers);
  myOLED.print(String(DrinkCount), LEFT, 13);
  myOLED.print(String(Drink), (Drink < 10) ? 80 : 57, 13);
  myOLED.update();
}


void oled_naliv(int MenuFlag) {
  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0);

  myOLED.print(F("Y F K B D F > "), CENTER, 27);
  DrinkInfo(47);
  myOLED.update();
}

void oled_nalito(int MenuFlag, int Nalito) {
  myOLED.clrScr();
  myOLED.setFont(RusFont);
  myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0);
  myOLED.print(F("Y F K B N J"), CENTER, 20);
  if (Nalito == 1) {
    myOLED.print(F("H > V R F"), CENTER, 55);
  } else if (Nalito <= 4 ) {
    myOLED.print(F("H > V R B"), CENTER, 55);
  } else {
    myOLED.print(F("H > V J R"), CENTER, 55);
  }

  myOLED.setFont(SmallFont);
  myOLED.print(String(Nalito), CENTER, 36);
  myOLED.update();
}

void ServoNaliv(byte rumka) {
  servo.attach(PIN_SERVO);
  for (int pos = servo.read(); pos <= Rumka_pos[rumka]; pos += 1) { 
    // с шагом в 1 градус
    servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos'
    delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию
  }
  servo.detach();


}

void ServoParking () {
  //Serial.println(servo.read());
  servo.attach(PIN_SERVO);
  for (int pos = servo.read();  pos >= 0; pos -= 1) {
    // с шагом в 1 градус
    servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos'
    delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию
  }
  servo.detach();
}

void CvetoMuzik() {
  for (int i = 0; i <= 7; i++) {
    for (int y = 0; y < max_DrinkCount; y++) {
      strip.setPixelColor(y, strip.Color(255, 0, 0));
      strip.show();
      delay(30);
    }
    for (int y = 0; y < max_DrinkCount; y++) {
      strip.setPixelColor(y, strip.Color(0, 255, 0));
      strip.show();
      delay(30);
    }
    for (int y = 0; y < max_DrinkCount; y++) {
      strip.setPixelColor(y, strip.Color(0, 0, 255));
      strip.show();
      delay(30);
    }
  }
}

void setup()  {
  //Serial.begin(9600);
  //  servo.attach(PIN_SERVO);
  pinMode(pin_SW, INPUT); // устанавливаем pin pin_SW как вход
  digitalWrite(pin_SW, HIGH); // Поддяжка вывода к 1
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  pinMode(PIN_PUMP, OUTPUT);
  digitalWrite(PIN_PUMP, 0);
  currentTime = millis();
  loopTime = currentTime;
  //   Volume=EEPROM.read(0);
  myOLED.begin();
  oled_menu(0);
  strip.begin();
  for (int i = 0; i < 5; i++) {
    pinMode(Optics[i], INPUT);
  }
  ServoParking();



}

void loop()  {
  currentTime = millis();
  if (currentTime >= (loopTime + 5)) { // проверяем каждые 5мс

    //     int  val = analogRead(0);     // считываем значение
    //  Serial.println(val);
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода B энкодера
    if ((!encoder_A) && (encoder_A_prev)) {  // если состояние изменилось с положительного к нулю

      //Вращение влево
      if (encoder_B) {
        if (MenuFlag == 0) {
          (Menu <= 0 ) ? Menu = 2 : Menu--; // Перемещение курсора по главному меню назад
          oled_menu(Menu);
        } else if (MenuFlag == 1) {
          (Drink <= 2 ) ? Drink = max_Drink : Drink--; // Уменьшаем кол-во милилитров в рюмку
          oled_auto(Drink);
        } else if (MenuFlag == 2) {
          (DrinkCount >= max_DrinkCount ) ? DrinkCount = 1 : DrinkCount++; // Влево увечичиваем рюмки для ручного режима
          oled_manual(DrinkCount, Drink);
        }
        //Вращение вправо
      } else {
        if (MenuFlag == 0) {
          (Menu >= 2 ) ? Menu = 0 : Menu++; // Перемещение курсора по главному меню вперед.
          oled_menu(Menu);
        } else if (MenuFlag == 1) {
          (Drink >= max_Drink ) ? Drink = 2 : Drink++;
          oled_auto(Drink);
        } else if (MenuFlag == 2) {
          (Drink >= max_Drink ) ? Drink = 2 : Drink++;
          oled_manual(DrinkCount, Drink);
        }
      }

    }

    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла

    int encoder_sw = digitalRead(pin_SW);
    if  (encoder_sw == 0 && encoder_sw != encoder_sw_prew)  { // Нажата кнопка

      int pause_sw = 0;
      boolean promivka = false;
      while (digitalRead(pin_SW) == 0) { // Держим кнопку. Считаем сколько времени прошло...
        delay(100);
        pause_sw++;
        if (pause_sw > 20 && Menu != 2 ) break;

        if (pause_sw > 20 && Menu == 2 && promivka == false) { // Если пункт меню промывка и держим кнопку больше 2 секунд.
          promivka = true;
          pump_enable(); // Включаем насос
          myOLED.clrScr();
          myOLED.setFont(RusFont);
          myOLED.print(F("G H J V S D R F"), CENTER, 15);
          myOLED.print(F(". . ."), CENTER, 45);
          myOLED.update();
        }
      }

      //После отпускания кнопки , обрабатываем
      if (promivka == true) { //Отпустили кнопку. Если включена промывка, выключаем насос и возвращаемся в главное меню
        promivka = false;
        pump_disable() ; //Выключаем насос
        oled_menu(2);

      } else {
        //Обработка всех нажатий кнопки
        if (Menu == 0 && MenuFlag == 0 &&  pause_sw < 10) { //Нажатие кнопки меню авто
          MenuFlag = 1;
          oled_auto(Drink);
        } else if (MenuFlag == 1 && pause_sw > 20) { //Выход из меню авто в главное
          MenuFlag = 0;
          oled_menu(0);
        } else if (MenuFlag == 1 ) { //Начинается автоматический разлив
          Serial.println("Начало автоматического разлива");
          oled_naliv(MenuFlag); // Выводим на экран наливаем ...
          byte drink_count = 0;
          for (int y = 0; y < max_DrinkCount; y++) {
            if (analogRead(Optics[y]) > 1000 ) {
              strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом
              strip.show();
              ServoNaliv(y); // Перемещяемся к рюмке
              pump_timer(Drink); // Налив.
              strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито.
              strip.show();
              drink_count++;
            }
          }
          if (drink_count > 0) {
            oled_nalito(MenuFlag, drink_count );
            ServoParking();
            delay(1000);
            Tost();
            CvetoMuzik();
            oled_auto(Drink);
          } else {
            myOLED.clrScr();
            myOLED.setFont(RusFont);
            myOLED.print(F("YTN H>VJR !"), CENTER, 25);
            myOLED.update();
            delay(2000);
            oled_auto(Drink);

          }
        } else if (Menu == 1 && MenuFlag == 0 &&  pause_sw < 10) { // Нажатие меню ручное
          MenuFlag = 2;
          oled_manual(DrinkCount, Drink);
        } else if (MenuFlag == 2 && pause_sw > 20) { //Выход из меню ручное в главное
          MenuFlag = 0;
          oled_menu(1);
        } else if (MenuFlag == 2 ) { //Начинается ручной разлив
          //  Serial.println("Начало ручного разлива " + String(DrinkCount));
          oled_naliv(MenuFlag); // Выводим на экран наливаем ...
          for (int y = 0; y < DrinkCount; y++) {
            strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом
            strip.show();
            ServoNaliv(y); // Перемещяемся к рюмке
            pump_timer(Drink); // Налив.
            strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито.
            strip.show();
          }
          oled_nalito(MenuFlag, DrinkCount );
          ServoParking();
          Tost();
          CvetoMuzik();
          oled_manual(DrinkCount, Drink);
        }
      }
    }

    if (currentTime >= (ledTime + 300)) {
      //Опрашиваем оптопары ... Если рюмка поставлена , светодиод светится синим, нет ничего - не светится
      for (int i = 0; i < max_DrinkCount; i++) {
        
        int val = analogRead(Optics[i]);     // считываем значение
        Serial.println(val);
        if (val > 1000) {
          strip.setPixelColor(i, strip.Color(0, 0, 255));
        } else {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
    //    delay(20);

      }
      strip.show();
      ledTime = currentTime;
    }
    encoder_sw_prew = encoder_sw;
    loopTime = currentTime;

  }
}

 

Sentiurev
Offline
Зарегистрирован: 01.08.2019

Корпус кто-нибудь из дерева вырезал?

Viblis
Offline
Зарегистрирован: 04.11.2016

У меня, на фотках выше из фанеры, на 4-ре рюмки 

 

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Sentiurev пишет:

Корпус кто-нибудь из дерева вырезал?

Завтра сфоткаю заготовку на 5 рюмок,("из спичек   и желудей"). Причешу и позже чертежи в Визио выложу.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

stpavel, спасибо, + в карму.

Viblis
Offline
Зарегистрирован: 04.11.2016

Я думаю в конструкцию стекло добавить и держатель для бутылки

Viblis
Offline
Зарегистрирован: 04.11.2016

Я думаю в конструкцию стекло добавить и держатель для бутылки

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Viblis пишет:

Я думаю в конструкцию стекло добавить и держатель для бутылки

Стекло на поверхность?

Держатели для бутылок из нержавейки в хозяйственных видел.

Viblis
Offline
Зарегистрирован: 04.11.2016

Да, верх из стекла, а бутылку вот такую купил, для масла, в Максидоме:

Но возможно из нее только пробка понадобиться

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

кто подскажет, что за зверь из ссылки выше

1х3, 2х4 ,3х5 мне понятно, а это что и чем отличается ?

Viblis
Offline
Зарегистрирован: 04.11.2016

xDriver пишет:

кто подскажет, что за зверь из ссылки выше

1х3, 2х4 ,3х5 мне понятно, а это что и чем отличается ?

Насколько я понимаю это материал трубок (silicon\BPT), вот тут лучше описано:

https://ru.aliexpress.com/item/32818705101.html?scm=1007.23534.124000.0&...

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Viblis пишет:

xDriver пишет:

кто подскажет, что за зверь из ссылки выше

1х3, 2х4 ,3х5 мне понятно, а это что и чем отличается ?

Насколько я понимаю это материал трубок (silicon\BPT), вот тут лучше описано:

https://ru.aliexpress.com/item/32818705101.html?scm=1007.23534.124000.0&...

 

да, понял. сенкс.

atom23rus
Offline
Зарегистрирован: 06.08.2019

я буду на 3д принтере печатать. позже выложу задумку.

atom23rus
Offline
Зарегистрирован: 06.08.2019

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

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

stpavel, вопрос, в функции "myOLED.print(F("F D N J"), CENTER, 15)", что означает- F ? -  , в описании библиотеки не нашел и в чем отличие от myOLED.print("F D N J", CENTER, 15)?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

И ещё коллеги, кто посоветует как лучше организовать питание:

1. два лития 3,7В  2200А в паралель с зарядкой 1А + повышающий до 5В;

2. два лития 3,7В  2200А последовательно с балансиром зарядки на 2 ака + понижающий до 5В;

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Forthomo пишет:

stpavel, вопрос, в функции "myOLED.print(F("F D N J"), CENTER, 15)", что означает- F ? -  , в описании библиотеки не нашел и в чем отличие от myOLED.print("F D N J", CENTER, 15)?

Макрос F()

Когда используется выражение типа

1
Serial.print("Write something on the Serial Monitor");

строка, которая выводится на печать, хранится в оперативной памяти. Если ваш скет печатает много всего в монитор порта, можно очень легко переполнить оперативную память. Если у вас есть свободное место во флеше, то вы можете поместить строку в него, используя макрос F() следующим образом:

1
Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Forthomo пишет:

И ещё коллеги, кто посоветует как лучше организовать питание:

1. два лития 3,7В  2200А в паралель с зарядкой 1А + повышающий до 5В;

2. два лития 3,7В  2200А последовательно с балансиром зарядки на 2 ака + понижающий до 5В;

смотря на каких DC-DC собирать, я бы выбрал 2 вариант.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Концепт такой, верхняя панель береза (фанера) выбеленная, боковые дошечки от импортных ящиков для фруктов (в субботу на нке возьму) обклеенные самоклейкой "венге". На фото заготовка.

Выглядеть должно как УСЬ.

 

 

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

xDriver пишет:

смотря на каких DC-DC собирать, я бы выбрал 2 вариант.

 Спасибо, + + в карму!Второй так второй. КПД китайских преобразователей  практически равный, насос 385 при питании 5В потребляет 150мА, 50 мЛ наливает в среднем за 5,5 сек.

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

stpavel, вопрос, в функции "myOLED.print(F("F D N J"), CENTER, 15)", что означает- F ? -  , в описании библиотеки не нашел и в чем отличие от myOLED.print("F D N J", CENTER, 15)?

Да, как тут уже написали чуть выше, макрос F переносит строку во флеш память, позволяет здорово сэкономить оперативную память . Без его использования, при компиляции скетча, ардуино IDE материлось бы на то что оперативной памяти осталось очень мало . 

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Век живи - век учись. А все равно дураком помрешь! (шутка такая)

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

stpavel, проверь этот код. Хочется что бы наливатор мог говорить.

#include <SoftwareSerial.h>//добавляем библиотеки
#include <DFPlayer_Mini_Mp3.h>//добавляем библиотеки

//добавляем в блок void setup
	//Serial.begin(9600);//
	//mp3_set_serial (Serial);//set Serial for DFPlayer-mini mp3 module 
	//delay (100);Между двумя командами необходимо делать задержку 100 миллисекунд, в противном случае некоторые команды могут работать не стабильно.
	//mp3_set_volume (20); устанвливаем громкость 20
	//delay (100);
//КУДА ЗАБРОСИТЬ ЭТОТ БЛОК?
// выводим привествие после включения перед наливом
    myOLED.clrScr();  
    myOLED.setFont(RusFont);
	myOLED.print(F("Ye? yfxfkb!"), CENTER, 50);// Ну, начали!
	myOLED.update(); 
// и озвучиваем
	mp3_set_volume (28);// устанвливаем громкость 28 (0_30)
	delay (100);
	mp3_play (1); // Проигрываем "mp3/0001.mp3"(0001_get started!.mp3)
	mp3_stop (1); // остановить воспроизведение
	mp3_set_volume (20);// устанвливаем громкость 20 (0_30)
	delay (2000); //ждем 2 секунды

Рандом пока причесываю.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Forthomo пишет:

stpavel, проверь этот код. Хочется что бы наливатор мог говорить.

И чтоб, чем больше наливает, тем бессвязнее речь. Так будет в лучших традициях капреализьма. 

 

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

stpavel, проверь этот код. Хочется что бы наливатор мог говорить.

#include <SoftwareSerial.h>//добавляем библиотеки
#include <DFPlayer_Mini_Mp3.h>//добавляем библиотеки

//добавляем в блок void setup
	//Serial.begin(9600);//
	//mp3_set_serial (Serial);//set Serial for DFPlayer-mini mp3 module 
	//delay (100);Между двумя командами необходимо делать задержку 100 миллисекунд, в противном случае некоторые команды могут работать не стабильно.
	//mp3_set_volume (20); устанвливаем громкость 20
	//delay (100);
//КУДА ЗАБРОСИТЬ ЭТОТ БЛОК?
// выводим привествие после включения перед наливом
    myOLED.clrScr();  
    myOLED.setFont(RusFont);
	myOLED.print(F("Ye? yfxfkb!"), CENTER, 50);// Ну, начали!
	myOLED.update(); 
// и озвучиваем
	mp3_set_volume (28);// устанвливаем громкость 28 (0_30)
	delay (100);
	mp3_play (1); // Проигрываем "mp3/0001.mp3"(0001_get started!.mp3)
	mp3_stop (1); // остановить воспроизведение
	mp3_set_volume (20);// устанвливаем громкость 20 (0_30)
	delay (2000); //ждем 2 секунды

Рандом пока причесываю.

У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()

Что бы писал "Ну начали" перед наливом , можно засунуть в процедуру oled_naliv.

atom23rus
Offline
Зарегистрирован: 06.08.2019

Парни, а подскажите как откалибровать насос?