Tag Archives: project

Arduino Powered Tachistoscope

About fifteen hundred years ago I wrote WordApp, a Java applet tachistoscope that reads a text file from either the local filesystem or the Internet and displays it one word at a time. The idea is that it trains your brain to recognise words quickly, increasing your reading speed. I thought it was a little silly, but according to me web host’s logs WordUp still sees a bit of use even though I haven’t touched it for years.

I was hunting around for something to do with my Arduino while I waited for some other parts to arrive when I had the idea of making a physical tachistoscope that reads its data off an SD card and displays the text using an LCD display I have lying around.

The SD card contains the text to be shown. One of the potentiometers is used to vary the contrast on the LCD. The other is sampled by the CPU and converted into a delay to vary the speed at which the words appear.

Unfortunately the refresh rate of the LCD is very poor, so the text becomes almost impossible to read at even modest speeds. A better display might help, but I am not going to spend any more time and money on something so simple. Fortunately, the other parts I ordered arrived yesterday so I have other things to play with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
An Arduino implementation of a Tachistoscope.
This uses both the LiquidCrystal and SD libraries (and repective devices). The 
words are read one at a time from a file on the SD card. A simple variable resistor
is used to control the speed.
In practice this does not work terribly well since the LCD display has a poor
refresh rate.
 
Pins: 
The LCD is connected via pins 2-8. Technically I could get away without the RW pin.
The SD card reader is connected via pins 10-13 (the standard SPI pins)
The variable resistor is connected via analog A0
 
Author: Andrew Stephens http://sandfly.net.nz/
*/
 
#include <LiquidCrystal.h>
#include <SD.h>
 
LiquidCrystal lcd(8, 7, 6, 5, 4, 3, 2);
File file;
 
void setup()
{
  lcd.begin( 16, 2 );
  lcd.clear();
  lcd.setCursor(0, 0);
 
  pinMode(10, OUTPUT);  // required if I ever change the CS pin from 10
  pinMode(A0, INPUT);
 
  SD.begin(10);
  file = SD.open("test.txt");
}
 
// Skip over whitespace, positions the file position at the start of the next
// word
bool findNextWord( File& file )
{
  int r;
  while ((r = file.peek()) != -1 )
  {
    if ( !isSpace(r) )
    {
      return true;
    }
    file.read();
  }
  return false;  
}
 
// Reads a single word (anything up to the next whitespace character) into
// the given buffer
bool getNextWord( File& file, char* buffer, int bufferSize )
{
  int r;
  while ((r = file.read()) != -1 )
  {
    if ( isSpace( r ) )
    {
      *buffer = '\0';
      return true;
    }
    if (bufferSize > 1 )
    {
      *buffer = r;
      ++buffer;
      bufferSize--;
    }
  }
 
  *buffer = '\0';
  return false;
}
 
 
// originally this function did more
int readResistor()
{
  return analogRead(A0);
}
 
 
void loop()
{
  char buffer[17];
 
  if (findNextWord( file ) )
  {
    getNextWord( file, buffer, sizeof(buffer) );
    lcd.clear();
    lcd.print( buffer );
  }
  else
  {
    lcd.clear();
    lcd.print("--end--");
  }
  int v = readResistor();
  lcd.setCursor(0, 1);
  lcd.print( v );
  delay(v);  
}

Arduino POV Device Part II

Last week I wrote about starting with digital electronics with the Arduino prototyping platform. Getting something working was easy enough but I was dissatisfied with ugly result, especially when my friend Lloyd showed up with his extremely tidy version of the same idea. The piece of cardboard had to go!

My first version used a breadboard and uncut LED leads because I thought that I would want to dismantle the components for reuse. However I have since realised that I am a grown man with a career and can easily afford the $4.50 material cost. Behold POV version 2:



I won’t be entering this in any soldering competitions but it works OK.

The code has also changed. Compiling in what amounts to a 2D bitmap was a quick way to get something up and running but it wasn’t very flexible, especially since in the future I want to display long strings of text. This means storing glyphs (letter shapes) for every letter of the alphabet (plus digits and symbols) – what I needed was a proper font; what I got was this:

I then turned to Python to generate the program data to embed in the new Arduino code. This script slices the image vertically, generating one byte (actually only 7 bits) for each slice of pixels. What comes out is a long list of byte values that can be output directly to the Arduino’s IO pins to display each section of the text, along with a set of indexes that map letters to the start and end positions of individual glyphs in the array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import sys
 
def GetSlice(i, pos):
	t = 0
	for q in range( pos, len(i), len(i) / 7 ):
		t = t * 2
		if ( i[q] != '\x00' ):
			t = t + 1
	return t
 
def GetGlyph( i, pos ):
	end = pos
	start = pos
	data = []
	while (end < len(i) ):
		t = GetSlice( i, end )
		if ( t == 0 ):
			break;
		data.append( t )
		end = end + 1
	return (start, end, data)
 
def GetFont( d ):
    result = []
    i = 0
    currentIndex = 0
    indices = []
    while ( i < len(d) / 7 ):
	(start, end, data) = GetGlyph( d, i )
	if ( len(data) == 0 ):
		break
	i = end + 1
	indices.append( currentIndex )
	currentIndex = currentIndex + len(data)
	result.extend( data )
    return ( result, indices )
 
if __name__ == '__main__':
    if ( len(sys.argv ) != 3 ):
        print "USAGE: program <input> <output>"
        exit()
    data = []
    i = file( sys.argv[1], "rb" )
    data = i.read()
    i.close()
    ( d, indices ) = GetFont( data )
    o = file( sys.argv[2], "w" )
    o.write( "static const int indices[] = { " + ",".join(map(str, indices ) ) + " }; ")
    o.write("\n")
    o.write( "static const unsigned char fontdata[] = { " + ",".join(map(str, d)) + "};")
    o.write("\n")
    o.close()

This scheme is more complex that the original bitmap but allows arbitrary text to be display without lots of editing. The modified Arduino code now looks like this. The first two lines contain the new font data, and you can see that the text to display is simply declared on line 5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
static const int indices[] = { 0,4,8,12,16,19,22,26,30,33,37,42,45,52,59,63,67,71,75,79,82,86,91,96,101,106,111,116,121,126,131,136,141,146,151,156,161,163,165,167 }; 
static const unsigned char fontdata[] = { 63,72,72,63,127,73,73,54,62,65,65,34,127,65,65,62,127,73,65,127,72,64,62,65,69,39,127,8,8,127,65,127,65,2,1,1,126,127,8,20,34,65,127,1,1,63,64,64,60,64,64,63,127,32,16,8,4,2,127,127,65,65,127,127,72,72,48,62,65,71,62,127,72,76,51,50,73,73,38,64,127,64,126,1,1,126,112,12,3,12,112,126,1,15,1,126,65,54,8,54,65,96,16,15,16,96,67,69,73,81,97,62,69,73,81,62,17,33,127,1,1,71,73,73,73,49,65,65,73,73,54,24,40,72,127,8,121,73,73,73,6,62,73,73,73,6,65,66,68,72,112,54,73,73,73,54,48,73,73,73,62,3,3,123,123,27,27,127};
 
static int outputPins[] = { 12, 11, 10, 9, 8, 7, 6 };
static char text[] = "ANDREW";
 
void setup()
{
  for (int i = 6; i<=12; ++i)
  {
    pinMode(i, OUTPUT);     
    digitalWrite(i, HIGH);
  }
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  delay(2000);
}
 
void loop()
{
  byte row = 0;
  byte endRow = 0;
  char* currentChar = text;
 
  while (1)
  {
    if (*currentChar == 0)
      currentChar = text;
    if ( row == endRow )
    {
        char t = *currentChar;
        currentChar++;
        t = t - 'A';
        row = indices[t];
        endRow = indices[t+1];
    }
    while (row != endRow)
    {
      byte mask = 64;
      for (byte pin = 0; pin < (sizeof( outputPins) / sizeof(outputPins[0])); ++pin )
      {
        digitalWrite( outputPins[pin], (fontdata[row]&mask)? HIGH : LOW  );
        mask = mask / 2; // divide mask by two, moving it down one bit
      }
      row++;
      delay(1);
    }
    for (byte pin = 0; pin < (sizeof( outputPins) / sizeof(outputPins[0])); ++pin )
    {
      digitalWrite( outputPins[pin], LOW);
    }
 
    delay(1);
  }
}

Still to do: This code is not very efficient. It uses digitalWrite() in a loop to turn on the LEDs. digitalWrite() is very easy to use but if you look at the source code you will see it does all sorts of unnecessary stuff for this job. I plan to replace it with direct writes to the required Arduino IO registers.

I also want to make the whole thing interrupt driven to free up the CPU. Why would I want the extra CPU time? I have plans for that as well…

Starting with Arduino

I have a new hobby – digital electronics! Last week I bought an Arduino Uno on a whim from JayCar. Being a typical programmer, I have very little idea how computers actually work on the physical level so this gives me an easy introduction to lower-level coding and electronics in general.

The Arduino is a small board with a fairly capable 8 bit microprocessor (an ATmega328 to be precise) with the IO pins hooked up to convenient headers ready for attaching external devices. The CPU has its own RAM and programmable flash memory, and it comes with a bootloader that can reprogram the flash via the handy USB connection (which can also power the whole board). It is hard to imagine a more plug-n-play device.

I decided that I would follow the well-worn path and create a persistence of vision device for my first project. Mine consists of 7 LEDs hooked up to IO 7 pins (via appropriate resistors), the idea is to make the LEDs blink in such a way that recognisable shapes appear as the LEDs are waved quickly in front of your eyes.

My prototype is a little rough, but works fine in a darkened room (I was too cheap to spring for super bright LEDs and the darkness hides my shoddy soldering job.) The breadboard is too fragile to wave around so the LEDs are mounted on cardboard and connected using a couple of metres of CAT5, which conveniently has 8 internal wires to supply the 7 LEDs with a common ground. The total cost is less than $10, excluding the breadboard and the Arduino itself.

The Arduino programming environment is pretty nifty. The language used is a limited form of C++ (no standard library or runtime support for much of anything) with some extra libraries for managing the CPU’s features. Compiling and flashing the CPU is as simple as pushing a button. Here is the code that generated the above picture:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Array holding the graphic to display
static char* text[] = {
" XX   X     X  XX     XXXX   XXXX  X     X     ",
"X  X  XX    X  X  X   X   X  X     X     X     ",
"X  X  X X   X  X   X  X   X  X     X     X     ",
"XXXX  X  X  X  X   X  XXXX   XXX   X  X  X     ",
"X  X  X   X X  X   X  X X    X     X  X  X     ",
"X  X  X    XX  X  X   X  X   X     X  X  X     ",
"X  X  X     X  XXX    X   X  XXXX   XX XX      " };
 
static int outputPins[] = { 12, 11, 10, 9, 8, 7, 6 };
static int graphicLength;
 
 
void setup()
{
	// setup the initial state of the pins
  for (int i = 6; i<=12; ++i)
  {
    pinMode(i, OUTPUT);     
  }
	// pin 13 is hardwired to the onboard LED, turn it off
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
 
  graphicLength = 0;
  for (char* t = text[0]; *t!=0; ++t)
  {
    ++graphicLength;
  }  
}
 
void loop()
{
  while (1)
  {
    for (int i = 0; i < graphicLength; ++i )
    {
		// find out if the pin is supposed to be on (HIGH) or off (LOW)
      for (int pin = 0; pin < (sizeof( outputPins) / sizeof(outputPins[0])); ++pin )
      {
        if (text[pin][i] == ' ')
        {
          digitalWrite( outputPins[pin], LOW );
        }
        else
        {
          digitalWrite( outputPins[pin], HIGH );
        }
      }
      delay( 1 );
    }
  }
}

Not very efficient but simple enough to get going. I am already working on a more functional version which will have its own font and interrupt driven display.

Minecraft Creeper Shirt

The minecraft creeper face textureI don’t use my computer for games much these days, but I have been playing a bit of Minecraft lately. Minecraft is a strange beast, more of a pastime than an actual game, but well worth the money. I have tried online games before, and although I like shooting things, the first person shooters all look the same after a while, and the MMOs are tedious. A huge, multiplayer lego set turns out to be just what I wanted. Besides, I find the lo-fi graphics and even the obvious bugs in the game charming.

As I was invited to a fancy dress party recently, I decided I needed a Minecarft creeper shirt. The creepers are the most terrifying creatures in the game, and I knew I needed to do them justice. 4 pots of fabric paint and many hours gave this result:Me in my creeper teeshirt

SsssssSSSSS – kabooom!

Not too bad, if I say so myself.

Update: I have been asked how the tee shirt was made. This was my first experience with this type of craft, so perhaps a better way exists, but the following steps seemed to work OK:

Materials

  • Plain white tee shirt (I brought mine from the Warehouse for the princely sum of $8. If I was going to do it again I might spring for a better quality shirt since the one I got was made from rather thin fabric.)
  • Long straight edge ruler
  • A dark pencil (2B or similar), dress makers chalk would probably be better
  • Textile Ink – I used Fastex Textile Ink which I found in the craft section of Warehouse Stationary. The colours I used for the Creeper design were Black, White, Leaf and Green.
  • Some brushes
  • Water
  • Small containers for mixing colours (I used yogurt pottles)
  • Lots of newspaper to protect the table top
  • Lots of copier paper for stencils
  • Baking paper
  • An Iron
  • Some scissors

Method

First I ironed the shirt until it was as smooth as I could make it. Then with the ruler and pencil I divided the shirt into squares of equal size. Because the design I wanted extends all around the shirt, some of the squares wrap around across seams.

Don’t make the squares too small! Large areas are much quicker to paint than small ones.

I started at the centre line for both the front and marched the squares towards the edges. It doesn’t matter that the squares the wrap around over the seams are slightly different widths, being symmetrical is more important.

With the dining table covered in newspaper, I laid out the tee shirt as flat as I could. Then I inserted the glossy insert magazines that came with the paper into the tee shirt to keep the inside surfaces from touching. This is to stop the ink from bleeding through to the reverse surface when you brush it on.

I used a purpose-bought Weekend Herald for this, because I knew it came with a lot of glossy paper inserts that will not absorb ink or fall apart when damp like newsprint will. If you follow my lead, it is vitally important not to accidentally glance at any of the editorials, regular columns, or especially the letters to the editor. You need to maintain your calm for applying the ink.

To get really straight edges on the design it is best to mask out the fabric with masking tape. I found the really cheap off-brand sello-tape works even better, as the adhesive sticks just well enough to do the job but comes off very easily. However, I had far to many square to paint, so I just used bits of copier paper cut more or less straight with scissors. Holding down the paper against the fabric with one hand, I quickly brushed on the int with the other, taking particular care with the corners. Working this way I found I could do a square every couple of minutes.

I needed a lot a shades of green, so I was continuously mixing colours. Some very vivid colours can be created, but mixing in too much black or white just results in a muddy mess. Some of the squares are supposed to be white – I just left them unpainted.

The squares that wrap around from front to back across the seams were the hardest. I carefully folded the sides of the shirt up to reach the hidden side, then placed bits of baking paper over the wet ink before I laid the fabric flat against the newsprint. The prevented the ink from smearing if the shirt moved around, the baking paper doesn’t get stuck to the ink as it dries.

Once the front was done and completely dry, I fixed the ink (see below) before completing the other side. Remember the wash and dry your brushes.

Fixing the ink (so it doesn’t run when damp) is done with a hot iron. Iron each part of the shirt for 3-5 minutes to make sure that the ink stay where it is supposed to. I thought I did a pretty good job, but found the the black areas still ran a little when I washed the shirt, so you might like to pay particular attention to dark colours.

Go forth and impress people* with your custom, one-of-a-kind shirt.

* results may vary

Longest Word You Can Type (QWERTY Edition)

My previous blog entry on TXTing provoked this response from my friend Lloyd:

…[I] figured out that longest word typed with only the upper letters in the QWERTY keyboard is not only TYPEWRITER but also includes several 3 other words: PERPETUITY, PROPRIETOR and REPERTOIRE. The longest in the middle line is: GALAHADS and nothing from the bottom line but 2 character element symbols like: Zn

Obviously this is some sort of geek challenge. I accept!

Using Python I replicated Lloyd’s results for the top row of the QWERTY keyboard:
PERPETUITY, PROPRIETOR, REPERTOIRE, and TYPEWRITER

Lloyd’s result for the middle row is highly suspect – GALAHADS is the plural of a proper noun. www.thefreedictionary.com does cite a couple of references, but it certainly isn’t in the dictionary I am using. My results are:
ALFALFA and HALALAS (a unit of currency in Saudi Arabia)

There is nothing of note on the vowel-forsaken bottom row.

The longest words that can be typed using only your left hand are:
AFTEREFFECTS, DESEGREGATED, DESEGREGATES, RESEGREGATED, RESEGREGATES, REVERBERATED, REVERBERATES, and STEWARDESSES

For the right hand I get:
HYPOLIMNION (the bottom layer of water in a deep lake)

It seems that Lloyd and I are not the only ones to try this experiment, Wikipedia has completely different (and even more obscure) words listed.