Запуск двоступеневої ракети приблизно за 100 рядків JavaScript
Ніякого фізичного рушія, ніякої бібліотеки орбітальної механіки — лише рівняння ракети Ціолковського, програма тангажу гравітаційного розвороту та подія відділення ступеня, все у звичайному циклі requestAnimationFrame. Наприкінці у вас буде справжній (хоч і спрощений) ступеневий запуск, що виконує розворот, скидає перший ступінь і рухається за інерцією до орбітальної швидкості.
1. Стан ракети та константи
Ми моделюємо ракету як матеріальну точку з позицією (дальність, висота), швидкістю та кутом тангажу. Кожен ступінь несе власну суху масу, масу палива, тягу та питомий імпульс (Isp) — двоступенева конструкція відображає реальні апарати на кшталт Falcon 9, де легший, ефективніший другий ступінь бере на себе роботу, щойно важкий перший ступінь вичерпав паливо.
const G0 = 9.81; // м/с^2, стандартна гравітація для перерахунку Isp
const stage1 = { dryMass: 25000, propMass: 395000, thrust: 7600000, isp: 282 };
const stage2 = { dryMass: 4000, propMass: 92000, thrust: 934000, isp: 348 };
const payload = 8000; // кг
let rocket = {
x: 0, y: 0, // дальність (м), висота (м)
vx: 0, vy: 0, // компоненти швидкості (м/с)
pitch: Math.PI / 2, // радіани, pi/2 = прямо вгору
stage: 1,
mass: stage1.dryMass + stage1.propMass + stage2.dryMass + stage2.propMass + payload,
propRemaining: stage1.propMass,
t: 0,
};
2. Тяга і витрата маси
Тяга і витрата палива пов'язані через швидкість витоку: F = ṁ · v_e, де v_e = Isp · g₀. По мірі спалювання палива загальна маса зменшується щокроку — саме це зменшення маси й робить рівняння Ціолковського нелінійним, а поділ на ступені — виправданим.
function exhaustVelocity(isp) {
return isp * G0;
}
function massFlowRate(thrust, isp) {
return thrust / exhaustVelocity(isp); // кг/с
}
function currentStageConfig(rocket) {
return rocket.stage === 1 ? stage1 : stage2;
}
3. Програма тангажу гравітаційного розвороту
Справжня ракета не летить прямо вгору весь час — це витратило б величезну кількість палива на боротьбу з гравітацією замість набору горизонтальної (орбітальної) швидкості. Гравітаційний розворот починається майже вертикально, а потім поступово нахиляється до горизонталі зі зростанням висоти й швидкості, дозволяючи самій гравітації виконати більшу частину повороту.
// Проста емпірична програма тангажу: вертикально нижче 1 км, потім плавний розворот
function pitchProgram(altitude, t) {
if (altitude < 1000) return Math.PI / 2; // прямо вгору зі стартового майданчика
const turnProgress = Math.min(1, (t - 10) / 120); // розворот протягом ~2 хвилин
const targetPitch = (Math.PI / 2) * (1 - turnProgress) + 0.12 * turnProgress;
return Math.max(0.05, targetPitch);
}
4. Рівняння руху
На кожному кроці підсумовуються три сили — тяга вздовж поточного напрямку тангажу, гравітація прямо вниз і спрощений доданок опору — а потім прискорення інтегрується у швидкість і позицію.
function step(dt) {
const cfg = currentStageConfig(rocket);
const mdot = massFlowRate(cfg.thrust, cfg.isp);
const thrusting = rocket.propRemaining > 0;
const thrust = thrusting ? cfg.thrust : 0;
rocket.pitch = pitchProgram(rocket.y, rocket.t);
const Fx = thrust * Math.cos(rocket.pitch);
const Fy = thrust * Math.sin(rocket.pitch);
const rho = 1.225 * Math.exp(-rocket.y / 8500); // проста експоненційна атмосфера
const speed = Math.hypot(rocket.vx, rocket.vy);
const dragMag = 0.5 * rho * speed * speed * 0.3 * 10; // Cd*A ≈ 3 м^2
const dragX = speed > 0 ? -dragMag * rocket.vx / speed : 0;
const dragY = speed > 0 ? -dragMag * rocket.vy / speed : 0;
const ax = (Fx + dragX) / rocket.mass;
const ay = (Fy + dragY) / rocket.mass - G0;
rocket.vx += ax * dt;
rocket.vy += ay * dt;
rocket.x += rocket.vx * dt;
rocket.y = Math.max(0, rocket.y + rocket.vy * dt);
if (thrusting) {
const burned = mdot * dt;
rocket.propRemaining -= burned;
rocket.mass -= burned;
}
rocket.t += dt;
checkStaging();
}
5. Відділення ступеня
Коли паливо першого ступеня закінчується, ми повністю скидаємо його суху масу — далі це мертвий вантаж — і перемикаємо облік на тягу, Isp та запас палива другого ступеня. Саме це стрибкоподібне зменшення маси й пояснює, чому поділ на ступені кращий за один «усереднений» двигун: апарат позбувається тепер уже марних порожніх баків і конструкції, замість того щоб тягнути їх аж до орбіти.
function checkStaging() {
if (rocket.stage === 1 && rocket.propRemaining <= 0) {
rocket.mass -= stage1.dryMass; // скидання порожнього першого ступеня
rocket.stage = 2;
rocket.propRemaining = stage2.propMass;
console.log(`Відділення ступеня на t=${rocket.t.toFixed(1)}с, висота=${(rocket.y/1000).toFixed(1)}км`);
}
}
6. Графік траєкторії
Простий графік на canvas дальності відносно висоти показує класичну дугу запуску ракети: майже вертикальний підйом, викривлений гравітаційний розворот, а потім довга полога траєкторія по мірі зростання горизонтальної швидкості до орбітальної (~7,8 км/с для кругової орбіти НЗО).
function renderTrajectory(ctx, trace) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
const scaleX = ctx.canvas.width / 500000; // 500 км дальності вміщуються у ширину canvas
const scaleY = ctx.canvas.height / 150000; // 150 км висоти вміщуються у висоту canvas
trace.forEach((p, i) => {
const px = p.x * scaleX;
const py = ctx.canvas.height - p.y * scaleY;
i === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
});
ctx.strokeStyle = '#3b82f6';
ctx.lineWidth = 2;
ctx.stroke();
}
7. Збираємо все разом — головний цикл
Повна симуляція виконує крок фізики кілька разів за кожен відрендерений кадр для числової стабільності, записує слід траєкторії й перемальовує графік — повний запуск двоступеневої ракети менш ніж за 100 рядків, включно з налаштуванням, логікою відділення ступенів та рендерингом.
const canvas = document.getElementById('rocket');
const ctx = canvas.getContext('2d');
const trace = [];
function loop() {
for (let i = 0; i < 20; i++) step(0.05); // 20 підкроків на кадр, dt=0,05с
trace.push({ x: rocket.x, y: rocket.y });
renderTrajectory(ctx, trace);
if (rocket.y >= 0 && rocket.t < 600) requestAnimationFrame(loop);
}
loop();
Часті запитання
Чого я навчуся в цьому уроці?
Симулюйте запуск ступеневої ракети з нуля приблизно за 100 рядків JavaScript: масові співвідношення Ціолковського, гравітаційний розворот, відділення ступеня та графік траєкторії на canvas.
Які теми розглядаються в цьому уроці?
Цей урок охоплює такі теми: Стан ракети та константи, Тяга і витрата маси, Програма тангажу гравітаційного розвороту, Рівняння руху, Відділення ступеня, Графік траєкторії, Збираємо все разом — головний цикл.
Скільки часу займає цей урок?
Цей урок займає приблизно 25 хв.
Які попередні знання потрібні?
Це урок рівня «Середній рівень» — окрема попередня підготовка, крім базового JavaScript, не потрібна.