Command line tools for monitoring and debugging LCM (Lightweight Communications and Marshalling)
Project description
LCM CLI Tools
Command line tools for monitoring and debugging LCM (Lightweight Communications and Marshalling) networks.
Features
lcm topic echo <channel> — View real-time topic data
lcm topic list — List active topics/channels
lcm topic stats — Real-time topic stats: rate, bandwidth, msg count
lcm topic bw <channel> — Monitor bandwidth for a single channel with sparkline graph
lcm topic info <channel> — Detailed channel information with type structure
lcm node list — List discovered publisher nodes
lcm type list — List all registered LCM types
lcm type show <type> — Show type field structure
lcm record — Record live LCM traffic to .log file
lcm play <file.log> — Replay .log file to multicast
Highlights:
- Built-in pure-Python
.lcmfile parser — nolcm-genorPYTHONPATHneeded - Message Export: CSV/JSONL export with field extraction (
--csv,--jsonl,--field) - Advanced Monitoring: Sort/filter stats (
--sort,--top,--freeze,--spark) - Live Watch Mode: Continuous refresh for topic/node list (
--watch) - Recording & Playback: Full log file support compatible with
lcm-logger
Installation
# From PyPI
pip install lcm-cli
# From source (development)
git clone https://github.com/Joyserr/lcm-cli.git
cd lcm-cli
pip install -e .
# Optional: traditional lcm-gen Python package decode support
pip install lcm-cli[decode]
Requirements: Python >= 3.9, typer, rich (lcm package is optional, only for legacy --type module.Class decoding).
Quick Start
# Show all subcommands
lcm --help
# Show version
lcm --version
# List active channels (listens for 5 seconds)
lcm topic list
# Continuous watch mode (live refresh)
lcm topic list --watch
# View messages on a channel (raw hex format)
lcm topic echo EXAMPLE
# Receive only 10 messages
lcm topic echo EXAMPLE -n 10
# Match multiple channels with regex
lcm topic echo "CAM.*"
# Monitor real-time statistics for all channels
lcm topic stats
# Sort by bandwidth, show top 5
lcm topic stats --sort bw --top 5
# Freeze mode (single snapshot)
lcm topic stats --freeze
# Monitor bandwidth with sparkline graph
lcm topic bw CAMERA --spark
# Detailed channel information
lcm topic info CAMERA --lcm-file types/
# List discovered publisher nodes
lcm node list
Recording & Playback
# Record all channels to a .log file
lcm record
# Record specific channels with regex
lcm record --channel "CAM.*" -o camera.log
# Record for a fixed duration
lcm record -d 60 # 60 seconds
# Replay a .log file
lcm play camera.log
# Replay at 2x speed
lcm play camera.log --speed 2.0
# Loop playback
lcm play camera.log --loop
Message Export
# Export to CSV (headers auto-determined from first message)
lcm topic echo EXAMPLE --csv output.csv
# Export to JSON Lines
lcm topic echo EXAMPLE --jsonl output.jsonl
# Extract specific fields
lcm topic echo EXAMPLE --field position --field velocity --csv data.csv
# Extract nested fields
lcm topic echo EXAMPLE --field imu.accel.x --field imu.gyro.y
# Extract array slices
lcm topic echo EXAMPLE --field "position[0:2]"
# Custom timestamp format
lcm topic echo EXAMPLE --csv data.csv --ts-format iso
Advanced Statistics
# Sort channels by message rate
lcm topic stats --sort rate
# Show top 10 channels by bandwidth
lcm topic stats --sort bw --top 10
# Single snapshot (non-interactive)
lcm topic stats --freeze
# Add sparkline trend visualization
lcm topic stats --spark
# Monitor bandwidth for a single channel
lcm topic bw CAMERA --window 10 --spark
# Read stats from log file
lcm topic stats --from recording.log
Message Decoding
Type Diagnostics
# List all registered types
lcm type list
# Filter by package
lcm type list --package exlcm
# Show type structure
lcm type show example_t --lcm-file types/
# Grep search types
lcm type list --grep "sensor"
Method 1: Specify .lcm files directly (recommended)
No lcm-gen installation, no PYTHONPATH configuration. The tool includes a built-in pure-Python parser:
# Specify a single .lcm file — auto-matches message type by fingerprint
lcm topic echo EXAMPLE --lcm-file types/example_t.lcm
# Specify a directory (recursively scans all .lcm files)
lcm topic echo EXAMPLE -f types/
# Specify multiple paths
lcm topic echo EXAMPLE -f types/ -f extra_types/
# Specify a concrete type name (when .lcm files contain multiple structs)
lcm topic echo EXAMPLE -f types/ --type example_t
Supports the complete LCM type system:
- All primitive types (
int8_t~int64_t,float,double,string,boolean,byte) - Fixed-length and variable-length arrays (
double position[3],int16_t ranges[num_ranges]) - Multi-dimensional arrays (
int32_t data[size_a][size_b][size_c]) - Nested structs and cross-file type references
- Recursive types (e.g.,
node_t children[n]in a linked-listnode_t) - Constant declarations (
const int32_t MAX_SIZE = 100)
How it works: Parses .lcm files → builds decode classes in memory (type() dynamic creation) → auto-matches by the first 8-byte fingerprint of the payload → decodes and recursively expands nested structs. No files are generated at any point.
Method 2: Traditional lcm-gen generated files
# Install the lcm Python package
pip install lcm-cli[decode]
# Generate Python files with lcm-gen, then configure PYTHONPATH
lcm-gen --python -d types/ types/example_t.lcm
export PYTHONPATH=types:$PYTHONPATH
# Use --type to specify the decode class (module.Class format)
lcm topic echo EXAMPLE --type exlcm.example_t
Custom Multicast Address
lcm topic list --lcm-url 239.255.76.68 --lcm-port 7668
Statistics
| Metric | Description |
|---|---|
| Rate (Hz) | Message frequency within a sliding window (last 2000 messages) |
| BW (KB/s) | Bandwidth within the sliding window |
| Avg Size (B) | Average bytes per message |
| Total (KB) | Cumulative total transferred |
Architecture
┌───────────────────────────────────────────────────┐
│ CLI Layer (Typer) │
│ topic echo │ topic list │ topic stats │ node │
├───────────────────────────────────────────────────┤
│ Display Layer (Rich Panel) │
│ recursive nesting │ hex dump │ stats table │
├───────────────────────────────────────────────────┤
│ Type Parsing Layer (Pure Python) │
│ .lcm parse → AST → fingerprint → dynamic class │
├───────────────────────────────────────────────────┤
│ Protocol Layer (Raw UDP Socket) │
│ LCM Wire Protocol parsing (zero deps) │
├───────────────────────────────────────────────────┤
│ UDP Multicast (239.255.76.67) │
└───────────────────────────────────────────────────┘
- Zero external LCM dependency: Core functionality directly parses the LCM wire protocol from UDP multicast packets
- Built-in type parsing: Pure-Python
.lcmfile parser + runtime decode class generator - Node discovery: Infers different publishers from UDP packet source IP:port
- Legacy decode compatible: Optional
lcmPython package for--type module.Classdecoding
LCM Protocol
LCM uses UDP multicast for communication (default 239.255.76.67:7667).
Short messages (< 64KB): 8-byte header (magic=0x4c433032 + seqno) + channel name (null-terminated) + payload
Fragmented messages: 20-byte header (magic=0x4c433033 + seqno + payload_size + fragment_offset + fragment_no + n_fragments)
Reference: LCM UDP Multicast Protocol
LCM vs ROS2 Concepts
LCM and ROS2 share similar pub/sub communication patterns. Here's a concept mapping:
| LCM Concept | ROS2 Equivalent | Description |
|---|---|---|
| Channel | Topic | Message publish/subscribe conduit |
| UDP (IP:port) | Node | LCM has no native node concept; inferred from publisher address |
| Fingerprint | Message Type Hash | Unique identifier for a message type |
Project Structure
src/lcm_cli/
├── __init__.py # Package definition + version
├── __main__.py # python -m lcm_cli entry point
├── cli.py # Typer entry point, registers subcommands
├── commands/
│ ├── topic_echo.py # lcm topic echo (with --csv/--jsonl export)
│ ├── topic_list.py # lcm topic list (with --watch mode)
│ ├── topic_stats.py # lcm topic stats (with --sort/--top/--freeze)
│ ├── topic_bw.py # lcm topic bw (bandwidth monitor)
│ ├── topic_info.py # lcm topic info (channel details)
│ ├── node_list.py # lcm node list (with --watch mode)
│ ├── type_list.py # lcm type list
│ ├── type_show.py # lcm type show
│ ├── record.py # lcm record
│ └── play.py # lcm play
├── core/
│ ├── discovery.py # Passive channel/node discovery
│ ├── stats.py # Real-time statistics (rate, bandwidth)
│ ├── lcm_type_parser.py # .lcm file parser + fingerprint algorithm
│ └── lcm_type_builder.py # Runtime decode class generation + TypeRegistry
├── display/
│ ├── echo_display.py # Rich panel display (with recursive nesting)
│ ├── stats_display.py # Statistics table display (with sparkline)
│ └── type_display.py # Type structure table display
├── export.py # Field extraction + CSV/JSONL writers
├── lcm_log.py # LCM log file reader/writer (lcm-logger compatible)
├── listener.py # UDP multicast listener thread
├── protocol.py # LCM Wire Protocol parser
└── source.py # PacketSource abstraction (live/offline)
Testing
pip install -e ".[dev]"
pytest tests/ -v
Network Configuration
If you can't receive messages, check your multicast routing:
macOS:
# View multicast routes
netstat -rn | grep 239
# Add route if needed
sudo route add -net 239.255.76.0/24 -interface en0
Linux:
# Add route
sudo ip route add 239.255.76.0/24 dev eth0
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lcm_cli-0.2.0.tar.gz.
File metadata
- Download URL: lcm_cli-0.2.0.tar.gz
- Upload date:
- Size: 59.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8dcd8bbf60f249678a30f67819a77843902f75ad870c86f5aad0b05467da4b18
|
|
| MD5 |
bb663a91bcfbd7af095a5d047c941987
|
|
| BLAKE2b-256 |
0cb1156729aa1b399b9edd0410f7c055bcc42b8703bdff9937c0b43c6d563f43
|
Provenance
The following attestation bundles were made for lcm_cli-0.2.0.tar.gz:
Publisher:
ci.yml on Joyserr/lcm-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lcm_cli-0.2.0.tar.gz -
Subject digest:
8dcd8bbf60f249678a30f67819a77843902f75ad870c86f5aad0b05467da4b18 - Sigstore transparency entry: 1895385996
- Sigstore integration time:
-
Permalink:
Joyserr/lcm-cli@d1bfd67a513967959334dde4b51f46964dddf859 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Joyserr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@d1bfd67a513967959334dde4b51f46964dddf859 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lcm_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: lcm_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 54.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b949ba8bf136f80d8735ba9fd085423c2b6b12d52d51582481c79e70b91d128
|
|
| MD5 |
c38b68ad5e7ad5c92e9f140358dc2345
|
|
| BLAKE2b-256 |
613cf5e979a2780265569f02d7b6a017e3682c0396cdc428ff462bff17745b09
|
Provenance
The following attestation bundles were made for lcm_cli-0.2.0-py3-none-any.whl:
Publisher:
ci.yml on Joyserr/lcm-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lcm_cli-0.2.0-py3-none-any.whl -
Subject digest:
0b949ba8bf136f80d8735ba9fd085423c2b6b12d52d51582481c79e70b91d128 - Sigstore transparency entry: 1895386155
- Sigstore integration time:
-
Permalink:
Joyserr/lcm-cli@d1bfd67a513967959334dde4b51f46964dddf859 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Joyserr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@d1bfd67a513967959334dde4b51f46964dddf859 -
Trigger Event:
push
-
Statement type: