NavX Yaw Reset

We are having trouble with resetting yaw on the NavX. It is set for software reset. so reset should be immediate. We are recording the yaw and heading (derived from the totalAngle value) before calling yaw reset and immediately after.

On a test run yesterday we arrived at the end of a movement and before starting the next movement, we read yaw=94 and heading=80. We call to reset the yaw and then read the values back again. After the reset, the yaw=6 and the heading still = 80.

Now maybe the reset happens and in the very short time between the reset all and reading the yaw back, the robot is still moving and that is the source of the 6 degrees. One would expect this after reset movement to be small but sometimes the yaw value after reset is 15-20 degrees. Filming the robot, we don’t see any significant movement after the robot stops from the previous movement.

Further, while the yaw is non-zero, suggesting the robot moved after reset, that 6 degrees should be reflected in the heading but is not. We have tried waiting after reset but while that improves the result sometimes, we still get non-zero yaw on the read back. Again a consistently small value would be ok and in many cases does not cause a problem. However, if the way value is significantly non-zero, that will cause the next movement to fail because it is expecting to start with zero or small yaw.

I can’t think of a hypothesis to explain these results. The software yaw reset should take effect immediately, and that code in the library hasn’t changed for several years, so I’m surprised.

Rather than using the library to reset the yaw, perhaps it makes sense to have the students implement yaw reset themselves in software, by storing the yaw value when reset it desired, and then subtracting it from all future yaw values. There is some interesting math there to handle the wrap-around cases (e.g., at -180 degrees) they might find challenging - and it would certainly isolate the yaw reset portion of the library.

Another option is to enable on-board yaw reset. This works best when using SPI or I2C, and it has an inherent pipeline delay of maximum 2 * (1 second/update rate in hz) - which typically is 40 ms.

I’m curious what you find.

I’m not clear on how implementing yaw reset in our software would be different than the yaw reset in the Navx software. At this point my results suggest there is movement reported by the Navx hardware in the very small time between resetYaw() and immediate readback of the current yaw value. When this is small no real problem. In the cases where large, it is a problem. Why some large values? No idea.

Of more concern is why the unexpected yaw difference from zero is not reported in the heading value. The heading is computed from totalAngle so if yaw changes that value should change and be reflected in the heading.

So I am going to do more testing and review our code and will come back if the problem continues and I don’t find the cause in our code.

I’ve had problems with resetting the yaw on the NavX before. It’s intermittent and I’ve never succeeded in figuring out what causes it. When in doubt, power cycle.

The yaw value is generated by the sensor fusion algorithm from gyro/accel data. This value tends to settle a bit (and thus change value) after stopping, due to the slower rate at which accelerometer data is integrated into the yaw angle - this may account for yaw angle changing soon after stopping. Yaw is a non-referenced value, and yaw reset is used to reset it to 0 - allowing the user to apply a reference. Yaw reset is typically used right before the next move starts - rather than as soon as the last move ends, and this tends to mitigate the effect of the accelerometer settling somewhat.

The compass heading is different - it’s based upon the data from the magnetometers (i.e., it is referenced to earth’s magnetic field) and so it’s value will definitely tend to diverge from the yaw angle. Yaw reset does not reset the compass heading at all, as 0 degrees compass heading is defined as magnetic north.

Finally, the fused heading is a fusion of compass heading and change in the yaw angle. The change in yaw angle is integrated into the fused heading when rotation occurs (because during rotation the change in yaw angle is more accurate than the magnetometer data), but when still the fused heading angle is again updated by the magnetometer data (as long as a magnetic anomaly is not detected). Like compass heading, yaw reset does not impact fused heading.

  • scott

Thanks for the detailed replies. I have to apologize, I failed to clarify the heading values I described actually come from a wrapper library we have for the Navx. The heading we use is derived from the Navx getAngle() function. We set our heading to zero at start of a match which represents the direction straight down the field from robot starting point. We then track the cumulative change in angle and develop the robots heading at all times. This works fine. We use this heading for auto driving as well as plain yaw values. We also display this heading on driver station so the driver can see which way the robot is pointing if it is not directly visible. While the yaw being not zero after being reset is not desirable, we can live with it and minimizing robot motion as turns approach completion helps. The thing that bothered me is the change in yaw without matching change in the value returned by getAngle(). In every other case, change in yaw is matched by a change in getAngle(). We are retesting our code that generates that heading to make sure this is not a bug in our code.

We do reset yaw at the start of next move, but the next move comes right after the end of the last move, there is no significant delay between moves so the robot may not stop moving from inertia between the moves. This is not unexpected and we may be doing this to ourselves with not enough rotational damping in our PID loop. We are still working on that.

In our code we are tracing all of this and the timing between the resetYaw call and the call to get the new current yaw is a few milliseconds and it just seemed odd we could get up to 10 degrees of rotation in that short time. But that is a subjective thought as you can’t see that with the eye. So its possible our expectations are out of line.

One thing we tried is to wait between moves watching the Navx getYawRate() function for yaw rate less than 1 deg/sec. This did not work so well as sometimes that took way too long to return a value less than 1 deg/sec.

After an interesting test session yesterday I have new results to add to this discussion. When I wrote our heading tracker I assumed that getAngle() and getYaw() would move in sync. It seemed to me that the yaw would be derived from the total angle accumulated by the Navx. Testing of this code seemed to bear this out as our heading tracking was solid…but that testing did not include many (if any calls) to resetYaw.

Now our tests seem to show that these two items don’t move in sync, at least not always, and we see this at the resetYaw() call. In our testing we record the yaw and heading (getAngle derived) just prior to resetYaw() and just after. In most cases (though not all), we see the yaw is not zero after the reset, but some value typically a few degrees. However, the getAngle value (our heading) has not changed by the same amount, typically but not always unchanged from before resetYaw(). We then move on to the start of the next auto move where (as part of this investigation) we record the yaw and heading again. At this point the yaw has changed again (not unexpected) but the getAngle value now matches the original getAngle value plus this 3rd read of the yaw. This happens on a lot of resets but not all and the are some variations of the readings but there is the strong suggestion of some disconnect between getYaw and getAngle.

This could be our code but I have checked and checked it and don’t see anything to explain this.

A supporting observation is that our auto routine uses a mix of straight driving schemes, one based on not deviating from zero yaw (requires a resetYaw at start of drive) and one based on driving to a specified heading. We visually observed that as the routine progressed, the heading driving seemed to get off and a heading of zero (for instance) would end up not pointing in the correct physical direction, meaning the robots idea of heading zero no longer points directly down the field. This appeared to explain our routines tendency of getting off heading and failing to navigate the course. As part of the tests yesterday, all of the zero yaw driving moves were replaced with drive to heading moves (no calls to resetYaw) and the heading did not deviate from correct physical heading and the robot navigated the course correctly.

A separate test had the robot lined up with a physical mark on our floor and heading initialized to zero. Lots of teleop driving all around the room including greater than 360 spins and then lining back up with the physical mark. The final heading, zero. We then added a button to call resetYaw(). We executed the same driving test but pushed the button to call resetYaw() randomly during the driving. At the end when we lined back up with the mark, the heading was not reading zero, a few degrees off.

To summarize, it appears we are seeing cases of resetYaw() resetting getAngle() but not resetting resetYaw()…or they are both reset but then getYaw() changes without a corresponding change in getAngle().

Do you know what the relationship is between these two angle measures by the Navx?

Ok, I understand what your team’s software is doing a bit better. With that in mind, I’ve been reviewing the code executed when the yaw is reset, and when software reset is used:

  • the value returned from getYaw() will be updated immediately.
  • however, the value returned from getAngle() will not be updated with the yaw reset until the next sample is received from the board.

So this matches your observation that the two don’t move in sync, at least not always - because it depends upon the timing when resetYaw() is invoked, and when the “navx data acquisition thread” runs.

You can potentially increase the update rate to decrease this time period somewhat. But ultimately, to be deterministic there should be a (2 * 1/update rate) delay between the call to resetYaw() and the call to getAngle(), to meet the requirement that the latest resetYaw() is incorporated into the result returned from getAngle().

Alternatively, custom reset yaw logic could be added to your wrapper class, in order to overcome this delay.

In your previous mail, you mentioned using getYawRate() to determine when the robot is not rotating. Since as mentioned earlier the yaw angle is perhaps still being adjusted by the accelerometer data for a little while after rotation stops, it might be preferable to determine “stillness” instead by using getRawGyroZ(), and checking when the value is below a threshold.

One other thing that could possibly contribute to a yaw angle that doesn’t quickly stabilize after motion stops is sub-optimal mounting. If you haven’t already reviewed it, this is discussed in item 1) on the best practices page.

Thanks so much for looking into this and the detailed reply. I was sure there was something afoot here.

But I have a question: based on this new information and what I see in the trace, when we call resetYaw, it appears both the getYaw and getAngle results are zeroed out. Then a few ms later when I read them back, the yaw value has changed but the getAngle value has not. This fits your explanation of how getAngle is updated. The unchanged getAngle indicates we have not yet received an update from the Navx since reset. But if we have not received an update, where does that change in yaw value come from?

Considering all you said I have been trying to figure out how all this causes our Navx wrapper’s heading tracking to get off. My theory is that there is vibration induced yaw that gets introduced which is not matched by actual robot motion. This is how the heading indicator end up saying robot is pointing at zero (for instance) but the robot is actually pointing at about 5 degrees. Your point about mounting the Navx is good and I think we did not do a good enough job of that. Will try to get some testing in next week to confirm.

Testing yesterday confirmed that both yaw and angle reset immediate. yaw starts changing without delay but angle does remain zero until next Navx update. Again, without an update from the hardware, how does the yaw value change?

Internally, resetYaw() establishes a yaw offset, which is calculated as the average of the last 10 received yaw samples. This average is updated asynchronously whenever new yaw samples are received.

getYaw() returns the last received yaw, minus the yaw offset established during the last resetYaw(). The last received yaw is updated asynchronously whenever new yaw samples are received.

getAngle() returns a value calculated using the most recent yaw angle and the previous yaw angle (since it needs to assess directionality of rotation to calculate when wraparound events occur). These yaw angles are internally fed to a tracker asynchronously when new yaw samples are received, and are the same values returned from getYaw(), and thus have the current yaw offset applied. When resetYaw() occurs the tracker is reinitialized (the previous yaw angle and current yaw angle are set to 0).

Ok. Thanks again for the detailed responses. I think I have a good understanding of Navx reset and things are going better with our robot, though I think our mounting is problematic. I’m satisfied this is put to bed and moving on to the next issue.

Glad to hear things are going better; all the best to your team during their at-home competitions.