Control: Tweak new pushback

This commit is contained in:
Joshua Davidson 2018-04-04 15:15:15 -04:00
parent 5f85d712aa
commit d21d700b0d
7 changed files with 497 additions and 483 deletions

View file

@ -46,8 +46,8 @@
<K_psi_push type="float">0.05</K_psi_push>
<K_V_turn type="float">1.4</K_V_turn>
<F_V_turn type="float">7.0</F_V_turn>
<K_psi_turn type="float">0.2</K_psi_turn>
<V_min type="float">2.5</V_min>
<K_psi_turn type="float">0.1</K_psi_turn>
<V_min type="float">1.5</V_min>
</driver>
</pushback>
<icing>
@ -247,8 +247,10 @@
<item>
<label>Pushback</label>
<binding>
<command>dialog-show</command>
<dialog-name>autopush</dialog-name>
<command>nasal</command>
<script>
autopush.push_dlg.open();
</script>
</binding>
</item>
<item>

View file

@ -4,6 +4,7 @@
# Copyright (c) 2018 Michael Danilov <mike.d.ft402 -eh- gmail.com>
# Distribute under the terms of GPLv2.
var push_dlg = gui.Dialog.new("sim/gui/dialogs/autopush/push/dialog", "Aircraft/IDG-A32X/Systems/autopush.xml");
var _K_p = nil;
var _K_i = nil;
@ -14,63 +15,60 @@ var _deltaV_old = nil;
var _t_old = nil;
var loop = func() {
if(!getprop("/sim/model/pushback/available")){
stop();
return;
}
var force = 0.0;
# Rollspeed is only adequate if the wheel is touching the ground.
if(getprop("/gear/gear[0]/wow")){
var deltaV =
getprop("/sim/model/pushback/target-speed-km_h") -
getprop("/gear/gear[0]/rollspeed-ms") * 3.6;
var dV = deltaV - _deltaV_old;
var t = getprop("/sim/time/elapsed-sec");
var dt = math.max(t - _t_old, 0.0001);
_int = math.min(math.max(_int + dV * dt, -_F_i), _F_i);
force = (_K_p * deltaV + _K_d * dV / dt + _K_i * _int) * KG2LB;
_deltaV_old = deltaV;
_t_old = t;
var yaw = getprop("/sim/model/pushback/yaw-deg") * D2R;
setprop("/sim/model/pushback/force-x", math.cos(yaw));
setprop("/sim/model/pushback/force-y", math.sin(yaw));
}
setprop("/sim/model/pushback/force-lbf", force);
if (!getprop("/sim/model/pushback/available")) {
stop();
return;
}
var force = 0.0;
# Rollspeed is only adequate if the wheel is touching the ground.
if (getprop("/gear/gear[0]/wow")) {
var deltaV =
getprop("/sim/model/pushback/target-speed-km_h") -
getprop("/gear/gear[0]/rollspeed-ms") * 3.6;
var dV = deltaV - _deltaV_old;
var t = getprop("/sim/time/elapsed-sec");
var dt = math.max(t - _t_old, 0.0001);
_int = math.min(math.max(_int + dV * dt, -_F_i), _F_i);
force = (_K_p * deltaV + _K_d * dV / dt + _K_i * _int) * KG2LB;
_deltaV_old = deltaV;
_t_old = t;
var yaw = getprop("/sim/model/pushback/yaw-deg") * D2R;
setprop("/sim/model/pushback/force-x", math.cos(yaw));
setprop("/sim/model/pushback/force-y", math.sin(yaw));
}
setprop("/sim/model/pushback/force-lbf", force);
}
var timer = maketimer(0.026, func{loop()});
var start = func() {
_K_p = getprop("/sim/model/pushback/K_p");
_K_i = getprop("/sim/model/pushback/K_i");
_K_d = getprop("/sim/model/pushback/K_d");
_F_i = getprop("/sim/model/pushback/F_i");
_int = 0.0;
_deltaV_old = 0.0;
_t_old = getprop("/sim/time/elapsed-sec");
setprop("/sim/model/pushback/connected", 1);
if(!timer.isRunning){
screen.log.write("(pushback): Release brakes.");
}
timer.start();
_K_p = getprop("/sim/model/pushback/K_p");
_K_i = getprop("/sim/model/pushback/K_i");
_K_d = getprop("/sim/model/pushback/K_d");
_F_i = getprop("/sim/model/pushback/F_i");
_int = 0.0;
_deltaV_old = 0.0;
_t_old = getprop("/sim/time/elapsed-sec");
setprop("/sim/model/pushback/connected", 1);
if (!timer.isRunning) {
screen.log.write("(pushback): Release brakes.");
}
timer.start();
}
var stop = func() {
if(timer.isRunning){
screen.log.write("(pushback): Pushback disconnected, bypass pin removed.");
}
timer.stop();
setprop("/sim/model/pushback/force-lbf", 0.0);
setprop("/sim/model/pushback/connected", 0);
if (timer.isRunning) {
screen.log.write("(pushback): Pushback disconnected, bypass pin removed.");
}
timer.stop();
setprop("/sim/model/pushback/force-lbf", 0.0);
setprop("/sim/model/pushback/connected", 0);
}
var toggle = func(){
if(
getprop("/sim/model/pushback/enabled") *
getprop("/sim/model/pushback/available")
){
start();
}else{
stop();
}
if (getprop("/sim/model/pushback/enabled") * getprop("/sim/model/pushback/available")) {
start();
} else {
stop();
}
}

View file

@ -26,88 +26,86 @@ var _psi_parking = nil;
var _psi_turn = nil;
var loop = func() {
if(!getprop("/sim/model/pushback/connected")){
stop();
return;
}
var V = 0.0;
var steering = 0.0;
var deltapsi = 0.0;
var psi = getprop("/orientation/heading-deg");
if(!_turning){
# Initially follow a straight line parallel to our initial heading.
var (A, S) = courseAndDistance(_target);
S *= NM2M;
# Stop when the bearing flips, guarante against infinite pushing.
if(
(abs(S) < _S_min) +
(abs(saw180(_psi_parking - A - math.min(_sign, 0.0) * 180.0) > 90.0))
){
_turning = 1;
screen.log.write("(pushback): Turning to face heading " ~ int(_psi_turn) ~ ".");
}
deltapsi = saw180(_psi_parking - psi);
V = math.min(math.max(_K_V_push * _sign * (S / _S_min), -_F_V_push), _F_V_push);
steering = math.min(math.max(_K_psi_push * _sign * deltapsi, -1.0), 1.0);
}else{
# Turn (almost) in place.
deltapsi = saw180(_psi_turn - psi);
V = math.min(math.max(_K_V_turn * _sign * abs(deltapsi), -_F_V_turn), _F_V_turn);
# We are done when the heading error is small.
if(abs(V) < _V_min){
stop();
return;
}
steering = math.min(math.max(_K_psi_turn * _sign * deltapsi, -1.0), 1.0);
}
setprop("/sim/model/pushback/target-speed-km_h", V);
setprop("/sim/model/pushback/driver/steer-cmd-norm", steering);
if (!getprop("/sim/model/pushback/connected")) {
stop();
return;
}
var V = 0.0;
var steering = 0.0;
var deltapsi = 0.0;
var psi = getprop("/orientation/heading-magnetic-deg");
if (!_turning) {
# Initially follow a straight line parallel to our initial heading.
var (A, S) = courseAndDistance(_target);
S *= NM2M;
# Stop when the bearing flips, guarante against infinite pushing.
if ((abs(S) < _S_min) + (abs(saw180(_psi_parking - A - math.min(_sign, 0.0) * 180.0) > 90.0))) {
_turning = 1;
screen.log.write("(pushback): Turning to face heading " ~ int(_psi_turn) ~ ".");
}
deltapsi = saw180(_psi_parking - psi);
V = math.min(math.max(_K_V_push * _sign * (S / _S_min), -_F_V_push), _F_V_push);
steering = math.min(math.max(_K_psi_push * _sign * deltapsi, -1.0), 1.0);
} else {
# Turn (almost) in place.
deltapsi = saw180(_psi_turn - psi);
V = math.min(math.max(_K_V_turn * _sign * abs(deltapsi), -_F_V_turn), _F_V_turn);
# We are done when the heading error is small.
if (abs(V) < _V_min) {
stop();
return;
}
steering = math.min(math.max(_K_psi_turn * _sign * deltapsi, -1.0), 1.0);
}
setprop("/sim/model/pushback/target-speed-km_h", V);
setprop("/sim/model/pushback/driver/steer-cmd-norm", steering);
}
var timer = maketimer(0.051, func{loop()});
var start = func() {
_K_V_push = getprop("/sim/model/pushback/driver/K_V_push");
_F_V_push = getprop("/sim/model/pushback/driver/F_V_push");
_S_min = getprop("/sim/model/pushback/driver/S_min-m");
_K_psi_push = getprop("/sim/model/pushback/driver/K_psi_push");
_K_V_turn = getprop("/sim/model/pushback/driver/K_V_turn");
_F_V_turn = getprop("/sim/model/pushback/driver/F_V_turn");
_K_psi_turn = getprop("/sim/model/pushback/driver/K_psi_turn");
_V_min = getprop("/sim/model/pushback/driver/V_min");
if(!getprop("/sim/model/pushback/connected")){
return;
}
towdist = getprop("/sim/model/pushback/driver/tow-distance-m");
_target = geo.aircraft_position();
_psi_parking = getprop("/orientation/heading-deg");
_target.apply_course_distance(_psi_parking, towdist);
_psi_turn = getprop("/sim/model/pushback/driver/face-heading-deg");
_sign = 1.0 - 2.0 * (towdist < 0.0);
_turning = 0;
timer.start();
if(_sign < 0.0){
screen.log.write("(pushback): Pushing back.");
}else{
screen.log.write("(pushback): Towing.");
}
_K_V_push = getprop("/sim/model/pushback/driver/K_V_push");
_F_V_push = getprop("/sim/model/pushback/driver/F_V_push");
_S_min = getprop("/sim/model/pushback/driver/S_min-m");
_K_psi_push = getprop("/sim/model/pushback/driver/K_psi_push");
_K_V_turn = getprop("/sim/model/pushback/driver/K_V_turn");
_F_V_turn = getprop("/sim/model/pushback/driver/F_V_turn");
_K_psi_turn = getprop("/sim/model/pushback/driver/K_psi_turn");
_V_min = getprop("/sim/model/pushback/driver/V_min");
if (!getprop("/sim/model/pushback/connected")) {
return;
}
towdist = getprop("/sim/model/pushback/driver/tow-distance-m");
_target = geo.aircraft_position();
_psi_parking = getprop("/orientation/heading-deg");
_target.apply_course_distance(_psi_parking, towdist);
_psi_turn = getprop("/sim/model/pushback/driver/face-heading-deg");
_sign = 1.0 - 2.0 * (towdist < 0.0);
_turning = 0;
timer.start();
if (_sign < 0.0) {
screen.log.write("(pushback): Pushing back.");
} else {
screen.log.write("(pushback): Towing.");
}
}
var stop = func() {
if(timer.isRunning){
screen.log.write("(pushback): Done.");
}
timer.stop();
setprop("/sim/model/pushback/target-speed-km_h", 0.0);
if (timer.isRunning) {
screen.log.write("(pushback): Done.");
setprop("/controls/flight/rudder", 0);
}
timer.stop();
setprop("/sim/model/pushback/target-speed-km_h", 0.0);
}
# Sawtooth: -180..+180 deg.
var saw180 = func(p) {
while (p <= -180.0){
p += 360.0;
}
while (p > 180.0){
p -= 360.0;
}
return p;
while (p <= -180.0) {
p += 360.0;
}
while (p > 180.0) {
p -= 360.0;
}
return p;
}

375
Systems/autopush.xml Normal file
View file

@ -0,0 +1,375 @@
<?xml version="1.0"?>
<!--
AUTOPUSH
Pushback dialog.
Copyright (c) 2018 Michael Danilov <mike.d.ft402 -eh- gmail.com>
Original code (c) FlightGear
Distribute under the terms of GPLv2.
-->
<PropertyList>
<name>autopush</name>
<layout>vbox</layout>
<group>
<layout>hbox</layout>
<text>
<label>Pushback</label>
</text>
<empty>
<stretch>true</stretch>
</empty>
<button>
<halign>right</halign>
<pref-width>20</pref-width>
<pref-height>20</pref-height>
<legend>X</legend>
<key>Esc</key>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
<hrule/>
<group>
<stretch>true</stretch>
<layout>vbox</layout>
<halign>center</halign>
<valign>top</valign>
<checkbox>
<halign>left</halign>
<label>Connect</label>
<property>/sim/model/pushback/enabled</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>autopush.toggle();</script>
</binding>
</checkbox>
<hrule/>
<group>
<layout>table</layout>
<text>
<row>0</row>
<col>0</col>
<label>Speed: </label>
</text>
<button>
<row>0</row>
<col>1</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&lt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/target-speed-km_h</property>
<min>-15</min>
<max>15</max>
<step>-1</step>
<wrap>false</wrap>
</binding>
</button>
<slider>
<row>0</row>
<col>2</col>
<min>-15</min>
<max>15</max>
<property>/sim/model/pushback/target-speed-km_h</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<button>
<row>0</row>
<col>3</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&gt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/target-speed-km_h</property>
<min>-15</min>
<max>15</max>
<step>1</step>
<wrap>false</wrap>
</binding>
</button>
<button>
<row>0</row>
<col>4</col>
<pref-width>50</pref-width>
<pref-height>25</pref-height>
<legend>Stop</legend>
<binding>
<command>property-assign</command>
<property>/sim/model/pushback/target-speed-km_h</property>
<value>0</value>
</binding>
</button>
<text>
<row>0</row>
<col>5</col>
<pref-width>16</pref-width>
<property>/sim/model/pushback/target-speed-km_h</property>
<format>%3.0f</format>
<live>true</live>
</text>
<text>
<row>0</row>
<col>6</col>
<label>km/h</label>
</text>
</group>
<hrule/>
<group>
<layout>table</layout>
<text>
<row>0</row>
<col>0</col>
<halign>left</halign>
<label>Distance:</label>
</text>
<button>
<row>0</row>
<col>1</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&lt;&lt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<min>-100</min>
<max>100</max>
<step>-10</step>
<wrap>false</wrap>
</binding>
</button>
<button>
<row>0</row>
<col>2</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&lt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<min>-100</min>
<max>100</max>
<step>-1</step>
<wrap>false</wrap>
</binding>
</button>
<slider>
<row>0</row>
<col>3</col>
<min>-100</min>
<max>100</max>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<button>
<row>0</row>
<col>4</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&gt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<min>-100</min>
<max>100</max>
<step>1</step>
<wrap>false</wrap>
</binding>
</button>
<button>
<row>0</row>
<col>5</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&gt;&gt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<min>-100</min>
<max>100</max>
<step>10</step>
<wrap>false</wrap>
</binding>
</button>
<text>
<row>0</row>
<col>6</col>
<pref-width>16</pref-width>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<format>%4.0f</format>
<live>true</live>
</text>
<text>
<row>0</row>
<col>7</col>
<label>m </label>
</text>
</group>
<group>
<layout>table</layout>
<text>
<row>0</row>
<col>0</col>
<halign>left</halign>
<label>Facing: </label>
</text>
<button>
<row>0</row>
<col>1</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&lt;&lt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<min>0</min>
<max>360</max>
<step>-10</step>
<wrap>false</wrap>
</binding>
</button>
<button>
<row>0</row>
<col>2</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&lt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<min>0</min>
<max>360</max>
<step>-1</step>
<wrap>false</wrap>
</binding>
</button>
<slider>
<row>0</row>
<col>3</col>
<min>0</min>
<max>360</max>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<button>
<row>0</row>
<col>4</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&gt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<min>0</min>
<max>360</max>
<step>1</step>
<wrap>false</wrap>
</binding>
</button>
<button>
<row>0</row>
<col>5</col>
<pref-width>25</pref-width>
<pref-height>25</pref-height>
<legend>&gt;&gt;</legend>
<binding>
<command>property-adjust</command>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<min>0</min>
<max>360</max>
<step>10</step>
<wrap>false</wrap>
</binding>
</button>
<text>
<row>0</row>
<col>6</col>
<pref-width>16</pref-width>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<format>%3.0f</format>
<live>true</live>
</text>
<text>
<row>0</row>
<col>7</col>
<label> </label>
</text>
</group>
<group>
<layout>hbox</layout>
<button>
<legend>Start</legend>
<binding>
<command>nasal</command>
<script>autopush_driver.start();</script>
</binding>
</button>
<button>
<legend>Stop</legend>
<binding>
<command>nasal</command>
<script>autopush_driver.stop();</script>
</binding>
</button>
</group>
</group>
</PropertyList>

View file

@ -1,158 +0,0 @@
<?xml version="1.0"?>
<!--
AUTOPUSH
Pushback dialog.
Copyright (c) 2018 Michael Danilov <mike.d.ft402 -eh- gmail.com>
Original code (c) FlightGear
Distribute under the terms of GPLv2.
-->
<PropertyList>
<name>autopush</name>
<layout>vbox</layout>
<group>
<layout>hbox</layout>
<text>
<label>Pushback</label>
</text>
<empty>
<stretch>true</stretch>
</empty>
<button>
<legend/>
<key>Esc</key>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<border>2</border>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
<hrule/>
<group>
<stretch>true</stretch>
<layout>vbox</layout>
<halign>center</halign>
<valign>top</valign>
<checkbox>
<halign>left</halign>
<label>Connect</label>
<property>/sim/model/pushback/enabled</property>
<binding><command>dialog-apply</command></binding>
<binding>
<command>nasal</command>
<script>autopush.toggle();</script>
</binding>
</checkbox>
<group>
<layout>hbox</layout>
<text>
<label>Speed:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>-15</min>
<max>15</max>
<property>/sim/model/pushback/target-speed-km_h</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/sim/model/pushback/target-speed-km_h</property>
<format>%3.0f</format>
<live>true</live>
</text>
<text>
<label> km/h</label>
</text>
</group>
<hrule/>
<group>
<layout>hbox</layout>
<text>
<label>Distance:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>-100</min>
<max>100</max>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/sim/model/pushback/driver/tow-distance-m</property>
<format>%4.0f</format>
<live>true</live>
</text>
<text>
<label> m</label>
</text>
</group>
<group>
<layout>hbox</layout>
<text>
<label>Facing:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>0</min>
<max>360</max>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/sim/model/pushback/driver/face-heading-deg</property>
<format>%3.0f</format>
<live>true</live>
</text>
</group>
<group>
<layout>hbox</layout>
<button>
<legend>Tow / push back</legend>
<binding>
<command>nasal</command>
<script>
autopush_driver.start();
</script>
</binding>
</button>
<button>
<legend>Stop</legend>
<binding>
<command>nasal</command>
<script>
autopush_driver.stop();
</script>
</binding>
</button>
</group>
</group>
</PropertyList>

View file

@ -1,201 +0,0 @@
<?xml version="1.0"?>
<PropertyList>
<name>pushback</name>
<layout>vbox</layout>
<!-- Uncomment for default FG pushback.
-->
<nasal>
<open>
var pushback_position = aircraft.door.new("sim/model/pushback", 10.0);
pushback_position.setpos(pushback_position.getpos());
props.globals.getNode("/sim/model/pushback/enabled", 1 ).setBoolValue(1);
props.globals.initNode("/sim/model/pushback/target-speed-fps", 0.0 );
</open>
<close>
pushback_position.setpos(0);
setprop("/sim/model/pushback/enabled", 0 );
setprop("/sim/model/pushback/target-speed-fps", 0 );
setprop("/sim/model/pushback/force", 0);
</close>
</nasal>
<group>
<layout>hbox</layout>
<text>
<label>Pushback</label>
</text>
<empty>
<stretch>true</stretch>
</empty>
<button>
<legend/>
<key>Esc</key>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<border>2</border>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
<hrule/>
<group>
<stretch>true</stretch>
<layout>vbox</layout>
<halign>center</halign>
<valign>top</valign>
<checkbox>
<halign>left</halign>
<label>Connect</label>
<!-- Uncomment for Tu-144 pushback.
<property>/sim/model/pushback/enabled</property>
<binding><command>dialog-apply</command></binding>
-->
<!-- Uncomment for default FG pushback.
-->
<binding>
<command>nasal</command>
<script>pushback_position.toggle();</script>
</binding>
</checkbox>
<!-- Uncomment for Tu-144 pushback.
<group>
<layout>hbox</layout>
<text>
<label>Speed:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>-15</min>
<max>15</max>
<property>/sim/model/pushback/target-speed-km_h</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/sim/model/pushback/target-speed-km_h</property>
<format>%3.0f</format>
<live>true</live>
</text>
<text>
<label> km/h</label>
</text>
</group>
-->
<!-- Uncomment for default FG pushback.
-->
<group>
<layout>hbox</layout>
<text>
<label>Speed:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>-25</min>
<max>25</max>
<property>/sim/model/pushback/target-speed-fps</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/sim/model/pushback/target-speed-fps</property>
<format>%3.0f</format>
<live>true</live>
</text>
<text>
<label> fps</label>
</text>
</group>
<hrule/>
<group>
<layout>hbox</layout>
<text>
<label>Distance:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>-100</min>
<max>100</max>
<property>/nasal/pushback_driver/tow-distance-m</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/nasal/pushback_driver/tow-distance-m</property>
<format>%4.0f</format>
<live>true</live>
</text>
<text>
<label> m</label>
</text>
</group>
<group>
<layout>hbox</layout>
<text>
<label>Facing:</label>
</text>
<slider>
<row>0</row>
<col>2</col>
<min>0</min>
<max>360</max>
<property>/nasal/pushback_driver/face-heading-deg</property>
<binding>
<command>dialog-apply</command>
</binding>
</slider>
<text>
<pref-width>16</pref-width>
<property>/nasal/pushback_driver/face-heading-deg</property>
<format>%3.0f</format>
<live>true</live>
</text>
</group>
<group>
<layout>hbox</layout>
<button>
<legend>Tow / push back</legend>
<binding>
<command>nasal</command>
<script>
pushback_driver.start();
</script>
</binding>
</button>
<button>
<legend>Stop</legend>
<binding>
<command>nasal</command>
<script>
pushback_driver.stop();
</script>
</binding>
</button>
</group>
</group>
</PropertyList>