Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AP_L1_Control: Add wind compensation for 90 degree turn distance #28509

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions libraries/AP_L1_Control/AP_L1_Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,60 @@ int32_t AP_L1_Control::target_bearing_cd(void) const
}

/*
this is the turn distance assuming a 90 degree turn
This is the turn distance assuming a 90 degree turn
*/
float AP_L1_Control::turn_distance(float wp_radius) const
{
wp_radius *= sq(_ahrs.get_EAS2TAS());
return MIN(wp_radius, _L1_dist);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L1 distance is already scaled by the groundspeed, which will increase as you have more tailwind.
Isn't your approach double-dipping on the scaling of L1 distance?

I admit however that this MIN( is forcing a max distance of WP_RADIUS, which can be too small, and masking the effect of the L1 scaling.

What I would like to see is some testing that shows:

  1. The current behaviour in head and tailwind.
  2. Your proposed PR in head and tailwind.
  3. What would happen if you turned this MIN( into a MAX(, instead of using your new code.

Copy link
Contributor Author

@menschel menschel Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting Idea.
I can't say that I fully understand the L1 algo but with my limited knowledge I assume that L1 point will continue to update on the course and not stop at the waypoint.
The MIN(wp_radius, _L1_dist) seems to be an invariant for that.

This is an attempt to setup L1 Navigation correctly with 20km/h wind from the right and 35km/h cruise speed. Rectangle 300x100m. Regular Arduplane 4.5
It is clear that turning into the wind is beneficiary to perfectly line up with the next leg. While turning with the wind creates crosstrack error. Reviewing this picture also unveils, that the 90degree approach is not perfect, so I'll try to setup a SITL test first.
rectangle_mission

// True airspeed correction
const float eas2tas_sq = sq(_ahrs.get_EAS2TAS());

// Distance scaled to true airspeed
float turn_distance_m = wp_radius * eas2tas_sq;

// The L1-distance can be closer then the waypoint radius because we are off-track.
turn_distance_m = MIN(turn_distance_m, _L1_dist);

/** Forward correct the crosstrack error caused by the lateral shift by the wind during the turn.
* Simplified for a rectangle turn, the head-wind (or tail-wind) before the turn is the crosswind after the turn.
* Turn early on tail-wind, because it works against the turn and this may exceed the plane's turn capability.
*
* An overly simplified example:
* wp_radius = 50m
* tail_wind_mps = 10m/s
* arc_distance_m = 0.5*3.14*50 = 78,5m
* air_speed_mps = 10m/s
* turn_duration_s = 7,85s
* lateral_shift_m = 78,5m
* turn_distance_m = 50m + 78,5m = 128,5m
*
* Note: Head-wind condition is not corrected because is creates the mathmatical problem of possibly negative turn distances.
*/

const float tail_wind_mps = -(_ahrs.head_wind());

float air_speed_mps = 0.0f;

// Only apply correction is airspeed is available and for tail-wind condition.
if ((tail_wind_mps > 0.0f) && (_ahrs.airspeed_estimate_true(air_speed_mps)))
{
/** The flight distance on the arc segment.
* By assuming an ideal rectangle turn that starts when the distance to the waypoint equals wp_radius,
* the turn radius also equals wp_radius.
* The distance therefore is a quarter of the circumfence (2*PI*R)
*/
const float arc_distance_m = 0.5f * M_PI * wp_radius;

// the time needed for the turn
const float turn_duration_s = arc_distance_m / air_speed_mps;

// the resulting lateral shift during the turn
const float lateral_shift_m = turn_duration_s * tail_wind_mps;

// the resulting turn distance
turn_distance_m += lateral_shift_m;
}

return turn_distance_m;
}

/*
Expand Down
Loading