{"id":7802,"date":"2012-08-16T07:57:07","date_gmt":"2012-08-16T11:57:07","guid":{"rendered":"http:\/\/scruss.com\/blog\/?p=7802"},"modified":"2012-11-01T20:17:59","modified_gmt":"2012-11-02T00:17:59","slug":"raspberry-pi-python-arduino-and-a-gui","status":"publish","type":"post","link":"https:\/\/scruss.com\/blog\/2012\/08\/16\/raspberry-pi-python-arduino-and-a-gui\/","title":{"rendered":"Raspberry Pi, Python &#038; Arduino *and* a GUI &#8230;"},"content":{"rendered":"<p><em><a href=\"http:\/\/scruss.com\/blog\/2012\/11\/01\/the-magpi\/\">Whee!<\/a> This entry was the basis of the cover article of <a href=\"http:\/\/themagpi.com\/\">The MagPi<\/a> issue 7. <a title=\"The MagPi Issue 7\" href=\"http:\/\/issuu.com\/themagpi\/docs\/the_magpi_issue_7?mode=window\" target=\"_blank\">Read it on Issuu<\/a>, or <a title=\"The MagPi Issue 7\" href=\"http:\/\/themagpi.com\/view?issue=7\">download the PDF<\/a>.<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7803\" title=\"tkinter interface to arduino\" src=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2012\/08\/2012-08-15-230512_408x98_scrot.png\" alt=\"\" width=\"408\" height=\"98\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2012\/08\/2012-08-15-230512_408x98_scrot.png 408w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2012\/08\/2012-08-15-230512_408x98_scrot-160x38.png 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2012\/08\/2012-08-15-230512_408x98_scrot-320x76.png 320w\" sizes=\"auto, (max-width: 408px) 100vw, 408px\" \/><\/p>\n<p>Okay, so maybe I can stop answering the StackExchange question &#8220;<a href=\"http:\/\/raspberrypi.stackexchange.com\/questions\/1505\/how-to-attach-an-arduino\/1507#1507\">How to attach an Arduino?<\/a>&#8221; now. While I got the <a href=\"http:\/\/scruss.com\/blog\/2012\/08\/14\/raspberry-pi-python-arduino\/\">Arduino working with pyFirmata on the Raspberry Pi<\/a> before, it wasn&#8217;t that pretty. With a <a href=\"http:\/\/wiki.python.org\/moin\/TkInter\">TkInter<\/a> front end, it actually looks like some effort was involved. You can happily brighten and dim the LED attached to the Arduino all you want, while the temperature quietly updates on the screen independent of your LED frobbing.<\/p>\n<p>I&#8217;d never used TkInter before. For tiny simple things like this, it&#8217;s not that hard. Every widget needs a callback; either a subroutine it calls every time it is activated, or a variable that the widget&#8217;s value is tied to. In this case, the Scale widget merely calls a function <code>set_brightness()<\/code> that sets a PWM value on the Arduino.<\/p>\n<p>Updating the temperature was more difficult, though. After TkInter has set up its GUI, it runs in a loop, waiting for user events to trigger callback events. It doesn&#8217;t really allow you to run another loop alongside its main event loop. What you have to do then is set up a routine which is called periodically using TkInter&#8217;s <code>after()<\/code> function, which calls a subroutine after a set amount of time. If this subroutine ends with another call to <code>after()<\/code> to call itself again, it will maintain its own event loop separate from TkInter&#8217;s GUI loop. This is what I do in the <code>get_temp()<\/code> subroutine, which schedules itself after a \u00c2\u00bd second.<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n\r\n#!\/usr\/bin\/python\r\n# -*- coding: utf-8 -*-\r\n\r\n# graphical test of pyfirmata and Arduino; read from an LM35 on A0,\r\n#                                          brighten an LED on D3 using PWM\r\n# Connections:\r\n# - small LED connected from D3, through a 1k\u00ce\u00a9 resistor to GND;\r\n# - LM35: +Vs -&gt; +5V, Vout -&gt; A0, and GND -&gt; GND.\r\n# scruss, 2012-08-16 - tested on Raspberry Pi and Arduino Uno\r\n\r\nimport pyfirmata\r\nimport sys                              # just for script name and window\r\nfrom Tkinter import *\r\n\r\n# Create a new board, specifying serial port\r\nboard = pyfirmata.Arduino('\/dev\/ttyACM0')\r\n\r\n# start an iterator thread so that serial buffer doesn't overflow\r\nit = pyfirmata.util.Iterator(board)\r\nit.start()\r\n\r\n# set up pins\r\npin0=board.get_pin('a:0:i')             # A0 Input      (LM35)\r\npin3=board.get_pin('d:3:p')             # D3 PWM Output (LED)\r\n\r\n# IMPORTANT! discard first reads until A0 gets something valid\r\nwhile pin0.read() is None:\r\n    pass\r\n\r\ndef get_temp():                         # LM35 reading in \u00c2\u00b0C to label\r\n    selection = &quot;Temperature: %6.1f \u00c2\u00b0C&quot; % (pin0.read() * 5 * 100)\r\n    label.config(text = selection)\r\n    root.after(500, get_temp)           # reschedule after half second\r\n\r\ndef set_brightness(x):  # set LED; range 0 .. 100 called by Scale widget\r\n    y=float(x)\r\n    pin3.write(y \/ 100.0)               # pyfirmata expects 0 .. 1.0\r\n\r\ndef cleanup():                          # on exit\r\n    print(&quot;Shutting down ...&quot;)\r\n    pin3.write(0)                       # turn LED back off\r\n    board.exit()\r\n\r\n# now set up GUI\r\nroot = Tk()\r\nroot.wm_title(sys.argv&#x5B;0])              # set window title to program name\r\nroot.wm_protocol(&quot;WM_DELETE_WINDOW&quot;, cleanup) # cleanup called on exit\r\nscale = Scale( root, command=set_brightness, orient=HORIZONTAL, length=400,\r\n               label='Brightness')      # a nice big slider for LED brightness\r\nscale.pack(anchor=CENTER)\r\n\r\nlabel = Label(root)\r\nlabel.pack(anchor='nw')                 # place label up against scale widget\r\n\r\nroot.after(500, get_temp)               # start temperature read loop\r\nroot.mainloop()\r\n\r\n<\/pre>\n<p>The program takes a few seconds to start on the Raspberry Pi, mainly because initializing pyFirmata over a serial line and waiting for the duff values to subside takes time. I tried to exit the program gracefully in the <code>cleanup()<\/code> subroutine, but sometimes one of the loops (I suspect pyFirmata&#8217;s iterator) doesn&#8217;t want to quit, so it takes a few clicks to exit.<\/p>\n<p>The program also seems to chew up a fair bit of CPU on the Raspberry Pi; I had it at around 40% usage just sitting idle. I guess those serial ports don&#8217;t read themselves, and you have to remember that this computer is basically no more powerful than a phone.<\/p>\n<p>So there you are; a simple demo of how to control an output and read an input on an Arduino, from a Raspberry Pi, written in Python (the Raspberry Pi&#8217;s official language) with a simple GUI. Considering <a href=\"http:\/\/scruss.com\/blog\/2012\/08\/01\/learning-to-tolerate-python\/\">I&#8217;d never written a line of Python before the beginning of this month<\/a>, I think I&#8217;m doing not too badly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Whee! This entry was the basis of the cover article of The MagPi issue 7. Read it on Issuu, or download the PDF. Okay, so maybe I can stop answering the StackExchange question &#8220;How to attach an Arduino?&#8221; now. While I got the Arduino working with pyFirmata on the Raspberry Pi before, it wasn&#8217;t that [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[2207,2540,2510,2544],"class_list":["post-7802","post","type-post","status-publish","format-standard","hentry","category-computers-suck","tag-arduino","tag-python","tag-raspberrypi","tag-tkinter"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pQNZZ-21Q","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/7802","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/comments?post=7802"}],"version-history":[{"count":12,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/7802\/revisions"}],"predecessor-version":[{"id":8010,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/7802\/revisions\/8010"}],"wp:attachment":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/media?parent=7802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/categories?post=7802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/tags?post=7802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}