Fixed noise and unreliability issues, cleaned up code

This commit is contained in:
Mark van Renswoude 2019-01-07 20:07:50 +01:00
parent fa53deb9d0
commit fb32be56d3

View File

@ -34,8 +34,9 @@ static const uint16_t ServoMinPulse = 544;
static const uint16_t ServoMaxPulse = 2400;
static const uint16_t ServoPulseInterval = 20;
static const uint16_t ServoStabilizeDelay = 100;
static const uint16_t ServoPulseInterval = 20; // How often servo pulses are sent (around 20 ms is the protocol)
static const uint16_t ServoHoldDelay = 500; // How long the position is held after moving, to account for the servo catching up
static const uint16_t ServoStabilizeDelay = 200; // How long to wait for the voltage to stabilize before checking calibration
int offPosition; // 0 - 180 degrees, read from "Off" potentiometer
@ -44,16 +45,28 @@ int speed; // 0 - 1023, read from "Speed" potentiometer
float degreesPerMilli; // Degrees per millisecond
enum State
{
Idle,
Holding,
Stabilizing,
Moving,
Calibrating,
ZzZzZz
};
State state; // The current state
bool lastOn; // If the switch was on when it was last flipped
int startPosition; // The position the servo was in when the switch was flipped
unsigned long startTime; // The last time the switch was flipped
unsigned long idleTime; // The last time anything happened
unsigned long lastChangeTime; // The last time anything happened
bool servoEnabled; // Whether or not pulses should be sent to the servo
int servoPosition; // The desired position of the servo
unsigned long servoPulseTime; // The last time the servo pulse was sent
#ifdef DEBUG
SoftwareSerial debug(-1,3);
#endif
@ -68,6 +81,13 @@ void sleepUntilSwitch();
float floatMap(float x, float in_min, float in_max, float out_min, float out_max);
// Macros
#define setState(newState) { state = newState; lastChangeTime = currentTime; }
#define isServoEnabled() (state == Holding || state == Moving || state == Calibrating)
#define timePassed() (currentTime - lastChangeTime)
void setup()
{
#ifdef DEBUG
@ -86,12 +106,11 @@ void setup()
updateSettings();
lastOn = false;
state = Holding;
startPosition = offPosition;
servoPosition = offPosition;
servoPulseTime = 0;
servoEnabled = true;
#ifdef DEBUG
debug.println("Started");
@ -103,7 +122,7 @@ void loop()
{
unsigned long currentTime = millis();
if (servoEnabled)
if (isServoEnabled())
pulseServo(currentTime);
bool isOn = (digitalRead(PinSwitch) == LOW);
@ -118,54 +137,80 @@ void loop()
lastOn = isOn;
startPosition = servoPosition;
startTime = currentTime;
idleTime = startTime;
}
int targetPosition = isOn ? onPosition : offPosition;
if (servoPosition != targetPosition)
{
servoPosition = getNewPosition(currentTime, targetPosition);
servoEnabled = true;
idleTime = currentTime;
}
else if (servoEnabled)
{
// Ensure we pulsed the last position
currentTime = millis();
delay(ServoPulseInterval);
pulseServo(currentTime);
delay(ServoPulseInterval);
// Stop sending pulses when we reach the destination, to prevent
// power consumption and possible buzzing
servoEnabled = false;
idleTime = currentTime;
setState(Moving);
}
// Don't update the settings while the servo is moving, as the
// voltage drop can cause fluctuating results
if (!servoEnabled && currentTime - idleTime >= ServoStabilizeDelay)
switch (state)
{
if (updateSettings())
case Idle:
{
// Immediately go to the new position
currentTime = millis();
servoPosition = isOn ? onPosition : offPosition;
// Only check the settings first when the servo is idle, as the
// voltage drop can cause fluctuating results
if (updateSettings())
{
setState(Calibrating);
servoPosition = isOn ? onPosition : offPosition;
}
else if (timePassed() >= SleepTime)
{
state = ZzZzZz;
sleepUntilSwitch();
}
delay(ServoPulseInterval);
pulseServo(currentTime);
delay(ServoPulseInterval);
idleTime = currentTime;
break;
}
}
// Stay awake for a bit to allow changes to the on and off positions
// to take effect immediately
if (currentTime - idleTime >= SleepTime)
sleepUntilSwitch();
case Holding:
{
// Keep the servo signal on until ServoHoldDelay has passed
if (timePassed() >= ServoHoldDelay)
setState(Stabilizing);
break;
}
case Stabilizing:
{
// Keep the servo signal off until ServoStabilizeDelay has passed
if (timePassed() >= ServoStabilizeDelay)
setState(Idle);
break;
}
case Moving:
{
int targetPosition = isOn ? onPosition : offPosition;
servoPosition = getNewPosition(currentTime, targetPosition);
if (servoPosition == targetPosition)
setState(Holding);
break;
}
case Calibrating:
{
// While calibrating, update immediatly, slight variations
// aren't that much of a concern at this point
if (updateSettings())
{
lastChangeTime = currentTime;
servoPosition = isOn ? onPosition : offPosition;
}
else if (timePassed() >= ServoHoldDelay)
setState(Idle);
break;
}
case ZzZzZz:
// Apparantly we were woken up without a switch change, go back to sleep
sleepUntilSwitch();
break;
}
}