123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- #include "AP_Landing.h"
- #include <GCS_MAVLink/GCS.h>
- #include <AP_HAL/AP_HAL.h>
- #include <SRV_Channel/SRV_Channel.h>
- #include <AP_Common/Location.h>
- #include <AP_AHRS/AP_AHRS.h>
- const AP_Param::GroupInfo AP_Landing_Deepstall::var_info[] = {
-
-
-
-
-
-
- AP_GROUPINFO("V_FWD", 1, AP_Landing_Deepstall, forward_speed, 1),
-
-
-
-
- AP_GROUPINFO("SLOPE_A", 2, AP_Landing_Deepstall, slope_a, 1),
-
-
-
-
- AP_GROUPINFO("SLOPE_B", 3, AP_Landing_Deepstall, slope_b, 1),
-
-
-
-
-
-
- AP_GROUPINFO("APP_EXT", 4, AP_Landing_Deepstall, approach_extension, 50),
-
-
-
-
-
-
- AP_GROUPINFO("V_DWN", 5, AP_Landing_Deepstall, down_speed, 2),
-
-
-
-
-
-
- AP_GROUPINFO("SLEW_SPD", 6, AP_Landing_Deepstall, slew_speed, 0.5),
-
-
-
-
-
-
- AP_GROUPINFO("ELEV_PWM", 7, AP_Landing_Deepstall, elevator_pwm, 1500),
-
-
-
-
-
-
- AP_GROUPINFO("ARSP_MAX", 8, AP_Landing_Deepstall, handoff_airspeed, 15.0),
-
-
-
-
-
-
- AP_GROUPINFO("ARSP_MIN", 9, AP_Landing_Deepstall, handoff_lower_limit_airspeed, 10.0),
-
-
-
-
-
-
- AP_GROUPINFO("L1", 10, AP_Landing_Deepstall, L1_period, 30.0),
-
-
-
-
-
- AP_GROUPINFO("L1_I", 11, AP_Landing_Deepstall, L1_i, 0),
-
-
-
-
-
-
- AP_GROUPINFO("YAW_LIM", 12, AP_Landing_Deepstall, yaw_rate_limit, 10),
-
-
-
-
-
-
- AP_GROUPINFO("L1_TCON", 13, AP_Landing_Deepstall, time_constant, 0.4),
-
-
- AP_SUBGROUPINFO(ds_PID, "", 14, AP_Landing_Deepstall, PID),
-
-
-
-
-
-
- AP_GROUPINFO("ABORTALT", 15, AP_Landing_Deepstall, min_abort_alt, 0.0f),
-
-
-
-
-
- AP_GROUPINFO("AIL_SCL", 16, AP_Landing_Deepstall, aileron_scalar, 1.0f),
- AP_GROUPEND
- };
- void AP_Landing_Deepstall::do_land(const AP_Mission::Mission_Command& cmd, const float relative_altitude)
- {
- stage = DEEPSTALL_STAGE_FLY_TO_LANDING;
- ds_PID.reset();
- L1_xtrack_i = 0.0f;
- hold_level = false;
-
- memcpy(&landing_point, &cmd.content.location, sizeof(Location));
- if (!landing_point.relative_alt && !landing_point.terrain_alt) {
- approach_alt_offset = cmd.p1;
- landing_point.alt += approach_alt_offset * 100;
- } else {
- approach_alt_offset = 0.0f;
- }
- }
- void AP_Landing_Deepstall::verify_abort_landing(const Location &prev_WP_loc, Location &next_WP_loc, bool &throttle_suppressed)
- {
-
-
- throttle_suppressed = false;
- landing.nav_controller->update_heading_hold(prev_WP_loc.get_bearing_to(next_WP_loc));
- }
- bool AP_Landing_Deepstall::verify_land(const Location &prev_WP_loc, Location &next_WP_loc, const Location ¤t_loc,
- const float height, const float sink_rate, const float wp_proportion, const uint32_t last_flying_ms,
- const bool is_armed, const bool is_flying, const bool rangefinder_state_in_range)
- {
- switch (stage) {
- case DEEPSTALL_STAGE_FLY_TO_LANDING:
- if (current_loc.get_distance(landing_point) > abs(2 * landing.aparm.loiter_radius)) {
- landing.nav_controller->update_waypoint(current_loc, landing_point);
- return false;
- }
- stage = DEEPSTALL_STAGE_ESTIMATE_WIND;
- loiter_sum_cd = 0;
- FALLTHROUGH;
- case DEEPSTALL_STAGE_ESTIMATE_WIND:
- {
- landing.nav_controller->update_loiter(landing_point, landing.aparm.loiter_radius, landing_point.loiter_ccw ? -1 : 1);
- if (!landing.nav_controller->reached_loiter_target() || (fabsf(height - approach_alt_offset) > DEEPSTALL_LOITER_ALT_TOLERANCE)) {
-
- return false;
- }
-
- int32_t target_bearing = landing.nav_controller->target_bearing_cd();
- int32_t delta = wrap_180_cd(target_bearing - last_target_bearing);
- delta *= (landing_point.loiter_ccw ? -1 : 1);
- if (delta > 0) {
- loiter_sum_cd += delta;
- }
- last_target_bearing = target_bearing;
- if (loiter_sum_cd < 36000) {
-
- return false;
- }
- stage = DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT;
- loiter_sum_cd = 0;
- FALLTHROUGH;
- }
- case DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT:
-
-
-
-
- if (loiter_sum_cd < 36000) {
- build_approach_path(false);
- }
- if (!verify_breakout(current_loc, arc_entry, height - approach_alt_offset)) {
- int32_t target_bearing = landing.nav_controller->target_bearing_cd();
- int32_t delta = wrap_180_cd(target_bearing - last_target_bearing);
- if (delta > 0) {
- loiter_sum_cd += delta;
- }
- last_target_bearing = target_bearing;
- landing.nav_controller->update_loiter(landing_point, landing.aparm.loiter_radius, landing_point.loiter_ccw ? -1 : 1);
- return false;
- }
- stage = DEEPSTALL_STAGE_FLY_TO_ARC;
- memcpy(&breakout_location, ¤t_loc, sizeof(Location));
- FALLTHROUGH;
- case DEEPSTALL_STAGE_FLY_TO_ARC:
- if (current_loc.get_distance(arc_entry) > 2 * landing.aparm.loiter_radius) {
- landing.nav_controller->update_waypoint(breakout_location, arc_entry);
- return false;
- }
- stage = DEEPSTALL_STAGE_ARC;
- FALLTHROUGH;
- case DEEPSTALL_STAGE_ARC:
- {
- Vector2f groundspeed = landing.ahrs.groundspeed_vector();
- if (!landing.nav_controller->reached_loiter_target() ||
- (fabsf(wrap_180(target_heading_deg -
- degrees(atan2f(-groundspeed.y, -groundspeed.x) + M_PI))) >= 10.0f)) {
- landing.nav_controller->update_loiter(arc, landing.aparm.loiter_radius, landing_point.loiter_ccw ? -1 : 1);
- return false;
- }
- stage = DEEPSTALL_STAGE_APPROACH;
- }
- FALLTHROUGH;
- case DEEPSTALL_STAGE_APPROACH:
- {
- Location entry_point;
- landing.nav_controller->update_waypoint(arc_exit, extended_approach);
- float height_above_target;
- if (is_zero(approach_alt_offset)) {
- landing.ahrs.get_relative_position_D_home(height_above_target);
- height_above_target = -height_above_target;
- } else {
- Location position;
- if (landing.ahrs.get_position(position)) {
- height_above_target = (position.alt - landing_point.alt + approach_alt_offset * 100) * 1e-2f;
- } else {
- height_above_target = approach_alt_offset;
- }
- }
- const float travel_distance = predict_travel_distance(landing.ahrs.wind_estimate(), height_above_target, false);
- memcpy(&entry_point, &landing_point, sizeof(Location));
- entry_point.offset_bearing(target_heading_deg + 180.0, travel_distance);
- if (!current_loc.past_interval_finish_line(arc_exit, entry_point)) {
- if (current_loc.past_interval_finish_line(arc_exit, extended_approach)) {
-
- stage = DEEPSTALL_STAGE_FLY_TO_LANDING;
- }
- return false;
- }
- predict_travel_distance(landing.ahrs.wind_estimate(), height_above_target, true);
- stage = DEEPSTALL_STAGE_LAND;
- stall_entry_time = AP_HAL::millis();
- const SRV_Channel* elevator = SRV_Channels::get_channel_for(SRV_Channel::k_elevator);
- if (elevator != nullptr) {
-
-
-
- initial_elevator_pwm = elevator->get_output_pwm();
- }
- }
- FALLTHROUGH;
- case DEEPSTALL_STAGE_LAND:
-
- landing.nav_controller->update_waypoint(current_loc, extended_approach);
- landing.disarm_if_autoland_complete_fn();
- return false;
- default:
- return true;
- }
- }
- bool AP_Landing_Deepstall::override_servos(void)
- {
- if (stage != DEEPSTALL_STAGE_LAND) {
- return false;
- }
- SRV_Channel* elevator = SRV_Channels::get_channel_for(SRV_Channel::k_elevator);
- if (elevator == nullptr) {
-
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Deepstall: Unable to find the elevator channels");
- request_go_around();
- return false;
- }
-
- float slew_progress = 1.0f;
- if (slew_speed > 0) {
- slew_progress = (AP_HAL::millis() - stall_entry_time) / (100.0f * slew_speed);
- }
-
- elevator->set_output_pwm(linear_interpolate(initial_elevator_pwm, elevator_pwm,
- slew_progress, 0.0f, 1.0f));
-
- float airspeed;
- if (!landing.ahrs.airspeed_estimate(&airspeed)) {
- airspeed = 0;
- }
-
- if (slew_progress >= 1.0f || airspeed <= handoff_airspeed) {
-
- float pid = update_steering();
- float travel_limit = constrain_float((handoff_airspeed - airspeed) /
- (handoff_airspeed - handoff_lower_limit_airspeed) *
- 0.5f + 0.5f,
- 0.5f, 1.0f);
- float output = constrain_float(pid, -travel_limit, travel_limit);
- SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, output*4500*aileron_scalar);
- SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, output*4500);
- SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, 0);
-
- }
-
- return true;
- }
- bool AP_Landing_Deepstall::request_go_around(void)
- {
- float current_altitude_d;
- landing.ahrs.get_relative_position_D_home(current_altitude_d);
- if (is_zero(min_abort_alt) || -current_altitude_d > min_abort_alt) {
- landing.flags.commanded_go_around = true;
- return true;
- } else {
- return false;
- }
- }
- bool AP_Landing_Deepstall::is_throttle_suppressed(void) const
- {
- return stage == DEEPSTALL_STAGE_LAND;
- }
- bool AP_Landing_Deepstall::is_flying_forward(void) const
- {
- return stage != DEEPSTALL_STAGE_LAND;
- }
- bool AP_Landing_Deepstall::is_on_approach(void) const
- {
- return stage == DEEPSTALL_STAGE_LAND;
- }
- bool AP_Landing_Deepstall::get_target_altitude_location(Location &location)
- {
- memcpy(&location, &landing_point, sizeof(Location));
- return true;
- }
- int32_t AP_Landing_Deepstall::get_target_airspeed_cm(void) const
- {
- if (stage == DEEPSTALL_STAGE_APPROACH ||
- stage == DEEPSTALL_STAGE_LAND) {
- return landing.pre_flare_airspeed * 100;
- } else {
- return landing.aparm.airspeed_cruise_cm;
- }
- }
- bool AP_Landing_Deepstall::send_deepstall_message(mavlink_channel_t chan) const
- {
- CHECK_PAYLOAD_SIZE2(DEEPSTALL);
- mavlink_msg_deepstall_send(
- chan,
- landing_point.lat,
- landing_point.lng,
- stage >= DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT ? arc_exit.lat : 0.0f,
- stage >= DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT ? arc_exit.lng : 0.0f,
- stage >= DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT ? arc_entry.lat : 0.0f,
- stage >= DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT ? arc_entry.lng : 0.0f,
- landing_point.alt * 0.01,
- stage >= DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT ? predicted_travel_distance : 0.0f,
- stage == DEEPSTALL_STAGE_LAND ? crosstrack_error : 0.0f,
- stage);
- return true;
- }
- const AP_Logger::PID_Info& AP_Landing_Deepstall::get_pid_info(void) const
- {
- return ds_PID.get_pid_info();
- }
- void AP_Landing_Deepstall::Log(void) const {
- const AP_Logger::PID_Info& pid_info = ds_PID.get_pid_info();
- struct log_DSTL pkt = {
- LOG_PACKET_HEADER_INIT(LOG_DSTL_MSG),
- time_us : AP_HAL::micros64(),
- stage : (uint8_t)stage,
- target_heading : target_heading_deg,
- target_lat : landing_point.lat,
- target_lng : landing_point.lng,
- target_alt : landing_point.alt,
- crosstrack_error : (int16_t)(stage >= DEEPSTALL_STAGE_LAND ?
- constrain_float(crosstrack_error * 1e2f, (float)INT16_MIN, (float)INT16_MAX) : 0),
- travel_distance : (int16_t)(stage >= DEEPSTALL_STAGE_LAND ?
- constrain_float(predicted_travel_distance * 1e2f, (float)INT16_MIN, (float)INT16_MAX) : 0),
- l1_i : stage >= DEEPSTALL_STAGE_LAND ? L1_xtrack_i : 0.0f,
- loiter_sum_cd : stage >= DEEPSTALL_STAGE_ESTIMATE_WIND ? loiter_sum_cd : 0,
- desired : pid_info.target,
- P : pid_info.P,
- I : pid_info.I,
- D : pid_info.D,
- };
- AP::logger().WriteBlock(&pkt, sizeof(pkt));
- }
- bool AP_Landing_Deepstall::terminate(void) {
-
- if(!landing.flags.in_progress || stage != DEEPSTALL_STAGE_LAND) {
- stall_entry_time = AP_HAL::millis();
- ds_PID.reset();
- L1_xtrack_i = 0.0f;
- landing.flags.in_progress = true;
- stage = DEEPSTALL_STAGE_LAND;
- if(landing.ahrs.get_position(landing_point)) {
- build_approach_path(true);
- } else {
- hold_level = true;
- }
- }
-
- return override_servos();
- }
- void AP_Landing_Deepstall::build_approach_path(bool use_current_heading)
- {
- float loiter_radius = landing.nav_controller->loiter_radius(landing.aparm.loiter_radius);
- Vector3f wind = landing.ahrs.wind_estimate();
-
- target_heading_deg = use_current_heading ? landing.ahrs.yaw_sensor * 1e-2 : (degrees(atan2f(-wind.y, -wind.x)));
- memcpy(&extended_approach, &landing_point, sizeof(Location));
- memcpy(&arc_exit, &landing_point, sizeof(Location));
-
- extended_approach.offset_bearing(target_heading_deg, 1000.0);
- float expected_travel_distance = predict_travel_distance(wind, is_zero(approach_alt_offset) ? landing_point.alt * 0.01f : approach_alt_offset,
- false);
- float approach_extension_m = expected_travel_distance + approach_extension;
- float loiter_radius_m_abs = fabsf(loiter_radius);
-
-
- approach_extension_m = MAX(approach_extension_m, loiter_radius_m_abs * 0.5f);
- arc_exit.offset_bearing(target_heading_deg + 180, approach_extension_m);
- memcpy(&arc, &arc_exit, sizeof(Location));
- memcpy(&arc_entry, &arc_exit, sizeof(Location));
- float arc_heading_deg = target_heading_deg + (landing_point.loiter_ccw ? -90.0f : 90.0f);
- arc.offset_bearing(arc_heading_deg, loiter_radius_m_abs);
- arc_entry.offset_bearing(arc_heading_deg, loiter_radius_m_abs * 2);
- #ifdef DEBUG_PRINTS
-
- gcs().send_text(MAV_SEVERITY_INFO, "Arc: %3.8f %3.8f",
- (double)(arc.lat / 1e7),(double)( arc.lng / 1e7));
- gcs().send_text(MAV_SEVERITY_INFO, "Loiter en: %3.8f %3.8f",
- (double)(arc_entry.lat / 1e7), (double)(arc_entry.lng / 1e7));
- gcs().send_text(MAV_SEVERITY_INFO, "Loiter ex: %3.8f %3.8f",
- (double)(arc_exit.lat / 1e7), (double)(arc_exit.lng / 1e7));
- gcs().send_text(MAV_SEVERITY_INFO, "Extended: %3.8f %3.8f",
- (double)(extended_approach.lat / 1e7), (double)(extended_approach.lng / 1e7));
- gcs().send_text(MAV_SEVERITY_INFO, "Extended by: %f (%f)", (double)approach_extension_m,
- (double)expected_travel_distance);
- gcs().send_text(MAV_SEVERITY_INFO, "Target Heading: %3.1f", (double)target_heading_deg);
- #endif
- }
- float AP_Landing_Deepstall::predict_travel_distance(const Vector3f wind, const float height, const bool print)
- {
- bool reverse = false;
- float course = radians(target_heading_deg);
-
- float forward_speed_ms = MAX(forward_speed, 0.1f);
- Vector2f wind_vec(wind.x, wind.y);
- float wind_length = MAX(wind_vec.length(), 0.05f);
- Vector2f course_vec(cosf(course), sinf(course));
- float offset = course - atan2f(-wind.y, -wind.x);
-
- float stall_distance = slope_a * wind_length * cosf(offset) + slope_b;
- float theta = acosf(constrain_float((wind_vec * course_vec) / wind_length, -1.0f, 1.0f));
- if ((course_vec % wind_vec) > 0) {
- reverse = true;
- theta *= -1;
- }
- float cross_component = sinf(theta) * wind_length;
- float estimated_crab_angle = asinf(constrain_float(cross_component / forward_speed_ms, -1.0f, 1.0f));
- if (reverse) {
- estimated_crab_angle *= -1;
- }
- float estimated_forward = cosf(estimated_crab_angle) * forward_speed_ms + cosf(theta) * wind_length;
- if (is_positive(down_speed)) {
- predicted_travel_distance = (estimated_forward * height / down_speed) + stall_distance;
- } else {
-
-
- predicted_travel_distance = stall_distance;
- }
- if(print) {
-
- gcs().send_text(MAV_SEVERITY_INFO, "Deepstall: Entry: %0.1f (m) Travel: %0.1f (m)",
- (double)stall_distance, (double)predicted_travel_distance);
- }
- return predicted_travel_distance;
- }
- bool AP_Landing_Deepstall::verify_breakout(const Location ¤t_loc, const Location &target_loc,
- const float height_error) const
- {
- const Vector2f location_delta = current_loc.get_distance_NE(target_loc);
- const float heading_error = degrees(landing.ahrs.groundspeed_vector().angle(location_delta));
-
-
- if (heading_error <= 10.0 && fabsf(height_error) < DEEPSTALL_LOITER_ALT_TOLERANCE) {
-
- return true;
- }
- return false;
- }
- float AP_Landing_Deepstall::update_steering()
- {
- Location current_loc;
- if ((!landing.ahrs.get_position(current_loc) || !landing.ahrs.healthy()) && !hold_level) {
-
-
-
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Deepstall: Invalid data from AHRS. Holding level");
- hold_level = true;
- }
- float desired_change = 0.0f;
- if (!hold_level) {
- uint32_t time = AP_HAL::millis();
- float dt = constrain_float(time - last_time, (uint32_t)10UL, (uint32_t)200UL) * 1e-3;
- last_time = time;
- Vector2f ab = arc_exit.get_distance_NE(extended_approach);
- ab.normalize();
- const Vector2f a_air = arc_exit.get_distance_NE(current_loc);
- crosstrack_error = a_air % ab;
- float sine_nu1 = constrain_float(crosstrack_error / MAX(L1_period, 0.1f), -0.7071f, 0.7107f);
- float nu1 = asinf(sine_nu1);
- if (L1_i > 0) {
- L1_xtrack_i += nu1 * L1_i / dt;
- L1_xtrack_i = constrain_float(L1_xtrack_i, -0.5f, 0.5f);
- nu1 += L1_xtrack_i;
- }
- desired_change = wrap_PI(radians(target_heading_deg) + nu1 - landing.ahrs.yaw) / time_constant;
- }
- float yaw_rate = landing.ahrs.get_gyro().z;
- float yaw_rate_limit_rps = radians(yaw_rate_limit);
- float error = wrap_PI(constrain_float(desired_change, -yaw_rate_limit_rps, yaw_rate_limit_rps) - yaw_rate);
- #ifdef DEBUG_PRINTS
- gcs().send_text(MAV_SEVERITY_INFO, "x: %f e: %f r: %f d: %f",
- (double)crosstrack_error,
- (double)error,
- (double)degrees(yaw_rate),
- (double)current_loc.get_distance(landing_point));
- #endif
- return ds_PID.get_pid(error);
- }
|