Pages: [1]   Go Down
Author Topic: Fast serial output for multiple Ping )) Ultrasonic Sensors  (Read 1418 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi folks,

I am trying desperately to get 4 Ultrasonic Sensors to output to serial as fast as possible. The thing is when I use a single Ultrasonic Sensor I can output "in real time" once every 10ms with the first patch I will copy here.

After trying to multiply the code lines from this first sketch to adapt it to 4 sensors, I found a thread which suggested using arrays for multiple sensors (that I will copy here as a second sketch).

Well I tried multiplying the code lines, I tried the sketch with arrays, I tried stripping this second sketch, I even deleted the delays which I know is not such a good idea, all with no luck!

Is there a fix somewhere so as an arduino with multiple sensors would output to serial as fast as an arduino with only one sensor?

This is the typical sketch for outputing to serial from a single Ultrasonic Sensor

Code:
/* Ping))) Sensor
 
   This sketch reads a PING))) ultrasonic rangefinder and returns the
   distance to the closest object in range. To do this, it sends a pulse
   to the sensor to initiate a reading, then listens for a pulse
   to return.  The length of the returning pulse is proportional to
   the distance of the object from the sensor.
     
   The circuit:
    * +V connection of the PING))) attached to +5V
    * GND connection of the PING))) attached to ground
    * SIG connection of the PING))) attached to digital pin 7

   http://www.arduino.cc/en/Tutorial/Ping
   
   created 3 Nov 2008
   by David A. Mellis
   modified 30 Jun 2009
   by Tom Igoe
 
   This example code is in the public domain.

 */

// this constant won't change.  It's the pin number
// of the sensor's output:
const int pingPin = 7;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}

void loop()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, cm;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  cm = microsecondsToCentimeters(duration);
 

  Serial.print(cm);
  Serial.print(" cm");
  Serial.println();
 
  delay(10);
}


long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

This is the second sketch which is skipping a few "beats" even though I tried everything I could! It's for multiple Ultrasonic Sensors

Code:
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236272388

int ultraSoundSignalPins[] = {7,8,9,12}; // Front Left,Front, Front Right, Rear Ultrasound signal pins
char *pingString[] = {"a "," b ", " c ", " d "}; // just something to print to indicate direction

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  unsigned long ultrasoundValue;
  for(int i=0; i < 4; i++)
  {
    ultrasoundValue = ping(i);
    Serial.print(pingString[i]);
    Serial.print(ultrasoundValue);   
    delay(10);
  }
  Serial.println();
  delay(10);
 }

//Ping function
unsigned long ping(int i)
{
  unsigned long echo;

  pinMode(ultraSoundSignalPins[i], OUTPUT); // Switch signalpin to output
  digitalWrite(ultraSoundSignalPins[i], LOW); // Send low pulse
  delayMicroseconds(2); // Wait for 2 microseconds
  digitalWrite(ultraSoundSignalPins[i], HIGH); // Send high pulse
  delayMicroseconds(5); // Wait for 5 microseconds
  digitalWrite(ultraSoundSignalPins[i], LOW); // Holdoff
  pinMode(ultraSoundSignalPins[i], INPUT); // Switch signalpin to input
  digitalWrite(ultraSoundSignalPins[i], HIGH); // Turn on pullup resistor
  echo = pulseIn(ultraSoundSignalPins[i], HIGH); //Listen for echo
  return (echo / 58.138); //convert to CM
}
 
 

As I said, I tried many things to make it work faster (but it still skips a few readings):

- deleted char *pingString[] = {"a ","b ", "c ", "d "}; and anything related
- changed return (echo / 58.138); to return (echo); as to not convert to centimeters on the arduino and even deleted it
- decreased the two delays in the void loop (even lower than 10 each) and even deleted the two delays

Nothing seems to work!

Any solutions are truly appreciated!
ygreq
« Last Edit: July 05, 2011, 03:40:24 pm by ygreq » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 220
Posts: 13846
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


use Serial.begin(115200)  that makes the serial output 12 times as fast

Code:
long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

should not be used,  just use :   cm = duration/58; in your main code. It is not the main overhead but definitely faster...


Have you timed your ping(i) function, how many millis it takes?

Please try ping(i) as below : // just one lookup instead of looking it up every line of code

Code:
unsigned long ping(int i)
{
  uint8_t pin = ultraSoundSignalPins[i]; 
  pinMode(pin, OUTPUT);   
  digitalWrite(pin, LOW);   
  delayMicroseconds(2);     
  digitalWrite(pin, HIGH);   
  delayMicroseconds(5);     
  digitalWrite(pin, LOW);   
  pinMode(pin, INPUT);     
  digitalWrite(pin, HIGH); 
  return pulseIn(pin, HIGH) /58.138;  //Listen for echo && convert to CM
}

2 cents,
Rob
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

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

Hey Rob,

Thank you for your input.

1. The thing is changing the Serial.begin doesn't help at all. I tried. It seems there is a limitation from within arduino and how it reads more than one sensor.
2. About
Quote
just use :   cm = duration/58; in your main code. It is not the main overhead but definitely faster...
. Thank you! I think it helps when using the sketch for the single sensor, but still I need speed improvements when using multiple sensors (so this doesn't help unfortunately with the second sketch).
3. About
Quote
Please try ping(i) as below : // just one lookup instead of looking it up every line of code
, I think what you are suggesting here is already in the second sketch I posted, the one using arrays.

I stripped the second sketch for multiple sensors even more. It outputs "duration" values, not distance. Still no results!

Code:
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236272388

int ultraSoundSignalPins[] = {7,8,9,10}; // Front Left,Front, Front Right, Rear Ultrasound signal pins

void setup()
{

  Serial.begin(115200);
}

void loop()
{
  unsigned long ultrasoundValue;
  for(int i=0; i < 4; i++)
  {
    ultrasoundValue = ping(i);
    Serial.print(ultrasoundValue);
    Serial.print(" ");   
    delay(10);
  }
  Serial.println();
  delay(10);
 }

//Ping function
unsigned long ping(int i)
{
  unsigned long echo;

  pinMode(ultraSoundSignalPins[i], OUTPUT); // Switch signalpin to output
  digitalWrite(ultraSoundSignalPins[i], LOW); // Send low pulse
  delayMicroseconds(2); // Wait for 2 microseconds
  digitalWrite(ultraSoundSignalPins[i], HIGH); // Send high pulse
  delayMicroseconds(5); // Wait for 5 microseconds
  digitalWrite(ultraSoundSignalPins[i], LOW); // Holdoff
  pinMode(ultraSoundSignalPins[i], INPUT); // Switch signalpin to input
  digitalWrite(ultraSoundSignalPins[i], HIGH); // Turn on pullup resistor
  echo = pulseIn(ultraSoundSignalPins[i], HIGH); //Listen for echo
   
}

I still need desperate help!
 
« Last Edit: July 06, 2011, 05:06:22 am by ygreq » Logged

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

I am looking at how fast the TX LED blinks when I have the first sketch for a single sensor and it blinks so fast that I can not see it go LOW. On the other hand, when I have the second sketch (for 4 sensors) .. well.. Let me just say, I see it blink! smiley

I think a solution would be for the arduino to send to serial one sensor info while calculating the second one and so on.

Any suggestions on how I can achieve this?

Thank you kindly!
ygreq
Logged

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

I did it!!

Real time, baby! smiley-razz

Anyone wanting to improve the code, please do! But for now all I can say is IT WORKS! It is based on the first sketch I posted. It outputs duration and you have to do the calculations to find the distance in another program or just add the calculations yourselves! In this configuration, use routing in max 5 for example to check each sensor.


Code:
// this constant won't change.  It's the pin number
// of the sensor's output:
const int pingPin1 = 7;
const int pingPin2 = 8;
const int pingPin3 = 9;
const int pingPin4 = 10;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}

void loop()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration1;
  pinMode(pingPin1, OUTPUT);
  digitalWrite(pingPin1, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin1, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin1, LOW);
  pinMode(pingPin1, INPUT);
  duration1 = pulseIn(pingPin1, HIGH);
  Serial.print("A ");
  Serial.println(duration1);
   
  long duration2;
  pinMode(pingPin2, OUTPUT);
  digitalWrite(pingPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin2, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin2, LOW);
  pinMode(pingPin2, INPUT);
  duration2 = pulseIn(pingPin2, HIGH);
  Serial.print("B ");
  Serial.println(duration2);
 
  long duration3;
  pinMode(pingPin3, OUTPUT);
  digitalWrite(pingPin3, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin3, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin3, LOW);
  pinMode(pingPin3, INPUT);
  duration3 = pulseIn(pingPin3, HIGH);
  Serial.print("C ");
  Serial.println(duration3);
   
  long duration4;
  pinMode(pingPin4, OUTPUT);
  digitalWrite(pingPin4, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin4, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin4, LOW);
  pinMode(pingPin4, INPUT);
  duration4 = pulseIn(pingPin4, HIGH);
  Serial.print("D ");
  Serial.println(duration4);


 delay(10);
}


Logged

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

Hi, your code worked, but the readings that I get are jumping all around, from high to low, low to high every second. Is there anyway way to make it more stable or did you add a capacitor or something?

I added a 0.47uF capacitor in parallel to +5V and GND, a 100ohm resistor to +5V. Readings seems more stable but increases delay, making the readings inaccurate. Please advise.
Logged

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

I did it!!

Real time, baby! smiley-razz

Anyone wanting to improve the code, please do! But for now all I can say is IT WORKS! It is based on the first sketch I posted. It outputs duration and you have to do the calculations to find the distance in another program or just add the calculations yourselves! In this configuration, use routing in max 5 for example to check each sensor.


Code:
// this constant won't change.  It's the pin number
// of the sensor's output:
const int pingPin1 = 7;
const int pingPin2 = 8;
const int pingPin3 = 9;
const int pingPin4 = 10;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}

void loop()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration1;
  pinMode(pingPin1, OUTPUT);
  digitalWrite(pingPin1, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin1, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin1, LOW);
  pinMode(pingPin1, INPUT);
  duration1 = pulseIn(pingPin1, HIGH);
  Serial.print("A ");
  Serial.println(duration1);
   
  long duration2;
  pinMode(pingPin2, OUTPUT);
  digitalWrite(pingPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin2, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin2, LOW);
  pinMode(pingPin2, INPUT);
  duration2 = pulseIn(pingPin2, HIGH);
  Serial.print("B ");
  Serial.println(duration2);
 
  long duration3;
  pinMode(pingPin3, OUTPUT);
  digitalWrite(pingPin3, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin3, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin3, LOW);
  pinMode(pingPin3, INPUT);
  duration3 = pulseIn(pingPin3, HIGH);
  Serial.print("C ");
  Serial.println(duration3);
   
  long duration4;
  pinMode(pingPin4, OUTPUT);
  digitalWrite(pingPin4, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin4, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin4, LOW);
  pinMode(pingPin4, INPUT);
  duration4 = pulseIn(pingPin4, HIGH);
  Serial.print("D ");
  Serial.println(duration4);


 delay(10);
}




Hi I tried your code. Only the last sensor gave an accurate reading. The first two is way off. Any advice on this? Here is my modified code:
Code:
// this constant won't change.  It's the pin number
// of the sensor's output:
const int pingPin1 = 2;
const int pingPin2 = 7;
const int pingPin3 = 8;
//const int pingPin4 = 10;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}

void loop()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration1, cm;
  pinMode(pingPin1, OUTPUT);
  digitalWrite(pingPin1, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin1, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin1, LOW);
  pinMode(pingPin1, INPUT);
  duration1 = pulseIn(pingPin1, HIGH);
    cm = microsecondsToCentimeters(duration1);
  Serial.print("A ");
  Serial.print(cm);
    Serial.print("\t");    // prints a tab
   
  long duration2, cm2;
  pinMode(pingPin2, OUTPUT);
  digitalWrite(pingPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin2, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin2, LOW);
  pinMode(pingPin2, INPUT);
  duration2 = pulseIn(pingPin2, HIGH);
    cm2 = microsecondsToCentimeters(duration2);
  Serial.print("B ");
  Serial.print(cm2);
    Serial.print("\t");    // prints a tab
 
  long duration3, cm3;
  pinMode(pingPin3, OUTPUT);
  digitalWrite(pingPin3, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin3, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin3, LOW);
  pinMode(pingPin3, INPUT);
  duration3 = pulseIn(pingPin3, HIGH);
    cm3 = microsecondsToCentimeters(duration3);
  Serial.print("C ");
  Serial.println(cm3);
   
 /* long duration4;
  pinMode(pingPin4, OUTPUT);
  digitalWrite(pingPin4, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin4, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin4, LOW);
  pinMode(pingPin4, INPUT);
  duration4 = pulseIn(pingPin4, HIGH);
  Serial.print("D ");
  Serial.println(duration4);
*/

 delay(100);
}
long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}
Logged

Pages: [1]   Go Up
Jump to: