Toybox.Activity.Info.offCourseDistance is always null when Off Course Warnings is off

According to the API documentation, the attribute offCourseDistance in class Toybox.Activity.Info contains the distance to the nearest point on the current course in meters. I have tested the value of this attribute with a simple data field with the following code in the compute method of the View class:

function compute(info) {
if (info != null and info has :offCourseDistance) {
if (info.offCourseDistance == null) {
return "null";
} else {
return info.offCourseDistance;
}
} else {
return "-";
}


Next, I have uploaded a course on my Garmin Edge 1030, and started riding it. The Off Course Warnings setting on the Edge is off.

While I am not riding off course, the simple data field shows null (which indicates that info.offCoursedistance is null).

When I am riding deliberately off course, the simple data field still shows null. At the same time the native data field Dist. to Next, however, shows the distance between my current location and the nearest point on the course. (This behavior of this native data field is not documented, but from experience I have learned that this is the case.) Therefore, the Edge has detected that I am indeed off course.

When I repeat this test with the Off Course Warnings setting switched on, info.offCoursedistance is still null when I am not riding off course, but some value is showing in my simple data field when I ride off course. This value, however, is sometimes null, and sometimes a numeric value, but never a value that is equal to the value in the native data field Dist. to Next.

This is not at all what I expected. I would expect info.offCoursedistance to have the following value:
  • null when I am not riding a course
  • 0 when I am riding a course, and I am not off course
  • The same value shown in native data field Dist. to Next when I am riding a course and I am off course

I would expect these values to be independent from the Off Course Warnings setting. Specifically, if Off Course Warnings is off, info.offCoursedistance should still have a value when I am riding off course. Switching on Off Course Warnings has undesired side effects (buzzes, pop-ups). And what is more, there is no way in Connect IQ to check the value of the Off Course Warnings setting.

Some additional information:
  • Garmin Edge 1030, firmware version 3.90
  • Code sample created with Eclipse IDE for Java Developers Version: Oxygen.3a Release (4.7.3a) and Connect IQ SDK 3.0.7
    • Navigation > Courses > Saved Courses > hamburger menu > Turn Guidance: off


    I may have found where the issue is coming from. Turn Turn guidance setting on. Does that change the behavior?

    For me having Turn Guidance off results in null from info.offCourseDistance. Not sure why this is the case, but I will focus the ticket on this.

    Also, Thanks for the really clear procedure and settings profile. That helped a lot :)
  • I just went outside on a course to confirm, and the TurnGuidance setting appears to be the cause. I also noticed a difference in the distToNext native dataField when I switched the TurnGuidance setting. I assume it's a related issue.
  • Also, Thanks for the really clear procedure and settings profile.


    My pleasure. I appreciate the time and trouble you and your colleagues are taking to try and help me out.
  • Just now, I have done a ride, along the lines of my typical use case as described above, with the only difference being that I have switched the Turn Guidance setting on. So, the Off Course Warnings setting was still off.

    When I was riding my course, info.offCourseDistance always had a non-null value greater than 0, whether I was on course or off course. Even when I was on course, info.offCourseDistance was showing values ranging from 0.5 to 95, sometimes increasing, sometimes decreasing. The values seemed random to me, I could not make any sense of them. However, they were never 0, even though the map showed that I was right on course.

    And when I had gone deliberately off course, info.offCourseDistance also showed non-null values greater than 0. Again, I could not make much sense of the values being shown. The values did not seem to represent, as far as I could see, the distance from my current location to the nearest point on the course path in a straight line.

    I did not expect this. I had expected info.offCourseDistance to be 0 when I was on course, but it never was. Furthermore, the values of info.offCourseDistance seemed completely random to me. I had no idea what they were representing.
  • remember that offCourceDistance is in meters, so .5 is maybe an arm's length. Also, your GPS location can be off, based on quality, what sats are in view, buildings, etc. It's not accurate within a meter, maybe 10-20, or maybe more. I'd expect if the alert was on, you wouldn't get it below some minimum, as I don't think you'll want it if you were just moving to the other side of a road.

    If I start up GPS and just leave the device on my desk, it will pick up distance over time, due to some wobble in GPS.

    I'd be surprised if it was always 0 meters if you stayed on course to be honest.
  • I'd be surprised if it was always 0 meters if you stayed on course to be honest.

    So, there is no way for an app to know that the device is in an "off course" state?

  • As I said, there's probably some kind of minimum for the system to generate an alert - you wouldn't want an alert if you were .5 meters or maybe even 10 or more. Your app can do something similar, and what that minimum is could vary based on what your app is doing.

    I have kind of the opposite thing in a few of my apps, where I have a list of locations (waypoints), and I alert when the user gets "close". If I waited for an exact match, that might never come or mean walking around in a small circle until the alert happens. So I consider "close" to be within something like 30 meters in that app. And when "close", I consider it "not close any more" at double that distance, to avoid any "sputtering" right at the "close" distance.
  • So, there is no way for an app to know that the device is in an "off course" state?



    Just my two cents without being an expert on the matter. I do use navigation as a runner pretty regularly. Hopefully I am not missing something.

    As Jim pointed out, GPS is inaccurate. So any field that represents the literal off course distance will probably always be non-zero, like Jim said. However, as Jim also pointed out, you probably don't get an alert unless your off course distance goes over some threshold.

    So maybe what needs to happen is there should be another field called isOffCourse, which represents whether the Garmin off-course alert algorithm thinks you are off-course.

    Of course, this could be needlessly complicated and also not backwards compatible with older devices which may never get new internal or external fields.

    So maybe what really needs to happen is:

    - info.offCourseDistance (and the data field?) should be null if the Garmin off-course alert algorithm does not think you are off course and would not show you an alert. In other words, if the internal off course distance is less than the threshold, report a value of null in that case
    - In all other cases, just report the actual internal offCourseDistance

    TL;DR, if the device doesn't think you're off course when you're only 5 metres off course, does the device need to show "5" in that field?

    Somewhat analogously, if your pace goes slower about 59:59 per km or mi, the Garmin pace data field shows "--:--", instead of "1:20:30" (for example). (However, the internal speed field still has the real number.)

    The difference here is that it's pretty easy for devs to guess what Garmin's algorithm is for showing "--:--" and they don't need to match that exactly. I don't know how easy it is for devs to guess what Garmin's algorithm is for showing off-course alerts.
  • Having a flag in Activity.Info might not be useful for all apps and means the structure gets larger and it's really easy to do in a specific app.
    if(offCourseDistance>=30.0) {offCourse=true;}
    else {offCourse=false;}

    in its simplest case. You could even have a user setting for what distance is used.
    You'll likely see something similar if you were watching distanceToNextPoint as I see in my app. You probably don't want to wait for it to be 0 meters as you could just be on the other side of the road.