Skip to main content

SSL ground data plane: telemetry sources, protocol bridges, and telecommand for simulated and real vehicles

Project description

ssl_link

The SSL ground data plane — one interface for getting robot data (from a log, a running simulation, or a real vehicle over telemetry) and one interface for sending commands back. Simulated and real vehicles look identical to everything downstream.

The link is the channel between your vehicles (simulated in ssl_simulator, or flying over pprzlink/Ivy) and your ground applications (the ssl_vista viewer, GCS tools, analysis notebooks) — telemetry down, telecommand up. It owns the canonical log format, so every producer writes files that every consumer reads.


Everything in ssl_link is built from two contracts. Learn these and the rest is adapters.

1. A frame is (time, {name: array}). A snapshot of the world: named, entity-indexed arrays (p is (N, 3), R is (N, 3, 3), …) at one instant. This is exactly what ssl_simulator.Engine hands to its sink, what goes on the wire, and what a telemetry parser produces. It is the same vocabulary of components the simulator uses. So a plotter that reads "p" doesn't care whether the number came from a solver an hour ago or a radio a millisecond ago.

2. Data flows through a DataSource; commands flow through a Commander.

                        ┌─────────────── ssl_link ───────────────┐
 producers              │  in:  DataSource   out: Commander      │   consumers
 ─────────              │  ┌──────────────┐  ┌────────────────┐  │   ─────────
 Engine(sink=…) ───────►│  │ StreamSource │  │ SimCommander   │◄─┼── vista / GCS panels
 udp datagrams ────────►│  │ UdpSource    │  │ IvyCommander   │  │   analysis notebooks
 pprzlink/Ivy ─────────►│  │ IvyFeed      │  │                │──┼──► real vehicles (Ivy)
 a .csv/.npz/.h5 log ──►│  │ LoggedSource │  └────────────────┘  │
                        │  └──────────────┘                      │
                        │  persistence: DataLogger / save_sim / load_sim (the log standard)
                        └────────────────────────────────────────┘

A DataSource is a plain Mapping (source["p"] gives (T, N, 3)) plus liveness (is_live, revision) and frame access (frame(idx), time(idx), history(...)). A viewer binds to a source and never knows which subclass it got. A Commander exposes the telecommand surface (setting, move_waypoint, jump_to_block) — a GCS panel calls it and never knows whether the target is simulated or flying.


Installation

pip install ssl_link

The core (DataSource, the wire format, persistence for csv/npz) needs only numpy + msgpack. Extras add capability:

Extra Adds Needed for
ssl_link[hdf5] h5py reading/writing .h5 log files
ssl_link[pprz] ivy-python the Ivy bridges & IvyCommander (real Paparazzi vehicles)
ssl_link[all] both of the above

Note. ssl_link does not depend on ssl_simulator. the data plane is producer-agnostic. The relationship is the other way round: ssl_simulator depends on ssl_link for the log format, so simulated and real runs share one on-disk standard. Install ssl_simulator separately when you want the simulator as a data producer.


Tutorial

1. A source is a live, seekable view of frames

StreamSource is the base live buffer: push frames in, read them back like a finished run.

import numpy as np
from ssl_link import StreamSource

source = StreamSource(capacity=1000)             # bounded ring: keeps the last 1000 frames
for k in range(5):
    source.push(k * 0.1, {"p": np.full((3, 2), float(k))})   # (time, frame)

source["p"].shape        # (5, 3, 2)  — stacked like a logged run
source.n_frames          # 5
source.frame(-1)["p"]    # the latest snapshot: (3, 2)
source.is_live           # True

It's bounded on purpose, a telemetry link runs for hours, so an unbounded buffer isn't an option. It rejects a changing set of component names mid-stream, so ragged data can't creep in.

2. Live-stream a running simulation (needs ssl_simulator)

StreamSource.push has exactly the signature of ssl_simulator.Engine's streaming sink — so connecting a running sim to a live source is one argument, no glue:

from ssl_simulator import Engine
# ... build a `world` (see ssl_simulator) ...

stream = StreamSource(capacity=2000)
Engine(time_step=0.01, log_time_step=0.1, sink=stream.push).run(world, duration=60.0)
# `stream` fills as the engine runs; hand it to a viewer to watch live.

3. Cross a process boundary with UDP

udp_sink is a sink that publishes each frame as one msgpack datagram; UdpSource receives them on a background thread and pushes them into itself. Producer and consumer can be different terminals or machines.

# producer process:
from ssl_link.transports import udp_sink
Engine(sink=udp_sink(host="127.0.0.1", port=4700)).run(world, 60.0)

# consumer process (a viewer, a recorder, …):
from ssl_link.sources import UdpSource
with UdpSource(port=4700, capacity=2000).start() as source:
    ...  # `source` is a DataSource that fills as datagrams arrive

A UDP-streamed run is byte-for-byte the same as the logged replay of the same run — the wire adds nothing but distance.

4. Persist to the canonical log format

The formats (.csv with a # SETTINGS: header, .npz, .h5) are the shared standard. Any producer's output opens in any consumer:

from ssl_link import save_sim, load_sim

save_sim("run.csv", {"time": t, "p": p, "R": R}, settings={"gain": 0.5})
data, settings = load_sim("run.csv")          # data["p"] -> (T, N, 3)

from ssl_link.sources import LoggedSource
source = LoggedSource.from_file("run.csv")     # replay a log through the same DataSource interface

DataLogger is the streaming writer the simulator's engine uses (writes a row per tick); reach for save_sim when you already have the whole run in memory.

5. WIP: Send commands — the same code for sim and reality

A Commander is the telecommand surface. Point a GCS panel at one and swap the implementation underneath:

from ssl_link.command import SimCommander, IngestCommands

commander = SimCommander()                     # queues commands into a running world
world.add_system(IngestCommands(commander, {   # the world declares what each command does
    "setting": lambda w, ac_id, cmd: w["gain"].__setitem__(ac_id, cmd["value"]),
}))
# ... run the engine in a thread ...
commander.setting(ac_id=0, index=0, value=4.0) # mid-run: drone 0's gain becomes 4.0

Swap SimCommander for IvyCommander (needs ssl_link[pprz]) and the identical commander.setting(...) call radios a real Paparazzi aircraft instead. That symmetry — one command API, sim or reality — is the point of the layer.

6. WIP: Bridge a real Paparazzi swarm (needs ssl_link[pprz])

IvyTelemetrySink publishes a simulation onto the Ivy bus as per-aircraft pprzlink telemetry, so existing ground tools see a simulated swarm exactly as they see real drones. IvyFeed does the reverse — assembles incoming telemetry back into component frames for a viewer. Both are driven by one mapping table (bridges.DEFAULT_TELEMETRY_MAP) so the two directions can't drift apart.

Scope. IvyTelemetrySink emulates the telemetry surface, not the firmware. Full PprzGCS visibility additionally requires server.ml with the aircraft in conf.xml (the ALIVE/CONFIG handshake). Lab tools that subscribe telemetry directly by ac_id need none of that.


Package map

ssl_link/
  sources/       DataSource (the contract) · LoggedSource · StreamSource · UdpSource
  transports/    encode_frame/decode_frame (msgpack wire) · udp_sink (an Engine sink)
  persistence/   DataLogger · save_sim · load_sim   — the canonical log standard
  bridges/       IvyTelemetrySink · IvyFeed · the message↔component mapping table   [pprz]
  command/       Commander (protocol) · SimCommander/IngestCommands · IvyCommander

Top-level shortcuts: from ssl_link import DataSource, LoggedSource, StreamSource, DataLogger, load_sim, save_sim.


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ssl_link-0.1.0.tar.gz (26.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ssl_link-0.1.0-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page