BradWii on the Hubsan Q4

In which the author runs open source firmware on a palm sized quadcopter

Similar projects worth following
BradWii, an open source alternative firmware for multicopters, runs on inexpensive "toy" quadcopters based on Nuvoton Mini54 ARM Cortex-M0 processors such as the Hubsan H107 and JXD JD385. Despite having a different form factor, the tiny Hubsan Q4 (also sold as Estes Proto-X) has nearly identical hardware as the H107. Because of its size, Hubsan abandoned the 4-pin header footprint for factory programming of the CPU in favor of irregularly spaced pads.

This is my try at porting BradWii to the Q4 and a way to program the port to a new Q4.


Because it can be done, it's an opportunity for me to learn, and it opens up the possibility for someone to do something unexpected.

BradWii doesn't offer much over the original firmware. In fact it takes away the trick flip features of the original. The features it does bring are mostly lost on the Hubsan Q4. The Q4 is too small for any significant payload, so using it to add GPS, magnetometer, or cameras isn't practical.

Don't do this to your Q4 if you think it's an upgrade. You'll be disappointed at best.


Most of the process is in the logs even though I was mostly done when I posted this to

As of now there's a 3D printed SWD pogo pin jig, openocd setup to unlock and flash the micro, bradwii modified to build under GCC using make, and my Q4 flies about as well as stock to my untrained thumbs.

The Future

I'm done with this project. Not enough time, too many other projects.

If anyone wants to pick this up, here's what's left of my todo list:

  • Put OpenOCD patch and target script in separate github
  • Document:
    • setting up build env
    • setting up OpenOCD
    • building the jig (done)
    • building fw
    • flashing fw
    • using semihosting
  • Find a better way for arm/disarm that works w/ the original 4ch remote


  • Configure with UART-less MultiWii protocol over
    • semihosting
    • Unused RF protocol channel
      • with high-end TX training port
      • to PC with simultaneously paired radio module
  • Servo control with PC camera tracking, using LED patterns as fiducials
  • Add heading hold

  • 1 × Hubsan Q4 The victim. Rebranded versions like the Estes Proto-X also work.
  • 1 × 3D printed debug jig from until I move it to github
  • 1 × STLink/v2 SWD debugger Either the built-in STLink/v2 on a STMicro STM32 Discovery board or a dedicated STLink/v2 pod. Nucleo might work but is untested. Other SWD debuggers should work too with changes to the OpenOCD script
  • 4 × SparkFun PRT-9174 pointed tip pogo pin Consider getting 5, these can be fragile. The rounded tip version may work as well, but the pointed tip will deal better with dirt.
  • 1 × Wires to connect the pogo pins to the debugger I used an old CD-ROM audio cable cut in half. You could use 2 Dupont F-F jumper wires cut in half, or whatever else, as long as it can be soldered at one end and plugged into the right signals on your SWD debugger

View all 7 components

  • Works fine, but what do I know?

    ajlitt03/16/2015 at 04:14 0 comments


    The weather was nice enough yesterday to try autotuning outside. The battery held out for about a minute each of pitch and roll tuning and long enough to write the results to EEPROM to dump out at home. I ended up with PIDs that seem to work great for my Q4 as defaults in the code. It flies just about as well as I remember the stock firmware behaving, which given my untrained thumbs is like saying Apple earbuds sound as good as $30k Sennheiser Orpheus headphones. It even works with the original remote.

    There's still work to be done: change PID tuning TX channel to something less destructive, more code cleanups (most importantly pull from victzh's latest commit), better documentation, test unlock procedure on a new Q4.

  • Recap #6: Moving slowly

    ajlitt03/16/2015 at 04:03 0 comments

    I went a few rounds with PID autotuning in the living room after the kids were asleep. It's been constant nasty weather for the last few weeks, so I couldn't get outside so the Q4 could have more room for its autotuning dance.

    Meanwhile I discovered the LED mappings for both the X4 and Q4 weren't right, I merged Q4 and X4 configurations together as much as possible, and found the right scaling factor for the battery voltage.

  • Recap #5: Abusing the debug port

    ajlitt03/16/2015 at 03:50 0 comments

    So it turns out BradWii can do autotuning of the PID coefficients. It pitches and rolls +/- 15 degrees, systematically varying each coefficient until it converges. Once the tuning is done, the new coefficients can be saved to EEPROM. Autotune is started, stopped, and parameters saved using an extra TX channel so that it can be started when the quad is hovering in an open space. The consensus is that the BradWii autotuning is very effective as long as the initial PIDs are good enough to get into a hover.

    I planned to use autotuning to find workable PID coefficents and pull them out of the EEPROM with the debugger. I bought a Hubsan X4 for its remote (now I'm in deep...) which is compatible with the Q4 but has a couple of pushbutton channels, one of which I'd use to control the autotuning. But not long after I started playing with autotune I realized that the battery voltage ADC wasn't tripping the low battery detection at all. I needed to know what the ADC was reading, and while it could be done with memory inspection it would be easier if I had a stdout to printf to...

    Fortunately ARM specifies a standard for "semihosting", or sending arbitrary data between the debug host and target applications via the debug port. The standard specifies fairly straightforward stdio and file operations that the target application can ask the debug host to perform. One of these prints a null-terminated string to the debug console. This was exactly what I needed.

    I added some inline assembly functions to the serial driver so I could later pipe the UART configuration protocol over SWD. But for now printfs to the screen would be enough. I also had to make the breakpoint ISR check that the breakpoint was for semihosting so it could continue execution if the debugger wasn't attached.

    Semihosting works ok in practice if you know the limitations. Or limitation. Semihosting is incredibly slow. It's transferring a 1k file over a 300 baud modem slow. But it's enough to print the autotuned PID parameters from EEPROM on power-up and to print the ADC raw value for debug.

    This was the last piece in making BradWii autotuning work and find the right mapping of battery voltage to ADC counts.

  • Recap #4: Flying

    ajlitt03/16/2015 at 02:50 0 comments

    I ran into a couple of roadblocks in the week since barely getting Bradwii loaded:

    BradWii for X4 was configured to arm the motors if the yaw is all the way to the right and the throttle at 0. The stock TX has a range too narrow to hit the default thresholds. The stock TX's case has rounded edges in the stick cutout so the values at the corners are lower than at the extreme of one axis. To get around this I changed the arming combination to low throttle + high pitch and decreased the thresholds until they worked reliably.

    I got the Q4 to arm, and the props turned at low throttle. But trying to fly resulted in an instant barrel roll. It took a few days of trial and error, but I eventually realized I had mapped the motor PWM channels 180 degrees from the orientation of the sensors. With fixed motor channels I got the Q4 to hover for a few seconds, but then the shakes set in and ultimately it would power dive into the floor. I hadn't changed the PID coefficients from the X4 defaults so I'm not surprised.

    On more formal quadcopters, the PID settings are tuned remotely during flight with a sideband channel, or with a serial cable on a fixture that allows the quad to rotate on one axis on the bench. BradWii has a feature to change certain parameters in realtime and save them to on-chip EEPROM, using the micro's UART for communication. Unfortunately the Q4 has no other external interface but the ARM SWD debug port and is too small to use the usual tricks for running tethered anyway.

    The pin map I made showed that the UART pads on the Mini54 were being used for radio SPI framing and the interrupt from the accelerometer, so I couldn't blue wire out the UART. One alternative I considered was using unused bytes in the Hubsan protocol and modifying the TX somehow. The Hubsan TX uses an STM8 micro, but even that board has its UART pins committed to other peripherals. It would also mean a descent into yak shaving as I would have to write my own replacement TX firmware. I also considered using [alvaro]'s work in putting the TX under PC control, but being a relative noob to flying RC things I didn't want to stray far from the handheld transmitter.

  • Recap #3: Bringing up BradWii

    ajlitt03/15/2015 at 05:45 0 comments

    I spent a few lunch hours poking at BradWii. Usually the ARM fork of BradWii is built in Keil, but TheLastMutt had added project files for Eclipse and GCC. I don't care for Eclipse, but for a small project I'd deal with it. I couldn't get the OpenOCD integration to work. But I discovered that Eclipse can convert its project format into Makefiles, so with exported Makefiles in hand I got the Hubsan X4 build of BradWii to build.

    But before any code could be written, I would need to know the pin mapping for the Mini54 to the peripherals. I traced out the pins mapping to the motors, LEDs, battery voltage monitor, gyro, accelerometer, and radio. I forked BradWii on github and made changes to the Hubsan X4 config and support sources to work with that pin map. Along the way I added a target in the main Makefile to erase flash and call OpenOCD for flashing.

    Good news is the LEDs blink on power up and change pattern when the TX is turned on, so at least the RX section and the LEDs work. Bad news is that's all it can do right now.

  • Recap: early work #2

    ajlitt03/15/2015 at 05:22 1 comment

    After a few iterations of the OpenSCAD model and a week of waiting for the pogo pins I ordered from Sparkfun to come in, I have a working jig. It turns out my photogrammetry was a little off, since it took a couple of iterations of the model to dial in the pin locations. This likely comes from parallax error since I didn't remove the motors when I scanned the board. I also had some problems getting the hole sizes right for the pins since the C and D pins are so close to each other that they wind up a little narrower than the other two.

    Next up I soldered wires to the pogo pins and hooked them to the STLink/V2 debugger on a STMicro STM32F0 eval board I had on hand. I found this guide by TheLastMutt for flashing and erasing the contents to remove the flash read/write lock on the Mini54 under OpenOCD.

    So what's with the flash lock? Like most micros the Mini54 has a similar feature, preventing most debug port operations including writing flash unless a bulk erase is performed first. Hubsan's firmware is written to the Q4 with this lock enabled.

    The code in the guide didn't work without some changes, one being the transport settings needed changing for STLink/V2, and the OpenOCD patch didn't have the right mask for the part ID. My changes in gist form.

    After I got OpenOCD and the part to talk, I erased the original firmware to get rid of the flash lock. Unfortunately the lock also prevents reading out the existing contents, so I was stuck with a dead toy until I could get some alternate firmware working. This is the part of the movie where the scientist infects themselves with the deadly mystery virus for motivation to find a cure. I knew that the BradWii firmware supported very similar quads but getting this to work would be a learning experience.

  • Recap: early work #1

    ajlitt03/14/2015 at 15:18 0 comments

    I bought a Q4 on a whim while browsing the local hobby shop. $30 is impressive given the individual components: CPUs in both the TX and RX, gyro, accelerometer, LiPo battery, motors, and 2-way 2.4GHz radios in the TX and RX. Add to that the part where it flies and it was an easy decision. I also remembered [Alvaro's] deep dive into the TX protocol on this model a couple of months back.

    Of course I had to take it apart when I got home. The Q4 is nothing more than a flying PCB with a battery and motors to keep a workable power/weight ratio. The only unnecessary component is the plastic canopy over the battery. This also covers the ICs on the top of the PCB, but leaves the bottom side exposed, including a number of test pads. Fortunately Hubsan was kind enough to label some of these "+", "-", "C", "D". Some Googling revealed that the "HBS002" CPU is really a Nuvoton MINI54 ARM Cortex-M0 CPU. I beeped out the pads, following the "C" and "D" pads to the SWCLK and SWDIO pins on the micro. "+" goes to the 3.3V output rail of what looks like a linear regulator.

    I had to go further. I considered soldering to the pads, but thought that even a small header dangling off this copter would affect flight performance. Given the ease of getting to the pads, I decided to make a pogo pin jig using my go-to physical toolchain of a 3D printer and OpenSCAD.

    I started on this by getting the positions of the pad centers. The pads aren't evenly spaced, so I needed to measure positions for each relative to a central point. I scanned the bottom of the Q4 on a flatbed scanner and used Gimp and calipers to turn the scan into distances relative to one of the corners.

View all 7 project logs

  • 1
    Step 1

    Build the Jig

    1. Get 4 (or more) SparkFun Pogo Pins and any STMicro Discovery board with STLink/v2.
    2. Get some wire to connect between the jig and STLink/v2. 3 pins (SWCLK, SWDIO, GND) will go to 3 neighboring pins on the SWD header of the Discovery, and 1 (3.3V) will go to one of the IO breakout pins. Preferably this would be bare wire on one end and 0.1" Dupont single pin sockets on the other, but use what you've got.
    3. Print the model here. The holes are on the small end for FFF printing and need some care in printing. You might need to regenerate from OpenSCAD to get the holes tight enough that all the pins stay centered.
    4. Solder the bare end of each wire to the body of the pin 3mm below the hole where the plunger slides. Make sure to keep solder off the plunger and the sliding joint.
    5. Fit the pins in the jig. DO NOT FORCE THEM IN. They will break. You did buy a spare, didn't you?
    6. Load a Q4 / Proto-X (powered off of course) in the jig to see if the pins hit their targets, making sure to get the right orientation.
    7. If the pins line up but are a bit loose in the jig, use some carefully applied hot glue to fix them to the jig. Also it can't hurt to glue the wires to the jig as a strain relief.
    8. Connect the wires to the STLink/v2. Use the pads on the Q4 as a guide. "C" should connect to SWD header "SWCLK", "D" should connect to SWD header "SWDIO", "+" should connect to the "3V" pin or any similar 3.3V supply on the breakout headers (depending on your board), and the unlabeled pad should connect to the ground pin on the SWD header.
    9. Follow the directions in the user guide for the Discovery board to disconnect the target CPU from the onboard STLink/v2. Usually this involves removing two jumpers, but each board may be different.

View all instructions

Enjoy this project?



Jobyro wrote 11/19/2016 at 14:37 point

also, is it possible to program it using an arduino uno? Thanks again

  Are you sure? yes | no

Jobyro wrote 11/19/2016 at 14:34 point

hello, I am wondering where this project is at now? I bought a proto x with the hopes of being able to hack it to have an open source firmware. o you happen to have the firmware file that you built still? Thank you in advance.

  Are you sure? yes | no

Anton wrote 10/20/2015 at 08:37 point

That's an interesting dock! I suspect that you were at least thinking about teaching it automated takeoff and landing directly onto the charging dock. A simple IR based auto-docking guidance system would probably be a part of the solution, but getting a solid electrical contact appears to be a problem on your current design (velcro seems to be your workaround). Have you tried using magnetic electrical contacts to assist the docking and undocking process?

  Are you sure? yes | no

ajlitt wrote 10/20/2015 at 13:54 point


Unfortunately that's well beyond me.  The pogos aren't aligned tightly enough to hit the test points on every insertion, so they're limited to "safe" (behind the 3.3v regulator) parts of the board.  I'd be afraid of the splosions I'd cause from trying to make contact with the battery terminals with the pogos.

They also need a decent amount of force to maintain contact, hence the velcro.  

The Bitcraze Crazyflie 2.0 (which I won for entering this into a contest here!) does have an optional wireless charging payload module (which I don't have) that can charge while sitting on top of any Qi-compatible charger.  Combine that with some sort of optical navigation (Wiimote sensor?) and you could potentially have it autonomously dock.  Though the Crazyflie doesn't need anything like the dock I have here since it can have firmware programmed through both microUSB and through the Nordic radio.  Very cool product, and I'd encourage you to take a look if you're interested in autonomous quadcopters.

  Are you sure? yes | no

deʃhipu wrote 10/20/2015 at 20:30 point

If I were to do this, I would just add contacts that would be larger and more widely spaced -- just for the charging. For instance, you could have it "sit" on a pair of wires, using a set of wire hooks -- they could extend quite a bit to the sides, giving you a lot of margin. Shutting down the motors for charging would make the whole toy hang from those wires, hopefully providing decent enough contact.

Add some way of navigating (IR beacons?) and you can have them automatically patrol your home and annoy your cat all day ;)

  Are you sure? yes | no

Adam Fabio wrote 04/08/2015 at 05:58 point

Oh wow - Finally some Bradwii work here on! I've been following the github repos on and off since it was first announced. (I have a soft spot for tiny copters). Do you have any updates on the project ajlitt?  I'd love to hear where you are with it now. 

  Are you sure? yes | no

ajlitt wrote 04/08/2015 at 15:03 point

Not yet.  I still want to get this entry in a state so others can try it out, which means fixing outstanding issues with my fork, checking in my OpenOCD patches, and updating this entry with a howto.  Work and non-work has kept me busy over the last month, but I should have some time to get this prettied up soon.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates