Прогулка по лунолётам. 4 - Вблизи и на орбите
Все прогулки: первая, вторая, третья и четвёртая.
На прошлых прогулках мы опробовали расчетную модель и графическую основу для нашего интерактивного симулятора полётов вблизи Луны и других безатмосферных планет. Однако, данная модель не учитывала ни изменение ускорения свободного падения при наборе высоты, ни сферическую форму планеты, что не позволяло нам сделать главный шаг - набрать первую космическую скорость и выйти в свободный полёт на лунной орбите.
Пришла пора усовершенствовать математику полёта и собрать наш симулятор из трех частей: основного цикла "реального" времени для взаимодействия с пилотом лунолёта, расчетного блока и блока вывода графической информации. Для работы нам понадобится ПМК типа HP 50g/49 (с небольшими переделками программа пойдет и на 48g) или его эмулятор, например, уже упоминавшийся Debug4x.
Итак, наш лунолёт становится способным совершать орбитальные полёты. Вот как это выглядит в понятиях используемой математической модели.
Движение лунолёта характеризуется вертикальной "u" и горизонтальной "v" скоростями, тяга определяется вектором ускорения "a", угол "альфа" которого задаётся как отклонение от вертикали (прямая между лунолётом и центром планеты). Местонахождение определяется расстоянием "r" от центра планеты (высота "h" является разностью этого расстояния и радиуса планеты) и углом отклонения "гамма" от места старта "гамма-ноль". Как вы могли заметить, мы перешли к расчетам в полярной системе координат. Пройденная дистанция "L" рассчитывается как сумма пройденных участков пути (наш симулятор рассчитывает манёвр ежесекундно)
Тем не менее, при полёте вблизи поверхности на небольшие расстояния и вертикальных полетах расчеты позволяют использовать привычную и удобную в этих случаях декартову систему координат. Координата "x" вычисляется по приведенной формуле даже более точно с учетом сферической поверхности. Привычный набор параметров: высота, координата "x", скорости, позволяют однозначно определить положение корабля и направление его движения.
Для орбитальных полётов удобнее использовать угол отклонения "гамма" и высоту. Виток вокруг планеты будет означать изменение "гаммы" от нуля до 360°.
На базе блок-схемы "Орбитальная станция" из журнала "Техника молодёжи" №6 1986 была разработана следующая схема расчетов маневра. В отличие от модели, использованной на предыдущих прогулках, ускорение зависит от гравитационных, центробежных (вертикальная или, точнее, радиальная составляющая) и кориолисовых (горизонтальная) сил.
Чтобы начать полет на симуляторе загружаем в ПМК программу "Лунолёт" (Lunar Ship), приведенную в конце статьи.
Параметры и управление
После заставки программа показывает горячие клавиши, доступные пилоту для управления лунолётом.
- Стрелки вверх и вниз служат для управления ускорением. Одно нажатие клавиши соответствует изменению ускорения на 1 м/сек2. Клавишей "F2" для более точного манёвра можно изменять приращение с 1 до 0,5 м/сек2 и обратно. Клавишей "F6" можно мгновенно выключить двигатель.
- Вектор тяги задаётся углом "альфа" в пределах [-180°, 180°]. Изначально "альфа" равна нулю (тяга направлена вверх по вертикали). Для изменения угла используются стрелки вправо и влево. Изменение цикличное: угол -190° становится 170° и наоборот. Шаг изменения - 10°. Аналогичным образом клавишей "F1" можно переключать шаг с 10° до 10° и обратно.
- Клавиша "J" ("var") делает паузу в игре и рисует на экране траекторию полета в орбитальном масштабе. Если вы будете летать вблизи поверхности на малые расстояния, то, разумеется, кроме Луны на картинке ничего видно не будет.
- Клавиша "N" запускает новую игру (дожидаться приземления необязательно), клавиша "Q" - выход из программы.
Следующий экран появляется перед каждой новой игрой и позволяет ввести начальные параметры полёта, касающиеся корабля и планеты.
- g - ускорение свободного падения на поверхности планеты, м/сек2
- R - радиус планеты, м
- c - скорость истечения топлива, м/сек
- LS - жизнеобеспечение корабля в секундах
- A - предельное допустимое ускорение, м/сек2. В рассказе С. Лема "Дознание" из цикла о пилоте Пирксе робот сумел сорвать этот предохранитель и вывести корабль на запредельные перегрузки, подвергая смертельному риску экипаж людей. Наш лунолёт не позволяет такие шалости.
- Ms - "сухая" масса корабля, включая экипаж, кг
- Mf - масса топлива, кг
- L/X - переключатель для режима орбитального полёта и полетов вблизи планеты. В первом случае (значение "1") выводится информация о пройденной дистанции L, во втором ("0") - информация о текущей координате "x" на поверхности.
Чтобы изменить параметры, стрелками подведите курсор к полю, введите новое значение и нажмите "Ввод" (Enter).
В кресле пилота
Итак, корабль на старте. Посмотрим, какую бортовую информацию даёт нам симулятор. Координатная сетка показывает масштаб в метрах. При движении лунолёта масштаб будет динамически меняться. В левом ряду расположились все основные цифры телеметрии.
- H - текущая высота в метрах
- L (или "X", если выбран это режим) - пройденная дистанция или текущая координата, также в метрах
- γ - "гамма" - угол отклонения от начальной вертикали, градусы
- a - текущее ускорение, м/сек2
- α - "альфа" - угол вектора тяги, градусы
- V - горизонтальная скорость
- U - вертикальная скорость
- LS - запас жизнеобеспечения, секунды
- F - запас топлива, кг
Теперь обратите внимание на кружок, разделяющий ряд на блок координат и остальную телеметрию. Кружок показывает Луну, а точка - текущее положение корабля согласно углу "гамма" (высота в расчет не принимается). По мере увеличения "гаммы" точка будет вырисовываться в дугу, потом в окружность. Окружность будет означать выполнение полного витка вокруг планеты. Для детального просмотра орбиты существует соответствующий режим, войти в который можно нажав кнопку "J".
Можно не трогая горизонтальных стрелок немедленно перейти в вертикальный полёт и попробовать себя в роли Саши Перепёлкина: разогнаться, набрать высоту около 10 км, а потом совершить мягкую посадку в той же точке.
Можно потренироваться, повторив выполнение задания из "Лунолет-2", совершив баллистический полёт на 250 километров. Для этого, правда, лучше нажать "N" (новая игра) и перейти в режим координат "X".
Но мы сразу попробуем стартовать на орбиту. Ускоряемся и меняем угол. Рекомендуем отклоняться вправо, так как полет влево будет мешать наблюдению за цифрами.
Разгоняемся
Выходим на орбиту, отключаем двигатель. Судя по цифрам, круговая орбита не получилась, нас выносит на эллипс. Включаем кнопкой "2" режим 10-кратного ускорения времени и ждём, куда эллипс вынесет...
Так и есть, эллипс вынес на Луну! При таких скоростях от корабля и пилота не осталось и дыма...
Жмем "J", смотрим на орбиту - вот она во всей красе...
Итак, первый полет завершился "сваливанием" на эллипс и падением корабля на поверхность планеты с космической скоростью.
Ваша задача - не повторить ошибки и попытаться совершить круговой полёт вокруг Луны при заданных начальных параметрах (3500 кг топлива, 2250 кг сухой массы корабля). В пошаговом режиме с карандашом и миллиметровкой в уютном кабинете редакции КЭИ - это одно. Пришло время проверить, возможно ли это в суровых условиях динамического полёта.
%%HP: T(0)A(D)F(.);
«
PUSH
DEG
«
CLLCD
{ {} {} {} {} {} {"Next" « » } } TMENU
"Lunar ship simulator" 1 DISP
FONT\->
FONT6 \->FONT
"v.1.1" 3 DISP
"(c) 1985" 3 DISP
" Mikhail PUKHOV, USSR" 4 DISP
"(c) 2011" 5 DISP
" Serguei TARASSOV" 6 DISP
" pmk.arbinada.com" 7 DISP
" st@arbinada.com" 8 DISP
"This software is" 10 DISP
"under GNU GPL" 11 DISP
\->FONT
-1 WAIT DROP
CLLCD
"Keyboard shortcuts" 1 DISP
FONT\->
FONT7 \->FONT
"\|^\|v: acceleration" 3 DISP
"\<-\->: ship rotation" 4 DISP
"1 2 3: set \GDt 1/10/100" 5 DISP
"F1: switch \GD\Ga 10/1°" 6 DISP
"F2: switch \GDa 1/0.5" 7 DISP
"F6: stop acceleration" 8 DISP
"J: orbital view/pause" 9 DISP
"N: restart Q: quit" 10 DISP
\->FONT
-1 WAIT DROP
» 'showhelp' STO
@
@ Parameters
@
1.62 'g' STO @ Lunar acceleration of gravity on surface, m/sec2
1738000. 'rp' STO @ Radius of planet, m
0.
29.4 'alim' STO @ Acceleration limit, m/sec2
3660. 'c' STO @ Nozzle flow, m/sec
4500. 'mf' STO @ Fuel mass in kg
mf 'mfn1' STO
2250. 'ms' STO @ Ship mass w/o fuel
1. 'dt' STO @ Maneuver discrete time in sec
@ Initial screen scale
0. 'ymin0' STO
1000. 'ymax0' STO
-1500. 'xmin0' STO
1500. 'xmax0' STO
@ Initialisation every flight parameters
«
0. 'a' STO @ Current acceleration
0. 'an1' STO @ Acceleration N-1 (previous step)
1. 'da' STO @ Acceleration increment
0. 'ac' STO @ angle of climb in degrees
0. 'acn1' STO
10. 'dac' STO @ Angle increment
1. 'dacn1' STO
0. 'u' STO @ vertical velocity
0. 'un1' STO
0. 'v' STO @ horisontal velosity
0. 'vn1' STO
0. 'h' STO @ Current altitude
h 'hn1' STO
0. 'phi' STO @ Initial angle
phi 'phin1' STO
rp 'r' STO @ Initial orbit altitude
r 'rn1' STO
r 'rmax' STO
0. 'x' STO @ Current coord X
x 'xn1' STO
0. 'l' STO @ Traversed distance
l 'ln1' STO
3600. 4 *
'ls' STO @ Life support in sec
ls 'lsn1' STO
{} 'orbit' STO @ Orbit coordinates list
@ Temporary values
0. 'q' STO
0. 't' STO
0. 'dmf' STO
@ Screen scale
ymin0 'ymin' STO
ymax0 'ymax' STO
xmin0 'xmin' STO
xmax0 'xmax' STO
@ Flags
0 'started' STO
0 'landing' STO
» 'paramsinit' STO
paramsinit
@ Global application flags
0 'tostop' STO
1 'toinit' STO
1 'newgame' STO
1 'showdist' STO
@ Cleanup procedure
«
{
'g', 'rp',
'a', 'an1', 'da', 'alim',
'ac', 'acn1', 'dac', 'dacn1',
'c',
'v', 'vn1',
'u', 'un1',
'h', 'hn1',
'x', 'xn1',
'l', 'ln1',
'r', 'rn1', 'rmax',
'phi', 'phin1',
'ls', 'lsn1',
'mf', 'dmf', 'mfn1', 'ms',
'orbit',
'dt',
't', 'q',
'started', 'landing',
'tostop', 'toinit', 'newgame', 'showdist',
'xmin', 'xmax', 'ymin', 'ymax',
'xmin0', 'xmax0', 'ymin0', 'ymax0',
'showrepl', 'showgxor', 'getpoint', 'showship',
'showorbit1', 'showorbit2', 'orbitaddpoint',
'paramsinput', 'paramsinit',
'calcmaneuver', 'cleanup', 'showhelp',
'debugout',
'PPAR'
} PURGE
POP
» 'cleanup' STO
@ Ask for initial parameters
«
CLLCD
"Lunar ship"
{
{"g " "Gravity acceler.on surface, m/s2" 0}
{"R " "Planet radus, m" 0}
{"c " "Nozzle flow, m/sec" 0}
{"LS" "Life support, sec" 0}
{"A " "Acceleration limit, m/s2" 0}
{"Ms" "Ship mass w/o fuel, kg" 0}
{"Mf" "Fuel mass, kg" 0}
{"L/X" "Show 1 - distance; 0 - coord, m" 0}
}
{2 1}
g rp c ls alim ms mf showdist
8 \->LIST
g rp c ls alim ms mf showdist
8 \->LIST
IF INFORM
THEN
OBJ\->
DROP
ABS SIGN 'showdist' STO
'mf' STO
'ms' STO
'alim' STO
'ls' STO
'c' STO
'rp' STO
'g' STO
ELSE
cleanup
HALT
END
» 'paramsinput' STO
@ Application const
0.3 @ delay in sec between iterations
@ can be modifed [0.1, 0.8] depending on calc speed
131 80
20 20 10 12 11 8 4
#8d #32d #2d #5d
4 @ 360 should divide it without reminder
\-> stepdelay
dispwidth dispheight
alpha1 alpha2 r1 r2 r3 r4 r5
lunx luny lunr shipr
deginc
«
«
\-> val line
«
dispheight 2 / R\->B
15 line 7 * + R\->B
2 \->LIST
val
showrepl
»
» 'debugout' STO
«
1 \->GROB PICT UNROT REPL
» 'showrepl' STO
«
\-> valn1 valn coord toinit
«
IF toinit valn1 valn \=/ OR
THEN
IF toinit NOT
THEN
PICT coord valn1 1 \->GROB GXOR
END
PICT coord valn 1 \->GROB GXOR
END
»
» 'showgxor' STO
«
\-> x0 y0 r phi
«
r phi COS * x0 + R\->B
y0 r phi SIN * - R\->B
2 \->LIST
»
» 'getpoint' STO
«
\-> xn1 hn1 x h phi
«
@ Trajectory
xn1 hn1 R\->C x h R\->C LINE
@ Ship
x h R\->C C\->PX LIST\-> DROP B\->R
DUP IP
IF dispheight 5 - \>=
THEN
DROP dispheight 5 -
END
SWAP B\->R
\-> y0 x0
«
x0 y0
x0 y0 r1 180 alpha1 - phi -
getpoint
x0 y0 r1 alpha1 phi -
getpoint
x0 y0 r3 0 phi -
getpoint
x0 y0 r2 alpha2 NEG phi -
getpoint
x0 y0 r2 180 alpha2 + phi -
getpoint
x0 y0 r3 180 phi -
getpoint
x0 y0 r4 90 phi -
getpoint
x0 y0 r5 270 phi -
getpoint
\-> p1 p2 p3 p4 p5 p6 p7 p8
«
p1 p2 TLINE
p2 p3 TLINE
p3 p4 TLINE
p3 p6 TLINE
p5 p6 TLINE
p1 p6 TLINE
p1 p7 TLINE
p2 p7 TLINE
x0 R\->B y0 R\->B 2 \->LIST p8 TLINE
»
DROP2
»
»
» 'showship' STO
@ Calculate maneuver
«
a ms mf + * t * c / DUP 'dmf' STO
IF mf >
THEN
mf DUP 'dmf' STO
0 'mf' STO
c * ms mf + t * /
ELSE
mf dmf - 'mf' STO
a
END
\-> ai
«
DO
ai ac COS * rp r / SQ g * - v SQ r / +
ai ac SIN * u v * r / -
\-> air aix
«
IF started NOT air 0 > AND
THEN
1 'started' STO
END
IF started landing NOT AND
THEN
r
u DUP air t * + DUP 'u' STO
+ 2 / t * + 'r' STO
v DUP aix t * + DUP 'v' STO
+ 2 / t * DUP l + 'l' STO
90 * \pi \->NUM r * / phi + DUP 'phi' STO
2 \pi \->NUM * r * * 360 / 'x' STO
r rp - DUP 'h' STO
IF 0 <
THEN
h t * ABS 2 h * / 't' STO
END
END
»
UNTIL
h -0.01 \>=
END
r rp - ABS
IF 0.01 <
THEN
rp 'r' STO
0 'h' STO
IF started
THEN
1 'landing' STO
END
END
»
» 'calcmaneuver' STO
@ Small view of planet and orbit
«
\-> phin1 phi toinit
«
IF toinit
THEN
lunx luny 2 \->LIST lunr 0 360 ARC
xmin 0 R\->C xmax 0 R\->C LINE @ Lune surface
lunx luny 2 \->LIST shipr 0 phi IP
IF v 0 > THEN NEG SWAP END
ARC
END
phi IP deginc MOD
IF 0 ==
THEN
lunx luny 2 \->LIST shipr 0 phi IP
IF v 0 > THEN NEG SWAP END
ARC
END
»
» 'showorbit1' STO
@ Show orbit in detailed view
«
@ {
@ (1738000., 0)
@ (1785000., 5)
@ (1790000., 10)
@ (1800000., 15)
@ (1900000., 25)
@ (1950000., 45)
@ } 'orbit' STO
rp rmax MAX 'rmax' STO
rp 1000 / IP DUP
rmax rp / * IP
DUP dispwidth dispheight / * IP
\-> rpkm maxcoordy maxcoordx
«
maxcoordx NEG maxcoordx XRNG
maxcoordy NEG maxcoordy YRNG
ERASE
@ Axes
(0., 0.)
maxcoordx 10 / IP
"y, km" "x, km"
4 \->LIST AXES
DRAX
LABEL
{#0d, #0d} PVIEW
(0., 0.) rpkm 0 360 ARC
orbit LIST\->
DUP
IF 0 ==
THEN
DROP
ELSE
1 SWAP FOR i
C\->R
SWAP 1000 / SWAP
DUP2
COS * IP
3 ROLLD
SIN * IP
R\->C
IF i 1 >
THEN
DUP prevpoint LINE
END
'prevpoint' STO
NEXT
'prevpoint' PURGE
END
0 WAIT DROP
»
» 'showorbit2' STO
@ Store points of orbit in polar coords
«
\-> pr pphi dinc
«
pphi IP deginc MOD
IF 0 ==
THEN
orbit SIZE dinc * DUP
IF 0 == SWAP pphi ABS IP < OR
THEN
orbit LIST\->
pr pphi R\->C
SWAP 1 +
\->LIST
'orbit' STO
r rmax MAX 'rmax' STO
END
END
»
» 'orbitaddpoint' STO
showhelp
DO
IF newgame 1 ==
THEN
paramsinit
paramsinput
0 'newgame' STO
1 'toinit' STO
END
IF toinit
THEN
xmin xmax XRNG
ymin ymax YRNG
ERASE
@ Axes
xmax ymax R\->C
xmax xmin - 10 / IP ymax ymin - 8 / IP
2 \->LIST
"" ""
4 \->LIST AXES
DRAX
{#0d, #0d} PVIEW
@ Axes labels
@ X
IF xmin 0 < xmax 0 > AND
THEN
(0, 0) C\->PX LIST\-> DROP2
#3d 2 \->LIST
0.
showrepl @ Show 0 on "x" axe
END
{#0d, #3d} xmin
showrepl
dispwidth xmax LOG IP 1 + 5 * - R\->B
#3d
2 \->LIST
xmax
showrepl
@ Y
dispwidth 10 - R\->B
dispheight 8 - R\->B 2 \->LIST
0.
showrepl @ Show 0 on "y" axe
dispwidth ymax LOG IP 1 + 5 * - R\->B
#10d
2 \->LIST
ymax
showrepl
{#0d, #9d} "H:"
showrepl
{#0d, #15d} IF showdist THEN "L:" ELSE "X:" END
showrepl
{#0d, #21d} "\Gg:"
showrepl
{#0d, #41d} "a:"
showrepl
{#0d, #47d} "\Ga:"
showrepl
@ {#100d, #47d} "\GD\Ga:\177"
@ showrepl
{#0d, #54d} "V:"
showrepl
{#0d, #60d} "U:"
showrepl
{#0d, #67d} "LS:"
showrepl
{#0d, #73d} "F:"
showrepl
END
phin1 phi toinit
showorbit1
hn1 IP h IP {#12d, #9d} toinit
showgxor
IF showdist THEN ln1 l ELSE xn1 x END
IP SWAP IP SWAP {#12d, #15d} toinit
showgxor
phin1 1 RND phi 1 RND {#12d, #21d} toinit
showgxor
an1 a {#12d, #41d} toinit
showgxor
acn1 ac {#12d, #47d} toinit
showgxor
@ dacn1 dac {#117d, #47d} toinit
@ showgxor
vn1 1 RND v 1 RND {#12d, #54d} toinit
showgxor
un1 1 RND u 1 RND {#12d, #60d} toinit
showgxor
lsn1 ls {#12d, #67d} toinit
showgxor
mfn1 IP mf IP {#12d, #73d} toinit
showgxor
@ Calculate points as a function of coordonates
IF
toinit
ac acn1 \=/ OR
h hn1 \=/ OR
showdist NOT x xn1 \=/ AND OR
showdist l ln1 \=/ AND OR
THEN
IF toinit NOT
THEN
IF showdist THEN ln1 ELSE xn1 END
hn1
DUP2
acn1
showship
END
IF showdist
THEN
ln1 hn1 l h
ELSE
xn1 hn1 x h
END
ac
showship
END
stepdelay WAIT
0 'toinit' STO
@ Prevoius iteration values
a 'an1' STO
ac 'acn1' STO
v 'vn1' STO
u 'un1' STO
dac 'dacn1' STO
h 'hn1' STO
x 'xn1' STO
l 'ln1' STO
ls 'lsn1' STO
mf 'mfn1' STO
phi 'phin1' STO
WHILE KEY
REPEAT
\-> k
«
CASE
k 25 ==
k 35 == OR THEN
a da IF k 25 == THEN + ELSE - END
DUP IF 0 < THEN DROP 0 END
DUP IF alim > THEN DROP alim IP END
'a' STO
END
k 31 == THEN
showorbit2
1 'toinit' STO
END
k 34 ==
k 36 == OR THEN
ac dac IF k 34 == THEN - ELSE + END
@ Cyclic transform like 190°->-170; -190->170
DUP ABS
IF 180 >
THEN
DUP SIGN 360 * -
END
'ac' STO
END
@ Switch increments
k 92 == THEN 1 'dt' STO END
k 93 == THEN 10 'dt' STO END
k 94 == THEN 100 'dt' STO END
k 11 == THEN
IF dac 1 == THEN 10 ELSE 1 END 'dac' STO
END
k 12 == THEN
IF da 1 == THEN 0.5 ELSE 1 END 'da' STO
END
k 16 == THEN 0 'a' STO END
@ Game restart/end
k 42 == THEN 1 'newgame' STO END
k 51 == THEN 1 'tostop' STO END
END
»
END
ls dt - 'ls' STO
dt 't' STO
calcmaneuver
r phi deginc
orbitaddpoint
IF h hn1 < h 0 == AND
THEN
CASE
v ABS 2 <
u ABS 2 < AND THEN "Perfect landing!" END
v ABS 4 <
u ABS 4 < AND THEN "Good landing!" END
v ABS 6 <
u ABS 6 < AND THEN "Hard landing!" END
v ABS 8 <
u ABS 8 < AND THEN "Very hard landing! Ambulance ship was sent!" END
"Landing failed. Ship is destroyed!"
END
MSGBOX
{#0d, #0d} PVIEW
END
@ Scaling coordinates
@ Zoom out
xmax xmin -
ymax ymin -
IF showdist THEN l ELSE x END
v dt * 50 *
\-> dx dy currx xincr
«
IF
ymax h - ABS dy 0.2 * <
THEN
ymax 2 * IP 'ymax' STO
1 'toinit' STO
ELSE
IF
ymin h - ABS dy 0.2 * <
THEN
h 1.5 * IP
DUP
IF ymax0 <
THEN
DROP
ymax0
END
DUP
IF ymax \=/
THEN
'ymax' STO
1 'toinit' STO
ELSE
DROP
END
END
END
IF
xmax currx - ABS dx 0.2 * <
THEN
currx xincr + IP 'xmax' STO
currx xincr 2.5 / - IP 'xmin' STO
1 'toinit' STO
ELSE
IF xmin currx - ABS dx 0.2 * <
THEN
currx xincr + IP 'xmin' STO
currx xincr 2.5 / - IP 'xmax' STO
1 'toinit' STO
END
END
»
UNTIL
tostop
END
»
cleanup
»
HOME
'Lunar' PURGE
'Lunar' STO
CLEAR
CLLCD
@ show the VAR menu
2. MENU
11.1 KEYEVAL
blog comments powered by Disqus