INAV is a navigation-capable flight controller firmware for multirotor, fixed-wing, and other RC vehicles. It is a community-driven project written primarily in C (C99/C11 standard) with support for STM32 F4, F7, H7, and AT32 microcontrollers.
- Type: Embedded firmware for flight controllers
- Language: C (C99/C11), with some C++ for unit tests
- Build System: CMake (version 3.13+)
- License: GNU GPL v3
- Version: 9.0.1 (as of this writing)
- Codebase History: Evolved from Cleanflight/Baseflight
The INAV codebase is organized into the following major subsystems:
- Flight Control (
fc/): Core flight controller logic, initialization, MSP protocol handling - Sensors (
sensors/): Gyro, accelerometer, compass, barometer, GPS, rangefinder, pitot tube - Flight (
flight/): PID controllers, mixers, altitude hold, position hold, navigation - Navigation (
navigation/): Waypoint missions, RTH (Return to Home), position hold - Drivers (
drivers/): Hardware abstraction layer for MCU peripherals (SPI, I2C, UART, timers, etc.) - IO (
io/): Serial communication, OSD, LED strips, telemetry - RX (
rx/): Radio receiver protocols (CRSF, SBUS, IBUS, etc.) - Scheduler (
scheduler/): Real-time task scheduling - Configuration (
config/): Parameter groups, EEPROM storage, settings management - MSP (
msp/): MultiWii Serial Protocol implementation - Telemetry (
telemetry/): SmartPort, FPort, MAVLink, LTM, CRSF telemetry - Blackbox (
blackbox/): Flight data recorder - Programming (
programming/): Logic conditions and global functions for in-flight programming
/src/main/ - Main source code
├── build/ - Build configuration and macros
├── common/ - Common utilities (math, filters, utils)
├── config/ - Configuration system (parameter groups)
├── drivers/ - Hardware drivers (MCU-specific)
├── fc/ - Flight controller core
├── flight/ - Flight control algorithms
├── io/ - Input/output (serial, OSD, LED)
├── msp/ - MSP protocol
├── navigation/ - Navigation and autopilot
├── rx/ - Radio receiver protocols
├── sensors/ - Sensor drivers and processing
├── scheduler/ - Task scheduler
├── telemetry/ - Telemetry protocols
└── target/ - Board-specific configurations
/docs/ - Documentation
└── development/ - Developer documentation
/cmake/ - CMake build scripts
/lib/ - External libraries
/tools/ - Build and utility tools
- Types: Use
_tsuffix for typedef'd types:gyroConfig_t,pidController_t - Enums: Use
_esuffix for enum types:portMode_e,cfTaskPriority_e - Functions: Use camelCase with verb-phrase names:
gyroInit(),deleteAllPages() - Variables: Use camelCase nouns, avoid noise words like "data" or "info"
- Booleans: Question format:
isOkToArm(),canNavigate() - Constants: Upper case with underscores:
MAX_GYRO_COUNT - Macros: Upper case with underscores:
FASTRAM,STATIC_UNIT_TESTED
- Indentation: 4 spaces (no tabs)
- Braces: K&R style (opening brace on same line, except for functions)
- Line Length: Keep reasonable (typically under 120 characters)
- Comments: Explain WHY, not WHAT. Document variables at declaration, not at extern usage
- Header Guards: Use
#pragma once(modern convention used throughout codebase)
INAV uses special memory attributes for performance-critical code on resource-constrained MCUs:
FASTRAM // Fast RAM section (aligned)
EXTENDED_FASTRAM // Extended fast RAM (STM32F4/F7 only)
DMA_RAM // DMA-accessible RAM (STM32H7, AT32F43x)
SLOW_RAM // Slower external RAM - deprecated, o not use
STATIC_FASTRAM // Static variable in fast RAM
STATIC_FASTRAM_UNIT_TESTED // Static fast RAM variable visible in unit testsSTATIC_UNIT_TESTED // static in production, visible in unit tests
STATIC_INLINE_UNIT_TESTED // static inline in production, visible in tests
INLINE_UNIT_TESTED // inline in production, visible in tests
UNIT_TESTED // Always visible (no storage class)INAV uses CMake with custom target definition functions:
- Target Definition: Each board has a
target.hand optionallyCMakeLists.txt - Hardware Function:
target_stm32f405xg(NAME optional_params) - Build Directory: Always use out-of-source builds in
/builddirectory
# From workspace root
cd build
cmake ..
make MATEKF722SE # Build specific target
make # Build all targetsTargets are defined in /src/main/target/TARGETNAME/:
target.h: Hardware pin definitions, feature enables, MCU configurationtarget.c: Board-specific initialization codeCMakeLists.txt: Build configuration (optional)
Example target definition:
#define TARGET_BOARD_IDENTIFIER "MF7S"
#define LED0 PA14
#define BEEPER PC13
#define USE_SPI
#define USE_SPI_DEVICE_1
#define SPI1_SCK_PIN PA5Feature flags control code inclusion:
#ifdef USE_GPS
// GPS code
#endif
#if defined(STM32F4)
// F4-specific code
#elif defined(STM32F7)
// F7-specific code
#endifINAV uses a sophisticated configuration system called "Parameter Groups" for persistent storage:
// Define a configuration structure
typedef struct {
uint8_t gyro_lpf_hz;
uint16_t gyro_kalman_q;
// ...
} gyroConfig_t;
// Register with reset template
PG_REGISTER_WITH_RESET_TEMPLATE(gyroConfig_t, gyroConfig, PG_GYRO_CONFIG, 12);
// Define default values
PG_RESET_TEMPLATE(gyroConfig_t, gyroConfig,
.gyro_lpf_hz = 60,
.gyro_kalman_q = 200,
// ...
);
// Access in code
gyroConfig()->gyro_lpf_hzKey Functions:
PG_REGISTER_WITH_RESET_TEMPLATE(): Register with static defaultsPG_REGISTER_WITH_RESET_FN(): Register with function-based initializationPG_REGISTER_ARRAY(): For arrays of configuration items- Parameter group IDs are in
config/parameter_group_ids.h
INAV uses a priority-based cooperative task scheduler:
typedef enum {
TASK_PRIORITY_IDLE = 0,
TASK_PRIORITY_LOW = 1,
TASK_PRIORITY_MEDIUM = 3,
TASK_PRIORITY_HIGH = 5,
TASK_PRIORITY_REALTIME = 18,
} cfTaskPriority_e;Tasks are defined in fc/fc_tasks.c with priority and desired execution period.
Sensors use a common pattern:
- Detection: Auto-detect hardware at boot (
gyroDetect(),baroDetect()) - Initialization: Configure sensor parameters
- Calibration: Zero-offset calibration (gyro, accelerometer)
- Data Processing: Apply calibration, alignment, and filtering
The main control loop follows this pattern:
- Gyro Task (highest priority): Read gyro, apply filters
- PID Task: Calculate PID corrections
- RX Task: Process radio input
- Other Tasks: Sensors, telemetry, OSD, etc. (lower priority)
MultiWii Serial Protocol is used for configuration and telemetry:
- Request/response model
- Message types defined in
msp/msp_protocol.h - Handlers in
fc/fc_msp.c
INAV abstracts hardware through resource allocation:
// IO pins
IO_t pin = IOGetByTag(IO_TAG(PA5));
IOInit(pin, OWNER_SPI, RESOURCE_SPI_SCK, 1);
// Timers
const timerHardware_t *timer = timerGetByTag(IO_TAG(PA8), TIM_USE_ANY);
// DMA
dmaIdentifier_e dma = dmaGetIdentifier(DMA1_Stream0);INAV uses several approaches:
- Return codes: Boolean success/failure or error enums
- Diagnostics:
sensors/diagnostics.cfor sensor health - Status indicators: Beeper codes, LED patterns for user feedback
- Logging: CLI-based logging system
Sensor data typically goes through multiple filtering stages:
// Low-pass filters
gyroLpfApplyFn = lowpassFilterGetApplyFn(filterType);
gyroLpfApplyFn(&gyroLpfState[axis], sample);
// Notch filters (for dynamic filtering)
for (int i = 0; i < dynamicNotchCount; i++) {
sample = biquadFilterApply(¬chFilter[i], sample);
}All sensors go through board alignment transforms to correct for mounting orientation:
// Apply board alignment rotation matrix
applySensorAlignment(gyroData, gyroData, gyroAlign);INAV can be compiled for host system simulation:
cmake -DSITL=ON ..
makemaintenance-X.x: Current version development (e.g.,maintenance-9.x)maintenance-Y.x: Next major version (e.g.,maintenance-10.x)master: Tracks current version, receives merges from maintenance branches
-
Target Branch:
- Bug fixes and backward-compatible features → current maintenance branch
- Breaking changes → next major version maintenance branch
- Never target
masterdirectly
-
Keep PRs Focused: One feature/fix per PR
-
Code Quality:
- Follow existing code style
- Add unit tests where possible
- Update documentation in
/docs - Test on real hardware when possible
-
Commit Messages: Clear, descriptive messages
Before making changes, review:
docs/development/Development.md- Development principlesdocs/development/Contributing.md- Contribution guidelines- Target-specific files in
/src/main/target/
platform.h: Platform-specific includes and definestarget.h: Board-specific hardware configurationconfig/parameter_group.h: Parameter group systemconfig/parameter_group_ids.h: PG ID definitionsfc/settings.yaml: CLI settings definitions
fc/fc_core.c: Main flight control loopfc/fc_init.c: System initializationfc/fc_tasks.c: Task scheduler configurationflight/pid.c: PID controller implementationflight/mixer.c: Motor mixing
build/build_config.h: Build-time configuration macroscommon/axis.h: Axis definitions (X, Y, Z, ROLL, PITCH, YAW)common/maths.h: Math utilities and constantscommon/filter.h: Digital filter implementationsdrivers/accgyro/accgyro.h: Gyro/accelerometer interface
- Understand the Module: Read related files in the same directory
- Check for Similar Code: Search for similar features to maintain consistency
- Follow Parameter Group Pattern: New settings should use PG system
- Add to Scheduler: New periodic tasks go in
fc/fc_tasks.c - Update Documentation: Add/update files in
/docs - Consider Target Support: Use
#ifdef USE_FEATUREfor optional features - Generate CLI setting docs: Remember to inform user to run
python src/utils/update_cli_docs.py - Follow conding standard: Follow MISRA C rules
- Increase Paremeterer Group Version: When changing PG structure, increase version corresponding in
PG_REGISTER,PG_REGISTER_WITH_RESET_FN,PG_REGISTER_WITH_RESET_TEMPLATE,PG_REGISTER_ARRAYorPG_REGISTER_ARRAY_WITH_RESET_FN
- Review Recent Changes: Check git history for related modifications
- Test Signal Path: For sensor issues, trace from hardware through filters to consumer
- Consider All Platforms: STM32F4, F7, H7, and AT32 may behave differently
- Check Memory Usage: Embedded system has limited RAM/flash
- Maintain API Compatibility: Unless targeting next major version
- Preserve Unit Tests: Update tests to match refactored code
- Update Documentation: Keep docs synchronized with code changes
- Consider Performance: Profile on target hardware, not just host compilation
- Check All Callers: Use grep/search to find all usage sites
- Don't Ignore Memory Attributes: FASTRAM placement affects real-time performance
- Don't Break Parameter Groups: Changing PG structure requires version bump
- Don't Assume Hardware: Always check feature flags (
#ifdef USE_GPS) - Don't Break MSP: Changes to MSP protocol affect configurator compatibility
- Don't Commit Wrong Branch: Target maintenance branch, not master
- Don't Skip Documentation: Code without docs increases support burden
- Don't Hardcode Values: Use parameter groups for configurable values
Find definitions:
grep -r "typedef.*_t" src/main/ # Find all type definitions
grep -r "PG_REGISTER" src/main/ # Find parameter groups
grep -r "TASK_" src/main/ # Find scheduled tasksFind usage:
grep -r "functionName" src/main/
grep -r "USE_GPS" src/main/target/ # Feature support by targetFind similar code:
- Look in the same directory first
- Check for similar sensor/peripheral implementations
- Review git history:
git log --all --oneline --grep="keyword"
- Startup:
main.c→fc_init.c:init()→fc_tasks.c:tasksInit() - Main Loop:
scheduler.c:scheduler()executes tasks by priority - Critical Path: Gyro → PID → Mixer → Motors (highest priority)
- Configuration: CLI/MSP → Parameter Groups → EEPROM
Different MCU families have different characteristics:
- STM32F4: Most common, 84-168 MHz, FPU, no cache
- STM32F7: Faster, 216 MHz, FPU, I/D cache, requires cache management
- STM32H7: Fastest, 480 MHz, more RAM, complex memory architecture (DTCM, SRAM)
- AT32F43x: Chinese MCU, STM32F4-compatible, different peripherals
Always test on target or use #if defined() guards for MCU-specific code.
*_config.h: Configuration structures (usually with PG)*_impl.h: Implementation headers (MCU-specific)*_hal.h: Hardware abstraction layeraccgyro_*.c: Gyro/accelerometer driversbus_*.c: Communication bus drivers (SPI, I2C)
- FC: Flight Controller
- PG: Parameter Group
- MSP: MultiWii Serial Protocol
- CLI: Command Line Interface
- OSD: On-Screen Display
- RTH: Return to Home
- PID: Proportional-Integral-Derivative (controller)
- IMU: Inertial Measurement Unit (gyro + accel)
- AHRS: Attitude and Heading Reference System
- ESC: Electronic Speed Controller
- SITL: Software In The Loop
- HITL: Hardware In The Loop
- Main Repository: https://github.com/iNavFlight/inav
- Configurator: https://github.com/iNavFlight/inav-configurator
- Discord: https://discord.gg/peg2hhbYwN
- Documentation: https://github.com/iNavFlight/inav/wiki
- Release Notes: https://github.com/iNavFlight/inav/releases
This document is accurate for INAV 9.0.1. As the project evolves, some details may change. Always refer to the latest documentation and code for authoritative information.
Remember: INAV flies aircraft that people build and fly. Code quality, safety, and reliability are paramount. When in doubt, ask the community or maintainers for guidance.