Programming my Tello Drone with Arduino and Goodwill

Programming my Tello Drone with Arduino and Goodwill

Among all the impulse purchases of this year, my quadcopter is one I don't regret at all. In general, I was always fascinated by drones (it's understandable, they are flying robots after all) and I like programming stuff - so I decided to get the best of both worlds and go buy my own. The market offers a few alternatives, but my ideal drone had to feature the following must-haves:

  • it would be programmable in a full-fledged language like C or Python
  • it would have at least a camera, and maybe also some other sensors, and they should be accessible via some API
  • it should be compatible with some kind of modular, plug-and-play hardware

The TelloTalent from DJI matched all the above requirements. What really got me was seeing the flashy LED screen packaged with it and all the cool projects made by the community: there are people controlling the drone with their hand or body movements, developing autonomous flight plans using visual markers, and even repurposing it with random stuff like bar-code scanners. This repository gathers many cool projects from the community and I recommend giving it a look: the possibilities are endless.

On the other hand, I must admit that this drone is in practice a little more than just a fancy toy - which is not inherently bad, of course. It's clearly targeted for educational purposes only: for starters, forget about flying it outdoors and prepare for an awfully short battery life span. However, it still does an excellent job for its own purpose and, in my opinion, it provides a lot of value.

Components and SDK overview

As mentioned above, the Tello Talent comes with a hardware module containing an ESP32 microcontroller, a LED, and a matrix screen. The drone itself can be controlled by connecting via WiFi, or by sending commands to the USB serial port.

Source: www.dji.com

DJI offers an official cockpit app to fly the drone around and capture some images, but nothing prevents you to build your own: in fact, it is possible to interact with the drone thanks to a text-based SDK. An excerpt from the command list is shown below. More info can be found in the official documentation here.

Command NameDescription
commandEnters in SDK mode
takeoffAuto takeoff
landAuto landing
up xAscend to "x" cm
down xDescend to "x" cm
right xFly right for “x” cm
left xFly left for “x” cm

My goal was simple: control the drone from the microcontroller only, from a script that I would develop in C and then flash into the ESP32 ROM memory.

Developing a flight plan

Setting up an Arduino IDE to work with the ESP32 was not easy as I thought: the documentation is not clear, the examples are scarce, and unfortunately often from Chinese-speaking contributors. However, after a couple of attempts, I was able to download the correct drivers and make them work in my Arduino IDE. On a brighter note, the helper packages and examples from the TelloTalent developers were extremely useful as well since I am not an experienced C programmer - and surely not of the Embedded Systems flavor anyway.

There are two important methods available: setup and loop. As the names suggest, they are respectively used for the initial drone startup phase and for the main behavior loop. As I wanted to execute a brief 30 seconds routine, I put all my logic into the setup section. It is also possible to use the setup function to stay idle and wait for a specific event (e.g. a button is pressed, or a specific command is received), before entering into the main loop. Anyway, I developed a basic flight plan to get started:

As can be noted here, the tt_matrix and tt_sdk packages are doing the heavy lifting. The tt_sdk is a straightforward interface that decouples the high-level SDK commands from the serial port connection and data transfer; on the other hand, tt_matrix deals with low-level operations to access and write to the LED screen registries. Speaking of which, it was due time to tinker with the little lights.

Animating the LED screen

After creating a flight plan, I wanted to make this project a bit more personal with a custom animation on the drone's screen. The ESP32 chip on the TelloTalent comes out of the box with an 8x8 LED matrix, which is enough to show a bit of text and render some simple sprites. I decided that my drone would fit perfectly with the theme of aliens and spaceships, and should become a monster from Space Invaders 👾.

Now, the documentation on the TT is not super accessible, but some reverse engineering showed that the screen features two color channels - blue and red. These two channels can be independently set (and mixed) on each cell on the screen, and their luminosity can be configured on 256 different levels of intensity. With this information, I was finally able to sketch my beloved alien monster in two alternating sprites:

Finally, I wrote a simple method to animate the UFO:

The sprite_a and sprite_b are just matrixes with constant values, respectively modeling one of the two alien sprites.

Enabling parallel execution

I had a flight plan and a way to animate the sprites on the screen. However, since the move_sprite method had a blocking infinite loop, it would never allow for the flight plan to execute. How could I instruct my Tello to do both things at once?

Fortunately, the ESP32 microcontroller comes with a set of useful RTOS APIs, such as xTaskCreate and its multitasking capabilities:

BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,
                       const char * const pcName,
                       configSTACK_DEPTH_TYPE usStackDepth,
                       void *pvParameters,
                       UBaseType_t uxPriority,
                       TaskHandle_t *pxCreatedTask);

The xTaskCreate takes a reference to a function (a new "task") and adds it to the queue of tasks ready to run: the OS will then manage the concurrent tasks by alternating between them, for example by taking advantage of the time spent waiting for I/O operations.

The most important arguments here are pvTaskCode, which is the matrix handler function name, and usStackDepth, the depth of the stack that the target task will need to execute: I admit that I just guessed the appropriate value here after failing a couple of attempts, choosing at the end a multiple of the minimum stack size allowed:

xTaskCreate( move_sprite, "Move Sprite", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY, &xHandle );

Finally, I could bring everything together in a single script:

The little UFO was now ready for take-off!

Conclusion

Programming my Tello drone to follow a simple flight plan while interacting with its LED screen was a very fun experience, and a way to grow out of my comfort zone: dealing with software near to the "metal" and with real-time constraints, understanding drone stuff and, above all, managing to make sense of scarce and sometimes obscure documentation by virtue of reverse-engineering and translating from Chinese 🤓.

All in all, with a little imagination and goodwill, the Tello can provide a vast source of side-project ideas and unique challenges!

References