Rev 966 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
Copyright 2008, by Michael Walter
All functions written by Michael Walter are free software and can be redistributed and/or modified under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
Please note: The software is based on the framework provided by H. Buss and I. Busker in their Mikrokopter projekt. All functions that
are not written by Michael Walter are under the license by H. Buss and I. Busker (license_buss.txt) published by www.mikrokopter.de
unless it is stated otherwise.
*/
/*****************************************************************************
INCLUDES
**************************************************************************** */
#include "main.h"
#include "kafi.h"
#include "mymath.h"
#include <math.h>
/*****************************************************************************
(SYMBOLIC) CONSTANTS
*****************************************************************************/
/*****************************************************************************
VARIABLES
*****************************************************************************/
int GPSTracking
= 0;
int targetPosValid
= 0;
int homePosValid
= 0;
int holdPosValid
= 0;
volatile gpsInfo_t actualPos
;// measured position (last gps record)
volatile gpsInfo_t targetPos
;// measured position (last gps record)
volatile gpsInfo_t homePos
;// measured position (last gps record)
volatile gpsInfo_t holdPos
; // measured position (last gps record)
NAV_STATUS_t navStatus
;
NAV_POSLLH_t navPosLlh
;
NAV_POSUTM_t navPosUtm
;
NAV_VELNED_t navVelNed
;
uint8_t gpsState
;
signed int GPS_Nick
= 0;
signed int GPS_Roll
= 0;
long distanceNS
= 0;
long distanceEW
= 0;
long velocityNS
= 0;
long velocityEW
= 0;
unsigned long maxDistance
= 0;
int roll_gain
= 0;
int nick_gain
= 0;
int nick_gain_p
, nick_gain_d
;
int roll_gain_p
, roll_gain_d
;
int Override
= 0;
int TargetGier
= 0;
extern int sollGier
;
extern int RemoteLinkLost
;
volatile char*ubxP
, *ubxEp
, *ubxSp
;// pointers to packet currently transfered
volatile uint8_t CK_A
, CK_B
;// UBX checksum bytes
volatile uint8_t ignorePacket
;// true when previous packet was not processed
volatile unsigned short msgLen
;
volatile uint8_t msgID
;
void GPSscanData
(void);
void GPSupdate
(void);
void SetNewHeading
(unsigned long maxDistance
);
/* ****************************************************************************
Functionname: GPSupdate */ /*!
Description:
@param[in]
@return void
@pre -
@post -
@author Michael Walter
**************************************************************************** */
void GPSupdate
(void)
{
float SIN_H
, COS_H
;
long max_p
= 0;
long max_d
= 0;
int SwitchPos
= 0;
/* Determine Selector Switch Position */
if (PPM_in
[EE_Parameter.
Kanalbelegung[K_POTI3
]] < -100)
{
SwitchPos
= 0;
}
else if (PPM_in
[EE_Parameter.
Kanalbelegung[K_POTI3
]] > 100)
{
SwitchPos
= 2;/* Target Mode */
}
else
{
SwitchPos
= 1;/* Position Hold */
}
/* Overide On / Off */
if (abs(PPM_in
[EE_Parameter.
Kanalbelegung[K_ROLL
]])> 10 ||
abs(PPM_in
[EE_Parameter.
Kanalbelegung[K_GIER
]])> 10 ||
abs(PPM_in
[EE_Parameter.
Kanalbelegung[K_NICK
]])> 10)
{
Override
= 1;
}
else
{
Override
= 0;
}
/* Set Home Position */
if ((actualPos.
state > 2) &&
(homePosValid
== 0))
{
homePos.
north = actualPos.
north;
homePos.
east = actualPos.
east;
homePos.
altitude = actualPos.
altitude ;
homePosValid
= 1;
}
/* Set Target Position */
if ((actualPos.
state > 2) &&
(SwitchPos
== 0))
{
targetPos.
north = actualPos.
north;
targetPos.
east = actualPos.
east;
targetPos.
altitude = actualPos.
altitude ;
targetPosValid
= 1;
}
if ((actualPos.
state < 3) &&
(SwitchPos
== 0))
{
targetPosValid
= 0;
}
/* Set Hold Position */
if ((actualPos.
state > 2) &&
((Override
== 1) ||
(SwitchPos
== 2) )) /* Update the hold position in case we are in target mode */
{
holdPos.
north = actualPos.
north;
holdPos.
east = actualPos.
east;
holdPos.
altitude = actualPos.
altitude ;
holdPosValid
= 1;
}
if ((actualPos.
state < 3) &&
(Override
== 1))
{
holdPosValid
= 0;
}
/* Indicate Valid GPS Position */
if ((actualPos.
state > 2) &&
(SwitchPos
== 0))
{
if(BeepMuster
== 0xffff)
{
beeptime
= 5000;
BeepMuster
= 0x0100;
}
}
if (RemoteLinkLost
== 0) /* Disable Heading Update in case we lost the RC - Link */
{
max_p
= (MAX
(0, (PPM_in
[EE_Parameter.
Kanalbelegung[K_POTI1
]] + 170)) / 20);
max_d
= (MAX
(0, (PPM_in
[EE_Parameter.
Kanalbelegung[K_POTI2
]] + 170)) / 40);
}
else
{
max_p
= 8;
max_d
= 4;
}
/* Those seem to be good values */
max_p
= 8;
max_d
= 4;
//DebugOut.Analog[11] = max_p;
//DebugOut.Analog[12] = max_d;
static int GPSTrackingCycles
= 0;
long maxGainPos
= 140;
long maxGainVel
= 140;
/* Ramp up gain */
if (GPSTrackingCycles
< 1000)
{
GPSTrackingCycles
++;
}
maxGainPos
= (maxGainPos
* GPSTrackingCycles
) / 1000;
maxGainVel
= (maxGainVel
* GPSTrackingCycles
) / 1000;
/* Determine Offset from nominal Position */
if (actualPos.
state > 2 )
{
if ((SwitchPos
== 2) &&
(targetPosValid
== 1) &&
(RemoteLinkLost
== 0) &&
(Override
== 0))
{ /* determine distance from target position */
distanceNS
= actualPos.
north - targetPos.
north; // in 0.1m
distanceEW
= actualPos.
east - targetPos.
east; // in 0.1m
velocityNS
= actualPos.
velNorth; // in 0.1m/s
velocityEW
= actualPos.
velEast; // in 0.1m/s
maxDistance
= sqrt(distanceNS
* distanceNS
+ distanceEW
* distanceEW
);
}
else if ((SwitchPos
== 1)&&
(holdPosValid
== 1) &&
(RemoteLinkLost
== 0) &&
(Override
== 0))
{ /* determine distance from hold position */
distanceNS
= actualPos.
north - holdPos.
north; // in 0.1m
distanceEW
= actualPos.
east - holdPos.
east; // in 0.1m
velocityNS
= actualPos.
velNorth; // in 0.1m/s
velocityEW
= actualPos.
velEast; // in 0.1m/s
maxDistance
= sqrt(distanceNS
* distanceNS
+ distanceEW
* distanceEW
);
}
else if ((RemoteLinkLost
== 1) &&
(homePosValid
==1)) /* determine distance from target position */
{/* Overide in case the remote link got lost */
distanceNS
= actualPos.
north - homePos.
north; // in 0.1m
distanceEW
= actualPos.
east - homePos.
east; // in 0.1m
velocityNS
= actualPos.
velNorth; // in 0.1m/s
velocityEW
= actualPos.
velEast; // in 0.1m/s
maxDistance
= sqrt(distanceNS
* distanceNS
+ distanceEW
* distanceEW
);
}
else
{
distanceNS
= 0.0F; // in 0.1m
distanceEW
= 0.0F; // in 0.1m
velocityNS
= 0.0F; // in 0.1m/s
velocityEW
= 0.0F; // in 0.1m/s
maxDistance
= 0.0F;
GPSTrackingCycles
= 0;
}
/* Limit GPS_Nick to 25 */
nick_gain_p
= (long) MAX
(-maxGainPos
, MIN
(maxGainPos
, ((distanceNS
* max_p
)/50))); //m
nick_gain_d
= (long) MAX
(-maxGainVel
, MIN
(maxGainVel
, ((velocityNS
* max_d
)/50))); //m/s
roll_gain_p
= (long) MAX
(-maxGainPos
, MIN
(maxGainPos
, ((distanceEW
* max_p
)/50))); //m
roll_gain_d
= (long) MAX
(-maxGainVel
, MIN
(maxGainVel
, ((velocityEW
* max_d
)/50))); //m/s
TargetGier
= c_atan2
(-distanceEW
/ 8, -distanceNS
/ 8) * 10;
/* PD-Control */
nick_gain
= nick_gain_p
+ nick_gain_d
;
roll_gain
= -(roll_gain_p
+ roll_gain_d
);
/* Calculate Distance to Target */
SIN_H
= (float) sin(status.
Psi);
COS_H
=(float) cos(status.
Psi);
GPS_Nick
= (int) (COS_H
* (float) nick_gain
- SIN_H
* (float) roll_gain
);
GPS_Roll
= (int) (SIN_H
* (float) nick_gain
+ COS_H
* (float) roll_gain
);
GPS_Nick
= MAX
(-maxGainPos
, MIN
(maxGainPos
, GPS_Nick
));
GPS_Roll
= MAX
(-maxGainPos
, MIN
(maxGainPos
, GPS_Roll
));
/* Set New Heading */
SetNewHeading
(maxDistance
);
}
else
{
GPS_Nick
= 0;
GPS_Roll
= 0;
maxDistance
= 0.0F;
}
}
#if 0
if (maxDistance
/ 10 < 12)
{
static int iState
= 0;
switch (iState
)
{
case 0:
targetPos.
north += 400;
targetPos.
east += 0;
GPSTrackingCycles
= 0;
iState
++;
break;
case 1:
targetPos.
north += 0;
targetPos.
east += 400;
GPSTrackingCycles
= 0;
iState
++;
break;
case 2:
targetPos.
north -= 400;
targetPos.
east += 0;
GPSTrackingCycles
= 0;
iState
++;
break;
case 3:
targetPos.
north += 0;
targetPos.
east -= 400;
GPSTrackingCycles
= 0;
iState
=0;
break;
default:
iState
=0;
break;
}
beeptime
= 5000;
BeepMuster
= 0x0c00;
}
#endif
void SetNewHeading
(unsigned long maxDistance
)
/* Set New Heading */
{
int OffsetGier
= 0;
if (maxDistance
/ 10 > 8)
{
OffsetGier
= 4;
}
if (TargetGier
< 0)
{
TargetGier
+= 3600;
}
if (TargetGier
> sollGier
)
{
if (TargetGier
- sollGier
< 1800)
{
sollGier
+= OffsetGier
;
}
else
{
sollGier
-= OffsetGier
;
}
}
else
{
if (sollGier
- TargetGier
< 1800)
{
sollGier
-= OffsetGier
;
}
else
{
sollGier
+= OffsetGier
;
}
}
}
/* ****************************************************************************
Functionname: InitGPS */ /*!
Description:
@return void
@pre -
@post -
@author
**************************************************************************** */
void InitGPS
(void)
{
// USART1 Control and Status Register A, B, C and baud rate register
uint8_t sreg
= SREG
;
//uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART1_BAUD) - 1);
// disable all interrupts before reconfiguration
cli
();
// disable RX-Interrupt
UCSR1B
&= ~
(1 << RXCIE1
);
// disable TX-Interrupt
UCSR1B
&= ~
(1 << TXCIE1
);
// disable DRE-Interrupt
UCSR1B
&= ~
(1 << UDRIE1
);
// set direction of RXD1 and TXD1 pins
// set RXD1 (PD2) as an input pin
PORTD
|= (1 << PORTD2
);
DDRD
&= ~
(1 << DDD2
);
// set TXD1 (PD3) as an output pin
PORTD
|= (1 << PORTD3
);
DDRD
|= (1 << DDD3
);
// USART0 Baud Rate Register
// set clock divider
UBRR1H
= 0;
UBRR1L
= BAUDRATE
;
// enable double speed operation
//UCSR1A |= (1 << U2X1);
UCSR1A
= _B0
(U2X1
);
// enable receiver and transmitter
UCSR1B
= (1 << TXEN1
) | (1 << RXEN1
);
// set asynchronous mode
UCSR1C
&= ~
(1 << UMSEL11
);
UCSR1C
&= ~
(1 << UMSEL10
);
// no parity
UCSR1C
&= ~
(1 << UPM11
);
UCSR1C
&= ~
(1 << UPM10
);
// 1 stop bit
UCSR1C
&= ~
(1 << USBS1
);
// 8-bit
UCSR1B
&= ~
(1 << UCSZ12
);
UCSR1C
|= (1 << UCSZ11
);
UCSR1C
|= (1 << UCSZ10
);
// flush receive buffer explicit
while ( UCSR1A
& (1<<RXC1
) ) UDR1
;
// enable interrupts at the end
// enable RX-Interrupt
UCSR1B
|= (1 << RXCIE1
);
// enable TX-Interrupt
UCSR1B
|= (1 << TXCIE1
);
// enable DRE interrupt
//UCSR1B |= (1 << UDRIE1);
// restore global interrupt flags
SREG
= sreg
;
gpsState
= GPS_EMPTY
;
}
/* ****************************************************************************
Functionname: InitGPS */ /*!
Description: Copy GPS paket data to actualPos
@return void
@pre -
@post -
@author
**************************************************************************** */
void GPSscanData
(void)
{
if (navStatus.
packetStatus == 1)// valid packet
{
actualPos.
state = navStatus.
GPSfix;
if ((actualPos.
state > 1) && (GPSTracking
== 0))
{
GRN_FLASH
;
}
navStatus.
packetStatus = 0;
}
if (navPosUtm.
packetStatus == 1)// valid packet
{
actualPos.
north = navPosUtm.
NORTH/10L;
actualPos.
east = navPosUtm.
EAST/10L;
actualPos.
altitude = navPosUtm.
ALT/100;
actualPos.
ITOW = navPosUtm.
ITOW;
navPosUtm.
packetStatus = 0;
}
/*
if (navPosLlh.packetStatus == 1)
{
actualPos.longi = navPosLlh.LON;
actualPos.lati = navPosLlh.LAT;
actualPos.height = navPosLlh.HEIGHT;
navPosLlh.packetStatus = 0;
}
*/
if (navVelNed.
packetStatus == 1)
{
actualPos.
velNorth = navVelNed.
VEL_N;
actualPos.
velEast = navVelNed.
VEL_E;
actualPos.
velDown = navVelNed.
VEL_D;
actualPos.
groundSpeed = navVelNed.
GSpeed;
navVelNed.
packetStatus = 0;
}
}
/* ****************************************************************************
Functionname: SIGNAL */ /*!
Description:
@return void
@pre -
@post -
@author
**************************************************************************** */
SIGNAL
(SIG_USART1_RECV
)
{
uint8_t c
;
uint8_t re
;
re
= (UCSR1A
& (_B1
(FE1
) | _B1
(DOR1
)));// any error occured ?
c
= UDR1
;
if (re
== 0)
{
switch (gpsState
)
{
case GPS_EMPTY
:
if (c
== SYNC_CHAR1
)
{
gpsState
= GPS_SYNC1
;
}
break;
case GPS_SYNC1
:
if (c
== SYNC_CHAR2
)
{
gpsState
= GPS_SYNC2
;
}
else if (c
!= SYNC_CHAR1
)
{
gpsState
= GPS_EMPTY
;
}
break;
case GPS_SYNC2
:
if (c
== CLASS_NAV
)
{
gpsState
= GPS_CLASS
;
}
else
{
gpsState
= GPS_EMPTY
;
}
break;
case GPS_CLASS
:// msg ID seen: init packed receive
msgID
= c
;
CK_A
= CLASS_NAV
+ c
;
CK_B
= CLASS_NAV
+ CK_A
;
gpsState
= GPS_LEN1
;
switch (msgID
)
{
case MSGID_STATUS
:
ubxP
= (char*)&navStatus
;
ubxEp
= (char*)(&navStatus
+ sizeof(NAV_STATUS_t
));
ubxSp
= (char*)&navStatus.
packetStatus;
ignorePacket
= navStatus.
packetStatus;
break;
/*
case MSGID_POSLLH:
ubxP = (char*)&navPosLlh;
ubxEp = (char*)(&navPosLlh + sizeof(NAV_POSLLH_t));
ubxSp = (char*)&navPosLlh.packetStatus;
ignorePacket = navPosLlh.packetStatus;
break;
*/
case MSGID_POSUTM
:
ubxP
= (char*)&navPosUtm
;
ubxEp
= (char*)(&navPosUtm
+ sizeof(NAV_POSUTM_t
));
ubxSp
= (char*)&navPosUtm.
packetStatus;
ignorePacket
= navPosUtm.
packetStatus;
break;
case MSGID_VELNED
:
ubxP
= (char*)&navVelNed
;
ubxEp
= (char*)(&navVelNed
+ sizeof(NAV_VELNED_t
));
ubxSp
= (char*)&navVelNed.
packetStatus;
ignorePacket
= navVelNed.
packetStatus;
break;
default:
ignorePacket
= 1;
ubxSp
= (char*)0;
}
break;
case GPS_LEN1
:// first len byte
msgLen
= c
;
CK_A
+= c
;
CK_B
+= CK_A
;
gpsState
= GPS_LEN2
;
break;
case GPS_LEN2
:// second len byte
msgLen
= msgLen
+ (c
* 256);
CK_A
+= c
;
CK_B
+= CK_A
;
gpsState
= GPS_FILLING
;// next data will be stored in packet struct
break;
case GPS_FILLING
:
CK_A
+= c
;
CK_B
+= CK_A
;
if ( !ignorePacket
&& ubxP
< ubxEp
)
{
*ubxP
++ = c
;
}
if (--msgLen
== 0)
{
gpsState
= GPS_CKA
;
}
break;
case GPS_CKA
:
if (c
== CK_A
)
{
gpsState
= GPS_CKB
;
}
else
{
gpsState
= GPS_EMPTY
;
}
break;
case GPS_CKB
:
if (c
== CK_B
&& ubxSp
)// No error -> packet received successfully
{
*ubxSp
= 1;// set packetStatus in struct
GPSscanData
();
}
gpsState
= GPS_EMPTY
;// ready for next packet
break;
default:
gpsState
= GPS_EMPTY
;// ready for next packet
}
}
else// discard any data if error occured
{
gpsState
= GPS_EMPTY
;
}
}