Getting the Wi-Fi Streamer Working on the AI Deck: Challenges and Solutions

I've spent the last few weeks battling with the Wi-Fi streamer on the AI deck, and I'm happy to report I finally got some images streamed to my PC! It wasn't easy, and I expect more challenges ahead, but here's my experience so far and where I'm headed next.
Assembling and flying the Crazyflie
The initial assembly of the Crazyflie 2.1 was straightforward - I simply followed Bitcraze's official documentation. Connecting to the drone using their mobile app was quite easy, but actually flying it this way proved surprisingly difficult. This worried me initially, but I decided to push forward.

Radio Setup and Client Installation
The next stage was flashing the Crazyradio 2.0 firmware. Again, this wasn't particularly challenging, and the Bitcraze documentation walked me through it clearly. Installing the Client on my PC worked immediately - I connected to the Crazyflie right away and was able to control it. I bought a cheap Xbox controller which made flying the drone significantly easier than using the mobile app.

One thing I noticed was that the Crazyflie has quite a bit of drift during flight. Adjusting the trim values really helped stabilize the drone so it could hover properly. I imagine in future autonomous applications, this drift could become a problem and potential source of collisions if the drone's path isn't adequately in its field of view. I even played with manually balancing the drone by moving the battery slightly in its slot, which also affects the drift characteristics.
Installing the AI deck
Installing the AI deck physically wasn't an issue however following these instructions is when I started to have difficulty.

Updating the Crazyflie and AI deck firmware went off without a hitch. The biggest hurdle came when I ran into the GAP8 bootloader problem. My over-the-air flashing attempts kept freezing at either 4% or 99% and never completing—a tell tale sign of an outdated bootloader from the factory. After confirming this was indeed the issue, I had to order an Olimex ARM-USB-TINY-H JTAG debugger, along with the ARM-JTAG-20-10 adapter cable and a standard USB Type-A to Type-B cable to connect everything together.
With the hardware in hand, I tried using the 2023 VM from Bitcraze to flash the bootloader through Docker. Big mistake. The process kept failing or hanging, and I soon realized why: even though the virtual disk appeared large enough, the actual Ubuntu partition (and its LVM volume) inside the VM was only around 20GB with almost no free space left. The Docker pulls and build/flash steps simply couldn't complete because there wasn't enough room.
I spent hours trying to fix this - resizing the VirtualBox disk with GParted, extending the LVM physical and logical volumes, and desperately cleaning up Docker images to free up space. I even managed to get more space showing as available, but the process still failed with low-disk-space errors. This whole side quest into Linux volume management was interesting but ultimately a waste of time.
The solution turned out to be much simpler: ditch the 2023 VM entirely and fall back to Bitcraze's 2022 VM image instead. This older version came pre-configured with ample disk space and all the right tools already installed. As soon as I switched, the flashing process worked smoothly. When I finally saw "flasher is done!" in the terminal, it was a genuine relief.
Finally Going Wireless
After fixing the bootloader, I could finally flash over-the-air via Crazyradio, which was a huge relief. I uploaded the WiFi streamer binary (aideck_gap8_wifi_img_streamer_with_ap.bin
) wirelessly without needing to reconnect the JTAG cable. The bootloader fix was a one-time hurdle that unlocked this much smoother workflow—though I wish Bitcraze would update their factory process to avoid shipping with outdated bootloaders in the first place.
Environment Conflicts and Virtual Environment Solutions
I found the solution for the incompatibility between the OpenCV-based image streaming code and the Crazyflie Python client fairly quickly. This is a documented issue:
When run together, Python crashes with errors related to threading and OpenCV conflicts. The solution was straightforward and predictable: create separate virtual environments for each component. This is a standard approach for handling Python package conflicts.
This clean separation worked perfectly. When I needed to connect to the Crazyflie for configuration or flashing, I'd activate the cfclient environment. When viewing the camera stream, I'd switch to the vision environment. It's a basic practice in Python development to keep conflicting packages isolated, and in this case, it solved the problem effectively with minimal effort. Unlike the bootloader issues, this was one of the easier challenges to overcome. The solution was expected and implemented without complications, allowing me to move forward with the more complex aspects of the project.
First Images!
Before I could get to the streaming part, I needed to clone the example repository:
This repository contains all the example code for the AI deck, including the WiFi streamer example that I needed. After following the bootloader flashing process and flashing the WiFi streamer firmware to the AI deck, it created its own WiFi network called "WiFi streamer example."
I connected my laptop to this hotspot, activated my vision-env environment, and ran the Python-based OpenCV viewer Suddenly, I was seeing actual images from the camera on my screen!

After a few seconds the stream freezes and stops. I ran the code again after rebooting the Crazyflie with the same result. This also appears to be a known issue that needs more of my time.
Next Steps
- I'm planning to tweak the frame rate, resolution, and buffer settings in both the firmware and viewer code to reduce the freezing issues.
- Once the image streaming is reliable I can begin to work on the obstacle avoidance part of the project
- While not talked about in detail I also attempted to setup the GAP8 development environment. This is ongoing work with many issues that I need to write up in detail later.