I am building quadcopter with IMU to get orientation in 3D and ultrasound range finder to measure distance to the ground. For some mechanical reasons, IMU is not aligned with quadcopter axis. Range finder is pointing down perpendicular to the copter plane. IMU has left-hand coordinate system where X axis pointing down, Z axis backwards and Y to the right. IMU provides quaternion to describe the orientation. The following picture illustrates the setup.
There are two problems I am facing:
I am using numpy-quaternion library. To solve the first problem (adjust IMU quaternion to get copter orientation) I placed the copter on the known horizontal surface, got 5 quaternions from IMU, average them, then create quaternion without rotations and calculate the difference quaternion as suggested here:
qs = quaternion.as_quat_array(sensor_data)
avg_imu_pos = np.average(qs)
base_q = quaternion.from_rotation_vector([[0, 0, 0]])[0]
diff = base_q * avg_imu_pos.conjugate()
Then to get copter position I am multiplying calculated difference with quaternion from IMU:
orientation_true = diff * orientation
where orientation
is the quaternion received from IMU. As far as I can tell, this step is working properly. I made simple visualization and it looks correct to me.
The problem I can not solve for now is how to adjust the range finder measurement. I made the following function for it:
def correct_distance(self, measured_distance: float, orientation: quaternion) -> float:
q1 = quaternion.from_rotation_vector([[0, 0, 0]])[0]
diff = q1.conjugate() * orientation
if diff.w < -1:
diff.w = -1
elif diff.w > 1:
diff.w = 1
angle = 2 * math.acos(diff.w)
return measured_distance * math.cos(angle)
The assumption here is that orientation
is the quaternion describing the orientation of the copter, i.e. corrected IMU quaternion. So the idea was to calculate the angle between not rotated quaternion and quaternion describing copter position. Then use this angle to adjust the distance measurement by multiplying it by cos(angle).
Unfortunately, this step leads to unexpected results. Even rotation around vertical axis considerably decrease the corrected measurement which is obviously wrong.
So my question is - is my general strategy correct and if yes, did you see any mistake preventing me from getting properly adjusted distance measurement?
The magnitude of the w
of a quaternion representing a rotation is determined in part by the angle of that rotation, but you don't want the angle of the rotation. You want to know how it affects a particular vector.
Form the vector describing the rangefinder's measured range in local space, then rotate it by the orientation quaternion to find the range vector in global space. Then get whatever information you want from that (in this case, the x coordinate).