This guide is intended for developers who wish to modify the firmware of the ODrive. As such it assumes that you know things like how to use Git, what a compiler is, etc. If that sounds scary, turn around now.
The official releases are maintained on the
master branch. However since you are a developer, you are encouraged to use the
devel branch, as it contains the latest features.
The project is under active development, so make sure to check the Changelog to keep track of updates.
The recommended tools for ODrive development are:
See below for specific installation instructions for your OS.
Depending on what you’re gonna do, you may not need all of the components.
Once you have everything, you can verify the correct installation by running:
$ arm-none-eabi-gcc --version $ arm-none-eabi-gdb --version $ openocd --version # should be 0.10.0 or later $ tup --version # should be 0.7.5 or later $ python --version # should be 3.7 or later
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa sudo apt-get update sudo apt-get install gcc-arm-embedded sudo apt-get install openocd sudo add-apt-repository ppa:jonathonf/tup && sudo apt-get update && sudo apt-get install tup
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-binutils sudo pacman -S arm-none-eabi-gdb sudo pacman -S tup
First install Homebrew. Then you can run these commands in Terminal:
brew cask install gcc-arm-embedded brew cask install osxfuse && brew install tup brew install openocd
Note: make sure these programs are not only installed but also added to your
Some instructions in this document may assume that you’re using a bash command prompt, such as the Windows 10 built-in bash or Git bash.
ARM_GCC_ROOTwhose value is the path you installed to. e.g.
C:\Program Files (x86)\GNU Tools Arm Embedded\7 2018-q2-update. This variable is used to locate include files for the c/c++ Visual Studio Code extension.
To customize the compile time parameters, copy or rename the file
Firmware/tup.config and edit the parameters in that file:
CONFIG_BOARD_VERSION: The board version you’re using. Can be
v3.5-48V, etc. Check for a label on the upper side of the ODrive to find out which version you have. Some ODrive versions don’t specify the voltage: in that case you can read the value of the main capacitors: 120uF are 48V ODrives, 470uF are 24V ODrives.
CONFIG_USB_PROTOCOL: Defines which protocol the ODrive should use on the USB interface.
native: The native ODrive protocol. Use this if you want to use the python tools in this repo.
native-stream: Like the native ODrive protocol, but the ODrive will treat the USB connection exactly as if it was a UART connection. Use this if you’re on macOS. This is necessary because macOS doesn’t grant our python tools sufficient low-level access to treat the device as the USB device that it is.
none: Disable USB. The device will still show up when plugged in but it will ignore any commands.
Note: There is a second USB interface that is always a serial port.
CONFIG_UART_PROTOCOL: Defines which protocol the ODrive should use on the UART interface (GPIO1 and GPIO2). Note that UART is only supported on ODrive v3.3 and higher.
native: The native ODrive protocol. Use this if you’re connecting the ODrive to a PC using UART and want to use the python tools to control and setup the ODrive.
ascii: The ASCII protocol. Use this option if you control the ODrive with an Arduino. The ODrive Arduino library is not yet updated to the native protocol.
none: Disable UART.
You can also modify the compile-time defaults for all
.config parameters. You will find them if you search for
SWCon connector J2 to the programmer. Note: Always plug in
make flashin the
Firmwaredirectory. Note: If you receive the error
can't find target interface/stlink-v2.cfgor similar, create and set an environment variable named
OPENOCD_SCRIPTSto the location of the openocd scripts directory.
If the flashing worked, you can connect to the board using the odrivetool.
tools/run_tests.py runs a sequence of automated tests for several firmware features as well as high power burn-in tests. Some tests only need one ODrive and one motor/encoder pair while other tests need a back-to-back test rig such as this one. In any case, to run the tests you need to provide a YAML file that lists the parameters of your test setup. An example can be found at
tools/test-rig-parallel.yaml. The programmer serial number can be found by running
Firmware/find_programmer.sh (make sure it has the latest formware from STM).
./run_tests.py --test-rig-yaml ../tools/test-rig-parallel.yaml
make gdb. This will reset and halt at program start. Now you can set breakpoints and run the program. If you know how to use gdb, you are good to go.
For working with the ODrive code you don’t need an IDE, but the open-source IDE VSCode is recommended. It is also possible to use Eclipse. If you’d like to go that route, please see the respective configuration document:
This project uses the STM32CubeMX tool to generate startup code and to ease the configuration of the peripherals. You can download it from here. All CubeMX related files are in
You will likely want the pinout for this process. It is available here.
When generating the code, STM32CubeMX will nuke everything except some special sections that they provide. These sections are marked like
USER CODE BEGIN…
USER CODE END.
We used to try to make sure all edits we made to the generated code would only go in these sections, so some code structrure may reflect that.
However over time we realized this will not be tenable, so instead we use git to rebase all changes of the generated code whenever we need to regenerate it.
We use two special branches that will help us to do this, they are
How to use these is shown in the following example.
Note: Due to how this rebasing is done, all development that changes the generated code should be done directly on
STM32CubeMX-end, and not based on
devel, then follow step 4 below to carry them over to your feature branch. If you did some changes to the generated code based from
devel, you need to cherry pick just those changes over to
git checkout STM32CubeMX-start
Project -> Generate code.
git config --local core.autocrlf input- This will tell git that all files should be checked in with LF endings (CubeMX generates CRLF endings).
git diff- Ignore the pile of line ending warnings.
git commit -am "Run STM32CubeMX v1.21"- Replace with actual version of CubeMX
git statusshould include “nothing to commit, working tree clean”
Project -> Generate code)
git diff- Check that the introduced changes are as expected
git checkout STM32CubeMX-end
git rebase STM32CubeMX-start
Simply merge the new state at
STM32CubeMX-end into your feature branch.
git checkout your-feature
git merge STM32CubeMX-end
STM32CubeMX-endbranches on your fork.
LIBUSB_ERROR_IOwhen flashing with the STLink/v2
Problem: when I try to flash the ODrive with the STLink using
make flash I get this error:
Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 2000 kHz adapter_nsrst_delay: 100 none separate Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : clock speed 1800 kHz Error: libusb_open() failed with LIBUSB_ERROR_IO Error: open failed in procedure 'init' in procedure 'ocd_bouncer'
Solution: This happens from time to time.
All *.md files in the
docs/ directory of the master branch are served up by GitHub Pages on this domain.
To run the docs server locally:
cd docs gem install bundler bundle install --path ruby-bundle bundle exec jekyll serve --host=0.0.0.0
We use GitHub Releases to provide firmware releases.
The cortex M4F processor has hardware single precision float unit. However double precision operations are not accelerated, and hence should be avoided. The following regex is helpful for cleaning out double constants:
In general the project uses the Google C++ Style Guide, except that the default indendtation is 4 spaces, and that the 80 character limit is not very strictly enforced, merely encouraged.