Go Down

Topic: Laser Binary Writer (Read 63 times) previous topic - next topic

stevenjryall

Mar 29, 2017, 02:02 am Last Edit: Mar 29, 2017, 02:30 am by stevenjryall
Hello to you all!

So I'm working on a project that isn't exactly useful to anybody but is just a really interesting way to create and display simple binary data.

I have created what I call a 'Laser Binary Writer' or LBW. Essentially it is just a laser module pointing to a photoresistor. The Arduino takes in data from the photoresistor to generate either a 0 or a 1. If the photoresistor is receiving light from the laser, it generates a 1, and if not, a 0. It takes these 0s and 1s and places them in a string array, which gets sent to Processing. Processing then analyses the binary data and outputs the equivalent character from the ASCII table and saves it to a file. Sending multiple lines of data allows for a word or a sentence to be written and saved to a file, all from creating simple 0s and 1s from a laser and photoresistor!

I'm wanting to take this quite a few steps further, but here's the Arduino code with the Processing code below. I've also attached some pictures of the setup for your reference if you'd like to recreate this.

Arduino code:

Code: [Select]


/*
   Laser Binary Writer

   [IF YOU COPY AND PASTE, ENSURE TO SEPARATE COMMENTS FROM CODE]
 
   This sketch allows you to record binary data to be sent to Processing.

   A Laser Binary Writer setup is used to create the data.
   
   The LBW takes in a photoresistor sensor value which changes depending
   on whether a laser module facing it is lit or not. It then records
   a value of either 1 (laser on) or 0 (laser off) in a string. When
   the user creates a string of 8 1s or 0s it can be sent to Processing
   which will analyse the string and output the character equivalent
   from the ASCII table into a newly created file and saves it to the
   sketch folder. When this file is opened in a text editor the ASCII
   characters produced by the binary data will be there.

   The LBW has four buttons - 'Record', 'Run', 'Laser' and 'Clear'.

   Firstly, 'Laser' should be used to turn the laser on and off, which
   will allow the computer to calculate whether it will record either
   a 1 or a 0.

   Secondly, the 'Record' button should be used to actually record
   a 0 or a 1 to a string array. If the laser is on, it will record
   a 1, and if the laser is off it will record a 0. This will pile up.

   The 'Laser' and 'Record' buttons should be used eight times to create
   a whole piece of information. For example, to get an 'A' from Processing,
   you should write 01000001. 

   Lastly, the 'Run' button should be used to take all the piled
   0s and 1s and write them to the Serial buffer as one unit.

   The 'Clear' button will just clear the string array of all information.

   Created Tuesday 28th March, 2017
   By Steven Ryall <steven_j_ryall@hotmail.co.uk>

   THIS CODE IS IN THE PUBLIC DOMAIN

   *************ISSUES (1)***************
   * Sometimes the 8 bits come through  *
   * split on the Processing side. I    *
   * don't know which side it could be  *
   * resolved on or whether it's both.  *
   **************************************
 
 */

/* Photo resistor sensor */
int sensorPin = A5;
/* Debug LED to show whether we're sending a 1 or a 0 */
int debugPin = 6;
/* Variable to store the value coming from the photoresistor */
int sensorValue = 100;
/* Laser module */
int laserPin = 2;

/* Three buttons to record data, turn the laser on and off
   and to send the data to processing */
const int _recButton  = 3;
const int _laserButton = 4;
const int _runButton = 5;

/* Button to clear already saved information */
const int _clearButton = 7;

/* Variable to count saved data */
int moreElements = 0;

/* String array to contain the data */
String _actions[100]{};

/* Boolean variables which correspond to buttons */
boolean _0Value, _1Value, _rec, _run, _laser;

void setup() {

   /* Declare variable functions and begin Serial */
   
   pinMode(_recButton, INPUT_PULLUP);
   pinMode(_laserButton, INPUT_PULLUP);
   pinMode(_runButton,INPUT_PULLUP);
   pinMode(_clearButton,INPUT_PULLUP);
   pinMode(debugPin,OUTPUT);
   pinMode(laserPin, OUTPUT);
   digitalWrite(laserPin,HIGH);
   pinMode(debugPin, OUTPUT);
   Serial.begin(9600);

}

void loop() {
 
    /* Ensure two booleans are on or off depending on
       whether the laser is lit or not */

    if(analogRead(sensorPin) > sensorValue ){   
       
        _0Value = true;
        _1Value = false;
       
    } else if(analogRead(sensorPin) < sensorValue){
       
        _1Value = true;
        _0Value = false;
    }

    /* Activate record function with button */
   
    if (digitalRead(_recButton)==LOW){

      Record();
      delay(100);
     
    }

    /* Turn the laser on or off with button */
   
    if(digitalRead(_laserButton)==LOW){
     
      _laser = !_laser;
      delay(300);
     
    }

    /* Send saved information to processing with button */
   
    if(digitalRead(_runButton) == LOW){

     Run();
     
    }

    /* Clear already saved information */

    if(digitalRead(_clearButton) == LOW){

      Clear();
     
    }

    /* Controlling whether or not the laser is on
       depending on boolean */

    if(_laser){
     
      digitalWrite(laserPin,HIGH);
     
    } else if(!_laser){
     
      digitalWrite(laserPin,LOW);
     
    }
   
    /* Function for debug led */
   
    if(analogRead(sensorPin) > sensorValue ){   
       
        digitalWrite(debugPin,HIGH);
       
    } else if(analogRead(sensorPin) < sensorValue){
       
        digitalWrite(debugPin,LOW);
    }

    }

    /* Run function - sends each saved elements as a string
       to be picked up and processed by processing */
 
    void Run(){

       for(int i=0; i<moreElements;i++){
       
        Serial.print(_actions[i]);
         
    }
   
        delay(500);
       
 


Continued below...

stevenjryall

And the Processing code:

Code: [Select]


/*
  Laser Binary Writer
  
  [IF YOU COPY AND PASTE, ENSURE TO SEPARATE COMMENTS FROM CODE]
  
  This sketch allows you to analyse incoming binary data from
  a Laser Binary Writer setup and an Arduino.
  
  More information on the LBW in the Arduino code below.
  
  The data will be converted from user inputted binary data
  to the ASCII character equivalent of that binary data and
  then saved to a file.
  
  This allows the user to create a string of numbers, letters
  and other general characters. If you want a space between
  words, simply send a 0 and the character value will be blank.
  
  Firstly, when the Arduino is connected, write the binary information
  using the instructions in the Arduino code.
  
  When this is sent using the 'Run' button on the LBW, you will see
  information about the information you just created and sent.
  
  Lastly, simply press any key to save all information to a file
  and end the Processing program.
  
  Check the sketch folder for the file. If you have saved
  it as a .bin file, the best way to open it is with a text
  editor, though you can use 'File Info Professional' if
  you're on a mac to get the characters as well as the
  hexidecimal values.
  
  Created Tuesday 28th March, 2017
  By Steven Ryall <steven_j_ryall@hotmail.co.uk>
  
  THIS CODE IS IN THE PUBLIC DOMAIN
  
  *************ISSUES (1)***************
  * Sometimes the 8 bits come through  *
  * split on the Processing side. I    *
  * don't know which side it could be  *
  * resolved on or whether it's both.  *
  **************************************

*/

import processing.serial.*;

// Save method
PrintWriter outputBin;
// Serial ports
Serial myPort,myPort1;

void setup(){
  
    size(500,500);
    background(100,255);
  
    // Create the file the binary data should be saved to
    // The format can be changed, but the best ones to use
    // are .txt or .bin as both can be opened with a text editor
    outputBin = createWriter("binary.bin");

    // Create the Serial port(s) to connect to microcontroller
    // If you're on a mac your Serial port will be something like
    // what I have, but on windows it will likely be different.
    myPort = new Serial(this, "/dev/cu.usbmodem1431", 9600);
    
    // Another Arduino can be connected to your computer and
    // can receive information too. A small program to be used on
    // another Arduino can be found below. If you want to talk
    // to it, simply uncomment
    
    // myPort1 = new Serial(this, "/dev/cu.usbmodem1441", 9600);
    
    // to initialise it.
}

void draw(){
  
    //If we receive information
    if(myPort.available()>0)
    {
  
    //Create a string to represent that information
    String data = myPort.readString();
    //Convert that string of binary into its character counterpart
    char c = char(unbinary(data));
    //Save the character to the file
    outputBin.println(c);
    //Also print some information to the debug log
    println("Binary Input: " + data + " Decimal: " + unbinary(data) + " Character value: " + c);
 
    }

    //myPort1.write(data); <--- To write to another arduino
  
}
 
void keyPressed() { // Any key
  
    outputBin.flush(); // Writes the remaining data to the file
    outputBin.close(); // Finishes the file
    exit(); // Stops the program
  
}



stevenjryall

#2
Mar 29, 2017, 02:23 am Last Edit: Mar 29, 2017, 04:02 pm by stevenjryall
So the photos attached will show you my setup.

It's not very complicated, but the only problem is whilst trying to press buttons the laser sometimes knocks out of place. I've bought some boards to solder components and wires to - so I'm going to make this a standalone module with its own microcontroller chip and everything.

I've also taken some screenshots of how Processing outputs the data in the debug log, a text editor and file info professional. You can see when I tried to send some values it accidentally split them - this bug needs to be fixed.

What can be done with it is another thing. At the moment I have it simply representing binary data in character form, but I have a few other ideas...

With enough patience, one could create one of those old ASCII pictures that utilises numbers, letters and characters. You could write an entire book out of coding binary data if you were dedicated enough. You could change the system, and have processing represent the binary data using colours, send appropriate numbers for it to use to calculate the colours, and create an image file from it.

I would REALLY love to create a genetic algorithm and to give control of a motor that blocks the light to the algorithm, give it say... a play by shakespeare and have it try to create a work that's similar. That would be amazing!

Furthering this to realise these ideas would mean making the system much more reliable so information doesn't randomly split when being sent from Arduino to Processing - but that's in the works. You have to be careful when sending information as it can split. If anyone reading this would like to fix that, go right ahead. More so, if you have an idea on how to apply this system, or even how to improve it, please go right ahead, and post your results here. I'd love to see. It's very much a prototype at the moment.

I understand that it's a longwinded way of creating information, but I'm certainly not creating this for it to be useful to anybody - I just think it's great to send even simple information over light. This guy ---> https://www.youtube.com/watch?v=MCTqC2-AN7o <--- sent music over light. Really amazing stuff.

I've also noticed a lot of people don't understand how to do data conversion in Processing so this can potentially be a great resource for them (I'm also posting this to the Processing forum).

I was also inspired by this guy ---> https://www.youtube.com/watch?v=iHWIZsIBj3Q <--- who was able to take a solar cell and send data to a computer by encoding information in subtle changed of the brightness of an LED lamp pointing to the solar cell. I'm wondering if I could achieve the same thing with just a laser, a photoresistor, an Arduino and Processing. That would be the ultimate goal!

Thanks for reading. :)

stevenjryall

Oh P.S - here's some code you can upload to another Arduino which can listen in as it were to the conversation between Processing and the LBW. If it receives a 0 or a 1 it turns an LED on and off.

You can easily change a few bits and pieces around in the main Arduino and Processing sketches to allow it to send 0s and 1s with a delay in between, meaning you can essentially write a program using one Arduino and the LBW and have another Arduino run that very program - but if you send the 1s and 0s as a binary byte - 8 characters - then currently it will only take the last character and use that as a reference for its function as Serial.available != 0 whilst the master Arduino and Processing are communicating.

Code: [Select]



    Code for extra Arduino
   
    Laser Binary Writer

    [IF YOU COPY AND PASTE, ENSURE TO SEPARATE COMMENTS FROM CODE]

    This sketch allows you to receive simple data from the Serial
    buffer. It is being used here in particular to receive a 0 or
    a 1 and to turn on and off an LED pin in response to a Laser
    Binary Writer setup.

    The LBW will allow you to send a 0 or a 1 to Processing and
    then Processing can send that information here to be
    processed. This is a very simple example, and plenty more
    creative things could be done.
 
    THIS CODE IS IN THE PUBLIC DOMAIN

    // The pin the LED is connected to
    int ledPin = 13;

    void setup() {

    // Begin the Serial, and declare the LED pin
        as an output
    Serial.begin(9600);
    pinMode(ledPin, OUTPUT);

}

void loop() {

    // If we're receiving information, convert it into an integer,
     read and react appropriately.

    if(Serial.available() > 0){

      int _bit = Serial.read();

      if(_bit == '0'){
       
        digitalWrite(ledPin,LOW);

      } else if(_bit == '1'){
       
       digitalWrite(ledPin,HIGH);
 
      }
     
   }

}


stevenjryall

#4
Mar 29, 2017, 08:02 pm Last Edit: Mar 29, 2017, 09:15 pm by stevenjryall
An update!

So I've kept the sketch allowing me to manually insert binary data into the system but have created a different copy to generate it automatically. I used this algorithm in void loop():

Code: [Select]


int randomNumber;

    randomNumber = random(0,20);

    if(randomNumber < 10){
      _laser = false;
    } else if(randomNumber > 10){
      _laser = true;
    }

    Record();

    if(moreElements == 8){
      Run();
      Clear();
    }



this generates a random number between 0 - 10 and 10 - 20. If the number is between 0 and 10 then turn the laser off to produce a 0, otherwise if it's between 10 and 20, turn the laser on to produce a one. It records this, checks if it's recorded 8 values and when it has, sends it to processing and clears the array string to write to it again.

I've also upped the baud rate to a whopping 115200 to lessen fractured bytes.

In Processing, I've added a couple of things:

Code: [Select]


char acceptedchars[] = {'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','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','0','1','2','3','4','5','6','7','8','9'};



This creates an array of characters to accept, and here:

Code: [Select]


for(int i = 0; i < acceptedchars.length; i++){
    if(c == acceptedchars[i]){
    outputBin.println(c);
    //Also print some information to the debug log
    println("Binary Input: " + data + " Decimal: " + unbinary(data) + " Character value: " + c);
    }
    }



we check whether what we've received is one of those characters before we process it. This allows us to filter out all the mistakes that will happen on the Arduino side (like producing a binary string that doesn't have a character equivalent) - this also means we get clear and concise data. The images show the output I'm getting to the .bin file and the debug log.

From here I'm going to try to create a sorting algorithm in Processing that allows it to take the characters and sort them into something intelligible. I will try to use this to create an algorithm that will analyse a work by shakespeare, figure out some patterns in his work and then take the characters we receive and arrange them using the same patterns.

That's gonna be a lot of hard work - phew! Anybody happen to have any ideas on how to approach that task? I understand Processing has powerful string analysis capabilities - but perhaps a text analysis project that's already finished might give me a big boost.

Thanks for reading up to yet! :)

stevenjryall

UPDATE: I found after multiple uses it was generating the same random numbers. This is of course because I wasn't using Arduino's randomSeed function in start. I put:

Code: [Select]


randomSeed(analogRead(0));



in void setup and it generates much more randomly now. :)

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy