HC-SR04 and Mozzi

813 views
Skip to first unread message

Roberto Gallea

unread,
Oct 24, 2013, 4:34:10 AM10/24/13
to mozzi...@googlegroups.com
Hi there,
I am facing some issues while using HC-SR04 and Mozzi. I have six HC-SR04 connected to 12 digital pins (all except 9 and 13). I am not using serial port. I read the distance during updateControl(). Since reading all the six sensors in a single updateControl() call deteriorates the performances, I read a single sensor for each call, so I have a full reading after six calls of updateControl().  The problem is that when I stop producing sounds I still can hear some popping. When I output samples I cannot hear the pops (but maybe they are still there). I am sure the problem occurs during the reading of the sensor, since, bypassing that part, everything is smooth.
HC-SR04 requires the introduction of some dalayMicroseconds() that cannot be used with mozzi. I used mozziMillis() in this way (for example to reproduce a delay of 2 microseconds):

long msecs = mozziMicros();
while (mozziMicros()-msecs<2) ;

I have correct readings. I thought it was a matter of timing and so I used direct port writing instead of digitalWrite() but I still got the issue.

I cannot post the whole code because it is quite long. Any idea? I also thought "can it be some kind of interference on pin 9?) 
If you cannot figure out anything, maybe I can try to post just a part of the code...

Thanks!

Tim Barrass

unread,
Oct 24, 2013, 7:30:30 AM10/24/13
to mozzi...@googlegroups.com
Hi,
anything which introduces a delay by waiting in a loop will stop the code in updateAudio() from filling the output buffer.  I would have thought such a short wait would be OK if the buffer is full enough, but it depends on the processing load.
There's a workaround, but first I might also say that mozziMicros() has a resolution of 61 microseconds, as it's updated each time the audio output interrupt is called (1000000/16384 = 61, audio rate is 16384), so the wait you've introduced will last for one audio outut sample tick- which doesn't seem like it should introduce clicks unless the load is heavy.
Anyway, one solution to this is hopefully like the ones for reading analog, doing I2C and serial - make it non-blocking by making your wait period be the gap between two successive calls of updateControl().  So, in order, you receive your last reading or result, then request your next read so it will be ready to receive next time around.
Hope that helps - I can have a closer look at it in a week or so if you haven't worked it out by then.  Would be great to post a simple example to the list if you want to include it in the Mozzi examples....
Tim


--
You received this message because you are subscribed to the Google Groups "Mozzi-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mozzi-users...@googlegroups.com.
To post to this group, send an email to mozzi...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/mozzi-users/12d25be0-7ff5-43ce-af17-67a86deb906d%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Roberto Gallea

unread,
Oct 24, 2013, 10:02:17 AM10/24/13
to mozzi...@googlegroups.com
Hi Tim,
Thank you for your reply. I tried eliminating anything requiring or introducing delays and use constant fake readings and the problem is still present. Maybe, I messed up with the code. I try to post the relevant part of the code, maybe it could help... Now I can tell where exactly the problem arises (look in the function readSensor()). However, when I will solve this problem, I will be glad to add an example code in the mozzi examples.

int i=0;
void updateControl() {


  distances[i] = readSensor(i);
  i = (i+1)%NSENS;
  int final = getMinFreq(); // this function returns the minimum of the 3 readings for sine frequency
  if (final != OUT_OF_RANGE) {
    active = 1;
  } else {
    final = 0;
    active = 0;
  }

  float modulation = getMinMod();  // this function returns the minimum of the 3 readings for vibrato frequency
  if (modulation == OUT_OF_RANGE)
    modulation = 0;
  else
    modulation = map(modulation,0,OUT_OF_RANGE,-15,15);

  aVibrato.setFreq(modulation);
  averaged =  kAverage.next(final>>1);

  aSin0.setFreq(averaged);
}


int readSensor(int i) {
  
  digitalWrite( triggerPort[i], LOW );
  long msecs = mozziMicros();
  while ((mozziMicros() - msecs) < 2);

  digitalWrite( triggerPort[i], HIGH ); // IF I COMMENT JUST THIS LINE THE POPPING VANISHES!!!
                                                    // notice that triggerPort is defined as: int triggerPort[NSENS] = {12,10,6,4,2,0};
                                                    // if I change pin the popping still occurs, just with a different, but similar, pattern
    
  msecs = mozziMicros();
  while ((mozziMicros() - msecs) < 10);
  digitalWrite( triggerPort[i], LOW );

  int duration = pulseIn( echoPort[i], HIGH, OUT_OF_RANGE );
  if (duration == 0) duration = OUT_OF_RANGE;
   
  return duration;
}

int updateAudio(){
  long vibrato = 300 * aVibrato.next();
  return aSin0.phMod(vibrato)*active;
}

Roberto Gallea

unread,
Oct 27, 2013, 1:30:27 PM10/27/13
to mozzi...@googlegroups.com
Hi Tim,
problem solved. It was not a software issue, it was hardware matter. I read somwhere that HC-SR04 uses a lot of power when is triggered and a caps between 5V and GND can be required. Actually, this was the problem in my case. Even though the sensors read the values correctly, this lack of power caused some glitches in the audio. I added a cap and the problem was solved. For six sensors I needed to put a large one, 3300uf, to fully eliminate the noise. Do you wish me to provide a simple example to use a single ultrasound range finder to drive an oscillator for including it in the next release of the mozzi library?

Thank you again for the support.


Il giorno giovedì 24 ottobre 2013 10:34:10 UTC+2, Roberto Gallea ha scritto:

Tim Barrass

unread,
Oct 27, 2013, 10:05:01 PM10/27/13
to mozzi...@googlegroups.com
Hi Roberto,

glad you worked it out!  Very useful detective work which will help others.  I wouldn't have been much help fiddling about with the software at this end - but I did have a few thoughts about it, looking at the code you posted last time.  I was a bit concerned about the delays using while() and the modulo % taking up processor time (a switch() would be much faster than %).   But if it works, hey!

If you have time to post a simple example that's working, that would be great.

Cheers,
Tim


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

Roberto Gallea

unread,
Oct 28, 2013, 4:58:13 AM10/28/13
to mozzi...@googlegroups.com
Well,
sure using modulo instead of switch is heavier. However, at this state of the project I do not know exactly how many sensors will I use. For this reasong so using modulo was the "more general" way of doing that thing, though not the fastest. Concerning the while statements, I have entirely remove those, but since I needed delay of 2-10us, the longest delay was the resolution of mozziMicros(), and should have not interferenced with the audio stream. I tried also to break the sensor triggering part and the echoing part as you suggested but it was no use. The problem shown when I triggered the module (that infamous but still unharmful digitalWrite()). So I DECIDED it was not a software issue, and in fact that was. Now I can concentrate on the audio part. I will show you the final result when I will finish. Concerning the example code, I will prepare something and post it.

Have a good day!

Sean

unread,
Nov 13, 2013, 1:34:36 PM11/13/13
to mozzi...@googlegroups.com

Hey Roberto,

I'm just writing to ask if you managed to get your SRF04 working with Mozzi after all?
i'm trying to use one with the library at the moment without much luck so im wondering if you know a way to do this?

Thanks
Sean

Roberto Gallea

unread,
Nov 15, 2013, 10:27:57 AM11/15/13
to mozzi...@googlegroups.com
Hi Sean,
yes, I succeeded in using SRF04. What is the problem in your case? Mine was just a problem of some weird noise I solver adding some caps between 5v and GND.

Roberto.

Sean

unread,
Nov 15, 2013, 11:24:51 AM11/15/13
to mozzi...@googlegroups.com


Hi Roberto,

 My problem was getting it to work at all, i tried a few things and nothing was working eventually i tried the new ping library and have now got it to work.

But it would be interesting to see how you got the sensor to work, do you have any simple examples running one or two srf04 or 5's?

Thanks
Sean

Wouter

unread,
Aug 14, 2014, 3:55:26 AM8/14/14
to mozzi...@googlegroups.com
Hi Tim and Roberto,

I also want to combine ultrasonic sensors with mozzi. Same issue here. I get a glitchy sound every time I use the pulseIn() command. You start to hear it once I measure over 1.5 meters, I tried some code workarounds but they don't give a good output. Also I tried some different capacitors between the GND and the 5v. what type did you use? Here is also the code I used. What would you suggest?


#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin8192_int8.h>
#include <EventDelay.h>

#define CONTROL_RATE 64

Oscil <SIN8192_NUM_CELLS, AUDIO_RATE> aSin(SIN8192_DATA);

EventDelay kGainChangeDelay;

long msecs;
long duration;

void setup() {
  startMozzi(CONTROL_RATE);
  aSin.setFreq(200);
  kGainChangeDelay.set(200);
  Serial.begin(9600);
}


void updateControl() {
  if (kGainChangeDelay.ready()) {

    msecs = mozziMicros();
    while ((mozziMicros() - msecs) < 2);
    digitalWrite(50, HIGH );
    msecs = mozziMicros();
    while ((mozziMicros() - msecs) < 10);
    digitalWrite( 50, LOW );
    duration = pulseIn( 51, HIGH, 20000 );
    Serial.println(duration / 29 / 2);
    kGainChangeDelay.start();
  }
}


int updateAudio() {
  return aSin.next();
}


void loop() {
  audioHook();
}



Op vrijdag 15 november 2013 16:27:57 UTC+1 schreef Roberto Gallea:

Tim Barrass

unread,
Aug 15, 2014, 12:21:30 AM8/15/14
to mozzi...@googlegroups.com
Hi Wouter,
it -might- be that the updateControl() interrupt gets called again before your previous one has finished, with its loops and especially the print statement with divides in it, which will be very slow.
Does it work differently if the print line ls commented out?
Also, I think the 'while' loops might give inaccurate results because the resolution of mozziMicros() is 61 msec, updated when each audio sample is output.
I would be inclined to use an interrupt instead of pulseIn(), http://arduino.cc/en/Reference/AttachInterrupt
Then it can return in the background so you don't have to waste processor time waiting for it.
I might eventually get around to trying to make a demo of this one day...

Tim


--
You received this message because you are subscribed to the Google Groups "Mozzi-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mozzi-users...@googlegroups.com.
To post to this group, send email to mozzi...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/mozzi-users/5dc2abb2-9773-4449-844a-cd8101522322%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

nescivi

unread,
Aug 15, 2014, 3:22:21 AM8/15/14
to mozzi...@googlegroups.com
Hi,

pulseIn() has a busy wait in the internals, if I am not mistaken. That
will interfer with the audio production.

It might be worthwhile to make a version of the library that checks on
the audio interrupt whether the pulse has come back or not, and
calculates the time based on that.

sincerely,
Marije
> --
> You received this message because you are subscribed to the Google
> Groups "Mozzi-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to mozzi-users...@googlegroups.com
> <mailto:mozzi-users...@googlegroups.com>.
> To post to this group, send email to mozzi...@googlegroups.com
> <mailto:mozzi...@googlegroups.com>.
> <https://groups.google.com/d/msgid/mozzi-users/5dc2abb2-9773-4449-844a-cd8101522322%40googlegroups.com?utm_medium=email&utm_source=footer>.

Roberto Gallea

unread,
Sep 1, 2014, 4:14:14 AM9/1/14
to mozzi...@googlegroups.com
Hi,
sorry for the late reply, I moved to a new house during this month and I was very very busy... However, from what you told in your message I think that the glitch is, as Tim pointed out, due to the busy wait in the pulseIn() function. In fact this interfere only for long distances. Probably the buffer runs out of data before the pulseIn() function returns and that is why the glitch occurs. I used low distances (around 60cm max) and the problem does not occur. I agree with Tim, you should use a custom *non-blocking* version of pulseIn(), something like this.

boolean measuring = false;
unsigned lond duration = 0;
unsigned long timestamp = 0;

void updateControl() {
if (!measuring) {
  timestamp = mozziMicros();
  measuring = true;
}
else {
  if (digitalRead(ECHO_PIN) == true) {
    duration = mozziMicros() - timestamp;
    measuring = false;
    produceAudio(duration); // code that builds output once fly time is measured
  }
}

Anyway, this could still be slow to update new sounds for very large distances, however the glitch should disappear.

Hope it helps.

Gonzalo Sandoval

unread,
Aug 21, 2020, 8:25:23 AM8/21/20
to Mozzi-users
Hi Roberto
you finally got to get the ultrasonic sensor to work?
I could not understand the last code, where does the TRIGGER go and what would be the value returned by the ECHO, at the end you occupy the PulseIn?
If you could help me I would be grateful.
thanks

Tim Barrass

unread,
Aug 23, 2020, 8:55:49 AM8/23/20
to mozzi...@googlegroups.com
Hi,
I found a sketch (attached) from a couple of years ago when I must have been testing an hc-sr04 sensor.  I just tried it now and it seems to work.  The distance measuring code is in updateAudio() so it has finer grained time resolution than it would in updateControl().  Maybe it will be useful in some way...
Sinewave_Ping.ino

Gonzalo Sandoval

unread,
Aug 23, 2020, 9:38:56 AM8/23/20
to Mozzi-users
Thank you very much TIM, I will test this sketch. anyway I tell you that in my desperation I have managed to read the sensors with an arduino nano and then send the data through I2C to the STM32 that I am using as a master. I think this serves to have more input and output pins available.
Thanks again
regards
Reply all
Reply to author
Forward
0 new messages