Pixelblaze w/HC-SR04 Distance Sensor

I was done with work early today, so instead of digging in to the backlog of Useful and Important Projects, I decided to take a quick look at what might be done with this very timing dependent ultrasonic distance sensor. Thought it might be fun for proximity based interactive toys and art and such. Source code below the video.

I hooked the sensor to GPIO 4 & 5 on a Pixelblaze 2, and used the “Performance test framework” from the library to figure out workable delays.

There’s also a function that detects what model Pixelblaze the pattern is running on (2+, 3 or nano) based on capacitance on the “orange LED” GPIO pin. It works on every Pixelblaze I’ve tried it on, but is definitely not guaranteed. It may break with firmware revisions. Interesting to know that you can do that though.

I’d planned to use it to adjust delay based on CPU speed, but didn’t have a PB3 around that I could solder random things to, so it just sets the color of the LEDs based on PB model…

/*
Read approximate distance from an HC-SR04 Ultrasonic sensor using GPIO

MIT License

ZRanger1 6/7/2021
*/

var triggerPin = 4;
var echoPin = 5;
pinMode(triggerPin,OUTPUT);  
pinMode(echoPin,INPUT);  

var sensorTimer = 999;
var maSize = 6;
var aIndex = 0;
var avgBuffer = array(maSize);

// maxIterations controls the maximum measurable distance. On a 
// Pixelblaze2, 1500 is about 1.5 meters.  Minimum measurable distance is
// about 15cm (6 inches), determined to some extent by the Pixelblaze's
// execution speed. 
var maxIterations = 1500;   

// retrieve the Pixelblaze type so someday we can set delay times.
// appropriately.
var hw = getHardwareType();

// something like 1.8ms measured delay on PB2.  TBD - Will
// need to increase delay time on PB3
function delay() {
  ;
}

// average the last <maSize> readings to get rid of some
// of the noise and stabilize our distance reading.
function avgNewReading(dist) {
  var r = 0;
  avgBuffer[aIndex] = dist;
  aIndex = (aIndex + 1) % maSize;
  for (var i = 0; i < maSize; i++) {
    r += avgBuffer[i];
  }
  return r / maSize;
}

// Attempt to detect the Pixelblaze variant the pattern is
// currently running on, based on differences in capacitance 
// returned by touchRead on the "orange LED" GPIO Pin (GPIO12)
//
// Returns: 0 - Pixelblaze 2, 1 - Pixelblaze 3, 2 - Pixelblaze Nano
function getHardwareType() {
  var hw = 0;   // default to pb2
  
  var e = touchRead(12);
  if (e == 0) { hw = 2; }
  else if (e >= 0.99) hw = 1;
  
  return hw;
}  

// send a brief pulse on the trigger pin to start the sensor
function triggerSensor() {
  digitalWrite(triggerPin,LOW);
  delay();
  digitalWrite(triggerPin,HIGH);
  delay();
  delay();
  digitalWrite(triggerPin,LOW);  
}

// wait for the sensor to receive an echo.  Length of the
// wait time determines distance.  It times out in about 38ms
function readSensor() {
  var t = 0;
  // wait for echo pin to go high, indicating that we've
  // started listening.
  while (!digitalRead(echoPin)) {
    if (t++ > 100) break;
  }
  
  // measure how long it takes for echo pin to return to low
  // this will give us a rough distance estimate.
  t = 0;
  while(digitalRead(echoPin)) {
    // if we hit timeout, set the echo pin to LOW
    // to reset the hardware, which otherwise can get stuck
    if (t++ >= maxIterations) {
      pinMode(echoPin,OUTPUT);
      digitalWrite(echoPin,LOW);
      pinMode(echoPin,INPUT);
      break;
    }
  }
  return t / maxIterations;
}

export var distance;
export function beforeRender(delta) {
  sensorTimer += delta;
  
  if (sensorTimer > 50) {
    triggerSensor();
    distance = readSensor();
    distance = avgNewReading(distance);
    sensorTimer = 0;
  }
}

// Display red for pb2, green for pb3, blue for nano, moving lit area of pixels 
// down the strip according to distance sensor reading.
export function render(index) {
  h = hw * 0.3333; // color according to Pixelblaze type.
  s = 1
  v = abs((index / pixelCount) - distance) < 0.1;
  hsv(h, s, v)
}
2 Likes

interesting, and cool. I have to look, but I think I have a bunch of these

which are similar but only use 1 pin instead of 2. I’ll have to see if I can adapt this to work.

Looks like a good “garage backup space indicator” among other simple uses.

2 Likes

Only having one signal line would be a definite improvement. But darn it, you made me look at the seeedstudio store! All the strange and wonderful sensors! And I’ve wanted a Bus Pirate for a while. There goes the monthly electronic project budget…

1 Like

If only I made a commission on all of the cool stuff I find that other people buy… :slight_smile:
I could afford to buy more myself.

BTW, the m5stack store also has a bunch of nifty sensors, and I agree with Ben, they often seem underpriced, compared to other sources. Between these two sources, you can find so much “plug and program” stuff.

1 Like

Hi all, fresh PB owner here building my first project (playa vehicle) with likely one PB3 and two PB Picos.

Anyone know if it’s possible to have a pattern running normally, eg one of the included ones, and have one parameter (eg Hue) change depending on the sensor input?

Im imagining a standard pattern playing and as someone gets closer to the proximity sensor, the pattern keeps playing but the Hue shifts more and more Red the closer they get.

Thanks!

1 Like

This is definitely possible! I know the MaxBotics ultrasonic modules have an analog voltage output, so this could be as simple as connecting to the ADC via a voltage divider.

1 Like

@Schwifty, at this point you would need to put the sensor reading code into each pattern you’re using. There isn’t yet a way to have common code that runs for all patterns.

If I needed to build a “universal” proximity sensor, I’d hook up the distance sensor to a cheap Arduino or ESP8266, and have it communicate with the Pixelblaze either over wifi, or hardwired to the serial interface normally used by the Electromage sensor board. You’d probably get higher quality distance readings, and it’d be easier to adjust your patterns to just read a data value vs. adding all that highly timing-dependent code needed to read the sensor.

@jeff and @zranger1 Thanks for the responses. I imagine I would only use the distance sensor in a few patterns in my playlist so adding the code to each pattern is definitely not an issue.

Will get back when I get to this part of my build.
Cheers!