-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add GPS Lap Timer #11856
Add GPS Lap Timer #11856
Conversation
This comment has been minimized.
This comment has been minimized.
src/main/cli/settings.h
Outdated
@@ -185,8 +187,8 @@ typedef enum { | |||
#define VALUE_MODE_MASK (0xE0) | |||
|
|||
typedef struct cliMinMaxConfig_s { | |||
const int16_t min; | |||
const int16_t max; | |||
const int32_t min; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will double size of cliValueConfig_t
, considerably increasing flash size.
Maybe just assume that int32 has symmetric limits and use d32Max. But it will need some more general six in future
src/main/fc/gps_lap_timer.h
Outdated
|
||
typedef struct gpsLapTimerData_s { | ||
gpsLocation_t gateLocation; | ||
uint32_t previousLaps[3]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use #define for lap history. It bill make rest of code slightly cleaner (for
instead of inlining 3 readings)
src/main/io/gps.c
Outdated
@@ -683,7 +685,17 @@ void gpsInitUblox(void) | |||
} | |||
break; | |||
case 12: | |||
ubloxSetNavRate(0x64, 1, 1); // set rate to 10Hz (measurement period: 100ms, navigation rate: 1 cycle) (for 5Hz use 0xC8) | |||
switch (gpsConfig()->gps_update_rate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using array mapping index to {0xc8,0x64,0x35} and maybe #defining it's context near GPS_UPDATE_RATE_xHZ will be cleaner,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I want to just use an int to store the update rate.
The easiest way to do that would be to store it as a period in milliseconds, because that can be passed straight to the existing ubloxSetNavRate
function.
The other way, which would be easier for the user, would be to store it as a rate in Hz and have ubloxSetNavRate
convert the Hz to a period. The problem here is that the rates may not be integers. The max rate I found to work on my units was 53ms, or 18.86Hz. So then we would set the max allowed value to 19Hz, but clamp the calculated period to 53ms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO using enum is a bit better here. It will prevent users using values that don't work. Without error message, this can be support nightmare.
src/main/io/gps.h
Outdated
GPS_UPDATE_RATE_10HZ, | ||
GPS_UPDATE_RATE_19HZ | ||
} gpsUpdateRate_e; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define GPS_UPDATE_RATE__MAP {0xc8,0x64,0x35}
or similar, see above
src/main/osd/osd.c
Outdated
uint32_t lapTimeSeconds; | ||
uint32_t lapTimeDecimals; | ||
if (gpsLapTimerData.best3Consec != 0) { | ||
lapTimeSeconds = gpsLapTimerData.best3Consec / 1000; | ||
lapTimeDecimals = (gpsLapTimerData.best3Consec % 1000) / 10; | ||
tfp_sprintf(buff, "%3u.%02u", lapTimeSeconds, lapTimeDecimals); | ||
} else { | ||
tfp_sprintf(buff, " -.--"); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be replaced with function (maybe including optional prefix character/string /empty value), removing lot of code duplication
src/main/osd/osd.c
Outdated
lapTimeSeconds = gpsLapTimerData.bestLapTime / 1000; | ||
lapTimeDecimals = (gpsLapTimerData.bestLapTime % 1000) / 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused code
@@ -1014,8 +1015,18 @@ static void osdElementGpsHomeDirection(osdElementParms_t *element) | |||
{ | |||
if (STATE(GPS_FIX) && STATE(GPS_FIX_HOME)) { | |||
if (GPS_distanceToHome > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(technically, gpsLapTimerData.timerRunning will be ignored with GPS_distanceToHome == 0)
Also, does code below handle correctly case when distance to gate is zero?
src/main/osd/osd_elements.c
Outdated
#ifdef USE_GPS_LAP_TIMER | ||
// Change the "home" point to the start/finish location if the lap timer is running | ||
if (gpsLapTimerData.timerRunning) { | ||
const int h = gpsLapTimerData.dirToPoint/100 - DECIDEGREES_TO_DEGREES(attitude.values.yaw); | ||
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | ||
} else { | ||
#endif | ||
const int h = DECIDEGREES_TO_DEGREES(GPS_directionToHome - attitude.values.yaw); | ||
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | ||
#ifdef USE_GPS_LAP_TIMER | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifdef USE_GPS_LAP_TIMER | |
// Change the "home" point to the start/finish location if the lap timer is running | |
if (gpsLapTimerData.timerRunning) { | |
const int h = gpsLapTimerData.dirToPoint/100 - DECIDEGREES_TO_DEGREES(attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
} else { | |
#endif | |
const int h = DECIDEGREES_TO_DEGREES(GPS_directionToHome - attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
#ifdef USE_GPS_LAP_TIMER | |
} | |
#endif | |
do { | |
#ifdef USE_GPS_LAP_TIMER | |
// Override the "home" point to the start/finish location if the lap timer is running | |
if (gpsLapTimerData.timerRunning) { | |
const int h = gpsLapTimerData.dirToPoint/100 - DECIDEGREES_TO_DEGREES(attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
break; | |
} | |
#endif | |
const int h = DECIDEGREES_TO_DEGREES(GPS_directionToHome - attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
} while(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely need to fix this section. Is there any reason not to do it like this? It uses a non-const int, but I assume that doesn't make it to the machine code anyways, right?
#ifdef USE_GPS_LAP_TIMER | |
// Change the "home" point to the start/finish location if the lap timer is running | |
if (gpsLapTimerData.timerRunning) { | |
const int h = gpsLapTimerData.dirToPoint/100 - DECIDEGREES_TO_DEGREES(attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
} else { | |
#endif | |
const int h = DECIDEGREES_TO_DEGREES(GPS_directionToHome - attitude.values.yaw); | |
element->buff[0] = osdGetDirectionSymbolFromHeading(h); | |
#ifdef USE_GPS_LAP_TIMER | |
} | |
#endif | |
int direction = GPS_directionToHome | |
#ifdef USE_GPS_LAP_TIMER | |
// Override the "home" point to the start/finish location if the lap timer is running | |
if (gpsLapTimerData.timerRunning) { | |
direction = gpsLapTimerData.dirToPoint/10; // dirToPoint is centidegrees | |
} | |
#endif | |
element->buff[0] = osdGetDirectionSymbolFromHeading(DECIDEGREES_TO_DEGREES(direction - attitude.values.yaw)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, overriding direction is fine.
My comment was mainly about two #ifdef mixed into C block, it is too easy to break with future changes.
src/main/osd/osd_elements.c
Outdated
#ifdef USE_GPS_LAP_TIMER | ||
static void osdElementGpsLapTimeCurrent(osdElementParms_t *element) | ||
{ | ||
uint32_t lapTimeSeconds = gpsLapTimerData.currentLapTime / 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(see above; prefix variant)
Also, isn't -:--
possible here too ?
src/main/target/common_pre.h
Outdated
@@ -373,7 +373,7 @@ extern uint8_t _dmaram_end__; | |||
#define USE_CANVAS | |||
#define USE_FRSKYOSD | |||
#define USE_GPS | |||
#define USE_GPS_NMEA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like quite intrusive change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. This was done mostly just let me test. We will have to discuss feature priority. I understand keeping NMEA for whacky receivers that can't do UBLOX. How do we decide which features go away when making room for new ones?
AUTOMERGE: (FAIL)
|
Thanks for the through review, @ledvinap! Just what I've been waiting for. |
BTW: What about using home position as a gate? Gate positioning code would apply to home (which may be useful for other purposes), only problem I see is unintended flyaway when someone saves different site as home (I heard of $20k drone flying back to Africa on first test) |
Can you explain more? I don't see how it would be helpful. |
Current code uses concept of 'home' location. It is initialized on arming and used for HOME info on OSD and RTH code. But it is quite similar to your gate location. |
e90cab0
to
faa3465
Compare
This comment has been minimized.
This comment has been minimized.
I see what you're talking about now. I think a non-volatile RTH position wouldn't be desirable because of flyaways. I could see it being cool to have a completely separate "POI" with a distance and pointer that you could have set at your vacation home or an airport, but I don't feel like betaflight is the right place for a secondary airfield feature. |
86272c1
to
48a8c56
Compare
Very cool! Thanks @ledvinap for your assistance. Can I clarify that GPS Rescue can still be activated via switch or RC loss, while this function is active? I can imagine this opening up the possibility of relatively long-distance races where a functional GPS Rescue could be required, even if the user wants to use GPS to time their laps. Also, GPS Rescue now does good landings. I can imagine that if the user chose the 'set home point once' rescue option, and arms once at the landing point, then they could go racing with this, do their laps, and at the end just hit GPS Rescue switch, and it would bring back and land at the correct spot. Hence I think that keeping the GPS Rescue capability and its home point separate, and both functional, would be good. How much extra flash space is required? |
I haven't tested GPS Rescue while the timer is running, but I can't imagine any way it would interfere. I'm not planning to overwrite the home point at all other than hijacking the OSD element. Even that isn't necessary if we want to make two new elements for distance and direction to the gate. I'm not controlling flight or injecting positioning data to existing structs. Not sure on flash space. After implementing some of the suggestions here, I was able to build for all targets within the flash limits without removing any other features. Unfortunately I am too busy to work on this any more this month. The code still needs some changes done, so this isn't ready for testing yet. |
OK thanks for the heads up. |
src/main/fc/gps_lap_timer.c
Outdated
#define MIN(a,b) (((a)<(b))?(a):(b)) | ||
#define MAX(a,b) (((a)>(b))?(a):(b)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define MIN(a,b) (((a)<(b))?(a):(b)) | |
#define MAX(a,b) (((a)>(b))?(a):(b)) |
These macros are defined in common/maths.h
, so we can remove them here.
Why would GPS Rescue not work with this active? This is the normal acro mode we are used to, just with OSD elements for lap times that is using the GPS data to get times. This is not some fancy flight mode that could potentially block other flight modes. |
@SpencerGraffunder can you update this so it's ready for 4.5? Looks like some changes were requested but the feature freeze was missed. However it's a great looking feature so please update as I'm sure this will be popular. |
Feature freeze wasn't missed. This PR was opened well before the feature freeze so no problem 👍 |
thanks for the correction, was worried this wasn't making the cut. Even better news! |
Co-authored-by: Jan Post <Rm2k-Freak@web.de>
eab3a02
to
8ee2e74
Compare
This comment has been minimized.
This comment has been minimized.
@SteveCEvans are the requested changes resolved? |
} else { | ||
// Just left the circle, so record the lap time | ||
if (wasInCircle) { | ||
// Not the first time through the gate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with this PR, but as a possible future enhancement would we be able to get better timing accuracy with a smaller circle size qualified with an exit direction? Setting this direction would be a potential challenge, perhaps requiring training on a practice lap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have a compass you could dial in the heading of the gate directly through the CMS menu or CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveCEvans IIRC gate time is taken at closest point to gate (minimum distance is tracked, with timestamp). So actual gate size should not matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An exit direction could help by letting us make the circle bigger and not be caught by other parts of the track. Since it's using the closest point to the gate waypoint, I think that's the most accurate we can be without correcting the gate waypoint. I'm sure there is a lot more we could do with this in the future. Split times and auto-correcting the start/finish point are two things I've thought of.
This comment has been minimized.
This comment has been minimized.
I think I've resolved everything. Does the INT32 stuff still need to be changed, @ledvinap? |
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Jan Post <Rm2k-Freak@web.de>
Do you want to test this code? Here you have an automated build:
WARNING: It may be unstable. Use only for testing! |
Hi , I want to run a test for this new feature but failed.
What should I do next ? |
Thx for reply. |
Don't use |
* Add gps lap timer * change timing to GPS time instead of local time * rebase and minor changes * implement KarateBrot's suggestions * follow ledvinap's suggestions, some OSD symbol changes * move platform.h include to the top Co-authored-by: Jan Post <Rm2k-Freak@web.de> * fix osd elements not showing, remove useless block * cleanup, move pg stuff to pg folder * cleanup from review * minor mods to gps lap timer update, add number of laps tracked * rename time variable * add const to timeMs Co-authored-by: Jan Post <Rm2k-Freak@web.de> * Update licenses, add is_sys_element macro * update licenses * round to nearest centisecond Co-authored-by: Jan Post <Rm2k-Freak@web.de> --------- Co-authored-by: Jan Post <Rm2k-Freak@web.de>
* Add gps lap timer * change timing to GPS time instead of local time * rebase and minor changes * implement KarateBrot's suggestions * follow ledvinap's suggestions, some OSD symbol changes * move platform.h include to the top Co-authored-by: Jan Post <Rm2k-Freak@web.de> * fix osd elements not showing, remove useless block * cleanup, move pg stuff to pg folder * cleanup from review * minor mods to gps lap timer update, add number of laps tracked * rename time variable * add const to timeMs Co-authored-by: Jan Post <Rm2k-Freak@web.de> * Update licenses, add is_sys_element macro * update licenses * round to nearest centisecond Co-authored-by: Jan Post <Rm2k-Freak@web.de> --------- Co-authored-by: Jan Post <Rm2k-Freak@web.de>
Resubmitting #10968. See discussion there.
Feature described here: https://youtu.be/TA5cWwFafY4
Test with:
make XYZ EXTRA_FLAGS="-DUSE_GPS -DUSE_GPS_LAP_TIMER"