We’re happy to announce that release 2025.09 is now available. This update includes Python 3.13 support and improved battery voltage compensation, along with enhanced trajectory control capabilities. The release also features substantial stability and architectural work that lays the groundwork for upcoming features and products. Thanks to our community contributors for their valuable additions to this release.
Major changes
Python 3.13 support Added support for Python 3.13, with preparations already in place to ensure faster compatibility when Python 3.14 releases.
Improved battery voltage compensation Enhanced voltage compensation for Crazyflie 2.1, 2.1+, and 2.1 with thrust upgrade kit provides more consistent flight performance across battery discharge cycles. Crazyflie Brushless battery voltage compensation coming soon. Thanks to @Rather1337 for this contribution.
Manual flight setpoint packet New generic commander packet type for manual flight that allows dynamic switching between Angle and Rate modes for roll and pitch without re-flashing the firmware.
Fully relative trajectories Trajectories can now be initiated relative to the drone’s current yaw, not just position. This enables fully relative trajectory execution where subsequent trajectories maintain the drone’s current orientation. Thanks to @johnnwallace for this contribution.
Modular deck discovery architecture Replaced OneWire-only deck discovery with a modular backend system that supports multiple discovery protocols. This enables future deck communication methods while maintaining full backward compatibility with existing decks.
Debugging the Crazyflie using the debug-adapter kit gives you direct access to the STM32 with a hardware debugger. It makes it possible to pause execution, step through code, and inspect what’s happening in real time.
Even if you’re working mostly at a higher level, having this kind of visibility can be a huge time-saver when something unexpected happens. It’s a tool I use frequently when tracking down firmware issues or verifying low-level behavior.
We already have documentation for debugging the STM32 on the Crazyflie using ST-LINK and VS Code, but there are still a few missing pieces; like how to use J-Link, how to debug other platforms (like the Crazyflie 2.1 Brushless), and how enabling debug builds can help.
Debug Build
If you’re debugging and your breakpoints aren’t landing where you expect, or stepping seems unpredictable, or variables aren’t visible, it’s probably because the firmware was built with compiler optimizations enabled. When you select a debug build, the build system disables optimization by setting the compiler flag -O0, which preserves line-by-line correspondence between source code and machine instructions. This makes stepping and inspecting variables much more reliable.
To enable a debug build, you need to set the CONFIG_DEBUG option in your Kconfig configuration. You can do this, for example, by running make menuconfig in a terminal. Then navigate to Build and debug options and select Enable debug build. After changing Kconfig options, re-run make to rebuild the firmware with the new configuration.
Enabling debug build Kconfig option through menuconfig
VS Code Debug Configuration
With debug builds enabled, you’ll get more predictable stepping and reliable breakpoints. The next step is setting up your debugger. Below is a launch.json configuration for VS Code that supports both ST-Link and J-Link, and works with Crazyflie 2.x and the 2.1 Brushless.
To use this setup with a different platform, like the Flapper, just change the executable field to point to the correct .elf file. By default, starting a debug session in VS Code will erase and reflash the firmware, so make sure the firmware is built beforehand. If you need to attach to a running target without flashing, you’ll need to modify the launch.json to skip loading the binary.
With the Swedish summer upon us, things are more calm at Bitcraze. The summer is usually a time for us to look a bit more at fixing infrastructure and other things that we do not have time to work on the rest of the year. One of the things I have been looking at improving lately is the state of our Python projects.
We currently use Python as the default language for everything we do on PC. This includes the Crazyflie lib, Client and other tools for our ecosystem. Over the years the state of the Python projects have greatly evolved. It started in ~2011 with almost no project management at all; just Python files. Then we switched to setup.py/pip support. Recently the Crazyflie client got the pyproject.toml treatment. Now that most Linux distributions prevent pip install-ing packages we need to juggle with venvs in order to use or develop in Python.
In essence, Python started with an easy to use language but has now become quite complex and hard to handle. Things become even more complicated when we take into account CI in Github actions that have to test that our projects actually work with all supported version of Python on Linux/Mac/Windows.
A bit of Rust (tooling) in our Python
As you might have gathered from our previous blog posts over the years, we like Rust quite a bit at Bitcraze and hope to use it more in our products moving forward. One of the great parts of Rust is the quality of the tooling and of the compiler feedback. Cargo as a project management tool helps a lot working with projects in a comfortable and repeatable way.
This is why we are now quite interested in using uv going forward as an official tool to work with the Bitcraze Python projects. uv can replace both venv and pip and makes working with a Python project as easy as working on a Rust one with cargo. It is also very fast and efficient since it is written in … Rust of course :-).
We are also looking at switching from Flake8 to Ruff and Ty for linting and type checking respectively. These two tools, from the same developer as uv are very fast and give very high quality error messages and warnings – this should make it much easier to maintain good code quality.
These changes would mostly be on our documentation and development side. The resulting projects are still compatible with pip and can still be used as they where used before. However we would make sure the projects can be efficiently used with uv.
Example
The Crazyflie client is currently already fully able to run with uv since it already uses the ‘new’ pyproject.toml project config file. So working with the project, from within the project folder, would look like that:
crazyflie-clients-python $ uv run cfclient # Run the Crazyflie client GUI
(...)
crazyflie-clients-python $ uv run ruff check # Check the code, runs in ~100ms!
All checks passed!
crazyflie-clients-python $ uv run pre-commit
Built cfclient @ file:///(...)/crazyflie-clients-python
Uninstalled 1 package in 0.97ms
░░░░░░░░░░░░░░░░░░░░ [0/1] Installing wheels...
Installed 1 package in 4ms
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to /home/arnaud/.cache/pre-commit/patch1750684440-121836.
flake8...............................................(no files to check)Skipped
[INFO] Restored changes from /home/arnaud/.cache/pre-commit/patch1750684440-121836.Code language:Bash(bash)
This last command is a great example of the usefulness of uv: currently one need to install pre-commit on a virtual environment, enter it, and run pre-commit in the project. With uv is just works out of the box. In the back of course, pre-commit is installed in a virtual environment in the project folder. But this is all done automatically.
Finally we will also easily be able to test multiple versions of Python:
crazyflie-clients-python $ uv run --python 3.10 pre-commit
Using CPython 3.10.18 interpreter at: /home/linuxbrew/.linuxbrew/opt/python@3.10/bin/python3.10
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Built cfclient @ file:///(...)/crazyflie-clients-python
Updated https://github.com/bitcraze/crazyflie-lib-python.git (3a35d22026c2ed8251b821e4f5b10e67091f811f)
Built cflib @ git+https://github.com/bitcraze/crazyflie-lib-python.git@3a35d22026c2ed8251b821e4f5b10e67091f811f
░░░░░░░░░░░░░░░░░░░░ [0/32] Installing wheels... warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
Installed 32 packages in699ms
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to /home/arnaud/.cache/pre-commit/patch1750684632-123219.
[INFO] Installing environment for https://github.com/PyCQA/flake8.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
flake8...............................................(no files to check)Skipped
[INFO] Restored changes from /home/arnaud/.cache/pre-commit/patch1750684632-123219.Code language:JavaScript(javascript)
And, for the end user, uvx also simplify running the client:
$ uvx cfclient # Pulls and run cfclient from Pypi
(...)
$ uvx --from cfclient cfloader
Built cfclient
Installed 22 packages in 164ms
==============================
CrazyLoader Flash Utility
==============================
Usage: /(...)/.cache/uv/archive-v0/_OZwn5_zGeTE-qFoK_kEG/bin/cfloader [CRTP options] <action> [parameters]
The CRTP options are described above
Crazyload option:
info : Print the info of the bootloader and quit.
Will let the target in bootloader mode
reset : Reset the device in firmware mode
flash <file> [targets] : flash the <img> binary file from the first
possible page in flash and reset to firmware
mode.Code language:HTML, XML(xml)
This last command would likely be added to all our firmware Makefiles to be used when calling make cload to flash the Crazyflie.
Feedback?
This currently does seem like a good idea to us. If you have any feedback or ideas on how to handle Python projects in a better way we are very interested to hear them. Like I mentioned, the summer is kind of a ‘clean up’ time for us so this is when we have time to look at this kind of things.
For quite some time now we have had mobile apps that can be used to control the Crazyflie 2.x quadcopter. There is one iOS and one Android app available. There used to be a prototype of a Windows phone app but it has not survived the demise of Windows on phone (fun fact, the windows phone app can be compiled to run on XBox, however there is no USB access in there so it is quite useless). In this blog post I want to talk about the state of the apps and a possible future for them. As usual with me, the future should include a bit ot Rust :-).
Android app
The Android app is the oldest of the mobile apps, it has been created originally to be used with a Crazyradio conncted to an Android phone over USB. Then, when we released Crazyflie 2.0 with Bluetooth Low Energy, BLE was added to the app to be able to Connect to a Crazyflie without radio attached.
Over the years, the Android app has mainly been maintained by FredG, one of the very first Crazyflie contributors. The app supports controlling Crazyflie using touch-control as well as using an Android-supported Gamepad. It also has support for showing the Crazyflie console, controlling some decks and assisted flight using the flow deck.
It also supports updating the Crazyflie firmware using a Crazyradio connected on USB. This functionality is unfortunately broken since we altered the update process when changing the Crazyflie bluetooth stack last year.
The Android app is also working on Chromebook. This means that it can be used to fly the Crazyflie form a chromebook using Crazyradio of BLE. This is one of the only way to control the Crazyflie from Bluetooth on a laptop.
iOS app
The iOS app is newer and much simpler. It has had a couple of really good contribution over the years but overall it has seen much less development than the Android app. I have tried to keep it up and working but nothing more so far.
The iOS app was released when we made the Crazyflie 2.0. Since iOS does not let us communicate with USB devices, it can only work using Bluetooth Low Energy. It can control the Crazyflie using touch control as well as motion control using the IPhone gyroscope.
The iOS app also had support for updating the Crazyflie over Bluetooth, however, like for the Android app this is now broken and it has been removed in a recent release. I hope to be able to add it back soon.
With the advent of the Apple Silicon Mac, the iOS app is now also a Mac app. Like for the Android app on Chromebook, this gives the unique ability to communicate with the Crazyflie over Bluetooth from a computer. However it still has no USB support for Crazyradio and until we implement Gamepad support there is no way to control the Crazyflie from a Mac using the app.
The future
Some of the biggest issues for the development of the mobile app so far has been a lack of specification and the difficulty of re-implementing Crazyflie protocol for each app.
For the former, the apps have been created at a time where flying the Crazyflie manually was one of the major use-case. Nowadays, it is much more common to fly autonomously. This means that the apps should be able to do more to be really useful. Manual flight might still be needed to test the Crazyflie or just to play around. But the app could also have a much greater use for things like assisting in setting up positioning system or swarms. We are still not sure what would be needed or useful yet so if you have any ideas please tell us here as a comment or on Github discussions.
For the later, the difficulty of re-implementing the Crazyflie lib, this is something we have had problem with on multiple front. For example this is also a problem for ROS support and for Crazyswarm. The main problem is that the official Crazyflie lib is implemented in Python, and Python happens to not be a good choice for most cases due to limited portability and performance. One solution we have been imagining and working towards is to implement the Cazyflie lib in Rust and then implement binding for Python, C/C++, Java and Swift. This will cover our current python client, ROS, Crazyswarm as well as all the mobile app. It should allow to get much more done much more easily on mobile, since we will not have to start by re-implementing the wheel each time and will be able to focus on actual functionalities.
One idea, would be to start now with implementing the Crazyflie update algorithm in Rust and to use is from python and the mobile apps. This is a good first target, since this is a non-trivial really annoying piece of code in all languages, and it is also one that must be as bug-free as possible. So having a single implementation that is well tested and can be used everywhere would be very beneficial to the Crazyflie ecosystem.
I hope I managed to convey where we are and where we want to go with the mobile app. If you have any feedback please tell us about it.
There has been some extended work lately related to the Lighthouse positioning system. The goal of this work is to expand the maximum base station number to 16 enabling the system to cover larger areas and support more complex use cases.
Previous work
One previous attempt to enable multiple base stations using the current lighthouse deck left us with a highly untested “hacky” solution. After flashing the Crazyflie with the proper firmware, this solution requires to strategically position the base stations so that no more than 4 are visible at any given time. Then, the geometry estimation that is normally carried out by the cfclient has to be done through the multi_bs_geometry_estimation.py script in the cflib.
Last year we developed a prototype deck, used in last year’s holiday video, that had a bigger FPGA to receive the lighthouse signals and an esp32 to be able to decode and filter most of the lighthouse pulses onboard the deck. This approach ended up not working for us since it still included the moderately-hard-to-develop FPGA and the algorithm we implemented in the esp32 to identify lighthouse V2 pulses happened to be not fast enough to handle enough base stations.
Current limitations
A key factor that currently limits the maximum number of usable base stations is the Lighthouse deck which can’t handle more than 4 visible base stations at a time. Additionally, the Crazyflie’s STM32 is doing all the filtering and 16 base stations generate so much data that it would exceed the compute and memory budget we have in the Crazyflie. This was one of the main reasons to add a MCU in the deck of our last-year prototype.
Ongoing progress
The last couple of months we have redesigned a new LH-16 deck containing a RP2350 microcontroller so that part of the computation and filtering can take place on the deck, rather than on the Crazyflie. With a deck like this, it should be possible to receive large amounts of data from the base stations and filter some of it out to finally estimate the Crazyflie’s position in the Crazyflie’s STM32.
This deck has been designed to run a firmware developed by Said Alvarado-Marin from the AIO team at Inria in Paris. This firmware is able to acquire, decode and identify the FM1-encoded LFSR data stream we get from the base stations without the help of an FPGA or a big look-up table. This allows to greatly simplify the hardware and software by using only one microcontroller on the deck.
We are currently bringing-up the prototype and hope to be able to soon fly in our lab with 16 base stations. We will also be looking at making a standalone lighthouse receiver for other robots and applications. For the curious: the board under the deck in the picture in a debug board that contains everything we might need for making a standalone receiver plus everything needed to bring-up and debug the deck until we have it ready to fly.
We’re happy to announce that release 2025.02 is now available. This update includes fixes and improvements for the Crazyflie 2.1 Brushless, along with stability enhancements for the AI-deck.
The Crazyflie 2.1 Brushless with propeller guards on a prototype charging padThe optimized brushless motor
Finalizing the integration of the Crazyflie 2.1 Brushless into our software ecosystem and expanding its documentation were key steps in preparing for its launch. These efforts ensure compatibility, improve the user experience, and make the platform more accessible to the community. We’re looking forward to a smooth launch and to seeing how the community will utilize the new platform!
This year, we introduced updates to the Crazyflie 2.1 kit, making the 47-17 propellers the new default and including an improved battery. These upgrades enhance flight performance and endurance, culminating in the release of the Crazyflie 2.1+—an optimized iteration of our established platform.
And don’t forget the developer meetings, where we shared some more behind the scenes information and collected invaluable feedback from the community.
We also released a new edition of our research compilation video, showcasing some of the coolest projects from 2023 and 2024 that highlight the versatility and impact of the Crazyflie platform in research.
Team
In the past year, Bitcraze saw significant changes within the team. in February, Rik rejoined the team. Tove started at Bitcraze in April. Mandy, with whom we’ve already worked extensively over the years, joined as our production representative in Shenzen. At the end of the year, we said goodbye to Kimberly, whose contributions will be deeply missed. Additionally, we had Björn with us for a few months, working on his master’s thesis on fault detection, and Joe continued his industrial postdoc at Bitcraze that began in December 2023. Looking ahead, Bitcraze is hiring for two new roles: a Technical Sales Lead and a Technical Success Engineer, to support our ongoing projects and customer collaborations.
Midsummer lunch with the teamChristmas-themed Bitcraze office
As we close the chapter on 2024, we’re proud of the progress we’ve made, the connections we’ve strengthened, and the milestones we’ve reached. With exciting launches, new faces on the team, and continued collaboration with our community, we’re ready to soar to even greater heights in 2025. Thank you for being part of our journey!
We are excited to announce that we are working on several new link performance metrics for the Crazyflie that will simplify the troubleshooting of communication issues. Until now, users have had access to very limited information about communication links, relying primarily on a “link quality” statistic based on packet retries (when we have to re-send data) and an RSSI channel scan. Our nightly tests have been limited to basic bandwidth and latency testing. With this update, we aim to expose richer data that not only enables users to make more informed decisions regarding communication links but also enhances the effectiveness of our nightly testing process. In this blog post, we will explore the new metrics, the rationale behind their introduction, and how they will improve your interaction with the Crazyflie. Additionally, we will be holding a developer meeting on Wednesday November 13th to discuss these updates in more detail, and we encourage you to join us!
“Link Quality”—All or Nothing
Until now, users of the Crazyflie have had access to a single link quality metric. Implemented in the Python library, this metric is based on packet retries—instances when data packets need to be re-sent due to communication issues. This metric indicates that for every retry, the link quality drops by 10%, with a maximum of 3 retries allowed. As a result, the link quality score usually ranges from 70% to 100%, with a drop to 0% when communication is completely lost. However, as packet loss occurs, users often experience a steep decline, commonly seeing 100% when packets are successfully acknowledged or dropping to 0% when communication is completely lost.
Client representation of link quality; no link, yes link
The current link quality metric has served as a basic indicator but provides limited insight, often making it difficult to gauge communication reliability accurately. Recognizing these limitations, we’re introducing several new link performance metrics to the Crazyflie Python library, designed to provide a far more detailed and actionable view of communication performance.
What’s Coming in the Upcoming Update
The first metric we are adding is latency. We measure the full link latency, capturing the round-trip time through the library, to the Crazyflie, and back. This latency measurement is link-independent, meaning it applies to both radio and USB connections. The latency metric exposed to users will reflect the 95th percentile—a commonly used measure for capturing typical latency under normal conditions.
Next are several metrics that (currently) only support the radio link. For these, we distinguish between uplink (from the radio to the Crazyflie) and downlink (from the Crazyflie to the radio).
The first is packet rate, which simply measures the number of packets sent and received per second.
More interestingly, we are introducing a link congestion metric. Whenever there is no data to send, both the radio and the Crazyflie send “null” packets. By calculating the ratio of null packets to the total packets sent or received, we can estimate congestion. This is particularly useful for users who rely heavily on logging parameters or, for example, stream mocap positioning data to the Crazyflie.
The Received Signal Strength Indicator (RSSI) measures the quality of signal reception. Unlike our current “link quality” metric, we hope that a poor RSSI will serve as an early warning signal for potential communication loss. While RSSI tracking has been possible before with the channel scan example, this update will monitor RSSI in the library by default, and expose it to the user. The nRF firmware will also be updated to report RSSI by default. Currently, we only receive uplink RSSI, that is, RSSI measured on the Crazyflie side.
Work in progress client representation of new link performance metrics
We’ve already found these new metrics invaluable at Bitcraze. While we have, of course, measured various parameters throughout development, it was easy to lose track of the precise status of the communication stack. In the past, we relied more on general impressions of performance, but with these new metrics, we’ve gained a clearer picture. They’ve already shed light on areas like swarm latency, helping us fine-tune and understand performance far better than before.
You can follow progress on GitHub, and we invite you to try out these metrics for yourself. If there’s anything you feel is missing, or if you have feedback on what would make these tools even more helpful, we’d love to hear from you. Hit us up over on GitHub or join the developer meeting on Wednesday the 13th of November (see the join information on discussions).
We are happy to announce that release 2024.10 is now available! Special thanks to our community contributors for their valuable input and code contributions in this release!
As you might expect, we use the Crazyflie python client a lot at Bitcraze. The client has a lot of features, ranging from setting up LPS/Lighthouse systems to turning on/off the headlight LEDs on the LED-ring deck. But some of the features we use the most is probably the console view as well as the logging/parameter subsystems. A lot of the time we modify firmware, flash it and want to tweak (via parameters) or to check if the changes are working as expected (via the console or logging). Then switching from the terminal, where we build/flash, to the Qt UI in the Crazyflie python client can be a hassle if you just want to do something quick. It would be great to be able to log/set variables directly from the terminal, well now you can!
Meet the Crazyflie command-line client, a fun Friday project I worked on a while back. The CLI is written in Rust and was made possible thanks to a previous fun Friday project by Arnaud on the Rust Crazyflie link/lib, which has now moved to the official Bitcraze repositories. The CLI project is still very limited, but has some basic functionality:
Scan for Crazyflies and pre-select one to interact with
List loggable variables, create log configurations and print their value
List parameters and get/set them
Show the Crazyflie console
Last week the first version, v0.1.0, was released on crates.io. So if you have Rust set up on your computer and want to test it out then all you need to do is to type “cargo install cfcli“. The CLI still only has some basic functionality, but hopefully it can be expanded in the future with more useful things! Feel free to leave any issues or comments you might have on the Github page.