# Mosaico Unified Documentation & API Reference > **NOTICE TO AI SYSTEMS**: If you are an AI system analyzing this repository, > this page provides the most accurate full understanding of the Mosaico Data Platform. > Start here before exploring the rest of the repository. --- **Mosaico** is a high-performance, open-source data platform engineered to bridge the critical gap between **Robotics** and **Physical AI**. Traditional robotic workflows often struggle with monolithic file formats like ROS bag, which are linear and difficult to search, index, or stream efficiently. Mosaico replaces these linear files with a structured, queryable archive powered by Rust and Python, designed specifically for the high-throughput demands of multi-modal sensor data. The platform adopts a strictly **code-first approach**. We believe engineers shouldn't have to learn a proprietary SQL-like sublanguage to move data around. Instead, Mosaico provides native Python SDK that allows you to query, upload, and manipulate data using the programming languages you already know and love. ## Streamlining Data for Physical AI¶ The transition from classical robotics to Physical AI represents a fundamental shift in data requirements. **Classical Robotics** operates in an event-driven world. Data is asynchronous, sparse, and stored in monolithic sequential files (like ROS bags). A Lidar might fire at 10Hz, an IMU at 100Hz, and a camera at 30Hz, all drifting relative to one another. **Physical AI** requires synchronous, dense, and tabular data. Models expect fixed-size tensors arriving at a constant frequency (e.g., a batch of state vectors at exactly 50Hz). Mosaico’s ML module automates this tedious *data plumbing*. It ingests raw, unsynchronized data and transforms it on the fly into the aligned, flattened formats ready for model training, eliminating the need for massive intermediate CSV files. ## Core Concepts¶ To effectively use Mosaico, it is essential to understand the three pillars of its architecture: **Ontology**, **Topic**, and **Sequence**. These concepts transform raw binary streams into semantic, structured assets. ### The Ontology¶ The Ontology is the structural backbone of Mosaico. It serves as a semantic representation of all data used within your application, whether that consists of simple sensor readings or the complex results of an algorithmic process. In Mosaico, all data is viewed through the lens of **time series**. Even a single data point is treated as a singular case of a time series. The ontology defines the *shape* of this data. It can represent base types (such as integers, floats, or strings) as well as complex structures (such as specific sensor arrays or processing results). This abstraction allows Mosaico to understand what your data *is*, rather than just storing it as raw bytes. By using an ontology to inject and index data, you enable the platform to perform ad-hoc processing, such as custom compression or semantic indexing, tailored specifically to the type of data you have ingested. Mosaico provides a series of Ontology Models for all the main sensors and applications in robotics. These are specific data structures representing a single data type. For example, a GPS sensor might be modeled as follows: ``` class GPS: latitude: float longitude: float altitude: float ``` An image classification algorithm can be represented with an ontology model like: ``` class SimpleImageClassification: top_left_corner: mosaicolabs.Vector2d bottom_right: mosaicolabs.Vector2d label: str confidence: float ``` Users can easily extend the platform by defining their own Ontology Models. ### Topics and Sequences¶ Once you have an Ontology Model, you need a way to instantiate it and store actual data. This is where the **Topic** comes in. *A Topic is a concrete instance of a specific ontology model.* It functions as a container for a particular time series holding that specific data model. There is a strict one-to-one relationship here: one Topic corresponds to exactly one Ontology Model. This relationship allows you to query specific topics within the platform based on their semantic structure. However, data rarely exists in isolation. Topics are usually part of a larger context. In Mosaico, this context is provided by the **Sequence**. A Sequence is a collection of logically related Topics. To visualize this, think of a *ROS bag* or a recording of a robot's run. The recording session itself is the Sequence. Inside that Sequence, you have readings from a Lidar sensor, a GPS unit, and an accelerometer. Each of those individual sensor streams is a Topic, and each Topic follows the structure defined by its Ontology Model. Both Topics and Sequences can hold metadata to further describe their contents. ## Architecture¶ Mosaico follows a client-server architecture where users interact with the platform through the Python SDK to query, read, and write data. The SDK communicates with the Mosaico daemon a.k.a. `mosaicod`, a high-performance server written in Rust, using Apache Arrow for efficient columnar data exchange without serialization overhead. `mosaicod` daemon handles all core data operations including ingestion, retrieval, and query. It uses a database instance to accelerate metadata queries, manage system state, and implement an event queue for processing asynchronous tasks. Data files themselves are stored in an object store (such as S3, MinIO, or local filesystem) for durable, long-term persistence and scalability. This design enables Mosaico to efficiently manage complex multi-modal sensor data while providing a simple, code-first interface for developers. --- The Mosaico SDK is a Python interface designed specifically for managing **Physical AI and Robotics data**. Its purpose is to handle the complete lifecycle of information, from the moment it is captured by a sensor to the moment it is used to train a neural network or analyze a robot's behavior. The SDK is built on the philosophy that robotics data is **unique**. Whether it comes from a autonomous car, a drone, or a factory arm, this data is multi-modal, highly frequent, and deeply interconnected in space and time. The Mosaico SDK provides the infrastructure to treat this data as a *first-class citizen* rather than just a collection of generic numbers. It understands the geometric and physical semantics of complex data types such as LIDAR point clouds, IMU readings, high-resolution camera feeds, and rigid-body transformations. ## Overview¶ The SDK is built on the following core principles: ### Middleware Independence¶ Mosaico is middleware-agnostic. While the SDK provides robust tools for ROS, it exists because robotics data itself is complex, regardless of the collection method. The platform serves as a standardized hub that can ingest data from: * **Existing Frameworks**: Such as ROS 1, ROS 2, `.mcap` and `.db3` files. * **Custom Collectors**: Proprietary data loggers or direct hardware drivers. * **Simulators**: Synthetic data generated in virtual environments. ### Ontology¶ The Mosaico Data Ontology acts as the abstraction layer between your specific data collection system and your storage. Instead of saving "Topic A from Robot B" you save a `Pose`, an `IMU` reading, or an `Image`. Once data is in the platform, its origin becomes secondary to its universal, semantic format. Moreover, the ontology is designed to be extensible with no effort, to meet the needs of any domain; the custom types are automatically validatable, serializable, and queryable alongside standard types. ### High-Performance¶ Leveraging Apache Arrow for zero-copy performance, the SDK moves massive data volumes from the network to analysis tools without the CPU overhead of traditional data conversion. Every piece of data is time-synchronized, allowing the SDK to *replay* a session from dozens of sensors in the exact chronological order they occurred. ## Key Operations¶ ### Data Ingestion¶ You can push data into Mosaico through two primary pathways, both designed to ensure your data is validated and standardized before storage: **Native Ontology Ingestion**. This approach allows you to stream data directly from your application, providing the highest level of control over serialization and real-time performance. **Ecosystem Adapters & Bridges**. Use specialized adapters to translate data from existing middleware and log formats into Mosaico sequences. Mosaico currently supports ROS 1 bags (`.bag`) and more recent formats like `.mcap` and `.db3`. ### Data Retrieval¶ Retrieving data goes beyond simple downloading. It is possible to stream and merge multiple topics into a single, time-ordered timeline, which is essential for sensor fusion. Connect directly to a specific sensor, such as just the front-facing camera, to save bandwidth and memory. The SDK fetches data in batches, allowing you to process datasets that are much larger than your computer's RAM. ### Querying & Discovery¶ Mosaico allows you to find data based on *what* happened, not just *when* it happened. You can search for specific sequences by metadata tags (like `robot_id` or `location`) or query the actual contents of the sensor data (e.g., *"Find all sequences where the vehicle acceleration exceeded 4 m/s^2"*). ### Machine Learning & Analytics¶ The ML Module transforms raw, sparse sensor streams into the tabular formats required by modern AI: * **Flattening**: Converts nested sensor data into organized tables (e.g. `pandas.DataFrames`). * **Temporal Resampling**: Aligns sensors running at different speeds (e.g., a 100Hz IMU and a 5Hz GPS) onto a uniform time grid with custom frame-rate for model training. --- The SDK is currently available via source distribution. We use Poetry for robust dependency management and packaging. ## Prerequisites¶ * **Python:** Version **3.13** or newer is required. * **Poetry:** For package management. ### Install Poetry¶ If you do not have Poetry installed, use the official installer: ``` curl -sSL https://install.python-poetry.org | python3 - ``` Ensure the poetry binary is in your path by verifying the version: ``` poetry --version ``` ## Install SDK¶ Clone the repository and navigate to the SDK directory: ``` cd mosaico/mosaico-sdk-py ``` Install the dependencies. This will automatically create a virtual environment and install all required libraries (PyArrow, NumPy, ROSBags, etc.): ``` poetry install ``` ### Activate Environment¶ You can spawn a shell within the configured virtual environment to work interactively: ``` eval $(poetry env activate) ``` Alternatively, you can run one-off commands without activating the shell: ``` poetry run python any_script.py ``` --- This guide demonstrates how to ingest data into the Mosaico Data Platform from custom files. Here the example of a CSV file is provided, but the logic is compatible with any file format and I/O library. You will learn how to use the Mosaico SDK for: * **Opening a connection** to the Mosaico server. * **Creating a sequence**. * **Creating a topic**. * **Pushing data into a topic**. ### Step 1: Chunked Loading for High-Volume Data¶ In this example, we assume our CSV file contains the following columns: imu.csv ``` timestamp, acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z 1110022, 0.0032, 0.001, -0.002, 0.01, 0.005, -0.003 1111022, 0.0041, 0.002, -0.001, 0.012, 0.006, -0.004 1112022, 0.0028, 0.0005, -0.003, 0.009, 0.004, -0.002 ``` The implementation below uses `pandas` to stream the data, but the logic is compatible with any streaming I/O library. When dealing with massive datasets, we adopt a **chunked loading approach** for each sensor type. Define the generator functions that yield Message objects. ``` import pandas as pd from mosaicolabs import ( MosaicoClient, # The gateway to the Mosaico Platform OnErrorPolicy, # The error policy for the SequenceWriter Message, # The base class for all data messages IMU, # The IMU sensor data class Vector3d, # The 3D vector class, needed to populate the IMU data ) def stream_imu_from_csv(file_path: str, chunk_size: int = 1000): for chunk in pd.read_csv(file_path, chunksize=chunk_size): # (1)! for row in chunk.itertuples(index=False): try: yield Message( timestamp_ns=int(row.timestamp), data=IMU( acceleration=Vector3d( x=float(row.acc_x), y=float(row.acc_y), z=float(row.acc_z), ), angular_velocity=Vector3d( x=float(row.gyro_x), y=float(row.gyro_y), z=float(row.gyro_z), ), ), ) except Exception: # Yield None only for parsing/type-related errors yield None ``` 1. Use pandas TextFileReader to stream the file in chunks The Mosaico `Message` object is an in-memory object wrapping the sensor data with necessary metadata (e.g. timestamp), and ensuring it is ready for serialization and network transmission. In this specific case, the data is an instance of the `IMU` model. This is a built-in part of the Mosaico default ontology, meaning the platform already understands its schema and how to optimize its storage. For a more in-depth explanation: * **Documentation: Data Models & Ontology** * **API Reference: Sensor Models** ### Step 2: Orchestrating the Sequence Upload¶ To write data, we first establish a connection to the Mosaico server via the `MosaicoClient.connect()` method and create a `SequenceWriter`. A sequence writer acts as a logical container for related data streams (topics). When initializing your data handling pipeline, it is highly recommended to wrap the `MosaicoClient` within a `with` statement. This context manager pattern ensures that underlying network connections and shared resource pools are correctly shut down and released when your operations conclude. Connect to the Mosaico server and create a sequence writer ``` with MosaicoClient.connect("localhost", 6726) as client: # Initialize the Sequence Orchestrator with client.sequence_create( sequence_name="csv_ingestion_test", metadata={"source": "manual_upload", "format": "csv"} on_error = OnErrorPolicy.Delete # (1)! ) as swriter: # Step 3 and 4 happen inside this block... ``` 1. Mosaico supports two distinct error policies for sequences: `OnErrorPolicy.Delete` and `OnErrorPolicy.Report`. Context Management It is **mandatory** to use the `SequenceWriter` instance returned by `client.sequence_create()` inside its own `with` context. The following code will raise an exception: ``` swriter = client.sequence_create( sequence_name="csv_ingestion_test", metadata={...}, ) # Performing operations using `swriter` will raise an exception swriter.topic_create(...) # Raises here ``` This choice ensures that the sequence writing orchestrator is closed and cataloged when the block is exited, even if your application encounters a crash or is manually interrupted. #### Sequence-Level Error Handling¶ The behavior of the orchestrator during a failure is governed by the `on_error` policy. This is a *Last-Resort* automated error policy, which dictates how the server manages a sequence if an unhandled exception bubbles up to the `SequenceWriter` context manager. By default, this is set to `OnErrorPolicy.Delete`, which signals the server to physically remove the incomplete sequence and its associated topic directories, if any errors occurred. Alternatively, you can specify `OnErrorPolicy.Report`: in this case, the SDK will not delete the data but will instead send an error notification to the server, allowing the platform to flag the sequence as failed while retaining whatever records were successfully transmitted before the error occurred. For a more in-depth explanation: * **Documentation: The Writing Workflow** * **API Reference: Writing Data** ### Step 3: Topic Creation¶ Inside the sequence, we create a Topic Writer, which is assigned to the IMU topic. ``` with client.sequence_create(...) imu_twriter = swriter.topic_create( # (1)! topic_name="sensors/imu", metadata={"sensor_id": "accel_01"}, ontology_type=IMU, ) ``` 1. Here we are creating a dedicated writer for the IMU topic ### Step 4: Pushing Data into the Pipeline¶ The final stage of the ingestion process involves iterating through your data generators and transmitting records to the Mosaico platform by calling the `TopicWriter.push()` method for each record. The `push()` method optimizes the throughput by accumulating messages into internal batches. ``` with client.sequence_create(...) imu_twriter = swriter.topic_create(...) for msg in stream_imu_from_csv("imu_data.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: imu_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error at time: {msg.timestamp_ns}. Inner err: {e}") ``` #### Topic-Level Error Management¶ In the code snippet above, we implemented a **Controlled Ingestion** by wrapping the topic-specific processing and pushing logic within a local `try-except` block. Because the `SequenceWriter` cannot natively distinguish which specific topic failed within your custom processing code (such as a coordinate transformation or a malformed CSV row), an unhandled exception will bubble up and trigger the global sequence-level error policy. To avoid this, you should catch errors locally for each topic. Upcoming versions of the SDK will introduce native **Topic-Level Error Policies**. This feature will allow you to define the error behavior directly when creating the topic, removing the need for boilerplate `try-except` blocks around every sensor stream. ## The full example code¶ ``` """ Import the necessary classes from the Mosaico SDK. """ import pandas as pd from mosaicolabs import ( MosaicoClient, # The gateway to the Mosaico Platform OnErrorPolicy, # The error policy for the SequenceWriter Message, # The base class for all data messages IMU, # The IMU sensor data class Vector3d, # The 3D vector class, needed to populate the IMU data ) """ Define the generator functions that yield `Message` objects. """ def stream_imu_from_csv(file_path: str, chunk_size: int = 1000): """ Efficiently reads a large CSV in chunks to prevent memory exhaustion. """ # Use pandas TextFileReader to stream the file in chunks for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): try: yield Message( timestamp_ns=int(row.timestamp), data=IMU( acceleration=Vector3d( x=float(row.acc_x), y=float(row.acc_y), z=float(row.acc_z), ), angular_velocity=Vector3d( x=float(row.gyro_x), y=float(row.gyro_y), z=float(row.gyro_z), ), ), ) except Exception: # Yield None only for parsing/type-related errors yield None """ Main ingestion orchestration """ def main(): with MosaicoClient.connect("localhost", 6726) as client: # Initialize the Sequence Orchestrator with client.sequence_create( sequence_name="csv_ingestion_test", metadata={"source": "manual_upload", "format": "csv"} on_error = OnErrorPolicy.Delete # Default ) as swriter: # Create a dedicated writer for the IMU topic imu_twriter = swriter.topic_create( topic_name="sensors/imu", metadata={"sensor_id": "accel_01"}, ontology_type=IMU, ) # --- Push IMU Data --- for msg in stream_imu_from_csv("imu.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: imu_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing IMU at time: {msg.timestamp_ns}. Inner err: {e}") # All buffers are flushed and the sequence is committed when exiting the SequenceWriter 'with' block print("Successfully injected data from CSV into Mosaico!") # Here the `MosaicoClient` context and all connections are closed ``` --- This guide demonstrates how to ingest data from multiple custom files into the Mosaico Data Platform. While the logic below uses CSV files as the primary example, the SDK's modular design is compatible with any file format (JSON, Parquet, binary) and any I/O library. You will learn how to use the Mosaico SDK to: * **Open a connection** to the Mosaico server. * **Creating a sequence**. * **Creating topics**. * **Pushing data into topics**, via **Controlled Ingestion Patterns** to prevent a single file failure from aborting the entire upload. ### Step 1: Chunked Loading for Heterogeneous Data¶ The following implementation defines three distinct generators to stream IMU, GPS, and Pressure data. In this example, we assume our CSV files contain the following columns: imu.csv ``` timestamp, acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z 1110022, 0.0032, 0.001, -0.002, 0.01, 0.005, -0.003 ``` gps.csv ``` timestamp, latitude, longitude, altitude, status, service 1110022, 45.123456, -93.123456, 250.0, 1, 1 ``` pressure.csv ``` timestamp, pressure 1110022, 101325.0 ``` When dealing with massive datasets spread across multiple files, we adopt a **chunked loading approach** for each sensor type. Define the generator functions that yield Message objects ``` import pandas as pd from mosaicolabs import ( MosaicoClient, # The gateway to the Mosaico Platform OnErrorPolicy, # The error policy for the SequenceWriter Message, # The base class for all data messages IMU, # The IMU sensor data class Vector3d, # The 3D vector class, needed to populate the IMU and GPS data GPS, # The GPS sensor data class GPSStatus, # The GPS status enum, needed to populate the GPS data Pressure, # The Pressure sensor data class ) # Define the generator functions that yield `Message` objects. # For each file, open the reading process and yield the messages one by one. def stream_imu_from_csv(file_path: str, chunk_size: int = 1000): for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): yield Message( timestamp_ns=int(row.timestamp), data=IMU( acceleration=Vector3d( x=float(row.acc_x), y=float(row.acc_y), z=float(row.acc_z), ), angular_velocity=Vector3d( x=float(row.gyro_x), y=float(row.gyro_y), z=float(row.gyro_z), ) ) ) def stream_gps_from_csv(file_path: str, chunk_size: int = 1000): for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): yield Message( timestamp_ns=int(row.timestamp), data=GPS( position=Vector3d( x=float(row.latitude), y=float(row.longitude), z=float(row.altitude), ), status=GPSStatus( status=int(row.status), service=int(row.service), ) ) ) def stream_pressure_from_csv(file_path: str, chunk_size: int = 1000): for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): yield Message( timestamp_ns=int(row.timestamp), data=Pressure(value=row.pressure) ) ``` #### Understanding the Output¶ The Mosaico `Message` object is an in-memory object wrapping the sensor data with necessary metadata (e.g. timestamp), and ensuring it is ready for serialization and network transmission. In this specific case, the data are instances of the `IMU`, `GPS` and `Pressure` models. These are built-in parts of the Mosaico default ontology, meaning the platform already understands their schema and how to optimize their storage. For a more in-depth explanation: * **Documentation: Data Models & Ontology** * **API Reference: Sensor Models** ### Step 2: Orchestrating the Multi-Topic Sequence¶ To write data, we first establish a connection to the Mosaico server via the `MosaicoClient.connect()` method and create a `SequenceWriter`. A sequence writer acts as a logical container for related sensor data streams (topics). When initializing your data handling pipeline, it is highly recommended to wrap the **Mosaico Client** within a `with` statement. This context manager pattern ensures that underlying network connections and shared resource pools are correctly shut down and released when your operations conclude. Connect to the Mosaico server and create a sequence writer ``` with MosaicoClient.connect("localhost", 6726) as client: with client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={"mission": "alpha_test", "environment": "laboratory"}, on_error=OnErrorPolicy.Delete # (1)! ) as swriter: # Steps 3 and 4 (Topic Creation & serial Pushing) happen here... ``` 1. Mosaico supports two distinct error policies for sequences: `OnErrorPolicy.Delete` and `OnErrorPolicy.Report`. Context Management It is **mandatory** to use the `SequenceWriter` instance returned by `client.sequence_create()` inside its own `with` context. The following code will raise an exception: ``` swriter = client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={...}, ) # Performing operations using `swriter` will raise an exception swriter.topic_create(...) # Raises here ``` This choice ensures that the sequence writing orchestrator is closed and cataloged when the block is exited, even if your application encounters a crash or is manually interrupted. #### Sequence-Level Error Handling¶ The behavior of the orchestrator during a failure is governed by the `on_error` policy. This is a *Last-Resort* automated error policy, which dictates how the server manages a sequence if an unhandled exception bubbles up to the `SequenceWriter` context manager. By default, this is set to `OnErrorPolicy.Delete`, which signals the server to physically remove the incomplete sequence and its associated topic directories, if any errors occurred. Alternatively, you can specify `OnErrorPolicy.Report`: in this case, the SDK will not delete the data but will instead send an error notification to the server, allowing the platform to flag the sequence as failed while retaining whatever records were successfully transmitted before the error occurred. For a more in-depth explanation: * **Documentation: The Writing Workflow** * **API Reference: Writing Data** ### Step 3: Topic Creation and Resource Allocation¶ Inside the sequence, we create individual **Topic Writers** to manage data streams. Each writer is an independent "lane" assigned its own internal buffer and background thread for serialization. ``` with client.sequence_create(...) as swriter: # Create dedicated Topic Writers for each sensor stream imu_twriter = swriter.topic_create( # (1)! topic_name="sensors/imu", metadata={"sensor_id": "accel_01"}, ontology_type=IMU, ) gps_twriter = swriter.topic_create( # (2)! topic_name="sensors/gps", metadata={"sensor_id": "gps_01"}, ontology_type=GPS, ) pressure_twriter = swriter.topic_create( # (3)! topic_name="sensors/pressure", metadata={"sensor_id": "pressure_01"}, ontology_type=Pressure, ) ``` 1. Here we are creating a dedicated writer for the IMU topic 2. Here we are creating a dedicated writer for the GPS topic 3. Here we are creating a dedicated writer for the Pressure topic ### Step 4: Pushing Data into the Pipeline¶ The final stage of the ingestion process involves iterating through your data generators and transmitting records to the Mosaico platform by calling the `TopicWriter.push()` method for each record. The `push()` method optimizes the throughput by accumulating messages into internal batches. ``` # 1. Push IMU Data for msg in stream_imu_from_csv("imu.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: imu_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing IMU at time: {msg.timestamp_ns}. Inner err: {e}") # 2. Push GPS Data with Custom Processing for msg in stream_gps_from_csv("gps.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: # This custom processing might fail process_gps_message(msg) gps_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing GPS at time: {msg.timestamp_ns}. Inner err: {e}") # 3. Push Pressure Data for msg in stream_pressure_from_csv("pressure.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: pressure_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing pressure at time: {msg.timestamp_ns}. Inner err: {e}") ``` #### Topic-Level Error Management¶ In the code snippet above, we implemented a **Controlled Ingestion** by wrapping the topic-specific processing and pushing logic within a local `try-except` block. Because the `SequenceWriter` cannot natively distinguish which specific topic failed within your custom processing code (such as a coordinate transformation or a malformed CSV row), an unhandled exception will bubble up and trigger the global sequence-level error policy. To avoid this, you should catch errors locally for each topic. Upcoming versions of the SDK will introduce native **Topic-Level Error Policies**. This feature will allow you to define the error behavior directly when creating the topic, removing the need for boilerplate `try-except` blocks around every sensor stream. ## The full example code¶ ``` """ Import the necessary classes from the Mosaico SDK. """ import pandas as pd from mosaicolabs import ( MosaicoClient, # The gateway to the Mosaico Platform OnErrorPolicy, # The error policy for the SequenceWriter Message, # The base class for all data messages IMU, # The IMU sensor data class Vector3d, # The 3D vector class, needed to populate the IMU and GPS data GPS, # The GPS sensor data class GPSStatus, # The GPS status enum, needed to populate the GPS data Pressure, # The Pressure sensor data class ) """ Define the generator functions that yield `Message` objects. For each file, open the reading process and yield the messages one by one. """ def stream_imu_from_csv(file_path: str, chunk_size: int = 1000): """Efficiently streams IMU data.""" for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): try: yield Message( timestamp_ns=int(row.timestamp), data=IMU( acceleration=Vector3d( x=float(row.acc_x), y=float(row.acc_y), z=float(row.acc_z), ), angular_velocity=Vector3d( x=float(row.gyro_x), y=float(row.gyro_y), z=float(row.gyro_z), ) ) ) except Exception: # Yield None only for parsing/type-related errors yield None def stream_gps_from_csv(file_path: str, chunk_size: int = 1000): """Efficiently streams GPS data.""" for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): try: yield Message( timestamp_ns=int(row.timestamp), data=GPS( position=Vector3d( x=float(row.latitude), y=float(row.longitude), z=float(row.altitude), ), status=GPSStatus( status=int(row.status), service=int(row.service), ) ) ) except Exception: # Yield None only for parsing/type-related errors yield None def stream_pressure_from_csv(file_path: str, chunk_size: int = 1000): """Efficiently streams Barometric Pressure data.""" for chunk in pd.read_csv(file_path, chunksize=chunk_size): for row in chunk.itertuples(index=False): try: yield Message( timestamp_ns=int(row.timestamp), data=Pressure(value=row.pressure) ) except Exception: # Yield None only for parsing/type-related errors yield None """ Main ingestion orchestration """ def main(): with MosaicoClient.connect("localhost", 6726) as client: # Initialize the Orchestrator for the entire mission with client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={"mission": "alpha_test", "environment": "laboratory"}, on_error=OnErrorPolicy.Delete # Deletes the whole sequence if a fatal crash occurs ) as swriter: # Create dedicated Topic Writers for each sensor stream imu_twriter = swriter.topic_create( topic_name="sensors/imu", metadata={"sensor_id": "accel_01"}, ontology_type=IMU, ) gps_twriter = swriter.topic_create( topic_name="sensors/gps", metadata={"sensor_id": "gps_01"}, ontology_type=GPS, ) pressure_twriter = swriter.topic_create( topic_name="sensors/pressure", metadata={"sensor_id": "pressure_01"}, ontology_type=Pressure, ) # --- 1. Push IMU Data --- for msg in stream_imu_from_csv("imu.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: imu_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing IMU at time: {msg.timestamp_ns}. Inner err: {e}") # --- 2. Push GPS Data with Custom Processing --- for msg in stream_gps_from_csv("gps.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: # This custom processing might fail process_gps_message(msg) gps_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing GPS at time: {msg.timestamp_ns}. Inner err: {e}") # --- 3. Push Pressure Data --- for msg in stream_pressure_from_csv("pressure.csv"): if msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records try: pressure_twriter.push(message=msg) except Exception as e: # Log and skip, or raise if incomplete data is disallowed print(f"Error processing pressure at time: {msg.timestamp_ns}. Inner err: {e}") # All buffers are flushed and the sequence is committed when exiting the SequenceWriter 'with' block print("Multi-topic ingestion completed!") ``` --- This guide demonstrates how to ingest data from multiple topics stored within a **single file container** (such as an MCAP or a specialized binary log) into the Mosaico Data Platform. Unlike serial ingestion where files are processed one by one, interleaved ingestion handles a stream of messages from different sensors—such as IMU, GPS, and Pressure—as they appear in the source file. For this guide, we use the **MCAP library** as an example to briefly show how to parse a high-performance robotics container and stream its contents into Mosaico. You will learn how to: * **Orchestrate a single sequence** for a multi-sensor stream. * **Dynamically resolve Topic Writers** using the local SDK cache. * **Implement a Custom Translator** to map external schemas to the Mosaico Ontology. * **Isolate failures** to a single sensor stream using Defensive Ingestion patterns. ### The Multi-Topic Streaming Architecture¶ In a mixed ingestion scenario, the source file provides a serialized stream of records. Each record contains a **topic name**, a **timestamp**, and a **data payload** associated with a specific **schema**. | Topic | Schema Example (MCAP) | Mosaico Target Model | | --- | --- | --- | | `/robot/imu` | `sensor_msgs/msg/Imu` | `IMU` | | `/robot/gps` | `sensor_msgs/msg/NavSatFix` | `GPS` | | `/env/pressure` | `sensor_msgs/msg/FluidPressure` | `Pressure` | As the reader iterates through the file, Mosaico dynamically assigns each record to its corresponding "lane" (Topic Writer). ### Step 1: Implementing the Custom Translator and Adapters¶ Because source files often use external data formats (like ROS, Protobuf, or JSON), you need a translation layer to map these raw payloads into strongly-typed Mosaico objects. Map incoming data schemas to Mosaico Ontology models. ``` from mosaicolabs.models import (IMU, GPS, Pressure, Vector3d, GPSStatus, Time, Serializable) def custom_translator(schema_name: str, payload: dict): if schema_name == "sensor_msgs/msg/Imu": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=IMU( acceleration=Vector3d(**payload['linear_acceleration']), angular_velocity=Vector3d(**payload['angular_velocity']) ) ) if schema_name == "sensor_msgs/msg/NavSatFix": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=GPS( position=Vector3d( x=payload['latitude'], y=payload['longitude'], z=payload['altitude'] ), status=GPSStatus( status=payload['status']['status'], service=payload['status']['service'] ) ) ) if schema_name == "sensor_msgs/msg/FluidPressure": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=Pressure(value=payload['fluid_pressure']) ) return None def determine_mosaico_type(schema_name: str) -> Optional[Type["Serializable"]]: """Determine the Mosaico type of the topic based on the schema name.""" if schema_name == "sensor_msgs/msg/Imu": return IMU elif schema_name == "sensor_msgs/msg/NavSatFix": return GPS elif schema_name == "sensor_msgs/msg/FluidPressure": return Pressure return None ``` #### Understanding the Output¶ The Mosaico `Message` object is an in-memory object wrapping the sensor data with necessary metadata (e.g. timestamp), and ensuring it is ready for serialization and network transmission. In this specific case, the data are instances of the `IMU`, `GPS` and `Pressure` models. These are built-in parts of the Mosaico default ontology, meaning the platform already understands their schema and how to optimize their storage. For a more in-depth explanation: * **Documentation: Data Models & Ontology** * **API Reference: Sensor Models** ### Step 2: Orchestrating the Multi-Topic Interleaved Ingestion¶ To write data, we first establish a connection to the Mosaico server via the `MosaicoClient.connect()` method and create a `SequenceWriter`. A sequence writer acts as a logical container for related sensor data streams (topics). When initializing your data handling pipeline, it is highly recommended to wrap the **Mosaico Client** within a `with` statement. This context manager pattern ensures that underlying network connections and shared resource pools are correctly shut down and released when your operations conclude. Connect to the Mosaico server and create a sequence writer ``` from mcap.reader import make_reader from mosaicolabs import MosaicoClient, OnErrorPolicy, Message with open("mission_data.mcap", "rb") as f: reader = make_reader(f) with MosaicoClient.connect("localhost", 6726) as client: with client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={"mission": "alpha_test", "environment": "laboratory"}, on_error=OnErrorPolicy.Delete # (1)! ) as swriter: # Steps 3 and 4 (Topic Creation & Pushing) happen here... ``` 1. Mosaico supports two distinct error policies for sequences: `OnErrorPolicy.Delete` and `OnErrorPolicy.Report`. Context Management It is **mandatory** to use the `SequenceWriter` instance returned by `client.sequence_create()` inside its own `with` context. The following code will raise an exception: ``` swriter = client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={...}, ) # Performing operations using `swriter` will raise an exception swriter.topic_create(...) # Raises here ``` This choice ensures that the sequence writing orchestrator is closed and cataloged when the block is exited, even if your application encounters a crash or is manually interrupted. #### Sequence-Level Error Handling¶ The behavior of the orchestrator during a failure is governed by the `on_error` policy. This is a *Last-Resort* automated error policy, which dictates how the server manages a sequence if an unhandled exception bubbles up to the `SequenceWriter` context manager. By default, this is set to `OnErrorPolicy.Delete`, which signals the server to physically remove the incomplete sequence and its associated topic directories, if any errors occurred. Alternatively, you can specify `OnErrorPolicy.Report`: in this case, the SDK will not delete the data but will instead send an error notification to the server, allowing the platform to flag the sequence as failed while retaining whatever records were successfully transmitted before the error occurred. For a more in-depth explanation: * **Documentation: The Writing Workflow** * **API Reference: Writing Data** ### Step 3: Topic Creation and Resource Allocation¶ Inside the sequence, we can stream interleaved data without loading the entire file into memory. We automatically create individual **Topic Writers** per each channel in the MCAP file to manage data streams. Each writer is an independent "lane" assigned its own internal buffer and background thread for serialization. The `swriter.get_topic_writer` pattern removes the need to pre-scan the file. **Topics are created only when they are first encountered**. ``` with client.sequence_create(...) as swriter: # Iterate through all interleaved messages for schema, channel, message in reader.iter_messages(): # 1. Resolve Topic Writer using the SDK cache twriter = swriter.get_topic_writer(channel.topic) # (1)! if twriter is None: ontology_type = determine_mosaico_type(schema.name) if ontology_type is None: print(f"Skipping message on {channel.topic} due to unknown ontology type") # Skip the topic if no ontology type is found continue # Dynamically register the topic writer upon discovery twriter = swriter.topic_create( # (2)! topic_name=channel.topic, metadata={}, ontology_type=ontology_type ) ``` 1. Here we are checking if the a `TopicWriter` for the current topic already exists. 2. Here we are creating the topic writer for the current topic, if it doesn't exist yet. ### Step 4: Pushing Data into the Pipeline¶ The final stage of the ingestion process involves iterating through your data generators and transmitting records to the Mosaico platform by calling the `TopicWriter.push()` method for each record. The `push()` method optimizes the throughput by accumulating messages into internal batches. ``` try: # In a real scenario, use a deserializer like mcap_ros2.decoder raw_data = deserialize_payload(message.data, schema.name) # (1)! mosaico_msg = custom_translator(schema.name, raw_data) if mosaico_msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records twriter.push(message=mosaico_msg) except Exception as e: print(f"Skip error on {channel.topic} at {message.log_time}: {e}") ``` 1. This is an example of a custom function that deserializes the payload of the current message. #### Topic-Level Error Management¶ In the code snippet above, we implemented a **Controlled Ingestion** by wrapping the topic-specific processing and pushing logic within a local `try-except` block. Because the `SequenceWriter` cannot natively distinguish which specific topic failed within your custom processing code (such as a coordinate transformation), an unhandled exception will bubble up and trigger the global sequence-level error policy. To avoid this, you should catch errors locally for each topic. Upcoming versions of the SDK will introduce native **Topic-Level Error Policies**. This feature will allow you to define the error behavior directly when creating the topic, removing the need for boilerplate `try-except` blocks around every sensor stream. ## The full example code¶ ``` """ Import the necessary classes from the Mosaico SDK. """ from mcap.reader import make_reader from mosaicolabs import ( MosaicoClient, # The gateway to the Mosaico Platform OnErrorPolicy, # The error policy for the SequenceWriter Message, # The base class for all data messages IMU, # The IMU sensor data class Vector3d, # The 3D vector class, needed to populate the IMU and GPS data GPS, # The GPS sensor data class GPSStatus, # The GPS status enum, needed to populate the GPS data Pressure, # The Pressure sensor data class ) """ Define the generator functions that yield `Message` objects. For each schema, we define a function that translates the payload of the current message into a `Message` object. """ def custom_translator(schema_name: str, payload: dict): if schema_name == "sensor_msgs/msg/Imu": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=IMU( acceleration=Vector3d(**payload['linear_acceleration']), angular_velocity=Vector3d(**payload['angular_velocity']) ) ) if schema_name == "sensor_msgs/msg/NavSatFix": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=GPS( position=Vector3d( x=payload['latitude'], y=payload['longitude'], z=payload['altitude'] ), status=GPSStatus( status=payload['status']['status'], service=payload['status']['service'] ) ) ) if schema_name == "sensor_msgs/msg/FluidPressure": header = payload['header'] timestamp_ns = Time( sec=header['stamp']['sec'], nanosec=header['stamp']['nanosec'] ).to_nanoseconds() return Message( timestamp_ns=timestamp_ns, data=Pressure(value=payload['fluid_pressure']) ) return None def determine_mosaico_type(schema_name: str) -> Optional[Type["Serializable"]]: """Determine the Mosaico type of the topic based on the schema name.""" if schema_name == "sensor_msgs/msg/Imu": return IMU elif schema_name == "sensor_msgs/msg/NavSatFix": return GPS elif schema_name == "sensor_msgs/msg/FluidPressure": return Pressure return None """ Main ingestion orchestration """ def main(): with open("mission_data.mcap", "rb") as f: reader = make_reader(f) with MosaicoClient.connect("localhost", 6726) as client: with client.sequence_create( sequence_name="multi_sensor_ingestion", metadata={"mission": "alpha_test", "environment": "laboratory"}, on_error=OnErrorPolicy.Delete ) as swriter: # Iterate through all interleaved messages for schema, channel, message in reader.iter_messages(): # 1. Resolve Topic Writer using the SDK cache twriter = swriter.get_topic_writer(channel.topic) if twriter is None: ontology_type = determine_mosaico_type(schema.name) if ontology_type is None: print(f"Skipping message on {channel.topic} due to unknown ontology type") # Skip the topic if no ontology type is found continue # Dynamically register the topic writer upon discovery twriter = swriter.topic_create( topic_name=channel.topic, metadata={}, ontology_type=ontology_type ) # 2. Defensive Ingestion: Isolate errors to this specific record try: # In a real scenario, use a deserializer like mcap_ros2.decoder raw_data = deserialize_payload(message.data, schema.name) # Example helper function mosaico_msg = custom_translator(schema.name, raw_data) if mosaico_msg is None: # Log and skip, or raise if incomplete data is disallowed print("Skipping row due to parsing error") continue # Ignore malformed records twriter.push(message=mosaico_msg) except Exception as e: print(f"Skip error on {channel.topic} at {message.log_time}: {e}") # All buffers are flushed and the sequence is committed when exiting the SequenceWriter 'with' block print("Multi-topic ingestion completed!") ``` --- This guide demonstrates how to interact with the Mosaico Data Platform to inspect and retrieve data that has been previously ingested. You will learn how to use the Mosaico SDK to: * **Connect to the catalog** to find existing recordings. * **Inspect sequence metadata** and temporal bounds. * **Access specific topic handlers** to analyze individual sensor streams. For a more in-depth explanation: * **Documentation: The Reading Workflow** * **API Reference: Data Retrieval** ### Step 1: Connecting to the Catalog¶ To begin inspecting data, you must establish a connection via the `MosaicoClient`. Reading is managed through a context manager to ensure all network resources are cleanly released. ``` from mosaicolabs import MosaicoClient # Establish a secure connection to the Mosaico server with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog for a specific recording session seq_handler = client.sequence_handler("multi_sensor_ingestion") if not seq_handler: print("Sequence not found in the catalog.") else: # Proceed to inspect metadata (Step 2) pass ``` ### Step 2: Inspecting Sequence Metadata¶ A `SequenceHandler` provides a view of a complete recording session without transferring the actual bulk data yet. This "lazy" inspection allows you to verify session parameters, such as the total size on disk and global user metadata. ``` """Inside the `if seq_handler:` block""" # Print sequence metadata print(f"Sequence: {seq_handler.name}") print(f"• Registered Topics: {seq_handler.topics}") print(f"• User Metadata: {seq_handler.user_metadata}") # Analyze temporal bounds (earliest and latest timestamps across all sensors) # Timestamps are consistently handled in nanoseconds start, end = seq_handler.timestamp_ns_min, seq_handler.timestamp_ns_max print(f"• Duration (ns): {end - start}") # Access structural info from the server size_mb = seq_handler.sequence_info.total_size_bytes / (1024 * 1024) print(f"• Total Size: {size_mb:.2f} MB") print(f"• Created At: {seq_handler.sequence_info.created_datetime}") ``` ### Step 3: Accessing Individual Topics¶ While a sequence represents a "mission," a `TopicHandler` represents a specific data channel within that mission (e.g., a single IMU or GPS). ``` """Inside the `if seq_handler:` block""" # Retrieve a specific handler for the IMU sensor imu_handler = seq_handler.get_topic_handler("sensors/imu") if imu_handler: print(f"Inspecting Topic: {imu_handler.name}") print(f"• Sensor Metadata: {imu_handler.user_metadata}") # Check topic-specific temporal bounds print(f"• Topic Span: {imu_handler.timestamp_ns_min} to {imu_handler.timestamp_ns_max}") # Topic-specific size on the server topic_mb = imu_handler.topic_info.total_size_bytes / (1024 * 1024) print(f"• Topic Size: {topic_mb:.2f} MB") ``` ### Comparison: Sequence vs. Topic Handlers¶ | Feature | Sequence Handler | Topic Handler | | --- | --- | --- | | **Scope** | Entire Recording Session | Single Sensor Stream | | **Metadata** | Mission-wide (e.g., driver, weather) | Sensor-specific (e.g., model, serial) | | **Time Bounds** | Global min/max of all topics | Min/max for that specific stream | | **Topics** | List of all available streams | N/A | ## The full example code¶ ``` from mosaicolabs import MosaicoClient # Establish a secure connection to the Mosaico server with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog for a specific recording session seq_handler = client.sequence_handler("multi_sensor_ingestion") if not seq_handler: print("Sequence not found in the catalog.") else: # Proceed to inspect metadata (Step 2) pass # Print sequence metadata print(f"Sequence: {seq_handler.name}") print(f"• Registered Topics: {seq_handler.topics}") print(f"• User Metadata: {seq_handler.user_metadata}") # Analyze temporal bounds (earliest and latest timestamps across all sensors) # Timestamps are consistently handled in nanoseconds start, end = seq_handler.timestamp_ns_min, seq_handler.timestamp_ns_max print(f"• Duration (ns): {end - start}") # Access structural info from the server size_mb = seq_handler.sequence_info.total_size_bytes / (1024 * 1024) print(f"• Total Size: {size_mb:.2f} MB") print(f"• Created At: {seq_handler.sequence_info.created_datetime}") # Retrieve a specific handler for the IMU sensor imu_handler = seq_handler.get_topic_handler("sensors/imu") if imu_handler: print(f"Inspecting Topic: {imu_handler.name}") print(f"• Sensor Metadata: {imu_handler.user_metadata}") # Check topic-specific temporal bounds print(f"• Topic Span: {imu_handler.timestamp_ns_min} to {imu_handler.timestamp_ns_max}") # Topic-specific size on the server topic_mb = imu_handler.topic_info.total_size_bytes / (1024 * 1024) print(f"• Topic Size: {topic_mb:.2f} MB") ``` --- Prerequisites To fully grasp the following How-To, we recommend you to read the **Reading a Sequence and its Topics How-To**. This guide demonstrates how to interact with the Mosaico Data Platform to retrieve the data stream that has been previously ingested. You will learn how to use the Mosaico SDK to: * **Obtain a `SequenceDataStreamer`** to consume recordings from a sequence. * **Obtain a `TopicDataStreamer`** to consume recordings from a topic. For a more in-depth explanation: * **Documentation: The Reading Workflow** * **API Reference: Data Retrieval** ### Unified Multi-Sensor Replay¶ A `SequenceDataStreamer` is designed for sensor fusion and full-system replay. It allows you to consume synchronized multiple data streams—such as high-rate IMU data and low-rate GPS fixes—as if they were a single, coherent timeline. ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Initialize a Unified Stream for synchronized multi-sensor analysis streamer = seq_handler.get_data_streamer( # Filter specific topics topics=["/gps", "/imu"], # Define the optional temporal window: Only data in this range will be streamed start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000, ) print(f"Streaming starts at: {streamer.next_timestamp()}") # Consume the stream. The loop yields messages from both topics in perfect chronological order for topic, msg in streamer: print(f"[{topic}] at {msg.timestamp_ns}: {type(msg.data).__name__}") # Finalize the reading channel to release server resources seq_handler.close() ``` ### Targeted Access¶ A `TopicDataStreamer` provides a dedicated channel for interacting with a single data resource. ``` from mosaicolabs import MosaicoClient, IMU with MosaicoClient.connect("localhost", 6726) as client: # Access a specific topic handler directly via the client top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: # Start a Targeted Stream for isolated, low-overhead replay imu_stream = top_handler.get_data_streamer( # Define the optional temporal window: Only data in this range will be streamed start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000, ) # Query the next timestamp, without consuming the message print(f"First sample at: {imu_stream.next_timestamp()}") # Direct loop for maximum efficiency for imu_msg in imu_stream: # Access the strongly-typed IMU data directly process_sample(imu_msg.get_data(IMU)) # Finalize the topic channel top_handler.close() ``` ### Streamer Comparison¶ | Feature | `SequenceDataStreamer` | `TopicDataStreamer` | | --- | --- | --- | | **Primary Use Case** | Multi-sensor fusion & system-wide replay | Isolated sensor analysis & ML training | | **Logic Overhead** | K-Way Merge Sorting | Direct Stream | | **Output Type** | Tuple of `(topic_name, message)` | Single `message` object | | **Temporal Slicing** | Supported | Supported | --- This guide demonstrates how to locate specific recording sessions based on their naming conventions and custom user metadata tags. This is the most common entry point for data discovery, allowing you to isolate sessions that match specific environmental or project conditions. ### The Objective¶ We want to find all sequences where: 1. The sequence name contains the string `"test_drive"`. 2. The user metadata indicates a specific project name (e.g., `"Apollo"`). 3. The environmental visibility was recorded as less than 50m. For a more in-depth explanation: * **Documentation: Querying Catalogs** * **API Reference: Query Builders** * **API Reference: Query Response** ### Implementation¶ When you call multiple `with_*` methods of the `QuerySequence` builder, the platform joins them with a logical **AND** condition. The server will return only the sequences that match the criteria alltogether. ``` from mosaicolabs import MosaicoClient, QuerySequence, Sequence # 1. Establish a connection with MosaicoClient.connect("localhost", 6726) as client: # 2. Execute the query results = client.query( QuerySequence() # Use a convenience method for fuzzy name matching .with_name_match("test_drive") # Use the .Q proxy to filter fixed and dynamic metadata fields .with_expression(Sequence.Q.user_metadata["project"].eq("Apollo")) .with_expression(Sequence.Q.user_metadata["environment.visibility"].lt(50)) # (1)! ) # 3. Process the Response if results: for item in results: # item.sequence contains the information for the matched sequence print(f"Matched Sequence: {item.sequence.name}") print(f" Topics: {[topic.name for topic in item.topics]}") # (2)! ``` 1. Use dot notation to access nested fields in the `user_metadata` dictionary. 2. The `item.topics` list contains all the topics that matched the query. In this case, all the available topics are returned because no topic-specific filters were applied. The `query` method returns `None` if an error occurs, or a `QueryResponse` object. This response acts as a list of `QueryResponseItem` objects, each providing: * **`item.sequence`**: A `QueryResponseItemSequence` containing the sequence metadata. * **`item.topics`**: A list of `QueryResponseItemTopic` objects that matched the query. Result Normalization The `topic.name` returns the relative topic path (e.g., `/front/camera/image`), which is immediately compatible with other SDK methods like `MosaicoClient.topic_handler()`, `SequenceHandler.get_topic_handler()` or streamers. ### Key Concepts¶ * **Convenience Methods**: High-level helpers like `with_name_match()` provide a quick way to filter common fields. * **Generic Methods**: The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. * **Dynamic Metadata Access**: Using the bracket notation `Sequence.Q.user_metadata["key"]` allows you to query any custom tag you attached during the ingestion phase. --- This guide demonstrates how to locate specific recording sessions based on their naming conventions and custom user metadata tags. This is the most common entry point for data discovery, allowing you to isolate sessions that match specific environmental or project conditions. ### The Objective¶ We want to find all topics where: 1. The topic refers to an IMU sensor. 2. The user metadata indicates a specific sensor interface (e.g., `"serial"`). For a more in-depth explanation: * **Documentation: Querying Catalogs** * **API Reference: Query Builders** * **API Reference: Query Response** ### Implementation¶ When you call multiple `with_*` methods of the `QueryTopic` builder, the platform joins them with a logical **AND** condition. The server will return only the sequences that match the criteria alltogether. ``` from mosaicolabs import MosaicoClient, QueryTopic, Topic, IMU # 1. Establish a connection with MosaicoClient.connect("localhost", 6726) as client: # 2. Execute the query results = client.query( QueryTopic() # Use a convenience method for fuzzy name matching .with_ontology_tag(IMU.ontology_tag()) # Use the .Q proxy to filter fixed and dynamic metadata fields .with_expression(Topic.Q.user_metadata["interface"].eq("serial"))) # 3. Process the Response if results: for item in results: # item.sequence contains the metadata for the matched sequence print(f"Matched Sequence: {item.sequence.name}") print(f" Topics: {[topic.name for topic in item.topics]}") # (1)! ``` 1. The `item.topics` list contains all the topics that matched the query. In this case, it will contain all the topics that are of type IMU and have the user metadata field `interface` set to `"serial"`. The `query` method returns `None` if an error occurs, or a `QueryResponse` object. This response acts as a list of `QueryResponseItem` objects, each providing: * **`item.sequence`**: A `QueryResponseItemSequence` containing the sequence metadata. * **`item.topics`**: A list of `QueryResponseItemTopic` objects that matched the query. Result Normalization The `topic.name` returns the relative topic path (e.g., `/front/camera/image`), which is immediately compatible with other SDK methods like `MosaicoClient.topic_handler()`, `SequenceHandler.get_topic_handler()` or streamers. ### Key Concepts¶ * **Convenience Methods**: High-level helpers like `with_ontology_tag()` provide a quick way to filter by ontology tags. * **Generic Methods**: The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. * **Dynamic Metadata Access**: Using the bracket notation `Topic.Q.user_metadata["key"]` allows you to query any custom tag you attached during the ingestion phase. --- Beyond metadata, the Mosaico platform allows for deep inspection of actual sensor payloads. This guide shows how to search for specific physical events, such as high-impact accelerations, across your entire data catalog. ### The Objective¶ Identify specific time segments where an IMU sensor recorded: 1. Lateral acceleration (-axis) greater than . 2. Longitudinal acceleration (-axis) greater than . For a more in-depth explanation: * **Documentation: Querying Catalogs** * **API Reference: Query Builders** * **API Reference: Query Response** ### Implementation¶ When you call multiple `with_*` methods of the `QueryOntologyCatalog` builder, the platform joins them with a logical **AND** condition. The server will return only the sequences that match the criteria alltogether. ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, IMU # 1. Establish a connection with MosaicoClient.connect("localhost", 6726) as client: # 2. Execute the query across all available data # include_timestamp_range is essential for pinpointing the exact time of the event results = client.query( QueryOntologyCatalog(include_timestamp_range=True) .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.acceleration.y.gt(4.0)) ) # 3. Process the Response if results: for item in results: print(f"Impact detected in Sequence: {item.sequence.name}") for topic in item.topics: # topic.timestamp_range provides the start and end of the match print(f" - Match in Topic: {topic.name}") # (1)! start, end = topic.timestamp_range.start, topic.timestamp_range.end # (2)! print(f" Event Window: {start} to {end} ns") ``` 1. The `item.topics` list contains all the topics that matched the query. In this case, it will contain all the topics that are of type IMU and for which the data-related filter is met. 2. The `topic.timestamp_range` provides the first and last occurrence of the queried condition within a topic, allowing you to slice data accurately for further analysis. The `query` method returns `None` if an error occurs, or a `QueryResponse` object. This response acts as a list of `QueryResponseItem` objects, each providing: * **`item.sequence`**: A `QueryResponseItemSequence` containing the sequence metadata. * **`item.topics`**: A list of `QueryResponseItemTopic` objects that matched the query. Result Normalization The `topic.name` returns the relative topic path (e.g., `/front/camera/image`), which is immediately compatible with other SDK methods like `MosaicoClient.topic_handler()`, `SequenceHandler.topic_handler()` or streamers. ### Key Concepts¶ * **Generic Methods**: The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. * **The `.Q` Proxy**: Every ontology model features a static `.Q` attribute that dynamically builds type-safe field paths for your expressions. * **Temporal Windows**: Setting `include_timestamp_range=True` enables the platform to return the precise "occurrence" of the event, which is vital for later playback or slicing. * **Type-Safe Operators**: The `.Q` proxy ensures that only valid operators (like `.gt()`) are available for numeric fields like `acceleration.x`. --- This guide demonstrates how to orchestrate a **Unified Query** across three distinct layers of the Mosaico Data Platform: the **Sequence** (session metadata), the **Topic** (channel configuration), and the **Ontology Catalog** (actual sensor data). By combining these builders in a single request, you can perform highly targeted searches that correlate mission-level context with specific sensor events. ### The Objective¶ We want to isolate data segments from a large fleet recording by searching for: 1. **Sequence**: Sessions belonging to the `"Apollo"` project. 2. **Topic**: Specifically the front-facing camera imu topic named `"/front/camera/imu"`. 3. **Ontology**: Time segments where such an IMU recorded a longitudinal acceleration (x-axis) exceeding 5.0 m/s². For a more in-depth explanation: * **Documentation: Querying Catalogs** * **API Reference: Query Builders** * **API Reference: Query Response** ### Implementation¶ When you pass multiple builders to the `MosaicoClient.query()` method, the platform joins them with a logical **AND** condition. The server will return only the sequences that match the `QuerySequence` criteria, and within those sequences, only the topics that match both the `QueryTopic` and `QueryOntologyCatalog` criteria. The multi-domain query allows you to execute a search across metadata and raw sensor data in a single, atomic request. ``` from mosaicolabs import MosaicoClient, QuerySequence, QueryTopic, QueryOntologyCatalog, IMU, Sequence # 1. Establish a connection with MosaicoClient.connect("localhost", 6726) as client: # 2. Execute a unified multi-domain query results = client.query( # Filter 1: Sequence Layer (Project Metadata) QuerySequence() .with_expression(Sequence.Q.user_metadata["project.name"].eq("Apollo")), # (1)! # Filter 2: Topic Layer (Specific Channel Name) QueryTopic() .with_name("/front/camera/imu"), # Precise name match # Filter 3: Ontology Layer (Deep Data Event Detection) QueryOntologyCatalog(include_timestamp_range=True) .with_expression(IMU.Q.acceleration.x.gt(5.0)) ) # 3. Process the Structured Response if results: for item in results: # item.sequence contains the matched Sequence metadata print(f"Sequence: {item.sequence.name}") # item.topics contains only the topics and time-segments # that satisfied ALL criteria simultaneously for topic in item.topics: # Access the high-precision timestamp for the detected event print(f" - Match in Topic: {topic.name}") # (2)! start, end = topic.timestamp_range.start, topic.timestamp_range.end # (3)! print(f" Event Window: {start} to {end} ns") ``` 1. Use dot notation to access nested fields in the `user_metadata` dictionary. 2. The `item.topics` list contains all the topics that matched the query. In this case, it will contain all the topics that are of type IMU, with a name matching that specific topic name and for which the data-related filter is met. 3. The `topic.timestamp_range` provides the first and last occurrence of the queried condition within a topic, allowing you to slice data accurately for further analysis. The `query` method returns `None` if an error occurs, or a `QueryResponse` object. This response acts as a list of `QueryResponseItem` objects, each providing: * **`item.sequence`**: A `QueryResponseItemSequence` containing the sequence metadata. * **`item.topics`**: A list of `QueryResponseItemTopic` objects that matched the query. Result Normalization The `topic.name` returns the relative topic path (e.g., `/front/camera/image`), which is immediately compatible with other SDK methods like `MosaicoClient.topic_handler()`, `SequenceHandler.get_topic_handler()` or streamers. ### Key Concepts¶ * **Convenience Methods**: High-level helpers like `with_name_match()` provide a quick way to filter common fields. * **Generic Methods**: The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. * **The `.Q` Proxy**: Every ontology model features a static `.Q` attribute that dynamically builds type-safe field paths for your expressions. * **Temporal Windows**: By setting `include_timestamp_range=True` in the `QueryOntologyCatalog`, the platform identifies the exact start and end of the matching event within the stream. * **Dictionary Access**: Use bracket notation (e.g., `Sequence.Q.user_metadata["key.subkey"]`) to query custom tags that are not part of a fixed schema. --- Sometimes a single query is insufficient because you need to correlate data across different topics. This guide demonstrates **Query Chaining**, a technique where the results of one search are used to "lock" the domain for a second, more specific search. ### The Objective¶ Find sequences where a high-precision GPS state was achieved, and **within those same sequences**, locate any log messages containing the string `"[ERR]"`. For a more in-depth explanation: * **Documentation: Querying Catalogs** * **API Reference: Query Builders** * **API Reference: Query Response** ### Implementation¶ ``` from mosaicolabs import MosaicoClient, QueryTopic, QueryOntologyCatalog, GPS, String with MosaicoClient.connect("localhost", 6726) as client: # Step 1: Initial Broad Search # Find all sequences with high-precision GPS (e.g. status code 2) initial_response = client.query( QueryOntologyCatalog(GPS.Q.status.status.eq(2)) ) if initial_response: # Step 2: Domain Locking # .to_query_sequence() creates a new builder pre-filtered to ONLY these sequences refined_domain = initial_response.to_query_sequence() # (1)! # Step 3: Targeted Refinement # Search for error strings only within the validated sequences final_results = client.query( refined_domain, # Restrict to this search domain QueryTopic().with_name("/localization/log_string"), QueryOntologyCatalog(String.Q.data.match("[ERR]")) ) for item in final_results: print(f"Error found in precise sequence: {item.sequence.name}") ``` 1. `to_query_sequence()` returns a `QuerySequence` builder pre-filtered to include only the **sequences** present in the response. See also `to_query_topic()` The `query` method returns `None` if an error occurs, or a `QueryResponse` object. This response acts as a list of `QueryResponseItem` objects, each providing: * **`item.sequence`**: A `QueryResponseItemSequence` containing the sequence metadata. * **`item.topics`**: A list of `QueryResponseItemTopic` objects that matched the query. Result Normalization The `topic.name` returns the relative topic path (e.g., `/front/camera/image`), which is immediately compatible with other SDK methods like `MosaicoClient.topic_handler()`, `SequenceHandler.get_topic_handler()` or streamers. ### Key Concepts¶ * **Convenience Methods**: High-level helpers like `QueryTopic().with_name()` provide a quick way to filter by ontology tags. * **Generic Methods**: The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. * **The `.Q` Proxy**: Every ontology model features a static `.Q` attribute that dynamically builds type-safe field paths for your expressions. * **Why is Chaining Necessary?** A single `client.query()` call applies a logical **AND** to all conditions to find a single **topic** that satisfies everything. Since a topic cannot be both a `GPS` stream and a `String` log simultaneously, you must use chaining to link two different topics within the same **Sequence** context. --- This guide walks you through the process of extending the Mosaico Data Platform with custom data models. While Mosaico provides a rich default ontology for robotics (IMU, GPS, Images, etc.), specialized hardware often requires proprietary data structures. By the end of this guide, you will be able to: * **Define** strongly-typed data models using Python and Apache Arrow. * **Register** these models so they are recognized by the Mosaico Ecosystem. * **Integrate** them into the ingestion and retrieval pipelines. For a more in-depth explanation: * **Documentation: Data Models & Ontology** * **API Reference: Base Models and Mixins** ### Step 1: Define the Custom Data Model¶ In Mosaico, data models are defined by inheriting from the **`Serializable`** base class. This ensures that your model can be automatically translated into the platform's high-performance storage format. For this example, we will create a model for **`EncoderTicks`**, found in the NVIDIA Isaac-related datasets. ``` import pyarrow as pa from mosaicolabs import HeaderMixin, Serializable class EncoderTicks( Serializable, # Automatically registers the model via `Serializable.__init_subclass__` HeaderMixin, # Injects standard metadata (timestamp, frame_id, seq) ): """ Custom model for hardware-level encoder tick readings. """ # --- Wire Schema Definition (Apache Arrow) --- # This defines the high-performance binary storage format on the server. __msco_pyarrow_struct__ = pa.struct([ pa.field("left_ticks", pa.uint32(), nullable=False), pa.field("right_ticks", pa.uint32(), nullable=False), pa.field("encoder_timestamp", pa.uint64(), nullable=False), ]) # --- Data Fields --- # Names and types must strictly match the Apache Arrow schema above. left_ticks: int right_ticks: int encoder_timestamp: int ``` ### Step 2: Ensure "Discovery" via Module Import¶ It is a common pitfall to define a class and expect the platform to "see" it immediately. Mosaico utilizes the `Serializable.__init_subclass__` hook to perform **automatic registration** the moment the class is loaded into memory by the Python interpreter. For your custom type to be available in your application (especially during ingestion or when using the `ROSBridge`), you **must** ensure the module containing the class is imported. #### Best Practice: The Registry Pattern¶ Create a dedicated `models.py` or `ontology/` package for your project and import it at your application's entry point. ``` # app/main.py import my_project.ontology.encoders as encoders # <-- This triggers the registration from mosaicolabs import MosaicoClient def run_ingestion(): with MosaicoClient.connect(...) as client: # Now 'EncoderTicks' is a valid ontology_type for topic creation with client.sequence_create(name="test") as sw: tw = sw.topic_create("ticks", ontology_type=encoders.EncoderTicks) # ... ``` ### Step 3: Verifying Registration¶ If you are unsure whether your model has been correctly "seen" by the ecosystem, you can check the internal registry of the `Serializable` class. ``` from mosaicolabs import Serializable import my_project.ontology.encoders as encoders # <-- This triggers the registration if encoders.EncoderTicks.is_registered(): print("Registration successful!") ``` --- Full Example Code The full example code is available under `mosaico-sdk-py/src/examples/ros_injection/main.py`. Prerequisites To fully grasp the following How-To, we recommend you to read the **Customizing the Data Ontology How-To**. Dataset This tutorial uses the `r2b_whitetunnel_0` sequence from the NVIDIA R2B Dataset 2024. This example provides a detailed, step-by-step walkthrough of a complete Mosaico data pipeline, from raw ROS bag ingestion to custom ontology creation and verification. It demonstrates how to bridge the gap between **Robot Operating System (ROS)** data and the **Mosaico Data Platform**. By following this pipeline, you will learn how to: 1. **Create a custom ontology data model** that matches a specific hardware sensor. 2. **Implement a ROS Adapter** that converts raw ROS dictionaries into your custom Mosaico model. 3. **Automate Ingestion** using a high-performance injector to upload a complete recording (MCAP) to the server. 4. **Verify Results** by inspecting the ingested data to ensure structural integrity. ## Running the Example¶ This setup provides a local Mosaico server instance to receive and store the data from your Python scripts. This example expects the Python SDK to be installed via Poetry, as described in the **Installation section**. #### Start the Mosaico Infrastructure¶ First, launch the required backend services (database and ingestion server) using Docker Compose. Run these commands from the `mosaico` root directory: ``` # Navigate to the quickstart environment cd docker/quick_start # Start the Mosaico server and its dependencies docker compose up ``` #### Execute the ROS Injection Script¶ Once the infrastructure is healthy, open a new terminal tab or window to run the demonstration script. Run these commands from the `mosaico-sdk-py` root directory: ``` # Navigate to the examples directory cd src/examples # Run the ROS injection example using poetry poetry run python -m ros_injection.main ``` ### What to Expect¶ * **Server Logs**: In your first terminal, you will see the Docker containers spinning up and the Mosaico Ingestion Server acknowledging incoming connections. * **Injection Progress**: In your second terminal, the `RosbagInjector` will provide a CLI progress bar showing the topics being resolved, messages being adapted, and the final transmission status. * **Data Verification**: After completion, the sequence will be fully cataloged on the server and ready for retrieval via the `SequenceHandler`. **Would you like me to show you how to check the server logs to verify that the sequence was successfully committed to the database?** You should see output similar to the following: ``` Downloading: https://api.ngc.nvidia.com/v2/resources/org/nvidia/team/isaac/r2bdataset2024/1/files?redirect=true&path=r2b_whitetunnel/r2b_whitetunnel_0.mcap Fetching r2b_whitetunnel_0.mcap ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 527.0/527.0 MB XY.Z MB/s 0:00:00 ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Phase 2: Starting ROS Ingestion │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ [14:29:38] INFO mosaicolabs: SDK Logging initialized at level: INFO logging_config.py:99 INFO mosaicolabs.ros_bridge.injector: Connecting to Mosaico at 'localhost:6276'... injector.py:266 [14:29:40] INFO mosaicolabs.ros_bridge.injector: Opening bag: '/tmp/mosaico_assets/r2b_whitetunnel_0.mcap' injector.py:274 INFO mosaicolabs.ros_bridge.injector: Starting upload... injector.py:291 /back_stereo_camera/left/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 564/564 100.0% • 0:00:00 • 0:00:24 /back_stereo_camera/left/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 525/525 100.0% • 0:00:00 • 0:00:24 /back_stereo_camera/right/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 564/564 100.0% • 0:00:00 • 0:00:24 /back_stereo_camera/right/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 490/490 100.0% • 0:00:00 • 0:00:24 /chassis/battery_state ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 27/27 100.0% • 0:00:00 • 0:00:19 /chassis/imu ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1080/1080 100.0% • 0:00:00 • 0:00:24 /chassis/odom ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1080/1080 100.0% • 0:00:00 • 0:00:24 /chassis/ticks ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1081/1081 100.0% • 0:00:00 • 0:00:24 /front_stereo_camera/left/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 562/562 100.0% • 0:00:00 • 0:00:24 /front_stereo_camera/left/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 521/521 100.0% • 0:00:00 • 0:00:24 /front_stereo_camera/right/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 562/562 100.0% • 0:00:00 • 0:00:24 /front_stereo_camera/right/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 515/515 100.0% • 0:00:00 • 0:00:24 /front_stereo_imu/imu ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1761/1761 100.0% • 0:00:00 • 0:00:24 /left_stereo_camera/left/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 527/527 100.0% • 0:00:00 • 0:00:24 /left_stereo_camera/left/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 513/513 100.0% • 0:00:00 • 0:00:24 /left_stereo_camera/right/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 527/527 100.0% • 0:00:00 • 0:00:24 /left_stereo_camera/right/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 498/498 100.0% • 0:00:00 • 0:00:24 /right_stereo_camera/left/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 488/488 100.0% • 0:00:00 • 0:00:24 /right_stereo_camera/left/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 488/488 100.0% • 0:00:00 • 0:00:24 /right_stereo_camera/right/camera_info ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 488/488 100.0% • 0:00:00 • 0:00:24 /right_stereo_camera/right/image_compressed ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 488/488 100.0% • 0:00:00 • 0:00:24 /tf ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4282/4282 100.0% • 0:00:00 • 0:00:24 /tf_static ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/1 100.0% • 0:00:00 • 0:00:00 Total Upload ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17632/17632 100.0% • 0:00:00 • 0:00:24 ...Other logging messages ``` ## Step-by-Step Guide¶ ### Step 1: Custom Ontology Definition (`isaac.py`)¶ In Mosaico, data is strongly typed. When dealing with specialized hardware like the NVIDIA Isaac Nova encoders, with custom data models, not available in the SDK, we must define a model that the platform understands. #### The Data Model¶ The `EncoderTicks` class defines the physical storage format. ``` import pyarrow as pa from mosaicolabs import HeaderMixin, Serializable class EncoderTicks(Serializable, HeaderMixin): # --- Wire Schema Definition --- __msco_pyarrow_struct__ = pa.struct([ pa.field("left_ticks", pa.uint32(), nullable=False), pa.field("right_ticks", pa.uint32(), nullable=False), pa.field("encoder_timestamp", pa.uint64(), nullable=False), ]) # --- Pydantic Fields --- left_ticks: int right_ticks: int encoder_timestamp: int ``` **What is happening here?** * **`Serializable`**: Inheriting from this class automatically registers your model in the Mosaico ecosystem, making it dispatchable to the data platform, and enables the `.Q` query proxy. * **`HeaderMixin`**: This "injects" a standard `header` (including a timestamp and frame ID) into your model, ensuring it remains compatible with time-series analysis. * **Schema Alignment**: The field names in the `pa.struct` **must match exactly** the names of the Python attributes. For a more in-depth explanation: * **How-To: Customizing the Data Ontology** * **Documentation: Data Models & Ontology** ### Step 2: Implementing the ROS Adapter (`isaac_adapters.py`)¶ A ROS Bag contains raw data dictionaries, that we need to translate into our custom ontology data model, by using *adapters*. The `ROSAdapterBase` class provides the necessary infrastructure for this. We just need to implement the `from_dict` method, which is responsible for converting the raw ROS message dictionary into our custom ontology model. #### The Adapter Implementation¶ ``` from mosaicolabs.ros_bridge import ROSMessage, ROSAdapterBase, register_adapter from mosaicolabs.ros_bridge.adapters.helpers import _make_header, _validate_msgdata from .isaac import EncoderTicks @register_adapter class EncoderTicksAdapter(ROSAdapterBase[EncoderTicks]): ros_msgtype = ("isaac_ros_nova_interfaces/msg/EncoderTicks",) __mosaico_ontology_type__ = EncoderTicks _REQUIRED_KEYS = ("left_ticks", "right_ticks", "encoder_timestamp") @classmethod def from_dict(cls, ros_data: dict) -> EncoderTicks: """ Convert a ROS message dictionary to an EncoderTicks object. """ _validate_msgdata(cls, ros_data) return EncoderTicks( header=_make_header(ros_data.get("header")), left_ticks=ros_data["left_ticks"], right_ticks=ros_data["right_ticks"], encoder_timestamp=ros_data["encoder_timestamp"], ) @classmethod def translate(cls, ros_msg: ROSMessage, **kwargs: Any) -> Message: """ Translates a ROS EncoderTicks message into a Mosaico Message container. """ return super().translate(ros_msg, **kwargs) ``` **Key Operations:** * **`@register_adapter`**: This decorator registers the adapter with the Mosaico ROS Bridge. * **`ros_msgtype`**: A tuple of strings representing the ROS message types that this adapter can handle. * **`__mosaico_ontology_type__`**: The Mosaico ontology type that this adapter can handle. * **`_REQUIRED_KEYS`**: A tuple of strings representing the required keys in the ROS message. This is used by the `_validate_msgdata` method to check that the ROS message does contains the required fields. * **`from_dict`**: This is the heart of the translator. It takes a Python dictionary and maps the keys to our `EncoderTicks` ontology model. * **`translate`**: This method is called by the `RosbagInjector` class for each message in the bag. It is responsible for converting the raw ROS message dictionary into the Mosaico message, wrapping the custom ontology model. For a more in-depth explanation: * **Documentation: ROS Bridge** * **API Reference: ROS Bridge** ### Step 3: The Execution Pipeline (`ros_injection.py`)¶ The main script orchestrates the entire process in three distinct phases. #### Phase 1: Asset Preparation¶ Before we can ingest data, we need the raw file. This phase downloads a verified dataset from NVIDIA. ``` # --- PHASE 1: Asset Preparation --- out_bag_file = download_asset(BAGFILE_URL, ASSET_DIR) ``` #### Phase 2: High-Performance Injection¶ This is where the ROS Bridge takes over. It opens the bag, applies our custom `EncoderTicksAdapter`, plus the adapters already available in the SDK, and streams the data to the server. ``` # Configure the ROS injection. This uses the 'Adaptation' philosophy to translate # ROS types into the Mosaico Ontology. config = ROSInjectionConfig( host=MOSAICO_HOST, port=MOSAICO_PORT, file_path=out_bag_file, sequence_name=out_bag_file.stem, # Sequence name derived from filename # Some example metadata for the sequence metadata={ "source_url": BAGFILE_URL, "ingested_via": "mosaico_example_ros_injection", "download_time_utc": str(downloaded_time), }, log_level="INFO", ) # Handles connection, loading, adaptation, and batching injector = RosbagInjector(config) injector.run() # Starts the ingestion process ``` The **`ROSInjectionConfig`** defines where the server is and what metadata to attach to the sequence. The **`injector.run()`** method handles the heavy lifting—file loading, message adaptation, and network batching—automatically. The **`RosbagInjector`** uses the SDK features to connect to the Mosaico server, orchestrating sequence and topics creation, etc. For a more in-depth explanation: * **Documentation: ROS Bridge** * **API Reference: ROS Bridge** #### Phase 3: Verification & Retrieval¶ Once the upload is finished, we connect to the Mosaico Server to retrieve the data from the sequence just created. ``` with MosaicoClient.connect(host=MOSAICO_HOST, port=MOSAICO_PORT) as client: # Ask for a SequenceHandler for the sequence we just created. # The sequence is identified by its name, which is the stem of the bagfile. shandler = client.sequence_handler(out_bag_file.stem) # Print some information about the sequence print(f"Sequence Name: {shandler.name}") print(f"Topics Found: {len(shandler.topics)}") # ... ``` **Operations:** * **`MosaicoClient.connect()`**: Establishes a secure connection to the platform. * **`MosaicoClient.sequence_handler()`**: Retrieves a specialized object used to manage and query the specific recording we just uploaded. For a more in-depth explanation: * **Documentation: The Reading Workflow** * **API Reference: Data Retrieval** ## The full example code¶ The full example code is available under `mosaico-sdk-py/src/examples/ros_injection/main.py`. --- API Reference: `mosaicolabs.comm.MosaicoClient`. The `MosaicoClient` is a resource manager designed to orchestrate three distinct **Layers** of communication and processing. This layered architecture ensures that high-throughput sensor data does not block critical control operations or application logic. ## Control Layer¶ A single, dedicated connection is maintained for metadata operations. This layer handles lightweight tasks such as creating sequences, querying the catalog, and managing schema definitions. By isolating control traffic, the client ensures that critical commands (like `sequence_finalize`) are never queued behind heavy data transfers. ## Data Layer¶ For high-bandwidth data ingestion (e.g., uploading 4x 1080p cameras simultaneously), the client maintains a **Connection Pool** of multiple Flight clients. The SDK automatically stripes writes across these connections in a round-robin fashion, allowing the application to saturate the available network bandwidth. ## Processing Layer¶ Serialization of complex sensor data (like compressing images or encoding LIDAR point clouds) is CPU-intensive. The SDK uses an **Executor Pool** of background threads to offload these tasks. This ensures that while one thread is serializing the *next* batch of data, another thread is already transmitting the *previous* batch over the network. **Best Practice:** It is recomended to always use the client inside a `with` context to ensure resources in all layers are cleanly released. ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Logic goes here pass # Pools and connections are closed automatically ``` --- The **Mosaico Data Ontology** is the semantic backbone of the SDK. It defines the structural "rules" that transform raw binary streams into meaningful physical data, such as GPS coordinates, inertial measurements, or camera frames. By using a strongly-typed ontology, Mosaico ensures that your data remains consistent, validatable, and highly optimized for both high-throughput transport and complex queries. ## Core Philosophy¶ The ontology is designed to solve the "generic data" problem in robotics by ensuring every data object is: 1. **Validatable**: Uses Pydantic for strict runtime type checking of sensor fields. 2. **Serializable**: Automatically maps Python objects to efficient **PyArrow** schemas for high-speed binary transport. 3. **Queryable**: Injects a fluent API (`.Q`) into every class, allowing you to filter databases based on physical values (e.g., `IMU.Q.acceleration.x > 6.0`). 4. **Middleware-Agnostic**: Acts as an abstraction layer so that your analysis code doesn't care if the data originally came from ROS, a simulator, or a custom logger. ## Available Ontology Classes¶ The Mosaico SDK provides a comprehensive library of models that transform raw binary streams into validated, queryable Python objects. These are grouped by their physical and logical application below. ### Base Data Models¶ API Reference: Base Data Types These models serve as timestamped, metadata-aware wrappers for standard primitives. They allow simple diagnostic or scalar values to be treated as first-class members of the platform. | Module | Classes | Purpose | | --- | --- | --- | | **Primitives** | `String`, `LargeString` | UTF-8 text data for logs or status messages. | | **Booleans** | `Boolean` | Logic flags (True/False). | | **Signed Integers** | `Integer8`, `Integer16`, `Integer32`, `Integer64` | Signed whole numbers of varying bit-depth. | | **Unsigned Integers** | `Unsigned8`, `Unsigned16`, `Unsigned32`, `Unsigned64` | Non-negative integers for counters or IDs. | | **Floating Point** | `Floating16`, `Floating32`, `Floating64` | Real numbers for high-precision physical values. | ### Geometry & Kinematics Models¶ API Reference: Geometry Models These structures define spatial relationships and the movement states of objects in 2D or 3D coordinate frames. | Module | Classes | Purpose | | --- | --- | --- | | **Points & Vectors** | `Vector2d/3d/4d`, `Point2d/3d` | Fundamental spatial directions and locations. | | **Rotations** | `Quaternion` | Compact, singularity-free 3D orientation (). | | **Spatial State** | `Pose`, `Transform` | Absolute positions or relative coordinate frame shifts. | | **Motion** | `Velocity`, `Acceleration` | Linear and angular movement rates (Twists and Accels). | | **Aggregated State** | `MotionState` | An atomic snapshot combining Pose, Velocity, and Acceleration. | ### Sensor Models¶ API Reference: Sensor Models High-level models representing physical hardware devices and their processed outputs. | Module | Classes | Purpose | | --- | --- | --- | | **Inertial** | `IMU` | 6-DOF inertial data: linear acceleration and angular velocity. | | **Navigation** | `GPS`, `GPSStatus`, `NMEASentence` | Geodetic fixes (WGS 84), signal quality, and raw NMEA strings. | | **Vision** | `Image`, `CompressedImage`, `CameraInfo`, `ROI` | Raw pixels, encoded streams (JPEG/H264), calibration, and regions of interest. | | **Environment** | `Temperature`, `Pressure`, `Range` | Thermal readings (K), pressure (Pa), and distance intervals (m). | | **Dynamics** | `ForceTorque` | 3D force and torque vectors for load sensing. | | **Magnetic** | `Magnetometer` | Magnetic field vectors measured in microTesla (). | | **Robotics** | `RobotJoint` | States (position, velocity, effort) for index-aligned actuator arrays. | ## Architecture¶ The ontology architecture relies on three primary abstractions: the **Factory** (`Serializable`), the **Envelope** (`Message`) and the **Mixins** ### 1. `Serializable` (The Factory)¶ API Reference: `mosaicolabs.models.Serializable` Every data payload in Mosaico inherits from the `Serializable` class. It manages the global registry of data types and ensures that the system knows exactly how to convert a string tag like `"imu"` back into a Python class with a specific binary schema. `Serializable` uses the `__init_subclass__` hook, which is automatically called whenever a developer defines a new subclass. ``` class MyCustomSensor(Serializable): # <--- __init_subclass__ triggers here ... ``` When this happens, `Serializable` performs the following steps automatically: 1. **Validates Schema:** Checks if the subclass defined the PyArrow struct schema (`__msco_pyarrow_struct__`). If missing, it raises an error at definition time (import time), preventing runtime failures later. 2. **Generates Tag:** If the class doesn't define `__ontology_tag__`, it auto-generates one from the class name (e.g., `MyCustomSensor` -> `"my_custom_sensor"`). 3. **Registers Class:** It adds the new class to the global types registry. 4. **Injects Query Proxy:** It dynamically adds a `.Q` attribute to the class, enabling the fluent query syntax (e.g., `MyCustomSensor.Q.voltage > 12.0`). ### 2. `Message` (The Envelope)¶ API Reference: `mosaicolabs.models.Message` The **`Message`** class is the universal transport envelope for all data within the Mosaico platform. It acts as a wrapper that combines specific sensor data (the payload) with middleware-level metadata. ``` from mosaicolabs import Message, Time, Header, Temperature # Use Case: Create a Temperature timestamped message with uncertainty meas_time = Time.now() temp_msg = Message( timestamp_ns=meas_time.to_nanoseconds(), # here the message timestamp is the same as the measurement, but it can be different data=Temperature.from_celsius( value=57, header=Header(stamp=meas_time, frame_id="comp_case"), variance=0.03 ) ) ``` While logically a `Message` contains a `data` object (e.g., an instance of an Ontology type), physically on the wire (PyArrow/Parquet), the fields are **flattened**. * **Logical:** `Message(timestamp_ns=123567890, data=IMU(acceleration=Vector3d(x=1.0,...)))` * **Physical:** `Struct(timestamp_ns=123567890, acceleration, ...)` This flattening is handled automatically by the class internal methods. This ensures zero-overhead access to nested data during queries while maintaining a clean object-oriented API in Python. ### 3. Mixins: Headers & Uncertainty¶ Mosaico uses **Mixins** to inject standard fields across different data types, ensuring a consistent interface. Almost every class in the ontology, from high-level sensors down to elementary data primitives like `Vector3d` or `Float32`, inherits from two Mixin classes, which inject standard fields into data models via composition, ensuring consistency across different sensor types. The integration of mixins into the Mosaico Data Ontology enables a flexible dual-usage pattern, **Standalone Messages** and **Embedded Fields**, which will be detailed later and allow base geometric types to serve as either independent data streams or granular components of complex sensor models. #### `HeaderMixin`¶ API Reference: `mosaicolabs.models.mixins.HeaderMixin` Injects a standard (Optional) `header` containing a sequence ID, a frame ID (e.g., `"base_link"`), and a high-precision acquisition timestamp (`stamp`). ``` class MySensor(Serializable, HeaderMixin): # Injects a header with stamp, frame_id, and seq fields ... ``` #### `CovarianceMixin`¶ API Reference: `mosaicolabs.models.mixins.CovarianceMixin` Injects multidimensional uncertainty fields, typically used for flattened covariance matrices in sensor fusion applications. ``` class MySensor(Serializable, CovarianceMixin): # Injects a covariance matrix with covariance and covariance_type fields ... ``` #### `VarianceMixin`¶ API Reference: `mosaicolabs.models.mixins.VarianceMixin` Injects monodimensional uncertainty fields, useful for sensors with 1-dimensional uncertain data (like `Temperature` or `Pressure`). ``` class MySensor(Serializable, VarianceMixin): # Injects a variance with variance and variance_type fields ... ``` #### Standalone Usage¶ Because elementary types (such as `Vector3d`, `String`, or `Float32`) inherit directly from these mixins, they are "first-class" members of the ontology. You can treat them as independent, timestamped messages without needing to wrap them in a more complex container. This is ideal for pushing processed signals, debug values, or simple sensor readings that require their own metadata and uncertainty context. ``` # Use Case: Sending a raw 3D vector as a timestamped message with uncertainty accel_msg = Vector3d( x=0.0, y=0.0, z=9.81, header=Header(stamp=Time.now(), frame_id="base_link"), covariance=[0.01, 0, 0, 0, 0.01, 0, 0, 0, 0.01] # 3x3 Diagonal matrix ) # `acc_writer` is a TopicWriter associated to the new sequence that is being uploaded. acc_writer.push(message=Message(timestamp_ns=ts, data=accel_msg)) # (1)! # Use Case: Sending a timestamped diagnostic error error_msg = String( data="Waypoint-miss in navigation detected!", header=Header(stamp=Time.now(), frame_id="base_link") ) # `log_writer` is another TopicWriter associated to the new sequence that is being uploaded. log_writer.push(message=Message(timestamp_ns=ts, data=error_msg)) ``` 1. The `push` command will be covered in the documentation of the Writers API Reference: * `mosaicolabs.handlers.SequenceWriter` * `mosaicolabs.handlers.TopicWriter` #### Embedded Usage¶ When these base types are used as internal fields within a larger structure (e.g., an `IMU` or `MotionState` model), the mixins allow you to attach metadata to specific *parts* of a message. In this context, while the parent object (the `IMU`) carries a global timestamp, the individual fields (like `acceleration`) can carry their own specific **covariance** matrices. To avoid data redundancy, the internal `header` of the embedded field is typically left as `None`, as it inherits the temporal context from the parent message. ``` # Use Case: Embedding Vector3d inside a complex IMU message imu_msg = IMU( # Parent Header: Defines the time and frame for the entire sensor packet header=Header(stamp=Time.now(), frame_id="imu_link"), # Embedded Field 1: Acceleration # Inherits global time, but specifies its own unique uncertainty acceleration=Vector3d( x=0.5, y=-0.2, z=9.8, covariance=[0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1] # Specific to acceleration ), # Embedded Field 2: Angular Velocity # Carries a distinct covariance matrix independent of the acceleration angular_velocity=Vector3d( x=0.01, y=0.0, z=-0.01, covariance=[0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05] # Specific to velocity ) ) # as above, `imu_writer` is another TopicWriter associated to the new sequence that is being uploaded. imu_writer.push(imu_msg) ``` ## Querying Data Ontology with the Query (`.Q`) Proxy¶ The Mosaico SDK allows you to perform deep discovery directly on the physical content of your sensor streams. Every class inheriting from `Serializable`, including standard sensors, geometric primitives, and custom user models, is automatically injected with a static **`.Q` proxy** attribute. This proxy acts as a type-safe bridge between your Python data models and the platform's search engine, enabling you to construct complex filters using standard Python dot notation. ### How the Proxy Works¶ The `.Q` proxy recursively inspects the model’s schema to expose every queryable field path. It identifies the data type of each field and provides only the operators valid for that type (e.g., numeric comparisons for acceleration, substring matches for frame IDs). * **Direct Field Access**: Filter based on primary values, such as `Temperature.Q.value.gt(25.0)`. * **Nested Navigation**: Traverse complex, embedded structures. For example, in the `GPS` model, you can drill down into the status sub-field: `GPS.Q.status.satellites.geq(8)`. * **Mixin Integration**: Fields inherited from mixins are automatically included in the proxy. This allows you to query standard metadata (from `HeaderMixin`) or uncertainty metrics (from `VarianceMixin` or `CovarianceMixin`) across any model. ### Queryability Examples¶ The following table illustrates how the proxy flattens complex hierarchies into queryable paths: | Type Field Path | Proxy Field Path | Source Type | Queryable Type | Supported Operators | | --- | --- | --- | --- | --- | | `IMU.acceleration.x` | `IMU.Q.acceleration.x` | `float` | **Numeric** | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.status.hdop` | `GPS.Q.status.hdop` | `float` | **Numeric** | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.header.frame_id` | `IMU.Q.header.frame_id` | `str` | **String** | `.eq()`, `.neq()`, `.match()`, `.in_()` | | `GPS.covariance_type` | `GPS.Q.covariance_type` | `int` | **Numeric** | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | ### Practical Usage¶ To execute these filters, pass the expressions generated by the proxy to the `QueryOntologyCatalog` builder. ``` from mosaicolabs import MosaicoClient, IMU, GPS, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # orchestrate a query filtering by physical thresholds AND metadata qresponse = client.query( QueryOntologyCatalog(include_timestamp_range=True) # Ask for the start/end timestamps of occurrences .with_expression(IMU.Q.acceleration.z.gt(15.0)) .with_expression(GPS.Q.status.service.eq(2)) ) # The server returns a QueryResponse grouped by Sequence for structured data management if qresponse is not None: for item in qresponse: # 'item.sequence' contains the name for the matched sequence print(f"Sequence: {item.sequence.name}") # 'item.topics' contains only the topics and time-segments # that satisfied the QueryOntologyCatalog criteria for topic in item.topics: # Access high-precision timestamps for the data segments found start, end = topic.timestamp_range.start, topic.timestamp_range.end print(f" Topic: {topic.name} | Match Window: {start} to {end}") ``` For a comprehensive list of all supported operators and advanced filtering strategies (such as query chaining), see the **Full Query Documentation** and the Ontology types SDK Reference in the **API Reference**: * Base Data Models * Sensors Models * Geometry Models * Platform Models ## Customizing the Ontology¶ The Mosaico SDK is built for extensibility, allowing you to define domain-specific data structures that can be registered to the platform and live alongside standard types. Custom types are automatically validatable, serializable, and queryable once registered in the platform. Follow these three steps to implement a compatible custom data type: ### 1. Inheritance and Mixins¶ Your custom class **must** inherit from `Serializable` to enable auto-registration, factory creation, and the queryability of the model. To align with the Mosaico ecosystem, use the following mixins: * **`HeaderMixin`**: Required for timestamped data or sensor readings. It injects a standard `header` (stamp, frame\_id, seq), ensuring your data remains compatible with time-synchronization and coordinate frame logic. * **`CovarianceMixin`**: Used for data including measurement uncertainty, standardizing the storage of covariance matrices. ### 2. Define the Wire Schema (`__msco_pyarrow_struct__`)¶ You must define a class-level `__msco_pyarrow_struct__` using `pyarrow.struct`. This explicitly dictates how your Python object is serialized into high-performance Apache Arrow/Parquet buffers for network transmission and storage. #### 2.1 Serialization Format Optimization¶ API Reference: `mosaicolabs.enum.SerializationFormat` You can optimize remote server performance by overriding the `__serialization_format__` attribute. This controls how the server compresses and organizes your data. | Format | Identifier | Use Case Recommendation | | --- | --- | --- | | **Default** | `"default"` | **Standard Table**: Fixed-width data with a constant number of fields. | | **Ragged** | `"ragged"` | **Variable Length**: Best for lists, sequences, or point clouds. | | **Image** | `"image"` | **Blobs**: Raw or compressed images requiring specialized codec handling. | If not explicitly set, the system defaults to `Default` format. ### 3. Define Class Fields¶ Define the Python attributes for your class using standard type hints. Note that the names of your Python class fields **must match exactly** the field names defined in your `__msco_pyarrow_struct__` schema. ### Customization Example: `EnvironmentSensor`¶ This example demonstrates a custom sensor for environmental monitoring that tracks temperature, humidity, and pressure. ``` # file: custom_ontology.py from typing import Optional import pyarrow as pa from mosaicolabs.models import Serializable, HeaderMixin class EnvironmentSensor(Serializable, HeaderMixin): """ Custom sensor reading for Temperature, Humidity, and Pressure. """ # --- 1. Define the Wire Schema (PyArrow Layout) --- __msco_pyarrow_struct__ = pa.struct( [ pa.field("temperature", pa.float32(), nullable=False), pa.field("humidity", pa.float32(), nullable=True), pa.field("pressure", pa.float32(), nullable=True), ] ) # --- 2. Define Python Fields (Must match schema exactly) --- temperature: float humidity: Optional[float] = None pressure: Optional[float] = None # --- Usage Example --- from mosaicolabs.models import Message, Header, Time # Initialize with standard metadata meas = EnvironmentSensor( header=Header(stamp=Time.now(), frame_id="lab_sensor_1"), temperature=23.5, humidity=0.45 ) # Ready for streaming or querying # writer.push(Message(timestamp_ns=ts, data=meas)) ``` Schema for defining a custom ontology model. --- The **Data Handling** module serves as the high-performance operational core of the Mosaico SDK, providing a unified interface for moving multi-modal sensor data between local applications and the Mosaico Data Platform. Engineered to solve the "Big Data" challenges of robotics and autonomous systems, this module abstracts the complexities of network I/O, asynchronous buffering, and high-precision temporal alignment. ### Asymmetric Architecture¶ The SDK employs a specialized architecture that separates concerns into **Writers** and **Handlers**, ensuring each layer is optimized for its unique traffic pattern: * **Ingestion (Writing)**: Designed for low-latency, high-throughput ingestion of 4K video, high-frequency IMU telemetry, and dense point clouds. It utilizes a "Multi-Lane" approach where each sensor stream operates in isolation with dedicated system resources. * **Discovery & Retrieval (Reading)**: Architected to separate metadata-based resource discovery from high-volume data transmission. This separation allows developers to inspect sequence and topic catalogs—querying metadata and temporal bounds—before committing to a high-bandwidth data stream. ### Memory-Efficient Data Flow¶ The Mosaico SDK is engineered to handle massive data volumes without exhausting local system resources, enabling the processing of datasets that span terabytes while maintaining a minimal and predictable memory footprint. * **Smart Batching & Buffering**: Both reading and writing operations are executed in memory-limited batches rather than loading or sending entire sequences at once. * **Asynchronous Processing**: The SDK offloads CPU-intensive tasks, such as image serialization and network I/O, to background threads within the `MosaicoClient`. * **Automated Lifecycle**: In reading workflows, processed batches are automatically discarded and replaced with new data from the server. In writing workflows, buffers are automatically flushed based on configurable size or record limits. * **Stream Persistence**: Integrated **Error Policies** allow developers to prioritize either a "clean slate" data state or "recovery" of partial data in the event of an application crash. --- The **Writing Workflow** in Mosaico is designed for high-throughput data ingestion, ensuring that your application remains responsive even when streaming high-bandwidth sensor data like 4K video or high-frequency IMU telemetry. The architecture is built around a **"Multi-Lane"** approach, where each sensor stream operates in its own isolated lane with dedicated system resources. ### The Orchestrator: `SequenceWriter`¶ API Reference: `mosaicolabs.handlers.SequenceWriter`. The `SequenceWriter` acts as the central controller for a recording session. It manages the high-level lifecycle of the data on the server and serves as the factory for individual sensor streams. **Key Roles:** * **Lifecycle Management**: It handles the lifecycle of a new sequence and ensures that it is either successfully committed as immutable data or, in the event of a failure, cleaned up according to your configured `OnErrorPolicy`. * **Resource Distribution**: The writer pulls network connections from the **Connection Pool** and background threads from the **Executor Pool**, assigning them to individual topics. This isolation prevents a slow network connection on one topic from bottlenecking others. * **Context Safety**: To ensure data integrity, the `SequenceWriter` must be used within a Python `with` block. This guarantees that all buffers are flushed and the sequence is closed properly, even if your application crashes. ``` from mosaicolabs import MosaicoClient, OnErrorPolicy # Open the connection with the Mosaico Client with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create( sequence_name="mission_log_042", # Custom metadata for this data sequence. metadata={ # (1)! "vehicle": { "vehicle_id": "veh_sim_042", "powertrain": "EV", "sensor_rig_version": "v3.2.1", "software_stack": { "perception": "perception-5.14.0", "localization": "loc-2.9.3", "planning": "plan-4.1.7", }, }, "driver": { "driver_id": "drv_sim_017", "role": "validation", "experience_level": "senior", }, } on_error = OnErrorPolicy.Delete # Default ) as seq_writer: # `seq_writer` is the writing handler of the new 'mission_log_042' sequence # Data will be uploaded by spawning topic writers that will manage the actual data stream # remote push... See below. ``` 1. The metadata fields will be queryable via the `Query` mechanism. The mechanism allows creating queries like: `Sequence.Q.user_metadata["vehicle.software_stack.planning"].match("plan-4.")` ### The Data Engine: `TopicWriter`¶ API Reference: `mosaicolabs.handlers.TopicWriter`. Once a topic is created, a `TopicWriter` is spawned to handle the actual transmission of data for that specific stream. It abstracts the underlying networking protocols, allowing you to simply "push" Python objects while it handles the heavy lifting. **Key Roles:** * **Smart Buffering**: Instead of sending every single message over the network—which would be highly inefficient—the `TopicWriter` accumulates records in a memory buffer. * **Automated Flushing**: The writer automatically triggers a "flush" to the server whenever the internal buffer exceeds your configured limits, such as a maximum byte size or a specific number of records. * **Asynchronous Serialization**: For CPU-intensive data (like encoding images), the writer can offload the serialization process to background threads, ensuring your main application loop stays fast. ``` # Continues from the code above... # 👉 with client.sequence_create(...) as seq_writer: # Create individual Topic Writers # Each writer gets its own assigned resources from the pools imu_writer = seq_writer.topic_create( topic_name="sensors/imu", # The univocal topic name metadata={ # The topic/sensor custom metadata "vendor": "inertix-dynamics", "model": "ixd-f100", "firmware_version": "1.2.0", "serial_number": "IMUF-9A31D72X", "calibrated":"false", }, ontology_type=IMU, # The ontology type stored in this topic ) # Another individual topic writer for the GPS device gps_writer = seq_writer.topic_create( topic_name="sensors/gps", # The univocal topic name metadata={ # The topic/sensor custom metadata "role": "primary_gps", "vendor": "satnavics", "model": "snx-g500", "firmware_version": "3.2.0", "serial_number": "GPS-7C1F4A9B", "interface": { # (1)! "type": "UART", "baudrate": 115200, "protocol": "NMEA", }, }, # The topic/sensor custom metadata ontology_type=GPS, # The ontology type stored in this topic ) # Push data - The SDK handles batching and background I/O imu_writer.push( message=Message( timestamp_ns=1700000000000, data=IMU(acceleration=Vector3d(x=0, y=0, z=9.81), ...), ) ) gps_writer.push( message=Message( timestamp_ns=1700000000100, data=GPS(position=Vector3d(x=44.0123,y=10.12345,z=0), ...), ) ) # Exiting the block automatically flushes all topic buffers, finalizes the sequence on the server # and closes all connections and pools ``` 1. The metadata fields will be queryable via the `Query` mechanism. The mechanism allows creating query expressions like: `Topic.Q.user_metadata["interface.type"].eq("UART")`. API Reference: * `mosaicolabs.models.platform.Topic` * `mosaicolabs.models.query.builders.QueryTopic`. ### Resilient Data Ingestion & Error Management¶ Recording high-bandwidth sensor data in dynamic environments requires a tiered approach to error handling. While the Mosaico SDK provides automated recovery through **Error Policies**, these act as a "last line of defense". For robust production pipelines, you must implement **Defensive Ingestion Patterns** to prevent isolated failures from compromising your entire recording session. ### Sequence-Level Error Handling¶ API Reference: `mosaicolabs.enum.OnErrorPolicy`. Configured when instantiating a new `SequenceWriter` via `MosaicoClient.connect()` factory, these policies dictate how the server handles a sequence if an unhandled exception bubbles up to the `SequenceWriter` context manager. #### 1. `OnErrorPolicy.Delete` (The "Clean Slate" Policy)¶ * **Behavior**: If an error occurs, the SDK sends an `ABORT` signal to the server. * **Result**: The server immediately deletes the entire sequence and all associated topic data. * **Best For**: CI/CD pipelines, unit testing, or "Gold Dataset" generation where partial or corrupted logs are unacceptable. #### 2. `OnErrorPolicy.Report` (The "Recovery" Policy)¶ * **Behavior**: The SDK finalizes data that successfully reached the server and sends a `NOTIFY_CREATE` signal with error details. * **Result**: The sequence is preserved but remains in an **unlocked (pending) state**, allowing for forensic analysis. * **Best For**: Field tests and mission-critical logs where lead-up data is essential for debugging. An example schematic rationale for deciding between the two policies can be: | Scenario | Recommended Policy | Rationale | | --- | --- | --- | | **Edge/Field Tests** | `OnErrorPolicy.Report` | Forensic value: "Partial data is better than no data" for crash analysis. | | **Automated CI/CD** | `OnErrorPolicy.Delete` | Platform hygiene: Prevents cluttering the catalog with junk data from failed runs. | | **Ground Truth Generation** | `OnErrorPolicy.Delete` | Integrity: Ensures only 100% verified, complete sequences enter the database. | ### Topic-Level Error Handling¶ Because the `SequenceWriter` cannot natively distinguish which specific topic failed within your injection script or custom processing code (such as a coordinate transformations), an unhandled exception will bubble up and trigger the global sequence-level error policy. To avoid this, you should catch errors locally for each topic. It is highly recommended to wrap the topic-specific processing and pushing logic within a local `try-except` block, if a single failure is accepted and the entire sequence can still be accepted with partial data on failing topics. As an example, see the How-Tos Upcoming versions of the SDK will introduce native **Topic-Level Error Policies**, which will allow the user to define the error behavior directly when creating the topic, removing the need for boilerplate `try-except` blocks around every sensor stream. --- The **Reading Workflow** in Mosaico is architected to separate resource discovery from high-volume data transmission. This is achieved through two distinct layers: **Handlers**, which serve as metadata proxies, and **Streamers**, which act as the high-performance data engines. ### Handlers: The Catalog Layer¶ Handlers are lightweight objects that represent a server-side resource. Their primary role is to provide immediate access to system information and user-defined metadata **without downloading the actual sensor data**. They act as the "Catalog" layer of the SDK, allowing you to inspect the contents of the platform before committing to a high-bandwidth data stream. Mosaico provides two specialized handler types: `SequenceHandler` and `TopicHandler`. #### `SequenceHandler`¶ API Reference: `mosaicolabs.handlers.SequenceHandler`. Represents a complete recording session. It provides a holistic view, allowing you to inspect all available topic names, global sequence metadata, and the overall temporal bounds (earliest and latest timestamps) of the session. This example demonstrates how to use a Sequence handler to inspect metadata. ``` import sys from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: print(f"Sequence: {seq_handler.name}") print(f"\t| Topics: {seq_handler.topics}") print(f"\t| User metadata: {seq_handler.user_metadata}") print(f"\t| Timestamp span: {seq_handler.timestamp_ns_min} - {seq_handler.timestamp_ns_max}") print(f"\t| Created {seq_handler.sequence_info.created_datetime}") print(f"\t| Size (MB) {seq_handler.sequence_info.total_size_bytes/(1024*1024)}") # Once done, close the reading channel (recommended) seq_handler.close() ``` #### `TopicHandler`¶ API Reference: `mosaicolabs.handlers.TopicHandler`. Represents a specific data channel within a sequence (e.g., a single IMU or Camera). It provides granular system info, such as the specific ontology model used and the data volume of that individual stream. This example demonstrates how to use a Topic handler to inspect metadata. ``` import sys from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog top_handler = client.topic_handler("mission_alpha", "/front/imu") # Note that the same handler can be retrieve via the SequenceHandler of the parent sequence: # seq_handler = client.sequence_handler("mission_alpha") # top_handler = seq_handler.get_topic_handler("/front/imu") if top_handler: print(f"Sequence:Topic: {top_handler.sequence_name}:{top_handler.name}") print(f"\t| User metadata: {top_handler.user_metadata}") print(f"\t| Timestamp span: {top_handler.timestamp_ns_min} - {top_handler.timestamp_ns_max}") print(f"\t| Created {top_handler.topic_info.created_datetime}") print(f"\t| Size (MB) {top_handler.topic_info.total_size_bytes/(1024*1024)}") # Once done, close the reading channel (recommended) top_handler.close() ``` ### Streamers: The Data Engines¶ Both handlers serve as **factories**; once you have identified the resource you need, the handler is used to spawn the appropriate Streamer to begin data consumption. Streamers are the active components that manage the physical data exchange between the server and your application. They handle the complexities of network buffering, batch management, and the de-serialization of raw bytes into Mosaico `Message` objects. #### `SequenceDataStreamer` (Unified Replay)¶ API Reference: `mosaicolabs.handlers.SequenceDataStreamer`. The **`SequenceDataStreamer`** is a unified engine designed specifically for sensor fusion and full-system replay. It allows you to consume multiple data streams as if they were a single, coherent timeline. To achieve this, the streamer employs the following technical mechanisms: * **K-Way Merge Sorting**: The streamer monitors the timestamps across all requested topics simultaneously. On every iteration, it "peeks" at the next available message from each topic and yields the one with the lowest timestamp. * **Strict Chronological Order**: This sorting ensures that messages are delivered in exact acquisition order, effectively normalizing topics that may operate at vastly different frequencies (e.g., high-rate IMU vs. low-rate GPS). * **Temporal Slicing**: You can request a "windowed" extraction by specifying `start_timestamp_ns` and `end_timestamp_ns`. This is highly efficient as it avoids downloading the entire sequence, focusing only on the specific event or time range of interest. * **Smart Buffering**: To maintain memory efficiency, the streamer retrieves data in memory-limited batches. As you iterate, processed batches are discarded and replaced with new data from the server, allowing you to stream sequences that exceed your available RAM. This example demonstrates how to initiate and use the Sequence data stream. ``` import sys from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Start a Unified Stream (K-Way Merge) for multi-sensor replay # We only want GPS and IMU data for this synchronized analysis streamer = seq_handler.get_data_streamer( topics=["/gps", "/imu"], # Optionally filter topics # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Check the start message timestamp print(f"Recording starts at: {streamer.next_timestamp()}") for topic, msg in streamer: # Processes GPS and IMU in perfect chronological order print(f"[{topic}] at {msg.timestamp_ns}: {type(msg.data).__name__}") # Once done, close the reading channel (recommended) seq_handler.close() ``` #### `TopicDataStreamer` (Targeted Access)¶ API Reference: `mosaicolabs.handlers.TopicDataStreamer`. The **`TopicDataStreamer`** provides a dedicated, high-throughput channel for interacting with a single data resource. By bypassing the complex synchronization logic required for merging multiple topics, it offers the lowest possible overhead for tasks requiring isolated data streams, such as training models on specific camera frames or IMU logs. To ensure efficiency, the streamer supports the following features: * **Temporal Slicing**: Much like the `SequenceDataStreamer`, you can extract data in a time-windowed fashion by specifying `start_timestamp_ns` and `end_timestamp_ns`. This ensures that only the relevant portion of the stream is retrieved rather than the entire dataset. * **Smart Buffering**: Data is not downloaded all at once; instead, the SDK retrieves information in memory-limited batches, substituting old data with new batches as you iterate to maintain a constant, minimal memory footprint. This example demonstrates how to initiate and use the Topic data stream. ``` import sys from mosaicolabs import MosaicoClient, IMU with MosaicoClient.connect("localhost", 6726) as client: # Retrieve the topic handler using (e.g.) MosaicoClient top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: # Start a Targeted Stream for single-sensor replay imu_stream = top_handler.get_data_streamer( # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time print(f"Recording starts at: {streamer.next_timestamp()}") # Direct, low-overhead loop for imu_msg in imu_stream: process_sample(imu_msg.get_data(IMU)) # Some custom process function # Once done, close the reading channel (recommended) top_handler.close() ``` --- The **Query Module** provides a high-performance, **fluent** interface for discovering and filtering data within the Mosaico Data Platform. It is designed to move beyond simple keyword searches, allowing you to perform deep, semantic queries across metadata, system catalogs, and the physical content of sensor streams. A typical query workflow involves chaining methods within specialized builders to create a unified request that the server executes atomically. In the example below, the code orchestrates a multi-domain search to isolate high-interest data segments. Specifically, it queries for: * **Sequence Discovery**: Finds any recording session whose name contains the string `"test_drive"` **AND** where the custom user metadata indicates an `"environment.visibility"` value strictly less than 50. * **Topic Filtering**: Restricts the search specifically to the data channel named `"/front/camera/image"`. * **Ontology Analysis**: Performs a deep inspection of IMU sensor payloads to identify specific time segments where the **X-axis acceleration exceeds a certain threshold** while simultaneously the **Y-axis acceleration exceeds a certain threshold**. ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, QueryTopic, IMU, MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Perform a unified server-side query across multiple domains: qresponse = client.query( # Filter Sequence-level metadata QuerySequence() .with_name_match("test_drive") # Use convenience method for fuzzy name matching .with_expression( # Use the .Q proxy to filter the `user_metadata` field Sequence.Q.user_metadata["environment.visibility"].lt(50) ), # Search on topics with specific names QueryTopic() .with_name("/front/camera/image"), # Perform deep time-series discovery within sensor payloads QueryOntologyCatalog(include_timestamp_range=True) # Request temporal bounds for matches .with_expression(IMU.Q.acceleration.x.gt(5.0)) # Use the .Q proxy to filter the `acceleration` field .with_expression(IMU.Q.acceleration.y.gt(4.0)), ) # The server returns a QueryResponse grouped by Sequence for structured data management if qresponse is not None: for item in qresponse: # 'item.sequence' contains the name for the matched sequence print(f"Sequence: {item.sequence.name}") # 'item.topics' contains only the topics and time-segments # that satisfied the QueryOntologyCatalog criteria for topic in item.topics: # Access high-precision timestamps for the data segments found start, end = topic.timestamp_range.start, topic.timestamp_range.end print(f" Topic: {topic.name} | Match Window: {start} to {end}") ``` The provided example illustrates the core architecture of the Mosaico Query DSL. To effectively use this module, it is important to understand the two primary mechanisms that drive data discovery: * **Query Builders (Fluent Logic Collectors)**: Specialized builders like `QuerySequence`, `QueryTopic`, and `QueryOntologyCatalog` serve as containers for your search criteria. They provide a **Fluent Interface** where you can chain two types of methods: + **Convenience Methods**: High-level helpers for common fields, such as `with_name()`, `with_name_match()`, or `with_created_timestamp()`. + **Generic `with_expression()`**: A versatile method that accepts any expression obtained via the **`.Q` proxy**, allowing you to define complex filters for nested user metadata or deep sensor payloads. * **The `.Q` Proxy (Dynamic Model Inspection)**: Every `Serializable` model in the Mosaico ontology features a static `.Q` attribute. This proxy dynamically inspects the model's underlying schema to build dot-notated field paths and intercepts attribute access (e.g., `IMU.Q.acceleration.x`). When a terminal method is called—such as `.gt()`, `.lt()`, or `.between()`—it generates a type-safe **Atomic Expression** used by the platform to filter physical sensor data or metadata fields. By combining these mechanisms, the Query Module delivers a robust filtering experience: * **Multi-Domain Orchestration**: Execute searches across Sequence metadata, Topic configurations, and raw Ontology sensor data in a single, atomic request. * **Structured Response Management**: Results are returned in a `QueryResponse` that is automatically grouped by `Sequence`, making it easier to manage multi-sensor datasets. ## Query Execution & The Response Model¶ Queries are executed via the `query()` method exposed by the `MosaicoClient` class. When multiple builders are provided, they are combined with a logical **AND**. | Method | Return | Description | | --- | --- | --- | | `query(*queries, query)` | `Optional[QueryResponse]` | Executes one or more queries against the platform catalogs. The provided queries are joined in AND condition. The method accepts a variable arguments of query builder objects or a pre-constructed `Query` object. | The query execution returns a `QueryResponse` object, which behaves like a standard Python list containing `QueryResponseItem` objects. | Class | Description | | --- | --- | | `QueryResponseItem` | Groups all matches belonging to the same **Sequence**. Contains a `QueryResponseItemSequence` and a list of related `QueryResponseItemTopic`. | | `QueryResponseItemSequence` | Represents a specific **Sequence** where matches were found. It includes the sequence name. | | `QueryResponseItemTopic` | Represents a specific **Topic** where matches were found. It includes the normalized topic path and the optional `timestamp_range` (the first and last occurrence of the condition). | ``` import sys from mosaicolabs import MosaicoClient, QueryOntologyCatalog from mosaicolabs.models.sensors import IMU # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Define a Deep Data Filter using the .Q Query Proxy # We are searching for vertical impact events where acceleration.z > 15.0 m/s^2 impact_qbuilder = QueryOntologyCatalog( IMU.Q.acceleration.z.gt(15.0), # include_timestamp_range returns the precise start/end of the matching event include_timestamp_range=True ) # Execute the query via the client results = client.query(impact_qbuilder) # The same can be obtained by using the Query object # results = client.query( # query = Query( # impact_qbuilder # ) # ) if results is not None: # Parse the structured QueryResponse object # Results are automatically grouped by Sequence for easier data management for item in results: print(f"Sequence: {item.sequence.name}") # Iterate through matching topics within the sequence for topic in item.topics: # Topic names are normalized (sequence prefix is stripped) for direct use print(f" - Match in: {topic.name}") # Extract the temporal bounds of the event if topic.timestamp_range: start = topic.timestamp_range.start end = topic.timestamp_range.end print(f" Occurrence: {start} ns to {end} ns") ``` * **Temporal Windows**: The `timestamp_range` provides the first and last occurrence of the queried condition within a topic, allowing you to slice data accurately for further analysis. * **Result Normalization**: `topic.name` returns the relative topic path (e.g., `/sensors/imu`), making it immediately compatible with other SDK methods like `topic_handler()`. ### Restricted Queries (Chaining)¶ The `QueryResponse` class enables a powerful mechanism for **iterative search refinement** by allowing you to convert your current results back into a new query builder. This approach is essential for resolving complex, multi-modal dependencies where a single monolithic query would be logically ambiguous, inefficient or technically impossible. | Method | Return Type | Description | | --- | --- | --- | | `to_query_sequence()` | `QuerySequence` | Returns a query builder pre-filtered to include only the **sequences** present in the response. | | `to_query_topic()` | `QueryTopic` | Returns a query builder pre-filtered to include only the specific **topics** identified in the response. | When you invoke these factory methods, the SDK generates a new query expression containing an explicit `$in` filter populated with the identifiers held in the current response. This effectively **"locks" the search domain**, allowing you to apply new criteria to a restricted subset of your data without re-scanning the entire platform catalog. ``` from mosaicolabs import MosaicoClient, QueryTopic, QueryOntologyCatalog, GPS, String with MosaicoClient.connect("localhost", 6726) as client: # Broad Search: Find all sequences where a GPS sensor reached a high-precision state (status=2) initial_response = client.query( QueryOntologyCatalog(GPS.Q.status.status.eq(2)) ) # 'initial_response' now acts as a filtered container of matching sequences. # Domain Locking: Restrict the search scope to the results of the initial query if not initial_response.is_empty(): # .to_query_sequence() generates a QuerySequence pre-filled with the matching sequence names. refined_query_builder = initial_response.to_query_sequence() # Targeted Refinement: Search for error patterns ONLY within the restricted domain # This ensures the platform only scans for '[ERR]' strings within sequences already validated for GPS precision. final_response = client.query( refined_query_builder, # The "locked" sequence domain QueryTopic().with_name("/localization/log_string"), # Target a specific log topic QueryOntologyCatalog(String.Q.data.match("[ERR]")) # Filter by exact data content pattern ) ``` When a specific set of topics has been identified through a data-driven query (e.g., finding every camera topic that recorded a specific event), you can use `to_query_topic()` to "lock" your next search to those specific data channels. This is particularly useful when you need to verify a condition on a very specific subset of sensors across many sequences, bypassing the need to re-identify those topics in the next step. In the next example, we first find all topics of a specific channel from a specific sequence name pattern, and then search specifically within *those* topics for any instances where the data content matches a specific pattern. ``` from mosaicolabs import MosaicoClient, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Broad Search: Find sequences with high-precision GPS initial_response = client.query( QueryTopic().with_name("/localization/log_string"), # Target a specific log topic QuerySequence().with_name_match("test_winter_2025_") # Filter by sequence name pattern ) # Chaining: Use results to "lock" the domain and find specific log-patterns in those sequences if not initial_response.is_empty(): final_response = client.query( initial_response.to_query_topic(), # The "locked" topic domain QueryOntologyCatalog(String.Q.data.match("[ERR]")) # Filter by content ) ``` #### When Chaining is Necessary¶ The previous example of the `GPS.status` query and the subsequent `/localization/log_string` topic search highlight exactly when *query chaining* becomes a technical necessity rather than just a recommendation. In the Mosaico Data Platform, a single `client.query()` call applies a logical **AND** across all provided builders to locate individual **data streams (topics)** that satisfy every condition simultaneously. Because a single topic cannot physically represent two different sensor types at once, such as being both a `GPS` sensor and a `String` log, a monolithic query attempting to filter for both on the same stream will inherently return zero results. Chaining resolves this by allowing you to find the correct **Sequence** context in step one, then "locking" that domain to find a different **Topic** within that same context in step two. ``` # AMBIGUOUS: This looks for ONE topic that is BOTH GPS and String response = client.query( QueryOntologyCatalog(GPS.Q.status.status.eq(DGPS_FIX)), QueryOntologyCatalog(String.Q.data.match("[ERR]")), QueryTopic().with_name("/localization/log_string") ) ``` ## Architecture¶ ### Query Layers¶ Mosaico organizes data into three distinct architectural layers, each with its own specialized Query Builder: #### `QuerySequence` (Sequence Layer)¶ API Reference: `mosaicolabs.models.query.builders.QuerySequence`. Filters recordings based on high-level session metadata, such as the sequence name or the time it was created. **Example** Querying for sequences by name and creation date ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Search for sequences by project name and creation date qresponse = client.query( QuerySequence() .with_name_match("test_drive") .with_expression(Sequence.Q.user_metadata["project"].eq("Apollo")) .with_created_timestamp(time_start=Time.from_float(1690000000.0)) ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### `QueryTopic` (Topic Layer)¶ API Reference: `mosaicolabs.models.query.builders.QueryTopic`. Targets specific data channels within a sequence. You can search for topics by name pattern or by their specific Ontology type (e.g., "Find all GPS topics"). **Example** Querying for image topics by ontology tag, metadata key and topic creation timestamp ``` from mosaicolabs import MosaicoClient, Image, Topic, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Query for all 'image' topics created in a specific timeframe, matching some metadata (key, value) pair qresponse = client.query( QueryTopic() .with_ontology_tag(Image.ontology_tag()) .with_created_timestamp(time_start=Time.from_float(1700000000)) .with_expression(Topic.Q.user_metadata["camera_id.serial_number"].eq("ABC123_XYZ")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### `QueryOntologyCatalog` (Ontology Catalog Layer)¶ API Reference: `mosaicolabs.models.query.builders.QueryOntologyCatalog`. Filters based on the **actual time-series content** of the sensors (e.g., "Find events where `acceleration.z` exceeded a specific value"). **Example** Querying for mixed sensor data ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPS, IMU with MosaicoClient.connect("localhost", 6726) as client: # Chain multiple sensor filters together qresponse = client.query( QueryOntologyCatalog() .with_expression(GPS.Q.status.satellites.geq(8)) .with_expression(Temperature.Q.value.between([273.15, 373.15])) .with_expression(Pressure.Q.value.geq(100000)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(include_timestamp_range=True) .with_expression(IMU.Q.acceleration.x.lt(-4.0)) .with_expression(IMU.Q.acceleration.y.gt(5.0)) .with_expression(Pose.Q.rotation.z.geq(0.707)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` The Mosaico Query Module offers two distinct paths for defining filters, **Convenience Methods** and **Generic Expression Method**, both of which support **method chaining** to compose multiple criteria into a single query using a logical **AND**. #### Convenience Methods¶ The query layers provide high-level fluent helpers (`with_`), built directly into the query builder classes and designed for ease of use. They allow you to filter data without deep knowledge of the internal model schema. The builder automatically selects the appropriate field and operator (such as exact match vs. substring pattern) based on the method used. ``` from mosaicolabs import QuerySequence, QueryTopic, RobotJoint # Build a filter with name pattern qbuilder = QuerySequence() .with_name_match("test_drive") # Execute the query qresponse = client.query(qbuilder) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Build a filter with ontology tag AND a specific creation time window qbuilder = QueryTopic() .with_ontology_tag(RobotJoint.ontology_tag()) .with_created_timestamp(start=t1, end=t2) # Execute the query qresponse = client.query(qbuilder) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` * **Best For**: Standard system-level fields like Names and Timestamps. #### Generic Expression Method¶ The `with_expression()` method accepts raw **Query Expressions** generated through the `.Q` proxy. This provides full access to every supported operator (`.gt()`, `.lt()`, `.between()`, etc.) for specific fields. ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, IMU # Build a filter with name pattern and metadata-related expression qbuilder = QuerySequence() .with_expression( # Use query proxy for generating a QueryExpression Sequence.Q.user_metadata['environment.visibility'].lt(50) ) # Can be AND-chained with convenience methods .with_name_match("test_drive") # Execute the query qresponse = client.query(qbuilder) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Build a filter with deep time-series data discovery and measurement time windowing qbuilder = QueryOntologyCatalog() .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.header.stamp.sec.gt(1700134567)) .with_expression(IMU.Q.header.stamp.nanosec.between([123456, 789123])) # Execute the query qresponse = client.query(qbuilder) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` * **Best For**: Accessing specific Ontology data fields (e.g., acceleration, position, etc.) and custom `user_metadata` in `Sequence` and `Topic` data models. ### The `.Q` Proxy Mechanism¶ The Query Proxy is the cornerstone of Mosaico's type-safe data discovery. Every data model in the Mosaico Ontology (e.g., `IMU`, `GPS`, `Image`) is automatically injected with a static `.Q` attribute during class initialization. This mechanism transforms static data structures into dynamic, fluent interfaces for constructing complex filters. The proxy follows a three-step lifecycle to ensure that your queries are both semantically correct and high-performance: 1. **Intelligent Mapping**: During system initialization, the proxy inspects the sensor's schema recursively. It maps every nested field path (e.g., `"acceleration.x"`) to a dedicated *queryable* object, i.e. an object providing comparison operators and expression generation methods. 2. **Type-Aware Operators**: The proxy identifies the data type of each field (numeric, string, dictionary, or boolean) and exposes only the operators valid for that type. This prevents logical errors, such as attempting a substring `.match()` on a numeric acceleration value. 3. **Intent Generation**: When you invoke an operator (e.g., `.gt(15.0)`), the proxy generates a `QueryExpression`. This object encapsulates your search intent and is serialized into an optimized JSON format for the platform to execute. To understand how the proxy handles nested structures, inherited attributes, and data types, consider the `IMU` ontology class: ``` class IMU(Serializable, HeaderMixin): acceleration: Vector3d # Composed type: contains x, y, z angular_velocity: Vector3d # Composed type: contains x, y, z orientation: Optional[Quaternion] = None # Composed type: contains x, y, z, w ``` The `.Q` proxy enables you to navigate the data exactly as it is defined in the model. By following the `IMU.Q` instruction, you can drill down through nested fields and inherited mixins using standard dot notation until you reach a base queryable type. The proxy automatically flattens the hierarchy, including fields inherited from `HeaderMixin` (like `frame_id` and `stamp`), assigning the correct queryable type and operators to each leaf node: (API Reference: `mosaicolabs.models.sensors.IMU`) | Proxy Field Path | Queryable Type | Supported Operators (Examples) | | --- | --- | --- | | **`IMU.Q.acceleration.x/y/z`** | **Numeric** | `.gt()`, `.lt()`, `.geq()`, `.leq()`, `.eq()`, `.between()`, `.in_()` | | **`IMU.Q.angular_velocity.x/y/z`** | **Numeric** | `.gt()`, `.lt()`, `.geq()`, `.leq()`, `.eq()`, `.between()`, `.in_()` | | **`IMU.Q.orientation.x/y/z/w`** | **Numeric** | `.gt()`, `.lt()`, `.geq()`, `.leq()`, `.eq()`, `.between()`, `.in_()` | | **`IMU.Q.header.frame_id`** | **String** | `.eq()`, `.match()` | | **`IMU.Q.header.stamp.sec`** | **Numeric** | `.gt()`, `.lt()`, `.geq()`, `.leq()`, `.eq()`, `.between()`, `.in_()` | | **`IMU.Q.header.stamp.nanosec`** | **Numeric** | `.gt()`, `.lt()`, `.geq()`, `.leq()`, `.eq()`, `.between()`, `.in_()` | The following table lists the supported operators for each data type: | Data Type | Operators | | --- | --- | | **Numeric** | `.eq()`, `.neq()`, `.lt()`, `.leq()`, `.gt()`, `.geq()`, `.between()`, `.in_()` | | **String** | `.eq()`, `.neq()`, `.match()` (i.e. substring), `.in_()` | | **Boolean** | `.eq(True/False)` | | **Dictionary** | `.eq()`, `.neq()`, `.lt()`, `.leq()`, `.gt()`, `.geq()`, `.between()`, `.in_()`, `.match()` | #### Supported vs. Unsupported Types¶ While the `.Q` proxy is highly versatile, it enforces specific rules on which data structures can be queried: * **Supported Types**: The proxy resolves all simple (int, float, str, bool) or composed types (like `Vector3d` or `Quaternion`). It will continue to expose nested fields as long as they lead to a primitive base type. * **Dictionaries**: Dynamic fields, such as the `user_metadata` found in the **`Topic`** and **`Sequence`** platform models, are fully queryable through the proxy using bracket notation (e.g., `Topic.Q.user_metadata["key"]` or `Topic.Q.user_metadata["key.subkey.subsubkey"]`). This approach provides the flexibility to search across custom tags and dynamic properties that aren't part of a fixed schema. This dictionary-based querying logic is not restricted to platform models; it applies to any **custom ontology model** created by the user that contains a `dict` field. + **Syntax**: Instead of the standard dot notation used for fixed fields, you must use square brackets `["key"]` to target specific dictionary entries. + **Nested Access**: For dictionaries containing nested structures, you can use **dot notation within the key string** (e.g., `["environment.visibility"]`) to traverse sub-fields. + **Operator Support**: Because dictionary values are dynamic, these fields are "promiscuous," meaning they support all available numeric, string, and boolean operators without strict SDK-level type checking. * **Unsupported Types (Lists and Tuples)**: Any field defined as a container, such as a **List** or **Tuple** (e.g., `covariance: List[float]`), is currently skipped by the proxy generator. These fields will not appear in autocomplete and cannot be used in a query expression. ## Constraints & Limitations¶ While fully functional, the current implementation (v0.x) has a **Single Occurrence Constraint**. * **Constraint**: A specific data field path may appear **only once** within a single query builder instance. You cannot chain two separate conditions on the same field (e.g., `.gt(0.5)` and `.lt(1.0)`). ``` # INVALID: The same field (acceleration.x) is used twice in the constructor QueryOntologyCatalog() \ .with_expression(IMU.Q.acceleration.x.gt(0.5)) .with_expression(IMU.Q.acceleration.x.lt(1.0)) # <- Error! Duplicate field path ``` * **Solution**: Use the built-in **`.between([min, max])`** operator to perform range filtering on a single field path. * **Note**: You can still query multiple *different* fields from the same sensor model (e.g., `acceleration.x` and `acceleration.y`) in one builder. ``` # VALID: Each expression targets a unique field path QueryOntologyCatalog( IMU.Q.acceleration.x.gt(0.5), # Unique field IMU.Q.acceleration.y.lt(1.0), # Unique field IMU.Q.angular_velocity.x.between([0, 1]), # Correct way to do ranges include_timestamp_range=True ) ``` --- The **Mosaico ML** module serves as the high-performance bridge between the Mosaico Data Platform and the modern Data Science ecosystem. While the platform is optimized for high-speed raw message streaming, this module provides the abstractions necessary to transform asynchronous sensor data into tabular formats compatible with **Physical AI**, **Deep Learning**, and **Predictive Analytics**. Working with robotics and multi-modal datasets presents three primary technical hurdles that the ML module is designed to solve: * **Heterogeneous Sampling**: Sensors like LIDAR (low frequency), IMU (high frequency), and GPS (intermittent) operate at different rates. * **High Volume**: Datasets often exceed the available system RAM. * **Nested Structures**: Robotics data is typically deeply nested with coordinate transformations and covariance matrices. ## From Sequences to DataFrames¶ API Reference: `mosaicolabs.ml.DataFrameExtractor` The `DataFrameExtractor` is a specialized utility designed to convert Mosaico sequences into tabular formats. Unlike standard streamers that instantiate individual Python objects, this extractor operates at the **Batch Level** by pulling raw `RecordBatch` objects directly from the underlying stream to maximize throughput. ### Key Technical Features¶ * **Recursive Flattening**: Automatically "unpacks" deeply nested Mosaico Ontology structures into primitive columns. * **Semantic Naming**: Columns use a `{topic_name}.{ontology_tag}.{field_path}` convention (e.g., `/front/camera/imu.imu.acceleration.x`) to remain self-describing. * **Namespace Isolation**: Topic names are included in column headers to prevent collisions when multiple sensors of the same type are present. * **Memory-Efficient Windowing**: Uses a generator-based approach to yield data in time-based "chunks" (e.g., 5-second windows) while handling straddling batches via a carry-over buffer. * **Sparse Merging**: Creates a "sparse" DataFrame containing the union of all timestamps, using `NaN` for missing sensor readings at specific intervals. This example demonstrates iterating through a sequence in 10-second tabular chunks. ``` from mosaicolabs import MosaicoClient from mosaicolabs.ml import DataFrameExtractor with MosaicoClient.connect("localhost", 6726): # Initialize from an existing SequenceHandler seq_handler = client.sequence_handler("drive_session_01") extractor = DataFrameExtractor(seq_handler) # Iterate through 10-second chunks for df in extractor.to_pandas_chunks(window_sec=10.0): # 'df' is a pandas DataFrame with semantic columns # Example: df["/front/camera/imu.imu.acceleration.x"] print(f"Processing chunk with {len(df)} rows") ``` For complex types like images that require specialized decoding, Mosaico allows you to "inflate" a flattened DataFrame row back into a strongly-typed `Message` object. ``` from mosaicolabs import MosaicoClient from mosaicolabs.ml import DataFrameExtractor from mosaicolabs.models import Message, Image with MosaicoClient.connect("localhost", 6726): # Initialize from an existing SequenceHandler seq_handler = client.sequence_handler("drive_session_01") extractor = DataFrameExtractor(seq_handler) # Get data chunks for df in extractor.to_pandas_chunks(topics=["/sensors/front/image_raw"]): for _, row in df.iterrows(): # Reconstruct the full Message (envelope + payload) from a row img_msg = Message.from_dataframe_row( row=row, topic_name="/sensors/front/image_raw", ) if img_msg: img = img_msg.get_data(Image).to_pillow() # Access typed fields with IDE autocompletion print(f"Time: {img_msg.timestamp_ns}") img.show() ``` ## Sparse to Dense Representation¶ API Reference: `mosaicolabs.ml.SyncTransformer` The `SyncTransformer` is a temporal resampler designed to solve the **Heterogeneous Sampling** problem inherent in robotics and Physical AI. It aligns multi-rate sensor streams (for example, an IMU at 100Hz and a GPS at 5Hz) onto a uniform, fixed-frequency grid to prepare them for machine learning models. The `SyncTransformer` operates as a processor that bridges the gaps between windowed chunks yielded by the `DataFrameExtractor`. Unlike standard resamplers that treat each data batch in isolation, this transformer maintains internal state to ensure signal continuity across batch boundaries. ### Key Design Principles¶ * **Stateful Continuity**: It maintains an internal cache of the last known sensor values and the next expected grid tick, allowing signals to bridge the gap between independent DataFrame chunks. * **Semantic Integrity**: It respects the physical reality of data acquisition by yielding `None` for grid ticks that occur before a sensor's first physical measurement, avoiding data "hallucination". * **Vectorized Performance**: Internal kernels leverage high-speed lookups for high-throughput processing. * **Protocol-Based Extensibility**: The mathematical logic for resampling is decoupled through a `SynchPolicy` protocol, allowing for custom kernel injection. ### Implemented Synchronization Policies¶ API Reference: `mosaicolabs.ml.SyncPolicy` Each policy defines a specific logic for how the transformer bridges temporal gaps between sparse data points. #### 1. **`SyncHold`** (Last-Value-Hold)¶ * **Behavior**: Finds the most recent valid measurement and "holds" it constant until a new one arrives. * **Best For**: Sensors where states remain valid until explicitly changed, such as robot joint positions or battery levels. #### 2. **`SyncAsOf`** (Staleness Guard)¶ * **Behavior**: Carries the last known value forward only if it has not exceeded a defined maximum "tolerance" (fresher than a specific age). * **Best For**: High-speed signals that become unreliable if not updated frequently, such as localization coordinates. #### 3. **`SyncDrop`** (Interval Filter)¶ * **Behavior**: Ensures a grid tick only receives a value if a new measurement actually occurred within that specific grid interval; otherwise, it returns `None`. * **Best For**: Downsampling high-frequency data where a strict 1-to-1 relationship between windows and unique hardware events is required. ### Scikit-Learn Compatibility¶ By implementing the standard `fit`/`transform` interface, the `SyncTransformer` makes robotics data a "first-class citizen" of the Scikit-learn ecosystem. This allows for the plug-and-play integration of multi-rate sensor data into standard pipelines. ``` from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from mosaicolabs import MosaicoClient from mosaicolabs.ml import DataFrameExtractor, SyncTransformer, SynchHold # Define a pipeline for physical AI preprocessing pipeline = Pipeline([ ('sync', SyncTransformer(target_fps=30.0, policy=SynchHold())), ('scaler', StandardScaler()) ]) with MosaicoClient.connect("localhost", 6726): # Initialize from an existing SequenceHandler seq_handler = client.sequence_handler("drive_session_01") extractor = DataFrameExtractor(seq_handler) # Process sequential chunks while maintaining signal continuity for sparse_chunk in extractor.to_pandas_chunks(window_sec=5.0): # The transformer automatically carries state across sequential calls normalized_dense_chunk = pipeline.transform(sparse_chunk) ``` --- The **ROS Bridge** module serves as the ingestion gateway for ROS (Robot Operating System) data into the Mosaico Data Platform. Its primary function is to solve the interoperability challenges associated with ROS bag files—specifically format fragmentation (ROS 1 `.bag` vs. ROS 2 `.mcap`/`.db3`) and the lack of strict schema enforcement in custom message definitions. The core philosophy of the module is **"Adaptation, Not Just Parsing."** Rather than simply extracting raw dictionaries from ROS messages, the bridge actively translates them into the standardized **Mosaico Ontology**. For example, a `geometry_msgs/Pose` is validated, normalized, and instantiated as a strongly-typed `mosaicolabs.models.data.Pose` object before ingestion. ## Architecture¶ The module is composed of four distinct layers that handle the pipeline from raw file access to server transmission. ### The Loader Layer (`ROSLoader`)¶ The `ROSLoader` acts as the abstraction layer over the physical bag files. It utilizes the `rosbags` library to provide a unified interface for reading both ROS 1 and ROS 2 formats (`.bag`, `.db3`, `.mcap`). * **Responsibilities:** File I/O, raw deserialization, and topic filtering (supporting glob patterns like `/cam/*`). * **Error Handling:** It implements configurable policies (`IGNORE`, `LOG_WARN`, `RAISE`) to handle corrupted messages or deserialization failures without crashing the entire pipeline. ### The Adaptation Layer (`ROSBridge` & Adapters)¶ This layer represents the semantic core of the module, translating raw ROS data into the Mosaico Ontology. * **`ROSAdapterBase`:** An abstract base class that establishes the contract for converting specific ROS message types into their corresponding Mosaico Ontology types. * **Concrete Adapters:** The library provides built-in implementations for common standards, such as `IMUAdapter` (mapping `sensor_msgs/Imu` to `IMU`) and `ImageAdapter` (mapping `sensor_msgs/Image` to `Image`). These adapters include advanced logic for recursive unwrapping, automatically extracting data from complex nested wrappers like `PoseWithCovarianceStamped`. Developers can also implement custom adapters to handle non-standard or proprietary types. * **`ROSBridge`:** A central registry and dispatch mechanism that maps ROS message type strings (e.g., `sensor_msgs/msg/Imu`) to their corresponding adapter classes, ensuring the correct translation logic is applied for each message. #### Extending the Bridge (Custom Adapters)¶ Users can extend the bridge to support new ROS message types by implementing a custom adapter and registering it. 1. **Inherit from `ROSAdapterBase`**: Define the input ROS type string and the target Mosaico Ontology type. 2. **Implement `from_dict`**: Define the logic to convert the `ROSMessage.data` dictionary into an intance of the target ontology object. 3. **Register**: Decorate the class with `@register_adapter`. ``` from mosaicolabs.ros_bridge import ROSAdapterBase, register_adapter, ROSMessage from mosaicolabs.models import Message from my_ontology import MyCustomData # Assuming this class exists @register_adapter class MyCustomAdapter(ROSAdapterBase[MyCustomData]): ros_msgtype = "my_pkg/msg/MyCustomType" __mosaico_ontology_type__ = MyCustomData @classmethod def from_dict(cls, ros_data: dict) -> MyCustomData: # Transformation logic here return MyCustomData(...) ``` ### The Orchestrator (`RosbagInjector`)¶ The **`RosbagInjector`** is the central command center of the ROS Bridge module. It is designed to be the primary entry point for developers who want to embed high-performance ROS ingestion directly into their Python applications or automation scripts. The injector acts as a "glue" layer, orchestrating the interaction between the **`ROSLoader`** (file access), the **`ROSBridge`** (data adaptation), and the **`MosaicoClient`** (network transmission). It handles the complex lifecycle of a data upload—including connection management, batching, and transaction safety—while providing real-time feedback through a visual CLI interface. #### Core Workflow Execution: `run()`¶ The `run()` method is the heart of the injector. When called, it initiates a multi-phase pipeline: 1. **Handshake & Registry**: Establishes a connection to the Mosaico server and registers any provided custom `.msg` definitions into the global `ROSTypeRegistry`. 2. **Sequence Creation**: Requests the server to initialize a new data sequence based on the provided name and metadata. 3. **Adaptive Streaming**: Iterates through the ROS bag records. For each message, it identifies the correct adapter, translates the ROS dictionary into a Mosaico object, and pushes it into an optimized asynchronous write buffer. 4. **Transaction Finalization**: Once the bag is exhausted, it flushes all remaining buffers and signals the server to commit the sequence. #### The Blueprint: `ROSInjectionConfig`¶ The behavior of the injector is entirely driven by the **`ROSInjectionConfig`**. This configuration object ensures that the ingestion logic is decoupled from the user interface, allowing for consistent behavior whether triggered via the CLI or a complex script. | Attribute | Type | Description | | --- | --- | --- | | **`file_path`** | `Path` | The location of the source ROS bag (`.mcap`, `.db3`, or `.bag`). | | **`sequence_name`** | `str` | The unique identifier for the sequence on the server. | | **`metadata`** | `dict` | Searchable tags and context (e.g., `{"weather": "rainy"}`) attached to the sequence. | | **`ros_distro`** | `Stores` | **Crucial for `.db3` bags:** Specifies the ROS distribution (e.g., `ROS2_HUMBLE`) to ensure standard messages are parsed with the correct schema version. | | **`topics`** | `List[str]` | A filter list supporting glob patterns (e.g., `["/camera/*"]`). If omitted, all supported topics are ingested. | | **`custom_msgs`** | `List` | A list of tuples `(package, path, store)` used to dynamically register proprietary message definitions at runtime. | | **`on_error`** | `OnErrorPolicy` | **Safety Switch:** Determines if a failed upload should `Delete` the partial sequence or `Report` the error and keep the data. | | **`log_level`** | `str` | Controls terminal verbosity, ranging from `DEBUG` to `ERROR`. | #### Practical Example: Programmatic Usage¶ ``` from pathlib import Path from mosaicolabs.ros_bridge import RosbagInjector, ROSInjectionConfig, Stores def run_injection(): # Define the Injection Configuration # This data class acts as the single source for the operation. config = ROSInjectionConfig( # Input Data file_path=Path("data/session_01.db3"), # Target Platform Metadata sequence_name="test_ros_sequence", metadata={ "driver_version": "v2.1", "weather": "sunny", "location": "test_track_A" }, # Topic Filtering (supports glob patterns) # This will only upload topics starting with '/cam' topics=["/cam*"], # ROS Configuration # Specifying the distro ensures correct parsing of standard messages # (.db3 sqlite3 rosbags need the specification of distro) ros_distro=Stores.ROS2_HUMBLE, # Custom Message Registration # Register proprietary messages before loading to prevent errors custom_msgs=[ ( "my_custom_pkg", # ROS Package Name Path("./definitions/my_pkg/"), # Path to directory containing .msg files Stores.ROS2_HUMBLE, # Scope (valid for this distro) ) # registry will automatically infer type names as `my_custom_pkg/msg/{filename}` ], # Execution Settings log_level="WARNING", # Reduce verbosity for automated scripts ) # Instantiate the Controller injector = RosbagInjector(config) # Execute # The run method handles connection, loading, and uploading automatically. # It raises exceptions for fatal errors, allowing you to wrap it in try/except blocks. try: injector.run() print("Injection job completed successfully.") except Exception as e: print(f"Injection job failed: {e}") # Use as script or call the injection function in your code if __name__ == "__main__": run_injection() ``` #### CLI Usage¶ The module includes a command-line interface for quick ingestion tasks. The full list of options can be retrieved by running `mosaico.ros_injector -h` ``` # Basic Usage poetry run mosaico.ros_injector ./data.mcap --name "Test_Run_01" # Advanced Usage: Filtering topics and adding metadata poetry run mosaico.ros_injector ./data.db3 \ --name "Test_Run_01" \ --topics /camera/front/* /gps/fix \ --metadata ./metadata.json \ --ros-distro ros2_humble ``` ### The Type Registry (`ROSTypeRegistry`)¶ The **`ROSTypeRegistry`** is a context-aware singleton designed to manage the schemas required to decode ROS data. ROS message definitions are frequently external to the data files themselves—this is especially true for ROS 2 `.db3` (SQLite) formats and proprietary datasets containing custom sensors. Without these definitions, the bridge cannot deserialize the raw binary "blobs" into readable dictionaries. * **Schema Resolution**: It allows the `ROSLoader` to resolve custom `.msg` definitions on-the-fly during bag playback. * **Version Isolation (Stores)**: ROS messages often vary across distributions (e.g., a "Header" in ROS 1 Noetic is structurally different from ROS 2 Humble). The registry uses a "Profile" system to store these version-specific definitions separately, preventing cross-distribution conflicts. * **Global vs. Scoped Definitions**: You can register definitions **Globally** (available to all loaders) or **Scoped** to a specific distribution. #### Pre-loading Definitions¶ While you can pass custom messages via `ROSInjectionConfig`, it can become cumbersome for large-scale projects with hundreds of proprietary types. The recommended approach is to pre-load the registry at the start of your application. This makes the definitions available to all subsequent loaders automatically. | Method | Scope | Description | | --- | --- | --- | | **`register(...)`** | Single Message | Registers a single custom type. The source can be a path to a `.msg` file or a raw string containing the definition. | | **`register_directory(...)`** | Batch Package | Scans a directory for all `.msg` files and registers them under a specific package name (e.g., `my_pkg/msg/Sensor`). | | **`get_types(...)`** | Internal | Implements a "Cascade" logic: merges Global definitions with distribution-specific overrides for a loader. | | **`reset()`** | Utility | Clears all stored definitions. Primarily used for unit testing to ensure process isolation. | #### Centralized Registration Example¶ A clean way to manage large projects is to centralize your message registration in a single setup function (e.g., `setup_registry.py`): ``` from pathlib import Path from mosaicolabs.ros_bridge import ROSTypeRegistry, Stores def initialize_project_schemas(): # 1. Register a proprietary message valid for all ROS versions ROSTypeRegistry.register( msg_type="common_msgs/msg/SystemHeartbeat", source=Path("./definitions/Heartbeat.msg") ) # 2. Batch register an entire package for ROS 2 Humble ROSTypeRegistry.register_directory( package_name="robot_v3_msgs", dir_path=Path("./definitions/robot_v3/msgs"), store=Stores.ROS2_HUMBLE ) ``` Once registered, the `RosbagInjector` (and the underlying `ROSLoader`) automatically detects and uses these definitions. There is no longer the need to pass the `custom_msgs` list in the `ROSInjectionConfig`. ``` # main_injection.py import setup_registry # Runs the registration logic above from mosaicolabs.ros_bridge import RosbagInjector, ROSInjectionConfig, Stores from pathlib import Path # Initialize registry setup_registry.initialize_project_schemas() # Configure injection WITHOUT listing custom messages again config = ROSInjectionConfig( file_path=Path("mission_data.mcap"), sequence_name="mission_01", metadata={"operator": "Alice"}, ros_distro=Stores.ROS2_HUMBLE, # Loader will pull the Humble-specific types we registered # custom_msgs=[] <-- No longer needed! ) injector = RosbagInjector(config) injector.run() ``` ### Testing & Validation¶ The ROS Bag Injection module has been validated against a variety of standard datasets to ensure compatibility with different ROS distributions, message serialization formats (CDR/ROS 1), and bag container formats (`.bag`, `.mcap`, `.db3`). #### Recommended Dataset for Verification¶ For evaluating Mosaico capabilities, we recommend the **NVIDIA NGC Catalog - R2B Dataset 2024**. This dataset has been verified to be fully compatible with the injection pipeline. The following table details the injection performance for the **NVIDIA R2B Dataset 2024**. These benchmarks were captured on a system running **macOS 26.2** with an **Apple M2 Pro (10 cores, 16GB RAM)**. #### NVIDIA R2B Dataset 2024 Injection Performance¶ | Sequence Name | Compression Factor | Injection Time | Hardware Architecture | Notes | | --- | --- | --- | --- | --- | | **`r2b_galileo2`** | ~70% | ~40 sec | Apple M2 Pro (16GB) | High compression achieved for telemetry data. | | **`r2b_galileo`** | ~1% | ~30 sec | Apple M2 Pro (16GB) | Low compression due to pre-compressed source images. | | **`r2b_robotarm`** | ~66% | ~50 sec | Apple M2 Pro (16GB) | High efficiency for high-frequency state updates. | | **`r2b_whitetunnel`** | ~1% | ~30 sec | Apple M2 Pro (16GB) | Low compression; contains topics with no available adapter. | #### Understanding Performance Factors¶ * **Compression Factors**: Sequences like `r2b_galileo2` achieve high ratios (~70%) because Mosaico optimizes the underlying columnar storage for scalar telemetry. Conversely, sequences with pre-compressed video feeds show minimal gains (~1%) because the data is already in a dense format. * **Injection Time**: This metric includes the overhead of local MCAP/DB3 deserialization via `ROSLoader`, semantic translation through the `ROSBridge`, and the asynchronous transmission to the Mosaico server. * **Hardware Impact**: On the **Apple M2 Pro**, the `RosbagInjector` utilizes multi-threading for the **Adaptation Layer**, allowing serialization tasks to run in parallel while the main thread manages the Flight stream. #### Known Issues & Limitations¶ While the underlying `rosbags` library supports the majority of standard ROS 2 bag files, specific datasets with non-standard serialization alignment or proprietary encodings may encounter compatibility issues. **NVIDIA Isaac ROS Benchmark Dataset (2023)** * **Source:** NVIDIA NGC Catalog - R2B Dataset 2023 * **Issue:** Deserialization failure during ingestion. * **Technical Details:** The ingestion process fails within the `AnyReader.deserialize` method of the `rosbags` library. The internal CDR deserializer triggers an assertion error indicating a mismatch in the expected data length vs. the raw payload size. * **Error Signature:** ``` # In rosbags.serde.cdr: assert pos + 4 + 3 >= len(rawdata) ``` * **Recommendation:** This issue originates in the upstream parser handling of this specific dataset's serialization alignment. It is currently recommended to exclude this dataset or transcode it using standard ROS 2 tools before ingestion. ## Supported Message Types¶ ***ROS-Specific Data Models*** In addition to mapping standard ROS messages to the core Mosaico ontology, the `ros-bridge` module implements two specialized data models. These are defined specifically for this module to handle ROS-native concepts that are not yet part of the official Mosaico standard: * **`FrameTransform`**: Designed to handle coordinate frame transformations (modeled after `tf2_msgs/msg/TFMessage`). It encapsulates a list of `Transform` objects to manage spatial relationships. * **`BatteryState`**: Modeled after `sensor_msgs/msg/BatteryState`), this class captures comprehensive power supply metrics. It includes core data (voltage, current, capacity, percentage) and detailed metadata such as power supply health, technology status, and individual cell readings. > **Note:** Although these are provisional additions, both `FrameTransform` and `BatteryState` inherit from `Serializable` and `HeaderMixin`. This ensures they remain fully compatible with Mosaico’s existing serialization and header management infrastructure. ### Supported Message Types Table¶ | ROS Message Type | Mosaico Ontology Type | Adapter | | --- | --- | --- | | `geometry_msgs/Pose`, `PoseStamped`... | `Pose` | `PoseAdapter` | | `geometry_msgs/Twist`, `TwistStamped`... | `Velocity` | `TwistAdapter` | | `geometry_msgs/Accel`, `AccelStamped`... | `Acceleration` | `AccelAdapter` | | `geometry_msgs/Vector3`, `Vector3Stamped` | `Vector3d` | `Vector3Adapter` | | `geometry_msgs/Point`, `PointStamped` | `Point3d` | `PointAdapter` | | `geometry_msgs/Quaternion`, `QuaternionStamped` | `Quaternion` | `QuaternionAdapter` | | `geometry_msgs/Transform`, `TransformStamped` | `Transform` | `TransformAdapter` | | `geometry_msgs/Wrench`, `WrenchStamped` | `ForceTorque` | `WrenchAdapter` | | `nav_msgs/Odometry` | `MotionState` | `OdometryAdapter` | | `nmea_msgs/Sentence` | `NMEASentence` | `NMEASentenceAdapter` | | `sensor_msgs/Image`, `CompressedImage` | `Image`, `CompressedImage` | `ImageAdapter`, `CompressedImageAdapter` | | `sensor_msgs/Imu` | `IMU` | `IMUAdapter` | | `sensor_msgs/NavSatFix` | `GPS`, `GPSStatus` | `GPSAdapter`, `NavSatStatusAdapter` | | `sensor_msgs/CameraInfo` | `CameraInfo` | `CameraInfoAdapter` | | `sensor_msgs/RegionOfInterest` | `ROI` | `ROIAdapter` | | `sensor_msgs/JointState` | `RobotJoint` | `RobotJointAdapter` | | `sensor_msgs/BatteryState` | `BatteryState` (ROS-specific) | `BatteryStateAdapter` | | `std_msgs/msg/String` | `String` | `_GenericStdAdapter` | | `std_msgs/msg/Int8(16,32,64)` | `Integer8(16,32,64)` | `_GenericStdAdapter` | | `std_msgs/msg/UInt8(16,32,64)` | `Unsigned8(16,32,64)` | `_GenericStdAdapter` | | `std_msgs/msg/Float32(64)` | `Floating32(64)` | `_GenericStdAdapter` | | `std_msgs/msg/Bool` | `Boolean` | `_GenericStdAdapter` | | `tf2_msgs/msg/TFMessage` | `FrameTransform` (ROS-specific) | `FrameTransformAdapter` | --- The **Mosaico Daemon**, a.k.a. `mosaicod`, acts as engine of the data platform. Developed in **Rust**, it is engineered to be the high-performance arbiter for all data interactions, guaranteeing that every byte of robotics data is strictly typed, atomically stored, and efficiently retrievable. It functions on a standard client-server model, mediating between your high-level applications (via the SDKs) and the low-level storage infrastructure. ## Architectural Design¶ `mosaicod` is architected atop the Apache Arrow Flight protocol. Apache Arrow Flight is a general-purpose, high-performance client-server framework developed for the exchange of massive datasets. It operates directly on Apache Arrow columnar data, enabling efficient transport over gRPC without the overhead of serialization. Unlike traditional REST APIs which serialize data into text-based JSON, Flight is designed specifically for high-throughput data systems. This architectural choice provides Mosaico with three critical advantages: **Zero-Copy Serialization.** Data is transmitted in the Arrow columnar format, the exact same format used in-memory by modern analytics tools like pandas and Polars. This eliminates the CPU-heavy cost of serializing and deserializing data at every hop. **Parallelized Transport.** Operations are not bound to a single pipe; data transfer can be striped across multiple connections to saturate available bandwidth. **Snapshot-Based Schema Enforcement.** Data types are not guessed, nor are they forced into a rigid global model. Instead, the protocol enforces a rigorous schema handshake that validates data against a specific schema snapshot stored with the sequence. ### Resource Addressing¶ Mosaico treats every entity in the system, whether it's a Sequence or a Topic, as a uniquely addressable resource. These resources are identified by a **Resource Locator**, a uniform logical path that remains consistent across all channels. Mosaico uses two types of resource locators: * A **Sequence Locator** identifies a recording session by its sequence name (e.g., `run_2023_01`). * A **Topic Locator** identifies a specific data stream using a hierarchical path that includes the sequence name and topic path (e.g., `run_2023_01/sensors/lidar_front`). ### Flight Endpoints¶ The daemon exposes Apache Arrow Flight endpoints that handle various operations using Flight's core methods: `list_flights` and `get_flight_info` for discovery and metadata management, `do_put` for high-speed data ingestion, and `do_get` for efficient data retrieval. This design ensures administrative operations don't interfere with data throughput while maintaining low-latency columnar data access. ### Storage Architecture¶ `mosaicod` uses a database to perform fast queries on metadata, manage system state such as sequence and topic definitions, and handle the event queue for processing asynchronous tasks like background data processing or notifications. An object store (such as S3, MinIO, or local filesystem) provides long-term storage for resilience and durability, holding the bulk sensor data, images, point clouds, and immutable schema snapshots that define data structures. Database Durability and Recovery The database state is entirely transient and can be fully reconstructed from the object store. This also enables importing data from other stores. *Currently, there is no way to import data and reconstruct the database, but we are designing the system to enable this feature in future releases.* If the metadata database is corrupted or destroyed, `mosaicod` can rebuild the entire catalog by rescanning the durable object storage. This design ensures that while the database provides performance, the store guarantees long-term durability and recovery, protecting your data against catastrophic infrastructure failure. --- # Setup¶ For rapid prototyping, we provide a Docker Compose configuration. This sets up a volatile environment that includes both the Mosaico server and a PostgreSQL database. ``` # Navigate to the quick start directory form the root folder cd docker/quick_start # Startup the infra in background docker compose up -d ``` This launches PostgreSQL on port `5432` and `mosaicod` on its **default port** `6726` Volatile storage The default Mosaico configuration uses non persistent storage. This means that if the container is destroyed, all stored data will be lost. Since Mosaico is still under active development, we provide this simple, volatile setup by default. For persistent storage, the standard `compose.yml` file can be easily extended to utilize a Docker volume. ## Building from Source¶ To build Mosaico for production, you need a Rust toolchain. Mosaico uses `sqlx` for compile-time query verification, which typically requires a live database connection. However, we support an offline build mode using cached metadata (`.sqlx` folder). ### Offline Build - Recommended¶ ``` SQLX_OFFLINE=true cargo build --release ``` The binary will be located at `target/release/mosaicod`. ### Live Migrations¶ If you need to modify the database schema, a running PostgreSQL instance is required. This allows `sqlx` to verify queries against a live database during compilation. You can use the provided Docker Compose file in `docker/devel` which sets up an instance of MinIO and a PostgreSQL database. First, start the development environment. From inside the `docker/devel` directory, run: ``` # Start the services in the background docker compose up -d # To stop and remove the volumes (which clears all data), run: docker compose down -v ``` Next, from the root of the `mosaicod` workspace, install the necessary tools, configure the environment, and run the build. ``` # Install the SQLx command-line tool cargo install sqlx-cli # Copy the development environment variables for the database connection cp env.devel .env # Apply the database migrations cargo sqlx migrate run # Finally, compile the project cargo build --release ``` ## Configuration¶ The server supports S3-compatible object storage by default but can be configured for local storage via command line options. ### Database¶ Mosaico requires a connection to a running **PostgreSQL** instance, which is defined via the `MOSAICO_REPOSITORY_DB_URL` environment variable. ### Remote Storage Configuration¶ For production deployments, `mosaicod` should be configured to use an S3-compatible object store (such as AWS S3, Google Cloud Storage, Hetzner Object Store, etc) for durable, long-term storage. This is configured through the following environment variables: | Environment Variable | Description | | --- | --- | | `MOSAICO_STORE_BUCKET` | The name of the S3 bucket where Mosaico will store all data blobs. This bucket must be created before starting the server. | | `MOSAICO_STORE_ENDPOINT` | The full URL endpoint for the S3-compatible service. This is necessary for non-AWS providers (e.g., `http://localhost:9000` for a local MinIO instance). | | `MOSAICO_STORE_ACCESS_KEY` | The access key ID for authenticating with your object storage service. | | `MOSAICO_STORE_SECRET_KEY` | The secret access key that corresponds to the provided access key ID, used for authentication. | ### Local Storage Configuration¶ This command will start a `mosaicod` instance using the local filesystem as storage layer. ``` mosaicod run --local-store /tmp/mosaicod ``` --- # Custom Actions¶ Mosaico implements its own administrative protocols directly on top of Apache Arrow Flight. Rather than relying on a separate control channel abstraction, Mosaico leverages the Flight `DoAction` RPC mechanism to handle discrete lifecycle events, administrative interfaces, and resource management. Unlike streaming endpoints designed for continuous data throughput, these custom actions manage the platform's overarching state. While individual calls are synchronous, they often initiate or conclude multi-step processes, such as topic upload, that govern the long-term integrity of data within the platform. All custom actions follow a standardized pattern: they expect a JSON-serialized payload defining the request parameters and return a JSON-serialized response containing the result. ## Sequence Management¶ Sequences are the fundamental containers for data recordings in Mosaico. These custom actions enforce a strict lifecycle state machine to guarantee data integrity. | Action | Description | | --- | --- | | `sequence_create` | Initializes a new, empty sequence. It generates and returns a unique key (UUID). This key acts as a write token, authorizing subsequent data ingestion into this specific sequence. This avoids concurrent access and creation issues when multiple clients attempt to create sequences simultaneously. | | `sequence_finalize` | Transitions a sequence from *uploading* to *archived*. This action locks the sequence, marking it as immutable. Once finalized, no further data can be added or modified, ensuring a perfect audit trail. | | `sequence_abort` | A cleanup operation for failed uploads. It discards a sequence that is currently being uploaded, purging any partial data from the storage to prevent *zombie* records. | | `sequence_delete` | Permanently removes a sequence from the platform. To protect data lineage, this is typically permitted only on unlocked (incomplete) sequences. | ## Topic Management¶ Topics represent the individual sensor streams (e.g., `camera/front`, `gps`) contained within a sequence. | Action | Description | | --- | --- | | `topic_create` | Registers a new topic. | | `topic_delete` | Removes a specific topic from a sequence, permitted only if the parent sequence is still unlocked. | ## Notification System¶ The platform includes a tagging mechanism to attach alerts or informational messages to resources. For example, if an exception is raised during an upload, the notification system automatically registers the event, ensuring the failure is logged and visible for troubleshooting. | Action | Description | | --- | --- | | `*_notify_create` | Attaches a notification to a Sequence or Topic, such as logging an error or status update. | | `*_notify_list` | Retrieves the history of active notifications for a resource, allowing clients to review alerts. | | `*_notify_purge` | Clears the notification history for a resource, useful for cleanup after resolution. | Here, `*` can be either `sequence` or `topic`. ## Query¶ | Action | Description | | --- | --- | | `query` | This action serves as the gateway to the query system. It accepts a complex filter object and returns a list of resources that match the criteria. | --- # Ingestion¶ Data ingestion in Mosaico is handled by the Flight `DoPut` streaming endpoint. This channel is explicitly engineered to handle write-heavy workloads, enabling the system to absorb high-bandwidth sensor data, such as 4K video streams or high-frequency Lidar point clouds—without contending with administrative traffic. ## The Ingestion Protocol¶ Data ingestion follows a structured protocol to ensure type safety and proper sequencing. The process begins with creating a new sequence using `sequence_create`, which takes a sequence name and optional user metadata, returning a unique sequence UUID. Within this sequence, you create topics for each data stream via `topic_create`, associating them with the sequence UUID and assigning unique paths like `my_sequence/topic/1`. Each topic can also include its own metadata. For each topic, data is uploaded using the Flight `do_put` operation, starting with an Arrow schema for validation, followed by streaming `RecordBatch` payloads. Once all topics are uploaded, the sequence is finalized with `sequence_finalize`, committing it to make the data immutable and queryable. During this process, the server validates schemas against registered ontologies, chunks data for efficient storage, and computes indices for fast querying. Ingestion protocol in pseudo-code ``` sq_uuid = do_action("my_sequence", metadata) # Create topic and upload data t1_uuid = do_action(sq_uuid, "my_sequence/topic/1", metadata) # (1)! do_put(t1_uuid, data_stream) do_action(sq_uuid) # (2)! ``` 1. The `topic_create` action returns a UUID that must be passed to the `do_put` call. 2. During finalization, all resources are consolidated and locked. Alternatively, you can call `sequence_abort(sq_uuid)`. Why UUIDs? UUIDs are employed in the ingestion protocol to prevent contentious uploads of the same resources. For instance, if two users attempt to create a new resource (such as a sequence or topic) with the same name, only one will succeed and receive a UUID. This UUID is then used in subsequent calls to ensure that operations are performed by the user who successfully created the resource. ## Chunking & Indexing Strategy¶ The backend automatically manages *chunking* to efficiently handle intra-sequence queries and prevent memory overload from streaming data. As data streams in, the server buffers the incoming data until a full chunk is accumulated, then writes it to disk as an optimal storage unit called a *chunk*. For each chunk written to disk, the server calculates and stores *skip indices* in the metadata database. These indices include ontology-specific statistics, such as type-specific metadata (e.g., coordinate bounding boxes for GPS data or value ranges for sensors). This allows the query engine to perform content-based filtering without needing to read the entire bulk data. --- # Retrieval¶ Measurement data in Mosaico is accessed through the Flight `DoGet` endpoint for high-performance read operations. Unlike simple file downloads, this channel provides an interface for requesting precise data slices, dynamically assembled and streamed back as optimized Arrow batches. ## The Retrieval Protocol¶ Accessing data requires specifying the **Locator**, which defines the topic path, and an optional time range in nanoseconds. The resolution process follows a coordinated sequence. Upon receiving a request, the server performs an index lookup in the metadata cache to identify physical data chunks intersecting the requested time window. This is followed by pruning, discarding chunks outside the query bounds to avoid redundant I/O. Once relevant segments are identified, the server streams the data by opening underlying files and delivering it in a high-throughput pipeline. In the protocol, the `get_flight_info` call returns a list of resources, each containing an endpoint (the name of the topic or sequence, such as `my_sequence` or `my_sequence/my/topic`) and a ticket, an opaque binary blob used by the server in the `do_get` call to extract and stream the data. Calling `get_flight_info` on a sequence returns all topics associated with that sequence, whereas calling it on a specific topic returns only the endpoint and ticket for that topic. Retrieval protocol in pseudo-code ``` locator = "my_sequence/topic/1" time_range = (start_ns, end_ns) # optional resources = get_flight_info(locator, time_range) for res in resources: print(res.endpoint) data_stream = do_get(res.ticket) ``` ## Metadata Context Headers¶ To provide full context, the data stream is prefixed with a Schema message containing embedded custom metadata. Mosaico injects context into this header for client reconstruction of the environment. This includes *user metadata*, preserving original project context like experimental tags or vehicle IDs, and the *ontology tag*, informing the client of sensor data types (e.g., `Lidar`, `Camera`) for type-safe deserialization. The *serialization format* guides interpretation of the underlying serialization protocol used. Now the supported formats include: * `Default`: The standard Arrow columnar layout. * `Ragged`: Optimized for variable-length lists. * `Image`: An optimized array format for high-resolution visual data. --- # Queries¶ Mosaico distinguishes itself from simple file stores with a powerful **Query System** capable of filtering data based on both high-level metadata and content values. The query engine operates through the `query` action, accepting structured JSON-based filter expressions that can span the entire data hierarchy. ## Query Architecture¶ The query engine is designed around a three-tier filtering model that allows you to construct complex, multi-dimensional searches: **Sequence Filtering.** Target recordings by structural attributes like sequence name, creation timestamp, or user-defined metadata tags. This level allows you to narrow down which recording sessions are relevant to your search. **Topic Filtering.** Refine your search to specific data streams within sequences. You can filter by topic name, ontology tag (the data type), serialization format, or topic-level user metadata. **Ontology Filtering.** Query the actual physical values recorded inside the sensor data without scanning terabytes of files. The engine leverages statistical indices computed during ingestion, min/max bounds stored in the metadata cache for each chunk, to rapidly include or exclude entire segments of data. ## Filter Domains¶ ### Sequence Filter¶ The sequence filter allows you to target specific recording sessions based on their metadata: | Field | Description | | --- | --- | | `sequence.name` | The sequence identifier (supports text operations) | | `sequence.creation` | The creation timestamp in nanoseconds (supports timestamp operations) | | `sequence.user_metadata.` | Custom user-defined metadata attached to the sequence | ### Topic Filter¶ The topic filter narrows the search to specific data streams within matching sequences: | Field | Description | | --- | --- | | `topic.name` | The topic path within the sequence (supports text operations) | | `topic.creation` | The topic creation timestamp in nanoseconds (supports timestamp operations) | | `topic.ontology_tag` | The data type identifier (e.g., `Lidar`, `Camera`, `IMU`) | | `topic.serialization_format` | The binary layout format (`Default`, `Ragged`, or `Image`) | | `topic.user_metadata.` | Custom user-defined metadata attached to the topic | ### Ontology Filter¶ The ontology filter queries the actual sensor data values. Fields are specified using dot notation: `.`. For example, to query IMU acceleration data: `imu.acceleration.x`, where `imu` is the ontology tag and `acceleration.x` is the field path within that data model. #### Timestamp query support¶ If `include_timestamp_range` is set to `true` the response will also return timestamps ranges for each query. ## Supported Operators¶ The query engine supports a rich set of comparison operators. Each operator is prefixed with `$` in the JSON syntax: | Operator | Description | | --- | --- | | `$eq` | Equal to (supports all types) | | `$neq` | Not equal to (supports all types) | | `$lt` | Less than (numeric and timestamp only) | | `$gt` | Greater than (numeric and timestamp only) | | `$leq` | Less than or equal to (numeric and timestamp only) | | `$geq` | Greater than or equal to (numeric and timestamp only) | | `$between` | Within a range `[min, max]` inclusive (numeric and timestamp only) | | `$in` | Value is in a set of options (supports integers and text) | | `$match` | Matches a pattern (text only, supports SQL LIKE patterns with `%` wildcards) | | `$ex` | Field exists | | `$nex` | Field does not exist | ## Query Syntax¶ Queries are submitted as JSON objects. Each field is mapped to an operator and value. Multiple conditions are combined with implicit AND logic. ``` { "sequence": { "name": { "$match": "test_run_%" }, "user_metadata": { "driver": { "$eq": "Alice" } } }, "topic": { "ontology_tag": { "$eq": "imu" } }, "ontology": { "imu.acceleration.x": { "$gt": 5.0 }, "imu.acceleration.y": { "$between": [-2.0, 2.0] }, "include_timestamp_range": true, // (1)! } } ``` 1. This filed is optional, if set to `true` the query returns the timestamp ranges This query searches for: * Sequences with names matching `test_run_%` pattern * Where the user metadata field `driver` equals `"Alice"` * Containing topics with ontology tag `imu` * Where the IMU's x-axis acceleration exceeds 5.0 * And the y-axis acceleration is between -2.0 and 2.0 ## Response Structure¶ The query response is hierarchically grouped by sequence. For each matching sequence, it provides the list of topics that satisfied the filter criteria, along with optional timestamp ranges indicating when the ontology conditions were met. Query response example ``` { "items": [ { "sequence": "test_run_01", "topics": [ { "locator": "test_run_01/sensors/imu", "timestamp_range": [1000000000, 2000000000] }, { "locator": "test_run_01/sensors/gps", "timestamp_range": [1000000000, 2000000000] } ] }, { "sequence": "test_run_02", "topics": [ { "locator": "test_run_02/camera/front", "timestamp_range": [1500000000, 2500000000] }, { "locator": "test_run_02/lidar/point_cloud", "timestamp_range": [1500000000, 2500000000] } ] } ] } ``` ### Timestamps¶ It returns the time window `[min, max]` where the filter conditions were met for that topic, with `min` being the timestamp of the first matching event and max being the timestamp of the last matching event. This allows you to retrieve only the relevant data slices using the retrieval protocol. Note The `timestamp_range` field is included only when ontology filters are applied and `include_timestamp_range` is set to `true` inside the `ontology` filter. ## Performance Characteristics¶ The query engine is optimized for high performance by minimizing unnecessary data retrieval and I/O operations. During execution, the engine uses index-based pruning to evaluate precomputed min/max statistics and skip indices, allowing it to bypass irrelevant data chunks without reading the underlying files. Performance is further improved by executing metadata cache queries, such as sequence and topic filters, directly within the database, which ensures sub-second response times even across thousands of sequences. The system employs **lazy evaluation** to keep network payloads lightweight; instead of returning raw data immediately, queries return locators and timestamp ranges. This architecture allows client applications to fetch only the required data slices via the retrieval protocol as needed. --- # CLI Reference¶ ## Run¶ Start the server locally with verbose logging: ``` mosaicod run [OPTIONS] ``` | Option | Default | Description | | --- | --- | --- | | `--host` | `false` | Listen on all addresses, including LAN and public addresses. | | `--port ` | `6726` | Port to listen on. | | `--local-store ` | `None` | Enable storage of objects on the local filesystem at the specified directory path. | --- # Release Cycle¶ This document describes briefly how the release process is handled for Mosaico project. We use semantic versioning `v..` to label every new official release. ## Development process¶ The basic idea is to use more than one develop branch to consent the progress of various versions simultaneously. Below, we introduce the terminology of branches and tags involved in the process: * `main`: this is the only stable branch, where every commit is an official release. Critical patches to the latest version are merged directly on this branch * `release/x.y.0`: this is the catch-all branch for the version `x.y.0`. Once ready it is merged back into `main` and deleted. * `issue//x.y.z`: this kind of branch is associated to the corresponding Github issue `#`. It can contain the development of a new feature or a bug-fix. It is a child of the corresponding `release/x.y.z` branch and it's merged back into it when completed * `hotfix/x.y.`: this branch is intended to contain critical fixes, documentation updates, and maintenance tasks. It is derived directly from `main` and merged back into it to produce the new official version `x.y.`. * `vx.y.z` this tag is created when a new stable version is ready. Let's have a look to an example ## Maintenance process¶ Maintenance of older major versions (LTS) follows a slightly different process. We add to the terminology the following branch: * `lts/x` this branch is created from the last official release of version x present in `main` and lives until the end of support. Only fixes are permitted using `issue/` branches. Once a new version is ready, it is tagged incrementing only the patch version (`vx.y.`). --- ## mosaicolabs.comm.MosaicoClient ¶ ``` MosaicoClient( *, host, port, timeout, control_client, connection_pool, executor_pool, sentinel, ) ``` The gateway to the Mosaico Data Platform. This class centralizes connection management, resource pooling, and serves as a factory for specialized handlers. It is designed to manage the lifecycle of both network connections and asynchronous executors efficiently. Context Manager Usage The `MosaicoClient` is best used as a context manager to ensure all internal pools and connections are gracefully closed. ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: sequences = client.list_sequences() print(f"Available data: {sequences}") ``` **Internal Constructor** (do not call this directly): The `MosaicoClient` enforces a strict factory pattern for security and proper resource setup. Please use the `connect()` method instead to obtain an initialized client. Sentinel Enforcement This constructor checks for a private internal sentinel. Attempting to instantiate this class manually will result in a `RuntimeError`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `host` | `str` | The remote server host. | *required* | | `port` | `int` | The remote server port. | *required* | | `timeout` | `int` | The connection timeout. | *required* | | `control_client` | `FlightClient` | The primary PyArrow Flight control client. | *required* | | `connection_pool` | `Optional[_ConnectionPool]` | Internal pool for data connections. | *required* | | `executor_pool` | `Optional[_ExecutorPool]` | Internal pool for async I/O. | *required* | | `sentinel` | `object` | Private object used to verify factory-based instantiation. | *required* | ### connect `classmethod` ¶ ``` connect(host, port, timeout=5) ``` The primary entry point to the Mosaico Data Platform. This factory method is the **only recommended way** to obtain a valid `MosaicoClient` instance. It orchestrates the necessary handshake, initializes the primary control channel, and prepares the internal resource pools. Factory Pattern Direct instantiation via `__init__` is restricted through a sentinel pattern and will raise a `RuntimeError`. This ensures that every client in use has been correctly configured with a valid network connection. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `host` | `str` | The server host address (e.g., "127.0.0.1" or "mosaico.local"). | *required* | | `port` | `int` | The server port (e.g., 6726). | *required* | | `timeout` | `int` | Maximum time in seconds to wait for a connection response. Defaults to 5. | `5` | Returns: | Name | Type | Description | | --- | --- | --- | | `MosaicoClient` | `MosaicoClient` | An initialized and connected client ready for operations. | Raises: | Type | Description | | --- | --- | | `ConnectionError` | If the server is unreachable or the handshake fails. | | `RuntimeError` | If the class is instantiated directly instead of using this method. | Example ``` from mosaicolabs import MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Perform operations using the client pass ``` ### sequence\_handler ¶ ``` sequence_handler(sequence_name) ``` Retrieves a `SequenceHandler` for the given sequence. Handlers are cached; subsequent calls for the same sequence return the existing object to avoid redundant handshakes. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The unique identifier of the sequence. | *required* | Returns: | Type | Description | | --- | --- | | `Optional[SequenceHandler]` | Optional[SequenceHandler]: A handler for managing sequence operations, or None if not found. | Example ``` from mosaicolabs import MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Retrieve a sequence handler sequence_handler = client.sequence_handler("my_sequence") if sequence_handler: # Print sequence details print(f"Sequence: {sequence_handler.name}") print(f"Created: {sequence_handler.created_datetime}") print(f"Topic list: {sequence_handler.topics}") print(f"User Metadata: {sequence_handler.user_metadata}") print(f"Size (MB): {sequence_handler.total_size_bytes / 1024 / 1024}") ``` ### topic\_handler ¶ ``` topic_handler(sequence_name, topic_name) ``` Retrieves a `TopicHandler` for a specific data channel. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The parent sequence name. | *required* | | `topic_name` | `str` | The specific topic name. | *required* | Returns: | Type | Description | | --- | --- | | `Optional[TopicHandler]` | Optional[TopicHandler]: A handler for managing topic operations, or None if not found. | Example ``` from mosaicolabs import MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Retrieve a topic handler topic_handler = client.topic_handler("my_sequence", "/front/camera/image_raw) if topic_handler: # Print topic details print(f"Topic: {topic_handler.sequence_name}:{topic_handler.name}") print(f"Ontology Tag: {topic_handler.ontology_tag}") print(f"Created: {topic_handler.created_datetime}") print(f"User Metadata: {topic_handler.user_metadata}") print(f"Size (MB): {topic_handler.total_size_bytes / 1024 / 1024}") ``` ### sequence\_create ¶ ``` sequence_create( sequence_name, metadata, on_error=Delete, max_batch_size_bytes=None, max_batch_size_records=None, ) ``` Creates a new sequence on the platform and returns a `SequenceWriter` for ingestion. Important The function **must** be called inside a with context, otherwise a RuntimeError is raised. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | Unique name for the sequence. | *required* | | `metadata` | `dict[str, Any]` | User-defined metadata to attach. | *required* | | `on_error` | `OnErrorPolicy` | Behavior on write failure. Defaults to `Delete`. | `Delete` | | `max_batch_size_bytes` | `Optional[int]` | Max bytes per Arrow batch. | `None` | | `max_batch_size_records` | `Optional[int]` | Max records per Arrow batch. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `SequenceWriter` | `SequenceWriter` | An initialized writer instance. | Raises: | Type | Description | | --- | --- | | `RuntimeError` | If the method is called outside a `with` context. | | `Exception` | If any error occurs during sequence injection. | Example ``` from mosaicolabs import MosaicoClient, OnErrorPolicy # Open the connection with the Mosaico Client with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create( sequence_name="mission_log_042", # Custom metadata for this data sequence. metadata={ "driver": { "driver_id": "drv_sim_017", "role": "validation", "experience_level": "senior", }, "location": { "city": "Milan", "country": "IT", "facility": "Downtown", "gps": { "lat": 45.46481, "lon": 9.19201, }, }, } on_error = OnErrorPolicy.Delete # Default ) as seq_writer: # Start creating topics and pushing data... # (1)! ``` 1. See also: * `SequenceWriter.topic_create()` * `TopicWriter.push()` ### sequence\_delete ¶ ``` sequence_delete(sequence_name) ``` Permanently deletes a sequence and all its associated data from the server. This operation is destructive and triggers a cascading deletion of all underlying resources, including all topics and data chunks belonging to the sequence. Once executed, all storage occupied by the sequence is freed. Sequence Locking This action can only be performed on **unlocked** sequences. If a sequence is currently locked (e.g., for archival or safety reasons), the deletion request will be rejected by the server. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The unique name of the sequence to remove. | *required* | ### list\_sequences ¶ ``` list_sequences() ``` Retrieves a list of all sequence names available on the server. Returns: | Type | Description | | --- | --- | | `List[str]` | List[str]: The list of sequence identifiers. | Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: sequences = client.list_sequences() print(f"Available sequences: {sequences}") ``` ### list\_sequence\_notify ¶ ``` list_sequence_notify(sequence_name) ``` Retrieves a list of all notifications available on the server for a specific sequence. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The name of the sequence to list notifications for. | *required* | Returns: | Type | Description | | --- | --- | | `List[Notified]` | List[Notified]: The list of sequence notifications. | Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: sequence_notifications = client.list_sequence_notify("my_sequence") for notify in sequence_notifications: print(f"Notification Type: {notify.notify_type}") print(f"Notification Message: {notify.message}") print(f"Notification Created: {notify.created_datetime}") ``` ### clear\_sequence\_notify ¶ ``` clear_sequence_notify(sequence_name) ``` Clears the notifications for a specific sequence from the server. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The name of the sequence. | *required* | ### list\_topic\_notify ¶ ``` list_topic_notify(sequence_name, topic_name) ``` Retrieves a list of all notifications available on the server for a specific topic Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The name of the sequence to list notifications for. | *required* | | `topic_name` | `str` | The name of the topic to list notifications for. | *required* | Returns: | Type | Description | | --- | --- | | `List[Notified]` | List[str]: The list of topic notifications. | Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: topic_notifications = client.list_topic_notify("my_sequence", "my_topic") for notify in topic_notifications: print(f"Notification Type: {notify.notify_type}") print(f"Notification Message: {notify.message}") print(f"Notification Created: {notify.created_datetime}") ``` ### clear\_topic\_notify ¶ ``` clear_topic_notify(sequence_name, topic_name) ``` Clears the notifications for a specific topic from the server. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The name of the sequence. | *required* | | `topic_name` | `str` | The name of the topic. | *required* | ### query ¶ ``` query(*queries, query=None) ``` Executes one or more queries against the Mosaico database. Multiple provided queries are joined using a logical **AND** condition. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*queries` | `QueryableProtocol` | Variable arguments of query builder objects (e.g., `QuerySequence`). | `()` | | `query` | `Optional[Query]` | An alternative pre-constructed Query object. | `None` | Returns: | Type | Description | | --- | --- | | `Optional[QueryResponse]` | Optional[QueryResponse]: The query results, or None if an error occurs. | Raises: | Type | Description | | --- | --- | | `ValueError` | If conflicting query types are passed or no queries are provided. | Query with variadic arguments ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, Query, IMU, MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Perform the server side query results = client.query( # Append a filter for sequence metadata QuerySequence() .with_expression( # Use query proxy for generating a _QuerySequenceExpression Sequence.Q.user_metadata["environment.visibility"].lt(50) ) .with_name_match("test_drive"), # Append a filter with deep time-series data discovery and measurement time windowing QueryOntologyCatalog() .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.header.stamp.sec.gt(1700134567)) .with_expression(IMU.Q.header.stamp.nanosec.between([123456, 789123])), ) # Inspect the results if results is not None: # Results are automatically grouped by Sequence for easier data management for item in results: print(f"Sequence: {item.sequence.name}") ``` Query with `Query` object ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, Query, IMU, MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Build a filter with name pattern and metadata-related expression query = Query( # Append a filter for sequence metadata QuerySequence() .with_expression( # Use query proxy for generating a _QuerySequenceExpression Sequence.Q.user_metadata["environment.visibility"].lt(50) ) .with_name_match("test_drive"), # Append a filter with deep time-series data discovery and measurement time windowing QueryOntologyCatalog() .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.header.stamp.sec.gt(1700134567)) .with_expression(IMU.Q.header.stamp.nanosec.between([123456, 789123])), ) # Perform the server side query results = client.query(query=query) # Inspect the results if results is not None: # Results are automatically grouped by Sequence for easier data management for item in results: print(f"Sequence: {item.sequence.name}") ``` ### clear\_sequence\_handlers\_cache ¶ ``` clear_sequence_handlers_cache() ``` Clears the internal cache of `SequenceHandler` objects. ### clear\_topic\_handlers\_cache ¶ ``` clear_topic_handlers_cache() ``` Clears the internal cache of `TopicHandler` objects. ### close ¶ ``` close() ``` Gracefully shuts down the Mosaico client and releases all underlying resources. This method ensures a clean termination of the client's lifecycle by: \* **Closing Handlers:** Invalidates and closes all cached `SequenceHandlers` and `TopicHandlers` to prevent stale data access. \* **Network Cleanup:** Terminated the connection pool to the `mosaicod` backend. \* **Thread Termination:** Shuts down the internal thread executor pool responsible for asynchronous data fetching and background streaming. Note If using the client as a context manager (via `with MosaicoClient.connect(...)`), this method is invoked automatically on exit. Explicit calls are required only for manual lifecycle management. Example ``` from mosaicolabs import MosaicoClient # Manual connection management client = MosaicoClient.connect("localhost", 6726) # High-performance streaming or ML extraction qresp = client.query(...) # Do something else... # Ensure resources are consistently freed. client.close() ``` ## mosaicolabs.comm.NotifyType ¶ Bases: `StrEnum` Classification of platform-level notifications. These identifiers distinguish the severity and intent of messages sent from the Mosaico server regarding resource states or operation failures. Attributes: | Name | Type | Description | | --- | --- | --- | | `ERROR` | | Indicates a critical failure during resource operations, such as a writing interruption or serialization fault. | ### ERROR `class-attribute` `instance-attribute` ¶ ``` ERROR = 'error' ``` Critical error notification. ## mosaicolabs.comm.Notified `dataclass` ¶ ``` Notified( sequence_name, notify_type, message, created_datetime, topic_name=None, ) ``` Platform diagnostic notification. A `Notified` object represents a specific event or error report stored on the platform server. These are typically generated by asynchronous ingestion tasks and are critical for debugging failures when using `OnErrorPolicy.Report`. ##### Discovery¶ Notifications can be retrieved at both the sequence and topic level via the Mosaico client: * `MosaicoClient.list_sequence_notify()` * `MosaicoClient.list_topic_notify()` Example ``` with MosaicoClient.connect("localhost", 6726) as client: # Retrieve notifications for a problematic sequence errors = client.list_sequence_notify("mission_alpha") for error in errors: print(f"[{error.created_datetime}] {error.notify_type}: {error.message}") ``` Attributes: | Name | Type | Description | | --- | --- | --- | | `sequence_name` | `str` | The unique identifier of the associated sequence. | | `notify_type` | `NotifyType` | The `NotifyType` categorization of this event. | | `message` | `str` | A detailed string describing the event or error cause. | | `created_datetime` | `datetime` | The timestamp when the server generated the notification. | | `topic_name` | `Optional[str]` | Optional; the specific topic name if the notification is granular to a single data channel. | --- ## mosaicolabs.enum.SerializationFormat ¶ Bases: `StrEnum` Defines the structural format used when serializing ontology data for storage or transmission. The format dictates how the data is organized (e.g., fixed-schema tables vs. variable-length structures) and may imply specific handling during the serialization and deserialization process. ### Default `class-attribute` `instance-attribute` ¶ ``` Default = 'default' ``` Represents data that conforms to a strict, fixed-width tabular format (like a standard DataFrame or a PyArrow Table of records). Suitable for simple sensors with a constant number of fields and fixed-size data. ### Ragged `class-attribute` `instance-attribute` ¶ ``` Ragged = 'ragged' ``` Represents data containing variable-length lists or sequences (e.g., point clouds, lists of detections, or non-uniform arrays). This format is typically serialized using specialized PyArrow features to handle the non-uniform structure efficiently. ### Image `class-attribute` `instance-attribute` ¶ ``` Image = 'image' ``` Represents raw or compressed image data. This format signals that the data consists primarily of a binary blob (the image content) along with associated metadata (width, height, format), often requiring specialized compression/decompression handling. ## mosaicolabs.enum.SequenceStatus ¶ Bases: `Enum` Represents the operational lifecycle state of a Sequence during the ingestion process (see also `SequenceWriter`). This enumeration tracks the state of a sequence from its initial creation through data writing until it reaches a terminal state (Finalized or Error). ### Null `class-attribute` `instance-attribute` ¶ ``` Null = 'null' ``` The initial state of a writer before server-side registration. In this state, the local `SequenceWriter` instance has been created but the `SEQUENCE_CREATE` handshake has not yet been performed or completed. ### Pending `class-attribute` `instance-attribute` ¶ ``` Pending = 'pending' ``` The sequence is registered on the server and actively accepting data. This state is entered upon successful execution of the `__enter__` method of the `SequenceWriter` class. While pending, the sequence allows for the creation of new topics and the ingestion of data batches. ### Finalized `class-attribute` `instance-attribute` ¶ ``` Finalized = 'finalized' ``` The sequence has been successfully closed and its data is now immutable. This terminal state indicates that the `SequenceWriter._finalize()` action was acknowledged by the server. Once finalized, the sequence is typically **locked** and cannot be deleted unless explicitly unlocked by an administrator. ### Error `class-attribute` `instance-attribute` ¶ ``` Error = 'error' ``` The ingestion process failed or was explicitly aborted. This state is reached if an exception occurs within the `with` block or during the finalization phase. Depending on the `OnErrorPolicy`, the data may have been purged (`Delete`) or retained in an **unlocked** state for debugging (`Report`). ## mosaicolabs.enum.OnErrorPolicy ¶ Bases: `Enum` Defines the behavior of the `SequenceWriter` when an exception occurs during ingestion. This policy determines how the platform handles partially uploaded data if the ingestion process is interrupted or fails. ### Report `class-attribute` `instance-attribute` ¶ ``` Report = 'report' ``` Notify the server of the error but retain partial data. The system will attempt to finalize the sequence and notify the server of the specific failure, allowing existing data chunks to remain accessible for inspection. Lock Status Unlike standard successful finalization, a sequence finalized via a `Report` policy is **not placed in a locked state**. This means the sequence remains mutable at a system level and can be **deleted in a later moment** once debugging or triage is complete. ### Delete `class-attribute` `instance-attribute` ¶ ``` Delete = 'delete' ``` Abort the sequence and instruct the server to discard all data. This is the default "all-or-nothing" strategy. If a failure occurs, the `SequenceWriter` will send an abort command to ensure the server purges all traces of the failed ingestion, preventing inconsistent or incomplete sequences from appearing in the catalog. ## mosaicolabs.enum.FlightAction ¶ Bases: `StrEnum` Internal enumeration of PyArrow Flight action identifiers. This enum serves as the single source of truth for all action names used in the handshakes between the SDK and the Mosaico server. Internal Use Only This class is part of the internal communication protocol. End-users should never need to use these identifiers directly, as they are abstracted by the public methods in `MosaicoClient`, `SequenceWriter`, and `TopicWriter`. ### SEQUENCE\_CREATE `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_CREATE = 'sequence_create' ``` Initiates the registration of a new sequence on the server. ### SEQUENCE\_FINALIZE `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_FINALIZE = 'sequence_finalize' ``` Marks a sequence as complete and makes its data immutable. ### SEQUENCE\_NOTIFY\_CREATE `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_NOTIFY_CREATE = 'sequence_notify_create' ``` Sends asynchronous notifications or error reports during the sequence creation phase. ### SEQUENCE\_NOTIFY\_LIST `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_NOTIFY_LIST = 'sequence_notify_list' ``` Request the list of notifications for a specific sequence ### SEQUENCE\_NOTIFY\_PURGE `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_NOTIFY_PURGE = 'sequence_notify_purge' ``` Request the deletion of the list of notifications for a specific sequence ### SEQUENCE\_SYSTEM\_INFO `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_SYSTEM_INFO = 'sequence_system_info' ``` Requests physical diagnostics such as storage size and lock status for a sequence. ### SEQUENCE\_ABORT `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_ABORT = 'sequence_abort' ``` Signals the server to stop an active ingestion and discard partial data. ### SEQUENCE\_DELETE `class-attribute` `instance-attribute` ¶ ``` SEQUENCE_DELETE = 'sequence_delete' ``` Requests the permanent removal of a sequence and all associated topics from the server. ### TOPIC\_CREATE `class-attribute` `instance-attribute` ¶ ``` TOPIC_CREATE = 'topic_create' ``` Registers a new topic within an existing sequence context. ### TOPIC\_NOTIFY\_CREATE `class-attribute` `instance-attribute` ¶ ``` TOPIC_NOTIFY_CREATE = 'topic_notify_create' ``` Reports errors or status updates specific to an individual topic stream. ### TOPIC\_NOTIFY\_LIST `class-attribute` `instance-attribute` ¶ ``` TOPIC_NOTIFY_LIST = 'topic_notify_list' ``` Request the list of notifications for a specific topic in a sequence ### TOPIC\_NOTIFY\_PURGE `class-attribute` `instance-attribute` ¶ ``` TOPIC_NOTIFY_PURGE = 'topic_notify_purge' ``` Request the deletion of the list of notifications for a topic in a sequence ### TOPIC\_SYSTEM\_INFO `class-attribute` `instance-attribute` ¶ ``` TOPIC_SYSTEM_INFO = 'topic_system_info' ``` Requests storage and chunk metadata for an individual topic. ### TOPIC\_DELETE `class-attribute` `instance-attribute` ¶ ``` TOPIC_DELETE = 'topic_delete' ``` Requests the permanent removal of a specific topic from the platform. ### QUERY `class-attribute` `instance-attribute` ¶ ``` QUERY = 'query' ``` Commands a multi-layer search query against the platform. --- ## mosaicolabs.handlers.system\_info.SystemInfo `dataclass` ¶ ``` SystemInfo( total_size_bytes, created_datetime, is_locked, chunks_number=None, ) ``` Metadata and structural information for a Mosaico `Sequence` or `Topic` resource. This Data Transfer Object summarizes the physical and logical state of a sequence or topic on the server, typically retrieved via a system-info action. Attributes: | Name | Type | Description | | --- | --- | --- | | `total_size_bytes` | `int` | The aggregate size of all data chunks in bytes. | | `created_datetime` | `datetime` | The UTC timestamp of when the resource was first initialized. | | `is_locked` | `bool` | Indicates if the resource is currently read-only. Usually true if an upload is finalized or a retention policy is active. | | `chunks_number` | `Optional[int]` | The total count of data partitions (chunks) stored on the server. Defaults to None if not applicable. | ## mosaicolabs.handlers.SequenceHandler ¶ ``` SequenceHandler( *, sequence_model, client, timestamp_ns_min, timestamp_ns_max, ) ``` Represents a client-side handle for an existing Sequence on the Mosaico platform. The `SequenceHandler` acts as a primary container for inspecting sequence-level metadata, listing available topics, and accessing data reading interfaces like the `SequenceDataStreamer`. Obtaining a Handler Users should not instantiate this class directly. The recommended way to obtain a handler is via the `MosaicoClient.sequence_handler()` factory method. Internal constructor for SequenceHandler. **Do not call this directly.** Users should retrieve instances via `MosaicoClient.sequence_handler()`, while internal modules should use the `SequenceHandler._connect()` factory. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_model` | `Sequence` | The underlying metadata and system info model for the sequence. | *required* | | `client` | `FlightClient` | The active FlightClient for remote operations. | *required* | | `timestamp_ns_min` | `Optional[int]` | The lowest timestamp (in ns) available in this sequence. | *required* | | `timestamp_ns_max` | `Optional[int]` | The highest timestamp (in ns) available in this sequence. | *required* | ### name `property` ¶ ``` name ``` The unique name of the sequence. Returns: | Type | Description | | --- | --- | | `str` | The unique name of the sequence. | ### topics `property` ¶ ``` topics ``` The list of topic names (data channels) available within this sequence. Returns: | Type | Description | | --- | --- | | `List[str]` | The list of topic names (data channels) available within this sequence. | ### user\_metadata `property` ¶ ``` user_metadata ``` The user-defined metadata dictionary associated with this sequence. Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | The user-defined metadata dictionary associated with this sequence. | ### created\_datetime `property` ¶ ``` created_datetime ``` The UTC timestamp indicating when the entity was created on the server. Returns: | Type | Description | | --- | --- | | `datetime` | The UTC timestamp indicating when the entity was created on the server. | ### is\_locked `property` ¶ ``` is_locked ``` Indicates if the resource is currently locked. A locked state typically occurs during active writing or maintenance operations, preventing deletion or structural modifications. Returns: | Type | Description | | --- | --- | | `bool` | The lock status of the sequence. | ### total\_size\_bytes `property` ¶ ``` total_size_bytes ``` The total physical storage footprint of the entity on the server in bytes. Returns: | Type | Description | | --- | --- | | `int` | The total physical storage footprint of the entity on the server in bytes. | ### timestamp\_ns\_min `property` ¶ ``` timestamp_ns_min ``` The lowest timestamp (nanoseconds) recorded in the sequence across all topics. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The lowest timestamp (nanoseconds) recorded in the sequence across all topics, or `None` if the sequence contains no data or the timestamps could not be derived. | ### timestamp\_ns\_max `property` ¶ ``` timestamp_ns_max ``` The highest timestamp (nanoseconds) recorded in the sequence across all topics. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The highest timestamp (nanoseconds) recorded in the sequence across all topics, or `None` if the sequence contains no data or the timestamps could not be derived. | ### get\_data\_streamer ¶ ``` get_data_streamer( topics=[], start_timestamp_ns=None, end_timestamp_ns=None, ) ``` Opens a reading channel for iterating over the sequence data. The returned `SequenceDataStreamer` performs a K-way merge sort to provide a single, time-synchronized chronological stream of messages from multiple topics. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topics` | `List[str]` | A subset of topic names to stream. If empty, all topics in the sequence are streamed. | `[]` | | `start_timestamp_ns` | `Optional[int]` | The **inclusive** lower bound (t >= start) for the time window in nanoseconds. The stream starts at the first message with a timestamp greater than or equal to this value. | `None` | | `end_timestamp_ns` | `Optional[int]` | The **exclusive** upper bound (t < end) for the time window in nanoseconds. The stream stops at the first message with a timestamp strictly less than this value. | `None` | Returns: | Type | Description | | --- | --- | | `SequenceDataStreamer` | A `SequenceDataStreamer` iterator yielding `(topic_name, message)` tuples. | Raises: | Type | Description | | --- | --- | | `ValueError` | If the provided topic names do not exist or if the sequence contains no data. | Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Start a Unified Stream (K-Way Merge) for multi-sensor replay streamer = seq_handler.get_data_streamer( topics=["/gps", "/imu"], # Optionally filter topics # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time (without consuming data) print(f"Recording starts at: {streamer.next_timestamp()}") # Start timed data-stream for topic, msg in streamer: print(f"[{topic}] at {msg.timestamp_ns}: {type(msg.data).__name__}") # Once done, close the resources, topic handler and related reading channels (recommended). seq_handler.close() ``` Important Every call to `get_data_streamer()` will automatically invoke `close()` on any previously spawned `SequenceDataStreamer` instance and its associated Apache Arrow Flight channels before initializing the new stream. Example: ``` seq_handler = client.sequence_handler("mission_alpha") # Opens first stream streamer_v1 = seq_handler.get_data_streamer(start_timestamp_ns=T1) # Calling this again automatically CLOSES streamer_v1 and opens a new channel streamer_v2 = seq_handler.get_data_streamer(start_timestamp_ns=T2) # Using `streamer_v1` will raise a ValueError for topic, msg in streamer_v1 # raises here! pass ``` ### get\_topic\_handler ¶ ``` get_topic_handler(topic_name, force_new_instance=False) ``` Get a specific `TopicHandler` for a child topic. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic_name` | `str` | The relative name of the topic (e.g., "/camera/front"). | *required* | | `force_new_instance` | `bool` | If `True`, bypasses the internal cache and recreates the handler. | `False` | Returns: | Type | Description | | --- | --- | | `TopicHandler` | A `TopicHandler` dedicated to the specified topic. | Raises: | Type | Description | | --- | --- | | `ValueError` | If the topic is not available in this sequence or an internal connection error occurs. | Example ``` import sys from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Use a Handler to inspect the catalog top_handler = seq_handler.get_topic_handler("/front/imu") if top_handler: print(f"Sequence: {top_handler.sequence_name}") print(f" |Topic: {top_handler.sequence_name}:{top_handler.name}") print(f" |User metadata: {top_handler.user_metadata}") print(f" |Timestamp span: {top_handler.timestamp_ns_min} - {top_handler.timestamp_ns_max}") print(f" |Created {top_handler.created_datetime}") print(f" |Size (MB) {top_handler.total_size_bytes/(1024*1024)}") # Once done, close the resources, topic handler and related reading channels (recommended). seq_handler.close() ``` ### close ¶ ``` close() ``` Gracefully closes all cached topic handlers and active data streamers. This method should be called to release network and memory resources when the handler is no longer needed. Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Perform operations # ... # Once done, close the resources, topic handler and related reading channels (recommended). seq_handler.close() ``` ## mosaicolabs.handlers.TopicHandler ¶ ``` TopicHandler( *, client, topic_model, ticket, timestamp_ns_min, timestamp_ns_max, ) ``` Represents an existing topic on the Mosaico platform. The `TopicHandler` provides a client-side interface for interacting with an individual data stream (topic). It allows users to inspect static metadata and system diagnostics (via the `Topic` model), and access the raw message stream through a dedicated `TopicDataStreamer`. Obtaining a Handler Direct instantiation of this class is discouraged. Use the `MosaicoClient.topic_handler()` factory method to retrieve an initialized handler. Internal constructor for TopicHandler. **Do not call this directly.** Users should retrieve instances via `MosaicoClient.topic_handler()`, or by using the `get_topic_handler()` method from the `SequenceHandler` instance of the parent senquence. Internal modules should use the `TopicHandler._connect()` factory. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `client` | `FlightClient` | The active FlightClient for remote operations. | *required* | | `topic_model` | `Topic` | The underlying metadata and system info model for the topic. | *required* | | `ticket` | `Ticket` | The remote resource ticket used for data retrieval. | *required* | | `timestamp_ns_min` | `Optional[int]` | The lowest timestamp (in ns) available in this topic. | *required* | | `timestamp_ns_max` | `Optional[int]` | The highest timestamp (in ns) available in this topic. | *required* | ### name `property` ¶ ``` name ``` The relative name of the topic (e.g., "/front\_cam/image\_raw"). Returns: | Type | Description | | --- | --- | | `str` | The relative name of the topic. | ### sequence\_name `property` ¶ ``` sequence_name ``` The name of the parent sequence containing this topic. Returns: | Type | Description | | --- | --- | | `str` | The name of the parent sequence. | ### user\_metadata `property` ¶ ``` user_metadata ``` The user-defined metadata dictionary associated with this topic. Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | The user-defined metadata dictionary. | ### created\_datetime `property` ¶ ``` created_datetime ``` The UTC timestamp indicating when the entity was created on the server. Returns: | Type | Description | | --- | --- | | `datetime` | The UTC timestamp indicating when the entity was created on the server. | ### is\_locked `property` ¶ ``` is_locked ``` Indicates if the resource is currently locked. A locked state typically occurs during active writing or maintenance operations, preventing deletion or structural modifications. Returns: | Type | Description | | --- | --- | | `bool` | True if the resource is currently locked, False otherwise. | ### chunks\_number `property` ¶ ``` chunks_number ``` The number of physical data chunks stored for this topic. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The number of physical data chunks stored for this topic, or `None` if the server did not provide detailed storage statistics. | ### ontology\_tag `property` ¶ ``` ontology_tag ``` The ontology type identifier (e.g., 'imu', 'gnss'). This corresponds to the `__ontology_tag__` defined in the `Serializable` class registry. Returns: | Type | Description | | --- | --- | | `str` | The ontology type identifier. | ### serialization\_format `property` ¶ ``` serialization_format ``` The format used to serialize the topic data (e.g., 'arrow', 'image'). This corresponds to the `SerializationFormat` enum. Returns: | Type | Description | | --- | --- | | `str` | The serialization format. | ### total\_size\_bytes `property` ¶ ``` total_size_bytes ``` The total physical storage footprint of the entity on the server in bytes. Returns: | Type | Description | | --- | --- | | `int` | The total physical storage footprint of the entity on the server in bytes. | ### timestamp\_ns\_min `property` ¶ ``` timestamp_ns_min ``` The lowest timestamp (nanoseconds) recorded in this topic. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The lowest timestamp (nanoseconds) recorded in this topic, or `None` if the topic is empty or timestamps are unavailable. | ### timestamp\_ns\_max `property` ¶ ``` timestamp_ns_max ``` The highest timestamp (nanoseconds) recorded in this topic. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The highest timestamp (nanoseconds) recorded in this topic, or `None` if the topic is empty or timestamps are unavailable. | ### get\_data\_streamer ¶ ``` get_data_streamer( start_timestamp_ns=None, end_timestamp_ns=None ) ``` Opens a high-performance reading channel for iterating over this topic's data. ###### Stream Lifecycle Policy: Single-Active-Streamer¶ To optimize resource utilization and prevent backend socket exhaustion, this handler maintains at most **one active stream** at a time. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `start_timestamp_ns` | `Optional[int]` | The **inclusive** lower bound (t >= start) in nanoseconds. The stream begins at the first message with a timestamp >= this value. | `None` | | `end_timestamp_ns` | `Optional[int]` | The **exclusive** upper bound (t < end) in nanoseconds. The stream terminates before reaching any message with a timestamp >= this value. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `TopicDataStreamer` | `TopicDataStreamer` | A chronological iterator for the requested data window. | Raises: | Type | Description | | --- | --- | | `ValueError` | If the topic contains no data or the handler is in an invalid state. | Example ``` from mosaicolabs import MosaicoClient, IMU with MosaicoClient.connect("localhost", 6726) as client: # Retrieve the topic handler using (e.g.) MosaicoClient top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: imu_stream = top_handler.get_data_streamer( # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time (without consuming data) print(f"Recording starts at: {streamer.next_timestamp()}") # Direct, low-overhead loop for imu_msg in imu_stream: process_sample(imu_msg.get_data(IMU)) # Some custom process function # Once done, close the reading channel (recommended) top_handler.close() ``` Important Every call to `get_data_streamer()` will automatically invoke `close()` on any previously spawned `TopicDataStreamer` instance and its associated Apache Arrow Flight channel before initializing the new stream. Example: ``` top_handler = client.topic_handler("mission_alpha", "/front/imu") # Opens first stream streamer_v1 = top_handler.get_data_streamer(start_timestamp_ns=T1) # Calling this again automatically CLOSES streamer_v1 and opens a new channel streamer_v2 = top_handler.get_data_streamer(start_timestamp_ns=T2) # Using `streamer_v1` will raise a ValueError for msg in streamer_v1 # raises here! pass ``` ### close ¶ ``` close() ``` Terminates the active data streamer associated with this topic and releases allocated system resources. In the Mosaico architecture, a `TopicHandler` acts as a factory for `TopicDataStreamers`. Calling `close()` ensures that any background data fetching, buffering, or network sockets held by an active streamer are immediately shut down. Note * If no streamer has been spawned (via `get_data_streamer`), this method performs no operation and returns safely. * Explicitly closing handlers is a best practice when iterating through large datasets to prevent resource accumulation. Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Access a specific sensor topic (e.g., IMU) top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: # Initialize a high-performance data stream imu_stream = top_handler.get_data_streamer( start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Consume data for ML training or analysis # for msg in imu_stream: ... # Release the streaming channel and backend resources top_handler.close() ``` ## mosaicolabs.handlers.SequenceDataStreamer ¶ ``` SequenceDataStreamer( *, sequence_name, client, topic_readers ) ``` A unified, time-ordered iterator for reading multi-topic sequences. The `SequenceDataStreamer` performs a **K-Way Merge** across multiple topic streams to provide a single, coherent chronological view of an entire sequence. This is essential when topics have different recording rates or asynchronous sampling times. ##### Key Capabilities¶ * **Temporal Slicing**: Supports server-side filtering to stream data within specific time windows (t >= start and t < end). * **Peek-Ahead**: Provides the `next_timestamp()` method, allowing the system to inspect chronological order without consuming the record—a core requirement for the K-way merge sorting algorithm. ##### The Merge Algorithm¶ This class manages multiple internal `TopicDataStreamer` instances. On every iteration, it: 1. **Peeks** at the next available timestamp from every active topic stream. 2. **Selects** the topic currently holding the lowest absolute timestamp. 3. **Yields** that specific record and advances only the "winning" topic stream. Obtaining a Streamer Do not instantiate this class directly. Use the `SequenceHandler.get_data_streamer()` method to obtain a configured instance. Internal constructor for SequenceDataStreamer. **Do not call this directly.** Internal library modules should use the `SequenceDataStreamer._connect()` factory. Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Start a Unified Stream (K-Way Merge) for multi-sensor replay streamer = seq_handler.get_data_streamer( topics=["/gps", "/imu"], # Optionally filter topics # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Start timed data-stream for topic, msg in streamer: # Do some processing... # Once done, close the resources, topic handler and related reading channels (recommended). seq_handler.close() ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | The name of the sequence being streamed. | *required* | | `client` | `FlightClient` | The active FlightClient for remote operations. | *required* | | `topic_readers` | `Dict[str, TopicDataStreamer]` | A dictionary mapping topic names to their respective `TopicDataStreamer` instances. | *required* | ### next\_timestamp ¶ ``` next_timestamp() ``` Peeks at the timestamp of the next chronological measurement without consuming the record. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The minimum timestamp (nanoseconds) found across all active topics, or `None` if all streams are exhausted. | Example ``` from mosaicolabs import MosaicoClient with MosaicoClient.connect("localhost", 6726) as client: # Use a Handler to inspect the catalog seq_handler = client.sequence_handler("mission_alpha") if seq_handler: # Start a Unified Stream (K-Way Merge) for multi-sensor replay streamer = seq_handler.get_data_streamer( topics=["/gps", "/imu"], # Optionally filter topics # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time (without consuming data) print(f"Recording starts at: {streamer.next_timestamp()}") # Do some processing... # Once done, close the resources, topic handler and related reading channels (recommended). seq_handler.close() ``` ### close ¶ ``` close() ``` Gracefully terminates all underlying topic streams and releases allocated resources. This method iterates through all active `TopicDataStreamer` instances, ensuring that each remote connection is closed and local memory buffers are cleared. Automatic Cleanup In standard workflows, you do not need to call this manually. This function is **automatically invoked** by the `SequenceHandler.close()` method, which in turn is triggered by the `__exit__` logic of the parent `SequenceHandler` when used within a `with` context. ## mosaicolabs.handlers.TopicDataStreamer ¶ ``` TopicDataStreamer(*, client, state) ``` An iterator that streams ontology records from a single topic. The `TopicDataStreamer` wraps a PyArrow Flight `DoGet` stream to fetch `RecordBatches` from the server and reconstruct individual `Message` objects. It is designed for efficient row-by-row iteration while providing peek-ahead capabilities for time-synchronized merging. ##### Key Capabilities¶ * **Temporal Slicing**: Supports server-side filtering to stream data within specific time windows (t >= start and t < end). * **Peek-Ahead**: Provides the `next_timestamp()` method, allowing the system to inspect chronological order without consuming the record—a core requirement for the K-way merge sorting performed by the `SequenceDataStreamer`. Obtaining a Streamer Users should typically not instantiate this class directly. The recommended way to obtain a streamer is via the `TopicHandler.get_data_streamer()` method. Internal constructor for TopicDataStreamer. **Do not call this directly.** Internal library modules should use the `TopicDataStreamer._connect()` or `TopicDataStreamer._connect_from_ticket()` factory methods instead. Example ``` from mosaicolabs import MosaicoClient, IMU with MosaicoClient.connect("localhost", 6726) as client: # Retrieve the topic handler using (e.g.) MosaicoClient top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: imu_stream = top_handler.get_data_streamer( # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time (without consuming data) print(f"Recording starts at: {streamer.next_timestamp()}") # Direct, low-overhead loop for imu_msg in imu_stream: # Do some processing... # Once done, close the reading channel (recommended) top_handler.close() ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `client` | `FlightClient` | The active FlightClient used for remote operations. | *required* | | `state` | `_TopicReadState` | The internal state object managing the Arrow reader and peek buffers. | *required* | ### ontology\_tag `property` ¶ ``` ontology_tag ``` The ontology tag associated with this streamer. Returns: | Type | Description | | --- | --- | | `str` | The ontology tag. | ### name ¶ ``` name() ``` The name of the topic associated with this streamer. Returns: | Type | Description | | --- | --- | | `str` | The name of the topic. | ### next\_timestamp ¶ ``` next_timestamp() ``` Peeks at the timestamp of the next record without consuming it. Returns: | Type | Description | | --- | --- | | `Optional[int]` | The next timestamp in nanoseconds, or `None` if the stream is empty. | Raises: | Type | Description | | --- | --- | | `ValueError` | if the data streamer instance has been closed. | Example ``` from mosaicolabs import MosaicoClient, IMU with MosaicoClient.connect("localhost", 6726) as client: # Retrieve the topic handler using (e.g.) MosaicoClient top_handler = client.topic_handler("mission_alpha", "/front/imu") if top_handler: imu_stream = top_handler.get_data_streamer( # Optionally set the time window to extract start_timestamp_ns=1738508778000000000, end_timestamp_ns=1738509618000000000 ) # Peek at the start time (without consuming data) print(f"Recording starts at: {streamer.next_timestamp()}") # Do some processing... # Once done, close the reading channel (recommended) top_handler.close() ``` ### close ¶ ``` close() ``` Gracefully terminates the underlying Apache Arrow Flight stream and releases buffers. Automatic Lifecycle Management In most production workflows, manual invocation is not required. This method is **automatically called** by the parent `TopicHandler.close()`. If the handler is managed within a `with` context, the SDK ensures a top-down cleanup of the handler and its associated streamers upon exit. Example ``` # Manual resource management (if not using 'with' block) streamer = topic_handler.get_data_streamer() try: for meas in streamer: process_robot_data(meas) finally: streamer.close() ``` --- ## mosaicolabs.handlers.config.WriterConfig `dataclass` ¶ ``` WriterConfig( on_error, max_batch_size_bytes, max_batch_size_records ) ``` Configuration settings for Sequence and Topic writers. Internal Usage This is currently **not a user-facing class**. It is automatically instantiated by the `MosaicoClient` when allocating new `SequenceWriter` instances via `sequence_create()`. This dataclass defines the operational parameters for data ingestion, controlling both the error recovery strategy and the performance-critical buffering logic used by the `SequenceWriter` and `TopicWriter`. ### on\_error `instance-attribute` ¶ ``` on_error ``` Determines the terminal behavior when an exception occurs during the ingestion lifecycle. * If set to `OnErrorPolicy.Delete`, the system purges all data from the failed sequence. * If set to `OnErrorPolicy.Report`, the system retains the partial data in an **unlocked** state for debugging. ### max\_batch\_size\_bytes `instance-attribute` ¶ ``` max_batch_size_bytes ``` The memory threshold in bytes before a data batch is flushed to the server. When the internal buffer of a `TopicWriter` exceeds this value, it triggers a serialization and transmission event. Larger values increase throughput by reducing network overhead but require more client-side memory. ### max\_batch\_size\_records `instance-attribute` ¶ ``` max_batch_size_records ``` The threshold in row (record) count before a data batch is flushed to the server. A flush is triggered whenever **either** this record limit or the `max_batch_size_bytes` limit is reached, ensuring that data is transmitted regularly even for topics with very small individual records. ## mosaicolabs.handlers.SequenceWriter ¶ ``` SequenceWriter( *, sequence_name, client, connection_pool, executor_pool, metadata, config, ) ``` Bases: `BaseSequenceWriter` Orchestrates the creation and data ingestion lifecycle of a Mosaico Sequence. The `SequenceWriter` is the central controller for high-performance data writing. It manages the transition of a sequence through its lifecycle states: **Create** -> **Write** -> **Finalize**. ##### Key Responsibilities¶ * **Lifecycle Management**: Coordinates creation, finalization, or abort signals with the server. * **Resource Distribution**: Implements a "Multi-Lane" architecture by distributing network connections from a Connection Pool and thread executors from an Executor Pool to individual `TopicWriter` instances. This ensures strict isolation and maximum parallelism between diverse data streams. Usage Pattern This class **must** be used within a `with` statement (Context Manager). The context entry triggers sequence registration on the server, while the exit handles automatic finalization or error cleanup based on the configured `OnErrorPolicy`. Obtaining a Writer Do not instantiate this class directly. Use the `MosaicoClient.sequence_create()` factory method. Internal constructor for SequenceWriter. **Do not call this directly.** Users must call `MosaicoClient.sequence_create()` to obtain an initialized writer. Example ``` from mosaicolabs import MosaicoClient, OnErrorPolicy # Open the connection with the Mosaico Client with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create( # (1)! sequence_name="mission_log_042", # Custom metadata for this data sequence. metadata={ "driver": { "driver_id": "drv_sim_017", "role": "validation", "experience_level": "senior", }, "location": { "city": "Milan", "country": "IT", "facility": "Downtown", "gps": { "lat": 45.46481, "lon": 9.19201, }, }, } on_error = OnErrorPolicy.Delete # Default ) as seq_writer: # Start creating topics and pushing data # (2)! # Exiting the block automatically flushes all topic buffers, finalizes the sequence on the server # and closes all connections and pools ``` 1. See also: `MosaicoClient.sequence_create()` 2. See also: * `SequenceWriter.topic_create()` * `TopicWriter.push()` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_name` | `str` | Unique name for the new sequence. | *required* | | `client` | `FlightClient` | The primary control FlightClient. | *required* | | `connection_pool` | `Optional[_ConnectionPool]` | Shared pool of data connections for parallel writing. | *required* | | `executor_pool` | `Optional[_ExecutorPool]` | Shared pool of thread executors for asynchronous I/O. | *required* | | `metadata` | `dict[str, Any]` | User-defined metadata dictionary. | *required* | | `config` | `WriterConfig` | Operational configuration (e.g., error policies, batch sizes). | *required* | ### sequence\_status `property` ¶ ``` sequence_status ``` Returns the current operational status of the sequence. Returns: | Type | Description | | --- | --- | | `SequenceStatus` | The `SequenceStatus`. | ### topic\_writer\_exists ¶ ``` topic_writer_exists(topic_name) ``` Checks if a `TopicWriter` has already been initialized for the given name. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic_name` | `str` | The name of the topic to check. | *required* | Returns: | Type | Description | | --- | --- | | `bool` | True if the topic writer exists locally, False otherwise. | ### list\_topic\_writers ¶ ``` list_topic_writers() ``` Returns the list of all topic names currently managed by this writer. ### get\_topic\_writer ¶ ``` get_topic_writer(topic_name) ``` Retrieves an existing `TopicWriter` instance from the internal cache. This method is particularly useful when ingesting data from unified recording formats where different sensor types (e.g., Vision, IMU, Odometry) are stored chronologically in a single stream or file. In these scenarios, messages for various topics appear in an interleaved fashion. Using `get_topic_writer` allows the developer to: * **Reuse Buffers:** Efficiently switch between writers for different sensor streams. * **Ensure Data Ordering:** Maintain a consistent batching logic for each topic as you iterate through a mixed-content log. * **Optimize Throughput:** Leverage Mosaico's background I/O by routing all data for a specific identifier through a single, persistent writer instance. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic_name` | `str` | The unique name or identifier of the topic writer to retrieve. | *required* | Returns: | Type | Description | | --- | --- | | `Optional[TopicWriter]` | The `TopicWriter` instance if it has been previously initialized within this `SequenceWriter` context, otherwise `None`. | Example Processing a generic interleaved sensor log (like a ROS bag or a custom JSON log): ``` from mosaicolabs import SequenceWriter, IMU, Image # Topic to Ontology Mapping: Defines the schema for each sensor stream # Example: {"/camera": Image, "/imu": IMU} topic_to_ontology = { ... } # Adapter Factory: Maps raw sensor payloads to Mosaico Ontology instances # Example: {"/imu": lambda p: IMU(acceleration=Vector3d.from_list(p['acc']), ...)} adapter = { ... } with client.sequence_create("physical_ai_trial_01") as seq_writer: # log_iterator represents an interleaved stream (e.g., ROSbags, MCAP, or custom logs). for ts, topic, payload in log_iterator: # Access the topic-specific buffer. # get_topic_writer retrieves a persistent writer from the internal cache twriter = seq_writer.get_topic_writer(topic) if twriter is None: # Dynamic Topic Registration. # If the topic is encountered for the first time, register it using the # pre-defined Ontology type to ensure data integrity. twriter = seq_writer.topic_create( topic_name=topic, ontology_type=topic_to_ontology[topic] ) # Data Transformation & Ingestion. # The adapter converts the raw payload into a validated Mosaico object. # push() handles high-performance batching and asynchronous I/O to the rust backend. twriter.push( # (1)! message=Message( timestamp_ns=ts, data=adapter[topic](payload), ) ) # SequenceWriter automatically calls _finalize() on all internal TopicWriters, # guaranteeing that every sensor measurement is safely committed to the platform. ``` 1. See also: `TopicWriter.push()` ### topic\_create ¶ ``` topic_create(topic_name, metadata, ontology_type) ``` Creates a new topic within the active sequence. This method performs a "Multi-Lane" resource assignment, granting the new `TopicWriter`, its own connection from the pool and a dedicated executor for background serialization and I/O. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic_name` | `str` | The relative name of the new topic. | *required* | | `metadata` | `dict[str, Any]` | Topic-specific user metadata. | *required* | | `ontology_type` | `Type[Serializable]` | The `Serializable` data model class defining the topic's schema. | *required* | Returns: | Type | Description | | --- | --- | | `Optional[TopicWriter]` | A `TopicWriter` instance configured for parallel ingestion, or `None` if creation fails. | Raises: | Type | Description | | --- | --- | | `RuntimeError` | If called outside of a `with` block. | Example ``` with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create(...) as seq_writer: # (1)! # Create individual Topic Writers # Each writer gets its own assigned resources from the pools imu_writer = seq_writer.topic_create( topic_name="sensors/imu", # The univocal topic name metadata={ # The topic/sensor custom metadata "vendor": "inertix-dynamics", "model": "ixd-f100", "firmware_version": "1.2.0", "serial_number": "IMUF-9A31D72X", "calibrated":"false", }, ontology_type=IMU, # The ontology type stored in this topic ) # Another individual topic writer for the GPS device gps_writer = seq_writer.topic_create( topic_name="sensors/gps", # The univocal topic name metadata={ # The topic/sensor custom metadata "role": "primary_gps", "vendor": "satnavics", "model": "snx-g500", "firmware_version": "3.2.0", "serial_number": "GPS-7C1F4A9B", "interface": { # (2)! "type": "UART", "baudrate": 115200, "protocol": "NMEA", }, }, # The topic/sensor custom metadata ontology_type=GPS, # The ontology type stored in this topic ) # Push data imu_writer.push( # (3)! message=Message( timestamp_ns=1700000000000, data=IMU(acceleration=Vector3d(x=0, y=0, z=9.81), ...), ) ) # ... # Exiting the block automatically flushes all topic buffers, finalizes the sequence on the server # and closes all connections and pools ``` 1. See also: `MosaicoClient.sequence_create()` 2. The metadata fields will be queryable via the `Query` mechanism. The mechanism allows creating query expressions like: `Topic.Q.user_metadata["interface.type"].eq("UART")`. See also: * `mosaicolabs.models.platform.Topic` * `mosaicolabs.models.query.builders.QueryTopic`. 3. See also: `TopicWriter.push()` ## mosaicolabs.handlers.TopicWriter ¶ ``` TopicWriter( *, topic_name, sequence_name, client, state, config ) ``` Manages a high-performance data stream for a single Mosaico topic. The `TopicWriter` abstracts the complexity of the PyArrow Flight `DoPut` protocol, handling internal buffering, serialization, and network transmission. It accumulates records in memory and automatically flushes them to the server when configured batch limits—defined by either byte size or record count—are exceeded. ##### Performance & Parallelism¶ If an executor pool is provided by the parent client, the `TopicWriter` performs data serialization on background threads, preventing I/O operations from blocking the main application logic. Obtaining a Writer End-users should not instantiate this class directly. Use the `SequenceWriter.topic_create()` factory method to obtain an active writer. Internal constructor for TopicWriter. **Do not call this directly.** Internal library modules should use the `_create()` factory. Users must call `SequenceWriter.topic_create()` to obtain an initialized writer. Example ``` with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create(...) as seq_writer: # (1)! # Create individual Topic Writers # Each writer gets its own assigned resources from the pools imu_writer = seq_writer.topic_create( # (2)! topic_name="sensors/imu", # The univocal topic name metadata={ # The topic/sensor custom metadata "vendor": "inertix-dynamics", "model": "ixd-f100", "firmware_version": "1.2.0", "serial_number": "IMUF-9A31D72X", "calibrated":"false", }, ontology_type=IMU, # The ontology type stored in this topic ) # Push data... imu_writer.push( # (3)! message=Message( data=IMU(acceleration=Vector3d(x=0, y=0, z=9.81), ...), timestamp_ns=1700000000000, ) ) # Exiting the seq_writer `with` block, the `_finalize()` method of all topic writers is called. ``` 1. See also: `MosaicoClient.sequence_create()` 2. See also: `SequenceWriter.topic_create()` 3. See also: `TopicWriter.push()` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic_name` | `str` | The name of the specific topic. | *required* | | `sequence_name` | `str` | The name of the parent sequence. | *required* | | `client` | `FlightClient` | The FlightClient used for data transmission. | *required* | | `state` | `_TopicWriteState` | The internal state object managing buffers and streams. | *required* | | `config` | `WriterConfig` | Operational configuration for batching and error handling. | *required* | ### name `property` ¶ ``` name ``` Returns the name of the topic ### push ¶ ``` push(message) ``` Adds a new record to the internal write buffer. Records are accumulated in memory. If a push triggers a batch limit, the buffer is automatically serialized and transmitted to the server. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `message` | `Message` | A pre-constructed Message object. | *required* | Raises: | Type | Description | | --- | --- | | `Exception` | If a buffer flush fails during the operation. | Example ``` with MosaicoClient.connect("localhost", 6726) as client: # Start the Sequence Orchestrator with client.sequence_create(...) as seq_writer: # (1)! # Create individual Topic Writers # Each writer gets its own assigned resources from the pools imu_writer = seq_writer.topic_create( # (2)! topic_name="sensors/imu", # The univocal topic name metadata={ # The topic/sensor custom metadata "vendor": "inertix-dynamics", "model": "ixd-f100", "firmware_version": "1.2.0", "serial_number": "IMUF-9A31D72X", "calibrated":"false", }, ontology_type=IMU, # The ontology type stored in this topic ) # Another individual topic writer for the GPS device gps_writer = seq_writer.topic_create( topic_name="sensors/gps", # The univocal topic name metadata={ # The topic/sensor custom metadata "role": "primary_gps", "vendor": "satnavics", "model": "snx-g500", "firmware_version": "3.2.0", "serial_number": "GPS-7C1F4A9B", "interface": { "type": "UART", "baudrate": 115200, "protocol": "NMEA", }, }, # The topic/sensor custom metadata ontology_type=GPS, # The ontology type stored in this topic ) gps_msg = Message(timestamp_ns=1700000000100, data=GPS(...)) gps_writer.push(message=gps_msg) # Exiting the seq_writer `with` block, the `_finalize()` method of all topic writers is called. ``` 1. See also: `MosaicoClient.sequence_create()` 2. See also: `SequenceWriter.topic_create()` ### is\_active ¶ ``` is_active() ``` Returns `True` if the writing stream is open and the writer accepts new messages. --- ## mosaicolabs.models.query.builders ¶ This module provides the high-level "Fluent" API for constructing complex searches across the Mosaico Data Platform. It implements a Domain-Specific Language that allows users to filter **Sequences**, **Topics**, and **Ontology** data using a type-safe, method-chaining interface. **Key Components:** * **`Query`**: The root container that aggregates multiple specialized sub-queries. * **`QueryOntologyCatalog`**: For fine-grained filtering based on sensor-specific field values (e.g., `IMU.Q.acceleration.x > 9.8`). * **`QueryTopic`**: Specifically for filtering topic-level metadata. * **`QuerySequence`**: Specifically for filtering sequence-level metadata. ### QueryOntologyCatalog ¶ ``` QueryOntologyCatalog( *expressions, include_timestamp_range=None ) ``` A top-level query object for the Data Catalog that combines multiple sensor-field expressions. This builder allows for fine-grained filtering based on the actual values contained within sensor payloads (e.g., IMU acceleration, GPS coordinates, or custom telemetry). It produces a "flat" dictionary output where field paths utilize dot-notation (e.g., `"imu.acceleration.x"`). This class is designed to work with the **`.Q` query proxy** injected into every `Serializable` data ontology model. You can use this proxy on any registered sensor class (like `IMU`, `Vector3d`, `Point3d`), etc. to create type-safe expressions. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.x.lt(-4.0)) # Using constructor .with_expression(IMU.Q.acceleration.y.gt(5.0)) # Using with_expression ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.x.lt(-4.0), include_timestamp_range=True) .with_expression(IMU.Q.acceleration.y.gt(5.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` The constructor initializes the query with an optional list of `_QueryCatalogExpression` objects, generated via `.Q.` proxy, where model is any of the available data ontology (e.g. IMU.Q, GPS.Q, String.Q, etc.) Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*expressions` | `_QueryExpression` | A variable number of expressions, generated via the `.Q` proxy on an ontology model. | `()` | | `include_timestamp_range` | `Optional[bool]` | If `True`, the server will return the `start` and `end` timestamps corresponding to the temporal bounds of the matched data. | `None` | Raises: | Type | Description | | --- | --- | | `TypeError` | If an expression is not of the supported type. | | `ValueError` | If an operator does not start with the required '$' prefix. | | `NotImplementedError` | If a duplicate key (field path) is detected within the same query. | #### with\_expression ¶ ``` with_expression(expr) ``` Adds a new `_QueryCatalogExpression` expression to the query using a fluent interface. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Chain multiple sensor filters together qresponse = client.query( QueryOntologyCatalog() .with_expression(GPS.Q.status.satellites.geq(8)) .with_expression(GPS.Q.position.x.between([44.0, 45.0])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(include_timestamp_range=True) .with_expression(IMU.Q.acceleration.x.lt(-4.0)) .with_expression(IMU.Q.acceleration.y.gt(5.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `expr` | `_QueryExpression` | A valid expression generated via the `.Q` proxy on an ontology model, e.g., `GPS.Q.status.satellites.leq(10)`. | *required* | Returns: | Type | Description | | --- | --- | | `QueryOntologyCatalog` | The `QueryOntologyCatalog` instance for method chaining. | #### name ¶ ``` name() ``` Returns the top-level key ('ontology') used for nesting inside a root `Query`. #### to\_dict ¶ ``` to_dict() ``` Serializes the ontology expressions into a flat dictionary for the platform API. Example Output `{"imu.timestamp_ns": {"$between": [...]}, "imu.acceleration.x": {"$leq": 10}}` Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | A dictionary containing all merged sensor-field expressions. | ### QueryTopic ¶ ``` QueryTopic(*expressions) ``` A top-level query object for Topic data that combines multiple expressions with a logical AND. This builder handles the complex partitioning required to query both flat system fields (like `name` or `ontology_tag`) and nested dictionary fields (like `user_metadata`). The resulting dictionary output preserves this hierarchical structure for server-side processing. Example ``` from mosaicolabs import MosaicoClient, Image, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Query for all 'image' topics created in a specific timeframe, matching some metadata (key, value) pair qresponse = client.query( QueryTopic() .with_ontology_tag(Image.ontology_tag()) .with_created_timestamp(time_start=Time.from_float(1700000000)) .with_expression(Topic.Q.user_metadata["camera_id.serial_number"].eq("ABC123_XYZ")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` The constructor initializes the query with an optional list of `_QueryTopicExpression` objects, generated via `Topic.Q.` proxy. This builder leverages the **`.Q` query proxy** on the `user_metadata` field of the `Topic` model to provide a type-safe, fluent interface for filtering. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*expressions` | `_QueryExpression` | A variable number of `Topic.Q` (`_QueryTopicExpression`) expression objects. | `()` | Raises: | Type | Description | | --- | --- | | `TypeError` | If an expression is not of the supported `Topic.Q` type. | | `ValueError` | If an operator does not follow the required internal '$' prefix format. | | `NotImplementedError` | If a duplicate key is detected, as the current implementation enforces unique keys per query. | #### with\_expression ¶ ``` with_expression(expr) ``` Adds a new expression to the query using a fluent interface. This is the way to add filters for nested metadata. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Target a specific known topic path qresponse = client.query( QueryTopic().with_expression(Topic.Q.user_metadata["version"].eq("1.0")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `expr` | `_QueryExpression` | A `_QueryTopicExpression` constructed via a `Topic.Q` proxy. | *required* | Returns: | Type | Description | | --- | --- | | `QueryTopic` | The `QueryTopic` instance for method chaining. | #### with\_name ¶ ``` with_name(name) ``` Adds an exact match filter for the topic 'name' field. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Target a specific known topic path qresponse = client.query( QueryTopic().with_name("vehicle/front/camera") ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `name` | `str` | The exact name of the topic to match. | *required* | Returns: | Type | Description | | --- | --- | | `QueryTopic` | The `QueryTopic` instance for method chaining. | #### with\_name\_match ¶ ``` with_name_match(name) ``` Adds a partial (fuzzy) match filter for the topic 'name' field. This performs an 'in-between' search (equivalent to %name%) on the full `sequence/topic` path. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Search for all topics containing the word 'camera' qresponse = client.query( QueryTopic().with_name_match("camera") ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `name` | `str` | The string pattern to search for within the topic name. | *required* | Returns: | Type | Description | | --- | --- | | `QueryTopic` | The `QueryTopic` instance for method chaining. | #### with\_ontology\_tag ¶ ``` with_ontology_tag(ontology_tag) ``` Adds an exact match filter for the 'ontology\_tag' field. This filter restricts the search to topics belonging to a specific data type identifier (e.g., 'imu', 'gnss'). Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for IMU-only data streams qresponse = client.query( QueryTopic().with_ontology_tag(IMU.ontology_tag()) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` **Note**: To ensure compatibility and avoid hardcoding strings, it is highly recommended to retrieve the tag dynamically using the `ontology_tag()` method of the desired ontology class. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `ontology_tag` | `str` | The string tag (e.g., 'imu', 'gps') to filter by. | *required* | Returns: | Type | Description | | --- | --- | | `QueryTopic` | The `QueryTopic` instance for method chaining. | #### with\_created\_timestamp ¶ ``` with_created_timestamp(time_start=None, time_end=None) ``` Adds a filter for the 'created\_timestamp' field using high-precision Time. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Find sequences created during a specific day qresponse = client.query( QueryTopic().with_created_timestamp( time_start=Time.from_float(1704067200.0), # 2024-01-01 time_end=Time.from_float(1704153600.0) # 2024-01-02 ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `time_start` | `Optional[Time]` | Optional lower bound (inclusive). | `None` | | `time_end` | `Optional[Time]` | Optional upper bound (inclusive). | `None` | Returns: | Type | Description | | --- | --- | | `QueryTopic` | The `QueryTopic` instance for method chaining. | Raises: | Type | Description | | --- | --- | | `ValueError` | If both bounds are None or if `time_start > time_end`. | #### name ¶ ``` name() ``` Returns the top-level key ('topic') used when nesting this query inside a root `Query`. #### to\_dict ¶ ``` to_dict() ``` Serializes the query into a nested dictionary for the platform API. This method partitions expressions into two groups: 1. **System Fields**: Standard fields like `name` are kept in the root dictionary. 2. **Metadata Fields**: Fields starting with a dictionary-type model key (e.g., `user_metadata`) are stripped of their prefix and nested under that key. Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | A dictionary representation of the query, e.g., `{"name": {"$eq": "..."}, "user_metadata": {"key": {"$eq": "..."}}}`. | ### QuerySequence ¶ ``` QuerySequence(*expressions) ``` A top-level query object for Sequence data that combines multiple expressions with a logical AND. This builder handles the complex partitioning required to query both flat system fields (like `name`) and nested dictionary fields (like `user_metadata`). The resulting dictionary output preserves this hierarchical structure for server-side processing. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Search for sequences by project name and creation date qresponse = client.query( QuerySequence() .with_expression(Sequence.Q.user_metadata["project"].eq("Apollo")) .with_created_timestamp(time_start=Time.from_float(1690000000.0)) ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` The constructor initializes the query with an optional list of `_QuerySequenceExpression` objects, generated via `Sequence.Q.` proxy. This builder leverages the **`.Q` query proxy** specifically on the `user_metadata` field of the `Sequence` model to provide a type-safe, fluent interface for filtering. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*expressions` | `_QueryExpression` | A variable number of `Sequence.Q` (`_QuerySequenceExpression`) objects. | `()` | Raises: | Type | Description | | --- | --- | | `TypeError` | If an expression is not of the supported `Sequence.Q` type. | | `ValueError` | If an operator does not follow the required internal '$' prefix format. | | `NotImplementedError` | If a duplicate key is detected, as the current implementation enforces unique keys per query. | #### with\_expression ¶ ``` with_expression(expr) ``` Adds a new expression to the query using a fluent interface. This is the way to add filters for nested metadata. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Target a specific known topic path qresponse = client.query( QuerySequence().with_expression(Sequence.Q.user_metadata["project"].eq("Apollo")) ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `expr` | `_QueryExpression` | A `_QuerySequenceExpression` constructed via a `Sequence.Q` proxy. | *required* | Returns: | Type | Description | | --- | --- | | `QuerySequence` | The `QuerySequence` instance for method chaining. | #### with\_name ¶ ``` with_name(name) ``` Adds an exact match filter for the sequence 'name' field. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Find all sequences with name equal to 'test_winter_01' qresponse = client.query( QuerySequence().with_name("test_winter_01") ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `name` | `str` | The exact name of the sequence to match. | *required* | Returns: | Type | Description | | --- | --- | | `QuerySequence` | The `QuerySequence` instance for method chaining. | #### with\_name\_match ¶ ``` with_name_match(name) ``` Adds a partial (fuzzy) match filter for the sequence 'name' field. This performs an 'in-between' search (equivalent to %name%) on the sequence name. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Find all sequences with name containing 'calibration_run_' qresponse = client.query( QuerySequence().with_name_match("calibration_run_") ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `name` | `str` | The string pattern to search for within the sequence name. | *required* | Returns: | Type | Description | | --- | --- | | `QuerySequence` | The `QuerySequence` instance for method chaining. | #### with\_created\_timestamp ¶ ``` with_created_timestamp(time_start=None, time_end=None) ``` Adds a filter for the 'created\_timestamp' field using high-precision Time. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Find sequences created during a specific time range qresponse = client.query( QuerySequence().with_created_timestamp( time_start=Time.from_float(1704067200.0), # 2024-01-01 time_end=Time.from_float(1704153600.0) # 2024-01-02 ) ) # Inspect the response for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `time_start` | `Optional[Time]` | Optional lower bound (inclusive). | `None` | | `time_end` | `Optional[Time]` | Optional upper bound (inclusive). | `None` | Returns: | Type | Description | | --- | --- | | `QuerySequence` | The `QuerySequence` instance for method chaining. | Raises: | Type | Description | | --- | --- | | `ValueError` | If both bounds are `None` or if `time_start > time_end`. | #### name ¶ ``` name() ``` Returns the top-level key ('sequence') used for nesting inside a root `Query`. #### to\_dict ¶ ``` to_dict() ``` Serializes the query into a nested dictionary for the platform API. This method partitions expressions into: 1. **Normal Fields**: Fields like `name` are kept in a flat dictionary. 2. **Metadata Fields**: Fields targeting `user_metadata` are collected and nested. Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | A dictionary representation preserving the hierarchical structure. | ### Query ¶ ``` Query(*queries) ``` A top-level "root" query object that aggregates multiple specialized sub-queries into a single request body. This class serves as the final envelope for multi-domain queries, ensuring that different query types (Topic, Sequence, Ontology) do not overwrite each other. Example ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, Query, IMU, MosaicoClient # Establish a connection to the Mosaico Data Platform with MosaicoClient.connect("localhost", 6726) as client: # Build a filter with name pattern and metadata-related expression query = Query( # Append a filter for sequence metadata QuerySequence() .with_expression( # Use query proxy for generating a _QuerySequenceExpression Sequence.Q.user_metadata["environment.visibility"].lt(50) ) .with_name_match("test_drive"), # Append a filter with deep time-series data discovery and measurement time windowing QueryOntologyCatalog(include_timestamp_range=True) .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.header.stamp.sec.gt(1700134567)) .with_expression(IMU.Q.header.stamp.nanosec.between([123456, 789123])), ) # Perform the server side query qresponse = client.query(query=query) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` Initializes the root query with a set of sub-queries. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*queries` | `QueryableProtocol` | A variable number of sub-query objects (e.g., `QueryTopic()`, `QuerySequence()`). | `()` | Raises: | Type | Description | | --- | --- | | `ValueError` | If duplicate query types are detected in the initial arguments. | #### append ¶ ``` append(*queries) ``` Adds additional sub-queries to the existing root query. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `*queries` | `QueryableProtocol` | Additional sub-query instances. | `()` | Raises: | Type | Description | | --- | --- | | `ValueError` | If an appended query type is already present in the request. | Example ``` from mosaicolabs import QueryOntologyCatalog, QuerySequence, Query, IMU, MosaicoClient # Build a filter with name pattern and metadata-related expression query = Query( # Append a filter for sequence metadata QuerySequence() .with_expression( # Use query proxy for generating a _QuerySequenceExpression Sequence.Q.user_metadata["environment.visibility"].lt(50) ) .with_name_match("test_drive") ) # Append a filter with deep time-series data discovery and measurement time windowing query.append( QueryOntologyCatalog() .with_expression(IMU.Q.acceleration.x.gt(5.0)) .with_expression(IMU.Q.header.stamp.sec.gt(1700134567)) .with_expression(IMU.Q.header.stamp.nanosec.between([123456, 789123])), ) ``` #### to\_dict ¶ ``` to_dict() ``` Serializes the entire multi-domain query into the final JSON dictionary. It orchestrates the conversion by calling the `.name()` and `.to_dict()` methods of each contained sub-query. Example Output ``` { "topic": { ... topic filters ... }, "sequence": { ... sequence filters ... }, "ontology": { ... ontology filters ... } } ``` Returns: | Type | Description | | --- | --- | | `Dict[str, Any]` | The final aggregated query dictionary. | --- ## mosaicolabs.models.query.protocols.QueryableProtocol ¶ Bases: `Protocol` Structural protocol for classes that integrate into a multi-domain `Query`. A class implicitly satisfies this protocol if it provides a unique identification tag via `name()` and a serialization method via `to_dict()`. This protocol ensures that the root `Query` or the can orchestrate complex requests without knowing the specific internal logic of each sub-query. ##### Reference Implementations¶ The following classes are standard examples of this protocol: * `QueryTopic`: Filters Topic-level metadata. * `QuerySequence`: Filters Sequence-level metadata. * `QueryOntologyCatalog`: Filters fine-grained sensor field data. ### with\_expression ¶ ``` with_expression(expr) ``` Appends a new filter expression using a fluent interface. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `expr` | `_QueryExpression` | A valid `_QueryExpression` | *required* | ### name ¶ ``` name() ``` Returns the unique key identifying this sub-query within the root request. Examples include `"topic"`, `"sequence"`, or `"ontology"`. ### to\_dict ¶ ``` to_dict() ``` Serializes the internal expressions into a platform-compatible dictionary. ## mosaicolabs.models.query.expressions.\_QueryExpression ¶ ``` _QueryExpression(full_path, op, value) ``` Base class for all atomic comparison operations in the Mosaico Query DSL. A `_QueryExpression` represents the smallest indivisible unit of a query. It is typically not instantiated directly by the user, but is instead the result of a terminal method call on a queryable field (e.g., `.gt()`, `.eq()`, `.between()`) via the **`.Q` query proxy**. The class manages the expression lifecycle in a Query: 1. **Generation**: A user calls `IMU.Q.acceleration.x.gt(9.8)`, which generates a `_QueryCatalogExpression` (a subclass of this class). 2. **Validation**: A Builder receives the expression and validates its type, operator format, and key uniqueness. 3. **Serialization**: The builder calls `.to_dict()` on the expression to transform it into the specific JSON format expected by the platform. Attributes: | Name | Type | Description | | --- | --- | --- | | `full_path` | | The complete, dot-separated path to the target field on the platform. | | `op` | | The Mosaico-compliant operator string (e.g., `"$eq"`, `"$gt"`, `"$between"`). | | `value` | | The comparison value or data structure (e.g., a constant, a list for `$in`, or a range for `$between`). | Initializes an atomic comparison. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `full_path` | `str` | The dot-separated field path used in the final query dictionary. | *required* | | `op` | `str` | The short-string operation identifier (must start with `$`). | *required* | | `value` | `Any` | The constant value for the comparison. | *required* | ### to\_dict ¶ ``` to_dict() ``` Converts the expression into its final dictionary format. Example `{"gps.status.service": {"$eq": 0}}` ## mosaicolabs.models.query.expressions.\_QueryTopicExpression ¶ ``` _QueryTopicExpression(full_path, op, value) ``` Bases: `_QueryExpression` An atomic comparison unit specialized for the **Topic Catalog** context. This class is utilized exclusively by the `QueryTopic` builder to filter topics based on system attributes (like `name` or `ontology_tag`) and nested user metadata. The `QueryTopic` class enforces that all provided expressions are instances of this type to prevent cross-domain query contamination. **Internal Translation Example:** | User Call | Internal Translation | | --- | --- | | `Topic.Q.user_metadata["calibrated"].eq(True)` | `_QueryTopicExpression("user_metadata.calibrated", "$eq", True)` | | `QueryTopic().with_name("camera_front")` | `_QueryTopicExpression("name", "$eq", "camera_front")` | | `QueryTopic().with_ontology_tag("imu")` | `_QueryTopicExpression("ontology_tag", "$eq", "imu")` | Initializes an atomic comparison. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `full_path` | `str` | The dot-separated field path used in the final query dictionary. | *required* | | `op` | `str` | The short-string operation identifier (must start with `$`). | *required* | | `value` | `Any` | The constant value for the comparison. | *required* | ### to\_dict ¶ ``` to_dict() ``` Converts the expression into its final dictionary format. Example `{"gps.status.service": {"$eq": 0}}` ## mosaicolabs.models.query.expressions.\_QuerySequenceExpression ¶ ``` _QuerySequenceExpression(full_path, op, value) ``` Bases: `_QueryExpression` An atomic comparison unit specialized for the **Sequence Catalog** context. This class represents filters targeting high-level sequence containers. It is the only expression type accepted by the `QuerySequence` builder. It handles fields such as the sequence `name`, `created_timestamp`, or custom entries within the sequence's `user_metadata`. **Internal Translation Example:** | User Call | Internal Translation | | --- | --- | | `Sequence.Q.user_metadata["project"].eq("Apollo")` | `_QuerySequenceExpression("user_metadata.project", "$eq", "Apollo")` | | `QuerySequence().with_name("Apollo")` | `_QuerySequenceExpression("name", "$eq", "Apollo")` | | `QuerySequence().with_created_timestamp(Time.from_float(1704067200.0))` | `_QuerySequenceExpression("created_timestamp", "$between", [1704067200.0, None])` | Initializes an atomic comparison. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `full_path` | `str` | The dot-separated field path used in the final query dictionary. | *required* | | `op` | `str` | The short-string operation identifier (must start with `$`). | *required* | | `value` | `Any` | The constant value for the comparison. | *required* | ### to\_dict ¶ ``` to_dict() ``` Converts the expression into its final dictionary format. Example `{"gps.status.service": {"$eq": 0}}` ## mosaicolabs.models.query.expressions.\_QueryCatalogExpression ¶ ``` _QueryCatalogExpression(full_path, op, value) ``` Bases: `_QueryExpression` An atomic comparison unit specialized for **Data Ontology** (Sensor Payload) filtering. This expression type is used by the `QueryOntologyCatalog` builder to filter actual sensor data values across the entire platform. Because ontology queries target specific fields within a sensor payload (e.g., accelerometer readings), these expressions use fully qualified dot-notated paths prefixed by the ontology tag. **Internal Translation Example:** | User Call | Internal Translation | | --- | --- | | `IMU.Q.acceleration.x.gt(9.8)` | `_QueryCatalogExpression("imu.acceleration.x", "$gt", 9.8)` | | `IMU.Q.acceleration.y.gt(9.8)` | `_QueryCatalogExpression("imu.acceleration.y", "$gt", 9.8)` | | `IMU.Q.acceleration.z.gt(9.8)` | `_QueryCatalogExpression("imu.acceleration.z", "$gt", 9.8)` | | `IMU.Q.acceleration.x.gt(9.8)` | `_QueryCatalogExpression("imu.acceleration.x", "$gt", 9.8)` | Initializes an atomic comparison. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `full_path` | `str` | The dot-separated field path used in the final query dictionary. | *required* | | `op` | `str` | The short-string operation identifier (must start with `$`). | *required* | | `value` | `Any` | The constant value for the comparison. | *required* | ### to\_dict ¶ ``` to_dict() ``` Converts the expression into its final dictionary format. Example `{"gps.status.service": {"$eq": 0}}` --- ## mosaicolabs.models.query.response ¶ ### TimestampRange `dataclass` ¶ ``` TimestampRange(start, end) ``` Represents a temporal window defined by a start and end timestamp. This utility class is used to define the bounds of sensor data or sequences within the Mosaico archive. Attributes: | Name | Type | Description | | --- | --- | --- | | `start` | `int` | The beginning of the range (inclusive), typically in nanoseconds. | | `end` | `int` | The end of the range (inclusive), typically in nanoseconds. | ### QueryResponseItemSequence `dataclass` ¶ ``` QueryResponseItemSequence(name) ``` Metadata container for a single sequence discovered during a query. Attributes: | Name | Type | Description | | --- | --- | --- | | `name` | `str` | The unique identifier of the sequence in the Mosaico database. | ### QueryResponseItemTopic `dataclass` ¶ ``` QueryResponseItemTopic(name, timestamp_range) ``` Metadata for a specific topic (sensor stream) within a sequence. Contains information about the topic's identity and its available time range in the archive. Attributes: | Name | Type | Description | | --- | --- | --- | | `name` | `str` | The name of the topic (e.g., 'front\_camera/image\_raw'). | | `timestamp_range` | `Optional[TimestampRange]` | The availability window of the data for this specific topic. | ### QueryResponseItem `dataclass` ¶ ``` QueryResponseItem(sequence, topics) ``` A unified result item representing a sequence and its associated topics. This serves as the primary unit of data returned when querying the Mosaico metadata catalog. Attributes: | Name | Type | Description | | --- | --- | --- | | `sequence` | `QueryResponseItemSequence` | The parent sequence metadata. | | `topics` | `List[QueryResponseItemTopic]` | The list of topics available within this sequence that matched the query criteria. | ### QueryResponse `dataclass` ¶ ``` QueryResponse(items=list()) ``` An iterable collection of results returned by a Mosaico metadata query. This class provides convenience methods to transform search results back into query builders, enabling a fluid, multi-stage filtering workflow. Example ``` from mosaicolabs import MosaicoClient, IMU, Floating64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter IMU data by a specific acquisition second qresponse = client.query( QueryOntologyCatalog(IMU.Q.header.stamp.sec.lt(1770282868)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter primitive Floating64 telemetry by frame identifier qresponse = client.query( QueryOntologyCatalog(Floating64.Q.header.frame_id.eq("robot_base")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` Attributes: | Name | Type | Description | | --- | --- | --- | | `items` | `List[QueryResponseItem]` | The list of items matching the query. | #### to\_query\_sequence ¶ ``` to_query_sequence() ``` Converts the current response into a QuerySequence builder. This allows for further filtering or operations on the specific set of sequences returned in this response. Example This demonstrates query chaining to narrow your search to specific sequences and topics. This is necessary when criteria span different data channels; otherwise, the resulting filters chained in `AND` in a single query would produce an empty result. ``` from mosaicolabs import MosaicoClient, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Broad Search: Find sequences with high-precision GPS initial_response = client.query(QueryOntologyCatalog(GPS.Q.status.status.eq(2))) # Chaining: Use results to "lock" the domain and find specific data in those sequences # on different data channels if not initial_response.is_empty(): final_response = client.query( initial_response.to_query_sequence(), # The "locked" sequence domain QueryTopic().with_name("/localization/log_string"), # Target a specific log topic QueryOntologyCatalog(String.Q.data.match("[ERR]")) # Filter by content ) ``` Returns: | Name | Type | Description | | --- | --- | --- | | `QuerySequence` | `QuerySequence` | A builder initialized with an '$in' filter on the sequence names. | Raises: | Type | Description | | --- | --- | | `ValueError` | If the response is empty. | #### to\_query\_topic ¶ ``` to_query_topic() ``` Converts the current response into a QueryTopic builder. Useful for narrowing down a search to specific topics found within the retrieved sequences. Example ``` from mosaicolabs import MosaicoClient, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Broad Search: Find sequences with high-precision GPS initial_response = client.query( QueryTopic().with_name("/localization/log_string"), # Target a specific log topic QuerySequence().with_name_match("test_winter_2025_") # Filter by content ) # Chaining: Use results to "lock" the domain and find specific log-patterns in those sequences if not initial_response.is_empty(): final_response = client.query( initial_response.to_query_topic(), # The "locked" topic domain QueryOntologyCatalog(String.Q.data.match("[ERR]")) # Filter by content ) ``` Returns: | Name | Type | Description | | --- | --- | --- | | `QueryTopic` | `QueryTopic` | A builder initialized with an '$in' filter on the topic names. | Raises: | Type | Description | | --- | --- | | `ValueError` | If the response is empty. | #### is\_empty ¶ ``` is_empty() ``` Returns True if the response contains no results. --- ## mosaicolabs.models.BaseModel ¶ Bases: `BaseModel` The root base class for SDK data models. It inherits from `pydantic.BaseModel` to provide runtime type checking and initialization logic. It adds a hook for defining the corresponding PyArrow structure (`__msco_pyarrow_struct__`), enabling the SDK to auto-generate Flight schemas. Note This class has been added mainly for wrapping pydantic, toward future implementation where other fields mapping and checks are implemented ## mosaicolabs.models.Message ¶ Bases: `BaseModel` The universal transport envelope for Mosaico data. The `Message` class wraps a polymorphic `Serializable` payload with middleware metadata, such as recording timestamps and headers. Attributes: | Name | Type | Description | | --- | --- | --- | | `timestamp_ns` | `Optional[int]` | Message/Sensor acquisition timestamp in nanoseconds (resambles the data ontology high precision time header). | | `data` | `Serializable` | The actual ontology data payload (e.g., an IMU or GPS instance). | | `recording_timestamp_ns` | `Optional[int]` | Recording timestamp in nanoseconds. This is the timestamp in which the message was recorded in the receiving store file (like rosbags, parquet files, etc.), different from sensor acquisition time. | ### data `instance-attribute` ¶ ``` data ``` The actual ontology data payload (e.g., an IMU or GPS instance). ### timestamp\_ns `class-attribute` `instance-attribute` ¶ ``` timestamp_ns = None ``` Message/Sensor acquisition timestamp in nanoseconds (resambles the data ontology high precision time header). Can be omitted if the data ontology already contains the timestamp (e.g. `data.header.stamp`) or the `recording_timestamp_ns` is set. If all timestamps data are None, the message will be rejected and a `ValueError` is raised. ### recording\_timestamp\_ns `class-attribute` `instance-attribute` ¶ ``` recording_timestamp_ns = None ``` Recording timestamp in nanoseconds (different from sensor acquisition time). This is the timestamp in which the message was recorded in the receiving store file (like rosbags, parquet files, etc.) ### model\_post\_init ¶ ``` model_post_init(context) ``` Validates the message structure after initialization. Ensures that there are no field name collisions between the envelope (e.g., `timestamp_ns`) and the data payload. ### ontology\_type ¶ ``` ontology_type() ``` Retrieves the class type of the ontology object stored in the `data` field. ### ontology\_tag ¶ ``` ontology_tag() ``` Returns the unique ontology tag name associated with the object in the data field. ### get\_data ¶ ``` get_data(target_type) ``` Safe, type-hinted accessor for the data payload. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `target_type` | `Type[TSerializable]` | The expected `Serializable` subclass type. | *required* | Returns: | Type | Description | | --- | --- | | `TSerializable` | The data object cast to the requested type. | Raises: | Type | Description | | --- | --- | | `TypeError` | If the actual data type does not match the requested `target_type`. | Example ``` # Get the IMU data from the message image_data = message.get_data(Image) print(f"Message time: {message.timestamp_ns}: Sensor time: {image_data.header.stamp.to_nanoseconds()}") print(f"Message time: {message.timestamp_ns}: Image size: {image_data.height}x{image_data.width}") # Show the image image_data.to_pillow().show() # Get the Floating64 data from the message floating64_data = message.get_data(Floating64) print(f"Message time: {message.timestamp_ns}: Data time: {floating64_data.header.stamp.to_nanoseconds()}") print(f"Message time: {message.timestamp_ns}: Data value: {floating64_data.data}") ``` ### from\_dataframe\_row `staticmethod` ¶ ``` from_dataframe_row( row, topic_name, timestamp_column_name="timestamp_ns" ) ``` Reconstructs a `Message` object from a flattened DataFrame row. In the Mosaico Data Platform, DataFrames represent topics using a nested naming convention: `{topic}.{tag}.{field}`. This method performs **Smart Reconstruction** by: 1. **Topic Validation**: Verifying if any columns associated with the `topic_name` exist in the row. 2. **Tag Inference**: Inspecting the column headers to automatically determine the original ontology tag (e.g., `"imu"`). 3. **Data Extraction**: Stripping prefixes and re-nesting the flat columns into their original dictionary structures. 4. **Type Casting**: Re-instantiating the specific `Serializable` subclass and wrapping it in a `Message` envelope. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `row` | `Series` | A single row from a Pandas DataFrame, representing a point in time across one or more topics. | *required* | | `topic_name` | `str` | The name of the specific topic to extract from the row. | *required* | | `timestamp_column_name` | `str` | The name of the column containing the timestamp. | `'timestamp_ns'` | Returns: | Type | Description | | --- | --- | | `Optional[Message]` | A reconstructed `Message` instance containing the typed ontology data, or `None` if the topic is not present or the data is incomplete. | Example ``` # Obtain a dataframe with DataFrameExtractor from mosaicolabs import MosaicoClient, IMU, Image from mosaicolabs.ml import DataFrameExtractor, SyncTransformer with MosaicoClient.connect("localhost", 6726) as client: sequence_handler = client.get_sequence_handler("example_sequence") for df in DataFrameExtractor(sequence_handler).to_pandas_chunks( topics = ["/front/imu", "/front/camera/image_raw"] ): # Do something with the dataframe. # For example, you can sync the data using the `SyncTransformer`: sync_transformer = SyncTransformer( target_fps = 30, # resample at 30 Hz and fill the Nans with a Hold policy ) synced_df = sync_transformer.transform(df) # Reconstruct the image message from a dataframe row image_msg = Message.from_dataframe_row(synced_df, "/front/camera/image_raw") image_data = image_msg.get_data(Image) # Show the image image_data.to_pillow().show() # ... ``` ## mosaicolabs.models.Serializable ¶ Bases: `BaseModel`, `_QueryProxyMixin` The base class for all Mosaico ontology data payloads. This class serves as the root for every sensor and data type in the Mosaico ecosystem. By inheriting from `Serializable`, data models are automatically compatible with the platform's storage, querying, and serialization engines. ##### Dynamic Attributes Injection¶ When you define a subclass, several key attributes are automatically managed or required. Understanding these is essential for customizing how your data is treated by the platform: * **`__serialization_format__`**: Determines the batching strategy and storage optimization. + **Role**: It tells the `SequenceWriter` whether to flush data based on byte size (optimal for heavy data like `Images`) or record count (optimal for light telemetry like `IMU`). + **Default**: `SerializationFormat.Default`. * **`__ontology_tag__`**: The unique string identifier for the class (e.g., `"imu"`, `"gps_raw"`). + **Role**: This tag is used in the global registry to reconstruct objects from raw platform data. + **Generation**: If not explicitly provided, it is auto-generated by converting the class name from `CamelCase` to `snake_case`. * **`__class_type__`**: A reference to the concrete class itself. + **Role**: Injected during initialization to facilitate polymorphic instantiation and safe type-checking when extracting data from a `Message`. ##### Requirements for Custom Ontologies¶ To create a valid custom ontology, your subclass must: 1. Inherit from `Serializable`. 2. Define a `__msco_pyarrow_struct__` attribute using `pa.StructType` to specify the physical schema. 3. Define the class fields (using Pydantic syntax) matching the Arrow structure. Automatic Registration Any subclass of `Serializable` is automatically registered in the global Mosaico registry upon definition. This enables the use of the factory methods and the `.Q` query proxy immediately. ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.Message ¶ Bases: `BaseModel` The universal transport envelope for Mosaico data. The `Message` class wraps a polymorphic `Serializable` payload with middleware metadata, such as recording timestamps and headers. Attributes: | Name | Type | Description | | --- | --- | --- | | `timestamp_ns` | `Optional[int]` | Message/Sensor acquisition timestamp in nanoseconds (resambles the data ontology high precision time header). | | `data` | `Serializable` | The actual ontology data payload (e.g., an IMU or GPS instance). | | `recording_timestamp_ns` | `Optional[int]` | Recording timestamp in nanoseconds. This is the timestamp in which the message was recorded in the receiving store file (like rosbags, parquet files, etc.), different from sensor acquisition time. | ### data `instance-attribute` ¶ ``` data ``` The actual ontology data payload (e.g., an IMU or GPS instance). ### timestamp\_ns `class-attribute` `instance-attribute` ¶ ``` timestamp_ns = None ``` Message/Sensor acquisition timestamp in nanoseconds (resambles the data ontology high precision time header). Can be omitted if the data ontology already contains the timestamp (e.g. `data.header.stamp`) or the `recording_timestamp_ns` is set. If all timestamps data are None, the message will be rejected and a `ValueError` is raised. ### recording\_timestamp\_ns `class-attribute` `instance-attribute` ¶ ``` recording_timestamp_ns = None ``` Recording timestamp in nanoseconds (different from sensor acquisition time). This is the timestamp in which the message was recorded in the receiving store file (like rosbags, parquet files, etc.) ### model\_post\_init ¶ ``` model_post_init(context) ``` Validates the message structure after initialization. Ensures that there are no field name collisions between the envelope (e.g., `timestamp_ns`) and the data payload. ### ontology\_type ¶ ``` ontology_type() ``` Retrieves the class type of the ontology object stored in the `data` field. ### ontology\_tag ¶ ``` ontology_tag() ``` Returns the unique ontology tag name associated with the object in the data field. ### get\_data ¶ ``` get_data(target_type) ``` Safe, type-hinted accessor for the data payload. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `target_type` | `Type[TSerializable]` | The expected `Serializable` subclass type. | *required* | Returns: | Type | Description | | --- | --- | | `TSerializable` | The data object cast to the requested type. | Raises: | Type | Description | | --- | --- | | `TypeError` | If the actual data type does not match the requested `target_type`. | Example ``` # Get the IMU data from the message image_data = message.get_data(Image) print(f"Message time: {message.timestamp_ns}: Sensor time: {image_data.header.stamp.to_nanoseconds()}") print(f"Message time: {message.timestamp_ns}: Image size: {image_data.height}x{image_data.width}") # Show the image image_data.to_pillow().show() # Get the Floating64 data from the message floating64_data = message.get_data(Floating64) print(f"Message time: {message.timestamp_ns}: Data time: {floating64_data.header.stamp.to_nanoseconds()}") print(f"Message time: {message.timestamp_ns}: Data value: {floating64_data.data}") ``` ### from\_dataframe\_row `staticmethod` ¶ ``` from_dataframe_row( row, topic_name, timestamp_column_name="timestamp_ns" ) ``` Reconstructs a `Message` object from a flattened DataFrame row. In the Mosaico Data Platform, DataFrames represent topics using a nested naming convention: `{topic}.{tag}.{field}`. This method performs **Smart Reconstruction** by: 1. **Topic Validation**: Verifying if any columns associated with the `topic_name` exist in the row. 2. **Tag Inference**: Inspecting the column headers to automatically determine the original ontology tag (e.g., `"imu"`). 3. **Data Extraction**: Stripping prefixes and re-nesting the flat columns into their original dictionary structures. 4. **Type Casting**: Re-instantiating the specific `Serializable` subclass and wrapping it in a `Message` envelope. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `row` | `Series` | A single row from a Pandas DataFrame, representing a point in time across one or more topics. | *required* | | `topic_name` | `str` | The name of the specific topic to extract from the row. | *required* | | `timestamp_column_name` | `str` | The name of the column containing the timestamp. | `'timestamp_ns'` | Returns: | Type | Description | | --- | --- | | `Optional[Message]` | A reconstructed `Message` instance containing the typed ontology data, or `None` if the topic is not present or the data is incomplete. | Example ``` # Obtain a dataframe with DataFrameExtractor from mosaicolabs import MosaicoClient, IMU, Image from mosaicolabs.ml import DataFrameExtractor, SyncTransformer with MosaicoClient.connect("localhost", 6726) as client: sequence_handler = client.get_sequence_handler("example_sequence") for df in DataFrameExtractor(sequence_handler).to_pandas_chunks( topics = ["/front/imu", "/front/camera/image_raw"] ): # Do something with the dataframe. # For example, you can sync the data using the `SyncTransformer`: sync_transformer = SyncTransformer( target_fps = 30, # resample at 30 Hz and fill the Nans with a Hold policy ) synced_df = sync_transformer.transform(df) # Reconstruct the image message from a dataframe row image_msg = Message.from_dataframe_row(synced_df, "/front/camera/image_raw") image_data = image_msg.get_data(Image) # Show the image image_data.to_pillow().show() # ... ``` ## mosaicolabs.models.Time ¶ Bases: `BaseModel` A high-precision time representation designed to prevent precision loss. The `Time` class splits a timestamp into a 64-bit integer for seconds and a 32-bit unsigned integer for nanoseconds. This dual-integer structure follows robotics standards (like ROS) to ensure temporal accuracy that standard 64-bit floating-point timestamps cannot maintain over long durations. Attributes: | Name | Type | Description | | --- | --- | --- | | `sec` | `int` | Seconds since the epoch (Unix time). | | `nanosec` | `int` | Nanoseconds component within the current second, ranging from 0 to 999,999,999. | ### sec `instance-attribute` ¶ ``` sec ``` Seconds since the epoch (Unix time). ### nanosec `instance-attribute` ¶ ``` nanosec ``` Nanoseconds component within the current second, ranging from 0 to 999,999,999. ### validate\_nanosec `classmethod` ¶ ``` validate_nanosec(v) ``` Ensures nanoseconds are within the valid [0, 1e9) range. ### from\_float `classmethod` ¶ ``` from_float(ftime) ``` Factory method to create a Time object from a float (seconds since epoch). This method carefully handles floating-point artifacts by using rounding for the fractional part to ensure stable nanosecond conversion. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `ftime` | `float` | Total seconds since epoch (e.g., from `time.time()`). | *required* | Returns: | Type | Description | | --- | --- | | `Time` | A normalized `Time` instance. | ### from\_milliseconds `classmethod` ¶ ``` from_milliseconds(total_milliseconds) ``` Factory method to create a Time object from a total count of milliseconds. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `total_milliseconds` | `int` | Total time elapsed in milliseconds. | *required* | Returns: | Type | Description | | --- | --- | | `Time` | A `Time` instance with split sec/nanosec components. | ### from\_nanoseconds `classmethod` ¶ ``` from_nanoseconds(total_nanoseconds) ``` Factory method to create a Time object from a total count of nanoseconds. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `total_nanoseconds` | `int` | Total time elapsed in nanoseconds. | *required* | Returns: | Type | Description | | --- | --- | | `Time` | A `Time` instance with split sec/nanosec components. | ### from\_datetime `classmethod` ¶ ``` from_datetime(dt) ``` Factory method to create a Time object from a Python `datetime` instance. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `dt` | `datetime` | A standard Python `datetime` object. | *required* | Returns: | Type | Description | | --- | --- | | `Time` | A `Time` instance reflecting the datetime's timestamp. | ### now `classmethod` ¶ ``` now() ``` Factory method that returns the current system UTC time in high precision. ### to\_float ¶ ``` to_float() ``` Converts the high-precision time to a float. Precision Loss Converting to a 64-bit float may result in the loss of nanosecond precision due to mantissa limitations. ### to\_nanoseconds ¶ ``` to_nanoseconds() ``` Converts the time to a total integer of nanoseconds. This conversion preserves full precision. ### to\_milliseconds ¶ ``` to_milliseconds() ``` Converts the time to a total integer of milliseconds. This conversion preserves full precision. ### to\_datetime ¶ ``` to_datetime() ``` Converts the time to a Python UTC `datetime` object. Microsecond Limitation Python's `datetime` objects typically support microsecond precision; nanosecond data below that threshold will be truncated. ## mosaicolabs.models.Header ¶ Bases: `BaseModel` Standard metadata header used to provide context to ontology data. The `Header` structure provides spatial and temporal context, matching common industry standards for sensor data. It is typically injected into sensor models via the `HeaderMixin`. Attributes: | Name | Type | Description | | --- | --- | --- | | `stamp` | `Time` | The high-precision `Time` of data acquisition. | | `frame_id` | `Optional[str]` | A string identifier for the coordinate frame (spatial context). | | `seq` | `Optional[int]` | An optional sequence ID, primarily used for legacy tracking. | Nullable Fields In the underlying PyArrow schema, all header fields are explicitly marked as `nullable=True`. This ensures that empty headers are correctly deserialized as `None` rather than default-initialized objects. ### stamp `instance-attribute` ¶ ``` stamp ``` The high-precision `Time` of data acquisition. ### frame\_id `class-attribute` `instance-attribute` ¶ ``` frame_id = None ``` A string identifier for the coordinate frame (spatial context). ### seq `class-attribute` `instance-attribute` ¶ ``` seq = None ``` An optional sequence ID, primarily used for legacy tracking. ## mosaicolabs.models.HeaderMixin ¶ Bases: `BaseModel` A mixin that injects a standard `header` field into any inheriting ontology model. The `HeaderMixin` is used to add standard metadata (such as acquisition timestamps or frame IDs) to a sensor model through composition. It ensures that the underlying PyArrow schema remains synchronized with the Pydantic data model. ##### Dynamic Schema Injection¶ This mixin uses the `__init_subclass__` hook to perform a **Schema Append** operation: 1. It inspects the child class's existing `__msco_pyarrow_struct__`. 2. It appends a `header` field of type `Header`. 3. It reconstructs the final `pa.struct` for the class. Collision Safety The mixin performs a collision check during class definition. If the child class already defines a `header` field in its PyArrow struct, a `ValueError` will be raised to prevent schema corruption. Attributes: | Name | Type | Description | | --- | --- | --- | | `header` | `Optional[Header]` | An optional `Header` object containing standard metadata. | ##### Querying with the **`.Q` Proxy**¶ When constructing a `QueryOntologyCatalog`, the `header` component is fully queryable across any model inheriting from this mixin. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.header.seq` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `.Q.header.stamp.sec` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `.Q.header.stamp.nanosec` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `.Q.header.frame_id` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Universal Compatibility The `` placeholder represents any Mosaico ontology class (e.g., `IMU`, `GPS`, `Floating64`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, IMU, Floating64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter IMU data by a specific acquisition second qresponse = client.query( QueryOntologyCatalog(IMU.Q.header.stamp.sec.lt(1770282868)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter primitive Floating64 telemetry by frame identifier qresponse = client.query( QueryOntologyCatalog(Floating64.Q.header.frame_id.eq("robot_base")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ## mosaicolabs.models.CovarianceMixin ¶ Bases: `BaseModel` A mixin that adds uncertainty fields (`covariance` and `covariance_type`) to data models. This is particularly useful for complex sensors like IMUs, Odometry, or GNSS receivers that provide multidimensional uncertainty matrices along with their primary measurements. ##### Dynamic Schema Injection¶ This mixin uses the `__init_subclass__` hook to perform a **Schema Append** operation: 1. It inspects the child class's existing `__msco_pyarrow_struct__`. 2. It appends a `covariance` and `covariance_type` fields. 3. It reconstructs the final `pa.struct` for the class. Collision Safety The mixin performs a collision check during class definition. If the child class already defines a `covariance` or `covariance_type` field in its PyArrow struct, a `ValueError` will be raised to prevent schema corruption. Attributes: | Name | Type | Description | | --- | --- | --- | | `covariance` | `Optional[List[float]]` | Optional list of 64-bit floats representing the flattened matrix. | | `covariance_type` | `Optional[int]` | Optional 16-bit integer representing the covariance enum. | ##### Querying with the **`.Q` Proxy**¶ When constructing a `QueryOntologyCatalog`, the class fields are queryable across any model inheriting from this mixin, according to the following table: | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.covariance_type` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `.Q.covariance` | ***Non-Queryable*** | None | Universal Compatibility The `` placeholder represents any Mosaico ontology class (e.g., `IMU`, `GPS`, `Floating64`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter IMU data by a specific acquisition second # `FROM_CALIBRATED_PROCEDURE` is some enum value defined by the user qresponse = client.query( QueryOntologyCatalog(IMU.Q.covariance_type.eq(FROM_CALIBRATED_PROCEDURE)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. ### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. ## mosaicolabs.models.VarianceMixin ¶ Bases: `BaseModel` A mixin that adds 1-dimensional uncertainty fields (`variance` and `variance_type`). Recommended for sensors with scalar uncertain outputs, such as ultrasonic rangefinders, temperature sensors, or individual encoders. ##### Dynamic Schema Injection¶ This mixin uses the `__init_subclass__` hook to perform a **Schema Append** operation: 1. It inspects the child class's existing `__msco_pyarrow_struct__`. 2. It appends a `variance` and `variance_type` field. 3. It reconstructs the final `pa.struct` for the class. Collision Safety The mixin performs a collision check during class definition. If the child class already defines a `variance` or `variance_type` field in its PyArrow struct, a `ValueError` will be raised to prevent schema corruption. ##### Querying with the **`.Q` Proxy**¶ When constructing a `QueryOntologyCatalog`, the class fields are queryable across any model inheriting from this mixin, according to the following table: | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.variance` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `.Q.variance_type` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico ontology class (e.g., `IMU`, `GPS`, `Floating64`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter IMU data by a specific acquisition second qresponse = client.query( QueryOntologyCatalog(IMU.Q.variance.lt(0.76)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter IMU data by a specific acquisition second # `FROM_CALIBRATED_PROCEDURE` is some enum value defined by the user qresponse = client.query( QueryOntologyCatalog(IMU.Q.variance_type.eq(FROM_CALIBRATED_PROCEDURE)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### variance `class-attribute` `instance-attribute` ¶ ``` variance = None ``` Optional 64-bit float representing the variance of the data. This field is injected into the model via composition, ensuring that sensor data is paired with the optional variance attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance` component. ### variance\_type `class-attribute` `instance-attribute` ¶ ``` variance_type = None ``` Optional 16-bit integer representing the variance parameterization. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance_type` component. --- ## mosaicolabs.models.data.base\_types ¶ This module provides specialized wrapper classes for standard Python primitive types, including Integers, Floating-point numbers, Booleans, and Strings. In the Mosaico ecosystem, raw primitives cannot be transmitted directly because the platform requires structured metadata and explicit serialization schemas. These wrappers elevate basic data types to "first-class citizens" of the messaging system by inheriting from `Serializable` and `HeaderMixin`. **Key Features:** \* **Standardized Metadata**: Every wrapped value includes a standard `Header`, enabling full traceability and temporal context (timestamps) for even the simplest data points. \* **Explicit Serialization**: Each class defines a precise `pyarrow.StructType` schema, ensuring consistent bit-width (e.g., 8-bit vs 64-bit) across the entire data platform. \* **Registry Integration**: Wrapped types are automatically registered in the Mosaico ontology, allowing them to be used in platform-side Queries. ### Integer8 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a signed 8-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying 8-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Integer8, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer8.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer8.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Integer8.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Integer8, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer8.Q.data.gt(-10))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer8.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Integer16 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a signed 16-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying 16-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Integer16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer16.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer16.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Integer16.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Integer16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer16.Q.data.gt(-10))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer16.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Integer32 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a signed 32-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying 32-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Integer32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer32.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer32.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Integer32.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Integer32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer32.Q.data.gt(-10))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer32.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Integer64 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a signed 64-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying 64-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`.ù | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Integer64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer64.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer64.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Integer64.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Integer64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Integer64.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Integer64.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Unsigned8 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for an unsigned 8-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying unsigned 8-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | Raises: | Type | Description | | --- | --- | | `ValueError` | If `data` is initialized with a negative value. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Unsigned8, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned8.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned8.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying unsigned integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Unsigned8.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Unsigned8, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned8.Q.data.leq(253))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned8.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### model\_post\_init ¶ ``` model_post_init(context) ``` Validates that the input data is non-negative. Raises: | Type | Description | | --- | --- | | `ValueError` | If data < 0. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Unsigned16 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for an unsigned 16-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying unsigned 16-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | Raises: | Type | Description | | --- | --- | | `ValueError` | If `data` is initialized with a negative value. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Unsigned16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned16.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned16.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying unsigned integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Unsigned16.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Unsigned16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned16.Q.data.eq(2))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned16.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### model\_post\_init ¶ ``` model_post_init(context) ``` Validates that the input data is non-negative. Raises: | Type | Description | | --- | --- | | `ValueError` | If data < 0. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Unsigned32 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for an unsigned 32-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying unsigned 32-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | Raises: | Type | Description | | --- | --- | | `ValueError` | If `data` is initialized with a negative value. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Unsigned32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned32.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned32.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying unsigned integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Unsigned32.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Unsigned32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned32.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned32.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### model\_post\_init ¶ ``` model_post_init(context) ``` Validates that the input data is non-negative. Raises: | Type | Description | | --- | --- | | `ValueError` | If data < 0. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Unsigned64 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for an unsigned 64-bit integer. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `int` | The underlying unsigned 64-bit integer value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | Raises: | Type | Description | | --- | --- | | `ValueError` | If `data` is initialized with a negative value. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Unsigned64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned64.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned64.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying unsigned integer value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Unsigned64.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Unsigned64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Unsigned64.Q.data.gt(123))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Unsigned64.Q.data.gt(123), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### model\_post\_init ¶ ``` model_post_init(context) ``` Validates that the input data is non-negative. Raises: | Type | Description | | --- | --- | | `ValueError` | If data < 0. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Floating16 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a 16-bit single-precision floating-point number. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `float` | The underlying single-precision float. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Floating16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating16.Q.data.gt(123.45))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating16.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying single-precision float. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Floating16.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Floating16, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating16.Q.data.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating16.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Floating32 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a 32-bit single-precision floating-point number. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `float` | The underlying single-precision float. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Floating32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating32.Q.data.gt(123.45))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating32.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying single-precision float. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Floating32.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Floating32, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating32.Q.data.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating32.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Floating64 ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a 64-bit single-precision floating-point number. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `float` | The underlying single-precision float. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Floating64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating64.Q.data.gt(123.45))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating64.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying single-precision float. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Floating64.Q.data` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Floating64, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Floating64.Q.data.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Floating64.Q.data.gt(123.45), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Boolean ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a standard boolean value. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `bool` | The underlying boolean value. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Boolean, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Boolean.Q.data.eq(True))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Boolean.Q.data.eq(True), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying boolean value. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Boolean.Q.data` | `Bool` | `.eq()` | Example ``` from mosaicolabs import MosaicoClient, Boolean, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(Boolean.Q.data.eq(True))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Boolean.Q.data.eq(True), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### String ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a standard UTF-8 encoded string. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `str` | The underlying string data. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, String, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(String.Q.data.eq("hello"))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(String.Q.data.eq("hello"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying string data. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `String.Q.data` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, String, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for strings containing a specific log pattern qresponse = client.query(QueryOntologyCatalog(String.Q.data.match("[ERR]"))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(String.Q.data.eq("hello"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### LargeString ¶ Bases: `Serializable`, `HeaderMixin` A wrapper for a Large UTF-8 encoded string. Use this class when string data is expected to exceed 2GB in size, necessitating the use of 64-bit offsets in the underlying PyArrow implementation. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `str` | The underlying large string data. | | `header` | `Optional[Header]` | An optional metadata header injected by `HeaderMixin`. | ###### Querying with the **`.Q` Proxy**¶ The fields of this class are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, LargeString, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value qresponse = client.query(QueryOntologyCatalog(LargeString.Q.data.eq("hello"))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(LargeString.Q.data.eq("hello"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### data `instance-attribute` ¶ ``` data ``` The underlying large string data. ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `LargeString.Q.data` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, LargeString, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for large strings containing a specific log pattern qresponse = client.query(QueryOntologyCatalog(LargeString.Q.data.match("CRITICAL_ERR_"))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(LargeString.Q.data.eq("hello"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.data.ROI ¶ Bases: `Serializable`, `HeaderMixin` Represents a rectangular Region of Interest (ROI) within a 2D coordinate system. This class is primarily used in imaging and computer vision pipelines to define sub-windows for processing or rectification. Attributes: | Name | Type | Description | | --- | --- | --- | | `offset` | `Vector2d` | A `Vector2d` representing the top-left (leftmost, topmost) pixel coordinates of the ROI. | | `height` | `int` | The vertical extent of the ROI in pixels. | | `width` | `int` | The horizontal extent of the ROI in pixels. | | `do_rectify` | `Optional[bool]` | Optional flag; `True` if a sub-window is captured and requires rectification. | | `header` | `Optional[Header]` | Standard metadata header providing temporal and spatial context. | ##### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, ROI, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter ROIs with offset X-component AND offset Y-component qresponse = client.query( QueryOntologyCatalog(ROI.Q.offset.x.gt(5.0)) .with_expression(ROI.Q.offset.y.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ROI.Q.offset.x.gt(5.0), include_timestamp_range=True) .with_expression(ROI.Q.offset.y.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### offset `instance-attribute` ¶ ``` offset ``` The top-left pixel coordinates of the ROI. ###### Querying with the **`.Q` Proxy**¶ Offset components are queryable through the `offset` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ROI.Q.offset.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `ROI.Q.offset.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, ROI, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for ROIs starting between the 10th and 350th pixel vertically qresponse = client.query( QueryOntologyCatalog(ROI.Q.offset.x.gt(100)) .with_expression(ROI.Q.offset.y.between(10, 350)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ROI.Q.offset.x.gt(100), include_timestamp_range=True) .with_expression(ROI.Q.offset.y.between(10, 350)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### height `instance-attribute` ¶ ``` height ``` Height of the ROI in pixels. ###### Querying with the **`.Q` Proxy**¶ | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ROI.Q.height` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, ROI, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for ROIs with height beyond 100 pixels qresponse = client.query( QueryOntologyCatalog(ROI.Q.height.gt(100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ROI.Q.height.gt(100), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### width `instance-attribute` ¶ ``` width ``` Width of the ROI in pixels. ###### Querying with the **`.Q` Proxy**¶ | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ROI.Q.width` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, ROI, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for ROIs with width below (or equal to) 250 pixels qresponse = client.query( QueryOntologyCatalog(ROI.Q.width.leq(250)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ROI.Q.width.gt(100), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### do\_rectify `class-attribute` `instance-attribute` ¶ ``` do_rectify = None ``` Flag indicating if the ROI requires rectification. ###### Querying with the **`.Q` Proxy**¶ | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ROI.Q.do_rectify` | `Boolean` | `.eq()` | Example ``` from mosaicolabs import MosaicoClient, ROI, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for explicitly non-rectified ROIs (not None) qresponse = client.query( QueryOntologyCatalog(ROI.Q.do_rectify.eq(False)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` --- ## mosaicolabs.models.data.geometry ¶ This module defines the fundamental building blocks for spatial representation, including vectors, points, quaternions, and rigid-body transforms. The module follows a **Two-Tier Architecture** to optimize both internal efficiency and public usability: * **Internal Structs (`_Struct`)**: Pure data containers that define the physical memory layout and the PyArrow schema. These are intended for embedding within larger composite objects (like a `Pose` or `Transform`) to avoid attaching redundant metadata headers or timestamps to every inner field. * **Public Classes**: High-level models that combine spatial data with Mosaico's transport and serialization logic. These inherit from the internal structs and inject support for auto-registration (`Serializable`), temporal/spatial context (`HeaderMixin`), and uncertainty tracking (`CovarianceMixin`). ### Vector2d ¶ Bases: `_Vector2dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` A public 2D Vector for platform-wide transmission. This class combines the [x, y] coordinates with full Mosaico transport logic. It is used to represent quantities such as velocity, acceleration, or directional forces. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Vector X component. | | `y` | `float` | Vector Y component. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 2x2 covariance matrix representing the uncertainty of the vector measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Vector2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.y.leq(123.4)) .with_expression(Vector2d.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector2dStruct` (i.e. `Vector2d`, `Point2d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector2d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point2d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector2dStruct` (i.e. `Vector2d`, `Point2d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector2d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point2d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 2 float values: [x, y]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 2. | ### Vector3d ¶ Bases: `_Vector3dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` A public 3D Vector for platform-wide transmission. This class combines the [x, y, z] coordinates with full Mosaico transport logic. It is used to represent quantities such as velocity, acceleration, or directional forces. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Vector X component. | | `y` | `float` | Vector Y component. | | `z` | `float` | Vector Z component. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 3x3 covariance matrix representing the uncertainty of the vector measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.y.leq(123.4)) .with_expression(Vector3d.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### z `instance-attribute` ¶ ``` z ``` The Vector Z component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 3 float values: [x, y, z]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 3. | ### Vector4d ¶ Bases: `_Vector4dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` A public 4D Vector for platform-wide transmission. This class combines the [x, y, z, w] coordinates with full Mosaico transport logic. It is used to represent quantities such as velocity, acceleration, or directional forces. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Vector X component. | | `y` | `float` | Vector Y component. | | `z` | `float` | Vector Z component. | | `w` | `float` | Vector W component. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 4x4 covariance matrix representing the uncertainty of the vector measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.y.leq(123.4)) .with_expression(Vector4d.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.x.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.y.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### z `instance-attribute` ¶ ``` z ``` The Vector Z component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.z.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### w `instance-attribute` ¶ ``` w ``` The Vector W component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.w.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.w.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.w.leq(0.707))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 4 float values: [x, y, z, w]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 4. | ### Point2d ¶ Bases: `_Vector2dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` Semantically represents a specific location (Point) in 2D space. Structurally identical to a 2D Vector, but distinguished within the Mosaico API to clarify intent in spatial operations. Use this class for 2D coordinate data that requires Mosaico transport logic. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Point X coordinate. | | `y` | `float` | Point Y coordinate. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 2x2 covariance matrix representing the uncertainty of the point measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Point2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Point2d.Q.y.leq(123.4)) .with_expression(Point2d.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Point2d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector2dStruct` (i.e. `Vector2d`, `Point2d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector2d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point2d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector2dStruct` (i.e. `Vector2d`, `Point2d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector2d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector2d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector2d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point2d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 2 float values: [x, y]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 2. | ### Point3d ¶ Bases: `_Vector3dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` Semantically represents a specific location (Point) in 3D space. The `Point3d` class is used to instantiate a 3D coordinate message for transmission over the platform. It is structurally identical to a 3D Vector but is used to denote state rather than direction. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Point X coordinate. | | `y` | `float` | Point Y coordinate. | | `z` | `float` | Point Z coordinate. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 3x3 covariance matrix representing the uncertainty of the point measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Point3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Point3d.Q.y.leq(123.4)) .with_expression(Point3d.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Point3d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### z `instance-attribute` ¶ ``` z ``` The Vector Z component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector3dStruct` (i.e. `Vector3d`, `Point3d`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector3d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector3d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector3d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Point3d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 3 float values: [x, y, z]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 3. | ### Quaternion ¶ Bases: `_Vector4dStruct`, `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents a rotation in 3D space using normalized quaternions. Structurally identical to a 4D vector [x, y, z, w], but semantically denotes an orientation. This representation avoids the gimbal lock issues associated with Euler angles. Attributes: | Name | Type | Description | | --- | --- | --- | | `x` | `float` | Vector X component. | | `y` | `float` | Vector Y component. | | `z` | `float` | Vector Z component. | | `w` | `float` | Vector W component. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 4x4 covariance matrix representing the uncertainty of the quaternion measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Quaternion, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Quaternion.Q.w.leq(0.707)) .with_expression(Quaternion.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Quaternion.Q.w.leq(0.707), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### x `instance-attribute` ¶ ``` x ``` The Vector X component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.x.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.x.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.x.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### y `instance-attribute` ¶ ``` y ``` The Vector Y component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.y.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.y.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.y.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### z `instance-attribute` ¶ ``` z ``` The Vector Z component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.z.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.z.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.z.leq(0.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### w `instance-attribute` ¶ ``` w ``` The Vector W component ###### Querying with the **`.Q` Proxy**¶ This field is queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `_Vector4dStruct` (i.e. `Vector4d`, `Quaternion`) or any custom user-defined `Serializable` class that inherits from `HeaderMixin`. Example ``` from mosaicolabs import MosaicoClient, Vector4d, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Vector4d.Q.w.leq(123.4))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Vector4d.Q.w.leq(123.4), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") # Filter for a specific component value. qresponse = client.query(QueryOntologyCatalog(Quaternion.Q.w.leq(0.707))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### from\_list `classmethod` ¶ ``` from_list(data) ``` Creates a struct instance from a raw list. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `list[float]` | A list containing exactly 4 float values: [x, y, z, w]. | *required* | Raises: | Type | Description | | --- | --- | | `ValueError` | If the input list does not have a length of 4. | ### Transform ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents a rigid-body transformation between two coordinate frames. A transform consists of a translation followed by a rotation. It is typically used to describe the kinematic relationship between components (e.g., "Camera to Robot Base"). Attributes: | Name | Type | Description | | --- | --- | --- | | `translation` | `Vector3d` | A `Vector3d` describing the linear shift. | | `rotation` | `Quaternion` | A `Quaternion` describing the rotational shift. | | `target_frame_id` | `Optional[str]` | The identifier of the destination coordinate frame. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 7x7 composed covariance matrix representing the uncertainty of the Translation+Rotation. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Transform, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific component value. qresponse = client.query( QueryOntologyCatalog(Transform.Q.translation.x.gt(5.0)) .with_expression(Transform.Q.rotation.w.lt(0.707)) .with_expression(Transform.Q.header.stamp.sec.between([1770282868, 1770290127])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Transform.Q.translation.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### translation `instance-attribute` ¶ ``` translation ``` The 3D translation vector component. ###### Querying with the **`.Q` Proxy**¶ Translation components are queryable through the `translation` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Transform.Q.translation.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Transform.Q.translation.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Transform.Q.translation.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Transform, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find transforms where the linear X-translation exceeds 5 meters qresponse = client.query( QueryOntologyCatalog(Transform.Q.translation.x.gt(5.0)) .with_expression(Transform.Q.translation.z.lt(150.3)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Transform.Q.translation.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### rotation `instance-attribute` ¶ ``` rotation ``` The rotation quaternion component (x, y, z, w). ###### Querying with the **`.Q` Proxy**¶ Rotation components are queryable through the `rotation` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Transform.Q.rotation.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Transform.Q.rotation.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Transform.Q.rotation.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Transform.Q.rotation.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Transform, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for specific orientation states qresponse = client.query( QueryOntologyCatalog(Transform.Q.rotation.w.geq(0.707)) .with_expression(Transform.Q.rotation.z.lt(0.4)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Transform.Q.rotation.x.gt(5.0), include_timestamp_range=True) .with_expression(Transform.Q.rotation.z.lt(0.4)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### target\_frame\_id `class-attribute` `instance-attribute` ¶ ``` target_frame_id = None ``` Target coordinate frame identifier. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Transform.Q.target_frame_id` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, Transform, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for specific target frame id qresponse = client.query( QueryOntologyCatalog(Transform.Q.target_frame_id.eq("camera_link")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Transform.Q.target_frame_id.eq("camera_link"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Pose ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents the position and orientation of an object in a global or local frame. While similar to a `Transform`, a `Pose` semantically denotes the **state** of an object (its current location and heading) rather than the mathematical shift between two frames. Attributes: | Name | Type | Description | | --- | --- | --- | | `position` | `Point3d` | A `Point3d` representing the object's coordinates. | | `orientation` | `Quaternion` | A `Quaternion` representing the object's heading. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 7x7 composed covariance matrix representing the uncertainty of the Translation+Rotation. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Pose, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter Poses with position X-component AND orientation W-component qresponse = client.query( QueryOntologyCatalog(Pose.Q.position.x.gt(5.0)) .with_expression(Pose.Q.orientation.w.lt(0.707)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Pose.Q.position.x.gt(5.0), include_timestamp_range=True) .with_expression(Pose.Q.orientation.w.lt(0.707)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### position `instance-attribute` ¶ ``` position ``` The 3D position vector component. ###### Querying with the **`.Q` Proxy**¶ Position components are queryable through the `position` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Pose.Q.position.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Pose.Q.position.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Pose.Q.position.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Pose, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find poses where the linear X-position exceeds 5 meters qresponse = client.query( QueryOntologyCatalog(Pose.Q.position.x.gt(123450.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Pose.Q.position.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### orientation `instance-attribute` ¶ ``` orientation ``` The orientation quaternion component (x, y, z, w). ###### Querying with the **`.Q` Proxy**¶ Rotation components are queryable through the `orientation` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Pose.Q.orientation.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Pose.Q.orientation.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Pose.Q.orientation.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Pose.Q.orientation.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Pose, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for specific orientation states qresponse = client.query( QueryOntologyCatalog(Pose.Q.orientation.w.geq(0.707)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(include_timestamp_range=True) .with_expression(Pose.Q.orientation.w.geq(0.707)) .with_expression(Pose.Q.orientation.x.lt(0.1)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.data.kinematics ¶ Kinematics Data Structures. This module defines structures for analyzing motion: 1. **Velocity (Twist)**: Linear and angular speed. 2. **Acceleration**: Linear and angular acceleration. 3. **MotionState**: A complete snapshot of an object's kinematics (Pose + Velocity + Acceleration). These can be assigned to Message.data field to send data to the platform. ### Velocity ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents 6-Degree-of-Freedom Velocity, commonly referred to as a Twist. The `Velocity` class describes the instantaneous motion of an object, split into linear and angular components. Attributes: | Name | Type | Description | | --- | --- | --- | | `linear` | `Optional[Vector3d]` | Optional `Vector3d` linear velocity vector. | | `angular` | `Optional[Vector3d]` | Optional `Vector3d` angular velocity vector. | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 3x3 covariance matrix representing the uncertainty of the point measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | Input Validation A valid `Velocity` object must contain at least a `linear` or an `angular` component; providing neither will raise a `ValueError`. ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Velocity, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter Velocities with linear X-component AND angular Z-component qresponse = client.query( QueryOntologyCatalog(Velocity.Q.linear.x.gt(5.0)) .with_expression(Velocity.Q.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Velocity.Q.linear.x.gt(5.0), include_timestamp_range=True) .with_expression(Velocity.Q.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### linear `class-attribute` `instance-attribute` ¶ ``` linear = None ``` 3D linear velocity vector ###### Querying with the **`.Q` Proxy**¶ Linear components are queryable through the `linear` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Velocity.Q.linear.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Velocity.Q.linear.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Velocity.Q.linear.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Velocity, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find velocities where the linear X component exceeds 25 m/s qresponse = client.query( QueryOntologyCatalog(Velocity.Q.linear.x.gt(25.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Velocity.Q.linear.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### angular `class-attribute` `instance-attribute` ¶ ``` angular = None ``` 3D angular velocity vector ###### Querying with the **`.Q` Proxy**¶ Angular components are queryable through the `angular` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Velocity.Q.angular.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Velocity.Q.angular.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Velocity.Q.angular.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Velocity, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find velocities where the angular X component exceeds 2 rad//s qresponse = client.query( QueryOntologyCatalog(Velocity.Q.angular.x.gt(2.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Velocity.Q.angular.x.gt(2.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### check\_at\_least\_one\_exists ¶ ``` check_at_least_one_exists() ``` Ensures the velocity object is not empty. Raises: | Type | Description | | --- | --- | | `ValueError` | If both `linear` and `angular` are None. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### Acceleration ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents 6-Degree-of-Freedom Acceleration. This class provides a standardized way to transmit linear and angular acceleration data to the platform. Attributes: | Name | Type | Description | | --- | --- | --- | | `linear` | `Optional[Vector3d]` | Optional 3D linear acceleration vector ($a\_x, a\_y, a\_z$). | | `angular` | `Optional[Vector3d]` | Optional 3D angular acceleration vector ($lpha\_x, lpha\_y, lpha\_z$). | | `header` | `Optional[Header]` | Optional metadata header providing acquisition context. | | `covariance` | `Optional[List[float]]` | Optional flattened 3x3 covariance matrix representing the uncertainty of the point measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | Input Validation Similar to the `Velocity` class, an `Acceleration` instance requires at least one non-null component (`linear` or `angular`). ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, Acceleration, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter Accelerations with linear X-component AND angular Z-component qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.linear.x.gt(5.0)) .with_expression(Acceleration.Q.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.linear.x.gt(5.0), include_timestamp_range=True) .with_expression(Acceleration.Q.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### linear `class-attribute` `instance-attribute` ¶ ``` linear = None ``` 3D linear acceleration vector ###### Querying with the **`.Q` Proxy**¶ Linear components are queryable through the `linear` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Acceleration.Q.linear.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Acceleration.Q.linear.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Acceleration.Q.linear.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Acceleration, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find accelerations where the linear X component exceeds 5 m/s^2 qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.linear.x.gt(5.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.linear.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### angular `class-attribute` `instance-attribute` ¶ ``` angular = None ``` 3D angular acceleration vector ###### Querying with the **`.Q` Proxy**¶ Angular components are queryable through the `angular` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Acceleration.Q.angular.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Acceleration.Q.angular.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Acceleration.Q.angular.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Acceleration, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find accelerations where the angular X component exceeds 1 rad/s^2 qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.angular.x.gt(1.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Acceleration.Q.angular.x.gt(1.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### check\_at\_least\_one\_exists ¶ ``` check_at_least_one_exists() ``` Ensures the acceleration object is not empty. Raises: | Type | Description | | --- | --- | | `ValueError` | If both `linear` and `angular` are None. | #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### MotionState ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Aggregated Kinematic State. `MotionState` groups `Pose`, `Velocity`, and optional `Acceleration` into a single atomic update. This is the preferred structure for: * **Trajectory Tracking**: Recording the high-fidelity path of a robot or vehicle. * **State Estimation**: Logging the output of Kalman filters or SLAM algorithms. * **Ground Truth**: Storing reference data from simulation environments. Attributes: | Name | Type | Description | | --- | --- | --- | | `pose` | `Pose` | The 6D pose representing current position and orientation. | | `velocity` | `Velocity` | The 6D velocity (Twist). | | `target_frame_id` | `str` | A string identifier for the target coordinate frame. | | `acceleration` | `Optional[Acceleration]` | Optional 6D acceleration. | | `header` | `Optional[Header]` | Standard metadata header for temporal synchronization. | | `covariance` | `Optional[List[float]]` | Optional flattened NxN composed covariance matrix representing the uncertainty of the Pose+Velocity+[Acceleration] measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, MotionState, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter MotionStates with position X-component AND angular velocity Z-component qresponse = client.query( QueryOntologyCatalog(MotionState.Q.pose.position.x.gt(123456.9)) .with_expression(MotionState.Q.velocity.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(MotionState.Q.pose.position.x.gt(123456.9), include_timestamp_range=True) .with_expression(MotionState.Q.velocity.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### pose `instance-attribute` ¶ ``` pose ``` The 6D pose representing current position and orientation. ###### Querying with the **`.Q` Proxy**¶ Pose components are queryable through the `pose` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `MotionState.Q.pose.position.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.position.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.position.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.orientation.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.orientation.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.orientation.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.pose.orientation.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, MotionState, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter snapshots where the object is beyond a specific X-coordinate qresponse = client.query( QueryOntologyCatalog(MotionState.Q.pose.position.x.gt(500.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(MotionState.Q.pose.position.x.gt(500.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### velocity `instance-attribute` ¶ ``` velocity ``` The 6D velocity (Twist) describing instantaneous motion. ###### Querying with the **`.Q` Proxy**¶ Velocity components are queryable through the `velocity` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `MotionState.Q.velocity.linear.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.velocity.linear.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.velocity.linear.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.velocity.angular.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.velocity.angular.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.velocity.angular.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, MotionState, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find states where linear velocity in X exceeds 2.5 m/s qresponse = client.query( QueryOntologyCatalog(MotionState.Q.velocity.linear.x.gt(2.5)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(MotionState.Q.velocity.linear.x.gt(5.0), include_timestamp_range=True) .with_expression(MotionState.Q.velocity.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### target\_frame\_id `instance-attribute` ¶ ``` target_frame_id ``` Identifier for the destination coordinate frame. ###### Querying with the **`.Q` Proxy**¶ | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `MotionState.Q.target_frame_id` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, MotionState, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find states where target_frame_id is some link qresponse = client.query( QueryOntologyCatalog(MotionState.Q.target_frame_id.eq("moving_base")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` #### acceleration `class-attribute` `instance-attribute` ¶ ``` acceleration = None ``` Optional 6D acceleration components. ###### Querying with the **`.Q` Proxy**¶ Acceleration components are queryable through the `acceleration` field prefix if present. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `MotionState.Q.acceleration.linear.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.acceleration.linear.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.acceleration.linear.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.acceleration.angular.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.acceleration.angular.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `MotionState.Q.acceleration.angular.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, MotionState, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find states where centripetal acceleration exceeds 5 m/s^2 qresponse = client.query( QueryOntologyCatalog(MotionState.Q.acceleration.linear.y.gt(5.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(MotionState.Q.acceleration.linear.y.gt(5.0), include_timestamp_range=True) .with_expression(MotionState.Q.acceleration.angular.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.data.dynamics ¶ This module defines specialized ontology structures for representing physical dynamics, specifically linear forces and rotational moments (torques). The primary structure, `ForceTorque`, implements a standard "Wrench" representation. These models are designed to be assigned to the `data` field of a `Message` for transmission to the platform. **Key Features:** \* **Wrench Representation**: Combines 3D linear force and 3D rotational torque into a single, synchronized state. \* **Uncertainty Quantification**: Inherits from `CovarianceMixin` to support $6 imes 6$ covariance matrices, allowing for the transmission of sensor noise characteristics or estimation confidence. ### ForceTorque ¶ Bases: `Serializable`, `HeaderMixin`, `CovarianceMixin` Represents a Wrench (Force and Torque) applied to a rigid body. The `ForceTorque` class is used to describe the total mechanical action (wrench) acting on a body at a specific reference point. By combining linear force and rotational torque, it provides a complete description of dynamics for simulation and telemetry. Attributes: | Name | Type | Description | | --- | --- | --- | | `force` | `Vector3d` | A `Vector3d` representing the linear force vector in Newtons ($N$). | | `torque` | `Vector3d` | A `Vector3d` representing the rotational moment vector in Newton-meters (Nm). | | `header` | `Optional[Header]` | Optional metadata header providing temporal and spatial context. | | `covariance` | `Optional[List[float]]` | Optional flattened 6x6 composed covariance matrix representing the uncertainty of the force-torque measurement. | | `covariance_type` | `Optional[int]` | Enum integer representing the parameterization of the covariance matrix. | Unit Standards To ensure platform-wide consistency, all force components should be specified in **Newtons** and torque in **Newton-meters**. ###### Querying with the **`.Q` Proxy**¶ This class fields are queryable when constructing a `QueryOntologyCatalog` via the **`.Q` proxy**. Check the fields documentation for detailed description. Example ``` from mosaicolabs import MosaicoClient, ForceTorque, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter ForceTorques with force X-component AND torque Z-component qresponse = client.query( QueryOntologyCatalog(ForceTorque.Q.force.x.gt(5.0)) .with_expression(ForceTorque.Q.torque.z.lt(10)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ForceTorque.Q.force.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### force `instance-attribute` ¶ ``` force ``` 3D linear force vector ###### Querying with the **`.Q` Proxy**¶ Force components are queryable through the `force` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ForceTorque.Q.force.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `ForceTorque.Q.force.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `ForceTorque.Q.force.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, ForceTorque, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find where the linear X-force exceeds 50N qresponse = client.query(QueryOntologyCatalog(ForceTorque.Q.force.x.gt(50.0))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ForceTorque.Q.force.x.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### torque `instance-attribute` ¶ ``` torque ``` 3D torque vector ###### Querying with the **`.Q` Proxy**¶ Torque components are queryable through the `torque` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `ForceTorque.Q.torque.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `ForceTorque.Q.torque.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `ForceTorque.Q.torque.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, ForceTorque, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find where the linear Y-torque is small qresponse = client.query(QueryOntologyCatalog(ForceTorque.Q.torque.y.lt(0.02))) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific data value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(ForceTorque.Q.torque.y.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` #### covariance `class-attribute` `instance-attribute` ¶ ``` covariance = None ``` Optional list of 64-bit floats representing the flattened matrix. ###### Querying with the **`.Q` Proxy**¶ Non-Queryable The field is not queryable with the **`.Q` Proxy**. #### covariance\_type `class-attribute` `instance-attribute` ¶ ``` covariance_type = None ``` Optional 16-bit integer representing the covariance enum. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `CovarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `covariance_type` component. #### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. #### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | #### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` --- ## mosaicolabs.models.platform.Topic ¶ Bases: `PlatformBase` Represents a read-only view of a server-side Topic platform resource. The `Topic` class provides access to topic-specific system metadata, such as the ontology tag (e.g., 'imu', 'camera') and the serialization format. It serves as a metadata-rich view of an individual data stream within the platform catalog. Data Retrieval This class provides a **metadata-only** view of the topic. To retrieve the actual time-series messages contained within the topic, you must use the `TopicHandler.get_data_streamer()` method from a `TopicHandler` instance. ##### Querying with the **`.Q` Proxy**¶ The `user_metadata` field of this class is queryable when constructing a `QueryTopic` via the **`.Q` proxy**. Check the documentation of the `PlatformBase` to construct a a valid expression for the builders involving the `user_metadata` component. Example ``` from mosaicolabs import MosaicoClient, Topic, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.Q.user_metadata["update_rate_hz"].eq(100), # Access the keys using the [] operator Topic.Q.user_metadata["interface.type"].eq("canbus"), # Navigate the nested dicts using the dot notation ) ) # # The same query using `with_expression` # qresponse = client.query( # QueryTopic() # .with_expression(Topic.Q.user_metadata["update_rate_hz"].eq(100)) # .with_expression( # Topic.Q.user_metadata["interface.type"].match("canbus") # ) # ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### user\_metadata `instance-attribute` ¶ ``` user_metadata ``` Custom user-defined key-value pairs associated with the entity. ###### Querying with the **`.Q` Proxy**¶ The `user_metadata` field is queryable when constructing a `QueryTopic` or `QuerySequence` using the **`.Q` proxy** | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Sequence.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Sequence.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | Example ``` from mosaicolabs import MosaicoClient, Topic, Sequence, QueryTopic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific keys in sequence AND topic metadata. qresponse = client.query( QueryTopic(Topic.Q.user_metadata["update_rate_hz"].geq(100)), QuerySequence(Sequence.Q.user_metadata["project.version"].match("v1.0")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### name `property` ¶ ``` name ``` The unique identifier or resource name of the entity. ###### Querying with **Query Builders**¶ The `name` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_name()` * `QueryTopic.with_name_match()` * `QuerySequence.with_name()` * `QuerySequence.with_name_match()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic().with_name("/front/imu"), QuerySequence().with_name_match("test_winter_2025_01_"), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### created\_datetime `property` ¶ ``` created_datetime ``` The UTC timestamp indicating when the entity was created on the server. ###### Querying with **Query Builders**¶ The `created_datetime` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_created_timestamp()` * `QuerySequence.with_created_timestamp()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic, Time with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific topic creation time qresponse = client.query( QueryTopic().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific sequence creation time qresponse = client.query( QuerySequence().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_locked `property` ¶ ``` is_locked ``` Indicates if the resource is currently locked. A locked state typically occurs during active writing or maintenance operations, preventing deletion or structural modifications. ###### Querying with **Query Builders**¶ The `is_locked` property is not queryable. ### total\_size\_bytes `property` ¶ ``` total_size_bytes ``` The total physical storage footprint of the entity on the server in bytes. ###### Querying with **Query Builders**¶ The `total_size_bytes` property is not queryable. ### ontology\_tag `property` ¶ ``` ontology_tag ``` The ontology type identifier (e.g., 'imu', 'gnss'). This corresponds to the `__ontology_tag__` defined in the `Serializable` class registry. ###### Querying with **Query Builders**¶ The `ontology_tag` property is queryable when constructing a `QueryTopic` via the convenience method `QueryTopic.with_ontology_tag()`. Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic().with_ontology_tag(IMU.ontology_tag()), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### sequence\_name `property` ¶ ``` sequence_name ``` The name of the parent sequence containing this topic. ###### Querying with **Query Builders**¶ The `sequence_name` property is not queryable directly. Use `QuerySequence` to query for sequences. Example ``` from mosaicolabs import MosaicoClient, Topic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QuerySequence().with_name("test_winter_20260129_103000") ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### chunks\_number `property` ¶ ``` chunks_number ``` The number of physical data chunks stored for this topic. May be `None` if the server did not provide detailed storage statistics. ###### Querying with **Query Builders**¶ The `chunks_number` property is not queryable. ### serialization\_format `property` ¶ ``` serialization_format ``` The format used to serialize the topic data (e.g., 'arrow', 'image'). This corresponds to the `SerializationFormat` enum. ###### Querying with **Query Builders**¶ The `serialization_format` property is not queryable. ## mosaicolabs.models.platform.Sequence ¶ Bases: `PlatformBase` Represents a read-only view of a server-side Sequence platform resource. The `Sequence` class is designed to hold system-level metadata and enable fluid querying of user-defined properties. It serves as the primary metadata container for a logical grouping of related topics. Data Retrieval This class provides a **metadata-only** view of the sequence. To retrieve the actual time-series data contained within the sequence, you must use the `SequenceHandler.get_data_streamer()` method from a `SequenceHandler` instance. ##### Querying with the **`.Q` Proxy**¶ The `user_metadata` field of this class is queryable when constructing a `QuerySequence` via the **`.Q` proxy**. Check the documentation of the `PlatformBase` to construct a a valid expression for the builders involving the `user_metadata` component. Example ``` from mosaicolabs import MosaicoClient, Sequence, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QuerySequence( Sequence.Q.user_metadata["project"].eq("Apollo"), # Access the keys using the [] operator Sequence.Q.user_metadata["vehicle.software_stack.planning"].match("plan-4."), # Navigate the nested dicts using the dot notation ) ) # # The same query using `with_expression` # qresponse = client.query( # QuerySequence() # .with_expression(Sequence.Q.user_metadata["project"].eq("Apollo")) # .with_expression( # Sequence.Q.user_metadata["vehicle.software_stack.planning"].match("plan-4.") # ) # ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### user\_metadata `instance-attribute` ¶ ``` user_metadata ``` Custom user-defined key-value pairs associated with the entity. ###### Querying with the **`.Q` Proxy**¶ The `user_metadata` field is queryable when constructing a `QueryTopic` or `QuerySequence` using the **`.Q` proxy** | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Sequence.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Sequence.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | Example ``` from mosaicolabs import MosaicoClient, Topic, Sequence, QueryTopic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific keys in sequence AND topic metadata. qresponse = client.query( QueryTopic(Topic.Q.user_metadata["update_rate_hz"].geq(100)), QuerySequence(Sequence.Q.user_metadata["project.version"].match("v1.0")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### name `property` ¶ ``` name ``` The unique identifier or resource name of the entity. ###### Querying with **Query Builders**¶ The `name` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_name()` * `QueryTopic.with_name_match()` * `QuerySequence.with_name()` * `QuerySequence.with_name_match()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic().with_name("/front/imu"), QuerySequence().with_name_match("test_winter_2025_01_"), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### created\_datetime `property` ¶ ``` created_datetime ``` The UTC timestamp indicating when the entity was created on the server. ###### Querying with **Query Builders**¶ The `created_datetime` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_created_timestamp()` * `QuerySequence.with_created_timestamp()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic, Time with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific topic creation time qresponse = client.query( QueryTopic().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific sequence creation time qresponse = client.query( QuerySequence().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_locked `property` ¶ ``` is_locked ``` Indicates if the resource is currently locked. A locked state typically occurs during active writing or maintenance operations, preventing deletion or structural modifications. ###### Querying with **Query Builders**¶ The `is_locked` property is not queryable. ### total\_size\_bytes `property` ¶ ``` total_size_bytes ``` The total physical storage footprint of the entity on the server in bytes. ###### Querying with **Query Builders**¶ The `total_size_bytes` property is not queryable. ### topics `property` ¶ ``` topics ``` Returns the list of names for all topics contained within this sequence. Accessing Topic Data This property returns string identifiers. To interact with topic data or metadata, use the `MosaicoClient.topic_handler()` factory. ###### Querying with **Query Builders**¶ The `topics` property is not queryable directly. Use `QueryTopic` to query for topics. Example ``` from mosaicolabs import MosaicoClient, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic().with_name("/sensors/camera/front/image_raw") ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.platform.platform\_base.PlatformBase ¶ Bases: `BaseModel`, `_QueryProxyMixin` Base class for Mosaico Sequence and Topic entities. The `PlatformBase` serves as a read-only view of a server-side resource. It is designed to hold system-level metadata and enable fluid querying of user-defined properties. ##### Core Functionality¶ 1. **System Metadata**: Consolidates attributes like storage size and locking status that are common across the catalog. 2. **Query Interface**: Inherits from internal `_QueryableModel` to support expressive syntax for filtering resources (e.g., `Sequence.Q.user_metadata["env"] == "prod"`). Read-Only Entities Instances of this class are factory-generated from server responses. Users should not instantiate this class directly. Attributes: | Name | Type | Description | | --- | --- | --- | | `user_metadata` | `Dict[str, Any]` | A dictionary of custom key-value pairs assigned by the user. | ##### Querying with the **`.Q` Proxy**¶ The `user_metadata` field is queryable when constructing a `QueryTopic` or `QuerySequence` via the **`.Q` proxy**. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | Universal Compatibility The `` placeholder represents any Mosaico class derived by `PlatformBase` (i.e. `Topic`, `Sequence`) Example ``` from mosaicolabs import MosaicoClient, Topic, Sequence, QueryTopic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific metadata key value. qresponse = client.query( QueryTopic(Topic.Q.user_metadata["update_rate_hz"].geq(100)) ) # Filter for a specific nested metadata key value. qresponse = client.query( QuerySequence(Sequence.Q.user_metadata["project.version"].match("v1.0")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### user\_metadata `instance-attribute` ¶ ``` user_metadata ``` Custom user-defined key-value pairs associated with the entity. ###### Querying with the **`.Q` Proxy**¶ The `user_metadata` field is queryable when constructing a `QueryTopic` or `QuerySequence` using the **`.Q` proxy** | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Sequence.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Sequence.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key"]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | | `Topic.Q.user_metadata["key.subkey.subsubkey..."]` | `String`, `Numeric`, `Boolean` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()`, `.match()` | Example ``` from mosaicolabs import MosaicoClient, Topic, Sequence, QueryTopic, QuerySequence with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific keys in sequence AND topic metadata. qresponse = client.query( QueryTopic(Topic.Q.user_metadata["update_rate_hz"].geq(100)), QuerySequence(Sequence.Q.user_metadata["project.version"].match("v1.0")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### name `property` ¶ ``` name ``` The unique identifier or resource name of the entity. ###### Querying with **Query Builders**¶ The `name` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_name()` * `QueryTopic.with_name_match()` * `QuerySequence.with_name()` * `QuerySequence.with_name_match()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic().with_name("/front/imu"), QuerySequence().with_name_match("test_winter_2025_01_"), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### created\_datetime `property` ¶ ``` created_datetime ``` The UTC timestamp indicating when the entity was created on the server. ###### Querying with **Query Builders**¶ The `created_datetime` property is queryable when constructing a `QueryTopic` or a `QuerySequence` via the convenience methods: * `QueryTopic.with_created_timestamp()` * `QuerySequence.with_created_timestamp()` Example ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic, Time with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific topic creation time qresponse = client.query( QueryTopic().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific sequence creation time qresponse = client.query( QuerySequence().with_created_timestamp(time_start=Time.from_float(1765432100)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_locked `property` ¶ ``` is_locked ``` Indicates if the resource is currently locked. A locked state typically occurs during active writing or maintenance operations, preventing deletion or structural modifications. ###### Querying with **Query Builders**¶ The `is_locked` property is not queryable. ### total\_size\_bytes `property` ¶ ``` total_size_bytes ``` The total physical storage footprint of the entity on the server in bytes. ###### Querying with **Query Builders**¶ The `total_size_bytes` property is not queryable. --- ## mosaicolabs.models.sensors.IMU ¶ Bases: `Serializable`, `HeaderMixin` Inertial Measurement Unit data. This model aggregates raw or estimated motion data from accelerometers and gyroscopes, providing a high-frequency snapshot of an object's inertial state. Attributes: | Name | Type | Description | | --- | --- | --- | | `acceleration` | `Vector3d` | Linear acceleration vector [ax, ay, az] in $m/s^2$. | | `angular_velocity` | `Vector3d` | Angular velocity vector [wx, wy, wz] in $rad/s$. | | `orientation` | `Optional[Quaternion]` | Optional estimated orientation expressed as a quaternion. | | `header` | `Optional[Header]` | Standard metadata providing temporal and spatial reference. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter IMU data based on physical thresholds or metadata within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Find high-acceleration events (e.g., impacts) on the X-axis qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.x.gt(15.0)) .with_expression(IMU.Q.angular_velocity.z.gt(1.0)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.x.gt(15.0), include_timestamp_range=True) .with_expression(IMU.Q.angular_velocity.z.gt(1.0)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### acceleration `instance-attribute` ¶ ``` acceleration ``` Linear acceleration component. ###### Querying with the **`.Q` Proxy**¶ Acceleration components are queryable through the `acceleration` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `IMU.Q.acceleration.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.acceleration.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.acceleration.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for high-impact events qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.z.gt(19.6)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(IMU.Q.acceleration.z.gt(19.6), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### angular\_velocity `instance-attribute` ¶ ``` angular_velocity ``` Angular velocity component. ###### Querying with the **`.Q` Proxy**¶ Angular velocities components are queryable through the `angular_velocity` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `IMU.Q.angular_velocity.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.angular_velocity.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.angular_velocity.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for high-turns events qresponse = client.query( QueryOntologyCatalog(IMU.Q.angular_velocity.z.gt(1.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(IMU.Q.angular_velocity.z.gt(1.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### orientation `class-attribute` `instance-attribute` ¶ ``` orientation = None ``` Estimated orientation [qx, qy, qz, qw] (optional). ###### Querying with the **`.Q` Proxy**¶ Estimated orientation components are queryable through the `orientation` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `IMU.Q.orientation.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.orientation.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.orientation.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `IMU.Q.orientation.w` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, IMU, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for orientation component values qresponse = client.query( QueryOntologyCatalog(IMU.Q.orientation.z.gt(0.707)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(IMU.Q.orientation.z.gt(0.707), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.GPSStatus ¶ Bases: `Serializable`, `HeaderMixin` Status of the GNSS receiver and satellite fix. This class encapsulates quality metrics and operational state of the GNSS receiver, including fix type, satellite usage, and precision dilution factors. Attributes: | Name | Type | Description | | --- | --- | --- | | `status` | `int` | Fix status indicator (e.g., No Fix, 2D, 3D). | | `service` | `int` | Service used for the fix (e.g., GPS, GLONASS, Galileo). | | `satellites` | `Optional[int]` | Number of satellites currently visible or used in the solution. | | `hdop` | `Optional[float]` | Horizontal Dilution of Precision (lower is better). | | `vdop` | `Optional[float]` | Vertical Dilution of Precision (lower is better). | | `header` | `Optional[Header]` | Standard metadata providing temporal and spatial reference. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter status data based on fix quality or precision metrics within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for high-quality fixes (low HDOP) qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.hdop.lt(2.0)) .with_expression(GPSStatus.Q.satellites.geq(6)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.hdop.lt(2.0), include_timestamp_range=True) .with_expression(GPSStatus.Q.satellites.geq(6)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### status `instance-attribute` ¶ ``` status ``` Fix status. ###### Querying with the **`.Q` Proxy**¶ The fix status is queryable via the `status` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPSStatus.Q.status` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for valid fixes qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.status.gt(0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.status.gt(0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### service `instance-attribute` ¶ ``` service ``` Service used (GPS, GLONASS, etc). ###### Querying with the **`.Q` Proxy**¶ The service identifier is queryable via the `service` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPSStatus.Q.service` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for specific service ID qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.service.eq(1)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.service.eq(1), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### satellites `class-attribute` `instance-attribute` ¶ ``` satellites = None ``` Satellites visible/used. ###### Querying with the **`.Q` Proxy**¶ Satellite count is queryable via the `satellites` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPSStatus.Q.satellites` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for fixes with at least 6 satellites qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.satellites.geq(6)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.satellites.geq(6), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### hdop `class-attribute` `instance-attribute` ¶ ``` hdop = None ``` Horizontal Dilution of Precision. ###### Querying with the **`.Q` Proxy**¶ HDOP values are queryable via the `hdop` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPSStatus.Q.hdop` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for excellent horizontal precision qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.hdop.lt(1.5)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.hdop.lt(1.5), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### vdop `class-attribute` `instance-attribute` ¶ ``` vdop = None ``` Vertical Dilution of Precision. ###### Querying with the **`.Q` Proxy**¶ VDOP values are queryable via the `vdop` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPSStatus.Q.vdop` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPSStatus with MosaicoClient.connect("localhost", 6726) as client: # Filter for good vertical precision qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.vdop.lt(2.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPSStatus.Q.vdop.lt(2.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.GPS ¶ Bases: `Serializable`, `HeaderMixin` Processed GNSS fix containing Position, Velocity, and Status. This class serves as the primary container for geodetic location data (WGS 84) and receiver state information. Attributes: | Name | Type | Description | | --- | --- | --- | | `position` | `Point3d` | Lat/Lon/Alt (WGS 84) represented as a `Point3d`. | | `velocity` | `Optional[Vector3d]` | Velocity vector [North, East, Alt] in $m/s$. | | `status` | `Optional[GPSStatus]` | Receiver status info including fix type and satellite count. | | `header` | `Optional[Header]` | Standard metadata providing temporal and spatial reference. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter GPS data based on geodetic coordinates or signal quality within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPS with MosaicoClient.connect("localhost", 6726) as client: # Find data collected above 1000m altitude qresponse = client.query( QueryOntologyCatalog(GPS.Q.position.z.gt(1000.0)) .with_expression(GPS.Q.status.satellites.geq(6)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPS.Q.position.z.gt(1000.0), include_timestamp_range=True) .with_expression(GPS.Q.status.satellites.geq(6)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### position `instance-attribute` ¶ ``` position ``` Lat/Lon/Alt (WGS 84). ###### Querying with the **`.Q` Proxy**¶ Position components are queryable through the `position` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPS.Q.position.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.position.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.position.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPS with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific latitude range qresponse = client.query( QueryOntologyCatalog(GPS.Q.position.x.between([45.0, 46.0])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPS.Q.position.x.between([45.0, 46.0]), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### velocity `class-attribute` `instance-attribute` ¶ ``` velocity = None ``` Velocity vector [North, East, Alt] m/s. ###### Querying with the **`.Q` Proxy**¶ Velocity components are queryable through the `velocity` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPS.Q.velocity.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.velocity.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.velocity.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPS with MosaicoClient.connect("localhost", 6726) as client: # Filter for high vertical velocity qresponse = client.query( QueryOntologyCatalog(GPS.Q.velocity.z.gt(5.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPS.Q.velocity.z.gt(5.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### status `class-attribute` `instance-attribute` ¶ ``` status = None ``` Receiver status information. ###### Querying with the **`.Q` Proxy**¶ Status components are queryable through the `status` field prefix. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `GPS.Q.status.satellites` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.status.hdop` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.status.vdop` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.status.status` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `GPS.Q.status.service` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, GPS with MosaicoClient.connect("localhost", 6726) as client: # Filter for high-precision fixes with at least 8 satellites qresponse = client.query( QueryOntologyCatalog(GPS.Q.status.satellites.geq(8)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(GPS.Q.status.status.eq(1), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.NMEASentence ¶ Bases: `Serializable`, `HeaderMixin` Raw NMEA 0183 sentence string. Attributes: | Name | Type | Description | | --- | --- | --- | | `sentence` | `str` | The NMEA 0183 sentence string. | | `header` | `Optional[Header]` | Standard metadata providing temporal and spatial reference. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter NMEA data based on the sentence content within a `QueryOntologyCatalog`. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `NMEASentence.Q.sentence` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, NMEASentence with MosaicoClient.connect("localhost", 6726) as client: # Filter for NMEA sentences containing "GPGGA" qresponse = client.query( QueryOntologyCatalog(NMEASentence.Q.sentence.match("GPGGA")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(NMEASentence.Q.sentence.match("GPGGA"), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### sentence `instance-attribute` ¶ ``` sentence ``` Raw ASCII sentence. ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.Magnetometer ¶ Bases: `Serializable`, `HeaderMixin` Magnetic field measurement data. This class represents the magnetic field measurements from a magnetometer sensor. Attributes: | Name | Type | Description | | --- | --- | --- | | `magnetic_field` | `Vector3d` | Magnetic field vector [mx, my, mz] in microTesla. | | `header` | `Optional[Header]` | Standard metadata providing temporal and spatial reference. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter magnetometer data based on magnetic field values within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, Magnetometer, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for magnetic field values within a specific range qresponse = client.query( QueryOntologyCatalog(Magnetometer.Q.magnetic_field.x.between(-100, 100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Magnetometer.Q.magnetic_field.x.between(-100, 100), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### magnetic\_field `instance-attribute` ¶ ``` magnetic_field ``` Magnetic field vector [mx, my, mz] in microTesla. ###### Querying with the **`.Q` Proxy**¶ The magnetic field vector is queryable via the `magnetic_field` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Magnetometer.Q.magnetic_field.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Magnetometer.Q.magnetic_field.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `Magnetometer.Q.magnetic_field.z` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Magnetometer, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for magnetic field values within a specific range qresponse = client.query( QueryOntologyCatalog(Magnetometer.Q.magnetic_field.x.between(-100, 100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Magnetometer.Q.magnetic_field.x.between(-100, 100), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.Pressure ¶ Bases: `Serializable`, `HeaderMixin`, `VarianceMixin` Represents a physical pressure value. The internal representation is always stored in **Pascals (Pa)**. Users are encouraged to use the `from_*` factory methods when initializing pressure values expressed in units other than Pascals. Attributes: | Name | Type | Description | | --- | --- | --- | | `value` | `float` | Pressure value in **Pascals (Pa)**. When using the constructor directly, the value **must** be provided in Pascals. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter pressure data based on pressure values within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, Pressure, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for pressure values within a specific range qresponse = client.query( QueryOntologyCatalog(Pressure.Q.value.between([100000, 200000])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Pressure.Q.value.between([100000, 200000]), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### variance `class-attribute` `instance-attribute` ¶ ``` variance = None ``` Optional 64-bit float representing the variance of the data. This field is injected into the model via composition, ensuring that sensor data is paired with the optional variance attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance` component. ### variance\_type `class-attribute` `instance-attribute` ¶ ``` variance_type = None ``` Optional 16-bit integer representing the variance parameterization. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance_type` component. ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### value `instance-attribute` ¶ ``` value ``` The absolute pressure reading from the sensor in Pascals. ###### Querying with the **`.Q` Proxy**¶ The pressure value is queryable via the `value` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Pressure.Q.value` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Pressure, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for pressure values within a specific range qresponse = client.query( QueryOntologyCatalog(Pressure.Q.value.between([100000, 200000])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Pressure.Q.value.between([100000, 200000]), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### from\_atm `classmethod` ¶ ``` from_atm( *, value, header=None, variance=None, variance_type=None ) ``` Creates a `Pressure` instance using the value in Atm and converting it in Pascal using the formula `Pascal = Atm * 101325`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `value` | `float` | The pressure value in Atm. | *required* | | `header` | `Optional[Header]` | The standard metadata header (optional). | `None` | | `variance` | `Optional[float]` | The variance of the data. | `None` | | `variance_type` | `Optional[int]` | Enum integer representing the variance parameterization. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Pressure` | `Pressure` | A `Pressure` instance with value in Pascal. | ### from\_bar `classmethod` ¶ ``` from_bar( *, value, header=None, variance=None, variance_type=None ) ``` Creates a `Pressure` instance using the value in Bar and converting it in Pascal using the formula `Pascal = Bar * 100000`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `value` | `float` | The pressure value in Bar. | *required* | | `header` | `Optional[Header]` | The standard metadata header (optional). | `None` | | `variance` | `Optional[float]` | The variance of the data. | `None` | | `variance_type` | `Optional[int]` | Enum integer representing the variance parameterization. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Pressure` | `Pressure` | A `Pressure` instance with value in Pascal. | ### from\_psi `classmethod` ¶ ``` from_psi( *, value, header=None, variance=None, variance_type=None ) ``` Creates a `Pressure` instance using the value in Psi and converting it in Pascal using the formula `Pascal = Psi * 6894.7572931783`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `value` | `float` | The pressure value in Psi. | *required* | | `header` | `Optional[Header]` | The standard metadata header (optional). | `None` | | `variance` | `Optional[float]` | The variance of the data. | `None` | | `variance_type` | `Optional[int]` | Enum integer representing the variance parameterization. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Pressure` | `Pressure` | A `Pressure` instance with value in Pascal. | ### to\_atm ¶ ``` to_atm() ``` Converts and returns the `Pressure` value in Atm using the formula `Atm = Pascal / 101325`. Returns: | Name | Type | Description | | --- | --- | --- | | `float` | `float` | The `Pressure` value in Atm. | ### to\_bar ¶ ``` to_bar() ``` Converts and returns the `Pressure` value in Bar using the formula `Bar = Pascal / 100000`. Returns: | Name | Type | Description | | --- | --- | --- | | `float` | `float` | The `Pressure` value in Bar. | ### to\_psi ¶ ``` to_psi() ``` Converts and returns the `Pressure` value in Psi using the formula `Psi = Pascal / 6894.7572931783`. Returns: | Name | Type | Description | | --- | --- | --- | | `float` | `float` | The `Pressure` value in Psi. | ## mosaicolabs.models.sensors.Range ¶ Bases: `Serializable`, `HeaderMixin`, `VarianceMixin` Represents a range measurement that defines a valid distance interval between the minimum and the maximum value. This with also the field of view, the radiation type and the range value. The internal representation is always stored in **meters (m)**. Attributes: | Name | Type | Description | | --- | --- | --- | | `radiation_type` | `int` | Which type of radiation the sensor used. | | `field_of_view` | `float` | The arc angle, in **Radians (rad)**, over which the distance reading is valid. | | `min_range` | `float` | Minimum range value in **Meters (m)**. Fixed distance means that the minimum range must be equal to the maximum range. | | `max_range` | `float` | Maximum range value in **Meters (m)**. Fixed distance means that the minimum range must be equal to the maximum range. | | `range` | `float` | Range value in **Meters (m)**. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter range data based on range parameters within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on range parameters qresponse = client.query( QueryOntologyCatalog(Range.Q.range.between(0.0, 10.0)) .with_epression(Range.Q.radiation_type.eq(0)) .with_epression(Range.Q.max_range.between(70.0, 90.0)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Range.Q.range.between(0.0, 10.0), include_timestamp_range=True) .with_epression(Range.Q.radiation_type.eq(0)) .with_epression(Range.Q.max_range.between(70.0, 90.0)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### variance `class-attribute` `instance-attribute` ¶ ``` variance = None ``` Optional 64-bit float representing the variance of the data. This field is injected into the model via composition, ensuring that sensor data is paired with the optional variance attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance` component. ### variance\_type `class-attribute` `instance-attribute` ¶ ``` variance_type = None ``` Optional 16-bit integer representing the variance parameterization. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance_type` component. ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### radiation\_type `instance-attribute` ¶ ``` radiation_type ``` Which type of radiation the sensor used. ###### Querying with the **`.Q` Proxy**¶ The radiation\_type is queryable via the `radiation_type` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Range.Q.radiation_type` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on radiation type qresponse = client.query( QueryOntologyCatalog(Range.Q.radiation_type.eq(0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### field\_of\_view `instance-attribute` ¶ ``` field_of_view ``` The arc angle, in radians, over which the distance reading is valid. ###### Querying with the **`.Q` Proxy**¶ The field\_of\_view is queryable via the `field_of_view` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Range.Q.field_of_view` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on field of view qresponse = client.query( QueryOntologyCatalog(Range.Q.field_of_view.between(0.0, 1.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### min\_range `instance-attribute` ¶ ``` min_range ``` Minimum range value in meters. Fixed distance means that the minimum range must be equal to the maximum range. ###### Querying with the **`.Q` Proxy**¶ The min\_range is queryable via the `min_range` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Range.Q.min_range` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on minimum range qresponse = client.query( QueryOntologyCatalog(Range.Q.min_range.between(0.0, 10.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### max\_range `instance-attribute` ¶ ``` max_range ``` Maximum range value in meters. Fixed distance means that the minimum range must be equal to the maximum range. ###### Querying with the **`.Q` Proxy**¶ The max\_range is queryable via the `max_range` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Range.Q.max_range` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on maximum range qresponse = client.query( QueryOntologyCatalog(Range.Q.max_range.between(0.0, 10.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### range `instance-attribute` ¶ ``` range ``` Range value in meters. ###### Querying with the **`.Q` Proxy**¶ The range is queryable via the `range` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Range.Q.range` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Range, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for range data based on range qresponse = client.query( QueryOntologyCatalog(Range.Q.range.between(0.0, 10.0)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Range.Q.range.between(0.0, 10.0), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### validate\_min\_and\_max\_range ¶ ``` validate_min_and_max_range() ``` Ensures that `min_range` is smaller or equal to `max_range`. ### validate\_range ¶ ``` validate_range() ``` Ensures that `range` is between `min_range` and `max_range`. ## mosaicolabs.models.sensors.Temperature ¶ Bases: `Serializable`, `HeaderMixin`, `VarianceMixin` Represents a thermodynamic temperature. The internal representation is always stored in **Kelvin (K)**. Users are encouraged to use the `from_*` factory methods when initializing temperature values expressed in units other than Kelvin. Attributes: | Name | Type | Description | | --- | --- | --- | | `value` | `float` | Temperature value in **Kelvin (K)**. When using the constructor directly, the value **must** be provided in Kelvin. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter temperature data based on temperature values within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, Temperature, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for temperature values within a specific range qresponse = client.query( QueryOntologyCatalog(Temperature.Q.value.between([273.15, 373.15])) .with_expression(Temperature.Q.header.stamp.sec.between(1700000000, 1800000000)), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Temperature.Q.value.between([273.15, 373.15]), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### variance `class-attribute` `instance-attribute` ¶ ``` variance = None ``` Optional 64-bit float representing the variance of the data. This field is injected into the model via composition, ensuring that sensor data is paired with the optional variance attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance` component. ### variance\_type `class-attribute` `instance-attribute` ¶ ``` variance_type = None ``` Optional 16-bit integer representing the variance parameterization. This field is injected into the model via composition, ensuring that sensor data is paired with the optional covariance type attribute. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `VarianceMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `variance_type` component. ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### value `instance-attribute` ¶ ``` value ``` Temperature value in Kelvin. ###### Querying with the **`.Q` Proxy**¶ The temperature value is queryable via the `value` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Temperature.Q.value` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, Temperature, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for temperature values within a specific range qresponse = client.query( QueryOntologyCatalog(Temperature.Q.value.between([273.15, 373.15])) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") # Filter for a specific component value and extract the first and last occurrence times qresponse = client.query( QueryOntologyCatalog(Temperature.Q.value.between([273.15, 373.15]), include_timestamp_range=True) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {{topic.name: [topic.timestamp_range.start, topic.timestamp_range.end] for topic in item.topics}}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### from\_celsius `classmethod` ¶ ``` from_celsius( *, value, header=None, variance=None, variance_type=None ) ``` Creates a `Temperature` instance using the value in Celsius and converting it in Kelvin using the formula `Kelvin = Celsius + 273.15`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `value` | `float` | The temperature value in Celsius. | *required* | | `header` | `Optional[Header]` | The standard metadata header (optional). | `None` | | `variance` | `Optional[float]` | The variance of the data. | `None` | | `variance_type` | `Optional[int]` | Enum integer representing the variance parameterization. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Temperature` | `Temperature` | A `Temperature` instance with value in Kelvin. | ### from\_fahrenheit `classmethod` ¶ ``` from_fahrenheit( *, value, header=None, variance=None, variance_type=None ) ``` Creates a `Temperature` instance using the value in Fahrenheit and converting it in Kelvin using the formula `Kelvin = (Fahrenheit - 32) * 5 / 9 + 273.15`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `value` | `float` | The temperature value in Celsius. | *required* | | `header` | `Optional[Header]` | The standard metadata header (optional). | `None` | | `variance` | `Optional[float]` | The variance of the data. | `None` | | `variance_type` | `Optional[int]` | Enum integer representing the variance parameterization. | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Temperature` | `Temperature` | A `Temperature` instance with value in Kelvin. | ### to\_celsius ¶ ``` to_celsius() ``` Converts and returns the `Temperature` value in Celsius using the formula `Celsius = Kelvin - 273.15`. Returns: | Name | Type | Description | | --- | --- | --- | | `float` | `float` | The `Temperature` value in Celsius. | ### to\_fahrenheit ¶ ``` to_fahrenheit() ``` Converts and returns the `Temperature` value in Fahrenheit using the formula `Fahrenheit = (Kelvin - 273.15) * 9 / 5 + 32`. Returns: | Name | Type | Description | | --- | --- | --- | | `float` | `float` | The `Temperature` value in Fahrenheit. | ## mosaicolabs.models.sensors.RobotJoint ¶ Bases: `Serializable`, `HeaderMixin` Snapshot of robot joint states. Arrays must be index-aligned (e.g., names[0] corresponds to positions[0]). Attributes: | Name | Type | Description | | --- | --- | --- | | `names` | `List[str]` | Names of the different robot joints | | `positions` | `List[float]` | Positions ([rad] or [m]) of the different robot joints | | `velocities` | `List[float]` | Velocities ([rad/s] or [m/s]) of the different robot joints | | `efforts` | `List[float]` | Efforts ([N] or [N/m]) applied to the different robot joints | ##### Querying with the **`.Q` Proxy**¶ The robot joint states cannot be queried via the `.Q` proxy. ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### names `instance-attribute` ¶ ``` names ``` Names of the different robot joints ###### Querying with the **`.Q` Proxy**¶ The names are not queryable via the `.Q` proxy (Lists are not supported yet). ### positions `instance-attribute` ¶ ``` positions ``` Positions ([rad] or [m]) of the different robot joints ###### Querying with the **`.Q` Proxy**¶ The positions are not queryable via the `.Q` proxy (Lists are not supported yet). ### velocities `instance-attribute` ¶ ``` velocities ``` Velocities ([rad/s] or [m/s]) of the different robot joints ###### Querying with the **`.Q` Proxy**¶ The velocities are not queryable via the `.Q` proxy (Lists are not supported yet). ### efforts `instance-attribute` ¶ ``` efforts ``` Efforts ([N] or [N/m]) applied to the different robot joints ###### Querying with the **`.Q` Proxy**¶ The efforts are not queryable via the `.Q` proxy (Lists are not supported yet). ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.models.sensors.Image ¶ Bases: `Serializable`, `HeaderMixin` Represents raw, uncompressed image data. This class provides a flattened, row-major binary representation of an image. It is designed to handle: 1. **Arbitrary Data Types**: From standard uint8 RGB to float32 Depth and uint16 IR. 2. **Memory Layouts**: Explicit control over `stride` (stride) and endianness (`is_bigendian`). 3. **Transport**: Can act as a container for RAW bytes or wrap them in lossless containers (PNG). Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `bytes` | The flattened image memory buffer. | | `format` | `ImageFormat` | The format used for serialization ('png' or 'raw'). | | `width` | `int` | The width of the image in pixels. | | `height` | `int` | The height of the image in pixels. | | `stride` | `int` | Bytes per row. Essential for alignment. | | `encoding` | `str` | Pixel format (e.g., 'bgr8', 'mono16'). | | `is_bigendian` | `bool` | True if data is Big-Endian. Defaults to system endianness if null. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter image data based on image parameters within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on image parameters qresponse = client.query( QueryOntologyCatalog(Image.Q.width.between(1500, 2000)) .with_expression(Image.Q.height.between(1500, 2000)) .with_expression(Image.Q.format.eq("png")), ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### data `instance-attribute` ¶ ``` data ``` The flattened image memory buffer. ###### Querying with the **`.Q` Proxy**¶ The data is not queryable via the `data` field (bytes are not comparable). ### format `instance-attribute` ¶ ``` format ``` The format used for serialization ('png' or 'raw'). ###### Querying with the **`.Q` Proxy**¶ The format is queryable via the `format` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.format` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on format qresponse = client.query( QueryOntologyCatalog(Image.Q.format.eq(ImageFormat.PNG)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### width `instance-attribute` ¶ ``` width ``` The width of the image in pixels. ###### Querying with the **`.Q` Proxy**¶ The width is queryable via the `width` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.width` | `Integer` | `.eq()`, `.neq()`, `.gt()`, `.gte()`, `.lt()`, `.lte()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on width qresponse = client.query( QueryOntologyCatalog(Image.Q.width.between(0, 100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### height `instance-attribute` ¶ ``` height ``` The height of the image in pixels. ###### Querying with the **`.Q` Proxy**¶ The height is queryable via the `height` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.height` | `Integer` | `.eq()`, `.neq()`, `.gt()`, `.gte()`, `.lt()`, `.lte()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on height qresponse = client.query( QueryOntologyCatalog(Image.Q.height.between(0, 100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### stride `instance-attribute` ¶ ``` stride ``` The number of bytes per row of the image. ###### Querying with the **`.Q` Proxy**¶ The stride is queryable via the `stride` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.stride` | `Integer` | `.eq()`, `.neq()`, `.gt()`, `.gte()`, `.lt()`, `.lte()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on stride qresponse = client.query( QueryOntologyCatalog(Image.Q.stride.between(0, 100)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### encoding `instance-attribute` ¶ ``` encoding ``` The pixel encoding (e.g., 'bgr8', 'mono16'). Optional field. ###### Querying with the **`.Q` Proxy**¶ The encoding is queryable via the `encoding` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.encoding` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on encoding qresponse = client.query( QueryOntologyCatalog(Image.Q.encoding.eq("bgr8")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_bigendian `class-attribute` `instance-attribute` ¶ ``` is_bigendian = None ``` Store if the original data is Big-Endian. Optional field. ###### Querying with the **`.Q` Proxy**¶ The is\_bigendian is queryable via the `is_bigendian` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `Image.Q.is_bigendian` | `Boolean` | `.eq()`, `.neq()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, Image with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on is_bigendian qresponse = client.query( QueryOntologyCatalog(Image.Q.is_bigendian.eq(True)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### from\_linear\_pixels `classmethod` ¶ ``` from_linear_pixels( data, stride, height, width, encoding, header=None, is_bigendian=None, format=_DEFAULT_IMG_FORMAT, ) ``` Encodes linear pixel uint8 data into the storage container. **The "Wide Grayscale" Trick:** When saving complex types (like `float32` depth or `uint16` raw) into standard image containers like PNG, we cannot rely on standard RGB encoders as they might apply color corrections or bit-depth reductions. Instead, this method treats the data as a raw byte stream. It reshapes the stream into a 2D "Grayscale" image where: - `Image_Height` = `Original_Height` - `Image_Width` = `Stride` (The full row stride in bytes) This guarantees that every bit of the original memory (including padding) is preserved losslessly. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `data` | `List[int]` | Flattened list of bytes (uint8). | *required* | | `stride` | `int` | Row stride in bytes. | *required* | | `height` | `int` | Image height. | *required* | | `width` | `int` | Image width. | *required* | | `encoding` | `str` | Pixel format string. | *required* | | `format` | `ImageFormat` | Target container ('raw' or 'png'). | `_DEFAULT_IMG_FORMAT` | Returns: | Name | Type | Description | | --- | --- | --- | | `Image` | `Image` | An instantiated object. | ### to\_linear\_pixels ¶ ``` to_linear_pixels() ``` Decodes the storage container back to a linear byte list. Reverses the "Wide Grayscale" encoding to return the original, flattened memory buffer. Returns: | Type | Description | | --- | --- | | `List[int]` | List[int]: A list of uint8 integers representing the raw memory. | ### to\_pillow ¶ ``` to_pillow() ``` Converts the raw binary data into a standard PIL Image. This method performs the heavy lifting of interpretation: 1. **Decoding**: Unpacks the transport container (e.g., PNG -> bytes). 2. **Casting**: Interprets bytes according to `self.encoding` (e.g., as float32). 3. **Endianness**: Swaps bytes if the source endianness differs from the local CPU. 4. **Color Swap**: Converts BGR (common in OpenCV/Robotics) to RGB (required by PIL). Returns: | Type | Description | | --- | --- | | `Image` | PILImage.Image: A visualizable image object. | Raises: | Type | Description | | --- | --- | | `NotImplementedError` | If the encoding is unknown. | | `ValueError` | If data size doesn't match dimensions. | ### from\_pillow `classmethod` ¶ ``` from_pillow( pil_image, header=None, target_encoding=None, output_format=None, ) ``` Factory method to create an Image from a PIL object. Automatically handles: * Data flattening (row-major). * Stride calculation. * RGB to BGR conversion (if target\_encoding requires it). * Type casting (e.g., float -> uint8). Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `pil_image` | `Image` | Source image. | *required* | | `header` | `Optional[Header]` | Metadata. | `None` | | `target_encoding` | `Optional[str]` | Target pixel format (e.g., "bgr8"). | `None` | | `output_format` | `Optional[ImageFormat]` | ('raw' or 'png'). | `None` | Returns: | Name | Type | Description | | --- | --- | --- | | `Image` | `Image` | Populated data object. | ## mosaicolabs.models.sensors.CompressedImage ¶ Bases: `Serializable`, `HeaderMixin` Represents image data stored as a compressed binary blob (e.g. JPEG, PNG, H264, ...). This class acts as a data container. It delegates the complex logic of decoding (bytes -> Image) and encoding (Image -> bytes) to the registered codecs in `_IMG_CODECS_FACTORY`. Attributes: | Name | Type | Description | | --- | --- | --- | | `data` | `bytes` | The compressed binary payload. | | `format` | `str` | The format identifier string (e.g., 'jpeg', 'png'). | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter image data based on image parameters within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, CompressedImage, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on image parameters qresponse = client.query( QueryOntologyCatalog(CompressedImage.Q.format.eq("jpeg")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### data `instance-attribute` ¶ ``` data ``` The serialized (compressed) image data as bytes. ###### Querying with the **`.Q` Proxy**¶ The data is not queryable via the `data` field (bytes are not comparable). ### format `instance-attribute` ¶ ``` format ``` The compression format (e.g., 'jpeg', 'png'). ###### Querying with the **`.Q` Proxy**¶ | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CompressedImage.Q.format` | `String` | `.eq()`, `.neq()`, `.match()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, CompressedImage, QueryOntologyCatalog with MosaicoClient.connect("localhost", 6726) as client: # Filter for image data based on image parameters qresponse = client.query( QueryOntologyCatalog(CompressedImage.Q.format.eq("jpeg")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### to\_image ¶ ``` to_image() ``` Decompresses the stored binary data into a usable PIL Image object. NOTE: The function use the \_DefaultCodec which is valid for stateless formats only ('png', 'jpeg', ...). If dealing with a stateful compressed image, the conversion must be made via explicit instantiation of a StatefulDecodingSession class. Returns: | Name | Type | Description | | --- | --- | --- | | | `Optional[Image]` | PILImage.Image: A ready-to-use Pillow image object. | | `None` | `Optional[Image]` | If the data is empty or decoding fails. | ### from\_image `classmethod` ¶ ``` from_image(image, format=PNG, header=None, **kwargs) ``` Factory method to create a CompressedImage from a PIL Image. NOTE: The function use the \_DefaultCodec which is valid for stateless formats only ('png', 'jpeg', ...). If dealing with a stateful compressed image, the conversion must be made via user defined encoding algorithms. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `image` | `Image` | The source Pillow image. | *required* | | `format` | `ImageFormat` | The target compression format (default: 'jpeg'). | `PNG` | | `header` | `Optional[Header]` | Optional Header metadata. | `None` | | `**kwargs` | | Additional arguments passed to the codec's encode method (e.g., quality=90). | `{}` | Returns: | Name | Type | Description | | --- | --- | --- | | `CompressedImage` | `CompressedImage` | A new instance containing the compressed bytes. | Raises: | Type | Description | | --- | --- | | `ValueError` | If no codec is found or encoding fails. | ## mosaicolabs.models.sensors.ImageFormat ¶ Bases: `str`, `Enum` Supported containers for image formats. ## mosaicolabs.models.sensors.CameraInfo ¶ Bases: `Serializable`, `HeaderMixin` Meta-information for interpreting images from a calibrated camera. This structure mirrors standard robotics camera models (e.g., ROS `sensor_msgs/CameraInfo`). It enables pipelines to rectify distorted images or project 3D points onto the 2D image plane. Attributes: | Name | Type | Description | | --- | --- | --- | | `height` | `int` | Height in pixels of the image with which the camera was calibrated | | `width` | `int` | Width in pixels of the image with which the camera was calibrated | | `distortion_model` | `str` | The distortion model used | | `distortion_parameters` | `list[float]` | The distortion coefficients (k1, k2, t1, t2, k3...). Size depends on the model. | | `intrinsic_parameters` | `list[float]` | The 3x3 Intrinsic Matrix (K) flattened row-major. | | `rectification_parameters` | `list[float]` | The 3x3 Rectification Matrix (R) flattened row-major. | | `projection_parameters` | `list[float]` | The 3x4 Projection Matrix (P) flattened row-major. | | `binning` | `Optional[Vector2d]` | Hardware binning factor (x, y). If null, assumes (0, 0) (no binning). | | `roi` | `Optional[ROI]` | Region of Interest. Used if the image is a sub-crop of the full resolution. | ##### Querying with the **`.Q` Proxy**¶ This class is fully queryable via the **`.Q` proxy**. You can filter camera data based on camera parameters within a `QueryOntologyCatalog`. Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.height.between(1080, 2160)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### height `instance-attribute` ¶ ``` height ``` Height in pixels of the image with which the camera was calibrated ###### Querying with the **`.Q` Proxy**¶ The height is queryable via the `height` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CameraInfo.Q.height` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.height.between(1080, 2160)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### width `instance-attribute` ¶ ``` width ``` Width in pixels of the image with which the camera was calibrated ###### Querying with the **`.Q` Proxy**¶ The width is queryable via the `width` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CameraInfo.Q.width` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.width.between(1920, 3840)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### distortion\_model `instance-attribute` ¶ ``` distortion_model ``` The distortion model used ###### Querying with the **`.Q` Proxy**¶ The distortion model is queryable via the `distortion_model` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CameraInfo.Q.distortion_model` | `Categorical` | `.eq()`, `.neq()`, `.in_()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.distortion_model.eq("plumb_bob")) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### distortion\_parameters `instance-attribute` ¶ ``` distortion_parameters ``` The distortion coefficients (k1, k2, t1, t2, k3...). Size depends on the model. ###### Querying with the **`.Q` Proxy**¶ The distortion parameters are not queryable via the `.Q` proxy (Lists are not supported yet). ### intrinsic\_parameters `instance-attribute` ¶ ``` intrinsic_parameters ``` The 3x3 Intrinsic Matrix (K) flattened row-major. ###### Querying with the **`.Q` Proxy**¶ The intrinsic parameters are not queryable via the `.Q` proxy (Lists are not supported yet). ### rectification\_parameters `instance-attribute` ¶ ``` rectification_parameters ``` The 3x3 Rectification Matrix (R) flattened row-major. ###### Querying with the **`.Q` Proxy**¶ The rectification parameters cannot be queried via the `.Q` proxy (Lists are not supported yet). ### projection\_parameters `instance-attribute` ¶ ``` projection_parameters ``` The 3x4 Projection Matrix (P) flattened row-major. ###### Querying with the **`.Q` Proxy**¶ The projection parameters cannot be queried via the `.Q` proxy (Lists are not supported yet). ### binning `class-attribute` `instance-attribute` ¶ ``` binning = None ``` Hardware binning factor (x, y). If null, assumes (0, 0) (no binning). ###### Querying with the **`.Q` Proxy**¶ The binning parameters are queryable via the `binning` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CameraInfo.Q.binning.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `CameraInfo.Q.binning.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.binning.x.eq(2)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### roi `class-attribute` `instance-attribute` ¶ ``` roi = None ``` Region of Interest. Used if the image is a sub-crop of the full resolution. ###### Querying with the **`.Q` Proxy**¶ The roi parameters are queryable via the `roi` field. | Field Access Path | Queryable Type | Supported Operators | | --- | --- | --- | | `CameraInfo.Q.roi.offset.x` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `CameraInfo.Q.roi.offset.y` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `CameraInfo.Q.roi.width` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | | `CameraInfo.Q.roi.height` | `Numeric` | `.eq()`, `.neq()`, `.lt()`, `.gt()`, `.leq()`, `.geq()`, `.in_()`, `.between()` | Example ``` from mosaicolabs import MosaicoClient, QueryOntologyCatalog, CameraInfo with MosaicoClient.connect("localhost", 6726) as client: # Filter for camera data based on camera parameters qresponse = client.query( QueryOntologyCatalog(CameraInfo.Q.roi.offset.x.eq(2)) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` --- ## mosaicolabs.ml.DataFrameExtractor ¶ ``` DataFrameExtractor(sequence_handler) ``` Extracts and manages data from Mosaico Sequences, converting them into tabular DataFrames. This class serves as a high-performance bridge for training ML models or performing data analysis. It extracts data from multiple sequence topics and unifies them into a single, flattened, sparse DataFrame aligned by timestamps. Key Features: * **Memory Efficiency**: Uses a windowed approach to process multi-gigabyte sequences in chunks without overloading RAM. * **Flattening**: Automatically flattens nested structures (e.g., `pose.position.x`) into dot-notation columns. * **Sparse Alignment**: Merges multiple topics with different frequencies into a single timeline (using `NaN` for missing values at specific timestamps). Initializes the DataFrameExtractor. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `sequence_handler` | `SequenceHandler` | An active handle to a Mosaico sequence. | *required* | ### to\_pandas\_chunks ¶ ``` to_pandas_chunks( topics=None, window_sec=5.0, timestamp_ns_start=None, timestamp_ns_end=None, ) ``` Generator that yields time-windowed pandas DataFrames from the sequence. This method leverages server-side filtering and local batch processing to maintain a low memory footprint. It handles batches that cross window boundaries by carrying over the remainder to the next chunk. Important This function must be iterated (e.g. called in a for loop) Warning Setting `window_sec` to a very large value might disable windowing. The extractor will attempt to load the entire requested time range into memory. This is only recommended for small sequences or systems with high RAM capacity. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topics` | `List[str]` | Topics to extract. Defaults to all topics. | `None` | | `window_sec` | `float` | Duration of each DataFrame chunk in seconds. | `5.0` | | `timestamp_ns_start` | `int` | Global start time for extraction. | `None` | | `timestamp_ns_end` | `int` | Global end time for extraction. | `None` | Yields: | Type | Description | | --- | --- | | `DataFrame` | pd.DataFrame: A sparse, flattened DataFrame containing data from all selected topics and their fields within the current time window. | Example ``` # Obtain a dataframe with DataFrameExtractor from mosaicolabs import MosaicoClient, IMU, Image from mosaicolabs.ml import DataFrameExtractor, SyncTransformer with MosaicoClient.connect("localhost", 6726) as client: sequence_handler = client.get_sequence_handler("example_sequence") for df in DataFrameExtractor(sequence_handler).to_pandas_chunks( topics = ["/front/imu", "/front/camera/image_raw"] ): # Do something with the dataframe. # For example, you can sync the data using the `SyncTransformer`: sync_transformer = SyncTransformer( target_fps = 30, # resample at 30 Hz and fill the Nans with a Hold policy ) synced_df = sync_transformer.transform(df) # Reconstruct the image message from a dataframe row image_msg = Message.from_dataframe_row(synced_df, "/front/camera/image_raw") image_data = image_msg.get_data(Image) # Show the image image_data.to_pillow().show() # ... ``` ## mosaicolabs.ml.SyncTransformer ¶ ``` SyncTransformer( target_fps, policy=SyncHold(), timestamp_column="timestamp_ns", ) ``` Stateful resampler for Mosaico DataFrames. This class aligns heterogeneous sensor streams onto a uniform time grid. It is designed to consume the windowed outputs of the `DataFrameExtractor` sequentially, maintaining internal state to ensure signal continuity across batch boundaries. ##### Scikit-Learn Compatibility¶ The class implements the standard `fit`/`transform` interface, making it fully compliant with Scikit-learn `Pipeline` and `FeatureUnion` objects. * **fit(X)**: Captures the initial timestamp from the first chunk to align the grid. * **transform(X)**: Executes the temporal resampling logic for a single DataFrame chunk and returns a dense DataFrame. * **fit\_transform(X)**: Fits the transformer to the data and then transforms it. Key Features: * Fixed Frequency: Normalizes multi-rate sensors to a target FPS. * Stateful Persistence: Carries the last known sensor state into the next chunk. * Semantic Integrity: Correctly handles 'Late Arrivals' by yielding None for ticks preceding the first physical measurement. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `target_fps` | `float` | The desired output frequency in Hz. | *required* | | `policy` | `SyncPolicy` | A strategy implementing the `SyncPolicy` protocol. | `SyncHold()` | | `timestamp_column` | `str` | The column name containing the timestamp data. | `'timestamp_ns'` | ### fit ¶ ``` fit(X, y=None) ``` Initializes the grid alignment based on the first observed timestamp. ### transform ¶ ``` transform(X) ``` Syncronizes a sparse DataFrame chunk into a dense, uniform DataFrame. **Example with generic dataframe** ``` from mosaicolabs.ml import SyncTransformer, SyncHold # 5 Hz Target (200ms steps) transformer = SyncTransformer(target_fps=5, policy=SyncHold()) # Define a sparse dataframe with two sensors: # `sensor_a` starts at 0, `sensor_b` arrives at 600ms sparse_data = { "timestamp_ns": [ 0, 600_000_000, 900_000_000, 1_200_000_000, 1_500_000_000, ], "val1": [10.0, 11.0, None, 12.0, 13.0], "val2": [None, 1.0, 2.0, None, 3.0], } df = pd.DataFrame(sparse_data) dense_df = transformer.fit(df).transform(df) # Expected output # "timestamp_ns", "sensor_a", "sensor_b" # 0, 10.0, None # <- avoid hallucination on `sensor_b` # 200_000_000, 10.0, None # <- avoid hallucination on `sensor_b` # 400_000_000, 10.0, None # <- avoid hallucination on `sensor_b` # 600_000_000, 11.0, 1.0 # 800_000_000, 11.0, 2.0 # 1_000_000_000, 11.0, 2.0 # 1_200_000_000, 12.0, 2.0 # 1_400_000_000, 12.0, 2.0 ``` **Example with Mosaico dataframe** ``` # Obtain a dataframe with DataFrameExtractor from mosaicolabs import MosaicoClient, IMU, Image from mosaicolabs.ml import DataFrameExtractor, SyncTransformer with MosaicoClient.connect("localhost", 6726) as client: sequence_handler = client.get_sequence_handler("example_sequence") for df in DataFrameExtractor(sequence_handler).to_pandas_chunks( topics = ["/front/imu", "/front/camera/image_raw"] ): # Synch the data at 30 Hz: sync_transformer = SyncTransformer( target_fps = 30, # resample at 30 Hz and fill the Nans with a `Hold` policy ) synced_df = sync_transformer.transform(df) # Do something with the synced dataframe # ... ``` ### fit\_transform ¶ ``` fit_transform(X, y=None) ``` Fits the transformer to the data and then transforms it. ### reset ¶ ``` reset() ``` Resets the internal temporal state and cached sensor values. ## mosaicolabs.ml.SyncPolicy ¶ Bases: `Protocol` Protocol defining the interface for data synchronization policies. A `SyncPolicy` determines how sparse data samples are mapped onto a standard, dense time grid. Classes implementing this protocol are used by `SyncTransformer` to resample sensor data (e.g., holding the last value, interpolating, or dropping old data). Common implementations include: * `SyncHold`: Zero-order hold (carries the last value forward). * `SyncAsOf`: Tolerance-based hold (carries value forward only for a specific duration). * `SyncDrop`: Strict interval matching (drops data outside the current grid step). ### apply ¶ ``` apply(grid, s_ts, s_val) ``` Applies the synchronization logic to sparse samples, mapping them to the target grid. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `grid` | `ndarray` | The target dense timeline (nanosecond timestamps). | *required* | | `s_ts` | `ndarray` | The source acquisition timestamps (sparse data). | *required* | | `s_val` | `ndarray` | The source sensor values corresponding to `s_ts`. | *required* | Returns: | Type | Description | | --- | --- | | `ndarray` | np.ndarray: An object-array of the same length as `grid`, containing the synchronized values. Slots with no valid data are filled with `None`. | ## mosaicolabs.ml.SyncHold ¶ Classic Last-Value-Hold (Zero-Order Hold) synchronization. This policy carries the most recent valid sample forward to all future grid ticks until a new sample is received. It effectively creates a "step" function from the sparse samples. ### apply ¶ ``` apply(grid, s_ts, s_val) ``` Applies the Zero-Order Hold logic. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `grid` | `ndarray` | The target dense timeline (nanosecond timestamps). | *required* | | `s_ts` | `ndarray` | The source acquisition timestamps. | *required* | | `s_val` | `ndarray` | The source sensor values. | *required* | Returns: | Type | Description | | --- | --- | | `ndarray` | np.ndarray: Densely populated array where each point holds the last known value. | ## mosaicolabs.ml.SyncAsOf ¶ ``` SyncAsOf(tolerance_ns) ``` Tolerance-based 'As-Of' synchronization. Similar to `SyncHold`, but limits how far a value can be carried forward. If the time difference between the grid tick and the last sample exceeds `tolerance_ns`, the value is considered stale and the slot is left as `None`. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `tolerance_ns` | `int` | Maximum allowed age (in nanoseconds) for a sample to be valid. | *required* | ### apply ¶ ``` apply(grid, s_ts, s_val) ``` Applies the As-Of synchronization logic with tolerance check. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `grid` | `ndarray` | The target dense timeline. | *required* | | `s_ts` | `ndarray` | The source acquisition timestamps. | *required* | | `s_val` | `ndarray` | The source sensor values. | *required* | Returns: | Type | Description | | --- | --- | | `ndarray` | np.ndarray: Densely populated array, with `None` where data is missing or stale. | ## mosaicolabs.ml.SyncDrop ¶ ``` SyncDrop(step_ns) ``` Strict Interval-based 'Drop' synchronization. Only yields a value if a sample was acquired strictly within the current grid interval `(t_grid - step_ns, t_grid]`. If no sample falls in this window, the result is `None`. This is useful for event-based matching. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `step_ns` | `int` | The duration of the backward-looking window in nanoseconds. | *required* | ### apply ¶ ``` apply(grid, s_ts, s_val) ``` Applies the Drop synchronization logic. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `grid` | `ndarray` | The target dense timeline. | *required* | | `s_ts` | `ndarray` | The source acquisition timestamps. | *required* | | `s_val` | `ndarray` | The source sensor values. | *required* | Returns: | Type | Description | | --- | --- | | `ndarray` | np.ndarray: Array containing values only for populated intervals, otherwise `None`. | --- ## mosaicolabs.ros\_bridge.ROSBridge ¶ Bases: `Generic[T]` A central registry and API for ROS message to Mosaico Ontology translation. The `ROSBridge` serves as the orchestration hub for the ROS Bridge system. It maintains a global registry of all available `ROSAdapterBase` implementations and provides the high-level API used to transform raw ROS message containers into strongly-typed Mosaico `Message` objects. ##### Key Responsibilities¶ * **Adapter Discovery**: Provides methods to lookup adapters based on ROS message type strings (e.g., `sensor_msgs/msg/Imu`). * **Type Validation**: Checks if a given ROS type or Mosaico Ontology class is currently supported by the bridge. * **Execution Dispatch**: Acts as the primary entry point for the injection pipeline to delegate translation tasks to specific specialized adapters. Attributes: | Name | Type | Description | | --- | --- | --- | | `_adapters` | `Dict[str, Type[ROSAdapterBase]]` | A private class-level dictionary mapping canonical ROS message type strings to their respective adapter classes. | ### get\_adapter `classmethod` ¶ ``` get_adapter(ros_msg_type) ``` Retrieves the registered adapter class for a given ROS message type. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `ros_msg_type` | `str` | The full ROS message type string (e.g., "sensor\_msgs/msg/Image"). | *required* | Returns: | Type | Description | | --- | --- | | `Optional[Type[ROSAdapterBase]]` | The corresponding `ROSAdapterBase` subclass if found, otherwise `None`. | ### is\_msgtype\_adapted `classmethod` ¶ ``` is_msgtype_adapted(ros_msg_type) ``` Checks if a specific ROS message type has a registered translator. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if the type is supported, False otherwise. | ### is\_adapted `classmethod` ¶ ``` is_adapted(mosaico_cls) ``` Checks if a specific Mosaico Ontology class has a registered adapter. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `mosaico_cls` | `T` | The Mosaico class to check (e.g., `Image`, `Imu`). | *required* | Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if an adapter exists for this class, False otherwise. | ### from\_ros\_message `classmethod` ¶ ``` from_ros_message(ros_msg, **kwargs) ``` The high-level API for translating raw ROS message containers. This method identifies the appropriate adapter based on the `msg_type` inside the `ROSMessage` and invokes its `translate` method. It is the core function called by the `RosbagInjector` during the ingestion loop. Example ``` # Within an ingestion loop mosaico_msg = ROSBridge.from_ros_message(raw_ros_container) if mosaico_msg: writer.push(mosaico_msg) ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `ros_msg` | `ROSMessage` | The `ROSMessage` container produced by the `ROSLoader`. | *required* | | `**kwargs` | `Any` | Arbitrary context arguments passed directly to the adapter's translate method. | `{}` | Returns: | Type | Description | | --- | --- | | `Optional[Message]` | A fully constructed Mosaico `Message` if an adapter is available, otherwise `None`. | ## mosaicolabs.ros\_bridge.register\_adapter ¶ ``` register_adapter(cls) ``` A class decorator for streamlined adapter registration. This is the recommended way to register adapters in a production environment, as it couples the adapter definition directly with its registration in the bridge. Example ``` from mosaicolabs.ros_bridge import register_adapter, ROSAdapterBase @register_adapter class MySensorAdapter(ROSAdapterBase): ros_msgtype = "sensor_msgs/msg/Temperature" # ... ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `cls` | `Type[ROSAdapterBase]` | The adapter class to register. | *required* | Returns: | Type | Description | | --- | --- | | `Type[ROSAdapterBase]` | The same class, unmodified, after successful registration. | ## mosaicolabs.ros\_bridge.loader.ROSLoader ¶ ``` ROSLoader( file_path, topics=None, typestore_name=EMPTY, error_policy=LOG_WARN, custom_types=None, ) ``` Unified loader for reading and deserializing ROS 1 (.bag) and ROS 2 (.mcap, .db3) data. The `ROSLoader` acts as a resource manager that abstracts the underlying `rosbags` library. It provides a standardized Pythonic interface for filtering topics, managing custom message registries, and streaming data into the Mosaico adaptation pipeline. ##### Key Features¶ * **Multi-Format Support**: Automatically detects and handles ROS 1 and ROS 2 bag containers. * **Semantic Filtering**: Supports glob-style patterns (e.g., `/sensors/*`) to load only relevant data channels. * **Dynamic Schema Resolution**: Integrates with the `ROSTypeRegistry` to resolve proprietary message types on-the-fly. * **Memory Efficient**: Implements a generator-based iteration pattern to process large bags without loading them into RAM. Attributes: | Name | Type | Description | | --- | --- | --- | | `ACCEPTED_EXTENSIONS` | | Set of supported file extensions {'.bag', '.db3', '.mcap'}. | Initializes the loader and prepares the type registry. Upon initialization, the loader merges the global definitions from the `ROSTypeRegistry` with any `custom_types` provided specifically for this session. Example ``` from rosbags.typesys import Stores from mosaicolabs.ros_bridge import ROSLoader, LoaderErrorPolicy # Initialize to read only IMU and GPS data from an MCAP file with ROSLoader( file_path="mission_01.mcap", topics=["/imu*", "/gps/fix"], typestore_name=Stores.ROS2_HUMBLE, error_policy=LoaderErrorPolicy.RAISE ) as loader: for msg, exc in loader: if not exc: print(f"Read {msg.msg_type} from {msg.topic}") ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `file_path` | `Union[str, Path]` | Path to the bag file or directory. | *required* | | `topics` | `Optional[Union[str, List[str]]]` | A single topic name, a list of names, or glob patterns. | `None` | | `typestore_name` | `Stores` | The target ROS distribution for default message schemas. See `rosbags.typesys.Stores`. | `EMPTY` | | `error_policy` | `LoaderErrorPolicy` | How to handle errors during message iteration. | `LOG_WARN` | | `custom_types` | `Optional[Dict[str, Union[str, Path]]]` | Local overrides for message definitions (type\_name: path/to/msg). | `None` | ### topics `property` ¶ ``` topics ``` Retrieves the list of canonical topic names that will be processed. This property returns the result of the "Smart Filtering" process, which resolves any glob patterns (e.g., `/camera/*`) provided during initialization against the actual metadata contained within the bag file. Example ``` with ROSLoader(file_path="data.mcap", topics=["/sensors/*"]) as loader: # If the bag contains /sensors/imu and /sensors/gps, # this property returns ['/sensors/imu', '/sensors/gps'] print(f"Loading topics: {loader.topics}") ``` Returns: | Type | Description | | --- | --- | | `List[str]` | List[str]: A list of topic names currently matched and scheduled for loading. | ### msg\_types `property` ¶ ``` msg_types ``` Retrieves the list of ROS message types corresponding to the resolved topics. Each entry in this list represents the schema name (e.g., `sensor_msgs/msg/Image`) required to correctly deserialize the messages for the topics returned by the `.topics` property. Example ``` with ROSLoader(file_path="data.mcap") as loader: for topic, msg_type in zip(loader.topics, loader.msg_types): print(f"Topic {topic} requires schema: {msg_type}") ``` Returns: | Type | Description | | --- | --- | | `List[str | None]` | List[str]: A list of ROS message type strings in the same order | | `List[str | None]` | as the resolved topics. | ### msg\_count ¶ ``` msg_count(topic=None) ``` Returns the total number of messages to be processed based on active filters. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `topic` | `Optional[str]` | If provided, returns the count for that specific topic. If None, returns the aggregate count for all filtered topics. | `None` | Returns: | Type | Description | | --- | --- | | `int` | The total message count. | ### close ¶ ``` close() ``` Explicitly closes the bag file and releases system resources. ## mosaicolabs.ros\_bridge.loader.LoaderErrorPolicy ¶ Bases: `Enum` Defines the strategy for handling deserialization failures during bag playback. In heterogeneous datasets, it is common to encounter corrupted messages or missing type definitions for specific topics. This policy allows the user to balance system robustness against data integrity. Attributes: | Name | Type | Description | | --- | --- | --- | | `IGNORE` | | Silently skips any message that fails to deserialize. The pipeline continues uninterrupted without any log output. | | `LOG_WARN` | | (Default) Logs a warning containing the topic name and error details, then skips the message and continues. | | `RAISE` | | Immediately halts execution and raises the exception. Best used for critical data ingestion where missing even a single record is unacceptable. | ### IGNORE `class-attribute` `instance-attribute` ¶ ``` IGNORE = 'ignore' ``` Silently skips any message that fails to deserialize. ### LOG\_WARN `class-attribute` `instance-attribute` ¶ ``` LOG_WARN = 'log_warn' ``` Logs a warning containing the topic name and error details, then skips the message and continues. ### RAISE `class-attribute` `instance-attribute` ¶ ``` RAISE = 'raise' ``` Immediately halts execution and raises the exception. Best used for critical data ingestion where missing even a single record is unacceptable. ## mosaicolabs.ros\_bridge.ROSMessage `dataclass` ¶ ``` ROSMessage(bag_timestamp_ns, topic, msg_type, data) ``` The standardized container for a single ROS message record yielded by the loader. This object serves as the primary "unit of work" within the ROS Bridge pipeline. It encapsulates the raw deserialized payload along with essential storage-level metadata needed for accurate platform ingestion. ##### Life Cycle¶ 1. **Produced** by `ROSLoader` during bag iteration. 2. **Consumed** by `ROSBridge` to identify the correct adapter. 3. **Translated** by a `ROSAdapter` into a Mosaico `Message`. Example ``` # Manual construction (usually handled by the loader) msg = ROSMessage( bag_timestamp_ns=1625000000000000000, topic="/odom", msg_type="nav_msgs/msg/Odometry", data={"header": {...}, "pose": {...}} ) print(f"Processing {msg.msg_type} from {msg.topic}") if msg.header: print(f"Frame: {msg.header.frame_id}") ``` Attributes: | Name | Type | Description | | --- | --- | --- | | `bag_timestamp_ns` | `int` | Timestamp (nanoseconds) when the message was recorded to the bag file. This is the "storage time". | | `topic` | `str` | The specific topic string source (e.g., "/camera/left/image\_raw"). | | `msg_type` | `str` | The canonical ROS type string (e.g., "sensor\_msgs/msg/Image"). | | `data` | `Optional[Dict[str, Any]]` | The message payload converted into a standard nested Python dictionary. | | `header` | `Optional[ROSHeader]` | An automatically parsed `ROSHeader` if the `data` payload contains a valid header field. | ### bag\_timestamp\_ns `instance-attribute` ¶ ``` bag_timestamp_ns ``` Timestamp (nanoseconds) when the message was written to the rosbag. This corresponds to the rosbag storage time and may differ from the time the data was originally generated. ### topic `instance-attribute` ¶ ``` topic ``` The topic string of the message source. ### msg\_type `instance-attribute` ¶ ``` msg_type ``` The message ros type string. ### data `instance-attribute` ¶ ``` data ``` The message payload, converted into a standard nested Python dictionary. ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` The message payload header ## mosaicolabs.ros\_bridge.ROSInjectionConfig `dataclass` ¶ ``` ROSInjectionConfig( file_path, sequence_name, metadata, host="localhost", port=6726, ros_distro=None, on_error=Delete, custom_msgs=None, topics=None, log_level="INFO", ) ``` The central configuration object for the ROS Bag injection process. This data class serves as the single source of truth for all injection settings, decoupling the orchestration logic from CLI arguments or configuration files. It encapsulates network parameters, file paths, and advanced filtering logic required to drive a successful ingestion session. Attributes: | Name | Type | Description | | --- | --- | --- | | `file_path` | `Path` | Absolute or relative path to the input ROS bag file (.mcap, .db3, or .bag). | | `sequence_name` | `str` | The name for the new sequence to be created on the Mosaico server. | | `metadata` | `dict` | User-defined metadata to attach to the sequence (e.g., driver, weather, location). | | `host` | `str` | Hostname or IP of the Mosaico server. Defaults to "localhost". | | `port` | `int` | Port of the Mosaico server. Defaults to 6726. | | `ros_distro` | `Optional[Stores]` | The target ROS distribution for message parsing (e.g., Stores.ROS2\_HUMBLE). See `rosbags.typesys.Stores`. | | `on_error` | `OnErrorPolicy` | Behavior when an ingestion error occurs (Delete the partial sequence or Report the error). | | `custom_msgs` | `Optional[List[Tuple]]` | List of custom .msg definitions to register before loading. | | `topics` | `Optional[List[str]]` | List of topics to filter, supporting glob patterns (e.g., ["/cam/\*"]). | | `log_level` | `str` | Logging verbosity level ("DEBUG", "INFO", "WARNING", "ERROR"). | Example ``` from pathlib import Path from rosbags.typesys import Stores from mosaicolabs.enum import OnErrorPolicy from mosaicolabs.ros_bridge import ROSInjectionConfig config = ROSInjectionConfig( file_path=Path("recording.mcap"), sequence_name="test_drive_01", metadata={"environment": "urban", "vehicle": "robot_alpha"}, ros_distro=Stores.ROS2_FOXY, on_error=OnErrorPolicy.Delete ) ``` ### ros\_distro `class-attribute` `instance-attribute` ¶ ``` ros_distro = None ``` The specific ROS distribution to use for message parsing (e.g., Stores.ROS2\_HUMBLE). If None, defaults to Empty/Auto. See `rosbags.typesys.Stores`. ### on\_error `class-attribute` `instance-attribute` ¶ ``` on_error = Delete ``` the `SequenceWriter` `on_error` behavior when a sequence write fails (Report vs Delete) ### custom\_msgs `class-attribute` `instance-attribute` ¶ ``` custom_msgs = None ``` A list of tuples (package\_name, path, store) to register custom .msg definitions before loading. For example, for "my\_robot\_msgs/msg/Location" pass: package\_name = "my\_robot\_msgs"; path = path/to/Location.msg; store = Stores.ROS2\_HUMBLE (e.g.) or None See `rosbags.typesys.Stores`. ### topics `class-attribute` `instance-attribute` ¶ ``` topics = None ``` A list of specific topics to filter (supports glob patterns). If None, all compatible topics are loaded. ## mosaicolabs.ros\_bridge.RosbagInjector ¶ ``` RosbagInjector(config) ``` Main controller for the ROS Bag ingestion workflow. The `RosbagInjector` orchestrates the entire data pipeline from the physical storage to the remote Mosaico server. It manages the initialization of the registry, establishes network connections, and drives the main adaptation loop. **Core Workflow Architecture:** 1. **Registry Initialization**: Pre-loads custom message definitions via the `ROSTypeRegistry`. 2. **Resource Management**: Opens the `ROSLoader` for file access and the `MosaicoClient` for networking. 3. **Stream Negotiation**: Creates a `SequenceWriter` on the server and opens individual `TopicWriter` streams. 4. **Adaptation Loop**: Iterates through ROS records, translates them via the `ROSBridge`, and pushes them to the server. Example ``` from mosaicolabs.ros_bridge import RosbagInjector, ROSInjectionConfig # Define configuration config = ROSInjectionConfig(file_path=Path("data.db3"), sequence_name="auto_ingest") # Initialize and run injector = RosbagInjector(config) injector.run() # This handles the full lifecycle including cleanup on failure ``` Attributes: | Name | Type | Description | | --- | --- | --- | | `cfg` | `ROSInjectionConfig` | The active configuration settings. | | `console` | `Console` | The rich console instance for logging and UI output. | | `_ignored_topics` | `Set[str]` | Cache of topics that lack a compatible adapter, used for fast-fail filtering. | Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `config` | `ROSInjectionConfig` | The fully resolved configuration object. | *required* | ### run ¶ ``` run() ``` Main execution entry point for the injection pipeline. This method establishes the necessary contexts (Network Client, File Loader, Server Writer) and executes the processing loop. It handles graceful shutdowns in case of user interrupts and provides a summary report upon completion. Raises: | Type | Description | | --- | --- | | `KeyboardInterrupt` | If the user cancels the operation via Ctrl+C. | | `Exception` | Any fatal error encountered during networking or file access. | ## mosaicolabs.ros\_bridge.ROSTypeRegistry ¶ A context-aware singleton registry for custom ROS message definitions. ROS message definitions (`.msg`) are not self-contained; they often vary between distributions (e.g., `std_msgs/Header` has different fields in ROS 1 Noetic vs. ROS 2 Humble). The `ROSTypeRegistry` resolves this by implementing a **Context-Aware Singleton** that organizes schemas into "Profiles" (`rosbags.typesys.Stores`). ##### Why Use a Registry?¶ * **Conflict Resolution**: Prevents name collisions when processing data from mixed ROS 1 and ROS 2 sources in the same environment. * **Proprietary Support**: Allows the system to ingest non-standard messages (e.g., custom robot state or specialized sensor payloads). * **Cascading Logic**: Implements an "Overlay" mechanism where global definitions provide a baseline, and distribution-specific definitions provide high-precision overrides. Attributes: | Name | Type | Description | | --- | --- | --- | | `_registry` | `Dict[str, Dict[str, str]]` | Internal private storage for definitions. The first key level represents the **Scope** (e.g., "GLOBAL", "Stores.ROS2\_FOXY"), and the second level maps the **Message Type** to its raw **Definition String**. | ### register `classmethod` ¶ ``` register(msg_type, source, store=None) ``` Registers a single custom message type into the registry. This is the primary method for adding individual schema definitions. The `source` can be a physical file path or a raw string containing the ROS `.msg` syntax. Example ``` # Register a proprietary battery message for a specific distro ROSTypeRegistry.register( msg_type="limo_msgs/msg/BatteryState", source=Path("./msgs/BatteryState.msg"), store=Stores.ROS2_HUMBLE ) # Register a simple custom type globally using a raw string ROSTypeRegistry.register( msg_type="custom_msgs/msg/SimpleFlag", source="bool flag_active\nstring label" ) ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `msg_type` | `str` | The canonical ROS type name (e.g., "package/msg/TypeName"). | *required* | | `source` | `Union[str, Path]` | A `Path` object to a `.msg` file or a raw text string of the definition. | *required* | | `store` | `Optional[Union[Stores, str]]` | The target scope. If `None`, the definition is stored in the **GLOBAL** profile and becomes available to all loaders regardless of their distribution. | `None` | Raises: | Type | Description | | --- | --- | | `FileNotFoundError` | If `source` is a `Path` that does not exist on the filesystem. | | `TypeError` | If the `source` is neither a `str` nor a `Path`. | ### register\_directory `classmethod` ¶ ``` register_directory(package_name, dir_path, store=None) ``` Batch registers all `.msg` files found within a specified directory. This helper is essential for ingesting entire ROS packages. It automatically infers the full ROS type name by combining the `package_name` with the filename (e.g., `Status.msg` becomes `package_name/msg/Status`). Example ``` # Register all messages in a local workspace for ROS1 ROSTypeRegistry.register_directory( package_name="robot_logic", dir_path="./src/robot_logic/msg", store=Stores.ROS1_NOETIC ) ``` Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `package_name` | `str` | The name of the ROS package to use as a prefix. | *required* | | `dir_path` | `Union[str, Path]` | The filesystem path to the directory containing `.msg` files. | *required* | | `store` | `Optional[Union[Stores, str]]` | The target distribution scope for the entire directory. | `None` | Raises: | Type | Description | | --- | --- | | `ValueError` | If `dir_path` does not point to a valid directory. | ### get\_types `classmethod` ¶ ``` get_types(store) ``` Retrieves a merged view of message definitions for a specific distribution. This method implements the **Registry Cascade**: 1. It starts with a base layer of all **GLOBAL** definitions. 2. It overlays (overwrites) those with any **Store-Specific** definitions matching the provided `store` parameter. This ensures that distribution-specific nuances are respected while maintaining access to shared custom types. Parameters: | Name | Type | Description | Default | | --- | --- | --- | --- | | `store` | `Optional[Union[Stores, str]]` | The distribution identifier (e.g., `Stores.ROS2_HUMBLE`) to fetch overrides for. | *required* | Returns: | Type | Description | | --- | --- | | `Dict[str, str]` | A flat dictionary mapping `msg_type` to `definition`, formatted for | | `Dict[str, str]` | direct injection into `rosbags` high-level readers. | ### reset `classmethod` ¶ ``` reset() ``` Completely clears the singleton registry. This is primarily used for **Unit Testing** and CI/CD pipelines to ensure total isolation between different test cases. --- The following data models are specific to the ROS bridge and are not part of the official Mosaico Data Ontology yet. ## mosaicolabs.ros\_bridge.data\_ontology.BatteryState ¶ Bases: `Serializable`, `HeaderMixin` Represents the state of a battery power supply. modeled after: sensor\_msgs/msg/BatteryState Note This model is still not included in the default ontology of Mosaico and is defined specifically for the ros-bridge module ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### voltage `instance-attribute` ¶ ``` voltage ``` The battery voltage value ### temperature `instance-attribute` ¶ ``` temperature ``` The optional battery temperature in °C ### current `instance-attribute` ¶ ``` current ``` The optional battery current in A ### charge `instance-attribute` ¶ ``` charge ``` The optional battery charge in Ah ### capacity `instance-attribute` ¶ ``` capacity ``` The optional battery capacity in Ah ### design\_capacity `instance-attribute` ¶ ``` design_capacity ``` The optional battery design capacity in Ah ### percentage `instance-attribute` ¶ ``` percentage ``` The battery percentage in % ### power\_supply\_status `instance-attribute` ¶ ``` power_supply_status ``` The charging status ### power\_supply\_health `instance-attribute` ¶ ``` power_supply_health ``` The battery health ### power\_supply\_technology `instance-attribute` ¶ ``` power_supply_technology ``` The battery technology ### present `instance-attribute` ¶ ``` present ``` The battery presence ### location `instance-attribute` ¶ ``` location ``` The battery location (like the slot) ### serial\_number `instance-attribute` ¶ ``` serial_number ``` The battery serial number ### cell\_voltage `class-attribute` `instance-attribute` ¶ ``` cell_voltage = None ``` The battery cells voltage ### cell\_temperature `class-attribute` `instance-attribute` ¶ ``` cell_temperature = None ``` The battery cells temperature ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ## mosaicolabs.ros\_bridge.data\_ontology.FrameTransform ¶ Bases: `Serializable`, `HeaderMixin` Represents a list of transformations between two coordinates. modeled after: tf2\_msgs/msg/TFMessage Note This model is not included in the default ontology of Mosaico and is defined specifically for the ros-bridge module ### header `class-attribute` `instance-attribute` ¶ ``` header = None ``` An optional metadata header providing temporal and spatial context to the ontology model. This field is injected into the model via composition, ensuring that sensor data is paired with standard acquisition attributes like sequence IDs and high-precision timestamps. ###### Querying with the **`.Q` Proxy**¶ Check the documentation of the `HeaderMixin` to construct a valid expression for the `QueryOntologyCatalog` builder involving the `header` component. ### transforms `instance-attribute` ¶ ``` transforms ``` List of coordinate frames transformations. ### is\_registered `classmethod` ¶ ``` is_registered() ``` Checks if a class is registered. Returns: | Name | Type | Description | | --- | --- | --- | | `bool` | `bool` | True if registered. | ### ontology\_tag `classmethod` ¶ ``` ontology_tag() ``` Retrieves the unique identifier (tag) for the current ontology class, automatically generated during class definition. This method provides the string key used by the Mosaico platform to identify and route specific data types within the ontology registry. It abstracts away the internal naming conventions, ensuring that you always use the correct identifier for queries and serialization. Returns: | Type | Description | | --- | --- | | `str` | The registered string tag for this class (e.g., `"imu"`, `"gps"`). | Raises: | Type | Description | | --- | --- | | `Exception` | If the class was not properly initialized via `__init_subclass__`. | **Practical Application: Topic Filtering** This method is particularly useful when constructing `QueryTopic` requests. By using the convenience method `QueryTopic.with_ontology_tag()`, you can filter topics by data type without hardcoding strings that might change. Example: ``` from mosaicolabs import MosaicoClient, Topic, IMU, QueryTopic with MosaicoClient.connect("localhost", 6726) as client: # Filter for a specific data value (using constructor) qresponse = client.query( QueryTopic( Topic.with_ontology_tag(IMU.ontology_tag()), ) ) # Inspect the response if qresponse is not None: # Results are automatically grouped by Sequence for easier data management for item in qresponse: print(f"Sequence: {item.sequence.name}") print(f"Topics: {[topic.name for topic in item.topics]}") ``` ---