Pages: [1]   Go Down
Author Topic: Having problems with Serial Communication on FIO  (Read 1497 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I need some help.

I am working on a project that is inspired by the Beatfly project, which is a blimp project with 3 motors, some sensors and a handful of RGB LEDs. The original project leveraged Quartz Composer and a few interfaces to control the blimp and I have modified that to leverage TouchOSC iPad application and Processing.

I have all of the communication between Processing and the iPad/TouchOSC working fine and able to read from and write to the iPad.

I am having problems sending data between Processing and the Arduino FIO. I will eventually be using the Xbee Series 1 modules to handle wireless communication, but for now I am using a USB/FDTI cable to upload sketches and debug the communication structure.

What I would like to do is send the data in an array to the arduino. It currently has up to 20 items in the array which are all less than 255 so I am thinking that sending encoded using byte() will be the best method.

The data structure is as follows: 0xF0, 0x51, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0xF7 - where X is a value from 0-255

The 0xF0 opens the set and 0xF7 closes the set. 0x51 or 0x52 allow me to detect which type of command is being sent either 0x51 for LEDs and 0x52 for motor control.

I am able to construct and populate the array in processing, open the port and what I understand to be writing to the port.

I have tried a couple things to debug this over the last few evenings. First off I tried to just send a single byte, read it and then react to the data. I have had intermittent success with this, I tried to send multiple bytes and have had no success.

I put the my Arduino code for the project aside for the moment and wrote a very simple serial reading function which prints the value to the serial monitor and if it detects the byte 0xF0 turns on an LED connected to D2 on the FIO.

I have left the code as I am using it with various attempts commented out so you can see the logic and what I have tried to resolve this before posting to the forums.

Arduino Code:
int inByte = 0;         // incoming serial byte

void setup()
{
  Serial.begin(57600); // native speed of the FIO and Xbees - have tried 9600 as well with no discernable difference
  Serial.print(255); // send an initial byte out to the serial buffer to test for receipt
}

void loop()
{
  if (Serial.available()) {
    inByte = Serial.read();
    //Serial.flush(); - tried this earlier to clear the buffer after reading the result, but it did not seem to make any difference
    Serial.println(inByte);          
  }
}


Processing Code snippet:

variables declared before setup:

boolean debug=false;
int [] motors = new int [7];
int redVal;
int greenVal;
int blueVal;
String [] colorLED = new String[5];
int sendComd = 0;
int testByte = -1;

declared in setup()
mySerial = new Serial(this, Serial.list()[0], 57600);

loop from draw()
  if(sendComd!=0){
    sendCommand(sendComd);
  }

//function to send the data to Arduino which is called from the loop in draw()

void sendCommand(int ardCtrl){ // ardCtrl will be either 1 for LED or 2 for Motor

  if(debug)println("send command function called");
  int[] pass2ard = new int [19];
  if(ardCtrl == 1){  
    pass2ard[0] = 0xF0; //start
    pass2ard[1] = 0x51; //LED control
    pass2ard[2] = 15; / length of data to read on the arduino
     for(int l=0; l<=colorLED.length-1; l++){
       color currColor = color(unhex(colorLED[l]));
       if(debug)println(currColor);
       int cPos = (l*3)+3;
       int r = (currColor >> 16) & 0xFF;  // Faster way of getting red
       int g = (currColor >> smiley-cool & 0xFF;   // Faster way of getting green
       int b = currColor & 0xFF;            // Faster way of getting blue
       pass2ard[cPos] = r;
       pass2ard[cPos +1] = g;
       pass2ard[cPos +2] = b;
       }
    pass2ard[18] = 0xF7; //end string
    //the array that is sent to arduino should look like this "0xF0, 0x51, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0xF7" - where X is a value from 0-255

  } else if (ardCtrl == 2){
      pass2ard[0] = 0xF0; //start
      pass2ard[1] = 0x52; //motor control
      pass2ard[2] = 7; // the number of bytes to control the motors 1st is speed, 2nd through 7th are directional HIGH/LOW for the H-Bridge
      for(int l=0; l<=6; l++){
        pass2ard[l+3] = motors[l];
      }
      pass2ard[10] = 0xF7; //end string
      //the array that is sent to arduino should look like this "0xF0, 0x51, 6, X, X, X, X, X, X, 0xF7" - where X is a value
  }
   mySerial.clear();        //clear the output channel
   //mySerial.write(byte(0)); //the first byte is the index.
   //mySerial.write(byte(pass2ard[0])); //the second byte is the command.
   //delay(40); // send the start string byte to arduino and wait until response come
  
   //reinsert code to read the last byte, validate it was the one we just sent and then proceed to the following
  
   for (int i=1;i<pass2ard.length;i++){
//   for (int i=0;i<1;i++){ // temporary test to send only a couple bytes rather than all 19
//     while (mySerial.available()>0){
//     int last=mySerial.read();
//     if(debug)println("last byte: " + last);
//     if (int(last)==pass2ard[i-1]){  //confirm that the last element was received
       //mySerial.clear();
       mySerial.write(char(pass2ard));
       if(debug)println(i + ": " + pass2ard);
       delay(40);
//        }
//     }
//   }
  }
   sendComd = 0; // set the trigger to zero if successful
   if(debug)println("end of function");
}

Thanks in advance!


Oh and here is the eventual commands I would like to be able to execute on the Arduino:


void loop() {
  if (Serial.available()) {
    //check to see if the end of the string has been reached - 0xF7
    buff[0] = Serial.read();
    delay(10);
    if(debug) Serial.print("I received: ");
    if(debug) Serial.println(buff[0], DEC);
    if (buff[0] == 0xF0){ // wait for the start Sysex string command
      if(debug) Serial.println("start of string found");
      if(debug){
        digitalWrite(2,1);
        digitalWrite(4,1);
        digitalWrite(5,1);
      }
      state=1;
    }

    if (state>0){
      buff[1]=Serial.read();
      buff[2]=Serial.read();
      for (int i=0; i<buff[2]; i++) {
        buff[i+3]=Serial.read();
        if(debug) Serial.println(i + ": " + buff);
        if(buff==0xF7){
          if(debug) Serial.print("found end of string");  
          state=0;
        }
        if(debug) Serial.println(buff);
      }
      if(buff[0] == TLC_MESSAGE){
        if(debug) Serial.println("LED");
        Tlc.set(0, buff[3]);
        Tlc.set(1, buff[4]);
        Tlc.set(2, buff[5]);
        Tlc.set(3, buff[6]);
        Tlc.set(4, buff[7]);
        Tlc.set(5, buff[8]);
        Tlc.set(6, buff[9]);
        Tlc.set(7, buff[10]);
        Tlc.set(8, buff[11]);
        Tlc.set(9, buff[12]);
        Tlc.set(10, buff[13]);
        Tlc.set(11, buff[14]);
        Tlc.set(12, buff[15]);
        Tlc.set(13, buff[16]);
        Tlc.set(14, buff[17]);
      } else if(buff[0] == MOTOR_MESSAGE){
          if(debug) Serial.println("Motor");
          analogWrite(MOTOR_ENCODER, buff[3]);
          digitalWrite(L_MOTOR_DIR, buff[4]);
          digitalWrite(L_MOTOR_PWM, buff[5]);
          digitalWrite(R_MOTOR_DIR, buff[6]);
          digitalWrite(R_MOTOR_PWM, buff[7]);
          digitalWrite(V_MOTOR_DIR, buff[8]);
          digitalWrite(V_MOTOR_PWM, buff[9]);
      }
    }
  }
 if(debug) Serial.println(state);

  colorSweep(512);
  Tlc.update();
  delay(100);  
}
« Last Edit: August 03, 2011, 01:00:40 am by mattschoenholz » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 286
Posts: 25666
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
if (state>0){
      buff[1]=Serial.read();
      buff[2]=Serial.read();
It looks like you're reading data without first checking to see if data is available.

To avoid getting smilies in your code, please use a "code" box by clicking on the # icon on the editor's toolbar.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I thought I was checking to see if the data was available and then when it is proceeding to reading in Arduino. Do i need to check to see if every byte is available? Read it into an array and then process?

Could you please clarify a bit more?

thanks
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I thought I was checking to see if the data was available and then when it is proceeding to reading in Arduino. Do i need to check to see if every byte is available?
There seems to be a popular misconception about Serial.available(). It does not return true, there is data, or false, no, there is no data. It returns the number of bytes available to be read, whether that is 0, 1, or 47.

So, if you know that there are to be two bytes to be read, you can do nothing until both bytes have arrived:
Code:
if(Serial.available() >= 2)
{
  // Read both bytes...
}

Or you can wait for each byte to arrive:
Code:
while(Serial.available() == 0); // Do nothing while there is no serial data
int val1 = Serial.read();
while(Serial.available() == 0); // Do nothing while there is no serial data
int val2 = Serial.read();
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Paul!

So in the processing code, I am sending the values in an array (19 of them) as bytes. All of them are less than 255, does this mean that I will be sending 19 bytes and should wait until 19 bytes have arrived, read the whole set into an array and then use the data?

I tried the code below, and when it printed the data, it was not the data I expected. Also, probably a silly question, but if I Serial.print, will it mess up the data in the Serial buffer? I am trying to check the the data coming in and view with the serial monitor.

I flushed the Serial buffer at the end. Should I write back to Processing with a known value and then when received send a new stream of data?

  if (Serial.available() >= 19) {
   
    buff[1] = Serial.read();
    buff[2] = Serial.read();
    for (int i=0; i<buff[2]; i++) {
      buff[i+3]=Serial.read();     
    }     
   
    Serial.println("all data processed");
    for (int i=0; i<19; i++) {
      Serial.println(char(buff));
    }
    Serial.flush();
  }
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So in the processing code, I am sending the values in an array (19 of them) as bytes. All of them are less than 255, does this mean that I will be sending 19 bytes
Just because the values fit in a byte does not mean that only one byte will be sent. The number of bytes actually sent depends on the data type in Processing. Need to see some code...

Quote
I tried the code below, and when it printed the data, it was not the data I expected.
Then, it is likely that Processing is not sending just 19 bytes. See above.

Quote
Also, probably a silly question, but if I Serial.print, will it mess up the data in the Serial buffer?
Not silly at all. Still, the answer is no. The send functions (print, println, and write) have no affect on the input functions or the buffer used to hold unread data.

Quote
I flushed the Serial buffer at the end.
So, you discarded random amounts of unread data. Was this really what you wanted to do?

Quote
Should I write back to Processing with a known value and then when received send a new stream of data?
Maybe, maybe not. It depends on when/why Processing is sending data, and whether the Arduino can keep up with the data at the rate Processing is sending it. If it can't, then handshaking (which is what your proposal is called) will be useful/necessary.

Code:
if (Serial.available() >= 19) {
   
    buff[1] = Serial.read();
    buff[2] = Serial.read();
    for (int i=0; i<buff[2]; i++) {
      buff[i+3]=Serial.read();     
    }     
This code could read more than 19 bytes or less than 19 bytes. You should be waiting for/reading the number of bytes defined by buff[2].

Why are you starting to store data in buff[1] instead of buff[0]?

I think we need to see the Processing code and all of the Arduino code.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, I appreciate the guidance (and not providing the answer but pointing me in the right direction. After looking at the approach here, I realized I needed to simplify the start and end bits to a single character and then check for each of these. I am now sending a '[' and ']' for the start and end string and then a 'L' or 'M' for the LED or Motor Control.

PaulS I also saw a recent post on Serial communication using the 'started && ended' approach with a while statement. This was super helpful for guidance as well.

Here is the code that is working right now! Yay!
Code:
void loop() {
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == '[') // check for the opening character
    {
      started = true;
      index = 0;
      inData[index] = '\0';
    }
    else if(inChar == ']') // check for the end character
    {
      ended = true;
      break;
    }
    else
    {
      if(started && index < 19) // process all the bits in between
      {
        inData[index++] = inChar;
        inData[index] = '\0';
      }
    }
  }

  if(started && ended)
  {
    if (inData[0] == 'L'){ // process all the data for the LED control. Use the 15 bits 3-17 for the 5 RGB LEDs.
        if(debug) Serial.println("LED");
        Tlc.set(0, inData[3]);
        Tlc.set(1, inData[4]);
        Tlc.set(2, inData[5]);
        Tlc.set(3, inData[6]);
        Tlc.set(4, inData[7]);
        Tlc.set(5, inData[8]);
        Tlc.set(6, inData[9]);
        Tlc.set(7, inData[10]);
        Tlc.set(8, inData[11]);
        Tlc.set(9, inData[12]);
        Tlc.set(10, inData[13]);
        Tlc.set(11, inData[14]);
        Tlc.set(12, inData[15]);
        Tlc.set(13, inData[16]);
        Tlc.set(14, inData[17]);
    }
    else if(inData[0] == 'M'){
          if(debug) Serial.println("Motor");
          analogWrite(MOTOR_ENCODER, inData[2]);
          digitalWrite(L_MOTOR_DIR, inData[3]);
          digitalWrite(L_MOTOR_PWM, inData[4]);
          digitalWrite(R_MOTOR_DIR, inData[5]);
          digitalWrite(R_MOTOR_PWM, inData[6]);
          digitalWrite(V_MOTOR_DIR, inData[7]);
          digitalWrite(V_MOTOR_PWM, inData[8]);
        
    }
    if(debug){
      for(int i=1; i<17; i++) { // print the data bits (excluding the '[' and ']'
        Serial.println(inData[i]);
      }
    }

    // Reset for next pass
    inData[0] = '\0';
    index = 0;
    ended = false;
    started = false;
  }

  Tlc.update(); // send all data to the TLC through the update function
  delay(100);  
}
And here is the processing code:
Code:
void sendCommand(int ardCtrl){
 // this function will take supplied variables and package and send to arduino
  mySerial.clear(); //clear the serial buffer at the start of the function
  if(debug) println("send command function called");
  byte[] pass2ard = new byte [19];
  if(ardCtrl == 1){  
    pass2ard[0] = byte('['); //start
    pass2ard[1] = byte('L'); //led control
    pass2ard[2] = byte(15);
     for(int l=0; l<=colorLED.length-1; l++){
       color currColor = color(unhex(colorLED[l]));
       println(currColor);
       int cPos = (l*3)+3;
       int r = (currColor >> 16) & 0xFF;  // Faster way of getting red
       int g = (currColor >> 8)& 0xFF;   // Faster way of getting green
       int b = currColor & 0xFF;          // Faster way of getting blue
       pass2ard[cPos] = byte(r);
       pass2ard[cPos +1] = byte(g);
       pass2ard[cPos +2] = byte(b);
       }
    pass2ard[18] = byte(']'); //end string
    //the array that is sent to arduino should look like this "[, L, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, ]" - where X is a value

  } else if (ardCtrl == 2){
      pass2ard[0] = byte('['); //start
      pass2ard[1] = byte('M'); //motor control
      pass2ard[2] = byte(7);
      for(int l=0; l<=6; l++){
        pass2ard[l+3] = byte(motors[l]);
      }
      pass2ard[10] = byte(']'); //end string
      //the array that is sent to arduino should look like this "[, M, 6, X, X, X, X, X, X, ]" - where X is a value
  }

   mySerial.write(byte(pass2ard[0])); //the second byte is the command.
   delay(40); // send the start string byte to arduino and wait until response come

   for (int i=1;i<pass2ard.length;i++){
       mySerial.write(byte(pass2ard[i]));
       println(i + ": " + pass2ard[i]);
       delay(40);
  }
   sendComd = 0; // set the trigger to zero if successful
   println("end of function");
}

Thanks again! Now on to debugging the hardware!
« Last Edit: August 06, 2011, 12:16:47 pm by mattschoenholz » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Thanks, I appreciate the guidance (and not providing the answer but pointing me in the right direction.
I think that if put some effort into finding the answer, you will better understand the answer, as well as why it is the answer, than if you are just given an answer.

When you know why something works, you have another tool that you can adapt. If you know something works, but not why, you have no idea whether that thing can be adapted for another purpose.

So, I prefer to provide some clues, rather than complete code. If you get stuck, or need a bigger clue by four, I'm happy to provide code, and explanations.

In your case, though, you probably won't make any more mistakes in reading and using serial data, now that you understand the hows and whys and limitations. Not everyone else is there, yet.

Quote
Now on to debugging the hardware!
And learning to post code properly... See the # button?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 286
Posts: 25666
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I think that if put some effort into finding the answer, you will better understand the answer, as well as why it is the answer, than if you are just given an answer.
I think that should be framed - thanks Paul
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I think that should be framed
Well, maybe if I'd proofread it first... There is a missing "you" in the first sentence.

Logged

Pages: [1]   Go Up
Jump to: