• 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
Sterowanie silnikiem z czujnikiem przeciążenia
#1
Witam, 
to mój pierwszy projekt więc proszę o łagodne traktowanie. Dopiero zaczynam ogarniać podstawy i póki co błądzę jak dziecko we mgle. 
Chcę stworzyć sterowanie silnikiem elektrycznym w taki sposób, że po naciśnięciu przycisku silnik obraca się i wyłącza po osiągnięciu zadanego poboru prądu. Do tego celu wykorzystałem moduł BTS7960 który na pinach R_IS i L_IS wystawia rosnące napięcie w takim przypadku. Z pomocą arduino udało mi się stworzyć sterowanie z przełącznika i mogę już sterować silnikiem w obu kierunkach, udaje mi się także mierzyć napięcie na pinach R_IS i L_IS póki co połączone na jeden pin A0 i odczytać je przez "serial.println" ale jak teraz mógłbym sprawić aby po osiągnięciu zadanego napięcia arduino zmieniło stan wyjścia do sterowania kierunku z HIGH na LOW? Odnalazłem funkcję Analog Comparator ale nie wiem jak z niej skorzystać i czy to w moim przypadku nie zbytnia komplikacja? Może ktoś ma lepszy pomysł? Mój kod jaki stworzyłem do tej pory umieszczam w załączniku.
Dodatkowo byłoby genialnie gdyby stan wyjść został automatycznie podtrzymany w stanie HIGH po naciśnięciu przełącznika aż do osiągnięcia napięcia ale jak to zrobić to nie udało mi się znaleźć choć może nie umiem po prostu szukać.


Załączone pliki
.txt   kod.txt (Rozmiar: 653 bajtów / Pobrań: 8)
 
Odpowiedź
#2
if (Vin>progZatrzymania)
{
wykonajInstrukcjeWymaganeDoZatrzymania();
}
Przerób kurs Arduino, są darmowe, online: https://forbot.pl/blog//kurs-arduino-pod...rsu-id5290
Na pewno znajdziesz też mnóstwo kursów w formie vlogów na Youtube, nauka może i jest nudna, lekcje mogą się wydawać niezwiązane z problemem, ale za to nie będziesz błądził po omacku. Jak zadajesz takie pytanie, to zresztą każda lekcja kursu powinna być ciekawa i nowatorska.
Podtrzymanie to już w kursie może nie znajdziesz, ale by zrozumieć wskazówkę i tak bez niego się nie obejdziesz.
Instalujesz bibliotekę do obsługi przycisków, na wciśnięcie ustawiasz flagę na 1, w kolejnym bloku programu sprawdzasz czy flaga jest 1 i (logiczne and) próg zadziałania < max, jeśli tak to załączasz, w przeciwnym wypadku ustawiasz flagę na 0 i wyłączasz pracę silnika.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
(23-03-2024, 01:20)chavez napisał(a): Witam, 
to mój pierwszy projekt więc proszę o łagodne traktowanie. Dopiero zaczynam ogarniać podstawy i póki co błądzę jak dziecko we mgle. 
Chcę stworzyć sterowanie silnikiem elektrycznym w taki sposób, że po naciśnięciu przycisku silnik obraca się i wyłącza po osiągnięciu zadanego poboru prądu. Do tego celu wykorzystałem moduł BTS7960 który na pinach R_IS i L_IS wystawia rosnące napięcie w takim przypadku. Z pomocą arduino udało mi się stworzyć sterowanie z przełącznika i mogę już sterować silnikiem w obu kierunkach, udaje mi się także mierzyć napięcie na pinach R_IS i L_IS póki co połączone na jeden pin A0 i odczytać je przez "serial.println" ale jak teraz mógłbym sprawić aby po osiągnięciu zadanego napięcia arduino zmieniło stan wyjścia do sterowania kierunku z HIGH na LOW? Odnalazłem funkcję Analog Comparator ale nie wiem jak z niej skorzystać i czy to w moim przypadku nie zbytnia komplikacja? Może ktoś ma lepszy pomysł? Mój kod jaki stworzyłem do tej pory umieszczam w załączniku.
Dodatkowo byłoby genialnie gdyby stan wyjść został automatycznie podtrzymany w stanie HIGH po naciśnięciu przełącznika aż do osiągnięcia napięcia ale jak to zrobić to nie udało mi się znaleźć choć może nie umiem po prostu szukać.

Dokumentacja układu użytego w tym module podaje, że na wyjściu IS podawany jest prąd - by mieć napięcie trzeba użyć rezystora. Takie działanie chyba umożliwia połączenie tych pinów razem - bo prądy się sumują. Jest taki rezystor w module?
Zerknąłem też na kod.
Masz tam trochę dziwne, nadmiarowe odczyty BUTTONów - raz czytasz je do zmiennych - i to jest ok, ale po co jeszcze raz, gdy z wynikiem odczytu nic nie robisz?
Kod:
digitalRead(BUTTON_UP);

Masz też instrukcję:
Kod:
float Vin = ((float)analogRead(A0)/1024)*5; // A0 pin pomiarowy


Nawiasy wymuszają najpierw podzielenie przez 1024, a potem pomnożenie przez 5.
Nie lepiej od razy dzielić przez 204.8? A tak w ogóle to pewnie będziesz i tak chciał to przeliczyć na prąd silnika a nie napięcie na pinie.

Kod:
float Vin = analogRead(A0)/204.8; // A0 pin pomiarowy

Użycie stałej niecałkowitej od razu "przeniesie" działania na typ float.

AnalogComparator to może być funkcja do obsługi takiego modułu sprzętowego w atmedze. Dobrze sprawdź do czego służy. W twoim przypadku wystarczy w kodzie porównać obliczoną wartość z wartością, której oczekujesz. Nie trzeba do tego żadnej biblioteki.
 
Odpowiedź
#4
Dzięki za podpowiedzi. Jak widzisz nie do końca wiem co robię. Ważne, że to co napisałem działa i robi to czego potrzebuję. Czy dobrze i optymalnie to inna sprawa. To w sumie pierwszy mój kod na tej platformie. Jak widać zapewne to składak z kilku tutoriali z internetu dopasowany do moich potrzeb nie do końca z pełnym rozumieniem zagadnień. Na moją obronę dodam, że powstał w godzinę łącznie z poszukiwaniem tych wspomnianych tutoriali. Jeśli ktoś jest skłonny pomóc w ulepszeniu tego tak aby nadawało się do użytku to bardzo chętnie odwdzięczę się odpowiednią opłatą.
 
Odpowiedź
#5
Zainstaluj sobie bibliotekę EasyButton i spróbuj użyć z tymi przyciskami, to Ci wrzucę na bazie tego potem jakiś przykład.
Kod:
#include <EasyButton.h>

#define BUTTON_UP 2
#define BUTTON_DOWN 3

EasyButton buttonUP(BUTTON_UP);
EasyButton buttonDOWN(BUTTON_DOWN);

void onPressedUP() {
  Serial.println("ButtonUP has been pressed!");
}
void onPressedDOWN() {
  Serial.println("ButtonDOWN has been pressed!");
}




void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);

pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
buttonUP.begin();
buttonUP.onPressed(onPressedUP);
buttonDOWN.begin();
buttonDOWN.onPressed(onPressedDOWN);

}

void loop() {
  buttonUP.read();
  buttonDOWN.read();
}
Jak masz ogarnięte przyciski, to ja sobie zawsze dodaję formatkę czas, można to zrobić na wiele sposobów by zarządzać czasem, mi to pozwala obserwować, czy program się coś tam rusza, czy się nie zresetował, czy czas w nim płynie, jest zliczany i ciągle rośnie:

Kod:
#include <EasyButton.h>

#define BUTTON_UP 2
#define BUTTON_DOWN 3

EasyButton buttonUP(BUTTON_UP);
EasyButton buttonDOWN(BUTTON_DOWN);

uint32_t czasTeraz,czasPoprzedni,tik=10; //tik musi byc mniejszy niz 1000 i dzilic 1000ms na rowne czesci
uint8_t nTik,sekundy,minuty,godziny,dni; //liczniki tikow, sekund, itd.
bool fnTik,fsekundy,fminuty,fgodziny,fdni; //flagi zdarzen nowy tik, nowa sekunda,minuta, godzina, dzien
char napis[10];

void onPressedUP() {
  Serial.println("ButtonUP has been pressed!");
}
void onPressedDOWN() {
  Serial.println("ButtonDOWN has been pressed!");
}




void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);

buttonUP.begin();
buttonUP.onPressed(onPressedUP);
buttonDOWN.begin();
buttonDOWN.onPressed(onPressedDOWN);

}

void loop() {
   czas();
   
if (fnTik)
{
  buttonUP.read();
  buttonDOWN.read();
}

if(fsekundy) {
sprintf(napis,"%03d:%02d:%02d",godziny,minuty,sekundy);
Serial.println(napis);

}
   

}

void czas()
{
  czasTeraz=millis();
fnTik=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik) //tan napisany warunek jest odporny na "klątwe 50 dni millis()"
{
  czasPoprzedni=czasTeraz;
  fnTik=1;
  nTik++;
  if(nTik>=(1000/tik))
  {
    nTik=0;
    sekundy++;
    fsekundy=1;
     if (sekundy>=60)
    {
      sekundy=0;
      minuty++;
      fminuty=1;
      if (minuty>=60)
      {
        minuty=0;
        godziny++;
        fgodziny=1;
        if (godziny>=24)
        {
          godziny=0;
          fdni=1;
          dni++;
   
        }
      }
    }
  }
}
}
Tu są te flagi, to po prostu zmienne, które sobie w każdym loop zeruje, ale w wybranych, gdy od poprzedniego ustawienia minęło 10ms (taką sobie ustawiłem tu najmniejszą rozdzielczość i to wystarcza do sprawdzania stanu przycisków), 1s, 1m, 1h. W tym konkretnym obiegu loop, gdy jest nowa sekunda, minuta, flaga ma wartość 1 i coś z tym można zrobić. Prostymi operacjami można też sobie też to dalej rozwijać, gdy jest np. nowa sekunda, ale co czwarta, albo tylko 37 w każdej minucie. 
Ze zmiennymi do napięcia, to można oczywiście użyć float, ale lepiej w takim małym uC użyć zmiennej, która tak nie zamula. Napięcie można określić jako 2.345V, albo jako 2345mV, a do max 5V wystarcza zmienna int16, czyli o zakresie +/-32 tysiące. Niestety zakres przy obliczeniach by się przekręcił, więc trzeba dać int32, ale i tak jest szybciej niż z float. W Arduino to zresztą nie ma dużego znaczenia, tu wszędzie się wstawia floaty w bibliotekach, czasem to kuleje, ale nie ma musu z tego korzystać. Dodalem parę funkcji dla zaciemnienia całości i teraz by wystartować silnik wystarczy wcisnąć UP, nazwałem, że silnik ruszy w prawo przy takim ustawieniu pinów, bo nie pokazałeś schematu i tak to wygląda:
Kod:
#include <EasyButton.h>

#define BUTTON_UP 2
#define BUTTON_DOWN 3

EasyButton buttonUP(BUTTON_UP);
EasyButton buttonDOWN(BUTTON_DOWN);


uint32_t napiecieWylaczenia=3456,napiecieMierzone;   //mV

uint32_t czasTeraz,czasPoprzedni,tik=10; //tik musi byc mniejszy niz 1000 i dzilic 1000ms na rowne czesci
uint8_t nTik,sekundy,minuty,godziny,dni; //liczniki tikow, sekund, itd.
bool fnTik,fsekundy,fminuty,fgodziny,fdni; //flagi zdarzen nowy tik, nowa sekunda,minuta, godzina, dzien
char napis[10];
bool fButtonUP, fButtonDOWN, fSilnikStart,fSilnikStop;

void onPressedUP() {
  Serial.println("ButtonUP has been pressed!");
  fSilnikStart=1;
 
}
void onPressedDOWN() {
  Serial.println("ButtonDOWN has been pressed!");
 
}

void silnikRunR ()
{
digitalWrite(A4, LOW);
digitalWrite(A5, HIGH); 
}

void silnikRunL()
{
digitalWrite(A4, HIGH);
digitalWrite(A5, LOW); 
}

void silnikStop ()
{
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
}

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);

buttonUP.begin();
buttonUP.onPressed(onPressedUP);
buttonDOWN.begin();
buttonDOWN.onPressed(onPressedDOWN);

}

void loop() {
   czas();
   
if (fnTik)
{
  buttonUP.read();
  buttonDOWN.read();
}
// skoro mierzyles napiecie co 500ms, to zakladam, ze co 100ms bedzie jeszcze lepiej
if(fnTik and nTik%10==0) //czyli co nowy tik i gdy jednoczesnie liczba tikow jest podzielna przez x bez reszty, co x*fnTik ms
{
  napiecieMierzone = 5000UL*analogRead(A0) /1023;
  Serial.println(napiecieMierzone);
}

if(fsekundy) {
sprintf(napis,"%03d:%02d:%02d",godziny,minuty,sekundy);
Serial.println(napis);
}

if( fSilnikStart and napiecieMierzone<napiecieWylaczenia) //jesli zostal wcisniety przycisk i napiecie jest ponizej
{
    silnikRunR();
   
}
else       //zatrzymanie silnika i wyzerowanie flagi startu
{
  silnikStop();
  fSilnikStart = 0;
}



}

void czas()
{
  czasTeraz=millis();
fnTik=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik) //tan napisany warunek jest odporny na "klątwe 50 dni millis()"
{
  czasPoprzedni=czasTeraz;
  fnTik=1;
  nTik++;
  if(nTik>=(1000/tik))
  {
    nTik=0;
    sekundy++;
    fsekundy=1;
     if (sekundy>=60)
    {
      sekundy=0;
      minuty++;
      fminuty=1;
      if (minuty>=60)
      {
        minuty=0;
        godziny++;
        fgodziny=1;
        if (godziny>=24)
        {
          godziny=0;
          fdni=1;
          dni++;
   
        }
      }
    }
  }
}
}

Ale skoro nie umiesz programować to nie przewidziałeś wszystkiego i to nie jest wszystko co powinien robić program, sterownik jest na kilkadziesiąt amperów, takiego silnika nie powinno się ot tak zatrzymać, raczej hamować, nie można zmienić kierunków obrotów w każdej chwili, raczej trzeba najpierw zatrzymać silnik. Powinno się też dać wyłączyć silnik również przyciskiem, może być ten sam, raz się wciska to silnik rusza, drugi raz zatrzymuje, teraz z tą biblioteką nie ma też problemu, że będą drgania styków i że silnik dostanie czkawki co ma robić tysiąc razy/s po jednym dotknięciu przycisku. Powinien być WDT, by w razie zawieszenia zrobił reset i wystartował program od nowa.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#6
Wrzuciłem Twój szkic i mam kilka problemów:
1. BUTTON_DOWN nie działał wcale, czyli silnik nie startował. Dopisałem w 25 linijce fSilnikStart=1; tak jak dla BUTTON_UP to działa w obu kierunkach tak samo
2. BUTTON_UP działa ale napięcie na A0 wyłącza go od razu po starcie.
Po odłączeniu A0 silnik obraca się. Zdaje się, że pin pomiarowy albo muszę w jakiś sposób filtrować albo trzeba by dopisać jakieś opóźnienie w pomiarze bądź średnią pomiaru bo reaguje na zakłócenia. Kiedy A0 wisi w powietrzu a silnik się obraca wystarczy, że dotknę przewodu i silnik się zatrzymuje. Dodatkowo zdaje się, że przełączniki działają teraz na zboczu opadającym (czyli w chwili ich puszczania) co w tym zastosowaniu będzie raczej niepożądane. Gdzie można to zmienić bo jeszcze się nie doczytałem, ale może dojdę do tego sam Wink

EDIT:
Teraz dopiero zobaczyłem, że zaraz po pojawieniu się komunikatu o naciśnięciu przycisku pojawia się kolejny o wartości 5000 czyli tak jakby pomiar napięcia pokazywał 5V co by się zgadzało z moimi pomiarami po fakcie. W chwili startu na R_IS i L_IS połączonych razem pojawia się chwilowe 5.9V mierzone moim multimetrem. To w miarę dokładny i pewny pomiar bo i multimetr z tych z wyższej półki a nie z marketu. To sugeruje, że nie dość, że potrzebne jest jakieś opóźnienie 0,5s po naciśnięciu przycisku kiedy funkcja wyłączenia z powodu przekroczenia progu napięcia zadziała to jeszcze pozostaje problem zakłóceń które również są wychwytywane i brane pod uwagę. Z tym muszę chyba powalczyć już sprzętowo tak myślę.
 
Odpowiedź
#7
Kod:
void onPressedUP() {
  Serial.println("ButtonUP has been pressed!");
  fSilnikStart=1;

}
void onPressedDOWN() {
  Serial.println("ButtonDOWN has been pressed!");

}
No tak, nic nie robi, bo ma tylko drukować wciśnięcie na serial. Wystarczy CTR-C CTR-V i można zrobić to w drugą stronę, a przynajmniej tak jak miałeś to w kodzie. Ale przecież nie można włączać jednocześnie obrotów w obie strony, możesz się sam ze sobą umówić, że nie wciskasz przeciwnego przycisku jak trzymasz pierwszy, albo że czekasz aż się silnik zatrzyma zanim każesz mu się kręcić w drugą stronę. W programie nie powinno się zostawiać takich możliwości.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#8
(25-03-2024, 19:00)chavez napisał(a): EDIT:
Teraz dopiero zobaczyłem, że zaraz po pojawieniu się komunikatu o naciśnięciu przycisku pojawia się kolejny o wartości 5000 czyli tak jakby pomiar napięcia pokazywał 5V co by się zgadzało z moimi pomiarami po fakcie. W chwili startu na R_IS i L_IS połączonych razem pojawia się chwilowe 5.9V mierzone moim multimetrem. To w miarę dokładny i pewny pomiar bo i multimetr z tych z wyższej półki a nie z marketu. To sugeruje, że nie dość, że potrzebne jest jakieś opóźnienie 0,5s po naciśnięciu przycisku kiedy funkcja wyłączenia  z powodu przekroczenia progu napięcia zadziała to jeszcze pozostaje problem zakłóceń które również są wychwytywane i brane pod uwagę. Z tym muszę chyba powalczyć już sprzętowo tak myślę.

To jest max napięcie na wejściu - pojawienie się wyższego może uszkodzić procek. Pewnie na wejściu analogowym są diody zabezpieczające pomiędzy wejściem a liniami zasilania, normalnie spolaryzowane zaporowo, jedna zapezpiecza przed napięciem ujemnym, druga wyższym od zasilania. Jak wiadomo około 0.6-0.7V jest potrzebne by dioda zaczęła przewodzić. 0.9V to już jest dużo - sugeruje że diodą płynie znaczny prąd, który może podnieść zasilanie kontrolera.
Jak było podane w specyfikacji układu, co już też cytowałem pin IS jest wyjściem prądowym i dopuszczalne napięcie na nim to 45V. Do pomiaru tego prądu przetwornikiem ADC potrzebny jest rezystor, który zamieni prąd na napięcie. Widocznie taki rezystor jest za duży (albo go wcale nie ma). Trzeba dołączyć drugi równolegle by napięcie pomiarowe spadło. Konkretna wartość to już zależy od specyfikacji układu i ewentualnego rezystora, który już jest. Sprawdź rezystancje pomiędzy pinami IS a masą (oczywiście przy odłączonym module). Tak ogólnie to moduł składa się w dwóch układów, z którym każdy tworzy połowę mostka H i prąd płynący przez oba powinien być taki sam. Nie ma więc potrzeby łaczenia pinów IS - wystarczy sprawdzać jeden z nich. Maksymalny prąd na tym pinie to 7mA - by napięcie wtedy było 5V potrzeba rezystor 714 Ohmów, nie ma takich więc trzeba zastosować coś mniejszego, 680 Ohmów. Jeśli połączysz piny IS to dwa razy mniej, dostępny powinien być 330 Ohmów.

A jeśli chodzi o start - ja bym zorganizował to w ten sposób je dopóki przycisk jest naciśniety napięcie podawane jest na silnik a pobierany prąd jest jedynie wyświetlany (może być jedynie sprawdzany na jakieś wartości ekstremalne - typu zwarcie). Dopiero po puszczeniu przycisku prąd jest sprawdzany i uwzględniany w algorytmie - silnik jest trzymany włączony aż prąd osiągnie zaprogramowaną wartość. Sam układ zabezpiecza przed nadmiernym prądem.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości