Skocz do zawartości

lubniewicz

Użytkownicy
  • Zawartość

    43
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    2

lubniewicz wygrał w ostatnim dniu 19 sierpnia

lubniewicz ma najbardziej lubianą zawartość!

Reputacja

16 Dobra

O lubniewicz

  • Ranga
    3/10

Informacje

  • Płeć
    Mężczyzna

Ostatnio na profilu byli

Blok z ostatnio odwiedzającymi jest wyłączony i nie jest wyświetlany innym użytkownikom.

  1. Rozumiem. Będę czekał. Jest dużo darmowych programów na Androida które można wykorzystać do komunikacji np roboremo. Może lepiej z tego skorzystaj?
  2. Jestem już, nie mogłem wcześniej odpisać - obowiązki zawodowe. Robot będzie już stał na ... kołach. Robot będzie trzymał około 0 st. lecz będzie uciekał na boki bo jeszcze nie będzie miał PID prędkości, który będzie zadawał kąt. Pamiętaj, że te nastawy które teraz zrobimy mogę ulec delikatnie zmianie, ponieważ dopiero finalną regulacje zrobi się mając w sumie 3 PID. Więc nie zdziw się jak będziemy musieli jeszcze te nastawy zmienić. Będę mówił w skrócie o poszczególnych członach jako P, I, D. Jak powiem że masz zwiększyć np D to będę miał na myśli zwiększenie "ram_rejestr.p_kd". Proponuje na razie nie zakładać blokady WINDUP. Proponuje jednak aby kontrolować, aby suma błędów nie była za duża. To wyjdzie w regulacji. Ok zaczynamy: Ustaw kąt zadany na 0st. Zlikwiduj ograniczenie windup i wyświetlaj po UART jaki masz wynik na całym członie P, I, D oraz suma błędów (osobna dla każdego). Kąta już nie musisz wyświetlać po UART. Robota postaw pionowo. Zwiększaj P aby robot zaczął oscylować w pobliży 0st, mam tutaj na myśli np w granicy od -5st do 5st. Ważne aby oscylował. Trzymaj robota w pionie, dłońmi trzymaj go z tyły i z przodu aby nie pojechał. Robot ma oscylować. Jak będzie oscylował to zmniejsz P tak aby już nie oscylował. To ma być tak na styk. Wiem, że mój opis jest mało dokładny ale lepiej nie umiem tego opisać. Resztę roboty przejmie człon I. Zwiększaj I aby robot znowu zaczął balansować. Jednocześnie sprawdzaj jaką masz sumę błędu. Nie może być ta wartość za duża. Szczegółowo o tym później napiszę. Teraz zwiększaj D, aż oscylacje będą mniejsze, krótsze. D można porównać do amortyzatora samochodowego. Jak dobrze to ustawisz to robot powinien trzymać około 0 stopni i powoli odjeżdżać w tył lub przód. Mam tutaj na myśli, że może i musi przyspieszać w dany kierunek i ma trzymać około 0st. Nie może oscylować w miejscu ma delikatnie odjeżdżać w tył lub przód. Jak to zrobisz przejdziemy dalej. PS. W żadnym wypadku dane wysłane po UART nie mogą blokować częstotliwości wywołania procesu 10ms. Ja to sprawdzałem na analizatorze stanów logicznych. To jest bardzo ważne.
  3. W razie problemów, wątpliwości pisz. Przed przystąpieniem może zobacz sobie ciekawy wykład o PID. Dużo Tobie to powie:
  4. Nie dajesz -10. To było dla mnie takie ułatwienie aby nie wpisywać dużej wartości ram_rejestr.p_kd. Mam tutaj na myśli, że zamiast wpisać 500, ja wpisałem tylko 50. Minus był dlatego, że wcześniej miałem: position.gyro_0 = gyro_()*(-0.01). W Twoim przypadku nie patrz na to. Powiem Tobie o co chodzi. Odejmuję od napięcia jakie mogę otrzymać maksymalnie (i jakie miałem w trakcie regulacji) czyli 14.4V wartość aktualnego napięcia czyli np 12.1V mnożę to przez współczynnik i dodaję +1. Czyli to jest zwykła funkcja liniowa. Tą funkcję linową i współczynnik wyznaczyłem doświadczalnie. Wyglądało to tak że zebrałem parametry prąd, napięcie, moc dla danych wartości PWM. Teraz niezależnie od napięcia na akumulatorze silniki pobierają stałą moc. Jest podbijane napięcie poprzez zwiększenie PWM. Tak w skrócie aby nie zaciemniać podam przykład: PWM 128 przy napięciu 14.4V = 7.2V, natomiast już dla napięcia dla aku 11.2V = 5.6V. Rozumiesz już. My musimy niezależnie od naładowania aku utrzymać stałe napięcie przy danym PWM. Oczywiście najlepiej zmierzyć prąd i napięcie. Nie zawracaj sobie na razie tym głowy. To było takie moje usprawnienie, bo widziałem, że robot zaczął się inaczej zachowywać przy pełnym i pustym akumulatorze. Na razie odpuść temat później sam sobie zrobisz kompensację. Nie sugeruj się moimi współczynnikami sam sobie to kiedyś zrobisz. Po prostu z: temp = -constrain((pTerm + iTerm + dTerm)*multipler, -power, power) usuń multipler. Chcę Tobie tylko wskazać na problem ze regulator może inaczej działać przy innym zasilaniu niż jak miałeś w czasie regulacji. Tak, wyplucie. Pisałem skrótami bo wiem, że to zrozumiesz.
  5. To dobrze, bo dałeś mi niezłą łamigłówkę. Lecimy dalej. Robimy zgodnie z umową regulator kąta. Czyli na wejście regulatora podajemy kąt obliczony i kąt zadany. Kąt zadany to w chwili obecnej będzie 0 stopni. Później zrobimy kolejny regulator który będzie obliczał ten kąt. Podsumowując tworzymy regulator PID, wejście aktualny kąt, oraz kąt zadany na sztywno 0 stopni. Na wyjściu musimy otrzymać PWM. Może później damy jakiś filtr dolnoprzepustowy, zobaczymy. Tam też dodamy korektę po napięciu, bo wiadomo, że im mniejsze napięcie tym musimy dać więcej PWM, ponieważ regulator się rozjedzie. Obliczmy błąd: errors = (targetPosition - currentPosition); Obliczony błąd sumujemy: integrated_errors += errors*1.00; Wprowadzamy Windup błędu (czyli granicę do której sumujemy błąd. Jest to ważne aby człon całkujący nie nasycił się za mocno) integrated_errors = constrain(integrated_errors,-ram_rejestr.i_lim, ram_rejestr.i_lim); Człon proporcjonalny pTerm = ram_rejestr.p_kp *errors*1.00; Człon całkujący iTerm = (ram_rejestr.p_ki/10.00) * integrated_errors*1.0; Człon różniczkujący (ten parametr -10 to tylko dlatego aby zmienna "ram_rejestr.p_kd" była mniejsza) dTerm = ram_rejestr.p_kd * parametry.angular_velocity * (-10.00); Wprowadzamy ograniczenie - zmienna 8 bit PWM temp = -constrain((pTerm + iTerm + dTerm)*multipler, -power, power) Korekta po napięciu multipler = (144.0000 - parametry.u12/100.0000)*0.0086+1.0000; Wynik return temp; Dobra możesz działać. Myślę, że się domyślisz. Zrób dodatkowo aby: ram_rejestr.p_kp, ram_rejestr.p_ki, ram_rejestr.p_kd czyli nastawy regulatora, oraz ram_rejestr.i_lim czyli windup można było ustawiać zdalnie. Jak to zrobisz to powiem Tobie jak to wyregulować, a potem zrobimy kolejne dwa regulatory. PS. Ten PID ustaw w tym samym procesie, poniżej tego filtru komplementarnego. Oczywiście te mnożniki w członach "x10" i "x-10" możesz wywalić. Po prostu nastawy będą dziesięć razy mniejsze, nie chciałem się bawić w float .
  6. Dla potomnych napisz co zmieniłeś. Co powodowało problem.
  7. Dobra powoli. Zaraz Tobie to wytłumaczę. Wysyłasz dane po uart i to ma wpływ na obliczenia. Masz przez to laga. Wydaje mi się, że ten proces nie odpala się 100 razy na sekundę. Przez to masz laga. Pamiętaj, że tam masz dt czyli sampling rate. Jak proces się nie wyrabia to obliczenia idą w łeb. Proszę zrób test. Zobaczy czy przez 10 sekund proces odpalił się 1000 razy. Wszystko zostaw, tylko licznik dodaj.
  8. Dobrze, że przesłałeś mi fotkę. Według mnie prędkość kątową powinieneś mierzyć po osi Y, a nie X. Twoje poprzednie pomiary wskazują jakby gyro łapał coś przypadkowego.
  9. Analizuje Twoje wykresy i wydaje mi się, że niepotrzebnie zmieniłeś wartość gyro mnożąc -1. Wiesz to zależy jak masz ustawiony gyro. Powinno to wyglądać tak jak na wykresie poniżej. PS. Według mnie poprzednie ustawienie było lepsze ponieważ obecnie kąt z filtra ma mniejszą amplitudę. Dlatego bez wykresów ciężko się zorientować czy wszystko dobrze zrobiliśmy. Zmień na 1 i może przesunięcie będzie mniejsze. Jak będziesz gotowy polecimy dalej. A na żyroskopie jakie masz ustawione "Full scale range (dps)" zakres w stopniach na sekundę, im mniej tym większa dokładność, ale po przekroczeniu zakresu może się nasycić.
  10. Kąt z akcelerometru dobrze pokazuje. To znaczy w przedziale od -90 do 90 stopni, tak ma być do regulatora. Nie jest potrzebny kąt do góry nogami. Odnośnie skalowania to wynika to z rozdzielczości, wykonałem to tak: void calcgRes() { switch (gScale) { case G_SCALE_245DPS: gRes = ((int32_t)245*100000) / 32768; break; case G_SCALE_500DPS: gRes = ((int32_t)500*1000) / 32768; break; case G_SCALE_2000DPS: gRes = ((int32_t)2000*1000) / 32768; break; } } float calcGyro(int16_t gyro) { // Return the gyro raw reading times our pre-calculated DPS / (ADC tick): return (((float)gyro * gRes)/(int32_t)100000.0); // /100 } float gyro_() { readGyro(); return calcGyro(gx); } Podsumowując to Twoje skalowanie: gyroX = (float)gyro.x/131.072; //skaluje gyro to jest to samo co ja miałem ale powyżej, lecz już na sztywno ustalony współczynnik 131.072. Dobra szkoda czasu nie będziemy wnikać bo wydaje się, że działa. Odczyt kąta z gyro mam podobnie: position.gyro_0 = gyro_()*(-0.01); Wracając do Twojego pytania to tak można odczytać kąt z gyro. Jest to nawet niezbędne przy szybkich ruchach, ponieważ accel podaje wtedy błędne dane. Dryf jest w tym przypadku pomijalny. Całkowałeś go bez sensu. Filtr masz dobry, ja dałem współczynnik 0.03 zamiast twojego 0.02. Proszę Ciebie abyś zrobił jeszcze raz test. Tylko, że zamiast na wykresie całkowane gyro to daj bieżąca wartość gyro i pomnóż to np razy 100 aby na wykresie było ładnie widać. Chcę zobaczyć, jak zmienia się odczyt z accel, gyro i komplementarny. Odczyt z gyro jest niezbędny przy szybkich ruchach robotem. Możesz eksperymentalnie zmienić współczynnik na 0.03. Jak to zrobisz to polecimy dalej. Będziemy robić regulator kąta.
  11. To bardzo dobrze powinno wystarczyć. Zrób tak abyś miał trzy zmienne z prędkością obrotowa to jest impulsy dla lewego koła, prawego i średnia. Następnie kolejna rzeczą do zrobienia to odczyt kąta. Mianowicie musisz połączyć prędkość kątowa i kąt obliczony z akcelerometru. Mozesz to zrobić poprzez filtr kalmana lub komplementarny. Ma to na celu aby przy szybkich ruchach robotem nie dochodziło do przeklamania kąta pochylenia. Jest to druga najważniejsza rzecz po tych enkoderach. Jak to będzie zrobione źle to nic nie wyregulujesz. Ja to zrobiłem na komplementarnym. Poniżej to testowałem w twn sposób ze wysyłałem dane po uarcie do programu który rysował mi wykres. To jest najlepsza metoda w według mnie. Skąd bedzie wiadomo ze filtr działa? Jak bedziesz wolno zmieniał kąt to wykres musi być gładki, jak szybko - wręcz szarpał to także kąt ma być gładki, nie może być tak ze jak robot przechylasz ze 100 na 80 to nagle po drodze masz 120, a jak zatrzymujesz to powiedzmy 50 stopni. Mam tutaj na myśli to że ma być dokładnie odwzorowany ruch robota. Bez przeklamania. Dla robota enkodery i kąt to są "oczy" . Zapomniałem dodać ze pomiar i obliczenia wrzuć do tego samego procesu 10 ms ale pod funkcja enkoderow. Tak więc w procesie będziesz mial, odczyt prędkości z enkoderow, obliczenie kąta, a potem zrobimy regulator. Jak bedziesz mial problemy i wątpliwości to pisz. Ps. Dla lepszego rozrachunku możesz w programie przyjąć 90 stopni za pionową postawe robota.
  12. Ps. Z tymi 24bit oczywiście przesadziłem... Zobacz jakie drobne ruchy musisz wykryć. O to mi właśnie chodzi.
  13. Zmień na 10ms. I podaj mi ile masz impulsów na tą jednostkę czasu przy tym jak delikatnie i powoli ręką obracasz koło. To jest bardzo ważny moment i trzeba to dobrze dobrać, bo inaczej bedzie potem flustracja i nerwy przy regulacji. Ponadto moim zdaniem niepotrzebnie zastosowałes timer chyba 24 bitowy, na spokojnie pójdzie na 8 bitach. Zwiększenie rozdzielczości powoduje ze masz gigantyczny offset. Nie wprowadzaj offsetu, według mnie to jest błąd. Wyobraź sobie taką sytuację, że regulator ustalił pwm na tak małą wartość że silnik nie pracuje ale jednak okazuje się że koło może sie obracać z mniejszym oporem bo silnik delikatnie je napędza. Chodzi mi o to, że nieraz potrzebne jest takie subtelne sterownie pwm, a w przypadku offsetu silnik ma obcinana taka charakterystykę, to znaczy regulator steruję ale pwm jest obcinany offsetem. Jak to zrobisz polecimy dalej.
  14. Dobrze może tak być, ale wydaje mi się ze 5 ms to za szybko. Zrób test obracaj powoli kołem i zobacz ile masz impulsów zliczanych przez te 5ms. Przy bardzo wolnym obracaniu dobrze miec minumum 10 impulsów. Ps. Żebyśmy sie zrozumieli masz już prędkość obrotowa dla 2 kół oddzielnie, jak obracasz w jedna to masz ze znakiem + a w druga ze znakiem -? Jak to sprawdzisz to przejdziemy dalej. Jako parametr do PID proponuje zastosować właśnie ilość impulsów w tych 5ms. Podaj mi ile masz impulsów w 5 ms przy maksymalnych obrotach i bardzo bardzo minimalnych. Musimy poznać dolny próg. Często robot balansuje i wykonuje bardzo małe ruchy musimy to wykryć.
  15. Ok. Czyli rozumiem że nie masz jeszcze nic napisane? Proponuje na sam początek obsłużyć enkodery. Czyli stwórz "proces" który będzie uruchamiany co 20 milisekund. Będziemy tam wszystko wrzucać. Czyli wykorzystaj jeden z timerów sprzętowych, nie będziemy się bawić na razie w programowe. W kwestii enkoderów to możesz to zrobić na dwa sposoby, ale z przerwaniami albo za pomocą kodu Graya. to już zależy od Ciebie. Ja stosuje kod Graya bodaj w pętli głównej. Podsumowując musisz napisać obsługę enkoderów na poszczególne koła. W jedną stroną inkrementacja, a w drugą dekrementacja. W ten "proces" 20ms wrzucasz funkcję, w ciele funkcji kopiujesz odczytane obroty ze zmiennej tymczasowej do zmiennej którą później wykorzystamy do PID, a następnie zerujesz zmienną tymczasową aby znowu się napełniła od obrotów. Najlepiej do tego celu stosować klasy. Chyba zrozumiałeś Dane sobie wysyłaj po uarcie aby zobaczyć czy wszystko działa. Jak będziesz miał już odczyt z kół to przejdziemy dalej.
×
×
  • Utwórz nowe...