Need help interfacing my Plotter with Processing

Hello everyone

I've built a nice little x/y plotter (Dropbox - Error) with 2 stepper motors that "prints" 128x128 bitmap images.
Right now, as you can see in the code, the Image is stored as bytes in a huge 2d array.
I would like a way to use Processing to import a 128x128 png image, convert it to a binary image, and then send it to the arduino via serial connection.
Sadly i'm a huge noob in processing and serial connections and also couldn't find anything on the internet that does such a thing. Could someone please help me create the processing application and change the arduino code?

thanks in advance
dabre
ps.: sorry for my bad english , i'm swiss.

this is my code:

#include <Stepper.h>
#include <avr/pgmspace.h>

#define STEPS 48

int penPlusA = 10;
int penPlusB = 11;
int penMinusA = 12;
int penMinusB = 13;

Stepper stepperX(STEPS, 0,1,2,3);
Stepper stepperY(STEPS, 4,5,6,7);

int limitPin = 8;
int stopSwitch = 9;

int x_inc = 0;
int y_inc = 0;
int z_pos = 0;

int stepSizeX = 6;//max 8
int stepSizeY = round(stepSizeX*1.6);

int maxSteps = 1075;
int homePos = (maxSteps/2)-((128*stepSizeX)/2);

String color = "color";// color, draft, line, square or cross
int motorSpeed = 280;

const byte image[128][128] PROGMEM = //insert image here, I deleted the array definition because the code would be too big
{};

void setup()
{
  if(homePos<0){homePos = 0;}
  
  if(color == "square" ){motorSpeed = 200;}else if(color == "draft" || color == "line"){motorSpeed = 300;}
  
  stepperX.setSpeed(motorSpeed);
  stepperY.setSpeed(motorSpeed);

  pinMode(penPlusA, OUTPUT);     
  pinMode(penPlusB, OUTPUT);     
  pinMode(penMinusA, OUTPUT);     
  pinMode(penMinusB, OUTPUT);    
  
  pinMode(limitPin, INPUT);
  digitalWrite(limitPin, HIGH);
  
  pinMode(stopSwitch, INPUT);
  digitalWrite(stopSwitch, HIGH);
  
  Serial.begin(9600);
  
  delay(2000);
}

void loop()
{
  goHome();
  draw();
  while(1){
  }

}


void penDown()
{

  if (z_pos == 0){
    digitalWrite(penPlusA, HIGH);
    digitalWrite(penPlusB, HIGH);
    digitalWrite(penMinusA, LOW);
    digitalWrite(penMinusB, LOW);
    delay(500);               
    digitalWrite(penPlusA, LOW);
    digitalWrite(penPlusB, LOW);
    digitalWrite(penMinusA, LOW);
    digitalWrite(penMinusB, LOW);

    z_pos = 100;
  }
}

void penUp()
{
  if(z_pos == 100){
    digitalWrite(penPlusA, LOW);
    digitalWrite(penPlusB, LOW);
    digitalWrite(penMinusA, HIGH);
    digitalWrite(penMinusB, HIGH);
    delay(500);
    digitalWrite(penPlusA, LOW);   
    digitalWrite(penPlusB, LOW);   
    digitalWrite(penMinusA, LOW);  
    digitalWrite(penMinusB, LOW);  

    z_pos = 0; 
  }
}

void colorIn(int dir){
  penDown();
  for(int i = 0;i<stepSizeX;i+=1){
    if(i%2 == 0){
      stepperY.step(stepSizeY);
    }
    else{
      stepperY.step(-stepSizeY);
    }
    stepperX.step(1*dir);
  }
}

void sqr(int dir){
  penUp();
  stepperX.step(stepSizeX*dir);
  penDown();
  stepperY.step(stepSizeY);
  stepperX.step(-stepSizeX*dir);
  stepperY.step(-stepSizeY);
  stepperX.step(stepSizeX*dir);
}

void draft(int dir){
  penDown();
  for(int i = 0;i<2*stepSizeX;i++){
    if (i%2 == 0){
      stepperY.step(1);
    }else{
      stepperX.step(1*dir);
    }
  }
  //penUp();
  stepperY.step(-stepSizeX);
}

void line(int dir){
  penDown();
  stepperX.step(round(stepSizeX*dir));
}

void cross(int dir){
  penDown();
  for(int i = 0;i<2*stepSizeX;i++){
    if (i%2 == 0){
      stepperY.step(1);
    }else{
      stepperX.step(1*dir);
    }
  }
  penUp();
  stepperX.step(-stepSizeX*dir);
  penDown();
  for(int i = 0;i<2*stepSizeX;i++){
    if (i%2 == 0){
      stepperY.step(-1);
    }else{
      stepperX.step(1*dir);
    }
  }
  delay(50);
}

void goHome(){
  while(digitalRead(limitPin) == HIGH){
    stepperX.step(-1);
  }
  stepperX.step(homePos);
}

void draw(){
  for(int row = 0; row < 128; row+=2) { 

    penUp();

    stepperX.step(-x_inc);
    x_inc = 0;  

    for(int column = 0; column < 128; column++){ 
      int pixel = pgm_read_byte(&(image[row][column]));
      int thisDir = 1;
       
      if(digitalRead(stopSwitch) == 0){
        while(digitalRead(stopSwitch) == 0){
          penUp();
          delay(10);
        }
      }
      Serial.println(String(row) +"," + String(column) + "," +String(pixel));
      if(pixel == 1){

        if(color == "color"){colorIn(thisDir);}
        else if(color == "square"){sqr(thisDir);}
        else if (color == "draft"){draft(thisDir);}
        else if(color == "line"){line(thisDir);}
        else{cross(thisDir);}
        
        x_inc += stepSizeX;
      }
      else{
        penUp();

        stepperX.step(stepSizeX);
        x_inc += stepSizeX;
      }
    }
    penUp();
    stepperY.step(stepSizeY);
    y_inc += stepSizeY;
    delay(15);
    
    for(int column = 127; column >= 0; column--){ 
      int pixel = pgm_read_byte(&(image[row+1][column]));
      int thisDir = -1;
      
      if(digitalRead(stopSwitch) == 0){
        while(digitalRead(stopSwitch) == 0){
          penUp();
          delay(stepSizeX);
        }
      }
      Serial.println(String(row+1) +"," + String(column)) + "," +String(pixel);
      if(pixel == 1){

        if(color == "color"){colorIn(thisDir);}
        else if(color == "square"){sqr(thisDir);}
        else if (color == "draft"){draft(thisDir);}
        else if(color == "line"){line(thisDir);}
        else{cross(thisDir);}
        
        x_inc -= stepSizeX;
      }
      else{
        penUp();

        stepperX.step(-stepSizeX);
        x_inc -= stepSizeX;
      }
    }

    penUp();

    stepperY.step(stepSizeY);
    y_inc += stepSizeY;
    delay(15);
  }

  penUp();

  stepperX.step(-x_inc);
  stepperY.step(5*stepSizeY);
}

I'm guessing you have the "while(1)" in your code so that it just plots a picture once. If you only want "goHome()" and "draw()" to run once just put them in setup() and leave loop() empty.

I don't know processing but, if it doesn't have a standard way to convert a PNG to a BMP file I would do that with some external program rather than try to write your own.

Sending the data to the Arduino should be straightforward. I suggest you try sending some simple stuff first until you learn how to do it.

When you know how to send data you will need to decide how the organize the order and quantity of data that is sent so that it is in the order the plotter expects and so that it gets data as it needs it. I haven't studied your plotting system to figure out how it relates the data to the plotting - is it sufficient to have the X and Y value of a particular point and does it work row by row or column by column?

Interesting project.

...R

The plotting system works row by row in 2 for loops, the first iterates over all the rows, the second one over each column for each row. this gives me the x/y byte to plot.

i think you could send the image row by row when the arduino asks for it:

arduino: row 1?
processing: {0,1,0,0,1,0,1,1}

so on and so forth, until the whole image is sent.
the processing application should also be able to set the step size and the color variable

Of course, the imported image could also be a 128x128 bmp file...

That sounds practical.

If each pixel is represented by a 1 or 0 you could use a single byte to represent 8 pixels which would reduce the amount of bytes to be transmitted and reduce the memory requirement in the Arduino.

And I guess if you only have to store a single row in the Arduino you can probably work with larger images if you want to.

Would it matter if there was a pause at the end of each row?

...R

That would definitely not matter, as the plotter/printer is slow anyways XD

Okay.. but you can convert binary into Hexadecimal and send these hexadecimal as CHARACTER (Extended ASCII) to Arduino. This will further simplify your problem. But mind, serial data processing needs a protocol so that no garbage interfere during transportation of binary from Processing to Arduino etc.
I am using my DIY GRAPHICAL WATERFALL with same protocol.you can search at Arduino forum

Sending binary data is much more efficient than sending human-readable characters. For example 253 takes a single binary byte, three decimal characters or two hex characters (FD).

...R

I am very newbie, but i think the computer can not send the binary to Arduino. If computer send 1 then the arduino will consider as a byte.. I don't know much about

There should be functions in your PC programming language that can create a byte from a number expressed as a string such as "57".

...R

but i think the computer can not send the binary to Arduino.

Mine can.

Paul,
Yes my bad.. every computer can :).. here is your informative reply
http://forum.arduino.cc/index.php/topic,39199.0.html