Симулятор солнечной системы. Ключ на старт!

в 17:24, , рубрики: fun, game development, python, метки:

В первой части симулятора я описал правила игры и простейшую их реализацию.

Я благодарен всем кто оставил конструктивный комментарии первой версии. Это помогло мне оценить всю глубину проблемы. Отдельное спасибо пользователям kahi4, Ethril, Uri и lexasss

Сейчас симулятор вырос. Все тела влияют друг на друга по общим правилам, метод Эйлера ушел в прошлое, появилась возможность выбирать системы для симуляции и т.д.

Настала пора двигаться дальше — к покорению просторов космоса управляемым аппаратом.

Симулятор солнечной системы. Ключ на старт!

По траектории понятно
Что Ваш полет идет к концу
Мы помним Вас, скорбим и любим.
Ваш ЦУП.

Наша цель — коммунизм. Завод по производству ракет

Итак, симулятор звездных систем Spacesim позволяет задавать начальное состояние системы и моделировать ее поведение.

Представим теперь, что у нас есть классическая идеальная одноступенчатая ракета ракета

Пусть ракета имеет сухую массу m,
в нее залито топливо массой mf
тяга двигателя — z
и расход топлива — n
Пусть двигатель имеет неограниченный ресурс и неограниченное количество включений.

Предположим, что наша ракета находится на поверхности планеты массой М и радиусом H. Нашей основной задачей будет выведение ракеты на круговую орбиту вокруг планеты.

heaven ahead

Перед запуском на круговую орбиту запустим нашу ракету вертикально вверх и понаблюдаем за ее движением.
На ракету действуют две силы:
1. Сила тяги двигателя (вверх): F = n * z
2. Гравитация планеты (вниз): F = G*M*(m + mf) / r^2, m + mf — полная масса ракеты, r — расстояние от ракеты до центра планеты.

Далее везде будем полагать G = 1

Результирующая сила, действующая на ракету будет: n * z — G*M*(m + mf) / r^2
Отсюда можно найти ускорение ракеты:

a = n * z / (m + mf) — M / r^2

теперь легко можно рассчитать движение ракеты вертикально вверх под действием гравитации планеты:

Методом Эйлера:

H=409.0 #Start level above sea

t=0

m=2   #Mass of equipment
mf=9   #Mass of Fuel

M=600000  #Planet mass

y=H + 1  #Initial position
a=0      #accel
v=0      #speed
f=0      #engine accel

n=1       #Fuel consumption
z=40.0    #Fuel impulse

cnt = 0   #Step count

dt = .1
maxy = 0

while(y > H and cnt < 300000000):
    if mf > 0:
        f = n*z/(m + mf) #Engine gives acceleration to
        mf -= dt*n          #Fuel goes down
        
    else:
        f = 0            #Out of fuel
    
    a = f - M/y**2       #Total = engine - gravity
    
    v += dt*a               #new speed

    y += dt*v               #new altitude
    maxy = max(maxy, y)

    print("Step: ", cnt,
          " Height: ", y,
          " VSpeed: ", v)
    
    cnt += 1

print(dt ,maxy)

Методом Рунге-Кутты

H=409.0 #Start level above sea

t=0

m=2   #Mass of equipment
mf=9   #Mass of Fuel

M=600000  #Planet mass

x=H + 1  #Initial position
a=0      #accel
v=0      #speed
f=0      #engine accel

n=1       #Fuel consumption
z=40.0    #Fuel impulse

cnt = 0   #Step count

dt = .1
maxy = 0

def f(t, x, v):
    global m,mf,n,z
    
    if mf > 0:
        f = n*z/(m + mf) #Engine gives acceleration to

    else:
        f = 0            #Out of fuel
    
    a = f - M/x**2       #Total = engine - gravity

    #We'll use Runge-Kutta method
    
    return a               #new speed

def g(t, x, v):
    return v
    

while(x > H and cnt < 30000):
    maxy = max(maxy, x)

    k1 = dt * f(t, x, v)
    q1 = dt * g(t, x, v)
    
    k2 = dt * f(t + dt/2, x + q1/2, v + k1/2)
    q2 = dt * g(t + dt/2, x + q1/2, v + k1/2)

    k3 = dt * f(t + dt/2, x + q2/2, v + k2/2)
    q3 = dt * g(t + dt/2, x + q2/2, v + k2/2)
    
    k4 = dt * f(t + dt, x + q3, v + k3)
    q4 = dt * g(t + dt, x + q3, v + k3)
    

    v1 = v + (k1 + 2*k2 + 2*k3 + k4)/6
    x1 = x + (q1 + 2*q2 + 2*q3 + q4)/6
    

    print("Step: ", cnt,
          " Height: ", x1,
          " Speed: ", v1)
    
    cnt += 1

    t += dt
    v = v1
    x = x1

    if mf > 0:
        mf -= dt*n          #Fuel goes down

print(dt ,maxy)

Как видим, результаты совпадают с большой точностью
Симулятор солнечной системы. Ключ на старт!

Собираем все вместе

Итак, мы научились запускать реактивный двигатель и взлетать вертикально вверх.
Также у нас есть симулятор из прошлой части, в котором тела двигаются под действием сил гравитации друг относительно друга.

Объединим их! Добавим ракету в симулятор.

Добавим в ракету бортовой компьютер, работающий по программе.
Чтобы выйти на круговую орбиту, будет действовать по такому алгоритму:

1. Запускаем двигатель и ракета начинает лететь вверх.
2. Выключаем двигатель. Ракета летит вверх по инерции
3. Поворачиваем корпус ракеты на 90 градусов.
4. В тот момент, когда вертикальная скорость становится равной нулю, включаем двигатель
5. Через небольшой промежуток времени выключаем двигатель.

А так выглядит реализация:

class EarthOrbiter(Rocket):
    def flightProgram(self):
        #Take off and turn 90" right
        if self.mode == 0:
            self.engineOn()
            self.mode = 1

        if self.t > 12.0 and self.mode == 1:
            self.engineOff()
            self.setHead(90)
            self.mode = 2

        #Go to round orbit
        if self.t > 20 and self.mode == 2:
            self.engineOn()
            self.mode = 3

        if self.t >= 27 and self.mode == 3:
            self.engineOff()
            self.mode = 4

События в нашей ракете происходят в зависимости от полетного времени и предыдущего состояния.

Бинго! Полет нормальный. Траектория стабильная.

Вот короткое фидео о первом полете:
Полетное видео 1
Полетное видео 2

Следующим этапом будет доббавление Луны в систему и полет к ней.
Также в планах есть многоступенчатые ракеты.

Исходники — тут

Автор: RedTroll

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js