Рулетка наливатора

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Привет. Опять я из топика по наливатору http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam :)) 

Скетч, допустим, этот http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam?page=8#comment-481135 просто вставлено еще пара меню и прочее. Суть вопроса вот в чем

Рулетка есть такая

      // Рулетка
    else if (Rezim == 2 && MenuFlag == 1 && pause_sw < 10) { //вход в рулетку
          MenuFlag = 6;
          oled_rul(DrinkCount, Drink);
    } else if (MenuFlag == 6 && pause_sw > 20) { //Выход из меню рулетки в режимы
          MenuFlag = 1;
          oled_rezim(2);
    } else if (MenuFlag == 6 ) {  // запуск рулетки

          myDFPlayer.volume(vol_tost); 
          delay (100);
          myDFPlayer.playFolder (1, 105); 
          delay (1000);
          CvetoMuzik();
          delay (2000);
      for (int y = 0; y <= 4; y++) {
          strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом все рюмки
          strip.show();
}
          servo.attach(PIN_SERVO);// серва туды сюды
      for (int pos = servo.read(); pos <= 180; pos += 1) {
          servo.write(pos);   
          delay(servo_speed); 
}
      for (int pos = servo.read();  pos >= 0; pos -= 1) {
          servo.write(pos);   
          delay(servo_speed); 
}

     int r = random(0, 5);       //рюмка в которую не нальёт
      for (int y = 0; y < 5; y++) {
        if (y != r) {
          ServoNaliv(y); // Перемещяемся к рюмке
          delay (300); //Задержка перед наливом после поворота к рюмке
          pump_timer(Drink, Optics[y]); // Налив.
          delay(1000);
          strip.setPixelColor(y, strip.Color(0, 255, 0)); // Налито.
          strip.show();
          delay(500);
  }
        else { (y=r);
 }
}
         
          servo.detach();
          ServoParking();
          myDFPlayer.volume(vol_tost);  
          delay (100);
          myDFPlayer.playFolder (1, 102);
          delay (3000);
          Tost();
          CvetoMuzik();
          oled_rul(DrinkCount, Drink);
    }

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

Если делать так, по аналогии с авто разливом, то да, льет в только поставленные, но не выбирает из них, а думает что их пять. Где я туплю? При изменении max в int r = random(0, 5); начинает просто пропускать первую рюмку... Постоянно...

byte drink_count = 0;
     int r = random(0, 5);       //рюмка в которую не нальёт
      for (int y = 0; y < 5; y++) {
        if (analogRead(Optics[y]) < Optics_porog[y] ) {
        if (y != r) {
          ServoNaliv(y); // Перемещяемся к рюмке
          delay (300); //Задержка перед наливом после поворота к рюмке
          pump_timer(Drink, Optics[y]); // Налив.
          delay(1000);
          strip.setPixelColor(y, strip.Color(0, 255, 0)); // Налито.
          strip.show();
          drink_count++;
          delay(500);
  }
        else { (y=r);
  }
 }
}

Подтолкнете на умную мыслю? 

 

З.Ы. В том топике спросил. Молчат :)) После того как многие встали на коммерческие рельсы, так помощи почти нет :(( А разобраться в работе хочется для, так сказать, увеличения кругозора. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А Вы попытайтесь вывести r на серийный порт. Там скорее всего 1. Рандом не очень рандомный.

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Этот рандом, на сколь уже понял, сам по себе не очень. Тут просто хочется понять как сделать... В целом, так сказать, даже с этим рандомом.

А в сериал попробую. С командировки вернусь только.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Gridzilla пишет:
Этот рандом, на сколь уже понял, сам по себе не очень.

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

uint32_t seed = sec + 60UL * (min + hour * 60UL);
randomSeed(seed);

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

В топике про "наливатор" , адекватных разработчиков нет в принципе.
Ибо проект сам по себе слишком элементарный.
И при правильном подходе весь текущий вопрос сведётся к функции типа:
void randomnii_naliv(){
doza=random(min,max);
Naliv(doza);
}

Kakmyc
Offline
Зарегистрирован: 15.01.2018
//программа разливочного аппарата

//==========БИБЛИОТЕКИ===========
#include <EEPROM.h>
#include <TM1637.h>
#include <AccelStepper.h>
#include <Adafruit_NeoPixel.h>
#include <Arduino.h>
#include <kakmyc_btn.h>
#include <avr/interrupt.h>

//==========КОНСТАНТЫ============
#define BUGFIX
#define ZERO_POSITION 0
#define STEP2POS1 50 //количество шагов от стартовой позиции до центра первой тары
#define STEP2POS2 100 //от стартовой позиции до центра второй тары
#define STEP2POS3 150 //и тд
#define STEP2POS4 200
#define STEP2POS5 250

#define STEPS_PER_ROUND 48 //количество шагов двигателч на один оборот вала
#define MOTOR_SPEED 120 //скорость об/мин
#define MIN_DOZA 10 //минимальная доза
#define MAX_DOZA 100 //максимальная доза
#define LED_COUNT 5 //количество светодиодов
enum position_state{tare_none,tare_empty,tare_filled};
enum btn_signal{SHORT=1,LONG=255};
enum direction_val{FORWARD,BACK};

/*коофициент заполнения, вычисляется опытным путем его значение умножается на
переменную doza , тем самым высчитывается время включения насоса
*/
#define doza_K 10 
//#define BUGFIX

//константы пинов
#define EncA 2 //пин А энкодера, не менять
#define EncB 3 //пин В энкодера, не менять
#define EncBtn 4 //пин кнопки энкодера 
//пины сенсоров с 1го по 5ый, не менять на них прерывание
#define sensor1 5
#define sensor2 6
#define sensor3 7
#define sensor4 8
#define sensor5 9 

#define limit_switch 10 //пин конечного выключателя

//пины подключения дисплея
#define CLK 11
#define DIO 12

//пины подключения драйвера мотора
#define STEP_PIN A0
#define DIR_PIN A1

#define POMP_PIN A4 //пин ключа насоса
#define LED_PIN A5 //пин подключения управления светодиодами

//==========ОБЪЕКТЫ==============
AccelStepper myStepper(1,STEP_PIN,DIR_PIN);
TM1637 tm1637(CLK,DIO);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT,LED_PIN, NEO_GRB + NEO_KHZ800);
kakmyc_btn ENC_BTN(EncBtn,1,1);

//==========ПЕРЕМЕННЫЕ===========
boolean ready;
boolean cycle_on;
volatile int doza=50;
byte tare_state[5]={0,0,0,0,0};//принимает три значения 0-тары нет,1-тара пустая,2-налито.

uint32_t RED=strip.Color(255,0,0);
uint32_t GREEN=strip.Color(0,255,0);
uint32_t BLUE=strip.Color(0,0,255);
int32_t stepPosition;
byte currentPosition=0;
byte newPosition;
int32_t position_coordinates[6]={ZERO_POSITION,STEP2POS1,STEP2POS2,STEP2POS3,STEP2POS4,STEP2POS5};
int btnState;
long currentCoordinates;
//===========ФУНКЦИИ=============

//вывод на дисплей
void display_out(int16_t value){
    tm1637.display(value);
}
        

//обработчик энкодера
void EncA_ISR(){
    if(ready&&!cycle_on){
        digitalRead(2)==digitalRead(EncB)?doza++:doza--;
               
    if(doza<MIN_DOZA)doza=MIN_DOZA;
    if(doza>MAX_DOZA)doza=MAX_DOZA;
        display_out(doza);
        }    
    }


//опрос датчиков
void check_sensor(){
   for(int i=0;i<5;i++){
if(tare_state[i]!=2){
            tare_state[i]=!digitalRead(i+sensor1);}
    }

}


//промывка
void clean(){
    digitalWrite(POMP_PIN,1);
    delay(500);
    digitalWrite(POMP_PIN,0);
}

//проверка готовности
boolean ready_OK(){
   int val;
    for(int i=sensor1;i<=sensor5;i++){
if(digitalRead(i)==tare_empty)val++;}
    if(val&&!digitalRead(limit_switch))
    return 1;
    else return 0;
}



//рулим двигателем

void step_1(long steps){
    myStepper.run();
}

void goto_position(){
    
}

//на исходную
void goto_home(){
    while(digitalRead(limit_switch)){
        //step_1(-1);
    }
    stepPosition=0;
    currentCoordinates=0;
    ready=ready_OK();
}

//расчет движения
long move_calc(){
   int step=position_coordinates[currentPosition]-position_coordinates[newPosition];
    return step;
}

//опрос кнопки энкодера
void EncoderBtn_check(byte num){
    switch(num){
        
/*при коротком нажатии кнопки, записываем в энергонезависимую память
выставленное значение. И мигаем 3 раза цифрами на дисплее*/        
case SHORT:
EEPROM.update(0,doza);
for(int i=0;i<3;i++){
tm1637.clearDisplay();
delay(200);
display_out(doza);
delay(200);}           
        cycle_on=true;
            break;
        
/*при длинном нажатии кнопки, через 1,5секунды начинается промывка.
завершается после того, как кнопка будет отпущена*/
            case LONG:
while(!digitalRead(EncBtn)){clean();}
            break;
        }//end switch(num)  
    }

//приветствие
void hello(){
    randomSeed(analogRead(A7));
    for (int i=0;i<20;i++){
        for(int j=0;j<5;j++){           strip.setPixelColor(j,random(127),random(127),random(127));
        }
strip.show();
delay(100);
    }
}

//выбор цвета диодов
void indication(){
    for (int i=0;i<5;i++){
        switch (tare_state[i]){
            case tare_none:
        strip.setPixelColor(i,RED);
            break;
            case tare_empty:
        strip.setPixelColor(i,BLUE);
            break;
            case tare_filled:
        strip.setPixelColor(i,GREEN);
            break;
        }
    }
    strip.show();
    
}

//наливание
void filling(int doza){
    if(tare_state[currentPosition-1]==tare_empty){
    digitalWrite(POMP_PIN,1);
    delay(doza*doza_K);
    digitalWrite(POMP_PIN,0);
   delay(500); tare_state[currentPosition-1]=tare_filled;}
    indication();
}

//прерывания по изменению состояния пинов
ISR(PCINT2_vect){
    check_sensor();
    indication();
}
ISR(PCINT0_vect){
    check_sensor();
    indication();
}

//вычисление направления дальнейшего движения
void check_direction(){
     boolean direction_flag=0;
    for(int i=currentPosition;i<=5;i++){
        if(tare_state[i]==tare_empty){
            newPosition=i;
            direction_flag=1;
            break;
        }
    }
    
    if(!direction_flag){
        for(int i=currentPosition;i>0;i--){
if(tare_state[i]==tare_empty){
                newPosition=i;
                break;
            }else newPosition=0;
        }
    }
}

void motor_step(){
    myStepper.runToNewPosition(position_coordinates[newPosition]);
currentPosition=newPosition;
    
}

void GO(){
   //первый шаг цикла, уходим с исходного на позицию 1
     myStepper.runToNewPosition(position_coordinates[1]);
    currentPosition=1;   
    if(tare_state[0]==tare_empty){
        filling(doza);
    }
    
//сам цикл
    while(digitalRead(limit_switch)){
        check_direction();
        motor_step();
        filling(doza);
    }
}

//======================

//установочный цикл
void setup(){
#ifdef BUGFIX
    Serial.begin(9600);
#endif
    
    pinMode(EncA,0x2);
    pinMode(EncB,0x2);
    pinMode(EncBtn,0x2);
if(EEPROM.read(25)!=44){
        EEPROM.write(25, 44);
        EEPROM.put(0,doza);}
else{EEPROM.get(0,doza);}
    
myStepper.setSpeed(MOTOR_SPEED);
    
tm1637.set();
tm1637.init();
pinMode(10,INPUT_PULLUP);
for(int i=A0;i<=A5;i++)pinMode(i,OUTPUT);
    for (int i=sensor1;i<=sensor5;i++)pinMode(i,INPUT_PULLUP);
/*настройка векторов прерывания датчиков
при изменении состояния любого из пинов датчиков
будем их переопрашивать и менять значения,
настраиваем слежение за пинами с 5го по 9ый*/
PCICR=(1<<PCIE0)|(1<<PCIE2);
PCMSK2=(1<<PCINT21)|(1<<PCINT22)|(1<<PCINT23);
PCMSK0=(1<<PCINT0)|(1<<PCINT1);
attachInterrupt(0,EncA_ISR,CHANGE);
strip.begin();
strip.setBrightness(30);
strip.show(); 
display_out(doza);
hello();
check_sensor();
indication();
goto_home();   
    sei();
}

//======================

//основной цикл
void loop(){
    btnState=ENC_BTN.read();
EncoderBtn_check(btnState);
 if(cycle_on&&ready_OK()){
    GO();
}
    
}

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

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Понял, попробую. Спасибо! Осталось по знакомым пошукать, модуль отжать...

Один фиг мне интересно, меняя значения max в random (0, max), почему ж он не выбирает из меньшего количества? Или выбирает, но?.... Но льет всегда в первую...

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Kakmyc пишет:
В топике про "наливатор" , адекватных разработчиков нет в принципе.
Ибо проект сам по себе слишком элементарный.
И при правильном подходе весь текущий вопрос сведётся к функции типа:
void randomnii_naliv(){
doza=random(min,max);
Naliv(doza);
}

Мне, как новичку в этом деле, интересно. Не с проф точки зрения, ибо чтобы этим заниматься надо больше знаний, а на уровне любителя, собрать и чуть для себя подпилить. За наводку спасибо, но можно чуть поподробнее? Если не сложно. И пойду курить мануалы дальше.

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Если вот тут 

byte drink_count = 0;
     int r = random(0, 5);       //рюмка в которую не нальёт
      for (int y = 0; y < 5; y++) {
        if (analogRead(Optics[y]) < Optics_porog[y] ) {
        if (y != r) {
          ServoNaliv(y); // Перемещяемся к рюмке
          delay (300); //Задержка перед наливом после поворота к рюмке
          pump_timer(Drink, Optics[y]); // Налив.
          delay(1000);
          strip.setPixelColor(y, strip.Color(0, 255, 0)); // Налито.
          strip.show();
          drink_count++;
          delay(500);
  }
        else { (y=r);
  }
 }
}

менять  int r = random(0, 5); 5 на 4, 3 и т.д. и ставить такое же количество рюмок, то он льет именно так как надо, выбирает из нужного. То что писал ранее в первом сообщении, что пропускает - более не актуально. 

Как мне привязать этот max в рандоме к количеству поставленных рюмок? Не могу сообразить.  

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Gridzilla пишет:

Если вот тут 

byte drink_count = 0;
     int r = random(0, 5);       //рюмка в которую не нальёт
      for (int y = 0; y < 5; y++) {
        if (analogRead(Optics[y]) < Optics_porog[y] ) {
        if (y != r) {
          ServoNaliv(y); // Перемещяемся к рюмке
          delay (300); //Задержка перед наливом после поворота к рюмке
          pump_timer(Drink, Optics[y]); // Налив.
          delay(1000);
          strip.setPixelColor(y, strip.Color(0, 255, 0)); // Налито.
          strip.show();
          drink_count++;
          delay(500);
  }
        else { (y=r);
  }
 }
}

менять  int r = random(0, 5); 5 на 4, 3 и т.д. и ставить такое же количество рюмок, то он льет именно так как надо, выбирает из нужного. То что писал ранее в первом сообщении, что пропускает - более не актуально. 

Как мне привязать этот max в рандоме к количеству поставленных рюмок? Не могу сообразить.  

Да нету там нормального рандома. Берите с шумящего стабилитрона на аналоговый вход.

Gridzilla
Offline
Зарегистрирован: 25.10.2019

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