Reading Continuous Serial Packets

Hi All

Background: I'm a newbie to Ardunio. Please be patient. I'm an Avionics teacher at George T. Baker Aviation School in Miami, Florida USA. Please visit our web-site at http://www.bakeraviation.edu/ . My students and I are in the process of building a full motion Flight Simulator using Arduinos to capture motion data packets. See video of our Sim at http://alanmunoz.smugmug.com/Other/Thank-You-ISATAT/28097956_8pFXvM#!i=2374199097&k=dBXbrDp

This project is funded by ISTAT ( INTERNATIONAL SOCIETY OF TRANSPORT AIRCRAFT TRADING FOUNDATION), Miami Dade County Public Schools and The Ed-Fund. Most of the major mechanical aspect of the project is done.

We now beginning to start electrical aspects.

At present we are using MS X Sim software and BFF 6DOF Motion Driver V3.0 beta ( http://bffsimulation.com/6DOF-Motion-Software.php)which captures cues from MS-X. It sends out continuous actuator data in serial format (Bin) such as "AB" byte1 byte2 byte3 byte4 byte5 byte6 byte7 (CR), see ( http://bffsimulation.com/Manual-6DOF/Formats.php ).

We are looking to using 7 Arduino Megas in I2c configuration where there will be one master and six slaves, one for each actuator.

The Problem:

Currently we are using one master and one slave (connected to two different Laptops). I'm at work and don't have master and slave sketches with me. The master works like this, it clears the serial buffer and begins to look for the character "A" once found it reads off each character there after which are turned into integer for each actuator. Act1 data is sent across the I2c to slave 1. Slave 1 prints out the data on it's serial monitor. Initially on the slave monitor when first starting out, I can see the proper data values (53), then it begins to show what i call out liars randomly. Such (65) which is the "A" or "B" (66) or even a "CR" (13).

Then I found an example that uses a different technique which allow one to read of bytes using a while loop. I add the I2c (Wire) commands to have the master send to the slave each bytes read. Again initially the data sequence starts out correct and then begins to show out-liars. Last evening I added code to the slave that would filter out known out-liar values. This seemed to work but then I notice -1 would occasionally come in, I filtered that but the slave did not like that, it would run showing captured data then halt.

With all this said and not having the actual sketches used, what would be the best way to capture a continuous stream of byte in sequence?

I will post Master and Slave sketches when I get home.

Your help in this mater is truly appreciated.

sim123

My first guess is, that it is a software problem. It seems that the serial port communcation is mixed with the i2c communication.

How long are the I2C wires ? What kind of wires ? How is the ground connected ? How is it powered ?

Is using the serial communication an option ? With a few extra serial ports (SoftwareSerial) you should be able to connect it all.

How long are the I2C wires ? Wire are short no more than 6" long with 10K ohms pull-ups on each SDA anSCL. In my reading I2C can handle wires up to 100' under the proper conditions.

What kind of wires ? 20 gauge solid

How is the ground connected ? Both Arduinos grounds are tied together.

How is it powered ? Each Arduino is powered by its Lap-Top.

BFF Motion Comm (BFF) can use Com1-Com9, I'm using standard the 8bits, no parity, 1 stop bit, continous flow.

When a constant is sent (I2C Test) across to the slave no variations are seen even when moving wires, thus no cross talk I believe.

I contacted the developer of BFF he assured me that his data was solid. He suggessted that I get serial monitor software and it will show his data is in fact solid. I have yet to purchase it.

I'm not familiar with (Software Serial)but I'm thinking it where you would use data lines for communication. In that case I would need additional hardware, Max232 and maybe a USB to 232 conversion cable. What woud be the advantages?

How does the serial buffer works is it a FIFO? According to what I've read it 64 Bytes long and when empty on serial read one gets a -1. When a read is done a byte is pulled off would does another go in on the other end? I tried peek thinking data was being shifted as I read it off. But on review of the stream on the slave monitor it does not show that.

I appreciate your help

Sim123

(Answer to your first post) In short: You want to transfer the 7 bytes received on the standard Serial port (after an 'A') on the board designated Master, and then copy them to each of 7 boards, using the I2C, one byte to each. Your current setup is only one slave but it is not echoing the correct characters.

After having sent the one byte to slave1, do you wait for the initiator sequence again (Or at least read and discard 6 characters)? Your description gives reason to believe you send all bytes to the slave.

(As I wrote your 2nd post arrived). The Serial is a straight FIFO (FirstInFirstOut). Thus having read the first byte Serial.read() your next Serial.read() will read the next character. BUT if you keep doing Serial.read() you will be reading before the bytes have arrived, so do not do Serial.read() without checking Serial.available()>0 Your 2nd post makes me believe you incorrectly read Serial.

Thank you for your answers.

For a serial terminal, I use the serial monitor of the Arduino. If I don't have the Arduino software installed on a PC, I use this one, http://sourceforge.net/projects/qst/

The Arduino has RX and TX pins. You can connect that to other Arduinos without additional hardware. You have choosen the I2C bus. That is no problem, and you have a single Master with a few Slaves.

I didn't mean crosstalk, but some software mixing of the serial port and the I2C bus. I see that Msquare is also thinking about a software problem.

Thank you Erdin. Yes, we do not know at this moment if the problem is HW or SW. :~

Here is a "correct" way to read serial to do some processing.

void setup() {
  Serial.begin(9600) ;
}
boolean WaitA = true ;
void loop() {
  if ( Serial.available()>0 ) {
    char C = Serial.read() ;
    if ( WaitA ) {  // If we are waiting for the A
      WaitA = C!='A' ;  // See if it has arrived
         // and then do no more. Execute loop many times until next char arrives
    } else {        // We have recieved a character AFTER the A
      Serial.println(C,DEC) ;  // Printout the decimal value
      WaitA = true ;     // ignore all else until the next A
    }
  }
}

just use your I2C send routine instead. (with write, not print).

The logic here is flawed, if an "A" is part of the data packet - but it is a short example.

In my reading I2C can handle wires up to 100’ under the proper conditions.

It’s a protocol meant for communications between ICs on a board - in most cases this will be less than 1/50th that distance.

Hi All

Here is may one of my Master code:

#include <Wire.h>

// BFF Binary actuator code sequence

int A; // First Start of data identifier
int B; // Second Start data identifier
int C; // Reserved
int Act1;
int Act2;
int Act3;
int Act4;
int Act5;
int Act6;

int j1;
int j2;

void setup()
{

Serial.begin(9600);
Serial.flush();
Wire.begin(); // join i2c bus (address optional for master)
}

void loop() {
// read the oldest byte in the serial buffer:

if (Serial.available() > 0) {
j1 = Serial.read();

if (j1 == ‘A’){ // Find the first indentifing char
//delay (11); // It seems to need a delay here
B = char (Serial.read()); // read second start identifier
//delay (20);
//Serial.print(B);
C = char(Serial.read()); // read reseved identifer
//delay (20);
//Serial.print(C);
Act1 = int(Serial.read()); // read actuator 1
//delay (20);
//Serial.print(Act1);
Act2 = int(Serial.read()); // read actuator 2
//delay (20);
//Serial.print(Act2);
Act3 = int(Serial.read()); // read actuator 3
//delay (20);
//Serial.print(Act3);
Act4 = int(Serial.read()); // read actuator 4
//delay (20);
//Serial.print(Act4);
Act5 = int(Serial.read()); // read actuator 5
// delay (20);
//Serial.print(Act5);
Act6 = int(Serial.read()); // read actuactor 6)
//Serial.print(Act6);

delay (100);

Wire.beginTransmission(1); // transmit to device #4
Wire.write("Ac1= "); // sends five bytes
Wire.write(Act1); // sends one byte
Wire.endTransmission(); // stop transmitting
delay(100);

}
}
}

Here is my Slave code:

#include “DualVNH5019MotorShield.h”
DualVNH5019MotorShield md;
#include <Wire.h>
int potPin = 0; // select the input pin for the potentiometer
int PreVal = 0;

void setup()
{
Wire.begin(1); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
Serial.println(“Dual VNH5019 Motor Shield”);
md.init();

}

void loop()
{
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{

Start:

while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int Act1 = Wire.read(); // receive byte as an integer

if (Act1 = 65)
{
goto Start;
}

if (Act1 = 66)
{
goto Start;
}

if (Act1 = 1)
{
goto Start;
}

if (Act1 = 13)

{
goto Start;
}

Serial.println(Act1); // print the integer

PreVal = analogRead(potPin); // Read actuator pot value OldX

Serial.println(PreVal); // Print actuator pot value OldX
Serial.println(Act1); // Print actuator pot value OldX

Serial.println(“check1”);

delay(20);

if (Act1 < PreVal-21)
{
delay(20);
Serial.println(“Forward”);
md.setM1Speed(200);
//delay(2000);
//goto Start;
}
else if (Act1 > PreVal+21)
{
delay(20);
Serial.println(“Reverse”);
md.setM1Speed(-200);
//delay(2000);
//goto Start;
}

else if ((Act1 <= PreVal+20) && (Act1 >= PreVal-20) )
{

delay(20);
Serial.println(“Stop”);
md.setM1Speed(0);
//delay(2000);

}

}

Now, again, with code tags and without gotos, please.

  if (Act1 = 65)those can get corrected too.

The Serial.begin() initializes everything. You don't need a flush after that.

Reading the 'act' variables is wrong. In the way Msquare wrote about. If you test "Serial.available() > 0", it is "true" if only one byte is received. The following code is executed while the serial port is still receiving data. In other words: you call Serial.read() while that data is being received at that very moment. The data is probably available a few milliseconds later. The 11 ms delay could be enough, but if the data is transmitted with pauses, it could be longer than 11 ms. If a mismatch occurs between sender and receiver, that 11 ms will do no good at all.

Conclusion: Call only the Serial.read() for bytes that are actually Serial.available().

The receiveEvent() function is a handler. Using long delays is not something to put in a handler function. The 'goto' is ofcourse not needed. Many people (like me) don't like a 'goto' in a C++ program.

Are you saying that I should do a serial available prior to each read.

if (Act1 = 65)
  {
  goto Start;   
  }

No, I'm saying you'll always go to "start".

Are you saying that I should do a serial available prior to each read.

YES.

Execpt it means that with your loop it will then fall through (as all the available() test will be false for 10ms after the first read) and so you will be back at athe beginning of your loop() and look for the start character....

A "quick" fix (not pretty, has it's own problems) is to do if ( Serial.available()>=9 )at the top. Ie you wait until you have all 9 characters. (The AB and 7 bytes.) This will break - horribly - if you miss one byte or the sending protocol sends more (like a Carraige return)

Are we talking Master or Slave, on the master are you say do a serial available prior to serial read.

I played with that, if ( Serial.available()>=9 ) and 10 there was no effect change in slave data misses. I going to do the serial available prior to each read.

New Master Code

#include <Wire.h>

// BFF Binary actuator code sequence

int A; // First Start of data identifier
int B; // Second Start data identifier
int C; // Reserved
int Act1;
int Act2;
int Act3;
int Act4;
int Act5;
int Act6;

int j1;
int j2;

void setup()
{

Serial.begin(9600);
Serial.flush();
Wire.begin(); // join i2c bus (address optional for master)
}

void loop() {
// read the oldest byte in the serial buffer:

if (Serial.available() > 0) {
j1 = Serial.read();

if (j1 == ‘A’){ // Find the first indentifing char

if (Serial.available() > 0)
//delay (11); // It seems to need a delay here
B = char (Serial.read()); // read second start identifier

if (Serial.available() > 0)
//delay (20);
//Serial.print(B);
C = char(Serial.read()); // read reseved identifer

if (Serial.available() > 0)

//delay (20);
//Serial.print(C);
Act1 = int(Serial.read()); // read actuator 1

if (Serial.available() > 0)

//delay (20);
//Serial.print(Act1);
Act2 = int(Serial.read()); // read actuator 2

if (Serial.available() > 0)
//delay (20);
//Serial.print(Act2);
Act3 = int(Serial.read()); // read actuator 3

if (Serial.available() > 0)
//delay (20);
//Serial.print(Act3);
Act4 = int(Serial.read()); // read actuator 4

if (Serial.available() > 0)
//delay (20);
//Serial.print(Act4);
Act5 = int(Serial.read()); // read actuator 5

if (Serial.available() > 0)
// delay (20);
//Serial.print(Act5);
Act6 = int(Serial.read()); // read actuactor 6)
//Serial.print(Act6);

delay (100);

Wire.beginTransmission(1); // transmit to device #4
Wire.write("Ac1= "); // sends five bytes
Wire.write(Act1); // sends one byte
Wire.endTransmission(); // stop transmitting
delay(100);

}
}
}

Slave code was changed where if goto’s were commented out Stream continue to show out-liars.

Thanks for the learning experience.

And what If Serial.available isn't greater than zero? What about some CODE TAGS?

Here is another piece of Master code to test throughput

Master

#include <Wire.h>

void setup() {
Serial.begin(9600);
Wire.begin(); // join i2c bus (address optional for master)
}
unsigned int integerValue=0; // Max value is 65535
char incomingByte;

void loop() {
if (Serial.available() > 0) { // something came across serial

while(1) { // force into a loop until ‘CR’ is received
Serial.flush();
incomingByte = Serial.read();
if (incomingByte == ‘CR’) break; // exit the while(1), we’re done receiving
if (incomingByte == -1) continue; // if no characters are in the buffer read() returns -1

Wire.beginTransmission(1); // transmit to device #1
Wire.write("incomingByte= "); // sends five bytes
Wire.write(incomingByte); // sends one byte
Wire.endTransmission(); // stop transmitting
delay(100);

}
}
}

Slave

#include <Wire.h>

void setup()
{
Wire.begin(1); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
Serial.println(“Dual VNH5019 Motor Shield”);

}

void loop()
{
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{

//if (Wire.available()>0);
while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int incomingByte = Wire.read(); // receive byte as an integer
Serial.println(incomingByte); // print the integer
Serial.println(“check1”);

}

I get the same data misses on the slave Arduino serial monitor. I’m going to see what happens when I exchange the Master Arduino with a new one.

Code tags. Use the # symbol on the toolbar.

Please.

if (incomingByte == 'CR') break does it seem likely that a single character read will ever equal two characters?

ok ASCII carriage return, CR is = 13 DEC