diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp
index 7132772aa..c70db6671 100644
--- a/src/FDM/YASim/Airplane.cpp
+++ b/src/FDM/YASim/Airplane.cpp
@@ -52,6 +52,9 @@ Airplane::~Airplane()
 
 void Airplane::iterate(float dt)
 {
+    // The gear might have moved.  Change their aerodynamics.
+    updateGearState();
+
     _model.iterate();
 
     // FIXME: Consume fuel
@@ -108,27 +111,12 @@ Gear* Airplane::getGear(int g)
     return ((GearRec*)_gears.get(g))->gear;
 }
 
-void Airplane::setGearState(bool down, float dt)
+void Airplane::updateGearState()
 {
-    int i;
-    for(i=0; i<_gears.size(); i++) {
+    for(int i=0; i<_gears.size(); i++) {
         GearRec* gr = (GearRec*)_gears.get(i);
-        if(gr->time == 0) {
-            // Non-extensible
-            gr->gear->setExtension(1);
-            gr->surf->setXDrag(1);
-            gr->surf->setYDrag(1);
-            gr->surf->setZDrag(1);
-            continue;
-        }
+        float ext = gr->gear->getExtension();
 
-        float diff = dt / gr->time;
-        if(!down) diff = -diff;
-        float ext = gr->gear->getExtension() + diff;
-        if(ext < 0) ext = 0;
-        if(ext > 1) ext = 1;
-
-        gr->gear->setExtension(ext);
         gr->surf->setXDrag(ext);
         gr->surf->setYDrag(ext);
         gr->surf->setZDrag(ext);
@@ -236,12 +224,11 @@ int Airplane::addTank(float* pos, float cap, float density)
     return _tanks.add(t);
 }
 
-void Airplane::addGear(Gear* gear, float transitionTime)
+void Airplane::addGear(Gear* gear)
 {
     GearRec* g = new GearRec();
     g->gear = gear;
     g->surf = 0;
-    g->time = transitionTime;
     _gears.add(g);
 }
 
@@ -589,9 +576,6 @@ void Airplane::compile()
     // Do this after solveGear, because it creates "gear" objects that
     // we don't want to affect.
     compileContactPoints();
-
-    // Drop the gear (use a really big dt)
-    setGearState(true, 1000000);
 }
 
 void Airplane::solveGear()
@@ -678,16 +662,13 @@ void Airplane::runCruise()
 	Control* c = (Control*)_cruiseControls.get(i);
 	_controls.setInput(c->control, c->val);
     }
-    _controls.applyControls();
+    _controls.applyControls(1000000); // Huge dt value
 
     // The local wind
     float wind[3];
     Math::mul3(-1, _cruiseState.v, wind);
     Math::vmul33(_cruiseState.orient, wind, wind);
  
-    // Gear are up (if they're non-retractable, this is a noop)
-    setGearState(false, 100000);
-    
     // Cruise is by convention at 50% tank capacity
     setFuelFraction(0.5);
    
@@ -700,6 +681,8 @@ void Airplane::runCruise()
     }
     stabilizeThrust();
 
+    updateGearState();
+
     // Precompute thrust in the model, and calculate aerodynamic forces
     _model.getBody()->reset();
     _model.initIteration();
@@ -719,7 +702,7 @@ void Airplane::runApproach()
 	Control* c = (Control*)_approachControls.get(i);
 	_controls.setInput(c->control, c->val);
     }
-    _controls.applyControls();
+    _controls.applyControls(1000000);
 
     // The local wind
     float wind[3];
@@ -729,9 +712,6 @@ void Airplane::runApproach()
     // Approach is by convention at 20% tank capacity
     setFuelFraction(0.2);
 
-    // Gear are down
-    setGearState(true, 100000);
-
     // Run the thrusters until they get to a stable setting.  FIXME:
     // this is lots of wasted work.
     for(i=0; i<_thrusters.size(); i++) {
@@ -741,6 +721,8 @@ void Airplane::runApproach()
     }
     stabilizeThrust();
 
+    updateGearState();
+
     // Precompute thrust in the model, and calculate aerodynamic forces
     _model.getBody()->reset();
     _model.initIteration();
diff --git a/src/FDM/YASim/Airplane.hpp b/src/FDM/YASim/Airplane.hpp
index cf088f1b9..9a38700a0 100644
--- a/src/FDM/YASim/Airplane.hpp
+++ b/src/FDM/YASim/Airplane.hpp
@@ -35,7 +35,7 @@ public:
     void addFuselage(float* front, float* back, float width,
                      float taper=1, float mid=0.5);
     int addTank(float* pos, float cap, float fuelDensity);
-    void addGear(Gear* g, float transitionTime);
+    void addGear(Gear* g);
     void addThruster(Thruster* t, float mass, float* cg);
     void addBallast(float* pos, float mass);
 
@@ -51,7 +51,6 @@ public:
 
     int numGear();
     Gear* getGear(int g);
-    void setGearState(bool down, float dt);
 
     int numTanks();
     void setFuelFraction(float frac); // 0-1, total amount of fuel
@@ -74,7 +73,7 @@ private:
     struct Tank { float pos[3]; float cap; float fill;
 	          float density; int handle; };
     struct Fuselage { float front[3], back[3], width, taper, mid; };
-    struct GearRec { Gear* gear; Surface* surf; float wgt; float time; };
+    struct GearRec { Gear* gear; Surface* surf; float wgt; };
     struct ThrustRec { Thruster* thruster;
 	               int handle; float cg[3]; float mass; };
     struct Control { int control; float val; };
@@ -94,6 +93,7 @@ private:
     void addContactPoint(float* pos);
     void compileContactPoints();
     float normFactor(float f);
+    void updateGearState();
 
     Model _model;
     ControlMap _controls;
diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp
index a023d91f3..9bc74b5ec 100644
--- a/src/FDM/YASim/ControlMap.cpp
+++ b/src/FDM/YASim/ControlMap.cpp
@@ -63,6 +63,7 @@ void ControlMap::addMapping(int input, int type, void* object, int options)
 	out = new OutRec();
 	out->type = type;
 	out->object = object;
+        out->oldL = out->oldR = out->time = 0;
 	_outputs.add(out);
     }
     
@@ -73,12 +74,8 @@ void ControlMap::addMapping(int input, int type, void* object, int options)
     map->idx = out->maps.add(map);
 
     // The default ranges differ depending on type!
-    map->src1 = map->dst1 = 1;
-    map->src0 = map->dst0 = 0;
-    if(type==FLAP0 || type==FLAP1 || type==STEER)
-	map->src0 = map->dst0 = -1;
-    if(type==MAGNETOS)
-	map->src1 = map->dst1 = 3;
+    map->src1 = map->dst1 = rangeMax(type);
+    map->src0 = map->dst0 = rangeMin(type);
 
     // And add it to the approproate vectors.
     Vector* maps = (Vector*)_inputs.get(input);
@@ -91,7 +88,7 @@ void ControlMap::reset()
     for(int i=0; i<_outputs.size(); i++) {
 	OutRec* o = (OutRec*)_outputs.get(i);
 	for(int j=0; j<o->maps.size(); j++)
-	    ((MapRec*)o->maps.get(j))->val = 0;
+	    ((MapRec*)(o->maps.get(j)))->val = 0;
     }
 }
 
@@ -114,7 +111,31 @@ void ControlMap::setInput(int input, float val)
     }
 }
 
-void ControlMap::applyControls()
+int ControlMap::getOutputHandle(void* obj, int type)
+{
+    for(int i=0; i<_outputs.size(); i++) {
+	OutRec* o = (OutRec*)_outputs.get(i);
+	if(o->object == obj && o->type == type)
+	    return i;
+    }
+}
+
+void ControlMap::setTransitionTime(int handle, float time)
+{
+    ((OutRec*)_outputs.get(handle))->time = time;
+}
+
+float ControlMap::getOutput(int handle)
+{
+    return ((OutRec*)_outputs.get(handle))->oldL;
+}
+
+float ControlMap::getOutputR(int handle)
+{
+    return ((OutRec*)_outputs.get(handle))->oldR;
+}
+
+void ControlMap::applyControls(float dt)
 {
     int outrec;
     for(outrec=0; outrec<_outputs.size(); outrec++) {
@@ -139,6 +160,25 @@ void ControlMap::applyControls()
 		rval += val;
 	}
 
+        // If there is a finite transition time, clamp the values to
+        // the maximum travel allowed in this dt.
+        if(o->time > 0) {
+            float dl = lval - o->oldL;
+            float dr = rval - o->oldR;
+            float adl = Math::abs(dl);
+            float adr = Math::abs(dr);
+        
+            float max = (dt/o->time) * (rangeMax(o->type) - rangeMin(o->type));
+            if(adl > max) dl = dl*max/adl;
+            if(adr > max) dr = dr*max/adr;
+
+            lval = o->oldL + dl;
+            rval = o->oldR + dr;
+        }
+
+        o->oldL = lval;
+        o->oldR = rval;
+
 	void* obj = o->object;
 	switch(o->type) {
 	case THROTTLE: ((Thruster*)obj)->setThrottle(lval);        break;
@@ -162,4 +202,28 @@ void ControlMap::applyControls()
     }
 }
 
-}; // namespace yasim
+float ControlMap::rangeMin(int type)
+{
+    // The minimum of the range for each type of control
+    switch(type) {
+    case FLAP0:    return -1;  // [-1:1]
+    case FLAP1:    return -1;
+    case STEER:    return -1;
+    case MAGNETOS: return 0;   // [0:3]
+    default:       return 0;   // [0:1]
+    }
+}
+
+float ControlMap::rangeMax(int type)
+{
+    // The maximum of the range for each type of control
+    switch(type) {
+    case FLAP0:    return 1; // [-1:1]
+    case FLAP1:    return 1;
+    case STEER:    return 1;
+    case MAGNETOS: return 3; // [0:3]
+    default:       return 1; // [0:1]
+    }
+}
+
+} // namespace yasim
diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp
index b9d6f0f17..cbbd46ab6 100644
--- a/src/FDM/YASim/ControlMap.hpp
+++ b/src/FDM/YASim/ControlMap.hpp
@@ -43,10 +43,31 @@ public:
     void setInput(int input, float value);
 
     // Calculates and applies the settings received since the last reset().
-    void applyControls();
+    void applyControls(float dt);
+
+    // Returns the input/output range appropriate for the given
+    // control.  Ailerons go from -1 to 1, while throttles are never
+    // lower than zero, etc...
+    static float rangeMin(int type);
+    static float rangeMax(int type);
+
+    // Each output record is identified by both an object/type tuple
+    // and a numeric handle.
+    int getOutputHandle(void* obj, int type);
+
+    // Sets the transition time for the control output to swing
+    // through its full range.
+    void setTransitionTime(int handle, float time);
+
+    // Retrieves the current value of the control output.  Controls
+    // with OPT_SPLIT settable on inputs will have a separately
+    // computed "right side" value.
+    float getOutput(int handle);
+    float getOutputR(int handle);
 
 private:
-    struct OutRec { int type; void* object; Vector maps; };
+    struct OutRec { int type; void* object; Vector maps;
+                    float oldL, oldR, time; };
     struct MapRec  { OutRec* out; int idx; int opt; float val;
                      float src0; float src1; float dst0; float dst1; };
 
diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp
index 73bc4b429..4fa0cee11 100644
--- a/src/FDM/YASim/FGFDM.cpp
+++ b/src/FDM/YASim/FGFDM.cpp
@@ -57,7 +57,8 @@ FGFDM::~FGFDM()
 	delete[] wr->prop;
 	delete wr;
     }
-    
+    for(i=0; i<_controlProps.size(); i++)
+        delete (PropOut*)_controlProps.get(i);
 }
 
 void FGFDM::iterate(float dt)
@@ -170,8 +171,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
 	g->setDynamicFriction(attrf(a, "dfric", 0.7));
 	if(a->hasAttribute("castering"))
 	    g->setCastering(true);
-        float transitionTime = attrf(a, "retract-time", 0);
-	_airplane.addGear(g, transitionTime);
+	_airplane.addGear(g);
     } else if(eq(name, "fuselage")) {
 	float b[3];
 	v[0] = attrf(a, "ax");
@@ -225,34 +225,55 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
 	v[1] = attrf(a, "y");
 	v[2] = attrf(a, "z");
 	((Thruster*)_currObj)->setDirection(v);
-    } else if(eq(name, "control")) {
+    } else if(eq(name, "control-setting")) {
+	// A cruise or approach control setting
 	const char* axis = a->getValue("axis");
-	if(a->hasAttribute("output")) {
-	    // assert: output type must match _currObj type!
-	    const char* output = a->getValue("output");
-	    int opt = 0;
-	    opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
-	    opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
-	    opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
+	float value = attrf(a, "value", 0);
+	if(_cruiseCurr)
+	    _airplane.addCruiseControl(parseAxis(axis), value);
+	else
+	    _airplane.addApproachControl(parseAxis(axis), value);
+    } else if(eq(name, "control-input")) {
 
-	    ControlMap* cm = _airplane.getControlMap();
-	    if(a->hasAttribute("src0")) {
-		cm->addMapping(parseAxis(axis), parseOutput(output),
-			       _currObj, opt,
-			       attrf(a, "src0"), attrf(a, "src1"), 
-			       attrf(a, "dst0"), attrf(a, "dst1"));
-	    } else {
-		cm->addMapping(parseAxis(axis), parseOutput(output),
-			       _currObj, opt);
-	    }
+	// A mapping of input property to a control
+        int axis = parseAxis(a->getValue("axis"));
+	int control = parseOutput(a->getValue("control"));
+	int opt = 0;
+	opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0;
+	opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0;
+	opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0;
+	
+	ControlMap* cm = _airplane.getControlMap();
+	if(a->hasAttribute("src0")) {
+                           cm->addMapping(axis, control, _currObj, opt,
+			   attrf(a, "src0"), attrf(a, "src1"), 
+			   attrf(a, "dst0"), attrf(a, "dst1"));
 	} else {
-	    // assert: must be under a "cruise" or "approach" tag
-	    float value = attrf(a, "value", 0);
-	    if(_cruiseCurr)
-		_airplane.addCruiseControl(parseAxis(axis), value);
-	    else
-		_airplane.addApproachControl(parseAxis(axis), value);
+            cm->addMapping(axis, control, _currObj, opt);
 	}
+    } else if(eq(name, "control-output")) {
+        // A property output for a control on the current object
+        ControlMap* cm = _airplane.getControlMap();
+        int type = parseOutput(a->getValue("control"));
+        int handle = cm->getOutputHandle(_currObj, type);
+
+	PropOut* p = new PropOut();
+	p->prop = fgGetNode(a->getValue("prop"), true);
+	p->handle = handle;
+	p->type = type;
+	p->left = !(a->hasAttribute("side") &&
+                        eq("right", a->getValue("side")));
+	p->min = attrf(a, "min", cm->rangeMin(type));
+	p->max = attrf(a, "max", cm->rangeMax(type));
+	_controlProps.add(p);
+
+    } else if(eq(name, "control-speed")) {
+        ControlMap* cm = _airplane.getControlMap();
+        int type = parseOutput(a->getValue("control"));
+        int handle = cm->getOutputHandle(_currObj, type);
+        float time = attrf(a, "transition-time", 0);
+        
+        cm->setTransitionTime(handle, time);
     } else {
 	*(int*)0=0; // unexpected tag, boom
     }
@@ -269,22 +290,33 @@ void FGFDM::getExternalInput(float dt)
 	float val = fgGetFloat(a->name, 0);
 	cm->setInput(a->handle, val);
     }
-    cm->applyControls();
+    cm->applyControls(dt);
 
     // Weights
     for(i=0; i<_weights.size(); i++) {
 	WeightRec* wr = (WeightRec*)_weights.get(i);
 	_airplane.setWeight(wr->handle, fgGetFloat(wr->prop));
     }
-
-    // Gear state
-    _airplane.setGearState(fgGetBool("/controls/gear-down"), dt);
 }
 
 void FGFDM::setOutputProperties()
 {
     char buf[256];
     int i;
+
+    ControlMap* cm = _airplane.getControlMap();
+    for(i=0; i<_controlProps.size(); i++) {
+        PropOut* p = (PropOut*)_controlProps.get(i);
+        float val = (p->left
+                     ? cm->getOutput(p->handle)
+                     : cm->getOutputR(p->handle));
+        float rmin = cm->rangeMin(p->type);
+        float rmax = cm->rangeMax(p->type);
+        float frac = (val - rmin) / (rmax - rmin);
+        val = frac*(p->max - p->min) + p->min;
+        p->prop->setFloatValue(val);
+    }
+
     float fuelDensity = 718.95; // default to gasoline: ~6 lb/gal
     for(i=0; i<_airplane.numTanks(); i++) {
         fuelDensity = _airplane.getFuelDensity(i);
@@ -461,8 +493,7 @@ int FGFDM::parseOutput(const char* name)
     if(eq(name, "FLAP1"))     return ControlMap::FLAP1;
     if(eq(name, "SLAT"))      return ControlMap::SLAT;
     if(eq(name, "SPOILER"))   return ControlMap::SPOILER;
-    // error here...
-    return *(int*)0;
+    *(int*)0=0;
 }
 
 void FGFDM::parseWeight(XMLAttributes* a)
@@ -484,7 +515,7 @@ void FGFDM::parseWeight(XMLAttributes* a)
 bool FGFDM::eq(const char* a, const char* b)
 {
     // Figure it out for yourself. :)
-    while(*a && *b && *a++ == *b++);
+    while(*a && *b && *a == *b) { a++; b++; }
     return !(*a || *b);
 }
 
diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp
index f9506dbd2..0a374b7a3 100644
--- a/src/FDM/YASim/FGFDM.hpp
+++ b/src/FDM/YASim/FGFDM.hpp
@@ -30,6 +30,8 @@ private:
     struct AxisRec { char* name; int handle; };
     struct EngRec { char* prefix; Thruster* eng; };
     struct WeightRec { char* prop; float size; int handle; };
+    struct PropOut { SGPropertyNode* prop; int handle, type; bool left;
+                     float min, max; };
 
     void setOutputProperties();
 
@@ -58,6 +60,9 @@ private:
     // Engine types.  Contains an EngRec structure.
     Vector _thrusters;
 
+    // Output properties for the ControlMap
+    Vector _controlProps;
+
     // Parsing temporaries
     void* _currObj;
     bool _cruiseCurr;
diff --git a/src/FDM/YASim/YASim.cxx b/src/FDM/YASim/YASim.cxx
index 118d14aab..e37432933 100644
--- a/src/FDM/YASim/YASim.cxx
+++ b/src/FDM/YASim/YASim.cxx
@@ -159,9 +159,10 @@ void YASim::init()
     fgSetFloat("/controls/spoilers", 0);
 
     // Are we at ground level?  If so, lift the plane up so the gear
-    // clear the ground
+    // clear the ground.
     double runway_altitude =
       fgGetDouble("/environment/ground-elevation-m") * SG_METER_TO_FEET;
+    fgSetBool("/controls/gear-down", false);
     if(get_Altitude() - runway_altitude < 50) {
 	float minGearZ = 1e18;
 	for(i=0; i<a->numGear(); i++) {
@@ -172,6 +173,7 @@ void YASim::init()
 		minGearZ = pos[2];
 	}
 	_set_Altitude(runway_altitude - minGearZ*M2FT);
+	fgSetBool("/controls/gear-down", true);
     }
 
     // The pilot's eyepoint
@@ -418,7 +420,6 @@ void YASim::copyFromYASim()
 	SGPropertyNode * node = fgGetNode("gear/gear", i, true);
 	node->setBoolValue("has-brake", g->getBrake() != 0);
 	node->setBoolValue("wow", g->getCompressFraction() != 0);
-	node->setBoolValue("position", g->getExtension());
     }
 
     for(i=0; i<model->numThrusters(); i++) {