Skocz do zawartości

Kurs Arduino - #5 - PWM, serwomechanizmy, biblioteki


Komentator

Pomocna odpowiedź

W związku z ostrzeżeniami o NIE zasilaniu serwa z USB, czyli lepiej wgrać najpierw program do płytki bez podłączenia serwa. Potem podłączyć zasilanie 9v i serwo?

Chyba miałem szczęście że to serwo jest małe bo wgrałem program przez USB z serwem podłączonym do płytki, na domiar złego do wyjścia 5V. Po wgraniu programu serwo od razu ruszyło. Nic się nie stało...

Chciałem się też upewnić, V in to jest to samo napięcie co podane z zasilania zewnętrznego?

Czy jest ono podłączone bezpośrednio do gniazda zasilającego  bez stabilizacji i ograniczeń?

Czy można mieć płytkę włączoną do zasilania USB i zasilania zewnętrznego jednocześnie?

 

Link do komentarza
Share on other sites

41 minut temu, szlak18 napisał:

W związku z ostrzeżeniami o NIE zasilaniu serwa z USB, czyli lepiej wgrać najpierw program do płytki bez podłączenia serwa. Potem podłączyć zasilanie 9v i serwo?

Tak byłoby najbezpieczniej.

41 minut temu, szlak18 napisał:

Chciałem się też upewnić, V in to jest to samo napięcie co podane z zasilania zewnętrznego?

Dokładnie tak - to jest "przedłużenie" napięcia podawanego na złącze zasilania. Więcej na ten temat znajdziesz w tym artykule (szczegóły widać na schemacie): Arduino, co w środku piszczy – #1 – schemat

42 minuty temu, szlak18 napisał:

Czy można mieć płytkę włączoną do zasilania USB i zasilania zewnętrznego jednocześnie?

Oczywiście 🙂

Link do komentarza
Share on other sites

Cześć, 

Trochę utknąłem ze swoim mały pomysłem w miejscu i nie wiem co z nim zrobić dalej. Nie ruszyłem jeszcze serwomechanizmu bo trochę chciałem "powymyślać" z diodą. Otóż wymyśliłem sobie, że zrobię diodę led z czujnikiem zmierzchu. Wykorzystałem do tego dodatkowo potencjometr aby ustawić "próg" zmierzchu. Jest jednak jedna kwestia, której nie mogę przeskoczyć. Mianowicie, chciałem również, żeby LED rozświetlał się stopniowo, po przekroczeniu progu. Problem w tym, że przy ustawieniu pewnego progu "zmierzchu" jest on tak wysoki, że przy moim kodzie LED rozświetla się od razu dość jasno, a różnica między minimalnym świeceniem a maksymalnym jest ledwo zauważalna. 

Tutaj kod: 

#define dioda 5
#define fotorezystor A5
#define potencjometr A4

int wypelnienie = 0; //zmienna wypelnienia sygnalu
int zmiana = 5; //stopien zmiany
int odczytanaWartosc = 0; //wartosc z ADC
int prog = 0; //prog wlaczenia swiatla
int poziomSwiecenia; //jasnosc diody

void setup()
{
    pinMode(dioda, OUTPUT); //konfiguracja wyjsc
    Serial.begin(9600);

}

void loop()
{
    prog = analogRead(A4);
    odczytanaWartosc = analogRead(A5); //odczytanie wartosci z fotorezystora
    poziomSwiecenia = map(odczytanaWartosc, 0, 1024, 255, 0); //mapowanie wartosci
    if (odczytanaWartosc < prog)
    {

        Serial.println(String(poziomSwiecenia));
        if (poziomSwiecenia < 30)
        {
            digitalWrite(dioda, LOW);
            delay(50);
        } else
        {

            analogWrite(dioda, poziomSwiecenia);
            delay(50);
        }

    }
    else
    {
        digitalWrite(dioda, LOW);
        Serial.println(String(poziomSwiecenia));
    }

}

Wszystko pięknie, z tym, ze jeżeli próg ustawiony jest dość wysoko (pokój  pojedynczym światłem) to uzależnienie wypełnienia sygnału od odczytu z fotorezystora jest słabe, bo od razu łapie wartości rzędu 120+ (zmienna poziomSwiecenia, powstała w skutek funkcji map odczytu z fotorezystora). Czy jest jakiś sposób aby "skalibrować" wskazania fotorezystora po wejściu do ifa porównującego wartości z fotorezystora i potencjometru? Na zasadzie, że załóżmy wartość 500, która jest progiem z potencjometru po wejściu do ifa będzie stanowić punkt zerowy i regulacja będzie odbywać się w pozostałym zakresie (500-1024)? Dodam, że do fotorezystora podłączyłem szeregowo 3 oporniki 10kΩ. Na rezystorach 1kΩ wartości były zupełnie w kosmosie - obecnie na początku świecenia wartość wypełnienia jest w około 60, ale za to ucierpiały na tym wartości maksymalne, które oscylują w okolicach 160. 

Edytowano przez BHBmacieg
Link do komentarza
Share on other sites

Po prostu przepuść wynik map przez constrain, czyli np.
 

poziomSwiecenia = map(odczytanaWartosc, 500, 1024, 255,0);
poziomSwiecenia = constrain(poziomSwiecenia, 0, 255);

Pierwsza linijka zamieni Ci interesujący zakres odczytanej wartości na wartości które wrzucisz w analogWrite, druga zadba o to aby trzymały się w dopuszczalnym zakresie.

  • Lubię! 2
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

26 minut temu, ethanak napisał:

Po prostu przepuść wynik map przez constrain, czyli np.
 


poziomSwiecenia = map(odczytanaWartosc, 500, 1024, 255,0);
poziomSwiecenia = constrain(poziomSwiecenia, 0, 255);

Pierwsza linijka zamieni Ci interesujący zakres odczytanej wartości na wartości które wrzucisz w analogWrite, druga zadba o to aby trzymały się w dopuszczalnym zakresie.

Super, dziękuję za szybką odpowiedź. Jutro po pracy sprawdzę w praktyce i dam znać co mi z tego wyszło. Rozumiem, że równie dobrze, zamiast wartość 500 w funkcji map mogę podać po prostu zmienną "próg", tak aby przedział ustalał się automatycznie bez konieczności zmiany go ręcznie w kodzie? 

Link do komentarza
Share on other sites

16 minut temu, BHBmacieg napisał:

zamiast wartość 500 w funkcji map mogę podać po prostu zmienną "próg", tak aby przedział ustalał się automatycznie bez konieczności zmiany go ręcznie w kodzie

Oczywiście. Możesz spróbować zastosować dwa potencjometry i regulować również drugi koniec przedziału - to może być ciekawe doświadczenie.

  • Lubię! 2
Link do komentarza
Share on other sites

Wracam, 

Póki co na tarczy a nie z tarczą. Generalnie mam problem z funkcją map w momencie, gdy stosuję ją w sposób map(x, 0, 1024, 255, 0) - wyniki takiego mapowania są strasznie dziwne - otrzymuję nawet wartości rzędy -3000. Czy z założenia wartości tej zmiennej po zmapowaniu nie powinny przyjąć wartości z przedziały 0 - 255? Bo gdy wpiszę x = map(x, 0, 1024, 0, 255) wydaje się, że wszystko działa jak należy. Takie rozwiązanie jednak powoduje odwrotne działanie układu niż bym chciał - im więcej światła tym LED świeci mocniej. 

Metoda z mapowaniem przedziału podana wyżej nie przynosi rezultatów. Przykład: odczytany próg to: 490, wartość odczytana z potencjometru to: 466, czyli jesteśmy tylko delikatnie poniżej progu, a wartość poziomSwiecenia to 255. Jak to się dzieje, że wartości 466 odczytanej z fotorezystora, czyli wartości nawet poniżej połowy wartości maksymalnej jaką może przyjąć ta zmienna program przypisuje wartość 255 w wyniku mapowania? Nie powinno być coś w okolicach 100-120, żeby i tu być w połowie przedziału? Powoduje to, że dla większości ustawień potencjometru po przekroczeniu progu dioda od razu pali się maksymalnym światłem. Są pewnie położenia dla których układ działa poprawnie, ale trzeba się nieźle wysilić żeby się w nie wstrzelić. Częściowo pomaga sztuczne przesunięcie przedziału mapowania, to jest na przykład: poziomSwiecenia=map(odczytanaWartosc, prog, 1024, 255, -500);. Wtedy tych "poprawnych ustawień" potencjometru jest kapkę więcej.  Kurcze mam wrażenie, że piszę to bardzo zawile ale ciężko to opisać ładnie słowami 🙂

#define dioda 5
#define fotorezystor A5
#define potencjometr A4
#define potencjometr2 A3

int wypelnienie = 0; //zmienna wypelnienia sygnalu
int zmiana = 5; //stopien zmiany
int odczytanaWartosc = 0; //wartosc z ADC
int prog = 0; //prog wlaczenia swiatla
int poziomSwiecenia = 0; //jasnosc diody
int poziomJasnosci = 0;

void setup()
{
    pinMode(dioda, OUTPUT); //konfiguracja wyjsc
    Serial.begin(9600);

}

void loop()
{
    prog = analogRead(A4);
    odczytanaWartosc = analogRead(A5); //odczytanie wartosci z fotorezystora
    Serial.println("prog: " + String(prog));
    if (odczytanaWartosc < prog)
    {
        Serial.println("OdczytanaWartosc: " + String(odczytanaWartosc));
        poziomSwiecenia = map(odczytanaWartosc, prog, 1024, 255, 0);
        poziomSwiecenia = constrain(poziomSwiecenia, 0, 255);
        Serial.println("Poziom swiecenia: " + String(poziomSwiecenia));

        analogWrite(dioda, poziomSwiecenia);
        delay(1000);

    }
    else
    {
        analogWrite(dioda, 0);
        delay(1000);

    }

}

 

Problem występuje przy niskich warunkach progu. przy wartości progu 800 w górę jest całkiem ok pod warunkiem zrezygnowania z ograniczania przedziału mapowania. 

Edytowano przez BHBmacieg
Link do komentarza
Share on other sites

51 minut temu, BHBmacieg napisał:

Czy z założenia wartości tej zmiennej po zmapowaniu nie powinny przyjąć wartości z przedziały 0 - 255?

A może zamiast zawracać głowę nieco samodzielności? https://www.arduino.cc/reference/en/language/functions/math/map/ - tam masz wyjaśnione jak działa map, ze szczególnym uwzględnieniem tego, że dla wartości spoza zakresu wejściowego wartości wynikowe będą również poza zakresem.

57 minut temu, BHBmacieg napisał:

odczytany próg to: 490, wartość odczytana z potencjometru to: 466, czyli jesteśmy tylko delikatnie poniżej progu, a wartość poziomSwiecenia to 255. Jak to się dzieje, że wartości 466 odczytanej z fotorezystora, czyli wartości nawet poniżej połowy wartości maksymalnej jaką może przyjąć ta zmienna program przypisuje wartość 255 w wyniku mapowania?

Z potencjometru czy fotorezystora, bo już nie wiem o co Ci chodzi.

Jeśli to z fotorezystora to jaki Twoim zdaniem powinien być wynik map(466,490,1024,255,0)?

 

Link do komentarza
Share on other sites

59 minut temu, ethanak napisał:

A może zamiast zawracać głowę nieco samodzielności? https://www.arduino.cc/reference/en/language/functions/math/map/ - tam masz wyjaśnione jak działa map, ze szczególnym uwzględnieniem tego, że dla wartości spoza zakresu wejściowego wartości wynikowe będą również poza zakresem.

 

Dziękuję za link. Czytałem o funkcji map ale widocznie w złym miejscu, bo tam brakowało informacji o tym co się dzieje gdy liczba jest poza zakresem. 

 

59 minut temu, ethanak napisał:

Jeśli to z fotorezystora to jaki Twoim zdaniem powinien być wynik map(466,490,1024,255,0)?

 

O i to też dużo wyjaśnia! Źle patrzyłem na tę funkcję. A mianowicie pierwszą wartość w nawiasie traktowałem jako wskazanie, którą zmienną ma mapować a nie jako konkretną wartość. Strona, na której czytałem o funkcji map niezbyt jasno to przedstawiła. Dziękuje i idę walczyć dalej 😉

 

Póki co wrzucam kody z prac domowych 🙂

5.2

#define dioda 5

int wypelnienie = 0; //zmienna wypelnienia sygnalu
int zmiana = 5; //stopien zmiany


void setup()
{
    pinMode(dioda, OUTPUT); //konfiguracja wyjsc  

}

void loop()
{
    while (wypelnienie < 255)
    { //kiedy jestesmy ponizej maksimum
        wypelnienie += zmiana;
        analogWrite(dioda, wypelnienie);
        delay(60); //odczekanie chwile
    }

    while (wypelnienie <= 255 && wypelnienie != 0) 
    { //gdy osiagniemy maksimum
        wypelnienie -= zmiana;
        analogWrite(dioda, wypelnienie);
        delay(60);
    }
    

}

 

5.4:

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

Servo serwomechanizm; //towrzenie obiektu do odwłoania
int pozycja = 0; //aktualna pozycja serwa 0-100
int zmiana = 6; // co ile ma sie zmienic pozycja
String podanaWartosc = ""; //zmienna podana przez uzytkownika
int podanaWartoscINT = 0; //zmiena podawaWartosc w INT

void setup()
{
    Serial.begin(9600);
    serwomechanizm.attach(9); //serwomechanizm na pinie 9

}

void loop()
{
    Serial.println("Podaj kąt obrotu serwa! (0-180)");
  while (Serial.available() == 0)
    {
        delay(25);
    }
    podanaWartosc = Serial.readStringUntil('\n'); // odczytanie wartosci z klawiatury
    podanaWartoscINT = podanaWartosc.toInt(); //zamiana na INT

    if (podanaWartoscINT <=180 && podanaWartoscINT >=0)
    { //jesli miesciemy sie w zakresie

        serwomechanizm.write(podanaWartoscINT);
        Serial.println("aktalny kąt serwomechanizmu to: " + podanaWartosc);
        
    } else
    {
        Serial.println("Podano kąt z poza zakresu!");
    }

    delay(50);

}

5.5

#define potencjometr A5
#include <Servo.h> // biblioteka odpowiedzialna za serwa


Servo serwomechanizm; //towrzenie obiektu do odwłoania
int pozycja = 0; //aktualna pozycja serwa 0-100
int ustawieniePotencjometru = 0; //odczytanie z ADC

void setup()
{
    Serial.begin(9600);
    serwomechanizm.attach(9); //serwomechanizm na pinie 9

}

void loop()
{
    ustawieniePotencjometru = analogRead(potencjometr); //odczytanie wartosci z potencjometru
    pozycja = map(ustawieniePotencjometru, 0, 1024, 0, 180); //przeliczenie wartosci ADC na kat
    serwomechanizm.write(pozycja); //ustawienie serwa w zadany kat

    delay(50);

}

 

Edytowano przez BHBmacieg
Link do komentarza
Share on other sites

Witam

Zadanie 5.2, dlaczego nie działa?

#define diodaPIN 3
 
int wypelnienie = 0;
int zmiana = 5;
 
void setup() {
 pinMode(diodaPIN, OUTPUT);//Konfiguracja pinu jako wyjścia 
}
 
void loop() {
 analogWrite(diodaPIN, wypelnienie); //Generujemy sygnał o zadanym wypełnieniu
 
 while(wypelnienie < 255) { //Jeśli wypełnienie mniejsze od 100%
 wypelnienie = wypelnienie + zmiana; //Zwiększamy wypełnienie
 delay(50);
 }

 while(wypelnienie <= 255 && wypelnienie >0)
 {
  wypelnienie = wypelnienie - zmiana;
  delay(50);
 }
 
}

 

Edytowano przez radekwrc
Link do komentarza
Share on other sites

@radekwrc, zadanie 5.5 z tego co widziałem w artykule dotyczyło serwa i potencjometru, czyli chodziło o 5.2? Tak się domyślam, że chodziło o stopniowe rozjaśnianie i gaszenie diody.

Program nie działa jak oczekujesz dlatego, że zmieniasz w tych dwóch pętlach tylko wartość zmiennej wypelnienie. A należałoby mając w niej nową wartość użyć tam instrukcji analogWrite do wygenerowania PWMu o takim wypełnieniu jak w tej zmiennej 😉

Link do komentarza
Share on other sites

Teraz działa:)

#define diodaPIN 3
 
int wypelnienie = 0;
int zmiana = 5;
 
void setup() {
 pinMode(diodaPIN, OUTPUT);//Konfiguracja pinu jako wyjścia 
}
 
void loop() {
 analogWrite(diodaPIN, wypelnienie); //Generujemy sygnał o zadanym wypełnieniu
 
 while(wypelnienie < 255) { //Jeśli wypełnienie mniejsze od 100%
 wypelnienie = wypelnienie + zmiana;//Zwiększamy wypełnienie
 analogWrite(diodaPIN, wypelnienie);
 delay(500);
 }

 while(wypelnienie <= 255 && wypelnienie >0)
 {
  wypelnienie = wypelnienie - zmiana;
  analogWrite(diodaPIN, wypelnienie);
  delay(500);
 }
 
}

Może umiał by Pan pomóc mi w zadaniu 4.5?

Link do komentarza
Share on other sites

Trochę offtop, bo to inny temat na forum, ale odpiszę tylko tyle, że polecam poprawić w tam wstawionym kodzie formatowanie 😉 Jak nawiasy są tak nierówno to bardzo ciężko się to czyta i może z tego powodu nie otrzymałeś jeszcze odpowiedzi. Chociaż spróbuję w dłuższej wolnej chwili zerknąć tam, ale mam nadzieję, że już wtedy Twój post będzie o to poprawiony 🙂

  • Lubię! 1
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.