Category: Software

As some of you might know, we are working full ahead on developing a local positioning system for the Crazyflie 2.0 ecosystem. There are many things to be done and we just took two major step by improving the stabilizer code architecture and moving the position control code into the firmware. Getting the position from an external system is fine and dandy, but we also have to control the pitch, roll and yaw of the Crazyflie to keep its desired position. Up til now we have been running this control algorithm outside the Crazyflie in an external computer, but now we have moved it into the Crazyflie itself. The controller is a simple PID controller and can definitely be improved, but the main purpose of the work has been to improve the architecture in this area. We know there are people in the community working on position related features and we hope the new architecture will make it easier for us all to implement the bits and pieces needed to get an autonomous Crazyflie. The estimation of the position has not been implemented in the firmware yet but the architecture now has support for it.

The general layout of the new architecture is as follow:

  • The sensors are gyroscope, accelerometer and pressure sensor. More could and will be added in the future like position and altitude measurement.
  • The state estimator calculate an as good as possible estimate of the Crazyflie state using the sensor values. The state contains the Crazyflie orientation (roll, pitch, yaw), its position and speed. Currently the state estimator has complementary filters for the orientation and the altitude. In the near future the full position will be estimated as well.
  • The commander generate a setpoint to be followed by the Crazyflie. Currently this is only done by receiving commander packet from the ground using Crazyradio or bluetooth low energy.
  • The state controller generates control output to achieve the requested setpoint from the current state.
  • Finally the power distribution is translating controls from the controller into driving the actual motors.

This is implemented in stabilizer.c and each block is implemented in there own file. Stabilizer.c used to be very verbose and complex to read and modify, it has now been greatly simplified and the above architecture is implemented in one short loop (see the full code in GitHub):

while(1) {
  vTaskDelayUntil(&lastWakeTime, F2T(RATE_MAIN_LOOP)); // 1KHz

  sensorsAcquire(&sensorData, tick);
  stateEstimator(&state, &sensorData, tick);
  commanderGetSetpoint(&setpoint, &state);
  stateController(&control, &sensorData, &state, &setpoint, tick);
  powerDistribution(&control);
  tick++;
}

Our philosophy with this new architecture is to keep the code as simple as possible and to allow customisation at compile time. The high-level functions have as simple as possible interface and so can be exchanged easily. So if tomorrow, we have a shiny new controller we just have to compile it instead of the current PID controller. We think that this fits the way the Crazyflie is used, as a development tool.

This is just the beginning: there is still some more to clean-up in the functions and we will most certainly enhance the code from feedback. Please tell us if this is useful and how it can be enhanced even more.

Crazyflie 2.0 already has two mobile clients, one for Android maintained by Fred and the iPhone client. Now we officially have a new one on development: the Windows client.

IMG_20160425_202412

Theseankelly, from the community, has started a Windows client for Crazyflie 2.0. It connects Crazyflie using bluetooth low energy and works both on phone and on PC running windows. Last week, he transferred the source code repos in the Bitcraze github so that it can have more visibility. We plan to eventually released it in the Windows store, but first it needs to have a little bit more features :-). To this end we have created a milestone on GitHub and have filled a couple of tasks. The plan is to get to a minimum set of functionalities. That for, we will focus on phone support first but if you are interested in PC support do not hesitate to say so and push tickets for it (gamepad support and configuration is the first thing I can think about for desktop support).

Last week Fred released a new version of the Android client. The outstanding new feature is a support of the LED and Buzzer decks when using Crazyradio! It means that you can now change the light effects and play sounds on the Crazyflie from the phone. This is even better because it means that the Android client code is now able to access the param subsystem and soon the log subsystem: this will allow for much more interactions in the future (like access to advanced Crazyflie settings and supporting more decks). The support of decks using BLE and more are on going so stay tuned and if you have any functionality request please head to the GitHub ticket tracker.

aclient-deck

We have just released a new version 2016.04.1 of the Crazyflie client.

client_2016.4.1

The biggest change is actually not so visible but very important: we have now separated the GUI client from the Crazyflie lib. The great advantage is that the lib became a small project and could be pushed to pypi. This means that if you want to control Crazyflie from your own Python program all you have to do is to “pip install cflib” and you are ready to “import cflib” in your program to control the Crazyflie.

For the new release of the client we also pushed the client in pypi as well. This will be mainly useful in Linux and Mac where you are now able to install the client with “pip3 install cfclient”. One little drawback however: since the GUI lib we are using, pyqt, is not in pypi it has to be installed on the side. This can be done in Ubuntu with something like “sudo apt-get python3-pyqt4 install python3-pyqtgraph” or on Mac with homebrew or MacPorts.

Last but not least we have enabled Windows continuous integration with appveyor and fixed the Windows build. This means that a Windows build and installer are going to be generated for every commit in the Crazyflie client repos. Maintaining the Windows client has always been a challenge to us since we are mainly Linux users, so the this will help a lot to keep good Windows support. We still consider this Windows build to be somewhat experimental so please test it and report any bug you are hitting.

The last system to support for executable distribution is Mac. We did put some time trying to generate a mac app out of the client without any success. If anyone wants to give it a try or have some tips please head to the ticket on github.

Historically the main way to control a Crazyflie has been by using a computer running a Crazyflie client and communicating with a Crazyradio (PA). However since very early we have made an Android client that also communicated using the Crazyradio. This was at the very beginning of USB On-The-Go for Android and it allowed to fly without a PC. When we released Crazyflie 2.0 with Bluetooth LE support we made an iPhone client as well as adding bluetooth to the Android client.

The Android App is the oldest and thanks to the community the most fully featured. It has a community maintainer, Fred, that is doing a great job a keeping the app stable and adding features.

android_client

With the Android app you can fly with both touchscreen control and game-pad control. It works with Bluetooth and Crazyradio. It can update Crazyflie 1.0 and Crazyflie 2.0 firmware using Crazyradio and soon Bluetooth for Crazyflie 2.0. Soon the possibility to use deck functionality like LED ring and Buzzer will be added.

The iPhone app is, for the moment, a bit more simple:

ios_main

 

It allows to fly and update Crazyflie 2.0 using Bluetooth low energy. There has already been a couple of contribution to keep the app up to date with Apple dev tools and more featured are currently being pushed.

Finally there is a new one coming soon. A windows 10 app prototype has been done by theseankelly and is just waiting to be enhanced. The exciting parts is that it works on Windows phone but it is also the first Bluetooth GUI client for Crazyflie 2.0 on desktop platform (there is nodejs libs that supports BLE on computer but no GUI that I know off, if I am wrong please comment!).

windows_client

A great thanks to all the contributors, the mobile clients for Crazyflie would not be that far without you! If you are interested in mobile development you are welcome to contribute, these clients started as a “just to fly” remote control but they could do so much more.

As we already talked before in a couple of post, we are currently developping a local positioning system for the Crazyflie based on ultra-wide-band radio DWM1000. This is one of our main focus currently so we wanted to post a short update on our progress.

We have assembled and shipped a couple of LPS system already and so far the performance and progress are great. We now think that we have the copter flying as good as we can have it without running sensor fusion and the control loop in the Crazyflie microcontroller. Next step is to integrate algorithms in the Crazyflie.

We are currently working hard at finishing the design to make it ready for production. We will write more updates about that so stay tuned :).

We have shot a short video demonstrating the current state, see after the video for more information about the setup:

To make this video we have installed 6 anchors. 3 are above the room and 3 at about 50cm from the ground. The Crazyflie has a LPS deck and ranges in a round-robing fashion with all 6 anchors. The ROS driver pulls the ranging, estimate the Crazyflie position, and calculate a corrected roll/pitch/thrust in order to keep it at the pre-defined setpoint. The Yaw is not controlled externally, it is kept by the Crazyflie internal gyroscope only.

The ROS computer was setup according to the instruction on our wiki, and by launching the pf_hover launch file:

roslaunch bitcraze_lps_estimator dwm_loc_pf_hover.launch uri:=radio://0/110/2M x:=1.5 y:=5 z:=1.2

We have stared to look at what is needed to make the Crazyflie position aware and to integrate the upcoming positioning system. The rough idea is to add a position estimation module to the firmware of the Crazyflie that will be responsible of estimating the current position based on data from internal or external sensors. The sensors could be mounted on the Crazyflie but it should also be possible to inject the position over radio from an external system. A control module will use the estimated position to try to navigate the copter to a desired position that could be set for instance by a user or by some navigation algorithm. If you want to participate in the design discussions or implementation head over to github where we will use issues for this conversation.

We decided that a suitable first step was to improve the altitude hold, so that is what we did last week. The code has been refactored and improved and we think the altitude hold is now working much better than before. It’s not perfect, still room for improvements :-)

Tilt compensation

While we were at it we also added a thrust compensation to avoid loosing altitude when tilting the copter. It turns out it makes flying easier as the pilot does not have to add extra thrust when moving around. Good for both human and automatic pilots.

Hackster.io

Have you checked out our projects on hackster.io? Help out and make Bitcraze a featured platform by adding your own project or just follow us, we need 10 projects and 25 followers to be featured. You can make a difference!

First of all, happy new year on behalf of the Bitcraze team. In this post we would like to talk about the Deck API, but first a little bit of background.

Crazyflie and pretty much all we do is open-source. The main reason is that we want to share and allow everyone to build upon what we are doing. The first Crazyflie was expendable with an expansion port but modifying it was hard because it required good soldering skills. However if we really want others to build and use what we do, we had to increase the usability. So, when designing Crazyflie 2.0 we put a lot of efforts into making it easily expendable. We ended up with the deck port, which makes it easily to add an expansion board, called a deck, on top or bottom of the Crazyflie 2.0. An installed deck will automatically be detected and initialized when the Crazyflie starts thanks to the one-wire memory they contain. Finally we have also made the breakout and prototype deck to help making new decks.

Connector_multiplexing

With all this, we believe we managed to make it much easier to create a new deck. However making the firmware driver for these decks still required to understand a lot about how our firmware is architectured. It also did require to add code to multiple files to ensure the driver runs properly. The new deck API aims at making the firmware driver development more straightforward.

The base of the deck API is the driver declaration: it is possible to add a deck driver without having to modify any code in the firmware. The driver just has to be compiled and it will be automatically loaded at Crazyflie startup. This is inspired by the way the Linux kernel is loading modules and drivers. So the minimal driver can be written in 12 lines of code:

#define DEBUG_MODULE "HelloDeck"
#include "debug.h"
#include "deck.h"

/* init function */
static void helloInit()
{
 DEBUG_PRINT("Hello Crazyflie 2.0 deck world!\n");
}

/* Driver registration */
static const DeckDriver helloDriver = {
 .name = "myHello",
 .init = helloInit,
};
DECK_DRIVER(helloDriver);

In this example, the driver will be initialized automatically if a deck is installed with the name “myHello”. It is also possible to force the driver initialization. For more information there is a documentation for this on the wiki and there is also a short howto that will guides you from zero to having your code running in Crazyflie.

There is also an implementation of the digital and analog input/output API similar to Arduino.

There is a lot of work left on the deck API. Among other things:

  • Easy shortcut to run tasks: currently the only way to run a task is to create one using the FreeRTOS API. The plan is to provide easy to use timers and an Arduino-like loop function.
  • More drivers for SPI, Serial, I2C, …
  • Access to other parts of the system like controlling the flight setpoint or setting the LEDs.

The two first are quite straightforward and ‘just’ need to be done. We are not so sure how to implement the last one yet (we need a good way to modularise the firmware). If you have any input on things you would like to see in the API please contact us, the forum is good for discussion and a ticket in the firmware github project for functionality. You are also welcome to help-out with the implementation, documentation or reporting bug :-).

Last week I was at Lua Workshop 2015 in Stockholm, it was a very interesting conference with lots of interesting people. I also had the opportunity to see the office of King, the host for the workshop, and it gives a lot of idea for fun stuff and toys we could have in our office :-)

On a side note we are organizing a presentation in our office in Malmö the 22nd of October: Mandy from Seeedstudio is visiting us and will talk about manufacturing in China. If you want to come you can register.

lua-logo-crazyflie

Now, back to Lua. Lua is a dynamic programming language that is small, fast and meant to be embedded within other programs. Currently is is used a lot in video games and a bit on servers. It has also be used in deeply embedded system with the eLua project, for example Seeeds sells a Lua-preloaded ESP8266 wifi module. One of our plan for Crazyflie 2.0 is to be able to write deck drivers in Lua.

With Crazyflie 2.0 we are aiming to make a research-grade flying platform more accessible and versatile, hence the expansion capabilities (with decks) and the new API we are writing for it. Lua would fit well in this goal. It would allow to very quicky script and test a device driver. As a bonus Lua being safe (ie. the virtual machine cannot crash the system), there would be no risk of crashing the copter with those kind of driver. The architecture would look something like that:

cfluaArchitecture

Though Crazyflie Lua integration has not been prioritized so far, we think it is something that would be interesting to play with it in the future. If anyone is interested into testing and helping out please reach us on Github or on the forum.

We have decided to use Travis for continuous integration builds of our open source repositories. Travis is automatically building the code on all branches and pull requests, which gives all developers that wants to contribute to the project, the possibility to see that their code passes the build. The current status of the latest build on the main branch, is visible through the icon in the readme in github, or on the Bitcraze page at travis.

travis-ci

The projects we have added so far to travis are written in C or python. The C projects for instance, must be compiled with special compilers for the processors used in the crazyflie which adds some extra complexity. We have created a docker image (bitcraze/builder) with the tools needed, to make life easier for developers. If you use the image when developing, there is no need to install tools locally, and the same image is used in travis builds, so you know you will get the same results as the CI-server. This also removes the problem of tools with different versions (and results) in the development- and build environment.

To use the image you can for instance type

docker run --rm -v ${PWD}:/module bitcraze/builder make

Event though it is awesome to be able to create a well known build environment through a docker container, we feel that too much typing is needed to execute a simple make.  To solve that problem we are looking at the possibility of creating a toolbelt that will handle that for you. More information on that later on, for now developers will have to find their own solutions through scripting, aliasing or other means.

Obviously you need Docker to use this image. If you have not tried it out yet, take a look at www.docker.com.

We are aiming for automated testing of our code, and even though we have a lot of work to do, we have taken the first baby step. For the moment, firmware projects are simply compiled and linked to ensure that the code is coherent. Projects that support both crazyflie 1 and 2 are built in both flavours to avoid problems for developers that might only use one of the platforms.  The python client project is only checked for PEP8 compliance, but we are looking at how to unit test. Any input from the community is welcome!

Happy hacking!

During the last week we’ve taken a big step, moving to Python 3! The reason for the move is that Python 3 is becoming broadly adopted and it has more features that we want to make use of. Also 3 > 2. This post will explain a bit of what we did, some of the problems we encounters and the current status. The numbers 2 and 3 will be thrown around a lot in the text, but to precise we’re talking about versions 2.7+ and 3.4+ (even more precise it’s been tested on 2.7.9 and 3.4.3). The next release of the client will run on Python 3, but if you want to test it now just clone the development branch on GitHub.

Status

If you have developed applications using the API and Python 2 then you might be getting a bit worried right about now. The compatibility for both Python 2 and 3 will be kept for most things, except for the client:

This will be compatible with both 2 and 3:

  • The Crazyflie Python API (everything in lib/cflib)
  • The examples for the Crazyflie Python API (everything in examples)
  • The ZMQ server using the Crazyflie Python API (bin/cfzmq)
  • The Crazyflie command-line bootloader (bin/cfloader)

But the main clients will only have Python 3 compatibility:

  • The Crazyflie Python client (bin/cfclient)
  • The Crazyflie Python headless client (bin/cfheadless)

API Examples

While doing the porting we’ve also added more examples to cover more of the Crazyflie Python API. In order to keep 2/3 compatibility for the API it’s important to be able to test it easily with the different versions. We are having unit-tests on the TODO-list, but until then we’ve been using the API examples to test. All the examples should run with both Python 2 and 3. It’s also a good thing with more examples showing how to use the API…

Porting and compatibility

The approach we used was to first run the 2to3 utility to automatically to as much as possible of the porting. After that we had to fix the rest of the errors manually and also maintain the dual 2/3 compatibility of the API.

In our previous implementation we made use of strings to store binary data that we were sending/receiving. But because of incompatibilities between Python 2 and 3 this didn’t fit very well. To make things neat for the API we found a container where we could store bytes that works with both Python 2 and 3, the bytearray. Even though we use the same type, there’s still some subtle differences in usage between the versions. After doing some testing we found ways where the syntax was the same for Python 2/3.

First of all bytearrays can be created from a string, tuple or list. When indexed by the [] operator it will give you the value of each byte.

>>> d = bytearray([i for i in range(10)])
>>> d
bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t')
>>> d[5]
5

The main point is getting something meaningful out of the bytearray when doing the communication, here’s a few examples:

Unpacking a byte, an integer and a word from the first 7 bytes (little endian)

>>> struct.unpack("<BIH", a[:7])
(0, 67305985, 1541)

Getting a string from a subset of the data can be done by using decode and the char-set to use for decoding. We use ISO-8859-1 since the Crazyflie does not support Unicode (yet?).

>>> d = bytearray([i for i in range(97,100)])
>>> d
bytearray(b'abc')
>>> d.decode("ISO-8859-1")
'abc'

You can also easily get a tuple or a list:

>>> list(d)
[97, 98, 99]
>>> tuple(d)
(97, 98, 99)

And you can also concatenate:

>>> d + d
bytearray(b'abcabc')

And find a byte:

>>> d.find(bytearray((98, )))
1

But there’s also a few things we couldn’t get to work in a good way and have to check which version we’re running and execute different code, like the queue import that has changed name.

if sys.version_info < (3,):
    import Queue as queue
else:
    import queue

Another problem we haven’t solved is creating a bytearray from a string, so it’s also

if sys.version_info < (3,):
    self._data = bytearray(data)
else:
    self._data = bytearray(data.encode('ISO-8859-1'))

As for the client code that was ported to Python 3 without keeping the backwards compatibility there wasn’t any big issues. The biggest change was the PyQT4 API where there’s a few things that have improved when placing custom Python data in GUI objects. Before QVariant was used for this. You would create a QVariant object that wrapped the Python object. To get data out from the QVariant again you would have to explicitly say what type it had by calling the correct function (like toInt()). Now this is a lot smoother. QVariant has been skipped and you just use the Python type directly.

For more information have a look here where we found a lot of useful tips. Don’t hesitate to leave a comment if you think we could have done things differently or if you have any tips!

What’s not working

There’s still a few things we’re not sure how to fix and we have to look into it a bit more. These are:

  • There doesn’t seem to be any Python 3 bindings for the Leap Motion. According to this it’s possible to build the bindings yourself.
  • The Python 3 bindings to Marble for the GPS tab hasn’t been investigated yet

PEP-8

On a side note we’ve started using Travis CI (more on this next week) and will start creating unit-tests for the Crazyflie Python  API. As a first step we’re running PEP-8 on all the code. This will be checked automatically for all commits and pull-requests.