Need help project deadline approaching!

I am very new at this and probably took on a project that was too big for my experience level. Here's to hoping that the brains in the Arduino forum can help!

I am trying to create a hardware response to data fed to Arduino from Processing. I have a looping stream of 4 values (999,R,G,B) constantly flowing from processing. 999 is a constant that I was using to keep the two in sync. R,G,and B are int variables.

First my code from Processing:

import processing.serial.*;
Serial port;

int pixcolor;
int r;
int g;
int b;

void setup() {
size(800, 600, P2D);
println("Serial Port List:");
println(Serial.list());

port = new Serial(this, Serial.list()[0], 9600);
}

void draw() {
PImage x;
x = loadImage("PowerMouse.jpg"); // display test image
image(x, 0, 0);

//read pixel data at current mouse position and write to 3 variables
pixcolor = get (mouseX, mouseY);
r = int(red(pixcolor));
g = int(green(pixcolor));
b = int(blue(pixcolor));

//sequentially write variables to serial port
port.write (999);
delay(10);
println("red: "+ r);
port.write (r);
delay(10);
println("green: "+ g);
port.write (g);
delay(10);
println("blue: "+ b);
port.write (b);
delay(10);
}

I think the Processing portion is ok(probably better ways to do it but it seems to work), but I am totally unsure of my Arduino code:

const int magPin = 9;
const int thermo1 = 5;
const int thermo2 = 6;
const int vibe = 1;
int r;
int g;
int b;
int k;

void setup()
{
Serial.begin(9600);
pinMode(magPin, OUTPUT);
pinMode(thermo1, OUTPUT);
pinMode(thermo2, OUTPUT);
pinMode(vibe, OUTPUT);
}

// looping function to read serial data in 4 chunks

void loop() {
byte data;
if (Serial.available()) {
data = Serial.read(); // initial read
}

// if 999 is not read go back to loop() and start over

if (data != 999) loop();
else {
data = Serial.read(); //read next data and write to variable r
data = r;
data = Serial.read(); //read next data and write to variable g
data = g;
data = Serial.read(); //read next data and write to variable b
data = b;

// if R,G and B are the same write this value to K (Greyscale)
if (r == g)
{if (g == b) k = r; //i'm sure this is wayyy wrong
else loop();
}
else k == 0;
}
analogWrite (magPin, k); // Write K value to PWM pin

//if pixel is red turn on H Bridge direction 1
if (r > 10) {
digitalWrite (thermo1, HIGH);
digitalWrite (thermo2, LOW);
}

//if pixel is blue turn on H bridge direction 2
if (b > 10) {
digitalWrite (thermo1, LOW);
digitalWrite (thermo2, HIGH);
}
}

OK, I know that was ugly, but I don't know another way to do this. From my initial tests, this doesn't seem to work anyway. Please help a noob! I'm trying to learn, but running out of time. Feel free to pester me on AIM/iChat at bremnerr@me.com

Hi Ryan B;

Here are some suggestions, I hope it helps get you back on your feet.

You appear to be timing the data as you send it - but that is going to be really hard to identify at the receiving end, especially if the serial chip buffers the communications data at all. (the spacing in the communications may be present, but there is no way to determine that later in the receiving code)

What you are doing is essentially making a communications protocol, and you have to start to define some rules - normally from the receiving end in mind first, because that is the part acting on the needed data.

Since we already know from your code and description, it is easy to break down the protocol into steps:

  • Get the color component to modify, 'R', 'G', or 'B'
  • Get the 4 bytes indicating the value for the color component.

This is just one way to do it. You could also send plain text, wait for a end of line marker, etc, but then you have to deal with parsing out the numbers and reassembling them into numbers. I will leave the alternative ideas for your imagination to draw up, if you don't like the way I took this: :-X

The following protocol works like this:
The transmission to set all LEDs off will look like: 'R', 0x00, 0x00, 0x00, 0x00, 'G', 0x00, 0x00, 0x00, 0x00, 'B', 0x00, 0x00, 0x00, 0x00

To turn on the red completely and all others off, we need: 'R', 0xff, 0xff, 0xff, 0xf, 'G', 0x00, 0x00, 0x00, 0x00, 'B', 0x00, 0x00, 0x00, 0x00

And, I can just send 'B' 0xff, 0xff, 0xff, 0xff to turn Blue on, I don't have to send the other color data.

Then, we write this up in the receiving code:

loop()
{
   char c;
   // find the start character.  our protocol says that it has to be R, G, or B.  Don't go on unless it is.
   do
   {
      c = Serial.read();
    } while(c!='R' && c!='G' && c!='B');

   // wait until the rest of our data is present.
   while(Serial.available()<4)
     {;}
   
   if(c=='R')
  {
       int iColor = read4ByteValue();
       SetRedLed(iColor);
   }
   else if(c=='B')
    // etc...
}

int read4ByteValue()
{
    int iRet =0;
    for(int i=0;i<4;i++)
   {
      int iThis = Serial.read();
      iRet = iRet<<8;
      iRet |= iThis;
   }
    return iRet;
}

and to send a value, make something like this function:

#define RED 'R'
#define BLUE 'B'
#define GREEN 'G'

void sendCommand(char type, int value)
{
    Serial.write(type);
    Serial.write((byte)((value & 0xff000000) >> 24));
    Serial.write((byte)((value & 0x00ff0000) >> 16));
    Serial.write((byte)((value & 0x0000ff00) >> 8));
    Serial.write((byte)((value & 0x000000ff)));
}

and then to actually run the send function:

sendCommand(RED, 250);
sendCommand(BLUE, 500);
sendCommand(GREEN, 250);

I bet you can drop those in and troubleshoot the rest...

Some of the features of your protocol should also handle:

  1. Starting the receiver mid protocol stream. What happens if R, 0x05, 0x02, 0x11 is sent, but we start listening at 0x02? (The above code handles that...)
  2. Expansion. We can add other control codes, like 'A' 0x00 0x00 0x00 0x00 which turns all off, or all on - with the same 5 bytes.
  3. What happens when the sender dies mid-send. ('R' 0x00, 0x00.... and we get nothing else.) The above code won't handle that well. (modify the while(Serial.available()<4) to take time into effect, perhaps...
  4. This code doesn't time things well. If I send 'R', wait ten seconds, send '0x00', etc... The receiving will pause until the data is in. Under high baud rates, it shouldn't be a problem, but if you have 600 baud or some slow communications protocol, you may start to see noticable delays.

Thanks for the post Spinlock! It still looks like greek to me, but I am trying. One of the things I need to maintain is the value of the colors as they are transferred to the Arduino. Mostly this is just for the K (greyscale) & G values as they are going to be used to vary the power to an electromagnet and a vibration motor respectively. The R & B are not as critical (i.e. they can be simple on off digital signals) because they are just driving the pins of an H Bridge to drive and reverse the voltage through a Peltier.

So the flow goes like this. The user mouses over colored boxes and greyscale gradients. The associated components (magnet, vibe motor and Peltier are all mounted inside the users mouse so that the user receives feedback when mousing over the test boxes. (i.e. mousing over red box makes mouse hot, blue cold, green applies varying degrees of vibration, and the grayscale gradient causes the mouse to be more resistive to movement)

The code below seems to operate the K value just fine. I will try to interpret your code to get all 4 variables operating simultaneously.

 import processing.serial.*;
Serial port;
 
 int pixcolor;
 int r;
 int g;
 int b;
 int k;
 
 void setup() {
   size(800, 600, P2D);
   println("Serial Port List:");
   println(Serial.list());
   
port = new Serial(this, Serial.list()[0], 9600);  
 }
 
 void draw() {
  PImage x;
  x = loadImage("PowerMouse.jpg");
  image(x, 0, 0);
 
pixcolor = get (mouseX, mouseY);
r = int(red(pixcolor));
g = int(green(pixcolor));
b = int(blue(pixcolor));
  if ((r+b+g)/3 == r)  // determine if pixel is grayscale
    k = r;
      else k = 0;
println("grey: "+ k);
port.write (k);
delay(10);
 }

OK this a last call for any kind souls to help me bang out this code. I haven't had the time to fetter over trying to send the serial data string, and I am running out of time, LIKE TOMORROW out of time!!!! So if anyone has the skills to take this on and wants me to be forever in their debt, let me know!!! :smiley:
You can reach me at iChat: bremnerr@me.com or AIM: JWingnut19

Hi Ryan,
Just so you will know for next time, there are a lot of people here willing to help you.

However, there are not so many who will do a project or assignment for you. Many of us are, or were, teachers of some description and know the difference between help, which is fine, and plagiarism which is not.

Grumpy_Mike. I appreciate your feedback and I assure you that I would not be placing a request like this if I had any other alternative right now. Considering that I have gone from zero knowledge to at least a basic understanding of Arduino, basic circuitry and simple programming in a few short weeks in my spare time, I have been learning as much as I possibly can, but this is beyond my reach at this point.

I also am a teacher of 9 years so I too understand the difference between helping and doing, and teaching media design and content creation, I also understand what plagiarism is. I am not asking to take someone's code and claim it as my own, which IS plagiarism. I am simply looking for someone who would be willing to help me complete a project, WHICH WOULD BE FULLY ATTRIBUTED, which is NOT plagiarism.

I am not an unintelligent man, nor am I a leech who takes credit for others successes. My heart leapt when I saw that a message in my inbox from this discussion board, hoping that someone had taken the time to lend me a hand. Imagine my surprise when instead, I found someone who seems to be taking cheap shots at my ethics. I thought this was a community of people who were willing to help people who are enthusiastic about electronics and ideas.

I look forward to continuing to learn about the Arduino platform and it's capabilities. I'm sure that it will be much more enjoyable when I can explore at my leisure without a deadline looming.

I am not asking to take someone's code and claim it as my own, which IS plagiarism. I am simply looking for someone who would be willing to help me complete a project, WHICH WOULD BE FULLY ATTRIBUTED, which is NOT plagiarism.

Fine but did not say that at the start and it sounded like it was a project you have been given and couldn't cope with. It's a poor teacher that lets a student do that, or its a student who has not been paying attention or attending.

Ok then, help is offered freely.

What you are doing wrong is you are thinking that the line
data = Serial.read(); //read next data and write to variable r
data = r;
(by the way the last line should be r = data or simply put r =Serial.read():wink:

You think this transfers a value to the variable r, it does not. When you write the data out in processing you are writing a string of ASCII characters that can be interpreted as a number. When you read in Serial.read(); in the arduino you are just reading one of these characters and thinking it is the value.
So for example if you print out a value of 132 in processing you are sending the hex values 0x31, 0x33, 0x32, 0x0D
where 0x means what follows is hex and the 0D bit is the end of line marker.
At the arduino end you are reading the value of one of these bytes and thransfering that to the data. Hence you will never read 999 as you are just reading the ASCII for 9 which is 0x39 (hex) or 57 in decimal.

Basically you are not communicating between the two systems.
Break the problem down into simple bits instead of trying to do everything at once. Start off by just transferring a value back and forwards.

Look at communicating between the two systems, there are lots of examples in the playground, start with:- http://www.arduino.cc/playground/Interfacing/Processing
alternatively look to see how I do it with my processing to mini monome code at:- http://www.thebox.myzen.co.uk/Hardware/Mini_Monome.html

Thank you for the understanding Grumpy_Mike, my apologies for not being clear in my intentions in the initial post. I will try to integrate the suggestions that you have offered and post what I have come up with this evening. Hopefully yourself and fellow forum members will be available this evening as I may need to bounce some ideas off of you. Your explanation helped to make Spinlock's helpful post more clear to me. We are all professionals here and I am looking forward to continuing discourse with everyone on all things Arduino. :slight_smile:

Here's to early successes in what is bound to be a long evening :slight_smile:

Ok Grumpy_Mike et al. I took your suggestions and tried to go back to a single variable. I REMed out the code for the other 3 and it seems to work fine. However instead of dealing with converting to hex and back I just used a little math to shorten the output to one byte per variable. This gives me 0-9 steps of resolution instead of 0-255 but that is fine. Any suggestions how to proceed from here? Thanks again!

Current PowerMouse Processing code:

import processing.serial.*;
Serial port;
 
 int pixcolor;
 int r;
 int g;
 int b;
 int k;

 
 void setup() {
   size(1440, 900, P2D);
   println("Serial Port List:");
   println(Serial.list());
   PImage x;
  x = loadImage("PowerMouse.jpg");
  image(x, 0, 0);   
  port = new Serial(this, Serial.list()[0], 9600);  
 }
 
 void draw() {
   
println ("getting color");
pixcolor = get (mouseX, mouseY);
r = int(red(pixcolor));
g = int(green(pixcolor));
b = int(blue(pixcolor));
 if ((r+b+g)/3 == r)
    k = r;
      else k = 0;      
 if (k != 0) {
    r = 0;
    g = 0;
    b = 0;
 }   
 if (g != 0) {
    r = 0;
    k = 0;
    b = 0;
 }  
  if (b != 0) {
    r = 0;
    k = 0;
    g = 0;
 }  
  if (r != 0) {
    g = 0;
    k = 0;
    b = 0;
 }  
r= int(r*.0392);
b= int(b*.0392);
g= int(g*.0392);
k= int(k*.0392);

println ("writing values");

port.write(65);

println("red: "+ r);
port.write (r);

//println("green: "+ g);
//port.write (g);

//println("blue: "+ b);
//port.write (b);

//println("grey: "+ k);
//port.write (k);
    }

Current PowerMouse Arduino code:

const int magPin = 9;
const int thermo1 = 5;
const int thermo2 = 6;
const int vibe = 3;
byte r;
byte g;
byte b;
byte k;
byte x;


void setup()
{
  Serial.begin(9600);
  pinMode(magPin, OUTPUT);
  pinMode(thermo1, OUTPUT);
  pinMode(thermo2, OUTPUT);
  pinMode(vibe, OUTPUT);


}

void loop() {
  
  if (Serial.available())
    x = Serial.read();
    if (x = 'A') {
   
      if (Serial.available())
    {
     r = Serial.read();
      }
   delay (10);
  /* if (Serial.available())
    {
     g = Serial.read();
      }
       delay (10); */
  /*  if (Serial.available())
    {
     b = Serial.read();
      }
    delay (10); 
      if (Serial.available())
    {
     k = Serial.read();
      }
      delay (10);*/

r=int(r*28.33);
b= int(b*28.33);
g= int(g*28.33);
k= int(k*28.33);
      
  analogWrite (magPin, k);
  analogWrite (vibe, g); 
  
  if (r > 10) {
    digitalWrite (thermo1, HIGH);
    digitalWrite (thermo2, LOW);
    }
  else {
    digitalWrite (thermo1, LOW);
    digitalWrite (thermo2, LOW);
   }
 /* if (b > 10) {

    digitalWrite (thermo2, HIGH);
     }
   else { 

    digitalWrite (thermo2, LOW);
     }*/
     
    }
}

If you want 60% more resolution, you could use hex instead of decimal and go from 0...15 instead of 0...9.
Or go to a pseudo-base 26, and just use A..Z instead.

Thanks for the suggestion AWOL, but I am not worried too much about resolution right now. Mostly just being able to transmit all of my data to the 'duino :o. I may mess with different bases once I get this working properly.

OK so now lets get processing to send an R followed by the byte value and the same for G and B.

println ("writing values");
println("red: "+ r);
port.write ('R');
port.write (r);

and the same for G and B

Now at the Arduino end you want to read a byte when it is available and if it is R, G or B you want to WAIT for the next byte, read that and put it into the appropriate variable.
Like this:-

if (Serial.available())
    x = Serial.read();
    if (x == 'R') {
       while (!Serial.available()) { } // do nothing until data byte arrives
     r = Serial.read();
    }

    if (x == 'G') {
       while (!Serial.available()) { } // do nothing until data byte arrives
     g = Serial.read();
    }

    if (x == 'B') {
       while (!Serial.available()) { } // do nothing until data byte arrives
     b = Serial.read();
    }

  x = 0;   // rub out x so we don't mistake the last read the next time round the loop
if (x = 'R') {

Tut-tut! :wink:

Having modified my post I can pretend your making it up. :wink:

Ok, great news! I integrated your code into my project (slightly modified) and it runs fine.

However, I built a test rig on a spare arduino with the 4 output pins connected to LEDs so that I could monitor its reaction to the data it was receiving and there seems to be a problem. The LEDs seem to blink at random, except for the one connected to the R output. The way that the code is written, I had hoped for only one output (LED) to be active at a time, but that is not the case.

Any thoughts? Did I do something wrong?

Arduino code:

const int magPin = 9;
const int thermo1 = 5;
const int thermo2 = 6;
const int vibe = 3;
byte r;
byte g;
byte b;
byte k;
byte x;


void setup()
{
  Serial.begin(9600);
  pinMode(magPin, OUTPUT);
  pinMode(thermo1, OUTPUT);
  pinMode(thermo2, OUTPUT);
  pinMode(vibe, OUTPUT);


}

void loop() {
  
  if (Serial.available())
    x = Serial.read();
    if (x = 'R') {
       while (!Serial.available()) { } 
    }

    if (x = 'G') {
       while (!Serial.available()) { } 
     g = Serial.read();
    }

    if (x = 'B') {
       while (!Serial.available()) { } 
     b = Serial.read();
    }

  x = 0;   
  
r= int(r*28.33);
b= int(b*28.33);
g= int(g*28.33);
k= int(k*28.33);
      
  analogWrite (magPin, k);
  analogWrite (vibe, g); 
  
  if (r > 10) {
    digitalWrite (thermo1, HIGH);
    digitalWrite (thermo2, LOW);
    }
  else {
    digitalWrite (thermo1, LOW);
    digitalWrite (thermo2, LOW);
   }
  if (b > 10) {

    digitalWrite (thermo2, HIGH);
     }
   else { 

    digitalWrite (thermo2, LOW);
     }
     
    }

Processing code:

import processing.serial.*;
Serial port;
 
 int pixcolor;
 int r;
 int g;
 int b;
 int k;

 
 void setup() {
   size(1440, 900, P2D);
   println("Serial Port List:");
   println(Serial.list());
   PImage x;
  x = loadImage("PowerMouse.jpg");
  image(x, 0, 0);   
  port = new Serial(this, Serial.list()[0], 9600);  
 }
 
 void draw() {
   
println ("getting color");
pixcolor = get (mouseX, mouseY);
r = int(red(pixcolor));
g = int(green(pixcolor));
b = int(blue(pixcolor));
 
if ((r+b+g)/3 == r)
   k = r;
     else k = 0;    
      
 if (k != 0) {
    r = 0;
    g = 0;
    b = 0;
    
 }   
 if (g != 0) {
    r = 0;
    k = 0;
    b = 0;
 }  
  if (b != 0) {
    r = 0;
    k = 0;
    g = 0;
 }  
  if (r != 0) {
    g = 0;
    k = 0;
    b = 0;
 }  

r= int(r*.0392);
g= int(g*.0392);
b= int(b*.0392);
k= int(k*.0392);

println("red: "+ r); 
port.write ('R');
port.write (r);

println("green: "+ g);
port.write ('G');
port.write (g);

println("blue: "+ b);
port.write ('B');
port.write (b);

println("grey: "+ k);
port.write ('K');
port.write (k);

    }
 if (x = 'G') {
       while (!Serial.available()) { }
     g = Serial.read();
    }

    if (x = 'B') {
       while (!Serial.available()) { }
     b = Serial.read();
    }

(x = 'B') and ( x = 'G' ).
They're both assignments that evaluate to non-zero values, so will always be true.
You don't do anything with red.

Ok, dumb mistake on my part. I don't quite follow the part on non-zero values though. I will try fixing my code and report the result.

Thank you!

Isn't more likely a problem with the still missing =?

x = 'G' will always set x = to 'G' where as x == 'G' will evaluate if x actually = 'G' :wink:

I don't quite follow the part on non-zero values though.

In 'C', just about any statement produces a result that can be tested.
So, you can write legally stuff like

if (a = Serial.available ())
  {
     Serial.print ("there's stuff there ");
     Serial.print (a);
  }

which says "assign the value returned by "Serial.available" to the variable 'a' and test the result of the assignment".
If the value returned was non-zero, this is taken as "true" and so the Serial.print is executed.
If Serial.available returned zero, the assignment evaluates to false, so the print isn't executed.

So, if you write
"if (val = 'A')"
'A' is a constant, it is obviously not zero, so "val" will now have the value 'A', the assignment is therefore true, so the statement following will always be executed.

Ok I must be super dense or something, or very very tired. Now all I get is pin6 (thermo2, blue) going off when I mouse over an area that should be returning a value for k or g, I also get a very faint glow on the LED connected to pin5 (thermo1, red) when I mouse over the areas that should return a value for r and b.

Something is wrong here, but I don't know what.

const int magPin = 9;
const int thermo1 = 5;
const int thermo2 = 6;
const int vibe = 3;
byte r =0;
byte g =0;
byte b =0;
byte k =0;
byte x =0;


void setup()
{
  Serial.begin(9600);
  pinMode(magPin, OUTPUT);
  pinMode(thermo1, OUTPUT);
  pinMode(thermo2, OUTPUT);
  pinMode(vibe, OUTPUT);


}

void loop() {
  
  if (Serial.available())
    x = Serial.read();
    if (x = 82) {
       while (!Serial.available()) { } 
     r = Serial.read();
    }
   if (Serial.available())
    x = Serial.read();
    if (x = 71) {
       while (!Serial.available()) { } 
     g = Serial.read();
    }
   if (Serial.available())
    x = Serial.read();
    if (x = 66) {
       while (!Serial.available()) { } 
     b = Serial.read();
    }
      if (Serial.available())
    x = Serial.read();
    if (x = 75) {
       while (!Serial.available()) { } 
     k = Serial.read();
    }

  x = 0;   
  
r= int(r*28.33);
b= int(b*28.33);
g= int(g*28.33);
k= int(k*28.33);
      

  
  
  
 if (r > 30) {
    digitalWrite (thermo1, HIGH);
    digitalWrite (thermo2, LOW);
    }
  else {
    digitalWrite (thermo1, LOW);
    digitalWrite (thermo2, LOW);
   }
   
 if (b > 30) {
    digitalWrite (thermo1, LOW);
    digitalWrite (thermo2, HIGH);
    }
  else {
    digitalWrite (thermo1, LOW);
    digitalWrite (thermo2, LOW);   
  }
   
     
  }