FixedwingPositionControl: Add support for figure 8 loitering.

The command is sent by a dedicated mavlink command and forwarded to the fixed wing position controller.

The pattern is defined by the radius of the major axis, the radius of the minor axis and the orientation. The pattern is then defined by:
The upper part of the pattern consist of a clockwise circle with radius defined by the minor axis. The center of the circle is defined by the major axis minus the minor axis away from the pattern center.
The lower part of the pattern consist of a counter-clockwise circle with the same definitions as above.
In between, the circles are connected with straight lines in a cross configuration. The lines are always tangetial to the circles.
The orientation rotates the major axis around the NED down axis.

The loitering logic is defined inside its own class used by the fixed wing position control module. It defines which segment (one of the circles or lines) is active and uses the path controller (npfg or l1-control) to determine the desired roll angle.

A feedback mavlink message is send with the executed pattern parameters.
This commit is contained in:
Konrad
2023-07-14 10:14:47 +02:00
committed by Daniel Agar
parent 0d6c2c8ce9
commit e5e66370e7
15 changed files with 1048 additions and 23 deletions
@@ -53,6 +53,7 @@ FixedwingPositionControl::FixedwingPositionControl(bool vtol) :
WorkItem(MODULE_NAME, px4::wq_configurations::nav_and_controllers),
_attitude_sp_pub(vtol ? ORB_ID(fw_virtual_attitude_setpoint) : ORB_ID(vehicle_attitude_setpoint)),
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")),
_figure_eight(_npfg, _wind_vel, _eas2tas),
_launchDetector(this),
_runway_takeoff(this)
{
@@ -895,7 +896,12 @@ FixedwingPositionControl::control_auto(const float control_interval, const Vecto
if (position_sp_type == position_setpoint_s::SETPOINT_TYPE_LOITER
|| current_sp.type == position_setpoint_s::SETPOINT_TYPE_LOITER) {
publishOrbitStatus(current_sp);
if (current_sp.loiter_pattern == position_setpoint_s::LOITER_TYPE_FIGUREEIGHT) {
publishFigureEightStatus(current_sp);
} else {
publishOrbitStatus(current_sp);
}
}
switch (position_sp_type) {
@@ -914,10 +920,24 @@ FixedwingPositionControl::control_auto(const float control_interval, const Vecto
break;
case position_setpoint_s::SETPOINT_TYPE_LOITER:
control_auto_loiter(control_interval, curr_pos, ground_speed, pos_sp_prev, current_sp, pos_sp_next);
if (current_sp.loiter_pattern == position_setpoint_s::LOITER_TYPE_FIGUREEIGHT) {
controlAutoFigureEight(control_interval, curr_pos, ground_speed, pos_sp_prev, current_sp);
} else {
control_auto_loiter(control_interval, curr_pos, ground_speed, pos_sp_prev, current_sp, pos_sp_next);
}
break;
}
/* reset loiter state */
if ((position_sp_type != position_setpoint_s::SETPOINT_TYPE_LOITER) ||
((position_sp_type == position_setpoint_s::SETPOINT_TYPE_LOITER) &&
(current_sp.loiter_pattern != position_setpoint_s::LOITER_TYPE_FIGUREEIGHT))) {
_figure_eight.resetPattern();
}
/* Copy thrust output for publication, handle special cases */
if (position_sp_type == position_setpoint_s::SETPOINT_TYPE_IDLE) {
@@ -1287,6 +1307,63 @@ FixedwingPositionControl::control_auto_loiter(const float control_interval, cons
_param_climbrate_target.get());
}
void
FixedwingPositionControl::controlAutoFigureEight(const float control_interval, const Vector2d &curr_pos,
const Vector2f &ground_speed, const position_setpoint_s &pos_sp_prev, const position_setpoint_s &pos_sp_curr)
{
// airspeed settings
float target_airspeed = adapt_airspeed_setpoint(control_interval, pos_sp_curr.cruising_speed,
_param_fw_airspd_min.get(), ground_speed);
// Lateral Control
Vector2f curr_pos_local{_local_pos.x, _local_pos.y};
FigureEight::FigureEightPatternParameters params;
params.center_pos_local = _global_local_proj_ref.project(pos_sp_curr.lat, pos_sp_curr.lon);
params.loiter_direction_counter_clockwise = pos_sp_curr.loiter_direction_counter_clockwise;
params.loiter_minor_radius = pos_sp_curr.loiter_minor_radius;
params.loiter_orientation = pos_sp_curr.loiter_orientation;
params.loiter_radius = pos_sp_curr.loiter_radius;
_figure_eight.initializePattern(curr_pos_local, ground_speed, params);
// Apply control
_figure_eight.updateSetpoint(curr_pos_local, ground_speed, params, target_airspeed);
_att_sp.roll_body = _figure_eight.getRollSetpoint();
target_airspeed = _figure_eight.getAirspeedSetpoint();
_target_bearing = _figure_eight.getTargetBearing();
_closest_point_on_path = _figure_eight.getClosestPoint();
// TECS
float tecs_fw_thr_min;
float tecs_fw_thr_max;
if (pos_sp_curr.gliding_enabled) {
/* enable gliding with this waypoint */
_tecs.set_speed_weight(2.0f);
tecs_fw_thr_min = 0.0;
tecs_fw_thr_max = 0.0;
} else {
tecs_fw_thr_min = _param_fw_thr_min.get();
tecs_fw_thr_max = _param_fw_thr_max.get();
}
tecs_update_pitch_throttle(control_interval,
pos_sp_curr.alt,
target_airspeed,
radians(_param_fw_p_lim_min.get()),
radians(_param_fw_p_lim_max.get()),
tecs_fw_thr_min,
tecs_fw_thr_max,
_param_sinkrate_target.get(),
_param_climbrate_target.get());
// Yaw
_att_sp.yaw_body = _yaw; // yaw is not controlled, so set setpoint to current yaw
}
void
FixedwingPositionControl::control_auto_takeoff(const hrt_abstime &now, const float control_interval,
const Vector2d &global_position, const Vector2f &ground_speed, const position_setpoint_s &pos_sp_curr)
@@ -2834,6 +2911,21 @@ void FixedwingPositionControl::publishOrbitStatus(const position_setpoint_s pos_
_orbit_status_pub.publish(orbit_status);
}
void FixedwingPositionControl::publishFigureEightStatus(const position_setpoint_s pos_sp)
{
figure_eight_status_s figure_eight_status{};
figure_eight_status.timestamp = hrt_absolute_time();
figure_eight_status.major_radius = pos_sp.loiter_radius * (pos_sp.loiter_direction_counter_clockwise ? -1.f : 1.f);
figure_eight_status.minor_radius = pos_sp.loiter_minor_radius;
figure_eight_status.orientation = pos_sp.loiter_orientation;
figure_eight_status.frame = 5; //MAV_FRAME_GLOBAL_INT
figure_eight_status.x = static_cast<int32_t>(pos_sp.lat * 1e7);
figure_eight_status.y = static_cast<int32_t>(pos_sp.lon * 1e7);
figure_eight_status.z = pos_sp.alt;
_figure_eight_status_pub.publish(figure_eight_status);
}
void FixedwingPositionControl::navigateWaypoints(const Vector2f &start_waypoint, const Vector2f &end_waypoint,
const Vector2f &vehicle_pos, const Vector2f &ground_vel, const Vector2f &wind_vel)
{