1# ####################################################################################
2# ####################################################################################
3# Nasal script to handle drag robot, in case there is no other dragger
4#
5# ####################################################################################
6# Author:  Klaus Kerner
7# Version: 2012-03-08
8#
9# ####################################################################################
10# Concepts:
11# 1. search for allready existing dragger in the property tree                  done
12# 2. if an dragger does not exist, create a new one                             done
13# 3. place dragger in front of glider                                           done
14# 4. run the dragger up into the sky                                       mostly done
15# 5. after releasing tow reset the dragger                                 mostly done
16# 6. allow redefining presets                                                   done
17
18
19
20# ####################################################################################
21# ## new properties in the property tree
22# ai/models/dragger
23# ai/models/dragger/id
24# ai/models/dragger/callsign
25# ai/models/dragger/valid
26# ai/models/dragger/position/latitude-deg
27# ai/models/dragger/position/longitude-deg
28# ai/models/dragger/position/altitude-ft
29# ai/models/dragger/orientation/true-heading-deg
30# ai/models/dragger/orientation/pitch-deg
31# ai/models/dragger/orientation/roll-deg
32# ai/models/dragger/velocities/true-airspeed-kt
33# ai/models/dragger/velocities/vertical-speed-fps
34# models/model[id_model]/path
35# models/model[id_model]/longitude-deg-prop
36# models/model[id_model]/latitude-deg-prop
37# models/model[id_model]/elevation-ft-prop
38# models/model[id_model]/heading-deg-prop
39# sim/glider/dragger/flags/exist                flag for existence of robot
40# sim/glider/dragger/flags/run                  flag for triggering operation
41# sim/glider/dragger/robot/id_AI
42# sim/glider/dragger/robot/id_model
43# sim/glider/dragger/robot/wp0lat_deg           wp0 reference point for different legs
44# sim/glider/dragger/robot/wp0lon_deg
45# sim/glider/dragger/robot/wp0alt_m
46# sim/glider/dragger/robot/wp0head_deg
47# sim/glider/dragger/robot/exit_height_m        exit height for stopping robot
48# sim/glider/dragger/robot/anchorlat_deg        anchor for checking leg position
49# sim/glider/dragger/robot/anchorlon_deg
50# sim/glider/dragger/robot/anchoralt_m
51# sim/glider/dragger/robot/leg_type             storing type of leg, 0 start,
52#                                                                    1 turn,
53#                                                                    2 straight
54#                                                                    3 end
55# sim/glider/dragger/robot/leg_distance_m       target distance in straight leg
56# sim/glider/dragger/robot/leg_angle_deg        target turn angle in turn leg
57# sim/glider/dragger/robot/turnside             1: right turn, 0: left turn
58# sim/glider/dragger/robot/leg_segment          storing segment of leg0,
59#                                                                    0 tauten,
60#                                                                    1 acceleration
61#                                               storing segment of leg1
62#                                                                    2 roll in
63#                                                                    3 keep roll angle
64#                                                                    4 roll out
65# sim/glider/dragger/conf/glob_min_speed_takeoff_mps
66#                .../glob/glob_min_speed_takeoff_mps
67# sim/glider/dragger/conf/glob_max_speed_mps
68#                .../glob/glob_max_speed_mps
69# sim/glider/dragger/conf/glob_max_speed_lift_mps
70#                .../glob/glob_max_speed_lift_mps
71# sim/glider/dragger/conf/glob_max_speed_tauten_mps
72#                .../glob/glob_max_speed_tauten_mps
73# sim/glider/dragger/conf/glob_min_acceleration_mpss
74#                .../glob/glob_min_acceleration_mpss
75# sim/glider/dragger/conf/glob_max_acceleration_mpss
76#                .../glob/glob_max_acceleration_mpss
77# sim/glider/dragger/conf/glob_max_roll_deg
78#                .../glob/glob_max_roll_deg
79# sim/glider/dragger/conf/glob_max_rollrate_degs
80#                .../glob/glob_max_rollrate_degs
81# sim/glider/dragger/conf/glob_max_turnrate_degs
82#                .../glob/glob_max_turnrate_degs
83# sim/glider/dragger/conf/glob_max_lift_height_m
84#                .../glob/glob_max_lift_height_m
85# sim/glider/dragger/conf/glob_max_tautendist_m
86#                .../glob/glob_max_tautendist_m
87
88# ## used properties from the property tree
89# environment/wind-from-north-fps
90# environment/wind-from-east-fps
91# environment/wind-from-down-fps
92# orientation/heading-deg
93# sim/glider/dragger/hooked
94
95
96
97# ####################################################################################
98# global variables:
99var dragrobot_timeincrement_s = 0.;                     # timer increment
100
101
102
103# ####################################################################################
104# set drag roboter parameters to global values, if not properly defined by plane
105# setup-file
106# store global values or plane-specific values to prepare for reset option
107var initRobotAttributes = func {
108  # constants for describing dragger attributes, if not defined by plane setup-file
109  var glob_min_speed_takeoff_mps  = 20;       # min. speed for take-off of drag-robot
110  var glob_max_speed_mps          = 36;       # max. speed of drag-robot
111  var glob_max_speed_lift_mps     = 3;        # max. lift speed of drag-robot
112  var glob_max_speed_tauten_mps   = 3;        # max. speed to tauten the rope
113  var glob_min_acceleration_mpss  = 0.5;      # min. acceleration
114  var glob_max_acceleration_mpss  = 3;        # max. acceleration
115  var glob_max_roll_deg           = 20;       # max. roll angle
116  var glob_max_rollrate_degs      = 5;        # max. roll rate per second
117  var glob_max_turnrate_degs      = 3;        # max. turn rate per second
118                                                # at max roll angle
119  var glob_max_lift_height_m      = 800;      # max. lifht height over start point
120  var glob_max_tautendist_m       = 50;       # max. distance for tauten the rope
121
122  if ( getprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps") == nil ) {
123    setprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps",
124             glob_min_speed_takeoff_mps);
125    setprop("sim/glider/dragger/glob/glob_min_speed_takeoff_mps",
126             glob_min_speed_takeoff_mps);
127  }
128  else {
129    setprop("sim/glider/dragger/glob/glob_min_speed_takeoff_mps",
130             getprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps"));
131  }
132
133  if ( getprop("sim/glider/dragger/conf/glob_max_speed_mps") == nil ) {
134    setprop("sim/glider/dragger/conf/glob_max_speed_mps",
135             glob_max_speed_mps);
136    setprop("sim/glider/dragger/glob/glob_max_speed_mps",
137             glob_max_speed_mps);
138  }
139  else {
140    setprop("sim/glider/dragger/glob/glob_max_speed_mps",
141             getprop("sim/glider/dragger/conf/glob_max_speed_mps"));
142  }
143
144  if ( getprop("sim/glider/dragger/conf/glob_max_speed_lift_mps") == nil ) {
145    setprop("sim/glider/dragger/conf/glob_max_speed_lift_mps",
146             glob_max_speed_lift_mps);
147    setprop("sim/glider/dragger/glob/glob_max_speed_lift_mps",
148             glob_max_speed_lift_mps);
149  }
150  else {
151    setprop("sim/glider/dragger/glob/glob_max_speed_lift_mps",
152             getprop("sim/glider/dragger/conf/glob_max_speed_lift_mps"));
153  }
154
155  if ( getprop("sim/glider/dragger/conf/glob_max_speed_tauten_mps") == nil ) {
156    setprop("sim/glider/dragger/conf/glob_max_speed_tauten_mps",
157             glob_max_speed_tauten_mps);
158    setprop("sim/glider/dragger/glob/glob_max_speed_tauten_mps",
159             glob_max_speed_tauten_mps);
160  }
161  else {
162    setprop("sim/glider/dragger/glob/glob_max_speed_tauten_mps",
163             getprop("sim/glider/dragger/conf/glob_max_speed_tauten_mps"));
164  }
165
166  if ( getprop("sim/glider/dragger/conf/glob_min_acceleration_mpss") == nil ) {
167    setprop("sim/glider/dragger/conf/glob_min_acceleration_mpss",
168             glob_min_acceleration_mpss);
169    setprop("sim/glider/dragger/glob/glob_min_acceleration_mpss",
170             glob_min_acceleration_mpss);
171  }
172  else {
173    setprop("sim/glider/dragger/glob/glob_min_acceleration_mpss",
174             getprop("sim/glider/dragger/conf/glob_min_acceleration_mpss"));
175  }
176
177  if ( getprop("sim/glider/dragger/conf/glob_max_acceleration_mpss") == nil ) {
178    setprop("sim/glider/dragger/conf/glob_max_acceleration_mpss",
179             glob_max_acceleration_mpss);
180    setprop("sim/glider/dragger/glob/glob_max_acceleration_mpss",
181             glob_max_acceleration_mpss);
182  }
183  else {
184    setprop("sim/glider/dragger/glob/glob_max_acceleration_mpss",
185             getprop("sim/glider/dragger/conf/glob_max_acceleration_mpss"));
186  }
187
188  if ( getprop("sim/glider/dragger/conf/glob_max_roll_deg") == nil ) {
189    setprop("sim/glider/dragger/conf/glob_max_roll_deg",
190             glob_max_roll_deg);
191    setprop("sim/glider/dragger/glob/glob_max_roll_deg",
192             glob_max_roll_deg);
193  }
194  else {
195    setprop("sim/glider/dragger/glob/glob_max_roll_deg",
196             getprop("sim/glider/dragger/conf/glob_max_roll_deg"));
197  }
198
199  if ( getprop("sim/glider/dragger/conf/glob_max_rollrate_degs") == nil ) {
200    setprop("sim/glider/dragger/conf/glob_max_rollrate_degs",
201             glob_max_rollrate_degs);
202    setprop("sim/glider/dragger/glob/glob_max_rollrate_degs",
203             glob_max_rollrate_degs);
204  }
205  else {
206    setprop("sim/glider/dragger/glob/glob_max_rollrate_degs",
207             getprop("sim/glider/dragger/conf/glob_max_rollrate_degs"));
208  }
209
210  if ( getprop("sim/glider/dragger/conf/glob_max_turnrate_degs") == nil ) {
211    setprop("sim/glider/dragger/conf/glob_max_turnrate_degs",
212             glob_max_turnrate_degs);
213    setprop("sim/glider/dragger/glob/glob_max_turnrate_degs",
214             glob_max_turnrate_degs);
215  }
216  else {
217    setprop("sim/glider/dragger/glob/glob_max_turnrate_degs",
218             getprop("sim/glider/dragger/conf/glob_max_turnrate_degs"));
219  }
220
221  if ( getprop("sim/glider/dragger/conf/glob_max_lift_height_m") == nil ) {
222    setprop("sim/glider/dragger/conf/glob_max_lift_height_m",
223             glob_max_lift_height_m);
224    setprop("sim/glider/dragger/glob/glob_max_lift_height_m",
225             glob_max_lift_height_m);
226  }
227  else {
228    setprop("sim/glider/dragger/glob/glob_max_lift_height_m",
229             getprop("sim/glider/dragger/conf/glob_max_lift_height_m"));
230  }
231
232  if ( getprop("sim/glider/dragger/conf/glob_max_tautendist_m") == nil ) {
233    setprop("sim/glider/dragger/conf/glob_max_tautendist_m",
234             glob_max_tautendist_m);
235    setprop("sim/glider/dragger/glob/glob_max_tautendist_m",
236             glob_max_tautendist_m);
237  }
238  else {
239    setprop("sim/glider/dragger/glob/glob_max_tautendist_m",
240             getprop("sim/glider/dragger/conf/glob_max_tautendist_m"));
241  }
242}
243
244
245
246# ####################################################################################
247# re-initialize presets
248var resetRobotAttributes = func {
249  # reading all global variables in case they has been changed in the property tree
250  setprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps",
251    getprop("sim/glider/dragger/glob/glob_min_speed_takeoff_mps"));
252  setprop("sim/glider/dragger/conf/glob_max_speed_mps",
253    getprop("sim/glider/dragger/glob/glob_max_speed_mps"));
254  setprop("sim/glider/dragger/conf/glob_max_speed_lift_mps",
255    getprop("sim/glider/dragger/glob/glob_max_speed_lift_mps"));
256  setprop("sim/glider/dragger/conf/glob_max_speed_tauten_mps",
257    getprop("sim/glider/dragger/glob/glob_max_speed_tauten_mps"));
258  setprop("sim/glider/dragger/conf/glob_min_acceleration_mpss",
259    getprop("sim/glider/dragger/glob/glob_min_acceleration_mpss"));
260  setprop("sim/glider/dragger/conf/glob_max_acceleration_mpss",
261    getprop("sim/glider/dragger/glob/glob_max_acceleration_mpss"));
262  setprop("sim/glider/dragger/conf/glob_max_roll_deg",
263    getprop("sim/glider/dragger/glob/glob_max_roll_deg"));
264  setprop("sim/glider/dragger/conf/glob_max_rollrate_degs",
265    getprop("sim/glider/dragger/glob/glob_max_rollrate_degs"));
266  setprop("sim/glider/dragger/conf/glob_max_turnrate_degs",
267    getprop("sim/glider/dragger/glob/glob_max_turnrate_degs"));
268  setprop("sim/glider/dragger/conf/glob_max_lift_height_m",
269    getprop("sim/glider/dragger/glob/glob_max_lift_height_m"));
270  setprop("sim/glider/dragger/conf/glob_max_tautendist_m",
271    getprop("sim/glider/dragger/glob/glob_max_tautendist_m"));
272}
273
274
275
276# ####################################################################################
277# check for allready available dragger
278var checkDragger = func {
279
280  #local variables
281  var dragid = -1;                              # the allready used id
282  var aiobjects = {};                           # vector to keep all ai objects
283
284  aiobjects = props.globals.getNode("ai/models", 1).getChildren();  # store AI objects
285  foreach ( var aimember; aiobjects ) {
286    # get data from aimember
287    if ( (var c = aimember.getNode("callsign")) != nil) {
288      var callsign = c.getValue();
289      if ( callsign == "dragger" ) {
290        dragid = aimember.getNode("id").getValue();
291      }
292    }
293  }
294  return(dragid);
295}
296
297
298
299# ####################################################################################
300# get the next free id of ai/models members
301var getFreeAIID = func {
302
303  #local variables
304  var aiid = 0;                                 # for the next unsused id
305  var aiobjects = {};                           # vector to keep all ai objects
306
307  aiobjects = props.globals.getNode("ai/models", 1).getChildren();  # store AI objects
308  foreach ( var aimember; aiobjects ) {
309    # get data from aimember
310    if ( (var c = aimember.getNode("id")) != nil) {
311      var id = c.getValue();
312      if ( aiid <= id ) {
313        aiid = id +1;
314      }
315    }
316  }
317
318# dirty bug-fix for double-used IDs, assign a most probably never reached ID (9999)
319# hopefully this will change in the future with correct ID assignment as the
320# AI-system does, needs access to flightgear core functions
321#  return(aiid);
322  return(9999);
323}
324
325
326
327# ####################################################################################
328# get the next free id of models/model members
329var getFreeModelID = func {
330
331  #local variables
332  var modelid = 0;                                 # for the next unsused id
333  var modelobjects = {};                           # vector to keep all model objects
334
335  modelobjects = props.globals.getNode("models", 1).getChildren(); # get model objects
336  foreach ( var member; modelobjects ) {
337    # get data from member
338    if ( (var c = member.getNode("id")) != nil) {
339      var id = c.getValue();
340      if ( modelid <= id ) {
341        modelid = id +1;
342      }
343    }
344  }
345  return(modelid);
346}
347
348
349
350# ####################################################################################
351# create the drag robot in the ai property tree
352var createDragRobot = func {
353  # place drag roboter with a distance, that the tow is nearly tautened
354  var rope_length_m = getprop("/sim/glider/towing/conf/rope_length_m");
355  var tauten_relative = getprop("/sim/glider/towing/conf/rope_x1");
356###  var install_distance_m = rope_length_m * (tauten_relative - 0.02);
357  var install_distance_m = rope_length_m - 2.;
358
359  # local variables
360  var ac_pos = geo.aircraft_position();                   # get position of aircraft
361  var ac_hd  = getprop("orientation/heading-deg");        # get heading of aircraft
362  var dip    = ac_pos.apply_course_distance( ac_hd , install_distance_m );
363                                                          # initial dragger position,
364                                                            # close to tauten-distance
365  var dipalt_m = geo.elevation(dip.lat(), dip.lon());     # height at dragger position
366  var glob_max_lift_height_m     =
367    getprop("sim/glider/dragger/conf/glob_max_lift_height_m");
368
369  # get the next free ai id and model id
370  var freeAIid = getFreeAIID();
371  var freeModelid = getFreeModelID();
372
373
374  var dragger_ai  = props.globals.getNode("ai/models/dragger", 1);
375  var dragger_mod = props.globals.getNode("models", 1);
376  var dragger_sim = props.globals.getNode("sim/glider/dragger/robot", 1);
377  var dragger_flg = props.globals.getNode("sim/glider/dragger/flags", 1);
378
379  dragger_sim.getNode("id_AI", 1).setIntValue(freeAIid);
380  dragger_sim.getNode("id_model", 1).setIntValue(freeModelid);
381  dragger_sim.getNode("leg_type", 1).setIntValue(0);
382  dragger_sim.getNode("leg_distance_m", 1).setValue(2000);
383  dragger_sim.getNode("leg_angle_deg", 1).setValue(ac_hd);
384  dragger_sim.getNode("leg_segment", 1).setIntValue(0);
385
386  dragger_flg.getNode("exist", 1).setIntValue(1);
387
388
389  dragger_ai.getNode("id", 1).setIntValue(freeAIid);
390  dragger_ai.getNode("callsign", 1).setValue("dragger");
391  dragger_ai.getNode("valid", 1).setBoolValue(1);
392  dragger_ai.getNode("position/latitude-deg", 1).setValue(dip.lat());
393  dragger_ai.getNode("position/longitude-deg", 1).setValue(dip.lon());
394  dragger_ai.getNode("position/altitude-ft", 1).setValue(dipalt_m * M2FT);
395  dragger_ai.getNode("orientation/true-heading-deg", 1).setValue(ac_hd);
396  dragger_ai.getNode("orientation/pitch-deg", 1).setValue(0);
397  dragger_ai.getNode("orientation/roll-deg", 1).setValue(0);
398  dragger_ai.getNode("velocities/true-airspeed-kt", 1).setValue(0);
399  dragger_ai.getNode("velocities/vertical-speed-fps", 1).setValue(0);
400
401  dragger_mod.model = dragger_mod.getChild("model", freeModelid, 1);
402  dragger_mod.model.getNode("path", 1).setValue("Aircraft/asw20/Models/Dragger/robot.xml");
403  dragger_mod.model.getNode("longitude-deg-prop", 1).setValue(
404        "ai/models/dragger/position/longitude-deg");
405  dragger_mod.model.getNode("latitude-deg-prop", 1).setValue(
406        "ai/models/dragger/position/latitude-deg");
407  dragger_mod.model.getNode("elevation-ft-prop", 1).setValue(
408        "ai/models/dragger/position/altitude-ft");
409  dragger_mod.model.getNode("heading-deg-prop", 1).setValue(
410        "ai/models/dragger/orientation/true-heading-deg");
411  dragger_mod.model.getNode("roll-deg-prop", 1).setValue(
412        "ai/models/dragger/orientation/roll-deg");
413  dragger_mod.model.getNode("load", 1).remove();
414
415
416  #storing initial position for reseting after reaching escape height
417  setprop("sim/glider/dragger/robot/wp0lat_deg", dip.lat() );
418  setprop("sim/glider/dragger/robot/wp0lon_deg", dip.lon() );
419  setprop("sim/glider/dragger/robot/wp0alt_m", dipalt_m );
420  setprop("sim/glider/dragger/robot/wp0head_deg", ac_hd );
421  setprop("sim/glider/dragger/robot/exit_height_m", dip.alt() + glob_max_lift_height_m );
422}
423
424
425
426# ####################################################################################
427# main function to initialize the drag roboter
428# used by key "D" or gui
429var setupDragRobot = func {
430
431  # look for allready existing ai object with callsign "dragger"
432  var existingdragid = checkDragger();
433  if ( existingdragid > -1 ) {               # dragger allready exists, we can exit
434    atc_msg(" existing dragger id: ", existingdragid);
435  }
436  else {                                     # dragger does not exist, we have to work
437    # create a new ai object with callsign "dragger"
438    # set initial position
439    createDragRobot();
440    dragger_msg(" I will lift you up into the sky.");
441  }
442}
443
444
445
446# ####################################################################################
447# dummy function to delete the drag roboter
448# used by gui and dragrobot.nas functions
449var removeDragRobot = func {
450
451  # look for allready existing ai object with callsign "dragger"
452  # will be filled in the next future
453
454  # in any case, first stop the dragger
455  setprop("sim/glider/dragger/flags/run", 0);
456
457  # next check for the dragger is still existent
458  # if yes,
459  #   remove the dragger from the property tree ai/models
460  #   remove the dragger from the property tree models/
461  #   remove the dragger working properties
462  # if no,
463  #   do nothing
464
465  # local variables
466  var modelsNode = {};
467
468  if ( getprop("/sim/glider/dragger/flags/exist") == 1 ) {   # does the dragger exist?
469    # remove 3d model from scenery
470    # identification is /models/model[x] with x=id_model
471    var id_model = getprop("sim/glider/dragger/robot/id_model");
472    modelsNode = "models/model[" ~ id_model ~ "]";
473    props.globals.getNode(modelsNode).remove();
474    props.globals.getNode("ai/models/dragger").remove();
475    props.globals.getNode("sim/glider/dragger/robot").remove();
476    atc_msg("dragger removed");
477    setprop("/sim/glider/dragger/flags/exist", 0);
478  }
479  else {                                                     # do nothing
480    atc_msg("dragger does not exist");
481  }
482
483}
484
485
486
487# ####################################################################################
488# run the drag robot for start leg
489var leg0DragRobot = func {
490
491  # ##################################################################################
492  # Strategy:
493  # set flag for start
494  # tauten the rope
495  # accelerate up to minimum lift speed
496  # switch to next leg
497
498
499
500
501  var initpos_geo = geo.Coord.new();
502  var dragpos_geo = geo.Coord.new();
503  var temppos_geo = geo.Coord.new();
504
505  var oldspeed_mps     = 0;
506  var oldlift_mps      = 0;
507  var oldheading_deg   = 0;
508  var newspeed_mps     = 0;
509  var newlift_mps      = 0;
510  var newliftdist_m    = 0;
511  var newelevation_m   = 0;
512  var distance_m       = 0;
513  var leg_distance_m   = 0;
514  var deltatime_s      = 0;
515  var leg_angle_deg    = 0;
516  var headwind_mps     = 0;
517
518
519  var segment = getprop("sim/glider/dragger/robot/leg_segment");
520  var glob_min_speed_takeoff_mps =
521    getprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps");
522  var glob_max_speed_tauten_mps  =
523    getprop("sim/glider/dragger/conf/glob_max_speed_tauten_mps");
524  var glob_min_acceleration_mpss =
525    getprop("sim/glider/dragger/conf/glob_min_acceleration_mpss");
526  var glob_max_acceleration_mpss =
527    getprop("sim/glider/dragger/conf/glob_max_acceleration_mpss");
528  var glob_max_tautendist_m     =
529    getprop("sim/glider/dragger/conf/glob_max_tautendist_m");
530
531
532  if ( dragrobot_timeincrement_s == 0 ) {
533    deltatime_s = getprop("sim/time/delta-sec");
534  }
535  else {
536    deltatime_s = dragrobot_timeincrement_s;
537  }
538
539
540  oldspeed_mps     = getprop("ai/models/dragger/velocities/true-airspeed-kt") * KT2MPS;
541  oldheading_deg   = getprop("ai/models/dragger/orientation/true-heading-deg");
542
543  initpos_geo.set_latlon( getprop("sim/glider/dragger/robot/wp0lat_deg"),
544                          getprop("sim/glider/dragger/robot/wp0lon_deg"),
545                          getprop("sim/glider/dragger/robot/wp0alt_m") );
546  dragpos_geo.set_latlon( getprop("ai/models/dragger/position/latitude-deg"),
547                          getprop("ai/models/dragger/position/longitude-deg"),
548                          getprop("ai/models/dragger/position/altitude-ft") * FT2M);
549
550  headwind_mps = aircraft.wind_speed_from(oldheading_deg) * KT2MPS;
551
552
553  # update properties like speed and position
554  if ( segment == 1 ) {                         # accelerate to min take-off speed
555    newspeed_mps = oldspeed_mps + glob_max_acceleration_mpss * deltatime_s;
556    distance_m = (oldspeed_mps - headwind_mps) * deltatime_s
557                   + 0.5 * glob_max_acceleration_mpss * deltatime_s * deltatime_s ;
558  }
559  else {                                        # segment 0, tauten rope
560    if ( ( oldspeed_mps - headwind_mps ) < glob_max_speed_tauten_mps ) {
561      if ( oldspeed_mps < headwind_mps ) {
562        oldspeed_mps = headwind_mps;
563      }
564      newspeed_mps = glob_min_acceleration_mpss * deltatime_s + oldspeed_mps;
565      distance_m = (oldspeed_mps - headwind_mps) * deltatime_s
566                   + 0.5 * glob_min_acceleration_mpss * deltatime_s * deltatime_s ;
567      if ( distance_m < 0.01 ) {  # keep robot locked until speed is high enough
568        distance_m = 0;
569      }
570    }
571    else {
572      newspeed_mps = oldspeed_mps;
573      distance_m = (oldspeed_mps - headwind_mps) * deltatime_s ;
574    }
575    if ( dragpos_geo.direct_distance_to(initpos_geo) > glob_max_tautendist_m ) {
576      setprop("sim/glider/dragger/robot/leg_segment", 1);
577    }
578  }
579
580  temppos_geo.set_latlon(dragpos_geo.lat(), dragpos_geo.lon());
581  newelevation_m = geo.elevation( temppos_geo.lat(), temppos_geo.lon() );
582
583  dragpos_geo.apply_course_distance( oldheading_deg , distance_m );
584  dragpos_geo.set_alt(newelevation_m);
585
586  setprop("ai/models/dragger/position/latitude-deg", dragpos_geo.lat());
587  setprop("ai/models/dragger/position/longitude-deg", dragpos_geo.lon());
588  setprop("ai/models/dragger/position/altitude-ft", dragpos_geo.alt() * M2FT);
589  setprop("ai/models/dragger/velocities/true-airspeed-kt", newspeed_mps * MPS2KT);
590
591
592  # check for exit criteria
593  if ( oldspeed_mps > glob_min_speed_takeoff_mps ) {
594    # set anchor point
595    setprop("sim/glider/dragger/robot/anchorlat_deg", dragpos_geo.lat());
596    setprop("sim/glider/dragger/robot/anchorlon_deg", dragpos_geo.lon());
597    setprop("sim/glider/dragger/robot/anchoralt_m", dragpos_geo.alt());
598    # set flags for next leg
599    setprop("sim/glider/dragger/robot/leg_type", 2);    # next one is straight forward
600    # set next exit criteria for straight leg, 200m ... 400m
601    leg_distance_m = 200 + rand() * 200;
602    setprop("sim/glider/dragger/robot/leg_distance_m", leg_distance_m );
603    dragger_msg("straight ahead");
604    dragger_msg( leg_distance_m, "m");
605  }
606}
607
608
609
610# ####################################################################################
611# run the drag robot for turns
612var leg1DragRobot = func {
613  # turns are described by the turn angle, so the delta angle from heading at initial
614  # position to heading from current position is the criteria for exit
615
616
617  var initpos_geo = geo.Coord.new();
618  var dragpos_geo = geo.Coord.new();
619
620  var oldspeed_mps     = 0;
621  var oldlift_mps      = 0;
622  var oldheading_deg   = 0;
623  var oldroll_deg      = 0;
624  var deltatime_s      = 0;
625  var distance_m       = 0;
626  var newspeed_mps     = 0;
627  var newlift_mps      = 0;
628  var newelevation_m   = 0;
629  var newroll_deg      = 0;
630  var newturn_deg      = 0;
631  var newheading_deg   = 0;
632  var wind_from_east_mps = 0;
633  var wind_from_nord_mps = 0;
634  var wind_from_down_mps = 0;
635
636
637  var segment = getprop("sim/glider/dragger/robot/leg_segment");
638  var side    = getprop("sim/glider/dragger/robot/turnside");
639  var targetheading_deg = getprop("sim/glider/dragger/robot/leg_angle_deg");
640  var glob_min_speed_takeoff_mps =
641    getprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps");
642  var glob_max_speed_mps         =
643    getprop("sim/glider/dragger/conf/glob_max_speed_mps");
644  var glob_max_speed_lift_mps    =
645    getprop("sim/glider/dragger/conf/glob_max_speed_lift_mps");
646  var glob_max_acceleration_mpss =
647    getprop("sim/glider/dragger/conf/glob_max_acceleration_mpss");
648  var glob_max_roll_deg          =
649    getprop("sim/glider/dragger/conf/glob_max_roll_deg");
650  var glob_max_rollrate_degs     =
651    getprop("sim/glider/dragger/conf/glob_max_rollrate_degs");
652  var glob_max_turnrate_degs     =
653    getprop("sim/glider/dragger/conf/glob_max_turnrate_degs");
654
655
656  if ( dragrobot_timeincrement_s == 0 ) {
657    deltatime_s = getprop("sim/time/delta-sec");
658  }
659  else {
660    deltatime_s = dragrobot_timeincrement_s;
661  }
662
663  oldspeed_mps     = getprop("ai/models/dragger/velocities/true-airspeed-kt") * KT2MPS;
664  oldlift_mps      = getprop("ai/models/dragger/velocities/vertical-speed-fps") * FT2M;
665  oldheading_deg   = getprop("ai/models/dragger/orientation/true-heading-deg");
666  oldroll_deg      = getprop("ai/models/dragger/orientation/roll-deg");
667  wind_from_east_mps = getprop("environment/wind-from-east-fps") * FT2M;
668  wind_from_nord_mps = getprop("environment/wind-from-north-fps") * FT2M;
669  wind_from_down_mps = getprop("environment/wind-from-down-fps") * FT2M;
670
671  dragpos_geo.set_latlon( getprop("ai/models/dragger/position/latitude-deg"),
672                          getprop("ai/models/dragger/position/longitude-deg"),
673                          getprop("ai/models/dragger/position/altitude-ft") * FT2M);
674
675  # calculate current roll angle for turns
676  if ( side == 1 ) {          # right turns
677    if ( segment == 2 ) {
678      if ( oldroll_deg < glob_max_roll_deg) {
679        # calculate new roll angle
680        newroll_deg = oldroll_deg + deltatime_s * glob_max_rollrate_degs;
681      }
682      else {
683        newroll_deg = oldroll_deg;
684        setprop("sim/glider/dragger/robot/leg_segment", 3);
685      }
686    }
687
688    if (segment == 3 ) {
689      newroll_deg = oldroll_deg;
690      # check for target turn
691      if ( (oldheading_deg > targetheading_deg)
692             and
693               (oldheading_deg <= (targetheading_deg+5)) ) {
694        # turn finished
695        setprop("sim/glider/dragger/robot/leg_segment", 4);
696      }
697      # if yes, change segment type
698    }
699
700    if ( segment == 4 ) {
701      if ( oldroll_deg > 0) {
702        # calculate new roll angle
703        newroll_deg = oldroll_deg - deltatime_s * glob_max_rollrate_degs;
704      }
705      else {                                                      # also exit criteria
706        newroll_deg = 0;
707        # set anchor point
708        setprop("sim/glider/dragger/robot/anchorlat_deg", dragpos_geo.lat());
709        setprop("sim/glider/dragger/robot/anchorlon_deg", dragpos_geo.lon());
710        setprop("sim/glider/dragger/robot/anchoralt_m", dragpos_geo.alt());
711        # set next leg
712        setprop("sim/glider/dragger/robot/leg_segment", 2);
713        setprop("sim/glider/dragger/robot/leg_type", 2);
714        var length_m = 100;                                    # first turn after 100m
715        setprop("sim/glider/dragger/robot/leg_distance_m", length_m);
716        dragger_msg("straight leg");
717        dragger_msg( length_m, "m");
718      }
719    }
720  }
721  else {                 # left turns
722    if ( segment == 2 ) {
723      if ( oldroll_deg > -glob_max_roll_deg) {
724        # calculate new roll angle
725        newroll_deg = oldroll_deg - deltatime_s * glob_max_rollrate_degs;
726      }
727      else {
728        newroll_deg = oldroll_deg;
729        setprop("sim/glider/dragger/robot/leg_segment", 3);
730      }
731    }
732
733    if (segment == 3 ) {
734      newroll_deg = oldroll_deg;
735      # check for target turn
736      if ( (oldheading_deg < targetheading_deg)
737             and
738               (oldheading_deg >= (targetheading_deg-5)) ) {
739        # turn finished
740        setprop("sim/glider/dragger/robot/leg_segment", 4);
741      }
742      # if yes, change segment type
743    }
744
745    if ( segment == 4 ) {
746      if ( oldroll_deg < 0) {
747        # calculate new roll angle
748        newroll_deg = oldroll_deg + deltatime_s * glob_max_rollrate_degs;
749      }
750      else {                                                      # also exit criteria
751        newroll_deg = 0;
752        # set anchor point
753        setprop("sim/glider/dragger/robot/anchorlat_deg", dragpos_geo.lat());
754        setprop("sim/glider/dragger/robot/anchorlon_deg", dragpos_geo.lon());
755        setprop("sim/glider/dragger/robot/anchoralt_m", dragpos_geo.alt());
756        # set next leg
757        setprop("sim/glider/dragger/robot/leg_segment", 2);
758        setprop("sim/glider/dragger/robot/leg_type", 2);
759        var length_m = 100;                                    # first turn after 100m
760        setprop("sim/glider/dragger/robot/leg_distance_m", length_m);
761        dragger_msg("straight leg");
762        dragger_msg( length_m, "m");
763      }
764    }
765  }
766  # calculate current speed
767  if ( oldspeed_mps >= glob_max_speed_mps) {
768    newspeed_mps = oldspeed_mps;
769    distance_m = oldspeed_mps * deltatime_s;
770  }
771  else {
772    newspeed_mps = oldspeed_mps + glob_max_acceleration_mpss * deltatime_s;
773    distance_m = oldspeed_mps * deltatime_s
774                 + 0.5 * glob_max_acceleration_mpss * deltatime_s * deltatime_s;
775  }
776
777  # calculate current lift
778  newlift_mps = glob_max_speed_lift_mps * (oldspeed_mps - glob_min_speed_takeoff_mps) /
779                   (glob_max_speed_mps - glob_min_speed_takeoff_mps);
780  newliftdist_m = (newlift_mps + wind_from_down_mps) * deltatime_s;
781
782
783  # calculate current turn rate based on roll angle
784  newturn_deg = glob_max_turnrate_degs * newroll_deg / glob_max_roll_deg * deltatime_s;
785
786  # calculate new heading based on turn rate
787  if ( (oldheading_deg + newturn_deg) > 360 ) { # if a rightturn exceeds 360 heading
788    newheading_deg = oldheading_deg + newturn_deg - 360;
789  }
790  else {
791    if ( (oldheading_deg + newturn_deg) < 0 ) { # if a leftturn exceeds 0 heading
792      newheading_deg = oldheading_deg + newturn_deg +360;
793    }
794    else { # for all other headings
795      newheading_deg = oldheading_deg + newturn_deg;
796    }
797  }
798
799  # calculate new position based on new heading and distance increment
800  dragpos_geo.apply_course_distance( newheading_deg , distance_m );
801  dragpos_geo.apply_course_distance( 270.0 , wind_from_east_mps * deltatime_s );
802  dragpos_geo.apply_course_distance( 180.0 , wind_from_nord_mps * deltatime_s );
803  newelevation_m = dragpos_geo.alt() + newliftdist_m;
804  dragpos_geo.set_alt(newelevation_m);
805
806
807  setprop("ai/models/dragger/position/latitude-deg",         dragpos_geo.lat());
808  setprop("ai/models/dragger/position/longitude-deg",        dragpos_geo.lon());
809  setprop("ai/models/dragger/position/altitude-ft",          dragpos_geo.alt() * M2FT);
810  setprop("ai/models/dragger/orientation/true-heading-deg",  newheading_deg);
811  setprop("ai/models/dragger/orientation/roll-deg",          newroll_deg);
812  setprop("ai/models/dragger/velocities/true-airspeed-kt",   newspeed_mps * MPS2KT);
813  setprop("ai/models/dragger/velocities/vertical-speed-fps", newlift_mps * M2FT);
814}
815
816
817
818# ####################################################################################
819# run the drag robot for straight legs
820var leg2DragRobot = func {
821  # straight legs are described by the length, so the delta distance from initial
822  # position to current position is the criteria for exit
823
824
825
826  var initpos_geo = geo.Coord.new();
827  var dragpos_geo = geo.Coord.new();
828
829  var oldspeed_mps     = 0;
830  var oldheading_deg   = 0;
831  var newspeed_mps     = 0;
832  var newlift_mps      = 0;
833  var newliftdist_m    = 0;
834  var newelevation_m   = 0;
835  var distance_m       = 0;
836  var leg_distance_m   = 0;
837  var deltatime_s      = 0;
838  var leg_angle_deg    = 0;
839  var wind_from_east_mps = 0;
840  var wind_from_nord_mps = 0;
841  var wind_from_down_mps = 0;
842
843  var glob_min_speed_takeoff_mps =
844    getprop("sim/glider/dragger/conf/glob_min_speed_takeoff_mps");
845  var glob_max_speed_mps         =
846    getprop("sim/glider/dragger/conf/glob_max_speed_mps");
847  var glob_max_speed_lift_mps    =
848    getprop("sim/glider/dragger/conf/glob_max_speed_lift_mps");
849  var glob_max_acceleration_mpss =
850    getprop("sim/glider/dragger/conf/glob_max_acceleration_mpss");
851
852
853  if ( dragrobot_timeincrement_s == 0 ) {
854    deltatime_s = getprop("sim/time/delta-sec");
855  }
856  else {
857    deltatime_s = dragrobot_timeincrement_s;
858  }
859
860  oldspeed_mps     = getprop("ai/models/dragger/velocities/true-airspeed-kt") * KT2MPS;
861  oldheading_deg   = getprop("ai/models/dragger/orientation/true-heading-deg");
862  leg_distance_m   = getprop("sim/glider/dragger/robot/leg_distance_m");
863  wind_from_east_mps = getprop("environment/wind-from-east-fps") * FT2M;
864  wind_from_nord_mps = getprop("environment/wind-from-north-fps") * FT2M;
865  wind_from_down_mps = getprop("environment/wind-from-down-fps") * FT2M;
866
867  initpos_geo.set_latlon( getprop("sim/glider/dragger/robot/anchorlat_deg"),
868                          getprop("sim/glider/dragger/robot/anchorlon_deg"),
869                          getprop("sim/glider/dragger/robot/anchoralt_m") );
870  dragpos_geo.set_latlon( getprop("ai/models/dragger/position/latitude-deg"),
871                          getprop("ai/models/dragger/position/longitude-deg"),
872                          getprop("ai/models/dragger/position/altitude-ft") * FT2M);
873
874  if ( oldspeed_mps >= glob_max_speed_mps) {
875    newspeed_mps = oldspeed_mps;
876    distance_m = oldspeed_mps * deltatime_s;
877  }
878  else {
879    newspeed_mps = oldspeed_mps + glob_max_acceleration_mpss * deltatime_s;
880    distance_m = oldspeed_mps * deltatime_s
881                 + 0.5 * glob_max_acceleration_mpss * deltatime_s * deltatime_s;
882  }
883
884  newlift_mps = glob_max_speed_lift_mps * (oldspeed_mps - glob_min_speed_takeoff_mps) /
885                   (glob_max_speed_mps - glob_min_speed_takeoff_mps);
886  newliftdist_m = (newlift_mps + wind_from_down_mps) * deltatime_s;
887
888  dragpos_geo.apply_course_distance( oldheading_deg , distance_m );
889  dragpos_geo.apply_course_distance( 270.0 , wind_from_east_mps * deltatime_s );
890  dragpos_geo.apply_course_distance( 180.0 , wind_from_nord_mps * deltatime_s );
891  newelevation_m = dragpos_geo.alt() + newliftdist_m;
892  dragpos_geo.set_alt(newelevation_m);
893
894  setprop("ai/models/dragger/position/latitude-deg", dragpos_geo.lat());
895  setprop("ai/models/dragger/position/longitude-deg", dragpos_geo.lon());
896  setprop("ai/models/dragger/position/altitude-ft", dragpos_geo.alt() * M2FT);
897  setprop("ai/models/dragger/velocities/true-airspeed-kt", newspeed_mps * MPS2KT);
898  setprop("ai/models/dragger/velocities/vertical-speed-fps", newlift_mps * M2FT);
899
900
901  # exit criteria to next turn
902  if ( dragpos_geo.direct_distance_to(initpos_geo) > leg_distance_m ) {
903    var turn_deg = 30 + rand() * 240;                    # turn range from 30� to 270�
904    if ( (oldheading_deg + turn_deg) >= 360) {
905      leg_angle_deg = oldheading_deg + turn_deg - 360;
906    }
907    else {
908      leg_angle_deg = oldheading_deg + turn_deg;
909    }
910    setprop("sim/glider/dragger/robot/leg_angle_deg", leg_angle_deg);
911    var side = rand();
912    if (side > 0.5) {
913      setprop("sim/glider/dragger/robot/turnside", 1);
914      dragger_msg("turn right");
915      dragger_msg( turn_deg , "deg");
916    }
917    else {
918      setprop("sim/glider/dragger/robot/turnside", 0);
919      dragger_msg("turn left");
920      dragger_msg( turn_deg , "deg");
921    }
922    setprop("sim/glider/dragger/robot/leg_type", 1);
923    setprop("sim/glider/dragger/robot/leg_segment", 2);
924  }
925
926  # exit criteria to final drop-down: max height reached
927  if ( dragpos_geo.alt() > getprop("sim/glider/dragger/robot/exit_height_m") ) {
928    dragger_msg(" we have reached max height, bye bye");
929    setprop("sim/glider/dragger/robot/leg_type", 3);
930    setprop("sim/glider/dragger/robot/leg_segment", 2);
931  }
932}
933
934
935
936# ####################################################################################
937# run the drag robot for final leg
938var leg3DragRobot = func {
939
940  dragger_msg(" turn right, I turn left" );
941  # unhook from dragger
942  releaseDragger();                                         # function from towing.nas
943
944
945  # stop loop for updating roboter
946  if ( getprop("sim/glider/dragger/flags/run") == 1 ) {
947    setprop("sim/glider/dragger/flags/run", 0);
948  }
949
950
951  # reseting all variables and position to initial values
952   setprop("ai/models/dragger/position/latitude-deg",
953                  getprop("sim/glider/dragger/robot/wp0lat_deg") );
954  setprop("ai/models/dragger/position/longitude-deg",
955                  getprop("sim/glider/dragger/robot/wp0lon_deg") );
956  setprop("ai/models/dragger/position/altitude-ft",
957                  getprop("sim/glider/dragger/robot/wp0alt_m")  * M2FT);
958  setprop("ai/models/dragger/orientation/true-heading-deg",
959                  getprop("sim/glider/dragger/robot/wp0head_deg") );
960  setprop("ai/models/dragger/orientation/roll-deg",          0);
961  setprop("ai/models/dragger/velocities/true-airspeed-kt",   0);
962  setprop("ai/models/dragger/velocities/vertical-speed-fps", 0);
963  setprop("sim/glider/dragger/robot/leg_type", 0);
964  setprop("sim/glider/dragger/robot/leg_segment", 0);
965
966}
967
968
969
970# ####################################################################################
971# function to switch the drag roboter on or off running
972# used by key "d" and gui
973var startDragRobot = func {
974  if ( getprop("sim/glider/dragger/flags/run" ) == 1) {
975    setprop("sim/glider/dragger/flags/run", 0);
976    print(" stop the drag robot");
977  }
978  else {
979    print(" start the drag robot");
980    setprop("sim/glider/dragger/flags/run", 1);
981  }
982}
983
984
985
986# ####################################################################################
987# triggered function to run the drag roboter
988var runDragRobot = func {
989  if ( getprop("sim/glider/dragger/flags/run" ) == 1) {
990    var leg = -1;
991
992    leg = getprop("sim/glider/dragger/robot/leg_type");
993
994    if ( leg == 0 ) {
995      leg0DragRobot();
996    }
997
998    if ( leg == 1 ) {
999      leg1DragRobot();
1000    }
1001
1002    if ( leg == 2 ) {
1003      leg2DragRobot();
1004    }
1005
1006    if ( leg == 3 ) {
1007      leg3DragRobot();
1008    }
1009
1010    settimer(runDragRobot, dragrobot_timeincrement_s);
1011  }
1012}
1013
1014
1015
1016# ####################################################################################
1017var pulling = setlistener("sim/glider/dragger/flags/run", runDragRobot);
1018var initializing_dragrobot = setlistener("sim/signals/fdm-initialized", initRobotAttributes);
1019