Finished merging GPS autoconfig + ubx protocol code.

use set gps_type=X in cli to configure, where X=0 if NMEA (no special config), X=1 if UBX (enters ubx binary mode), X=2 if MTK (sets up MTK for 5Hz operation).
changed default GPS rate to 115200 baud
added baudrate reset stuff to UART driver for GPS autoconfigure
NONE of this is tested (except UBX working on my window)

git-svn-id: https://afrodevices.googlecode.com/svn/trunk/baseflight@204 7c89a4a9-59b9-e629-4cfe-3a2d53b20e61
This commit is contained in:
timecop@gmail.com 2012-09-04 16:26:46 +00:00
parent 80d7ba604b
commit b2bc4bf9e6
6 changed files with 2416 additions and 2000 deletions

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,12 @@ typedef enum {
FEATURE_TELEMETRY = 1 << 11,
} AvailableFeatures;
typedef enum {
GPS_NMEA = 0,
GPS_UBLOX,
GPS_MTK,
} GPSHardware;
typedef void (* sensorInitFuncPtr)(void); // sensor init prototype
typedef void (* sensorReadFuncPtr)(int16_t *data); // sensor read and align prototype
typedef int32_t (* baroCalculateFuncPtr)(void); // baro calculation (returns altitude in cm based on static data collected)

View File

@ -184,8 +184,8 @@ void checkFirstTime(bool reset)
cfg.gimbal_roll_mid = 1500;
// gps/nav stuff
cfg.gps_type = 0; // NMEA
cfg.gps_baudrate = 9600;
cfg.gps_type = GPS_NMEA;
cfg.gps_baudrate = 115200;
cfg.gps_wp_radius = 200;
cfg.gps_lpf = 20;
cfg.nav_slew_rate = 30;

View File

@ -157,11 +157,25 @@ uint32_t tx2BufferTail = 0;
uint32_t tx2BufferHead = 0;
bool uart2RxOnly = false;
static void uart2Open(uint32_t speed)
{
USART_InitTypeDef USART_InitStructure;
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = speed;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | (uart2RxOnly ? 0 : USART_Mode_Tx);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
}
void uart2Init(uint32_t speed, uartReceiveCallbackPtr func, bool rxOnly)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
@ -184,21 +198,18 @@ void uart2Init(uint32_t speed, uartReceiveCallbackPtr func, bool rxOnly)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = speed;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | (rxOnly ? 0 : USART_Mode_Tx);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
uart2Open(speed);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
if (!rxOnly)
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
USART_Cmd(USART2, ENABLE);
uart2Callback = func;
}
void uart2ChangeBaud(uint32_t speed)
{
uart2Open(speed);
}
void uart2Write(uint8_t ch)
{
if (uart2RxOnly)

View File

@ -9,6 +9,7 @@ uint8_t uartReadPoll(void);
void uartWrite(uint8_t ch);
void uartPrint(char *str);
// USART2 (
// USART2 (GPS, Spektrum)
void uart2Init(uint32_t speed, uartReceiveCallbackPtr func, bool rxOnly);
void uart2ChangeBaud(uint32_t speed);
void uart2Write(uint8_t ch);

331
src/gps.c
View File

@ -5,20 +5,99 @@
#define sq(x) ((x)*(x))
#endif
uint32_t init_speed[5] = { 9600, 19200, 38400, 57600, 115200 };
static void GPS_NewData(uint16_t c);
static void GPS_set_pids(void);
static void gpsPrint(const char *str);
static const char *gpsInitStrings[] = {
"$PUBX,41,1,0003,0001,19200,0*23\r\n", // UBX0..3
"$PUBX,41,1,0003,0001,38400,0*26\r\n",
"$PUBX,41,1,0003,0001,57600,0*2D\r\n",
"$PUBX,41,1,0003,0001,115200,0*1E\r\n",
"$PMTK251,19200*22\r\n", // MTK4..7
"$PMTK251,38400*27\r\n",
"$PMTK251,57600*2C\r\n",
"$PMTK251,115200*1F\r\n",
};
static const uint8_t ubloxInit[] = {
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x05, 0x00, 0xFF, 0x19, // disable all default NMEA messages
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15,
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xFB, 0x11,
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x00, 0x00, 0xFA, 0x0F,
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x02, 0x00, 0xFC, 0x13,
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x04, 0x00, 0xFE, 0x17,
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x01, 0x0E, 0x47, // set POSLLH MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0x01, 0x0F, 0x49, // set STATUS MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x06, 0x01, 0x12, 0x4F, // set SOL MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1E, 0x67, // set VELNED MSG rate
0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x51, 0x08, 0x00, 0x00, 0x8A, 0x41, // set WAAS to EGNOS
0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A // set rate to 5Hz
};
void gpsInit(uint32_t baudrate)
{
int i;
int offset = 0;
GPS_set_pids();
uart2Init(baudrate, GPS_NewData, false);
if (cfg.gps_type == GPS_UBLOX)
offset = 0;
else if (cfg.gps_type == GPS_MTK)
offset = 4;
if (cfg.gps_type != GPS_NMEA) {
for (i = 0; i < 5; i++) {
uart2ChangeBaud(init_speed[i]);
switch (baudrate) {
case 19200:
gpsPrint(gpsInitStrings[offset]);
break;
case 38400:
gpsPrint(gpsInitStrings[offset + 1]);
break;
case 57600:
gpsPrint(gpsInitStrings[offset + 2]);
break;
case 115200:
gpsPrint(gpsInitStrings[offset + 3]);
break;
}
delay(10);
}
}
uart2ChangeBaud(baudrate);
if (cfg.gps_type == GPS_UBLOX) {
for (i = 0; i < sizeof(ubloxInit); i++) {
uart2Write(ubloxInit[i]); // send ubx init binary
delay(4);
}
} else if (cfg.gps_type == GPS_MTK) {
gpsPrint("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"); // only GGA and RMC sentence
gpsPrint("$PMTK220,200*2C\r\n"); // 5 Hz update rate
}
// catch some GPS frames. TODO check this
delay(500);
delay(1000);
if (GPS_Present)
sensorsSet(SENSOR_GPS);
}
static void gpsPrint(const char *str)
{
while (*str) {
uart2Write(*str);
if (cfg.gps_type == GPS_UBLOX)
delay(4);
str++;
}
}
/*-----------------------------------------------------------
*
* Multiwii GPS code - revision: 1097
@ -46,6 +125,8 @@ static void GPS_calc_nav_rate(int max_speed);
static void GPS_update_crosstrack(void);
static bool GPS_newFrame(char c);
static bool GPS_NMEA_newFrame(char c);
static bool GPS_UBLOX_newFrame(uint8_t data);
static bool UBLOX_parse_gps(void);
static int16_t GPS_calc_desired_speed(int16_t max_speed, bool _slow);
int32_t wrap_18000(int32_t error);
static int32_t wrap_36000(int32_t angle);
@ -669,11 +750,11 @@ static uint8_t hex_c(uint8_t n)
static bool GPS_newFrame(char c)
{
switch (cfg.gps_type) {
case 0: // NMEA
case GPS_NMEA: // NMEA
case GPS_MTK: // MTK outputs NMEA too
return GPS_NMEA_newFrame(c);
case 1: // UBX
return false; // GPS_UBLOX_newFrame(c);
case GPS_UBLOX: // UBX
return GPS_UBLOX_newFrame(c);
}
return false;
@ -761,3 +842,243 @@ static bool GPS_NMEA_newFrame(char c)
GPS_Present = 1;
return frameOK && (frame == FRAME_GGA);
}
// UBX support
typedef struct {
uint8_t preamble1;
uint8_t preamble2;
uint8_t msg_class;
uint8_t msg_id;
uint16_t length;
} ubx_header;
typedef struct {
uint32_t time; // GPS msToW
int32_t longitude;
int32_t latitude;
int32_t altitude_ellipsoid;
int32_t altitude_msl;
uint32_t horizontal_accuracy;
uint32_t vertical_accuracy;
} ubx_nav_posllh;
typedef struct {
uint32_t time; // GPS msToW
uint8_t fix_type;
uint8_t fix_status;
uint8_t differential_status;
uint8_t res;
uint32_t time_to_first_fix;
uint32_t uptime; // milliseconds
} ubx_nav_status;
typedef struct {
uint32_t time;
int32_t time_nsec;
int16_t week;
uint8_t fix_type;
uint8_t fix_status;
int32_t ecef_x;
int32_t ecef_y;
int32_t ecef_z;
uint32_t position_accuracy_3d;
int32_t ecef_x_velocity;
int32_t ecef_y_velocity;
int32_t ecef_z_velocity;
uint32_t speed_accuracy;
uint16_t position_DOP;
uint8_t res;
uint8_t satellites;
uint32_t res2;
} ubx_nav_solution;
typedef struct {
uint32_t time; // GPS msToW
int32_t ned_north;
int32_t ned_east;
int32_t ned_down;
uint32_t speed_3d;
uint32_t speed_2d;
int32_t heading_2d;
uint32_t speed_accuracy;
uint32_t heading_accuracy;
} ubx_nav_velned;
enum {
PREAMBLE1 = 0xb5,
PREAMBLE2 = 0x62,
CLASS_NAV = 0x01,
CLASS_ACK = 0x05,
CLASS_CFG = 0x06,
MSG_ACK_NACK = 0x00,
MSG_ACK_ACK = 0x01,
MSG_POSLLH = 0x2,
MSG_STATUS = 0x3,
MSG_SOL = 0x6,
MSG_VELNED = 0x12,
MSG_CFG_PRT = 0x00,
MSG_CFG_RATE = 0x08,
MSG_CFG_SET_RATE = 0x01,
MSG_CFG_NAV_SETTINGS = 0x24
} ubs_protocol_bytes;
enum {
FIX_NONE = 0,
FIX_DEAD_RECKONING = 1,
FIX_2D = 2,
FIX_3D = 3,
FIX_GPS_DEAD_RECKONING = 4,
FIX_TIME = 5
} ubs_nav_fix_type;
enum {
NAV_STATUS_FIX_VALID = 1
} ubx_nav_status_bits;
// Packet checksum accumulators
static uint8_t _ck_a;
static uint8_t _ck_b;
// State machine state
static uint8_t _step;
static uint8_t _msg_id;
static uint16_t _payload_length;
static uint16_t _payload_counter;
static bool next_fix;
static uint8_t _class;
// do we have new position information?
static bool _new_position;
// do we have new speed information?
static bool _new_speed;
static uint8_t _disable_counter;
// Receive buffer
static union {
ubx_nav_posllh posllh;
ubx_nav_status status;
ubx_nav_solution solution;
ubx_nav_velned velned;
uint8_t bytes[64];
} _buffer;
void _update_checksum(uint8_t *data, uint8_t len, uint8_t *ck_a, uint8_t *ck_b)
{
while (len--) {
*ck_a += *data;
*ck_b += *ck_a;
data++;
}
}
static bool GPS_UBLOX_newFrame(uint8_t data)
{
bool parsed = false;
switch (_step) {
case 1:
if (PREAMBLE2 == data) {
_step++;
break;
}
_step = 0;
case 0:
if (PREAMBLE1 == data)
_step++;
break;
case 2:
_step++;
_class = data;
_ck_b = _ck_a = data; // reset the checksum accumulators
break;
case 3:
_step++;
_ck_b += (_ck_a += data); // checksum byte
_msg_id = data;
break;
case 4:
_step++;
_ck_b += (_ck_a += data); // checksum byte
_payload_length = data; // payload length low byte
break;
case 5:
_step++;
_ck_b += (_ck_a += data); // checksum byte
_payload_length += (uint16_t) (data << 8);
if (_payload_length > 512) {
_payload_length = 0;
_step = 0;
}
_payload_counter = 0; // prepare to receive payload
break;
case 6:
_ck_b += (_ck_a += data); // checksum byte
if (_payload_counter < sizeof(_buffer)) {
_buffer.bytes[_payload_counter] = data;
}
if (++_payload_counter == _payload_length)
_step++;
break;
case 7:
_step++;
if (_ck_a != data)
_step = 0; // bad checksum
break;
case 8:
_step = 0;
if (_ck_b != data)
break; // bad checksum
GPS_Present = 1;
if (UBLOX_parse_gps()) {
parsed = true;
}
} //end switch
return parsed;
}
static bool UBLOX_parse_gps(void)
{
switch (_msg_id) {
case MSG_POSLLH:
//i2c_dataset.time = _buffer.posllh.time;
GPS_coord[LON] = _buffer.posllh.longitude;
GPS_coord[LAT] = _buffer.posllh.latitude;
GPS_altitude = _buffer.posllh.altitude_msl / 10 / 100; //alt in m
f.GPS_FIX = next_fix;
_new_position = true;
break;
case MSG_STATUS:
next_fix = (_buffer.status.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.status.fix_type == FIX_3D);
if (!next_fix)
f.GPS_FIX = false;
break;
case MSG_SOL:
next_fix = (_buffer.solution.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.solution.fix_type == FIX_3D);
if (!next_fix)
f.GPS_FIX = false;
GPS_numSat = _buffer.solution.satellites;
// GPS_hdop = _buffer.solution.position_DOP;
// debug[3] = GPS_hdop;
break;
case MSG_VELNED:
// speed_3d = _buffer.velned.speed_3d; // cm/s
GPS_speed = _buffer.velned.speed_2d; // cm/s
GPS_ground_course = (uint16_t) (_buffer.velned.heading_2d / 10000); // Heading 2D deg * 100000 rescaled to deg * 10
_new_speed = true;
break;
default:
return false;
}
// we only return true when we get new position and speed data
// this ensures we don't use stale data
if (_new_position && _new_speed) {
_new_speed = _new_position = false;
return true;
}
return false;
}