Skip to content

Commit 756a400

Browse files
committed
Add parameters metadata for qgc
Handle COMPONENT_METADATA requests from gcs, providing a manually written (for now) static metadata urls.
1 parent eb0018a commit 756a400

5 files changed

Lines changed: 296 additions & 0 deletions

File tree

‎.github/workflows/tools.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ on:
77
branches: [ master ]
88

99
jobs:
10+
metadata:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v7
14+
- name: Check metadata
15+
run: tools/metadata.py
1016
csv_to_ulog:
1117
runs-on: ubuntu-latest
1218
steps:

‎flix/mavlink.ino‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,15 @@ int handleMavlinkCommand(const void *_m) {
268268
return MAV_RESULT_ACCEPTED;
269269
}
270270

271+
if (m.command == MAV_CMD_REQUEST_MESSAGE && m.param1 == MAVLINK_MSG_ID_COMPONENT_METADATA) {
272+
mavlink_message_t response;
273+
mavlink_msg_component_metadata_pack(mavlinkSysId, MAV_COMP_ID_AUTOPILOT1, &response, t * 1000,
274+
2566517357, // crc
275+
"https://quadcopter.dev/meta/2566517357/general.json");
276+
sendMessage(&response);
277+
return MAV_RESULT_ACCEPTED;
278+
}
279+
271280
if (m.command == MAV_CMD_COMPONENT_ARM_DISARM) {
272281
if (m.param1 == 1 && controlThrottle > 0.05) return MAV_RESULT_DENIED; // don't arm if throttle is not low
273282
armed = m.param1 == 1;

‎tools/general.json‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"version": 1,
3+
"metadataTypes": [
4+
{
5+
"type": 1,
6+
"uri": "https://quadcopter.dev/meta/3307474483/parameters.json",
7+
"fileCrc": 3307474483
8+
}
9+
]
10+
}

‎tools/metadata.py‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
3+
# Script for checking the metadata files
4+
5+
import sys
6+
import re
7+
from pathlib import Path
8+
import json
9+
import zlib
10+
import requests
11+
12+
13+
def mavlink_crc323(data: bytes) -> int:
14+
return (zlib.crc32(data, 0xFFFFFFFF) ^ 0xFFFFFFFF) & 0xFFFFFFFF
15+
16+
17+
parameter_regexp = re.compile(r'^\s+\{"(?P<name>[^"]+)",\s*&(?P<variable>[^,]+)(.*)\},?$', re.MULTILINE)
18+
19+
parameters_source_file = Path(__file__).parent.parent / 'flix' / 'parameters.ino'
20+
parameters_code = parameters_source_file.read_text()
21+
parameters_meta_file = Path(__file__).parent / 'parameters.json'
22+
parameters_meta = json.loads(parameters_meta_file.read_text())
23+
assert parameters_meta['version'] == 1
24+
25+
parameters = parameter_regexp.finditer(parameters_code)
26+
27+
for parameter in parameters:
28+
name = parameter.group('name')
29+
variable = parameter.group('variable')
30+
31+
for meta in parameters_meta['parameters']:
32+
name_meta = meta['name']
33+
regex = re.sub(r'\{[^\}]+\}', r'.*', name_meta) # handle {n} wildcards
34+
if re.fullmatch(regex, name):
35+
break
36+
else:
37+
raise RuntimeError(f'Parameter {name} is missing in parameters.json')
38+
39+
general_meta_file = Path(__file__).parent / 'general.json'
40+
general_crc = mavlink_crc323(general_meta_file.read_bytes())
41+
general_data = json.loads(general_meta_file.read_text())
42+
43+
parameters_crc = mavlink_crc323(parameters_meta_file.read_bytes())
44+
45+
general_url = f'https://quadcopter.dev/meta/{general_crc}/general.json'
46+
parameters_url = f'https://quadcopter.dev/meta/{parameters_crc}/parameters.json'
47+
48+
print(f'General CRC: {general_crc}')
49+
print(f'Parameters CRC: {mavlink_crc323(parameters_meta_file.read_bytes())}')
50+
print(f'General URL: {general_url}')
51+
print(f'Parameters URL: {parameters_url}')
52+
53+
code = 0
54+
55+
assert general_data['version'] == 1
56+
for meta in general_data['metadataTypes']:
57+
if meta['type'] == 1:
58+
if meta['uri'] != parameters_url:
59+
print(f'ERROR: Parameters URI should be {parameters_url}')
60+
code = 1
61+
if meta['fileCrc'] != parameters_crc:
62+
print(f'ERROR: Parameters CRC shoule be {parameters_crc}')
63+
code = 1
64+
break
65+
else:
66+
print('ERROR: Parameters metadata not found in general.json')
67+
code = 1
68+
69+
resp = requests.get(general_url, allow_redirects=True)
70+
resp.raise_for_status()
71+
assert resp.json() == general_data
72+
73+
resp = requests.get(parameters_url, allow_redirects=True)
74+
resp.raise_for_status()
75+
assert resp.json() == parameters_meta
76+
77+
if code == 0:
78+
print('Everything is good')
79+
sys.exit(code)

‎tools/parameters.json‎

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
{
2+
"version": 1,
3+
"parameters": [
4+
{ "name": "CTL_RATE_R_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for roll rate" },
5+
{ "name": "CTL_RATE_R_I", "type": "Float", "group": "Control", "shortDesc": "Integral gain for roll rate" },
6+
{ "name": "CTL_RATE_R_D", "type": "Float", "group": "Control", "shortDesc": "Derivative gain for roll rate" },
7+
{ "name": "CTL_RATE_R_WU", "type": "Float", "group": "Control", "shortDesc": "Integral windup limit for roll rate" },
8+
{ "name": "CTL_RATE_R_D_A", "type": "Float", "group": "Control", "shortDesc": "Low-pass filter alpha for roll rate" },
9+
{ "name": "CTL_RATE_P_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for pitch rate" },
10+
{ "name": "CTL_RATE_P_I", "type": "Float", "group": "Control", "shortDesc": "Integral gain for pitch rate" },
11+
{ "name": "CTL_RATE_P_D", "type": "Float", "group": "Control", "shortDesc": "Derivative gain for pitch rate" },
12+
{ "name": "CTL_RATE_P_WU", "type": "Float", "group": "Control", "shortDesc": "Integral windup limit for pitch rate" },
13+
{ "name": "CTL_RATE_P_D_A", "type": "Float", "group": "Control", "shortDesc": "Low-pass filter alpha for pitch rate" },
14+
{ "name": "CTL_RATE_Y_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for yaw rate" },
15+
{ "name": "CTL_RATE_Y_I", "type": "Float", "group": "Control", "shortDesc": "Integral gain for yaw rate" },
16+
{ "name": "CTL_RATE_Y_D", "type": "Float", "group": "Control", "shortDesc": "Derivative gain for yaw rate" },
17+
{ "name": "CTL_RATE_Y_WU", "type": "Float", "group": "Control", "shortDesc": "Integral windup limit for yaw rate" },
18+
{ "name": "CTL_RATE_Y_D_A", "type": "Float", "group": "Control", "shortDesc": "Low-pass filter alpha for yaw rate" },
19+
20+
{ "name": "CTL_RATE_P_MAX", "type": "Float", "group": "Control", "units": "rad/s", "shortDesc": "Maximum pitch rate for ACRO mode" },
21+
{ "name": "CTL_RATE_R_MAX", "type": "Float", "group": "Control", "units": "rad/s", "shortDesc": "Maximum roll rate for ACRO mode" },
22+
{ "name": "CTL_RATE_Y_MAX", "type": "Float", "group": "Control", "units": "rad/s", "shortDesc": "Maximum yaw rate for ACRO mode" },
23+
24+
{ "name": "CTL_ATT_R_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for roll angle" },
25+
{ "name": "CTL_ATT_P_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for pitch angle" },
26+
{ "name": "CTL_ATT_Y_P", "type": "Float", "group": "Control", "shortDesc": "Proportional gain for yaw angle" },
27+
{ "name": "CTL_ATT_MAX", "type": "Float", "group": "Control", "units": "radians", "shortDesc": "Maximum tilt angle for STAB mode" },
28+
29+
{
30+
"name": "CTL_FLT_MODE_{n}",
31+
"type": "Float",
32+
"group": "Control",
33+
"shortDesc": "Flight mode for switch position {n}",
34+
"values": [{ "value": 0, "description": "RAW" }, { "value": 1, "description": "ACRO" }, { "value": 2, "description": "STAB" }, { "value": 3, "description": "AUTO" }, { "value": 4, "description": "POS" }]
35+
},
36+
37+
{
38+
"name": "IMU_MODEL",
39+
"type": "Float",
40+
"shortDesc": "IMU sensor model",
41+
"group": "IMU",
42+
"increment": 1,
43+
"decimalPlaces": 0,
44+
"values": [{ "value": -1, "description": "Disabled"}, { "value": 1, "description": "MPU-9250"}, { "value": 2, "description": "ICM-20948"}, { "value": 3, "description": "MPU-6050"}, { "value": 4, "description": "ICM-40609-D"}],
45+
"rebootRequired": true
46+
},
47+
{
48+
"name": "IMU_BUS",
49+
"type": "Float",
50+
"shortDesc": "IMU bus type",
51+
"group": "IMU",
52+
"values": [
53+
{ "value": 0, "description": "SPI" },
54+
{ "value": 1, "description": "I2C" }
55+
],
56+
"rebootRequired": true
57+
},
58+
{ "name": "IMU_PIN_SCK", "type": "Float", "group": "IMU", "shortDesc": "IMU SPI SCK pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
59+
{ "name": "IMU_PIN_MISO", "type": "Float", "group": "IMU", "shortDesc": "IMU SPI MISO pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
60+
{ "name": "IMU_PIN_MOSI", "type": "Float", "group": "IMU", "shortDesc": "IMU SPI MOSI pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
61+
{ "name": "IMU_PIN_CS", "type": "Float", "group": "IMU", "shortDesc": "IMU SPI CS pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
62+
{ "name": "IMU_PIN_SDA", "type": "Float", "group": "IMU", "shortDesc": "IMU I2C SDA pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
63+
{ "name": "IMU_PIN_SCL", "type": "Float", "group": "IMU", "shortDesc": "IMU I2C SCL pin", "min": 1, "increment": 1, "decimalPlaces": 0 },
64+
{ "name": "IMU_PIN_INT", "type": "Float", "group": "IMU", "shortDesc": "IMU interrupt pin (-1 for using timer)", "min": -1, "increment": 1, "decimalPlaces": 0 },
65+
66+
{ "name": "IMU_ROT_ROLL", "type": "Float", "group": "IMU", "units": "radians", "shortDesc": "IMU roll rotation" },
67+
{ "name": "IMU_ROT_PITCH", "type": "Float", "group": "IMU", "units": "radians", "shortDesc": "IMU pitch rotation" },
68+
{ "name": "IMU_ROT_YAW", "type": "Float", "group": "IMU", "units": "radians", "shortDesc": "IMU yaw rotation" },
69+
70+
{ "name": "IMU_ACC_BIAS_X", "type": "Float", "group": "IMU (Calibration)", "units": "m/s^2", "shortDesc": "Accelerometer bias X", "volatile": true },
71+
{ "name": "IMU_ACC_BIAS_Y", "type": "Float", "group": "IMU (Calibration)", "units": "m/s^2", "shortDesc": "Accelerometer bias Y", "volatile": true },
72+
{ "name": "IMU_ACC_BIAS_Z", "type": "Float", "group": "IMU (Calibration)", "units": "m/s^2", "shortDesc": "Accelerometer bias Z", "volatile": true },
73+
74+
{ "name": "IMU_ACC_SCALE_X", "type": "Float", "group": "IMU (Calibration)", "shortDesc": "Accelerometer scale X", "volatile": true },
75+
{ "name": "IMU_ACC_SCALE_Y", "type": "Float", "group": "IMU (Calibration)", "shortDesc": "Accelerometer scale Y", "volatile": true },
76+
{ "name": "IMU_ACC_SCALE_Z", "type": "Float", "group": "IMU (Calibration)", "shortDesc": "Accelerometer scale Z", "volatile": true },
77+
78+
{ "name": "IMU_GYRO_BIAS_A", "type": "Float", "group": "IMU", "shortDesc": "Alpha for gyroscope bias estimation" },
79+
80+
{ "name": "EST_ACC_WEIGHT", "type": "Float", "group": "Estimation", "shortDesc": "Accelerometer weight" },
81+
{ "name": "EST_LVL_WEIGHT", "type": "Float", "group": "Estimation", "shortDesc": "Level weight", "decimalPlaces": 5 },
82+
{ "name": "EST_RATES_LPF_A", "type": "Float", "group": "Estimation", "shortDesc": "Low-pass filter alpha for rates" },
83+
{ "name": "EST_RATES_NO_F", "type": "Float", "group": "Estimation", "units": "Hz", "shortDesc": "Notch filter center frequency for rates", "min": 0, "decimalPlaces": 0 },
84+
{ "name": "EST_RATES_NO_BW", "type": "Float", "group": "Estimation", "units": "Hz", "shortDesc": "Notch filter bandwidth for rates", "min": 0, "decimalPlaces": 0 },
85+
86+
{ "name": "MOT_PIN_FL", "type": "Float", "group": "Motors", "shortDesc": "Front-left motor pin (-1 to disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
87+
{ "name": "MOT_PIN_FR", "type": "Float", "group": "Motors", "shortDesc": "Front-right motor pin (-1 to disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
88+
{ "name": "MOT_PIN_RL", "type": "Float", "group": "Motors", "shortDesc": "Rear-left motor pin (-1 to disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
89+
{ "name": "MOT_PIN_RR", "type": "Float", "group": "Motors", "shortDesc": "Rear-right motor pin (-1 to disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
90+
{ "name": "MOT_PWM_FREQ", "type": "Float", "group": "Motors", "units": "Hz", "shortDesc": "PWM frequency", "min": 0, "increment": 1, "decimalPlaces": 0 },
91+
{ "name": "MOT_PWM_RES", "type": "Float", "group": "Motors", "units": "bits", "shortDesc": "PWM resolution", "min": 1, "increment": 1, "decimalPlaces": 0 },
92+
{ "name": "MOT_PWM_STOP", "type": "Float", "group": "Motors", "units": "μs", "shortDesc": "PWM for stopping the motors (brushless motors)", "min": 0, "decimalPlaces": 0 },
93+
{ "name": "MOT_PWM_MIN", "type": "Float", "group": "Motors", "units": "μs", "shortDesc": "PWM for minimum throttle (brushless motors)", "min": 0, "decimalPlaces": 0 },
94+
{ "name": "MOT_PWM_MAX", "type": "Float", "group": "Motors", "units": "μs", "shortDesc": "PWM for maximum throttle (-1 for brushed motors)", "min": -1, "decimalPlaces": 0 },
95+
96+
{ "name": "RC_RX_PIN", "type": "Float", "group": "RC", "shortDesc": "RC receiver RX pin (-1 for disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
97+
{
98+
"name": "RC_ZERO_{n}",
99+
"type": "Float",
100+
"group": "RC (Calibration)",
101+
"shortDesc": "RC channel {n} zero PWM",
102+
"units": "μs",
103+
"min": 0,
104+
"decimalPlaces": 0
105+
},
106+
{
107+
"name": "RC_MAX_{n}",
108+
"type": "Float",
109+
"group": "RC (Calibration)",
110+
"shortDesc": "RC channel {n} maximum PWM",
111+
"units": "μs",
112+
"min": 0,
113+
"decimalPlaces": 0
114+
},
115+
116+
{ "name": "RC_ROLL", "type": "Float", "group": "RC (Calibration)", "shortDesc": "RC roll channel", "min": 0, "increment": 1, "decimalPlaces": 0 },
117+
{ "name": "RC_PITCH", "type": "Float", "group": "RC (Calibration)", "shortDesc": "RC pitch channel", "min": 0, "increment": 1, "decimalPlaces": 0 },
118+
{ "name": "RC_THROTTLE", "type": "Float", "group": "RC (Calibration)", "shortDesc": "RC throttle channel", "min": 0, "increment": 1, "decimalPlaces": 0 },
119+
{ "name": "RC_YAW", "type": "Float", "group": "RC (Calibration)", "shortDesc": "RC yaw channel", "min": 0, "increment": 1, "decimalPlaces": 0 },
120+
{ "name": "RC_MODE", "type": "Float", "group": "RC (Calibration)", "shortDesc": "RC mode switch channel", "min": 0, "increment": 1, "decimalPlaces": 0 },
121+
122+
{
123+
"name": "WIFI_MODE",
124+
"type": "Float",
125+
"group": "Wi-Fi",
126+
"shortDesc": "Wi-Fi mode",
127+
"values": [
128+
{ "value": 0, "description": "Disabled" },
129+
{ "value": 1, "description": "Access point (AP)" },
130+
{ "value": 2, "description": "Client (STA)" },
131+
{ "value": 3, "description": "ESP-NOW" }
132+
]
133+
},
134+
{ "name": "WIFI_PORT_LOC", "type": "Float", "group": "Wi-Fi", "shortDesc": "Local UDP port", "min": 0, "max": 65535, "increment": 1, "decimalPlaces": 0 },
135+
{ "name": "WIFI_PORT_REM", "type": "Float", "group": "Wi-Fi", "shortDesc": "Remote UDP port", "min": 0, "max": 65535, "increment": 1, "decimalPlaces": 0 },
136+
{
137+
"name": "WIFI_LONG_RANGE",
138+
"type": "Float",
139+
"group": "Wi-Fi",
140+
"shortDesc": "Long-range WiFi mode",
141+
"values": [
142+
{ "value": 0, "description": "Off" },
143+
{ "value": 1, "description": "On" }
144+
]
145+
},
146+
{
147+
"name": "WIFI_BROADCAST",
148+
"type": "Float",
149+
"group": "Wi-Fi",
150+
"shortDesc": "Always broadcast UDP",
151+
"values": [
152+
{ "value": 0, "description": "Off" },
153+
{ "value": 1, "description": "On" }
154+
]
155+
},
156+
157+
{ "name": "ESPNOW_CHANNEL", "type": "Float", "group": "ESP-NOW", "shortDesc": "ESP-NOW channel", "min": 1, "max": 13, "increment": 1, "decimalPlaces": 0 },
158+
159+
{ "name": "MAV_SYS_ID", "type": "Float", "group": "MAVLink", "shortDesc": "MAVLink system ID", "min": 1, "increment": 1, "decimalPlaces": 0 },
160+
{ "name": "MAV_RATE_SLOW", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for heartbeats and battery state", "min": 0, "decimalPlaces": 0 },
161+
{ "name": "MAV_RATE_FAST", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for attitude, RC channels and motors state", "min": 0, "decimalPlaces": 0 },
162+
{ "name": "MAV_RATE_EXTRA", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for IMU data and exposed log topic", "min": 0, "decimalPlaces": 0 },
163+
{ "name": "MAV_RATE_ATT", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for attitude", "min": 0, "decimalPlaces": 0 },
164+
{ "name": "MAV_RATE_ATT_TG", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for attitude target", "min": 0, "decimalPlaces": 0 },
165+
{ "name": "MAV_RATE_RC", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for RC channels", "min": 0, "decimalPlaces": 0 },
166+
{ "name": "MAV_RATE_MOT", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for motors state", "min": 0, "decimalPlaces": 0 },
167+
{ "name": "MAV_RATE_IMU", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for IMU data", "min": 0, "decimalPlaces": 0 },
168+
{ "name": "MAV_RATE_TOPIC", "type": "Float", "group": "MAVLink", "units": "Hz", "shortDesc": "Rate for exposed log topic", "min": 0, "decimalPlaces": 0 },
169+
170+
{
171+
"name": "LOG_MEMORY",
172+
"type": "Float",
173+
"group": "Log",
174+
"shortDesc": "Memory type for logging",
175+
"values": [
176+
{ "value": -1, "description": "Disabled" },
177+
{ "value": 0, "description": "RAM" },
178+
{ "value": 1, "description": "PSRAM" }
179+
]
180+
},
181+
{ "name": "LOG_USAGE", "type": "Float", "group": "Log", "units": "norm", "shortDesc": "Percentage of memory to use for logging" },
182+
{ "name": "LOG_RATE_{n}", "type": "Float", "group": "Log", "units": "Hz", "shortDesc": "Log topic {n} rate", "min": 0, "decimalPlaces": 0 },
183+
184+
{ "name": "PWR_VOLT_PIN", "type": "Float", "group": "Power", "shortDesc": "Voltage ADC input pin (-1 for disabled)", "min": -1, "increment": 1, "decimalPlaces": 0 },
185+
{ "name": "PWR_VOLT_SCALE", "type": "Float", "group": "Power", "shortDesc": "Voltage divider scale factor" },
186+
{ "name": "PWR_VOLT_LPF_A", "type": "Float", "group": "Power", "shortDesc": "Low-pass filter alpha for battery voltage" },
187+
188+
{ "name": "SF_RC_LOSS_TIME", "type": "Float", "group": "Safety", "units": "s", "shortDesc": "RC signal loss timeout in seconds", "min": 0, "decimalPlaces": 1 },
189+
{ "name": "SF_DESCEND_TIME", "type": "Float", "group": "Safety", "units": "s", "shortDesc": "Automatic descent timeout in seconds", "min": 0, "decimalPlaces": 1 },
190+
{ "name": "SF_DISARM_TILT", "type": "Float", "group": "Safety", "units": "radians", "shortDesc": "Tilt angle above which auto-disarm triggers" }
191+
]
192+
}

0 commit comments

Comments
 (0)