Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
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 "GfxWater.h"
29
30using namespace Ogre;
31using namespace RoR;
32
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;
59 m_ils_angle_vdev = -90;
60 m_ils_angle_hdev = -90;
64 wantsdisconnect = false;
65
68}
69
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);
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 }
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 {
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
225float 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
266{
267 if (mode == mode_alt)
269 else
270 mode_alt = mode;
271 return mode_alt;
272}
273
275{
277 return mode_ias;
278}
279
281{
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
322void 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
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
375 for (size_t i = 0; i < localizers.size(); i++)
376 {
377 Plane hplane = Plane(Vector3::UNIT_Y, 0);
378 Vector3 plocd = hplane.projectVector(localizers[i].rotation * Vector3::UNIT_Z);
379 float loc = atan2(plocd.z, plocd.x);
380 Vector3 posd = hplane.projectVector(position - localizers[i].position);
381 float dir = atan2(posd.z, posd.x);
382 float diff = (dir - loc) * 57.295779513082;
383 if (diff > 180.0)
384 diff -= 360.0;
385 if (diff < -180.0)
386 diff += 360.0;
387 if (diff < 80 && diff > -80)
388 {
389 //we are in the visibility cone, we search the closest
390 float dist = (localizers[i].position - position).length();
391 //horizontal
392 if (localizers[i].type == LOCALIZER_HORIZONTAL)
393 {
394 if (closest_hdist < 0 || closest_hdist > dist)
395 {
396 closest_hdist = dist;
397 closest_hangle = diff;
398 m_ils_runway_heading = loc * 57.295779513082 - 90.0; //dont ask me why
399 if (m_ils_runway_heading < 0.0)
400 m_ils_runway_heading += 360.0;
402 }
403 }
404 //vertical
405 if (localizers[i].type == LOCALIZER_VERTICAL)
406 {
407 if (closest_vdist < 0 || closest_vdist > dist)
408 {
409 Vector3 normv = (localizers[i].rotation * Vector3::UNIT_Z).crossProduct(Vector3::UNIT_Y);
410 Plane vplane = Plane(normv, 0);
411 float glideslope = 4; //4 degree is the norm
412 Vector3 posd2 = vplane.projectVector(position - localizers[i].position);
413 float d = posd2.length();
414 if (d < 0.01)
415 d = 0.01;
416 float dir2 = 90.0;
417 d = posd2.y / d;
418 if (d >= 1.0)
419 dir2 = 90.0;
420 else if (d <= -1.0)
421 dir2 = -90.0;
422 else
423 dir2 = asin(d) * 57.295779513082;
424 float diff2 = dir2 - glideslope;
425 closest_vdist = dist;
426 closest_vangle = diff2;
427 }
428 }
429 }
430 }
431 m_ils_angle_hdev = closest_hangle;
432 m_ils_angle_vdev = closest_vangle;
433
434 m_horizontal_locator_available = (closest_hdist != -1);
435 m_vertical_locator_available = (closest_vdist != -1);
436
437 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)
438 {
440 }
441
442 last_closest_hdist = closest_hdist;
444 {
445 // disconnect if close to runway or no locators are available
446 if (closest_hdist < 20.0 || closest_vdist < 20.0)
447 wantsdisconnect = true;
448 if (!this->IsIlsAvailable())
449 wantsdisconnect = true;
450 }
451
452}
Central state/object manager and communications hub.
Game state manager and message-queue provider.
Core data structures for simulation; Everything affected by by either physics, network or user intera...
#define SOUND_PLAY_ONCE(_ACTOR_, _TRIG_)
int toggleHeading(int mode)
float getRudder()
float m_ils_runway_distance
Definition AutoPilot.h:114
void setInertialReferences(node_t *refl, node_t *refr, node_t *refb, node_t *refc)
Definition AutoPilot.cpp:82
Autopilot(int actor_id)
Definition AutoPilot.cpp:33
int adjALT(int d)
float m_ils_runway_heading
Definition AutoPilot.h:113
int adjIAS(int d)
float getAilerons()
Definition AutoPilot.cpp:91
float last_closest_hdist
Definition AutoPilot.h:115
void gpws_update(float spawnheight)
node_t * ref_r
Definition AutoPilot.h:99
float last_aileron
Definition AutoPilot.h:104
node_t * ref_c
Definition AutoPilot.h:101
float m_ils_angle_hdev
Definition AutoPilot.h:112
int adjVS(int d)
bool m_vertical_locator_available
Definition AutoPilot.h:109
node_t * ref_b
Definition AutoPilot.h:100
float last_gpws_height
Definition AutoPilot.h:106
bool m_horizontal_locator_available
Definition AutoPilot.h:110
float m_ils_angle_vdev
Definition AutoPilot.h:111
float last_elevator
Definition AutoPilot.h:103
float last_pullup_height
Definition AutoPilot.h:107
float getElevator()
bool wantsdisconnect
Definition AutoPilot.h:55
node_t * ref_l
Definition AutoPilot.h:98
int adjHDG(int d)
bool IsIlsAvailable()
Definition AutoPilot.h:80
void disconnect()
Definition AutoPilot.cpp:70
float last_rudder
Definition AutoPilot.h:105
float getThrottle(float thrtl, float dt)
int toggleAlt(int mode)
const TerrainPtr & GetTerrain()
TerrainObjectManager * getObjectManager()
Definition Terrain.h:80
float getHeightAt(float x, float z)
Definition Terrain.cpp:512
Wavefield * getWater()
Definition Terrain.h:87
float GetStaticWaterHeight()
Returns static water level configured in 'terrn2'.
Definition Wavefield.cpp:75
@ LOCALIZER_HORIZONTAL
Definition SimData.h:227
@ LOCALIZER_VERTICAL
Definition SimData.h:226
@ SS_TRIG_GPWS_PULLUP
@ SS_TRIG_GPWS_APDISCONNECT
@ SS_TRIG_GPWS_MINIMUMS
std::vector< Localizer > LocalizerVec
SoundScriptManager * GetSoundScriptManager()
GameContext * GetGameContext()
Physics: A vertex in the softbody structure.
Definition SimData.h:260
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition SimData.h:267
Ogre::Vector3 Velocity
Definition SimData.h:268
Ogre::Vector3 RelPosition
relative to the local physics origin (one origin per actor) (shaky)
Definition SimData.h:266