Dynamiczne wyważanie pędnika statku kosmicznego

14

Kosmos jest w mojej grze przeznaczony do budowania przez gracza z dowolną liczbą pędników przymocowanych w dowolnym miejscu z dowolnym obrotem. Obecnie mam trochę brudnego kodu, aby obrócić statek pod danym kątem (przyspieszanie i zwalnianie).

Oto przykład symetrycznego statku skierowanego w stronę wskazującą czerwoną linię, która ma obrócić się w lewo.

Statek

Jednak, jak można sobie wyobrazić, w zależności od tego, gdzie gracz umieścił pędniki, czasami niepożądane siły liniowe wpływają na statek. W takim przypadku statek zaczyna iść naprzód.

Zastanawiam się, czy można znaleźć maksymalny ciąg, jaki może zastosować pędnik, aby nie powodować prędkości liniowej. (W powyższym przypadku byłoby to niemożliwe, ponieważ nie ma nic, co mogłoby przeciwdziałać siłom z tylnych pędników, a przednie zabijają się nawzajem).

Do tej pory wymyśliłem formułę określającą „efektywność obrotu”, np. Ile obrotu powstaje w związku z ruchem liniowym.

a - wektor pozycji do pędnika a b - wektor pozycji do pędnika b v1 - siła z pędnika a v2 - siła z pędnika b

wydajnośćDelta = a. krzyż (v1) / | v1 | - (a. krzyż (v1) + b. krzyż (v2)) / | v1 + v2 |

, w zasadzie „a.cross (v1 * t) / | v1 |” ma być efektywnością obrotu. Następnie odejmujemy ją od łącznej wydajności obrotów silników pędnych, aby sprawdzić, czy warto odpalić nowy pędnik.

Problem pojawia się, gdy zdaję sobie sprawę, że pędniki nie powinny być włączone / wyłączone, ale mogą zmieniać swój ciąg od 0 do 1. I jak się poruszać, gdy gracz chce, aby statek ruszył naprzód. Oczywiście, musiałaby istnieć równowaga, ile obrócić / przesunąć.

Nie jestem naukowcem od rakiet, więc mam nadzieję, że znajdzie się ktoś, kto może mi powiedzieć, czy można obliczyć przepustnicę każdego pędnika w ten sposób i popchnąć mnie we właściwym kierunku.

Dziękuję Ci za poświęcenie czasu! / Kim

Kim
źródło
3
Zacząłem na tej samej ścieżce, ale przy wielu konfiguracjach nie można zarówno obracać, ani tłumaczyć. Czy zabierasz rotację? Czy pozwalasz na tłumaczenie? Ostatecznie to użytkownik projektującego statek. W moim demo tego podrobiłem to. Powiązane: gamedev.stackexchange.com/questions/58216/… , gamedev.stackexchange.com/questions/40615/…
MichaelHouse
Poszedłem podobną ścieżką i skończyłem pisać demo na tej stronie . Podczas przesuwania silników odrzutowych (przeciągnij je na statek, aby ustawić pozycję i moc), rysuje trzy kształty. Intuicja polega na tym, że wszystkie możliwe ruchy można traktować jako punkt w przestrzeni 3D (x, y, obrót), a ograniczenie do 0-1 jest ograniczeniem w tej przestrzeni. W rezultacie otrzymujesz kształt 3d zawierający wszystkie możliwe ruchy. Jeśli nie chcesz prędkości liniowej, patrzysz na linię (x = 0, y = 0) w tej przestrzeni (Q, W, E, S wszystkie 0 w moim demo)
amitp

Odpowiedzi:

7

Zakładam, że masz fizycznie poprawny ruch dla swojego statku, ponieważ w przeciwnym razie ta analiza nie zostanie przeprowadzona. Potrzebujesz czegoś silniejszego niż wydajność, aby poprawnie rozwiązać ten problem.

Każdy pędnik wytworzy dwa efekty na ruch statku: liniowy i kątowy. Można je rozpatrywać niezależnie. Jeśli pędnik wytwarza siłę fw kierunku diri jest przesunięty względem środka masy o wektor r(nie środek geometryczny ani środek duszka!), Wówczas wpływ na składową liniową jest:

t = f * dir // f is a scalar, dir is unit length

Moment obrotowy wpływa na prędkość kątową:

tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product

tjest wektorem siły (tj. ciągiem liniowym). taujest znakiem skalarnym, który podzielony przez moment bezwładności masy da przyspieszenie kątowe. Istotne jest to, że diri rto zarówno w tej samej przestrzeni współrzędnych, czyli zarówno w lokalnym układzie współrzędnych lub zarówno we współrzędnych światowych.

Całkowite liniowe przyspieszenie statku jest podane jako suma wartości tdla każdego pędnika podzielona przez masę statku. Podobnie przyspieszenie kątowe jest po prostu sumą momentów obrotowych podzieloną przez moment bezwładności masy (który jest kolejnym skalarem). Statek się nie obróci, jeśli całkowity moment obrotowy wynosi zero. Podobnie nie porusza się, jeśli całkowity ciąg wynosi zero. Przypomnijmy, że moment obrotowy jest skalarem, ale ciąg (suma t's) jest wektorem 2D.

Chodzi o to, że teraz możemy napisać nasz problem jako program liniowy . Powiedz najpierw, że chcemy, aby nasz statek zawrócił bez ruchu . Mamy zmienną dla każdego steru strumieniowego, $ x_1, x_2, ... $, która jest ilością ciągu, który zapewni ster. Jeden zestaw ograniczeń to:

0 <= x_i < fmax_i  //for each i

gdzie fmaxjest maksymalna siła dla tego pędnika (pozwala nam to mieć mocniejsze lub słabsze). Następnie mówimy, że obie równości:

0 = Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y

To koduje ograniczenie, że nie zastosujemy przyspieszenia liniowego, mówiąc, że całkowity ciąg jest równy zero (ciąg jest wektorem, więc po prostu mówimy, że każda część jest zerowa).

Teraz chcemy, aby nasz statek zawrócił. Przypuszczalnie chcemy to zrobić tak szybko, jak to możliwe, dlatego chcemy:

max (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>

Rozwiązanie tych problemów przy x_ijednoczesnym zaspokojeniu nierówności i równości powyżej, przy maksymalizacji powyższego podsumowania, da nam pożądany ciąg. Większość języków programowania ma dla nich bibliotekę LP. Po prostu włóż w to powyższy problem, a otrzymasz odpowiedź.

Podobny problem pozwoli nam poruszać się bez zawracania. Powiedzmy, że ponownie zapisujemy nasz problem w układzie współrzędnych, w którym chcemy poruszać się w dodatnim kierunku x. Zatem ograniczenia są następujące:

0 <= x_i < fmax_i  //for each i
max Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y
0 = (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before

Z ograniczeniem, że pędniki mogą wytwarzać pchnięcie tylko w jednym kierunku, będą ograniczenia dotyczące rodzajów obrotów i prędkości liniowych, które będziesz w stanie osiągnąć. Ujawni się to jako rozwiązanie 0 = x_1 = x_2 = ... = x_n, co oznacza, że ​​nigdy nigdzie się nie dostaniesz. Aby to złagodzić, sugeruję dodanie pary małych, słabych (powiedzmy 5% lub 10%) silników strumieniowych dla każdego gracza umieszczonego w 45 stopniach z każdej strony. Zapewni to rozwiązaniu większą elastyczność, ponieważ można je wykorzystać do przeciwdziałania słabym wtórnym efektom głównych silników odrzutowych.

Wreszcie, dla maksymalnie 100 silników odrzutowych, rozwiązanie LP jest wystarczająco szybkie, aby można go było wykonać na ramkę. Ponieważ jednak rozwiązanie nie zależy od położenia ani bieżącego stanu, można każdorazowo obliczyć rozwiązanie dla każdej rozsądnej kombinacji danych wejściowych kontrolera za każdym razem, gdy zmienia się kształt (obejmuje to dodawanie nierzutowych, które zmieniają moment bezwładności lub masę statku, ponieważ wtedy pędniki znajdują się w innym miejscu względem środka masy!). To 24 możliwości (tj. 8 kierunków razy {lewy obrót, brak obrotu, prawy obrót}).


źródło
Bardzo dobrze wyjaśnione!
Kim
1
Co Sum_iznaczy w tym kontekście?
S. Tarık Çetin
1

Moją pierwszą myślą było rozwiązanie czysto empiryczne, czyli symulacja platformy w środowisku piaskownicy dla różnych stopni ciągu, aby sprawdzić, jak się zachowuje. Zamiast równoważyć wiele skomplikowanych obliczeń matematycznych w poszukiwaniu deterministycznego rozwiązania, można je osiągnąć numerycznie, na przykład stosując metodę Newtona. Przykład:

Zakres ciągu wynosi od 0 do 1000, gdzie 1000 to ALOT.

Krok 1

Symuluj z zaufaniem (0 + 1000) / 2 = 500. Wynik: zbyt duże zaufanie

Krok 2

Zakres wynosi teraz od 0 do 500 Symuluj z zaufaniem (0 + 500) / 2 = 250. Wynik: zbyt duże zaufanie

Krok 3

Zakres wynosi teraz od 0 do 250 Symuluj z zaufaniem (0 + 250) / 2 = 125 Wynik: za mało zaufania

Krok 4

Zakres wynosi teraz od 125 do 250 Symuluj z zaufaniem (125 + 250) /2=187,5 Wynik za dużo zaufania

Krok 5 Zakres wynosi teraz od 125 do 187,5 Symuluj z zaufaniem (125 + 187,5) /2=156,25 Wynik jest zbyt mały

Krok # 6 Zakres wynosi teraz od 156,25 do 187,5 Zakres jest poniżej progu 35, co oznacza, że ​​jest to wystarczająco dobry szacunek

Wynik końcowy = (187,5 + 156,25) / 2 = 171,875

Lennart Rolland
źródło