Sensor Display : Prison Tap Code


So back in the Vietnam War, US prisoners of war would be isolated from each other in solitary cells, where verbal communication was impossible. To make up for this, prisoners used Tap Code, an ancient Greek invention. Tap code is based off of a 5×5 table of the Latin alphabet, as shown below:

One prisoner would knock a certain number of times to determine the row, pause, and then knock a certain number of times to determine the column of the letter they were describing. The listening prisoner would mark down the two numbers, and determine which letter was being knocked out by checking the table (usually mentally). So, for example, 1 tap then 1 tap would be A, 4 taps then 2 taps would be R, and so on.
I decided to create a listening prisoner, for whom I could tap messages, and they would print them out in a console. To better visualize this process, I created an animated tap table which would show the letter being tapped. Certainly, this makes the process much easier than it was the prisoners of war in Vietnam, but I lack the time or necessity to become fluent. Here it is in action:

To complete this, I used a piezo, a vibration sensor, to detect my taps on the table. Here is my circuit (real bare bones stuff):

20141028_203031

In Fritzing:

assignment 10 knock sensing fritzing

My Arduino code:

    
const int knockSensor = A0; 
const int threshold = 70; 
const int knockTimeMaxThreshhold = 1000;
const int knockTimeMinThreshhold = 100;

int sensorReading = 0;
int knockNum = 0;
long knockTime = 0;
int col = 0;
int row = 0;

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

void loop() {
  sensorReading = analogRead(knockSensor);   
  if (millis() - knockTime > knockTimeMaxThreshhold)
  {
    if (knockNum == 1)
    {
      knockNum = 2;
      knockTime = millis();
    }
    else if (knockNum == 2)
    {
      Serial.print("A");
      Serial.println(100);
      knockNum = 0;
      col = 0;
      row = 0;
    }
  }
  if (sensorReading >= threshold && millis()-knockTime > knockTimeMinThreshhold)
  {
    knockTime = millis();
    if (knockNum == 0)
    {
      knockNum = 1;
    }
    if (knockNum == 2)
    {
      row++;
      Serial.print("B");
      Serial.println(row);
    }
    else
    {
      col++;
      Serial.print("A");
      Serial.println(col);
    }
  }    
  delay(1); 
}

My Processing code:

// This Processing program reads serial data for two sensors,
// presumably digitized by and transmitted from an Arduino. 
// It displays two rectangles whose widths are proportional
// to the values 0-1023 received from the Arduino.
 
// Import the Serial library and create a Serial port handler
import processing.serial.*;
Serial myPort;   
 
// Hey you! Use these variables to do something interesting. 
// If you captured them with analog sensors on the arduino, 
// They're probably in the range from 0 ... 1023:
int valueA;  // Sensor Value A
int valueB;  // Sensor Value B
 
//------------------------------------
void setup() {
  size(200, 200);
  String portName = Serial.list()[0]; 
  myPort = new Serial(this, portName, 9600);
  serialChars = new ArrayList();
}
void draw() { 
  int prevValA = valueA;
  processSerial();
  if (valueA == 100){
    print(tapTable(valueB-1, prevValA-1));
    valueA = 0;
    valueB = 0;
  }
  for(int i = 0; i < 5; i++)
  {
    float iw = width*i/5;
    float ih = height*i/5;
    line(iw,0,iw,height);
    line(0,ih,width,ih);
    for(int j = 0; j < 5; j++)
    {
      color c = color(0,0,0);
      if (valueA - 1 == j && valueB - 1 == i)
      {
        c = color(255,0,0);
      }
      float wOffset = width/10-5;
      float hOffset = height/10+3;
      float jh = height*j/5;
      fill(c);
      text(tapTable(i,j),iw+wOffset,jh+hOffset);
    }
  }
}

char tapTable(int col, int row)
{
  char[][] table = {{'A','B','C','D','E'},
                    {'F','G','H','I','J'},
                    {'L','M','N','O','P'},
                    {'Q','R','S','T','U'},
                    {'V','W','X','Y','Z'}};
  return table[constrain(row,0,4)][constrain(col,0,4)];
}
 
ArrayList serialChars;      // Temporary storage for received serial data
int whichValueToAccum = 0;  // Which piece of data am I currently collecting? 
boolean bJustBuilt = false; // Did I just finish collecting a datum?
 
void processSerial() {
 
  while (myPort.available () > 0) {
    char aChar = (char) myPort.read();
 
    // You'll need to add a block like one of these 
    // if you want to add a 3rd sensor:
    if (aChar == 'A') {
      bJustBuilt = false;
      whichValueToAccum = 0;
    } else if (aChar == 'B') {
      bJustBuilt = false;
      whichValueToAccum = 1;
    } else if (((aChar == 13) || (aChar == 10)) && (!bJustBuilt)) {
      // If we just received a return or newline character, build the number: 
      int accum = 0; 
      int nChars = serialChars.size(); 
      for (int i=0; i < nChars; i++) { 
        int n = (nChars - i) - 1; 
        int aDigit = ((Integer)(serialChars.get(i))).intValue(); 
        accum += aDigit * (int)(pow(10, n));
      }
 
      // Set the global variable to the number we captured.
      // You'll need to add another block like one of these 
      // if you want to add a 3rd sensor:
      if (whichValueToAccum == 0) {
        valueA = accum;
        // println ("A = " + valueA);
      } else if (whichValueToAccum == 1) {
        valueB = accum;
        // println ("B = " + valueB);
      }
 
      // Now clear the accumulator
      serialChars.clear();
      bJustBuilt = true;
 
    } else if ((aChar >= 48) && (aChar <= 57)) {
      // If the char is between '0' and '9', save it.
      int aDigit = (int)(aChar - '0'); 
      serialChars.add(aDigit);
    }
  }
}

Comments are closed.