Skip to main content

Welcome to the Development Section

Work in progress

This site is still new. Very new. As of writing this, it's only 5 days since we started working on it. So it's still very much a work in progress. Pages going to be added, updated and improved pretty every day in the weeks to come. So if you're missing something, please be patient. It will come! You can also help us out, check out the #documentation channel on the Discord server for more info.

Contributing

Contributions are welcome and encouraged. You can contribute in many ways:

  • implement a new feature in the firmware or in configurator (see below);
  • documentation updates and corrections;
  • How-To guides - received help? Help others!
  • bug reporting & fixes;
  • new feature ideas & suggestions;
  • provide a new translation for configurator, or help us maintain the existing ones (see below).

The best place to start is the Betaflight Slack (registration here). Next place is the github issue tracker:

https://github.com/betaflight/betaflight/issues https://github.com/betaflight/betaflight-configurator/issues

Before creating new issues please check to see if there is an existing one, search first otherwise you waste people's time when they could be coding instead!

If you want to contribute to our efforts financially, please consider making a donation to us through PayPal.

If you want to contribute financially on an ongoing basis, you should consider becoming a patron for us on Patreon.

Development

This document is primarily for developers.

Contribution of bugfixes and new features is encouraged. Please be aware that we have a thorough review process for pull requests, and be prepared to explain what you want to achieve with your pull request. Before starting to write code, please read this document and the coding style definition.

GitHub actions are used to run automatic builds

Translators

We want to make Betaflight accessible for pilots who are not fluent in English, and for this reason we are currently maintaining translations into 21 languages for Betaflight Configurator: Català, Dansk, Deutsch, Español, Euskera, Français, Galego, Hrvatski, Bahasa Indonesia, Italiano, 日本語, 한국어, Latviešu, Português, Português Brasileiro, polski, Русский язык, Svenska, 简体中文, 繁體中文. We have got a team of volunteer translators who do this work, but additional translators are always welcome to share the workload, and we are keen to add additional languages. If you would like to help us with translations, you have got the following options:

  • if you help by suggesting some updates or improvements to translations in a language you are familiar with, head to crowdin and add your suggested translations there;
  • if you would like to start working on the translation for a new language, or take on responsibility for proof-reading the translation for a language you are very familiar with, please head to the Betaflight Discord chat (registration here), and join the 'translation' channel - the people in there can help you to get a new language added, or set you up as a proof reader.

General Principles

  1. Name everything well.
  2. Strike a balance between simplicity and not-repeating code.
  3. Methods that start with the word 'find' can return a null, methods that start with 'get' should not.
  4. Keep methods short - it makes it easier to test.
  5. Don't be afraid of moving code to a new file - it helps to reduce test dependencies.
  6. Avoid noise-words in variable names, like 'data' or 'info'. Think about what you're naming and name it well. Don't be afraid to rename anything.
  7. Avoid comments that describe what the code is doing, the code should describe itself. Comments are useful however for big-picture purposes and to document content of variables.
  8. If you need to document a variable do it at the declaration, don't copy the comment to the extern usage since it will lead to comment rot.
  9. Seek advice from other developers - know you can always learn more.
  10. Be professional - attempts at humor or slating existing code in the codebase itself is not helpful when you have to change/fix it.
  11. Know that there's always more than one way to do something and that code is never final - but it does have to work.

It is also advised to read about clean code, here are some useful links:

Unit Testing

Ideally, there should be tests for any new code. However, since this is a legacy codebase which was not designed to be tested this might be a bit difficult.

If you want to make changes and want to make sure it's tested then focus on the minimal set of changes required to add a test.

Tests currently live in the test folder and they use the google test framework. The tests are compiled and run natively on your development machine and not on the target platform. This allows you to develop tests and code and actually execute it to make sure it works without needing a development board or simulator.

This project could really do with some functional tests which test the behaviour of the application.

All pull requests to add/improve the testability of the code or testing methods are highly sought!

Note: Tests are written in C++ and linked with with firmware's C code. All code is also instrumented using gcov to make test coverage analysis possible.

Running The Tests.

The tests and test build system is very simple and based off the googletest example files, it will be improved in due course. From the root folder of the project simply do:

make test

You can also do:

make junittest

This will build a set of executable files in the obj/test folder, one for each *_unittest.cc file. It will stop after first compile/build error. If you want it to continue with the next test module you can use make -k test.

After they have been executed by the make invocation, you can still run them on the command line to execute the tests and to see the test report. Test reports will also be produced in form of junit XML files, if tests are built and run with the "junittest" goal. Junit report files are saved in obj/test directory and has the following naming pattern test_name_results.xml, for example: obj/test/battery_unittest_results.xml

You can also step-debug the tests in eclipse and you can use the GoogleTest test runner to make building and re-running the tests simple.

The tests are currently always compiled with debugging information enabled, there may be additional warnings, if you see any warnings please attempt to fix them and submit pull requests with the fixes.

Tests are verified and working with GCC 4.9.3

Using Git and Github

Ensure you understand the github workflow: https://guides.github.com/introduction/flow/index.html

Please keep pull requests focused on one thing only, since this makes it easier to merge and test in a timely manner.

If you need help with pull requests there are guides on github here:

https://help.github.com/articles/creating-a-pull-request/

The main flow for a contributing is as follows:

  1. Login to github, go to the betaflight repository and press fork;
  2. Then using the command line/terminal on your computer: git clone <url to YOUR fork>;
  3. cd betaflight;
  4. git checkout master;
  5. git checkout -b my-new-code;
  6. Make changes;
  7. git add <files that have changed>;
  8. git commit;
  9. git push origin my-new-code;
  10. Create pull request using github UI to merge your changes from your new branch into betaflight/master;
  11. Repeat from step 4 for new other changes.

The primary thing to remember is that separate pull requests should be created for separate branches. Never create a pull request from your master branch.

Once you have created the PR, every new commit/push in your branch will propagate from your fork into the PR in the main github/betaflight repo. Checkout another branch first if you want something else.

Push will often fail if you edit or squash commits in a branch already pushed. Never do such things after creating the PR.

Later, you can get the changes from the betaflight repo into your master branch by adding betaflight as a git remote and merging from it as follows:

  1. git remote add betaflight https://github.com/betaflight/betaflight.git
  2. git checkout master
  3. git fetch betaflight
  4. git merge betaflight/master
  5. git push origin master is an optional step that will update your fork on github

You can also perform the git commands using the git client inside Eclipse. Refer to the Eclipse git manual.

Providing Test Targets for Pull Requests

If you open a pull request for the betaflight repository that contains a change that can be tested by other users, please build a set of test firmware files for all Unified Targets and attach them to the pull request. The required firmware files can be built in zipped form ready for upload to GitHub with make unified_zip. When attaching test firmware files, you can point users to this video for instructions on how to install the test firmware: https://youtu.be/I1uN9CN30gw

Example of a pull request with test firmware attached:

Pull request with test targets

IDEs and .gitignore

The projects .gitignore already ignores certain artifacts from some IDEs, but if you'd like to use something else, you can set up git to ignore the necessary files at a global level (all git projects on the computer)

It is always good to check that you haven't done this already: git config --global --get core.excludesfile

For Linux/BSD/OSX: git config --global core.excludesfile '~/.gitignore'

For Windows: git config --global core.excludesfile '%USERPROFILE%\.gitignore'

When you git config --global --get core.excludesfile a second time, you should get a file location back.

Building a hex file locally

Given the roll out of the CLOUD BUILD platform, there is a need for those of you who want to build locally to add in the options for selecting the features you want. Surprisingly this has always been there in the form of the EXTRA_FLAGS command line parameter for make. The cloud building platform merely makes use of this parameter - extensively.

The best way to demonstrate this is to give an example:

make TARGET=STM32F411 EXTRA_FLAGS="-DUSE_GPS -DUSE_LED_STRIP"

The above would make a F411 target hex with GPS and LED_STRIP included. Happy compiling! :). For the most part simply make with the MCU target will include almost everytihing. The exception is the lower flash MCUs, e.g. F411 and F722. These do not have the flash space for everything, so even building locally you will need to specify what you would like included.

note

Please note the use of -D and the USE_. This differs from the way in which the configurator displays theses options.

These defines that we add, either on the command line or in the custom defines (in expert mode) in the configurator, are called gates, and include or exclude whole sections of code.

Custom Defaults - for Developers - DEBUGGER USE ONLY

As all targets are now MCU based (and cloud built), this poses a problem for developers in flashing and running a fully baked "hex" using the standard debugger. The board scratch space (located at the /src/main/board directory) allows developers to setup their environment like they were running a fully baked unified target.

danger

These instructions are for flashing with a debugger ONLY. Any hex created this way will not flash using the configurator.

This is by design.

Once setup, you can simply execute make with make BOARD=BETAFLIGHTF7 where BETAFLIGHTF7 is the sub directory name under /src/main/board i.e. /src/main/board/BETAFLIGHTF7.

For example if you were developing and you had the BETAFLIGHTF7 target:

  1. Create the directory /src/main/board/BETAFLIGHTF7

  2. Create files, board.c, board.h, and board.mk in the directory created (in #1 above).

  3. board.c is where you will insert the custom defaults so they are baked into the board already (and do not need to be loaded separately). This is great for debugging as they will already be present in the flash. So the board.c for BETAFLIGHTF7 is:

board.c

#include "board.h"

const char __attribute__ ((section(".custom_defaults"), used, aligned(4))) customDefaults[] =
"# Betaflight\n"
"board_name BETAFLIGHTF7\n"
"manufacturer_id FPVM\n"
"resource BEEPER 1 D15\n",
"resource MOTOR 1 B00\n",
"resource MOTOR 2 B01\n",
"resource MOTOR 3 E09\n",
"resource MOTOR 4 E11\n",
"resource PPM 1 A03\n",
"resource SONAR_TRIGGER 1 B10\n",
"resource SONAR_ECHO 1 B11\n",
"resource LED_STRIP 1 D12\n",
"resource SERIAL_TX 1 A09\n",
"resource SERIAL_TX 2 A02\n",
"resource SERIAL_TX 3 B10\n",
"resource SERIAL_TX 6 C06\n",
"resource SERIAL_RX 1 A10\n",
"resource SERIAL_RX 2 A03\n",
"resource SERIAL_RX 3 B11\n",
"resource SERIAL_RX 6 C07\n",
"resource LED 1 E00\n",
"resource SPI_SCK 1 A05\n",
"resource SPI_SCK 2 B13\n",
"resource SPI_SCK 3 C10\n",
"resource SPI_SCK 4 E02\n",
"resource SPI_MISO 1 A06\n",
"resource SPI_MISO 2 B14\n",
"resource SPI_MISO 3 C11\n",
"resource SPI_MISO 4 E05\n",
"resource SPI_MOSI 1 A07\n",
"resource SPI_MOSI 2 B15\n",
"resource SPI_MOSI 3 C12\n",
"resource SPI_MOSI 4 E06\n",
"resource CAMERA_CONTROL 1 C08\n",
"resource ADC_BATT 1 C03\n",
"resource ADC_RSSI 1 C05\n",
"resource ADC_CURR 1 C02\n",
"resource BARO_CS 1 A01\n",
"resource FLASH_CS 1 E04\n",
"resource OSD_CS 1 B12\n",
"resource GYRO_EXTI 1 D00\n",
"resource GYRO_EXTI 2 E08\n",
"resource GYRO_CS 1 A04\n",
"resource GYRO_CS 2 A15\n",
"resource USB_DETECT 1 C04\n",
"timer C08 AF3\n",
"timer E13 AF1\n",
"timer B00 AF2\n",
"timer B01 AF2\n",
"timer E09 AF1\n",
"timer E11 AF1\n",
"timer D12 AF2\n",
"timer B10 AF1\n",
"timer B11 AF1\n",
"timer C06 AF3\n",
"timer C07 AF3\n",
"timer A03 AF1\n",
"timer A02 AF3\n",
"dma ADC 1 1\n",
"dma pin C08 1\n",
"dma pin E13 1\n",
"dma pin B00 0\n",
"dma pin B01 0\n",
"dma pin E09 2\n",
"dma pin E11 1\n",
"dma pin D12 0\n",
"dma pin B10 0\n",
"dma pin B11 0\n",
"dma pin C06 0\n",
"dma pin C07 1\n",
"dma pin A03 0\n",
"feature OSD\n",
"set mag_bustype = I2C\n",
"set mag_i2c_device = 2\n",
"set baro_spi_device = 1\n",
"set blackbox_device = SPIFLASH\n",
"set current_meter = ADC\n",
"set battery_meter = ADC\n",
"set beeper_inversion = ON\n",
"set beeper_od = OFF\n",
"set max7456_spi_bus = 2\n",
"set dashboard_i2c_bus = 2\n",
"set flash_spi_bus = 4\n",
"set gyro_1_bustype = SPI\n",
"set gyro_1_spibus = 1\n",
"set gyro_1_sensor_align = CW90\n",
"set gyro_1_align_yaw = 900\n",
"set gyro_2_spibus = 3\n",
"set gyro_2_sensor_align = CW270\n",
"set gyro_2_align_yaw = 2700\n"
"\0";

NOTE: When wanting to do this for other boards, the contents is replaced with everything you need for the custom defaults configuration you want to "bake" into the board when flashed. You can get this from the unified targets repository if needed. DO NOT forget the firstline # Betaflight\n, the \0 terminator (one at the very end of the list), and the \n line termination (one at the end of each line) need to be added.

  1. board.h allows for any defines that you are working on as developers rather than specify via command line in EXTRA_FLAGS (as the cloud build system does). Therefore for board.h for the BETAFLIGHTF7 insert the following:

board.h

#define USE_GYRO_SPI_MPU6000
#define USE_ACC_SPI_MPU6000
#define USE_GYRO_SPI_MPU6500
#define USE_ACC_SPI_MPU6500
#define USE_MAX7456
#define USE_DSHOT
#define USE_SERIALRX
#define USE_SERIALRX_CRSF
#define USE_SERIALRX_GHST
#define USE_SERIALRX_SBUS
#define USE_TELEMETRY
#define USE_FLASH
#define USE_OSD
#define USE_VTX
#define USE_TELEMETRY_CRSF
#define USE_TELEMETRY_GHST
  1. board.mk allows for any additional source files, and to specify the target. The minimum requirement is the target (unless you specify this on the command line for make). So the contents of board.mk for BETAFLIGHTF7 is as follows:

board.mk

TARGET := STM32F7X2

  1. You should now be able to successfully make a debuggable version of Betaflight for the BETAFLIGHTF7 board, using the command line: make BOARD=BETAFLIGHTF7. Other command line options all remain valid also. e.g. make BOARD=BETAFLIGHTF7 TARGET=STM32F7X2 EXTRA_FLAGS="-DUSE_BATTERY_CONTINUE".

NOTE: The /src/main/board directory is GIT IGNORED. This is because it is a developers scratch space for this very purpose, so code you include will not be picked up for committing. You can create as many board "profiles" as you like in this directory.