{"id":262,"date":"2019-05-30T00:10:20","date_gmt":"2019-05-29T16:10:20","guid":{"rendered":"http:\/\/www.bxworks.com\/?p=262"},"modified":"2019-05-30T00:10:20","modified_gmt":"2019-05-29T16:10:20","slug":"dji-flightrecord-decoder-app%e9%87%8c%e7%9a%84txt%e9%a3%9e%e8%a1%8c%e8%ae%b0%e5%bd%95%e6%95%b0%e6%8d%ae%e6%a0%bc%e5%bc%8f","status":"publish","type":"post","link":"http:\/\/www.bxworks.com\/?p=262","title":{"rendered":"DJI FlightRecord decoder APP\u91cc\u7684txt\u98de\u884c\u8bb0\u5f55\u6570\u636e\u683c\u5f0f"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">DJI FlightRecord-decoder<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">Decode flight record TXT files from DJI GO app<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Tested with DJI Phantom 4<\/h4>\n\n\n\n<p>The DJI GO app stores flight records for every flight, collecting data from the aircraft at ~10 Hz. <br>\nThe files are given names corresponding to the time of the flight (e.g. <code>DJIFlightRecord_2016-06-18_[21-05-26].txt<\/code>) <br>\nand are stored in <code>\/DJI\/dji.pilot\/FlightRecord\/<\/code> on Android.<\/p>\n\n\n\n<p>Although they have the <code>.txt<\/code> extension, the data is stored in an undocumented, proprietary format. This repository <br>\ncontains Python scripts for decoding the files into more useful <code>.csv<\/code> files, ideal for use with software like <a href=\"http:\/\/www.dashware.net\/\">Dashware<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to use<\/h2>\n\n\n\n<p>Run <code>python txt2csv.py path-to-file.TXT<\/code>. This will create <code>path-to-file.csv<\/code> in the same directory as the original <code>.TXT<\/code> file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">File Format<\/h2>\n\n\n\n<p>Bytes 0-11 are some sort of header and have not yet been decoded.<\/p>\n\n\n\n<p>From byte 12 onwards, the file contains a stream of variable length frames. Each frame is structured as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Byte 0: <strong>Frame type<\/strong> &#8211; Frame types 1,2,3,4,5,6,7,8,9,11,13,15 have been observed<\/li><li>Byte 1: <strong>Payload length<\/strong> &#8211; The number of bytes of data following this header<\/li><li>Bytes 2-n: <strong>Payload<\/strong> &#8211; Different for each frame type. See below.<\/li><li>Byte n+1: <strong>0xFF<\/strong> &#8211; Frame delimiter. This isn&#8217;t really necessary, but it&#8217;s there anyway.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>|---------------|-----------------|------------------------------------------|------|----\n| type (1 byte) | length (1 byte) | payload (n bytes)                        | 0xFF | ...\n|---------------|-----------------|------------------------------------------|------|----<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Frame Types<\/h3>\n\n\n\n<p>The various frames appear with different frequencies and each contain different types of data. Position, battery, gimbal, etc. <br>\nTheir formats are described here. All multi-byte encodings are little-endian.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 1 &#8211; <strong>Position<\/strong><\/h4>\n\n\n\n<p>This frame is always 53 (<code>0x35<\/code>) bytes long. Appears at ~10 Hz<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field                    | Unit\n--------|---------------------|--------------------------|------------\n      0 | 64-bit double       | Longitude                | radians\n      8 | 64-bit double       | Latitude                 | radians\n     16 | 16-bit signed int   | Ascent above start point | metres * 10\n     18 | 16-bit signed int   | X Speed                  | m\/s * 10\n     20 | 16-bit signed int   | Y Speed                  | m\/s * 10\n     22 | 16-bit signed int   | Z Speed                  | m\/s * 10\n     24 | 16-bit signed int   | Pitch                    | degrees * 10\n     26 | 16-bit signed int   | Roll                     | degrees * 10\n     28 | 16-bit signed int   | Yaw (compass heading)    | degrees * 10\n     30 | 16-bit unsigned int | Fly C State              | ?\n     32 | 16-bit ?            | ?                        | \n     34 | 16-bit ?            | ?                        | \n     36 | unsigned byte       | Visible GPS satellites   | count\n     37 | unsigned byte       | Flight Action            | ?\n     38 | unsigned byte       | Motor Start Failed Cause | ?\n     39 | unsigned byte       | Non GPS Cause            | ?\n     40 | unsigned byte       | Battery                  | ?\n     41 | unsigned byte       | S Wave Height            | ?\n     42 | 16-bit unsigned int | Fly time                 | seconds * 10\n     44 | 16-bit unsigned int | Motor Revolution         | ?<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 2 &#8211; <strong>Home Point<\/strong><\/h4>\n\n\n\n<p>This frame reports details of the current Home Point.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type           | Field             | Unit\n--------|----------------|-------------------|------------\n      0 | 64-bit double  | Latitude          | radians\n      4 | 64-bit double  | Longitude         | radians\n      8 | 16-bit float   | Pressure Altitude | metres * 10<\/code><\/pre>\n\n\n\n<p>Note that <em>pressure altitude<\/em> is the barometric altitude assuming a pressure at sea-level of 1013.25 millibars. See https:\/\/en.wikipedia.org\/wiki\/Pressure_altitude<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 3 &#8211; <strong>Gimbal<\/strong><\/h4>\n\n\n\n<p>This frame reports the current state of the camera gimbal.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field                   | Unit\n--------|---------------------|-------------------------|------------\n      0 | 16-bit signed int   | Pitch                   | degrees * 10\n      2 | 16-bit signed int   | Roll                    | degrees * 10\n      4 | 16-bit signed int   | Yaw (compass heading)   | degrees * 10\n      6 | unsigned byte       | Mode                    | ?\n      7 | unsigned byte       | Roll Adjust             | ?\n      8 | unsigned byte       | Yaw Angle               | ?\n      9 | unsigned byte       | Is Auto Calibration     | ?\n     10 | unsigned byte       | Auto Calibration Result | ?\n     11 | unsigned byte       | Version                 | ?\n     12 | 16-bit unsigned int | Counter                 | ?<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 4 &#8211; <strong>Controller<\/strong><\/h4>\n\n\n\n<p>This frame reports the status of the radio controller at a frequency of ~10 Hz.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field    | Unit\n--------|---------------------|----------|------------\n      0 | 16-bit unsigned int | Throttle | position (0 - 2048)\n      2 | 16-bit unsigned int | Rudder   | position (0 - 2048)\n      4 | 16-bit unsigned int | Elevator | position (0 - 2048)\n      6 | 16-bit unsigned int | Aileron  | position (0 - 2048)<\/code><\/pre>\n\n\n\n<p>The remaining bytes certainly contain the state of all the other controls, but are yet to be decoded.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 5 &#8211; <strong>Time<\/strong><\/h4>\n\n\n\n<p>This frame contains a current UTC time stamp, among other things<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field      | Unit\n--------|---------------------|------------|------------\n      0 | byte                | ?          | \n      1 | byte                | ?          |\n      2 | 32-bit float        | Speed      | m\/s\n      6 | 32-bit float        | Distance   | metres\n     10 | 64-bit unsigned int | Time (UTC) | milliseconds since UNIX epoch<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 6 &#8211; <em>Unknown<\/em><\/h4>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 7 &#8211; <strong>Battery 1<\/strong><\/h4>\n\n\n\n<p>This frame contains general raw information about the battery state.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field            | Unit\n--------|---------------------|------------------|------------\n      0 | unsigned byte       | Level            | percent\n      1 | 16-bit unsigned int | Current PV       | ? * 1000\n      3 | 16-bit unsigned int | Current Capacity | mAh\n      5 | 16-bit unsigned int | Total Capacity   | mAh\n      7 | unsigned byte       | Life             | ?\n      8 | 32-bit unsigned int | Charge Cycles    | count\n     12 | 16-bit unsigned int | Error Type       | ?\n     14 | 16-bit signed int   | Current          | mA * 1000\n     16 | 16-bit unsigned int | Cell 1 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Cell 2 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Cell 3 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Cell 4 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Cell 5 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Cell 6 Voltage   | volts * 1000\n     16 | 16-bit unsigned int | Serial No.       | \n     16 | 16-bit DOS date     | Manufacture Date | see below\n     16 | 16-bit unsigned int | Temperature      | Kelvin * 10<\/code><\/pre>\n\n\n\n<p>The Manufacture Date is packed into 16 bits using the MS-DOS Date encoding. See <code>decoder.py<\/code> for decoding.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 8 &#8211; <strong>Battery 2<\/strong><\/h4>\n\n\n\n<p>This frame contains calculated battery statistics.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field             | Unit\n--------|---------------------|-------------------|------------\n      0 | 16-bit unsigned int | Useful Time       | seconds\n      2 | 16-bit unsigned int | Go Home Time      | seconds\n      4 | 16-bit unsigned int | Land Time         | seconds\n      6 | 16-bit unsigned int | Go Home Battery   | ?\n      8 | 16-bit unsigned int | Land Battery      | ?\n     10 | 32-bit float        | Safe Fly Radius   | ?\n     14 | 32-bit float        | Volume Consume    | ?\n     18 | 16-bit unsigned int | Status            | ?\n     20 | 16-bit unsigned int | Go Home Status    | ?\n     22 | 16-bit unsigned int | Go Home Countdown | ?\n     24 | 16-bit unsigned int | Voltage           | volts * 1000\n     26 | byte                | Level             | percent\n     27 | byte                | Low Warning       | ?<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 9 &#8211; <strong>Message<\/strong><\/h4>\n\n\n\n<p>This frame is recorded when the DJI GO app displays messages to the pilot. The entire payload is an ASCII string. There is no null-termination.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 11 &#8211; <em>Unknown<\/em><\/h4>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 13 &#8211; <strong>Aircraft<\/strong><\/h4>\n\n\n\n<p>This frame contains details of the aircraft.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset  | Type                | Field                 | Unit\n--------|---------------------|-----------------------|------------\n      0 | byte                | Drone Type            | ?\n      1 | byte                | App Type              | ?\n      2 | byte                | App Major Version     | \n      3 | byte                | App Minor Version     | \n      4 | byte                | App Revision          | \n      5 | 10-byte string      | Aircraft Serial No.   | \n     15 | 32-byte string      | Aircraft Name         |\n     47 | 64-bit unsigned int | Activation Time       | seconds since UNIX epoch\n     57 | 10-byte string      | Camera Serial No.     |\n     67 | 10-byte string      | Controller Serial No. |\n     77 | 10-byte string      | Battery Serial No.    |<\/code><\/pre>\n\n\n\n<p>The <code>Activaction Time<\/code> field contains the time when the aircraft was first powered on.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Frame 15 &#8211; <em>Unknown<\/em><\/h4>\n","protected":false},"excerpt":{"rendered":"<p>DJI FlightRecord-decoder Decode flight record TXT files &hellip; <a href=\"http:\/\/www.bxworks.com\/?p=262\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">DJI FlightRecord decoder APP\u91cc\u7684txt\u98de\u884c\u8bb0\u5f55\u6570\u636e\u683c\u5f0f<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-262","post","type-post","status-publish","format-standard","hentry","category-science"],"_links":{"self":[{"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/posts\/262","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=262"}],"version-history":[{"count":1,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/posts\/262\/revisions"}],"predecessor-version":[{"id":263,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=\/wp\/v2\/posts\/262\/revisions\/263"}],"wp:attachment":[{"href":"http:\/\/www.bxworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=262"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=262"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.bxworks.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=262"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}