mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-06 19:00:27 +08:00
If the sub is disarmed in many modes, the output "throttle" (vertical control) is set to 0.0, corresponding to full downward thrust. While this does not affect manual control, it can affect subsequent mode changes (e.g. to ALT_HOLD). Set to a constant NEUTRAL_THROTTLE, set to 0.5, instead.
131 lines
5.6 KiB
C++
131 lines
5.6 KiB
C++
#include "Sub.h"
|
|
|
|
|
|
bool ModeAlthold::init(bool ignore_checks) {
|
|
if(!sub.control_check_barometer()) {
|
|
return false;
|
|
}
|
|
|
|
// initialize vertical maximum speeds and acceleration
|
|
// sets the maximum speed up and down returned by position controller
|
|
// All limits must be positive
|
|
position_control->D_set_max_speed_accel_cm(sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
|
|
position_control->D_set_correction_speed_accel_cm(sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
|
|
|
|
// initialise position and desired velocity
|
|
position_control->D_init_controller();
|
|
|
|
sub.last_pilot_heading_rad = ahrs.get_yaw_rad();
|
|
|
|
return true;
|
|
}
|
|
|
|
// althold_run - runs the althold controller
|
|
// should be called at 100hz or more
|
|
void ModeAlthold::run()
|
|
{
|
|
run_pre();
|
|
control_depth();
|
|
run_post();
|
|
}
|
|
|
|
void ModeAlthold::run_pre()
|
|
{
|
|
uint32_t tnow = AP_HAL::millis();
|
|
|
|
// initialize vertical speeds and acceleration
|
|
// All limits must be positive
|
|
position_control->D_set_max_speed_accel_cm(sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
|
|
|
|
if (!motors.armed()) {
|
|
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
|
|
// Sub vehicles do not stabilize roll/pitch/yaw when not auto-armed (i.e. on the ground, pilot has never raised throttle)
|
|
attitude_control->set_throttle_out(NEUTRAL_THROTTLE,true,g.throttle_filt);
|
|
attitude_control->relax_attitude_controllers();
|
|
position_control->D_relax_controller(motors.get_throttle_hover());
|
|
sub.last_pilot_heading_rad = ahrs.get_yaw_rad();
|
|
return;
|
|
}
|
|
|
|
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
|
|
|
|
// get pilot desired lean angles
|
|
float target_roll, target_pitch;
|
|
|
|
// Check if set_attitude_target_no_gps is valid
|
|
if (tnow - sub.set_attitude_target_no_gps.last_message_ms < 5000) {
|
|
float target_yaw;
|
|
Quaternion(
|
|
sub.set_attitude_target_no_gps.packet.q
|
|
).to_euler(
|
|
target_roll,
|
|
target_pitch,
|
|
target_yaw
|
|
);
|
|
target_roll = degrees(target_roll);
|
|
target_pitch = degrees(target_pitch);
|
|
target_yaw = degrees(target_yaw);
|
|
|
|
attitude_control->input_euler_angle_roll_pitch_yaw_cd(target_roll * 1e2f, target_pitch * 1e2f, target_yaw * 1e2f, true);
|
|
return;
|
|
}
|
|
|
|
sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, attitude_control->get_althold_lean_angle_max_cd());
|
|
|
|
// get pilot's desired yaw rate
|
|
float yaw_input = channel_yaw->pwm_to_angle_dz_trim(channel_yaw->get_dead_zone() * sub.gain, channel_yaw->get_radio_trim());
|
|
float target_yaw_rate = sub.get_pilot_desired_yaw_rate(yaw_input);
|
|
|
|
// call attitude controller
|
|
if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
|
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(target_roll, target_pitch, target_yaw_rate);
|
|
sub.last_pilot_heading_rad = ahrs.get_yaw_rad();
|
|
sub.last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
|
|
|
|
} else { // hold current heading
|
|
|
|
// this check is required to prevent bounce back after very fast yaw maneuvers
|
|
// the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
|
|
if (tnow < sub.last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
|
|
target_yaw_rate = 0; // Stop rotation on yaw axis
|
|
|
|
// call attitude controller with target yaw rate = 0 to decelerate on yaw axis
|
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(target_roll, target_pitch, target_yaw_rate);
|
|
sub.last_pilot_heading_rad = ahrs.get_yaw_rad(); // update heading to hold
|
|
|
|
} else { // call attitude controller holding absolute bearing
|
|
attitude_control->input_euler_angle_roll_pitch_yaw_cd(target_roll, target_pitch, rad_to_cd(sub.last_pilot_heading_rad), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ModeAlthold::run_post()
|
|
{
|
|
motors.set_forward(channel_forward->norm_input());
|
|
motors.set_lateral(channel_lateral->norm_input());
|
|
}
|
|
|
|
void ModeAlthold::control_depth() {
|
|
// return 0.2f when at the surface to p
|
|
// scale linearly between 0.2f and 1.0f as we approach the surface
|
|
float distance_to_surface = (g.surface_depth - inertial_nav.get_position_z_up_cm()) * 0.01f;
|
|
distance_to_surface = constrain_float(distance_to_surface, 0.0f, 1.0f);
|
|
motors.set_max_throttle(g.surface_max_throttle + (1.0f - g.surface_max_throttle) * distance_to_surface);
|
|
|
|
float target_climb_rate_cms = sub.get_pilot_desired_climb_rate(channel_throttle->get_control_in());
|
|
target_climb_rate_cms = constrain_float(target_climb_rate_cms, -sub.get_pilot_speed_dn(), g.pilot_speed_up);
|
|
|
|
// desired_climb_rate returns 0 when within the deadzone.
|
|
//we allow full control to the pilot, but as soon as there's no input, we handle being at surface/bottom
|
|
if (fabsf(target_climb_rate_cms) < 0.05f) {
|
|
if (sub.ap.at_surface) {
|
|
position_control->set_pos_desired_U_cm(MIN(position_control->get_pos_desired_U_cm(), g.surface_depth)); // set target to 5 cm below surface level
|
|
} else if (sub.ap.at_bottom) {
|
|
position_control->set_pos_desired_U_cm(MAX(inertial_nav.get_position_z_up_cm() + 10.0f, position_control->get_pos_desired_U_cm())); // set target to 10 cm above bottom
|
|
}
|
|
}
|
|
|
|
position_control->D_set_pos_target_from_climb_rate_cms(target_climb_rate_cms);
|
|
position_control->D_update_controller();
|
|
}
|