Heading does not work when recording activity

Former Member
Former Member
When I start recording an activity I notice that the heading
From sensorinfo no longer works. Once I stop the activity recording
Then I am able to read heading information. This is happening
On the fenix 3. Anyone aware of this problem or a workaround?

Thanks
Jesus
  • I seem to recall seeing something like this months ago on the va-hr, and what I did was use the heading from Activity.Info instead of Sensor.Info and it worked fine.

    The common thing with the f3 and va-hr is they both have HW compasses, so maybe that's what's involved - which heading is used and how long it's "fresh" when recording.

    update: Forgot to mention that based on what I see on a va-hr, Activity.Info is the GPS heading (changes when you are moving). You can however calculate the compass heading on devices with a HW Compass (and has "mag" available in the Sensor info). You're heading will change when you just turn your arm. A strange thing I found just the other day is that the 230 devices have "mag" and it kind of changes, but appears to have never been calibrated so it's odd....
  • Former Member
    Former Member over 8 years ago
    The heading value suddenly freezes to a single value and only that value will be returned every time you read it. This is true for Sensor.Info, Activity.info and Location.info.
    Buggy !!

    Jesus
  • Try downloading one of my apps https://apps.garmin.com/en-US/apps/028c5a06-48ed-4a5d-9910-236a7ef10ce0

    On 2 of the screens, you see the heading. I know it works fine on watches (including the va-hr with a mag compass) other than the Fenix, but if it works for you on the Fenix, something else is involved. If it doesn't, it's Fenix specific. This might help to narrow it down..
  • Jesus,

    Are you getting the Info object once and then reading the data from within it multiple times? i.e.,

    class MyView extends Ui.View
    {
    function initialize() {
    }

    var info;

    function onLayout(dc) {
    info = Activity.getInfo();
    }

    hidden var timer;

    function onShow() {
    timer = new Timer.Timer();
    timer.start(self.method(:onTimer), 1000, true);
    }

    function onHide() {
    timer.stop();
    timer = null;
    }

    function onUpdate(dc) {
    if (info != null) {
    if (info.heading != null) {
    System.println(info.heading);
    }
    }
    }
    }



    You need to be sure you are calling getInfo() every time you want to get updated data...

    class MyView extends Ui.View
    {
    function initialize() {
    }

    hidden var timer;

    function onShow() {
    timer = new Timer.Timer();
    timer.start(self.method(:onTimer), 1000, true);
    }

    function onHide() {
    timer.stop();
    timer = null;
    }

    function onUpdate(dc) {
    var info = Activity.getInfo();
    if (info != null) {
    if (info.heading != null) {
    System.println(info.heading);
    }
    }
    }
    }


    Travis
  • Former Member
    Former Member over 8 years ago
    jim_m_58:

    I tried your app and the heading works. Which of the three info classes are you using to read the heading: Sensor, Activity or Location?
    I am using Sensor.Info right now but I have tried all three. Sometimes it works, most of the time it doesn't. It is a random behavior.
    My activity type is swimming. I am going to try setting it to "Walking" and see if that has any effects.

    I have a main timer on my app firing every second with the following code:

    function timerHandler()
    {
    var sensorInfo = Sensor.getInfo();
    heading = sensorInfo.heading;
    }

    "heading" is a global variable that gets used in one of my views:
    function onUpdate(dc)
    {
    if (heading == null) {
    return;
    }
    // heading operations here
    }
  • Ok, here's what I do..

    I too have a 1 sec timer for onUpdate().

    In onUpdate(), if recording has started, I grab the data fro Activity.Info, and for this it's:

    if(aInfo.currentHeading!=null) {
    heading=makeDirection(aInfo.currentHeading*57.2957795);
    }

    (The 57.xyz is a cheap conversion to degrees!)

    Then I just display the result if needed...

    makeDirection() converts the degrees into a string with the compass points.

    Could it be your version of makeDirection() gets confused/stuck for some reason?

    Oh, wait.. Swimming? Are you trying to use GPS? I can see where it's wrong... With normal GPS, swimming will be odd, as you lose GPS when your arm is in the water...
  • Former Member
    Former Member over 8 years ago
    I think I found the issue. It happens when I start the Fit session before the GPS has locked on to the satellites.
    Jesus
  • Hey Jesus,

    After talking to our sensor team it looks like heading will lock a value if the GPS signal has not been acquired. Since you are starting the activity and calling for the heading before the GPS has been acquired it is causing the lock. You may be able to use some control statements making the start of your recording or the heading value dependent on a certain level of GPS quality. Pleas let me know if there are more issue that arise.

    -Coleman
  • Former Member
    Former Member over 8 years ago
    Thanks Coleman, Jim. I sent you this email and I am posting it here to keep other folks informed.

    Hi,

    I'm experiencing an issue on the Fenix 3 where the heading locks a value when recording an activity with GPS enabled. The heading works perfectly when I am not recording or when recoding with GPS off. I believe I am doing things correctly because I do not read sensor information until the GPS signal has been acquired. Below is a log from my app showing that the sequence of events are done in the right order. Timestamps are in seconds.


    -time 455362 -event GPS_ON
    -time 455372 -event GPS_READY
    -time 455374 -event FIT_SESSION_CREATE
    -time 455377 -event FIT_SESSION_START
    -time 455378 -heading -1.276648
    -time 455379 -heading -1.276648
    -time 455380 -heading -1.276648
    -time 455381 -heading -1.276648
    -time 455382 -heading -1.276648
    -time 455383 -heading -1.276648
    -time 455384 -heading -1.276648
    -time 455385 -heading -1.276648
    -time 455386 -heading -1.276648
    -time 455387 -heading -1.276648
    -time 455388 -heading -1.276648

    Below is the relevant code from my app. It is a little more involved than most apps for the following reasons:
    It requires no input from the user. Its a diving app. The user has other things to worry about.
    I am artificially introducing delays between the events shown in the log to rule that the issue might be caused by executing the events too fast one after the other.
    I start recording the activity while on the surface and discard it every 2 minutes if the diver is not yet under water. I do this because I want to record only during the dive but I also want to capture the location of the dive site before the diver goes under water. Once the diver is under water I turn off the GPS.
    The locking of the heading happens from the very beginning, so I know it has nothing to do with restarting the session every two minutes while on the surface.

    [FONT=Courier New][FONT=Courier New]enum {
    FIT_STATE_GPS_ON = 0,
    FIT_STATE_GPS_READY = 3,
    FIT_STATE_SURFACE_SESSION_CREATE = 5,
    FIT_STATE_SURFACE_SESSION_START = 8,
    FIT_STATE_SURFACE_SESSION_DISCARD = 128,
    FIT_STATE_DIVING
    }

    var barometer;
    var fitState;
    var session;
    var heading;

    class DiveComputerApp extends App.AppBase
    {
    function onStart(state)
    {
    gpsOn();
    }

    function timerHandler()
    {
    if (session != null && session.isRecording()) {
    systrace("-event READING_SENSORS");
    var info = Activity.getActivityInfo();
    barometerBars = barometer.getBars(info.altitude);
    heading = info.currentHeading;
    }
    }

    function gpsOn()
    {
    systrace("-event GPS_ON");
    fitState = FIT_STATE_GPS_ON;
    Position.enableLocationEvents(Position.LOCATION_CONTINUOUS, method(:onPosition));
    }
    }

    function onPosition(info)
    {
    if (fitState < FIT_STATE_GPS_READY) {
    if (info.accuracy == Position.QUALITY_GOOD || info.accuracy == Position.QUALITY_USABLE){
    fitState++;
    }
    } else if (fitState == FIT_STATE_GPS_READY) {
    systrace("-event GPS_READY");
    fitState++;
    } else if (fitState < FIT_STATE_SURFACE_SESSION_CREATE) {
    fitState++;
    } else if (fitState == FIT_STATE_SURFACE_SESSION_CREATE) {
    sessionCreate();
    fitState++;
    } else if (fitState < FIT_STATE_SURFACE_SESSION_START) {
    fitState++;
    } else if (fitState == FIT_STATE_SURFACE_SESSION_START) {
    sessionStart();
    fitState++;
    } else if (fitState < FIT_STATE_SURFACE_SESSION_DISCARD) {
    fitState++;
    } else if (fitState == FIT_STATE_SURFACE_SESSION_DISCARD) {
    sessionDiscard();
    fitState = FIT_STATE_GPS_ON;
    }
    }

    function sessionCreate()
    {
    systrace("-event FIT_SESSION_CREATE");
    session = Fit.createSession({:name=>"Scuba", :sport=>Fit.SPORT_SWIMMING,
    :subSport=>Fit.SUB_SPORT_OPEN_WATER});
    depthField = session.createField("Depth", 0, FitContributor.DATA_TYPE_FLOAT,
    {:mesgType=>FitContributor.MESG_TYPE_RECORD, :units=>"Depth"});
    maxDepthField = session.createField("MaxDepth", 1, FitContributor.DATA_TYPE_FLOAT,
    {:mesgType=>FitContributor.MESG_TYPE_SESSION, :units=>"Depth"});
    }

    function sessionStart()
    {
    systrace("-event FIT_SESSION_START");
    session.start();
    }

    function sessionStop()
    {
    systrace("-event FIT_SESSION_STOP");
    session.stop();
    }

    function gpsOff()
    {
    systrace("-event GPS_OFF");
    Position.enableLocationEvents(Position.LOCATION_DISABLE, null);
    }

    function sessionSave()
    {
    systrace("-event FIT_SESSION_SAVE");
    session.save();
    session = null;
    depthField = null;
    maxDepthField = null;
    gpsOn();
    }

    function sessionDiscard()
    {
    if (session == null) {
    return;
    }
    systrace("-event FIT_SESSION_DISCARD");
    session.discard();
    session = null;
    depthField = null;
    maxDepthField = null;
    }

    function systrace(log)
    {
    Sys.println("-time " + Sys.getTimer()/1000 + " " + log);
    }[/FONT][/FONT]
  • (using "code" tags is good for code :) )
    Try this: When you display the heading, also display the lat/lon (currentLocation.toDegrees() )
    That way you can check if the location is really changing (valid GPS). If lat/lon don't change, heading won't change. You may also want to display the accuracy.