Close
0%
0%

DJI FPV - 6S Battery Compatibility Mod [Part 1]

I'm trying to mod/recreate the DJI FPV battery to use regular 6S lipo batteries. In a first attempt I try to replace the lipo cells.

Public Chat
Similar projects worth following
The DJI FPV smart batteries are expensive and only allow a flight time of about 8 - 15 minutes. Due to the proprietary design, regular 6S lipo batteries cannot be used and there are no third-party offerings to address these issues.

Strangely, there are hardly any solutions to these problems from the community either. Or maybe I just didn't search well enough...

Inspired by projects from DuaneDegn, theosky, Reversing Entropy and BigBallVlogs I started experimenting with one of my three batteries. Here I will present what I have done so far and what my conclusions are.

Your ideas, advices and hints are welcome :)

Latest videos about the project: https://www.youtube.com/channel/UC9QQtYSpTLALFfDgfIlqKbg

Ref.:
https://hackaday.io/project/178299-dji-fpv-investigations
https://hackaday.io/project/182115-dji-fpv-6s-battery-diy-compatible
https://www.youtube.com/watch?v=1bSUWn0l7Kk
https://www.youtube.com/watch?v=MaxIl53lTQ8

Initial idea...

My initial research showed that DJI FPV smart batteries consist of an "smart" control board and an ordinary LiPo battery. They communicate with the drone via a three-pin plug and provide information about battery voltage, temperature, etc. Without these additional informations, the drone refuses to start the motors.

So my original idea was to separate the brain from the body. The LiPo battery control board from the LiPo Battery cells. My hope was that it would be possible to create some kind of a modular system. Use the original smart battery control board as the base module and add any LiPo battery pack as the second module.

To test this, one of my DJI FPV smart batteries had to be sacrificed...


Disassembly of a DJI FPV smart battery

There are already some pictures and even videos of the inside of the batteries. But I took a few pictures and that shouldn't be wasted.

Opening the battery case without damaging it is not easy (impossible?). It won't open after removing the two obvious screws. In addition to four clips, there is some sort of double-sided tape holding the battery cover in place. It took me a while to open it...

After removing the cover it was still not possible to remove the control board and the LiPo cells. The cells were additionally fixed to the bottom of the housing with double-sided adhesive tape. But the cells and the control board could be pulled out with a little effort and a lot of patience.

Now the time had come to separate the brain from the body. Besides the two main power wires and the six balancing wires, there was a temperature sensor that had to be carefully detached from the LiPo cells. The glue used to attach the sensor to the LiPo cells is very soft and can be carefully removed with a knife or screwdriver.



The prototype of a modular smart battery

After that I thought the hardest part was over. I soldered XT60 connectors to the main power wires and JST-XH connectors to the balance wires. A rapid test showed that the patient survived. In addition to a simple battery test, I tested the modified battery with the drone. Everything worked fine. I was able to turn on the drone and even start the motors. Nice!

In the next step, further battery cells should be tested. The first attempt was to use six Samsung INR18650 35E LiIon batteries as a 6S pack. Weighing around 250 g and with a capacity of 3500 mAh, this battery had almost the same weight (even lighter) as the original battery but with a much higher capacity. So I soldered six of these batteries together to give it a try. Soldering LiIons is not recommended and even dangerous, but I don't have a spot welder... To hold everything together I 3d printed a case for the control board and a seperate case the battery pack. Both could be screwed together to build the battery unit. However, I wasn't sure how changing the technology from LiPo to LiIon would affect the discharge process controlled by the "smart" control board.
(I know that the maximum discharge current of this kind of LiIon batteries is much lower than the maximum discharge current of LiPos. But it was just a test and I even hoped it would be enough for some slow and smooth flights.)



When things started to go wrong

So it was time to assemble the control board and the LiIon 6S package and to turn on the drone. After connecting the pack to the board, two of the status LEDs lit up for a few seconds. After a click on the battery test button, all four LEDs lit up, indicating that the battery was fully charged. Strange because it wasn't. After turning on the drone, everything seemed fine. But then I noticed that the battery status was highlighted with a red rectangle and the drone's status LEDs were flashing red. Not a good sign. Apparently the battery control board was smart enough to notice that something was not as it should be.

I decided to fully charge the LiIon battery pack with my balance charger, but that didn't...

Read more »

DumlFileTime.txt

12min duml communication between drone and smart battery with timestamps

plain - 1.19 MB - 04/14/2022 at 12:03

Download

DumlFile.txt

12min pure duml communication between drone and smart battery

plain - 909.08 kB - 04/14/2022 at 12:02

Download

  • Demystifying the communication protocol (3)

    AirCruiser06/01/2022 at 09:53 0 comments

    Finally, coming to the point: The important commands...

    As I mentioned before, the authentication process is a big and still unsolved problem. Without proper authentication, the drone will not start the motors. But there is a workaround that I will discuss in detail in the second part of this project. So let's focus on the other parts of the communication. Sure, all messages are important in some way. But it seems most of them don't need to be understood. Using recorded data fields seems to be enough to respond to requests from the drone without understanding all the details (or even a bit). Of course, replying the entire recorded duml message is not enough. Why? The sequence numbers of most drone requests change, but it is important that the request and reply sequence numbers are the same, so they need to be adjusted. And even if a single bit of the message is changed, the checksum must also be recalculated. 


    Hashing the duml

    Since it is important to implement hashing correctly, I will say a few words about it. As mentioned in part 2, the hashes of the header and the entire duml message are CRC8 and CRC16 checksums with custom initial values and non-standard hexadecimal lookup tables. So most of the standard libraries won't work (I guess).

    Based on the sources mentioned, I wrote the following C++ code to calculate the checksum of the header. As you can see, the custom initial value is 119 and the non-default hexadecimal lookup table is {0, 94, ... , 53}. The duml message is passed to this function through the array of integers buff. CRC8 is only used to calculate the checksum of the header, so only the first 3 bytes are hashed. 

    int CalcCRC8(int buff[]){
      int value     = 119;
      int crc8      = 0;
      int LUTCRC8[] = {0, 94, -68, -30, 97, 63, -35, -125, -62, -100, 126, 32, -93, -3, 31, 65, -99, -61, 33, 127, -4, -94, 64, 30, 95, 1, -29, -67, 62, 96, -126, -36, 35, 125, -97, -63, 66, 28, -2, -96, -31, -65, 93, 3, -128, -34, 60, 98, -66, -32, 2, 92, -33, -127, 99, 61, 124, 34, -64, -98, 29, 67, -95, -1, 70, 24, -6, -92, 39, 121, -101, -59, -124, -38, 56, 102, -27, -69, 89, 7, -37, -123, 103, 57, -70, -28, 6, 88, 25, 71, -91, -5, 120, 38, -60, -102, 101, 59, -39, -121, 4, 90, -72, -26, -89, -7, 27, 69, -58, -104, 122, 36, -8, -90, 68, 26, -103, -57, 37, 123, 58, 100, -122, -40, 91, 5, -25, -71, -116, -46, 48, 110, -19, -77, 81, 15, 78, 16, -14, -84, 47, 113, -109, -51, 17, 79, -83, -13, 112, 46, -52, -110, -45, -115, 111, 49, -78, -20, 14, 80, -81, -15, 19, 77, -50, -112, 114, 44, 109, 51, -47, -113, 12, 82, -80, -18, 50, 108, -114, -48, 83, 13, -17, -79, -16, -82, 76, 18, -111, -49, 45, 115, -54, -108, 118, 40, -85, -11, 23, 73, 8, 86, -76, -22, 105, 55, -43, -117, 87, 9, -21, -75, 54, 104, -118, -44, -107, -53, 41, 119, -12, -86, 72, 22, -23, -73, 85, 11, -120, -42, 52, 106, 43, 117, -105, -55, 74, 20, -10, -88, 116, 42, -56, -106, 21, 75, -87, -9, -74, -24, 10, 84, -41, -119, 107, 53};
      
      for (int i=0;i<3;i++){
        value = LUTCRC8[(value^buff[i]) & 255];
      }
      
      crc8 = value & 0xff;
      
      return crc8;
    }

    My version of the code to calculate the CRC16 checksum of the entire duml looks similar to the CRC8 code but is slightly different. We also have a custom initial value (13970) and a non-default hexadecimal lookup table ({0, 4489, ... , 3960}). But now the checksum is calculated over the whole duml. Except for the last two bytes which represent the CRC16 checksum encoded in the duml. Since the transmitted checksum is split into two bytes, I also split the resulting calculated checksum into two bytes to simplify the comparison. But that is a matter of taste and could also be done differently.

    void CalcCRC16(int buff[], int crc16[]){
      int value      = 13970;
      int LUTCRC16[] = {0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, 8450, 12427, 528, 5017, 26406, 30383,...
    Read more »

  • Demystifying the communication protocol (2)

    AirCruiser05/22/2022 at 11:20 0 comments

    Learn to speak dronish

    Since my last post, I've recorded many drone <> battery communications, trying to decode the vocabulary and grammar. As mentioned, https://b3yond.d3vl.com/duml/ is a good place to start to decode the DUML (DJI Universal Markup Language) messages sent between the drone and the battery. A major disadvantage of this website is that the data fields cannot be decoded. So you are told what the subject of the message is (e.g. battery request), but not the exact information that is being transmitted. Furthermore, since there is no official documentation of DUML and all knowledge about it is reverse engineered, this website is unable to decrypt every message. But this is a common problem of all sources I found.

    In this log, I don't want to discuss every aspect of DUML in detail. If you want to learn more about it, there are some really great resources. For example, a master's thesis by Thomas Christof and a related blog: https://epub.jku.at/obvulihs/download/pdf/6966648?originalFilename=true

    A great collection of different tools for DJI firmware that also covers DUML:
    https://github.com/o-gs/dji-firmware-tools/

    This includes the Comm Dissector, which can be used to analyze communication with the DJI drone via Wireshark:
    https://github.com/o-gs/dji-firmware-tools/tree/master/comm_dissector

    Also helpful if you want to learn how to decode and encode DUML messages:
    https://github.com/fpv-wtf/margerine/blob/master/src/packer.js

    With this sources and some great hints and advice (thx to Joonas and bri3d) I learned to decode and encode DUML messages by my own.


    Spoiler warning: In this log I will tell you many things that I have observed. But I really understand very few in detail.

    Structure of a DUML message

    DUML messages have a well-defined structure from which follows that they are at least 13 bytes long. There is a header, an address part and a data part. The hash of the header and the hash of the entire message are also transmitted (CRC8 and CRC16).

    Byte Bits Description Comment
    0 8 Delimiter Fixed value: 0x55
    1 + 2 10 Packet Length Length of the entire DUML [bytes] (little endian)
    C/C++: Length = ((duml[2] << 8) | (duml[1] & 255)) & 1023;
    2 6 Protocol Version Fixed value: 0x01
    C/C++: Version = (duml[2] & 252) >> 2;
    3 8 Header CRC8 Custom initial value (0x77) and non-standard
    hexadecimal lookup table
    4 3 Sender ID C/C++: SenderID = duml[4] >> 5;
    4 5 Sender Type C/C++: SenderType = duml[4] & 31;
    5 3 Receiver ID C/C++: ReceiverID = duml[5] >> 5;
    5 3 Receiver Type C/C++: ReceiverType = duml[5] & 31;
    6 + 7 16 Sequence Number 16 bit integer (little endian)
    C/C++: SeqNum= (duml[8] << 8) | (duml[7] & 255);
    8 1 Command Type Request: 0x00
    Response: 0x01
    C/C++: CmdType = duml[8] >> 7;
    8 3 Acknowledgement No ACK: 0x00
    Before Exec: 0x02
    After Exec: 0x03
    C/C++: ACK = (duml[8] >> 4) & 7;
    8 4 Encryption None: 0x00
    AES 128: 0x01
    Self Def: 0x02
    Xor: 0x03
    DES 56: 0x04
    DES 112: 0x05
    AES 192: 0x06
    AES 256: 0x07

    (DJI FPV only uses None (0x00))

    C/C++: Encryption = duml[8] & 15;
    9 8 Command Set Defines set of commands between sender and receiver
    10 8 Command ID Command to be executed
    11 : 10+n 8*n  Payload Data transmitted
    11+n : 12+n 16 Packet CRC16 Custom initial value (0x3692) and non-standard
    hexadecimal lookup table

    C/C++: CRC16= (duml[12+n] << 8) | (duml[11+n] & 255);


    As I know, byte decomposition, bitwise operations and things like that can be a bit confusing the first time. So I tried to show the translation of a duml massage into the values we are interested in a little bit more grafically. For this example we take the short duml massage "550E0466030BE322400D1900E0FE". In the upper row you find the byte and hex value information, below that the representation in bits. The background color of the bits indicates the information they represent. I tried to give each piece...

    Read more »

  • Little Frankenstein

    AirCruiser05/04/2022 at 16:53 4 comments

    Just a quick update

    I soldered all the components of my first test onto a perfboard. The display shows the voltage [V] and the current [mA]. Instead of the percentage, the glasses show the voltage (10x). Big and ugly, but it does the job. After some more tests and improvements I will design a PCB.

  • Nailed it!

    AirCruiser04/29/2022 at 00:49 1 comment

    With this modification, any 6s Lipo battery can be used without any modifications/hacks of the drone. Full compatibility with the original batteries is retained. I set the battery percentage to a random number that changes every second just for demonstration purposes.

    Details coming soon...

  • Demystifying the communication protocol (1)

    AirCruiser04/05/2022 at 21:56 0 comments

    Close, but no cigar

    As said, there are some rumors that the CAN bus is used for the communication between the battery and the drone. So I ordered a cheap logic analyzer and a suitable bridge circuit (CAN <-> serial) to analyze the communication and maybe mimic it. While waiting, I got my hands on an oscilloscope and wanted to check if these rumors are really true. But the measured signals made me a bit suspicious...

    The CAN bus is a new topic for me, but all the schematics I've seen so far looked a little different. In these schemes, CAN high never went to ground. In addition, the low maximum voltage of approx. 3.2 V made me a little nervous, since the bridge circuit I ordered had an operating voltage of 5 V. As I was told that the CAN bus should be tolerant to 5V and what matters is that the difference between CAN high and CAN low is at least 2V in the dominant state.


    But I was still afraid of frying my drone/battery so I decided to take a closer look at the smart battery control board. Unfortunately, most ICs were covered with a coating that made the labeling very difficult to read. After a while I could figure out all but one of the ICs. And none of them were capable of CAN bus communication. So it had to be the last one. I was able to gently scrape off the coating with a scalpel without damaging the label. After this I could recognize a SN65HVD75 which is a RS-485 communication IC. Ok, RS-485 instead of CAN. Very similar but not quite the same.

    With the help of the manual (https://www.ti.com/lit/ds/symlink/sn65hvd78.pdf) the communication pins A and B could be identified. As assumed, these pins are connected directly to the drone <-> battery connector.

    Using my logic analyzer I was able to easily measure the signal on pin A. Interpreted as asynchronous serial communication it turned out to be DJI's duml protocol.



    And now comes the hard part

    Right now I can read all communication between the smart battery and the drone. So far so good... But the goal is to mimic this communication so I can tell the drone what I want and the drone will accept that. To do this, I need to be able to read and understand the drone's requests and to respond accordingly. Also, I need to find out if there are any requests from the battery to the drone that the drone is expecting but don't ask for, "pings", etc.

    Sounds like routine work, but the problem is that the duml protocol is undocumented. It is mostly reverse engineered knowledge that is not complete. To dig a little deeper, I recorded 12 minutes of drone <> battery communication (16209 duml messages, downloadable in the files section of this project). Wireshark which was suggested to me is a great help to decode the messages. But there are still many unknown CMDIDs, data fields that I can't be decoded, etc.

    One example: A request from FLYC to Battery with the CMDID GetPushDynamicData (55110492030bb126400d02000000004b03) followd by ACK from Battery to FLYC with the datafield 0000765300006cfcffff7c070000cc0100004801061900000000030000001301640000470281020000" (5536043d0b03b126800d020000765300006cfcffff7c070000cc010000480106190000000003000000130164000047028102000064e4).

    So the question is: What does 0000765300006cfcffff7c070000cc0100004801061900000000030000001301640000470281020000 mean? Battery status? Battery voltage? LiPo cell voltages?

    Wireshark tries to decode the data field, but returns unrealistic values. The warning is another indication that something is out of date...

    As you can see, there is still a lot to do. I feel like I've only just started.

    If you want to help and participate, you can download the dumls and give me some hints or advices.

View all 5 project logs

Enjoy this project?

Share

Discussions

John wrote 06/29/2022 at 19:49 point

Very interesting project. my couple of thoughts about possibility hacking DJI FPV Battery. 

As I see it have another two ways for hacking ,one of them it is modify original BMS with chip bq9006 firmware for any elements like 18650 etc. another one is to root DJI FPV Drone system and modify original battery system file for switch off security identification/check original battery. As I know chip bq9003 already hacked, but bq9006 is on develop status. About root DJI FPV Drone as I know it's already done. 

  Are you sure? yes | no

orthemius wrote 04/27/2022 at 05:33 point

Do you know how https://airdata.com/ works? I mean they somehow know how to download and interpret DJI logs. And it works well with my dji fpv, just plug android to goggles and synchronize.

May be you can combine their logs interpretaion and your communication logs together and find out someth useful.

(unfortunately cannot apply an image https://drive.google.com/file/d/1b8GU5Y_tUYvz46i7CaubmCIgj7JQjqLx/view?usp=sharing)

  Are you sure? yes | no

orthemius wrote 04/27/2022 at 05:08 point

There is no public chat in your project :)

>> But every time you disconnect them, the control board resets and the battery needs a few percent (up to 100 %) of charging to "calibrate" the battery to the new LiPo.

May be it's not enoght. Lipo in contrast to Lion has a vary flat discharge characteristic, so it's almost impossible to say how much power does it left in your battary if you know only its voltage. It's ok, when you fly just till you battary reaches 3,5V per cell (no matter how long it takes, but you have to see th voltage), but not ok if you whant to know how much time have you left during the flight (eq to see battary percantage). It seems that smart battary counts the capacity during the whole charging, and then, calculates left capacity during discharging, plus controls the voltage for emergancy landing. That's why the battary is 'smart'. So, when you change lipo, you need minimum one full charge-discharcge-charge cycle to calibrate battary brains for it. Better 2-4 cycles. Without it, the percantage indicator is not accuracy and shows 'the weather'.

  Are you sure? yes | no

Poppy Ann wrote 04/08/2022 at 10:20 point

I did something similar for a different drone (which I cannot remember the name of) but all I did was to dismantle a knackered lipo which had its own make connector I just soldered a XT60 connector to the back of the original battery connector then took the end cover of the knackered battery which had a built in clip to hold the battery in place so now I could fit original battery's or any 3s 2500 mA or more battery's  in.

I also did a very similar project to some cordless tools where I took apart one of the original batteries and removed all of the parts I attached an electrical project box which had hinges and clips to close it, I ran some wires from the old battery connectors down through to the inside of the project box and fitted two XT60 connectors wired in parallel so if I wanted I could fit either one or two 3s lipo battery's inside of the box depending on which tool I was using on a couple of tools it was a bit to large and clumsy but on most of them it worked better than any of the supplied battery's that came with the tools whilst not being the most aesthetically looking modification this was a great where it mattered ie at powering the tool.

  Are you sure? yes | no

Duane Degn wrote 04/05/2022 at 15:03 point

Thanks for sharing your work. I was afraid DJI wouldn't make it easy to swap batteries. It seems like you have a semi-workable solution for now. I'll likely try something similar in the future.

  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