// verify_circle - check if we have circled the point enough bool Copter::verify_circle(const AP_Mission::Mission_Command& cmd) { // check if we've reached the edge if (auto_mode == Auto_CircleMoveToEdge) { if (wp_nav.reached_wp_destination()) { Vector3f curr_pos = inertial_nav.get_position(); Vector3f circle_center = pv_location_to_vector(cmd.content.location); // set target altitude if not provided if (is_zero(circle_center.z)) { circle_center.z = curr_pos.z; } // set lat/lon position if not provided if (cmd.content.location.lat == 0 && cmd.content.location.lng == 0) { circle_center.x = curr_pos.x; circle_center.y = curr_pos.y; } // start circling auto_circle_start(); } return false; } // check if we have completed circling return fabsf(circle_nav.get_angle_total()/M_2PI) >= LOWBYTE(cmd.p1); }
// 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(); } }
// do_circle - initiate moving in a circle void Copter::do_circle(const AP_Mission::Mission_Command& cmd) { Vector3f curr_pos = inertial_nav.get_position(); Vector3f circle_center = pv_location_to_vector(cmd.content.location); uint8_t circle_radius_m = HIGHBYTE(cmd.p1); // circle radius held in high byte of p1 bool move_to_edge_required = false; // set target altitude if not provided if (cmd.content.location.alt == 0) { circle_center.z = curr_pos.z; } else { move_to_edge_required = true; } // set lat/lon position if not provided // To-Do: use previous command's destination if it was a straight line or spline waypoint command if (cmd.content.location.lat == 0 && cmd.content.location.lng == 0) { circle_center.x = curr_pos.x; circle_center.y = curr_pos.y; } else { move_to_edge_required = true; } // set circle controller's center circle_nav.set_center(circle_center); // set circle radius if (circle_radius_m != 0) { circle_nav.set_radius((float)circle_radius_m * 100.0f); } // check if we need to move to edge of circle if (move_to_edge_required) { // move to edge of circle (verify_circle) will ensure we begin circling once we reach the edge auto_circle_movetoedge_start(); } else { // start circling auto_circle_start(); } }