123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #!/usr/bin/env python
- '''
- fit best estimate of magnetometer rotation to gyro data
- '''
- from __future__ import print_function
- from builtins import range
- from builtins import object
- from argparse import ArgumentParser
- parser = ArgumentParser(description=__doc__)
- parser.add_argument("--no-timestamps", dest="notimestamps", action='store_true', help="Log doesn't have timestamps")
- parser.add_argument("--verbose", action='store_true', help="verbose output")
- parser.add_argument("--min-rotation", default=5.0, type=float, help="min rotation to add point")
- parser.add_argument("logs", metavar="LOG", nargs="+")
- args = parser.parse_args()
- from pymavlink import mavutil
- from pymavlink.rotmat import Vector3, Matrix3
- from math import radians
- class Rotation(object):
- def __init__(self, name, roll, pitch, yaw):
- self.name = name
- self.roll = roll
- self.pitch = pitch
- self.yaw = yaw
- self.r = Matrix3()
- self.r.from_euler(self.roll, self.pitch, self.yaw)
- def is_90_degrees(self):
- return (self.roll % 90 == 0) and (self.pitch % 90 == 0) and (self.yaw % 90 == 0)
- def __str__(self):
- return self.name
- # the rotations used in APM
- rotations = [
- Rotation("ROTATION_NONE", 0, 0, 0),
- Rotation("ROTATION_YAW_45", 0, 0, 45),
- Rotation("ROTATION_YAW_90", 0, 0, 90),
- Rotation("ROTATION_YAW_135", 0, 0, 135),
- Rotation("ROTATION_YAW_180", 0, 0, 180),
- Rotation("ROTATION_YAW_225", 0, 0, 225),
- Rotation("ROTATION_YAW_270", 0, 0, 270),
- Rotation("ROTATION_YAW_315", 0, 0, 315),
- Rotation("ROTATION_ROLL_180", 180, 0, 0),
- Rotation("ROTATION_ROLL_180_YAW_45", 180, 0, 45),
- Rotation("ROTATION_ROLL_180_YAW_90", 180, 0, 90),
- Rotation("ROTATION_ROLL_180_YAW_135", 180, 0, 135),
- Rotation("ROTATION_PITCH_180", 0, 180, 0),
- Rotation("ROTATION_ROLL_180_YAW_225", 180, 0, 225),
- Rotation("ROTATION_ROLL_180_YAW_270", 180, 0, 270),
- Rotation("ROTATION_ROLL_180_YAW_315", 180, 0, 315),
- Rotation("ROTATION_ROLL_90", 90, 0, 0),
- Rotation("ROTATION_ROLL_90_YAW_45", 90, 0, 45),
- Rotation("ROTATION_ROLL_90_YAW_90", 90, 0, 90),
- Rotation("ROTATION_ROLL_90_YAW_135", 90, 0, 135),
- Rotation("ROTATION_ROLL_270", 270, 0, 0),
- Rotation("ROTATION_ROLL_270_YAW_45", 270, 0, 45),
- Rotation("ROTATION_ROLL_270_YAW_90", 270, 0, 90),
- Rotation("ROTATION_ROLL_270_YAW_135", 270, 0, 135),
- Rotation("ROTATION_PITCH_90", 0, 90, 0),
- Rotation("ROTATION_PITCH_270", 0, 270, 0),
- Rotation("ROTATION_PITCH_180_YAW_90", 0, 180, 90),
- Rotation("ROTATION_PITCH_180_YAW_270", 0, 180, 270),
- Rotation("ROTATION_ROLL_90_PITCH_90", 90, 90, 0),
- Rotation("ROTATION_ROLL_180_PITCH_90", 180, 90, 0),
- Rotation("ROTATION_ROLL_270_PITCH_90", 270, 90, 0),
- Rotation("ROTATION_ROLL_90_PITCH_180", 90, 180, 0),
- Rotation("ROTATION_ROLL_270_PITCH_180", 270, 180, 0),
- Rotation("ROTATION_ROLL_90_PITCH_270", 90, 270, 0),
- Rotation("ROTATION_ROLL_180_PITCH_270", 180, 270, 0),
- Rotation("ROTATION_ROLL_270_PITCH_270", 270, 270, 0),
- Rotation("ROTATION_ROLL_90_PITCH_180_YAW_90", 90, 180, 90),
- Rotation("ROTATION_ROLL_90_YAW_270", 90, 0, 270)
- ]
- def mag_fixup(mag, AHRS_ORIENTATION, COMPASS_ORIENT, COMPASS_EXTERNAL):
- '''fixup a mag vector back to original value using AHRS and Compass orientation parameters'''
- if COMPASS_EXTERNAL == 0 and AHRS_ORIENTATION != 0:
- # undo any board orientation
- mag = rotations[AHRS_ORIENTATION].r.transposed() * mag
- # undo any compass orientation
- if COMPASS_ORIENT != 0:
- mag = rotations[COMPASS_ORIENT].r.transposed() * mag
- return mag
- def add_errors(mag, gyr, last_mag, deltat, total_error, rotations):
- for i in range(len(rotations)):
- if not rotations[i].is_90_degrees():
- continue
- r = rotations[i].r
- m = Matrix3()
- m.rotate(gyr * deltat)
- rmag1 = r * last_mag
- rmag2 = r * mag
- rmag3 = m.transposed() * rmag1
- err = rmag3 - rmag2
- total_error[i] += err.length()
- def magfit(logfile):
- '''find best magnetometer rotation fit to a log file'''
- print("Processing log %s" % filename)
- mlog = mavutil.mavlink_connection(filename, notimestamps=args.notimestamps)
- last_mag = None
- last_usec = 0
- count = 0
- total_error = [0]*len(rotations)
- AHRS_ORIENTATION = 0
- COMPASS_ORIENT = 0
- COMPASS_EXTERNAL = 0
- last_gyr = None
- # now gather all the data
- while True:
- m = mlog.recv_match()
- if m is None:
- break
- if m.get_type() in ["PARAM_VALUE", "PARM"]:
- if m.get_type() == "PARM":
- name = str(m.Name)
- value = int(m.Value)
- else:
- name = str(m.param_id)
- value = int(m.param_value)
- if name == "AHRS_ORIENTATION":
- AHRS_ORIENTATION = value
- if name == 'COMPASS_ORIENT':
- COMPASS_ORIENT = value
- if name == 'COMPASS_EXTERNAL':
- COMPASS_EXTERNAL = value
- if m.get_type() in ["RAW_IMU", "MAG","IMU"]:
- if m.get_type() == "RAW_IMU":
- mag = Vector3(m.xmag, m.ymag, m.zmag)
- gyr = Vector3(m.xgyro, m.ygyro, m.zgyro) * 0.001
- usec = m.time_usec
- elif m.get_type() == "IMU":
- last_gyr = Vector3(m.GyrX,m.GyrY,m.GyrZ)
- continue
- elif last_gyr is not None:
- mag = Vector3(m.MagX,m.MagY,m.MagZ)
- gyr = last_gyr
- usec = m.TimeMS * 1000
- mag = mag_fixup(mag, AHRS_ORIENTATION, COMPASS_ORIENT, COMPASS_EXTERNAL)
- if last_mag is not None and gyr.length() > radians(args.min_rotation):
- add_errors(mag, gyr, last_mag, (usec - last_usec)*1.0e-6, total_error, rotations)
- count += 1
- last_mag = mag
- last_usec = usec
- best_i = 0
- best_err = total_error[0]
- for i in range(len(rotations)):
- r = rotations[i]
- if not r.is_90_degrees():
- continue
- if args.verbose:
- print("%s err=%.2f" % (r, total_error[i]/count))
- if total_error[i] < best_err:
- best_i = i
- best_err = total_error[i]
- r = rotations[best_i]
- print("Current rotation is AHRS_ORIENTATION=%s COMPASS_ORIENT=%s COMPASS_EXTERNAL=%u" % (
- rotations[AHRS_ORIENTATION],
- rotations[COMPASS_ORIENT],
- COMPASS_EXTERNAL))
- print("Best rotation is %s err=%.2f from %u points" % (r, best_err/count, count))
- print("Please set AHRS_ORIENTATION=%s COMPASS_ORIENT=%s COMPASS_EXTERNAL=1" % (
- rotations[AHRS_ORIENTATION],
- r))
- for filename in args.logs:
- magfit(filename)
|