151 lines
6.3 KiB
Python
151 lines
6.3 KiB
Python
import pyactr
|
|
# from XPlaneConnect import *
|
|
import xpc
|
|
|
|
# Initialize XPlaneConnect client
|
|
|
|
class AircraftLandingModel(pyactr.ACTRModel):
|
|
def __init__(self,client):
|
|
super().__init__()
|
|
# Initialize the declarative memory (DM)
|
|
# self.decmem.add(
|
|
# [
|
|
# ("airspeed", 100), # Current airspeed (e.g., 100 knots)
|
|
# ("roll", 0), # Current roll (0 for wings level)
|
|
# ("heading", 0), # Current heading
|
|
# ("descent_rate", 500), # Current descent rate in fpm
|
|
# ("target_airspeed", 80), # Target airspeed during descent
|
|
# ("target_roll", 0), # Target roll (wings level)
|
|
# ("target_heading", 90), # Target heading (runway heading)
|
|
# ("target_descent_rate", 500) # Target descent rate (fpm)
|
|
# ]
|
|
# )
|
|
self.client = client
|
|
self.airspeed = 100
|
|
self.roll = 0
|
|
self.heading = 0
|
|
self.descent_rate = 500
|
|
self.target_airspeed = 80
|
|
self.target_roll = 0
|
|
self.target_heading = 0
|
|
self.target_descent_rate = 500
|
|
|
|
# Declare the state for previous values
|
|
self.previous_airspeed = None
|
|
self.previous_roll = None
|
|
self.previous_heading = None
|
|
self.previous_descent_rate = None
|
|
|
|
# Initialize the integral errors for each parameter
|
|
self.integral_airspeed = 0
|
|
self.integral_roll = 0
|
|
self.integral_heading = 0
|
|
self.integral_descent_rate = 0
|
|
|
|
# Integral gains (tune these values for performance)
|
|
self.Kp = 0.1 # Proportional gain
|
|
self.Ki = 0.01 # Integral gain
|
|
|
|
def proportionalIntegralControl(self, current, target, integral_error):
|
|
"""
|
|
Proportional-Integral control rule implementation for multiple parameters.
|
|
"""
|
|
# Calculate the error (current - target)
|
|
error = target - current
|
|
|
|
# Update the integral of the error
|
|
integral_error += error
|
|
|
|
# Calculate the control value using the PI formula
|
|
control_value = (self.Kp * error) + (self.Ki * integral_error)
|
|
|
|
return control_value, integral_error # Return control value and updated integral error
|
|
|
|
def update_controls_simultaneously(self):
|
|
"""
|
|
Update all controls at the same time by calculating control values for each parameter.
|
|
"""
|
|
|
|
print("Entered Update Controls Simultaneously")
|
|
# Compute control values for all parameters (yoke pull, yoke steer, rudder, throttle)
|
|
yoke_pull, self.integral_airspeed = self.proportionalIntegralControl(self.airspeed, self.target_airspeed, self.integral_airspeed)
|
|
yoke_steer, self.integral_roll = self.proportionalIntegralControl(self.roll, self.target_roll, self.integral_roll)
|
|
rudder, self.integral_heading = self.proportionalIntegralControl(self.heading, self.target_heading, self.integral_heading)
|
|
throttle, self.integral_descent_rate = self.proportionalIntegralControl(self.descent_rate, self.target_descent_rate, self.integral_descent_rate)
|
|
|
|
# Send all controls simultaneously to X-Plane
|
|
self.send_controls_to_xplane(yoke_pull, yoke_steer, rudder, throttle)
|
|
|
|
def send_controls_to_xplane(self, yoke_pull, yoke_steer, rudder, throttle):
|
|
"""
|
|
Sends all control inputs to X-Plane using XPlaneConnect
|
|
"""
|
|
# Send yoke pull, yoke steer, rudder, and throttle simultaneously
|
|
self.client.sendCTRL([yoke_pull, yoke_steer, rudder, throttle, -998, -998]) # Control inputs: [yoke_pull, yoke_steer, rudder, throttle]
|
|
|
|
|
|
|
|
# Update the model's DM based on X-Plane data
|
|
def update_aircraft_state(self):
|
|
print("Entered Update Aircraft State")
|
|
# Retrieve current data from X-Plane
|
|
airspeed = self.client.getDREF("sim/cockpit2/gauges/indicators/airspeed_kts_pilot")
|
|
roll = self.client.getDREF("sim/cockpit2/gauges/indicators/roll_AHARS_deg_pilot")
|
|
heading = self.client.getDREF("sim/cockpit2/gauges/indicators/heading_AHARS_deg_mag_pilot")
|
|
descent_rate = self.client.getDREF("sim/flightmodel/position/vh_ind_fpm")
|
|
|
|
# Update the model's declarative memory
|
|
# model.declarative_memory["airspeed"] = airspeed
|
|
# model.declarative_memory["roll"] = roll
|
|
# model.declarative_memory["heading"] = heading
|
|
# model.declarative_memory["descent_rate"] = descent_rate
|
|
|
|
self.airspeed = airspeed[0]
|
|
self.roll = roll[0]
|
|
self.heading = heading[0]
|
|
self.descent_rate = descent_rate[0]
|
|
print(self.airspeed)
|
|
print(self.roll)
|
|
print(self.heading)
|
|
print(self.descent_rate)
|
|
|
|
|
|
# def rules(self):
|
|
# """
|
|
# Define the rules for descent control using proportional-integral control for all controls at once.
|
|
# """
|
|
# return [
|
|
# # Rule to adjust all controls simultaneously based on PI control for each parameter
|
|
# pyactr.Production(
|
|
# condition=pyactr.Condition("airspeed", "airspeed") &
|
|
# pyactr.Condition("roll", "roll") &
|
|
# pyactr.Condition("heading", "heading") &
|
|
# pyactr.Condition("descent_rate", "descent_rate") &
|
|
# pyactr.Condition("target_airspeed", "target_airspeed") &
|
|
# pyactr.Condition("target_roll", "target_roll") &
|
|
# pyactr.Condition("target_heading", "target_heading") &
|
|
# pyactr.Condition("target_descent_rate", "target_descent_rate"),
|
|
# action=self.update_controls_simultaneously(),
|
|
# ),
|
|
# ]
|
|
|
|
|
|
# # Function to get the current dataref value for a given parameter
|
|
# def getDref(parameter_name):
|
|
# # Depending on the parameter name, you would query X-Plane datarefs
|
|
# if parameter_name == "Airspeed":
|
|
# # Get airspeed dataref
|
|
# return client.getData([DATAREF_AIRSPEED])
|
|
# elif parameter_name == "Roll":
|
|
# # Get roll angle dataref
|
|
# return client.getData([DATAREF_ROLL])
|
|
# elif parameter_name == "Hdg":
|
|
# # Get heading dataref
|
|
# return client.getData([DATAREF_HEADING])
|
|
# elif parameter_name == "DescentRate":
|
|
# # Get descent rate dataref
|
|
# return client.getData([DATAREF_DESCENT_RATE])
|
|
|
|
|
|
|