Thursday, April 18, 2013

Starting up again

I will start posting on here again soon. This will be a place to keep my thoughts organized so I don't have to keep everything in my head. I will be writing about


  • REST API Best Practices
  • R Programming and custom R Packages
  • Felxible artificial intelligence competition framework.
  • Interesting computer science problems or bugs I have worked on.
  • Others?
Stay tuned!

Friday, July 13, 2012

Java Socket Chat Application v0.1

This is a project for a couple of my CS1332 students. I have been working with them explaining how sockets and networking works specifically related to Java sockets. This is a quick proof of concept application that I threw together just to make sure that I was leading them in the right direction.

Right now it is an infinite loop that checks to see if the user has submitted text to the console or if the socket has received a string. All text is logged to an output file on each machine with the correct prefix to each message (">>" for incoming and "<<" for outgoing).



Code can be found below.

Server.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket sSocket = new ServerSocket(3000);
            Socket socket = sSocket.accept();
            System.out.println(\"Client accepted\");
            Chatter c = new Chatter(socket, \"Server.log\");
            c.run();
        } catch (IOException e) {
            // ignore
        }
    }
}

Client.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket sSocket = new ServerSocket(3000);
            Socket socket = sSocket.accept();
            System.out.println(\\\"Client accepted\\\");
            Chatter c = new Chatter(socket, \\\"Server.log\\\");
            c.run();
        } catch (IOException e) {
            // ignore
        }
    }
}

Chatter.java

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class Chatter {
    private Socket socket;
    private BufferedInputStream bis;
    private ObjectInputStream ois;
    private ObjectOutputStream oos;
    private BufferedInputStream console_bis;
    private Scanner scanner;
    private BufferedWriter bfw;

    public Chatter(Socket socket, String logName) {
        try {
            this.socket = socket;
            this.bis = new BufferedInputStream(socket.getInputStream());
            this.oos = new ObjectOutputStream(socket.getOutputStream());
            this.console_bis = new BufferedInputStream(System.in);
            this.scanner = new Scanner(console_bis);
            this.bfw = new BufferedWriter(new FileWriter(new File(logName), true));
            this.bfw.append(\"\\n\\n\"
                    + new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\")
                            .format(new Date()) + \"\\n===================\\n\");
            this.bfw.flush();
            
            this.ois = new ObjectInputStream(bis);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        String temp = \"\";
        while (temp == null || !temp.equals(\"quit\")) {
            temp = readSocketMessage();
            if (temp != null) {
                if (temp.equals(\"quit\")) {
                    System.out.println(\"[[ Other User Logged Off ]]\");
                    close();
                    System.exit(0);
                }
                logMessage(temp, true);
            }
            temp = readConsoleMessage();
            if (temp != null) {
                sendMessage(temp);
                logMessage(temp, false);
            }
        }
        this.close();
    }
    
    private void close() {
        try {
            socket.close();
        } catch (IOException e) {
            // ignore
        }
        try {
            bfw.close();
        } catch (IOException e) {
            // ignore
        }
    }

    private String readSocketMessage() {
        try {
            if (bis.available() > 0) {
                return (String) ois.readObject();
            }
        } catch (IOException e) {
            System.err
                    .println(\"Fatal Socket Exception: could not read message.\");
            System.exit(0);
        } catch (ClassNotFoundException e) {
            System.err.println(\"Socket Exception: peer sent bad input.\");
        }
        return null;
    }

    private String readConsoleMessage() {
        try {
            if (console_bis.available() > 0)
                return scanner.nextLine();
        } catch (IOException e) {
        }
        return null;
    }

    private void sendMessage(String message) {
        try {
            oos.reset();
            oos.writeObject(message);
            oos.flush();
        } catch (IOException e) {
            System.err
                    .println(\"Fatal Socket Exception: could not send message.\");
            System.exit(0);
        }
    }

    private void logMessage(String message, boolean display) {
        try {
            if (display) {
                System.out.println(\">> \" + message);
                bfw.append(\">> \");
            } else
                bfw.append(\"<< \");
            bfw.append(message).append(\"\\n\");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Sunday, July 8, 2012

Whiteboard Clock


Introduction

I have been working on a calculator for my girlfriend, but unforeseen complexity has caused the project to stretch out over months rather than weeks. In place of finishing the calculator, I came up with a more simple, more useful project (birthday present) which has the potential to be profitable if the design is tweaked to be easier to manufacture. This post contains (1) a video of the finished product (2) followed by background information (3) followed by a gallery detailing each step of the build process and (4) finally the Arduino code behind the functionality.


Lizz's Whiteboard Clock


Background

Each led requires a high signal to turn on. This means that I need a total of 72 separate signals to turn on each led individually. However an Arduino only has 14 digital output. If we consider using pins in combinations there are a few methods of controlling large number of signals using a small number of I/O ports.

  1. Multiplexing: This allows a microprocessor to control 2^n signals with n outputs. These are used heavily when building custom hardware (verilog, VHDL, etc.) but there are not large IC chips available. I would have to string multiple smaller DEMUX chips together to achieve a 7 bit DEMUX.
  2. Charlieplexing: This allows a microprocessor to control n(n-1) signals with n outputs. Charlieplexing relies on the fact that LED are directional i.e. they will only turn on when a voltage is applied to then in the correct direction. This means that we can have an LED hooked up to pin 1 and 2 and another LED hooked to pin 2 and 1 while turning them on or off independently.
Both of these methods allows for a single LED to be turning on at any given time. However, for a clock we need at most 2 or 3 LEDs turned on at once (hours, minutes, seconds). We can accomplish this using persistence of vision. Most video on the internet is only 30 frames per second (updates 30 times a second) because the human eye cannot perceive changes faster than that. This means that if we update the clock 30 times per second while cycling through hours, minutes and seconds, then we can make each LED appear to be on simultaneous to the other two. There are specialized chips which do this (MAX7221) for 7-segment display and LED dot-matrices.


The Build


The Code

LizzClock.h

#ifndef LIZZCLOCK_h
#define LIZZCLOCK_h


typedef struct LED {
  char high;
  char low;
} LED;

typedef struct BUTTON {
  long down;
  char set;
  char PIN;
} BUTTON;


typedef struct TIME {
  char hours;
  char minutes;
  char seconds;
} TIME;

#endif

LizzClock.ino

#include "LizzClock.h"
#include <TimerOne.h>

#define TRUE    1
#define FALSE   0

// Display Constants
#define OFFSET  2

LED lights[72];
LED* curr_led = 0;
char PAUSE = 50;
char BRIGHTNESS = 0;
int UPDATE_COUNT (100/PAUSE);
int ON_DELAY = PAUSE;
int OFF_DELAY = 0;

TIME *curr_time;
long start_time;

BUTTON *minutes_button;
BUTTON *hours_button;

void setup() {
  /*
   * Initalize current time and update interrupt
   */
  start_time = millis();
  curr_time = (TIME*) malloc(sizeof(TIME));
  curr_time->seconds = 0;
  curr_time->minutes = 0;
  curr_time->hours = 0;
  Timer1.initialize(100000);
  Timer1.attachInterrupt(update_time);

  /*
   * Initalize buttons
   */
  minutes_button = (BUTTON*)malloc(sizeof(BUTTON));
  minutes_button->down = 0;
  minutes_button->PIN = 12;
  pinMode(minutes_button->PIN, INPUT);
  hours_button = (BUTTON*)malloc(sizeof(BUTTON));
  hours_button->down = 0;
  hours_button->PIN = 13;
  pinMode(hours_button->PIN, INPUT);

  /*
   * Initalize display
   */
  set_brightness(30);  

  /*
   * MINUTES/SECONDS
   */
  init_LED( 0, 0, 1); // 0  and 1
  init_LED( 2, 0, 2); // 2  and 3 
  init_LED( 4, 1, 2); // 4  and 5
  init_LED( 6, 0, 3); // 6  and 7
  init_LED( 8, 1, 3); // 8  and 9
  init_LED(10, 2, 3); // 10 and 11
  init_LED(12, 0, 4); // 12 and 13
  init_LED(14, 1, 4); // 14 and 15
  init_LED(16, 2, 4); // 16 and 17
  init_LED(18, 3, 4); // 18 and 19
  init_LED(20, 0, 5); // 20 and 21
  init_LED(22, 1, 5); // 22 and 23
  init_LED(24, 2, 5); // 24 and 25
  init_LED(26, 3, 5); // 26 and 27
  init_LED(28, 4, 5); // 28 and 29
  init_LED(30, 0, 6); // 30 and 31
  init_LED(32, 1, 6); // 32 and 33
  init_LED(34, 2, 6); // 34 and 35
  init_LED(36, 3, 6); // 36 and 37
  init_LED(38, 4, 6); // 38 and 39
  init_LED(40, 5, 6); // 40 and 41
  init_LED(42, 0, 7); // 42 and 43
  init_LED(44, 1, 7); // 44 and 45
  init_LED(46, 2, 7); // 46 and 47
  init_LED(48, 3, 7); // 48 and 49
  init_LED(50, 4, 7); // 50 and 51
  init_LED(52, 5, 7); // 52 and 53
  init_LED(54, 6, 7); // 54 and 55
  init_LED(56, 0, 8); // 56 and 57
  init_LED(58, 1, 8); // 58 and 59

  /*
   * HOURS
   */
  init_LED(60, 2, 8); // 12 and 1
  init_LED(62, 3, 8); // 2  and 3
  init_LED(64, 4, 8); // 4  and 5
  init_LED(66, 5, 8); // 6  and 7
  init_LED(68, 6, 8); // 8  and 9
  init_LED(70, 7, 8); // 10 and 11
}

/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 *      [[  DISPLAY INIT START  ]]
 */

char set_brightness(int new_brightness) {
  if (new_brightness >= 0 && new_brightness <= PAUSE) {
    BRIGHTNESS = new_brightness;
    ON_DELAY = (PAUSE > BRIGHTNESS ? PAUSE - BRIGHTNESS : 0);
    OFF_DELAY = (PAUSE < BRIGHTNESS ? PAUSE : BRIGHTNESS);
    return TRUE;
  }
  return FALSE;
}

void init_LED(char index, char high, char low) {
  lights[index+1].high = high;
  lights[index+1].low = low;
  lights[index].high = low;
  lights[index].low = high;
}
//      [[  DISPLAY INIT END  ]]
//////////////////////////////////////////////////////////


/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 *      [[  EXECUTION START  ]]
 */
void loop() {
  // update_time called on timed interrupt 10 times a second
  display_time(curr_time);
  check_user_set_time();
}
//      [[  EXECUTION END  ]]
//////////////////////////////////////////////////////////


/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 *      [[  MAINTAIN DISPLAY START  ]]
 */
LED* get_hour(char hour) {
  if (hour <= 0 || hour >= 12)
    return &lights[60];
  return &lights[hour + 60];
}

void all_off()
{
  for(int i = 2; i < 12; i++) {
    pinMode(i, INPUT);
    digitalWrite(i, LOW);
  }
}

char get_pin(char index) {
  return index + OFFSET;
}

void display_time(TIME *time) {
  lightup(&lights[time->seconds]);
  lightup(&lights[time->minutes]);
  lightup(get_hour(time->hours));
}

void lightup(LED* led) {
  // blank display and pause to control brightness
  all_off();
  delayMicroseconds(OFF_DELAY);
  //delayMicroseconds();

  // turn on display for short time to allow for persistance of vision.
  pinMode(get_pin(led->high), OUTPUT);
  digitalWrite(get_pin(led->high), HIGH);
  pinMode(get_pin(led->low), OUTPUT);
  digitalWrite(get_pin(led->low), LOW);
  curr_led = led;
  delayMicroseconds(ON_DELAY);
}
//      [[  MAINTAIN DISPLAY END  ]]
//////////////////////////////////////////////////////////


/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 *    [[  MAINTAIN CLOCK START  ]]
 */
void update_time() {
  long temp = (millis() - start_time) / 1000.0;
  //long temp = (millis() - start_time) / 3;
  curr_time->seconds = temp % 60;
  temp /= 60.0;
  curr_time->minutes = temp % 60;
  curr_time->hours = temp / 60.0;
  if (curr_time->hours == 12) {
    curr_time->hours = 0;
    // assume time is updated more than once a second.
    start_time = millis() - (curr_time->seconds * 1000);
    //start_time = millis() - (curr_time->seconds * 3);
  }
}

void check_user_set_time() {
  if (digitalRead(minutes_button->PIN)) {
    // if button down
    if (minutes_button->down) {
      // if currently debouncing
      if (!minutes_button->set && millis() - minutes_button->down > 20) {
        // if debounced long enough
        start_time -= 60000; // seconds * milliseconds
        minutes_button->set = 1;
      }
    } 
    else {
      // start debouncing
      minutes_button->down = millis() ^ 1;
    }
  } 
  else if (minutes_button->down) {
    minutes_button->down = 0;
    minutes_button->set = 0;
  }
  if (digitalRead(hours_button->PIN)) {
    // if button down
    if (hours_button->down) {
      // if currently debouncing
      if (!hours_button->set && millis() - hours_button->down > 20) {
        // if debounced long enough
        start_time -= 3600000; // minutes * seconds * milliseconds
        hours_button->set = 1;
      }
    } 
    else {
      // start debouncing
      hours_button->down = millis() ^ 1;
    }
  } 
  else if (hours_button->down) {
    hours_button->down = 0;
    hours_button->set = 0;
  }
}
//      [[  MAINTAIN CLOCK END  ]]
//////////////////////////////////////////////////////////

Thursday, June 14, 2012

Towel Build and Parts

The Towel is a simple RC delta wing poularized by Brooklyn Aerodrom and MAKE Online. It is a simple build for under $100 that should allow flight in only a few hours work. I stumbled across HobbyPartz.com which has amazing deals on robotics, RC and hobby electronics parts.

The following parts are either on their way for my Towel build or worthy of mention: 


  • 2.4G FlySky 6-Channel TX/RX Combo for $33 [[ Here ]] 
  • 2.4G FlySky 6-Channel Receiver for $9 [[ Here ]] 
  • Brushless Motor (KV 1300) + 18A ESC + 3 x 9g Servos for $25 [[ Here ]] 
I will post as progress is made. However, research will not let that happen anytime soon...

Tuesday, June 12, 2012

AI Battle Challenge

Two Georgia Tech students are developing AI challenge platforms similar to the Google AI Challenges. This site will serve as online documentation of the development process as well as a resource for the AI challenge participants.

Look for games like:

  • Battleship
  • Minesweeper
  • Mancala
  • Pong

Check it out

Saturday, June 9, 2012

Lizz's Calculator - Software Update

Reminder
As a reminder, I am building a custom calculator with an Arduino as a brain. This will use four linear time algorithms for pre-parsing the equation and a context free grammar to define valid syntax with a recursive descent parser to evaluate the equations. Note that each time the application is redesigned I am changing the version numbers so that I can more easily compare my documentation. Version 0.1 is implementing recursive pre-parsing and currently ignoring high precision requirements* for fast development and greater overall simplicity.

*This can (semi-)easily be fixed later using 3rd party libraries or implementing a custom library which implements big_floats by keeping track of a numerator and denominator, each in scientific notation.

Pre-Parsing
The pre-parsing code is complete, tested and committed to the repository.  The following algorithms serve to sanitize the input; ensuring the syntax passed to the recursive descent parser can be parsed by the grammar efficiently and accurately. The pre-parsing process is completed as follows.

  1. Parses a string (char*) and convert each equation element to a node inside a doubly linked list. Each number is parsed and converted to a float, each multi-character operation is converted to a single node with an identifying character e.g. SIN(...)->'s', LOG(...)->'g', etc. . 
  2. Once the equations is parsed into a linked lists, an algorithm uses a stack to ensure parentheses matching. While performing this check, an instance variable in each node containing a parentheses is set to specify its corresponding parentheses. 
  3. A third algorithm is used to surround each argument of two-argument operations with parentheses if necessary. This is done recursively keeping track of the insert position of the left parentheses and searching for operations to specify the position for the closing parentheses e.g. '+', '-', '*' and '/'. To ensure correct order of operations, this parsing is done on addition and subtraction, then re-evaluated on multiplication and division. Note that this step is not required for exponents or single argument operations e.g. SIN, COS, etc. . The algorithm includes checks to avoid duplicate or nested parentheses using the "match" instance variable, set in step 2, in each node containing a parentheses e.g. avoid "((3))+((4))".
Current UML
This will grow quickly as hardware is added; the project is still pending 128x64 pixel display, 5-bit 30-button array and power management including power button and low power state.



Evaluating The Equation
The current grammar is currently being redesigned as an LL(1) or LL(2) context free grammar. The current grammar is far too ambiguous to evaluate equations efficiently. I will post updates as progress is made, but I have multiple large research deadlines approaching in the next two weeks.

Friday, June 1, 2012

Lizz's Calculator - Build Update

This is an update from the previous design post which can be found here.

Software:

The code repository can be found here. All information found in updates on this blog will also be included in the README file for proper documentation. An old version or the parser which linearly parses the equation. This was originally written for a 32-bit PIC chip.

Electronics:

Recall that I had the "complexity" requirement (look as crazy as possible, with wires everywhere!). I think it is working out nicely. The schematics can be found on the design post linked above.