// auto_circle_movetoedge_start - initialise waypoint controller to move to edge of a circle with it's center at the specified location // we assume the caller has performed all required GPS_ok checks void Copter::auto_circle_movetoedge_start(const Location_Class &circle_center, float radius_m) { // convert location to vector from ekf origin Vector3f circle_center_neu; if (!circle_center.get_vector_from_origin_NEU(circle_center_neu)) { // default to current position and log error circle_center_neu = inertial_nav.get_position(); Log_Write_Error(ERROR_SUBSYSTEM_NAVIGATION, ERROR_CODE_FAILED_CIRCLE_INIT); } circle_nav.set_center(circle_center_neu); // set circle radius if (!is_zero(radius_m)) { circle_nav.set_radius(radius_m * 100.0f); } // check our distance from edge of circle Vector3f circle_edge_neu; circle_nav.get_closest_point_on_circle(circle_edge_neu); float dist_to_edge = (inertial_nav.get_position() - circle_edge_neu).length(); // if more than 3m then fly to edge if (dist_to_edge > 300.0f) { // set the state to move to the edge of the circle auto_mode = Auto_CircleMoveToEdge; // convert circle_edge_neu to Location_Class Location_Class circle_edge(circle_edge_neu); // convert altitude to same as command circle_edge.set_alt_cm(circle_center.alt, circle_center.get_alt_frame()); // initialise wpnav to move to edge of circle if (!wp_nav.set_wp_destination(circle_edge)) { // failure to set destination can only be because of missing terrain data failsafe_terrain_on_event(); } // if we are outside the circle, point at the edge, otherwise hold yaw const Vector3f &curr_pos = inertial_nav.get_position(); float dist_to_center = norm(circle_center_neu.x - curr_pos.x, circle_center_neu.y - curr_pos.y); if (dist_to_center > circle_nav.get_radius() && dist_to_center > 500) { set_auto_yaw_mode(get_default_auto_yaw_mode(false)); } else { // vehicle is within circle so hold yaw to avoid spinning as we move to edge of circle set_auto_yaw_mode(AUTO_YAW_HOLD); } } else { auto_circle_start(); } }
// auto_wp_start - initialises waypoint controller to implement flying to a particular destination void Copter::auto_wp_start(const Location_Class& dest_loc) { auto_mode = Auto_WP; // send target to waypoint controller if (!wp_nav.set_wp_destination(dest_loc)) { // failure to set destination can only be because of missing terrain data failsafe_terrain_on_event(); } // initialise yaw // To-Do: reset the yaw only when the previous navigation command is not a WP. this would allow removing the special check for ROI if (auto_yaw_mode != AUTO_YAW_ROI) { set_auto_yaw_mode(get_default_auto_yaw_mode(false)); } }
// executes terrain failsafe if data is missing for longer than a few seconds // missing_data should be set to true if the vehicle failed to navigate because of missing data, false if navigation is proceeding successfully void Copter::failsafe_terrain_check() { // trigger with 5 seconds of failures while in AUTO mode bool valid_mode = (control_mode == AUTO || control_mode == GUIDED || control_mode == GUIDED_NOGPS || control_mode == RTL); bool timeout = (failsafe.terrain_last_failure_ms - failsafe.terrain_first_failure_ms) > FS_TERRAIN_TIMEOUT_MS; bool trigger_event = valid_mode && timeout; // check for clearing of event if (trigger_event != failsafe.terrain) { if (trigger_event) { failsafe_terrain_on_event(); } else { Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_TERRAIN, ERROR_CODE_ERROR_RESOLVED); failsafe.terrain = false; } } }
// auto_takeoff_start - initialises waypoint controller to implement take-off void Copter::auto_takeoff_start(const Location& dest_loc) { auto_mode = Auto_TakeOff; // convert location to class Location_Class dest(dest_loc); // set horizontal target dest.lat = current_loc.lat; dest.lng = current_loc.lng; // get altitude target int32_t alt_target; if (!dest.get_alt_cm(Location_Class::ALT_FRAME_ABOVE_HOME, alt_target)) { // this failure could only happen if take-off alt was specified as an alt-above terrain and we have no terrain data Log_Write_Error(ERROR_SUBSYSTEM_TERRAIN, ERROR_CODE_MISSING_TERRAIN_DATA); // fall back to altitude above current altitude alt_target = current_loc.alt + dest.alt; } // sanity check target if (alt_target < current_loc.alt) { dest.set_alt_cm(current_loc.alt, Location_Class::ALT_FRAME_ABOVE_HOME); } // Note: if taking off from below home this could cause a climb to an unexpectedly high altitude if (alt_target < 100) { dest.set_alt_cm(100, Location_Class::ALT_FRAME_ABOVE_HOME); } // set waypoint controller target if (!wp_nav.set_wp_destination(dest)) { // failure to set destination can only be because of missing terrain data failsafe_terrain_on_event(); return; } // initialise yaw set_auto_yaw_mode(AUTO_YAW_HOLD); // clear i term when we're taking off set_throttle_takeoff(); // get initial alt for TKOFF_NAV_ALT auto_takeoff_set_start_alt(); }
// executes terrain failsafe if data is missing for longer than a few seconds // missing_data should be set to true if the vehicle failed to navigate because of missing data, false if navigation is proceeding successfully void Sub::failsafe_terrain_check() { // trigger with 5 seconds of failures while in AUTO mode bool valid_mode = (control_mode == AUTO || control_mode == GUIDED); bool timeout = (failsafe.terrain_last_failure_ms - failsafe.terrain_first_failure_ms) > FS_TERRAIN_TIMEOUT_MS; bool trigger_event = valid_mode && timeout; // check for clearing of event if (trigger_event != failsafe.terrain) { if (trigger_event) { gcs().send_text(MAV_SEVERITY_CRITICAL,"Failsafe terrain triggered"); failsafe_terrain_on_event(); } else { Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_TERRAIN, ERROR_CODE_ERROR_RESOLVED); failsafe.terrain = false; } } }
// auto_spline_start - initialises waypoint controller to implement flying to a particular destination using the spline controller // seg_end_type can be SEGMENT_END_STOP, SEGMENT_END_STRAIGHT or SEGMENT_END_SPLINE. If Straight or Spline the next_destination should be provided void Copter::auto_spline_start(const Location_Class& destination, bool stopped_at_start, AC_WPNav::spline_segment_end_type seg_end_type, const Location_Class& next_destination) { auto_mode = Auto_Spline; // initialise wpnav if (!wp_nav.set_spline_destination(destination, stopped_at_start, seg_end_type, next_destination)) { // failure to set destination can only be because of missing terrain data failsafe_terrain_on_event(); return; } // initialise yaw // To-Do: reset the yaw only when the previous navigation command is not a WP. this would allow removing the special check for ROI if (auto_yaw_mode != AUTO_YAW_ROI) { set_auto_yaw_mode(get_default_auto_yaw_mode(false)); } }