Quick Start#
ltcodecs encodes structured Python dictionaries and ROS messages into
compact bit streams. A codec is configured with a field dictionary: each field
name maps to a codec alias and the parameters for that field codec.
Install#
Install the package from PyPI:
pip install ltcodecs
For local development, install the checkout in editable mode:
pip install -e .
Encode a Dictionary#
The quickest way to use ltcodecs is with
ltcodecs.dict_codec.DictCodec. This path does not require ROS.
from bitstring import ConstBitStream
import ltcodecs
fields = {
"name": {
"codec": "string",
"max_length": 10,
},
"count": {
"codec": "integer",
"min_value": 0,
"max_value": 100,
},
"enabled": {
"codec": "bool",
},
}
message = {
"name": "test",
"count": 21,
"enabled": True,
}
codec = ltcodecs.DictCodec(fields)
bits, metadata = codec.encode(message)
decoded = codec.decode(ConstBitStream(bits))
assert decoded == message
The bits value is a bitstring.Bits object. The metadata return
value is usually None unless the field configuration includes one of the
metadata encoder aliases.
Encode Metadata#
encode() for the Message/Dictionary codecs returns a tuple of (bits, metadata).
The first value is the encoded bit stream.
The second value is a small metadata dictionary for values
that should travel outside the compressed payload, such as packet routing
fields. Most codecs return None for metadata, and you can ignore it.
It is possible to define fields that
use metadata encoders rather than (or in addition to) adding bits to the output stream.
Use YAML Configuration#
Codec configurations are commonly stored as YAML. The same dictionary codec above can be written as:
name:
codec: string
max_length: 10
count:
codec: integer
min_value: 0
max_value: 100
enabled:
codec: bool
Load the YAML file with
ltcodecs.dict_codec.DictCodec.from_codec_file():
from bitstring import ConstBitStream
import ltcodecs
codec = ltcodecs.DictCodec.from_codec_file("message_codec.yaml")
bits, _metadata = codec.encode({
"name": "test",
"count": 21,
"enabled": True,
})
decoded = codec.decode(ConstBitStream(bits))
Nested Dictionaries and Optional Fields#
A field can itself be a dictionary. Use the dict codec and provide a
nested fields mapping:
nested:
codec: dict
fields:
value:
codec: uint8
Optional fields are controlled by a boolean field. If the controlling value is true, the target fields are encoded. If false, those fields use no bits.
has_extra:
codec: optional
target_fields:
extra:
codec: uint8
The input dictionary for that configuration would include both the controlling field and the target field:
message = {
"has_extra": True,
"extra": 42,
}
Encode a ROS Message#
Use ltcodecs.ros_message_codec.RosMessageCodec for ROS messages.
If no field dictionary is provided, ltcodecs asks ARMW for the message
fields and chooses codecs from the ROS field types.
from bitstring import ConstBitStream
import armw
import ltcodecs
String = armw.import_message("std_msgs", "String")
msg = String()
msg.data = "hello"
codec = ltcodecs.RosMessageCodec("std_msgs/String")
bits, metadata = codec.encode(msg)
decoded = codec.decode(ConstBitStream(bits))
assert decoded.data == "hello"
You can also provide a YAML field configuration for a ROS message:
data:
codec: string
max_length: 10
codec = ltcodecs.RosMessageCodec.from_codec_file(
"std_msgs/String",
"string_msg_codec.yaml",
)
ROS 1 and ROS 2 Type Names#
ROS message fields may use ROS 1 style type names such as pkg/Msg and
pkg/Msg[] or ROS 2 introspection names such as pkg/msg/Msg and
sequence<pkg/msg/Msg>. ltcodecs normalizes these forms when it infers
fields from a ROS message or when an explicit field config contains a ROS type.
For arrays, use the array codecs directly when writing explicit configs:
samples:
codec: variable_len_array
max_length: 10
element_type: uint8
points:
codec: fixed_len_array
length: 3
element_type: msg
element_params:
ros_type: geometry_msgs/Point
Checksums#
Top-level dictionary and ROS message codecs can append a checksum. Supported
values are crc8 and crc32.
codec = ltcodecs.DictCodec(fields, checksum="crc8")
bits, _metadata = codec.encode(message)
decoded = codec.decode(ConstBitStream(bits))
If the received checksum does not match the encoded content, decode raises
ValueError.
Next Steps#
See Codec Reference for the codec reference, Codec Aliases for the full alias table, and Python API for the generated API reference.