Creating a 5 dot matrix large scale printer

I’d like some advice on how to create a 5 dot matrix printer.

I have 5 lasers that can be turned on and off to write dashes on a sheet of material as it emerges from a process.

I have calculated that each dash will take approx 1 second with a 1 second gap. so using 5x5 matrix for each character will take ~10 secs.

I would like to write “words” up to 30 characters and be able to change what is written easily. I have a 5x5 matrix for each letter of the alphabet plus numbers and a few symbols, so 40 in all.

I can easily interface the 5 digital outputs from the Arduino into the on/off for each of the lasers.
I am looking for the best way to create the <30 digit “word” and then get the arduino to turn the outputs on and off as each column of a segment is sequenced.

I am new to Arduino so would appreciate any guidance, including where to look for a solution.

Many thanks

David

Serial out to a shift-reg, burn, serial out to shift-reg, burn, ....

123Splat

Thank you for replying. Could you explain your solution in a bit more detail as I don't understand your suggestion.

I do wish to use the Arduino standalone, so would program it with the required text and then run it standalone.

I am thinking to create a new sketch for each text that I wish to print.

Thanks
David

5 by 5 character matrix (not much resolution, but OK) = 5 bit positions (y axis) x 5 time positions (x axis)
with 5 time positions for space (one after each dot) between characters, correct? Example:
T0 T1 T2 T3 T4 T5 T6 T7 T8 T9
Y4 OFF ON OFF ON OFF ON OFF ON OFF ON = X.X.X.X.X. ==> XXXXX
Y3 OFF OFF OFF OFF OFF OFF OFF OFF OFF OFF = . . . . . . . . . . ==> .....
Y2 OFF ON OFF ON OFF OFF OFF ON OFF ON = . x . x . . . x . x ==> XX.XX
Y1 and so on and so on
Y0

If you plan to use lineprinter style (print a line at a time) move the printhead along the x axis for each print line (Y4 to Y0) and then shift the printed material up or down a line space (space between printed lines). you need a laser print head with 5 lasers and 5 bits in a shift register to represent the drive state of each laser (bit on, laser on,, bit off, laset off). You shift the bit pattern which represents your T0 (left most) row of your dot matrix for that character, into the shift register. Then latch the shift register, drive the lasers with TTL modulation from the five bits of the shift register, for one second. Save the millis value when you stop the laser drive. move the print head to the T2 position. load the T2 bit pattern into the shift reg. when millis now - millis laser off = 1 second (1000), or better, latch and TTL drive the lasers for T2 pattern. Assuming that the one second off time is to cool the laser head. With proper design of your laser head, you probablly wont need the one second off after each burn, just add one at the end of each character.

You could simplify your print bed design by printing each Y position simultaneously, but your print head would then have to consist of one laser for each printable bit position in X. you'll also need a shift reg bit for each printable bit and a buffer in working storage to bild each Y line. You load the Yx bits into the shifr reg. burn for one sec. shift the printed material up one Y position, latch and burn the next Yx line. and so on and so on. (not really a good idea, but at great expense in hardware and software resources, gives much faster print time for each message line, and is easier on the lasers).

I may have mis-interpreted your meaning, but I think you should be able to get an idea from the above.
This is NOT the grail of how to do it, just my vision of same. Good luck!

Depending upon your material and how sensitive it is to the lasers, suggestion 2 is basically how most 'laser' (xerox) printer do it. A print bar out of a dead laser printer may help. Old IBM 3800 or Xerox 9700 printer systems use heafty IR bars.

123 splat,

Thank you for your suggestion, I will be printing each Y position simultaneously. I will have to read up on how to work with arrays with Aduino.
Your suggestion of setting up an array with Y0 to Y 4 for each of the dots and then indexing forward T0 -> T1 ->T2 .... would work well as I can do that with a loop and put the 1 sec on and 1 sec delay between dots into the loop which will allow me to fine adjust so that the printing looks right.
It will also allow me to put a reset in so that I can restart easily.

For 30 characters it will mean the array is from T0 to T149 and Y0 to Y4 so 5x150. I don't know what the max size is.

Thanks again

David

If it is a fixed message, load the message's character array into eprom and read in a coll at a time, burn move head (or material), read in next coll, burn,,, ans so on.

David0072:
For 30 characters it will mean the array is from T0 to T149 and Y0 to Y4 so 5x150. I don't know what the max size is.

To make things easy to put in the sentences later, you can make an array of character definitions consisting of 5 bytes for each character you will be printing. Then when you have a message to print, you need only use the chracter as an index into the array, and output 5 bytes in succession, turning the appropriate lasers on or off according to the values fetched.

Here's an example of a 5 byte sequence for the letter 'X'.
An 'o signifies a laser ON and a '. signifies a laser OFF.
Below that are the values you would place in the array at the 'X' index.

  o...o
  .o.o.
  ..o..
  .o.o.
  o...o

Depending on the drive circuit for the lasers (HIGH = laser on, or HIGH = laser off), your byte values will be:

0x11, 0x0A, 0x04, 0x0A, 0x11
or
0x0E, 0x15, 0x0B, 0x15, 0x0E

If you do something like this, there will be no need to reprogram the Arduino for each message... just send it via serial.. Of course, you still could reprogram if you don't have an easy means of attaching a PC to the Arduino's USB connector.

lar3ry,

The array works well, I have created it manually with all the hex for each column of dots for each letter. It then “prints” to required pattern using the lasers. I have to create a new array for each thing I want to write

You mentioned a way to just write the letters and then get the Arduino to look the hexadecimal up. I was wondering whether you have a suggestion for the best way to do this?

Many thanks for your help. I haven’t done an C programming before so its quite a steep learning curve.

David

Here’s a little sketch to show you how you might use an array of bytes to hold the actual “font”. The array is two dimensional, and would hold the digits 0 through 9 (but I only put in the first three characters, the digits 0, 1, and 2), some punctuation, and the upper case letters A though Z. (that’s the first dimension, [43]. You can think of a two dimensional array as an array of arrays. In other words, each element of the first dimension ( [43] ), holds a 5 byte array. The first element of the font array holds the dot pattern for a character ‘0’ in Y order See the comments in the code.

byte font[43][5] = {   // This array will take up 215 bytes.
  {
    B01110,  // number 0
    B10001,
    B10101,
    B10001,
    B01110
  } ,

  {
    B00101,  // number 1
    B01001,
    B11111,
    B00001,
    B00001
  } ,

  {
    B01001,  // number 2
    B10011,
    B10101,
    B01001,
    B00001
  }
};

void setup() {
  Serial.begin(115200);
}

void loop() {
  char data;
  if (Serial.available()) {
    data = Serial.read();    // get a byte of data
    printit(data);           // and print it
  }
}

void printit( byte fontchar ) {
  fontchar -= '0';  // subtract 48 ( char '0' to get the index into the first element of the array

  for (byte column = 0; column < 5; column++) {  // Starting at the appropriate fontchar entry, count 5 entries
    Serial.println(font[fontchar][column], BIN);    // and print them out (or turn lasers on and off at timed intervals
  }
  Serial.println();
}

Run this code, send the characters 0, 1, or 2 with the Serial Monitor. You will get a series of binary values. Copy the output to a text editor, and choose a fixed pitch font (New Courier will work). Make them all the same length (5 characters), by adding zeroes to the beginning of each short line. Now put a space between each character on a line (for better viewing). Use the Search/replace to change all '1’s to ‘o’ (lower case letter O). Then change all the zeroes to ’ ’ (space). Now, if you tilt your head to the left, you should see mirror images of the characters you typed in. Mirror image because of the way you are outputting the characters, from the top down. On your material, they should come out right.

Attached is a picture of the output after editing.

Hope this helps.

5x5.jpg

Lar3ry,

Thank you for your help so far. It has been fantastically helpful.

Rather than using the serial input, I would prefer to create a new sketch for each different work I wish to write using the lasers. We’ll be running the same word for quite a while so don’t need to change it regularly. I am thinking that I can just have a master sketch where I just change the word and upload the new sketch

So, I am thinking that I can create an array with the dot sequence for all the letters and numbers. So, then for example if I wish to write CD, I can start with C and then go through a if…else loop through all the characters until I get to C. I can then do the same for D and so on if there were more letters.

Is there a way to read each character from a word. A bit like bitRead allows me to extract each bit from a hex number?

My thinking is as follows:

in the Sketch I write the word I want to “print” using my 5 lasers.

eg if I want to write NON-MAGNETIC

  1. I load the sketch with NON-MAGNETIC in an array

  2. I first ask for character 1 // ie N

  3. using if…else I run through all the characters until I get to N and then use the defined array for N to print it using the lasers

  4. I then get character number 2 which will be O

5 I then repeat 3 but for the letter O

…etc. etc.

My difficulty is working out how to pick the letters out one at a time from the required work. Is there a bitRead type command that works with letters?

Many thanks

David

David0072:
So, I am thinking that I can create an array with the dot sequence for all the letters and numbers. So, then for example if I wish to write CD, I can start with C and then go through a if…else loop through all the characters until I get to C. I can then do the same for D and so on if there were more letters.

Good heavens, No! See the sketch I posted to see how to access the individual characters.
The characters are arranged in the array in increasing order. Starting from the number ‘0’ to the letter ‘Z’
So they go

 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

(you can start with the punctuation below ‘0’ and end higher if you want)

So, the first character is a ‘0’ (the ASCII value of the printable character, which is 0x30 or decimal 48.
So, let’s assume you want to print “CD” with your lasers:

First, you fetch the character C from your string.
Then you subtract ‘0’ from it.
This will do the following: ‘C’ is decimal 67, and ‘0’ is decimal 48, so 67-48 = 19
Well, look at that. we have an index, starting from 0.
However, each character contains 5 bytes defining the Y columns.
So we multiply 19 * 5, which will point us to the first Y column of the letter ‘C’, which is at index 95
So, we now use a for loop to count from 95 to 99, which points us to each Y column byte for ‘C’.

Now we can use bitRead() to extract the individual bits (5 of them, so we can use yet another for loop), and digitalWrite each bit to a laser.

Is there a way to read each character from a word. A bit like bitRead allows me to extract each bit from a hex number?
eg if I want to write NON-MAGNETIC

  1. I load the sketch with NON-MAGNETIC in an array

You are right up to here. Your array will be programmed like this:

char word = “NON-MAGNETIC”

Then you select each character in a for loop. In pseudo-code:

for select = 0 to length of word   // select each character in turn
   c = word[select]    // this is the character we select
   c = c - '0'   // make it into an index
   c = c * 5     // and adjust it to get to the Y columns
    for column = c  to c + 4 {   // count 5 columns
        Y = font[column]     // and grab each one
        for bit = 0 to 4 {      // count from bits 0 through 5
            onoff = bitRead(Y, bit)     // read them into onoff, one at a time
            digitalWrite(laserPin[i], onoff)  // and write them to the laser pins
        }
       delay (dot spacing)
       turn all the lasers off
    }
    delay(character spacing)
}

That’s an approximation. There may be errors in it. Youll need to translate it into real C++, add some delays, declare some variables, and so on, but that a start at an outline.

Lar3ry,

Thank you for your help and patience, I'm afraid this is quite a steep learning curve for me. I tried your suggestion about using the ASCII value for each character.

It works well, but the printed output always has 5x5 dots for each letter or symbol. This looks a bit strange as letters like M or W fill the space but letters like I or a full stop . look a bit strange.
Some letters and symbols would look better if they were only 5 dots high by 1 or 2 wide.
If I have variable width then I can't see how to make the technique of subtracting the ASCII characters and multiplying them by 5 work.

So, if I want to laser write the word LIGHT, it would look better as






So I thought that maybe I could enter the text to be written as a String and then work out the number of characters using the length command. I can then create a for loop to pick each letter in turn. I can easily define the pattern for each letter. some will be 1x5 some 2x5, etc up to 5x5.

e.g C and I where I is shorter.

C is 0x0E,0x11,0x11,0x11,0x00, and
I 0xFF, 0x00,

How can I look up the bit pattern for a particular letter

Something like

The words to be written are a string ie NON-MAGNETIC
"length" calculates this is 12 letters long so using the "charAt" command and a "for" loop I can create the following:

Letter 1 is N...
Letter 2 is O...
.
.
.
Letter 12 is C

If I know I want to laser write an N and I have N defined as an array, how do I "find" the array for N.

Thanks

David

You can still use an 8-bit byte to store the chatacter dots. The problem then becomes “How do I know when to start and stop the sending of the dots and spaces of the character?”

Well, it’s pretty easy. Look at the characters for M and I (letter I with no serif).

Y bytes        laser pattern
------------------------
1 1 1 1 1     o o o o o
0 1 0 0 0       o      
0 0 1 0 0         o
0 1 0 0 0       o      
1 1 1 1 1     o o o o o

0 0 0 0 0              
0 0 0 0 0              
1 1 1 1 1     o o o o o
0 0 0 0 0              
0 0 0 0 0

While it’s obvious we don’t need four of the bytes for the I, it’s also obvious that it’s easier to access the y bytes using the index methods I mentioned. So how do we decide when to start printing and when to stop? Three ways come to mind.

  1. always start with the first of the five Y bytes, and somehow indicate the end of the printable Y bytes
  2. somehow indicate the start of the printable Y bytes, and always print until we are done with the fifth byte.
  3. Somehow indicate the start and the end of the printableY bytes.

Fortunately, we only use 5 bits to print a column of a character, leaving us three bytes to work with, so we can use, for example, bit 5 set to a 1, to indicate that we want to print this column, and set to a zero to indicate we are done with the character. So, adding the ‘flag bit’ (F), we get the following . I have used method 1, but you could place the printable columns anywhere in the 5 bytes. The slight advantage of method 1 is that you always print the first printable Y byte, regardless of the flag, and stop when you’ve printed the column with the flag, and yoyu can then start timing to the nect character.

F Y bytes     laser pattern
- -------     -------------
0 1 1 1 1 1     o o o o o
0 0 1 0 0 0       o      
0 0 0 1 0 0         o
0 0 1 0 0 0       o      
1 1 1 1 1 1     o o o o o   <-- last byte, start timing and fetch next character

1 1 1 1 1 1     o o o o o   <-- last byte, start timing and fetch next character
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0