Author: Arnaud

A couple of weeks ago we found the NeoPixel ring from Adafruit at a local shop, we had to attach this neat board to our copter and see what cool effect we could make with it. The ring has 16 RGB LEDs that can be driven independently with only one data wire. The LEDs the Neopixel contains are called WS2812.

This post is describing the development of a WS2812 driver for the Crazyflie. A later post will show the usage we did of it (fairly limited in comparison of the seemingly endless possibility, as usual we have more ideas than time to execute them :-).

The WS2812 LED

First of all we needed to see how to control the LEDs. The protocol used by the WS2812 is quite simple but special. All LED on the ring have a data input and a data output pin in a chained manner. Colors of the LED is send over the Data line to the first LED that will save it internally. When sending a second color the first LED will send the saved color to the second LED. And so on, by sending 16 color data we can set the color of all LEDs of the ring independently. Colors are sent as 24 bits (8 bits per component).

Up to there nothing is really peculiar, the system is pretty neat and allows to control a lot of LEDs with just one IO. The problems comes with the Bit encoding:

ws2812_format

Bits are encoded with pulse width: a short pulse means 0 and a long pulse means 1. The bitrate is of about 800KHz and the tolerances on bit timing is pretty tight. As there is no hardware peripheral dedicated for this (on common microcontrollers), this bitstream needs to be implemented either by bit-banging or by being a bit creative with the peripheral we actually have at our disposal.

Driver implementation

Adafruit did implement a driver for the WS2812 for Arduino, this is a software implementation that uses the CPU to implement the signal. However at that bitrate a software/bit-bang implementation have to be timed carefully and the easiest for that is actually to implement it in assembler. Arduino runs on an AVR processor and these processor are very predictable: each instruction runs in a specified number of clock cycle which makes it possible to implement a timed loop like the one of Adafruit. However this becomes impractical on bigger CPU that implements caches and other optimization that makes it really hard to predict how much cycle each instruction will take.

The Crazyflie runs a STM32F103 based on an ARM Cortex-M3. This is just complex enough to make the ASM-timed loop impractical: The CPU core runs at 72MHz but the flash is slower so a simple cache memory is inserted in the middle and depending of the state of this cache it may take from 1 to 3 cycles to execute an instruction. There is an even bigger problem: a CPU timed loop requires to stop all interrupt and to have the CPU running exclusively on updating the WS2812. We cannot allow that on the Crazyflie that require a 250Hz control loop to stay (controllably) airborne.

We asked Google to see if someone already came with a solution and actually someone did. The Elia’s Electronics Blog posted a neat, well documented, solution using the STM32 Pulse Width Modulation (PWM) capabilities of the STM32 to generate signals that the WS2812 understands. All we needed was a timer/pwm output then. It happens that we have one timer1 output on the Crazyflie extension port:

crazyflie_neopixelring

This is only 3 wires: VCOM for the battery voltage, GND and the timer output.

I started porting the Elia’s code to the Crazyfle. The only free timer we could easily use was different and much more complex than the one Elia uses. So part of the frustrating implementation was to figure out WHY the signal was looking weird on the scope! Finally after an hour or so the code was working:

IMG_20140411_202251

Enhancements

Now that was not quite enough. The driver is using the PWM to generate the 1’s and 0’s pulse width and the DMA is used to feed the bit width independently of the CPU (so that it can do something else, like controlling the copter attitude…). It requires all the 16 LEDs data to be written in the memory buffer before starting the DMA. Each LED has 24 bits color data and each bit will be encoded as 16bit pulse length for the timer. It means that the full ring will take 768Bytes in RAM. It sounds small but its a bit too much for us and, most importantly, it does not scale: if we want a second ring the ram requirement will double.

To fix this I implemented two things: An easy one is that the DMA can do some type conversion and one of these is that it can read 8 bit in memory and write 16 bit in the peripheral. This allows to store only 8 bits pulse width in memory and so divides by 2 the memory requirement, but it still doesn’t scale.

The fix to scaling is double buffering. The STM32F103 does not implement DMA double buffering as such but what it has is close enough: circular DMA with half-transfer interrupt. The idea is to load the 2 first LED in a buffer and to start the DMA for 42 bytes in circular mode. When the DMA has transferred the first LED it triggers the half-transfers interrupt which allows the CPU to replace the first LED data by the 3rd. When the 2nd LED is transferred the transfer-complete interrupt is triggered by the DMA and the CPU fills in the 4th LED in place of the 2nd one. The DMA roll-over at the beginning of the buffer and sends what is now the 3rd LED data. This continues until all the LEDs has been  sent. This solution scales: it requires a 42 bytes buffer for as many LED as we want!

Conclusion

All that process was not really simple. However the result is simple, now the only thing required to control a Neopixel ring in the Crazyflie is:

 

#define BLACK {0x00, 0x00, 0x00}</span>
static uint8_t color[][3] = {{40, 40, 40}, {32, 32, 32}, {16,16,16}, {8,8,8},
                             {4,4,4}, {2,2,2}, {1,1,1}, BLACK,
                             BLACK, BLACK, BLACK, BLACK,
                             BLACK, BLACK, BLACK, BLACK,
                            };

/* ... */
ws2812Send(color, 16);

And it will run nicely without interrupting other tasks like control and communication. Replace 16 by 32 to control 2 Neopixel rings. The current implementation has been pushed in the crazyflie-firmware neopixel_dev branch (still require some clean-ups!). Actual implementation is in ws2812.c and neopixelring.c.

neopixel_flying

The only problem left is not software: At the end of the battery life, the voltage is not enough to fully lit the blue LED. That make all white look orange-ish. The only way to fix this problem would be to step-up the battery voltage higher then the forward voltage of the blue LED. Though it works well enough without that.

Stay tuned for a following post about actual usage of the ring.

Most of last week was spent at the Devoxx France conference in Paris. Even though we didn’t have our talk until the end of the week, we hung around most of the time just developing and working. And of course we also got the chance to meet lots of interesting people and demo the Crazyflie. We worked on some code for the NeoPixel ring from Adafruit, implementing some different effects. We also did a quick hack to be able to change effects when flying using the Leap Motion. Since we haven’t had any time to prepare videos/photos of it and to clean up the code, we will post more about that next week.

We also got a chance to do some other fun things, like flying the FPV Crazyflie over the crowd at one of the keynotes and also record some video while flying though the conference.

 

[pe2-gallery album=”http://picasaweb.google.com/data/feed/base/user/115721472821530986219/albumid/6002584693333310545?alt=rss&hl=en_US&kind=photo” ]

A couple of weeks ago we attached a uBlox MAX-7 GPS module to the Crazyflie (blog post). Back then it was mostly a proof of concept, all we did was to re-route the raw GPS data (in text NMEA format) directly to the PC using the Crazyflie text console port. This allowed us to quickly prove that a GPS can work on the Crazyflie but was not that useful and efficient: the copter did not decode the gps position and a lot of radio bandwidth was used. Last Friday we decided to fix it and to make it clean(er).

The ultimate goal was to measure the Crazyflie speed, if it wasn’t for the rain we could have done the measurement! Anyway, this work allowed us to exercise the debug functionality of the Crazyflie platform and so to see the strength of it but also what needs to be enhanced. In this post we will try to document (at high level) the steps taken to implement the GPS in the Crazyflie. The source code is pushed in the crazyflie firmware and python-client git repos. The Python client code is in the master branch and the firmware code in the gpu_ublox_dev branch (dev branch means that the code is far from final/clean, but it works!).

Electronically the GPS is connected using only 4 pins: VCC, GND, serial RX and serial TX. The serial port is connected to pins 3 and 5 of the expansion header. The power is connected to VCC.

crazyflie-ublox

The electronic was already tested and working so we had 2 tasks left:

  • Decoding the GPS information in the firmware and creating log variables to make the data available for the PC software
  • Updating the GPS tab of the PC software to fetch GPS data from the log subsystem instead of parsing it from the text console

It happens that these two tasks could be done mostly independently and Marcus and I started to work in parallel. The only thing we had to agree upon was which log variable and what scaling to use for the variables. We used the format that the GPS chip is already using which made things easier.

Firmware

For the firmware part, the first step was to acquire the GPS data. GPS chips usually can talk two languages: the standard text-based NMEA and some kind of proprietary binary format, UBX for uBlox. I chose the binary format as it is a lot easier use in C: no text parsing has to be done, all data dirrectly fits in a C structure. But first the GPS has to be setup to output data in binary modes and to output the data we were interested in. To quickly setup the GPS I used a tool that uBlox provides and that permits to generate proper UBX messages:

u-center_msg

Two UBX messages where required: One to disable NMEA output and one to enable the NAV-PVP message which contains basically all data you would want from a GPS (position, speed, date and the accuracy). Once this is sent to the GPS chip it starts to send a NAV-PVP UBX packet once a second. Then, the GPS acquisition loop in the Crazyflie (currently implemented in the UART task, so it has to be moved into a proper driver) just has to wait for an UBX packet, read it and if it is a NAV-PVT packet then extract values from it. The GPX code has been tested on PC using another uBlox receiver connected to a USB serial cable. Then after copying the newly added uartReceiveUbx() function  into the Crazyflie firmware, the GPS acquisition loop looks like this:

  while(1)
  {
    uartReceiveUbx(&msg, 100);

    if (msg.class_id == NAV_PVT) {
      gps_fixType = msg.nav_pvt->fixType;
      gps_lat = msg.nav_pvt->lat;
      gps_lon = msg.nav_pvt->lon;
      gps_hMSL = msg.nav_pvt->hMSL;
      gps_hAcc = msg.nav_pvt->hAcc;
      gps_gSpeed = msg.nav_pvt->gSpeed;
      gps_heading = msg.nav_pvt->heading;
    }

    ledseqRun(LED_GREEN, seq_linkup);
  }

The last thing, to make the data available from the PC, is to add a GPS log block and to add variables to it:

LOG_GROUP_START(gps)
LOG_ADD(LOG_UINT8, fixType, &gps_fixType)
LOG_ADD(LOG_INT32, lat, &gps_lat)
LOG_ADD(LOG_INT32, lon, &gps_lon)
LOG_ADD(LOG_INT32, hMSL, &gps_hMSL)
LOG_ADD(LOG_UINT32, hAcc, &gps_hAcc)
LOG_ADD(LOG_INT32, gSpeed, &gps_gSpeed)
LOG_ADD(LOG_INT32, heading, &gps_heading)
LOG_GROUP_STOP(gps)

Debugging the firmware code can be done using the client log plotter tab, not so nice to look at positioning but good enough to see if it is working (when the accuracy, gps.hAcc,  goes down the GPS has a fix!):

gps_graph_fix

Client

Once the log block was decided, Marcus could start the client development by updating the debug driver. The debug link is a module of the Python client that behaves like a CRTP (the Crazyflie protocol) link but is in fact just some software running offline. It allows to easily develop and debug the client without requiring the usage of a Crazyflie. The debug link was modified to include all variable that the Crazyflie would eventually contain and to give them some value that can be logged.

When this was done, the GPS tab has to be updated to display actual values, a max speed and reset button is also added (the idea was to measure the Crazyflie speed). After fighting more than expected with the QT layouts the result is good enough:

vm-gps-debug

Note that the client uses the Python binding of KDE Marble which has to be compiled manually. Only Marcus has had the courage to do that on his computer, but luckily he also compiled it on the latest Bitcraze VM so that we can all easily enjoy the new GPS tab :).

Merge

Now that the client and the firmware are made separately we ‘just’ have to connect the new client to the new firmware. And guess what? it worked the first time :-) (Yes I know you have no reason to believe me but this time it really worked the first time).

Unfortunately for us last Friday was one of these Swedish rainy day, all we could do was to take turns to stand in the middle of the road outside of our office, in the rain, holding the Crazyflie in a plastic bag and waiting for the GPS to get a fix (people passing by were looking quite strangely at us …). It happens that the rain where not helping at all! And the fact that we don’t have assisted-GPS (yet) means that the GPS would get a fix in 40sec best case, it took about 5-10minutes for us. But eventually we got the fix:

gps-test-fix

Conclusion

One thing we have to work on is the modularity of the firmware. Things like having a clear and easy to use HAL for peripherals on the extension port. It is on our ToDo list and it would have been useful here to do a cleaner job with the firmware implementation. A good thing is that while this implementation is uBlox specific for the firmware part, it is completely hardware-independent on the client side. It means that it is possible to implement any kind of positioning, with other GPS chip or other technology, and as long as this positioning declares the right log variable the client will work with it unmodified.

As for the GPS, uploading assistance data to the Crazyflie would permit to drastically reduce the fix time to about 10-15sec. Also this GPS is capable of 10Hz update rate which would be nice to test. The GPS on a Crazyflie is still mostly a proof-of-concept and is of course not useful for indoor flight. Though with light winds the Crazyflie is pretty capable outdoor, so with GPS capability it could be interesting to experiment a bit with trajectory planing. Of course this is even more true for country with a warm and dry weather :-).

The Crazyflie 10DOF has a pressure sensor that can be used as an altimeter. This sensors was waiting to be used and we had many contributors implementing altitude hold/hover mode for it. We recently merged one of the best working contributions to the main branch of both the Crazyflie client and firmware so that it is now a bit easier to experiment with it. The current code is based on the work done by omwdunkley who did a great initial job and you can read more about it in his post.

The altitude-hold is another control-loop that will try to keep the copter at the same altitude by using the altimeter and the accelerometer to sense the altitude and vertical speed. This is controlled by keeping a button pressed on the game-pad. When altitude hold is activated the thrust joystick axis controls the altitude set-point and thus are used to make the copter rise or fall.

Foam on the Crazyflie 10DOF altimeter

Foam on the Crazyflie 10DOF pressure sensor

From our test in a calm pressure stable room the altitude is held at roughly ±15cm. However we had some problems when we where moving around. The Crazyflie sometimes suddenly rose and went to the ceiling. After some debugging we found that the problem was mainly physical, the pressure sensor is exposed of dynamic pressure when flying. To fix that we cut some of the foam we have in the Crazyflie box (yes that was planed all along ;-), and we stuck it on top of the pressure sensor. Doing so greatly improve the stability when flying more aggressively! (Something we kind of knew from peoples suggestions but it is nice to see it working in reality)

This functionality still require some debugging, tuning and code clean-up, but if you want to test it just grab the latest version of the firmware and client from Bitbucket. To begin with check that the altitude hold function is well configured for you joystick mapping (we found that it is best set on the shoulder button of the thrust hand). The altitude lock will be activated as long as the button is pressed. It can be pressed while the copter is flying or while it is in the ground. If pressed when the copter is in the ground, you will have to press the thrust joystick up a bit to make the copter fly higher. We also recommend to be a bit experienced with flying the Crazyflie as the altitude hold sometimes requires a quick recovery manoeuvre ;-).

The Crazyflie project started as a competence project in a Swedish consulting company called Epsilon (now called ÅF). The first blog, Daedalus projects, was the competence-group blog. When crazyflie became more than yet another competence project we created our own website but Epsilon/ÅF graciously allowed us to still use the same server. We thank Epsilon/ÅF for the support but we thought it was time to be independent.

Since this week-end all the Bicraze public services run on our own server, the wiki and blog where the last pieces to move. There should be no noticeable difference except than we seems to have slightly more power now. We also are able to ramp up the server power in minutes if we ever get on Slashdot ;-).

Tell us if you see any problem or if the website suddenly became slow. Next step will be to improve the website front-page to make it more informative.

Thanks to some of the motor mount feedback we have now managed to improve the motor mount a bit. It now has a longer extruded cylinder and a larger stop to prevent the motor form popping out when landing hard. This should add a bit more protection but it is still a good idea to do one of the mods described in the wiki for even better protection, especially when expecting to do some hard crashes.

Motor mount v2

Motor mount v2

The improved motor mounts will be available in the next batch of kits, which is still scheduled to be ready in the end of June, and also as a separate spare part item. For the next batch the Crazyflie kit without the Crazyradio and antenna will also be available for ordering.

On another note we are planning on modifying our webpage a bit. We feel that when new people visit our webpage they get no overview of our projects. So we are planning a nicer landing page with some images and more general information. We will of course keep the blog and also keep updating it at least every Monday. Aside from this we are also planning on integrating the forum and wiki with the blog and also have the same theme. After doing a quick test with the forum we are pretty sure our green/black theme will look good, but we aren’t that convinced about the wiki…. Let’s see where we end up. If you have any suggestions or comments about the webpage and our plans then  don’t hesitate to leave a comment below.

Lastly we have also installed TapaTalk on our forum. So if you use the TapaTalk app you can find our forum in the directory by searching for Bitcraze.

Even though controlling the  Crazyflie with a PC is quite unique and permits a lot interesting things to be done, like controlling Crazyflie with a webcam or getting realtime telemetry, we have also been looking at controlling it with a, pc-free, standalone controller.

Current (unfinished) implementation of a standalone controller are using Crazyradio as a PPM to CRTP converter, a very experimental Android app, and using a raspberry pie as ground station. This week we finally managed to fly Crazyflie with an E-Sky transmitter:

Crazyflie standalone controllers

The transmitter is using a nordic-semiconductor chip compatible with our radio. The protocol is also well documented by dvdouden et al. It is using a power amplifier and uses a channel hopping scheme which makes the radio link quite secure.

Code to support this has been in the repo for a couple of week but a problem was that, by default, this transmitter was mixing pitch, roll and thrust channels which made the control of our Crazyflie nearly impossible (pitch and roll was changing by increasing the thrust ….). This week-end, we discovered two switches in the battery compartment, with which you can disable the mixing, and by doing that suddenly the Crazyflie is flying! There are still some work left to make RC transmitters works as good as a gamepad but the current source code is good enough to fly. Overall we have observed that a gamepad is really ideal to fly the Crazyflie in a fast and dynamic way. By comparison RC transmitter benefit by having more precision, mostly for the altitude control, but we are not used to it and it does not feel that ‘fast’ (our opinion).

As for the pre-order production, it is still going forward as planed. Testing of the first production samples  are finalized and now all the PCBs has been manufactured. The expected time of shipping is still according to the Seeedstudio Crazyflie product page.

We just received the first 10 sample boards from the production at Seeedstudio :-D

DSC_0210e

So far we got time to test only two boards and they are working. We have finalized the firmware, bootloader and production scripts so now it has really started :-)

Nothing new exiting about the production, it is still going as planned :-). Meanwhile we are focusing on stabilizing the Crazyflie firmware and its side projects.

This weekend we fixed a bug related to the memory allocation, which we have had a while now and that we never had time to track down. It kind of forced us to use heavier machinery so we decided to setup eclipse for debugging FreeRTOS threads and it happened to be very useful.

Since version 0.5 OpenOCD contains a rtos-awarness mode for FreeRTOS and, when painfully configured in eclipse, this allows us to observe the stack trace and the running state of all the tasks running on Crazyflie:

eclipse-threads

This helped us to track-down the bug much quicker and will greatly help us in the future. We also found a eclipse plugin, embsysregview, that enables one to show and analyse the peripheral register values, great little plugin!

The virtual machine will be updated with the debug environment and we will try to update the Wiki with the setup procedure.

The community interest for FPV flight made us buy a light weight analog FPV kits a while a go. We bought the 5.8GHz micro combo set from fpvhobby to do a first test. It took a little while to solder things together but it wasn’t that bad. We soldered the camera and the transmitter power to the VCOM voltage on the Crazyflie which is available on the expansion port. Then we taped the camera and transmitter to the Crazyflie and did a test flight.  The FPV kit is only about 3 grams which doesn’t affect the flight performances that much.

It was almost too easy, but as soon as we took off we noticed some vertical lines on the TV so maybe it wasn’t that easy. There seems to be some electrical interference, probably from the motors. Also the battery voltage drop generated by fast accelerations cuts the video feed after a couple of minutes of flight. We still think that there are some improvements to be done so hopefully it will work better in the future.

As for the production, so far it is still going forward as planned.

Finally an Alpha version of the virtual machine has been posted on the forum, you are welcome to test and report any problem/suggestion you may have :-).