#include <Arduino.h>
#include <Servo.h>
#include <Wire.h>
#include <MPU6050_tockn.h>
#define RATELIMIT
#define SMOOTHANGLE
#define LIMITACTIVE
int an = 200;
int kurzePause = 300;
int langePause = 500;
const int servoLeftPin = 9;
const int servoRightPin = 10;
Servo servoLeft;
Servo servoRight;
MPU6050 mpu6050(Wire);
int positionLeft = 90;
int positionRight = 90;
const int beaconLedPinRed = 3;
const int beaconLedPinGreen = 5;
const int beaconLedPinBlue = 6;
const int portLedPin = 7;
const int starboardLedPin = 8;
const int tempSensPin = 14;
const int callCount = 5;
int callTemp[callCount];
float tempAverage;
unsigned long lastRainbowMs = 0;
const uint16_t rainbowStepMs = 15;
uint16_t rainbowHue = 0;
float ema(float currentEMA, int newValue, float alpha) {
return alpha * newValue + (1 - alpha) * currentEMA;
}
int rateLimit(int desiredPosition, int currentPosition, int maxChange) {
int change = desiredPosition - currentPosition;
if (change > maxChange) change = maxChange;
else if (change < -maxChange) change = -maxChange;
return currentPosition + change;
}
static void hsvToRgb(uint16_t h, uint8_t s, uint8_t v, uint8_t &r, uint8_t &g, uint8_t &b) {
if (s == 0) { r = g = b = v; return; }
uint16_t region = h / 60;
uint16_t rem = (h % 60) * 255 / 60;
uint8_t p = (uint16_t)v * (255 - s) / 255;
uint8_t q = (uint16_t)v * (255 - ((uint16_t)s * rem) / 255) / 255;
uint8_t t = (uint16_t)v * (255 - ((uint16_t)s * (255 - rem)) / 255) / 255;
switch (region) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
default: r = v; g = p; b = q; break;
}
}
void setup() {
servoLeft.attach(servoLeftPin);
servoRight.attach(servoRightPin);
servoLeft.write(positionLeft);
servoRight.write(positionRight);
Serial.begin(9600);
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(true);
pinMode(beaconLedPinRed, OUTPUT);
pinMode(beaconLedPinGreen, OUTPUT);
pinMode(beaconLedPinBlue, OUTPUT);
pinMode(portLedPin, OUTPUT);
pinMode(starboardLedPin, OUTPUT);
pinMode(tempSensPin, INPUT);
}
void updateServoControl() {
mpu6050.update();
static float smoothedPositionLeft = 90;
static float smoothedPositionRight = 90;
#ifdef SMOOTHANGLE
smoothedPositionLeft = ema(smoothedPositionLeft, 90 - (mpu6050.getAngleY() + mpu6050.getAngleX()), 0.1);
smoothedPositionRight = ema(smoothedPositionRight, 90 + (mpu6050.getAngleY() - mpu6050.getAngleX()), 0.1);
#else
smoothedPositionLeft = 90 - (mpu6050.getAngleY() + mpu6050.getAngleX());
smoothedPositionRight = 90 + (mpu6050.getAngleY() - mpu6050.getAngleX());
#endif
#ifdef RATELIMIT
positionLeft = rateLimit((int)smoothedPositionLeft, positionLeft, 25);
positionRight = rateLimit((int)smoothedPositionRight, positionRight, 25);
#else
positionLeft = smoothedPositionLeft;
positionRight = smoothedPositionRight;
#endif
#ifdef LIMITACTIVE
positionLeft = min(135, max(10, positionLeft));
positionRight = min(135, max(10, positionRight));
#endif
servoLeft.write(positionLeft);
servoRight.write(positionRight);
}
void updateTemperature() {
tempAverage = 0;
for (int k = 0; k < callCount; k++) {
callTemp[k] = analogRead(tempSensPin);
tempAverage += callTemp[k];
}
tempAverage /= callCount;
}
void updateBeaconRainbow() {
unsigned long now = millis();
if (now - lastRainbowMs < rainbowStepMs) return;
lastRainbowMs = now;
rainbowHue++;
if (rainbowHue >= 360) rainbowHue = 0;
uint8_t r, g, b;
hsvToRgb(rainbowHue, 255, 255, r, g, b);
Serial.print("Light: ");
Serial.print(r);
Serial.print(g);
Serial.println(b);
analogWrite(beaconLedPinRed, r);
analogWrite(beaconLedPinGreen, g);
analogWrite(beaconLedPinBlue, b);
}
unsigned long navLastMs = 0;
const unsigned long pulseOnTime = an;
const unsigned long pulseOffTime = kurzePause;
const unsigned long pauseTime = langePause;
uint8_t navState = 0;
void updateNavigationLights() {
unsigned long now = millis();
switch (navState) {
case 0:
digitalWrite(portLedPin, HIGH);
digitalWrite(starboardLedPin, HIGH);
navLastMs = now;
navState = 1;
break;
case 1:
if (now - navLastMs >= pulseOnTime) {
digitalWrite(portLedPin, LOW);
digitalWrite(starboardLedPin, LOW);
navLastMs = now;
navState = 2;
}
break;
case 2:
if (now - navLastMs >= pulseOffTime) {
digitalWrite(portLedPin, HIGH);
digitalWrite(starboardLedPin, HIGH);
navLastMs = now;
navState = 3;
}
break;
case 3:
if (now - navLastMs >= pulseOnTime) {
digitalWrite(portLedPin, LOW);
digitalWrite(starboardLedPin, LOW);
navLastMs = now;
navState = 4;
}
break;
case 4:
if (now - navLastMs >= pauseTime) {
navState = 0;
}
break;
}
}
void loop() {
updateServoControl();
updateTemperature();
updateBeaconRainbow();
updateNavigationLights();
Serial.print("Servo Left: ");
Serial.println(positionLeft);
Serial.print("Servo Right: ");
Serial.println(positionRight);
}