Project showcase
ASCII-Braille Real-Time Translation via Arduino

ASCII-Braille Real-Time Translation via Arduino © GPL3+

A senseless, badly implemented idea for anybody to improve: ASCII-Braille real-time translation via Arduino.

  • 10 views
  • 0 comments
  • 0 respects

Components and supplies

About this project

Take an absurd idea: create a 2x6 solenoid matrix, and translate ASCII characters received via serial port into the corresponding Braille dot configuration.

Then, try to implement it in the cheapest, quickest and dirtiest way in a few days before your summer holydays.

What do you get? A mess.

But an interesting one (at least on the software side...), and easily improvable by everyone!

Why absurd? Visually impaired people use screen readers, incredibly more effective than any mechanical device. Plus, even for deaf and blind people, my prototype, requiring that somebody sends ASCII characters to an Arduino, would be very unpractical to say the least.

In any case, one can as well implement a 2 x 6 LED matrix (in fact, that's how I tested the software!) to get the utmost absurdity: visual Braille! And that was my true intention, making an unusual implementation requiring the use of bit masks in a translation process.

Contrary to the poor breadboarding and component choice, the software is fully successful, and most probably is the only useful part of this project.

Even before describing the idea, I'd like to state that I know that I should and would have done better.

It's very obvious that I ventured in uncharted terrain totally beyond my minimal knowledge. I'll gladly accept to be the laughing stock of any competent Arduino fan.

Main problems:

Real push-pull solenoids have the extraordinary advantage that they snap back in their default position as soon as the current is removed - having bought on ebay the cheap, push-only solenoids described here (Don't be mislead! Despite the ad, they are NOT push-pull type!): https://www.ebay.it/itm/Mini-DC-5V-5mm-Push-Pull-Type-Permanent-Magnet-Strong-magnetic-Electric-Solenoid/172438873301, my greatest waste of time was trying to transform them into something that could snap back when inactive. And I didn't succeed...
  • 2) I shouldn't have been worried to use 12V or 9V solenoids. When purchasing the cheapest 5V ones, I wanted to power everything with the classic 5V from Arduino (I still ignored the current absorption problem of the solenoids).

A silly concern on my part: it's very easy to power a breadboard at 9V or 12V with a separate power supply, then control it with Arduino.

  • 3) Current: solenoids, even the smallest and cheapest 5V that I used, are thirsty devices. Any attempt to power more than two solenoids with Vin or 5V from Arduino results in continuous resets, due to the excessive current absorption by the solenoids. Even with separate power to the solenoids, if power is marginal, misfires are frequent. Any serious project involving solenoids & Arduino requires independent supplies of adequate power and well-conceived circuits. Important: by powering my cheap solenoids above their nominal voltage (e.g. by setting the external switchable power supply to 7, 5V instead of 5V), action is much more energetic, with the "piston" of the solenoid being ejected at some distance.

Here is a list of good implementations of solenoids + Arduino: https://www.google.com/search?tbs=li%3A1&q=arduino+solenoids&oq=arduino+solenoids - see in particular https://arduino.stackexchange.com/questions/50668/can-arduino-control-8-solenoids for good technical advice. For a single 5V solenoid, Arduino alone may suffice - but you will see that most implementations require special components and a good knowledge of electronics.

Operation

With the solenoids arranged in a 3x2 pack as illustrated (each solenoid was individually wrapped in insulating tape, then again in rows and in a single block), the objective would be to have the core of each solenoid pop out /stick out if its respective point is activated. And that would work egregiously with *real* push-pull solenoids, that would pop out decidedly then pop in as soon as inactivated.

In fact, with the illustrated circuit and components, and with everything powered at 5V, even with separate power supplies the solenoids barely move (unless power supplies are set at an higher voltage... that may be unsafe!) but, with the thumb's pad gently pressed on the tips of the pistons, one may anyway perceive which tips are being rised and which tips are motionless. If one piston disengages and is ejected, it must be clicked in again: another drawback of this suboptimal equipment.

I would beg anybody that may be interested in improving this project to share a refined version of the circuit as soon as available, for everybody to see.

Thanks for the attention!

Code

Arduino ASCII- Braille TranslatorArduino
/*
  Arduino ASCII- Braille Translator
  by Cesare Brizio | CC by-sa-nc
  this sketch is in the public domain

  Version 1.0 - 29 June 2019
  ------------------------------
  This sketch will use six small solenoids/electromagnets arranged in
  three rows of two columns to operate a Braille dot matrix.
  Any ASCII character sent to Arduino via COM port will be "translated"
  in a timed sequence of Braille symbols by configuring, one character 
  at a time, the dot matrix, so that the "dots" (solenoids) corresponding
  to the current ASCII character are raised for 500 msec before passing to
  the subsequent character. 
  When an un-translatable character is sent, a short buzz is emitted.

  ==== DOT NUMBERING ====
  Dots are not numbered according to the Braille convention, but are
  conventionally numbered from left to right, then from top to bottom:
  1  2
  3  4
  5  6
  As an example, showing letter "b" (asterisk represent an high dot):
  *-
  *-
  --
  will require raising dots number 1 and 3


  ==== DOT CONFIGURATION ====
  Dot configuration will be stored as a series of six binary values. As an
  example, according to the preceding explanation, the configuration for "b"
  is 101000.
  As long as configurations contain just 6 bits of information, they can be
  stored in a single char that, translated bitwise (least significant bit at
  right), corresponds to the needed configuration.
  So, 101000 (configuration for "b"), corresponding to DEC 40 and HEX 28,
  will be represented by ASCII character "(".
  Summarizing, considering that ascii code for "b" is 98D (62H) I will say
  that 
  myBrailleDots[98] = 40; 
  meaning that the binary sextet corresponding to letter "b" is 101000.
 
  When needed, a bitwise AND with increasing powers of two (from 1 to 32)
  will reveal which dots shall be raised: this is accomplished by iterating
  through a 6 bit mask:
  
  Some simplifications will be applied, e.g.:
  a) the multi-letter Braille glyphs (ch, ing, for, ar, th and others)
  b) number prefix (010111), 
  c) letter prefix (000101), 
  d) uppercase prefix (000001) and other prefixes
  will not be implemented in this version, but this sketch can
  be quite easily implemented with the needed modifications.
*/  

// Declare a char array with one index for every possible ASCII byte / character
byte myBrailleDots[255];
int firstOutputPin = 2; // pin corresponding to least significant bit
int buzzerPin = 8; // Buzzer on pin 8
byte matrixPoints = 0; // byte that will store the point matrix configuration
                       // for a specific ASCII character
byte inByte;
byte mask = 1; //our bitmask

void setup() {
  // Temporarily assign 99 to every possible ASCII byte/character
  // All the characters in the input string will decode to "99" by default
  for (int i = 0; i < 256; i = i + 1) {
     myBrailleDots[i] = 99;
  }

  // Now, only for the ASCII characters with a corresponding Braille character.
  // assign the corresponding Braille Dot configuration
  myBrailleDots[32] = 0;  // blank is 000000
  myBrailleDots[33] = 14;  // exlamation mark is 001110
  myBrailleDots[34] = 7;  // double quote is 000111
  myBrailleDots[34] = 2;  // single quote is 000010
  myBrailleDots[40] = 15;  // left parenthesis is 001111
  myBrailleDots[41] = 15;  // right parenthesis is 001111
  myBrailleDots[44] = 8;  // comma is 001000
  myBrailleDots[46] = 13;  // period is 001101
  myBrailleDots[48] = 28; // 0 is 011100
  myBrailleDots[49] = 32; // 1 is 100000
  myBrailleDots[50] = 40; // 2 is 101000
  myBrailleDots[51] = 48; // 3 is 110000
  myBrailleDots[52] = 52; // 4 is 110100
  myBrailleDots[53] = 36; // 5 is 100100
  myBrailleDots[54] = 56; // 6 is 111000
  myBrailleDots[55] = 60; // 7 is 111100
  myBrailleDots[56] = 44; // 8 is 101100
  myBrailleDots[57] = 24; // 9 is 011000
  myBrailleDots[58] = 12; // colon is 001100
  myBrailleDots[59] = 10; // semicolon is 001010
  myBrailleDots[63] = 11; // question mark is 001011
  myBrailleDots[65] = 32; // A is 100000
  myBrailleDots[66] = 40; // B is 101000
  myBrailleDots[67] = 48; // C is 110000
  myBrailleDots[68] = 52; // D is 110100
  myBrailleDots[69] = 36; // E is 100100
  myBrailleDots[70] = 56; // F is 111000
  myBrailleDots[71] = 60; // G is 111100
  myBrailleDots[72] = 44; // H is 101100
  myBrailleDots[73] = 24; // I is 011000
  myBrailleDots[74] = 28; // J is 011100
  myBrailleDots[75] = 34; // K is 100010
  myBrailleDots[76] = 42; // L is 101010
  myBrailleDots[77] = 50; // M is 110010
  myBrailleDots[78] = 54; // N is 110110
  myBrailleDots[79] = 38; // O is 100110
  myBrailleDots[80] = 58; // P is 111010
  myBrailleDots[81] = 62; // Q is 111110
  myBrailleDots[82] = 46; // R is 101110
  myBrailleDots[83] = 26; // S is 011010
  myBrailleDots[84] = 30; // T is 011110
  myBrailleDots[85] = 35; // U is 100011
  myBrailleDots[86] = 43; // V is 101011
  myBrailleDots[87] = 29; // W is 011101
  myBrailleDots[88] = 51; // X is 110011
  myBrailleDots[89] = 55; // Y is 110111
  myBrailleDots[90] = 39; // Z is 100111
  myBrailleDots[97] = 32; // A is 100000
  myBrailleDots[98] = 40; // B is 101000
  myBrailleDots[99] = 48; // C is 110000
  myBrailleDots[100] = 52; // D is 110100
  myBrailleDots[101] = 36; // E is 100100
  myBrailleDots[102] = 56; // F is 111000
  myBrailleDots[103] = 60; // G is 111100
  myBrailleDots[104] = 44; // H is 101100
  myBrailleDots[105] = 24; // I is 011000
  myBrailleDots[106] = 28; // J is 011100
  myBrailleDots[107] = 34; // K is 100010
  myBrailleDots[108] = 42; // L is 101010
  myBrailleDots[109] = 50; // M is 110010
  myBrailleDots[110] = 54; // N is 110110
  myBrailleDots[111] = 38; // O is 100110
  myBrailleDots[112] = 58; // P is 111010
  myBrailleDots[113] = 62; // Q is 111110
  myBrailleDots[114] = 46; // R is 101110
  myBrailleDots[115] = 26; // S is 011010
  myBrailleDots[116] = 30; // T is 011110
  myBrailleDots[117] = 35; // U is 100011
  myBrailleDots[118] = 43; // V is 101011
  myBrailleDots[119] = 29; // W is 011101
  myBrailleDots[120] = 51; // X is 110011
  myBrailleDots[121] = 55; // Y is 110111
  myBrailleDots[122] = 39; // Z is 100111
  pinMode(buzzerPin, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  Serial.begin(9600); 
  Serial.println("ASCII - Braille Arduino Converter");
  Serial.println("LED test - begin");
  digitalWrite(2,HIGH);
  digitalWrite(3,HIGH);
  digitalWrite(4,HIGH);
  digitalWrite(5,HIGH);
  digitalWrite(6,HIGH);
  digitalWrite(7,HIGH);
  delay(3000);
  digitalWrite(2,LOW);
  digitalWrite(3,LOW);
  digitalWrite(4,LOW);
  digitalWrite(5,LOW);
  digitalWrite(6,LOW);
  digitalWrite(7,LOW);
  Serial.println("LED test - end");
  Serial.println("Type some character: it will be transmitted to Arduino and displayed on a Braille 2 x 3 matrix");
}


void loop() {
   // Braille print data only when you receive data:
   if (Serial.available() > 0) {
      // read the incoming byte:
      inByte = Serial.read();
      // say what you got:
      Serial.print("Received (inByte): ");
      Serial.println(inByte);
      // Translate inByte in matrix points
      Serial.print("Matrix points variable (myBrailleDots[inByte]): ");
      Serial.println(myBrailleDots[inByte]);

      // Braille print only admissible characters
      // the unadmissible ones decode to 99
      if (myBrailleDots[inByte] == 99)   // if unadmissible
      {
         Serial.println("Not a translatable character");
         digitalWrite(buzzerPin,HIGH); // buzz
         delay(250); 
         digitalWrite(buzzerPin,LOW); // stop buzzing
      }
      else{ 
              int thisPin = 2;
              for (mask = 000001; mask<64; mask <<= 1) { 
                  Serial.print("thisPin = ");
                  Serial.println(thisPin); 
                  if (myBrailleDots[inByte] & mask){ // if bitwise AND resolves to true
                     Serial.print("AND successful, put pin on!");
                     Serial.println(mask);  
                     digitalWrite(thisPin,HIGH);               
                  }
                  else{ //if bitwise and resolves to false
                     Serial.print("AND unsuccessful, put pin off!");
                     Serial.println(mask);  
                     digitalWrite(thisPin,LOW);
                  }
              thisPin = thisPin + 1;   
              }
      } 
      delay(3000); // allow 3 sec before passing to next character
   }
}

Schematics

General overview of a breadboard implementation of the circuit
Caution: read the text attentively. There are many better implementations of solenoids under Arduino.
Arduino braille bb pzu6cnuqga

Comments

Similar projects you might like

Real time LPG monitoring system

Project showcase by TEAM DIY

  • 2,906 views
  • 2 comments
  • 3 respects

LED Ring Real Time Clock

Project showcase by 3 developers

  • 1,320 views
  • 0 comments
  • 1 respect

Arduino OLED Temperature Display with Real Time Clock

Project tutorial by Keval Doshi

  • 10,573 views
  • 7 comments
  • 35 respects

Real Time Clock (RTC) PCF8563

by Arduino_Scuola

  • 7,499 views
  • 1 comment
  • 6 respects

LCD with DS3231 Real Time Clock Module

Project showcase by Tan See Youu

  • 45,349 views
  • 0 comments
  • 36 respects
Add projectSign up / Login