RigsofRods
Soft-body Physics Simulation
AutoPilot.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5 
6  For more information, see http://www.rigsofrods.org/
7 
8  Rigs of Rods is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License version 3, as
10  published by the Free Software Foundation.
11 
12  Rigs of Rods is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "AutoPilot.h"
22 
23 #include "Application.h"
24 #include "GameContext.h"
25 #include "SimData.h"
26 #include "SoundScriptManager.h"
27 #include "Terrain.h"
28 #include "Water.h"
29 
30 using namespace Ogre;
31 using namespace RoR;
32 
33 Autopilot::Autopilot(int actor_id):
34  m_actor_id(actor_id)
35 {
36  ref_l = nullptr;
37  ref_r = nullptr;
38  ref_b = nullptr;
39  ref_c = nullptr;
40  ref_span = 1.0f;
41  reset();
42 }
43 
45 {
48  mode_ias = false;
49  mode_gpws = true;
50  heading = 0;
51  alt = 1000;
52  vs = 0;
53  ias = 150;
54  last_elevator = 0;
55  last_rudder = 0;
56  last_aileron = 0;
57  last_gpws_height = 0;
59  m_ils_angle_vdev = -90;
60  m_ils_angle_hdev = -90;
64  wantsdisconnect = false;
65 
68 }
69 
71 {
74  mode_ias = false;
75  wantsdisconnect = false;
76  if (mode_gpws)
77  {
79  }
80 }
81 
83 {
84  ref_l = refl;
85  ref_r = refr;
86  ref_b = refb;
87  ref_c = refc; // ar_camera_node_pos(0)
88  ref_span = (refl->RelPosition - refr->RelPosition).length();
89 }
90 
92 {
93  float val = 0;
94  if (ref_l && ref_r)
95  {
96  float rat = (ref_r->RelPosition.y - ref_l->RelPosition.y) / ref_span;
97  float bank = 90.0;
98  if (rat >= 1.0)
99  bank = 90.0;
100  else if (rat <= -1.0)
101  bank = -90.0;
102  else
103  bank = 57.3 * asin(rat);
104  if (mode_heading == HEADING_WLV)
105  {
106  val = bank / 100.0;
107  if (val > 0.5)
108  val = 0.5;
109  if (val < -0.5)
110  val = -0.5;
111  }
113  {
114  Vector3 vel = (ref_l->Velocity + ref_r->Velocity) / 2.0;
115  float curdir = atan2(vel.x, -vel.z) * 57.295779513082;
116  float want_bank = curdir - (float)heading;
117  if (want_bank < -180.0)
118  want_bank += 360.0;
119  want_bank = want_bank * 2.0;
120  if (want_bank > 45.0)
121  want_bank = 45.0;
122  if (want_bank < -45.0)
123  want_bank = -45.0;
124  val = (bank - want_bank) / 100.0;
125  if (val > 0.5)
126  val = 0.5;
127  if (val < -0.5)
128  val = -0.5;
129  }
130  if (mode_heading == HEADING_NAV)
131  {
132  //compute intercept heading
133  float error_heading = m_ils_angle_hdev / 10.0;
134  if (error_heading > 1.0)
135  error_heading = 1.0;
136  if (error_heading < -1.0)
137  error_heading = -1.0;
138  float offcourse_tolerance = m_ils_runway_distance / 30.0;
139  if (offcourse_tolerance > 60.0)
140  offcourse_tolerance = 60.0;
141  float intercept_heading = m_ils_runway_heading + error_heading * offcourse_tolerance;
142  Vector3 vel = (ref_l->Velocity + ref_r->Velocity) / 2.0;
143  float curdir = atan2(vel.x, -vel.z) * 57.295779513082;
144  float want_bank = curdir - intercept_heading;
145  if (want_bank < -180.0)
146  want_bank += 360.0;
147  want_bank = want_bank * 2.0;
148  if (want_bank > 45.0)
149  want_bank = 45.0;
150  if (want_bank < -45.0)
151  want_bank = -45.0;
152  val = (bank - want_bank) / 100.0;
153  if (val > 0.5)
154  val = 0.5;
155  if (val < -0.5)
156  val = -0.5;
157  }
158  }
159  last_aileron = (last_aileron + val) / 2.0;
160  return last_aileron;
161 }
162 
164 {
165  float val = 0;
166  if (ref_l && ref_r && ref_b)
167  {
168  float wanted_vs = (float)vs / 196.87;
169  float current_vs = (ref_l->Velocity.y + ref_r->Velocity.y) / 2.0;
170  float pitch_var = current_vs - ref_b->Velocity.y;
171  if (mode_alt == ALT_VS)
172  {
173  if (mode_heading == HEADING_NAV)
174  {
175  //this is cheating a bit
176  float ch = m_ils_runway_distance * sin((m_ils_angle_vdev + 4.0) / 57.295779513082);
177  float oh = m_ils_runway_distance * sin((4.0) / 57.295779513082);
178  wanted_vs = 5000.0 / 196.87;
179  float wanted_vs2 = (-ch + oh) / 5.0;
180  if (wanted_vs2 < -wanted_vs)
181  wanted_vs2 = -wanted_vs;
182  if (wanted_vs2 > wanted_vs)
183  wanted_vs2 = wanted_vs;
184  val = (wanted_vs2 - current_vs) / 40.0 + pitch_var / 40.0;
185  if (val > 0.75)
186  val = 0.75;
187  if (val < -0.75)
188  val = -0.75;
189  }
190  else
191  {
192  val = (wanted_vs - current_vs) / 40.0 + pitch_var / 40.0;
193  if (val > 0.5)
194  val = 0.5;
195  if (val < -0.5)
196  val = -0.5;
197  }
198  }
199  if (mode_alt == ALT_FIXED)
200  {
201  float wanted_alt = (float)alt * 0.3048;
202  float current_alt = (ref_l->AbsPosition.y + ref_r->AbsPosition.y) / 2.0;
203  if (wanted_vs < 0)
204  wanted_vs = -wanted_vs; //absolute value
205  float wanted_vs2 = (wanted_alt - current_alt) / 8.0;
206  if (wanted_vs2 < -wanted_vs)
207  wanted_vs2 = -wanted_vs;
208  if (wanted_vs2 > wanted_vs)
209  wanted_vs2 = wanted_vs;
210  val = (wanted_vs2 - current_vs) / 40.0 + pitch_var / 40.0;
211  if (val > 0.5)
212  val = 0.5;
213  if (val < -0.5)
214  val = -0.5;
215  }
216  }
217  return val;
218 }
219 
221 {
222  return 0;
223 }
224 
225 float Autopilot::getThrottle(float thrtl, float dt)
226 {
227  if (!mode_ias) { return thrtl; };
228 
229  float val = thrtl;
230  if (ref_l && ref_r)
231  {
232  //tropospheric model valid up to 11.000m (33.000ft)
233  float altitude = ref_l->AbsPosition.y;
234  //float sea_level_temperature=273.15+15.0; //in Kelvin
235  float sea_level_pressure = 101325; //in Pa
236  //float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin
237  float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947); //in Pa
238  float airdensity = airpressure * 0.0000120896;//1.225 at sea level
239 
240  float gspd = 1.94384449 * ((ref_l->Velocity + ref_r->Velocity) / 2.0).length();
241 
242  float spd = gspd * sqrt(airdensity / 1.225); //KIAS
243 
244  if (spd > (float)ias)
245  val = val - dt / 15.0;
246  if (spd < (float)ias)
247  val = val + dt / 15.0;
248  if (val > 1.0)
249  val = 1.0;
250  if (val < 0.02)
251  val = 0.02;
252  }
253  return val;
254 }
255 
257 {
258  if (mode == mode_heading)
260  else
261  mode_heading = mode;
262  return mode_heading;
263 }
264 
265 int Autopilot::toggleAlt(int mode)
266 {
267  if (mode == mode_alt)
268  mode_alt = ALT_NONE;
269  else
270  mode_alt = mode;
271  return mode_alt;
272 }
273 
275 {
276  mode_ias = !mode_ias;
277  return mode_ias;
278 }
279 
281 {
282  mode_gpws = !mode_gpws;
283  return mode_gpws;
284 }
285 
287 {
288  heading += d;
289  if (heading < 0)
290  heading += 360;
291  if (heading > 359)
292  heading -= 360;
293  return heading;
294 }
295 
297 {
298  alt += d;
299  return alt;
300 }
301 
303 {
304  vs += d;
305  if (vs > 9900)
306  vs = 9900;
307  if (vs < -9900)
308  vs = -9900;
309  return vs;
310 }
311 
313 {
314  ias += d;
315  if (ias < 0)
316  ias = 0;
317  if (ias > 350)
318  ias = 350;
319  return ias;
320 }
321 
322 void Autopilot::gpws_update(float spawnheight)
323 {
324 #ifdef USE_OPENAL
325  if (App::GetSoundScriptManager()->isDisabled())
326  return;
327  if (mode_gpws && ref_b)
328  {
330  if (App::GetGameContext()->GetTerrain()->getWater() && groundalt < App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight())
332  float height = (ref_c->AbsPosition.y - groundalt - spawnheight) * 3.28083f; //in feet!
333  //skip height warning sounds when the plane is slower then ~10 knots
334  if ((ref_c->Velocity.length() * 1.9685f) > 10.0f)
335  {
336  if (height < 10 && last_gpws_height > 10)
338  if (height < 20 && last_gpws_height > 20)
340  if (height < 30 && last_gpws_height > 30)
342  if (height < 40 && last_gpws_height > 40)
344  if (height < 50 && last_gpws_height > 50)
346  if (height < 100 && last_gpws_height > 100)
348  }
349  last_gpws_height = height;
350 
351  // pullup warning calculation
352  // height to meters
353  height *= 0.3048;
354  // get the y-velocity in meters/s
355  float yVel = ref_c->Velocity.y * 1.9685f;
356  // will trigger the pullup sound when vvi is high (avoid pullup warning when landing normal) and groundcontact will be in less then 10 seconds
357  if (yVel * 10.0f < -height && yVel < -10.0f)
359  }
360 #endif //OPENAL
361 }
362 
363 void Autopilot::UpdateIls(std::vector<TerrainObjectManager::localizer_t> localizers)
364 {
365  if (!ref_l || !ref_r)
366  return;
367  Vector3 position = (ref_l->AbsPosition + ref_r->AbsPosition) / 2.0;
368  float closest_hdist = -1;
369  float closest_hangle = -90;
370  float closest_vdist = -1;
371  float closest_vangle = -90;
373  for (std::vector<TerrainObjectManager::localizer_t>::size_type i = 0; i < localizers.size(); i++)
374  {
375  Plane hplane = Plane(Vector3::UNIT_Y, 0);
376  Vector3 plocd = hplane.projectVector(localizers[i].rotation * Vector3::UNIT_Z);
377  float loc = atan2(plocd.z, plocd.x);
378  Vector3 posd = hplane.projectVector(position - localizers[i].position);
379  float dir = atan2(posd.z, posd.x);
380  float diff = (dir - loc) * 57.295779513082;
381  if (diff > 180.0)
382  diff -= 360.0;
383  if (diff < -180.0)
384  diff += 360.0;
385  if (diff < 80 && diff > -80)
386  {
387  //we are in the visibility cone, we search the closest
388  float dist = (localizers[i].position - position).length();
389  //horizontal
390  if (localizers[i].type == LOCALIZER_HORIZONTAL)
391  {
392  if (closest_hdist < 0 || closest_hdist > dist)
393  {
394  closest_hdist = dist;
395  closest_hangle = diff;
396  m_ils_runway_heading = loc * 57.295779513082 - 90.0; //dont ask me why
397  if (m_ils_runway_heading < 0.0)
398  m_ils_runway_heading += 360.0;
399  m_ils_runway_distance = dist;
400  }
401  }
402  //vertical
403  if (localizers[i].type == LOCALIZER_VERTICAL)
404  {
405  if (closest_vdist < 0 || closest_vdist > dist)
406  {
407  Vector3 normv = (localizers[i].rotation * Vector3::UNIT_Z).crossProduct(Vector3::UNIT_Y);
408  Plane vplane = Plane(normv, 0);
409  float glideslope = 4; //4 degree is the norm
410  Vector3 posd2 = vplane.projectVector(position - localizers[i].position);
411  float d = posd2.length();
412  if (d < 0.01)
413  d = 0.01;
414  float dir2 = 90.0;
415  d = posd2.y / d;
416  if (d >= 1.0)
417  dir2 = 90.0;
418  else if (d <= -1.0)
419  dir2 = -90.0;
420  else
421  dir2 = asin(d) * 57.295779513082;
422  float diff2 = dir2 - glideslope;
423  closest_vdist = dist;
424  closest_vangle = diff2;
425  }
426  }
427  }
428  }
429  m_ils_angle_hdev = closest_hangle;
430  m_ils_angle_vdev = closest_vangle;
431 
432  m_horizontal_locator_available = (closest_hdist != -1);
433  m_vertical_locator_available = (closest_vdist != -1);
434 
435  if (mode_heading == HEADING_NAV && mode_gpws && closest_hdist > 10.0 && closest_hdist < 350.0 && last_closest_hdist > 10.0 && last_closest_hdist > 350.0)
436  {
438  }
439 
440  last_closest_hdist = closest_hdist;
441  if (mode_heading == HEADING_NAV)
442  {
443  // disconnect if close to runway or no locators are available
444  if (closest_hdist < 20.0 || closest_vdist < 20.0)
445  wantsdisconnect = true;
446  if (!this->IsIlsAvailable())
447  wantsdisconnect = true;
448  }
449 
450 }
RoR::SS_TRIG_GPWS_40
@ SS_TRIG_GPWS_40
Definition: SoundScriptManager.h:73
GameContext.h
Game state manager and message-queue provider.
RoR::Autopilot::setInertialReferences
void setInertialReferences(node_t *refl, node_t *refr, node_t *refb, node_t *refc)
Definition: AutoPilot.cpp:82
RoR::IWater::GetStaticWaterHeight
virtual float GetStaticWaterHeight()=0
Returns static water level configured in 'terrn2'.
RoR::SS_TRIG_GPWS_APDISCONNECT
@ SS_TRIG_GPWS_APDISCONNECT
Definition: SoundScriptManager.h:69
RoR::App::GetSoundScriptManager
SoundScriptManager * GetSoundScriptManager()
Definition: Application.cpp:277
RoR::Autopilot::getThrottle
float getThrottle(float thrtl, float dt)
Definition: AutoPilot.cpp:225
RoR::node_t::Velocity
Ogre::Vector3 Velocity
Definition: SimData.h:295
RoR::Autopilot::m_ils_runway_heading
float m_ils_runway_heading
Definition: AutoPilot.h:111
RoR::node_t::AbsPosition
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition: SimData.h:294
RoR::Autopilot::UpdateIls
void UpdateIls(std::vector< RoR::TerrainObjectManager::localizer_t > localizers)
Definition: AutoPilot.cpp:363
RoR::Autopilot::last_pullup_height
float last_pullup_height
Definition: AutoPilot.h:105
RoR::Autopilot::heading
int heading
Definition: AutoPilot.h:53
RoR::Autopilot::HEADING_FIXED
@ HEADING_FIXED
Definition: AutoPilot.h:41
RoR::Autopilot::last_rudder
float last_rudder
Definition: AutoPilot.h:103
RoR::SS_TRIG_GPWS_MINIMUMS
@ SS_TRIG_GPWS_MINIMUMS
Definition: SoundScriptManager.h:77
AutoPilot.h
RoR::Autopilot::ALT_FIXED
@ ALT_FIXED
Definition: AutoPilot.h:49
RoR::LOCALIZER_VERTICAL
@ LOCALIZER_VERTICAL
Definition: SimData.h:253
RoR::Autopilot::vs
int vs
Definition: AutoPilot.h:94
RoR::SS_TRIG_GPWS_PULLUP
@ SS_TRIG_GPWS_PULLUP
Definition: SoundScriptManager.h:76
RoR::node_t::RelPosition
Ogre::Vector3 RelPosition
relative to the local physics origin (one origin per actor) (shaky)
Definition: SimData.h:293
RoR::Autopilot::ref_span
float ref_span
Definition: AutoPilot.h:100
RoR::Autopilot::m_horizontal_locator_available
bool m_horizontal_locator_available
Definition: AutoPilot.h:108
RoR::Autopilot::gpws_update
void gpws_update(float spawnheight)
Definition: AutoPilot.cpp:322
RoR::Autopilot::toggleHeading
int toggleHeading(int mode)
Definition: AutoPilot.cpp:256
RoR::Terrain::GetHeightAt
float GetHeightAt(float x, float z)
Definition: Terrain.cpp:503
RoR::Autopilot::mode_ias
bool mode_ias
Definition: AutoPilot.h:91
RoR::Autopilot::m_ils_runway_distance
float m_ils_runway_distance
Definition: AutoPilot.h:112
RoR::Autopilot::m_actor_id
int m_actor_id
Definition: AutoPilot.h:115
RoR::SS_TRIG_GPWS_10
@ SS_TRIG_GPWS_10
Definition: SoundScriptManager.h:70
RoR::Autopilot::toggleAlt
int toggleAlt(int mode)
Definition: AutoPilot.cpp:265
RoR::Autopilot::ref_b
node_t * ref_b
Definition: AutoPilot.h:98
RoR::Autopilot::ALT_VS
@ ALT_VS
Definition: AutoPilot.h:50
RoR::Autopilot::last_closest_hdist
float last_closest_hdist
Definition: AutoPilot.h:113
SimData.h
Core data structures for simulation; Everything affected by by either physics, network or user intera...
RoR::Autopilot::adjVS
int adjVS(int d)
Definition: AutoPilot.cpp:302
RoR::Autopilot::getRudder
float getRudder()
Definition: AutoPilot.cpp:220
RoR::Autopilot::getElevator
float getElevator()
Definition: AutoPilot.cpp:163
RoR::Autopilot::ias
int ias
Definition: AutoPilot.h:95
RoR::Autopilot::adjHDG
int adjHDG(int d)
Definition: AutoPilot.cpp:286
RoR::Autopilot::m_vertical_locator_available
bool m_vertical_locator_available
Definition: AutoPilot.h:107
RoR::Autopilot::disconnect
void disconnect()
Definition: AutoPilot.cpp:70
RoR::Autopilot::wantsdisconnect
bool wantsdisconnect
Definition: AutoPilot.h:54
RoR::Autopilot::IsIlsAvailable
bool IsIlsAvailable()
Definition: AutoPilot.h:79
RoR::SS_TRIG_GPWS_50
@ SS_TRIG_GPWS_50
Definition: SoundScriptManager.h:74
RoR::Autopilot::HEADING_WLV
@ HEADING_WLV
Definition: AutoPilot.h:42
RoR::Autopilot::reset
void reset()
Definition: AutoPilot.cpp:44
Application.h
Central state/object manager and communications hub.
SoundScriptManager.h
RoR::node_t
Physics: A vertex in the softbody structure.
Definition: SimData.h:286
RoR::Autopilot::adjALT
int adjALT(int d)
Definition: AutoPilot.cpp:296
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::Autopilot::toggleIAS
bool toggleIAS()
Definition: AutoPilot.cpp:274
RoR::Autopilot::ref_c
node_t * ref_c
Definition: AutoPilot.h:99
RoR::Autopilot::alt
int alt
Definition: AutoPilot.h:93
RoR::SS_TRIG_GPWS_30
@ SS_TRIG_GPWS_30
Definition: SoundScriptManager.h:72
RoR::Autopilot::mode_gpws
bool mode_gpws
Definition: AutoPilot.h:92
RoR::SS_TRIG_GPWS_20
@ SS_TRIG_GPWS_20
Definition: SoundScriptManager.h:71
RoR::Autopilot::mode_heading
int mode_heading
Definition: AutoPilot.h:89
RoR::Autopilot::last_aileron
float last_aileron
Definition: AutoPilot.h:102
RoR::SS_TRIG_GPWS_100
@ SS_TRIG_GPWS_100
Definition: SoundScriptManager.h:75
RoR::Autopilot::adjIAS
int adjIAS(int d)
Definition: AutoPilot.cpp:312
RoR::Autopilot::toggleGPWS
bool toggleGPWS()
Definition: AutoPilot.cpp:280
RoR::Autopilot::HEADING_NONE
@ HEADING_NONE
Definition: AutoPilot.h:40
RoR::LOCALIZER_HORIZONTAL
@ LOCALIZER_HORIZONTAL
Definition: SimData.h:254
SOUND_PLAY_ONCE
#define SOUND_PLAY_ONCE(_ACTOR_, _TRIG_)
Definition: SoundScriptManager.h:34
RoR::Autopilot::ref_l
node_t * ref_l
Definition: AutoPilot.h:96
RoR::Autopilot::HEADING_NAV
@ HEADING_NAV
Definition: AutoPilot.h:43
Terrain.h
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR::Autopilot::ALT_NONE
@ ALT_NONE
Definition: AutoPilot.h:48
RoR::Autopilot::m_ils_angle_vdev
float m_ils_angle_vdev
Definition: AutoPilot.h:109
RoR::Autopilot::last_elevator
float last_elevator
Definition: AutoPilot.h:101
RoR::Autopilot::last_gpws_height
float last_gpws_height
Definition: AutoPilot.h:104
RoR::Autopilot::mode_alt
int mode_alt
Definition: AutoPilot.h:90
RoR::Autopilot::ref_r
node_t * ref_r
Definition: AutoPilot.h:97
RoR
Definition: AppContext.h:36
RoR::Autopilot::getAilerons
float getAilerons()
Definition: AutoPilot.cpp:91
Water.h
RoR::Autopilot::m_ils_angle_hdev
float m_ils_angle_hdev
Definition: AutoPilot.h:110
RoR::Terrain::getWater
IWater * getWater()
Definition: Terrain.h:84
RoR::GameContext::GetTerrain
const TerrainPtr & GetTerrain()
Definition: GameContext.h:117