Avionics
Dropship Simulator
AFCS.cpp
Go to the documentation of this file.
1 #include "Module.h"
2 #include "../Extensions.h"
3 
4 Afcs::Afcs(Bus* prmBus, Logger* prmLogger) : Module(prmBus)
5 {
6  bus = prmBus;
7  logger = prmLogger;
8 }
9 
10 void Afcs::FrameMove(float fElapsedTime)
11 {
15 
16 #pragma region Commands
17 
18  for (UINT i = 0; i < bus->commandStream.size(); i++)
19  {
20  Command command = bus->commandStream.at(i);
21  if (command.delay != 0.0f) continue;
22 
23  if (command.name == "AFCS-VerticalModeCycle")
24  {
25  Command newCommand;
26  newCommand.name = "AFCS-VerticalMode";
27  switch (bus->AFCS.CurrentVerticalMode)
28  {
29  case Bus::Afcs::VerticalModes::VerticalMode_Off: newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::Pitch);
30  break;
31  case Bus::Afcs::VerticalModes::Pitch: newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::VerticalSpeed);
32  break;
33  case Bus::Afcs::VerticalModes::VerticalSpeed: newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::Altitude);
34  break;
35  default: newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::VerticalMode_Off);
36  break;
37  }
38  bus->commandStream.push_back(newCommand);
39  bus->commandStream.erase(bus->commandStream.begin() + i);
40  }
41  else if (command.name == "AFCS-LateralModeCycle")
42  {
43  Command newCommand;
44  newCommand.name = "AFCS-LateralMode";
45  switch (bus->AFCS.CurrentLateralMode)
46  {
47  case Bus::Afcs::LateralModes::LateralMode_Off: newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::Roll);
48  break;
49  case Bus::Afcs::LateralModes::Roll: newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::Heading);
50  break;
51  case Bus::Afcs::LateralModes::Heading:
52  {
53  if (bus->waypoints.size() > 0) // must have a waypoint in order to NAV
54  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::Navigation);
55  else
56  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::LateralMode_Off);
57  break;
58  }
59  default: newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::LateralMode_Off);
60  break;
61  }
62  bus->commandStream.push_back(newCommand);
63  bus->commandStream.erase(bus->commandStream.begin() + i);
64  }
65  else if (command.name == "AFCS-VerticalMode")
66  {
68 
70  if (bus->AFCS.CurrentVerticalMode && bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::LateralMode_Off)
71  {
72  Command newCommand;
73  newCommand.name = "AFCS-LateralMode";
74  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::Roll);
75  bus->commandStream.push_back(newCommand);
76  }
77 
80  {
82  {
83  Command newCommand;
84  newCommand.name = "AFCS-LateralMode";
85  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::LateralMode_Off);
86  bus->commandStream.push_back(newCommand);
87  }
89  {
90  Command newCommand;
91  newCommand.name = "AFCS-Autopilot";
92  newCommand.bvalue = false;
93  bus->commandStream.push_back(newCommand);
94  }
96  {
97  Command newCommand;
98  newCommand.name = "AFCS-ArmVerticalMode";
99  newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::VerticalMode_Off);
100  bus->commandStream.push_back(newCommand);
101  }
102  }
103  if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalSpeed)
104  bus->AFCS.DesiredVsi = 0.0f;
105 
107  if (bus->AFCS.CurrentVerticalMode && bus->AFCS.CurrentVerticalMode != Bus::Afcs::VerticalModes::Altitude)
108  bus->AFCS.StandbyVerticalMode = Bus::Afcs::VerticalModes::Altitude;
109  else
110  bus->AFCS.StandbyVerticalMode = Bus::Afcs::VerticalModes::VerticalMode_Off;
111  bus->commandStream.erase(bus->commandStream.begin() + i);
112  }
113  else if (command.name == "AFCS-PitchSetting")
114  {
115  bus->AFCS.DesiredPitch = command.fvalue;
116  bus->commandStream.erase(bus->commandStream.begin() + i);
117  }
118  else if (command.name == "AFCS-VsiSetting")
119  {
120  bus->AFCS.DesiredVsi = command.fvalue;
121  bus->commandStream.erase(bus->commandStream.begin() + i);
122  }
123  else if (command.name == "AFCS-AltitudeSetting")
124  {
125  bus->AFCS.DesiredAltitude = command.fvalue;
126  bus->commandStream.erase(bus->commandStream.begin() + i);
127  }
128  else if (command.name == "AFCS-ArmLateralMode")
129  {
130  bus->AFCS.StandbyLateralMode = static_cast<Bus::Afcs::LateralModes>(command.ivalue);
131  bus->commandStream.erase(bus->commandStream.begin() + i);
132  }
133  else if (command.name == "AFCS-ArmVerticalMode")
134  {
136  bus->commandStream.erase(bus->commandStream.begin() + i);
137  }
138  else if (command.name == "AFCS-LateralMode")
139  {
140  bus->AFCS.CurrentLateralMode = static_cast<Bus::Afcs::LateralModes>(command.ivalue);
141 
142  if (bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Roll)
143  {
145  if (fabsf(D3DXToDegree(bus->RollAttitude)) <= 6.0f)
146  bus->AFCS.DesiredRoll = 0.0f;
147  else if (D3DXToDegree(bus->RollAttitude) >= 35.0f)
148  bus->AFCS.DesiredRoll = 35.0f;
149  else if (D3DXToDegree(bus->RollAttitude) <= -35.0f)
150  bus->AFCS.DesiredRoll = -35.0f;
151  else
153  }
154  else if (bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Heading)
155  {
157  }
158  else if (bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Navigation)
159  {
160  bus->AFCS.DesiredCourse = -999.0f; // direct
161  }
162 
164  if (bus->AFCS.CurrentLateralMode && bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalMode_Off)
165  {
166  Command newCommand;
167  newCommand.name = "AFCS-VerticalMode";
168  newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::Pitch);
169  bus->commandStream.push_back(newCommand);
170  }
171 
174  {
176  {
177  Command newCommand;
178  newCommand.name = "AFCS-VerticalMode";
179  newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::VerticalMode_Off);
180  bus->commandStream.push_back(newCommand);
181  }
183  {
184  Command newCommand;
185  newCommand.name = "AFCS-Autopilot";
186  newCommand.bvalue = false;
187  bus->commandStream.push_back(newCommand);
188  }
190  {
191  Command newCommand;
192  newCommand.name = "AFCS-ArmLateralMode";
193  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::LateralMode_Off);
194  bus->commandStream.push_back(newCommand);
195  }
196  }
197 
198  bus->commandStream.erase(bus->commandStream.begin() + i);
199  }
200  else if (command.name == "AFCS-RollSetting")
201  {
202  bus->AFCS.DesiredRoll = command.fvalue;
203  bus->commandStream.erase(bus->commandStream.begin() + i);
204  }
205  else if (command.name == "AFCS-HeadingRelative")
206  {
208  bus->commandStream.erase(bus->commandStream.begin() + i);
209  }
210  else if (command.name == "AFCS-AutopilotCycle")
211  {
212  Command newCommand;
213  newCommand.name = "AFCS-Autopilot";
214  newCommand.bvalue = !bus->AFCS.AutopilotEngaged;
215  bus->commandStream.push_back(newCommand);
216  bus->commandStream.erase(bus->commandStream.begin() + i);
217  }
218  else if (command.name == "AFCS-Autopilot")
219  {
220  bus->AFCS.AutopilotEngaged = command.bvalue;
222  {
224  if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalMode_Off)
225  {
226  Command newCommand;
227  newCommand.name = "AFCS-VerticalMode";
228  newCommand.ivalue = static_cast<int>(Bus::Afcs::VerticalModes::Pitch);
229  bus->commandStream.push_back(newCommand);
230  }
231  }
232  else
233  {
234  Command newCommand;
235  newCommand.name = "APDisconnect";
236  bus->commandStream.push_back(newCommand);
238  {
239  newCommand.name = "AFCS-Autothrottle";
240  newCommand.bvalue = false;
241  bus->commandStream.push_back(newCommand);
242  }
243  }
244  bus->commandStream.erase(bus->commandStream.begin() + i);
245  }
246  else if (command.name == "AFCS-Autothrottle")
247  {
248  if (command.bvalue)
249  {
251  bus->AFCS.AutothrottleEngaged = command.bvalue;
252  }
253  else
254  bus->AFCS.AutothrottleEngaged = command.bvalue;
255  bus->commandStream.erase(bus->commandStream.begin() + i);
256  }
257  else if (command.name == "AFCS-SetThrust")
258  {
259  bus->AFCS.DesiredThrust = command.fvalue;
260  bus->commandStream.erase(bus->commandStream.begin() + i);
261  }
262  }
263 
264 #pragma endregion
265 
266 #pragma region Vertical Modes
267 
268  if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::GlideSlope && bus->waypoints.size() > 0) // G/S
269  {
271  D3DXVECTOR3 diff3 = bus->Location - bus->waypoints.at(0).absoluteLocation();
272  bus->RadioAltitude = -diff3.z;
273 
274  D3DXVECTOR2 diff2 = D3DXVECTOR2(diff3.x, diff3.y);
275  float dist = D3DXVec2Length(&diff2);
276  float desiredaltitude = -(bus->waypoints.at(0).absoluteLocation().z - sinf(0.05235987755982988730771072305466f) * dist); // sin of 0.05 is 3 degree slope
277 
278  // positive means we are above
279  bus->GlideslopeDeviation = atanf((bus->PressureAltitude - desiredaltitude) / dist);
280 
281  // FPA should be -.0523 so we take difference and add it to the current pitch attitude
282  float pitchdiff = D3DXToRadian(-3.0f) - bus->FlightPathAngle; // was -.06 .. we want -.0523 so that means we need to pitch up +.01
283  float desiredpitch = bus->PitchAttitude + pitchdiff * 0.5f; // 1 deg of pitch doesn't equal 1 deg of fpa?
284  desiredpitch -= bus->GlideslopeDeviation * 0.5f;
285 
286  // smooth the new pitch down
287  bus->AFCS.DesiredPitch += (desiredpitch - bus->AFCS.DesiredPitch) * fElapsedTime;
288  }
289  else if (bus->AFCS.StandbyVerticalMode == Bus::Afcs::VerticalModes::GlideSlope && bus->waypoints.size() > 1)
290  {
292  D3DXVECTOR3 diff3 = bus->Location - bus->waypoints.at(1).absoluteLocation();
293  bus->RadioAltitude = -diff3.z;
294 
295  D3DXVECTOR2 diff2 = D3DXVECTOR2(diff3.x, diff3.y);
296  float dist = D3DXVec2Length(&diff2);
297  float desiredaltitude = -(bus->waypoints.at(1).absoluteLocation().z - sinf(0.05235987755982988730771072305466f) * dist); // sin of 0.05 is 3 degree slope
298 
299  // positive means we are above
300  bus->GlideslopeDeviation = atanf((bus->PressureAltitude - desiredaltitude) / dist);
301  }
302  else
303  {
304  bus->GlideslopeDeviation = 0.0f;
305  bus->RadioAltitude = 0.0f;
306  }
307 
308  if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::Altitude) // msl or G/S
309  {
313  if ((fabsf(oldDesiredVsi) > 0.3048f && fabsf(bus->AFCS.DesiredVsi) <= 0.3048f) || // roughly 1000 feet
314  (fabsf(oldDesiredVsi) < 0.06096f && fabsf(bus->AFCS.DesiredVsi) >= 0.06096f)) // roughly 200 feet
315  {
316  Command newCommand;
317  newCommand.name = "CChord";
318  bus->commandStream.push_back(newCommand);
319  }
321 
322  bus->AFCS.DesiredVsi *= 0.03477690288713910761154855643045f; // 1/.3048*.01016
323  //if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::GlideSlope)
324  // bus->AFCS.DesiredVsi *= 2.5f;
325  // if we leave the altitude once we got there? 200 feet is the rule in GA, and within 1000 feet of selected
326  // so T-1 with 2 is .1 but E-10 with 3.5 is .05
327  // limit +/- 6000 fpm (30.5 m/s)
328  if (bus->AFCS.DesiredVsi > 0.0305f)
329  bus->AFCS.DesiredVsi = 0.0305f;
330  else if (bus->AFCS.DesiredVsi < -0.0305f)
331  bus->AFCS.DesiredVsi = -0.0305f;
332  // desiredvsi*=0.012695510867357302457850903920374;
333  // sprintf_s(msg, 99, "\t MSL\tcur %.3f\n", f_MSL);
334  // _write(logfile, msg, strlen(msg));
335  }
336  /*
337  if (verticalmode == 3) // ias
338  {
339  // 0.090 - 0.080 is +0.010 is 1 deg so *100
340  float deltaias = -(desiredias - ias);
341  float targetpitch = horizonpitch + deltaias*3.0f; // was 10
342  float diff = targetpitch - desiredpitch;
343  if (diff>0.052359877559829887307710723054658f) // 3 degrees per second
344  diff = 0.052359877559829887307710723054658f;
345  else if (diff<-0.052359877559829887307710723054658f)
346  diff = -0.052359877559829887307710723054658f;
347  desiredpitch += diff*fElapsedTime; // 0.1-0.01=0.09
348  // deg limit
349  if (desiredpitch>0.34906585039886591538473815369772f) // nose up 20
350  desiredpitch = 0.34906585039886591538473815369772f;
351  else if (desiredpitch<-0.26179938779914943653855361527329f) // nose down 15
352  desiredpitch = -0.26179938779914943653855361527329f;
353  // sprintf_s(msg, 99, "\t VSI\tcur %.3f tgt %.3f\n", vsi, desiredvsi);
354  // _write(logfile, msg, strlen(msg));
355  }
356  */
357 
358  // v/s, higher modes than IAS, T/O (T/O used to be a vertical speed mode!? yup, +/-0.1 (km/s?) )
359  if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalSpeed ||
360  bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::Altitude ||
361  bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::SpeedPitch)
362  {
364  static float smoothalt = 0.0f;
365  smoothalt += (bus->PressureAltitude - smoothalt) * fElapsedTime * 2.0f; // was 0.25f no elapsed
366 
368  static float lastAltitudeUpdate = 0.0f;
369  lastAltitudeUpdate += fElapsedTime;
370  static float oldaltitude = 0.0f;
371  float altdiff = smoothalt - oldaltitude;
372  if (altdiff != 0.0f)
373  {
374  bus->VerticalSpeed = altdiff / fElapsedTime;
375  lastAltitudeUpdate = 0.0f;
376  }
377  else if (lastAltitudeUpdate > 1.0f)
378  bus->VerticalSpeed = 0.0f;
379  oldaltitude = smoothalt;
380 
381 
382  // 0.020 - 0.010 is +0.010 is 1 deg so *100
383  float deltavsi = bus->AFCS.DesiredVsi - bus->VerticalSpeed;
384  float targetpitch = bus->PitchAttitude + deltavsi * 3.0f;
385  float diff = targetpitch - bus->AFCS.DesiredPitch;
386  if (diff > 0.052359877559829887307710723054658f) // 3 degrees per second
387  diff = 0.052359877559829887307710723054658f;
388  else if (diff < -0.052359877559829887307710723054658f)
389  diff = -0.052359877559829887307710723054658f;
390  //if (bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::GlideSlope)
391  //{
392  // if (diff > 0.025f) // 1.5 degrees per second
393  // diff = 0.025f;
394  // else if (diff<-0.025f)
395  // diff = -0.025f;
396  //}
397  bus->AFCS.DesiredPitch += diff * fElapsedTime; // 0.1-0.01=0.09
398  // deg limit
399  if (bus->AFCS.DesiredPitch > 0.34906585039886591538473815369772f) // nose up 20
400  bus->AFCS.DesiredPitch = 0.34906585039886591538473815369772f;
401  else if (bus->AFCS.DesiredPitch < -0.26179938779914943653855361527329f) // nose down 15
402  bus->AFCS.DesiredPitch = -0.26179938779914943653855361527329f;
403  // sprintf_s(msg, 99, "\t VSI\tcur %.3f tgt %.3f\n", vsi, desiredvsi);
404  // _write(logfile, msg, strlen(msg));
405  }
406 
407 
408  if (bus->AFCS.CurrentVerticalMode && bus->AFCS.AutopilotEngaged) // pitch mode
409  {
410  // smooth pitch
411  static float pitch = 0.0f;
412  pitch += (bus->PitchAttitude - pitch) * fElapsedTime * 2.0f; // was 0.25f no elapsed
413 
414  static float oldpitchrate = 0.0f;
415 
416  float deltapitch;
417  if (fabsf(bus->RollAttitude) < D3DX_PI) // unusual attitudes
418  deltapitch = bus->AFCS.DesiredPitch - pitch;//-playerships[ourcockpit.ourshipC].pitch;
419  else
420  deltapitch = -bus->AFCS.DesiredPitch - pitch;//-playerships[ourcockpit.ourshipC].pitch;
421 
422  float currentrate = (pitch - oldPitchAttitude) / fElapsedTime;
423 
424  // 10 deg, we do max of 3 deg per sec
425  float desiredrate = deltapitch * 0.3f;
426  // never more than 3 deg per sec
427  if (desiredrate > 0.052359877559829887307710723054658f)
428  desiredrate = 0.052359877559829887307710723054658f;
429  else if (desiredrate < -0.052359877559829887307710723054658f)
430  desiredrate = -0.052359877559829887307710723054658f;
431 
432 
433  // float authority=fabsf(playerships[ourcockpit.ourshipC].pitch/0.052359877559829887307710723054658f);
434  // if (authority>10.0f) // 3 deg/sec==1.0f
435  // authority=10.0f;
436  // else if (authority<0.1f)
437  // authority=0.1f;
438  // desiredrate*=1.0f/authority;
439 
440  static float oldcorrection = 0.0f;
441  // we want to effect a change on the pitch of a certain number of deg/s/s so we look at how much it did
442  // from one frame to another and magnify the effect
443  float effectivechange = oldpitchrate - currentrate;
444  float magnify = 1.0f;
445  if (oldcorrection != 0.0f && bus->IndicatedAirspeed > Vs1)
446  magnify = fabsf(oldcorrection - effectivechange) / fabsf(oldcorrection) + 1.0f;
447  // magnify*=magnify; // 4
448  if (magnify > 10.0f)
449  magnify = 10.0f;
450  else if (magnify < 0.1f)
451  magnify = 0.1f;
452 
453  //desiredrate *= magnify;
454  // follow a running magnify average
455  // static float magavg=200.0f;
456  // magavg*=0.995f; // was 100, now 99
457  // magavg+=magnify; // now 10 again
458 
459 
460  // char msg[999];
461  //sprintf_s( msg, 999, "AF* current %.1f requested %.1f magnify %.1f desiredrate %.1f/s\n",
462  //D3DXToDegree(horizonpitch), D3DXToDegree(desiredpitch), magnify, D3DXToDegree(desiredrate) );
463  //_write(logfile, msg, strlen(msg));
464 
465  oldpitchrate = currentrate;
466  oldPitchAttitude = pitch; // save for next time where it should have been
467 
468  // oldcorrection=(desiredrate-playerships[ourcockpit.ourshipC].pitch)*fElapsedTime*ourcockpit.appitagr;
469  oldcorrection = (desiredrate - currentrate) * magnify * fElapsedTime * 0.3f * PitchAggression;
470  if (oldcorrection > 0.52359877559829887307710723054658f)
471  oldcorrection = 0.52359877559829887307710723054658f;
472  else if (oldcorrection < -0.52359877559829887307710723054658f)
473  oldcorrection = -0.52359877559829887307710723054658f;
474  //oldcorrection *= fElapsedTime;
475 
476  bus->AFCS.PitchInput = Library::MathUtils::Clamp(bus->AFCS.PitchInput + oldcorrection, -1.0f, 1.0f);
477 
478  float transfer = bus->PitchControl * 0.02f * fElapsedTime; // will be there in less than 60 sec times pitch agressivness
481  if (bus->PitchTrim > 0.2618f) // 15°
482  bus->PitchTrim = 0.2618f;
483  else if (bus->PitchTrim < -0.2618f)
484  bus->PitchTrim = -0.2618f;
485  else
486  bus->PitchTrim += transfer;
487 
488  if (fabsf(bus->AFCS.PitchInput + bus->PitchTrim) >= 0.5f)
489  {
490  Command command;
491  command.name = "AltitudeCoupler";
492  bus->commandStream.push_back(command);
493  }
494 
495  // we want pitch to be 0 when desiredpitch==horizonpitch, 3deg/sec when desiredpitch is 10 off
496  // sprintf_s(msg, 99, "\tPITCH\ttgt %.3f - cur %.3f = dlt %.3f (sat rat %.3f) - cur %.3f = trm %.3f\n", D3DXToDegree(desiredpitch), D3DXToDegree(horizonpitch), D3DXToDegree(deltapitch), desiredrate, playerships[ourcockpit.ourshipC].pitch, trim);
497  // _write(logfile, msg, strlen(msg));
498  }
499 
500 #pragma endregion
501 
502  // rules like we are squat switched and not TO/TO but have active mode then switch to TO/TO
503 
504 #pragma region Lateral Modes
505 
506  if (bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Navigation ||
507  bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Localizer) // nav mode/loc mode determines a heading
508  {
509  // if we are in loc/nav and we run out of waypoints then we go to heading mode?
510  if (bus->waypoints.size() > 0)
511  {
512  Waypoint nextWaypoint = bus->waypoints.at(0);
513  D3DXVECTOR3 result = bus->Location - nextWaypoint.absoluteLocation();
514  D3DXVECTOR2 result2 = D3DXVECTOR2(result.x, result.y);
515  float dist = D3DXVec2Length(&result2);
516  float bear = atan2f(result2.y, result2.x) - D3DX_PI * 0.5f - bus->HeadingTrue;
517  if (bear >= D3DX_PI * 2.0f)
518  bear -= D3DX_PI * 2.0f;
519  else if (bear < 0.0f)
520  bear += D3DX_PI * 2.0f;
521 
523  bus->HeadingTrack = bus->HeadingTrue; // no wind
524 
525 
526  //LOOK HERE, we were 352.7 he was bear 17.3 so course is 10
527 
528  // start with desiredcrs given
529  // heading to object
530  float hdg2obj = bus->HeadingTrue + bear; // 020+020 is 040
531  if (hdg2obj > D3DX_PI * 2.0f)
532  hdg2obj -= D3DX_PI * 2.0f;
533  else if (hdg2obj < 0.0f)
534  hdg2obj += D3DX_PI * 2.0f;
535 
536 
537  if (bus->AFCS.DesiredCourse == -999.0f) // direct
538  bus->AFCS.DesiredCourse = hdg2obj;
539 
540 
541  // difference between them should be 0
542  // this is where we need to look for flyover vs. flyby
543  // http://rise.unistellar.com/jira/view.php?id=456
544  float correct = hdg2obj - bus->AFCS.DesiredCourse; // 020-350 is -330
545  if (correct > D3DX_PI) // 359
546  correct -= D3DX_PI * 2.0f; // to fix case of 359-0 is 359 instead of -1
547  else if (correct < -D3DX_PI)
548  correct += D3DX_PI * 2.0f;
549  if (correct > D3DX_PI * 0.5f) // 179
550  correct = D3DX_PI - correct; // 1 to the right
551  else if (correct < -D3DX_PI * 0.5f) // -179
552  correct = -D3DX_PI - correct;
553 
554  bus->LocalizerDeviation = correct;
555 
556  if (bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Localizer)
557  correct *= 4.0f;
558  else
559  correct *= 2.0f; // overcorrect to intercept... 1.0f would just be parallel
560  if (correct > D3DX_PI * 0.25f) // no more than 45 degrees though
561  correct = D3DX_PI * 0.25f;
562  else if (correct < -D3DX_PI * 0.25f)
563  correct = -D3DX_PI * 0.25f;
564  if (dist < 4.0f) // and reduce correction based on distance
565  correct *= dist * 0.25f;
566 
567  // if insttrk is 320 and we are 330 then we need to pretend we are +10
568  float trkadj = bus->HeadingTrue - bus->HeadingTrack; // +10
569  if (trkadj > D3DX_PI * 2.0f)
570  trkadj -= D3DX_PI * 2.0f;
571  else if (trkadj < 0.0f)
572  trkadj += D3DX_PI * 2.0f;
573 
574  bus->AFCS.DesiredHeading = bus->AFCS.DesiredCourse + correct + trkadj;
575  if (bus->AFCS.DesiredHeading > D3DX_PI * 2.0f)
576  bus->AFCS.DesiredHeading -= D3DX_PI * 2.0f;
577  else if (bus->AFCS.DesiredHeading < 0.0f)
578  bus->AFCS.DesiredHeading += D3DX_PI * 2.0f;
579  }
580  else
581  {
582  Command newCommand;
583  newCommand.name = "AFCS-LateralMode";
584  newCommand.ivalue = static_cast<int>(Bus::Afcs::LateralModes::Heading);
585  bus->commandStream.push_back(newCommand);
586  }
587  }
588 
589 
590  if (bus->AFCS.CurrentLateralMode >= Bus::Afcs::LateralModes::Heading) // hdg mode
591  {
592  float desiredroll = bus->AFCS.DesiredHeading - bus->HeadingTrue; // we were 030 and selected 360, that is 330 greater than 180
593 
594  if (desiredroll < -D3DX_PI)
595  desiredroll = D3DX_PI * 2.0f + bus->AFCS.DesiredRoll;
596  else if (desiredroll > D3DX_PI) // more than 180 to right
597  desiredroll = bus->AFCS.DesiredRoll - D3DX_PI * 2.0f;
598  //desiredroll *= 0.333333f*3.0f; // agressive A-4 is 1.0f // 30 bank is 10 deg
599 
600  // limit to 30 deg of bank
601  if (desiredroll > 0.523599f)
602  desiredroll = 0.523599f;
603  else if (desiredroll < -0.523599f)
604  desiredroll = -0.523599f;
605 
606  // smooth the new roll
607  bus->AFCS.DesiredRoll += (desiredroll - bus->AFCS.DesiredRoll) * fElapsedTime;
608  }
609 
610 
611  if (bus->AFCS.CurrentLateralMode && bus->AFCS.AutopilotEngaged) // roll mode
612  {
613  // we want 30 deg bank, we are at 0 deg bank so that is 30deg
614  float deltaroll = bus->AFCS.DesiredRoll - bus->RollAttitude;//-D3DXToDegree(playerships[ourcockpit.ourshipC].roll); // degrees, can be up to 60 usually 30
615 
616  // desiredrate is 10deg/s
617  float desiredrate = deltaroll * 0.3f; // 10 deg/s for 30 deg
618  // desiredrate=D3DXToRadian(desiredrate); everything is in rads
619  // we want 10 deg per sec max
620  desiredrate = Library::MathUtils::Clamp(desiredrate, -0.1745329252f, 0.1745329252f);
621  // we want roll to be 0 when desiredroll==horizonroll, 10deg/sec when desiredpitch is 30 off
622  // so we want to increase/decrease the rate
623 
624  float currentRollRate = (bus->RollAttitude - oldRollAttitude) / fElapsedTime; // rad per second
626 
627  float ratediff = desiredrate - currentRollRate; // we want 10deg per sec, we have 0deg per sec
628  // so ratediff=10deg/sec, 0 deg/sec is centered, 10deg/sec is full right
629 
630  float oldcorrection = (ratediff * 3.0f - bus->AFCS.RollInput) * RollAggression * 0.5235987756f; // agressiveness, A-4 is 1.0f
631  //oldcorrection = Clamp(oldcorrection, -0.523599f, 0.523599f); // limit to 30 deg of bank? I commented this out 4/18/2015
632 
633  bus->AFCS.RollInput = Library::MathUtils::Clamp(bus->AFCS.RollInput + oldcorrection * fElapsedTime, -1.0f, 1.0f);
634  // char msg[999];
635  //sprintf_s(msg, "desired %.1f° - horizon %.1f° = delta %.1f° *0.3= ratechange %frad - currate %frad = ratediff %frad >>> rolladj %frad/s\n",
636  //desiredroll, horizonroll, deltaroll, desiredrate, playerships[ourcockpit.ourshipC].roll, ratediff, ratediff*3.0f-roll);
637  //_write(logfile, msg, strlen(msg));
638 
639 
640  // sprintf_s(msg, 99, "\tROLL\ttgt %.3f - cur %.3f = dlt %.3f (rad %.3f - cur %.3f = trm %.3f)\n",
641  // D3DXToDegree(desiredroll), D3DXToDegree(horizonroll), D3DXToDegree(deltaroll), desiredrate, playerships[ourcockpit.ourshipC].roll, roll);
642  // _write(logfile, msg, strlen(msg));
643  }
644 
645 #pragma endregion
646 }
D3DXVECTOR3 absoluteLocation() const
Definition: Waypoint.h:23
const float Vs1
Definition: Module.h:244
const float PitchAggression
Definition: Module.h:242
float PressureAltitude
Definition: Bus.h:40
const float RollAggression
Definition: Module.h:243
float fvalue
Definition: Command.h:22
float PitchInput
Definition: Bus.h:127
float oldRollAttitude
Definition: Module.h:246
std::vector< Command > commandStream
Definition: Bus.h:20
Definition: Logger.h:5
float oldDesiredVsi
Definition: Module.h:241
float DesiredThrust
Definition: Bus.h:125
enum Bus::Afcs::LateralModes CurrentLateralMode
std::vector< Waypoint > waypoints
Definition: Bus.h:367
float IndicatedAirspeed
(3) Indicated Airspeed in km per second?
Definition: Bus.h:42
static float Clamp(float x, float min, float max)
Definition: Extensions.h:37
float DesiredAltitude
Definition: Bus.h:124
float PitchAttitude
(6) Pitch attitude;
Definition: Bus.h:49
float PitchControl
Definition: Bus.h:57
float DesiredHeading
Definition: Bus.h:120
float HeadingTrue
(4) Heading–primary flight crew reference (if selectable, record discrete, true or magnetic); ...
Definition: Bus.h:44
float PitchTrim
Definition: Bus.h:259
float DesiredPitch
Definition: Bus.h:123
bool AutothrottleEngaged
Definition: Bus.h:81
Definition: Bus.h:12
std::string name
command name
Definition: Command.h:11
float RollAttitude
(7) Roll attitude;
Definition: Bus.h:51
float DesiredRoll
Definition: Bus.h:122
float HeadingTrack
Definition: Bus.h:45
Afcs(Bus *prmBus, Logger *prmLogger)
Definition: AFCS.cpp:4
void FrameMove(float fElapsedTime) override
Definition: AFCS.cpp:10
Abstract base class for modules By definition, instruments don&#39;t do any of the work (they don&#39;t modif...
Definition: Module.h:11
float FlightPathAngle
Definition: Bus.h:275
LateralModes
Definition: Bus.h:100
Logger * logger
Definition: Module.h:239
float RollInput
Definition: Bus.h:128
Definition: Command.h:5
float RadioAltitude
Definition: Bus.h:134
struct Bus::Afcs AFCS
bool bvalue
Definition: Command.h:23
enum Bus::Afcs::VerticalModes StandbyVerticalMode
Bus * bus
Definition: Module.h:240
float VerticalSpeed
Definition: Bus.h:274
float DesiredVsi
Definition: Bus.h:119
int ivalue
Definition: Command.h:21
enum Bus::Afcs::VerticalModes CurrentVerticalMode
float DesiredCourse
Definition: Bus.h:121
bool AutopilotEngaged
Definition: Bus.h:80
float delay
wait number of seconds before executing command
Definition: Command.h:8
enum Bus::Afcs::LateralModes StandbyLateralMode
VerticalModes
so I guess we allow them to fly until they get to x degrees off
Definition: Bus.h:86
float oldPitchAttitude
Definition: Module.h:247
float LocalizerDeviation
Definition: Bus.h:135
D3DXVECTOR3 Location
Definition: Bus.h:359
float GlideslopeDeviation
Definition: Bus.h:136