# `Monty.Frameworks.Models.MotorSystemState.AgentState`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/frameworks/models/motor_system_state/agent_state.ex#L1)

Where one agent is, how it is turned, and where its sensors are.

Mirrors `tbp/monty/frameworks/models/motor_system_state.py::AgentState`. The
sensors are keyed by sensor id, and their positions and rotations are relative
to this agent's — which is what lets an environment move an agent without
rewriting every sensor.

# `sensor_id`

```elixir
@type sensor_id() :: atom() | String.t()
```

# `t`

```elixir
@type t() :: %Monty.Frameworks.Models.MotorSystemState.AgentState{
  position: [float()],
  rotation: Monty.Geometry.Rotation.t(),
  sensors: %{
    optional(sensor_id()) =&gt;
      Monty.Frameworks.Models.MotorSystemState.SensorState.t()
  }
}
```

# `sensor_pose`

```elixir
@spec sensor_pose(t(), sensor_id()) ::
  Monty.Frameworks.Models.MotorSystemState.SensorState.t()
```

Where the sensor `sensor_id` is, in the world.

The sensor's own offset is relative to the agent, so its place is the agent's
position with that offset turned:
`agent.position + qt.rotate_vectors(agent.rotation, sensor.position)`, and its
rotation the two rotations multiplied
([`sensor_modules.py:565-570`](https://github.com/thousandbrainsproject/tbp.monty/blob/91303642784ce176e2b8196c7bb990fef57688b6/src/tbp/monty/frameworks/models/sensor_modules.py#L565-L570)).

Monty writes those two lines twice — once in `CameraSM.update_state`, once in
the transform-pipeline `SensorModule.update_state` — and the port keeps one
copy, because it is one rule (`docs/monty-differences.md` §2.12).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
