Skip to content

Commit 5666185

Browse files
dr-obliviumf5soh
authored andcommitted
Merged in Oblivium/librepilot/LP-536_GNSS_improvements (pull request #444)
LP-536 GNSS improvements Approved-by: Lalanne Laurent <f5soh@free.fr> Approved-by: Brian Webb <webbbn@gmail.com> Approved-by: Alessio Morale <alessiomorale@gmail.com> Approved-by: Philippe Renon <philippe_renon@yahoo.fr> Approved-by: Jan NIJS <dr.oblivium@gmail.com>
2 parents a62064d + c1aeb9f commit 5666185

27 files changed

Lines changed: 1167 additions & 557 deletions

flight/modules/GPS/GPS.c

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,30 +105,52 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev);
105105
// the new location with Set = true.
106106
#define GPS_HOMELOCATION_SET_DELAY 5000
107107

108-
#define GPS_LOOP_DELAY_MS 6
108+
// PIOS serial port receive buffer for GPS is set to 32 bytes for the minimal and 128 bytes for the full version.
109+
// GPS_READ_BUFFER is defined a few lines below in this file.
110+
//
111+
// 57600 bps = 5760 bytes per second
112+
//
113+
// For 32 bytes buffer: this is a maximum of 5760/32 = 180 buffers per second
114+
// that is 1/180 = 0.0056 seconds per packet
115+
// We must never wait more than 5ms since packet was last drained or it may overflow
116+
//
117+
// For 128 bytes buffer: this is a maximum of 5760/128 = 45 buffers per second
118+
// that is 1/45 = 0.022 seconds per packet
119+
// We must never wait more than 22ms since packet was last drained or it may overflow
120+
121+
// There are two delays in play for the GPS task:
122+
// - GPS_BLOCK_ON_NO_DATA_MS is the time to block while waiting to receive serial data from the GPS
123+
// - GPS_LOOP_DELAY_MS is used for a context switch initiated by calling vTaskDelayUntil() to let other tasks run
124+
//
125+
// The delayMs time is not that critical. It should not be too high so that maintenance actions within this task
126+
// are run often enough.
127+
// GPS_LOOP_DELAY_MS on the other hand, should be less then 5.55 ms. A value set too high will cause data to be dropped.
128+
129+
#define GPS_LOOP_DELAY_MS 5
130+
#define GPS_BLOCK_ON_NO_DATA_MS 20
109131

110132
#ifdef PIOS_GPS_SETS_HOMELOCATION
111133
// Unfortunately need a good size stack for the WMM calculation
112-
#define STACK_SIZE_BYTES 1024
134+
#define STACK_SIZE_BYTES 1024
113135
#else
114136
#if defined(PIOS_GPS_MINIMAL)
115-
#define GPS_READ_BUFFER 32
137+
#define GPS_READ_BUFFER 32
116138

117139
#ifdef PIOS_INCLUDE_GPS_NMEA_PARSER
118-
#define STACK_SIZE_BYTES 580 // NMEA
119-
#else
120-
#define STACK_SIZE_BYTES 440 // UBX
140+
#define STACK_SIZE_BYTES 580 // NMEA
141+
#else // PIOS_INCLUDE_GPS_NMEA_PARSER
142+
#define STACK_SIZE_BYTES 440 // UBX
121143
#endif // PIOS_INCLUDE_GPS_NMEA_PARSER
122-
#else
123-
#define STACK_SIZE_BYTES 650
144+
#else // PIOS_GPS_MINIMAL
145+
#define STACK_SIZE_BYTES 650
124146
#endif // PIOS_GPS_MINIMAL
125147
#endif // PIOS_GPS_SETS_HOMELOCATION
126148

127149
#ifndef GPS_READ_BUFFER
128-
#define GPS_READ_BUFFER 128
150+
#define GPS_READ_BUFFER 128
129151
#endif
130152

131-
#define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
153+
#define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
132154

133155
// ****************
134156
// Private variables
@@ -284,14 +306,7 @@ MODULE_INITCALL(GPSInitialize, GPSStart);
284306

285307
static void gpsTask(__attribute__((unused)) void *parameters)
286308
{
287-
// 57600 baud = 5760 bytes per second
288-
// PIOS serial buffers appear to be 32 bytes long
289-
// that is a maximum of 5760/32 = 180 buffers per second
290-
// that is 1/180 = 0.005555556 seconds per packet
291-
// we must never wait more than 5ms since packet was last drained or it may overflow
292-
// 100ms is way slow too, considering we do everything possible to make the sensor data as contemporary as possible
293-
portTickType xDelay = 5 / portTICK_RATE_MS;
294-
uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
309+
uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
295310

296311
#ifdef PIOS_GPS_SETS_HOMELOCATION
297312
portTickType homelocationSetDelay = 0;
@@ -353,8 +368,8 @@ static void gpsTask(__attribute__((unused)) void *parameters)
353368

354369
uint16_t cnt;
355370
int res;
356-
// This blocks the task until there is something on the buffer (or 100ms? passes)
357-
cnt = PIOS_COM_ReceiveBuffer(gpsPort, c, GPS_READ_BUFFER, xDelay);
371+
// This blocks the task until there is something in the buffer (or GPS_BLOCK_ON_NO_DATA_MS passes)
372+
cnt = PIOS_COM_ReceiveBuffer(gpsPort, c, GPS_READ_BUFFER, GPS_BLOCK_ON_NO_DATA_MS);
358373
res = PARSER_INCOMPLETE;
359374
if (cnt > 0) {
360375
PERF_TIMED_SECTION_START(counterParse);
@@ -416,7 +431,7 @@ static void gpsTask(__attribute__((unused)) void *parameters)
416431
//
417432
// if (the fix is good) {
418433
if ((gpspositionsensor.PDOP < gpsSettings.MaxPDOP) && (gpspositionsensor.Satellites >= gpsSettings.MinSatellites) &&
419-
(gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
434+
((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) &&
420435
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
421436
AlarmsClear(SYSTEMALARMS_ALARM_GPS);
422437
#ifdef PIOS_GPS_SETS_HOMELOCATION
@@ -436,7 +451,7 @@ static void gpsTask(__attribute__((unused)) void *parameters)
436451
}
437452
#endif
438453
// else if (we are at least getting what might be usable GPS data to finish a flight with) {
439-
} else if ((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
454+
} else if (((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) &&
440455
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
441456
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING);
442457
// else data is probably not good enough to fly

flight/modules/GPS/UBX.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,35 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
173173
#if defined(PIOS_GPS_MINIMAL)
174174
restart_state = RESTART_NO_ERROR;
175175
#else
176-
restart_state = RESTART_WITH_ERROR;
176+
/* UBX-NAV-SVINFO (id 30) and UBX-NAV-SAT (id 35) packets are NOT critical to the navigation.
177+
Their only use is to update the nice GPS constellation widget in the GCS.
178+
These packets become very large when a lot of SV (Space Vehicles) are tracked. (8 + 12 * <number of SV>) bytes
179+
180+
In the case of 3 simultaneously enabled GNSS, it is easy to reach the currently defined tracking limit of 32 SV.
181+
The memory taken up by this is 8 + 12 * 32 = 392 bytes
182+
183+
The NEO-M8N has been seen to send out information for more than 32 SV. This causes overflow errors.
184+
We will ignore these informational packets if they become too large.
185+
The downside of this is no more constellation updates in the GCS when we reach the limit.
186+
187+
An alternative fix could be to increment the maximum number of satellites: MAX_SVS and UBX_CFG_GNSS_NUMCH_VER8 in UBX.h
188+
This would use extra memory for little gain. Both fixes can be combined.
189+
190+
Tests indicate that, once we reach this amount of tracked SV, the NEO-M8N module positioning output
191+
becomes jittery (in time) and therefore less accurate.
192+
193+
The recommendation is to limit the maximum number of simultaneously used GNSS to a value of 2.
194+
This will help keep the number of tracked satellites in line.
195+
*/
196+
if ((ubx->header.class == 0x01) && ((ubx->header.id == 0x30) || (ubx->header.id == 0x35))) {
197+
restart_state = RESTART_NO_ERROR;
198+
} else {
199+
restart_state = RESTART_WITH_ERROR;
200+
}
177201
#endif
202+
// We won't see the end of the packet. Which means it is useless to do any further processing.
203+
// Therefore scan for the start of the next packet.
204+
proto_state = START;
178205
break;
179206
} else {
180207
if (ubx->header.len == 0) {
@@ -337,7 +364,7 @@ static void parse_ubx_nav_sol(struct UBXPacket *ubx, GPSPositionSensorData *GpsP
337364
GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX2D;
338365
break;
339366
case STATUS_GPSFIX_3DFIX:
340-
GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX3D;
367+
GpsPosition->Status = (sol->flags & STATUS_FLAGS_DIFFSOLN) ? GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS : GPSPOSITIONSENSOR_STATUS_FIX3D;
341368
break;
342369
default: GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX;
343370
}
@@ -399,10 +426,18 @@ static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsP
399426
GpsPosition->Longitude = pvt->lon;
400427
GpsPosition->Satellites = pvt->numSV;
401428
GpsPosition->PDOP = pvt->pDOP * 0.01f;
429+
402430
if (pvt->flags & PVT_FLAGS_GNSSFIX_OK) {
403-
GpsPosition->Status = pvt->fixType == PVT_FIX_TYPE_3D ?
404-
GPSPOSITIONSENSOR_STATUS_FIX3D : GPSPOSITIONSENSOR_STATUS_FIX2D;
405-
} else {
431+
switch (pvt->fixType) {
432+
case PVT_FIX_TYPE_2D:
433+
GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX2D;
434+
break;
435+
case PVT_FIX_TYPE_3D:
436+
GpsPosition->Status = (pvt->flags & PVT_FLAGS_DIFFSOLN) ? GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS : GPSPOSITIONSENSOR_STATUS_FIX3D;
437+
break;
438+
default: GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX;
439+
}
440+
} else { // fix is not valid so we make sure to treat is as NOFIX
406441
GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX;
407442
}
408443

flight/modules/Osd/OsdEtStd/OsdEtStd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ static void Run(void)
450450
// positionData.Status, positionData.Satellites, (uint32_t)positionData.Altitude);
451451

452452
// GPS Status
453-
if (positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) {
453+
if ((positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) {
454454
msg[OSDMSG_GPS_STAT] = OSDMSG_GPS_STAT_FIX;
455455
} else {
456456
msg[OSDMSG_GPS_STAT] = OSDMSG_GPS_STAT_NOFIX;

flight/modules/StateEstimation/filterlla.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static filterResult filter(__attribute__((unused)) stateFilter *self, stateEstim
104104

105105
// check if we have a valid GPS signal (not checked by StateEstimation istelf)
106106
if ((gpsdata.PDOP < this->settings.MaxPDOP) && (gpsdata.Satellites >= this->settings.MinSatellites) &&
107-
(gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
107+
((gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) &&
108108
(gpsdata.Latitude != 0 || gpsdata.Longitude != 0)) {
109109
int32_t LLAi[3] = {
110110
gpsdata.Latitude,

flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ static void uavoFrSKYSensorHubBridgeTask(__attribute__((unused)) void *parameter
382382
status = 300;
383383
break;
384384
case GPSPOSITIONSENSOR_STATUS_FIX3D:
385+
case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS:
385386
if (hl_set == HOMELOCATION_SET_TRUE) {
386387
status = 500;
387388
} else {
@@ -419,7 +420,8 @@ static void uavoFrSKYSensorHubBridgeTask(__attribute__((unused)) void *parameter
419420
msg_length += frsky_pack_temperature_02((vdop * 256 + hdop), shub_global->serial_buf + msg_length);
420421

421422
if (gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX2D ||
422-
gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) {
423+
gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D ||
424+
gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS) {
423425
msg_length += frsky_pack_gps(
424426
gpsPosData.Heading,
425427
gpsPosData.Latitude,

flight/modules/UAVOHottBridge/uavohottbridge.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ uint16_t build_GPS_message(struct hott_gps_message *msg)
357357
msg->gps_fix_char = '2';
358358
break;
359359
case GPSPOSITIONSENSOR_STATUS_FIX3D:
360+
case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS:
360361
msg->gps_fix_char = '3';
361362
break;
362363
default:

flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ static void mavlink_send_position()
320320
gps_fix_type = 2;
321321
break;
322322
case GPSPOSITIONSENSOR_STATUS_FIX3D:
323+
case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS:
323324
gps_fix_type = 3;
324325
break;
325326
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
******************************************************************************
3+
*
4+
* @file flatearthwidget.cpp
5+
* @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017.
6+
* Edouard Lafargue Copyright (C) 2010.
7+
* @addtogroup GCSPlugins GCS Plugins
8+
* @{
9+
* @addtogroup FlatEarthWidget FlatEarth Widget Plugin
10+
* @{
11+
* @brief A widget for visualizing a location on a flat map of the world.
12+
*****************************************************************************/
13+
/*
14+
* This program is free software; you can redistribute it and/or modify
15+
* it under the terms of the GNU General Public License as published by
16+
* the Free Software Foundation; either version 3 of the License, or
17+
* (at your option) any later version.
18+
*
19+
* This program is distributed in the hope that it will be useful, but
20+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22+
* for more details.
23+
*
24+
* You should have received a copy of the GNU General Public License
25+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
26+
*/
27+
28+
#include "flatearthwidget.h"
29+
#include <QtSvg/QSvgRenderer>
30+
#include <QtSvg/QGraphicsSvgItem>
31+
#include <math.h> /* fabs */
32+
33+
#define MARKER_SIZE 40.0
34+
35+
FlatEarthWidget::FlatEarthWidget(QWidget *parent) : QGraphicsView(parent)
36+
{
37+
// Disable scrollbars to prevent an "always updated loop"
38+
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
39+
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
40+
41+
// Show the whole world by default
42+
zoomedin = false;
43+
44+
// Set initial location
45+
oldLat = oldLon = 0;
46+
47+
// Draw the earth
48+
earthScene = new QGraphicsScene(this);
49+
QPixmap earthpix(":/gpsgadget/images/flatEarth.jpg");
50+
earthPixmapItem = earthScene->addPixmap(earthpix);
51+
this->setScene(earthScene);
52+
53+
// Draw the marker
54+
marker = new QGraphicsSvgItem();
55+
QSvgRenderer *renderer = new QSvgRenderer();
56+
renderer->load(QString(":/gpsgadget/images/marker.svg"));
57+
marker->setSharedRenderer(renderer);
58+
earthScene->addItem(marker);
59+
}
60+
61+
FlatEarthWidget::~FlatEarthWidget()
62+
{
63+
delete earthScene;
64+
earthScene = NULL;
65+
}
66+
67+
/*
68+
* Refresh the map on first showing
69+
*/
70+
void FlatEarthWidget::showEvent(QShowEvent *event)
71+
{
72+
Q_UNUSED(event)
73+
74+
refreshMap();
75+
}
76+
77+
/*
78+
* Refresh the map while resizing the widget
79+
*/
80+
void FlatEarthWidget::resizeEvent(QResizeEvent *event)
81+
{
82+
Q_UNUSED(event)
83+
84+
refreshMap();
85+
}
86+
87+
/*
88+
* Toggle zoom state on mouse click event
89+
*/
90+
void FlatEarthWidget::mousePressEvent(QMouseEvent *event)
91+
{
92+
Q_UNUSED(event)
93+
94+
// toggle zoom state and refresh the map
95+
zoomedin = !zoomedin;
96+
refreshMap();
97+
}
98+
99+
/*
100+
* Update the position of the marker on the map
101+
*/
102+
void FlatEarthWidget::setPosition(double lat, double lon, bool forceUpdate)
103+
{
104+
/* Only perform this expensive graphics operation if the position has changed enough
105+
to be visible on the map. Or if an update is requested by force.
106+
*/
107+
if (fabs(oldLat - lat) > 0.1 || fabs(oldLon - lon) > 0.1 || forceUpdate) {
108+
double wscale = this->sceneRect().width() / 360;
109+
double hscale = this->sceneRect().height() / 180;
110+
QPointF opd = QPointF((lon + 180) * wscale - marker->boundingRect().width() * marker->scale() / 2,
111+
(90 - lat) * hscale - marker->boundingRect().height() * marker->scale() / 2);
112+
marker->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false);
113+
114+
// Center the map on the uav position
115+
if (zoomedin) {
116+
this->centerOn(marker);
117+
}
118+
}
119+
oldLat = lat;
120+
oldLon = lon;
121+
}
122+
123+
/*
124+
* Update the scale of the map
125+
*/
126+
void FlatEarthWidget::refreshMap(void)
127+
{
128+
double markerScale;
129+
130+
if (zoomedin) {
131+
// Hide the marker
132+
marker->setVisible(false);
133+
134+
// Zoom the map to it's native resolution
135+
this->resetTransform();
136+
137+
// Center the map on the uav position
138+
this->centerOn(marker);
139+
140+
// Rescale the marker dimensions to keep the same appearance in both zoom levels
141+
markerScale = MARKER_SIZE / 100.0 * (double)this->rect().width() / (double)(earthPixmapItem->boundingRect().width());
142+
marker->setScale(markerScale);
143+
144+
// Show the marker again
145+
marker->setVisible(true);
146+
} else {
147+
// Hide the marker
148+
marker->setVisible(false);
149+
150+
// Fit the whole world
151+
this->fitInView(earthPixmapItem, Qt::KeepAspectRatio);
152+
153+
// Rescale the marker dimensions to keep the same appearance in both zoom levels
154+
markerScale = MARKER_SIZE / 100.0;
155+
marker->setScale(markerScale);
156+
157+
// Show the marker again
158+
marker->setVisible(true);
159+
}
160+
// force an update of the marker position
161+
this->setPosition(oldLat, oldLon, true);
162+
}

0 commit comments

Comments
 (0)