Orangutan SVP-1284 and Ping)))

I’m trying to get my ping)) sensor to work with my Orangutan SVP-1284. I am a Java developer but all this microcontroller stuff is new to me. I really don’t have much of an idea what I am doing and may be going in the wrong direction entirely

Here is the code I am trying to use:

#include <pololu/orangutan.h>

    int main()
    {
        while (1)  // main loop
        {
	   	    clear();
		 
	   	    delay_ms(1000);
		    print("Signalling Ping)))");
	   	    set_digital_output(IO_C0, LOW);
		    set_digital_output(IO_C0, HIGH);
		    set_digital_output(IO_C0, LOW);

		    set_digital_input(IO_C0, HIGH_IMPEDANCE);

            if(is_digital_input_high(IO_C0))     // Take digital reading of PC0.  
            {  
	           clear();
		       print("ping input found");
			   //code to measure length of response pulse will go here once this works
			   delay_ms(500);
            }  
		    else
		    {
               clear();
		       print("input not found");
		       delay_ms(500);
		    }

       }
    }

I just end up with “input not found” even though i see the sensor’s LED flashing. Any help would be greatly appreciated

OK, I got it working (kind of) using the following code:

[code] #include <pololu/orangutan.h>

int main()
{

	unsigned long x = 0;
    while (1)  // main loop
    {
   	    clear();
		print("distances: ");
	 	print_long(x);
        delay_ms(1000);
	    
   	    set_digital_output(IO_C0, LOW);
	    set_digital_output(IO_C0, HIGH);
	    set_digital_output(IO_C0, LOW);

	    set_digital_input(IO_C0, HIGH_IMPEDANCE);


		int startOfSignalFound = 0;
		int endOfSignalFound = 0;
		while (!startOfSignalFound)
        {
           if(is_digital_input_high(IO_C0))
       	   {  
		      time_reset();
			  startOfSignalFound = 1;
              clear();
	          print("ping input found");
		     
		      while (!endOfSignalFound) {
			  
              if(!is_digital_input_high(IO_C0)) {
			  endOfSignalFound = 1;
			  x = get_ms();
			  }
			  
			  
			  }
		   
            }  
        }

   }
}[/code]

apologies for the formatting, I swear it looks fine in the editor. Anyway, this only returns me 3 or 4 different values. It doesn’t look like you can use the pololu library to get microseconds? I’m guessing there is a better way to do this.

Hello.

There are a few ways to time your pulse with better resolution. One is to use the delay_us() function as follows:

unsigned int x = 0;  // using x to store pulse length in units of microseconds, not milliseconds
while (is_digital_input_high(IO_C0)) {
  delay_us(10);  // delay 10 us
  x += 10;
}

The reason I’m delaying for 10 us instead of 1 us is that the rest of the loop takes time to execute, and that time could be close to 1 us by itself. I’m trying to pick a time to delay for that is large compared to the overhead of the loop (so that the accuracy of x will be within 10% or so) but that is still small enough to give you a high-resolution pulse reading. This is a pretty simple solution, but it is also somewhat crude.

A much better way to measure your pulse duration is to use one of the hardware timers, though two of the three hardware timers are also used by Pololu AVR library functions, so you need to be careful when doing this. David is making a post right now that gives an example of how to use a hardware timer to time your pulse along with some additional information about using timers on the Orangutan SVP.

- Ben

According to the PING))) documentation under the Resources tab, the input pulse must be at least 2 microseconds but typically should be 5 microseconds. The ATmega1284p on the SVP-1284 runs at 20MHz, so when you call set_digital_output back-to-back your pulse will most likely not be long enough to have an effect. You should insert a delay using delay_us(), like this:

set_digital_output(IO_C0, LOW);
delay_us(10);
set_digital_output(IO_C0, HIGH);
delay_us(5);
set_digital_output(IO_C0, LOW);
delay_us(10);
set_digital_input(IO_C0, HIGH_IMPEDANCE);

Also, I don’t recommend printing to the LCD during this operation because printing can be relatively slow and might mess up your timing; it might be okay, but without actually timing it we can’t be sure. You can use the user LEDs to get feedback.

Getting accurate timing is going to be harder because it will involve writing code to use a hardware timer on the AVR (unless you use Ben’s method). The AVR has three timers, named Timer 0, Timer 1, and Timer 2. You can read all about the them in the datasheet for the ATmega1284p.

Timer 0 is not used by the AVR library on the SVP (but it is used by OrangutanMotors on other Orangutans), so your code can do whatever it wants to Timer 0 without messing up the library.

Timer 1 is used by OrangutanServos, OrangutanBuzzer, and OrangutanPulseIn. If you aren’t using those sections of the library, you can do whatever you want to Timer 1.

Timer 2 is used by OrangutanTime, OrangutanMotors, and PololuQTRSensors, so you probably don’t want to change its configuration. However, you can write a program that reads the value of Timer 2 repeatedly and uses that information to measure time spans accurately. I recommend this method because it will leave Timer 0 and Timer 1 free for later use, and we already have example code for it. The code in PololuQTRSensors.cpp in readPrivate() shows you how to measure time spans with Timer 2, and I’ve put the important parts of that code here:

unsigned int time = 0;
unsigned char last_time;
unsigned char delta_time;
TCCR2A |= 0x03;
TCCR2B = 0x02;		// run timer2 in normal mode at 2.5 MHz (compatible with OrangutanMotors)
last_time = TCNT2;
while(1)
{
	// Keep track of the total time.
	// This implicitly casts the difference to unsigned char, so
	// we don't add negative values.
	delta_time = TCNT2 - last_time;
	time += delta_time;
	last_time += delta_time;

	if(pulseIsDone()) // insert your own condition here
	{
		break;
	}

	if (time > 55000) // maximum PING))) pulse time should be 18.5 ms (e.g. 46250 ticks)
	{
		break;
	}
}

After the loop runs, the variable “time” should contain a measurement of how long the pulse lasted, in units of Timer 2 ticks (0.4 microseconds). I haven’t compiled or tested this code, so there may be some problems, but it was copied from PololuQTRSensors.cpp which definitely works.

-David

I really appreciate the help guys. I was with you until I started seeing stuff like this:

TCCR2A |= 0x03;
TCCR2B = 0x02;      // run timer2 in normal mode at 2.5 MHz (compatible with OrangutanMotors)
last_time = TCNT2;

I don’t have a clue what is going on here. I could not find any info about it in anything linked to on this site. Is there a good source you can point me to?

Hi,

The ATmega1284p data sheet explains the registers:

I found the link on this Pololu web page:

Hope this helps,
Mike