px4-configuration 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- px4_configuration/api/main.py +3 -3
- px4_configuration/api/models.py +2 -2
- px4_configuration/api/services/calibration_service.py +12 -4
- px4_configuration/api/services/health_service.py +121 -28
- px4_configuration/api/utils/calibration_parser.py +62 -21
- {px4_configuration-0.2.0.dist-info → px4_configuration-0.2.1.dist-info}/METADATA +3 -3
- {px4_configuration-0.2.0.dist-info → px4_configuration-0.2.1.dist-info}/RECORD +9 -9
- {px4_configuration-0.2.0.dist-info → px4_configuration-0.2.1.dist-info}/WHEEL +1 -1
- {px4_configuration-0.2.0.dist-info → px4_configuration-0.2.1.dist-info}/entry_points.txt +0 -0
px4_configuration/api/main.py
CHANGED
|
@@ -70,11 +70,11 @@ async def start_calibration(request: CalibrationRequest):
|
|
|
70
70
|
calibration_type=request.calibration_type, # <-- enum here
|
|
71
71
|
):
|
|
72
72
|
# Convert dict -> SSE frame
|
|
73
|
-
yield
|
|
73
|
+
yield json.dumps(payload)
|
|
74
74
|
except Exception as exc:
|
|
75
|
-
yield
|
|
75
|
+
yield json.dumps({'type': 'error', 'message': str(exc)})
|
|
76
76
|
finally:
|
|
77
|
-
yield
|
|
77
|
+
yield json.dumps({'type': 'complete'})
|
|
78
78
|
|
|
79
79
|
return EventSourceResponse(event_generator())
|
|
80
80
|
|
px4_configuration/api/models.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from enum import
|
|
3
|
+
from enum import Enum
|
|
4
4
|
from typing import Literal, Optional, Dict, Any
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field, ConfigDict
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class CalibrationType(
|
|
9
|
+
class CalibrationType(Enum):
|
|
10
10
|
"""Supported calibration types."""
|
|
11
11
|
GYROSCOPE = "gyroscope"
|
|
12
12
|
ACCELEROMETER = "accelerometer"
|
|
@@ -53,8 +53,10 @@ async def calibrate_sensors(
|
|
|
53
53
|
"message": "Starting gyroscope calibration...",
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
prev: Dict[str, Any] | None = None
|
|
56
57
|
async for progress_data in drone.calibration.calibrate_gyro():
|
|
57
|
-
structured_data = parse_gyroscope_progress(progress_data)
|
|
58
|
+
structured_data = parse_gyroscope_progress(progress_data, prev=prev)
|
|
59
|
+
prev = structured_data
|
|
58
60
|
yield structured_data
|
|
59
61
|
|
|
60
62
|
yield {
|
|
@@ -70,8 +72,10 @@ async def calibrate_sensors(
|
|
|
70
72
|
"message": "Starting accelerometer calibration...",
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
prev = None
|
|
73
76
|
async for progress_data in drone.calibration.calibrate_accelerometer():
|
|
74
|
-
structured_data = parse_accelerometer_progress(progress_data)
|
|
77
|
+
structured_data = parse_accelerometer_progress(progress_data, prev=prev)
|
|
78
|
+
prev = structured_data
|
|
75
79
|
yield structured_data
|
|
76
80
|
|
|
77
81
|
yield {
|
|
@@ -87,8 +91,10 @@ async def calibrate_sensors(
|
|
|
87
91
|
"message": "Starting magnetometer calibration...",
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
prev = None
|
|
90
95
|
async for progress_data in drone.calibration.calibrate_magnetometer():
|
|
91
|
-
structured_data = parse_magnetometer_progress(progress_data)
|
|
96
|
+
structured_data = parse_magnetometer_progress(progress_data, prev=prev)
|
|
97
|
+
prev = structured_data
|
|
92
98
|
yield structured_data
|
|
93
99
|
|
|
94
100
|
yield {
|
|
@@ -104,8 +110,10 @@ async def calibrate_sensors(
|
|
|
104
110
|
"message": "Starting board level horizon calibration...",
|
|
105
111
|
}
|
|
106
112
|
|
|
113
|
+
prev = None
|
|
107
114
|
async for progress_data in drone.calibration.calibrate_level_horizon():
|
|
108
|
-
structured_data = parse_horizon_progress(progress_data)
|
|
115
|
+
structured_data = parse_horizon_progress(progress_data, prev=prev)
|
|
116
|
+
prev = structured_data
|
|
109
117
|
yield structured_data
|
|
110
118
|
|
|
111
119
|
yield {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
-
from typing import Optional, Dict, Any
|
|
6
|
+
from typing import Optional, Dict, Any, Iterable
|
|
7
7
|
|
|
8
8
|
from mavsdk import System
|
|
9
9
|
|
|
@@ -37,6 +37,42 @@ async def _get_gps_info_once(drone: System, timeout_s: float = 5.0):
|
|
|
37
37
|
return await asyncio.wait_for(_first(), timeout_s)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
SENSOR_INDEXES: Iterable[int] = (0, 1, 2)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def _is_family_calibrated(
|
|
44
|
+
drone: System,
|
|
45
|
+
family: str,
|
|
46
|
+
indexes: Iterable[int] = SENSOR_INDEXES,
|
|
47
|
+
) -> bool:
|
|
48
|
+
"""
|
|
49
|
+
Param-based heuristic:
|
|
50
|
+
|
|
51
|
+
A sensor family (gyro/accel/mag) is considered calibrated if ANY
|
|
52
|
+
CAL_FAMILYn_ID != 0 for the probed indexes and the param read succeeds.
|
|
53
|
+
"""
|
|
54
|
+
prefix_map = {
|
|
55
|
+
"gyro": "CAL_GYRO",
|
|
56
|
+
"accel": "CAL_ACC",
|
|
57
|
+
"mag": "CAL_MAG",
|
|
58
|
+
}
|
|
59
|
+
prefix = prefix_map.get(family)
|
|
60
|
+
if not prefix:
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
for i in indexes:
|
|
64
|
+
name = f"{prefix}{i}_ID"
|
|
65
|
+
try:
|
|
66
|
+
sensor_id = await drone.param.get_param_int(name)
|
|
67
|
+
except Exception:
|
|
68
|
+
# Ignore this index if param read fails
|
|
69
|
+
continue
|
|
70
|
+
if sensor_id != 0:
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
40
76
|
async def read_px4_health(
|
|
41
77
|
port: Optional[str] = None,
|
|
42
78
|
baudrate: Optional[int] = None,
|
|
@@ -45,7 +81,8 @@ async def read_px4_health(
|
|
|
45
81
|
"""
|
|
46
82
|
Connect to PX4 via MAVSDK and return a one-shot health snapshot.
|
|
47
83
|
|
|
48
|
-
- Uses
|
|
84
|
+
- Uses PX4 CAL_* params to derive calibration health.
|
|
85
|
+
- Uses telemetry.health() for armable + positional flags.
|
|
49
86
|
- Uses telemetry.gps_info() for fix type + satellites.
|
|
50
87
|
- Returns Px4HealthResponse; never raises to the API layer.
|
|
51
88
|
"""
|
|
@@ -61,49 +98,105 @@ async def read_px4_health(
|
|
|
61
98
|
# Connect to PX4
|
|
62
99
|
await drone.connect(system_address=serial)
|
|
63
100
|
|
|
64
|
-
#
|
|
65
|
-
|
|
101
|
+
# Optional: verify we actually got a connection state
|
|
102
|
+
async for state in drone.core.connection_state():
|
|
103
|
+
if not state.is_connected:
|
|
104
|
+
# Treat as disconnected; don't bother with the rest
|
|
105
|
+
return Px4HealthResponse(
|
|
106
|
+
status="disconnected",
|
|
107
|
+
connection_port=port,
|
|
108
|
+
connection_baudrate=baudrate,
|
|
109
|
+
calibration=None,
|
|
110
|
+
gps_fix_type=None,
|
|
111
|
+
satellites_used=None,
|
|
112
|
+
armable=False,
|
|
113
|
+
raw_health=None,
|
|
114
|
+
)
|
|
115
|
+
break
|
|
116
|
+
|
|
117
|
+
# -------- PARAM-BASED CALIBRATION (source of truth) --------
|
|
118
|
+
gyroscope_ok = await _is_family_calibrated(drone, "gyro")
|
|
119
|
+
accelerometer_ok = await _is_family_calibrated(drone, "accel")
|
|
120
|
+
magnetometer_ok = await _is_family_calibrated(drone, "mag")
|
|
121
|
+
|
|
122
|
+
calibration = CalibrationHealth(
|
|
123
|
+
gyroscope_ok=gyroscope_ok,
|
|
124
|
+
accelerometer_ok=accelerometer_ok,
|
|
125
|
+
magnetometer_ok=magnetometer_ok,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# -------- TELEMETRY HEALTH (for armable + debug) --------
|
|
129
|
+
try:
|
|
130
|
+
health = await _get_health_once(drone, timeout_s=timeout_s / 2)
|
|
131
|
+
except asyncio.TimeoutError:
|
|
132
|
+
health = None
|
|
133
|
+
|
|
134
|
+
# -------- GPS INFO (unchanged) --------
|
|
66
135
|
try:
|
|
67
136
|
gps_info = await _get_gps_info_once(drone, timeout_s=timeout_s / 2)
|
|
68
137
|
except asyncio.TimeoutError:
|
|
69
138
|
gps_info = None
|
|
70
139
|
|
|
71
|
-
# Build calibration health
|
|
72
|
-
calibration = CalibrationHealth(
|
|
73
|
-
gyroscope_ok=health.is_gyrometer_calibration_ok,
|
|
74
|
-
accelerometer_ok=health.is_accelerometer_calibration_ok,
|
|
75
|
-
magnetometer_ok=health.is_magnetometer_calibration_ok,
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
# GPS fields
|
|
79
140
|
gps_fix_type: Optional[str] = None
|
|
80
141
|
satellites_used: Optional[int] = None
|
|
81
142
|
|
|
82
143
|
if gps_info is not None:
|
|
83
|
-
# gps_info.fix_type is an enum; prefer its name
|
|
84
144
|
if hasattr(gps_info.fix_type, "name"):
|
|
85
145
|
gps_fix_type = gps_info.fix_type.name.lower()
|
|
86
146
|
else:
|
|
87
147
|
gps_fix_type = str(gps_info.fix_type).lower()
|
|
88
148
|
|
|
89
|
-
# MAVSDK docs: num_satellites = number of visible satellites in use
|
|
90
149
|
satellites_used = int(getattr(gps_info, "num_satellites", 0))
|
|
91
150
|
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
151
|
+
# -------- STATUS + ARMABLE (respect your Literal) --------
|
|
152
|
+
armable: Optional[bool] = None
|
|
153
|
+
if health is not None:
|
|
154
|
+
armable = health.is_armable
|
|
155
|
+
|
|
156
|
+
# Map everything into your fixed status vocabulary:
|
|
157
|
+
# - disconnected: handled in exception / early return
|
|
158
|
+
# - ok: armable and all calibrated
|
|
159
|
+
# - degraded: anything else (not armable or missing calibration)
|
|
160
|
+
if armable and not calibration.requires_calibration:
|
|
96
161
|
status = "ok"
|
|
162
|
+
else:
|
|
163
|
+
status = "degraded"
|
|
97
164
|
|
|
98
|
-
#
|
|
99
|
-
raw_health: Dict[str, Any] = {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
165
|
+
# -------- RAW HEALTH FOR DEBUG/UI --------
|
|
166
|
+
raw_health: Dict[str, Any] = {}
|
|
167
|
+
|
|
168
|
+
# Telemetry-derived bits (if available)
|
|
169
|
+
if health is not None:
|
|
170
|
+
raw_health.update(
|
|
171
|
+
{
|
|
172
|
+
"is_gyrometer_calibration_ok": health.is_gyrometer_calibration_ok,
|
|
173
|
+
"is_accelerometer_calibration_ok": health.is_accelerometer_calibration_ok,
|
|
174
|
+
"is_magnetometer_calibration_ok": health.is_magnetometer_calibration_ok,
|
|
175
|
+
"is_local_position_ok": getattr(health, "is_local_position_ok", None),
|
|
176
|
+
"is_global_position_ok": getattr(health, "is_global_position_ok", None),
|
|
177
|
+
"is_home_position_ok": getattr(health, "is_home_position_ok", None),
|
|
178
|
+
"is_armable": health.is_armable,
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
raw_health.update(
|
|
183
|
+
{
|
|
184
|
+
"is_gyrometer_calibration_ok": None,
|
|
185
|
+
"is_accelerometer_calibration_ok": None,
|
|
186
|
+
"is_magnetometer_calibration_ok": None,
|
|
187
|
+
"is_local_position_ok": None,
|
|
188
|
+
"is_global_position_ok": None,
|
|
189
|
+
"is_home_position_ok": None,
|
|
190
|
+
"is_armable": None,
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Param-derived calibration snapshot as debug info (so you can see IDs in Swagger/UI later if you want)
|
|
195
|
+
raw_health["calibration_params"] = {
|
|
196
|
+
"source": "CAL_*_ID heuristic",
|
|
197
|
+
"gyroscope_ok": gyroscope_ok,
|
|
198
|
+
"accelerometer_ok": accelerometer_ok,
|
|
199
|
+
"magnetometer_ok": magnetometer_ok,
|
|
107
200
|
}
|
|
108
201
|
|
|
109
202
|
return Px4HealthResponse(
|
|
@@ -113,7 +206,7 @@ async def read_px4_health(
|
|
|
113
206
|
calibration=calibration,
|
|
114
207
|
gps_fix_type=gps_fix_type,
|
|
115
208
|
satellites_used=satellites_used,
|
|
116
|
-
armable=
|
|
209
|
+
armable=armable,
|
|
117
210
|
raw_health=raw_health,
|
|
118
211
|
)
|
|
119
212
|
|
|
@@ -5,7 +5,10 @@ from typing import Optional, Dict, Any, List
|
|
|
5
5
|
import math
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def parse_accelerometer_progress(
|
|
8
|
+
def parse_accelerometer_progress(
|
|
9
|
+
progress_data,
|
|
10
|
+
prev: Optional[Dict[str, Any]] = None,
|
|
11
|
+
) -> Dict[str, Any]:
|
|
9
12
|
"""
|
|
10
13
|
Parse accelerometer calibration progress data into structured format.
|
|
11
14
|
|
|
@@ -33,10 +36,11 @@ def parse_accelerometer_progress(progress_data) -> Dict[str, Any]:
|
|
|
33
36
|
result["progress"] = float(progress_value)
|
|
34
37
|
|
|
35
38
|
# Extract status text if available
|
|
39
|
+
pending_match = None
|
|
36
40
|
if hasattr(progress_data, 'has_status_text') and progress_data.has_status_text:
|
|
37
41
|
status_text = progress_data.status_text
|
|
38
42
|
result["status_text"] = status_text
|
|
39
|
-
|
|
43
|
+
|
|
40
44
|
# Parse pending orientations (e.g., "pending: back front left right up down")
|
|
41
45
|
pending_match = re.search(r'pending:\s*([a-z\s]+)', status_text, re.IGNORECASE)
|
|
42
46
|
if pending_match:
|
|
@@ -65,31 +69,44 @@ def parse_accelerometer_progress(progress_data) -> Dict[str, Any]:
|
|
|
65
69
|
except ValueError:
|
|
66
70
|
pass
|
|
67
71
|
|
|
68
|
-
# Determine current message/instruction
|
|
69
|
-
|
|
72
|
+
# Determine current message/instruction (normalize to simple labels)
|
|
73
|
+
low = status_text.lower()
|
|
74
|
+
if "progress" in low and "<" in status_text and ">" in status_text:
|
|
70
75
|
# This seems to be a completion indicator (e.g., "progress <102>")
|
|
71
76
|
result["is_complete"] = True
|
|
72
77
|
result["current_message"] = "complete"
|
|
73
|
-
elif
|
|
78
|
+
elif pending_match:
|
|
79
|
+
result["current_message"] = "pending"
|
|
80
|
+
elif "hold vehicle still" in low:
|
|
74
81
|
result["current_message"] = "hold_still"
|
|
75
|
-
elif "detected rest position" in
|
|
82
|
+
elif "detected rest position" in low:
|
|
76
83
|
result["current_message"] = "rest_detected"
|
|
77
|
-
elif "measuring" in
|
|
84
|
+
elif "measuring" in low:
|
|
78
85
|
result["current_message"] = "measuring"
|
|
79
|
-
elif "done, rotate" in
|
|
86
|
+
elif "done, rotate" in low:
|
|
80
87
|
result["current_message"] = "rotate"
|
|
81
|
-
elif "already completed" in
|
|
88
|
+
elif "already completed" in low:
|
|
82
89
|
result["current_message"] = "already_completed"
|
|
83
|
-
elif "orientation detected" in
|
|
90
|
+
elif "orientation detected" in low:
|
|
84
91
|
result["current_message"] = "orientation_detected"
|
|
85
92
|
else:
|
|
86
93
|
# Default: use the status text as message
|
|
87
94
|
result["current_message"] = status_text
|
|
95
|
+
|
|
96
|
+
# Carry forward state from previous snapshot where appropriate
|
|
97
|
+
if prev:
|
|
98
|
+
if not result["pending_orientations"]:
|
|
99
|
+
result["pending_orientations"] = prev.get("pending_orientations", [])
|
|
100
|
+
if result["current_orientation"] is None:
|
|
101
|
+
result["current_orientation"] = prev.get("current_orientation")
|
|
88
102
|
|
|
89
103
|
return result
|
|
90
104
|
|
|
91
105
|
|
|
92
|
-
def parse_gyroscope_progress(
|
|
106
|
+
def parse_gyroscope_progress(
|
|
107
|
+
progress_data,
|
|
108
|
+
prev: Optional[Dict[str, Any]] = None,
|
|
109
|
+
) -> Dict[str, Any]:
|
|
93
110
|
"""
|
|
94
111
|
Parse gyroscope calibration progress data into structured format.
|
|
95
112
|
|
|
@@ -126,11 +143,19 @@ def parse_gyroscope_progress(progress_data) -> Dict[str, Any]:
|
|
|
126
143
|
result["status_text"] = status_text
|
|
127
144
|
if status_text and not result["current_message"]:
|
|
128
145
|
result["current_message"] = status_text
|
|
146
|
+
|
|
147
|
+
# Carry forward simple state where helpful
|
|
148
|
+
if prev:
|
|
149
|
+
if result["progress"] is None:
|
|
150
|
+
result["progress"] = prev.get("progress")
|
|
129
151
|
|
|
130
152
|
return result
|
|
131
153
|
|
|
132
154
|
|
|
133
|
-
def parse_magnetometer_progress(
|
|
155
|
+
def parse_magnetometer_progress(
|
|
156
|
+
progress_data,
|
|
157
|
+
prev: Optional[Dict[str, Any]] = None,
|
|
158
|
+
) -> Dict[str, Any]:
|
|
134
159
|
"""
|
|
135
160
|
Parse magnetometer calibration progress data into structured format.
|
|
136
161
|
|
|
@@ -185,29 +210,40 @@ def parse_magnetometer_progress(progress_data) -> Dict[str, Any]:
|
|
|
185
210
|
result["current_orientation"] = match.group(1).lower()
|
|
186
211
|
break
|
|
187
212
|
|
|
188
|
-
# Determine current message/instruction
|
|
189
|
-
|
|
213
|
+
# Determine current message/instruction (normalize)
|
|
214
|
+
low = status_text.lower()
|
|
215
|
+
if "rotate vehicle" in status_text:
|
|
190
216
|
result["current_message"] = "rotate"
|
|
191
|
-
elif "hold vehicle still" in
|
|
217
|
+
elif "hold vehicle still" in low:
|
|
192
218
|
result["current_message"] = "hold_still"
|
|
193
|
-
elif "detected rest position" in
|
|
219
|
+
elif "detected rest position" in low:
|
|
194
220
|
result["current_message"] = "rest_detected"
|
|
195
|
-
elif "detected motion" in
|
|
221
|
+
elif "detected motion" in low:
|
|
196
222
|
result["current_message"] = "motion_detected"
|
|
197
|
-
elif "done, rotate" in
|
|
223
|
+
elif "done, rotate" in low:
|
|
198
224
|
result["current_message"] = "rotate"
|
|
199
|
-
elif "already completed" in
|
|
225
|
+
elif "already completed" in low:
|
|
200
226
|
result["current_message"] = "already_completed"
|
|
201
|
-
elif "orientation detected" in
|
|
227
|
+
elif "orientation detected" in low:
|
|
202
228
|
result["current_message"] = "orientation_detected"
|
|
203
229
|
else:
|
|
204
230
|
# Default: use the status text as message
|
|
205
231
|
result["current_message"] = status_text
|
|
232
|
+
|
|
233
|
+
# Carry forward orientation / pending where appropriate
|
|
234
|
+
if prev:
|
|
235
|
+
if not result["pending_orientations"]:
|
|
236
|
+
result["pending_orientations"] = prev.get("pending_orientations", [])
|
|
237
|
+
if result["current_orientation"] is None:
|
|
238
|
+
result["current_orientation"] = prev.get("current_orientation")
|
|
206
239
|
|
|
207
240
|
return result
|
|
208
241
|
|
|
209
242
|
|
|
210
|
-
def parse_horizon_progress(
|
|
243
|
+
def parse_horizon_progress(
|
|
244
|
+
progress_data,
|
|
245
|
+
prev: Optional[Dict[str, Any]] = None,
|
|
246
|
+
) -> Dict[str, Any]:
|
|
211
247
|
"""
|
|
212
248
|
Parse level horizon calibration progress data into structured format.
|
|
213
249
|
|
|
@@ -243,6 +279,11 @@ def parse_horizon_progress(progress_data) -> Dict[str, Any]:
|
|
|
243
279
|
result["status_text"] = status_text
|
|
244
280
|
if status_text and not result["current_message"]:
|
|
245
281
|
result["current_message"] = status_text
|
|
282
|
+
|
|
283
|
+
# Carry forward simple state where helpful
|
|
284
|
+
if prev:
|
|
285
|
+
if result["progress"] is None:
|
|
286
|
+
result["progress"] = prev.get("progress")
|
|
246
287
|
|
|
247
288
|
return result
|
|
248
289
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: px4-configuration
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Tools and REST API for configuring PX4 from a companion computer
|
|
5
5
|
Author-email: Alex <bonnefond@fly4future.com>
|
|
6
6
|
License: BSD-3-Clause
|
|
7
|
-
Requires-Python: >=3.
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
8
|
Requires-Dist: fastapi>=0.104.0
|
|
9
9
|
Requires-Dist: mavsdk==3.0.1
|
|
10
10
|
Requires-Dist: python-multipart>=0.0.6
|
|
@@ -60,7 +60,7 @@ pip install dist/px4_configuration-0.1.0-py3-none-any.whl
|
|
|
60
60
|
|
|
61
61
|
## Requirements
|
|
62
62
|
|
|
63
|
-
- Python 3.
|
|
63
|
+
- Python 3.10+
|
|
64
64
|
- PX4 flight controller connected over serial (e.g. `/dev/pixhawk`)
|
|
65
65
|
- User added to the `dialout` group for serial access (`sudo usermod -aG dialout $USER`)
|
|
66
66
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
px4_configuration/__init__.py,sha256=U0jqmbB8mDtIQ_ZPVjfHzoF7b9EM1TFJQRWEJ49Vk1I,334
|
|
2
2
|
px4_configuration/api/__init__.py,sha256=o0txTrY6RjO1ehOJGtMerrVMm0QR1E4PiutPhoKtmZo,137
|
|
3
3
|
px4_configuration/api/config.py,sha256=imb6qv75ye_DE4t7kbf7xbxWPvy3Yota95keVjg1c5A,562
|
|
4
|
-
px4_configuration/api/main.py,sha256=
|
|
5
|
-
px4_configuration/api/models.py,sha256=
|
|
4
|
+
px4_configuration/api/main.py,sha256=aeGpssDFcg9xwps3sdRM0tH2p2yYeqkGn9y7QLHw3I4,8278
|
|
5
|
+
px4_configuration/api/models.py,sha256=UeP_FOiimmBxJmeDZ6EGHTodRfQiBNOSt_hSfiVsglI,3546
|
|
6
6
|
px4_configuration/api/services/__init__.py,sha256=U91RCGMiGcIQqtbnzscfNbWpFw65ZNz0DKabCPtTGMw,163
|
|
7
|
-
px4_configuration/api/services/calibration_service.py,sha256=
|
|
8
|
-
px4_configuration/api/services/health_service.py,sha256=
|
|
7
|
+
px4_configuration/api/services/calibration_service.py,sha256=qA5NQx267djW853FKWrfGb6wTsCdqGGpTb3QN6j9zA4,4363
|
|
8
|
+
px4_configuration/api/services/health_service.py,sha256=T1pSMQLxpC41puxQIuTsFj5FVy5NAV0dtTkEoHfHvXE,7539
|
|
9
9
|
px4_configuration/api/services/param_service.py,sha256=95Ee5v3rEGjXiW2LJURTUHXqtxBl2JomV_tMcLwGjac,5201
|
|
10
10
|
px4_configuration/api/services/sdcard_service.py,sha256=6bnMTcaHddo8ZOsrKtl39V518MBO_Z-2fXFT4PTLT5M,2643
|
|
11
11
|
px4_configuration/api/services/shell_service.py,sha256=A_28vCxWyc6e-Usf3QLHqCy5Auf7tyGwqySQ5E5LO1s,2096
|
|
12
12
|
px4_configuration/api/utils/__init__.py,sha256=KR-_U6nAXr8V1uxsB1hCFXPxKYYEwbf096kvhhUJfFk,54
|
|
13
|
-
px4_configuration/api/utils/calibration_parser.py,sha256=
|
|
14
|
-
px4_configuration-0.2.
|
|
15
|
-
px4_configuration-0.2.
|
|
16
|
-
px4_configuration-0.2.
|
|
17
|
-
px4_configuration-0.2.
|
|
13
|
+
px4_configuration/api/utils/calibration_parser.py,sha256=rlW4D-ogc0z8o80jBkazZ3oqucAvSMGp_vKfpp5bLp0,10990
|
|
14
|
+
px4_configuration-0.2.1.dist-info/METADATA,sha256=URkhx2PatvDNwcOVKWCyhqv60E6qDyAwnqGj2IaUQ3c,7108
|
|
15
|
+
px4_configuration-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
16
|
+
px4_configuration-0.2.1.dist-info/entry_points.txt,sha256=mBRa68p2qL9HPLE9nCruYZDtTmuDOhFIbkY_nwX-WTc,67
|
|
17
|
+
px4_configuration-0.2.1.dist-info/RECORD,,
|
|
File without changes
|