ArduinoGeneral

Sharp distance sensor GP2Y0A710K0F

userHead Account cancelled 2013-07-20 03:25:59 4357 Views0 Replies
I recently got myself one of these modules, and have come up with a program to use it to sense motion. I'm using it as a focused, active PIR (yes, I know the contradiction here...) to try to reduce (eliminate?) the chance of my cats inadvertently triggering this circuit. I'm not even converting from raw ADC values (on my UNO) to distances, just checking to see if the ADC value changes more than a defined amount.

I do have a hardware question about this module. The datasheet suggests using a 10uF (minimum) bypass cap for stability. I'll probably use both a 10uF and a 0.1uF in parallel for bypass. I see there are some test points on the back and I've identified two that appear to be connected to the power pins (I buzzed them out to the included cable). Can I solder the bypass cap(s) to these tespoints (smt-style), or should I just have the bypass cap(s) near the 3-pin header where I attach the cable? (I didn't check to see if the test points are only for one of the two pairs of power pins on the actual module... That might be an issue...)

One quirk (I'm not familiar with IR distance sensors, so this may be typical) is the response isn't linear but hyperbolic (inversely proportional). So with my application where I'm trying to see a door opening down a 10 foot hallway, the change in the ADC count isn't very much (just a bit over noise). The result is it is much more sensitive at short range than it is at long range.

I haven't seen any examples or documentation (beyond Sharp's datasheet) for this device so I thought I would share my code as it is. I release this code to the public domain as an example of using this sensor. If anyone has any questions, or a better way of doing what I'm doing, please feel free to share your thoughts.

SharpDistanceSensorPWMout.ino
[code]/*
* Entry Sensor Light: with Sharp Distance Sensor and PWM Output
* - Use a distance sensor (Sharp# GP2Y0A710K0F) to ramp (fade) a PWM output
* up when the sensed distance changes. Then after a time out, ramp the PWM
* output down at a (potentially) different rate.
*
* By Chris "Sembazuru" Elliott, SembazuruCDE (at) GMail.com
* 2013/07/19
*
* To the extent possible under law, Chris "Sembazuru" Elliott has waived all
* copyright and related or neighboring rights to SharpDistanceSensorPWMout.ino
* See http://creativecommons.org/publicdomain/zero/1.0/ for details.
* (Attribution would be nice, but in no way compulsory.)
*
* Hardware configuration on Arduino UNO:
* - Analog output of sensor to A0
* - LED13 used to show trigger status
* - PWM on pin 3 used for the ramping output (pin 4 used as ground reference for
* testing with 0.1" 5V LED)
* - A5 pin used to disable serial diagnostics (A4 pin used as ground reference
* for testing with 0.1" shorting pins)
*/

// Template version. See http://playground.arduino.cc/Main/runningMedian for details and downloads.
#include <RunningMedian.h>

// Pair of pins to enable serial diagnostics. Short these two pins (or just the diagnosticsPin to ground) to silence serial diagnostics.
const byte diagnosticsPin = A5;
const byte diagnosticsGnd = A4;

// Constants and variables for data collection.
const byte sensorPin = A0;
unsigned int currentADC;
unsigned int currentMedian;
const unsigned int medianArraySize = 16; // number of data points to collect to calculate the median
const unsigned long readingInterval = 17;
unsigned long readingStart = millis();
RunningMedian<unsigned int, medianArraySize> myMedian;

// Constants and variables for triggering.
unsigned int lastMedian;
const unsigned int triggerThreshold = 7; // +/- value for medians
const byte triggerLED = 13; // Indicator LED for trigger
const unsigned long triggerDelay = 10000; // How long the trigger will last (minimum) in milliseconds
unsigned long triggerStart; // To allow capturing the time at the start of a trigger
boolean triggered = false;

// Constants and variables for ramping the output up and down.
boolean ramping = false; // true == need to ramp, false == done ramping.
boolean rampDir = false; // true == up, false == down.
const byte rampPin = 3; // PWM pin to ramp up and down.
const byte rampGnd = 4; // Adjacent ground provided for use of 0.1" spacing 5V LED.
const int rampMin = 0;
const int rampMax = 255;
const byte rampStep = 4; // How much to change the rampValue by each iteration.
const byte rampUDRatio = 2; // Amount to divide the rampStep by when ramping down to change the ramp up to ramp down rate ratio.
const unsigned long rampTime = 3000; // How many milliseconds (base) to take for the ramp up.
const unsigned long rampStepInterval = rampTime / ((rampMax - rampMin) / rampStep); // Calculate how long between ramp steps. Do this calculation once here.
unsigned long rampStepStart = millis(); // Sensor readings take 16.5ms +/- 3.7ms.
int rampValue = rampMin;

void setup()
{
Serial.begin(115200);
while (!Serial); // Wait for serial port to connect. Needed for Leonardo only.
delay(1000); // Simply to allow time for the ERW versions of the IDE time to automagically open the Serial Monitor. 1 second chosen arbitrarily.

// Setup pins for enabling/disabling serial diagnostics.
pinMode(diagnosticsPin, INPUT_PULLUP);
pinMode(diagnosticsGnd, OUTPUT);
digitalWrite(diagnosticsGnd, LOW);

// Setup pins for using the onboard LED to indicate triggering.
pinMode(triggerLED, OUTPUT);
digitalWrite(triggerLED, LOW);

// Setup pins for the ramping (fading) PWM pin.
analogWrite(rampPin, rampValue);
pinMode(rampGnd, OUTPUT);
digitalWrite(rampGnd, LOW);
}

void loop()
{
if ((millis() - readingStart) > readingInterval)
{
getData();
triggerCheck();
if (digitalRead(diagnosticsPin))
{
diagnostics();
}
}
if (ramping)
{
if ((millis() - rampStepStart) > rampStepInterval)
{
rampValue = rampOutput(rampValue, rampStep, rampDir);
if (digitalRead(diagnosticsPin))
{
diagnostics();
}
}
}
}

void getData()
{
readingStart = millis();
currentADC = analogRead(sensorPin);
myMedian.add(currentADC);
lastMedian = currentMedian;
myMedian.getMedian(currentMedian);
}

void triggerCheck()
{
// Trigger if the median drops by more than the threshold or raises by more than the threshold.
if ((currentMedian < (lastMedian - triggerThreshold)) || (currentMedian > (lastMedian + triggerThreshold)))
{
triggerStart = millis();
digitalWrite(triggerLED, HIGH);
triggered = true;
ramping = true;
rampDir = true;
}
// If currently triggered, check to see if enough time has passed since the last trigger event to turn off the trigger.
if (triggered)
{
if ((millis() - triggerStart) > triggerDelay)
{
digitalWrite(triggerLED, LOW);
triggered = false;
ramping = true;
rampDir = false;
}
}
}

int rampOutput(int _value, int _step, boolean _dir)
{
rampStepStart = millis();
if (!_dir)
{
_step = -_step / rampUDRatio;
}
_value += _step;
if (_value < rampMin)
{
_value = rampMin;
ramping = false;
}
if (_value > rampMax)
{
_value = rampMax;
ramping = false;
}
analogWrite(rampPin, _value);
return _value;
}

void diagnostics()
{
// Use the F() macro throughout to not waste valueable SRAM on diagnostic messages.
Serial.print(myMedian.getCount());
Serial.print(F(":"));
Serial.print(F(" Current = "));
Serial.print(currentADC);
Serial.print(F(" "));
Serial.print(F(" Current Median = "));
Serial.print(currentMedian);
Serial.print(F(" Last Median = "));
Serial.print(lastMedian);
Serial.print(F(" Median Delta = "));
Serial.print(((int) currentMedian) - ((int) lastMedian)); // Casting to signed values to allow a negative result.
Serial.print(F(" Triggered = "));
Serial.print(triggered);
Serial.print(F(" Ramping = "));
Serial.print(ramping);
Serial.print(F(" Ramp Direction = "));
if (rampDir)
{
Serial.print(F(" UP "));
}
else
{
Serial.print(F("DOWN"));
}
Serial.print(F(" Ramp Value = "));
Serial.print(rampValue);
Serial.println();
// A short delay to slow things down for serial output. No need to get fancy, a simple blocking delay is fine here.
delay(20);
}
[/code]