File evamSoftwareServoDriver.h¶
File List > src > evamSoftwareServoDriver.h
Go to the documentation of this file
#pragma once
#include <Arduino.h>
#include <evaTickable.h>
using namespace eva;
namespace evam
{
struct SoftwareServoConfig {
int pin;
int minPulse;
int middlePulse;
int maxPulse;
SoftwareServoConfig(int pin, int minPulse, int middlePulse, int maxPulse)
: pin(pin), minPulse(minPulse), middlePulse(middlePulse), maxPulse(maxPulse) {}
};
template <int kPin, int kMinPulse = 1000, int kMiddlePulse = 1500, int kMaxPulse = 2000>
class SoftwareServoDriver : public virtual Tickable
{
static_assert(kMinPulse >= 500 && kMinPulse <= 2500, "kMinPulse out of range 500..2500");
static_assert(kMiddlePulse >= 500 && kMiddlePulse <= 2500, "kMiddlePulse out of range 500..2500");
static_assert(kMaxPulse >= 500 && kMaxPulse <= 2500, "kMaxPulse out of range 500..2500");
static_assert(kMinPulse < kMiddlePulse, "kMinPulse must be less than kMiddlePulse");
static_assert(kMiddlePulse < kMaxPulse, "kMiddlePulse must be less than kMaxPulse");
private:
static constexpr unsigned long kRefreshIntervalMs = 20;
SoftwareServoConfig mConfig;
unsigned long mTargetPulseUs = kMinPulse;
unsigned long mPulseStartUs = 0;
unsigned long mLastRefreshMs = 0;
bool mPulseActive = false;
void tick() override
{
unsigned long nowUs = micros();
if (mPulseActive)
{
if (nowUs - mPulseStartUs >= mTargetPulseUs)
{
digitalWrite(mConfig.pin, LOW);
mPulseActive = false;
}
}
if (!mPulseActive)
{
unsigned long nowMs = millis();
if (nowMs - mLastRefreshMs >= kRefreshIntervalMs)
{
mLastRefreshMs = nowMs;
digitalWrite(mConfig.pin, HIGH);
mPulseStartUs = nowUs;
mPulseActive = true;
}
}
}
public:
SoftwareServoDriver() : mConfig(kPin, kMinPulse, kMiddlePulse, kMaxPulse)
{
pinMode(mConfig.pin, OUTPUT);
digitalWrite(mConfig.pin, LOW);
}
template<typename... Args>
SoftwareServoDriver(SoftwareServoConfig config, Args... args) : mConfig(config)
{
pinMode(mConfig.pin, OUTPUT);
digitalWrite(mConfig.pin, LOW);
}
int GetPin() const
{
return mConfig.pin;
}
protected:
void actBipolar(signed short aValue)
{
aValue = constrain(aValue, -1000, 1000);
if (aValue < 0)
mTargetPulseUs = map(aValue, -1000, 0, mConfig.minPulse, mConfig.middlePulse);
else
mTargetPulseUs = map(aValue, 0, 1000, mConfig.middlePulse, mConfig.maxPulse);
}
void actUnipolar(signed short aValue)
{
aValue = constrain(aValue, 0, 1000);
if (aValue < 500)
mTargetPulseUs = map(aValue, 0, 500, mConfig.minPulse, mConfig.middlePulse);
else
mTargetPulseUs = map(aValue, 500, 1000, mConfig.middlePulse, mConfig.maxPulse);
}
};
template <int kPin, int kMinPulse, int kMaxPulse>
using SoftwareServoFlatDriver = SoftwareServoDriver<kPin, kMinPulse, (kMaxPulse - kMinPulse) / 2 + kMinPulse, kMaxPulse>;
}