Skip to the content
FixTheRobot Explore Robotics / UAV / Module 1 / M1-T4

UAV Systems Engineering · Module 1

M1-T4: UAV coordinate frames: Body, World, NED and ENU

Four letters decide whether a UAV flies where you told it to: get NED, ENU, FRD and FLU straight before touching any code.

  • Lesson 4 of 12
  • UAV Fundamentals and System Architecture
  • Established engineering
  • About 9 minutes to read

Every sensor reading, setpoint and estimate is a vector expressed in some frame. A wrong frame does not cause an error message; it causes a vehicle that flies away from where it was told to go. This lesson fixes the frames used in UAV software and the exact conversions between them.

Learning objectives

After this lesson, you should be able to:

  • Define the body, world, NED and ENU frames and the handedness of each.
  • Convert positions, velocities and yaw between NED and ENU, and body vectors between FRD and FLU.
  • Rotate a body-frame vector into the world frame with a ZYX Euler rotation matrix.
  • Name the frame conventions used by PX4 and by ROS 2 and find the conversion needed at the boundary.

Conceptual explanation

A frame is an origin and three orthogonal axes. UAV systems use two families. World (navigation) frames are fixed to the Earth near the vehicle and are used for position, velocity and waypoints. Body frames are fixed to the airframe, with the origin at the centre of mass, and are used for IMU data, thrust direction and angular rates.

NED, ENU, FRD and FLU framesLeft: world frames. NED has x north, y east, z down. ENU has x east, y north, z up. Right: body frames. FRD has x forward, y right, z down. FLU has x forward, y left, z up. The two world frames are related by swapping the first two axes and flipping the third; the two body frames by flipping y and z.World frames (fixed to the Earth) North (x NED) East (y NED) Down (z NED): into the page NED: x = North, y = East, z = Down ENU: x = East, y = North, z = Up p_ENU = (y, x, −z) of p_NED Body frames (fixed to the airframe) Forward (x) Right (y FRD)Left (y FLU) FRD (PX4): x forward, y right, z down FLU (ROS): x forward, y left, z up v_FLU = (x, −y, −z) of v_FRD
The two common world frames (NED, ENU) and the two common body frames (FRD, FLU). All are right-handed.

NED (North-East-Down) is the aerospace convention and the one used by PX4 for position and velocity. ENU (East-North-Up) is the convention of the Robot Operating System: REP-103 specifies ENU for world frames and FLU (forward-left-up) for body frames. All four frames are right-handed, so z=x×yz=x\times y in each.

Frame conventions and where each is used
FramexxyyzzUsed by
NEDNorthEastDownPX4 and aerospace: position, velocity
ENUEastNorthUpROS world frames (map, odom)
FRDForwardRightDownPX4 body frame
FLUForwardLeftUpROS body frame (base_link)
Animation of a vehicle turning in yaw while a velocity of five metres per second towards North stays fixed in the world. The left panel is a top view with North up and East to the right, showing the vehicle and its body axes. The right panel plots the velocity components in the body frame, forward and right, against yaw: the forward component is five times the cosine of the yaw and the right component minus five times the sine of the yaw. The East and North values in the ENU convention are listed beside the NED values.
A vector does not change when the frame changes; its components do. For a yaw rotation ψ\psi about Down, vbody=R(ψ)⊤ vNEDv_{\text{body}}=R(\psi )^{\top}\,v_{\text{NED}}, which gives forward = vN cos⁡ ψ\cos \,\psi + vE sin⁡ ψ\sin \,\psi and right = −vN sin⁡ ψ\sin \,\psi + vE cos⁡ ψ\cos \,\psi . NED order is (North, East, Down); ENU order is (East, North, Up). (Looping, about 5 seconds; drawn and computed for this course with illustrative values.)

Engineering intuition

Altitude is the quickest sanity check. In NED a vehicle 10 m above the ground has z=−10z=-10. In ENU the same vehicle has z=+10z=+10. If a takeoff sends the UAV into the ground, suspect a missing sign flip on zz before anything else.

The conversions are index shuffles with a sign flip, so they are cheap and exact. Keep every variable name tagged with its frame (p_ned, v_enu, acc_flu) and convert at one place, the boundary between systems. A conversion hidden in the middle of an algorithm is where the bug will be.

Yaw is the second trap. NED yaw is measured clockwise from north (a compass heading). ENU yaw is measured counter-clockwise from east (the usual maths angle). They are related by ψENU=π/2−ψNED\psi _{\text{ENU}}=\pi /2-\psi _{\text{NED}}: a UAV facing east has NED yaw 90∘90^{\circ} and ENU yaw 0∘0^{\circ}.

Mathematical formulation

Position and velocity

NED and ENU conversion
pENU=(pE, pN, −pD)=(yNED, xNED, −zNED)\mathbf p_{\mathrm{ENU}} = (p_E,\ p_N,\ -p_D) = (y_{\mathrm{NED}},\ x_{\mathrm{NED}},\ -z_{\mathrm{NED}})
pNED=(pN, pE, −pU)=(yENU, xENU, −zENU)\mathbf p_{\mathrm{NED}} = (p_N,\ p_E,\ -p_U) = (y_{\mathrm{ENU}},\ x_{\mathrm{ENU}},\ -z_{\mathrm{ENU}})
The same swap-and-flip converts velocities.

As a matrix, with CNEDENUC^{\text{ENU}}_{\text{NED}} the rotation that expresses an NED vector in ENU coordinates:

The NED to ENU matrix
CNED→ENU=[01010000−1],pENU=CNED→ENU pNED,det⁡C=+1\mathbf C_{\mathrm{NED}\to\mathrm{ENU}} = \begin{bmatrix}0 & 1 & 0\\ 1 & 0 & 0\\ 0 & 0 & -1\end{bmatrix}, \qquad \mathbf p_{\mathrm{ENU}} = \mathbf C_{\mathrm{NED}\to\mathrm{ENU}}\,\mathbf p_{\mathrm{NED}}, \qquad \det\mathbf C = +1

Its determinant is +1 (swapping two axes contributes a factor −1 and flipping zz another −1), so it is a proper rotation: a rotation of 180∘180^{\circ} about the axis (1, 1, 0)/2(1,\,1,\,0)/\sqrt{2}, for which R=2R=2nn⊤−I^{\top}-I. The conversion is exact and loses no information.

Body vectors

FRD and FLU conversion
vFLU=(x, −y, −z)FRD,vFRD=(x, −y, −z)FLU\mathbf v_{\mathrm{FLU}} = (x,\ -y,\ -z)_{\mathrm{FRD}}, \qquad \mathbf v_{\mathrm{FRD}} = (x,\ -y,\ -z)_{\mathrm{FLU}}

Body to world with Euler angles

With yaw ψ\psi (about the down or up axis), pitch θ\theta and roll ϕ\phi applied in the ZYX order, a body vector is rotated into the world frame by R=Rz(ψ)Ry(θ)Rx(ϕ)R=R_{z}(\psi )R_{y}(\theta )R_{x}(\phi ):

ZYX rotation matrix
R(ϕ,θ,ψ)=[cos⁡ψcos⁡θcos⁡ψsin⁡θsin⁡ϕ−sin⁡ψcos⁡ϕcos⁡ψsin⁡θcos⁡ϕ+sin⁡ψsin⁡ϕsin⁡ψcos⁡θsin⁡ψsin⁡θsin⁡ϕ+cos⁡ψcos⁡ϕsin⁡ψsin⁡θcos⁡ϕ−cos⁡ψsin⁡ϕ−sin⁡θcos⁡θsin⁡ϕcos⁡θcos⁡ϕ]\mathbf R(\phi,\theta,\psi) = \begin{bmatrix}\cos\psi\cos\theta & \cos\psi\sin\theta\sin\phi - \sin\psi\cos\phi & \cos\psi\sin\theta\cos\phi + \sin\psi\sin\phi\\ \sin\psi\cos\theta & \sin\psi\sin\theta\sin\phi + \cos\psi\cos\phi & \sin\psi\sin\theta\cos\phi - \cos\psi\sin\phi\\ -\sin\theta & \cos\theta\sin\phi & \cos\theta\cos\phi\end{bmatrix}
vworld=R vbody\mathbf v_{\text{world}} = \mathbf R\,\mathbf v_{\text{body}}
ϕ\phi , θ\theta , ψ\psi
roll, pitch, yaw (rad) about the body xx, yy, zz axes (applied yaw first, then pitch, then roll).
cc, ss
cos and sin of the angle that follows.
RR
rotation matrix: orthogonal, with det⁡ R=+1\det \,R=+1 and R−1=RTR^{-1}=R^{T}.

In NED/FRD with the angles defined as in PX4 (roll positive right-wing-down, pitch positive nose-up, yaw clockwise from north) this is the matrix that maps body FRD vectors into NED. Hovering at level attitude, the thrust vector in FRD is (0, 0, −TT): thrust points up, which is negative zz in a down-positive frame.

Euler angles have a singularity at pitch = ±90∘90^{\circ} (gimbal lock). Autopilots store attitude as a quaternion (lesson M5-T4) and use Euler angles only for display.

Architecture and data flow

Frame conversions live at interface boundaries. In the usual PX4 plus ROS 2 stack the data cross them as shown:

  • IMU on the flight controller: body FRD, consumed by EKF2 inside PX4.
  • EKF2 output to the companion over uXRCE-DDS: NED position and velocity, FRD body rates, quaternion from FRD to NED (px4_msgs/VehicleOdometry).
  • Companion algorithms (VIO, planners) in ROS: ENU world, FLU body.
  • Setpoints back to PX4 over uXRCE-DDS: NED. Odometry from the companion to EKF2: converted from ENU/FLU to NED/FRD.

The conversion code therefore appears exactly twice in a well-structured system: once going from PX4 to ROS and once coming back. The px4_ros_com package provides frame-transform helpers for this purpose.

Real-world UAV applications

  • Feeding visual-inertial odometry (computed in ROS ENU/FLU) into PX4’s EKF2 (NED/FRD) as external vision.
  • Sending a position setpoint “5 m north of home at 10 m altitude” in offboard mode: (5, 0, −10) in NED.
  • Interpreting an IMU log: gravity measured by a level, stationary FRD accelerometer is (0, 0, −gg), because the sensor measures specific force (reaction to gravity), not gravity.
  • Combining LiDAR points (sensor frame) with attitude (body frame) and position (world frame) into a map.

Implementation example

A small, tested conversion module is the first thing to write in any UAV autonomy stack. This runs as shown; the round-trip checks catch a wrong sign immediately.

import numpy as np

def ned_to_enu(p):          # (N, E, D) -> (E, N, U)
    return np.array([p[1], p[0], -p[2]])

def enu_to_ned(p):          # (E, N, U) -> (N, E, D)
    return np.array([p[1], p[0], -p[2]])

def frd_to_flu(v):          # (x, y, z) body: forward, right, down -> forward, left, up
    return np.array([v[0], -v[1], -v[2]])

def yaw_ned_to_enu(psi):    # compass heading (cw from north) -> angle ccw from east
    return (np.pi / 2 - psi + np.pi) % (2 * np.pi) - np.pi

def rot_zyx(roll, pitch, yaw):
    cr, sr, cp, sp, cy, sy = np.cos(roll), np.sin(roll), np.cos(pitch), np.sin(pitch), np.cos(yaw), np.sin(yaw)
    return np.array([[cy*cp, cy*sp*sr - sy*cr, cy*sp*cr + sy*sr],
                     [sy*cp, sy*sp*sr + cy*cr, sy*sp*cr - cy*sr],
                     [-sp,   cp*sr,            cp*cr]])

# 1. round trips are exact
p = np.array([3.0, -2.0, -10.0])                 # 10 m above ground in NED
assert np.allclose(enu_to_ned(ned_to_enu(p)), p)
assert ned_to_enu(p)[2] == 10.0                  # up is positive in ENU

# 2. facing east: NED yaw 90 deg == ENU yaw 0
assert abs(yaw_ned_to_enu(np.pi / 2)) < 1e-12

# 3. a level vehicle facing east: body forward axis points east
fwd_ned = rot_zyx(0.0, 0.0, np.pi / 2) @ np.array([1.0, 0.0, 0.0])
assert np.allclose(fwd_ned, [0.0, 1.0, 0.0])     # (N, E, D) = (0, 1, 0)

# 4. R is a proper rotation
R = rot_zyx(0.2, -0.3, 1.0)
assert np.allclose(R @ R.T, np.eye(3)) and abs(np.linalg.det(R) - 1) < 1e-12
print("all frame checks pass")
Frame conversions and the checks that should live next to them.

Common engineering mistakes

Forgetting the sign flip on z

The vehicle “climbs” into the ground or the altitude controller pushes the wrong way. Always check the sign of zz against “10 m above ground”.

Converting position but not yaw

A vehicle that translates correctly but points 90∘90^{\circ} off. Yaw conventions differ, not only axes.

Treating Euler angles as vectors

Roll, pitch and yaw do not add or convert like vectors. Convert the quaternion or rotation matrix, then extract angles if needed.

Confusing the rotation of a vector with the rotation of a frame

RR rotates body coordinates into world coordinates; its transpose does the reverse. Name matrices by direction (R_world_from_body).

Doing conversions inside algorithms

Two different parts of the system then silently assume different frames. Convert at the interface only.

Failure modes

Failure modes, symptoms and causes
Failure modeHow it shows upLikely cause
Altitude sign errorVehicle drives into the ground after takeoff or diverges verticallyDown vs up mismatch between estimate and setpoint
Swapped xx and yyVehicle flies east when told northENU vs NED axis order not converted
Yaw offset of 90∘90^{\circ} or 180∘180^{\circ}Correct shape of path but rotated; camera-IMU extrinsics seem “wrong”Compass heading used as east-referenced angle, or the reverse
Mirror-image trajectoryPath is flipped left to rightLeft-handed frame created by flipping one axis without flipping another

Debugging approach

  1. Command a known motion (for example 2 m north, then 2 m up) and print the setpoint, the estimate and the logged result in one frame.
  2. Hold the vehicle by hand, tilt it nose-down and check the sign of pitch and of the accelerometer’s xx component in both frames.
  3. Round-trip every conversion in a unit test and assert the sign of gravity and of altitude.
  4. Plot xx against yy of the estimate and of an independent reference (GNSS or motion capture) on one chart; a rotation, flip or swap is obvious.

Practical exercises

  1. Convert the NED position (120, −45, −30) to ENU and state in words where the vehicle is.
  2. A vehicle faces south-west. Give its yaw in NED and in ENU.
  3. Show that CNED→ENUC_{\text{NED}\to \text{ENU}} is a proper rotation by computing its determinant, and find its rotation axis and angle.
  4. A level, stationary FRD accelerometer reads (0, 0, −9.81). Predict the reading in FLU, and after a 30∘30^{\circ} nose-up pitch.
  5. Write a unit test that fails if anyone changes the sign convention of one conversion.

Interview questions

Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.

Question 1

What is the difference between NED and ENU, and which do PX4 and ROS use?

Model answer

NED is North-East-Down and ENU is East-North-Up. PX4 uses NED for world frames and FRD for the body; ROS (REP-103) uses ENU for world frames and FLU for the body. Position converts as (x, y, z)ENU=(y, x, −z)NED(x,\,y,\,z)_{\text{ENU}}=(y,\,x,\,-z)_{\text{NED}}.

Question 2

A UAV flies correctly in a straight line in SITL but mirrored on a real VIO input. What do you check first?

Model answer

The frame conventions at the VIO-to-EKF2 boundary: ENU/FLU versus NED/FRD, including the sign of yy and zz and the yaw convention, and whether a single axis flip produced a left-handed frame.

Question 3

Why does a stationary level accelerometer read +g up (or −gg in a down-positive frame) rather than zero?

Model answer

An accelerometer measures specific force: the non-gravitational force per unit mass. Resting on a surface, the support force equals −gg in the inertial sense, so it reads 1 gg opposite to gravity, which points up in a z-up frame and is −gg on zz in a z-down frame.

References and further reading

Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.

What’s next

Mark this lesson

Saved in this browser and synced to your account when you are signed in.

Practice this lesson

M1-L2: Visualize UAV coordinate frames

Rotate a vector between body, NED and ENU and check handedness.

Next lesson

M1-T5: Six-degree-of-freedom UAV dynamics

Write the Newton–Euler equations of a rigid-body quadrotor and identify each state.