Pages: [1]   Go Down
Author Topic: Manage multiple HC SR04 sensors using Arduino UNO's Timer1 to build a radar  (Read 1935 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

I'm new in this forum... I bought an Arduino UNO and 6 HC SR04 sensors a few days ago.
I've googled a bit and I found the NewPing library
which lets you manage the sensors' ping.  smiley
I've used the example shown here
and I think it is great if you're playing with the Arduino, but I want something more from this great board, than it.

I'd like to build a Event-driven system using the Timer1 which is into UNO's chip.
I've thought to use the internal timer to manage the Task which get the data from the sensors using the Job "read_distance".
So every period X, the timer is pinging the sensors one-by-one to get the different distances from them.
I've written some lines of code and if I use only one sensor the program works perfectly, but when I increase the number of sensors it doesn't work anymore.
Here you are my code:
Code:
 #define trigPin  2   // Trigger Pin
  
  #define echoPin1 5    // Echo Pin for sensor # 1
  #define echoPin2 6    // Echo Pin for sensor # 2
  #define echoPin3 7    // Echo Pin for sensor # 3
  #define echoPin4 8    // Echo Pin for sensor # 4
  #define echoPin5 9    // Echo Pin for sensor # 5
  #define echoPin6 10   // Echo Pin for sensor # 6
  
  #define SENSORS_NUMBER 6
  #define MAXIMUM_RANGE  200  // Maximum range needed
  #define MINIMUM_RANGE  0    // Minimum range needed
  
  volatile boolean time_elapsed;
  volatile byte i;
  
  volatile byte vect[] = {-2, -2, -2, -2, -2, -2};
  
  void read_distance(byte sensor_trig_pin, byte sensor_echo_pin, byte sensor_id);
  
  void setup()
  {
      pinMode(trigPin, OUTPUT);
      
      pinMode(echoPin1, INPUT);
      pinMode(echoPin2, INPUT);
      pinMode(echoPin3, INPUT);
      pinMode(echoPin4, INPUT);
      pinMode(echoPin5, INPUT);
      pinMode(echoPin6, INPUT);
      
      // open the serial port at 9600 bps:
      Serial.begin(9600);
  
      // initialize Timer1
      cli();          // disable global interrupts
      
      TCCR1A = 0;     // set entire TCCR1A register to 0
      TCCR1B = 0;     // set entire TCCR1B register to 0
  
      // set compare match register to desired timer count, corresponds to 1 second
      OCR1A = 15624;   // Timer 1 Output Compare Register A
      
      // turn on CTC mode on Timer1:
      TCCR1B |= (1 << WGM12);
      
      // Set CS10 and CS12 bits for 1024 prescaler:
      TCCR1B |= (1 << CS10);
      TCCR1B |= (1 << CS12);
      
      // enable timer compare interrupt:
      TIMSK1 |= (1 << OCIE1A);
      
      // enable Timer1 overflow interrupt:
      //TIMSK1 = (1 << TOIE1);
      
      // enable global interrupts:
      sei();    
    
      time_elapsed = false;  
  }
  
  ISR(TIMER1_COMPA_vect)
  {
    read_distance(trigPin, echoPin1, 0);
    read_distance(trigPin, echoPin2, 1);
    read_distance(trigPin, echoPin3, 2);
    read_distance(trigPin, echoPin4, 3);
    read_distance(trigPin, echoPin5, 4);
    read_distance(trigPin, echoPin6, 5);
    
    time_elapsed = true;  
  }
  
  void loop()
  {    
    if(time_elapsed){
      
      for(i = 0; i < SENSORS_NUMBER; i++){
         Serial.print(" # ");
         Serial.print(i+1);
         Serial.print(" :");
         Serial.println(vect[i]);
      }
      time_elapsed = false;  
    }
  }
  
  void read_distance(byte sensor_trig_pin, byte sensor_echo_pin, byte sensor_id){
    
    long duration; // Duration used to calculate distance
    long distance;
    
    digitalWrite(sensor_trig_pin, LOW);
    delayMicroseconds(2);
    
    digitalWrite(sensor_trig_pin, HIGH);
    delayMicroseconds(10);
    
    digitalWrite(sensor_trig_pin, LOW);
    duration = pulseIn(sensor_echo_pin, HIGH);
    
    //Calculate the distance (in cm) based on the speed of sound.
    distance = duration/58.2;
    
    if (!(distance >= MAXIMUM_RANGE || distance <= MINIMUM_RANGE)){
      vect[sensor_id] = distance;
    }
    else{
      vect[sensor_id] = -1;
    }
  }


I've configured Timer1 with CTC mode and I've set the prescale to 1024 (# Divisions).
The OCR1A value has been evaluated according to the following formula:


The value of OCR1A corresponds to 1 second; so every time Timer1 reaches that value, 1 second has gone, ISR function is executed, and inside of it there are 6 calls to the function which get distances using the sensors.
All the sensors uses the same trigPin, the only pin which changes is the echoPin.

I can't understand where is the problem, maybe the timer but I'm not shure.
Can you help me please?

You can see my elcetrical scheme here attached to the topic.




* HC_SR04_net.png (428.73 KB, 2826x2007 - viewed 225 times.)
« Last Edit: January 21, 2014, 01:19:33 pm by Starscream » Logged

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

Code:
ISR(TIMER1_COMPA_vect)
  {
    read_distance(trigPin, echoPin1, 0);
    read_distance(trigPin, echoPin2, 1);
    read_distance(trigPin, echoPin3, 2);
    read_distance(trigPin, echoPin4, 3);
    read_distance(trigPin, echoPin5, 4);
    read_distance(trigPin, echoPin6, 5);
   
    time_elapsed = true; 
  }
Bad idea.

Why are you doing all that time-consuming stuff in an ISR?
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: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How could I avoid it? I think it is necessary if I want to get the distances from my sensors...
Can you suggest me a better idea, please?  smiley
« Last Edit: January 21, 2014, 12:55:47 pm by Starscream » Logged

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

Why is it necessary to use an interrupt?
Have a look at the blink without delay example.
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: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've seen it, but I want to use Timer's interrupt because in the main loop I can do something else with less priority than the Sensors_Ping task.
I think using interrupts is more efficient than the other ways...
Logged

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

Quote
I think using interrupts is more efficient than the other ways
But if it doesn't work, perhaps a more pragmatic approach is required.
Your call.
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.

New Jersey
Offline Offline
Faraday Member
**
Karma: 72
Posts: 3763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It looks like you're triggering all the sensors at the same time. Unless they are far apart, they're likely to interfere with each other. Even if you trigger them one at a time, you're likely to need a delay for returns from further objects to die away. Delaying in an interrupt routine is not recommended.
Logged

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

It hardly seems necessary to point out that the speed of sound provides a very real delay.
But I'll do it anyway.
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: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I want to do something like this:


they could interfere but I'm not sure.
Changing my code, I reduced Timer1's period from 1 second to 0.1 second and I ping the sensors one at period. It works, but I've divided the tak with six jobs, into 6 tasks with one job per task.
In this way the tasks will run more frequently than what it did the "big" old task.

Here you are the changes:

I've changed OCR1A's value, it corresponds to 0.1 seconds:
Code:
      // set compare match register to desired timer count:
      OCR1A = 1561;   // Timer 1 Output Compare Register A


I've introduced a new global variable:
Code:
volatile byte current_sensor;
void setup()
  {
      ...
      current_sensor = 0;
  }

I've changed the ISR function:
Code:
ISR(TIMER1_COMPA_vect)
  {
    switch(current_sensor){
      case 0:  read_distance(trigPin, echoPin1, 0);
               current_sensor = 1;
        break;
      case 1:  read_distance(trigPin, echoPin2, 1);
               current_sensor = 2;
        break;
      case 2:  read_distance(trigPin, echoPin3, 2);
               current_sensor = 3;
        break;
      case 3:  read_distance(trigPin, echoPin4, 3);
               current_sensor = 4;
        break;
      case 4:  read_distance(trigPin, echoPin5, 4);
               current_sensor = 5;
        break;
      case 5:  read_distance(trigPin, echoPin6, 5);
               current_sensor = 0;
        break;
    }
   
    time_elapsed = true; 
  }

 I've changed the loop in this way:
Code:
void loop()
  {   
    if(time_elapsed){
     
      Serial.print(" # ");
      Serial.print(current_sensor+1);
      Serial.print(" :");
      Serial.println(vect[current_sensor]);
     
      time_elapsed = false; 
    }
  }

This is not what I've thought, but it works!
If you have any better idea tell me please!
Logged

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

Have you looked at the blink without delay example?
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: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, I have. But I don't think it will be as accurate as Timer1's interrupt.
It simply checks, periodicaly, if a value is bigger than an other, so it isn't a "real-time" criteria...
Logged

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

Quote
But I don't think it will be as accurate as Timer1's interrupt.
I'm sorry, I really don't see that it matters.
Is there some hard real-time requirement for range data?
Does it really matter if there is +/- 1ms jitter on the times these measurements are taken?
(bearing in mind that 1ms is about 34cm)
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: 6
I've discovered micros world recently! :-D
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you're right.
I'm developing this project because I'd like to build a little drone. That's why I have placed the sensors in this position (see the schema above).
The drone will receive instruction from a PC via wirless communication and I don't it to crash against an obstacle will it 's receiving the instruction set.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50903
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The drone will receive instruction from a PC via wirless communication and I don't it to crash against an obstacle will it 's receiving the instruction set.
I think you need to do three things:
1) Look at the examples that come with the NewPing library. It already provides for scheduled reading from the sensors. Let the library handle when to read again.

2) Stop replicating code and pretending to have an array of sensors and pins. Use real arrays.

3) Concentrate on reading the PC data as fast as possible, and quit worrying about stuff that is already interrupt driven. Worry about the stuff that really will take time.
Logged

Pages: [1]   Go Up
Jump to: