AirControl  1.3.0
Open Source, Modular, and Extensible Flight Simulator For Deep Learning Research
AC_Airplane_Controller.cs
1 using System.Collections.Generic;
2 using UnityEngine;
3 using Communicator;
4 using UnityEngine.UI;
5 using System.Numerics;
6 using Commons;
7 namespace AirControl
8 {
9 
10  public enum AirplaneState{
11  Taxiing,
12  GROUNDED,
13  FLYING,
14  }
19  [RequireComponent(typeof(AC_Airplane_Characteristics))]
20  [RequireComponent(typeof(AC_BaseAirplane_Input))]
21  [RequireComponent(typeof(AC_XboxAirplane_Input))]
23  {
24  #region variables
25  [Header("Base Airplane Properties")]
26  [Tooltip("Drag and drop here the AC_BaseAirplane_Input.cs OR AC_XboxAirplane_Input.cs")]
27  public AC_BaseAirplane_Input input;
28 
29  [Header("Airplane Characteristics")]
30  [Tooltip("Drag and drop here the AC_Airplane_Characteristics.cs")]
31  public AC_Airplane_Characteristics characteristics;
32 
33  [Tooltip("Weight is in pounds")]
34  private float airplaneWeight;
35 
36  [Tooltip("Initialize an empty object and set it in airplane body. That position is Center of Gravity of the Airplane. Hook that object here")]
37  public Transform centerOfGravity;
38 
39  [Header("Engines")]
40  [Tooltip("Initialize an empty object and set it in airplane body at the place of Engine. Add AC_Airplane_Engine script to that object. Hook that engine object here")]
41  public List<AC_Airplane_Engine> engines = new List<AC_Airplane_Engine>();
42 
43  [Header("Wheels")]
44  [Tooltip("Initialize wheel colliders and set it in airplane body at the place of wheel. Add AC_Airplane_Wheel script to that object. Hook those wheels object here")]
45  public List<AC_Airplane_Wheel> wheels = new List<AC_Airplane_Wheel>();
46 
47  [Header("Control Surfaces")]
48  [Tooltip("Initialize empty control surfaces. Add AC_Airplane_ControlSurface script to that object. Hook wheels object here")]
49  public List<AC_Airplane_ControlSurface> controlSurfaces = new List<AC_Airplane_ControlSurface>();
50 
51  // Starting from ground
52  private AirplaneState airplaneState = AirplaneState.Taxiing;
53  [SerializeField] private bool isGrounded = true;
54  [SerializeField] private bool isTaxiing = true;
55  [SerializeField] private bool isFlying = false;
56 
57  [Header("Airplane States")]
58  [Tooltip("Attach Airplane state gameobject from UI canvas here")]
59  public Toggle IsGroundedObject;
60  public Toggle IsFlyingObject;
61  public Toggle IsTaxiingObject;
62 
63 
64  // Meadian sea level
65  private float currentMSL;
66  // Above Ground Level
67  private float currentAGL;
68 
69  private float angularVelocity;
70 
71  // To detect if the Airplane is stuck
72  private UnityEngine.Vector3 lastAirplanePosition;
73  private UnityEngine.Vector3 currAirplanePosition;
74 
75  // private int lastCommCounter=0;
76  // private int currCommCounter=0;
77 
78  private float startPos_x;
79  private float startPos_y;
80  private float startPos_z;
81  private float startRot_x;
82  private float startRot_y;
83  private float startRot_z;
84  // Linear and angular velocity calcuation
85  // Linear and angular acceleration calcuation
86  private UnityEngine.Vector3 lastLinearVelocity;
87  private UnityEngine.Vector3 lastAngularVelocity;
88  private UnityEngine.Vector3 linearAcceleration;
89  private UnityEngine.Vector3 angularAcceleration;
90  #endregion
91 
92  #region Properties
93  public float CurrentMSL{
94  get{return currentMSL;}
95  }
96  public float CurrentAGL{
97  get{return currentAGL;}
98  }
99  public UnityEngine.Vector3 AngularVelocity{
100  get{return rb.angularVelocity;}
101  }
102  public UnityEngine.Vector3 LinearVelocity{
103  get{return rb.velocity;}
104  }
105  #endregion
106 
107  #region Constants
108  const float poundToKilos = 0.453592f;
109  const float metersToFeets = 3.28084f;
110 
111  #endregion
112 
113  #region Builtin Methods
114  public override void Start()
118  {
119  base.Start();
120  airplaneWeight = (float)CommonFunctions.airplanePreset[CommonFunctions.activeAirplane+"/airplaneWeight"];
121  //calculate final mass in kilos
122  float finalMass = airplaneWeight * poundToKilos;
123  startPos_x = rb.position.x;
124  startPos_y = rb.position.y;
125  startPos_z = rb.position.z;
126  startRot_x = rb.rotation.eulerAngles.x;
127  startRot_y = rb.rotation.eulerAngles.y;
128  startRot_z = rb.rotation.eulerAngles.z;
129  Debug.LogFormat("Starting Position x : {0} y: {1} z: {2} ",startPos_x, startPos_y, startPos_z );
130  Debug.LogFormat("Starting Rotation x : {0} y: {1} z: {2} ",startRot_x, startRot_y, startRot_z );
131  // linear & angular; Velocity & Acceleration
132  lastLinearVelocity = rb.velocity;
133  lastAngularVelocity = rb.angularVelocity;
134 
135  // if rigid body added then add center of mass
136  if (rb){
137  rb.mass = finalMass;
138  if(centerOfGravity){
139  rb.centerOfMass = centerOfGravity.localPosition;
140  } // handel exception
141 
142  // Initialize Airplane characteristics
143  characteristics = GetComponent<AC_Airplane_Characteristics>();
144  if(characteristics){
145  characteristics.InitCharacteristics(rb, input);
146  }
147 
148  }
149 
150  // Initialize Wheels
151  if (wheels != null){
152  if(wheels.Count>0){
153  foreach(AC_Airplane_Wheel wheel in wheels){
154  wheel.initWheel();
155  }
156  }
157  }
158  InvokeRepeating("CheckGrounded", 1f, 1f);
159  // InvokeRepeating("DetectAirplaneStuck", 5f, 5f);
160  }
161  void Update()
162  {
163  rewardCalculator();
164  broadcastPosition();
165  broadcastRotation();
166  broadcastAngulars();
167  }
168 
174  void broadcastPosition(){
175  UnityEngine.Vector3 absolutePosition = rb.position;
176  StaticOutputSchema.PosXAbs = absolutePosition.x;
177  StaticOutputSchema.PosYAbs = absolutePosition.y;
178  StaticOutputSchema.PosZAbs = absolutePosition.z;
179  UnityEngine.Vector3 relativePosition = rb.position - new UnityEngine.Vector3(startPos_x, startPos_y, startPos_z);
180  StaticOutputSchema.PosXRel = relativePosition.x;
181  StaticOutputSchema.PosYRel = relativePosition.y;
182  StaticOutputSchema.PosZRel = relativePosition.z;
183  }
189  void broadcastRotation(){
190  UnityEngine.Vector3 absoluteRotation = rb.rotation.eulerAngles;
191  StaticOutputSchema.RotXAbs = absoluteRotation.x;
192  StaticOutputSchema.RotYAbs = absoluteRotation.y;
193  StaticOutputSchema.RotZAbs = absoluteRotation.z;
194  UnityEngine.Vector3 relativeRotation = rb.rotation.eulerAngles - new UnityEngine.Vector3(startRot_x, startRot_y, startRot_z);
195  StaticOutputSchema.RotXRel = relativeRotation.x;
196  StaticOutputSchema.RotYRel = relativeRotation.y;
197  StaticOutputSchema.RotZRel = relativeRotation.z;
198  // Debug.LogFormat("Abs Rotation x : {0} y: {1} z: {2} ",absoluteRotation.x, absoluteRotation.y, absoluteRotation.z );
199  // Debug.LogFormat("Relative Rotation x : {0} y: {1} z: {2} ", relativeRotation.x, relativeRotation.y, relativeRotation.z);
200  }
204  void broadcastAngulars(){
205  // angular Acceleration & Velocity
206  StaticOutputSchema.AngularXVelocity = AngularVelocity.x;
207  StaticOutputSchema.AngularYVelocity = AngularVelocity.y;
208  StaticOutputSchema.AngularZVelocity = AngularVelocity.z;
209  angularAcceleration = (rb.angularVelocity - lastAngularVelocity) / Time.fixedDeltaTime;
210  lastAngularVelocity = rb.angularVelocity;
211  StaticOutputSchema.AngularXAcceleration = angularAcceleration.x;
212  StaticOutputSchema.AngularYAcceleration = angularAcceleration.y;
213  StaticOutputSchema.AngularXAcceleration = angularAcceleration.z;
214  // linear Acceleration & Velocity
215  StaticOutputSchema.LinearXVelocity = LinearVelocity.x;
216  StaticOutputSchema.LinearYVelocity = LinearVelocity.y;
217  StaticOutputSchema.LinearZVelocity = LinearVelocity.z;
218  linearAcceleration = (rb.velocity - lastLinearVelocity) / Time.fixedDeltaTime;
219  lastLinearVelocity = rb.velocity;
220  StaticOutputSchema.LinearXAcceleration = linearAcceleration.x;
221  StaticOutputSchema.LinearYAcceleration = linearAcceleration.y;
222  StaticOutputSchema.LinearZAcceleration = linearAcceleration.z;
223  }
224 
228  // void rewardCalculator(){
229  // float Height = 100f;
230  // float Base = start_y;
231  // float RateOfInclination = 230f;
232  // float Angle = 3f;
233  // float ideal_height= Height+((Base-Height)/(1.0f+ (float)Math.Pow(rb.position.z/RateOfInclination,Angle)));
234  // float Penalty = (float)Math.Pow(ideal_height-rb.position.y, 2);
235  // CommonFunctions.MaxR -= Penalty;
236  // Debug.Log("Reward : "+CommonFunctions.MaxR );
237  // StaticOutputSchema.Reward = CommonFunctions.MaxR;
238  // // Debug.LogFormat( "Ideal Height : {0} | Position Up (y) : {1} | Position Forward (z) : {2} ",ideal_height, rb.position.y, rb.position.z);
239  // }
240 
244  void rewardCalculator(){
245 
248  // if (StaticOutputSchema.IfCollision == false)
249  // {
250  if (isTaxiing){
251  Debug.DrawLine(rb.transform.forward,rb.velocity);
252  float forward_velocity = UnityEngine.Vector3.Dot(rb.velocity.normalized,rb.transform.forward)*0.1f;
253  // Debug.LogFormat("Forward Velocity : {0}, Direction : {1}, Forward Vector {2}",rb.velocity, rb.transform.forward,forward_velocity);
254  float l2_side = Mathf.Pow(UnityEngine.Vector3.Dot(rb.velocity,rb.transform.right),2);
255  float l2_up = -UnityEngine.Vector3.Dot(rb.velocity,rb.transform.up);
256  // Debug.LogFormat("other Side penalty : {0}, up reward : {1}",l2_side, l2_up);
257  StaticOutputSchema.Reward = forward_velocity*l2_up-l2_side;
258  if(StaticOutputSchema.CurrentSpeed<45){
259  //extra penalty if plane moves away from center of runway when speed is low
260  float dist = Mathf.Abs(transform.position.x - startPos_x);
261  StaticOutputSchema.Reward = forward_velocity*l2_up-l2_side-(dist*0.2);
262  }
263  else{
264  StaticOutputSchema.Reward = forward_velocity*l2_up-l2_side;
265  }
266  }
267  if (isFlying){
268  Debug.DrawLine(rb.transform.forward,rb.velocity);
269  float forward_velocity = UnityEngine.Vector3.Dot(rb.velocity,rb.transform.forward);
270  // Debug.LogFormat("Forward Velocity : {0}, Direction : {1}, Forward Vector {2}",rb.velocity, rb.transform.forward,forward_velocity);
271  float l2_side = Mathf.Pow(UnityEngine.Vector3.Dot(rb.velocity,rb.transform.right),2);
272  float l2_up = Mathf.Pow(UnityEngine.Vector3.Dot(rb.velocity,rb.transform.up),2);
273  // Debug.LogFormat("other Side penalty : {0}, up reward : {1}",l2_side, l2_up);
274  // Upside down detection
275  // to discourage Rolling
276  float rolling = -UnityEngine.Vector3.Dot(transform.up, UnityEngine.Vector3.down); // penalize if roll
277  float pitch = UnityEngine.Vector3.Dot(transform.forward, UnityEngine.Vector3.up); // penalize if head down
278  // Debug.Log("pitch : "+ pitch + " l2 up : "+ l2_up);
279  // Final reward
280  // StaticOutputSchema.Reward = l2_up*currentMSL*rolling-l2_side;
281  // StaticOutputSchema.Reward = pitch*currentMSL*rolling-l2_side;
282 
283  if(StaticOutputSchema.CurrentSpeed<45){
284  //extra penalty if plane moves away from center of runway when speed is low
285  float dist = Mathf.Abs(transform.position.x - startPos_x);
286  StaticOutputSchema.Reward = pitch*currentMSL*2*rolling-(dist*0.2);
287  }
288  else{
289  StaticOutputSchema.Reward = pitch*currentMSL*2*rolling;
290  }
291 
292  }
293 
294  // }
295 
296 
297  }
298 
299  #endregion
300 
301  #region Custom Methods
302  protected override void HandlePhysics()
306  {
307  if(input)
308  {
309  HandleEngines();
310  HandleCharacteristics();
311  HandleControlSurfaces();
312  HandleWheel();
313  HandleAltitude();
314  }// handle else
315 
316  // DB based update
317 
318  }
319 
323  void HandleEngines()
324  {
325  if(engines != null)
326  {
327  if(engines.Count > 0 )
328  {
329  foreach(AC_Airplane_Engine engine in engines)
330  {
331  rb.AddForce(engine.CalculateForce(input.StickyThrottle));
332  }
333  }
334  }
335 
336  }
340  void HandleCharacteristics( )
341  {
342  if (characteristics)
343  {
344  characteristics.UpdateCharacteristics();
345  }
346 
347  }
351  void HandleControlSurfaces( )
352  {
353  if(controlSurfaces.Count > 0)
354  {
355  foreach (AC_Airplane_ControlSurface controlSurface in controlSurfaces){
356  controlSurface.HandleControlSurface(input);
357  }
358  }
359  }
363  void HandleWheel( ){
364  if (wheels.Count>0)
365  {
366  foreach (AC_Airplane_Wheel wheel in wheels)
367  {
368  wheel.HandleWheel(input);
369  }
370  }
371 
372  }
376  void HandleAltitude(){
377  currentMSL = transform.position.y * metersToFeets;
378  RaycastHit hit;
379  if(Physics.Raycast(transform.position, UnityEngine.Vector3.down, out hit))
380  {
381  if(hit.transform.tag == "Ground" || hit.transform.tag == "Building")
382  {
383  currentAGL = (hit.distance) *metersToFeets;
384  }
385  }
386 
387  #region DBArea
388  StaticOutputSchema.MSL = currentMSL;
389  StaticOutputSchema.AGL = currentAGL;
390  #endregion
391  }
392 
396  void CheckGrounded()
397  {
398  if(wheels.Count > 0){
399  int groundedCount = 0;
400  foreach(AC_Airplane_Wheel wheel in wheels)
401  {
402  if(wheel.isGrounded)
403  {
404  groundedCount++;
405  }
406  }
407  if(groundedCount == wheels.Count)
408  {
409  if(rb.velocity.magnitude > 1f){
410  isTaxiing = true;
411  isGrounded = false;
412  isFlying = false;
413  // update to API and UI
414  IsGroundedObject.isOn = StaticOutputSchema.IsGrounded = isGrounded;
415  IsTaxiingObject.isOn = StaticOutputSchema.IsTaxiing = isTaxiing;
416  IsFlyingObject.isOn = StaticOutputSchema.IsFlying = isFlying;
417  }
418  else{
419  isTaxiing = false;
420  isGrounded = true;
421  isFlying = false;
422  // update to API and UI
423  IsGroundedObject.isOn = StaticOutputSchema.IsGrounded = isGrounded;
424  IsTaxiingObject.isOn = StaticOutputSchema.IsTaxiing = isTaxiing;
425  IsFlyingObject.isOn = StaticOutputSchema.IsFlying = isFlying;
426  }
427  }
428  else
429  {
430  isTaxiing = false;
431  isGrounded = false;
432  isFlying = true;
433  // update to API and UI
434  IsGroundedObject.isOn = StaticOutputSchema.IsGrounded = isGrounded;
435  IsTaxiingObject.isOn = StaticOutputSchema.IsTaxiing = isTaxiing;
436  IsFlyingObject.isOn = StaticOutputSchema.IsFlying = isFlying;
437  }
438 
439  }
440  }
444  // private void DetectAirplaneStuck()
445  // {
446  // currAirplanePosition = rb.transform.localPosition;
447  // if(currAirplanePosition == lastAirplanePosition)
448  // {
449  // StaticOutputSchema.log = "Airplane was stuck";
450  // Debug.LogError("Airplane was stuck");
451 
452  // // Relaod the level
453  // SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene().name);
454  // SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().name);
455  // StaticOutputSchema.IfCollision = true;
456  // StaticOutputSchema.CollisionObject = "Stuck";
457  // }
458  // lastAirplanePosition = currAirplanePosition;
459 
460  // }
461 
462 
463  #endregion
464  }
465 
466 }
AirControl.AC_Airplane_Controller.HandlePhysics
override void HandlePhysics()
Handles physics related to Engine, Characteristics, Control surfaces wheel and Altitude
Definition: AC_Airplane_Controller.cs:305
AirControl.AC_Airplane_Engine
Engine controls
Definition: AC_Airplane_Engine.cs:22
AirControl.AC_BaseAirplane_Input
Base class to listen for keyboard Inputs
Definition: AC_BaseAirplane_Input.cs:12
AirControl.AC_Airplane_ControlSurface.HandleControlSurface
void HandleControlSurface(AC_BaseAirplane_Input input)
Main function to handle Control Surface
Definition: AC_Airplane_ControlSurface.cs:53
AirControl.AC_Airplane_Wheel.initWheel
void initWheel()
Init wheel set the motor torque to very small nuber to allow it to roll freely
Definition: AC_Airplane_Wheel.cs:70
AirControl.AC_Airplane_Controller
Master Controller, controls the entire Airplane it implements function to Handle Engines,...
Definition: AC_Airplane_Controller.cs:22
AirControl.AC_Airplane_Characteristics.InitCharacteristics
void InitCharacteristics(Rigidbody curRB, AC_BaseAirplane_Input curInput)
Initialize Airplane Charatceristics
Definition: AC_Airplane_Characteristics.cs:90
AirControl.AC_Airplane_Engine.CalculateForce
Vector3 CalculateForce(float throttle)
Calculate the force created by engine Calculate Engine RPM Calculate fuel consumption
Definition: AC_Airplane_Engine.cs:110
AirControl.AC_BaseRigidbody_Controller
Definition: AC_BaseRigidbody_Controller.cs:12
AirControl.AC_Airplane_Characteristics.UpdateCharacteristics
void UpdateCharacteristics()
Update all the Flight Characteristics methods
Definition: AC_Airplane_Characteristics.cs:105
AirControl
Definition: AirplaneSelector.cs:8
AirControl.AC_Airplane_ControlSurface
Handle control surfaces including Rudder, Elevator, Flaps,and Alerons
Definition: AC_Airplane_ControlSurface.cs:16
Communicator
Definition: InputHandle.cs:10
AirControl.AC_Airplane_Wheel.HandleWheel
void HandleWheel(AC_BaseAirplane_Input input)
Handle whele graphics, and steering
Definition: AC_Airplane_Wheel.cs:81
AirControl.AC_Airplane_Controller.Start
override void Start()
Regulate initilaization like mass of the Vehicle, Gravity, Wheels and Characteristics
Definition: AC_Airplane_Controller.cs:117
AirControl.AC_Airplane_Wheel
Handle wheel braking and steering
Definition: AC_Airplane_Wheel.cs:11
Commons
Definition: AirplaneProperties.cs:14
AirControl.AC_Airplane_Characteristics
Main class defines the Airplane Characteristics
Definition: AC_Airplane_Characteristics.cs:11