/*************************************************************************** plane.c - Created by Peter Mauger 17/07/01 last modified 12/10/01 plane contains planestate object (contains all data on plane position, attitude and control surfaces), as well as the functions required to manipulate it. ***************************************************************************/ #include "plane.h" /******************** The following functions manipulate the positional settings of the plane */ /* Init_Plane_Position_State initialises the internal variables of the position * state part of the plane state * returns: an initialised planeposstatestate structure */ planeposstate Init_Plane_Position_State() { planeposstate planepos; wplist wps = Init_Wplist(); /* wps contains a dummy set of waypoints */ position init_pos = Init_Pos(); /* init_pos contains a dummy set of data */ int i; planepos.desired_turn = STRAIGHT; planepos.desired_altitude = LEVEL; planepos.waypoints = wps; planepos.altitude = 0; planepos.curr_pos = init_pos; planepos.curr_wp = init_pos; planepos.stored_pos = init_pos; planepos.curr_heading = 0; planepos.req_bearing = 0; planepos.stored_heading = 0; planepos.pitch = 0; planepos.bank_angle = 0; planepos.airspeed = 0; planepos.best_correction = 0; planepos.improve_count = 0; planepos.gps_mesg.complete = FALSE; planepos.gps_mesg.valid = FALSE; planepos.gps_mesg.mesg_length = 0; planepos.gps_mesg.mesg_ptr = 0; for(i=0;ia variable for passing the plane control state out; * returns: SERVOERROR if an error has occured in initialising the servo, * NOERROR otherwise */ error Init_Plane_Control_State(planectrlstate *pcs) { error error_type; ctrlsurface cs; pcs->rudder_state = STRAIGHT; error_type = Init_Ctrl_Surface(RUDDER, &cs); if(error_type == NOERROR) { pcs->rudder = cs; } else return error_type; error_type = Init_Ctrl_Surface(AILERON, &cs); if(error_type == NOERROR) { pcs->banking = cs; } else return error_type; error_type = Init_Ctrl_Surface(ELEVATOR, &cs); if(error_type == NOERROR) { pcs->elevator = cs; } else return error_type; error_type = Init_Ctrl_Surface(THROTTLE, &cs); if(error_type == NOERROR) { pcs->throttle = cs; } else return error_type; return NOERROR; } /* Init_Plane_State initialises the internal variables of the plane state structure * inputs: ps->the variable for passing the main plane state structure * returns: SERVOERROR if an error occured when initialising the servos, * NOERROR otherwise */ error Init_Plane_State(planestate *ps) { error error_type; planectrlstate pcs; planeposstate pps; ps->log.curr_error_num = 0; pps = Init_Plane_Position_State(); error_type = Init_Plane_Control_State(&pcs); if(error_type == NOERROR) { ps->position = pps; ps->control = pcs; return NOERROR; } else return error_type; } /******************** The following functions manipulate the positional settings of the plane */ /* Get_Desired_Turn returns the desired turn variable stored in the plane state * structure * inputs: plane->contains positional info * returns: the desired turn state of the plane (LEFT, RIGHT, STRAIGHT) */ turnstate Get_Desired_Turn(planestate plane) { return plane.position.desired_turn; } /* Set_Desired_Turn sets the desired turn variable stored in the plane state * structure. This variable determines which way the plane is trying to turn. * inputs: plane->contains positional info * turn->the direction of the turn (LEFT, RIGHT, STRAIGHT) */ void Set_Desired_Turn(planestate *plane, turnstate turn) { plane->position.desired_turn = turn; } /* Get_Desired_Altitude returns the desired altitude variable stored in the plane * state structure * inputs: plane->contains positional info * returns: the desired altitude state of the plane (HIGHER, LOWER, LEVEL) */ altitudestate Get_Desired_Altitude(planestate plane) { return plane.position.desired_altitude; } /* Set_Desired_Altitude sets the desired altitude variable stored in the plane * state structure. This variable determines whether the plane is trying to * rise, fall or remain level. * inputs: plane->contains positional info * turn->the altitude change required (HIGHER, LOWER, LEVEL) */ void Set_Desired_Altitude(planestate *plane, altitudestate altitude) { plane->position.desired_altitude = altitude; } /* Get_Wplist returns the list of waypoints stored in the plane state structure * inputs: plane->contains positional info * returns: the list of waypoints the plane is to travel to */ wplist Get_Wplist(planestate plane) { return plane.position.waypoints; } /* Store_Wplist stores a new set of waypoints in the plane state structure * inputs: plane->contains positional info * waypoints->list of waypoints */ void Store_Wplist(planestate *plane, wplist waypoints) { plane->position.waypoints = waypoints; } /* Get_Altitude retrieves the current altitude information of the plane * inputs: plane->contains positional info * returns: the altitude of the plane */ double Get_Altitude(planestate plane) { return plane.position.altitude; } /* Set_Altitude sets the current altitude variable information of the plane * inputs: plane->contains positional info * altitude->the current altitude of the plane */ void Set_Altitude(planestate *plane, double altitude) { plane->position.altitude = altitude; } /* Get_GPS_Message retrieves the message fragment stored in the plane structure * inputs: plane->contains the message fragment * returns: the current message fragment */ message Get_GPS_Message(planestate plane) { return plane.position.gps_mesg; } /* Set_GPS_Message updates the message fragment stored in the plane structure * inputs: plane->contains the old message fragment * mesg->the current message fragment */ void Set_GPS_Message(planestate *plane, message mesg) { plane->position.gps_mesg = mesg; } /* Get_Curr_Pos retrieves the current coordinate information of the plane * inputs: plane->contains positional info * returns: the current coordinates of the plane */ position Get_Curr_Pos(planestate plane) { return plane.position.curr_pos; } /* Set_Curr_Pos sets the current coordinate information of the plane * inputs: plane->contains positional info * pos->the current coordinates of the plane */ void Set_Curr_Pos(planestate *plane, position pos) { plane->position.curr_pos = pos; } /* Get_Curr_Wp retrieves the coordinates of the current waypoint the plane * is heading to. * inputs: plane->contains positional info * returns: the coordinates of the current waypoint */ position Get_Curr_Wp(planestate plane) { return plane.position.curr_wp; } /* Set_Curr_Wp establishes the next waypoint the plane is to fly to * inputs: plane->contains positional info * curr_wpnum->the number of the next waypoint * returns: INVALIDWPNUM if curr_wpnum out of range of list * NOERROR otherwise */ error Set_Curr_Wp(planestate *plane, int curr_wpnum) { position pos; error error_type; error_type = Get_Wp(plane->position.waypoints, curr_wpnum, &pos); if(error_type == NOERROR) { plane->position.curr_wp = pos; return NOERROR; } else return error_type; } /* Store_Old_Position stores the old position so that it can be retrieved later * (if an error occurs in getting the new position) * inputs: plane->contains positional info */ void Store_Old_Position(planestate *plane) { plane->position.stored_pos = plane->position.curr_pos; } /* Restore_Old_Position restores the previously known position of the plane in * the event that an error has ocurred in determining the new position * inputs: plane->contains positional info */ void Restore_Old_Position(planestate *plane) { plane->position.curr_pos = plane->position.stored_pos; } /* Get_Curr_Heading retrieves the current heading information of the plane * inputs: plane->contains positional info * returns: the currently known heading of the plane */ int Get_Curr_Heading(planestate plane) { return plane.position.curr_heading; } /* Set_Curr_Heading sets the current heading information of the plane * inputs: plane->contains positional info * heading->the current heading of the plane */ void Set_Curr_Heading(planestate *plane, int heading) { plane->position.curr_heading = heading; } /* Get_Req_Bearing retrieves the required bearing information of the plane * inputs: plane->contains positional info * returns: the currently required bearing of the plane */ double Get_Req_Bearing(planestate plane) { return plane.position.req_bearing; } /* Set_Req_Bearing sets the required bearing information of the plane * inputs: plane->contains positional info * heading->the currently required bearing of the plane */ void Set_Req_Bearing(planestate *plane, double bearing) { plane->position.req_bearing = bearing; } /* Store_Old_Heading stores the old heading so that it can be retrieved later * (if an error occurs in getting the new heading) * inputs: plane->contains positional info */ void Store_Old_Heading(planestate *plane) { plane->position.stored_heading = plane->position.curr_heading; } /* Restore_Old_Heading restores the previously known heading of the plane in * the event that an error has ocurred in determining the new heading * inputs: plane->contains positional info */ void Restore_Old_Heading(planestate *plane) { plane->position.curr_heading = plane->position.stored_heading; } /* Get_Pitch retrieves the pitch information of the plane * inputs: plane->contains positional info * returns: the pitch of the plane */ double Get_Pitch(planestate plane) { return plane.position.pitch; } /* Set_Pitch sets the pitch information of the plane * inputs: plane->contains positional info * pitch->the pitch of the plane */ void Set_Pitch(planestate *plane, double pitch) { plane->position.pitch = pitch; } /* Get_Bank_Angle retrieves the bank angle information of the plane * inputs: plane->contains positional info * returns: the bank angle of the plane */ double Get_Bank_Angle(planestate plane) { return plane.position.bank_angle; } /* Set_Bank_Angle sets the bank angle information of the plane * inputs: plane->contains positional info * bank_angle->the bank angle of the plane */ void Set_Bank_Angle(planestate *plane, double bank_angle) { plane->position.bank_angle = bank_angle; } /* Get_Airspeed retrieves the airspeed information of the plane * inputs: plane->contains positional info * returns: the airspeed of the plane */ double Get_Airspeed(planestate plane) { return plane.position.airspeed; } /* Set_Airspeed sets the airspeed information of the plane * inputs: plane->contains positional info * airspeed->the airspeed of the plane */ void Set_Airspeed(planestate *plane, double airspeed) { plane->position.airspeed = airspeed; } /* Get_Best_Correction retrieves the best correction information of the current * turn of the plane * inputs: plane->contains positional info * returns: the best correction of the current turn of the plane */ double Get_Best_Correction(planestate plane) { return plane.position.best_correction; } /* Set_Best_Correction sets the best correction information of the current turn * of the plane * inputs: plane->contains positional info * correction->the current correction required by the plane */ void Set_Best_Correction(planestate *plane, double correction) { plane->position.best_correction = correction; } /* Get_Improve_Count retrieves the number of times the plane has failed to improve * its heading * inputs: plane->contains positional info * returns: the bearing improvement count of the plane */ int Get_Improve_Count(planestate plane) { return plane.position.improve_count; } /* Set_Improve_count updates the improve count * inputs: plane->contains positional info * count->the current number of times the plane has failed to improve its bearing */ void Set_Improve_Count(planestate *plane, int count) { plane->position.improve_count = count; } /* Heading_Improvement determines whether the plane is making any improvement in heading * given the current turn direction * inputs: plane->plane information * curr_correction->the current correction the plane needs to make */ void Heading_Improvement(planestate *plane, double curr_correction) { if(Get_Desired_Turn(*plane)==RIGHT) /* The new corr must be > the best corr to improve */ { if(curr_correction <= plane->position.best_correction) { if(plane->position.best_correction > 170 && curr_correction < -170) /* In this case it is deemed */ { /* likely that the plane has */ plane->position.best_correction = curr_correction; /* just passed the 180 180->(-180) */ plane->position.improve_count = 0; /* boundary. Has improved. */ } else /* Otherwise the plane has not improved */ { plane->position.improve_count++; /* Increase count by 1 */ if(plane->position.improve_count >= 20) /* If no improvement for 20 cycles */ { /* then turn the other direction */ Turn_Left(plane); plane->position.improve_count = 0; /* reset improvement count for new turn */ } } } else /* Else the plane has improved */ { plane->position.best_correction = curr_correction; /* Update the best correction */ plane->position.improve_count = 0; /* Reset the improvement count */ } } if(Get_Desired_Turn(*plane)==LEFT) /* The new corr must be < the best corr to improve */ { if(curr_correction >= plane->position.best_correction) { if(plane->position.best_correction < -170 && curr_correction > 170) /* In this case it is deemed */ { /* likely that the plane has */ plane->position.best_correction = curr_correction; /* just passed the (-180)->180 */ plane->position.improve_count = 0; /* boundary. Has improved. */ } /* Assuming plane cant turn */ /* >340 degrees, in wrong */ /* direction, in 1 cycle :) */ else /* Otherwise the plane has not improved */ { plane->position.improve_count++; if(plane->position.improve_count >= 20) { Turn_Right(plane); plane->position.improve_count = 0; } } } else /* Else the plane has improved */ { plane->position.best_correction = curr_correction; /* Update the best correction */ plane->position.improve_count = 0; /* Reset the improvement count */ } } } /* Get_Log returns the error log so new messages can be added * inputs: plane->contains the error log * returns: errorlog of all errors to date */ errorlog Get_Log(planestate plane) { return plane.log; } /* Set_Log updates the messages in the error log with new messages * inputs: plane->contains the old log for overwriting * log->conatins the new set of error messages */ void Set_Log(planestate *plane, errorlog log) { plane->log = log; } /* Log_Event performs the procedure required to log an event * inputs: plane->contains old log and positional data * error_type->identifies the event that occured */ void Log_Event(planestate *plane, error event) { errorlog log; log = Get_Log(*plane); /* retrieve the log from the plane data structure */ /* update the log with the event, position, and heading */ Add_Event(&log, event, plane->position.curr_pos, plane->position.curr_wp, plane->position.curr_heading, plane->position.req_bearing); Set_Log(plane, log); /* store the new information in the plane data struct */ } /* Add_Event adds an event to the message log. Message is not added if capacity * has been reached. * inputs: log->contains the old error messages (will be added to) * tag->an identifier for the event (type error) * gps_pos->current position of the aircraft * wp_pos->position of current waypoint * heading->current heading of the aircraft * bearing->bearing required to reach current waypoint */ void Add_Event(errorlog *log, error tag, position gps_pos, position wp_pos, int heading, double bearing) { if(log->curr_error_num < MAX_ERROR_MESGS ) { log->tag[log->curr_error_num] = tag; log->gps_pos[log->curr_error_num] = gps_pos; log->wp_pos[log->curr_error_num] = wp_pos; log->heading[log->curr_error_num] = heading; log->bearing[log->curr_error_num] = bearing; log->curr_error_num++; } } /* Upload_Error_Log uploads the error log to a PC * inputs: plane->contains the log of all events that have occured * type->the grouping/order of the upload (chronological order or event grouping) * returns: SENDERROR if an error occured during the send (resend the data!) * NOERROR otherwise */ error Upload_Error_Log(planestate plane, upltype type) { char curr_mesg[MAX_LOG_SIZE]; char event[MAX_EVENT_LENGTH]; int mesg_ptr = 0; int i; int result = 0; errorlog temp_log; temp_log.curr_error_num = 0; if(type == TIME) { for(i=0;ithe event label * event_str->the string which defines the event */ void Convert_Tag2Event(error tag, char *event_str) { char *temp_event_str = NULL; switch(tag) { case NOERROR: temp_event_str = "noerror "; break; case SWITCHDETECT: temp_event_str = "switchnotdetected "; break; case SERVOERROR: temp_event_str = "servoerror "; break; case INITERROR: temp_event_str = "errorduringinitialisation"; break; case IDERROR: temp_event_str = "servoidincorrect "; break; case INVALIDSERVO: temp_event_str = "servohandleincorrect "; break; case LIMITERROR: temp_event_str = "servoangleoutofrange "; break; case LIMITCROSS: temp_event_str = "minlimit>maxlimit "; break; case ABSOLUTELIMITERROR: temp_event_str = "limitsetoutsideabsolute "; break; case COMPASSERROR: temp_event_str = "compassiniterror "; break; case COMPASSHEADINGERROR: temp_event_str = "headingerror "; break; case NOHEADING: temp_event_str = "noheading "; break; case GPSERROR: temp_event_str = "GPSiniterror "; break; case GPSPOSERROR: temp_event_str = "GPSpositionerror "; break; case MESGTOOLONG: temp_event_str = "GPSmesgtoolong "; break; case NOPOSITION: temp_event_str = "noposition "; break; case NOWPS: temp_event_str = "nowaypoints "; break; case INVALIDWPNUM: temp_event_str = "waypointnumoutofrange "; break; case WPFILEERROR: temp_event_str = "waypointfileerror "; break; case DIVZERO: temp_event_str = "dividebyzero "; break; case NEGVAL: temp_event_str = "-vevalue(shouldbe+ve) "; break; case COMMERROR: temp_event_str = "communicationserror "; break; case SENDERROR: temp_event_str = "sendingerror "; break; case SWITCHMANUAL: temp_event_str = "manualswitch "; break; case SWITCHAUTO: temp_event_str = "autopilotswitch "; break; case LOGPOSITION: temp_event_str = "log "; break; case ATWP: temp_event_str = "waypointreached "; break; case FLIGHTCOMPLETE: temp_event_str = "flightcompleted "; break; default: temp_event_str = "unknownerror "; } strncpy(event_str, temp_event_str, MAX_EVENT_LENGTH); } /******************** The following functions update the servo states and settings of the plane */ /* Get_Ctrl_Surface returns the relevant control surface information from the * plane control struct * inputs: plane->contains the control information * ctrl_surface_name->the label of the control surface that is to be returned * ctrl_surface->the control surface being returned * returns: INVALIDSERVO if the servo label is out of range * NOERROR otherwise */ error Get_Ctrl_Surface(planestate plane, servoconsts ctrl_surface_name, ctrlsurface *ctrl_surface) { if(ctrl_surface_name == RUDDER) { *ctrl_surface = plane.control.rudder; return NOERROR; } else if(ctrl_surface_name == AILERON) { *ctrl_surface = plane.control.banking; return NOERROR; } else if(ctrl_surface_name == ELEVATOR) { *ctrl_surface = plane.control.elevator; return NOERROR; } else if(ctrl_surface_name == THROTTLE) { *ctrl_surface = plane.control.throttle; return NOERROR; } else return INVALIDSERVO; } /* Set_Ctrl_Surface stores new control surface information for the surface * inputs: plane->contains the control information * ctrl_surface->the control surface to be updated * ctrl_surface_name->the name of the ctrl_surface to be updated * returns: INVALIDSERVO if the servo label is out of range * NOERROR otherwise */ error Set_Ctrl_Surface(planestate *plane, ctrlsurface ctrl_surface, servoconsts ctrl_surface_name) { if(ctrl_surface_name == RUDDER) { plane->control.rudder = ctrl_surface; return NOERROR; } else if(ctrl_surface_name == AILERON) { plane->control.banking = ctrl_surface; return NOERROR; } else if(ctrl_surface_name == ELEVATOR) { plane->control.elevator = ctrl_surface; return NOERROR; } else if(ctrl_surface_name == THROTTLE) { plane->control.throttle = ctrl_surface; return NOERROR; } else return INVALIDSERVO; } /* Get_Rudder_State retrieves the current state of the rudder * inputs: plane->contains the control information * returns: the turn state of the rudder (LEFT, RIGHT, STRAIGHT); */ turnstate Get_Rudder_State(planestate plane) { return plane.control.rudder_state; } /* Set_Rudder_State sets the current state of the rudder * inputs: plane->contains control information * rudder->the turn state required of the rudder */ void Set_Rudder_State(planestate *plane, turnstate rudder) { plane->control.rudder_state = rudder; } /* This function will change the servos to reflect the current states in the * plane control structure. If any new surfaces are required then this function * must be updated. * inputs: plane->plane structure containing the required servo settings * returns: error occured or not (SERVOERROR if failed, NOERROR otherwise) */ error Update_Servos(planestate *plane) { error error_type; error_type = Move_Ctrl_Surface_Servo(plane->control.rudder); return error_type; }