One process per drone: seeded patrol kinematics, sensor streams at realistic rates, detection events, hot current/ blocks sealed into Hive-partitioned Parquet, and the compact UDP state broadcast with peer RSSI derivation. Scales via docker compose --scale.
81 lines
2.4 KiB
Python
81 lines
2.4 KiB
Python
"""Sensor row generators. Pure functions: (pose, rng, ts) -> row dict.
|
|
|
|
Every row carries int64 epoch nanoseconds. Values are emitted at full float
|
|
precision - quantization happens only in the broadcast payload, never in
|
|
stored telemetry.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
import random
|
|
from typing import Any
|
|
|
|
from .flight import Pose
|
|
|
|
Row = dict[str, Any]
|
|
|
|
|
|
def imu_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
|
|
return {
|
|
"ts_ns": ts_ns,
|
|
"accel_x": rng.gauss(0.0, 0.35),
|
|
"accel_y": rng.gauss(0.0, 0.35),
|
|
"accel_z": rng.gauss(-9.81, 0.25),
|
|
"gyro_x": math.radians(rng.gauss(pose.roll, 0.8)),
|
|
"gyro_y": math.radians(rng.gauss(pose.pitch, 0.8)),
|
|
"gyro_z": math.radians(rng.gauss(0.0, 0.5)),
|
|
}
|
|
|
|
|
|
def baro_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
|
|
pressure = 101325.0 * math.exp(-pose.z / 8434.0) + rng.gauss(0.0, 4.0)
|
|
return {"ts_ns": ts_ns, "pressure_pa": pressure, "alt_est_m": pose.z + rng.gauss(0.0, 0.3)}
|
|
|
|
|
|
def temp_row(_pose: Pose, rng: random.Random, ts_ns: int) -> Row:
|
|
return {
|
|
"ts_ns": ts_ns,
|
|
"cpu_c": 55.0 + rng.gauss(0.0, 3.0),
|
|
"gpu_c": 62.0 + rng.gauss(0.0, 4.0),
|
|
"ambient_c": 24.0 + rng.gauss(0.0, 0.5),
|
|
}
|
|
|
|
|
|
def battery_row(_pose: Pose, rng: random.Random, ts_ns: int, elapsed_s: float, duration_s: float) -> Row:
|
|
level = max(0.0, 100.0 - 80.0 * elapsed_s / max(duration_s, 1.0) + rng.gauss(0.0, 0.2))
|
|
return {"ts_ns": ts_ns, "level_pct": level, "voltage_v": 22.2 * (0.85 + 0.15 * level / 100.0)}
|
|
|
|
|
|
DETECTION_CLASSES = ("vehicle", "person", "animal", "structure", "unknown")
|
|
|
|
|
|
def detection_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
|
|
return {
|
|
"ts_ns": ts_ns,
|
|
"cls": rng.choice(DETECTION_CLASSES),
|
|
"confidence": round(rng.uniform(0.42, 0.99), 3),
|
|
"obj_x": pose.x + rng.uniform(-40.0, 40.0),
|
|
"obj_y": pose.y + rng.uniform(-40.0, 40.0),
|
|
"obj_z": rng.uniform(0.0, 5.0),
|
|
"ego_x": pose.x,
|
|
"ego_y": pose.y,
|
|
"ego_z": pose.z,
|
|
}
|
|
|
|
|
|
def state_row(pose: Pose, ts_ns: int) -> Row:
|
|
return {
|
|
"ts_ns": ts_ns,
|
|
"pos_x": pose.x,
|
|
"pos_y": pose.y,
|
|
"pos_z": pose.z,
|
|
"roll": pose.roll,
|
|
"pitch": pose.pitch,
|
|
"yaw": pose.yaw,
|
|
"vel_x": pose.vx,
|
|
"vel_y": pose.vy,
|
|
"vel_z": pose.vz,
|
|
"frame_ref": 0,
|
|
}
|