Reverse engineering a hoverboard

First things first, disassembly time! In the picture below we can see the different components making up the hoverboard. We can see two gyro boards, one main board and the battery.
Each gyro board contains a Cortex-M3 processor calculating its orientation from an MPU-6050 accelerometer/gyro sensor and sending it over UART to the main board, which is responsible for driving the motors.

8230091472677088076
Thanks to Drew Dibble's work we know that the UART lines run at 26315baud, with 1 stop bit, no parity and LSB-first. In the pictures below we see the serial bus and the IR sensors used to check if the user is standing on the board, which we will spoof with a bit of tape.

Using a logic analyzer we find, as Drew explained, that the instructions follow a pattern of six commands: 0x100, 0x0aa, 0x0bb, 0x0aa, 0x0bb, 0x055. The first command marks the start of the instruction, and the last is 0x055 if both IR sensors are blocked.

We captured data at various inclination angles in both directions to find out the values of the middle bytes. The table below shows the data being sent by the board when increasing the angle. For example, if the board is tilted a few degrees forwards, it sends the sequence 0x100, 0x053, 0x000, 0x053, 0x000, 0x055, which can be seen as 0053h or 83d.

Forwards (hex) Forwards (dec) Backwards (hex) Backwards (dec)
0x053
0x000
83 0x0C0
0x0FF
65472
0x06C
0x000
108 0x08C
0x0FF
65420
0x013
0x001
275 0x065
0x0FE
65125
0x0A8
0x002
680 0x061
0x0FD
64865
0x07E
0x005
1408 0x04C
0x0FB
64332
0x069
0x00F
3945 0x030
0x0F8
63536
0x07B
0x016
5755 0x0F0
0x0E0
57584

As we can see, when moving forwards the values go from 0 to over 5k, while going backwards the values would go from 65535 to about 57k.

Armed with this knowledge, we can easily map the input of a potentiometer to the range of speed desired, and control the motor from our favorite dev board!

5 thoughts on “Reverse engineering a hoverboard

  1. Bruno Duarte Reply

    By any chances have you dumped the firmware that goes on the STM32F mcu of the gyroscope boards ? I’ve accidentally erased mine while trying to read it 😛

    • Alvaro Post authorReply

      Ouch! No, sorry, I just hooked it up to a logic analyzer to get the protocol, I didn’t think of making a copy of the firmware.
      Have you tried extracting it from the other board and copying it to the one you wiped?

  2. Liu Reply

    The code on the GitHub seems different from your explanation here
    Should it be “motor1.format(9,SerialBase::None,1);” before you putc(256)?
    Why format twice? Will it work in this way?

    Here is the code on GitHub
    motor1.putc(00);//Start byte
    motor1.putc(sp[1]);
    motor1.format(8,SerialBase::None,2); //Expects 9bit, 1stop, receives 8bit,2stop -> MSB=first stop bit=1
    motor1.putc(sp[0]);
    motor1.format(9);
    motor1.putc(sp[1]);
    motor1.putc(sp[0]);
    if(motOn==1) motor1.putc(0x55);//End byte

    • Alvaro Post authorReply

      Yeah… that’s one of those *brilliant* comments that you think is perfectly clear until you try to understand it a couple of years later 🙂

      I think I wrote that as a hack because Mbed wouldn’t let me add a stop bit to the 9-bit port, so I instead added a second stop bit on the 8-bit port, effectively having 9+1 bits, where the MSB would always be ‘1’ (the first stop bit). That way to send the start byte ‘0x100’ I sent ‘0x00’ so that the sent value would be 1+00.

      Anyway I remember spending a good amount of time reading the values on the logic analyzer and trying different things until I got it to work, and once it did I didn’t touch it.

      You could of course try using “motor1.format(9,SerialBase::None,1);” it’s perfectly possible that it has been solved in the meantime 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *