Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega32][C]Jak "dopasować rozmiar" zmiennej?

A.T. 31 Aug 2011 10:29 2340 24
  • #1
    A.T.
    Level 20  
    Witam
    jestem początkującym i nie wiem jak się rozwiązuje tego typy problemy. Chodzi mi o sterowanie przetwornikiem DAC MAX534. Jeśli z dotychczas napisanego programu wychodzi mi zmienna, która przyjmuje wartości z zakresu od -10000.0 do 10000.0 i jest to float to jak przy jej pomocy mam sterować tym przetwornikiem którego rozdzielczość to 8 bitów. Jeżeli to ważne to dodam, że ta zmienna wychodzi z regulatora PID, a sterować chcę poprzez ten przetwornik DAC i mostek H silnikiem.
    Dziękuję i pozdrawiam.
    A.T.
  • #2
    tmf
    Moderator of Microcontroller designs
    Musisz mieć funkcję wiążącą wyjście z PID z wejściem DAC. W najprostszym przypadku, kiedy jest to zależność liniowa to z proporcji możesz to przeliczyć. Wyjdzie, że 128 odpowiada 0.0, 0 to -10000, a 255 to 10000. Z drugiej strony, skoro następuje tak znacząca redukcja, to zapewne same obliczenia w PID też można zredukować. Bo po co liczyć na float, skoro na końcu mamy 8-bitową zmienną?
  • #3
    gaskoin
    Level 38  
    Pokaż no ten twój PID, bo z reguły tak jak pisze tmf niepotrzebny Ci jest float.
  • #4
    A.T.
    Level 20  
    Dziękuję za odpowiedź. Niestety zbyt słabo rozumiem zasadę działania regulatora PID, żeby móc tam cokolwiek zmienić:/ Mam jeszcze jedno pytanie. Muszę jeszcze go nastroić. Czytałem już w Internecie jak się stroi regulatory ale że tak się wyrażę tylko na czuja. Czytałem też o jakichś metodach Zieglera Nicholsa itp ale są trochę zbyt skomplikowane:P
    Tylko, że na większości stron jest napisane, żeby stroić PID już na działającym urządzeniu. A ja zauważyłem, że jak zmienię te 3 stałe to również poziom wartości tych zmiennych wychodzących z regulatora na DAC się zmienia. Korzystając z metody proporcji musiałbym za każdym razem zmieniać tę proporcje?
    A.T.

    Dodano po 2 [minuty]:

    Tutaj jest kod regulatora. Nie jest pisany przeze mnie, tylko znaleziony w Internecie.
    Dziękuję i pozdrawiam
    A.T.

    #include <stdlib.h>
    #include <math.h>
    #include "pid.h"
    
    //-------------------------------------------------------------------------------------------------
    //
    // Definicja struktury ustawien PID - zmienna globalna
    //
    //-------------------------------------------------------------------------------------------------
    
    struct Settings_tag {
    	struct {
    		float P;
    		float I;
    		float D;
    		float angle_int_err;
    	} angle_PID;
    	
    	struct {
    		float P;
    		float I;
    		float D;
    		float diferential_int_err;
    		float diferential_old_err;
    	} diferential_PID;
    };
    struct Settings_tag settings;
    
    float phi1; // obrót pierwszego koła
    float phi2; // pbrót drugiego koła
    float dphi1; // prędkość obrotowa pierwszego koła
    float dphi2; // prędkość obrotowa drugiego koła
    
    int output1 = 0;
    int output2 = 0;
    //settings.angle_PIDa.P = 1.5;
    //settings.angle_PID.I = 10.0;
    //settings.angle_PID.D = 0.01;
    
    //-------------------------------------------------------------------------------------------------
    //
    // Procedura regulacji
    //
    //-------------------------------------------------------------------------------------------------
    
    void PID(void)
    {
    //
    //-------------------------------------------------------------------------------------------------
    // Prosty podwójny regulator PID
    //-------------------------------------------------------------------------------------------------
    //
    
    	float ster1 = 0; // sterowanie pierwszego silnika - zmienna pomocnicza
    	float ster2 = 0; // sterowanie drugiego silnika - zmienna pomocnicza
    
    	float angle_err = 0; // błąd odchylenia od pionu
    
    	float diferential_err = 0; // błąd różnicy prędkości kół
    	float diferential_deriv_err = 0; // różnica błędu różnicy prędkości kół
    
    	settings.angle_PID.P = ANGLE_PID_P; //1.5
    	settings.angle_PID.I = ANGLE_PID_I; //10.0
    	settings.angle_PID.D = ANGLE_PID_D; //0.01
    //
    ////////////////////////////////////////////////
    // Pierwszy regulator PID (odchylenie od pionu)
    //
    
    	angle_err = state.alpha; // błąd odchylenia od pionu
    	settings.angle_PID.angle_int_err += angle_err; // całkowanie błędu
    
    // Sprawdzanie granic całkowania
    
    	if(settings.angle_PID.angle_int_err > 0.1) settings.angle_PID.angle_int_err = 0.1;
    	if(settings.angle_PID.angle_int_err < -0.1) settings.angle_PID.angle_int_err = -0.1;
    
    //
    ///////////////////////////////////////////////
    // Drugi regulator PID (różnica prędkości kół)
    //
    
    	diferential_err = dphi1 - dphi2; // błąd różnicy
    	settings.diferential_PID.diferential_int_err += diferential_err; // całkowanie błędu
    
    // Sprawdzanie granic całkowania
    
    	if(settings.diferential_PID.diferential_int_err > 10) settings.diferential_PID.diferential_int_err = 10;
    	if(settings.diferential_PID.diferential_int_err < -10) settings.diferential_PID.diferential_int_err = -10;
    
    //
    
    	diferential_deriv_err = diferential_err - settings.diferential_PID.diferential_old_err; // różniczkowanie błędu
    
    //
    /////////////////////////////////////////////
    // Wyliczanie sterowania dla pierwszego koła
    //
    
    	ster1 = (angle_err * settings.angle_PID.P + state.dalpha * settings.angle_PID.D + settings.angle_PID.angle_int_err * settings.angle_PID.I)
    		+ diferential_err * settings.diferential_PID.P + settings.diferential_PID.diferential_int_err * settings.diferential_PID.I
    		+ diferential_deriv_err * settings.diferential_PID.D;
    
    //
    ///////////////////////////////////////////
    // Wyliczanie sterowania dla drugiego koła
    //
    
    	ster2 = (angle_err * settings.angle_PID.P + state.dalpha * settings.angle_PID.D + settings.angle_PID.angle_int_err * settings.angle_PID.I)
    		- diferential_err * settings.diferential_PID.P - settings.diferential_PID.diferential_int_err * settings.diferential_PID.I
    		- diferential_deriv_err * settings.diferential_PID.D;
    
    	output1 = ster1;
    	output2 = ster2;
    
    }


    Dodano po 3 [minuty]:

    Dodam jeszcze, że jest to podwójny regulator. Projektem jest robot balansujący. Czyli do regulatora wchodzi zmienna state.alpha - odchylenie od pionu oraz state.dalpha - prędkość tego odchylenia.
  • #5
    gaskoin
    Level 38  
    Ło matko skąd to masz :D

    W bardzo prostej formie może to wyglądać tak:

    Code: c
    Log in, to see the code


    Trzeba jeszcze dodać sprawdzanie granic całkowania. Możesz zmniejszać wzmocnienie Kr żeby się wstrzelić w 0-255, (albo zwiększać jak sterowanie będzie działało w zakresie np 0-10% :P). Nastawy podane są dla pewnego obiektu, w rzeczywistości musisz tam podać nastawy dla swojego.

    Dałem consty w programie bo w ARMach tak się zmienne wrzuca do flasha, w AVRach wygodniej będzie zrobić define'y :)
  • #6
    A.T.
    Level 20  
    Bardzo dziękuję za pomoc oraz za wrzucenie uproszczonej wersji PIDa. Niestety dalej mam problem. Nie rozumiem od czego zależą granice całkowania i jakie ja powinienem wpisać.
    Pozdrawiam
    A.T.
  • #7
    nsvinc
    Level 35  
    To się nazywa anti-windup i służy do tego, aby (w tym przypadku) zmienna "Int" nie osiągała zbyt wysokich wartości niwelując w ten sposób prawidłowe działanie regulatora. Najłatwiej zrobić to dwoma ifami (dolny+górny) które przytną zakres liczb jakie może przyjąć zmienna Int...
  • #8
    gaskoin
    Level 38  
    Aaa i jeszcze jedno - zamiast pajacować z kr, przy strojeniu (jeżeli będzie strojone Z-N albo QDR) do obliczeń za sygnał wejściowy nie podajesz napięcia tylko "kod" tego napięcia z przetwornika, wtedy nic nie trzeba przeliczać.
  • #9
    A.T.
    Level 20  
    Dziękuje:)
    Co się podaje na zmienne CV i SP? Nie rozumiem w którym miejscu mam wpisać moje odchylenie i prędkość odchylania:/
  • #11
    A.T.
    Level 20  
    Kurcze teraz to już coraz mniej rozumiem:/
    Nie wiem czy dobrze wyjaśniłem jak to ma działać:)
    Projektem jest robot balansujący. Pobieram wartości z akcelerometru i żyroskopu. Przeliczam wartości z akcelerometru na odchylenie od pionu. I teraz te dwie informacje tzn. odchylenie i prędkość kątową wrzucam do filtra kalmana. Z filtra otrzymuję odfiltrowane odchylenie od pionu oraz prędkość tego odchylenia. I te dwie zmienne muszę podać na regulator PID, z którego otrzymuję dwie zmienne sterujące dwoma silnikami. Silnikami steruję poprzez przetwornik DAC MAX534 i mostek H sterowany prądowo.
    Dlatego teraz nie rozumiem do których zmiennych tego regulatora mam wpisać te wartości, które otrzymuję po FK? I jak mam przerobić ten kod regulatora aby dawał sygnały na 2 silniki(zmienne output1 i output2)?
    Proszę o pomoc. Sam sobie niestety nie potrafię poradzić, ponieważ tak sobie rozumiem zasadę działania regulatora PID:/
    A.T.
  • #13
    A.T.
    Level 20  
    Jak każdą? Przecież odchylenie jest tylko w jednej osi.
  • #14
    LordBlick
    VIP Meritorious for electroda.pl
    Nie podałeś w sumie żadnego rysunku i myślałem, że jest to bardziej zaawansowana wersja... :)



    Tym niemniej, jeśli robisz coś w rodzaju segway-a to i tak jest jeszcze jedna oś - skręt, czyli żyroskop, sterująca proporcjami pomiędzy poszczególnymi kołami...
  • #15
    A.T.
    Level 20  
    Zgadza się robię coś ala segwaya. Tylko skręcać on na razie nie będzie, zależy mi tylko na tym, żeby ustał w miejscu. Bardzo proszę o odpowiedź na moje pytania, które zadałem wyżej.
    A.T.
  • #17
    A.T.
    Level 20  
    Dzięki za wrzucenie tego opisu regulatora. Teraz już rozumiem trochę więcej. Tylko w tym opisie autor dostawał informacje o pracy silników jedynie z enkoderów. A w moim przypadku to są także enkodery ale jeszcze głównym źródłem informacji o sterowaniu silnikami są dane o odchyleniu i szybkości tego odchylenia. W regulatorze PID, który ja tutaj wrzuciłem jest to w jakiś sposób połączone i nazwanie podwójnym regulatorem. I tego właśnie dalej nie rozumiem, jak uwzględnić dwa źródła informacji w regulatorze.
  • #19
    gaskoin
    Level 38  
    Widzę, że kolega to raczej by wolał dostać gotowe klocki i je sobie poskładać nieważne jak działa. Nie ma tak ! :)
  • #20
    A.T.
    Level 20  
    Bazując na Waszych przykładach postarałem się napisać kod regulatora PID. Na razie nie posiada on obsługi enkoderów, steruje on silnikami jedynie na podstawie danych z akcelerometru i żyroskopu - odchylenie i prędkość odchylania. Poniżej wrzucam kod, bardzo bym prosił o sprawdzenie czy w ogóle ma to szanse działać.
    Pozdrawiam
    A.T.
    Code: c
    Log in, to see the code
  • #21
    gaskoin
    Level 38  
    Nie ma.

    Po pierwsze nie kapuje po co Ci ten float. Nie musisz przeliczać danych z akcelerometru i żyroskopu na floaty, możesz wrzucać nieprzeliczone dane jako inty.

    Po drugie - Nastawy które Ci podałem są z innego układu (wirnik z zawieszeniem magnetycznym), więc na 99% dla Ciebie będą złe.

    Po trzecie - żeby cokolwiek regulować musisz podać jaka regulowana wartość ma być. W Twoim PIDzie skąd regulator ma "wiedzieć" jakie ma dać sterowanie skoro "nie wie" jaka jest wartość zadana ? W Twoim kodzie błąd jest stały (i bez sensu)
    więc sterowanie będzie ciągle narastało. Zobacz mój kod - ja tam steruje jedną wielkością i podaje dwa parametry.

    Chyba musisz doczytać o PIDzie, bez wiedzy jak to działa bez sensu jest to w ogóle implementować skoro nie rozumiesz tego wzoru.
  • #23
    A.T.
    Level 20  
    Dziękuję za odpowiedź.
    Floaty już zamieniłem na inty. Jeśli chodzi o wartości stałych to wiem, że muszą być dobrane indywidualnie. Dlatego na razie zostawiłem Twoje. Nie rozumiem tylko ostatniej uwagi. Dlaczego błąd jest stały. Przecież zmienna alpha to jest informacja z akcelerometru, nie jest to wartość stała. Wartość zadaną wziąłem pod uwage, ale ponieważ wydaje mi się że wynosi 0(zerowe odchylenie aby robot stał) to bez sensu jest ją odejmować.
    Dziękuję za pomoc.
    A.T.
  • #24
    bolek
    Level 35  
    Nie ma znaczenia że masz 0 jako zadane, ważne ile masz aktualnie i ile masz mieć, czyli twoja odchyłka od zadanej.
    Jeśli np akt=5, zad=0, wzmocnienie KP=1 to na wyjściu masz -5. Jeśli KP=1.5 to dostajesz -7.5. A jeśli masz KP=3.47 to ile będzie na wyjściu?

    Teraz I.
    Dajmy na to że akt i zad j.w. Przy całkowaniu najczęściej zmienia się wzmocnenie i czas całkowania. Tak więc niech wzmocnienie będzie Ki=1, a czas=3s. Tak więc twoje wyjście będzie się zmieniać o 5 co każde 3 sekundy. Jeśli Ki=0.42 to co 3s zmieni się o 2.1

    Na temat D doszperaj sam i napisz jak rozumiesz. Patrz do innych kodów a nie nie dziwne wzory profesora na PID bo skubańce specjalnie tak je napisali żeby wydawało się abstrakcją.
    Ogólnie na wyjściu masz sume wszystkich członów (P+I+D), choć nie jest to regułą bo są np tylko P+I (zależy co kto ootrzebuje)
    Jak to ogarniesz to od razu zabierz się anty windup, po prostu przestajesz zwiększać całkę gdy osiągnie maksymalną wartość wyjścia i zmniejszać gdy osiągnie min.
    A jeszcze lepiej gdy każdy człon ograniczysz do skrajnych wartości jaki może osiągnąć twój element wykonawczy. Na deser procedura strojenia. Podpowiem ci też że skoro masz silniki to będziesz pracował na liczbach ze znakiem (np 0=stoi, + to w rawo, - to w lewo)
  • #25
    A.T.
    Level 20  
    Ja rozumiem D, że to jest iloczyn stałej Kd i różnicy (błąd - błąd poprzedni).
    Jednak dalej nie rozumiem gdzie jest błąd w tym co ja napisałem:/
    Nawet wgrałem to do procesora i chyba działa tak jak powinno. Gdy płytka z czujnikami jest w poziomie to wartość zmiennej output wynosi 126-128, gdy przechylę w którąś stronę to zmierza do 0 lub do 255, tak jak powinna.
    Bardzo proszę o pokazanie w której części kodu jest coś błędnego.
    Code: c
    Log in, to see the code