# 6D localization with 6 lasers

I have to know where a multi-rotor is, in a rectangular room, via 6 lasers, 2 on each axis.

The problem is like this:

# Inputs :

• Room : square => 10 meters by 10 meters
• 6 positions of the lasers : Fixed on the frame
• 6 orientations of the lasers : Fixed on the frame
• The 6 measurements of the lasers
• The quaternion from the IMU of my flight controller (PixHawk).
• The origin is centered on the gravity center of the multi-rotor and defined as if the walls are perpendicular to each axes (the normal of the wall in X is (-1,0,0))

# Output :

• Position in 3D (X,Y,Z)
• Angular position (quaternion)

Since I got the angular position of the multi-rotor, I rotated the laser positions and orientations via the quaternion, then extrapolate via the 6 measurements and I got the 3 walls. (orientations of the walls are trivial, then only one point is enough to determine its position.

Badly, I noticed that the yaw (rotation about z) measurement from the PixHawk is unreliable. Then I should measure the yaw from the lasers, but I do not success to do it. Event if the 2D problem is easy, I am lost in 3D.

Does someone know if it [Algorithm to know XYZ position and quaternion from 6 measurments] exists somewhere ? Or what is the right way to go on this problem ?

The question : How could I get the yaw from 2 measurements from 2 lasers which I know the original position, orientation and the pitch and roll.

NOTE : Green pointers are the origin position, Red pointers are the "final" position, but could be rotated around the red circle (due to yaw). • We can easily get the orientation via MavLink from the PixHawk. Badly, the yaw, heading, orientation about Z is not stable due to the indoor application, while pitch and roll are stable. I am editing the question to add the setup – Alexis Paques Feb 27 '16 at 15:43

# Solution : Is there another solution without prerotating vectors ?

I finally got a solution, and here it is.

Python, ROS geometry library, numpy

My actual code/maths in short :

1) Rotate the position & orientation of lasers by roll & pitch. The axes='sxyz' means : Static axis, apply roll, pitch, yaw.

quaternion_matrix creates a 4x4 transformation matrix from the quaternion.

laser = (1,1,1,0) # laser position
orientation = (1,0,0,0) # laser orientation

roll, pitch, _ = list(euler_from_quaternion(q, axes='sxyz'))
q = quaternion_from_euler(roll, pitch, 0, axes="sxyz")
laser = numpy.dot(quaternion_matrix(q), laser)
orientation = numpy.dot(quaternion_matrix(q), orientation)


2) Algebric solution : Rotation around Z in function of yaw laser       = [-sin(a)*laser + cos(t)*laser,
cos(t)*laser + sin(t)*laser,
laser]

orientation = [-sin(a)*orientation + cos(t)*orientation,
cos(t)*orientation + sin(t)*orientation,
orientation]


3) Algebric solution : Extrapolation from the measurments in function of yaw

Important notice : Since the rotation do not scale vectors, the denominator of the K factor is a constant. Then, we can simplify it by precompute length of the orientation vector.

M = 100 # distance
K = sqrt(M^2 / (orientation^2 + orientation^2 + orientation^2))
PointOnWall = [ K * orientation + laser,
K * orientation + laser,
K * orientation + laser]


4) Algebric solution : From this, on two laser, get walls.

The two "PointOnWall" equations should gives enough data to get the yaw. Knowing this is a (-1,0,0) normale, I can find 2 planes from the two points : 5) Algebric solution : Measure the YAW.

One plane in the other (Via XMaxima), we got : def getYaw(position1, orientation1, measure1, position2, orientation2, measure2):
length1 = length(orientation1)
length2 = length(orientation2)
k1 = measure1/length1
k2 = measure2/length2
numerator   = -k2*orientation2 + k1*orientation1 + position1 - position2
denominator = -k2*orientation2 + k1*orientation1 + position1 - position2
return atan(numerator/denominator)


As expected, roll & pitch DO NOT interfere, since the positions and orientations are prerotated.

• Is this an answer to your own question, or more detail for the question? – Ben Feb 28 '16 at 0:05
• Incomplete answer :/ Mainly to show how I am doing right now, maybe I am doing it wrong. – Alexis Paques Feb 28 '16 at 1:10
• I finally got the complete solution :D – Alexis Paques Feb 28 '16 at 14:53