Need help with programming ultrasonic ranger to Arduino UNO

Hi, This is the first time I am using Arduino. I am building robot using an arduino uno, and a couple of Devantech SRF02 Sensors (http://www.robot-electronics.co.uk/htm/srf02tech.htm) I have wired everything up alright to the Arduino, but I have no idea how to program it! I have done a bit of programming in Visual Basic and Java before, and I was simply assuming that the sensor would return the result in the desired format, and then I could assign that result to a variable called 'range', and then when the range gets within a certain value, a simple while statement to execute a block of code. It seems that it is not going to be that easy. I have looked at other forums, and found the basic code to initialize and command the ranger to give me a reading in centimetres, but I have no idea how to get the ranger to actually return the result and then assign that result to a variable!!

Could someone please explain how I could do this?

Thankyou so much, Rohan

and found the basic code to initialize and command the ranger to give me a reading in centimetres,

So what's the problem?

Post the code that you have that gives the range in centimetres and we will go from there. With your experience of VB and Java it should be a small step for you to compare the range with a number and act upon the result [u]if[/u] it is larger or smaller that the target.

and then assign that result to a variable!!

The best way of doing that is to use an equals sign =

I suspect you might know this but you did ask. How about trying to say what you want to do and posting the code you have so far, hopefully with you trying to do something.

Hi, I'm sorry, now that I re read my post it does sound a little confusing!!

What I was trying to say was that I found the basic code that calls the sensor, and I also found out how to configure the sensor so that when it returns a result it returns it in centimetres. However I have no idea how to program it so that it actually returns a result!

(http://arduino.cc/en/Tutorial/SFRRangerReader) That link provides the code to configure the sensor and return a result, I understand what is going on until step 3 in the code. I have no idea what all the bytes mean!! Is what is shown the cirrect way to extract the range? If so could someone please explain what all that means? As I have no idea why it has to return 2 bytes and how that returns a range. If however there is a better way, could someone please show me that?

Thanks, Rohan

What I was trying to say was that I found the basic code that calls the sensor, and I also found out how to configure the sensor so that when it returns a result it returns it in centimetres. However I have no idea how to program it so that it actually returns a result!

Slow down. You call a function which causes the sensor to return a range. The returned value can be assigned to a variable. With that variable, you can compare the most recent range to some threshold, or print the range...or all sorts of manipulations.

If you don't understand these concepts, the IDE comes with a ton of examples to work through.

I understand what is going on until step 3 in the code. I have no idea what all the bytes mean!! Is what is shown the cirrect way to extract the range?

void loop()
{
  // step 1: instruct sensor to read echoes
  Wire.beginTransmission(112); // transmit to device #112 (0x70)
                               // the address specified in the datasheet is 224 (0xE0)
                               // but i2c adressing uses the high 7 bits so it's 112
  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)  
  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50) 
                               // use 0x51 for centimeters
                               // use 0x52 for ping microseconds
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen
  delay(70);                   // datasheet suggests at least 65 milliseconds

  // step 3: instruct sensor to return a particular echo reading
  Wire.beginTransmission(112); // transmit to device #112
  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
  Wire.endTransmission();      // stop transmitting

  // step 4: request reading from sensor
  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    reading = Wire.read();  // receive high byte (overwrites previous reading)
    reading = reading << 8;    // shift high byte to be high 8 bits
    reading |= Wire.read(); // receive low byte as lower 8 bits
    Serial.println(reading);   // print the reading
  }

  delay(250);                  // wait a bit since people have to read the output :)
}

Our ranging sensor is out on address 112, it is essentially a complete peripheral with it’s own microcontroller…we send instructions, it performs, we send a read request, it sends the data…

In step #3, we open a request, set a register, and close out request.
In step #4, we ask the sensor to send us the register value
In step #5, we check to see if the sensor sent & the Arduino received the register
If Yes, we assign the variable reading the buffer value
But, reading is a 16-bit variable and we get only 8 bits at a time from the buffer, so we have to call the buffer twice - but we shift the first reading by 8 positions before the second read! After the second read, we have the 16-but value in the variable.

These details are often abstracted (hidden) by putting this into a library. But, it is just how it would be done in a step-by-step fashion.

Ray

Ok,
So from what I understand, Reading is the variable that has the range. So if i do a simple IF statement to say that when reading is greater than a certain number run this program, would that work?

This is my code

void setup()
{
  Wire.begin();                // join i2c bus (address optional for master)
  Serial.begin(9600);          // start serial communication at 9600bps
}

int reading = 0;
int led = 13;
void loop()
{
  // step 1: instruct sensor to read echoes
  Wire.beginTransmission(112); // transmit to device #112 (0x70)
                               // the address specified in the datasheet is 224 (0xE0)
                               // but i2c adressing uses the high 7 bits so it's 112
  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)  
  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50) 
                               // use 0x51 for centimeters
                               // use 0x52 for ping microseconds
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen
  delay(70);                   // datasheet suggests at least 65 milliseconds

  // step 3: instruct sensor to return a particular echo reading
  Wire.beginTransmission(112); // transmit to device #112
  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
  Wire.endTransmission();      // stop transmitting

  // step 4: request reading from sensor
  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    reading = Wire.read();  // receive high byte (overwrites previous reading)
    reading = reading << 8;    // shift high byte to be high 8 bits
    reading |= Wire.read(); // receive low byte as lower 8 bits
    Serial.println(reading);   // print the reading
  }
if (reading > 5)
{
  digitalWrite(led,HIGH)
}
else
digitalWrite (led, LOW)
}
  delay(250);                  // wait a bit since people have to read the output :)
}

When I tried to upload the program, it keeps telling me 'wire' was not declared in this scope..

You didn't #include the Wire.h header.

Ok, after adding that it uploads fine. The aim of my code is to light up the little orange led on the board itself, when something is within a certain range.

This is my code:

#include <Wire.h>
void setup()
{
  Wire.begin();                // join i2c bus (address optional for master)
  Serial.begin(9600);          // start serial communication at 9600bps
}

int reading = 0;
int led = 13;
void loop()
{
  // step 1: instruct sensor to read echoes
  Wire.beginTransmission(112); // transmit to device #112 (0x70)
                               // the address specified in the datasheet is 224 (0xE0)
                               // but i2c adressing uses the high 7 bits so it's 112
  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)  
  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50) 
                               // use 0x51 for centimeters
                               // use 0x52 for ping microseconds
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen
  delay(70);                   // datasheet suggests at least 65 milliseconds

  // step 3: instruct sensor to return a particular echo reading
  Wire.beginTransmission(112); // transmit to device #112
  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
  Wire.endTransmission();      // stop transmitting

  // step 4: request reading from sensor
  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    reading = Wire.read();  // receive high byte (overwrites previous reading)
    reading = reading << 8;    // shift high byte to be high 8 bits
    reading |= Wire.read(); // receive low byte as lower 8 bits
    Serial.println(reading);   // print the reading
  }
if (reading > 5)
{
  digitalWrite(led,HIGH);
}
else
digitalWrite (led,HIGH);
delay (1000);
digitalWrite (led, LOW);
}

For some reason, the LED stays lit up, no matter how far away an object is. I assume that there is something I am doing wrong, but I have no idea what it is…

Thanks,
Rohan

So add some debug prints.

  if (reading > 5)
  {
    digitalWrite(led,HIGH);
  }
  else
    digitalWrite (led,HIGH);

If the reading is greater than 5 turn on the LED, otherwise turn on the LED. Looks like copy/paste then forgetting to revise the pasted code to me.

Your use of different styles (with/without braces) for if/else makes the code harder to read and can obscure what the code is meant to do. It is a matter of opinion but using braces makes things clearer,

  if(2 <= Wire.available())    // if two bytes were received

How would you describe what that statement is doing, in English?

How would you describe this statement?

  if(Wire.available() >= 2)    // if two bytes were received

Which is more natural?

Now that you can read from the device, put all the code that does so in a function. Get rid of the global variables used, and make the function return a value. Then, call that function:

   int reading = GetSensorValue();

See how much shorter, and easier to understand that makes loop()?

#include <Wire.h>
void setup()
{
  Wire.begin();                // join i2c bus (address optional for master)
  Serial.begin(9600);          // start serial communication at 9600bps
}

int reading = 0;
int led = 13;
void loop()
{
  // step 1: instruct sensor to read echoes
  Wire.beginTransmission(112); // transmit to device #112 (0x70)
                               // the address specified in the datasheet is 224 (0xE0)
                               // but i2c adressing uses the high 7 bits so it's 112
  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)  
  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50) 
                               // use 0x51 for centimeters
                               // use 0x52 for ping microseconds
  Wire.endTransmission();      // stop transmitting

  // step 2: wait for readings to happen
  delay(70);                   // datasheet suggests at least 65 milliseconds

  // step 3: instruct sensor to return a particular echo reading
  Wire.beginTransmission(112); // transmit to device #112
  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
  Wire.endTransmission();      // stop transmitting

  // step 4: request reading from sensor
  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    reading = Wire.read();  // receive high byte (overwrites previous reading)
    reading = reading << 8;    // shift high byte to be high 8 bits
    reading |= Wire.read(); // receive low byte as lower 8 bits
    Serial.println(reading);   // print the reading
  }
if (reading > 5)
{
  digitalWrite(led,HIGH);
}
else
digitalWrite (led,LOW);
}

Ok, I fixed that up, but when I run it, the light turns on after the condition is met, but as soon as the condition isnt met, the light remains on!!

Do I need to use a While loop for this?

Shouldn't there be apinMode(led, OUTPUT);in there somewhere ?

Incidentally, I still think that

if (reading > 5)
{
  digitalWrite(led,HIGH);
}
else
{
  digitalWrite (led,LOW);
}

is easier to read and understand.

Debugging a little deeper…
Get one section working, comment out the print, and move on lower into the code to resolve further issues…

  // step 5: receive reading from sensor
  if(2 <= Wire.available())    // if two bytes were received
  {
    reading = Wire.read();  // receive high byte (overwrites previous reading)
    reading = reading << 8;    // shift high byte to be high 8 bits
    reading |= Wire.read(); // receive low byte as lower 8 bits
    // Serial.println(reading);   // print the reading
  }

Serial.print("Reading = ");
Serial.print(reading);   // print the reading and a few spaces...
Serial.print("    ");

if (reading > 5)
{
    digitalWrite(led,HIGH);
    Serial.println("LED is HIGH");
}
else
     digitalWrite (led,LOW);
     Serial.println("LED is LOW");
}

Hmmm, I made all those changes, but now I cannot seem to upload it! COM 3 which was the COM Port I normally use for Arduino had disappeared, and all that is now remaining is COM 1! I have tried reinstalling drivers, restarting my computer, I have also tried unplugging it to see if the COM 1 disappears. I went into device manager, but there is only 1 COM port there, and that is COM Port 1, also when I try to reinstall the arduino drivers, it keeps saying an error occurred.

This is the error I get on the IDE - avrdude: stk500_getsync(): not in sync: resp=0x00

How would I fix this?

COM 3 which was the COM Port I normally use for Arduino had disappeared, and all that is now remaining is COM 1

1) Try another USB device on the same port. Do you get a port/mount? If so, the port is working. 2) Try Arduino on another USB port. Windows should reassign it. 3) Try another cable 4) Look carefully at Arduino end of cable for dirt/wear/broken solder/etc. 5) Try same Arduino+cable on another PC 6) Search this forum about same problem. This happens often.

Good luck. It is frustrating. Some would add: 7) Goto Linux but USB issues sometimes happen there!

Ray