Pages: [1]   Go Down
Author Topic: Connecting a whole bunch of Arduinos  (Read 389 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,
I'm looking to get some advice on speeding up a little serial chain of arduino pro minis.
I have 13 pro minis plus 1 digital compass (ocean server) communicating to my mac via a bluetooth (bluesmirf). Everything is daisy chained together: Tx of modem >> Rx of compass >> Tx of compass >> Rx of Arduino #1 >> Tx or Arduino #1 >> ... >> Tx or Arduino #13 >> Rx of modem. It's quite an impressive collection of tiny flashing LEDs. The compass is at the beginning of the chain since it sends data as soon as it gets powered up (can't poll it), but I can at least set it's sampling rate. The compass is serial output and is read by the first arduino via the Rx pin, where the line feed character (the end of the packet from the compass) triggers a print of the data from all the analog pins (basically adding the data to the end of the packet), and passes it down the line. I think I've set it up so that while the minis are not dealing with data from the serial port they are reading data from the analog pins. This was one of my efforts to speed things up a bit, thinking that if it wasn't reading AND printing the data when it received a line feed it might take less time. I was originally planning on setting up a little I2C network until I read the fine print about it needing 2 of my 6 analog ports...hence the daisy chain.

Everything is working great, however with each arduino that I've added I've had to lower the sampling rate to ensure that the entire packet (all the data from the compass and the 13 minis) reaches the computer. It now sits at about 12Hz, and was hoping for closer to 40Hz. My code is below, and was wondering if anyone had any pointers on how to speed this up.

Thank you in advance for any guidance.

Cheers,
David

Code:
int statusLED = 13; // status LED on Arduino
byte serialIn; // container to hold incoming serial data
// values below are used to determine sampling inverval
unsigned long time_now = 0; // current time
unsigned long time_lastprint = 0; // previous time
unsigned long dt = 0; // elapsed time
unsigned long sampleclock_now = 0; // current time
unsigned long sampleclock_lastread = 0; // previous time
unsigned long sampleclock_dt = 0; // elapsed time
int photo[6]; // holds all the data for the photosensors
unsigned long readclock_0 = 0;
unsigned long readclock_1 = 0;
unsigned long readclock_dt = 0;

// ********** change this for each Arduino in the chain **********  //
int place_in_chain = 1; // = 1 is master, others = slave
// ***************************************************************  //

void setup()
{
  Serial.begin(57600); // 57600 115200

    pinMode(statusLED, OUTPUT); // declare pin as output

  for (int i=0; i < place_in_chain; i++){ // flash status LED # flashes = assignment in chain
    digitalWrite(statusLED, HIGH);
    delay(150);
    digitalWrite(statusLED, LOW);
    delay(150);
  } // end LED flash for loop

  for (int i=0; i <= 6; i++){ // set sensor data to 0
    photo[i] = 0;
  } // end for

} // end setup

void loop()
{
  // reads data from analog inputs in background so when line feed comes in
  // it merely prints the current values rather than taking time to read the ports
  // hopefully this will speed up the sampling a bit given the number of Arduinos in our chain
  readclock_0 = micros();
  readclock_dt = readclock_0 - readclock_1;
  if (readclock_dt >= 1000) // = 1 ms
    getInputData(); // get data from analog inputs
  readclock_1 = readclock_0;

  if (place_in_chain == 1) { // I am the master
    while (Serial.available() > 0) { // check serial buffer for any data
      serialIn = Serial.read(); // assigns incoming byte to serialIn array
      if (serialIn == 10) { // line feed = end of packet from compass
        Serial.print(" "); // add a space before getting pin data
        getElapsedTime(); // get elapsed time since last pass and print it
        printInputData(); // add data from analog inputs
        Serial.println(); // print a line break  
      } // end if for line feed character

      else if (serialIn == 44) { // 44 = comma
        Serial.print(" "); // replace comma with a space
      }
      else {
        Serial.print(serialIn, BYTE); // if not a line break, then pass along Rx (compass) to the Tx pin (to the modem)
      }
    } // end while
  }
  else {
    while (Serial.available() > 0) { // check serial buffer for any data
      serialIn = Serial.read(); // assigns incoming byte to serialIn array
      if (serialIn == 10) { // line feed = end of packet from previous arduino
        Serial.print(" "); // add a space before getting pin data
        printInputData(); // add this arduinos data to packet
        Serial.println(); // print a line break
      }
      else { // it's not a line feed, so pass the data along
        Serial.print(serialIn, BYTE);
      } // end serialIn if

    } //end while loop

  }
}


void getInputData() {

  photo[0] = analogRead(0);
  photo[1] = analogRead(1);
  photo[2] = analogRead(2);
  photo[3] = analogRead(3);
  photo[4] = analogRead(4);
  photo[5] = analogRead(5);

} // end getInputData

void printInputData() {

  // add a header
  Serial.print("photo_");
  Serial.print(place_in_chain);
  Serial.print(" ");

  Serial.print(photo[0]);
  Serial.print(" ");
  Serial.print(photo[1]);
  Serial.print(" ");
  Serial.print(photo[2]);
  Serial.print(" ");
  Serial.print(photo[3]);
  Serial.print(" ");
  Serial.print(photo[4]);
  Serial.print(" ");
  Serial.print(photo[5]);
  Serial.print(" ");

} // end printInputData

void getElapsedTime() {
  time_now = millis();
  dt = time_now - time_lastprint;
  Serial.print(dt); // should be last element in list
  Serial.print(" ");
  time_lastprint = time_now;
} // end getElapsedTime


Logged

Rural Arizona
Offline Offline
Edison Member
*
Karma: 7
Posts: 1711
Incorrigible tinkerer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Calculate the number of serial bytes your sending:  the sheer volume of data is making it impossible to get 40 readings/second through the line.

You can do several things to speed things up:

1. Go to 115K baud.

2. Shrink the data volume by formatting the A/D readings in hex (this will only help if they're > 1000 a lot of the time).

3. Buy some USB-to-serial adapters,  and split the Arduinos into multiple strings.  If you double the baud rate and go with two strings of 6,  you should just about make your 40Hz rate.  You can avoid changing your Arduino software by having the GPS drive multiple strings,  and stripping the GPS data from all but one.

You might also get some improvement by increasing the I/O overlap.  Change your main loop to something like this:

Code:
serial_in_not_done = 1;

for (i = 0; i < 6; i++)
      {
      pass_through_serial();
      read_analog(i);
      }
while (serial_in_not_done)
      pass_through_serial();

append_my_readings();


serial_in_not_done is a global that gets set to 0 when the linefeed arrives in the serial input stream.

pass_through_serial() exits immediately if serial_in_not_done is 0.  Otherwise,  it checks for pending serial input,  passes it through to the output,  and watches for the linefeed.

read_analog() reads an analog input,  and formats it with something like sprintf or itoa into an appropriate spot in a buffer that holds all the readings as one string.

append_my_readings() sends the buffered readings to the serial output (with the terminating LF).

With this approach,  you'll probably have all your data ready to go by the time the LF shows up in the input stream,  minimizing processing delays.

Ran
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Ran,
Thank you so much for your help with this (and apologies for the delay in responding...been spending time switching my wireless from bluetooth to xbee, and am now back on this problem).

For some reason I haven't been able to get the compass and an arduino to play nicely at 115k, so I've been stuck at 57.6k (compass is fine @ 115k, mini is fine @ 115k, but not so when daisy-chained together as described in the first post...I get lots of bad characters, almost like a baud rate mismatch...but not). Since clearly I'm sending a ridiculous amount of data, I might as well move the compass to it's own dedicated radio, then try to split the arduinos into 2 chains and incorporate your suggestions above.

I'll be sure to report back once I've figured this out.

Much thanks,
David

Logged

Pages: [1]   Go Up
Jump to: