@@ -56,45 +56,33 @@ void NPFG::evaluate(const Vector2f &ground_vel, const Vector2f &wind_vel, Vector
56
56
Vector2f air_vel = ground_vel - wind_vel;
57
57
const float airspeed = air_vel.norm ();
58
58
59
- if (airspeed < MIN_AIRSPEED) {
60
- // this case should only ever happen if we have not launched, the wind
61
- // estimator has failed, or the aircraft is legitimately in a very sad
62
- // situation
63
- airspeed_ref_ = airspeed_nom_;
64
- lateral_accel_ = 0 .0f ;
65
- feas_ = 0 .0f ;
66
- feas_on_track_ = 0 .0f ;
67
- return ;
68
- }
69
-
70
59
const float wind_speed = wind_vel.norm ();
71
- const float wind_ratio = wind_speed / airspeed;
72
60
73
61
float track_error = fabsf (signed_track_error);
74
62
63
+ // track error bound is dynamic depending on ground speed
64
+ track_error_bound_ = trackErrorBound (ground_speed, time_const_);
65
+ float normalized_track_error = normalizedTrackError (track_error, track_error_bound_);
66
+
67
+ // look ahead angle based purely on track proximity
68
+ float look_ahead_ang = lookAheadAngle (normalized_track_error);
69
+
70
+ bearing_vec_ = bearingVec (unit_path_tangent, look_ahead_ang, signed_track_error);
71
+
75
72
// on-track wind triangle projections
76
73
float wind_cross_upt = cross2D (wind_vel, unit_path_tangent);
77
74
float wind_dot_upt = wind_vel.dot (unit_path_tangent);
78
75
79
76
// calculate the bearing feasibility on the track at the current closest point
80
- feas_on_track_ = bearingFeasibility (wind_cross_upt, wind_dot_upt, wind_speed, wind_ratio );
77
+ feas_on_track_ = bearingFeasibility (wind_cross_upt, wind_dot_upt, airspeed, wind_speed );
81
78
82
79
// update control parameters considering upper and lower stability bounds (if enabled)
83
80
// must be called before trackErrorBound() as it updates time_const_
84
- adapted_period_ = adaptPeriod (ground_speed, airspeed, wind_ratio , track_error,
81
+ adapted_period_ = adaptPeriod (ground_speed, airspeed, wind_speed , track_error,
85
82
path_curvature, wind_vel, unit_path_tangent, feas_on_track_);
86
83
p_gain_ = pGain (adapted_period_, damping_);
87
84
time_const_ = timeConst (adapted_period_, damping_);
88
85
89
- // track error bound is dynamic depending on ground speed
90
- track_error_bound_ = trackErrorBound (ground_speed, time_const_);
91
- float normalized_track_error = normalizedTrackError (track_error, track_error_bound_);
92
-
93
- // look ahead angle based purely on track proximity
94
- float look_ahead_ang = lookAheadAngle (normalized_track_error);
95
-
96
- bearing_vec_ = bearingVec (unit_path_tangent, look_ahead_ang, signed_track_error);
97
-
98
86
// specific waypoint logic complications... handles case where we are following
99
87
// waypoints and are in front of the first of the segment.
100
88
// TODO: find a way to get this out of the main eval method!
@@ -118,9 +106,9 @@ void NPFG::evaluate(const Vector2f &ground_vel, const Vector2f &wind_vel, Vector
118
106
119
107
wind_cross_upt = cross2D (wind_vel, unit_path_tangent);
120
108
wind_dot_upt = wind_vel.dot (unit_path_tangent);
121
- feas_on_track_ = bearingFeasibility (wind_cross_upt, wind_dot_upt, wind_speed, wind_ratio );
109
+ feas_on_track_ = bearingFeasibility (wind_cross_upt, wind_dot_upt, airspeed, wind_speed );
122
110
123
- adapted_period_ = adaptPeriod (ground_speed, airspeed, wind_ratio , track_error,
111
+ adapted_period_ = adaptPeriod (ground_speed, airspeed, wind_speed , track_error,
124
112
path_curvature, wind_vel, unit_path_tangent, feas_on_track_);
125
113
p_gain_ = pGain (adapted_period_, damping_);
126
114
time_const_ = timeConst (adapted_period_, damping_);
@@ -133,7 +121,7 @@ void NPFG::evaluate(const Vector2f &ground_vel, const Vector2f &wind_vel, Vector
133
121
const float wind_dot_bearing = wind_vel.dot (bearing_vec_);
134
122
135
123
// continuous representation of the bearing feasibility
136
- feas_ = bearingFeasibility (wind_cross_bearing, wind_dot_bearing, wind_speed, wind_ratio );
124
+ feas_ = bearingFeasibility (wind_cross_bearing, wind_dot_bearing, airspeed, wind_speed );
137
125
138
126
// we consider feasibility of both the current bearing as well as that on the track at the current closest point
139
127
const float feas_combined = feas_ * feas_on_track_;
@@ -152,7 +140,7 @@ void NPFG::evaluate(const Vector2f &ground_vel, const Vector2f &wind_vel, Vector
152
140
153
141
// lateral acceleration needed to stay on curved track (assuming no heading error)
154
142
lateral_accel_ff_ = lateralAccelFF (unit_path_tangent, ground_vel, wind_dot_upt,
155
- wind_cross_upt, airspeed, wind_speed, wind_ratio, signed_track_error, path_curvature);
143
+ wind_cross_upt, airspeed, wind_speed, signed_track_error, path_curvature);
156
144
157
145
// total lateral acceleration to drive aircaft towards track as well as account
158
146
// for path curvature. The full effect of the feed-forward acceleration is smoothly
@@ -161,13 +149,13 @@ void NPFG::evaluate(const Vector2f &ground_vel, const Vector2f &wind_vel, Vector
161
149
lateral_accel_ = lateral_accel + feas_combined * track_proximity_ * lateral_accel_ff_;
162
150
} // evaluate
163
151
164
- float NPFG::adaptPeriod (const float ground_speed, const float airspeed, const float wind_ratio ,
152
+ float NPFG::adaptPeriod (const float ground_speed, const float airspeed, const float wind_speed ,
165
153
const float track_error, const float path_curvature, const Vector2f &wind_vel,
166
154
const Vector2f &unit_path_tangent, const float feas_on_track) const
167
155
{
168
156
float period = period_;
169
157
const float air_turn_rate = fabsf (path_curvature * airspeed);
170
- const float wind_factor = windFactor (wind_ratio );
158
+ const float wind_factor = windFactor (airspeed, wind_speed );
171
159
172
160
if (en_period_lb_) {
173
161
// lower bound the period for stability w.r.t. roll time constant and current flight condition
@@ -213,10 +201,15 @@ float NPFG::normalizedTrackError(const float track_error, const float track_erro
213
201
return math::constrain (track_error / track_error_bound, 0 .0f , 1 .0f );
214
202
}
215
203
216
- float NPFG::windFactor (const float wind_ratio ) const
204
+ float NPFG::windFactor (const float airspeed, const float wind_speed ) const
217
205
{
218
206
// See [TODO: include citation] for definition/elaboration of this approximation.
219
- return 2 .0f * (1 .0f - sqrtf (1 .0f - math::min (1 .0f , wind_ratio)));
207
+ if (wind_speed > airspeed || airspeed < EPSILON) {
208
+ return 2 .0f ;
209
+
210
+ } else {
211
+ return 2 .0f * (1 .0f - sqrtf (1 .0f - math::min (1 .0f , wind_speed / airspeed)));
212
+ }
220
213
} // windFactor
221
214
222
215
float NPFG::periodUB (const float air_turn_rate, const float wind_factor, const float feas_on_track) const
@@ -419,58 +412,23 @@ Vector2f NPFG::infeasibleAirVelRef(const Vector2f &wind_vel, const Vector2f &bea
419
412
return air_vel_ref.normalized () * airspeed;
420
413
} // infeasibleAirVelRef
421
414
422
- float NPFG::bearingFeasibility (const float wind_cross_bearing, const float wind_dot_bearing, const float wind_speed ,
423
- const float wind_ratio ) const
415
+ float NPFG::bearingFeasibility (float wind_cross_bearing, const float wind_dot_bearing, const float airspeed ,
416
+ const float wind_speed ) const
424
417
{
425
- float sin_cross_wind_ang; // in [0, 1] (constant after 90 deg)
426
-
427
- if (wind_dot_bearing <= 0 .0f ) {
428
- sin_cross_wind_ang = 1 .0f ;
418
+ if (wind_dot_bearing < 0 .0f ) {
419
+ wind_cross_bearing = wind_speed;
429
420
430
421
} else {
431
- sin_cross_wind_ang = fabsf (wind_cross_bearing / wind_speed);
432
- }
433
-
434
- // upper and lower feasibility barriers
435
- float wind_ratio_ub, wind_ratio_lb;
436
-
437
- if (sin_cross_wind_ang < CROSS_WIND_ANG_CO) { // small angle approx.
438
- // linear feasibility function (avoid singularity)
439
-
440
- const float wind_ratio_ub_co = ONE_DIV_SIN_CROSS_WIND_ANG_CO;
441
- wind_ratio_ub = wind_ratio_ub_co + CO_SLOPE * (CROSS_WIND_ANG_CO - sin_cross_wind_ang);
442
-
443
- const float wind_ratio_lb_co = (ONE_DIV_SIN_CROSS_WIND_ANG_CO - 2 .0f ) * wind_ratio_buffer_ + 1 .0f ;
444
- wind_ratio_lb = wind_ratio_lb_co + wind_ratio_buffer_ * CO_SLOPE * (CROSS_WIND_ANG_CO - sin_cross_wind_ang);
445
-
446
- } else {
447
- const float one_div_sin_cross_wind_ang = 1 .0f / sin_cross_wind_ang;
448
- wind_ratio_ub = one_div_sin_cross_wind_ang;
449
- wind_ratio_lb = (one_div_sin_cross_wind_ang - 2 .0f ) * wind_ratio_buffer_ + 1 .0f ;
450
- }
451
-
452
- // calculate bearing feasibility
453
- float feas = 1 .0f ; // feasible
454
-
455
- if (wind_ratio > wind_ratio_ub) {
456
- // infeasible
457
- feas = 0 .0f ;
458
-
459
- } else if (wind_ratio > wind_ratio_lb) {
460
- // partially feasible
461
- // smoothly transition from fully feasible to fully infeasible
462
- feas = cosf (M_PI_F * 0 .5f * math::constrain ((wind_ratio - wind_ratio_lb) / (wind_ratio_ub - wind_ratio_lb), 0 .0f ,
463
- 1 .0f ));
464
- feas *= feas;
422
+ wind_cross_bearing = fabsf (wind_cross_bearing);
465
423
}
466
424
467
- return feas;
425
+ float sin_arg = sinf (M_PI_F * 0 .5f * math::constrain ((airspeed - wind_cross_bearing) / airspeed_buffer_, 0 .0f , 1 .0f ));
426
+ return sin_arg * sin_arg;
468
427
} // bearingFeasibility
469
428
470
429
float NPFG::lateralAccelFF (const Vector2f &unit_path_tangent, const Vector2f &ground_vel,
471
430
const float wind_dot_upt, const float wind_cross_upt, const float airspeed,
472
- const float wind_speed, const float wind_ratio, const float signed_track_error,
473
- const float path_curvature) const
431
+ const float wind_speed, const float signed_track_error, const float path_curvature) const
474
432
{
475
433
// NOTE: all calculations within this function take place at the closet point
476
434
// on the path, as if the aircraft were already tracking the given path at
0 commit comments