Parallax Ping))) untrasonic sensor porblems with ioio V1 board

250 views
Skip to first unread message

Vic Wintriss

unread,
Apr 13, 2014, 10:22:39 PM4/13/14
to ioio-...@googlegroups.com
I am trying to use the Parallax Ping))) ultrasonic sensor with a ioio V1 board, using the IOIO00503 library.  I get a good looking signal...see the attached scope view, but the input.getDuration() call returns 16.8 micro seconds most of the time, called 2 times per second.  Every once in a while I get the proper number. 

 Any ideas? Here is the code:

import ioio.lib.api.DigitalOutput;

import ioio.lib.api.IOIO;

import ioio.lib.api.PulseInput;

import ioio.lib.api.PulseInput.PulseMode;

import ioio.lib.api.exception.ConnectionLostException;


public class UltraSonicSensors 

{

private static final int LEFT_ULTRASONIC_INPUT_PIN = 35;

private static final int LEFT_STROBE_ULTRASONIC_OUTPUT_PIN = 15;

private final PulseInput leftInput;

private DigitalOutput leftStrobe;

private float leftDistance;

private IOIO ioio;


public UltraSonicSensors(IOIO ioio) throws ConnectionLostException 

{

this.leftInput = ioio.openPulseInput(LEFT_ULTRASONIC_INPUT_PIN, PulseMode.POSITIVE);

this.leftStrobe = ioio.openDigitalOutput(LEFT_STROBE_ULTRASONIC_OUTPUT_PIN);

this.ioio = ioio;

}


public void read() throws ConnectionLostException, InterruptedException 

{

read(leftStrobe, leftInput);

}


private void read(DigitalOutput strobe, PulseInput input) throws ConnectionLostException, InterruptedException 

{

ioio.beginBatch();

strobe.write(true);

strobe.write(false);

ioio.endBatch();

this.leftDistance =  input.getDuration();

}


public float getLeftDistance() 

{

return leftDistance;

}

}

TEK0000.JPG

Ytai Ben-Tsvi

unread,
Apr 14, 2014, 2:30:10 PM4/14/14
to ioio-...@googlegroups.com
getDuration() would return you whatever last pulse width was measured last.
What you want is to add a ioio_.sync() followed by input.getDurationSync(), which will guarantee that the pulse has been obtained after the strobe.
However, looking at this now, there's a small chance that you'll miss the pulse this way. Ideally, the sync() call would have its "send" half inside the batch and "wait" half outside. Unfortunately, this is not currently possible (although easy enough to add if you need to).


--
You received this message because you are subscribed to the Google Groups "ioio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ioio-users+...@googlegroups.com.
To post to this group, send email to ioio-...@googlegroups.com.
Visit this group at http://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.

Vic Wintriss

unread,
Apr 15, 2014, 7:03:36 PM4/15/14
to ioio-...@googlegroups.com
Thanks for the ideas. I've tried many combinations of synch, readBuffered...etc, but unfortunately it still reads very small numbers...probably measuring the last part of the trigger pulse. Is there any way that I can delay the read by a couple of hundred micro seconds?  Could you do the..... sync() call  "send" half inside the batch and "wait" half outside thing?

Thanks for all the help.  The kids are trying to use these sensors for iARoC 2014 (the International Autonomous Robot Competition) here in San Diego.

Ytai Ben-Tsvi

unread,
Apr 15, 2014, 7:27:19 PM4/15/14
to ioio-...@googlegroups.com

Can you send me the most "correct" version of your code that demonstrates the issue?
I can probably make the necessary changes to sync () if this is indeed a problem.

On Apr 15, 2014 4:03 PM, "Vic Wintriss" <g...@san.rr.com> wrote:
Thanks for the ideas. I've tried many combinations of synch, readBuffered...etc, but unfortunately it still reads very small numbers...probably measuring the last part of the trigger pulse. Is there any way that I can delay the read by a couple of hundred micro seconds?  Could you do the..... sync() call  "send" half inside the batch and "wait" half outside thing?

Thanks for all the help.  The kids are trying to use these sensors for iARoC 2014 (the International Autonomous Robot Competition) here in San Diego.

--

Vic Wintriss

unread,
Apr 15, 2014, 7:43:08 PM4/15/14
to ioio-...@googlegroups.com
Ytai:

This code produces only 1.6875E-5…reading 2 times per second.

import ioio.lib.api.DigitalOutput;
import ioio.lib.api.IOIO;
import ioio.lib.api.PulseInput;
import ioio.lib.api.PulseInput.PulseMode;
import ioio.lib.api.exception.ConnectionLostException;

public class UltraSonicSensors 
{
private static final int LEFT_ULTRASONIC_INPUT_PIN = 35;
private static final int LEFT_STROBE_ULTRASONIC_OUTPUT_PIN = 15;
private final PulseInput leftInput;
private DigitalOutput leftStrobe;
private float leftDistance;
private IOIO ioio;
public UltraSonicSensors(IOIO ioio) throws ConnectionLostException 
{
this.leftInput = ioio.openPulseInput(LEFT_ULTRASONIC_INPUT_PIN, PulseMode.POSITIVE);
this.leftStrobe = ioio.openDigitalOutput(LEFT_STROBE_ULTRASONIC_OUTPUT_PIN);
this.ioio = ioio;
}

public void read() throws ConnectionLostException, InterruptedException 
{
read(leftStrobe, leftInput);
}

private void read(DigitalOutput strobe, PulseInput input) throws ConnectionLostException, InterruptedException 
{
ioio.beginBatch();
strobe.write(true);
strobe.write(false);
ioio.endBatch();
this.leftDistance =  input.getDurationSync();
}

public float getLeftDistance() 
{
return leftDistance;
}
}
You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+...@googlegroups.com.

Ytai Ben-Tsvi

unread,
Apr 15, 2014, 8:32:01 PM4/15/14
to ioio-...@googlegroups.com

This code doesn't have the sync() call I proposed. It should come after the batch.

Vic Wintriss

unread,
Apr 15, 2014, 10:00:37 PM4/15/14
to ioio-...@googlegroups.com
Ytai:

With the sync() call after the endBatch() and before the getDuration() the program hangs up and I get no readings.

Vic

Ytai Ben-Tsvi

unread,
Apr 16, 2014, 12:41:52 AM4/16/14
to ioio-...@googlegroups.com
Yes, that's what I meant when I said that you may miss the actual pulse.

What about the following approach:
beginBatch();
sendPulse();
endBatch();
while (true) {
  float duration = pulseIn.GetDurationBuffered();
  if (duration > MIN_DURATION) return duration;
}

Of course, you can timeout if you want.
With this approach, every pulse is captured and considered, and you're filtering out the really short ones that indicate the input pulses.

BTW, there are equivalent ultrasonic range finders that have a more pleasant interface (for example, analog, or similar to the one you have but the feedback is on a separate pin). Here's one (available on DX for <$5):

Vic Wintriss

unread,
Apr 16, 2014, 6:18:00 PM4/16/14
to ioio-...@googlegroups.com
It’s not too important that we get every pulse.
I tried the following code, but still get all zeroes:
public class UltraSonicSensors 
{
private static final int LEFT_ULTRASONIC_INPUT_PIN = 35;
private static final int LEFT_STROBE_ULTRASONIC_OUTPUT_PIN = 15;
private final PulseInput leftInput;
private DigitalOutput leftStrobe;
private float leftDistance;
private IOIO ioio;


public UltraSonicSensors(IOIO ioio) throws ConnectionLostException 
{
this.leftInput = ioio.openPulseInput(LEFT_ULTRASONIC_INPUT_PIN, PulseMode.POSITIVE);
this.leftStrobe = ioio.openDigitalOutput(LEFT_STROBE_ULTRASONIC_OUTPUT_PIN);
this.ioio = ioio;
}

public void read() throws ConnectionLostException, InterruptedException 
{
read(leftStrobe, leftInput);
}

private void read(DigitalOutput strobe, PulseInput input) throws ConnectionLostException, InterruptedException 
{
ioio.beginBatch();
strobe.write(true);
strobe.write(false);
ioio.endBatch();
while (true
{
  float leftDistance = leftInput.getDurationBuffered();
  if (leftDistance > .0000001)
  {
  break;
  }
}
}

public float getLeftDistance() 
{
return leftDistance;
}
}
What should I try next?
Thanks for the lead to the 4-pin sensors.  I have ordered some…but since a lot of the kids already have the 3-pin versions, I’m stuck with having to make that work, too.
I use use a pretty simple circuit to separate the input from the output…attached.

Thanks for all the great help.
Image041714031902.pdf

Ytai Ben-Tsvi

unread,
Apr 16, 2014, 7:50:22 PM4/16/14
to ioio-...@googlegroups.com

Your local leftDistance variable is shadowing the class field...

Vic Wintriss

unread,
Apr 17, 2014, 4:15:51 PM4/17/14
to ioio-...@googlegroups.com
Sorry about the Java error…very embarrassing!
Corrected the code, but still returns mostly zeroes.  Tried this, but stalls after a read or two…don’t know why:

public void read() throws ConnectionLostException, InterruptedException, IncompatibilityException 
{
ioio.beginBatch();
leftStrobe.write(true);
leftStrobe.write(false);
leftInput = ioio.openPulseInput(LEFT_ULTRASONIC_INPUT_PIN, PulseMode.POSITIVE);
ioio.waitForConnect();
leftDistance = leftInput.getDuration();
leftInput.close();
ioio.endBatch();

Ytai Ben-Tsvi

unread,
Apr 17, 2014, 9:54:18 PM4/17/14
to ioio-...@googlegroups.com
What's with the waitForConnect()? And why are you closing the pins?
The approach you took before is OK. Why did you change it? I think the fact that you set the threshold to 0.1us is a problem. You should set it to whatever you think is the minimum pulse width you're ever going to get.
Also, I'd have this function simply return the result as opposed to set a field.

Vic Wintriss

unread,
Apr 17, 2014, 11:01:05 PM4/17/14
to ioio-...@googlegroups.com
My theory was that the getDuration() call was coming too quickly and actually reading the end of the trigger pulse. I thought that by delaying the getDuration() a bit (or not opening it until the trigger pulse was finished) I could avoid that.  Does that hypothesis sound likely to you?

Setting a threshold makes me miss a lot of readings.  When the robot is moving fast, I need as many valid readings as possible.

Ytai Ben-Tsvi

unread,
Apr 18, 2014, 10:56:24 AM4/18/14
to ioio-...@googlegroups.com
Your explanation of what's happening is correct. Your solution may work if you get rid of the ioio.waitForConnect() and move the endBatch to where it used to be.

However, I don't understand why you're saying that you'll be missing readings with the approach I proposed. You're only discarding pulses which are not legitimate readings and the getDurationBuffered() method is supposed to give you every pulse.

Vic Wintriss

unread,
Apr 18, 2014, 11:33:43 AM4/18/14
to ioio-...@googlegroups.com
OK...understood...I'll try it again. 

Vic Wintriss

unread,
Apr 21, 2014, 6:23:13 PM4/21/14
to ioio-...@googlegroups.com
I don't think that I can use getDurationBuffered() in this case. The getDuration() Interface notes say: "...Note that once a pulse is detected, the next one must have its leading edge at least 5ms after the leading edge of the current one, or else it will be skipped."  The ping pulse is about 50 microsecs long, and the echo pulse comes about 750 microsecs after the ping pulse,  If I am getting the last part of the ping pulse, the echo pulse will come too soon for getDurationBuffered() to acquire the echo pulse.  Am I understanding this right?

Ytai Ben-Tsvi

unread,
Apr 21, 2014, 8:12:27 PM4/21/14
to ioio-...@googlegroups.com
Good catch, I forgot about this constraint.
In that case, this (similar to what you've proposed) approach might work:

beginBatch();
generatePulse();
openPulseIn();
endBatch();
getDuration();
closePulseIn();

I'd like to emphasize that the fact we have to jump through weird hoops to get is working is mostly due to the fact that this sensor has a weird interface. BTW, another thing you can do is use a discrete logic gate to filter out the ping input pulse from the output. Something like:
clean_out = ping_pin & !ioio_pulse_out_pin

This will convert the Ping's interface to be similar to the one of the other sensor I referred you to.



--

Vic Wintriss

unread,
Apr 21, 2014, 11:36:44 PM4/21/14
to ioio-...@googlegroups.com
Good idea about the logic fix.  I’m redoing the interface boards, so I might add that logic.
If I am, in fact, reading part of the trigger pulse, is there any way of imposing a short, predictable delay…say 50 microsecs…after the trigger pulse but before the getDuration() read?

You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+...@googlegroups.com.

Ytai Ben-Tsvi

unread,
Apr 22, 2014, 8:05:23 PM4/22/14
to ioio-...@googlegroups.com
No, there isn't, and even if there were, I'm not sure this will actually do what you want.
Have you tried the hack I recommended on the previous post?

Vic Wintriss

unread,
Apr 23, 2014, 1:10:05 AM4/23/14
to ioio-...@googlegroups.com
I tried the following:

public void read() throws ConnectionLostException, InterruptedException {

ioio.beginBatch();

leftStrobe.write(false);

leftStrobe.write(true);

leftStrobe.write(false);

  leftInput = ioio.openPulseInput(LEFT_ULTRASONIC_INPUT_PIN,

PulseMode.POSITIVE);

  ioio.endBatch();

leftDistance = (int) (leftInput.getDurationBuffered() * 1000000);

leftInput.close();

SystemClock.sleep(100);

dashboard.log(leftDistance + "");

}

It makes one reading and then hangs up.  How do I time out if I want stop waiting?
I put the scope on the sensor and discovered that I am reading alternately both the trigger pulse and the echo pulse...most often the trigger pulse.

Ytai Ben-Tsvi

unread,
Apr 23, 2014, 11:51:26 AM4/23/14
to ioio-...@googlegroups.com
Are you using the latest firmware?
Also, cancellation is supported. Search the forum for TimerTask.

Vic Wintriss

unread,
Apr 23, 2014, 5:33:34 PM4/23/14
to ioio-...@googlegroups.com
I'm using 0503.

The problem is that the ping and the return are getting out of sync.  The getDuration() readings match exactly the times that I see on the scope.
How can I synchronize so that I only start listening after the ping pulse is complete?

Ytai Ben-Tsvi

unread,
Apr 23, 2014, 11:44:02 PM4/23/14
to ioio-...@googlegroups.com
Opening the pulse input after sending the pulse should have done that. You shouldn't be able to get a pulse from the past the way you're doing this. Are you saying that what you're reading back is the output pulse?
It is possible that there's a bug in the firmware side on the PulseInput implementation in that case.

Vic Wintriss

unread,
Apr 24, 2014, 12:15:02 AM4/24/14
to ioio-...@googlegroups.com
I have tried all combinations of opening pulse input after sending the trigger pulse...no luck.  I am reading both the output (trigger pulse) and the echo (return) pulse...alternately.  About 5 trigger pulse readings to each echo pulse reading.  Any work around ideas?

Ytai Ben-Tsvi

unread,
Apr 24, 2014, 12:21:54 AM4/24/14
to ioio-...@googlegroups.com
Nope. The PulseInput module was really not designed for such a use-case. If you had only the output pulses on the input things would "just work". Try the AND gate trick.

Vic Wintriss

unread,
Apr 25, 2014, 6:09:57 PM4/25/14
to ioio-...@googlegroups.com
Could you give me a simple example of how to interrupt getDuration(). I checked the TimerTask forum, but am not sure that I understand. I assume that getDuration() is blocking.

Ytai Ben-Tsvi

unread,
Apr 25, 2014, 7:40:07 PM4/25/14
to ioio-...@googlegroups.com

Vic Wintriss

unread,
Apr 26, 2014, 12:50:00 AM4/26/14
to ioio-...@googlegroups.com
I am just trying to put out a pulse on one pin and then read a  pulse width on a different pin 750 microsecs later. Why do you say that it was not designed for such a use?


On Wednesday, April 23, 2014 9:21:54 PM UTC-7, Ytai wrote:

Ytai Ben-Tsvi

unread,
Apr 26, 2014, 7:04:51 PM4/26/14
to ioio-...@googlegroups.com
PulseInput is primarily designed for:
  1. Measuring rate or pulse-width of a pulse train signal, where it is not necessarily important to get a result for each and every pulse. This is useful, for example, to measure speed of a wheel or to decode a servo signal.
  2. Measuring width of individual pulses that occur relatively sporadically, like outputs from ultrasonics.
In your case, we have two kinds of pulses (in/out) on the same line in close proximity, and you're trying to extract one but not the other. Not that there is anything particularly hard to implement such a feature, only that it is not generic enough to be addressed in the standard interfaces that I've developed.

Duane DeSieno

unread,
Apr 26, 2014, 7:08:15 PM4/26/14
to ioio-...@googlegroups.com
I work with Vic and I have followed this thread.
I have tried many of the suggestions you have made.
The primary result I see is that the getDuration call hangs.

For background, Earlier version of the IOIO software had worked quite well.
I ran it many times and was able to use the getDuration result with a calibrated constant to get readings in mm using the PING transducer.

The I have seen the signals on my scope and the frustration is that my code used to work well.

Hope you can help.

Duane

Vic Wintriss

unread,
Apr 26, 2014, 7:20:06 PM4/26/14
to ioio-...@googlegroups.com
The output pulse and input pulse are not on the same pin.  I assume by line you meant pin.  Output is on one pin and input is on another pin.

Ytai Ben-Tsvi

unread,
Apr 26, 2014, 7:23:51 PM4/26/14
to ioio-...@googlegroups.com
@Duane
At this point I'm convinced that there is no reason why this should work. If it used to work in the past it is probably coincidental and you can of course downgrade if you prefer.
I'm not going to spend any time supporting one specific sensor that has a weird interface. You have several viable options for solving your problem:
  • Use a different sensor as recommended above.
  • Filter out the trigger pulse using simple discrete logic as recommended above.
  • Change the firmware to support your use-case, for example, to filter out pulses shorter than a certain limit or even having a dedicated PING interface that can do both the output and input.
@Vic
While you're generating the output with one pin and reading the input with another, the latter pin is being exposed to both signals.

Vic Wintriss

unread,
Apr 26, 2014, 7:47:12 PM4/26/14
to ioio-...@googlegroups.com

Can I close the input while I am doing the strobe so that the input is not being exposed to both pulses?

Ytai Ben-Tsvi

unread,
Apr 26, 2014, 7:57:52 PM4/26/14
to ioio-...@googlegroups.com

Yes. This is what we tried before. I'm still under the impression that it should have worked but you've reported that it doesn't.

Vic Wintriss

unread,
Apr 26, 2014, 8:02:00 PM4/26/14
to ioio-...@googlegroups.com
It doesn't work when I close and then reopen the input line.  Can you recommend some tests that I can do to try and find out why it doesn't work?

Ytai Ben-Tsvi

unread,
Apr 26, 2014, 11:06:53 PM4/26/14
to ioio-...@googlegroups.com
OK. I think I know why it isn't working. The way the input capture (PulseInput) works in the firmware is that a 200Hz (=5ms) timer kicks off the captures. I've done this in order to throttle the rate of pulse reports. So when you open a pulse input, it can take up to 5ms before it triggers a conversion.
From looking at the ping datasheet, it is not clear whether the operation is triggered by the rising edge or the falling edge or your pulse. If it is the falling edge, you should be able to do something like:

triggerHigh();
in = openPulseInput();
sleep(20ms);  // wait until the pulse input module is ready for a pulse.
triggerLow();  // kick off a measurement (falling edge does not trigger the pulse input)
duration = in.getDuration();
in.close();
return duration;

Vic Wintriss

unread,
Apr 27, 2014, 12:04:41 AM4/27/14
to ioio-...@googlegroups.com
Thanks so much for the analaysis...I'll try it tomorrow and let you know...sounds like it might work!

Duane DeSieno

unread,
Apr 27, 2014, 1:57:09 PM4/27/14
to ioio-...@googlegroups.com
My confusion is maybe over the way getDuration works. 
Does it delay 5ms before looking for the pulse or does it look immediately?
I put 555 timer on the input pin and set it up for 3.15hz and 25.4% duty cycle or an 80.6ms pulse every 317.4ms.
I called getDuration roughly every 100ms.  It did not block and returned the same value several times before the next pulse occurred(not what I expected).

Looked at the Arduino approach to using the PING and they use just one pin, changing from output after sending a pulse to ping to an input for their get duration call.
Since they don't impose a 5ms delay, they get the duration of the return pulse.

Thanks for you help on this.

Duane




Ytai Ben-Tsvi

unread,
Apr 27, 2014, 2:36:53 PM4/27/14
to ioio-...@googlegroups.com
Let me shed some light on the internals of PulseInput:
  • A timer is running on the IOIO set to 200Hz (5ms).
  • As soon as the pulse input module is opened, and every time after a pulse is captured the module will be put in the "ready" state.
  • Every time the 200Hz timer triggers, each "ready" module will be activated, i.e. put in a state where it is waiting for a new pulse.
  • Once activated, the module will wait forever (or until closed) for a pulse, then measure its duration, then sends the result to the Android.
  • So this means that effectively no matter what the actual pulse rate is, you will never get more than 200 reports per second. This has been done on purpose to prevent a high frequency pulse train from saturating the connection between the IOIO and the Android. This also means that there is a potential "dead time" of up to 5ms after opening or between pulses, during which a pulse would not be detected.
  • On the Android side, every pulse report finds its way to your PulseInput object. You can then read it in one of three ways:
    • getDuration() will return the last report. It will generally not block, then only exception is until the first report arrives.
    • getDurationSync() will always block until a new report comes in, then return it. So you can be sure that the report is new.
    • getDurationBuffered() pulls pulses one by one from a queue. When the queue becomes empty it behave like getDurationSync(), i.e. waits until a new report comes in.
The Arduino approach cannot be directly applied to the IOIO API, since you have to take into account that because of the communication between the Android and the IOIO, much of the IOIO API has been designed to be asynchronous in nature. If you were to bake the PING driver directly into the IOIO firmware, you can use a similar approach to Arduino's (although you'd probably want to implement it in a non-blocking way, since the IOIO allows everything to be used concurrently). The reason why I have not done that is because I tried to focus on generic use-cases rather than on one peculiar sensor interface.



Vic Wintriss

unread,
Apr 27, 2014, 11:19:55 PM4/27/14
to ioio-...@googlegroups.com
I finally got it to work using your last suggestion.  This code works that you recommended works perfectly.  Thanks so much for sticking with us.  We've got 30 or 40 kids using this code at the International Autonomous Robot Competition (iARoC 2014) coming up at the end of June.  Check out iaroc.org.

triggerHigh();
in = openPulseInput();
sleep(20ms);  // wait until the pulse input module is ready for a pulse.
triggerLow();  // kick off a measurement (falling edge does not trigger the pulse input)
duration = in.getDuration();
in.close();
return duration;

Ytai Ben-Tsvi

unread,
Apr 27, 2014, 11:24:19 PM4/27/14
to ioio-...@googlegroups.com
Cool. If you can create a nice class for using the PING (where the ctor gets a IOIO and two pin numbers, and there's a getDistance() method) and share it on this forum, it would be a decent return for our efforts :) As a side note, since you're doing the open-close trick, you might as well use a single pin and open-close the digital output as well and not need the driver chip, so you can even further simplify both your code and your circuit.

Duane DeSieno

unread,
Apr 29, 2014, 5:53:07 PM4/29/14
to ioio-...@googlegroups.com
I encountered a small problem. 
In the case of a hardware or wiring problem with the PING, this code that works will hang at the getDuration call. 
Also, I noticed that a 20ms sleep works and a 10ms sleep does not with working hardware.

So my question is, can you give us a way to limit the time for the getDuration().
For example we know that the ping is only good to about 3 meters or 17.74ms.
If we had a call like getDuration(msLimit), we could make the call getDuration(20) and know that it will return after 20ms.

I had an intermittent power lead to the PING and my whole robot stopped.

Thanks
Duane

Ytai Ben-Tsvi

unread,
Apr 29, 2014, 7:07:08 PM4/29/14
to ioio-...@googlegroups.com

Earlier on this thread I answered this question. Essentially you can have a second thread interrupt the blocked thread to unblock it. A TimerTask is a convenient way to achieve this. You can wrap the whole process in a method that would look pretty much like the interface you purposed.

v...@wintrisstech.org

unread,
Apr 30, 2014, 1:25:27 PM4/30/14
to ioio-...@googlegroups.com
I'll clean up the class and post it.  Hope other people can use it.  Works very solidly with the Parallax Ping))) ultrasonic module.
Great suggestion to use only one pin for both input and output.  It would even have saved me a part on the pc boards.


On Sunday, April 27, 2014 8:24:19 PM UTC-7, Ytai wrote:

v...@wintrisstech.org

unread,
May 16, 2014, 12:25:28 AM5/16/14
to ioio-...@googlegroups.com
Here is some code that works great with the Parallax Ping))) with the circuit in the file attached (thanks to Ytai):

private int read(DigitalOutput strobe, PulseInput input, int inputPin) throws ConnectionLostException, InterruptedException // Order of following statements is very important...do not change
{
int distance = 0;
ioio.beginBatch();
strobe.write(true);
input = ioio.openPulseInput(inputPin, PulseMode.POSITIVE);
ioio.endBatch();
SystemClock.sleep(40);
strobe.write(false);
distance += (int) (input.getDuration() * CONVERSION_FACTOR);
input.close();
return distance;
}
PingCircuit.psd

Ytai Ben-Tsvi

unread,
May 16, 2014, 1:03:20 PM5/16/14
to ioio-...@googlegroups.com
Thanks for sharing!

Daniel Brown

unread,
Apr 10, 2015, 8:59:52 PM4/10/15
to ioio-...@googlegroups.com
We have a project that uses 6 distance finders,  when we try to call .getDuration() on more then one all further reading freezes.

protected void setup() throws ConnectionLostException {

// front left pulse and echo 
echoPinfl_ = ioio_.openPulseInput(6, PulseMode.POSITIVE); 
triggerPinfl_ = ioio_.openDigitalOutput(7);
// front middle pulse and echo 
echoPinfm_ = ioio_.openPulseInput(2, PulseMode.POSITIVE);
triggerPinfm_ = ioio_.openDigitalOutput(4);

...

public void loop() throws ConnectionLostException, InterruptedException {
// updates front left sensor
try{
triggerPinfl_.write(false);
Thread.sleep(5);
triggerPinfl_.write(true);
Thread.sleep(1);
triggerPinfl_.write(false);
echosecondsfl_ = (int)(echoPinfl_.getDuration() * 1000 * 1000);
echoDistanceCmfl_ = echosecondsfl_ / 29 / 2;
}catch (ConnectionLostException e) { throw e;}
// updates front middle sensor
try{
triggerPinfm_.write(false);
Thread.sleep(5);
triggerPinfm_.write(true);
Thread.sleep(1);
triggerPinfm_.write(false);
// echosecondsfm_ = (int)(echoPinfm_.getDuration() * 1000 * 1000);  //if this line is commented in all further input stops
// echoDistanceCmfm_ = echosecondsfm_ / 29 / 2;
}catch (ConnectionLostException e) { throw e;}

...

Ytai Ben-Tsvi

unread,
Apr 10, 2015, 9:26:48 PM4/10/15
to ioio-...@googlegroups.com
Vic posted some code earlier on this thread that is claimed to work and looks pretty nice. Why are you not using that?

Daniel Brown

unread,
Apr 22, 2015, 5:42:01 PM4/22/15
to ioio-...@googlegroups.com
if one PulseInput pin is open or has not received a pulse and you call getDuration() it will block you from reading all other PulseInput pins until it has received at least one pulse. We have found that one bad sensor will stop you from reading any other sensor.

Ytai Ben-Tsvi

unread,
Apr 24, 2015, 12:43:50 AM4/24/15
to ioio-...@googlegroups.com
You can add a TimerTask to interrupt the thread after some timeout. Search the forum for examples if you need them. If you don't want to delay all the other 5 if one is stuck you can easily run 6 sensors on 6 different threads.

vic.wi...@jointheleague.org

unread,
Apr 2, 2016, 12:38:03 AM4/2/16
to ioio-users
It's a new iARoC (International Autonomous Robot Competition) year (2016) and we are back to the ultrasonic sensor problem.  This year I am using the 4-pin version.  The following code works:

public void readRight() throws ConnectionLostException, InterruptedException
{//This code works with the 4-pin sensor...don't change anything!
   
rightStrobe.write(true);
   
SystemClock.sleep(10);
   
rightStrobe.write(false);
   
rightDistance = (int) (rightInput.getDuration() * CONVERSION_FACTOR);
}


But it will not work with less than a 10 ms long trigger pulse.  I don't understand this, because the ultrasonic sensor spec says that the trigger pulse should be around 10 micro sec.  Do you have any idea why I need such a long trigger pulse.  I verified the waveforms with a scope.  It seems to be the case with both the 4-pin and the 3-pin version.

Ytai Ben-Tsvi

unread,
Apr 2, 2016, 12:55:17 AM4/2/16
to ioio-...@googlegroups.com

When you look at the waveforms, what do you see as the output pulse? My guess would be that it is very narrow, in the order of a couple of usec perhaps, and if that's indeed the case, it is likely because both messages comprising the pulse got collapsed into the same packet over one of the slower connections such as Bluetooth. In short, trying to achieve precise timing of any sort at this time scale is a bad idea. It would be possible to add a one-shot feature to the IOIO to achieve that. If you want this reading periodically, consider using a PwmOutput to keep triggering the sensor without your intervention at very precise pulse widths and period. Another option would be to use a version of those sensors that emits an analog voltage corresponding to the distance.

vic.wi...@jointheleague.org

unread,
Apr 4, 2016, 1:51:21 PM4/4/16
to ioio-users
The output pulse (echo pulse returning from the ultrasonic sensor) is correct...it is milli secs long and varies proportionately with the distance.  I am not using Bluetooth...the Android is directly connected to the ioio board.  It is the trigger pulse that must be long...more than 10 millisec...for the program to run.  It hangs up with smaller trigger pulses.  I can easily generate 10 microsec trigger pulses...as observed on scope...but then the program hangs up.  Ideas?

Ytai Ben-Tsvi

unread,
Apr 5, 2016, 12:25:36 AM4/5/16
to ioio-...@googlegroups.com
Sorry, I meant "output" from the IOIO's point of view.
Let me make sure I understand you correctly: are you claiming that you're emitting a shorter-than-10-ms trigger pulse, the pulse gets emitted correctly as verified by a scope, the echo pulse gets emitted correctly as verified by a scope, but your app is blocked on waitPulseGetDuration()? If that's the case, the only thing I can imagine is that the wait*() method is called after the pulse has already comes back.

Have you considered using PwmOutput as trigger, as per my suggestion? Then you can use getDuration() and never have to block. I think this is a rather elegant solution.

Vic Wintriss

unread,
Apr 11, 2016, 4:03:27 PM4/11/16
to ioio-users
When I use this code:
ioio.beginBatch();
rightStrobe.write(true);
rightStrobe.write(false);
ioio.endBatch();
I get this beautiful result:


But the code hangs up and I get no duration readings.

If I use this code:
rightStrobe.write(true);
SystemClock.sleep(10);
rightStrobe.write(false);
rightDistance = (int) (rightInput.getDuration() * CONVERSION_FACTOR);
 I get this awful situation, but it works. Anything less than a 10 millisec sleep fails.

Ytai Ben-Tsvi

unread,
Apr 11, 2016, 4:28:48 PM4/11/16
to ioio-...@googlegroups.com

I feel like I gave you my best advice, but you seem to insist on doing it in a way that's not supposed to work.

Vic Wintriss

unread,
Apr 12, 2016, 1:36:17 PM4/12/16
to ioio-users
I thought I was following your instructions.  I am using the 4-pin sensor as suggested and code that I thought was standard.  What did you tell me to do that I am not doing?

Ytai Ben-Tsvi

unread,
Apr 12, 2016, 1:37:52 PM4/12/16
to ioio-...@googlegroups.com

Use PWM output to generate periodic, precisely timed trigger pulses.

Vic Wintriss

unread,
Apr 12, 2016, 1:52:30 PM4/12/16
to ioio-users
I would rather run the ultrasonics asynchronously.  Also since the kids may not be be that advanced in our curriculum I prefer to stay away from threads.  The last code that I posted works fine.

Ytai Ben-Tsvi

unread,
Apr 12, 2016, 1:54:34 PM4/12/16
to ioio-...@googlegroups.com

No threads involved and nothing asynchronous. You set the PWM once during setup(), then you getDuration() whenever you please.

Vic Wintriss

unread,
Apr 12, 2016, 2:05:08 PM4/12/16
to ioio-users
I'll try it.  This will cause some interference with the other robots close by, but may not be a problem.

Vic Wintriss

unread,
Apr 12, 2016, 2:07:34 PM4/12/16
to ioio-users
How would you work the PWM with multiple sensors?


On Tuesday, April 12, 2016 at 10:54:34 AM UTC-7, Ytai wrote:

Ytai Ben-Tsvi

unread,
Apr 12, 2016, 5:57:09 PM4/12/16
to ioio-...@googlegroups.com

Good question. Currently the only way to ensure this level of sync is the motion control API. Alternatively, if your time constants are coarse enough, you can open multiple PWM channels running at slow rates and insert delays between the open command (order of 10's of ms as you have seen with your experiments). The ideal solution would have been a one-shot function, which is easy to implement using an output compare module, but this doesn't currently exist.

Vic Wintriss

unread,
Apr 12, 2016, 6:02:46 PM4/12/16
to ioio-...@googlegroups.com
Ytai:

Why can’t I use:

strobe.write(true);
strobe.write(false);
input.getDuration();

Vic


You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+...@googlegroups.com.

Ytai Ben-Tsvi

unread,
Apr 12, 2016, 6:09:22 PM4/12/16
to ioio-...@googlegroups.com

Because there's no guarantee hour long it would take between when your command executed on the Android and when the actual pin voltage changes. What you're seeing when having a short (or no) delay between the commands is that sometimes they would end up actually getting executed a very short gap between them.
Coming to think of it, if you only care about minimum duration, you can add a ioio.sync() call after starting the pulse and before starting the delay. This will guarantee that the delay begins after the pin has already been set. This will allow you to set a 1ms sleep without the pulse collapsing, but no guarantees on maximum width, it may come out wider than 1ms.

Vic Wintriss

unread,
Apr 12, 2016, 6:11:33 PM4/12/16
to ioio-...@googlegroups.com
OK…thanks…I’ll try it.

Vic Wintriss

unread,
Apr 21, 2016, 7:57:36 PM4/21/16
to ioio-users
I'm having difficulty bringing up one of my roomba boards with ioio cIrcutry on the board. It would be really nice if I could have a hex file of your blink program. I have a pickit3 that can load but nothing else works. I don't have a development environment set up for the pic so compiling would be a big job. Thanks.

Ytai Ben-Tsvi

unread,
Apr 21, 2016, 8:20:26 PM4/21/16
to ioio-...@googlegroups.com
Can you put on a bootloader and then use the blink ioioapp file with IOIODude?

On Thu, Apr 21, 2016 at 4:57 PM, Vic Wintriss <vic.wi...@gmail.com> wrote:
I'm having difficulty bringing up one of my roomba boards with ioio cIrcutry on the board. It would be really nice if I  could have a hex file of your blink program. I have a  pickit3 that can load but nothing else works. I don't have a development environment set up for the pic so compiling would be a big job. Thanks.

Vic Wintriss

unread,
Apr 21, 2016, 8:28:38 PM4/21/16
to ioio-...@googlegroups.com
In using a Mac. Iodide doesn't seem to work. 

Sent from my iPhone
You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+...@googlegroups.com.

Ytai Ben-Tsvi

unread,
Apr 21, 2016, 8:36:39 PM4/21/16
to ioio-...@googlegroups.com
Can you just get it to work? Seems like a problem with a specific computer. I'm very regularly using a MacBook as well as Windows for this purpose. I've had reports on IOIODude 1.03 not working on Linux whereas 1.02 does, but I don't think it's that badly broken that you cannot get it to work with very little effort. It will be much more beneficial for you in the long term. My schedule doesn't really allow me to be very responsive to requests for building custom images for custom boards at the moment.

Vic Wintriss

unread,
Apr 21, 2016, 8:42:07 PM4/21/16
to ioio-...@googlegroups.com
Ok. I'll try to get it working on another Mac. I'll let you know what happens. 

Sent from my iPhone

Vic Wintriss

unread,
Apr 27, 2016, 12:31:48 AM4/27/16
to ioio-users
I tried ioiodude on another Mac...a recent iMac and it worked fine.  Still won't work on my Mac mini...strange.


On Thursday, April 21, 2016 at 5:42:07 PM UTC-7, Vic Wintriss wrote:
Ok. I'll try to get it working on another Mac. I'll let you know what happens. 

Sent from my iPhone

On Apr 21, 2016, at 5:36 PM, Ytai Ben-Tsvi <yta...@gmail.com> wrote:

Can you just get it to work? Seems like a problem with a specific computer. I'm very regularly using a MacBook as well as Windows for this purpose. I've had reports on IOIODude 1.03 not working on Linux whereas 1.02 does, but I don't think it's that badly broken that you cannot get it to work with very little effort. It will be much more beneficial for you in the long term. My schedule doesn't really allow me to be very responsive to requests for building custom images for custom boards at the moment.
On Thu, Apr 21, 2016 at 5:28 PM, Vic Wintriss <sd...@me.com> wrote:
In using a Mac. Iodide doesn't seem to work. 

Sent from my iPhone

On Apr 21, 2016, at 5:20 PM, Ytai Ben-Tsvi <yta...@gmail.com> wrote:

Can you put on a bootloader and then use the blink ioioapp file with IOIODude?
On Thu, Apr 21, 2016 at 4:57 PM, Vic Wintriss <vic.wi...@gmail.com> wrote:
I'm having difficulty bringing up one of my roomba boards with ioio cIrcutry on the board. It would be really nice if I  could have a hex file of your blink program. I have a  pickit3 that can load but nothing else works. I don't have a development environment set up for the pic so compiling would be a big job. Thanks.

--
You received this message because you are subscribed to the Google Groups "ioio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ioio-users+unsubscribe@googlegroups.com.

To post to this group, send email to ioio-...@googlegroups.com.
Visit this group at https://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+unsubscribe@googlegroups.com.

To post to this group, send email to ioio-...@googlegroups.com.
Visit this group at https://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "ioio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ioio-users+unsubscribe@googlegroups.com.

To post to this group, send email to ioio-...@googlegroups.com.
Visit this group at https://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "ioio-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ioio-users/3MDLEEKtejY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ioio-users+unsubscribe@googlegroups.com.

vic.wi...@jointheleague.org

unread,
Jun 22, 2016, 12:58:31 PM6/22/16
to ioio-users
It's iARoC time again, and we are having ultrasonic problems again!  This year I am using only 4-pin sensors like you recommend and OTG.
I can't find any of the ioio.sync() methods.  What version of the ioiolib are they in?  All the robots have 3 or 4 ultrasonic sensors.

Ytai Ben-Tsvi

unread,
Jun 23, 2016, 12:36:41 AM6/23/16
to ioio-...@googlegroups.com
You can check the release notes page on the wiki. I strongly recommend against using old versions of the library.

vic.wi...@jointheleague.org

unread,
Jun 23, 2016, 12:47:11 AM6/23/16
to ioio-users
Is ioio.sync() in the latest versions?

Ytai Ben-Tsvi

unread,
Jun 23, 2016, 12:50:24 AM6/23/16
to ioio-...@googlegroups.com

Yes

Reply all
Reply to author
Forward
0 new messages