{"id":1367,"date":"2017-06-25T19:16:14","date_gmt":"2017-06-26T02:16:14","guid":{"rendered":"https:\/\/partofthething.com\/thoughts\/?p=1367"},"modified":"2018-03-11T13:05:53","modified_gmt":"2018-03-11T20:05:53","slug":"reading-data-from-a-dxl360-digital-level-onto-your-computer","status":"publish","type":"post","link":"https:\/\/partofthething.com\/thoughts\/reading-data-from-a-dxl360-digital-level-onto-your-computer\/","title":{"rendered":"Reading data from a DXL360 digital level onto your computer"},"content":{"rendered":"<p>There are some digital levels on the market that are really nice tools to have for a variety of purposes. I grabbed a DXL360 and am really happy with it so far. When I wanted to do an angle vs. time calibration measurement of my <a href=\"https:\/\/partofthething.com\/thoughts\/?p=1327\">Barn Door Startracker<\/a> over 10s of minutes, I really wanted to get the data from the level into a computer so I could plot and process it a bit.<\/p>\n<p>The level has a USB port but the manual suggests that an optional attachment is required to get it into a computer, at least for this model. However, the manual also states that data comes out of it in RS232 format. I bet I could read that data with some more generic equipment that I have sitting around. And it turned out to be easy. This post shows how I did it.<\/p>\n<p><a href=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1373\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636-1024x683.jpg\" alt=\"\" width=\"660\" height=\"440\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636-1024x683.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6636.jpg 2048w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p>First, I cut a USB cable in half to tap into the level. As a check, I hooked the data lines up to my oscilloscope. I was greeted with a binary bitstream that changed pleasantly as I rotated the level. Looks promising.<a href=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1368\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639-1024x683.jpg\" alt=\"\" width=\"660\" height=\"440\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639-1024x683.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6639.jpg 2048w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/a><\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/jktKsl6aX_k\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Next, I just plugged the data cables into my extraordinarily useful Adafruit FT232H breakout board, which is basically a universal attachment for these kinds of things. I love this chip. In this case I just plugged the TX line (white in my cable) to the UART RX line on the chip (D1) and GND to GND.<\/p>\n<p><a href=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1369\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641-1024x683.jpg\" alt=\"\" width=\"660\" height=\"440\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641-1024x683.jpg 1024w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641-300x200.jpg 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641-768x512.jpg 768w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/IMG_6641.jpg 2048w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/a><\/p>\n<p>To test it, I just followed <a href=\"https:\/\/learn.adafruit.com\/adafruit-ft232h-breakout\/serial-uart\">Adafruit&#8217;s instructions<\/a> to open up a `screen` session on my (linux) laptop. I was immediately greeted with and ASCII stream of data in a meaningful format. The FT232H starts up in its UART serial mode by default which is exactly what I needed for this device. Yay: this is an easy project.<\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/76vRCsxSesI\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Since I didn&#8217;t need any advanced features of this chip for this project, I didn&#8217;t need to use the Adafruit library or anything. I just wrote a bit of Python 3 code to parse the data:<\/p>\n<pre class=\"height-set:true wrap:false lang:python decode:true\" title=\"Code for reading the level data\">\"\"\"\r\nDigital Level Reader.\r\n\r\nReads DXL360 digital level measurements coming in over the serial port.\r\n\r\nData comes in via UART, converted to USB with a FT232H or equiv.\r\nFormat is X+0000Y+0000\r\n\r\nOriginal Purpose: Calibrate\/verify star-tracking barn-door camera mount.\r\nBy: Nick Touran\r\n\"\"\"\r\nimport serial\r\nimport re\r\nimport time\r\n\r\n\r\nDEV = '\/dev\/ttyUSB0'\r\nBAUD = 9600\r\nMSG_LENGTH = 12\r\n\r\n\r\ndef read():\r\n    with serial.Serial(DEV, BAUD, timeout=1) as port:\r\n        # sync up when you find an 'X' character\r\n        char = b''\r\n        while char != b'X':\r\n            char = port.read()\r\n        port.read(MSG_LENGTH - 1)  # toss one datum since X was consumed\r\n        start = time.time()\r\n        seconds = 0.0\r\n        # now read continuously and process into floats\r\n        while True:\r\n            datum = port.read(MSG_LENGTH).decode()\r\n            match = re.search('X([+-]\\d\\d\\d\\d)Y([+-]\\d\\d\\d\\d)', datum)\r\n            if not match:\r\n                raise ValueError('Level did not provide valid data. Check connection.')\r\n            x, y = match.groups()\r\n            x = int(x) * 0.01\r\n            y = int(y) * 0.01\r\n            seconds = time.time() - start\r\n            print('{:&lt;10.1f} {: 6.2f} {: 6.2f}'.format(seconds, x, y))\r\n            yield (seconds, x, y)\r\n\r\nif __name__ == '__main__':\r\n    read()\r\n\r\n<\/pre>\n<p>This code creates a generator that you iterate over very simply for whatever application you need. For my calibration stuff, the plotting code looks like this:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"height-set:true lang:python decode:true\" title=\"Collecting data and plotting\">import matplotlib.pyplot as plt\r\n\r\nimport level\r\n\r\n\r\ndef measure(duration_in_seconds=20):\r\n    t, x, y = [], [], []\r\n\r\n\r\n    for seconds, xi, yi in level.read():\r\n        t.append(seconds)\r\n        x.append(xi)\r\n        y.append(yi)\r\n        if seconds &gt; duration_in_seconds:\r\n            break\r\n\r\n    plt.plot(t, x, '.')\r\n    plt.xlabel('Time (s)')\r\n    plt.ylabel('Angle (degrees)')\r\n    plt.title('Level data')\r\n    plt.grid(alpha=0.3)\r\n    plt.show()<\/pre>\n<p>That just reads some data and then plots it, like this:<a href=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/calibration1_30mins.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1370\" src=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/calibration1_30mins.png\" alt=\"\" width=\"1008\" height=\"784\" srcset=\"https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/calibration1_30mins.png 1008w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/calibration1_30mins-300x233.png 300w, https:\/\/partofthething.com\/thoughts\/wp-content\/uploads\/calibration1_30mins-768x597.png 768w\" sizes=\"auto, (max-width: 1008px) 100vw, 1008px\" \/><\/a>Sweeeeeet.<\/p>\n<p>Coupling a computer to this level really makes it an even more awesome and useful instrument.<\/p>\n<p>Update: I open-sourced this software as part of the <a href=\"https:\/\/github.com\/partofthething\/startracker\">startracker project on github. <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are some digital levels on the market that are really nice tools to have for a variety of purposes. I grabbed a DXL360 and am really happy with it so far. When I wanted to do an angle vs. time calibration measurement of my Barn Door Startracker over 10s of minutes, I really wanted &hellip; <a href=\"https:\/\/partofthething.com\/thoughts\/reading-data-from-a-dxl360-digital-level-onto-your-computer\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Reading data from a DXL360 digital level onto your computer<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[3,69],"tags":[],"class_list":["post-1367","post","type-post","status-publish","format-standard","hentry","category-computers","category-electronics-and-physics"],"_links":{"self":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/comments?post=1367"}],"version-history":[{"count":7,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1367\/revisions"}],"predecessor-version":[{"id":1623,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/posts\/1367\/revisions\/1623"}],"wp:attachment":[{"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/media?parent=1367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/categories?post=1367"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/partofthething.com\/thoughts\/wp-json\/wp\/v2\/tags?post=1367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}