Skocz do zawartości
Komentator

Kurs Arduino - #5 - PWM, serwomechanizmy, biblioteki

Pomocna odpowiedź

@Shango witam Cię na forum 🙂 

Serwa mają gwarantowany zakres ruchu 45-135° Jak mają więcej to fajnie, ale z reguły nie osiągają 0-180°. Możesz ewentualnie sprawdzić jak zachowa się serwo z własnym kodem do generowania sygnału sterującego, a stosując bibliotekę, ale raczej nie zmieni się to.

Udostępnij ten post


Link to post
Share on other sites

A co w przypadku jak mam Maker Uno  bez gniazda zasilania jak Arduino Uno? Jak podłączyć servo?

Udostępnij ten post


Link to post
Share on other sites

@Vescus niestety w takiej sytuacji musisz doprowadzić osobno linie zasilania inną drogą. Jeśli będziesz miał z tym problem to załóż proszę osobny temat, bo w komentarzach do kursów staramy się rozmawiać jedynie o przypadkach, gdy ktoś korzysta dokładnie z tego sprzętu, który jest używany w kursie. W przeciwnym wypadku powstaje zamieszanie, które jest szczególnie mylące dla nowych kursantów 🙂

Udostępnij ten post


Link to post
Share on other sites

Pytanie:

Skoro serwomechanizm wymaga napięcia 5 V i prądu większego niż 20 mA, który oferuje Arduino, to czy zamiast stabilizatora napięcia nie moglibyśmy wpiąć w układ po prostu tranzystora o odpowiednim wzmocnieniu prądowym i zrezygnować z zasilania baterią 9 V ?

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

@Zorpak Zauważ jak jest zbudowany stabilizator liniowy - jest  to właśnie tranzystor z odpowiednim układem regulacji - tylko tam potrzeba wyższe napięcie od wejściowego.

Istotą dodanie osobnego zasilania jest rozgraniczenie zasilania silnika od zasilania elektroniki (tzw. logiki). W ten sposób indukcyjny charakter silnika ma mniejszy wpływ na elektronikę - mniej szumów przy gwałtownych zmianach. Dodanie tranzystora w zasilanie przez który będzie płynął prąd wiele nie da, gdyż tranzystor gdy jest jedynie zasilany prądem stałym to traci sens - staje się złączem PN, które powoduje spadek napięcia. Zaś wzmocnienie prądowe nie powoduje że prąd jest jakoś tam wyższy czy lepszej jakości niż był - jest to taki jakby "zawór" lekko odkręcisz to jak jest co, to tyle razy więcej wyleci, ale jak nie masz możliwości wypuszczenia takiego prądu bo ogranicza cię układ stabilizatora z Arduino, albo USB to nic nie zdziałasz.

Gdybyś miał jakiś filtr, albo informację zwrotną to już byłoby coś, ale to właśnie masz w układzie stabilizatora 🙂 

Edytowano przez Gieneq
  • Lubię! 1
  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites

@Gieneq Dzięki za wyjaśnienia, teraz wiem o co chodzi. Szukałem co prawda na Googlach ale nigdzie nie znalazłem jasnego wytłumaczenia...

 

Udostępnij ten post


Link to post
Share on other sites

Chciałby zaproponować trochę zmodyfikowaną wersję programu do sterowania serwomechanizmem, ponieważ w tej wersji, która jest w kursie zmienna "pozycja" po wyzerowaniu jest od razu zwiększana o wartość "zmiana", a następnie jest wykonywany ruch czyli nigdy wychylenie nie osiąga wartości równej 0. W mojej propozycji linijka odpowiedzialna za wykonanie ruchu została przeniesiona przed instrukcję warunkową, a linijka, w której zwiększana jest wartość zmiennej "pozycja" trafiła do instrukcji warunkowej.

#include <Servo.h> //Biblioteka odpowiedzialna za serwa

Servo serwomechanizm; //Tworzymy obiekt, dzięki któremu możemy odwołać się do serwa
int pozycja = 0; //Aktualna pozycja serwa 0-180
int zmiana = 6; //Co ile ma się zmieniać pozycja serwa?

void setup() {
  serwomechanizm.attach(9); //Serwomechanizm podłączony do pinu 9
}


void loop() {
  serwomechanizm.write(pozycja); //Wykonaj ruch do aktualnej pozycji
  if (pozycja < 180) { //Jeśli pozycja mieści się w zakresie
    pozycja = pozycja + zmiana; //Zwiększenie aktualnej pozycji serwa
  } else { //Jeśli nie
    pozycja = 0; //Zmniejszenie aktualnej pozycji serwa
  }
  
  delay(100); //Opóźnienie dla lepszego efektu
}

 

Poza tym chciałbym też zaproponować program, który będzie płynnie obracał serwomechanizmem od pozycji minimalnej do maksymalnej i z powrotem:

#include <Servo.h> //Biblioteka odpowiedzialna za serwa

Servo serwomechanizm; //Tworzymy obiekt, dzięki któremu możemy odwołać się do serwa
int pozycja = 0; //Aktualna pozycja serwa 0-180
int zmiana = 1; //Co ile ma się zmieniać pozycja serwa?
boolean wzrost = true; //Czy zwiększamy wychylenie?

void setup() {
  serwomechanizm.attach(9); //Serwomechanizm podłączony do pinu 9
}

void loop() {
  serwomechanizm.write(pozycja); //Wykonaj ruch do aktualnej pozycji

  if (wzrost == true) { //Jeżeli zwiększamy wychylenie
    pozycja = pozycja + zmiana; //Zwiększ wartość pozycji
  } else { //W przeciwnym wypadku
    pozycja = pozycja - zmiana; //Zmniejsz wartość pozycji
  }
  
  if (pozycja == 180) { //Jeżeli pozycja osiągnie maksimum
    wzrost = false; //Przejdź do zmniejszania wychylenia
  } else if (pozycja == 0) { //Jeżeli pozycja osiągnie minimum
    wzrost = true; //Przejdź do zwiększania wychylenia
  }
  delay(10);
}

 

Udostępnij ten post


Link to post
Share on other sites
2 godziny temu, ewgron napisał:

zmienna "pozycja" po wyzerowaniu jest od razu zwiększana o wartość "zmiana", a następnie jest wykonywany ruch czyli nigdy wychylenie nie osiąga wartości równej 0

Nie zgadzam się. Najpierw  jest wykonywany ruch serwem a później zmieniana jest wartość "pozycja"

  Przeanalizujmy Twój kod a później kod z kursu. 

void loop() {
  serwomechanizm.write(pozycja); // zmienna " pozycja" = 0 ; pozycja serwa = 0 
  if (pozycja < 180) { // zmienna " pozycja" = 0 ; pozycja serwa = 0 
    pozycja = pozycja + zmiana; // zmienna " pozycja" = 6 ; pozycja serwa = 0  
  } else { 
    pozycja = 0; 
  }  
   delay(100); //  zmienna " pozycja" = 6 ; pozycja serwa = 0 przez 0,1 sekundy
}

kod z kursu:

void loop() {
  if (pozycja < 180) { // zmienna " pozycja" = 0 ; pozycja serwa = 0 
    serwomechanizm.write(pozycja); // zmienna " pozycja" = 0 ; pozycja serwa = 0  
  } else { 
    pozycja = 0; 
  }  
   pozycja = pozycja + zmiana; // zmienna " pozycja" = 6 ; pozycja serwa = 0 
   delay(200); //  zmienna " pozycja" = 6 ; pozycja serwa = 0 przez 0,2 sekundy
}

 

Udostępnij ten post


Link to post
Share on other sites
58 minut temu, jas123 napisał:

Nie zgadzam się. Najpierw  jest wykonywany ruch serwem a później zmieniana jest wartość "pozycja"

  Przeanalizujmy Twój kod a później kod z kursu. 


void loop() {
  serwomechanizm.write(pozycja); // zmienna " pozycja" = 0 ; pozycja serwa = 0 
  if (pozycja < 180) { // zmienna " pozycja" = 0 ; pozycja serwa = 0 
    pozycja = pozycja + zmiana; // zmienna " pozycja" = 6 ; pozycja serwa = 0  
  } else { 
    pozycja = 0; 
  }  
   delay(100); //  zmienna " pozycja" = 6 ; pozycja serwa = 0 przez 0,1 sekundy
}

kod z kursu:


void loop() {
  if (pozycja < 180) { // zmienna " pozycja" = 0 ; pozycja serwa = 0 
    serwomechanizm.write(pozycja); // zmienna " pozycja" = 0 ; pozycja serwa = 0  
  } else { 
    pozycja = 0; 
  }  
   pozycja = pozycja + zmiana; // zmienna " pozycja" = 6 ; pozycja serwa = 0 
   delay(200); //  zmienna " pozycja" = 6 ; pozycja serwa = 0 przez 0,2 sekundy
}

 

Może się mylę ale działanie programu z kursu w skrajnych położeniach rozumiem tak (analizę zaczynam w 29 przebiegu czyli wtedy gdy zmienna "pozycja" ma już wartość 174):

  1. Warunek "pozycja < 180" jest spełniony (ponieważ wartość zmiennej "pozycja" wynosi 174) więc serwo jest przestawiane na pozycję 174, następuje zwiększenie wartości zmiennej "pozycja" na 180, a na koniec pojawia się opóźnienie.
  2. Warunek "pozycja < 180" nie jest już spełniony (ponieważ wartość zmiennej "pozycja" jest równa 180) więc wykonuje się polecenie w "else" to znaczy wartość zmiennej "pozycja" jest ustalana na 0 (serwo nie wykonuje ruchu), następnie wartość zmiennej "pozycja" jest zwiększana o 6 (pozycja = pozycja + zmiana) i przyjmuje wartość 6, na koniec pojawia się opóźnienie.
  3. Warunek "pozycja < 180" jest spełniony (ponieważ wartość zmiennej "pozycja" wynosi 6) więc serwo jest przestawiane na pozycję 6, następuje zwiększenie wartości zmiennej "pozycja" na 12, a na koniec pojawia się opóźnienie.

Wygląda na to, że serwo nie przyjmuje wartości skrajnych czyli 0 i 180. Dlatego zaproponowałem inne podejście.

Jeżeli źle rozumiem działanie programu z kursu, proszę o wyjaśnienie 🙂 Dopiero zaczynam przygodę z Arduino i w związku z tym proszę o wyrozumiałość 🙂 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

 

W obu programach serwo może mieć wartość 0 .Różnica Twojego kodu a kodu z kursu jest taka że w kodzie z kursu warunek jest na początku czyli nie ma możliwości żeby pozycja serwa była większa od 179 może być równa 179 ale nie musi (to zależy od zmiennej "zmiana").W Twoim kodzie maksymalna pozycja serwa to 179 + wartość zmiennej "zmiana" (to też zależy od zmiennej).

Edit: Namieszałem trochę , komentarz poprawiony.

Edytowano przez jas123

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
24 minuty temu, jas123 napisał:

Jak to nie ? Napiszmy to trochę inaczej:


Jeśli (180 jest większe od 180 ){
//zrób coś
}

Według mnie 180 jest równe 180 .

W obu programach serwo może mieć wartość 0 .Różnica Twojego kodu a kodu z kursu jest taka że w kodzie z kursu warunek jest na początku czyli nie ma możliwości żeby pozycja serwa była większa od 180 może być równa 180 ale nie musi (to zależy od zmiennej "zmiana").W Twoim kodzie maksymalna pozycja serwa to 180 + wartość zmiennej "zmiana" (to też zależy od zmiennej).

Warunek zapisany w instrukcji "if" sprawdza czy wartość zmiennej "pozycja" jest mniejsza od 180. Jeżeli zmienna "pozycja" jest równa lub większa od 180 to warunek nie jest spełniony.

Gdyby warunek był zapisany w ten sposób:

if (pozycja <= 180) 

to wówczas byłoby tak jak napisałeś. Natomiast w kodzie jest zapis:

if (pozycja < 180)

czyli gdy zmienna "pozycja" ma wartość 180 to mamy:

if (180 < 180)

czego wynikiem jest "false" czyli warunek nie jest spełniony ponieważ 180 nie jest mniejsze od 180.

https://www.arduino.cc/reference/en/language/structure/comparison-operators/lessthan/

@Gieneq Proszę o rozstrzygnięcie.

Edytowano przez ewgron

Udostępnij ten post


Link to post
Share on other sites

Zastanawianie się nad działaniem Ifów jest tu zbędne. Wystarczy zrobić tabelkę przebiegu wartości zmiennej i da się dojść jaką wartość ma zmienna gdy ustawiane jest serwo.

W kodzie z kursu faktycznie serwo nie osiąga wartości 0, bo gdy zmienna zostaje ustawiona wyskakuje z warunku zostaje zinkrementowana i trafia z powrotem do warunku dla < 180 gdzie jest już niezerowa.

Czy jest to błąd? W sumie nie, są małe szanse, że przy gwarantowanym zakresie ruchu serwa, ktoś wykorzysta pozycję 0.

Poza tematem taka ciekawostka jak wygląda funkcja serwa write:

void Servo::write(int value)
{
  if(value < MIN_PULSE_WIDTH)
  {  // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
    if(value < 0) value = 0;
    if(value > 180) value = 180;
    value = map(value, 0, 180, SERVO_MIN(),  SERVO_MAX());
  }
  this->writeMicroseconds(value);
}
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4)  // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4)  // maximum value in uS for this servo
uint8_t Servo::attach(int pin, int min, int max)
{
  if(this->servoIndex < MAX_SERVOS ) {
    pinMode( pin, OUTPUT) ;                                   // set servo pin to output
    servos[this->servoIndex].Pin.nbr = pin;
    // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
    this->min  = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
    this->max  = (MAX_PULSE_WIDTH - max)/4;

Domyślnie this->min/max mają wartość 0.

Widać tu, że można włożyć do funkcji np -1, albo 190 bo i tak zostaną docięte do akceptowalnych wartości. W kursie zostało to tak zrealizowane aby mieć pewność, że kod będzie zrozumiały, że nikt nie będzie miał dylematu że zmienna wychodzi poza "bezpieczny obszar" (który i tak zawsze jest bezpieczny ), ale bez wnikania w kod biblioteki raczej mało kto się nad tym zastanowi. 

To jeszcze jeżeli mam być czepialski to ustawienie serwa powinno być jako efekt aktualizacji zmiennej i można je wrzucić pod warunki i będzie super 🙂 @ewgron Fajnie, że kombinujesz, tak trzymaj!

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Podzielę się moją propozycją rozwiązania zadania 5.5:

Układ:

IMG_20200601_180324.thumb.jpg.9f660c561b6cea1cdf214655be59f8f9.jpg

Program:

#include <Servo.h> //Biblioteka odpowiedzialna za serwa

Servo serwomechanizm; //Obiekt odwołujący się do serwa

int potencjometr = 0; //Zmienna do przechowywania wartości odczytanej z dzielnika
int pozycja = 0; //Zmienna do przechowywania pozycji serwa

void setup() {
  serwomechanizm.attach(9); //Serwomechanizm podłączony do pinu 9
}

void loop() {
  potencjometr = analogRead(A5); //Odczytanie wartości z dzielnika
  pozycja = map(potencjometr, 0, 1023, 0, 180); //Przeskalowanie wartości
  serwomechanizm.write(pozycja); //Wykonanie ruchu
}

 

Udostępnij ten post


Link to post
Share on other sites

@ewgron fajnie 🙂 dla oszczędności miejsca całą zawartość loop() możesz zawrzeć w jednej linii 🙂 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Zadanie 5.4, wstępne podejście wyszło tak: 

#include <Servo.h>
Servo serwomechanizm;

int pozycja = 0;

void setup() {
  Serial.begin(9600);
  serwomechanizm.attach(9);
}

void loop () {
  pozycja = Serial.parseInt();
  if (pozycja >= 0 && pozycja <= 180) serwomechanizm.write(pozycja);
  else Serial.println("Wybierz liczbe z zakresu 0-180");
}

W tym rozwiązaniu serwo porusza się do żądanej pozycji a potem wraca do 0. Chciałem zrobić tak, aby serwo zostało w danej pozycji do momentu w którym użytkownik wprowadzi nową wartość. Wraz z wujkiem G opracowaliśmy takie rozwiązanie:

#include <Servo.h>
Servo serwo;

int pozycja = 0;

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

void loop () {
  if (Serial.available() > 0) serwo.attach(9); // Aktywacja serwa na pinie 9
  pozycja = Serial.parseInt(); // Zapisanie do zmiennej wartosci podanej przez uzytkownika
  if (pozycja >= 0 && pozycja <= 180) serwo.write(pozycja); // Ustawienie serwa w zadanym kacie
  else Serial.println("Wybierz liczbe z zakresu 0-180");
  serwo.detach(); // Odlaczenie serwa 
}

Założenie jest takie, że po kiedy otwiera się komunikacja, serwo się włącza a po wprowadzeniu kąta przechodzi do żądanej pozycji po czym zostaje odłączone i zostaje w tej pozycji. Jestem zadowolony z tego rozwiązania ze względu na jego prostotę 🙂 

Mam natomiast jedno pytanie dotyczące pierwszego kodu - po przesłaniu kodu do Arduino (lub wciśnięciu przycisku Reset) serwo wychyla się o jakieś 90 stopni po czym wraca do pozycji początkowej. Z czym może być to związane? 

 

Pochwalę się jeszcze zadaniem 5.5:

#include <Servo.h>
Servo serwomechanizm;

int potencjometr = 0;

void setup() {
  serwomechanizm.attach(9);
}

void loop () {
  potencjometr = map(analogRead(A5), 0, 1023, 0, 181); // Odczytuje sygnał analogowy z potencjometru i za pomoca funkcji map rozbijam na zakres obrotu serwa
  serwomechanizm.write(potencjometr); // Informacja dla serwa o kacie wychylenia
}

Serwo bardzo płynnie porusza się razem z obrotem potencjometrem 🙂 

Edytowano przez Slowik

Udostępnij ten post


Link to post
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!

Gość
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...