• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Problem z serwami i losowaniem
#1
Witam,

dopiero co się zarejestrowałem, bo mam problem i proszę bardziej ogarniętych o pomoc.
Dopiero zaczynam, znam podstawy elektroniki ale z programowaniem bardzo słabo.

Chcę napisać program, który porusza serwem w następujący sposób:

-pozycja I serwa (np 10 stopni)
-następnie w tej pozycji serwo pozostaje losowy czas z zakresu powiedzmy 3-15 sekund
-następnie serwo zmienia pozycję o 90 stopni (czyli np. pozycja II 100 stopni)
-serwo pozostaje w pozycji II czas określony potencjometrem w zakresie 0,5-5 sekund
-powrót do pozycji I i od nowa.

Napisałem coś takiego jak poniżej, ale nie pracuje to stabilnie:
(opóźnienia w programie są takie robocze)


- serwo zmienia pozycje o ok 90 stopni ale buczy
-kręcenie potencjometrem chyba nie działa bo nie ma wpływu na opóźnienia które są dziwne 
(pot,środkowy do A1,A2, zewnętrzne GND i 5V, raczej dobre bo sprawdzałem miernikiem)

 UNO SINTRON, zasilane z baterii 9v, serwo przez regulator 7805 ale nie miałem kondensatorów do filtrowania


Kod:
#include <Servo.h> // biblioteka obsługa serwa
Servo serwo; // nazwa serwa

int pos = 10; // pozycja I serwa
int pos2 = 100;// pozycja II serwa
int opoz1 = 0; // opoznienie na pozycji I
int opoz2 = 0; // opoznienie na pozycji II
int pot1 = analogRead(A1); // odczyt potencjometru I
int pot2 = analogRead(A2); // odczyt potencjometru II

void setup() {
pinMode(A1,INPUT);
pinMode(A2,INPUT);
pinMode(A0,INPUT);
 serwo.attach(9); // put your setup code here, to run once:
 randomSeed(analogRead(A0));
  serwo.write(pos); // pozycja poczatkowa


}
void loop(){
pot1= analogRead(A1);// oczyt pot.
pot1 = map(pot1,2,10,0,1023);// przeliczenie
opoz1 = random(1,pot1)*500;//losowanie opoznienia z zakresu
                           //1-10 przeskok co 0,5 sekundy

serwo.write(pos);// ustawienie w pozycji I
delay (500);// czas na ruch serwa
if (pos >9)// warunek od ktorego biegnie czas opozn.
  {for ( opoz1 =opoz1; opoz1>=0; opoz1--)// petla opoznienia
    {delay(1);}
   };
pot2 = analogRead(A2); // oczyt pot. II
pot2 = map(pot2,6,12,0,1023);//przeliczenie
opoz2 = pot2*500;//opoznienie zalezne od pot II

serwo.write(pos2);// ustawienie w pozycji II
delay (500);// czas na ruch serwa
if (pos2 >99) // warunek od ktorego biegnie opoznienie
  {for ( opoz2=opoz2; opoz2>=0; opoz2--)//petla opoznienia
    {delay(1);}
  };


}
 
Odpowiedź
#2
Witam,
Hmm, a przypadkiem w kodzie dla funkcji map() nie masz zamienionej kolejności wartości wchodzących z wychodzącymi?
Jak już to pozamieniasz (dla obu użyć funkcji map()) to wyrzuć drugiego if-a : if (pos2 >99), bo w przypadku "najgorszym", gdy opoz2 = 6 * 500 da zawsze coś większego od 99.
Unikaj też używania jako warunków w pętli zmiennych globalnych. Dlatego też zamiast:
for ( opoz2=opoz2; opoz2>=0; opoz2--)
raczej:
for(int opoznienie_w _tej_petli = opoz2; opoznienie_w _tej_petli >= 0; opoznienie_w _tej_petli --)
Pozdrawiam,
Tomek.
 
Odpowiedź
#3
Dzięki Tomku,
Wygląda na to ze się poprawiło i losowanie chyba działa, wywaliłem oba ify.. zamieniłem wartości w funkcji map, zmieniłem zmienna opoz1 i 2
ale...

1. Serwo nadal buczy (Tower Pro SG90) co oznacza, jak mi się wydaje, że ciągle próbuje się ustawić na pozycji. To chyba nie wróży mu długiego życia, takie obciążenie

2. pomimo ustawienia wartości kąta na 90 stopni (tzn. 10 stopni i 100stopni) na oko widać że zakres ruchu jest większy niż 90

Czy można to jakoś ustabilizować? Brak kondensatorów filtrujących na zasilaniu serwa może na to wpływać?
Pozdrawiam,
 
Odpowiedź
#4
Witam,
A na przykładowych programach z biblioteki Servo jak serwo się sprawuje? Czy też buczy?
Pozdrawiam,
Tomek.
 
Odpowiedź
#5
Sprawdziłem na przykładzie też buczy w 80% pozycji. Czyli słaba jakość serwa.
W zarysie uzyskałem to co chciałem, teraz dopracowywanie szczegółów.


Dzięki za pomoc.
Pozdrawiam,
 
Odpowiedź
#6
Cytat:1. Serwo nadal buczy (Tower Pro SG90) co oznacza, jak mi się wydaje, że ciągle próbuje się ustawić na pozycji. To chyba nie wróży mu długiego życia, takie obciążenie
 
Znalazłem w szafie identyczne serwo i też buczy jak szalone. Pewnie ten typ tak ma Huh
 
Odpowiedź
#7
Witam,
Masz rację, ten typ tak ma.
Pozdrawiam,
Tomek.
 
Odpowiedź
#8
Ok. dzięki.
Napotkałem kolejny problem,
Chcę aby pewna pętla for była wykonywana tyle razy ile kliknięć przycisku.
Zatrzymałem się na tym, że sam licznik osobno działa. Ale jak dodam pętle for to nie czeka ona na zliczenie klikniec
np. z ostatnich  paru sekund tylko startuje od razu po pierwszym kliknieciu.  Probowałem z funkcją millis() ale chyba się zapętliłem w if-ach.

Po kolei, docelowo ma być tak:
pętla for ma wykonać tyle obiegow, ile zliczy klikniec
Klikniec moze być maksymalnie 5, potem licznik klikniec się zeruje.
chciałem zrobić tak że jeśli nic się nie dzieje od 3 sekund to zliczona ilość kliknięć jest wrzucana do pętli for.
Klikniecia są zliczane(widzę na monitorze portu szeregowego) ale do pętli iloscPowtorzen i licznikPetli są od razu 0.
Czyli nie odlicza tych 3 sekund i nie przerzuca wartości.
Przepraszam za chaos

 

Kod:
 
void loop(){
int iloscPowtorzen=0;
 int licznikPetli = 0;
 buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState)
  {
     if (buttonState == HIGH)
     {
     
      buttonPushCounter= buttonPushCounter+1;// zliczanie klikniec
    delay(25);// czas na drganie stykow
     czas = millis();// zapis czasu w momencie klikniecia
    
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter); // licznik
      }
          if(millis() >= czas + 3000)// po 3 sek po ostatnim kliknieciu
           {
            iloscPowtorzen = buttonPushCounter;//liczba klikniec na liczbe powtorzen
             buttonPushCounter=0;// zerowanie licznika klikniec
           }
             Serial.println(iloscPowtorzen);// kontrola
           if (buttonPushCounter>5)// zerowanie powyzej 5 klikniec
             {
              buttonPushCounter=0;}
     }
     lastButtonState = buttonState;

 for (licznikPetli=iloscPowtorzen; licznikPetli>0; licznikPetli--)
 {Serial.println(licznikPetli); // tyle obiegow petli ile klikniec
 
Odpowiedź
#9
Zacznij od dobrego algorytmu a dopiero potem bierz się za pisanie programu.
Jeśli nie potrafisz opisać czegoś słowami to nie masz szansy abyś to oprogramował.
Np:
1. Każde kliknięcie zwiększa wartość licznika i zapamiętuje aktualne millis
2. Jeśli od ostatniego kliknięcia minęło więcej niż x sekund to startuje pętla.
3. Jeśli pętla wykona się określoną ilość obiegów to zapamiętuje że się wykonał aby nie wystartować ponownie.
Najłatwiej to osiągnąć z pętlą while i dekrementacją licznika.
Pomagam za darmo więc szanuj mój czas.
Wklejaj tekst a nie jego zdjęcie.
Nie pisz następnego postu jak nie odpowiedziałeś na poprzedni.
Jak mądrze zadawać pytania
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości