I. Tổng quan

Cộng đồng khoa học hẳn sẽ không lạ gì với những phần mềm tính toán siêu việt như Matlab. Tuy nhiên, một số dự án là quá nặng về tính toán tới mức tự tính toán toàn bộ gần như là bất khả thi. Trong một số trường hợp vô cùng cụ thể, việc sử dụng những thư viện đặc dụng sẽ giúp tiết kiệm thời gian và công sức hơn rất nhiều.

Qua bài đăng này, mình sẽ giới thiệu một thư viện khoa học Python nhẹ, đa dụng, dễ tinh chỉnh và có độ chính xác cao, dùng trong một trường hợp khá đặc biệt: mô phỏng bay cho tên lửa.

II. Hướng dẫn

1. Cài đặt

Vì hướng dẫn này dành cho người mới, mình sẽ nhẹ nhàng cầm tay dắt qua từng bước một. Nhưng nếu bạn cảm thấy Internet Explorer còn nhanh hơn tốc độ của hướng dẫn này, bạn có thể nhảy qua các đề mục để tới phần cần thiết.

Chúng ta sắp sử dụng thư viện mã nguồn mở RocketPy. Để đơn giản, mình khuyến khích sử dụng Google Colab - với toàn bộ sự thoải mái của môi trường Python đám mây, tài nguyên tính toán dường như không thể dùng hết, và những pha tắt nhầm tab trừ vào tiền lương tháng.

Nếu bạn chọn dùng Google Colab, thì rất đơn giản, chỉ cần nhập:

!pip install rocketpy

Rồi bấm Ctrl + Enter. Về mặt cơ bản, dấu "!" là tiền tố của một lệnh shell trên Google Colab. Bạn vừa nhập một lệnh shell, rồi thực thi nó. Và nếu bạn không gõ sai chữ nào, thì giờ bạn hẳn có thể thư thái thưởng thức install log chạy qua màn hình:

Tuy nhiên, nếu bạn không muốn cho Google nhìn thấy bạn chập chững dùng thư viện mới, hay tự tin rằng máy làm việc của bạn ăn đứt server của Google, bạn vẫn có thể mở terminal lên và gõ vào lệnh sau:

pip install rocketpy

Nếu cửa sổ terminal bị nhuộm đỏ màu lỗi, thì có thể sửa câu lệnh thành:

pip3 install rocketpy

Hoặc:

py -m pip install rocketpy

Và nếu bạn đang trong tâm trạng muốn khác biệt với đám đông, bạn có thể tham khảo thêm cách cài đặt từ Conda hay trực tiếp qua mã nguồn tại hướng dẫn cài đặt của RocketPy.

RocketPy cũng đã chu đáo chuẩn bị sẵn một Colab notebook preview, trong trường hợp bạn chỉ muốn nghịch thử.

2. Import

Trang Github chính của RocketPy đã cung cấp cho chúng ta một sơ đồ khá ngắn gọn về cách các model tương tác:

Bạn có thể sẽ muốn chuyển sang light mode một lúc

Về cơ bản, chính là bạn nhập các cài đặt trên vào model của RocketPy, và rồi để ma thuật đen hoàn thành nốt công việc tính toán. Do đó, để bắt đầu, chúng ta cần import tất cả các model trên vào:

from rocketpy import Environment, Rocket, SolidMotor, Flight

Trong ví dụ này, mình muốn cài đặt thời gian là ngày mai, nên mình sẽ cần thêm module datetime nữa:

import datetime

3. Tinh chỉnh

Mỗi model sẽ cần được cài đặt riêng biệt. Ví dụ, để tạo một object theo model môi trường:

Env = Environment(
    railLength=5.2,
    latitude=32.990254,
    longitude=-106.974998,
    elevation=1400,
    date=(2022, 6, 22, 12) # Tomorrow's date in year, month, day, hour UTC format
) 

Env.setAtmosphericModel(type='Forecast', file='GFS')

Nâng cao hơn một chút, nếu bạn muốn object môi trường luôn tính toán theo thông số của ngày mai:

tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)

Env = Environment(
    railLength = 5.2,
    latitude = 21.2187149,
    longitude = 105.8041709, # Noi Bai International Airport
    elevation = 12, # meters
    date = (
        tomorrow.year,
        tomorrow.month,
        tomorrow.day,
        tomorrow.hour
    )
)

Env.setAtmosphericModel(type='Forecast', file='GFS')

Những người dùng có kiến thức về Python hẳn có thể dễ dàng thấy đây là quá trình tạo ra một object. Kiểu dữ liệu cũng đơn thuần là số thập phân, và tên các biến cũng khá dễ hiểu.

Kế tiếp, bởi chúng ta cần một cái tên lửa chứ không phải máy khoan, chúng ta cần chọn một model động cơ cho hợp lý. RocketPy chỉ hỗ trợ động cơ tên lửa rắn (solid rocket motor), không có động cơ nhiên liệu lỏng phức tạp. Dù vậy, một vài dữ liệu động cơ thú vị đã được để sẵn trong Git repo của module.

Vì mục đích thử nghiệm, lần này chúng ta sẽ nghịch với động cơ Cesaroni M3100. Trước nhất, chúng ta cần phải lấy dữ liệu của động cơ, bằng cách chạy lệnh sau:

!wget https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/motors/Cesaroni_M3100.eng

Hoặc bạn có thể trực tiếp tải model đó tại đây: Cesaroni_M3100.eng.

Bước kế tiếp là dựng một object động cơ hoàn chỉnh.

Pro75M3100 = SolidMotor(
    thrustSource="Cesaroni_M3100.eng",
    burnOut=3.9,
    grainNumber=5,
    grainSeparation=5/1000,
    grainDensity=1815,
    grainOuterRadius=33/1000,
    grainInitialInnerRadius=15/1000,
    grainInitialHeight=120/1000,
    nozzleRadius=33/1000,
    throatRadius=11/1000,
    interpolationMethod='linear'
)

Như vậy, chỉ trong nửa giây chúng ta đã mô phỏng được một động cơ hoàn thiện hơn cả BE-4. Nếu bạn tò mò về thông số của động cơ, bạn có thể xem thông qua phương thức .info() như thế này:

Từ động cơ trở thành tên lửa trong RocketPy là một bước nhỏ như bước đi của Armstrong vậy. Ví dụ, nếu chúng ta đặt tên cho tên lửa của chúng ta là calisto, thì object của nó sẽ được tạo ra như thế này:

calisto = Rocket(
    motor=Pro75M3100,
    radius=127/2000,
    mass=19.197-2.956,
    inertiaI=6.60,
    inertiaZ=0.0351,
    distanceRocketNozzle=-1.255,
    distanceRocketPropellant=-0.85704,
    powerOffDrag='powerOffDragCurve.csv',
    powerOnDrag='powerOnDragCurve.csv'
)

Tới đây, chương trình của bạn sẽ gào lên vì không có các file dữ liệu csv cần thiết. Bạn có thể tải chúng thông qua lệnh này:

!wget https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/calisto/powerOffDragCurve.csv https://raw.githubusercontent.com/Projeto-Jupiter/RocketPy/master/data/calisto/powerOnDragCurve.csv

Hoặc một lần nữa, tải trực tiếp ở đây: powerOffDragCurve.csv, powerOnDragCurve.csv.

Các bước tiếp theo sẽ gần giống chính xác như lúc bạn chơi Kerbal Space Program, bắt đầu từ nút ray (rail button?):

calisto.setRailButtons([0.2, -0.5])

Kế tiếp là chóp nón:

NoseCone = calisto.addNose(length=0.55829, kind="vonKarman", distanceToCM=0.71971)

Rồi tới vây:

FinSet = calisto.addFins(4, span=0.100, rootChord=0.120, tipChord=0.040, distanceToCM=-1.04956)

Và cuối cùng là đuôi:

Tail = calisto.addTail(topRadius=0.0635, bottomRadius=0.0435, length=0.060, distanceToCM=-1.194656)

Các thành tố cho một vụ phóng mỹ mãn đã tập hợp đủ… Ý mình là, một vụ phóng ICBM.

Để mô phỏng của chúng ta không trở thành mô phỏng chiến tranh, một nhân tố thường bị lãng quên trong KSP - dù bay - sẽ cần được thêm vào.

# Adding parachutes to rocket 

def drogueTrigger(p, y):
    return True if y[5] < 0 else False

def mainTrigger(p, y):
    return True if y[5] < 0 and y[2] < 800 else False

Main = calisto.addParachute('Main', CdS=10.0, trigger=mainTrigger, samplingRate=105, lag=1.5, noise=(0, 8.3, 0.5))

Drogue = calisto.addParachute('Drogue', CdS=1.0, trigger=drogueTrigger, samplingRate=105, lag=1.5, noise=(0, 8.3, 0.5))

Vậy là con tàu của chúng ta cuối cùng cũng đã sẵn sàng rời khỏi VAB.

4. Mô phỏng

Môi trường và tên lửa đã sẵn sàng. Không cần lùi lịch liên tục như NASA, chúng ta hoàn toàn có thể cất cánh ngay bây giờ.

Khá đơn giản, giống như khi tạo ra tên lửa, để mô phỏng chuyến bay, chúng ta cũng cần một object.

TestFlight = Flight(rocket=calisto, environment=Env, inclination=85, heading=0)

Nếu lệnh trên không sinh ra lỗi, tức là chuyến bay mô phỏng của chúng ta đã hoàn thành. Để xem thông tin về mô phỏng đó, một lần nữa chúng ta sẽ dùng phương thức .info():

TestFlight.info()

Rất nhiều thông tin sẽ nhảy ra, ví dụ:

Surface Wind Conditions

Frontal Surface Wind Speed: -0.57 m/s
Lateral Surface Wind Speed: -1.38 m/s


Rail Departure State

Rail Departure Time: 0.233 s
Rail Departure Velocity: 34.300 m/s
Rail Departure Static Margin: 2.154 c
Rail Departure Angle of Attack: 2.495°
Rail Departure Thrust-Weight Ratio: 17.509
Rail Departure Reynolds Number: 2.654e+05


BurnOut State

BurnOut time: 2.000 s
Altitude at burnOut: 335.521 m (AGL)
Rocket velocity at burnOut: 313.776 m/s
Freestream velocity at burnOut: 313.916 m/s
Mach Number at burnOut: 0.900
Kinetic energy at burnOut: 7.995e+05 J


Apogee

Apogee Altitude: 3328.738 m (ASL) | 3302.197 m (AGL)
Apogee Time: 24.890 s
Apogee Freestream Speed: 22.460 m/s


Events

Drogue Ejection Triggered at: 24.895 s
Drogue Parachute Inflated at: 26.395 s
Drogue Parachute Inflated with Freestream Speed of: 26.660 m/s
Drogue Parachute Inflated at Height of: 3291.269 m (AGL)
Main Ejection Triggered at: 165.171 s
Main Parachute Inflated at: 166.671 s
Main Parachute Inflated with Freestream Speed of: 17.237 m/s
Main Parachute Inflated at Height of: 747.508 m (AGL)


Impact

X Impact: 100.916 m
Y Impact: -250.161 m
Time of Impact: 305.258 s
Velocity at Impact: -5.287 m/s


Maximum Values

Maximum Speed: 314.984 m/s at 1.93 s
Maximum Mach Number: 0.903 Mach at 1.93 s
Maximum Reynolds Number: 2.394e+06 at 1.92 s
Maximum Dynamic Pressure: 5.523e+04 Pa at 1.92 s
Maximum Acceleration: 192.131 m/s² at 0.82 s
Maximum Gs: 19.592 g at 0.82 s
Maximum Upper Rail Button Normal Force: 0.612 N
Maximum Upper Rail Button Shear Force: 0.219 N
Maximum Lower Rail Button Normal Force: 0.219 N
Maximum Lower Rail Button Shear Force: 0.219 N

Cuối cùng, nếu bạn muốn các thông số chi tiết, cụ thể, cùng biểu đồ rõ ràng, bạn có thể sử dụng phương thức .allInfo():

TestFlight.allInfo()

Như bạn có thể thấy, nếu có 3 việc đơn giản nhất trên đời thì một trong số đó chắc chắn là chạy một giả lập RocketPy.

III. Ứng dụng

Bởi RocketPy không hỗ trợ động cơ nhiên liệu lỏng, hay động cơ phi hóa học (hoặc bạn có thể tinh chỉnh thông số sao cho phù hợp với nhu cầu sử dụng của bạn, biết đâu?), module tiện dụng và thân thiện này chủ yếu dùng cho các tên lửa mô hình công suất cao. Với tất cả tính tiện dụng và khả năng tinh chỉnh, RocketPy chắc chắn sẽ chứng tỏ mình thập phần hữu dụng trong các mô phỏng tên lửa thú vị.

Nguồn

  1. RocketPy Github
  2. RocketPy Documentation
  3. RocketPy Colab notebook preview
  4. Động cơ Cesaroni M3100
  5. Tên lửa mô hình công suất cao