Skocz do zawartości

Jak uzyskać powolną pracę serva bez delay.


OLi_m

Pomocna odpowiedź

Kombinuję jak koń pod górkę z napisaniem sterowania do serva. Będzie b. mocne (80kg/cm) i wykonujące część ruchu po maleńku - w przybliżeniu  20st. w ciągu 1-2 minut, resztę szybciej, ale i tak ze 3 razy wolniej od oryginalnej prędkości.

W związku z tym zastosowanie delay między krokami odpada, bo niczego innego w tym czasie procesor nie jest mi w stanie obsłużyć.

Przeszukując internet i literaturę natknąłem się na opracowanie:

https://botland.com.pl/content/226-wielozadaniowosc-arduino-czesc-druga

jest tam przykład sterowania servo w mikrokrokach właśnie bez delay:

#include <Servo.h>
class Flasher {
  // Zmienne składowe klasy
  // Są inicjowane podczas uruchamiania:
  int ledPin;                    // the number of the LED pin
  long OnTime;                   // milliseconds of on-time
  long OffTime;                  // milliseconds of off-time
                                 // Utrzymują one obecny stan
  int ledState;                  // ledState używany do ustawiania diody LED
  unsigned long previousMillis;  // zapisze ostatnią aktualizację diody LED
                                 // Konstruktor - tworzy Flashera
  // i inicjuje zmienne składowe i stan
public:
  Flasher(int pin, long on, long off) {
    ledPin = pin;
    pinMode(ledPin, OUTPUT);
    OnTime = on;
    OffTime = off;
    ledState = LOW;
    previousMillis = 0;
  }
  void Update() {
    // sprawdź, czy nadszedł czas, aby zmienić stan diody LED
    unsigned long currentMillis = millis();

    if ((ledState == HIGH) && (currentMillis - previousMillis >= OnTime)) {
      ledState = LOW;                  // Turn it off
      previousMillis = currentMillis;  // zapamiętuje czas
      digitalWrite(ledPin, ledState);  // Update the actual LED
    } else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime)) {
      ledState = HIGH;                 // turn it on
      previousMillis = currentMillis;  // zapamiętuje czas
      digitalWrite(ledPin, ledState);  // aktualizuje aktualną diodę LED
    }
  }
};
class Sweeper {   //    do serva
  Servo servo;               // the servo
  int pos;                   // aktualna pozycja serwa
  int increment;             // krok do przesunięcia dla każdego interwału
  int updateInterval;        // odstęp między aktualizacjami
  unsigned long lastUpdate;  // ostatnia aktualizacja pozycji
public:
  Sweeper(int interval) {
    updateInterval = interval;
    increment = 1;
  }
  void Attach(int pin) {
    servo.attach(pin);
  }
  void Detach() {
    servo.detach();
  }
  void Update() {
    if ((millis() - lastUpdate) > updateInterval)  // czas na aktualizację
    {
      lastUpdate = millis();
      pos += increment;
      servo.write(pos);
      Serial.println(pos);
      if ((pos >= 180) || (pos <= 0))  // koniec sweep
      {
        // odwrotny kierunek
        increment = -increment;
      }
    }
  }
};


Flasher led1(11, 123, 400);  // nr pin ,  czas on , czas off
Flasher led2(12, 350, 350);
Flasher led3(13, 50, 500);
Sweeper sweeper1(15);        //   odstęp pomiędzy kolejnymi krokami w ms, serva nr 1
Sweeper sweeper2(25);        //   odstęp pomiędzy kolejnymi krokami w ms, serva nr 2

void setup() {
  Serial.begin(9600);
  sweeper1.Attach(9);         // pin serva 1
  sweeper2.Attach(10);
}

void loop() {
  sweeper2.Update();

  if (digitalRead(2) == HIGH) {
    sweeper1.Update();
    led1.Update();
  }
  led2.Update();
  led3.Update();
}

wszystko ładnie mruga, chodzi w tę i z powrotem, problem jest jak chcę to przerobić tak,

żeby mieć pojedyncze ruchy serva w takich mikrokrokach, np. jak na przykładzie poniżej -  0st. i 170st. Obraca się, ale na pełnej prędkości, nie w krokach.

#include <Servo.h>
int buttonPin = 2;    //  pin, na którym znajduje się przycisk
volatile int pos;

class Sweeper {              
  Servo servo;               
//  int pos;                   
  int increment;             
  int updateInterval;        
  unsigned long lastUpdate;  
public:
  Sweeper(int interval, int inc) {
    updateInterval = interval;
    increment = inc;  
  }
  void Attach(int pin) {
    servo.attach(pin);
  }
  void Detach() {
    servo.detach();
  }
  void Update() {

    if ((millis() - lastUpdate) > updateInterval) {
      lastUpdate = millis();
      pos += increment;  //  dodanie increment do aktualnej pozycji
      servo.write(pos);
    }
  }
};  

Sweeper sweeper1(15,1);  //   odstęp pomiędzy kolejnymi krokami w ms,  krok przesunięcia serwa



void setup() {
    pinMode(buttonPin, INPUT);   //  ustawienie pinu jako wejście
  sweeper1.Attach(9);
 
} 

void loop() {

  int buttonState = digitalRead(buttonPin);   //  odczyt stanu przycisku

  if (buttonState == LOW) {   //  jeśli przycisk jest wciśnięty
    pos = 0;                        //  wpisanie jaka ma być docelowa pozycja 
    sweeper1.Update();
  }
  else if (buttonState == HIGH) {   //  jeśli przycisk jest nie wciśnięty
    pos = 170;                      //  wpisanie jaka ma być docelowa pozycja 
    sweeper1.Update();
  }
}

drążąc dalej otrzymałem taką wskazówkę:

Cytat

Wygląda na to, że problem polega na tym, że zmienna 'pos' jest zmienną globalną, a nie zmienną klasy, więc zmienna ta jest modyfikowana przez 'loop' bezpośrednio, a nie przez 'Update' klasy 'Sweeper'. Aby rozwiązać ten problem, należy przekształcić 'pos' w zmienną klasową i dostęp do niej uzyskać przez metodę klasy, np. 'setPos()', a następnie w miejscu gdzie jest ustawiana pozycja serwa należy użyć metody setPos.

Co dało poniższy szkic ( sam bym go nie stworzył , tyle że kapuję o co w nim biega )  i niestety żadnej poprawy w działaniu:

#include <Servo.h>
int buttonPin = 2;    //  pin, na którym znajduje się przycisk

class Sweeper {              
  Servo servo;               
  int pos;                   
  int increment;             
  int updateInterval;        
  unsigned long lastUpdate;  
public:
  Sweeper(int interval, int inc) {
    updateInterval = interval;
    increment = inc;  
  }
  void Attach(int pin) {
    servo.attach(pin);
  }
  void Detach() {
    servo.detach();
  }
  void setPos(int newPos){
    pos = newPos;
  }
  void Update() {

    if ((millis() - lastUpdate) > updateInterval) {
      lastUpdate = millis();
      pos += increment;  
      servo.write(pos);
    }
  }
};  

Sweeper sweeper1(15,1);  //   odstęp pomiędzy kolejnymi krokami w ms, krok przesunięcia serwa


void setup() {
    pinMode(buttonPin, INPUT);   //  ustawienie pinu jako wejście
  sweeper1.Attach(9);
 
} 

void loop() {
  int buttonState = digitalRead(buttonPin);   //  odczyt stanu przycisku

if (buttonState == LOW) {   //  jeśli przycisk jest wciśnięty
    sweeper1.setPos(0);    
    sweeper1.Update();
  }
  else if (buttonState == HIGH) {   //  jeśli przycisk jest nie wciśnięty
    sweeper1.setPos(170);
    sweeper1.Update();
  }

}

Jak to zrobić, żeby działało prawidłowo ( na razie bez zmiennej prędkości - tylko jednostajnie , ale powoli )  ?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Zasilanie oddzielnie , dziwna praca - tak jakby nie kasował całości poprzedniego kodu , mrugał na pół gwizdka w rytm poprzedniego szkicu , ustawiał servo na pozycji z poprzedniego szkicu , ale mega wolno. Nie przejmuję się, w końcu nauka coś tam kosztuje oprócz czasu 🙂

 

Link do komentarza
Share on other sites

(edytowany)

Może przyda się komuś do zabawy:

/*
---------------------------------  LCD Keypad Shield ----------------------------------
*/
#include <Servo.h>
Servo myservo;

#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);;

int keypad_pin = A0;
int keypad_value = 0;
int keypad_value_old = 0;

char btn_push;

byte mainMenuPage = 1;
byte mainMenuPageOld = 1;
byte mainMenuTotal = 6;

int a = 90;                      // ustawienie zmiennej do menu E i F


unsigned long previousMillis = 0;
const long interval = 200;          // czas kroku w ms


void setup()
{
  lcd.begin(16,2);  //Initialize a 2x16 type LCD
  lcd.setCursor(0,0); // Ustawienie kursora w pozycji 0,0 

    Serial.begin(9600);
    MainMenuDisplay();


    myservo.attach(3);
    myservo.write(0);              //   początkowe ustawienie na 0 st.



}
void loop()
{
    btn_push = ReadKeypad();

    MainMenuBtn();

    if(btn_push == 'S')//enter selected menu
    {
        WaitBtnRelease();
        switch (mainMenuPage)
        {
            case 1:
              MenuA();
              break;
            case 2:
              MenuB();
              break;
            case 3:
              MenuC();
              break;
            case 4:
              MenuD();
              break;
            case 5:
              MenuE();
              break;
            case 6:
              MenuF();
              break;                            
        }

          MainMenuDisplay();
          WaitBtnRelease();
    }



    delay(10);

}//--------------- End of loop() loop ---------------------

void MainMenuDisplay()
{
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Wybor menu:");
    lcd.setCursor(1,1);
    switch (mainMenuPage)
    {
        case 1:
          lcd.print("1. Menu A");
          break;
        case 2:
          lcd.print("2. Menu B");
          break;
        case 3:
          lcd.print("3. Menu C");
          break;
        case 4:
          lcd.print("4. Menu D");
          break;
        case 5:
          lcd.print("5. Menu E");
          break;
        case 6:
          lcd.print("6. Menu F");
          break;                    
    }
}

void MenuA()   
{  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu A");
    while(ReadKeypad()!= 'L')  {
       btn_push = ReadKeypad(); 

    }    
}

void MenuB() 
{  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu B");
    while(ReadKeypad()!= 'L')  {
       btn_push = ReadKeypad(); 

    }    
}

void MenuC()
{  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu C");
    while(ReadKeypad()!= 'L')  {
       btn_push = ReadKeypad(); 

    }    
}

void MenuD()
{  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu D");
    while(ReadKeypad()!= 'L')  {
       btn_push = ReadKeypad(); 
       
    }    
}

void MenuE()   // poruszanie servem góra-dół w mikrokrokach z( interval = 200;) + licznik na lcd
{
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu E");
      lcd.setCursor(9,1);
      lcd.print("a = ");
      lcd.setCursor(13,1);
      lcd.println(a); 

    while(ReadKeypad()!= 'L')
    {
      btn_push = ReadKeypad();
      myservo.attach(3);
      myservo.write(a);  // servo ustawia się na wartość zmiennej a 
            lcd.setCursor(13,1);
      lcd.println(a); 

if ( btn_push == 'U') {
    digitalWrite(12, HIGH);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {
        a = a+1;
        previousMillis = currentMillis;
    }
  }
      
if ( btn_push == 'D') {
    digitalWrite(12, LOW);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {
        a = a-1;
        previousMillis = currentMillis;
    }
  }
 }
}

void MenuF()        // poruszanie servem góra-dół w mikrokrokach z( interval = 200;) + licznik na lcd
                    // w granicach / do pozycji wyznaczonych w if-ach
{  
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Menu F");
      lcd.setCursor(9,1);
      lcd.print("a = ");


    while(ReadKeypad()!= 'L')
    {
      btn_push = ReadKeypad();

      myservo.attach(3);

      myservo.write(a);  // servo ustawia się na wartoś zmiennej a 
      
      lcd.setCursor(13,1);
      lcd.println(a); 

if ( btn_push == 'U') {
    digitalWrite(12, HIGH);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {
        
        if (a < 110) {                                      // kąt zatrzymania w st.
          a = a+1;
        }
        previousMillis = currentMillis;
    }
  }
      
if ( btn_push == 'D') {
    digitalWrite(12, LOW);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {
        if (a > 70) {                                     // kąt zatrzymania w st.
          a = a-1;
        }
        previousMillis = currentMillis;
    }
  }
 }
}

//------------------------------------koniec------------------------------------------
void MainMenuBtn()
{
    WaitBtnRelease();
    if(btn_push == 'U')
    {
        mainMenuPage++;
        if(mainMenuPage > mainMenuTotal)
          mainMenuPage = 1;
    }
    else if(btn_push == 'D')
    {
        mainMenuPage--;
        if(mainMenuPage == 0)
          mainMenuPage = mainMenuTotal;    
    }

    if(mainMenuPage != mainMenuPageOld) //aktualizuje wyświetlanie tylko po zmianie strony
    {
        MainMenuDisplay();
        mainMenuPageOld = mainMenuPage;
    }
}

char ReadKeypad()
{
  /* Nic nie wciśnięte - 1023
  select  741
  left    503
  up      326
  down    142
  right   0
  */
  keypad_value = analogRead(keypad_pin);

  if(keypad_value < 100)
    return 'R';
  else if(keypad_value < 200)
    return 'D';
  else if(keypad_value < 400)
    return 'U';
  else if(keypad_value < 600)
    return 'L';
  else if(keypad_value < 800)
    return 'S';
  else
    return 'N';

}

void WaitBtnRelease()
{
    while( analogRead(keypad_pin) < 800){}
}

i  jeszcze coś ze zmiennymi prędkościami:  🙂

if ( btn_push == 'U') {
    digitalWrite(12, HIGH);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {

      if (a >= 0 && a <= 120) {
      interval = 20;
        }
      if (a >= 121 && a <= 150) {
      interval = 200;
        }

      if (a >= 0 && a <= 120) {
      a = a + 1;
        }
      if (a >= 121 && a <= 150) {
      a = a + 1;
        }
      if (a < 150) {                                      // kąt zatrzymania w st.
          a = a;
        }
        previousMillis = currentMillis;
    }
  }
      
if ( btn_push == 'D') {
    digitalWrite(12, LOW);  
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis >= interval) {
        if (a > 0) {                                     // kąt zatrzymania w st.
          a = a-1;
        }
    if (a >= 100 && a <= 150) {
      interval = 100; 
      }
    if (a >= 0 && a <= 100) {
      interval = 15; 
      }
          previousMillis = currentMillis;
    }
   }
  }

 

Edytowano przez OLi_m
uzupełnienie
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.