I need to change or add a way to stop oscillations. The device I am trying to control fly's out of the dead band / hysteresis before it can get stopped in time and in return bounces up and down. The noise cancelling that is currently in the code made it worse by adding to much delay so I stopped using it. Is there a way to have it see the end is near and predict the needed stop. PWM is not an option due to how the control circuit reads the up and down.
This is the current code I have been using. Thanks go to Blackfin for the coding so far.
#define DESIRED_HEIGHT 500 //# raw ADC counts representing desired height and the lower the number the greater the down pressure on the ground
#define HIGH_HYSTERESIS 105 //# hysteresis -- positive side
#define LOW_HYSTERESIS 105 //# hysteresis -- negative side
#define NUM_AVGS 1 //# number of samples in averaging array
#define SAMPLE_PERIOD 1 //mS number of milliseconds between samples
//Constants
const byte PotPin = A0;
const byte UpPin = 2;
const byte DownPin = 4;
unsigned long
timeNow;
unsigned long
timeSample = 0;
int
grAvgHeight[NUM_AVGS];
unsigned long
ulSum;
int
Height;
void setup()
{
Serial.begin( 9600 );
pinMode(UpPin, OUTPUT);
pinMode(DownPin, OUTPUT);
digitalWrite( UpPin, HIGH );
digitalWrite( DownPin, HIGH );
//
pinMode(PotPin, INPUT);
//initialize the averaging array and sum
Height = analogRead( PotPin );
for( int i=0; i<NUM_AVGS; i++ )
grAvgHeight[i] = Height;
ulSum = Height * NUM_AVGS;
}//setup
//state names
#define NOT_MOVING 0
#define MOVING_UP 1
#define MOVING_DOWN 2
//
void loop()
{
static byte
stateMovement = NOT_MOVING;
//get the time now
timeNow = millis();
//is it time for a check on the position?
if( (timeNow - timeSample) >= SAMPLE_PERIOD )
{
//yes; save this time for the next compare
timeSample = timeNow;
//read the position sensing pot and filter it
Height = FilterHeight( analogRead( PotPin ) );
//what are we currently doing?
switch( stateMovement )
{
case NOT_MOVING:
//we're in the deadband now. Check to see if we're outside the limits
if( Height < (DESIRED_HEIGHT - LOW_HYSTERESIS) )
{
//too low; set the Up direction
Serial.println( "MOVING UP" );
digitalWrite( UpPin, LOW );
stateMovement = MOVING_UP; //and move to that state
}//if
else if( Height > (DESIRED_HEIGHT + HIGH_HYSTERESIS) )
{
//too high; set the Down direction
Serial.println( "MOVING DOWN" );
digitalWrite( DownPin, LOW );
stateMovement = MOVING_DOWN; //and move to that state
}//else
break;
case MOVING_UP:
//when actually moving up, we seek to stop moving when the filtered height matches or is greater than that desired
if( Height >= DESIRED_HEIGHT )
{
Serial.println( "STOPPING UPWARD MOVEMENT" );
digitalWrite( UpPin, HIGH );
stateMovement = NOT_MOVING;
}//if
break;
case MOVING_DOWN:
//when actually moving up, we seek to stop moving when the filtered height matches or is less than that desired
if( Height <= DESIRED_HEIGHT )
{
Serial.println( "STOPPING DOWNWARD MOVEMENT" );
digitalWrite( DownPin, HIGH );
stateMovement = NOT_MOVING;
}//if
break;
}//switch
}//if
}//loop
//add a bit of noise filtering to the ADC readings
int FilterHeight( int NewReading )
{
static int
idx = 0;
//on each pass, we subtract from the sum the value in the array pointed to by idx
ulSum -= grAvgHeight[idx];
//then add in the new value
ulSum += NewReading;
//and store that new value in the array
grAvgHeight[idx] = NewReading;
//walk through the array each pass; when we hit the end of the array, reset to zero
//this treats the array as a "circular" array
idx++;
if( idx == NUM_AVGS )
idx = 0;
//compute avg of updated sum divided by number of samples
return( (int)(ulSum / NUM_AVGS) );
}//FilterHeight