Add hydraulic system, tidy pneumatic system
[fg:toms-fgdata.git] / Aircraft / Hurricane / Systems / hydraulic.nas
1 ###############################################################################
2 ##
3 ##  Hydraulic system module for FlightGear.
4 ##
5 ##  Copyright (C) 2012  Vivian Meazza  (vivia.meazza(at)lineone.net)
6 ##  This file is licensed under the GPL license v2 or later.
7 ##
8 ###############################################################################
9 # Properties under /systems/hydraulic:
10 # + servicable      - Current status  Must be set by user code.
11
12 # + pressure        - OUTPUT ONLY property, do not try to set
13
14 # ==================================== Definiions ===========================================
15 # set the maximum and minimum pressure
16 MAX_PRESSURE = 1250.0;
17 MIN_PRESSURE = 1000.0;
18
19 # set the update period
20 UPDATE_PERIOD = 0.3;
21
22 # set the timer for the selected function
23
24 registerTimer = func {
25
26     settimer(arg[0], UPDATE_PERIOD);
27
28 } # end function 
29
30 #does what it says on the tin
31 var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
32
33 # ================================ Initalize ====================================== 
34 # Make sure all needed properties are present and accounted 
35 # for, and that they have sane default values.
36
37 # =============== Variables ================
38 var pressure = 0;
39 var max_pressure = 0;
40 var pump = nil;
41
42 var valve = nil;
43 var valve_1 = nil;
44 var valve_2 = nil;
45
46 var actuator = nil;
47 var actuator_1 = nil;
48 var actuator_2 = nil;
49 var actuator_3 = nil;
50 var actuator_4 = nil;
51
52 var relief_valve = nil;
53
54 var initialize = func {
55
56 print( "Initializing Hydraulic System ..." );
57
58 props.globals.initNode("/systems/hydraulic/serviceable", 1, "BOOL");
59 props.globals.initNode("/systems/hydraulic/pressure-psi", 0, "DOUBLE");
60 props.globals.initNode("/controls/hydraulic/lever", -1, "DOUBLE");
61 props.globals.initNode("/controls/hydraulic/lever[1]", 1, "DOUBLE");
62 props.globals.initNode("/controls/hydraulic/lever[2]", 0, "DOUBLE");
63 #props.globals.initNode("/systems/hydraulic/outputs/gear", 1, "DOUBLE");
64 props.globals.initNode("/systems/hydraulic/outputs/gear[1]", 1, "DOUBLE");
65 props.globals.initNode("/systems/hydraulic/outputs/gear[2]", 1, "DOUBLE");
66 props.globals.initNode("/systems/hydraulic/outputs/flaps", 0, "DOUBLE");
67
68 ###
69 # overwrite these functions in controls.nas
70 #
71 controls.gearDown = func(x) { if (x) { hydraulicLever(-1, -x) } }
72 controls.flapsDown = func(x) { if (x) { hydraulicLever(1, -x) } }
73
74 ###
75 # suppliers ("name", "rpm source", "control property", status, factor, max pressure)
76 #
77         pump = Pump.new("pump-engine",
78                                         "engines/engine[0]/rpm",
79                                         "controls/hydraulic/system/engine-pump",
80                                         1,
81                                         0.9,
82                                         MAX_PRESSURE);
83
84 ###
85 # valves ("name", "input property", "control property", "control1 property",status, initial state, initial state)
86 #
87         valve = Valve.new("four-way",
88                                         "systems/hydraulic/pressure-psi",
89                                         "controls/hydraulic/lever",
90                                         "controls/hydraulic/lever[1]",
91                                         1,
92                                         0,
93                                         0);
94
95 ###
96 # actuators ("name", "input property", "output property", "position property",
97 # status, min, max, initial state)
98 #
99         actuator_1 = Actuator.new("gear-1",
100                                         "systems/hydraulic/valves/four-way/output-pressure-psi",
101                                         "systems/hydraulic/outputs/gear[1]",
102                                         "gear/gear[1]/position-norm",
103                                         1,
104                                         -MAX_PRESSURE,
105                                         MAX_PRESSURE,
106                                         1);
107
108         actuator_2 = Actuator.new("gear-2",
109                                         "systems/hydraulic/valves/four-way/output-pressure-psi",
110                                         "systems/hydraulic/outputs/gear[2]",
111                                         "gear/gear[2]/position-norm",
112                                         1,
113                                         -MAX_PRESSURE,
114                                         MAX_PRESSURE,
115                                         1);
116
117         actuator_3 = Actuator.new("flaps",
118                                         "systems/hydraulic/valves/four-way/output-pressure-psi[1]",
119                                         "systems/hydraulic/outputs/flaps",
120                                         "surface-positions/flap-pos-norm",
121                                         1,
122                                         -1200,
123                                         1200,
124                                         0);
125
126 ###
127 # relief valves ("name", "input property", "control property", "output property", status,
128 # max, initial state)
129 #
130         relief_valve = Relief.new("blow-off",
131                                         "systems/hydraulic/suppliers/pump-engine/output-pressure-psi",
132                                         "systems/hydraulic/valves/flaps/output-pressure-psi",
133                                         "systems/hydraulic/pressure-psi",
134                                         1,
135                                         1200,
136                                         0);
137
138 # =============================== listeners ===============================
139 #
140
141         setlistener("/gear/gear[1]/wow", func (n){
142                 var wow = n.getValue();
143                 var up_lock = 0;
144                 var down_lock = getprop("/gear/gear[1]/position-norm");
145
146                 if(wow and down_lock < 1.0)
147                         {
148                         print("collapse");
149                         }
150
151 #               setprop("systems/hydraulic/outputs/gear", gear);
152 #               setprop("systems/hydraulic/outputs/gear[1]", gear);
153 #               setprop("systems/hydraulic/outputs/gear[2]", gear);
154 #               print ("lever ", lever," gear ", gear);
155
156         },
157         0,
158         0); # end listener
159
160 # =============================== start it up ===============================
161 #
162 print( "... done" );
163 update_hydraulic();
164
165 } #end func init
166
167 ###
168 # =================== hydraulic system =========================
169 #
170 ###
171 # This is the main loop which keeps eveything updated
172 #
173 update_hydraulic = func {
174 #       time = props.globals.getNode("/sim/time/elapsed-sec", 1).getValue();
175 #       dt = time - last_time;
176 #       last_time = time;
177         
178         foreach (var p; Pump.list)
179                 {
180                 p.update();
181                 }
182
183         foreach ( var r; Relief.list)
184                 {
185                 r.update();
186                 }
187
188         foreach (var v; Valve.list)
189                 {
190                 v.update();
191                 }
192
193         foreach ( var a; Actuator.list)
194                 {
195                 a.update();
196                 }
197
198 # Request that the update fuction be called again 
199         registerTimer(update_hydraulic);
200 }
201
202 ##
203 # Pump class. Defines an hydraulic pump
204
205 Pump = {
206          new : func(name, source, control, serviceable, factor, max_pressure) {
207                 var obj = { parents : [ Pump ] };
208                 obj.name = name;
209                 #print ("name ", name);
210                 #print ("output ", output);
211                 obj.rpm_source_N = props.globals.getNode( source, 1 );
212                 obj.rpm_source_N.setDoubleValue(0);
213                 obj.control_N = props.globals.getNode( control, 1 );
214                 obj.control_N.setBoolValue( 1 );
215 #               obj.output_pressure_N = props.globals.getNode( output, 1 );
216 #               obj.output_pressure_N.setDoubleValue( 0 );
217                 obj.factor = factor;
218                 obj.max_pressure = max_pressure;
219                 obj.props_N = props.globals.getNode( "systems/hydraulic/suppliers", 1 ).getChild(name, 0, 1);
220                 obj.props_serviceable_N = obj.props_N.getChild("serviceable", 0, 1);
221                 obj.props_serviceable_N.setBoolValue( serviceable );
222                 obj.props_out_pressure_N = obj.props_N.getChild("output-pressure-psi", 0, 1);
223                 obj.props_out_pressure_N.setDoubleValue( 0 );
224                 append(Pump.list, obj); 
225                 return obj;
226         },
227         update : func {
228                 var rpm = me.rpm_source_N.getValue();
229                 var serviceable = me.props_serviceable_N.getValue();
230                 var control = me.control_N.getValue();
231                 var factor = me.factor;
232                 var max_pressure = me.max_pressure;
233
234                 if (serviceable)
235                         {
236                         pressure = clamp(factor * rpm * control, 0, max_pressure);
237                         }
238                 else
239                         {
240                         pressure = 0;
241                         }
242
243         me.props_out_pressure_N.setDoubleValue(pressure);
244         # print ("pressure ", pressure);
245                 
246         },
247         setMaxPressure : func (pressure) {
248                 me.max_pressure = pressure;
249         },
250         setServiceable : func (serviceable) {
251                 me.props_serviceable_N.setBoolValue( serviceable ); 
252         },
253         list : [],
254 };
255
256 # Valve class. Defines a valve in the hydraulic system. Input is an hydraulic pressure source, output is used 
257 # to drive an actuator. The 4 way valve is unique to the Hurricane
258
259 Valve = {
260          new : func(name, source, control, control1, serviceable, state, state1) {
261                 var obj = { parents : [ Valve ] };
262                 obj.name = name;
263 #               print ("name ", name);
264 #        print ("source ", source);
265 #               print ("output ", output);
266 #               print ("control ", control);
267 #               print ("contro1l ", control1);
268                 obj.source_N = props.globals.getNode( source, 1 );
269                 obj.source_N.setDoubleValue(0);
270                 obj.control_N = props.globals.getNode( control, 1 );
271                 obj.control_N.setDoubleValue(state);
272                 obj.control1_N = props.globals.getNode( control1, 1 );
273                 obj.control1_N.setDoubleValue(state1);
274                 obj.props_N = props.globals.getNode( "systems/hydraulic/valves", 1 ).getChild(name, 0, 1);
275                 obj.props_serviceable_N = obj.props_N.getChild("serviceable", 0, 1);
276                 obj.props_serviceable_N.setBoolValue( serviceable );
277                 obj.props_in_pressure_N = obj.props_N.getChild("input-pressure-psi", 0, 1);
278                 obj.props_in_pressure_N.setDoubleValue( 0 );
279                 obj.props_out_pressure_N = obj.props_N.getChild("output-pressure-psi", 0, 1);
280                 obj.props_out_pressure_N.setDoubleValue( 0 );
281                 obj.props_out_pressure1_N = obj.props_N.getChild("output-pressure-psi", 1, 1);
282                 obj.props_out_pressure1_N.setDoubleValue( 0 );
283 #               obj.props_out_pressure2_N = obj.props_N.getChild("output-pressure-psi", 2, 1);
284 #               obj.props_out_pressure2_N.setDoubleValue( 0 );
285 #               obj.props_out_pressure3_N = obj.props_N.getChild("output-pressure-psi", 3, 1);
286 #               obj.props_out_pressure3_N.setDoubleValue( 0 );
287
288                 append(Valve.list, obj); 
289                 return obj;
290         },
291         update : func {
292                 var source = me.source_N.getValue();
293                 var control = clamp(me.control_N.getValue(), -1, 1); 
294                 var control1 = clamp(me.control1_N.getValue(), -1, 1); 
295                 var serviceable = me.props_serviceable_N.getValue();
296                 var output_pressure = 0;
297
298                 if (serviceable)
299                         {
300                         output_pressure = source * -control1;
301 #                       print (me.name, " valve output ", output_pressure);
302
303                         if(control == -1) 
304                                 {           # wheels
305 #                               print (me.name," wheels source ", source, " control " , control, " control1 " , control1);
306                                 me.props_out_pressure_N.setDoubleValue(output_pressure); 
307                                 me.props_out_pressure1_N.setDoubleValue(0); 
308                                 }
309                         elsif(control == 1) 
310                                 {           # flaps
311 #                               print (me.name," flaps source ", source, " control " , control, " control1 " , control1);
312                                 me.props_out_pressure_N.setDoubleValue(0); 
313                                 me.props_out_pressure1_N.setDoubleValue(output_pressure); 
314                                 }
315                         else
316                                 {           # neutral
317 #                               print (me.name," neutral ", source, " control " , control, " control1 " , control1);
318                                 me.props_out_pressure_N.setDoubleValue(0); 
319                                 me.props_out_pressure1_N.setDoubleValue(0); 
320                                 }
321
322                         }
323                         else
324                         {
325                         me.props_out_pressure_N.setDoubleValue(100); 
326                         me.props_out_pressure1_N.setDoubleValue(100); 
327                         }
328
329                 me.props_in_pressure_N.setDoubleValue(source);
330 #               me.props_out_pressure_N.setDoubleValue(output_pressure);
331
332            
333                 
334         },
335         setServiceable : func (serviceable) {
336                 me.props_serviceable_N.setBoolValue( serviceable ); 
337         },
338         list : [],
339 };
340
341 # Actuator class. Defines a double acting actuator in the hydraulic system.  
342 # The output can be used to drive control surfaces etc 
343
344 Actuator = {
345          new : func(name, source, output, pos_norm, serviceable, min, max, state) {
346                 var obj = { parents : [ Actuator ] };
347                 obj.name = name;
348 #               print ("name ", name);
349 #       print ("source ", source);
350 #       print ("output ", output);
351                 obj.source_N = props.globals.getNode( source, 1 );
352                 obj.source_N.setDoubleValue( 0 );
353                 obj.output_N = props.globals.getNode( output, 1 );
354                 obj.output_N.setDoubleValue( state );
355                 obj.position_norm_N = props.globals.getNode( pos_norm, 1 );
356                 obj.position_norm_N.setDoubleValue( state );
357                 obj.props_N = props.globals.getNode( "systems/hydraulic/actuators", 1 ).getChild(name, 0, 1);
358                 obj.props_serviceable_N = obj.props_N.getChild("serviceable", 0, 1);
359                 obj.props_serviceable_N.setBoolValue( serviceable );
360                 obj.props_in_pressure_N = obj.props_N.getChild("input-pressure-psi", 0, 1);
361                 obj.props_in_pressure_N.setDoubleValue( 0 );
362                 obj.props_position_norm_N = obj.props_N.getChild("position-norm", 0, 1);
363                 obj.props_position_norm_N.setDoubleValue( 0 );
364                 obj.min = min;
365                 obj.max = max;
366
367                 append(Actuator.list, obj); 
368                 return obj;
369         },
370         update : func {
371                 var source = me.source_N.getValue();
372                 var serviceable = me.props_serviceable_N.getValue();
373                 var state = me.position_norm_N.getValue();
374                 var output = 0;
375 #               print (me.name, " source ", source, " state " , state);
376
377                 if(source < MIN_PRESSURE and source > -MIN_PRESSURE or !serviceable)
378                         {
379                         output = state;
380                         #print (me.name," low pressure ", output);
381                         }
382                 elsif (source >= MIN_PRESSURE)
383                         {
384                         output = source / me.max;
385                         #print(me.name," max output ", output);
386                         output = math.max(output, state);
387                         #print(me.name," output max ", output);
388                         }
389                 elsif(source <= - MIN_PRESSURE)
390                         {
391                         output = (source - me.min) / math.abs(me.min);
392                         #print(me.name," min output ", output);
393                         output = math.min(output, state);
394                         #print(me.name," output min ", output);
395                         }
396                 else
397                         {
398                         output = state;
399                         }
400
401                 output = clamp(output, -1, 1);
402                 me.output_N.setDoubleValue( output );
403                 me.props_in_pressure_N.setDoubleValue( source );
404                 me.props_position_norm_N.setDoubleValue( state );
405
406 #           print (me.name, " output ", me.output_N.getValue());
407                 
408         },
409         setServiceable : func (serviceable) {
410                 me.props_serviceable_N.setBoolValue( serviceable ); 
411         },
412         list : [],
413 };
414
415 # Relief Valve class. Defines a relief valve in the hydraulic system.  The output controls
416 # the pressure in the hydraulic system.
417 # "name", "input property", "control property", "output property", status,
418 # max, initial state
419
420 Relief = {
421          new : func(name, source, control, output, serviceable,  max, state) {
422                 var obj = { parents : [ Relief ] };
423                 obj.name = name;
424 #               print ("name ", name);
425 #       print ("source ", source);
426 #               print ("output ", output);
427                 obj.source_N = props.globals.getNode( source, 1 );
428                 obj.source_N.setDoubleValue( 0 );
429                 obj.control_N = props.globals.getNode( control, 1 );
430                 obj.control_N.setDoubleValue(state);
431                 obj.output_N = props.globals.getNode( output, 1 );
432                 obj.output_N.setDoubleValue( MAX_PRESSURE );
433
434                 obj.props_N = props.globals.getNode( "systems/hydraulic/relief-valves", 1 ).getChild(name, 0, 1);
435                 obj.props_serviceable_N = obj.props_N.getChild("serviceable", 0, 1);
436                 obj.props_serviceable_N.setBoolValue( serviceable );
437                 obj.props_in_pressure_N = obj.props_N.getChild("input-pressure-psi", 0, 1);
438                 obj.props_in_pressure_N.setDoubleValue( 0 );
439                 obj.props_out_pressure_N = obj.props_N.getChild("output-pressure-psi", 0, 1);
440                 obj.props_out_pressure_N.setDoubleValue( 0 );
441
442                 obj.max = max;
443
444                 append(Actuator.list, obj); 
445                 return obj;
446         },
447         update : func {
448                 var source = me.source_N.getValue();
449                 var serviceable = me.props_serviceable_N.getValue();
450                 var control = me.control_N.getValue();
451                 var output = source;
452         #       print (me.name, " source ", source, " control " , control);
453
454                 if (serviceable and control != 0)
455                         {
456                         output = clamp(source, 0, me.max);
457                         }
458                 else
459                         {
460                         output = source;
461                         }
462
463                 me.output_N.setDoubleValue( output );
464                 me.props_in_pressure_N.setDoubleValue( source );
465                 me.props_out_pressure_N.setDoubleValue( output );
466
467         #    print (me.name, " output ", me.output_N.getValue());
468                 
469         },
470         setServiceable : func (serviceable) {
471                 me.props_serviceable_N.setBoolValue( serviceable ); 
472         },
473         list : [],
474 };
475
476 ###
477 #=============================== functions ===============================
478
479 hydraulicLever = func{             #sets the lever up-down, right-left or neutral
480
481         right = arg[0]; 
482         up = arg[1];
483         lever=[0,1];
484         
485 #       print("input: ", right, " ", up);
486         
487         lever[0]= getprop("controls/hydraulic/lever[0]"); #right/left
488         lever[1]= getprop("controls/hydraulic/lever[1]"); #up/down
489         
490 #       print ("lever in: ", lever[0],lever[1], lever[]);
491                 
492         if ( lever[0] == 0 or lever[0] == right) 
493                 {     
494                 if (up == 1) 
495                         {
496 #                       print ("lever move: ", lever[0],lever[1]);
497                         lever[1] = lever[1] + 1;
498                         }
499                 elsif (up == 0) 
500                         {
501                         lever[1] = 0;
502                         }
503                 elsif ( up == -1)
504                         {
505                         lever[1] = lever[1] - 1;
506                         }
507
508                 if (lever[1] == 0) 
509                         {
510                         lever[0] = 0;
511                         } 
512                 else 
513                         {
514                         lever[0] = right;
515                         }
516                 }
517
518 #       print ("lever out: ", lever[0],lever[1], lever[]);
519
520         setprop("controls/hydraulic/lever[0]",clamp(lever[0], -1, 1));
521         setprop("controls/hydraulic/lever[1]",clamp(lever[1], -1, 1));
522         
523 #       if (lever[0] == 1 and lever[1] == -1) 
524 #               { registerTimer (hurricane.flapBlowin)}   # run the timer 
525                 
526         if (lever[0] == -1 and lever[1] != 0) 
527                 { registerTimer (hurricane.wheelsMove)}   # run the timer                    
528                 
529 } # end function 
530 # ==================== Fire it up =====================
531
532 setlistener("sim/signals/fdm-initialized", initialize);
533
534 # end 
535
536