Skip to content

Estimator

The estimator is the first block of the control cascade: each tick it turns the sensors' values into the estimate, the vehicle's state that the guidance and the controller read. It's a component of the loop, and its stages run after the sensors' and before the guidance's. The estimate is the estimate signal, of the type PoseTwist: the base body's position, its quaternion, and its linear and angular velocity, in world axes. The guidance and each controller that reads the vehicle's state read it, never the physics state, so a controller written against the estimate flies behind any estimator.

One estimator ships, GroundTruthEstimator, a passthrough that hands on the base body's true pose and twist with no noise and no delay. Its stage also runs once over the settled state before the first tick, so the guidance's first stage reads an estimate. A run whose guidance or controller reads the estimate, and that has no estimator, fails before any stage runs, with an error that names the readers and the estimator. PX4 takes none, because its own estimator runs in its peer and takes the sensors' values over the lockstep link.

The estimator belongs to the vehicle's flight stack, beside its controller, and the vehicle's Universal Scene Description (USD) file declares it. The shipped class is internal: a vehicle names it by its schema, and a project's estimator subclasses Component and writes a PoseTwist, which nexus_uav exports.

GroundTruthEstimator

GroundTruthEstimator()

Bases: Component

The passthrough estimator: its stage copies the pose and twist its pose input holds, the plant's output for the base body unless a connection on its prim names another body, to the signal estimate, in world axes, with no noise and no delay. So a guidance or a controller that reads the estimate reads the values of the physics state, and one written against the estimate runs behind any estimator.

Source code in nexus_uav/_src/vehicle/estimators/ground_truth.py
19
20
21
def __init__(self):
    self.pose = Signal("pose", PoseTwist, shape=(1,))
    self.estimate = Signal("estimate", PoseTwist, shape=(1,))

pose instance-attribute

pose = Signal('pose', PoseTwist, shape=(1,))

estimate instance-attribute

estimate = Signal('estimate', PoseTwist, shape=(1,))

stages

stages() -> list[Stage]

One warm device stage, estimate, which copies the pose into the estimate. The loop runs it after the sensors' stages and before the guidance's, and once over the settled state before the first tick, so the guidance's first stage reads an estimate.

Source code in nexus_uav/_src/vehicle/estimators/ground_truth.py
23
24
25
26
27
28
def stages(self) -> list[Stage]:
    """One warm device stage, ``estimate``, which copies the pose into the estimate. The loop runs it after
    the sensors' stages and before the guidance's, and once over the settled state before the first tick,
    so the guidance's first stage reads an estimate.
    """
    return [Stage("estimate", "device", self._run, reads=(self.pose,), writes=(self.estimate,))]

PoseTwist

The pose and twist of one body in world axes: what the plant writes per body, as the signal body/<label> of shape (1,), and the estimate an estimator writes, as the signal estimate, which the guidance and the controllers read.

position instance-attribute

position: vec3

The body's origin, metres.

orientation instance-attribute

orientation: quat

The body's orientation, a quaternion in (x, y, z, w) order.

linear_velocity instance-attribute

linear_velocity: vec3

The velocity of the body's center of mass, m/s.

angular_velocity instance-attribute

angular_velocity: vec3

The body's angular velocity, rad/s.