Some background information on the Firmware, Subsystems and Modules can be found on the Airframe Configuration page.
Paparazzi is currently split into various firmware types where Fixedwing and Rotorcraft are the main autopilot firmware versions. These firmwares implement some vehicle type specific code using predefined Makefiles defined in conf/firmwares subfolder.
Low Level drivers
low level code organization is roughly:
- sw/airborne/mcu_periph : interfaces/drivers for MCU peripherals like I2C, SPI, ADC, etc... (the HAL)
- sw/airborne/peripherals : drivers for external peripherals, like sensor chips, etc...
- sw/airborne/arch : everything that is architecture specific (lpc21, stm32, linux, ..)
- sw/airborne/boards : board definitions, pinout, etc... (no need to touch this unless you want to support a new board)
Modules use code generation in order to allow people to use them by only editing the vehicle's xml configuration as opposed to changing/adding to the code of the autopilot. This makes the paparazzi build process highly configurable. Typically, function calls are generated for initialization and in the main loop for timers (periodic in paparazzi slang) and events. The event and periodic functions of the Modules get called at the end of event_task_ap and periodic_task_ap respectively.
Modules are used to configure all parts of paparazzi other than the firmware described above. The build configuration for each module is described using xml description language and the located in the conf/modules subfolder. These modules implement not only the user implemented mission specific code but also the low level drivers and subsystems.
sw/airborne/modules contains the mission specific software such as image processing, video recording or relay or guidance commands.
Creating a new Module
- See Modules for more information
/sw/airborne/subsystems contains the code base for some of the more critical mission independent software such as AHRS, IMU, INS and GPS.
|Since v5.8 it is possible to safely replace subsystem by module in your airframe file. The following describes the original description of the legacy subsystems.|
They are selected and configured with a
<subsystems name="foo" type="bar"> in the firmware section of the airframe file. All this does is basically include a makefile foo_bar.makefile that adds the respective sources and adds a few configuration options. (See conf/autopilot/subsystems/...)
This makes it easier to put an airframe file together (they replace the old raw makefile section) and also allows us to change the code and move/rename files behind the scenes without breaking everyones airframe files.
Creating a new Subsystem
A new subsystem is required when adding support for new or alternate core functionalities, as listed above. Some new subsystems will rely on underlying peripheral or MCU peripheral drivers (for example a new IMU subsystem), others do not need this (for example a new set of control loops). An MCU peripheral uses on-chip hardware peripherals in the main microcontroller (such as the SPI hardware), while normal peripherals are external hardware such as an analog to digital converter integrated circuit (such as the MAX1168).
The general strategy for adding a new subsystem should be something along the lines of:
- (if required) write a peripheral driver for the specific device or device family in sw/airborne/peripherals/
- (if required) in the peripheral driver, use the sw/airborne/mcu_periph/*.[c|h] arch-independent mcu peripheral drivers to handle the communication and input-output operations
- (if required) you may wish to use a family generic c header (.h) file for register definitions, etc., if the driver could be used with a family of peripheral devices
- write a subsystem driver for the new functionality, device or device family in sw/airborne/subsystems/TYPE/
- you may wish to use a family generic c header (.h) file for register definitions, etc., if the driver could be used with a family of peripheral devices
- if you need to add complex features (for example, use a gpio for a reset, use an interrupt for data ready, etc), you will need to add some arch specific files in the correct location to handle some of the extra initialization and operation, for example in sw/airborne/arch/ARCHTYPE/subsystems|peripherals|mcu_periph|ETC/
- write a subsystem makefile to aid in building the code, found in conf/firmwares/subsystems/fixedwing|rotorcraft|shared/
- even though you technically need to make a new one, you can undoubtedly use existing examples to make your life easier. For example, for an IMU, try looking at the adxl345 peripheral driver, or possibly the imu_b2.[c|h] (which uses for example the ms2100 and max1168 peripherals) for some ideas
- last thing, make sure you USE MASTER for all development, and take a look at the Contributing page, and be sure to review the coding style guidelines
- heavily comment the code, especially regarding any magic numbers and operations (for example, scaling the input of a sensor)
Finally, master is always being updated and changed, so if you aren't quite sure about something, don't hesitate to ask on the mailing list. In addition, there may be style differences between newer, updated subsystems and older subsystems.
So the difference is that with subsystems you explicitly call the functions (e.g. control loops) from the main ap loop, whereas the event/periodic functions of the Modules get called at the end of the main event/periodic tasks. So Modules are perfect to add stuff like extra payload and sensors, but Subsystems give you tighter control over when and in what order to call functions (e.g. for estimation/control).
Modules naturally provide the "several implementations" feature of the Subsystems. So, we could have a "generic" main.c consisting only in calls to the generated functions. Nevertheless, care should be taken that switching to a "module only" configuration doesn't become detrimental to the readability and debugability of the code.
You can also wrap some subsystem code as a modules (e.g. infrared), or the other way round (e.g. imu_ppzuav). As you can see with the imu_ppzuav module it also still expects a direct ImuEvent call from main_ap, so you could say it's not a "pure" module.