RGB-LED Lesson 4 (Scratch GPIO) – Extra Credit Universal Translator
The idea and principles introduced in this guide were written for version 4 of Scratch GPIO, although they may still work for the latest version of Scratch GPIO, this method of extending it has not been adopted by “SimpleSi” (the author of Scratch GPIO). Therefore, I’ve not pursued the idea any further, but have left this as a helpful reference instead.
However, if you are keen to get into the inner workings behind how Scratch GPIO actually works so you can customise it how you like, then this may be a useful guide for you.
The Universal Translator – How it works!
The Universal Translator works by using three main files:
1. scratch_gpio_handler.py – will be modified to use the Universal Translator files (if they exist).
- ut_index.py – Provides an index of KEYWORDS which we will allow Scratch to use with the Universal Translator.
rgb_ut.py – A specific Universal Translator file for the RGB-LED Kit.
Changes to scratch_gpio_handler.py
This file forms the heart of SimpleSi’s Scratch GPIO handler (as discussed in Lesson 2 (Scratch GPIO) – Getting Started) and currently handles all the messages which are sent/received to/from Scratch. There are three small modifications made to this file:
Located before definition of isNumeric() function.
The 1st modification, defines a function which allows us to check for a specific module being available, so that we can import python modules as and when we need them without fear of an error if they do not exist.
#LIB_UT MOD: START def module_exists(module_name): try: __import__(module_name) module_name except ImportError: return False else: return True #LIB_UT MOD: END
Located before the class definitions, after GPIO.setup.
The 2nd modification checks for the ut_index.py file and if available, fetches the array of KEYWORDS from it, for use later (if not available, the UT_KEYWORD array is empty).
#LIB_UT MOD: START #Get the ui_index keywords if module_exists('ut_index'): import ut_index UT_KEYWORD = ut_index.get_keywords() else: UT_KEYWORD =  #LIB_UT MOD: END
Located in ScratchListener class’s run() function after the try/except section.
The last modification, uses the KEYWORD array UT_KEYWORD to check for any supported words which are in the broadcast message from Scratch. If there is a match, the broadcast message is passed to the module with a matching name (if it exists), by calling scratch_out().
#LIB_UT MOD: START #Send the data to be checked by the Universal Translator for keyword in UT_KEYWORD: if keyword in dataraw: if module_exists(keyword+'_ut'): LIB_UT = __import__(keyword+'_ut', fromlist=['']) dataraw = LIB_UT.scratch_out(dataraw) else: print 'Scratch said '+'"'+keyword+'"'+'? I do not understand - '+keyword+'_ut.py does not exist' #LIB_UT MOD: END
The modifications to this code is implemented in such a way, that if the ut_index.py or rgb_ut.py files are removed then the script would still work without problems (therefore the modifications may be added to the default script without impacting it’s operation).
The Universal Translator Index File – ut_index.py
This file simply contains a function to return the list of supported keywords.
#Universal Translator Keyword Index #List the keywords for the supported UT py files (named <keyword>_ut.py) #Note: "unknown" is added to show that invalid items are ignored KEYWORDS = ["rgb","unknown"] def get_keywords(): return KEYWORDS
RGB-LED Universal Translator File – rgb_ut.py
This file contains a function called scratch_out() which receives the broadcast message from Scratch, and then (in this case) returns a translated version to the handler.
The following file is just an example, since I intend to develop the abilities of it further however it illustrates how easy it is to make your own hardware specific translations.
#RGB-LED Scratch GPIO Interface def scratch_out(datain): print "Scratch Output :" + datain updated = False if 'rgballon' in datain: dataout = datain.replace("rgballon", "pinpattern1110000"); updated = True if 'rgballoff' in datain: dataout = datain.replace("rgballoff", "pinpattern0001111"); updated = True if 'rgballred' in datain: dataout = datain.replace("rgballred", "pinpattern1000000"); updated = True if 'rgballgreen' in datain: dataout = datain.replace("rgballgreen", "pinpattern0100000"); updated = True if 'rgballblue' in datain: dataout = datain.replace("rgballblue", "pinpattern0010000"); updated = True if updated == False: dataout = datain return dataout
The code can be simple, like above, or we can break up the message further and allow the rgb_ut to generate translations for controlling individual LEDs or to produce more colours, or even control the GPIO pins directly.
Obviously, if we generate the translations dynamically by using defines, it means that any changes made to the wiring or hardware is easily dealt with.
Check out the code for the latest rgb_ut.py for a more complicated example.
In theory, all the hardware which we control using Scratch and the GPIO could be controlled using these ut files (motors, servos etc), allowing the functionality to be modular and easier to modify and extend in future.
Adding Support for your Own Hardware
Making a Universal Translator for your own hardware is nice and easy, simply add your chosen keyword to the KEYWORDS array in ut_index (i.e. 7seg). Then create a new _ut.py file (i.e. 7seg_ut.py) with scratch_out() function similar to the one above to convert/replace the Scratch message as required.
SimpleSi is progressing with his Scratch GPIO 2.0 development, which I hope will be able to make use of the Universal Translators as part of it’s operation. I’ve purposely kept this development separate for now, as I intend to make use of it immediately and I do not wish to interfere with SimpleSi’s plans.
Currently, the Universal Translator only supports out-going Broadcast Messages. However, as and when it is required, I shall add the ability to use Scratch variables as well as the ability to monitor GPIO inputs and provide input into Scratch as well.
Feedback and Share
I am keen to know how everyone uses this, and if it is useful at all. So if you do find it useful, or if you have created your own Universal Translators, then please let me know and I will be happy to feature your code and/or hardware on the site, so that other’s can learn from it too.