ICRA Yokohama

From the beginning of the company, we’ve always loved to join in at conferences. Only at a conference do you get the opportunity to show our products, meet our users or other tech-oriented people, learn about what others are doing, and let’s not forget the chance to discover a new place!

This year, we’ll be present at ICRA Yokohama – it’s in just 3 weeks. We’ll have a booth there (IC085 if you’re looking for us). We’ll be showing our autonomous demo with a twist just like we have shown last time, so please check the event page. This demo is extremely impressive and we’ve been improving on it each time we’ve shown it – beginning in our latest Japan trip and lastly at the last ICRA too. What’s new?

We’re really excited to be showing that and receive feedback, but also in hearing about what our users have been doing. ICRA is always a perfect place to catch up on all the amazing papers and publications featuring our hardware, and we couldn’t be prouder of all the cool stuff we’ve seen so far. We’re so proud, in fact, that we want to be able to show off! So, if you have a paper or a publication featured at ICRA, let us know – you can write us an email at, leave a comment below this post, or pass by our booth.

In fact, we’re prepared to make a deal. If you have a nice poster featuring our products and don’t know what to do with it once you’ve presented it, pass by our booth! We’re ready to swap them for something extra special. We plan to have a “hall of fame” at the office featuring your awesome work – in fact, it’s an idea we had last ICRA when someone just offered us their posters. Now, we’d like to cover our walls with them!

The corridor leading to the kitchen – we have space to show off the awesomeness!

So, whether you’re a seasoned conference-goer or a first-time attendee, don’t hesitate to wsing by our booth, say hello, and discover our newest demo! We hope to see you there.

Dev meeting

Next developer meeting is going to be on the 8th of May – we traditionally have a dev meeting every first Wednesday of the month, but this time it happens to be on the 1st of May which is a holiday here in Sweden. So already prepare your calendar for the 8th of May at 15.00 CET, and stay tuned for more info on which topic we’ll talk about!

Crazyflies back in stock !

You may have noticed that the Crazyflies have been out of stock for some time now. After some adventures, we are now fully back in stock with most of our bundles and products available in the shop!

This week we have a guest blogpost by Christian Llanes, a Robotics PhD of from Formal Methods & Autonomous Control of Transportation Systems Lab of the Georgia Institute of Technology. Enjoy!

Why do we need simulators?

Simulators are one of the most important tools used in robotics research. They usually are designed for different purposes with different levels of complexity. For example, simulators with low computational overhead that are parallelizable are mainly used for either training reinforcement learning algorithms or Monte Carlo sampling for verification of task completion in a nondeterministic environment. Some simulators also use rendering engines for the graphical display of models and the environment or when cameras are intended to be used in the robotics platform. Simulation is also useful for the development and deployment of new robotics firmware features where the firmware is compiled on a test machine and run in the loop with a simulated sensor suite. This simulator configuration is known as software-in-the-loop (SITL) because the vehicle firmware is intended to be run in the loop with the simulated vehicle physics and/or rendering engine. This feature is supported by autopilot suites such as PX4ArduPilotCogniPilot, and BetaFlight. This feature is not officially supported yet for Crazyflies because it requires a large overhaul of the firmware to be able to compile on a desktop machine and interact with different simulators such as Gazebo, Webots, PyBullet, CoppeliaSim, Isaac Sim, or Unreal Engine.


Last summer I began working with Crazyflies and noticed this Crazyflie simulator gap. I stumbled on a community-developed project for Crazyflie SITL called sim_cf. This project is exactly what I was looking for. However, the firmware used by the project is from July 2019 and the official firmware has had over 2000 commits made since then. The project also uses ROS 1, Gazebo Classic, and doesn’t support the Crazyflie Python library (CFLib). Using this project as a starting point I set out to develop CrazySim–a Crazyflie SITL project that doesn’t require ROS, uses Gazebo Sim, and supports connectivity through CFLib. Using CFLib we can connect the simulator to external software such as Crazyswarm2 or the Crazyflie ground station client. Users test their control algorithms in the external software using the simulator interface before deploying to real flight hardware.

An example of offboard model predictive control design and deployment workflow using CrazySim.

Using the Crazyflie Client for PID Tuning

We have also provided a modified Crazyflie client for CrazySim support. The Crazyflie client is a cool tool for testing a single drone in hardware. We can perform command based flight control, look at real time plots, save log data, and tune PID values in real time. The PID values are typically tuned for an out of the box Crazyflie. However, when we modify the Crazyflie and add extra weight through batteries, decks, and upgraded thrust motors then the behavior of the Crazyflie will change. If a user wants to tune a custom Crazyflie setup, then they can add additional models in this folder with their own motor and mass properties. Then they just need to add it to the list of supported models in either of the launch scripts. There is already an example model for the thrust upgrade bundle. Documentation for installing the custom client can be found here.

PID tuning a simulated Crazyflie using CrazySim on the Crazyflie PC client.


We can now connect to the simulated Crazyflie firmware using CFLib. Therefore, we can set up a ROS 2 interface through Crazyswarm2 for swarm command and control through ROS 2 topics and services. To do this we first startup the drones using any of the launch scripts.

bash tools/crazyflie-simulation/simulator_files/gazebo/launch/ -n 16 -m crazyflie

Then, we bring up Crazyswarm2 after setting up the configuration file for the number of drones chosen.

ros2 launch crazyflie backend:=cflib

We demonstrate an example of how we can control a swarm of drones using Crazyswarm2 GoTo service commands.

Crazyswarm2 GoTo service commands using CrazySim.

ICRA 2024

CrazySim is also being presented as a paper at the 2024 IEEE International Conference on Robotics and Automation in Yokohama, Japan. If you are attending this conference and are interested in this work, then I invite you to my presentation and let me know that you are coming from this blog post after. For the paper, I created a multi agent decentralized model predictive controller (MPC) case study on ROS 2 to demonstrate the CrazySim simulation to hardware deployment workflow. Simulating larger swarms with MPC may require a high performance computer. The simulations in this work were performed on an AMD Ryzen 9 5950X desktop processor.

Model predictive control case study for ICRA 2024 paper.


  1. CrazySim
  2. Modified Crazyflie client

Other Crazyflie SITL projects:

  1. sim_cf
  2. sim_cf2 blog post
  3. LambdaFlight blog post

Today, we’d like to take the opportunity to spotlight a feature that’s been in our code base for some time, yet hasn’t been the subject of a blog post: the Python bindings for our Crazyflie firmware. You may have noticed it mentioned in previous blog posts, and now we’ll delve into more detail about what it is, how we and others are utilizing it, and what its future holds.

Schematized visualization of code within the Crazyflie

What are the Python bindings?

Language bindings, in essence, are libraries that encapsulate chunks of code, enabling one programming language to interface with another. For instance, consider the project Zenoh. Its core library is crafted in Rust, but it offers bindings/wrappings for numerous other languages like Python, C/C++, and so on. This allows Zenoh’s API to be utilized in scripts or executables written in those languages. This approach significantly broadens the functionality without necessitating the rewriting of code across multiple programs. A case in point from the realm of robotics is ROS(1), which initially created all of their APIs for different languages from scratch—a maintenance nightmare. To address this, for ROS 2, they developed the primary functionality entirely in C and provided wrappers for all other programming languages. This strategy eliminates the need to ‘reinvent the wheel’ with each iteration.

Rather than redeveloping the firmware in Python, our esteemed collaborators Wolfgang Hönig and James Preiss took a pragmatic approach. They selected parts of the Crazyflie firmware and wrapped them for Python use. You can see the process in this ticket. This was a crucial step for the simulation of the original Crazyswarm (ROS1) project and was continued for its use in the Crazyswarm2 project, which is based on ROS 2. They opted for SWIG, a tool specifically designed to wrap C or C++ programs for use with higher-level target languages. This includes not only Python, but also C#, GO, Javascript, and more, making it the clear choice for implementing those bindings at the time. We also strongly recommend checking out a previous blogpost by Simon D. Levy, who used Haskell to wrap the C-based Crazyflie Firmware for C++.

Where are the Python bindings being used?

As previously mentioned, the Crazyswarm1 & 2 projects heavily utilize Python bindings for testing key components of the firmware (such as the high-level commander, planner, and controller) and for a (hybrid) software-in-the-loop simulation. During the project’s installation, these Python bindings must be compiled so they can be used during simulation. This approach allows users to first test their trajectories in a simulated environment before deploying them on actual Crazyflies. The advantage is that minimal or no modifications are required to achieve the same results. While simulations do not perfectly mirror real-world conditions, they are beneficial because they operate with the same controller as the one used on the Crazyflie itself. In our own Crazyflie simulation in Webots, it’s also possible to use these same bindings in the simulator by following these instructions.

Three controllers (PID, Mellinger, and Brescianini), intra-drone collision avoidance, and the high-level commander planner have all been converted into Python bindings. Recently, we’ve added a new component: the Extended Kalman Filter (EKF). This addition is ideal as it allows us to test the filter with recorded data from a real Crazyflie and experiment with different measurement models. As we discussed in a previous blogpost, estimators are complex due to their dependence on chance and environmental factors. It’s beneficial for developers to have more control over the inputs and expected outputs. However, the EKF is deeply integrated into the interconnected processes within the Crazyflie Firmware. After a significant refactoring effort, these were added to the bindings by creating an EKF emulator (see this PR). This enabled Kristoffer to further enhance the TDOA outlier filter for the Crazyflie by emulating the full process of the EKF, including IMU data.

In addition to SITL simulation and EKF development, Python bindings are also invaluable for continuous integration. They enable comprehensive testing that encompasses not just isolated code snippets, but entire processes. For instance, if there’s a recording of a Crazyflie flight complete with sensor data (such as flow, height, and IMU data), and it’s supplemented with a recorded ground truth (from lighthouse/mocap), this sensor data can be fed into the EKF Python binding. We can then compare the outputted pose with the ground truth to verify accuracy. The same principle applies to the controllers. Consequently, if any changes are made to the firmware that affect these crucial aspects of Crazyflie flight, these tests can readily detect them.

If you like to try the python bindings tests for yourself, clone the Crazyflie-firmware repo and build/install the python bindings via these instructions. Make sure you are in the root of the repository and run: python3 -m pytest test_python/. Mind that you might need to put the bindings in the same path with export PYTHONPATH=<PATH_TO_>/crazyflie-firmware/build:$PYTHONPATH (please see this open ticket)

The next steps of the python bindings

We’ve seen how Python bindings have proven to be extremely useful, and we’re keen to further expand their application. At present, only the Loco positioning system has been incorporated into the EKF part of the Python bindings. Work is now underway to enable this for the Lighthouse system (see this draft PR). Incorporating the Lighthouse system will be somewhat more complex, but fortunately, much of the groundwork has already been laid, so we hope it won’t be too challenging. However, we have encountered issues when using the controller bindings with simulation (see this open ticket). It appears that some hardware-specific timing has been hardcoded throughout the PID controller in particular. Therefore, work needs to be done to separate the hardware abstraction from the code, necessitating additional refactoring work for the controller.

Recent projects like Sim_CF2 (see this blogpost) and Crazysim (see this discussion thread) have successfully compiled the Crazyflie firmware to run as a standalone node on a computer. This allows users to connect it to the Crazyflie Python library as if it were an actual Crazyflie. This full Software-In-The-Loop (SITL) functionality, already possible with autopilot suites like PX4 and Ardupilot, is something we at Bitcraze are eager to implement as well. However, considering the extensive work required by the aforementioned SITL projects to truly separate the hardware abstraction layer from the codebase, we anticipate that refactoring the entire firmware will be a substantial task. We’re excited to see what we can achieve in this area.

Indeed, even with a more comprehensive Software-In-The-Loop (SITL) solution, there’s no reason to completely abandon Python bindings. For developments requiring more input/output control—such as the creation of a new controller or an addition to the Extended Kalman Filter (EKF)—it’s beneficial to start with just that portion of the firmware code. Python bindings and a SITL build can coexist, each offering its own advantages and disadvantages for different stages of the development process. By leveraging the tools at our disposal, we can minimize the risk of damaging Crazyflies during development. Let’s continue to make the most of these valuable resources!

There is a new release of the firmware, version 2024.2. The main change, and almost only change, in this release, is the Bluetooth stack that was updated from the Nordic’s semiconductor S110 to S130, which affects the firmware on the NRF51 on the Crazyflie. This was mainly done to be able to pass the listing requirement on Bluetooth SIG, but it will also have beneficial technical effects on the Crazyflie radio communication state of affairs.

The new stack and bootloader are distributed in the normal release .zip, which means that it can be updated from the client as normal. Please note that the latest lib and clients are required as we have had to implement new procedures to flash the bootloader and stack.

First of all, let’s define what is a soft device. Nordic semiconductor radio chips are awesome in the way that the radio hardware is fully documented, this means that we can implement our own radio protocols but we would also be able to implement our own Bluetooth stack (I have attempted that a long time ago with some success, the nRF5 radio hardware is really powerful and can be set up to do much of the work!). However, backing your own Bluetooth stack would require passing a full suite of validation at the Bluetooth SIG to prove the stack conform to specification. In order to avoid that, the usual strategy is to buy a Bluetooth device and to talk to it over UART. What Nordic did is to implement a “Softdevice”, a binary blob that runs in the same CPU as the user application and that talks to the application using software interrupt. This keeps the application completely separated from the Bluetooth stack and so means that we get the benefits of a pre-qualified Bluetooth stack that has already been tested and approved.

Currently, we have ported the bootloader and the nrf firmware to the new S130 stack. This opens a lot of potential benefits for the future:

  • The new stack should be at least 6 times faster than the old one. This makes implementing BLE communication for the Crazyflie to a PC/Chromebook much more appealing and should allow to make the existing mobile client more full features.
  • We are now able to update the bootloader, so we can make a new improved version of it in the future (ie. with safe link, swarm optimization, much faster Bluetooth boot loading….)
  • The new stack supports device and host mode. So things like pairing a gamepad with the Crazyflie becomes a technical possibility! (actual implementation is left as an exercise for the contributor ;-).

One very important thing to note is that working on the bootloader requires a debugger: if you flash a bugged radio bootloader you need a SWD debug probe to be able to fix your Crazyflie. The bootloader+softdevice flashing procedure is very safe, as long as you flash a working firmware.

This change should open quite new exciting possibilities. It will be interesting to see what we can achieve with BLE and updated bootloaders in the future. Please note that we had to make a change to both the Crazyflie python library and the CFclient in order to flash this new firmware so make sure that you update those as well to try out this new release.

Developer meeting

The next developer meeting will be on the 6th of March 2024, we will talk about the Crazyflie Supervisor subsystem… We have made some changes to the supervisor recently, and we will continue working more on it in the next couple of weeks mostly preparing for the arrival of the Brushless Crazyflie. We will talk about the current state and what we are working on. Follow the thread on Bitcraze Discussions to be up to date on how to join!

You may have noticed that the HQ propellers, which are a part of the thrust upgrade bundle, have been out of stock for quite some time now. I know that many of you are relying on those propellers for the additional 20 grams of thrust they allow, so I have some news – some good, some bad.

Let’s start with the bad news: our partner and manufacturer, unfortunately, faced some problems with the mold they were using for these propellers- we prepared to face the fact that having our thrust propellers as they were before was not possible anymore. With the mold in this state, we could never go back to the same version of those propellers. To be a little dramatic, the high-quality propellers have taken their final spin. We knew it could take some time to find a good solution, and were prepared to communicate about a long-time shortage of the item.

But now for the good news! Thankfully, the replacement mold our partner used proved to be as good as the previous one – and faster than scheduled. Now back in stock, the HQ propeller can fly as well as its predecessor. We tested it and it showed the same characteristics that we’ve come to expect from the thrust upgrade.

Picture of 4 new HQ ultralight propellers -from a 45 degrees angle

So, what’s the real difference? Well, since it maintains the same level of performance, agility, and stability, not much. They have an updated design and have an added “ultralight” in the name (which sounds cooler, doesn’t it?). Those of you with a keen sense of observation will also notice that they have a new SKU – as well as the thrust upgrade bundle.

All in all, this change will have minimal impact on your flying if you’re used to the thrust upgrade bundle. Don’t hesitate to try out this new version and give us some feedback if you have any!

If you haven’t seen it yet then check out our latest Christmas video! In it, we show off a bunch of new stuff, with the main ones being the new Crazyflie brushless and the Lighthouse V2 (which supports up to 16 base stations). But there were also a few other things featured in the video! One of them is the charging pad the Crazyflie brushless takes off from and lands on in the video. This weeks blog post is about the charger, how it came to be, how it works and what lies ahead.

Picture of the Crazyflie brushless on the charging pad

Some history

A while back I worked a bit on a contact charger for the Crazyflie 2.1. The idea was to try and make a design where small pogo-pins could be added to various decks which would allow the Crazyflie 2.1 to charge when lading on a charging pad. Some of the issues with the design was that the area was small (it had to fit on a deck), it put requirements on each deck and that some decks (like the Flow V2 deck) has components which are taller than the pogo-pins. So after the blog post back in 2021 this has been on the shelf, until recently when the Crazyflie brushless work has been moving forward.

With the new prototype design for the Crazyflie brushless being made, there was a chance to address some of the issues I’ve seen before and do another try. All we needed was to add some pads for soldering pogo-pins on the wings (which actually wasn’t as easy as one would think due to layout constraints). So now the charging points didn’t have to be on each deck, they are built into the Crazyflie BL base. The distance between the points is also larger, allowing for a bigger hole in the charging PCB and allowing for a higher variety of decks, like the LED ring with the diffuser shown in the video.

The last missing part of the puzzle was when we needed to do more flight testing with the Crazyflie brushless. We wanted to reproduce the infinite flight demo we previously had for the Crazyflie 2.1, but the current Qi charger pad didn’t work with the new Crazyflie brushless. Time for the next iteration of the charger prototype!

Under the hood

So how complex can you make a charger? Lots! When making a prototype I like to add as much ideas possible to the design. Missing something you wanted to test and doing a new version takes a lot of time but adding some extra crazy ideas might be pretty quick in the design phase. A lot of the time ideas are scrapped along the way, most of the time because of space- or price constraints. Sometimes they are just bad or too complex. Luckily in this case the charger has a large PCB with lots of space and it’s just an early prototype so there’s (almost) no bad ideas!

Under the hood (or 3D printed plastic in this case) there’s a bunch of stuff:

  • An WiFi/BLE module, the ESP32-C6-MINI
  • USB-C connector
  • USB-PD controller
  • 6 DC-jack connectors and 5 terminals for connecting power
  • Measurement of charging current and supply voltage
  • 12 WS2812B RGB LEDs for the outer ring and 12 for the inner one
  • 20-to-5V DC/DC and 5-to-3V3 DC/DC
  • Some debugging LEDs and UART

Intended use

The idea with the contact charger has been to easily charge your Crazyflie without disconnecting the battery, plugging in the micro-USB connector or blocking the use of decks facing downwards like the Qi charger does. In addition to this I also wanted to try out some other ideas.

Chaining chargers: When we go to fairs we normally show a demo of 9 x Crazyflie 2.1 flying with decentralized decision making and the lighthouse positioning system. As you can see there’s a lot of power cords and charging pads laying around. The idea here was to chain the power supplies together and also attach the chargers to each other (hence the hexagonal shape).

WiFi: For a long time I’ve had a prototype of a server for connecting various hardware to (like a charger) so I wanted to try to connect it to this for monitoring.

BLE: The idea was that the Crazyflie could talk to the charger via BLE to for instance change the light effect.

LEDs (and lots of them): The idea was to give some feedback from the charging of the Crazyflie but also to give the charger the ability to act as something more, like lighting up when a Crazyflie decides to land on it.

USB-PD: This is connected to the chaining of power. The ideas was to connect a USB-C charger and distribute the power from it to other chargers via the DC-jack.

Rust: Like we’ve written about before, we’ve been trying out more and more Rust here at Bitcraze. This is yet another experiment, the firmware for the charger is written in Rust using Embassy.


Currently the charger is an internal project, since we use it in our lab for the infinite flight. But it’s of course something that would be exciting to offer our users if there any interest. So let us know what you think!

Also, don’t forget to join us for this Wednesday’s dev meeting. the main topic will be about the Kalman filters however we can answer questions about the wireless as well!

A while ago, we wrote a generic blog post about state estimation in the Crazyflie, mostly discussing different ways the Crazyflie can determine its attitude and/or position. At that time, we only had the Complementary filter and Extended Kalman filter (EKF). Over the years, we’ve made some great additions like the M-estimation-based robust Kalman filter (an enhancement of the EKF, see this blog post) and the Unscented Kalman filter.

However, we have noticed that some of our beginning users struggle with understanding the concept of Kalman filtering, depending on whether this has been covered in their curriculum. And for some more experienced users, it might be nice to have a recap of the basics as well, since this is a very important part of the Crazyflie’s capabilities of flight (and also for robotics in general). So, in this blog post, we will explain the principles of Kalman filtering and how it is applied within the Crazyflie firmware, which hopefully will provide a good base for anyone starting to delve into state estimation within the Crazyflie.

We will also have a developer meeting about Kalman filtering on the Crazyflie, so we hope you can join that as well if you have any questions about how it all works. Also we are planning to got to FOSdem this weekend so we hope to see you there too.

Main Principles of the Kalman Filter

Anybody remotely working with autonomous systems must, at one point, have heard of the Kalman filter, as it has existed since the 60s and even played a role in the Apollo program. Understanding its main principles is also important for anyone working with drones or robotics. There are plenty of resources available, and its Wikipedia page is filled with examples, so here we will focus mostly on the concept and principles and leave the bulk of the mathematics as an exercise for those who like to delve into that :).

So basically, there are several principles that apply to a Kalman filter:

  • It estimates a linear system that is driven by stochastic processes. The probability function that drives these stochastic processes should ideally be Gaussian.
  • It makes use of the Bayes’ rule, which is a general term in statistics that describes the probability of an event happening based on previous knowledge related to that event.
  • It assumes that the ‘to be estimated state’ can be described with a Markov model, which assumes that a sequence of the next possible event (or scenario) can be predicted by the current event. In other words, it does not need a full history of events to predict the next step(s), only the information from the event of one previous step.
  • A Kalman filter is described as a recursive filter, which means that it reuses (part of) its output as input for the next filtering step.

So the state estimate is usually a vector of different variables that the developer or user of the system likes to observe, for either control or prediction, something like position and velocity, for instance: [x, y, , ẏ, …]. One can describe a dynamics model that can predict the state in the next step using only the current time step’s state, like for instance: xt+1 = xt + t, yt+1 = yt + ẏt. This can also be nicely described in matrix form as well if you like linear algebra. To this model, you can also add predicted noise to make it more realistic, or the effect of the input commands to the system (like voltage to motors). We will not go into the latter in this blogpost.

The Concept of Kalman filters

Simplified block scheme of Kalman filtering

So, we will go through the process of explaining the steps of the Kalman filter now, which hopefully will be clear with the above picture. As mentioned before, we’d like to avoid formulas and are oversimplifying some parts to make it as clear as possible (hopefully…).

First, there is the predict phase, where the current state (estimate) and a dynamics model (also known as the state transition model) result in a predicted state. Also in the same phase, the predicted estimated covariance is calculated, which also uses the dynamics model plus an indication of the process noise model, indicating how much the dynamics model deviates from reality in predicting that state. In an ideal world and with an ideal model, this could be enough; however, no dynamics model is perfect, which is why the next phase is also very important.

Then it’s the update phase, where the filter estimate gets updated by a measurement of the real world through sensors. The measurement needs to go through a measurement model, which transforms the measurement into a measured state (also known as innovation or measurement pre-fit residual). Usually, a measurement is not a 1-1 depiction of one variable of the state, so the measurement model ensures that the measurement can properly be compared to the predicted state. This same measurement model, accompanied by the measurement noise model (which indicates how much the measurement differs from the real world), together with the predicted covariance, is used to calculate the innovation and Kalman gain.

The last part of the update phase is where the predictions are updated with the innovation. The Kalman gain is then used to update the predicted state to a new estimated state with the measured state. The same Kalman gain is also used to update the covariance, which can be used for the next time step.

An 1D example, height estimation

It’s always good to show the filter in some form of example, so let’s show you a simple one in terms of height estimation to demonstrate its implications.

1D example of height estimation

You see here a Crazyflie flying, and currently it has its height estimated at zt and its velocity at żt. It goes to the predict phase and predicts the next height to be at zt+1,predict, which is a simple model of just zt + żt. Then for the innovation and updating phase, a measurement (from a range sensor) rz is used for the filter, which is translated to zt+1, meas. In this case, the measurement model is very simple when flying over a flat surface, as it probably is only a translation addition of the sensor to the middle of the Crazyflie, or perhaps a compensation for a roll or pitch rotation.

In the background, the covariances are updated and the Kalman gain is calculated, and based on zt+1,predict and zt+1, meas, the next state zt+1 is calculated. As you probably noticed, there was a discrepancy between the predicted height and measured height, which could be due to the fact that the dynamics model couldn’t correctly predict the height. Perhaps a PID gain was higher than expected or the Crazyflie had upgraded motors that made it climb faster on takeoff. As you can see here, the filter put the estimated height closer to zt+1 to the measurement than the predicted height. The measurement noise model incorporated into the covariances indicates that the height sensor is more accurate than the height coming from the dynamics model. This would very well be the case for an infrared height sensor like the one on the Flow Deck; however, if it were an ultrasound-based sensor or barometer instead (which are much noisier), then the predicted height would be closer to the one predicted by the dynamics model.

Also, it’s good to note that the dynamics model does not currently include the motor input, but it could have done so as well. In that case, it would have been better able to predict the jump it missed now.

A 2D example, horizontal position

A 2D example in x and y position

Let’s take it up a notch and add an extra dimension. You see here now that there is a 2D solution of the Crazyflie moving horizontally. It is at position xt, yt and has a velocity of t, ẏt at that moment in time. The dynamics model estimates the Crazyflie to end up in the general direction of the velocity factor, so it is a simple addition of the current position and velocity vector. If the Crazyflie has a flow sensor (like on the Flow Deck), flow fx, fy can be detected and translated by the measurement model to a measured velocity (part of the state filter) by combining it with a height measurement and camera characteristics.

However, the measurement in the form of the measured flow fx, fy estimates that there is much more flow detected in the x-direction than in the y-direction. This can be due to a sudden wind gust in the y-direction, which the dynamics model couldn’t accurately predict, or the fact that there weren’t as many features on the surface in the y-direction, making it more difficult for the flow sensor to measure the flow in that direction. Since this is not something that both models can account for, the filter will, based on the Kalman gain and covariances, put the estimate somewhere in between. However, this is of course dependent on the estimated covariances of both the outcome of the measurement and dynamic models.

In case of non-linearity

It would be much simpler if the world’s processes could be described with linear systems and have Gaussian distributions. However, the world is complex, so that is rarely the case. We can make parts of the world more abstract in simulation, and Kalman filters can handle that, but when dealing with real flying vehicles, such as the Crazyflie, which is considered a highly nonlinear system, it needs to be described by a nonlinear dynamics model. Additionally, the measurements of sensors in more complex and 3D situations usually don’t have a one-to-one linear relationship with the variables in the state. Can you still use the Kalman filter then, considering the earlier mentioned principles?

Luckily certain assumptions can be made that can still make Kalman filters useful in the sense of non-linearity.

  • Extended Kalman Filter (EKF): If there is non-linearity in either the dynamics model, measurement models or both, at each prediction and update step, these models are linearized around the current state variables by calculating the Jacobian, which is a collection of first-order partial derivative calculations of the model and the state variables.
  • Unscented Kalman Filter (UKF): An unscented Kalman filter deals with linearities by selecting sigma points selected around the mean of the state estimate, which are backpropagated through the non-linear dynamics model.

However, there is also the case of non-Gaussian processes in both dynamics and measurements, and in that case a complementary filter or particle filter would be best suited. The Crazyflie contains a complementary filter (which does not estimate x and y), an extended Kalman filter and an experimental unscented Kalman filter. Check out the state-estimation documentation for more information.

So…. where is the code?

This is all fine and dandy, however… where can you find all of this in the code of the Crazyflie firmware? Here is an overview of where you can find it exactly in the sense of the most used filter of them all, namely the Extended Kalman Filter.

There are several assumptions made and adjustments made to the regular EKF implementation to make it suitable for flight on the Crazyflie. For those details I’d like to refer to the papers on where this implementation is based on, which can be found in the EKF documentation. Also for a more precise explanation of Kalman filter, please check out the lecture slides of Stanford University on Linear dynamical systems or the Linköping university’s course slides on Sensor Fusion.

Update: From the comments we also got notified of an nice EKF tutorial where you write the filter from scratch (github) from Prof. Simon D. Levy from Washington and Lee university. Practice makes perfect!

Next Developer meeting and FOSdem

As you would have guessed, our next developer meeting will be about the Kalman filters in the Crazyflie. Keep an eye on this Discussion thread for more details on the meeting.

Also Kimberly and Arnaud will be attending FOSdem this weekend in Brussels, Belgium. We are hoping to organize an open-source robotics BOF/meetup there, so please let us know if you are planning to go as well!

Today we have a guest blogpost by Thomas Izycki (Technische Hochschule Augsburg) and Klaus Kefferpütz (Ingolstadt Technical University of Applied Sciences, former Augsburg Technical University of Applied Sciences) talking about implementing Software-in -the-Loop for swarm simulation of the Crazyflie.

When our cooperative control lab at the Technical University of Applied Sciences Augsburg was founded a few years ago, our goal was to develop distributed algorithms for teams of UAVs. We quickly decided to use Crazyflies with the algorithms directly implemented in the firmware, thus having a platform for a truly decentralized system. Our ongoing projects focus on cooperative path planning, navigation, and communication.

Since working with several drones at once, which have to communicate and coordinate with each other, can quickly become confusing and very time-consuming, a simulation was needed. It should preferably offer the possibility to integrate the firmware directly in the simulation environment and ideally also offer an interface to the crazyflie python API. With the relocation of our laboratory from Augsburg to the Technical University of Applied Sciences Ingolstadt, which however does not yet have a permanently established flying space, the need for a simulation environment was further increased in order to be less dependent on hardware accessibility. A look at the community and the available simulations quickly led us to the sim_cf flight simulator for the Crazyflie. A fantastic project supporting the use of the actual Crazyflie firmware in software-in-the-loop (SITL) mode and even in hardware-in-the-loop (HITL) mode on a real Crazyflie using the FreeRTOS Linux Port together with ROS and Gazebo. Unfortunately, the project has not been maintained for several years and also had no integration with the Crazyflie Python API. After a short chat with Franck Djeumou and his agreement to use the code of the original sim_cf simulation, the project was ready for an upgrade.

sim_cf2 Flight Simulator

With support for ROS coming to an end we decided to migrate the project to ROS2 and additionally support the current version of the Crazyflie firmware, which at this time is release version 2023.11. With the addition of a driver to connect the cflib to the SITL process, the same python cflib-based scripts can now be used with real Crazyflies and for use in the simulation environment. Only the corresponding driver needs to be loaded during initialization. Overall, the focus of the sim_cf2 simulation is now on using the Crazyflie python API instead of commanding the Crazyflies via ROS.

As for the Crazyflie firmware the whole build process has been fully integrated into the firmware’s KBuild build system. This also allows the use of the same code base for simulation and execution on the real Crazyflie. Depending on the configuration, the firmware is compiled for the STM32F on the Crazyflie or the host system running the SITL.

Components of the sim_cf2 Flight Simulator

To run the simulation, the three modules must therefore be started separately. Gazebo is started using the main launch file. The number and initial pose of the simulated Crazyflies is also defined in this file. Once the firmware for the host system has been built, the desired number of SITL instances can be started using the attached script. Finally, a cflib-based script, the Crazyflie client or the multi-agent client presented below is started. With no radio dongles attached to the computer, the simulation driver is initialized automatically and a connection to the simulated Crazyflie can be established.

There are still a few open issues, including the absence of implemented decks for positioning, such as LPS and Lighthouse. Currently, the absolute position is sent from Gazebo to the SITL instance and fused in the estimator. Moreover, Gazebo requires quite a lot of computing power. We were able to run a maximum of four Crazyflies simultaneously on a relatively old laptop. However, a modern desktop CPU with multiple cores allows for simulating a significantly larger number of Crazyflies.

Multi-Agent Client

Independent of the simulation we designed a GUI for controlling and monitoring our multi-agent teams. It currently supports up to eight Crazyflies but could be upgraded for bigger teams in the future. So far it has been enough for our requirements.

Multi-Agent Client with six connected Crazyflies

A central feature is the interactive map, which makes up about half of the gui. This is a 2D representation of the flight area with a coordinate system drawn in. Connected Crazyflies are displayed as small circles on the map and a new target position can be assigned by clicking on the map after they have been selected by their corresponding button. If required, obstacles or paths to be flown can also be drawn into the map.

Pseudo-decentralized communication

An important aspect of a truly decentralized system is peer to peer communication. It allows information to be exchanged directly between agents and ideally takes place without a central entity. Currently peer to peer communication is not available in the Crazyflie ecosystem, but is in development.

For this reason, we have implemented a workaround in our client, enabling a pseudo-decentralized communication system. This involves adding an additional layer to the Crazy RealTime Protocol (CRTP), which we named the Multi-Agent Communication Protocol (MACP). It consists of an additional packet header made of the destination ID, source ID and a port as endpoint identifier. Every ID is unique and directly derived from the Crazyflie’s address.

These MACP packets are sent via the unused CRTP port 0x9. The packet routing mechanism implemented in the client forwards the packets to their destination. It is also possible to send packets as a broadcast or to address the client directly.

On the firmware side, we have added a corresponding interface to simplify the sending and receiving of macp packets. It is analogous to the CRTP implementation and allows the registration of callback functions or queues for incoming packets on corresponding ports. It can be activated via KBuild.

At least for use in the laboratory and the development of distributed algorithms, this method has proven its worth for us.


We hope that the sim_cf2 simulation can also be useful to others. The complete source code is available on GitHub. Further information concerning installation and configuration can be found in the readme files in the respective repositories.

We would also like to point out that other simulations have been created that are based on sim_cf and therefore offer similar functionality. One of these projects is CrazySim, also available on GitHub. Moreover, there are ongoing efforts to officially integrate such a software-in-the-loop simulation into the Crazyflie firmware and ecosystem.


Multi-Agent Client:

Show-and-tell post of CrazySim:

For the original sim_cf Flight Simulator for the Crazyflie visit:

A few years ago, we wrote a blogpost about the Commander framework, where we explained how the setpoint structure worked, which drives the controller of the Crazyflie, which is an essential part of the stabilization module. Basically, without these, there would not be any autonomy on the Crazyflie, let alone manual flight.

In the blogpost, we already shed some light on where different setpoints can come from in the commander framework, either from the Crazyflie python library (externally with the Crazyradio), the high level commander (onboard) or the App layer (onboard).

General framework of the stabilization structure of the crazyflie with setpoint handling. * This part is takes place on the computer through the CFlib for python, so there is also communication protocol in between. It is left out of this schematics for easier understanding.

However, we notice that there is sometimes confusion regarding these different functionalities and what exactly sends which setpoints and how. These details might not be crucial when using just one Crazyflie, but become more significant when managing multiple drones. Understanding how often your computer needs to send setpoints or not becomes crucial in such scenarios. Therefore, this blog post aims to provide a clearer explanation of this aspect.

Sending set-points directly from the CFlib

Let’s start at the lower level from the computer. It is possible to send various types of setpoints directly from a Python script using the Crazyflie Python library (cflib for short). This capability extends to tasks such as manual control:

send_setpoint(roll, pitch, yawrate, thrust)

or for hover control (velocity control):

send_hover_setpoint(vx, vy, yawrate, zdistance)

You can check the automatic generated API documentation for more setpoint sending options.

If you use these functions in a script, the principle is quite basic: the Crazyradio sends exactly 1 packet with this setpoint over the air to the Crazyflie, and it will act upon that. There are no secret threads opening in the background, and nothing magical happens on the Crazyflie either. However, the challenge here is that if your script doesn’t send an updated setpoint within a certain amount of time (default of 2 seconds), a timeout will occur, and the Crazyflie will drop out of the sky. Therefore, you need to send a setpoint at regular intervals, like in a for loop, to keep the Crazyflie flying. This is something you need to take care of in the script.

Example scripts in the CFlib that are sending setpoints directly:

Setpoint handling through Motion Commander Class

Another way to handle the regular sending of setpoints automatically in the CFLib is through the Motion Commander class. By initializing a Motion Commander object (usually using a context manager), a thread is started with takeoff that will continuously send (velocity) setpoints at a fixed rate. These setpoints can then be updated by the following functions, for instance, moving forward with blocking:


or a giving body fixed velocity setpoint updates (that returns immediately):

start_linear_motion(vx, vy, vz, rate_yaw)

You can check the Motion Commander’s API-generated documentation for more functions that can be utilized. As there is a background thread consistently sending setpoints to the Crazyflie, no timeout will occur, and you only need to use one of these functions for the ‘behavior update’. This thread will be closed as soon as the Crazyflie lands again.

Here are example scripts in the CFlib that use the motion commander class:

Setpoint handling through the high level commander

Prior to this, all logical and setpoint handling occurred on the PC side. Whether sending setpoints directly or using the Motion Commander class, there was a continuous stream of setpoint packets sent through the air for every movement the Crazyflie made. However, what if the Crazyflie misses one of these packets? Or how does this stream handle communication with many Crazyflies, especially in swarms where bandwidth becomes a critical factor?

This challenge led the developers at the Crazyswarm project (now Crazyswarm2) to implement more planning autonomy directly on the Crazyflie itself, in the form of the high-level commander. With the High-Level Commander, you can simply send one higher-level command to the Crazyflie, and the intermediate substeps (setpoints) are generated on the Crazyflie itself. This can be achieved with a regular takeoff:


or go to a certain position in space:

go_to(x, y)

This can be accomplished using either the PositionHLCommander, which can be used as a context manager similar to the Motion Commander (without the Python threading), or by directly employing the functions of the High-Level Commander. You can refer to the automated API documentation for the available functions of the PositionHLCommander class or the High-Level Commander class.

Here are examples in the CFlib using either of these classes:

Notes on location of autonomy and discrepancies

Considering the various options available in the Crazyflie Python library, it’s essential to realize that these setpoint-setting choices, whether direct or through the High-Level Commander, can also be configured through the app layer onboard the Crazyflie itself. You can find examples of these app layer configurations in the Crazyflie firmware repository.

It’s important to note some discrepancies regarding the Motion Commander class, which was designed with the Flow Deck (relative positioning) in mind. Consequently, it lacks a ‘go to this position’ equivalent. For such tasks, you may need to use the lower-level send_position_setpoint() function of the regular Commander class (see this ticket.) The same applies to the High-Level Commander, which was primarily designed for absolute positioning systems and lacks a ‘go forward with x m/s‘ equivalent. Currently, there isn’t a possibility to achieve these functionalities at a lower level from the Crazyflie Python library as this functionality needs to be implemented in the Crazyflie firmware first (see this ticket). It would be beneficial to align these functionalities on both the CFlib and High-Level Commander sides at some point in the future.

Hope this helps a bit to explain the commander frame work in more detail and where the real autonomy lies of the Crazyflie when you use different commander classes. If you have any questions on what the Crazyflie can do with these, we advise you to ask your questions on and we will try to point you in the right direction and give examples!

It’s not often a blog post happens on the 25th of December, so this time, you’re having a treat with some new Bitcraze prototypes as a present from us! If you have time to get away from the Christmas table, there’s something we’d love you to watch:

Now let’s try to see if you noticed all the new stuff you see in this video!

Our new flight lab

We teased it, but in the beginning of December, we got our extended flight lab! We added 110 m2 to our flight space. It was a rush to have everything ready for the video – we cleaned everything, painted the walls and the green logo, set up the positioning system without our truss… But now we’re happy to show you how big the space is! Even if it’s hard to convey the real size on camera.

The Crazyflie 2.1 brushless

We already talked about it in this blog post, but the brushless has made significant progress and we feel confident that you will get your hands on it in 2024. Here, we use the extra power for a fast and agile flight. It also was very stable and didn’t crash once during the shooting!

The Lighthouse V2

Yes, you counted right! The Brushless flew with 16 base stations! We’ve worked really hard this past three months to create a new Lighthouse deck – the Lighthouse deck 2.0. It could get its position from 16 base stations. That’s 4 times more than what was previously possible! It behaved consistently well during the different tries, and we are really happy with the result. Right now, it’s just a prototype, but we’re hoping to get it to the next step in the coming months.

The contact charging station

Marcus created a power charger for the Brushless that doesn’t need any extra deck to allow for charging. It connects with the brushless feet. It has also the cool feature of changing LEDs indicating the status (idle, charging or charged). It is also a prototype, and we don’t know if this will end up being a product

The high-power LED

This is trickier to see, but it’s not our usual LED ring that the brushless carries. It’s a new, powerful LED underneath. It is so powerful that it nearly blinded us when we tried it for the first time. We put a diffuser on it, and it allowed the Crazyflie to be visible at such a high pace! This is a prototype too of course and we’re not sure if we will release it, but it’s fun to use for this kind of project.

Other announcements

During this week, our office is closed- we take this week to celebrate and rest a little before 2024. This means that shipping and support will be greatly reduced.

But we’re back the week after- at a somewhat reduced pace though. The developer meeting on the 3rd of January is maintained but without any presentation. We’ll take this time to answer any questions you have and talk a little! The details are here.

Bitcraze got their presents this year: a handful of working prototypes! We hope we got your wishes too, merry Christmas to you!