Rev 185 | Rev 190 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 185 | Rev 187 | ||
---|---|---|---|
Line 132... | Line 132... | ||
132 | 132 | ||
133 | //------------------------------------------------------------- |
133 | //------------------------------------------------------------- |
134 | // Update GPSParamter |
134 | // Update GPSParamter |
135 | void GPS_UpdateParameter(void) |
135 | void GPS_UpdateParameter(void) |
136 | { |
- | |
137 | #define SWITCH_DELAY 500 |
- | |
138 | static u8 wpclear = FALSE; |
- | |
139 | static u32 SwitchDelay = 0; |
- | |
140 | static GPS_FlightMode_t FlightMode_Old = GPS_FLIGHT_MODE_UNDEF; |
- | |
141 | - | ||
142 | // in case of bad receiving conditions |
- | |
143 | if(FC.RC_Quality < 100) |
- | |
144 | { // set fixed parameter |
- | |
145 | GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_WAYPOINT; |
- | |
146 | GPS_Parameter.Gain = (float) 100; |
- | |
147 | GPS_Parameter.P = (float) 90; |
- | |
148 | GPS_Parameter.I = (float) 90; |
- | |
149 | GPS_Parameter.D = (float) 90; |
- | |
150 | GPS_Parameter.A = (float) 90; |
- | |
151 | GPS_Parameter.ACC = (float) 0; |
- | |
152 | GPS_Parameter.P_Limit = 90; |
- | |
153 | GPS_Parameter.I_Limit = 90; |
- | |
154 | GPS_Parameter.D_Limit = 90; |
- | |
155 | GPS_Parameter.PID_Limit = 200; |
- | |
156 | GPS_Parameter.BrakingDuration = 0; |
- | |
157 | GPS_Parameter.SpeedCompensation = (float) 30; |
- | |
158 | GPS_Parameter.MinSat = 6; |
- | |
159 | GPS_Parameter.StickThreshold = 8; |
- | |
160 | GPS_Parameter.WindCorrection = 0.0; |
- | |
161 | GPS_Parameter.OperatingRadius = 0; // forces the aircraft to fly to home positon |
- | |
162 | - | ||
163 | } |
- | |
164 | else |
- | |
165 | { |
- | |
166 | // update parameter from FC |
- | |
167 | if(StopNavigation) GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_FREE; |
- | |
168 | else |
- | |
169 | { |
- | |
170 | if(Parameter.NaviGpsModeControl < 50) |
- | |
171 | { |
- | |
172 | if(FlightMode_Old == GPS_FLIGHT_MODE_FREE) SetDelay(SWITCH_DELAY); |
- | |
173 | if(CheckDelay(SwitchDelay)) |
- | |
174 | { |
- | |
175 | GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_FREE; |
- | |
176 | } |
- | |
177 | } |
- | |
178 | else if(Parameter.NaviGpsModeControl < 180) |
- | |
179 | { |
- | |
180 | if(FlightMode_Old == GPS_FLIGHT_MODE_AID) SetDelay(SWITCH_DELAY); |
- | |
181 | if(CheckDelay(SwitchDelay)) |
- | |
182 | { |
- | |
183 | GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_AID; |
- | |
184 | } |
- | |
185 | } |
- | |
186 | else |
- | |
187 | { |
- | |
188 | if(FlightMode_Old == GPS_FLIGHT_MODE_WAYPOINT) SetDelay(SWITCH_DELAY); |
- | |
189 | if(CheckDelay(SwitchDelay)) |
- | |
190 | { |
- | |
191 | GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_WAYPOINT; |
- | |
192 | } |
- | |
193 | } |
- | |
194 | } |
- | |
195 | GPS_Parameter.Gain = (float)Parameter.NaviGpsGain; |
- | |
196 | GPS_Parameter.P = (float)Parameter.NaviGpsP; |
- | |
197 | GPS_Parameter.I = (float)Parameter.NaviGpsI; |
- | |
198 | GPS_Parameter.D = (float)Parameter.NaviGpsD; |
- | |
199 | GPS_Parameter.A = (float)Parameter.NaviGpsD; |
- | |
200 | GPS_Parameter.ACC = (float)Parameter.NaviGpsACC; |
- | |
201 | GPS_Parameter.P_Limit = (s32)Parameter.NaviGpsPLimit; |
- | |
202 | GPS_Parameter.I_Limit = (s32)Parameter.NaviGpsILimit; |
- | |
203 | GPS_Parameter.D_Limit = (s32)Parameter.NaviGpsDLimit; |
- | |
204 | GPS_Parameter.PID_Limit = 2* (u32)Parameter.NaviAngleLimitation; |
- | |
205 | GPS_Parameter.BrakingDuration = (u32)Parameter.NaviPH_LoginTime; |
- | |
206 | GPS_Parameter.SpeedCompensation = (float)Parameter.NaviSpeedCompensation; |
- | |
207 | GPS_Parameter.MinSat = (u8)Parameter.NaviGpsMinSat; |
- | |
208 | GPS_Parameter.StickThreshold = (s8)Parameter.NaviStickThreshold; |
- | |
209 | GPS_Parameter.WindCorrection = (float)Parameter.NaviWindCorrection; |
- | |
210 | GPS_Parameter.OperatingRadius = (s32)Parameter.NaviOperatingRadius * 100; // conversion of m to cm |
- | |
211 | } |
- | |
212 | // FlightMode transitions |
- | |
213 | if(GPS_Parameter.FlightMode != FlightMode_Old) |
- | |
214 | { |
- | |
215 | BeepTime = 100; // beep to indicate that mode has been switched |
- | |
216 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
217 | switch(GPS_Parameter.FlightMode) |
- | |
218 | { |
- | |
219 | case GPS_FLIGHT_MODE_FREE: |
- | |
220 | NCFlags &= ~(NC_FLAG_PH | NC_FLAG_CH); |
- | |
221 | NCFlags |= NC_FLAG_FREE; |
- | |
222 | if(!StopNavigation && wpclear) |
- | |
223 | { |
- | |
224 | WPList_Clear(); // clear WPList if mode has changed to Free |
- | |
225 | wpclear = FALSE; |
- | |
226 | } |
- | |
227 | break; |
- | |
228 | - | ||
229 | case GPS_FLIGHT_MODE_AID: |
- | |
230 | NCFlags &= ~(NC_FLAG_FREE | NC_FLAG_CH); |
- | |
231 | NCFlags |= NC_FLAG_PH; |
- | |
232 | break; |
- | |
233 | - | ||
234 | case GPS_FLIGHT_MODE_WAYPOINT: |
- | |
235 | wpclear = TRUE; // clear WP's only if CH was once active |
- | |
236 | NCFlags &= ~(NC_FLAG_FREE | NC_FLAG_PH); |
- | |
237 | NCFlags |= NC_FLAG_CH; |
- | |
238 | break; |
- | |
239 | - | ||
240 | default: // should never happen |
- | |
241 | NCFlags = 0; |
- | |
242 | break; |
- | |
243 | } |
- | |
244 | FlightMode_Old = GPS_Parameter.FlightMode; |
- | |
245 | } |
136 | { |
Line 246... | Line 137... | ||
246 | } |
137 | } |
247 | 138 | ||
248 | //------------------------------------------------------------- |
139 | //------------------------------------------------------------- |
249 | // This function defines a good GPS signal condition |
140 | // This function defines a good GPS signal condition |
250 | u8 GPS_IsSignalOK(void) |
- | |
251 | { |
- | |
252 | if( (GPSData.Status != INVALID) && (GPSData.SatFix == SATFIX_3D) && (GPSData.NumOfSats >= GPS_Parameter.MinSat)) return(1); |
141 | u8 GPS_IsSignalOK(void) |
Line 253... | Line 142... | ||
253 | else return(0); |
142 | { |
254 | } |
143 | } |
255 | 144 | ||
256 | //------------------------------------------------------------ |
145 | //------------------------------------------------------------ |
257 | // Checks for manual control action |
- | |
258 | u8 GPS_IsManuallyControlled(void) |
- | |
259 | { |
- | |
260 | if( ( (abs(FC.StickNick) > GPS_Parameter.StickThreshold) || (abs(FC.StickRoll) > GPS_Parameter.StickThreshold)) && (GPS_Parameter.StickThreshold > 0) && (FC.RC_Quality > 150) ) |
- | |
261 | { |
- | |
262 | NCFlags |= NC_FLAG_MANUAL_CONTROL; |
- | |
263 | return(1); |
- | |
264 | } |
- | |
265 | else |
- | |
266 | { |
- | |
267 | NCFlags &= ~NC_FLAG_MANUAL_CONTROL; |
146 | // Checks for manual control action |
Line 268... | Line 147... | ||
268 | return(0); |
147 | u8 GPS_IsManuallyControlled(void) |
269 | } |
148 | { |
270 | } |
149 | } |
271 | 150 | ||
272 | //------------------------------------------------------------ |
- | |
273 | // copy GPS position from source position to target position |
- | |
274 | u8 GPS_CopyPosition(GPS_Pos_t * pGPSPosSrc, GPS_Pos_t* pGPSPosTgt) |
- | |
275 | { |
- | |
276 | u8 retval = 0; |
- | |
277 | if((pGPSPosSrc == NULL) || (pGPSPosTgt == NULL)) return(retval); // bad pointer |
- | |
278 | // copy only valid positions |
- | |
279 | if(pGPSPosSrc->Status != INVALID) |
- | |
280 | { |
- | |
281 | // if the source GPS position is not invalid |
- | |
282 | pGPSPosTgt->Longitude = pGPSPosSrc->Longitude; |
- | |
283 | pGPSPosTgt->Latitude = pGPSPosSrc->Latitude; |
- | |
284 | pGPSPosTgt->Altitude = pGPSPosSrc->Altitude; |
- | |
285 | pGPSPosTgt->Status = NEWDATA; // mark data in target position as new |
151 | //------------------------------------------------------------ |
Line 286... | Line 152... | ||
286 | retval = 1; |
152 | // copy GPS position from source position to target position |
287 | } |
153 | u8 GPS_CopyPosition(GPS_Pos_t * pGPSPosSrc, GPS_Pos_t* pGPSPosTgt) |
288 | return(retval); |
154 | { |
289 | } |
155 | } |
290 | - | ||
291 | //------------------------------------------------------------ |
- | |
292 | // clear position data |
- | |
293 | u8 GPS_ClearPosition(GPS_Pos_t * pGPSPos) |
- | |
294 | { |
- | |
295 | u8 retval = FALSE; |
- | |
296 | if(pGPSPos == NULL) return(retval); // bad pointer |
- | |
297 | else |
- | |
298 | { |
- | |
299 | pGPSPos->Longitude = 0; |
- | |
300 | pGPSPos->Latitude = 0; |
- | |
301 | pGPSPos->Altitude = 0; |
156 | |
Line 302... | Line 157... | ||
302 | pGPSPos->Status = INVALID; |
157 | //------------------------------------------------------------ |
303 | retval = TRUE; |
158 | // clear position data |
304 | } |
159 | u8 GPS_ClearPosition(GPS_Pos_t * pGPSPos) |
305 | return (retval); |
- | |
306 | } |
- | |
307 | - | ||
308 | 160 | { |
|
Line 309... | Line 161... | ||
309 | //------------------------------------------------------------ |
161 | } |
310 | void GPS_Neutral(void) |
162 | |
311 | { |
163 | |
312 | GPS_Stick.Nick = 0; |
- | |
313 | GPS_Stick.Roll = 0; |
- | |
314 | GPS_Stick.Yaw = 0; |
- | |
315 | } |
- | |
316 | - | ||
317 | //------------------------------------------------------------ |
- | |
318 | void GPS_Init(void) |
- | |
319 | { |
- | |
320 | UART1_PutString("\r\n GPS init..."); |
- | |
321 | UBX_Init(); |
- | |
322 | GPS_Neutral(); |
164 | //------------------------------------------------------------ |
Line 323... | Line 165... | ||
323 | GPS_ClearPosition(&GPS_HoldPosition); |
165 | void GPS_Neutral(void) |
324 | GPS_ClearPosition(&GPS_HomePosition); |
166 | { |
325 | GPS_pTargetPosition = NULL; |
167 | } |
326 | WPList_Init(); |
168 | |
327 | GPS_pWaypoint = NULL; |
- | |
328 | GPS_UpdateParameter(); |
- | |
329 | UART1_PutString("ok"); |
- | |
330 | } |
- | |
331 | 169 | //------------------------------------------------------------ |
|
Line 332... | Line 170... | ||
332 | //------------------------------------------------------------ |
170 | void GPS_Init(void) |
333 | // calculate the bearing to target position from its deviation |
171 | { |
334 | s32 DirectionToTarget_N_E(float northdev, float eastdev) |
172 | } |
335 | { |
173 | |
336 | s32 bearing; |
174 | //------------------------------------------------------------ |
337 | bearing = (s32)(atan2(northdev, eastdev) / M_PI_180); |
- | |
338 | bearing = (270L - bearing)%360L; |
- | |
339 | return(bearing); |
- | |
340 | } |
- | |
341 | - | ||
342 | - | ||
343 | //------------------------------------------------------------ |
- | |
344 | // Rescale xy-vector length if length limit is violated |
- | |
345 | // returns vector len after scaling |
- | |
346 | s32 GPS_LimitXY(s32 *x, s32 *y, s32 limit) |
- | |
347 | { |
- | |
348 | s32 dist; |
175 | // calculate the bearing to target position from its deviation |
Line 349... | Line 176... | ||
349 | 176 | s32 DirectionToTarget_N_E(float northdev, float eastdev) |
|
350 | dist = (s32)hypot(*x,*y); // the length of the vector |
177 | { |
351 | if (dist > limit) |
178 | } |
352 | // if vector length is larger than the given limit |
179 | |
353 | { // scale vector compontents so that the length is cut off to limit |
- | |
354 | *x = (s32)(( (double)(*x) * (double)limit ) / (double)dist); |
180 | |
Line 355... | Line 181... | ||
355 | *y = (s32)(( (double)(*y) * (double)limit ) / (double)dist); |
181 | //------------------------------------------------------------ |
356 | dist = limit; |
182 | // Rescale xy-vector length if length limit is violated |
357 | } |
183 | // returns vector len after scaling |
358 | return(dist); |
184 | s32 GPS_LimitXY(s32 *x, s32 *y, s32 limit) |
359 | } |
- | |
360 | 185 | { |
|
Line 361... | Line 186... | ||
361 | //------------------------------------------------------------ |
186 | } |
362 | // transform the integer deg into float radians |
187 | |
363 | inline double RadiansFromGPS(s32 deg) |
188 | //------------------------------------------------------------ |
364 | { |
189 | // transform the integer deg into float radians |
365 | return ((double)deg * 1e-7f * M_PI_180); // 1E-7 because deg is the value in ° * 1E7 |
- | |
366 | } |
- | |
367 | - | ||
368 | //------------------------------------------------------------ |
- | |
369 | // transform the integer deg into float deg |
- | |
370 | inline double DegFromGPS(s32 deg) |
- | |
371 | { |
- | |
372 | return ((double)deg * 1e-7f); // 1E-7 because deg is the value in ° * 1E7 |
- | |
373 | } |
- | |
374 | - | ||
375 | //------------------------------------------------------------ |
- | |
376 | // calculate the deviation from the current position to the target position |
- | |
377 | u8 GPS_CalculateDeviation(GPS_Pos_t * pCurrentPos, GPS_Pos_t * pTargetPos, GPS_Deviation_t* pDeviationFromTarget) |
- | |
378 | { |
- | |
379 | double temp1, temp2; |
- | |
380 | // if given pointer is NULL |
- | |
381 | if((pCurrentPos == NULL) || (pTargetPos == NULL)) goto baddata; |
- | |
382 | // if positions are invalid |
- | |
383 | if((pCurrentPos->Status == INVALID) || (pTargetPos->Status == INVALID)) goto baddata; |
- | |
384 | - | ||
385 | // The deviation from the current to the target position along north and east direction is |
- | |
386 | // simple the lat/lon difference. To convert that angular deviation into an |
- | |
387 | // arc length the spherical projection has to be considered. |
- | |
388 | // The mean earth radius is 6371km. Therfore the arc length per latitude degree |
- | |
389 | // is always 6371km * 2 * Pi / 360deg = 111.2 km/deg. |
- | |
390 | // The arc length per longitude degree depends on the correspondig latitude and |
- | |
391 | // is 111.2km * cos(latitude). |
- | |
392 | - | ||
393 | // calculate the shortest longitude deviation from target |
- | |
394 | temp1 = DegFromGPS(pCurrentPos->Longitude) - DegFromGPS(pTargetPos->Longitude); |
- | |
395 | // outside an angular difference of -180 deg ... +180 deg its shorter to go the other way around |
- | |
396 | // In our application we wont fly more than 20.000 km but along the date line this is important. |
- | |
397 | if(temp1 > 180.0f) temp1 -= 360.0f; |
- | |
398 | else if (temp1 < -180.0f) temp1 += 360.0f; |
- | |
399 | temp1 *= cos((RadiansFromGPS(pTargetPos->Latitude) + RadiansFromGPS(pCurrentPos->Latitude))/2); |
- | |
400 | // calculate latitude deviation from target |
- | |
401 | // this is allways within -180 deg ... 180 deg |
- | |
402 | temp2 = DegFromGPS(pCurrentPos->Latitude) - DegFromGPS(pTargetPos->Latitude); |
- | |
403 | // deviation from target position in cm |
- | |
404 | // i.e. the distance to walk from the target in northern and eastern direction to reach the current position |
- | |
405 | - | ||
406 | pDeviationFromTarget->Status = INVALID; |
- | |
407 | pDeviationFromTarget->North = (s32)(11119492.7f * temp2); |
- | |
408 | pDeviationFromTarget->East = (s32)(11119492.7f * temp1); |
- | |
409 | // If the position deviation is small enough to neglect the earth curvature |
- | |
410 | // (this is for our application always fulfilled) the distance to target |
- | |
411 | // can be calculated by the pythagoras of north and east deviation. |
- | |
412 | pDeviationFromTarget->Distance = (s32)(11119492.7f * hypot(temp1, temp2)); |
- | |
413 | if (pDeviationFromTarget->Distance == 0L) pDeviationFromTarget->Bearing = 0L; |
- | |
414 | else pDeviationFromTarget->Bearing = DirectionToTarget_N_E(temp2, temp1); |
- | |
415 | pDeviationFromTarget->Status = NEWDATA; |
- | |
416 | return TRUE; |
- | |
417 | - | ||
418 | baddata: |
- | |
419 | pDeviationFromTarget->North = 0L; |
- | |
420 | pDeviationFromTarget->East = 0L; |
- | |
421 | pDeviationFromTarget->Distance = 0L; |
- | |
422 | pDeviationFromTarget->Bearing = 0L; |
- | |
423 | pDeviationFromTarget->Status = INVALID; |
- | |
424 | return FALSE; |
- | |
425 | } |
- | |
426 | - | ||
427 | //------------------------------------------------------------ |
- | |
428 | void GPS_Navigation(void) |
- | |
429 | { |
- | |
430 | static u32 beep_rythm; |
- | |
431 | static u32 GPSDataTimeout = 0; |
- | |
432 | float compassheading, sin_h, cos_h; |
- | |
433 | - | ||
434 | // pointer to current target position |
- | |
435 | static GPS_Pos_t * pTargetPositionOld = NULL; |
- | |
436 | - | ||
437 | static GPS_Pos_t RangedTargetPosition = {0,0,0, INVALID}; // the limited target position, this is derived from the target position with repect to the operating radius |
- | |
438 | static s32 OperatingRadiusOld = -1; |
- | |
439 | static u32 WPTime = 0; |
- | |
440 | - | ||
441 | - | ||
442 | - | ||
443 | // get current heading from the FC gyro compass heading |
- | |
444 | if(abs(FC.StickYaw) > 20 || FromFlightCtrl.GyroHeading > 3600) compassheading = (float)I2C_Heading.Heading * M_PI_180; |
- | |
445 | else compassheading = ((float)FromFlightCtrl.GyroHeading * M_PI_180) / 10.0; |
- | |
446 | - | ||
447 | sin_h = sin(compassheading); |
- | |
448 | cos_h = cos(compassheading); |
- | |
449 | - | ||
450 | - | ||
451 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
- | |
452 | //+ Check for new data from GPS-receiver |
- | |
453 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
- | |
454 | switch(GPSData.Status) |
- | |
455 | { |
- | |
456 | case INVALID: // no gps data available |
- | |
457 | // do nothing |
- | |
458 | GPS_Parameter.PID_Limit = 0; // disables PID output |
- | |
459 | break; |
- | |
460 | - | ||
461 | case PROCESSED: // the current data have been allready processed |
- | |
462 | // if no new data are available within the timeout switch to invalid state. |
- | |
463 | if(CheckDelay(GPSDataTimeout)) GPSData.Status = INVALID; |
- | |
464 | // wait for new gps data |
- | |
465 | break; |
- | |
466 | - | ||
467 | case NEWDATA: // handle new gps data |
- | |
468 | - | ||
469 | // update GPS Parameter from FC-Data via SPI interface |
- | |
470 | GPS_UpdateParameter(); |
- | |
471 | - | ||
472 | // wait maximum of 3 times the normal data update time before data timemout |
- | |
473 | GPSDataTimeout = SetDelay(3 * GPS_UPDATETIME_MS); |
- | |
474 | beep_rythm++; |
- | |
475 | - | ||
476 | // debug |
- | |
477 | DebugOut.Analog[21] = (s16)GPSData.Speed_North; |
- | |
478 | DebugOut.Analog[22] = (s16)GPSData.Speed_East; |
- | |
479 | DebugOut.Analog[31] = (s16)GPSData.NumOfSats; |
- | |
480 | - | ||
481 | // If GPS signal condition is sufficient for a reliable position measurement |
- | |
482 | if(GPS_IsSignalOK()) |
- | |
483 | { |
- | |
484 | // update home deviation info |
- | |
485 | GPS_CalculateDeviation(&(GPSData.Position), &GPS_HomePosition, &CurrentHomeDeviation); |
- | |
486 | - | ||
487 | // if the MK is starting or the home position is invalid then store the home position |
- | |
488 | if((FC.MKFlags & MKFLAG_START) || (GPS_HomePosition.Status == INVALID)) |
- | |
489 | { // try to update the home position from the current position |
- | |
490 | if(GPS_CopyPosition(&(GPSData.Position), &GPS_HomePosition)) |
- | |
491 | { |
- | |
492 | BeepTime = 700; // beep on success |
- | |
493 | GPS_CopyPosition(&GPS_HomePosition, &(NaviData.HomePosition)); |
- | |
494 | } |
- | |
495 | GPS_pWaypoint = WPList_Begin(); // go to start of waypoint list, return NULL of the list is empty |
- | |
496 | if(GPS_pWaypoint != NULL) // if new WP exist |
- | |
497 | { // update WP hold time stamp immediately! |
- | |
498 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // update hold time stamp |
- | |
499 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
500 | } |
- | |
501 | } |
- | |
502 | - | ||
503 | /* The selected flight mode influences the target position pointer and therefore the behavior */ |
- | |
504 | - | ||
505 | // check for current flight mode and set the target pointer GPS_pTargetPosition respectively |
- | |
506 | switch(GPS_Parameter.FlightMode) |
- | |
507 | { |
- | |
508 | // the GPS control is deactived |
- | |
509 | case GPS_FLIGHT_MODE_FREE: |
- | |
510 | - | ||
511 | GPS_Parameter.PID_Limit = 0; // disables PID output |
- | |
512 | // update hold position |
- | |
513 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); |
- | |
514 | // no target position |
- | |
515 | GPS_pTargetPosition = NULL; |
- | |
516 | GPS_TargetRadius = 0; |
- | |
517 | break; |
- | |
518 | - | ||
519 | // the GPS supports the position hold, if the pilot takes no action |
- | |
520 | case GPS_FLIGHT_MODE_AID: |
- | |
521 | - | ||
522 | if(GPS_IsManuallyControlled()) |
- | |
523 | { |
- | |
524 | GPS_Parameter.PID_Limit = 0; // disables PID output, as long as the manual conrol is active |
- | |
525 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); |
- | |
526 | GPS_pTargetPosition = NULL; |
- | |
527 | GPS_TargetRadius = 0; |
- | |
528 | } |
- | |
529 | else |
- | |
530 | { |
- | |
531 | /* |
- | |
532 | #define PH_MOVE_THRESHOLD 8 |
- | |
533 | if( ((abs(FC.StickNick) > PH_MOVE_THRESHOLD) || (abs(FC.StickRoll) > PH_MOVE_THRESHOLD) ) && (FC.RC_Quality > 150)) |
- | |
534 | { // indirect control by moving the hold position with rc sticks |
- | |
535 | // rc sticks have a range of +/-127 counts |
- | |
536 | // GPS Coordinates are in 1-E7 deg, i.e. 1 counts is 1E-7°/360°*40E+8cm = 1.11 cm |
- | |
537 | // normal manual activtion threshold is 8 counts that results in a change of the hold position |
- | |
538 | // of min 8*1.11cm * 5Hz = 8.88 = 44.4cm/s an max 127*1.11cm *5Hz = 705cm/s |
- | |
539 | GPS_HoldPosition.Latitude += (s32)(cos_h*FC.StickNick + sin_h*FC.StickRoll); |
- | |
540 | GPS_HoldPosition.Longitude += (s32)((sin_h*FC.StickNick - cos_h*FC.StickRoll) / cos(RadiansFromGPS(GPS_HoldPosition.Latitude)) ); |
- | |
541 | }*/ |
- | |
542 | // set target position |
- | |
543 | GPS_pTargetPosition = &GPS_HoldPosition; |
- | |
544 | GPS_TargetRadius = 100; // 1 meter |
- | |
545 | } |
- | |
546 | break; |
- | |
547 | - | ||
548 | // the GPS control is directed to a target position |
- | |
549 | // given by a waypoint or by the home position |
- | |
550 | case GPS_FLIGHT_MODE_WAYPOINT: |
- | |
551 | - | ||
552 | if(GPS_IsManuallyControlled()) // the human pilot takes the action |
- | |
553 | { |
- | |
554 | GPS_Parameter.PID_Limit = 0; // disables PID output, as long as the manual conrol is active |
- | |
555 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); // update hold position |
- | |
556 | GPS_pTargetPosition = NULL; // set target position invalid |
- | |
557 | GPS_TargetRadius = 0; |
- | |
558 | } |
- | |
559 | else // no manual control -> gps position hold active |
- | |
560 | { |
- | |
561 | // waypoint trigger logic |
- | |
562 | if(GPS_pWaypoint != NULL) // pointer to waypoint exist |
- | |
563 | { |
- | |
564 | if(GPS_pWaypoint->Position.Status == INVALID) // should never happen |
- | |
565 | { |
- | |
566 | GPS_pWaypoint = WPList_Next(); // goto to next WP |
- | |
567 | if(GPS_pWaypoint != NULL) // if new WP exist |
- | |
568 | { // update WP hold time stamp immediately! |
- | |
569 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // update hold time stamp |
- | |
570 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
571 | } |
- | |
572 | BeepTime = 255; |
- | |
573 | } |
- | |
574 | else // waypoint position is valid |
- | |
575 | { |
- | |
576 | // if WP has been reached once, wait hold time before trigger to next one |
- | |
577 | if(NCFlags & NC_FLAG_TARGET_REACHED) |
- | |
578 | { |
- | |
579 | /* ToDo: Adjust GPS_pWaypoint->Heading, GPS_pWaypoint->Event handling */ |
- | |
580 | if(CheckDelay(WPTime)) |
- | |
581 | { |
- | |
582 | GPS_pWaypoint = WPList_Next(); // goto to next waypoint, return NULL if end of list has been reached |
- | |
583 | if(GPS_pWaypoint == NULL) GPS_pWaypoint = WPList_End(); // goto last WP if next one not exist |
- | |
584 | if(GPS_pWaypoint != NULL) // if new WP exist |
- | |
585 | { // update WP hold time stamp immediately! |
- | |
586 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // update hold time stamp |
- | |
587 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
588 | } |
- | |
589 | } |
- | |
590 | } // EOF target reached |
- | |
591 | else |
- | |
592 | { |
- | |
593 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // set hold time stamp |
- | |
594 | } |
- | |
595 | } |
- | |
596 | } |
- | |
597 | else // pointer to waypoint does not exist |
- | |
598 | { |
- | |
599 | // try to catch the first waypoint from the list |
- | |
600 | GPS_pWaypoint = WPList_Begin(); |
- | |
601 | if(GPS_pWaypoint != NULL) // if new WP exist |
- | |
602 | { // update WP hold time stamp immediately! |
- | |
603 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // update hold time stamp |
- | |
604 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
605 | } |
- | |
606 | } |
- | |
607 | // EOF waypoint trigger logic |
- | |
608 | - | ||
609 | if(GPS_pWaypoint != NULL) // Waypoint exist |
- | |
610 | { |
- | |
611 | // possible new data have been put into wp-list |
- | |
612 | if(GPS_pWaypoint->Position.Status == NEWDATA) |
- | |
613 | { |
- | |
614 | WPTime = SetDelay(GPS_pWaypoint->HoldTime * 1000); // update hold time stamp |
- | |
615 | NCFlags &= ~NC_FLAG_TARGET_REACHED; |
- | |
616 | } |
- | |
617 | // update the hold position |
- | |
618 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); |
- | |
619 | // set target to the waypoint |
- | |
620 | GPS_pTargetPosition = &(GPS_pWaypoint->Position); |
- | |
621 | // update target radius |
- | |
622 | GPS_TargetRadius = (s32)(GPS_pWaypoint->ToleranceRadius) * 100L; |
- | |
623 | - | ||
624 | } |
- | |
625 | else // no waypoint info available, i.e. the WPList is empty or the end of the list has been reached |
- | |
626 | { |
- | |
627 | // fly back to home postion |
- | |
628 | if(GPS_HomePosition.Status == INVALID) |
- | |
629 | { |
- | |
630 | GPS_pTargetPosition = &GPS_HoldPosition; // fall back to hold mode if home position is not available |
- | |
631 | GPS_TargetRadius = 100; |
- | |
632 | BeepTime = 255; // beep to indicate missin home position |
- | |
633 | } |
- | |
634 | else // the home position is valid |
- | |
635 | { |
- | |
636 | // update the hold position |
- | |
637 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); |
- | |
638 | // set target to home position |
- | |
639 | GPS_pTargetPosition = &GPS_HomePosition; |
- | |
640 | GPS_TargetRadius = 100; |
- | |
641 | } |
- | |
642 | } |
- | |
643 | } // EOF no manual control |
- | |
644 | break; |
- | |
645 | - | ||
646 | case GPS_FLIGHT_MODE_UNDEF: |
- | |
647 | default: |
- | |
648 | GPS_Parameter.PID_Limit = 0; // disables PID output |
- | |
649 | // update hold position |
- | |
650 | GPS_CopyPosition(&(GPSData.Position), &GPS_HoldPosition); |
- | |
651 | // no target position |
- | |
652 | GPS_pTargetPosition = NULL; |
- | |
653 | GPS_TargetRadius = 0; |
- | |
654 | break; |
- | |
655 | - | ||
656 | }// EOF GPS Mode Handling |
- | |
657 | - | ||
658 | - | ||
659 | /* Calculation of range target based on the real target */ |
- | |
660 | - | ||
661 | // if no target position exist clear the ranged target position |
- | |
662 | if(GPS_pTargetPosition == NULL) GPS_ClearPosition(&RangedTargetPosition); |
- | |
663 | else |
- | |
664 | { // if the target position has been changed or the value has been updated or the OperatingRadius has changed |
- | |
665 | if((GPS_pTargetPosition != pTargetPositionOld) || (GPS_pTargetPosition->Status == NEWDATA) || (GPS_Parameter.OperatingRadius != OperatingRadiusOld) ) |
- | |
666 | { |
- | |
667 | BeepTime = 255; // beep to indicate setting of a new target position |
- | |
668 | NCFlags &= ~NC_FLAG_TARGET_REACHED; // clear target reached flag |
- | |
669 | // calculate deviation of new target position from home position |
- | |
670 | if(GPS_CalculateDeviation(GPS_pTargetPosition, &GPS_HomePosition, &TargetHomeDeviation)) |
- | |
671 | { |
- | |
672 | // check distance from home position |
- | |
673 | if(TargetHomeDeviation.Distance > GPS_Parameter.OperatingRadius) |
- | |
674 | { |
- | |
675 | //calculate ranged target position to be within the operation radius area |
- | |
676 | NCFlags |= NC_FLAG_RANGE_LIMIT; |
- | |
677 | - | ||
678 | TargetHomeDeviation.North = (s32)(((float)TargetHomeDeviation.North * (float)GPS_Parameter.OperatingRadius) / (float)TargetHomeDeviation.Distance); |
- | |
679 | TargetHomeDeviation.East = (s32)(((float)TargetHomeDeviation.East * (float)GPS_Parameter.OperatingRadius) / (float)TargetHomeDeviation.Distance); |
- | |
680 | TargetHomeDeviation.Distance = GPS_Parameter.OperatingRadius; |
- | |
681 | - | ||
682 | RangedTargetPosition.Status = INVALID; |
- | |
683 | RangedTargetPosition.Latitude = GPS_HomePosition.Latitude; |
- | |
684 | RangedTargetPosition.Latitude += (s32)((float)TargetHomeDeviation.North / 1.11194927f); |
- | |
685 | RangedTargetPosition.Longitude = GPS_HomePosition.Longitude; |
- | |
686 | RangedTargetPosition.Longitude += (s32)((float)TargetHomeDeviation.East / (1.11194927f * cos(RadiansFromGPS(GPS_HomePosition.Latitude))) ); |
- | |
687 | RangedTargetPosition.Altitude = GPS_pTargetPosition->Altitude; |
- | |
688 | RangedTargetPosition.Status = NEWDATA; |
- | |
689 | } |
- | |
690 | else |
- | |
691 | { // the target is located within the operation radius area |
- | |
692 | // simple copy the loaction to the ranged target position |
- | |
693 | GPS_CopyPosition(GPS_pTargetPosition, &RangedTargetPosition); |
- | |
694 | NCFlags &= ~NC_FLAG_RANGE_LIMIT; |
- | |
695 | } |
- | |
696 | } |
- | |
697 | else |
- | |
698 | { // deviation could not be determined |
- | |
699 | GPS_ClearPosition(&RangedTargetPosition); |
- | |
700 | } |
- | |
701 | GPS_pTargetPosition->Status = PROCESSED; // mark current target as processed! |
- | |
702 | } |
- | |
703 | } |
- | |
704 | OperatingRadiusOld = GPS_Parameter.OperatingRadius; |
- | |
705 | // remember last target position pointer |
- | |
706 | pTargetPositionOld = GPS_pTargetPosition; |
- | |
707 | - | ||
708 | /* Calculate position deviation from ranged target */ |
- | |
709 | - | ||
710 | // calculate deviation of current position to ranged target position in cm |
- | |
711 | if(GPS_CalculateDeviation(&(GPSData.Position), &RangedTargetPosition, &CurrentTargetDeviation)) |
- | |
712 | { // set target reached flag of we once reached the target point |
- | |
713 | if(!(NCFlags & NC_FLAG_TARGET_REACHED) && (CurrentTargetDeviation.Distance < GPS_TargetRadius)) |
- | |
714 | { |
- | |
715 | NCFlags |= NC_FLAG_TARGET_REACHED; // set target reached flag |
- | |
716 | } |
- | |
717 | // implement your control code here based |
- | |
718 | // in the info available in the CurrentTargetDeviation, GPSData and FromFlightCtrl.GyroHeading |
- | |
719 | GPS_Stick.Nick = 0; |
- | |
720 | GPS_Stick.Roll = 0; |
- | |
721 | GPS_Stick.Yaw = 0; |
- | |
722 | } |
- | |
723 | else // deviation could not be calculated |
- | |
724 | { // do nothing on gps sticks! |
- | |
725 | GPS_Neutral(); |
- | |
726 | NCFlags &= ~NC_FLAG_TARGET_REACHED; // clear target reached |
- | |
727 | } |
- | |
728 | - | ||
729 | }// eof if GPSSignal is OK |
- | |
730 | else // GPSSignal not OK |
- | |
731 | { |
- | |
732 | GPS_Neutral(); |
- | |
733 | // beep if signal is not sufficient |
- | |
734 | if(GPS_Parameter.FlightMode != GPS_FLIGHT_MODE_FREE) |
- | |
735 | { |
- | |
736 | if(!(GPSData.Flags & FLAG_GPSFIXOK) && !(beep_rythm % 5)) BeepTime = 100; |
- | |
737 | else if (GPSData.NumOfSats < GPS_Parameter.MinSat && !(beep_rythm % 5)) BeepTime = 10; |
- | |
738 | } |
- | |
739 | } |
- | |
740 | GPSData.Status = PROCESSED; // mark as processed |
- | |
741 | break; |
- | |
742 | } |
- | |
743 | - | ||
744 | DebugOut.Analog[6] = NCFlags; |
- | |
745 | DebugOut.Analog[27] = (s16)CurrentTargetDeviation.North; |
- | |
746 | DebugOut.Analog[28] = (s16)CurrentTargetDeviation.East; |
- | |
747 | DebugOut.Analog[29] = GPS_Stick.Nick; |
- | |
748 | DebugOut.Analog[30] = GPS_Stick.Roll; |
- | |
749 | - | ||
750 | // update navi data, send back to ground station |
- | |
751 | GPS_CopyPosition(&(GPSData.Position), &(NaviData.CurrentPosition)); |
- | |
752 | GPS_CopyPosition(&RangedTargetPosition, &(NaviData.TargetPosition)); |
- | |
753 | GPS_CopyPosition(&GPS_HomePosition, &(NaviData.HomePosition)); |
- | |
754 | NaviData.SatsInUse = GPSData.NumOfSats; |
- | |
755 | NaviData.TargetPositionDeviation.Distance = (u16)CurrentTargetDeviation.Distance/10; // dm |
- | |
756 | NaviData.TargetPositionDeviation.Bearing = (s16)CurrentTargetDeviation.Bearing; |
- | |
757 | NaviData.HomePositionDeviation.Distance = (u16)CurrentHomeDeviation.Distance/10; // dm |
- | |
758 | NaviData.HomePositionDeviation.Bearing = (s16)CurrentHomeDeviation.Bearing; |
- | |
759 | NaviData.UBat = FC.UBat; |
190 | inline double RadiansFromGPS(s32 deg) |
760 | NaviData.GroundSpeed = (u16)GPSData.Speed_Ground; |
191 | { |