Baby O and PING

Hi,

Trying a test with a PING sensor (Parallax PING))) Ultrasonic Sensor #28015). I can’t seem to prime it to send a pulse. It’s getting the 5V power. Here’s the code. Any thoughts? Thanks!

-Tyler-

#include <pololu/orangutan>

OrangutanPulseIn PulseIn;
OrangutanAnalog analog;
OrangutanLEDs leds;
OrangutanMotors motors;


void loop ()
{
int microPulse =0;
int pingPin = 1;

// 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:
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMilliseconds(2);
  OrangutanDigital::setOutput(pingPin, HIGH);
  OrangutanTime::delayMilliseconds(10);
  OrangutanDigital::setOutput(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.
OrangutanDigital::setInput(pingPin, HIGH_IMPEDANCE);

microPulse = OrangutanPulseIn::getLastHighPulse(pingPin);

microPulse *= 5;

OrangutanTime::delayMilliseconds(10);


leds.red(HIGH);   //led on 
OrangutanTime::delayMilliseconds(microPulse);
leds.red(LOW); //led off 
  
  
  OrangutanTime::delayMilliseconds(900);
  
}

int main()
{
  // setup();
  while(1)
  {
    loop();
  }
}
  // 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:
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMilliseconds(2);
  OrangutanDigital::setOutput(pingPin, HIGH);
  OrangutanTime::delayMilliseconds(10);
  OrangutanDigital::setOutput(pingPin, LOW);

These pauses need to be changed to microsecond pauses. Also look at the rest of your program to make sure you are using the correct delay. There is a 1000 times difference between micro and milliseconds.

Ooops, thanks, good catch. :blush:

I still can’t seem to get a reading out of the sensor though. No response from it’s indicator light. I am using the Orangutan on-board LED as feedback for the PING pulses, but it stays lit continuously…

Here’s the new code:

#include <pololu/orangutan>
//#include <OrangutanLEDs.h>
//#include <OrangutanAnalog.h>
//#include <OrangutanMotors.h>


// 
OrangutanPulseIn PulseIn;
OrangutanAnalog analog;
OrangutanLEDs leds;
OrangutanMotors motors;


void loop ()
{
int microPulse =0;
int pingPin = 1;

// 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:
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMicroseconds(2);
  OrangutanDigital::setOutput(pingPin, HIGH);
  OrangutanTime::delayMicroseconds(5);
  OrangutanDigital::setOutput(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.
OrangutanDigital::setInput(pingPin, HIGH_IMPEDANCE);

microPulse = OrangutanPulseIn::getLastHighPulse(pingPin);

microPulse *= 50;

OrangutanTime::delayMilliseconds(10);


leds.red(HIGH);   //led on 
OrangutanTime::delayMilliseconds(microPulse);
leds.red(LOW); //led off 
  
  
  OrangutanTime::delayMilliseconds(900);
  
}

int main()
{
  // setup();
  while(1)
  {
    loop();
  }
}

It looks like using Orang Pulsin is more complex than simply calling the pulsin function. I’m guessing you need a call to OrangutanPulseIn::start, possibly others.

You have a construct similar to Arduino. If are using the Ardiuno libraries, there is a simple pulsin command that you could use.

I’m not much of an AVR user myself, so I couldn’t help you write your own. On PIC I could use something along the lines of:

TRISA = 0b00000001;  //Pin 0 is input
while(RA0 == 0);
while(RA0 == 1)
{
pulseLength++;
}

A delay would be necessary for higher clock speeds, and micro second resolution, or a divider on the final result for slower clock speeds. There are better ways to do this (such as using a timer), but that is a quick and simple method that gets you up and running.

Yeah, I think you are right. I’ve tried incorporating the “start” command as well now. I am now getting the Ping indicator light to flash, so it seems to be sending the pulses, but I’m not getting anything out of the BabyO LED, which means I’m not able to access the length of the last high pulse. I’ve tried to keep it as close to the examples just to see if I can get it to work…

(I suppose the workaround you posted would suffice, but I would really love to use the Baby O library if I can… :slight_smile: )

Hello.

Can you post the most recent version of your code? One thing you might try to do is simulate the Ping pulse with one of the Baby O’s digital outputs and try measuring that. That way you can be sure that your problems aren’t being caused by the Ping.

- Ben

Hi Ben, sorry I meant to post the code last time. I’m really just trying to get the onboard LED to flash, so there’s no much to simulate. The PING is getting it’s pulses, but I’m not sure about the pulses it sends back. I wish I had a better way to debug, but I don’t. I’m starting to play around with the sloscope a little…

PS, I did get the Ping to work on an Arduino, so the Ping itself should be OK.

#include <pololu/orangutan>
//#include <OrangutanLEDs.h>
//#include <OrangutanAnalog.h>
//#include <OrangutanMotors.h>


// 
OrangutanPulseIn PulseIn;
OrangutanAnalog analog;
OrangutanLEDs leds;
OrangutanMotors motors;


void loop ()
{
unsigned long pulse_width;
unsigned char pingPin = IO_D2;
//unsigned char pulseArray [] = {1,2};

// 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:
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMicroseconds(2);
  OrangutanDigital::setOutput(pingPin, HIGH);
  OrangutanTime::delayMicroseconds(5);
  OrangutanDigital::setOutput(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.
//OrangutanDigital::setInput(pingPin, HIGH_IMPEDANCE);

OrangutanPulseIn::start((unsigned char[]) {pingPin}, 1);

pulse_width = OrangutanPulseIn::getLastHighPulse(pingPin);

unsigned long ledDelay = pulse_width * 250000;

OrangutanTime::delayMilliseconds(10);


leds.red(HIGH);   //led on 
OrangutanTime::delayMilliseconds(ledDelay);
leds.red(LOW); //led off 
  
  
  OrangutanTime::delayMilliseconds(900);
  
}

int main()
{
  // setup();
  while(1)
  {
    loop();
  }
}

I apologize for my delayed reply. I hope you’ve fixed your program by now, but if not, I notice a few problems:

  1. You have commented out the line that sets the pin as an input.

    //OrangutanDigital::setInput(pingPin, HIGH_IMPEDANCE);
    

The PulseIn library does not do that for you, so you should uncomment that line.

  1. Your LED delay is ridiculously long:
unsigned long ledDelay = pulse_width * 250000;

OrangutanTime::delayMilliseconds(10);


leds.red(HIGH);   //led on 
OrangutanTime::delayMilliseconds(ledDelay);
leds.red(LOW); //led off

You are trying to delay 250 seconds (4.2 minutes) for every quarter microsecond of Ping pulse length. Given that the Ping pulse length might be a few tens of milliseconds if your object is 10m away, that means you are potentially trying to delay for around 200 days. This won’t actually work, since the argument to delayMilliseconds() is a two-byte integer and limited to values from 0 to 65535, but even if it worked as you intended, it would not be very helpful.

Did you mean to divide by 4000? (4000 quarter microseconds is one millisecond.)

- Ben

Hi Ben,

I’ve tried switching to an input first. I had commented it out in an effort to experiment around. Same with the delay. I’ve tried multiplying, dividing, diferent values, all with the same result: no LED reaction. The value I have in the code above was me trying to use some extremes to see if there was any change. Nope.

(actually, I get the faintest flicker out of it as the PING light pulses, but it is so dim, I think it is just spilling over)…

So… has anyone gotten a Ping Ultrasound sensor to work with the Baby O? If you could post your code, I would be most grateful… I still don’t seem to be able to “capture” the return pulse… thanks,
-Tyler-

Sorry for the delayed reply. I didn’t look at your code too closely the first time because I immediately saw two glaring errors that would explain why nothing was happening. Looking at it some more, I see at least two other problems:

OrangutanPulseIn::start((unsigned char[]) {pingPin}, 1);
pulse_width = OrangutanPulseIn::getLastHighPulse(pingPin);

getLastHighPulse() does not block execution while waiting for a pulse to finish. Rather, it just tells you how long the last high pulse was, and at the time you are calling it, there has not been a high pulse yet, so it will just return zero. Also, the “channel” argument to getLastHighPulse() is not the pin, it’s the index of the pulsePins array supplied to the start method. You should be doing something like:

OrangutanPulseIn::start((unsigned char[]) {pingPin}, 1);
while (!OrangutanPulseIn::newHighPulse(0));  // wait for the high pulse from the ping to end
pulse_width = OrangutanPulseIn::getLastHighPulse(0);

I haven’t tested this, but can you try something like the following for your program and see if it works?

#include <pololu/orangutan>

OrangutanPulseIn PulseIn;
OrangutanLEDs leds;
const unsigned char pingPin = IO_D2;

void loop ()
{
  unsigned long pulse_width;
  unsigned char pingPin = IO_D2;

  // 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:
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMicroseconds(2);
  OrangutanDigital::setOutput(pingPin, HIGH);
  OrangutanTime::delayMicroseconds(5);
  OrangutanDigital::setOutput(pingPin, LOW);
  OrangutanTime::delayMicroseconds(2);

  // 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.
  OrangutanDigital::setInput(pingPin, HIGH_IMPEDANCE);
  OrangutanPulseIn::start((unsigned char[]) {pingPin}, 1);
  while (!OrangutanPulseIn::newHighPulse(0));  // wait for the high pulse from the ping to end
  pulse_width = OrangutanPulseIn::getLastHighPulse(0);

  unsigned int ledDelay = pulse_width / 40;

  leds.red(HIGH);   //led on 
  OrangutanTime::delayMilliseconds(ledDelay);  // should delay between 0.01 and 1.8 s
  leds.red(LOW); //led off 
  
  OrangutanTime::delayMilliseconds(900);
  OrangutanPulseIn::stop();
}

int main()
{
  setup();
  while(1)
  {
    loop();
  }
}

Using an LED for feedback makes debugging tough, however. If you have our USB AVR programmer, you could use it as a USB-to-serial adapter and send the actual measured pulse length back to the computer so you can have a better idea what’s going on.

- Ben

Success! You nailed it. I did not know the channel was the array…
Thanks for your while command suggestion as well.

I would love to debug that way & I do have your USB AVR programmer. Can you elaborate on how to accomplish this? What software would I need on the PC to monitor the data from the programmer/Baby O?

Thanks,
Tyler

I’m very glad it’s working for you now!

The programmer’s USB-to-serial adapter feature is described in the user’s guide. You would need to connect the programmer’s TX and RX pins to the PD0 and PD1 pins on the Baby Orangutan, respectively. You will also need to make sure there is a common ground between the programmer and the Baby O. The Pololu AVR library has functions for serial communication that you could use to communicate with your computer.

If you still have questions or run into trouble getting it working, please let me know.

- Ben

Hi Ben,

Thanks, I got it working, to a degree. I’m using hyperterminal. I got some characters like “hello” to work like this:


// send_buffer: A buffer for sending bytes on PD1/TXD. 
char send_buffer[] = "hello"; 
  
// wait_for_sending_to_finish:  Waits for the bytes in the send buffer to 
// finish transmitting on PD1/TXD.  We must call this before modifying 
// send_buffer or trying to send more bytes, because otherwise we could 
// corrupt an existing transmission. 
void wait_for_sending_to_finish() 
{ 
    while(!OrangutanSerial::sendBufferEmpty()); 
} 

void loop ()
{

    // Set the baud rate to 9600 bits per second.  Each byte takes ten bit 
    // times, so you can get at most 960 bytes per second at this speed. 
    OrangutanSerial::setBaudRate(9600); 
    wait_for_sending_to_finish();
	OrangutanSerial::send(send_buffer, 6);

    OrangutanTime::delayMilliseconds(1000); 

But, I’m having trouble getting numerical output to work:


// send_buffer: A buffer for sending bytes on PD1/TXD. 
int send_buffer[] = {1,2,3}; 
  
// wait_for_sending_to_finish:  Waits for the bytes in the send buffer to 
// finish transmitting on PD1/TXD.  We must call this before modifying 
// send_buffer or trying to send more bytes, because otherwise we could 
// corrupt an existing transmission. 
void wait_for_sending_to_finish() 
{ 
    while(!OrangutanSerial::sendBufferEmpty()); 
} 

void loop ()
{

    // Set the baud rate to 9600 bits per second.  Each byte takes ten bit 
    // times, so you can get at most 960 bytes per second at this speed. 
    OrangutanSerial::setBaudRate(9600); 
    wait_for_sending_to_finish();
	OrangutanSerial::send(send_buffer, 3);

    OrangutanTime::delayMilliseconds(1000); 

}

int main()
{
  // setup();
  while(1)
  {
    loop();
  }
}

With this error:

rm -rf Serial_to_terminal_test.o  test.elf dep/* test.hex test.eep test.lss test.map
Build succeeded with 0 Warnings...
avr-g++  -mmcu=atmega328p -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Serial_to_terminal_test.o -MF dep/Serial_to_terminal_test.o.d  -c  ../Serial_to_terminal_test.cpp
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
../Serial_to_terminal_test.cpp: In function 'void loop()':
../Serial_to_terminal_test.cpp:35: error: no matching function for call to 'OrangutanSerial::send(int [3], int)'
c:/winavr-20100110/lib/gcc/../../avr/include/pololu/OrangutanSerial/OrangutanSerial.h:146: note: candidates are: static void OrangutanSerial::send(char*, unsigned char)
c:/winavr-20100110/lib/gcc/../../avr/include/pololu/OrangutanSerial/OrangutanSerial.h:166: note:                 static void OrangutanSerial::send(unsigned char, char*, unsigned char)
make: *** [Serial_to_terminal_test.o] Error 1
Build failed with 1 errors and 1 warnings...

I’m also not sure how to convert to following to C++, can you help me with that? It’s from the serial1 example. I’ve searched the internet to no avail…

memcpy_P(send_buffer, PSTR("Hi there!/r/n"), 11);

I’m not sure what exactly you’re trying to do, but you should change the type of your send_buffer array to “char”. You either want:

char send_buffer[] = {1,2,3};

or

char send_buffer[] = {'1','2','3'};

(or char send_buffer[] = {123};)

What are you trying to accomplish with the memcpy_P() call, and what error do you get? Can you post your full code?

- Ben

If I use “char” instead of “int”, it builds OK, but the output on hyperterminal is " " (depending on the font), instead of “123”. I assumed it was because it thought it was a character instead of a number… :confused:

As for the memcpy_P call, I was just trying to get the example serial1 from the user guide to work. I was assuming it was because I was building it in C++… Here’s the complete code:

#include <pololu/orangutan>
//#include <OrangutanLEDs.h>  these are Arduino libraries
//#include <OrangutanAnalog.h>
//#include <OrangutanMotors.h>

OrangutanPulseIn PulseIn;
OrangutanAnalog analog;
OrangutanLEDs leds;
OrangutanMotors motors;

// send_buffer: A buffer for sending bytes on PD1/TXD. 
char send_buffer[32]; 
// wait_for_sending_to_finish:  Waits for the bytes in the send buffer to 
// finish transmitting on PD1/TXD.  We must call this before modifying 
// send_buffer or trying to send more bytes, because otherwise we could 
// corrupt an existing transmission. 
void wait_for_sending_to_finish() 
{ 
    while(!OrangutanSerial::sendBufferEmpty()); 
} 

void loop ()
{
    // Set the baud rate to 9600 bits per second.  Each byte takes ten bit 
    // times, so you can get at most 960 bytes per second at this speed. 
    OrangutanSerial::setBaudRate(9600); 
    wait_for_sending_to_finish();
	memcpy__P(send_buffer, PSTR("Hi there!/r/n"), 11);
	OrangutanSerial::send(send_buffer, 11);
    OrangutanTime::delayMilliseconds(1000); 
}

int main()
{
  // setup();
  while(1)
  {
    loop();
  }
}

ERRORS:

Build started 8.5.2012 at 19:47:48
avr-g++  -mmcu=atmega328p -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Serial_to_terminal_test.o -MF dep/Serial_to_terminal_test.o.d  -c  ../Serial_to_terminal_test.cpp
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
../Serial_to_terminal_test.cpp: In function 'void loop()':
../Serial_to_terminal_test.cpp:28: error: 'PSTR' was not declared in this scope
../Serial_to_terminal_test.cpp:28: error: 'memcpy__P' was not declared in this scope
make: *** [Serial_to_terminal_test.o] Error 1
Build failed with 2 errors and 1 warnings...
char send_buffer[] = {1, 2, 3};

will not display “123” in hyperterminal. It displays the character code, which are non printing characters for 1 2 and 3, and a left brace “{” for:

char send_buffer[] = {123};

If you use

char send_buffer[] = {'1','2','3'};

then it should display “123”, as single quotes denote an encoded character, such that ‘1’ actually equals 49 in decimal.

I would also suggest using Br@y’s Terminal instead of hyperterminal. It’s designed for this type of work, and is much better in my opition. You can find it here: https://sites.google.com/site/terminalbpp/ It can also display binary, decimal, and hexadecimal in addition to encoded character output.

Hello, Tyler.

It sounds like you don’t understand how to send numbers over a serial connection. When you are using a typical terminal program such as hyper terminal, every byte received is interpreted as an ASCII character. To find the correspondence between bytes (0-255) and ASCII characters, just search Google for “ASCII code” or take a look at the chart at http://www.asciitable.com/. This will help you understand what’s going on.

What you need to do is convert your number into a string of bytes representing ASCII characters. Some characters will represent digits of your number, and other characters will be separators to make the numbers easier to read. The easiest way to do this is to use sprintf. Please try the following code. I didn’t compile it myself but I expect it to work:

#include <pololu/orangutan>
#include <stdio.h>

char send_buffer[80]; 

int a = 1, b = 44;

void setup()
{
    OrangutanSerial::setBaudRate(9600); 
}

void loop()
{
    OrangutanSerial::sendBlocking(send_buffer, sprintf(send_buffer, "a=%d b=%d\r\n", a, b));
    OrangutanTime::delayMilliseconds(1000);
}

int main()
{
    setup();
    while(1)
    {
        loop();
    }
}

–David

Cool, thanks to you both; it looks like I got it working. :sunglasses: I’ll check out Br@y’s terminal. Thanks for the fsprint tip, I did not know about that.

Regarding fsprint, I got a warning if I tried to use an “unsigned long”. The warning said it was expecting “int”. Can fsprint only be used with int? How would you use fsprint with a combination of variables like unsigned long and int?

You should use %lu or %ld for long variables. For more information, please see the avr-libc documentation of stdio.h:

nongnu.org/avr-libc/user-man … stdio.html

In the future, please tell us the exact error message rather than paraphrasing it because that is more useful.

–David