An attempt to create a programming trainer that uses physical blocks, instead of using drag-and-drop on a computer screen. The aim is to create a tactile, tangible programming experience to make learning programming easy and fun.
In late 2018 while studying at Monash University, I started a project for the unit "FIT3146 - Emergent Technologies". This was a "physical programming language" using Arduinos as programming blocks. The proof of concept was a success, so now I am documenting what I did with the aim of taking this idea further...
The Tangible Programming project is a new way of teaching programming. Instead of learning to program by typing code, or by using drag and drop (a la Scratch), Tangible Programming is designed to be a tactile programming experience. Using physical modules which you plug together, you create a program just like building with Lego. By plugging the brightly coloured modules into each other you build up your program. The main control unit will show you which blocks are attached and when the entire program is connected and read in you can follow the progress as it executes as each module lights up as it is being executed.
While the current prototype only offers a few commands, more programming commands are planned, including support for strings, functions and even integration with Arduino sensors and modules.
I have been quite busy with all manner of things in the past few months, but this project has had some love. (Unlike just about every other project I had in my queue...) I am currently working on a build using pogo-pin-style connectors and magnets to hold the blocks together - TBH I'm not sure it is going to work, but I am discovering some other potential options if these connectors are not quite right. I am trying to mock up some case designs to fully test the new connectors and hope to have a proper update for this project in a few days.
After some discussions with a few academics this past week, I have decided to work on (re-)defining the focus of this project. I want to make sure I keep the focus as tight as possible, because adding too much to the scope of this project will run the risk of diluting the core purpose. Keep it simple, focussed and to the point. (unlike my writing style!)
With that in mind, I want to redefine the purpose of this project: SPLaT is a simple programming language trainer, aimed primarily at young children and is intended to teach the basics of programming in a tactile manner. As such, the functionality is intended to be quite limited - integer variables only, simple arithmetic, simple loops and if/then/else conditionals. Functions, scoping of variables, advanced input/output functionality, etc. are all outside the scope of this initial project.
I had started to get carried away dreaming up extensions to the project which would allow functions, attaching Arduino-compatible sensors and modules, different input/output modules and so on, but the problem with this is I believe it detracts from the core promise of this as a tool to teach the fundamentals. If it becomes a general purpose programming tool, it loses its differentiation from other, similar general purpose products.
So, SPLaT will be a simple programming language trainer. The number of variables will be deliberately limited, the size of the variables will likewise be limited to 2-digit integers (0 to 99), and input/output will be limited to simply displaying values. If I get that all working, then I can start to think about extending the language, but I really need to keep the focus tight and simple for now.
Sometimes I am too clever for my own good. Or I try to be at least. For numeric input, I had been using BCD thumbwheel switches, which are kinda cool input devices, but they have two drawbacks - one, they are quite large compared to the modules, and two, they can be kinda expensive (and hard to source).
So I had the brilliant idea of ditching the thumbwheels and using simple "dongles" plugged into the value blocks. All I'd have to do is add some jumper pads to the digit PCBs, solder the jumpers to indicate an appropriate value, solder on the header pins and bingo!
Above are some of the resulting PCBs. If I use values from 0 to 9 for digits, that leaves 10 through 15 as "special" dongles that can represent variables and operators.
And it all works as expected. instead of two-digit values with thumbwheels, I now have a bunch of single digit plugins - to make a two-digit number, just plug in the two digits required. Easy-peasy!
Until you have to solder a bunch of the little suckers! 8^/
That's just a pile of four of each digit and they took me the better part of two hours to solder the jumpers and headers onto each one. How many will I need? A lot more than this - I don't think this is going to be a suitable solution for hand-manufacture. Then there's the storage and sorting of these little suckers. This prolly isn't going to be a sustainable solution once the prototypes land in the hands of small children.
I have enough thumbwheels for small prototypes, but I think I really do need to find a cheaper, but easier to build, option here.
Does anyone know of a small, cheap, 0-9 input switch that might be worth looking at? Or can you come up with some other (again - cheap) suggestion for entering values?
I'm about to start work on designing the next iteration of the blocks and modules. I have some (mostly vague) plans for this redesign:
Integrate a value module into some blocks
Variables, Loops, If, Output and some other block types all require at least one value, if not a whole expression to work properly. I think it makes sense to integrate a value module into a program block, which will reduce the number of parts needed to write a program. In order to do this, I think the combined block + value will need to use a microcontroller with more free GPIOs than the ATTiny841.
I really like the '841, but to incorporate a value module I need more GPIOs than are available. I could get around this by including an I2C GPIO extender chip (such as the MCP23008) but that adds complexity and cost. It is probably best to just jump straight to a larger MCU. I'm leaning toward the ATMega328P, or even the ATMega328PB (which has two serial ports instead of one). I have samples of both, so I will do some prototypes to see which works out best...
Revisit the interconnections
Currently the blocks connect to one another using a 4-pin make and female connectors. I think this is fine for prototyping, but it might not be the best solution for a finished product. I need to do some research into other connectors to find something that is cheap and robust enough to be practical. For now I will probably stick with the connectors I am using, but I should start looking sooner rather than later.
The pinout of my connectors is also something I need to look at. The block connections I am happy with - they have VCC, Gnd, Tx, Rx. For block to module connections I have used SDA, SCL, Gnd, and VCC. Grove connectors use SCL, SDA, VCC, Gnd which is quite a different layout. I think it might make sense to standardise on the Grove connector to allow for a wider variety of add-ons.
Finally, I need to look at the value connectors. I am using a modified 6-pin connector, with pin two removed to make the connector polarised. This works, but can be a bit awkward to plug the numeric, variable and operator dongles in at times. So I need to find a better way of plugging values into a block or module.
The form factor for the blocks and modules was decreed by the size of the original tiny breadboards I used for my first prototype and the size of the Arduino Pro Mini modules I was using to control the blocks. Now I am using bare chips instead of pre-built devices, I can resize the blocks and modules.
However, I do find the size quite pleasing so far. 30x50mm for the blocks seems like a nice size. The blocks are not too big and not too small for my clumsy hands to manipulate. The variable and value dongles on the other hand are a bit small. 8^/
These blocks and modules will eventually be housed in cases of some description. I would like the cases to be colourful and sturdy, with different functions have a specific colour and shape to allow for quick and easy identification. Smaller PCBs can fit in large cases without problems, but large PCBs limit the smallest size the case can be. I think making the PCBs larger just for sake of making them larger might be a mistake.
The case layout and design may actually inform the layout of the PCBs to an extent. The placement of the connectors, LEDs and value connections all need to be consistent and work with the eventual case design. I should consider mocking up some cases just to get a feel for what I might be working with here.
What else should I consider when designing the next rev?
Okay, so after talking to some friends at university, I've decided to call this project SPLaT. That stands for Simple Programming Language Trainer. I'm still not sold on the name to be honest, but if Scratch can survive, why not SPLaT?
I have also thought of another project that can reuse many of the same modules (or at least, very similar modules) which will mean the Tangible Programming moniker will still stand, but more on that later... ;^)
I still have a few issues to iron out, but I managed to find an OLED library that was small enough to fit on the ATTiny841 and got a small, 0.49" OLED display working on an output block. Now, as the program is running, the output block shows the current value of a variable. I even have enough spare memory to use two different fonts, which I was a pleasant surprise.
This has highlighted some issues with my power distribution. I really need to work out what is happening with the power. The current set up doesn't quite provide enough power to initialise the OLED on the block, but if I power up the block first with an external power supply, then add the block to the other blocks while it is still powered, then apply power to the master controller, it will work. I think that might be a little too hacky...
I do want to replace the Arduino Uno with a custom board, so maybe that should be the next thing I focus on. I can try to work out the power issues while creating the master controller's board. Or, do I really need a master controller at all? If I can stick a display on individual blocks, the need for a master controller to display the output is reduced. Something for me to think about...
I really should come up with a proper name for this project. Up until now I have mostly referred to this as "Tangible Programming" or "Programmable Blocks". Tangible Programming is closest to what the project is, but it isn't a particularly enticing name. When I wrote my report for the university assignment this came from, I used the name SPLaT (Simple Programming Language Trainer) but I'm not sure about that as a name.
Any ideas? Anyone? What would you call this project?
I am quite happy with my latest PCBs for this project (thanks JLCPCB!) although they do have some issues. The matte black boards look particularly sexy, although flux residue can be a bit of an issue if not cleaned up.
I thought it'd be nice to give you a brief tour of the board and talk about some of the things I will most likely be changing for the next revision. The next revision will be some time off, but I am building a wishlist of things to change/add.
A Brief Tour
So let's have a quick look at the current boards:
First of all, please ignore the missing Vin at the top left of the board - somehow I managed to delete it before I generated the Gerbers. 8^/
The board is designed to be somewhat flexible, with two incoming serial connections, and two outgoing serial connections. (Highlighted in yellow above.) Both of the ports at the top of the board are connected, as are the two ports at the bottom. This means I can choose to solder the 4-pin connectors in either position, which lets me create blocks that "indent" the code. This can be seen in my favourite demo program (which calculates the Fibonacci sequence) where the yellow LOOP block makes sure the loop contents are nicely indented and the END LOOP block un-indents the code.
At the right end of the board is a four pin port which is used to connect to other modules. Currently I am using this for value and expression blocks. The port uses I2C, so theoretically any I2C module could be plugged in. (With the appropriate code modifications of course.) That means it might be possible to plug an OLED display directly into a board, or even sensor modules such as temperature, light, or sound sensors, opening up a whole world of new possibilities.
The last port on the board is a programming header. (Circled in blue above) I built a pogo-pin adapter with a USB to FTDI module to program the blocks via this port, and it all seems to work fine.
Lastly, there is a white rectangle at the back of the board where I can label the board's function if required. At the moment I have been able to keep each colour to a a different programming construct and thinking about it, this label might not be needed. For example, yellow boards are being used for LOOP/END LOOP and I will build some yellow variable boards, but the placement of the input/output ports will be enough to distinguish variables from loops.
Other things to note about the boards: There is no power regulation on the board. This was not an oversight - it is by design. The boards draw their power from the input port and the master controller (currently an Arduino Uno, but soon to be a separate custom board) is used to handle the regulation of power. This has allowed me to reduce the parts count and make the boards a bit cheaper to make.
There are two indicator LEDs - one red and one green. The boards can use these to indicate their current execution states, or if they have an error.
And apart from that there is not much else to these boards. K.I.S.S.
Alas, it is not all smooth sailing however...
Flashing the Bootloader
Apart from the missing Vin label, there are a couple of other issues with the board. Starting with the biggie - I forgot to consider how I would flash the bootloader. Oops! While I have the FTDI header, that is not used when flashing the bootloader and setting fuses on the chip. I did manage to get it all working, but it is a bit of a bodge.
To flash a bootloader you need access to an ICSP port. On ATTiny (and ATMega) chips, that means connecting to VCC and Ground (got both of them on the serial ports and the I2C port), MISO, MOSI and SCK (those are TX Out, SCL on the I2C port and RX Out) and the RESET pin. There is a RESET on the FTDI header, but that is connected to the RESET pin via a capacitor, and the ICSP protocol doesn't like that idea. 8^(
I was able to flash the bootloader by connecting the the five broken out pins (basically the outgoing serial port...
When I built my first breadboard prototype for my university class, I had a problem where only the first eight blocks would be recognised. When I checked the voltage on each module, I realised that after about eight blocks, the voltage had dropped too low for the Arduino Pro Mini clones to effectively operate. It was actually at around the 11th or 12th module that the Pro Minis would not boot, but I figured that the 9th module didn't have enough power to send or receive serial communications. Luckily my showcase program (the Fibonacci Sequence) only needed eight modules, so I waved the issue off as a power problem and stuck to programs of eight steps or fewer.
With the move to ATTiny841-based blocks I was able to reduce the power requirements considerably, so I ought to be able to have more than eight blocks in a program. Unfortunately my testing showed otherwise. The power was getting through okay, so something else must be at fault here.
I did some testing by tweaking the code. Instead of sending a broadcast message to all modules, I sent an "identify yourself" query to a small handful of select blocks. That showed that I could communicate with the 10th, 11th, 12th blocks with no problems. But if I sent a broadcast query, only the first eight blocks would respond.
Maybe forwarding the broadcast message was failing after eight hops? That didn't seem right, but I through I would try to rule that out. My next test was to send queries to each block individually - i.e. not using a broadcast message. Here is where it started to get weird: Sending 13 ID queries in order (from 0 through 12) still only returned eight results, but the fourth block's response didn't appear. This seemed to indicate to me that timing was an issue, and the timing issue was most likely in the master control unit (MCU), rather than the nodes.
I decided to manually trace the code in the MCU and noticed that I was sending the messages and then clearing the screen in the setup() function and the loop() had no particularly intricate operations during the receipt of the messages. So I moved the code to clear the screen to immediately before the message(s) were sent and bingo! All 13 connected blocks responded and were displayed on screen.
So I can now create programs up to 13 blocks long - any more and I won't be able to display the full program on the tiny screen I am using! As an added bonus, switching the the '841 has reduced the power consumption such that I can power the whole system off a USB power bank. (The Pro Mini modules were too hungry for battery operation and I needed a wall wart to power even four or five modules, let alone eight or more.)
Now that I know what was causing the issue I will revisit the code when I have some spare time and try to make it even faster. I will also look into how I can display longer programs. I am quite relieved that I found this problem and that it was such a simple fix. My biggest fear was that there was a problem with the circuit board, or that there was a more fundamental error in my design.
Update (16 April 2019)
Today I was showing this project to my Honours supervisor while we discussed my Honours project for next semester. I want to do an Honours project based on the communication protocol I am using - i.e. are there any existing protocols that might be better, or am I on the right track with this protocol? I explained to him this issue and how I fixed it, but I still wasn't 100% certain why it was happening - just that it was a timing issue of some sort. As I said this to him it struck me what the underlying issue was...
When the master control unit (MCU) sends out the broadcast message and then starts the screen clear, the blocks receive the message and start replying immediately. The MCU's serial input buffer starts filling up with the incoming replies while the screen is being cleared. By the time the screen clear has completed and the MCU gets into the...
First up, an apology for the lack of updates since I received my last batch of PCBs. There have been a few things going on in my life that I am not willing to discuss here, but it has been a rather trying time. I have been focussing on my family and my studies (in that order) and all of my projects have taken somewhat of a backseat. I'm slowing getting back into the swing of things...
Secondly, another apology is due. I had recorded the unboxing of my PCBs and an initial investigation into the quality, but I am a doofus and the recording was all but unusable. The audio was ruined by a neighbour's intermittent, loud music and the video was affected by a big, clumsy doofus knocking the tripod. After trying to cut around the damage and re-record the voice over, I have decided to give up - it was taking me too long and I am not a videographer. I will try o chop what I have up and reuse some pieces if I can, but the whole unboxing experience was a non-event - sorry about that.
Some Colourful New PCBs...
As you may know, I recently received a batch of PCBs from JLCPCB, who kindly provided them free of charge. This was a great boon, because I am a (mature-age) student, currently living off student payments (Austudy) and as such I don't have a lot of disposable income. JLCPCB recently dropped the price of their coloured PCBs and I thought it would be neat to see how the colours worked for my program blocks. In my original prototype I used coloured breadboards to represent different programming constructs. For example, Red, Green, Blue and Yellow blocks were variables, White blocks were output blocks. Now that colourful PCBs are affordable, I could implement a similar colour scheme again instead of having all green PCBs.
I quite liked those colourful blocks, and have preserved a set of them for posterity. 8^)
At around the same time I had been experimenting with the ATTiny841 as a replacement for the Arduino Pro Mini clones in my blocks. The '841 is a neat little chip - it has two serial ports, which I can use for the incoming and outgoing connections, and 12 GPIO pins ('though I am using four of those for the serial ports). A bit of ugly breadboarding proved the chip was up to the task, so I decided to take the leap and use the chip in the next iteration of the design.
I somewhat cheekily reached out to JLCPCB via Twitter and their representative offered to pay for my next batch of boards, so I went about designing a new PCB layout using the ATTiny841 and placed my order for a small batch of five panels of each colour - Green, Blue, Red, White, Yellow and Black. The new boards would be quite sparse compared to the previous iteration - the '841 is much smaller than an entire Pro Mini and the reduced number of available GPIO pins (out of the 12 available, four are used for 2x serial, 2 for I2C and one for the reset pin, leaving 5 free) meant I had to drop the jumpers for the block id. The lack of block id jumpers means I have to hard-code each block's id, which is not that big a deal IMHO.
Unfortunately (for me) the '841 is only available in an SMD package, so I went the whole hog and used all SMD in the new design. I included an FTDI-compatible programming header on one end of the board so I could easily program the blocks when needed.
Examining the New PCBs
The new panels indeed looked quite sexy!
And breaking the boards apart leaves some very sexy, tiny modules!
And here is where I discovered my first mistake (thankfully a tiny one) - the Vin label on the first connector was missing. I don't know how that happened, but it is an easy fix.
A close inspection of the boards showed them to be very nice. The matte black boards in particular look gorgeous, but all the colours are quite nice. One complaint I have however is the white...