Skip to content

Commit ef9cd3f

Browse files
CopilotHTRamsey
andauthored
Enhance Copilot instructions with Quick Start, Testing, and Troubleshooting (#13658)
Co-authored-by: HTRamsey <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]>
1 parent b1ca72a commit ef9cd3f

File tree

1 file changed

+176
-11
lines changed

1 file changed

+176
-11
lines changed

.github/copilot-instructions.md

Lines changed: 176 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
Ground Control Station for MAVLink-enabled UAVs supporting PX4 and ArduPilot.
44

5+
## Quick Start for AI Assistants
6+
7+
**First-time here?** Start with these critical files:
8+
1. **This file** - Architecture patterns and coding standards
9+
2. `.github/CONTRIBUTING.md` - Contribution workflow
10+
3. `src/FactSystem/Fact.h` - The most important pattern in QGC
11+
4. `src/Vehicle/Vehicle.h` - Core vehicle model
12+
13+
**Most Critical Pattern**: The **Fact System** handles ALL vehicle parameters. Never create custom parameter storage - always use Facts.
14+
15+
**Golden Rule**: Multi-vehicle support means ALWAYS null-check `MultiVehicleManager::instance()->activeVehicle()`.
16+
517
## Tech Stack
618
- **C++20** with **Qt 6.10.0** (QtQml, QtQuick)
719
- **Build**: CMake 3.25+, Ninja
@@ -146,6 +158,13 @@ void method(Vehicle* vehicle) {
146158
- Do NOT create verbose file headers or unnecessary documentation files
147159
- Do NOT add README files unless explicitly requested
148160
161+
**Security & Dependencies:**
162+
- Never commit secrets, API keys, or credentials
163+
- Validate all external inputs (MAVLink messages, file uploads, user input)
164+
- Use Qt's built-in sanitization for SQL and string operations
165+
- When adding dependencies, check for known vulnerabilities
166+
- Prefer Qt's built-in functionality over external libraries
167+
149168
## Common Pitfalls (DO NOT!)
150169
151170
1. ❌ Assume single vehicle - Always null-check `activeVehicle()`
@@ -173,6 +192,55 @@ cmake --build build --config Debug
173192
- `QGC_ENABLE_BLUETOOTH` - Bluetooth support
174193
- `QGC_DISABLE_APM_PLUGIN` / `QGC_DISABLE_PX4_PLUGIN`
175194

195+
## Testing
196+
197+
### Running Tests
198+
```bash
199+
# Run all unit tests
200+
./build/Debug/QGroundControl --unittest
201+
202+
# Run specific test
203+
./build/Debug/QGroundControl --unittest:<TestClassName>
204+
205+
# Run with verbose output
206+
./build/Debug/QGroundControl --unittest --logging:full
207+
```
208+
209+
### Test Structure
210+
- Tests mirror `src/` structure in `test/` directory
211+
- Use `UnitTest` base class from Qt Test framework
212+
- Mock vehicle connections when testing vehicle-dependent code
213+
- Always test with null vehicle checks
214+
215+
### Adding New Tests
216+
```cpp
217+
class MyComponentTest : public UnitTest {
218+
Q_OBJECT
219+
private slots:
220+
void init(); // Called before each test
221+
void cleanup(); // Called after each test
222+
void testMyFunction();
223+
};
224+
```
225+
226+
## Troubleshooting
227+
228+
### Build Issues
229+
- **Qt not found**: Set `CMAKE_PREFIX_PATH` to Qt installation, or use qt-cmake
230+
- **Submodule errors**: Run `git submodule update --init --recursive`
231+
- **Missing dependencies**: Check platform-specific build instructions at https://dev.qgroundcontrol.com/
232+
- **CMake cache issues**: Delete `build/` directory and reconfigure
233+
234+
### Runtime Issues
235+
- **Crash on startup**: Check log files in `~/.local/share/QGroundControl/` (Linux/macOS) or `%LOCALAPPDATA%\QGroundControl` (Windows)
236+
- **Vehicle not connecting**: Verify MAVLink protocol compatibility, check link configuration
237+
- **Parameter load failures**: Ensure `parametersReady` signal before accessing Facts
238+
239+
### Development Environment
240+
- **Qt Creator recommended**: Import CMakeLists.txt as project
241+
- **clangd for VSCode**: Uses `.clangd` config in repo root
242+
- **Pre-commit hooks**: Run `pre-commit install` to enable automatic formatting
243+
176244
## Performance Tips
177245
- Batch updates: `fact->setSendValueChangedSignals(false)`
178246
- Suppress live updates: `factGroup->setLiveUpdates(false)`
@@ -182,19 +250,116 @@ cmake --build build --config Debug
182250
183251
## Common Tasks
184252
185-
**Add parameter:**
186-
1. Access via `vehicle->parameterManager()->getParameter()`
187-
2. Validate with `fact->validate()` before setting
188-
3. Listen to `valueChanged()` signal
253+
### Working with Vehicle Parameters
254+
```cpp
255+
// 1. Get parameter (always null-check!)
256+
Vehicle* vehicle = MultiVehicleManager::instance()->activeVehicle();
257+
if (!vehicle) return;
258+
259+
Fact* param = vehicle->parameterManager()->getParameter(-1, "PARAM_NAME");
260+
if (!param) {
261+
qCWarning(Log) << "Parameter not found";
262+
return;
263+
}
264+
265+
// 2. Validate before setting
266+
QString error = param->validate(newValue, false);
267+
if (!error.isEmpty()) {
268+
qCWarning(Log) << "Invalid value:" << error;
269+
return;
270+
}
271+
272+
// 3. Set value (cookedValue for UI with units)
273+
param->setCookedValue(newValue);
189274
190-
**Create settings group:**
191-
1. Subclass `SettingsGroup`, use `DEFINE_SETTINGFACT`
192-
2. Create `*.SettingsGroup.json` metadata
193-
3. Access via `SettingsManager::instance()`
275+
// 4. Listen to changes
276+
connect(param, &Fact::valueChanged, this, [](QVariant value) {
277+
qCDebug(Log) << "Parameter changed:" << value;
278+
});
279+
```
280+
281+
### Creating a Settings Group
282+
```cpp
283+
// 1. Define in MySettings.h
284+
class MySettings : public SettingsGroup {
285+
Q_OBJECT
286+
public:
287+
DEFINE_SETTINGFACT(mySetting) // Creates Fact with JSON metadata
288+
};
289+
290+
// 2. Create MySettings.SettingsGroup.json with metadata
291+
{
292+
"mySetting": {
293+
"shortDescription": "My setting",
294+
"type": "uint32",
295+
"default": 100,
296+
"min": 0,
297+
"max": 1000
298+
}
299+
}
300+
301+
// 3. Access anywhere
302+
int value = SettingsManager::instance()->mySettings()->mySetting()->rawValue().toInt();
303+
```
304+
305+
### Adding a Vehicle Component
306+
```cpp
307+
// 1. Create MyComponent.h (subclass VehicleComponent)
308+
class MyComponent : public VehicleComponent {
309+
Q_OBJECT
310+
public:
311+
MyComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = nullptr);
312+
313+
QString name() const override { return "My Component"; }
314+
QString description() const override { return "Component description"; }
315+
QString iconResource() const override { return "/qmlimages/MyComponentIcon.svg"; }
316+
bool requiresSetup() const override { return true; }
317+
bool setupComplete() const override { return _setupComplete; }
318+
QUrl setupSource() const override { return QUrl::fromUserInput("qrc:/qml/MyComponentSetup.qml"); }
319+
};
320+
321+
// 2. Register in AutoPilotPlugin::getVehicleComponents()
322+
```
323+
324+
### Handling MAVLink Messages
325+
```cpp
326+
// In a FactGroup or custom component
327+
void MyFactGroup::handleMessage(Vehicle* vehicle, mavlink_message_t& message) {
328+
switch (message.msgid) {
329+
case MAVLINK_MSG_ID_MY_MESSAGE: {
330+
mavlink_my_message_t msg;
331+
mavlink_msg_my_message_decode(&message, &msg);
332+
333+
// Update Facts (thread-safe via Qt signals)
334+
myFact()->setRawValue(msg.value);
335+
break;
336+
}
337+
}
338+
}
339+
```
194340
195-
**Add vehicle component:**
196-
1. Subclass `VehicleComponent`, implement virtuals
197-
2. Create QML UI, register in AutoPilotPlugin
341+
### Adding a QML UI Component
342+
```qml
343+
// 1. Create MyControl.qml
344+
import QtQuick
345+
import QGroundControl
346+
import QGroundControl.Controls
347+
348+
QGCButton {
349+
text: "My Action"
350+
351+
property var vehicle: QGroundControl.multiVehicleManager.activeVehicle
352+
353+
enabled: vehicle && vehicle.armed
354+
355+
onClicked: {
356+
if (vehicle) {
357+
// Always null-check vehicle!
358+
vehicle.sendMavCommand(...)
359+
}
360+
}
361+
}
362+
```
198363

199364
## Essential Files to Read
200365
1. `.github/CONTRIBUTING.md` - Contribution guidelines

0 commit comments

Comments
 (0)