44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""The wire shape of a `joy` message.
|
|
|
|
dora 1.0 has no standard joystick type, so this schema is the whole contract a
|
|
consumer gets. It is **declared, never inferred**: pyarrow reads an empty
|
|
`axes` list as `list<null>`, which would mean the port silently changed type the
|
|
moment somebody unplugged the pad.
|
|
|
|
It is not `sensor_msgs/Joy`. There is no header, because dora already knows when
|
|
a message arrived and a second clock in the payload only invites skew questions;
|
|
buttons are booleans rather than ROS's `int32`, because a button is down or it is
|
|
not; and `present` is a field rather than an absence of messages, because a
|
|
consumer stopping a robot needs to tell "the pad is centred" from "the pad is
|
|
gone" within a tick rather than within a timeout.
|
|
"""
|
|
|
|
import pyarrow as pa
|
|
|
|
from dora_joy.gamepad import Sample
|
|
|
|
JOY = pa.struct(
|
|
[
|
|
# Raw, exactly as SDL reports it: no deadzone, no expo, no rescaling.
|
|
# Shaping is a decision about what the pad means, which belongs to
|
|
# whoever is driving something with it.
|
|
("axes", pa.list_(pa.float32())),
|
|
("buttons", pa.list_(pa.bool_())),
|
|
("present", pa.bool_()),
|
|
]
|
|
)
|
|
|
|
|
|
def pack(sample: Sample) -> pa.Array:
|
|
"""Build one `joy` message from a reading."""
|
|
return pa.array(
|
|
[
|
|
{
|
|
"axes": [float(value) for value in sample.axes],
|
|
"buttons": [bool(down) for down in sample.buttons],
|
|
"present": sample.present,
|
|
}
|
|
],
|
|
type=JOY,
|
|
)
|