Skip to content

Instantly share code, notes, and snippets.

@ericyd
Created February 4, 2020 06:08
Show Gist options
  • Save ericyd/2f54b4702ae0c3b851d656cce7d9c6d0 to your computer and use it in GitHub Desktop.
Save ericyd/2f54b4702ae0c3b851d656cce7d9c6d0 to your computer and use it in GitHub Desktop.
Arduino LEDs
/*
Basically, an experiment right now
*/
bool const DEBUG_NEXT_VALUE = false;
bool const DEBUG_CALCULATE_NEXT_VALUES = false;
struct RGB
{
double r;
double g;
double b;
};
class RGBFactory {
int nMax, nMin, saturationMax, saturationMin, range;
double rChannelOffset, gChannelOffset, bChannelOffset;
public:
RGBFactory(int xMin, int xMax, int satMin, int satMax) {
// define basic parameters
nMax = xMax;
nMin = xMin;
saturationMax = satMax;
saturationMin = satMin;
double n6th = (nMax - nMin) / 6;
double n12th = n6th / 2;
range = saturationMax - saturationMin;
// define each channel offset
rChannelOffset = n6th * 2 - n12th;
gChannelOffset = n6th * 6 - n12th;
bChannelOffset = n6th * 4 - n12th;
}
RGB calculateNextValues(double n) {
RGB rgb;
rgb.r = clip(rangeAdjust(position(n, rChannelOffset)));
rgb.b = clip(rangeAdjust(position(n, bChannelOffset)));
rgb.g = clip(rangeAdjust(position(n, gChannelOffset)));
if (DEBUG_CALCULATE_NEXT_VALUES) {
Serial.println("n: " + String(n) + "; rChannelOffset: " + String(rChannelOffset) + "; position(n, rChannelOffset): " + position(n, rChannelOffset) + "; rangeAdjust(...)" + rangeAdjust(position(n, rChannelOffset)) + "; clip(...):" + clip(rangeAdjust(position(n, rChannelOffset))));
}
return rgb;
}
private:
// transformers convert the number to a channel value
// where a channel is one of red, green, or blue
double clip(double x) {
if (x < saturationMin) {
return double(saturationMin);
}
if (x > saturationMax) {
return double(saturationMax);
}
return x;
}
// range adjustment is slightly non-standard because sine functions can be negative
double rangeAdjust(double x) {
return double(x * double(range) + saturationMin + range) / 2;
}
// calculate the points position on a sine curve, where
// `x` is the input number that is being transformed
// `offset` is the phase offset of the point in the sine curve
// `nMax` is the wave amplitude
// `2 * PI` is the frequency in radians
// Ref: https://en.wikipedia.org/wiki/Sine_wave
double position(double x, double offset) {
return sin((2 * PI / nMax) * (x + offset));
}
};
int const RED_POT_PIN = A2;
int const GREEN_POT_PIN = A1;
int const BLUE_POT_PIN = A0;
int const RED_OUT_PIN = 3;
int const GREEN_OUT_PIN = 5;
int const BLUE_OUT_PIN = 6;
double nextValue;
double currentVal = 0;
unsigned long now;
unsigned long timeDifference = 0;
unsigned long lastTime = 0;
int slowDownFactor = 100; // name it like it is, right?
RGBFactory factory(0, 1000, 0, 255);
RGB nextRgb;
void setup()
{
pinMode(RED_OUT_PIN, OUTPUT);
pinMode(GREEN_OUT_PIN, OUTPUT);
pinMode(BLUE_OUT_PIN, OUTPUT);
if (DEBUG_NEXT_VALUE || DEBUG_CALCULATE_NEXT_VALUES) {
Serial.begin(9600);
}
}
void loop()
{
if (analogRead(BLUE_POT_PIN) > 500) {
// time-based
nextValue = analogRead(RED_POT_PIN);
now = millis();
timeDifference = now - lastTime;
lastTime = now;
// pseudo code
currentVal = currentVal + (sqrt(double(timeDifference) * nextValue / slowDownFactor));
// for time-based sweep through rainbox
nextRgb = factory.calculateNextValues(currentVal);
} else {
nextValue = analogRead(GREEN_POT_PIN);
// for manual sweep through rainbow
nextRgb = factory.calculateNextValues(nextValue);
}
if (DEBUG_NEXT_VALUE) {
Serial.println(String(nextValue) + " : " + String(nextRgb.r) + " : " + String(nextRgb.g) + " : " + String(nextRgb.b));
}
analogWrite(RED_OUT_PIN, nextRgb.r);
analogWrite(GREEN_OUT_PIN, nextRgb.g);
analogWrite(BLUE_OUT_PIN, nextRgb.b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment