How to get Yaw angle or Heading on Robot Inventor Hub? #675
-
I am using imu.tilt() to get pitch and roll angles on Robot Inventor Hub. |
Beta Was this translation helpful? Give feedback.
Replies: 13 comments 37 replies
-
Yaw and heading are mostly the same. The sensor doesn’t measure them directly. To get them, we need to add a background process that continuously monitors the IMU to keep track of yaw motion. We haven’t gotten around to doing this yet. |
Beta Was this translation helpful? Give feedback.
-
Thanks much for the reply. |
Beta Was this translation helpful? Give feedback.
-
I have started working on a yaw_angle routine but I noticed some problems with the yaw_rate readings that may make it hard to do. from pybricks.hubs import PrimeHub, InventorHub
from pybricks.tools import wait
from pybricks.geometry import Axis
# Initialize the hub.
#hub = PrimeHub()
# Initialize the hub. In this case, specify that the hub is mounted with the
# top side facing forward and the front side facing to the right.
# For example, this is how the hub is mounted in BLAST in the 51515 set.
hub = InventorHub(top_side=Axis.X, front_side=-Axis.Y)
# Get the acceleration or angular_velocity along a single axis.
# If you need only one value, this is more memory efficient.
while True:
# Read the forward acceleration.
# forward_acceleration = hub.imu.acceleration(Axis.X)
# Read the yaw rate.
yaw_rate = hub.imu.angular_velocity(Axis.Z)
# Print the yaw rate.
print(yaw_rate)
wait(100) |
Beta Was this translation helpful? Give feedback.
-
I upgraded to latest firmware 3.2 to try the fix for yaw angle rate drifting as in above chart. |
Beta Was this translation helpful? Give feedback.
-
I have been interested in adding some firmware-level calibration routines to the IMU class in pybricks-micropython to get good heading readings, so this discussion is a good kick. In the EV3 days, our FLL team would use the gyro, but ever since the SPIKE Prime, we haven't been able to be more accurate with the gyro than estimating with motor encoder counts. So where our heads are at now is that we need to address three main problems to get a usable heading (we are still experimenting, so this is all subject to change):
All of the above change with temperature and age, so if you are using this in competition, you'd need to re-calibrate often. As a fun observation, we have noticed that the scale-factor error is different when you swing clockwise vs counterclockwise (by a LOT). Here are some of the better (more understandable) papers/sites that we have been collecting: |
Beta Was this translation helpful? Give feedback.
-
Hi again, Basically, I seem to be fighting the noise in the Yaw_angle readings even though I thought it might cancel out. Also, I am doing this on Blast robot in which the Hub is the head and can move around when you move the arms or head. I suspect that I also need a higher sample rate but have not optimized on that yet. # Get Yaw Angle using timer to get time interval
yaw_timer = StopWatch()
yaw_timer.reset()
yaw_angle_integration = 0
yaw_angle_running = False
yaw_angle_integration_enabled = True
# yaw rate calibration factors; offset in degrees/sec
# yaw_rate_offset will be measured during robot setup or when requested
yaw_rate_offset = 1.0
yaw_rate_factor = 1.0
yaw_rate_offset_max =-10
yaw_rate_offset_min = 10
yaw_rate_min_use = 0.3
yaw_rate_num_samples = 5
def get_yaw_angle():
global yaw_timer, yaw_angle_running, yaw_angle_integration
if yaw_angle_integration_enabled:
# Read the yaw rate value with Averaging. Calculate Yaw_angle.
if yaw_angle_running:
yaw_rate_raw =0
for i in range(yaw_rate_num_samples):
yaw_rate_raw += hub.imu.angular_velocity(Axis.Z)
yaw_rate_raw = yaw_rate_raw/yaw_rate_num_samples
yaw_rate = (yaw_rate_raw-yaw_rate_offset)*yaw_rate_factor
delta_time = yaw_timer.time()
delta_time = delta_time/1000
# Check for low yaw rate which means we are not moving
# So don't integrate to reduce drift
if abs(yaw_rate) > yaw_rate_min_use:
yaw_angle_integration = yaw_angle_integration + yaw_rate*delta_time
# First time, start the timer, set yaw_angle_running
yaw_angle_running = True
# Reset Timer and return Yaw Angle
yaw_timer.reset()
return(yaw_angle_integration)
# Get Yaw Rate Offset ; Call during robot setup while Not moving
def get_yaw_rate_offset():
global yaw_rate_offset
global yaw_rate_offset_max, yaw_rate_offset_min
yaw_rate_offset = 0
print('Yaw_Rate Offset Setup:')
# Take First group of readings of yaw rate and Discard them
num_samples = 10
for i in range(num_samples):
wait(100)
yaw_rate = hub.imu.angular_velocity(Axis.Z)
# Take Second group of readings of yaw rate and Average them
num_samples = 50
for i in range(num_samples):
wait(100)
yaw_rate = hub.imu.angular_velocity(Axis.Z)
yaw_rate_offset = yaw_rate_offset + yaw_rate
print('Yaw Rate Reading #', i+1, '=', yaw_rate)
yaw_rate_offset = yaw_rate_offset/num_samples
if(yaw_rate_offset > yaw_rate_offset_max):
yaw_rate_offset_max = yaw_rate_offset
if(yaw_rate_offset < yaw_rate_offset_min):
yaw_rate_offset_min = yaw_rate_offset
print("Yaw Rate Offset Average=", yaw_rate_offset, 'Min=', yaw_rate_offset_min, 'Max=', yaw_rate_offset_max)
# Reset Yaw Angle Integration
def reset_yaw_angle():
global yaw_timer, yaw_angle_running, yaw_angle_integration
yaw_angle_integration = 0
yaw_angle_running = False
yaw_timer.reset()
# Get Heading from Yaw Angle Integration
def get_heading_angle():
global yaw_angle_integration
if yaw_angle_integration <= 0:
heading_angle = (-yaw_angle_integration % 360)
else:
heading_angle = 360-(yaw_angle_integration % 360)
return(heading_angle) |
Beta Was this translation helpful? Give feedback.
-
Reading the datasheet, I don't see how the FIFO could get us a higher sample rate compared to not using it. Since the FIFO can only be read 2 bytes at a time, using it introduces quite a bit of overhead (32 bits of overhead for every 2 bytes read, i.e 24 cycles per byte read) . There are 6-bytes per data set and 4 data sets, so 24 bytes to read per sample. And since the chips are using I2C at 400kHz best case scenario reading the FIFI is 400k cycles/sec / 24 cycles/byte / 24 byte/sample = 400 sample/sec. If we just read the regular value registers instead of the FIFO register, we can read everything (temp/accel/gyro) in a single read of 14 bytes of data. This comes with 44 bits of overhead per each read, so 11.14 cycles per byte read. Best case scenario here would be 400k cycles/sec / 11.14 cycles/byte / 14 bytes/sample = 2564 samples/sec. |
Beta Was this translation helpful? Give feedback.
-
I've just pushed some changes for testing. I haven't messed with any FIFO stuff yet, but I've made a proper driver for the IMU chip so that it reads in the background instead of when called from Python. Now calling the You can grab a firmware from this ci build and flash it with |
Beta Was this translation helpful? Give feedback.
-
I think I just saw the "lock up" issue where the I2C bus has an error for the first time. This happened even with my new changes. However, I've also left a hub running all night without hitting the issue. So if anyone has any suggestions on how to reliably reproduce the issue, that would be helpful. |
Beta Was this translation helpful? Give feedback.
-
@cmyers734 @johnscary-ev3 Can you explain how you came to the conclusion that temperature is a major contributing factor to the error? I've done some experiments where I turn all of the lights on the hub on or off to vary the temperature of the IMU and graphed them. I'm not seeing any effect of temperature on the angular rotation rate measured by the gyro. First, I did this when the hub was not moving to see if temperature has an effect on the static bias error. Then I did it while the hub was turning in place to see if temperature had an effect on the scale factor error (note: spikes are when the hub hit obstacles and I had to move it - it wasn't staying exactly in place). I don't see any measurable effect of temperature. Am I missing something? Surely temperature would not affect the angle random walk error of the integrated value? |
Beta Was this translation helpful? Give feedback.
-
How to get Yaw angle or Heading on Robot Inventor Hub? It occured to me that there is another practical (but perhaps unexpected) answer to the original question. You can use the Naturally, this has its own challenges like slipping wheels, but it can work well for some applications as shown in the video below. Original response to @cmyers734 below.
You might like the DriveBase class. We should probably do a better job talking about what it can do by now :) Here's 99 turns of 90/180/270 degrees and it's still on track at the end, despite not using the gyro. drivebase_turn2.mp4We've done our best to make something that students can really use in practice. If you try it, we'd love to get your feedback, both in terms of ease-of-use and performance. |
Beta Was this translation helpful? Give feedback.
-
Updated answer: we have a solution for this now! Check out #989 |
Beta Was this translation helpful? Give feedback.
Updated answer: we have a solution for this now! Check out #989