void rotate_vector_by_axis_angle(fixedpointnum *v1, fixedpointnum *axisvector, fixedpointnum angle, fixedpointnum *v2) { fixedpointnum cosineofangle=lib_fp_cosine(angle); fixedpointnum sineofangle=lib_fp_sine(angle); fixedpointnum crossproductvector[3]; vector_cross_product(axisvector,v1, crossproductvector); fixedpointnum dotproducttimesoneminuscosineofangle=lib_fp_multiply(vector_dot_product(axisvector,v1),FIXEDPOINTONE-cosineofangle); v2[0]=lib_fp_multiply(v1[0], cosineofangle)+lib_fp_multiply(crossproductvector[0],sineofangle)+lib_fp_multiply(axisvector[0],dotproducttimesoneminuscosineofangle); v2[1]=lib_fp_multiply(v1[1], cosineofangle)+lib_fp_multiply(crossproductvector[1],sineofangle)+lib_fp_multiply(axisvector[1],dotproducttimesoneminuscosineofangle); v2[2]=lib_fp_multiply(v1[2], cosineofangle)+lib_fp_multiply(crossproductvector[2],sineofangle)+lib_fp_multiply(axisvector[2],dotproducttimesoneminuscosineofangle); }
void navigation_setangleerror(unsigned char gotnewgpsreading,fixedpointnum *angleerror) { // calculate the angle errors between our current attitude and the one we wish to have // and adjust the angle errors that were passed to us. They have already been set by pilot input. // For now, we just override any pilot input. // keep track of the time between good gps readings. navigation_time_sliver+=global.timesliver; if (gotnewgpsreading) { // unshift our timesliver since we are about to use it. Since we are accumulating time, it may get too large to use while shifted. navigation_time_sliver=navigation_time_sliver>>TIMESLIVEREXTRASHIFT; // get the new distance and bearing from our current location to our target position global.navigation_distance=navigation_getdistanceandbearing(global.gps_current_latitude,global.gps_current_longitude,target_latitude,target_longitude,&global.navigation_bearing); // split the distance into it's ontrack and crosstrack components // see the diagram above fixedpointnum angledifference=global.navigation_bearing-navigation_starttodestbearing; fixedpointnum crosstrack_distance=lib_fp_multiply(global.navigation_distance,lib_fp_sine(angledifference)); fixedpointnum ontrack_distance=lib_fp_multiply(global.navigation_distance,lib_fp_cosine(angledifference)); // accumulate integrated error for both ontrack and crosstrack navigation_crosstrack_integrated_error+=lib_fp_multiply(crosstrack_distance,navigation_time_sliver); navigation_ontrack_integrated_error+=lib_fp_multiply(ontrack_distance,navigation_time_sliver); lib_fp_constrain(&navigation_crosstrack_integrated_error,-NAVIGATIONINTEGRATEDERRORLIMIT,NAVIGATIONINTEGRATEDERRORLIMIT); lib_fp_constrain(&navigation_ontrack_integrated_error,-NAVIGATIONINTEGRATEDERRORLIMIT,NAVIGATIONINTEGRATEDERRORLIMIT); // calculate the ontrack and crosstrack velocities toward our target. // We want to put the navigation velocity (change in distance to target over time) into a low pass filter but // we don't want to divide by the time interval to get velocity (divide is expensive) to then turn around and // multiply by the same time interval. So the following is the same as the lib_fp_lowpassfilter code // except we eliminate the multiply. // note: if we use a different time period than FIXEDPOINTONEOVERONE, we need to multiply the distances by the new time period. fixedpointnum fraction=lib_fp_multiply(navigation_time_sliver,FIXEDPOINTONEOVERONE); navigation_crosstrack_velocity=(navigation_last_crosstrack_distance-crosstrack_distance+lib_fp_multiply((FIXEDPOINTONE)-fraction,navigation_crosstrack_velocity)); navigation_ontrack_velocity=(navigation_last_ontrack_distance-ontrack_distance+lib_fp_multiply((FIXEDPOINTONE)-fraction,navigation_ontrack_velocity)); navigation_last_crosstrack_distance=crosstrack_distance; navigation_last_ontrack_distance=ontrack_distance; // calculate the desired tilt in each direction independently using navigation PID fixedpointnum crosstracktiltangle=lib_fp_multiply(usersettings.pid_pgain[NAVIGATIONINDEX],crosstrack_distance) +lib_fp_multiply(usersettings.pid_igain[NAVIGATIONINDEX],navigation_crosstrack_integrated_error) -lib_fp_multiply(usersettings.pid_dgain[NAVIGATIONINDEX],navigation_crosstrack_velocity); fixedpointnum ontracktiltangle =lib_fp_multiply(usersettings.pid_pgain[NAVIGATIONINDEX],ontrack_distance) +lib_fp_multiply(usersettings.pid_igain[NAVIGATIONINDEX],navigation_ontrack_integrated_error) -lib_fp_multiply(usersettings.pid_dgain[NAVIGATIONINDEX],navigation_ontrack_velocity); // don't tilt more than MAX_TILT lib_fp_constrain(&crosstracktiltangle,-MAX_TILT,MAX_TILT); lib_fp_constrain(&ontracktiltangle,-MAX_TILT,MAX_TILT); // Translate the ontrack and cross track tilts into pitch and roll tilts. // Set angledifference equal to the difference between the aircraft's heading (the way it's currently pointing) // and the angle between waypoints and rotate our tilts by that much. angledifference=global.currentestimatedeulerattitude[YAWINDEX]-navigation_starttodestbearing; fixedpointnum sineofangle=lib_fp_sine(angledifference); fixedpointnum cosineofangle=lib_fp_cosine(angledifference); navigation_desiredeulerattitude[ROLLINDEX]=lib_fp_multiply(crosstracktiltangle,cosineofangle)-lib_fp_multiply(ontracktiltangle,sineofangle); navigation_desiredeulerattitude[PITCHINDEX]=lib_fp_multiply(crosstracktiltangle,sineofangle)+lib_fp_multiply(ontracktiltangle,cosineofangle); // for now, don't rotate the aircraft in the direction of travel. Add this later. navigation_time_sliver=0; } // set the angle error as the difference between where we want to be and where we currently are angle wise. angleerror[ROLLINDEX]=navigation_desiredeulerattitude[ROLLINDEX]-global.currentestimatedeulerattitude[ROLLINDEX]; angleerror[PITCHINDEX]=navigation_desiredeulerattitude[PITCHINDEX]-global.currentestimatedeulerattitude[PITCHINDEX]; // don't set the yaw. Let the pilot do yaw // angleerror[YAWINDEX]=navigation_desiredeulerattitude[YAWINDEX]-global.currentestimatedeulerattitude[YAWINDEX]; // don't let the yaw angle error get too large for any one cycle in order to control the maximum yaw rate. // lib_fp_constrain180(&angleerror[YAWINDEX]); // lib_fp_constrain(&angleerror[YAWINDEX],-MAXYAWANGLEERROR,MAXYAWANGLEERROR); }
void getangleerrorfrompilotinput(fixedpointnum * angleerror) { // sets the ange errors for roll, pitch, and yaw based on where the pilot has the tx sticks. fixedpointnum rxrollvalue; fixedpointnum rxpitchvalue; // if in headfree mode, rotate the pilot's stick inputs by the angle that is the difference between where we are currently heading and where we were heading when we armed. if (global.activecheckboxitems & CHECKBOXMASKHEADFREE) { fixedpointnum angledifference = global.currentestimatedeulerattitude[YAWINDEX] - global.heading_when_armed; fixedpointnum cosangledifference = lib_fp_cosine(angledifference); fixedpointnum sinangledifference = lib_fp_sine(angledifference); rxpitchvalue = lib_fp_multiply(global.rxvalues[PITCHINDEX], cosangledifference) + lib_fp_multiply(global.rxvalues[ROLLINDEX], sinangledifference); rxrollvalue = lib_fp_multiply(global.rxvalues[ROLLINDEX], cosangledifference) - lib_fp_multiply(global.rxvalues[PITCHINDEX], sinangledifference); #ifdef INVERTED rxrollvalue = - rxrollvalue; #endif } else { rxpitchvalue = global.rxvalues[PITCHINDEX]; rxrollvalue = global.rxvalues[ROLLINDEX]; #ifdef INVERTED rxrollvalue = - rxrollvalue; #endif } // first, calculate level mode values // how far is our estimated current attitude from our desired attitude? // desired angle is rxvalue (-1 to 1) times LEVEL_MODE_MAX_TILT // First, figure out which max angle we are using depending on aux switch settings. fixedpointnum levelmodemaxangle; if (global.activecheckboxitems & CHECKBOXMASKHIGHANGLE) levelmodemaxangle = FP_LEVEL_MODE_MAX_TILT_HIGH_ANGLE; else levelmodemaxangle = FP_LEVEL_MODE_MAX_TILT; // the angle error is how much our current angles differ from our desired angles. fixedpointnum levelmoderollangleerror = lib_fp_multiply(rxrollvalue, levelmodemaxangle) - global.currentestimatedeulerattitude[ROLLINDEX]; fixedpointnum levelmodepitchangleerror = lib_fp_multiply(rxpitchvalue, levelmodemaxangle) - global.currentestimatedeulerattitude[PITCHINDEX]; // In acro mode, we want the rotation rate to be proportional to the pilot's stick movement. The desired rotation rate is // the stick movement * a multiplier. // Fill angleerror with acro values. If we are currently rotating at rate X and // we want to be rotating at rate Y, then our angle should be off by (Y-X)*timesliver. In theory, we should probably accumulate // this error over time, but our I term will do that anyway and we are talking about rates, which don't need to be perfect. // First figure out what max rotation rates we are using depending on our aux switch settings. fixedpointnum maxyawrate; fixedpointnum maxpitchandrollrate; if (global.activecheckboxitems & CHECKBOXMASKHIGHRATES) { maxyawrate = highyawrate; maxpitchandrollrate = highpitchandrollrate; } else { maxyawrate = usersettings.maxyawrate; maxpitchandrollrate = usersettings.maxpitchandrollrate; } angleerror[ROLLINDEX] = lib_fp_multiply(lib_fp_multiply(rxrollvalue, maxpitchandrollrate) - global.gyrorate[ROLLINDEX], global.timesliver); angleerror[PITCHINDEX] = lib_fp_multiply(lib_fp_multiply(rxpitchvalue, maxpitchandrollrate) - global.gyrorate[PITCHINDEX], global.timesliver); // put a low pass filter on the yaw gyro. If we don't do this, things can get jittery. lib_fp_lowpassfilter(&filteredyawgyrorate, global.gyrorate[YAWINDEX], global.timesliver >> (TIMESLIVEREXTRASHIFT - 3), FIXEDPOINTONEOVERONESIXTYITH, 3); if(global.activecheckboxitems & CHECKBOXMASKYAWHOLD) { // Yaw hold: control yaw angle instead of yaw rate by accumulating the yaw errors. // This is similar to compass mode, but no hardware compass needed. if(!(global.previousactivecheckboxitems & CHECKBOXMASKYAWHOLD)) { // This mode was just switched on. Use current position as reference by setting error to zero. accumulatedyawerror = 0; } // Accumulate yaw angle error accumulatedyawerror += lib_fp_multiply(lib_fp_multiply(global.rxvalues[YAWINDEX], maxyawrate) - filteredyawgyrorate, global.timesliver) >> TIMESLIVEREXTRASHIFT; // Make sure it does not get too high lib_fp_constrain180(&accumulatedyawerror); angleerror[YAWINDEX] = accumulatedyawerror; } else {