bool MissionFeasibilityChecker::checkMissionFeasible(int mavlink_fd, bool isRotarywing,
	dm_item_t dm_current, size_t nMissionItems, Geofence &geofence,
	float home_alt, bool home_valid, double curr_lat, double curr_lon, float max_waypoint_distance, bool &warning_issued,
	float default_acceptance_rad,
	bool condition_landed)
{
	bool failed = false;
	bool warned = false;
	/* Init if not done yet */
	init();

	_mavlink_fd = mavlink_fd;

	// first check if we have a valid position
	if (!home_valid /* can later use global / local pos for finer granularity */) {
		failed = true;
		warned = true;
		mavlink_log_info(_mavlink_fd, "Not yet ready for mission, no position lock.");
	} else {
		failed = failed || !check_dist_1wp(dm_current, nMissionItems, curr_lat, curr_lon, max_waypoint_distance, warning_issued);
	}

	// check if all mission item commands are supported
	failed = failed || !checkMissionItemValidity(dm_current, nMissionItems, condition_landed);
	failed = failed || !checkGeofence(dm_current, nMissionItems, geofence);
	failed = failed || !checkHomePositionAltitude(dm_current, nMissionItems, home_alt, home_valid, warned);

	if (isRotarywing) {
		failed = failed || !checkMissionFeasibleRotarywing(dm_current, nMissionItems, geofence, home_alt, home_valid, default_acceptance_rad);
	} else {
		failed = failed || !checkMissionFeasibleFixedwing(dm_current, nMissionItems, geofence, home_alt, home_valid);
	}

	return !failed;
}
Example #2
0
void
Mission::set_mission_items()
{
    /* make sure param is up to date */
    updateParams();

    /* reset the altitude foh logic, if altitude foh is enabled (param) a new foh element starts now */
    altitude_sp_foh_reset();

    struct position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();

    /* set previous position setpoint to current */
    set_previous_pos_setpoint();

    /* Copy previous mission item altitude (can be extended to a copy of the full mission item if needed) */
    if (pos_sp_triplet->previous.valid) {
        _mission_item_previous_alt = get_absolute_altitude_for_item(_mission_item);
    }

    /* get home distance state */
    bool home_dist_ok = check_dist_1wp();
    /* the home dist check provides user feedback, so we initialize it to this */
    bool user_feedback_done = !home_dist_ok;

    /* try setting onboard mission item */
    if (_param_onboard_enabled.get() && read_mission_item(true, true, &_mission_item)) {
        /* if mission type changed, notify */
        if (_mission_type != MISSION_TYPE_ONBOARD) {
            mavlink_log_critical(_navigator->get_mavlink_fd(), "onboard mission now running");
        }
        _mission_type = MISSION_TYPE_ONBOARD;

        /* try setting offboard mission item */
    } else if (home_dist_ok && read_mission_item(false, true, &_mission_item)) {
        /* if mission type changed, notify */
        if (_mission_type != MISSION_TYPE_OFFBOARD) {
            mavlink_log_info(_navigator->get_mavlink_fd(), "offboard mission now running");
        }
        _mission_type = MISSION_TYPE_OFFBOARD;
    } else {
        /* no mission available or mission finished, switch to loiter */
        if (_mission_type != MISSION_TYPE_NONE) {
            /* https://en.wikipedia.org/wiki/Loiter_(aeronautics) */
            mavlink_log_critical(_navigator->get_mavlink_fd(), "mission finished, loitering");

            /* use last setpoint for loiter */
            _navigator->set_can_loiter_at_sp(true);

        } else if (!user_feedback_done) {
            /* only tell users that we got no mission if there has not been any
             * better, more specific feedback yet
             * https://en.wikipedia.org/wiki/Loiter_(aeronautics)
             */
            mavlink_log_critical(_navigator->get_mavlink_fd(), "no valid mission available, loitering");
        }
        _mission_type = MISSION_TYPE_NONE;

        /* set loiter mission item */
        set_loiter_item(&_mission_item);

        /* update position setpoint triplet  */
        pos_sp_triplet->previous.valid = false;
        mission_item_to_position_setpoint(&_mission_item, &pos_sp_triplet->current);
        pos_sp_triplet->next.valid = false;

        /* reuse setpoint for LOITER only if it's not IDLE */
        _navigator->set_can_loiter_at_sp(pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_LOITER);

        set_mission_finished();

        _navigator->set_position_setpoint_triplet_updated();
        return;
    }

    if (pos_sp_triplet->current.valid) {
        _on_arrival_yaw = _mission_item.yaw;
    }

    /* do takeoff on first waypoint for rotary wing vehicles */
    if (_navigator->get_vstatus()->is_rotary_wing) {
        /* force takeoff if landed (additional protection) */
        if (!_takeoff && _navigator->get_vstatus()->condition_landed) {
            _need_takeoff = true;
        }

        /* new current mission item set, check if we need takeoff */
        if (_need_takeoff && (
                    _mission_item.nav_cmd == NAV_CMD_TAKEOFF ||
                    _mission_item.nav_cmd == NAV_CMD_WAYPOINT ||
                    _mission_item.nav_cmd == NAV_CMD_LOITER_TIME_LIMIT ||
                    _mission_item.nav_cmd == NAV_CMD_LOITER_TURN_COUNT ||
                    _mission_item.nav_cmd == NAV_CMD_LOITER_UNLIMITED ||
                    _mission_item.nav_cmd == NAV_CMD_RETURN_TO_LAUNCH)) {
            _takeoff = true;
            _need_takeoff = false;
        }
    }

    if (_takeoff) {
        /* do takeoff before going to setpoint */
        /* set mission item as next position setpoint */
        mission_item_to_position_setpoint(&_mission_item, &pos_sp_triplet->next);

        /* calculate takeoff altitude */
        float takeoff_alt = get_absolute_altitude_for_item(_mission_item);

        /* takeoff to at least NAV_TAKEOFF_ALT above home/ground, even if first waypoint is lower */
        if (_navigator->get_vstatus()->condition_landed) {
            takeoff_alt = fmaxf(takeoff_alt, _navigator->get_global_position()->alt + _param_takeoff_alt.get());

        } else {
            takeoff_alt = fmaxf(takeoff_alt, _navigator->get_home_position()->alt + _param_takeoff_alt.get());
        }

        /* check if we already above takeoff altitude */
        if (_navigator->get_global_position()->alt < takeoff_alt) {
            mavlink_log_critical(_navigator->get_mavlink_fd(), "takeoff to %.1f meters above home", (double)(takeoff_alt - _navigator->get_home_position()->alt));

            _mission_item.nav_cmd = NAV_CMD_TAKEOFF;
            _mission_item.lat = _navigator->get_global_position()->lat;
            _mission_item.lon = _navigator->get_global_position()->lon;
            _mission_item.yaw = NAN;
            _mission_item.altitude = takeoff_alt;
            _mission_item.altitude_is_relative = false;
            _mission_item.autocontinue = true;
            _mission_item.time_inside = 0;

            mission_item_to_position_setpoint(&_mission_item, &pos_sp_triplet->current);

            _navigator->set_position_setpoint_triplet_updated();
            return;

        } else {
            /* skip takeoff */
            _takeoff = false;
        }
    }

    /* set current position setpoint from mission item */
    mission_item_to_position_setpoint(&_mission_item, &pos_sp_triplet->current);

    /* require takeoff after landing or idle */
    if (pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_LAND || pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_IDLE) {
        _need_takeoff = true;
    }

    _navigator->set_can_loiter_at_sp(false);
    reset_mission_item_reached();

    if (_mission_type == MISSION_TYPE_OFFBOARD) {
        set_current_offboard_mission_item();
    }
    // TODO: report onboard mission item somehow

    if (_mission_item.autocontinue && _mission_item.time_inside <= 0.001f) {
        /* try to read next mission item */
        struct mission_item_s mission_item_next;

        if (read_mission_item(_mission_type == MISSION_TYPE_ONBOARD, false, &mission_item_next)) {
            /* got next mission item, update setpoint triplet */
            mission_item_to_position_setpoint(&mission_item_next, &pos_sp_triplet->next);
        } else {
            /* next mission item is not available */
            pos_sp_triplet->next.valid = false;
        }

    } else {
        /* vehicle will be paused on current waypoint, don't set next item */
        pos_sp_triplet->next.valid = false;
    }

    /* Save the distance between the current sp and the previous one */
    if (pos_sp_triplet->current.valid && pos_sp_triplet->previous.valid) {
        _distance_current_previous = get_distance_to_next_waypoint(pos_sp_triplet->current.lat,
                                     pos_sp_triplet->current.lon,
                                     pos_sp_triplet->previous.lat,
                                     pos_sp_triplet->previous.lon);
    }

    _navigator->set_position_setpoint_triplet_updated();
}