This is taking place on a Duemilanove with an ATMega328P.
My sketch polls a MaxSonar sensor to determine whether someone is standing in front of my aquarium and then adjusts the tank lights accordingly. Distance measurement is by way of pulse width detection (147 microseconds to the inch).
I'm playing around with the sketch and the hardware to eliminate spurious measurements. I've got a working solution...but only when the Arduino's USB port is plugged into the serial port of my laptop. When it's not plugged in, the sketch detects the presence of an observer and ramps the lights up, but it never detects the observer's departure so as to turn the lights down.
The effect of plugging in the USB connection is reproducible. Merely rebooting the Arduino, without the USB being connected, doesn't solve the problem.
Here's the portion of the code that interfaces to the MaxSonar. The entire sketch is pretty large (it compiles to around 20KB) so posting it probably wouldn't be too useful.
The header file:
// interface for sonar observation
#ifndef OBSERVATION_H
#define OBSERVATION_H
#include "Arduino.h"
#include <Time.h>
#define MICROSEC_PER_INCH 147.0
#define SONAR_READINGS 5
#define SENSE_WINDOW_MICROSEC 50000
class ObserverDetection;
typedef void (* DetectionCallback) ( ObserverDetection* );
class ObserverDetection
{
public:
ObserverDetection( byte pin );
int detect();
int detect( const time_t t );
byte freqSec;
private:
byte _pin;
unsigned long _pulseWidths[SONAR_READINGS];
unsigned long _sortedWidths[SONAR_READINGS];
int _lastDist;
time_t _lastTime;
void sortReadings();
};
#endif
The method definition file:
// implementation of sonar observation interface
#include "observation.h"
ObserverDetection::ObserverDetection( byte pin )
{
_pin = pin;
pinMode(_pin, INPUT);
freqSec = 5;
_lastTime = 0; // force reading on first detect
_lastDist = -1;
}
int ObserverDetection::detect()
{
return detect(now());
}
int ObserverDetection::detect( const time_t t )
{
if( (t - _lastTime) < freqSec ) return _lastDist;
for( byte idx = 0; idx < SONAR_READINGS; idx++ )
{
_pulseWidths[idx] = pulseIn(_pin, HIGH, SENSE_WINDOW_MICROSEC);
}
sortReadings();
_lastDist = (int) ((float) _sortedWidths[ SONAR_READINGS / 2 ] / MICROSEC_PER_INCH);
if( _lastDist <= 0 ) _lastDist = -1;
return _lastDist;
}
void ObserverDetection::sortReadings()
{
for( byte i = 0; i < SONAR_READINGS; i++ )
{
_sortedWidths[i] = _pulseWidths[i];
}
for( byte i=0; i< SONAR_READINGS- 1; i++ )
{
byte m = i;
for( byte j=i+1; j< SONAR_READINGS; j++ )
{
if (_sortedWidths[j] < _sortedWidths[m]) m = j;
}
if (m != i)
{
unsigned long t = _sortedWidths[m];
_sortedWidths[m] = _sortedWidths[i];
_sortedWidths[i] = t;
}
}
}
FYI, the basic algorithm is:
- wait 5 seconds between observations (this is adjustable)
- take 5 sonar readings (each one with a timeout window of 50000 microseconds)
- sort the readings by distance
- select the 3rd reading (median) as the observation
Elsewhere in the sketch the observed median distance value is used to determine whether the system is or is not under observation.
My question is this: are there side effects of the Arduino USB port being connected to a destination which alter the way the board works? Even to the extent of "just" inserting some timing delays in the looping?