State of a set of joints.
Fields
names- List of joint names as atomspositions- Joint configurationsvelocities- Joint velocitiesefforts- Joint efforts
All lists must have the same length. Missing values can be represented as empty lists.
Values are shaped to the joint's type
A joint with more than one degree of freedom has no single number to report, so
each list is heterogeneous and its elements line up with names:
| Joint type | positions | velocities | efforts |
|---|---|---|---|
| single-DoF | float | float | float |
:planar | BB.Math.Transform2D | BB.Message.Geometry.Twist2D | BB.Message.Geometry.Wrench2D |
:floating | BB.Math.Transform | BB.Message.Geometry.Twist | BB.Message.Geometry.Wrench |
Most consumers only ever see single-DoF joints, so in practice their handling is unchanged — but a consumer that pattern matches on a float, or does arithmetic on an element, should say which joint types it supports.
Splitting multi-DoF state into a separate message type was considered and rejected: a robot's joint state would then arrive on two topics, and every consumer wanting the whole configuration would have to subscribe to both and correlate them by timestamp to reconstruct one instant. That is a permanent tax on every consumer, levied to avoid changing one message.
All three lists changed together for the same reason. velocities and efforts
have precisely the same problem as positions, and breaking a widely-consumed
message twice is worse than breaking it once.
Examples
alias BB.Message.Sensor.JointState
{:ok, msg} = JointState.new(:arm,
names: [:joint1, :joint2],
positions: [0.0, 1.57],
velocities: [0.1, 0.0],
efforts: [0.5, 0.2]
)
# A mobile base reports its whole pose in the same message as its mast
{:ok, msg} = JointState.new(:rover,
names: [:base, :mast],
positions: [BB.Math.Transform2D.new(12.4, -3.1, 1.57), 0.5]
)
Summary
Types
A joint's configuration, shaped to its type.
A joint's effort, shaped to its type.
A joint's velocity, shaped to its type.
Types
@type configuration() :: float() | BB.Math.Transform2D.t() | BB.Math.Transform.t()
A joint's configuration, shaped to its type.
@type effort() :: float() | BB.Message.Geometry.Wrench2D.t() | BB.Message.Geometry.Wrench.t()
A joint's effort, shaped to its type.
@type t() :: %BB.Message.Sensor.JointState{ efforts: [effort()], names: [atom()], positions: [configuration()], velocities: [velocity()] }
@type velocity() :: float() | BB.Message.Geometry.Twist2D.t() | BB.Message.Geometry.Twist.t()
A joint's velocity, shaped to its type.
Functions
@spec new( atom(), keyword() ) :: {:ok, BB.Message.t()} | {:error, term()}