Arduino Polska Forum
Dozownik cieczy - Wersja do druku

+- Arduino Polska Forum (https://forum.arduinopolska.pl)
+-- Dział: Korzystanie z Arduino (https://forum.arduinopolska.pl/dzial-korzystanie-z-arduino)
+--- Dział: Silniki, Mechanika i Zasilanie (https://forum.arduinopolska.pl/dzial-silniki-mechanika-i-zasilanie)
+--- Wątek: Dozownik cieczy (/watek-dozownik-cieczy)



Dozownik cieczy - tanderer - 23-02-2017

Witajcie,
Od jakiegoś czasu pracuję nad dozownikiem cieczy, na który składa się zawór obrotowy napędzany przez silnik krokowy oraz pompy perystaltycznej napędzanej silnikiem DC. Kontrola silnika krokowego jest realizowana za pośrednictwem modułu Pololu A4988 i biblioteki AccelStepper ( http://www.airspayce.com/mikem/arduino/AccelStepper/ ), natomiast za sterowanie obrotami silnika DC odpowiada moduł Pololu MAX14870. Oczywiście nad wszystkim czuwa Arduino UNO. Zasada działania takiego urzadzenia jest dość prosta: obracajacy się silnik DC napędza pompę, która zasysa jeden z siedmiu roztworów, natomiast o tym, który to jest roztwór decyduje pozycja w jakiej znajduje się silnik krokowy (wiem,że to trochę ciężko sobie wyobrazić bez zdjęcia pogladowego, ale pozwólcie, że takowe zamieszczę gdy już wszystko będzie gotowe, bo sa tam jeszcze dodatkowe elementy jak czujniki temperatury, moduł bluetooth czy wyświetlacz oled, dlatego tym razem skupię sie tylko na sterowaniu mechanika). Wszystko działa bez problemu gdy ręcznie steruje poszczególnymi elementami. Tzn. przez serial wysyłam symbol 'c' i silnik krokowy ustawia się w pozycji 1, wysyłam 'd' i silnik ustawia się w pozycji 2 itd. Problem pojawia się gdy piszę kot, w którym urzdzenie bedzie pracowała w sposób autonomiczny. Tzn. wysyłam symbol 'a' i urzadzenie rozpoczyna pracę. Najpierw silnik krokowy ustawia się w pozycji 1 a po upływie pewnego czasu przechodzi do pozycji 2 itd. Wstępnie jest to zrealizowane za pomoc delay() więc jak już wystartuje, to zatrzymać go można tylko poprzez reset, a chciałbym mieć możliwość przerwania takiego programu np. poprzez wysłanie symbolu 'b'. Rozważałem możliwość użycia jednej spośród sekstyliarda dostepnych bibliotek typu Tiamer, ale możliwość ich użycia w projekcie innym niż miganie dioda nie jest dla mnie do końca zrozumiałe. Może ktoś z was wie jak to zastosować w moim projekcie, ewentualnie zna podobne projekty, o których mógłbym sobie poczytać?
Całość kodu prezentuje się następujaco:


Kod:
#include <AccelStepper.h>

int motorPin = 11;
int dirPin = 12;
int motorDirPin = 7;
int motorStepPin = 6;

AccelStepper stepper(1, motorStepPin, motorDirPin);  


void setup()
{  
  pinMode(motorPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  stepper.setMaxSpeed(9600.0);
  stepper.setAcceleration(10000.0);
  Serial.begin(9600);
  }

void loop(){


if(Serial.available() > 0){     
     }

if (Serial.read() == 'a') {   
  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(0);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(10 * 1000);             //T1

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(256);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(12 * 1000);             //T2

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(512);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(15 * 1000);             //T3

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(768);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(20 * 1000);             //T4

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(1024);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(23 * 1000);             //T5

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(1280);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(25 * 1000);              //T6

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(1536);
  delay(60000);
  analogWrite(motorPin, 0);
  delay(27 * 1000);               //T7

  digitalWrite(dirPin, HIGH);
  analogWrite(motorPin, 244);
  delay(2000);
  stepper.runToNewPosition(0);
  delay(60000);
  analogWrite(motorPin, 0);
   
}
   
if (Serial.read() == 'b') {
  stepper.runToNewPosition(0);
  analogWrite(motorPin, 0);
  }
 
 }


Chodzi mi głównie o wyeliminowanie delay() zaznaczonych komentarzami T1, T2 do T7, bo w ostatecznym projekcie będa liczone w godzinach.

Z góry dziękuję za wasza pomoc i przepraszam za ewentualne błędy z mojej strony, ale kultura i zwyczaje na forum nie sa dla mnie jeszcze dobrze znane.

Pozdrawiam,


RE: Dozownik cieczy - namok - 23-02-2017

To co potrzebujesz zrobisz bez problemu z użyciem millis() i switch .. case. Tu: http://forum.arduinopolska.com/watek-skrzyżowanie-z-przejściami-dla-pieszych?pid=5195#pid5195 próbowałem gościa czegoś nauczyć ale nie skorzystał. Przeczytaj i jak będziesz miał pytania to pisz ale najpierw zapoznaj się ze wszystkimi postawowymi poleceniami bo inaczej to będzie rozmowa ze ścianą.


RE: Dozownik cieczy - tanderer - 27-02-2017

(23-02-2017, 15:31)namok napisał(a): To co potrzebujesz zrobisz bez problemu z użyciem millis() i switch .. case. Tu: http://forum.arduinopolska.com/watek-skrzyżowanie-z-przejściami-dla-pieszych?pid=5195#pid5195 próbowałem gościa czegoś nauczyć ale nie skorzystał. Przeczytaj i jak będziesz miał pytania to pisz ale najpierw zapoznaj się ze wszystkimi postawowymi poleceniami bo inaczej to będzie rozmowa ze ścianą.

Dzięki za nakierowanie, chociaż z tym "bez problemu" to się nie zgodzę. Przejrzałem wątki, w których to tłumaczyłeś, ale nadal nie do końca wiem jak to użyć. Zwróciłem też uwagę na bibliotekę leOS 2, o której albo Ty wspomniałeś, albo ktoś z kim dyskutowałeś. Ale z tą biblioteką nie najlepiej to działa. A wracając do switch case i millis, to nie rozumiem co ma być użyte jako zmienna w switch. Większość przykładów które widziałem jako zmienną używają symbol otrzymywany przez serial, ale w moim przypadku całą lawinę zdarzeń ma zapoczątkować otrzymanie jednego konkretnego symbolu. Wydaje mi się, że w tym przypadku najlepiej byłoby użyć zmiennej w postaci (currentMillis - previousMillis >= interval), ale to sie nie kompiluje. Możliwe, a nawet na pewno brakuje mi doświadczenia żeby wyciągnąć jakieś przydatne dla mnie wnioski z przykładów, które przeglądałem.

p.s. Przepraszam, że odpisuję ze sporym poślizgiem, ale zanim odpiszę staram się to sprawdzić i popróbować. Nie mniej informuję już z góry, że każdą sugestie i pomoc jestem bardzo wdzięczny.


RE: Dozownik cieczy - namok - 27-02-2017

(27-02-2017, 22:18)tanderer napisał(a): Wydaje mi się, że w tym przypadku najlepiej byłoby użyć zmiennej w postaci (currentMillis - previousMillis >= interval), ale to sie nie kompiluje.

Taki kod na pewno się nie skompiluje. Wklej coś co można przeanalizować.


RE: Dozownik cieczy - tanderer - 28-02-2017

(27-02-2017, 23:59)namok napisał(a):
(27-02-2017, 22:18)tanderer napisał(a): Wydaje mi się, że w tym przypadku najlepiej byłoby użyć zmiennej w postaci (currentMillis - previousMillis >= interval), ale to sie nie kompiluje.

Taki kod na pewno się nie skompiluje. Wklej coś co można przeanalizować.

Tak, bo sugerowałem się trochę tym: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay/
i próbowałem coś takiego:
Kod:
#include <AccelStepper.h>

unsigned long previousMillis = 0;
unsigned long val = (millis() - previousMillis);

int motorPin = 11;
int dirPin = 12;
int motorDirPin = 7;
int motorStepPin = 6;
AccelStepper stepper(1, motorStepPin, motorDirPin);  

void setup()
{  
  pinMode(motorPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  stepper.setMaxSpeed(9600.0);
  stepper.setAcceleration(10000.0);
  Serial.begin(9600);
}

void loop(){
 
if(Serial.available() > 0){     
   }

if (Serial.read() == 'z') {   
  switch (val) {
    case '1000':
      digitalWrite(dirPin, HIGH);
      analogWrite(motorPin, 244);
      delay(2000);
      stepper.runToNewPosition(0);
      delay(6000);
      analogWrite(motorPin, 0);
      break;
   
    case '19000':
      digitalWrite(dirPin, HIGH);
      analogWrite(motorPin, 244);
      delay(2000);
      stepper.runToNewPosition(256);
      delay(6000);
      analogWrite(motorPin, 0);
      break;

    case '29000':
      digitalWrite(dirPin, HIGH);
      analogWrite(motorPin, 244);
      delay(2000);
      stepper.runToNewPosition(512);
      delay(6000);
      analogWrite(motorPin, 0);
      break;

    case '41000':
      digitalWrite(dirPin, HIGH);
      analogWrite(motorPin, 244);
      delay(2000);
      stepper.runToNewPosition(768);
      delay(6000);
      analogWrite(motorPin, 0);
      break;

    case '56000':
      digitalWrite(dirPin, HIGH);
      analogWrite(motorPin, 244);
      delay(2000);
      stepper.runToNewPosition(1024);
      delay(6000);
      analogWrite(motorPin, 0);
      break;

    }
  }
}

to oczywiście tylko pomysł, który zresztą i tak się nie kompiluje Sad


[url=https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay/][/url]


RE: Dozownik cieczy - Smaczek - 28-02-2017

Witam,
Dwie rzeczy:
- w pętli loop musisz zapisywać do zmiennej val wartość, gdyż w powyższym kodzie wartość masz przypisywaną jedynie w linijce jej deklaracji,
- jeśli val jest typu unsigned long to wartości podawane za case muszą być bez apostrofów.
Pozdrawiam.


RE: Dozownik cieczy - tanderer - 28-02-2017

(28-02-2017, 08:25)Smaczek napisał(a): Witam,
Dwie rzeczy:
- w pętli loop musisz zapisywać do zmiennej val wartość, gdyż w powyższym kodzie wartość masz przypisywaną jedynie  w linijce jej deklaracji,
- jeśli val jest typu unsigned long to wartości podawane za case muszą być bez apostrofów.
Pozdrawiam.

Tymczasowo wyrzuciłem komendy odpowiedzialne za obsługę silników tylko żeby było to szybsze do odczytania:

Kod:
unsigned long previousMillis = 0;
int odczyt;


void setup()
{  
  Serial.begin(9600);
}


void loop(){
 
unsigned long val = (millis() - previousMillis);

if(Serial.available() > 0){     
     odczyt = Serial.read();}

if (odczyt == 'z') {   

  switch (val) {
    
    case 1000:
      Serial.println("CASE1");
      break;
   
    case 10000:
      Serial.println("CASE2");
      break;

    case 20000:
      Serial.println("CASE3");
      break;

    case 30000:
      Serial.println("CASE4");
      break;

    case 40000:
      Serial.println("CASE5");
      break;
    case 50000:
      Serial.println("CASE6");
      break;

    }
  }
}

Oczywiście ten kod się kompiluje i nawet coś działa, ale chyba nie do końca zgodnie z moim zamiarem, bo po wysłaniu 'z' do arduino, po 4 sekundach 10 razy wyświetla się 'CASE2', po 14 sekundach 10 razy 'CASE3' i tak dalej w odstępach 10 sekundowych kolejne, oprócz 'CASE1'.
Ale gdy na końcu pętli loop dodam delay(500); to po 20 sekundach wyświetla się 'CASE4', po kolejnych 10 sekundach 'CASE5' i po kolejnych 10 'CASE6' tym razem pojedynczo. To już lepiej, ale brakuje początku (CASE1, 2 i 3). Nie bardzo rozumiem dlaczego tak to działa?


RE: Dozownik cieczy - namok - 28-02-2017

Obecnie val = millis();
Pierwszego warunku "case 1000" nigdy nie złapiesz(w tak napisanym programie) bo millis już miał taką wartość(po jednej sekundzie od startu programu) nim wysłałeś "z".
millis = 10000 trwa przez jedną milisekundę!!! Dla następnych wartości też. Dla procesora taktowanego zegarem 16MHz to dużo. Dlatego masz kilka transmisji.
Taki program najlepiej sprawdzić na symulatyorze: https://www.sites.google.com/site/unoardusim/home